home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume19 / nn / part06 < prev    next >
Text File  |  1989-06-22  |  50KB  |  2,245 lines

  1. Subject:  v19i067:  NN, a Usenet news reader, Part06/15
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: storm@texas.dk (Kim F. Storm)
  7. Posting-number: Volume 19, Issue 67
  8. Archive-name: nn/part06
  9.  
  10. #!/bin/sh
  11. # this is part 6 of a multipart archive
  12. # do not concatenate these parts, unpack them in order with /bin/sh
  13. # file keymap.h continued
  14. #
  15. CurArch=6
  16. if test ! -r s2_seq_.tmp
  17. then echo "Please unpack part 1 first!"
  18.      exit 1; fi
  19. ( read Scheck
  20.   if test "$Scheck" != $CurArch
  21.   then echo "Please unpack part $Scheck next!"
  22.        exit 1;
  23.   else exit 0; fi
  24. ) < s2_seq_.tmp || exit 1
  25. echo "x - Continuing file keymap.h"
  26. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' >> keymap.h
  27. X#define K_FIRST_PAGE        0x002b /* first page             */
  28. X#define K_LAST_PAGE        0x002c /* last page             */
  29. X
  30. X#define K_GOTO_LINE        0x002d /* goto specific line        */
  31. X#define K_GOTO_PAGE        0x002e /* goto specific page        */
  32. X#define K_GOTO_MATCH        0x002f /* goto line matching regexp    */
  33. X#define K_NEXT_MATCH        0x0030 /* find next match        */
  34. X
  35. X#define K_PREVIOUS        0x0031 /* goto prev group or article    */
  36. X                /* (no update is performed)    */
  37. X
  38. X    /* more() SPECIFIC COMMANDS */
  39. X
  40. X#define K_LEAVE_ARTICLE        0x0033 /* goto next article, mark current */
  41. X#define K_NEXT_ARTICLE        0x0034 /* goto next article         */
  42. X#define K_NEXT_SUBJECT        0x0035 /* goto next subject        */
  43. X#define K_FULL_DIGEST        0x0036 /* show full digest        */
  44. X#define K_ROT13            0x0037 /* do rot13             */
  45. X#define K_COMPRESS        0x0038 /* compress spaces        */
  46. X#define K_BACK_TO_MENU        0x0039 /* return to menu */
  47. X
  48. X    /* menu() SPECIFIC COMMANDS     */
  49. X
  50. X#define K_SELECT        0x0041 /* select current, move down     */
  51. X#define K_SELECT_INVERT        0x0042 /* invert all selections     */
  52. X#define K_SELECT_SUBJECT     0x0043 /* select all with same subject */
  53. X#define K_SELECT_RANGE        0x0044 /* select range         */
  54. X#define K_AUTO_SELECT        0x0045 /* auto select from kill file    */
  55. X#define K_UNSELECT_ALL        0x0046 /* undo all selections        */
  56. X
  57. X#define K_LAYOUT        0x0049 /* change menu layout         */
  58. X
  59. X#define K_NEXT_GROUP_NO_UPDATE     0x004a /* goto next group, no update     */
  60. X#define K_READ_GROUP_UPDATE     0x004b /* read selected, then next group */
  61. X#define K_READ_GROUP_THEN_SAME    0x004c /* read selected, then same group */
  62. X
  63. X#define K_ADVANCE_GROUP        0x004d /* advance one group in sequence */
  64. X#define K_BACK_GROUP        0x004e /* back-up one group in sequence */
  65. X    
  66. X#define K_PREVIEW        0x004f /* preview article         */
  67. X
  68. X#define    K_MACRO            0x0100 /* call macro            */
  69. X#define    K_ARTICLE_ID        0x0200 /* article id in lower part    */
  70. X
  71. X/* special keys returned by get_c() */
  72. X
  73. X#define    K_interrupt    CTRL('G')
  74. X
  75. X#define    K_up_arrow    0x0081
  76. X#define    K_down_arrow    0x0082
  77. X#define K_left_arrow    0x0083
  78. X#define K_right_arrow    0x0084
  79. X
  80. X#define    K_function(n)    (0x0085 + n)
  81. X
  82. X
  83. X#define    GETC_COMMAND    0x4000    /* bit set by get_c to return a command */
  84. X
  85. X/*
  86. X * KEY MAP SIZE is:
  87. X *   (128 normal chars) + (0200) + (4 arrow keys) + (10 function keys)
  88. X */
  89. X
  90. X#define MULTI_KEYS    (1 + 4 + 10)
  91. X#define KEY_MAP_SIZE    (128 + MULTI_KEYS)
  92. X
  93. X
  94. X/* restrictions */ 
  95. X
  96. X#define K_ONLY_MENU    0x0001
  97. X#define K_ONLY_MORE    0x0002
  98. X
  99. Xextern int menu_key_map[];
  100. Xextern int more_key_map[];
  101. X
  102. Xextern char global_key_map[];
  103. NO_NEWS_IS_GOOD_NEWS
  104. echo "File keymap.h is complete"
  105. chmod 0644 keymap.h || echo "restore of keymap.h fails"
  106. set `wc -c keymap.h`;Sum=$1
  107. if test "$Sum" != "4343"
  108. then echo original size 4343, current size $Sum;fi
  109. echo "x - extracting kill.c (Text)"
  110. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > kill.c &&
  111. X#include "config.h"
  112. X#include "term.h"
  113. X
  114. X/*
  115. X * kill file handling
  116. X */
  117. X
  118. Xchar KILL_FILE[] =     "kill";
  119. Xchar COMPILED_KILL[] =    "KILL.COMP";
  120. X
  121. Xextern char *quick_match();
  122. X
  123. X#define COMP_KILL_MAGIC    0x4b694c6c    /* KiLl */
  124. X
  125. X/*
  126. X * kill flags
  127. X */
  128. X
  129. X#define    AUTO_KILL    0x01
  130. X#define AUTO_SELECT    0x00    /* pseudo flag */
  131. X#define ON_SUBJECT    0x02
  132. X#define    ON_SENDER    0x00    /* pseudo flag */
  133. X
  134. X#define    KILL_MUST_MATCH    0x10
  135. X
  136. X/*
  137. X * external flag representation
  138. X */
  139. X
  140. X#define    EXT_AUTO_KILL        '!'
  141. X#define EXT_AUTO_SELECT        '+'
  142. X#define EXT_ON_SUBJECT        's'
  143. X#define    EXT_ON_SENDER        'n'
  144. X#define    EXT_KILL_MUST_MATCH    '='
  145. X
  146. X/*
  147. X * period = nnn DAYS
  148. X */
  149. X
  150. X#define    DAYS    * 24 * 60 * 60
  151. X
  152. X
  153. X/*
  154. X * kill_article
  155. X *
  156. X *    return 1 to kill article, 0 to include it
  157. X */
  158. X
  159. Xtypedef struct kill_list_entry {
  160. X    int kill_flag;
  161. X    char *kill_pattern;
  162. X    struct kill_list_entry *next_kill;
  163. X} kill_list_entry;
  164. X
  165. X
  166. Xstatic kill_list_entry dummy_kill = {
  167. X    0, (char *)NULL, (kill_list_entry *)NULL 
  168. X};
  169. Xstatic kill_list_entry *global_kill_list = &dummy_kill;
  170. Xstatic kill_list_entry *end_kill_list = &dummy_kill;
  171. X
  172. X
  173. Xkill_article(ah)
  174. Xarticle_header *ah;
  175. X{
  176. X    register kill_list_entry *kl;
  177. X    char *string;
  178. X    
  179. X    end_kill_list->next_kill = (kill_list_entry *)(current_group->kill_list);
  180. X    
  181. X    kl = global_kill_list;
  182. X    while (kl = kl->next_kill) {
  183. X    if (kl->kill_flag & ON_SUBJECT)
  184. X        string = ah->subject;
  185. X    else
  186. X        string = ah->sender;
  187. X    
  188. X    if (kl->kill_flag & KILL_MUST_MATCH) {
  189. X        if (strcmp(kl->kill_pattern, string))
  190. X        continue;
  191. X    } else
  192. X        if (quick_match(string, kl->kill_pattern) == NULL)
  193. X        continue;
  194. X    
  195. X    if (kl->kill_flag & AUTO_KILL)
  196. X        return 1;
  197. X    
  198. X    ah->flag |= A_SELECT;
  199. X    break;
  200. X    }
  201. X    
  202. X    return 0;
  203. X}
  204. X
  205. X
  206. Xauto_select_article(ah)
  207. Xarticle_header *ah;
  208. X{
  209. X    register kill_list_entry *kl;
  210. X    char *string;
  211. X    
  212. X    end_kill_list->next_kill = ah->a_group ?
  213. X    (kill_list_entry *)(ah->a_group->kill_list) :
  214. X    (kill_list_entry *)(current_group->kill_list);
  215. X    
  216. X    kl = global_kill_list;
  217. X    while (kl = kl->next_kill) {
  218. X    if (kl->kill_flag & AUTO_KILL) continue;
  219. X    
  220. X    if (kl->kill_flag & ON_SUBJECT)
  221. X        string = ah->subject;
  222. X    else
  223. X        string = ah->sender;
  224. X    
  225. X    if (kl->kill_flag & KILL_MUST_MATCH) {
  226. X        if (strcmp(kl->kill_pattern, string))
  227. X        continue;
  228. X    } else
  229. X        if (quick_match(string, kl->kill_pattern) == NULL)
  230. X        continue;
  231. X    return 1;
  232. X    }
  233. X    
  234. X    return 0;
  235. X}
  236. X
  237. X
  238. X
  239. X
  240. X
  241. Xenter_kill_file(gh, pattern, flag, days)
  242. Xgroup_header *gh;
  243. Xchar *pattern;
  244. Xint flag;
  245. Xint days;
  246. X{
  247. X    time_t now;
  248. X    FILE *killf;
  249. X    register kill_list_entry *kl;
  250. X    char *str;
  251. X    
  252. X    killf = open_file(relative(nn_directory, "kill"), OPEN_APPEND);
  253. X    if (killf == NULL) {
  254. X    msg("cannot create kill file");
  255. X    return;
  256. X    }
  257. X    
  258. X    if (days >= 0) {
  259. X    time(&now);
  260. X    if (days == 0) days = 30;
  261. X    fprintf(killf, "%lu:", (long)(now + days DAYS));
  262. X    }
  263. X
  264. X    if (gh) fputs(gh->group_name, killf);
  265. X    fputc(':', killf);
  266. X
  267. X    fputc(flag & AUTO_KILL ? EXT_AUTO_KILL : EXT_AUTO_SELECT, killf);
  268. X    fputc(flag & ON_SUBJECT ? EXT_ON_SUBJECT : EXT_ON_SENDER, killf);
  269. X    if (flag & KILL_MUST_MATCH) fputc(EXT_KILL_MUST_MATCH, killf);
  270. X    fputc(':', killf);
  271. X
  272. X    fputs(pattern, killf);
  273. X    fputc(NL, killf);
  274. X    
  275. X    fclose(killf);
  276. X    rm_kill_file();
  277. X    
  278. X    str = malloc(strlen(pattern) + 1);
  279. X    mem_check(str, 1, "string");
  280. X    
  281. X    strcpy(str, pattern);
  282. X    
  283. X    if ((flag & KILL_MUST_MATCH) == 0)
  284. X    init_quick_match(str);
  285. X    
  286. X    kl = (kill_list_entry *)calloc(1, sizeof(kill_list_entry));
  287. X    mem_check(kl, 1, "kill list entry");
  288. X    
  289. X    kl->kill_pattern = str;
  290. X    kl->kill_flag = flag;
  291. X    
  292. X    if (gh) {
  293. X    kl->next_kill = (kill_list_entry *)(gh->kill_list);
  294. X    gh->kill_list = (char *)kl;
  295. X    } else {
  296. X    kl->next_kill = NULL;
  297. X    end_kill_list->next_kill = kl;
  298. X    end_kill_list = kl;
  299. X    }
  300. X}
  301. X
  302. X
  303. Xtypedef struct {
  304. X    group_number    ck_group;
  305. X    char        ck_flag;
  306. X    long        ck_pattern_index;
  307. X} comp_kill_entry;
  308. X
  309. Xtypedef struct {
  310. X    long        ckh_magic;
  311. X    off_t        ckh_pattern_offset;
  312. X    long        ckh_pattern_size;
  313. X    long        ckh_entries;
  314. X} comp_kill_header;
  315. X
  316. X
  317. Xkill_menu(ah)
  318. Xarticle_header *ah;
  319. X{
  320. X    int flag, days;
  321. X    char *mode1, *mode2;
  322. X    char *pattern, *dflt, *days_str, buffer[512];
  323. X    extern article_header *get_menu_article();
  324. X    group_header *gh;
  325. X    
  326. X    prompt("\1AUTO\1 (K)ill or (S)elect (CR => Kill subject 1 month) ");
  327. X    switch (get_c()) {
  328. X     case CR:
  329. X     case NL:
  330. X    if (ah == NULL) {
  331. X        ah = get_menu_article();
  332. X        if (ah == NULL) return;
  333. X    }
  334. X    
  335. X    strcpy(buffer, ah->subject);
  336. X    enter_kill_file(current_group, buffer, 
  337. X            AUTO_KILL | ON_SUBJECT | KILL_MUST_MATCH, 30);
  338. X    msg("DONE");
  339. X    return;
  340. X    
  341. X     case 'k':
  342. X     case 'K':
  343. X     case '!':
  344. X    flag = AUTO_KILL;
  345. X    mode1 = "KILL";
  346. X    break;
  347. X     case 's':
  348. X     case 'S':
  349. X     case '+':
  350. X    flag = AUTO_SELECT;
  351. X    mode1 = "SELECT";
  352. X    break;
  353. X     default:
  354. X    return;
  355. X    }
  356. X    
  357. X    prompt("\1AUTO %s\1 on (S)ubject or (N)ame ?", mode1);
  358. X    
  359. X    dflt = NULL;
  360. X    switch (get_c()) {
  361. X     case 'n':
  362. X     case 'N':
  363. X    flag |= ON_SENDER;
  364. X    if (ah) dflt = ah->sender;
  365. X    mode2 = "Name";
  366. X    break;
  367. X     case 's':
  368. X     case 'S':
  369. X     case SP:
  370. X     case CR:
  371. X     case NL:
  372. X    flag |= ON_SUBJECT;
  373. X    if (ah) dflt = ah->subject;
  374. X    mode2 = "Subject";
  375. X    break;
  376. X     default:
  377. X    return;
  378. X    }
  379. X
  380. X    prompt("\1%s %s:\1", mode1, mode2);
  381. X    
  382. X    pattern = get_s(dflt, NONE, "%=", NO_COMPLETION);
  383. X    if (pattern == NULL) return;
  384. X    if (*pattern == NUL || *pattern == '%' || *pattern == '=') {
  385. X    if (dflt && *dflt)
  386. X        pattern = dflt;
  387. X    else {
  388. X        if ((ah = get_menu_article()) == NULL) return;
  389. X        pattern = (flag & ON_SUBJECT) ? ah->subject : ah->sender;
  390. X    }
  391. X    flag |= KILL_MUST_MATCH;
  392. X    }
  393. X    
  394. X    strcpy(buffer, pattern);
  395. X    pattern = buffer;
  396. X    
  397. X    prompt("\1%s\1 in (G)roup '%s' or in (A)ll groups",
  398. X       mode1, current_group->group_name);
  399. X    
  400. X    switch (get_c()) {
  401. X      case 'g':
  402. X      case 'G':
  403. X      case SP:
  404. X      case CR:
  405. X      case NL:
  406. X     gh = current_group;
  407. X     break;
  408. X      case 'A':
  409. X      case 'a':
  410. X     gh = NULL;
  411. X     break;
  412. X      default:
  413. X     return;
  414. X     }
  415. X
  416. X    prompt("\1Lifetime of entry in days\1 (P)ermanent ");
  417. X    days_str = get_s(" 30 days", NONE, "pP", NO_COMPLETION);
  418. X    if (days_str == NULL) return;
  419. X
  420. X    if (*days_str == NUL) {
  421. X        days_str = "30 days";
  422. X    days = 30;
  423. X    } else if (*days_str == 'p' || *days_str == 'P') {
  424. X    days_str = "perm";
  425. X    days = -1;
  426. X    } else if (isdigit(*days_str)) {
  427. X    days = atoi(days_str);
  428. X    sprintf(days_str, "%d days", days);
  429. X    } else {
  430. X    ding();
  431. X    return;
  432. X    }
  433. X
  434. X    prompt("\1CONFIRM\1 %s %s %s%s: %-.35s%s ",
  435. X       mode1, mode2, days_str, 
  436. X       (flag & KILL_MUST_MATCH) ? " exact" : "",
  437. X       pattern, strlen(pattern) > 35 ? "..." : "");
  438. X    if (yes(0) <= 0) return;
  439. X    
  440. X    enter_kill_file(gh, pattern, flag, days);
  441. X}
  442. X
  443. X
  444. X    
  445. X
  446. Xinit_kill()
  447. X{
  448. X    FILE *killf;
  449. X    comp_kill_header header;
  450. X    comp_kill_entry  entry;
  451. X    kill_list_entry *kill_tab;
  452. X    register group_header *gh;
  453. X    register kill_list_entry *kl;
  454. X    char *patterns;
  455. X    time_t kill_age, comp_age;
  456. X    register n;
  457. X    
  458. X    Loop_Groups_Header(gh)
  459. X    gh->kill_list = NULL;
  460. X
  461. X    kill_age = file_exist(relative(nn_directory, KILL_FILE), "frw");
  462. X    if (kill_age == 0) return 0;
  463. X    
  464. X    comp_age = file_exist(relative(nn_directory, COMPILED_KILL), "fr");
  465. X    if (comp_age < kill_age && !compile_kill_file()) return 0;
  466. X    
  467. X    killf = open_file(relative(nn_directory, COMPILED_KILL), OPEN_READ);
  468. X    if (killf == NULL) return 0;
  469. X
  470. X    if (fread(&header, sizeof(header), 1, killf) != 1) goto err;
  471. X    if (header.ckh_magic != COMP_KILL_MAGIC) goto err;
  472. X
  473. X    patterns = malloc(header.ckh_pattern_size);
  474. X    mem_check(patterns, header.ckh_pattern_size, "kill bytes");
  475. X    
  476. X    kill_tab = (kill_list_entry *)
  477. X    calloc(header.ckh_entries, sizeof(kill_list_entry));
  478. X    mem_check(kill_tab, header.ckh_entries, "kill entries");
  479. X    
  480. X    for (n = header.ckh_entries, kl = kill_tab; --n >= 0; kl++) {
  481. X    if (fread(&entry, sizeof(entry), 1, killf) != 1) goto err;
  482. X    
  483. X    kl->kill_pattern = patterns + entry.ck_pattern_index;
  484. X    kl->kill_flag = entry.ck_flag;
  485. X    
  486. X    if (entry.ck_group >= 0) {
  487. X        gh = active_groups + entry.ck_group;
  488. X        kl->next_kill = (kill_list_entry *)(gh->kill_list);
  489. X        gh->kill_list = (char *)kl;
  490. X    } else {
  491. X        kl->next_kill = NULL;
  492. X        end_kill_list->next_kill = kl;
  493. X        end_kill_list = kl;
  494. X    }
  495. X    }
  496. X          
  497. X    if (fread(patterns, sizeof(char), header.ckh_pattern_size, killf)
  498. X    !=  header.ckh_pattern_size) goto err;
  499. X
  500. X    fclose(killf);
  501. X    
  502. X    return 1;
  503. X    
  504. X err:
  505. X    fclose(killf);
  506. X    msg("Error in compiled kill file");
  507. X    rm_kill_file();
  508. X
  509. X    Loop_Groups_Header(gh)
  510. X    gh->kill_list = NULL;
  511. X    
  512. X    end_kill_list = global_kill_list = &dummy_kill;
  513. X
  514. X    return 0;
  515. X}
  516. X
  517. X
  518. Xstatic compile_kill_file()
  519. X{
  520. X    FILE *killf, *compf, *patternf, *dropf;
  521. X    comp_kill_header header;
  522. X    comp_kill_entry  entry;
  523. X    time_t now, age;
  524. X    off_t cur_line_start;
  525. X    char line[512];
  526. X    register char *cp, *np;
  527. X    register int c;
  528. X    group_header *gh;
  529. X    int flag, any_errors;
  530. X    extern char *temp_file;
  531. X    
  532. X    any_errors = 0;
  533. X    header.ckh_entries = 0;
  534. X    
  535. X    killf = open_file(relative(nn_directory, KILL_FILE),
  536. X              OPEN_READ | DONT_CREATE);
  537. X    if (killf == NULL) return 0;
  538. X
  539. X    compf = open_file(relative(nn_directory, COMPILED_KILL), OPEN_CREATE);
  540. X    if (compf == NULL) goto err1;
  541. X
  542. X    if ((patternf = open_file(temp_file, OPEN_CREATE)) == NULL)
  543. X    goto err2;
  544. X
  545. X    dropf = NULL;
  546. X
  547. X    printf("\nCompiling kill file\n");
  548. X
  549. X    fseek(compf, (off_t)sizeof(header), 0);
  550. X    
  551. X    time(&now);
  552. X    
  553. X next_entry:
  554. X
  555. X    for (;;) {
  556. X    cur_line_start = ftell(killf);
  557. X    
  558. X    if (fgets(line, 512, killf) == NULL) break;
  559. X    
  560. X    cp = line;
  561. X    while (*cp && isascii(*cp) && isspace(*cp)) cp++;
  562. X    if (*cp == NUL || *cp == '#' || !isascii(*cp)) continue;
  563. X    
  564. X    if ((np = strchr(cp, ':')) == NULL) goto bad_entry;
  565. X
  566. X    /* optional "age:" */
  567. X
  568. X    if (np != cp && isdigit(*cp)) {
  569. X        *np++ = NUL;
  570. X        age = (time_t)atol(cp);
  571. X        if (age < now) goto drop_entry;
  572. X        cp = np;
  573. X        if ((np = strchr(cp, ':')) == NULL) goto bad_entry;
  574. X    }
  575. X
  576. X    /* "group-name:"  or ":" for all groups */
  577. X
  578. X    if (np == cp) {
  579. X        entry.ck_group = -1;
  580. X        np++;
  581. X    } else {
  582. X        *np++ = NUL;
  583. X        if ((gh = lookup(cp)) == NULL) {
  584. X        printf("Unknown group in kill file: %s\n", cp);
  585. X        any_errors++;
  586. X        goto drop_entry;
  587. X        }
  588. X        entry.ck_group = gh->group_num;
  589. X    }
  590. X
  591. X    /* flags */
  592. X
  593. X    cp = np;
  594. X    flag = 0;
  595. X    
  596. X    for (;;) {
  597. X        switch (*cp++) {
  598. X         case EXT_AUTO_KILL:
  599. X        flag |= AUTO_KILL;
  600. X        continue;
  601. X         case EXT_AUTO_SELECT:
  602. X        flag |= AUTO_SELECT;
  603. X        continue;
  604. X         case EXT_ON_SUBJECT:
  605. X        flag |= ON_SUBJECT;
  606. X        continue;
  607. X         case EXT_ON_SENDER:
  608. X        flag |= ON_SENDER;
  609. X        continue;
  610. X         case EXT_KILL_MUST_MATCH:
  611. X        flag |= KILL_MUST_MATCH;
  612. X        continue;
  613. X         case ':':
  614. X        break;
  615. X         case NL:
  616. X        goto bad_entry;
  617. X         default:
  618. X        printf("Ignored flag '%c' in kill file\n", cp[-1]);
  619. X        any_errors++;
  620. X        continue;
  621. X        }        
  622. X        break;
  623. X    }
  624. X
  625. X    entry.ck_flag = flag;
  626. X    
  627. X    if ((np = strchr(cp, NL)) == NULL) goto bad_entry;
  628. X    
  629. X    *np++ = NUL;
  630. X    if ((flag & KILL_MUST_MATCH) == 0)
  631. X        init_quick_match(cp);
  632. X    
  633. X    entry.ck_pattern_index = ftell(patternf);
  634. X    
  635. X    if (fwrite(&entry, sizeof(entry), 1, compf) != 1)
  636. X        goto err3;
  637. X
  638. X    if (fwrite(cp, sizeof(char), np - cp, patternf) != (np - cp)) 
  639. X        goto err3;
  640. X    
  641. X    header.ckh_entries++;
  642. X    }
  643. X    
  644. X    header.ckh_pattern_size = ftell(patternf);
  645. X    
  646. X    fclose(patternf);
  647. X    patternf = open_file(temp_file, OPEN_READ | OPEN_UNLINK);
  648. X    if (patternf == NULL) goto err2;
  649. X    
  650. X    header.ckh_pattern_offset = ftell(compf);
  651. X    
  652. X    while ((c = getc(patternf)) != EOF)
  653. X    putc(c, compf);
  654. X
  655. X    fclose(patternf);
  656. X
  657. X    rewind(compf);
  658. X
  659. X    header.ckh_magic = COMP_KILL_MAGIC;
  660. X
  661. X    if (fwrite(&header, sizeof(header), 1, compf) != 1)
  662. X    goto err2;
  663. X    
  664. X    fclose(compf);
  665. X    fclose(killf);
  666. X    if (dropf != NULL) fclose(dropf);
  667. X
  668. X    if (any_errors) {
  669. X    putchar(NL);
  670. X    any_key(0);
  671. X    }
  672. X    
  673. X    return 1;
  674. X    
  675. X bad_entry:
  676. X    printf("Incomplete kill file entry:\n%s", line);
  677. X    fl;
  678. X    any_errors++;
  679. X    
  680. X drop_entry:
  681. X    if (dropf == NULL) {
  682. X    dropf = open_file(relative(nn_directory, KILL_FILE),
  683. X              OPEN_UPDATE | DONT_CREATE);
  684. X    if (dropf == NULL) goto next_entry;
  685. X    }
  686. X    fseek(dropf, cur_line_start, 0);
  687. X    fwrite("# ", sizeof(char), 2, dropf);
  688. X    goto next_entry;
  689. X    
  690. X err3:       
  691. X    fclose(patternf);
  692. X    unlink(temp_file);
  693. X err2:
  694. X    fclose(compf);
  695. X    rm_kill_file();
  696. X err1:
  697. X    fclose(killf);
  698. X    if (dropf != NULL) fclose(dropf);
  699. X    
  700. X    msg("cannot compile kill file");
  701. X    return 0;
  702. X}
  703. X    
  704. X
  705. Xrm_kill_file()
  706. X{    
  707. X    unlink(relative(nn_directory, COMPILED_KILL));
  708. X}
  709. X
  710. X
  711. Xdump_kill_list()
  712. X{
  713. X    register kill_list_entry *kl;
  714. X
  715. X    pg_init(0, 1);
  716. X    
  717. X    pg_next();
  718. X    so_printf("\1GLOBAL kill list entries:\1");
  719. X    
  720. X    kl = end_kill_list->next_kill = NULL;
  721. X
  722. X    kl = global_kill_list;
  723. X    while (kl = kl->next_kill) 
  724. X    if (print_kill(kl) < 0) goto out;
  725. X
  726. X    if (pg_next() < 0) goto out;
  727. X    if (pg_next() < 0) goto out;
  728. X    so_printf("\1GROUP %s kill list entries\1", current_group->group_name);
  729. X    
  730. X    kl = (kill_list_entry *)(current_group->kill_list);
  731. X    while (kl) {
  732. X    if (print_kill(kl) < 0) break;
  733. X    kl = kl->next_kill;
  734. X    }
  735. X
  736. X out:
  737. X    
  738. X    pg_end();
  739. X}
  740. X
  741. X
  742. X
  743. Xprint_kill(kl)
  744. Xregister kill_list_entry *kl;
  745. X{
  746. X    if (pg_next() < 0) return -1;
  747. X
  748. X    printf("\r%s ON %s '%.35s'%s\n",
  749. X       kl->kill_flag & AUTO_KILL ? "KILL" : "SELECT",
  750. X       kl->kill_flag & ON_SUBJECT ? "SUBJECT" : "NAME",
  751. X       kl->kill_pattern,
  752. X       kl->kill_flag & KILL_MUST_MATCH ? " (exact)" : "");
  753. X
  754. X    return 0;
  755. X}
  756. X
  757. NO_NEWS_IS_GOOD_NEWS
  758. chmod 0644 kill.c || echo "restore of kill.c fails"
  759. set `wc -c kill.c`;Sum=$1
  760. if test "$Sum" != "13252"
  761. then echo original size 13252, current size $Sum;fi
  762. echo "x - extracting log_entry.c (Text)"
  763. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > log_entry.c &&
  764. X/*
  765. X *    log_entry type string
  766. X *    
  767. X *    Enter a message in the Log.
  768. X */
  769. X
  770. Xmain(argc, argv)
  771. Xint argc;
  772. Xchar *argv[];
  773. X{
  774. X    if (argc != 3) exit(1);
  775. X
  776. X    init_global(0);
  777. X    
  778. X    if (log_entry(argv[1][0], "%s", argv[2]) == 0)
  779. X    exit(1);
  780. X    
  781. X    nn_exit(0);
  782. X}
  783. X
  784. Xnn_exit(n)
  785. Xint n;
  786. X{
  787. X    exit(n);
  788. X}
  789. X
  790. Xuser_error()
  791. X{
  792. X    nn_exit(1);
  793. X}
  794. X
  795. NO_NEWS_IS_GOOD_NEWS
  796. chmod 0644 log_entry.c || echo "restore of log_entry.c fails"
  797. set `wc -c log_entry.c`;Sum=$1
  798. if test "$Sum" != "320"
  799. then echo original size 320, current size $Sum;fi
  800. echo "x - extracting m-att3b.h (Text)"
  801. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-att3b.h &&
  802. X
  803. X/************** Machine (and compiler) dependent definitions. **************
  804. X *
  805. X *    Define appropriate types for the following ranges of integer
  806. X *    variables.  These are processor & compiler dependent, but the
  807. X *    distributed definitions will probably work on most systems.
  808. X */
  809. X
  810. X
  811. X
  812. X/*      MACHINE TYPE    DEFINED TYPE        VALUE RANGE    */
  813. X
  814. Xtypedef unsigned char    int8;        /*        0 ..     255 */
  815. Xtypedef short        int16;        /*  -10,000 ..  10,000 */
  816. Xtypedef long        int32;        /* -100,000 .. 100,000 */
  817. Xtypedef unsigned long    uint32;        /*       0 ..  2^31-1 */
  818. X
  819. X
  820. X/*
  821. X *    Define NETWORK_BYTE_ORDER if the machine's int32's are
  822. X *    already in network byte order, i.e. m68k based.
  823. X */
  824. X
  825. X#define NETWORK_BYTE_ORDER    /* */
  826. NO_NEWS_IS_GOOD_NEWS
  827. chmod 0644 m-att3b.h || echo "restore of m-att3b.h fails"
  828. set `wc -c m-att3b.h`;Sum=$1
  829. if test "$Sum" != "688"
  830. then echo original size 688, current size $Sum;fi
  831. echo "x - extracting m-dec3100.h (Text)"
  832. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-dec3100.h &&
  833. X/************** Machine (and compiler) dependent definitions. **************
  834. X *
  835. X *    This file is for a DECstation 3100, running Ultrix
  836. X */
  837. X
  838. X/*      MACHINE TYPE    DEFINED TYPE        VALUE RANGE    */
  839. X
  840. Xtypedef unsigned char    int8;        /*        0 ..     255 */
  841. Xtypedef short        int16;        /*  -10,000 ..  10,000 */
  842. Xtypedef long        int32;        /* -100,000 .. 100,000 */
  843. Xtypedef unsigned long    uint32;        /*       0 ..  2^31-1 */
  844. X
  845. X#undef NO_VARARGS
  846. X
  847. X#ifdef NETWORK_DATABASE
  848. X#undef NETWORK_BYTE_ORDER
  849. X#include <netinet/in.h>
  850. X#endif    /* NETWORK DATABASE */
  851. NO_NEWS_IS_GOOD_NEWS
  852. chmod 0644 m-dec3100.h || echo "restore of m-dec3100.h fails"
  853. set `wc -c m-dec3100.h`;Sum=$1
  854. if test "$Sum" != "519"
  855. then echo original size 519, current size $Sum;fi
  856. echo "x - extracting m-gould.h (Text)"
  857. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-gould.h &&
  858. X/************** Machine (and compiler) dependent definitions. **************
  859. X *
  860. X *    Define appropriate types for the following ranges of integer
  861. X *    variables.  These are processor & compiler dependent, but the
  862. X *    distributed definitions will probably work on most systems.
  863. X */
  864. X
  865. X
  866. X
  867. X/*      MACHINE TYPE    DEFINED TYPE        VALUE RANGE    */
  868. X
  869. Xtypedef unsigned char    int8;        /*        0 ..     255 */
  870. Xtypedef short        int16;        /*  -10,000 ..  10,000 */
  871. Xtypedef long        int32;        /* -100,000 .. 100,000 */
  872. Xtypedef unsigned long    uint32;        /*       0 ..  2^31-1 */
  873. X
  874. X/*
  875. X *    GOULD/UTX has varargs.h but not v[s]printf()
  876. X */
  877. X
  878. X#define NO_VARARGS 
  879. X
  880. X
  881. X/*
  882. X *    Not in network byte order on the GOULD
  883. X */
  884. X
  885. X#undef NETWORK_BYTE_ORDER    /* */
  886. X#ifdef NETWORK_DATABASE
  887. X#include <netinet/in.h>
  888. X#endif
  889. NO_NEWS_IS_GOOD_NEWS
  890. chmod 0644 m-gould.h || echo "restore of m-gould.h fails"
  891. set `wc -c m-gould.h`;Sum=$1
  892. if test "$Sum" != "751"
  893. then echo original size 751, current size $Sum;fi
  894. echo "x - extracting m-hp9000.h (Text)"
  895. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-hp9000.h &&
  896. X
  897. X/************** Machine (and compiler) dependent definitions. **************
  898. X *
  899. X *    This is for HP9000 Series 320 and 800 (at least)
  900. X */
  901. X
  902. X
  903. X/*      MACHINE TYPE    DEFINED TYPE        VALUE RANGE    */
  904. X
  905. Xtypedef unsigned char    int8;        /*        0 ..     255 */
  906. Xtypedef short        int16;        /*  -10,000 ..  10,000 */
  907. Xtypedef long        int32;        /* -100,000 .. 100,000 */
  908. Xtypedef unsigned long    uint32;        /*       0 ..  2^31-1 */
  909. X
  910. X
  911. X/*
  912. X *    Define NETWORK_BYTE_ORDER if the machine's int32's are
  913. X *    already in network byte order, i.e. m68k based.
  914. X */
  915. X
  916. X#define NETWORK_BYTE_ORDER    /* */
  917. NO_NEWS_IS_GOOD_NEWS
  918. chmod 0644 m-hp9000.h || echo "restore of m-hp9000.h fails"
  919. set `wc -c m-hp9000.h`;Sum=$1
  920. if test "$Sum" != "550"
  921. then echo original size 550, current size $Sum;fi
  922. echo "x - extracting m-m680x0.h (Text)"
  923. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-m680x0.h &&
  924. X
  925. X/************** Machine (and compiler) dependent definitions. **************
  926. X *
  927. X *    These are for 680x0 based systems.
  928. X */
  929. X
  930. X
  931. X
  932. X/*      MACHINE TYPE    DEFINED TYPE        VALUE RANGE    */
  933. X
  934. Xtypedef unsigned char    int8;        /*        0 ..     255 */
  935. Xtypedef short        int16;        /*  -10,000 ..  10,000 */
  936. Xtypedef long        int32;        /* -100,000 .. 100,000 */
  937. Xtypedef unsigned long    uint32;        /*       0 ..  2^31-1 */
  938. X
  939. X
  940. X/*
  941. X *    Define NETWORK_BYTE_ORDER if the machine's int32's are
  942. X *    already in network byte order, i.e. m68k based.
  943. X */
  944. X
  945. X#define NETWORK_BYTE_ORDER    /* */
  946. NO_NEWS_IS_GOOD_NEWS
  947. chmod 0644 m-m680x0.h || echo "restore of m-m680x0.h fails"
  948. set `wc -c m-m680x0.h`;Sum=$1
  949. if test "$Sum" != "534"
  950. then echo original size 534, current size $Sum;fi
  951. echo "x - extracting m-sparc.h (Text)"
  952. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-sparc.h &&
  953. X
  954. X/************** Machine (and compiler) dependent definitions. **************
  955. X *
  956. X *    Define appropriate types for the following ranges of integer
  957. X *    variables.  These are processor & compiler dependent, but the
  958. X *    distributed definitions will probably work on most systems.
  959. X */
  960. X
  961. X
  962. X
  963. X/*      MACHINE TYPE    DEFINED TYPE        VALUE RANGE    */
  964. X
  965. Xtypedef unsigned char    int8;        /*        0 ..     255 */
  966. Xtypedef short        int16;        /*  -10,000 ..  10,000 */
  967. Xtypedef long        int32;        /* -100,000 .. 100,000 */
  968. Xtypedef unsigned long    uint32;        /*       0 ..  2^31-1 */
  969. X
  970. X
  971. X
  972. X/*
  973. X *    Define NETWORK_BYTE_ORDER if the machine's longs are
  974. X *    already in network byte order.
  975. X */
  976. X
  977. X#define NETWORK_BYTE_ORDER
  978. NO_NEWS_IS_GOOD_NEWS
  979. chmod 0644 m-sparc.h || echo "restore of m-sparc.h fails"
  980. set `wc -c m-sparc.h`;Sum=$1
  981. if test "$Sum" != "664"
  982. then echo original size 664, current size $Sum;fi
  983. echo "x - extracting m-sun.h (Text)"
  984. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-sun.h &&
  985. X
  986. X/************** Machine (and compiler) dependent definitions. **************
  987. X *
  988. X *    Define appropriate types for the following ranges of integer
  989. X *    variables.  These are processor & compiler dependent, but the
  990. X *    distributed definitions will probably work on most systems.
  991. X */
  992. X
  993. X
  994. X
  995. X/*      MACHINE TYPE    DEFINED TYPE        VALUE RANGE    */
  996. X
  997. Xtypedef unsigned char    int8;        /*        0 ..     255 */
  998. Xtypedef short        int16;        /*  -10,000 ..  10,000 */
  999. Xtypedef long        int32;        /* -100,000 .. 100,000 */
  1000. Xtypedef unsigned long    uint32;        /*       0 ..  2^31-1 */
  1001. X
  1002. X
  1003. X
  1004. X/*
  1005. X *    Define NETWORK_BYTE_ORDER if the machine's longs are
  1006. X *    already in network byte order.
  1007. X */
  1008. X
  1009. X#define NETWORK_BYTE_ORDER    /* */
  1010. X
  1011. NO_NEWS_IS_GOOD_NEWS
  1012. chmod 0644 m-sun.h || echo "restore of m-sun.h fails"
  1013. set `wc -c m-sun.h`;Sum=$1
  1014. if test "$Sum" != "671"
  1015. then echo original size 671, current size $Sum;fi
  1016. echo "x - extracting m-sun386i.h (Text)"
  1017. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-sun386i.h &&
  1018. X/************** Machine (and compiler) dependent definitions. **************
  1019. X *
  1020. X *    Define appropriate types for the following ranges of integer
  1021. X *    variables.  These are processor & compiler dependent, but the
  1022. X *    distributed definitions will probably work on most systems.
  1023. X */
  1024. X
  1025. X
  1026. X
  1027. X/*      MACHINE TYPE    DEFINED TYPE        VALUE RANGE    */
  1028. X
  1029. Xtypedef unsigned char    int8;        /*        0 ..     255 */
  1030. Xtypedef short        int16;        /*  -10,000 ..  10,000 */
  1031. Xtypedef long        int32;        /* -100,000 .. 100,000 */
  1032. Xtypedef unsigned long    uint32;        /*       0 ..  2^31-1 */
  1033. X
  1034. X
  1035. X
  1036. X/*
  1037. X *    Not in network byte order on the 386
  1038. X */
  1039. X
  1040. X#undef NETWORK_BYTE_ORDER    /* */
  1041. X#ifdef NETWORK_DATABASE
  1042. X#include <netinet/in.h>
  1043. X#endif
  1044. NO_NEWS_IS_GOOD_NEWS
  1045. chmod 0644 m-sun386i.h || echo "restore of m-sun386i.h fails"
  1046. set `wc -c m-sun386i.h`;Sum=$1
  1047. if test "$Sum" != "673"
  1048. then echo original size 673, current size $Sum;fi
  1049. echo "x - extracting m-template.h (Text)"
  1050. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-template.h &&
  1051. X
  1052. X/************** Machine (and compiler) dependent definitions. **************
  1053. X *
  1054. X *    Define appropriate types for the following ranges of integer
  1055. X *    variables.  These are processor & compiler dependent, but the
  1056. X *    distributed definitions will probably work on most systems.
  1057. X */
  1058. X
  1059. X
  1060. X
  1061. X/*      MACHINE TYPE    DEFINED TYPE        VALUE RANGE    */
  1062. X
  1063. Xtypedef unsigned char    int8;        /*        0 ..     255 */
  1064. Xtypedef short        int16;        /*  -10,000 ..  10,000 */
  1065. Xtypedef long        int32;        /* -100,000 .. 100,000 */
  1066. Xtypedef unsigned long    uint32;        /*       0 ..  2^31-1 */
  1067. X
  1068. X
  1069. X/*
  1070. X *     Define NO_VARARGS if the varargs feature is not available
  1071. X *
  1072. X *    Also define NO_VARARGS if the vprintf/vsprintf routines are not
  1073. X *    available (however, this will only by safe on some machines, like
  1074. X *    the VAX).
  1075. X *    
  1076. X */
  1077. X
  1078. X/* #define NO_VARARGS */
  1079. X
  1080. X
  1081. X
  1082. X#ifdef NETWORK_DATABASE
  1083. X
  1084. X/*
  1085. X *    Define NETWORK_BYTE_ORDER if the machine's int32's are
  1086. X *    already in network byte order, i.e. m68k based.
  1087. X */
  1088. X
  1089. X#define NETWORK_BYTE_ORDER    /* */
  1090. X
  1091. X/*
  1092. X *    OTHERWISE provide the functions/macros ntohl/htonl to
  1093. X *    convert longs from and to network byte order
  1094. X */
  1095. X
  1096. X#ifndef NETWORK_BYTE_ORDER
  1097. X
  1098. X/*
  1099. X * Include appropriate files or define macroes or functions (include them 
  1100. X * in data.c) to convert longs and shorts to and from network byte order.
  1101. X */
  1102. X
  1103. X/*
  1104. X * This will work on most BSD based systems...
  1105. X */
  1106. X
  1107. X#include <netinet/in.h>
  1108. X
  1109. X/*
  1110. X * Otherwise, define something appropriate below
  1111. X */
  1112. X
  1113. X#define htonl(l)    ...    /* host long to network long */
  1114. X#define ntohl(l)    ...    /* network long to host long */
  1115. X
  1116. X#endif    /* not NETWORK BYTE ORDER */
  1117. X
  1118. X#endif    /* NETWORK DATABASE */
  1119. NO_NEWS_IS_GOOD_NEWS
  1120. chmod 0644 m-template.h || echo "restore of m-template.h fails"
  1121. set `wc -c m-template.h`;Sum=$1
  1122. if test "$Sum" != "1577"
  1123. then echo original size 1577, current size $Sum;fi
  1124. echo "x - extracting m-vax.h (Text)"
  1125. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-vax.h &&
  1126. X
  1127. X/************** Machine (and compiler) dependent definitions. **************
  1128. X *
  1129. X *    Define appropriate types for the following ranges of integer
  1130. X *    variables.  These are processor & compiler dependent, but the
  1131. X *    distributed definitions will probably work on most systems.
  1132. X */
  1133. X
  1134. X
  1135. X
  1136. X/*      MACHINE TYPE    DEFINED TYPE        VALUE RANGE    */
  1137. X
  1138. Xtypedef unsigned char    int8;        /*        0 ..     255 */
  1139. Xtypedef short        int16;        /*  -10,000 ..  10,000 */
  1140. Xtypedef long        int32;        /* -100,000 .. 100,000 */
  1141. Xtypedef unsigned long    uint32;        /*       0 ..  2^31-1 */
  1142. X
  1143. X
  1144. X/*
  1145. X *    VAX/BSD has varargs.h but not v[s]printf()
  1146. X */
  1147. X
  1148. X#define NO_VARARGS 
  1149. X
  1150. X
  1151. X/*
  1152. X *    The VAX does not have longs in network byte order
  1153. X */
  1154. X
  1155. X#undef NETWORK_BYTE_ORDER    /* we need to use ntohl/htonl */
  1156. X#ifdef NETWORK_DATABASE
  1157. X#include <netinet/in.h>
  1158. X#endif
  1159. NO_NEWS_IS_GOOD_NEWS
  1160. chmod 0644 m-vax.h || echo "restore of m-vax.h fails"
  1161. set `wc -c m-vax.h`;Sum=$1
  1162. if test "$Sum" != "789"
  1163. then echo original size 789, current size $Sum;fi
  1164. echo "x - extracting macro.c (Text)"
  1165. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > macro.c &&
  1166. X#include "config.h"
  1167. X#include "keymap.h"
  1168. X#include "term.h"
  1169. X
  1170. Xexport int in_menu_mode = 0;
  1171. Xexport int get_from_macro = 0;
  1172. Xexport int macro_debug = 0;
  1173. X
  1174. X#define M_DUMMY        0    /* do nothing (end of branch)     */
  1175. X
  1176. X#define    M_COMMAND    1    /* a command (get_c())          */
  1177. X#define M_KEY        2    /* a key stroke (get_c())      */
  1178. X#define M_STRING    3    /* a string (get_s())         */
  1179. X
  1180. X#define M_INPUT        4    /* take input from keyboard (get_c/get_s) */
  1181. X
  1182. X#define M_YES        5    /* answer yes to confirmation     */
  1183. X#define M_NO        6    /* answer no to confirmation and break */
  1184. X                /* -- if neither are present, take input */
  1185. X
  1186. X#define M_PROMPT    8    /* prompt(...)              */
  1187. X#define M_ECHO        9    /* msg(...)             */
  1188. X
  1189. X#define M_IS_MENU    10    /* in menu mode ?         */
  1190. X#define M_IS_SHOW    11    /* in reading mode ?         */
  1191. X#define M_IS_GROUP    12    /* are we in a news group ?     */
  1192. X#define M_IS_FOLDER    13    /* are we in a folder ?         */
  1193. X#define M_CONFIRM    14    /* ask for confirmation to procede     */
  1194. X#define M_REJECT    15    /* ask for !confirmation to procede     */
  1195. X#define M_VARTEST    16    /* test value of variable     */
  1196. X#define M_BREAK        17    /* exit from macroes         */
  1197. X#define    M_RETURN    18    /* return from this macro     */
  1198. X
  1199. X
  1200. Xstruct macro {
  1201. X    int            m_type;        /* entry type */
  1202. X    union {
  1203. X    int         mu_int;        /* command or char */
  1204. X    char         *mu_string;    /* string for get_s */
  1205. X    struct macro     *mu_branch;    /* false conditional */
  1206. X    } m_value;
  1207. X    struct macro *m_next;        /* next macro element */
  1208. X};
  1209. X
  1210. X#define m_int        m_value.mu_int
  1211. X#define m_string    m_value.mu_string
  1212. X#define m_branch    m_value.mu_branch
  1213. X
  1214. X#define NMACRO 32        /* max number of macros */
  1215. X#define MSTACK 5        /* max nesting level */
  1216. X
  1217. Xstatic struct macro *macro[NMACRO];     /* macro table */
  1218. X
  1219. Xstatic struct macro *mstack[MSTACK];    /* macro stack */
  1220. Xstatic int cstack[MSTACK];
  1221. Xstatic int m_level = 0;
  1222. X
  1223. Xstatic struct macro *m = NULL;        /* current macro */
  1224. Xstatic int no_advance = 0;
  1225. X
  1226. Xstatic int cur_m;
  1227. X
  1228. X#define MERROR ((struct macro *)1)
  1229. X
  1230. Xinit_macro()
  1231. X{
  1232. X    int n;
  1233. X    
  1234. X    for (n = 0; n < NMACRO; n++)
  1235. X    macro[n] = NULL;
  1236. X}
  1237. X
  1238. Xstatic m_new(t)
  1239. Xint t;
  1240. X{
  1241. X    struct macro *m1;
  1242. X    
  1243. X    m1 = (struct macro *)calloc(1, sizeof(struct macro));
  1244. X    mem_check(m1, sizeof(struct macro), "for macro");
  1245. X
  1246. X    if (m == NULL)
  1247. X    m = macro[cur_m] = m1;
  1248. X    else {
  1249. X    m->m_next = m1;
  1250. X    m = m1;
  1251. X    }
  1252. X    m->m_type = t;
  1253. X    m->m_next = NULL;
  1254. X}
  1255. X
  1256. X
  1257. X/*
  1258. X *    Define macro "id" reading from file f until "end"
  1259. X *
  1260. X *    Macro definition syntax:
  1261. X *        define <id>
  1262. X *           <body>
  1263. X *        end
  1264. X */
  1265. X
  1266. X
  1267. Xm_define(id, f)
  1268. Xchar *id;
  1269. XFILE *f;
  1270. X{
  1271. X    char line[256], *lp, skip;
  1272. X
  1273. X    if (id) {
  1274. X    cur_m = atoi(id);
  1275. X    if (cur_m < 0 || cur_m >= NMACRO) {
  1276. X        m_error("macro number out of range\n", id);
  1277. X        return 0;
  1278. X    }
  1279. X    } else {
  1280. X    for (cur_m = 0; cur_m < NMACRO; cur_m++)
  1281. X        if (macro[cur_m] == NULL) break;
  1282. X    if (cur_m == NMACRO) {
  1283. X        init_message("No unused macro numbers");
  1284. X        return 0;
  1285. X    }
  1286. X    }
  1287. X    
  1288. X    if (f == NULL) {
  1289. X    clrdisp();
  1290. X    printf("DEFINE MACRO %d -- END WITH 'end'\n\n\r", cur_m);
  1291. X    no_raw();
  1292. X    f = stdin;
  1293. X    }
  1294. X    
  1295. X    m = NULL;
  1296. X    skip = 0;
  1297. X
  1298. X    while (fgets(line, 256, f)) {
  1299. X    for (lp = line; *lp && isspace(*lp); lp++);
  1300. X    if (*lp == NUL) continue;
  1301. X    if (strncmp(lp, "end", 3) == 0) goto out;
  1302. X    if (!skip && parse_line(lp)) {
  1303. X        macro[cur_m] = NULL;
  1304. X        skip++;
  1305. X    }
  1306. X    }
  1307. X
  1308. X    if (f != stdin)
  1309. X    m_error("end missing", (char *)NULL);
  1310. X
  1311. X out:
  1312. X    if (f == stdin) raw();
  1313. X    m = NULL;
  1314. X    return 1;
  1315. X}
  1316. X
  1317. Xstatic parse_line(lp)
  1318. Xchar *lp;
  1319. X{
  1320. X    char *word;
  1321. X    struct macro *m1, *branch = NULL;
  1322. X
  1323. X    while (*lp) {
  1324. X    if (*lp == '#') break;
  1325. X    
  1326. X    if (*lp == ':') {
  1327. X        m_new(M_COMMAND);
  1328. X        m->m_int = GETC_COMMAND | K_EXTENDED_CMD;
  1329. X        m_new(M_STRING);
  1330. X        m->m_string = copy_str(lp + 1);
  1331. X        break;
  1332. X    }
  1333. X
  1334. X    if (*lp == '?') {
  1335. X        m_new(M_IS_MENU);
  1336. X        if (branch == NULL) {
  1337. X        m1 = m;
  1338. X        m_new(M_DUMMY);
  1339. X        branch = m;
  1340. X        m = m1;
  1341. X        }
  1342. X        m->m_branch = branch;
  1343. X    }
  1344. X
  1345. X    word = lp;
  1346. X    if (*lp == '"')
  1347. X        do lp++;
  1348. X        while (*lp && *lp != '"');
  1349. X    else
  1350. X    if (*lp == '\'')
  1351. X        do lp++;
  1352. X        while (*lp && *lp != '\'');
  1353. X    else
  1354. X        while (*lp && !isspace(*lp)) lp++;
  1355. X    if (*lp) {
  1356. X        *lp++ = NUL;
  1357. X        while (*lp && isspace(*lp)) lp++;
  1358. X    }
  1359. X    if (parse_word(word)) return 1;
  1360. X    }
  1361. X
  1362. X    if (branch) {
  1363. X    m->m_next = branch;
  1364. X    m = branch;
  1365. X    }
  1366. X    return 0;
  1367. X}
  1368. X
  1369. Xstatic parse_word(w)
  1370. Xchar *w;
  1371. X{
  1372. X    int cmd;
  1373. X    register struct macro *m1;
  1374. X    
  1375. X    if (m && m->m_type == M_COMMAND && m->m_int == (GETC_COMMAND | K_MACRO)) {
  1376. X    if (isdigit(*w)) {
  1377. X        m->m_int |= atoi(w);
  1378. X        goto ok;
  1379. X    }
  1380. X    m_error("macro number missing", (char *)NULL);
  1381. X    return 1;
  1382. X    }
  1383. X
  1384. X    if (*w == '"') {
  1385. X    if (m == NULL || (m->m_type != M_PROMPT && m->m_type != M_ECHO))
  1386. X        m_new(M_STRING);
  1387. X    m->m_string = copy_str(w + 1);
  1388. X    goto ok;
  1389. X    }
  1390. X
  1391. X    if (*w == '\'') {
  1392. X    m_new(M_KEY);
  1393. X    m->m_int = parse_key(w + 1);
  1394. X    goto ok;
  1395. X    }
  1396. X
  1397. X    if (*w == '?') {
  1398. X    if (strchr(w, '=')) {
  1399. X        m->m_type = M_VARTEST;
  1400. X        m1 = m;
  1401. X        m_new(M_DUMMY);
  1402. X        m->m_branch = m1->m_branch;
  1403. X        m1->m_string = copy_str(w + 1);
  1404. X        goto ok;
  1405. X    }
  1406. X    
  1407. X    switch (w[1]) {
  1408. X     case 'f': /* ?folder */
  1409. X        cmd = M_IS_FOLDER;
  1410. X        break;
  1411. X     case 'g': /* ?group */
  1412. X        cmd = M_IS_GROUP;
  1413. X        break;
  1414. X     case 'm': /* ?menu */
  1415. X        cmd = M_IS_MENU;
  1416. X        break;
  1417. X     case 'n': /* ?no */
  1418. X        cmd = M_REJECT;
  1419. X        break;
  1420. X     case 's': /* ?show */
  1421. X        cmd = M_IS_SHOW;
  1422. X        break;
  1423. X     case 'y': /* ?yes */
  1424. X        cmd = M_CONFIRM;
  1425. X        break;
  1426. X     default:
  1427. X        m_error("unknown conditional %s", w - 1);
  1428. X        return 1;
  1429. X    }
  1430. X    m->m_type = cmd;
  1431. X    goto ok;
  1432. X    }
  1433. X
  1434. X    if ((cmd = lookup_command(w, (K_ONLY_MENU | K_ONLY_MORE))) != K_INVALID) {
  1435. X    m_new(M_COMMAND);
  1436. X    m->m_int = GETC_COMMAND | cmd;
  1437. X    goto ok;
  1438. X    }
  1439. X
  1440. X    if (strcmp(w, "prompt") == 0) {
  1441. X    m_new(M_PROMPT);
  1442. X    m->m_string = "?";
  1443. X    goto ok;
  1444. X    }
  1445. X    if (strcmp(w, "echo") == 0) {
  1446. X    m_new(M_ECHO);
  1447. X    m->m_string = "ups";
  1448. X    goto ok;
  1449. X    }
  1450. X    if (strcmp(w, "input") == 0) {
  1451. X    m_new(M_INPUT);
  1452. X    goto ok;
  1453. X    }
  1454. X    if (strcmp(w, "yes") == 0) {
  1455. X    m_new(M_YES);
  1456. X    goto ok;
  1457. X    }
  1458. X    if (strcmp(w, "no") == 0) {
  1459. X    m_new(M_NO);
  1460. X    goto ok;
  1461. X    }
  1462. X    if (strcmp(w, "break") == 0) {
  1463. X    m_new(M_BREAK);
  1464. X    goto ok;
  1465. X    }
  1466. X    if (strcmp(w, "return") == 0) {
  1467. X    m_new(M_RETURN);
  1468. X    goto ok;
  1469. X    }
  1470. X
  1471. X    m_error("Unknown word >>%s<<", w);
  1472. X    return 1;
  1473. X
  1474. X ok:
  1475. X    return 0;
  1476. X}
  1477. X
  1478. X/*
  1479. X *    Invoke macro # N
  1480. X */
  1481. X
  1482. Xm_invoke(n)
  1483. Xint n;
  1484. X{
  1485. X    if (n < 0 || n > NMACRO || macro[n] == NULL) {
  1486. X    msg("undefined macro %d", n);
  1487. X    return;
  1488. X    }
  1489. X
  1490. X    if (m == NULL)
  1491. X    no_advance = 0;
  1492. X    else {
  1493. X    if (m_level == MSTACK) {
  1494. X        msg("Macro stack overflow");
  1495. X        m = NULL;
  1496. X        m_level = 0;
  1497. X        return;
  1498. X    }
  1499. X    mstack[m_level] = m;
  1500. X    cstack[m_level] = cur_m;
  1501. X    m_level++;
  1502. X    }
  1503. X
  1504. X    cur_m = n;
  1505. X    m = macro[cur_m];
  1506. X}
  1507. X
  1508. Xm_startinput()
  1509. X{
  1510. X    no_advance = 1;
  1511. X}
  1512. X
  1513. Xm_endinput()
  1514. X{
  1515. X    if (no_advance) {
  1516. X    no_advance = 0;
  1517. X    if (m && m->m_type == M_INPUT)
  1518. X        m = m->m_next;
  1519. X    }
  1520. X}
  1521. X
  1522. Xm_advinput()
  1523. X{
  1524. X    if (m && m->m_type == M_INPUT)
  1525. X    m = m->m_next;
  1526. X}
  1527. X
  1528. Xstatic struct macro *m_call(who)
  1529. Xint who;
  1530. X{
  1531. X    struct macro *m1;
  1532. X
  1533. X    for (;;) {
  1534. X    while (m == NULL && m_level > 0) {
  1535. X        m_level--;
  1536. X        m = mstack[m_level];
  1537. X        cur_m = cstack[m_level];
  1538. X    }
  1539. X    if (m == NULL) {
  1540. X        if (macro_debug) msg("end");
  1541. X        return NULL;
  1542. X    }
  1543. X    
  1544. X    if (macro_debug) 
  1545. X        macro_dbg();
  1546. X        
  1547. X    if (who == 3) {
  1548. X        if (m->m_type == M_YES || m->m_type == M_NO) goto out;
  1549. X        return NULL;
  1550. X    }
  1551. X
  1552. X    switch (m->m_type) {
  1553. X     case M_COMMAND:
  1554. X     case M_KEY:
  1555. X        if (who == 1) goto out;
  1556. X        goto err;
  1557. X
  1558. X     case M_STRING:
  1559. X        if (who == 2) goto out;
  1560. X        goto err;
  1561. X
  1562. X     case M_INPUT:
  1563. X        if (no_advance) return m;
  1564. X        goto out;
  1565. X
  1566. X     case M_YES:
  1567. X     case M_NO:
  1568. X     case M_DUMMY:
  1569. X        break;
  1570. X
  1571. X     case M_PROMPT:
  1572. X        prompt("\1%s\1 ", m->m_string);
  1573. X        break;
  1574. X
  1575. X     case M_ECHO:
  1576. X        msg(m->m_string);
  1577. X        break;
  1578. X
  1579. X     case M_IS_MENU:
  1580. X        if (!in_menu_mode) m = m->m_branch;
  1581. X        break;
  1582. X     case M_IS_SHOW:
  1583. X        if (in_menu_mode) m = m->m_branch;
  1584. X        break;
  1585. X     case M_IS_GROUP:
  1586. X        if (current_group->group_flag & G_FOLDER) m = m->m_branch;
  1587. X        break;
  1588. X     case M_IS_FOLDER:
  1589. X        if ((current_group->group_flag & G_FOLDER) == 0) m = m->m_branch;
  1590. X        break;
  1591. X     case M_CONFIRM:
  1592. X        if (!yes(0)) m = m->m_branch;
  1593. X        break;
  1594. X     case M_REJECT:
  1595. X        if (yes(0)) m = m->m_branch;
  1596. X        break;
  1597. X
  1598. X     case M_VARTEST:
  1599. X        m1 = m;
  1600. X        m = m->m_next;
  1601. X        
  1602. X        switch (test_variable(m1->m_string)) {
  1603. X         case 0:
  1604. X        m = m->m_branch;
  1605. X        break;
  1606. X         case -1:
  1607. X        goto err1;
  1608. X        }
  1609. X        break;
  1610. X        
  1611. X     case M_RETURN:
  1612. X        m = NULL;
  1613. X        continue;
  1614. X
  1615. X     case M_BREAK:
  1616. X        goto term;
  1617. X    }
  1618. X
  1619. X    m = m->m_next;
  1620. X    }
  1621. X
  1622. X out:
  1623. X    m1 = m;
  1624. X    m = m->m_next;
  1625. X    no_advance = 0;
  1626. X    return m1;
  1627. X
  1628. X err:
  1629. X    msg("Error in macro %d", cur_m);
  1630. X err1:
  1631. X    user_delay(1);
  1632. X    m = NULL;
  1633. X    m_level = 0;
  1634. X    return MERROR;
  1635. X
  1636. X term:
  1637. X    m = NULL;
  1638. X    m_level = 0;
  1639. X    return NULL;
  1640. X}
  1641. X
  1642. Xm_break()
  1643. X{
  1644. X    m = NULL;
  1645. X    m_level = 0;
  1646. X}
  1647. X
  1648. Xmacro_dbg()
  1649. X{
  1650. X    extern char *command_name(), *key_name();
  1651. X    char *name;
  1652. X    
  1653. X    switch (m->m_type) {
  1654. X     case M_COMMAND:
  1655. X    msg("COMMAND: %s", command_name(m->m_int));
  1656. X    goto delay;
  1657. X    
  1658. X     case M_KEY:
  1659. X    msg("KEY: %s", key_name(m->m_int));
  1660. X    goto delay;
  1661. X    
  1662. X     case M_STRING:
  1663. X    msg("STRING: %s", m->m_string);
  1664. X    goto delay;
  1665. X    
  1666. X     case M_INPUT:
  1667. X    name = "input";
  1668. X    break;
  1669. X    
  1670. X     case M_YES:
  1671. X    name = "yes";
  1672. X    break;
  1673. X    
  1674. X     case M_NO:
  1675. X    name = "no";
  1676. X    break;
  1677. X    
  1678. X     case M_DUMMY:
  1679. X    name = "dummy";
  1680. X    break;
  1681. X    
  1682. X     case M_PROMPT:
  1683. X    msg("PROMPT: %s", m->m_string);
  1684. X    goto delay;
  1685. X    
  1686. X     case M_ECHO:
  1687. X    msg("ECHO: %s", m->m_string);
  1688. X    goto delay;
  1689. X    
  1690. X     case M_IS_MENU:
  1691. X    msg("?menu => %d", in_menu_mode);
  1692. X    goto delay;
  1693. X
  1694. X     case M_IS_SHOW:
  1695. X    msg("?show => %d", !in_menu_mode);
  1696. X    goto delay;
  1697. X
  1698. X     case M_IS_GROUP:
  1699. X    msg("?group => %d", (current_group->group_flag & G_FOLDER) == 0);
  1700. X    goto delay;
  1701. X
  1702. X     case M_IS_FOLDER:
  1703. X    msg("?group => %d", (current_group->group_flag & G_FOLDER));
  1704. X    goto delay;
  1705. X
  1706. X     case M_CONFIRM:
  1707. X    name = "?yes";
  1708. X    break;
  1709. X
  1710. X     case M_REJECT:
  1711. X    name = "?no";
  1712. X    break;
  1713. X    
  1714. X     case M_VARTEST:
  1715. X    msg("?%s => %d", m->m_string, test_variable(m->m_string));
  1716. X    goto delay;
  1717. X    
  1718. X     case M_RETURN:
  1719. X    name = "return";
  1720. X    break;
  1721. X
  1722. X     case M_BREAK:
  1723. X    name = "break";
  1724. X    break;
  1725. X    }
  1726. X    msg(name);
  1727. X
  1728. X delay:
  1729. X    user_delay(1);
  1730. X}    
  1731. X/*
  1732. X *    Macro processing for get_c()
  1733. X */
  1734. X
  1735. Xm_getc(cp)
  1736. Xint *cp;
  1737. X{
  1738. X    struct macro *m1;
  1739. X    
  1740. X    get_from_macro = 0;
  1741. X    if (m && (m1 = m_call(1))) {
  1742. X    if (m1 == MERROR) return 2;
  1743. X    if (m1->m_type == M_INPUT) return 0;
  1744. X    *cp = m1->m_int;
  1745. X    get_from_macro = 1;
  1746. X    return 1;
  1747. X    }
  1748. X    return 0;
  1749. X}
  1750. X
  1751. X/*
  1752. X *    Macro processing for get_s()
  1753. X */
  1754. X
  1755. Xm_gets(s)
  1756. Xchar *s;
  1757. X{
  1758. X    struct macro *m1;
  1759. X
  1760. X    get_from_macro = 0;
  1761. X    if (m && (m1 = m_call(2))) {
  1762. X    if (m1 == MERROR) return 2;
  1763. X    if (m1->m_type == M_INPUT) return 0;
  1764. X    strcpy(s, m1->m_string);
  1765. X    get_from_macro = 1;
  1766. X    return 1;
  1767. X    }
  1768. X    return 0;
  1769. X}
  1770. X
  1771. X/*
  1772. X *    Macro processing for yes()
  1773. X */
  1774. X
  1775. Xm_yes()
  1776. X{
  1777. X    struct macro *m1;
  1778. X
  1779. X    if (m) {
  1780. X    if (m1 = m_call(3))
  1781. X        if (m1->m_type == M_NO)
  1782. X        return 1;
  1783. X        else
  1784. X        return 2;
  1785. X    else
  1786. X        return 3;
  1787. X    }
  1788. X    return 0;
  1789. X}
  1790. X
  1791. Xstatic m_error(fmt, arg)
  1792. Xchar *fmt, *arg;
  1793. X{
  1794. X    char buf[80];
  1795. X
  1796. X   if (arg) {
  1797. X       sprintf(buf, fmt, arg);
  1798. X       fmt = buf;
  1799. X   }
  1800. X
  1801. X   init_message("Error in macro %d: %s", cur_m, fmt);
  1802. X}
  1803. NO_NEWS_IS_GOOD_NEWS
  1804. chmod 0644 macro.c || echo "restore of macro.c fails"
  1805. set `wc -c macro.c`;Sum=$1
  1806. if test "$Sum" != "10847"
  1807. then echo original size 10847, current size $Sum;fi
  1808. echo "x - extracting master.c (Text)"
  1809. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > master.c &&
  1810. X/*
  1811. X *    nn master daemon
  1812. X *
  1813. X *    maintains the article header database.
  1814. X */
  1815. X
  1816. X#include <signal.h>
  1817. X#include <errno.h>
  1818. X#include "config.h"
  1819. X#include "db.h"
  1820. X
  1821. X/*
  1822. X * nnmaster options:
  1823. X *
  1824. X *    -e N    expire a group if more than N articles are gone
  1825. X *    -r N    repeat every N minutes
  1826. X *
  1827. X *    -E    expire by recolleting entire groups rather than copying files
  1828. X *    -C    check consistency of database on start-up
  1829. X *
  1830. X *    -I    initialize
  1831. X *    -t    trace collection of each group
  1832. X *    -v    print version and exit
  1833. X *    -u    update even if active is not modified
  1834. X *    -w    send wakeup to real master
  1835. X *    -D    debug
  1836. X */
  1837. X
  1838. X#include "options.h"
  1839. X
  1840. Xstatic int
  1841. X    initialize = 0,
  1842. X    prt_vers = 0,
  1843. X    unconditional = 0,
  1844. X    wakeup_master = 0,
  1845. X    expire_level = 1,
  1846. X    clean_to_expire = 0,
  1847. X    check_on_startup = 0,
  1848. X    repeat_delay = 0,
  1849. X    debug_mode = 0;
  1850. X
  1851. Xexport int
  1852. X    trace = 0,
  1853. X#ifdef NNTP
  1854. X    silent = 1,
  1855. X#endif
  1856. X    Debug = 0;
  1857. X
  1858. X
  1859. XOption_Description(master_options) {
  1860. X
  1861. X    'I', Bool_Option( initialize ),
  1862. X    'v', Bool_Option( prt_vers ),
  1863. X    'u', Bool_Option( unconditional ),
  1864. X    'w', Bool_Option( wakeup_master ),
  1865. X
  1866. X    'e', Int_Option( expire_level ),
  1867. X    'r', Int_Option_Optional( repeat_delay, 10 ),
  1868. X
  1869. X    'E', Bool_Option( clean_to_expire ),
  1870. X    'C', Bool_Option( check_on_startup ),
  1871. X
  1872. X    'D', Bool_Option( debug_mode ),
  1873. X    't', Bool_Option( trace ),
  1874. X
  1875. X    '\0',
  1876. X};
  1877. X
  1878. X
  1879. Ximport FILE *master_file;
  1880. Ximport char news_active[];
  1881. X
  1882. Xstatic int rm_mpid_on_exit = 0;
  1883. X
  1884. Xmain(argc, argv)
  1885. Xint argc;
  1886. Xchar **argv;
  1887. X{
  1888. X    time_t             age_active;
  1889. X    register group_header    *gh;
  1890. X    register int        cur_group;
  1891. X    int                col_article_count, col_group_count;
  1892. X    int                exp_article_count, exp_group_count;
  1893. X    int                temp;
  1894. X    time_t            start_time;
  1895. X    FILE            *m_pid;
  1896. X    
  1897. X
  1898. X    umask(002);            /* avoid paranoia */
  1899. X    
  1900. X    init_global(1);
  1901. X
  1902. X    parse_options(argc, argv, (char *)NULL, master_options, (char *)NULL);
  1903. X
  1904. X    if (wakeup_master) {
  1905. X    if (!kill_master(SIGALRM) && errno == ESRCH)
  1906. X        printf("master is not running\n");
  1907. X    nn_exit(0);
  1908. X    }
  1909. X    
  1910. X    if (prt_vers) {
  1911. X    print_version("Master: Release %R.%V.%P, Compilation %U\n");
  1912. X    nn_exit(0);
  1913. X    }
  1914. X
  1915. X    if (kill_master(SIGALRM)) {
  1916. X    printf("The master is already running\n");
  1917. X    nn_exit(0);
  1918. X    }
  1919. X#ifdef NNTP
  1920. X    nntp_check();
  1921. X#endif
  1922. X    if (initialize) {
  1923. X    build_master();
  1924. X    nn_exit(0);
  1925. X    }
  1926. X
  1927. X    if (repeat_delay && !debug_mode) {
  1928. X    while ((temp = fork()) < 0) sleep(1);
  1929. X    if (temp) nn_exit(0);
  1930. X
  1931. X    process_id = getpid();    /* init_global saved parent's pid */
  1932. X    
  1933. X    DETATCH_TERMINAL
  1934. X    }
  1935. X
  1936. X    rm_mpid_on_exit = 1;
  1937. X    m_pid = open_file(relative(lib_directory, "MPID"),
  1938. X              OPEN_CREATE|MUST_EXIST);
  1939. X    fprintf(m_pid, "%d\n", process_id);
  1940. X    fclose(m_pid);
  1941. X
  1942. X    log_entry('M', "Master started -r%d -e%d%s", 
  1943. X               repeat_delay, expire_level, clean_to_expire ? " -E" : "");
  1944. X
  1945. X    if (check_on_startup) {
  1946. X    char cmd[FILENAME];
  1947. X    sprintf(cmd, "%s/nnadmin Z", BIN_DIRECTORY);
  1948. X    system(cmd);
  1949. X    log_entry('M', "Database validation completed");
  1950. X    }
  1951. X    
  1952. X    repeat_delay *= 60;
  1953. X    
  1954. X    init_digest_parsing();
  1955. X    
  1956. X    open_master(OPEN_READ);
  1957. X    close_master();
  1958. X
  1959. X    open_master(OPEN_UPDATE);
  1960. X    
  1961. X again:
  1962. X
  1963. X#ifdef NNTP
  1964. X    if (use_nntp) {
  1965. X    if (nntp_get_active() < 0) {
  1966. X        nntp_close_server();
  1967. X        current_group = NULL; /* for init_group */
  1968. X        log_entry('N', "Can't access active file --- %s",
  1969. X              repeat_delay ? "sleeping" : "termating");
  1970. X        if (repeat_delay == 0)
  1971. X        nn_exit(1);
  1972. X        sleep(repeat_delay);
  1973. X        goto again;
  1974. X    }
  1975. X    }
  1976. X#endif
  1977. X
  1978. X    age_active = file_exist(news_active, "fr");
  1979. X#ifdef NNTP
  1980. X    if (!use_nntp)
  1981. X#endif
  1982. X    if (age_active == (time_t)0)
  1983. X        sys_error("Cannot access active file");
  1984. X
  1985. X    temp = receive_admin();
  1986. X    
  1987. X    if (!temp && !unconditional && age_active <= master.last_scan) {
  1988. X    if (repeat_delay == 0)
  1989. X        goto out;
  1990. X    
  1991. X    if (s_hangup) goto out;
  1992. X#ifdef NNTP
  1993. X    if (use_nntp)
  1994. X        nntp_cleanup();
  1995. X#endif /* NNTP */
  1996. X    if (debug_mode) 
  1997. X        printf("NONE (*** SLEEP ***)\n");
  1998. X    else {
  1999. X        if (trace) log_entry('T', "none");
  2000. X        sleep(repeat_delay);
  2001. X    }
  2002. X    
  2003. X    if (s_hangup) goto out;
  2004. X
  2005. X    goto again;
  2006. X    }
  2007. X
  2008. X    unconditional = 0;    /* only first pass */
  2009. X    
  2010. X    time(&start_time);
  2011. X    col_article_count = col_group_count = 0;
  2012. X    exp_article_count = exp_group_count = 0;
  2013. X    
  2014. X    visit_active_file();
  2015. X        
  2016. X    for (cur_group = 0; cur_group < master.number_of_groups; cur_group++) {
  2017. X
  2018. X    if (s_hangup) break;
  2019. X
  2020. X    gh = &active_groups[cur_group];
  2021. X
  2022. X    if (gh->group_flag & G_NO_DIRECTORY) {
  2023. X        if (gh->group_flag & G_BLOCKED) goto unblock_group;
  2024. X        continue;
  2025. X    }
  2026. X    
  2027. X    if (gh->last_l_article  > gh->last_article || 
  2028. X        gh->first_l_article > gh->first_article) {
  2029. X        log_entry('X', "group %s renumbered", gh->group_name);
  2030. X        clean_group(gh);
  2031. X
  2032. X        goto do_collect;
  2033. X    }
  2034. X
  2035. X    if (expire_level > 0 && gh->last_l_article > 0) {
  2036. X        if ((gh->first_l_article + expire_level) <= gh->first_article) {
  2037. X        if (trace) log_entry('T', "%s expire level", gh->group_name);
  2038. X        gh->group_flag |= G_EXPIRE;
  2039. X        goto do_collect;
  2040. X        }
  2041. X        
  2042. X        if (gh->first_article > gh->last_l_article) {
  2043. X        if (trace) log_entry('T', "%s expire void", gh->group_name);
  2044. X        clean_group(gh);
  2045. X        goto do_collect;
  2046. X        }
  2047. X    }
  2048. X
  2049. X    if (gh->last_l_article == gh->last_article) {
  2050. X        if (gh->group_flag & G_BLOCKED) goto unblock_group;
  2051. X        continue;
  2052. X    }
  2053. X    
  2054. X     do_collect:
  2055. X    if (!init_group(gh)) {
  2056. X        log_entry('R', "%s: no directory", gh->group_name);
  2057. X        gh->group_flag |= G_NO_DIRECTORY;
  2058. X        gh->group_flag &= ~(G_EXPIRE | G_BLOCKED);        
  2059. X        save_group(current_group);
  2060. X        continue;
  2061. X    }
  2062. X    
  2063. X    if (gh->group_flag & G_EXPIRE) {
  2064. X        if (clean_to_expire) {
  2065. X        temp = gh->first_article - gh->first_l_article;
  2066. X        clean_group(gh);
  2067. X        } else {
  2068. X        if ((gh->group_flag & G_BLOCKED) == 0) {
  2069. X            gh->group_flag |= G_BLOCKED;
  2070. X            save_group(gh);
  2071. X        }
  2072. X        temp = expire_group(gh);
  2073. X        }
  2074. X        if (temp) {
  2075. X        exp_article_count += temp;
  2076. X        exp_group_count++;
  2077. X        }
  2078. X    }
  2079. X        
  2080. X    temp = collect_group(gh);
  2081. X#ifdef NNTP
  2082. X    if (temp < 0) {
  2083. X        /* connection broken */
  2084. X        gh->group_flag &= ~G_EXPIRE;    /* remains blocked */
  2085. X        save_group(gh);
  2086. X        age_active = master.last_scan;     /* did not complete */
  2087. X        current_group = NULL; /* for init_group */
  2088. X        break;
  2089. X    }
  2090. X#endif
  2091. X    if (temp > 0) {
  2092. X        col_article_count += temp;
  2093. X        col_group_count++;
  2094. X    }
  2095. X
  2096. X     unblock_group:
  2097. X    if (temp || (gh->group_flag & G_BLOCKED)) {
  2098. X        gh->group_flag &= ~(G_EXPIRE | G_BLOCKED);
  2099. X        save_group(gh);
  2100. X    }
  2101. X    }
  2102. X
  2103. X    /* if master is interrupted, all new articles may not be collected */
  2104. X
  2105. X    if (!s_hangup) 
  2106. X    master.last_scan = age_active;
  2107. X
  2108. X    save_master();
  2109. X
  2110. X    if (exp_article_count)
  2111. X    log_entry('X', "Expire: %3d art, %2d gr, %2ld s %s",
  2112. X          exp_article_count, exp_group_count, 
  2113. X          time((time_t *)0) - start_time,
  2114. X          col_article_count ? "(incl. collect)" : "");
  2115. X
  2116. X    if (col_article_count)
  2117. X    log_entry('C', "Collect: %3d art, %2d gr, %2ld s %s",
  2118. X          col_article_count, col_group_count,
  2119. X          time((time_t *)0) - start_time,
  2120. X          exp_article_count ? "(incl. expire)" : "");
  2121. X    
  2122. X    if (!s_hangup && repeat_delay) {
  2123. X#ifdef NNTP
  2124. X    if (use_nntp)
  2125. X        nntp_cleanup();
  2126. X#endif /* NNTP */
  2127. X    if (!debug_mode) sleep(repeat_delay);
  2128. X    if (!s_hangup) goto again;
  2129. X    }
  2130. X    
  2131. X out:
  2132. X    nn_exit(0);
  2133. X    /*NOTREACHED*/
  2134. X}
  2135. X
  2136. X
  2137. X/* 
  2138. X * nn_exit() --- called whenever a program exits.
  2139. X */
  2140. Xnn_exit(n)
  2141. X{
  2142. X#ifdef NNTP
  2143. X    if (use_nntp)
  2144. X    nntp_cleanup();
  2145. X#endif /* NNTP */
  2146. X    close_master();
  2147. X
  2148. X    if (rm_mpid_on_exit)
  2149. X    unlink(relative(lib_directory, "MPID"));
  2150. X
  2151. X    if (n)
  2152. X    log_entry('E', "Abnormal termination, exit=%d", n);
  2153. X    else
  2154. X    if (rm_mpid_on_exit)
  2155. X    log_entry('M', "Master terminated%s", s_hangup ? " (hangup)" : "");
  2156. X
  2157. X    exit(n);
  2158. X}
  2159. X
  2160. X
  2161. X/*
  2162. X * add new group to master file
  2163. X */
  2164. X
  2165. Xgroup_header *add_new_group(name)
  2166. Xchar *name;
  2167. X{
  2168. X    register group_header *gh;
  2169. X    FILE *group_file;
  2170. X    static has_warned = 0;
  2171. X    
  2172. X    if (master.free_groups <= 0) {
  2173. X    if (!has_warned) {
  2174. X        log_entry('R', "NO MORE FREE GROUP SLOTS -- RESTART MASTER");
  2175. X        has_warned++;
  2176. X    }
  2177. X    return NULL;
  2178. X    }
  2179. X    
  2180. X    master.free_groups--;
  2181. X    
  2182. X    gh = &active_groups[master.number_of_groups];
  2183. X    sorted_groups[master.number_of_groups] = gh;
  2184. X    
  2185. X    gh->group_name_length = strlen(name);
  2186. X    gh->group_name = (char *)malloc(gh->group_name_length + 1);
  2187. X    mem_check(gh->group_name, gh->group_name_length, "bytes for group name");
  2188. X    strcpy(gh->group_name, name);
  2189. X    
  2190. X    gh->group_num = master.number_of_groups++;
  2191. X    
  2192. X    group_file = open_groups(OPEN_UPDATE|MUST_EXIST);
  2193. X    
  2194. X    fseek(group_file, master.next_group_write_offset, 0);
  2195. X    name[gh->group_name_length] = NL;
  2196. X    Fwrite(name, sizeof(char), gh->group_name_length + 1, group_file);
  2197. X    name[gh->group_name_length] = NUL;
  2198. X    fclose(group_file);
  2199. X    
  2200. X    master.next_group_write_offset += gh->group_name_length + 1;
  2201. X
  2202. X    clean_group(gh);
  2203. X    
  2204. X    save_master();
  2205. X
  2206. X    sort_groups();
  2207. X
  2208. X    log_entry('C', "new group: %s (%d)", gh->group_name, gh->group_num);
  2209. X    
  2210. X    return gh;
  2211. X}
  2212. X
  2213. X
  2214. Xsave_group(gh)
  2215. Xgroup_header *gh;
  2216. X{
  2217. X    int flag;
  2218. X    
  2219. X    flag = gh->group_flag;
  2220. X    gh->group_flag &= G_MASTER_FLAGS;
  2221. X
  2222. X    if (!db_write_group(master_file, gh, gh->group_num))
  2223. X    write_error();
  2224. X    fflush(master_file);
  2225. X    
  2226. X    gh->group_flag = flag;
  2227. X}
  2228. X
  2229. X
  2230. Xsave_master()
  2231. X{
  2232. X    rewind(master_file);
  2233. X    if (!db_write_master(master_file, &master))
  2234. NO_NEWS_IS_GOOD_NEWS
  2235. echo "End of part 6"
  2236. echo "File master.c is continued in part 7"
  2237. echo "7" > s2_seq_.tmp
  2238. exit 0
  2239. ---
  2240. Kim F. Storm        storm@texas.dk        Tel +45 429 174 00
  2241. Texas Instruments, Marielundvej 46E, DK-2730 Herlev, Denmark
  2242.       No news is good news, but nn is better!
  2243.  
  2244.