-
Notifications
You must be signed in to change notification settings - Fork 6
/
zmodem.e
3198 lines (2622 loc) · 82.5 KB
/
zmodem.e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
OPT LARGE,MODULE
MODULE 'dos/dos','socket','*axenums','*bcd','exec'
/*
way to update errors, error/resume position
*/
/* crc16.c */
/* CCITT 16-bit CRC table and calculation function */
/* $Id: crc16.c,v 1.7 2014/02/10 04:44:31 deuce Exp $ */
CONST MAX_PATH=512
CONST NOINP=-1 /* input buffer empty (incom only) */
CONST TELNET_IAC=255
CONST RXSUBPACKETSIZE=8192
CONST TXSUBPACKETSIZE=8192
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2007 Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* Anonymous FTP access to the most recent released source is available at *
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
* *
* Anonymous CVS access to the development source and modification history *
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
* (just hit return, no password is necessary) *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* You are encouraged to submit any modifications (preferably in Unix diff *
* format) via e-mail to mods@synchro.net *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
PROC strcopy(dest: PTR TO CHAR,src: PTR TO CHAR,len=-1)
DEF i,c
i:=0
REPEAT
dest[i]:=(c:=src[i])
i++
UNTIL (i=len) OR (c=0)
ENDPROC
PROC fexist(file)
DEF lh
IF lh:=Lock(file,ACCESS_READ)
UnLock(lh)
RETURN TRUE
ENDIF
ENDPROC FALSE
PROC flength(file)
DEF fBlock: fileinfoblock
DEF fLock
DEF fsize=8192
IF((fLock:=Lock(file,ACCESS_READ)))=NIL
RETURN 8192
ENDIF
IF((fBlock:=AllocDosObject(DOS_FIB,NIL)))=NIL
UnLock(fLock)
RETURN 8192
ENDIF
IF(Examine(fLock,fBlock)) THEN fsize:=fBlock.size
UnLock(fLock)
FreeDosObject(DOS_FIB,fBlock)
ENDPROC fsize
->todo proper disk space check
PROC getFreeDiskSpace() IS 300000000
EXPORT PROC getZmSystemTime()
DEF currDate: datestamp
DateStamp(currDate)
ENDPROC Mul(Mul(currDate.days,1440),60)+(currDate.minute*60)+(currDate.tick/50),Mod(currDate.tick,50)
PROC getFileSize(zm,fp)
DEF p
p:=doSeek(zm,fp,0,OFFSET_END)
ENDPROC doSeek(zm,fp,p,OFFSET_BEGINING)
/* zmodem.c */
/* Synchronet ZMODEM Functions */
/* $Id: zmodem.c,v 1.122 2018/02/20 11:44:53 rswindell Exp $ */
/******************************************************************************/
/* Project : Unite! File : zmodem general Version : 1.02 */
/* */
/* (C) Mattheij Computer Service 1994 */
/*
* 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
******************************************************************************/
/*
* zmodem primitives and other code common to zmtx and zmrx
*/
/*
* zmodem.h
* zmodem constants
* (C) Mattheij Computer Service 1994
*
* 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
*/
/* $Id: zmodem.h,v 1.55 2018/02/01 08:20:19 deuce Exp $ */
CONST SOH=$01
CONST STX=$02
CONST EOT=$04
CONST ENQ=$05
CONST ACK=$06
CONST LF=$0a
CONST CR=$0d
CONST DLE=$10
CONST XON=$11
CONST XOFF=$13
CONST XONOR80=$91
CONST XOFFOR80=$93
CONST NAK=$15
CONST CAN=$18
/*
* zmodem constants
*/
CONST ZBLOCKLEN=1024 /* "true" Zmodem max subpacket length */
CONST ZMAXHLEN=$10 /* maximum header information length */
CONST ZMAXSPLEN=$400 /* maximum subpacket length */
CONST ZPAD=$2a /* pad character; begins frames */
CONST ZDLE=$18 /* ctrl-x zmodem escape */
CONST ZDLEE=$58 /* escaped ZDLE */
CONST ZBIN=$41 /* binary frame indicator (CRC16) */
CONST ZHEX=$42 /* hex frame indicator */
CONST ZBIN32=$43 /* binary frame indicator (CRC32) */
CONST ZBINR32=$44 /* run length encoded binary frame (CRC32) */
CONST ZVBIN=$61 /* binary frame indicator (CRC16) */
CONST ZVHEX=$62 /* hex frame indicator */
CONST ZVBIN32=$63 /* binary frame indicator (CRC32) */
CONST ZVBINR32=$64 /* run length encoded binary frame (CRC32) */
CONST ZRESC=$7e /* run length encoding flag / escape character */
/*
* zmodem frame types
*/
CONST ZRQINIT=$00 /* request receive init (s->r) */
CONST ZRINIT=$01 /* receive init (r->s) */
CONST ZSINIT=$02 /* send init sequence (optional) (s->r) */
CONST ZACK=$03 /* ack to ZRQINIT ZRINIT or ZSINIT (s<->r) */
CONST ZFILE=$04 /* file name (s->r) */
CONST ZSKIP=$05 /* skip this file (r->s) */
CONST ZNAK=$06 /* last packet was corrupted (?) */
CONST ZABORT=$07 /* abort batch transfers (?) */
CONST ZFIN=$08 /* finish session (s<->r) */
CONST ZRPOS=$09 /* resume data transmission here (r->s) */
CONST ZDATA=$0a /* data packet(s) follow (s->r) */
CONST ZEOF=$0b /* end of file reached (s->r) */
CONST ZFERR=$0c /* fatal read or write error detected (?) */
CONST ZCRC=$0d /* request for file CRC and response (?) */
CONST ZCHALLENGE=$0e /* security challenge (r->s) */
CONST ZCOMPL=$0f /* request is complete (?) */
CONST ZCAN=$10 /* pseudo frame;
other end cancelled session with 5* CAN */
CONST ZFREECNT=$11 /* request free bytes on file system (s->r) */
CONST ZCOMMAND=$12 /* issue command (s->r) */
CONST ZSTDERR=$13 /* output data to stderr (??) */
/*
* ZDLE sequences
*/
CONST ZCRCE=$68 /* CRC next, frame ends, header packet follows */
CONST ZCRCG=$69 /* CRC next, frame continues nonstop */
CONST ZCRCQ=$6a /* CRC next, frame continuous, ZACK expected */
CONST ZCRCW=$6b /* CRC next, frame ends, ZACK expected */
CONST ZRUB0=$6c /* translate to rubout $7f */
CONST ZRUB1=$6d /* translate to rubout $ff */
/*
* frame specific data.
* entries are prefixed with their location in the header array.
*/
/*
* Byte positions within header array
*/
CONST FTYPE=0 /* frame type */
CONST ZF0=4 /* First flags byte */
CONST ZF1=3
CONST ZF2=2
CONST ZF3=1
CONST ZP0=1 /* Low order 8 bits of position */
CONST ZP1=2
CONST ZP2=3
CONST ZP3=4 /* High order 8 bits of file position */
/*
* ZRINIT frame
* zmodem receiver capability flags
*/
CONST ZF0_CANFDX=$01 /* Receiver can send and receive true full duplex */
CONST ZF0_CANOVIO=$02 /* receiver can receive data during disk I/O */
CONST ZF0_CANBRK=$04 /* receiver can send a break signal */
CONST ZF0_CANCRY=$08 /* Receiver can decrypt DONT USE */
CONST ZF0_CANLZW=$10 /* Receiver can uncompress DONT USE */
CONST ZF0_CANFC32=$20 /* Receiver can use 32 bit Frame Check */
CONST ZF0_ESCCTL=$40 /* Receiver expects ctl chars to be escaped */
CONST ZF0_ESC8=$80 /* Receiver expects 8th bit to be escaped */
CONST ZF1_CANVHDR=$01 /* Variable headers OK */
/*
* ZSINIT frame
* zmodem sender capability
*/
CONST ZF0_TESCCTL=$40 /* Transmitter expects ctl chars to be escaped */
CONST ZF0_TESC8=$80 /* Transmitter expects 8th bit to be escaped */
CONST ZATTNLEN=$20 /* Max length of attention string */
CONST ALTCOFF=ZF1 /* Offset to alternate canit string, 0 if not used */
/*
* ZFILE frame
*/
/*
* Conversion options one of these in ZF0
*/
CONST ZF0_ZCBIN=1 /* Binary transfer - inhibit conversion */
CONST ZF0_ZCNL=2 /* Convert NL to local end of line convention */
CONST ZF0_ZCRESUM=3 /* Resume interrupted file transfer */
/*
* Management include options, one of these ored in ZF1
*/
CONST ZF1_ZMSKNOLOC=$80 /* Skip file if not present at rx */
CONST ZF1_ZMMASK=$1f /* Mask for the choices below */
CONST ZF1_ZMNEWL=1 /* Transfer if source newer or longer */
CONST ZF1_ZMCRC=2 /* Transfer if different file CRC or length */
CONST ZF1_ZMAPND=3 /* Append contents to existing file (if any) */
CONST ZF1_ZMCLOB=4 /* Replace existing file */
CONST ZF1_ZMNEW=5 /* Transfer if source newer */
CONST ZF1_ZMDIFF=6 /* Transfer if dates or lengths different */
CONST ZF1_ZMPROT=7 /* Protect destination file */
CONST ZF1_ZMCHNG=8 /* Change filename if destination exists */
/*
* Transport options, one of these in ZF2
*/
CONST ZF2_ZTNOR=0 /* no compression */
CONST ZF2_ZTLZW=1 /* Lempel-Ziv compression */
CONST ZF2_ZTRLE=3 /* Run Length encoding */
/*
* Extended options for ZF3, bit encoded
*/
CONST ZF3_ZCANVHDR=$01 /* Variable headers OK */
/* Receiver window size override */
CONST ZF3_ZRWOVR=$04 /* byte position for receive window override/256 */
CONST ZF3_ZXSPARS=$40 /* encoding for sparse file operations */
/*
* ZCOMMAND frame
*/
CONST ZF0_ZCACK1=$01 /* Acknowledge, then do command */
CONST ENDOFFRAME=2
CONST FRAMEOK=1
CONST TIMEOUT=-1 /* rx routine did not receive a character within timeout */
CONST INVHDR=-2 /* invalid header received; but within timeout */
CONST ABORTED=-3 /* Aborted *or* disconnected */
CONST SUBPKTOVERFLOW=-4 /* Subpacket received more than block length */
CONST CRCFAILED=-5 /* Failed CRC comparison */
CONST INVALIDSUBPKT=-6 /* Invalid Subpacket Type */
CONST ZDLEESC=$8000 /* one of ZCRCE; ZCRCG; ZCRCQ or ZCRCW was received; ZDLE escaped */
CONST BADSUBPKT=$80
CONST HDRLEN=5 /* size of a zmodem header */
EXPORT OBJECT zmodem_t
rxd_header[ZMAXHLEN]:ARRAY OF CHAR /* last received header */
rxd_header_len:INT /* last received header size */
rxd_header_pos:LONG /* last received header position value */
/*
* receiver capability flags
* extracted from the ZRINIT frame as received
*/
can_full_duplex:CHAR
can_overlap_io:CHAR
can_break:CHAR
can_fcs_32:CHAR
want_fcs_16:CHAR
escape_ctrl_chars:CHAR
escape_8th_bit:CHAR
iacEncode:CHAR
/*
* file management options.
* only one should be on
*/
management_newer:INT
management_clobber:INT
management_protect:INT
/* from zmtx.c */
tx_data_subpacket:PTR TO CHAR ->[TXSUBPACKETSIZE]:ARRAY OF CHAR
rx_data_subpacket:PTR TO CHAR ->[RXSUBPACKETSIZE]:ARRAY OF CHAR /* zzap = 8192 */
sendBuffer:PTR TO CHAR
sendBufferSize
sendBufferPtr:PTR TO CHAR
sendBufferEnd
crc16tbl:PTR TO INT
crc32tbl:PTR TO LONG
zm_lputs
zm_progress
zm_recv_byte
zm_is_connected
zm_is_cancelled
zm_upload_completed
zm_upload_failed
zm_download_completed
zm_dupecheck
zm_data_waiting
zm_flush
zm_duplicate_filename
zm_fopen
zm_fclose
zm_fread
zm_fwrite
zm_fseek
zm_firstfile
zm_nextfile
current_file_name[MAX_PATH]:ARRAY OF CHAR
current_file_size:LONG
current_file_pos:LONG
current_file_time:LONG
current_file_num:LONG
total_files:LONG
total_bytes[8]:ARRAY OF CHAR
files_remaining:LONG
bytes_remaining[8]:ARRAY OF CHAR
transfer_start_pos:LONG
transfer_start_time1:LONG
transfer_start_time2:INT
new_file:INT
receive_32bit_data:INT
use_crc16:INT
ack_file_pos:LONG /* file position used in acknowledgement of correctly */
/* received data subpackets */
last_sent:INT
n_cans:INT
/* Stuff added by RRS */
/* Status */
cancelled:CHAR
local_abort:CHAR
file_skipped:CHAR
send_successful:CHAR
no_streaming:CHAR
frame_in_transit:CHAR
recv_bufsize:LONG /* Receiver specified buffer size */
crc_request:LONG
errors:LONG
consecutive_errors:LONG
/* Configuration */
escape_telnet_iac:CHAR
init_timeout:LONG
send_timeout:LONG
recv_timeout:LONG
crc_timeout:LONG
max_errors:LONG
block_size:LONG
max_block_size:LONG
max_file_size:LONG /* 0 = unlimited */
user_data:LONG
/* Callbacks */
/* error C2520: conversion from unsigned __int64 to double not implemented, use signed __int64 */
cbdata: PTR TO CHAR
->int (*lputs)(void*, int level, const char* str)
->int (*send_byte)(void*, BYTE ch, unsigned timeout /* seconds */)
->int (*recv_byte)(void*, unsigned timeout /* seconds */)
->void (*progress)(void*, int64_t current_pos)
->BOOL (*is_connected)(void*)
->BOOL (*is_cancelled)(void*)
->BOOL (*data_waiting)(void*, unsigned timeout /* seconds */)
->BOOL (*duplicate_filename)(void*, void *zm)
->void (*flush)(void*)
ENDOBJECT
->PROC ucrc16(zm:PTR TO zmodem_t,ch,crc) IS Eor(zm.crc16tbl[Eor(Shr(crc,8) AND $ff,ch)],Shl(crc,8)) AND $ffff
#define ucrc16(ch,crc) Eor(zm.crc16tbl[Eor(Shr(crc,8) AND $ff,ch)],Shl(crc,8)) AND $ffff
->PROC ucrc32(zm:PTR TO zmodem_t,ch,crc) IS Eor(zm.crc32tbl[(Eor(crc,ch)) AND 255],Shr(crc,8) AND $ffffff)
#define ucrc32(ch,crc) Eor(zm.crc32tbl[(Eor(crc,ch)) AND 255],Shr(crc,8) AND $ffffff)
EXPORT PROC crc32str(str:PTR TO CHAR,len)
DEF crctbl:PTR TO LONG
DEF crc,i,ch
DEF tstr[255]:STRING
StrCopy(tstr,str,len)
crctbl:={crc32tbl}
crc:=-1
FOR i:=0 TO len-1
ch:=str[i]
crc:=Eor(crctbl[(Eor(crc,ch)) AND 255],Shr(crc,8) AND $ffffff)
ENDFOR
ENDPROC crc
PROC fcrc32(zm:PTR TO zmodem_t,fp, len)
DEF crc=$ffffffff
DEF rl
DEF i,n,n2: PTR TO CHAR
doSeek(zm,fp,0,OFFSET_BEGINNING)
n:=New(32768)
IF n=0 THEN RETURN $ffffffff
REPEAT
rl:=doRead(zm,fp,n,IF len>32768 THEN 32768 ELSE len)
n2:=n
FOR i:=1 TO rl
crc:=ucrc32(n2[]++,crc)
ENDFOR
len:=len-rl
UNTIL (rl=0) OR (len=0)
Dispose(n)
ENDPROC Not(crc)
PROC lprintf(zm:PTR TO zmodem_t, level, str:PTR TO CHAR)
DEF p
IF(zm.zm_lputs=NIL) THEN RETURN -1
p:=zm.zm_lputs
ENDPROC p(level,str)
PROC is_connected(zm: PTR TO zmodem_t)
DEF p
p:=zm.zm_is_connected
IF(p<>NIL) THEN RETURN p()
ENDPROC TRUE
PROC is_cancelled(zm: PTR TO zmodem_t)
DEF p
IF zm.cancelled THEN RETURN TRUE
p:=zm.zm_is_cancelled
IF(p<>NIL)
zm.cancelled:=zm.cancelled OR p()
RETURN zm.cancelled
ENDIF
ENDPROC FALSE
PROC download_completed(zm:PTR TO zmodem_t,fname,filesize,sentsize)
DEF p
p:=zm.zm_download_completed
IF p<>NIL
RETURN p(filesize,sentsize)
ENDIF
ENDPROC
PROC upload_completed(zm:PTR TO zmodem_t,fname:PTR TO CHAR,filebytes)
DEF p
p:=zm.zm_upload_completed
IF (p<>NIL) THEN p(fname,filebytes)
ENDPROC
PROC upload_failed(zm:PTR TO zmodem_t,fname:PTR TO CHAR)
DEF p
p:=zm.zm_upload_failed
IF (p<>NIL) THEN p(fname)
ENDPROC
PROC dupe_check(zm:PTR TO zmodem_t,fname)
DEF res=FALSE
DEF p
p:=zm.zm_dupecheck
IF (p<>NIL) THEN res:=p(fname)
ENDPROC res
PROC zmodem_data_waiting(zm: PTR TO zmodem_t,timeout)
DEF p
p:=zm.zm_data_waiting
IF(p<>NIL) THEN RETURN p(timeout)
ENDPROC FALSE
PROC chr(ch,output)
SELECT ch
CASE TIMEOUT
StrCopy(output,'TIMEOUT')
RETURN
CASE ABORTED
StrCopy(output,'ABORTED')
RETURN
CASE SUBPKTOVERFLOW
StrCopy(output,'Subpacket Overflow')
RETURN
CASE CRCFAILED
StrCopy(output,'CRC Failure')
RETURN
CASE INVALIDSUBPKT
StrCopy(output,'Invalid Subpacket')
RETURN
CASE ZRQINIT
StrCopy(output,'ZRQINIT')
RETURN
CASE ZRINIT
StrCopy(output,'ZRINIT')
RETURN
CASE ZSINIT
StrCopy(output,'ZSINIT')
RETURN
CASE ZACK
StrCopy(output,'ZACK')
RETURN
CASE ZFILE
StrCopy(output,'ZFILE')
RETURN
CASE ZSKIP
StrCopy(output,'ZSKIP')
RETURN
CASE ZCRC
StrCopy(output,'ZCRC')
RETURN
CASE ZNAK
StrCopy(output,'ZNAK')
RETURN
CASE ZABORT
StrCopy(output,'ZABORT')
RETURN
CASE ZFIN
StrCopy(output,'ZFIN')
RETURN
CASE ZRPOS
StrCopy(output,'ZRPOS')
RETURN
CASE ZDATA
StrCopy(output,'ZDATA')
RETURN
CASE ZEOF
StrCopy(output,'ZEOF')
RETURN
CASE ZFERR
StrCopy(output,'ZFERR')
RETURN
CASE ZPAD
StrCopy(output,'ZPAD')
RETURN
CASE ZCAN
StrCopy(output,'ZCAN')
RETURN
CASE ZDLE
StrCopy(output,'ZDLE')
RETURN
CASE ZDLEE
StrCopy(output,'ZDLEE')
RETURN
CASE ZBIN
StrCopy(output,'ZBIN')
RETURN
CASE ZHEX
StrCopy(output,'ZHEX')
RETURN
CASE ZBIN32
StrCopy(output,'ZBIN32')
RETURN
CASE ZRESC
StrCopy(output,'ZRESC')
RETURN
CASE ZCRCE
StrCopy(output,'ZCRCE')
RETURN
CASE ZCRCG
StrCopy(output,'ZCRCG')
RETURN
CASE ZCRCQ
StrCopy(output,'ZCRCQ')
RETURN
CASE ZCRCW
StrCopy(output,'ZCRCW')
RETURN
ENDSELECT
IF(ch<0)
StringF(output,'\d',ch)
ELSEIF((ch>=" ") AND (ch<="~"))
StringF(output,'''\c'' (\h[2])',ch,ch)
ELSE
StringF(output,'\d (\h[2])',ch,ch)
ENDIF
ENDPROC
PROC frame_desc(frame,output)
DEF str[25]:STRING
DEF tmp
IF(frame=TIMEOUT)
StrCopy(output,'TIMEOUT')
RETURN
ENDIF
IF(frame=INVHDR)
StrCopy(output,'Invalid Header')
RETURN
ENDIF
IF(frame=ABORTED)
StrCopy(output,'Aborted')
RETURN
ENDIF
IF(frame>=0)
IF (frame AND BADSUBPKT) THEN StrCopy(str,'BAD ')
tmp:=frame AND (Not(BADSUBPKT))
SELECT tmp
CASE ZRQINIT
StrAdd(str,'ZRQINIT')
CASE ZRINIT
StrAdd(str,'ZRINIT')
CASE ZSINIT
StrAdd(str,'ZSINIT')
CASE ZACK
StrAdd(str,'ZACK')
CASE ZFILE
StrAdd(str,'ZFILE')
CASE ZSKIP
StrAdd(str,'ZSKIP')
CASE ZNAK
StrAdd(str,'ZNAK')
CASE ZABORT
StrAdd(str,'ZABORT')
CASE ZFIN
StrAdd(str,'ZFIN')
CASE ZRPOS
StrAdd(str,'ZRPOS')
CASE ZDATA
StrAdd(str,'ZDATA')
CASE ZEOF
StrAdd(str,'ZEOF')
CASE ZFERR
StrAdd(str,'ZFERR')
CASE ZCRC
StrAdd(str,'ZCRC')
CASE ZCHALLENGE
StrAdd(str,'ZCHALLENGE')
CASE ZCOMPL
StrAdd(str,'ZCOMPL')
CASE ZCAN
StrAdd(str,'ZCAN')
CASE ZFREECNT
StrAdd(str,'ZFREECNT')
CASE ZCOMMAND
StrAdd(str,'ZCOMMAND')
CASE ZSTDERR
StrAdd(str,'ZSTDERR')
DEFAULT
StringF(str,'Unknown (\h[8])', frame)
ENDSELECT
ELSE
chr(frame,str)
ENDIF
StrCopy(output,str)
ENDPROC
/*PROC frame_pos(zm: PTR TO zmodem_t,type)
IF (type=ZRPOS) OR (type=ZACK) OR (type=ZEOF) OR (type=ZDATA) THEN RETURN zm.rxd_header_pos
ENDPROC 0*/
/*
* read bytes as long as rdchk indicates that
* more data is available.
*/
PROC zmodem_recv_purge(zm: PTR TO zmodem_t)
DEF p
p:=zm.zm_recv_byte
WHILE p(0)>=0
ENDWHILE
ENDPROC
/*
* Flush the output buffer
*/
EXPORT PROC zmodem_flush(zm: PTR TO zmodem_t)
DEF p
p:=zm.zm_flush
IF (zm.sendBufferPtr>zm.sendBuffer)
IF(p<>NIL) THEN p(zm.sendBuffer,zm.sendBufferPtr-zm.sendBuffer)
zm.sendBufferPtr:=zm.sendBuffer
ENDIF
ENDPROC
/*
* transmit a character.
* this is the raw modem interface
*/
EXPORT PROC zmodem_send_raw(zm: PTR TO zmodem_t,ch)
IF (zm.iacEncode AND (ch=255))
IF zm.sendBufferPtr>=(zm.sendBufferEnd-2) THEN zmodem_flush(zm)
zm.sendBufferPtr[]:=ch
zm.sendBufferPtr:=zm.sendBufferPtr+1
zm.sendBufferPtr[]:=ch
zm.sendBufferPtr:=zm.sendBufferPtr+1
IF zm.sendBufferPtr=zm.sendBufferEnd THEN zmodem_flush(zm)
ELSE
zm.sendBufferPtr[]:=ch
zm.sendBufferPtr:=zm.sendBufferPtr+1
IF zm.sendBufferPtr=zm.sendBufferEnd THEN zmodem_flush(zm)
ENDIF
zm.last_sent:=ch
ENDPROC
/*
* transmit a character ZDLE escaped
*/
PROC zmodem_send_esc(zm: PTR TO zmodem_t,c)
zmodem_send_raw(zm, ZDLE)
/*
* exclusive or; not an or so ZDLE becomes ZDLEE
*/
zmodem_send_raw(zm,Eor(c,64))
ENDPROC
/*
* transmit a character; ZDLE escaping if appropriate
*/
PROC zmodem_tx(zm:PTR TO zmodem_t,c)
IF (c=DLE) OR (c=(DLE+128)) OR (c=XON) OR (c=(XON+128)) OR (c=XOFF) OR (c=(XOFF+128)) OR (c=ZDLE)
RETURN zmodem_send_esc(zm, c)
ELSEIF (c=CR) OR (c=(CR+128))
IF(zm.escape_ctrl_chars AND ((zm.last_sent AND 127) ="@")) THEN RETURN zmodem_send_esc(zm, c)
ELSEIF (c=TELNET_IAC)
IF(zm.escape_telnet_iac)
zmodem_send_raw(zm, ZDLE)
RETURN zmodem_send_raw(zm, ZRUB1)
ENDIF
ELSE
IF((zm.escape_ctrl_chars<>0) AND ((c AND 96)=0)) THEN RETURN zmodem_send_esc(zm, c)
ENDIF
/*
* anything that ends here is so normal we might as well transmit it.
*/
ENDPROC zmodem_send_raw(zm,c)
/**********************************************/
/* Output single byte as two hex ASCII digits */
/**********************************************/
PROC zmodem_send_hex(zm:PTR TO zmodem_t,val)
DEF xdigit[16]:STRING
->DEF tempstr[255]:STRING
StrCopy(xdigit,'0123456789abcdef')
->StringF(tempstr,'send_hex: \d \h[2] ',val,val)
->lprintf(zm,LOG_DEBUG,tempstr)
zmodem_send_raw(zm, xdigit[Shr(val,4)])
ENDPROC zmodem_send_raw(zm, xdigit[val AND 15])
PROC zmodem_send_padded_zdle(zm: PTR TO zmodem_t)
zmodem_send_raw(zm, ZPAD)
zmodem_send_raw(zm, ZPAD)
ENDPROC zmodem_send_raw(zm, ZDLE)
/*
* transmit a hex header.
* these routines use tx_raw because we're sure that all the
* characters are not to be escaped.
*/
PROC zmodem_send_hex_header(zm:PTR TO zmodem_t, p: PTR TO CHAR)
DEF i
DEF type
DEF crc
->DEF tempstr[255]:STRING
->DEF tempstr2[255]:STRING
type:=p[]
->chr(type,tempstr)
->StringF(tempstr2,'send_hex_header: \s', tempstr)
->lprintf(zm,LOG_DEBUG,tempstr2)
zmodem_send_padded_zdle(zm)
zmodem_send_raw(zm, ZHEX)
/*
* initialise the crc
*/
crc:=0
/*
* transmit the header
*/
FOR i:=0 TO HDRLEN-1
zmodem_send_hex(zm, p[])
crc:=ucrc16(p[], crc)
p++
ENDFOR
/*
* update the crc as though it were zero
*/
/*
* transmit the crc
*/
zmodem_send_hex(zm,(Shr(crc,8)))
zmodem_send_hex(zm,(crc AND 255))
/*
* end of line sequence
*/
zmodem_send_raw(zm, "\b")
zmodem_send_raw(zm, "\n") /* FDSZ sends 0x8a instead of 0x0a */
IF((type<>ZACK) AND (type<>ZFIN)) THEN zmodem_send_raw(zm, XON)
zmodem_flush(zm)
ENDPROC
/*
* Send ZMODEM binary header hdr
*/
PROC zmodem_send_bin32_header(zm:PTR TO zmodem_t, p: PTR TO CHAR)
DEF i
DEF crc
->DEF tempstr[255]:STRING
->DEF tempstr2[255]:STRING
DEF pp
->chr(p[],tempstr)
->StringF(tempstr2,'"send_bin32_header: \s',tempstr)
->lprintf(zm,LOG_DEBUG,tempstr2)
zmodem_send_padded_zdle(zm)
zmodem_send_raw(zm, ZBIN32)
crc:=-1
FOR i:=0 TO HDRLEN-1
pp:=p[]
p++
crc:=ucrc32(pp,crc)
zmodem_tx(zm, pp)
ENDFOR
crc:= Not(crc)
zmodem_tx(zm,((crc) AND $ff))
zmodem_tx(zm,((Shr(crc,8)) AND $ff))
zmodem_tx(zm,((Shr(crc,16)) AND $ff))
ENDPROC zmodem_tx(zm,((Shr(crc,24)) AND $ff))
PROC zmodem_send_bin16_header(zm:PTR TO zmodem_t, p: PTR TO CHAR)
DEF i
DEF crc
->DEF tempstr[255]:STRING
->DEF tempstr2[255]:STRING
DEF tmp
->chr(p[],tempstr)
->StringF(tempstr2,'send_bin16_header: \s',tempstr)
->lprintf(zm,LOG_DEBUG,tempstr2)
zmodem_send_padded_zdle(zm)
zmodem_send_raw(zm, ZBIN)
crc:=0
FOR i:=0 TO HDRLEN-1
crc:=ucrc16(p[],crc)
tmp:=p[]
p++
zmodem_tx(zm,tmp)
ENDFOR
zmodem_tx(zm,(Shr(crc,8)))
ENDPROC zmodem_tx(zm, (crc AND $ff))
/*
* 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
*/
PROC zmodem_send_bin_header(zm: PTR TO zmodem_t, p: PTR TO CHAR)
IF((zm.can_fcs_32<>0) AND (zm.want_fcs_16=0)) THEN RETURN zmodem_send_bin32_header(zm, p)
ENDPROC zmodem_send_bin16_header(zm, p)
/*