|
|
1.1 root 1: /* xmodem.c */
2:
3: /* Synchronet X/YMODEM Functions */
4:
5: /* $Id: xmodem.c,v 1.3 2003/09/17 03:51:58 rswindell Exp $ */
6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
11: * Copyright 2003 Rob Swindell - http://www.synchro.net/copyright.html *
12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: #include "sexyz.h"
39: #include "genwrap.h" /* YIELD */
40: #include "conwrap.h" /* kbhit */
41:
42: #define getcom(t) recv_byte(xm->sock,t,xm->mode)
43: #define putcom(ch) send_byte(xm->sock,ch,10,xm->mode)
44: #define newline() fprintf(xm->statfp,"\n");
45:
46: void xmodem_put_nak(xmodem_t* xm)
47: {
48: while(getcom(1)!=NOINP)
49: ; /* wait for any trailing data */
50: putcom(NAK);
51: }
52:
53: void xmodem_cancel(xmodem_t* xm)
54: {
55: int i;
56:
57: for(i=0;i<8;i++)
58: putcom(CAN);
59: for(i=0;i<10;i++)
60: putcom('\b');
61: }
62:
63: /****************************************************************************/
64: /* Receive a X/Ymodem block (sector) from COM port */
65: /* hdrblock is 1 if attempting to get Ymodem header block, 0 if data block */
66: /* Returns blocknum if all went well, -1 on error or CAN, and -EOT if EOT */
67: /****************************************************************************/
68: int xmodem_get_block(xmodem_t* xm, uchar* block, uint block_size, BOOL hdrblock)
69: {
70: uchar block_num; /* Block number received in header */
71: uchar chksum,calc_chksum;
72: int i,errors,eot=0,can=0;
73: uint b;
74: ushort crc,calc_crc;
75:
76: for(errors=0;errors<MAXERRORS;errors++) {
77: i=getcom(10);
78: if(eot && i!=EOT)
79: eot=0;
80: if(can && i!=CAN)
81: can=0;
82: switch(i) {
83: case SOH: /* 128 byte blocks */
84: block_size=128;
85: break;
86: case STX: /* 1024 byte blocks */
87: block_size=1024;
88: break;
89: case EOT:
90: if((xm->mode&(YMODEM|GMODE))==YMODEM && !eot) {
91: eot=1;
92: xmodem_put_nak(xm); /* chuck's double EOT trick */
93: continue;
94: }
95: return(-EOT);
96: case CAN:
97: newline();
98: if(!can) { /* must get two CANs in a row */
99: can=1;
100: fprintf(xm->statfp,"Received CAN Expected SOH, STX, or EOT\n");
101: continue;
102: }
103: fprintf(xm->statfp,"Cancelled remotely\n");
104: bail(-1);
105: break;
106: case NOINP: /* Nothing came in */
107: continue;
108: default:
109: newline();
110: fprintf(xm->statfp,"Received %s Expected SOH, STX, or EOT\n",chr((uchar)i));
111: if(hdrblock) /* Trying to get Ymodem header block */
112: return(-1);
113: xmodem_put_nak(xm);
114: continue;
115: }
116: i=getcom(1);
117: if(i==NOINP) {
118: xmodem_put_nak(xm);
119: continue;
120: }
121: block_num=i;
122: i=getcom(1);
123: if(i==NOINP) {
124: xmodem_put_nak(xm);
125: continue;
126: }
127: if(block_num!=(uchar)~i) {
128: newline();
129: fprintf(xm->statfp,"Block number error\n");
130: xmodem_put_nak(xm);
131: continue;
132: }
133: calc_crc=calc_chksum=0;
134: for(b=0;b<block_size;b++) {
135: i=getcom(1);
136: if(i==NOINP)
137: break;
138: block[b]=i;
139: if(xm->mode&CRC)
140: calc_crc=ucrc16(block[b],calc_crc);
141: else
142: calc_chksum+=block[b];
143: }
144:
145: if(b<block_size) {
146: xmodem_put_nak(xm);
147: continue;
148: }
149:
150: if(xm->mode&CRC) {
151: crc=getcom(1)<<8;
152: crc|=getcom(1);
153: }
154: else
155: chksum=getcom(1);
156:
157: if(xm->mode&CRC) {
158: if(crc==calc_crc)
159: break;
160: newline();
161: fprintf(xm->statfp,"CRC error\n");
162: }
163: else /* CHKSUM */
164: {
165: if(chksum==calc_chksum)
166: break;
167: newline();
168: fprintf(xm->statfp,"Checksum error\n");
169: }
170:
171: if(xm->mode&GMODE) { /* Don't bother sending a NAK. He's not listening */
172: xmodem_cancel(xm);
173: bail(1);
174: }
175: xmodem_put_nak(xm);
176: }
177:
178: if(errors>=MAXERRORS) {
179: newline();
180: fprintf(xm->statfp,"Too many errors\n");
181: return(-1);
182: }
183: return(block_num);
184: }
185:
186: /*****************/
187: /* Sends a block */
188: /*****************/
189: void xmodem_put_block(xmodem_t* xm, uchar* block, uint block_size, ulong block_num)
190: {
191: uchar ch,chksum;
192: uint i;
193: ushort crc;
194:
195: if(block_size==128)
196: putcom(SOH);
197: else /* 1024 */
198: putcom(STX);
199: ch=(uchar)(block_num&0xff);
200: putcom(ch);
201: putcom((uchar)~ch);
202: chksum=0;
203: crc=0;
204: for(i=0;i<block_size;i++) {
205: putcom(block[i]);
206: if(xm->mode&CRC)
207: crc=ucrc16(block[i],crc);
208: else
209: chksum+=block[i];
210: }
211:
212: if(xm->mode&CRC) {
213: putcom((uchar)(crc >> 8));
214: putcom((uchar)(crc&0xff));
215: }
216: else
217: putcom(chksum);
218: YIELD();
219: }
220:
221: /************************************************************/
222: /* Gets an acknowledgement - usually after sending a block */
223: /* Returns 1 if ack received, 0 otherwise. */
224: /************************************************************/
225: int xmodem_get_ack(xmodem_t* xm, int tries)
226: {
227: int i,errors,can=0;
228:
229: for(errors=0;errors<tries;errors++) {
230:
231: if(xm->mode&GMODE) { /* Don't wait for ACK on Ymodem-G */
232: if(getcom(0)==CAN) {
233: newline();
234: fprintf(xm->statfp,"Cancelled remotely\n");
235: xmodem_cancel(xm);
236: bail(1);
237: }
238: return(1);
239: }
240:
241: i=getcom(10);
242: if(can && i!=CAN)
243: can=0;
244: if(i==ACK)
245: return(1);
246: if(i==CAN) {
247: if(can) {
248: newline();
249: fprintf(xm->statfp,"Cancelled remotely\n");
250: xmodem_cancel(xm);
251: bail(1);
252: }
253: can=1;
254: }
255: if(i!=NOINP) {
256: newline();
257: fprintf(xm->statfp,"Received %s Expected ACK\n",chr((uchar)i));
258: if(i!=CAN)
259: return(0);
260: }
261: }
262:
263: return(0);
264: }
265:
266: const char* xmodem_source(void)
267: {
268: return(__FILE__);
269: }
270:
271: char* xmodem_ver(char *buf)
272: {
273: sscanf("$Revision: 1.3 $", "%*s %s", buf);
274:
275: return(buf);
276: }
277:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.