/*
**++
**  FACILITY:
**	NEWSKILL
**
**  ABSTRACT:
**      Manage kill filters
**
**  AUTHOR:
**      Geoff Huston
**
**  COPYRIGHT:
**      Copyright © 1989, 1990
**
**  MODIFICATION HISTORY:
**	V6.1b11	21-Feb-1997     Mark Martinec   mark.martinec@ijs.si
**	  - fp_open is now int;  pass it by ref;
**	    don't try to delete_file_versions(fp_open);
**	V6.1b11 14-Apr-1997	Mark Martinec   mark.martinec@ijs.si
**	  - replace several calls to strcpy with safer strnncpy
**	  - replace pattern strcpy(news_malloc(strlen(x)+1),x) with news_strdup
**	  - replace pattern strcat(err_oline,x) with err_oline_cat(x)
**--
**/

#ifdef vaxc
#module NEWSKILL "V6.2"
#endif

#define _NEWSKILL_C
#define module_name "NEWSKILL"

#include "newsinclude.h"
#include "newsextern.h"

void kill_read(f)
  FILE *f;
{
  int i;
  char *in_line, *cp, *subj, *from, *header;
  struct marks *n, *c = mk_head;

  if (mk_head) return;

  while ((in_line = fgetl(f)) != 0) {
    if (in_line[0] == '#') continue;
    if (!strcmp(in_line,"PROFILE\n")) {
      profile_read(f);
      break;
      }
    from = subj = header = 0;
    chop_str(in_line,'\n');
    if ((cp = strchr(in_line,' ')) != 0) {
      if ((i = substrcmp(cp," S:")) != 0) {
        cp[i-1] = '\0';
        subj = cp + (i + 2);
        }
      if ((i = substrcmp(cp," F:")) != 0) {
        cp[i-1] = '\0';
        from = cp + (i + 2);
        }
      if ((i = substrcmp(cp," H:")) != 0) {
        cp[i-1] = '\0';
        header = cp + (i + 2);
        }
      *cp = '\0';

      if (!subj && !from && !header) continue;
      while (c && c->m_next) c = c->m_next;
      n = (struct marks *) news_malloc(sizeof *n);
      n->m_type = 1;
      n->m_next = 0;
      if (!c) {
        mk_head = n;
        n->m_tag = news_strdup("1",1);
        }
      else {
        int tag_num = 1;
        char tag_val[4];

        if (sscanf(c->m_tag,"%d",&tag_num) == 1) ++tag_num;
        c->m_next = n;
        sprintf(tag_val,"%d",tag_num);
        n->m_tag = news_strdup(tag_val,-1);
        }
      c = n;
      c->k_grp_name = news_strdup(in_line,-1);
      if (subj) {
        lower_case(subj);
        c->k_itm_title = news_strdup(subj,-1);
        }
      else c->k_itm_title = 0;
      if (from) {
        lower_case(from);
        c->k_itm_from = news_strdup(from,-1);
        }
      else c->k_itm_from = 0;
      if (header) {
        lower_case(header);
        c->k_itm_header = news_strdup(header,-1);
        }
      else c->k_itm_header = 0;
      c->m_itms = 0;
      }
    }
}

/*
 *  kill_write
 *
 *  Write the kill list out to a text file
 */

void kill_write(f)
    FILE *f;
{
    struct marks *c;
    char il[512];
    int init = 0;

    for (c=mk_head; c; c=c->m_next) {
        if (!init++) putl("KILLLIST\n",f);
        strnncpy(il,sizeof(il), c->k_grp_name,-1, 0);
        putl(il,f);
        if (c->k_itm_title) {
            strcpy(il," S:");
            strnncat(il,sizeof(il),-1, c->k_itm_title,-1, 0);
            putl(il,f);
            }
        if (c->k_itm_from) {
            strcpy(il," F:");
            strnncat(il,sizeof(il),-1, c->k_itm_from,-1, 0);
            putl(il,f);
            }
        if (c->k_itm_header) {
            strcpy(il," H:");
            strnncat(il,sizeof(il),-1, c->k_itm_header,-1, 0);
            putl(il,f);
            }
        putl("\n",f);
        }
}

