/*
**++
**  FACILITY:
**      NEWSSKIP
**
**  ABSTRACT:
**      Mark items as seen.
**
**  AUTHOR:
**      Geoff Huston
**
**  COPYRIGHT:
**      Copyright © 1988,1989,1990
**
**  MODIFICATION HISTORY:
**      V5.5    7-Oct-1988      GIH
**      V5.6    11-Nov-1988     GIH
**          No changes for V5.6 release
**      V5.8    17-Mar-1989     Stuart McGraw
**        - SKIP command marks item as read in item directory, but does not
**          decrement unread count in newsgroups directory.
**	V6.0	 5-June-1990	GIH
**	  - Support UNSKIP to undo last SKIP command
**	V6.1b7	15-May-1993	Charles Bailey  bailey@genetics.upenn.edu
**	  - Optimize item number lookup
**	6.1b8	24-Jan-1994	Mark Martinec  mark.martinec@ijs.si
**	  - replace calls to smg$put_chars with calls to smg_put_chars 
**	  - check status returned from all calls to SMG$
**	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
**	B6.2 22-Jun-1997	Mark Pizzolato mark@infocomm.com
**	  - added a call to "cur_down_itm" after a successful SKIP/FOLLOWUP
**--
**/

#ifdef vaxc
#module NEWSSKIP "V6.2"
#endif

#define _NEWSSKIP_C
#define module_name "NEWSSKIP"

#include "newsinclude.h"
#include "newsextern.h"

/*
 *  screen_update_gread
 *
 *  Update the read field of the directory screen display
 */

void screen_update_gread(g)
  int g;
{
  int status;
  int indx;

  if ((smg_active) && (indx = ga[g]->grp_display_indx)) {
    if (ga[g]->grp_reg && ga[g]->grp_unread)
      _c$cks(smg$change_rendition(&grp_vd,&indx,c$ac(4),c$ac(1),c$ac(5),c$ac(SMG$M_BOLD),0));
    else
      _c$cks(smg$change_rendition(&grp_vd,&indx,c$ac(4),c$ac(1),c$ac(5),c$ac(0),0));
    sprintf(err_oline,"%5d",ga[g]->grp_unread);
    smg_put_chars(grp_vd,err_oline,indx,73,0,0);
    }
}

/*
 *  screen_update_iread
 *
 *  Update an item display on the screen to indicate that the item
 *  has been read
 */

void screen_update_iread(g,i)
  int g,
      i;
{
  int status;

  if (smg_active && ga[g]->grp_iavdsize) {
    if (ga[g]->grp_ia[i].itm_flags & NEWS_M_UNREAD)
      _c$cks(smg$change_rendition(&(ga[g]->grp_iavd),&i,c$ac(3),c$ac(1),c$ac(6),c$ac(SMG$M_BOLD),0));
    else
      _c$cks(smg$change_rendition(&(ga[g]->grp_iavd),&i,c$ac(3),c$ac(1),c$ac(6),c$ac(0),0));
    }
}

/*
 * add_skip_itm
 *
 * Support for the UNSKIP command - save the group and item numbers
 * in an array for subsequent possible undoing. As well as this array
 * a char pointer is used to save / restore reg text if required
 */

static unsigned int *old_skip_nums = 0,
                     o_s_count,
                     o_s_malloc,
		     o_t_gnum,
		     o_t_ucount,
		     o_t_topread,
		     o_t_funread;

static char *o_t_txt = 0;


static void add_skip_itm(g,i)
  unsigned int g,i;
{
  int j;

  if (!old_skip_nums) old_skip_nums = news_malloc((o_s_malloc = 256) * (sizeof (unsigned int)));
  if (((j = o_s_count * 2)) >= o_s_malloc)
    old_skip_nums = news_realloc(old_skip_nums,(o_s_malloc += 256) * (sizeof (unsigned int)));
  old_skip_nums[j++] = g;
  old_skip_nums[j] = i;
  ++o_s_count;
}

