/*
**++
**  FACILITY:
**      NEWSSITE
**
**  ABSTRACT:
**      This module contains two areas of functionality: firstly startup
**      code which checks for the existence of various logical names before
**      linking to the local news database, and secondly the filters which
**      implement the local and remote news item acceptance conditions.
**
**  AUTHOR:
**      Geoff Huston
**
**  COPYRIGHT:
**      Copyright © 1988,1989,1990
**
**  VERSION:
**	V6.0-4	25-May-1991	volz@process.com
**	  - Added TCPware support
**	V6.1B6	 9-Mar-1993	Pat Rankin, rankin@eql.caltech.edu
**	  - Fix two personal name problems reported by David Bellamy
**		<bellamy@commerce.uq.edu.au>; also clean up some lint.
**	V6.1b7	31-Aug-1993	Charles Bailey  bailey@genetics.upenn.edu
**	  - change no_priv() to try $GetJPI or $Find_Held based on VMS
**	    version, rather than requiring compile-time decision
**	V6.1b8  22-Dec-1993	mark.martinec@ijs.si
**	  - convert calls to RMS to use new sys_* macros for error handling 
**	V6.1b10 09-DEC-1996	Mark Pizzolato	mark@infocomm.com
**	  - added the compiler used to the output displayed by SHOW VERSION.
**	V6.1b11 14-Apr-1997	Mark Martinec   mark.martinec@ijs.si
**	  - replace several calls to strcpy/strcat with safer strnncpy/strnncat
**	  - partially fix dsformatline() to handle narrow displays
**	V6.2 18-JUN-1997	Mark Pizzolato	mark@infocomm.com
**	  - added GRPNAMELEN_F to the output displayed by SHOW VERSION.
**--
**/

#ifdef vaxc
#module NEWSSITE "V6.2"
#endif

#define _NEWSSITE_C
#define module_name "NEWSSITE"

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

#if NAKED_INCLUDES
#include syidef
#include uaidef
#include jpidef
#else
#include <syidef.h>
#include <uaidef.h>
#include <jpidef.h>
#endif

#ifndef UAI$V_RESTRICTED

#ifdef UAI$V_CAPTIVE
#undef UAI$V_CAPTIVE
#endif
#ifdef UAI$M_CAPTIVE
#undef UAI$M_CAPTIVE
#endif
#ifdef UAI$M_RESTRICTED
#undef UAI$M_RESTRICTED
#endif

#define UAI$V_RESTRICTED 3
#define UAI$V_CAPTIVE    16
#define UAI$M_RESTRICTED (1<<UAI$V_RESTRICTED)	/* 8 */
#define UAI$M_CAPTIVE	 (1<<UAI$V_CAPTIVE)	/* 65536 */
#endif

#define MAIL_DAT_NAME     "VMSMAIL"
#define MAIL_DAT_DEFAULT  "SYS$SYSTEM:.DAT"

int held_ids[100];

static int mgr_priv = -1,
           post_priv = -1,
           post_id,
           nopost_id;

static char mgrid[256],
            version[11];

static struct itv {
    short bl;
    short code;
    char *ba;
    unsigned short *rl;
    } ver_item[]= {{10,SYI$_VERSION,(char *) &version,0}, {0,0,0,0}};


/*
 *  site_get_env
 *
 * read site specific logical name values
 */
