/*
**++
**  FACILITY:
**      NEWSDIR
**
**  ABSTRACT:
**      This module determines which newsgroups are included in the displayed
**      newsgroup directory.
**
**  AUTHOR:
**      Geoff Huston
**
**  COPYRIGHT:
**      Copyright © 1988,1989,1990
**
**  VERSION:
**	V6.1b11 14-Apr-1997	Mark Martinec   mark.martinec@ijs.si
**	  - replace several calls to strcpy/strcat/sprintf(%s)
**	    with safer strnncpy/strnncat
**	  - use new variable displ_subjlen to dynamically control the
**	    item title and newsgroup name size on the display, depending
**	    on the current screen width
**--
**/

#ifdef vaxc
#module NEWSDIR "V6.2"
#endif

#define _NEWSDIR_C
#define module_name "NEWSDIR"

#include "newsinclude.h"
#include "newsextern.h"

char dir_sincestr[132];

static
int since_time;

static
$DESCRIPTOR(since_dsc,dir_sincestr);

/*
 *  item_dir
 *
 *  dir - directory listing of selected group
 */

static void item_dir(start)
  int start;
{
  int i,
      g_reg;
  ITM_PTR iap;
  char *fdate;

  if (!ga[curr_g]->grp_count) {
    printf("\tDir - Newsgroup is empty: %s\n",ga[curr_g]->grp_name);
    return;
    }

  if ((start + 20) > ga[curr_g]->grp_count) start = ga[curr_g]->grp_count - 20;
  if (start < 1) start = 1;

  textptr.usr_line = 0;
  printf("\n");

  start_header(T_DISPLAY_LOOP,DIR_ITEMS);
  strcpy(err_oline,"News Directory   Group "); err_oline_cat(ga[curr_g]->grp_name);
  put_line(err_oline,0,T_DISPLAY_LOOP);
  put_line("",0,T_DISPLAY_LOOP);
  sprintf(err_oline,"Last item #%d",ga[curr_g]->grp_topnum);
  put_line(err_oline,0,T_DISPLAY_LOOP);
  put_line("",0,T_DISPLAY_LOOP);
  put_line(" Number    Title                                              Lines   Date",0,T_DISPLAY_LOOP);
  put_line("",0,T_DISPLAY_LOOP);
  end_header(T_DISPLAY_LOOP);
  iap = ga[curr_g]->grp_ia;
  g_reg = ga[curr_g]->grp_reg;
  for (i = start; i <= ga[curr_g]->grp_count; ++i) {
    fdate = gendate(iap[i].itm_recvdate);
    if (iap[i].itm_flags & NEWS_M_LINESVALID)
      sprintf(err_oline,"  %-5d %s%s %-*.*s %5d %s",
            iap[i].itm_num,(iap[i].itm_cachedate ? " " : "R"),
            ((iap[i].itm_flags & NEWS_M_UNREAD) ? "*" : " "),
            displ_subjlen,displ_subjlen,iap[i].itm_title,
            iap[i].itm_lines,fdate);
    else sprintf(err_oline,"  %-5d %s%s %-*.*s       %s",
            iap[i].itm_num,(iap[i].itm_cachedate ? " " : "R"),
            ((iap[i].itm_flags & NEWS_M_UNREAD) ? "*" : " "),
            displ_subjlen,displ_subjlen,iap[i].itm_title,
            fdate);
    if (i == ga[curr_g]->grp_c_itm) {
      *err_oline = '-';
      *(err_oline+1) = '>';
      }
    put_line(err_oline,0,T_DISPLAY_LOOP);
    }
}

/*
 *  newsgroup_dir
 *
 *  dir/group - directory of all groups in the system
 */

