/* Copyright (C) Magna Carta Software, Inc. 1988-1990. All Rights Reserved. C COMMUNICATIONS TOOLKIT CCTZ.H -- ZMODEM routines for CCT */ #define CCT_DEVELOPMENT #if (defined(CCTW) || defined(_WINDOWS)) #include #endif #include #include #include #include #include #include static short NEAR_ z_g_zrinit_(COMM_PORT *p); static short NEAR_ z_s_fdata_(COMM_PORT *p); static short NEAR_ z_s_file_(COMM_PORT *p, char *buf, short blen); static short NEAR_ z_s_rqinit_(COMM_PORT *p); #if XDEBUG static char *a_cap[] = {"CANFDX", "CANOVIO", "CANBRK", "CANCRY", "CANLZW", "CANFC32", "ESCCTL", "ESC8"}; static char *a_bool[] = {"FALSE", "TRUE"}; #endif extern int Beenhereb4; /* How many times we've been ZRPOS'd same place */ /* Z_G_ZRINIT_ Get the receiver's init parameters. */ static short NEAR_ z_g_zrinit_(COMM_PORT *p) { short n; #if XDEBUG short i; #endif short ret = EOF, done = FALSE; Z_PARMS *z = p->ppb; XFER *x = (XFER *) p->x; for (n=10; --n >= 0 && !done; ) { switch (ret = z_r_h_(p, z->rxhdr, 1)) { case ZCHALLENGE: /* Echo receiver's challenge number */ #if XDEBUG printf("\nReceived ZCHALLENGE"); #endif if (x->p_user != NULL)(*x->p_user)(p, ZCHALLENGE | 0X2000, 0L); stohdr_(z, z->rxpos); z_s_hh_(p, ZACK, z->txhdr); continue; case ZRINIT: z->r_cap = (BYTE) z->rxhdr[ZF0]; if (x->p_user != NULL)(*x->p_user)(p, ZRINIT | 0X2000, z->r_cap); #if XDEBUG for (i=0; i < 8; i++) { printf("\nReceiver %s = %s", a_cap[i], (z->r_cap & (1 << i)) ? a_bool[1] : a_bool[0]); } #endif z->txfcs32 = (wantfc32(z) && (z->r_cap & CANFC32)); z->ctlesc |= z->r_cap & TESCCTL; z->rxbuflen = (z->rxhdr[ZP0] & 0XFF)+((0XFF & z->rxhdr[ZP1])<<8); if (!(z->r_cap & CANFDX)) z->txwindow = 0; /* OVERRIDE TO FORCE SHORTER FRAME LENGTH */ if (z->rxbuflen && (z->rxbuflen > z->tframlen) && (z->tframlen >= 32)) z->rxbuflen = z->tframlen; if (!z->rxbuflen && (z->tframlen >= 32) && (z->tframlen <= 1024)) z->rxbuflen = z->tframlen; /* Set initial subpacket length */ if (z->blklen < 1024) { /* Command line override? */ if (z->speed >= 300) z->blklen = 256; if (z->speed >= 1200) z->blklen = 512; if (z->speed >= 2400) z->blklen = 1024; } if (z->rxbuflen && z->blklen > z->rxbuflen) z->blklen = z->rxbuflen; if (z->blkopt && z->blklen > z->blkopt) z->blklen = z->blkopt; done = TRUE; ret = ZFILE; break; case ZCAN: case EOF: ret = EOF; break; case ZRQINIT: #if XDEBUG printf("\nReceived ZRQINIT"); #endif if (z->rxhdr[ZF0] == ZCOMMAND) continue; case USER_CANCELLED: ret = USER_CANCELLED; done = TRUE; break; default: z_s_hh_(p, ZNAK, z->txhdr); continue; } } return (ret); } /* Z_S_RQINIT_ -- Send ZRQINIT packet. Called from ZSEND. */ static short NEAR_ z_s_rqinit_(COMM_PORT *p) { Z_PARMS *z = p->ppb; short ret; /* z->txhdr[ZF0] = ZCOMMAND; */ z_s_hh_(p, ZRQINIT, z->txhdr); ret = z_g_zrinit_(p); if (!ret) { } /* else send can */ return (ret); } /* Z_S_FILE_ -- Send file name and related info. Header contains ZMODEM management options. */ static short NEAR_ z_s_file_(COMM_PORT *p, char *buf, short blen) { short ret, c; short done = FALSE; Z_PARMS *z = p->ppb; XFER *x = (XFER *) p->x; DWORD crc, i; char zbuf[Y_PKT_0_SIZE]; /* desired size of file info. buffer */ memset(zbuf, 0X0, sizeof(zbuf)); ret = ymodem_hdr_build_(p->x, zbuf); if (!ret) for (;;) { blen = Y_PKT_0_SIZE; #if XDEBUG printf("\nz_s_file: building txhdr for: %s", zbuf); #endif z->txhdr[ZF0] = z->l_conv; /* file conversion request */ z->txhdr[ZF1] = z->l_manag; /* file management request */ if (z->l_manag & ZMSKNOLOC) z->txhdr[ZF1] |= ZMSKNOLOC; z->txhdr[ZF2] = z->l_trans; /* file transport request */ z->txhdr[ZF3] = 0; z_s_bh_(p, ZFILE, z->txhdr); z_s_data_(p, zbuf, blen, ZCRCW); /* send the file header */ again: c = z_r_h_(p, z->rxhdr, 1); switch (c) { case ZRINIT: while ((c = c_waitc(p, EOF, 5000)) > 0) if (c == ZPAD) { goto again; } continue; case USER_CANCELLED: ret = done = USER_CANCELLED; break; case ZCRC: /* Do CRC32 on number of bytes specified and send complement of the result in a ZCRC header */ #if XDEBUG printf("\nZFILE response: ZCRC"); #endif if (x->p_user != NULL)(*x->p_user)(p, ZCRC | 0X2000, 0L); crc = 0xFFFFFFFFL; while (((c = c_fgetc_(x)) != EOF) && --z->rxpos) crc = UPDC32(c, crc); crc = ~crc; fseekbuf_(x, 0L, SEEK_SET); stohdr_(z, crc); z_s_bh_(p, ZCRC, z->txhdr); goto again; case ZSKIP: /* CLOSE FILE, CLEAR BUFFERS, AND GO TO NEXT */ done = TRUE; ret = c; break; case ZRPOS: /* ADD: SEEK TO REQUESTED POSITION */ if (z->rxpos) for (i=0; i < z->rxpos && (c = c_fgetc_(x)) != EOF; i++); /* * Suppress zcrcw request otherwise triggered by * lastsync==bytcnt */ z->lastsync = (z->bytcnt = z->txpos = z->rxpos) - 1; if (x->p_user)(*x->p_user)(p, (c > 0) ? (c | 0X2000) : c, 0L); done = ret = ZDATA; break; case ZCAN: case ZABORT: case ZFIN: if (x->p_user)(*x->p_user)(p, (c > 0) ? (c | 0X2000) : c, 0L); case EOF: default: done = ret = EOF; #if XDEBUG printf("\nZFILE response: %d", c); #endif } if (done) break; } return (ret); } #if defined(_MSC_VER) #pragma optimize ("egl", off) #endif /* Z_S_FDATA_ -- Send the data in the file. */ static short NEAR_ z_s_fdata_(COMM_PORT *p) { Z_PARMS *z = p->ppb; XFER *x = (XFER *) p->x; short e, n, ret; short newcnt, c; unsigned long tcount; short junkcount; /* Counts garbage chars received by TX */ short done = FALSE; z->lrxpos = 0; z->f_eof = FALSE; somemore: junkcount = 0; Beenhereb4 = FALSE; newcnt = z->rxbuflen; z->txwcnt = 0; stohdr_(z, z->txpos); z_s_bh_(p, ZDATA, z->txhdr); do { /* CHECK FOR A KBD. ABORT */ if (is_key(p->abort_key)) { done = TRUE; ret = USER_CANCELLED; break; } /* CHECK FOR LOSS OF CARRIER */ if (checkdcd) { if (get_dcd(p) == FALSE) { ret = done = CONNECTION_LOST; if (x->p_user != NULL)(*x->p_user)(p, CONNECTION_LOST, z->bytcnt); break; } } n = z_filbuf_(p); if (z->f_eof) e = ZCRCE; else if (junkcount > 3) e = ZCRCW; else if (z->bytcnt == z->lastsync) e = ZCRCW; else if (z->rxbuflen && (newcnt -= n) <= 0) e = ZCRCW; else if (z->txwindow && (z->txwcnt += n) >= z->txwspac) { z->txwcnt = 0; e = ZCRCQ; } else e = ZCRCG; z_s_data_(p, z->txbuf, n, e); z->bytcnt = z->txpos += n; if (x->p_user != NULL)(*x->p_user)(p, XFER_POSITION, z->bytcnt); /* if (e == ZCRCW) break; */ if (z->txwindow) { while (((tcount = z->txpos - z->lrxpos) >= z->txwindow) && !done) { if (e != ZCRCQ) z_s_data_(p, z->txbuf, 0, e = ZCRCQ); c = z_sync_(p, 1); if (c != ZACK) { z_s_data_(p, z->txbuf, 0, ZCRCE); switch (c) { default: case ZCAN: ret = done = EOF; break; case ZSKIP: ret = done = c; break; case ZACK: case ZRPOS: newcnt = z->rxbuflen; z->txwcnt = 0; stohdr_(z, z->txpos); z_s_bh_(p, ZDATA, z->txhdr); break; case ZRINIT: done = TRUE; ret = 0; break; } } } } } while (!z->f_eof && !done); /* EOF REACHED -- SEND ZEOF */ for (;!done;) { stohdr_(z, z->txpos); z_s_bh_(p, ZEOF, z->txhdr); ret = z_sync_(p, 0); if (x->p_user != NULL)(*x->p_user)(p, (ret > 0) ? (ret | 0X2000) : ret, 0L); switch (ret) { case ZACK: continue; case ZRPOS: goto somemore; case ZRINIT: done = TRUE; ret = ZFILE; break; case ZSKIP: done = TRUE; ret = c; break; default: done = TRUE; ret = EOF; } } return (ret); } #if defined(_MSC_VER) #pragma optimize ("", on) #endif /* Z_SEND_ -- Start a ZMODEM send session. This is the state machine for send events. */ short z_send_(COMM_PORT *p) { short ret = 0; short done = FALSE, state = ZSIDLE; char sxlat[XLAT_SIZE]; if (((Z_PARMS *)p->ppb)->x == NULL) ((Z_PARMS *)p->ppb)->x = p->x; /* SAVE THE DATA TRANSLATION PARAMETERS AND SET NEW ONES FOR ZMODEM */ save_xlat(p, sxlat); p->tx_xlat = ON; p->tx_eol = p->tx_case_convert = p->tx_ascii_only = FALSE; #if XDEBUG set_rx_xlat(p, LOCAL_ECHO, TRUE); #endif do { switch (state) { case ZSIDLE: /* goes to ZRQINIT */ c_puts(p, "rz\r"); state = ZRQINIT; break; case ZRQINIT: state = z_s_rqinit_(p); /* goes to ZFILE */ #if XDEBUG printf("\nReturned %d from z_s_rqinit", state); #endif break; case ZFILE: /* goes to ZDATA */ /* ATTEMPT TO LOAD THE FILE TO SEND */ if ((ret = fmakebuf_(p->x, ((XFER *) p->x)->maxlen)) != 0) { done = TRUE; } else { #if XDEBUG printf("\nEntering z_s_file with file=%s", ((XFER *)p->x)->xf->fspec); #endif state = z_s_file_(p, ((XFER *)p->x)->xf->fspec, 9); #if XDEBUG printf("\nReturned %d from z_s_file\n", state); #endif } break; case ZDATA: /* goes to ZFIN */ state = z_s_fdata_(p); #if XDEBUG printf("\nReturned %d from z_s_fdata", state); #endif switch (state) { case ZCAN: case ZSKIP: case EOF: default: cct_file_close_(((XFER *)p->x)->fh); break; case ZFILE: if (!funload(p->x, ((XFER *)p->x)->fspec)) { if (((XFER *)p->x)->num_files == 0) state = ZFIN; } break; } break; case ZFIN: /* goes to ZCOMPL */ state = z_s_fin_(p); break; case USER_CANCELLED: x_can(p); if (((XFER *)p->x)->p_user != NULL)(*((XFER *)p->x)->p_user)(p, USER_CANCELLED, 0L); ret = done = USER_CANCELLED; break; case ZCOMPL: done = TRUE; break; default: ret = EOF; done = TRUE; } } while (!done); rest_xlat(p, sxlat); return (ret); }