/*
**++
**  FACILITY:
**      NEWSSETSHOW
**
**  ABSTRACT:
**      Support the SET and SHOW command to set/display newsgroup attributes.
**
**  AUTHOR:
**      Geoff Huston
**
**  COPYRIGHT:
**      Copyright © 1988,1989,1990,1991
**
**  VERSION:
**	V6.0-1	 5-Nov-1990	glass@mgi.com
**	  - Minor changes to show members
**	  - bug fix to do_modify_member
**	V6.0-4	25-May-1991	volz@process.com
**	  - Added TCPware support
**  6.1b5   17-Feb-1993 bailey@genetics.upenn.edu
**    - changed 'unseenitems' to 'unreaditems' throughout
**	V6.1b6	28-Feb-1993	mark.martinec@ijs.si
**	  - fix strncmp match for generic TCP  (broken by V6.0-4,
**	    so that /PROTOCOL=TCP matched TCPWARE instead of generic TCP)
**	  - change "TCPWARETCP" to "TCPWARE" to match code in NEWS.C
**	    and NEWSFILES.C
**	V6.1b7	15-May-1993	Charles Bailey  bailey@genetics.upenn.edu
**	  - optimize item number lookup
**	  - incorporate improved message-id handling into dsg()
**	V6.1b7   15-Jun-1993 Charles Bailey  bailey@genetics.upenn.edu
**	  - set record size in grprab to NEWS_GRPFIL_RSZ, not sizeof newsgrp,
**	    since newsgrp struct contains volatile data not needed in file
**	V6.1b7	20-May-1993	Charles Bailey  bailey@genetics.upenn.edu
**	  - apply TCPWARE fixes to instance missed in above patch
**	V6.1b8  22-Dec-1993	Mark Martinec   mark.martinec@ijs.si
**	  - convert calls to RMS to use new sys_* macros for error handling 
**	V6.1b9	17-Sep-1994     Mark Martinec   mark.martinec@ijs.si
**	  - code cleanup to preserve the read-only nature of string literals
**	    (strategically placed 'const' attribute to string parameters)
**	V6.1b9	 6-Oct-1994     Mark Martinec   mark.martinec@ijs.si
**	  - when NNTP_CLIENT_ONLY do not call the following routines routines:
**	      add_check_id, clear_gl, server_check, noserver_add, noserver_skim
**	    since they are not present
**	V6.1b11	21-Feb-1997     Mark Martinec   mark.martinec@ijs.si
**	  - fp_open, fpa_open and fpd_open are now int;
**	V6.1b11	28-Mar-1997	Mark Martinec   mark.martinec@ijs.si
**	  - use new procedures available_proto, proto_name and name_to_proto
**	    to replace frequent code patterns and to make possible
**	    using ANU with different TCP transport library
**	    without changing NEWSRC user files (automatically changes
**	    requested and unavailable TCP library to the one
**	    that is compiled-in with the program).
**	V6.1b11 14-Apr-1997	Mark Martinec   mark.martinec@ijs.si
**	  - replace several calls to strcpy/strcat with safer strnncpy/strnncat
**	  - replace pattern strcpy(news_malloc(strlen(x)+1),x) with news_strdup
**	  - replace pattern strcat(err_oline,x) with err_oline_cat(x)
**	  - change %s to %.<n>s in sprintf to guard against overwriting buffer
**          (with somewhat arbitrary limits)
**--
**/

#ifdef vaxc
#module NEWSSETSHOW "V6.2"
#endif

#define _NEWSSETSHOW_C
#define module_name "NEWSSETSHOW"

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

static
char notice[MAXQUALLEN],
     moderator[MAXQUALLEN],
     maillist[MAXQUALLEN],
     title[MAXQUALLEN],
     server_node[MAXQUALLEN],
     tmpstr[MAXQUALLEN];

static
unsigned short cache_val,
               hold_val,
               itemhold_val,
               protocol_val,
               len;

static
int approval_sts,
    cache_sts,
    hold_sts,
    ignexp_sts,
    itemhold_sts,
    local_sts,
    subjectorder_sts,
    moderator_sts,
    maillist_sts,
    notice_sts,
    protocol_sts,
    restrict_sts,
    server_sts,
    title_sts,
    update_sts,
    write_sts;

static
$DESCRIPTOR(dsc,tmpstr);

int get_newsgroup_params()
{
  approval_sts = cli$present(c$dsc("APPROVAL"));
  ignexp_sts = cli$present(c$dsc("IGNOREEXPIRES"));
  local_sts = cli$present(c$dsc("LOCAL"));
  subjectorder_sts = cli$present(c$dsc("SUBJECTORDER"));
  restrict_sts = cli$present(c$dsc("RESTRICT"));
  write_sts = cli$present(c$dsc("WRITE"));
  update_sts = cli$present(c$dsc("UPDATE"));

  dsc.dsc$a_pointer = tmpstr;
  if ((cache_sts = cli$present(c$dsc("CACHE"))) & 1) {
    if (!(cli$get_value(c$dsc("CACHE"),&dsc,&len) & 1))
      cache_val = ga[0]->grp_srvcache;
    else {
      tmpstr[len] = '\0';
      if (sscanf(tmpstr,"%hd",&cache_val) != 1) {
        err_line("Error: Newsgroup qualifier - /CACHE=val not an integer");
        return(0);
        }
      }
    }
  if (cache_sts == CLI$_ABSENT) {
    if ((cache_sts = cli$present(c$dsc("KEEPREQUEST"))) & 1) {
      if (!(cli$get_value(c$dsc("FILEHOLD"),&dsc,&len) & 1))
        cache_val = ga[0]->grp_srvcache;
      else {
        tmpstr[len] = '\0';
        if (sscanf(tmpstr,"%hd",&cache_val) != 1) {
          err_line("Error: Newsgroup qualifier - /FILEHOLD=val not an integer");
          return(0);
          }
        }
      }
    }

  dsc.dsc$a_pointer = tmpstr;
  if ((hold_sts = cli$get_value(c$dsc("HOLD"),&dsc,&len)) & 1) {
    tmpstr[len] = '\0';
    if (!strcmp(tmpstr,"*")) hold_val = (unsigned short) ~0;
    else if (sscanf(tmpstr,"%hd",&hold_val) != 1) {
      err_line("Error: Newsgroup qualifiers - /HOLD=val not an integer");
      return(0);
      }
    }

  dsc.dsc$a_pointer = tmpstr;
  itemhold_sts = cli$present(c$dsc("ITEMHOLD"));
  itemhold_val = 0;
  if (itemhold_sts & 1) {
    if ((itemhold_sts = cli$get_value(c$dsc("ITEMHOLD"),&dsc,&len)) & 1) {
      tmpstr[len] = '\0';
      if (!strcmp(tmpstr,"*")) itemhold_val = (unsigned short) ~0;
      else if (sscanf(tmpstr,"%hd",&itemhold_val) != 1) {
        err_line("Error: Newsgroup qualifiers - /ITEMHOLD=val not an integer");
        return(0);
        }
      }
    }

  dsc.dsc$a_pointer = moderator;
  *moderator = '\0';
  if ((moderator_sts = cli$present(c$dsc("MODERATOR"))) & 1) {
    if (cli$get_value(c$dsc("MODERATOR"),&dsc,&len) & 1) moderator[len] = '\0';
    else *moderator = '\0';
    }

  dsc.dsc$a_pointer = maillist;
  if ((maillist_sts = cli$present(c$dsc("MAILLIST"))) & 1) {
    moderator_sts = maillist_sts;
    approval_sts = CLI$_NEGATED;
    if (cli$get_value(c$dsc("MAILLIST"),&dsc,&len) & 1) {
      strnncpy(moderator,sizeof(moderator), maillist,len, 0);
      }
    }

  dsc.dsc$a_pointer = notice;
  if (((notice_sts = cli$present(c$dsc("NOTICE"))) & 1) &&
      ((notice_sts = cli$get_value(c$dsc("NOTICE"),&dsc,&len)) & 1))
    notice[len] = '\0';

  dsc.dsc$a_pointer = tmpstr;
  if ((protocol_sts = cli$present(c$dsc("PROTOCOL"))) & 1) {
    if (!(cli$get_value(c$dsc("PROTOCOL"),&dsc,&len) & 1))
      protocol_val = ga[0]->grp_srvproto;
    else {
      tmpstr[len] = '\0';
      protocol_val = name_to_proto(tmpstr,len);
      protocol_val = available_proto(protocol_val);
      }
    }

  *server_node = '\0';
  dsc.dsc$a_pointer = server_node;
  if ((server_sts = cli$present(c$dsc("SERVER"))) & 1) {
    len = 0;
    if (cli$get_value(c$dsc("SERVER"),&dsc,&len) & 1) server_node[len] = '\0';
    if (!len) get_input_dflt(&dsc,c$dsc("SERVER Node: "), &len,
                             (ga[0]->grp_srvnode && *(ga[0]->grp_srvnode) ?
                               c$dsc(ga[0]->grp_srvnode) : 0), 0);
    if (!len) server_sts = CLI$_ABSENT;
    if (len > 131) len = 131;
    server_node[len] = '\0';
    }

  dsc.dsc$a_pointer = title;
  if (((title_sts = cli$present(c$dsc("TITLE"))) & 1) &&
      ((title_sts = cli$get_value(c$dsc("TITLE"),&dsc,&len)) & 1))
    title[len] = '\0';

  return(1);
}

