rsalz@uunet.uu.net (Rich Salz) (06/23/89)
Submitted-by: storm@texas.dk (Kim F. Storm) Posting-number: Volume 19, Issue 67 Archive-name: nn/part06 #!/bin/sh # this is part 6 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file keymap.h continued # CurArch=6 if test ! -r s2_seq_.tmp then echo "Please unpack part 1 first!" exit 1; fi ( read Scheck if test "$Scheck" != $CurArch then echo "Please unpack part $Scheck next!" exit 1; else exit 0; fi ) < s2_seq_.tmp || exit 1 echo "x - Continuing file keymap.h" sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' >> keymap.h X#define K_FIRST_PAGE 0x002b /* first page */ X#define K_LAST_PAGE 0x002c /* last page */ X X#define K_GOTO_LINE 0x002d /* goto specific line */ X#define K_GOTO_PAGE 0x002e /* goto specific page */ X#define K_GOTO_MATCH 0x002f /* goto line matching regexp */ X#define K_NEXT_MATCH 0x0030 /* find next match */ X X#define K_PREVIOUS 0x0031 /* goto prev group or article */ X /* (no update is performed) */ X X /* more() SPECIFIC COMMANDS */ X X#define K_LEAVE_ARTICLE 0x0033 /* goto next article, mark current */ X#define K_NEXT_ARTICLE 0x0034 /* goto next article */ X#define K_NEXT_SUBJECT 0x0035 /* goto next subject */ X#define K_FULL_DIGEST 0x0036 /* show full digest */ X#define K_ROT13 0x0037 /* do rot13 */ X#define K_COMPRESS 0x0038 /* compress spaces */ X#define K_BACK_TO_MENU 0x0039 /* return to menu */ X X /* menu() SPECIFIC COMMANDS */ X X#define K_SELECT 0x0041 /* select current, move down */ X#define K_SELECT_INVERT 0x0042 /* invert all selections */ X#define K_SELECT_SUBJECT 0x0043 /* select all with same subject */ X#define K_SELECT_RANGE 0x0044 /* select range */ X#define K_AUTO_SELECT 0x0045 /* auto select from kill file */ X#define K_UNSELECT_ALL 0x0046 /* undo all selections */ X X#define K_LAYOUT 0x0049 /* change menu layout */ X X#define K_NEXT_GROUP_NO_UPDATE 0x004a /* goto next group, no update */ X#define K_READ_GROUP_UPDATE 0x004b /* read selected, then next group */ X#define K_READ_GROUP_THEN_SAME 0x004c /* read selected, then same group */ X X#define K_ADVANCE_GROUP 0x004d /* advance one group in sequence */ X#define K_BACK_GROUP 0x004e /* back-up one group in sequence */ X X#define K_PREVIEW 0x004f /* preview article */ X X#define K_MACRO 0x0100 /* call macro */ X#define K_ARTICLE_ID 0x0200 /* article id in lower part */ X X/* special keys returned by get_c() */ X X#define K_interrupt CTRL('G') X X#define K_up_arrow 0x0081 X#define K_down_arrow 0x0082 X#define K_left_arrow 0x0083 X#define K_right_arrow 0x0084 X X#define K_function(n) (0x0085 + n) X X X#define GETC_COMMAND 0x4000 /* bit set by get_c to return a command */ X X/* X * KEY MAP SIZE is: X * (128 normal chars) + (0200) + (4 arrow keys) + (10 function keys) X */ X X#define MULTI_KEYS (1 + 4 + 10) X#define KEY_MAP_SIZE (128 + MULTI_KEYS) X X X/* restrictions */ X X#define K_ONLY_MENU 0x0001 X#define K_ONLY_MORE 0x0002 X Xextern int menu_key_map[]; Xextern int more_key_map[]; X Xextern char global_key_map[]; NO_NEWS_IS_GOOD_NEWS echo "File keymap.h is complete" chmod 0644 keymap.h || echo "restore of keymap.h fails" set `wc -c keymap.h`;Sum=$1 if test "$Sum" != "4343" then echo original size 4343, current size $Sum;fi echo "x - extracting kill.c (Text)" sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > kill.c && X#include "config.h" X#include "term.h" X X/* X * kill file handling X */ X Xchar KILL_FILE[] = "kill"; Xchar COMPILED_KILL[] = "KILL.COMP"; X Xextern char *quick_match(); X X#define COMP_KILL_MAGIC 0x4b694c6c /* KiLl */ X X/* X * kill flags X */ X X#define AUTO_KILL 0x01 X#define AUTO_SELECT 0x00 /* pseudo flag */ X#define ON_SUBJECT 0x02 X#define ON_SENDER 0x00 /* pseudo flag */ X X#define KILL_MUST_MATCH 0x10 X X/* X * external flag representation X */ X X#define EXT_AUTO_KILL '!' X#define EXT_AUTO_SELECT '+' X#define EXT_ON_SUBJECT 's' X#define EXT_ON_SENDER 'n' X#define EXT_KILL_MUST_MATCH '=' X X/* X * period = nnn DAYS X */ X X#define DAYS * 24 * 60 * 60 X X X/* X * kill_article X * X * return 1 to kill article, 0 to include it X */ X Xtypedef struct kill_list_entry { X int kill_flag; X char *kill_pattern; X struct kill_list_entry *next_kill; X} kill_list_entry; X X Xstatic kill_list_entry dummy_kill = { X 0, (char *)NULL, (kill_list_entry *)NULL X}; Xstatic kill_list_entry *global_kill_list = &dummy_kill; Xstatic kill_list_entry *end_kill_list = &dummy_kill; X X Xkill_article(ah) Xarticle_header *ah; X{ X register kill_list_entry *kl; X char *string; X X end_kill_list->next_kill = (kill_list_entry *)(current_group->kill_list); X X kl = global_kill_list; X while (kl = kl->next_kill) { X if (kl->kill_flag & ON_SUBJECT) X string = ah->subject; X else X string = ah->sender; X X if (kl->kill_flag & KILL_MUST_MATCH) { X if (strcmp(kl->kill_pattern, string)) X continue; X } else X if (quick_match(string, kl->kill_pattern) == NULL) X continue; X X if (kl->kill_flag & AUTO_KILL) X return 1; X X ah->flag |= A_SELECT; X break; X } X X return 0; X} X X Xauto_select_article(ah) Xarticle_header *ah; X{ X register kill_list_entry *kl; X char *string; X X end_kill_list->next_kill = ah->a_group ? X (kill_list_entry *)(ah->a_group->kill_list) : X (kill_list_entry *)(current_group->kill_list); X X kl = global_kill_list; X while (kl = kl->next_kill) { X if (kl->kill_flag & AUTO_KILL) continue; X X if (kl->kill_flag & ON_SUBJECT) X string = ah->subject; X else X string = ah->sender; X X if (kl->kill_flag & KILL_MUST_MATCH) { X if (strcmp(kl->kill_pattern, string)) X continue; X } else X if (quick_match(string, kl->kill_pattern) == NULL) X continue; X return 1; X } X X return 0; X} X X X X X Xenter_kill_file(gh, pattern, flag, days) Xgroup_header *gh; Xchar *pattern; Xint flag; Xint days; X{ X time_t now; X FILE *killf; X register kill_list_entry *kl; X char *str; X X killf = open_file(relative(nn_directory, "kill"), OPEN_APPEND); X if (killf == NULL) { X msg("cannot create kill file"); X return; X } X X if (days >= 0) { X time(&now); X if (days == 0) days = 30; X fprintf(killf, "%lu:", (long)(now + days DAYS)); X } X X if (gh) fputs(gh->group_name, killf); X fputc(':', killf); X X fputc(flag & AUTO_KILL ? EXT_AUTO_KILL : EXT_AUTO_SELECT, killf); X fputc(flag & ON_SUBJECT ? EXT_ON_SUBJECT : EXT_ON_SENDER, killf); X if (flag & KILL_MUST_MATCH) fputc(EXT_KILL_MUST_MATCH, killf); X fputc(':', killf); X X fputs(pattern, killf); X fputc(NL, killf); X X fclose(killf); X rm_kill_file(); X X str = malloc(strlen(pattern) + 1); X mem_check(str, 1, "string"); X X strcpy(str, pattern); X X if ((flag & KILL_MUST_MATCH) == 0) X init_quick_match(str); X X kl = (kill_list_entry *)calloc(1, sizeof(kill_list_entry)); X mem_check(kl, 1, "kill list entry"); X X kl->kill_pattern = str; X kl->kill_flag = flag; X X if (gh) { X kl->next_kill = (kill_list_entry *)(gh->kill_list); X gh->kill_list = (char *)kl; X } else { X kl->next_kill = NULL; X end_kill_list->next_kill = kl; X end_kill_list = kl; X } X} X X Xtypedef struct { X group_number ck_group; X char ck_flag; X long ck_pattern_index; X} comp_kill_entry; X Xtypedef struct { X long ckh_magic; X off_t ckh_pattern_offset; X long ckh_pattern_size; X long ckh_entries; X} comp_kill_header; X X Xkill_menu(ah) Xarticle_header *ah; X{ X int flag, days; X char *mode1, *mode2; X char *pattern, *dflt, *days_str, buffer[512]; X extern article_header *get_menu_article(); X group_header *gh; X X prompt("\1AUTO\1 (K)ill or (S)elect (CR => Kill subject 1 month) "); X switch (get_c()) { X case CR: X case NL: X if (ah == NULL) { X ah = get_menu_article(); X if (ah == NULL) return; X } X X strcpy(buffer, ah->subject); X enter_kill_file(current_group, buffer, X AUTO_KILL | ON_SUBJECT | KILL_MUST_MATCH, 30); X msg("DONE"); X return; X X case 'k': X case 'K': X case '!': X flag = AUTO_KILL; X mode1 = "KILL"; X break; X case 's': X case 'S': X case '+': X flag = AUTO_SELECT; X mode1 = "SELECT"; X break; X default: X return; X } X X prompt("\1AUTO %s\1 on (S)ubject or (N)ame ?", mode1); X X dflt = NULL; X switch (get_c()) { X case 'n': X case 'N': X flag |= ON_SENDER; X if (ah) dflt = ah->sender; X mode2 = "Name"; X break; X case 's': X case 'S': X case SP: X case CR: X case NL: X flag |= ON_SUBJECT; X if (ah) dflt = ah->subject; X mode2 = "Subject"; X break; X default: X return; X } X X prompt("\1%s %s:\1", mode1, mode2); X X pattern = get_s(dflt, NONE, "%=", NO_COMPLETION); X if (pattern == NULL) return; X if (*pattern == NUL || *pattern == '%' || *pattern == '=') { X if (dflt && *dflt) X pattern = dflt; X else { X if ((ah = get_menu_article()) == NULL) return; X pattern = (flag & ON_SUBJECT) ? ah->subject : ah->sender; X } X flag |= KILL_MUST_MATCH; X } X X strcpy(buffer, pattern); X pattern = buffer; X X prompt("\1%s\1 in (G)roup '%s' or in (A)ll groups", X mode1, current_group->group_name); X X switch (get_c()) { X case 'g': X case 'G': X case SP: X case CR: X case NL: X gh = current_group; X break; X case 'A': X case 'a': X gh = NULL; X break; X default: X return; X } X X prompt("\1Lifetime of entry in days\1 (P)ermanent "); X days_str = get_s(" 30 days", NONE, "pP", NO_COMPLETION); X if (days_str == NULL) return; X X if (*days_str == NUL) { X days_str = "30 days"; X days = 30; X } else if (*days_str == 'p' || *days_str == 'P') { X days_str = "perm"; X days = -1; X } else if (isdigit(*days_str)) { X days = atoi(days_str); X sprintf(days_str, "%d days", days); X } else { X ding(); X return; X } X X prompt("\1CONFIRM\1 %s %s %s%s: %-.35s%s ", X mode1, mode2, days_str, X (flag & KILL_MUST_MATCH) ? " exact" : "", X pattern, strlen(pattern) > 35 ? "..." : ""); X if (yes(0) <= 0) return; X X enter_kill_file(gh, pattern, flag, days); X} X X X X Xinit_kill() X{ X FILE *killf; X comp_kill_header header; X comp_kill_entry entry; X kill_list_entry *kill_tab; X register group_header *gh; X register kill_list_entry *kl; X char *patterns; X time_t kill_age, comp_age; X register n; X X Loop_Groups_Header(gh) X gh->kill_list = NULL; X X kill_age = file_exist(relative(nn_directory, KILL_FILE), "frw"); X if (kill_age == 0) return 0; X X comp_age = file_exist(relative(nn_directory, COMPILED_KILL), "fr"); X if (comp_age < kill_age && !compile_kill_file()) return 0; X X killf = open_file(relative(nn_directory, COMPILED_KILL), OPEN_READ); X if (killf == NULL) return 0; X X if (fread(&header, sizeof(header), 1, killf) != 1) goto err; X if (header.ckh_magic != COMP_KILL_MAGIC) goto err; X X patterns = malloc(header.ckh_pattern_size); X mem_check(patterns, header.ckh_pattern_size, "kill bytes"); X X kill_tab = (kill_list_entry *) X calloc(header.ckh_entries, sizeof(kill_list_entry)); X mem_check(kill_tab, header.ckh_entries, "kill entries"); X X for (n = header.ckh_entries, kl = kill_tab; --n >= 0; kl++) { X if (fread(&entry, sizeof(entry), 1, killf) != 1) goto err; X X kl->kill_pattern = patterns + entry.ck_pattern_index; X kl->kill_flag = entry.ck_flag; X X if (entry.ck_group >= 0) { X gh = active_groups + entry.ck_group; X kl->next_kill = (kill_list_entry *)(gh->kill_list); X gh->kill_list = (char *)kl; X } else { X kl->next_kill = NULL; X end_kill_list->next_kill = kl; X end_kill_list = kl; X } X } X X if (fread(patterns, sizeof(char), header.ckh_pattern_size, killf) X != header.ckh_pattern_size) goto err; X X fclose(killf); X X return 1; X X err: X fclose(killf); X msg("Error in compiled kill file"); X rm_kill_file(); X X Loop_Groups_Header(gh) X gh->kill_list = NULL; X X end_kill_list = global_kill_list = &dummy_kill; X X return 0; X} X X Xstatic compile_kill_file() X{ X FILE *killf, *compf, *patternf, *dropf; X comp_kill_header header; X comp_kill_entry entry; X time_t now, age; X off_t cur_line_start; X char line[512]; X register char *cp, *np; X register int c; X group_header *gh; X int flag, any_errors; X extern char *temp_file; X X any_errors = 0; X header.ckh_entries = 0; X X killf = open_file(relative(nn_directory, KILL_FILE), X OPEN_READ | DONT_CREATE); X if (killf == NULL) return 0; X X compf = open_file(relative(nn_directory, COMPILED_KILL), OPEN_CREATE); X if (compf == NULL) goto err1; X X if ((patternf = open_file(temp_file, OPEN_CREATE)) == NULL) X goto err2; X X dropf = NULL; X X printf("\nCompiling kill file\n"); X X fseek(compf, (off_t)sizeof(header), 0); X X time(&now); X X next_entry: X X for (;;) { X cur_line_start = ftell(killf); X X if (fgets(line, 512, killf) == NULL) break; X X cp = line; X while (*cp && isascii(*cp) && isspace(*cp)) cp++; X if (*cp == NUL || *cp == '#' || !isascii(*cp)) continue; X X if ((np = strchr(cp, ':')) == NULL) goto bad_entry; X X /* optional "age:" */ X X if (np != cp && isdigit(*cp)) { X *np++ = NUL; X age = (time_t)atol(cp); X if (age < now) goto drop_entry; X cp = np; X if ((np = strchr(cp, ':')) == NULL) goto bad_entry; X } X X /* "group-name:" or ":" for all groups */ X X if (np == cp) { X entry.ck_group = -1; X np++; X } else { X *np++ = NUL; X if ((gh = lookup(cp)) == NULL) { X printf("Unknown group in kill file: %s\n", cp); X any_errors++; X goto drop_entry; X } X entry.ck_group = gh->group_num; X } X X /* flags */ X X cp = np; X flag = 0; X X for (;;) { X switch (*cp++) { X case EXT_AUTO_KILL: X flag |= AUTO_KILL; X continue; X case EXT_AUTO_SELECT: X flag |= AUTO_SELECT; X continue; X case EXT_ON_SUBJECT: X flag |= ON_SUBJECT; X continue; X case EXT_ON_SENDER: X flag |= ON_SENDER; X continue; X case EXT_KILL_MUST_MATCH: X flag |= KILL_MUST_MATCH; X continue; X case ':': X break; X case NL: X goto bad_entry; X default: X printf("Ignored flag '%c' in kill file\n", cp[-1]); X any_errors++; X continue; X } X break; X } X X entry.ck_flag = flag; X X if ((np = strchr(cp, NL)) == NULL) goto bad_entry; X X *np++ = NUL; X if ((flag & KILL_MUST_MATCH) == 0) X init_quick_match(cp); X X entry.ck_pattern_index = ftell(patternf); X X if (fwrite(&entry, sizeof(entry), 1, compf) != 1) X goto err3; X X if (fwrite(cp, sizeof(char), np - cp, patternf) != (np - cp)) X goto err3; X X header.ckh_entries++; X } X X header.ckh_pattern_size = ftell(patternf); X X fclose(patternf); X patternf = open_file(temp_file, OPEN_READ | OPEN_UNLINK); X if (patternf == NULL) goto err2; X X header.ckh_pattern_offset = ftell(compf); X X while ((c = getc(patternf)) != EOF) X putc(c, compf); X X fclose(patternf); X X rewind(compf); X X header.ckh_magic = COMP_KILL_MAGIC; X X if (fwrite(&header, sizeof(header), 1, compf) != 1) X goto err2; X X fclose(compf); X fclose(killf); X if (dropf != NULL) fclose(dropf); X X if (any_errors) { X putchar(NL); X any_key(0); X } X X return 1; X X bad_entry: X printf("Incomplete kill file entry:\n%s", line); X fl; X any_errors++; X X drop_entry: X if (dropf == NULL) { X dropf = open_file(relative(nn_directory, KILL_FILE), X OPEN_UPDATE | DONT_CREATE); X if (dropf == NULL) goto next_entry; X } X fseek(dropf, cur_line_start, 0); X fwrite("# ", sizeof(char), 2, dropf); X goto next_entry; X X err3: X fclose(patternf); X unlink(temp_file); X err2: X fclose(compf); X rm_kill_file(); X err1: X fclose(killf); X if (dropf != NULL) fclose(dropf); X X msg("cannot compile kill file"); X return 0; X} X X Xrm_kill_file() X{ X unlink(relative(nn_directory, COMPILED_KILL)); X} X X Xdump_kill_list() X{ X register kill_list_entry *kl; X X pg_init(0, 1); X X pg_next(); X so_printf("\1GLOBAL kill list entries:\1"); X X kl = end_kill_list->next_kill = NULL; X X kl = global_kill_list; X while (kl = kl->next_kill) X if (print_kill(kl) < 0) goto out; X X if (pg_next() < 0) goto out; X if (pg_next() < 0) goto out; X so_printf("\1GROUP %s kill list entries\1", current_group->group_name); X X kl = (kill_list_entry *)(current_group->kill_list); X while (kl) { X if (print_kill(kl) < 0) break; X kl = kl->next_kill; X } X X out: X X pg_end(); X} X X X Xprint_kill(kl) Xregister kill_list_entry *kl; X{ X if (pg_next() < 0) return -1; X X printf("\r%s ON %s '%.35s'%s\n", X kl->kill_flag & AUTO_KILL ? "KILL" : "SELECT", X kl->kill_flag & ON_SUBJECT ? "SUBJECT" : "NAME", X kl->kill_pattern, X kl->kill_flag & KILL_MUST_MATCH ? " (exact)" : ""); X X return 0; X} X NO_NEWS_IS_GOOD_NEWS chmod 0644 kill.c || echo "restore of kill.c fails" set `wc -c kill.c`;Sum=$1 if test "$Sum" != "13252" then echo original size 13252, current size $Sum;fi echo "x - extracting log_entry.c (Text)" sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > log_entry.c && X/* X * log_entry type string X * X * Enter a message in the Log. X */ X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X if (argc != 3) exit(1); X X init_global(0); X X if (log_entry(argv[1][0], "%s", argv[2]) == 0) X exit(1); X X nn_exit(0); X} X Xnn_exit(n) Xint n; X{ X exit(n); X} X Xuser_error() X{ X nn_exit(1); X} X NO_NEWS_IS_GOOD_NEWS chmod 0644 log_entry.c || echo "restore of log_entry.c fails" set `wc -c log_entry.c`;Sum=$1 if test "$Sum" != "320" then echo original size 320, current size $Sum;fi echo "x - extracting m-att3b.h (Text)" sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-att3b.h && X X/************** Machine (and compiler) dependent definitions. ************** X * X * Define appropriate types for the following ranges of integer X * variables. These are processor & compiler dependent, but the X * distributed definitions will probably work on most systems. X */ X X X X/* MACHINE TYPE DEFINED TYPE VALUE RANGE */ X Xtypedef unsigned char int8; /* 0 .. 255 */ Xtypedef short int16; /* -10,000 .. 10,000 */ Xtypedef long int32; /* -100,000 .. 100,000 */ Xtypedef unsigned long uint32; /* 0 .. 2^31-1 */ X X X/* X * Define NETWORK_BYTE_ORDER if the machine's int32's are X * already in network byte order, i.e. m68k based. X */ X X#define NETWORK_BYTE_ORDER /* */ NO_NEWS_IS_GOOD_NEWS chmod 0644 m-att3b.h || echo "restore of m-att3b.h fails" set `wc -c m-att3b.h`;Sum=$1 if test "$Sum" != "688" then echo original size 688, current size $Sum;fi echo "x - extracting m-dec3100.h (Text)" sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-dec3100.h && X/************** Machine (and compiler) dependent definitions. ************** X * X * This file is for a DECstation 3100, running Ultrix X */ X X/* MACHINE TYPE DEFINED TYPE VALUE RANGE */ X Xtypedef unsigned char int8; /* 0 .. 255 */ Xtypedef short int16; /* -10,000 .. 10,000 */ Xtypedef long int32; /* -100,000 .. 100,000 */ Xtypedef unsigned long uint32; /* 0 .. 2^31-1 */ X X#undef NO_VARARGS X X#ifdef NETWORK_DATABASE X#undef NETWORK_BYTE_ORDER X#include <netinet/in.h> X#endif /* NETWORK DATABASE */ NO_NEWS_IS_GOOD_NEWS chmod 0644 m-dec3100.h || echo "restore of m-dec3100.h fails" set `wc -c m-dec3100.h`;Sum=$1 if test "$Sum" != "519" then echo original size 519, current size $Sum;fi echo "x - extracting m-gould.h (Text)" sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-gould.h && X/************** Machine (and compiler) dependent definitions. ************** X * X * Define appropriate types for the following ranges of integer X * variables. These are processor & compiler dependent, but the X * distributed definitions will probably work on most systems. X */ X X X X/* MACHINE TYPE DEFINED TYPE VALUE RANGE */ X Xtypedef unsigned char int8; /* 0 .. 255 */ Xtypedef short int16; /* -10,000 .. 10,000 */ Xtypedef long int32; /* -100,000 .. 100,000 */ Xtypedef unsigned long uint32; /* 0 .. 2^31-1 */ X X/* X * GOULD/UTX has varargs.h but not v[s]printf() X */ X X#define NO_VARARGS X X X/* X * Not in network byte order on the GOULD X */ X X#undef NETWORK_BYTE_ORDER /* */ X#ifdef NETWORK_DATABASE X#include <netinet/in.h> X#endif NO_NEWS_IS_GOOD_NEWS chmod 0644 m-gould.h || echo "restore of m-gould.h fails" set `wc -c m-gould.h`;Sum=$1 if test "$Sum" != "751" then echo original size 751, current size $Sum;fi echo "x - extracting m-hp9000.h (Text)" sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-hp9000.h && X X/************** Machine (and compiler) dependent definitions. ************** X * X * This is for HP9000 Series 320 and 800 (at least) X */ X X X/* MACHINE TYPE DEFINED TYPE VALUE RANGE */ X Xtypedef unsigned char int8; /* 0 .. 255 */ Xtypedef short int16; /* -10,000 .. 10,000 */ Xtypedef long int32; /* -100,000 .. 100,000 */ Xtypedef unsigned long uint32; /* 0 .. 2^31-1 */ X X X/* X * Define NETWORK_BYTE_ORDER if the machine's int32's are X * already in network byte order, i.e. m68k based. X */ X X#define NETWORK_BYTE_ORDER /* */ NO_NEWS_IS_GOOD_NEWS chmod 0644 m-hp9000.h || echo "restore of m-hp9000.h fails" set `wc -c m-hp9000.h`;Sum=$1 if test "$Sum" != "550" then echo original size 550, current size $Sum;fi echo "x - extracting m-m680x0.h (Text)" sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-m680x0.h && X X/************** Machine (and compiler) dependent definitions. ************** X * X * These are for 680x0 based systems. X */ X X X X/* MACHINE TYPE DEFINED TYPE VALUE RANGE */ X Xtypedef unsigned char int8; /* 0 .. 255 */ Xtypedef short int16; /* -10,000 .. 10,000 */ Xtypedef long int32; /* -100,000 .. 100,000 */ Xtypedef unsigned long uint32; /* 0 .. 2^31-1 */ X X X/* X * Define NETWORK_BYTE_ORDER if the machine's int32's are X * already in network byte order, i.e. m68k based. X */ X X#define NETWORK_BYTE_ORDER /* */ NO_NEWS_IS_GOOD_NEWS chmod 0644 m-m680x0.h || echo "restore of m-m680x0.h fails" set `wc -c m-m680x0.h`;Sum=$1 if test "$Sum" != "534" then echo original size 534, current size $Sum;fi echo "x - extracting m-sparc.h (Text)" sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-sparc.h && X X/************** Machine (and compiler) dependent definitions. ************** X * X * Define appropriate types for the following ranges of integer X * variables. These are processor & compiler dependent, but the X * distributed definitions will probably work on most systems. X */ X X X X/* MACHINE TYPE DEFINED TYPE VALUE RANGE */ X Xtypedef unsigned char int8; /* 0 .. 255 */ Xtypedef short int16; /* -10,000 .. 10,000 */ Xtypedef long int32; /* -100,000 .. 100,000 */ Xtypedef unsigned long uint32; /* 0 .. 2^31-1 */ X X X X/* X * Define NETWORK_BYTE_ORDER if the machine's longs are X * already in network byte order. X */ X X#define NETWORK_BYTE_ORDER NO_NEWS_IS_GOOD_NEWS chmod 0644 m-sparc.h || echo "restore of m-sparc.h fails" set `wc -c m-sparc.h`;Sum=$1 if test "$Sum" != "664" then echo original size 664, current size $Sum;fi echo "x - extracting m-sun.h (Text)" sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-sun.h && X X/************** Machine (and compiler) dependent definitions. ************** X * X * Define appropriate types for the following ranges of integer X * variables. These are processor & compiler dependent, but the X * distributed definitions will probably work on most systems. X */ X X X X/* MACHINE TYPE DEFINED TYPE VALUE RANGE */ X Xtypedef unsigned char int8; /* 0 .. 255 */ Xtypedef short int16; /* -10,000 .. 10,000 */ Xtypedef long int32; /* -100,000 .. 100,000 */ Xtypedef unsigned long uint32; /* 0 .. 2^31-1 */ X X X X/* X * Define NETWORK_BYTE_ORDER if the machine's longs are X * already in network byte order. X */ X X#define NETWORK_BYTE_ORDER /* */ X NO_NEWS_IS_GOOD_NEWS chmod 0644 m-sun.h || echo "restore of m-sun.h fails" set `wc -c m-sun.h`;Sum=$1 if test "$Sum" != "671" then echo original size 671, current size $Sum;fi echo "x - extracting m-sun386i.h (Text)" sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-sun386i.h && X/************** Machine (and compiler) dependent definitions. ************** X * X * Define appropriate types for the following ranges of integer X * variables. These are processor & compiler dependent, but the X * distributed definitions will probably work on most systems. X */ X X X X/* MACHINE TYPE DEFINED TYPE VALUE RANGE */ X Xtypedef unsigned char int8; /* 0 .. 255 */ Xtypedef short int16; /* -10,000 .. 10,000 */ Xtypedef long int32; /* -100,000 .. 100,000 */ Xtypedef unsigned long uint32; /* 0 .. 2^31-1 */ X X X X/* X * Not in network byte order on the 386 X */ X X#undef NETWORK_BYTE_ORDER /* */ X#ifdef NETWORK_DATABASE X#include <netinet/in.h> X#endif NO_NEWS_IS_GOOD_NEWS chmod 0644 m-sun386i.h || echo "restore of m-sun386i.h fails" set `wc -c m-sun386i.h`;Sum=$1 if test "$Sum" != "673" then echo original size 673, current size $Sum;fi echo "x - extracting m-template.h (Text)" sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-template.h && X X/************** Machine (and compiler) dependent definitions. ************** X * X * Define appropriate types for the following ranges of integer X * variables. These are processor & compiler dependent, but the X * distributed definitions will probably work on most systems. X */ X X X X/* MACHINE TYPE DEFINED TYPE VALUE RANGE */ X Xtypedef unsigned char int8; /* 0 .. 255 */ Xtypedef short int16; /* -10,000 .. 10,000 */ Xtypedef long int32; /* -100,000 .. 100,000 */ Xtypedef unsigned long uint32; /* 0 .. 2^31-1 */ X X X/* X * Define NO_VARARGS if the varargs feature is not available X * X * Also define NO_VARARGS if the vprintf/vsprintf routines are not X * available (however, this will only by safe on some machines, like X * the VAX). X * X */ X X/* #define NO_VARARGS */ X X X X#ifdef NETWORK_DATABASE X X/* X * Define NETWORK_BYTE_ORDER if the machine's int32's are X * already in network byte order, i.e. m68k based. X */ X X#define NETWORK_BYTE_ORDER /* */ X X/* X * OTHERWISE provide the functions/macros ntohl/htonl to X * convert longs from and to network byte order X */ X X#ifndef NETWORK_BYTE_ORDER X X/* X * Include appropriate files or define macroes or functions (include them X * in data.c) to convert longs and shorts to and from network byte order. X */ X X/* X * This will work on most BSD based systems... X */ X X#include <netinet/in.h> X X/* X * Otherwise, define something appropriate below X */ X X#define htonl(l) ... /* host long to network long */ X#define ntohl(l) ... /* network long to host long */ X X#endif /* not NETWORK BYTE ORDER */ X X#endif /* NETWORK DATABASE */ NO_NEWS_IS_GOOD_NEWS chmod 0644 m-template.h || echo "restore of m-template.h fails" set `wc -c m-template.h`;Sum=$1 if test "$Sum" != "1577" then echo original size 1577, current size $Sum;fi echo "x - extracting m-vax.h (Text)" sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-vax.h && X X/************** Machine (and compiler) dependent definitions. ************** X * X * Define appropriate types for the following ranges of integer X * variables. These are processor & compiler dependent, but the X * distributed definitions will probably work on most systems. X */ X X X X/* MACHINE TYPE DEFINED TYPE VALUE RANGE */ X Xtypedef unsigned char int8; /* 0 .. 255 */ Xtypedef short int16; /* -10,000 .. 10,000 */ Xtypedef long int32; /* -100,000 .. 100,000 */ Xtypedef unsigned long uint32; /* 0 .. 2^31-1 */ X X X/* X * VAX/BSD has varargs.h but not v[s]printf() X */ X X#define NO_VARARGS X X X/* X * The VAX does not have longs in network byte order X */ X X#undef NETWORK_BYTE_ORDER /* we need to use ntohl/htonl */ X#ifdef NETWORK_DATABASE X#include <netinet/in.h> X#endif NO_NEWS_IS_GOOD_NEWS chmod 0644 m-vax.h || echo "restore of m-vax.h fails" set `wc -c m-vax.h`;Sum=$1 if test "$Sum" != "789" then echo original size 789, current size $Sum;fi echo "x - extracting macro.c (Text)" sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > macro.c && X#include "config.h" X#include "keymap.h" X#include "term.h" X Xexport int in_menu_mode = 0; Xexport int get_from_macro = 0; Xexport int macro_debug = 0; X X#define M_DUMMY 0 /* do nothing (end of branch) */ X X#define M_COMMAND 1 /* a command (get_c()) */ X#define M_KEY 2 /* a key stroke (get_c()) */ X#define M_STRING 3 /* a string (get_s()) */ X X#define M_INPUT 4 /* take input from keyboard (get_c/get_s) */ X X#define M_YES 5 /* answer yes to confirmation */ X#define M_NO 6 /* answer no to confirmation and break */ X /* -- if neither are present, take input */ X X#define M_PROMPT 8 /* prompt(...) */ X#define M_ECHO 9 /* msg(...) */ X X#define M_IS_MENU 10 /* in menu mode ? */ X#define M_IS_SHOW 11 /* in reading mode ? */ X#define M_IS_GROUP 12 /* are we in a news group ? */ X#define M_IS_FOLDER 13 /* are we in a folder ? */ X#define M_CONFIRM 14 /* ask for confirmation to procede */ X#define M_REJECT 15 /* ask for !confirmation to procede */ X#define M_VARTEST 16 /* test value of variable */ X#define M_BREAK 17 /* exit from macroes */ X#define M_RETURN 18 /* return from this macro */ X X Xstruct macro { X int m_type; /* entry type */ X union { X int mu_int; /* command or char */ X char *mu_string; /* string for get_s */ X struct macro *mu_branch; /* false conditional */ X } m_value; X struct macro *m_next; /* next macro element */ X}; X X#define m_int m_value.mu_int X#define m_string m_value.mu_string X#define m_branch m_value.mu_branch X X#define NMACRO 32 /* max number of macros */ X#define MSTACK 5 /* max nesting level */ X Xstatic struct macro *macro[NMACRO]; /* macro table */ X Xstatic struct macro *mstack[MSTACK]; /* macro stack */ Xstatic int cstack[MSTACK]; Xstatic int m_level = 0; X Xstatic struct macro *m = NULL; /* current macro */ Xstatic int no_advance = 0; X Xstatic int cur_m; X X#define MERROR ((struct macro *)1) X Xinit_macro() X{ X int n; X X for (n = 0; n < NMACRO; n++) X macro[n] = NULL; X} X Xstatic m_new(t) Xint t; X{ X struct macro *m1; X X m1 = (struct macro *)calloc(1, sizeof(struct macro)); X mem_check(m1, sizeof(struct macro), "for macro"); X X if (m == NULL) X m = macro[cur_m] = m1; X else { X m->m_next = m1; X m = m1; X } X m->m_type = t; X m->m_next = NULL; X} X X X/* X * Define macro "id" reading from file f until "end" X * X * Macro definition syntax: X * define <id> X * <body> X * end X */ X X Xm_define(id, f) Xchar *id; XFILE *f; X{ X char line[256], *lp, skip; X X if (id) { X cur_m = atoi(id); X if (cur_m < 0 || cur_m >= NMACRO) { X m_error("macro number out of range\n", id); X return 0; X } X } else { X for (cur_m = 0; cur_m < NMACRO; cur_m++) X if (macro[cur_m] == NULL) break; X if (cur_m == NMACRO) { X init_message("No unused macro numbers"); X return 0; X } X } X X if (f == NULL) { X clrdisp(); X printf("DEFINE MACRO %d -- END WITH 'end'\n\n\r", cur_m); X no_raw(); X f = stdin; X } X X m = NULL; X skip = 0; X X while (fgets(line, 256, f)) { X for (lp = line; *lp && isspace(*lp); lp++); X if (*lp == NUL) continue; X if (strncmp(lp, "end", 3) == 0) goto out; X if (!skip && parse_line(lp)) { X macro[cur_m] = NULL; X skip++; X } X } X X if (f != stdin) X m_error("end missing", (char *)NULL); X X out: X if (f == stdin) raw(); X m = NULL; X return 1; X} X Xstatic parse_line(lp) Xchar *lp; X{ X char *word; X struct macro *m1, *branch = NULL; X X while (*lp) { X if (*lp == '#') break; X X if (*lp == ':') { X m_new(M_COMMAND); X m->m_int = GETC_COMMAND | K_EXTENDED_CMD; X m_new(M_STRING); X m->m_string = copy_str(lp + 1); X break; X } X X if (*lp == '?') { X m_new(M_IS_MENU); X if (branch == NULL) { X m1 = m; X m_new(M_DUMMY); X branch = m; X m = m1; X } X m->m_branch = branch; X } X X word = lp; X if (*lp == '"') X do lp++; X while (*lp && *lp != '"'); X else X if (*lp == '\'') X do lp++; X while (*lp && *lp != '\''); X else X while (*lp && !isspace(*lp)) lp++; X if (*lp) { X *lp++ = NUL; X while (*lp && isspace(*lp)) lp++; X } X if (parse_word(word)) return 1; X } X X if (branch) { X m->m_next = branch; X m = branch; X } X return 0; X} X Xstatic parse_word(w) Xchar *w; X{ X int cmd; X register struct macro *m1; X X if (m && m->m_type == M_COMMAND && m->m_int == (GETC_COMMAND | K_MACRO)) { X if (isdigit(*w)) { X m->m_int |= atoi(w); X goto ok; X } X m_error("macro number missing", (char *)NULL); X return 1; X } X X if (*w == '"') { X if (m == NULL || (m->m_type != M_PROMPT && m->m_type != M_ECHO)) X m_new(M_STRING); X m->m_string = copy_str(w + 1); X goto ok; X } X X if (*w == '\'') { X m_new(M_KEY); X m->m_int = parse_key(w + 1); X goto ok; X } X X if (*w == '?') { X if (strchr(w, '=')) { X m->m_type = M_VARTEST; X m1 = m; X m_new(M_DUMMY); X m->m_branch = m1->m_branch; X m1->m_string = copy_str(w + 1); X goto ok; X } X X switch (w[1]) { X case 'f': /* ?folder */ X cmd = M_IS_FOLDER; X break; X case 'g': /* ?group */ X cmd = M_IS_GROUP; X break; X case 'm': /* ?menu */ X cmd = M_IS_MENU; X break; X case 'n': /* ?no */ X cmd = M_REJECT; X break; X case 's': /* ?show */ X cmd = M_IS_SHOW; X break; X case 'y': /* ?yes */ X cmd = M_CONFIRM; X break; X default: X m_error("unknown conditional %s", w - 1); X return 1; X } X m->m_type = cmd; X goto ok; X } X X if ((cmd = lookup_command(w, (K_ONLY_MENU | K_ONLY_MORE))) != K_INVALID) { X m_new(M_COMMAND); X m->m_int = GETC_COMMAND | cmd; X goto ok; X } X X if (strcmp(w, "prompt") == 0) { X m_new(M_PROMPT); X m->m_string = "?"; X goto ok; X } X if (strcmp(w, "echo") == 0) { X m_new(M_ECHO); X m->m_string = "ups"; X goto ok; X } X if (strcmp(w, "input") == 0) { X m_new(M_INPUT); X goto ok; X } X if (strcmp(w, "yes") == 0) { X m_new(M_YES); X goto ok; X } X if (strcmp(w, "no") == 0) { X m_new(M_NO); X goto ok; X } X if (strcmp(w, "break") == 0) { X m_new(M_BREAK); X goto ok; X } X if (strcmp(w, "return") == 0) { X m_new(M_RETURN); X goto ok; X } X X m_error("Unknown word >>%s<<", w); X return 1; X X ok: X return 0; X} X X/* X * Invoke macro # N X */ X Xm_invoke(n) Xint n; X{ X if (n < 0 || n > NMACRO || macro[n] == NULL) { X msg("undefined macro %d", n); X return; X } X X if (m == NULL) X no_advance = 0; X else { X if (m_level == MSTACK) { X msg("Macro stack overflow"); X m = NULL; X m_level = 0; X return; X } X mstack[m_level] = m; X cstack[m_level] = cur_m; X m_level++; X } X X cur_m = n; X m = macro[cur_m]; X} X Xm_startinput() X{ X no_advance = 1; X} X Xm_endinput() X{ X if (no_advance) { X no_advance = 0; X if (m && m->m_type == M_INPUT) X m = m->m_next; X } X} X Xm_advinput() X{ X if (m && m->m_type == M_INPUT) X m = m->m_next; X} X Xstatic struct macro *m_call(who) Xint who; X{ X struct macro *m1; X X for (;;) { X while (m == NULL && m_level > 0) { X m_level--; X m = mstack[m_level]; X cur_m = cstack[m_level]; X } X if (m == NULL) { X if (macro_debug) msg("end"); X return NULL; X } X X if (macro_debug) X macro_dbg(); X X if (who == 3) { X if (m->m_type == M_YES || m->m_type == M_NO) goto out; X return NULL; X } X X switch (m->m_type) { X case M_COMMAND: X case M_KEY: X if (who == 1) goto out; X goto err; X X case M_STRING: X if (who == 2) goto out; X goto err; X X case M_INPUT: X if (no_advance) return m; X goto out; X X case M_YES: X case M_NO: X case M_DUMMY: X break; X X case M_PROMPT: X prompt("\1%s\1 ", m->m_string); X break; X X case M_ECHO: X msg(m->m_string); X break; X X case M_IS_MENU: X if (!in_menu_mode) m = m->m_branch; X break; X case M_IS_SHOW: X if (in_menu_mode) m = m->m_branch; X break; X case M_IS_GROUP: X if (current_group->group_flag & G_FOLDER) m = m->m_branch; X break; X case M_IS_FOLDER: X if ((current_group->group_flag & G_FOLDER) == 0) m = m->m_branch; X break; X case M_CONFIRM: X if (!yes(0)) m = m->m_branch; X break; X case M_REJECT: X if (yes(0)) m = m->m_branch; X break; X X case M_VARTEST: X m1 = m; X m = m->m_next; X X switch (test_variable(m1->m_string)) { X case 0: X m = m->m_branch; X break; X case -1: X goto err1; X } X break; X X case M_RETURN: X m = NULL; X continue; X X case M_BREAK: X goto term; X } X X m = m->m_next; X } X X out: X m1 = m; X m = m->m_next; X no_advance = 0; X return m1; X X err: X msg("Error in macro %d", cur_m); X err1: X user_delay(1); X m = NULL; X m_level = 0; X return MERROR; X X term: X m = NULL; X m_level = 0; X return NULL; X} X Xm_break() X{ X m = NULL; X m_level = 0; X} X Xmacro_dbg() X{ X extern char *command_name(), *key_name(); X char *name; X X switch (m->m_type) { X case M_COMMAND: X msg("COMMAND: %s", command_name(m->m_int)); X goto delay; X X case M_KEY: X msg("KEY: %s", key_name(m->m_int)); X goto delay; X X case M_STRING: X msg("STRING: %s", m->m_string); X goto delay; X X case M_INPUT: X name = "input"; X break; X X case M_YES: X name = "yes"; X break; X X case M_NO: X name = "no"; X break; X X case M_DUMMY: X name = "dummy"; X break; X X case M_PROMPT: X msg("PROMPT: %s", m->m_string); X goto delay; X X case M_ECHO: X msg("ECHO: %s", m->m_string); X goto delay; X X case M_IS_MENU: X msg("?menu => %d", in_menu_mode); X goto delay; X X case M_IS_SHOW: X msg("?show => %d", !in_menu_mode); X goto delay; X X case M_IS_GROUP: X msg("?group => %d", (current_group->group_flag & G_FOLDER) == 0); X goto delay; X X case M_IS_FOLDER: X msg("?group => %d", (current_group->group_flag & G_FOLDER)); X goto delay; X X case M_CONFIRM: X name = "?yes"; X break; X X case M_REJECT: X name = "?no"; X break; X X case M_VARTEST: X msg("?%s => %d", m->m_string, test_variable(m->m_string)); X goto delay; X X case M_RETURN: X name = "return"; X break; X X case M_BREAK: X name = "break"; X break; X } X msg(name); X X delay: X user_delay(1); X} X/* X * Macro processing for get_c() X */ X Xm_getc(cp) Xint *cp; X{ X struct macro *m1; X X get_from_macro = 0; X if (m && (m1 = m_call(1))) { X if (m1 == MERROR) return 2; X if (m1->m_type == M_INPUT) return 0; X *cp = m1->m_int; X get_from_macro = 1; X return 1; X } X return 0; X} X X/* X * Macro processing for get_s() X */ X Xm_gets(s) Xchar *s; X{ X struct macro *m1; X X get_from_macro = 0; X if (m && (m1 = m_call(2))) { X if (m1 == MERROR) return 2; X if (m1->m_type == M_INPUT) return 0; X strcpy(s, m1->m_string); X get_from_macro = 1; X return 1; X } X return 0; X} X X/* X * Macro processing for yes() X */ X Xm_yes() X{ X struct macro *m1; X X if (m) { X if (m1 = m_call(3)) X if (m1->m_type == M_NO) X return 1; X else X return 2; X else X return 3; X } X return 0; X} X Xstatic m_error(fmt, arg) Xchar *fmt, *arg; X{ X char buf[80]; X X if (arg) { X sprintf(buf, fmt, arg); X fmt = buf; X } X X init_message("Error in macro %d: %s", cur_m, fmt); X} NO_NEWS_IS_GOOD_NEWS chmod 0644 macro.c || echo "restore of macro.c fails" set `wc -c macro.c`;Sum=$1 if test "$Sum" != "10847" then echo original size 10847, current size $Sum;fi echo "x - extracting master.c (Text)" sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > master.c && X/* X * nn master daemon X * X * maintains the article header database. X */ X X#include <signal.h> X#include <errno.h> X#include "config.h" X#include "db.h" X X/* X * nnmaster options: X * X * -e N expire a group if more than N articles are gone X * -r N repeat every N minutes X * X * -E expire by recolleting entire groups rather than copying files X * -C check consistency of database on start-up X * X * -I initialize X * -t trace collection of each group X * -v print version and exit X * -u update even if active is not modified X * -w send wakeup to real master X * -D debug X */ X X#include "options.h" X Xstatic int X initialize = 0, X prt_vers = 0, X unconditional = 0, X wakeup_master = 0, X expire_level = 1, X clean_to_expire = 0, X check_on_startup = 0, X repeat_delay = 0, X debug_mode = 0; X Xexport int X trace = 0, X#ifdef NNTP X silent = 1, X#endif X Debug = 0; X X XOption_Description(master_options) { X X 'I', Bool_Option( initialize ), X 'v', Bool_Option( prt_vers ), X 'u', Bool_Option( unconditional ), X 'w', Bool_Option( wakeup_master ), X X 'e', Int_Option( expire_level ), X 'r', Int_Option_Optional( repeat_delay, 10 ), X X 'E', Bool_Option( clean_to_expire ), X 'C', Bool_Option( check_on_startup ), X X 'D', Bool_Option( debug_mode ), X 't', Bool_Option( trace ), X X '\0', X}; X X Ximport FILE *master_file; Ximport char news_active[]; X Xstatic int rm_mpid_on_exit = 0; X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X time_t age_active; X register group_header *gh; X register int cur_group; X int col_article_count, col_group_count; X int exp_article_count, exp_group_count; X int temp; X time_t start_time; X FILE *m_pid; X X X umask(002); /* avoid paranoia */ X X init_global(1); X X parse_options(argc, argv, (char *)NULL, master_options, (char *)NULL); X X if (wakeup_master) { X if (!kill_master(SIGALRM) && errno == ESRCH) X printf("master is not running\n"); X nn_exit(0); X } X X if (prt_vers) { X print_version("Master: Release %R.%V.%P, Compilation %U\n"); X nn_exit(0); X } X X if (kill_master(SIGALRM)) { X printf("The master is already running\n"); X nn_exit(0); X } X#ifdef NNTP X nntp_check(); X#endif X if (initialize) { X build_master(); X nn_exit(0); X } X X if (repeat_delay && !debug_mode) { X while ((temp = fork()) < 0) sleep(1); X if (temp) nn_exit(0); X X process_id = getpid(); /* init_global saved parent's pid */ X X DETATCH_TERMINAL X } X X rm_mpid_on_exit = 1; X m_pid = open_file(relative(lib_directory, "MPID"), X OPEN_CREATE|MUST_EXIST); X fprintf(m_pid, "%d\n", process_id); X fclose(m_pid); X X log_entry('M', "Master started -r%d -e%d%s", X repeat_delay, expire_level, clean_to_expire ? " -E" : ""); X X if (check_on_startup) { X char cmd[FILENAME]; X sprintf(cmd, "%s/nnadmin Z", BIN_DIRECTORY); X system(cmd); X log_entry('M', "Database validation completed"); X } X X repeat_delay *= 60; X X init_digest_parsing(); X X open_master(OPEN_READ); X close_master(); X X open_master(OPEN_UPDATE); X X again: X X#ifdef NNTP X if (use_nntp) { X if (nntp_get_active() < 0) { X nntp_close_server(); X current_group = NULL; /* for init_group */ X log_entry('N', "Can't access active file --- %s", X repeat_delay ? "sleeping" : "termating"); X if (repeat_delay == 0) X nn_exit(1); X sleep(repeat_delay); X goto again; X } X } X#endif X X age_active = file_exist(news_active, "fr"); X#ifdef NNTP X if (!use_nntp) X#endif X if (age_active == (time_t)0) X sys_error("Cannot access active file"); X X temp = receive_admin(); X X if (!temp && !unconditional && age_active <= master.last_scan) { X if (repeat_delay == 0) X goto out; X X if (s_hangup) goto out; X#ifdef NNTP X if (use_nntp) X nntp_cleanup(); X#endif /* NNTP */ X if (debug_mode) X printf("NONE (*** SLEEP ***)\n"); X else { X if (trace) log_entry('T', "none"); X sleep(repeat_delay); X } X X if (s_hangup) goto out; X X goto again; X } X X unconditional = 0; /* only first pass */ X X time(&start_time); X col_article_count = col_group_count = 0; X exp_article_count = exp_group_count = 0; X X visit_active_file(); X X for (cur_group = 0; cur_group < master.number_of_groups; cur_group++) { X X if (s_hangup) break; X X gh = &active_groups[cur_group]; X X if (gh->group_flag & G_NO_DIRECTORY) { X if (gh->group_flag & G_BLOCKED) goto unblock_group; X continue; X } X X if (gh->last_l_article > gh->last_article || X gh->first_l_article > gh->first_article) { X log_entry('X', "group %s renumbered", gh->group_name); X clean_group(gh); X X goto do_collect; X } X X if (expire_level > 0 && gh->last_l_article > 0) { X if ((gh->first_l_article + expire_level) <= gh->first_article) { X if (trace) log_entry('T', "%s expire level", gh->group_name); X gh->group_flag |= G_EXPIRE; X goto do_collect; X } X X if (gh->first_article > gh->last_l_article) { X if (trace) log_entry('T', "%s expire void", gh->group_name); X clean_group(gh); X goto do_collect; X } X } X X if (gh->last_l_article == gh->last_article) { X if (gh->group_flag & G_BLOCKED) goto unblock_group; X continue; X } X X do_collect: X if (!init_group(gh)) { X log_entry('R', "%s: no directory", gh->group_name); X gh->group_flag |= G_NO_DIRECTORY; X gh->group_flag &= ~(G_EXPIRE | G_BLOCKED); X save_group(current_group); X continue; X } X X if (gh->group_flag & G_EXPIRE) { X if (clean_to_expire) { X temp = gh->first_article - gh->first_l_article; X clean_group(gh); X } else { X if ((gh->group_flag & G_BLOCKED) == 0) { X gh->group_flag |= G_BLOCKED; X save_group(gh); X } X temp = expire_group(gh); X } X if (temp) { X exp_article_count += temp; X exp_group_count++; X } X } X X temp = collect_group(gh); X#ifdef NNTP X if (temp < 0) { X /* connection broken */ X gh->group_flag &= ~G_EXPIRE; /* remains blocked */ X save_group(gh); X age_active = master.last_scan; /* did not complete */ X current_group = NULL; /* for init_group */ X break; X } X#endif X if (temp > 0) { X col_article_count += temp; X col_group_count++; X } X X unblock_group: X if (temp || (gh->group_flag & G_BLOCKED)) { X gh->group_flag &= ~(G_EXPIRE | G_BLOCKED); X save_group(gh); X } X } X X /* if master is interrupted, all new articles may not be collected */ X X if (!s_hangup) X master.last_scan = age_active; X X save_master(); X X if (exp_article_count) X log_entry('X', "Expire: %3d art, %2d gr, %2ld s %s", X exp_article_count, exp_group_count, X time((time_t *)0) - start_time, X col_article_count ? "(incl. collect)" : ""); X X if (col_article_count) X log_entry('C', "Collect: %3d art, %2d gr, %2ld s %s", X col_article_count, col_group_count, X time((time_t *)0) - start_time, X exp_article_count ? "(incl. expire)" : ""); X X if (!s_hangup && repeat_delay) { X#ifdef NNTP X if (use_nntp) X nntp_cleanup(); X#endif /* NNTP */ X if (!debug_mode) sleep(repeat_delay); X if (!s_hangup) goto again; X } X X out: X nn_exit(0); X /*NOTREACHED*/ X} X X X/* X * nn_exit() --- called whenever a program exits. X */ X Xnn_exit(n) X{ X#ifdef NNTP X if (use_nntp) X nntp_cleanup(); X#endif /* NNTP */ X close_master(); X X if (rm_mpid_on_exit) X unlink(relative(lib_directory, "MPID")); X X if (n) X log_entry('E', "Abnormal termination, exit=%d", n); X else X if (rm_mpid_on_exit) X log_entry('M', "Master terminated%s", s_hangup ? " (hangup)" : ""); X X exit(n); X} X X X/* X * add new group to master file X */ X Xgroup_header *add_new_group(name) Xchar *name; X{ X register group_header *gh; X FILE *group_file; X static has_warned = 0; X X if (master.free_groups <= 0) { X if (!has_warned) { X log_entry('R', "NO MORE FREE GROUP SLOTS -- RESTART MASTER"); X has_warned++; X } X return NULL; X } X X master.free_groups--; X X gh = &active_groups[master.number_of_groups]; X sorted_groups[master.number_of_groups] = gh; X X gh->group_name_length = strlen(name); X gh->group_name = (char *)malloc(gh->group_name_length + 1); X mem_check(gh->group_name, gh->group_name_length, "bytes for group name"); X strcpy(gh->group_name, name); X X gh->group_num = master.number_of_groups++; X X group_file = open_groups(OPEN_UPDATE|MUST_EXIST); X X fseek(group_file, master.next_group_write_offset, 0); X name[gh->group_name_length] = NL; X Fwrite(name, sizeof(char), gh->group_name_length + 1, group_file); X name[gh->group_name_length] = NUL; X fclose(group_file); X X master.next_group_write_offset += gh->group_name_length + 1; X X clean_group(gh); X X save_master(); X X sort_groups(); X X log_entry('C', "new group: %s (%d)", gh->group_name, gh->group_num); X X return gh; X} X X Xsave_group(gh) Xgroup_header *gh; X{ X int flag; X X flag = gh->group_flag; X gh->group_flag &= G_MASTER_FLAGS; X X if (!db_write_group(master_file, gh, gh->group_num)) X write_error(); X fflush(master_file); X X gh->group_flag = flag; X} X X Xsave_master() X{ X rewind(master_file); X if (!db_write_master(master_file, &master)) NO_NEWS_IS_GOOD_NEWS echo "End of part 6" echo "File master.c is continued in part 7" echo "7" > s2_seq_.tmp exit 0 --- Kim F. Storm storm@texas.dk Tel +45 429 174 00 Texas Instruments, Marielundvej 46E, DK-2730 Herlev, Denmark No news is good news, but nn is better! -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.