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