1 #include <config.h>
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #ifdef HAVE_UNISTD_H
6 #include <unistd.h>
7 #endif
8 #ifdef HAVE_DIRENT_H
9 # include <dirent.h>
10 #else
11 # define dirent direct
12 # ifdef HAVE_SYS_NDIR_H
13 # include <sys/ndir.h>
14 # endif
15 # ifdef HAVE_SYS_DIR_H
16 # include <sys/dir.h>
17 # endif
18 #endif
19 #include <string.h>
20 #include <sys/types.h>
21 #include <netdb.h>
22 #include <sys/stat.h>
23 #include <errno.h>
24 #include <ctype.h>
25
26 #ifdef DMALLOC
27 #include <dmalloc.h>
28 #endif
29
30 #include "both.h"
31 #include "suck_config.h"
32 #include "phrases.h"
33
34 /* set up defaults */
35 char **test_phrases=default_test_phrases;
36 char **both_phrases=default_both_phrases;
37
38 #define MAXCMDLEN 128 /* length of longest command to send + its args */
39 struct {
40 const char *command;
41 int response;
42 } cmds[] = { { "help", 100 },
43 { "list", 215 },
44 { "list newsgroups", 215 },
45 { "newgroups", 231},
46 { "list overview.fmt", 215},
47 };
48
49 enum { CMD_HELP, CMD_LIST, CMD_DESC, CMD_NEWGRP, CMD_OVERVIEW };
50 enum { RETVAL_OK = 0, RETVAL_ERROR = -1, RETVAL_BAD_DATES = -2, RETVAL_NOAUTH = -3};
51
52 /*-functions----*/
53 int do_a_command(int, int, FILE *, char *, char *, char *, int, void *);
54 int check_date_format(char *, char *, char *);
55 void load_phrases(const char *);
56 void free_phrases(void);
57
58 /*------------------------------------------------------------------*/
main(int argc,char * argv[])59 int main(int argc, char *argv[]) {
60
61 int sockfd, response, loop, cmd, quiet, mode_reader, do_ssl, retval = RETVAL_OK;
62 struct stat sbuf;
63 unsigned short int portnr;
64 FILE *fptr = stdout; /* used to print output to */
65 void *ssl_struct;
66
67 char *host, *buf, *ptr, *cmdargs, *userid, *passwd;
68 char ndate[14]; /* 6 for yymmdd 6 for hhmmss and 1 for space and 1 for null */
69
70 const char *phrases;
71
72 /* set up defaults */
73 host = getenv("NNTPSERVER");
74 cmd = CMD_HELP;
75 loop = 1;
76 cmdargs = NULL;
77 portnr = DEFAULT_NNRP_PORT;
78 passwd = NULL;
79 userid = NULL;
80 phrases = NULL;
81 mode_reader = FALSE;
82 do_ssl = FALSE;
83 quiet = FALSE; /* do we show status or not */
84
85 /* have to do this next so if set on cmd line, overrides this */
86 #ifdef N_PHRASES /* in case someone nukes def */
87 if(stat(N_PHRASES, &sbuf) == 0 && S_ISREG(sbuf.st_mode)) {
88 /* we have a regular phrases file make it the default */
89 phrases = N_PHRASES;
90 }
91
92 #endif
93
94 if(argc > 1 && argv[loop][0] != '-') {
95 host = argv[loop++];
96 }
97 for(;loop<argc;loop++) {
98 if(argv[loop][0] == '-') {
99 switch(argv[loop][1]) {
100 case 'a':
101 cmd = CMD_LIST;
102 break;
103 case 'd':
104 cmd = CMD_DESC;
105 break;
106 case 'o':
107 cmd = CMD_OVERVIEW;
108 break;
109 case 'q':
110 quiet = TRUE;
111 break;
112 case 'M':
113 mode_reader = TRUE;
114 break;
115 case 'n':
116 cmd = CMD_NEWGRP;
117 /* next two args must be date & time YYMMDD HHMMSS format */
118 if(loop + 2 > argc) {
119 error_log(ERRLOG_REPORT, test_phrases[0], NULL);
120 retval = RETVAL_ERROR;
121 }
122 else {
123 if((retval = check_date_format(ndate, argv[loop+1], argv[loop+2])) == RETVAL_OK) {
124 cmdargs = ndate;
125 }
126 else {
127 error_log(ERRLOG_REPORT, test_phrases[1], argv[loop+1], argv[loop+2], NULL);
128 }
129 loop += 2; /* past the args if there, if not this will finish up the arg loop */
130 }
131 break;
132 case 'e': /* use default error log path */
133 error_log(ERRLOG_SET_FILE, ERROR_LOG, NULL);
134 break;
135 case 'E': /* error log path */
136 if(loop+1 == argc) {
137 error_log(ERRLOG_REPORT, test_phrases[2], NULL);
138 retval = RETVAL_ERROR;
139 }
140 else {
141 error_log(ERRLOG_SET_FILE, argv[++loop], NULL);
142 }
143 break;
144 case 's': /* use default status log path */
145 if((fptr = fopen(STATUS_LOG, "a")) == NULL) {
146 MyPerror(test_phrases[3]);
147 retval = RETVAL_ERROR;
148 }
149 break;
150 case 'S': /* status log path */
151 if(loop+1 == argc) {
152 error_log(ERRLOG_REPORT, test_phrases[12], NULL);
153 retval = RETVAL_ERROR;
154 }
155 else if((fptr = fopen(argv[++loop], "a")) == NULL) {
156 MyPerror(test_phrases[3]);
157 retval = RETVAL_ERROR;
158 }
159 break;
160 case 'N': /* override port nr */
161 if(loop+1 == argc) {
162 error_log(ERRLOG_REPORT, test_phrases[4], NULL);
163 retval = RETVAL_ERROR;
164 }
165 else {
166 portnr = atoi(argv[++loop]);
167 }
168 break;
169 case 'U': /* next arg is userid for authorization */
170 if(loop+1 == argc) {
171 error_log(ERRLOG_REPORT, test_phrases[5], NULL);
172 retval = RETVAL_ERROR;
173 }
174 else {
175 userid = argv[++loop];
176 }
177 break;
178 case 'P': /* next arg is password for authorization */
179 if(loop+1 == argc) {
180 error_log(ERRLOG_REPORT, test_phrases[6], NULL);
181 retval = RETVAL_ERROR;
182 }
183 else {
184 passwd = argv[++loop];
185 }
186 break;
187 case 'Q': /* get from env */
188 userid = getenv("NNTP_USER");
189 passwd = getenv("NNTP_PASS");
190 break;
191 case 'l': /* next arg is phrases file */
192 if(loop+1 == argc) {
193 error_log(ERRLOG_REPORT, test_phrases[11], NULL);
194 retval = RETVAL_ERROR;
195 }
196 else {
197 phrases = argv[++loop];
198 }
199 break;
200 #ifdef TIMEOUT
201 case 'T': /* timeout */
202 if(loop+1 == argc) {
203 error_log(ERRLOG_REPORT, test_phrases[13], NULL);
204 retval = RETVAL_ERROR;
205 }
206 else {
207 TimeOut = atoi(argv[++loop]);
208 }
209 break;
210 #endif
211 #ifdef HAVE_LIBSSL
212 case 'z':
213 do_ssl = TRUE;
214 portnr = DEFAULT_SSL_PORT;
215 break;
216 #endif
217 default:
218 retval = RETVAL_ERROR;
219 error_log(ERRLOG_REPORT, test_phrases[7], argv[loop], NULL);
220 }
221 }
222 else {
223 retval = RETVAL_ERROR;
224 error_log(ERRLOG_REPORT, test_phrases[7], argv[loop], NULL);
225 }
226 }
227
228 if(retval == RETVAL_OK) {
229 load_phrases(phrases); /* this is here so everything displays okay */
230
231 sockfd = connect_to_nntphost( host, NULL, 0, (quiet == FALSE)? fptr : NULL, portnr, do_ssl, &ssl_struct);
232 if(sockfd < 0 ) {
233 retval = RETVAL_ERROR;
234 }
235 /* get the announcement line */
236 else if(sgetline(sockfd, &buf, do_ssl, ssl_struct) < 0) {
237 retval = RETVAL_ERROR;
238 }
239 else {
240 ptr = number(buf, &response);
241 if(quiet == FALSE) {
242 fprintf(fptr,"%s",ptr); /* print it */
243 }
244
245 if(response != 200 && response != 201) {
246 /* not a valid response */
247 retval = RETVAL_ERROR;
248 }
249 else {
250 if(mode_reader == TRUE) {
251 sputline(sockfd, "mode reader\r\n", do_ssl, ssl_struct);
252 sgetline(sockfd, &buf, do_ssl, ssl_struct);
253 }
254 do_a_command(sockfd, cmd, fptr, cmdargs, userid, passwd, do_ssl, ssl_struct);
255 }
256 }
257 if(sockfd >= 0) {
258 disconnect_from_nntphost(sockfd, do_ssl, &ssl_struct);
259 }
260
261 if(retval == RETVAL_ERROR) {
262 error_log(ERRLOG_REPORT, test_phrases[8], host, NULL);
263 }
264 }
265 if(fptr != stdout && fptr != NULL) {
266 fclose(fptr);
267 }
268 free_phrases(); /* do this last so everything is displayed correctly */
269 exit(retval);
270 }
271 /*-------------------------------------------------------------------------------*/
do_a_command(int sockfd,int cmd,FILE * fptr,char * cmdargs,char * userid,char * passwd,int do_ssl,void * ssl_struct)272 int do_a_command(int sockfd, int cmd, FILE *fptr, char *cmdargs, char *userid, char *passwd, int do_ssl, void *ssl_struct ) {
273 char *ptr, *buf, cmdstr[MAXCMDLEN], buf2[MAXCMDLEN];
274 int response;
275 int len, done, retval = RETVAL_OK;
276
277 /* build command to send */
278 strcpy(cmdstr, cmds[cmd].command);
279 if(cmdargs != NULL) {
280 strcat(cmdstr, " ");
281 strcat(cmdstr, cmdargs);
282 }
283 strcat(cmdstr, "\r\n");
284
285 sputline(sockfd, cmdstr, do_ssl, ssl_struct); /* which command do I run? */
286 sgetline(sockfd, &buf, do_ssl, ssl_struct); /* get response */
287
288 ptr = number(buf, &response);
289 if(response == 480 ) { /* we must do authorization */
290 sprintf(buf2, "AUTHINFO USER %s\r\n", userid);
291 sputline(sockfd, buf2, do_ssl, ssl_struct);
292 len = sgetline(sockfd, &buf, do_ssl, ssl_struct);
293 if( len < 0) {
294 retval = RETVAL_ERROR;
295 }
296 else {
297 ptr = number(buf, &response);
298 if(response != 381) {
299 error_log(ERRLOG_REPORT, test_phrases[9], buf, NULL);
300 retval = RETVAL_NOAUTH;
301 }
302 else {
303 sprintf(buf2, "AUTHINFO PASS %s\r\n", passwd);
304 sputline(sockfd, buf2, do_ssl, ssl_struct);
305 len = sgetline(sockfd, &buf, do_ssl, ssl_struct);
306 if(len < 0) {
307 retval = RETVAL_ERROR;
308 }
309 else {
310 number(buf, &response);
311 switch(response) {
312 case 281: /* bingo resend original command*/
313 sputline(sockfd, cmdstr, do_ssl, ssl_struct);
314 len = sgetline(sockfd, &buf, do_ssl, ssl_struct);
315 if( len < 0) {
316 retval = RETVAL_ERROR;
317 }
318 else {
319 ptr = number(buf,&response);
320 }
321 break;
322 case 502: /* permission denied */
323 retval = RETVAL_NOAUTH;
324 error_log(ERRLOG_REPORT, test_phrases[10], NULL);
325 break;
326 default: /* wacko error */
327 error_log(ERRLOG_REPORT, test_phrases[9], ptr, NULL);
328 retval = RETVAL_NOAUTH;
329 break;
330 }
331 }
332 }
333 }
334 }
335 if(cmds[cmd].response != response) {
336 error_log(ERRLOG_REPORT, "%v1%\n", buf, NULL);
337 retval = RETVAL_ERROR;
338 }
339 else {
340 /* okay here we go */
341 fprintf(fptr, "%s", ptr);
342 /* commands are ended by a . on a line by itself */
343
344 len = done = 0;
345 while( len >=0 && done == 0) {
346
347 len = sgetline(sockfd, &buf, do_ssl, ssl_struct);
348
349 if(len == 2 && strcmp(buf, ".\n") == 0) {
350 done = 1;
351 }
352 else if(len > 0) {
353 fprintf(fptr,"%s",buf);
354 }
355 }
356 if(len < 0) {
357 retval = RETVAL_ERROR;
358 }
359 }
360 return retval;
361 }
362 /*---------------------------------------------------------------*/
check_date_format(char * dates,char * indate,char * intime)363 int check_date_format(char *dates, char *indate, char *intime) {
364
365 /* if indate & intime are not valid format, return error */
366 /* when done, dates will be yymmdd hhmmss */
367
368 int i, retval = RETVAL_OK;
369
370 /* now test my incoming args */
371 if(indate == NULL || intime == NULL) {
372 retval = RETVAL_ERROR;
373 }
374 else if(strlen(indate) != 6 || strlen(intime) != 6) {
375 retval = RETVAL_ERROR;
376 }
377 else {
378 for(i=0;i<6;i++) {
379 if(!isdigit(indate[i]) || !isdigit(intime[i])) {
380 retval = RETVAL_ERROR;
381 }
382 }
383 }
384
385 if(retval == RETVAL_OK) {
386 sprintf(dates, "%s %s", indate, intime);
387 }
388 return retval;
389 }
390 /*--------------------------------------------------------------------------------*/
391 /* THE strings in this routine is the only one not in the arrays, since */
392 /* we are in the middle of reading the arrays, and they may or may not be valid. */
393 /*--------------------------------------------------------------------------------*/
load_phrases(const char * phrases)394 void load_phrases(const char *phrases) {
395
396 int error=TRUE;
397 FILE *fpi;
398 char buf[MAXLINLEN];
399
400 if(phrases != NULL) {
401
402 if((fpi = fopen(phrases, "r")) == NULL) {
403 MyPerror(phrases);
404 }
405 else {
406 fgets(buf, MAXLINLEN, fpi);
407 if(strncmp( buf, SUCK_VERSION, strlen(SUCK_VERSION)) != 0) {
408 error_log(ERRLOG_REPORT, "Invalid Phrase File, wrong version\n", NULL);
409 }
410 else if((both_phrases = read_array(fpi, NR_BOTH_PHRASES, TRUE)) != NULL) {
411 read_array(fpi, NR_RPOST_PHRASES, FALSE); /* skip these */
412 if((test_phrases = read_array(fpi, NR_TEST_PHRASES, TRUE)) != NULL) {
413 error = FALSE;
414 }
415 }
416 }
417 fclose(fpi);
418 if(error == TRUE) {
419 /* reset back to default */
420 error_log(ERRLOG_REPORT, "Using default Language phrases\n", NULL);
421 test_phrases = default_test_phrases;
422 both_phrases = default_both_phrases;
423 }
424 }
425 }
426 /*--------------------------------------------------------------------------------*/
free_phrases(void)427 void free_phrases(void) {
428 /* free up the memory alloced in load_phrases() */
429 if(test_phrases != default_test_phrases) {
430 free_array(NR_TEST_PHRASES, test_phrases);
431 }
432 if(both_phrases != default_both_phrases) {
433 free_array(NR_BOTH_PHRASES, both_phrases);
434 }
435
436 }
437