Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / uip / burst.c
1 /* burst.c - explode digests into individual messages */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: burst.c,v 1.7 1992/12/15 00:20:22 jromine Exp $";
4 #endif  /* lint */
5
6 #include "../h/mh.h"
7 #include <stdio.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #ifdef LOCALE
11 #include        <locale.h>
12 #endif
13
14 static  cpybrst(), burst();
15 /* \f */
16
17 static struct swit switches[] = {
18 #define INPLSW  0
19     "inplace", 0,
20 #define NINPLSW 1
21     "noinplace", 0,
22
23 #define QIETSW  2
24     "quiet", 0,
25 #define NQIETSW 3
26     "noquiet", 0,
27
28 #define VERBSW  4
29     "verbose", 0,
30 #define NVERBSW 5
31     "noverbose", 0,
32
33 #define HELPSW  6
34     "help", 4,
35
36     NULL, 0
37 };
38
39 /* \f */
40
41 static char delim3[] = "-------";
42
43
44 static struct msgs *mp;
45
46 struct smsg {
47     long    s_start;
48     long    s_stop;
49 };
50
51 /* \f */
52
53 /* ARGSUSED */
54
55 main (argc, argv)
56 int     argc;
57 char  **argv;
58 {
59     int     inplace = 0,
60             quietsw = 0,
61             verbosw = 0,
62             msgp = 0,
63             hi,
64             msgnum;
65     char   *cp,
66            *maildir,
67            *folder = NULL,
68             buf[100],
69           **ap,
70           **argp,
71            *arguments[MAXARGS],
72            *msgs[MAXARGS];
73     struct smsg *smsgs;
74
75 #ifdef LOCALE
76         setlocale(LC_ALL, "");
77 #endif
78     invo_name = r1bindex (argv[0], '/');
79     if ((cp = m_find (invo_name)) != NULL) {
80         ap = brkstring (cp = getcpy (cp), " ", "\n");
81         ap = copyip (ap, arguments);
82     }
83     else
84         ap = arguments;
85     (void) copyip (argv + 1, ap);
86     argp = arguments;
87
88 /* \f */
89
90     while (cp = *argp++) {
91         if (*cp == '-')
92             switch (smatch (++cp, switches)) {
93                 case AMBIGSW: 
94                     ambigsw (cp, switches);
95                     done (1);
96                 case UNKWNSW: 
97                     adios (NULLCP, "-%s unknown\n", cp);
98                 case HELPSW: 
99                     (void) sprintf (buf, "%s [+folder] [msgs] [switches]",
100                             invo_name);
101                     help (buf, switches);
102                     done (1);
103
104                 case INPLSW: 
105                     inplace++;
106                     continue;
107                 case NINPLSW: 
108                     inplace = 0;
109                     continue;
110
111                 case QIETSW: 
112                     quietsw++;
113                     continue;
114                 case NQIETSW: 
115                     quietsw = 0;
116                     continue;
117
118                 case VERBSW: 
119                     verbosw++;
120                     continue;
121                 case NVERBSW: 
122                     verbosw = 0;
123                     continue;
124             }
125         if (*cp == '+' || *cp == '@') {
126             if (folder)
127                 adios (NULLCP, "only one folder at a time!");
128             else
129                 folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
130         }
131         else
132             msgs[msgp++] = cp;
133     }
134
135 /* \f */
136
137     if (!m_find ("path"))
138         free (path ("./", TFOLDER));
139     if (!msgp)
140         msgs[msgp++] = "cur";
141     if (!folder)
142         folder = m_getfolder ();
143     maildir = m_maildir (folder);
144
145     if (chdir (maildir) == NOTOK)
146         adios (maildir, "unable to change directory to");
147     if (!(mp = m_gmsg (folder)))
148         adios (NULLCP, "unable to read folder %s", folder);
149     if (mp -> hghmsg == 0)
150         adios (NULLCP, "no messages in %s", folder);
151
152     for (msgnum = 0; msgnum < msgp; msgnum++)
153         if (!m_convert (mp, msgs[msgnum]))
154             done (1);
155     m_setseq (mp);
156
157     smsgs = (struct smsg   *)
158                 calloc ((unsigned) (MAXFOLDER + 2), sizeof *smsgs);
159     if (smsgs == NULL)
160         adios (NULLCP, "unable to allocate burst storage");
161
162     hi = mp -> hghmsg + 1;
163     for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
164         if (mp -> msgstats[msgnum] & SELECTED)
165             burst (smsgs, msgnum, inplace, quietsw, verbosw);
166
167     free ((char *) smsgs);
168
169     m_replace (pfolder, folder);
170     if (inplace) {
171         if (mp -> lowsel != mp -> curmsg)
172             m_setcur (mp, mp -> lowsel);
173     }
174     else
175         if (hi <= mp -> hghmsg)
176             m_setcur (mp, hi);
177     m_sync (mp);
178     m_update ();
179
180     done (0);
181 }
182
183 /* \f */
184
185 static  burst (smsgs, msgnum, inplace, quietsw, verbosw)
186 register struct smsg *smsgs;
187 int     msgnum,
188         inplace,
189         quietsw,
190         verbosw;
191 {
192     int     i,
193             j,
194             ld3,
195             wasdlm,
196             mode,
197             msgp;
198     register long   pos;
199     register char   c,
200                     cc,
201                    *msgnam;
202     char    buffer[BUFSIZ],
203             f1[BUFSIZ],
204             f2[BUFSIZ],
205             f3[BUFSIZ];
206     struct stat st;
207     register    FILE *in,
208                      *out;
209
210     ld3 = strlen (delim3);
211
212     if ((in = fopen (msgnam = m_name (msgnum), "r")) == NULL)
213         adios (msgnam, "unable to read message");
214
215     mode = fstat (fileno (in), &st) != NOTOK ? (st.st_mode & 0777)
216         : m_gmprot ();
217     for (msgp = 0, pos = 0L; msgp <= MAXFOLDER;) {
218         while (fgets (buffer, sizeof buffer, in) != NULL
219                 && buffer[0] == '\n')
220             pos += (long) strlen (buffer);
221         if (feof (in))
222             break;
223         (void) fseek (in, pos, 0);
224         smsgs[msgp].s_start = pos;
225
226         for (c = 0;
227                 fgets (buffer, sizeof buffer, in) != NULL;
228                 c = buffer[0])
229             if (strncmp (buffer, delim3, ld3) == 0
230                     && (msgp == 1 || c == '\n')
231                     && ((cc = peekc (in)) == '\n' || cc == EOF))
232                 break;
233             else
234                 pos += (long) strlen (buffer);
235
236         wasdlm = strncmp (buffer, delim3, ld3) == 0;
237         if (smsgs[msgp].s_start != pos)
238             smsgs[msgp++].s_stop = (c == '\n' && wasdlm) ? pos - 1 : pos;
239         if (feof (in)) {
240 #ifdef  notdef
241             if (wasdlm) {
242                 smsgs[msgp - 1].s_stop -= ((long) strlen (buffer) + 1);
243                 msgp++;         /* fake "End of XXX Digest" */
244             }
245 #endif
246             break;
247         }
248         pos += (long) strlen (buffer);
249     }
250
251 /* \f */
252
253     switch (msgp--) {           /* toss "End of XXX Digest" */
254         case 0: 
255             adios (NULLCP, "burst() botch -- you lose big");
256
257         case 1: 
258             if (!quietsw)
259                 admonish (NULLCP, "message %d not in digest format", msgnum);
260             (void) fclose (in);
261             return;
262
263         default: 
264             if (verbosw)
265                 printf ("%d message%s exploded from digest %d\n",
266                         msgp, msgp != 1 ? "s" : "", msgnum);
267             break;
268     }
269     /* msgp now contains the number of new msgs to be created */
270
271     if ((mp = m_remsg (mp, 0, mp -> hghmsg + msgp)) == NULL)
272         adios (NULLCP, "unable to allocate folder storage");
273
274 /* \f */
275
276     j = mp -> hghmsg;           /* old value */
277     mp -> hghmsg += msgp;
278     mp -> nummsg += msgp;
279     if (mp -> hghsel > msgnum)
280         mp -> hghsel += msgp;
281
282     if (inplace)
283         for (i = mp -> hghmsg; j > msgnum; i--, j--) {
284             (void) strcpy (f1, m_name (i));
285             (void) strcpy (f2, m_name (j));
286             if (mp -> msgstats[j] & EXISTS) {
287                 if (verbosw)
288                     printf ("message %d becomes message %d\n", j, i);
289
290                 if (rename (f2, f1) == NOTOK)
291                     admonish (f1, "unable to rename %s to", f2);
292                 mp -> msgstats[i] = mp -> msgstats[j];
293                 mp -> msgstats[j] = 0;
294                 mp -> msgflags |= SEQMOD;
295             }
296         }
297     
298     mp -> msgstats[msgnum] &= ~SELECTED;
299     i = inplace ? msgnum + msgp : mp -> hghmsg; /* new hghmsg is hghmsg+msgp */
300     for (j = msgp; j >= (inplace ? 0 : 1); i--, j--) {
301         (void) strcpy (f1, m_name (i));
302         (void) strcpy (f2, m_scratch ("", invo_name));
303         if (verbosw && i != msgnum)
304             printf ("message %d of digest %d becomes message %d\n",
305                     j, msgnum, i);
306
307         if ((out = fopen (f2, "w")) == NULL)
308             adios (f2, "unable to write message");
309         (void) chmod (f2, mode);
310         (void) fseek (in, pos = smsgs[j].s_start, 0);
311         cpybrst (in, out, msgnam, f2,
312                 (int) (smsgs[j].s_stop - smsgs[j].s_start));
313         (void) fclose (out);
314
315         if (i == msgnum) {
316             (void) strcpy (f3, m_backup (f1));
317             if (rename (f1, f3) == NOTOK)
318                 admonish (f3, "unable to rename %s to", f1);
319         }
320         if (rename (f2, f1) == NOTOK)
321             admonish (f1, "unable to rename %s to", f2);
322         mp -> msgstats[i] = mp -> msgstats[msgnum];
323         mp -> msgflags |= SEQMOD;
324     }
325
326     (void) fclose (in);
327 }
328
329
330 /* \f */
331
332 #define S1      0
333 #define S2      1
334 #define S3      2
335
336 static cpybrst (in, out, ifile, ofile, len)
337 register FILE   *in,
338                 *out;
339 register char   *ifile,
340                 *ofile;
341 register int    len;
342 {
343     register int    c,
344                     state;
345
346     for (state = S1; (c = fgetc (in)) != EOF && len > 0; len--) {
347         if (c == 0)
348             continue;
349         switch (state) {
350             case S1: 
351                 switch (c) {
352                     case '-': 
353                         state = S3;
354                         break;
355
356                     default: 
357                         state = S2;
358                     case '\n': 
359                         (void) fputc (c, out);
360                         break;
361                 }
362                 break;
363
364             case S2: 
365                 switch (c) {
366                     case '\n': 
367                         state = S1;
368                     default: 
369                         (void) fputc (c, out);
370                         break;
371                 }
372                 break;
373
374             case S3: 
375                 switch (c) {
376                     case ' ': 
377                         state = S2;
378                         break;
379
380                     default: 
381                         state = c == '\n' ? S1 : S2;
382                         (void) fputc ('-', out);
383                         (void) fputc (c, out);
384                         break;
385                 }
386                 break;
387         }
388     }
389
390     if (ferror (in) && !feof (in))
391         adios (ifile, "error reading");
392     if (ferror (out))
393         adios (ofile, "error writing");
394 }