home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume30 / tin / part12 / kill.c < prev    next >
C/C++ Source or Header  |  1992-05-20  |  12KB  |  530 lines

  1. /*
  2.  *  Project   : tin - a threaded Netnews reader
  3.  *  Module    : kill.c
  4.  *  Author    : I.Lea & J.Robinson
  5.  *  Created   : 01-04-91
  6.  *  Updated   : 10-05-92
  7.  *  Notes     : kill & auto select (hot) articles
  8.  *  Copyright : (c) Copyright 1991-92 by Iain Lea & Jim Robinson
  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. #ifdef NO_REGEX 
  18. char *stars = "";
  19. #else        
  20. char *stars = "*";
  21. #endif
  22.  
  23. #define SET_KILLED(i)        (arts[i].unread = ART_READ, arts[i].killed = 1, num_of_killed_arts++)
  24. #define SET_HOT(i)        (arts[i].hot = 1, num_of_hot_arts++)
  25. #define IS_READ(i)        (arts[i].unread == ART_READ)
  26. #define IS_KILLED(i)        (arts[i].killed == 1)
  27.  
  28. #define KILL_CHAR    'K'
  29. #define HOT_CHAR    'H'
  30.  
  31. #define K_KILL        0
  32. #define K_HOT        1
  33.  
  34. int kill_level = 1;
  35. int kill_num = 0;
  36. int max_kill;
  37. struct kill_t *killf;
  38.  
  39. /*
  40.  *  read_kill_file - read ~/.tin/kill file contents into kill array
  41.  */
  42.  
  43. int read_kill_file ()
  44. {
  45.     char buf[LEN];
  46.     FILE *fp;
  47.     int n;
  48.     char c;
  49.     unsigned int type;
  50.  
  51.     free_kill_array ();
  52.     
  53.     set_real_uid_gid ();
  54.  
  55.     if ((fp = fopen (killfile, "r")) == NULL) {
  56.         set_tin_uid_gid ();
  57.         return FALSE;
  58.     }
  59.  
  60.     kill_num=0;
  61.     while (fgets (buf, sizeof buf, fp) != NULL) {
  62.         if (buf[0] == '#') {
  63.             continue;
  64.         }    
  65.         if (kill_num == max_kill-1) {
  66.             expand_kill ();
  67.         }
  68.         n = sscanf(buf, "%d %c", &type, &c);
  69.         if (n == 0) {
  70.             goto corrupt_killfile;
  71.         }    
  72.         if (n > 1 && c == HOT_CHAR) {    /* hot */
  73.              killf[kill_num].kill_how = K_HOT;
  74.         } else {
  75.              killf[kill_num].kill_how = K_KILL;
  76.         }     
  77.         killf[kill_num].kill_type = type;
  78.  
  79.         if (fgets (buf, sizeof buf, fp) == NULL)  {
  80.             goto corrupt_killfile;
  81.         }
  82.         
  83.         killf[kill_num].kill_group = (long) atol (buf);
  84.  
  85.         switch (killf[kill_num].kill_type) {
  86.         case KILL_SUBJ:
  87.             if (fgets (buf, sizeof buf, fp) != NULL) {
  88.                 buf[strlen (buf)-1] = '\0';
  89.                 killf[kill_num].kill_subj = str_dup (buf);
  90.             }
  91.             break;
  92.         case KILL_FROM:
  93.             if (fgets (buf, sizeof buf, fp) != NULL) {
  94.                 buf[strlen (buf)-1] = '\0';
  95.                 killf[kill_num].kill_from = str_dup (buf);
  96.             }
  97.             break;
  98.         case KILL_BOTH:
  99.             if (fgets (buf, sizeof buf, fp) != NULL) {
  100.                 buf[strlen (buf)-1] = '\0';
  101.                 killf[kill_num].kill_subj = str_dup (buf);
  102.             }
  103.             if (fgets (buf, sizeof buf, fp) != NULL) {
  104.                 buf[strlen (buf)-1] = '\0';
  105.                 killf[kill_num].kill_from = str_dup (buf);
  106.             }
  107.             break;
  108.         default:
  109.             goto corrupt_killfile;
  110.         }
  111.         kill_num++;
  112.     }
  113.  
  114.     fclose (fp);
  115.     set_tin_uid_gid ();
  116.     return (kill_num);
  117.  
  118. corrupt_killfile:
  119.     fclose (fp);
  120.     killf[kill_num].kill_type = 0;
  121.     error_message (txt_corrupt_kill_file, killfile);
  122.     set_tin_uid_gid ();
  123.     return FALSE;
  124. }
  125.  
  126. /*
  127.  *  write_kill_file - write kill strings to ~/.tin/kill
  128.  */
  129.  
  130. void write_kill_file ()
  131. {
  132.     FILE *fp;
  133.     int i;
  134.     
  135.     set_real_uid_gid ();
  136.  
  137.     if (kill_num == 0 || (fp = fopen (killfile, "w")) == NULL) {
  138.         set_tin_uid_gid ();
  139.         return;
  140.     }
  141.  
  142.     wait_message (txt_saving);
  143.     fprintf (fp, "# 1st line  1=(Subject: only)  2=(From: only)  3=(Subject: & From:)\n");
  144.     fprintf (fp, "#           %c=(kill) %c=(auto-selection)\n", KILL_CHAR, HOT_CHAR);
  145.     fprintf (fp, "# 2nd line  0=(kill on all newsgroups)  >0=(kill on specific newsgroup)\n");
  146.     for (i=0 ; i < kill_num ; i++) {
  147.         if (killf[i].kill_type == 0 || (killf[i].kill_subj == 0 
  148.             &&  killf[i].kill_from == 0)) 
  149.             continue;
  150.  
  151.         if (killf[i].kill_how == K_KILL) {
  152.             fprintf (fp, "#\n# %03d KILL\n", i+1);
  153.             fprintf (fp, "%d\t%c\n", killf[i].kill_type, KILL_CHAR);
  154.         } else {
  155.             fprintf (fp, "#\n# %03d HOT\n", i+1);
  156.             fprintf (fp, "%d\t%c\n", killf[i].kill_type, HOT_CHAR);
  157.         }    
  158.         fprintf (fp, "%ld\n", killf[i].kill_group);
  159.  
  160.         switch (killf[i].kill_type) {
  161.             case KILL_SUBJ:
  162.                 fprintf (fp, "%s\n", killf[i].kill_subj);
  163.                 break;
  164.             case KILL_FROM:
  165.                 fprintf (fp, "%s\n", killf[i].kill_from);
  166.                 break;
  167.             case KILL_BOTH:
  168.                 fprintf (fp, "%s\n", killf[i].kill_subj);
  169.                 fprintf (fp, "%s\n", killf[i].kill_from);
  170.                 break;
  171.         }
  172.     }
  173.  
  174.     fclose (fp);
  175.     chmod (killfile, 0600);
  176.  
  177.     set_tin_uid_gid ();
  178. }
  179.  
  180. static int get_choice (x, help, prompt, opt1, opt2, opt3, opt4)
  181.     int x;
  182.     char *help, *prompt, *opt1, *opt2, *opt3, *opt4;
  183. {
  184.     int ch, n = 0, i = 0;
  185.     char *argv[4];
  186.     
  187.     if (opt1)
  188.         argv[n++] = opt1;
  189.     if (opt2)
  190.         argv[n++] = opt2;
  191.     if (opt3)
  192.         argv[n++] = opt3;
  193.     if (opt4)
  194.         argv[n++] = opt4;
  195.     assert(n > 0);
  196.  
  197.     if (help)
  198.         show_menu_help (help);
  199.         
  200.     do {
  201.         MoveCursor(x, (int) strlen (prompt));
  202.         fputs (argv[i], stdout);
  203.         fflush (stdout);
  204.         CleartoEOLN (); 
  205.         if ((ch = ReadCh ()) != ' ')
  206.             continue;
  207.         if (++i == n)
  208.             i = 0;
  209.     } while (ch != CR && ch != ESC);
  210.  
  211.     if (ch == ESC)
  212.         return (-1);
  213.     return (i);
  214. }
  215.  
  216. /*
  217.  *  options menu so that the user can dynamically change parameters
  218.  */
  219.  
  220. int kill_art_menu (group_name, index)
  221.     char *group_name;
  222.     int index;
  223. {
  224.     char buf[LEN];
  225.     char text[LEN];
  226.     char kill_from[LEN];
  227.     char kill_subj[LEN];
  228.     char kill_group[LEN];
  229.     char ch_default = 's';
  230.     int ch;
  231.     int counter = 0;
  232.     int killed = TRUE;
  233.     int kill_from_ok = FALSE;
  234.     int kill_subj_ok = FALSE;
  235.     int kill_every_group = FALSE;
  236.     int i;
  237.     int kill_how;
  238.  
  239. #ifdef SIGTSTP
  240.     sigtype_t (*susp)() = (sigtype_t *) 0;
  241.  
  242.     if (do_sigtstp) {
  243.         susp = sigdisp (SIGTSTP, SIG_DFL);
  244.         sigdisp (SIGTSTP, SIG_IGN);
  245.     }
  246. #endif
  247.     
  248.     sprintf (kill_group, "%s only", group_name);
  249.     sprintf (kill_subj, txt_kill_subject, COLS-35, COLS-35, arts[index].subject);
  250.     if (arts[index].name != (char *) 0) {
  251.         sprintf (text, "%s (%s)", arts[index].from, arts[index].name);
  252.     } else {
  253.         strcpy (text, arts[index].from);
  254.     }
  255.     sprintf (kill_from, txt_kill_from, COLS-35, COLS-35, text);
  256.     text[0] = '\0';
  257.     
  258.     ClearScreen ();
  259.  
  260.     center_line (0, TRUE, txt_kill_menu);
  261.     
  262.     MoveCursor (INDEX_TOP, 0);
  263.     printf ("%s\r\n\r\n\r\n", txt_kill_how);
  264.     printf ("%s\r\n\r\n", txt_kill_text);
  265.     printf ("%s\r\n\r\n\r\n", txt_kill_text_type);
  266.     printf ("%s\r\n\r\n", kill_subj);
  267.     printf ("%s\r\n\r\n\r\n", kill_from);
  268.     printf ("%s%s", txt_kill_group, kill_group);
  269.     fflush (stdout);
  270.  
  271.     i = get_choice (INDEX_TOP, txt_help_kill_how, txt_kill_how, 
  272.                "Kill       ", "Auto Select", NULL, NULL);
  273.     if (i == -1) {
  274.         return FALSE;
  275.     }    
  276.     kill_how = (i == 0 ? K_KILL : K_HOT);
  277.  
  278.     show_menu_help (txt_help_kill_text);
  279.     
  280.     if (! prompt_menu_string (INDEX_TOP+3, (int) strlen (txt_kill_text), text)) {
  281.         return FALSE;
  282.     }
  283.  
  284.     if (text[0]) {
  285.         i = get_choice(INDEX_TOP+5, txt_help_kill_text_type, 
  286.                    txt_kill_text_type, "Subject: line only    ", 
  287.                    "From: line only       ", "Subject: & From: lines", 
  288.                    NULL);
  289.         if (i == -1) {
  290.             return FALSE;
  291.         }    
  292.         counter = ((i == 0 ? KILL_SUBJ : (i == 1 ? KILL_FROM : KILL_BOTH)));
  293.     }
  294.  
  295.     if (! text[0]) {
  296.         i = get_choice (INDEX_TOP+8, txt_help_kill_subject, 
  297.                     kill_subj, "Yes", "No ", NULL, NULL);
  298.         if (i == -1) {
  299.             return FALSE;
  300.         } else {
  301.             kill_subj_ok = (i ? FALSE : TRUE);
  302.         }
  303.         i = get_choice (INDEX_TOP+10, txt_help_kill_from, 
  304.                     kill_from, "No ", "Yes", NULL, NULL);
  305.         if (i == -1) {
  306.             return FALSE;
  307.         } else {
  308.             kill_from_ok = (i ? TRUE : FALSE);
  309.         }
  310.     }
  311.  
  312.     if (text[0] || kill_subj_ok || kill_from_ok) {
  313.         i = get_choice (INDEX_TOP+13, txt_help_kill_group, 
  314.                    txt_kill_group, kill_group, "All groups", 
  315.                    NULL, NULL);
  316.         if (i == -1) {
  317.             return FALSE;
  318.         }    
  319.         kill_every_group = (i == 0 ? FALSE : TRUE);
  320.     }
  321.  
  322.     while (1) {
  323.         do {
  324.             sprintf (msg, "%s%c", txt_quit_edit_save_killfile, ch_default);
  325.             wait_message (msg);
  326.             MoveCursor (LINES, (int) strlen (txt_quit_edit_save_killfile));
  327.             if ((ch = ReadCh ()) == CR)
  328.                 ch = ch_default;
  329.         } while (ch != ESC && ch != 'q' && ch != 'e' && ch != 's');
  330.         switch (ch) {
  331.         case 'e':
  332.             start_line_offset = 2;
  333.             invoke_editor (killfile);
  334.             unkill_all_articles ();
  335.             killed_articles = read_kill_file ();
  336.             killed = TRUE;
  337.             goto kill_done;
  338.  
  339.         case 'a':
  340.         case ESC:
  341.             killed = FALSE;
  342.             goto kill_done;
  343.             
  344.         case 's':
  345.             if (kill_num > max_kill-1) {
  346.                 expand_kill ();
  347.             }
  348.  
  349.             killf[kill_num].kill_how = kill_how;
  350.  
  351.             if (text[0]) {
  352.                 sprintf (buf, "%s%s%s", stars, text, stars);
  353.                 switch (counter) {
  354.                 case KILL_SUBJ:
  355.                     killf[kill_num].kill_subj = str_dup (buf);
  356.                     break;
  357.                 case KILL_FROM:
  358.                     killf[kill_num].kill_from = str_dup (buf);
  359.                     break;
  360.                 case KILL_BOTH:
  361.                     killf[kill_num].kill_subj = str_dup (buf);
  362.                     killf[kill_num].kill_from = killf[kill_num].kill_subj; 
  363.                     break;
  364.                 }
  365.                 killf[kill_num].kill_type = counter;
  366.                 if (kill_every_group) {
  367.                     killf[kill_num].kill_group = 0L;
  368.                 } else {
  369.                     killf[kill_num].kill_group = hash_s (group_name);
  370.                 }
  371.                 kill_num++;
  372.             } else {
  373.                 if (kill_subj_ok) {
  374.                     killf[kill_num].kill_type = KILL_SUBJ;
  375.                     sprintf (buf, "%s%s%s", 
  376.                         stars, arts[index].subject, stars);
  377.                     killf[kill_num].kill_subj = str_dup (buf);
  378.                 }
  379.                 if (kill_from_ok) {
  380.                     killf[kill_num].kill_type |= KILL_FROM;
  381.                     if (arts[index].name != (char *) 0) {
  382.                         sprintf (buf, "%s%s (%s)%s", 
  383.                             stars, arts[index].from, arts[index].name, stars);
  384.                     } else {
  385.                         sprintf (buf, "%s%s%s", 
  386.                             stars, arts[index].from, stars);
  387.                     }
  388.                     killf[kill_num].kill_from = str_dup (buf);
  389.                 }
  390.                 if (killf[kill_num].kill_type) {        
  391.                     if (kill_every_group) {
  392.                         killf[kill_num].kill_group= 0L;
  393.                     } else {
  394.                         killf[kill_num].kill_group= hash_s (group_name);
  395.                     }
  396.                     kill_num++;
  397.                 }
  398.             }
  399.             write_kill_file ();
  400.             
  401.         kill_done:
  402.             
  403. #ifdef SIGTSTP
  404.             if (do_sigtstp) {
  405.                 sigdisp (SIGTSTP, susp);
  406.             }
  407. #endif
  408.             return (killed);
  409.         }    
  410.     }
  411.     /* NOTREACHED */
  412. }
  413.  
  414.  
  415. /*
  416.  * We assume that any articles which are tagged as killed are also
  417.  * tagged as being read BECAUSE they were killed. So, we retag
  418.  * them as being unread.
  419.  */
  420.  
  421. int unkill_all_articles ()
  422. {
  423.     int unkilled = FALSE;
  424.     register int i;
  425.  
  426.     for (i=0 ; i < top ; i++) {
  427.         if (arts[i].killed) {
  428.             arts[i].killed = FALSE;
  429.             arts[i].unread = ART_UNREAD;
  430.             unkilled = TRUE;
  431.         }
  432.     }
  433.     num_of_killed_arts = 0;
  434.  
  435.     return (unkilled);
  436. }
  437.  
  438.  
  439. int kill_any_articles (group)
  440.     char *group;
  441. {
  442.     char buf[LEN];
  443.     int killed = FALSE;
  444.     int run_ok = FALSE;
  445.     int is_hot;
  446.     long newsgroup_hash;
  447.     register int i, j;
  448.  
  449.     if (! kill_num) {
  450.         return (killed);
  451.     }
  452.  
  453.     num_of_killed_arts = 0;
  454.     num_of_hot_arts = 0;
  455.  
  456.     newsgroup_hash = hash_s (group);
  457.  
  458.     for (i=0 ; i < kill_num ; i++) {
  459.         if (killf[i].kill_group == 0L ||
  460.             killf[i].kill_group == newsgroup_hash) {
  461.             run_ok = TRUE;    
  462.         }
  463.     }
  464.     if (! run_ok) {
  465.         return (killed);
  466.     }
  467.     if (debug && ! update) {
  468.         wait_message (txt_killing_arts);
  469.     }
  470.     for (i=0 ; i < top ; i++) {
  471.         if (IS_READ(i) && kill_level == 0) {
  472.             continue;
  473.         }    
  474.         for (j=0 ; j < kill_num ; j++) {
  475.             if (killf[j].kill_group != 0L &&
  476.                 killf[j].kill_group != newsgroup_hash)
  477.                 continue;
  478.  
  479.             is_hot = (killf[j].kill_how == K_HOT ? TRUE : FALSE);
  480.             switch (killf[j].kill_type) {
  481.             case KILL_SUBJ:
  482.                 if (STR_MATCH (arts[i].subject, killf[j].kill_subj)) {
  483.                     if (!is_hot)
  484.                         SET_KILLED(i);
  485.                     else
  486.                         SET_HOT(i);
  487.                 }
  488.                 break;
  489.             case KILL_FROM:
  490.                 if (arts[i].name != (char *) 0) {
  491.                     sprintf (buf, "%s (%s)", arts[i].from, arts[i].name);
  492.                 } else {
  493.                     strcpy (buf, arts[i].from);
  494.                 }
  495.                 if (STR_MATCH (buf, killf[j].kill_from)) {
  496.                     if (!is_hot)
  497.                         SET_KILLED(i);
  498.                     else
  499.                         SET_HOT(i);
  500.                 }
  501.                 break;
  502.             case KILL_BOTH:
  503.                 if (STR_MATCH (arts[i].subject, killf[j].kill_subj)) {
  504.                     if (!is_hot)
  505.                         SET_KILLED(i);
  506.                     else
  507.                         SET_HOT(i);
  508.                     break;        /* XXX ? - JBR */
  509.                 }
  510.                 if (arts[i].name != (char *) 0) {
  511.                     sprintf (buf, "%s (%s)", arts[i].from, arts[i].name);
  512.                 } else {
  513.                     strcpy (buf, arts[i].from);
  514.                 }
  515.  
  516.                 if (STR_MATCH (buf, killf[j].kill_from)) {
  517.                     if (!is_hot)
  518.                         SET_KILLED(i);
  519.                     else
  520.                         SET_HOT(i);
  521.                 }
  522.                 break;
  523.             }
  524.             if (IS_KILLED(i) || ! killed)
  525.                 killed = TRUE;
  526.         }
  527.     }
  528.     return (killed);
  529. }
  530.