zmodem.c 58.6 KB
Newer Older
1 2 3 4 5 6 7 8
/* zmodem.c */

/* Synchronet ZMODEM Functions */

/******************************************************************************/
/* Project : Unite!       File : zmodem general        Version : 1.02         */
/*                                                                            */
/* (C) Mattheij Computer Service 1994                                         */
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/*
 *	Date: Thu, 19 Nov 2015 10:10:02 +0100
 *	From: Jacques Mattheij
 *	Subject: Re: zmodem license
 *	To: Stephen Hurd, Fernando Toledo
 *	CC: Rob Swindell
 *
 *	Hello there to all of you,
 *
 *	So, this email will then signify as the transfer of any and all rights I
 *	held up to this point with relation to the copyright of the zmodem
 *	package as released by me many years ago and all associated files to
 *	Stephen Hurd. Fernando Toledo and Rob Swindell are named as
 *	witnesses to this transfer.
 *
 *	...
 *
 *	best regards,
 *
 *	Jacques Mattheij
 ******************************************************************************/
30 31 32 33 34 35

/*
 * zmodem primitives and other code common to zmtx and zmrx
 */

#include <stdio.h>
deuce's avatar
deuce committed
36
#include <string.h>
deuce's avatar
deuce committed
37
#include <stdarg.h>	/* va_list */
38 39 40
#include <sys/stat.h>	/* struct stat */

#include "genwrap.h"
41 42
#include "dirwrap.h"	/* getfname() */
#include "filewrap.h"	/* filelength() */
43 44 45 46 47

#include "zmodem.h"
#include "crc16.h"
#include "crc32.h"

48
#include "sexyz.h"
49
#include "telnet.h"
50

51 52 53 54 55 56 57 58
#define ENDOFFRAME	2
#define FRAMEOK		1
#define TIMEOUT			-1	/* rx routine did not receive a character within timeout */
#define INVHDR			-2	/* invalid header received; but within timeout */
#define ABORTED			-3	/* Aborted *or* disconnected */
#define SUBPKTOVERFLOW  -4	/* Subpacket received more than block length */
#define CRCFAILED		-5	/* Failed CRC comparison */
#define INVALIDSUBPKT	-6	/* Invalid Subpacket Type */
59 60
#define ZDLEESC 0x8000	/* one of ZCRCE; ZCRCG; ZCRCQ or ZCRCW was received; ZDLE escaped */

61 62
#define BADSUBPKT	0x80

63 64
#define SEND_SUCCESS	0

65 66
#define HDRLEN     5	/* size of a zmodem header */

67 68
#define STRIPPED_PARITY(c)	((c) & 0x7f)

rswindell's avatar
rswindell committed
69 70 71 72 73 74 75
static int lprintf(zmodem_t* zm, int level, const char *fmt, ...)
{
	va_list argptr;
	char	sbuf[1024];

	if(zm->lputs==NULL)
		return(-1);
76 77 78
	if(zm->log_level != NULL)
		if(level > *zm->log_level)
			return 0;
rswindell's avatar
rswindell committed
79 80 81 82 83 84 85 86

    va_start(argptr,fmt);
    vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
	sbuf[sizeof(sbuf)-1]=0;
    va_end(argptr);
    return(zm->lputs(zm->cbdata,level,sbuf));
}

87 88 89 90 91 92 93
static BOOL is_connected(zmodem_t* zm)
{
	if(zm->is_connected!=NULL)
		return(zm->is_connected(zm->cbdata));
	return(TRUE);
}

94 95 96 97 98 99
static BOOL is_cancelled(zmodem_t* zm)
{
	if(zm->is_cancelled!=NULL)
		return(zm->cancelled=zm->is_cancelled(zm->cbdata));
	return(zm->cancelled);
}
rswindell's avatar
rswindell committed
100

101
static BOOL is_data_waiting(zmodem_t* zm, unsigned timeout)
102 103
{
	if(zm->data_waiting)
104
		return(zm->data_waiting(zm->cbdata, timeout));
105 106 107
	return(FALSE);
}

