1: /* scansbr.c - routines to help scan along... */ 2: 3: #include "../h/mh.h" 4: #include "../h/addrsbr.h" 5: #include "../h/formatsbr.h" 6: #include "../h/scansbr.h" 7: #include "../zotnet/tws.h" 8: #include <stdio.h> 9: #include <ctype.h> 10: #include <sys/types.h> 11: #include <sys/stat.h> 12: 13: 14: #define MAXSCANL 256 /* longest possible scan line */ 15: #define SBUFSIZ 128 /* buffer size for content part of header 16: * fields. We want this to be large 17: * enough so that we don't do a lot of 18: * extra FLDPLUS calls on m_getfld but 19: * small enough so that we don't snarf 20: * the entire message body when we're 21: * only going to display 30 characters 22: * of it. 23: */ 24: 25: /* */ 26: 27: static struct format *fmt; 28: 29: static struct comp *datecomp; /* pntr to "date" comp */ 30: static struct comp *bodycomp; /* pntr to "body" pseudo-comp 31: * (if referenced) */ 32: static int ncomps = 0; /* # of interesting components */ 33: static char **compbuffers = 0; /* buffers for component text */ 34: static struct comp **used_buf = 0; /* stack for comp that use buffers */ 35: 36: char *scanl = 0; /* text of most recent scanline */ 37: 38: static int dat[4]; /* aux. data for format routine */ 39: 40: #ifdef RPATHS 41: char *unixline (); /* info from UNIX From: line */ 42: #endif RPATHS 43: 44: #define FPUTS(buf) {\ 45: if (fputs(buf,scnout) == EOF)\ 46: adios (scnmsg, "write error on");\ 47: } 48: 49: /* */ 50: 51: /* ARGSUSED */ 52: 53: int scan (inb, innum, outnum, nfs, width, curflg, header, size, noisy) 54: char *nfs; 55: int innum, 56: outnum, 57: width, 58: curflg, 59: header, 60: noisy; 61: long size; 62: register FILE *inb; 63: { 64: int compnum, 65: state; 66: register int i; 67: register struct comp *cptr; 68: register char *tmpbuf; 69: register char **nxtbuf; 70: register struct comp **savecomp; 71: char *scnmsg; 72: FILE *scnout; 73: char name[NAMESZ]; 74: static int slwidth; 75: #ifdef RPATHS 76: char *cp; 77: #endif RPATHS 78: 79: /* first-time only initialization */ 80: if (scanl == NULLCP) { 81: if (width == 0) { 82: if ((width = sc_width ()) < WIDTH/2) 83: width = WIDTH/2; 84: else if (width > MAXSCANL) 85: width = MAXSCANL; 86: } 87: dat[3] = slwidth = width; 88: scanl = (char *)malloc( (unsigned) (slwidth + 2) ); 89: if (outnum) 90: (void) umask( ~ m_gmprot() ); 91: 92: ncomps = fmt_compile (nfs, &fmt) + 1; 93: FINDCOMP(bodycomp, "body"); 94: FINDCOMP(datecomp, "date"); 95: nxtbuf = compbuffers = (char **)calloc((unsigned) ncomps,sizeof(char *)); 96: used_buf = (struct comp **)calloc((unsigned) (ncomps+1),sizeof(struct comp *)); 97: used_buf += ncomps+1; *--used_buf = 0; 98: for (i = ncomps; i--; ) 99: *nxtbuf++ = malloc( SBUFSIZ ); 100: } 101: /* each-message initialization */ 102: nxtbuf = compbuffers; 103: savecomp = used_buf; 104: tmpbuf = *nxtbuf++; 105: dat[0] = innum? innum : outnum; 106: dat[1] = curflg; 107: 108: /* 109: * get the first field. If the msg is non-empty and we're doing 110: * an "inc", open the output file. 111: */ 112: if ((state = m_getfld (FLD, name, tmpbuf, SBUFSIZ, inb)) == FILEEOF) 113: return SCNEOF; 114: 115: if (outnum) { 116: scnmsg = m_name (outnum); 117: if (*scnmsg == '?') /* msg num out of range */ 118: return SCNNUM; 119: if ((scnout = fopen (scnmsg, "w")) == NULL) 120: adios (scnmsg, "unable to write"); 121: #ifdef RPATHS 122: if ((cp = unixline ()) && *cp) { 123: FPUTS ("Return-Path: "); 124: FPUTS (cp); 125: } 126: #endif RPATHS 127: } 128: 129: /* scan - main loop */ 130: for (compnum = 1; ; state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb)) { 131: switch (state) { 132: case FLD: 133: case FLDPLUS: 134: compnum++; 135: if (outnum) { 136: FPUTS (name); 137: (void) putc (':', scnout); 138: FPUTS (tmpbuf); 139: } 140: /* 141: * if we're interested in this component, save a pointer 142: * to the component text, then start using our next free 143: * buffer as the component temp buffer (buffer switching 144: * saves an extra copy of the component text). 145: */ 146: if (cptr = wantcomp[CHASH(name)]) 147: do { 148: if (uleq(name, cptr->c_name)) { 149: if (! cptr->c_text) { 150: cptr->c_text = tmpbuf; 151: *--savecomp = cptr; 152: tmpbuf = *nxtbuf++; 153: } 154: break; 155: } 156: } while (cptr = cptr->c_next); 157: 158: while (state == FLDPLUS) { 159: state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb); 160: if (outnum) 161: FPUTS (tmpbuf); 162: } 163: break; 164: 165: case BODY: 166: compnum = -1; 167: if (! outnum) { 168: state = FILEEOF; /* stop now if scan cmd */ 169: goto finished; 170: } 171: (void) putc ('\n', scnout); 172: FPUTS (tmpbuf); 173: /* 174: * performance hack: some people like to run "inc" on 175: * things like net.sources or large digests. We do a 176: * copy directly into the output buffer rather than 177: * going through an intermediate buffer. 178: * 179: * We need the amount of data m_getfld found & don't 180: * want to do a strlen on the long buffer so there's 181: * a hack in m_getfld to save the amount of data it 182: * returned in the global "msg_count". 183: */ 184: body: ; 185: while (state == BODY) { 186: if (scnout->_cnt <= 0) { 187: if (fflush(scnout) == EOF) 188: adios (scnmsg, "write error on"); 189: } 190: state = m_getfld( state, name, scnout->_ptr, 191: -(scnout->_cnt), inb ); 192: scnout->_cnt -= msg_count; 193: scnout->_ptr += msg_count; 194: } 195: goto finished; 196: 197: case LENERR: 198: case FMTERR: 199: fprintf (stderr, 200: innum ? "??Format error (message %d) in " 201: : "??Format error in ", 202: outnum ? outnum : innum); 203: fprintf (stderr, "component %d\n", compnum); 204: 205: if (outnum) { 206: FPUTS ("\n\nBAD MSG:\n"); 207: FPUTS (name); 208: (void) putc ('\n', scnout); 209: state = BODY; 210: goto body; 211: } 212: /* fall through */ 213: 214: case FILEEOF: 215: goto finished; 216: 217: default: 218: adios (NULLCP, "getfld() returned %d\n", state); 219: } 220: } 221: /* 222: * format and output the scan line. 223: */ 224: finished: 225: if (noisy) { 226: if (bodycomp) 227: bodycomp->c_text = tmpbuf; 228: 229: if (size) 230: dat[2] = size; 231: else if (outnum) 232: dat[2] = ftell(scnout); 233: 234: if ( (datecomp && ! datecomp->c_text) || (!size && !outnum)) { 235: struct stat st; 236: (void) fstat (fileno(inb), &st); 237: if (!size && !outnum) 238: dat[2] = st.st_size; 239: if (datecomp) { 240: if (! datecomp->c_text) { 241: *datecomp->c_tws = *dlocaltime ((long *) &st.st_mtime); 242: datecomp->c_flags = -1; 243: } else { 244: datecomp->c_flags = 0; 245: } 246: } 247: } 248: (void) fmtscan (fmt, scanl, slwidth, dat); 249: (void) fputs (scanl, stdout); 250: 251: if (bodycomp) 252: bodycomp->c_text = NULLCP; 253: } 254: 255: /* return dynamically allocated buffers to pool */ 256: while ( cptr = *savecomp++ ) { 257: *--nxtbuf = cptr->c_text; 258: cptr->c_text = NULLCP; 259: } 260: *--nxtbuf = tmpbuf; 261: 262: if (outnum) 263: if (fclose (scnout) == EOF) 264: adios (scnmsg, "write error on"); 265: 266: return (state == FILEEOF? SCNMSG : SCNERR); 267: } 268: 269: /* */ 270: 271: /* Cheat: we are loaded with adrparse, which wants a routine called 272: OfficialName(). We call adrparse:getm() with the correct arguments 273: to prevent OfficialName() from being called. Hence, the following 274: is to keep the loader happy. 275: */ 276: 277: char *OfficialName (name) 278: register char *name; 279: { 280: return name; 281: }