forked from hperaza/Kermit-180
-
Notifications
You must be signed in to change notification settings - Fork 0
/
kpkt.mac
3130 lines (2826 loc) · 96.3 KB
/
kpkt.mac
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
; KPKT.MAC
; KERMIT - (Celtic for "FREE")
;
; This is the RSX180/280 implementation of the Columbia University
; KERMIT file transfer protocol. (C) 2021, Hector Peraza.
;
; Version 4.0
;
; Derived from Kermit-80, originally written by Bill Catchings of the
; Columbia University Center for Computing Activities, 612 W. 115th St.,
; New York, NY 10025. with contributions by Frank da Cruz, Daphne Tzoar,
; Bernie Eiben, Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen,
; Jeff Damens, and many others.
;
; Copyright June 1981,1982,1983,1984,1985 Columbia University
;
; This file contains the (system-independent) routines that implement
; the KERMIT protocol, and the commands that use them:
; RECEIVE, SEND, FINISH, and LOGOUT.
;
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Revision history (latest first):
;
; edit 33, 4-Dec-2021 by H. Peraza: suppress output of status and (most)
; error messages during Remote operation.
;
; edit 32, 28-Mar-2021 by H. Peraza: packet character encoding was moved
; into a separate ENCODE routine that can be called from the server
; code. SDATA and SEOF were also slightly modified to support server
; operation.
;
; edit 31, 21-Mar-2021 by H. Peraza: display received file name only after
; version number is known. Fixed SET COLLISION OVERWRITE.
;
; edit 30, 20-Mar-2021 by H. Peraza: reset Server Mode flag in INCHR if
; the user entered Control-C at the console. Added SEND1 and READ1
; entry points for Server mode get and send commands. Close directory
; after sending last file in SEOF.
;
; edit 29, 9-Jan-2021 by H. Peraza: converted to Z80, targeting RSX180/280.
; Optimized a bit the SDATA routine (keep pointers in registers, not in
; memory variables). The receive packet routine now times out after the
; given RTIME seconds. Purge modem input on timeout.
;
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Old Kermit-80 4.11 revision history:
;
; edit 28, 21-Mar-1991 by MF. After "inchr7", close TAKE-file (if any) so
; ^C will halt all processing (including commands from TAKE-files)
; and put the user back at Kermit command-level.
;
; edit 27, 16-Jan-1991 by MF. The bug of (22) was not fixed (although
; the error described needed to be corrected). Really fixed the bug this:
; time. changed "lda 'E'" after "ptch9b" to "mvi a,'E'" -- Zilog
; mnemonic thinking must've addled my brain!
;
; edit 26, 14-Jan-1991 by MF. Fix bug in the code which sends an "E" packet
; to the remote Kermit on encountering "disk full" so that
; uncontrollified <CR><LF> is not copied to the packet data area (and
; hence sent to the remote Kermit). This should fix a bug reported
; by Russell Lang of Monash University in Australia wherein a PC
; running Kermit in Server mode complained of invalid characters when
; receiving the "disk full" error packet from CP/M Kermit.
;
; edit 25 of 3-Jan-1991 by MF. Reverse part of edit 20 which flushes comm
; input at EOF send: the problem of multiple copies of packets being
; sent when a stream of files being sent is partially interrupted with
; ^X has been fixed by modifying "inchr" in CPSPK2.ASM.
; Modify routine "inchr" after label "inchr5" to not take retry
; (nonskip) return if ^X/^Z seen on the Console. This will prevent
; multiple copies of packets being sent if user aborts some files
; in a stream being sent via ^X and is a better fix to this problem
; than flushing comm input before sending the "Z" packet requesting
; the remote Kermit to discard the current file being received (as
; implemented in edit 24 of 2-jan-1991).
;
; edit 24, 2-Jan-1991 by MF. Tightened up code just after "sdata1" and around
; "sdat14". Added code to flush comm input after user has typed ^X
; or ^Z to interrupt file sends so that duplicate packets are not
; sent after the interrupt character (especially ^X) has been typed.
;
; edit 23, 14-Dec-1990 by MF. Place "<<>>" around "F" and "X" packets coming
; as replies to REMOTE commands a la VMS Bliss Kermit.
; Also type each character of "X" or "F" packet explicitly in case
; dollar-signs are part of the filename (as in VMS Bliss Kermit
; when a REMOTE TYPE is given and SET FILE NAMING FULL is in effect).
; Expanded code is at label rfil3f. Modified "gofil" routine to allow
; for specification of a drive in the local filespec for GET and
; RECEIVE commands. Thus commands such as
; GET HELLO.TXT B:GOODBYE.TXT
; and
; RECEIVE B:GOODBYE.TXT
; now work as expected.
;
; edit 22, 27-Nov-1990 by MF. Fix bug introduced with edit 17 which resulted
; in "E" packet being sent twice when receiving file(s) and disk-full
; occurred. Sorry about that, folks!
;
; edit 21, 27-Nov-1990 by MF. When receiving files, make the decision as to
; whether to delete a partially-received file on a "disk full"
; condition subject to the setting of the SET INCOMPLETE-FILES
; switch in conformity with the behavior of MSDOS Kermit.
; An "E" packet is still sent to the remote Kermit. Also try to close
; any incomplete file whether deleting it or not (labels rdat16 and
; rdat3a). If keeping incomplete files, try to write outstanding
; buffers to disk, giving an error if the disk is full.
;
; edit 20, 23-Nov-1990 by MF. When receiving, cause the file being written
; to disk to **always** be deleted and an "E" packet to be sent when a
; "disk full" condition is encountered (per suggestion of
; RJL@MONU1.CC.MONASH.EDU.AU).
;
; edit 19, 15-Nov-1990 by MF. Changed code for the Receive Complete state
; to always go into RECEIVE if AUTORECEIVE is on. This will happen
; most of the time anyway as most mainframe Kermits issue a prompt
; after a single SEND command (wild-carded or not), thus guaranteeing
; that the modem status check of Kermit-80 ver. 4.09 would **always**
; have characters ready for input (the mainframe Kermit's prompt),
; defeating the status check and the Console input check (originally
; intended to drop the user out of the loop if he/she typed a key with
; no comm input present). Eliminate "any key" message there also.
; the user can drop out by hitting ^C.
; Of course, none of the foregoing applies if the Receive Complete
; state occurs as the result of a "Get" command where Autoreceive
; is meaningless and we just drop back to Kermit command-level.
;
; edit 18, 22-Oct-1990 by MF. Fixed bug in completion-message routine
; "finmes" wherein the completion message was not printed if the
; terminal was set to QUIET because the message pointer was clobbered
; by prcrlf.
;
; edit 17, 1-Oct-1990 by MF. Added code to send an "I" packet before an
; "R" packet in GET command.
; Modified routine "sinit" to ignore "E" packets when sending an
; "i" packet (per KPROTO.DOC).
;
; edit 16, 14-Sep-1990 by MF. Added code to implement SET FILE COLLISION
; and SET INCOMPLETE commands. Add hooks for SET COLLISION command.
; Eliminate commented-out old file warning rename routine.
; Clear communication input buffers (call flsmdm) before
; BYE, FINISH and LOGOUT commands.
;
; edit 15, 9-Sep-1990 by MF. Added code to prevent packet counts
; from being displayed during Remote commands. Fixed AUTORECEIVE
; code, file colision Rename algorithm and eliminated multiple
; display of initial messages during GET/RECEIVE. Implemented fixes
; in CPKERM.BWR for garbage printout during quiet transfers and for
; file existence/rename algorithm. Also implemented hooks for Remote
; commands.
;
; edit 14, 18 June 1990 by Russell Lang [rjl@monu1.cc.monash.edu.au]
; When trying to generate a unique file name on receive, zero
; the attribute bits between file opening attempts. This is
; to fix a bug which caused the unique file name to have the
; attributes of the already existing file. If the attribute
; was R/O, a bdos error occured later when an attempt was made
; to write to the file.
;
; edit 13, 27 October, 1987 By OBSchou. Changed the rename routine to
; be more like the MSDOS issue.
;
; edit 12, 28 July, 1987 by OBSchou. Commented out capas etc support
; (Long packets etc) as this is not worth the effort coding... but
; I have left what WAS done for any enthusiast. Also set in a few
; to NOT write to screen if SET TERMINAL QUIET set. Hopefully speeds
; up transfers on systems taking forever to update screens.
; Added traps to NOT print to screen during file transfers if quietd
; is non zero (ie we SET TERMINAL QUIET). This hopefully speeds up
; transfers in systems spending an age updating the screen.
;
; edit 11, 8 April, 1987 by OBSchou. Tarted up all sorts of bits n bobs
; to cope with all the new aditions for Kermit-80 V 4.09
; Look for the [10] for most cahnges. spar and rpar largely replaced.
; Minor edit to put drive and user number in the "filename" field on
; the transfer screen. This means that the offset on the line for
; the file name proper has moved along 4 space. Also, it writes 15
; spaces AFER the xxd: string to clear the field of any prevous file.
; Needed for those terminals that cannot clear to end of line...
;
; edit 10, March 30th by OBSchou. Set bits for automatically receiving
; another file if a remote sender sends files in separate sessions.
; The code simply checks the serial line, and if there is some
; activity, assume its another SEND INIT packet. As there is no
; simple way to go to receive with the control-a, just ignore the
; packet. Causes one retry on the sender, but so what. Really
; should make it a server gizzmo.
;
; edit 9: January 28, 1987 by OBSchou
; Some modifications to the GET routines to correctly print the file
; name instead of the fireworks. Trouble was with GET <file> <file>
; and RECEIVE <file>. However, new bugs discovered...
;
; edit 8: August 11, 1986 Godfrey N. Nix [gnn] Nottingham University
; To ignore echoed packets (ie send 'S' receive 'S' before 'A');
; To allow character other than SOH for packet header (see also
; updates to CP4MIT and CP4UTL for other code needed);
; To permit SEND and RECEIVE to specify a host filename which
; is of a different structure to that of CP/M.
;
; edit 7: [OBSchou] 7 March, 1985.
; Edited file with additions from MJ Carter. He writes:
; 25th September 1985, M J Carter [majoc], Nottingham University
; Code in gofil() amended, for exactly the same reasons to the
; alteration to cmifil() in cpscmd.asm. If there is any deep
; reason why gofil() has to be used instead of a call to comnd(cmofil),
; I can't see it. The bug (on a British Micro Mimi 803) caused
; gofil() to overwrite existing files in GET and RECEIVE, even
; with file warning SET ON.
;
; edit 6: November 22, 1984
; Change SEND's 'Unable to find file' error exit from calling
; error3 to calling prtstr instead. I don't know about you, but
; I greatly dislike having messages dumped into pre-existing
; junk on the screen where I have to spend lots of time hunting
; for them. [Hal Hostetler]
;
; edit 5: September 9, 1984
; Call flsmdm in init to flush old input when starting transfers.
; Select console before returning from inpkt.
; Replace inline code with calls to makfil/clofil to set up for
; multisector buffering on output.
; Remove superfluous call to clrlin in error3.
;
; edit 4: August 21, 1984 (CJC)
; Fix comment in inpkt: packet is terminated by NUL on return, not CR.
; If debugging, display the outgoing packet before putting the EOL
; character on, so the dumped packet doesn't get overwritten.
;
; edit 3: July 27, 1984
; add link directive for LASM. CP4PKT is linked by CP4MIT, and links
; to CP4TT. Add Toad Hall TACtrap to permit operations through a TAC.
;
; edit 2: June 8, 1984
; formatting and documentation; remove some unused labels; move setpar
; to cp4mit.m80; add module version string; make all arithmetic on
; 'pktnum' modulo 64; apply defaults correctly for missing parameters
; in send-init packet (and corresponding ack).
;
; edit 1: May, 1984
; extracted from CPMBASE.M80 version 3.9; modifications are described
; in the accompanying .UPD file.
.Z80
ident /33/
include KDEF.INC
include SYSFN.INC
include FCB.INC
public PKTVER,READ,READ0,READ2,SEND,LOGO,LOGOUT,FINISH
public NAK,NAK0,ACKP,COUNTP,ERROR,ERROR0,RPACK,SPACK
public INIT,SINIT,SEND1,READ1,RINI2A,SPAR,SNDERR,FINMES
public ENCODE,ERROR3,CBFPTR,OUTPKN,SDATA,SEOF,SEOT,COMPP
public OUTRTR,UPDRTR
extrn KERMIT,KERMT3,COMND,PRTSTR,PRCRLF,SCRFLN,NOUT
extrn SCRNP,SELCON,INPCON,OUTCON,SELMDM,INPMDM,OUTMDM
extrn PURMDM,CLOFIL,MFINIT,MFNAME,INBUF,OUTBUF,OUTPRN
extrn GETFIL,SCRST,RPPOS,SPPOS,SETPAR,CLRTOP,SCREND
extrn MAKFIL,CFMCMD,SCRNRT,SCRERR,CLSETK,SYSSCR,FCBSTR
extrn OPENRW,CLOSEF,CLOSE2,SETFCB,FCBS2,STRLEN,DELET2
extrn MAKFI1,MFEND,CLREOL,FLSCON,PRTERR,R,RSKP,DELAY
extrn GTRXFL,REMDAT,RDL,QUIETD,STATE,CZSEEN,NUMPKT
extrn NUMRTR,PKTNUM,NUMTRY,REMTXT,AUTORC,DATA,ARGBLK
extrn CURCHK,OLDTRY,INICHK,INCFLG,CHKTYP,RECPKX,WRN8
extrn DSCFLG,BYTES,SIZE,QUOT8,PARITY,BUFLEN,REOL,FILBUF
extrn RPSIZ,RTIME,RPAD,RPADCH,RQUOTE,SEOL,QBCHR,TEMP4
extrn SQUOTE,SPSIZ,SPAD,SPADCH,TEMP1,OUTPNT,TEMP3
extrn FLWFLG,CHRCNT,BUFPNT,FMFLG,TEMP2,SOHCHR,FNBUF
extrn IBMFLG,PACKET,DBGFLG,RECPKT,TAKFLG,RCVSOP,PRNFLG
extrn SNDSOP,TACFLG,TIMFLG,SFCB,FCB,FCB2,SRVFLG,SRVTXT
extrn OPMODE
extrn ERMS15
extrn CPHLDE,PFN
cseg
PKTVER: defb 'KPKT (33) 4-Dec-2021',0 ; name, edit number, date
; GET command
; Here from: KERMIT
READ: ld a,0FFh ; we are doing a Get
ld (GTRXFL),a ; so set flag
ld de,REMDAT ; where to put the text (if any)
ld a,CMTXT
call COMND ; get either some text or a confirm
jp KERMT3 ; didn't get anything
or a ; got any chars?
jp z,KERMT3 ; GET must have a filename
ld (RDL),a ; store the number of chars
ex de,hl ; get pointer into HL
ld (hl),0 ; put in a trailing null for printing
call INIT ; clear the line and initialize the buffers
ld a,(OPMODE) ; Remote operation?
and a
jp z,READ0A ; yes
ld a,(QUIETD) ; quiet display?
and a
jr z,READ01 ; no, go ahead and position cursor
call PRCRLF ; yes, keep from overwriting the prompt
jr READ00 ; and write filename
READ01: call SCRFLN ; position cursor and erase to end of line
READ00: ld de,REMDAT ; print the file name, in either case
call PRTSTR
jp READ0A ; go get local name if any
; Enter here from SERVER routine
READ1: xor a ; we received a Server Send command
ld (GTRXFL),a ; so set flag
ld (REMTXT),a
inc a
ld (RDL),a
call RINI2A ; ACK the Send-Init packet with params
ld de,INMS24 ; get "Receiving..." message
call FINMES ; print it
jr READ11
; Enter here for RECEIVE command
READ0: xor a
ld (RDL),a ; flag entry as Receive, not Get
ld (GTRXFL),a ; doing a Receive, so reset flag
READ0A: ld de,REMNAM ; save local name here
ld a,CMTXT
call COMND ; read second filename if present
jp KERMT3 ; error exit
ld (REMLEN),a ; save length of name, may be zero
ld (GTRXFL),a ; may also be receive <fnam> so
; pretend get for printing filename
ld a,(RDL) ; look at first name
or a ; Receive or Get?
jr nz,READ12 ; Get
call INIT ; clear line, initialise buffers
call RMREAD ; output message if in Remote mode
jr READ13
READ12: ld a,'I' ; Get, set state to send "I" packet
ld (STATE),a
READ13: xor a
ld (CZSEEN),a ; clear the ^X/^Z flag initially
ld hl,0
ld (NUMPKT),hl ; set the number of packets to zero
ld (NUMRTR),hl ; set the number of retries to zero
ld (PKTNUM),a ; set the packet number to zero
ld (NUMTRY),a ; set the number of tries to zero
READ11: call OUTRTR ; write the number of retries
ld a,(RDL) ; Get or Receive?
or a
jr nz,READ2 ; Get, don't reset state
ld a,'R'
ld (STATE),a ; set the state to Receive-Initiate
;...
; RECEIVE state table switcher.
READ2: ld a,(REMTXT) ; in Remote command?
or a
call z,OUTPKN ; no, write the current packet number
READ21: ld a,(STATE) ; get the state
cp 'D' ; are we in the Data Receive state?
jr nz,READ22
call RDATA
jp READ2
READ22: cp 'X' ; F packet but not an F packet?
jr nz,READ3 ; nope, so try next one
call RFILE ; 'get' the filename (but don't open it)
jp READ2
READ3: cp 'F' ; are we in the File Receive state?
jr nz,READ4
call RFILE ; call Receive File
jp READ2
READ4: cp 'R' ; are we in the Receive-Initiate state?
jr nz,READ5
call RINIT
ld a,(STATE) ; get new state
cp 'F' ; went into Receive state?
jp nz,READ2 ; no
ld de,INMS24 ; yes, get "Receiving..." message
call FINMES ; go print it
jp READ2
READ5: cp 'C' ; are we in the Receive-Complete state?
jr nz,READ6
ld de,INFMS3 ; put in "Complete" message
ld a,(CZSEEN) ; or was it interrupted?
or a
jr z,READ5A ; no.
xor a ; yes, clear flag
ld (CZSEEN),a
ld de,INMS13 ; issue "Interrupted" message
READ5A: ld a,(REMTXT) ; doing a Remote command?
or a
call z,FINMES ; print completion message in right place if not
ld a,(RDL) ; Receive or Get?
or a
jp nz,KERMIT ; Get, Autoreceive means nothing
ld a,(AUTORC) ; see if we want autoreceives
and a
jp z,KERMIT ; no autoreceives, so drop out
ld de,AUTMES ; yes, tell the user what we're doing
call PRTSTR
jp READ12 ; try another Receive (we get one
; retry from the sender as the ^A is lost)
READ6: cp 'Y' ; simple ACK (from Remote command)?
jp z,KERMIT ; yes
cp 'I' ; exchanging parameters via info packet?
jr nz,READ7 ; no
call SINIT ; yes, send the packet
ld a,(STATE) ; now see what happened
cp 'X' ; did we exchange parameters successfully?
jr z,READ6A ; yes, go send the filespec
cp 'A' ; no, are we in Abort state?
jp nz,READ2 ; no, try again
jp KERMIT ; yes, it's a real disaster, we must stop
READ6A: ld a,(RDL) ; get length of filespec
ld (ARGBLK+1),a ; as length of packet
ld c,a ; we must copy the filespec
ld b,0
ld hl,REMDAT ; from the temporary buffer
ld de,DATA ; to the packet data area
ldir ; do it
; for GET we must send the name of the file we want
ld a,'1' ; start with single character checksum
ld (CURCHK),a ; save the type
xor a ; start a packet zero
ld (ARGBLK),a
ld a,'R' ; Receive Init packet
call SPACK ; send the packet
jp KERMT3 ; die!
xor a
ld (CZSEEN),a ; clear the ^X/^Z flag initially.
ld hl,0
ld (NUMPKT),hl ; set the number of packets to zero
ld (PKTNUM),a ; set the packet number to zero
ld (NUMTRY),a ; set the number of tries to zero
ld a,'R' ; set state to Receive-Initiate
ld (STATE),a
jp READ21 ; and go around again
; without retyping packet-number
READ7: cp 'A' ; are we in the Receive-"Abort" state?
jp nz,READ8
READ8: ld de,INFMS4 ; anything else is equivalent to "Abort"
call FINMES
jp KERMIT
RMREAD: ld a,(OPMODE) ; Remote operation?
or a
ret nz ; no, return
ld de,INFMS1
call PRTSTR ; else output message
xor a
ret
INFMS1: defb CR,LF,'Return to your local Kermit and give a SEND command'
defb CR,LF,0
INFMS3: defb BELL,'Completed',0
INFMS4: defb BELL,'Failed',0
INMS13: defb BELL,'Interrupted',0
INMS24: defb 'Receiving...',0
AUTMES: defb CR,LF,LF,'[Automatically receiving, type ^C to abort]'
defb CR,LF,LF,0
; Output current packet number to the screen
OUTPKN: ld a,(OPMODE) ; Remote mode?
and a
ret z ; yes, so don't write
ld a,(QUIETD) ; quiet display?
and a
ret nz ; yes, don't write either
call SCRNP ; position cursor
ld hl,(NUMPKT)
call NOUT ; write the packet number
call CLREOL ; erase to end of line
jp FLSCON ; ensure immediate output
; Receive routines
; Receive Init
; Called by: READ
RINIT: ld a,(NUMTRY) ; get the number of tries
cp IMXTRY ; have we reached the maximum number of tries?
jp m,RINIT2
ld de,ERMES4
call ERROR3 ; move cursor and print an error message
jp ABORT ; change the state to Abort
RINIT2: inc a ; increment it
ld (NUMTRY),a ; save the updated number of tries
ld a,'1' ; reset block check type to single character
ld (CURCHK),a ; store as current type for initialization
call RPACK ; get a packet
jp NAK ; trashed packet: NAK, retry
cp 'S' ; is it a Send Initiate packet?
jp nz,RINIT3 ; if not, see if it's an Error
RINI2A: ld a,(NUMTRY) ; get the number of tries
ld (OLDTRY),a ; save it
xor a
ld (NUMTRY),a ; reset the number of tries
ld a,(ARGBLK) ; returned packet number (synchronize them)
call COUNTP ; increment it
ld a,(ARGBLK+1) ; get the number of arguments received
ld hl,DATA ; get a pointer to the data
call SPAR ; get the data into the proper variables
ld hl,DATA ; get a pointer to our data block
call RPAR ; set up the receive parameters
ld (ARGBLK+1),a ; store the returned number of arguments
ld a,'Y' ; acknowledge packet
call SPACK ; send the packet
jp ABORT ; failed, abort
ld a,(INICHK) ; now switch to agreed upon check-type
ld (CURCHK),a ; for all future packets
ld a,'F' ; set the state to File Send
ld (STATE),a
ret
RINIT3: cp 'E' ; is it an Error packet?
jp nz,NAK0 ; if not, NAK whatever it is
call ERROR ; if yes, display the error info
jp ABORT ; and Abort
ERMES4: defb '?Unable to receive initiate',0
; Receive File
; Called by: READ
RFILE: ld a,(NUMTRY) ; get the number of tries
cp MAXTRY ; have we reached the maximum number of tries?
jp m,RFILE1
ld de,ERMES5
call ERROR3 ; move cursor and print an error message
jp ABORT ; change the state to Abort
RFILE1: inc a ; increment it
ld (NUMTRY),a ; save the updated number of tries
call RPACK ; get a packet
jp NAK ; trashed packet: NAK, retry
cp 'S' ; is it a Send Initiate packet?
jr nz,RFILE2 ; no, try next type
ld a,(OLDTRY) ; get the number of tries
cp IMXTRY ; have we reached the maximum number of tries?
jp m,RFIL12 ; if not, proceed
ld de,ERMES4
call ERROR3 ; move cursor and print an error message
jp ABORT ; change the state to Abort
RFIL12: inc a ; increment it
ld (OLDTRY),a ; save the updated number of tries
ld a,(PKTNUM) ; get the present packet number
dec a ; decrement
and 3Fh ; modulo 64
ld b,a
ld a,(ARGBLK) ; get the packet's number
cp b ; is the packet's number one less than now?
jp nz,NAK0 ; no, NAK and try again
call UPDRTR ; update the retry count
xor a
ld (NUMTRY),a ; reset the number of tries
ld hl,DATA ; get a pointer to our data block
call RPAR ; set up the parameter information
ld (ARGBLK+1),a ; save the number of arguments
ld a,'Y' ; acknowledge packet
call SPACK ; send the packet
jp ABORT ; failed, Abort
ret
RFILE2: cp 'Z' ; is it an EOF packet?
jr nz,RFILE3 ; no, try next type
ld a,(OLDTRY) ; get the number of tries
cp MAXTRY ; have we reached the maximum number of tries?
jp m,RFIL21 ; if not, proceed
ld de,ERMES6
call ERROR3 ; move cursor and print an error message
jp ABORT ; change the state to Abort
RFIL21: call TRYAGN
ret
RFILE3: cp 'F' ; start of file?
jr nz,RFIL3B
ld c,a ; save packet type
ld a,(REMTXT) ; doing a Remote server command?
or a
ld a,c ; restore packet type
jr nz,RFIL3D ; if yes, same as X packet
call COMPP ; expected packet?
jp nz,NAK0 ; no, NAK it and try again
call COUNTP ; increment packet number modulo 64
ld c,a
ld a,(REMTXT) ; doing a Remote command?
or a
ld a,c
jr nz,RFIL3A ; yes, don't open a file
call GOFIL ; get a file to write to, and init output buffer
jp ABORT ; on error, Abort
ld a,(OPMODE) ; Remote mode?
or a
jr z,RFIL3A ; yes, don't output anything
ld a,(QUIETD) ; quiet display?
or a
call z,SCRFLN ; no, position cursor and erase to end of line
ld ix,FCB2 ; point to FCB
ld hl,FNBUF ; get address of string buffer
push hl ; save string address
call FCBS2 ; convert FCB to string
pop de ; restore string address
call PRTSTR ; print the file name
RFIL3A: ld a,(NUMTRY) ; get the number of tries
ld (OLDTRY),a ; save it
call ACKP
ld a,'D' ; set the state to Data Receive
ld (STATE),a
ld a,(CZSEEN) ; check if we punted a file
cp 'Z' ; and didn't want any more
ret z ; if that was the request, keep telling other end
xor a ; otherwise, clear flag (^X is only for one file)
ld (CZSEEN),a ; and store the flag back
ret
RFIL3B: cp 'X' ; start of 'file?', but not a file?
jr nz,RFILE4
RFIL3D: call COMPP ; expected packet?
jp nz,NAK0 ; no, NAK it and try again
call COUNTP ; increment packet number modulo 64
call SELCON ; select Console
ld a,(ARGBLK+1) ; get length
or a ; anything to write?
jp z,RFIL3E ; no
push af ; yes, save character count
ld e,'<' ; write "<<" as in VMSKermit
call OUTCON
call OUTCON
pop af ; restore character count
ld hl,DATA ; lets write the filename (?) to display
RFIL3F: push af ; save loop counter
ld e,(hl) ; get character to write
inc hl ; and increment character pointer
push hl ; save the pointer
call OUTCON ; write character to display
pop hl ; restore pointer
pop af ; and loop counter
dec a ; decrement the counter
jr nz,RFIL3F ; display entire filename
ld e,'>' ; put in ">>" as in VMSKermit
call OUTCON
call OUTCON
call PRCRLF ; new line
RFIL3E: ld a,(NUMTRY) ; get the number of tries
ld (OLDTRY),a ; save it
call ACKP
ld a,'D' ; expecting a D packet
ld (STATE),a
ld a,(CZSEEN) ; check if we punted a file
cp 'Z' ; and didn't want any more
ret z ; if that was the request, keep telling other end
xor a ; otherwise, clear flag (^X is only for one file)
ld (CZSEEN),a ; and store the flag back
ret
RFILE4: cp 'B' ; end of transmission?
jr nz,RFILE5
call COMPP ; expected packet?
jp nz,NAK0 ; no, NAK it and try again
xor a ; no data (packet number already in ARGBLK)
ld (ARGBLK+1),a
ld a,'Y' ; acknowledge packet
call SPACK ; send the packet
jp ABORT
ld a,'C' ; set the state to Complete
ld (STATE),a
ret
RFILE5: cp 'E' ; is it an Error packet?
jp nz,ABORT ; no, send state to Abort
call ERROR ; yes, display error info
jp ABORT ; and Abort
ERMES5: defb '?Unable to receive file name',0
ERMES6: defb '?Unable to receive end of file',0
; Receive data
; Called by: READ
RDATA: ld a,(NUMTRY) ; get the number of tries
cp MAXTRY ; have we reached the maximum number of tries?
jp m,RDATA1
ld de,ERMS10
call ERROR3 ; display error message
RDAT16: ld a,(REMTXT) ; is a Remote command in progress?
or a
jp nz,ABORT ; yes, don't worry about file disposition
ld a,(INCFLG) ; are we keeping incomplete files?
or a
jr nz,RDAT17 ; yes
call CLOSE2 ; no, close the file, ignoring errors
call DELET2 ; now delete the file, ignoring errors
jp ABORT ; change the state to Abort
RDAT17: call CLOFIL ; try to close the file, writing
; outstanding buffers to disk
jp RDAT37 ; we can't, the disk is full
jp ABORT ; change the state to "Abort"
RDATA1: inc a ; increment it
ld (NUMTRY),a ; save the updated number of tries
call RPACK ; get a packet
jp NAK ; trashed packet: NAK, retry
cp 'D' ; is it a data packet?
jp nz,RDATA2 ; no, try next type
call COMPP ; check for correct packet number (zero flag = OK)
jp z,RDAT14 ; it's correct
ld a,(OLDTRY) ; get the number of tries
cp MAXTRY ; have we reached the maximum number of tries?
jp m,RDAT12 ; if not, proceed
ld de,ERMS10
call ERROR3 ; display error message
jp RDAT16 ; change the state to Abort
RDAT12: call TRYAGN
ret
RDAT14: call COUNTP ; increment packet number modulo 64
ld a,(NUMTRY) ; get the number of tries
ld (OLDTRY),a ; save it
ld a,(ARGBLK+1) ; get the length of the data
call PTCHR
jp RDAT3B ; unable to write out chars, abort
xor a
ld (NUMTRY),a ; reset the number of tries
ld (ARGBLK+1),a ; no data (packet number still in ARGBLK)
ld c,a ; assume no data
ld a,(CZSEEN) ; check if control-X typed
or a
jp z,RDAT15 ; zero if not typed
ld c,a ; get the type of character typed
ld a,1 ; one data character
ld (ARGBLK+1),a ; save the count
ld a,c ; get the possible data character
ld (DATA),a ; store in data area
RDAT15: ld a,'Y' ; acknowledge packet
call SPACK ; send the packet
jp RDAT16
ret
RDATA2: cp 'F' ; start of file?
jr nz,RDATA3 ; no, try next type
ld a,(OLDTRY) ; get the number of tries
cp MAXTRY ; have we reached the maximum number of tries?
jp m,RDAT21 ; if not, proceed
ld de,ERMES5
call ERROR3 ; display error message
jp RDAT16 ; change the state to Abort
RDAT21: call TRYAGN
ret
RDATA3: cp 'Z' ; is it a EOF packet?
jp nz,RDATA4 ; try and see if it's an error
call COMPP ; expected packet?
jp nz,NAK0 ; no, NAK it and try again
call COUNTP ; increment packet number modulo 64
ld a,(ARGBLK+1) ; get the data length
cp 1 ; have one item?
jr nz,RDAT33 ; if not, ignore data
ld a,(DATA) ; yes, get the character
cp 'D' ; is it a 'D' for discard?
jp z,RDAT36 ; if so, punt file
RDAT33: ld a,(REMTXT) ; writing text to disk?
or a
jr nz,RDAT38 ; no, don't close file
call CLOFIL ; finish off the file
jp RDAT37 ; give up if the disk is full
RDAT38: xor a ; since we kept the file,
ld (CZSEEN),a ; don't say it was discarded
ld a,(NUMTRY) ; get the number of tries
ld (OLDTRY),a ; save it
call ACKP
jp RDAT39 ; and get ready to get more files
RDAT36: ld a,(NUMTRY) ; get the number of tries
ld (OLDTRY),a ; save it
call ACKP
ld a,(REMTXT) ; is a Remote command in progress?
or a
jp nz,RDAT39 ; yes, don't worry about file disposition
ld a,(DSCFLG) ; is the file being punted because
or a ; of a collision?
jp nz,RDAT39 ; yes, don't delete the existing file
ld a,(INCFLG) ; no, are we keeping incomplete files?
or a
jp nz,RDAT3A ; yes
call CLOSE2 ; no, close the file, ignoring errors
call DELET2 ; now delete the file, ignoring errors
jp RDAT39 ; and continue
RDAT3A: call CLOFIL ; try to close the file, writing
; outstanding buffers to disk
jp RDAT37 ; can't, disk is full
RDAT39: ld a,'F'
ld (STATE),a
ret
RDAT37: call PTCHR9 ; send "?Disk full" on the error line
; and to the remote Kermit
RDAT3B: ld a,(REMTXT) ; doing a Remote command?
or a
jp nz,ABORT ; yes, just abort
call CLOSE2 ; close the file, ignoring errors
ld a,(INCFLG) ; are we keeping incomplete files?
or a
jp nz,ABORT ; yes, just abort transfer
call DELET2 ; no, delete the file, ignoring errors
jp ABORT ; abort transfer
RDATA4: cp 'E' ; is it an Error packet?
jp nz,RDAT16 ; no, close file and Abort
call ERROR ; yes, display error info
jp RDAT16 ; close file and Abort
ERMS10: defb '?Unable to receive data',0
; SEND command
; Here from: KERMIT
SEND: ld a,CMIFI ; parse an input file spec
ld de,SFCB ; give the address for the FCB
call COMND
jp KERMIT ; give up on bad parse
; section to get remote filename
ld de,REMNAM ; where to put filename
ld a,CMTXT
call COMND ; get the text to end of the line
jp KERMT3 ; failure in reading buffer
ld (REMLEN),a ; save length (may be zero)
xor a
ld (SRVTXT),a
jr SEND11 ; continue below
; Enter here from SERVER routine.
SEND1: xor a ; here from SERVER routine
ld (REMLEN),a ; so clear length (no local file name)
ld (REMTXT),a
SEND11: call MFINIT ; initialize file search
call MFNAME ; handle (multi) files
jr nc,SEND14 ; got a valid file-name
ld de,ERMS15
push de
call SEND12 ; display error msg. (where it's visible)
pop de
ld a,(SRVFLG)
or a ; are we in Server mode?
call nz,SNDERR ; yes, send error to remote client
jp KERMIT
SEND12: ld a,(SRVFLG)
or a ; Server mode?
jp z,PRTERR ; no, output error message after newline
ld a,(OPMODE) ; Remote mode?
or a
ret z ; yes, return
push de
ld a,(QUIETD)
or a ; quiet display?
call z,SCRERR ; no, position cursor
pop de
call PRTSTR ; output message
ld a,(QUIETD)
or a ; quiet display?
ret nz ; yes, return
call CLREOL ; else erase to end of line
jp PRCRLF ; and output a newline
SEND14: call INIT ; clear the line and initialize the buffers
ld a,(OPMODE) ; Remote operation?
or a
jr nz,SEND15 ; no
ld a,(SRVFLG) ; Server mode?
or a
jr nz,SEND15 ; yes
ld de,INFMS2
call PRTSTR ; else output message
ld hl,5
call DELAY ; and wait 5 seconds before start
SEND15: xor a
ld (PKTNUM),a ; set the packet number to zero
ld (NUMTRY),a ; set the number of tries to zero
ld (WRN8),a ; we haven't sent the 8-bit-lost warning
ld hl,0
ld (NUMPKT),hl ; set the number of packets to zero
ld (NUMRTR),hl ; set the number of retries to zero
call OUTRTR ; write the number of retries
ld a,'1' ; reset to use single character checksum
ld (CURCHK),a ; for startup
ld a,'S'
ld (STATE),a ; set the state to Send Initiate
; ...
; SEND state table switcher
SEND2: call OUTPKN ; write the packet number
ld a,(STATE) ; get the state
cp 'D' ; are we in the Data Send state?
jr nz,SEND3
call SDATA
jp SEND2
SEND3: cp 'F' ; are we in the File Send state?
jr nz,SEND4
call SFILE ; call Send File
jp SEND2
SEND4: cp 'Z' ; are we in the EOF state?
jr nz,SEND5
call SEOF
jp SEND2
SEND5: cp 'S' ; are we in the Send Initiate state?
jr nz,SEND6
call SINIT
ld a,(STATE) ; get state back
cp 'F' ; into File Send state yet?
jp nz,SEND2 ; no
ld de,INMS23 ; yes, print "Sending..."
call FINMES
jp SEND2
SEND6: cp 'B' ; are we in the EOT state?
jr nz,SEND7
call SEOT
jp SEND2
SEND7: cp 'C' ; are we in the Send Complete state?
jr nz,SEND8 ; no...
ld de,INFMS3 ; yes, write "Complete" message.
ld a,(CZSEEN) ; or was it interrupted?
or a
jr z,SEND7A ; no
ld de,INMS13 ; yes, then say "Interrupted" instead
SEND7A: call FINMES
jp KERMIT
SEND8: cp 'A' ; are we in the Send "Abort" state?
jr nz,SEND9
ld de,INFMS4 ; print message
call FINMES
jp KERMIT
SEND9: ld de,INFMS4 ; anything else is equivalent to "Abort"
call FINMES
jp KERMIT
INFMS2: defb CR,LF,'Return to your local Kermit and give a RECEIVE command'
defb CR,LF,0
INMS23: defb 'Sending...',0
; Send routines
; Send initiate
; Called by: SEND
SINIT: ld a,(NUMTRY) ; get the number of tries
cp IMXTRY ; have we reached the maximum number of tries?
jp m,SINIT2 ; not yet
ld de,ERMS14
call ERROR3 ; display eror message
jp ABORT ; change the state to Abort
SINIT2: inc a ; increment it
ld (NUMTRY),a ; save the updated number of tries
ld a,'1' ; reset to use single character checksum
ld (CURCHK),a ; for startup
ld a,(CHKTYP) ; get our desired block check type
ld (INICHK),a ; store so we tell other end
ld hl,DATA ; get a pointer to our data block
call RPAR ; set up the parameter information
ld (ARGBLK+1),a ; save the number of arguments
ld a,(NUMPKT) ; get the packet number
ld (ARGBLK),a
ld a,(STATE) ; load state (I or S)
call SPACK ; send the packet
jp ABORT ; failed, abort
call RPACK ; get a packet