/*
	BDM_VMS - VMS specific routines.

	Note: Most routines in this module use accountnames if use_account_name
		is specified and use username if use_account_name is not
		defined. To keep the modules easy to view the variables are
		the same name (typically accountname) even though it could be
		a username.

*/
#include "bdm.h"

#include clidef
#include climsgdef
#include descrip
#include dvidef
#include fab
#include jpidef
#include ssdef
#include stdio
#include rab
#include rmsdef
#include uaidef
#ifdef use_li_server
#include "li-access.h"
#endif /* use_li_server */
#include "uaf.h"

#ifdef DEBUG
# define LOGFLAG  0xff
#else  DEBUG
# define LOGFLAG  0x80
#endif DEBUG

#ifdef use_account_name
#include "rmfcom.h"
RMFCOM rmfcom;
#endif /* use_account_name */

struct item_lst_3 {unsigned short length;
		   unsigned short code;
		   char *address;
		   int *rladdress;};


/* Global data definitions. */
extern struct sys_ident_node *sys_info; /* System information on idents */
extern char pname[PNAMESIZE];		/* Command parameter */
extern struct plist_type plist;
extern char username[USERNAMESIZE];
extern char ident[IDENTSIZE];
extern int  cl_size;
extern char owner[ACCOUNTNAMESIZE];
extern char partition[PNAMESIZE];		/* Command qualifier */
extern char expiration[EXPIRESIZE];
extern int  cl_user;
extern int  cl_administrator;
extern int  cl_full;
extern int  cl_brief;
extern int  cl_write;
extern int  cl_read;
extern int  cl_repair;
extern int  cl_confirm;
extern int  cl_type;
extern char description[PDESCSIZE];
extern char my_account[ACCOUNTNAMESIZE];	/* Account name of caller */


/* Routine definitions. */
int create_ident(char *id);
int create_user_ident(unsigned long id, char *accountname);
void destroy_ident(char *id);
void get_my_account();
void get_space(int *available_space, int *used_space);
void *get_sys_info();
unsigned long get_uic(char *accountname);
int grant_ident(char *id, char *accountname);
#ifdef use_li_server
int li_newgroup(char *id);
#endif /* use_li_server */
void parse_command();
int revoke_ident(char *id, char *accountname);
int trans_account(char *username[], char *accountname[]);
int trans_user(char *username[], char *accountname[]);


/*
	Create_ident - Routine to create the identifier id$w, id$r.
*/
int create_ident(id)
char *id;
{
  int ident_value;
  char id_name[IDENTSIZE+2];
  char line[1024];
  int i;
  int sts;
  struct dsc$descriptor_s id_desc =
    {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &id_name};

  /* Type 1 identifiers do not have a $x after them. */
  if(cl_type) {
    for(i=0;((i<IDENTSIZE) && (id[i] != '\0') && (id[i] != ' '));i++)
      id_name[i] = id[i];
      id_name[i] = '\0';
    id_desc.dsc$w_length = i;
#ifdef use_li_server
    if((ident_value = li_newgroup(id_name)) == 0) {
      fprintf(stderr,"Error getting group number\n");
      return(0); /* Opps */
    }
#else
    ident_value = 0;
#endif /* use_li_server */
    sts = sys$add_ident(&id_desc, ident_value, 0, 0);
    if((sts == SS$_DUPIDENT) || (sts == SS$_DUPLNAM)) {
      printf("Identifier already in use\n");
    }
    if(!(sts & 1)) 
      return(0);
    else
      return(1);
  }


  /* If type 0 identifier then create the ident with the $r and $w appended */
  for(i=0;((i<IDENTSIZE) && (id[i] != '\0') && (id[i] != ' '));i++)
    id_name[i] = id[i];
  id_name[i++] = '$';
  id_name[i++] = 'W';
  id_name[i] = '\0';
  id_desc.dsc$w_length = i;

#ifdef use_li_server
  if((ident_value = li_newgroup(id_name)) == 0) {
    fprintf(stderr,"Error getting group number\n");
    return(0); /* Opps */
  }
#else
  ident_value = 0;
#endif /* use_li_server */

  sts = sys$add_ident(&id_desc, ident_value, 0, 0);
  if((sts == SS$_DUPIDENT) || (sts == SS$_DUPLNAM)) {
    printf("Identifier already in use\n");
  }
  if(!(sts & 1)) return(0);

  /* Now add the read identifier */
  id_name[i-1] = 'R';
#ifdef use_li_server
  if((ident_value = li_newgroup(id_name)) == 0) {
    fprintf(stderr,"Error getting group number\n");
    return(0); /* Opps */
  }
#else
  ident_value = 0;
#endif /* use_li_server */
  sts = sys$add_ident(&id_desc, ident_value, 0, 0);
  if(!(sts & 1)) return(0);

  return(1);
} /*** End of routine create_ident ***/

