Commit | Line | Data |
---|---|---|
0f4556f1 C |
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 | |
95f51977 | 12 | * intuition code is flakey and out of date. The from user is probably |
0f4556f1 C |
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 | |
95f51977 | 35 | * should not allow recnews (and thus the mail interface) to be used. |
0f4556f1 C |
36 | */ |
37 | ||
95f51977 C |
38 | #ifdef SCCSID |
39 | static char *SccsId = "@(#)recnews.c 2.11 3/19/86"; | |
40 | #endif /* SCCSID */ | |
0f4556f1 C |
41 | |
42 | #include "defs.h" | |
43 | ||
44 | #include <stdio.h> | |
45 | #include <ctype.h> | |
46 | ||
47 | /* | |
48 | * Note: we assume there are 2 kinds of hosts using recnews: | |
49 | * Those that have delivermail (and hence this program will never | |
50 | * have to deal with more than one message at a time) and those on the arpanet | |
95f51977 | 51 | * that do not (and hence all messages end with a sentinel). It is |
0f4556f1 C |
52 | * supposed that regular v7 type systems without delivermail or some |
53 | * other automatic forwarding device will just use rnews. We do | |
54 | * not attempt to tell where a message ends on all systems due to the | |
55 | * different conventions in effect. (This COULD be fixed, I suppose.) | |
56 | */ | |
57 | ||
58 | /* | |
59 | * Kinds of lines in a message. | |
60 | */ | |
61 | #define FROM 001 /* From line */ | |
62 | #define SUBJ 002 /* Subject */ | |
63 | #define TO 003 /* To (newgroup based on this) */ | |
64 | #define BLANK 004 /* blank line */ | |
65 | #define EOM 005 /* End of message (4 ctrl A's) */ | |
66 | #define HEADER 006 /* any unrecognized header */ | |
67 | #define TEXT 007 /* anything unrecognized */ | |
95f51977 | 68 | #define INCLUSIVE 010 /* newsgroup is already in header */ |
0f4556f1 C |
69 | |
70 | /* | |
71 | * Possible states program can be in. | |
72 | */ | |
73 | #define SKIPPING 0100 /* In header of message */ | |
74 | #define READING 0200 /* In body of message */ | |
75 | ||
76 | #define BFSZ 250 | |
77 | ||
78 | #define EOT '\004' | |
79 | ||
80 | char from[BFSZ]; /* mailing address for replies */ | |
81 | char sender[BFSZ]; /* mailing address of author, if different */ | |
82 | char to[BFSZ]; /* Destination of mail (msgs, etc) */ | |
83 | char subject[BFSZ]; /* subject of message */ | |
84 | char newsgroup[BFSZ]; /* newsgroups of message */ | |
85 | char cmdbuf[BFSZ]; /* command to popen */ | |
86 | ||
87 | extern char *strcat(), *strcpy(); | |
88 | extern FILE *popen(); | |
89 | char *any(); | |
90 | ||
91 | main(argc, argv) | |
92 | int argc; | |
93 | char **argv; | |
94 | { | |
95f51977 C |
95 | char buf[BFSZ], inews[BFSZ]; |
96 | register char *p, *q; | |
97 | register FILE *pipe = NULL; | |
98 | register int state; | |
99 | ||
100 | /* build inews command */ | |
101 | #ifdef IHCC | |
102 | sprintf(inews, "%s/%s/%s", logdir(HOME), LIBDIR, "inews"); | |
103 | #else | |
104 | sprintf(inews, "%s/%s", LIBDIR, "inews"); | |
105 | #endif | |
0f4556f1 C |
106 | |
107 | if (argc > 1) | |
108 | strcpy(to, argv[1]); | |
109 | if (argc > 2) | |
110 | strcpy(from, argv[2]); | |
111 | #ifdef debug | |
112 | printf("argv[0] is <%s>, argv[1] is <%s>, argv[2] is <%s>\n", | |
113 | argv[0], argv[1], argv[2]); | |
114 | #endif | |
115 | state = SKIPPING; | |
116 | while (fgets(buf, BFSZ, stdin) != NULL) { | |
95f51977 C |
117 | if (state == READING) { |
118 | fputs(buf,pipe); | |
119 | continue; | |
120 | } | |
121 | switch (type(buf)) { | |
0f4556f1 | 122 | |
95f51977 | 123 | case FROM: |
0f4556f1 C |
124 | frombreak(buf, from); |
125 | break; | |
126 | ||
95f51977 | 127 | case SUBJ: |
0f4556f1 C |
128 | p = any(buf, " \t"); |
129 | if (p == NULL) | |
95f51977 C |
130 | p = buf + 8; |
131 | q = subject; | |
132 | while (*++p) { | |
133 | if (*p == '"') | |
134 | *q++ = '\\'; | |
135 | *q++ = *p; | |
136 | } | |
137 | q[-1] = '\0'; | |
0f4556f1 C |
138 | break; |
139 | ||
95f51977 | 140 | case TO: |
0f4556f1 C |
141 | if (to[0]) |
142 | break; /* already have one */ | |
143 | p = any(buf, " \t"); | |
144 | if (p == NULL) | |
95f51977 C |
145 | p = buf + 3; |
146 | q = to; | |
147 | while (*++p) { | |
148 | if (*p == '"') | |
149 | *q++ = '\\'; | |
150 | *q++ = *p; | |
151 | } | |
152 | q[-1] = '\0'; | |
0f4556f1 C |
153 | break; |
154 | ||
95f51977 C |
155 | case INCLUSIVE: |
156 | sprintf(cmdbuf,"exec %s -p", inews); | |
157 | pipe = popen(cmdbuf,"w"); | |
158 | if (pipe == NULL){ | |
159 | perror("recnews: open failed"); | |
160 | exit(1); | |
161 | } | |
162 | state = READING; | |
163 | fputs(buf,pipe); | |
164 | break; | |
165 | ||
0f4556f1 C |
166 | /* |
167 | * Kludge to compensate for messages without real headers | |
168 | */ | |
95f51977 | 169 | case HEADER: |
0f4556f1 C |
170 | break; |
171 | ||
95f51977 | 172 | case BLANK: |
0f4556f1 C |
173 | state = READING; |
174 | findgroup(to, newsgroup); | |
95f51977 C |
175 | sprintf(cmdbuf, "exec %s -t \"%s\" -n \"%s\" -f \"%s\"", |
176 | inews, *subject ? subject : "(none)", | |
177 | newsgroup, from); | |
0f4556f1 C |
178 | #ifdef debug |
179 | pipe = stdout; | |
180 | printf("BLANK: %s\n", cmdbuf); | |
181 | #else | |
182 | pipe = popen(cmdbuf, "w"); | |
183 | if (pipe == NULL) { | |
184 | perror("recnews: popen failed"); | |
185 | exit(1); | |
186 | } | |
187 | #endif | |
95f51977 | 188 | if (sender[0]) { |
0f4556f1 | 189 | fputs(sender, pipe); |
95f51977 C |
190 | putc('\n', pipe); |
191 | } | |
0f4556f1 C |
192 | break; |
193 | ||
95f51977 | 194 | case TEXT: |
0f4556f1 C |
195 | findgroup(to, newsgroup); |
196 | state = READING; | |
197 | if (subject[0] == 0) { | |
198 | strcpy(subject, buf); | |
199 | if (subject[strlen(subject)-1] == '\n') | |
200 | subject[strlen(subject)-1] = '\0'; | |
201 | } | |
95f51977 C |
202 | sprintf(cmdbuf, "exec \"%s\" -t \"%s\" -n \"%s\" -f \"%s\"", |
203 | inews, subject, newsgroup, from); | |
0f4556f1 C |
204 | #ifdef debug |
205 | pipe = stdout; | |
206 | printf("TEXT: %s\n", cmdbuf); | |
207 | #else | |
208 | pipe = popen(cmdbuf, "w"); | |
209 | if (pipe == NULL) { | |
95f51977 | 210 | perror("pipe failed"); |
0f4556f1 C |
211 | exit(1); |
212 | } | |
213 | #endif | |
95f51977 | 214 | if (sender[0]){ |
0f4556f1 | 215 | fputs(sender, pipe); |
95f51977 C |
216 | putc('\n',pipe); |
217 | } | |
0f4556f1 C |
218 | break; |
219 | } | |
220 | } | |
221 | exit(0); | |
222 | } | |
223 | ||
0f4556f1 C |
224 | type(p) |
225 | register char *p; | |
226 | { | |
227 | char *firstbl; | |
95f51977 | 228 | static char lasthdr; /* prev line was a header */ |
0f4556f1 | 229 | |
95f51977 C |
230 | lasthdr = 1; |
231 | if ((*p == ' ' || *p == '\t') && lasthdr) | |
232 | return HEADER; /* continuation line */ | |
0f4556f1 C |
233 | firstbl = any(p, " \t"); |
234 | while (*p == ' ' || *p == '?' || *p == '\t') | |
235 | ++p; | |
236 | ||
237 | if (*p == '\n' || *p == 0) | |
95f51977 C |
238 | return BLANK; |
239 | if (strncmp(p, ">From", 5) == 0 || strncmp(p, "From", 4) == 0) | |
240 | return FROM; | |
241 | if (strncmp(p, "Subj", 4)==0 || strncmp(p, "Re:", 3)==0 || | |
242 | strncmp(p, "re:", 3)==0) | |
243 | return SUBJ; | |
0f4556f1 | 244 | if (strncmp(p, "To", 2)==0) |
95f51977 | 245 | return TO; |
0f4556f1 | 246 | if (strncmp(p, "\1\1\1\1", 4)==0) |
95f51977 | 247 | return EOM; |
0f4556f1 | 248 | if (firstbl && firstbl[-1] == ':' && isalpha(*p)) |
95f51977 C |
249 | return HEADER; |
250 | lasthdr = 0; | |
251 | return TEXT; | |
0f4556f1 C |
252 | } |
253 | ||
254 | /* | |
255 | * Figure out who a message is from. | |
256 | */ | |
257 | frombreak(buf, fbuf) | |
258 | register char *buf, *fbuf; | |
259 | { | |
0f4556f1 C |
260 | char wordfrom[BFSZ], uname[BFSZ], at[BFSZ], site[BFSZ]; |
261 | ||
262 | if (fbuf[0]) { /* we already know who it's from */ | |
95f51977 | 263 | if (sender[0] == 0 || buf[4] == ':') { |
0f4556f1 C |
264 | #ifdef debug |
265 | printf("sender set to: %s", buf); | |
266 | #endif | |
267 | strcpy(sender, buf); | |
268 | } | |
269 | return; | |
270 | } | |
271 | /* break the line into tokens. */ | |
272 | sscanf(buf, "%s %s %s %s", wordfrom, uname, at, site); | |
273 | if (isat(at)) | |
274 | /* | |
275 | * Some arpanet mail comes from "joe at mit-dms" | |
276 | * instead of "joe@mit-dms", so handle it here. | |
277 | */ | |
278 | sprintf(fbuf, "%s@%s", uname, site); | |
279 | else | |
280 | strcpy(fbuf, uname); | |
281 | } | |
282 | ||
283 | isat(str) | |
284 | char *str; | |
285 | { | |
286 | if (strcmp(str, "@")==0) return TRUE; | |
287 | if (strcmp(str, "at")==0) return TRUE; | |
288 | if (strcmp(str, "AT")==0) return TRUE; | |
289 | return FALSE; | |
290 | } | |
291 | ||
95f51977 C |
292 | findgroup(dest, group) |
293 | char *dest ; | |
0f4556f1 C |
294 | char *group; |
295 | { | |
296 | #ifdef debug | |
95f51977 | 297 | printf("findgroup(%s)\n", dest); |
0f4556f1 C |
298 | #endif |
299 | #ifdef fussy | |
300 | /* | |
301 | * Default unknown "to" fields to "general". This gives you | |
302 | * tight control over which newsgroups exist. | |
303 | */ | |
95f51977 | 304 | if (strcmp(dest, "msgs")==0) |
0f4556f1 | 305 | strcpy(group, "msgs"); |
95f51977 | 306 | else if (strcmp(dest, "allmsgs")==0) |
0f4556f1 | 307 | strcpy(group, "NET.allmsgs"); |
95f51977 | 308 | else if (strcmp(dest, "csmsgs")==0) |
0f4556f1 C |
309 | strcpy(group, "NET.csmsgs"); |
310 | else | |
311 | strcpy(group, "general"); | |
312 | #else | |
313 | /* | |
314 | * Allow any newsgroup. This way you don't have to recompile | |
95f51977 | 315 | * recnews every time you add a newsgroup. |
0f4556f1 | 316 | */ |
95f51977 | 317 | strcpy(group, dest); |
0f4556f1 C |
318 | #endif |
319 | } | |
320 | ||
321 | /* | |
322 | * Return the ptr in sp at which a character in sq appears; | |
323 | * NULL if not found | |
324 | * | |
325 | */ | |
326 | ||
327 | char * | |
328 | any(sp, sq) | |
329 | char *sp, *sq; | |
330 | { | |
331 | register c1, c2; | |
332 | register char *q; | |
333 | ||
334 | while (c1 = *sp++) { | |
335 | q = sq; | |
336 | while (c2 = *q++) | |
337 | if (c1 == c2) | |
338 | return(--sp); | |
339 | } | |
340 | return(NULL); | |
341 | } |