108
static char *chr(int ch)
109 110 111 112
{
	static char str[25];

	switch(ch) {
113 114 115
		case TIMEOUT:			return("TIMEOUT");
		case ABORTED:			return("ABORTED");
		case SUBPKTOVERFLOW:	return "Subpacket Overflow";
116
		case CRCFAILED:			return "CRC ERROR";
117 118 119 120 121 122 123 124 125 126 127 128 129 130
		case INVALIDSUBPKT:		return "Invalid Subpacket";
		case ZRQINIT:			return("ZRQINIT");
		case ZRINIT:			return("ZRINIT");
		case ZSINIT:			return("ZSINIT");
		case ZACK:				return("ZACK");
		case ZFILE:				return("ZFILE");
		case ZSKIP:				return("ZSKIP");
		case ZCRC:				return("ZCRC");
		case ZNAK:				return("ZNAK");
		case ZABORT:			return("ZABORT");
		case ZFIN:				return("ZFIN");
		case ZRPOS:				return("ZRPOS");
		case ZDATA:				return("ZDATA");
		case ZEOF:				return("ZEOF");
rswindell's avatar
rswindell committed
131
		case ZFERR:				return("ZFERR");
132 133 134 135 136 137 138 139 140 141 142 143
		case ZPAD:				return("ZPAD");
		case ZCAN:				return("ZCAN");
		case ZDLE:				return("ZDLE");
		case ZDLEE:				return("ZDLEE");
		case ZBIN:				return("ZBIN");
		case ZHEX:				return("ZHEX");
		case ZBIN32:			return("ZBIN32");
		case ZRESC:				return("ZRESC");
		case ZCRCE:				return("ZCRCE");
		case ZCRCG:				return("ZCRCG");
		case ZCRCQ:				return("ZCRCQ");
		case ZCRCW:				return("ZCRCW");
144 145
		case XON:				return "XON";
		case XOFF:				return "XOFF";
146
	}
147 148 149
	if(ch<0)
		sprintf(str,"%d",ch);
	else if(ch>=' ' && ch<='~')
150
		sprintf(str,"'%c' (%02Xh)",(uchar)ch,(uchar)ch);
151
	else
152
		sprintf(str,"%u (%02Xh)",(uchar)ch,(uchar)ch);
rswindell's avatar
rswindell committed
153
	return(str);
154 155
}

156 157 158 159 160
static char* frame_desc(int frame)
{
	static char str[25];

	if(frame==TIMEOUT)
161
		return "TIMEOUT";
162 163

	if(frame==INVHDR)
164
		return "Invalid Header";
165

166 167 168 169
	if(frame==ABORTED)
		return "Aborted";

	if(frame >= 0 && (frame&BADSUBPKT)) {
170
		strcpy(str,"BAD ");
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
		switch(frame&~BADSUBPKT) {
			case ZRQINIT:		strcat(str,"ZRQINIT");		break;
			case ZRINIT:		strcat(str,"ZRINIT");		break;
			case ZSINIT:		strcat(str,"ZSINIT");		break;
			case ZACK:			strcat(str,"ZACK");			break;
			case ZFILE:			strcat(str,"ZFILE");		break;
			case ZSKIP:			strcat(str,"ZSKIP");		break;
			case ZNAK:			strcat(str,"ZNAK");			break;
			case ZABORT:		strcat(str,"ZABORT");		break;
			case ZFIN:			strcat(str,"ZFIN");			break;
			case ZRPOS:			strcat(str,"ZRPOS");		break;
			case ZDATA:			strcat(str,"ZDATA");		break;
			case ZEOF:			strcat(str,"ZEOF");			break;
			case ZFERR:			strcat(str,"ZFERR");		break;
			case ZCRC:			strcat(str,"ZCRC");			break;
			case ZCHALLENGE:	strcat(str,"ZCHALLENGE");	break;
			case ZCOMPL:		strcat(str,"ZCOMPL");		break;
			case ZCAN:			strcat(str,"ZCAN");			break;
			case ZFREECNT:		strcat(str,"ZFREECNT");		break;
rswindell's avatar
rswindell committed
190 191 192
			case ZCOMMAND:		strcat(str,"ZCOMMAND");		break;
			case ZSTDERR:		strcat(str,"ZSTDERR");		break;
			default:
193 194 195 196
				sprintf(str,"Unknown (%08X)", frame);
				break;
		}
	} else
197
		return chr(frame);
rswindell's avatar
rswindell committed
198
	return(str);
199 200
}

