Mercurial > hg > Applications > mh
diff uip/replsbr.c @ 0:bce86c4163a3
Initial revision
author | kono |
---|---|
date | Mon, 18 Apr 2005 23:46:02 +0900 |
parents | |
children | 441a2190cfae |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uip/replsbr.c Mon Apr 18 23:46:02 2005 +0900 @@ -0,0 +1,479 @@ +/* replsbr.c - routines to help repl along... */ +#ifndef lint +static char ident[] = "@(#)$Id$"; +#endif /* lint */ + +#include "../h/mh.h" +#include "../h/addrsbr.h" +#include "../h/formatsbr.h" +#include <ctype.h> +#include <stdio.h> +#include <sys/types.h> /* off_t */ +#include <sys/file.h> /* L_SET */ +#ifdef UNISTD +#include <unistd.h> +#endif + + +extern short ccto, /* from repl.c */ + cccc, + ccme, + format, + outputlinelen, + querysw; +extern int mime; +extern char *fcc, + *filter, + *form; + +static int dftype=0; + +static char *badaddrs = NULL; +static char *dfhost=NULL; + +static struct mailname mq={NULL}; + + +#define SBUFSIZ 256 + /* buffer size for content part of header + * fields. We want this to be large + * enough so that we don't do a lot of + * extra FLDPLUS calls on m_getfld but + * small enough so that we don't snarf + * the entire message body when we're + * not going to use any of it. + */ + +static struct format *fmt; + +static int ncomps = 0; /* # of interesting components */ +static char **compbuffers = 0; /* buffers for component text */ +static struct comp **used_buf = 0; /* stack for comp that use buffers */ + +static int dat[5]; /* aux. data for format routine */ + +static char *addrcomps[] = { + "from", + "sender", + "reply-to", + "to", + "cc", + "bcc", + "resent-from", + "resent-sender", + "resent-reply-to", + "resent-to", + "resent-cc", + "resent-bcc", + NULL +}; + +static insert(), replfilter(); +/* */ + +/* ARGSUSED */ + +replout (inb, msg, drft, mp) + register FILE *inb; + char *msg; + char *drft; + struct msgs *mp; +{ + register int state; + register int i; + register struct comp *cptr; + register char *tmpbuf; + register char **nxtbuf; + register struct comp **savecomp; + FILE *out; + char name[NAMESZ]; + char *scanl; + int char_read = 0; + char *cp; + int format_len; + register char **ap; + + (void) umask( ~ m_gmprot() ); + if ((out = fopen (drft, "w")) == NULL) + adios (drft, "unable to create"); + + cp = new_fs (form ? form : replcomps, NULLCP, NULLCP); + format_len = strlen (cp); + ncomps = fmt_compile (cp, &fmt) + 1; + if ((nxtbuf = compbuffers = (char **) + calloc((unsigned)ncomps,sizeof(char *))) + == (char **)NULL) + adios (NULLCP, "unable to allocate component buffers"); + if ((savecomp = used_buf = (struct comp **) + calloc((unsigned)(ncomps+1),sizeof(struct comp *))) + == (struct comp **)NULL) + adios (NULLCP, "unable to allocate component buffer stack"); + savecomp += ncomps + 1; + *--savecomp = (struct comp *)0; /* point at zero'd end minus 1 */ + for (i = ncomps; i--; ) + if ((*nxtbuf++ = malloc( SBUFSIZ )) == NULL) + adios (NULLCP, "unable to allocate component buffer"); + + nxtbuf = compbuffers; /* point at start */ + tmpbuf = *nxtbuf++; + + for (ap = addrcomps; *ap; ap++) { + FINDCOMP (cptr, *ap); + if (cptr) + cptr -> c_type |= CT_ADDR; + } + + /* ignore any components killed by command line switches */ + if (!ccto) { + FINDCOMP (cptr, "to"); + if (cptr) + cptr->c_name = ""; + } + if (!cccc) { + FINDCOMP (cptr, "cc"); + if (cptr) + cptr->c_name = ""; + } + /* set up the "fcc" pseudo-component */ + if (fcc) { + FINDCOMP (cptr, "fcc"); + if (cptr) + cptr->c_text = getcpy (fcc); + } + if (cp = getenv("USER")) { + FINDCOMP (cptr, "user"); + if (cptr) + cptr->c_text = getcpy(cp); + } + if (!ccme) + (void) ismymbox ((struct mailname *)0); /* XXX */ + + /* pick any interesting stuff out of msg "inb" */ + for (state = FLD;;) { + state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb); +#ifdef JAPAN + (void) ml_conv(tmpbuf); +#endif /* JAPAN */ + switch (state) { + case FLD: + case FLDPLUS: + /* + * if we're interested in this component, save a pointer + * to the component text, then start using our next free + * buffer as the component temp buffer (buffer switching + * saves an extra copy of the component text). + */ + if (cptr = wantcomp[CHASH(name)]) + do { + if (uleq(name, cptr->c_name)) { + char_read += msg_count; + if (! cptr->c_text) { + cptr->c_text = tmpbuf; + *--savecomp = cptr; + tmpbuf = *nxtbuf++; + } else { + i = strlen (cp = cptr->c_text) - 1; + if (cp[i] == '\n') + if (cptr->c_type & CT_ADDR) { + cp[i] = '\0'; + cp = add (",\n\t", cp); + } else { + cp = add ("\t", cp); + } + cptr->c_text = add (tmpbuf, cp); + } + while (state == FLDPLUS) { + state = m_getfld (state, name, tmpbuf, + SBUFSIZ, inb); +#ifdef JAPAN + (void) ml_conv(tmpbuf); +#endif /* JAPAN */ + cptr->c_text = add (tmpbuf, cptr->c_text); + char_read += msg_count; + } + break; + } + } while (cptr = cptr->c_next); + + while (state == FLDPLUS) + state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb); +#ifdef JAPAN + (void) ml_conv(tmpbuf); +#endif /* JAPAN */ + break; + + case LENERR: + case FMTERR: + case BODY: + case FILEEOF: + goto finished; + + default: + adios (NULLCP, "m_getfld() returned %d", state); + } + } + /* + * format and output the header lines. + */ +finished: + /* drop ending newline */ + for (i = 0; i < sizeof(wantcomp)/sizeof(wantcomp[0]); i++) + for (cptr = wantcomp[i]; cptr; cptr = cptr->c_next) + if (cptr->c_text && (cp = rindex(cptr->c_text, '\n')) && !cp[1]) + *cp = 0; + + /* if there's a "subject" component, strip any "re:"s off it */ + FINDCOMP (cptr, "subject") + if (cptr && (cp = cptr->c_text)) { + register char *sp = cp; + + for (;;) { + while (isspace(*cp & 0xff)) + cp++; + if(uprf(cp, "re:")) + cp += 3; + else + break; + sp = cp; + } + if (sp != cptr->c_text) { + cp = cptr->c_text; + cptr->c_text = getcpy (sp); + free (cp); + } + } + i = format_len + char_read + 256; + scanl = malloc ((unsigned)i + 2); + dat[0] = dat[1] = dat[2] = dat[4] = 0; + dat[3] = outputlinelen; + (void) fmtscan (fmt, scanl, i, dat); +#ifdef JAPAN + ml_fputs (scanl, out); +#else /* JAPAN */ + fputs (scanl, out); +#endif /* JAPAN */ + if (badaddrs) { + fputs ("\nrepl: bad addresses:\n", out); + fputs ( badaddrs, out); + } + if (filter) + replfilter (inb, out); +#ifdef MIME + else + if (mp && mime) + (void) fprintf (out, "#forw [original message] +%s %s\n", + mp -> foldpath, m_name (mp -> lowsel)); +#endif /* MIME */ + + if (ferror (out)) + adios (drft, "error writing"); + (void) fclose (out); + + /* return dynamically allocated buffers */ + free (scanl); + for (nxtbuf = compbuffers, i = ncomps; + cptr = *savecomp++; nxtbuf++, i--) + free (cptr->c_text); /* if not nxtbuf, nxtbuf already freed */ + while ( i-- > 0) + free (*nxtbuf++); /* free unused nxtbufs */ + free ((char *) compbuffers); + free ((char *) used_buf); +} + +/* */ + +static char *buf; /* our current working buffer */ +static char *bufend; /* end of working buffer */ +static char *last_dst; /* buf ptr at end of last call */ +static unsigned int bufsiz=0; /* current size of buf */ + +#define BUFINCR 512 /* how much to expand buf when if fills */ + +#define CPY(s) { cp = (s); while (*dst++ = *cp++) ; --dst; } + +/* check if there's enough room in buf for str. add more mem if needed */ +#define CHECKMEM(str) \ + if ((len = strlen (str) + 1) >= bufend - dst) {\ + int i = dst - buf;\ + int n = last_dst - buf;\ + bufsiz += ((dst + len - bufend) / BUFINCR + 1) * BUFINCR;\ + buf = realloc (buf, bufsiz);\ + dst = buf + i;\ + last_dst = buf + n;\ + if (! buf)\ + adios (NULLCP, "formataddr: couldn't get buffer space");\ + bufend = buf + bufsiz;\ + } + + +/* fmtscan will call this routine if the user includes the function + * "(formataddr {component})" in a format string. "orig" is the + * original contents of the string register. "str" is the address + * string to be formatted and concatenated onto orig. This routine + * returns a pointer to the concatenated address string. + * + * We try to not do a lot of malloc/copy/free's (which is why we + * don't call "getcpy") but still place no upper limit on the + * length of the result string. + */ +char *formataddr (orig, str) + char *orig; + char *str; +{ + register int len; + char baddr[BUFSIZ], + error[BUFSIZ]; + register int isgroup; + register char *dst; + register char *cp; + register char *sp; + register struct mailname *mp = NULL; + + /* if we don't have a buffer yet, get one */ + if (bufsiz == 0) { + buf = malloc (BUFINCR); + if (! buf) + adios (NULLCP, "formataddr: couldn't allocate buffer space"); + last_dst = buf; /* XXX */ + bufsiz = BUFINCR - 6; /* leave some slop */ + bufend = buf + bufsiz; + } + /* + * If "orig" points to our buffer we can just pick up where we + * left off. Otherwise we have to copy orig into our buffer. + */ + if (orig == buf) + dst = last_dst; + else if (!orig || !*orig) { + dst = buf; + *dst = '\0'; + } else { + dst = last_dst; /* XXX */ + CHECKMEM (orig); + CPY (orig); + } + + /* concatenate all the new addresses onto 'buf' */ + for (isgroup = 0; cp = getname (str); ) { + if ((mp = getm (cp, dfhost, dftype, AD_NAME, error)) == NULL) { + (void) sprintf (baddr, "\t%s -- %s\n", cp, error); + badaddrs = add (baddr, badaddrs); + continue; + } + if (isgroup && (mp->m_gname || !mp->m_ingrp)) { + *dst++ = ';'; + isgroup = 0; + } + if (insert (mp)) { + /* if we get here we're going to add an address */ + if (dst != buf) { + *dst++ = ','; + *dst++ = ' '; + } + if (mp->m_gname) { + CHECKMEM (mp->m_gname); + CPY (mp->m_gname); + isgroup++; + } + sp = adrformat (mp); + CHECKMEM (sp); + CPY (sp); + } + } + + if (isgroup) + *dst++ = ';'; + + *dst = '\0'; + last_dst = dst; + return (buf); +} +/* */ + +static insert (np) +register struct mailname *np; +{ + char buffer[BUFSIZ]; + register struct mailname *mp; + + if (np -> m_mbox == NULL) + return 0; + + for (mp = &mq; mp -> m_next; mp = mp -> m_next) { +#ifdef BERK + if (uleq (np -> m_mbox, mp -> m_next -> m_mbox)) + return 0; +#else /* not BERK */ + if (uleq (np -> m_host, mp -> m_next -> m_host) + && uleq (np -> m_mbox, mp -> m_next -> m_mbox)) + return 0; +#endif /* BERK */ + } + if (!ccme && ismymbox (np)) + return 0; + + if (querysw) { +#ifdef MIME_HEADERS + char *cp, *ep; + cp = adrformat (np); + if ((ep = malloc((unsigned)strlen(cp)+1)) == NULL) + adios (NULLCP, "out of memory"); + (void) exthdr_decode(cp, ep); + (void) sprintf (buffer, "Reply to %s? ", ep); + free(ep); +#else /* MIME_HEADERS */ + (void) sprintf (buffer, "Reply to %s? ", adrformat (np)); +#endif /* MIME_HEADERS */ + if (!gans (buffer, anoyes)) + return 0; + } + mp -> m_next = np; +#ifdef ISI + if (ismymbox (np)) + ccme = 0; +#endif /* ISI */ + return 1; +} + +/* */ + +static replfilter (in, out) +register FILE *in, + *out; +{ + int pid; + char *mhl; + + if (filter == NULL) + return; + + if (access (filter, 04) == NOTOK) + adios (filter, "unable to read"); + + mhl = r1bindex (mhlproc, '/'); + + rewind (in); + (void) lseek (fileno(in), (off_t)0, L_SET); + (void) fflush (out); + + switch (pid = vfork ()) { + case NOTOK: + adios ("fork", "unable to"); + + case OK: + (void) dup2 (fileno (in), fileno (stdin)); + (void) dup2 (fileno (out), fileno (stdout)); + closefds (3); + + execlp (mhlproc, mhl, "-form", filter, "-noclear", NULLCP); + fprintf (stderr, "unable to exec "); + perror (mhlproc); + _exit (-1); + + default: + if (pidXwait (pid, mhl)) + done (1); + (void) fseek (out, 0L, 2); + break; + } +}