home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume27 / trn-3.3 / part08 / rt-select.c < prev   
C/C++ Source or Header  |  1993-11-27  |  24KB  |  1,010 lines

  1. /* $Id: rt-select.c,v 3.0 1992/12/14 00:14:12 davison Trn $
  2. */
  3. /* The authors make no claims as to the fitness or correctness of this software
  4.  * for any use whatsoever, and it is provided as is. Any use of this software
  5.  * is at the user's own risk. 
  6.  */
  7.  
  8. #include "EXTERN.h"
  9. #include "common.h"
  10. #include "trn.h"
  11. #include "term.h"
  12. #include "final.h"
  13. #include "util.h"
  14. #include "help.h"
  15. #include "cache.h"
  16. #include "bits.h"
  17. #include "artsrch.h"
  18. #include "ng.h"
  19. #include "ngdata.h"
  20. #include "ngstuff.h"
  21. #include "kfile.h"
  22. #include "rthread.h"
  23. #include "rt-page.h"
  24. #include "rt-util.h"
  25. #include "INTERN.h"
  26. #include "rt-select.h"
  27.  
  28. /* When display mode is 'l', each author gets a separate line; when 's', no
  29. ** authors are displayed.
  30. */
  31. char *display_mode = select_order;
  32. char sel_disp_char[] = { ' ', '+', '-', '*' };
  33.  
  34. static char sel_ret;
  35. static bool empty_ok;
  36. static bool disp_status_line;
  37. static bool clean_screen;
  38.  
  39. /* Display a menu of threads/subjects/articles for the user to choose from.
  40. ** If "cmd" is '+' we display all the unread items and allow the user to mark
  41. ** them as selected and perform various commands upon them.  If "cmd" is 'U'
  42. ** the list consists of previously-read items for the user to mark as unread.
  43. */
  44. char
  45. do_selector(cmd)
  46. char_int cmd;
  47. {
  48.     register int j;
  49.     int got_dash;
  50.     int ch, action;
  51.     char page_char, end_char;
  52.     char promptbuf[80];
  53.     char oldmode = mode;
  54.     char *in_select;
  55.  
  56.     mode = 't';
  57.     art = lastart+1;
  58.     sel_rereading = (cmd == 'U');
  59.     clear_on_stop = TRUE;
  60.     empty_ok = FALSE;
  61.  
  62.     set_sel_mode(cmd);
  63.  
  64.     if (!cache_range(sel_rereading? absfirst : firstart, lastart)) {
  65.     sel_ret = '+';
  66.     goto sel_exit;
  67.     }
  68.  
  69.   start_selector:
  70.     /* Setup for selecting articles to read or set unread */
  71.     if (sel_rereading) {
  72.     page_char = '>';
  73.     end_char = 'Z';
  74.     sel_page_app = Null(ARTICLE**);
  75.     sel_page_sp = Nullsubj;
  76.     sel_mask = AF_DELSEL;
  77.     } else {
  78.     page_char = page_select;
  79.     end_char = end_select;
  80.     if (curr_artp) {
  81.         sel_last_ap = curr_artp;
  82.         sel_last_sp = curr_artp->subj;
  83.     }
  84.     sel_mask = AF_SEL;
  85.     }
  86.     selected_only = TRUE;
  87.     count_subjects(cmd ? CS_UNSEL_STORE : CS_NORM);
  88.  
  89.     /* If nothing to display, we're done. */
  90.     if (!article_count && !empty_ok) {
  91.     empty_complaint();
  92.     sel_ret = '+';
  93.     goto sel_exit;
  94.     }
  95.     init_pages();
  96.     sel_item_index = 0;
  97.     *promptbuf = '\0';
  98.     disp_status_line = FALSE;
  99.     if (added_articles > 0) {
  100.     register long i = added_articles, j;
  101.     register ARTICLE *ap = article_ptr(lastart - i + 1);
  102.     for (j = 0; j < added_articles; j++, ap++) {
  103.         if (ap->flags & AF_READ)
  104.         i--;
  105.     }
  106.     if (i == added_articles)
  107.         sprintf(promptbuf, "** %ld new article%s arrived **  ",
  108.         (long)added_articles, added_articles == 1? nullstr : "s");
  109.     else
  110.         sprintf(promptbuf, "** %ld of %ld new articles unread **  ",
  111.         i, (long)added_articles);
  112.     disp_status_line = TRUE;
  113.     }
  114.     added_articles = 0;
  115.     if (cmd && selected_count) {
  116.     sprintf(promptbuf+strlen(promptbuf), "%ld article%s selected.",
  117.         (long)selected_count, selected_count == 1? " is" : "s are");
  118.     disp_status_line = TRUE;
  119.     }
  120.     cmd = 0;
  121. display_selector:
  122.     /* Present a page of items to the user */
  123.     display_page();
  124.  
  125.     /* Check if there is really anything left to display. */
  126.     if (!sel_item_cnt && !empty_ok) { /*TODO: this may not be needed anymore */
  127.     empty_complaint();
  128.     sel_ret = '+';
  129.     goto sel_exit;
  130.     }
  131.     empty_ok = FALSE;
  132.  
  133.     if (sel_item_index >= sel_item_cnt)
  134.     sel_item_index = 0;
  135.     if (disp_status_line) {
  136.     printf("\n%s", promptbuf);
  137.     if (can_home) {
  138.         carriage_return();
  139.         goto_line(sel_last_line+1, sel_last_line);
  140.     } else
  141.         putchar('\n');
  142.     }
  143. reask_selector:
  144.     /* Prompt the user */
  145. #ifdef MAILCALL
  146.     setmail(FALSE);
  147. #endif
  148.     if (sel_at_end)
  149.     sprintf(cmd_buf, "%s [%c%c] --",
  150.         (!sel_prior_arts? "All" : "Bot"), end_char, page_char);
  151.     else
  152.     sprintf(cmd_buf, "%s%ld%% [%c%c] --",
  153.         (!sel_prior_arts? "Top " : nullstr),
  154.         (long)((sel_prior_arts+sel_page_arts)*100 / sel_total_arts),
  155.         page_char, end_char);
  156.     sprintf(promptbuf, "%s-- %s %s (%s%s order) -- %s", mailcall,
  157.         sel_exclusive? "SELECTED" : "Select", sel_mode_string,
  158.         sel_direction<0? "reverse " : nullstr, sel_sort_string, cmd_buf);
  159. #ifdef CLEAREOL
  160.     if (erase_screen && can_home_clear)
  161.     clear_rest();
  162. #endif
  163.     standout();
  164.     fputs(promptbuf, stdout);
  165.     un_standout();
  166.     if (can_home)
  167.     carriage_return();
  168.     sel_line = sel_last_line;
  169. position_selector:
  170.     got_dash = 0;
  171.     if (can_home)
  172.     goto_line(sel_line, sel_items[sel_item_index].line);
  173.     sel_line = sel_items[sel_item_index].line;
  174. reinp_selector:
  175.     /* Grab some commands from the user */
  176.     fflush(stdout);
  177.     eat_typeahead();
  178.     spin_char = sel_chars[sel_item_index];
  179.     cache_until_key();
  180.     spin_char = ' ';
  181. #ifdef CONDSUB
  182.     getcmd(buf);
  183.     ch = *buf;
  184. #else
  185.     getcmd(cmd_buf);    /* If no conditionals, don't allow macros */ 
  186.     buf[0] = ch = *cmd_buf;
  187.     buf[1] = FINISHCMD;
  188. #endif
  189.     if (errno)
  190.     ch = Ctl('l');
  191.     if (disp_status_line) {
  192.     if (can_home) {
  193.         goto_line(sel_line, sel_last_line+1);
  194.         erase_eol();
  195.         sel_line = sel_last_line+1;
  196.     }
  197.     disp_status_line = FALSE;
  198.     }
  199.     if (ch == '-') {
  200.     got_dash = 1;
  201.     if (!can_home)
  202.         putchar('-'), fflush(stdout);
  203.     goto reinp_selector;
  204.     }
  205.     if (ch == ' ') {
  206.     if (sel_at_end)
  207.         ch = end_char;
  208.     else
  209.         ch = page_char;
  210.     }
  211.     in_select = index(sel_chars, ch);
  212.     if (in_select) {
  213.     j = in_select - sel_chars;
  214.     if (j >= sel_item_cnt) {
  215.         dingaling();
  216.         goto position_selector;
  217.     } else if (got_dash)
  218.         ;
  219.     else if (sel_items[j].sel == 1)
  220.         action = (sel_rereading ? 'k' : '-');
  221.     else
  222.         action = '+';
  223.     } else if (ch == '*' && sel_mode == SM_ARTICLE) {
  224.     register ARTICLE *ap = (ARTICLE*)sel_items[sel_item_index].ptr;
  225.     if (sel_items[sel_item_index].sel)
  226.         deselect_subject(ap->subj);
  227.     else
  228.         select_subject(ap->subj, 0);
  229.     update_page();
  230.     goto position_selector;
  231.     } else if (ch == 'y' || ch == '.' || ch == '*') {
  232.     j = sel_item_index;
  233.     if (sel_items[j].sel == 1)
  234.         action = (sel_rereading ? 'k' : '-');
  235.     else
  236.         action = '+';
  237.     } else if (ch == 'k' || ch == 'j' || ch == ',') {
  238.     j = sel_item_index;
  239.     action = 'k';
  240.     } else if (ch == 'm' || ch == '\\') {
  241.     j = sel_item_index;
  242.     action = '-';
  243.     } else if (ch == 'M') {
  244.     j = sel_item_index;
  245.     action = 'M';
  246.     } else if (ch == '@') {
  247.     sel_item_index = 0;
  248.     j = sel_item_cnt-1;
  249.     got_dash = 1;
  250.     action = '@';
  251.     } else if (ch == '[' || ch == 'p') {
  252.     if (--sel_item_index < 0)
  253.         sel_item_index = sel_item_cnt ? sel_item_cnt-1 : 0;
  254.     goto position_selector;
  255.     } else if (ch == ']' || ch == 'n') {
  256.     if (++sel_item_index >= sel_item_cnt)
  257.         sel_item_index = 0;
  258.     goto position_selector;
  259.     } else {
  260.     sel_ret = ch;
  261.     switch (sel_command(ch)) {
  262.     case DS_POS:
  263.         if (!clean_screen)
  264.         goto display_selector;
  265.         goto position_selector;
  266.     case DS_ASK:
  267.         if (!clean_screen)
  268.         goto display_selector;
  269.         goto reask_selector;
  270.     case DS_DISPLAY:
  271.     ds_display:
  272.         if (disp_status_line)
  273.         strcpy(promptbuf, buf);
  274.         goto display_selector;
  275.     case DS_UPDATE:
  276.         if (!clean_screen)
  277.         goto ds_display;
  278.         if (disp_status_line) {
  279.         printf("\n%s",buf);
  280.         if (can_home) {
  281.             carriage_return();
  282.             up_line();
  283.             erase_eol();
  284.         }
  285.         }
  286.         update_page();
  287.         if (can_home) {
  288.         goto_line(sel_line, sel_last_line);
  289.         sel_line = sel_last_line;
  290.         }
  291.         goto reask_selector;
  292.     case DS_RESTART:
  293.         goto start_selector;
  294.     case DS_QUIT:
  295.         sel_cleanup();
  296.         if (!output_chase_phrase)
  297.         putchar('\n') FLUSH;
  298.         goto sel_exit;
  299.     case DS_STATUS:
  300.         disp_status_line = TRUE;
  301.         if (!clean_screen) {
  302.         strcpy(promptbuf, buf);
  303.         goto display_selector;
  304.         }
  305.         if (can_home) {
  306.         goto_line(sel_line, sel_last_line+1);
  307.         sel_line = sel_last_line+1;
  308.         } else
  309.         putchar('\n');
  310.  
  311.         fputs(buf, stdout);
  312.  
  313.         if (can_home)
  314.         carriage_return();
  315.         else
  316.         putchar('\n');
  317.         goto position_selector;
  318.     }
  319.     }
  320.  
  321.     /* The user manipulated one of the letters -- handle it. */
  322.     if (!got_dash)
  323.     sel_item_index = j;
  324.     else {
  325.     if (j < sel_item_index) {
  326.         ch = sel_item_index-1;
  327.         sel_item_index = j;
  328.         j = ch;
  329.     }
  330.     }
  331.     if (++j == sel_item_cnt)
  332.     j = 0;
  333.     do {
  334.     register int sel = sel_items[sel_item_index].sel;
  335.     register SUBJECT *sp = (SUBJECT*)sel_items[sel_item_index].ptr;
  336.     if (can_home) {
  337.         goto_line(sel_line, sel_items[sel_item_index].line);
  338.         sel_line = sel_items[sel_item_index].line;
  339.     }
  340.     if (action == '@') {
  341.         if (sel == 2)
  342.         ch = (sel_rereading ? '+' : ' ');
  343.         else if (sel_rereading)
  344.         ch = 'k';
  345.         else if (sel == 1)
  346.         ch = '-';
  347.         else
  348.         ch = '+';
  349.     } else
  350.         ch = action;
  351.     switch (ch) {
  352.     case '+':
  353.         if (sel_mode == SM_THREAD)
  354.         select_thread(sp->thread, 0);
  355.         else if (sel_mode == SM_SUBJECT)
  356.         select_subject(sp, 0);
  357.         else
  358.         select_article((ARTICLE*)sp, 0);
  359.         output_sel(1);
  360.         break;
  361.     case '-':  case 'k':  case 'M':
  362.        {
  363.         bool sel_reread_save = sel_rereading;
  364.         if (ch == 'M') {
  365.         if (sel_mode == SM_ARTICLE)
  366.             delay_unmark((ARTICLE*)sp);
  367.         else {
  368.             register ARTICLE *ap;
  369.             if (sel_mode == SM_THREAD) {
  370.             for (ap = first_art(sp); ap; ap = next_art(ap))
  371.                 if (!(ap->flags & AF_READ) ^ sel_rereading)
  372.                 delay_unmark(ap);
  373.             } else {
  374.             for (ap = sp->articles; ap; ap = ap->subj_next)
  375.                 if (!(ap->flags & AF_READ) ^ sel_rereading)
  376.                 delay_unmark(ap);
  377.             }
  378.         }
  379.         }
  380.         if (ch == '-')
  381.         sel_rereading = FALSE;
  382.         else
  383.         sel_rereading = TRUE;
  384.         if (sel_mode == SM_THREAD)
  385.         deselect_thread(sp->thread);
  386.         else if (sel_mode == SM_SUBJECT)
  387.         deselect_subject(sp);
  388.         else
  389.         deselect_article((ARTICLE*)sp);
  390.         sel_rereading = sel_reread_save;
  391.         output_sel(ch == '-'? 0 : 2);
  392.         break;
  393.        }
  394.     }
  395.     fflush(stdout);
  396.     if (++sel_item_index == sel_item_cnt)
  397.         sel_item_index = 0;
  398.     if (can_home)
  399.         carriage_return();
  400.     } while (sel_item_index != j);
  401.     goto position_selector;
  402.  
  403. sel_exit:
  404.     if (sel_rereading) {
  405.     sel_rereading = 0;
  406.     sel_mask = AF_SEL;
  407.     }
  408.     if (sel_mode != SM_ARTICLE || sel_sort == SS_GROUPS
  409.      || sel_sort == SS_SUBJECT) {
  410.     if (artptr_list) {
  411.         free((char*)artptr_list);
  412.         artptr_list = sel_page_app = Null(ARTICLE**);
  413.         sort_subjects();
  414.     }
  415.     artptr = Null(ARTICLE**);
  416. #ifdef ARTSEARCH
  417.     if (!ThreadedGroup)
  418.         srchahead = -1;
  419. #endif
  420.     }
  421. #ifdef ARTSEARCH
  422.     else
  423.     srchahead = 0;
  424. #endif
  425. /*    selected_only = (selected_count || !article_count);*/
  426.     selected_only = (selected_count != 0);
  427.     if (sel_ret != '#')
  428.     count_subjects(sel_ret == '+'? CS_RESELECT : CS_UNSELECT);
  429.     clear_on_stop = FALSE;
  430.     mode = oldmode;
  431.     if (sel_ret == '+') {
  432.     art = curr_art;
  433.     artp = curr_artp;
  434.     } else
  435.     top_article();
  436.     return sel_ret;
  437. }
  438.  
  439. static void
  440. sel_cleanup()
  441. {
  442.     if (sel_rereading) {
  443.     /* Turn selections into unread selected articles.  Let
  444.     ** count_subjects() fix the counts after we're through.
  445.     */
  446.     register SUBJECT *sp;
  447.     sel_last_ap = Nullart;
  448.     sel_last_sp = Nullsubj;
  449.     for (sp = first_subject; sp; sp = sp->next)
  450.         unkill_subject(sp);
  451.     } else {
  452.     if (sel_mode == SM_ARTICLE) {
  453.         register ARTICLE *ap;
  454.         register ART_NUM an;
  455.         for (an=absfirst, ap=article_ptr(an); an<=lastart; an++, ap++) {
  456.         if (ap->flags & AF_DEL) {
  457.             ap->flags &= ~AF_DEL;
  458.             set_read(ap);
  459.         }
  460.         }
  461.     } else {
  462.         register SUBJECT *sp;
  463.         for (sp = first_subject; sp; sp = sp->next) {
  464.         if (sp->flags & SF_DEL) {
  465.             sp->flags &= ~SF_DEL;
  466.             if (sel_mode == SM_THREAD)
  467.             kill_thread(sp->thread, KF_UNSELECTED);
  468.             else
  469.             kill_subject(sp, KF_UNSELECTED);
  470.         }
  471.         }
  472.     }
  473.     }
  474. }
  475.  
  476. static int
  477. sel_command(ch)
  478. char_int ch;
  479. {
  480.     if (can_home)
  481.     goto_line(sel_line, sel_last_line);
  482.     sel_line = sel_last_line;
  483.     clean_screen = TRUE;
  484.   do_command:
  485.     output_chase_phrase = TRUE;
  486.     switch (ch) {
  487.     case '>':
  488.     sel_item_index = 0;
  489.     if (next_page())
  490.         return DS_DISPLAY;
  491.     return DS_POS;
  492.     case '<':
  493.     sel_item_index = 0;
  494.     if (prev_page())
  495.         return DS_DISPLAY;
  496.     return DS_POS;
  497.     case '^':  case Ctl('r'):
  498.     sel_item_index = 0;
  499.     if (first_page())
  500.         return DS_DISPLAY;
  501.     return DS_POS;
  502.     case '$':
  503.     sel_item_index = 0;
  504.     if (last_page())
  505.         return DS_DISPLAY;
  506.     return DS_POS;
  507.     case Ctl('l'):
  508.     return DS_DISPLAY;
  509.     case Ctl('f'):
  510.     erase_eol();        /* erase the prompt */
  511. #ifdef MAILCALL
  512.     setmail(TRUE);        /* force a mail check */
  513. #endif
  514.     return DS_ASK;
  515.     case '#':
  516.        {
  517.     register SUBJECT *sp;
  518.     for (sp = first_subject; sp; sp = sp->next)
  519.         sp->flags &= ~SF_VISIT;
  520.     selected_count = 0;
  521.     sp = (SUBJECT*)sel_items[sel_item_index].ptr;
  522.     switch (sel_mode) {
  523.     case SM_THREAD:
  524.         deselect_thread(sp->thread);
  525.         select_thread(sp->thread, 0);
  526.         break;
  527.     case SM_SUBJECT:
  528.         deselect_subject(sp);
  529.         select_subject(sp, 0);
  530.         break;
  531.     case SM_ARTICLE:
  532.         deselect_article((ARTICLE*)sp);
  533.         select_article((ARTICLE*)sp, 0);
  534.         break;
  535.     }
  536.     return DS_QUIT;
  537.        }
  538.     case '\r':  case '\n':
  539.     if (!selected_count) {
  540.         if (sel_rereading || sel_items[sel_item_index].sel != 2) {
  541.         register SUBJECT *sp = (SUBJECT*)sel_items[sel_item_index].ptr;
  542.         switch (sel_mode) {
  543.         case SM_THREAD:
  544.             select_thread(sp->thread, 0);
  545.             break;
  546.         case SM_SUBJECT:
  547.             select_subject(sp, 0);
  548.             break;
  549.         case SM_ARTICLE:
  550.             select_article((ARTICLE*)sp, 0);
  551.             break;
  552.         }
  553.         }
  554.     }
  555.     return DS_QUIT;
  556.     case 'Z':  case '\t':
  557.     return DS_QUIT;
  558.     case 'q':  case 'Q':
  559.     return DS_QUIT;
  560.     case Ctl('Q'):  case '\033':  case '+':
  561.     sel_ret = '+';
  562.     return DS_QUIT;
  563.     case 'N':  case 'P':
  564.     return DS_QUIT;
  565.     case 'L':
  566.     if (!*++display_mode)
  567.         display_mode = select_order;
  568.     return DS_DISPLAY;
  569.     case 'Y':
  570.     if (!dmcount) {
  571.         sprintf(buf,"No marked articles to yank back.");
  572.         return DS_STATUS;
  573.     }
  574.     yankback();
  575.     sel_line++;
  576.     if (!sel_rereading)
  577.         sel_cleanup();
  578.     disp_status_line = TRUE;
  579.     count_subjects(CS_NORM);
  580.     sel_page_sp = Nullsubj;
  581.     sel_page_app = Null(ARTICLE**);
  582.     init_pages();
  583.     return DS_DISPLAY;
  584.     case 'U':
  585.     sel_cleanup();
  586.     sel_rereading = !sel_rereading;
  587.     sel_page_sp = Nullsubj;
  588.     sel_page_app = Null(ARTICLE**);
  589.     if (!cache_range(sel_rereading? absfirst : firstart, lastart))
  590.         sel_rereading = !sel_rereading;
  591.     empty_ok = TRUE;
  592.     return DS_RESTART;
  593.     case '=':
  594.     if (!sel_rereading)
  595.         sel_cleanup();
  596.     if (sel_mode == SM_ARTICLE) {
  597.         set_selector(sel_threadmode, sel_threadsort);
  598.         sel_page_sp = sel_page_app[0]->subj;
  599.     } else {
  600.         set_selector(SM_ARTICLE, sel_artsort);
  601.         sel_page_app = 0;
  602.     }
  603.     count_subjects(CS_NORM);
  604.     sel_item_index = 0;
  605.     init_pages();
  606.     return DS_DISPLAY;
  607.     case 'S':
  608.     if (!sel_rereading)
  609.         sel_cleanup();
  610.     erase_eol();        /* erase the prompt */
  611.     reask_output:
  612.     in_char("Selector mode:  Threads, Subjects, Articles? [tsa] ", 'o');
  613.     setdef(buf,"t");
  614. #ifdef VERIFY
  615.     printcmd();
  616. #endif
  617.     if (*buf == 'h') {
  618. #ifdef VERBOSE
  619.         IF(verbose)
  620.         fputs("\n\
  621. Type t or SP to display/select thread groups (threads the group, if needed).\n\
  622. Type s to display/select subject groups.\n\
  623. Type a to display/select individual articles.\n\
  624. Type q to leave things as they are.\n\n\
  625. ",stdout) FLUSH;
  626.         ELSE
  627. #endif
  628. #ifdef TERSE
  629.         fputs("\n\
  630. t or SP selects thread groups (threads the group too).\n\
  631. s selects subject groups.\n\
  632. a selects individual articles.\n\
  633. q does nothing.\n\n\
  634. ",stdout) FLUSH;
  635. #endif
  636.         clean_screen = FALSE;
  637.         goto reask_output;
  638.     } else if (*buf == 'q') {
  639.         if (can_home) {
  640.         carriage_return();
  641.         erase_eol();
  642.         }
  643.         return DS_ASK;
  644.     }
  645.     set_sel_mode(*buf);
  646.     count_subjects(CS_NORM);
  647.     init_pages();
  648.     return DS_DISPLAY;
  649.     case 'O':
  650.     if (!sel_rereading)
  651.         sel_cleanup();
  652.     erase_eol();        /* erase the prompt */
  653.     reask_sort:
  654.     if (sel_mode == SM_ARTICLE)
  655.         in_char("Order by Date, Subject, Author, subject-date Groups? [dsagDSAG] ",
  656.             'q');
  657.     else
  658.         in_char("Order by Date, Subject, or Count? [dscDSC] ", 'q');
  659.     setdef(buf,"d");
  660. #ifdef VERIFY
  661.     printcmd();
  662. #endif
  663.     if (*buf == 'h') {
  664. #ifdef VERBOSE
  665.         IF(verbose) {
  666.         fputs("\n\
  667. Type d or SP to order the displayed items by date.\n\
  668. Type s to order the items by subject.\n\
  669. ",stdout) FLUSH;
  670.         if (sel_mode == SM_ARTICLE)
  671.             fputs("\
  672. Type a to order the items by author.\n\
  673. Type g to order the items in subject-groups by date.\n\
  674. ",stdout) FLUSH;
  675.         else
  676.             fputs("\
  677. Type c to order the items by article-count.\n\
  678. ",stdout) FLUSH;
  679.         fputs("\
  680. Typing your selection in upper case it will reverse the selected order.\n\
  681. Type q to leave things as they are.\n\n\
  682. ",stdout) FLUSH;
  683.         }
  684.         ELSE
  685. #endif
  686. #ifdef TERSE
  687.         {
  688.         fputs("\n\
  689. d or SP sorts by date.\n\
  690. s sorts by subject.\n\
  691. ",stdout) FLUSH;
  692.         if (sel_mode == SM_ARTICLE)
  693.             fputs("\
  694. a sorts by author.\n\
  695. g sorts in subject-groups by date.\n\
  696. ",stdout) FLUSH;
  697.         else
  698.             fputs("\
  699. c sorts by article-count.\n\
  700. ",stdout) FLUSH;
  701.         fputs("\
  702. Upper case reverses the sort.\n\
  703. q does nothing.\n\n\
  704. ",stdout) FLUSH;
  705.         }
  706. #endif
  707.         clean_screen = FALSE;
  708.         goto reask_sort;
  709.     } else if (*buf == 'q') {
  710.         if (can_home) {
  711.         carriage_return();
  712.         erase_eol();
  713.         }
  714.         return DS_ASK;
  715.     }
  716.     set_sel_sort(*buf);
  717.     count_subjects(CS_NORM);
  718.     sel_page_sp = Nullsubj;
  719.     sel_page_app = Null(ARTICLE**);
  720.     init_pages();
  721.     return DS_DISPLAY;
  722.     case 'R':
  723.     if (!sel_rereading)
  724.         sel_cleanup();
  725.     sel_direction *= -1;
  726.     count_subjects(CS_NORM);
  727.     sel_page_sp = Nullsubj;
  728.     sel_page_app = Null(ARTICLE**);
  729.     init_pages();
  730.     return DS_DISPLAY;
  731.     case 'E':
  732.     if (!sel_rereading)
  733.         sel_cleanup();
  734.     sel_exclusive = !sel_exclusive;
  735.     count_subjects(CS_NORM);
  736.     sel_page_sp = Nullsubj;
  737.     sel_page_app = Null(ARTICLE**);
  738.     init_pages();
  739.     empty_ok = TRUE;
  740.     return DS_DISPLAY;
  741.     case 'X':  case 'D':  case 'J':
  742.     if (!sel_rereading) {
  743.         if (sel_mode == SM_ARTICLE) {
  744.         register ARTICLE *ap, **app, **limit;
  745.         limit = artptr_list + artptr_list_size;
  746.         if (ch == 'D')
  747.             app = sel_page_app;
  748.         else
  749.             app = artptr_list;
  750.         for (;;) {
  751.             ap = *app;
  752.             if ((!(ap->flags & AF_SEL) ^ (ch == 'J'))
  753.              || (ap->flags & AF_DEL))
  754.             if (!sel_exclusive || (ap->flags & AF_INCLUDED))
  755.                 set_read(ap);
  756.             app++;
  757.             if (app >= limit || (ch == 'D' && app == sel_next_app))
  758.             break;
  759.         }
  760.         } else {
  761.         register SUBJECT *sp;
  762.         if (ch == 'D')
  763.             sp = sel_page_sp;
  764.         else
  765.             sp = first_subject;
  766.         for (;;) {
  767.             if (((!(sp->flags & SF_SEL) ^ (ch == 'J')) && sp->misc)
  768.              || (sp->flags & SF_DEL)) {
  769.             if (!sel_exclusive || (sp->flags & SF_INCLUDED))
  770.                 kill_subject(sp, ch=='J'? KF_ALL : KF_UNSELECTED);
  771.             }
  772.             sp = sp->next;
  773.             if (!sp || (ch == 'D' && sp == sel_next_sp))
  774.             break;
  775.         }
  776.         }
  777.         count_subjects(CS_UNSELECT);
  778.         if (article_count
  779.          && (ch == 'J' || (ch == 'D' && !selected_count))) {
  780.         init_pages();
  781.         sel_item_index = 0;
  782.         return DS_DISPLAY;
  783.         }
  784.         if (artptr_list && article_count)
  785.         sort_articles();
  786.         return DS_QUIT;
  787.     } else if (ch == 'J') {
  788.         register SUBJECT *sp;
  789.         for (sp = first_subject; sp; sp = sp->next)
  790.         deselect_subject(sp);
  791.         selected_subj_cnt = selected_count = 0;
  792.         return DS_DISPLAY;
  793.     }
  794.     return DS_QUIT;
  795.     case 'T':
  796.     if (!ThreadedGroup) {
  797.         sprintf(buf,"Group is not threaded.");
  798.         return DS_STATUS;
  799.     }
  800.     /* FALL THROUGH */
  801.     case 'A':
  802.     erase_eol();        /* erase the prompt */
  803.     if (sel_mode == SM_ARTICLE)
  804.         artp = (ARTICLE*)sel_items[sel_item_index].ptr;
  805.     else {
  806.         register SUBJECT *sp = (SUBJECT*)sel_items[sel_item_index].ptr;
  807.         if (sel_mode == SM_THREAD) {
  808.         while (!sp->misc)
  809.             sp = sp->next;
  810.         }
  811.         artp = sp->articles;
  812.     }
  813.     art = article_num(artp);
  814.     /* This call executes the action too */
  815.     switch (ask_memorize(ch)) {
  816.     case 'j':  case ',':
  817.         count_subjects(sel_rereading ? CS_NORM : CS_UNSELECT);
  818.         init_pages();
  819.         sprintf(buf,"Kill memorized.");
  820.         disp_status_line = TRUE;
  821.         return DS_DISPLAY;
  822.     case '.':
  823.         sprintf(buf,"Selection memorized.");
  824.         disp_status_line = TRUE;
  825.         return DS_DISPLAY;
  826.     case '+':
  827.         sprintf(buf,"Selection memorized.");
  828.         disp_status_line = TRUE;
  829.         return DS_UPDATE;
  830.     case 'c':  case 'C':
  831.         sprintf(buf,"Auto-commands cleared.");
  832.         disp_status_line = TRUE;
  833.         return DS_DISPLAY;
  834.     case 'q':
  835.         return DS_DISPLAY;
  836.     case 'Q':
  837.         break;
  838.     }
  839.     if (can_home) {
  840.         carriage_return();
  841.         erase_eol();
  842.     }
  843.     return DS_ASK;
  844.     case Ctl('k'):
  845.     edit_kfile();
  846.     return DS_DISPLAY;
  847.     case ':':  case '/':  case '&':  case '!':
  848.     erase_eol();        /* erase the prompt */
  849.     if (!finish_command(TRUE)) {    /* get rest of command */
  850.         if (clean_screen)
  851.         return DS_ASK;
  852.         goto extend_done;
  853.     }
  854.     if (ch == '&' || ch == '!') {
  855.         one_command = TRUE;
  856.         perform(buf, FALSE);
  857.         one_command = FALSE;
  858.         putchar('\n') FLUSH;
  859.         clean_screen = FALSE;
  860.     } else {
  861.         int sel_art_save = selected_count;
  862.  
  863.         if (ch == ':') {
  864.         clean_screen = (use_selected() == 2) && clean_screen;
  865.         if (!sel_rereading) {
  866.             register SUBJECT *sp;
  867.             for (sp = first_subject; sp; sp = sp->next) {
  868.             if (sp->flags & SF_DEL) {
  869.                 sp->flags = 0;
  870.                 if (sel_mode == SM_THREAD)
  871.                 kill_thread(sp->thread, KF_UNSELECTED);
  872.                 else
  873.                 kill_subject(sp, KF_UNSELECTED);
  874.             }
  875.             }
  876.         }
  877.         } else {
  878.         /* Force the search to begin at absfirst or firstart,
  879.         ** depending upon whether they specified the 'r' option.
  880.         */
  881.         art = lastart+1;
  882.         page_line = 1;
  883.         switch (art_search(buf, sizeof buf, FALSE)) {
  884.         case SRCH_ERROR:
  885.         case SRCH_ABORT:
  886.         case SRCH_INTR:
  887.             fputs("\nInterrupted\n", stdout) FLUSH;
  888.             break;
  889.         case SRCH_DONE:
  890.         case SRCH_SUBJDONE:
  891.             fputs("Done\n", stdout) FLUSH;
  892.             break;
  893.         case SRCH_NOTFOUND:
  894.             fputs("\nNot found.\n", stdout) FLUSH;
  895.             break;
  896.         case SRCH_FOUND:
  897.             break;
  898.         }
  899.         clean_screen = FALSE;
  900.         }
  901.         /* Recount, in case something has changed. */
  902.         count_subjects(sel_rereading ? CS_NORM : CS_UNSELECT);
  903.         init_pages();
  904.         sel_item_index = 0;
  905.  
  906.         sel_art_save -= selected_count;
  907.         if (sel_art_save) {
  908.         putchar('\n');
  909.         if (sel_art_save < 0) {
  910.             fputs("S", stdout);
  911.             sel_art_save *= -1;
  912.         } else
  913.             fputs("Des", stdout);
  914.         printf("elected %d article%s.",
  915.             sel_art_save, sel_art_save == 1 ? nullstr : "s");
  916.         clean_screen = FALSE;
  917.         }
  918.         if (!clean_screen)
  919.         putchar('\n') FLUSH;
  920.     }/* if !& else :/ */
  921.  
  922.     if (clean_screen) {
  923.         carriage_return();
  924.         up_line();
  925.         erase_eol();
  926.         return DS_ASK;
  927.     }
  928.       extend_done:
  929.     if ((ch = pause_getcmd())) {
  930.       got_cmd:
  931.         if (ch > 0) {
  932.         /* try to optimize the screen update for some commands. */
  933.         if (!index(sel_chars, ch)
  934.          && (index("<+>^$!?&:/hDEJLNOPqQRSUXYZ\n\r\t\033", ch)
  935.           || ch == Ctl('k'))) {
  936.             buf[0] = sel_ret = ch;
  937.             buf[1] = FINISHCMD;
  938.             goto do_command;
  939.         }
  940.         pushchar(ch | 0200);
  941.         }
  942.     }
  943.     return DS_DISPLAY;
  944.     case 'c':
  945.     erase_eol();        /* erase the prompt */
  946.     if ((ch = ask_catchup()) == 'y' || ch == 'u') {
  947.         count_subjects(CS_UNSELECT);
  948.         if (ch != 'u' && article_count) {
  949.         sel_page_sp = Nullsubj;
  950.         sel_page_app = Null(ARTICLE**);
  951.         init_pages();
  952.         return DS_DISPLAY;
  953.         }
  954.         sel_ret = 'Z';
  955.         return DS_QUIT;
  956.     }
  957.     if (ch != 'N')
  958.         return DS_DISPLAY;
  959.     if (can_home) {
  960.         carriage_return();
  961.         erase_eol();
  962.     }
  963.     return DS_ASK;
  964.     case 'h':  case '?':
  965.     putchar('\n');
  966.     if ((ch = help_select()) || (ch = pause_getcmd()))
  967.         goto got_cmd;
  968.         return DS_DISPLAY;
  969.     default:
  970.     sprintf(buf,"Type ? for help.");
  971.     settle_down();
  972.     if (clean_screen)
  973.         return DS_STATUS;
  974.     printf("\n%s\n",buf);
  975.     goto extend_done;
  976.     }
  977. }
  978.  
  979. static void
  980. empty_complaint()
  981. {
  982.     clear_on_stop = FALSE;
  983.     putchar('\n');
  984.     if (sel_rereading) {
  985. #ifdef VERBOSE
  986.     IF (verbose)
  987.         fputs("\nNo articles to set unread.\n", stdout);
  988.     ELSE
  989. #endif
  990. #ifdef TERSE
  991.         fputs("\nNo articles.\n", stdout) FLUSH;
  992. #endif
  993.     sel_rereading = 0;
  994.     sel_mask = AF_SEL;
  995.     } else {
  996. #ifdef VERBOSE
  997.     IF (verbose)
  998.         fputs("\nNo unread articles to select.", stdout);
  999.     ELSE
  1000. #endif
  1001. #ifdef TERSE
  1002.         fputs("\nNo unread articles.", stdout);
  1003. #endif
  1004.     putchar('\n');    /* let "them" FLUSH */
  1005.     }
  1006.     selected_only = FALSE;
  1007.     art = curr_art;
  1008.     artp = curr_artp;
  1009. }
  1010.