1: #include "parms.h" 2: #include "structs.h" 3: #ifdef BSD 4: #include <sysexits.h> /* bsd only? */ 5: #else ! BSD 6: #define EX_OK 0 /* successful termination */ 7: #define EX_USAGE 64 /* command line usage error */ 8: #define EX_DATAERR 65 /* data format error */ 9: #define EX_UNAVAILABLE 69 /* service unavailable */ 10: #endif ! BSD 11: 12: #ifdef RCSIDENT 13: static char *rcsid = "$Header: nfmail.c,v 1.7.0.12 86/04/04 12:47:39 notes Rel $"; 14: #endif RCSIDENT 15: 16: /* 17: * nfmail 18: * 19: * A simple program which goes through standard input, which 20: * should be a formatted mail article with headers, and 21: * parses out the "Subject:" line. We then turn around and 22: * use it to invoke "nfpipe" and send the letter to the appropriate 23: * notesfile (specified on the nfmail command line). 24: * 25: * Original coding: Wayne Hamilton, U of Illinois CSO (I think) 26: * Modified: Stuart Cracraft, SRI International 27: * 28: */ 29: 30: 31: char *getadr (); 32: FILE * popen (); 33: 34: #define IGNORESIZE 256 35: 36: static char title[BUFSIZ] = "No Subject Line"; 37: 38: #ifdef DEBUG 39: int Debug = 0; 40: #endif DEBUG 41: 42: /* 43: * next three variables declared in "parsepath". 44: */ 45: extern char fromsys[SYSSZ + 1]; /* gave it to us */ 46: extern char origsys[SYSSZ + 1]; /* started here */ 47: extern char authname[NAMESZ + 1]; /* author */ 48: 49: char Nfpipe[BUFSIZ]; /* nfpipe pathname */ 50: char tmpname[BUFSIZ]; /* scratch file */ 51: 52: char system_rc[] = "/etc/Mail.rc"; 53: 54: #define MAX_IGNORE 32 55: char ignore[MAX_IGNORE][IGNORESIZE]; 56: int ignore_cnt = 0; 57: 58: int AnchorSearch = TRUE; 59: 60: main (argc, argv) 61: char **argv; 62: { 63: register FILE * Ftmp; 64: char command[BUFSIZ], 65: from[BUFSIZ], 66: oldfrom[BUFSIZ], 67: buf[BUFSIZ]; 68: int gotsubj = FALSE, 69: gotfrom = FALSE, 70: gotoldfrom = FALSE; 71: int stripheader = FALSE; /* leave headers in */ 72: int letterstatus = 0; /* director msg? */ 73: int tossit; 74: char *myrc = 0; 75: char *home; 76: int i; 77: char *p, 78: *q, 79: *skipwhite (); 80: 81: struct io_f io; 82: struct daddr_f where; 83: struct when_f entered; 84: struct id_f respid; 85: struct auth_f auth; 86: struct when_f whentime; 87: int notenum; 88: int status; 89: struct note_f note; 90: 91: startup (argc, argv); 92: argc--; /* blast command */ 93: argv++; 94: from[0] = oldfrom[0] = '\0'; /* zero them */ 95: 96: while (argc != 0) 97: { 98: 99: if (strncmp (*argv, "-s\0", 3) == 0) /* strip headers */ 100: { 101: argc--; 102: argv++; 103: stripheader = TRUE; 104: continue; 105: } 106: if (strncmp (*argv, "-F\0", 3) == 0) /* floating match */ 107: { 108: argv++; 109: argc--; /* to next arg */ 110: AnchorSearch = FALSE; /* floating search */ 111: continue; 112: } 113: if (strncmp (*argv, "-d\0", 3) == 0) /* enable dirmsg */ 114: { 115: argc--; 116: argv++; 117: letterstatus |= DIRMES; 118: continue; 119: } 120: if (strncmp (*argv, "-m\0", 3) == 0) /* specify .mailrc */ 121: { 122: argc--; 123: argv++; 124: if (argc != 0) 125: { 126: getignore (*argv); 127: } 128: else 129: { 130: fprintf (stderr, "Need to specifiy -m file\n"); 131: goto usage; 132: } 133: argc--; 134: argv++; 135: continue; /* next arg */ 136: } 137: break; /* not an arg */ 138: } 139: 140: 141: if (!argc) 142: { 143: usage: 144: fprintf (stderr, "Usage: %s [-F] [-s] [-m .mailrc-file] <notesfile>\n", 145: Invokedas); 146: exit (EX_USAGE); 147: } 148: 149: /* 150: * build ourselves a scratch file. If we can't, then pass the 151: * mail on with a default title. 152: */ 153: 154: sprintf (tmpname, "/tmp/nfm%05d", getpid ()); 155: sprintf (Nfpipe, "%s/nfpipe", BIN); 156: if ((Ftmp = fopen (tmpname, "w")) == NULL) 157: { 158: fprintf (stderr, "nfmail: can't fopen temp file, but the mail gets thru\n"); 159: sprintf (command, "%s %s -t \"Mail to %s\"", Nfpipe, *argv, *argv); 160: dopipe (command, stdin); 161: unlink (tmpname); /* ... remove scratch file */ 162: exit (EX_OK); /* and leave */ 163: } 164: 165: /* 166: * Step through the system Mail.rc file and pilfer the ignore commands. 167: */ 168: getignore (system_rc); 169: 170: /* 171: * read through the mail looking for the subject line. 172: */ 173: 174: while (gets (buf) != NULL) 175: { 176: if (!buf[0]) 177: { 178: #ifdef DEBUG 179: if (Debug != 0) 180: fprintf (stderr, "==== End of Header ====\n"); 181: #endif DEBUG 182: break; /* header's end */ 183: } 184: #ifdef DEBUG 185: if (Debug != 0) 186: fprintf (stderr, "%s\n", buf); 187: #endif DEBUG 188: if (buf[0] == '\t') /* continuation */ 189: goto doit; /* use same "tossit" */ 190: 191: if (!strncmp (buf, "Subject: ", 9)) /* check for title */ 192: { 193: if (!gotsubj) /* only first one */ 194: { 195: strcpy (title, buf + 9); 196: gotsubj = TRUE; 197: } 198: tossit = FALSE; 199: goto doit; /* skip other tests */ 200: } 201: if (!strncmp (buf, "From: ", 6)) /* author */ 202: { /* grab user name */ 203: if (!gotfrom) /* only once */ 204: { 205: strcpy (from, buf + 6); 206: gotfrom = TRUE; 207: } 208: tossit = FALSE; /* keep all from lines */ 209: goto doit; 210: } 211: if (!strncmp (buf, "From", 4) || !strncmp (buf, ">From", 5)) 212: { 213: if (!gotoldfrom) 214: { 215: strcpy (oldfrom, buf + 5); /* save it */ 216: gotoldfrom++; 217: } 218: tossit = FALSE; /* save all addresses */ 219: } 220: else 221: { 222: /* 223: * keep it if it isn't explicitly ignored and the strip 224: * flag is off. 225: */ 226: if (stripheader != 0 || shouldignore (buf)) 227: tossit = TRUE; 228: else 229: tossit = FALSE; 230: } 231: 232: doit: /* for continuation lines */ 233: if (tossit == FALSE) 234: { 235: #ifdef DEBUG 236: if (Debug != 0) 237: fprintf (stderr, "Keep: %s\n", buf); 238: #endif DEBUG 239: fprintf (Ftmp, "%s\n", buf); /* send the header line also */ 240: } 241: else 242: { 243: #ifdef DEBUG 244: if (Debug != 0) 245: fprintf (stderr, "Discard: %s\n", buf); 246: #endif DEBUG 247: } 248: } /* of header parsing loop */ 249: 250: putc ('\n', Ftmp); /* blank after headers */ 251: copy (stdin, Ftmp); 252: fclose (Ftmp); 253: 254: if ((Ftmp = fopen (tmpname, "r")) == NULL) 255: { 256: unlink (tmpname); /* ... remove scratch file */ 257: fprintf (stderr, "nfmail: can't re-fopen temp file %s\n", tmpname); 258: exit (EX_UNAVAILABLE); 259: } 260: 261: /* 262: * Now that we have collected the letter and parsed such banalities 263: * as the title and the author and stripped any header lines that we 264: * don't care to hear about, it's time to put the letter into 265: * the notesfile. We use routines scammed from our news/notes gateway 266: * code to look at the title and determine if it's a response to 267: * a previous letter. This allows us to have the correct linkage 268: * for mail sent to a notesfile.... 269: */ 270: 271: if ((i = init (&io, *argv)) < 0) 272: { 273: unlink (tmpname); /* zap scratch file */ 274: fprintf (stderr, "%s: can't open notesfile %s (retcode %d)\n", 275: Invokedas, *argv, i); 276: /* 277: * Should have a better scheme for knowing why can't open 278: */ 279: exit (EX_UNAVAILABLE); /* bad nf or such */ 280: } 281: p = title; 282: while (*p && (*p == ' ' || *p == '\t')) /* leading trash */ 283: p++; /* skip */ 284: if (!strncmp (p, "re: ", 4) || /* it looks like */ 285: !strncmp (p, "Re: ", 4) || /* a response */ 286: !strncmp (p, "RE: ", 4)) 287: { 288: do 289: { 290: for (p += 3; *p == ' ' || *p == '\t'; p++); /* drop spaces */ 291: } while (!strncmp (p, "re: ", 4) || 292: !strncmp (p, "Re: ", 4) || 293: !strncmp (p, "RE: ", 4)); 294: strncpy (io.xstring, p, TITLEN); /* load it */ 295: io.xstring[TITLEN - 1] = '\0'; /* and terminate it */ 296: notenum = findtitle (&io, io.descr.d_nnote, AnchorSearch);/* start at back */ 297: } 298: else 299: { 300: notenum = 0; /* has to be new */ 301: } 302: 303: /* 304: * OK. By now, we have a "notenum" if the article can be pegged 305: * as a response to one of our notes. 306: * Otherwise, notenum==0 and we'll have to turn it into 307: * a base note. 308: */ 309: 310: gettime (&whentime); 311: gettime (&entered); 312: /* 313: * load the user's name 314: */ 315: if (from[0] != '\0') /* got one */ 316: { 317: p = q = from; 318: while ((p = index (p, '<')) != (char *) NULL) 319: q = ++p; /* get innermost <..> */ 320: p = index (q, '>'); 321: if (p != (char *) NULL) 322: *p = '\0'; /* zap */ 323: parsepath (q, (char *) NULL); /* actually break it */ 324: } 325: else 326: { 327: if (oldfrom[0] != '\0') 328: { 329: parsepath (oldfrom, (char *) NULL); /* try for something */ 330: } 331: else 332: { 333: strcpy (authname, "MAILER-DAEMON"); /* general catch-all */ 334: origsys[0] = '\0'; /* local */ 335: } 336: } 337: strncpy (auth.aname, authname, NAMESZ); /* user */ 338: if (origsys[0] == '\0') 339: strncpy (auth.asystem, Authsystem, HOMESYSSZ); /* local host */ 340: else 341: strncpy (auth.asystem, origsys, HOMESYSSZ); /* system */ 342: auth.aname[NAMESZ - 1] = auth.asystem[HOMESYSSZ - 1] = '\0';/* chop */ 343: auth.aid = Anonuid; /* uid (none) */ 344: #ifdef DEBUG 345: printf ("parse path returns the following:\n"); 346: printf ("authname: %s\n", authname); 347: printf ("origsys: %s\n", origsys); 348: printf ("fromsys: %s\n", fromsys); 349: #endif DEBUG 350: if (notenum > 0) 351: { 352: pagein (&io, Ftmp, &where); 353: i = putresp (&io, &where, letterstatus, notenum, &entered, &auth, ¬e, 354: LOCKIT, &respid, ADDID, System, ADDTIME, &whentime); 355: } 356: else 357: { 358: for (p = &title[0]; *p && (*p == ' ' || *p == '\t');) 359: p++; /* strip blanks */ 360: for (i = 0; i < TITLEN; i++) /* shift down */ 361: { 362: if ((title[i] = *p++) == '\0') /* want assignment */ 363: break; /* end */ 364: } 365: title[TITLEN - 1] = '\0'; /* terminate for sure */ 366: pagein (&io, Ftmp, &where); 367: gettime (¬e.n_date); 368: notenum = putnote (&io, &where, title, letterstatus, ¬e, 369: &auth, NOPOLICY, LOCKIT, ADDID, System, ADDTIME); 370: } 371: 372: finish (&io); /* update numbers and close */ 373: fclose (Ftmp); /* close and ... */ 374: unlink (tmpname); /* ... remove scratch file */ 375: exit (EX_OK); 376: } 377: 378: 379: char *skipwhite (p) 380: char *p; 381: { 382: while (*p == ' ' || *p == '\t' || *p == '\n') 383: p++; 384: return (p); 385: } 386: 387: 388: /* 389: * Get all the "ignore" commands from the file. Do nothing if the file 390: * does not exist. 391: */ 392: getignore (name) 393: char *name; 394: { 395: FILE * f; 396: char buff[IGNORESIZE]; 397: char *p, 398: *q; 399: 400: if ((f = fopen (name, "r")) == 0) 401: { 402: #ifdef DEBUG 403: if (Debug != 0) 404: fprintf (stderr, "Unable to open %s\n", name); 405: #endif DEBUG 406: return (0); 407: } 408: 409: while (!feof (f)) 410: { 411: p = buff; 412: fgets (buff, IGNORESIZE, f); 413: p = skipwhite (p); 414: 415: if (strncmp (p, "ignore", 6) == 0) 416: { 417: p = skipwhite (p + 6); 418: 419: /* 420: * Collect the tags of the ignore command 421: */ 422: 423: while (*p != 0) 424: { 425: if (ignore_cnt >= MAX_IGNORE) 426: { 427: fprintf (stderr, "%s: too many ignore tags\n", Invokedas); 428: exit (EX_DATAERR); 429: } 430: p = skipwhite (p); 431: for (q = ignore[ignore_cnt]; 432: *p != ' ' && *p != '\t' && *p != '\n' && *p != 0; 433: *(q++) = *(p++) 434: ); 435: *q = 0; 436: if (!shouldignore (ignore[ignore_cnt])) 437: { 438: ignore_cnt++; 439: } 440: p = skipwhite (p); 441: } 442: } 443: } 444: 445: fclose (f); 446: #ifdef DEBUG 447: if (Debug != 0) 448: { 449: int i; 450: 451: fprintf (stderr, "Ignoring lines prefixed with:\n"); 452: for (i = 0; i < ignore_cnt; i++) 453: fprintf (stderr, "\t%s\n", ignore[i]); 454: } 455: #endif DEBUG 456: return (0); 457: } 458: 459: 460: 461: /* 462: * Should we ignore this line? 463: */ 464: 465: shouldignore (p) 466: char *p; 467: { 468: int i; 469: 470: for (i = 0; i < ignore_cnt; i++) 471: if (strncmp (p, ignore[i], strlen (ignore[i])) == 0) 472: { 473: #ifdef DEBUG 474: if (Debug != 0) 475: fprintf (stderr, "\tMatches %s. Kill it\n", ignore[i]); 476: #endif DEBUG 477: return (1); 478: } 479: #ifdef DEBUG 480: if (Debug != 0) 481: fprintf (stderr, "\tKeep it\n"); 482: #endif DEBUG 483: return (0); 484: } 485: 486: /* 487: * simple command feeds what is left of the file "File" into 488: * a pipe feeding stdin of "command". 489: * 490: */ 491: 492: dopipe (command, File) char *command; 493: FILE * File; 494: { 495: register FILE * Pipe; 496: 497: if ((Pipe = popen (command, "w")) == NULL) 498: { 499: fprintf (stderr, "%s: can't popen (%s)!?\n", Invokedas, command); 500: exit (EX_UNAVAILABLE); 501: } 502: 503: copy (File, Pipe); 504: pclose (Pipe); 505: } 506: 507: /* 508: * copy rest of file "File" to "To". 509: */ 510: 511: copy (From, To) FILE * From, *To; 512: { 513: register int c; 514: 515: while ((c = getc (From)) != EOF) 516: putc (c, To); 517: }