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