ZSEND.C
资源名称:zmodem.zip [点击查看]
上传用户:haiyue
上传日期:2007-01-05
资源大小:21k
文件大小:34k
源码类别:
通讯/手机编程
开发平台:
C/C++
- /*--------------------------------------------------------------------------*/
- /* FILE: zsend.c (Opus zmodem transmitter) */
- /* */
- /* */
- /* 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"
- /*--------------------------------------------------------------------------*/
- /* Global routines */
- /*--------------------------------------------------------------------------*/
- int cdecl send_Zmodem(byte *,byte *,int,int,int);
- /*--------------------------------------------------------------------------*/
- /* Private routines */
- /*--------------------------------------------------------------------------*/
- static void pascal ZS_SendBinaryHeader(unsigned short ,byte *);
- static void pascal ZS_SendData(byte *,int,unsigned short);
- static void pascal ZS_SendByte(byte);
- static int pascal ZS_GetReceiverInfo(void);
- static int pascal ZS_SendFile(int,int);
- static int pascal ZS_SendFileData(int);
- static int pascal ZS_SyncWithReceiver(void);
- static void pascal ZS_EndSend(void);
- /*--------------------------------------------------------------------------*/
- /* Private data */
- /*--------------------------------------------------------------------------*/
- static FILE *Infile; /* Handle of file being sent */
- static byte *Txbuf; /* Pointer to transmit buffer */
- static long Strtpos; /* Starting byte position of download */
- static long Txpos; /* Transmitted file position */
- static int Rxbuflen; /* Receiver's max buffer length */
- /*--------------------------------------------------------------------------*/
- /* External data not otherwise declared */
- /*--------------------------------------------------------------------------*/
- extern char *FLAGGING_msg;
- extern char *NOTSENT_msg;
- extern char *TRUNC_msg;
- extern char *KBD_msg;
- /*--------------------------------------------------------------------------*/
- /* SEND ZMODEM (send a file) */
- /* returns TRUE (1) for good xfer, FALSE (0) for bad */
- /* sends one file per call; 'fsent' flags start and end of batch */
- /*--------------------------------------------------------------------------*/
- int cdecl send_Zmodem(fname,alias,doafter,fsent,wazoo)
- byte *fname;
- byte *alias;
- int doafter;
- int fsent;
- int wazoo;
- begin
- register byte *p;
- register byte *q;
- struct stat f;
- int i;
- int rc;
- _BRK_DISABLE();
- XON_ENABLE();
- errno =
- z_size = 0;
- Infile = NULL;
- Txbuf = NULL;
- if (fname) set_xy("");
- switch(fsent)
- begin
- case 0:
- case NOTHING_TO_DO: n_disable();
- if (!wazoo)
- begin
- Z_PutString("rzr");
- Z_PutLongIntoHeader(0L);
- Z_SendHexHeader(ZRQINIT, Txhdr);
- end
- Rxtimeout = 20;
- if (ZS_GetReceiverInfo() == ERROR) return FALSE;
- end
- Rxtimeout = (int )(614400L/(long )cur_baud);
- Rxtimeout /= 10;
- if (Rxtimeout < 10) Rxtimeout = 10;
- if (Rxtimeout > 58) Rxtimeout = 58;
- if (fname == NULL) goto Done;
- /*--------------------------------------------------------------------*/
- /* Prepare the file for transmission. Just ignore file open errors */
- /* because there may be other files that can be sent. */
- /*--------------------------------------------------------------------*/
- Filename = fname;
- CLEAR_IOERR();
- Infile = fopen(Filename,read_binary);
- if (had_error(OPEN_msg,Filename)) return OK;
- Txbuf = zalloc();
- /*--------------------------------------------------------------------*/
- /* Send the file */
- /*--------------------------------------------------------------------*/
- rc = TRUE;
- /*--------------------------------------------------------------------*/
- /* Display outbound filename, size, and ETA for sysop */
- /*--------------------------------------------------------------------*/
- fstat(fileno(Infile), &f);
- message(NULL);
- cprintf( "Z-Send %s, %ldb",Filename,f.st_size);
- i = (int)(f.st_size*10/cur_baud+27)/54;
- if (i) cprintf(", %d min.",i);
- set_xy(NULL);
- /*--------------------------------------------------------------------*/
- /* Get outgoing file name; no directory path, lower case */
- /*--------------------------------------------------------------------*/
- for (p=(alias!=NULL)?alias:Filename, q=Txbuf ; *p; )
- begin
- if ((*q++ = tolower(*p)) == '\') q = Txbuf;
- p++;
- end
- *q++ = ' ';
- p = q;
- /*--------------------------------------------------------------------*/
- /* Zero out remainder of file header packet */
- /*--------------------------------------------------------------------*/
- while (q < (Txbuf + KSIZE)) *q++ = ' ';
- /*--------------------------------------------------------------------*/
- /* Store filesize, time last modified, and file mode in header packet */
- /*--------------------------------------------------------------------*/
- sprintf(p, "%lu %lo %o", f.st_size, f.st_mtime, f.st_mode);
- /*--------------------------------------------------------------------*/
- /* Transmit the filename block and begin the download */
- /*--------------------------------------------------------------------*/
- throughput(0,0L);
- /*--------------------------------------------------------------------*/
- /* Check the results */
- /*--------------------------------------------------------------------*/
- switch( ZS_SendFile(1+strlen(p)+(p-Txbuf), wazoo) )
- begin
- case ERROR: /*--------------------------------------------------*/
- /* Something tragic happened */
- /*--------------------------------------------------*/
- if (wazoo)
- begin
- status_line( NOTSENT_msg );
- mdm_hangup();
- end
- goto Err_Out;
- case OK: /*--------------------------------------------------*/
- /* File was sent */
- /*--------------------------------------------------*/
- CLEAR_IOERR();
- fclose(Infile);
- had_error(CLOSE_msg,Filename);
- Infile = NULL;
- status_line( "=DL %s", Filename );
- /*--------------------------------------------------*/
- /* Special WaZOO file handling following a */
- /* successful transmission. */
- /*--------------------------------------------------*/
- switch(doafter)
- begin
- case DELETE_AFTER: /*-----------------------*/
- /* Delete File */
- /*-----------------------*/
- CLEAR_IOERR();
- unlink(Filename);
- had_error(UNLINK_msg,Filename);
- break;
- case TRUNC_AFTER: /*-----------------------*/
- /* Truncate File */
- /*-----------------------*/
- CLEAR_IOERR();
- i = open(Filename,O_TRUNC,S_IWRITE);
- had_error( TRUNC_msg, Filename );
- status_line(FLAGGING_msg,Filename);
- close(i);
- break;
- end /* switch */
- default: /*--------------------------------------------------*/
- /* Probably a ZSKIP */
- /*--------------------------------------------------*/
- goto Done;
- end /* switch */
- Err_Out:
- rc = FALSE;
- Done:
- if (Infile) fclose(Infile);
- if (Txbuf) free(Txbuf);
- if (fsent < 0) ZS_EndSend();
- return rc;
- end /* send_Zmodem */
- /*--------------------------------------------------------------------------*/
- /* ZS SEND BINARY HEADER */
- /* Send ZMODEM binary header hdr of type type */
- /*--------------------------------------------------------------------------*/
- static void pascal ZS_SendBinaryHeader(type, hdr)
- unsigned short type;
- byte *hdr;
- begin
- register byte *hptr;
- register unsigned short crc;
- int n;
- SENDBYTE(ZPAD);
- SENDBYTE(ZDLE);
- SENDBYTE(ZBIN);
- ZS_SendByte(type);
- crc = Z_UpdateCRC(type, 0);
- hptr = hdr;
- for (n=4; --n >= 0;)
- begin
- ZS_SendByte(*hptr);
- crc = Z_UpdateCRC(((unsigned short)(*hptr++)), crc);
- end
- crc = Z_UpdateCRC(0,crc);
- crc = Z_UpdateCRC(0,crc);
- ZS_SendByte(crc>>8);
- ZS_SendByte(crc);
- if (type != ZDATA) wait_for_clear();
- end /* ZS_SendBinaryHeader */
- /*--------------------------------------------------------------------------*/
- /* ZS SEND DATA */
- /* Send binary array buf with ending ZDLE sequence frameend */
- /*--------------------------------------------------------------------------*/
- static void pascal ZS_SendData(buf, length, frameend)
- byte *buf;
- int length;
- unsigned short frameend;
- begin
- register unsigned short crc;
- int t;
- crc = 0;
- for (;--length >= 0;)
- begin
- ZS_SendByte(*buf);
- crc = Z_UpdateCRC(((unsigned short)(*buf++)), crc);
- end
- SENDBYTE(ZDLE);
- SENDBYTE(frameend);
- crc = Z_UpdateCRC(frameend, crc);
- crc = Z_UpdateCRC(0,crc);
- crc = Z_UpdateCRC(0,crc);
- ZS_SendByte(crc>>8);
- ZS_SendByte(crc);
- if (frameend == ZCRCW)
- begin
- SENDBYTE(XON);
- wait_for_clear();
- end
- end /* ZS_SendData */
- /*--------------------------------------------------------------------------*/
- /* ZS SEND BYTE */
- /* Send character c with ZMODEM escape sequence encoding. */
- /* Escape XON, XOFF. Escape CR following @ (Telenet net escape) */
- /*--------------------------------------------------------------------------*/
- static void pascal ZS_SendByte(c)
- register byte c;
- begin
- static byte lastsent;
- switch (c)
- begin
- case 015:
- case 0215: /*--------------------------------------------------*/
- /* */
- /*--------------------------------------------------*/
- if ((lastsent & 0x7F) != '@') goto SendIt;
- case 020:
- case 021:
- case 023:
- case 0220:
- case 0221:
- case 0223:
- case ZDLE: /*--------------------------------------------------*/
- /* Quoted characters */
- /*--------------------------------------------------*/
- SENDBYTE(ZDLE);
- c ^= 0x40;
- default: /*--------------------------------------------------*/
- /* Normal character output */
- SendIt: /*--------------------------------------------------*/
- SENDBYTE(lastsent = c);
- end /* switch */
- end /* ZS_SendByte */
- /*--------------------------------------------------------------------------*/
- /* ZS GET RECEIVER INFO */
- /* Get the receiver's init parameters */
- /*--------------------------------------------------------------------------*/
- static int pascal ZS_GetReceiverInfo()
- begin
- int n;
- int rxflags;
- for (n=10; --n>=0; )
- begin
- switch ( Z_GetHeader(Rxhdr) )
- begin
- case ZCHALLENGE: /*--------------------------------------*/
- /* Echo receiver's challenge number */
- /*--------------------------------------*/
- Z_PutLongIntoHeader(Rxpos);
- Z_SendHexHeader(ZACK, Txhdr);
- continue;
- case ZCOMMAND: /*--------------------------------------*/
- /* They didn't see our ZRQINIT */
- /*--------------------------------------*/
- Z_PutLongIntoHeader(0L);
- Z_SendHexHeader(ZRQINIT, Txhdr);
- continue;
- case ZRINIT: /*--------------------------------------*/
- /* */
- /*--------------------------------------*/
- Rxbuflen = ((word )Rxhdr[ZP1]<<8)|Rxhdr[ZP0];
- return OK;
- case ZCAN:
- case RCDO:
- case TIMEOUT: /*--------------------------------------*/
- /* */
- /*--------------------------------------*/
- return ERROR;
- case ZRQINIT: /*--------------------------------------*/
- /* */
- /*--------------------------------------*/
- if (Rxhdr[ZF0] == ZCOMMAND) continue;
- default: /*--------------------------------------*/
- /* */
- /*--------------------------------------*/
- Z_SendHexHeader(ZNAK, Txhdr);
- continue;
- end /* switch */
- end /* for */
- return ERROR;
- end /* ZS_GetReceiverInfo */
- /*--------------------------------------------------------------------------*/
- /* ZS SEND FILE */
- /* Send ZFILE frame and begin sending ZDATA frame */
- /*--------------------------------------------------------------------------*/
- static int pascal ZS_SendFile(blen, wazoo)
- int blen;
- int wazoo;
- begin
- register int c;
- while(1)
- begin
- if (((KEYPRESS()) and (READKB()==27)))
- begin
- send_can();
- z_log( KBD_msg );
- return ERROR;
- end
- else if (!CARRIER) return ERROR;
- Txhdr[ZF0] = LZCONV; /* Default file conversion mode */
- Txhdr[ZF1] = LZMANAG; /* Default file management mode */
- Txhdr[ZF2] = LZTRANS; /* Default file transport mode */
- Txhdr[ZF3] = 0;
- ZS_SendBinaryHeader(ZFILE, Txhdr);
- ZS_SendData(Txbuf, blen, ZCRCW);
- Again:
- switch (c = Z_GetHeader(Rxhdr))
- begin
- case ZRINIT: /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- goto Again;
- case ZCAN:
- case ZCRC:
- case RCDO:
- case TIMEOUT:
- case ZFIN:
- case ZABORT:
- /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- return ERROR;
- case ZSKIP: /*-----------------------------------------*/
- /* Other system wants to skip this file */
- /*-----------------------------------------*/
- return c;
- case ZRPOS: /*-----------------------------------------*/
- /* Resend from this position... */
- /*-----------------------------------------*/
- fseek(Infile, Rxpos, SEEK_SET);
- Strtpos = Txpos = Rxpos;
- CLEAR_INBOUND();
- return ZS_SendFileData(wazoo);
- end /* switch */
- end /* while */
- end /* ZS_SendFile */
- /*--------------------------------------------------------------------------*/
- /* ZS SEND FILE DATA */
- /* Send the data in the file */
- /*--------------------------------------------------------------------------*/
- static int pascal ZS_SendFileData(wazoo)
- int wazoo;
- begin
- register int c, e;
- word newcnt, blklen, maxblklen, goodblks, goodneeded = 1;
- byte *p;
- maxblklen = (cur_baud<300) ? 128 : cur_baud/300*256;
- if (maxblklen>WAZOOMAX) maxblklen = WAZOOMAX;
- if (!wazoo && maxblklen>KSIZE) maxblklen = KSIZE;
- if (Rxbuflen && maxblklen>Rxbuflen) maxblklen = Rxbuflen;
- blklen = maxblklen;
- SomeMore:
- if (CHAR_AVAIL())
- begin
- WaitAck:
- switch (c = ZS_SyncWithReceiver())
- begin
- default: /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- z_log(Cancelled_msg);
- errno = 0;
- fclose(Infile);
- had_error(CLOSE_msg,Filename);
- return ERROR;
- case ZSKIP: /*-----------------------------------------*/
- /* Skip this file */
- /*-----------------------------------------*/
- return c;
- case ZACK: /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- break;
- case ZRPOS: /*-----------------------------------------*/
- /* Resume at this position */
- /*-----------------------------------------*/
- blklen = (blklen>>2 > 64) ? blklen>>2 : 64;
- goodblks = 0;
- goodneeded = (goodneeded<<1) | 1;
- break;
- case ZRINIT: /*-----------------------------------------*/
- /* Receive init */
- /*-----------------------------------------*/
- throughput(1,Txpos-Strtpos);
- return OK;
- end /* switch */
- while (CHAR_AVAIL())
- begin
- switch (MODEM_IN())
- begin
- case CAN:
- case RCDO:
- case ZPAD: goto WaitAck;
- end /* switch */
- end /* while */
- end /* while */
- newcnt = Rxbuflen;
- Z_PutLongIntoHeader(Txpos);
- ZS_SendBinaryHeader(ZDATA, Txhdr);
- do
- begin
- if (((KEYPRESS()) and (READKB()==27)))
- begin
- send_can();
- z_log( KBD_msg );
- goto oops;
- end
- if (!CARRIER) goto oops;
- if ((c=fread(Txbuf,1,blklen,Infile))!=z_size)
- begin
- gotoxy( locate_x+10, locate_y );
- cputs( ultoa(((unsigned long )(z_size=c)),e_input,10) );
- putch(' ');
- end
- if (c < blklen) e = ZCRCE;
- else if (Rxbuflen && (newcnt -= c) <= 0) e = ZCRCW;
- else e = ZCRCG;
- ZS_SendData(Txbuf, c, e);
- gotoxy( locate_x, locate_y );
- cputs( ultoa(((unsigned long )Txpos),e_input,10) );
- putch(' ');
- Txpos += c;
- if (blklen<maxblklen && ++goodblks>goodneeded)
- begin
- blklen = (blklen<<1 < maxblklen) ? blklen<<1 : maxblklen;
- goodblks = 0;
- end
- if (e == ZCRCW) goto WaitAck;
- while (CHAR_AVAIL())
- begin
- switch (MODEM_IN())
- begin
- case CAN:
- case RCDO:
- case ZPAD: /*--------------------------------------*/
- /* Interruption detected; */
- /* stop sending and process complaint */
- /*--------------------------------------*/
- z_message("Trouble?");
- CLEAR_OUTBOUND();
- ZS_SendData(Txbuf, 0, ZCRCE);
- goto WaitAck;
- end /* switch */
- end /* while */
- end /* do */
- while (e == ZCRCG);
- while(1)
- begin
- Z_PutLongIntoHeader(Txpos);
- ZS_SendBinaryHeader(ZEOF, Txhdr);
- switch (ZS_SyncWithReceiver())
- begin
- case ZACK: /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- continue;
- case ZRPOS: /*-----------------------------------------*/
- /* Resume at this position... */
- /*-----------------------------------------*/
- goto SomeMore;
- case ZRINIT: /*-----------------------------------------*/
- /* Receive init */
- /*-----------------------------------------*/
- throughput(1,Txpos-Strtpos);
- return OK;
- case ZSKIP: /*-----------------------------------------*/
- /* Request to skip the current file */
- /*-----------------------------------------*/
- z_log(Skip_msg);
- CLEAR_IOERR();
- fclose(Infile);
- had_error(CLOSE_msg,Filename);
- return c;
- default: /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- oops: z_log(Cancelled_msg);
- errno = 0;
- fclose(Infile);
- had_error(CLOSE_msg,Filename);
- return ERROR;
- end /* switch */
- end /* while */
- end /* ZS_SendFileData */
- /*--------------------------------------------------------------------------*/
- /* ZS SYNC WITH RECEIVER */
- /* Respond to receiver's complaint, get back in sync with receiver */
- /*--------------------------------------------------------------------------*/
- static int pascal ZS_SyncWithReceiver()
- begin
- register int c;
- int num_errs = 7;
- while(1)
- begin
- c = Z_GetHeader(Rxhdr);
- CLEAR_INBOUND();
- switch (c)
- begin
- case TIMEOUT: z_message( TIME_msg );
- if ((num_errs--) >= 0) break;
- case ZCAN:
- case ZABORT:
- case ZFIN:
- case RCDO:
- /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- z_log("Err");
- return ERROR;
- case ZRPOS: /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- rewind(Infile); /* In case file EOF seen */
- fseek(Infile, Rxpos, SEEK_SET);
- Txpos = Rxpos;
- z_message(NULL);
- cputs("Resending from ");
- cputs( ultoa(((unsigned long )(Txpos)),e_input,10) );
- return c;
- case ZSKIP: /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- z_log(Skip_msg);
- case ZRINIT: /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- CLEAR_IOERR();
- fclose(Infile);
- had_error(CLOSE_msg,Filename);
- return c;
- case ZACK: /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- z_message( NULL );
- return c;
- default: /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- z_message( IDUNNO_msg );
- ZS_SendBinaryHeader(ZNAK, Txhdr);
- continue;
- end /* switch */
- end /* while */
- end /* ZS_SyncWithReceiver */
- /*--------------------------------------------------------------------------*/
- /* ZS END SEND */
- /* Say BIBI to the receiver, try to do it cleanly */
- /*--------------------------------------------------------------------------*/
- static void pascal ZS_EndSend()
- begin
- while(1)
- begin
- Z_PutLongIntoHeader(0L);
- ZS_SendBinaryHeader(ZFIN, Txhdr);
- switch (Z_GetHeader(Rxhdr))
- begin
- case ZFIN: /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- SENDBYTE('O');
- SENDBYTE('O');
- wait_for_clear();
- /* fallthrough... */
- case ZCAN:
- case RCDO:
- case TIMEOUT: /*-----------------------------------------*/
- /* */
- /*-----------------------------------------*/
- return;
- end /* switch */
- end /* while */
- end /* ZS_EndSend */
- /* END OF FILE: z_send.c */