int site_get_env()
{
  char *p, *cp,
       *gotenv,
       prefix[] = "SYS$SCRATCH";
  unsigned short len;
  struct crelnm_record {
        short bl;
        short ic;
        char *ba;
        unsigned short *rl;
        int enditm;
        } scritm;
  int no_logicals = 0;
 
  sys$getsyiw(0,0,0,ver_item,0,0,0);
  sscanf(version,"V%d.%d",&vms_major,&vms_minor);
  strnncpy(VMS_VERS,VMS_VERS_m, version,-1, 0);
  if ((p = strchr(VMS_VERS,' ')) != 0)
    *p = '\0';
  else
    VMS_VERS[10] = '\0';
  sprintf(Post_file,"SYS$SCRATCH:POST_NEWS_%X.TMP",getpid());
  sprintf(Mail_file,"SYS$SCRATCH:MAIL_NEWS_%X.TMP",getpid());
  if ( (gotenv = news_getenv("SYS$LOGIN",0)) )
    strnncpy(Extract_file,Extract_file_m, gotenv,-1, 0);
  else {
    *Extract_file = '\0';
    report_sys_error_routine(NEWS$_NOLOGNAM,(int)(c$dsc("SYS$LOGIN")),0,0,0);
    exit(1);
    }
  if ( (cp = strrchr(Extract_file,']')) ) strcpy(cp,".NEWS-EXTRACTS]");

  *print_constant = '\0';
  if (!news_getenv(prefix,0)) {           /* sys$scratch not defined... */
    strcpy(prefix,"SYS$LOGIN");
    if (!(gotenv = news_getenv(prefix,0))) {
      report_sys_error_routine(NEWS$_NOLOGNAM,(int)(c$dsc("SYS$SCRATCH")),0,0,0);
      exit(1);
      }
    scritm.bl = strlen(gotenv);       /* define it as sys$login (job lnt) */
    scritm.ic = LNM$_STRING;
    scritm.ba = (char *) gotenv;
    scritm.rl = &len;
    scritm.enditm = 0;
    c$cks(sys$crelnm(0,c$dsc("LNM$JOB"),c$dsc("SYS$SCRATCH"),0,&scritm));
    }

  no_logicals = !news_getenv("NEWS_ROOT",1);

  if (!no_logicals) {
    if (!news_getenv("NEWS_DEVICE",1)) {
      report_sys_error_routine(NEWS$_NOSECLOGNAM,(int)(c$dsc("NEWS_DEVICE")),0,0,0);
      exit(1);
      }
    }

  if (!(gotenv = news_getenv("NEWS_MANAGER",1))) {
    if (!no_logicals) {
      report_sys_error_routine(NEWS$_NOSECLOGNAM,(int)(c$dsc("NEWS_MANAGER")),0,0,0);
      exit(1);
      }
    else *newsmgr_dir = '\0';
    }
  else {
    strnncpy(newsmgr_dir,newsmgr_dir_m, gotenv,-1, 0);
    }

  init_names();  /* set up site name, address, Path: name */

  init_tz();     /* set up timezone and GMT offset */

  if (!(gotenv = news_getenv("NEWS_EDIT",0))) *Editor = '\0';
  else lower_case(strnncpy(Editor,Editor_m, gotenv,-1, 0));
  if (!strcmp(Editor,"callable_tpu")) *Editor = '\0';
  else if (!strcmp(Editor,"callable_edt"))
    strnncpy(Editor,Editor_m, "edt",3, 0);

  if (!(gotenv = news_getenv("NEWS_VIEW",0))) *Viewer = '\0';
  else lower_case(strnncpy(Viewer,Viewer_m, gotenv,-1, 0));
  if (!strcmp(Viewer,"callable_tpu")) *Viewer = '\0';
  else if (!strcmp(Viewer,"callable_edt"))
    strnncpy(Viewer,Viewer_m, "edt",3, 0);

  gotenv = news_getenv("NEWS_ORGANISATION",0);
  if (!gotenv) gotenv = news_getenv("NEWS_ORGANIZATION",0);
  if (gotenv) strnncpy(Organisation_name,Organisation_name_m, gotenv,-1, 0);
  else *Organisation_name = '\0';

  if (news_readonly) *mgrid = '\0';
  else {
    if ( (gotenv = news_getenv("NEWS_MGR_ID",1)) )
      strnncpy(mgrid,sizeof(mgrid), gotenv,-1, 0);
    else *mgrid = '\0';
    }

  nopost_id = 0;
  if ( (gotenv = news_getenv("NEWS_NONETPOST",1)) ) {
    if (!(sys$asctoid(c$dsc(gotenv),&nopost_id,0) & 1)) nopost_id = -1;
    }

  post_id = 0;
  if ( (gotenv = news_getenv("NEWS_NETPOST",1)) ) {
    if (!(sys$asctoid(c$dsc(gotenv),&post_id,0) & 1)) post_id = -1;
    }

  cuserid(usr_username);

#if ALLOW_USER_FROM
  if      ( (gotenv = news_getenv("NEWS_FROM",0)) )
    strnncpy(mail_sig,mail_sig_m, gotenv,-1, 0);
  else if ( (gotenv = news_getenv("PMDF_FROM",0)) )
    strnncpy(mail_sig,mail_sig_m, gotenv,-1, 0);
  else
#endif

    {
    strcpy(mail_sig,usr_username);
    lower_case(mail_sig);
    }
  if (!strchr(mail_sig,'@')) {
    int ll;
    strnncat(mail_sig,mail_sig_m,-1, "@",1, &ll);
    strnncat(mail_sig,mail_sig_m,ll, Node_address,-1, 0);
    }

  *usr_persname = '\0';
  mail_flags = 0;
  *mail_queue = '\0';
  *mail_form = '\0';
  *mail_editor = '\0';
  if (vms_major > 4) call_mail_profile();   
  else get_v4mailprofile();
  gotenv = news_getenv("NEWS_PERSONALNAME",0);
  if (!gotenv) gotenv = news_getenv("NEWS_PERSONAL_NAME",0);
  if (gotenv) strnncpy(usr_persname,usr_persname_m, gotenv,-1, 0);
  get_uaf_entry(usr_username);
  lower_case(usr_username);
  return(no_logicals);
}

