1: /* replsbr.c - routines to help repl along... */ 2: 3: #include "../h/mh.h" 4: #include "../h/addrsbr.h" 5: #include "../h/formatsbr.h" 6: #include <ctype.h> 7: #include <stdio.h> 8: 9: 10: extern short ccto, /* from repl.c */ 11: cccc, 12: ccme, 13: format, 14: outputlinelen, 15: querysw; 16: extern char *fcc, 17: *filter, 18: *form; 19: 20: static int dftype; 21: 22: static char *badaddrs = NULL; 23: static char *dfhost; 24: 25: static struct mailname mq; 26: 27: 28: #define SBUFSIZ 256 /* buffer size for content part of header 29: * fields. We want this to be large 30: * enough so that we don't do a lot of 31: * extra FLDPLUS calls on m_getfld but 32: * small enough so that we don't snarf 33: * the entire message body when we're 34: * not going to use any of it. 35: */ 36: 37: static struct format *fmt; 38: 39: static int ncomps = 0; /* # of interesting components */ 40: static char **compbuffers = 0; /* buffers for component text */ 41: static struct comp **used_buf = 0; /* stack for comp that use buffers */ 42: 43: static int dat[4]; /* aux. data for format routine */ 44: 45: /* */ 46: 47: /* ARGSUSED */ 48: 49: replout (inb, msg, drft) 50: register FILE *inb; 51: char *msg; 52: char *drft; 53: { 54: register int state; 55: register int i; 56: register struct comp *cptr; 57: register char *tmpbuf; 58: register char **nxtbuf; 59: register struct comp **savecomp; 60: FILE *out; 61: char name[NAMESZ]; 62: char *scanl; 63: int char_read = 0; 64: char *cp; 65: int format_len; 66: 67: (void) umask( ~ m_gmprot() ); 68: if ((out = fopen (drft, "w")) == NULL) 69: adios (drft, "unable to create"); 70: 71: cp = new_fs (form ? form : replcomps, NULLCP, NULLCP); 72: format_len = strlen (cp); 73: ncomps = fmt_compile (cp, &fmt) + 1; 74: nxtbuf = compbuffers = (char **)calloc((unsigned)ncomps,sizeof(char *)); 75: if (nxtbuf == NULL) 76: adios (NULLCP, "unable to allocate component buffers"); 77: used_buf = (struct comp **)calloc((unsigned)(ncomps+1),sizeof(struct comp *)); 78: if (used_buf == NULL) 79: adios (NULLCP, "unable to allocate component buffer stack"); 80: used_buf += ncomps+1; *--used_buf = 0; 81: for (i = ncomps; i--; ) 82: if ((*nxtbuf++ = malloc( SBUFSIZ )) == NULL) 83: adios (NULLCP, "unable to allocate component buffer"); 84: 85: nxtbuf = compbuffers; 86: savecomp = used_buf; 87: tmpbuf = *nxtbuf++; 88: 89: /* ignore any components killed by command line switches */ 90: if (!ccto) { 91: FINDCOMP (cptr, "to"); 92: if (cptr) 93: cptr->c_name = ""; 94: } 95: if (!cccc) { 96: FINDCOMP (cptr, "cc"); 97: if (cptr) 98: cptr->c_name = ""; 99: } 100: /* set up the "fcc" pseudo-component */ 101: if (fcc) { 102: FINDCOMP (cptr, "fcc"); 103: if (cptr) 104: cptr->c_text = getcpy (fcc); 105: } 106: if (!ccme) 107: (void) ismymbox ((struct mailname *)0); /* XXX */ 108: 109: /* pick any interesting stuff out of msg "inb" */ 110: for (state = FLD;;) { 111: state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb); 112: switch (state) { 113: case FLD: 114: case FLDPLUS: 115: /* 116: * if we're interested in this component, save a pointer 117: * to the component text, then start using our next free 118: * buffer as the component temp buffer (buffer switching 119: * saves an extra copy of the component text). 120: */ 121: if (cptr = wantcomp[CHASH(name)]) 122: do { 123: if (uleq(name, cptr->c_name)) { 124: char_read += msg_count; 125: if (! cptr->c_text) { 126: cptr->c_text = tmpbuf; 127: *--savecomp = cptr; 128: tmpbuf = *nxtbuf++; 129: } else { 130: i = strlen (cp = cptr->c_text) - 1; 131: if (cp[i] == '\n') 132: if (cptr->c_type & CT_ADDR) { 133: cp[i] = '\0'; 134: cp = add (",\n\t", cp); 135: } else { 136: cp = add ("\t", cp); 137: } 138: cptr->c_text = add (tmpbuf, cp); 139: } 140: while (state == FLDPLUS) { 141: state = m_getfld (state, name, tmpbuf, 142: SBUFSIZ, inb); 143: cptr->c_text = add (tmpbuf, cptr->c_text); 144: char_read += msg_count; 145: } 146: break; 147: } 148: } while (cptr = cptr->c_next); 149: 150: while (state == FLDPLUS) 151: state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb); 152: break; 153: 154: case LENERR: 155: case FMTERR: 156: case BODY: 157: case FILEEOF: 158: goto finished; 159: 160: default: 161: adios (NULLCP, "m_getfld() returned %d", state); 162: } 163: } 164: /* 165: * format and output the header lines. 166: */ 167: finished: 168: /* if there's a "subject" component, strip any "re:"s off it */ 169: FINDCOMP (cptr, "subject") 170: if (cptr && (cp = cptr->c_text)) { 171: register char *sp = cp; 172: 173: for (;;) { 174: while (isspace(i = *cp++)) 175: ; 176: if ((i | 0x20) != 'r' || (*cp++ | 0x20) != 'e' || *cp++ != ':') 177: break; 178: sp = cp; 179: } 180: if (sp != cptr->c_text) { 181: cp = cptr->c_text; 182: cptr->c_text = getcpy (sp); 183: free (cp); 184: } 185: } 186: i = format_len + char_read + 256; 187: scanl = malloc ((unsigned)i + 2); 188: dat[0] = dat[1] = dat[2] = 0; 189: dat[3] = outputlinelen; 190: (void) fmtscan (fmt, scanl, i, dat); 191: fputs (scanl, out); 192: if (badaddrs) { 193: fputs ("\nrepl: bad addresses:\n", out); 194: fputs ( badaddrs, out); 195: } 196: if (filter) 197: replfilter (inb, out); 198: 199: if (ferror (out)) 200: adios (drft, "error writing"); 201: (void) fclose (out); 202: 203: /* return dynamically allocated buffers */ 204: free (scanl); 205: while ( cptr = *savecomp++ ) 206: free (cptr->c_text); 207: while ( cp = *nxtbuf++) 208: free (cp); 209: free (tmpbuf); 210: free ((char *) compbuffers); 211: free ((char *) used_buf); 212: } 213: 214: /* */ 215: 216: static char *buf; /* our current working buffer */ 217: static char *bufend; /* end of working buffer */ 218: static char *last_dst; /* buf ptr at end of last call */ 219: static unsigned int bufsiz; /* current size of buf */ 220: 221: #define BUFINCR 512 /* how much to expand buf when if fills */ 222: 223: #define CPY(s) { cp = (s); while (*dst++ = *cp++) ; --dst; } 224: 225: /* check if there's enough room in buf for str. add more mem if needed */ 226: #define CHECKMEM(str) \ 227: if ((len = strlen (str)) >= bufend - dst) {\ 228: bufsiz += ((dst + len - bufend) / BUFINCR + 1) * BUFINCR;\ 229: buf = realloc (buf, bufsiz);\ 230: if (! buf)\ 231: adios (NULLCP, "formataddr: couldn't get buffer space");\ 232: bufend = buf + bufsiz;\ 233: } 234: 235: 236: /* fmtscan will call this routine if the user includes the function 237: * "(formataddr {component})" in a format string. "orig" is the 238: * original contents of the string register. "str" is the address 239: * string to be formatted and concatenated onto orig. This routine 240: * returns a pointer to the concatenated address string. 241: * 242: * We try to not do a lot of malloc/copy/free's (which is why we 243: * don't call "getcpy") but still place no upper limit on the 244: * length of the result string. 245: */ 246: char *formataddr (orig, str) 247: char *orig; 248: char *str; 249: { 250: register int len; 251: char baddr[BUFSIZ]; 252: register int isgroup; 253: register char *dst; 254: register char *cp; 255: register char *sp; 256: register struct mailname *mp = NULL; 257: 258: /* if we don't have a buffer yet, get one */ 259: if (bufsiz == 0) { 260: buf = malloc (BUFINCR); 261: if (! buf) 262: adios (NULLCP, "formataddr: couldn't allocate buffer space"); 263: bufsiz = BUFINCR - 6; /* leave some slop */ 264: bufend = buf + bufsiz; 265: } 266: /* 267: * If "orig" points to our buffer we can just pick up where we 268: * left off. Otherwise we have to copy orig into our buffer. 269: */ 270: if (orig == buf) 271: dst = last_dst; 272: else if (!orig || !*orig) { 273: dst = buf; 274: *dst = '\0'; 275: } else { 276: CHECKMEM (orig); 277: CPY (orig); 278: } 279: 280: /* concatenate all the new addresses onto 'buf' */ 281: for (isgroup = 0; cp = getname (str); ) { 282: if ((mp = getm (cp, dfhost, dftype, AD_NAME, NULLCP)) == NULL) { 283: (void) sprintf (baddr, "\tBAD ADDRRESS: %s\n", cp); 284: badaddrs = add (baddr, badaddrs); 285: continue; 286: } 287: if (isgroup && (mp->m_gname || !mp->m_ingrp)) { 288: *dst++ = ';'; 289: isgroup = 0; 290: } 291: if (insert (mp)) { 292: /* if we get here we're going to add an address */ 293: if (dst != buf) { 294: *dst++ = ','; 295: *dst++ = ' '; 296: } 297: if (mp->m_gname) { 298: CHECKMEM (mp->m_gname); 299: CPY (mp->m_gname); 300: isgroup++; 301: } 302: sp = adrformat (mp); 303: CHECKMEM (sp); 304: CPY (sp); 305: } 306: } 307: 308: if (isgroup) 309: *dst++ = ';'; 310: 311: *dst = '\0'; 312: last_dst = dst; 313: return (buf); 314: } 315: /* */ 316: 317: static insert (np) 318: register struct mailname *np; 319: { 320: char buffer[BUFSIZ]; 321: register struct mailname *mp; 322: 323: if (np -> m_mbox == NULL) 324: return 0; 325: 326: for (mp = &mq; mp -> m_next; mp = mp -> m_next) { 327: #ifdef BERK 328: if (uleq (np -> m_mbox, mp -> m_next -> m_mbox)) 329: return 0; 330: #else not BERK 331: if (uleq (np -> m_host, mp -> m_next -> m_host) 332: && uleq (np -> m_mbox, mp -> m_next -> m_mbox)) 333: return 0; 334: #endif BERK 335: } 336: if (!ccme && ismymbox (np)) 337: return 0; 338: 339: if (querysw) { 340: (void) sprintf (buffer, "Reply to %s? ", adrformat (np)); 341: if (!gans (buffer, anoyes)) 342: return 0; 343: } 344: mp -> m_next = np; 345: #ifdef ISI 346: if (ismymbox (np)) 347: ccme = 0; 348: #endif ISI 349: return 1; 350: } 351: 352: /* */ 353: 354: static replfilter (in, out) 355: register FILE *in, 356: *out; 357: { 358: int pid; 359: char *mhl; 360: 361: if (filter == NULL) 362: return; 363: 364: if (access (filter, 04) == NOTOK) 365: adios (filter, "unable to read"); 366: 367: mhl = r1bindex (mhlproc, '/'); 368: 369: rewind (in); 370: (void) fflush (out); 371: 372: switch (pid = vfork ()) { 373: case NOTOK: 374: adios ("fork", "unable to"); 375: 376: case OK: 377: (void) dup2 (fileno (in), fileno (stdin)); 378: (void) dup2 (fileno (out), fileno (stdout)); 379: closefds (3); 380: 381: execlp (mhlproc, mhl, "-form", filter, "-noclear", NULLCP); 382: fprintf (stderr, "unable to exec "); 383: perror (mhlproc); 384: _exit (-1); 385: 386: default: 387: if (pidXwait (pid, mhl)) 388: done (1); 389: (void) fseek (out, 0L, 2); 390: break; 391: } 392: }