void set_newsgroup_params(g)
  unsigned int g;
{
  char mod_add[MAXQUALLEN],
       mod[MAXQUALLEN],
       mod_prompt[MAXQUALLEN];
  unsigned short len;
  $DESCRIPTOR(dsc,mod);
  time_t cur_time;
  int grp_iexp_time,
      glob_iexp_val,
      glob_iexp_time;

  time(&cur_time);
  glob_iexp_val = (ga[0]->grp_itmlife ? ga[0]->grp_itmlife : EXP_TIME);
  glob_iexp_time = cur_time - (glob_iexp_val * DAY_SECS);

  if (approval_sts & 1) ga[g]->grp_flags &= ~NEWS_M_NOAPPROVAL;
  else if (approval_sts == CLI$_NEGATED) ga[g]->grp_flags |= NEWS_M_NOAPPROVAL;

  if (local_sts & 1) ga[g]->grp_flags |= NEWS_M_LOCAL;
  else if (local_sts == CLI$_NEGATED) ga[g]->grp_flags &= ~NEWS_M_LOCAL;

  if (subjectorder_sts & 1) ga[g]->grp_flags |= NEWS_M_ORDERBYSUBJECT;
  else if (subjectorder_sts == CLI$_NEGATED) ga[g]->grp_flags &= ~NEWS_M_ORDERBYSUBJECT;

  if (ignexp_sts & 1) ga[g]->grp_flags |= NEWS_M_IGNEXP;
  else if (ignexp_sts == CLI$_NEGATED) ga[g]->grp_flags &= ~NEWS_M_IGNEXP;

  if (restrict_sts & 1) {
    do_set_restrict(g);
    ga[g]->grp_flags |= NEWS_M_RESTRICT_SET;
    }
  else if (restrict_sts == CLI$_NEGATED) {
    do_set_norestrict(g);
    ga[g]->grp_flags &= ~NEWS_M_RESTRICT_SET;
    }

  if (write_sts & 1) ga[g]->grp_flags &= ~NEWS_M_NOWRITE_SET;
  else if (write_sts == CLI$_NEGATED) ga[g]->grp_flags |= NEWS_M_NOWRITE_SET;

  if (cache_sts & 1) {
    ga[g]->grp_flags |= NEWS_M_NNTPCACHE;
    ga[g]->grp_srvcache = cache_val;
    }
  else if (cache_sts == CLI$_NEGATED) ga[g]->grp_flags &= ~NEWS_M_NNTPCACHE;
  else {
    ga[g]->grp_flags |= NEWS_M_NNTPCACHE;
    ga[g]->grp_srvcache = NNTP_CACHE;
    }

  if (hold_sts & 1) ga[g]->grp_life = hold_val;

  if (itemhold_sts == CLI$_NEGATED) ga[g]->grp_flags |= NEWS_M_NOSTORE;
  else if (itemhold_sts & 1) {
    ga[g]->grp_itmlife = itemhold_val;
    ga[g]->grp_flags &= ~NEWS_M_NOSTORE;
    }

  if (moderator_sts & 1) {
    char *ma;

    ma = moderator_address(ga[g]->grp_name);
    strnncpy(mod_add,sizeof(mod_add), ma,-1, 0);  /* ma may be NULL */
    if (*moderator)
      { int ll; strnncpy(mod,sizeof(mod), moderator,-1, &ll); len = ll; }
    else {
      strcpy(mod_prompt,"Mod Addr: ");
      get_input_dflt(&dsc,c$dsc(mod_prompt),&len,c$dsc(mod_add),0);
      mod[len] = '\0';
      }
    if (!len)    /* if no input for moderator, use the default RRS */
      strnncpy(mod,sizeof(mod), mod_add,-1, 0);
    lower_case(mod);
    if (strcmp(mod,mod_add)) add_moderator(ga[g]->grp_name,mod);
    ga[g]->grp_flags |= NEWS_M_MAILMODERATE;
    }
  else if (moderator_sts == CLI$_NEGATED)
    ga[g]->grp_flags &= ~NEWS_M_MAILMODERATE;

  if (maillist_sts & 1) ga[g]->grp_flags |= NEWS_M_MAILLIST;
  else if (maillist_sts == CLI$_NEGATED) ga[g]->grp_flags &= ~NEWS_M_MAILLIST;
    
  if (notice_sts & 1) {
    if (ga[g]->grp_notice) news_free(ga[g]->grp_notice);
    ga[g]->grp_notice = news_strdup(notice,-1);
    }
  else if (notice_sts == CLI$_NEGATED) {
    if (ga[g]->grp_notice)
      { news_free(ga[g]->grp_notice); ga[g]->grp_notice = NULL; }
    }

  if (protocol_sts & 1) ga[g]->grp_srvproto = protocol_val;

  if (server_sts & 1) {
    if (ga[g]->grp_srvnode) news_free(ga[g]->grp_srvnode);
    ga[g]->grp_srvnode = news_strdup(server_node,-1);
    ga[g]->grp_flags |= NEWS_M_NNTPSRV;
    }
  else if (server_sts == CLI$_NEGATED) {
#if !NNTP_CLIENT_ONLY
    if ((ga[g]->grp_flags & NEWS_M_NNTPSRV)) noserver_add(ga[g]->grp_num);
#endif
    ga[g]->grp_flags &= ~NEWS_M_NNTPSRV;
    }

  if ((update_sts & 1) &&  g &&
      ((itemhold_sts & 1) || (protocol_sts & 1) || (server_sts & 1)) &&
      (ga[g]->grp_flags & NEWS_M_NNTPSRV)) {
    if (ga[g]->grp_itmlife)
      grp_iexp_time = cur_time - (ga[g]->grp_itmlife * DAY_SECS);
    else grp_iexp_time = glob_iexp_time;
    ++server_call;
#if !NNTP_CLIENT_ONLY
    add_check_id(ga[g]->grp_name,0,ga[g]->grp_num,ga[g]->grp_srvnode,
            grp_iexp_time,ga[g]->grp_srvproto);
#endif
    }

  if (title_sts & 1) {
    if (ga[g]->grp_topic) news_free(ga[g]->grp_topic);
    ga[g]->grp_topic = news_strdup(title,-1);
    }
  else if (title_sts == CLI$_NEGATED) {
    if (ga[g]->grp_topic) news_free(ga[g]->grp_topic);
    }
  update_newsgrp(g);
}

void newsg_status(g)
  unsigned int g;
{
  char itemhold[64],
       hold[64],
       delstr[64],
       s[512];
  int s_l;  /* length of s */
  unsigned int hold_val;

  newsgroup_status_line(g);
  hold_val = ga[g]->grp_life;
  *itemhold = '\0';
  if (ga[g]->grp_flags & NEWS_M_NOSTORE) strcpy(itemhold,"0");
  else if (ga[g]->grp_itmlife == 65535) strcpy(itemhold,"Perm");
  else if (ga[g]->grp_itmlife) sprintf(itemhold,"%u",ga[g]->grp_itmlife);

  *hold = '\0';
  if (ga[g]->grp_life == 65535) strcpy(hold,"Perm");
  else if (ga[g]->grp_life) sprintf(hold,"%u",ga[g]->grp_life);
  if ((!(*hold && *itemhold)) && g) {
    if (!*itemhold) {
      if (ga[0]->grp_itmlife == 65535) strcpy(itemhold,"Perm");
      else if (ga[0]->grp_itmlife) sprintf(itemhold,"%u",ga[0]->grp_itmlife);
      }
    if (!*hold) {
      if (ga[0]->grp_life == 65535) strcpy(hold,"Perm");
      else if (ga[0]->grp_life) sprintf(hold,"%u",ga[0]->grp_life);
      hold_val = ga[0]->grp_life;
      }
    }
  if (!*itemhold) sprintf(itemhold,"%u",EXP_TIME);
  if (!*hold) { sprintf(hold,"%u",GRP_TIME); hold_val = GRP_TIME; }

  if (ga[g]->grp_count)
    sprintf(delstr,"#:[121]%u",ga[g]->grp_count);
  else if (hold_val != 65535)
    sprintf(delstr,"Del[002]:[121]%.100s",
            gendate(ga[g]->grp_entdate + (hold_val * DAY_SECS)));
  else *delstr = '\0';

  /* sprintf(s,"%s - %s, Hold:(Itm:%s,Grp:%s), %s",
   *   ga[g]->grp_name,err_oline,itemhold,hold,delstr); s_l = strlen(s);
   *   news_assert(s_l < sizeof(s));  [* or die post-festum *]
   */
  strnncpy(s,sizeof(s), ga[g]->grp_name,-1,   &s_l);
  strnncat(s,sizeof(s),s_l, "[007],[151]",-1, &s_l);
  strnncat(s,sizeof(s),s_l, err_oline,-1,     &s_l);
  strnncat(s,sizeof(s),s_l, ",[121]Hold[003]:[101](Itm[002]:[101]",-1, &s_l);
  strnncat(s,sizeof(s),s_l, itemhold,-1,      &s_l);
  strnncat(s,sizeof(s),s_l, ",[101]Grp[002]:[101]",-1,  &s_l);
  strnncat(s,sizeof(s),s_l, hold,-1,          &s_l);
  strnncat(s,sizeof(s),s_l, ")",1,            &s_l);
  if (*delstr) {
    strnncat(s,sizeof(s),s_l, ",[121]",-1,     &s_l);
    strnncat(s,sizeof(s),s_l, delstr,-1,       &s_l);
    }
  if (ga[g]->grp_flags & NEWS_M_MAILMODERATE) {
    const char *ma = moderator_address(ga[g]->grp_name);
    if (!ma) ma = "<undef[004]>";
    strnncat(s,sizeof(s),s_l, ",[121]Mod-Addr[005]:[101]",-1, &s_l);
    strnncat(s,sizeof(s),s_l, ma,-1, &s_l);
    }
  if (ga[g]->grp_flags & NEWS_M_MAILLIST)
    strnncat(s,sizeof(s),s_l, ",[121]MailList[005]",-1, &s_l);
  strnncat(s,sizeof(s),s_l, "[090]",-1, &s_l);  /* \fill - flushed left */
  fit_line(s,s_l, sizeof(s), (devcol?devcol:80));
  err_line(s);
}

/*
 * update_newsitm
 *
 * Assumes the contents of newsitm have been altered - this procedure
 * updates the master item file.
 */

static void
update_newsitm(g,i)
  int g,i;
{
  int status;

  itmrab.rab$l_kbf = (char *) &(ga[g]->grp_ia[i].itm_num);
  itmrab.rab$b_krf = 0;
  itmrab.rab$b_ksz = 8;
  itmrab.rab$l_rop = RAB$M_WAT;
  itmrab.rab$b_rac = RAB$C_KEY;
  if (sys_find_nornf(&itmrab)) {
    itmrab.rab$l_rbf = (char *) &(ga[g]->grp_ia[i]);
    itmrab.rab$w_rsz = sizeof newsitm;
    sys_update(&itmrab);
    }
}


/*
 * update_newsgrp
 *
 * Assumes the contents of newsgrp have been altered - this procedure
 * updates the master newsgroup file.
 */

