/*

 * ckvcvt - assorted outboard processing for C-Kermit/VMS labeled files

 */



/* Revision History:

 * T1.0-00 - 08-Apr-91 - tmk - Initial coding, sync w/ 5A(167) and ckvfio.c

 *			       2.0-066.

 * T1.0-01 - 14-Apr-91 - tmk - Fix errors in help output, show actual system

 *			       message on RMS error.

 * T1.0-02 - 15-Apr-91 - tmk - Redefine fab$b_journal as fab$b_rfm+1.

 * T1.0-03 - 15-Apr-91 - tmk - ACL support, sync w/ 5A(169) and ckvfio.c 2.0-

 *			       069.

 * T1.0-04 - 16-Apr-91 - tmk - Fix _another_ journaling bug (whimper), handle

 *			       missing semicolon in filespec gracefully.

 * T1.0-05 - 04-Sep-92 - tmk - Implement ckvfio.c 087 fix.

 * T1.0-06 - 08-Apr-93 - tmk - Implement ckvfio.c 097 fix.

 * T1.0-07 - 24-Feb-95 - mpjz- Fix for DEC C on VAX.

 * T1.0-08 - 06-Sep-95 - fdc - Get rid of nonportable memmove().

 */



#ifdef WINTCP

#include stdio

#include stdlib

#include ctype

#include string

#include rms

#include ssdef

#else

#include <stdio.h>

#include <stdlib.h>

#include <ctype.h>

#include <string.h>

#include <rms.h>

#include <ssdef.h>

#endif /* WINTCP */

#define	VERSION	"T1.0-06"



#ifndef OLD_VMS

#include <starlet.h>

#endif /* OLD_VMS */



#define	R_MODE	"rb"

#define	IO_ERROR	0

#define IO_SUCCESS	1



/*

 * Definitions for output file

 */



static struct FAB fab_ofile;

static struct RAB rab_ofile;

static struct XABDAT xabdat_ofile;

static struct XABFHC xabfhc_ofile;

static struct XABPRO xabpro_ofile;

static struct XABALL xaball_ofile;

static struct XABRDT xabrdt_ofile;

static short ofile_ffb;

static int ofile_rec;



/*

 * Common RMS items

 */



static unsigned long int rms_sts;



/*

 * Global varables

 */



int	keepacl = 0;			/* Preserve ACL data? */

int	backup	= 0;			/* Preserve file backup date? */

int	debug	= 0;			/* Debug output? */

int	notrim	= 0;			/* Don't trim names? */

int	inquire = 0;			/* Testing if labeled? */

int	owner	= 0;			/* Preserve file ownership? */

int	strip	= 0;			/* Just stripping? */

FILE	*infd	= NULL;			/* Input file descriptor */

char	*infn	= NULL;			/* Input file name */

char	*outfn	= NULL;			/* Special output file name */

char	buffer[512];			/* Work buffer */

char	label[99];			/* Label name */

int	lblen	= 0;			/* Length of label */

char	vmsname[255];			/* Stored name */

char	vmsfile[70];			/* Stored file info */

char	vmsacl[512];			/* Stored ACL data */

int	acllen = 0;			/* Size of same */

char	*filptr = vmsfile;		/* Attribute pointer */

int	gotname	= 0;			/* Found name? */

int	gotfile = 0;			/* Found file info? */

int	gotacl = 0;			/* Found ACL info? */

int	bail	= 0;			/* If we should bail out */

char	revdat[8];			/* Revision date */

unsigned short revnum;			/* Revision number */

unsigned short jnlflg;			/* Journaling flags */



/*

 * Function prototypes

 */



extern int main(int, char **);

void do_help();

void barf(char *);

void strip_file();



#if !defined(__DECC) && !defined(VAX)

#define XABP char

#else

#define XABP void

#endif



/* memmove() replacement */



void

mymove(to, from, len) char * to; char * from; int len; {

    char tmp[16384];

    strncpy((char *)tmp,from,len);

    strncpy(to,(char *)tmp,len);

}