/*
	Create_user_ident - Routine to check to see if a user (UIC) has a
		rights list identifier associated with them and if not
		create one. The idenfitier will be the username. If the
		username is all numbers then the routine will add a U$
		at the front of the identifier.

	Input:	id - Identifier name
		accountname - Accountname or username for which id is to be
				created
*/
int create_user_ident(id, accountname)
unsigned long id;
char *accountname;
{
  int i;
  int sts;
  char user_ident[USERNAMESIZE+3];
  struct dsc$descriptor_s user_ident_desc =
    {0,  DSC$K_DTYPE_T, DSC$K_CLASS_S, &user_ident};

  trans_account(user_ident,accountname);
  truncate_string(user_ident,ACCOUNTNAMESIZE);
  user_ident_desc.dsc$w_length = strlen(user_ident);
  sts = sys$add_ident(&user_ident_desc, id, 0, 0);

  /* If it failed then add the U$ at the front. */
  if(sts == SS$_IVIDENT) {
    user_ident[0] = 'U';
    user_ident[1] = '$';
    trans_account(&user_ident[2],ACCOUNTNAMESIZE);
    truncate_string(user_ident,sizeof(user_ident));
    user_ident_desc.dsc$w_length = strlen(user_ident);
    sts = sys$add_ident(&user_ident_desc, id, 0, 0);
  }
  return(sts);
} /*** End of routine create_user_ident ***/

/*
	Destroy_ident - Routine to destroy an identifier and remove all
		of the holder records associated with the identifier.
*/
void destroy_ident(id)
char *id;
{
  int ident_value;
  char id_name[IDENTSIZE+2];
  int i;
  int sts;
  struct dsc$descriptor_s id_desc =
    {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &id_name};

  for(i=0;((i<IDENTSIZE) && (id[i] != '\0') && (id[i] != ' '));i++)
    id_name[i] = id[i];
  id_name[i++] = '$';
  id_name[i++] = 'W';
  id_desc.dsc$w_length = i;

  /* Remove the write ident */
  /* The sys$rem_ident routine also removes all holder records. */
  sts = sys$asctoid(&id_desc, &ident_value, 0);
  if(sts & 1)
    sts = sys$rem_ident(ident_value);

  /* Remove the read ident */
  id_name[i-1] = 'R';
  sts = sys$asctoid(&id_desc, &ident_value, 0);
  if(sts & 1)
    sts = sys$rem_ident(ident_value);

  return;
} /*** End of routine Descroy_ident ***/


/*
	Get_my_account - Routine to get the account name of the current
	process.
*/
void get_my_account()
{
  int sts;

  struct item_lst_3 jpi_itemlist[] = {
#ifdef use_account_name
    {sizeof(my_account), JPI$_ACCOUNT, &my_account, 0},
#else
    {sizeof(my_account), JPI$_USERNAME, &my_account, 0},
#endif use_account_name
    {0, 0, 0, 0}};

  sts = sys$getjpiw(0, 0, 0, jpi_itemlist, 0, 0, 0);
      if(!(sts & 1)) {
        printf("Error getting account name\n");
        bdm_exit(0);
      }

  truncate_string(my_account,sizeof(my_account));
  return;

} /*** End of get_my_account ***/

/*
	Get_space - Routine to get the amount of space available and used on a
		partition. The VMS version of this routine uses the volume
		name to locate the partition and then does a f$getdvi on the
		DISK$volname device.
*/
void get_space(available_space, used_space)
int *available_space;
int *used_space;
{
  int sts;
  char   volume_name[BUFSIZ];
  int	 free_blocks=0;
  int    available_blocks=0;
  struct item_lst_3 dvi_itemlist[] = {
    {sizeof(free_blocks), DVI$_FREEBLOCKS, &free_blocks, 0},
    {sizeof(available_blocks), DVI$_MAXBLOCK, &available_blocks, 0},
    {0, 0, 0, 0}};
  struct dsc$descriptor_s volume_d =
    {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &volume_name};

  sprintf(volume_name,"DISK$%s",&plist.ploc.plistvol[0]);

  volume_d.dsc$w_length = strlen(volume_name);

  sts = sys$getdviw(0, 0, &volume_d, &dvi_itemlist, 0, 0, 0, 0);
  *available_space = available_blocks;

  *used_space = available_blocks - free_blocks;
  return;
    
} /*** End of routine get_space ***/