int kill_filter(g,i)
  int g, i;
{
  struct marks *c;
  char *ngroup, subj[SUBJLEN], to_test = 0, inpline[1024];
  int filter_result = 0;

  if (!mk_head) return(0);

  ngroup = ga[g]->grp_name;
  strnncpy(subj,sizeof(subj), ga[g]->grp_ia[i].itm_title,-1, 0);
  lower_case(subj);
  strnncpy(inpline,sizeof(inpline), ga[g]->grp_ia[i].itm_from,-1, 0);
  lower_case(inpline);

  for (c = mk_head; c; c = c->m_next) {
    c->k_test = 0;
    if (!wild_match(ngroup,c->k_grp_name)) continue;
    if ((c->k_itm_title) && (!wild_match(subj,c->k_itm_title))) continue;
    if ((c->k_itm_from) && *inpline && (!wild_match(inpline,c->k_itm_from))) continue;
    c->k_test_from = (*inpline) ? 0 : c->k_itm_from != 0;
    c->k_test_header = c->k_itm_header != 0;
    if (!c->k_test_from && !c->k_test_header) return(1); 
    to_test = c->k_test = 1;
    }
  if (!to_test) return(0);
  if (!(fp = do_open_item(g,i,"r",&fp_open))) return(0);
  while (fgets(inpline,sizeof(inpline),fp)) {
    if (*inpline == '\n') break;
    lower_case(inpline);
    chop_str(inpline,'\n');
    strip(inpline,strlen(inpline));
    for (c = mk_head; c; c = c->m_next) {
      if (!c->k_test) continue;
      if (c->k_test_header) {
        if (wild_match(inpline,c->k_itm_header)) {
          if (!c->k_test_from) { filter_result = 1; break; }
          c->k_test_header = 0;
          }
        }
      if (c->k_test_from && !strncmp(inpline,"from:",5)) {
        if (wild_match(inpline,c->k_itm_from)) {
          if (!c->k_test_header) { filter_result = 1; break; }
          c->k_test_from = 0;
          }
        }
      }
    if (filter_result) break;
    }
  fclose(fp);
/*if (*fp_open > 1) delete_file_versions(fp_open); */
  fp_open = 0;
  return(filter_result);
}

/*
 *  do_killshow
 *
 *  Generate a display of marked items
 */
static int dks_1()
{
  return(mark_show("*",mk_head,0,1,1),0);
}

int do_killshow()
{
  return(unwind_display(I_DISPLAY_LOOP,dks_1));
}

/*
 *  do_kill
 *
 *  Add an entry into the kill filter list
 */