201 202 203 204 205 206 207 208 209 210 211 212
ulong frame_pos(zmodem_t* zm, int type)
{
	switch(type) {
		case ZRPOS:
		case ZACK:
		case ZEOF:
		case ZDATA:
			return(zm->rxd_header_pos);
	}

	return 0;
}
213

214 215 216 217 218
/*
 * read bytes as long as rdchk indicates that
 * more data is available.
 */

219
void zmodem_recv_purge(zmodem_t* zm, unsigned timeout)
220
{
221 222 223 224 225
	int c;

	while((c = zm->recv_byte(zm->cbdata, timeout)) >= 0) {
		lprintf(zm, LOG_DEBUG, "Purging data in receive buffer: %s", chr(c));
	}
226 227
}

rswindell's avatar
rswindell committed
228
/*
229 230 231 232 233 234 235 236
 * Flush the output buffer
 */
void zmodem_flush(zmodem_t* zm)
{
	if(zm->flush!=NULL)
		zm->flush(zm);
}

rswindell's avatar
rswindell committed
237 238
/*
 * transmit a character.
239 240
 * this is the raw modem interface
 */
241
/* Returns 0 on success */
242
int zmodem_send_raw(zmodem_t* zm, unsigned char ch)
243
{
244 245
	int	result;

246
	if((result = zm->send_byte(zm->cbdata, ch, zm->send_timeout)) != SEND_SUCCESS)
247 248 249
		lprintf(zm, LOG_ERR, "%s ERROR: %d", __FUNCTION__, result);
	else
		zm->last_sent = ch;
250 251

	return result;
252 253 254 255 256 257
}

/*
 * transmit a character ZDLE escaped
 */

258
int zmodem_send_esc(zmodem_t* zm, unsigned char c)
259
{
260 261
	int	result;

262
	if((result = zmodem_send_raw(zm, ZDLE)) != SEND_SUCCESS) {
263 264 265
		lprintf(zm, LOG_ERR, "%s ERROR: %d", __FUNCTION__, result);
		return result;
	}
266 267 268
	/*
	 * exclusive or; not an or so ZDLE becomes ZDLEE
	 */
269
	return zmodem_send_raw(zm, (uchar)(c ^ 0x40));
270 271 272 273 274 275
}

/*
 * transmit a character; ZDLE escaping if appropriate
 */

276
int zmodem_tx(zmodem_t* zm, unsigned char c)
277
{
278 279
	int result;

280
	switch (c) {
281 282 283 284 285 286
		case DLE:
		case DLE|0x80:          /* even if high-bit set */
		case XON:
		case XON|0x80:
		case XOFF:
		case XOFF|0x80:
287
		case ZDLE:
288
			return zmodem_send_esc(zm, c);
289 290
		case CR:
		case CR|0x80:
291
			if(zm->escape_ctrl_chars && (zm->last_sent&0x7f) == '@')
292
				return zmodem_send_esc(zm, c);
293
			break;
294 295
		case TELNET_IAC:
			if(zm->escape_telnet_iac) {
296
				if((result=zmodem_send_raw(zm, ZDLE)) != SEND_SUCCESS)
297 298 299 300
					return(result);
				return zmodem_send_raw(zm, ZRUB1);
			}
			break;
301
		default:
302
			if(zm->escape_ctrl_chars && (c&0x60)==0)
303
				return zmodem_send_esc(zm, c);
304 305 306 307 308
			break;
	}
	/*
	 * anything that ends here is so normal we might as well transmit it.
	 */
309
	return zmodem_send_raw(zm, c);
310 311
}

312 313 314
/**********************************************/
/* Output single byte as two hex ASCII digits */
/**********************************************/
315
int zmodem_send_hex(zmodem_t* zm, uchar val)
316
{
317
	char* xdigit="0123456789abcdef";
318
	int	result;
319

320
//	lprintf(zm, LOG_DEBUG, __FUNCTION__ " %02X",val);
321

322
	if((result=zmodem_send_raw(zm, xdigit[val>>4])) != SEND_SUCCESS)
323
		return result;
324
	return zmodem_send_raw(zm, xdigit[val&0xf]);
325 326
}