/*
 * If we have a version of C that does not include the JPI$_RIGHTSLIST
 * item, we need to define it here.
 */
#ifndef JPI$_RIGHTSLIST
#define JPI$_RIGHTSLIST 806  /* from VAXC 3.2 jpidef.h */
#endif

/*
 *  no_priv
 *
 *  Return 1 if the user is not an authorised news manager - check the
 *  list of held identifiers 
 *
 *  (Use $GetJPI if we're running VMS 5.4 or later; if we're
 *  runing an older version of VMS, use $Find_Held)
 *  31-Aug-1993 Charles Bailey  bailey@genetics.upenn.edu
 */

int no_priv()
{
  int mgr_id, mem_sysprv;
  int id = 0, contxt = 0, lstatus, idindx;
  unsigned int holder[2];
  struct id_attr {
     unsigned long identifier ;
     unsigned long attributes ;
     } ;
  struct id_attr held_id_attr[99] ;
  /* Length of binary rights list array, in bytes */
  unsigned short jpi_return_length ;
  struct item_list {
    unsigned short buffer_length ;
    unsigned short item_code ;
    void *buffer_address ;
    unsigned short *return_length_address ;
    unsigned long terminator ;
    } jpi_item_list = {sizeof (held_id_attr), JPI$_RIGHTSLIST,
                       (void *) held_id_attr, &jpi_return_length, 0};

  if (mgr_priv != -1) return(mgr_priv);
  if ((mem_sysprv = sysprv_off) != 0) sysprv();
  if (!*mgrid) mgr_id = -1;
  else if (!(sys$asctoid(c$dsc(mgrid),&mgr_id,0) & 1)) mgr_id = -1;
  mgr_priv = 1;

  /*
   * SYS$FIND_HELD looks up the RIGHTSLIST database for identifiers held.
   * What is more relevant is the list of rights identifiers currently held by
   * the process, which can be obtained using the JPI$_RIGHTSLIST item of the
   * SYS$GETJPI system call.
   */
  if ((vms_major > 5) || ((vms_major == 5) && (vms_minor >= 4))) {
    if (sys$getjpiw (0,0,0,&jpi_item_list,0,0,0) & 1) {
      int ident_count = jpi_return_length / sizeof (struct id_attr);
      held_ids[ident_count] = 0;
      while (--ident_count >= 0) {
        held_ids[ident_count] = held_id_attr[ident_count].identifier;
        if (held_ids[ident_count] == mgr_id) mgr_priv = 0;
        }
      }
    }
  else {
    holder[0] = (getgid() << 16) | getuid();
    holder[1] = 0;
    idindx = 0;
    while ((lstatus = sys$find_held(holder,&id,0,&contxt)) & 1) {
      held_ids[idindx++] = id;
      if (id == mgr_id) mgr_priv = 0;
      }
    held_ids[idindx] = 0;
    sys$finish_rdb(&contxt);
  }
  if (mem_sysprv) nosysprv();
  return(mgr_priv);
}

/*
 *  set_manager
 *  set_nomanager
 *
 *  Set the manager privs either on or off - Default on startup
 *  is ON if the user is an authorized manager.
 */

int
do_set_nomanager()
{
#if !NNTP_CLIENT_ONLY
  if (!nntp_client) {
    if (no_priv()) err_line("Set NoManager: NEWSmanager was not enabled");
    else {
      mgr_priv = 1;
      post_priv = -1;
      err_line("Set NoManager: NEWSmanager disabled");
      if (smg_active && (news_context > 1)) newsgroup_header();
      return(unwind_display(OUTER_LOOP,do_update_1));
      }
    }
#endif
  return(0);
}

int do_set_manager()
{
#if !NNTP_CLIENT_ONLY
  char sw[20];
  unsigned short sw_len;
  $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_nomanager(),0);
      }
    }
  if (!mgr_priv) err_line("Set Manager: NEWSmanager already enabled");
  else {
    mgr_priv = -1;
    if (no_priv()) err_line("Set Manager: No priv for attempted operation");
    else {
      err_line("Set Manager: NEWSmanager enabled");
      if (smg_active && (news_context > 1)) newsgroup_header();
      return(unwind_display(OUTER_LOOP,do_update_1));
      }
    }
#endif
  return(0);
}

int idmatch(identifier)
  char *identifier;
{
  int try_id, i;

  s_to_upper(identifier);
  if (!(sys$asctoid(c$dsc(identifier),&try_id,0) & 1)) return(0);
  for (i=0; held_ids[i]; i++) {
    if (held_ids[i] == try_id) return(1);
    }
  return(0);
}

