Mercurial > hg > Applications > mh
diff uip/scansbr.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/scansbr.c Mon Apr 18 23:46:02 2005 +0900 @@ -0,0 +1,402 @@ +/* scansbr.c - routines to help scan along... */ +#ifndef lint +static char ident[] = "@(#)$Id$"; +#endif /* lint */ + +#include "../h/mh.h" +#include "../h/addrsbr.h" +#include "../h/formatsbr.h" +#include "../h/scansbr.h" +#include "../zotnet/tws.h" +#include <stdio.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> + +#ifdef FILE__PTR +#define _ptr __ptr +#define _cnt __cnt +#endif + +#ifdef _FSTDIO +#define _ptr _p /* Gag */ +#define _cnt _w /* Wretch */ +#endif + +#define MAXSCANL 256 /* longest possible scan line */ +#define SBUFSIZ 512 /* 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 + * only going to display 30 characters + * of it. + */ + +/* */ + +static struct format *fmt; +#ifdef JLR +static struct format *fmt_top; +#endif /* JLR */ + +static struct comp *datecomp; /* pntr to "date" comp */ +static struct comp *bodycomp; /* pntr to "body" pseudo-comp + * (if referenced) */ +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 */ + +char *scanl = 0; /* text of most recent scanline */ + +static int dat[5]; /* aux. data for format routine */ + +#ifdef RPATHS +char *unixline (); /* info from UNIX From: line */ +#endif /* RPATHS */ + +#define FPUTS(buf) {\ + if (mh_fputs(buf,scnout) == EOF)\ + adios (scnmsg, "write error on");\ + } + +/* */ + +/* ARGSUSED */ + +int scan (inb, innum, outnum, nfs, width, curflg, unseen, + hdrflg, folder, size, noisy) +char *nfs, + *folder; +int innum, + outnum, + width, + curflg, + unseen, + hdrflg, + noisy; +long size; +register FILE *inb; +{ + int compnum, + encrypted, + state; + register int i; + register char *cp; + register struct comp *cptr; + register char *tmpbuf; + register char **nxtbuf; + register struct comp **savecomp; + char *scnmsg; + FILE *scnout; + char name[NAMESZ]; + static int rlwidth, + slwidth; + + /* first-time only initialization */ + if (scanl == NULLCP) { + int bigwid; + + if (width == 0) { + if ((width = sc_width ()) < WIDTH/2) + width = WIDTH/2; + else if (width > MAXSCANL) + width = MAXSCANL; + } + dat[3] = slwidth = width; + if ((scanl = (char *)malloc( (unsigned) (slwidth + 2) )) == (char *)0) + adios (NULLCP, "unable to malloc scan line (%d bytes)", slwidth+2); + if (outnum) + (void) umask( ~ m_gmprot() ); + + ncomps = fmt_compile (nfs, &fmt) + 1; +#ifdef JLR + fmt_top = fmt; +#endif /* JLR */ + FINDCOMP(bodycomp, "body"); + FINDCOMP(datecomp, "date"); + FINDCOMP(cptr, "folder"); + if (cptr && folder) { + cptr->c_text = folder; + cptr->c_flags = hdrflg; + } + FINDCOMP(cptr, "encrypted"); + if (!cptr) + if (cptr = (struct comp *) calloc (1, sizeof *cptr)) { + cptr -> c_name = "encrypted"; + cptr -> c_next = wantcomp[i = CHASH (cptr -> c_name)]; + wantcomp[i] = cptr; + ncomps++; + } + FINDCOMP (cptr, "dtimenow"); + if (cptr) + cptr->c_text = getcpy(dtimenow ()); + nxtbuf = compbuffers = (char **)calloc((unsigned) ncomps, + sizeof(char *)); + if (nxtbuf == NULL) + adios (NULLCP, "unable to allocate component buffers"); + used_buf = (struct comp **)calloc((unsigned) (ncomps+1), + sizeof(struct comp *)); + if (used_buf == NULL) + adios (NULLCP, "unable to allocate component buffer stack"); + used_buf += ncomps+1; *--used_buf = 0; + rlwidth = bodycomp && (width > SBUFSIZ) ? width : SBUFSIZ; + for (i = ncomps; i--; ) + if ((*nxtbuf++ = malloc( rlwidth )) == NULL) + adios (NULLCP, "unable to allocate component buffer"); + } + /* each-message initialization */ + nxtbuf = compbuffers; + savecomp = used_buf; + tmpbuf = *nxtbuf++; + dat[0] = innum ? innum : outnum; + dat[1] = curflg; + dat[4] = unseen; + + /* + * get the first field. If the msg is non-empty and we're doing + * an "inc", open the output file. + */ + if ((state = m_getfld (FLD, name, tmpbuf, rlwidth, inb)) == FILEEOF) + if (ferror(inb)) { + advise("read", "unable to"); /* "read error" */ + return SCNFAT; + } else + return SCNEOF; + + if (outnum) { + if (outnum > 0) { /* Fix from Van -- I'm not sure why... */ + scnmsg = m_name (outnum); + if (*scnmsg == '?') /* msg num out of range */ + return SCNNUM; + } + else + scnmsg = "/dev/null"; + if ((scnout = fopen (scnmsg, "w")) == NULL) + adios (scnmsg, "unable to write"); +#ifdef RPATHS + if ((cp = unixline ()) && *cp != '\n') { + FPUTS ("Return-Path: "); + FPUTS (cp); + } +#endif /* RPATHS */ + } + + /* scan - main loop */ + for (compnum = 1; ; state = m_getfld (state, name, tmpbuf, rlwidth, inb)) { + switch (state) { + case FLD: + case FLDPLUS: + compnum++; + if (outnum) { + FPUTS (name); + if (putc (':', scnout) == EOF) + adios (scnmsg, "write error on"); + FPUTS (tmpbuf); + } + /* + * 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)) { + if (! cptr->c_text) { +#ifdef JAPAN + (void) ml_conv(tmpbuf); +#endif /* JAPAN */ + cptr->c_text = tmpbuf; + for (cp = tmpbuf + strlen (tmpbuf) - 1; + cp >= tmpbuf; cp--) + if (isspace (*cp & 0xff)) + *cp = 0; + else + break; + *--savecomp = cptr; + tmpbuf = *nxtbuf++; + } + break; + } + } while (cptr = cptr->c_next); + + while (state == FLDPLUS) { + state = m_getfld (state, name, tmpbuf, rlwidth, inb); + if (outnum) + FPUTS (tmpbuf); + } + break; + + case BODY: + compnum = -1; + if (! outnum) { + state = FILEEOF; /* stop now if scan cmd */ + goto finished; + } + if (putc ('\n', scnout) == EOF) + adios (scnmsg, "write error on"); + FPUTS (tmpbuf); + /* + * performance hack: some people like to run "inc" on + * things like net.sources or large digests. We do a + * copy directly into the output buffer rather than + * going through an intermediate buffer. + * + * We need the amount of data m_getfld found & don't + * want to do a strlen on the long buffer so there's + * a hack in m_getfld to save the amount of data it + * returned in the global "msg_count". + */ + body: ; + while (state == BODY) { +#ifdef _STDIO_USES_IOSTREAM + if (scnout->_IO_write_ptr == scnout->_IO_write_end) { +#else + if (scnout->_cnt <= 0) { +#endif + if (fflush(scnout) == EOF) + adios (scnmsg, "write error on"); + } +#ifdef _STDIO_USES_IOSTREAM + state = m_getfld(state, name, scnout->_IO_write_ptr, + (long)scnout->_IO_write_ptr-(long)scnout->_IO_write_end, + inb); + scnout->_IO_write_ptr += msg_count; +#else + state = m_getfld( state, name, scnout->_ptr, + -(scnout->_cnt), inb ); + scnout->_cnt -= msg_count; + scnout->_ptr += msg_count; +#endif + } + goto finished; + + case LENERR: + case FMTERR: + fprintf (stderr, + innum ? "??Format error (message %d) in " + : "??Format error in ", + outnum ? outnum : innum); + fprintf (stderr, "component %d\n", compnum); + + if (outnum) { + FPUTS ("\n\nBAD MSG:\n"); + FPUTS (name); + if (putc ('\n', scnout) == EOF) + adios (scnmsg, "write error on"); + state = BODY; + goto body; + } + /* fall through */ + + case FILEEOF: + goto finished; + + default: + adios (NULLCP, "getfld() returned %d", state); + } + } + /* + * format and output the scan line. + */ +finished: + if (ferror(inb)) { + advise("read", "unable to"); /* "read error" */ + return SCNFAT; + } + { + char *saved_c_text; + + if (bodycomp) { + /* Save and restore buffer so we don't trash our dynamic pool! */ + saved_c_text = bodycomp->c_text; +#ifdef JAPAN + (void) ml_conv(tmpbuf); +#endif /* JAPAN */ + bodycomp->c_text = tmpbuf; + } + + if (size) + dat[2] = size; + else if (outnum > 0) + if ((dat[2] = ftell(scnout)) == EOF) + adios (scnmsg, "write error on"); + + if ( (datecomp && ! datecomp->c_text) || (!size && !outnum)) { + struct stat st; + (void) fstat (fileno(inb), &st); + if (!size && !outnum) + dat[2] = st.st_size; + if (datecomp) { + if (! datecomp->c_text) { + if (datecomp->c_tws == NULL) + datecomp->c_tws = (struct tws *) + calloc((unsigned) 1, sizeof(*datecomp->c_tws)); + if (datecomp->c_tws == NULL) + adios (NULLCP, "unable to allocate tws buffer"); + *datecomp->c_tws = *dlocaltime ((time_t *) &st.st_mtime); + datecomp->c_flags = -1; + } else { + datecomp->c_flags = 0; + } + } + } +#ifndef JLR + (void) fmtscan (fmt, scanl, slwidth, dat); +#else /* JLR */ + fmt = fmtscan (fmt, scanl, slwidth, dat); + if (!fmt) + fmt = fmt_top; /* reset for old format files */ +#endif /* JLR */ + + if (bodycomp) + bodycomp->c_text = saved_c_text; + } + if (noisy) +#ifdef JAPAN + ml_fputs (scanl, stdout); +#else /* JAPAN */ + (void) fputs (scanl, stdout); +#endif /* JAPAN */ + + FINDCOMP (cptr, "encrypted"); + encrypted = cptr && cptr -> c_text; + /* return dynamically allocated buffers to pool */ + while ( cptr = *savecomp++ ) { + *--nxtbuf = cptr->c_text; + cptr->c_text = NULLCP; + } + *--nxtbuf = tmpbuf; + + if (outnum && fclose (scnout) == EOF) + adios (scnmsg, "write error on"); + + return (state != FILEEOF ? SCNERR : encrypted ? SCNENC : SCNMSG); +} + +/* */ + +/* Cheat: we are loaded with adrparse, which wants a routine called + OfficialName(). We call adrparse:getm() with the correct arguments + to prevent OfficialName() from being called. Hence, the following + is to keep the loader happy. + */ + +char *OfficialName (name) +register char *name; +{ + return name; +} + +mh_fputs(s, stream) +char *s; +FILE *stream; +{ + char c; + while(c = *s++) + if(putc(c,stream) == EOF ) + return(EOF); + return(0); +}