void newsgroup_dir()
{
  int g,
      sg = 0;
  char srv[10];

  textptr.usr_line = 0;
  printf("\n");
  start_header(T_DISPLAY_LOOP,DIR_GROUPS);
  switch (cur_dir_type) {
    case DIR_ALL:
      put_line("NEWS - Directory of All Newsgroups",0,T_DISPLAY_LOOP);
      break;
    case DIR_DATE:
      strcpy(err_oline,"NEWS - Directory of Newsgroups - New items since ");
      err_oline_cat(dir_sincestr);
      put_line(err_oline,0,T_DISPLAY_LOOP);
      break;
    case DIR_NEW:
      put_line("NEWS - Directory of Registered Newsgroups with unread items",0,T_DISPLAY_LOOP);
      break;
    case DIR_REGISTER:
      put_line("NEWS - Directory of Registered Newsgroups",0,T_DISPLAY_LOOP);
      break;
    case DIR_UNREGISTER:
      put_line("NEWS - Directory of UNRegistered Newsgroups",0,T_DISPLAY_LOOP);
      break;
    }
  put_line(class_name(),0,T_DISPLAY_LOOP);
  sprintf(err_oline,"  Number %-*.*s  Count  Unread",
          displ_subjlen,displ_subjlen,"Group");
  put_line(err_oline,0,T_DISPLAY_LOOP);
  put_line("",0,T_DISPLAY_LOOP);
  end_header(T_DISPLAY_LOOP);

  if ((!curr_g) && ga_size) curr_g = 1;
  for (g = 1; g <= ga_size; ++g) {
    if (!ga[g]->grp_display_indx) continue;

    ga[g]->grp_display_indx = ++sg;
    if (ga[g]->grp_flags & NEWS_M_NNTPSRV) strcpy(srv,"[R]");
    else *srv = '\0';
    sprintf(err_oline,"   %-5d %-*.*s %6d %6d ",
            ga[g]->grp_display_indx,
            displ_subjlen,displ_subjlen,ga[g]->grp_name,
            ga[g]->grp_count,ga[g]->grp_unread);
    err_oline_cat(srv);
    if (curr_g == g) {
      *err_oline = '-';
      *(err_oline+1) = '>';
      }
    put_line(err_oline,0,T_DISPLAY_LOOP);
    }
  grp_display_size = sg;
}

/*
 *  do_dir
 *
 *  Process a directory command
 */

static int static_dt,
           static_fr;

static int
dd_1()
{
  int status;
  int dt, fr;
  char class[132];
  int dir_type = 0,
      gindx,
      new_curr_g = 0,
      incl_grp = 0,
      force_recalc = 0;
  unsigned short since_len;
  unsigned short class_len = 0;
  $DESCRIPTOR(class_dsc,class);

  dt = static_dt;
  fr = static_fr;
  if (!dt) {
    if (cli$present(c$dsc("RESET")) == CLI$_PRESENT) mem_reset(cur_dir_type,1);

    if ((status = cli$present(c$dsc("CLASS"))) == CLI$_NEGATED) {
      class_len = 1;
      reset_class();
      }
    else if ((status & 1) && (cli$get_value(c$dsc("CLASS"),&class_dsc,
        &class_len) & 1)) {
      class[class_len] = '\0';
      set_class(class);
      }

    force_recalc = 1;
    if (cli$present(c$dsc("ALL")) == CLI$_PRESENT) {
#if FAST_LOAD
      if (fast_loading) {
        set_level(1);  /* ensure the directory is shown */
        if (! all_loaded ) {
	  char orig_grp_name[GRPNAMELEN];

	  if (curr_g) strnncpy(orig_grp_name,sizeof(orig_grp_name),
                               ga[curr_g]->grp_name,-1, 0);
	  else orig_grp_name[0] = '\0';
          if (!nntp_client) {
            sysprv();
            sys_close(&itmfab);
            sys_close(&grpfab);
            nosysprv();               /* note this code is taken from the */
            close_hist_file();        /* closefiles function in the       */
            };                        /* NEWSFILES module.                */
          close_mail_file();  
          close_nntp_file();
          write_reg_file();
          all_loaded = 1;
          first_retr_call = 0;
          openfiles(nntp_client ? 4 : -1);
	  if (orig_grp_name[0]) {
            gindx = ga_exact_name(orig_grp_name);
            if (gindx) curr_g = gindx;
            }
          }
        }                                       
#endif
      dir_type = DIR_ALL;
      }
    else if (cli$get_value(c$dsc("SINCE"),&since_dsc,&since_len) & 1) {
      char *cp;

      dir_sincestr[since_len] = '\0';
      since_time = cvt_date_val(dir_sincestr);
      if ((cp = strchr(dir_sincestr,' ')) != 0) *cp = '\0';
      dir_type = DIR_DATE;
      }
    else if (cli$present(c$dsc("NEW")) == CLI$_PRESENT) dir_type = DIR_NEW;
    else if (cli$present(c$dsc("REGISTER")) == CLI$_PRESENT)
       dir_type = DIR_REGISTER;
    else if (cli$present(c$dsc("UNREGISTERED")) == CLI$_PRESENT) {
#if FAST_LOAD
      if (fast_loading) {
        set_level(1);  /* ensure the directory is shown */
        if (! all_loaded ) {
	  char orig_grp_name[GRPNAMELEN];

	  if (curr_g) strnncpy(orig_grp_name, sizeof(orig_grp_name),
                               ga[curr_g]->grp_name,-1, 0);
	  else orig_grp_name[0] = '\0';
          if (!nntp_client) {
            sysprv();
            sys_close(&itmfab);
            sys_close(&grpfab);
            nosysprv();               /* note this code is taken from the */
            close_hist_file();        /* closefiles function in the       */
            };                        /* NEWSFILES module.                */
          close_mail_file();  
          close_nntp_file();
          write_reg_file();
          all_loaded = 1;
	  first_retr_call = 0;
          openfiles(nntp_client ? 4 : -1);  /* note you may need to change the parameter's value */
	  if (orig_grp_name[0]) {
            gindx = ga_exact_name(orig_grp_name);
            if (gindx) curr_g = gindx;
            }
          }
        }                                       
#endif
      dir_type = DIR_UNREGISTER;
      }
    else if (!class_len) {
      force_recalc = 0;
      dir_type = cur_dir_type;
      if (cli$present(c$dsc("ITEMS")) == CLI$_PRESENT) {
        set_level(2);
        if (!smg_active) item_dir(1);
        return(0);
        }
      else if (cli$present(c$dsc("NEWSGROUPS")) == CLI$_PRESENT) set_level(1);
      else if (news_context > 1) {
        set_level(2);
        if (!smg_active) item_dir(curr_i-2);
        return(0);
        }
      }
    }
  else {
    dir_type = dt - 1;
    force_recalc = fr;
    }

  set_level(1);
  if ((!force_recalc) && (dir_type == cur_dir_type)) {
    if (!smg_active) newsgroup_dir();
    return(0);
    }

  grp_display_size = 0;
  for (gindx = 1; gindx <= ga_size; ++gindx) {
    switch (dir_type) {
      case DIR_ALL:
        incl_grp = 1;
        break;
      case DIR_DATE:
        incl_grp = (ga[gindx]->grp_entdate > since_time);
        break;
      case DIR_NEW:
        incl_grp = ((ga[gindx]->grp_reg) && (ga[gindx]->grp_unread));
        break;
      case DIR_REGISTER:
        incl_grp = (ga[gindx]->grp_reg);
        break;
      case DIR_UNREGISTER:
        incl_grp = (ga[gindx]->grp_reg == 0);
        break;
      }
    if (incl_grp && class_check(gindx)) {
      if (gindx < curr_g) new_curr_g = gindx;
      else if (curr_g || (curr_g == gindx)) {
        new_curr_g  = gindx;
        curr_g = 0;
        }
      ga[gindx]->grp_display_indx = ++grp_display_size;
      }
    else ga[gindx]->grp_display_indx = 0;
    }
  cur_dir_type = dir_type;
  if (grp_display_size) curr_g = new_curr_g;
  else curr_g = 0;
  if (smg_active) screen_map_dir();
  else {
    newsgroup_dir();
    set_level(1);
    set_level(2);
    }
  return(0);
}

