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 #include <string.h>
9 #include <ctype.h>
10
11 #ifdef HAVE_DIRENT_H
12 # include <dirent.h>
13 #else
14 # define dirent direct
15 # ifdef HAVE_SYS_NDIR_H
16 # include <sys/ndir.h>
17 # endif
18 # ifdef HAVE_SYS_DIR_H
19 # include <sys/dir.h>
20 # endif
21 #endif
22
23 #ifdef HAVE_LIMITS_H
24 #include <limits.h>
25 #endif
26
27 #include "suck_config.h"
28
29 #ifdef HAVE_REGEX_H
30 #include <regex.h>
31 #endif
32
33 #ifdef DMALLOC
34 #include <dmalloc.h>
35 #endif
36
37 #include "both.h"
38 #include "suck.h"
39 #include "suckutils.h"
40 #include "killfile.h"
41 #include "phrases.h"
42 #include "timer.h"
43
44 #define GROUP_KEEP "keep"
45 #define GROUP_DELETE "delete" /* word in param file parsed for on group line to signify keep or delete */
46 #define NEWSGROUP_HEADER "Newsgroups: " /* header for line to match group files to */
47
48 /* local function prototypes */
49 int get_chunk_mem(PMaster, unsigned long *len, int which, char **buf);
50 int check_newsgroups(char *, const char *);
51 void free_node(OneKill);
52 int parse_a_file(const char *, const char *, POneKill, int, int, int);
53 int pass_two(PKillStruct, int, const char *fname);
54 int check_a_group(PMaster, POneKill, char *, char **);
55 void print_debug(PKillStruct, const char *);
56 void debug_one_kill(POneKill);
57 void add_to_linkedlist(pmy_regex *, pmy_regex);
58 pmy_regex regex_scan(char *, char, int, int, char);
59 int regex_check(char *, pmy_regex, int);
60
61 void initialize_one_kill(POneKill);
62 #ifdef HAVE_REGEX_H
63 const char regex_chars[] = "*[]()^$\\?."; /* characters which make it a regex */
64 #endif
65
66 void display_skiparray(unsigned char [SIZEOF_SKIPARRAY]);
67 int find_string(int, pmy_regex, char *);
68
69 /*-------------------------------------------------------------------------*/
70 /* the enum must match the phrases in suckengl.c killf_reasons[] */
71 enum { REASON_NONE, REASON_TOOMANYLINES, REASON_NOTENUFLINES, REASON_NRGRPS, REASON_NOKEEP, REASON_TIE, REASON_HEADER, \
72 REASON_BODY, REASON_BODYBIG, REASON_BODYSMALL, REASON_NRXREF };
73 enum { CHECK_EXACT, CHECK_CHECK };
74 enum { CHUNK_HEADER, CHUNK_BODY };
75
76 const struct {
77 int len;
78 const char *name;
79 int headerlen;
80 const char *header;
81 } Params[] = {
82 {8, "HILINES=", 7, "Lines: " },
83 {9, "LOWLINES=", 7, "Lines: "},
84 {7, "NRGRPS=", 12, "Newsgroups: "},
85 {6, "GROUP=", 0, ""},
86 {6, "QUOTE=", 0, ""},
87 {8, "PROGRAM=", 0, ""},
88 {7, "HEADER:", 0, ""},
89 {5, "BODY:", 0, ""},
90 {9, "BODYSIZE>", 0, ""},
91 {9, "BODYSIZE<", 0, ""},
92 {21, "GROUP_OVERRIDE_MASTER", 0, ""}, /* string in masterfile to signify that group files override the master */
93 {17, "TIEBREAKER_DELETE", 0, ""}, /* what to do if match multi groups override default of keep */
94 {18, "USE_EXTENDED_REGEX", 0, ""}, /* do we use extended regular expressions */
95 {10, "NON_REGEX=", 0, ""},
96 {5, "PERL=", 0, ""},
97 {14, "XOVER_LOG_LONG", 0, ""}, /* make Xover killlog look like regular kill lo)*/
98 {7, "NRXREF=", 6, "Xref: "},
99 };
100
101
102 enum { PARAM_HILINE, PARAM_LOWLINE, PARAM_NRGRPS, PARAM_GROUP, PARAM_QUOTE, PARAM_PROGRAM,PARAM_HDRSCAN,
103 PARAM_BODY, PARAM_BODYBIG, PARAM_BODYSMALL, PARAM_GRPOVERRIDE, PARAM_TIEDELETE, PARAM_E_REGEX,
104 PARAM_NONREGEX, PARAM_PERL, PARAM_XOVER_LOG_LONG, PARAM_NRXREF};
105 #define NR_PARAMS ((int) (sizeof(Params)/sizeof(Params[0])))
106
107
108 /*--------------------------------------------------------------------------*/
parse_killfile(int which,int logfile_yn,int debug,int ignore_postfix)109 PKillStruct parse_killfile(int which, int logfile_yn, int debug, int ignore_postfix) {
110 FILE *fptr;
111 char buf[MAXLINLEN+1];
112 int i, doprg = FALSE, mastergrp = RETVAL_OK, retval = TRUE;
113 const char *filename;
114 #ifdef PERL_EMBED
115 int doperl = FALSE;
116 #endif
117 KillStruct *Masterkill = NULL;
118
119 /* kill file is going to get three passes, 1st one to count how many group files to process */
120 /* so can allocate memory for all the group stuff. */
121 /* also check for group override of masterkillfile */
122 /* and process PROGRAM line if it exists. If we have one we don't do anything else */
123 /* 2nd pass will be to actually process the group files */
124 /* 3rd pass will be to process the master delete stuff */
125
126 /* first malloc our master structure */
127 if((Masterkill = malloc(sizeof(KillStruct))) == NULL) {
128 error_log(ERRLOG_REPORT, killf_phrases[1], NULL);
129 retval = FALSE;
130 }
131 else {
132 /* now initialize everything */
133 Masterkill->logfp = NULL;
134 Masterkill->grp_override = FALSE;
135 Masterkill->tie_delete = FALSE;
136 Masterkill->totgrps = 0;
137 Masterkill->grps = NULL;
138 Masterkill->killfunc = chk_msg_kill;
139 Masterkill->pbody= NULL;
140 Masterkill->bodylen = 0;
141 Masterkill->use_extended_regex = FALSE;
142 Masterkill->xover_log_long = FALSE;
143 /* initialize the master struct */
144 Masterkill->child.Stdin = Masterkill->child.Stdout = -1;
145 Masterkill->child.Pid = -1;
146 initialize_one_kill(&(Masterkill->master));
147
148 #ifdef PERL_EMBED
149 Masterkill->perl_int = NULL;
150 #endif
151
152 Masterkill->logyn = logfile_yn;
153 /* which option to we use in call to full_path() ? Do we use the postfix or not? */
154 Masterkill->ignore_postfix = ( ignore_postfix == TRUE) ? FP_GET_NOPOSTFIX : FP_GET ;
155
156 filename = ( which == KILL_XOVER ) ? N_XOVER : N_KILLFILE;
157
158 if(debug == TRUE) {
159 do_debug("Trying to read killfile: %s\n", full_path(Masterkill->ignore_postfix, FP_DATADIR, filename));
160 }
161
162 /* FIRST PASS THRU MASTER KILLFILE - look for group delete/keeps and count em and check for PROGRAM call*/
163 if((fptr = fopen(full_path(Masterkill->ignore_postfix, FP_DATADIR, filename), "r")) == NULL) {
164 /* this is not really an error, so don't report it as such */
165 retval = FALSE;
166 }
167 else {
168 if(debug == TRUE) {
169 do_debug("Pass 1 & 2 kill file: %s\n", full_path(Masterkill->ignore_postfix, FP_DATADIR, filename));
170 }
171
172 while(fgets(buf, MAXLINLEN, fptr) != NULL && doprg == FALSE) {
173 /* nuke nl, so file names are correct, etc */
174 i = strlen(buf);
175 if(buf[i-1] == '\n') {
176 buf[i-1] = '\0';
177 }
178 if(debug == TRUE) {
179 do_debug("Read kill file line: %s\n", buf);
180 }
181 if(strncmp(buf, Params[PARAM_GROUP].name, (size_t) Params[PARAM_GROUP].len) == 0) {
182 Masterkill->totgrps++; /* how many group files must we process */
183 }
184 if(strncmp(buf, Params[PARAM_PROGRAM].name, (size_t) Params[PARAM_PROGRAM].len) == 0) {
185 #ifdef PERL_EMBED
186 if(Masterkill->perl_int == NULL) {
187 #endif
188 doprg = killprg_forkit(Masterkill, &buf[Params[PARAM_PROGRAM].len], debug, which);
189 #ifdef PERL_EMBED
190 }
191 #endif
192 }
193 if(strncmp(buf, Params[PARAM_GRPOVERRIDE].name, (size_t) Params[PARAM_GRPOVERRIDE].len) == 0) {
194 Masterkill->grp_override = TRUE;
195 }
196 if(strncmp(buf, Params[PARAM_TIEDELETE].name, (size_t) Params[PARAM_TIEDELETE].len) == 0) {
197 Masterkill->tie_delete = TRUE;
198 }
199 if(strncmp(buf, Params[PARAM_E_REGEX].name, (size_t) Params[PARAM_E_REGEX].len) == 0) {
200 Masterkill->use_extended_regex = TRUE;
201 }
202 if(strncmp(buf, Params[PARAM_XOVER_LOG_LONG].name, (size_t) Params[PARAM_XOVER_LOG_LONG].len) == 0) {
203 Masterkill->xover_log_long = TRUE;
204 }
205
206 #ifdef PERL_EMBED
207 if(strncmp(buf, Params[PARAM_PERL].name, (size_t) Params[PARAM_PERL].len) == 0) {
208 if(doprg == FALSE) {
209 doperl = killperl_setup(Masterkill, &buf[Params[PARAM_PERL].len], debug, which);
210 }
211 }
212 #endif
213 }
214 (void) fclose(fptr);
215 #ifndef PERL_EMBED
216 if(doprg == TRUE) {
217 #else
218 if(doprg == TRUE || Masterkill->perl_int != NULL) {
219 #endif
220 Masterkill->totgrps = 0;
221 }
222 else {
223 /* SECOND PASS - call routine */
224 if(Masterkill->totgrps > 0) {
225 if(pass_two(Masterkill, debug, filename) == RETVAL_ERROR) {
226 retval = FALSE;
227 }
228 }
229 /* THIRD PASS - process master delete stuff */
230 if(retval != FALSE && (mastergrp = parse_a_file(filename, "Master", &(Masterkill->master), debug, Masterkill->ignore_postfix, Masterkill->use_extended_regex)) == RETVAL_ERROR) {
231 retval = FALSE;
232 }
233 }
234 }
235
236 /* do we have an error OR do we have empty killfiles */
237 if((retval == FALSE) || (mastergrp == RETVAL_EMPTYKILL && Masterkill->totgrps == 0 && doprg == FALSE)) {
238 #ifdef PERL_EMBED
239 if(Masterkill->perl_int == NULL) {
240 #endif
241 free_killfile(Masterkill); /* just in case any memory got allocated */
242 Masterkill = NULL;
243 #ifdef PERL_EMBED
244 }
245 #endif
246 }
247 else if(debug == TRUE) {
248 print_debug(Masterkill, filename);
249 }
250 }
251
252 return Masterkill;
253 }
254 /*-------------------------------------------------------------------------------------------*/
255 int pass_two(PKillStruct killp, int debug, const char *filename ) {
256
257 int retval = RETVAL_OK;
258 FILE *fptr;
259 char buf[MAXLINLEN];
260 int grpon = 0;
261 size_t i;
262 char *grpname, *grpfile, *delkeep;
263
264 grpname = grpfile = delkeep = NULL;
265
266 /* SECOND PASS - now that we know how many, we can allocate the space for em */
267 /* and then have parse_a_file read em in. */
268 if((killp->grps = calloc((size_t) killp->totgrps, sizeof(Group))) == NULL) {
269 retval = RETVAL_ERROR;
270 error_log(ERRLOG_REPORT, killf_phrases[1], NULL);
271 }
272 else if((fptr = fopen(full_path(killp->ignore_postfix, FP_DATADIR, filename), "r")) == NULL) {
273 MyPerror(full_path(killp->ignore_postfix, FP_DATADIR, filename));
274 retval = RETVAL_ERROR;
275 }
276 else {
277 while(retval == RETVAL_OK && fgets(buf, MAXLINLEN, fptr) != NULL) {
278 if(strncmp(buf, Params[PARAM_GROUP].name, (size_t) Params[PARAM_GROUP].len) == 0 ) {
279
280 /* now parse the line for the 3 required elements */
281 /* keep/delete group_name filename */
282 delkeep = &buf[Params[PARAM_GROUP].len];
283 if(strncmp(delkeep, GROUP_KEEP, (size_t) strlen(GROUP_KEEP)) == 0) {
284 killp->grps[grpon].delkeep = DELKEEP_KEEP;
285 }
286 else if(strncmp(delkeep, GROUP_DELETE, (size_t) strlen(GROUP_DELETE)) == 0) {
287 killp->grps[grpon].delkeep = DELKEEP_DELETE;
288 }
289 else {
290 retval = RETVAL_ERROR;
291 }
292 if(retval == RETVAL_OK) {
293 grpname = strchr(delkeep, ' '); /* find the space */
294 if(grpname == NULL) {
295 retval = RETVAL_ERROR;
296 }
297 else {
298 ++grpname; /* move past space */
299 grpfile = strchr(grpname, ' ');
300 if(grpfile == NULL) {
301 retval = RETVAL_ERROR;
302 }
303 else {
304 *grpfile = '\0'; /* truncate the group name for easier copying later */
305 ++grpfile;
306
307 /* nuke newline */
308 i = strlen(grpfile) - 1;
309 if(grpfile[i] == '\n') {
310 grpfile[i] = '\0';
311 }
312 }
313 }
314 }
315 if(retval == RETVAL_ERROR) {
316 error_log(ERRLOG_REPORT, killf_phrases[2], buf, NULL);
317 }
318 else { /* have all three params, put them in place and parse the file */
319 /* +1 for newline */
320 if((killp->grps[grpon].group = malloc(strlen(grpname)+1)) == NULL) {
321 error_log(ERRLOG_REPORT, killf_phrases[0], NULL);
322 retval = RETVAL_ERROR;
323 }
324 else {
325 strcpy(killp->grps[grpon].group, grpname);
326 /* get, ignoring postfix, so use absolute filename on group line */
327 if(parse_a_file(grpfile, grpname, &(killp->grps[grpon].match), debug,FP_GET_NOPOSTFIX,killp->use_extended_regex) != RETVAL_OK) {
328 /* whoops couldn't open file, ignore */
329 free(killp->grps[grpon].group);
330 grpon--; /* so that we reuse this grp entry */
331 killp->totgrps--;
332 }
333
334 }
335 }
336 grpon++; /* finished with this group */
337 }
338 }
339 (void) fclose(fptr);
340 }
341
342 return retval;
343 }
344 /*--------------------------------------------------------------------------*/
345 void free_killfile(PKillStruct master) {
346
347 int i;
348
349 if(master != NULL) {
350 /* first kill off killprg if its there */
351 if(master->killfunc==chk_msg_kill_fork || master->child.Pid != -1) {
352 killprg_closeit(master);
353 }
354 #ifdef PERL_EMBED
355 if(master->perl_int != NULL) {
356 killperl_done(master);
357 }
358 #endif
359 /* close off log, if opened */
360 if(master->logfp != NULL) {
361 fclose(master->logfp);
362 }
363 free_node(master->master);
364 if(master->totgrps > 0) {
365 for(i=0;i<master->totgrps;i++) {
366 free_node(master->grps[i].match);
367 free(master->grps[i].group);
368 }
369 free(master->grps);
370 }
371
372 free(master);
373 }
374 }
375 /*--------------------------------------------------------------------*/
376 void free_node(OneKill node) {
377
378 pmy_regex curr, next;
379
380 curr = node.list;
381
382 if (node.header != NULL) {
383 #ifdef HAVE_REGEX_H
384 if(node.header->ptrs != NULL) {
385 regfree(node.header->ptrs);
386 }
387 #endif
388 if(node.header->header != NULL) {
389 free(node.header->header);
390 }
391 if(node.header->string != NULL) {
392 free(node.header->string);
393 }
394 }
395 while(curr != NULL) {
396 #ifdef HAVE_REGEX_H
397 if(curr->ptrs != NULL) {
398 regfree(curr->ptrs);
399 }
400 #endif
401 if(curr->header != NULL) {
402 free(curr->header);
403 }
404 if(curr->string != NULL) {
405 free(curr->string);
406 }
407 next = curr->next;
408 free(curr);
409 curr = next;
410 }
411
412 }
413 /*--------------------------------------------------------------------------*/
414 int get_one_article_kill(PMaster master, int logcount, long itemon) {
415
416 char buf[MAXLINLEN+1], *inbuf;
417 const char *tname;
418 char fname[PATH_MAX+1];
419 int retval, x;
420 unsigned long len;
421 FILE *fptr;
422 PKillStruct killp;
423
424 killp = master->killp;
425
426 retval = RETVAL_OK;
427
428 killp->pbody = NULL; /* since we haven't downloaded anything yet for this article */
429 killp->bodylen = 0;
430
431 retval =get_chunk_mem(master, &len, CHUNK_HEADER, &inbuf);
432
433 /* the killfunc pointer points to either chk_msg_kill(), chk_msg_kill_fork(), or chk_msg_kill_perl() */
434 /* do we have to download this sucker, is it mandatory? */
435 if(retval == RETVAL_OK && ((master->curr)->mandatory == MANDATORY_YES || (*killp->killfunc)(master, killp, inbuf, len) == FALSE)) {
436 if(master->MultiFile == TRUE) {
437 /* open file */
438 /* file name will be ####-#### ex 001-166 (nron,total) */
439 sprintf(buf,"%0*ld-%d", logcount, itemon, master->nritems);
440
441 /* the strcpy to avoid wiping out fname in second call to full_path */
442 strcpy(fname, full_path(FP_GET, FP_MSGDIR, buf));
443 strcat(buf, N_TMP_EXTENSION); /* add temp file extension */
444 tname = full_path(FP_GET, FP_TMPDIR, buf); /* temp file name */
445 if(master->debug == TRUE) {
446 do_debug("File name = \"%s\" temp = \"%s\"", fname, tname);
447 }
448 if((fptr = fopen(tname, "w")) == NULL) {
449 MyPerror(tname);
450 retval = RETVAL_ERROR;
451 }
452 else {
453 /* write the header */
454 x = fwrite(inbuf,sizeof(inbuf[0]),len, fptr);
455 fputs("\n", fptr); /* needed */
456 if(x != len) {
457 retval = RETVAL_ERROR;
458 error_log(ERRLOG_REPORT, killf_phrases[9], NULL);
459 }
460 if(retval == RETVAL_OK && master->header_only == FALSE) {
461 /* have we already downloaded the body? */
462 if(killp->pbody != NULL) {
463 inbuf = killp->pbody;
464 len = killp->bodylen;
465 }
466 else {
467 retval = get_chunk_mem(master, &len, CHUNK_BODY, &inbuf);
468 }
469 if(retval == RETVAL_OK) {
470 x = fwrite(inbuf, sizeof(inbuf[0]), len, fptr);
471 if(x != len) {
472 retval = RETVAL_ERROR;
473 error_log(ERRLOG_REPORT, killf_phrases[9], NULL);
474 }
475 }
476 }
477 (void) fclose(fptr);
478 if(retval != RETVAL_OK) {
479 unlink(tname);
480 }
481 /* now rename it to the permanent file name */
482 else {
483 move_file(tname, fname);
484 if((master->batch == BATCH_LIHAVE || master->batch == BATCH_INNFEED) && master->innfeed != NULL) {
485 /* write path name and msgid to file */
486 fprintf(master->innfeed, "%s %s\n", fname, (master->curr)->msgnr);
487 fflush(master->innfeed); /* so it gets written sooner */
488 }
489 }
490 }
491 }
492 else {
493 fputs(inbuf, stdout);
494 fputs("\n", stdout);
495 if(master->header_only == FALSE) {
496 retval = get_chunk_mem(master, &len, CHUNK_BODY, &inbuf);
497 if(retval == RETVAL_OK) {
498 fwrite(inbuf, sizeof(inbuf[0]), len, stdout);
499 }
500 }
501 /* this is needed as a separator in stdout version */
502 fputs(".\n", stdout);
503 }
504 if(retval == RETVAL_OK) {
505 master->nrgot++;
506 }
507 }
508 if(retval == RETVAL_UNEXPECTEDANS) {
509 retval = RETVAL_OK; /* so don't abort */
510 }
511
512 return retval;
513 }
514 /*---------------------------------------------------------------*/
515 /* this routine gets the header or body into memory, keeping separate buffers for each */
516 int get_chunk_mem(PMaster master, unsigned long *size, int which, char **retbuf) {
517
518
519 static char *header_buf = NULL;
520 static char *body_buf = NULL;
521 static int header_size = 8192;
522 static unsigned long body_size = KILL_BODY_BUF_SIZE;
523
524 int done, partial, len, i, retval;
525 char *inbuf, *newbuf, *buf;
526 const char *cmd;
527 unsigned long temp, bufsize, currbuf; /* bufsize = alloced memory, currbuf = what retrieved so far */
528
529
530 done = FALSE;
531 partial = FALSE;
532 currbuf = 0;
533 retval = RETVAL_OK;
534
535 if(which == CHUNK_HEADER) {
536 buf = header_buf;
537 bufsize = header_size;
538 }
539 else {
540 buf = body_buf;
541 bufsize = body_size;
542 }
543
544 if(buf == NULL) {
545 if((buf=malloc((size_t) bufsize)) == NULL) {
546 error_log(ERRLOG_REPORT, killf_phrases[0], NULL);
547 retval = RETVAL_ERROR;
548 }
549 }
550
551 if(buf != NULL) {
552 /* build command */
553 if(which == CHUNK_HEADER) {
554 cmd = build_command(master, "head", master->curr);
555 i = 221;
556 }
557 else {
558 cmd = build_command(master, "body", master->curr);
559 i = 222;
560 }
561 if((retval = send_command(master, cmd, NULL, i)) != RETVAL_OK) {
562 free(buf);
563 buf = NULL;
564 }
565 }
566 while(buf != NULL && done == FALSE) {
567 len=sgetline(master->sockfd, &inbuf, master->do_ssl, master->ssl_struct);
568 (void) TimerFunc(TIMER_ADDBYTES, len, NULL);
569 if(len < 0) {
570 free(buf);
571 buf = NULL;
572 done = TRUE;
573 retval = RETVAL_ERROR;
574 }
575 else if(partial == FALSE && inbuf[0] == '.') {
576 if(len == 2 && inbuf[1] == '\n') {
577 done = TRUE;
578 }
579 else {
580 /* handle double dots IAW RFC977 2.4.1*/
581 inbuf++; /* move past first dot */
582 len--;
583 }
584 }
585 if(done == FALSE) {
586 while((len+currbuf) > bufsize && buf != NULL) {
587 /* buffer not big enough realloc */
588 /* how much do we increase buf */
589 /* we do this test so in case KILL_CHUNK_BUF_INCREASE < len, we */
590 /* don't get a buffer overflow */
591 temp = (len > KILL_CHUNK_BUF_INCREASE) ? len : KILL_CHUNK_BUF_INCREASE;
592 if(master->debug == TRUE) {
593 do_debug("Re-allocing buffer from %lu to %lu\n", bufsize, bufsize+temp);
594 }
595 bufsize += temp;
596 if((newbuf = realloc(buf, (size_t) bufsize)) == NULL) {
597 free(buf);
598 buf = NULL;
599 currbuf = 0;
600 error_log(ERRLOG_REPORT, killf_phrases[0], NULL);
601 retval = RETVAL_ERROR;
602 }
603 else {
604 buf = newbuf;
605 }
606 }
607 if(buf != NULL) {
608 /* put string in buffer, use memmove in case of nulls*/
609 memmove(buf+currbuf, inbuf, len);
610 currbuf += len;
611 partial= (len==MAXLINLEN&&inbuf[len-1]!='\n') ? TRUE : FALSE;
612 }
613 }
614 }
615 /* now save the values for next time */
616 if(which == CHUNK_HEADER) {
617 header_buf = buf;
618 header_size = bufsize;
619 }
620 else {
621 body_buf = buf;
622 body_size = bufsize;
623 }
624 /* return the length */
625 *size = currbuf;
626
627 /* make sure buf is NULL terminated */
628 /* this is needed so logging is correct */
629 /* since using memmove() above, we don't copy the ending NULL */
630 if(buf != NULL) {
631 buf[currbuf] = '\0';
632 }
633
634 *retbuf = buf;
635 return retval;
636 }
637 /*-------------------------------------------------------------------------*/
638 /* chk_msg_kill - return TRUE if kill article, FALSE if keep */
639 /* if kill article, add it to killlog */
640 int chk_msg_kill(PMaster master, PKillStruct killp, char *headerbuf, int buflen) {
641
642 int killyn, i, del, keep, match, masterkill;
643 const char *group = "Master";
644 char *why, *goodwhy;
645
646 goodwhy = why = killf_reasons[REASON_NONE];
647 killyn = FALSE;
648
649 /* first check against master delete */
650 masterkill = check_a_group(master, &(killp->master), headerbuf, &why);
651 if(masterkill == TRUE && killp->grp_override == FALSE) {
652 killyn = masterkill;
653 }
654 else {
655 /* okay now have to parse group line */
656 /* then check to see if I have group keep/deletes for each group */
657 /* default actions */
658 keep = FALSE;
659 del = FALSE;
660 for(i=0;i<killp->totgrps;i++) {
661 if(check_newsgroups(headerbuf, killp->grps[i].group) == TRUE) {
662 /* bingo this article matches one of our group check it */
663 match = check_a_group(master, &(killp->grps[i].match), headerbuf, &why);
664 if(killp->grps[i].delkeep == DELKEEP_KEEP) {
665 /* matched keep group */
666 if(match == TRUE) {
667 keep = TRUE;
668 }
669 else {
670 del = TRUE;
671 group = killp->grps[i].group;
672 goodwhy = killf_reasons[REASON_NOKEEP];
673 }
674 }
675 else {
676 if(match == TRUE) {
677 del = TRUE;
678 goodwhy = why;
679 group = killp->grps[i].group;
680 }
681 else {
682 keep = TRUE;
683 }
684 }
685 }
686 }
687 /* now determine if we kill or keep this sucker */
688 if(keep == FALSE && del == FALSE) {
689 /* no group matches, do what masterkill says to do */
690 killyn = masterkill;
691 }
692 else if(keep != del) {
693 /* only matched one group, figure out which */
694 killyn = ( del == TRUE) ? TRUE : FALSE;
695 why = goodwhy;
696 }
697 else {
698 /* matched both, use TIEBREAKER */
699 why = killf_reasons[REASON_TIE];
700 killyn = killp->tie_delete;
701 }
702 }
703 if(master->debug == TRUE && killyn == TRUE) {
704 do_debug("killing: %s: %s: %s", group, why, headerbuf);
705 }
706 if(killyn == TRUE && killp->logyn != KILL_LOG_NONE) {
707 /* log it */
708 /* only open this sucker once */
709 if(killp->logfp == NULL) {
710 if((killp->logfp = fopen(full_path(FP_GET, FP_TMPDIR, master->kill_log_name), "a")) == NULL) {
711 MyPerror(killf_phrases[3]);
712 }
713 }
714 if(killp->logfp != NULL) {
715 /* first print our one-line reason */
716 print_phrases(killp->logfp,killf_phrases[4], group ,why, (master->curr)->msgnr, NULL);
717
718 if(killp->logyn == KILL_LOG_LONG) {
719 /* print the header as well */
720 /* the nl so I get a blank line between em */
721 print_phrases(killp->logfp, "%v1%\n", headerbuf, NULL);
722 }
723
724 }
725 }
726 return killyn;
727 }
728 /*-----------------------------------------------------------------------*/
729 int check_a_group(PMaster master, POneKill killp, char *headerbuf, char **why) {
730
731 int i, match = FALSE;
732 char *startline, *tptr;
733 pmy_regex curr;
734 static char reason[MAXLINLEN];
735 PKillStruct temp;
736
737 /* check hilines first */
738 if(killp->hilines > 0) {
739 if((startline = strstr(headerbuf, Params[PARAM_HILINE].header)) != NULL) {
740 i = 0; /* just in case */
741 sscanf(startline+Params[PARAM_HILINE].headerlen, "%d", &i);
742 if(killp->hilines < i) {
743 /* JACKPOT */
744 match = TRUE;
745 *why = killf_reasons[REASON_TOOMANYLINES];
746 }
747 }
748
749 }
750 /* now check low lines */
751 if(match == FALSE && killp->lowlines > 0) {
752 if((startline = strstr(headerbuf, Params[PARAM_LOWLINE].header)) != NULL) {
753 i = 0; /* just in case */
754 sscanf(startline+Params[PARAM_LOWLINE].headerlen, "%d", &i);
755 if(i < killp->lowlines) {
756 /* JACKPOT */
757 match = TRUE;
758 *why = killf_reasons[REASON_NOTENUFLINES];
759 }
760 }
761
762 }
763 /* now check nrgrps */
764 if(match == FALSE && killp->maxgrps > 0) {
765 if((startline = strstr(headerbuf, Params[PARAM_NRGRPS].header)) != NULL) {
766 /* count the nr of commas in the group line */
767 i = 1; /* have at least one group */
768 tptr = startline;
769 while(i <= killp->maxgrps && *tptr != '\n' && *tptr != '\0' ) {
770 /* some news server use space vice comma for separator */
771 if(*tptr == COMMA || *tptr == SPACE ) {
772 i++;
773 }
774 tptr++;
775 }
776 if(i > killp->maxgrps) {
777 match = TRUE;
778 *why = killf_reasons[REASON_NRGRPS];
779 }
780 }
781 }
782 /* now check nrxref */
783 if(match == FALSE && killp->maxxref > 0) {
784 if((startline = strstr(headerbuf, Params[PARAM_NRXREF].header)) != NULL) {
785 /* count the nr of colons in line, they separate the group/article nr */
786 i = 0;
787 tptr = startline;
788 while(i <= killp->maxxref && *tptr != '\n' && *tptr != '\0' ) {
789 if(*tptr == COLON) {
790 i++;
791 }
792 tptr++;
793 }
794 if(i > killp->maxxref) {
795 match = TRUE;
796 *why = killf_reasons[REASON_NRXREF];
797 }
798 }
799 }
800 curr = killp->list;
801
802 while(match == FALSE && curr != NULL) {
803 if(regex_check(headerbuf, curr, master->debug) == TRUE) {
804 match = TRUE;
805 sprintf(reason, "%s %s %s ", killf_reasons[REASON_HEADER], curr->header, curr->string);
806 *why = reason;
807 }
808 curr = curr->next;
809 }
810 curr = killp->header;
811 while(match == FALSE && curr != NULL) {
812 /* scan the entire header */
813 if(regex_block(headerbuf, curr, master->debug) == TRUE) {
814 match = TRUE;
815 sprintf(reason,"%s %s", killf_reasons[REASON_HEADER], curr->string);
816 *why = reason;
817 }
818 curr = curr->next;
819 }
820 if(match == FALSE && (killp->bodybig > 0 || killp->bodysmall > 0 || killp->body != NULL)) {
821 /* may have to download the header first to */
822 /* have a pointer to the master killstruct */
823 temp = master->killp;
824 if(temp->pbody == NULL) {
825 /* have to get the body first */
826 get_chunk_mem(master, &(temp->bodylen), CHUNK_BODY, &(temp->pbody));
827 }
828 if(killp->bodybig > 0 && temp->bodylen > killp->bodybig) {
829 match = TRUE;
830 sprintf(reason, "%s %lu", killf_reasons[REASON_BODYBIG], temp->bodylen);
831 *why = reason;
832 }
833 else if(killp->bodysmall > 0 && temp->bodylen < killp->bodysmall) {
834 match = TRUE;
835 sprintf(reason, "%s %lu", killf_reasons[REASON_BODYSMALL], temp->bodylen);
836 *why = reason;
837 }
838 else {
839 curr = killp->body;
840 while(match == FALSE && curr != NULL) { /* scan the body */
841 if(regex_block(temp->pbody, curr, master->debug) == TRUE) {
842 match = TRUE;
843 sprintf(reason, "%s %s", killf_reasons[REASON_BODY], curr->string);
844 *why = reason;
845 }
846 curr = curr->next;
847 }
848 }
849 }
850
851 return match;
852 }
853 /*--------------------------------------------------------------------------*/
854 int check_newsgroups(char *header, const char *whichgroup) {
855 /* search Newsgroup headerline for whichgroup */
856 /* if in return TRUE else return FALSE; */
857
858 int match = FALSE;
859 char *startline, *ptr;
860 const char *ptr_group;
861
862 if((startline = strstr(header, NEWSGROUP_HEADER)) != NULL) {
863 ptr = startline + strlen(NEWSGROUP_HEADER);
864 while( match == FALSE && *ptr != '\0' && *ptr != '\n' ) {
865 ptr_group = whichgroup;
866 while( *ptr == *ptr_group && *ptr != '\0') {
867 ptr++;
868 ptr_group++;
869 }
870 if(*ptr_group == '*') {
871 /* wildcard match, they match so far, so they match */
872 match = TRUE;
873 }
874 else if((*ptr_group == '\0') && (*ptr == COMMA || *ptr == ' ' || *ptr == '\n' || *ptr == '\0')) {
875 /* if we are at the end of both group names then we have a match */
876 /* we check for space even though its not in the standard, apparently */
877 /* some news server use it. */
878 match = TRUE;
879 }
880 else {
881 /* advance to next group on line */
882 while(*ptr != COMMA && *ptr != '\n' && *ptr != '\0') {
883 ptr++;
884 }
885 if(*ptr == COMMA) {
886 /* advance past it */
887 ptr++;
888 }
889 }
890 }
891 }
892 return match;
893 }
894 /*-------------------------------------------------------------------------------*/
895 void initialize_one_kill(POneKill mykill) {
896 /* initialize the various elements*/
897 mykill->list = NULL;
898 mykill->header = NULL;
899 mykill->body = NULL;
900 mykill->hilines = mykill->lowlines = mykill->maxgrps = mykill->maxxref = 0;
901 mykill->bodybig = mykill->bodysmall = 0;
902 mykill->quote = KILLFILE_QUOTE;
903 mykill->non_regex = KILLFILE_NONREGEX;
904
905 return;
906 }
907
908 /*-------------------------------------------------------------------------------*/
909 int parse_a_file(const char *fname, const char *group, POneKill mykill, int debug, int ignore_prefix, int use_e_regex) {
910
911 FILE *fptr;
912 char buf[MAXLINLEN+1];
913 int i, match;
914 int retval = RETVAL_OK;
915 pmy_regex curr;
916
917 /* first initialize the killstruct */
918 initialize_one_kill(mykill);
919 #ifdef HAVE_REGEX_H
920 mykill->use_extended = use_e_regex;
921 #endif
922 /* now read in the killfile and parse it */
923 if((fptr = fopen(full_path(ignore_prefix, FP_DATADIR, fname), "r")) == NULL) {
924 MyPerror(full_path(ignore_prefix, FP_DATADIR, fname));
925 retval = RETVAL_ERROR;
926 }
927 else {
928 if(debug == TRUE) {
929 do_debug("Pass 3 kill file: %s\n", full_path(ignore_prefix, FP_DATADIR, fname));
930 do_debug("Pass 3 options: group=%s, use_extended_regex=%s, ignore_prefix=%s\n",
931 group, true_str(use_e_regex), true_str(ignore_prefix));
932 }
933 while(fgets(buf, MAXLINLEN, fptr) != NULL) {
934 buf[MAXLINLEN] = '\0'; /* just in case */
935
936 i = strlen(buf);
937 /* strip nls off so they don't get added to regex scan, etc..*/
938 if(buf[i-1] == '\n') {
939 buf[i-1] = '\0';
940 }
941 if(debug == TRUE) {
942 do_debug("pass 3 kill file line: %s\n", buf);
943 }
944 if(buf[0] != KILLFILE_COMMENT_CHAR) {
945 /* skip any comment lines */
946 match = FALSE;
947 for(i = 0 ; i < NR_PARAMS; i++) {
948 if(strncmp(buf, Params[i].name, (size_t) Params[i].len) == 0) {
949 match = TRUE; /* so don't try header field scan later */
950 switch(i) {
951 case PARAM_HILINE:
952 (void) sscanf(&buf[Params[PARAM_HILINE].len], "%d", &(mykill->hilines));
953 break;
954 case PARAM_LOWLINE:
955 (void) sscanf(&buf[Params[PARAM_LOWLINE].len], "%d", &(mykill->lowlines));
956 break;
957 case PARAM_NRGRPS:
958 (void) sscanf(&buf[Params[PARAM_NRGRPS].len], "%d", &(mykill->maxgrps));
959 break;
960 case PARAM_NRXREF:
961 (void) sscanf(&buf[Params[PARAM_NRXREF].len], "%d", &(mykill->maxxref));
962 break;
963 case PARAM_QUOTE:
964 if(buf[Params[PARAM_QUOTE].len] == '\0') {
965 error_log(ERRLOG_REPORT, "%s\n", killf_phrases[6], NULL);
966 }
967 else {
968 mykill->quote = buf[Params[PARAM_QUOTE].len];
969 }
970 break;
971 case PARAM_NONREGEX:
972 if(buf[Params[PARAM_NONREGEX].len] == '\0') {
973 error_log(ERRLOG_REPORT, "%s\n", killf_phrases[12], NULL);
974 }
975 else {
976 mykill->non_regex = buf[Params[PARAM_NONREGEX].len];
977 }
978 break;
979 case PARAM_HDRSCAN:
980 if(buf[Params[PARAM_HDRSCAN].len] == '\0') {
981 error_log(ERRLOG_REPORT, "%s\n", killf_phrases[7], NULL);
982 }
983 else {
984 if((curr = regex_scan(buf, mykill->quote, debug, use_e_regex, mykill->non_regex)) != NULL) {
985 add_to_linkedlist(&(mykill->header), curr);
986 }
987 }
988 break;
989 case PARAM_BODY:
990 if(buf[Params[PARAM_BODY].len] == '\0') {
991 error_log(ERRLOG_REPORT, "%s\n", killf_phrases[10], NULL);
992 }
993 else {
994 if((curr = regex_scan(buf, mykill->quote, debug, use_e_regex, mykill->non_regex)) != NULL) {
995 add_to_linkedlist(&(mykill->body), curr);
996 }
997 }
998 break;
999 case PARAM_BODYBIG:
1000 (void) sscanf(&buf[Params[PARAM_BODYBIG].len], "%lu", &(mykill->bodybig));
1001 break;
1002 case PARAM_BODYSMALL:
1003 (void) sscanf(&buf[Params[PARAM_BODYSMALL].len], "%lu", &(mykill->bodysmall));
1004 break;
1005 case PARAM_E_REGEX:
1006 /* in case specified for this file only */
1007 use_e_regex = TRUE;
1008 #ifdef HAVE_REGEX_H
1009 mykill->use_extended = TRUE; /* save for printing in debug */
1010 #endif
1011 break;
1012 default: /* handle all other lines aka do nothing*/
1013 break;
1014
1015 }
1016 }
1017 }
1018 if(match == FALSE) {
1019 /* it's a different line in the header add to linked-list */
1020 if((curr = regex_scan(buf, mykill->quote, debug, use_e_regex, mykill->non_regex)) != NULL) {
1021 add_to_linkedlist(&(mykill->list), curr);
1022 }
1023 }
1024 } /* comment line stuff */
1025 }
1026 (void) fclose(fptr);
1027 /* check for an empty killfile */
1028 if(mykill->hilines == 0 && mykill->lowlines == 0 && mykill->maxgrps == 0 && mykill->bodybig == 0 && mykill->bodysmall == 0 && mykill->header == NULL && mykill->list == NULL && mykill->body == NULL && mykill->maxxref == 0) {
1029 retval = RETVAL_EMPTYKILL;
1030 }
1031 }
1032 return retval;
1033 }
1034 /*---------------------------------------------------------------------------------------------*/
1035 void add_to_linkedlist(pmy_regex *head_ptr, pmy_regex addon) {
1036
1037 /* this routine adds a pointer the end of a linked list */
1038 pmy_regex curr;
1039 if(*head_ptr == NULL) {
1040 /* put on top of list */
1041 *head_ptr = addon;
1042 }
1043 else {
1044 curr = *head_ptr;
1045 while(curr->next != NULL) {
1046 curr = curr->next;
1047 }
1048 curr->next = addon;
1049 }
1050 }
1051 /*----------------------------------------------------------------------------------*/
1052 /* scan a line and build the compiled regex pointers to call regexex() with */
1053 /* ---------------------------------------------------------------------------------*/
1054 pmy_regex regex_scan(char *linein, char quotechar, int debug, int use_e_regex, char non_regex) {
1055
1056 char *tptr, *startline;
1057 int len,x,y, case_sens = FALSE, flags = FALSE;
1058 #ifdef HAVE_REGEX_H
1059 char errmsg[256];
1060 int i,j, useregex = TRUE;
1061 #endif
1062
1063 pmy_regex which = NULL;
1064 int err = FALSE;
1065
1066 if(linein != NULL) {
1067 /* first find the : in the line to skip the parameter part */
1068 tptr = linein;
1069 while(*tptr != '\0' && *tptr != ':') {
1070 tptr++;
1071 }
1072 startline = tptr+1;
1073 len = startline - linein;
1074
1075 /* do we treat this string as a non-regex?? */
1076 if(*startline == non_regex) {
1077 startline++;
1078 #ifdef HAVE_REGEX_H
1079 useregex = FALSE;
1080 #endif
1081 }
1082 /* case sensitive search?? */
1083 if(*startline == quotechar) {
1084 startline++;
1085 case_sens = TRUE;
1086 }
1087 #ifdef HAVE_REGEX_H
1088 if(useregex == TRUE) {
1089 flags = REG_NOSUB;
1090 if(case_sens == FALSE) {
1091 flags |= REG_ICASE;
1092 }
1093 if(use_e_regex == TRUE) {
1094 flags |= REG_EXTENDED;
1095 }
1096 useregex = FALSE;
1097 /* test to see whether or not we need to use regex */
1098 for(i = 0; i < strlen(regex_chars) && useregex != TRUE; i++) {
1099 for(j = 0 ; j < strlen(startline)&& useregex != TRUE; j++) {
1100 if(startline[j] == regex_chars[i]) {
1101 useregex = TRUE;
1102 }
1103 }
1104 }
1105 }
1106
1107 #endif
1108 /* now count each of em, so that can alloc my array of regex_t */
1109 if(*tptr != '\0') {
1110 /* now alloc memory */
1111
1112 if((which = malloc(sizeof (my_regex))) == NULL) {
1113 error_log(ERRLOG_REPORT, killf_phrases[5], NULL);
1114 }
1115 else {
1116 /* first save the string for later printing, if necessary */
1117 if((which->string = malloc(strlen(startline)+1)) == NULL) {
1118 err = TRUE;
1119 error_log(ERRLOG_REPORT, killf_phrases[5], NULL);
1120 }
1121 else {
1122 strcpy(which->string,startline);
1123 which->next = NULL; /* initialize */
1124 which->case_sensitive = case_sens;
1125 #ifdef HAVE_REGEX_H
1126 which->ptrs = NULL; /* just to be on safe side */
1127 #endif
1128 if((which->header=calloc(sizeof(char), len+1)) == NULL) {
1129 error_log(ERRLOG_REPORT, killf_phrases[5], NULL);
1130 err = TRUE;
1131 }
1132 else {
1133 strncpy(which->header, linein, len);
1134 which->header[len] = '\0'; /* just in case */
1135 #ifdef HAVE_REGEX_H
1136 if(useregex == TRUE) {
1137 if((which->ptrs = malloc(sizeof(regex_t))) == NULL) {
1138 error_log(ERRLOG_REPORT, killf_phrases[5], NULL);
1139 }
1140 else {
1141 if(debug == TRUE) {
1142 do_debug("Regcomping -%s-\n", startline);
1143 }
1144 if((err = regcomp(which->ptrs, startline, flags)) != 0) {
1145 /* whoops */
1146 regerror(err, which->ptrs, errmsg, sizeof(errmsg));
1147 error_log(ERRLOG_REPORT, killf_phrases[11], startline, errmsg, NULL);
1148 err= TRUE;
1149 }
1150 }
1151 }
1152 else {
1153 #endif
1154 /* not using regex, fill in skiparray */
1155 /* first fill in max skip for all chars (len of string) */
1156 /* See Algorithms/Sedgewick pg 287-289 for explanation */
1157 y=strlen(which->string);
1158
1159 for(x=0;x<sizeof(which->skiparray);x++) {
1160 which->skiparray[x] = y;
1161 }
1162 /* now go back and fill in those in our search string */
1163 if(case_sens == FALSE) {
1164 /* case-insensitive search */
1165 for(x=0;x<y;x++) {
1166 /* have to match both upper and lower case */
1167 char xx;
1168 xx = which->string[x];
1169 which->skiparray[(unsigned char) toupper(xx)] = (y-1)-x;
1170 which->skiparray[(unsigned char) tolower(xx)] = (y-1)-x;
1171 }
1172 }
1173 else {
1174 for(x=1;x<y;x++) {
1175 which->skiparray[(unsigned char) which->string[x]] = (y-1)-x;
1176 }
1177 }
1178
1179
1180 #ifdef HAVE_REGEX_H
1181 }
1182 #endif
1183 }
1184 }
1185 }
1186
1187 }
1188 }
1189 if(which != NULL && err == TRUE) {
1190 /* error, free up everything */
1191 #ifdef HAVE_REGEX_H
1192 if(which->ptrs != NULL) {
1193 free(which->ptrs);
1194 }
1195 #endif
1196 if(which->string != NULL) {
1197 free(which->string);
1198 }
1199 if(which->header != NULL) {
1200 free(which->header);
1201 }
1202 if(which != NULL) {
1203 free(which);
1204 which = NULL;
1205 }
1206 }
1207
1208 return which;
1209 }
1210 /*------------------------------------------------------------------------------------*/
1211 int regex_check(char *headerbuf, pmy_regex expr, int debug) {
1212 int match = FALSE;
1213 char *startline, *endline;
1214
1215 if(expr->header != NULL) {
1216 if((startline = strstr(headerbuf, expr->header)) != NULL) {
1217 endline = strchr(startline, '\n');
1218 /* end this line, so we only search the right header line */
1219 if(endline != NULL) {
1220 *endline = '\0';
1221 }
1222 /* the +strlen(expr->header) so the header field and the space */
1223 /* immediately following it aren't included in the search */
1224 if(debug == TRUE) {
1225 do_debug("checking -%s- for -%s-\n", startline+strlen(expr->header)+1,
1226 expr->string);
1227 }
1228 #ifdef HAVE_REGEX_H
1229 if(expr->ptrs != NULL) {
1230
1231
1232 if(regexec(expr->ptrs, startline+strlen(expr->header)+1, 0, NULL, 0) == 0) {
1233 match = TRUE;
1234 }
1235 }
1236 else {
1237 #endif
1238 match = find_string(debug, expr, startline+strlen(expr->header)+1);
1239 #ifdef HAVE_REGEX_H
1240 }
1241 #endif
1242 /* put the nl back on that we deleted */
1243 if(endline != NULL) {
1244 *endline = '\n';
1245 }
1246 }
1247 }
1248 if(debug== TRUE) {
1249 do_debug("Returning match=%s\n", (match == TRUE) ? "True" : "False");
1250 }
1251
1252 return match;
1253 }
1254 /*------------------------------------------------------------------------------------*/
1255 int regex_block(char *what, pmy_regex where, int debug) {
1256
1257 /* find a string in a block */
1258 int match = FALSE;
1259
1260 if(debug == TRUE && where->string != NULL) {
1261 do_debug("Checking for -%s-\n", where->string);
1262 }
1263 #ifdef HAVE_REGEX_H
1264 if(where->ptrs != NULL) {
1265 if(regexec(where->ptrs, what, 0, NULL, 0) == 0) {
1266 match = TRUE;
1267 }
1268 }
1269 else {
1270 #endif
1271 match = find_string(debug, where, what);
1272 #ifdef HAVE_REGEX_H
1273 }
1274 #endif
1275 return match;
1276 }
1277 /*---------------------------------------------------------------------------------------------*/
1278 int find_string(int debug, pmy_regex expr, char *str) {
1279
1280 /* the search mechanism is based on the Boyer-Moor Algorithms (pg 286- of Algorithms book) */
1281 int match = FALSE;
1282 char *ptr; /* pointer to pattern */
1283 int lenp; /* length of pattern */
1284 int lens; /* length of string we are searching */
1285 int i; /* current location in string */
1286 int j; /* current location in pattern */
1287 int t; /* value of skip array for string location */
1288
1289 ptr = expr->string;
1290 lenp = strlen(ptr);
1291 lens = strlen(str);
1292
1293
1294 if(expr->case_sensitive == TRUE ) {
1295 /* do case-sensitive search */
1296 if(debug == TRUE) {
1297 do_debug("Case-sensitive search for %s\n", ptr);
1298 }
1299 i = j = lenp-1;
1300 do {
1301 if(str[i] == ptr[j]) {
1302 i--;
1303 j--;
1304 }
1305 else {
1306 t = expr->skiparray[(unsigned char) str[i]];
1307 i += ( lenp -j > t) ? (lenp - j) : t;
1308 j = lenp - 1;
1309 }
1310 } while( j >= 0 && i < lens);
1311 if(j < 0) {
1312 match = TRUE;
1313 }
1314
1315 }
1316 else {
1317 /* do case-insensitive search */
1318 if(debug == TRUE ) {
1319 do_debug("Case-insensitive search for --%s--\n", ptr);
1320 }
1321 i = j = lenp-1;
1322 do {
1323 if(tolower(str[i]) == tolower(ptr[j])) {
1324 i--;
1325 j--;
1326 }
1327 else {
1328 t = expr->skiparray[(unsigned char) str[i]];
1329 i += ( lenp -j > t) ? (lenp - j) : t;
1330 j = lenp - 1;
1331 }
1332 } while( j >= 0 && i < lens);
1333 if(j < 0) {
1334 match = TRUE;
1335 }
1336 }
1337 return match;
1338
1339 }
1340 /*------------------------------------------------------------------------------------*/
1341 void print_debug(PKillStruct master, const char *fname) {
1342 int i;
1343
1344 /* print out status of master killstruct to debug file */
1345 do_debug("--%s-- Master KillStruct\n",fname);
1346 do_debug("logyn=%s\n",true_str(master->logyn));
1347 do_debug("grp_override=%s\n",true_str(master->grp_override));
1348 do_debug("tie_delete=%s\n",true_str(master->tie_delete));
1349 do_debug("totgrps=%d\n", master->totgrps);
1350 do_debug("ignore_postfix=%s\n",true_str(master->ignore_postfix));
1351 do_debug("use_extended_regex=%s\n", true_str(master->use_extended_regex));
1352 do_debug("xover_long_long=%s\n", true_str(master->xover_log_long));
1353
1354 do_debug("Master kill group");
1355 debug_one_kill(&(master->master));
1356
1357 for(i = 0 ; i < master->totgrps ; i++ ) {
1358 do_debug("Group %d = %s\n", i, master->grps[i].group);
1359 do_debug("--delkeep =%s\n", (master->grps[i].delkeep == DELKEEP_KEEP) ? "keep" : "delete");
1360 debug_one_kill(&(master->grps[i].match));
1361
1362 }
1363 do_debug("--%s-- End of Killstruct\n", fname);
1364 }
1365 /*------------------------------------------------------------------------*/
1366 void debug_one_kill(POneKill ptr) {
1367 pmy_regex temp;
1368
1369 do_debug("--hilines =%d\n", ptr->hilines);
1370 do_debug("--lowlines=%d\n", ptr->lowlines);
1371 do_debug("--maxgrps=%d\n", ptr->maxgrps);
1372 do_debug("--maxxref=%d\n", ptr->maxxref);
1373 do_debug("--bodysize>%lu\n", ptr->bodybig);
1374 do_debug("--bodysize<%lu\n", ptr->bodysmall);
1375 do_debug("--quote=%c\n", ptr->quote);
1376 do_debug("--non_regex=%c\n", ptr->non_regex);
1377 #ifdef HAVE_REGEX_H
1378 do_debug("--use_extended_regex=%s\n", true_str(ptr->use_extended));
1379 #endif
1380 temp= ptr->header;
1381 while(temp != NULL) {
1382 #ifdef HAVE_REGEX_H
1383 do_debug("--header scan is %sregex\n", (temp->ptrs == NULL) ? "non-" : "");
1384 #endif
1385 do_debug("--Scan is %scase-sensitive\n", (temp->case_sensitive == TRUE) ? "" : "non-");
1386 if(temp->string != NULL) {
1387 do_debug("--header scan=%s\n", temp->string);
1388 }
1389 temp = temp->next;
1390 }
1391 temp = ptr->body;
1392 while(temp != NULL) {
1393 #ifdef HAVE_REGEX_H
1394 do_debug("--body scan is %sregex\n", (temp->ptrs == NULL) ? "non-" : "");
1395 #endif
1396 do_debug("--Scan is %scase-sensitive\n", (temp->case_sensitive == TRUE) ? "" : "non-");
1397 if(temp->string != NULL) {
1398 do_debug("--body scan=%s\n", temp->string);
1399 }
1400 temp = temp->next;
1401 }
1402 temp = ptr->list;
1403 while(temp != NULL) {
1404 #ifdef HAVE_REGEX_H
1405 do_debug("--header match is %sregex\n", (temp->ptrs == NULL) ? "non-" : "");
1406 #endif
1407 do_debug("--Scan is %scase-sensitive\n", (temp->case_sensitive == TRUE) ? "" : "non-");
1408 do_debug("--header match= %s %s\n", temp->header, temp->string);
1409 temp = temp->next;
1410 }
1411 do_debug("--end of Killfile Group--\n");
1412 }
1413
1414