/*
 * CKXFIO.C
 *
 * File I/O routines for XPR C Kermit.
 *
 */

char *ckzv = "Amiga XPR file support, 5A(001), 6 August 1992";

#include "ckcdeb.h"
#include "ckcker.h"
#include "ckxker.h"

char *DELCMD = "delete ";
char *DIRCMD = "list ";
char *DIRCM2 = "list ";
char *PWDCMD = "cd ";
char *SPACMD = "info ";
char *SPACM2 = "info ";
char *TYPCMD = "type ";
char *WHOCMD = "status ";
int backgrd = 1;
int ckxech = 0;
char *ckxsys = "Amiga External Protocol";
char *ckzsys = " Amiga XPR";
int maxnam = 128;
int maxpath = 128;
int success = 1;
int fdispla = XYFD_C;		/* We always do screen displays */
char optbuf[100];		/* Option buffer for MAIL or PRINT */

/* Declarations */
 
long fp[ZNFILS] = { 			/* File pointers */
    0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L };
 
/* (PWP) external def. of things used in buffered file input and output */
#ifdef DYNAMIC
extern CHAR *zinbuffer, *zoutbuffer;
#else
extern CHAR zinbuffer[], zoutbuffer[];
#endif /* DYNAMIC */
extern CHAR *zinptr, *zoutptr;
extern int zincnt, zoutcnt;

extern long (*xupdate) (), (*xswrite) (), (*xfopen) (), (*xfclose) (),
  (*xfread) (), (*xsread) (), (*xchkabort) (), (*xfnext) (), (*xffirst) (),
  (*xsflush) (), (*xfwrite) (), (*xgets) (), (*xfinfo) (), (*xunlink)() ,
  (*xsquery) (), (*xchkmisc) ();

/*  C H K F N  --  Internal function to verify file number is ok  */

/*
 Returns:
  -1: File number n is out of range
   0: n is in range, but file is not open
   1: n in range and file is open
*/
int
chkfn(int n) {
    switch (n) {
	case ZIFILE:
	case ZOFILE:
	case ZDFILE:
	case ZTFILE:
	case ZPFILE:
	case ZSFILE:
        case ZRFILE:
        case ZWFILE: break;
	default:
	    debug(F101,"chkfn: file number out of range","",n);
	    return(-1);
    }
    return( (fp[n] == 0L) ? 0 : 1 );
}

int
iswild(char *filespec) {
   if (strchr(filespec, '?') >= 0)
      return(1);
   else
      return(0);
}

#ifndef MAXPATHLEN
#define MAXPATHLEN 256
#endif

static char zcurrent[MAXPATHLEN] = "";

int
zchdir(char *dirnam) {
   strncpy(zcurrent, dirnam, MAXPATHLEN - 1);
   return 1;
}
/*  Z C H K I  --  Check if input file exists and is readable  */
 
/*
  Returns:
   >= 0 if the file can be read (returns the size).
     -1 if file doesn't exist or can't be accessed,
     -2 if file exists but is not readable (e.g. a directory file).
     -3 if file exists but protected against read access.
*/

static long iflen;
static long iftype;

long
zchki(char *fn) {

   iflen = callad(xfinfo, fn, 1L);
   if (iflen <= 0)
      return(-1);
   else {
      iftype = callad(xfinfo, fn, 2L);
      return iflen;
   }
}
/*  Z C H K O  --  Check if output file can be created  */
 
/*
 Returns -1 if write permission for the file would be denied, 0 otherwise.
 Since we can't really do this from XPR Kermit, always return zero and
 let the zopeno() call fail.
*/

int
zchko(char *fn) {
   return 0;
   
}

/*  Z C H K S P A -- Check to see if there is enough space for the file. */

int
zchkspa(char *f, long len) {
   return 1;
}

/*  Z C H I N  --  Get a character from the input file.  */
 
/*  Returns -1 if EOF, 0 otherwise with character returned in argument  */
int
zchin(int n, int *c) {
    int a, x;

    /* (PWP) Just in case this gets called when it shoudn't */
    if (n == ZIFILE) {
	x = zminchar();
	*c = x;
	return (x);
    }

    if (calladda(xfread, &a, sizeof(char), 1, fp[n]) != 1) return(-1);
    *c = (CHAR) a & 0377;
    return(0);
}

/*  Z C H O U T  --  Add a character to the given file.  */
 
/*  Should return 0 or greater on success, -1 on failure (e.g. disk full)  */

