|
|
Initial revision
/* scansbr.c - routines to help scan along... */
#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>
#define MAXSCANL 510 /* longest possible scan line */
#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
* only going to display 30 characters
* of it.
*/
/* */
static struct format *fmt;
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[4]; /* aux. data for format routine */
#ifdef RPATHS
char *unixline(); /* info from UNIX From: line */
#endif RPATHS
#define FPUTS(buf) {\
if (fputs(buf,scnout) == EOF)\
adios (scnmsg, "write error on");\
}
/* */
/* ARGSUSED */
scan(inb, innum, outnum, nfs, width, curflg, header, size, noisy, aud)
register FILE *inb;
char *nfs;
int innum, outnum, width, curflg, header;
long size;
int noisy, aud;
{
int compnum, encrypted, state;
register int i;
register struct comp *cptr;
register char *tmpbuf;
register char **nxtbuf;
register struct comp **savecomp;
char *scnmsg;
FILE *scnout;
char name[NAMESZ];
static int slwidth;
#ifdef RPATHS
char *cp;
#endif RPATHS
/* first-time only initialization */
if (scanl == NULLCP) {
if (width == 0) {
if ((width = sc_width()) < WIDTH / 2)
width = WIDTH / 2;
else if (width > MAXSCANL)
width = MAXSCANL;
}
dat[3] = slwidth = width;
scanl = (char *) malloc((unsigned)MAXSCANL+2);
if (outnum)
(void) umask(~m_gmprot());
ncomps = fmt_compile(nfs, &fmt) + 1;
FINDCOMP(bodycomp, "body");
FINDCOMP(datecomp, "date");
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++;
}
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;
for (i = ncomps; i--;)
if ((*nxtbuf++ = malloc(SBUFSIZ)) == 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;
/*
* 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, SBUFSIZ, inb)) == FILEEOF)
return SCNEOF;
if (outnum) {
if (outnum > 0) {
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, SBUFSIZ, inb)) {
switch (state) {
case FLD:
case FLDPLUS:
compnum++;
if (outnum) {
FPUTS(name);
(void) putc(':', scnout);
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) {
cptr->c_text = tmpbuf;
*--savecomp = cptr;
tmpbuf = *nxtbuf++;
}
break;
}
} while (cptr = cptr->c_next);
while (state == FLDPLUS) {
state =
m_getfld(state, name, tmpbuf, SBUFSIZ, inb);
if (outnum)
FPUTS(tmpbuf);
}
break;
case BODY:
compnum = -1;
if (!outnum) {
state = FILEEOF; /* stop now if scan cmd */
goto finished;
}
(void) putc('\n', scnout);
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) {
if (scnout->_cnt <= 0) {
if (fflush(scnout) == EOF)
adios(scnmsg, "write error on");
}
state = m_getfld(state, name,
scnout->_ptr, -(scnout->_cnt), inb);
scnout->_cnt -= msg_count;
scnout->_ptr += msg_count;
}
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);
(void) putc('\n', scnout);
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 (noisy || aud) {
char *saved_c_text;
if (bodycomp) {
/* Save and restore buffer so we don't trash our
dynamic pool! */
saved_c_text = bodycomp->c_text;
bodycomp->c_text = tmpbuf;
}
if (size)
dat[2] = size;
else if (outnum > 0)
dat[2] = ftell(scnout);
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((long *) &st.st_mtime);
datecomp->c_flags = -1;
} else {
datecomp->c_flags = 0;
}
}
}
(void) fmtscan(fmt, scanl, slwidth, dat);
if (aud)
(void) fputs(scanl, aud);
if (noisy)
(void) fputs(scanl, stdout);
if (bodycomp)
bodycomp->c_text = saved_c_text;
}
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.
*/
/* XXX don't bother if linking with the shared library */
#ifndef SHARED
char *
OfficialName(name)
register char *name;
{
return name;
}
#endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.