home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume30 / tin / part03 / thread.c < prev   
Encoding:
C/C++ Source or Header  |  1992-05-20  |  17.4 KB  |  856 lines

  1. /*
  2.  *  Project   : tin - a threaded Netnews reader
  3.  *  Module    : thread.c
  4.  *  Author    : I.Lea
  5.  *  Created   : 01-04-91
  6.  *  Updated   : 11-05-92
  7.  *  Notes     :
  8.  *  Copyright : (c) Copyright 1991-92 by Iain Lea
  9.  *              You may  freely  copy or  redistribute  this software,
  10.  *              so  long as there is no profit made from its use, sale
  11.  *              trade or  reproduction.  You may not change this copy-
  12.  *              right notice, and it must be included in any copy made
  13.  */
  14.  
  15. #include    "tin.h"
  16.  
  17. extern int index_point;
  18. int threaded_on_subject;
  19. static int top_thread = 0;
  20. static int thread_index_point = 0;
  21. static int thread_basenote = 0;
  22. static int thread_respnum = 0;
  23. static int first_thread_on_screen = 0;
  24. static int last_thread_on_screen = 0;
  25.  
  26.  
  27. /*
  28.  * show current thread. If threaded on Subject: show
  29.  *   <respnum> <name>    <respnum> <name>
  30.  * If threaded on Archive-name: show
  31.  *   <respnum> <subject> <name>
  32.  */
  33.  
  34. int show_thread (respnum, group, group_path)
  35.     int respnum;
  36.     char *group;
  37.     char *group_path;
  38. {
  39.     int ret_code = TRUE;
  40. #ifndef INDEX_DAEMON
  41.     int ch;
  42.     int i, index, n;
  43.     int scroll_lines;
  44.  
  45.     thread_respnum = respnum;
  46.     thread_basenote = which_thread (thread_respnum);
  47.     top_thread = num_of_responses (thread_basenote) + 1;
  48.  
  49.     if (top_thread <= 0) {
  50.         info_message (txt_no_resps_in_thread);
  51.         return FALSE;
  52.     }
  53.  
  54.     if (arts[thread_respnum].archive != (char *) 0) {
  55.         threaded_on_subject = FALSE;
  56.     } else {
  57.         threaded_on_subject = TRUE;
  58.     }
  59.  
  60.     thread_index_point = top_thread;
  61.     if (space_mode) {
  62.         if (i = new_responses (thread_basenote)) {
  63.             for (n=0, i = base[thread_basenote]; i >= 0 ;
  64.                  i = arts[i].thread, n++) {
  65.                 if (arts[i].unread == ART_UNREAD) {
  66.                     thread_index_point = n;
  67.                     break;
  68.                 }
  69.             }
  70.         }
  71.     }
  72.  
  73.     if (thread_index_point < 0) {
  74.         thread_index_point = 0;
  75.     }
  76.  
  77.     show_thread_page ();
  78.  
  79.     while (TRUE) {
  80.         ch = (char) ReadCh();
  81.  
  82.         if (ch >= '0' && ch <= '9') {    /* 0 goes to basenote */
  83.             prompt_thread_num (ch);
  84.         } else switch (ch) {
  85.             case ESC:    /* common arrow keys */
  86.                 switch (get_arrow_key ()) {
  87.                     case KEYMAP_UP:
  88.                         goto thread_up;
  89.  
  90.                     case KEYMAP_DOWN:
  91.                         goto thread_down;
  92.  
  93.                     case KEYMAP_PAGE_UP:
  94.                         goto thread_page_up;
  95.  
  96.                     case KEYMAP_PAGE_DOWN:
  97.                         goto thread_page_down;
  98.  
  99.                     case KEYMAP_HOME:
  100.                         if (thread_index_point != 0) {
  101.                             if (0 < first_thread_on_screen) {
  102. #ifndef USE_CLEARSCREEN
  103.                                 erase_thread_arrow ();
  104. #endif
  105.                                 thread_index_point = 0;
  106.                                 show_thread_page ();
  107.                             } else {
  108.                                 erase_thread_arrow ();
  109.                                 thread_index_point = 0;
  110.                                 draw_thread_arrow ();
  111.                             }
  112.                         }
  113.                         break;
  114.                     
  115.                     case KEYMAP_END:
  116.                         goto end_of_thread;
  117.                 }
  118.                 break;
  119.  
  120.             case '$':    /* show last page of threads */
  121. end_of_thread:            
  122.                 if (thread_index_point < top_thread - 1) {
  123.                     if (top_thread > last_thread_on_screen) {
  124. #ifndef USE_CLEARSCREEN
  125.                         erase_thread_arrow ();
  126. #endif                    
  127.                         thread_index_point = top_thread - 1;
  128.                         show_thread_page ();
  129.                     } else {
  130.                         erase_thread_arrow ();
  131.                         thread_index_point = top_thread - 1;
  132.                         draw_thread_arrow ();
  133.                     }
  134.                 }
  135.                 break;
  136.                 
  137.             case '\r':
  138.             case '\n':    /* read current article within thread */
  139.                 n = choose_response (thread_basenote, thread_index_point);
  140.                 n = show_page (n, &thread_index_point, group, group_path);
  141.                 if (n == thread_basenote) {
  142.                     show_thread_page ();
  143.                 } else {
  144.                     index_point = n;    
  145.                     goto thread_done;
  146.                 }
  147.                 break;
  148.  
  149.             case '\t':
  150.                  space_mode = TRUE;
  151.                 if (thread_index_point == 0) {
  152.                     n = thread_respnum;
  153.                 } else {
  154.                     n = choose_response (thread_basenote, thread_index_point);
  155.                 }
  156.                 index = thread_index_point;
  157.                 for (i = n ; i != -1 ; i = arts[i].thread) {
  158.                     if (arts[i].unread == ART_UNREAD) {
  159.                         n = show_page (i, &thread_index_point, group, group_path);
  160.                         break;
  161.                     }
  162.                     index++;
  163.                 }
  164.                 if (n == thread_basenote) {
  165.                     show_thread_page ();
  166.                 } else {
  167.                     index_point = n;    
  168.                     goto thread_done;
  169.                 }
  170.                 break;
  171.     
  172.             case ' ':        /* page down */
  173.             case ctrl('D'):        /* vi style */
  174.             case ctrl('V'):        /* emacs style */
  175. thread_page_down:
  176.                 if (thread_index_point + 1 == top_thread) {
  177. #ifdef NO_LOOP_AROUND
  178.                     break;
  179. #else
  180.                     if (0 < first_thread_on_screen) {
  181. #    ifndef USE_CLEARSCREEN
  182.                         erase_thread_arrow ();
  183. #    endif                    
  184.                         thread_index_point = 0;
  185.                         show_thread_page ();
  186.                     } else {
  187.                         erase_thread_arrow ();
  188.                         thread_index_point = 0;
  189.                         draw_thread_arrow ();
  190.                     }
  191.                     break;
  192. #endif                    
  193.                 }
  194.                 erase_thread_arrow ();
  195.                 scroll_lines = (full_page_scroll ? NOTESLINES : NOTESLINES / 2);
  196.                 thread_index_point = ((thread_index_point + scroll_lines) /
  197.                             scroll_lines) * scroll_lines;
  198.                 if (thread_index_point >= top_thread) {
  199.                     thread_index_point = (top_thread / scroll_lines) * scroll_lines;
  200.                     if (thread_index_point < top_thread - 1) {
  201.                         thread_index_point = top_thread - 1;
  202.                     }
  203.                 }
  204.                 if (thread_index_point < first_thread_on_screen ||
  205.                     thread_index_point >= last_thread_on_screen) {
  206.                     show_thread_page ();
  207.                 } else {
  208.                     draw_thread_arrow ();
  209.                 }
  210.                 break;
  211.  
  212.             case ctrl('L'):        /* redraw screen */
  213.             case ctrl('R'):
  214.             case ctrl('W'):
  215. #ifndef USE_CLEARSCREEN
  216.                 ClearScreen ();
  217. #endif
  218.                 show_thread_page ();
  219.                 break;
  220.  
  221.             case ctrl('N'):
  222.             case 'j':        /* line down */
  223. thread_down:
  224.                 if (thread_index_point + 1 >= top_thread) {
  225. #ifdef NO_LOOP_AROUND
  226.                     break;
  227. #else
  228.                     if (0 < first_thread_on_screen) {
  229.                         thread_index_point = 0;
  230.                         show_thread_page ();
  231.                     } else {
  232.                         erase_thread_arrow ();
  233.                         thread_index_point = 0;
  234.                         draw_thread_arrow ();
  235.                     }
  236.                     break;
  237. #endif                    
  238.                 }
  239.                 if (thread_index_point + 1 >= last_thread_on_screen) {
  240. #ifndef USE_CLEARSCREEN
  241.                     erase_thread_arrow ();
  242. #endif                    
  243.                     thread_index_point++;
  244.                     show_thread_page ();
  245.                 } else {
  246.                     erase_thread_arrow ();
  247.                     thread_index_point++;
  248.                     draw_thread_arrow ();
  249.                 }
  250.                 break;
  251.  
  252.             case ctrl('P'):
  253.             case 'k':        /* line up */
  254. thread_up:
  255.                 if (thread_index_point == 0) {
  256. #ifdef NO_LOOP_AROUND
  257.                     break;
  258. #else
  259.                     if (top_thread > last_thread_on_screen) {
  260.                         thread_index_point = top_thread - 1;
  261.                         show_thread_page ();
  262.                     } else {
  263.                         erase_thread_arrow ();
  264.                         thread_index_point = top_thread - 1;
  265.                         draw_thread_arrow ();
  266.                     }
  267.                     break;
  268. #endif
  269.                 }
  270.                 if (thread_index_point <= first_thread_on_screen) {
  271.                     thread_index_point--;
  272.                     show_thread_page ();
  273.                 } else {
  274.                     erase_thread_arrow ();
  275.                     thread_index_point--;
  276.                     draw_thread_arrow ();
  277.                 }
  278.                 break;
  279.  
  280.             case ctrl('U'):        /* page up */
  281.             case 'b':
  282. thread_page_up:
  283.                 if (thread_index_point == 0) {
  284. #ifdef NO_LOOP_AROUND
  285.                     break;
  286. #else
  287.                     if (top_thread > last_thread_on_screen) {
  288.                         thread_index_point = top_thread - 1;
  289.                         show_thread_page ();
  290.                     } else {
  291.                         erase_thread_arrow ();
  292.                         thread_index_point = top_thread - 1;
  293.                         draw_thread_arrow ();
  294.                     }
  295.                     break;
  296. #endif                    
  297.                 }
  298. #ifndef USE_CLEARSCREEN
  299.                 clear_message ();
  300. #endif
  301.                 erase_thread_arrow ();
  302.                 scroll_lines = (full_page_scroll ? NOTESLINES : NOTESLINES / 2);
  303.                 if ((n = thread_index_point % scroll_lines) > 0) {
  304.                     thread_index_point = thread_index_point - n;
  305.                 } else {
  306.                     thread_index_point = ((thread_index_point - scroll_lines) / scroll_lines) * scroll_lines;
  307.                 }
  308.                 if (thread_index_point < 0) {
  309.                     thread_index_point = 0;
  310.                 }
  311.                 if (thread_index_point < first_thread_on_screen
  312.                 || thread_index_point >= last_thread_on_screen)
  313.                     show_thread_page ();
  314.                 else
  315.                     draw_thread_arrow ();
  316.                 break;
  317.  
  318.             case 'B':    /* bug/gripe/comment mailed to author */
  319.                 mail_bug_report ();
  320. #ifndef USE_CLEARSCREEN
  321.                 ClearScreen ();
  322. #endif
  323.                 show_thread_page ();
  324.                 break;
  325.  
  326.             case 'c':    /* catchup thread but ask for confirmation */
  327.             case 'K':    /* mark thread as read immediately */
  328.                 if (ch == 'c') {
  329.                     if (confirm_action && !prompt_yn (LINES, txt_mark_thread_read, 'y')) {
  330.                         break;
  331.                     }
  332.                 }
  333.                 for (i = (int) base[thread_basenote] ; i != -1 ; i = arts[i].thread) {
  334.                     arts[i].unread = ART_READ;
  335.                 }
  336.                 goto thread_done;
  337.                 break;
  338.  
  339.             case 'd':    /* toggle display of subject & subj/author */
  340.                 if (! threaded_on_subject) {
  341.                     toggle_subject_from ();
  342.                     show_thread_page ();
  343.                 }    
  344.                 break;
  345.                 
  346.             case 'h':    /* help */
  347.                 show_info_page (HELP_INFO, help_thread, txt_thread_com);
  348.                 show_thread_page ();
  349.                 break;
  350.  
  351.             case 'I':    /* toggle inverse video */
  352.                 toggle_inverse_video ();
  353.                 show_thread_page ();
  354.                 break;
  355.  
  356.             case 'q':    /* return to previous level */
  357.                 goto thread_done;
  358.  
  359.             case 'Q':    /* quit */
  360.                 ret_code = -2;
  361.                 goto thread_done;
  362.  
  363.              case 'T':    /* tag/untag art for mailing/piping/printing/saving */
  364.                  if (thread_index_point == 0) {
  365.                      n = thread_respnum;
  366.                  } else {
  367.                      n = choose_response (thread_basenote, thread_index_point);
  368.                  }
  369.                  if (n < 0)
  370.                      break;
  371.  
  372.                  if (arts[n].tagged) {
  373.                      arts[n].tagged = 0;
  374.                      info_message (txt_untagged_art);
  375.                  } else {
  376.                      arts[n].tagged = ++num_of_tagged_arts;
  377.                     info_message (txt_tagged_art);
  378.                  }
  379.                  show_thread_page ();
  380.                  goto thread_down;
  381.                 break;
  382.  
  383.             case 'v':    /* version */
  384.                 info_message (cvers);
  385.                 break;
  386.  
  387.             case 'z':    /* mark article as unread */
  388.                 if (thread_index_point == 0) {
  389.                     n = thread_respnum;
  390.                 } else {
  391.                     n = choose_response (thread_basenote, thread_index_point);
  392.                 }
  393.                 if (n >= 0) {
  394.                     arts[n].unread = ART_UNREAD;
  395.                     show_thread_page ();
  396.                     info_message (txt_art_marked_as_unread);
  397.                 }
  398.                 break;
  399.  
  400.             case 'Z':    /* mark thread as unread */
  401.                 for (i = (int) base[thread_basenote] ; i != -1 ; i = arts[i].thread) {
  402.                     arts[i].unread = ART_UNREAD;
  403.                 }
  404.                 show_thread_page ();
  405.                 info_message (txt_thread_marked_as_unread);
  406.                 break;
  407.                 
  408.             default:
  409.                 info_message (txt_bad_command);
  410.         }
  411.     }
  412.  
  413. thread_done:
  414.     clear_note_area ();
  415.  
  416. #endif /* INDEX_DAEMON */
  417.  
  418.     return (ret_code);
  419. }
  420.  
  421.  
  422. void show_thread_page ()
  423. {
  424. #ifndef INDEX_DAEMON
  425.  
  426.     extern int index_point;
  427.     char new_resps[8];
  428.     char from[LEN];
  429.     int i, j;
  430.     int len_from;
  431.     int len_subj = 0;
  432.     int off_subj = 0;
  433.     int off_both = 0;
  434.     static int index = 0;
  435.  
  436.     set_signals_thread ();
  437.     
  438.     ClearScreen ();
  439.  
  440.     if (threaded_on_subject) {
  441.         sprintf (msg, "Thread (%.*s)", COLS-23, arts[thread_respnum].subject);
  442.     } else {
  443.         sprintf (msg, "List Thread (%d of %d)", index_point+1, top_base);
  444.     }
  445.     show_title (msg);
  446.  
  447.     MoveCursor (INDEX_TOP, 0);
  448.     if (thread_index_point > top_thread - 1) {
  449.         thread_index_point = top_thread - 1;
  450.     }
  451.  
  452.     if (NOTESLINES <= 0) {
  453.         first_thread_on_screen = 0;
  454.     } else {
  455.         first_thread_on_screen = (thread_index_point / NOTESLINES) * NOTESLINES;
  456.         if (first_thread_on_screen < 0) {
  457.             first_thread_on_screen = 0;
  458.         }
  459.     }
  460.  
  461.     last_thread_on_screen = first_thread_on_screen + NOTESLINES;
  462.  
  463.     if (last_thread_on_screen >= top_thread) {
  464.         last_thread_on_screen = top_thread;
  465.         first_thread_on_screen = (top_thread / NOTESLINES) * NOTESLINES;
  466.  
  467.         if (first_thread_on_screen == last_thread_on_screen ||
  468.             first_thread_on_screen < 0) {
  469.             if (first_thread_on_screen < 0) {
  470.                 first_thread_on_screen = 0;
  471.             } else {
  472.                 first_thread_on_screen = last_thread_on_screen - NOTESLINES;
  473.             }
  474.         }
  475.     }
  476.  
  477.     if (top_thread == 0) {
  478.         first_thread_on_screen = 0;
  479.         last_thread_on_screen = 0;
  480.     }
  481.  
  482.     index = choose_response (thread_basenote, first_thread_on_screen);
  483.     assert(first_thread_on_screen != 0 || index == thread_respnum);
  484.  
  485.     if (! draw_arrow_mark) {
  486.         off_subj = 2;
  487.         off_both = 5;
  488.     }    
  489.  
  490.     if (threaded_on_subject) {
  491.         len_from = max_subj+max_from+off_both;
  492.     } else {
  493.         if (show_author != SHOW_FROM_NONE) {
  494.             len_from = max_from;
  495.             len_subj = max_subj+off_subj;
  496.         } else {
  497.             len_from = 0;
  498.             len_subj = max_from+max_subj+off_subj;
  499.         }
  500.     }    
  501.  
  502.     for (j=0, i = first_thread_on_screen; j < NOTESLINES && i < last_thread_on_screen; i++, j++) {
  503.         if (arts[index].tagged) {
  504.             sprintf (new_resps, "%3d", arts[index].tagged);
  505.         } else if (arts[index].unread == ART_UNREAD) {
  506.             if (arts[index].hot == 0)
  507.                 sprintf (new_resps, "  %c", UNREAD_ART_MARK);
  508.             else
  509.                 sprintf (new_resps, "  %c", HOT_ART_MARK);
  510.         } else if (arts[index].unread == ART_WILL_RETURN) {
  511.             sprintf (new_resps, "  %c", RETURN_ART_MARK);
  512.         } else {
  513.             strcpy (new_resps, "   ");
  514.         }
  515.  
  516.         if (threaded_on_subject) {
  517.             get_author (TRUE, index, from);
  518.             sprintf (screen[j].col, "  %4d%3s  %-*.*s\r\n",
  519.                 i, new_resps, len_from, len_from, from);
  520.         } else {
  521.             if (show_author != SHOW_FROM_NONE) {
  522.                 get_author (TRUE, index, from);
  523.             }
  524.             sprintf (screen[j].col, "  %4d%3s  %-*.*s   %-*.*s\r\n",
  525.                 i, new_resps, len_subj, len_subj,
  526.                 arts[index].subject, len_from, len_from, from);
  527.         }
  528.         
  529.         fputs (screen[j].col, stdout);
  530.         
  531.         if ((index = next_response (index)) == -1) {
  532.             break;
  533.         }    
  534.     }
  535.  
  536. #ifndef USE_CLEARSCREEN
  537.     CleartoEOS ();
  538. #endif
  539.  
  540.     if (last_thread_on_screen == top_thread) {
  541.         info_message (txt_end_of_thread);
  542.     }
  543.  
  544.     draw_thread_arrow ();
  545.  
  546. #endif /* INDEX_DAEMON */
  547. }
  548.  
  549.  
  550. void draw_thread_arrow ()
  551. {
  552.     draw_arrow (INDEX_TOP + (thread_index_point-first_thread_on_screen));
  553. }
  554.  
  555.  
  556. void erase_thread_arrow ()
  557. {
  558.     erase_arrow (INDEX_TOP + (thread_index_point-first_thread_on_screen));
  559. }
  560.  
  561.  
  562. int prompt_thread_num (ch)
  563.     char ch;
  564. {
  565.     int num;
  566.  
  567.     clear_message ();
  568.  
  569.     if ((num = prompt_num (ch, txt_read_art)) == -1) {
  570.         clear_message ();
  571.         return FALSE;
  572.     }
  573.  
  574.     if (num >= top_thread)
  575.         num = top_thread - 1;
  576.  
  577.     if (num >= first_thread_on_screen
  578.     &&  num < last_thread_on_screen) {
  579.         erase_thread_arrow ();
  580.         thread_index_point = num;
  581.         draw_thread_arrow ();
  582.     } else {
  583. #ifndef USE_CLEARSCREEN
  584.         erase_thread_arrow ();
  585. #endif        
  586.         thread_index_point = num;
  587.         show_thread_page ();
  588.     }
  589.     return TRUE;
  590. }
  591.  
  592. /*
  593.  *  Return the number of unread articles there are within a thread
  594.  */
  595.  
  596. int new_responses (thread)
  597.     int thread;
  598. {
  599.     int i;
  600.     int sum = 0;
  601.  
  602.     for (i = (int) base[thread]; i >= 0; i = arts[i].thread) {
  603.         if (arts[i].unread) {
  604.             sum++;
  605.         }
  606.     }
  607.     
  608.     return sum;
  609. }
  610.  
  611. /*
  612.  *  Which base note (an index into base[]) does a respnum
  613.  *  (an index into arts[]) corresponsd to?
  614.  *
  615.  *  In other words, base[] points to an entry in arts[] which is
  616.  *  the head of a thread, linked with arts[].thread.  For any q: arts[q],
  617.  *  find i such that base[i]->arts[n]->arts[o]->...->arts[q]
  618.  *
  619.  *  Note that which_thread() can return -1 if in show_read_only mode and
  620.  *  the article of interest has been read as well as all other articles in
  621.  *  the thread,  thus resulting in no base[] entry for it.
  622.  */
  623.  
  624. int which_thread (n)
  625.     int n;
  626. {
  627.     register int i, j;
  628.  
  629.     for (i = 0; i < top_base; i++) {
  630.         for (j = (int) base[i] ; j >= 0 ; j = arts[j].thread) {
  631.             if (j == n) {
  632.                 return i;
  633.             }
  634.         }
  635.     }
  636.  
  637.     sprintf (msg, "%d", n);
  638.     error_message (txt_cannot_find_base_art, msg);
  639.     return -1;
  640. }
  641.  
  642. /*
  643.  *  Find how deep in a thread a response is.  Start counting at zero
  644.  */
  645.  
  646. int which_response (n)
  647.     int n;
  648. {
  649.     int i, j;
  650.     int num = 0;
  651.  
  652.     i = which_thread (n);
  653.     assert(i >= 0);
  654.  
  655.     for (j = (int) base[i]; j != -1; j = arts[j].thread)
  656.         if (j == n)
  657.             break;
  658.         else
  659.             num++;
  660.  
  661.     return num;
  662. }
  663.  
  664. /*
  665.  *  Given an index into base[], find the number of responses for
  666.  *  that basenote
  667.  */
  668.  
  669. int num_of_responses (n)
  670.     int n;
  671. {
  672.     int i;
  673.     int oldi = -3;
  674.     int sum = 0;
  675.  
  676.     assert (n < top_base);
  677.  
  678.     for (i = (int) base[n]; i != -1; i = arts[i].thread) {
  679.         assert (i != -2);
  680.         assert (i != oldi);
  681.         oldi = i;
  682.         sum++;
  683.     }
  684.  
  685.     return sum - 1;
  686. }
  687.  
  688. /*
  689.  * Given an index into base[], return relevant statistics
  690.  */
  691.  
  692. int stat_thread (n, sbuf)
  693.     int n;
  694.     struct art_stat_t *sbuf;
  695. {
  696.     int i;
  697.  
  698.     sbuf->total  = 0;
  699.     sbuf->unread = 0;
  700.     sbuf->seen   = 0;
  701.     sbuf->hot_total = 0;
  702.     sbuf->hot_unread= 0;
  703.     sbuf->hot_seen  = 0;
  704.  
  705.     for (i = (int) base[n]; i != -1; i = arts[i].thread) {
  706.         ++sbuf->total;
  707.         if (arts[i].unread == ART_UNREAD)
  708.             ++sbuf->unread;
  709.         else if (arts[i].unread == ART_WILL_RETURN)
  710.             ++sbuf->seen;
  711.  
  712.         if (arts[i].hot) {
  713.             ++sbuf->hot_total;
  714.             if (arts[i].unread == ART_UNREAD)
  715.                 ++sbuf->hot_unread;
  716.             else if (arts[i].unread == ART_WILL_RETURN)
  717.                 ++sbuf->hot_seen;
  718.         }
  719.  
  720. #if 0
  721.         if (arts[i].killed) {
  722.             ++sbuf->killed;
  723.         }
  724. #endif
  725.     }
  726.  
  727.  
  728.     if (sbuf->hot_unread)
  729.         sbuf->art_mark = HOT_ART_MARK;
  730.     else if (sbuf->unread)
  731.         sbuf->art_mark = UNREAD_ART_MARK;
  732.     else if (sbuf->seen)
  733.         sbuf->art_mark = RETURN_ART_MARK;
  734.     else
  735.         sbuf->art_mark = READ_ART_MARK;
  736.  
  737.     return(sbuf->total);
  738. }
  739.  
  740.  
  741. /*
  742.  *  Find the next response.  Go to the next basenote if there
  743.  *  are no more responses in this thread
  744.  */
  745.  
  746. int next_response (n)
  747.     int n;
  748. {
  749.     int i;
  750.  
  751.     if (arts[n].thread >= 0)
  752.         return arts[n].thread;
  753.  
  754.     i = which_thread (n) + 1;
  755.  
  756.     if (i >= top_base)
  757.         return -1;
  758.  
  759.     return (int) base[i];
  760. }
  761.  
  762. /*
  763.  *  Given a respnum (index into arts[]), find the respnum of the
  764.  *  next basenote
  765.  */
  766.  
  767. int next_thread (n)
  768.     int n;
  769. {
  770.     int i;
  771.  
  772.     i = which_thread (n) + 1;
  773.     if (i >= top_base)
  774.         return -1;
  775.  
  776.     return (int) base[i];
  777. }
  778.  
  779. /*
  780.  *  Find the previous response.  Go to the last response in the previous
  781.  *  thread if we go past the beginning of this thread.
  782.  */
  783.  
  784. int prev_response (n)
  785.     int n;
  786. {
  787.     int resp;
  788.     int i;
  789.  
  790.     resp = which_response (n);
  791.  
  792.     if (resp > 0)
  793.         return choose_response (which_thread (n), resp-1);
  794.  
  795.     i = which_thread (n) - 1;
  796.  
  797.     if (i < 0)
  798.         return -1;
  799.  
  800.     return choose_response (i, num_of_responses (i));
  801. }
  802.  
  803. /*
  804.  *  return response number n from thread i
  805.  */
  806.  
  807. int choose_response (i, n)
  808.     int i;
  809.     int n;
  810. {
  811.     int j;
  812.  
  813.     j = (int) base[i];
  814.  
  815.     while (n-- && arts[j].thread >= 0) {
  816.         j = arts[j].thread;
  817.     }
  818.  
  819.     return j;
  820. }
  821.  
  822. /*
  823.  *  Find the next unread response in this group 
  824.  */
  825.  
  826. int next_unread (n)
  827.     int n;
  828. {
  829.     while (n >= 0) {
  830.         if (arts[n].unread == ART_UNREAD) {
  831.             return n;
  832.         }
  833.         n = next_response (n);
  834.     }
  835.  
  836.     return -1;
  837. }
  838.  
  839.  
  840. /*
  841.  *  Find the previous unread response in this thread
  842.  */
  843.  
  844. int prev_unread (n)
  845.     int n;
  846. {
  847.     while (n >= 0) {
  848.         if (arts[n].unread == ART_UNREAD) {
  849.             return n;
  850.         }
  851.         n = prev_response (n);
  852.     }
  853.  
  854.     return -1;
  855. }
  856.