327
int zmodem_send_padded_zdle(zmodem_t* zm)
328 329 330
{
	int result;

331
	if((result=zmodem_send_raw(zm, ZPAD)) != SEND_SUCCESS)
332
		return result;
333
	if((result=zmodem_send_raw(zm, ZPAD)) != SEND_SUCCESS)
334
		return result;
335
	return zmodem_send_raw(zm, ZDLE);
336 337
}

rswindell's avatar
rswindell committed
338
/*
339 340 341 342
 * transmit a hex header.
 * these routines use tx_raw because we're sure that all the
 * characters are not to be escaped.
 */
343
int zmodem_send_hex_header(zmodem_t* zm, unsigned char * p)
344 345
{
	int i;
346
	int result;
rswindell's avatar
rswindell committed
347
	uchar type=*p;
348 349
	unsigned short int crc;

350
//	lprintf(zm, LOG_DEBUG, __FUNCTION__ " %s", chr(type));
rswindell's avatar
rswindell committed
351

352
	if((result=zmodem_send_padded_zdle(zm)) != SEND_SUCCESS)
353
		return result;
354

355
	if((result=zmodem_send_raw(zm, ZHEX)) != SEND_SUCCESS)
356
		return result;
357 358 359 360 361 362 363 364 365 366 367

	/*
 	 * initialise the crc
	 */

	crc = 0;

	/*
 	 * transmit the header
	 */

368
	for(i=0;i<HDRLEN;i++) {
369
		if((result=zmodem_send_hex(zm, *p)) != SEND_SUCCESS)
370
			return result;
371
		crc = ucrc16(*p, crc);
372 373 374 375 376 377 378
		p++;
	}

	/*
 	 * update the crc as though it were zero
	 */

rswindell's avatar
rswindell committed
379
	/*
380 381 382
	 * transmit the crc
	 */

383
	if((result=zmodem_send_hex(zm, (uchar)(crc>>8))) != SEND_SUCCESS)
384
		return result;
385
	if((result=zmodem_send_hex(zm, (uchar)(crc&0xff))) != SEND_SUCCESS)
386
		return result;
387 388 389 390 391

	/*
	 * end of line sequence
	 */

392
	if((result=zmodem_send_raw(zm, '\r')) != SEND_SUCCESS)
393
		return result;
394
	if((result=zmodem_send_raw(zm, '\n')) != SEND_SUCCESS)	/* FDSZ sends 0x8a instead of 0x0a */
395
		return result;
396

rswindell's avatar
rswindell committed
397
	if(type!=ZACK && type!=ZFIN)
398
		result=zmodem_send_raw(zm, XON);
399

400 401
	zmodem_flush(zm);

402
	return(result);
403 404 405 406 407 408
}

/*
 * Send ZMODEM binary header hdr
 */

409
int zmodem_send_bin32_header(zmodem_t* zm, unsigned char * p)
410 411
{
	int i;
412
	int result;
deuce's avatar
deuce committed
413
	uint32_t crc;
414

415
//	lprintf(zm, LOG_DEBUG, __FUNCTION__ " %s", chr(*p));
416

417
	if((result=zmodem_send_padded_zdle(zm)) != SEND_SUCCESS)
418
		return result;
419

420
	if((result=zmodem_send_raw(zm, ZBIN32)) != SEND_SUCCESS)
421
		return result;
422 423 424

	crc = 0xffffffffL;

425
	for(i=0;i<HDRLEN;i++) {
426
		crc = ucrc32(*p,crc);
427
		if((result=zmodem_tx(zm, *p++)) != SEND_SUCCESS)
428
			return result;
429 430 431 432
	}

	crc = ~crc;

433
	if((result=	zmodem_tx(zm, (uchar)((crc      ) & 0xff))) != SEND_SUCCESS)
434
		return result;
435
	if((result=	zmodem_tx(zm, (uchar)((crc >>  8) & 0xff))) != SEND_SUCCESS)
436
		return result;
437
	if((result=	zmodem_tx(zm, (uchar)((crc >> 16) & 0xff))) != SEND_SUCCESS)
438 439
		return result;
	return		zmodem_tx(zm, (uchar)((crc >> 24) & 0xff));
440 441
}

