Added all of the MH sources, including RCS files, in
[mmh] / 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 }