void
update_newsgrp(g)
    unsigned int g;
{
  int status;
  GRPF newsgrp;

  grprab.rab$l_kbf = (char *) &(ga[g]->grp_num);
  grprab.rab$b_krf = 1;
  grprab.rab$b_ksz = 4;
  grprab.rab$l_rop = RAB$M_WAT;
  grprab.rab$b_rac = RAB$C_KEY;
  if (sys_find_nornf(&grprab)) {
    grprab.rab$l_rbf = (char *) cnvgroup_inmemory_to_filerec(&newsgrp, ga[g]);
    grprab.rab$w_rsz = NEWS_GRPFIL_RSZ;
    sys_update(&grprab);
    }
}

/*
 *  set_show_item
 *
 *  Common routine to set/show item attributes
 */

static int
set_show_item(setshow)
  int setshow;
{
  char s[132],
       hold[512],
       credate[11],
       deldate[11],
       delstr[20],
       holdstr[30];

  unsigned short  s_len = 0;
  unsigned short  hold_len;
  unsigned short  hold_val;
  $DESCRIPTOR(s_dsc,s);
  $DESCRIPTOR(hold_dsc,hold);

  if ((setshow) && (no_priv())) {
    err_line("Error: Set Item - No priv");
    return(0);
    }

  if ((setshow == 0) && (cli$present(c$dsc("FULL")) & 1)) return(do_show_note(),0);
  cli$get_value(c$dsc("NOTEID"),&s_dsc,&s_len);
  s[s_len] = '\0';
  if (setshow) {
    cli$get_value(c$dsc("HOLD"),&hold_dsc,&hold_len);
    hold[hold_len] = '\0';
    if (!hold_len) hold_len = 0;
    if (!strcmp(hold,"*")) hold_val = (unsigned short) ~0;
    else if (sscanf(hold,"%hd",&hold_val) != 1) {
      err_line("Error: Set Item - /HOLD value not an integer");
      return(0);
      }
    }

  if (!curr_g) {
    err_line("Error: Set/Show Item - No Newsgroup selected");
    return(0);
    }

  if (!*s) {
    if (curr_i <= 0) {
      err_line("Error: Set/Show Item - No current item");
      return(0);
      }
    }
  else if (setshow && !strcmp(s,"*")) {
    int i;

    if (!ga[curr_g]->grp_count) {
      err_line("Error: Set/Show Item - Newsgroup is empty");
      return(0);
      }
    set_level(2);
    for (i = 1 ; i <= ga[curr_g]->grp_count; ++i) {
      ga[curr_g]->grp_ia[i].itm_life = hold_val;
      update_newsitm(curr_g,i);
      }
    sprintf(hold,"Item *, Hold: %d",hold_val);
    err_line(hold);
    return(0);
    }
  else if (!item_find(s)) {
    sprintf(hold,"Error: Set/Show Item - Item %.80s not located",s);
    err_line(hold);
    return(0);
    }

  if (setshow) {
    ga[curr_g]->grp_ia[curr_i].itm_life = hold_val;
    update_newsitm(curr_g,curr_i);
    }

  strnncpy(credate,sizeof(credate),
           gendate(ga[curr_g]->grp_ia[curr_i].itm_recvdate), -1, 0);
  *delstr = '\0';
  if (ga[curr_g]->grp_ia[curr_i].itm_life) {
    if (ga[curr_g]->grp_ia[curr_i].itm_life == 65535) strcpy(holdstr,"Perm");
    else {
      sprintf(holdstr,"%u",ga[curr_g]->grp_ia[curr_i].itm_life);
      strnncpy(deldate,sizeof(deldate),
               gendate(ga[curr_g]->grp_ia[curr_i].itm_recvdate +
                       (ga[curr_g]->grp_ia[curr_i].itm_life * DAY_SECS)), -1,0);
      sprintf(delstr,"Del: %.12s, ",deldate);
      }
    }
  else {
    if (ga[curr_g]->grp_itmlife) {
      if (ga[curr_g]->grp_itmlife == 65535) strcpy(holdstr,"[Perm]");
      else {
        sprintf(holdstr,"[%u]",ga[curr_g]->grp_itmlife);
        strnncpy(deldate,sizeof(deldate),
                 gendate(ga[curr_g]->grp_ia[curr_i].itm_recvdate +
                         (ga[curr_g]->grp_itmlife * DAY_SECS)), -1, 0);
        sprintf(delstr,"Del: %.12s, ",deldate);
        }
      }
    else {
      if (!ga[0]->grp_itmlife) ga[0]->grp_itmlife = EXP_TIME;
      if (ga[0]->grp_itmlife == 65535) strcpy(holdstr,"[Perm]");
      else {
        sprintf(holdstr,"[%u]",ga[0]->grp_itmlife);
        strnncpy(deldate,sizeof(deldate),
                 gendate(ga[curr_g]->grp_ia[curr_i].itm_recvdate +
                         (ga[0]->grp_itmlife * DAY_SECS)), -1, 0);
        sprintf(delstr,"Del: %.12s, ",deldate);
        }
      }
    }
  if (ga[curr_g]->grp_ia[curr_i].itm_flags & NEWS_M_LINESVALID) 
    sprintf(err_oline,", Size: %u",
      ga[curr_g]->grp_ia[curr_i].itm_lines);
  else *err_oline = '\0';
  { int hold_l;
    sprintf(hold,"Item %u, Cre: ", ga[curr_g]->grp_ia[curr_i].itm_num);
    strnncat(hold,sizeof(hold),-1,     credate,-1,   &hold_l);
    strnncat(hold,sizeof(hold),hold_l, ", ",2,       &hold_l);
    strnncat(hold,sizeof(hold),hold_l, delstr,-1,    &hold_l);
    strnncat(hold,sizeof(hold),hold_l, "Hold: ",6,   &hold_l);
    strnncat(hold,sizeof(hold),hold_l, holdstr,-1,   &hold_l);
    strnncat(hold,sizeof(hold),hold_l, err_oline,-1, &hold_l);
    err_line(hold);
  }
  return(0);
}

/*
 *  set_show_newsgroup
 *
 *  Common routine to set/show newsgroup attributes
 */

int set_show_newsgroup(setshow)
    int setshow;
{
  char s[MAXQUALLEN];
  int old_lev,
      wild_group = 0;
  unsigned int g;
  unsigned short s_len;
  $DESCRIPTOR(s_dsc,s);

  if ((setshow) && (no_priv()))
    return(err_line("Error: Set Newsgroup - No priv"),0);
  if ((setshow == 0) && (cli$present(c$dsc("FULL")) & 1)) return(do_show_entry(),0);
  server_call = 0;
#if !NNTP_CLIENT_ONLY
  clear_gl();
#endif
  old_lev = news_context;
  cli$get_value(c$dsc("GROUP"),&s_dsc,&s_len);
  s[s_len] = '\0';

  if (setshow && !get_newsgroup_params()) return(0);

  if ((!*s) || !strcmp(s,".")) {
    if (!curr_g) {
      err_line("Error: Set/Show Newsgroup - No Newsgroup specified");
      return(0);
      }
    else g = curr_g;
    }
  else if (!strcmp(lower_case(s),"default")) {
    g = 0;
    strcpy(s,"Default Newsgroup");
    }
  else if (setshow && (strchr(s,'*') || strchr(s,'%'))) {
    wild_group = 1;
    util_cvrt(s,s);
    g = 1;
    err_line("Modifying all matching newsgroups to supplied parameters");
    }
  else {
    util_cvrt(s,s);
    if (!(g = ga_exact_name(s))) {
      sprintf(err_oline,"Error: Set/Show Newsgroup - %.200s not located",s);
      err_line(err_oline);
      return(0);
      }
    }

  if (setshow) {
    for (;;) {
      if (wild_group) {
        while (!wild_match(ga[g]->grp_name,s) && (++g <= ga_size));
        if (g > ga_size) break;
        }

      set_newsgroup_params(g);

      if (smg_active && (news_context > 1) && (g == curr_g)) newsgroup_header();
      if (!wild_group) break;
      if (++g > ga_size) break;
      }
    }

  if (server_call) {
    verbose = 1;
#if !NNTP_CLIENT_ONLY
    server_check(1,1);
    clear_gl();
#endif
    }
#if !NNTP_CLIENT_ONLY
  noserver_skim();
#endif
  if (wild_group) return(0);
  newsg_status(g);
  start_header(T_DISPLAY_LOOP,SHOW_ENTRY);
  sprintf(err_oline,"Show Entry: Newsgroup %.200s",ga[g]->grp_name);
  put_line(err_oline,0,T_DISPLAY_LOOP);
  put_line("",0,T_DISPLAY_LOOP);
  end_header(T_DISPLAY_LOOP);
  display_group(g);
  put_line("",1,T_DISPLAY_LOOP);
  return(0);
}

/*
 *  do_show_item
 *
 *  Show item attributes
 */

static int
dsi_1()
{
  return(set_show_item(0));
}

int
do_show_item()
{
  return(unwind_display(I_DISPLAY_LOOP,dsi_1));
}

/*
 *  do_set_item
 *
 *  Set item attributes
 */

#if !NNTP_CLIENT_ONLY
static int
dsi_2()
{
  return(set_show_item(1),0);
}
#endif

int
do_set_item()
{
#if NNTP_CLIENT_ONLY
  return(0);
#else
  if (nntp_client) return(0);
  return(unwind_display(I_DISPLAY_LOOP,dsi_2));
#endif
}

/*
 *  do_show_newsgroup
 *
 *  Set newsgroup attributes
 */

static int dsn_1()
{
  return(set_show_newsgroup(0),0);
}

int
do_show_newsgroup()
{
  return(unwind_display(I_DISPLAY_LOOP,dsn_1));
}

/*
 *  do_set_newsgroup
 *
 *  Set newsgroup attributes
 */

#if !NNTP_CLIENT_ONLY
static int
dsn_2()
{
  return(set_show_newsgroup(1),0);
}
#endif

int
do_set_newsgroup()
{
#if NNTP_CLIENT_ONLY
  return(0);
#else
  if (nntp_client) return(0);
  return(unwind_display(I_DISPLAY_LOOP,dsn_2));
#endif
}

