/* Program Name            : FILERENC.C                                 */
/*   Original Author       : C. K. Hung					*/
/*   Date                  : 30-MAY-1991				*/
/*   Program Description   :                                            */
/*                         :                                            */
/* Revision History follows                                             */
/*  03-Jun-1999 JL usage of __FIB 					*/
 
 
 
#include "global.h"
#include "endecode.h"
#include "filer.h"
#include "filercpy.h"
#include "filerenc.h"
#include "filerque.h"
#include "inquire.h"
#include <atrdef.h>
#include <FIBDEF.h>
#include <iodef.h>
#include <sbkdef.h>
 
/**  Record Attributes Area  **/
struct raa_tag {
    unsigned char fat$b_rtype;
    unsigned char fat$b_rattrib;
    unsigned short int fat$w_rsize;
    struct {
	unsigned short int fat$w_hiblkh;
	unsigned short int fat$w_hiblkl;
    } fat$l_hiblk;
    struct {
	unsigned short int fat$w_efblkh;
	unsigned short int fat$w_efblkl;
    } fat$l_efblk;
    short int fat$w_ffbyte;
    unsigned char fat$b_bktsize;
    unsigned char fat$b_vfcsize;
    short int fat$w_maxrec;
    short int fat$w_defext;
    short int fat$w_gbc;
    short int spares1;
    int spares2;
    short int spares3;
    short int fat$w_versions;
};
 
/*
**
**  INTERNAL FUNCTION PROTOTYPING
**
**/
 
    static int		    filer_encode$2(char *, char *, char *);
    static int		    save_stat(char *from, FILE *lzw_file, char *errmsg, unsigned short chan);
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
int	filer_encode()
{
    if (DX_CURRENT_DIRECTORY.filemode == multiple)
	filer_multiple_encode();
    else
	filer_single_encode();
    return DX__NORMAL;
}
 
 
/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
int	filer_multiple_encode()
{
    char dummy[] = "";
    char errmsg[MAXFILESPEC+1];
 
    strcpy(errmsg, "Error encoding file");
    multi_get_userinput_and_exec(
	filer_encode$1,
	"Multiple Encode",
	"Encode to: ",
	"",
	errmsg);
    return DX__NORMAL;
}
 
 
/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
int	filer_single_encode()
{
    char fn[MAXFILESPEC+1];
    char errmsg[MAXFILESPEC+1];
 
 
    if (!strcmp(DX_CURRENT_FILE->fn, "[-]"))
    {
        signal_err("Compress a parent directory file not allowed", bell);
    }
    else
    {
	find_full_path_name(DX_CURRENT_FILE->fn, fn, cntrl_info_block.cur_win);
	strcpy(errmsg, "Error encoding file");
	get_userinput_and_execute(
	    filer_encode$1,
	    "Encode File",
	    "Encode to: ",
	    "",
	    errmsg,
	    fn);
    }
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
 
int	filer_encode$1(to, from, errmsg)
char *to;
char *from;
char *errmsg;
{
    return filer_encode$2(from, to, errmsg);
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
static int	filer_encode$2(from, to, errmsg)
char *from;
char *to;
char *errmsg;
{
    FILE *input_file;
    FILE *lzw_file;
 
    unsigned long status;
    long vm_len;
 
    struct FAB to_fab;
    struct NAM to_nam;
    char expand_name[NAM$C_MAXRSS];
    int retcode;
    struct fil_dx_tag temp_entry;
    struct filespec_list_tag *s;
    unsigned short int chan;
    int total_dids;
    char equ_name[MAXFILESPEC+1],
	 dir_name[MAXFILESPEC+1];
    int i;
 
    vm_len = TABLE_SIZE*sizeof(unsigned int);
    if ((status = lib$get_vm (
			 &vm_len,
			 &code_value,
			 0)) != SS$_NORMAL)
    {
	strcpy(errmsg, "Insufficient virtual memory");
	return DX__ERROR;
    }
 
    if ((status = lib$get_vm (
			 &vm_len,
			 &prefix_code,
			 0)) != SS$_NORMAL)
    {
	strcpy(errmsg, "Insufficient virtual memory");
	return DX__ERROR;
    }
 
    vm_len = TABLE_SIZE*sizeof(unsigned char);
    if ((status = lib$get_vm (
			 &vm_len,
			 &append_character,
			 0)) != SS$_NORMAL)
    {
	strcpy(errmsg, "Insufficient virtual memory");
	return DX__ERROR;
    }
 
    input_file = fopen(from, "r");
    if (input_file == NULL)
    {
        sprintf(errmsg, "Error opening input file %s", from);
	return DX__ERROR;
    }
 
    /**  Get directory fid and file name of the output file  **/
    to_fab = cc$rms_fab;
    to_nam = cc$rms_nam;
 
    to_fab.fab$l_fna = to;
    to_fab.fab$b_fns = strlen(to);
    to_fab.fab$l_nam = &to_nam;
    to_fab.fab$l_xab = NULL;
 
    to_fab.fab$l_dna = from;
    to_fab.fab$b_dns = strcspn (from, ";");
 
    to_nam.nam$l_esa = &expand_name;
    to_nam.nam$b_ess = NAM$C_MAXRSS;
 
    if ((status = sys$parse(&to_fab, 0, 0)) != RMS$_NORMAL)
    {
	sprintf(errmsg, "Invalid file specification");
	return DX__ERROR;
    }
 
    expand_name[to_nam.nam$b_esl] = EOS;
 
    lzw_file = fopen(expand_name, "w", "fop=tef");
    if (lzw_file == NULL)
    {
        sprintf(errmsg, "Error creating output file %s", expand_name);
	return DX__ERROR;
    }
 
    /*
    **	Find the I/O channel for this file
    **/
 
    strcpy(equ_name, "");
    strcpy(dir_name, "");
    total_dids = 0;
    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;
		strcpy(dir_name, t->equivalent_name);
	    }
            if (strcmp(equ_name, t->equivalent_name))
            {
                total_dids++;
		strcpy(equ_name, t->equivalent_name);
            }
        }
    }
 
    if ((retcode = save_stat(from, lzw_file, errmsg, chan)) != DX__NORMAL)
    {
	fclose (input_file);
        fclose (lzw_file);
        delete (expand_name);
	return retcode;
    }
 
    compress(input_file, lzw_file);
 
    fclose(input_file);
    fclose(lzw_file);
 
    vm_len = TABLE_SIZE*sizeof(unsigned int);
    if ((status = lib$free_vm(
			    &vm_len,
			    &code_value,
			    0)) != SS$_NORMAL)
    {
	strcpy(errmsg, "Error freeing up virtual memory used");
	return DX__ERROR;
    }
 
    if ((status = lib$free_vm(
			    &vm_len,
			    &prefix_code,
			    0)) != SS$_NORMAL)
    {
	strcpy(errmsg, "Error freeing up virtual memory used");
	return DX__ERROR;
    }
 
    vm_len = TABLE_SIZE*sizeof(unsigned char);
    if ((status = lib$free_vm(
			    &vm_len,
			    &append_character,
			    0)) != SS$_NORMAL)
    {
	strcpy(errmsg, "Error freeing up virtual memory used");
	return DX__ERROR;
    }
 
    /*
    **	Get file attributes
    **/
 
    if (filestat(expand_name, &temp_entry, errmsg) == DX__ERROR)
    {
        return DX__ERROR;
    }
 
    if (total_dids > 1)
    {
        strcat(dir_name, temp_entry.fn);
	strcpy(temp_entry.fn, dir_name);
    }
    temp_entry.state = waiting;
    temp_entry.beg_y = temp_entry.beg_x = 0;
    temp_entry.forward = temp_entry.backward = NULL;
 
    /*
    **  Update cache queue.
    **	In case of running out of memory, output error message
    **	but update current display(s) anyway.
    **/
 
    if (update_filer_cache(temp_entry, add_to_filer_cache, errmsg) == DX__ERROR)
    {
        signal_err(errmsg, bell);
    }
 
    /*
    **	Update the filer list and display
    **/
 
    if (add_to_filer(temp_entry, errmsg, cntrl_info_block.cur_win) == 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 (add_to_filer(temp_entry, errmsg, i) == DX__ERROR)
            {
                 return DX__ERROR;
            }
        }
    }
 
    return DX__NORMAL;
}
 
 