/*

 * Ok, let's do it

 */



int main(argc, argv)

int argc;

char *argv[];

{

    register char *ap;

    int i, j;					/* How original */



    if (argc < 2)				/* User say anything? */

	do_help();				/* If not... */



    if (*argv[1] != '-') {

	infn = argv[1];

	if ((infd = fopen(argv[1], R_MODE)) == NULL) {

	    perror(argv[1]);

	    exit(IO_ERROR);

	}

	argc--;

	argv++;

    }

    else

	bail++;



    while (argc > 1) {

	ap = argv[1];

	if (*ap != '-') {

	    fprintf(stderr, "Unknown option '%s',", ap);

	    fprintf(stderr, " do CKVCVT -? for help.\n");

	}

	else for (ap++; *ap; ap++) {

	    switch (tolower(*ap)) {



	    case 'a':				/* Preserve ACL's */

		keepacl++;

		break;



	    case 'b':				/* Preserve backup date */

		backup++;

		break;



	    case 'd':				/* Debug mode? */

		debug++;

		break;



	    case 'f':				/* Name output file */

		if (isgraph(ap[1]) != 0)

		    outfn = &ap[1];

		else if (argc > 2) {

		    outfn = argv[2];

		    argc--;

		    argv++;

		}

		else {

		    break;

		}

		goto next_arg;



	    case 'i':				/* Inquire if labeled */

		inquire++;

		strip++;

		break;



	    case 'o':				/* Preserve file ownership */

		owner++;

		break;



	    case 's':				/* Just strip it */

		strip++;

		break;



	    case 't':				/* Don't trim filenames */

		notrim++;

		break;



	    case '?':				/* Emit help text */

	    case 'h':

		do_help();

		break;



	    default:

		fprintf(stderr, "?Unknown option '%c',", *ap);

		fprintf(stderr, " do CKVCVT -? for help\n");

	    }

	}

	next_arg:

	argc--;

	argv++;

    }



    if (bail != 0)

	exit(IO_ERROR);



    fread(buffer, 20, 1, infd);

    if (strncmp(buffer, "KERMIT LABELED FILE:", 20) != 0)

	barf("not a Kermit labeled file");



    fread(buffer, 2, 1, infd);

    buffer[2] = '\0';

    lblen = atoi(buffer);

    if (lblen != 2)

	barf("");



    fread(buffer, lblen, 1, infd);



    if (strip != 0)				/* Stripping headers? */

	strip_file();



    if (strncmp(buffer, "D7", 2) != 0)

	barf("not from a VAX/VMS system");



    fread(buffer, 6, 1, infd);

    if (strncmp(buffer, "04VERS", 6) != 0)

	barf("");



    fread(buffer, 8, 1, infd);

    buffer[8] = '\0';

    lblen = atoi(buffer);



    fread(buffer, lblen, 1, infd);

    buffer[lblen] = '\0';

    if (debug)

	fprintf(stderr, "File created under VAX/VMS %s\n", buffer);



    fread(buffer, 7, 1, infd);

    if (strncmp(buffer, "05KVERS", 7) != 0)

	barf("");



    fread(buffer, 8, 1, infd);

    buffer[8] = '\0';

    lblen = atoi(buffer);



    fread(buffer, lblen, 1, infd);

    buffer[lblen] = '\0';

    if (debug)

	fprintf(stderr, "File created with C-Kermit/VMS %s\n", buffer);



    next_label:

    fread(buffer, 2, 1, infd);

    buffer[2] = '\0';

    lblen = atoi(buffer);

    if (lblen == 0)

	barf("lost sync");



    fread(buffer, lblen, 1, infd);

    buffer[lblen] = '\0';

    if (strcmp(buffer, "VMSNAME") == 0) {

	fread(buffer, 8, 1, infd);

	buffer[8] = '\0';

	lblen = atoi(buffer);

	fread(vmsname, lblen, 1, infd);

	vmsname[lblen] = '\0';

	gotname++;

	if (debug)

	    fprintf(stderr, "Loaded file name block as %s\n", vmsname);

	i = (int)strstr(vmsname, "::");

	if (i != (int)NULL) {

	    char temp[255];

	    i += 2;

	    mymove(vmsname, (char *)i, (int)strlen(vmsname));

	}

        if (!notrim) {

	    char temp[255];

	    i = (int)strrchr(vmsname, ':');

	    j = (int)strrchr(vmsname, ']');

	    if (j == (int)NULL)

		j = (int)strrchr(vmsname, '>');

	    if (j > i)

		i = j;

	    i++;

	    mymove(vmsname, (char *)i, (int) strlen(vmsname));

	}

	if (strchr(vmsname, ';') != NULL) {

	    for (j = strlen(vmsname); vmsname[j] != ';'; j--)

	    ;

	    vmsname[j] = '\0';

	}

	if (debug)

	    fprintf(stderr, "Resultant filespec: %s\n", vmsname);

	goto next_label;

    }

    else if (strcmp(buffer, "VMSFILE") == 0) {

	fread(buffer, 8, 1, infd);

	buffer[8] = '\0';

	lblen = atoi(buffer);

	fread(vmsfile, lblen, 1, infd);

	vmsfile[lblen] = '\0';

	gotfile++;

	if (debug)

	    fprintf(stderr, "Loaded file attribute block\n");

	goto next_label;

    }

    else if (strcmp(buffer, "VMSACL") == 0) {

	fread(buffer, 8, 1, infd);

	buffer[8] = '\0';

	acllen = atoi(buffer);

	fread(vmsacl, acllen, 1, infd);

	vmsacl[acllen] = '\0';

	gotacl++;

	if (debug)

	    fprintf(stderr, "Loaded file ACL block\n");

	goto next_label;

    }

    else if (strcmp(buffer, "DATA") == 0) {

	fread(buffer, 8, 1, infd);

	buffer[8] = '\0';

	lblen = atoi(buffer);

	if (lblen != 0)

	    barf("");

	if (debug)

	    fprintf(stderr, "Positioned at start of file data\n");

	goto all_set;

    }

    else {

	fprintf(stderr, "%s: unrecognized label '%s'\n", infn, buffer);

	fread(buffer, 8, 1, infd);

	buffer[8] = '\0';

	lblen = atoi(buffer);

	if (lblen > 512)

	    barf("unrecognized label too long to skip");

	fread(vmsfile, lblen, 1, infd);

	goto next_label;

    }



    all_set:

    if (gotfile != 1 || gotname != 1)

	barf("missing required labels");



/*

 * Prep the characteristics

 */



    fab_ofile = cc$rms_fab;

    fab_ofile.fab$b_fac = FAB$M_BIO | FAB$M_PUT;

    fab_ofile.fab$l_fop = FAB$M_MXV;

    if (outfn == NULL) {

	fab_ofile.fab$l_fna = vmsname;

	fab_ofile.fab$b_fns = strlen(vmsname);

    }

    else {

	fab_ofile.fab$l_fna = outfn;

	fab_ofile.fab$b_fns = strlen(outfn);

    }

    fab_ofile.fab$l_xab = (XABP *)&xabdat_ofile;

    rab_ofile = cc$rms_rab;

    rab_ofile.rab$l_fab = &fab_ofile;

    xabdat_ofile = cc$rms_xabdat;

    xabdat_ofile.xab$l_nxt = (XABP *)&xabrdt_ofile;

    xabrdt_ofile = cc$rms_xabrdt;

    xabrdt_ofile.xab$l_nxt = (XABP *)&xabfhc_ofile;

    xabfhc_ofile = cc$rms_xabfhc;

    xabfhc_ofile.xab$l_nxt = (XABP *)&xabpro_ofile;

    xabpro_ofile = cc$rms_xabpro;

    xabpro_ofile.xab$l_nxt = (XABP *)&xaball_ofile;

    xaball_ofile = cc$rms_xaball;



/*

 * Load 'em up

 */



    mymove(&xabpro_ofile.xab$w_pro, filptr, 2);

    filptr += 2;

    if (owner != 0)

	mymove(&xabpro_ofile.xab$l_uic, filptr, 4);

    filptr += 4;

    mymove(&fab_ofile.fab$b_rfm, filptr, 1);

    filptr += 1;

    mymove(&fab_ofile.fab$b_org, filptr, 1);

    filptr += 1;

    mymove(&fab_ofile.fab$b_rat, filptr, 1);

    filptr += 5;				/* 4 bytes reserved for char */

    mymove(&fab_ofile.fab$b_fsz, filptr, 1);

    filptr += 1;

    mymove(&xabfhc_ofile.xab$w_lrl, filptr, 2);

    filptr += 2;

    mymove(&fab_ofile.fab$w_mrs, filptr, 2);

    filptr += 2;

    mymove(&xabfhc_ofile.xab$l_ebk, filptr, 4);

    filptr += 4;

/* preserve this as RMS won't remember it for us */

    mymove(&ofile_ffb, filptr, 2);

    filptr += 2;

    mymove(&xaball_ofile.xab$l_alq, filptr, 4);

    filptr += 4;

    mymove(&xaball_ofile.xab$w_deq, filptr, 2);

    filptr += 2;

#ifdef COMMENT /* was: defined(VAX) && defined(__DECC) */

/*

   This is really annoying. The people from DEC changed xaball, but only on

   VAX not AXP!  - mpjz

*/

    mymove(&xaball_ofile.xaballdef$$_fill_7, filptr, 1);

#else

    mymove(&xaball_ofile.xab$b_bkz, filptr, 1);

#endif /* COMMENT */

    filptr += 1;

    mymove(&fab_ofile.fab$w_gbc, filptr, 2);

    filptr += 2;

    mymove(&xabfhc_ofile.xab$w_verlimit, filptr, 2);

    filptr += 2;

    mymove(&jnlflg, filptr, 1);

    if (jnlflg !=0)

      printf(

	     "Original file was marked for RMS Journaling, this copy is not.\n"

	     );

    filptr += 1;

    mymove(&xabdat_ofile.xab$q_cdt, filptr, 8);

    filptr += 8;

    mymove(&revdat, filptr, 8);

    filptr += 8;

    mymove(&revnum, filptr, 2);

    filptr += 2;

    mymove(&xabdat_ofile.xab$q_edt, filptr, 8);

    filptr += 8;

    if (backup != 0)

	mymove(&xabdat_ofile.xab$q_bdt, filptr, 8);

    filptr += 8;



/*

 * ACL's?

 */



    if(keepacl != 0 && gotacl != 0) {

	xabpro_ofile.xab$l_aclbuf = (XABP *)&vmsacl;

	xabpro_ofile.xab$w_aclsiz = acllen;

    }



/*

 * Give it a quick whirl around the dance floor

 */



    printf("Creating %s...\n", fab_ofile.fab$l_fna);

    rms_sts = sys$create(&fab_ofile);

    if (!(rms_sts & 1))

	exit(rms_sts);



    if(keepacl != 0 && gotacl != 0) {

	if (!(xabpro_ofile.xab$l_aclsts & 1))

	    exit(xabpro_ofile.xab$l_aclsts);

    }



    rms_sts = sys$connect(&rab_ofile);

    if (!(rms_sts & 1))

	exit(rms_sts);



    ofile_rec = 1;

    fread(buffer, 512, 1, infd);

    while (!feof(infd)) {

	rab_ofile.rab$l_rbf = buffer;

	rab_ofile.rab$w_rsz = 512;

	if (ofile_rec == xabfhc_ofile.xab$l_ebk) {

	    xabfhc_ofile.xab$w_ffb = ofile_ffb;

	    if (ofile_ffb)

		rab_ofile.rab$w_rsz -= (512 - ofile_ffb);

	    if (debug) {

		fprintf(stderr,"FFB (first free byte) = %d\n", ofile_ffb);

		fprintf(stderr,"Last record size = %d\n", rab_ofile.rab$w_rsz);

	    }

	}

	rms_sts = sys$write(&rab_ofile);

	if (!(rms_sts & 1))

	    exit(rms_sts);

	fread(buffer, 512, 1, infd);

	ofile_rec++;

    }



/*

 * Update the revision information

 */



    mymove(&xabrdt_ofile.xab$q_rdt, revdat, 8);

    mymove(&xabrdt_ofile.xab$w_rvn, &revnum, 2);



    rms_sts = sys$close(&fab_ofile);

    if (!(rms_sts & 1))

	exit(rms_sts);

    printf("...done.\n");

    exit(IO_SUCCESS);

}