/*
 *  nout_priv
 *
 *  Return 1 if the user is not authorised to post to net newsgroups
 */

int nout_priv()
{
  if (post_priv != -1) return(post_priv);
  if (!(post_id || nopost_id)) return(post_priv = 0);
  if (no_priv()) {
    int i;
    for (i=0; held_ids[i]; i++) {
      if (held_ids[i] == post_id) return(post_priv = 0);
      if (held_ids[i] == nopost_id) post_priv = 1;
      }
    if (post_priv == -1) {
      if (post_id) post_priv = 1;
      else post_priv = 0;
      }
    }
  else post_priv = 0;
  return(post_priv);
}

void
add_keys(arg,val,val_m)
    char *arg, *val;
    int val_m;  /* sizeof(val) */
{
  char *cp1, *cp2, cmpval[132];

  strcpy(cmpval,"*,");
  for (cp1=arg; cp1; cp1=cp2) {
    if ((cp2 = strchr(cp1,',')) != 0) *cp2++ = '\0';
    if (!*cp1) continue;
    strcpy(&cmpval[2],cp1);
    strnncat(cmpval,sizeof(cmpval),-1, ",*",2, 0);
    if (!wild_match(val,cmpval)) {
      strnncat(val,val_m,-1, cp1,-1, 0);
      strnncat(val,val_m,-1, ",",1,  0);
      }
    }
}

void get_post_defaults(groups,cur_dist,cur_follow)
  char *groups, *cur_dist, *cur_follow;
{
  char input_line[512], hkey[256], arg[256];
  char *buf, *locgrp, *locdst, *locfol,
       *cp, *cp1, *cp2;
  int locgrp_m, locdst_m, locfol_m;  /* sizeof */
  int locgrp_l, locdst_l, locfol_l;  /* strlen */
  int skp = 0, dd = 1, df = 1;
  FILE *fpr;

  locgrp_m = (*groups ? strlen(groups) : 0) + 512;
  locgrp = (char *) news_malloc(locgrp_m); locgrp_l = 0;
  locdst_m = (*cur_dist ? strlen(cur_dist) : 0) + 512;
  locdst = (char *) news_malloc(locdst_m); locdst_l = 0;
  locfol_m = (*cur_follow ? strlen(cur_follow) : 0) + 512;
  locfol = (char *) news_malloc(locfol_m); locfol_l = 0;
  strnncpy(locgrp,locgrp_m, ",",1,     &locgrp_l);
  strnncpy(locdst,locdst_m, locgrp,-1, &locdst_l);
  strnncpy(locfol,locfol_m, locgrp,-1, &locfol_l);
  strnncat(locdst,locdst_m,locdst_l, cur_dist,-1,   &locdst_l);
  strnncat(locfol,locfol_m,locfol_l, cur_follow,-1, &locfol_l);
  if (*cur_dist) {
    strnncat(locdst,locdst_m,locdst_l, locgrp,locgrp_l, &locdst_l);
    dd = 0;
    }
  if (*cur_follow) {
    strnncat(locfol,locfol_m,locfol_l, locgrp,locgrp_l, &locfol_l);
    df = 0;
    }
  strnncat(locgrp,locgrp_m,locgrp_l, groups,-1, &locgrp_l);
  strnncat(locgrp,locgrp_m,locgrp_l, ",",1,     &locgrp_l);

  sysprv();
  if (!(fpr = fopen("NEWS_MANAGER:NEWS_POST.DEFAULTS","r"))) {
    nosysprv();
    return;
    }
  strcpy(input_line,"*,");
  buf = &input_line[2];
  while (skp || fgets(buf,500,fpr)) {
    skp = 0;
    if (*buf == '#') continue;
    if ((cp = strchr(buf,'\n')) != 0) *cp = '\0';
    if (isspace(*buf)) continue;
    lower_case(buf);
    if ((!strcmp(buf,"default")) ||
        ((strcat(buf,",*"), (wild_match(locgrp,input_line))))) {

                /* find out which newsgroups caused the successful match
                   and remove them from locgrp */

      char newloc[512], defdist[256], deffol[256];
      int  newloc_l,    defdist_l,    deffol_l;

      *defdist = *deffol = '\0';
      defdist_l = deffol_l = 0;
      if (!strcmp(buf,"default")) strcpy(buf,"*");
      else buf[strlen(buf) - 2] = '\0';
      strnncpy(newloc,sizeof(newloc), ",",1, &newloc_l);
      locgrp[--locgrp_l] = '\0';
      for (cp= &locgrp[1]; cp; cp=cp1) {
        if ((cp1 = strchr(cp,',')) != 0) *cp1++ = '\0';
        if (!wild_match(cp,buf)) {
          strnncat(newloc,sizeof(newloc),newloc_l, cp,-1, &newloc_l);
          strnncat(newloc,sizeof(newloc),newloc_l, ",",1, &newloc_l);
          }
        else {
          if (*deffol)
            strnncat(deffol,sizeof(deffol),deffol_l, ",",1, &deffol_l);
          strnncat(deffol,sizeof(deffol),deffol_l, cp,-1, &deffol_l);
          if ((cp2 = strchr(cp,'.')) != 0) *cp2 = '\0';
          if (*defdist)
            strnncat(defdist,sizeof(defdist),defdist_l, ",",1, &defdist_l);
          strnncat(defdist,sizeof(defdist),defdist_l, cp,-1, &defdist_l);
          }
        }
      if (strcmp(newloc,",")) strnncpy(locgrp,locgrp_m, newloc,-1, 0);
      else *locgrp = '\0';

                /* now read in the default header values */

      skp = 1;
      while (fgets(buf,500,fpr)) {
        if (*buf == '#') continue;
        if ((cp = strchr(buf,'\n')) != 0) *cp = '\0';
        if (!isspace(*buf)) break;
        lower_case(buf);
        if (sscanf(buf," %s %s",hkey,arg) == 2) {
          if (!strcmp(hkey,"distribution:")) {
            add_keys(arg,locdst,locdst_m);
            *defdist = '\0'; defdist_l = 0;
            dd = 0;
            }
          else if (!strcmp(hkey,"followup-to:")) {
            add_keys(arg,locfol,locfol_m);
            *deffol = '\0'; deffol_l = 0;
            df = 0;
            }
          }
        }
      if (*defdist) add_keys(defdist,locdst,locdst_m);
      if (*deffol) add_keys(deffol,locfol,locfol_m);
      if (!*locgrp) break;
      }
    }
  fclose(fpr);
  nosysprv();
  news_free(locgrp);
  if (!dd) {
    strcpy(cur_dist,&locdst[1]);
    if (cur_dist[skp = (strlen(cur_dist)-1)] == ',') cur_dist[skp] = '\0';
    }
  news_free(locdst);
  if (!df) {
    strcpy(cur_follow,&locfol[1]);
    if (cur_follow[skp = (strlen(cur_follow)-1)] == ',') cur_follow[skp] = '\0';
    }
  news_free(locfol);
  return;
}

