home *** CD-ROM | disk | FTP | other *** search
-
- /* JMODEM protocol implementation, version 1.1. Information extracted
- * from MS DOS files JMODEM.ASM and JMODEM.DOC by Richard B. Johnson
- * (version 1.20) This program was made 25.4 - 7.5 1989 by Kenneth
- * Österberg.
- * Command line syntax:
- * JModem devname unit baud {R|S} filename ...
- */
-
- /* files to include */
-
- #include <exec/types.h>
- #include <exec/nodes.h>
- #include <exec/memory.h>
- #include <exec/libraries.h>
- #include <exec/devices.h>
- #include <devices/serial.h>
- #include <libraries/dos.h>
- #include <intuition/intuition.h>
-
- #include "protsupp.h" /* Symbols and definition for protsupp.c */
-
- char *WinTxt[] = {
- "File name :",
- "File size :",
- "Block number :",
- "Block size :",
- "Bytes transferred:",
- "Status :",
- NULL
- };
-
- #define TXPOS 19 /* XPos where to print information texts */
- #define WINWID 500 /* Width of our JModem window */
- #define WINHGT 80 /* Height */
- #define GXPOS 36 /* Gadget left edge relative to our window */
- #define GYPOS WINHGT - 28 /* Gadget top edge relative to window bottom */
-
- struct windef wdef = {
- WINWID,WINHGT,
- GXPOS,GYPOS,
- " JModem v1.0 \0receive ",
- WinTxt
- };
-
- /* Other definitions */
-
- #define JC_NONE 0 /* Error codes for Jcleanup() */
- #define JC_IOREQ 1
- #define JC_CBUF 2
- #define JC_SBUF 3
-
- #define NAK 21 /* Negative Acknowledge, a block was not accepted */
- #define SYN 22 /* Sync character, used in long handshaking */
- #define CAN 24 /* Cancel, used to abort transfer */
- #define ACK 6 /* Acknowledge, signals that all is OK so far */
- #define BB 0xBB /* The 'sentinel', an escape char. in JModem */
- #define MAXSTRING 8192 /* Max size of a data block */
- #define MINSTRING 256 /* Minimum size, the value we start with */
- #define DSTRING 512 /* The amount we increase the block size with */
- #define MAXRETRIES 20 /* The number of times we try to resend a block */
-
- /* Three data buffers are used, one receive buffer, one send buffer
- * and one compress buffer. The required size of these buffers is
- * MAXSTRING + 256 + 6, and the compress buffer must be a few bytes
- * larger to prevent overrun when compressing. */
-
- #define BUFSIZE1 MAXSTRING + 256L + 6L /* The diskbuffer size */
- #define BUFSIZE2 BUFSIZE1 + 4L /* The size of the 'codedbuffer' */
-
- /* Magical JModem control byte constants */
-
- #define NORMAL 1 /* A normal uncompressed block */
- #define COMP 2 /* A compressed block */
- #define EOF 4 /* When this is set we have the last block */
- #define RETRY 8 /* Not currecntly used */
- #define TIMEOUT 16 /* Not currently used */
- #define ABORT 32 /* Transmission aborted. */
- #define SYNC 64 /* Noy currently used */
- #define ERROR 128 /* Not currently used */
-
- /* A macro for sending characters */
-
- #define SENDCHAR(x) *sbuf = (x); sendserchar(sbuf)
-
- /* Variables visible to all routines */
-
- int stringsize, retries;
- ULONG baudrate, unit;
- UWORD recnum;
- UBYTE *rbuf, *sbuf, *cbuf;
- int RetCode;
-
- /* Library routines we use */
-
- int Write(), Read();
- APTR AllocMem(), Open(), Lock(), Seek();
- void FreeMem(), Close(), DeleteFile(), Rename(), UnLock();
- struct Message *GetMsg();
-
- /* Routines in this file and docrc.asm */
-
- extern int docrc();
- int jsend(), readfile(), encode(), chkres(), rxchar(), docrc();
- void sendx(), sdata(), clearbuf(), Jcleanup();
- ULONG calctime();
- APTR htol();
-
- /* Some strings */
-
- char nomemstr[] = "Cannot allocate enough memory";
- char numform[] = "%ld";
-
- /* The main program starts here */
-
- void main(argc, argv)
- register int argc;
- char *argv[];
- {
- char devname[32]; /* Name of serial device */
- register char tmpchar;
- register int noerrors, fcount;
- struct recptrs *recptr; /* Ptr to structure containing IORequest ptrs */
-
- RetCode = RETURN_FAIL; /* Assume failure */
-
- if (!SetupWindow(&wdef)) /* Open the JModem window */
- exit(RetCode);
-
- if (argc < 5) {
- PText(5,TXPOS,"Too few arguments. Read JAmiga.txt");
- Delay(200L);
- Wcleanup(WC_NONE);
- exit(RetCode);
- }
-
- if ((rbuf = (UBYTE *)AllocMem(BUFSIZE1,MEMF_CHIP)) == NULL) {
- PText(5,TXPOS,nomemstr);
- Delay(200L);
- Wcleanup(WC_NONE);
- exit(RetCode);
- }
-
- if ((sbuf = (UBYTE *)AllocMem(BUFSIZE1,MEMF_CHIP)) == NULL) {
- PText(5,TXPOS,nomemstr);
- Delay(200L);
- Wcleanup(WC_NONE);
- Jcleanup(JC_SBUF);
- }
-
- if ((cbuf = (UBYTE *)AllocMem(BUFSIZE2,MEMF_CHIP)) == NULL) {
- PText(5,TXPOS,nomemstr);
- Delay(200L);
- Wcleanup(WC_NONE);
- Jcleanup(JC_CBUF);
- }
-
- strcpy(devname,argv[1]); /* Name of the serial device */
- unit = (ULONG)atoi(argv[2]); /* Unit number in the device */
- baudrate = (ULONG)atoi(argv[3]); /* The baudrate */
- argv += 4;
- argc -= 5;
- if ((baudrate < 110) || (baudrate > 19200)) {
- PText(5,TXPOS,"Baudrate %ld out of range",baudrate);
- Delay(200L);
- Wcleanup(WC_NONE);
- Jcleanup(JC_IOREQ);
- }
-
- if (!(OpenUpSerial(&RR,&WR,BUFSIZE1,baudrate,unit,devname))) {
- PText(5,TXPOS,"Can't open %s unit %ld",devname,unit);
- Delay(200L);
- Wcleanup(WC_NONE);
- Jcleanup(JC_IOREQ);
- }
-
- if (!(OpenUpTimer(&TR))) {
- PText(5,TXPOS,"Can't open timer.device");
- Delay(200L);
- Wcleanup(WC_NONE);
- Scleanup(SC_NONE);
- Jcleanup(JC_IOREQ);
- }
-
- tmpchar = argv[0][0]; /* This should be either R (receive) or S (send) */
- argv++; /* argv now points at the file name */
-
- stringsize = MINSTRING; /* We start with the smallest block size */
- noerrors = TRUE;
- fcount = 0; /* File transfer counter */
- RetCode = RETURN_ERROR;
- while ((argc--) && (noerrors)) { /* Process all file names */
- switch (tmpchar) {
- case 'R':
- case 'r':
- if (!fcount) { /* Change the window title only the first time */
- *(pwin->Title + strlen(pwin->Title)) = ' '; /* Remove \0 char */
- SetWindowTitles(pwin,pwin->Title,-1L); /* Show 'JModem receive' */
- }
- PText(0,TXPOS,"%s",argv[0]); /* Display file name */
- PText(1,TXPOS,"?");
- PText(2,TXPOS,"1");
- PText(3,TXPOS,"?");
- PText(4,TXPOS,"0");
-
- if (jrec(argv[0], rbuf, sbuf, cbuf)) {
- PText(5,TXPOS,"File received!");
- fcount++;
- }
- else {
- PText(5,TXPOS,"File transfer failed!");
- noerrors = FALSE;
- }
- break;
- case 'S':
- case 's':
- if (!fcount)
- SetWindowTitles(pwin," JModem v1.0 send ",-1L);
- PText(0,TXPOS,"%s",argv[0]);
- if (jsend(argv[0], rbuf, sbuf, cbuf)) {
- PText(5,TXPOS,"File sent!");
- fcount++;
- }
- else {
- PText(5,TXPOS,"File transfer failed");
- noerrors = FALSE;
- }
- break;
- default:
- PText(5,TXPOS,"Invalid args. R[eceive] or S[end] expected");
- noerrors = FALSE;
- RetCode = RETURN_FAIL;
- break;
- }
- argv++;
- }
-
- /* The return code gives the number of files successfully transferred, or if
- * no files were transferred RETURN_ERROR (10) is returned. A complete
- * JModem failure (out of memory, no serial device, or invalid command line)
- * results in RETURN_FAIL (20). These return codes should give a good idea
- * which files were sent, and which were not. */
-
- if (fcount)
- RetCode = fcount;
-
- Tcleanup(TC_NONE);
- Scleanup(SC_NONE);
-
- Delay(200L);
- Wcleanup(WC_NONE);
- Jcleanup(JC_NONE);
- }
-
- int jrec(name, rbuf, sbuf, cbuf)
- /* Receive a file from the remote system and write it to the disk
- * file 'name'. The function returns TRUE if the file was successfully
- * received and stored. */
-
- char *name;
- UBYTE *rbuf, *sbuf, *cbuf;
- {
- int blklen, recrec, status, success = FALSE;
- register int a;
- register UBYTE ctrl, *bufptr, *tmpptr;
- struct IntuiMessage *imsg;
- APTR file;
- ULONG totlen = 0;
-
- /* If the file name we wish to receive exists already, then add the
- * suffix '.old' to the existing file. */
-
- if (file = Lock(name,ACCESS_READ)) {
- a = strlen(name);
- bufptr = (UBYTE *)AllocMem((ULONG)a+6L,MEMF_PUBLIC);
- if (bufptr) {
- PText(5,TXPOS,"File already exists. Appending '.old'");
- tmpptr = (UBYTE *)name;
- while (*tmpptr) *bufptr++ = *tmpptr++;
- strcpy(bufptr,".old");
- bufptr -= a;
- Rename(name,bufptr);
- FreeMem(bufptr,(ULONG)a+6L);
- }
- UnLock(file);
- }
-
- /* Open the file to receive and get into sync with sender */
-
- if (((file = Open(name,MODE_NEWFILE))==0) || (!rxsync())) {
- sendx();
- if (file) {
- PText(5,TXPOS,"Syncronization failed. Aborting");
- Close(file);
- DeleteFile(name);
- }
- else
- PText(5,TXPOS,"Can't open file. Aborting");
- }
- else {
- recnum = 1;
- do {
- retries = MAXRETRIES;
- PText(2,TXPOS,numform,(ULONG)recnum);
-
- /* Try to get the block until no errors occurred or the retry count
- * reached 0. */
-
- while ((retries) &&
- (((status = rdata(rbuf,baudrate,&blklen)) != GS_NONE) ||
- (!docrc(rbuf,blklen+6)))
- ) {
-
- /* Reception of block failed (timeout or CRC mismatch). Send NAK */
-
- if (--retries) {
- if (CheckAbort()) {
- sendx();
- retries = 0;
- }
- else {
- SENDCHAR(NAK); /* Send NAK if receive failed */
- if (status == GS_TIMEOUT)
- PText(5,TXPOS,"Timeout waiting for block. Retry %ld",
- (ULONG)MAXRETRIES-retries);
- if (status == GS_NONE)
- PText(5,TXPOS,"CRC checksum mismatch. Retry %ld",
- (ULONG)MAXRETRIES-retries);
- }
- }
- else
- PText(5,TXPOS,"Retry count exceeded. Aborting");
- }
-
- if (CheckAbort()) {
- retries = 0;
- sendx();
- }
-
- ctrl = *(rbuf + 2); /* The control byte */
- recrec = *(rbuf + 3); /* Low byte of block number we received */
- if (retries) {
- bufptr = rbuf + 4; /* Default ptr to uncompressed data */
- if (ctrl & COMP) { /* Uncompress if data is compressed */
- blklen = decode(bufptr,cbuf,blklen);
- bufptr = cbuf;
- }
-
- if (ctrl & ABORT) {
- sendx();
- PText(5,TXPOS,"Transmission aborted by sender");
- retries = 0;
- }
- else {
- if (recrec == (recnum & 0xff)) {
- if (Write(file,bufptr,(ULONG)blklen) < blklen) {
- sendx();
- PText(5,TXPOS,"File write failed. Aborting");
- retries = 0;
- }
- else {
- PText(5,TXPOS,"Block %ld received",(ULONG)recnum);
- totlen += blklen;
- PText(4,TXPOS,numform,totlen);
- recnum++; /* Update expected record number */
- SENDCHAR(ACK); /* Allow sender to continue */
- checkeof(ctrl,&success); /* See if this is the last block */
- }
- }
- else {
- PText(5,TXPOS,"Expected block %ld, received %ld",
- (ULONG)recnum & 0xff, (ULONG)recrec);
- SENDCHAR(ACK);
- checkeof(ctrl,&success);
- if (success == TRUE) {
- success = FALSE;
- retries = 0;
- }
- }
- }
- }
- else {
- sendx();
- }
- } while ((!success) && (retries)); /* Continue until success or failure */
-
- /* Find out length of file before closing it */
-
- bufptr = (UBYTE *)Seek(file,0L,OFFSET_CURRENT);
- PText(1,TXPOS,numform,bufptr);
- Close(file); /* Close the file */
- if (bufptr == NULL) /* Delete file if length is 0 */
- DeleteFile(name);
- }
- if (success)
- return(TRUE);
- else
- return(FALSE);
- }
-
- checkeof(ctrl,success)
- register UBYTE ctrl;
- register int *success;
- {
- register int a;
-
- if (ctrl & EOF) { /* This was the last block */
- for (a=4; a; a--) SENDCHAR(ACK); /* Send 4 ACK's */
- *success = TRUE; /* We have success */
- }
- }
-
- int jsend(name, rbuf, sbuf, cbuf)
- /* This routine takes a file name and sends it to the remote system
- * using the JMODEM transfer protocol. The function returns TRUE if
- * the file was successfully sent.
- */
- char *name;
- register UBYTE *rbuf, *sbuf, *cbuf;
- {
- UBYTE *bufptr;
- int blklen = 6, status;
- APTR file;
- ULONG totsize = 0,fsize = 0;
- register struct IntuiMessage *imsg;
- register int abort = FALSE;
-
- retries = 0;
- recnum = 0;
-
- /* Open the source file and if that succeeds try to get in touch with
- * the receiver */
-
- PText(2,TXPOS,"1");
- PText(3,TXPOS,numform,(ULONG)stringsize);
- PText(4,TXPOS,"0");
-
- if ((file = Open(name,MODE_OLDFILE))==0)
- PText(5,TXPOS,"Could not open file");
-
- if ((file == 0) || (!txsynch(file,&totsize)))
- sendx(); /* No sync. Abort transfer */
- else {
-
- /* File is open and sync has been established. Proceed to send the file */
-
- do {
- fsize += (blklen - 6); /* Header is not counted in bytes transferred */
- PText(4,TXPOS,"%ld (%ld%% remains)", fsize, 100 - fsize * 100 / totsize);
-
- /* Read the source file */
-
- if ((blklen = readfile(file, sbuf+4, cbuf+4, &bufptr)) >= 6) {
- retries = MAXRETRIES;
- do {
-
- /* Check if user has hit the 'Abort' gadget */
-
- if (abort = CheckAbort()) {
- PText(5,TXPOS,"User abort! Telling receiver to quit");
- *(bufptr + 2) |= ABORT; /* Set ABORT bit in control byte */
- docrc(bufptr,blklen); /* Recalculate checksum */
- }
-
- /* Send the block */
-
- sendserdata(bufptr,(ULONG)blklen);
-
- /* Get ACKnowldge from receiver.
- * Loops until ACK, NAK or CAN is received (or user aborted) */
-
- do {
- if ((status = getserchar(13*50L,rbuf)) != GS_NONE) {
- if (status == GS_TIMEOUT)
- PText(5,TXPOS,"Timeout waiting for response. Aborting");
- abort = TRUE;
- }
- } while ((*rbuf != ACK) &&
- (chkres(*rbuf,&retries,&blklen) == FALSE) &&
- (abort == FALSE));
- } while ((*rbuf != ACK) && (retries > 0) && (abort == FALSE));
-
- if ((retries) && (blklen > 0) && (abort == FALSE))
- PText(5,TXPOS,"Block %ld sent",(ULONG)recnum);
- }
- } while (((*(bufptr + 2) & EOF) == 0) && (blklen >= 6) && (abort == FALSE));
-
- if (blklen < 0) {
- sendx();
- PText(5,TXPOS,"File read failed. Transmission aborted");
- }
- }
- if (abort)
- sendx();
- if (file) Close(file);
- if ((retries) && (abort == FALSE)) {
- fsize += (blklen - 6);
- PText(4,TXPOS,"%ld (0% remains)", fsize);
- return TRUE;
- }
- else
- return FALSE;
- }
-
- int txsynch(file,totsize)
- /* Get in sync. with remote and wait 0.3 seconds before returning */
- register APTR file;
- register APTR *totsize;
- {
- (void) Seek(file,0L,OFFSET_END);
- *totsize = Seek(file,0L,OFFSET_BEGINNING);
- PText(1,TXPOS,numform,*totsize);
- if (rxsync()) {
- Delay(15L);
- return(1);
- }
- else
- return(0);
- }
-
- int rxsync() {
- /* Get in syncronization with remote. Returns 0 if sync not
- * achieved. */
-
- register int a, abort = FALSE;
- register struct IntuiMessage *imsg;
-
- PText(5,TXPOS,"Synchronizing...");
- clearbuf();
-
- /* See if remote has sent something. If nothing is read in 2 seconds, we
- * send a NAK character. This is repeated until something is read */
-
- while ( (!(abort = CheckAbort())) && (getserchar(100L,rbuf)==GS_TIMEOUT)) {
- SENDCHAR(NAK);
- }
-
- /* If user pressed Abort gadget then cancel and return */
-
- if (abort) {
- sendx();
- return(0);
- }
-
- /* Check if we have quick syncronization */
-
- if ((*rbuf == ACK) || (*rbuf == NAK)) {
- if (*rbuf == NAK) {
- SENDCHAR(ACK); /* Send ACK if we got NAK */
- }
- PText(5,TXPOS,"Synchronized");
- return(1);
- }
-
- /* Well, quick sync. apparently failed. Do long handshaking with SYN
- * characters */
-
- for (a=0; a<64; a++)
- do {
- SENDCHAR(SYN); /* Send a SYN and wait for response */
- if (!(abort = CheckAbort())) {
- if (getserchar(150L,rbuf) != GS_NONE) {
- PText(5,TXPOS,"Synchronization not acquired");
- clearbuf();
- return(0);
- }
- if (*rbuf == CAN) {
- PText(5,TXPOS,"Remote system cancelled");
- clearbuf();
- return(0);
- }
- }
- else
- a = 64;
- } while ((*rbuf != SYN) && (!abort));
-
- if (!abort) {
- SENDCHAR(SYN);
- clearbuf();
- PText(5,TXPOS,"Synchronized");
- return(1);
- }
- else {
- sendx();
- return(0);
- }
- }
-
- void clearbuf() {
- /* Empty receiving buffer */
- RR->IOSer.io_Command = CMD_CLEAR; /* Flush receive buffer */
- DoIO(RR);
- }
-
- int rdata(buffer, baud, length)
- /* Receive bytes from the serial port. Variable 'baud' specifies the
- * current baud rate. From this value a timeout value is calculated
- * once we know the length of the block we are receiving.
- * The function returns an error code, and GS_NONE if all went well
- * The variable 'length' gets the block size (header not included),
- * which can be inspected from outside of this routine. */
-
- UBYTE *buffer;
- ULONG baud;
- UWORD *length;
- {
- register UWORD temp;
- register UWORD slen;
- ULONG timeout;
- int status;
-
- /* Get two bytes from the serial port. This is the length of the block,
- * (with low byte first of course :-( Timeout value is 6 seconds. */
-
- *length = 0;
- status = getserdata(300L,buffer,2L);
- if (status == GS_NONE) {
- slen = (*(buffer + 1) << 8) + *buffer; /* Extract length of string */
- *length = slen - 6;
- PText(3,TXPOS,numform,(ULONG)slen - 6);
- buffer += 2;
- timeout = 300L + ((3 * calctime(baud,slen-2)) >> 1); /* Estimate timeout */
- status = getserdata(timeout,buffer,(ULONG)slen-2L);
- }
- return(status);
- }
-
- ULONG calctime(baud,numbytes)
- /* This routine estimates how long it will take to receive
- * a specific number of bytes over a serial link at a specific
- * baud rate. The result is given in 20 millisecond (1/50 s) units
- */
- register ULONG baud;
- register UWORD numbytes;
- {
- return(400L * numbytes / baud);
- }
-
- int readfile(file, sbuf, cbuf, usebuffer)
- /* Read file to send into data buffer and change the string size according
- * to previous results. Build the string header, syntax (bytes):
- * LOWLEN, HILEN, CONTROL, REC, data bytes according to string size, CRC, CRC
- * Compress the read data and use the compressed version if it is shorter
- * than the uncompressed. The function returns the actual number of bytes to
- * transmit, or negative if an error occurred.
- * Uses external variables int stringsize, UWORD recnum
- */
- ULONG file;
- register UBYTE *sbuf, *cbuf, **usebuffer;
- {
- register int rawcount,codedcount;
-
- if (retries == MAXRETRIES) { /* If no transfer error occured in last block */
- if (stringsize < MAXSTRING) /* and the block size is not already 8TXPOS2 */
- stringsize +=DSTRING; /* then increase block size by 512 bytes */
- }
- else /* A transfer error occurred in last block. */
- if (stringsize > MINSTRING) /* If the blocksize isn't already at minimum */
- stringsize >>= 2; /* stringsize = stringsize DIV 4 */
-
- /* Read data from file. Create compressed version of data */
-
- if ((rawcount = Read(file,sbuf,(LONG)stringsize)) <= 0)
- return (rawcount);
- codedcount = encode(sbuf,cbuf,rawcount);
-
- /* If compressed data is shorter than uncompressed, then use the
- * compressed version. */
-
- if (codedcount < rawcount) {
- PText(3,TXPOS,"%ld (%ld%% compressed)",
- (ULONG)codedcount,
- (ULONG)100 - (LONG)codedcount * 100 / rawcount);
- codedcount += 6; /* Include the header bytes into length */
- cbuf -= 4; /* To beginning of header */
- *cbuf++ = (codedcount & 0xff); /* Low byte of string length */
- *cbuf++ = (codedcount >> 8); /* High byte of string length */
- *cbuf = COMP; /* Compressed block */
- if (rawcount < stringsize)
- *cbuf |= EOF; /* Set EOF flag if needed */
- cbuf++;
- *cbuf++ = ++recnum & 0xff; /* Record number (low byte) */
- docrc(cbuf-4,codedcount); /* Calculate checksum for the block */
- *usebuffer = cbuf-4;
- PText(2,TXPOS,numform,(ULONG)recnum);
- return(codedcount);
- }
- else {
- PText(3,TXPOS,"%ld (not compressed)",(ULONG)rawcount);
- rawcount += 6;
- sbuf -= 4;
- *sbuf++ = (rawcount & 0xff);
- *sbuf++ = (rawcount >> 8);
- *sbuf = NORMAL; /* Normal block, not compressed */
- if (rawcount < stringsize)
- *sbuf |= EOF; /* Set EOF flag if needed */
- sbuf++;
- *sbuf++ = ++recnum & 0xff;
- docrc(sbuf-4,rawcount);
- *usebuffer = sbuf-4;
- PText(2,TXPOS,numform,(ULONG)recnum);
- return(rawcount);
- }
- }
-
- int decode(srcbuf, dstbuf, srccnt)
- /* Uncompress data pointed to by srcbuf, place resulting data into
- * buffer pointed to by dstbuf. We have srccnt bytes to uncompress.
- * Returns the destination length. */
-
- register UBYTE *srcbuf, *dstbuf;
- register int srccnt;
- {
- register UBYTE chr;
- register UWORD dstcnt = 0, count;
-
- while (srccnt-- > 0) { /* Until whole source buffer processed */
- if ((chr = *srcbuf++) != BB) { /* Do we have the 'sentinel' byte? */
- *dstbuf++ = chr; /* Just transfer to destbuffer if not */
- dstcnt++;
- }
- else { /* The 'sentinel' byte was met */
- count = (*(srcbuf + 1) << 8); /* Fetch high byte of repeat count */
- count += *srcbuf; /* Fetch low byte of repeat count */
- srcbuf += 2;
- chr = *srcbuf++; /* Fetch character to repeat */
- srccnt -= 3;
- dstcnt += count;
- for (; count > 0; *dstbuf++ = chr, count--);
- }
- }
- return(dstcnt);
- }
-
- int encode(srcbuf, dstbuf, srccnt)
- /* Compress data pointed to by srcbuf, place resulting data into buffer
- * pointed to by dstbuf. We have srccnt bytes to compress. Returns the
- * destination length */
-
- UBYTE *srcbuf, *dstbuf;
- int srccnt;
- {
- register UBYTE curchar, *tmpsrc;
- register int dstcnt = 0, srcc = srccnt;
- register int remaining;
- register UWORD dupcnt;
-
- /* Start compressing. If the destination buffer size gets equal or larger
- * than the source buffer then the compression is immediately aborted.
- * You may use the compressed version only if it is smaller than the
- * uncompressed data. */
-
- while ((srcc > 0) && (dstcnt < srccnt)) {
- curchar = *srcbuf++; /* Get current character to process */
- tmpsrc = srcbuf; /* Ptr to next position in buffer */
- dupcnt = 1; /* Number of identical copies we have found */
- remaining = --srcc; /* Number of characters still unprocessed in buffer */
- while ((*tmpsrc++ == curchar) && (remaining--))
- dupcnt++; /* Count number of identical chars */
-
- /* Perform compression if the 'sentinel' byte 0xBB was met or the number of
- * identical characters was more than 4 */
-
- if ((curchar == BB) || (dupcnt > 4)) {
- *dstbuf++ = BB; /* Sentinel character for identification */
- *dstbuf++ = (dupcnt & 0xff); /* Store low byte of length first */
- *dstbuf++ = (dupcnt >> 8); /* then high byte */
- *dstbuf++ = curchar; /* The character we are processing */
- dstcnt += 4; /* Update destination count */
- srcbuf = tmpsrc - 1; /* Continue reading after handled chars */
- srcc -= dupcnt - 1; /* Decrement byte count of source buf. */
- }
- else { /* Store uncompressed */
- *dstbuf++ = curchar;
- dstcnt++;
- }
- }
- return (dstcnt);
- }
-
- int chkres(chr,retries,len)
- /* We should have got a ACK, but didn't. Find out what we did get.
- * This function returns FALSE if garbage was received. Returns TRUE
- * if we could interpret the character */
- register UBYTE chr;
- register int *retries, *len;
- {
- if (chr == CAN) {
- sendx(); /* Receiver sent CAN. Abort transfer */
- PText(5,TXPOS,"Receiver aborted. Transmission ended");
- *retries = 0;
- *len = 0;
- return TRUE;
- }
- if (chr != NAK) /* If not NAK it must be garbage. Get ACK again */
- return FALSE;
- else
- if (--(*retries)) /* Receiver didn't get. Update retry counter */
- return TRUE; /* Resend until retry counter is zero */
- else {
- sendx(); /* Tell receiver to stop waiting. We stop trying */
- *len = 0;
- PText(5,TXPOS,"Bad connection, giving up");
- return TRUE;
- }
- }
-
- void sendx() {
- /* Send 10 CAN chars (== CTRL-X) to remote */
- register int a;
- for (a=10; a!=0; a--) {
- SENDCHAR(CAN);
- }
- }
-
- APTR htol(str)
- /* Convert a hexadecimal string to a long integer */
- register char *str;
- {
- register char chr;
- register ULONG num = 0, multiplier = 1;
- register int cnt = 0;
-
- while (*(str + cnt++)); /* Find last character in string */
-
- while (--cnt) { /* Process all digits */
- chr = *(str + cnt - 1); /* Get character into a register */
- if (chr >= 'a') /* Convert to upper case letter */
- chr -= 32;
- num += (chr<='9') ? multiplier*(chr-'0') : multiplier*(chr-'A'+10);
- multiplier <<= 4; /* Multiplier * 16 */
- }
- return((APTR)num);
- }
-
- void Jcleanup(num)
- /* Perform resource deallocation. Uses global variable 'RetCode' */
- register int num;
- {
- switch(num) {
- case JC_NONE:
- case JC_IOREQ:
- FreeMem(cbuf,BUFSIZE2);
- case JC_CBUF:
- FreeMem(sbuf,BUFSIZE1);
- case JC_SBUF:
- FreeMem(rbuf,BUFSIZE1);
- default: ;
- }
- exit(RetCode);
- }
-