int ismember(ng,user)
    char *ng, *user;
{
    FILE *fpr;
    char il[256], cu[256],
         *cp, *ap, *op;
    int retval = 0;

    sprintf(itm_fname,Access_template,util_dir(ng));
    sysprv();
    if (!(fpr = fopen(itm_fname,"r"))) return(nosysprv(),0);
    while (fgets(il,sizeof(il),fpr)) {
        if (*il == '#') continue;
        cp = chop_str(il,' ');
        ap = chop_str(il,'@');
        op = chop_str(il,':');
        strnncpy(cu,sizeof(cu), il,-1, 0);
        if (cp) *cp = ' ';
        if (ap) *ap = '@';
        if (op) *op = ':';
        lower_case(cu);
        if (!strcmp(cu,user)) {
            retval = 1;
            break;
            }
        }
    fclose(fpr);
    nosysprv();
    return(retval);
}

#if NNTP_CLIENT_ONLY

int do_add_member() { return(0); }

#else

int do_add_member()
{
  int status;
  FILE *fpr, *fpw;
  char uv[256], username[132], mailstr[256], nodelist[256], privstr[256],
       *c, *cp, *ap, *op;
  int nodelist_l;  /* length of nodelist */
  int privstr_l;   /* length of privstr */
  int was_a_memb = 0,
      writeacc = 1,
      superacc = 0;
  unsigned short ul;
  $DESCRIPTOR(ud,uv);

  if (nntp_client) return(0);

  if (!curr_g) return(err_line("Add Member: No current newsgroup selected"),0);
  if (no_priv() && !(ga[curr_g]->grp_flags & NEWS_M_MOD_ACCESS))
    return(err_line("Add Member: No Privs for operation"),0);

  *mailstr = *privstr = *nodelist = '\0';  privstr_l = nodelist_l = 0;

  if (   !(cli$get_value(c$dsc("USERNAME"),&ud,&ul) & 1)
      || !ul)
    return(0);
  uv[ul] = '\0';
  lower_case(uv);
  if ((c = strchr(uv,':')) != 0 && *(c + 1) == ':') {
    *c = '\0';
    strnncpy(nodelist,sizeof(nodelist), "@",1, &nodelist_l);
    strnncat(nodelist,sizeof(nodelist),nodelist_l, uv,-1, &nodelist_l);
    strnncpy(username,sizeof(username), c+2,-1, 0);
    }
  else if ((c = strchr(uv,'@')) != 0) {
    strnncpy(nodelist,sizeof(nodelist), c,-1, &nodelist_l);
    *c = '\0';
    strnncpy(username,sizeof(username), uv,-1, 0);
    }
  else strnncpy(username,sizeof(username), uv,-1, 0);

  if (cli$get_value(c$dsc("MAIL"),&ud,&ul) & 1) {
    uv[ul] = '\0';
    strcpy(mailstr," MAIL:"); strnncat(mailstr,sizeof(mailstr),-1, uv,ul, 0);
    }
   while (cli$get_value(c$dsc("NODES"),&ud,&ul) & 1) {
    uv[ul] = '\0';
    lower_case(uv);
    if (*nodelist)
      strnncat(nodelist,sizeof(nodelist),nodelist_l, " ",1, &nodelist_l);
    strnncat(nodelist,sizeof(nodelist),nodelist_l, "@",1, &nodelist_l);
    strnncat(nodelist,sizeof(nodelist),nodelist_l, uv,ul, &nodelist_l);
    }

  while (cli$get_value(c$dsc("PRIVILEGES"),&ud,&ul) & 1) {
    uv[ul] = '\0';
    lower_case(uv);
    if (   !strncmp(uv,"moderate",ul)
        || !strncmp(uv,"supervise",ul)) superacc = 1;
    else if (!strncmp(uv,"write",ul)) writeacc = 1;
    else if (!strncmp(uv,"nowrite",ul)) writeacc = 0;
    }
  if (superacc)
    strnncat(privstr,sizeof(privstr),privstr_l, " SUPERVISE",-1, &privstr_l);
  strnncat(privstr,sizeof(privstr),privstr_l,
           writeacc ? " WRITE" : " NOWRITE", -1, &privstr_l);

  sprintf(itm_fname,Access_template,util_dir(ga[curr_g]->grp_name));
  sysprv();
  if (!(fpr = fopen(itm_fname,"r"))) {
    if (!((ga[curr_g]->grp_flags & NEWS_M_NOWRITE_SET) ||
         (ga[curr_g]->grp_flags & NEWS_M_RESTRICT_SET))) {
      sprintf(err_oline,"Newsgroup %.200s is NOT a Restricted Newsgroup",ga[curr_g]->grp_name);
      err_line(err_oline);
      status = get_input(&usr_inp_dsc,c$dsc("Create Membership file anyway? [y]"),&usr_inp_l);
      clear_err_line();
      if ((!(status & 1)) || (usr_inp_l && (tolower(*usr_inp) != 'y')))
        return(0);
      }
    }
  fpw = fopen(itm_fname,"w");
  fprintf(fpw,"%s%s%s%s\n",username,nodelist,privstr,mailstr);
  strcpy(err_oline,"Add Member ");
  err_oline_cat(ga[curr_g]->grp_name); err_oline_cat(": ");
  err_oline_cat(username); err_oline_cat(nodelist);
  err_oline_cat(privstr);  err_oline_cat(mailstr);
  if (fpr) {
    while (fgets(mailstr,sizeof(mailstr),fpr)) {
      if (*mailstr == '#') {
        fputs(mailstr,fpw);
        continue;
        }
      op = chop_str(mailstr,':');
      cp = chop_str(mailstr,' ');
      ap = chop_str(mailstr,'@');
      strnncpy(uv,sizeof(uv), mailstr,-1, 0);
      if (cp) *cp = ' ';
      if (ap) *ap = '@';
      if (op) *op = ':';
      lower_case(uv);
      if (!strcmp(uv,username)) {
        was_a_memb = 1;
        continue;
        }
      fputs(mailstr,fpw);
      }
    fclose(fpr);
    }
  fclose(fpw);
  strnncat(itm_fname,itm_fname_m,-1, ";-1",3, 0);
  delete_file_versions(itm_fname);
  nosysprv();
  if (was_a_memb) {
    strcpy(err_oline,"Alter Existing Member ");
    err_oline_cat(ga[curr_g]->grp_name); err_oline_cat(": ");
    err_oline_cat(username); err_oline_cat(nodelist);
    err_oline_cat(privstr);  err_oline_cat(mailstr);
    }
  err_line(err_oline);
  ga[curr_g]->grp_flags &= ~NEWS_M_ACCESS_CHECKED;
  gwrite_access(curr_g);
  if (smg_active && (news_context > 1)) newsgroup_header();
  return(0);
}
#endif

#if NNTP_CLIENT_ONLY

int do_delete_member() { return(0); }

#else

int
do_delete_member()
{
  FILE *fpr, *fpw;
  char uv[256], il[256], cu[132],
       *cp, *ap, *op;
  int m_deleted = 0, no_more = 1;
  unsigned short ul;
  $DESCRIPTOR(ud,uv);

  if (nntp_client) return(0);
  if (!curr_g)
    return(err_line("Delete Member: No current newsgroup selected"),0);
  if (no_priv() && !(ga[curr_g]->grp_flags & NEWS_M_MOD_ACCESS))
    return(err_line("Delete Member: No Privs for this command"),0);

  if (!(cli$get_value(c$dsc("USERNAME"),&ud,&ul) & 1)) return(0);
  if (!ul) return(0);
  uv[ul] = '\0';
  lower_case(uv);

  if (!ismember(ga[curr_g]->grp_name,uv)) {
    sprintf(err_oline,"Delete Member: Username %.200s is not a member of %.200s",uv,ga[curr_g]->grp_name);
    err_line(err_oline);
    return(0);
    }

  sprintf(itm_fname,Access_template,util_dir(ga[curr_g]->grp_name));
  sysprv();
  if (!(fpr = fopen(itm_fname,"r"))) {
    sprintf(err_oline,"Delete Member: Newsgroup %.200s member list is empty",ga[curr_g]->grp_name);
    err_line(err_oline);
    return(nosysprv(),0);
    }
  fpw = fopen(itm_fname,"w");
  while (fgets(il,sizeof(il),fpr)) {
    if (*il == '#') {
      fputs(il,fpw);
      continue;
      }
    cp = chop_str(il,' ');
    ap = chop_str(il,'@');
    op = chop_str(il,':');
    strnncpy(cu,sizeof(cu), il,-1, 0);
    if (cp) *cp = ' ';
    if (ap) *ap = '@';
    if (op) *op = ':';
    lower_case(cu);
    if (!strcmp(cu,uv)) {
      m_deleted = 1;
      continue;
      }
    else no_more = 0;
    fputs(il,fpw);
    }
  fclose(fpr);
  fclose(fpw);
  strnncat(itm_fname,itm_fname_m,-1, ";-1",3, 0);
  delete_file_versions(itm_fname);
  nosysprv();
  ga[curr_g]->grp_flags &= ~NEWS_M_ACCESS_CHECKED;
  gwrite_access(curr_g);
  if (smg_active && (news_context > 1)) newsgroup_header();
  if (m_deleted) {
    sprintf(err_oline,"Deleted Member: %.200s",uv);
    err_line(err_oline);
    if (!no_more) show_members(1,0,0);
    }
  else {
    sprintf(err_oline,"Delete Member: Username %.200s is not a member of %.200s",uv,ga[curr_g]->grp_name);
    err_line(err_oline);
    }
  return(0);
}
#endif

#if NNTP_CLIENT_ONLY

int do_modify_member(void) { return(0); }

#else