void do_help()

{

    printf("This is CKVCVT %s\n\n", VERSION);

    printf("Usage: CKVCVT infile options\n\n");

    printf("Options:\n");

    printf("         -a     Preserve file ACL data (may require privs)\n");

    printf("         -b     Preserve file backup date\n");

    printf("         -d     Print debugging information\n");

    printf("         -f fn  Name output file fn instead of default\n");

    printf("         -i     Inquire if a file is labeled\n");

    printf("         -o     Preserve file ownership (requires privs)\n");

    printf("         -s     Strip one level of label information\n");

    printf("         -t     Don't trim paths from output file name\n");

    printf("         -?     Display this message\n\n");

    exit(IO_SUCCESS);

}



void barf(text)

char *text;

{

    if (text == "")

	fprintf(stderr, "%s: corrupted Kermit labeled file\n", infn);

    else

	fprintf(stderr, "%s: %s\n", infn, text);

    exit(IO_ERROR);

}



void strip_file()

{

    next_label:

    fread(buffer, 2, 1, infd);			/* Get label length */

    buffer[2] = '\0';

    lblen = atoi(buffer);

    if (lblen == 0)				/* Better not be zero! */

	barf("lost sync");



    fread(label, lblen, 1, infd);		/* Get the label name */

    label[lblen] = '\0';

    fread(buffer, 8, 1, infd);			/* Get the contents length */

    buffer[8] = '\0';

    lblen = atoi(buffer);

    if (strcmp(label, "DATA") == 0) {		/* If done... */

	if (lblen != 0)

	    barf("");

	if (debug)

	    fprintf(stderr, "Positioned at start of file data\n");

	goto all_set;

    }

    fread(buffer, lblen, 1, infd);		/* Else skip contents */

    goto next_label;				/* And loop */



/*

 * We've skipped the first header, now do whatever task is needed

 */



    all_set:

    if (inquire != 0) {

	printf("%s is a properly formatted Kermit labeled file\n", infn);

	exit(IO_SUCCESS);

    }



    fab_ofile = cc$rms_fab;

    fab_ofile.fab$b_fac = FAB$M_BIO | FAB$M_PUT;

    fab_ofile.fab$l_fop = FAB$M_MXV;

    fab_ofile.fab$l_fna = infn;

    fab_ofile.fab$b_fns = strlen(infn);

    fab_ofile.fab$b_rfm = FAB$C_FIX;

    fab_ofile.fab$w_mrs = 512;

    rab_ofile = cc$rms_rab;

    rab_ofile.rab$l_fab = &fab_ofile;



    printf("Stripping %s...\n", fab_ofile.fab$l_fna);

    rms_sts = sys$create(&fab_ofile);

    if (!(rms_sts & 1))

	exit(rms_sts);



    rms_sts = sys$connect(&rab_ofile);

    if (!(rms_sts & 1))

	exit(rms_sts);



    fread(buffer, 512, 1, infd);

    while (!feof(infd)) {

	rab_ofile.rab$l_rbf = buffer;

	rab_ofile.rab$w_rsz = 512;

	rms_sts = sys$write(&rab_ofile);

	if (!(rms_sts & 1))

	    exit(rms_sts);

	fread(buffer, 512, 1, infd);

    }



    rms_sts = sys$close(&fab_ofile);

    if (!(rms_sts & 1))

	exit(rms_sts);

    printf("...done.\n");

    exit(IO_SUCCESS);

}