int
dir_call(dt,fr)
  int dt, fr;
{
  static_dt = dt;
  static_fr = fr;
  return(unwind_display(OUTER_LOOP,dd_1));
}

int
do_dir(dt,fr)
  int dt, fr;
{
  static_dt = dt;
  static_fr = fr;
  return(dd_1());
}

static int static_newlev;

static int
gd_1()
{
  dd_1();
  set_level(static_newlev);
  return(0);
}

int
groupdir(dt,fr,newlev)
  int dt, fr,newlev;
{
  static_dt = dt;
  static_fr = fr;
  static_newlev = newlev;
  return(unwind_display(OUTER_LOOP,gd_1));
}

/*
 *  do_dir_call
 *
 *  CLI entry point to do_dir function
 */

int
do_dircall()
{
    return(dir_call(0,0));
}

/*
 *  dirnew_check
 *
 * check if the newsdirectory requires redisplay in the case of DIR/NEW (i.e.
 * the directory currently contains newsgroups with no unread items - remove
 * them from the directory). This procedure is invoked only when cur_dir_type
 * is DIR_NEW and the screen display is active.
 */

void
dirnew_check()
{
  int g, new_curr_g;

  for (g = 1; g <= ga_size; ++g) {
    if (   (ga[g]->grp_display_indx && !ga[g]->grp_unread)
        || (    !ga[g]->grp_display_indx && ga[g]->grp_unread && ga[g]->grp_reg
             && class_check(g)))
      break;
    }
  if (g > ga_size) return;
  grp_display_size = 0;
  new_curr_g = g;
  for (; g <= ga_size; ++g) {
    if (ga[g]->grp_reg && ga[g]->grp_unread && class_check(g)) {
      if (g < curr_g) new_curr_g = g;
      else if (curr_g || (curr_g == g)) {
        new_curr_g  = g;
        curr_g = 0;
        }
      ga[g]->grp_display_indx = ++grp_display_size;
      }
    else ga[g]->grp_display_indx = 0;
    }
  if (grp_display_size) curr_g = new_curr_g;
  else {
    for (g = new_curr_g; g; --g) {
      if (ga[g]->grp_display_indx) {
        curr_g = g;
        break;
        }
      }
    if (!g) curr_g = 0;
    }
  screen_map_dir();
  return;
}