/*
	Get_sys_info - Routine to create a  list of identifiers on the system
		       and for each list create a separate list containing
		       the names of all accounts that hold the identifier.
*/
void *get_sys_info()
{
  char answer[BUFSIZ];			/* Confirm buffer */
  short ident_name_len;			/* Length of ident name */
  int ident_id;				/* Ident number */
  int attrib;				/* Ident attributes */
  int context=0, holder_context=0;	/* Context values for system calls */
  int holder[2];
  char ident_name[IDENTSIZE];
  struct dsc$descriptor_s ident_name_d =
    {sizeof(ident_name), DSC$K_DTYPE_T, DSC$K_CLASS_S, &ident_name};
  struct sys_ident_node *last_node;
  struct sys_user_node  *last_user;
  int group;			/* Printf uses longwords so must convert */
  int member;			/* word to longword for group/member     */
  int sts;
  struct FAB fab;               /* Fab for SYSUAF */
  struct RAB rab;               /* Rab for SYSUAF */
  struct UAFDEF uafrec;         /* UAF record from SYSUAF */


  /* Set up the FAB & RAB of the SYSUAF (used to translate UIC to account */
  fab = cc$rms_fab;
  rab = cc$rms_rab;
  fab.fab$b_fns = sizeof("sysuaf");
  fab.fab$l_fna = "sysuaf";
  fab.fab$b_dns = sizeof("sys$system:.dat");
  fab.fab$l_dna = "sys$system:.dat";
  fab.fab$b_fac = FAB$M_GET;
  fab.fab$b_org = FAB$C_IDX;
  fab.fab$b_rfm = FAB$C_VAR;
  fab.fab$b_shr = FAB$M_SHRGET | FAB$M_SHRPUT | FAB$M_SHRDEL | FAB$M_SHRUPD;
  rab.rab$l_fab = &fab;
  rab.rab$l_kbf = &uafrec.uaf$r_uic_overlay.uaf$l_uic;
  rab.rab$b_krf = 1;
  rab.rab$b_ksz = 4;
  rab.rab$b_rac = RAB$C_KEY;
  rab.rab$l_rop = RAB$M_NLK;
  rab.rab$l_ubf = &uafrec;
  rab.rab$w_usz = sizeof(uafrec);
  /* Open the SYSUAF to translate the uic to accountname */
  sts = SYS$OPEN(&fab);
  if(!(sts & 1)) {
    printf("Can't open SYSUAF\n");
    lib$signal(sts);
    bdm_exit(0);
  }
  sts = SYS$CONNECT(&rab);
  if(!(sts & 1)) {
    printf("Can't connect to SYSUAF\n");
    lib$signal(sts);
    bdm_exit(0);
  }

  sts = sys$idtoasc(-1,&ident_name_len, &ident_name_d, &ident_id, &attrib,
			&context);
  if(!(sts & 1) && (sts != SS$_NOSUCHID)) {
    printf("Error getting identifier information from system\n");
    lib$signal(sts);
    sys$close(&fab);
    bdm_exit(0);
  }
  while(sts != SS$_NOSUCHID) {
    if((ident_id & 0x80000000) && (!attrib)) {
      ident_name[ident_name_len] = '\0';	/* Terminate the name */
      /* Create the node in the list then fill it in... */
      if(!sys_info) {
	sys_info = (struct sys_ident_node *)malloc(sizeof(struct sys_ident_node));
	last_node = sys_info;
      } else {
	last_node->next = (struct sys_ident_node *)malloc(sizeof(struct sys_ident_node));
	last_node = last_node->next;
      }
      strcpy(last_node->ident_name,ident_name);
      last_node->in_pif = 0;
      last_node->u_node = 0;
      last_node->next = 0;
      /* Now find all of the holders of this ident and add them to the list */
      sts = sys$find_holder(ident_id, &holder,0, &holder_context);
      if(!(sts & 1) && (sts != SS$_NOSUCHID)) {
	printf("Error getting holders of identifier %s\n",ident_name);
	lib$signal(sts);
        sys$close(&fab);
	bdm_exit(0);
      }

      while(sts != SS$_NOSUCHID) {
	uafrec.uaf$r_uic_overlay.uaf$l_uic = holder[0];
	/* The following GET call only returns 1 account for a UIC however */
	/* there can be multiple accounts for a UIC. The code currently    */
	/* only creates one account record when building the userlist      */
	/* however it should create an account record for each account.    */
        sts = SYS$GET(&rab);
        if(!(sts & 1)) {
	  if(sts = RMS$_RNF) {
	    group = uafrec.uaf$r_uic_overlay.uaf$r_uic_fields.uaf$w_grp;
	    member = uafrec.uaf$r_uic_overlay.uaf$r_uic_fields.uaf$w_mem;
  	    printf("UIC [%o,%o] not owned by any account\n",group,member);
	    if(cl_repair) {
	      answer[0] = '\0';
	      if(cl_confirm) {
		printf("Remove holder? ");
		gets(answer);
	      } else {
	        answer[0] = 'Y';
	      }
	      if(toupper(answer[0]) == 'Y')  {
	        printf("  Removing holder\n");
	        sts = sys$rem_holder(ident_id,&holder[0]);
	        if(!(sts & 1)) {
		  printf("Error removing holder record\n");
		  lib$signal(sts);
		  bdm_exit(0);
	        }
	      }
	    }
	  } else {
	    lib$signal(sts);
	    sys$close(&fab);
	    bdm_exit(0);
	  }
	} else {
	  /* Place the accountname at the end of the userlist if one exists */
	  /* Create the list if one does not exits.			  */
	  if(last_node->u_node) {
	    last_user->next = (struct sys_user_node *)malloc(sizeof(struct sys_user_node));
	    last_user = last_user->next;
	  } else {
	    last_node->u_node = (struct sys_user_node *)malloc(sizeof(struct sys_user_node));
	    last_user = last_node->u_node;
	  }
#ifdef use_account_name
	  strncpy(&last_user->accountname,&uafrec.uaf$t_account,sizeof(last_user->accountname));
#else
	  strncpy(&last_user->accountname,&uafrec.uaf$t_username,sizeof(last_user->accountname));
#endif /* use_account_name */
	  truncate_string(last_user->accountname,sizeof(last_user->accountname));
	}
	sts = sys$find_holder(ident_id, &holder,0, &holder_context);
	if(!(sts & 1) && (sts != SS$_NOSUCHID)) {
	  printf("Error getting holders of identifier %s\n",ident_name);
	  lib$signal(sts);
          sys$close(&fab);
	  bdm_exit(0);
	}
      }
    }
    sts = sys$idtoasc(-1,&ident_name_len, &ident_name_d, &ident_id, &attrib,
			&context);
    if(!(sts & 1) && (sts != SS$_NOSUCHID)) {
      printf("Error getting identifier information from system\n");
      lib$signal(sts);
      sys$close(&fab);
      bdm_exit(0);
    }
  }
  sts = sys$close(&fab);
  return(sys_info);
} /*** End of routine get_sys_info ***/

