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

  1. Subject:  v19i068:  NN, a Usenet news reader, Part07/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 68
  8. Archive-name: nn/part07
  9.  
  10. #!/bin/sh
  11. # this is part 7 of a multipart archive
  12. # do not concatenate these parts, unpack them in order with /bin/sh
  13. # file master.c continued
  14. #
  15. CurArch=7
  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 master.c"
  26. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' >> master.c
  27. X    write_error();
  28. X    fflush(master_file);
  29. X}
  30. X
  31. X
  32. Xclean_group(gh)
  33. Xregister group_header *gh;
  34. X{
  35. X    if (trace)
  36. X    log_entry('T', "CLEAN %s", gh->group_name);
  37. X    
  38. X    gh->first_l_article = 0;
  39. X    gh->last_l_article = 0;
  40. X
  41. X    gh->index_write_offset = (off_t)0;
  42. X    gh->data_write_offset = (off_t)0;
  43. X
  44. X    gh->group_flag &= ~G_EXPIRE;
  45. X    gh->group_flag |= G_BLOCKED;
  46. X    
  47. X    save_group(gh);
  48. X}
  49. X
  50. X/*
  51. X *    Build initial master file ; calls Initialize script and
  52. X *    reads info from its standard output
  53. X */
  54. X
  55. Xbuild_master()
  56. X{
  57. X    char command[512];
  58. X    char groupname[512];
  59. X    group_header group;
  60. X    FILE *group_file, *src;
  61. X    int lcount, use_group_file;
  62. X
  63. X
  64. X    printf("Confirm initialization by typing 'OK': ");
  65. X    fl;
  66. X    gets(command);
  67. X    if (strcmp(command, "OK")) {
  68. X    printf("No initialization\n");
  69. X    nn_exit(0);
  70. X    }
  71. X
  72. X    printf("Initializing master data base...");
  73. X    fl;
  74. X    
  75. X    if (chdir(lib_directory) < 0)    /* so we can use open_file */
  76. X    sys_error("lib");
  77. X
  78. X#ifdef NNTP
  79. X    if (use_nntp && nntp_get_active() < 0)
  80. X        sys_error("Can't get active file");
  81. X#endif
  82. X    /* check active file for duplicates */
  83. X
  84. X    sprintf(command, "awk 'NF>0{print $1}' %s | sort | uniq -d", news_active);
  85. X    
  86. X    src = popen(command, "r");
  87. X
  88. X    for (lcount = 0; fgets(groupname, 512, src); lcount++) {
  89. X    if (lcount == 0)
  90. X        printf("\n%s contains duplicate entries for the following groups:",
  91. X           news_active);
  92. X        
  93. X    fputs(groupname, stdout);
  94. X    }
  95. X
  96. X    pclose(src);
  97. X
  98. X    if (lcount > 0) {
  99. X    printf("Do you want to repair this file before continuing ? (y)");
  100. X    gets(command);
  101. X    if (command[0] == NUL || command[0] == 'y' || command[0] == 'Y')
  102. X        nn_exit(0);
  103. X    }
  104. X
  105. X    /* if a "GROUPS" file exist offer to use that, else */
  106. X    /* read group names from active file */
  107. X
  108. X    use_group_file = 0;
  109. X    
  110. X    if (src = open_groups(OPEN_READ)) {
  111. X    printf("\nA GROUPS file already exist -- reuse it? (y)");
  112. X    fl;
  113. X    gets(command);
  114. X    if (command[0] == NUL || command[0] == 'y' || command[0] == 'Y') {
  115. X        use_group_file = 1;
  116. X    } else
  117. X        fclose(src);
  118. X    }
  119. X    
  120. X    if (!use_group_file) {
  121. X    strcpy(command, "awk 'NF>0{print $1}' ");
  122. X    strcat(command, news_active);
  123. X    strcat(command, " | sort -u");
  124. X        
  125. X    src = popen(command, "r");
  126. X
  127. X    group_file = open_groups(OPEN_CREATE|MUST_EXIST);
  128. X    }
  129. X    
  130. X    open_master(OPEN_CREATE);
  131. X
  132. X    fseek(master_file, sizeof(master), 0);
  133. X    
  134. X    master.number_of_groups = 0;
  135. X    
  136. X    while (fgets(groupname, 512, src)) {
  137. X
  138. X    group.group_num = master.number_of_groups++;
  139. X    
  140. X    group.group_name_length = strlen(groupname) - 1;    /* strip NL */
  141. X    groupname[group.group_name_length] = NUL;
  142. X    group.group_name = groupname;
  143. X
  144. X    init_group(&group);
  145. X
  146. X    clean_group(&group);
  147. X    
  148. X    group.group_flag = 0;
  149. X
  150. X    /* moderation flag will be set by first visit_active_file call */
  151. X
  152. X    if (strcmp(groupname, "control") == 0)
  153. X        group.group_flag |= G_CONTROL;
  154. X    
  155. X    save_group(&group);
  156. X
  157. X    if (!use_group_file) {
  158. X        groupname[group.group_name_length] = NL;
  159. X        Fwrite(groupname, sizeof(char), 
  160. X           group.group_name_length + 1, group_file);
  161. X    }
  162. X    }
  163. X
  164. X    if (use_group_file) {
  165. X    master.next_group_write_offset = ftell(src);
  166. X    fclose(src);
  167. X    } else {
  168. X    master.next_group_write_offset = ftell(group_file);
  169. X    fclose(group_file);
  170. X    pclose(src);
  171. X    }
  172. X    
  173. X    master.last_scan = 0;
  174. X
  175. X    save_master();
  176. X    
  177. X    close_master();
  178. X
  179. X    printf("done\n");
  180. X
  181. X    log_entry('M', "Master data base initialized");
  182. X    
  183. X    fl;
  184. X}
  185. X
  186. X
  187. X/*
  188. X * receive commands from administrator
  189. X */
  190. X
  191. Xreceive_admin()
  192. X{
  193. X    FILE *gate;
  194. X    char buffer[128], *bp;
  195. X    char command, *user_date;
  196. X    long arg1, arg2;
  197. X    int must_collect;
  198. X    register group_header *gh;
  199. X    
  200. X    gate = open_file(relative(lib_directory, "GATE"), OPEN_READ | OPEN_UNLINK);
  201. X    if (gate == NULL) return 0;
  202. X    
  203. X    sleep(2);    /* give administrator time to flush buffers */
  204. X
  205. X    must_collect = 0;
  206. X    
  207. X    while (fgets(buffer, 128, gate)) {
  208. X    bp = buffer;
  209. X    command = *bp;
  210. X    if ((bp = strchr(bp, ';')) == NULL) continue;
  211. X    arg1 = atol(++bp);
  212. X    if ((bp = strchr(bp, ';')) == NULL) continue;
  213. X    arg2 = atol(++bp);
  214. X    if ((bp = strchr(bp, ';')) == NULL) continue;
  215. X    user_date = ++bp;
  216. X    if ((bp = strchr(bp, ';')) == NULL) continue;
  217. X    *bp++ = NUL;
  218. X    if (*bp != NL) continue;
  219. X    
  220. X    log_entry('A', "RECV %c %ld %ld (%s)",
  221. X          command, arg1, arg2, user_date);
  222. X
  223. X    if (arg1 >= 0 && arg1 < master.number_of_groups)
  224. X        gh = &active_groups[arg1];
  225. X    else
  226. X        gh = NULL;
  227. X    
  228. X    switch (command) {
  229. X
  230. X     case 'r':
  231. X        repeat_delay = arg1;
  232. X        continue;
  233. X        
  234. X     case 'e':
  235. X        expire_level = arg1;
  236. X        continue;
  237. X        
  238. X     case 'X':    /* expire */
  239. X        if (gh) {
  240. X        gh->group_flag |= G_EXPIRE | G_BLOCKED;
  241. X        save_group(gh);
  242. X        break;
  243. X        } 
  244. X        visit_active_file();    /* just in case */
  245. X        Loop_Groups_Header(gh) {
  246. X        if (gh->first_l_article + arg2 < gh->first_article) {
  247. X            gh->group_flag |= G_EXPIRE;
  248. X            save_group(gh);    /* could block here */
  249. X        }
  250. X        }
  251. X        break;
  252. X
  253. X     case 'S':    /* set flag */
  254. X        gh->group_flag |= arg2;
  255. X        save_group(gh);
  256. X        continue;
  257. X
  258. X     case 'C':    /* clear flag */
  259. X        gh->group_flag |= arg2;
  260. X        save_group(gh);
  261. X        continue;
  262. X
  263. X     case 'R':    /* recollect */
  264. X        if (gh) {
  265. X        clean_group(gh);
  266. X        } else
  267. X        Loop_Groups_Header(gh)
  268. X            clean_group(gh);
  269. X        break;
  270. X
  271. X     case 'U':    /* unconditional pass */
  272. X        unconditional++;
  273. X        break;
  274. X
  275. X     case 'T':    /* toggle trace flag */
  276. X        trace = !trace;
  277. X        continue;
  278. X        
  279. X     default:
  280. X        continue;
  281. X    }     
  282. X    must_collect++;   
  283. X    }
  284. X    
  285. X    fclose(gate);
  286. X
  287. X    return must_collect;
  288. X}    
  289. X
  290. X
  291. X/*
  292. X * disk write with check -- halt if no space on disk
  293. X */
  294. X
  295. X
  296. XFwrite(buf, size, nitems, stream)
  297. Xchar *buf;
  298. Xint size;
  299. Xint nitems;
  300. XFILE *stream;
  301. X{
  302. X    if (fwrite(buf, size, nitems, stream) != nitems)
  303. X    write_error();
  304. X}
  305. X
  306. Xwrite_error()
  307. X{
  308. X    /*
  309. X     * should wait for problems to clear out rather than die...
  310. X     */
  311. X    sys_error("DISK WRITE ERROR");
  312. X}
  313. X
  314. X/*
  315. X * dummy routines - should never be called by master
  316. X */
  317. X
  318. X/*VARARGS*/
  319. Xuser_error()
  320. X{
  321. X    dummy_error("user_error");
  322. X}
  323. X
  324. Xdummy_error(name)
  325. Xchar *name;
  326. X{
  327. X    sys_error("Dummy routine called by master: %s", name);
  328. X}
  329. X
  330. X
  331. X#ifdef NNTP /* XXX */
  332. Xmsg() {}
  333. X#endif /* NNTP Bogus */
  334. NO_NEWS_IS_GOOD_NEWS
  335. echo "File master.c is complete"
  336. chmod 0644 master.c || echo "restore of master.c fails"
  337. set `wc -c master.c`;Sum=$1
  338. if test "$Sum" != "15145"
  339. then echo original size 15145, current size $Sum;fi
  340. echo "x - extracting match.c (Text)"
  341. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > match.c &&
  342. X#define    NUL    '\0'
  343. X#define    NULL    ((char *)0)
  344. X
  345. X
  346. X#ifdef notdef
  347. X
  348. X/* use this table for creating input to the match.h routines */
  349. X
  350. Xchar match_xxx[128] = {
  351. X    
  352. X/*  NUL SOH STX ETX EOT ENQ ACK BEL BS  TAB NL  VT  FF  CR  SO  SI  */
  353. X    00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 
  354. X
  355. X/*  DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM  SUB ESC FS  GS  RS  US  */
  356. X    00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 
  357. X
  358. X/*  SP  !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /   */
  359. X    00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 
  360. X
  361. X/*  0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?   */
  362. X    00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 
  363. X
  364. X/*  @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O   */
  365. X    00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 
  366. X
  367. X/*  P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _   */
  368. X    00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 
  369. X
  370. X/*  `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o   */
  371. X    00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 
  372. X
  373. X/*  p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~   DEL */
  374. X    00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
  375. X
  376. X};
  377. X#endif
  378. X
  379. X
  380. X/*
  381. X * the following routines only works for ASCII !!!!
  382. X *
  383. X * they are a quick hack to check for the occurrence of a word
  384. X * (regardless of case) in a string
  385. X */
  386. X
  387. X#define UNIFY 040
  388. X
  389. Xinit_quick_match(mask)
  390. Xchar *mask;
  391. X{
  392. X    register char *m;
  393. X
  394. X    for (m = mask; *m; m++) *m |= UNIFY;
  395. X}
  396. X
  397. Xchar *quick_match(subject, mask)
  398. Xregister char *subject;
  399. Xchar *mask;
  400. X{
  401. X    register char *q, *m;
  402. X    register char m1 = *mask;
  403. X
  404. X    for (; *subject; subject++) {
  405. X        if ((*subject | UNIFY) != m1) continue;
  406. X
  407. X        q = subject; m = mask;
  408. X        do
  409. X            if (*++m == NUL) return subject;
  410. X        while ((*++q | UNIFY) == *m); 
  411. X    }
  412. X    return NULL;
  413. X}
  414. NO_NEWS_IS_GOOD_NEWS
  415. chmod 0644 match.c || echo "restore of match.c fails"
  416. set `wc -c match.c`;Sum=$1
  417. if test "$Sum" != "1884"
  418. then echo original size 1884, current size $Sum;fi
  419. echo "x - extracting match.h (Text)"
  420. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > match.h &&
  421. X/* usage:
  422. X *    MATCH_DROP(t, a) and MATCH_DROP(t, b) must both be proven false
  423. X *    before MATCH_EQ(t, a, b) is used.
  424. X */
  425. X
  426. X#define    MATCH_DROP(table, c) ( c & 0200 || table[c] == 0 )
  427. X        
  428. X#define MATCH_EQ(table, a, b) ( a == b || table[a] == table[b] )
  429. X
  430. X#define MATCH_LS_EQ(table, a, b) ( a <= b || table[a] <= table[b] )
  431. X
  432. X#define MATCH_LS(table, a, b) ( a < b || table[a] < table[b] )
  433. X
  434. X#define    MATCH_CMP(table, a, b) (table[a] - table[b])
  435. NO_NEWS_IS_GOOD_NEWS
  436. chmod 0644 match.h || echo "restore of match.h fails"
  437. set `wc -c match.h`;Sum=$1
  438. if test "$Sum" != "439"
  439. then echo original size 439, current size $Sum;fi
  440. echo "x - extracting menu.c (Text)"
  441. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > menu.c &&
  442. X/*
  443. X *     selection mode menu
  444. X */
  445. X
  446. X#include "config.h"
  447. X#include "articles.h"
  448. X#include "term.h"
  449. X#include "keymap.h"
  450. X#include "menu.h"
  451. X
  452. X
  453. Xexport int  preview_window = 0;    /* size of preview window */
  454. Xexport int  fmt_linenum    = 1; /* menu line format */
  455. Xexport int  fmt_rptsubj    = 0; /* repeat identical subjects if !0 */
  456. Xexport int  novice       = 1; /* novice mode -- use extended prompts */
  457. Xexport int  long_menu       = 0; /* don't put empty lines around menu lines */
  458. Xexport int  delay_redraw   = 0; /* prompt again if :-command clears screen */
  459. X
  460. Xexport char *delayed_msg = NULL;    /* give to msg() after redraw */
  461. X
  462. Ximport also_read_articles;
  463. Ximport merged_menu;
  464. X
  465. Xextern group_completion();
  466. X
  467. Xstatic int firstl;    /* first menu line */
  468. X
  469. Xstatic int firsta;    /* first article on menu (0 based) */
  470. Xstatic int cura;    /* current article */
  471. Xstatic int next_cura;    /* article to become cura if >= 0 */
  472. Xstatic int numa;    /* no of articles on menu - 1 */
  473. X
  474. X#define INTERVAL1    ('z' - 'a' + 1)
  475. X#define INTERVAL2    ('9' - '0' + 1)
  476. X
  477. Xchar ident[] = "abcdefghijklmnopqrstuvwxyz0123456789";
  478. Xchar Ident[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ&&&&&&&&&&";
  479. X
  480. X/* mark commands */
  481. X
  482. X#define    OFF    0
  483. X#define    ON    1
  484. X#define    TOGGLE    2
  485. X#define    INIT    3
  486. X#define    SAVED    4
  487. X#define    REMOVE    5
  488. X#define CANCEL    6
  489. X
  490. Xstatic int how;
  491. X
  492. Xstatic mark()
  493. X{
  494. X    register article_header *ah;
  495. X    int lno, curhow, must_print, lnum, lsubj, lname;
  496. X
  497. X    ah = articles[firsta + cura];
  498. X    curhow = (ah->flag & A_SELECT) ? ON : OFF;
  499. X    if (how == curhow) return;
  500. X
  501. X    lno = firstl + cura;
  502. X    must_print = STANDOUT;
  503. X
  504. X toggle:
  505. X
  506. X    switch (how) {
  507. X  
  508. X     case TOGGLE:
  509. X    how = (curhow == ON) ? OFF : ON;
  510. X    goto toggle;
  511. X    
  512. X     case ON:
  513. X    if (ah->flag & A_CANCEL) {
  514. X        if (curhow == OFF) return;
  515. X        how = OFF;
  516. X        goto toggle;
  517. X    }
  518. X    ah->flag |= A_SELECT;
  519. X    break;
  520. X    
  521. X     case OFF:
  522. X    ah->flag &= ~A_SELECT;
  523. X    break;
  524. X
  525. X     case INIT:
  526. X    gotoxy(0, lno);
  527. X    putchar(ident[cura]);
  528. X    how = curhow;
  529. X    must_print = 1;
  530. X    break;
  531. X
  532. X     case SAVED:
  533. X    gotoxy(0, lno);
  534. X    putchar(Ident[cura]);
  535. X    return;
  536. X
  537. X     case REMOVE:
  538. X    gotoxy(0, lno);
  539. X    clrline();
  540. X    return;
  541. X
  542. X     case CANCEL:
  543. X    gotoxy(1, lno);
  544. X    if (ah->flag & A_SELECT) {
  545. X        ah->flag &= ~A_SELECT;
  546. X        break;
  547. X    }
  548. X    putchar((ah->flag & A_CANCEL) ? '#' : ' ');
  549. X    return;
  550. X    }
  551. X
  552. X    if (cura < 0 || cura > numa) return;
  553. X
  554. X    /* menu line formats:
  555. X                1  3    8 10     20 22        xx
  556. X        :  :    :  :      :  :        :
  557. X       0    id name           subject     +lines
  558. X       1    id name       lines  subject
  559. X       2    id  lines  subject
  560. X       3    id subject
  561. X       4    id name:8 subject
  562. X     */
  563. X
  564. X    if (must_print) {
  565. X
  566. X    if (fmt_linenum > 4) fmt_linenum = 1;
  567. X    
  568. X    if (ah->flag & A_CANCEL) {
  569. X        gotoxy(1, lno);
  570. X        putchar('#');
  571. X    } else
  572. X    if (how == ON) {
  573. X        if (so_gotoxy(1, lno, 1) == 0) putchar('*');
  574. X    } else {
  575. X        gotoxy(1, lno);
  576. X        putchar(' ');
  577. X    }
  578. X
  579. X    if (fmt_linenum >   1) lnum = 0; else
  580. X    if (ah->lines <    10) lnum = 1; else
  581. X    if (ah->lines <   100) lnum = 2; else
  582. X    if (ah->lines <  1000) lnum = 3; else
  583. X    if (ah->lines < 10000) lnum = 4; else lnum = 5;
  584. X    
  585. X    lsubj = Columns - cookie_size - 2; /* ident char + space */
  586. X
  587. X    switch (fmt_linenum) {
  588. X        
  589. X     case 0:
  590. X        lsubj -= NAME_LENGTH + 1 + 2 + lnum;  /* name. .subj. +.lines */
  591. X        so_printf("%-*s ", NAME_LENGTH, ah->sender);
  592. X        break;
  593. X        
  594. X     case 1:
  595. X        lsubj -= NAME_LENGTH + 4; 
  596. X        /* name.lines.  .subj (name may be shortened) */
  597. X        lname = NAME_LENGTH + 2 - lnum;
  598. X        lsubj -= 4;    /* 2 columns for the number + 2 spaces */
  599. X        so_printf("%-*.*s ", lname, lname, ah->sender);
  600. X        so_printf(ah->lines >= 0 ? "%d  " : "?  ", ah->lines);
  601. X        break;
  602. X       
  603. X     case 2:
  604. X        lsubj -= 6;
  605. X        so_printf("%5d ", ah->lines);
  606. X        break;
  607. X        
  608. X     case 3:
  609. X        break;
  610. X
  611. X     case 4:
  612. X        lsubj -= 9;
  613. X        so_printf("%-8.8s ", ah->sender);
  614. X        break;
  615. X    }
  616. X
  617. X    if (!fmt_rptsubj && lno > firstl && ah->flag & A_SAME) {
  618. X        if (ah->replies == 0)
  619. X        so_printf("-");
  620. X        else
  621. X        prt_replies(ah->replies);
  622. X    } else {
  623. X        lsubj -= prt_replies(ah->replies);
  624. X        so_printf("%-.*s", lsubj, ah->subject);
  625. X    }    
  626. X
  627. X    if (fmt_linenum == 0)
  628. X        so_printf(ah->lines >= 0 ? " +%d" : " +?", ah->lines);
  629. X
  630. X    so_end();
  631. X    } else
  632. X    putchar((how == OFF) ? ' ' : '*');
  633. X    
  634. X    fl;
  635. X    
  636. X    return;
  637. X}
  638. X
  639. X
  640. Xstatic prt_replies(level)
  641. X{
  642. X    if (level == 0) return 0;
  643. X    
  644. X    if (level < 10) {
  645. X    so_printf("%-.*s", level, ">>>>>>>>>");
  646. X    return level;
  647. X    }
  648. X    
  649. X    so_printf(">>>%3d >>>>", level);
  650. X    return 11;
  651. X}
  652. X
  653. X
  654. Xstatic int article_id;
  655. X
  656. Xstatic int get_k_cmd()
  657. X{
  658. X    register int c, map;
  659. X
  660. X loop:
  661. X    
  662. X    article_id = -1;
  663. X    
  664. X    if ((c = get_c()) & GETC_COMMAND)
  665. X    map = c & ~GETC_COMMAND;
  666. X    else
  667. X    map = menu_key_map[c];
  668. X    
  669. X    if (s_hangup) map = K_QUIT;
  670. X    
  671. X    if (map & K_MACRO) {
  672. X    m_invoke(map & ~K_MACRO);
  673. X    goto loop;
  674. X    }
  675. X    
  676. X    if (map & K_ARTICLE_ID) {
  677. X    article_id = map & ~K_ARTICLE_ID;
  678. X    map = K_ARTICLE_ID;
  679. X    
  680. X    if (article_id < 0 || article_id > numa) {
  681. X        ding();
  682. X        goto loop;
  683. X    }
  684. X    }    
  685. X    
  686. X    return map;
  687. X}
  688. X
  689. X
  690. Xchar *pct(start, end, first, last)
  691. Xlong start, end, first, last;
  692. X{
  693. X    long n = end - start;
  694. X    static char buf[16];
  695. X    char *fmt;
  696. X    
  697. X    if (first <= start || n <= 0)
  698. X    if (last >= end) 
  699. X        return "All";
  700. X    else
  701. X        fmt = "Top %d%%";
  702. X    else
  703. X    if (last >= end)
  704. X        return "Bot";
  705. X    else
  706. X        fmt = "%d%%";
  707. X    
  708. X    sprintf(buf, fmt, ((last - start) * 100)/n);
  709. X    return buf;
  710. X}
  711. X
  712. Xmenu(print_header)
  713. Xint (* print_header)();
  714. X{
  715. X    register         k_cmd, cur_k_cmd;
  716. X    register        article_header *ah;
  717. X    int            last_k_cmd, last_how, was_selected;
  718. X    int         seen_all, menu_cmd, temp;
  719. X    int         save_selected, last_save;
  720. X    int            doing_unshar, did_unshar;
  721. X    char         *fname, *savemode, *init_save();
  722. X    int         nexta;    /* first article on next menu */
  723. X    int         maxa;    /* max no of articles per menu page */
  724. X    int         o_firsta, o_mode;    /* for recursive calls */
  725. X    static        menu_level = 0;
  726. X    char        purpose[80], pr_fmt[60];
  727. X    extern int         enable_stop, file_completion();
  728. X    extern int        alt_cmd_key, in_menu_mode, slow_mode, any_message;
  729. X    
  730. X#define    menu_return(cmd) \
  731. X    { menu_cmd = (cmd); goto menu_exit; }
  732. X
  733. X    o_firsta = firsta;
  734. X    o_mode = in_menu_mode;
  735. X    in_menu_mode = 1;
  736. X    
  737. X    menu_level++;
  738. X
  739. X    sprintf(pr_fmt, 
  740. X        menu_level == 1 ? 
  741. X          "\1\2-- SELECT %s-----%%s-----\1" :
  742. X          "\1\2-- SELECT %s-----%%s-----<%s%d>--\1",
  743. X          novice ? "-- help:? " : "",
  744. X          novice ? "level " : "",
  745. X          menu_level);
  746. X
  747. X    purpose[0] = NUL;
  748. X    if (!merged_menu && current_group->group_flag & G_NEW)
  749. X    get_purpose(purpose);
  750. X    
  751. X    seen_all = 0;
  752. X    firsta = 0;
  753. X    while (firsta < n_articles && articles[firsta]->flag & A_SEEN)
  754. X    firsta++;
  755. X
  756. X    if (firsta == n_articles) {
  757. X    seen_all++;
  758. X    firsta = 0;
  759. X    }
  760. X    
  761. X    next_cura = -1;
  762. X    cur_k_cmd = K_UNBOUND;
  763. X    
  764. X#ifdef HAVE_JOBCONTROL
  765. X#define    REDRAW_CHECK    if (s_redraw) goto do_redraw
  766. X    
  767. X do_redraw:
  768. X    /* safe to clear here, because we are going to redraw anyway */
  769. X    s_redraw = 0; 
  770. X#else
  771. X#define REDRAW_CHECK
  772. X#endif
  773. X
  774. X redraw:
  775. X    s_keyboard = 0;
  776. X
  777. X empty_menu_hack:    /* do: "s_keyboard=1; goto empty_menu_hack;" */
  778. X    if (!slow_mode) s_keyboard = 0;
  779. X    
  780. X    nexta = firsta;
  781. X    
  782. X    clrdisp();
  783. X    
  784. X    firstl = (*print_header)();
  785. X    maxa = Lines - preview_window - firstl - 2;
  786. X    if (!long_menu) firstl++, maxa -= 2;
  787. X
  788. X    if (maxa > (INTERVAL1 + INTERVAL2))
  789. X    maxa = INTERVAL1 + INTERVAL2;
  790. X
  791. X nextmenu:
  792. X
  793. X    no_raw();
  794. X    gotoxy(0, firstl);
  795. X    clrpage(firstl);
  796. X    
  797. X    if (nexta > 0) {
  798. X    while (firsta < nexta)
  799. X        articles[firsta++]->flag |= A_SEEN;
  800. X    } else
  801. X    if (purpose[0]) {
  802. X        msg(purpose);
  803. X    }
  804. X
  805. X    firsta = nexta;
  806. X    numa = Lines; /* for mark; is set correctly below */
  807. X    cura = 0;
  808. X    
  809. X    REDRAW_CHECK;
  810. X    
  811. X    if (!s_keyboard)
  812. X    while (nexta < n_articles && cura < maxa) {
  813. X        
  814. X        REDRAW_CHECK;
  815. X    
  816. X        how = INIT;
  817. X        mark(); fl;
  818. X        
  819. X        if (s_keyboard) {      /* Signal may have corrupted output.  */
  820. X        if (cura == 0)
  821. X            mark();      /* redraw first entry */
  822. X        else {
  823. X            how = REMOVE; /* We delete the last entry (the user */
  824. X            mark();      /* wanted to stop the output anyway)  */
  825. X            cura--;
  826. X            nexta--;
  827. X        }            
  828. X        break;
  829. X        }
  830. X        
  831. X        nexta++; cura++;
  832. X    }
  833. X    
  834. X    s_keyboard = 0;
  835. X
  836. X    prompt_line = firstl + cura;
  837. X    if (!long_menu || cura < maxa) prompt_line++;
  838. X
  839. X    numa = nexta - firsta - 1;
  840. X     if (numa < 0) prompt_line++;
  841. X
  842. X     if (next_cura >= 0) {
  843. X     cura = next_cura;
  844. X     next_cura = -1;
  845. X     } else {
  846. X     cura = 0;
  847. X     for (article_id = firsta; cura < numa; article_id++, cura++)
  848. X         if ((articles[article_id]->flag & A_SELECT) == 0) break;
  849. X     }
  850. X
  851. X     how = TOGGLE;
  852. X
  853. X  build_prompt:
  854. X
  855. X     raw();
  856. X
  857. X  Prompt:
  858. X
  859. X     prompt(pr_fmt,
  860. X        pct(0L, (long)(n_articles-1), (long)firsta, (long)(firsta+numa)));
  861. X
  862. X     if (delayed_msg != NULL) {
  863. X     msg(delayed_msg);
  864. X     delayed_msg = NULL;
  865. X     }
  866. X
  867. X  same_prompt:
  868. X
  869. X     if (cura < 0 || cura > numa) cura = 0;
  870. X
  871. X     if (numa >= 0) {
  872. X     gotoxy(0, firstl + cura); 
  873. X     fl; /* place cursor at current article id */
  874. X     }
  875. X
  876. X     last_k_cmd = cur_k_cmd;
  877. X     cur_k_cmd = k_cmd = get_k_cmd();
  878. X     if (any_message) clrmsg(-1);
  879. X
  880. X  alt_key:
  881. X
  882. X     switch (k_cmd) {
  883. X
  884. X      case K_UNBOUND:
  885. X     ding();
  886. X     flush_input();
  887. X     goto same_prompt;
  888. X
  889. X      case K_REDRAW:
  890. X     goto redraw;
  891. X
  892. X      case K_LAST_MESSAGE:
  893. X     msg((char *)NULL);
  894. X     goto same_prompt;
  895. X
  896. X      case K_HELP:
  897. X     if (numa < 0)  goto nextmenu;    /* give specific help here */
  898. X     display_help("menu");
  899. X     goto redraw;
  900. X
  901. X      case K_SHELL:
  902. X     if (group_file_name) *group_file_name = NUL;
  903. X     if (shell_escape()) goto redraw;
  904. X     goto Prompt;
  905. X
  906. X      case K_VERSION:
  907. X     prompt(P_VERSION);
  908. X     goto same_prompt;
  909. X
  910. X      case K_EXTENDED_CMD:
  911. X     switch (alt_command()) {
  912. X
  913. X      case AC_QUIT:
  914. X         menu_return( ME_QUIT );
  915. X
  916. X      case AC_PROMPT:
  917. X         goto Prompt;
  918. X
  919. X      case AC_REORDER:
  920. X         firsta = 0;
  921. X         /* fall thru */
  922. X      case AC_REDRAW:
  923. X         goto redraw;
  924. X
  925. X      case AC_KEYCMD:
  926. X         k_cmd = alt_cmd_key;
  927. X         goto alt_key;
  928. X
  929. X      case AC_HEADER:
  930. X         home();
  931. X         (*print_header)();
  932. X         goto Prompt;
  933. X     }
  934. X
  935. X      case K_QUIT:
  936. X     menu_return(ME_QUIT);
  937. X
  938. X      case K_SAVE_NO_HEADER:
  939. X      case K_SAVE_SHORT_HEADER:
  940. X      case K_SAVE_FULL_HEADER:
  941. X      case K_PRINT:
  942. X      case K_UNSHAR:
  943. X      case K_PATCH:
  944. X
  945. X     if (numa < 0) goto nextmenu;
  946. X
  947. X     fname = init_save(k_cmd, &savemode);
  948. X     if (fname == NULL) goto Prompt;
  949. X
  950. X     enable_stop = 0;
  951. X     save_selected = 0;
  952. X     doing_unshar = k_cmd == K_UNSHAR || k_cmd == K_PATCH;
  953. X     did_unshar = 0;
  954. X
  955. X     m_startinput();
  956. X
  957. X     while (!save_selected && !did_unshar) {
  958. X         prompt("\1%s\1 %.*s Article (* +): ",
  959. X            savemode, Columns - 25, fname);
  960. X
  961. X         k_cmd = get_k_cmd();
  962. X
  963. X         if (k_cmd == K_SELECT_SUBJECT) {
  964. X         save_selected = 1;
  965. X         cura = 0;
  966. X         article_id = firsta;
  967. X         last_save = firsta + numa;
  968. X         } else
  969. X         if (k_cmd == K_AUTO_SELECT) {
  970. X         save_selected = 2;
  971. X         cura = -firsta;
  972. X         article_id = 0;
  973. X         last_save = n_articles - 1;
  974. X         } else
  975. X         if (k_cmd == K_ARTICLE_ID) {
  976. X         cura = article_id;
  977. X         article_id += firsta;
  978. X         last_save = article_id;
  979. X         } else
  980. X         break;
  981. X
  982. X         for ( ; article_id <= last_save ; article_id++, cura++) {
  983. X         ah = articles[article_id];
  984. X         if (save_selected && (ah->flag & A_SELECT) == 0) continue;
  985. X
  986. X         if (doing_unshar) {
  987. X             did_unshar++;
  988. X         } else
  989. X         if (cura >= 0 && cura <= numa)
  990. X             prompt("Processing %c...", ident[cura]);
  991. X         else
  992. X             prompt("Processing entry %d...", article_id);
  993. X
  994. X         if (save(ah)) {
  995. X             if (doing_unshar) {
  996. X             if (save_selected)
  997. X                 ah->flag &= ~A_SELECT;
  998. X             } else
  999. X             if (cura >= 0 && cura <= numa) {
  1000. X             how = save_selected ? OFF : SAVED;
  1001. X             mark();
  1002. X             how = TOGGLE;
  1003. X             } else
  1004. X             if (save_selected)
  1005. X             ah->flag &= ~A_SELECT;
  1006. X         }
  1007. X         }
  1008. X     }
  1009. X
  1010. X     if (save_selected) cura = 0;
  1011. X     how = TOGGLE;
  1012. X
  1013. X     m_endinput();
  1014. X
  1015. X     enable_stop = 1;
  1016. X     end_save();
  1017. X
  1018. X     if (did_unshar) {
  1019. X         any_key(0);
  1020. X         goto redraw;
  1021. X     }    
  1022. X     goto Prompt;
  1023. X
  1024. X      case K_REPLY:
  1025. X      case K_FOLLOW_UP:
  1026. X     if (numa < 0) goto nextmenu;
  1027. X
  1028. X     prompt(k_cmd == K_REPLY ? 
  1029. X        "\1Reply to author\1 of article: " : 
  1030. X        "\1Follow Up\1 to article: ");
  1031. X
  1032. X     if (get_k_cmd() == K_ARTICLE_ID)
  1033. X         if (answer(articles[firsta+article_id], k_cmd, -1))
  1034. X         goto redraw;
  1035. X
  1036. X     goto Prompt;
  1037. X
  1038. X      case K_POST:
  1039. X     if (post_menu()) goto redraw;
  1040. X     goto Prompt;
  1041. X
  1042. X      case K_MAIL_OR_FORWARD:
  1043. X     if (numa < 0) goto nextmenu;
  1044. X
  1045. X     prompt("\1Article to be forwarded\1 (SP if none): ");
  1046. X
  1047. X     if ((k_cmd = get_k_cmd()) == K_ARTICLE_ID) {
  1048. X         if (answer(articles[firsta+article_id], K_MAIL_OR_FORWARD, 1))
  1049. X         goto redraw;
  1050. X     } else
  1051. X     if (k_cmd == K_CONTINUE)
  1052. X         if (answer((article_header *)NULL, K_MAIL_OR_FORWARD, 0))
  1053. X         goto redraw;
  1054. X
  1055. X     goto Prompt;
  1056. X
  1057. X      case K_CANCEL:
  1058. X     if (numa < 0) goto nextmenu;
  1059. X
  1060. X     if (current_group->group_flag & G_FOLDER) {
  1061. X         prompt("\1Cancel Folder\1 Article: ");
  1062. X         if (get_k_cmd() == K_ARTICLE_ID) {
  1063. X         cura = article_id;
  1064. X         fcancel(articles[firsta+article_id]);
  1065. X         how = CANCEL;
  1066. X         mark();
  1067. X         }
  1068. X         goto Prompt;
  1069. X     }
  1070. X
  1071. X     prompt("\1Cancel\1 Article: ");
  1072. X
  1073. X     if (get_k_cmd() == K_ARTICLE_ID)
  1074. X         if (cancel(articles[firsta+article_id]) & 1) goto redraw;
  1075. X     goto Prompt;
  1076. X
  1077. X      case K_UNSUBSCRIBE:
  1078. X     if (unsubscribe(current_group)) {
  1079. X         if (!(current_group->group_flag & G_SUBSCRIPTION))
  1080. X         menu_return(ME_NEXT);
  1081. X         home();
  1082. X         (*print_header)();
  1083. X     }
  1084. X     goto Prompt;
  1085. X
  1086. X      case K_GROUP_OVERVIEW:
  1087. X     group_overview(0);
  1088. X     goto redraw;
  1089. X
  1090. X      case K_KILL_HANDLING:
  1091. X     kill_menu((article_header *)NULL);
  1092. X     goto Prompt;
  1093. X
  1094. X      case K_CONTINUE:    /* goto next menu page or show the articles */
  1095. X     if (nexta < n_articles && !seen_all) goto nextmenu;
  1096. X     /* fall thru */
  1097. X
  1098. X      case K_READ_GROUP_UPDATE:
  1099. X      case K_READ_GROUP_THEN_SAME:
  1100. X     no_raw();
  1101. X     clrdisp();
  1102. X
  1103. X     switch (show_articles()) {
  1104. X
  1105. X      case SH_MENU:
  1106. X         goto redraw;
  1107. X
  1108. X      case SH_QUIT:
  1109. X         menu_return(ME_QUIT);
  1110. X
  1111. X      case SH_NO_SELECT:
  1112. X         break;
  1113. X
  1114. X      case SH_NEXT:
  1115. X         menu_return(ME_NEXT);
  1116. X
  1117. X      case SH_READ:
  1118. X         if (k_cmd == K_READ_GROUP_THEN_SAME || also_read_articles) goto redraw;
  1119. X         break;
  1120. X
  1121. X      default:
  1122. X         user_error("show_articles returned improper value");
  1123. X     }
  1124. X
  1125. X     menu_return(ME_READ);
  1126. X
  1127. X      case K_NEXT_GROUP_NO_UPDATE:
  1128. X     menu_return(ME_NEXT);
  1129. X
  1130. X      case K_PREVIOUS:
  1131. X     menu_return(ME_PREV);
  1132. X
  1133. X      case K_ADVANCE_GROUP:
  1134. X      case K_BACK_GROUP:
  1135. X     if (merged_menu) {
  1136. X         msg("No possible on merged menu");
  1137. X         goto same_prompt;
  1138. X     }
  1139. X     /* FALL THRU */
  1140. X
  1141. X      case K_GOTO_GROUP:
  1142. X
  1143. X     switch (goto_group(k_cmd, (article_header *)NULL)) {
  1144. X
  1145. X      case ME_REDRAW:
  1146. X         firsta = 0;
  1147. X         goto redraw;
  1148. X
  1149. X      case ME_NO_ARTICLES:
  1150. X         msg("No selections made.");
  1151. X
  1152. X      case ME_NO_REDRAW:
  1153. X         goto Prompt;
  1154. X
  1155. X      case ME_QUIT:
  1156. X         menu_return( ME_QUIT );
  1157. X
  1158. X      case ME_PREV:
  1159. X         goto redraw;
  1160. X
  1161. X      case ME_NEXT:
  1162. X      case ME_READ:
  1163. X         s_keyboard = 1;
  1164. X         goto empty_menu_hack;
  1165. X     }
  1166. X
  1167. X      case K_ARTICLE_ID:
  1168. X     if (numa < 0) goto nextmenu;
  1169. X
  1170. X     cura = article_id; 
  1171. X     how = TOGGLE;
  1172. X     mark();
  1173. X     last_how = how;
  1174. X     cura++;
  1175. X
  1176. X     goto same_prompt;
  1177. X
  1178. X      case K_SELECT_INVERT:
  1179. X     if (numa < 0) goto nextmenu;
  1180. X
  1181. X     temp = cura;
  1182. X
  1183. X     no_raw();    /* for x-on/x-off */
  1184. X     for (cura = 0; cura <= numa; cura++) {
  1185. X         how = TOGGLE;
  1186. X         mark();
  1187. X     }
  1188. X     fl;
  1189. X
  1190. X     REDRAW_CHECK;
  1191. X     raw();
  1192. X
  1193. X     how = TOGGLE; cura = temp;
  1194. X     goto same_prompt;
  1195. X
  1196. X
  1197. X      case K_SELECT:
  1198. X     if (numa < 0) goto nextmenu;
  1199. X
  1200. X     how = TOGGLE;
  1201. X     mark();
  1202. X     last_how = how;
  1203. X     cura++;
  1204. X     goto same_prompt;
  1205. X
  1206. X      case K_UNSELECT_ALL:
  1207. X     for (cura = -firsta; cura < n_articles - firsta; cura++) {
  1208. X         how = OFF;
  1209. X         mark();
  1210. X     }
  1211. X     fl;
  1212. X     cura = 0;
  1213. X     goto same_prompt;
  1214. X
  1215. X      case K_NEXT_LINE:
  1216. X     if (numa < 0) goto nextmenu;
  1217. X
  1218. X     cura++;
  1219. X     how = TOGGLE;
  1220. X     goto same_prompt;
  1221. X
  1222. X      case K_PREV_LINE:
  1223. X     if (numa < 0) goto nextmenu;
  1224. X
  1225. X     if (--cura < 0) cura = numa;
  1226. X     how = TOGGLE;
  1227. X     goto same_prompt;
  1228. X
  1229. X      case K_SELECT_SUBJECT:
  1230. X     if (numa < 0) goto nextmenu;
  1231. X
  1232. X     mark();
  1233. X
  1234. X     while (firsta+cura > 0 && articles[firsta+cura]->flag & A_SAME) 
  1235. X         cura--;
  1236. X
  1237. X     do {
  1238. X         mark();
  1239. X         cura++;
  1240. X         if (firsta+cura >= n_articles) break;
  1241. X     } while (articles[firsta+cura]->flag & A_SAME);
  1242. X
  1243. X     how = TOGGLE;
  1244. X     goto same_prompt;
  1245. X
  1246. X      case K_SELECT_RANGE:
  1247. X     if (numa < 0) goto nextmenu;
  1248. X
  1249. X     if (last_k_cmd == K_ARTICLE_ID || last_k_cmd == K_SELECT) {
  1250. X         how = last_how;
  1251. X         cura--;
  1252. X         if (cura < 0) cura = numa;
  1253. X     } else
  1254. X         how = articles[firsta+cura]->flag & A_SELECT ? OFF : ON;
  1255. X
  1256. X      range_again:
  1257. X
  1258. X     prompt("\1%select range\1 %c-", how == ON ? "S" : "Des", ident[cura]);
  1259. X
  1260. X     k_cmd = get_k_cmd();
  1261. X     if (k_cmd == K_SELECT_RANGE) {
  1262. X         how = !how;
  1263. X         goto range_again;
  1264. X     }
  1265. X
  1266. X     if (k_cmd != K_ARTICLE_ID) goto Prompt;
  1267. X
  1268. X     if (last_k_cmd != K_ARTICLE_ID && last_k_cmd != K_SELECT) 
  1269. X         mark();
  1270. X
  1271. X     if (article_id <= cura) {
  1272. X         while (--cura >= article_id) mark();
  1273. X         if (cura < 0) cura = 0;
  1274. X     } else {
  1275. X         while (++cura <= article_id) mark();
  1276. X         if (cura > numa) cura = numa;
  1277. X     }
  1278. X
  1279. X     how = TOGGLE;
  1280. X     goto Prompt;
  1281. X
  1282. X      case K_AUTO_SELECT:
  1283. X     do_auto_select();
  1284. X     goto same_prompt;
  1285. X
  1286. X      case K_NEXT_PAGE:
  1287. X     if (nexta < n_articles) goto nextmenu;
  1288. X     if (firsta == 0) goto same_prompt;
  1289. X
  1290. X     seen_all++;
  1291. X     nexta = 0;
  1292. X     goto nextmenu;
  1293. X
  1294. X      case K_PREV_PAGE:
  1295. X     if (firsta == 0 && nexta == n_articles) goto same_prompt;
  1296. X
  1297. X     nexta = (firsta > 0 ? firsta : n_articles) - maxa;
  1298. X     if (nexta <= 1) nexta = 0;
  1299. X     goto nextmenu;
  1300. X
  1301. X      case K_FIRST_PAGE:
  1302. X     if (firsta == 0) goto same_prompt;
  1303. X
  1304. X     nexta = 0;
  1305. X     goto nextmenu;
  1306. X
  1307. X      case K_LAST_PAGE:
  1308. X     if (nexta == n_articles) goto same_prompt;
  1309. X
  1310. X     nexta = n_articles - maxa;
  1311. X     if (nexta <= 1) nexta = 0;
  1312. X     goto nextmenu;
  1313. X
  1314. X      case K_PREVIEW:
  1315. X     if (numa < 0) goto nextmenu;
  1316. X
  1317. X      preview_other:
  1318. X
  1319. X     prompt("\1Preview article\1");
  1320. X     k_cmd = get_k_cmd();
  1321. X
  1322. X     if (k_cmd != K_ARTICLE_ID) {
  1323. X         if (k_cmd != K_PREVIEW)
  1324. X         goto Prompt;
  1325. X         article_id = cura;
  1326. X     }
  1327. X
  1328. X     temp = prompt_line;
  1329. X
  1330. X      preview_next:
  1331. X     ah = articles[firsta+article_id];
  1332. X     cura = article_id + 1;
  1333. X     was_selected = (ah->flag & A_SELECT);
  1334. X
  1335. X     switch (more(ah, MM_PREVIEW, prompt_line)) {
  1336. X         
  1337. X      case MC_REDRAW:
  1338. X         next_cura = cura;
  1339. X         goto redraw;
  1340. X         
  1341. X      case MC_NO_REDRAW:
  1342. X         break;
  1343. X         
  1344. X      case MC_QUIT:
  1345. X         menu_return( ME_QUIT );
  1346. X
  1347. X      case MC_NEXT:        /* article not found -- preview next */
  1348. X         if (prompt_line == temp) 
  1349. X         break; /* not redrawn -- return to menu instead */
  1350. X         user_delay(1);
  1351. X         /* FALL THRU */
  1352. X         
  1353. X      case MC_PREVIEW_NEXT:
  1354. X         if (prompt_line < 0) {    /* redrawn screen ! */
  1355. X         if ((firsta + cura) >= n_articles) goto redraw;
  1356. X         prompt_line = Lines;
  1357. X         } else {
  1358. X         if ((ah->flag & A_SELECT) && was_selected == 0) {
  1359. X             cura--;
  1360. X             ah->flag &= ~A_SELECT;
  1361. X             how = ON;
  1362. X             mark();
  1363. X             cura++;
  1364. X         }
  1365. X         if (cura > numa) break;
  1366. X         prompt_line = temp;
  1367. X         }
  1368. X         article_id = cura;
  1369. X         goto preview_next;
  1370. X         
  1371. X      case MC_PREVIEW_OTHER:
  1372. X         prompt_line = temp;
  1373. X         raw();
  1374. X         goto preview_other;
  1375. X         
  1376. X      default:    
  1377. X         break;
  1378. X     }
  1379. X     
  1380. X     prompt_line = temp;
  1381. X     goto build_prompt;
  1382. X     
  1383. X      case K_LAYOUT:
  1384. X     if (++fmt_linenum > 3) fmt_linenum = 0;
  1385. X     goto redraw;
  1386. X    
  1387. X      default:
  1388. X     msg("Command %d not supported", k_cmd);
  1389. X     goto same_prompt;
  1390. X     }
  1391. X
  1392. X
  1393. X menu_exit:
  1394. X
  1395. X    firsta = o_firsta;
  1396. X    in_menu_mode = o_mode;
  1397. X    menu_level--;
  1398. X    
  1399. X    no_raw();
  1400. X    return menu_cmd;
  1401. X}
  1402. X
  1403. X
  1404. Xstatic show_articles()
  1405. X{
  1406. X    register cur, next, mode;
  1407. X    int cmd, prev = -1, again;
  1408. X    
  1409. X    do {
  1410. X    again = 0;
  1411. X    
  1412. X    for (cur = 0; cur < n_articles; cur++) {
  1413. X        if (articles[cur]->flag & A_SELECT) break;
  1414. X    }
  1415. X    
  1416. X    while (cur < n_articles) {
  1417. X        
  1418. X        for (next = cur+1; next < n_articles; next++) {
  1419. X        if (articles[next]->flag & A_SELECT) break;
  1420. X        }
  1421. X        
  1422. X        articles[cur]->flag &= ~A_SELECT;
  1423. X        
  1424. X     show:
  1425. X        mode = 0;
  1426. X        if (prev >= 0) mode |= MM_PREVIOUS;
  1427. X        if (next == n_articles) mode |= MM_LAST_ARTICLE;
  1428. X        
  1429. X        cmd = more(articles[cur], mode, 0);
  1430. X        
  1431. X        switch(cmd) {
  1432. X        
  1433. X         case MC_PREV:
  1434. X        if (prev == next) break;
  1435. X        
  1436. X        next = cur; cur = prev; prev = next;
  1437. X        goto show;
  1438. X        
  1439. X         case MC_NEXTSUBJ:
  1440. X        for (next = cur+1; next < n_articles; next++) {
  1441. X            if ((articles[next]->flag & A_SAME) == 0) break;
  1442. X            articles[next]->flag &= ~A_SELECT;
  1443. X        }
  1444. X        for (; next < n_articles; next++) {
  1445. X            if (articles[next]->flag & A_SELECT) break;
  1446. X        }
  1447. X        break;
  1448. X        
  1449. X         case MC_ALLSUBJ:
  1450. X        for (next = cur+1; next < n_articles; next++) {
  1451. X            if ((articles[next]->flag & A_SAME) == 0) break;
  1452. X            articles[next]->flag |= A_SELECT;
  1453. X        }
  1454. X        for (next = cur+1; next < n_articles; next++)
  1455. X            if (articles[next]->flag & A_SELECT) break;
  1456. X        break;
  1457. X        
  1458. X         case MC_MENU:
  1459. X        articles[cur]->flag |= A_SELECT;
  1460. X        firsta = cur - 5;
  1461. X        if (firsta < 0) firsta = 0;
  1462. X        next_cura = cur - firsta;
  1463. X        
  1464. X        return SH_MENU;
  1465. X        
  1466. X         case MC_QUIT:
  1467. X        return SH_QUIT;
  1468. X        
  1469. X         case MC_NEXT:
  1470. X        if (articles[cur]->flag & A_SELECT) again++;
  1471. X        break;
  1472. X        
  1473. X         case MC_NEXTGROUP:
  1474. X        return SH_NEXT;
  1475. X        
  1476. X         case MC_READGROUP:
  1477. X        return SH_READ;
  1478. X        }
  1479. X        
  1480. X        prev = cur; cur = next;
  1481. X    }
  1482. X
  1483. X    if (again > 1)
  1484. X        delayed_msg = "Showing this and the following articles again";
  1485. X    else
  1486. X        if (again == 1)
  1487. X        delayed_msg = "Showing article again";
  1488. X    
  1489. X    } while (again);
  1490. X    
  1491. X    return prev < 0 ? SH_NO_SELECT : SH_READ;
  1492. X}
  1493. X
  1494. X/*
  1495. X *    return article header for article on menu
  1496. X */
  1497. X
  1498. Xarticle_header *get_menu_article()
  1499. X{
  1500. X    register article_header *ah;
  1501. X    
  1502. X    fputs(" from article: ", stdout); fl;
  1503. X    
  1504. X    if (get_k_cmd() == K_ARTICLE_ID) {
  1505. X    ah = articles[firsta + article_id];
  1506. X    if (ah->a_group) init_group(ah->a_group);
  1507. X    return ah;
  1508. X    }
  1509. X    
  1510. X    return NULL;
  1511. X}
  1512. X
  1513. X
  1514. Xstatic get_purpose(purpose)
  1515. Xchar *purpose;
  1516. X{
  1517. X#ifdef NNTP
  1518. X    return;            /* newsgroups file is not available */
  1519. X#else    
  1520. X    FILE *f;
  1521. X    char line[256], group[80];
  1522. X    register char *cp, *pp;
  1523. X    register int len;
  1524. X    extern char news_active[];
  1525. X
  1526. X    strcpy(line, news_active);
  1527. X    if ((cp = strrchr(line, '/')) == NULL) return;
  1528. X    strcat(cp + 1, "newsgroups");
  1529. X
  1530. X    if ((f = fopen(line, "r")) == NULL) return;
  1531. X
  1532. X    sprintf(group, "%s\t", current_group->group_name);
  1533. X    len = current_group->group_name_length + 1;
  1534. X    
  1535. X    while (fgets(line, 256, f) != NULL) {
  1536. X    if (strncmp(line, group, len)) continue;
  1537. X    cp = line + len;
  1538. X    while (*cp && isspace(*cp)) cp++;
  1539. X    for (pp = purpose, len = 76; --len >= 0 && *cp && *cp != NL; )
  1540. X        *pp++ = *cp++;
  1541. X    *pp = NUL;
  1542. X    }
  1543. X
  1544. X    fclose(f);
  1545. X#endif
  1546. X}
  1547. X
  1548. X/*
  1549. X *    perform auto selections that are not already selected
  1550. X *    if article is in range firsta..firsta+numa (incl) mark article
  1551. X */
  1552. X
  1553. Xstatic do_auto_select()
  1554. X{
  1555. X    register int i;
  1556. X    register article_header *ah, **ahp;
  1557. X    int count = 0, o_cura;
  1558. X    
  1559. X    o_cura = cura;
  1560. X    
  1561. X    for (i = 0, ahp = articles; i < n_articles; i++, ahp++) {
  1562. X    ah = *ahp;
  1563. X    if (auto_select_article(ah)) {
  1564. X        count++;
  1565. X        if (ah->flag & A_SELECT) continue;
  1566. X        if (firsta <= i && i <= (firsta+numa)) {
  1567. X        cura = i - firsta;
  1568. X        how = ON;
  1569. X        mark();
  1570. X        } else
  1571. X        ah->flag |= A_SELECT;
  1572. X    }
  1573. X    }
  1574. X    
  1575. X    msg(count == 0 ? "No selections" : "Selected %d article%s",
  1576. X       count, count > 1 ? "s" : "");
  1577. X    cura = o_cura;
  1578. X}
  1579. X
  1580. X        
  1581. X
  1582. X/*
  1583. X *    read command from command line
  1584. X */
  1585. X
  1586. Xalt_command()
  1587. X{
  1588. X    int ok_val, macro_cmd;
  1589. X    char *cmd;
  1590. X    extern char erase_key;
  1591. X    extern int get_from_macro;
  1592. X    extern int alt_completion();
  1593. X    
  1594. X    prompt(":");
  1595. X    ok_val = AC_PROMPT;
  1596. X    
  1597. X again:
  1598. X    
  1599. X    cmd = "?? ";
  1600. X    cmd[1] = erase_key;
  1601. X    
  1602. X    cmd = get_s(NONE, NONE, cmd, alt_completion);
  1603. X    if (cmd == NULL ||
  1604. X    *cmd == NUL || *cmd == SP || *cmd == erase_key)
  1605. X    return ok_val;
  1606. X
  1607. X    macro_cmd = get_from_macro;
  1608. X    
  1609. X    if (*cmd == '?') {
  1610. X    display_file("help.extended", CLEAR_DISPLAY);
  1611. X    ok_val = AC_REDRAW;
  1612. X    goto new_prompt;
  1613. X    }
  1614. X
  1615. X    ok_val = parse_command(cmd, ok_val, (FILE *)NULL);
  1616. X    if (ok_val != AC_REDRAW || !delay_redraw) return ok_val;
  1617. X    
  1618. X new_prompt:
  1619. X    if (macro_cmd) return ok_val;
  1620. X    
  1621. X    prompt_line = -1;
  1622. X    printf("\n\r:");
  1623. X    fl;
  1624. X    goto again;
  1625. X}
  1626. NO_NEWS_IS_GOOD_NEWS
  1627. chmod 0644 menu.c || echo "restore of menu.c fails"
  1628. set `wc -c menu.c`;Sum=$1
  1629. if test "$Sum" != "23564"
  1630. then echo original size 23564, current size $Sum;fi
  1631. echo "x - extracting menu.h (Text)"
  1632. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > menu.h &&
  1633. X/* menu commands */
  1634. X
  1635. X#define ME_QUIT        0    /* quit nn                */
  1636. X#define ME_NEXT        1    /* continue to next group        */
  1637. X#define    ME_READ        2    /* read this group, cont to next     */
  1638. X#define ME_PREV        3    /* previous group            */
  1639. X#define ME_NO_ARTICLES    4    /* no articles in group            */
  1640. X#define ME_REDRAW    5    /* redraw screen after return */
  1641. X#define ME_NO_REDRAW    6    /* screen is not corrupted */
  1642. X
  1643. X/* show_articles commands */
  1644. X
  1645. X#define SH_QUIT        0    /* quit nn                 */
  1646. X#define SH_NEXT        1    /* goto next group, no read        */
  1647. X#define    SH_READ        2    /* articles has been read         */
  1648. X#define    SH_MENU        3    /* redraw menu                */ 
  1649. X#define    SH_NO_SELECT    4    /* no articles was selected        */
  1650. X
  1651. X
  1652. X/* more commands */
  1653. X
  1654. X#define MC_QUIT        0    /* quit nn */
  1655. X#define    MC_NEXT        1    /* next article */
  1656. X#define MC_MENU        2    /* return to menu */
  1657. X#define MC_PREV        3    /* previous article */
  1658. X#define MC_NEXTSUBJ    4    /* show next subject */
  1659. X#define MC_ALLSUBJ    5    /* show all with same subject */
  1660. X#define MC_NEXTGROUP    6    /* next group, no read */
  1661. X#define    MC_READGROUP    7    /* next group, mark as read */
  1662. X#define MC_PREVIEW_NEXT    8    /* preview next article */
  1663. X#define MC_PREVIEW_OTHER 9    /* preview another article */
  1664. X#define MC_REDRAW    10    /* redraw screen after return */
  1665. X#define MC_NO_REDRAW    11    /* screen is not corrupted */
  1666. X
  1667. X/* more modes */
  1668. X
  1669. X#define    MM_NORMAL    0    /* show article */
  1670. X#define MM_DIGEST    1    /* show full digest */
  1671. X#define MM_PREVIOUS    0x10    /* previous article exists */
  1672. X#define MM_LAST_ARTICLE    0x20    /* last article in group */
  1673. X#define MM_LAST_GROUP    0x40    /* last group */
  1674. X#define MM_PREVIEW    0x80    /* preview mode flag */
  1675. X
  1676. X/* alt_command return values */
  1677. X
  1678. X#define    AC_QUIT        0    /* quit nn */
  1679. X#define    AC_PROMPT    1    /* just redraw prompt line */
  1680. X#define    AC_REDRAW    2    /* redraw screen */
  1681. X#define AC_REORDER    3    /* articles have been reordered */
  1682. X#define    AC_HEADER    4    /* update header line + Prompt */
  1683. X#define AC_KEYCMD    5    /* alt_cmd_key contains command */
  1684. NO_NEWS_IS_GOOD_NEWS
  1685. chmod 0644 menu.h || echo "restore of menu.h fails"
  1686. set `wc -c menu.h`;Sum=$1
  1687. if test "$Sum" != "1853"
  1688. then echo original size 1853, current size $Sum;fi
  1689. echo "x - extracting mk_online_man (Text)"
  1690. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > mk_online_man &&
  1691. X# convert a manual to a folder
  1692. X
  1693. Xsed     -e 's/\\f[BPI]//g' \
  1694. X    -e 's/\\-/-/g' \
  1695. X    -e 's/\\&//' \
  1696. X    -e '/^\.\\"/d' \
  1697. X    -e '/^\.nf/d' \
  1698. X    -e '/^\.fi/d' \
  1699. X    -e 's/^\.[BI] //' "$@" |
  1700. Xawk '
  1701. XBEGIN {
  1702. X    l=""
  1703. X    o=""
  1704. X    m=72
  1705. X    a=0
  1706. X    h=""
  1707. X}
  1708. X/^\.SH / {
  1709. X    if (a) printf("%s\n\n", l)
  1710. X    a++
  1711. X    l=o=""
  1712. X    z=u=0
  1713. X    printf("From: %s\nSubject:", h);
  1714. X    for (i = 2; i <= NF; i++) printf(" %s", $i);
  1715. X    printf("\n\n");
  1716. X    next
  1717. X}
  1718. X/^\.TH / {
  1719. X    h=$2
  1720. X    next
  1721. X}
  1722. X/^\.UC / {
  1723. X    next
  1724. X}
  1725. X/^\.br/ {
  1726. X    if (l != o) printf("%s\n", l)
  1727. X    l=o
  1728. X    z=u
  1729. X    next
  1730. X}
  1731. X/^\.PP/ {
  1732. X    if (l != o) printf("%s\n", l)
  1733. X    printf("\n")
  1734. X    l="   "
  1735. X    z=3
  1736. X    o=""
  1737. X    u=0
  1738. X    next
  1739. X}
  1740. X/^\.LP/ || /^\.sp/ {
  1741. X    if (l != o) printf("%s\n", l)
  1742. X    printf("\n")
  1743. X    l=""
  1744. X    o=""
  1745. X    z=u=0
  1746. X    next
  1747. X}
  1748. X/^\.TP/ {
  1749. X    if (l != o) printf("%s\n", l)
  1750. X    printf("\n")
  1751. X    getline
  1752. X    l=$0
  1753. X    z=u=5
  1754. X    o="     "
  1755. X    if (length(l) >= 5) {
  1756. X        printf("%s\n", l)
  1757. X        l=o
  1758. X    } else while (length(l) < 4) l=l " "
  1759. X    next
  1760. X}
  1761. X{
  1762. X    s=1
  1763. X    p=" "
  1764. X    q=1
  1765. X}
  1766. X/^[     ]/ {
  1767. X    if (l != o) printf("%s\n",l)
  1768. X    l=o "     "
  1769. X    z=u+5
  1770. X}
  1771. X/^\.[IB] / {
  1772. X    s=2
  1773. X}
  1774. X/^\.[IB]R / {
  1775. X    s=2
  1776. X    p=""
  1777. X    q=0
  1778. X}
  1779. X{
  1780. X    r=" "
  1781. X    while (s <= NF) {
  1782. X        k=length($s)
  1783. X        if ((z+k) > m) {
  1784. X            printf("%s\n", l)
  1785. X            l=o
  1786. X            z=u
  1787. X        }
  1788. X        if (l != o)
  1789. X            l=l r $s
  1790. X        else
  1791. X            l=l $s
  1792. X        z=z + q + k
  1793. X        r=p
  1794. X        s++
  1795. X    }
  1796. X}
  1797. XEND {
  1798. X    if (l != o) printf("%s\n\n", l)
  1799. X}'
  1800. NO_NEWS_IS_GOOD_NEWS
  1801. chmod 0644 mk_online_man || echo "restore of mk_online_man fails"
  1802. set `wc -c mk_online_man`;Sum=$1
  1803. if test "$Sum" != "1198"
  1804. then echo original size 1198, current size $Sum;fi
  1805. echo "x - extracting more.c (Text)"
  1806. sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > more.c &&
  1807. X#include "config.h"
  1808. X#include "news.h"
  1809. X#include "term.h"
  1810. X#include "menu.h"
  1811. X#include "keymap.h"
  1812. X#include "regexp.h"
  1813. X
  1814. Xexport int  monitor_mode = 0;
  1815. Xexport int  show_article_date = 1;
  1816. Xexport int  first_page_lines = 0;
  1817. Xexport int  overlap = 2;
  1818. Xexport int  mark_overlap = 0;
  1819. Xexport char *header_lines = NULL;
  1820. X
  1821. Ximport int  preview_window;
  1822. Ximport int  novice;
  1823. X
  1824. Ximport char *delayed_msg;
  1825. X
  1826. Xextern char *init_save();
  1827. X
  1828. Xstatic char rot13tab[128];
  1829. Xstatic int norot13 = 1, rot13;
  1830. Xstatic int compress_space;
  1831. X
  1832. Xstatic regexp *regular_expr = NULL;
  1833. X
  1834. X#define LINEMAX    5000    /* max no of lines backed up */
  1835. X
  1836. Xstatic struct header_def {
  1837. X    char field;
  1838. X    char *text;
  1839. X    char **news;
  1840. X    char **digest;
  1841. X} header_defs[] = {
  1842. X    'A', "Approved",    &news.ng_appr,        0,
  1843. X    'B', "Distribution",&news.ng_dist,        0,
  1844. X    'D', "Date",    &news.ng_date,        &digest.dg_date,
  1845. X    'F', "From",    &news.ng_from,        &digest.dg_from,
  1846. X    'I', "Message-Id",    &news.ng_ident,        0,
  1847. X    'K', "Keywords",    &news.ng_keyw,        0,
  1848. X    'L', "Lines",    &news.ng_xlines,    0,
  1849. X    'N', "Newsgroups",    &news.ng_groups,    0,
  1850. X    'O', "Organization",&news.ng_org,        0,
  1851. X    'P', "Path",    &news.ng_path,        0,
  1852. X    'R', "Reply-To",    &news.ng_reply,        0,
  1853. X    'S', "Subject",    &news.ng_subj,        &digest.dg_subj,
  1854. X    'W', "Followup-To",    &news.ng_follow,    0,
  1855. X    'X', "References",    &news.ng_ref,        0,
  1856. X    0
  1857. X};
  1858. X
  1859. X
  1860. Xmore(ah, mode, screen_offset)
  1861. Xarticle_header *ah;
  1862. Xint mode, screen_offset;
  1863. X{
  1864. X    register c, col, lno;
  1865. X    register FILE *art;
  1866. X    int more_cmd, eof, skip_spaces, has_space, window_lines;
  1867. X    int form_feed, ignore_nl;
  1868. X    off_t firstl, lastl;
  1869. X    off_t linepos[LINEMAX];
  1870. X    char linebuf[200], *lp;
  1871. X    int linenum, maxline, topline, print_lines, lno1;
  1872. X    int underline_line, fake_underline;
  1873. X    int match_lines, match_redraw, match_topline, match_botline;
  1874. X    int goto_line, prev_goto, stop_line, extra_lines;
  1875. X    int in_digest = ah->flag & A_DIGEST;
  1876. X    article_header digestah;
  1877. X    char *fname, *hdrline;
  1878. X    extern STANDOUT;
  1879. X    char pr_fmt[60], send_date[40];
  1880. X    int match_expr;
  1881. X    char *match_start, *match_end;
  1882. X    int open_modes, hdr_mode, o_mode;
  1883. X    struct header_def *hdef;
  1884. X    extern int alt_cmd_key, in_menu_mode, any_message;
  1885. X#ifdef RESIZING
  1886. X    int entry_col = Columns;
  1887. X#endif    
  1888. X    extern char *pct();
  1889. X    
  1890. X#define more_return(cmd) \
  1891. X    { more_cmd = cmd; goto more_exit; }
  1892. X
  1893. X    if (ah->a_group != NULL) init_group(ah->a_group);
  1894. X    
  1895. X    open_modes = SKIP_HEADER;
  1896. X    if (show_article_date || header_lines) {
  1897. X    open_modes |= FILL_NEWS_HEADER;
  1898. X    if (header_lines == NULL) 
  1899. X        open_modes |= GET_DATE_ONLY;
  1900. X    else
  1901. X        open_modes |= GET_ALL_FIELDS;
  1902. X    if (in_digest) open_modes |= FILL_DIGEST_HEADER;
  1903. X    }
  1904. X    
  1905. X    /* temporary use of linepos array as header buffers... */
  1906. X
  1907. X    art = open_news_article(ah, open_modes, (char *)&linepos[100], (char *)&linepos[LINEMAX/2]);
  1908. X
  1909. X    if (art == NULL) {
  1910. X    msg("Expired: \"%s: %-.50s\"", ah->sender, ah->subject);
  1911. X    if ((mode & MM_PREVIEW) == 0) user_delay(1);
  1912. X    return MC_NEXT;
  1913. X    }
  1914. X
  1915. X    o_mode = in_menu_mode;
  1916. X    in_menu_mode = 0;
  1917. X    
  1918. X    if (screen_offset)
  1919. X    if (preview_window < 1 && Lines - screen_offset < 6) 
  1920. X        screen_offset = 0;
  1921. X        else {
  1922. X        so_printxy(0, screen_offset++, "%s: %s ", ah->sender, ah->subject);
  1923. X        if (!STANDOUT) screen_offset++;
  1924. X        clrline();
  1925. X    }
  1926. X    
  1927. X    if (show_article_date) {
  1928. X    if (in_digest && digest.dg_date)
  1929. X        strncpy(send_date, digest.dg_date, 40);
  1930. X    else
  1931. X        if (news.ng_date) {
  1932. X        strncpy(send_date, news.ng_date, 40);
  1933. X        } else
  1934. X        send_date[0] = NUL;
  1935. X    send_date[39] = NUL;
  1936. X    if (lp = strrchr(send_date, ':')) *lp = NUL;
  1937. X    }
  1938. X    
  1939. X    linepos[0] = ah->hpos;
  1940. X    linepos[1] = firstl = ah->fpos;
  1941. X    maxline = 1;
  1942. X    topline = 1;
  1943. X    hdrline = screen_offset == 0 ? header_lines : "";
  1944. X    
  1945. X    lastl = (ah->lpos - firstl + 99)/100;
  1946. X    if (lastl == 0) lastl = 1;    /* impossible ? */
  1947. X    
  1948. X    rot13 = 0;
  1949. X    compress_space = 0;
  1950. X    goto_line = -1, prev_goto = 1;
  1951. X    match_lines = match_redraw = match_expr = 0;
  1952. X    underline_line = -1;
  1953. X    fake_underline = 0;
  1954. X    
  1955. X    stop_line = first_page_lines ? first_page_lines : -1;
  1956. X
  1957. X    sprintf(pr_fmt,
  1958. X       "\1\2-- %s%s %s-----%%s-----\1",
  1959. X       (mode & MM_PREVIEW) ? "PREVIEW " : "",
  1960. X       (mode & MM_DIGEST) ? "FULL DIGEST" :
  1961. X       (mode & MM_LAST_ARTICLE) ? "LAST ARTICLE" : "ARTICLE",
  1962. X       novice ? "-- help:? " : "");
  1963. X
  1964. X    if (screen_offset) goto safe_redraw;
  1965. X    
  1966. X redraw:        /* redraw that will destroy whole screen */
  1967. X    screen_offset = 0;
  1968. X
  1969. X safe_redraw:     /* redraw of "more window" only */
  1970. X    linenum = topline;
  1971. X    
  1972. X next_page:
  1973. X    no_raw();
  1974. X
  1975. X    s_keyboard = 0;
  1976. X
  1977. X    if (stop_line) {
  1978. X    
  1979. X    if (lno = screen_offset) {
  1980. X        gotoxy(0, lno);
  1981. X        clrpage(lno);
  1982. X    } else
  1983. X        clrdisp();
  1984. X
  1985. X      print_header:
  1986. X    if (hdrline == NULL || *hdrline == '*') {
  1987. X        if (hdrline && *++hdrline == NUL) hdrline = NULL;
  1988. X
  1989. X        if (linenum <= 1) {
  1990. X        if (linenum == 0 || (mode & MM_DIGEST)) {
  1991. X            if (screen_offset) {
  1992. X            lno--;
  1993. X            if (!STANDOUT) lno--;
  1994. X            gotoxy(0, lno);
  1995. X            clrpage(lno);
  1996. X            }
  1997. X            so_printxy(0, lno,
  1998. X                   "Newsgroup: %s, article: %ld%s",
  1999. X                   current_group->group_name,
  2000. X                   (long)(ah->a_number),
  2001. X                   ((mode & MM_DIGEST) || in_digest) 
  2002. X                   ? "  *DIGEST*" : "");
  2003. X/*            fseek(art, linepos[0], 0); */
  2004. X            
  2005. X            lno++;
  2006. X            if (!STANDOUT) lno++;
  2007. X        } else {
  2008. X            if (screen_offset == 0 && linenum == 1) {
  2009. X            if (show_article_date) so_printxy(-1, 0, send_date);
  2010. X            
  2011. X            /* so_printxy will cut subject */
  2012. X            so_printxy(0, lno, "%s: %s ", ah->sender, ah->subject);
  2013. X            lno++;
  2014. X            if (!STANDOUT) lno++;
  2015. X            }
  2016. X        }
  2017. X        }
  2018. X    }
  2019. X
  2020. X    if (hdrline && screen_offset == 0) {
  2021. X        
  2022. X        hdr_mode = 0;
  2023. X        while (*hdrline) {
  2024. X        
  2025. X        if (*hdrline == '*') goto print_header;
  2026. X        
  2027. X        if (*hdrline == '=') {
  2028. X            hdr_mode = 1;
  2029. X            hdrline++;
  2030. X            continue;
  2031. X        }
  2032. X        if (*hdrline == '_') {
  2033. X            hdr_mode = 2;
  2034. X            hdrline++;
  2035. X            continue;
  2036. X        }
  2037. X        for (hdef = header_defs; hdef->field; hdef++) {
  2038. X            if (hdef->field != *hdrline) continue;
  2039. X            if (in_digest) {
  2040. X            if (hdef->digest == NULL) break;
  2041. X            if ((lp = *(hdef->digest)) == NULL)
  2042. X                break;
  2043. X            } else 
  2044. X            if ((lp = *(hdef->news)) == NULL)
  2045. X                break;
  2046. X            gotoxy(0, lno++);
  2047. X            c = strlen(hdef->text) + 2;
  2048. X            col = c + strlen(lp);
  2049. X            if (col > Columns) lp[Columns - c] = 0;
  2050. X            printf("%s: ", hdef->text);
  2051. X            switch (hdr_mode) {
  2052. X             case 0:
  2053. X            break;
  2054. X             case 1:
  2055. X            highlight(1);
  2056. X            break;
  2057. X             case 2:
  2058. X            underline(1);
  2059. X            break;
  2060. X            }
  2061. X            printf("%s", lp);
  2062. X            switch (hdr_mode) {
  2063. X             case 0:
  2064. X            break;
  2065. X             case 1:
  2066. X            highlight(0);
  2067. X            break;
  2068. X             case 2:
  2069. X            underline(0);
  2070. X            break;
  2071. X            }
  2072. X            break;
  2073. X        }
  2074. X        hdr_mode = 0;
  2075. X        hdrline++;
  2076. X        }
  2077. X        
  2078. X        hdrline = NULL;
  2079. X        putchar(NL);
  2080. X        lno++;
  2081. X    }
  2082. X        
  2083. X    lno1 = lno;
  2084. X    topline = linenum;
  2085. X    
  2086. X    window_lines = Lines - lno - 2;
  2087. X    print_lines = window_lines;
  2088. X    
  2089. X    ignore_nl = 1;    /* ignore blank lines at top op screen */
  2090. X    } else
  2091. X    print_lines = extra_lines;    /* LINT complaints here -- ignore */
  2092. X    
  2093. X    if (stop_line > 0) {
  2094. X    if (print_lines > stop_line) {
  2095. X        extra_lines = print_lines - stop_line;
  2096. X        print_lines = stop_line;
  2097. X        underline_line = -1;
  2098. X    }
  2099. X    stop_line = 0;
  2100. X    } else
  2101. X    stop_line = -1;
  2102. X    
  2103. X next_line:
  2104. X
  2105. X    if (linenum == LINEMAX) {
  2106. X    /* THIS IS EXTREMELY DIRTY (like most quick hacks) */
  2107. X    /* the following definitions assume that LINEMAX >> START+SIZE  */
  2108. X#define    HACK_START    1000    /* line numbers > START_POS are wrong */
  2109. X#define    HACK_SIZE    1000    /* we simply delete HACK_SIZE lines */
  2110. X    for (linenum = HACK_START; linenum < (LINEMAX-HACK_SIZE); linenum++)
  2111. X        linepos[linenum] = linepos[linenum+HACK_SIZE];
  2112. X    maxline = linenum - 1;
  2113. X    if (goto_line > 0) goto_line -= HACK_SIZE;
  2114. X    if (prev_goto > HACK_START)
  2115. X        if (prev_goto > (HACK_START + HACK_SIZE))
  2116. X        prev_goto -= HACK_SIZE;
  2117. X        else
  2118. X        prev_goto = HACK_START;
  2119. X    }
  2120. X    
  2121. X    if (goto_line == linenum) {
  2122. X    goto_line = -1;
  2123. X    goto next_page;
  2124. X    }
  2125. X    
  2126. X    eof = 0;
  2127. X
  2128. X    if (linenum > maxline)
  2129. X    linepos[++maxline] = ftell(art);
  2130. X    else
  2131. X    if (linenum > 0)
  2132. X    fseek(art, linepos[linenum], 0);
  2133. X        
  2134. X
  2135. X    if (linepos[linenum] >= ah->lpos) {
  2136. X    if (match_expr) {
  2137. X        match_expr = 0;
  2138. X        topline = match_topline;    /* LINT complaints here -- ignore */
  2139. X        linenum = match_botline;    /* LINT complaints here -- ignore */
  2140. X        fseek(art, linepos[linenum], 0);
  2141. X        msg("Not found");
  2142. X        goto Prompt;
  2143. X    }
  2144. X    eof++;
  2145. X    if (goto_line > 0) {
  2146. X        goto_line = -1;
  2147. X        linenum -= window_lines/2;
  2148. X        goto next_page;
  2149. X    }
  2150. X    goto Prompt;
  2151. X    }
  2152. X
  2153. X    if (linenum == 0) {
  2154. X    if (ftell(art) >= linepos[1]) {
  2155. X        linenum = 2;    /* current line is 1st line ! */
  2156. X        lno1 = lno;
  2157. X    }
  2158. X    } else
  2159. X    linenum++;
  2160. X    
  2161. X    lp = linebuf;
  2162. X    col = 0;
  2163. X    form_feed = 0;
  2164. X    
  2165. X next_char:
  2166. X
  2167. X    c = getc(art);
  2168. X    if (c == EOF) {
  2169. X    eof++;
  2170. X    if (lp == linebuf) goto Prompt;
  2171. X    goto end_line;
  2172. X    }
  2173. X    
  2174. X    if (c & 0200) {
  2175. X    col += 4;
  2176. X    if (col > Columns) {    /* then there is no room for M-^X */
  2177. X        ungetc(c, art);
  2178. X        goto long_line;
  2179. X    }
  2180. X    c &= 0177;
  2181. X    *lp++ = 'M';
  2182. X    *lp++ = '-';
  2183. X    if (c < SP) {
  2184. X        *lp++ = '^';
  2185. X        c += '@';
  2186. X    } else
  2187. X        col--;
  2188. X    } else
  2189. X    if (c < SP) {
  2190. X    if (monitor_mode) {
  2191. X        if (c == NL) {
  2192. X        *lp++ = '$';
  2193. X            goto end_line;
  2194. X        }
  2195. X        if (col + 2 > Columns) {
  2196. X        *lp++ = '\\';
  2197. X        ungetc(c, art);
  2198. X        goto end_line;
  2199. X        }
  2200. X        *lp++ = '^';
  2201. X        c += '@';
  2202. X        col++;
  2203. X    } else
  2204. X    switch (c) {
  2205. X
  2206. X     case '\f':
  2207. X        if (lp == linebuf) {
  2208. X        if (goto_line && lno == lno1) goto next_line;
  2209. X        form_feed = 1;
  2210. X        goto Prompt;
  2211. X        }
  2212. X        form_feed = 1;
  2213. X        goto end_line;
  2214. X        
  2215. X     case CR:
  2216. X        if (lp == linebuf || ignore_nl) goto next_char;
  2217. X        ignore_nl = 1;
  2218. X        goto end_line;
  2219. X
  2220. X     case NL:
  2221. X        if (ignore_nl) {
  2222. X        ignore_nl = 0;
  2223. X        if (lp == linebuf) {
  2224. X            if (lno == lno1) {
  2225. X            ignore_nl = 1;
  2226. X            goto next_line;
  2227. X            }
  2228. X            goto next_char;
  2229. X        }
  2230. X        }
  2231. X        goto end_line;
  2232. X        
  2233. X     case BS:
  2234. X        if (col) {
  2235. X        lp--;
  2236. X        col--;
  2237. X        }
  2238. X        goto next_char;
  2239. X        
  2240. X     case TAB:
  2241. X        if (col + 8 - (col & 07) >= Columns) 
  2242. X        goto long_line;
  2243. X
  2244. X        do {
  2245. X        *lp++ = SP;
  2246. X        col++;
  2247. X        } while (col & 07);
  2248. X        goto next_char;
  2249. X        
  2250. X     default:
  2251. X        if (col + 2 > Columns) {
  2252. X        ungetc(c, art);
  2253. X        goto long_line;
  2254. X        }
  2255. X        *lp++ = '^';
  2256. X        c += '@';
  2257. X        col++;
  2258. X        break;
  2259. X    }
  2260. X    }
  2261. X    
  2262. X    *lp++ = c;
  2263. X    col++;
  2264. X    ignore_nl = 0;
  2265. X    
  2266. X    if (col < Columns) goto next_char;
  2267. X    
  2268. Xlong_line:
  2269. X    ignore_nl = 1;
  2270. X    
  2271. X end_line:
  2272. X    /* if we are seaching for a specific line, repeat until it is found */
  2273. X    if (goto_line >= linenum) goto next_line;
  2274. X
  2275. X    *lp++ = NUL;
  2276. X
  2277. X    if (match_expr) {
  2278. X    if (!regexec(regular_expr, linebuf))
  2279. X        goto next_line;
  2280. X    match_expr = 0;
  2281. NO_NEWS_IS_GOOD_NEWS
  2282. echo "End of part 7"
  2283. echo "File more.c is continued in part 8"
  2284. echo "8" > s2_seq_.tmp
  2285. exit 0
  2286. ---
  2287. Kim F. Storm        storm@texas.dk        Tel +45 429 174 00
  2288. Texas Instruments, Marielundvej 46E, DK-2730 Herlev, Denmark
  2289.       No news is good news, but nn is better!
  2290.  
  2291.