/* Program Name            : FILERPRO.C                                 */
/*   Original Author       : C. K. Hung 				*/
/*   Date                  : 17-MAY-1991				*/
/*   Program Description   :                                            */
/*                         :                                            */
/* Revision History follows                                             */
/*  03-Jun-1999 JL usage of __FIB 					*/
 
#include "global.h"
#include "dx.h"
#include "filer.h"
#include "filerpro.h"
#include "filerque.h"
#include "filersta.h"
#include "inquire.h"
#include <atrdef.h>
#include <fibdef.h>
#include <iodef.h>
 
 
/*
**
**  INTERNAL FUNCTION PROTOTYPING
**
**/
 
    static int		    filer_protection$2(char *, unsigned short, char *, unsigned short);
    static int		    chprot$1(char *, unsigned short *, char *);
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
int	filer_protection()
{
    if (DX_CURRENT_DIRECTORY.filemode == multiple)
	filer_multiple_protection();
    else
	filer_single_protection();
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
int	filer_multiple_protection()
{
    char errmsg[MAXFILESPEC+1];
    char spro[5],   /**  PROTECTION CODES  **/
	 opro[5],
	 gpro[5],
	 wpro[5];
    char original_prot[28];
 
    getpro(DX_CURRENT_FILE->fpro, spro, opro, gpro, wpro);
    strcpy(original_prot, "S");
    if (strlen(spro) > 0)
	sprintf(original_prot, "%s%c%s", original_prot, ':', spro);
    strcat(original_prot, ",");
    strcat(original_prot, "O");
    if (strlen(opro) > 0)
	sprintf(original_prot, "%s%c%s", original_prot, ':', opro);
    strcat(original_prot, ",");
    strcat(original_prot, "G");
    if (strlen(gpro) > 0)
	sprintf(original_prot, "%s%c%s", original_prot, ':', gpro);
    strcat(original_prot, ",");
    strcat(original_prot, "W");
    if (strlen(wpro) > 0)
	sprintf(original_prot, "%s%c%s", original_prot, ':', wpro);
 
    strcpy(errmsg, "Error setting file protection");
    multi_get_userinput_and_exec(
	filer_protection$1,
	"Multiple Set Protection",
	"Enter File Protection Spec: ",
	original_prot,
	errmsg);
    return DX__NORMAL;
}
 
 
/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      FILER_SINGLE_PROTECTION() calls FILER_PROTECTION$1 to change
**	the file protection
**
**--
**/
int filer_single_protection()
{
    char errmsg[MAXFILESPEC+1];
    char fn[MAXFILESPEC+1];
    char spro[5],   /**  PROTECTION CODES  **/
	 opro[5],
	 gpro[5],
	 wpro[5];
    char original_prot[28];
 
    if (!strcmp(DX_CURRENT_FILE->fn, "[-]"))
    {
        signal_err("Set protection of a parent directory file not allowed", bell);
    }
    else
    {
	find_full_path_name(DX_CURRENT_FILE->fn, fn, cntrl_info_block.cur_win);
	getpro(DX_CURRENT_FILE->fpro, spro, opro, gpro, wpro);
	strcpy(original_prot, "S");
	if (strlen(spro) > 0)
	    sprintf(original_prot, "%s%c%s", original_prot, ':', spro);
	strcat(original_prot, ",");
	strcat(original_prot, "O");
	if (strlen(opro) > 0)
	    sprintf(original_prot, "%s%c%s", original_prot, ':', opro);
	strcat(original_prot, ",");
	strcat(original_prot, "G");
	if (strlen(gpro) > 0)
	    sprintf(original_prot, "%s%c%s", original_prot, ':', gpro);
	strcat(original_prot, ",");
	strcat(original_prot, "W");
	if (strlen(wpro) > 0)
	    sprintf(original_prot, "%s%c%s", original_prot, ':', wpro);
 
	strcpy(errmsg, "Error setting file protections");
	get_userinput_and_execute(
	    filer_protection$1,
	    "Set File Protection",
	    "Enter File Protection Spec: ",
	    original_prot,
	    errmsg,
	    fn);
    }
   return DX__NORMAL;
}
 
 
/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      FILER_PROTECTION$1() calls FILER_PROTECTION$2 to
**	change filer protection
**
**--
**/
int	filer_protection$1(protstr, from, errmsg)
char *protstr;
char *from;
char *errmsg;
{
    unsigned short protcode;
    int i;
    struct fil_dx_tag temp_entry;
 
    if (chprot(from, protstr, errmsg, &protcode) != DX__NORMAL)
	return DX__ERROR;
 
    if (filer_protection$2(
	    from, protcode, errmsg, cntrl_info_block.cur_win) == DX__ERROR)
    {
        return DX__ERROR;
    }
 
    /*
    **  Update filer cache
    **/
 
    if (filestat(from, &temp_entry, errmsg) == DX__ERROR)
    {
        return DX__ERROR;
    }
    if (update_filer_cache(
            temp_entry, change_to_filer_cache, errmsg) == DX__ERROR)
    {
        return DX__ERROR;
    }
 
    /**  Update other windows  **/
    for (i = 0;  i < cntrl_info_block.windows;  i++)
    {
        if (i != cntrl_info_block.cur_win)
        {
            if (filer_protection$2(from, protcode, errmsg, i) == DX__ERROR)
            {
                 return DX__ERROR;
            }
        }
    }
 
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      FILER_PROTECTION$2() changes file protection and
**	update FILER display
**
**--
**/
static int filer_protection$2(
		char *from,
		unsigned short protcode,
		char *errmsg,
		unsigned short win)
{
    char full_path_name[MAXFILESPEC+1];
    struct fil_dx_tag *p;
    char str[MAXFILESPEC+1];
    $DESCRIPTOR(str_descrip, str);
 
    /*
    **	    Update FILER
    **/
 
    if (cntrl_info_block.cur_win == win)
    {
        p = DX_CURRENT_FILE;
    }
    else
    {
	for (p = cntrl_info_block.dir_dx[win].dir_filelist->forward;
	     p != cntrl_info_block.dir_dx[win].non_dir_filelist; p = p->forward)
	{
	    if (p == cntrl_info_block.dir_dx[win].dir_filelist)
	    {
		p = cntrl_info_block.dir_dx[win].non_dir_filelist;
	    }
	    else
	    {
		find_full_path_name(p->fn, full_path_name, win);
		if (!strcmp(full_path_name, from))
		{
		    break;
		}
	    }
	}
	if (p == cntrl_info_block.dir_dx[win].non_dir_filelist)
	{
	    return DX__NORMAL;
	}
    }
 
    p->fpro = protcode;
    format_filer_entry(p, str, win);
    if (cntrl_info_block.dir_dx[win].form == short_form)
    {
	LENGTH(str_descrip) = strlen(str);
        if (p->fn[ strlen(p->fn)-1 ] != ']')
	{
	    check_OK(smg$put_chars (
			&cntrl_info_block.dir_dx[win].filer_display.id,
			&str_descrip,
			&p->beg_y,
			&p->beg_x,
			0,
			0,
			0,
			0))
	}
	else
	{
	    check_OK(smg$put_chars (
			&cntrl_info_block.dir_dx[win].filer_display.id,
			&str_descrip,
			&p->beg_y,
			&p->beg_x,
			0,
			&SMG$M_BOLD,
			0,
			0))
	}
    }
    else
    {
        if (p->fn[ strlen(p->fn)-1 ] != ']')
	{
	    LENGTH(str_descrip) = strlen(str);
	    check_OK(smg$put_chars (
			&cntrl_info_block.dir_dx[win].filer_display.id,
			&str_descrip,
			&p->beg_y,
			&p->beg_x,
			&SMG$M_ERASE_TO_EOL,
			0,
			0,
			0))
	}
	else
	{
	    LENGTH(str_descrip) = 1;
	    check_OK(smg$put_chars (
			&cntrl_info_block.dir_dx[win].filer_display.id,
			&str_descrip,
			&p->beg_y,
			&1,
			0,
			0,
			0,
			0))
	    memcpy (str, str+1, strlen(str));
	    LENGTH(str_descrip) = 30;
	    check_OK(smg$put_chars (
			&cntrl_info_block.dir_dx[win].filer_display.id,
			&str_descrip,
			&p->beg_y,
			&2,
			0,
			&SMG$M_BOLD,
			0,
			0))
	    memcpy (str, str+30, strlen(str)-30+1);
	    LENGTH(str_descrip) = strlen(str);
	    check_OK(smg$put_chars (
			&cntrl_info_block.dir_dx[win].filer_display.id,
			&str_descrip,
			&p->beg_y,
			&32,
			&SMG$M_ERASE_TO_EOL,
			0,
			0,
			0))
        }
    }
 
    check_OK(smg$set_cursor_abs (
	      &cntrl_info_block.dir_dx[win].filer_display.id,
	      &p->beg_y,
	      &p->beg_x))
 
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      CHPROT() uses ACP services to change a file's protection.
**	Use of RMS service will fail if the user tries to change
**	a file's protection when he does not have WRITE or DELETE privilege.
**
**--
**/
int chprot(from, protstr, errmsg, protcode)
char *from;
char *protstr;
char *errmsg;
unsigned short *protcode;
{
 
    /**  VARIABLES used by ACP  **/
 
    unsigned short int fpro;	    /**  File Protection  **/
    struct {			    /**  Access Control Block  **/
	unsigned short w_size;
	unsigned short w_type;
	char *l_addr;
    } acb[] = {
	{  2, ATR$C_FPRO, &fpro },
	{ 0, 0, (char *)NULL },
    };
    int iosb[2];
    static struct fibdef fib;
    $DESCRIPTOR(fib_descriptor, (char *)&fib);
    char short_filename[MAXFILESPEC+1];
    $DESCRIPTOR (filespec_descriptor, short_filename);
    unsigned short chan;	    /**  I/O channel  **/
 
    /**  LOCAL variables  **/
 
    char *cp;
    int status;
    int i;
    struct filespec_list_tag *s;
 
    /*
    **  Initialization for ACP
    **/
 
    LENGTH(fib_descriptor) = sizeof (struct fibdef);
 
    for (i = 0; i <= 2; i++)
	__FIB(fib,fib$r_did_overlay,fib$w_did[i]) = DX_CURRENT_FILE->did[i];
 
    if ((cp = strchr(from, ']')) == 0)
	strcpy(short_filename, from);
    else
	strcpy(short_filename, cp+1);
 
    /*
    **	Find the I/O channel for this file
    **/
    for (s = DX_CURRENT_DIRECTORY.cur_filter.name_filespec_list;
	    s != (struct filespec_list_tag *)NULL;  s = s->next)
    {
	struct w_dids_tag *t;
 
        for (t = s->w_dids;  t != (struct w_dids_tag *)NULL;  t = t->next)
        {
	    if (t->did[0] == DX_CURRENT_FILE->did[0] &&
		t->did[1] == DX_CURRENT_FILE->did[1] &&
		t->did[2] == DX_CURRENT_FILE->did[2])
	    {
		chan = t->chan;
		break;
	    }
        }
    }
 
    LENGTH(filespec_descriptor) = strlen(short_filename);
 
    check_OK(sys$qiow (0,
		 chan,
		 IO$_ACCESS,
		 iosb,
		 0,
		 0,
		 &fib_descriptor,
		 &filespec_descriptor,
		 0,
		 0,
		 acb,
		 0))
 
    if (iosb[0] != SS$_NORMAL)
    {	    /**  No READ access  **/
	strcpy(errmsg, "Insufficient privilege for read operation");
	return DX__ERROR;
    }
    else
    {
	*protcode = fpro;
 
	if ((status = chprot$1(protstr, protcode, errmsg)) == DX__NORMAL)
	    fpro = *protcode;
 
	check_OK(sys$qiow (0,
			 chan,
			 IO$_MODIFY,
			 iosb,
			 0,
			 0,
			 &fib_descriptor,
			 &filespec_descriptor,
			 0,
			 0,
			 acb,
			 0))
 
	if (iosb[0] != SS$_NORMAL)
	{	/**  No MODIFY access  **/
	    strcpy(errmsg, "Error setting file protections - insufficient privileges");
	    return DX__ERROR;
	}
    }
 
    return status;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
static int	chprot$1(protstr, protcode, errmsg)
char *protstr;
unsigned short int *protcode;
char *errmsg;
{
    char *cp1, *cp2;
    unsigned short int clear_bits, set_bits;
    char protstr1[80];
 
    strcpy(protstr1, protstr);
    cp1 = protstr1;
    cp2 = strchr(cp1, ',');
    while (cp2 != NULL) {
 
	*cp2 = EOS;
	if (getprotbits(cp1, &clear_bits, &set_bits) == -1) {
	    strcpy(errmsg, "File protections syntax error, re-specify");
	    return -1;
	}
	*protcode &= ~clear_bits;
	*protcode |= set_bits;
	cp1 = cp2+1;
	cp2 = strchr(cp1, ',');
 
    }
 
    if (getprotbits(cp1, &clear_bits, &set_bits) == -1) {
	strcpy(errmsg, "File protections syntax error, re-specify");
	return -1;
    }
    *protcode &= ~clear_bits;
    *protcode |= set_bits;
 
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
int	getprotbits(protsubstr, clear_bitsp, set_bitsp)
char *protsubstr;
unsigned short int *clear_bitsp;
unsigned short int *set_bitsp;
{
    char *cp;
    int shifts;
 
    cp = protsubstr;
    switch (*cp) {
 
	case 'S':
	    *clear_bitsp = 0xF;
	    shifts = 0;
	    break;
	case 'O':
	    *clear_bitsp = 0xF0;
	    shifts = 4;
	    break;
	case 'G':
	    *clear_bitsp = 0xF00;
	    shifts = 8;
	    break;
	case 'W':
	    *clear_bitsp = 0xF000;
	    shifts = 12;
	    break;
	default:
	    return -1;
    }
 
    cp++;
    *set_bitsp = 0xF;	/**  No access at all  **/
    if (*cp == ':')
	for (cp++; *cp; cp++)
	    switch (*cp) {
 
		case 'r':
		case 'R':
		    *set_bitsp &= 0xE;
		    break;
		case 'w':
		case 'W':
		    *set_bitsp &= 0xD;
		    break;
		case 'e':
		case 'E':
		    *set_bitsp &= 0xB;
		    break;
		case 'd':
		case 'D':
		    *set_bitsp &= 0x7;
		    break;
		default:
		    return -1;
 
	    }
    else if (*cp != EOS)
	return -1;
 
    *set_bitsp = (*set_bitsp << shifts);
    return DX__NORMAL;
}
