]> diplodocus.org Git - nmh/blob - docs/historical/mh-6.8.5/uip/scansbr.c
sbr/mts.c: Delete mmdlm2; use same-valued mmdlm1 instead.
[nmh] / 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 }