int
zchout(int n, char c) {
   if (chkfn(n) < 1) return(-1);
   if (calladda(xfwrite, &c, sizeof(char), 1, fp[n]) != 1)
      return(-1);
   else 				/* Otherwise... */
      return(0);			/* There was no error. */
}

/*  Z C L O S E  --  Close the given file.  */

/*  Returns 0 if arg out of range, 1 if successful, -1 if close failed.  */

int
zclose(int n) {
    int x, x2;

    if (chkfn(n) < 1) return(0);	/* Check range of n */

    if ((n == ZOFILE) && (zoutcnt > 0))	/* (PWP) output leftovers */
      x2 = zoutdump();
    else
      x2 = 0;

    x = calla(xfclose, fp[n]);
    iflen = -1;				/* Invalidate file length */
    fp[n] = NULL;                       /* And file pointer */
    if (x < 0)				/* if we got a close error */
	return (-1);
    else if (x2 < 0)		/* or an error flushing the last buffer */
	return (-1);		/* then return an error */
    else
	return (1);
}

/*  Z D E L E T  --  Delete the named file.  */

int
zdelet(char *fn) {
   if (xunlink != NULL) {
      if (calla(xunlink, fn) < 0)
	return -1;
   }
   return 0;
}

/* Z G T D I R --- Return pointer to name of current directory */

char *
zgtdir(void) {
   return NULL;
}

/* Z H O M E --- Return pointer to user's home directory */

/* we return "S:", which is where startup scripts are found */
char *
zhome(void) {
   return("S:");                  /* approximately */
}

/*
 * (PWP) (re)fill the buffered input buffer with data.  All file input
 * should go through this routine, usually by calling the zminchar()
 * macro (in ckcker.h).
 */
int
zinfill(void) {
    zincnt = calladda(xfread, zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]);
    debug(F101,"zinfill zincnt","",zincnt);
    if (zincnt == 0) return (-1); /* end of file */
    zinptr = zinbuffer;	   /* set pointer to beginning, (== &zinbuffer[0]) */
    zincnt--;			/* one less char in buffer */
    return((int)(*zinptr++) & 0377); /* because we return the first */
}

int
zkself(void) {
   return -1;
}
/*  Z S T R I P  --  Strip device & directory name from file specification */

/*  Strip pathname from filename "name", return pointer to result in name2 */

static char work[256];	/* buffer for use by zstrip and zltor and others */

void
zstrip(char *name, char **name2) {
    char *cp, *pp;
    debug(F110,"zstrip before",name,0);
    pp = work;
    if ((cp = strrchr(name, ':')) == NULL)
        cp = name;
    else
        ++cp;
    for (; *cp != '\0'; cp++) {
    	if (*cp == '/')
	  pp = work;
	else
	  *pp++ = *cp;
    }
    *pp = '\0';				/* Terminate the string */
    *name2 = work;
    debug(F110,"zstrip after",*name2,0);
}
/*  Z L T O R  --  Local TO Remote */

/*  Convert filename from local format to common (remote) form.  */
 
void
zltor(char *name, char *name2) {
    char *cp, *pp;
    int dc = 0;
 
    debug(F110,"zltor",name,0);
    pp = work;
    if ((cp = strrchr(name, ':')) == NULL)
        cp = name;
    else
    	++cp;

    for (; *cp != '\0'; cp++) {	/* strip path name */
    	if (*cp == '/') {
	    dc = 0;
	    pp = work;
	}
	else if (islower(*cp)) *pp++ = toupper(*cp); /* Uppercase letters */
	else if (*cp == '~') *pp++ = 'X';	/* Change tilde to 'X' */
	else if (*cp == '#') *pp++ = 'X';	/* Change number sign to 'X' */
	else if ((*cp == '.') && (++dc > 1)) *pp++ = 'X'; /* & extra dots */
	else *pp++ = *cp;
    }
    *pp = '\0';				/* Tie it off. */
    cp = name2;				/* If nothing before dot, */
    if (*work == '.') *cp++ = 'X';	/* insert 'X' */
    strcpy(cp,work);
    debug(F110," name2",name2,0);
}    

/* Z M A I L --- Send file as mail to user */

/* Not implementable on a personal computer. */
int
zmail(char *addr, char *fn) {
   return -2;
}
/*  Z N E W N  --  Make a new name for the given file  */
 