/*
 *  first_time
 *
 *  First time code - print out license message
 */

void first_time()
{
}

void
get_v4mailprofile()
{
  int status;
  struct FAB vmsmail_fab;
  struct RAB vmsmail_rab;
  unsigned char mail_data_area[1000], *p;

  vmsmail_fab = cc$rms_fab;
  vmsmail_fab.fab$b_fac = FAB$M_GET;
  vmsmail_fab.fab$l_fna = (char *) MAIL_DAT_NAME;
  vmsmail_fab.fab$b_fns = strlen(vmsmail_fab.fab$l_fna);
  vmsmail_fab.fab$l_dna = (char *) MAIL_DAT_DEFAULT;
  vmsmail_fab.fab$b_dns = strlen(vmsmail_fab.fab$l_dna);
  vmsmail_fab.fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET | FAB$M_SHRDEL | FAB$M_SHRUPD;

  vmsmail_rab = cc$rms_rab;
  vmsmail_rab.rab$l_fab = &vmsmail_fab;
  vmsmail_rab.rab$l_rop = RAB$M_NLK | RAB$M_RRL;
  vmsmail_rab.rab$b_krf = 0;
  vmsmail_rab.rab$l_kbf = usr_username;
  vmsmail_rab.rab$b_ksz = strlen(usr_username);
  vmsmail_rab.rab$b_rac = RAB$C_KEY;
  vmsmail_rab.rab$l_ubf = (char *) mail_data_area;
  vmsmail_rab.rab$w_usz = sizeof mail_data_area;

  sysprv();
  if (sys_open_nofnf(&vmsmail_fab)) {
    sys_connect(&vmsmail_rab);
    if sys_get_nornf(&vmsmail_rab) {
      p = &mail_data_area[68];
      if (mail_data_area[67]) p += mail_data_area[67];
      if (mail_data_area[66]) {
        strncpy(usr_persname,(char *)p,mail_data_area[66]);
        usr_persname[mail_data_area[66]] = '\0';
        }
      }
    sys_close(&vmsmail_fab);
    }
  nosysprv();
}

