Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1414 lines
32 KiB

/* zmdm_rcv.c -- ZMODEM compatible file receiving routines for HyperACCESS
*
* Copyright 1990 by Hilgraeve Inc. -- Monroe, MI
* All rights reserved
*
* $Revision: 15 $
* $Date: 7/12/02 8:35a $
*/
#include <windows.h>
#pragma hdrstop
//#define DEBUGSTR
#include <setjmp.h>
#include <time.h>
#include <term\res.h>
#include <sys\types.h>
#include <sys\utime.h>
#include <tdll\stdtyp.h>
#include <tdll\mc.h>
#include <tdll\com.h>
#include <tdll\assert.h>
#include <tdll\session.h>
#include <tdll\load_res.h>
#include <tdll\xfer_msc.h>
#include <tdll\globals.h>
#include <tdll\file_io.h>
#include <tdll\file_msc.h>
#include <tdll\htchar.h>
#define BYTE unsigned char
#include "itime.h"
#include "xfr_dsp.h"
#include "xfr_todo.h"
#include "xfr_srvc.h"
#include "xfer.h"
#include "xfer.hh"
#include "xfer_tsc.h"
#include "foo.h"
#include "zmodem.hh"
#include "zmodem.h"
/* * * * * * * * * * * * *
* Function Prototypes *
* * * * * * * * * * * * */
#if defined(DEBUG_DUMPPACKET)
#include <stdio.h>
FILE* fpPacket;
#endif // defined(DEBUG_DUMPPACKET)
int procheader (ZC *zc, TCHAR *name);
int putsec (ZC *zc, BYTE *buf, int n);
int isvalid (TCHAR c, int base);
TCHAR *stoi (TCHAR *ptr, int *val, int base);
TCHAR *stol (TCHAR *ptr, long *val, int base);
int IsAnyLower (TCHAR *s);
long getfree (void);
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* zmdm_rcv
*
* DESCRIPTION:
*
* ARGUMENTS:
*
* RETURNS:
*
*/
USHORT zmdm_rcv(HSESSION h, int method, int attended, int single_file)
{
ZC *zc = NULL;
BOOL still_trying = TRUE;
BOOL override = FALSE;
int nJmpVal = 0;
int xstatus;
unsigned int uiOldOptions;
int tvar;
TCHAR ch;
XFR_Z_PARAMS *pZ;
#if defined(DEADWOOD)
DWORD nLen;
#endif // defined(DEADWOOD)
#if defined(DEBUG_DUMPPACKET)
fpPacket = fopen("zpacket.dbg", "a");
assert(fpPacket);
fputs("----- Starting Zmodem rcv -----\n", fpPacket);
#endif // defined(DEBUG_DUMPPACKET)
(void)&single_file;
xstatus = TSC_NO_MEM;
zc = malloc(sizeof(ZC));
if (zc == NULL)
{
xstatus = TSC_NO_MEM;
goto done;
}
memset(zc, 0, sizeof(ZC));
zc->nMethod = method; // Zmodem, or Zmodem crash recovery
// This makes it easy to override some settings when
// Zmodem crash recovery is selected.
if (method == XF_ZMODEM_CR)
{
zc->fSavePartial = TRUE; // Leave partial files around
zc->ulOverride = XFR_RO_ALWAYS; // Always overwrite existing file
}
else
{
// Use default settings otherwise.
//
zc->fSavePartial = xfer_save_partial(h);
zc->ulOverride = (unsigned long)0;
}
zc->hSession = h;
zc->hCom = sessQueryComHdl(h);
zc->secbuf = NULL;
zc->fname = NULL;
zc->our_fname = NULL;
zc->z_crctab = NULL;
zc->z_cr3tab = NULL;
/* allocate space for large packets since we don't necessarily know what
* we'll be getting.
*/
zc->secbuf = malloc(1025 * sizeof(TCHAR));
if (zc->secbuf == NULL)
{
xstatus = TSC_NO_MEM;
goto done;
}
zc->fname = malloc(FNAME_LEN * sizeof(TCHAR));
if (zc->fname == NULL)
{
xstatus = TSC_NO_MEM;
goto done;
}
zc->our_fname = malloc(FNAME_LEN * sizeof(TCHAR));
if (zc->our_fname == NULL)
{
xstatus = TSC_NO_MEM;
goto done;
}
#if defined(DEADWOOD)
resLoadDataBlock(glblQueryDllHinst(),
IDT_CSB_CRC_TABLE,
&zc->z_crctab,
&nLen);
assert(nLen != 0);
#else // defined(DEADWOOD)
zc->z_crctab = usCrc16Lookup;
#endif // defined(DEADWOOD)
if (zc->z_crctab == NULL)
{
xstatus = TSC_NO_MEM;
goto done;
}
#if defined(DEADWOOD)
resLoadDataBlock(glblQueryDllHinst(),
IDT_CRC_32_TAB,
&zc->z_cr3tab,
&nLen);
assert(nLen != 0);
#else // defined(DEADWOOD)
zc->z_cr3tab = ulCrc32Lookup;
#endif // defined(DEADWOOD)
if (zc->z_cr3tab == NULL)
{
xstatus = TSC_NO_MEM;
goto done;
}
xstatus = TSC_OK;
if (xfer_set_comport(h, FALSE, &uiOldOptions) != TRUE)
{
goto done;
}
else
{
override = TRUE;
}
zmdm_retval (zc, TRUE, ZACK);
zc->file_bytes = 0L;
zc->real_bytes = 0L;
zc->total_bytes = 0L;
zc->actual_bytes = 0L;
zc->nSkip = FALSE;
zc->fh = NULL;
zc->pstatus = zc->last_event = -4;
zc->xfertimer = -1L;
zc->nfiles = 0;
zc->filen = 0;
zc->filesize = -1L;
zc->nbytes = -1L;
zc->errors = 0;
// Capture the current execution environment into the flagkey_buf buffer.
// The Trow() function will later use it to restore the execution
// environment (i.e., the state of all system registers and the instruction
// counter.
//
nJmpVal = setjmp(zc->flagkey_buf);
if (nJmpVal != 0)
{
if (nJmpVal == 4)
{
xstatus = TSC_DISK_FULL;
zmdm_retval(zc, TRUE, ZFERR);
}
else
{
xstatus = TSC_USER_CANNED;
zmdm_retval(zc, TRUE, ZCAN);
}
zc->xfertime = (long)interval(zc->xfertimer);
stohdr(zc, 0L);
zshhdr(zc, ZCAN, zc->Txhdr);
canit(zc);
if (zc->fh)
xfer_close_rcv_file(h,
zc->fh,
xstatus,
zc->fname,
zc->our_fname,
zc->fSavePartial,
zc->basesize + zc->filesize,
0);
zc->fh = NULL;
// zmdm_retval(zc, TRUE, ZABORT); jkh, 2/12/95 see above
goto done;
}
pZ = (XFR_Z_PARAMS *)xfer_get_params(zc->hSession, zc->nMethod);
assert(pZ);
if (pZ == NULL)
{
xstatus = TSC_NO_MEM;
goto done;
}
zc->Zctlesc = pZ->nEscCtrlCodes;
zc->Rxtimeout = pZ->nRetryWait;
if (zc->Rxtimeout <= 0)
{
zc->Rxtimeout = 10;
}
zc->Rxtimeout *= 10;
zc->do_init = TRUE; // Always start right up since we may be autostarted
zc->tryzhdrtype = ZRINIT;
if (tryz(zc) == ZFILE)
{
// tzset();
if (zc->xfertimer == (-1L))
{
zc->xfertimer = (long)startinterval();
}
// Receive files with Z-modem protocol.
//
switch (xstatus = rzfiles(zc))
{
case OK:
xstatus = TSC_OK;
break;
case ZABORT:
xstatus = TSC_USER_CANNED;
do {
// purgeline(zc);
ComRcvBufrClear(zc->hCom);
Sleep(100);
} while (mComRcvBufrPeek(zc->hCom, &ch) != 0);
// } while (rdchk(h) != ERROR);
/* we try to eat any characters until the other end quits */
break;
case RCDO: /* Not too sure about this one */
case ZCARRIER_LOST:
xstatus = TSC_LOST_CARRIER;
break;
case ERROR:
canit(zc);
/* fall through */
case ZMDM_VIRUS:
do {
// purgeline(zc);
ComRcvBufrClear(zc->hCom);
Sleep(100);
} while (mComRcvBufrPeek(zc->hCom, &ch) != 0);
// } while (rdchk(zc) != ERROR);
/* fall thru to the default case */
default:
xstatus = zmdm_error(zc, xstatus);
break;
}
}
done:
zmdmr_progress(zc, TRANSFER_DONE);
if (override)
{
xfer_restore_comport(h, uiOldOptions);
}
// Fool around with the return code to get a useful status return
if ((tvar = zmdm_retval(zc, FALSE, 0)) != ZACK)
// Retrieve last error message
{
if (tvar == ZMDM_VIRUS)
{
do {
// purgeline(zc);
ComRcvBufrClear(zc->hCom);
Sleep(100);
} while (mComRcvBufrPeek(zc->hCom, &ch) != 0);
// } while (rdchk(zc) != ERROR);
}
xstatus = zmdm_error(zc, tvar);
}
if (xstatus != TSC_OK)
{
if (zc->fh)
{
xfer_close_rcv_file(h,
zc->fh,
xstatus,
zc->fname,
zc->our_fname,
zc->fSavePartial,
zc->basesize + zc->filesize,
0);
}
}
if (zc->secbuf != NULL)
{
free(zc->secbuf);
zc->secbuf = NULL;
}
if (zc->fname != NULL)
{
free(zc->fname);
zc->fname = NULL;
}
if (zc->our_fname != NULL)
{
free(zc->our_fname);
zc->our_fname = NULL;
}
if (zc->z_crctab != NULL)
{
#if defined(DEADWOOD)
resFreeDataBlock(h, zc->z_crctab);
zc->z_crctab = NULL;
#else // defined(DEADWOOD
//
// We don't need to free zc->z_crctab since it is pointing
// to a static constant array. REV: 4/10/2002
//
zc->z_crctab = NULL;
#endif // defined(DEADWOOD)
}
if (zc->z_cr3tab)
{
#if defined(DEADWOOD)
resFreeDataBlock(h, zc->z_cr3tab);
zc->z_cr3tab = NULL;
#else // defined(DEADWOOD
//
// We don't need to free zc->z_cr3tab since it is pointing
// to a static constant array. REV: 4/10/2002
//
zc->z_cr3tab = NULL;
#endif // defined(DEADWOOD)
}
if (zc != NULL)
{
free(zc);
zc = NULL;
}
xferMsgClose(h);
#if defined(DEBUG_DUMPPACKET)
fputs("------- Ending Zmodem rcv -----\n", fpPacket);
fclose(fpPacket);
#endif // defined(DEBUG_DUMPPACKET)
return((USHORT)xstatus);
}
/*----------------------------------------------------------------------+
| getfree - Calculates the free bytes on the current file system.
| ~0 means many free bytes (unknown).
+----------------------------------------------------------------------*/
long getfree(void)
{
return(~0L); /* many free bytes ... */
}
/*----------------------------------------------------------------------+
| tryz - Initialize for ZMODEM receive attempt, try to activate ZMODEM
| sender. Handles ZSINIT frame. Returns ZFILE if ZMODEM filename
| received, -1 on error, ZCOMPL if transaction finished, else 0.
+----------------------------------------------------------------------*/
int tryz(ZC *zc)
{
register int c;
register int n;
int x;
int retrys;
for ( n = 10; --n >= 0; )
{
/* Set buffer length (0) and capability flags */
stohdr(zc, 0L);
/* Do we need an option to set the block size ? */
zc->Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO /* |CANBRK */ ;
if (zc->Zctlesc)
zc->Txhdr[ZF0] |= TESCCTL;
if (n <= 8)
zc->do_init = TRUE;
if (zc->do_init)
zshhdr(zc, zc->tryzhdrtype, zc->Txhdr);
if (zc->tryzhdrtype == ZSKIP) /* Don't skip too far */
zc->tryzhdrtype = ZRINIT; /* CAF 8-21-87 */
retrys = 25;
again:
switch (x = xfer_user_interrupt(zc->hSession))
{
case XFER_ABORT:
zmdmr_update(zc, ZCAN);
longjmp(zc->flagkey_buf, 1);
break;
case XFER_SKIP:
/* This MUST only happen while receiving */
stohdr(zc, zc->filesize);
#if defined(DEBUG_DUMPPACKET)
fputs("tryz: User skipped. ZRPOS\n", fpPacket);
#endif // defined(DEBUG_DUMPPACKET)
zshhdr(zc, ZRPOS, zc->Txhdr);
zc->nSkip = TRUE;
zc->file_bytes = zc->filesize;
break;
default:
break;
}
if (xfer_carrier_lost(zc->hSession))
{
zmdm_retval(zc, TRUE, ZCARRIER_LOST);
return ZCARRIER_LOST;
}
switch (zgethdr(zc, zc->Rxhdr, 'R'))
{
case ZRQINIT:
zc->do_init = TRUE;
continue;
case ZEOF:
zc->do_init = TRUE;
continue;
case TIMEOUT:
continue;
case ZFILE:
zc->zconv = zc->Rxhdr[ZF0];
zc->zmanag = zc->Rxhdr[ZF1];
zc->ztrans = zc->Rxhdr[ZF2];
zc->tryzhdrtype = ZRINIT;
c = zrdata(zc, zc->secbuf, 1024);
/* mode(3); TODO: figure out what this was supposed to do */
if (c == GOTCRCW)
return ZFILE;
if (--retrys <= 0)
{
zmdm_retval(zc, TRUE, ZNAK);
return ZNAK;
}
zshhdr(zc, ZNAK, zc->Txhdr);
goto again;
case ZSINIT:
zc->Zctlesc = TESCCTL & zc->Rxhdr[ZF0];
if (zrdata(zc, zc->Attn, ZATTNLEN) == GOTCRCW)
{
stohdr(zc, 1L);
zshhdr(zc, ZACK, zc->Txhdr);
goto again;
}
if (--retrys <= 0)
{
zmdm_retval(zc, TRUE, ZNAK);
return ZNAK;
}
zshhdr(zc, ZNAK, zc->Txhdr);
goto again;
case ZFREECNT:
stohdr(zc, getfree());
zshhdr(zc, ZACK, zc->Txhdr);
goto again;
case ZCOMMAND:
zmdm_retval(zc, TRUE, ZCOMMAND);
return ZCOMMAND;
case ZCOMPL:
goto again;
default:
zc->do_init = TRUE;
continue;
case ZFIN:
zc->xfertime = (long)interval(zc->xfertimer);
ackbibi(zc);
return ZCOMPL;
case ZCAN:
zmdm_retval(zc, TRUE, ZABORT);
return ZCAN;
}
}
zmdm_retval(zc, TRUE, TIMEOUT);
return TIMEOUT;
}
/*----------------------------------------------------------------------+
| rzfiles - Receive 1 or more files with ZMODEM protocol.
+----------------------------------------------------------------------*/
int rzfiles(ZC *zc)
{
register int c;
register int d;
for (;;)
{
switch (c = rzfile(zc))
{
case ZEOF:
case ZSKIP:
switch (d = tryz(zc))
{
case ZCOMPL:
return OK;
default:
return d;
case ZFILE:
break;
}
continue;
case ERROR:
default:
return c;
}
}
}
/*----------------------------------------------------------------------+
| rzfile - Receive single file with ZMODEM protocol.
| NOTE: Assumes file name frame is in secbuf.
+----------------------------------------------------------------------*/
int rzfile(ZC *zc)
{
register int c;
register int n;
int x;
int fBlocking = FALSE;
long lBlockStart = 0L;
zc->Eofseen = FALSE;
zc->file_bytes = 0L;
zc->real_bytes = 0L;
if (procheader(zc, (TCHAR *)zc->secbuf) == ERROR)
{
return (zc->tryzhdrtype = ZSKIP);
}
n = 20;
for (;;)
{
// If we're blocking and we've timed out, reset for another ZRPOS
if( fBlocking && (long)interval( lBlockStart ) > 100L )
fBlocking = FALSE;
// If we're not blocking already, set up for ZRPOS
if( ! fBlocking )
{
DbgOutStr( "Sending ZRPOS to %ld", zc->file_bytes, 0, 0, 0, 0 );
stohdr(zc, zc->file_bytes);
#if defined(DEBUG_DUMPPACKET)
fprintf(fpPacket, "rzfile: ZRPOS to %ld\n", zc->file_bytes);
#endif // defined(DEBUG_DUMPPACKET)
zshhdr(zc, ZRPOS, zc->Txhdr);
fBlocking = 1;
lBlockStart = (long)startinterval( );
DbgOutStr("Now blocked at t=%lu",lBlockStart,0,0,0,0);
}
nxthdr:
switch (x = xfer_user_interrupt(zc->hSession))
{
case XFER_ABORT:
zmdmr_update(zc, ZCAN);
longjmp(zc->flagkey_buf, 1);
break;
case XFER_SKIP:
/* This MUST only happen while receiving */
stohdr(zc, zc->filesize);
#if defined(DEBUG_DUMPPACKET)
fputs("rzfile: User skipped (1). ZRPOS\n", fpPacket);
#endif // defined(DEBUG_DUMPPACKET)
zshhdr(zc, ZRPOS, zc->Txhdr);
zc->nSkip = TRUE;
zc->file_bytes = zc->filesize;
break;
default:
break;
}
if (xfer_carrier_lost(zc->hSession))
{
zmdm_retval(zc, TRUE, ZCARRIER_LOST);
return ZCARRIER_LOST;
}
switch (c = zgethdr(zc, zc->Rxhdr, 'R'))
{
default:
if (--n < 0) /* A little fix from Delrina */
{
/* return ERROR; */
DbgOutStr("ZMODEM error %s %d\r\n", TEXT(__FILE__), __LINE__,0,0,0);
zmdm_retval(zc, TRUE, c);
return c;
}
continue;
case ZCARRIER_LOST:
zmdm_retval(zc, TRUE, ZCARRIER_LOST);
return c;
case ZNAK:
case TIMEOUT:
if ( --n < 0)
{
/* return ERROR; */
DbgOutStr("ZMODEM error %s %d\r\n", TEXT(__FILE__), __LINE__,0,0,0);
zmdm_retval(zc, TRUE, TIMEOUT);
return c;
}
continue; /* Another fix from Delrina */
case ZFILE:
if( fBlocking )
{
DbgOutStr( "rzfile: ZFILE && fBlocking!\n", 0, 0, 0, 0, 0 );
}
else
zrdata(zc, zc->secbuf, 1024);
continue;
case ZEOF:
if (rclhdr(zc->Rxhdr) != zc->file_bytes)
{
/*
* Ignore eof if it's at wrong place - force
* a timeout because the eof might have gone
* out before we sent our zrpos.
*/
goto nxthdr;
}
if (closeit(zc))
{
DbgOutStr("ZMODEM error %s %d\r\n", TEXT(__FILE__), __LINE__,0,0,0);
zc->tryzhdrtype = ZFERR;
/* return ERROR; */
return ZEOF;
}
zmdmr_progress(zc, FILE_DONE);
return c;
case ERROR: /* Too much garbage in header search error */
if ( --n < 0)
{
DbgOutStr("ZMODEM error %s %d\r\n", TEXT(__FILE__), __LINE__,0,0,0);
zmdm_retval(zc, TRUE, ERROR);
return ERROR;
}
if( ! fBlocking )
zmputs(zc, zc->Attn);
continue;
case ZSKIP:
closeit(zc);
zmdmr_progress(zc, FILE_DONE);
return c;
case ZDATA:
if( ! fBlocking )
{
if( rclhdr(zc->Rxhdr) != zc->file_bytes)
{
// DbgOutStr( "rzfile: ZDATA: n=%d\n", n, 0, 0, 0, 0 );
if ( --n < 0)
{
DbgOutStr("ZMODEM error %s %d", TEXT(__FILE__), __LINE__,0,0,0);
#if defined(DEBUG_DUMPPACKET)
fprintf(fpPacket, "rzfile: ZDATA pos = 0x%08lX vs. 0x%08lX\n",
rclhdr(zc->Rxhdr), zc->file_bytes);
#endif // defined(DEBUG_DUMPPACKET)
zmdm_retval(zc, TRUE, ZBADFMT);
return ERROR;
}
zmputs(zc, zc->Attn); continue;
}
}
else
{
// Did sender finally respond to our ZRPOS?
if( rclhdr(zc->Rxhdr) == zc->file_bytes )
{
// DbgOutStr("Now unblocked after %lu t-sec\n",interval(lBlockStart),0,0,0,0);
fBlocking = FALSE;
}
else
{
// Read the buffer and toss it
c = zrdata(zc, zc->secbuf, 1024);
continue;
}
}
moredata:
zmdmr_update(zc, ZDATA);
switch (x = xfer_user_interrupt(zc->hSession))
{
case XFER_ABORT:
zmdmr_update(zc, ZCAN);
longjmp(zc->flagkey_buf, 1);
break;
case XFER_SKIP:
/* This MUST only happen while receiving */
stohdr(zc, zc->filesize);
#if defined(DEBUG_DUMPPACKET)
fputs("rzfile: User skipped (2). ZRPOS\n", fpPacket);
#endif // defined(DEBUG_DUMPPACKET)
zshhdr(zc, ZRPOS, zc->Txhdr);
zc->nSkip = TRUE;
zc->file_bytes = zc->filesize;
break;
default:
break;
}
if (xfer_carrier_lost(zc->hSession))
{
DbgOutStr("ZMODEM error %s %d\r\n", TEXT(__FILE__), __LINE__,0,0,0);
zmdm_retval(zc, TRUE, ZCARRIER_LOST);
return ZCARRIER_LOST;
}
switch (c = zrdata(zc, zc->secbuf, 1024))
{
case ZCAN:
zmdm_retval(zc, TRUE, ZABORT);
return c;
case ERROR: /* CRC error */
if ( --n < 0)
{
DbgOutStr("ZMODEM error %s %d\r\n", TEXT(__FILE__), __LINE__,0,0,0);
zmdm_retval(zc, TRUE, ERROR);
return ERROR;
}
zmputs(zc, zc->Attn);
continue;
case TIMEOUT:
if ( --n < 0)
{
/* return ERROR; */
DbgOutStr("ZMODEM error %s %d\r\n", TEXT(__FILE__), __LINE__,0,0,0);
zmdm_retval(zc, TRUE, c);
return c;
}
continue;
case GOTCRCW:
n = 20;
putsec(zc, zc->secbuf, zc->Rxcount);
zc->file_bytes += zc->Rxcount;
zc->real_bytes += zc->Rxcount;
zmdmr_update(zc, ZMDM_ACKED);
zmdmr_progress(zc, 0);
stohdr(zc, zc->file_bytes);
zshhdr(zc, ZACK, zc->Txhdr);
sendline(zc, &zc->stP, XON);
goto nxthdr;
case GOTCRCQ:
n = 20;
putsec(zc, zc->secbuf, zc->Rxcount);
zc->file_bytes += zc->Rxcount;
zc->real_bytes += zc->Rxcount;
zmdmr_update(zc, ZMDM_ACKED);
zmdmr_progress(zc, 0);
stohdr(zc, zc->file_bytes);
zshhdr(zc, ZACK, zc->Txhdr);
goto moredata;
case GOTCRCG:
n = 20;
putsec(zc, zc->secbuf, zc->Rxcount);
zc->file_bytes += zc->Rxcount;
zc->real_bytes += zc->Rxcount;
zmdmr_progress(zc, 0);
goto moredata;
case GOTCRCE:
n = 20;
putsec(zc, zc->secbuf, zc->Rxcount);
zc->file_bytes += zc->Rxcount;
zc->real_bytes += zc->Rxcount;
zmdmr_progress(zc, 0);
goto nxthdr;
}
} /* switch */
} /* end for */
}
/*----------------------------------------------------------------------+
| zmputs - Send a string to the modem, processing for \336 (sleep 1 sec)
| and \335 (break signal).
+----------------------------------------------------------------------*/
void zmputs(ZC *zc, char *s)
{
register c;
while (*s)
{
switch (c = *s++)
{
case '\336':
Sleep(1000);
continue;
case '\335':
/* TODO: put in a call to sendbreak */
// sendbreak(h);
continue;
default:
sendline(zc, &zc->stP, (UCHAR)c);
}
}
}
/*----------------------------------------------------------------------+
| IsAnyLower - Returns TRUE if string s has lower case letters.
+----------------------------------------------------------------------*/
int IsAnyLower(char *s)
{
for ( ; *s; ++s)
// Don't use this stuff in a Chicago DLL
// if (islower(*s))
if ((*s >= 'a') && (*s <= 'z'))
return TRUE;
return FALSE;
}
/*----------------------------------------------------------------------+
| closeit - Close the receive dataset, return OK or ERROR
+----------------------------------------------------------------------*/
int closeit(ZC *zc)
{
// struct utimbuf timep;
int reason;
XFR_PARAMS *pX;
reason = TSC_COMPLETE; /* TODO: Get the real reason */
if (zc->nSkip)
{
reason = TSC_USER_SKIP;
}
if (xfer_close_rcv_file(zc->hSession,
zc->fh,
reason,
zc->fname,
zc->our_fname,
zc->fSavePartial,
0,
0) == ERROR)
{
return ERROR;
}
zc->fh = NULL;
zc->actual_bytes += zc->real_bytes;
zc->real_bytes = 0L;
zc->total_bytes += zc->file_bytes;
zc->file_bytes = 0L;
zc->filesize = 0L;
zc->nSkip = FALSE;
pX = (XFR_PARAMS *)0;
xfrQueryParameters(sessQueryXferHdl(zc->hSession), (VOID **)&pX);
if ((pX != (XFR_PARAMS *)0) && (pX->fUseDateTime))
{
if (zc->Modtime)
{
// BYTE acName[FNAME_LEN];
// zc->Modtime += timezone; /* Convert from GMT to local timezone */
// timep.actime = time(NULL);
// timep.modtime = zc->Modtime;
// CharToOem(zc->our_fname, acName);
// utime(acName, (void FAR *)&timep);
itimeSetFileTime(zc->our_fname, zc->Modtime);
}
}
// Disable this, it needs conversion and we only ever got complaints
// about it anyway
//if ((zc->Filemode & S_IFMT) == S_IFREG)
// far_chmod(zc->our_fname, (07777 & zc->Filemode));
return OK;
}
/*----------------------------------------------------------------------+
| ackbibi - Ack a ZFIN packet, let byegones be byegones
+----------------------------------------------------------------------*/
void ackbibi(ZC *zc)
{
register int n;
stohdr(zc, 0L);
for (n = 3; --n >= 0; )
{
// purgeline(zc);
ComRcvBufrClear(zc->hCom);
zshhdr(zc, ZFIN, zc->Txhdr);
// switch (readline(h, 100))
switch (readline(zc, zc->Rxtimeout)) // Mobidem
{
case 'O':
// readline(h, 1); /* Discard 2nd 'O' */
readline(zc, zc->Rxtimeout); /* Discard 2nd 'O' */ // Mobidem
return;
case RCDO:
return;
case TIMEOUT:
default:
break;
}
}
}
/*----------------------------------------------------------------------+
| isvalid
+----------------------------------------------------------------------*/
int isvalid(char c, int base)
{
if (c < '0')
return FALSE;
switch (base)
{
case 8:
if (c > '7')
return FALSE;
break;
case 10:
if (c > '9')
return FALSE;
break;
case 16:
if (c <= '9')
return TRUE;
// Don't use this stuff in a Chicago DLL
// if (toupper(c) < 'A')
// return FALSE;
//if (toupper(c) > 'F')
// return FALSE;
if ((c >= 'a') && (c <= 'f'))
break;
if ((c >= 'A') && (c <= 'F'))
break;
return FALSE;
}
return TRUE;
}
/*----------------------------------------------------------------------+
| ourspace -- replacement for isspace
+----------------------------------------------------------------------*/
int ourspace(char c)
{
if (c == 0x20)
return TRUE;
if ((c >= 0x9) && (c <= 0xD))
return TRUE;
return FALSE;
}
/*----------------------------------------------------------------------+
| stoi - string to integer.
+----------------------------------------------------------------------*/
char *stoi(char *ptr, int *val, int base)
{
int cnt;
if (ptr == NULL)
return NULL;
// Don't do this in a Chicago DLL
// while ((*ptr) && (isspace(*ptr)))
while ((*ptr) && ourspace(*ptr))
ptr++;
cnt = 0;
while ((*ptr) && (isvalid(*ptr, base)))
{
cnt *= base;
cnt += (*ptr++ - '0');
}
*val = cnt;
return ptr;
}
/*----------------------------------------------------------------------+
| stol - string to long.
+----------------------------------------------------------------------*/
char *stol(char *ptr, long *val, int base)
{
long cnt;
if (ptr == NULL)
return NULL;
// Don't do this in a Chicago DLL
// while ((*ptr) && (isspace(*ptr)))
while ((*ptr) && (ourspace(*ptr)))
ptr++;
cnt = 0;
while ((*ptr) && (isvalid(*ptr, base)))
{
cnt *= base;
cnt += (*ptr++ - '0');
}
*val = cnt;
return ptr;
}
/*----------------------------------------------------------------------+
| procheader - Process incoming file information header.
+----------------------------------------------------------------------*/
int procheader(ZC *zc, TCHAR *name)
{
int zRecover = FALSE;
int lconv = 0;
int file_err;
register char *p;
int serial_number;
int files_remaining;
long bytes_remaining;
long our_size;
LONG lOptions = 0;
XFR_Z_PARAMS *pZ;
struct st_rcv_open stRcv;
TCHAR loc_fname[FNAME_LEN];
StrCharCopy(zc->fname, name);
#if !defined(NT_EDITION)
//
// Removed uppercasing the filename per MS request. REV: 11/12/2001
//
CharUpper(zc->fname);
#endif //!defined(NT_EDITION)
zc->Thisbinary = FALSE;
zc->filesize = 0L;
zc->Filemode = 0;
zc->Modtime = 0L;
serial_number = 0;
files_remaining = -1;
bytes_remaining = -1L;
p = name + 1 + StrCharGetByteCount(name);
if (*p)
{ /* file coming from Unix or DOS system */
if (*p)
p = stol(p, &zc->filesize, 10);
if (*p)
p = stol(p, &zc->Modtime, 8);
if (*p)
p = stoi(p, &zc->Filemode, 8);
if (*p)
p = stoi(p, &serial_number, 10);
if (*p)
p = stoi(p, &files_remaining, 10);
if (*p)
p = stol(p, &bytes_remaining, 10);
if ((zc->nfiles == 0) && (files_remaining != -1))
{
zc->nfiles = files_remaining;
zmdmr_filecnt (zc, zc->nfiles);
}
if ((zc->nbytes == (-1L)) && (bytes_remaining != (-1L)))
{
zc->nbytes = bytes_remaining;
zmdmr_totalsize (zc, zc->nbytes);
}
}
else
{ /* File coming from CP/M system */
for (p = zc->fname; *p; ++p) /* change / to _ */
if ( *p == '/')
*p = '_';
if ( *--p == '.') /* zap trailing period */
*p = 0;
}
StrCharCopy(zc->our_fname, zc->fname);
StrCharCopy(loc_fname, zc->fname);
stRcv.pszSuggestedName = loc_fname;
stRcv.pszActualName = zc->our_fname;
stRcv.lFileTime = zc->Modtime;
xfer_build_rcv_name(zc->hSession, &stRcv);
//zc->ssMch = stRcv.ssmchVscanHdl;
lconv = 0;
pZ = (XFR_Z_PARAMS *)xfer_get_params(zc->hSession, zc->nMethod);
assert(pZ);
if (pZ)
{
switch (pZ->nCrashRecRecv)
{
case ZP_CRR_ALWAYS:
lconv = ZCRECOV;
break;
case ZP_CRR_NEVER:
if ((lconv = zc->zconv) == ZCRECOV)
lconv = 0;
break;
case ZP_CRR_NEG:
default:
lconv = zc->zconv;
break;
}
}
switch (lconv)
{
case ZCNL:
zc->Thisbinary = FALSE;
break;
case ZCRECOV:
/*
* This is a little complicated. To do recovery, we need to check
* the following:
* 1. Does the file exist on OUR side.
* 2. Has the sender sent over a file size.
* 3. Is the size sent greater than the size of OUR file.
* If so, we fudge around a little with the file and let things rip.
*/
zRecover = TRUE;
our_size = 0L;
if (zRecover)
{
if (GetFileSizeFromName(stRcv.pszActualName, &our_size))
zRecover = TRUE;
else
zRecover = FALSE;
}
if (zRecover)
{
/* Has the sender sent over a file size ? */
if (zc->filesize <= 0)
zRecover = FALSE;
}
if (zRecover)
{
/* This gets set up above after checking for existance */
if (our_size != 0L)
{
if (our_size < zc->filesize)
{
/*
* We do this in the vain hope of avoiding problems with
* files terminated by ^Z and padded last blocks
*
* Given that we don't know if it is necessary, it might be
* possible to eliminate it
*/
our_size = (our_size - 1) & ~255L;
}
else
{
return ERROR;
//zRecover = FALSE;
}
}
else
{
zRecover = FALSE;
}
}
if (zRecover)
{
zc->file_bytes = our_size;
}
/* FALL THROUGH */
case ZCBIN:
default:
zc->Thisbinary = TRUE;
break;
}
if (zRecover)
{
lOptions = XFR_RO_APPEND;
}
else if (pZ && pZ->nFileExists == ZP_FE_SENDER)
{
switch (zc->zmanag & ZMMASK)
{
case ZMNEWL:
/* TODO: complete this option */
lOptions = 0;
break;
case ZMCRC:
/* TODO: complete this option */
lOptions = 0;
break;
case ZMAPND:
lOptions = XFR_RO_APPEND;
break;
case ZMCLOB:
lOptions = XFR_RO_ALWAYS;
break;
case ZMNEW:
lOptions = XFR_RO_NEWER;
break;
case ZMDIFF:
/* TODO: complete this option */
lOptions = 0;
break;
case ZMPROT:
lOptions = XFR_RO_NEVER;
break;
default:
break;
}
}
else
{
lOptions = zc->ulOverride;
}
StrCharCopy(zc->our_fname, zc->fname);
StrCharCopy(loc_fname, zc->fname);
stRcv.pszSuggestedName = loc_fname;
stRcv.pszActualName = zc->our_fname;
stRcv.lFileTime = zc->Modtime;
/* TODO: pick up override options as necessary, like above */
file_err = xfer_open_rcv_file(zc->hSession, &stRcv, lOptions);
if (file_err != 0)
{
DbgOutStr("ZMODEM error %s %d\r\n", TEXT(__FILE__), __LINE__,0,0,0);
switch (file_err)
{
case -8:
zmdm_retval(zc, TRUE, ZMDM_INUSE);
break;
case -6: // File was rejected unconditionally
zmdm_retval(zc, TRUE, ZMDM_REFUSE);
break;
case -5: // Were unable to create needed directories
zmdm_retval(zc, TRUE, ZFERR);
break;
case -4: // No date, time supplied when required
zmdm_retval(zc, TRUE, ZFERR);
break;
case -3: // File could not be saved
zmdm_retval(zc, TRUE, ZFERR);
break;
case -2: // File was rejected due to date
zmdm_retval(zc, TRUE, ZMDM_OLDER);
break;
case -1: // Read/Write error occured
default:
zmdm_retval(zc, TRUE, ZFERR);
break;
}
zc->total_bytes += zc->filesize;
zc->filen += 1;
zmdmr_newfile (zc, zc->filen, zc->fname, stRcv.pszActualName);
return ERROR;
}
else
{
zmdm_retval(zc, TRUE, ZACK);
}
zc->fh = stRcv.bfHdl;
zc->basesize = stRcv.lInitialSize;
if (zRecover)
{
//jmh 04-02-96 Sure we opened it in "append" mode (which really
// opens the file for write and seeks to the end), but we
// might actually seek to a spot just before that due to the
// possible padding of the file with ^Z's.
//
fio_seek(zc->fh, zc->file_bytes, FIO_SEEK_SET);
}
zc->filen += 1;
zmdmr_newfile (zc, zc->filen, zc->fname, stRcv.pszActualName);
zmdmr_filesize(zc, zc->filesize);
return OK;
}
/*----------------------------------------------------------------------+
| putsec - Putsec writes the n characters of buf to receive file.
| If not in binary mode, carriage returns, and all characters
| starting with CPMEOF are discarded.
+----------------------------------------------------------------------*/
int putsec(ZC *zc, BYTE *buf, int n)
{
register BYTE *p;
register int ii;
if (n == 0)
return OK;
if (zc->Thisbinary)
{
// jkh, 2/11 Added error check
if (fio_write(buf, 1, n, zc->fh) != n)
longjmp(zc->flagkey_buf, 4);
}
else
{
if (zc->Eofseen)
return OK;
ii = FALSE;
for (p=buf; --n>=0; ++p )
{
if ( *p == '\n')
{
/*
* If we get a <NL> that wasn't preceeded by a <CR>
*/
if (ii == FALSE)
fio_putc('\r', zc->fh);
}
ii = (*p == '\r');
if (*p == CPMEOF)
{
zc->Eofseen=TRUE;
return OK;
}
fio_putc(*p, zc->fh);
}
}
return OK;
}
/* *********** end of zmdm_rcv.c *********** */