|
|
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.