/************************************************************************* ** File: xmodem.c ** contains xmodem send and receive functions ** ** Functions: ** XMODEM_Read_File() - xmodem protocol receive file from remote ** XMODEM_Send_File() - xmodem protocol send file to remote ** clrcrc() - initialize CRC and Checksum values ** updcrc() - calculate CRC or Checksum ** *************************************************************************/ #include "term.h" SHORT crc = 1; /* default to CRC mode */ USHORT crcaccum, checksum, rec, abort = 0; /* oper abort request */ extern struct MenuItem X_Sub_Item[]; extern int bufr_ptr, timeout, fd; extern char *bufr; extern char *getmem(); /**************************************/ /* xmodem send and recieve functions */ /************************************/ XMODEM_Read_File(file) char *file; { char line[80]; unsigned char ch; /* scratch handshake var */ unsigned char response; /* ACK/NAK/CRC handshake */ unsigned char rcksum; /* rec'd Checksum */ unsigned char r1; /* current record number */ unsigned char r2; /* 1's complement " */ int errors, /* error count */ hdr_time, /* header time out value */ chr_time; /* character time out value */ USHORT i, j; register char *buffer; /* start of 128 byte sector */ if (X_Sub_Item[0].Flags & CHECKED) crc = 1; else crc = 0; if (X_Sub_Item[2].Flags & CHECKED) { hdr_time = 10; chr_time = 10; } else { hdr_time = 20; /* note: LONG time out values */ chr_time = 20; } if (bufr == NULL) { if ((bufr = getmem(BufSize)) == NULL) { emits("Unable to Allocate Buffer\n"); return FALSE; } } if ((fd = creat(file, 0)) < 0) { emits("Cannot Open File\n"); return FALSE; } else sprintf(line,"\nReceiving File %s\n",file); emits(line); rec = 1; abort = 0; buffer = bufr; /* start of big buffer */ if (crc) response = CRC; /* CRC of CheckSum */ else response = NAK; if (!open_time()) { /* open timer device */ close(fd); return FALSE; } while (TRUE) { timeout = errors = 0; ch = '\0'; for (i = 1;i<200;i++) { timeout = 0; if (abort) response = CAN; if (ch == '\0') sendchar(response); /* send handshake */ if (response == CAN) { for (j=0;j<5;j++) sendchar(CAN); for (j=0;j<6;j++) sendchar('\b'); close(fd); close_time(); emits("\nTransfer Cancelled\n"); return(FALSE); } start_timer(hdr_time); if ((ch = readchar()) == SOH) { kill_timer(); sprintf(line,"\rReceiving # %d ",rec); emits(line); break; /* SOH indicates rec */ } if (timeout) { ch = '\0'; if (response == CRC) { if (++errors >= ERRORMAX/2) { emits("\nCRC handshake failed - switching to CheckSum\n"); response = NAK; crc = 0; i = 1; /* begin loop over */ continue; } continue; } /* endif response == CRC */ else { /* response not == CRC */ if (++errors >= ERRORMAX) { emits("\nCan't sync to sender\n"); close(fd); close_time(); return(FALSE); } } } kill_timer(); if (ch == EOT) { /* EOT indicates done */ if (buffer > bufr) { if (write(fd,bufr,buffer - bufr) == -1) emits("Error writing last buffer\n"); } sendchar(ACK); close(fd); close_time(); sprintf(line,"\nFile %s received\n",file); emits(line); return(TRUE); } if (ch == CAN) { if (buffer > bufr) { if (write(fd,bufr,buffer - bufr) == -1) emits("\nError writing last buffer\n"); } close(fd); close_time(); emits("Sender cancelled - aborted\n"); return(FALSE); } if (i==199) { /* handshake timeout */ emits("\nCan't sync to sender\n"); close(fd); close_time(); return(FALSE); } } start_timer(chr_time); /* set timeout for block */ r1 = readchar(); /* record number */ r2 = readchar(); /* 1's comp rec # */ clrcrc(); for (j = 0;j < SECSIZ;j++) { buffer[j] = readchar(); if (timeout) j = SECSIZ; else updcrc(buffer[j]); } if (!timeout) { rcksum = readchar(); if (crc) { updcrc(rcksum); if (!timeout) updcrc(readchar()); } } response = NAK; /* init response */ if (timeout) { emits(" *** Timeout ***\n"); if (++errors > ERRORMAX) abort = TRUE; continue; } kill_timer(); if ((~r1 & 0xff) != (r2 & 0xff)) { emits(" *** record numbers don't match\n"); if (++errors > ERRORMAX) abort = TRUE; continue; } if (crc) { /* CRC test */ if (crcaccum != 0) { emits(" CRC error\n"); if (++errors > ERRORMAX) abort = TRUE; continue; } } else if (rcksum != (checksum & 0xff)) { sprintf(line," CheckSum error - recvd %02x, calcd %02x\n",rcksum,checksum&0xff); emits(line); if (++errors > ERRORMAX) abort = TRUE; continue; } if (r1 == (rec - 1) & 0xff) { /* duplicate ? */ emits(" received duplicate record\n"); response = ACK; /* duplicate is ok */ continue; } if (r1 != (rec & 0xff)) { /* fatal sequence error */ emits(" Sequence error\n"); if (++errors > ERRORMAX) abort = TRUE; continue; } rec ++; if ((buffer += SECSIZ) >= (bufr + BufSize)) { if (write(fd,bufr,BufSize) == -1) { emits("\nWrite error - xfer cancelled\n"); abort = 1; continue; } buffer = bufr; /* reset buffer */ } response = ACK; /* normal loop end */ } } XMODEM_Send_File(file) char *file; { char line[80]; char c; /* scratch handshake var */ unsigned int bytes_to_send, size; int attempts; /* error count */ USHORT j; register char *buffer; /* start of 128 byte sector */ if (bufr == NULL) { if ((bufr = getmem(BufSize)) == NULL) { emits("Unable to Allocate Buffer\n"); return FALSE; } } timeout=FALSE; if ((fd = open(file, 1)) < 0) { emits("Cannot Open Send File\n"); return FALSE; } else sprintf(line,"\nSending File %s\n",file); emits(line); abort = attempts = 0; rec = 1; if (!open_time()) { close(fd); return FALSE; } start_timer(10); /* wait for sync char */ j=1; while (((c = readchar()) != NAK) && (c != CRC) && (j++ < ERRORMAX)) { if (abort) { kill_timer(); close(fd); close_time(); return FALSE; } if (timeout) start_timer(10); } kill_timer(); if (j >= (ERRORMAX)) { emits("\nReceiver did not handshake\n"); close(fd); close_time(); return FALSE; }; if (c == CRC) { emits("\nCRC requested\n"); crc = 1; } else { emits("\nCheckSum requested\n"); crc = 0; } while ((bytes_to_send = read(fd, bufr, BufSize)) && attempts != RETRYMAX) { if (bytes_to_send == EOF) { emits("\nError Reading File\n"); for (j=0;j<5;j++) sendchar(CAN); for (j=0;j<6;j++) sendchar('\b'); close(fd); close_time(); return FALSE; }; buffer = bufr; while (bytes_to_send > 0 && attempts != RETRYMAX) { attempts = 0; do { clrcrc(); sprintf(line,"\rSending record %d",rec); emits(line); sendchar(SOH); sendchar(rec&0xff); sendchar(~(rec&0xff)); size = SECSIZ <= bytes_to_send ? SECSIZ : bytes_to_send; bytes_to_send -= size; for (j = 0; j < SECSIZ; j++) if (j < size) { sendchar(buffer[j]); updcrc(buffer[j]); } else { sendchar(0); updcrc(0); } if (crc) { updcrc(0); updcrc(0); sendchar((crcaccum >> 8) & 0xff); sendchar(crcaccum & 0xff); } else sendchar(checksum & 0xff); attempts++; start_timer(10); c = readchar(); if (!timeout) kill_timer(); } while ((c != ACK) && (c != CAN) && (attempts != RETRYMAX) && (!abort)); if (attempts == RETRYMAX) { emits("\nRetry Limit Reached - send cancelled\n"); for (j=0;j<5;j++) sendchar(CAN); for (j=0;j<6;j++) sendchar('\b'); close(fd); close_time(); return(FALSE); } if (abort) { emits("\nSend cancelled per operator request\n"); for (j=0;j<5;j++) sendchar(CAN); for (j=0;j<6;j++) sendchar('\b'); close(fd); close_time(); return(FALSE); } if (c == CAN) { emits("\nReceiver cancelled transfer\n"); close(fd); close_time(); return(FALSE); } buffer += size; rec++; } } close(fd); attempts = 0; do { if (attempts && !timeout) kill_timer(); sendchar(EOT); attempts++; start_timer(10); } while ((readchar() != ACK) && (attempts != RETRYMAX) && (timeout == FALSE)); if (attempts == RETRYMAX) emits("\nNo Acknowledgment Of End Of File\n"); if (!timeout) kill_timer(); close_time(); return TRUE; } clrcrc() { crcaccum = checksum = 0; } updcrc(c) unsigned char c; { unsigned shifter, flag; if (crc) { for (shifter = 0x80;shifter;shifter >>= 1) { flag = (crcaccum & 0x8000); crcaccum <<= 1; crcaccum |= ((shifter & c) ? 1 : 0); if (flag) crcaccum ^= 0x1021; } } else { checksum = ((checksum + c) & 0xff); } }