]> diplodocus.org Git - nmh/blob - docs/historical/mh-6.8.5/uip/replsbr.c
sbr/mts.c: Delete mmdlm2; use same-valued mmdlm1 instead.
[nmh] / docs / historical / mh-6.8.5 / uip / replsbr.c
1 /* replsbr.c - routines to help repl along... */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: replsbr.c,v 1.19 1995/12/06 23:47:26 jromine Exp $";
4 #endif /* lint */
5
6 #include "../h/mh.h"
7 #include "../h/addrsbr.h"
8 #include "../h/formatsbr.h"
9 #include <ctype.h>
10 #include <stdio.h>
11 #include <sys/types.h> /* off_t */
12 #include <sys/file.h> /* L_SET */
13
14
15 extern short ccto, /* from repl.c */
16 cccc,
17 ccme,
18 format,
19 outputlinelen,
20 querysw;
21 extern int mime;
22 extern char *fcc,
23 *filter,
24 *form;
25
26 static int dftype=0;
27
28 static char *badaddrs = NULL;
29 static char *dfhost=NULL;
30
31 static struct mailname mq={NULL};
32
33
34 #define SBUFSIZ 256
35 /* buffer size for content part of header
36 * fields. We want this to be large
37 * enough so that we don't do a lot of
38 * extra FLDPLUS calls on m_getfld but
39 * small enough so that we don't snarf
40 * the entire message body when we're
41 * not going to use any of it.
42 */
43
44 static struct format *fmt;
45
46 static int ncomps = 0; /* # of interesting components */
47 static char **compbuffers = 0; /* buffers for component text */
48 static struct comp **used_buf = 0; /* stack for comp that use buffers */
49
50 static int dat[5]; /* aux. data for format routine */
51
52 static char *addrcomps[] = {
53 "from",
54 "sender",
55 "reply-to",
56 "to",
57 "cc",
58 "bcc",
59 "resent-from",
60 "resent-sender",
61 "resent-reply-to",
62 "resent-to",
63 "resent-cc",
64 "resent-bcc",
65 NULL
66 };
67
68 static insert(), replfilter();
69 /* \f */
70
71 /* ARGSUSED */
72
73 replout (inb, msg, drft, mp)
74 register FILE *inb;
75 char *msg;
76 char *drft;
77 struct msgs *mp;
78 {
79 register int state;
80 register int i;
81 register struct comp *cptr;
82 register char *tmpbuf;
83 register char **nxtbuf;
84 register struct comp **savecomp;
85 FILE *out;
86 char name[NAMESZ];
87 char *scanl;
88 int char_read = 0;
89 char *cp;
90 int format_len;
91 register char **ap;
92
93 (void) umask( ~ m_gmprot() );
94 if ((out = fopen (drft, "w")) == NULL)
95 adios (drft, "unable to create");
96
97 cp = new_fs (form ? form : replcomps, NULLCP, NULLCP);
98 format_len = strlen (cp);
99 ncomps = fmt_compile (cp, &fmt) + 1;
100 if ((nxtbuf = compbuffers = (char **)
101 calloc((unsigned)ncomps,sizeof(char *)))
102 == (char **)NULL)
103 adios (NULLCP, "unable to allocate component buffers");
104 if ((savecomp = used_buf = (struct comp **)
105 calloc((unsigned)(ncomps+1),sizeof(struct comp *)))
106 == (struct comp **)NULL)
107 adios (NULLCP, "unable to allocate component buffer stack");
108 savecomp += ncomps + 1;
109 *--savecomp = (struct comp *)0; /* point at zero'd end minus 1 */
110 for (i = ncomps; i--; )
111 if ((*nxtbuf++ = malloc( SBUFSIZ )) == NULL)
112 adios (NULLCP, "unable to allocate component buffer");
113
114 nxtbuf = compbuffers; /* point at start */
115 tmpbuf = *nxtbuf++;
116
117 for (ap = addrcomps; *ap; ap++) {
118 FINDCOMP (cptr, *ap);
119 if (cptr)
120 cptr -> c_type |= CT_ADDR;
121 }
122
123 /* ignore any components killed by command line switches */
124 if (!ccto) {
125 FINDCOMP (cptr, "to");
126 if (cptr)
127 cptr->c_name = "";
128 }
129 if (!cccc) {
130 FINDCOMP (cptr, "cc");
131 if (cptr)
132 cptr->c_name = "";
133 }
134 /* set up the "fcc" pseudo-component */
135 if (fcc) {
136 FINDCOMP (cptr, "fcc");
137 if (cptr)
138 cptr->c_text = getcpy (fcc);
139 }
140 if (cp = getenv("USER")) {
141 FINDCOMP (cptr, "user");
142 if (cptr)
143 cptr->c_text = getcpy(cp);
144 }
145 if (!ccme)
146 (void) ismymbox ((struct mailname *)0); /* XXX */
147
148 /* pick any interesting stuff out of msg "inb" */
149 for (state = FLD;;) {
150 state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb);
151 switch (state) {
152 case FLD:
153 case FLDPLUS:
154 /*
155 * if we're interested in this component, save a pointer
156 * to the component text, then start using our next free
157 * buffer as the component temp buffer (buffer switching
158 * saves an extra copy of the component text).
159 */
160 if (cptr = wantcomp[CHASH(name)])
161 do {
162 if (uleq(name, cptr->c_name)) {
163 char_read += msg_count;
164 if (! cptr->c_text) {
165 cptr->c_text = tmpbuf;
166 *--savecomp = cptr;
167 tmpbuf = *nxtbuf++;
168 } else {
169 i = strlen (cp = cptr->c_text) - 1;
170 if (cp[i] == '\n')
171 if (cptr->c_type & CT_ADDR) {
172 cp[i] = '\0';
173 cp = add (",\n\t", cp);
174 } else {
175 cp = add ("\t", cp);
176 }
177 cptr->c_text = add (tmpbuf, cp);
178 }
179 while (state == FLDPLUS) {
180 state = m_getfld (state, name, tmpbuf,
181 SBUFSIZ, inb);
182 cptr->c_text = add (tmpbuf, cptr->c_text);
183 char_read += msg_count;
184 }
185 break;
186 }
187 } while (cptr = cptr->c_next);
188
189 while (state == FLDPLUS)
190 state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb);
191 break;
192
193 case LENERR:
194 case FMTERR:
195 case BODY:
196 case FILEEOF:
197 goto finished;
198
199 default:
200 adios (NULLCP, "m_getfld() returned %d", state);
201 }
202 }
203 /*
204 * format and output the header lines.
205 */
206 finished:
207 /* if there's a "subject" component, strip any "re:"s off it */
208 FINDCOMP (cptr, "subject")
209 if (cptr && (cp = cptr->c_text)) {
210 register char *sp = cp;
211
212 for (;;) {
213 while (isspace(*cp))
214 cp++;
215 if(uprf(cp, "re:"))
216 cp += 3;
217 else
218 break;
219 sp = cp;
220 }
221 if (sp != cptr->c_text) {
222 cp = cptr->c_text;
223 cptr->c_text = getcpy (sp);
224 free (cp);
225 }
226 }
227 i = format_len + char_read + 256;
228 scanl = malloc ((unsigned)i + 2);
229 dat[0] = dat[1] = dat[2] = dat[4] = 0;
230 dat[3] = outputlinelen;
231 (void) fmtscan (fmt, scanl, i, dat);
232 fputs (scanl, out);
233 if (badaddrs) {
234 fputs ("\nrepl: bad addresses:\n", out);
235 fputs ( badaddrs, out);
236 }
237 if (filter)
238 replfilter (inb, out);
239 #ifdef MIME
240 else
241 if (mp && mime)
242 (void) fprintf (out, "#forw [original message] +%s %s\n",
243 mp -> foldpath, m_name (mp -> lowsel));
244 #endif /* MIME */
245
246 if (ferror (out))
247 adios (drft, "error writing");
248 (void) fclose (out);
249
250 /* return dynamically allocated buffers */
251 free (scanl);
252 for (nxtbuf = compbuffers, i = ncomps;
253 cptr = *savecomp++; nxtbuf++, i--)
254 free (cptr->c_text); /* if not nxtbuf, nxtbuf already freed */
255 while ( i-- > 0)
256 free (*nxtbuf++); /* free unused nxtbufs */
257 free ((char *) compbuffers);
258 free ((char *) used_buf);
259 }
260
261 /* \f */
262
263 static char *buf; /* our current working buffer */
264 static char *bufend; /* end of working buffer */
265 static char *last_dst; /* buf ptr at end of last call */
266 static unsigned int bufsiz=0; /* current size of buf */
267
268 #define BUFINCR 512 /* how much to expand buf when if fills */
269
270 #define CPY(s) { cp = (s); while (*dst++ = *cp++) ; --dst; }
271
272 /* check if there's enough room in buf for str. add more mem if needed */
273 #define CHECKMEM(str) \
274 if ((len = strlen (str) + 1) >= bufend - dst) {\
275 int i = dst - buf;\
276 int n = last_dst - buf;\
277 bufsiz += ((dst + len - bufend) / BUFINCR + 1) * BUFINCR;\
278 buf = realloc (buf, bufsiz);\
279 dst = buf + i;\
280 last_dst = buf + n;\
281 if (! buf)\
282 adios (NULLCP, "formataddr: couldn't get buffer space");\
283 bufend = buf + bufsiz;\
284 }
285
286
287 /* fmtscan will call this routine if the user includes the function
288 * "(formataddr {component})" in a format string. "orig" is the
289 * original contents of the string register. "str" is the address
290 * string to be formatted and concatenated onto orig. This routine
291 * returns a pointer to the concatenated address string.
292 *
293 * We try to not do a lot of malloc/copy/free's (which is why we
294 * don't call "getcpy") but still place no upper limit on the
295 * length of the result string.
296 */
297 char *formataddr (orig, str)
298 char *orig;
299 char *str;
300 {
301 register int len;
302 char baddr[BUFSIZ],
303 error[BUFSIZ];
304 register int isgroup;
305 register char *dst;
306 register char *cp;
307 register char *sp;
308 register struct mailname *mp = NULL;
309
310 /* if we don't have a buffer yet, get one */
311 if (bufsiz == 0) {
312 buf = malloc (BUFINCR);
313 if (! buf)
314 adios (NULLCP, "formataddr: couldn't allocate buffer space");
315 last_dst = buf; /* XXX */
316 bufsiz = BUFINCR - 6; /* leave some slop */
317 bufend = buf + bufsiz;
318 }
319 /*
320 * If "orig" points to our buffer we can just pick up where we
321 * left off. Otherwise we have to copy orig into our buffer.
322 */
323 if (orig == buf)
324 dst = last_dst;
325 else if (!orig || !*orig) {
326 dst = buf;
327 *dst = '\0';
328 } else {
329 dst = last_dst; /* XXX */
330 CHECKMEM (orig);
331 CPY (orig);
332 }
333
334 /* concatenate all the new addresses onto 'buf' */
335 for (isgroup = 0; cp = getname (str); ) {
336 if ((mp = getm (cp, dfhost, dftype, AD_NAME, error)) == NULL) {
337 (void) sprintf (baddr, "\t%s -- %s\n", cp, error);
338 badaddrs = add (baddr, badaddrs);
339 continue;
340 }
341 if (isgroup && (mp->m_gname || !mp->m_ingrp)) {
342 *dst++ = ';';
343 isgroup = 0;
344 }
345 if (insert (mp)) {
346 /* if we get here we're going to add an address */
347 if (dst != buf) {
348 *dst++ = ',';
349 *dst++ = ' ';
350 }
351 if (mp->m_gname) {
352 CHECKMEM (mp->m_gname);
353 CPY (mp->m_gname);
354 isgroup++;
355 }
356 sp = adrformat (mp);
357 CHECKMEM (sp);
358 CPY (sp);
359 }
360 }
361
362 if (isgroup)
363 *dst++ = ';';
364
365 *dst = '\0';
366 last_dst = dst;
367 return (buf);
368 }
369 /* \f */
370
371 static insert (np)
372 register struct mailname *np;
373 {
374 char buffer[BUFSIZ];
375 register struct mailname *mp;
376
377 if (np -> m_mbox == NULL)
378 return 0;
379
380 for (mp = &mq; mp -> m_next; mp = mp -> m_next) {
381 #ifdef BERK
382 if (uleq (np -> m_mbox, mp -> m_next -> m_mbox))
383 return 0;
384 #else /* not BERK */
385 if (uleq (np -> m_host, mp -> m_next -> m_host)
386 && uleq (np -> m_mbox, mp -> m_next -> m_mbox))
387 return 0;
388 #endif /* BERK */
389 }
390 if (!ccme && ismymbox (np))
391 return 0;
392
393 if (querysw) {
394 (void) sprintf (buffer, "Reply to %s? ", adrformat (np));
395 if (!gans (buffer, anoyes))
396 return 0;
397 }
398 mp -> m_next = np;
399 #ifdef ISI
400 if (ismymbox (np))
401 ccme = 0;
402 #endif /* ISI */
403 return 1;
404 }
405
406 /* \f */
407
408 static replfilter (in, out)
409 register FILE *in,
410 *out;
411 {
412 int pid;
413 char *mhl;
414
415 if (filter == NULL)
416 return;
417
418 if (access (filter, 04) == NOTOK)
419 adios (filter, "unable to read");
420
421 mhl = r1bindex (mhlproc, '/');
422
423 rewind (in);
424 (void) lseek (fileno(in), (off_t)0, L_SET);
425 (void) fflush (out);
426
427 switch (pid = vfork ()) {
428 case NOTOK:
429 adios ("fork", "unable to");
430
431 case OK:
432 (void) dup2 (fileno (in), fileno (stdin));
433 (void) dup2 (fileno (out), fileno (stdout));
434 closefds (3);
435
436 execlp (mhlproc, mhl, "-form", filter, "-noclear", NULLCP);
437 fprintf (stderr, "unable to exec ");
438 perror (mhlproc);
439 _exit (-1);
440
441 default:
442 if (pidXwait (pid, mhl))
443 done (1);
444 (void) fseek (out, 0L, 2);
445 break;
446 }
447 }