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