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