static int skipfollowup()
{
  char title[SUBJLEN+1],
       *cp;
  int i;
  ITM_PTR iap;

  if ((!curr_g) || (news_context < 2) || (curr_i < 1) || !(iap = ga[curr_g]->grp_ia))
    return(err_line("Error: Skip/Followup - No current item selected"),0);
  strnncpy(title,sizeof(title), iap[curr_i].itm_title,-1, 0);
  lower_case(title);
  if (!strncmp(title,"re:",3)) {
    strnncpy(title,sizeof(title), iap[curr_i].itm_title,-1, 0);
    cp = &title[3];
    while ((*cp) && (isspace(*cp))) cp++;
    if (!*cp) {
      err_line("Error: Skip/Followup - No subject!");
      return(0);
      }
    }
  else cp = strnncpy(title,sizeof(title), iap[curr_i].itm_title,-1, 0);
  if (strlen(cp) > (SUBJLEN - 5)) cp[SUBJLEN - 5] = '\0';
    /* clear off old skip buffer */
  o_s_count = 0;
  if (o_t_txt) { news_free(o_t_txt); o_t_txt = 0; }
  strip(cp,strlen(cp));
  for (i = 1; i <= ga[curr_g]->grp_count; ++i)
    if ((iap[i].itm_flags & NEWS_M_UNREAD) && (substrcmp(iap[i].itm_title,cp))) {
      markasread(curr_g,i,0); /* don't update the group display on each pass */
      add_skip_itm(ga[curr_g]->grp_num,iap[i].itm_num);
      }
  cur_down_itm(curr_g,1,1);
  screen_update_gread(curr_g);
  return(0);
}

/*
 *  do_skip
 *
 *  scan over all remaining new news in newsgroup
 */