442
int zmodem_send_bin16_header(zmodem_t* zm, unsigned char * p)
443 444
{
	int i;
445
	int result;
446 447
	unsigned int crc;

448
//	lprintf(zm, LOG_DEBUG, __FUNCTION__ " %s", chr(*p));
449

450
	if((result=zmodem_send_padded_zdle(zm)) != SEND_SUCCESS)
451
		return result;
452

453
	if((result=zmodem_send_raw(zm, ZBIN)) != SEND_SUCCESS)
454
		return result;
455 456 457

	crc = 0;

458
	for(i=0;i<HDRLEN;i++) {
459
		crc = ucrc16(*p,crc);
460
		if((result=zmodem_tx(zm, *p++)) != SEND_SUCCESS)
461
			return result;
462 463
	}

464
	if((result=	zmodem_tx(zm, (uchar)(crc >> 8))) != SEND_SUCCESS)
465 466
		return result;
	return		zmodem_tx(zm, (uchar)(crc&0xff));
467 468 469
}


rswindell's avatar
rswindell committed
470
/*
471 472 473 474 475 476
 * transmit a header using either hex 16 bit crc or binary 32 bit crc
 * depending on the receivers capabilities
 * we dont bother with variable length headers. I dont really see their
 * advantage and they would clutter the code unneccesarily
 */

477
int zmodem_send_bin_header(zmodem_t* zm, unsigned char * p)
478
{
479
	if(zm->can_fcs_32 && !zm->want_fcs_16)
480 481
		return zmodem_send_bin32_header(zm, p);
	return zmodem_send_bin16_header(zm, p);
482 483 484 485 486 487
}

/*
 * data subpacket transmission
 */

488
int zmodem_send_data32(zmodem_t* zm, uchar subpkt_type, unsigned char * p, size_t l)
489
{
490
	int	result;
deuce's avatar
deuce committed
491
	uint32_t crc;
492

493
//	lprintf(zm, LOG_DEBUG, __FUNCTION__ " %s (%u bytes)", chr(subpkt_type), l);
494 495 496

	crc = 0xffffffffl;

497
	while(l > 0) {
498
		crc = ucrc32(*p,crc);
499
		if((result=zmodem_tx(zm, *p++)) != SEND_SUCCESS)
500
			return result;
501 502 503
		l--;
	}

504
	crc = ucrc32(subpkt_type, crc);
505

506
	if((result=zmodem_send_raw(zm, ZDLE)) != SEND_SUCCESS)
507
		return result;
508
	if((result=zmodem_send_raw(zm, subpkt_type)) != SEND_SUCCESS)
509
		return result;
510 511 512

	crc = ~crc;

513
	if((result=	zmodem_tx(zm, (uchar) ((crc      ) & 0xff))) != SEND_SUCCESS)
514
		return result;
515
	if((result=	zmodem_tx(zm, (uchar) ((crc >> 8 ) & 0xff))) != SEND_SUCCESS)
516
		return result;
517
	if((result=	zmodem_tx(zm, (uchar) ((crc >> 16) & 0xff))) != SEND_SUCCESS)
518 519
		return result;
	return		zmodem_tx(zm, (uchar) ((crc >> 24) & 0xff));
520 521
}