void
znewn(char *fn,char **s) {
    static char buf[100];
    char *bp;
    int len = 0, d;
#ifdef MAXNAMLEN	
    int maxlen = MAXNAMLEN;
#else
    int maxlen = 14;
#endif
 
    bp = buf;
    while (*fn) {			/* Copy name into buf */
	*bp++ = *fn++;
	len++;
    }
    if (len > maxlen-3) bp -= 3;	/* Don't let it get too long */

    /* 
     * On the Amiga, it takes much less time to determine
     * if a given file exists than to read all the file names in
     * a directory (or even just names with a certain prefix).
     */
    d = 0;
    do {
	sprintf(bp, "~%d", ++d);
    } while (zchki(buf) != -1 && d < 100);

    *s = buf;
}

/* Z X P A N D --- Expand wild card file name list */

#define MAXWLD 300
static char *mtchs[MAXWLD],		/* Matches found for filename */
  **mtchptr;			        /* Pointer to current match */
static int fcount;                      /* Number of matches */
#define SSPACE 4000
static char sspace[SSPACE];             /* buffer to generate names in */

int
zxpand(char *fn) {
   char *sptr = sspace;
   long state;

   if ((state = callaa(xffirst, work, fn)) == 0)
      return 0;
   if (strlen(work) >= SSPACE)          /* Unlikely */
      return -1;
   strcpy(sptr, work);
   mtchs[0] = sptr;
   mtchptr = mtchs;
   fcount = 1;
   sptr += (strlen(sptr) + 1);
   while ((state = calldaa(xfnext, state, work, fn)) != 0) {
      if (sptr - sspace + strlen(work) >= SSPACE)
	 return -1;
      strcpy(sptr, work);
      mtchs[fcount++] = sptr;
      sptr += (strlen(sptr) + 1);
   }
   return(fcount);
}

/*  Z N E X T  --  Get name of next file from list created by zxpand(). */
/*
 Returns >0 if there's another file, with its name copied into the arg string,
 or 0 if no more files in list.
*/
int
znext(char *fn) {
    if (fcount-- > 0)
       strcpy(fn,*mtchptr++);
    else
       *fn = '\0';
    debug(F111,"znext",fn,fcount+1);
    return(fcount+1);
}

/*  Z O P E N I  --  Open an existing file for input. */

int
zopeni(int n, char *fn) {
   if (chkfn(n) != 0)
      return 0;
   fp[n] = callaa(xfopen, fn, "r");		/* Real file. */
   debug(F111," zopeni", name, (int) fp[n]);
   return((fp[n] != 0L) ? 1 : 0);
}

/*  Z O P E N O  --  Open a new file for output.  */
int
zopeno(int n, char *name, struct zattr *zz, struct filinfo *fcb) {

    char *p;		/* Local use pointer */

    if (fcb) {	
	debug(F101,"zopeno fcb disp","",fcb->dsp);
	debug(F101,"zopeno fcb type","",fcb->typ);
	debug(F101,"zopeno fcb char","",fcb->cs);
    } else {
	debug(F100,"zopeno fcb is NULL","",0);
    }
    if (n != ZDFILE)
      debug(F111," zopeno",name,n);
    if (chkfn(n) != 0) return(0);
    p = "w";				/* Assume write/create mode */
    if (fcb) {				/* If called with an FCB... */
	if (fcb->dsp == XYFZ_A)		/* Does it say Append? */
	  p = "a";			/* Yes. */
    }
    fp[n] = callaa(xfopen, name, p);	/* Open the file */

    if (fp[n] == 0L)
       perror("zopeno can't open");
    zoutcnt = 0;		/* (PWP) reset output buffer */
    zoutptr = zoutbuffer;
    if (n != ZDFILE)
       debug(F101, " fp[n]", "", (int) fp[n]);
    return((fp[n] != 0L) ? 1 : 0);
}

/* (PWP) buffered character output routine to speed up file IO */
int
zoutdump(void) {
    int x;
    zoutptr = zoutbuffer;		/* reset buffer pointer in all cases */
    debug(F101,"zoutdump chars","",zoutcnt);
    if (zoutcnt == 0) {			/* nothing to output */
	return(0);
    } else if (zoutcnt < 0) {		/* unexpected negative value */
	zoutcnt = 0;			/* reset output buffer count */
	return(-1);			/* and fail. */
    }
    if (x = calladda(xfwrite, zoutbuffer, 1, zoutcnt, fp[ZOFILE])) {
	debug(F101,"zoutdump fwrite wrote","",x);
	zoutcnt = 0;			/* reset output buffer count */
	return(0);			/* things worked OK */
    } else {
	zoutcnt = 0;			/* reset output buffer count */
	debug(F101,"zoutdump fwrite error","",x);
	return(x ? -1 : 0);		/* return failure if error */
    }
}