/*
	Get_uic - Routine to get the UIC associated with an accountname.
		(Or username if use_account_name is not defined)
*/
unsigned long get_uic(accountname)
char *accountname;
{
  struct {
    union {
      unsigned long uic;
      unsigned short g_m[2];
    } uic_union;
  } uic_struct;
  int sts;
  struct dsc$descriptor_s acct_descr = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};

#ifdef use_account_name
  static char rmf[] = "UW$DAT:RMF.DAT";
  $DESCRIPTOR(rmf_descr, rmf);
#else
  struct item_lst_3 uai_itemlist[] = {
    {sizeof(uic_struct.uic_union.uic),UAI$_UIC,&uic_struct.uic_union.uic},
    {0, 0, 0, 0}};
#endif /* use_account_name */

  /* First set up the accountname string. Truncate trailing spaces on name */
  truncate_string(accountname,ACCOUNTNAMESIZE);
  acct_descr.dsc$w_length = strlen(accountname);
  if(acct_descr.dsc$w_length > ACCOUNTNAMESIZE) /* If accountname is at max */
    acct_descr.dsc$w_length = ACCOUNTNAMESIZE;  /* then set length to max */
  acct_descr.dsc$a_pointer = accountname;

#ifdef use_account_name
  /* Now open the RMF, get the record then close the RMF. */
  if(!(rmfopen(&rmf_descr))) return(0);
  sts = rmfget(&acct_descr);
  uclose(&rmfcom.lun);
  if(!(sts & 1)) return(0);

  /* RMFGET returns the uic as two longwords. Convert to integer and then */
  /* switch the order of the words.                                       */
  uic_struct.uic_union.g_m[1] = rmfcom.uic[0];
  uic_struct.uic_union.g_m[0] = rmfcom.uic[1];
#else
  sts = sys$getuai(0, 0, &acct_descr, &uai_itemlist, 0, 0, 0);
  if(!(sts & 1)) return(0);
#endif /* use_account_name */

  return(uic_struct.uic_union.uic);

} /*** End of routine get_uic ***/


/*
	Grant_ident - Routine to grant the identifier to a account.
*/
int grant_ident(id, accountname)
char *id;
char *accountname;
{
  struct dsc$descriptor_s ident_descr = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
  int sts;
  long holder[2];
  long idnum;


  holder[0] = get_uic(accountname);
  if(holder[0] == 0) {
    printf("Grant ident routine can't get uic for account %s\n",accountname);
    return(FALSE);   /* Can't get UIC, return error... */
  }
  holder[1] = 0;

  /* Set up string descriptor for system service */
  ident_descr.dsc$w_length = strlen(id);
  ident_descr.dsc$a_pointer = id;

  /* Translate the identifier name to an identifier number */
  sts = sys$asctoid(&ident_descr, &idnum, 0);
  if(!(sts & 1)) {
    printf("No such identifier %s\n",id);
    return(FALSE);	      /* No such identifier exists */
  }

  /* Make sure that the user has a uic rights identifier */
  sts = sys$idtoasc(holder[0], 0, 0, 0, 0, 0);
  if(sts == SS$_NOSUCHID) sts = create_user_ident(holder[0],accountname);
  if(!(sts & 1)) {
    printf("Error finding idname for user %s\n",accountname);
    return(FALSE);
  }

  /* Now grant the identifier to the user. */
  sts = sys$add_holder(idnum, &holder, 0, 0);
  if(!(sts & 1) && (sts != SS$_DUPIDENT)) {
    printf("Error adding a holder record for ident %s\n",id);
    return(FALSE);
  }

  return(TRUE);
} /*** End of routine grant_ident ***/

