ZRECEIVE.C
资源名称:zmodem.zip [点击查看]
上传用户:haiyue
上传日期:2007-01-05
资源大小:21k
文件大小:32k
源码类别:
通讯/手机编程
开发平台:
C/C++
- /*--------------------------------------------------------------------------*/
- /* FILE: zreceive.c (Opus zmodem receiver) */
- /* */
- /* */
- /* The Opus Computer-Based Conversation System */
- /* (c) Copyright 1986, Wynn Wagner III, All Rights Reserved */
- /* */
- /* This implementation of Chuck Forsberg's ZMODEM protocol was */
- /* for Opus by Rick Huebner and Wynn Wagner III */
- /* */
- /* (MSC/4 with /Zp /Ox) */
- /* */
- /* */
- /* */
- /* */
- /* This module is similar to a routine used by Opus-Cbcs (1.00). It is */
- /* provided for your information only. You will find routines that need */
- /* to be coded and identifiers to be resolved. */
- /* */
- /* There is absolutely no guarantee that anything here will work. If you */
- /* break this routine, you own both pieces. */
- /* */
- /* USAGE: You may use this material in any program with no obligation */
- /* as long as there is no charge for your program. For more */
- /* information about commercial use, contact the "OPUSinfo HERE" */
- /* BBS (124/111). */
- /* */
- /* NOTE: There are a couple of things the Opus implementation does that */
- /* aren't part of the original ZModem protocol. They all deal */
- /* with WaZOO type ("ZedZap") netmail and should only show up when */
- /* used under that condition. */
- /* */
- /* * The maximum packet size can grow larger than 1k. It is */
- /* sensitive to the baud rate. (2400b=2048k; 9600b=8192k) */
- /* * The sender must be able to send nothing. In other words, */
- /* the sending system must be able to initiate and terminate */
- /* a zmodem send session without having to actually send a */
- /* file. Normally this kind of thing would never happen in */
- /* zmodem. */
- /* */
- /* */
- /*--------------------------------------------------------------------------*/
- #include "zmodem.h"
- /*--------------------------------------------------------------------------*/
- /* External material */
- /*--------------------------------------------------------------------------*/
- extern int dexists(byte *);
- /*--------------------------------------------------------------------------*/
- /* Local routines */
- /*--------------------------------------------------------------------------*/
- int cdecl get_Zmodem(byte *,FILE *);
- static int pascal RZ_ReceiveData(byte *,int );
- static int pascal RZ_InitReceiver(void);
- static int pascal RZ_ReceiveBatch(FILE *);
- static int pascal RZ_ReceiveFile(FILE *);
- static int pascal RZ_GetHeader(void);
- static int pascal RZ_SaveToDisk(unsigned long *);
- static void pascal RZ_AckBibi(void);
- /*--------------------------------------------------------------------------*/
- /* Private declarations */
- /*--------------------------------------------------------------------------*/
- static long DiskAvail;
- /*--------------------------------------------------------------------------*/
- /* Private data */
- /*--------------------------------------------------------------------------*/
- /* Parameters for ZSINIT frame */
- #define ZATTNLEN 32 /* Max length of attention string */
- static char Attn[ZATTNLEN+1]; /* String rx sends to tx on err */
- static FILE *Outfile; /* Handle of file being received */
- static byte *Secbuf; /* Pointer to receive buffer */
- static int Tryzhdrtype; /* Hdr type to send for Last rx close */
- static char isBinary; /* Current file is binary mode */
- static char EOFseen; /* indicates cpm eof (^Z) was received */
- static char Zconv; /* ZMODEM file conversion request */
- static int RxCount; /* Count of data bytes received */
- /*--------------------------------------------------------------------------*/
- /* GET ZMODEM */
- /* Receive a batch of files. */
- /* returns TRUE (1) for good xfer, FALSE (0) for bad */
- /* can be called from f_upload or to get mail from a WaZOO Opus */
- /*--------------------------------------------------------------------------*/
- int cdecl get_Zmodem(rcvpath, xferinfo)
- byte *rcvpath;
- FILE *xferinfo;
- begin
- byte namebuf[PATHLEN];
- int i;
- errno = 0;
- _BRK_DISABLE();
- XON_ENABLE();
- n_disable();
- Secbuf = NULL;
- Outfile = NULL;
- z_size = 0;
- DiskAvail = freespace(toupper(sys.uppath[0])-'@');
- Rxtimeout = 10;
- Tryzhdrtype = ZRINIT;
- Secbuf = zalloc();
- strcpy(namebuf, rcvpath);
- Filename = namebuf;
- if (((i=RZ_InitReceiver())==ZCOMPL) or
- ((i==ZFILE) and ((RZ_ReceiveBatch(xferinfo))==OK)) )
- begin
- free(Secbuf);
- return 1;
- end
- CLEAR_OUTBOUND();
- send_can(); /* transmit at least 10 cans */
- wait_for_clear();
- if (Secbuf) free(Secbuf);
- if (Outfile) fclose(Outfile);
- return 0;
- end /* get_Zmodem */
- /*--------------------------------------------------------------------------*/
- /* RZ RECEIVE DATA */
- /* Receive array buf of max length with ending ZDLE sequence */
- /* and CRC. Returns the ending character or error code. */
- /*--------------------------------------------------------------------------*/
- static int pascal RZ_ReceiveData(buf, length)
- byte *buf;
- int length;
- begin
- register int c;
- register word crc;
- int d;
- crc = RxCount = 0;
- while(1)
- begin
- if ((c = Z_GetZDL()) & ~0xFF)
- begin
- CRCfoo:
- switch (c)
- begin
- case GOTCRCE:
- case GOTCRCG:
- case GOTCRCQ:
- case GOTCRCW: /*-----------------------------------*/
- /* C R C s */
- /*-----------------------------------*/
- crc = Z_UpdateCRC(((d=c)&0xFF), crc);
- if ((c=Z_GetZDL()) & ~0xFF) goto CRCfoo;
- crc = Z_UpdateCRC(c, crc);
- if ((c=Z_GetZDL()) & ~0xFF) goto CRCfoo;
- crc = Z_UpdateCRC(c, crc);
- if (crc & 0xFFFF)
- begin
- z_message( CRC_msg );
- return ERROR;
- end
- return d;
- case GOTCAN: /*-----------------------------------*/
- /* Cancel */
- /*-----------------------------------*/
- z_log(Cancelled_msg);
- return ZCAN;
- case TIMEOUT: /*-----------------------------------*/
- /* Timeout */
- /*-----------------------------------*/
- z_message( TIME_msg );
- return c;
- case RCDO: /*-----------------------------------*/
- /* No carrier */
- /*-----------------------------------*/
- z_log( CARRIER_msg );
- return c;
- default: /*-----------------------------------*/
- /* Something bizarre */
- /*-----------------------------------*/
- z_message("Debris");
- return c;
- end /* switch */
- end /* if */
- if (--length < 0)
- begin
- z_message("Long pkt");
- return ERROR;
- end
- ++RxCount;
- *buf++ = c;
- crc = Z_UpdateCRC(c, crc);
- continue;
- end /* while(1) */
- end /* RZ_ReceiveData */
- /*--------------------------------------------------------------------------*/
- /* RZ INIT RECEIVER */
- /* Initialize for Zmodem receive attempt, try to activate Zmodem sender */
- /* Handles ZSINIT, ZFREECNT, and ZCOMMAND frames */
- /* */
- /* Return codes: */
- /* ZFILE .... Zmodem filename received */
- /* ZCOMPL ... transaction finished */
- /* ERROR .... any other condition */
- /*--------------------------------------------------------------------------*/
- static int pascal RZ_InitReceiver()
- begin
- register int n;
- int errors = 0;
- for (n=10; --n>=0; )
- begin
- /*--------------------------------------------------------------*/
- /* Set buffer length (0=unlimited, don't wait). */
- /* Also set capability flags */
- /*--------------------------------------------------------------*/
- Z_PutLongIntoHeader(0L);
- Txhdr[ZF0] = CANFDX|CANOVIO;
- Z_SendHexHeader(Tryzhdrtype, Txhdr);
- AGAIN:
- switch (Z_GetHeader(Rxhdr))
- begin
- case ZFILE: /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- Zconv = Rxhdr[ZF0];
- Tryzhdrtype = ZRINIT;
- if (RZ_ReceiveData(Secbuf,WAZOOMAX)==GOTCRCW)
- return ZFILE;
- Z_SendHexHeader(ZNAK, Txhdr);
- goto AGAIN;
- case ZSINIT: /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- if (RZ_ReceiveData(Attn, ZATTNLEN) == GOTCRCW)
- Z_SendHexHeader(ZACK, Txhdr);
- else Z_SendHexHeader(ZNAK, Txhdr);
- goto AGAIN;
- case ZFREECNT: /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- Z_PutLongIntoHeader(DiskAvail);
- Z_SendHexHeader(ZACK, Txhdr);
- goto AGAIN;
- case ZCOMMAND: /*-----------------------------------------*/
- /* Paranoia is good for you... */
- /* Ignore command from remote, but lie and */
- /* say we did the command ok. */
- /*-----------------------------------------*/
- if (RZ_ReceiveData(Secbuf,WAZOOMAX)==GOTCRCW)
- begin
- status_line("!Ignoring `%s'", Secbuf);
- Z_PutLongIntoHeader(0L);
- do
- begin
- Z_SendHexHeader(ZCOMPL, Txhdr);
- end
- while (++errors<10 && Z_GetHeader(Rxhdr) != ZFIN);
- RZ_AckBibi();
- return ZCOMPL;
- end
- else Z_SendHexHeader(ZNAK, Txhdr);
- goto AGAIN;
- case ZCOMPL: /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- goto AGAIN;
- case ZFIN: /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- RZ_AckBibi();
- return ZCOMPL;
- case ZCAN:
- case RCDO: /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- return ERROR;
- end /* switch */
- end /* for */
- return ERROR;
- end /* RZ_InitReceiver */
- /*--------------------------------------------------------------------------*/
- /* RZFILES */
- /* Receive a batch of files using ZMODEM protocol */
- /*--------------------------------------------------------------------------*/
- static int pascal RZ_ReceiveBatch(xferinfo)
- FILE *xferinfo;
- begin
- register int c;
- set_xy("");
- while(1)
- begin
- switch (c = RZ_ReceiveFile(xferinfo))
- begin
- case ZEOF:
- case ZSKIP:
- switch (RZ_InitReceiver())
- begin
- case ZCOMPL: return OK;
- default: return ERROR;
- case ZFILE: break;
- end /* switch */
- break;
- default:
- fclose(Outfile);
- Outfile = NULL;
- unlink(Filename);
- errno = 0;
- return c;
- end /* switch */
- end /* while */
- end /* RZ_ReceiveBatch */
- /*--------------------------------------------------------------------------*/
- /* RZ RECEIVE FILE */
- /* Receive one file; assumes file name frame is preloaded in Secbuf */
- /*--------------------------------------------------------------------------*/
- static int pascal RZ_ReceiveFile(xferinfo)
- FILE *xferinfo;
- begin
- register int c;
- int n;
- long rxbytes;
- EOFseen=FALSE;
- if (RZ_GetHeader() == ERROR) return (Tryzhdrtype = ZSKIP);
- n = 10;
- rxbytes = 0L;
- while(1)
- begin
- Z_PutLongIntoHeader(rxbytes);
- Z_SendHexHeader(ZRPOS, Txhdr);
- NxtHdr:
- switch (c = Z_GetHeader(Rxhdr))
- begin
- case ZDATA: /*-----------------------------------------*/
- /* Data Packet */
- /*-----------------------------------------*/
- if (Rxpos != rxbytes)
- begin
- if ( --n < 0) return ERROR;
- z_message(NULL);
- cprintf("Bad pos; %ld/%ld",rxbytes,Rxpos);
- Z_PutString(Attn);
- continue;
- end
- MoreData:
- switch (c = RZ_ReceiveData(Secbuf,WAZOOMAX))
- begin
- case ZCAN:
- case RCDO: /*-----------------------*/
- /* CAN or CARRIER */
- /*-----------------------*/
- z_log(Cancelled_msg);
- return ERROR;
- case ERROR: /*-----------------------*/
- /* CRC error */
- /*-----------------------*/
- if (--n<0)
- begin
- z_log( FUBAR_msg );
- return ERROR;
- end
- show_loc(rxbytes,n);
- Z_PutString(Attn);
- continue;
- case TIMEOUT: /*---------------------*/
- /* */
- /*-----------------------*/
- if (--n<0)
- begin
- z_log( TIME_msg );
- return ERROR;
- end
- show_loc(rxbytes,n);
- continue;
- case GOTCRCW: /*---------------------*/
- /* End of frame */
- /*-----------------------*/
- n = 10;
- if (RZ_SaveToDisk(&rxbytes)==ERROR)
- return ERROR;
- Z_PutLongIntoHeader(rxbytes);
- Z_SendHexHeader(ZACK, Txhdr);
- goto NxtHdr;
- case GOTCRCQ: /*---------------------*/
- /* Zack expected */
- /*-----------------------*/
- n = 10;
- if (RZ_SaveToDisk(&rxbytes)==ERROR)
- return ERROR;
- Z_PutLongIntoHeader(rxbytes);
- Z_SendHexHeader(ZACK, Txhdr);
- goto MoreData;
- case GOTCRCG: /*---------------------*/
- /* Non-stop */
- /*-----------------------*/
- n = 10;
- if (RZ_SaveToDisk(&rxbytes)==ERROR)
- return ERROR;
- goto MoreData;
- case GOTCRCE: /*---------------------*/
- /* Header to follow */
- /*-----------------------*/
- n = 10;
- if (RZ_SaveToDisk(&rxbytes)==ERROR)
- return ERROR;
- goto NxtHdr;
- end /* switch */
- case ZNAK:
- case TIMEOUT: /*-----------------------------------------*/
- /* Packed was probably garbled */
- /*-----------------------------------------*/
- if ( --n < 0)
- begin
- z_log( "Garbled packet" );
- return ERROR;
- end
- show_loc(rxbytes,n);
- continue;
- case ZFILE: /*-----------------------------------------*/
- /* Sender didn't see our ZRPOS yet */
- /*-----------------------------------------*/
- RZ_ReceiveData(Secbuf, WAZOOMAX);
- continue;
- case ZEOF: /*-----------------------------------------*/
- /* End of the file */
- /*-----------------------------------------*/
- if (Rxpos != rxbytes)
- begin
- status_line("-Bad EOF; %ld/%ld", rxbytes, Rxpos);
- continue;
- end
- throughput(2,rxbytes);
- errno = 0;
- fclose(Outfile);
- had_error(CLOSE_msg,Filename);
- status_line("=UL %s",Filename);
- Outfile = NULL;
- if (xferinfo != NULL)
- begin
- fprintf(xferinfo, "%sn", Filename);
- had_error(WRITE_msg,"XferInfo");
- end
- return c;
- case ERROR: /*-----------------------------------------*/
- /* Too much garbage in header search error */
- /*-----------------------------------------*/
- if ( --n < 0) return ERROR;
- show_loc(rxbytes,n);
- Z_PutString(Attn);
- continue;
- default: /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- z_log( IDUNNO_msg );
- return ERROR;
- end /* switch */
- end /* while */
- end /* RZ_ReceiveFile */
- /*--------------------------------------------------------------------------*/
- /* RZ GET HEADER */
- /* Process incoming file information header */
- /*--------------------------------------------------------------------------*/
- static int pascal RZ_GetHeader()
- begin
- static char suffix[] = ".001";
- register byte *p;
- register int n;
- byte *ourname;
- byte *theirname;
- unsigned long filesize;
- /*--------------------------------------------------------------------*/
- /* Setup the transfer mode */
- /*--------------------------------------------------------------------*/
- isBinary = (!RXBINARY && Zconv == ZCNL)? 0 : 1;
- /*--------------------------------------------------------------------*/
- /* Extract and verify filesize, if given. */
- /* Reject file if not at least 10K free */
- /*--------------------------------------------------------------------*/
- filesize = 0L;
- p = Secbuf + 1 + strlen(Secbuf);
- if (*p) sscanf(p, "%ld", &filesize);
- if (filesize+10240 > DiskAvail)
- begin
- status_line("!Disk space");
- return ERROR;
- end
- /*--------------------------------------------------------------------*/
- /* Get and/or fix filename for uploaded file */
- /*--------------------------------------------------------------------*/
- p = Filename+strlen(Filename)-1; /* Find end of Opus upload path */
- while (p>=Filename && *p!='\') p--;
- ourname = ++p;
- p = Secbuf+strlen(Secbuf)-1; /* Find transmitted simple filename */
- while (p >= Secbuf && *p!='\' && *p!='/' && *p!=':') p--;
- theirname = ++p;
- strcpy(ourname,theirname); /* Start w/ our path & their name */
- if (dexists(Filename))
- begin /* If file already exists... */
- p = ourname;
- while (*p && *p!='.') p++; /* ...find the extension, if any */
- for (n=0; n<4; n++) /* ...fill it out if neccessary */
- if (!*p)
- begin
- *p = suffix[n];
- *(++p) = ' ';
- end
- else p++;
- while (dexists(Filename)) /* ...If 'file.ext' exists suffix++ */
- begin
- p = ourname+strlen(ourname)-1;
- for (n=3; n--;)
- begin
- if (!isdigit(*p)) *p = '0';
- if (++(*p) <= '9') break;
- else *p-- = '0';
- end /* for */
- end /* while */
- end /* if exist */
- errno = 0;
- if (strcmp(ourname,theirname))
- status_line("+Dupe renamed: %s",ourname);
- errno = 0;
- Outfile = fopen( Filename, write_binary );
- if (had_error(OPEN_msg,Filename)) return ERROR;
- set_xy(NULL);
- cprintf("Z-Recv %s, %s%ldb, %d min.",
- Filename,
- (isBinary)? "": "ASCII ",
- filesize,
- (int)(filesize*10/cur_baud+27)/54);
- set_xy(NULL);
- throughput(0,0L);
- return OK;
- end /* RZ_GetHeader */
- /*--------------------------------------------------------------------------*/
- /* RZ SAVE TO DISK */
- /* Writes the received file data to the output file. */
- /* If in ASCII mode, stops writing at first ^Z, and converts all */
- /* solo CR's or LF's to CR/LF pairs. */
- /*--------------------------------------------------------------------------*/
- static int pascal RZ_SaveToDisk(rxbytes)
- unsigned long *rxbytes;
- begin
- static byte lastsent;
- register byte *p;
- register int count;
- count = RxCount;
- if (((KEYPRESS()) and (READKB()==27)))
- begin
- send_can();
- z_log( KBD_msg );
- return ERROR;
- end
- if (count!=z_size)
- begin
- gotoxy( locate_x+10, locate_y );
- cputs( ultoa(((unsigned long )(z_size=count)),e_input,10) );
- putch(' ');
- end
- errno = 0;
- if (isBinary)
- begin
- fwrite( Secbuf, count, 1, Outfile );
- if (errno) goto oops;
- end
- else
- begin
- if (EOFseen) return OK;
- for (p=Secbuf; --count>=0; ++p )
- begin
- if ( *p == CPMEOF)
- begin
- EOFseen = TRUE;
- return OK;
- end
- if ( *p=='n' ) {
- if (lastsent!='r' && putc('r', Outfile) == EOF)
- goto oops;
- } else {
- if (lastsent=='r' && putc('n', Outfile) == EOF)
- goto oops;
- }
- if (putc((lastsent=*p), Outfile) == EOF) goto oops;
- end
- end
- *rxbytes += RxCount;
- gotoxy( locate_x, locate_y );
- cputs( ultoa(((unsigned long )(*rxbytes)),e_input,10) );
- return OK;
- oops:
- had_error(WRITE_msg,Filename);
- return ERROR;
- end /* RZ_SaveToDisk */
- /*--------------------------------------------------------------------------*/
- /* RZ ACK BIBI */
- /* Ack a ZFIN packet, let byegones be byegones */
- /*--------------------------------------------------------------------------*/
- static void pascal RZ_AckBibi()
- begin
- register int n;
- Z_PutLongIntoHeader(0L);
- for (n=4; --n;)
- begin
- Z_SendHexHeader(ZFIN, Txhdr);
- switch (Z_GetByte(100))
- begin
- case 'O': Z_GetByte(1); /* Discard 2nd 'O' */
- case TIMEOUT:
- case RCDO: return;
- end /* switch */
- end /* for */
- end /* RZ_AckBibi */