This is kill.c in view mode; [Download] [Up]
/* * (c) Copyright 1990, Kim Fabricius Storm. All rights reserved. * * Kill file handling */ #include "config.h" #include "term.h" #include "regexp.h" 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; 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; /* * Build regexp_kill_list for current_group */ static 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(); printf("%sMATCH\n", flag & AND_MATCH ? "PARTIAL " : ""); } if (flag & AND_MATCH) continue; break; } return kl; } 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 && (ah->replies & 0x7f) >= kill_ref_count) { if (kill_debug) { pg_next(); printf("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; } 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 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; } 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; kill_menu(ah) article_header *ah; { int days; register flag_type flag; char *mode1, *mode2; char *pattern, *dflt, *days_str, buffer[512]; extern article_header *get_menu_article(); 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, strlen(pattern) > 35 ? "..." : ""); if (yes(0) <= 0) return -1; enter_kill_file(gh, pattern, flag, days); return (flag & AUTO_KILL) ? 1 : 0; } static 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]; extern char *temp_file; 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; 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; dropf = NULL; printf("\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)) { printf("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: printf("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) { putchar(NL); any_key(0); } return 1; bad_entry: printf("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; } 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; import char delayed_msg[]; 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; } rm_kill_file() { unlink(relative(nn_directory, COMPILED_KILL)); } static 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; } } 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 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) printf("\r AND "); else printf("\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"); printf("%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; } 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) { printf("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(); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.