static int dskip()
{
  char ngroup[GRPNAMELEN];
  $DESCRIPTOR(ngroup_dsc,ngroup);
  unsigned short ngroup_len;
  int g, i, upto = 0, allq, unregq = 0, regq = 0;
  char before[100], uptos[100];
  unsigned short before_len, uptol;
  time_t bef_time;
  $DESCRIPTOR(before_dsc,before);
  $DESCRIPTOR(upto_dsc,uptos);

  if (cli$present(c$dsc("FOLLOWUP")) & 1) return(skipfollowup(),0);

  time(&bef_time);
  before_len = 0;
  if (!nntp_client && cli$get_value(c$dsc("BEFORE"),&before_dsc,&before_len) & 1) {
    before[before_len] = '\0';
    bef_time = cvt_date_val(before);
    before_len = 1;
    }

  if (   (allq = (cli$present(c$dsc("ALL")) & 1))
      || (regq = (cli$present(c$dsc("REGISTERED")) & 1))
      || (unregq = (cli$present(c$dsc("UNREGISTERED")) & 1))) {
    for (g = 1; g <= ga_size; ++g) {
      if (allq || (regq && ga[g]->grp_reg) || (unregq && !ga[g]->grp_reg)) {
        if (ga[g]->grp_unread) {
	    /* clear off old skip buffer */
	  o_s_count = 0;
          if (o_t_txt) { news_free(o_t_txt); o_t_txt = 0; }
          o_t_ucount = ga[g]->grp_unread;
          o_t_topread = ga[g]->grp_topreadnum;
          o_t_funread = ga[g]->grp_funread;
          o_t_gnum = ga[g]->grp_num;
          if (!before_len) ga[g]->grp_unread = 0;
          else if (!ga[g]->grp_ia) map_items(g);
          if (ga[g]->grp_ia) {
            for (i = 1; i <= ga[g]->grp_count; ++i) {
              if (   (ga[g]->grp_ia[i].itm_flags & NEWS_M_UNREAD)
                  && (!before_len || (ga[g]->grp_ia[i].itm_recvdate < bef_time))) {
                markasread(g,i,0); /* don't update grp display on each pass */
                add_skip_itm(ga[g]->grp_num,ga[g]->grp_ia[i].itm_num);
                }
              }
            }
          else if (ga[g]->grp_reg_text) {
            char newreg[10];

            sprintf(newreg," <%d",ga[g]->grp_topnum);
            o_t_txt = news_strdup(ga[g]->grp_reg_text, -1);
            news_free(ga[g]->grp_reg_text);
            ga[g]->grp_reg_text = news_strdup(newreg,-1);
            ga[g]->grp_topreadnum = ga[g]->grp_topnum;
            ga[g]->grp_funread = ga[g]->grp_topnum + 1;
            }
          if (smg_active) screen_update_gread(g);
          }
        }
      }
    return(0);
    }

  g = curr_g;
  if (cli$present(c$dsc("POINTER")) & 1) {
    if (!g) return(err_line("Error: Skip - No Newsgroup selected"),0);
    if (news_context == 1)
      return(err_line("Error: Skip - No Newsgroup selected"),0);
    upto = ga[g]->grp_ia[curr_i].itm_num;
    }
  else if (cli$present(c$dsc("UPTO")) & 1) {
    upto = ga[g]->grp_ia[curr_i].itm_num;
    if (cli$get_value(c$dsc("UPTO"),&upto_dsc,&uptol) & 1) {
      uptos[uptol] = '\0';
      upto = atoi(uptos);
      }
    }

  if (upto) {
    if (ga[g]->grp_unread) {
	/* clear off old skip buffer */
      o_s_count = 0;
      if (o_t_txt) { news_free(o_t_txt); o_t_txt = 0; }
      if (ga[g]->grp_ia) {
        for (i = 1; ((ga[g]->grp_ia[i].itm_num <= upto) && (i <= ga[g]->grp_count)); ++i) {
          if (ga[g]->grp_ia[i].itm_flags & NEWS_M_UNREAD) {
            markasread(g,i,0); /* don't update grp display on each pass */
            add_skip_itm(ga[g]->grp_num,ga[g]->grp_ia[i].itm_num);
            }
          }
        if (smg_active) screen_update_gread(g);
        }
      }
    return(0);
    }

  if (cli$get_value(c$dsc("NEWG"),&ngroup_dsc,&ngroup_len) & 1) {
    ngroup[ngroup_len] = '\0';
    util_cvrt(ngroup,ngroup);

    if (!(g = ga_search_name(ngroup))) {
      strcpy(err_oline,"Error: Skip - no such Newsgroup: ");
      err_oline_cat(ngroup);
      err_line(err_oline);
      return(0);
      }
    }
  else if ((!(cli$present(c$dsc("NEWSGROUP")) & 1)) && (!before_len) &&
           (news_context > 1)) {
      /* clear off old skip buffer */
    o_s_count = 0;
    if (o_t_txt) { news_free(o_t_txt); o_t_txt = 0; }
    if (curr_g && (curr_i > 0)) {
      if (ga[curr_g]->grp_ia[curr_i].itm_flags & NEWS_M_UNREAD) {
        markasread(curr_g,curr_i,1);
        add_skip_itm(ga[curr_g]->grp_num,ga[curr_g]->grp_ia[curr_i].itm_num);
        }
      cur_down_itm(curr_g,1,1);
      }
    return(0);
    }

  if (!g) return(err_line("Error: Skip - No Newsgroup selected"),0);

  if (ga[g]->grp_unread) {
      /* clear off old skip buffer */
    o_s_count = 0;
    if (o_t_txt) { news_free(o_t_txt); o_t_txt = 0; }
    o_t_ucount = ga[g]->grp_unread;
    o_t_topread = ga[g]->grp_topreadnum;
    o_t_funread = ga[g]->grp_funread;
    o_t_gnum = ga[g]->grp_num;
    if (!before_len) ga[g]->grp_unread = 0;
    else if (!ga[g]->grp_ia) map_items(g);
    if (ga[g]->grp_ia) {
      for (i = 1; i <= ga[g]->grp_count; ++i) {
        if ((ga[g]->grp_ia[i].itm_flags & NEWS_M_UNREAD) &&
            (!before_len || (ga[g]->grp_ia[i].itm_recvdate < bef_time))) {
          markasread(g,i,0); /* don't update grp display on each pass */
          add_skip_itm(ga[g]->grp_num,ga[g]->grp_ia[i].itm_num);
          }
        }
      }
    else if (ga[g]->grp_reg_text) {
      char newreg[10];

      sprintf(newreg," <%d",ga[g]->grp_topnum);
      o_t_txt = news_strdup(ga[g]->grp_reg_text, -1);
      news_free(ga[g]->grp_reg_text);
      ga[g]->grp_reg_text = news_strdup(newreg,-1);
      ga[g]->grp_topreadnum = ga[g]->grp_topnum;
      ga[g]->grp_funread = ga[g]->grp_topnum + 1;
      }
    if (smg_active) screen_update_gread(g);
    }
  return(0);
}

