📄 xcxmdm.c
字号:
/* xcxmdm.c -- XMODEM Protocol module for XC This file uses 4-character tabstops*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <sys/types.h>#include <utime.h>#include <sys/stat.h>#include <signal.h>#include <setjmp.h>#include "xc.h"#define WANTCRG 'G'#define WANTCRC 'C'#define FALLBACK 16#define CPMEOF 032 /* ^Z */#define OK 0#define TIMEOUT -1 /* -1 is returned by readbyte() upon timeout */#define ERROR -2#define WCEOT -3#define RETRYMAX 10#define Maxtime 10#define SECSIZ 1025#define Resume_Not_Allowed 1#define RxUpdcrc(c,crc) (crc_xmodem_tab[((crc>>8)&0xff)]^(crc<<8)^c)&0xffff#define TxUpdcrc(c,crc) (crc_xmodem_tab[((crc>>8)^c)&0xff]^(crc<<8))#include <assert.h> static short int smallhdr = FALSE;static short int badline = FALSE;static short int g_flag = FALSE;static short int y_done = FALSE; short int y_flag = FALSE; /* global used in xcmain.c *//* define storage for info from decoding ymodem rx header */static struct yinfo { char *fnam ; long int fsiz ; time_t fdat ; unsigned long fprm ;} phdr ;/* crc_xmodem_tab calculated by Mark G. Mendel, Network Systems Corporation */unsigned short crc_xmodem_tab[256] ={ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0};static short crcheck = TRUE; /* CRC check enabled? */static FILE *xfp; /* buffered file pointer */static short firstsec, /* first sector of file or not? */ ksecsize, /* for Xmodem or old Ymodem packet */ stx_soh, /* SOH = Xmodem ; STX = old Ymodem */ amdone = FALSE, /* flag: xfer almost finished */ sync, /* flag for negotiating crc or checksum */ textmode = FALSE; /* Text translations enabled? */static char wcbuf[SECSIZ]; /* Ward Christensen sector buffer */static jmp_buf our_env;static char *p, sendchar;/* send cancel string to get the other end to shut up */voidcanit P_((void)){ char canistr[] = { 24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0 }; send_string(canistr);}static RETSIGTYPExmsigint(junk)int junk;{ signal (SIGINT, SIG_IGN); /* Ignore subsequent DEL's */ show_abort (); canit (); /* Abort the transmission */ longjmp (our_env, 1);}/* fill the CP/M sector buffer from the UNIX file do text adjustments if necessary return 1 if more sectors are to be read, or 0 if this is the last*/static intgetsec P_((void)){ int i; register c = 0 ; static int j, fbinit, fback; if ( firstsec && y_flag ) /* build ymodem header */ { return y_done? 0 : 1 ; } else if (amdone == FALSE) { i = 0; j = 8; fbinit = fback = TRUE; while (i < ksecsize && (c = getc (xfp)) != EOF) { if (textmode && c == '\n') { wcbuf[i++] = '\r'; if (i >= ksecsize) { /* handle a newline on the last byte */ ungetc (c, xfp); /* of the sector */ return (1); } } wcbuf[i++] = c; } /* make sure that an extra blank sector is not sent */ if (c != EOF && (c = getc (xfp)) != EOF) { ungetc (c, xfp); return (1); } /* fill up the last sector with ^Z's if text mode or 0's if binary mode */ j = i; while (i < ksecsize) wcbuf[i++] = textmode ? CPMEOF : '\0'; amdone = TRUE; fback = FALSE; if ( y_flag || stx_soh == SOH || j > 896) /* done, send whole sector */ return (0); j += 127; j >>= 7; /* calculate number of 128 bytes sectors to send */ fbinit = TRUE; } /* end of "amdone" */ if (fbinit) { p = wcbuf; /* save old buffer base address */ p -= 128; stx_soh = SOH; /* switch to 128 byte blocks */ ksecsize = 128; fbinit = FALSE; } /* end of "fbinit" */ p += 128; memcpy (wcbuf, p, 128); if (--j > 0) /* more packets remain */ return (1); else { if (fback) { amdone = FALSE; return (1); } else return (0); }}/* automatically negotiate crc or checksum reception */static charsyncem P_((void)){ int ct = 2; char c; purge (); while (ct) { /* try to negotiate a CRC transfer */ sendbyte ( g_flag ? WANTCRG : WANTCRC ); c = readbyte (10); if (c != CAN && c != SOH && c != STX) ct--; else { sendchar = ACK; crcheck = g_flag ? WANTCRG : WANTCRC ; return (c); } if ( g_flag ) { ct = 2, g_flag = FALSE ;} /* try again without "G" */ } ct = 2; purge (); while (ct) { /* maybe we can initiate a checksum transfer */ sendbyte (NAK); c = readbyte (10); if (c != CAN && c != SOH && c != STX) ct--; else { sendchar = ACK; crcheck = FALSE; return (c); } } purge (); return (TIMEOUT);}/* wcgetsec() inputs an XMODEM "sector". This routine returns the sector number encountered, or ERROR if a valid sector is not received or CAN received; or WCEOT if EOT sector. Maxtime is the timeout for the first character, set to 10 seconds for retries. No ACK is sent if the sector is received ok. This must be done by the caller when it is ready to receive the next sector.*/static intwcgetsec (maxtime) unsigned maxtime;{ register unsigned oldcrc; register checksum, j, c = 0; int sectcurr, sectcomp, attempts; if (sync == FALSE) { /* negotiate crc or checksum error detection */ c = syncem (); if (crcheck == FALSE) show (1, "ATTENTION: sender demands CHECKSUM error detection "); else show (1, "CRC packet validation enabled "); } for (attempts = 0; attempts < RETRYMAX; attempts++) { if (sync == TRUE) { do { c = readbyte (maxtime); } while (c != STX && c != SOH && c != EOT && c != CAN && c != TIMEOUT); } else sync = TRUE; switch (c) { case STX: case SOH: if (c == SOH) ksecsize = 128; /* xmodem packet size */ else ksecsize = 1024; /* ymodem packet size */ sectcurr = readbyte (3); sectcomp = readbyte (3); if ((sectcurr + sectcomp) == 0xff) { oldcrc = checksum = 0; for (j = 0; j < ksecsize; j++) { if ((c = readbyte (3)) == TIMEOUT) goto timeout; wcbuf[j] = c; oldcrc = RxUpdcrc (c, oldcrc); checksum += c; } if ((c = readbyte (3)) < 0) goto timeout; if (crcheck) { oldcrc = RxUpdcrc (c, oldcrc); if ((c = readbyte (3)) == TIMEOUT) goto timeout; if (RxUpdcrc (c, oldcrc)) { show(2,"CRC error "); if(g_flag) { show(2,"G-mode cancel "); goto gquit ; } break; } } else if (((checksum - c) & 0xff) != 0) { show(2,"Checksum error"); break; } return (sectcurr); } else /* packet header garbled */ { sprintf (Msg, "Packet number garbled %03d %03d", sectcurr, sectcomp); show (2,Msg); if(g_flag) { show(2,"G-mode cancel"); goto gquit ; } } break; case EOT: if (readbyte (3) == TIMEOUT) return (WCEOT); break; case CAN: show(2,"Sender CANcelled"); return (ERROR); case TIMEOUT: timeout: show(2,"Timeout"); break; } show(2,"Trying again on this sector"); purge (); maxtime = 6, sendbyte (NAK); } show(2,"Retry count exceeded");gquit: canit (); return (ERROR);}static intputsec P_((void)){ int i; register c; /* for y_modem: only write the exact number of chars */ if ( y_flag && 0 < phdr.fsiz ) { phdr.fsiz -= ksecsize ; if ( phdr.fsiz < 0 ) ksecsize += phdr.fsiz ; } for (i = 0; i < ksecsize; i++) { c = wcbuf[i]; if (textmode) { if (c == CPMEOF) return (1); if (c == '\r') continue; } putc (c, xfp); } return (0);}static voidset_dp( name_fl, time_fl, perm_fl ) const char *name_fl; const time_t time_fl; const unsigned long perm_fl;{ struct utimbuf utb ; if ( name_fl != NULL ) { if ( time_fl != 0 ) { utb.actime = utb.modtime = time_fl ; if ( utime( name_fl, &utb )) perror(name_fl); } if ( perm_fl != 0 ) { if ( chmod( name_fl, (mode_t) perm_fl )) perror(name_fl); } }}/* wcputsec outputs a Ward Christensen type sector. it returns OK or ERROR*/static intwcputsec (sectnum) int sectnum;{ unsigned short oldcrc; int checksum, j, c, attempts, errct = 0; oldcrc = checksum = 0; for (j = 0; j < (smallhdr ? 128 : ksecsize); j++) { c = wcbuf[j]; oldcrc = TxUpdcrc (c, oldcrc); checksum += c; } for (attempts = 0; attempts < RETRYMAX; attempts++) { sendbyte (smallhdr ? SOH : stx_soh); sendbyte (sectnum); sendbyte (-sectnum - 1); for (j = 0; j < (smallhdr ? 128 : ksecsize); j++) sendbyte (wcbuf[j]); /* Wait for output to drain before sending checksum/crc. Clear input buffer of any noise in anticipation of an acknowledgement after we send the checksum/crc. */ xc_drain (DRAIN_FLAG); if (crcheck) { sendbyte ((int) (oldcrc >> 8)); sendbyte ((int) oldcrc); } else sendbyte (checksum); /* check for response */ if (firstsec && y_flag) { if (g_flag) { /* Ymodem-g */ int ack_ct = 12; /* arbitrary max ACKS before error */ int timeout_ct = 4; /* arbitrary max number of timeouts */ if (y_done) { purge (); /* delete any extraneous trailing ACKs */ return OK; } do { c = readbyte (10); if (c == WANTCRG || c == CAN) break; else if (c == TIMEOUT) timeout_ct--; else c = TIMEOUT; } while (--ack_ct && timeout_ct); /* according to Forsberg any response other than the following is undefined at this sequence point in the ymodem-g protocol: */ assert (c == TIMEOUT || c == WANTCRG || c == CAN); } else { /* normal non-streaming ymodem */ c = readbyte (10); if (c == ACK) { firstsec = smallhdr = FALSE; if (y_done) return OK; c = readbyte (20); } } if (crcheck && c == crcheck) { assert (c == WANTCRC || c == WANTCRG); firstsec = smallhdr = FALSE; return OK; } } else { c = readbyte (g_flag ? RB_POLL : 10); } /* detect false CAN, require 2 in a row */ if (c == CAN) c = readbyte (g_flag ? 1 : 10); if (g_flag && c != CAN && (!firstsec || !y_flag)) return OK; switch (c)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -