1 #include <config.h>
2 
3 #include <stdio.h>
4 #include <stdlib.h>
5 
6 #ifdef HAVE_UNISTD_H
7 #include <unistd.h>
8 #endif
9 
10 #ifdef HAVE_SYS_WAIT_H
11 #include <sys/wait.h>
12 #endif
13 
14 #ifdef HAVE_DIRENT_H
15 # include <dirent.h>
16 #else
17 # ifdef HAVE_SYS_NDIR_H
18 #  include <sys/ndir.h>
19 # endif
20 # ifdef HAVE_SYS_DIR_H
21 #  include <sys/dir.h>
22 # endif
23 #endif
24 
25 #ifdef HAVE_LIMITS_H
26 #include <limits.h>
27 #endif
28 
29 #include <string.h>
30 #include <sys/types.h>
31 #include <netdb.h>
32 #include <sys/stat.h>
33 #include <math.h>
34 #include <errno.h>
35 #include <ctype.h>
36 
37 #ifdef DMALLOC
38 #include <dmalloc.h>
39 #endif
40 
41 #include "suck_config.h"
42 #include "both.h"
43 #include "suck.h"
44 #include "suckutils.h"
45 #include "dedupe.h"
46 #include "phrases.h"
47 #include "killfile.h"
48 #include "timer.h"
49 #include "active.h"
50 #include "batch.h"
51 #include "xover.h"
52 #include "db.h"
53 
54 #ifdef MYSIGNAL
55 #include <signal.h>
56 #endif
57 
58 #ifdef CHECK_HISTORY
59 #include "chkhistory.h"
60 #endif
61 
62 /* function prototypes */
63 int get_articles(PMaster);
64 int get_one_article(PMaster, int, long);
65 int do_supplemental(PMaster);
66 int restart_yn(PMaster);
67 int scan_args(PMaster, int, char *[]);
68 void do_cleanup(PMaster);
69 int do_authenticate(PMaster);
70 void load_phrases(PMaster);
71 void free_phrases(void);
72 int parse_args(PMaster, int, char *[]);
73 int get_group_number(PMaster, char *);
74 int do_supplemental(PMaster);
75 int do_sup_bynr(PMaster, char *);
76 int do_nodownload(PMaster);
77 #ifdef MYSIGNAL
78 RETSIGTYPE sighandler(int);
79 void pause_signal(int, PMaster);
80 enum {PAUSE_SETUP, PAUSE_DO};
81 
82 /*------------------------------------------*/
83 int GotSignal = FALSE;
84 /* the only static variable allowed, it's   */
85 /* the only graceful way to handle a signal */
86 /*------------------------------------------*/
87 #endif
88 
89 /* set up for phrases */
90 char **both_phrases=default_both_phrases;
91 char **suck_phrases=default_suck_phrases;
92 char **timer_phrases=default_timer_phrases;
93 char **chkh_phrases=default_chkh_phrases;
94 char **dedupe_phrases=default_dedupe_phrases;
95 char **killf_reasons=default_killf_reasons;
96 char **killf_phrases=default_killf_phrases;
97 char **killp_phrases=default_killp_phrases;
98 char **sucku_phrases=default_sucku_phrases;
99 char **active_phrases=default_active_phrases;
100 char **batch_phrases=default_batch_phrases;
101 char **xover_phrases=default_xover_phrases;
102 char **xover_reasons=default_xover_reasons;
103 
104 
105 enum { STATUS_STDOUT, STATUS_STDERR };
106 enum { RESTART_YES, RESTART_NO, RESTART_ERROR };
107 
108 enum {
109 	ARG_NO_MATCH, ARG_ALWAYS_BATCH, ARG_BATCH_INN, ARG_BATCH_RNEWS, ARG_BATCH_LMOVE, \
110 	ARG_BATCH_INNFEED, ARG_BATCH_POST, ARG_CLEANUP, ARG_DIR_TEMP, ARG_DIR_DATA, ARG_DIR_MSGS, \
111 	ARG_DEF_ERRLOG, ARG_HOST, ARG_NO_POSTFIX, ARG_LANGUAGE, ARG_MULTIFILE,  ARG_POSTFIX, \
112 	ARG_QUIET, ARG_RNEWSSIZE, ARG_DEF_STATLOG, ARG_WAIT_SIG, ARG_ACTIVE, ARG_RECONNECT, \
113 	ARG_DEBUG, ARG_ERRLOG, ARG_HISTORY, ARG_KILLFILE, ARG_KLOG_NONE, ARG_KLOG_SHORT,  \
114 	ARG_KLOG_LONG, ARG_MODEREADER, ARG_PORTNR, ARG_PASSWD, ARG_RESCAN, ARG_STATLOG, \
115 	ARG_USERID, ARG_VERSION, ARG_WAIT, ARG_LOCALHOST, ARG_TIMEOUT, ARG_NRMODE, ARG_AUTOAUTH, \
116 	ARG_NODEDUPE, ARG_NO_CHK_MSGID, ARG_READACTIVE, ARG_PREBATCH, ARG_SKIP_ON_RESTART, \
117 	ARG_KLOG_NAME, ARG_USEGUI, ARG_XOVER, ARG_CONN_DEDUPE, ARG_POST_FILTER, ARG_CONN_ACTIVE, \
118 	ARG_HIST_FILE, ARG_HEADER_ONLY, ARG_ACTIVE_LASTREAD, ARG_USEXOVER, ARG_RESETCOUNTER, \
119 	ARG_LOW_READ, ARG_SHOW_GROUP, ARG_USE_SSL, ARG_LOCAL_SSL, ARG_BATCH_POST_NR, \
120 	ARG_PASSWD_ENV,
121 };
122 
123 typedef struct Arglist{
124 	const char *sarg;
125 	const char *larg;
126 	int nr_params;
127 	int flag;
128 	int errmsg;		/* this is an index into suck_phrases */
129 } Args, *Pargs;
130 
131 const Args arglist[] = {
132 	{"a",  "always_batch", 0, ARG_ALWAYS_BATCH, -1},
133 	{"bi", "batch_inn",    1, ARG_BATCH_INN, 40},
134 	{"br", "batch_rnews",  1, ARG_BATCH_RNEWS, 40},
135 	{"bl", "batch_lmove",  1, ARG_BATCH_LMOVE, 40},
136 	{"bf", "batch_innfeed",1, ARG_BATCH_INNFEED, 40},
137 	{"bp", "batch_post",   0, ARG_BATCH_POST, -1},
138 	{"bP", "batch_post_nr", 1, ARG_BATCH_POST_NR, 72},
139 	{"c",  "cleanup",      0, ARG_CLEANUP, -1},
140 	{"dt", "dir_temp",    1, ARG_DIR_TEMP, 37},
141 	{"dd", "dir_data",    1, ARG_DIR_DATA, 37},
142 	{"dm", "dir_msgs",    1, ARG_DIR_MSGS, 37},
143 	{"e",  "def_error_log", 0, ARG_DEF_ERRLOG, -1},
144 	{"f",  "reconnect_dedupe", 0, ARG_CONN_DEDUPE, -1},
145 	{"g",  "header_only", 0, ARG_HEADER_ONLY, -1},
146 	{"h",  "host", 1, ARG_HOST, 51},
147 	{"hl", "localhost", 1, ARG_LOCALHOST, 50},
148 	{"i",  "default_activeread", 1, ARG_ACTIVE_LASTREAD, 65},
149 	{"k",  "kill_no_postfix", 0, ARG_NO_POSTFIX, -1},
150 	{"l",  "language_file", 1, ARG_LANGUAGE, 47},
151 	{"lr", "low_read", 0, ARG_LOW_READ, -1},
152 	{"m",  "multifile", 0, ARG_MULTIFILE, -1},
153 	{"n",  "number_mode", 0, ARG_NRMODE, -1},
154 	{"p",  "postfix", 1, ARG_POSTFIX, 36},
155 	{"q",  "quiet", 0, ARG_QUIET, -1},
156 	{"r",  "rnews_size", 1, ARG_RNEWSSIZE, 35},
157 	{"rc", "reset_counter", 0, ARG_RESETCOUNTER, -1},
158 	{"s",  "def_status_log", 0, ARG_DEF_STATLOG, -1},
159 	{"sg", "show_group", 0, ARG_SHOW_GROUP, -1},
160 #ifdef HAVE_LIBSSL
161 	{"ssl","use_ssl", 0, ARG_USE_SSL, -1},
162 #endif
163 	{"u",  "auto_authorization", 0, ARG_AUTOAUTH, -1},
164 	{"w",  "wait_signal", 2, ARG_WAIT_SIG, 46},
165 	{"x",  "no_chk_msgid", 0, ARG_NO_CHK_MSGID, -1},
166 	{"y",  "post_filter", 1, ARG_POST_FILTER, 62},
167 	{"z",  "no_dedupe", 0, ARG_NODEDUPE, -1},
168 	{"A",  "active", 0, ARG_ACTIVE, -1},
169 	{"AL", "read_active", 1, ARG_READACTIVE, 56},
170 	{"B",  "pre-batch", 0, ARG_PREBATCH, -1},
171 	{"C",  "reconnect", 1, ARG_RECONNECT, 49},
172 	{"D",  "debug", 0, ARG_DEBUG, -1},
173 	{"E",  "error_log", 1, ARG_ERRLOG, 41},
174 	{"F",  "reconnect_active", 0, ARG_CONN_ACTIVE, -1},
175 	{"G",  "use_gui", 0, ARG_USEGUI, -1},
176 	{"H",  "no_history", 0, ARG_HISTORY, -1},
177 	{"HF", "history_file", 1, ARG_HIST_FILE, 64},
178 	{"K",  "killfile", 0, ARG_KILLFILE, -1},
179 	{"L",  "kill_log_none", 0, ARG_KLOG_NONE, -1},
180 	{"LF", "kill_log_name", 1, ARG_KLOG_NAME, 61},
181 	{"LS", "kill_log_short", 0, ARG_KLOG_SHORT, -1},
182 	{"LL", "kill_log_long",  0, ARG_KLOG_LONG, -1},
183 	{"M",  "mode_reader", 0, ARG_MODEREADER, -1},
184 	{"N",  "portnr", 1, ARG_PORTNR, 45},
185 	{"O",  "skip_on_restart", 0, ARG_SKIP_ON_RESTART, -1},
186 	{"P",  "password", 1, ARG_PASSWD, 44},
187         {"Q",  "password_env", 0, ARG_PASSWD_ENV, -1},
188 	{"R",  "no_rescan", 0, ARG_RESCAN, -1},
189 	{"S",  "status_log", 1, ARG_STATLOG, 42},
190 #ifdef HAVE_LIBSSL
191 	{"SSL" "local_use_ssl", 0, ARG_LOCAL_SSL, -1},
192 #endif
193 #ifdef TIMEOUT
194 	{"T",  "timeout", 1, ARG_TIMEOUT, 52},
195 #endif
196 	{"U",  "userid",  1, ARG_USERID,  43},
197 	{"V",  "version", 0, ARG_VERSION, -1},
198 	{"W",  "wait", 2, ARG_WAIT, 46},
199 	{"X",  "no_xover", 0, ARG_XOVER, -1},
200 	{"Z",  "use_xover", 0, ARG_USEXOVER, -1},
201 
202 };
203 
204 #define MAX_ARG_PARAMS 2	/* max nr of params with any arg */
205 #define NR_ARGS (sizeof(arglist)/sizeof(arglist[0]))
206 
207 /*------------------------------------------------------------------*/
main(int argc,char * argv[])208 int main(int argc, char *argv[]) {
209 
210 	struct stat sbuf;
211 	Master master;
212 	PList temp;
213 	PGroups ptemp;
214 	POverview pov;
215 	char *inbuf, **args, **fargs = NULL;
216 	int nr, resp, loop, fargc, retval = RETVAL_OK;
217 
218 #ifdef LOCKFILE
219 	const char *lockfile = NULL;
220 #endif
221 #ifdef MYSIGNAL
222 #ifdef HAVE_SIGACTION
223 	struct sigaction sigs;
224 #endif
225 #endif
226 
227 	/* initialize master structure */
228 	master.head = master.curr = NULL;
229 	master.nritems = master.nrgot = 0;
230 	master.MultiFile = FALSE;
231 	master.msgs = stdout;
232 	master.sockfd = -1;
233 	master.status_file = FALSE;	/* are status messages going to a file */
234 	master.status_file_name = NULL;
235 	master.do_killfile = TRUE;
236 	master.do_chkhistory = TRUE;
237 	master.do_modereader = FALSE;
238 	master.always_batch = FALSE;
239 	master.rnews_size = 0L;
240 	master.batch = BATCH_FALSE;
241 	master.batchfile = NULL;
242 	master.cleanup = FALSE;
243 	master.portnr = DEFAULT_NNRP_PORT;
244 	master.host = getenv("NNTPSERVER");		/* the default */
245 	master.pause_time = -1;
246 	master.pause_nrmsgs = -1;
247 	master.sig_pause_time = -1;
248 	master.sig_pause_nrmsgs = -1;
249 	master.killfile_log = KILL_LOG_LONG;	/* do we log killed messages */
250 	master.phrases = NULL;
251 	master.errlog = NULL;
252 	master.debug = FALSE;
253 	master.rescan = TRUE;		/* do we do rescan on a restart */
254 	master.quiet = FALSE;		/* do we display BPS and msg count */
255 	master.killp = NULL;		/* pointer to killfile structure */
256 	master.kill_ignore_postfix = FALSE;
257 	master.reconnect_nr = 0;	/* how many x msgs do we disconnect and reconnect 0 = never */
258 	master.innfeed = NULL;
259 	master.do_active = FALSE; /* do we scan the local active list  */
260 	master.localhost = NULL;
261 	master.groups = NULL;
262 	master.nrmode = FALSE;    /* use nrs or msgids to get article */
263 	master.auto_auth = FALSE; /* do we do auto authorization */
264 	master.passwd = NULL;
265 	master.userid = NULL;
266 	master.no_dedupe = FALSE;
267 	master.chk_msgid = TRUE; /* do we check MsgID for trailing > */
268 	master.activefile = NULL;
269 	master.prebatch = FALSE; /* do we try to batch any left over articles b4 we start? */
270 	master.grpnr = -1;	/* what group number are we currently on */
271 	master.skip_on_restart = FALSE;
272 	master.kill_log_name = N_KILLLOG;
273 	master.use_gui = FALSE;
274 	master.do_xover = TRUE;
275 	master.conn_dedupe = FALSE;
276 	master.post_filter= NULL;
277 	master.conn_active = FALSE;
278 	master.history_file = HISTORY_FILE;
279 	master.header_only = FALSE;
280 	master.db = -1;
281 	master.active_lastread = ACTIVE_DEFAULT_LASTREAD;
282 	master.use_xover = FALSE;
283 	master.xoverview = NULL;
284 	master.resetcounter = FALSE;
285 	master.low_read = FALSE;
286 	master.show_group = FALSE;
287 	master.do_ssl = FALSE;
288 	master.ssl_struct = NULL;
289 	master.local_ssl = FALSE;
290 	master.local_ssl_struct = NULL;
291 	master.batch_post_nr = 0;
292 	master.passwd_env = FALSE;
293 
294 	/* have to do this next so if set on cmd line, overrides this */
295 
296 #ifdef N_PHRASES		/* in case someone nukes def */
297 	if(stat(N_PHRASES, &sbuf) == 0 && S_ISREG(sbuf.st_mode)) {
298 		/* we have a regular phrases file make it the default */
299 		master.phrases = N_PHRASES;
300 	}
301 
302 #endif
303 
304 	/* allow no args, only the hostname, or hostname as first arg */
305 	/* also have to do the file argument checking */
306 	switch(argc) {
307 	  case 1:
308 		break;
309 	  case 2:
310 		/* the fargs == NULL test so only process first file name */
311 		if(argv[1][0] == FILE_CHAR) {
312 			if((fargs = build_args(&argv[1][1], &fargc)) != NULL) {
313 				retval = scan_args(&master, fargc, fargs);
314 			}
315 		}
316 		else if(argv[1][0] == '-') {
317 			/* in case of suck -V */
318 			retval = scan_args(&master, 1, &(argv[1]));
319 		}
320 		else{
321 			master.host = argv[1];
322 		}
323 		break;
324 	  default:
325 		for(loop=1;loop<argc && fargs == NULL;loop++) {
326 			if(argv[loop][0] == FILE_CHAR) {
327 				if((fargs = build_args(&argv[loop][1], &fargc)) != NULL) {
328 					retval = scan_args(&master, fargc, fargs);
329 				}
330 			}
331 		}
332 		/* this is here so anything at command line overrides file */
333 		if(argv[1][0] != '-' && argv[1][0] != FILE_CHAR) {
334 			master.host = 	argv[1];
335 			argc-= 2;
336 			args = &(argv[2]);
337 		}
338 		else {
339 			args = &(argv[1]);
340 			argc--;
341 		}
342 		retval = scan_args(&master, argc, args);
343 		break;
344 	}
345 	/* print out status stuff */
346 	if(master.debug == TRUE) {
347 		do_debug("Suck version %s\n",SUCK_VERSION);
348 		do_debug("master.MultiFile = %d\n", master.MultiFile);
349 		do_debug("master.status_file = %d\n",master.status_file);
350 		do_debug("master.status_file_name = %s\n", null_str(master.status_file_name));
351 		do_debug("master.do_killfile = %s\n", true_str(master.do_killfile));
352 		do_debug("master.do_chkhistory = %s\n", true_str(master.do_chkhistory));
353 		do_debug("master.do_modereader = %s\n", true_str(master.do_modereader));
354 		do_debug("master.always_batch = %s\n", true_str(master.always_batch));
355 		do_debug("master.rnews_size = %ld\n", master.rnews_size);
356 		do_debug("master.batch = %d\n", master.batch);
357 		do_debug("master.batchfile = %s\n", null_str(master.batchfile));
358 		do_debug("master.cleanup = %s\n", true_str(master.cleanup));
359 		do_debug("master.host = %s\n", null_str(master.host));
360 		do_debug("master.portnr = %u\n", master.portnr);
361 		do_debug("master.pause_time = %d\n", master.pause_time);
362 		do_debug("master.pause_nrmsgs = %d\n", master.pause_nrmsgs);
363 		do_debug("master.sig_pause_time = %d\n", master.sig_pause_time);
364 		do_debug("master.sig_pause_nrmsgs = %d\n", master.sig_pause_nrmsgs);
365 		do_debug("master.killfile_log = %d\n", master.killfile_log);
366 		do_debug("master.phrases = %s\n", null_str(master.phrases));
367 		do_debug("master.errlog = %s\n", null_str(master.errlog));
368 		do_debug("master.rescan = %s\n", true_str(master.rescan == TRUE));
369 		do_debug("master.quiet = %s\n", true_str(master.quiet));
370 		do_debug("master.kill_ignore_postfix = %s\n", true_str(master.kill_ignore_postfix));
371 		do_debug("master.reconnect_nr=%d\n", master.reconnect_nr);
372 		do_debug("master.do_active = %s\n", true_str(master.do_active));
373 		do_debug("master.localhost = %s\n", null_str(master.localhost));
374 		do_debug("master.nrmode = %s\n", true_str(master.nrmode));
375 		do_debug("master.auto_auth = %s\n", true_str(master.auto_auth));
376 		do_debug("master.no_dedupe = %s\n", true_str(master.no_dedupe));
377 		do_debug("master.chk_msgid = %s\n", true_str(master.chk_msgid));
378 		do_debug("master.activefile = %s\n", null_str(master.activefile));
379 		do_debug("master.prebatch = %s\n", true_str(master.prebatch));
380 		do_debug("master.skip_on_restart = %s\n", true_str(master.skip_on_restart));
381 		do_debug("master.kill_log_name = %s\n", null_str(master.kill_log_name));
382 		do_debug("master.use_gui = %s\n", true_str(master.use_gui));
383 		do_debug("master.do_xover = %s\n", true_str(master.do_xover));
384 		do_debug("master.conn_dedupe = %s\n", true_str(master.conn_dedupe));
385 		do_debug("master.post_filter = %s\n", null_str(master.post_filter));
386 		do_debug("master.conn_active = %s\n", true_str(master.conn_active));
387 		do_debug("master.history_file = %s\n", null_str(master.history_file));
388 		do_debug("master.header_only = %s\n", true_str(master.header_only));
389 		do_debug("master.active_lastread = %d\n", master.active_lastread);
390 		do_debug("master.use_xover = %s\n", true_str(master.use_xover));
391 		do_debug("master.do_ssl = %s\n", true_str(master.do_ssl));
392 		do_debug("master.local_ssl = %s\n", true_str(master.local_ssl));
393 		do_debug("master.batch_post_nr =  %d\n",master.batch_post_nr);
394 		do_debug("master.passwd_env = %s\n", true_str(master.passwd_env));
395 #ifdef TIMEOUT
396 		do_debug("TimeOut = %d\n", TimeOut);
397 #endif
398 		do_debug("master.debug = TRUE\n");
399 	}
400         /* now do any final args checks needed */
401 	/* check to see if we have enough info to scan the localhost active file */
402 	if((master.do_active == TRUE || master.batch == BATCH_LIHAVE) && master.localhost == NULL) {
403 		retval = RETVAL_ERROR;
404 		error_log(ERRLOG_REPORT, suck_phrases[6], NULL);
405 	}
406 	else if(master.host == NULL) {
407 		retval = RETVAL_ERROR;
408 		error_log(ERRLOG_REPORT, suck_phrases[74], NULL);
409 	}
410 
411 
412 	/* okay now the main stuff */
413 	if(retval == RETVAL_OK) {
414 		if(master.status_file == FALSE) {
415 			/* if not in multifile mode, all status msgs MUST go to stderr to not mess up articles */
416 			/* this has to go before lockfile code, so lockfile prints msg to correct place. */
417 			master.msgs = ( master.MultiFile == FALSE) ? stderr : stdout ;
418 		}
419 #ifdef LOCKFILE
420 		/* this has to be here since we use full_path() to get path for lock file */
421 		/* and it isn't set up until we process the args above. */
422 		if(do_lockfile(&master) != RETVAL_OK) {
423 			exit(-1);
424 		}
425 #endif
426 
427 #ifdef MYSIGNAL
428 		/* set up signal handlers */
429 #ifdef HAVE_SIGACTION
430 		sigemptyset(&(sigs.sa_mask));
431 		sigs.sa_handler = sighandler;
432 		sigs.sa_flags = 0;
433 		if(sigaction(MYSIGNAL, &sigs, NULL) == -1
434 			     || sigaction(MYSIGNAL2, &sigs, NULL) == -1
435 			     || sigaction(PAUSESIGNAL, &sigs, NULL) == -1) {
436 			MyPerror(suck_phrases[67]);
437 		}
438 		else {
439 			signal_block(MYSIGNAL_SETUP);	/* set up sgetline() to block signal */
440 			pause_signal(PAUSE_SETUP, &master);	/* set up routine for pause swap if signal */
441 		}
442 #else
443 		/* the old-fashioned way */
444 		signal(MYSIGNAL, sighandler);
445 		signal(MYSIGNAL2, sighandler);
446 		signal(PAUSESIGNAL, sighander);
447 		pause_signal(PAUSE_SETUP, &master);
448 #endif
449 #endif
450 		load_phrases(&master);	/* this has to be here so rest prints okay */
451 
452 		/* set up status log, if none specified or unable to open status log */
453 		/* then  use stdout or stderr */
454 
455 		if(master.status_file_name != NULL) {
456 			/* okay attempt to open it up */
457 			if((master.msgs = fopen(master.status_file_name, "a")) == NULL) {
458 				MyPerror(suck_phrases[0]);
459 				master.msgs = stdout;	/* reset to default */
460 			}
461 			else {
462 				master.status_file = TRUE;
463 			}
464 		}
465 #ifdef HAVE_SETVBUF
466 		setvbuf(master.msgs, NULL, _IOLBF, 0);	/* set to line buffering */
467 #endif
468 		/* do we batch up any lingering articles ? */
469 		if(master.prebatch == TRUE) {
470 			switch(master.batch) {
471 			case BATCH_FALSE:
472 				error_log(ERRLOG_REPORT, suck_phrases[58], NULL);
473 				break;
474 			case BATCH_INNXMIT:
475 				do_innbatch(&master);
476 				break;
477 			case BATCH_RNEWS:
478 				do_rnewsbatch(&master);
479 				break;
480 			case BATCH_LMOVE:
481 				do_lmovebatch(&master);
482 				break;
483 			case BATCH_LIHAVE:
484 				do_localpost(&master);
485 				break;
486 			}
487 		}
488 
489 		/* now parse the killfile */
490 #ifdef KILLFILE
491 		if(master.do_killfile == TRUE) {
492 			master.killp = parse_killfile(KILL_KILLFILE, master.killfile_log, master.debug, master.kill_ignore_postfix);
493 		}
494 #endif
495 		/* now parse the xover killfile */
496 		if(master.do_xover == TRUE) {
497 			master.xoverp = parse_killfile(KILL_XOVER, master.killfile_log, master.debug, master.kill_ignore_postfix);
498 		}
499 
500 		print_phrases(master.msgs, suck_phrases[1], master.host, NULL);
501 		if(do_connect(&master, CONNECT_FIRST) != RETVAL_OK) {
502 			retval = RETVAL_ERROR;
503 		}
504 		else {
505 			/* if we have XOVER killfiles, we need to get the format of em before any processing */
506 			if(master.xoverp != NULL || master.use_xover == TRUE) {
507 				get_xoverview(&master);
508 				killprg_sendoverview(&master);
509 			}
510 
511 			/* first, check for restart articles, */
512 			/* then scan for any new articles */
513 			if((loop = restart_yn(&master)) == RESTART_ERROR) {
514 				retval = RETVAL_ERROR;
515 			}
516 			else if(loop == RESTART_NO || master.rescan == TRUE) {
517 				/* we don't do scan if we had restart and option = FALSE */
518 				/* do we scan the local active file? */
519 				if(master.do_active == TRUE || master.activefile != NULL) {
520 					if(get_message_index_active(&master) < RETVAL_OK) {
521 						retval = RETVAL_ERROR;
522 					}
523 				}
524 				else if(get_message_index(&master) < RETVAL_OK) {
525 					retval = RETVAL_ERROR;
526 				}
527 				if(retval == RETVAL_OK) {
528 					retval = do_supplemental(&master);
529 				}
530 				if(retval == RETVAL_OK) {
531                                         retval = do_nodownload(&master);
532                                 }
533 				if(retval == RETVAL_OK && master.head != NULL && master.nritems > 0) {
534 					/* if we don't have any messages, we don't need to do this */
535 					if(master.no_dedupe == FALSE) {
536 						dedupe_list(&master);
537 					}
538 #ifdef CHECK_HISTORY
539 					if(master.do_chkhistory == TRUE) {
540 						chkhistory(&master);
541 					}
542 #endif
543 					print_phrases(master.msgs,suck_phrases[20], str_int(master.nritems), NULL);
544 				}
545 			}
546 			if(retval == RETVAL_OK) {
547 				if(master.nritems == 0) {
548  					print_phrases(master.msgs,suck_phrases[3], NULL);
549 					retval = RETVAL_NOARTICLES;
550 				}
551 				else {
552 					/* write out restart db */
553 					retval = db_write(&master);
554 				/* reconnect after dedupe, in case of time out due to long dedupe time*/
555 					if(retval == RETVAL_OK && master.conn_dedupe == TRUE) {
556 						retval = do_connect(&master, CONNECT_AGAIN);
557 					}
558 					if(retval == RETVAL_OK) {
559 						retval = get_articles(&master);
560 					}
561 				}
562 
563 			}
564 			if(retval == RETVAL_OK) { /* if we got disconnected above, don't do this */
565 				/* send quit, and get reply */
566 				sputline(master.sockfd,"quit\r\n", master.do_ssl, master.ssl_struct);
567 				if(master.debug == TRUE) {
568 					do_debug("Sending command: quit\n");
569 				}
570 				do {
571 					resp = sgetline(master.sockfd, &inbuf, master.do_ssl, master.ssl_struct);
572 					if(resp>0) {
573 						if(master.debug == TRUE) {
574 							do_debug("Quitting GOT: %s", inbuf);
575 						}
576 						number(inbuf, &nr);
577 					}
578 
579 				}while(nr != 205 && resp > 0);
580 			}
581 		}
582 		if(master.sockfd >= 0) {
583 			disconnect_from_nntphost(master.sockfd, master.do_ssl, &master.ssl_struct);
584 			print_phrases(master.msgs,suck_phrases[4], master.host, NULL);
585 		}
586 		if(master.debug == TRUE) {
587 			do_debug("retval=%d (RETVAL_OK=%d), m.nrgot=%d, m.batch=%d\n", retval, RETVAL_OK, master.nrgot, master.batch);
588 		}
589 		if((retval == RETVAL_OK || master.always_batch == TRUE) && master.nrgot > 0 && master.header_only == FALSE) {
590 			switch(master.batch) {
591 			  case BATCH_INNXMIT:
592 				  do_post_filter(&master);
593 				  do_innbatch(&master);
594 				  break;
595 			  case BATCH_RNEWS:
596 				  do_post_filter(&master);
597 				  do_rnewsbatch(&master);
598 				  break;
599 			  case BATCH_LMOVE:
600 				  do_post_filter(&master);
601 				  do_lmovebatch(&master);
602 				  break;
603 			  case BATCH_LIHAVE:
604 				  do_post_filter(&master);
605 				  do_localpost(&master);
606 				  break;
607 			  default:
608 				  break;
609 			}
610 		}
611 		if((retval == RETVAL_NOARTICLES || retval == RETVAL_OK) && master.cleanup == TRUE) {
612 			print_phrases(master.msgs, suck_phrases[7], NULL);
613 			do_cleanup(&master);
614 		}
615 
616 		/* close out status log */
617 		if(master.msgs != NULL && master.msgs != stdout && master.msgs != stderr) {
618 			fclose(master.msgs);
619 		}
620 		if(master.head != NULL) {
621 			/* clean up memory */
622 			master.curr = master.head;
623 			while(master.curr != NULL) {
624 				temp = (master.curr)->next;
625 				free_one_node(master.curr);
626 				master.curr = temp;
627 			}
628 		}
629 		/* free up group list */
630 		while (master.groups != NULL) {
631 			ptemp=(master.groups)->next;
632 			free(master.groups);
633 			master.groups = ptemp;
634 		}
635 		/* free up overview.fmt list */
636 		while (master.xoverview != NULL) {
637 			pov = (master.xoverview)->next;
638 			if((master.xoverview)->header != NULL) {
639 				free((master.xoverview)->header);
640 			}
641 			free(master.xoverview);
642 			master.xoverview = pov;
643 		}
644 
645 #ifdef KILLFILE
646 		free_killfile(master.killp);
647 #endif
648 		free_killfile(master.xoverp);
649 
650 		if(fargs != NULL) {
651 			free_args(fargc, fargs);
652 		}
653 #ifdef LOCKFILE
654 		lockfile = full_path(FP_GET, FP_TMPDIR, N_LOCKFILE);
655 		if(lockfile != NULL) {
656 			unlink(lockfile);
657 		}
658 #endif
659 	}
660 	free_phrases();	/* do this last so everything is displayed correctly */
661 	exit(retval);
662 }
663 /*------------------------------------------------------------*/
do_connect(PMaster master,int which_time)664 int do_connect(PMaster master, int which_time) {
665 
666 	char *inbuf;
667 	int nr, resp, retval = RETVAL_OK;
668 	FILE *fp;
669 
670 
671 	if(which_time != CONNECT_FIRST) {
672 		/* close down previous connection */
673 		sputline(master->sockfd, "quit\r\n", master->do_ssl, master->ssl_struct);
674 		do {
675 			resp = sgetline(master->sockfd, &inbuf, master->do_ssl, master->ssl_struct);
676 			if(resp>0) {
677 				if(master->debug == TRUE) {
678 					do_debug("Reconnect GOT: %s", inbuf);
679 				}
680 				number(inbuf, &nr);
681 			}
682 
683 		}while(nr != 205 && resp > 0);
684 		disconnect_from_nntphost(master->sockfd, master->do_ssl, &master->ssl_struct);
685 
686 		/* now reset everything */
687 		if(master->curr != NULL) {
688 			(master->curr)->sentcmd = FALSE;
689 		}
690 		master->grpnr = -1;
691 	}
692 
693 	if(master->debug == TRUE) {
694 		do_debug("Connecting to %s on port %d\n", master->host, master->portnr);
695 	}
696 	fp = (which_time == CONNECT_FIRST) ? master->msgs : NULL;
697 
698 	master->sockfd = connect_to_nntphost( master->host, NULL, 0, fp, master->portnr, master->do_ssl, &master->ssl_struct);
699 
700 	if(master->sockfd < 0 ) {
701 		retval = RETVAL_ERROR;
702 	}
703 	else if(sgetline(master->sockfd, &inbuf, master->do_ssl, master->ssl_struct) < 0) {
704 	 	/* Get the announcement line */
705 		retval = RETVAL_ERROR;
706 	}
707 	else {
708 		if(master->debug == TRUE) {
709 			do_debug("Got: %s", inbuf);
710 		}
711 		if(which_time == CONNECT_FIRST) {
712 			fprintf(master->msgs ,"%s", inbuf );
713 		}
714 		/* check to see if we have to do authorization now */
715 		number(inbuf, &resp);
716 		if(resp == 480 ) {
717 			retval = do_authenticate(master);
718 		}
719 		if(retval == RETVAL_OK && master->do_modereader == TRUE) {
720 			retval = send_command(master, "mode reader\r\n", &inbuf, 0);
721 			if(retval == RETVAL_OK) {
722 				/* Again the announcement */
723 				if(which_time == CONNECT_FIRST) {
724 					fprintf(master->msgs ,"%s",inbuf);
725 				}
726 			}
727 		}
728 		if(master->auto_auth == TRUE) {
729 			if(master->passwd == NULL || master->userid == NULL) {
730 				error_log(ERRLOG_REPORT, suck_phrases[55], NULL);
731 				retval = RETVAL_ERROR;
732 			}
733 			else {
734 
735 				/* auto authorize */
736 				retval = do_authenticate(master);
737 			}
738 		}
739 	}
740 	return retval;
741 }
742 
743 /*--------------------------------------------------------------------*/
get_message_index(PMaster master)744 int get_message_index(PMaster master) {
745 
746 	long lastread;
747 	int nrread, retval, maxread;
748 
749 	char buf[MAXLINLEN], group[512];
750 	FILE *ifp,*tmpfp;
751 
752 	retval = RETVAL_OK;
753 	ifp = tmpfp = NULL;
754 
755 	TimerFunc(TIMER_START, 0, NULL);
756 
757 	if((ifp = fopen(full_path(FP_GET, FP_DATADIR, N_OLDRC), "r" )) == NULL) {
758 		MyPerror(full_path(FP_GET, FP_DATADIR, N_OLDRC));
759 		retval = RETVAL_ERROR;
760 	}
761 	else if((tmpfp = fopen(full_path(FP_GET, FP_TMPDIR, N_NEWRC), "w" )) == NULL) {
762 		MyPerror(full_path(FP_GET, FP_TMPDIR, N_NEWRC));
763 		retval = RETVAL_ERROR;
764 	}
765 	while(retval == RETVAL_OK && fgets(buf, MAXLINLEN-1, ifp) != NULL) {
766 		if(buf[0] == SUCKNEWSRC_COMMENT_CHAR) {
767 			/* skip this group */
768 			fputs(buf, tmpfp);
769 			print_phrases(master->msgs, suck_phrases[8], buf, NULL);
770 		}
771 		else {
772 			maxread = -1; /* just in case */
773 			nrread = sscanf(buf, "%s %ld %d\n", group, &lastread, &maxread);
774 			if ( nrread < 2 || nrread > 3) {
775 				error_log(ERRLOG_REPORT, suck_phrases[9], buf, NULL);
776 				fputs(buf, tmpfp);	/* rewrite the line */
777 			}
778 			else if(maxread == 0) {
779 				/* just rewrite the line */
780 				fputs(buf, tmpfp);
781 			}
782 			else {
783 				retval = do_one_group(master, buf, group, tmpfp, lastread, maxread);
784 			}
785 		}
786 	}
787 
788 	TimerFunc(TIMER_TIMEONLY, 0,master->msgs);
789 
790 	if(retval == RETVAL_OK) {
791 		print_phrases(master->msgs, suck_phrases[16], str_int(master->nritems), NULL);
792 	}
793 	else if(ifp != NULL) {
794 		/* this is in case we had to abort the above while loop (due to loss of pipe to server) and */
795 		/* we hadn't finished writing out the suck.newrc, this finishes it up. */
796 		do {
797 			fputs(buf, tmpfp);
798 		}
799 		while(fgets(buf, MAXLINLEN-1, ifp) != NULL);
800 	}
801 	if(tmpfp != NULL) {
802 		fclose(tmpfp);
803 	}
804 	if(ifp != NULL) {
805 		fclose(ifp);
806 	}
807 	return retval;
808 }
809 /*-----------------------------------------------------------------------------------------------------*/
do_one_group(PMaster master,char * buf,char * group,FILE * newrc,long lastread,int maxread)810 int do_one_group(PMaster master, char *buf, char *group, FILE *newrc, long lastread, int maxread) {
811 
812 	char *sp, *inbuf, cmd[MAXLINLEN];
813 	long count,low,high;
814 	int response,retval,i;
815 
816 	retval = RETVAL_OK;
817 
818 
819 	sprintf(cmd,"group %s\r\n",group);
820 	if(send_command(master,cmd,&inbuf,0) != RETVAL_OK) {
821 		retval = RETVAL_ERROR;
822 	}
823 	else {
824 		sp = number(inbuf, &response);
825 		if(response != 211) {
826 			fputs(buf, newrc);	/* rewrite line AS IS in newrc */
827 				/* handle group not found */
828 			switch(response) {
829 			case 411:
830 				error_log(ERRLOG_REPORT, suck_phrases[11], group, NULL);
831 				break;
832 			case 500:
833 				error_log(ERRLOG_REPORT, suck_phrases[48], NULL);
834 				break;
835 			default:
836 				error_log(ERRLOG_REPORT, suck_phrases[12],group,str_int(response),NULL);
837 				retval = RETVAL_ERROR; /* bomb out on wacko errors */
838 				break;
839 			}
840 		}
841 		else {
842 			sp = get_long(sp, &count);
843   			sp = get_long(sp, &low);
844 			sp = get_long(sp, &high);
845   			fprintf(newrc, "%s %ld", group, high);
846 
847 			if(maxread > 0) {
848 				fprintf(newrc, " %d", maxread);
849 			}
850 			fputs("\n", newrc);
851 
852   			/* add a sanity check in case remote host changes its numbering scheme */
853 			/* the > 0 is needed, since if a nnrp site has no article it will reset */
854 			/* the count to 0.  So not an error */
855   			if(lastread > high && high > 0) {
856 				if(master->resetcounter == TRUE) {
857 					/* reset lastread to low, so we pick up all articles in the group */
858 					lastread = low;
859 					print_phrases(master->msgs,suck_phrases[71],group,str_int(high),str_int(low),NULL);
860 				}
861 				else {
862 					print_phrases(master->msgs,suck_phrases[13],group,str_int(high),NULL);
863 				}
864   			}
865 
866 			if(lastread < 0 ) {
867 				/* if a neg number, get the last X nr of messages, handy for starting */
868 				/* a new group off ,say -100 will get the last 100 messages */
869 				lastread += high;	/* this works since lastread is neg */
870 				if(lastread < 0) {
871 					lastread = 0;	/* just to be on the safeside */
872 				}
873 			}
874 
875 			/* this has to be >= 0 since if there are no article on server high = 0 */
876 			/* so if we write out 0, we must be able to handle zero as valid lastread */
877 			/* the count > 0 so if no messages available we don't even try */
878 			/* or if low > high no messages either */
879 			if (low <= high && count > 0 && lastread < high && lastread >= 0) {
880 				/* add group name to list of groups */
881 
882    				if(lastread < low) {
883 					lastread = low - 1;
884 				}
885 				/* now set the max nr of messages to read */
886 				if(maxread > 0 && high-maxread > lastread) {
887 					if(master->low_read == TRUE) {
888 						/* instead of limiting from the high-water mark (the latest articles) */
889 						/* limit from the low-water mark (the oldest articles) */
890 						high = (lastread+1) + maxread;
891 					}
892 					else {
893 						lastread = high-maxread;
894 					}
895 					print_phrases(master->msgs, suck_phrases[14], group, str_int(maxread), NULL);
896 				}
897 				print_phrases(master->msgs, suck_phrases[15], group, str_long(high-lastread), str_long(lastread+1), str_long(high), NULL);
898 				if(master->xoverp != NULL) {
899 					/* do this via the xover killfile command */
900 					retval = do_group_xover(master, group, lastread+1, high);
901 				}
902 				/* do we use xover or xhdr to get our article list */
903 				if(master->use_xover == TRUE) {
904 					retval = get_xover(master, group, lastread+1, high);
905 				}
906 				else if((master->xoverp == NULL) || (retval == RETVAL_NOXOVER)) {
907 					/* do this the normal way */
908 					sprintf(cmd, "xhdr Message-ID %ld-%ld\r\n", lastread+1,high);
909 					i = send_command(master,cmd,&inbuf,221);
910 					if(i != RETVAL_OK) {
911 						retval = RETVAL_ERROR;
912 					}
913 					else {
914 						do {
915 							if(sgetline(master->sockfd, &inbuf, master->do_ssl, master->ssl_struct) < 0) {
916 								retval = RETVAL_ERROR;
917 							}
918 							else if (*inbuf != '.' ) {
919 								retval = allocnode(master, inbuf, MANDATORY_OPTIONAL, group, 0L);
920 							}
921 						} while (retval == RETVAL_OK && *inbuf != '.' && *(inbuf+1) != '\n');
922 					} /* end if response */
923 				} /* end if xover */
924   			} /* end if lastread */
925 		} /* end response */
926 	} /* end else */
927 
928 	if(retval == RETVAL_ERROR) {
929 		error_log(ERRLOG_REPORT, suck_phrases[59], NULL);
930 	}
931 	return retval;
932 }
933 /*-----------------------------------------------------------*/
get_articles(PMaster master)934 int get_articles(PMaster master) {
935 
936 	int retval, logcount, i, grpnr, grplen;
937 	long loop, downloaded;
938 	PGroups grps;
939 	const char *grpname;
940 	const char *empty = "";
941 
942 #ifdef HAVE_GETTIMEOFDAY
943 	double bps;
944 #endif
945 
946 #ifdef KILLFILE
947 	int ( *get_message)(PMaster, int, long); /* which function will we use get_one_article or get_one_article_kill) */
948 
949 	grpnr = -1;
950 	grps = NULL;
951 	grpname = empty;
952 	grplen = 0;
953 		/* do we use killfiles? */
954 	get_message = (master->killp == NULL) ? get_one_article : get_one_article_kill;
955 #endif
956 	retval = RETVAL_OK;
957 	downloaded = loop = 0; /* used to track how many downloaded, for reconnect option */
958 
959 	/* figure out how many digits wide the articleCount is for display purposes */
960 	/* this used to be log10()+1, but that meant I needed the math library */
961 	for(logcount=1, i=master->nritems; i > 9 ; logcount++) {
962 		i /= 10;
963 	}
964 
965 	if(master->MultiFile == TRUE && checkdir(full_path(FP_GET, FP_MSGDIR, NULL)) == FALSE) {
966 		retval = RETVAL_ERROR;
967 	}
968 	else {
969 		retval = db_open(master);
970 		if(retval == RETVAL_OK) {
971 			master->curr = master->head;
972 
973 			if(master->batch == BATCH_INNFEED) {
974 				/* open up batch file for appending to */
975 				if((master->innfeed = fopen(master->batchfile, "a")) == NULL) {
976 					MyPerror(master->batchfile);
977 				}
978 			}
979 			else if(master->batch == BATCH_LIHAVE) {
980 				if((master->innfeed = fopen(full_path(FP_GET, FP_TMPDIR, master->batchfile), "a")) == NULL) {
981 					MyPerror(full_path(FP_GET, FP_TMPDIR, master->batchfile));
982 					retval = RETVAL_ERROR;
983 				}
984 			}
985 
986 			TimerFunc(TIMER_START, 0, NULL);
987 
988 #ifdef MYSIGNAL
989 			while(retval == RETVAL_OK && master->curr != NULL && GotSignal == FALSE) {
990 #else
991 			while(retval == RETVAL_OK && master->curr != NULL) {
992 #endif
993 				if(master->debug == TRUE) {
994 					do_debug("Article nr = %s mandatory = %c\n", (master->curr)->msgnr, (master->curr)->mandatory);
995 				}
996 				loop++;
997 				if((master->curr)->downloaded == FALSE) {
998 					/* we haven't yet downloaded this article */
999 					downloaded++;
1000 
1001 				        /* to be polite to the server, lets allow for a pause every once in a while */
1002 					if(master->pause_time > 0 && master->pause_nrmsgs > 0) {
1003 						if((downloaded > 0) && (downloaded % master->pause_nrmsgs == 0)) {
1004 							sleep(master->pause_time);
1005 						}
1006 					}
1007 					if(master->status_file == FALSE && master->quiet == FALSE) {
1008 						/* if we are going to a file, we don't want all of these articles printed */
1009 						/* or if quiet flag is set */
1010 						/* this stuff doesn't go thru print_phrases so I can keep spacing right */
1011 						/* and I only print numbers and the BPS */
1012 #ifdef HAVE_GETTIMEOFDAY
1013 						bps = TimerFunc(TIMER_GET_BPS, 0, master->msgs);
1014 #endif
1015 						if(master->use_gui == TRUE) {
1016 							/* this stuff is formatted by the GUI so we put it out in a format it likes */
1017 #ifndef HAVE_GETTIMEOFDAY
1018 							fprintf(master->msgs, "---%ld+++\n",master->nritems - loop);
1019 #else
1020 							fprintf(master->msgs, "---%ld+++%f\n", master->nritems - loop, bps);
1021 #endif /* HAVE_GETTIMEOFDAY */
1022 						}
1023 						else {
1024 							if(master->show_group == TRUE) {
1025 							/* add the group name (if available) to the line printed */
1026 								if((master->curr)->groupnr >= 0) {
1027 									if((master->curr)->groupnr != grpnr) {
1028 										grpname = empty;
1029 										grpnr = (master->curr)->groupnr;
1030 										/* new group name find it */
1031 										grps = master->groups;
1032 										while(grps != NULL && grps->nr != grpnr) {
1033 											grps = grps->next;
1034 										}
1035 										if(grps != NULL) {
1036 											grpname = grps->group;
1037 											/* calculate max len for format of printf*/
1038 											/* which erases the previous group name */
1039 											if(strlen(grpname) > grplen) {
1040 												grplen = strlen(grpname);
1041 											}
1042 										}
1043 									}
1044 								}
1045 								else {
1046 									grpnr = -1;
1047 									grpname = empty;
1048 								}
1049 							}
1050 #ifndef HAVE_GETTIMEOFDAY
1051 							fprintf(master->msgs, "%5ld %-*s\r",master->nritems  - loop, grplen, grpname);
1052 #else
1053 							fprintf(master->msgs, "%5ld %9.1f %s %-*s\r",master->nritems-loop,bps,suck_phrases[5], grplen, grpname);
1054 #endif /* HAVE_GETTIMEOFDAY */
1055 						}
1056 						fflush(master->msgs);	/* so message gets printed now */
1057 					}
1058 #ifdef KILLFILE
1059 				        /* get one article */
1060 					retval = (*get_message)(master, logcount, loop);
1061 #else
1062 					retval = get_one_article(master, logcount, loop);
1063 #endif
1064 					if(retval == RETVAL_OK ) {
1065 						retval = db_mark_dled(master, master->curr);
1066 					}
1067 				}
1068 
1069 				master->curr = (master->curr)->next; 	/* get next article */
1070 
1071 				/* to be NOT polite to the server reconnect every X msgs to combat the INND */
1072 				/* LIKE_PULLERS=DONT.  This is last in loop, so if problem can abort gracefully */
1073 				if((master->reconnect_nr > 0) && (downloaded > 0) && (downloaded % master->reconnect_nr == 0)) {
1074 					retval =  do_connect(master, CONNECT_AGAIN);
1075 					if(master->curr != NULL) {
1076 						(master->curr)->sentcmd = FALSE;	/* if we sent command force resend */
1077 					}
1078 				}
1079 				// do a local post every x number of articles
1080 				if(master->batch == BATCH_LIHAVE && master->batch_post_nr > 0 && master->nrgot >=  master->batch_post_nr) {
1081 					fclose(master->innfeed);
1082 					master->innfeed = NULL;
1083 					do_post_filter(master);
1084 					retval = do_localpost(master);
1085 					if(retval == RETVAL_OK) {
1086 						master->nrgot = 0; // so if no more articles left we don't try to post in main routine
1087 						if((master->innfeed = fopen(full_path(FP_GET, FP_TMPDIR, master->batchfile), "a")) == NULL) {
1088 							MyPerror(full_path(FP_GET, FP_TMPDIR, master->batchfile));
1089 							retval = RETVAL_ERROR;
1090 						}
1091 					}
1092 				}
1093 
1094 		 	} /* end while */
1095 			db_close(master);
1096 			if(retval == RETVAL_OK && master->nritems == loop) {
1097 				db_delete(master);
1098 			}
1099 
1100 			if(retval == RETVAL_OK) {
1101 				TimerFunc(TIMER_TOTALS, 0, master->msgs);
1102 			}
1103 			if(master->innfeed != NULL) {
1104 				fclose(master->innfeed);
1105 			}
1106 		}
1107 	}
1108 	return retval;
1109 }
1110 /*-----------------------------------------------*/
1111 /* add items from supplemental list to link list */
1112 /* ----------------------------------------------*/
1113 int do_supplemental(PMaster master) {
1114 
1115 	int retval, oldkept;
1116 	FILE *fp;
1117 	char linein[MAXLINLEN+1];
1118 
1119 	retval = RETVAL_OK;
1120 	oldkept = master->nritems;
1121 
1122 	if((fp = fopen(full_path(FP_GET, FP_DATADIR, N_SUPPLEMENTAL), "r")) != NULL) {
1123 		print_phrases(master->msgs, suck_phrases[17], NULL);
1124 		while(retval == RETVAL_OK && fgets(linein, MAXLINLEN, fp) != NULL) {
1125 			if(linein[0] == '!') {
1126 				retval = do_sup_bynr(master, linein);
1127 			}
1128 			else if(linein[0] == '<') {
1129 				retval = allocnode(master, linein, MANDATORY_YES, NULL, 0L);
1130 			}
1131 			else {
1132 				error_log(ERRLOG_REPORT, suck_phrases[18], linein, NULL);
1133 			}
1134 		}
1135 		print_phrases(master->msgs, suck_phrases[19], str_int(master->nritems-oldkept), \
1136 			str_int(master->nritems), NULL);
1137 		fclose(fp);
1138 	}
1139 
1140 	return retval;
1141 }
1142 /*------------------------------------------------------------------------------------------*/
1143  int do_sup_bynr(PMaster master, char *linein) {
1144 	 int retval = RETVAL_OK;
1145 	 /* this routine takes in a line formated !group_name article_nr */
1146 	 /* gets it's Msg-ID (via XHDR), then adds it to our list of articles */
1147 	 /* as a mandatory article to download */
1148 
1149 	 char grpname[MAX_GRP_LEN], cmd[MAXLINLEN], *resp;
1150 	 int i, done;
1151 	 long nrlow, nrhigh;
1152 
1153 	 if(master->debug == TRUE) {
1154 		 do_debug("supplemental adding %s", linein);
1155 	 }
1156 	 i = sscanf(linein, "!%s %ld-%ld", grpname, &nrlow, &nrhigh);
1157 	 if(i < 2) {
1158 		 error_log(ERRLOG_REPORT, suck_phrases[18], linein, NULL);
1159 	 }
1160 	 else {
1161 		 sprintf(cmd,"group %s\r\n",grpname);
1162 		 if(send_command(master,cmd,NULL,211) == RETVAL_OK) {
1163 			 if(i == 2) {
1164 				 sprintf(cmd,"xhdr Message-ID %ld\r\n",nrlow);
1165 			 }
1166 			 else {
1167 				 sprintf(cmd,"xhdr Message-ID %ld-%ld\r\n",nrlow,nrhigh);
1168 			 }
1169 			 if(send_command(master,cmd,NULL,221) == RETVAL_OK) {
1170 				 /* now have to get message-id and the . */
1171 				 done = FALSE;
1172 				 while( done == FALSE) {
1173 					 if(sgetline(master->sockfd, &resp, master->do_ssl, master->ssl_struct) < 0) {
1174 						 retval = RETVAL_ERROR;
1175 						 done = TRUE;
1176 					 }
1177 					 else {
1178 						 if(master->debug == TRUE) {
1179 							 do_debug("Got %s", resp);
1180 						 }
1181 						 if(*resp == '.') {
1182 							 done = TRUE;
1183 						 }
1184 						 else {
1185 							 retval = allocnode(master, resp, MANDATORY_YES, grpname, 0L);
1186 						 }
1187 					 }
1188 				 }
1189 			 }
1190 		 }
1191 	 }
1192 
1193 	 return retval;
1194 
1195  }
1196  /*---------------------------------------------------------------------*/
1197  int do_nodownload(PMaster master) {
1198 	 int i, retval = RETVAL_OK;
1199 	 FILE *fp;
1200 	 PList item, prev;
1201 	 char linein[MAXLINLEN+1];
1202 	 long nrlines = 0, nrnuked = 0;
1203 
1204 	 if((fp = fopen(full_path(FP_GET, FP_DATADIR, N_NODOWNLOAD), "r")) != NULL) {
1205 		print_phrases(master->msgs, suck_phrases[68], NULL);
1206 		while(retval == RETVAL_OK && fgets(linein, MAXLINLEN, fp) != NULL) {
1207 			nrlines++;
1208 			i = strlen(linein) - 1; /* so it points at last char */
1209 			/* strip off nl */
1210 			if(linein[i] == '\n') {
1211 				linein[i] = '\0';
1212 				i--;
1213 			}
1214 			/* strip off extra spaces on the end */
1215 			while(isspace(linein[i])){
1216 				linein[i] = '\0';
1217 				i--;
1218 			}
1219 			item = master->head;
1220 			prev = NULL;
1221 			/* find start of msgid */
1222 			if(linein[0] != '<') {
1223 				error_log(ERRLOG_REPORT, suck_phrases[69], linein, NULL);
1224 			}
1225 			else {
1226 				if(master->debug == TRUE) {
1227 					do_debug("Checking Nodownload - %s\n", linein);
1228 				}
1229 
1230 				while((item != NULL) && (cmp_msgid(linein, item->msgnr) == FALSE)) {
1231 					prev = item;
1232 					item = item->next;
1233 				}
1234 				if(item != NULL) {
1235 					/* found a match, remove from the list */
1236 					if(master->debug == TRUE) {
1237 						do_debug("Matched, nuking from list\n");
1238 					}
1239 					nrnuked++;
1240 					master->nritems--;
1241 					if(item == master->head) {
1242 						/* change top of list */
1243 						master->head = (master->head)->next;
1244 					}
1245 					else {
1246                                                  /* its not the end of the list */
1247 						prev->next = item->next;
1248 						free_one_node(item);
1249 					}
1250 				}
1251 			}
1252 		}
1253 		fclose(fp);
1254 		print_phrases(master->msgs, suck_phrases[70], str_long(nrlines), str_long(nrnuked), str_long(master->nritems), NULL);
1255 	}
1256 	return retval;
1257  }
1258 /*----------------------------------------------------------------------*/
1259  int get_group_number(PMaster master, char *grpname) {
1260 
1261 	 PGroups grps, gptr;
1262 	 int groupnr = 0;
1263 
1264          /* first, find out if it doesn't exist already */
1265 	 gptr = master->groups;
1266 	 while(gptr != NULL && groupnr == 0) {
1267 		 if(strcmp(gptr->group, grpname) == 0) {
1268 				/* bingo */
1269 			 groupnr = gptr->nr;
1270 		 }
1271 		 else {
1272 			 gptr = gptr->next;
1273 		 }
1274 	 }
1275 
1276 	 if(groupnr == 0) {
1277 		 /* add group to group list and get group nr */
1278 		 if((grps = malloc(sizeof(Groups))) == NULL) {
1279 				/* out of memory */
1280 			 error_log(ERRLOG_REPORT, suck_phrases[22], NULL);
1281 		 }
1282 		 else {
1283 			 grps->next = NULL;
1284 			 strcpy(grps->group, grpname);
1285 				/* now add to list and count groupnr */
1286 			 if(master->groups == NULL) {
1287 				 grps->nr = 1;
1288 				 master->groups = grps;
1289 			 }
1290 			 else {
1291 				 gptr = master->groups;
1292 				 while(gptr->next != NULL) {
1293 					 gptr = gptr->next;
1294 				 }
1295 				 gptr->next = grps;
1296 				 grps->nr = gptr->nr + 1;
1297 			 }
1298 			 groupnr = grps->nr;
1299 
1300 			 if(master->debug == TRUE) {
1301 				 do_debug("Adding to group list: %d %s\n", grps->nr, grps->group);
1302 			 }
1303 		 }
1304 	 }
1305 	 return groupnr;
1306 
1307  }
1308 /*-----------------------------------------------------------------------*/
1309 int allocnode(PMaster master, char *linein, int mandatory, char *group, long msgnr_in) {
1310 	/* if msgnr_in is not filled in (0), then parse the msgnr off the linein */
1311 
1312 	/* if allocate memory here, must free in free_one_node */
1313 
1314 	PList ptr = NULL;
1315 	char *end_ptr, *st_ptr;
1316 	static PList curr = NULL;	/* keep track of current end of list */
1317 	int groupnr = 0, retval = RETVAL_OK;
1318 	long msgnr = 0;
1319 
1320 	static int warned = FALSE;
1321 
1322 	/* get the article nr */
1323 	if(group == NULL) {
1324 		/* we're called by do_supplemental */
1325 		st_ptr = linein;
1326 	}
1327 	else {
1328 		if (msgnr_in > 0) {
1329 			/* we're prob called by xover code */
1330 			st_ptr = linein;
1331 			msgnr = msgnr_in;
1332 		}
1333 		else {
1334 			st_ptr = get_long(linein,&msgnr);
1335 			if(msgnr == 0 && warned == FALSE) {
1336 				warned = TRUE;
1337 				error_log(ERRLOG_REPORT, suck_phrases[53], NULL);
1338 			}
1339 		}
1340 
1341 		if(msgnr > 0 && group != NULL) {
1342 			groupnr = get_group_number(master, group);
1343 		}
1344 	}
1345 
1346 	if(retval == RETVAL_OK) {
1347 		/* find the message id */
1348 		while(*st_ptr != '<' && *st_ptr != '\0') {
1349 			st_ptr++;
1350 		}
1351 		end_ptr = st_ptr;
1352 		while(*end_ptr != '>' && *end_ptr != '\0') {
1353 			end_ptr++;
1354 		}
1355 		if((*st_ptr != '<') || ( master->chk_msgid == TRUE && *end_ptr != '>')) {
1356 			error_log(ERRLOG_REPORT, suck_phrases[21], linein, NULL);
1357 		}
1358 		else {
1359 			*(end_ptr+1) = '\0';	/* ensure null termination */
1360 
1361 			if((ptr = malloc(sizeof(List))) == NULL) {
1362 				error_log(ERRLOG_REPORT, suck_phrases[22], NULL);
1363 				retval = RETVAL_ERROR;
1364 			}
1365 			else if(strlen(st_ptr) >= MAX_MSGID_LEN) {
1366 				error_log(ERRLOG_REPORT, suck_phrases[63], group, msgnr, NULL);
1367 				free(ptr);
1368 			}
1369 			else {
1370 				strcpy(ptr->msgnr, st_ptr);
1371 				ptr->next = NULL;
1372 				ptr->mandatory = (char) mandatory;
1373 				ptr->sentcmd = FALSE;		/* have we sent command to remote */
1374 				ptr->nr = msgnr;
1375 				ptr->groupnr = groupnr;
1376 				ptr->downloaded = FALSE;
1377 				ptr->dbnr = 0L;
1378 				ptr->delete = FALSE;
1379 
1380 				if(master->debug == TRUE) {
1381 					do_debug("MSGID %s NR %d GRP %d MANDATORY %c added\n",ptr->msgnr, ptr->nr, ptr->groupnr, ptr->mandatory);
1382 				}
1383 
1384 				/* now put on list */
1385 				if( curr == NULL) {
1386 					if(master->head == NULL) {
1387 				                /* first node */
1388 						master->head = curr = ptr;
1389 					}
1390 					else {
1391 						/* came in with a restart, find end of list */
1392 						curr = master->head;
1393 						while(curr->next != NULL) {
1394 							curr = curr->next;
1395 						}
1396 
1397 						/* now add node on */
1398 						curr->next = ptr;
1399 						curr = ptr;
1400 					}
1401 				}
1402 				else {
1403 					curr->next = ptr;
1404 					curr = ptr;
1405 				}
1406 				master->nritems++;
1407 			}
1408 		}
1409 	}
1410 
1411 	return retval;
1412 }
1413 /*------------------------------------------------------------------------*/
1414  void free_one_node(PList node) {
1415 
1416 	free(node);
1417 }
1418 /*----------------------------------------------------------------------------------*/
1419  const char *build_command(PMaster master, const char *cmdstart, PList article) {
1420 	 static char cmd[MAXLINLEN+1];
1421 	 static int warned = FALSE;
1422 	 char *resp;
1423 	 char grpcmd[MAXLINLEN+1];
1424 
1425 	 PGroups grps;
1426 
1427 	 /* build command to get article/head/body */
1428 	 /* if nrmode is on send group cmd if needed */
1429 	 if(master->nrmode == TRUE) {
1430 		 if(article->nr == 0) {
1431 			 master->nrmode = FALSE;
1432 		 }
1433 		 else if(master->grpnr != article->groupnr) {
1434 			 grps = master->groups;
1435 			 while(grps != NULL && grps->nr != article->groupnr) {
1436 				 grps = grps->next;
1437 			 }
1438 			 if(grps != NULL) {
1439 				 /* okay send group command */
1440 				 snprintf(grpcmd, MAXLINLEN, "GROUP %s\r\n", grps->group);
1441 				 if(send_command(master, grpcmd, &resp, 211) != RETVAL_OK) {
1442 					 master->nrmode = FALSE; /* can't chg groups turn it off */
1443 				 }
1444 				 else {
1445 					 /* so don't redo group command on next one */
1446 					 master->grpnr = grps->nr;
1447 				 }
1448 			 }
1449 		 }
1450 		 if(master->nrmode == TRUE) {
1451 			 /* everything hunky dory, we've switched groups, and got a good nr */
1452 			 snprintf(cmd, MAXLINLEN, "%s %ld\r\n", cmdstart, article->nr);
1453 		 }
1454 		 else if(warned == FALSE) {
1455 			 /* tell of the switch to nonnr mode */
1456 			 warned = TRUE;
1457 			 error_log(ERRLOG_REPORT, suck_phrases[54], NULL);
1458 		 }
1459 	 }
1460 	 /* the if is in case we changed it above */
1461 	 if(master->nrmode == FALSE) {
1462 		 snprintf(cmd, MAXLINLEN, "%s %s\r\n", cmdstart, article->msgnr);
1463 	 }
1464 	 return cmd;
1465  }
1466 /*----------------------------------------------------------------------------------*/
1467 int get_one_article(PMaster master, int logcount, long itemon) {
1468 
1469 	int nr, len, retval = RETVAL_OK;
1470 	char buf[MAXLINLEN+1];
1471 	const char *cmd = "", *tname = NULL;
1472 	char fname[PATH_MAX+1];
1473 
1474 	char *resp;
1475 	PList plist;
1476 
1477 	FILE *fptr = stdout;	/* the default */
1478 
1479 	fname[0] = '\0';	/* just in case */
1480 
1481 	/* first send command to get article if not already sent */
1482 	if((master->curr)->sentcmd == FALSE) {
1483 		cmd = (master->header_only == FALSE)
1484 			? build_command(master, "article", master->curr)
1485 			: build_command(master, "head", master->curr);
1486 		if(master->debug == TRUE) {
1487 			do_debug("Sending command: \"%s\"",cmd);
1488 		}
1489 		sputline(master->sockfd, cmd, master->do_ssl, master->ssl_struct);
1490 		(master->curr)->sentcmd = TRUE;
1491 	}
1492 	plist = (master->curr)->next;
1493 	if(plist != NULL && master->batch_post_nr == 0) {
1494 		/* if batch_post_nr > 0 we're doing periodic batch posts */
1495 		/* which confuses the remote server so we can't use pipelining */
1496 		if(master->nrmode == FALSE || plist->groupnr == (master->curr)->groupnr) {
1497 		/* can't use pipelining if nrmode on, cause of GROUP command I'll have to send*/
1498 			if(plist->sentcmd == FALSE) {
1499 				/* send next command */
1500 				cmd = (master->header_only == FALSE)
1501 					? build_command(master, "article", plist)
1502 					: build_command(master, "head", plist);
1503 				if(master->debug == TRUE) {
1504 					do_debug("Sending command: \"%s\"",cmd);
1505 				}
1506 				sputline(master->sockfd, cmd, master->do_ssl, master->ssl_struct);
1507 				plist->sentcmd = TRUE;
1508 			}
1509 		}
1510 	}
1511 
1512 	/* now while the remote is finding the article lets set up */
1513 
1514 	if(master->MultiFile == TRUE) {
1515 		/* open file */
1516 		/* file name will be ####-#### ex 001-166 (nron,total) */
1517 		sprintf(buf,"%0*ld-%d", logcount, itemon ,master->nritems);
1518 		/* the strcpy to avoid wiping out fname in second call to full_path */
1519 		strcpy(fname, full_path(FP_GET, FP_MSGDIR, buf));
1520 		strcat(buf, N_TMP_EXTENSION);		/* add tmp extension */
1521 		tname = full_path(FP_GET, FP_TMPDIR, buf);	/* temp file name */
1522 
1523 		if(master->debug == TRUE) {
1524 			do_debug("File name = \"%s\" temp = \"%s\"", fname, tname);
1525 		}
1526 		if((fptr = fopen(tname, "w")) == NULL) {
1527 			MyPerror(tname);
1528 			retval = RETVAL_ERROR;
1529 		}
1530 	}
1531 
1532 	/* okay hopefully by this time the remote end is ready */
1533 	if((len = sgetline(master->sockfd, &resp, master->do_ssl, master->ssl_struct)) < 0) {
1534 		retval = RETVAL_ERROR;
1535 	}
1536 	else {
1537 		if(master->debug == TRUE) {
1538 			do_debug("got answer: %s", resp);
1539 		}
1540 
1541 		TimerFunc(TIMER_ADDBYTES, len, NULL);
1542 
1543 		number(resp, &nr);
1544 		if(nr == 480) {
1545 			/* got to authorize, negate send-ahead for next msg */
1546 			if(plist != NULL) {
1547 				plist->sentcmd = FALSE;	/* cause its gonna error out in do_auth() */
1548 			}
1549 
1550 			if(do_authenticate(master) == RETVAL_OK) {
1551 				/* resend command for current article */
1552 				cmd = build_command(master, "article", master->curr);
1553 				if(master->debug == TRUE) {
1554 					do_debug("Sending command: \"%s\"",cmd);
1555 				}
1556 				sputline(master->sockfd, cmd, master->do_ssl, master->ssl_struct);
1557 				len = sgetline(master->sockfd, &resp, master->do_ssl, master->ssl_struct);
1558 				if(master->debug == TRUE) {
1559 					do_debug("got answer: %s", resp);
1560 				}
1561 				TimerFunc(TIMER_ADDBYTES, len, NULL);
1562 				number(resp, &nr);
1563 			}
1564 			else {
1565 				retval = RETVAL_ERROR;
1566 			}
1567 		}
1568 		/* 221 = header 220 = article */
1569 		if(nr == 220 || nr == 221 ) {
1570 			/* get the article */
1571 			if((retval = get_a_chunk(master, fptr)) == RETVAL_OK) {
1572 				master->nrgot++;
1573 				if (fptr == stdout) {
1574 					/* gracefully end the message in stdout version */
1575 					fputs(".\n", stdout);
1576 				}
1577 			}
1578 		}
1579 		else
1580 			{
1581 			/* don't return RETVAL_ERROR so we can get next article */
1582 			error_log(ERRLOG_REPORT, suck_phrases[29], cmd ,resp, NULL);
1583 		}
1584 	}
1585 	if(fptr != NULL && fptr != stdout) {
1586 		fclose(fptr);
1587 	}
1588 
1589 	if(master->MultiFile == TRUE) {
1590 		if(retval == RETVAL_ERROR || (nr != 221 && nr != 220)) {
1591 			unlink(tname);
1592 		}
1593 		/* now rename it to the permanent file name */
1594 		else {
1595 			move_file(tname, fname);
1596 			if((master->batch == BATCH_INNFEED || master->batch == BATCH_LIHAVE) && master->innfeed != NULL) {
1597 				/* write path name and msgid to file */
1598 				fprintf(master->innfeed, "%s %s\n", fname, (master->curr)->msgnr);
1599 				fflush(master->innfeed); /* so it gets written sooner */
1600 			}
1601 		}
1602 	}
1603 	return retval;
1604 }
1605 /*---------------------------------------------------------------------------*/
1606 int get_a_chunk(PMaster master, FILE *fptr) {
1607 
1608 	int done, partial, len, retval;
1609 	char *inbuf;
1610 	size_t nr;
1611 
1612 	retval = RETVAL_OK;
1613 	done = FALSE;
1614 	partial = FALSE;
1615 	len = 0; /* just to get rid of a compiler warning */
1616 	/* partial = was the previous line a complete line or not */
1617 	/* this is needed to avoid a scenario where the line is MAXLINLEN+1 */
1618 	/* long and the last character is a ., which would make us think */
1619 	/* that we are at the end of the article when we actually aren't */
1620 
1621 	while(done == FALSE && (len = sgetline(master->sockfd, &inbuf, master->do_ssl, master->ssl_struct)) >= 0) {
1622 
1623 		TimerFunc(TIMER_ADDBYTES, len, NULL);
1624 
1625 		if(inbuf[0] == '.' && partial == FALSE) {
1626 			if(len == 2 && inbuf[1] == '\n') {
1627 				done = TRUE;
1628 			}
1629 			else {
1630 				/* handle double dots IAW RFC977 2.4.1*/
1631 				inbuf++;	/* move past first dot */
1632 				len--;
1633 			}
1634 		}
1635 		if(done == FALSE) {
1636 			if(retval == RETVAL_OK) {
1637 				nr = fwrite(inbuf, sizeof(inbuf[0]), len, fptr);
1638 				fflush(fptr);
1639 				if(nr != len) {
1640 					retval = RETVAL_ERROR;
1641 					error_log(ERRLOG_REPORT, suck_phrases[57], NULL);
1642 				}
1643 			}
1644 			partial= (len==MAXLINLEN&&inbuf[len-1]!='\n') ? TRUE : FALSE;
1645  		}
1646 	}
1647 	if(len < 0) {
1648 		retval = RETVAL_ERROR;
1649 	}
1650 	return retval;
1651 }
1652 /*-----------------------------------------------------------------------------*/
1653 int restart_yn(PMaster master) {
1654 	int done, retval = RESTART_NO;
1655 	PList itemon;
1656 	long itemnr;
1657 	const char *fname;
1658 	struct stat buf;
1659 
1660 	fname = full_path(FP_GET, FP_TMPDIR, N_DBFILE);
1661 	if(stat(fname, &buf) == 0) {
1662 		/* restart file exists */
1663 		retval = db_read(master);
1664 		if(retval == RETVAL_OK) {
1665 			/* find out where we stopped */
1666 			itemon = master->head;
1667 			itemnr = 0L;
1668 			done = FALSE;
1669 			while(itemon != NULL && done == FALSE) {
1670 				itemnr++;
1671 				if(itemon->downloaded == FALSE) {
1672 					/* so that we don't think we already sent command */
1673 					itemon->sentcmd = FALSE;
1674 					if(master->skip_on_restart == TRUE) {
1675 						/* mark one more */
1676 						print_phrases(master->msgs, suck_phrases[60], NULL);
1677 						itemon->downloaded = TRUE;
1678 					}
1679 					else {
1680 						itemnr--; /* don't count this one */
1681 					}
1682 					done = TRUE;
1683 				}
1684 				itemon = itemon->next;
1685 			}
1686 		}
1687 	}
1688 	return retval;
1689 }
1690 /*-----------------------------------------------------------------*/
1691 #ifdef MYSIGNAL
1692 RETSIGTYPE sighandler(int what) {
1693 
1694 	switch(what) {
1695 	  case PAUSESIGNAL:
1696 		pause_signal(PAUSE_DO, NULL);
1697 		/* if we don't do this, the next time called, we'll abort */
1698 /*		signal(PAUSESIGNAL, sighandler); */
1699 /*		signal_block(MYSIGNAL_SETUP); */	/* just to be on the safe side */
1700 		break;
1701 	  case MYSIGNAL:
1702 	  case MYSIGNAL2:
1703 	  default:
1704 		error_log(ERRLOG_REPORT, suck_phrases[24], NULL);
1705 		GotSignal = TRUE;
1706 	}
1707 }
1708 /*----------------------------------------------------------------*/
1709 void pause_signal(int action, PMaster master) {
1710 
1711 	int x, y;
1712 	static PMaster psave = NULL;
1713 
1714 	switch(action) {
1715 	  case PAUSE_SETUP:
1716 		psave = master;
1717 		break;
1718 	  case PAUSE_DO:
1719 		if(psave == NULL) {
1720 			error_log(ERRLOG_REPORT, suck_phrases[25], NULL);
1721 		}
1722 		else {
1723 			/* swap pause_time and pause_nrmsgs with the sig versions */
1724 			x = psave->pause_time;
1725 			y = psave->pause_nrmsgs;
1726 			psave->pause_time = psave->sig_pause_time;
1727 			psave->pause_nrmsgs = psave->sig_pause_nrmsgs;
1728 			psave->sig_pause_time = x;
1729 			psave->sig_pause_nrmsgs = y;
1730 			print_phrases(psave->msgs, suck_phrases[26], NULL);
1731 		}
1732 	}
1733 }
1734 #endif
1735 /*----------------------------------------------------------------*/
1736  int send_command(PMaster master, const char *cmd, char **ret_response, int good_response) {
1737 	 /* this is needed so can do user authorization */
1738 
1739 	 int len, retval = RETVAL_OK, nr;
1740 	 char *resp;
1741 
1742 	 if(master->debug == TRUE) {
1743 		 do_debug("sending command: %s", cmd);
1744 	 }
1745 	 sputline(master->sockfd, cmd, master->do_ssl, master->ssl_struct);
1746 	 len = sgetline(master->sockfd, &resp, master->do_ssl, master->ssl_struct);
1747 	 if( len < 0) {
1748 		 retval = RETVAL_ERROR;
1749 	 }
1750 	 else {
1751 		 if(master->debug == TRUE) {
1752 			 do_debug("got answer: %s", resp);
1753 		 }
1754 
1755 		 TimerFunc(TIMER_ADDBYTES, len, NULL);
1756 
1757 		 number(resp, &nr);
1758 		 if(nr == 480 ) {
1759 			 /* we must do authorization */
1760 			 retval = do_authenticate(master);
1761 			 if(retval == RETVAL_OK) {
1762 				 /* resend command */
1763 				 sputline(master->sockfd, cmd, master->do_ssl, master->ssl_struct);
1764 				 if(master->debug == TRUE) {
1765 					 do_debug("sending command: %s", cmd);
1766 				 }
1767 				 len = sgetline(master->sockfd, &resp, master->do_ssl, master->ssl_struct);
1768 				 if( len < 0) {
1769 					 retval = RETVAL_ERROR;
1770 				 }
1771 				 else {
1772 					 number(resp,&nr);
1773 					 if(master->debug == TRUE) {
1774 						 do_debug("got answer: %s", resp);
1775 					 }
1776 
1777 					 TimerFunc(TIMER_ADDBYTES, len, NULL);
1778 
1779 				 }
1780 			 }
1781 		 }
1782 		 if (good_response != 0 && nr != good_response) {
1783 			 error_log(ERRLOG_REPORT, suck_phrases[29],cmd,resp,NULL);
1784 			 retval = RETVAL_UNEXPECTEDANS;
1785 		 }
1786 	 }
1787 	 if(ret_response != NULL) {
1788 		 *ret_response = resp;
1789 	 }
1790 	 return retval;
1791  }
1792 /*------------------------------------------------------------------------------*/
1793 /* 1. move N_OLDRC to N_OLD_OLDRC	N_OLDRC might not exist	       	        */
1794 /* 2. move N_NEWRC to N_OLDRC							*/
1795 /* 3. rm N_SUPPLEMENTAL								*/
1796 /*------------------------------------------------------------------------------*/
1797 void do_cleanup(PMaster master) {
1798 	const char *oldptr;
1799 	char ptr[PATH_MAX+1];
1800 	struct stat buf;
1801 	int exist;
1802 	int okay = TRUE;
1803 
1804 	if(master->debug == TRUE) {
1805 		do_debug("checking for existance of suck.newrc\n");
1806 	}
1807 
1808 	if(stat(full_path(FP_GET, FP_TMPDIR, N_NEWRC), &buf) == 0) {
1809 		if(master->debug == TRUE) {
1810 			do_debug("found suck.newrc\n");
1811 		}
1812 
1813 		/* we do the above test, in case we were in a restart */
1814 		/* with -R which would cause no suck.newrc to be created */
1815 		/* since message_index() would be skipped */
1816 		/* since no suck.newrc, don't move any of the sucknewrcs around */
1817 		strcpy(ptr,full_path(FP_GET, FP_DATADIR, N_OLDRC));
1818 		/* must strcpy since full path overwrites itself everytime */
1819 		oldptr = full_path(FP_GET, FP_DATADIR, N_OLD_OLDRC);
1820 
1821 		/* does the sucknewsrc file exist ? */
1822 		exist = TRUE;
1823 		if(stat(ptr, &buf) != 0 && errno == ENOENT) {
1824 			exist = FALSE;
1825 		}
1826 		if(master->debug == TRUE) {
1827 			do_debug("sucknewsrc.old = %s sucknewsrc = %s exist = %s\n", oldptr, ptr, true_str(exist));
1828 		}
1829 		if(exist == TRUE && move_file(ptr, oldptr) != 0) {
1830 			MyPerror(suck_phrases[30]);
1831 			okay = FALSE;
1832 		}
1833 		else if(move_file(full_path(FP_GET, FP_TMPDIR, N_NEWRC), ptr) != 0) {
1834 			MyPerror(suck_phrases[31]);
1835 			okay = FALSE;
1836 		}
1837 	}
1838 	else if( errno != ENOENT) {
1839 		MyPerror(full_path(FP_GET, FP_DATADIR, N_NEWRC));
1840 		okay = FALSE;
1841 	}
1842 	if(okay == TRUE && unlink(full_path(FP_GET, FP_DATADIR, N_SUPPLEMENTAL)) != 0 && errno != ENOENT) {
1843 		/* ENOENT is not an error since this file may not always exist */
1844 		MyPerror(suck_phrases[33]);
1845 	}
1846 }
1847 /*--------------------------------------------------------------------------------------*/
1848 int scan_args(PMaster master, int argc, char *argv[]) {
1849 
1850 	int loop, i, whicharg, arg, retval = RETVAL_OK;
1851 
1852 	for(loop = 0 ; loop < argc && retval == RETVAL_OK ; loop++) {
1853 		arg = ARG_NO_MATCH;
1854 		whicharg = -1;
1855 
1856 		if(master->debug == TRUE) {
1857 			do_debug("Checking arg #%d-%d: '%s'\n", loop, argc, argv[loop]);
1858 		}
1859 
1860 		if(argv[loop][0] == FILE_CHAR) {
1861 			/* totally skip these they are processed elsewhere */
1862 			continue;
1863 		}
1864 
1865 		if(argv[loop][0] == '-' && argv[loop][1] == '-') {
1866 			/* check long args */
1867 			for(i = 0 ; i < NR_ARGS && arg == ARG_NO_MATCH ; i++) {
1868 				if(arglist[i].larg != NULL) {
1869 					if(strcmp(&argv[loop][2], arglist[i].larg) == 0) {
1870 						arg = arglist[i].flag;
1871 						whicharg = i;
1872 					}
1873 				}
1874 			}
1875 		}
1876 		else if (argv[loop][0] == '-') {
1877 			/* check short args */
1878 			for(i = 0 ; i < NR_ARGS ; i++) {
1879 				if(arglist[i].sarg != NULL) {
1880 					if(strcmp(&argv[loop][1], arglist[i].sarg) == 0) {
1881 						arg = arglist[i].flag;
1882 						whicharg = i;
1883 					}
1884 				}
1885 			}
1886 		}
1887 		if(arg == ARG_NO_MATCH) {
1888 			/* we ignore the file_char arg, it is processed elsewhere */
1889 			retval = RETVAL_ERROR;
1890 			error_log(ERRLOG_REPORT, suck_phrases[34], argv[loop], NULL);
1891 		}
1892 		else {
1893 			/* need to check for valid nr of args and feed em down */
1894 			if(( loop + arglist[whicharg].nr_params) < argc) {
1895 				retval = parse_args(master, arg, &(argv[loop+1]));
1896 				/* skip em so they don't get processed as args */
1897 				loop += arglist[whicharg].nr_params;
1898 			}
1899 			else {
1900 				i = (arglist[whicharg].errmsg < 0) ? 34 : arglist[whicharg].errmsg;
1901 				error_log(ERRLOG_REPORT, suck_phrases[i], NULL);
1902 				retval = RETVAL_ERROR;
1903 			}
1904 		}
1905 	}
1906 
1907 	return retval;
1908 }
1909 /*---------------------------------------------------------------------------------------*/
1910 int parse_args(PMaster master, int arg, char *argv[]) {
1911 
1912 	int x, retval = RETVAL_OK;
1913 
1914 	switch(arg) {
1915 	case ARG_ALWAYS_BATCH:
1916 		/* if we have downloaded at least one article, then batch up */
1917 		/* even on errors */
1918 		master->always_batch = TRUE;
1919 		break;
1920 /* batch file implies MultiFile mode */
1921 	case  ARG_BATCH_INN:
1922 		master->batch = BATCH_INNXMIT;
1923 		master->MultiFile = TRUE;
1924 		master->batchfile = argv[0];
1925 		break;
1926 	case ARG_BATCH_RNEWS:
1927 		master->batch = BATCH_RNEWS;
1928 		master->MultiFile = TRUE;
1929 		master->batchfile = argv[0];
1930 		break;
1931 	case ARG_BATCH_LMOVE:
1932 		master->batch = BATCH_LMOVE;
1933 		master->MultiFile = TRUE;
1934 		master->batchfile = argv[0];
1935 		break;
1936 	case ARG_BATCH_INNFEED:
1937 		master->batch = BATCH_INNFEED;
1938 		master->MultiFile = TRUE;
1939 		master->batchfile = argv[0];
1940 		break;
1941 	case ARG_BATCH_POST_NR:
1942 		master->batch_post_nr = atoi(argv[0]);
1943 		/* no break fall thru to the rest of batch_post*/
1944 	case ARG_BATCH_POST:
1945 		master->batch = BATCH_LIHAVE;
1946 		master->MultiFile = TRUE;
1947 		master->batchfile = N_POSTFILE;
1948 		break;
1949 	case ARG_CLEANUP: 	/* cleanup option */
1950 		master->cleanup = TRUE;
1951 		break;
1952 	case ARG_DIR_TEMP:
1953 		full_path(FP_SET, FP_TMPDIR, argv[0]);
1954 		break;
1955 	case ARG_DIR_DATA:
1956 		full_path(FP_SET, FP_DATADIR, argv[0]);
1957 		break;
1958 	case ARG_DIR_MSGS:
1959 		full_path(FP_SET, FP_MSGDIR, argv[0]);
1960 		break;
1961 	case ARG_DEF_ERRLOG:	/* use default error log path */
1962 		error_log(ERRLOG_SET_FILE, ERROR_LOG, NULL);
1963 		master->errlog = ERROR_LOG;
1964 		break;
1965 	case ARG_HOST:	/* host name */
1966 		master->host = argv[0];
1967 		break;
1968 	case ARG_NO_POSTFIX:	/* kill files don't use the postfix */
1969 		master->kill_ignore_postfix = TRUE;
1970 		break;
1971 	case ARG_LANGUAGE: 	/* load language support */
1972 		master->phrases = argv[0];
1973 		break;
1974 	case ARG_MULTIFILE:
1975 		master->MultiFile = TRUE;
1976 		break;
1977 	case ARG_POSTFIX:
1978 		full_path(FP_SET_POSTFIX, FP_NONE, argv[0]);
1979 		break;
1980 	case ARG_QUIET: 	/* don't display BPS and message count */
1981 		master->quiet = TRUE;
1982 		break;
1983 	case ARG_RNEWSSIZE:
1984 		master->rnews_size = atol(argv[0]);
1985 		break;
1986 	case ARG_DEF_STATLOG:	/* use default status log name */
1987 		master->status_file_name = STATUS_LOG;
1988 		break;
1989 	case ARG_WAIT_SIG:	/* wait (sleep) x seconds between every y articles IF we get a signal */
1990 		master->sig_pause_time = atoi(argv[0]);
1991 		master->sig_pause_nrmsgs = atoi(argv[1]);
1992 		break;
1993 	case ARG_ACTIVE:
1994 		master->do_active = TRUE;
1995 		break;
1996 	case ARG_RECONNECT:	/* how often do we drop and reconnect to battle INNS's LIKE_PULLER=DONT */
1997 		master->reconnect_nr = atoi(argv[0]);
1998 		break;
1999 	case ARG_DEBUG:	/* debug */
2000 		master->debug = TRUE;
2001 		/* now set up our error log and MyPerror reporting so it goes to debug.suck */
2002 		error_log(ERRLOG_SET_DEBUG, NULL, NULL);
2003 		break;
2004 	case ARG_ERRLOG:	/* error log path */
2005 		error_log(ERRLOG_SET_FILE, argv[0], NULL);
2006 		master->errlog = argv[0];
2007 		break;
2008 	case ARG_HISTORY:
2009 		master->do_chkhistory = FALSE;
2010 		break;
2011 	case ARG_KILLFILE:
2012 		master->do_killfile = FALSE;
2013 		break;
2014 	case ARG_KLOG_NONE:
2015 		master->killfile_log = KILL_LOG_NONE;
2016 		break;
2017 	case ARG_KLOG_SHORT:
2018 		master->killfile_log = KILL_LOG_SHORT;
2019 		break;
2020 	case ARG_KLOG_LONG:
2021 		master->killfile_log = KILL_LOG_LONG;
2022 		break;
2023 	case ARG_MODEREADER: /* mode reader */
2024 		master->do_modereader = TRUE;
2025 		break;
2026 	case ARG_PORTNR:	/* override default portnr */
2027 		master->portnr = atoi(argv[0]);
2028 		break;
2029 	case ARG_PASSWD:	/* passwd */
2030 		master->passwd = argv[0];
2031 		break;
2032 	case ARG_RESCAN:	/* don't rescan on restart */
2033 		master->rescan = FALSE;
2034 		break;
2035 	case ARG_STATLOG:	/* status log path */
2036 		master->status_file_name = argv[0];
2037 		break;
2038 	case ARG_USERID:	/* userid */
2039 		master->userid = argv[0];
2040 		break;
2041 	case ARG_PASSWD_ENV:	/* get userid/password from ENV */
2042 		master->userid = getenv("NNTP_USER");
2043 		master->passwd = getenv("NNTP_PASS");
2044 		master->passwd_env = TRUE;
2045 		break;
2046 	case ARG_VERSION: 	/* show version number */
2047 		error_log(ERRLOG_REPORT,"Suck version %v1%\n",SUCK_VERSION, NULL);
2048 		retval = RETVAL_VERNR;	/* so we don't do anything else */
2049 		break;
2050 	case ARG_WAIT:	/* wait (sleep) x seconds between every y articles */
2051 		master->pause_time = atoi(argv[0]);
2052 		master->pause_nrmsgs = atoi(argv[1]);
2053 		break;
2054 	case ARG_LOCALHOST:
2055 		master->localhost = argv[0];
2056 		break;
2057 	case ARG_NRMODE:
2058 		master->nrmode = TRUE;
2059 		break;
2060 	case ARG_AUTOAUTH:
2061 		master->auto_auth = TRUE;
2062 		break;
2063 	case ARG_NODEDUPE:
2064 		master->no_dedupe = TRUE;
2065 		break;
2066 	case ARG_READACTIVE:
2067 		master->activefile = argv[0];
2068 		break;
2069 	case ARG_PREBATCH:
2070 		master->prebatch = TRUE;
2071 		break;
2072 	case ARG_SKIP_ON_RESTART:
2073 		master->skip_on_restart = TRUE;
2074 		break;
2075 	case ARG_KLOG_NAME:
2076 		master->kill_log_name = argv[0];
2077 		break;
2078 	case ARG_USEGUI:
2079 		master->use_gui = TRUE;
2080 		break;
2081 	case ARG_XOVER:
2082 		master->do_xover = FALSE;
2083 		break;
2084 	case ARG_CONN_DEDUPE:
2085 		master->conn_dedupe = TRUE;
2086 		break;
2087 	case ARG_POST_FILTER:
2088 		master->post_filter = argv[0];
2089 		break;
2090 	case ARG_CONN_ACTIVE:
2091 		master->conn_active = TRUE;
2092 		break;
2093 	case ARG_HIST_FILE:
2094 		master->history_file = argv[0];
2095 		break;
2096 	case ARG_HEADER_ONLY:
2097 		master->header_only = TRUE;
2098 		break;
2099 	case ARG_ACTIVE_LASTREAD:
2100 		x = atoi(argv[0]);
2101 		if(x > 0) {
2102 			error_log(ERRLOG_REPORT, suck_phrases[66], NULL);
2103 		}
2104 		else {
2105 			master->active_lastread = atoi(argv[0]);
2106 		}
2107 		break;
2108 	case ARG_USEXOVER:
2109 		master->use_xover = TRUE;
2110 		break;
2111 	case ARG_RESETCOUNTER:
2112 		master->resetcounter = TRUE;
2113 		break;
2114 	case ARG_LOW_READ:
2115 		master->low_read = TRUE;
2116 		break;
2117 	case ARG_SHOW_GROUP:
2118 		master->show_group = TRUE;
2119 		break;
2120 #ifdef TIMEOUT
2121 	case ARG_TIMEOUT:
2122 		TimeOut = atoi(argv[0]);
2123 		break;
2124 #endif
2125 #ifdef HAVE_LIBSSL
2126 	case ARG_USE_SSL:
2127 		master->do_ssl = TRUE;
2128 		master->portnr = DEFAULT_SSL_PORT;
2129 		break;
2130 	case ARG_LOCAL_SSL:
2131 		master->local_ssl = TRUE;
2132 		break;
2133 #endif
2134 
2135 	}
2136 
2137 	return retval;
2138 
2139 }
2140 /*----------------------------------*/
2141 /* authenticate when receive a 480 */
2142 /*----------------------------------*/
2143 int do_authenticate(PMaster master) {
2144 	 int len, nr, retval = RETVAL_OK;
2145 	 char *resp, buf[MAXLINLEN];
2146 
2147 
2148 	 if(master->userid == NULL || master->passwd == NULL) {
2149 		 error_log(ERRLOG_REPORT, suck_phrases[73], NULL);
2150 		 retval = RETVAL_NOAUTH;
2151 	 }
2152 	 else {
2153 		 /* we must do authorization */
2154 		 sprintf(buf, "AUTHINFO USER %s\r\n", master->userid);
2155 		 if(master->debug == TRUE) {
2156 			 do_debug("sending command: %s", buf);
2157 		 }
2158 		 sputline(master->sockfd, buf, master->do_ssl, master->ssl_struct);
2159 		 len = sgetline(master->sockfd, &resp, master->do_ssl, master->ssl_struct);
2160 		 if( len < 0) {
2161 			 retval = RETVAL_ERROR;
2162 		 }
2163 		 else {
2164 			 if(master->debug == TRUE) {
2165 				 do_debug("got answer: %s", resp);
2166 			 }
2167 
2168 			 TimerFunc(TIMER_ADDBYTES, len, NULL);
2169 
2170 			 number(resp, &nr);
2171 			 if(nr == 480) {
2172 				 /* this is because of the pipelining code */
2173 				 /* we get the second need auth */
2174 				 /* just ignore it and get the next line */
2175 				 /* which should be the 381 we need */
2176 				 len = sgetline(master->sockfd, &resp, master->do_ssl, master->ssl_struct);
2177 				 TimerFunc(TIMER_ADDBYTES, len, NULL);
2178 
2179 				 number(resp, &nr);
2180 			 }
2181 
2182 			 if(nr != 381) {
2183 				 error_log(ERRLOG_REPORT, suck_phrases[27], resp, NULL);
2184 				 retval = RETVAL_NOAUTH;
2185 			 }
2186 			 else {
2187 				 sprintf(buf, "AUTHINFO PASS %s\r\n", master->passwd);
2188 				 sputline(master->sockfd, buf, master->do_ssl, master->ssl_struct);
2189 				 if(master->debug == TRUE) {
2190 					 do_debug("sending command: %s", buf);
2191 				 }
2192 				 len = sgetline(master->sockfd, &resp, master->do_ssl, master->ssl_struct);
2193 				 if(len < 0) {
2194 					 retval = RETVAL_ERROR;
2195 				 }
2196 				 else {
2197 					 if(master->debug == TRUE) {
2198 						 do_debug("got answer: %s", resp);
2199 					 }
2200 
2201 					 TimerFunc(TIMER_ADDBYTES, len, NULL);
2202 
2203 					 number(resp, &nr);
2204 					 switch(nr) {
2205 					 case 281: /* bingo */
2206 						 retval = RETVAL_OK;
2207 						 break;
2208 					 case 502: /* permission denied */
2209 						 retval = RETVAL_NOAUTH;
2210 						 error_log(ERRLOG_REPORT, suck_phrases[28], NULL);
2211 						 break;
2212 					 default: /* wacko error */
2213 						 error_log(ERRLOG_REPORT, suck_phrases[27], resp, NULL);
2214 						 retval = RETVAL_NOAUTH;
2215 						 break;
2216 					 }
2217 				 }
2218 			 }
2219 		 }
2220 	 }
2221 	 return retval;
2222  }
2223 /*--------------------------------------------------------------------------------*/
2224 /* THE strings in this routine is the only one not in the arrays, since           */
2225 /* we are in the middle of reading the arrays, and they may or may not be valid.  */
2226 /*--------------------------------------------------------------------------------*/
2227 void load_phrases(PMaster master) {
2228 
2229 	int error=TRUE;
2230 	FILE *fpi;
2231 	char buf[MAXLINLEN];
2232 
2233 	if(master->phrases != NULL) {
2234 
2235 		if((fpi = fopen(master->phrases, "r")) == NULL) {
2236 			MyPerror(master->phrases);
2237 		}
2238 		else {
2239 			fgets(buf, MAXLINLEN, fpi);
2240 			if(strncmp( buf, SUCK_VERSION, strlen(SUCK_VERSION)) != 0) {
2241 				error_log(ERRLOG_REPORT, "Invalid Phrase File, wrong version\n", NULL);
2242 			}
2243 			else if((both_phrases = read_array(fpi, NR_BOTH_PHRASES, TRUE)) != NULL) {
2244 				read_array(fpi, NR_RPOST_PHRASES, FALSE);	/* skip these */
2245 				read_array(fpi, NR_TEST_PHRASES, FALSE);
2246 				if(( suck_phrases = read_array(fpi, NR_SUCK_PHRASES, TRUE)) != NULL &&
2247 				   ( timer_phrases= read_array(fpi, NR_TIMER_PHRASES,TRUE)) &&
2248 				   (  chkh_phrases= read_array(fpi, NR_CHKH_PHRASES,TRUE)) &&
2249 				   (dedupe_phrases= read_array(fpi, NR_DEDUPE_PHRASES,TRUE)) &&
2250 				   ( killf_reasons= read_array(fpi, NR_KILLF_REASONS,TRUE)) &&
2251 				   ( killf_phrases= read_array(fpi, NR_KILLF_PHRASES,TRUE)) &&
2252 				   ( sucku_phrases= read_array(fpi, NR_SUCKU_PHRASES,TRUE)) &&
2253 				   (read_array(fpi, NR_LMOVE_PHRASES, FALSE) == NULL) && /* skip this one */
2254 				   ( active_phrases=read_array(fpi, NR_ACTIVE_PHRASES,TRUE)) &&
2255 				   ( batch_phrases= read_array(fpi, NR_BATCH_PHRASES,TRUE)) &&
2256 				   ( xover_phrases= read_array(fpi, NR_XOVER_PHRASES,TRUE)) &&
2257 				   ( xover_reasons= read_array(fpi, NR_XOVER_REASONS,TRUE))) {
2258 					error = FALSE;
2259 				}
2260 			}
2261 
2262 		}
2263 		fclose(fpi);
2264 		if(error == TRUE) {
2265 			/* reset back to default */
2266 			error_log(ERRLOG_REPORT, "Using default Language phrases\n", NULL);
2267 			both_phrases = default_both_phrases;
2268 			suck_phrases=default_suck_phrases;
2269 			timer_phrases=default_timer_phrases;
2270 			chkh_phrases=default_chkh_phrases;
2271 			dedupe_phrases=default_dedupe_phrases;
2272 			killf_reasons=default_killf_reasons;
2273 			killf_phrases=default_killf_phrases;
2274 			killp_phrases=default_killp_phrases;
2275 			sucku_phrases=default_sucku_phrases;
2276 			active_phrases=default_active_phrases;
2277 			batch_phrases=default_batch_phrases;
2278 			xover_phrases=default_xover_phrases;
2279 			xover_reasons=default_xover_reasons;
2280 		}
2281 	}
2282 }
2283 /*--------------------------------------------------------------------------------*/
2284 void free_phrases(void) {
2285 		/* free up the memory alloced in load_phrases() */
2286 		if(both_phrases != default_both_phrases) {
2287 			free_array(NR_BOTH_PHRASES, both_phrases);
2288 		}
2289 		if(suck_phrases != default_suck_phrases) {
2290 			free_array(NR_SUCK_PHRASES, suck_phrases);
2291 		}
2292 		if(timer_phrases != default_timer_phrases) {
2293 			free_array(NR_TIMER_PHRASES, timer_phrases);
2294 		}
2295 		if(chkh_phrases != default_chkh_phrases) {
2296 			free_array(NR_CHKH_PHRASES, chkh_phrases);
2297 		}
2298 		if(dedupe_phrases != default_dedupe_phrases) {
2299 			free_array(NR_DEDUPE_PHRASES, dedupe_phrases);
2300 		}
2301 		if(killf_reasons != default_killf_reasons) {
2302 			free_array(NR_KILLF_REASONS, killf_reasons);
2303 		}
2304 		if(killf_phrases != default_killf_phrases) {
2305 			free_array(NR_KILLF_PHRASES, killf_phrases);
2306 		}
2307 		if(killp_phrases != default_killp_phrases) {
2308 			free_array(NR_KILLP_PHRASES, killp_phrases);
2309 		}
2310 		if(sucku_phrases != default_sucku_phrases) {
2311 			free_array(NR_SUCKU_PHRASES, sucku_phrases);
2312 		}
2313 		if(active_phrases != default_active_phrases) {
2314 			free_array(NR_ACTIVE_PHRASES, active_phrases);
2315 		}
2316 		if(batch_phrases != default_batch_phrases) {
2317 			free_array(NR_BATCH_PHRASES, batch_phrases);
2318 		}
2319 		if(xover_phrases != default_xover_phrases) {
2320 			free_array(NR_XOVER_PHRASES, xover_phrases);
2321 		}
2322 		if(xover_reasons != default_xover_reasons) {
2323 			free_array(NR_XOVER_REASONS, xover_reasons);
2324 		}
2325 
2326 
2327 
2328 }
2329 
2330 
2331