/*
        Index - Locate a character in a string.
*/
char *index(str, c)
register char *str, c;
{
        for (; *str != '\0'; str++) {
                if (*str == c)
                        return str;
        }

        return NULL;
} /*** End of index ***/


#ifdef use_li_server */
/*
	Routine to talk to Li and get a group number.
*/
int li_newgroup(id)
  char *id;
{
  char line[BUFSIZ];
  char *end_msg = "end\n";
  int  fd;
  int  len;
  char *tok;

  if ((fd = server("li","li",1023,LOGFLAG)) >= 0) {

    sprintf(line,"access %s; user bdm; getgroup name=%s seq=72\n", LI_OPS, id);
    if (socket_write(fd,line,strlen(line)) < 0) {
      perror("li write");
      socket_close(fd);
      return(0);
    }

    /*
    **  Check to see if group name already exists. If it does then get
    **  the value of the id from li and pass return it else call li to create
    **  a new group.
    */

    while (len = socket_read(fd,line,sizeof(line))) {
      line[len] = '\0';
      for(tok=strtok(line,"\n");tok != NULL;tok=strtok(0,"\n")) {
        if (!strncmp(tok,"nak",3)) {
	  if(strncmp(tok,"nak seq=72 err=15",17)) {
	    fprintf(stderr,"Error getting group id from Li\n");
	    fprintf(stderr,tok);
	    socket_write(fd,end_msg,strlen(end_msg));
	    socket_close(fd);
	    return(0);
	  }
  	  /* Group does not exist in li database, create it... */
	  printf("Group does not exist in li database\n");
	  sprintf(line,"newgroup name =%s seq=72\n",id);
	  if(socket_write(fd,line,strlen(line)) < 0) {
	    perror("li write");
	    socket_close(fd);
	    return(0);
	  }
	  while (len = socket_read(fd,line,sizeof(line))) {
	    line[len] = '\0';
	    for(tok=strtok(line,"\n");tok!= NULL;tok=strtok(0,"\n")) {
	      if(!strncmp(tok,"nak",3)) {
		fprintf(stderr,"Li error creating group\n");
		fprintf(stderr,tok);
		socket_write(fd,end_msg,strlen(end_msg));
		socket_close(fd);
		return(0);
	      } else if (!strncmp(tok,"ack seq=72",10)) {
		/* Created new group, now get the group number */
		socket_write(fd,end_msg,strlen(end_msg));
		socket_close(fd);
		return(li_parse_gid(tok));
	      }
	    }
	  }
        } else if (!strncmp(tok,"ack seq=72",10)) {
	  /* Group already exists... */
	  socket_write(fd,end_msg,strlen(end_msg));
	  socket_close(fd);
	  return(li_parse_gid(tok));
        }
      }
    }
  } else {

    fprintf(stderr,"Unable to communicate with li server to create ident.\n");
  }

  socket_close(fd);
  return(0);

} /*** End of routine li_newgroup ***/
#endif /* use_li_server */

