1 /* inews.c
2  */
3 /* This software is copyrighted as detailed in the LICENSE file. */
4 
5 
6 #include "EXTERN.h"
7 #include "common.h"
8 #include "env.h"
9 #include "init.h"
10 #include "util2.h"
11 #include "util3.h"
12 #include "nntpclient.h"
13 #include "nntpinit.h"
14 
15 #define	MAX_SIGNATURE	4
16 
17 int	debug = 0;
18 int	new_connection = FALSE;
19 char*	server_name;
20 char*	nntp_auth_file;
21 char	nullstr[1];
22 
23 char	buf[LBUFLEN+1];
24 
25 int valid_header _((char*));
26 void append_signature _((void));
27 
28 int
main(argc,argv)29 main(argc, argv)
30 int argc;
31 char* argv[];
32 {
33     bool has_fromline, in_header, has_pathline;
34     bool found_nl, had_nl;
35     int artpos, headbuf_size, len;
36     char* headbuf;
37     char* line_end;
38     register char* cp;
39     int i;
40 
41     headbuf_size = LBUFLEN * 8;
42     headbuf = safemalloc(headbuf_size);
43 
44 #ifdef LAX_INEWS
45     env_init(headbuf, 1);
46 #else
47     if (!env_init(headbuf, 0)) {
48 	fprintf(stderr,"Can't get %s information. Please contact your system adminstrator.\n",
49 		(*loginName || !*realName)? "user" : "host");
50 	exit(1);
51     }
52 #endif
53 
54     argv++;
55     while (argc > 1) {
56 	if (*argv[0] != '-')
57 	    break;
58 	argv++;
59 	argc--;
60     }
61     if (argc > 1) {
62 	if (freopen(*argv, "r", stdin) == NULL) {
63 	    perror(*argv);
64 	    exit(1);
65 	}
66     }
67 
68     cp = getenv("NNTPSERVER");
69     if (!cp) {
70 	cp = filexp(SERVER_NAME);
71 	if (FILE_REF(cp))
72 	    cp = nntp_servername(cp);
73     }
74     if (cp && *cp && strNE(cp,"local")) {
75 	server_name = savestr(cp);
76 	cp = index(server_name, ';');
77 	if (cp) {
78 	    *cp = '\0';
79 	    nntplink.port_number = atoi(cp+1);
80 	}
81 	line_end = "\r\n";
82 	nntp_auth_file = filexp(NNTP_AUTH_FILE);
83 	if ((cp = getenv("NNTP_FORCE_AUTH")) != NULL
84 	 && (*cp == 'y' || *cp == 'Y'))
85 	    nntplink.flags |= NNTP_FORCE_AUTH_NEEDED;
86     } else {
87 	server_name = NULL;
88 	line_end = "\n";
89     }
90 
91     in_header = 0;
92     has_fromline = 0;
93     has_pathline = 0;
94     artpos = 0;
95     cp = headbuf;
96     had_nl = 1;
97 
98     for (;;) {
99 	if (headbuf_size < artpos + LBUFLEN + 1) {
100 	    len = cp - headbuf;
101 	    headbuf_size += LBUFLEN * 4;
102 	    headbuf = saferealloc(headbuf,headbuf_size);
103 	    cp = headbuf + len;
104 	}
105 	i = getc(stdin);
106 	if (server_name && had_nl && i == '.')
107 	    *cp++ = '.';
108 
109 	if (i == '\n') {
110 	    if (!in_header)
111 		continue;
112 	    break;
113 	}
114 	else if (i == EOF || !fgets(cp+1, LBUFLEN-1, stdin)) {
115 	    /* Still in header after EOF?  Hmm... */
116 	    fprintf(stderr,"Article was all header -- no body.\n");
117 	    exit(1);
118 	}
119 	*cp = (char)i;
120 	len = strlen(cp);
121 	found_nl = (len && cp[len-1] == '\n');
122 	if (had_nl) {
123 	    if ((i = valid_header(cp)) == 0) {
124 		fprintf(stderr,"Invalid header:\n%s",cp);
125 		exit(1);
126 	    }
127 	    if (i == 2) {
128 		if (!in_header)
129 		    continue;
130 		break;
131 	    }
132 	    in_header = 1;
133 	    if (strncaseEQ(cp, "From:", 5))
134 		has_fromline = 1;
135 	    else if (strncaseEQ(cp, "Path:", 5))
136 		has_pathline = 1;
137 	}
138 	artpos += len;
139 	cp += len;
140 	if ((had_nl = found_nl) != 0 && server_name) {
141 	    cp[-1] = '\r';
142 	    *cp++ = '\n';
143 	}
144     }
145     *cp = '\0';
146 
147     /* Well, the header looks ok, so let's get on with it. */
148 
149     if (server_name) {
150 	if ((cp = getenv("NNTPFDS")) != NULL) {
151 	    int rd_fd, wr_fd;
152 	    if (sscanf(cp,"%d.%d",&rd_fd,&wr_fd) == 2) {
153 		nntplink.rd_fp = fdopen(rd_fd, "r");
154 		if (nntplink.rd_fp) {
155 		    nntplink.wr_fp = fdopen(wr_fd, "w");
156 		    if (nntplink.wr_fp)
157 			nntplink.flags |= NNTP_NEW_CMD_OK;
158 		    else
159 			nntp_close(FALSE);
160 		}
161 	    }
162 	}
163 	if (!nntplink.wr_fp) {
164 	    if (init_nntp() < 0 || !nntp_connect(server_name,0))
165 		exit(1);
166 	    new_connection = TRUE;
167 	}
168 	if (nntp_command("POST") <= 0 || nntp_check() <= 0) {
169 	    if (new_connection)
170 		nntp_close(TRUE);
171 	    fprintf(stderr,"Sorry, you can't post from this machine.\n");
172 	    exit(1);
173 	}
174     }
175     else {
176 	sprintf(buf, "%s -h", EXTRAINEWS);
177 	nntplink.wr_fp = popen(buf,"w");
178 	if (!nntplink.wr_fp) {
179 	    fprintf(stderr,"Unable to execute inews for local posting.\n");
180 	    exit(1);
181 	}
182     }
183 
184     fputs(headbuf, nntplink.wr_fp);
185     if (!has_pathline)
186 	fprintf(nntplink.wr_fp,"Path: not-for-mail%s",line_end);
187     if (!has_fromline) {
188 	fprintf(nntplink.wr_fp,"From: %s@%s (%s)%s",loginName,phostname,
189 		getval("NAME",realName),line_end);
190     }
191     if (!getenv("NO_ORIGINATOR")) {
192 	fprintf(nntplink.wr_fp,"Originator: %s@%s (%s)%s",loginName,phostname,
193 		getval("NAME",realName),line_end);
194     }
195     fprintf(nntplink.wr_fp,"%s",line_end);
196 
197     had_nl = 1;
198     while (fgets(headbuf, headbuf_size, stdin)) {
199 	/* Single . is eof, so put in extra one */
200 	if (server_name && had_nl && *headbuf == '.')
201 	    fputc('.', nntplink.wr_fp);
202 	/* check on newline */
203 	cp = headbuf + strlen(headbuf);
204 	if (cp > headbuf && *--cp == '\n') {
205 	    *cp = '\0';
206 	    fprintf(nntplink.wr_fp, "%s%s", headbuf, line_end);
207 	    had_nl = 1;
208 	}
209 	else {
210 	    fputs(headbuf, nntplink.wr_fp);
211 	    had_nl = 0;
212 	}
213     }
214 
215     if (!server_name)
216 	return pclose(nntplink.wr_fp);
217 
218     if (!had_nl)
219         fputs(line_end, nntplink.wr_fp);
220 
221     append_signature();
222 
223     fputs(".\r\n",nntplink.wr_fp);
224     (void) fflush(nntplink.wr_fp);
225 
226     if (nntp_gets(ser_line, sizeof ser_line) < 0
227      || *ser_line != NNTP_CLASS_OK) {
228 	if (atoi(ser_line) == NNTP_POSTFAIL_VAL) {
229 	    fprintf(stderr,"Article not accepted by server; not posted:\n");
230 	    for (cp = ser_line + 4; *cp && *cp != '\r'; cp++) {
231 		if (*cp == '\\')
232 		    fputc('\n',stderr);
233 		else
234 		    fputc(*cp,stderr);
235 	    }
236 	    fputc('\n', stderr);
237 	}
238 	else
239 	    fprintf(stderr, "Remote error: %s\n", ser_line);
240 	if (new_connection)
241 	    nntp_close(TRUE);
242 	exit(1);
243     }
244 
245     if (new_connection)
246 	nntp_close(TRUE);
247     cleanup_nntp();
248 
249     return 0;
250 }
251 
252 /* valid_header -- determine if a line is a valid header line */
253 int
valid_header(h)254 valid_header(h)
255 register char* h;
256 {
257     char* colon;
258     char* space;
259 
260     /* Blank or tab in first position implies this is a continuation header */
261     if (h[0] == ' ' || h[0] == '\t') {
262 	while (*++h == ' ' || *h == '\t') ;
263 	return *h && *h != '\n'? 1 : 2;
264     }
265 
266     /* Just check for initial letter, colon, and space to make
267      * sure we discard only invalid headers. */
268     colon = index(h, ':');
269     space = index(h, ' ');
270     if (isalpha(h[0]) && colon && space == colon + 1)
271 	return 1;
272 
273     /* Anything else is a bad header */
274     return 0;
275 }
276 
277 /* append_signature -- append the person's .signature file if
278  * they have one.  Limit .signature to MAX_SIGNATURE lines.
279  * The rn-style DOTDIR environmental variable is used if present.
280  */
281 void
append_signature()282 append_signature()
283 {
284     char* cp;
285     FILE* fp;
286     int count = 0;
287 
288 #ifdef NO_INEWS_DOTDIR
289     dotdir = homedir;
290 #endif
291     if (dotdir == NULL)
292 	return;
293 
294     fp = fopen(filexp(SIGNATURE_FILE), "r");
295     if (fp == NULL)
296 	return;
297 
298     fprintf(nntplink.wr_fp, "-- \r\n");
299     while (fgets(ser_line, sizeof ser_line, fp)) {
300 	count++;
301 	if (count > MAX_SIGNATURE) {
302 	    fprintf(stderr,"Warning: .signature files should be no longer than %d lines.\n",
303 		    MAX_SIGNATURE);
304 	    fprintf(stderr,"(Only %d lines of your .signature were posted.)\n",
305 		    MAX_SIGNATURE);
306 	    break;
307 	}
308 	/* Strip trailing newline */
309 	cp = ser_line + strlen(ser_line) - 1;
310 	if (cp >= ser_line && *cp == '\n')
311 	    *cp = '\0';
312 	fprintf(nntplink.wr_fp, "%s\r\n", ser_line);
313     }
314     (void) fclose(fp);
315 }
316 
317 #ifdef SUPPORT_NNTP
318 int
nntp_handle_timeout()319 nntp_handle_timeout()
320 {
321     if (!new_connection) {
322 	static bool handling_timeout = FALSE;
323 	char last_command_save[NNTP_STRLEN];
324 
325 	if (strcaseEQ(last_command,"quit"))
326 	    return 0;
327 	if (handling_timeout)
328 	    return -1;
329 	handling_timeout = TRUE;
330 	strcpy(last_command_save, last_command);
331 	nntp_close(FALSE);
332 	if (init_nntp() < 0 || nntp_connect(server_name,0) <= 0)
333 	    exit(1);
334 	if (nntp_command(last_command_save) <= 0)
335 	    return -1;
336 	handling_timeout = FALSE;
337 	new_connection = TRUE;
338 	return 1;
339     }
340     fputs("\n503 Server timed out.\n",stderr);
341     return -2;
342 }
343 #endif
344