522
int zmodem_send_data16(zmodem_t* zm, uchar subpkt_type,unsigned char * p, size_t l)
523
{
524
	int	result;
525 526
	unsigned short crc;

527
//	lprintf(zm, LOG_DEBUG, __FUNCTION__ " %s (%u bytes)", chr(subpkt_type), l);
528 529 530

	crc = 0;

531
	while(l > 0) {
532
		crc = ucrc16(*p,crc);
533
		if((result=zmodem_tx(zm, *p++)) != SEND_SUCCESS)
534
			return result;
535 536 537
		l--;
	}

538
	crc = ucrc16(subpkt_type,crc);
539

540
	if((result=zmodem_send_raw(zm, ZDLE)) != SEND_SUCCESS)
541
		return result;
542
	if((result=zmodem_send_raw(zm, subpkt_type)) != SEND_SUCCESS)
543
		return result;
rswindell's avatar
rswindell committed
544

545
	if((result=	zmodem_tx(zm, (uchar)(crc >> 8))) != SEND_SUCCESS)
546 547
		return result;
	return		zmodem_tx(zm, (uchar)(crc&0xff));
548 549
}

550 551 552 553 554
BOOL zmodem_end_of_frame(int subpkt_type)
{
	return subpkt_type == ZCRCW || subpkt_type == ZCRCE;
}

555 556 557 558
/*
 * send a data subpacket using crc 16 or crc 32 as desired by the receiver
 */

559
int zmodem_send_data_subpkt(zmodem_t* zm, uchar subpkt_type, unsigned char* data, size_t len)
560
{
561
	int result;
562

563
	if(zmodem_end_of_frame(subpkt_type))
rswindell's avatar
rswindell committed
564 565 566 567
		zm->frame_in_transit=FALSE;
	else	/* other subpacket (mid-frame) */
		zm->frame_in_transit=TRUE;

568
	if(!zm->want_fcs_16 && zm->can_fcs_32) {
569
		if((result=zmodem_send_data32(zm, subpkt_type, data, len)) != SEND_SUCCESS)
570
			return result;
571
	}
rswindell's avatar
rswindell committed
572
	else {
573
		if((result=zmodem_send_data16(zm, subpkt_type, data, len)) != SEND_SUCCESS)
574
			return result;
575 576
	}

577
	if(subpkt_type == ZCRCW)
578
		result=zmodem_send_raw(zm, XON);
579

580 581
	zmodem_flush(zm);

582
	return result;
583 584
}

585
int zmodem_send_data(zmodem_t* zm, uchar subpkt_type, unsigned char* data, size_t len)
rswindell's avatar
rswindell committed
586 587
{
	if(!zm->frame_in_transit)	{ /* Start of frame, include ZDATA header */
588 589
		lprintf(zm, LOG_DEBUG, "%lu %s Start of frame: %s"
			,(ulong)zm->current_file_pos, __FUNCTION__, chr(subpkt_type));
590
		zmodem_send_pos_header(zm, ZDATA, (uint32_t)zm->current_file_pos, /* Hex? */ FALSE);
rswindell's avatar
rswindell committed
591 592
	}

593
	return zmodem_send_data_subpkt(zm, subpkt_type, data, len);
rswindell's avatar
rswindell committed
594 595
}

rswindell's avatar
rswindell committed
596
int zmodem_send_pos_header(zmodem_t* zm, int type, int32_t pos, BOOL hex)
597
{
598
	uchar header[5];
599

600
	lprintf(zm, LOG_DEBUG, "%lu %s %s", (ulong)pos, __FUNCTION__, chr(type));
601
	header[0]   = type;
602
	header[ZP0] = (uchar) (pos        & 0xff);
rswindell's avatar
rswindell committed
603 604 605
	header[ZP1] = (uchar)((pos >>  8) & 0xff);
	header[ZP2] = (uchar)((pos >> 16) & 0xff);
	header[ZP3] = (uchar)((pos >> 24) & 0xff);
606

607
	if(hex)
608
		return zmodem_send_hex_header(zm, header);
609
	else
610
		return zmodem_send_bin_header(zm, header);
611 612
}

deuce's avatar
deuce committed
613
int zmodem_send_ack(zmodem_t* zm, int32_t pos)
614 615 616 617 618 619 620 621
{
	return zmodem_send_pos_header(zm, ZACK, pos, /* Hex? */ TRUE);
}

int zmodem_send_zfin(zmodem_t* zm)
{
	unsigned char zfin_header[] = { ZFIN, 0, 0, 0, 0 };

622
	lprintf(zm, LOG_NOTICE, "%lu Finishing Session (Sending ZFIN)", (ulong)zm->current_file_pos);
623
	return zmodem_send_hex_header(zm,zfin_header);
624 625
}

