home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Unix System Administration Handbook 1997 October
/
usah_oct97.iso
/
news
/
nn.tar
/
nn-6.5.1
/
kill.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-04-29
|
24KB
|
1,053 lines
/*
* (c) Copyright 1990, Kim Fabricius Storm. All rights reserved.
*
* Kill file handling
*/
#include "config.h"
#include "keymap.h"
#include "nn_term.h"
#include "regexp.h"
/* prototypes further down */
export int killed_articles;
export int dflt_kill_select = 30;
export int kill_file_loaded = 0;
export int kill_debug = 0;
export int kill_ref_count = 0;
extern char *temp_file;
import char delayed_msg[];
char KILL_FILE[] = "kill";
char COMPILED_KILL[] = "KILL.COMP";
#define COMP_KILL_MAGIC 0x4b694c6f /* KiLo */
/*
* kill flags
*/
#define COMP_KILL_ENTRY 0x80000000
#define GROUP_REGEXP 0x01000000
#define GROUP_REGEXP_HDR 0x02000000
#define AND_MATCH 0x00020000
#define OR_MATCH 0x00010000
#define KILL_CASE_MATCH 0x00000100
#define KILL_ON_REGEXP 0x00000200
#define KILL_UNLESS_MATCH 0x00000400
#define AUTO_KILL 0x00000001
#define AUTO_SELECT 0x00000002
#define ON_SUBJECT 0x00000004
#define ON_SENDER 0x00000008
#define ON_FOLLOW_UP 0x00000010
#define ON_ANY_REFERENCES 0x00000020
#define ON_NOT_FOLLOW_UP 0x00000040
/*
* external flag representation
*/
#define EXT_AUTO_KILL '!'
#define EXT_AUTO_SELECT '+'
#define EXT_KILL_UNLESS_MATCH '~'
#define EXT_ON_FOLLOW_UP '>'
#define EXT_ON_NOT_FOLLOW_UP '<'
#define EXT_ON_ANY_REFERENCES 'a'
#define EXT_ON_SUBJECT 's'
#define EXT_ON_SENDER 'n'
#define EXT_KILL_CASE_MATCH '='
#define EXT_KILL_ON_REGEXP '/'
#define EXT_AND_MATCH '&'
#define EXT_OR_MATCH '|'
/*
* period = nnn DAYS
*/
#define DAYS * 24 * 60 * 60
/*
* kill_article
*
* return 1 to kill article, 0 to include it
*/
typedef struct kill_list_entry {
flag_type kill_flag;
char *kill_pattern;
regexp *kill_regexp;
struct kill_list_entry *next_kill;
} kill_list_entry;
static kill_list_entry *kill_tab;
static char *kill_patterns;
static kill_list_entry *global_kill_list = NULL;
static kill_list_entry latest_kl_entry;
typedef struct {
regexp *group_regexp;
kill_list_entry *kill_entry;
} kill_group_regexp;
static kill_group_regexp *group_regexp_table = NULL;
static int regexp_table_size = 0;
static kill_list_entry *regexp_kill_list = NULL;
static group_header *current_kill_group = NULL;
/* kill.c */
static void build_regexp_kill __APROTO((void));
static kill_list_entry *exec_kill __APROTO((register kill_list_entry *kl, register article_header *ah, int *unlessp, int do_kill, int do_select));
static void fput_pattern __APROTO((register char *p, register FILE *f));
static char *get_pattern __APROTO((register char *p, int *lenp, int more));
static compile_kill_file __APROTO((void));
static void free_kill_list __APROTO((register kill_list_entry *kl));
static print_kill __APROTO((register kill_list_entry *kl));
/*
* Build regexp_kill_list for current_group
*/
static void
build_regexp_kill()
{
register kill_group_regexp *tb;
register int n, used_last;
register char *name;
regexp_kill_list = NULL;
current_kill_group = current_group;
name = current_group->group_name;
used_last = 0; /* get AND_MATCH/OR_MATCH for free */
for (n = regexp_table_size, tb = group_regexp_table; --n >= 0; tb++) {
if (tb->group_regexp != NULL) {
used_last = 0;
if (!regexec(tb->group_regexp, name)) continue;
} else
if (!used_last) continue;
tb->kill_entry->next_kill = regexp_kill_list;
regexp_kill_list = tb->kill_entry;
used_last = 1;
}
}
/*
* execute kill patterns on article
*/
static kill_list_entry *exec_kill(kl, ah, unlessp, do_kill, do_select)
register kill_list_entry *kl;
register article_header *ah;
int *unlessp, do_kill, do_select;
{
register flag_type flag;
register char *string;
for ( ; kl != NULL; kl = kl->next_kill) {
flag = kl->kill_flag;
if (do_select && (flag & AUTO_SELECT) == 0) goto failed;
if (do_kill && (flag & AUTO_KILL) == 0) goto failed;
if (kill_debug && print_kill(kl) < 0) kill_debug = 0;
if (flag & KILL_UNLESS_MATCH)
*unlessp = 1;
if (flag & ON_ANY_REFERENCES) {
if (ah->replies & 0x7f) goto match;
goto failed;
}
if (flag & ON_SUBJECT) {
if (flag & ON_FOLLOW_UP) {
if ((ah->replies & 0x80) == 0) goto failed;
}
else if (flag & ON_NOT_FOLLOW_UP) {
if (ah->replies & 0x80) goto failed;
}
string = ah->subject;
} else
string = ah->sender;
if (flag & KILL_CASE_MATCH) {
if (flag & KILL_ON_REGEXP) {
if (regexec(kl->kill_regexp, string)) goto match;
} else
if (strcmp(kl->kill_pattern, string) == 0) goto match;
} else
if (flag & KILL_ON_REGEXP) {
if (regexec_fold(kl->kill_regexp, string)) goto match;
} else
if (strmatch_fold(kl->kill_pattern, string)) goto match;
failed:
if ((flag & AND_MATCH) == 0) continue;
do /* skip next */
kl = kl->next_kill;
while (kl && (kl->kill_flag & AND_MATCH));
if (kl) continue;
break;
match:
if (kill_debug) {
pg_next();
tprintf("%sMATCH\n", flag & AND_MATCH ? "PARTIAL " : "");
}
if (flag & AND_MATCH) continue;
break;
}
return kl;
}
int
kill_article(ah)
article_header *ah;
{
register kill_list_entry *kl;
int unless_match = 0;
if (kill_debug) {
clrdisp();
pg_init(0, 1);
pg_next();
so_printf("\1KILL: %s: %s%-.40s (%d)\1",
ah->sender, ah->replies & 0x80 ? "Re: " : "",
ah->subject, ah->replies & 0x7f);
}
kl = exec_kill((kill_list_entry *)(current_group->kill_list), ah,
&unless_match, 0, 0);
if (kl == NULL && group_regexp_table != NULL) {
if (current_kill_group != current_group) build_regexp_kill();
kl = exec_kill(regexp_kill_list, ah, &unless_match, 0, 0);
}
if (kl == NULL)
kl = exec_kill(global_kill_list, ah, &unless_match, 0, 0);
if (kl != NULL) {
if (kl->kill_flag & AUTO_KILL)
goto did_kill;
if (kl->kill_flag & AUTO_SELECT) {
ah->attr = A_AUTO_SELECT;
goto did_select;
}
goto no_kill;
}
if (unless_match) goto did_kill;
no_kill:
if (kill_ref_count && (int)(ah->replies & 0x7f) >= kill_ref_count) {
if (kill_debug) {
pg_next();
tprintf("REFERENCE COUNT (%d) >= %d\n",
ah->replies & 0x7f, kill_ref_count);
}
goto did_kill;
}
did_select:
if (kill_debug && pg_end() < 0) kill_debug = 0;
return 0;
did_kill:
if (kill_debug && pg_end() < 0) kill_debug = 0;
killed_articles++;
return 1;
}
int
auto_select_article(ah, do_select)
article_header *ah;
int do_select;
{
register kill_list_entry *kl;
int dummy;
if (do_select == 1) {
kl = ah->a_group ? (kill_list_entry *)(ah->a_group->kill_list) :
(kill_list_entry *)(current_group->kill_list);
kl = exec_kill(kl, ah, &dummy, !do_select, do_select);
if (kl == NULL && group_regexp_table != NULL) {
if (current_kill_group != current_group) build_regexp_kill();
kl = exec_kill(regexp_kill_list, ah, &dummy, !do_select, do_select);
}
if (kl == NULL)
kl = exec_kill(global_kill_list, ah, &dummy, !do_select, do_select);
} else {
kl = exec_kill(&latest_kl_entry, ah, &dummy, !do_select, do_select);
}
if (kl == NULL) return 0;
if (!do_select) killed_articles++;
return 1;
}
static void
fput_pattern(p, f)
register char *p;
register FILE *f;
{
register char c;
while ((c = *p++)) {
if (c == ':' || c == '\\') putc('\\', f);
putc(c, f);
}
}
static char *get_pattern(p, lenp, more)
register char *p;
int *lenp, more;
{
register char c, *q, *start;
start = q = p;
while ((c = *p++)) {
if (c == '\\') {
c = *p++;
if (c != ':' && c != '\\') *q++ = '\\';
*q++ = c;
continue;
}
if (more) {
if (c == ':') break;
if (c == NL) return NULL;
} else
if (c == NL) break;
*q++ = c;
}
if (c == NUL) return NULL;
*q++ = NUL;
*lenp = q - start;
return p;
}
void
enter_kill_file(gh, pattern, flag, days)
group_header *gh;
char *pattern;
register flag_type flag;
int days;
{
FILE *killf;
register kill_list_entry *kl;
regexp *re;
char *str;
str = copy_str(pattern);
if ((flag & KILL_CASE_MATCH) == 0)
fold_string(str);
if (flag & KILL_ON_REGEXP) {
re = regcomp(pattern);
if (re == NULL) return;
} else
re = NULL;
killf = open_file(relative(nn_directory, KILL_FILE), OPEN_APPEND);
if (killf == NULL) {
msg("cannot create kill file");
return;
}
if (days >= 0) {
if (days == 0) days = 30;
fprintf(killf, "%lu:", (long)(cur_time() + days DAYS));
}
if (gh) fputs(gh->group_name, killf);
fputc(':', killf);
if (flag & KILL_UNLESS_MATCH) fputc(EXT_KILL_UNLESS_MATCH, killf);
if (flag & AUTO_KILL) fputc(EXT_AUTO_KILL, killf);
if (flag & AUTO_SELECT) fputc(EXT_AUTO_SELECT, killf);
if (flag & ON_FOLLOW_UP) fputc(EXT_ON_FOLLOW_UP, killf);
if (flag & ON_NOT_FOLLOW_UP) fputc(EXT_ON_NOT_FOLLOW_UP, killf);
if (flag & ON_ANY_REFERENCES) fputc(EXT_ON_ANY_REFERENCES, killf);
if (flag & ON_SENDER) fputc(EXT_ON_SENDER, killf);
if (flag & ON_SUBJECT) fputc(EXT_ON_SUBJECT, killf);
if (flag & KILL_CASE_MATCH) fputc(EXT_KILL_CASE_MATCH, killf);
if (flag & KILL_ON_REGEXP) fputc(EXT_KILL_ON_REGEXP, killf);
fputc(':', killf);
fput_pattern(pattern, killf);
fputc(NL, killf);
fclose(killf);
rm_kill_file();
kl = newobj(kill_list_entry, 1);
latest_kl_entry.kill_pattern = kl->kill_pattern = str;
latest_kl_entry.kill_regexp = kl->kill_regexp = re;
latest_kl_entry.kill_flag = kl->kill_flag = flag;
latest_kl_entry.next_kill = NULL;
if (gh) {
kl->next_kill = (kill_list_entry *)(gh->kill_list);
gh->kill_list = (char *)kl;
} else {
kl->next_kill = global_kill_list;
global_kill_list = kl;
}
}
typedef struct {
group_number ck_group;
flag_type ck_flag;
long ck_pattern_index;
} comp_kill_entry;
typedef struct {
long ckh_magic;
time_t ckh_db_check;
off_t ckh_pattern_offset;
long ckh_pattern_size;
long ckh_entries;
long ckh_regexp_size;
} comp_kill_header;
int
kill_menu(ah)
article_header *ah;
{
int days;
register flag_type flag;
char *mode1, *mode2;
char *pattern, *dflt, *days_str, buffer[512];
group_header *gh;
days = dflt_kill_select % 100;
flag = (dflt_kill_select / 100) ? AUTO_SELECT : AUTO_KILL;
prompt("\1AUTO\1 (k)ill or (s)elect (CR => %s subject %d days) ",
flag == AUTO_KILL ? "Kill" : "Select", days);
switch (get_c()) {
case CR:
case NL:
if (ah == NULL) {
ah = get_menu_article();
if (ah == NULL) return -1;
}
strcpy(buffer, ah->subject);
enter_kill_file(current_group, buffer,
flag | ON_SUBJECT | KILL_CASE_MATCH, days);
msg("DONE");
return 1;
case 'k':
case 'K':
case '!':
flag = AUTO_KILL;
mode1 = "KILL";
break;
case 's':
case 'S':
case '+':
flag = AUTO_SELECT;
mode1 = "SELECT";
break;
default:
return -1;
}
prompt("\1AUTO %s\1 on (s)ubject or (n)ame (s)", mode1);
dflt = NULL;
switch (get_c()) {
case 'n':
case 'N':
flag |= ON_SENDER;
if (ah) dflt = ah->sender;
mode2 = "Name";
break;
case 's':
case 'S':
case SP:
case CR:
case NL:
flag |= ON_SUBJECT;
if (ah) dflt = ah->subject;
mode2 = "Subject";
break;
default:
return -1;
}
prompt("\1%s %s:\1 (%=/) ", mode1, mode2);
pattern = get_s(dflt, NONE, "%=/", NULL_FCT);
if (pattern == NULL) return -1;
if (*pattern == NUL || *pattern == '%' || *pattern == '=') {
if (dflt && *dflt)
pattern = dflt;
else {
if ((ah = get_menu_article()) == NULL) return -1;
pattern = (flag & ON_SUBJECT) ? ah->subject : ah->sender;
}
flag |= KILL_CASE_MATCH;
} else
if (*pattern == '/') {
prompt("\1%s %s\1 (regexp): ", mode1, mode2);
pattern = get_s(NONE, NONE, NONE, NULL_FCT);
if (pattern == NULL || *pattern == NUL) return -1;
flag |= KILL_ON_REGEXP;
}
strcpy(buffer, pattern);
pattern = buffer;
prompt("\1%s\1 in (g)roup '%s' or in (a)ll groups (g)",
mode1, current_group->group_name);
switch (get_c()) {
case 'g':
case 'G':
case SP:
case CR:
case NL:
gh = current_group;
break;
case 'A':
case 'a':
gh = NULL;
break;
default:
return -1;
}
prompt("\1Lifetime of entry in days\1 (p)ermanent (30) ");
days_str = get_s(" 30 days", NONE, "pP", NULL_FCT);
if (days_str == NULL) return -1;
if (*days_str == NUL) {
days_str = "30 days";
days = 30;
} else if (*days_str == 'p' || *days_str == 'P') {
days_str = "perm";
days = -1;
} else if (isdigit(*days_str)) {
days = atoi(days_str);
sprintf(days_str, "%d days", days);
} else {
ding();
return -1;
}
prompt("\1CONFIRM\1 %s %s %s%s: %-.35s%s ",
mode1, mode2, days_str,
(flag & KILL_CASE_MATCH) ? " exact" :
(flag & KILL_ON_REGEXP) ? " regexp" : "",
pattern, (int)strlen(pattern) > 35 ? "..." : "");
if (yes(0) <= 0) return -1;
enter_kill_file(gh, pattern, flag, days);
return (flag & AUTO_KILL) ? 1 : 0;
}
static int
compile_kill_file()
{
FILE *killf, *compf, *patternf, *dropf;
comp_kill_header header;
comp_kill_entry entry;
time_t now, age;
off_t cur_line_start;
char line[512];
register char *cp, *np;
register int c;
group_header *gh;
flag_type flag, fields[10];
int any_errors, nfield, nf, len;
any_errors = 0;
header.ckh_entries = header.ckh_regexp_size = 0;
killf = open_file(relative(nn_directory, KILL_FILE),
OPEN_READ | DONT_CREATE);
if (killf == NULL) return 0;
dropf = NULL;
compf = open_file(relative(nn_directory, COMPILED_KILL), OPEN_CREATE);
if (compf == NULL) goto err1;
new_temp_file();
if ((patternf = open_file(temp_file, OPEN_CREATE)) == NULL)
goto err2;
tprintf("\nCompiling kill file\n");
fseek(compf, (off_t)sizeof(header), 0);
now = cur_time();
next_entry:
for (;;) {
cur_line_start = ftell(killf);
if (fgets(line, 512, killf) == NULL) break;
cp = line;
while (*cp && isascii(*cp) && isspace(*cp)) cp++;
if (*cp == NUL || *cp == '#' || !isascii(*cp)) continue;
if ((np = strchr(cp, ':')) == NULL) goto bad_entry;
/* optional "age:" */
if (np != cp && isdigit(*cp)) {
*np++ = NUL;
age = (time_t)atol(cp);
if (age < now) goto drop_entry;
cp = np;
if ((np = strchr(cp, ':')) == NULL) goto bad_entry;
}
/* "group-name:" or "/regexp:" or ":" for all groups */
flag = COMP_KILL_ENTRY;
if (np == cp) {
entry.ck_group = -1;
np++;
} else {
*np++ = NUL;
if (*cp == '/') {
entry.ck_group = (long)ftell(patternf);
cp++;
len = strlen(cp) + 1;
if (fwrite(cp, sizeof(char), len, patternf) != len)
goto err3;
flag |= GROUP_REGEXP | GROUP_REGEXP_HDR ;
} else {
if ((gh = lookup(cp)) == NULL || (gh->master_flag & M_IGNORE_GROUP)) {
tprintf("Unknown/ignored group in kill file: %s\n", cp);
any_errors++;
goto drop_entry;
}
entry.ck_group = gh->group_num;
}
}
/* flags */
cp = np;
nfield = 0;
for (;;) {
switch (*cp++) {
case EXT_AND_MATCH:
case EXT_OR_MATCH:
fields[nfield++] = flag;
flag &= ~(AND_MATCH | ON_SUBJECT | ON_SENDER |
KILL_CASE_MATCH | KILL_ON_REGEXP |
GROUP_REGEXP_HDR);
flag |= (cp[-1] == EXT_AND_MATCH) ? AND_MATCH : OR_MATCH;
continue;
case EXT_AUTO_KILL:
flag |= AUTO_KILL;
continue;
case EXT_AUTO_SELECT:
flag |= AUTO_SELECT;
continue;
case EXT_ON_FOLLOW_UP:
flag |= ON_FOLLOW_UP;
continue;
case EXT_ON_NOT_FOLLOW_UP:
flag |= ON_NOT_FOLLOW_UP;
continue;
case EXT_ON_ANY_REFERENCES:
flag |= ON_ANY_REFERENCES;
continue;
case EXT_ON_SUBJECT:
flag |= ON_SUBJECT;
continue;
case EXT_ON_SENDER:
flag |= ON_SENDER;
continue;
case EXT_KILL_CASE_MATCH:
flag |= KILL_CASE_MATCH;
continue;
case EXT_KILL_UNLESS_MATCH:
flag |= KILL_UNLESS_MATCH;
continue;
case EXT_KILL_ON_REGEXP:
flag |= KILL_ON_REGEXP;
continue;
case ':':
break;
case NL:
goto bad_entry;
default:
tprintf("Ignored flag '%c' in kill file\n", cp[-1]);
any_errors++;
continue;
}
break;
}
fields[nfield++] = flag;
for (nf = 0; --nfield >= 0; nf++) {
entry.ck_flag = flag = fields[nf];
np = cp;
if ((cp = get_pattern(np, &len, nfield)) == NULL) goto bad_entry;
if ((flag & KILL_CASE_MATCH) == 0)
fold_string(np);
entry.ck_pattern_index = ftell(patternf);
if (fwrite((char *)&entry, sizeof(entry), 1, compf) != 1)
goto err3;
if (fwrite(np, sizeof(char), len, patternf) != len)
goto err3;
header.ckh_entries++;
if (flag & GROUP_REGEXP) header.ckh_regexp_size++;
}
}
header.ckh_pattern_size = ftell(patternf);
fclose(patternf);
patternf = open_file(temp_file, OPEN_READ | OPEN_UNLINK);
if (patternf == NULL) goto err2;
header.ckh_pattern_offset = ftell(compf);
while ((c = getc(patternf)) != EOF)
putc(c, compf);
fclose(patternf);
rewind(compf);
header.ckh_magic = COMP_KILL_MAGIC;
header.ckh_db_check = master.db_created;
if (fwrite((char *)&header, sizeof(header), 1, compf) != 1)
goto err2;
fclose(compf);
fclose(killf);
if (dropf != NULL) fclose(dropf);
if (any_errors) {
tputc(NL);
any_key(0);
}
return 1;
bad_entry:
tprintf("Incomplete kill file entry:\n%s", line);
fl;
any_errors++;
drop_entry:
if (dropf == NULL) {
dropf = open_file(relative(nn_directory, KILL_FILE),
OPEN_UPDATE | DONT_CREATE);
if (dropf == NULL) goto next_entry;
}
fseek(dropf, cur_line_start, 0);
fwrite("# ", sizeof(char), 2, dropf);
goto next_entry;
err3:
fclose(patternf);
unlink(temp_file);
err2:
fclose(compf);
rm_kill_file();
err1:
fclose(killf);
if (dropf != NULL) fclose(dropf);
msg("cannot compile kill file");
return 0;
}
int
init_kill()
{
FILE *killf;
comp_kill_header header;
comp_kill_entry entry;
register kill_list_entry *kl;
register kill_group_regexp *tb;
register group_header *gh;
time_t kill_age, comp_age;
register long n;
int first_try = 1;
Loop_Groups_Header(gh)
gh->kill_list = NULL;
kill_age = file_exist(relative(nn_directory, KILL_FILE), "frw");
if (kill_age == 0) return 0;
comp_age = file_exist(relative(nn_directory, COMPILED_KILL), "fr");
again:
if (comp_age < kill_age && !compile_kill_file()) return 0;
kill_tab = NULL;
kill_patterns = NULL;
group_regexp_table = NULL;
regexp_table_size = 0;
killf = open_file(relative(nn_directory, COMPILED_KILL), OPEN_READ);
if (killf == NULL) return 0;
if (fread((char *)&header, sizeof(header), 1, killf) != 1) goto err;
/* MAGIC check: format changed or using different hardware */
if (header.ckh_magic != COMP_KILL_MAGIC) goto err;
/* DB check: if database is rebuilt, group numbers may change */
if (header.ckh_db_check != master.db_created) goto err;
if (header.ckh_entries == 0) {
fclose(killf);
kill_file_loaded = 1;
return 0;
}
if (header.ckh_pattern_size > 0) {
kill_patterns = newstr(header.ckh_pattern_size);
fseek(killf, (off_t)(header.ckh_entries * sizeof(entry)), 1);
if (fread(kill_patterns, sizeof(char), (int)header.ckh_pattern_size, killf)
!= header.ckh_pattern_size) goto err;
} else
kill_patterns = newstr(1);
kill_tab = newobj(kill_list_entry, header.ckh_entries);
if ((regexp_table_size = header.ckh_regexp_size))
group_regexp_table = newobj(kill_group_regexp, header.ckh_regexp_size);
tb = group_regexp_table;
fseek(killf, (off_t)sizeof(header), 0);
for (n = header.ckh_entries, kl = kill_tab; --n >= 0; kl++) {
if (fread((char *)&entry, sizeof(entry), 1, killf) != 1) goto err;
if (header.ckh_pattern_size <= entry.ck_pattern_index ||
entry.ck_pattern_index < 0) goto err;
kl->kill_pattern = kill_patterns + entry.ck_pattern_index;
kl->kill_flag = entry.ck_flag;
if (kl->kill_flag & KILL_ON_REGEXP)
kl->kill_regexp = regcomp(kl->kill_pattern);
else
kl->kill_regexp = NULL;
if (kl->kill_flag & GROUP_REGEXP) {
if (kl->kill_flag & GROUP_REGEXP_HDR) {
if (header.ckh_pattern_size <= entry.ck_group ||
entry.ck_group < 0) goto err;
tb->group_regexp = regcomp(kill_patterns + entry.ck_group);
} else
tb->group_regexp = NULL;
tb->kill_entry = kl;
tb++;
} else
if (entry.ck_group >= 0) {
gh = ACTIVE_GROUP(entry.ck_group);
kl->next_kill = (kill_list_entry *)(gh->kill_list);
gh->kill_list = (char *)kl;
} else {
kl->next_kill = global_kill_list;
global_kill_list = kl;
}
}
fclose(killf);
kill_file_loaded = 1;
return 1;
err:
if (group_regexp_table != NULL) freeobj(group_regexp_table);
if (kill_patterns != NULL) freeobj(kill_patterns);
if (kill_tab != NULL) freeobj(kill_tab);
fclose(killf);
rm_kill_file();
if (first_try) {
first_try = 0;
comp_age = 0;
goto again;
}
strcpy(delayed_msg, "Error in compiled kill file (ignored)");
Loop_Groups_Header(gh)
gh->kill_list = NULL;
global_kill_list = NULL;
group_regexp_table = NULL;
return 0;
}
void
rm_kill_file()
{
unlink(relative(nn_directory, COMPILED_KILL));
}
static void
free_kill_list(kl)
register kill_list_entry *kl;
{
register kill_list_entry *nxt;
while (kl) {
nxt = kl->next_kill;
if (kl->kill_regexp != NULL) freeobj(kl->kill_regexp);
if ((kl->kill_flag & COMP_KILL_ENTRY) == 0) {
if (kl->kill_pattern != NULL) freeobj(kl->kill_pattern);
freeobj(kl);
}
kl = nxt;
}
}
void
free_kill_entries()
{
register group_header *gh;
register kill_group_regexp *tb;
register int n;
Loop_Groups_Header(gh)
if (gh->kill_list) {
free_kill_list((kill_list_entry *)(gh->kill_list));
gh->kill_list = NULL;
}
free_kill_list(global_kill_list);
global_kill_list = NULL;
if ((tb = group_regexp_table)) {
for (n = regexp_table_size; --n >= 0; tb++)
if (tb->group_regexp != NULL) freeobj(tb->group_regexp);
freeobj(group_regexp_table);
group_regexp_table = NULL;
}
if (kill_patterns != NULL) freeobj(kill_patterns);
if (kill_tab != NULL) freeobj(kill_tab);
kill_file_loaded = 0;
}
static flag_type pk_prev_and;
static int
print_kill(kl)
register kill_list_entry *kl;
{
register flag_type flag = kl->kill_flag;
if (pg_next() < 0) return -1;
if (pk_prev_and)
tprintf("\r AND ");
else
tprintf("\r%s%s ON ",
flag & AUTO_KILL ? "AUTO KILL" :
flag & AUTO_SELECT ? "AUTO SELECT" : "",
(flag & KILL_UNLESS_MATCH) == 0 ? "" :
flag & AUTO_KILL ? " UNLESS" :
flag & AUTO_SELECT ? "" : "KEEP");
tprintf("%s '%s%.35s'%s\n",
flag & ON_SUBJECT ? "SUBJECT" :
flag & ON_SENDER ? "NAME" :
flag & ON_ANY_REFERENCES ? "ANY REF" : "????",
flag & ON_NOT_FOLLOW_UP ? "!Re: " :
flag & ON_FOLLOW_UP ? "Re: " : "",
kl->kill_pattern,
flag & KILL_CASE_MATCH ?
(flag & KILL_ON_REGEXP ? " (re exact)" : " (exact)") :
(flag & KILL_ON_REGEXP ? " (re fold)" : ""));
pk_prev_and = flag & AND_MATCH;
return 0;
}
void
dump_kill_list()
{
register kill_list_entry *kl;
pg_init(0, 1);
pg_next();
kl = (kill_list_entry *)(current_group->kill_list);
if (current_kill_group != current_group) build_regexp_kill();
if (kl == NULL && regexp_kill_list == NULL) {
tprintf("No kill entries for %s", current_group->group_name);
} else {
so_printf("\1GROUP %s kill list entries\1", current_group->group_name);
pk_prev_and = 0;
for ( ; kl; kl = kl->next_kill)
if (print_kill(kl) < 0) goto out;
pk_prev_and = 0;
for (kl = regexp_kill_list ; kl; kl = kl->next_kill)
if (print_kill(kl) < 0) goto out;
if (pg_next() < 0) goto out;
}
if (pg_next() < 0) goto out;
so_printf("\1GLOBAL kill list entries:\1");
pk_prev_and = 0;
for (kl = global_kill_list; kl != NULL; kl = kl->next_kill)
if (print_kill(kl) < 0) goto out;
out:
pg_end();
}