/* 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 #pragma hdrstop //#define DEBUGSTR #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 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 that wasn't preceeded by a */ 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 *********** */