/* commented out for the moment - all that is used for the moment in the
   captive flag - and the getjpi service is faster in this instance

	static int uaf_valid = 0;
	static unsigned int uaf_flags;

	static struct item_list {  
                short bl;
                short ic;
                char *ba;
                short *rl;
                }
	    getuai_itmlist[] = {
	        {  4, UAI$_FLAGS, &uaf_flags, 0},
	        {  0, 0, 0, 0}};

	int get_uaf_entry(username)
	  char *username;
	{
	  char loc_username[13];
	  int i;

	  for (i = 0; username[i] && (i < 12) ; ++i)
	    loc_username[i] = toupper(username[i]);
	  for ( ; i < 12 ; ++i) loc_username[i] = ' ';
	  loc_username[i] = '\0';

	  if (!(sys$getuai(0,0,c$dsc(loc_username),getuai_itmlist,0,0,0) & 1)) return(0);
	  uaf_valid = 1;
	  return(1);
	}

	captive_account()
	{
	  if (uaf_valid && (uaf_flags & (UAI$M_CAPTIVE | UAI$M_RESTRICTED))) return(1);
	  return(0);
	}
end of commented section */

/* alternate code ... */

int get_uaf_entry(username)
    char *username;
{
    return(1);
}
 
/*
 * captive_account
 *
 * determine if the account is captive or not.
 * Altered 1/8/90 to use restricted or captive flags
 */

int captive_account()
{
  static int captive_flag = -1;
  static int uaf_flags;
  static struct
    {
      short   len;                    /* buffer length */
      short   item_code;              /* information item requested */
      char    *buf;                   /* return buffer */
      int     *rlen;                  /* return length */
      int     endoflist;
    } jpi_itemlist  = {4,JPI$_UAF_FLAGS,(char *) &uaf_flags,(int *) 0,0};

  if (captive_flag != -1) return(captive_flag); 
  if (sys$getjpiw(0,0,0,&jpi_itemlist,0,0,0) & 1) {
    return(captive_flag = ((uaf_flags & (UAI$M_CAPTIVE | UAI$M_RESTRICTED)) ? 1 : 0));
    }
  return(0);
}

static
struct mai_itmlst null_list[] = {{0,0,0,0}};

static
unsigned int   forwarding_len,
               form_len,
               full_directory_len,
               personal_name_len,
               queue_len,
               sub_directory_len;

static
int autopurge,
    captive,
    cc_prompt,
    copy_forward,
    copy_reply,
    copy_send;

static
char forwarding[127+1],
     form[127+1],
     full_directory[255+1],
     personal_name[127+1],
     queue[127+1],
     sub_directory[255+1];

static
short new_messages;

static
struct mai_itmlst
  user_profile_list[] ={{sizeof autopurge,	    MAIL$_USER_AUTO_PURGE,
			 &autopurge,0},
			{sizeof cc_prompt,	    MAIL$_USER_CC_PROMPT,
			 &cc_prompt,0},
			{sizeof copy_forward,	    MAIL$_USER_COPY_FORWARD,
			 &copy_forward,0},
			{sizeof copy_reply,	    MAIL$_USER_COPY_REPLY,
			 &copy_reply,0},
			{sizeof copy_send,	    MAIL$_USER_COPY_SEND,
			 &copy_send,0},
			{sizeof forwarding - 1,	    MAIL$_USER_FORWARDING,
			 forwarding,&forwarding_len},
			{sizeof form - 1,	    MAIL$_USER_FORM,
			 form,&form_len},
			{sizeof full_directory - 1, MAIL$_USER_FULL_DIRECTORY,
			 full_directory,&full_directory_len},
			{sizeof new_messages,	    MAIL$_USER_NEW_MESSAGES,
			 &new_messages,0},
			{sizeof personal_name - 1,  MAIL$_USER_PERSONAL_NAME,
			 personal_name,&personal_name_len},
			{sizeof queue - 1,	    MAIL$_USER_QUEUE,
			 queue,&queue_len},
			{sizeof sub_directory - 1,  MAIL$_USER_SUB_DIRECTORY,
			 sub_directory,&sub_directory_len},
			{0,0,0,0}};

int call_mail_profile()
{
  int context = 0,
      status;

  /* explicitly [re]init static variables */
  autopurge = captive = cc_prompt = copy_forward = copy_reply = copy_send = 0;
  forwarding_len = form_len = full_directory_len = 0;
  personal_name_len = queue_len = sub_directory_len = 0;

  sysprv();
  if ((status = mail$user_begin(&context,null_list,null_list)) & 1) {
    status = mail$user_get_info(&context,null_list,user_profile_list);
    forwarding[forwarding_len] = '\0';
    form[form_len] = '\0';
    full_directory[full_directory_len] = '\0';
    personal_name[personal_name_len] = '\0';
    strnncpy(usr_persname,usr_persname_m, personal_name,personal_name_len, 0);
    queue[queue_len] = '\0';
    sub_directory[sub_directory_len] = '\0';
    }
  mail$user_end(&context,null_list,null_list);
  nosysprv();
  return(status & 1);
}