/*
	Routine to parse the command line.
*/
void parse_command(argc, argv, command)
  int argc;
  char *argv[];
  int *command;
{
  char option[50];				/* Command option */
  char part_size[50];
  char owner_username[USERNAMESIZE];
  char itype;					/* Identifier type */
  char exp_date[11];				/* Expiration date */
  int  month, day, year;		/* Expiration date as integers */
  char cmonth[3];			/* Expiration month as char */

  struct dsc$descriptor_s option_d =
    {sizeof(option), DSC$K_DTYPE_T, DSC$K_CLASS_S, &option};
  struct dsc$descriptor_s pname_d =
    {sizeof(pname), DSC$K_DTYPE_T, DSC$K_CLASS_S, &pname};
  struct dsc$descriptor_s username_d =
    {sizeof(username), DSC$K_DTYPE_T, DSC$K_CLASS_S, &username};
  struct dsc$descriptor_s partition_d =
    {sizeof(partition), DSC$K_DTYPE_T, DSC$K_CLASS_S, &partition};
  struct dsc$descriptor_s ident_d =
    {sizeof(ident), DSC$K_DTYPE_T, DSC$K_CLASS_S, &ident};
  struct dsc$descriptor_s size_d =
    {sizeof(part_size), DSC$K_DTYPE_T, DSC$K_CLASS_S, &part_size};
  struct dsc$descriptor_s owner_d =
    {sizeof(owner_username), DSC$K_DTYPE_T, DSC$K_CLASS_S, &owner_username};
  struct dsc$descriptor_s description_d =
    {sizeof(description), DSC$K_DTYPE_T, DSC$K_CLASS_S, &description};
  struct dsc$descriptor_s itype_d =
    {sizeof(itype), DSC$K_DTYPE_T, DSC$K_CLASS_S, &itype};
  struct dsc$descriptor_s exp_date_d =
    {sizeof(exp_date), DSC$K_DTYPE_T, DSC$K_CLASS_S, &exp_date};

  static $DESCRIPTOR(cli_option_d,"OPTION");

  /* Command parameters */
  static $DESCRIPTOR(cli_pname_d,"PNAME");
  static $DESCRIPTOR(cli_username_d,"USERNAME");
  static $DESCRIPTOR(cli_ident_d,"IDENT");
  static $DESCRIPTOR(cli_size_d,"SIZE");
  static $DESCRIPTOR(cli_owner_d,"OWNER");

  /* Command qualifiers */
  static $DESCRIPTOR(cli_administrator_d,"ADMINISTRATOR");
  static $DESCRIPTOR(cli_partition_d,"PARTITION");
  static $DESCRIPTOR(cli_type_d,"TYPE");
  static $DESCRIPTOR(cli_user_d,"USER");
  static $DESCRIPTOR(cli_full_d,"FULL");
  static $DESCRIPTOR(cli_brief_d,"BRIEF");
  static $DESCRIPTOR(cli_write_d,"WRITE");
  static $DESCRIPTOR(cli_read_d,"READ");
  static $DESCRIPTOR(cli_repair_d,"REPAIR");
  static $DESCRIPTOR(cli_confirm_d,"CONFIRM");
  static $DESCRIPTOR(cli_description_d,"DESCRIPTION");
  static $DESCRIPTOR(cli_expiration_d,"EXPIRATION");

  int  sts;


  /* Initialize parameters */
  partition[0] = '\0';			/* Set partition to null string */


  /* Find out which command was specified on the command line */
  sts = CLI$GET_VALUE(&cli_option_d,&option_d);
  if(!(sts & 1)) {
    printf("Error getting command line\n");
    bdm_exit(0);
  }

  if(strncmp(option,"CRE",3) == 0) *command = CREATE_COMMAND;
  if(strncmp(option,"DES",3) == 0) *command = DESTROY_COMMAND;
  if(strncmp(option,"ADD",3) == 0) *command = ADD_COMMAND;
  if(strncmp(option,"MOD",3) == 0) *command = MODIFY_COMMAND;
  if(strncmp(option,"REM",3) == 0) *command = REMOVE_COMMAND;
  if(strncmp(option,"VER",3) == 0) *command = VERIFY_COMMAND;
  if(strncmp(option,"MOU",3) == 0) *command = MOUNT_COMMAND;
  if(strncmp(option,"REP",3) == 0) *command = REPORT_COMMAND;
  if(strncmp(option,"SHO",3) == 0) *command = SHOW_COMMAND;
  if(strncmp(option,"EXP",3) == 0) *command = EXPIRE_COMMAND;

  /* Get username parameter */
  username[0] = '\0';  /* Make sure string is empty to start */
  if((*command == ADD_COMMAND) || (*command == MODIFY_COMMAND) ||
     (*command == REMOVE_COMMAND) || (*command == SHOW_COMMAND)) {
    if(CLI$PRESENT(&cli_username_d) == CLI$_PRESENT) {
      sts = CLI$GET_VALUE(&cli_username_d,&username_d);
      if(!(sts & 1)) {
        printf("Error getting command line\n");
        bdm_exit(0);
      }
      truncate_string(username,sizeof(username));
      if(strlen(username) == 0) {
	printf("Must supply a username.\n");
	bdm_exit(0);
      }
    }
  }

  /* Get partition parameter */
  if((*command == CREATE_COMMAND) || (*command == DESTROY_COMMAND) ||
     (*command == MOUNT_COMMAND)) {
    if(CLI$PRESENT(&cli_pname_d) == CLI$_PRESENT) {
      sts = CLI$GET_VALUE(&cli_pname_d,&pname_d);
      if(!(sts & 1)) {
        printf("Error getting command line\n");
        bdm_exit(0);
      }
      truncate_string(pname,sizeof(pname));
      if(strlen(pname) == 0) {
	printf("Must supply a partition name without spaces");
	bdm_exit(0);
      }
    }
  }

  /* Get identifier parameter */
  if(*command == CREATE_COMMAND) {
    if(CLI$PRESENT(&cli_ident_d) == CLI$_PRESENT) {
      sts = CLI$GET_VALUE(&cli_ident_d,&ident_d);
      if(!(sts & 1)) {
        printf("Error getting command line\n");
        bdm_exit(0);
      }
      truncate_string(ident,sizeof(ident));
      if(strlen(ident) == 0) {
	printf("Must supply an identifier without spaces");
	bdm_exit(0);
      }
    }
  }

  /* Get size parameter */
  if(*command == CREATE_COMMAND) {
    if(CLI$PRESENT(&cli_size_d) == CLI$_PRESENT) {
      sts = CLI$GET_VALUE(&cli_size_d,&size_d);
      if(!(sts & 1)) {
        printf("Error getting command line\n");
        bdm_exit(0);
      }
      cl_size = atoi(&part_size);
    }
  }

  /* Get owner parameter */
  if(*command == CREATE_COMMAND) {
    if(CLI$PRESENT(&cli_owner_d) == CLI$_PRESENT) {
      sts = CLI$GET_VALUE(&cli_owner_d,&owner_d);
      if(!(sts & 1)) {
        printf("Error getting command line\n");
        bdm_exit(0);
      }
      truncate_string(owner_username,sizeof(owner_username));
      /* Translate the username to an account name */
      if(!(trans_user(owner_username,owner))) {
        printf("No such username %12.12s\n",owner_username);
	bdm_exit(0);
      }
      truncate_string(owner,sizeof(owner));
      if(strlen(owner) == 0) {
	printf("Owner can't be blank\n");
	bdm_exit(0);
      }
    }
  }


  /* Get partition qualifier */
  if((*command == ADD_COMMAND) || (*command == MODIFY_COMMAND) ||
     (*command == REMOVE_COMMAND) || (*command == REPORT_COMMAND) ||
     (*command == VERIFY_COMMAND)) {
    if(CLI$PRESENT(&cli_partition_d)  == CLI$_PRESENT) {
      sts = CLI$GET_VALUE(&cli_partition_d,&partition_d);
      if(!(sts & 1)) {
        printf("Error getting command line\n");
        bdm_exit(0);
      }
      truncate_string(partition,sizeof(partition));
    }
  }

  /* Get type qualifier */
  /* Type = 0 (default) means that identifiers have $w and $r format */
  /* Type = 1 means that the identifiers don't have $w or $r */
  if(*command == CREATE_COMMAND) {
    if(CLI$PRESENT(&cli_type_d) == CLI$_PRESENT) {
      sts = CLI$GET_VALUE(&cli_type_d,&itype_d);
      if(!(sts & 1)) {
        printf("Error getting command line\n");
        bdm_exit(0);
      }
    }
  }

  /* Get Expiration date */
  if(*command == CREATE_COMMAND) {
    if(CLI$PRESENT(&cli_expiration_d) == CLI$_PRESENT) {
      sts = CLI$GET_VALUE(&cli_expiration_d,&exp_date_d);
      if(!(sts & 1)) {
	printf("Error getting command line\n");
	bdm_exit(0);
      }
      sscanf(exp_date,"%2d%*c%3s%*c%d",&day,&cmonth,&year);
      if(!strncmp(cmonth,"JAN",3)) month = 1;
      if(!strncmp(cmonth,"FEB",3)) month = 2;
      if(!strncmp(cmonth,"MAR",3)) month = 3;
      if(!strncmp(cmonth,"APR",3)) month = 4;
      if(!strncmp(cmonth,"MAY",3)) month = 5;
      if(!strncmp(cmonth,"JUN",3)) month = 6;
      if(!strncmp(cmonth,"JUL",3)) month = 7;
      if(!strncmp(cmonth,"AUG",3)) month = 8;
      if(!strncmp(cmonth,"SEP",3)) month = 9;
      if(!strncmp(cmonth,"OCT",3)) month = 10;
      if(!strncmp(cmonth,"NOV",3)) month = 11;
      if(!strncmp(cmonth,"DEC",3)) month = 12;
      sprintf(&expiration,"%02d-%02d-%04d",month,day,year);
    }
  }

  /* Get user and administrator qualifiers */
  if((*command == ADD_COMMAND) || (*command == MODIFY_COMMAND)) {
    if(CLI$PRESENT(&cli_user_d) == CLI$_PRESENT)
      cl_user = TRUE;
    else
      cl_user = FALSE;
    if(CLI$PRESENT(&cli_administrator_d) == CLI$_PRESENT) {
      cl_write = TRUE;
      cl_administrator = TRUE;
    } else
      cl_administrator = FALSE;
  }

  /* Get repair and confirm qualifiers */
  if(*command == VERIFY_COMMAND) {
    if(CLI$PRESENT(&cli_repair_d) == CLI$_PRESENT)
      cl_repair = TRUE;
    else
      cl_repair = FALSE;
    if(CLI$PRESENT(&cli_confirm_d) == CLI$_PRESENT)
      cl_confirm = TRUE;
    else
      cl_confirm = FALSE;
  }

  /* Get the brief and full qualifiers */
  if(*command == REPORT_COMMAND) {
    if(CLI$PRESENT(&cli_brief_d) == CLI$_PRESENT) {
      cl_brief = TRUE;
      cl_full  = FALSE;
     } else {
      if(CLI$PRESENT(&cli_full_d) == CLI$_PRESENT) {
        cl_full  = TRUE;
	cl_brief = FALSE;
      } else {
	/* Default condition */
	cl_brief = TRUE;
	cl_full  = FALSE;
      }
    } 
  }

  /* Get the write/read qualifiers */
  if((*command == ADD_COMMAND) || (*command == MODIFY_COMMAND)) {
    if((CLI$PRESENT(&cli_write_d) == CLI$_PRESENT) || (cl_administrator))
      cl_write = TRUE;
    else
      cl_write = FALSE;
    if(CLI$PRESENT(&cli_read_d) == CLI$_PRESENT)
      cl_read = TRUE;
    else
      cl_read = FALSE;
  }

  /* Get description parameter */
  if(*command == CREATE_COMMAND) {
    if(CLI$PRESENT(&cli_description_d) == CLI$_PRESENT) {
      sts = CLI$GET_VALUE(&cli_description_d,&description_d);
      if(!(sts & 1)) {
        printf("Error getting command line\n");
        bdm_exit(0);
      }
    }
  }

  return;

}  /*** End of Parse_command ***/


