1 #ifndef lint
2 static char *sccsid = "@(#)inews.c 1.16 (Berkeley) 8/27/89";
3 #endif
4
5 /*
6 * Itty-bitty inews for talking to remote server.
7 * Simply accept input on stdin (or via a named file) and dump this
8 * to the server; add a From: and Path: line if missing in the original.
9 * Print meaningful errors from the server.
10 * Limit .signature files to MAX_SIGNATURE lines.
11 * No processing of command line options.
12 *
13 * Original by Steven Grady <grady@ucbvax.Berkeley.EDU>, with thanks from
14 * Phil Lapsley <phil@ucbvax.berkeley.edu>
15 * Send bug reports to Stan Barber <sob@bcm.tmc.edu>
16 */
17
18 #ifdef HAVE_CONFIG_H
19 #include "../config.h"
20 #endif
21
22 #include <stdio.h>
23 #include <ctype.h>
24 #ifdef HAVE_PWD_H
25 #include <pwd.h>
26 #endif
27
28 /*
29 * standard defines __FP__
30 */
31
32 #ifdef STDC_HEADERS
33 #include <stdlib.h>
34 #include <string.h>
35 #endif
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39
40 #include "conf.h"
41 #include "nntp.h"
42
43
44 #define MAX_SIGNATURE 6
45
46 extern FILE *ser_wr_fp;
47
48 char host_name[256];
49
main(argc,argv)50 main(argc, argv)
51 int argc;
52 char *argv[];
53 {
54 char line[NNTP_STRLEN], s[NNTP_STRLEN];
55 int seen_fromline, in_header, seen_header;
56 int response;
57 char *server;
58 char *getserverbyfile();
59 register char *cp;
60
61 ++argv;
62 while (argc > 1)
63 if (*argv[0] == '-') {
64 ++argv;
65 --argc;
66 } else
67 break;
68
69 if (argc > 1) {
70 if (freopen(*argv, "r", stdin) == NULL) {
71 perror(*argv);
72 exit(1);
73 }
74 }
75
76 uname(host_name);
77
78 server = getserverbyfile(SERVER_FILE);
79 if (server == NULL) {
80 fprintf(stderr,
81 "Can't get the name of the news server from %s.\n",
82 SERVER_FILE);
83 fprintf(stderr,
84 "Either fix this file, or put NNTPSERVER in your enviroment.\n");
85 exit(1);
86 }
87
88 response = server_init(server);
89 if (response < 0) {
90 printf("Couldn't connect to %s news server, try again later.\n",
91 server);
92 exit(1);
93 }
94
95 if (handle_server_response(response, server) < 0
96 || response == OK_NOPOST) {
97 close_server();
98 exit(1);
99 }
100
101 put_server("POST");
102 (void) get_server(line, sizeof(line));
103 if (*line != CHAR_CONT) {
104 if (atoi(line) == ERR_NOPOST) {
105 close_server();
106 fprintf(stderr,
107 "Sorry, you can't post from this machine.\n");
108 exit(1);
109 } else {
110 close_server();
111 fprintf(stderr, "Remote error: %s\n", line);
112 exit(1);
113 }
114 }
115
116 in_header = 1;
117 seen_header = 0;
118 seen_fromline = 0;
119
120 while (fgets(s, NNTP_STRLEN, stdin) != NULL) {
121 while (s[0] && (s[strlen(s)-1] == '\r' || s[strlen(s)-1] == '\n'))
122 s[strlen(s)-1] = '\0';
123 if (s[0] == '.') /* Single . is eof, so put in extra one */
124 (void) fputc('.', ser_wr_fp);
125 if (in_header && strneql(s, "From:", sizeof("From:")-1)) {
126 seen_header = 1;
127 seen_fromline = 1;
128 }
129 if (in_header && s[0] == '\0') {
130 if (seen_header) {
131 in_header = 0;
132 if (!seen_fromline)
133 gen_frompath();
134 } else {
135 continue;
136 }
137 } else if (in_header) {
138 if (valid_header(s))
139 seen_header = 1;
140 else
141 continue;
142 }
143 fprintf(ser_wr_fp, "%s\r\n", s);
144 }
145
146 append_signature();
147
148 fprintf(ser_wr_fp, ".\r\n");
149 (void) fflush(ser_wr_fp);
150 (void) get_server(line, sizeof(line));
151 if (*line != CHAR_OK) {
152 if (atoi(line) == ERR_POSTFAIL) {
153 close_server();
154 printf("Article not accepted by server; not posted.\n");
155 for (cp = line + 4; *cp && *cp != '\r'; cp++)
156 if (*cp == '\\')
157 putchar('\n');
158 else
159 putchar(*cp);
160 exit(1);
161 } else {
162 close_server();
163 fprintf(stderr, "Remote error: %s\n", line);
164 exit(1);
165 }
166 }
167
168 /*
169 * Close server sends the server a
170 * "quit" command for us, which is why we don't send it.
171 */
172
173 close_server();
174
175 exit(0);
176 }
177
178 /*
179 * append_signature -- append the person's .signature file if
180 * they have one. Limit .signature to MAX_SIGNATURE lines.
181 * The rn-style DOTDIR environmental variable is used if present.
182 */
183
append_signature()184 append_signature()
185 {
186 char line[256], sigfile[256];
187 char *cp;
188 struct passwd *passwd;
189 FILE *fp;
190 int count = 0;
191 char *dotdir;
192
193 passwd = getpwuid(getuid());
194 if (passwd == NULL)
195 return;
196 #ifdef DO_DOTDIR
197 if ((dotdir = getenv("DOTDIR")) == NULL)
198 #endif
199 {
200 dotdir = passwd->pw_dir;
201 }
202
203 if (dotdir[0] == '~') {
204 (void) strcpy(sigfile, passwd->pw_dir);
205 (void) strcat(sigfile, &dotdir[1]);
206 } else {
207 (void) strcpy(sigfile, dotdir);
208 }
209 (void) strcat(sigfile, "/");
210 (void) strcat(sigfile, ".signature");
211
212 #ifdef DEBUG
213 fprintf(stderr,"sigfile = '%s'\n", sigfile);
214 #endif
215
216 fp = fopen(sigfile, "r");
217 if (fp == NULL)
218 return;
219
220 #ifdef DEBUG
221 fprintf(stderr,"sigfile opened OK\n");
222 #endif
223
224 fprintf(ser_wr_fp, "--\r\n");
225 while (fgets(line, sizeof (line), fp)) {
226 count++;
227 if (count > MAX_SIGNATURE) {
228 fprintf(stderr,
229 "Warning: .signature files should be no longer than %d lines.\n",
230 MAX_SIGNATURE);
231 fprintf(stderr,
232 "(Only %d lines of your .signature were posted.)\n",
233 MAX_SIGNATURE);
234 break;
235 }
236 if (cp = strchr(line, '\n'))
237 *cp = '\0';
238 fprintf(ser_wr_fp, "%s\r\n", line);
239 }
240 (void) fclose(fp);
241 #ifdef DEBUG
242 printf(".signature appended (from %s)\n", sigfile);
243 #endif
244 }
245
246
247 /*
248 * gen_frompath -- generate From: and Path: lines, in the form
249 *
250 * From: user@host.domain (full_name)
251 * Path: host!user
252 *
253 * This routine should only be called if the message doesn't have
254 * a From: line in it.
255 */
256
gen_frompath()257 gen_frompath()
258 {
259 char *full_name;
260 char *cp;
261 struct passwd *passwd;
262
263 passwd = getpwuid(getuid());
264
265 full_name = getenv("NAME");
266 if (full_name == NULL) {
267 full_name = passwd->pw_gecos;
268 if ((cp = strchr(full_name, ',')))
269 *cp = '\0';
270 }
271
272 /*
273 * changed from #ifdef HIDDENNET __FP__
274 */
275
276 #ifdef DOMAINNAME
277 #ifdef HIDDENNET
278 fprintf(ser_wr_fp, "From: %s@%s (",
279 passwd->pw_name,
280 DOMAINNAME);
281 #else
282 /* A heuristic to see if we should tack on a domain */
283
284 cp = strchr(host_name, '.');
285 if (cp)
286 fprintf(ser_wr_fp, "From: %s@%s (",
287 passwd->pw_name,
288 host_name);
289 else
290 fprintf(ser_wr_fp, "From: %s@%s.%s (",
291 passwd->pw_name,
292 host_name,
293 DOMAINNAME);
294 #endif
295 #else
296 fprintf(ser_wr_fp, "From: %s@%s (",
297 passwd->pw_name,
298 host_name);
299 #endif
300
301 for (cp = full_name; *cp != '\0'; ++cp)
302 if (*cp != '&')
303 putc(*cp, ser_wr_fp);
304 else { /* Stupid & hack. God damn it. */
305 putc(toupper(passwd->pw_name[0]), ser_wr_fp);
306 fprintf(ser_wr_fp, passwd->pw_name+1);
307 }
308
309 fprintf(ser_wr_fp, ")\r\n");
310
311 #ifdef HIDDENNET
312 /* Only the login name - nntp server will add uucp name */
313 fprintf(ser_wr_fp, "Path: %s\r\n", passwd->pw_name);
314 #else
315 fprintf(ser_wr_fp, "Path: %s!%s\r\n", host_name, passwd->pw_name);
316 #endif
317 }
318
319
320 /*
321 * strneql -- determine if two strings are equal in the first n
322 * characters, ignoring case.
323 *
324 * Parameters: "a" and "b" are the pointers
325 * to characters to be compared.
326 * "n" is the number of characters to compare.
327 *
328 * Returns: 1 if the strings are equal, 0 otherwise.
329 *
330 * Side effects: None.
331 */
332
strneql(a,b,n)333 strneql(a, b, n)
334 register char *a, *b;
335 int n;
336 {
337 char lower();
338
339 while (n && lower(*a) == lower(*b)) {
340 if (*a == '\0')
341 return (1);
342 a++;
343 b++;
344 n--;
345 }
346 if (n)
347 return (0);
348 else
349 return (1);
350 }
351
352 /*
353 * lower -- convert a character to lower case, if it's
354 * upper case.
355 *
356 * Parameters: "c" is the character to be
357 * converted.
358 *
359 * Returns: "c" if the character is not
360 * upper case, otherwise the lower
361 * case eqivalent of "c".
362 *
363 * Side effects: None.
364 */
365
lower(c)366 char lower(c)
367 register char c;
368 {
369 if (isascii(c) && isupper(c))
370 c = c - 'A' + 'a';
371 return(c);
372 }
373
374
375 /*
376 * valid_header -- determine if a line is a valid header line
377 *
378 * Parameters: "h" is the header line to be checked.
379 *
380 * Returns: 1 if valid, 0 otherwise
381 *
382 * Side Effects: none
383 *
384 */
385
valid_header(h)386 int valid_header(h)
387 register char *h;
388 {
389 char *colon, *space;
390
391 /*
392 * blank or tab in first position implies this is a continuation header
393 */
394 if (h[0] == ' ' || h[0] == '\t')
395 return (1);
396
397 /*
398 * just check for initial letter, colon, and space to make
399 * sure we discard only invalid headers
400 */
401 colon = strchr (h, ':');
402 space = strchr (h, ' ');
403 if (isalpha(h[0]) && colon && space == colon + 1)
404 return (1);
405
406 /*
407 * anything else is a bad header -- it should be ignored
408 */
409 return (0);
410 }
411