int do_modify_member(void)
{
  FILE *fpr, *fpw;
  static char newname[132];
  char uv[256], username[132], mailstr[256], nodelist[256], il[256],
       *c, *cp, *ap, *op;
  int writeacc = -1, modacc = -1, m_mod = 0;
  unsigned short ul;
  $DESCRIPTOR(ud,uv);

  if (!curr_g)
    return(err_line("Modify Member: No current newsgroup selected"),0);
  if (no_priv() && !(ga[curr_g]->grp_flags & NEWS_M_MOD_ACCESS))
    return(err_line("Modify Member: No Privs for this command"),0);

  *mailstr = *nodelist = '\0';
  if (!(cli$get_value(c$dsc("USERNAME"),&ud,&ul) & 1)) return(0);
  if (!ul) return(0);
  uv[ul] = '\0';
  lower_case(uv);
  strnncpy(username,sizeof(username), uv,ul, 0);
  strnncpy(newname,sizeof(newname),   uv,ul, 0);

  if (cli$get_value(c$dsc("NAME"),&ud,&ul) & 1) {
    if ((c = strchr(uv,':')) != 0 && *(c + 1) == ':') {
      *c = '\0';
      strcpy(nodelist,"@"); strnncat(nodelist,sizeof(nodelist),1, uv,-1, 0);
      strnncpy(newname,sizeof(newname), c+2,-1, 0);
      }
    else if ((c = strchr(uv,'@')) != 0) {
      strnncpy(nodelist,sizeof(nodelist), c,-1, 0);
      *c = '\0';
      strnncpy(newname,sizeof(newname), uv,-1, 0);
      }
    else strnncpy(newname,sizeof(newname), uv,-1, 0);
    }

  if (cli$get_value(c$dsc("MAIL"),&ud,&ul) & 1) {
    uv[ul] = '\0';
    strcpy(mailstr," MAIL:"); strnncat(mailstr,sizeof(mailstr),-1, uv,ul, 0);
    }
  while (cli$get_value(c$dsc("NODES"),&ud,&ul) & 1) {
    uv[ul] = '\0';
    lower_case(uv);
    if (*nodelist) strnncat(nodelist,sizeof(nodelist),-1, " ",1, 0);
    strnncat(nodelist,sizeof(nodelist),-1, "@",1, 0);
    strnncat(nodelist,sizeof(nodelist),-1, uv,ul, 0);
    }

  while (cli$get_value(c$dsc("PRIVILEGES"),&ud,&ul) & 1) {
    uv[ul] = '\0';
    lower_case(uv);
    if (!strncmp(uv,"moderate",ul)) modacc = 1;
    else if (!strncmp(uv,"nomoderate",ul)) modacc = 0;
    else if (!strncmp(uv,"supervise",ul)) modacc = 1;
    else if (!strncmp(uv,"nosupervise",ul)) modacc = 0;
    else if (!strncmp(uv,"write",ul)) writeacc = 1;
    else if (!strncmp(uv,"nowrite",ul)) writeacc = 0;
    }

  if (!ismember(ga[curr_g]->grp_name,username)) {
    sprintf(err_oline,"Modify Member: Username %.200s is not a member of %.200s",username,ga[curr_g]->grp_name);	/* changed uv to username */
    err_line(err_oline);
    return(0);
    }

  sprintf(itm_fname,Access_template,util_dir(ga[curr_g]->grp_name));
  sysprv();
  if (!(fpr = fopen(itm_fname,"r"))) {
    sprintf(err_oline,"Modify Member: Newsgroup %.200s is NOT a restricted newsgroup",ga[curr_g]->grp_name);
    err_line(err_oline);
    return(nosysprv(),0);
    }
  fpw = fopen(itm_fname,"w");
  while (fgets(il,sizeof(il),fpr)) {
    if (*il == '#') {
      fputs(il,fpw);
      continue;
      }
    cp = chop_str(il,' ');
    ap = chop_str(il,'@');
    op = chop_str(il,':');
    strnncpy(uv,sizeof(uv), il,-1, 0);
    if (cp) *cp = ' ';
    if (ap) *ap = '@';
    if (op) *op = ':';
    lower_case(uv);
    if (!strcmp(uv,username)) {
      int i;
      char *cx;

      ++m_mod;
      lower_case(il);
      fprintf(fpw,"%s",newname);

      if (op) *op = '\0';
      if ((!*nodelist) && (ap)) {
        while (ap) {
          for (; *ap && !isspace(*ap); ap++) fputc(*ap,fpw);
          ap = strchr(ap,'@');
          }
        }
      else if (*nodelist) fputs(nodelist,fpw);
      if (op) *op = ':';

      lower_case(cp);
      if ((cx = strchr(cp,'\n')) != 0) *cx = ' ';
      if (substrcmp(cp," write ") && writeacc == -1) writeacc = 1;
      else if (substrcmp(cp," nowrite ") && writeacc == -1) writeacc = 0;
      else if (writeacc == -1) writeacc = 1;
      if (substrcmp(cp," moderate ") && modacc == -1) modacc = 1;
      else if (substrcmp(cp," nomoderate ") && modacc == -1) modacc = 0;
      if (substrcmp(cp," moderator ") && modacc == -1) modacc = 1;
      else if (substrcmp(cp," nomoderator ") && modacc == -1) modacc = 0;
      if (substrcmp(cp," supervise ") && modacc == -1) modacc = 1;
      else if (substrcmp(cp," supervise ") && modacc == -1) modacc = 0;
      else if (modacc == -1) modacc = 0;

      if (modacc) fprintf(fpw," SUPERVISE ");
      if (!writeacc) fprintf(fpw," NOWRITE ");
      else fprintf(fpw," WRITE ");

      if ((!*mailstr) && (i = substrcmp(cp," mail:"))) {
        fputc(' ',fpw);
        for (; !isspace(cp[i]); i++) fputc(cp[i],fpw);
        }
      else if (*mailstr) fputs(mailstr,fpw);

      fputc('\n',fpw);
      }
    else fputs(il,fpw);
    }
  fclose(fpr);
  fclose(fpw);
  strnncat(itm_fname,itm_fname_m,-1, ";-1",3, 0);
  delete_file_versions(itm_fname);
  nosysprv();
  ga[curr_g]->grp_flags &= ~NEWS_M_ACCESS_CHECKED;
  gwrite_access(curr_g);
  if (smg_active && (news_context > 1)) newsgroup_header();
  if (m_mod) {
    sprintf(err_oline,"Modified Member Entry: %.200s",username);
    err_line(err_oline);
    show_members(0,0,newname);
    }
  else {
    sprintf(err_oline,"Modify Member: Username %.200s is not a member of %.200s",username,ga[curr_g]->grp_name);
    err_line(err_oline);
    }
  return(0);
}
#endif

static int st_all, st_mod;
static char *st_uv;

static int sm_1()
{
  char ml[256], il[256], rl[256], us[256],
       *cp, *ap, *op, *uv;
  int displayed = 0, all, mod;

  all = st_all; mod = st_mod; uv = st_uv;
  if (mod) all = 1;
  if (!curr_g)
    return(err_line("Show Member: No current newsgroup selected"),0);

  *ml = '\0';
  if (ga[curr_g]->grp_flags & NEWS_M_MAILMODERATE) {
    char *ma;

    ma = moderator_address(ga[curr_g]->grp_name);
    if (ma) sprintf(ml,"APPROVAL-MODERATOR Mail_Address: %.200s",ma);
    else sprintf(ml,"APPROVAL-MODERATOR Mail_Address: <address not locally defined>");
    }
  sprintf(itm_fname,Access_template,util_dir(ga[curr_g]->grp_name));
  sysprv();
  if (!(fp = fopen(itm_fname,"r"))) {
    err_line("Membership of this newsgroup is empty");
    return(nosysprv(),0);
    }
  fp_open = 1;
  nosysprv();

  while (fgets(il,sizeof(il),fp)) {
    if (*il == '#') continue;
    if ((cp = strchr(il,'\n')) != 0) *cp = ' ';
    strnncpy(rl,sizeof(rl), il,-1, 0);
    lower_case(rl);
    cp = chop_str(rl,' ');
    ap = chop_str(rl,'@');
    op = chop_str(rl,':');
    strnncpy(us,sizeof(us), rl,-1, 0);
    if (cp) *cp = ' ';
    if (ap) *ap = '@';
    if (op) *op = ':';
    if (all || (uv && !strcmp(us,uv))) {
      if (mod && !substrcmp(cp," moderate ")
              && !substrcmp(cp," moderator ")
              && !substrcmp(cp," supervise ")) continue;
      if (!displayed) {
        start_header(T_DISPLAY_LOOP,SHOW_MEMBER);
        if (mod) sprintf(err_oline,"Membership of Newsgroup %.200s - Supervisors",ga[curr_g]->grp_name);
        else if (all) sprintf(err_oline,"Membership of Newsgroup %.200s - All entries",ga[curr_g]->grp_name);
        else sprintf(err_oline,"Membership Entry for Newsgroup %.200s - User %.200s",ga[curr_g]->grp_name,uv);
        put_line(err_oline,0,T_DISPLAY_LOOP);
        put_line("",0,T_DISPLAY_LOOP);
        end_header(T_DISPLAY_LOOP);
        displayed = 1;
        if (*ml) put_line(ml,0,T_DISPLAY_LOOP);
        }
      put_line(il,0,T_DISPLAY_LOOP);
      }
    }
  sysprv();
  fclose(fp);
  fp_open = 0;
  nosysprv();
  if (displayed) put_line("",1,T_DISPLAY_LOOP);
  else {
    if (all) err_line("Membership of this newsgroup is empty");
    else err_line("No such Member in this newsgroup");
    }
  return(0);
}

int show_members(all,mod,uv)
  int all, mod;
  char *uv;
{
  st_all = all; st_mod = mod; st_uv = uv;
  return(unwind_display(I_DISPLAY_LOOP,sm_1));
}

int do_show_member()
{
  int all, mod;
  static char uv[256];
  unsigned short ul;
  $DESCRIPTOR(ud,uv);

  all = (cli$present(c$dsc("ALL")) & 1);
  mod = ((cli$present(c$dsc("SUPERVISOR")) & 1) || (cli$present(c$dsc("MODERATOR")) & 1));
  if (!all) {
    if (!(cli$get_value(c$dsc("USERNAME"),&ud,&ul) & 1)) {
      ul = 0;
      if (mod) all = 1;
      else if (!(get_input(&ud,c$dsc("Username :"),&ul) & 1)) return(0);
      }
    uv[ul] = '\0';
    lower_case(uv);
    }
  show_members(all,mod,uv);
  return 0;
}