/*
	Revoke_ident - Routine to revoke an identifer from an account.
*/
int revoke_ident(id, accountname)
char *id;
char *accountname;
{
  struct dsc$descriptor_s ident_descr = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
  int sts;
  long holder[2];
  long idnum;

  holder[0] = get_uic(accountname);
  if(holder[0] == 0) return(FALSE);   /* Can't get UIC, return error... */
  holder[1] = 0;

  /* Set up string descriptor for system service */
  ident_descr.dsc$w_length = strlen(id);
  ident_descr.dsc$a_pointer = id;

  /* Translate the identifier name to an identifier number */
  sts = sys$asctoid(&ident_descr, &idnum, 0);
  if(!(sts & 1)) return(FALSE);	      /* No such identifier exists */

  /* Make sure that the user has a uic rights identifier */
  sts = sys$idtoasc(holder[0], 0, 0, 0, 0, 0);
  if(sts == SS$_NOSUCHID) sts = create_user_ident(holder[0],accountname);
  if(!(sts & 1)) return(FALSE);

  /* Now revoke the identifier from the user. If the user never had it then */
  /* return all ok.							    */
  sts = sys$rem_holder(idnum, &holder);
  if(!(sts & 1) && (sts != SS$_NOSUCHID)) return(FALSE);

  return(TRUE);
} /*** End of routine revoke_ident ***/