int
zprint(char *p, char *f) {
   return 0;
}

int
zrename(char *fn, char *fn2) {
   return 0;
}

/*  Z R T O L  --  Convert remote filename into local form  */
 
/*  For AMIGA, this means changing uppercase letters to lowercase.  */
 
void
zrtol(char *name, char *name2) {
    for ( ; *name != '\0'; name++) {
    	*name2++ = isupper(*name) ? tolower(*name) : *name;
    }
    *name2 = '\0';
    debug(F110,"zrtol:",name2,0);
}

int
zsattr(struct zattr *xx) {
   long k;

   k = iflen % 1024L;                   /* File length in K */
   if (k != 0L) k = 1L;
   xx->lengthk = (iflen / 1024L) + k;
   if (iftype == 1L)
      xx->type.val = "text";
   else
      xx->type.val = "binary";
   xx->type.len = strlen(xx->type.val);
   xx->date.len = 0;
   xx->date.val = "";
    xx->creator.len = 0;		/* File creator */
    xx->creator.val = "";
    xx->account.len = 0;		/* File account */
    xx->account.val = "";
    xx->area.len = 0;			/* File area */
    xx->area.val = "";
    xx->passwd.len = 0;			/* Area password */
    xx->passwd.val = "";
    xx->blksize = -1L;			/* File blocksize */
    xx->access.len = 0;			/* File access */
    xx->access.val = "";
    xx->encoding.len = 0;		/* Transfer syntax */
    xx->encoding.val = 0;
    xx->disp.len = 0;			/* Disposition upon arrival */
    xx->disp.val = "";
    xx->lprotect.len = 0;		/* Local protection */
    xx->lprotect.val = "";
    xx->gprotect.len = 0;		/* Generic protection */
    xx->gprotect.val = "";
    xx->systemid.len = 2;		/* System ID length */
    xx->systemid.val = "L3";		/* Amiga system ID code */
    xx->recfm.len = 0;			/* Record format */
    xx->recfm.val = "";
    xx->sysparam.len = 0;		/* System-dependent parameters */
    xx->sysparam.val = "";
    xx->length = iflen;			/* Length */
    return(0);
}

int
zshcmd(char *s) {
   return -1;
}

int
zsyscmd(char *s) {
   return -1;
}

/*  Z S I N L  --  Read a line from a file  */

/*
  Writes the line into the address provided by the caller.
  n is the Kermit "channel number".
  Writing terminates when newline is encountered, newline is not copied.
  Writing also terminates upon EOF or if length x is exhausted.
  Returns 0 on success, -1 on EOF or error.
*/
int
zsinl(int n, char *s, int x) {
    int z = 0, a;

    if (chkfn(n) < 1) {			/* Make sure file is open */
	return(-1);
    }
    while (x--) {
	if (zchin(n,&a) < 0) {		/* Read a character from the file */
	    z = -1;
	    break;
	}
	if (a == '\n') break;
	*s = a;
	s++;
    }
    *s = '\0';
    return(z);
}

/*  Z S O U T  --  Write a string to the given file, buffered.  */
int
zsout(int n, char *s) {
   if (chkfn(n) < 1) return(-1);
   if (strlen(s) == 0)
      return 0;
   if (calladda(xfwrite, s, sizeof(char), strlen(s), fp[n]) <= 0)
      return -1;
   return(strlen(s));
}
 
/*  Z S O U T L  --  Write string to file, with line terminator, buffered  */
int
zsoutl(int n, char *s) {
    if (chkfn(n) < 1) return(-1);
    if (strlen(s) > 0)
       if (calladda(xfwrite, s, sizeof(char), strlen(s), fp[n]) <= 0)
	  return -1;
    if (calladda(xfwrite, "\n", sizeof(char), 1, fp[n]) <= 0)
       return -1;;
    return(0);
}

int
zsoutx(int n, char *s, int x) {
   if (x > 0)
      if (calladda(xfwrite, s, sizeof(char), x, fp[n]) != x)
	 return -1;
   return x;
}

int
zstime(char *f, struct zattr *yy, int x) {
   return 0;
}

int
zxcmd(int n, char *s) {
   return 0;
}

int
xsystem(char *cmd) {
   return -1;
}

int
priv_ini(void) {
   return 0;
}

int
priv_on(void) {
   return 0;
}

int
priv_off(void) {
   return 0;
}

int
priv_can(void) {
   return 0;
}


int
priv_chk(void) {
   return 0;
}