static int dsmoderator()
{
  int displayed = 0;
  char rl[256], il[256], ml[256], *cp;

  *ml = '\0';
  if (!curr_g) return(err_line("Show Supervisor: No current newsgroup selected"),0);

  if (ga[curr_g]->grp_flags & NEWS_M_MAILMODERATE) {
    char *ma;

    ma = moderator_address(ga[curr_g]->grp_name);
    if (ma) sprintf(ml,"APPROVAL-MODERATOR Mail_Address: %.200s",ma);
    else sprintf(ml,"APPROVAL-MODERATOR Mail_Address: <address not locally defined>");
    start_header(T_DISPLAY_LOOP,SHOW_MODERATOR);
    sprintf(err_oline,"Local Supervisors of Newsgroup %.200s",ga[curr_g]->grp_name);
    put_line(err_oline,0,T_DISPLAY_LOOP);
    put_line("",0,T_DISPLAY_LOOP);
    end_header(T_DISPLAY_LOOP);
    displayed = 1;
    put_line(ml,0,T_DISPLAY_LOOP);
    }

  sprintf(itm_fname,Access_template,util_dir(ga[curr_g]->grp_name));
  sysprv();
  if (!(fp = fopen(itm_fname,"r"))) {
    sprintf(err_oline,"Show Supervisor: Newsgroup %.200s is NOT a restricted newsgroup",ga[curr_g]->grp_name);
    err_line(err_oline);
    nosysprv();
    if (displayed) put_line("",1,T_DISPLAY_LOOP);
    return(0);
    }
  fp_open = 1;
  nosysprv();

  while (fgets(il,sizeof(il),fp)) {
    if (*il == '#') continue;
    if ((cp = strchr(il,'\n')) != 0) *cp = ' ';
    strnncpy(rl,sizeof(rl), il,-1, 0);
    lower_case(rl);
    if (   !substrcmp(rl," moderate ")
        && !substrcmp(rl," moderator ")
        && !substrcmp(rl," supervise ")) continue;
    if (!displayed) {
      start_header(T_DISPLAY_LOOP,SHOW_SUPERVISOR);
      sprintf(err_oline,"Local Supervisors of Newsgroup %.200s",ga[curr_g]->grp_name);
      put_line(err_oline,0,T_DISPLAY_LOOP);
      put_line("",0,T_DISPLAY_LOOP);
      end_header(T_DISPLAY_LOOP);
      displayed = 1;
      }
    put_line(il,0,T_DISPLAY_LOOP);
    }
  sysprv();
  fclose(fp);
  fp_open = 0;
  nosysprv();
  if (displayed) put_line("",1,T_DISPLAY_LOOP);
  else err_line("There is no local supervisor for this newsgroup");
  return(0);
}

int
do_show_moderator()
{
  return(unwind_display(I_DISPLAY_LOOP,dsmoderator));
}

int do_set_restrict(g)
  int g;
{
  int status;
  struct FAB resfab;
  struct XABPRO respro;
  int i;
  FILE *fpr;
  ITM_PTR iap;

  if (nntp_client) return(0);
  map_items(g);
  iap = ga[g]->grp_ia;
  sprintf(itm_fname,Access_template,util_dir(ga[g]->grp_name));
  sysprv();
  if ((fpr = fopen(itm_fname,"r")) != 0) {
    fclose(fpr);
    nosysprv();
    return(0);
    }
  resfab = cc$rms_fab;
  resfab.fab$b_fac = FAB$M_GET | FAB$M_PUT | FAB$M_UPD | FAB$M_DEL ;
  resfab.fab$l_fna = itm_fname;
  resfab.fab$b_fns = strlen(resfab.fab$l_fna);
  resfab.fab$l_fop = FAB$M_CIF;
  resfab.fab$w_mrs = 2000;
  resfab.fab$b_rat = FAB$M_CR;
  resfab.fab$b_rfm = FAB$C_VAR;
  resfab.fab$l_xab = (char *) &respro;

  respro = cc$rms_xabpro;
  respro.xab$w_pro = 0xEE00;
  if (sys_create(&resfab))
    sys_close(&resfab);
  else {
    nosysprv();
    err_line("Set Newsgroup/Restrict: Cannot create member file");
    return(0);
    }
  for (i = 1; i <= ga[g]->grp_count; ++i) {
    sprintf(itm_fname,Itm_template,util_dir(ga[g]->grp_name),iap[i].itm_num);
    chmod(itm_fname,0700);
    }
  nosysprv();
  err_line("Set Newsgroup/Restrict: Created new member file");
  return(1);
}

int do_set_norestrict(g)
    int g;
{
  int i;
  ITM_PTR iap;

  if (nntp_client) return(0);
  map_items(g);
  iap = ga[g]->grp_ia;
  sysprv();
  sprintf(itm_fname,Access_template,util_dir(ga[g]->grp_name));
  delete_file_versions(itm_fname);
  for (i = 1; i <= ga[g]->grp_count; ++i) {
    sprintf(itm_fname,Itm_template,util_dir(ga[g]->grp_name),iap[i].itm_num);
    chmod(itm_fname,0744);
    }
  nosysprv();
  return(0);
}

void check_access(g)
  int g;
{
  char acline[256], cknode[132], mod[132],
       *cp, *ap, *op;
  FILE *fpd;
  int mod_l;

  ga[g]->grp_flags |= NEWS_M_ACCESS_CHECKED;
  if (ga[g]->grp_flags & NEWS_M_MAILMODERATE) {
    char *ma;

    ma = moderator_address(ga[g]->grp_name);
    strnncpy(mod,sizeof(mod),       usr_username,-1, &mod_l);
    strnncat(mod,sizeof(mod),mod_l, "@",1,           &mod_l);
    strnncat(mod,sizeof(mod),mod_l, Node_address,-1, &mod_l);
    if (ma && !strcmp(mod,ma)) {
      ga[g]->grp_flags |= (NEWS_M_MOD_USER | NEWS_M_WRITE_ACCESS);
      return;
      }
    }
  if (!(ga[g]->grp_flags & NEWS_M_NOWRITE_SET))
    ga[g]->grp_flags |= NEWS_M_WRITE_ACCESS;
  sprintf(itm_fname,Access_template,util_dir(ga[g]->grp_name));
  sysprv();
  if ((fpd = fopen(itm_fname,"r")) != 0) {
    while (fgets(acline,sizeof(acline),fpd)) {
      if (*acline == '#') continue;
      if ((cp = strchr(acline,'\n')) != 0) *cp = ' ';
      lower_case(acline);
      op = chop_str(acline,':');
      cp = chop_str(acline,' ');
      ap = chop_str(acline,'@');
      if (   !strcmp(acline,usr_username)
          || wild_match(usr_username,acline)
          || idmatch(acline)) {
        if (cp) *cp = ' ';
        if (ap) *ap = '@';
        if (strchr(acline,'@')) {
          sprintf(cknode,"@%.129s ",Node_address);
          if (!substrcmp(cp,cknode)) continue;
          }
        if (substrcmp(cp," write ")) ga[g]->grp_flags |= NEWS_M_WRITE_ACCESS;
        if (substrcmp(cp," nowrite ")) ga[g]->grp_flags &= ~NEWS_M_WRITE_ACCESS;
        if (   substrcmp(cp," moderate ")
            || substrcmp(cp," moderator ")
            || substrcmp(cp," supervise "))
	  ga[g]->grp_flags |= (NEWS_M_MOD_USER | NEWS_M_WRITE_ACCESS);
        }
      }
    fclose(fpd);
    }
  nosysprv();
}

int
do_set_mod()
{
#if !NNTP_CLIENT_ONLY
  char sw[20];
  unsigned short sw_len;
  int g,count = 0;
  $DESCRIPTOR(sw_dsc,sw);

  if (nntp_client) return(0);
  if (cli$present(c$dsc("BOOL")) & 1) {
    if (cli$get_value(c$dsc("BOOL"),&sw_dsc,&sw_len) & 1) {
      sw[sw_len] = '\0';
      if (!strncmp(sw,"OF",2)) return(do_set_nomod(),0);
      }
    }
  if (cli$present(c$dsc("ALL")) & 1) {
    for (g = 1; g <= ga_size; ++g) {
      if (!(ga[g]->grp_flags & NEWS_M_ACCESS_CHECKED)) check_access(g);
      if (ga[g]->grp_flags & NEWS_M_MOD_USER) {
        ga[g]->grp_flags |= NEWS_M_MOD_ACCESS;
        ++count;
        }
      }
  } else {
    if (!(ga[curr_g]->grp_flags & NEWS_M_ACCESS_CHECKED)) check_access(curr_g);
     if (ga[curr_g]->grp_flags & NEWS_M_MOD_USER) {
      ga[curr_g]->grp_flags |= NEWS_M_MOD_ACCESS;
      ++count;
        }
  }
  if (count) {
    if (smg_active && (news_context > 1)) newsgroup_header();
    err_line("Supervisor privs enabled");
    }
  else err_line("You are not registered as a newsgroup Supervisor");
#endif
  return(0);
}

int
do_set_nomod()
{
#if !NNTP_CLIENT_ONLY
  int g;

  if (nntp_client) return(0);
  for (g = 1; g <= ga_size; ++g) ga[g]->grp_flags &= ~NEWS_M_MOD_ACCESS;
  if (smg_active && (news_context > 1)) newsgroup_header();
  err_line("Supervisor privs disabled");
#endif
  return(0);
}

static int
dse()
{
  int g,
      wild_group = 0;
  char s[132];
  unsigned short s_len;
  $DESCRIPTOR(s_dsc,s);

  cli$get_value(c$dsc("GROUP"),&s_dsc,&s_len);
  s[s_len] = '\0';
  if ((!*s) || !strcmp(s,".")) {
    if (!curr_g)
      return(err_line("Error: Show Entry - No Newsgroup specified"),0);
    else g = curr_g;
    }
  else if (!strcmp(lower_case(s),"default")) {
    g = 0;
    strcpy(s,"Default Newsgroup");
    }
  else if (strchr(s,'*') || strchr(s,'%')) {
    wild_group = 1;
    util_cvrt(s,s);
    g = 1;
    }
  else {
    util_cvrt(s,s);
    if (!(g = ga_exact_name(s))) {
      sprintf(err_oline,"Error: Show Entry - %.200s not located",s);
      err_line(err_oline);
      return(0);
      }
    }
  start_header(T_DISPLAY_LOOP,SHOW_NEWSGROUP);
  sprintf(err_oline,"Show Entry: Newsgroup %.200s",s);
  put_line(err_oline,0,T_DISPLAY_LOOP);
  put_line("",0,T_DISPLAY_LOOP);
  end_header(T_DISPLAY_LOOP);
  for (;;) {
    display_group(g);
    if (!wild_group) break;
    g++;
    while ((g <= ga_size) && !wild_match(ga[g]->grp_name,s)) ++g;
    if (g > ga_size) break;
    }
  put_line("",1,T_DISPLAY_LOOP);
  return(0);
}

