Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / uip / scansbr.c
1 /* scansbr.c - routines to help scan along... */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: scansbr.c,v 1.16 1994/04/21 18:20:50 jromine Exp $";
4 #endif  /* lint */
5
6 #include "../h/mh.h"
7 #include "../h/addrsbr.h"
8 #include "../h/formatsbr.h"
9 #include "../h/scansbr.h"
10 #include "../zotnet/tws.h"
11 #include <stdio.h>
12 #include <ctype.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15
16 #ifdef _FSTDIO
17 #define       _ptr    _p              /* Gag */
18 #define       _cnt    _w              /* Wretch */
19 #endif
20
21 #define MAXSCANL 256            /* longest possible scan line */
22 #define SBUFSIZ 512             /* buffer size for content part of header
23                                  * fields.  We want this to be large
24                                  * enough so that we don't do a lot of
25                                  * extra FLDPLUS calls on m_getfld but
26                                  * small enough so that we don't snarf
27                                  * the entire message body when we're
28                                  * only going to display 30 characters
29                                  * of it.
30                                  */
31
32 /* \f */
33
34 static struct format *fmt;
35 #ifdef JLR
36 static struct format *fmt_top;
37 #endif /* JLR */
38
39 static struct comp *datecomp;           /* pntr to "date" comp */
40 static struct comp *bodycomp;           /* pntr to "body" pseudo-comp 
41                                          * (if referenced) */
42 static int      ncomps = 0;             /* # of interesting components */
43 static char     **compbuffers = 0;      /* buffers for component text */
44 static struct comp **used_buf = 0;      /* stack for comp that use buffers */
45
46 char            *scanl = 0;             /* text of most recent scanline */
47
48 static int  dat[5];                     /* aux. data for format routine */
49
50 #ifdef  RPATHS
51 char   *unixline ();                    /* info from UNIX From: line */
52 #endif  /* RPATHS */
53
54 #define FPUTS(buf) {\
55                 if (mh_fputs(buf,scnout) == EOF)\
56                     adios (scnmsg, "write error on");\
57                 }
58
59 /* \f */
60
61 /* ARGSUSED */
62
63 int     scan (inb, innum, outnum, nfs, width, curflg, unseen,
64                                         hdrflg, folder, size, noisy)
65 char    *nfs,
66         *folder;
67 int     innum,
68         outnum,
69         width,
70         curflg,
71         unseen,
72         hdrflg,
73         noisy;
74 long    size;
75 register FILE   *inb;
76 {
77     int     compnum,
78             encrypted,
79             state;
80     register int  i;
81     register char *cp;
82     register struct comp *cptr;
83     register char *tmpbuf;
84     register char **nxtbuf;
85     register struct comp **savecomp;
86     char    *scnmsg;
87     FILE    *scnout;
88     char    name[NAMESZ];
89     static  int rlwidth,
90                 slwidth;
91
92     /* first-time only initialization */
93     if (scanl == NULLCP) {
94         int     bigwid;
95
96         if (width == 0) {
97             if ((width = sc_width ()) < WIDTH/2)
98                 width = WIDTH/2;
99             else if (width > MAXSCANL)
100                 width = MAXSCANL;
101         }
102         dat[3] = slwidth = width;
103         if ((scanl = (char *)malloc( (unsigned) (slwidth + 2) )) == (char *)0)
104             adios (NULLCP, "unable to malloc scan line (%d bytes)", slwidth+2);
105         if (outnum)
106             (void) umask( ~ m_gmprot() );
107
108         ncomps = fmt_compile (nfs, &fmt) + 1;
109 #ifdef JLR
110         fmt_top = fmt;
111 #endif  /* JLR */
112         FINDCOMP(bodycomp, "body");
113         FINDCOMP(datecomp, "date");
114         FINDCOMP(cptr, "folder");
115         if (cptr && folder) {
116             cptr->c_text = folder;
117             cptr->c_flags = hdrflg;
118         }
119         FINDCOMP(cptr, "encrypted");
120         if (!cptr)
121             if (cptr = (struct comp *) calloc (1, sizeof *cptr)) {
122                 cptr -> c_name = "encrypted";
123                 cptr -> c_next = wantcomp[i = CHASH (cptr -> c_name)];
124                 wantcomp[i] = cptr;
125                 ncomps++;
126         }
127         FINDCOMP (cptr, "dtimenow");
128         if (cptr)
129             cptr->c_text = getcpy(dtimenow ());
130         nxtbuf = compbuffers = (char **)calloc((unsigned) ncomps,
131             sizeof(char *));
132         if (nxtbuf == NULL)
133             adios (NULLCP, "unable to allocate component buffers");
134         used_buf = (struct comp **)calloc((unsigned) (ncomps+1),
135             sizeof(struct comp *));
136         if (used_buf == NULL)
137             adios (NULLCP, "unable to allocate component buffer stack");
138         used_buf += ncomps+1; *--used_buf = 0;
139         rlwidth = bodycomp && (width > SBUFSIZ) ? width : SBUFSIZ;
140         for (i = ncomps; i--; )
141             if ((*nxtbuf++ = malloc( rlwidth )) == NULL)
142                 adios (NULLCP, "unable to allocate component buffer");
143     }
144     /* each-message initialization */
145     nxtbuf = compbuffers;
146     savecomp = used_buf;
147     tmpbuf = *nxtbuf++;
148     dat[0] = innum ? innum : outnum;
149     dat[1] = curflg;
150     dat[4] = unseen;
151
152     /*
153      * get the first field.  If the msg is non-empty and we're doing
154      * an "inc", open the output file.
155      */
156     if ((state = m_getfld (FLD, name, tmpbuf, rlwidth, inb)) == FILEEOF)
157         if (ferror(inb)) {
158             advise("read", "unable to"); /* "read error" */
159             return SCNFAT;
160         } else
161             return SCNEOF;
162
163     if (outnum) {
164         if (outnum > 0) {       /* Fix from Van -- I'm not sure why... */
165             scnmsg = m_name (outnum);
166             if (*scnmsg == '?') /* msg num out of range */
167                 return SCNNUM;
168         }
169         else
170             scnmsg = "/dev/null";
171         if ((scnout = fopen (scnmsg, "w")) == NULL)
172             adios (scnmsg, "unable to write");
173 #ifdef  RPATHS
174         if ((cp = unixline ()) && *cp != '\n') {
175             FPUTS ("Return-Path: ");
176             FPUTS (cp);
177         }
178 #endif  /* RPATHS */
179     }
180
181     /* scan - main loop */
182     for (compnum = 1; ; state = m_getfld (state, name, tmpbuf, rlwidth, inb)) {
183         switch (state) {
184             case FLD: 
185             case FLDPLUS: 
186                 compnum++;
187                 if (outnum) {
188                     FPUTS (name);
189                     (void) putc (':', scnout);
190                     FPUTS (tmpbuf);
191                 }
192                 /*
193                  * if we're interested in this component, save a pointer
194                  * to the component text, then start using our next free
195                  * buffer as the component temp buffer (buffer switching
196                  * saves an extra copy of the component text).
197                  */
198                 if (cptr = wantcomp[CHASH(name)])
199                     do {
200                         if (uleq(name, cptr->c_name)) {
201                             if (! cptr->c_text) {
202                                 cptr->c_text = tmpbuf;
203                                 for (cp = tmpbuf + strlen (tmpbuf) - 1; 
204                                         cp >= tmpbuf; cp--)
205                                     if (isspace (*cp))
206                                         *cp = 0;
207                                     else
208                                         break;
209                                 *--savecomp = cptr;
210                                 tmpbuf = *nxtbuf++;
211                             }
212                             break;
213                         }
214                     } while (cptr = cptr->c_next);
215
216                 while (state == FLDPLUS) {
217                     state = m_getfld (state, name, tmpbuf, rlwidth, inb);
218                     if (outnum)
219                         FPUTS (tmpbuf);
220                 }
221                 break;
222
223             case BODY: 
224                 compnum = -1;
225                 if (! outnum) {
226                     state = FILEEOF; /* stop now if scan cmd */
227                     goto finished;
228                 }
229                 (void) putc ('\n', scnout);
230                 FPUTS (tmpbuf);
231                 /*
232                  * performance hack: some people like to run "inc" on
233                  * things like net.sources or large digests.  We do a
234                  * copy directly into the output buffer rather than
235                  * going through an intermediate buffer.
236                  *
237                  * We need the amount of data m_getfld found & don't
238                  * want to do a strlen on the long buffer so there's
239                  * a hack in m_getfld to save the amount of data it
240                  * returned in the global "msg_count".
241                  */
242         body:   ;
243                 while (state == BODY) {
244                     if (scnout->_cnt <= 0) {
245                         if (fflush(scnout) == EOF)
246                             adios (scnmsg, "write error on");
247                     }
248                     state = m_getfld( state, name, scnout->_ptr,
249                                       -(scnout->_cnt), inb );
250                     scnout->_cnt -= msg_count;
251                     scnout->_ptr += msg_count;
252                 }
253                 goto finished;
254
255             case LENERR: 
256             case FMTERR: 
257                 fprintf (stderr, 
258                         innum ? "??Format error (message %d) in "
259                               : "??Format error in ",
260                         outnum ? outnum : innum);
261                 fprintf (stderr, "component %d\n", compnum);
262
263                 if (outnum) {
264                     FPUTS ("\n\nBAD MSG:\n");
265                     FPUTS (name);
266                     (void) putc ('\n', scnout);
267                     state = BODY;
268                     goto body;
269                 }
270                 /* fall through */
271
272             case FILEEOF:
273                 goto finished;
274
275             default: 
276                 adios (NULLCP, "getfld() returned %d", state);
277         }
278     }
279     /*
280      * format and output the scan line.
281      */
282 finished:
283     if (ferror(inb)) {
284         advise("read", "unable to"); /* "read error" */
285         return SCNFAT;
286     }
287     {
288         char *saved_c_text;
289
290         if (bodycomp) {
291             /* Save and restore buffer so we don't trash our dynamic pool! */
292             saved_c_text = bodycomp->c_text;
293             bodycomp->c_text = tmpbuf;
294         }
295
296         if (size)
297             dat[2] = size;
298         else if (outnum > 0)
299             dat[2] = ftell(scnout);
300
301         if ( (datecomp && ! datecomp->c_text) || (!size && !outnum)) {
302             struct stat st;
303             (void) fstat (fileno(inb), &st);
304             if (!size && !outnum)
305                 dat[2] = st.st_size;
306             if (datecomp) {
307                 if (! datecomp->c_text) {
308                     if (datecomp->c_tws == NULL)
309                         datecomp->c_tws = (struct tws *)
310                             calloc((unsigned) 1, sizeof(*datecomp->c_tws));
311                     if (datecomp->c_tws == NULL)
312                         adios (NULLCP, "unable to allocate tws buffer");
313                     *datecomp->c_tws = *dlocaltime ((long *) &st.st_mtime);
314                     datecomp->c_flags = -1;
315                 } else {
316                     datecomp->c_flags = 0;
317                 }
318             }
319         }
320 #ifndef JLR
321         (void) fmtscan (fmt, scanl, slwidth, dat);
322 #else   /* JLR */
323         fmt = fmtscan (fmt, scanl, slwidth, dat);
324         if (!fmt)
325             fmt = fmt_top;              /* reset for old format files */
326 #endif  /* JLR */
327
328         if (bodycomp)
329             bodycomp->c_text = saved_c_text;
330     }
331     if (noisy)
332         (void) fputs (scanl, stdout);
333
334     FINDCOMP (cptr, "encrypted");
335     encrypted = cptr && cptr -> c_text;
336     /* return dynamically allocated buffers to pool */
337     while ( cptr = *savecomp++ ) {
338         *--nxtbuf = cptr->c_text;
339         cptr->c_text = NULLCP;
340     }
341     *--nxtbuf = tmpbuf;
342
343     if (outnum && fclose (scnout) == EOF)
344         adios (scnmsg, "write error on");
345
346     return (state != FILEEOF ? SCNERR : encrypted ? SCNENC : SCNMSG);
347 }
348
349 /* \f */
350
351 /* Cheat:  we are loaded with adrparse, which wants a routine called
352    OfficialName().  We call adrparse:getm() with the correct arguments
353    to prevent OfficialName() from being called.  Hence, the following
354    is to keep the loader happy.
355  */
356
357 char   *OfficialName (name)
358 register char  *name;
359 {
360     return name;
361 }
362
363 mh_fputs(s, stream)
364 char *s;
365 FILE *stream;
366 {
367     char    c;
368     while(c = *s++) 
369         if(putc(c,stream) == EOF )
370             return(EOF);
371     return(0);
372 }