|
|
/* mdmx_snd.c -- Routines to handle xmodem sending for HA5G
* * Copyright 1989 by Hilgraeve Inc. -- Monroe, MI * All rights reserved * * $Revision: 9 $ * $Date: 4/24/02 3:49p $ */ #include <windows.h>
#include <stdlib.h>
#pragma hdrstop
// #include <setjmp.h>
#define BYTE unsigned char
#include <tdll\mc.h>
#include <tdll\stdtyp.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\file_io.h>
#include <tdll\htchar.h>
#include "xfr_srvc.h"
#include "xfr_todo.h"
#include "xfr_dsp.h"
#include "xfer_tsc.h"
#include "foo.h"
#include "cmprs.h"
#include "xfer.h"
#include "xfer.hh"
#include "mdmx.h"
#include "mdmx.hh"
#if !defined(STATIC_FUNC)
#define STATIC_FUNC
#endif
#if !defined(CMPRS_MINSIZE)
#define CMPRS_MINSIZE 4000L
#endif
/* * * * * * * * * * * * * * * *
* local function prototypes * * * * * * * * * * * * * * * * */
STATIC_FUNC int xsend_start(ST_MDMX *xc, BYTE *start_chars, int *start_char);
STATIC_FUNC int getresponse(ST_MDMX *xc, int time);
STATIC_FUNC void make_file_pckt(ST_MDMX *xc, struct s_mdmx_pckt *p, char *fname, long size);
/* * * * * * * *
* Functions * * * * * * * * */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* mdmx_snd * * DESCRIPTION: * Sends a file using XMODEM or YMODEM protocol. Support 1k packets, batch * transfers and 'G' option streaming. * * ARGUMENTS: * attended -- TRUE if user is probably in attendance. Controls the display * of some messages. * * RETURNS: * True if transfer completes successfully, FALSE otherwise. */ int mdmx_snd(HSESSION hSession, int attended, int method, unsigned nfiles, long nbytes) { ST_MDMX *xc; struct s_mdmx_pckt * this_pckt = NULL; struct s_mdmx_pckt * next_pckt = NULL; struct s_mdmx_pckt * tpckt;
/* column values for display box */ TCHAR sfname[FNAME_LEN];// file name of file being sent
TCHAR xname[FNAME_LEN]; // transmitted file name
int still_trying; // controls exit from main transfer loop
int got_file; // controls when to complete batch op
int got_response; // controls loop to get valid response
int tries = 0; // number of retries for each packet
unsigned total_tries; // number of retries for entire transfer
int response; // response char. received from other end
BYTE start_chars[3]; // acceptable start chars. from receiver
int xstatus = TSC_OK; // winds up with overall status of transfer
int check_type; // type of error checking in use
unsigned pcktn; // number of packet currently being sent
int override = FALSE; // set TRUE if comm. details changed to
unsigned int uiOldOptions; int batch; // TRUE if YMODEM batch transfers used
int big_pckts; // TRUE if 1K packets are allowed
int streaming; // TRUE if no packet responses expected
if (xfer_set_comport(hSession, TRUE, &uiOldOptions) != TRUE) { goto done; } else { override = TRUE; }
/* set up options based on method used */ big_pckts = (method != XF_XMODEM); batch = (method == XF_YMODEM || method == XF_YMODEM_G); streaming = FALSE; /* will be turned on if receiver starts with 'G' */ // assert(nfiles == 1 || batch);
this_pckt = NULL; next_pckt = NULL;
xc = malloc(sizeof(ST_MDMX)); if (xc == NULL) { goto done; } memset(xc, 0, sizeof(ST_MDMX));
xc->hSession = hSession; xc->hCom = sessQueryComHdl(hSession);
// RemoteClear(hSession);
ComRcvBufrClear(xc->hCom);
this_pckt = malloc(sizeof(ST_MDMX) + (big_pckts ? LARGE_PACKET : SMALL_PACKET) + 2); if (this_pckt == NULL) { goto done; } memset(this_pckt, 0, sizeof(ST_MDMX) + (big_pckts ? LARGE_PACKET : SMALL_PACKET) + 2);
next_pckt = malloc(sizeof(ST_MDMX) + (big_pckts ? LARGE_PACKET : SMALL_PACKET) + 2); if (next_pckt == NULL) { goto done; } memset(next_pckt, 0, sizeof(ST_MDMX) + (big_pckts ? LARGE_PACKET : SMALL_PACKET) + 2);
mdmxXferInit(xc, method); /* Could be smaller but this is easier */ if (xc->p_crc_tbl == NULL) { xstatus = TSC_NO_MEM; goto done; }
// hp_report_xtime(0); /* make invalid in case transfer bombs */
xc->file_bytes = 0L; xc->total_bytes = 0L; xc->fh = NULL; xc->xfertimer = -1L; xc->nfiles = nfiles; /* make these available to display routines */ xc->filen = 0; xc->filesize = -1L; xc->nbytes = nbytes;
mdmxdspTotalsize(xc, nbytes); mdmxdspFilecnt(xc, nfiles);
xc->mdmx_byte_cnt = 0; StrCharCopy(start_chars, (batch ? "CG" : "C\x15")); /* \x15 is NAK */ check_type = CRC; mdmxdspChecktype(xc, (check_type == CRC) ? 0 : 1); total_tries = 0; mdmxdspErrorcnt(xc, total_tries); tries = 0; mdmxdspPacketErrorcnt(xc, tries); got_file = TRUE; while (got_file) { if ((got_file = xfer_nextfile(hSession, sfname)) == TRUE) { xc->total_bytes += xc->file_bytes; xc->file_bytes = xc->mdmx_byte_cnt = 0L;
mdmxdspNewfile(xc, xc->filen + 1, sfname, sfname);
++xc->filen;
if (xfer_opensendfile(hSession, &xc->fh, sfname, &xc->filesize, xname, NULL) != 0) { xstatus = TSC_CANT_OPEN; goto done; } mdmxdspFilesize(xc, xc->filesize); } else { // strblank(xname);
xname[0] = TEXT('\0'); }
pcktn = 0; if (batch) { make_file_pckt(xc, this_pckt, xname, xc->filesize); }
if ((xstatus = xsend_start(xc, start_chars, &response)) != TSC_OK) { break; }
if (xc->filen <= 1) { xc->xfertimer = (long)startinterval(); /* start the clock */ if (response == NAK) { check_type = CHECKSUM; } mdmxdspChecktype(xc, (check_type == CRC) ? 0 : 1); if (response == 'G') { streaming = TRUE; mdmxdspChecktype(xc, 2); }
/* once we've received the first start_char,
* subsequent ones must match */ start_chars[0] = (BYTE)response; start_chars[1] = '\0'; }
if (got_file) { xc->p_getc = xm_getc; tries = 0; if (!batch && !load_pckt(xc, this_pckt, pcktn = 1, big_pckts, check_type)) { xstatus = TSC_DISK_ERROR; goto done; } }
/* get the first pckt on its way while we prepare the second pckt */ if ( ComSndBufrSend(xc->hCom, &this_pckt->start_char, (unsigned)this_pckt->pcktsize, SMALL_WAIT) == COM_PORT_NOT_OPEN ) { xstatus = TSC_LOST_CARRIER; still_trying = FALSE; goto done; }
mdmxdspPacketnumber(xc, pcktn);
/* load next pckt*/ if (got_file && !load_pckt(xc, next_pckt, ++pcktn, big_pckts, check_type)) { xstatus = TSC_DISK_ERROR; goto done; }
still_trying = TRUE; while (still_trying) { if (streaming) { /* these things are done in getresponse() if not streaming */
if (xfer_carrier_lost(hSession)) { xstatus = TSC_LOST_CARRIER; break; }
if (xfer_user_interrupt(hSession)) { xstatus = TSC_USER_CANNED; break; } }
/* wait until last packet is out before watching for response */ ComSndBufrWait(xc->hCom, this_pckt->pcktsize >= LARGE_PACKET ? LARGE_WAIT : SMALL_WAIT);
/* get response from receiver */ got_response = FALSE; while (!got_response) { response = (streaming && this_pckt->start_char != EOT) ? ACK : getresponse(xc, 60);
got_response = TRUE;
switch(response) { case ACK: if (this_pckt->start_char == EOT) { /* successful */ mdmx_progress(xc, FILE_DONE); xc->xfertime = (long)interval(xc->xfertimer); fio_close(xc->fh);
xfer_log_xfer(hSession, TRUE, sfname, NULL, TSC_OK);
xc->fh = NULL; xstatus = TSC_OK; still_trying = FALSE; } else { xc->file_bytes = this_pckt->byte_count; tpckt = this_pckt; this_pckt = next_pckt; next_pckt = tpckt;
/* pcktn will only be <= 1 when batch is on and
* we've just sent the filename packet (packet 0) */ if (pcktn <= 1 && (!got_file || (xstatus = xsend_start(xc, start_chars, &response)) != TSC_OK)) { still_trying = FALSE; break; }
/* send packet */
if ( ComSndBufrSend(xc->hCom, &this_pckt->start_char, (unsigned)this_pckt->pcktsize, SMALL_WAIT) == COM_PORT_NOT_OPEN) { xstatus = TSC_LOST_CARRIER; still_trying = FALSE; break; }
mdmxdspPacketnumber(xc, pcktn);
mdmx_progress(xc, 0); if (tries != 0) { mdmxdspPacketErrorcnt(xc, 0);
tries = 0; } if (this_pckt->start_char != EOT) { if (!load_pckt(xc, next_pckt, ++pcktn, big_pckts, check_type)) { xstatus = TSC_DISK_ERROR; still_trying = FALSE; } } } break;
case NO_RESPONSE: mdmxdspLastError(xc, 12); still_trying = FALSE; break;
case ABORTED: xstatus = TSC_USER_CANNED; still_trying = FALSE; break;
case CARR_LOST: xstatus = TSC_LOST_CARRIER; still_trying = FALSE; break;
case 'C': case 'G': /* these act as NAKs for packets first packets */ if (pcktn > 2) { got_response = FALSE; break; } /* else fall through */ case NAK: if (++tries >= xc->mdmx_tries) { xstatus = TSC_ERROR_LIMIT; goto done; } else /* send packet */ { if (ComSndBufrSend(xc->hCom, &this_pckt->start_char, (unsigned)this_pckt->pcktsize, SMALL_WAIT) == COM_PORT_NOT_OPEN) { xstatus = TSC_LOST_CARRIER; still_trying = FALSE; break; } } if (this_pckt->start_char == EOT && tries == 1) { break; /* don't print first retransmission on final EOT */ } mdmxdspPacketErrorcnt(xc, tries);
mdmxdspErrorcnt(xc, ++total_tries);
mdmxdspLastError(xc, (response == NAK) ? 13 : 14);
break;
case CAN: if (getresponse(xc, 1) == CAN) /* two consecutive CANs? */ { xstatus = TSC_RMT_CANNED; still_trying = FALSE; break; } /* fall through */
default: got_response = FALSE; break; }
} /* end while (!got_response) */
} /* end while(still_trying) */
if (!batch || xstatus != TSC_OK) { break; }
} /* end while(got_file) */
done:
mdmx_progress(xc, TRANSFER_DONE);
mdmxdspCloseDisplay(xc);
// ComSendSetCharDelay(hld_send_cdelay, COMSEND_SETDELAY);
if (override) { #if FALSE
cnfg.bits_per_char = hld_bits_per_char; cnfg.parity_type = hld_parity_type; (void)(*ComResetPort)(); #endif
xfer_restore_comport(hSession, uiOldOptions); }
if (xc == NULL || this_pckt == NULL || next_pckt == NULL) { xstatus = TSC_NO_MEM; }
if (xc != NULL) { // hp_report_xtime((unsigned)xc->xfertime);
if (xc->fh) { fio_close(xc->fh); }
if (xstatus != TSC_OK) { if (xstatus != TSC_RMT_CANNED && xstatus != TSC_NO_MEM) { for (tries = 5 + 1; --tries > 0; ) { ComSendChar(xc->hCom, &xc->stP, CAN); } ComSendPush(xc->hCom, &xc->stP); } xfer_log_xfer(hSession, TRUE, sfname, NULL, xstatus); }
#if FALSE
if (attended && xstatus != TSC_USER_CANNED && xstatus != TSC_NO_MEM) { menu_bottom_line (BL_ESC, 0L); DosBeep(beepfreq, beeplen); menu_replybox((int)xc->msgrow, ENTER_RESP, 0, (int)transfer_status_msg((unsigned short)xstatus)); } #endif
if (xc->p_crc_tbl != NULL) { #if defined(DEADWOOD)
resFreeDataBlock(xc->hSession, xc->p_crc_tbl); xc->p_crc_tbl = NULL; #else // defined(DEADWOOD
//
// We don't need to free xc->p_crc_tbl since it is pointing
// to a static constant array. REV: 4/10/2002
//
xc->p_crc_tbl = NULL; #endif // defined(DEADWOOD)
}
free(xc); xc = NULL; }
if (this_pckt) { free(this_pckt); this_pckt = NULL; }
if (next_pckt) { free(next_pckt); next_pckt = NULL; }
return((unsigned)xstatus); }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* xsend_start * * DESCRIPTION: * Waits up to one minute for a start request from the receiver at the * other end of the line. * * ARGUMENTS: * chktype -- Pointer to a variable to be set to the requested error * correction checking method, CRC or Checksum * * RETURNS: * Status code indicating result. Can be one of * TSC_USER_CANNED if user interrupted by hitting the ESC key. * TSC_NO_RESPONSE if 60 seconds elapses without receiving a start char. * TSC_RMT_CANNED if remote sends a control-C * TSC_OK if remote sends proper start char. * */ STATIC_FUNC int xsend_start(ST_MDMX *xc, BYTE *start_chars, int *start_char) { for ( ; ; ) { switch(*start_char = getresponse(xc, 60)) { case ABORTED: return(TSC_USER_CANNED);
case NO_RESPONSE: return(TSC_NO_RESPONSE);
case CARR_LOST: return(TSC_LOST_CARRIER);
case ESC: case '\003': /* control-C */ return(TSC_RMT_CANNED);
default: if (strchr(start_chars, *start_char)) { return(TSC_OK); }
/* ignore any other char. */ break; } } return TSC_OK; }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* getresponse * * DESCRIPTION: * Waits a specified time for a response from the receiver. Can be forced * to terminate early if user intervention is detected. No effort is made * here to interpret the meaning of a response character. Any character * received within the time limit will be returned. * * ARGUMENTS: * time -- Number of seconds to wait for a response character. * * RETURNS: * The response character if one was received or ABORTED or NO_RESPONSE or * CARR_LOST. */ STATIC_FUNC int getresponse(ST_MDMX *xc, int time) { TCHAR rc = 0; long timer;
DbgOutStr("getresponse ", 0,0,0,0,0);
#if FALSE
if (kbd_check_flagkey(xc->flagkey, TRUE) > 0) { kbd_flush(); return ABORTED; } #endif
if (xfer_user_interrupt(xc->hSession)) { DbgOutStr("aborted\r\n", 0,0,0,0,0); return ABORTED; }
// if ((rc = RemoteGet(xc->hSession)) != -1)
if (mComRcvChar(xc->hCom, &rc) != 0) { DbgOutStr("returned %d\r\n", rc, 0,0,0,0); return(rc & 0x7F); }
time *= 10; timer = (long)startinterval(); while ((long)interval(timer) < (long)time) { #if FALSE
if (kbd_check_flagkey(xc->flagkey, TRUE) > 0) { kbd_flush(); return ABORTED; } #endif
if (xfer_carrier_lost(xc->hSession)) { DbgOutStr(" lost\r\n", 0,0,0,0,0); return CARR_LOST; }
if (xfer_user_interrupt(xc->hSession)) { DbgOutStr("aborted\r\n", 0,0,0,0,0); return ABORTED; }
mdmx_progress(xc, 0);
if (mComRcvChar(xc->hCom, &rc) != 0) { DbgOutStr("returned %d\r\n", rc, 0,0,0,0); return(rc & 0x7F); }
xfer_idle(xc->hSession, XFER_IDLE_IO);
} DbgOutStr(" none\r\n", 0,0,0,0,0); return(NO_RESPONSE); }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* make_file_pckt * * DESCRIPTION: sets up the initial filename pckt for Ymodem (only) * * ARGUMENTS: * p -- Pointer to the packet structure which receives the filename * packet. * fname -- The file name as it should be placed in the packet. * size -- The size of the file as it should be placed in the packet. * * RETURNS: * nothing */ STATIC_FUNC void make_file_pckt(ST_MDMX *xc, struct s_mdmx_pckt *p, char *fname, long size) { BYTE sizestr[20]; BYTE *ptr; BYTE *cp; unsigned int crc;
p->start_char = SOH; /* set start char to SOH */ p->pcktnum = 0; /* set pcktnumber to 0 */ p->npcktnum = 0xff; /* set npcktnumber to 0xff */ ptr = p->bdata;
/* initialize data area with zeros */ memset(ptr, 0, SMALL_PACKET + 2);
if (*fname) { StrCharCopy(ptr, fname); /* copy filename into buffer*/
/* replace all back slashes with slashes */ //while (strreplace(ptr, FstrBslashBslash(), "/"))
// ;
for (cp = ptr; *cp != '\0'; cp += 1) if (*cp == '\\') *cp = '/';
// StrFmt(sizestr, "%ld", size); /* format the file size */
wsprintf(sizestr, "%ld", (LONG)size);
StrCharCopy(&ptr[StrCharGetByteCount(ptr)+1], sizestr); /* add it to buffer */ }
/* calculate CRC value */ ptr = &p->bdata[SMALL_PACKET]; /* set ptr to char after buffer */ /* calculate CRC */ crc = calc_crc(xc, (unsigned)0, p->bdata, SMALL_PACKET+2); /* set the CRC */ *ptr++ = (BYTE)(crc / 0x100); *ptr = (BYTE)(crc % 0x100); /* set the packetsize */ p->pcktsize = SMALL_PACKET + 5; p->byte_count = xc->mdmx_byte_cnt; }
/*********************** end of mdmx_snd.c **************************/
|