int
do_show_entry()
{
  return(unwind_display(I_DISPLAY_LOOP,dse));
}

void
display_group(g)
  int g;
{
  unsigned short hold_val;
  char itemhold[132],
       hold[132], acc_fname[256],
       il[256];

  check_access(g);
  strcpy(err_oline,"Newsgroup: "); err_oline_cat(ga[g]->grp_name);
  put_line(err_oline,0,T_DISPLAY_LOOP);
  if (ga[g]->grp_topic && *(ga[g]->grp_topic)) {
    strcpy(err_oline,"Title: "); err_oline_cat(ga[g]->grp_topic);
    put_line(err_oline,0,T_DISPLAY_LOOP);
    }
  if (ga[g]->grp_notice && *(ga[g]->grp_notice)) {
    strcpy(err_oline,"Notice: "); err_oline_cat(ga[g]->grp_notice);
    put_line(err_oline,0,T_DISPLAY_LOOP);
    }
  newsgroup_status_line(g);
  fit_line(err_oline, -1, err_oline_m, -1);
  put_line(err_oline,0,T_DISPLAY_LOOP);
  put_line("",0,T_DISPLAY_LOOP);
  strcpy(err_oline,"Created:   "); err_oline_cat(gendate(ga[g]->grp_credate));
  put_line(err_oline,0,T_DISPLAY_LOOP);

  hold_val = ga[g]->grp_life;
  *itemhold = '\0';
  if (ga[g]->grp_flags & NEWS_M_NOSTORE) strcpy(itemhold,"NoHold");
  else if (ga[g]->grp_itmlife == 65535) strcpy(itemhold,"Permanent");
  else if (ga[g]->grp_itmlife) sprintf(itemhold,"%u days",ga[g]->grp_itmlife);
  *hold = '\0';
  if (ga[g]->grp_life == 65535) strcpy(hold,"Permanent");
  else if (ga[g]->grp_life) sprintf(hold,"%u days",ga[g]->grp_life);
  if ((!((*hold) && (*itemhold))) && (g)) {
    if (!*itemhold) {
      if (ga[0]->grp_itmlife == 65535) strcpy(itemhold,"Permanent (Default)");
      else if (ga[0]->grp_itmlife) sprintf(itemhold,"%u days (Default)",
                                             ga[0]->grp_itmlife);
      }
    if (!*hold) {
      if (ga[0]->grp_life == 65535) strcpy(hold,"[Permanent (Default)]");
      else if (ga[0]->grp_life) sprintf(hold,"%u days (Default)",
                                             ga[0]->grp_life);
      hold_val = ga[0]->grp_life;
      }
    }
  if (!*itemhold) sprintf(itemhold,"%u days (Default)",EXP_TIME);
  if (!*hold) {
    sprintf(hold,"%u days (Default)",GRP_TIME);
    hold_val = GRP_TIME;
    }
  strcpy(err_oline,"Retention: "); err_oline_cat(hold);
  put_line(err_oline,0,T_DISPLAY_LOOP);
  if (hold_val != 65535) {
    strcpy(err_oline,"Expires:   ");
    err_oline_cat(gendate(ga[g]->grp_entdate + (hold_val * DAY_SECS)));
    if (!ga[g]->grp_count) put_line(err_oline,0,T_DISPLAY_LOOP);
    }
  strcpy(err_oline,"Note-Retention: "); err_oline_cat(itemhold);
  put_line(err_oline,0,T_DISPLAY_LOOP);

  if (ga[g]->grp_flags & NEWS_M_IGNEXP)
    put_line("Expires: header lines Ignored - Note Retention period used forall items",0,T_DISPLAY_LOOP);

  sprintf(err_oline,"Count:     %d",ga[g]->grp_count);
  put_line(err_oline,0,T_DISPLAY_LOOP);

  if (ga[g]->grp_flags & NEWS_M_MAILLIST) {
    strcpy(err_oline,
           "MailList Enabled: Moderator is set to MailList Server address");
    put_line(err_oline,0,T_DISPLAY_LOOP);
    }
  if (ga[g]->grp_flags & NEWS_M_MAILMODERATE) {
    char *ma;

    ma = moderator_address(ga[g]->grp_name);
    strcpy(err_oline,"Moderator: Mail to - ");
    if (ma) err_oline_cat(ma);
    else err_oline_cat("<address not locally defined>");
    put_line(err_oline,0,T_DISPLAY_LOOP);
    if (ga[g]->grp_flags & NEWS_M_NOAPPROVAL) {
      strcpy(err_oline,"Moderator-Approval: Not required");
      put_line(err_oline,0,T_DISPLAY_LOOP);
      }
    else {
      strcpy(err_oline,"Moderator-Approval: Required");
      put_line(err_oline,0,T_DISPLAY_LOOP);
      }
    }

  if (ga[g]->grp_flags & NEWS_M_LOCAL)
    put_line("Status:    Locally defined Newsgroup",0,T_DISPLAY_LOOP);
  else put_line("Status:    Network Distributed Newsgroup",0,T_DISPLAY_LOOP);

  if (ga[g]->grp_flags & NEWS_M_NNTPSRV) {
    put_line("Network-Server: NNTP Server Enabled",0,T_DISPLAY_LOOP);
    strcpy(err_oline,"NNTP-Server:    ");
    err_oline_cat(ga[g]->grp_srvnode?ga[g]->grp_srvnode:"");
    put_line(err_oline,0,T_DISPLAY_LOOP);
    if (ga[g]->grp_srvproto == DECNET)
      put_line("NNTP-Transport: DECnet",0,T_DISPLAY_LOOP);
    else {
      sprintf(err_oline,"NNTP-Transport: TCP (%.20s)",
                        proto_name(ga[g]->grp_srvproto));
      put_line(err_oline,0,T_DISPLAY_LOOP);
      }
    if (!(ga[g]->grp_flags & NEWS_M_NNTPCACHE))
      put_line("NNTP-Local-Note-Cache: Disabled",0,T_DISPLAY_LOOP);
    else {
      sprintf(err_oline,"NNTP-Local-Note-Cache: %d days",ga[g]->grp_srvcache);
      put_line(err_oline,0,T_DISPLAY_LOOP);
      }
    }

  if (!(ga[g]->grp_flags & NEWS_M_WRITE_ACCESS))
    put_line("Post-Access: No POST Access to Newsgroup",0,T_DISPLAY_LOOP);
  else if (ga[g]->grp_flags & NEWS_M_NOWRITE_SET)
    put_line("Post-Access: Post Access is restricted",0,T_DISPLAY_LOOP);
  if (ga[g]->grp_flags & NEWS_M_RESTRICT_SET)
    put_line("Read-Access: Read Access is restricted to membership list",0,T_DISPLAY_LOOP);
  if (ga[g]->grp_flags & NEWS_M_MOD_USER) {
    sprintf(err_oline,"Supervisor-Access: User %.200s is Newsgroup Supervisor ",
      usr_username);
    if (ga[g]->grp_flags & NEWS_M_MOD_ACCESS) err_oline_cat("(enabled)");
    else err_oline_cat("(disabled)");
    put_line(err_oline,0,T_DISPLAY_LOOP);
    }

  sprintf(acc_fname,Access_template,util_dir(ga[g]->grp_name));
  sysprv();
  if (!(fpa = fopen(acc_fname,"r"))) {
    put_line("Access-File: None specified",0,T_DISPLAY_LOOP);
    nosysprv();
    }
  else {
    fpa_open = 1;
    nosysprv();
    put_line("Access-File: Membership list follows",0,T_DISPLAY_LOOP);
    while (fgets(il,sizeof(il),fpa)) {
      if (*il == '#') continue;
      chop_str(il,'\n');
      strcpy(err_oline,"Member: "); err_oline_cat(il);
      put_line(err_oline,0,T_DISPLAY_LOOP);
      }
    sysprv();
    fclose(fpa);
    fpa_open = 0;
    nosysprv();
    }

  if (ga[g]->grp_flags & NEWS_M_ORDERBYSUBJECT)
    put_line("Display Order:    by Subject",0,T_DISPLAY_LOOP);

  if (g) {
    list_classes(ga[g]->grp_num);
    mark_group_list(g);
    }
}

/*
 * do_cregrp
 *
 * Create a new (empty) newsgroup
 */