static struct pdesc
    {
    const char *pname;
    int  pvalue;
    const char *pdescr;
    } params[] =
    {
#ifdef CMU
    {"CMU", CMU, 
        "CMU IP networking"},
#endif
#ifdef UCXSOCKETS
    {"UCXSOCKETS", UCXSOCKETS, 
        "UCX IP networking (socket drivers)"},
#endif
#ifdef UCXQIOS
    {"UCXQIOS", UCXQIOS, 
        "UCX IP networking (qio drivers)"},
#endif
#ifdef MULTINET
    {"MULTINET", MULTINET, 
        "Multinet IP networking"},
#endif
#ifdef TCPWARE
    {"TCPWARE", TCPWARE, 
        "TCPware IP networking"},
#endif
#ifdef TWG
    {"TWG", TWG, 
        "TWG IP networking"},
#endif
#ifdef EXOS
    {"EXOS", EXOS, 
        "EXOS TCP/IP networking"},
#endif
    {"EXP_TIME", EXP_TIME, 
        "News item lifetime (in days); global default"},
    {"GRP_TIME", GRP_TIME, 
        "Newsgroup lifetime (in days); global default"},
    {"GRPNAMELEN_F", GRPNAMELEN_F, 
        "Newsgroup name length in the GROUPS file"},
    {"NEWS_BATCH_SIZE", NEWS_BATCH_SIZE, 
        "Maximum size of news batch files (in bytes - not blocks); global default"},
    {"RECHECK_TIMER", RECHECK_TIMER, 
        "Configuration file periodic recheck interval (in seconds)"},
    {"SELF_PATH_CHECK", SELF_PATH_CHECK, 
        "Path: header check for local site determines acceptance of inbound articles"},
    {"DIST_PATH_CHECK", DIST_PATH_CHECK, 
        "Path: header check for neighbor sites determines forwarding to that site"},
    {"CANCELMAIL", CANCELMAIL, 
        "USENET Mail notification for all Cancel Control message processing"},
    {"UNKCONTROLMAIL", UNKCONTROLMAIL, 
        "USENET Mail notification for all Unknown Control Messages"},
    {"JUNKNODOT", JUNKNODOT, 
        "Incoming Postings to groups without '.' (dots) will be junked"},
    {"DISTFILE", DISTFILE, 
        "news.sys vs news.distribution interpretation for down stream article flow"},
    {"UNAPPROVED_NEWS", UNAPPROVED_NEWS, 
        "What to do with unapproved incoming postings to moderated newsgroups, 0 - Disgard, 1 - Accept, 2 - Mail to Moderator"},
    {"MIN_DAYS", MIN_DAYS, 
        "Smallest number of days for item retention"},
    {"MAX_DAYS", MAX_DAYS, 
        "Largest number of days for item retention"},
    {"ITMLIFE_DEFAULTS", ITMLIFE_DEFAULTS, 
        "If non zero, restricts item lifetimes to a maximum of the newsgroup default retention period"},
    {"STARTLINE", STARTLINE, 
        "If non zero, implies the command line will provide the first command of the news session"},
    {"NEWS_INIT", NEWS_INIT, 
        "If non zero, do commands in NEWS_INIT or sys$login:news.init at startup"},
    {"DEBUG", DEBUG, 
        "Verbose reporting of NEWS ADD FILE processing activities"},
    {"MAX_UNK", MAX_UNK, 
        "Maximum number of article headers of the unknown type"},
    {"ADDFILE_STATISTICS_ENABLE", ADDFILE_STATISTICS_ENABLE,
        "If 1, compile the code to collect and report statistics during ADD FILE processing"},
    {"ADDFILE_NEWSGROUPS_SIZE_LIMIT", ADDFILE_NEWSGROUPS_SIZE_LIMIT,
        "Maximum size of 'Newsgroups:' list size accepted by ADD FILE (0 = no limit)"},
    {"ADDFILE_NEWSGROUPS_CROSSPOSTING_LIMIT", ADDFILE_NEWSGROUPS_CROSSPOSTING_LIMIT,
        "Maximum number of 'Newsgroups:' list elements accepted by ADD FILE (0 = no limit)"},
    {"FULL_DIRECTORY_ACCESS_CHECK", FULL_DIRECTORY_ACCESS_CHECK, 
        "If 1, each newsgroup directory is checked at news startup determining read accessability"},
    {"DIRECTORY_ACCESS_CHECK", DIRECTORY_ACCESS_CHECK, 
        "If 1, only newsgroups that are RESTRICTED will be checked for accessability"},
    {"NOALLOW_USER_FROM", NOALLOW_USER_FROM, 
        "Whether users can alias their from address on locally generated postings"},
    {"NNTP_CACHE", NNTP_CACHE, 
        "Cache control value"},
    {"NEWGROUP_REG", NEWGROUP_REG, 
        "Default action to take with newly created newsgroups, 1 - register, 0 - don't register"},
    {"CONFIRM_NEW_GROUPS", CONFIRM_NEW_GROUPS, 
        "Confirmation of newgroup registration default action"},
    {"NNTP_USE_XOVER", NNTP_USE_XOVER, 
        "Support for NNTP use of the ANU-NEWS extension for the 'xover' command"},
    {"NNTP_USE_XHDR", NNTP_USE_XHDR, 
        "Support for NNTP use of the ANU-NEWS extension for the 'xhdr' command"},
    {"NNTP_USE_XUPDGROUP", NNTP_USE_XUPDGROUP, 
        "Support for NNTP use of the ANU-NEWS extension for the 'xupdgroup' command"},
    {"NNTP_USE_XGTITLE", NNTP_USE_XGTITLE, 
        "Support for NNTP use of the ANU-NEWS extension for the 'xgtitle' command"},
    {"NNTP_USE_XGNOTICE", NNTP_USE_XGNOTICE, 
        "Support for NNTP use of the ANU-NEWS extension for the 'xgnotice' command"},
    {"DISPLAY_BY_NEWSGROUPS", DISPLAY_BY_NEWSGROUPS, 
        "Break and display newsgroup directory whenever newsgroup is changed"},
    {"STRIP_ERR_LINES", STRIP_ERR_LINES, 
        "Strip error message facility prefixes"},
    {"MENU_SUPPORT", MENU_SUPPORT, 
        "Waikato Menu support"},
    {"ARBITRON", ARBITRON, 
        "Record dates for each newsgroup that is read for Arbitron reports"},
    {"FAST_LOAD", FAST_LOAD, 
        "Fast Startup support included"},
    {"UWO", UWO, 
        "UWO/Mail support for VMS"},
    {"NOTE_RANGE_MAX", NOTE_RANGE_MAX, 
        "Number of slots available for notes ranges"},
    {NULL, 0, NULL}, /* List End */
    };