626
int zmodem_send_zabort(zmodem_t* zm)
627
{
628
	lprintf(zm, LOG_WARNING, "%lu Aborting Transfer (Sending ZABORT)", (ulong)zm->current_file_pos);
629 630 631
	return zmodem_send_pos_header(zm, ZABORT, 0, /* Hex? */ TRUE);
}

632
int zmodem_send_znak(zmodem_t* zm)
633
{
634
	lprintf(zm, LOG_INFO, "%lu Sending ZNAK", (ulong)zm->current_file_pos);
635
	return zmodem_send_pos_header(zm, ZNAK, 0, /* Hex? */ TRUE);
636 637
}

638
int zmodem_send_zskip(zmodem_t* zm)
639
{
640
	lprintf(zm, LOG_INFO, "%lu Sending ZSKIP", (ulong)zm->current_file_pos);
641
	return zmodem_send_pos_header(zm, ZSKIP, 0L, /* Hex? */ TRUE);
642 643
}

644
int zmodem_send_zeof(zmodem_t* zm)
645
{
646
	lprintf(zm, LOG_INFO, "%lu Sending End-of-File (ZEOF) frame", (ulong)zm->current_file_pos);
647
	return zmodem_send_pos_header(zm, ZEOF, (int32_t)zm->current_file_pos, /* Hex? */ TRUE);
648 649 650
}


651 652 653 654 655 656
/*
 * rx_raw ; receive a single byte from the line.
 * reads as many are available and then processes them one at a time
 * check the data stream for 5 consecutive CAN characters;
 * and if you see them abort. this saves a lot of clutter in
 * the rest of the code; even though it is a very strange place
657
 * for an exit. (but that was what session abort was all about.)
658 659
 */

660
int zmodem_recv_raw(zmodem_t* zm)
661 662
{
	int c;
663
	unsigned attempt;
664

665
	for(attempt=0; attempt < zm->recv_timeout; attempt++) {
666 667 668 669
		if((c=zm->recv_byte(zm->cbdata,1 /* second timeout */)) >= 0)
			break;
		if(is_cancelled(zm))
			return(ZCAN);
670
		if(!is_connected(zm))
671
			return(ABORTED);
672 673
		lprintf(zm, LOG_DEBUG, "%s Received NO INPUT (attempt %u of %u)"
			,__FUNCTION__, attempt + 1, zm->recv_timeout);
674 675
	}
	if(attempt >= zm->recv_timeout) {
676 677
		lprintf(zm, LOG_WARNING, "%lu %s TIMEOUT (%u seconds)"
			,(ulong)zm->current_file_pos, __FUNCTION__, attempt);
678
		return TIMEOUT;
679
	}
680

681
	if(c == CAN) {
682
		zm->n_cans++;
683
		if(zm->n_cans == 5) {
rswindell's avatar
rswindell committed
684
			zm->cancelled=TRUE;
685
			lprintf(zm, LOG_WARNING, "%lu Canceled remotely", (ulong)zm->current_file_pos);
686
/*			return(TIMEOUT);	removed June-12-2005 */
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
		}
	}
	else {
		zm->n_cans = 0;
	}

	return c;
}

/*
 * rx; receive a single byte undoing any escaping at the
 * sending site. this bit looks like a mess. sorry for that
 * but there seems to be no other way without incurring a lot
 * of overhead. at least like this the path for a normal character
 * is relatively short.
 */