static int dk_1()
{
  struct marks *n, *c = mk_head;
  unsigned short kh_len;
  int ks = 0,
      kf = 0,
      kh = 0;
  char *dflt,
       newslist[256],
       inpline[1024],
       from[256],
       *subj = 0,
       title[132],
       kht[132],
       *cp,
       *cp1;
  $DESCRIPTOR(kh_dsc,kht);


  if ((!curr_g) || (news_context < 2) || (curr_i < 1))
  return(err_line("Error: Kill - No current item selected"),0);

  if (cli$present(c$dsc("SUBJECT")) & 1) ks = 1;
  if (cli$present(c$dsc("FROM")) & 1) kf = 1;
  if ((cli$get_value(c$dsc("HEADER"),&kh_dsc,&kh_len) & 1) && kh_len) {
    kht[kh_len] = '\0';
    strnncat(kht,sizeof(kht),kh_len, "*",1, 0);
    lower_case(kht);
    kh = 1;
    }
  else kh_len = 0;

  if (!(ks + kf + kh)) ks = 1;
  dflt = ga[curr_g]->grp_name;
  parse_newsgroups(newslist,sizeof(newslist), dflt,1,0,0);
  if (!*newslist) return(err_line("Error: Kill - No newsgroup specified"),0);
  if (ks) {
    ks = 1;
    strncpy(title,ga[curr_g]->grp_ia[curr_i].itm_title,5);
    lower_case(title);
    if (!strncmp(title,"re:",3)) {
      strnncpy(title,sizeof(title), ga[curr_g]->grp_ia[curr_i].itm_title,-1, 0);
      cp = &title[3];
      while (*cp && isspace(*cp)) cp++;
      if (!*cp) return(err_line("Error: Kill/Subject - No subject!"),0);
      *--cp = '*';
      subj = cp;
      }
    else {
      int ll;
      *title = '*'; ll = 1;
      strnncat(title,sizeof(title),ll,
               ga[curr_g]->grp_ia[curr_i].itm_title,-1, &ll);
      strnncat(title,sizeof(title),ll, "*",1, &ll);
      subj = title;
      }
    strip(subj,strlen(subj));
    }
  if (kf || kh) {
    *from = '\0';
    if ((fp = do_open_item(curr_g,curr_i,"r",&fp_open)) != 0) {
      while (fgets(inpline,sizeof(inpline),fp)) {
        if (*inpline == '\n') break;
	chop_str(inpline,'\n');
        if (!strncmp(inpline,"From: ",6)) {
          strnncpy(from,sizeof(from), inpline+6,-1, 0);
          if (!kh_len) break;
          }
        if (kh_len) {
          lower_case(inpline);
          if (wild_match(inpline,kht)) {
            strnncpy(kht,sizeof(kht), inpline,-1, 0);
            kh_len = 0;
            if (*from) break;
            }
          }
        }
      fclose(fp);
   /* if (*fp_open > 1) delete_file_versions(fp_open); */
      fp_open = 0;
      }
    if (*from) strip(from,strlen(from));
    else kf = 0;
    if (kh && !kh_len) strip(kht,strlen(kht));
    else kh = 0;
    }
  if (!(ks + kf + kh)) return(err_line("Error: Kill - Cannot locate item text"),0);
  while (c && c->m_next) c = c->m_next;
  for (cp=newslist; cp; cp=cp1) {
    cp1 = chop_str_plus(cp,',');
    n = (struct marks *) news_malloc(sizeof *n);
    n->m_type = 1;
    n->m_next = 0;
    if (!c) {
      mk_head = n;
      n->m_tag = news_strdup("1",1);
      }
    else {
      int tag_num = 1;
      char tag_val[4];

      if (sscanf(c->m_tag,"%d",&tag_num) == 1) ++tag_num;
      c->m_next = n;
      sprintf(tag_val,"%d",tag_num);
      n->m_tag = news_strdup(tag_val,-1);
      }
    c = n;
    c->k_grp_name = news_strdup(cp,-1);
    if (ks) {
      lower_case(subj);
      c->k_itm_title = news_strdup(subj,-1);
      }
    else c->k_itm_title = 0;
    if (kf) {
      lower_case(from);
      c->k_itm_from = news_strdup(from,-1);
      }
    else c->k_itm_from = 0;
    if (kh) c->k_itm_header = news_strdup(kht,-1);
    else c->k_itm_header = 0;
    c->m_itms = 0;
    }
  if (mk_head) mark_show("*",mk_head,0,1,1);
  err_line("KILL Filter added to list");
  return(0);
}

int do_kill()
{
  return(unwind_display(I_DISPLAY_LOOP,dk_1));
}

static int kc_1()
{
  char tag[80];
  unsigned short tag_len;
  $DESCRIPTOR(tag_dsc,tag);

  if (cli$get_value(c$dsc("TAG"),&tag_dsc,&tag_len) & 1) {
    tag[tag_len] = '\0';
    mark_clear(tag,mk_head);
    strcpy(err_oline,"Cleared Kill Filter with Tag: "); err_oline_cat(tag);
    if (mk_head) mark_show("*",mk_head,0,1,1);
    else err_line("ALL Kill Filters cleared");
    }
  else {
    mark_clear(0,mk_head);
    err_line("ALL Kill Filters cleared");
    }
  return(0);
}

int
do_killclear()
{
  return(unwind_display(I_DISPLAY_LOOP,kc_1));
}

static int dkm_1()
{
  char tag[80];
  unsigned short tag_len;
  $DESCRIPTOR(tag_dsc,tag);
  struct marks *c = mk_head;

  if (!mk_head) err_line("No KILL filters defined");
  else if (cli$get_value(c$dsc("TAG"),&tag_dsc,&tag_len) & 1) {
    tag[tag_len] = '\0';
    lower_case(tag);
    chop_str(tag,' ');
    killmod_recurse(c,tag);
    }
  else return(err_line("MODIFY KILL <tag> - no tag number specified"),0);
  if (mk_head) {
    if ((c = find_tag(tag,mk_head,1)) != 0) mark_show(tag,mk_head,0,1,1);
    else mark_show("*",mk_head,0,1,1);
    }
  else err_line("ALL Kill Filters cleared");
  return(0);
}