static int save_stat(char *from, FILE *lzw_file, char *errmsg, unsigned short chan)
{
    static struct fibdef fib;
    $DESCRIPTOR(fib_descriptor, (char *)&fib);
    unsigned long status;
 
    char filespec[256];
    unsigned short filespec_length;
    $DESCRIPTOR (filespec_descriptor, filespec);
 
    /**  File Characteristics Bits  **/
    unsigned long fch;
 
    /**  Record attribute  **/
    struct raa_tag raa;
 
    /**  Statistics Block  **/
    struct sbkdef asb;
 
    /**  Access Control Block  **/
    struct {
	unsigned short w_size;
	unsigned short w_type;
	char *l_addr;
    } acb[] = {
	{ ATR$S_UCHAR, ATR$C_UCHAR, &fch },
	{ ATR$S_RECATTR, ATR$C_RECATTR, &raa },
	{ ATR$S_STATBLK, ATR$C_STATBLK, &asb },
	{ 0, 0, (char *)NULL },
    };
 
    struct {
	unsigned short status;
	unsigned short bytcnt;
	int filler;
    } iosb;
 
    unsigned short len;
    char *cp;
    int i;
 
    /**  Directory fid for the input file  **/
 
    for (i = 0;  i <= 2;  i++)
    {
	__FIB(fib,fib$r_did_overlay,fib$w_did[i]) = DX_CURRENT_FILE->did[i];
    }
 
    /**  SYS$QIO will not use device and directory name  **/
    strcpy(filespec, strchr(from, ']')+1);
 
    LENGTH(filespec_descriptor) = strlen(filespec);
    LENGTH(fib_descriptor) = sizeof (struct fibdef);
    status = sys$qiow (		/**  Read input file attributes  **/
		 0,
		 chan,
		 IO$_ACCESS+IO$M_ACCESS,
		 &iosb,
		 0,
		 0,
		 &fib_descriptor,
		 &filespec_descriptor,
		 0,
		 0,
		 acb,
		 0);
 
    if (iosb.status != SS$_NORMAL)
    {	    /**  No READ access  **/
	sprintf(errmsg, "Insufficient privilege for read operation");
	return DX__ERROR;
    }
 
    switch (raa.fat$b_rtype & 0xF0)
	{   /**  Compress only sequential and relative files  **/
	case FAB$C_SEQ:
	case FAB$C_REL:
		break;
	case FAB$C_IDX:
		sys$qiow (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fib_descriptor,
			    0, 0, 0, 0, 0);
		strcpy(errmsg, "Compression of an Indexed file not supported");
		return DX__ERROR;
	case FAB$C_HSH:
		sys$qiow (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fib_descriptor,
			    0, 0, 0, 0, 0);
		strcpy(errmsg, "Compression of a hashed file not supported");
		return DX__ERROR;
	default:
		sys$qiow (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fib_descriptor,
			    0, 0, 0, 0, 0);
		strcpy(errmsg, "Unknown file organization.  Compression aborted");
		return DX__ERROR;
	    ;
	}
 
    /**  Save input file name  **/
    len = strlen(filespec);
    fwrite(&len, sizeof (unsigned short), 1, lzw_file);
    fwrite (filespec, sizeof (char), len, lzw_file);
 
    /**  Save input file characteristics  **/
    fwrite (&fib, sizeof (struct fibdef), 1, lzw_file);
    fwrite(&fch, sizeof (unsigned long), 1, lzw_file);
    fwrite(&raa, sizeof (struct raa_tag), 1, lzw_file);
    fwrite(&asb, sizeof (struct sbkdef), 1, lzw_file);
 
    status = sys$qiow (
		0,
		chan,
		IO$_DEACCESS,
		&iosb,
		0,
		0,
		&fib_descriptor,
		0,
		0,
		0,
		0,
		0);
 
    if (iosb.status != SS$_NORMAL)
    {	    /**  File close error  **/
	sprintf(errmsg, "Error deaccessing file");
	return DX__ERROR;
    }
 
    return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
int	    filestat(fn, e, errmsg)
char *fn;
struct fil_dx_tag *e;
char *errmsg;
{
    struct NAM nam;
    struct FAB fab;
    struct XABPRO xabpro;
    struct XABDAT xabdat;
    int i;
    char resultant_name[NAM$C_MAXRSS];
    unsigned long int status;
 
    /*
    **	Init RMS$ data structures
    **/
 
    fab = cc$rms_fab;
    nam = cc$rms_nam;
    xabpro = cc$rms_xabpro;
    xabdat = cc$rms_xabdat;
 
    /*
    **	use RMS service to get the full file spec and
    **	characteristics.  Default directory is cwd.
    **
    **/
 
    fab.fab$l_fna = fn;
    fab.fab$b_fns = strlen(fn);
    fab.fab$l_nam = &nam;
    fab.fab$l_xab = &xabpro;
    xabpro.xab$l_nxt = &xabdat;
 
    nam.nam$l_rsa = &resultant_name;
    nam.nam$b_rss = sizeof resultant_name;
 
    if ((status = sys$open (
			&fab,
			0,
			0)) != RMS$_NORMAL)
    {	    /**  Open failed  **/
	e->fid[0] = e->fid[1] = e->fid[2] = 0Xffff;
	e->fpro = 0Xffff;
	sprintf(errmsg, "Open file %s failed", fn);
	return DX__ERROR;
    }
 
    status = sys$close(
		&fab,
		0,
		0);
 
    /**  File name  **/
    memcpy(e->fn, nam.nam$l_name, nam.nam$b_name+nam.nam$b_type+nam.nam$b_ver);
    e->fn[nam.nam$b_name+nam.nam$b_type+nam.nam$b_ver] = EOS;
 
    /**  File id and directory id  **/
    for (i = 0; i <= 2; i++)
    {
	e->fid[i] = nam.nam$w_fid[i];
	e->did[i] = nam.nam$w_did[i];
    }
 
    /**  File size  **/
    e->filesize = fab.fab$l_alq;
 
    /**  File protection  **/
    e->fpro = xabpro.xab$w_pro;
 
    /**  Creation date  **/
    e->cdat = xabdat.xab$q_cdt;
 
    /**  Revision date  **/
    e->rdat = xabdat.xab$q_rdt;
 
    /**  Expiration date  **/
    e->edat = xabdat.xab$q_edt;
 
    /**  Backup date  **/
    e->bdat = xabdat.xab$q_bdt;
 
    return DX__NORMAL;
}