int
cregrp(upd_client)
  int upd_client;
{
  int inquire_sts = 0,
      since_time = 0,
      first,
      last,
      i,
      confirm;
  unsigned int g,
               cre_grp[500];
  char s[MAXQUALLEN],
       *response,
       *srvgrps,
       *modlist = 0,
       *cp1,*cp2,*cp3,*cp4,
       newsg[132],
       mod[132];

  if (no_priv()) return(err_line("Error: Create - No Priv"),0);

  if (upd_client) confirm = (cli$present(c$dsc("CONFIRM")) & 1);
  else confirm = (cli$present(c$dsc("CONFIRM")) != CLI$_NEGATED);
  
  server_call = 0;
#if !NNTP_CLIENT_ONLY
  clear_gl();
#endif
  auto_cre_grp = 1;

  if (upd_client) strcpy(s,"*");
  else parse_newsgroups(s,sizeof(s), "",0,0,1);

  if (upd_client || (inquire_sts = (cli$present(c$dsc("INQUIRE")) & 1))) {
    if (!*s) strcpy(s,"*");
    since_time = 0;
    dsc.dsc$a_pointer = tmpstr;
    /* WARNING - next two was cli$present with cli$get_value's args */
    if (cli$present(c$dsc("SINCE")) & 1)
      if (cli$get_value(c$dsc("SINCE"),&dsc,&len) & 1) {
        tmpstr[len] = '\0';
        since_time = cvt_date_val(tmpstr);
        }
    }
  else {
    if (!*s) return(0);
      do_new_group(s,confirm,cre_grp);
      if (!*cre_grp) {
        err_line("Info: Create - No newsgroup created");
        return(0);
        }
      }

  if (!get_newsgroup_params()) return(0);

  if (upd_client || inquire_sts) {
    server_sts = CLI$_PRESENT;
    moderator_sts = CLI$_ABSENT;
    if ((!*server_node) && upd_client)
      strnncpy(server_node,sizeof(server_node), ga[0]->grp_srvnode,-1, 0);
    if (!*server_node) {
      dsc.dsc$a_pointer = server_node;
      get_input_dflt(&dsc,c$dsc("SERVER Node: "), &len,
                     (ga[0]->grp_srvnode && *(ga[0]->grp_srvnode) ?
                       c$dsc(ga[0]->grp_srvnode) : 0), 0);
      if (!len) return(0);
      if (len > 131) len = 131;
      server_node[len] = '\0';
      lower_case(server_node);
      }

    if (!(protocol_sts & 1)) {
      if (upd_client) protocol_val = ga[0]->grp_srvproto;
      else {
        dsc.dsc$a_pointer = tmpstr;
        get_input_dflt(&dsc,c$dsc("Protocol: "),&len,
               (ga[0]->grp_srvproto ? c$dsc("TCP") : c$dsc("DECNET")),0);
        tmpstr[len] = '\0';
        protocol_val = name_to_proto(tmpstr,len);
        protocol_val = available_proto(protocol_val);
        }
      }
    protocol_sts = CLI$_PRESENT;
    if (!(response = server_get_newsgroups(server_node,protocol_val,since_time))) {
      strcpy(err_oline,"Create - No served newsgroups response from ");
      err_oline_cat(server_node);
      err_line(err_oline);
      return(0);
      }
    srvgrps = (char *) news_malloc(strlen(response));
    *srvgrps = '\0';
    modlist = (char *) news_malloc(strlen(response));
    *modlist = '\0';
    for (cp1=response; cp1; cp1=cp2) {
      cp2 = chop_str_plus(cp1,'\n');
      if (sscanf(cp1,"%s %d %d %s",newsg,&first,&last,mod) == 4) {
        if ( *mod != '=' && *mod != 'x') {
          for (cp3=s; cp3; cp3=cp4) {
            cp4 = chop_str(cp3,',');
            if (wild_match(newsg,cp3)) {
              if (cp4) *cp4 = ',';
              break;
              }
            if (cp4) *cp4++ = ',';
            }
          if (cp3) {
            util_cvrt(newsg,newsg);
            if (!ga_exact_name(newsg)) {
              strcat(srvgrps,newsg);
              strcat(srvgrps,",");
              if ((tolower(*mod) == 'm') || (tolower(*mod) == 'n')) {
                strcat(modlist,newsg);
                strcat(modlist,",");
                }
              }
	    }
          }
        }
      }
    if (*srvgrps) srvgrps[strlen(srvgrps) - 1] = '\0';
    if (*modlist) modlist[strlen(modlist) - 1] = '\0';
    if (!*srvgrps) {
      news_free(response);
      news_free(srvgrps);
      news_free(modlist);
      err_line("Create - No newsgroups to create");
      return(0);
      }
    first = 0;
    for (cp1=srvgrps; cp1; cp1=cp2) {
      cp2 = chop_str_plus(cp1,',');
      do_new_group(cp1,confirm,&cre_grp[first]);
      while (cre_grp[first]) first++;
      }
    news_free(response);
    news_free(srvgrps);
    if (!*cre_grp) {
      news_free(modlist);
      err_line("Create - No newsgroups to create");
      return(0);
      }
    }

  for (i = 0; (g = cre_grp[i]) != 0; ++i) {
    if (!(g = ga_locate(g))) continue;
    set_newsgroup_params(g);
    update_newsgrp(g);
    newsg_status(g);
    }

  if (modlist) {
    if (*modlist) {
      for (cp1 = modlist; cp1; cp1=cp2) {
        /* WARNING - the comma was in a string */
        cp2 = chop_str_plus(cp1,',');
        if ((g = ga_exact_name(cp1)) != 0) {
          ga[g]->grp_flags |= NEWS_M_MAILMODERATE;
          update_newsgrp(g);
          }
        }
      }
    news_free(modlist);
    }
  if (server_call) {
    verbose = 1;
#if !NNTP_CLIENT_ONLY
    server_check(1,1);
    clear_gl();
#endif
    }
#if !NNTP_CLIENT_ONLY
  noserver_skim();
#endif
  return(0);
}

int do_update_client()
{
  if (no_priv()) return(err_line("Update/Client requires NEWSMGR privs"),0);
  return(cregrp(1));
}

int do_cregrp()
{
  return(cregrp(0));
}

static int dsa_param = 0, dsa_stk;

static void dsg(g)
  int g;
{
  int l_itm, f_itm, i;
  char rl[2048], il[20];
  GRP_PTR l_ga;
  ITM_PTR l_ia;

  l_ga = ga[g];
  if ((l_ia = l_ga->grp_ia) != 0) {  
    *rl = '\0';
    if (!l_ga->grp_count) sprintf(rl," <%d",l_ga->grp_topnum);
    else if (!l_ia) sprintf(rl," <0");
    else {
      f_itm = l_itm = 0;
      for (i=1; i <= l_ga->grp_count; i++) {
        if (l_ia[i].itm_flags & NEWS_M_UNREAD) {
          l_itm = l_ia[i].itm_num - 1;
          if (!f_itm) sprintf(il," <%d",l_itm);
          else if (f_itm != l_itm) sprintf(il," |%d=%d",f_itm,l_itm);
          else sprintf(il," %d",l_itm);
          strnncat(rl,sizeof(rl),-1, il,-1, 0);
          while ((i <= l_ga->grp_count) && (l_ia[i].itm_flags & NEWS_M_UNREAD))
            ++i;
          if (i > l_ga->grp_count) { i = 0; break; }
          f_itm = l_ia[i].itm_num;
          }
        }
      if (i > l_ga->grp_count) {
        l_itm = l_ia[i-1].itm_num;
        if (!f_itm) sprintf(il," <%d\n",l_itm);
        else if (f_itm != l_itm) sprintf(il," |%d=%d\n",f_itm,l_itm);
        else sprintf(il," %d\n",l_itm);
        strnncat(rl,sizeof(rl),-1, il,-1, 0);
        }
      }
    if (l_ga->grp_reg_text) news_free(l_ga->grp_reg_text);
    l_ga->grp_reg_text = news_strdup(rl+1, -1);
    if (l_ga->grp_ia) news_free(l_ga->grp_ia);
    l_ga->grp_ia = 0;
    if (l_ga->grp_idtail) {
      while ((l_ga->grp_idtail = (l_ga->grp_idtail)->b_link))
        news_free((l_ga->grp_idtail)->f_link);
      news_free(l_ga->grp_idhead);
      l_ga->grp_idhead = 0;
      }
    l_ga->grp_flags &= ~NEWS_M_ITMIDSSET;
    if (l_ga->grp_iavdsize) smg$delete_virtual_display(&l_ga->grp_iavd);
    l_ga->grp_iavdsize = 0;
    }
  if (dsa_param >= 0) {
    l_ga->grp_flags |= NEWS_M_NONDEFDISPLAY;
    if (!dsa_param || dsa_param == 2) l_ga->grp_flags &= ~NEWS_M_UNSEENSTACK;
    else {
      l_ga->grp_flags |= NEWS_M_UNSEENSTACK;
      l_ga->grp_displaystk = dsa_stk;
      }
    if (!dsa_param || dsa_param == 1) l_ga->grp_flags &= ~NEWS_M_UNREADITEMS; 
    else l_ga->grp_flags |= NEWS_M_UNREADITEMS;
    }
  if (!l_ga->grp_count) l_ga->grp_count = 1;
}

static int dsa()
{
  int i, si = 0;
  unsigned int sf = 0;

  if ((news_context > 1) && curr_i) si = ga[curr_g]->grp_ia[curr_i].itm_num;
  set_level(1);
  if (dsa_param < 0) {
    sf = ga[curr_g]->grp_flags;
    if (dsa_param == -2) ga[curr_g]->grp_flags |= NEWS_M_ORDERBYSUBJECT;
    else ga[curr_g]->grp_flags &= ~NEWS_M_ORDERBYSUBJECT;
    }
  dsg(curr_g);
  set_level(2);
  if (dsa_param < 0) ga[curr_g]->grp_flags = sf;
  if (si && ga[curr_g]->grp_ia) {
    find_itm_by_num(curr_g,si,&i);
    cur_set_itm(curr_g,i);
    }
  return(0);
}

int do_show_allitems()
{
  if (!curr_g) return(0);
  if (ga[curr_g]->grp_flags & NEWS_M_MAILGROUP) return(0);
  dsa_param = 0;
  return(unwind_display(OUTER_LOOP,dsa));
}  

int do_show_unseenstack()
{
  dsa_stk = 0;
  if (!curr_g) return(0);
  if (cli$get_value(c$dsc("PLUSMORE"),&dsc,&len) & 1) {
    tmpstr[len] = '\0';
    if (sscanf(tmpstr,"%d",&dsa_stk) != 1) dsa_stk = 0;
    }
  if (ga[curr_g]->grp_flags & NEWS_M_MAILGROUP) return(0);
  dsa_param =  1;
  return(unwind_display(OUTER_LOOP,dsa));
}  

int do_show_unreaditems()
{
  if (!curr_g) return(0);
  if (ga[curr_g]->grp_flags & NEWS_M_MAILGROUP) return(0);
  dsa_param = 2;
  return(unwind_display(OUTER_LOOP,dsa));
}  

static int dsag()
{
  int g;

  if (dsa_param < 0) {
    dsa();
    return(0);
    }

  for (g = 1; g <= ga_size; ++g) {
    if (ga[curr_g]->grp_flags & NEWS_M_MAILGROUP) continue;
    if (g == curr_g) dsa();
    else dsg(g);
    }
  return(0);
}

int do_set_display_type(dsap,dsastk)
  int dsap, dsastk;
{
  dsa_stk = dsastk;
  if (dsap > 2) dsap = 0;
  dsa_param = dsap;
  return(unwind_display(OUTER_LOOP,dsag));
}
