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