static void dsformatline(fmt, name, value, descrip)
  const char *fmt;
  const char *name;
  const char *value;
  const char *descrip;
{
  int fixed_part_len, offset = 0, i;
  static int wid = 0;
  extern int line_width;

    if (wid == 0) {
      wid = line_width;
      if (wid == 0) wid = 80;
    }
    sprintf(err_oline, fmt, name, value);
    fixed_part_len = strlen(err_oline);
    for (;;) {
      err_oline_cat("  "); err_oline_cat(descrip+offset);
      if (strlen(err_oline) <= wid)
        offset += wid;
      else {
        for (i=wid; err_oline[i] != ' '; i--) {}
        if (i+1 <= fixed_part_len+2) i = wid;
        err_oline[i] = '\0'; offset += i - (fixed_part_len+2) + 1;
        }
      put_line(err_oline,0,T_DISPLAY_LOOP);
      if (offset >= strlen(descrip)) break;
      else sprintf(err_oline, "%*s", fixed_part_len, "");
    }
}

static int dsversion()
{
  struct pdesc *p;
  const char *compiler = 
#ifdef __DECC
    		"DECC";
#endif
#ifdef vaxc
    		"VAXC";
#endif
#ifdef __GNUC__
    		"GNUC";
#endif

  start_header(T_DISPLAY_LOOP,SHOW_PROFILE);
  sprintf(err_oline,"%s (%s)  Compiled by %s on: %s at %s",NEWS_VERSION,NEWS_VDATE,compiler,__DATE__,__TIME__);
  put_line(err_oline,0,T_DISPLAY_LOOP);
  put_line("",0,T_DISPLAY_LOOP);
  end_header(T_DISPLAY_LOOP);
#if !defined(CMU) && !defined(UCXSOCKETS) && !defined(UCXQIOS) && !defined(MULTINET) && !defined(TCPWARE) && !defined(EXOS)
  put_line("No TCP/IP networking support",0,T_DISPLAY_LOOP);
  put_line("",0,T_DISPLAY_LOOP);
#endif
  for (p=params; p->pname; ++p) {
    char valbuf[12];
    sprintf(valbuf, "%6d", p->pvalue);
    dsformatline("%-29s%6s", p->pname, valbuf, p->pdescr);
  }
  /* Note USENET is the only NEWSSITE.H defined parameter that is a string */
  dsformatline("%-29s%6s","USENET", USENET, 
 "E-mail account that receives network related administrative mail messages from news");
  put_line("",1,T_DISPLAY_LOOP);
  return(0);
}

int do_version()
{
  return(unwind_display(I_DISPLAY_LOOP,dsversion));
}