int do_killmod()
{
  return(unwind_display(I_DISPLAY_LOOP,dkm_1));
}

static void killmod_recurse(c,tag)
  struct marks *c;
  char *tag;
{
  struct marks *p = 0,
               *n;
  char *kng, *kt, *kf, *kh, *cp, *cp1,
       newslist[256],
       nkt[132], nkf[132], nkh[132];
  unsigned short kt_len, trm;
  $DESCRIPTOR(kt_dsc,nkt);
  $DESCRIPTOR(kf_dsc,nkf);
  $DESCRIPTOR(kh_dsc,nkh);

  if ((c = find_tag(tag,c,1)) != 0) {
    mark_show("*",c,1,1,2);
    if (c == mk_head) mk_head = mk_head->m_next;
    else {
      for (p = mk_head;  p->m_next != c;  p = p->m_next) {}
      }
    if (c->m_itms) news_free(c->m_itms);
    if (c->m_tag) news_free(c->m_tag);
    kng = c->k_grp_name;
    kt = c->k_itm_title;
    kf = c->k_itm_from;
    kh = c->k_itm_header;
    err_line("Newsgroups to which this kill filter applies");
    parse_newsgroups(newslist,sizeof(newslist), kng,1,0,0);
    err_line("Subject: line to filter (empty line if not used)");
    get_input_dflt(&kt_dsc,c$dsc("Kill_Subject: "),&kt_len,(kt ? c$dsc(kt) : 0),&trm);
    nkt[kt_len] = '\0';
    err_line("From: to filter (empty line if not used)");
    get_input_dflt(&kf_dsc,c$dsc("Kill_From: "),&kt_len,(kf ? c$dsc(kf) : 0),&trm);
    nkf[kt_len] = '\0';
    err_line("Header line to filter (empty line if not used)");
    get_input_dflt(&kh_dsc,c$dsc("Kill_Header: "),&kt_len,(kh ? c$dsc(kh) : 0),&trm);
    nkh[kt_len] = '\0';
    lower_case(nkt);
    lower_case(nkf);
    lower_case(nkh);
    if (c->k_grp_name) news_free(c->k_grp_name);
    if (c->k_itm_title) news_free(c->k_itm_title);
    if (c->k_itm_from) news_free(c->k_itm_from);
    if (c->k_itm_header) news_free(c->k_itm_header);
    if (p) p->m_next = c->m_next;
    p = c;
    c = c->m_next;
    news_free(p);
    killmod_recurse(c,tag);
    for (c = mk_head;  c && c->m_next;  c = c->m_next) {}
    cp = newslist;
    if (!*cp || (!*nkt && !*nkf && !*nkh)) {
      err_line("Kill filter cleared");
      return;
      }
    for (; cp; cp=cp1) {
      cp1 = chop_str_plus(cp,',');
      n = (struct marks *) news_malloc(sizeof *n);
      n->m_type = 1;
      n->m_next = 0;
      if (!c) {
        mk_head = n;
        n->m_tag = news_strdup("1",1);
        }
      else {
        int tag_num = 1;
        char tag_val[4];

        if (sscanf(c->m_tag,"%d",&tag_num) == 1) ++tag_num;
        c->m_next = n;
        sprintf(tag_val,"%d",tag_num);
        n->m_tag = news_strdup(tag_val,-1);
        }
      c = n;
      c->k_grp_name = news_strdup(cp,-1);
      if (*nkt) c->k_itm_title = news_strdup(nkt,-1);
      else c->k_itm_title = 0;
      if (*nkf) c->k_itm_from = news_strdup(nkf,-1);
      else c->k_itm_from = 0;
      if (*nkh) c->k_itm_header = news_strdup(nkh,-1);
      else c->k_itm_header = 0;
      c->m_itms = 0;
      }
    err_line("KILL Filter modified");
    }
}