/*
	trans_account - Routine to translate an account name to a username.
			 If use_account_name is not set then the accountname
			 variable is already the username.
*/
int trans_account(username,accountname)
char *username[];
char *accountname[];
{
  int sts;

#ifdef use_account_name
  sts = get_uic(accountname);
  if(sts == 0) return(FALSE);
  strncpy(username,rmfcom.username,USERNAMESIZE);
#else
  strncpy(username,accountname,ACCOUNTNAMESIZE);
#endif /* use_account_name */

  truncate_string(username,USERNAMESIZE);


  return(TRUE);

} /*** End of trans_account ***/

/*
	trans_user - Routine to translate a username to an account name.
		      No translation occurs if use_account_name is not set.
*/
int trans_user(username,accountname)
char *username[];
char *accountname[];
{
  int sts;

#ifdef use_account_name
  struct dsc$descriptor_s u_d =
    {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};

  struct item_lst_3 itemlist_uai[] = {
    {ACCOUNTNAMESIZE, UAI$_ACCOUNT, 0, 0},
    {0, 0, 0, 0}};

  u_d.dsc$w_length = strlen(username);
  u_d.dsc$a_pointer = username;
  itemlist_uai[0].address = accountname;


  sts = SYS$GETUAI(0, 0, &u_d, itemlist_uai, 0, 0, 0);
  if(!(sts & 1)) return(FALSE);
#else
  strncpy(accountname,username,ACCOUNTNAMESIZE);
#endif use_account_name

  truncate_string(accountname,ACCOUNTNAMESIZE);
  return(TRUE);

} /*** End of trans_user ***/
