|
|
1.1 root 1: /*
2: * recnews [to newsgroup] [from user]
3: *
4: * Process a news article which has been mailed to some group like msgs.
5: * Such articles are in normal mail format and have never seen the insides
6: * of netnews. If the "to newsgroup" is included, the article is posted
7: * to this newsgroup instead of trying to intuit it from the headers.
8: * If the "from user" is included, the return address is forged to look
9: * like that user instead of what getuid or a from line says.
10: *
11: * It is recommended that you always include the to newsgroup, since the
12: * intution code is flakey and out of date. The from user is probably
13: * appropriate for arpanet mailing lists being funnelled at ucbvax but
14: * not otherwise. Sample lines in /usr/lib/aliases (if you run delivermail):
15: * worldnews: "|/usr/lib/news/recnews net.general"
16: * Allows you to mail to worldnews rather than using inews.
17: * Intended for humans to mail to.
18: * post-unix-wizards: "|/usr/lib/news/recnews fa.unix-wizards unix-wizards"
19: * Causes mail to post-unix-wizards to be fed into fa.unix-wizards
20: * and the return address forged as unix-wizards on the local
21: * machine. post-unix-wizards (on the local machine) should
22: * be part of the master mailing list somewhere (on a different
23: * machine.)
24: *
25: * Recnews is primarily useful in remote places on the usenet which collect
26: * mail from mailing lists and funnel them into the network. It is also
27: * useful if you like to send mail to some user instead of invoking
28: * inews -t .. -n .. when you want to submit an article. (Many mailers give
29: * you nice facilities like editing the message.) It is not, however,
30: * essential to use recnews to be able to join usenet.
31: *
32: * WARNING: recnews disables the "recording" check - it has to because
33: * by the time inews is run, it's in the background and too late to
34: * ask permission. If you depend heavily on recordings you probably
35: * should now allow recnews (and thus the mail interface) to be used.
36: */
37:
38: static char *SccsId = "@(#)recnews.c 2.4 3/3/83";
39:
40: #include "defs.h"
41:
42: #include <stdio.h>
43: #include <ctype.h>
44:
45: /*
46: * Note: we assume there are 2 kinds of hosts using recnews:
47: * Those that have delivermail (and hence this program will never
48: * have to deal with more than one message at a time) and those on the arpanet
49: * that do not (and hence all messages end with a sentenel). It is
50: * supposed that regular v7 type systems without delivermail or some
51: * other automatic forwarding device will just use rnews. We do
52: * not attempt to tell where a message ends on all systems due to the
53: * different conventions in effect. (This COULD be fixed, I suppose.)
54: */
55:
56: /*
57: * Kinds of lines in a message.
58: */
59: #define FROM 001 /* From line */
60: #define SUBJ 002 /* Subject */
61: #define TO 003 /* To (newgroup based on this) */
62: #define BLANK 004 /* blank line */
63: #define EOM 005 /* End of message (4 ctrl A's) */
64: #define HEADER 006 /* any unrecognized header */
65: #define TEXT 007 /* anything unrecognized */
66:
67: /*
68: * Possible states program can be in.
69: */
70: #define SKIPPING 0100 /* In header of message */
71: #define READING 0200 /* In body of message */
72:
73: #define BFSZ 250
74:
75: #define EOT '\004'
76:
77: char from[BFSZ]; /* mailing address for replies */
78: char sender[BFSZ]; /* mailing address of author, if different */
79: char to[BFSZ]; /* Destination of mail (msgs, etc) */
80: char subject[BFSZ]; /* subject of message */
81: char newsgroup[BFSZ]; /* newsgroups of message */
82: char cmdbuf[BFSZ]; /* command to popen */
83:
84: extern char *strcat(), *strcpy();
85: extern FILE *popen();
86: char *any();
87:
88: main(argc, argv)
89: int argc;
90: char **argv;
91: {
92: char buf[BFSZ];
93: register char *p;
94: register FILE *pipe;
95: register int state, pathcnt;
96: int t;
97:
98: if (argc > 1)
99: strcpy(to, argv[1]);
100: if (argc > 2)
101: strcpy(from, argv[2]);
102: #ifdef debug
103: printf("argv[0] is <%s>, argv[1] is <%s>, argv[2] is <%s>\n",
104: argv[0], argv[1], argv[2]);
105: #endif
106: state = SKIPPING;
107: while (fgets(buf, BFSZ, stdin) != NULL) {
108: t = type(buf) | state;
109: #ifdef debug
110: printf("%o\t%s", t, buf);
111: #endif
112: switch (t) {
113:
114: case FROM | SKIPPING:
115: frombreak(buf, from);
116: break;
117:
118: case FROM | READING:
119: fputs(buf, pipe);
120: break;
121:
122: case SUBJ | SKIPPING:
123: p = any(buf, " \t");
124: if (p == NULL)
125: p = buf+8;
126: strcpy(subject, p+1);
127: subject[strlen(subject)-1] = 0; /* trim trailing \n */
128: break;
129:
130: case SUBJ | READING:
131: fputs(buf, pipe);
132: break;
133:
134: case TO | SKIPPING:
135: if (to[0])
136: break; /* already have one */
137: p = any(buf, " \t");
138: if (p == NULL)
139: p = buf;
140: strcpy(to, p+1); /* strip leading blank */
141: to[strlen(to)-1] = 0; /* strip trailing \n */
142: break;
143:
144: case TO | READING:
145: fputs(buf, pipe);
146: break;
147:
148: /*
149: * Kludge to compensate for messages without real headers
150: */
151: case HEADER | SKIPPING:
152: break;
153:
154: case HEADER | READING:
155: fputs(buf, pipe);
156: break;
157:
158: case BLANK | SKIPPING:
159: state = READING;
160: findgroup(to, newsgroup);
161: sprintf(cmdbuf, "%s -D -t \"%s\" -n %s -f %s", INEWS, subject, newsgroup, from);
162: #ifdef debug
163: pipe = stdout;
164: printf("BLANK: %s\n", cmdbuf);
165: #else
166: pipe = popen(cmdbuf, "w");
167: if (pipe == NULL) {
168: perror("recnews: popen failed");
169: exit(1);
170: }
171: #endif
172: if (sender[0])
173: fputs(sender, pipe);
174: break;
175:
176: case BLANK | READING:
177: fputs(buf, pipe);
178: break;
179:
180: case TEXT | SKIPPING:
181: findgroup(to, newsgroup);
182: state = READING;
183: if (subject[0] == 0) {
184: strcpy(subject, buf);
185: if (subject[strlen(subject)-1] == '\n')
186: subject[strlen(subject)-1] = '\0';
187: }
188: sprintf(cmdbuf, "%s -D -t \"%s\" -n %s -f %s", INEWS, subject, newsgroup, from);
189: #ifdef debug
190: pipe = stdout;
191: printf("TEXT: %s\n", cmdbuf);
192: #else
193: pipe = popen(cmdbuf, "w");
194: if (pipe == NULL) {
195: fprintf(stderr, "pipe failed\n");
196: exit(1);
197: }
198: #endif
199: if (sender[0])
200: fputs(sender, pipe);
201: break;
202:
203: case TEXT | READING:
204: fputs(buf, pipe);
205: break;
206: }
207: }
208: exit(0);
209: }
210:
211: #define itsa(kind) {lastcomma=thiscomma; lasthdr=(kind!=TEXT); return kind;}
212: type(p)
213: register char *p;
214: {
215: char *firstbl;
216: static char lasthdr=0; /* prev line was a header */
217: static char lastcomma=0; /* prev line ended in a comma */
218: int thiscomma;
219:
220: thiscomma = (p[strlen(p)-2] == ',');
221: if (*p == ' ' && lasthdr && lastcomma)
222: itsa(HEADER); /* continuation line */
223: firstbl = any(p, " \t");
224: while (*p == ' ' || *p == '?' || *p == '\t')
225: ++p;
226:
227: if (*p == '\n' || *p == 0)
228: itsa(BLANK);
229: if (strncmp(p, ">From", 5) == 0 ||
230: strncmp(p, "From", 4) == 0)
231: itsa (FROM);
232: if (strncmp(p, "Subj", 4)==0 ||
233: strncmp(p, "Re:", 3)==0 ||
234: strncmp(p, "re:", 3)==0)
235: itsa (SUBJ);
236: if (strncmp(p, "To", 2)==0)
237: itsa(TO);
238: if (strncmp(p, "\1\1\1\1", 4)==0)
239: itsa(EOM);
240: if (firstbl && firstbl[-1] == ':' && isalpha(*p))
241: itsa(HEADER);
242: itsa(TEXT);
243: }
244:
245: /*
246: * Figure out who a message is from.
247: */
248: frombreak(buf, fbuf)
249: register char *buf, *fbuf;
250: {
251: register char *p;
252: char wordfrom[BFSZ], uname[BFSZ], at[BFSZ], site[BFSZ];
253:
254: if (fbuf[0]) { /* we already know who it's from */
255: if (sender[0] == 0) {
256: #ifdef debug
257: printf("sender set to: %s", buf);
258: #endif
259: strcpy(sender, buf);
260: }
261: return;
262: }
263: /* break the line into tokens. */
264: sscanf(buf, "%s %s %s %s", wordfrom, uname, at, site);
265: if (isat(at))
266: /*
267: * Some arpanet mail comes from "joe at mit-dms"
268: * instead of "joe@mit-dms", so handle it here.
269: */
270: sprintf(fbuf, "%s@%s", uname, site);
271: else
272: strcpy(fbuf, uname);
273: }
274:
275: isat(str)
276: char *str;
277: {
278: if (strcmp(str, "@")==0) return TRUE;
279: if (strcmp(str, "at")==0) return TRUE;
280: if (strcmp(str, "AT")==0) return TRUE;
281: return FALSE;
282: }
283:
284: findgroup(to, group)
285: char *to;
286: char *group;
287: {
288: #ifdef debug
289: printf("findgroup(%s)\n", to);
290: #endif
291: #ifdef fussy
292: /*
293: * Default unknown "to" fields to "general". This gives you
294: * tight control over which newsgroups exist.
295: */
296: if (strcmp(to, "msgs")==0)
297: strcpy(group, "msgs");
298: else if (strcmp(to, "allmsgs")==0)
299: strcpy(group, "NET.allmsgs");
300: else if (strcmp(to, "csmsgs")==0)
301: strcpy(group, "NET.csmsgs");
302: else
303: strcpy(group, "general");
304: #else
305: /*
306: * Allow any newsgroup. This way you don't have to recompile
307: * recnews everytime you add a newsgroup.
308: */
309: strcpy(group, to);
310: #endif
311: }
312:
313: /*
314: * Return the ptr in sp at which a character in sq appears;
315: * NULL if not found
316: *
317: */
318:
319: char *
320: any(sp, sq)
321: char *sp, *sq;
322: {
323: register c1, c2;
324: register char *q;
325:
326: while (c1 = *sp++) {
327: q = sq;
328: while (c2 = *q++)
329: if (c1 == c2)
330: return(--sp);
331: }
332: return(NULL);
333: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.