-
Notifications
You must be signed in to change notification settings - Fork 1
/
terminalemulation.asm
2743 lines (2570 loc) · 77.2 KB
/
terminalemulation.asm
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
NAME msster
; File MSSTER.ASM
include symboldefs.h
; Copyright (C) 1982, 1999, Trustees of Columbia University in the
; City of New York. The MS-DOS Kermit software may not be, in whole
; or in part, licensed or sold for profit as a software product itself,
; nor may it be included in or distributed with commercial products
; or otherwise distributed by commercial concerns to their clients
; or customers without written permission of the Office of Kermit
; Development and Distribution, Columbia University. This copyright
; notice must not be removed, altered, or obscured.
;
; Edit history
; 12 Jan 1995 version 3.14
; Last edit
; 12 Jan 1995
public clscpt, defkey, clscpi, ploghnd, sloghnd, tloghnd
public dopar, shokey, cptchr, pktcpt, targ, replay, repflg
public kbdflg, shkadr, telnet, ttyact, write, dec2di, caplft
public cnvlin, decout, valout, cnvstr, writeln
public pntchr, pntflsh, pntchk, prnhand, prnopen
public vfopen, vfread, ldiv, lmul, lgcd, atoi, atoibyte
public domath, domath_ptr, domath_cnt, domath_msg
public atoi_cnt, atoi_err, tod2secs
braceop equ 7bh ; opening curly brace
bracecl equ 7dh ; closing curly brace
data segment
extrn flags:byte, trans:byte, diskio:byte, portval:word
extrn rdbuf:byte, dosnum:word, filtst:byte, prnname:byte
extrn comand:byte, kstatus:word, flowon:byte, flowoff:byte
extrn cardet:byte
ifndef no_terminal
extrn anspflg:byte
endif ; no_terminal
targ termarg <0,1,cptchr,0,parnon>
crlf db cr,lf,'$'
tmsg1 db cr,lf,'(Connecting to host, type $'
tmsg3 db ' C to return to PC)',cr,lf,cr,lf,cr,lf,'$'
erms21 db cr,lf,'?Cannot start the connection.$'
erms25 db cr,lf,'?Input must be numeric$'
erms22 db cr,lf,'?No open logging file$'
erms23 db '*** Error writing session log, suspending capture ***$'
erms24 db cr,lf,'?Error writing Packet log$'
erms26 db ' *** PRINTER IS NOT READY *** press R to retry'
db ' or D to discard printing: $'
erms27 db cr,lf
db '? Carrier signal not detected on this serial port.'
db cr,lf
db ' Use the DIAL command, SET CARRIER OFF, or check your modem.$'
esctl db 'Control-$'
repflg db 0 ; REPLAY or SET TERM REPLAY filespec flag
reperr db cr,lf,'?File not found$' ; for REPLAY command
noterm db cr,lf,'Connect mode is not built into this Kermit$'
vfopbad db cr,lf,'?Cannot open file $' ; filename follows
vfclbad db cr,lf,'?Cannot close file$'
vfoptwice db cr,lf,'?File is already open$'
vfnofile db cr,lf,'?File is not open$'
vfrbad db cr,lf,'?Error while reading file$'
vfwbad db cr,lf,'?Error while writing file$'
vfrdbad db cr,lf,'?more parameters are needed$'
vfrhandle dw -1 ; READ FILE handle (-1 = invalid)
vfwhandle dw -1 ; WRITE FILE handle
opntab db 3 ; OPEN FILE table
mkeyw 'Read',1
mkeyw 'Write',2
mkeyw 'Append',3
inthlp db cr,lf,' ', 22 dup ('-'),' Special keys within Connect mode '
db 22 dup ('-')
db cr,lf,' numeric keypad keys:'
db cr,lf,' Pg Up/Dn roll screen vertically Ctrl Pg Up/Dn roll'
db ' screen one line '
db cr,lf,' Home/End roll to start/end screen Ctrl End screen dump'
db cr,lf,' - (minus) toggle status/mode line'
db cr,lf,' other key combinations:'
db cr,lf,' Alt-b send a BREAK Alt-n next active'
db ' Telnet session'
db cr,lf,' Alt-c start Compose sequence Alt-x exit emulator'
db cr,lf,' Alt-h show this menu Alt-z network session'
db ' hold'
db cr,lf,' Alt-= or Alt-r reset emulator Alt-- toggle terminal'
db ' type'
db cr,lf,' Ctrl Prtscrn toggle printing'
db cr,lf,' Additional commands are escape character '
inthlpc db ' '
db ' followed by special characters.'
db cr,lf,' ',78 dup ('-')
db cr,lf,' 7n1 = SET TERM BYTE 7, SET PARITY NONE, 1 stop bit'
db cr,lf,' 8n1 = SET TERM BYTE 8, SET PARITY NONE, 1 stop bit'
db cr,lf,' 7e1 = SET PARITY EVEN, 1 stop bit 7s1 = SET PARITY SPACE'
db ', 1 stop bit'
db cr,lf,' 7o1 = SET PARITY ODD, 1 stop bit 7m1 = SET PARITY MARK'
db ', 1 stop bit'
db cr,lf,' press a key to exit this menu'
db 0
intqry db cr,lf,' ',20 dup ('-'),' Single character commands active now '
db 20 dup ('-')
db cr,lf,' ? Show this menu F Dump screen to file'
db cr,lf,' C Close the emulator P Push to DOS'
db cr,lf,' S Status of the connection Q Quit logging'
db cr,lf,' M Toggle mode line R Resume logging'
db cr,lf,' B Send a Break 0 Send a null'
db cr,lf,' L Send a long 1.8 s Break H Hangup phone'
db cr,lf,' A Send Telnet "Are You There" I Send Telnet'
db ' "Interrupt Process"'
db cr,lf,' Typing the escape character '
intqryc db ' ' ; where escape char glyphs go
db ' will send it to the host'
db cr,lf,' press space bar to exit this menu'
db 0
intprm db 'Command> $'
intclet db 'B','C','F','H','L' ; single letter commands
db 'M','P','Q','R','S' ; must parallel dispatch table intcjmp
db '?','0','A','I'
numlet equ $ - intclet ; number of entries
even
ifndef no_terminal
intcjmp dw intchb,intchc,intchf,intchh,intchl
dw intchm,intchp,intchq,intchr,intchs
dw intchu,intchn,intayt,inttip
endif ; no_terminal
prnhand dw 4 ; printer file handle (4 = DOS default)
even
ploghnd dw -1 ; packet logging handle
sloghnd dw -1 ; session logging handle
tloghnd dw -1 ; transaction logging handle
clotab db 6
mkeyw 'READ-FILE',4001h
mkeyw 'WRITE-FILE',4002h
mkeyw 'All-logs',logpkt+logses+logtrn
mkeyw 'Packets',logpkt
mkeyw 'Session',logses
mkeyw 'Transactions',logtrn
clseslog db cr,lf,' Closing Session log$'
clpktlog db cr,lf,' Closing Packet log$'
cltrnlog db cr,lf,' Closing Transaction log$'
writetab db 5 ; Write command log file types
mkeyw 'FILE',4002h ; FILE
mkeyw 'Packet',logpkt
mkeyw 'Screen',80h ; unused value, to say screen
mkeyw 'Session',logses
mkeyw 'Transaction',logtrn
sttmsg db cr,lf,'Press space to continue ...$'
kbdflg db 0 ; non-zero means char here from Term
ttyact db 1 ; Connect mode active, if non-zero
shkadr dw 0 ; offset of replacement Show Key cmd
nbase dw 10 ; currently active number base
temp dw 0
temp1 dw 0
tmp db 0
tmp1 db 0
tmpstring db 6 dup (0) ; local string work buffer
pktlft dw cptsiz ; number free bytes left
caplft dw cptsiz ; number free bytes left
maxdepth equ 8 ; domath, parenthesis nesting depth
listlen equ 6 ; domath, outstanding numbers and ops
parendepth db 0 ; domath, depth of ()'s
mathkind db 0 ; domath, math operator symbol, temp
operators db '()!~^*/%&+-|#@' ; domath, math operator list
operator_len equ $ - operators ; domath, length of the list
precedence db 6,6,5,4,3, 2,2,2,2,1, 1,1,1,1 ; domath, precedence of ops
fevalst struc ; structure of demath work stacks, all on the stack
savebp dw 0 ; where bp is pushed
numcnt dw 0 ; count of values in numlist
numlist dw listlen dup (0,0) ; list of dword values
opcnt dw 0 ; count of operators in oplist
oplist dw listlen dup (0) ; list of pending operators
fevalst ends
domath_ptr dw 0 ; ds:offset of domath input text
domath_cnt dw 0 ; count of bytes in input text
domath_msg dw 0 ; non-zero to allow error msgs
matherr dw 0 ; non-zero = offset of error msg
opmsg db '?too many math operators or too few values $'
opmsg1 db '?math operator missing or invalid $'
opmsg2 db '?unknown math symbol: $'
opmsg3 db '?math expression error $'
opmsg4 db '?parentheses nested too deeply $'
atoibyte db 0 ; non-zero to say convert one char
atoi_err db 0 ; atoi return error codes
atoi_cnt dw 0 ; atoi, bytes supplied to/remaining
data ends
data1 segment
rephlp db 'name of file to playback$'
clohlp db cr,lf,' READ-FILE or WRITE-FILE, or the following log files:'
db cr,lf,' All-logs, Packets, Session, Transaction$'
msgtxt db 'text to be written$'
vfophlp db 'Filename$'
vfrdmsg db 'name of variable into which to read a line from file$'
pktbuf db cptsiz dup (0) ; packet logging buffer
pktbp dw pktbuf ; buffer pointer to next free byte
capbuf db cptsiz dup (0) ; session logging buffer
capbp dw capbuf ; buffer pointer to next free byte
prnbuf db cptsiz dup (0) ; printer buffer
pntptr dw prnbuf ; pointer to next free byte
data1 ends
code1 segment
extrn iseof:far, strlen:far, prtasz:far, isfile:far
assume cs:code1
code1 ends
code segment
extrn comnd:near, outchr:near, stat0:near, pcwait:far
extrn beep:near, puthlp:near, serhng:near, lnout:near
extrn serini:near, serrst:near, sendbr:near, putmod:near
extrn fpush:near, sendbl:near, trnmod:near, dodecom:near
ifndef no_terminal
extrn dumpscr:near,term:near
endif ; no_terminal
flnout proc far
call lnout
ret
flnout endp
assume cs:code, ds:data, es:nothing
; the show key command
shokey proc near
cmp shkadr,0 ; keyboard translator present?
je shokey1 ; e = no, use regular routines
mov bx,shkadr ; get offset of replacement routine
jmp bx ; and execute it rather than us
shokey1:clc
ret
shokey endp
; enter with ax/scan code to define, si/ pointer to definition, cx/ length
; of definition. Defines it in definition table. Obsolete.
defkey proc near
ret
defkey endp
; This is the CONNECT command
ifdef no_terminal
TELNET PROC NEAR
mov ah,cmeol
call comnd ; get a confirm
jnc teln1 ; nc = success
ret
teln1: mov ah,prstr
mov dx,offset noterm
int dos
clc
ret
TELNET ENDP
endif ; no_terminal
ifndef no_terminal
TELNET PROC NEAR
mov ah,cmeol
call comnd ; get a confirm
jnc teln1 ; nc = success
ret
teln1: cmp repflg,0 ; REPLAY?
jne teln1d ; ne = yes
call serini ; ensure port is inited now
jnc teln1a ; nc = success
test flags.remflg,dquiet ; quiet display mode?
jnz teln1b ; nz = yes. Don't write to screen
mov dx,offset erms21 ; say cannot start connection
mov ah,prstr
int dos
teln1b: or kstatus,ksgen ; general command failure
ret
teln1a: cmp flags.comflg,'F' ; Fossil port?
je teln1c ; e = yes
cmp flags.comflg,'4' ; using real or Bios serial ports?
ja teln1d ; a = no
teln1c: cmp flags.carrier,0 ; want CD on now?
je teln1d ; e = no
test cardet,80h ; CD on?
jnz teln1d ; nz = yes
mov ah,prstr ; complain on screen
mov dx,offset erms27
int dos
stc ; fail
ret
teln1d: cmp flags.vtflg,0 ; emulating a terminal?
jne teln2 ; ne= yes, no wait necessary
mov ah,prstr
mov dx,offset crlf ; output a crlf
int dos
call domsg ; reassure user
mov ax,2000 ; two seconds
call pcwait ; pause
teln2: xor al,al ; initial flags
mov ttyact,1 ; say telnet is active
cmp flags.vtflg,0 ; emulating a terminal?
je teln3 ; e = no, say mode line is to be off
cmp flags.modflg,0 ; mode line enabled?
jne tel010 ; ne = yes
teln3: or al,modoff ; no, make sure it stays off
tel010: test flags.debug,logses ; debug mode?
jz tel0 ; z = no, keep going
or al,trnctl ; yes, show control chars
tel0: cmp flags.vtflg,0 ; emulating a terminal?
je tel1 ; e = no
or al,emheath ; say emulating some kind of terminal
tel1: mov bx,portval
cmp [bx].ecoflg,0 ; echoing?
jz tel2 ; z = no
or al,lclecho ; turn on local echo
tel2: mov targ.flgs,al ; store flags
mov ah,flags.comflg ; COMs port identifier
mov targ.prt,ah ; Port 1 or 2, etc
mov ah,[bx].parflg ; parity flag
mov targ.parity,ah
mov ax,[bx].baud ; baud rate identifier
mov targ.baudb,al
xor ah,ah
test flags.capflg,logses ; select session logging flag bit
jz tel3 ; z = no logging
mov ah,capt ; set capture flag
tel3: or targ.flgs,ah
jmp short tem1
TEM: call serini ; init serial port
jnc tem1 ; nc = success
clc
ret ; and exit Connect mode
tem1: mov dx,offset crlf ; give user an indication that we are
mov ah,prstr ; entering terminal mode
int dos
mov ttyact,1 ; say telnet is active
mov ax,offset targ ; point to terminal arguments
call term ; call the main Terminal procedure
mov al,kbdflg ; get the char from Term, if any
mov kbdflg,0 ; clear the flag
or al,al ; was there a char from Term?
jnz intch2 ; nz = yes, else ask for one from kbd
intchar:call iseof ; stdin at eof?
jnc intch1 ; nc = not eof, get more
mov al,'C' ; use C when file is empty
jmp intchc ; to provide an exit
intch1: cmp al,0 ; asking for help?
jne intch1b ; ne = no
mov al,' '
mov ah,trans.escchr
cmp ah,' ' ; printable now?
jae intch1a ; ae = yes
mov al,'^'
add ah,40h ; make control visible
intch1a:mov word ptr intqryc,ax ; store escape char code
mov ax,offset intqry ; '?' get help message
call puthlp ; write help msg
mov dx,offset intprm
mov ah,prstr ; show prompt
int dos
intch1b:mov ah,0ch ; clear Bios keyboard buffer and do
mov al,coninq ; read keyboard, no echo
int dos ; get a char
or al,al ; scan code indicator?
jnz intch1c ; nz = no, ascii
mov ah,coninq ; read and discard scan code
int dos
jmp short intch1 ; try again
intch1c:cmp al,'?' ; want to see menu again?
jne intch2 ; ne = no
xor al,al ; prep for menu display
jmp short intchar
intch2: mov flags.cxzflg,0 ; prevent Control-C carryover
cmp al,' ' ; space?
je tem ; e = yes, ignore it
cmp al,cr ; check ^M (cr) against plain ascii M
je tem ; exit on cr
cmp al,trans.escchr ; is it the escape char?
jne intch3 ; ne = no
mov ah,al
call outchr
jmp tem ; return, we are done here
intch3: push es
push ds
pop es
mov di,offset intclet ; command letters
mov cx,numlet ; quantity of them
cmp al,' ' ; control code?
jae intch3a ; ae = no
or al,40H ; convert control chars to printable
intch3a:cmp al,96 ; lower case?
jb intch3b ; b = no
and al,not (20h) ; move to upper case
intch3b:cld
repne scasb ; find the matching letter
pop es
jne intch4 ; ne = not found, beep and get another
dec di ; back up to letter
sub di,offset intclet ; get letter number
shl di,1 ; make it a word index
jmp intcjmp[di] ; dispatch to it
intch4: call beep ; say illegal character
jmp intchar
intayt: mov ah,255 ; 'I' Telnet Are You There
call outchr ; send IAC (255) AYT (246)
mov ah,246
call outchr
jmp tem
intchb: call sendbr ; 'B' send a break
jmp tem ; And return
intchc: clc ; exit Connect mode
ret
intchf: call dumpscr ; 'F' dump screen, use msy routine
jmp tem ; and return
intchh: call serhng ; 'H' hangup phone
call serrst ; turn off port
jmp tem
intchl: call sendbl ; 'L' send a long break
jmp tem
inttip: mov ah,255 ; 'I' Telnet Interrrupt Process
call outchr ; send IAC (255) IP (244)
mov ah,244
call outchr
jmp tem
intchm: cmp flags.modflg,1 ; 'M' toggle mode line, enabled?
jne intchma ; ne = no, leave it alone
xor targ.flgs,modoff ; enabled, toggle its state
intchma:jmp tem ; and reconnect
intchp: call fpush ; 'P' push to DOS
mov dx,offset sttmsg ; say we have returned
mov ah,prstr
int dos
jmp short intchsb ; wait for a space
intchq: and targ.flgs,not capt ; 'Q' suspend session logging
jmp tem ; and resume
intchr: test flags.capflg,logses ; 'R' resume logging. Can we capture?
jz intchr1 ; z = no
or targ.flgs,capt ; turn on session logging flag
intchr1:jmp tem ; and resume
intchs: call stat0 ; 'S' status, call stat0
mov dx,offset sttmsg
mov ah,prstr
int dos
intchsa:call iseof ; is stdin at eof?
jnc intchsb ; nc = not eof, get more
jmp tem ; resume if EOF
intchsb:mov ah,coninq ; console input, no echo
int dos
cmp al,' ' ; space?
jne intchsa
jmp tem
intchu: mov ah,trans.escchr
cmp ah,' ' ; printable now?
jae intchu1 ; ae = yes
mov al,'^'
add ah,40h ; make control visible
intchu1:mov word ptr inthlpc,ax ; store escape char code
mov ax,offset inthlp ; help message
call puthlp ; write help msg
mov ah,0ch ; clear Bios keyboard buffer and do
mov al,coninq ; read keyboard, no echo
int dos ; get a char
or al,al ; scan code indicator?
jnz intchu2 ; nz = no, ascii
mov ah,coninq ; read and discard scan code
int dos
intchu2:jmp tem ; try again
intchn: xor ah,ah ; '0' send a null
call outchr
jmp tem
TELNET ENDP
endif ; no_terminal
code ends
code1 segment
assume cs:code1
; Reassure user about connection to the host. Tell him what escape sequence
; to use to return
DOMSG PROC FAR
mov ah,prstr
mov dx,offset tmsg1
int dos
call escprt
mov ah,prstr
mov dx,offset tmsg3
int dos
ret
DOMSG ENDP
; print the escape character in readable format.
ESCPRT PROC NEAR
mov dl,trans.escchr
cmp dl,' '
jge escpr2
push dx
mov ah,prstr
mov dx,offset esctl
int dos
pop dx
add dl,040H ; Make it printable
escpr2: mov ah,conout
int dos
ret
ESCPRT ENDP
code1 ends
code segment
assume cs:code
; Set parity for character in Register AL
dopar: push bx
mov bx,portval
mov bl,[bx].parflg ; get parity flag byte
test bl,PARHARDWARE ; hardware?
jnz parret ; nz = yes
cmp bl,parnon ; No parity?
je parret ; Just return
and al,07FH ; Strip parity. Same as Space parity
cmp bl,parspc ; Space parity?
je parret ; e = yes, then we are done here
cmp bl,parevn ; Even parity?
jne dopar0 ; ne = no
or al,al
jpe parret ; pe = even parity now
xor al,080H ; Make it even parity
jmp short parret
dopar0: cmp bl,parmrk ; Mark parity?
jne dopar1 ; ne = no
or al,080H ; Turn on the parity bit
jmp short parret
dopar1: cmp bl,parodd ; Odd parity?
or al,al
jpo parret ; Already odd, leave it
xor al,080H ; Make it odd parity
parret: pop bx
ret
; REPLAY filespec through terminal emulator
replay proc near
mov bx,offset rdbuf ; place for filename
mov dx,offset rephlp ; help
mov repflg,0 ; clear the replay active flag
mov ah,cmword ; get filename
call comnd
jc replay2 ; c = failure
mov ah,cmeol ; get an EOL confirm
call comnd
jc replay2 ; c = failure
ifndef no_terminal
mov ah,open2 ; open file
xor al,al ; open readonly
cmp byte ptr dosnum+1,2 ; above DOS 2?
jna replay1 ; na = no, so no shared access
mov al,0+40h ; open readonly, deny none
replay1:mov dx,offset rdbuf ; asciiz filename
int dos
jnc replay3 ; nc = success
mov ah,prstr
mov dx,offset reperr ; Cannot open that file
int dos
clc
ret
replay3:mov diskio.handle,ax ; file handle
mov repflg,1 ; set replay flag
call telnet ; enter Connect mode
mov bx,diskio.handle
mov ah,close2 ; close the file
int dos
endif ; no_terminal
mov repflg,0 ; clear the flag
clc
replay2:ret
replay endp
cptchr proc near ; session capture routine, char in al
test flags.capflg,logses ; session logging active now?
jz cptch1 ; z = no
push di
push es
mov di,data1 ; seg of capbp and capbuf
mov es,di
cld
mov di,es:capbp ; buffer pointer
stosb
inc es:capbp
pop es
pop di
dec caplft ; decrement chars remaining
jg cptch1 ; more room, forget this part
call cptdmp ; dump the info
cptch1: ret
cptchr endp
cptdmp proc near ; empty the capture buffer
push ax
push bx
push cx
push dx
mov bx,sloghnd ; get file handle
or bx,bx ; is file open?
jle cptdm1 ; le = no, skip it
mov cx,cptsiz ; original buffer size
sub cx,caplft ; minus number remaining
jl cptdm2 ; means error
jcxz cptdm1 ; z = nothing to do
push ds
mov dx,data1 ; seg of capbuf
mov ds,dx
mov dx,offset capbuf ; the capture routine buffer
mov ah,write2 ; write with filehandle
int dos ; write out the block
pop ds
jc cptdm2 ; carry set means error
cmp ax,cx ; wrote all?
jne cptdm2 ; no, an error
push es
mov dx,data1 ; seg of capbuf and capbp
mov es,dx
mov es:capbp,offset capbuf
pop es
mov caplft,cptsiz ; init buffer ptr & chrs left
clc
jmp short cptdm1
cptdm2: and targ.flgs,not capt ; so please stop capturing
and flags.capflg,not logses ; deselect session logging flag bit
mov dx,offset erms23 ; tell user the bad news
call putmod ; write on mode line
stc
cptdm1: pop dx
pop cx
pop bx
pop ax
ret
cptdmp endp
pktcpt proc near ; packet log routine, char in al
test flags.capflg,logpkt ; logging packets now?
jz pktcp1 ; z = no
push di
push es
mov di,data1 ; seg of pktbuf and pktbp
mov es,di
mov di,es:pktbp ; buffer pointer
cld
stosb ; store char in buffer
inc es:pktbp ; move pointer to next free byte
pop es
pop di
dec pktlft ; decrement chars remaining
jg pktcp1 ; g = more room, forget this part
call pktdmp ; dump the info
pktcp1: ret
pktcpt endp
pktdmp proc near ; empty the capture buffer
push ax
push bx
push cx
push dx
mov bx,ploghnd ; get file handle
or bx,bx ; is file open?
jle cptdm1 ; le = no, skip it
mov cx,cptsiz ; original buffer size
sub cx,pktlft ; minus number remaining
jl pktdm2 ; l means error
jcxz pktdm1 ; z = nothing to do
push ds
mov dx,data1 ; seg of pktbuf
mov ds,dx
mov dx,offset pktbuf ; the capture routine buffer
mov ah,write2 ; write with filehandle
int dos ; write out the block
pop ds
jc pktdm2 ; carry set means error
cmp ax,cx ; wrote all?
jne pktdm2 ; ne = no, error
push es
mov dx,data1 ; seg of pktbuf
mov es,dx
mov es:pktbp,offset pktbuf
pop es
mov pktlft,cptsiz ; init buffer ptr & chrs left
jmp short pktdm1
pktdm2: and flags.capflg,not logpkt ; so please stop capturing
mov dx,offset erms24 ; tell user the bad news
mov ah,prstr
int dos
call clscp4 ; close the packet log
pktdm1: pop dx
pop cx
pop bx
pop ax
ret
pktdmp endp
; CLOSE command
clscpt proc near
mov ah,cmkey ; get kind of file to close
mov dx,offset clotab ; close table
mov bx,offset clohlp ; help
call comnd
jc clscp2 ; c = failure
mov temp,bx
mov ah,cmeol
call comnd
jc clscp2 ; c = failure
mov kstatus,kssuc ; success status thus far
mov bx,temp
cmp bh,40h ; READ-FILE or WRITE-FILE?
jne clscp0 ; ne = no
mov ax,bx
jmp vfclose ; close FILE, pass kind in AX
clscp0: cmp bx,logpkt+logses+logtrn ; close all?
je clscpi ; e = yes
cmp bx,logpkt ; just packet?
je clscp4
cmp bx,logses ; just session?
je clscp6
cmp bx,logtrn ; just session?
jne clscp1 ; ne = no
jmp clscp8
clscp1: mov dx,offset erms22 ; say none active
mov ah,prstr
int dos
clc
ret
clscp2: mov kstatus,ksgen ; general cmd failure status
stc
ret
; CLSCPI called at Kermit exit
CLSCPI: mov bx,portval
mov [bx].flowc,0 ; set no flow control so no sending it
call pntflsh ; flush PRN buffer
call clscp4 ; close packet log
call clscp6 ; close session log
call clscp8 ; close transaction log
mov al,2 ; close WRITE FILE log
call vfclose
clc ; return success
ret
clscp4: push bx ; PACKET LOG
mov bx,ploghnd ; packet log handle
or bx,bx ; is it open?
jle clscp5 ; e = no
call pktdmp ; dump buffer
mov ah,close2
int dos
cmp flags.takflg,0 ; ok to echo?
je clscp5 ; e = no
mov ah,prstr
mov dx,offset clpktlog ; tell what we are doing
int dos
clscp5: mov ploghnd,-1 ; say handle is invalid
pop bx
and flags.capflg,not logpkt ; say this log is closed
ret
clscp6: push bx ; SESSION LOG
mov bx,sloghnd ; session log handle
or bx,bx ; is it open?
jle clscp7 ; e = no
call cptdmp ; dump buffer
mov ah,close2
int dos
cmp flags.takflg,0 ; ok to echo?
je clscp7 ; e = no
mov ah,prstr
mov dx,offset clseslog ; tell what we are doing
int dos
clscp7: mov sloghnd,-1 ; say handle is invalid
pop bx
and flags.capflg,not logses ; say this log is closed
ret
clscp8: push bx ; TRANSACTION LOG
mov bx,tloghnd ; transaction log handle
or bx,bx ; is it open?
jle clscp9 ; e = no
mov ah,close2
int dos
cmp flags.takflg,0 ; ok to echo?
je clscp9 ; e = no
mov ah,prstr
mov dx,offset cltrnlog ; tell what we are doing
int dos
clscp9: mov tloghnd,-1 ; say handle is invalid
pop bx
and flags.capflg,not logtrn ; say this log is closed
ret
clscpt endp
; Print on PRN the char in register al. On success return with C bit clear.
; On failure do procedure pntchk and return its C bit (typically C set).
; Uses buffer dumpbuf (screen dump).
pntchr proc near
push es
push ax
mov ax,data1 ; segment of pntptr and prnbuf
mov es,ax
cmp es:pntptr,offset prnbuf+cptsiz ; buffer full yet?
pop ax
pop es
jb pntchr1 ; b = no
call pntflsh ; flush buffer now
jnc pntchr1 ; nc = success
ret ; c = fail, discard char
pntchr1:push es
push bx
mov bx,data1 ; segment of pntptr and prnbuf
mov es,bx
mov bx,es:pntptr ; pointer to next open slot
mov es:[bx],al ; store the character
inc bx ; update pointer
mov es:pntptr,bx ; save pointer
pop bx
pop es
clc ; clear carry bit
ret
pntchr endp
; Flush printer buffer. Return carry clear if success.
; On failure do procedure pntchk and return its C bit (typically C set).
; Uses buffer dumpbuf (screen dump).
pntflsh proc near
push es
push ax
mov ax,data1 ; segment of pntptr and prnbuf
mov es,ax
cmp es:pntptr,offset prnbuf ; any text in buffer?
pop ax
pop es
ja pntfls1 ; a = yes
clc
ret ; else nothing to do
pntfls1:cmp prnhand,0 ; is printer handle valid?
jg pntfls2 ; g = yes
push es
push ax
mov ax,data1 ; segment of pntptr and prnbuf
mov es,ax
mov es:pntptr,offset prnbuf
pop ax
pop es
clc ; omit printing, quietly
ret
pntfls2:push ax
push bx
push cx
push dx
push si
push di
push es
mov ah,flowoff ; get flow control char
or ah,ah ; flow control active?
jz pntfls3 ; z = no, not using xoff
call outchr ; output xoff (ah), no echo
pntfls3:mov bx,prnhand ; file handle for DOS printer PRN
push DS ; about to change DS
mov dx,data1 ; segment of prnbuf
mov ds,dx ; set DS
mov dx,offset prnbuf ; start of buffer
mov cx,ds:pntptr
sub cx,dx ; cx = current byte count
pntfls4:push cx
push dx
mov cx,1
mov ah,write2
int dos ; write buffer to printer
pop dx
pop cx
jc pntfls5 ; c = call failed
cmp ax,1 ; did we write it?
jne pntfls5 ; ne = no, dos critical error
inc dx ; point to next char
loop pntfls4
mov ds:pntptr,offset prnbuf ; reset buffer pointer
pop DS ; restore DS
clc ; declare success
jmp pntfls11
pntfls5:mov si,dx ; address of next char to be printed
mov di,offset prnbuf ; start of buffer
sub dx,di ; dx now = number successful prints
mov cx,ds:pntptr
sub cx,si ; count of chars to be printed
jle pntfls6
mov ax,ds
mov es,ax
cld
rep movsb ; copy unwritten to start of buffer
pntfls6:sub ds:pntptr,dx ; move back printer pointer by ok's
pop DS ; restore DS
pntfls7:mov dx,offset erms26 ; printer not ready, get user action
call putmod ; write new mode line
call beep ; make a noise
mov ah,0ch ; clear DOS typeahead buffer
mov al,1 ; read from DOS buffer
int dos
or al,al ; Special key?
jnz pntfls8 ; nz = no, consume
mov al,1 ; consume scan code
int dos
jmp short pntfls7 ; try again
pntfls8:and al,not 20h ; lower to upper case quicky
cmp al,'R' ; Retry?
jne pntfls8a ; ne = no
call trnmod ; toggle mode line
call trnmod ; back to same state as before
jmp pntfls3 ; go retry
pntfls8a:cmp al,'D' ; Discard printing?
jne pntfls7 ; ne = no, try again
mov bx,prnhand
cmp bx,4 ; stdin/stdout/stderr/stdaux/stdprn?
jbe pntfls9 ; be = yes, always available
mov ah,close2 ; close this file
int dos
pntfls9:mov bx,offset prnname ; name of printer file
mov word ptr [bx],'UN' ; set to NUL<0>
mov word ptr [bx+2],'L'+0
push es
mov ax,data1 ; seg for pntptr
mov es,ax
mov es:pntptr,offset prnbuf ; reset pointer
pop es
mov prnhand,-1 ; declare handle invalid
ifndef no_terminal
mov anspflg,0 ; mszibm/msyibm print status flag off
endif ; no_terminal
pntfls10:call trnmod ; toggle mode line
call trnmod ; back to same state as before
stc ; declare failure
pntfls11:pushf
mov ah,flowon
or ah,ah ; flow control active?
jz pntfls12 ; z = no, not using xon
call outchr ; output xon (al), no echo
pntfls12:popf
pop es
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret ; nc = success
pntflsh endp
; Check for PRN (DOS's printer) being ready. If ready, return with C clear
; Otherwise, write Not Ready msg on mode line and return with C bit set.
; N.B. DOS Critical Error will occur here if PRN is not ready. [jrd]
pntchk proc near
push dx
push cx
push ax
mov cx,10 ; ten retries before declaring error
cmp prnhand,0 ; printer handle valid?
jle pntchk2 ; le = no, invalid
pntchk0:push bx
mov bx,prnhand ; file handle
mov ah,ioctl ; get printer status, via DOS
mov al,7 ; status for output
int dos
pop bx
jc pntchk1 ; c = call failed
cmp al,0ffh ; code for Ready?
je pntchk3 ; e = yes, assume printer is ready
pntchk1:push cx ; save counter, just in case
mov ax,100 ; wait 100 millisec
call pcwait
pop cx
loop pntchk0 ; and try a few more times
; get here when printer is not ready
pntchk2:pop ax