int
do_skip()
{
  return(unwind_display(OUTER_LOOP,dskip));
}

/*
 *  do_unskip
 *
 * Restore the read/unread status  of those items affected by the most recent
 * SKIP command.
 */

int dunskip()
{
  int i, j, gn, in, sg = 0, si;
  ITM_PTR l_ia;

  if (o_s_count) {
    for (i = 0; i < o_s_count; ++i) {
      j = 2 * i;
      gn = old_skip_nums[j++];
      in = old_skip_nums[j];
      if (gn != sg) {
        if (sg) screen_update_gread(sg);
        sg = ga_locate(gn);
        }
      if (sg) {
	l_ia = ga[sg]->grp_ia;
	if (find_itm_by_num(sg,in,&si)) markasunread(sg,si,0);
        }
      }
    if (sg) screen_update_gread(sg);
    }
  else if (o_t_txt) {
    GRP_PTR gap;
    ITM_PTR l_ia;
    char *cp;
    int f_itm, l_itm;

    if ((sg = ga_locate(o_t_gnum)) != 0) {
      gap = ga[sg];
      if ((l_ia = gap->grp_ia) != 0) {
        for (i = 1; i <= gap->grp_count; ++i) {
          if (l_ia[i].itm_flags & NEWS_M_UNREAD)
            l_ia[i].itm_flags |= NEWS_M_UNREAD;
          }
        cp = o_t_txt;
        while (cp) {
          if ((*cp == '<') || (*cp == '|')) {
            if (*cp == '|') {
              sscanf(++cp,"%d",&f_itm);
              cp = strchr(cp,'=');
              }
            else f_itm = 1;
            sscanf(++cp,"%d",&l_itm);
            cp = strchr(cp,' ');
            if (cp) ++cp;
            for (i = f_itm; i <= l_itm; ++i)
              if (find_itm_by_num(sg,i,&j)) l_ia[j].itm_flags &= ~NEWS_M_UNREAD;
            }
          else {
            sscanf(cp,"%d",&f_itm);
            cp = strchr(cp,' ');
            if (cp) ++cp;
            if (find_itm_by_num(sg,f_itm,&j)) l_ia[j].itm_flags &= ~NEWS_M_UNREAD;
            }
          }
        gap->grp_unread = 0;
        for (i = 1; i <= gap->grp_count; ++i) {
          if (l_ia[i].itm_flags & NEWS_M_UNREAD) {
            ++(gap->grp_unread);
            if (l_ia[i].itm_num < gap->grp_funread)
              gap->grp_funread = l_ia[i].itm_num;
            }
          else {
            if (l_ia[i].itm_num > gap->grp_topreadnum)
              gap->grp_topreadnum = l_ia[i].itm_num;
            }
          screen_update_iread(sg,i);
          }
        }
      else {
        if (gap->grp_reg_text) news_free(gap->grp_reg_text);
        gap->grp_reg_text = news_strdup(o_t_txt,-1);
        gap->grp_unread = o_t_ucount;
        gap->grp_topreadnum = o_t_topread;
        gap->grp_funread = o_t_funread;
        }
      }
    if (smg_active) screen_update_gread(sg);
    }
  else {
    err_line("UNSKIP: no previous SKIP buffer");
    return(0);
    }
  return(0);
}

int do_unskip()
{
  return(unwind_display(OUTER_LOOP,dunskip));
}