704
int zmodem_rx(zmodem_t* zm)
705 706 707 708 709 710 711 712 713
{
	int c;

	/*
	 * outer loop for ever so for sure something valid
	 * will come in; a timeout will occur or a session abort
	 * will be received.
	 */

714
	while(is_connected(zm) && !is_cancelled(zm)) {
715

716
		do {
717
			switch(c = zmodem_recv_raw(zm)) {
718 719
				case ZDLE:
					break;
720 721 722 723
				case XON:
				case XON|0x80:
				case XOFF:
				case XOFF|0x80:
724 725
					lprintf(zm,LOG_WARNING, "%lu Dropping flow ctrl char: %s"
						,(ulong)zm->current_file_pos, chr(c));
rswindell's avatar
rswindell committed
726
					continue;
727
				default:
728 729
					if(c < 0)
						return c;
730
					/*
rswindell's avatar
rswindell committed
731
	 				 * if all control characters should be escaped and
732
					 * this one wasn't then its spurious and should be dropped.
733
					 */
734
					if(zm->escape_ctrl_chars && (c >= 0) && (c & 0x60) == 0) {
735 736
						lprintf(zm,LOG_WARNING, "%lu Dropping unescaped ctrl char: %s"
							,(ulong)zm->current_file_pos, chr(c));
737 738 739 740 741 742 743
						continue;
					}
					/*
					 * normal character; return it.
					 */
					return c;
			}
744
			break;
745
		} while(!is_cancelled(zm));
rswindell's avatar
rswindell committed
746

747 748 749 750 751
		/*
	 	 * ZDLE encoded sequence or session abort.
		 * (or something illegal; then back to the top)
		 */

752
		while(!is_cancelled(zm)) {
753

754 755 756 757 758 759
			switch(c=zmodem_recv_raw(zm)) {
				case XON:
				case XON|0x80:
				case XOFF:
				case XOFF|0x80:
				case ZDLE:
760 761
					lprintf(zm,LOG_WARNING, "%lu Dropping escaped flow ctrl char: %s"
						,(ulong)zm->current_file_pos, chr(c));
rswindell's avatar
rswindell committed
762
					continue;
763 764
				/*
				 * these four are really nasty.
rswindell's avatar
rswindell committed
765
				 * for convenience we just change them into
766 767 768 769 770 771 772 773
				 * special characters by setting a bit outside the
				 * first 8. that way they can be recognized and still
				 * be processed as characters by the rest of the code.
				 */
				case ZCRCE:
				case ZCRCG:
				case ZCRCQ:
				case ZCRCW:
774
//					lprintf(zm,LOG_DEBUG, "%lu Encoding data subpacket type: %s", (ulong)zm->current_file_pos, chr(c));
775 776 777 778 779 780
					return (c | ZDLEESC);
				case ZRUB0:
					return 0x7f;
				case ZRUB1:
					return 0xff;
				default:
781 782 783
					if(c < 0)
						return c;

784
					if(zm->escape_ctrl_chars && (c & 0x60) == 0) {
785 786 787 788
						/*
						 * a not escaped control character; probably
						 * something from a network. just drop it.
						 */
789 790
						lprintf(zm,LOG_WARNING, "%lu Dropping unescaped ctrl char: %s"
							,(ulong)zm->current_file_pos, chr(c));
791 792 793 794
						continue;
					}
					/*
					 * legitimate escape sequence.
795
					 * rebuild the original and return it.
796
					 */
797
					if((c & 0x60) == 0x40) {
798 799
						return c ^ 0x40;
					}
800 801
					lprintf(zm,LOG_WARNING, "%lu Illegal sequence: ZDLE %s"
						,(ulong)zm->current_file_pos, chr(c));
802 803
					break;
			}
804
			break;
rswindell's avatar
rswindell committed
805
		}
806
	}
807 808

	/*
809
	 * not reached (unless canceled).
810 811
	 */

812
	return ABORTED;
813 814 815 816 817 818 819 820
}

/*
 * receive a data subpacket as dictated by the last received header.
 * return 2 with correct packet and end of frame
 * return 1 with correct packet frame continues
 * return 0 with incorrect frame.
 * return TIMEOUT with a timeout
821
 * if an acknowledgment is requested it is generated automatically
rswindell's avatar
rswindell committed
822
 * here.
823 824 825 826 827 828
 */

/*
 * data subpacket reception
 */

829
int zmodem_recv_data32(zmodem_t* zm, unsigned char * p, unsigned maxlen, unsigned* len, int* type)
830 831
{
	int c;
deuce's avatar
deuce committed
832 833
	uint32_t rxd_crc;
	uint32_t crc;
834
	int subpkt_type;
835

836
//	lprintf(zm,LOG_DEBUG, __FUNCTION___);
837

838
	*type = INVALIDSUBPKT;