home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
pcmagazi
/
1992
/
02
/
pcremot2.asm
< prev
next >
Wrap
Assembly Source File
|
1992-01-02
|
122KB
|
3,771 lines
TITLE PCREMOT2 - Unattended Computer Access - 1991 by Terry Lahman
PAGE 78,132
;======================================================================
;
; PCREMOT2 - An unattended computer access utility. Allows access to an
; unattended computer from a manned computer. The unattended computer
; executes the TSR portion of the program and waits for the manned
; computer to call. For use with text only programs. Like using the
; phone lines and modems as a long extension cord for your keyboard
; and monitor.
;
; Usage: PCREMOT2 [ /M ] [ /# ] [ /B# ] [ /D ] [ /S ] [ /N ] [ /U ] [ /? ]
;
; [ /M ] = "Manned" mode (used on remote system)
; [ /# ] = 1 - 4, Communication port used
; [ /B# ] = Baud rate 1=1200, 2=2400, 4=4800, 9=9600
; 19=19200, 3=38400
; [ /D ] = "Desnow" flag (used on CGA monitors)
; [ /S ] = Smiley face displayed (used on host system)
; [ /N ] = Null modem cable connecting 2 systems
; [ /U ] = Uninstall (used on host computer to remove from memory) "
; [ /? ] = Display help screen
;
;======================================================================
CSEG SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:CSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING
BS EQU 8
CR EQU 13
LF EQU 10
SPACE EQU 32
ESC_KEY EQU 1BH
;----------------------------------------------------------------------
; Start of code
;----------------------------------------------------------------------
ORG 100H ;Starting offset for .com
START: JMP INITIALIZE ;Jump over resident code
DW OFFSET CONFIG - $ ;Offset to config parameters
;----------------------------------------------------------------------
; Data storage
;----------------------------------------------------------------------
COPYRIGHT DB "PCREMOT2 Version 1.0 (c) 1989, 1991 Ziff Communications Co."
DB CR,LF," PC Magazine ",254," by Terry Lahman & Kevin Sims"
DB CR,LF,"$",26
CONNECT_FLAG DB 0 ;0=not connected
;1=connected to manned system
ACT_FLAG DB 0 ;0=unattended prog not active
;1=unattended program is active
; do not run again
OLDINT_8 DW 0,0 ;Old timer vector
OLDINT_21 DW 0,0 ;Old DOS vector
OLDINT_COMM DW 0,0 ;Old communications vector
INSTALLED_SEG DW 0 ;Segment of resident program
SET_VEC DW 2500H ;DOS set vector call
SLEEP_FLAG DB 0 ;0=pcremote is awake
;1=pcremote is asleep
;needs to sleep during init.
CURRENT_SPEED DB 0 ;Currently selected speed
SPEED_COUNT DB 0 ;Change speed once a second
COMM_PORT DW 0 ;Comm port address
COMM_INT_STA DB 0 ;Comm port interrupt status
;0=not transmitting data
;1=transmitting data
VIDEO_COPY DW 0 ;Address of video ram copy
VIDEO_SEGMENT DW 0 ;Segment register for vid ram
SHIFT_STATUS DB 0 ;Current status of shift byte
STACK_TOP DW INITIALIZE+256D ;Top of stack for unattended
OLD_SS DW 0 ;Old stack segment
OLD_SP DW 0 ;Old stack pointer
TEMP_REG DW 0 ;Temp storage for register
CURSOR_POSITION DW 0 ;Old cursor position
VID_RAM_OFFSET DW 0 ;Current compare offset
ASCII_FLAG DB 0 ;0=no data is pending
;1=received a FE
;2=received ASCII char
;4=received scan code
SHIFT_FLAG DB 0 ;0=no data is pending
;1=received a FD
KEY_ONE DB 0 ;ASCII char received
KEY_TWO DB 0 ;Scan code received
BAUD_RATE DB 0,60H ;1200 BAUD divisor MSB LSB
DB 0,30H ;2400 BAUD divisor MSB LSB
DB 0,18H ;4800 BAUD divisor MSB LSB
DB 0,0CH ;9600 BAUD divisor MSB LSB
DB 0,06H ;19200 BAUD divisor MSB LSB
DB 0,03H ;38400 BAUD divisor MSB LSB
IN_BUFF_SIZE EQU 256D ;Size for input buffer
OUT_BUFF_SIZE EQU 256D ;Size for output buffer
IN_BUFF_HEAD DW ? ;Pointer to input buffer head
IN_BUFF_TAIL DW ? ;Pointer to input buffer tail
IN_BUFF_BEGIN DW ? ;Pointer to input buffer begin
IN_BUFF_END DW ? ;Pointer to input buffer end
OUT_BUFF_HEAD DW ? ;Pointer to output buffer head
OUT_BUFF_TAIL DW ? ;Pointer to output buffer tail
OUT_BUFF_BEGIN DW ? ;Pointer to output buffer begin
OUT_BUFF_END DW ? ;Pointer to output buffer end
BLOCK_SIZE EQU 16D ;Block transfer size in words
BLOCK_SIZEX2 EQU BLOCK_SIZE*2 ;Block transfer size in bytes
BLOCK_COUNT DB ? ;Block number being processed
BLOCK_POINTER DW 0 ;Points to current video block
TEMP_VIDEO_PTR DW ? ;Pointer to temp video storage
CR_COUNT DB ? ;Number of CRs for speed sync
MODEM_ATTENTION DB CR,"AT",CR,0
MODEM_SETUP1 DB "ATE0 S12=40 Q0 V0 X1 S0=0",CR,0 ;Manned
MODEM_SETUP2 DB "ATE0 S12=40 Q1S0=2",CR,0 ;Unattended
MODEM_SETUP3 DB "AT&C1",CR,0 ;Enable DCD on 2400 baud modem
MODEM_SETUP4 DB "ATW0X4&Q5&K3L0",CR,0 ;for 9600 baud modems
MODEM_HANGUP DB "ATH0",CR,0
MODEM_ESCAPE DB "+++",0
PASS_MESSAGE DB "Enter password:",0 ;Enter password message
PASSWORD_BUFFER DB 20 DUP(?)
BAD_PASSWORD DB ? ;0=No, don't send exit code
;1=Yes, 3 bad, so send code
CONFIG: ;The following parameters must remain in order to support
; the setup program.
MANNED_FLAG DB 0 ;0=Operate in unattended mode
;1=Operate in manned mode
COMM_FLAG DB 0 ;0=Use comm1
;1=Use comm2
;2=Use comm3
;3=Use comm4
COMM_PORT3 DW 03E8H ;Port address for COMM 3
COMM_PORT4 DW 02E8H ;Port address for COMM 4
COMM3_INT DB 4 ;Interrupt for com1 and 3
COMM4_INT DB 3 ;Interrupt for com2 and 4
SPEED_FLAG DB 0 ;0=Use 1200 baud
;1=Use 2400 baud
;2=Use 4800 baud
;3=Use 9600 baud
;4=Use 19200 baud
;5=Use 38400 baud
DESNOW_FLAG DB 0 ;0=Do not use desnow code
;1=Use desnow code
NULL_MODEM DB 0 ;0=Using a modem
;1=Using a null modem cable
SMILE_FLAG DB 0 ;0=Disable corner smile face
;1=Enable corner smile face
CLEAR_CODE DB 0,2EH ; alt-c, clear code
EXIT_CODE DB 0,45D ; alt-x, code to exit program
SHELL_CODE DB 0,1FH ;alt-s, shell to DOS code
TRANSFER_CODE DB 0,20D ;alt-t, file transfer code
PASSWORD_SIZE DW EXTRA_PW_SPACE-PASSWORD
PASSWORD DB "PC MAGAZINE"
EXTRA_PW_SPACE DB 20-(EXTRA_PW_SPACE-PASSWORD) DUP(?)
MODEM_SETUP5 DB 30 DUP(0); ;Extra modem setup string
TONE_DIAL DB "ATDT",0 ;Tone dial command
;======================================================================
; Interrupt handlers. Interrupt 8 is used in unattended mode only.
; The communications interrupt is used in both modes.
;======================================================================
;----------------------------------------------------------------------
; Interrupt 8 handling routine. If program is already active do not run.
; Run connect unattended if not connected, otherwise run unattended.
;----------------------------------------------------------------------
INT8 PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH DS ;Save data segment
PUSH CS ;Set data segment to code seg
POP DS
PUSHF ;Call old int 8
CALL DWORD PTR OLDINT_8
I8_10:
CLI ;Disable interrupts
CMP BYTE PTR SLEEP_FLAG,1 ;If another program has control
JZ I8_EXIT ;then exit
CMP BYTE PTR ACT_FLAG,0 ;Check for program active
JNZ I8_EXIT ;Exit if progam is active
INC BYTE PTR ACT_FLAG ;Set program active flag
STI ;Enable interrupts
CALL SET_STACK ;Create stack & save registers
CMP BYTE PTR CONNECT_FLAG,0 ;Connected to manned?
JNZ I8_20 ;Yes, then run unattended
CALL CONNECT_UNATTENDED ;No, check for connection
JMP I8_30
I8_20:
CALL UNATTENDED ;Run unattended
I8_30:
CALL RESET_STACK ;Restore registers & stack
DEC BYTE PTR ACT_FLAG ;Clear program active flag
I8_EXIT:
STI ;Enable interrupts
POP DS ;Restore data segment
IRET
INT8 ENDP
;----------------------------------------------------------------------
; Interrupt 21 handling routine. If another program, zcopy, changes
; the comm interrupt, go to sleep by setting the sleep flag. When the
; comm interrupt vector returns, WAKE UP!
;----------------------------------------------------------------------
INT21 PROC FAR
PUSHF ;save registers
PUSH AX
PUSH BX
CMP AX,WORD PTR CS:SET_VEC ;setting comm int. vector?
JZ I21_20 ;yes
I21_10:
POP BX ;no, restore registers
POP AX
POPF
JMP DWORD PTR CS:OLDINT_21 ;execute original DOS int
I21_20:
MOV AX,CS ;is new code segment
MOV BX,DS ; the same as pcremote
CMP AX,BX
JNZ I21_30 ;no, then go to sleep
CMP DX,OFFSET CS:INT_COMM ;is it my comm interrupt vec?
JZ I21_40 ;yes, wake up
I21_30:
MOV BYTE PTR CS:SLEEP_FLAG,1 ;I'm getting sleeeeepy
JMP I21_10
I21_40:
POP BX ;restore registers
POP AX
STI ;enable interrupts
CALL DWORD PTR CS:OLDINT_21 ;execute original DOS int vec
CLI ;disable interrupts
CALL CLEAR_VIDEO ;clear the screen
MOV BYTE PTR CS:SLEEP_FLAG,00 ;WAKE UP!
PUSH DX
PUSH AX
PUSH DS ;Save data segment
PUSH CS ;Set data segment to code seg.
POP DS
CALL INIT_SERIAL ;Re-initialize serial port
CALL CLEAR_OUTBUFF ;Clear buffers because ZCOPY
CALL CLEAR_INBUFF ; sent hex 02's to sync systems
POP DS ;Restore the data segment
POP AX ;Restore registers
POP DX
STI ;Enable interrupts
RET 2 ;Return to calling program
INT21 ENDP
;---------------------------------------------------------------------
; Clear the video copy to force a new screen to be tranferred to
; remote system
;---------------------------------------------------------------------
CLEAR_VIDEO:
PUSH CX ;Store necessary registers
PUSH DI
PUSH ES
PUSHF
CLD ;Direction = forward
PUSH CS ;Push CS so ES can now
POP ES ; point at it .. ES->CS
MOV DI,WORD PTR VIDEO_COPY ;ES:DI->Video copy
MOV AX,720H ;AL=SPACE,AH=Normal attribute
MOV CX,2000D ;Clear entire video copy
REP STOSW ;Store char and attribute
MOV CURSOR_POSITION,0FFFFH ;Reset cursor to be updated
POPF ;Restore registers
POP ES
POP DI
POP CX
RET
;----------------------------------------------------------------------
; Interrupt handling routine for communications interrupt. Provides
; interrupt driven I/O. Transmit or receive a character.
;----------------------------------------------------------------------
INT_COMM PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH DS ;Save data segment
PUSH DX ;Save registers
PUSH BX
PUSH AX
PUSH CS ;Set data segment to code seg.
POP DS
MOV DX,COMM_PORT ;Get port base address
INC DX ;Point to int. id reg.
INC DX
IN AL,DX ;Get the interrupt id byte
IC_10:
CMP AL,2 ;Transmit empty int?
JZ IC_40 ;Yes transmit a byte
;
; received data, get it and store in buffer
;
DEC DX ;Port base address
DEC DX
IN AL,DX ;Get data from receive register
MOV BX,IN_BUFF_TAIL ;Get the buffer tail pointer
MOV [BX],AL ;Store the data in buffer
INC BX ;Point to next data storage
CMP IN_BUFF_END,BX ;Beyond end of buffer area?
JNE IC_20 ;No, then don't reset
MOV BX,IN_BUFF_BEGIN ;Yes, reset to buffer begin
IC_20:
CMP BX,IN_BUFF_HEAD ;Test for buffer full
JE IC_30 ;If so,don't change ptr ,sorry
MOV IN_BUFF_TAIL,BX ;Save new tail pointer
IC_30:
JMP IC_70
;
; transmit buffer empty, send a byte
;
IC_40:
DEC DX ;Port base address
DEC DX
MOV BX,OUT_BUFF_HEAD ;Get the buffer head pointer
CMP BX,OUT_BUFF_TAIL ;Test for data in buffer
JE IC_60 ;If the same, no data so exit
MOV AL,[BX] ;Get the data
INC BX ;Point to next data in buffer
CMP OUT_BUFF_END,BX ;Beyond end of buffer area?
JNE IC_50 ;No, then don't reset
MOV BX,OUT_BUFF_BEGIN ;Yes, reset to buffer begin
IC_50:
MOV OUT_BUFF_HEAD,BX ;Save new head pointer
OUT DX,AL ;Send the data out the port
JMP IC_70 ;Check for request pending
IC_60:
MOV BYTE PTR COMM_INT_STA,0 ;Reset transmitting data flag
IC_70:
INC DX ;Point to int. id reg.
INC DX
IN AL,DX ;Get the interrupt id byte
TEST AL,1 ;Request pending?
JZ IC_10 ;Yes, then process
IC_EXIT:
MOV AL,20H ;Reset 8259
OUT 20H,AL
STI ;Enable interrupts
POP AX ;Restore registers
POP BX
POP DX
POP DS ;Restore data segment
IRET
INT_COMM ENDP
;----------------------------------------------------------------------
; Create stack area and save all registers.
;----------------------------------------------------------------------
SET_STACK PROC NEAR
ASSUME CS:CSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING
MOV TEMP_REG,BX ;Save BX
POP BX ;Save the return address
PUSH AX ;Save AX
;
; make my own stack
;
CLI ;Disable interrupts
MOV AX,SS ;Put old stack segment in AX
MOV OLD_SS,AX ;And save it
MOV AX,SP ;Put old stack pointer in AX
MOV OLD_SP,AX ;And save it
MOV AX,CS ;Get current segment
MOV SS,AX ;And put into stack segment
MOV AX,STACK_TOP ;Get top of stack address
MOV SP,AX ;And put into stack pointer
STI ;Enable interrupts
;
; save all the registers on the stack
;
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH DS
PUSH ES
PUSH BP
MOV AX,CS ;Get code segment
MOV DS,AX ;Set data segment to code seg
MOV ES,AX ;Set extra seg to code seg
PUSH BX ;Restore return address
RET
SET_STACK ENDP
;----------------------------------------------------------------------
; Restore all registers and reset stack
;----------------------------------------------------------------------
RESET_STACK PROC NEAR
ASSUME CS:CSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING
POP BX ;Save return address
;
; restore the registers
;
POP BP ;Restore the registers
POP ES
POP DS
POP DI
POP SI
POP DX
POP CX
;
; restore the original stack
;
CLI ;Disable interrupts
MOV AX,OLD_SP ;Get old stack pointer
MOV SP,AX ;And restore it
MOV AX,OLD_SS ;Get old stack segment
MOV SS,AX ;And restore it
STI ;Enable interrupts
POP AX ;Restore AX
PUSH BX ;Put return add back on stack
MOV BX,TEMP_REG ;Restore BX
RET
RESET_STACK ENDP
;======================================================================
; The unattended routine will execute the connect routine to establish
; a connection with the manned system. Once connected it will execute
; the unattended routine to process incoming data and send any changed
; video data to the manned system.
;======================================================================
;----------------------------------------------------------------------
; CONNECT_UNATTENDED - Check for ring codes, answer the phone and check
; the password. If correct, set connected flag.
;----------------------------------------------------------------------
CONNECT_UNATTENDED PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:CSEG,SS:NOTHING
MOV BP,SP ;Save stack pointer for exit
XOR AH,AH ;Use input buffer
MOV CX,10D ;Number of char to check for CR
MOV BYTE PTR CR_COUNT,5 ;Number of matches required
CU_10:
CALL GET_BUFF_DATA ;Try to get data from buffer
JC CU_20 ;If data, check for CR code
JMP CU_40 ;else exit, try another speed
CU_20:
CMP AL,CR ;Check for CR code
JNZ CU_30 ;No so skip over
MOV BYTE PTR SPEED_COUNT,19 ;it's a CR, so speed is correct
DEC BYTE PTR CR_COUNT ;Found a match dec count
JZ CU_70 ;5 out of ten then null connect
CU_30:
LOOP CU_10 ;Keep trying
CU_40:
DEC BYTE PTR SPEED_COUNT
JZ CU_50
JMP CU_EXIT
CU_50:
DEC BYTE PTR CURRENT_SPEED ;Try a slower speed
CMP BYTE PTR CURRENT_SPEED,0FFH ;Out of speeds?
JNZ CU_60 ;No
MOV AL,BYTE PTR SPEED_FLAG ;Ran out of speeds, reset
MOV BYTE PTR CURRENT_SPEED,AL ; to starting speed
CU_60:
MOV BYTE PTR SPEED_COUNT,19 ;reset tick counter
MOV AL,BYTE PTR CURRENT_SPEED ;set the slower speed
CALL SET_BAUD_RATE
CALL CLEAR_INBUFF ;Empty the input buffer
JMP CU_EXIT ;No 5 out of 10, exit
CU_70:
MOV BYTE PTR CONNECT_FLAG,1 ;Set connect flag
MOV CX,3 ;3 tries to enter password
CU_80:
MOV SI,OFFSET PASS_MESSAGE ;Point to enter password mess.
CALL LOAD_ZSTRING ;Load it into output buffer
CALL GET_PASSWORD ;Get the password
CALL CHECK_PASSWORD ;Check the password sent
JZ CU_90 ;Jump if correct
LOOP CU_80 ;Keep trying
MOV AL,1 ;Use set up string 2
MOV BYTE PTR BAD_PASSWORD,1D ;Send exit code
CALL RESET_MODEM ;Hangup and reset modem
JMP CU_EXIT ;Done, so exit
CU_90:
MOV AH,1 ;Use output buffer
XOR AL,AL ;Sync byte to send
MOV CX,5 ;Send 5 of them
CU_100:
CALL PUT_BUFF_DATA ;Send them
LOOP CU_100
;
; Notify remote computer the value of host's COMM_FLAG switch. This allows
; the remote computer to properly send the ZCOPY command line to the host.
;
MOV AH,1 ;Use output buffer
MOV AL,BYTE PTR COMM_FLAG ;Send host's comm port
INC AL ;Bump AL so sent byte will be
; in range from 1 thru 4.
MOV CX,10D ;Send 10 of them
CU_110:
CALL PUT_BUFF_DATA ;Send Host Comm Port
LOOP CU_110 ;Sent 10 ?
XOR AL,AL ;Sync byte to send
MOV CX,5D ;Send 5 of them
CU_120:
CALL PUT_BUFF_DATA ;Send sync byte
LOOP CU_120 ;Sent 5 ?
CU_EXIT:
RET
CONNECT_UNATTENDED ENDP
;----------------------------------------------------------------------
; Get the password from the manned system
; Input - Nothing
; Output - Password buffer contains password from manned system
; Changes - DI, AX
;----------------------------------------------------------------------
GET_PASSWORD PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:CSEG,SS:NOTHING
PUSH CX ;Save register
MOV DI,OFFSET PASSWORD_BUFFER ;Point to password buffer
MOV CX,20D ;Zero buffer to clear previous
XOR AL,AL ; password
CLD
REP STOSB
MOV DI,OFFSET PASSWORD_BUFFER ;Pointer to buffer
MOV CX,20D ;Maximum password size
GP_10:
CALL CHECK_CARRIER ;Check for carrier loss
JNZ GP_20
JMP IP_90 ;Carrier loss, reset and exit
GP_20:
CALL INPUT_PROCESSING ;Get data & put in keybd buffer
CALL GET_KEYSTROKE ;Check for keystroke
JZ GP_10 ;None, so wait
CMP AL,60H ;Check for lower case
JL GP_30 ;No then leave it alone
AND AL,5FH ;Convert to upper case
GP_30:
CMP AL,CR ;If it is a CR then exit
JZ GP_EXIT
CMP AL,BS ;Is it a back space?
JNZ GP_40 ;No, so save it
INC CX ;Resetcounter for BS
CMP DI,OFFSET PASSWORD_BUFFER ;Already at start of buffer?
JZ GP_60 ;Yes, then don't backspace
DEC DI ;Backspace buffer pointer
MOV BYTE PTR [DI],0 ; and null the data
JMP GP_50
GP_40:
CLD ;Forward
STOSB ;Save the character
MOV AL,'*' ;Echo character
GP_50:
MOV AH,1 ;Use output buffer
CALL PUT_BUFF_DATA ; and store the character
GP_60:
LOOP GP_10 ;Receive up to CX characters
GP_EXIT:
POP CX ;Restore register
RET
GET_PASSWORD ENDP
;----------------------------------------------------------------------
; Check the password in the buffer with correct password
; Input - Nothing
; Output - Zero set - correct password
; Zero reset - Wrong password
; Changes - SI, DI
;----------------------------------------------------------------------
CHECK_PASSWORD PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:CSEG,SS:NOTHING
PUSH CX ;Save register
MOV SI,OFFSET PASSWORD_BUFFER ;Pointer to buffer
MOV DI,OFFSET PASSWORD ;Pointer to password
MOV CX,PASSWORD_SIZE ;Number of compares to make
CLD ;Compare forward
REPZ CMPSB ;Repeat while passwords match
POP CX ;Restore register
RET
CHECK_PASSWORD ENDP
;----------------------------------------------------------------------
; UNATTENDED - Process incoming data and check for changes in video
; data, format and send to manned system. Maintains 18 or less characters
; in output buffer, ensures maximum throughput.
;----------------------------------------------------------------------
UNATTENDED PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:CSEG,SS:NOTHING
MOV BP,SP ;Save stack pointer for exit
CALL INPUT_PROCESSING ;Process any buffered data
;
; Check for a change in the cursor position
;
PUSH ES
MOV AX,40H ;Set ES to BIOS data segment
MOV ES,AX
MOV BX,ES:[50H] ;Get current cursor position
CMP BX,CURSOR_POSITION ;Compare with copy
JZ UA_10 ;No change, skip
MOV CURSOR_POSITION,BX ;Save new cursor position
MOV AL,0D2H ;Sync bits, set position
MOV AH,1 ;Use output buffer
CALL PUT_BUFF_DATA ;Send sync byte
MOV AL,BL ;Low byte
CALL PUT_BUFF_DATA
MOV AL,BH ;High byte
CALL PUT_BUFF_DATA
UA_10:
POP ES ;Restore ES
CMP BYTE PTR SMILE_FLAG,0 ;Smile face enabled ?
JE UA_20 ;No, skip smile face coding
;
; Redisplay the smile face in upper right corner
;
PUSH ES ;Store ES
MOV AX,VIDEO_SEGMENT ;AX = Video Segment
MOV ES,AX ;ES = Video Segment
MOV DI,158D ;DI-> Upper right corner
MOV AL,01H ;Smiley Face code
CALL PUT_VIDEO_DATA ;Write Video RAM
POP ES ;Restore ES
UA_20:
MOV VID_RAM_OFFSET,0 ;Start at address 0
MOV BYTE PTR BLOCK_COUNT,0 ;Reset block counter
;
; Check the output buffer and keep it full enough so it's busy till
; next timer tick.
;
UA_30:
MOV AX,7 ;1200 baud, at least 7 bytes
MOV CL,BYTE PTR CURRENT_SPEED ;the speed decides the size
SHL AX,CL ;larger for faster baud
MOV CX,AX ;at least this many bytes
CLI
MOV AX,OUT_BUFF_HEAD ;Get the head pointer
MOV BX,OUT_BUFF_TAIL ;Get the tail pointer
STI
UA_40:
CMP AX,BX ;Less than bytes in buffer
JZ UA_60 ;Yes, check the video data
INC AX ;Increment head pointer
CMP OUT_BUFF_END,AX ;Beyond end of buffer area?
JNE UA_50 ;No, then don't reset
MOV AX,OUT_BUFF_BEGIN ;Yes, reset to buffer begin
UA_50:
LOOP UA_40 ;Check all the bytes
JMP UA_EXIT ;More than allowed, exit
;
; compare the video copy with the video ram
;
UA_60:
PUSH DS ;Save data segment
MOV SI,VID_RAM_OFFSET ;Get the current offset
MOV DI,TEMP_VIDEO_PTR ;Dest. ES:DI temp video buffer
MOV AX,VIDEO_SEGMENT ;Get video Segment register
MOV DS,AX ;Source DS:SI video RAM
;
; transfer block_size words of data from video RAM to the temp buffer
;
MOV CX,BLOCK_SIZE ;Get count of words to transfer
CLD
CMP BYTE PTR CS:DESNOW_FLAG,0 ;Check desnow flag
JZ UA_90
SAL CX,1 ;Convert words to bytes
MOV DX,3DAH ;CGA status port
UA_70:
IN AL,DX ;Get status byte
TEST AL,1 ;Test display enable
JNZ UA_70 ;If in Hor. sync then wait
CLI ;Disable interrupts
UA_80:
IN AL,DX ;Get status byte
TEST AL,1 ;Test display enable
JZ UA_80 ;Wait for Hor. sync
MOVSB ;Transfer one byte
STI ;Enable interrupts
LOOP UA_70 ;Transfer block size words
JMP UA_100
UA_90:
REP MOVSW
UA_100:
POP DS ;Restore data segment
;
; compare the block from video RAM with the video copy
;
MOV CX,BLOCK_SIZEX2 ;Number of words to compare
MOV SI,TEMP_VIDEO_PTR ;Point to block of video data
MOV DI,VIDEO_COPY ;Point to video copy
ADD DI,VID_RAM_OFFSET ;Adjust for current block
REPE CMPSB ;Compare while equal
JNE UA_110 ;No match, format & send block
MOV AX,VID_RAM_OFFSET ;Get current block pointer
ADD AX,BLOCK_SIZEX2 ;Point to next block
MOV VID_RAM_OFFSET,AX ;And save the pointer
INC BYTE PTR BLOCK_COUNT ;Increment current block count
CMP AX,4000D ;Check for end of video RAM
JNZ UA_60 ;No, keep checking the RAM
JMP UA_EXIT ;then exit
;
; data doesn't match, format and send to manned system
;
UA_110:
INC CX ;Adjust count
AND CX,1 ;LSB indicates char or attr.
CALL TRANSFER_BLOCK ;Prepare to send block of data
JMP UA_30 ;Again, till buffer is full
UA_EXIT:
RET
UNATTENDED ENDP
;----------------------------------------------------------------------
; Get data from the unattended input buffer and process
; Input - Nothing
; Output - Keyboard buffer or shift status is updated
; Changes - Nothing
;----------------------------------------------------------------------
INPUT_PROCESSING PROC NEAR
PUSH AX ;Save register
PUSH DX
PUSH ES
MOV AX,40H ;Set ES to BIOS data area
MOV ES,AX
IP_10:
CMP BYTE PTR CONNECT_FLAG,0 ;Are we connected
JZ IP_20 ;No, don't check carrier
CALL CHECK_CARRIER ;Yes check for carrier loss
JZ IP_90 ;Carrier loss, reset and exit
;
; make sure there is room in the keyboard buffer for a keystroke
;
IP_20:
CLI ;Don't allow interrupts
MOV AX,ES:[1CH] ;Get the buffer tail pointer
INC AX ;Point to next data storage
INC AX
CMP AX,3EH ;Beyond end of buffer area?
JNE IP_30 ;No, then don't reset
MOV AX,1EH ;Yes, reset to buffer begin
IP_30:
CMP AX,ES:[1AH] ;Test for buffer full
JE IP_40 ;If the same, don't process key
STI
JMP IP_50 ;Process incoming keystrokes
IP_40:
STI ;Enable interrupts
JMP IP_EXIT ;Exit the routine
IP_50:
MOV AH,0 ;Use input buffer
CALL GET_BUFF_DATA ;Get a byte of data
JC IP_60 ;If data then process
JMP IP_EXIT ;Otherwise exit
;
; Check to see if expecting ASCII data
;
IP_60:
CMP ASCII_FLAG,0 ;Check ASCII flag
JNZ IP_70 ;
JMP IP_120 ; 0=not expecting data here
IP_70:
CMP ASCII_FLAG,1 ;Check for received 1st byte
JNZ IP_80 ;Jump if second byte
MOV KEY_ONE,AL ;Save scan code, byte one
INC BYTE PTR ASCII_FLAG ;Indicate receiving one byte
JMP IP_10 ;Process next byte
IP_80:
MOV KEY_TWO,AL ;Save ASCII code, byte two
MOV AL,KEY_ONE ;Get ASCII code
MOV AH,KEY_TWO ;Get scan code
CMP AX,WORD PTR EXIT_CODE ;Check for exit code
JNZ IP_100 ;No,then continue processing
IP_90: ;Otherwise reset connect & exit
CMP BYTE PTR SMILE_FLAG,0 ;Smile flag set ?
JE IP_95 ;No, skip resetting smile face
PUSH AX ;Store AX
PUSH ES ;Store ES
PUSH DI ;Store DI
MOV AX,VIDEO_SEGMENT ;AX = VIDEO_SEGMENT
MOV ES,AX ;ES = VIDEO_SEGMENT
MOV DI,158D ;Bump DI 79 chars
MOV AL,SPACE ;Blank space
CALL PUT_VIDEO_DATA ;Write Video RAM
POP DI ;Restore DI
POP ES ;Restore ES
POP AX ;Restore AX
IP_95:
CALL CLEAR_INBUFF ;Clear input buffer
CALL CLEAR_OUTBUFF ;Clear output buffer
MOV BYTE PTR COMM_INT_STA,0 ;Reset transmitting data flag
CALL IU_10 ;reinit and reset modem
CLI ;Disable interrupts
MOV BYTE PTR CONNECT_FLAG,0 ;Reset the connect flag
MOV BYTE PTR ASCII_FLAG,0 ;Reset ASCII flag
MOV BYTE PTR SHIFT_FLAG,0 ;Reset shift flag
MOV BYTE PTR ES:[17H],0 ;Reset any shift status
MOV SP,BP ;Clean the stack
RET ;And exit unattended routine
IP_100:
CMP AX,WORD PTR CLEAR_CODE ;Clear code received
JNZ IP_110 ;No... skip clear code coding
CALL CLEAR_VIDEO ;Rewrite screen
MOV BYTE PTR ASCII_FLAG,0 ;Reset ASCII flag
JMP IP_10 ;Get next character
IP_110: ;
CALL PUT_KEY_DATA ;And stuff in keyboard buffer
MOV BYTE PTR ASCII_FLAG,0 ;Reset ASCII flag for next data
JMP IP_10 ;Process next byte
;
; Check to see if expecting shift data
;
IP_120:
CMP BYTE PTR SHIFT_FLAG,0 ;Check shift flag
JZ IP_130 ;0=not expecting data here
MOV ES:[17H],AL ;And save in shift status
MOV BYTE PTR SHIFT_FLAG,0 ;Reset shift flag for next data
JMP IP_10 ;Process next byte
;
; Check to see if it's a sync byte
;
IP_130:
CMP AL,0FEH ;Check for ASCII sync byte
JNZ IP_140 ;If not then check for shift
INC BYTE PTR ASCII_FLAG ;Indicate received FEh
JMP IP_10 ;Process next byte
IP_140:
CMP AL,0FDH ;Check for shift sync byte
JNZ IP_150 ;If not then throw away
INC BYTE PTR SHIFT_FLAG ;Indicate received FDh
IP_150:
JMP IP_10 ;Process till buffer empty
IP_EXIT:
POP ES ;Restore registers
POP DX
POP AX
RET
INPUT_PROCESSING ENDP
;----------------------------------------------------------------------
; Formats the data in temporary video buffer and puts it into the
; output buffer
; Input - CX=0 Transfer character data to output buffer
; CX=1 Transfer attribute data to output buffer
; Output - Nothing
; Changes - AX, BX, CX, SI, DI
;----------------------------------------------------------------------
TRANSFER_BLOCK PROC NEAR
PUSH CX ;Save the data type
;
; If the data is all the same only send it once, and set the repeat flag
;
MOV SI,TEMP_VIDEO_PTR ;Point
ADD SI,CX ;Adjust for char. or attr.
XOR BL,BL ;Initialize for non-repeating
MOV CX,BLOCK_SIZE ;Number of bytes to compare
MOV AH,[SI] ;Get the first byte in block
TB_10:
LODSB ;Get next byte from the block
INC SI ;Adjust for word
CMP AH,AL ;Verify all the same
LOOPZ TB_10 ;For the entire block
JNZ TB_20 ;Not the same, send block
MOV BL,2 ;set repeat flag
TB_20:
POP CX ;Restore data type
MOV AL,0FCH ;Start with base sync byte
OR AL,CL ;Include data type bit
OR AL,BL ;Include repeat bit
MOV AH,1 ;Use output buffer
CALL PUT_BUFF_DATA ;Put sync byte in output buff.
MOV AL,BLOCK_COUNT
MOV AH,1 ;Use output buffer
CALL PUT_BUFF_DATA ;Send the block number
MOV SI,TEMP_VIDEO_PTR ;Point to block of video data
ADD SI,CX ;Adjust for char. or attr.
MOV DI,VIDEO_COPY ;Point to video copy
ADD DI,VID_RAM_OFFSET ;Adjust for block offset
ADD DI,CX ; and character or attribute
MOV CX,BLOCK_SIZE ;Number of bytes to send
CLD ;Forward direction
TB_30:
LODSW ;Get the unmatched data
OR BL,BL ;Check the repeat flag
JNZ TB_40 ;Don't send repeat data
MOV AH,1 ;Use the output buffer
CALL PUT_BUFF_DATA ;Put the video data in out buff
TB_40:
STOSB ;Save video data in copy
INC DI ;Adjust for word offset
LOOP TB_30 ;Send block size bytes of data
OR BL,BL ;If repeat data then send one
JZ TB_50
MOV AH,1
CALL PUT_BUFF_DATA
TB_50:
RET
TRANSFER_BLOCK ENDP
;----------------------------------------------------------------------
; Put a byte of data into the unattended keyboard buffer.
; Input - AL contains ASCII to be put into buffer.
; AH contains scan code to be put into buffer.
; Output - Carry Set - Byte placed in buffer successfully
; Carry Reset - Buffer full, byte not stored in buffer
; Changes - Nothing
;----------------------------------------------------------------------
PUT_KEY_DATA PROC NEAR
PUSH BX ;Save registers
PUSH SI
PUSH DI
MOV SI,1AH ;Point to keyboard head pointer
CLI ;Don't allow interrupts
MOV BX,ES:[1CH] ;Get the buffer tail pointer
MOV DI,BX ;Save the tail pointer
INC BX ;Point to next data storage
INC BX
CMP BX,3EH ;Beyond end of buffer area?
JNE PK_10 ;No, then don't reset
MOV BX,1EH ;Yes, reset to buffer begin
PK_10:
CMP BX,ES:[1AH] ;Test for buffer full
JE PK_EXIT ;If the same, don't save it
; exit, carry is already reset
MOV ES:[DI],AX ;Store the data in buffer
MOV ES:[1CH],BX ;Save new tail pointer
STC ;Indicate data stored OK
PK_EXIT:
POP DI
POP SI
POP BX
STI ;Enable interrupts
RET
PUT_KEY_DATA ENDP
;======================================================================
; COMMON ROUTINES - These routines are common to both the unattended
; processing portion of the program and the manned processing portion.
;======================================================================
;----------------------------------------------------------------------
; Store the video data in AL in the memory location pointed to by DI
; INPUT - AL video data, ES:DI video RAM destination
; OUTPUT - Nothing
; Changes - DI is incremented
;----------------------------------------------------------------------
PUT_VIDEO_DATA PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
;
; Check desnow flag, if set wait for horizontal sync to put in video RAM
;
PUSH BX ; Save Registers
PUSH DX
CMP BYTE PTR DESNOW_FLAG,0 ; Check Desnow flag
JZ PV_30 ; No, skip over
CLD ; Forward
XCHG AX,BX ; Save video data
MOV DX,3DAH ; CGA status port
PV_10:
IN AL,DX ; Get status byte
TEST AL,1 ; Test display enable
JNZ PV_10 ; If in Hor. sync, wait
PV_20:
IN AL,DX ; Get status byte
TEST AL,1 ; Test display enable
JZ PV_20 ; Wait for Hor. sync
XCHG AX,BX ; Get video data
PV_30:
STOSB ; Put into video RAM
POP DX ; Restore registers
POP BX
RET
PUT_VIDEO_DATA ENDP
;----------------------------------------------------------------------
; Get a byte of data from a buffer. Byte pointed to by head pointer is
; is next data byte. If head=tail, no data in buffer.
; Input - AH - Buffer to use 0=Input buffer, 1=Output buffer.
; Output - Carry Set - Byte from buffer is in AL
; Carry Reset - No data in buffer
; Changes - AL
;----------------------------------------------------------------------
GET_BUFF_DATA PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH BX ;Save registers
PUSH SI
CMP AH,0 ;Check which buffer to use
JNZ GD_10 ;Jump for output buffer
MOV SI,OFFSET IN_BUFF_HEAD ;Point to input buffer
JMP GD_20 ;Skip over out buffer
GD_10:
MOV SI,OFFSET OUT_BUFF_HEAD ;Point to output buffer
GD_20:
CLI ;Don't allow interrupts
MOV BX,[SI] ;Get the buffer head pointer
CMP BX,2[SI] ;Test for data in buffer
JE GD_EXIT ;If the same, no data so
; exit, carry is already reset
MOV AL,[BX] ;Get the data
INC BX ;Point to data in buffer
CMP 6[SI],BX ;Beyond end of buffer area?
JNE GD_30 ;No, then don't reset
MOV BX,4[SI] ;Yes, reset to buffer begin
GD_30:
MOV [SI],BX ;Save new head pointer
STC ;Indicate data is in AL
GD_EXIT:
POP SI ;Restore registers
POP BX
STI ;Enable interrupts
RET
GET_BUFF_DATA ENDP
;----------------------------------------------------------------------
; Put a byte of data into a buffer. Byte is stored at location
; pointed to by tail pointer.
; Input - AL contains data to be put into buffer.
; AH - Buffer to use 0=Input buffer, 1=Output buffer
; Output - Carry Set - byte placed in buffer successfully
; Carry Reset - Buffer full, byte not stored in buffer
; Changes - Nothing
;----------------------------------------------------------------------
PUT_BUFF_DATA PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH AX ;Save registers
PUSH BX
PUSH DX
PUSH SI
PUSH DI
PUSH DS
PUSH CS ;Set data segment to CS
POP DS
CMP AH,0 ;Check which buffer to use
JNZ PD_10 ;Jump for output buffer
MOV SI,OFFSET IN_BUFF_HEAD ;Point to input buffer
JMP PD_20 ;Skip over out buffer
PD_10:
MOV SI,OFFSET OUT_BUFF_HEAD ;Point to output buffer
PD_20:
CLI ;Don't allow interrupts
MOV BX,2[SI] ;Get the buffer tail pointer
MOV DI,BX ;Save the tail pointer
INC BX ;Point to next data storage
CMP 6[SI],BX ;Beyond end of buffer area?
JNE PD_30 ;No, then don't reset
MOV BX,4[SI] ;Yes, reset to buffer begin
PD_30:
CMP BX,[SI] ;Test for buffer full
JE PD_40 ;If so, exit carry is reset
MOV [DI],AL ;Store the data in buffer
MOV 2[SI],BX ;Save new tail pointer
STC ;Indicate data stored ok
PD_40:
PUSHF ;Save the flags
CMP BYTE PTR COMM_INT_STA,0 ;Transmit int. running?
JNZ PD_60 ;Yes, so exit
MOV AX,OUT_BUFF_HEAD ;Is data in output buffer
CMP AX,OUT_BUFF_TAIL
JZ PD_60 ;No, so exit
MOV BYTE PTR COMM_INT_STA,1 ;Set transmitting data flag
MOV DX,COMM_PORT ;Get port base address
ADD DX,5 ;Line status register
PD_50:
IN AL,DX ;Make sure holding reg. empty
TEST AL,00100000B ;Test the hold reg empty flag
JZ PD_50 ;Loop if not empty
SUB DX,5 ;Port base register
MOV AH,1 ;Use the output buffer
CALL GET_BUFF_DATA ;Get data from output buffer
OUT DX,AL ;Send the data out the port
PD_60:
STI ;Enable interrupts
POPF ;Restore flags
POP DS ;Restore registers
POP DI
POP SI
POP DX
POP BX
POP AX
RET
PUT_BUFF_DATA ENDP
;----------------------------------------------------------------------
; Clear the input buffer
; Input - Nothing
; Output - Nothing
; Changes - Nothing
;----------------------------------------------------------------------
CLEAR_INBUFF PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH AX ;Save register
CLI ;Disable interrupts
MOV AX,IN_BUFF_TAIL ;Get buffer tail pointer
MOV IN_BUFF_HEAD,AX ;Make head equal tail
STI ;Enable interrupts
POP AX
RET
CLEAR_INBUFF ENDP
;----------------------------------------------------------------------
; Clear the output buffer
; Input - Nothing
; Output - Nothing
; Changes - Nothing
;----------------------------------------------------------------------
CLEAR_OUTBUFF PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH AX ;Save register
CLI ;Disable interrupts
MOV AX,OUT_BUFF_TAIL ;Get buffer tail pointer
MOV OUT_BUFF_HEAD,AX ;Make head equal tail
STI ;Enable interrupts
POP AX
RET
CLEAR_OUTBUFF ENDP
;----------------------------------------------------------------------
; Reset the modem and send the setup string to initialize
; Input - AL - 0 use setup string 1, 1 use setup string 2
; Output - Nothing
; Changes - Nothing
;----------------------------------------------------------------------
RESET_MODEM PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
CMP BYTE PTR NULL_MODEM,0 ;If null modem don't reset
JZ RM_10
MOV BYTE PTR CONNECT_FLAG,0 ;Reset connect flag
;
; After resetting connect flag, see if unattended and three bad passwords
; received, if so send an exit code to the remote computer so that the
; remote computer can exit to DOS.
;
CMP BYTE PTR MANNED_FLAG,0 ;If host, then send exit code
JNE RM_5 ; to remote system to exit
CMP BYTE PTR BAD_PASSWORD,0 ;Three bad passwords ?
JE RM_5 ;No, skip sending exit code
CALL CLEAR_OUTBUFF ;Clear out buff to insure room
MOV AX,WORD PTR EXIT_CODE ;Set up AL and AH to send
MOV AL,AH ; the exit code thru out buff.
MOV AH,1 ;Use output buffer
CALL PUT_BUFF_DATA ;Send char (exit_code)
RM_5: ;
JMP RM_EXIT ;and return to caller
RM_10:
PUSH SI ;Save registers
PUSH DX
PUSH AX
CMP BYTE PTR CONNECT_FLAG,0 ;Is modem connected?
JZ RM_20 ;No then send setup only
CALL CLEAR_OUTBUFF ;Empty the output buffer
MOV BYTE PTR CONNECT_FLAG,0 ;Reset connect flag
MOV AL,1 ;Wait a second for guard time
CALL DELAY
MOV SI,OFFSET MODEM_ESCAPE ;Send modem escape code
CALL LOAD_ZSTRING
MOV AL,2 ;Wait
CALL DELAY
MOV SI,OFFSET MODEM_HANGUP ;Send modem hangup code
CALL LOAD_ZSTRING
MOV AL,1 ;Wait for a second
CALL DELAY
RM_20:
MOV AL,SPEED_FLAG ;Get speed flag
MOV BYTE PTR CURRENT_SPEED,AL ;Save as next starting speed
CALL SET_BAUD_RATE
MOV BYTE PTR SPEED_COUNT,19
MOV SI,OFFSET MODEM_ATTENTION ;Point to modem attention
CALL LOAD_ZSTRING ;Put it into output buffer
MOV AL,1 ;Wait for a second
CALL DELAY
POP AX ;Get setup string to use
CMP AL,0 ;Test for string 1
JNZ RM_30 ;No, then use string 2
MOV SI,OFFSET MODEM_SETUP1 ;Point to modem setup string 1
JMP RM_40
RM_30:
MOV SI,OFFSET MODEM_SETUP2 ;Point to modem setup string 2
RM_40:
CALL LOAD_ZSTRING ;Load setup string to modem
MOV AL,1 ;Wait a second
CALL DELAY
MOV SI,OFFSET MODEM_SETUP3 ;Point to modem setup string 3
CALL LOAD_ZSTRING ;Load setup string to modem
CMP BYTE PTR SPEED_FLAG,2 ;If speed is 1200 or 2400
JL RM_50 ; skip setup string 4
MOV AL,1 ;Wait a second
CALL DELAY
MOV SI,OFFSET MODEM_SETUP4 ;Point to modem setup string 4
CALL LOAD_ZSTRING ;Load setup string to modem
RM_50:
MOV AL,1 ;Wait a second
CALL DELAY
MOV SI,OFFSET MODEM_SETUP5 ;Point to custom setup string 5
CALL LOAD_ZSTRING ;Load setup string to modem
CALL CLEAR_INBUFF ;Clear the input buffer
POP DX ;Restore registers
POP SI
RM_EXIT:
RET
RESET_MODEM ENDP
;----------------------------------------------------------------------
; Check carrier reads the carrier status signal and sets Z flag to
; indicate status
; Input - Nothing
; Output - Zero flag 0 - Carrier
; Zero flag 1 - No Carrier detected
; Changes - Nothing
;----------------------------------------------------------------------
CHECK_CARRIER PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH AX ;Save registers
CMP BYTE PTR NULL_MODEM,0 ;If null modem don't reset
JZ CC_10
CMP BYTE PTR CONNECT_FLAG,0 ;
JZ CC_EXIT ;not connected, send no carrier
MOV AH,1 ;reset zero flag
CMP AH,0
JMP CC_EXIT ;and return to caller
CC_10:
PUSH DX
MOV DX,COMM_PORT ;Get the comm base address
ADD DX,6 ;Modem status register
IN AL,DX ;Get the current status
TEST AL,10000000B ;Data carrier detect
POP DX ;Restore registers
CC_EXIT:
POP AX
RET
CHECK_CARRIER ENDP
;----------------------------------------------------------------------
; DELAY - delay approximate number of seconds in AL
; Input - AL
; Output - Nothing (just waits till AL is zero)
; Changes - Nothing
;----------------------------------------------------------------------
DELAY PROC NEAR
PUSH CX ;Save registers
PUSH DX
PUSH DI
PUSH AX
XOR AH,AH ;Read system time
INT 1AH
STI ;Enable interrupts Ver 1.1
MOV DI,DX ;Save low tick count
MOV SI,CX ;Save high tick count
POP AX ;Get number of seconds to delay
PUSH AX
XOR CX,CX ;Zero CX
MOV CL,AL ;Put seconds into loop counter
D_10:
ADD DI,19D ;Approximate counts in a second
ADC SI,0 ;Add carry to SI
LOOP D_10
D_20:
XOR AH,AH ;Read system time
INT 1AH
STI ;Enable interrupts Ver 1.1
CMP SI,CX
JNE D_20
CMP DI,DX ;End of delay time
JGE D_20 ;No, keep checking
POP AX ;Restore registers
POP DI
POP DX
POP CX
RET
DELAY ENDP
;----------------------------------------------------------------------
; String at SI is placed in output buffer to be sent out serial port
; Input - SI points to zero terminated string
; Output - Nothing
; Changes - SI
;----------------------------------------------------------------------
LOAD_ZSTRING PROC NEAR
PUSH AX ;Save register
MOV AH,1 ;Use output buffer
CLD ;Forward
LZ_10:
LODSB ;Get a byte of data
CMP AL,0 ;Check for zero
JZ LZ_EXIT ;Yes, then exit
CALL PUT_BUFF_DATA ;No, put in output buffer
JMP LZ_10 ;Process next data
LZ_EXIT:
POP AX ;Restore register
RET
LOAD_ZSTRING ENDP
;----------------------------------------------------------------------
; Check for a key in the keyboard buffer, if one is there, get it
; Input - Nothing
; Output - Zero flag = 1 no key in buffer
; Zero flag = 0 key is in AX
; Changes - AX
;----------------------------------------------------------------------
GET_KEYSTROKE PROC NEAR
ASSUME CS:CSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING
MOV AH,1 ;Check for keystroke
INT 16H ;Keyboard BIOS
JZ GK_EXIT ;No key so exit
PUSHF ;Save the zero flag
XOR AH,AH ;Get the keystroke
INT 16H
POPF ;Restore the zero flag
GK_EXIT:
RET
GET_KEYSTROKE ENDP
;----------------------------------------------------------------------
; Initialize the buffer pointers for the input and output buffers.
; Input - CX points to starting buffer location
; Output - Input and output buffer points are initialized
; Changes - BX, CX
;----------------------------------------------------------------------
INIT_BUFFERS PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
MOV BX,OFFSET IN_BUFF_HEAD ;In buffer will be here
MOV WORD PTR [BX],CX ; Set head pointer to buffer
MOV WORD PTR 2[BX],CX ;Set tail pointer to buffer
MOV WORD PTR 4[BX],CX ;Set begin of buffer
ADD CX,IN_BUFF_SIZE ;CX Points to end of in buffer
IB_10:
MOV WORD PTR 6[BX],CX ;Set end of buffer
MOV BX,OFFSET OUT_BUFF_HEAD ;Out buffer after in buffer
MOV WORD PTR [BX],CX ; Set head pointer to buffer
MOV WORD PTR 2[BX],CX ;Set tail pointer to buffer
MOV WORD PTR 4[BX],CX ;Set begin of buffer
ADD CX,OUT_BUFF_SIZE ;CX Points to end of out buffer
MOV WORD PTR 6[BX],CX ;Set end of buffer
RET
INIT_BUFFERS ENDP
;----------------------------------------------------------------------
; Change the interrupt 8 vector to the interrupt service routine of
; PCREMOTE
; Input - Nothing
; Output - Interrupt vector 8 points to INT8
; Changes - AX, DX, BX, ES
;----------------------------------------------------------------------
MODIFY_INT8 PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
;
; Change interrupt 8 vector
;
MOV AX,3508H ;Get interrupt 8h vector
INT 21H
MOV OLDINT_8,BX ;And save it
MOV OLDINT_8[2],ES
MOV AX,2508H ;Set interrupt 8h vector
MOV DX,OFFSET INT8 ; to point to new routine
INT 21H
RET
MODIFY_INT8 ENDP
;----------------------------------------------------------------------
; Change the interrupt 21 vector to the interrupt service routine of
; PCREMOTE
; Input - Nothing
; Output - Interrupt vector 21 points to INT21
; Changes - AX, DX, BX, ES
;----------------------------------------------------------------------
MODIFY_INT21 PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
MOV AX,3521H ;Get interrupt 21H vector
INT 21H
MOV WORD PTR OLDINT_21,BX ;And save it
MOV WORD PTR OLDINT_21[2],ES
MOV AX,2521H ;Set interrupt 21H vector
MOV DX,OFFSET INT21 ; to point to new routine
INT 21H
RET
MODIFY_INT21 ENDP
;----------------------------------------------------------------------
; Change the communication interrupt vector to the interrupt service
; routine of PCREMOTE
; Input - SET_VEC contains interrupt vector number
; Output - communications interrupt vector points to INT_COMM
; Changes - AX, DX, BX, ES
;----------------------------------------------------------------------
MODIFY_INTCOMM PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH ES
MOV AL,BYTE PTR SET_VEC ;Get the interrupt number
MOV AH,35H ;Get the old vector
INT 21H
MOV WORD PTR OLDINT_COMM,BX ;And save it
MOV WORD PTR OLDINT_COMM[2],ES
POP ES
MOV AL,BYTE PTR SET_VEC ;Get the interrupt number
MOV AH,25H ;Set interrupt for comm vector
MOV DX,OFFSET INT_COMM ; to point to new routine
INT 21H
RET
MODIFY_INTCOMM ENDP
;----------------------------------------------------------------------
; Set baud rate
; Input - AL -0 1200 baud, 1 2400 baud, 2 4800 baud, 3 9600 baud
; 4 19200 baud, 5 38400 baud
; Output - Nothing
; Changes - Nothing
;----------------------------------------------------------------------
SET_BAUD_RATE PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH DX ;Save registers
PUSH BX
PUSH SI
PUSH AX
MOV DX,COMM_PORT ;Get port address
ADD DX,3 ;Line control register
MOV AL,83H ;Toggle port address to
OUT DX,AL ; prepare to set baud rate
SUB DX,2 ;Baud rate divisor MSB port
POP AX ;Restore baud rate
PUSH AX
XOR AH,AH ;Zero AH
MOV SI,AX ;Save in index register
SHL SI,1 ;Multiply by 2, word address
MOV BX,OFFSET BAUD_RATE ;Point to baud rates
MOV AL,[BX+SI] ;Get baud rate MSB
OUT DX,AL ; and set it
DEC DX ;Baud rate divisor LSB port
MOV AL,1[BX+SI] ;Get baud rate LSB
OUT DX,AL ; and set it
ADD DX,3 ;Line control register
MOV AL,3 ;8 data bits,1 stop,no parity
OUT DX,AL ;Set data bit pattern
; and toggle port address
POP AX ;Restore registers
POP SI
POP BX
POP DX
RET
SET_BAUD_RATE ENDP
;----------------------------------------------------------------------
; Initialize the serial port
; Input - COMM_PORT contains port address,
; COMM_FLAG 0-comm1 1-comm2 2-comm3 3-comm4
; Output - Serial port initialize for interrupt driven I/O
; Changes - Nothing
;----------------------------------------------------------------------
INIT_SERIAL PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH DX ;Save registers
PUSH CX
PUSH BX
PUSH AX
;
; disable the interrupts on the 8250 and initialize DTR and RTS
;
CLI ;Disable interrupts
MOV DX,COMM_PORT ;Get UART base address
ADD DX,4 ;Modem control register
MOV AL,00001011B ;Set DTR, RTS, and OUT2
OUT DX,AL
;
; set the baud rate of the UART and initialize line control register
;
CMP BYTE PTR CONNECT_FLAG,0 ;If connect then use current
JZ IS_10
MOV AL,BYTE PTR CURRENT_SPEED
JMP IS_20
IS_10:
MOV AL,SPEED_FLAG ;Get speed flag
IS_20:
MOV BYTE PTR CURRENT_SPEED,AL ;Save the current speed
MOV BYTE PTR SPEED_COUNT,19
CALL SET_BAUD_RATE
;
; set 8259 mask to enable the comm port interrupt
;
MOV CL,BYTE PTR SET_VEC ;Get the interrupt number
SUB CL,8 ; and adjust
MOV AH,1 ;Mask for the interrupt
SHL AH,CL
NOT AH ;Invert
IN AL,21H ;Get current 8259 int mask
AND AL,AH ;Mask appropriate int bit
OUT 21H,AL ;And set new 8259 mask
;
; enable the data received interrupt and reset the 8250
;
SUB DX,3 ;Point to int enable reg
MOV AL,3 ;Enable data received
OUT DX,AL ; and transmit empty int
DEC DX ;Point to base address
MOV CX,7 ;Reset the serial port
IS_30:
IN AL,DX ;Read registers to reset
INC DX
LOOP IS_30
CMP BYTE PTR COMM_INT_STA,0 ;Transmit int. running?
JZ IS_50 ; no, so exit
MOV AX,OUT_BUFF_HEAD ;Is data in output buffer
CMP AX,OUT_BUFF_TAIL
JZ IS_50 ;No, so exit
MOV DX,COMM_PORT ;Get port base address
ADD DX,5 ;Line status register
IS_40:
IN AL,DX ;Make sure holding reg. empty
TEST AL,00100000B ;Test the hold reg empty flag
JZ IS_40 ;Loop if not empty
SUB DX,5 ;Port base register
MOV AH,1 ;Use the output buffer
CALL GET_BUFF_DATA ;Get data from output buffer
OUT DX,AL ;Send the data out the port
IS_50:
STI ;Enable interrupts
POP AX ;Restore registers
POP BX
POP CX
POP DX
RET
INIT_SERIAL ENDP
;======================================================================
; Initialize routines. The initialize routine for unattended is first
; because it must remain resident.
;======================================================================
;-----------------------------------------------------------------------------
; Initialize the unattended program.
;-----------------------------------------------------------------------------
INIT_UNATTENDED PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:CSEG,SS:NOTHING
CALL IU_10 ;Init pointers,clear video copy
CALL MODIFY_INT8 ;Change INT 8 vector
CALL MODIFY_INT21 ;Change INT 21 vector
;
; Terminate-Stay-Resident
;
MOV DX,VIDEO_COPY ;Start of video copy
ADD DX,4000D ;Allow room for video copy
INT 27H ;Terminate-Stay-Resident
;
; Initialize buffer pointers and video copy pointer
;
IU_10:
PUSH ES ;Save extra segment
MOV CX,OFFSET INITIALIZE ;CX points to begin of buffer
ADD CX,256D ;Leave room for TSR stack
CALL INIT_BUFFERS ;Initalize the buffer pointers
INC CX ;Point to copy of video ram
MOV TEMP_VIDEO_PTR,CX ;Save address of temp video buf
ADD CX,BLOCK_SIZEX2 ;Save room for temp video data
MOV VIDEO_COPY,CX ;Save address of video copy
;
; fill video RAM image with with space code since screen
; of manned system is blanked when connected
;
PUSH CS ;Video copy is destination
POP ES ;ES:DI points to video copy
MOV DI,WORD PTR VIDEO_COPY
MOV AX,0720H ;Data to fill buffer
CLD ;Move upward
MOV CX,2000D ;Move 2000 words
REP STOSW ;Fill to force screen dump
MOV CURSOR_POSITION,0FFFFH ;Force cursor position update
MOV AL,1 ;Use setup string 2
MOV BYTE PTR BAD_PASSWORD,0D ;Do not send exit code
CALL RESET_MODEM ;Reset the modem
POP ES ;Restore extra segment
RET
INIT_UNATTENDED ENDP
;-----------------------------------------------------------------------------
; INITIALIZE - Initialize the program. Determine whether it is manned
; or unattended by processing the command line. Initialize the serial
; port. This area is overwritten by PCREMOTE host mode to conserve memory.
;-----------------------------------------------------------------------------
INITIALIZE PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
;
; Display copyright notice.
;
MOV DX,OFFSET COPYRIGHT ;Display copyright notice
MOV AH,9 ;Display string
INT 21H
;
; check to see if the program is already in memory
;
MOV BYTE PTR START,0 ;Zero word to avoid false match
XOR BX,BX ;Initialize search segment
MOV AX,CS ;Save current segment in AX
CLD ;Clear direction flag
I_10:
INC BX ;Increment search segment
CMP AX,BX ;Reached current segment?
JE I_20 ;Yes, PCREMOTE not resident
MOV ES,BX ;Point ES to search segment
MOV SI,OFFSET START ;Start of compare area
MOV DI,SI ;Make offsets equal
MOV CX,16D ;Check 16 characters
REPE CMPSB ;Compare the strings
JNE I_10 ;Compare failed
MOV INSTALLED_SEG,BX ;Save the segment of resident
; MOV AH,09H ;Print string
; MOV DX,OFFSET PROG_RES ;Display program resident mess.
; INT 21H
; INT 20H ;Terminate
;
; Process command line for switches.
;
I_20:
PUSH CS ;Restore ES
POP ES
MOV BX,80H ;Point to command line length
MOV AH,[BX] ;Get command line length
I_30:
OR AH,AH ;Check for commands
JNZ I_40
JMP I_210 ;None, so don't look
I_40:
INC BX ;Point to next data
MOV AL,[BX] ;Get data
DEC AH ;Decrement counter
I_50:
CMP AL,"?" ;Check for help menu (usage)
JNE I_60 ;No, check for slash
JMP HELP ;Yes, help is requested !
I_60:
CMP AL,"/" ;Check for slash
JNE I_30 ;No, jump to check next data
OR AH,AH ;Check for data after slash
JNZ I_70
JMP I_210 ;No, so don't process
I_70:
INC BX ;Point to next data
MOV AL,[BX] ;Get data
DEC AH ;Decrement counter
CMP AL,"?" ;Check for help after a slash
JNE I_80 ;No, check for comm2
JMP HELP ;Yes, help is requested !
I_80:
CMP AL,"1" ;Check for comm1
JNE I_90 ;No, check for another switch
MOV BYTE PTR COMM_FLAG,0 ;Set comm1 flag
I_90:
CMP AL,"2" ;Check for comm2
JNE I_100 ;No, check for another switch
MOV BYTE PTR COMM_FLAG,1 ;Set comm2 flag
I_100:
CMP AL,"3" ;Check for comm port 3
JNE I_110 ;No, jump to check next data
MOV BYTE PTR COMM_FLAG,2 ;Set comm3 flag
I_110:
CMP AL,"4" ;Check for comm port 4
JNE I_120 ;No, jump to check next data
MOV BYTE PTR COMM_FLAG,3 ;Set comm4 flag
JMP I_30 ;Process next switch
I_120:
OR AL,20H ;Force data to lower case
CMP AL,"m" ;Check for manned switch
JNE I_130 ;No, check for another switch
INC BYTE PTR MANNED_FLAG ;Set manned flag
JMP I_30 ;Process next switch
I_130:
CMP AL,"b" ;Check for baud rate
JNE I_170 ;No, check for another switch
OR AH,AH ;Check for data after slash
JZ I_210 ;No, so don't process
INC BX ;Point to next data
MOV AL,[BX] ;Get data
DEC AH ;Decrement counter
CMP AL,"1" ;Check for 1200 baud
JNE I_140
MOV BYTE PTR SPEED_FLAG,0 ;1200 baud
MOV AL,[BX+1] ;Check for 19200 baud
CMP AL,"9"
JNE I_140 ;No so continue
INC BX ;Skip this data now
DEC AH ;Decrement counter
MOV BYTE PTR SPEED_FLAG,4 ;19200 baud
JMP I_30
I_140:
CMP AL,"2" ;Check for 2400
JNE I_150
MOV BYTE PTR SPEED_FLAG,1 ;2400 baud
I_150:
CMP AL,"4" ;Check for 4800
JNE I_160
MOV BYTE PTR SPEED_FLAG,2 ;4800 baud
I_160:
CMP AL,"9" ;Check for 9600
JNE I_165 ;Check next speed
MOV BYTE PTR SPEED_FLAG,3 ;9600
JMP I_30 ;Process next switch
I_165:
CMP AL,"3" ;Check for 38400
JE I_166
JMP I_50 ;maybe char is next slash
I_166:
MOV BYTE PTR SPEED_FLAG,5 ;38400
JMP I_30 ;Process next switch
I_170:
CMP AL,"d" ;Check for desnow
JNE I_180 ;No, process next switch
INC BYTE PTR DESNOW_FLAG ;Set desnow flag
JMP I_30 ;Process next switch
I_180:
CMP AL,"n" ;Check for null modem
JNE I_190 ;No, process next switch
INC BYTE PTR NULL_MODEM ;Set null modem flag
JMP I_30 ;Process next switch
I_190:
CMP AL,"s" ;Check for smile face flag
JNE I_200 ;No, process next switch
INC BYTE PTR SMILE_FLAG ;Yes, set smile flag
JMP I_30 ;No, check for more switches
I_200:
CMP AL,"u" ;Check for uninstall flag
JNE I_205 ;No, process next switch
JMP UNINSTALL ;If pcremote resident
I_205:
JMP I_30 ;Process next switch
I_210:
;
; If PCREMOTE is resident and this is host mode then terminate
;
CMP INSTALLED_SEG,0 ;Check for resident segment
JZ I_215 ;none, then ok to continue
CMP MANNED_FLAG,1 ;Check for manned mode
JZ I_215 ;yes, then continue
MOV AH,09H ;Print string
MOV DX,OFFSET PROG_RES ;Display program resident mess.
INT 21H
INT 20H ;Terminate
;----------------------------------------------------------------------
; Initialize the serial port
;----------------------------------------------------------------------
I_215:
;
; get the comm port base address using 2* comm port flag as offset
;
PUSH DS ;Save data segment
XOR BX,BX ;Zero BX
MOV BL,COMM_FLAG ;Get comm port flag
MOV SI,BX ;Save in index register
SHL SI,1 ;Multiply by 2, word address
MOV AX,40H ;Point DS to BIOS data area
MOV DS,AX
XOR BX,BX ;Point to comm port address
MOV AX,[BX+SI] ;Get comm port address
POP DS ;Restore data segment
CMP AX,0 ;Make sure there is a entry
JNZ I_230
CMP BYTE PTR COMM_FLAG,2 ;Is this comm 3?
JNZ I_220 ;No, must be comm4
MOV AX,WORD PTR COMM_PORT3 ;Yes, get the comm port 3 add
JMP I_230
I_220:
MOV AX,WORD PTR COMM_PORT4
I_230:
MOV WORD PTR COMM_PORT,AX ;Save comm port address
;
; modify the interrupt vector for the comm port
;
CMP BYTE PTR COMM_FLAG,0 ;Determine INT vector to change
JNZ I_240
MOV AL,4 ;Comm 1 interrupt 4
I_240:
CMP BYTE PTR COMM_FLAG,1
JNZ I_250
MOV AL,3 ;Comm 2 interrupt 3
I_250:
CMP BYTE PTR COMM_FLAG,2
JNZ I_260
MOV AL,BYTE PTR COMM3_INT ;Comm 3 interrupt
I_260:
CMP BYTE PTR COMM_FLAG,3
JNZ I_270
MOV AL,BYTE PTR COMM4_INT ;Comm 4 interrupt
I_270:
ADD AL,8 ;Interrupt number
CLI
MOV BYTE PTR SET_VEC,AL ;
CALL MODIFY_INTCOMM ;Change comm interrupt vector
CALL INIT_SERIAL ;Initialize the serial port
;
; determine color or monochrome and save appropriate video segment
;
MOV AH,0FH ;Determine video mode
INT 10H ;By using BIOS int 10
CMP AL,7 ;Check for monochrome
JZ MONOCHROME ;Jump if it is
MOV WORD PTR VIDEO_SEGMENT,0B800H ;Nope, it's CGA or EGA
JMP I_280 ;Skip over
MONOCHROME:
MOV WORD PTR VIDEO_SEGMENT,0B000H ;It's a monochrome
I_280:
;
; If manned then execute manned initialization, otherwise execute
; unattended initialization.
;
CMP BYTE PTR MANNED_FLAG,0 ;Manned or unattended
JZ I_290
JMP INIT_MANNED ;Init the manned routines
I_290:
JMP INIT_UNATTENDED ;Init the unattended routines
INITIALIZE ENDP
;----------------------------------------------------------------------
; Uninstall the resident (host) portion of PCREMOTE. Make sure another
; program did not change any of the interrupt vectors, if so, then the
; vectors cannot be restored properly and the program cannot be uninstalled.
; Tom - if this looks like some of your code, it is, I borrowed from
; PRN2FILE.
;----------------------------------------------------------------------
UNINSTALL PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
MOV AL,08H ;Check the timer interrupt
CALL CHECK_SEG
JNE CANT_UNINSTALL ;If changed, can't uninstall
MOV AL,21H ;Check DOS interrupt vector
CALL CHECK_SEG
JNE CANT_UNINSTALL ;If changed, can't uninstall
MOV ES,INSTALLED_SEG ;Get the segment of resident
MOV AL,BYTE PTR ES:SET_VEC ;Check comm interrupt vector
CALL CHECK_SEG
JNE CANT_UNINSTALL ;If changed, can't uninstall
MOV ES,INSTALLED_SEG
ASSUME DS:NOTHING, ES:NOTHING
LDS DX,DWORD PTR ES:OLDINT_8;Get original timer vector
MOV AX,2508H ;and change it back
INT 21H
LDS DX,DWORD PTR ES:OLDINT_21;Get original DOS vector
MOV AX,2521H ;and change it back
INT 21H
; comm vector changed last so PCREMOTE doesn't go to sleep
CALL RESET_COMM ;Reset the comm port 8250
LDS DX,DWORD PTR ES:OLDINT_COMM ;Get original comm vector
MOV AX,ES:SET_VEC ;and change it back
INT 21H
; release the memory allocated to the resident portion of PCREMOTE
MOV ES,WORD PTR ES:2CH ;Get the environment segment
MOV AH,49H ;Free allocated memory
INT 21H
JC RELEASE_ERR
MOV ES,INSTALLED_SEG ;Resident program segment
NOT WORD PTR ES:START ;Modify so can't find again
MOV AH,49H ;Free allocated memory
INT 21H
JC RELEASE_ERR ;Error releasing the memory
MOV DX,OFFSET YES_UNINSTALL ;Display uninstalled mess
JMP UNI_10
CANT_UNINSTALL:
MOV DX,OFFSET NO_UNINSTALL ;Display can't uninstall mess
JMP UNI_10
RELEASE_ERR:
MOV DX,OFFSET CANT_RELEASE ;Display can't release mess
JMP UNI_10
UNI_10:
PUSH CS ;Restore the data segment
POP DS
MOV AH,09H ;Print string
INT 21H
MOV AX,4C00H
INT 21H ;Terminate
UNINSTALL ENDP
;----------------------------------------------------------------------
; Check to see if an interrupt vector points to the installed program
; segment.
; Input: AL contains interrupt to check.
; Output: Zero flag = 1 if yes, else Zero flag = 0
; Destroys: AH, ES
;----------------------------------------------------------------------
CHECK_SEG PROC NEAR
MOV AH,35H ;Get vector
INT 21H
MOV AX,ES ;Save returned segment
CMP AX,INSTALLED_SEG ;Is it installed segment
RET
CHECK_SEG ENDP
;----------------------------------------------------------------------
; Initialize the manned program. Initialize buffers, and change INT 8
; vector.
;----------------------------------------------------------------------
INIT_MANNED PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
CALL GET_COMSPEC
MOV CX,OFFSET LAST_BYTE ;CX points to begin of buffer
CALL INIT_BUFFERS ;Initalize the buffer pointers
MOV AX,VIDEO_SEGMENT ;Set ES to point to video RAM
MOV ES,AX
JMP CONNECT_MANNED ;Run manned portion of program
INIT_MANNED ENDP
;======================================================================
; Data used by manned portion of program only. Not required to be
; resident for unattended mode.
;======================================================================
HOST_PORT EQU BYTE PTR CONNECT_UNATTENDED ;Host port number (1-4) DB
OLD_CURSOR EQU WORD PTR HOST_PORT+1 ;Cursor position save field DW
UP_LENGTH EQU WORD PTR OLD_CURSOR+2 ;Upload string length DW
DN_LENGTH EQU WORD PTR UP_LENGTH+2 ;Download string length DW
PATH_LENGTH EQU WORD PTR DN_LENGTH+2 ;Pathname string length DW
LAST_KEY EQU BYTE PTR PATH_LENGTH+2 ;Last key pressed save field DB
EXEC_VAL EQU BYTE PTR LAST_KEY+1 ;Shell Variable (1-3) DB
; 1 = Remote shell to DOS
; 2 = Remote Download
; 3 = Remote Upload
UPDN_STRING EQU BYTE PTR EXEC_VAL+1 ;Upload string (filename)
PATH_STRING EQU BYTE PTR UPDN_STRING+44 ;Path string (drive & path)
ORGDSK EQU BYTE PTR PATH_STRING+44 ;1 byte
ORGPTH EQU BYTE PTR ORGDSK+1 ;256 bytes
BLOCK_DATA_COUNT DB 0 ;Number of bytes left to rec.
TYPE_TRANSFER DB 0FFH ;FF - No data transfer in prog.
;00 - Received char. data
;01 - Received attr. data
RPT_STATUS DB 0 ;00 - No data repeat
;02 - Repeat the char in block
CUR_STATUS DB 0 ;0=No cursor data being rec.
; otherwise, byte count
CUR_LOW DB 0 ;Low byte of cursor data
CUR_HIGH DB 0 ;High byte of cursor data
ENTER_NUMBER DB CR,LF,CR,LF,"Enter phone number:$"
NO_CARRIER DB CR,LF,"No carrier.$"
MODEM_ERROR DB CR,LF,"Error.$"
TERMINATE_MESS DB CR,LF,"Returning to DOS.$"
PROG_RES DB CR,LF,"PCREMOT2 is already resident.$"
NO_UNINSTALL DB CR,LF,"Cannot uninstall PCREMOT2.$"
YES_UNINSTALL DB CR,LF,"PCREMOT2 uninstalled successfully.$"
CANT_RELEASE DB CR,LF,"Error release PCREMOT2 resident memory.$"
SHELL_PROMPT DB " Shell to DOS initiated. Type 'EXIT' at any DOS "
DB "prompt to return to PCREMOT2. ",0
TRANSFER_PROMPT DB " File transfer initiated ... ",0
PARM_$_1200 DB "/a /8 /r",0 ;ZCOPY parm 1200 baud
PARM_$_2400 DB "/a /7 /r",0 ;ZCOPY parm 2400 baud
PARM_$_4800 DB "/a /6 /r",0 ;ZCOPY parm 4800 baud
PARM_$_9600 DB "/a /5 /r",0 ;ZCOPY parm 9600 baud
PARM_$_19200 DB "/a /4 /r",0 ;ZCOPY parm 19200 baud
PARM_$_38400 DB "/a /3 /r",0 ;ZCOPY parm 38400 baud
PARM_STRING DB " ",0 ;Actual ZCOPY parm
ASCII_CODE DB "~`!1@2#3$4%5^6&7*8(9)0_-+|\=QWERTYUIOP{[}]ASDFGHJKL:;"
DB 34D,39D,CR,"ZXCVBNM<,>.?/ "
SCAN_CODE DB 1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12
DB 13,13,14,14,17,18,19,20,21,22,23,24,25,26,27,27,28,28
DB 31,32,33,34,35,36,37,38,39,40,40,41,41,43,46,47,48,49
DB 50,51,52,53,53,54,54,55,55,61
ZCOPY DB "ZCOPY ",0 ;ZCOPY command line
REMOTE_COM DB "COM ",0 ;Remote Comm value
HOST_COM DB "COM ",0 ;Host Comm value
UPDNLOAD_COM DB " /c zcopy ", 90 DUP(?)
HELP_SCREEN DB CR,LF
DB " Usage : PCREMOT2 [ /# ] [ /B# ] [ /M ] [ /D ] [ /S ] [ /N ]"
DB CR,LF,CR,LF
DB " [ /# ] - # = Communication port number ( 1 - 4 ) "
DB CR,LF
DB " [ /B# ] - # = Baud rate 1=1200, 2=2400, 4=4800, 9=9600 "
DB CR,LF
DB " null modem only 19=19200, 3=38400 "
DB CR,LF
DB " [ /M ] - Manned mode (used on remote computer) "
DB CR,LF
DB " [ /D ] - Desnow flag (used on CGA monitors) "
DB CR,LF
DB " [ /S ] - Smile face enable (used on host computer) "
DB CR,LF
DB " [ /N ] - Null modem connects the two computers "
DB CR,LF
DB " [ /U ] - Uninstall (used on host computer to remove from memory) "
DB CR,LF,CR,LF,"$",26
EXIT_MESSAGE DB " "
DB " ┌──────────────────┐ "
DB " │ OK to EXIT? (Y/N)│ "
DB " └──────────────────┘ "
DB " "
BOX_CHAR DW 164 ;location for character
DB '╔' ;Character for box
DW 256
DB '╗'
DW 324
DB '║'
DW 416
DB '║'
DW 484
DB '╠'
DW 576
DB '╣'
DW 644
DB '║'
DW 804
DB '║'
DW 964
DB '║'
DW 1124
DB '║'
DW 736
DB '║'
DW 896
DB '║'
DW 1056
DB '║'
DW 1216
DB '║'
DW 1284
DB '╠'
DW 1376
DB '╣'
DW 1444
DB '║'
DW 1536
DB '║'
DW 1604
DB '╚'
DW 1696
DB '╝'
TRANSFER_MESS DB "FILE TRANSFER REQUESTED",0
DB " ",0
DB " (U)pload - Send file(s) to Host System.",0
DB " or",0
DB " (D)ownload - Receive file(s) from Host.",0
UPLOAD_MESS DB " UPLOAD REQUESTED",0
DB "Enter the full pathname of the file(s) on ",0
DB "the remote system which you want to upload",0
DB "to the host system.",0
DB ":",0
DOWNLOAD_MESS DB " DOWNLOAD REQUESTED",0
DB "Enter the full pathname of the file(s) on ",0
DB "the host system which you want to download",0
DB "to the remote system.",0
DB ":",0
UP_PATH_MESS DB " UPLOAD REQUESTED",0
DB "Enter the path on the host system to place ",0
DB "the uploaded file(s). No target, other",0
DB "than directory path, may be specified.",0
DB ":",0
DN_PATH_MESS DB " DOWNLOAD REQUESTED",0
DB "Enter the path on the remote system to place",0
DB "the downloaded file(s). No target, other",0
DB "than directory path, may be specified.",0
DB ":",0
PRESS_ESC DB "Press <ESC> to return to PCREMOT2",0
;
;-----------------------------------------------------------------------
;
COMSPC LABEL DWORD
COM_OFS DW 0000
COM_SEG DW 0000
PAR_BLK DW 0000
DW 0000 ; OFFSET NUL_TAIL
DW 0000
DW 0000
DD 0FFFFH
NOEXEC DB 00
;--------------------------------------------------------------------
;
COM_VAR DB 'COMSPEC='
NUL_TAIL DB 00
;
; DON'T REMOVE OR PHYSICALLY REARRANGE THIS
;
GODPMT DB '$P$G',00
PMTSTR DB 'PROMPT=',00
PMTLOC DW 0000
DFTPMT DB 'PROMPT='
PCRSTR DB 'DOS SHELL- '
PMTLGT DW $-OFFSET PCRSTR
;======================================================================
; The manned routine will execute the connect manned routine to call the
; unattended system. These routines are only used in the manned mode.
;======================================================================
;----------------------------------------------------------------------
; User requested a help screen by including a question mark in the
; command line. Therefore, display the usage for PCREMOTE and end
; the program.
;----------------------------------------------------------------------
HELP PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH CS ;
POP DS ;DS->CS
MOV AH,09H ;String print INT21 (09)
MOV DX,OFFSET HELP_SCREEN ;DS:DX->Help screen variable
INT 21H ;Display the help screen
INT 20H ;Terminate the program
HELP ENDP
;----------------------------------------------------------------------
; Connect manned asks for the phone number to call, dials the number
; and waits for connect. Once connected it sends bursts of 20 CRs at
; one second intervals. When it receives alpha data it processes video
; data and waits for sync byte (00), then transfers control to the
; manned routine.
;----------------------------------------------------------------------
CONNECT_MANNED PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH ES ;
PUSH CS ;
POP ES ;
MOV BX,1000H ;
MOV AH,4AH ;
INT 21H ;
POP ES ;
CM_10:
CMP BYTE PTR NULL_MODEM,0 ;If null modem skip number
JNZ CM_50
XOR AL,AL ;Use setup string 1
CALL RESET_MODEM ;Reset the modem first
MOV DX,OFFSET ENTER_NUMBER ;Point to enter number mess.
MOV AH,9 ;Display message
INT 21H
MOV DX,OFFSET UPDN_STRING ;Unused area as keyboard buffer
MOV BX,DX ;Enter max characters for input
MOV BYTE PTR [BX],40D
MOV AH,0AH ;Buffered keyboard input
INT 21H ;Get the phone number
MOV AL,1 ;Wait a second
CALL DELAY
MOV SI,OFFSET UPDN_STRING ;Point to phone number
INC SI ;Amount of data in key buffer
XOR AX,AX ;Zero AX
CLD ;Forward
LODSB ;Get count
OR AL,AL ;Check for no input
JNZ CM_20 ;If there is then continue
JMP EXIT_MANNED ;No, then exit program
CM_20:
PUSH SI ;Save pointer
MOV SI,OFFSET TONE_DIAL ;Send the tone dial command
CALL LOAD_ZSTRING
POP SI ;Restore pointer
ADD SI,AX ;Point to end of buffer
INC SI ;Include CR code
MOV BYTE PTR [SI],0 ;And put a zero on end
DEC SI ;Adjust for previous INC
SUB SI,AX ;Back to begin of buffer
CALL LOAD_ZSTRING ;Dial the phone number
MOV AL,1 ;Wait a second
CALL DELAY
CALL CLEAR_INBUFF ;Clear input buffer
CM_30:
CALL GET_KEYSTROKE ;Check for a keystroke
JZ CM_40 ;None, so wait
CMP AL,ESC_KEY ;Check for ESCAPE
JNZ CM_40 ;No
JMP CM_10 ;Yes, then enter new number
CM_40:
CALL CHECK_CARRIER ;Check for a connect signal
JZ CM_60 ;No, then check for err codes
CM_50:
CALL CLEAR_SCREEN ;Yes, blank the screen
MOV BYTE PTR CONNECT_FLAG,1 ;Set the connect flag
JMP CM_90 ;Execute manned
CM_60:
MOV AH,0 ;Use input buffer
CALL GET_BUFF_DATA ;Get data from buffer
JNC CM_30 ;No data, try again
CMP AL,"3" ;No carrier code?
JNZ CM_80 ;No, check for other code
CM_70:
MOV DX,OFFSET NO_CARRIER ;Send no carrier message
MOV AH,09H
INT 21H
JMP CM_10 ;Yes, reset modem and try again
CM_80:
CMP AL,"8" ;2400 no answer code
JZ CM_70 ;Yes, display no carrier mess
CMP AL,"4" ;Error code?
JNZ CM_30 ;No, check for other code
MOV DX,OFFSET MODEM_ERROR ;Send modem command error mess
MOV AH,09H
INT 21H
JMP CM_10 ;Yes, reset modem and try again
CM_90:
MOV AL,1 ;Wait for a second
CALL DELAY
MOV BYTE PTR CR_COUNT,30D ;Send 30 CRs at a time
CM_100:
CALL CHECK_CARRIER ;Check for carrier loss
JNZ CM_110 ;No, then continue
JMP EXIT_MANNED ;Yes, then exit
CM_110:
CALL GET_KEYSTROKE ;Check for a keystroke
JZ CM_120 ;None, so wait
CMP AL,ESC_KEY ;Check for ESCAPE
JNZ CM_120 ;No
JMP EXIT_MANNED ;Yes, give up
CM_120:
MOV AX,OUT_BUFF_TAIL ;Is output buffer empty?
CMP AX,OUT_BUFF_HEAD
JNZ CM_130 ;No, skip CR
MOV AL,CR ;Send a CR for speed sync
MOV AH,1 ;Use output buffer
CALL PUT_BUFF_DATA
DEC BYTE PTR CR_COUNT ;Decrement CR counter
JZ CM_90
CM_130:
MOV AH,0 ;Use input buffer
CALL GET_BUFF_DATA ; and check for data
JNC CM_100 ;No data so keep checking
CMP AL,'@' ;Alpha message?
JL CM_100 ;No, then wait for it
CM_140:
CMP BYTE PTR NULL_MODEM,0 ;Using a null modem ?
JZ CM_150 ;No... no need for exit check
PUSH AX ;Store AX just in case
MOV AH,AL ;Set up AX for exit compare
XOR AL,AL ;Reset AL to zero
CMP WORD PTR EXIT_CODE,AX ;Did host send exit_code ?
POP AX ;Restore AX just in case no
JNZ CM_150 ;No check for sync byte
JMP EXIT_MANNED ;Yes, exit back to DOS
CM_150:
CMP AL,0 ;Is data a sync byte
JNE CM_270 ;No, then put data on screen
CM_160: ;
MOV AH,0 ;Input buffer
CALL GET_BUFF_DATA ;Receive a character
JNC CM_160 ;Did we receive one yet ?
CMP AL,0 ;Sync byte ?
JE CM_160 ;Yes
;
; A character was received that is not a sync byte. This is the host trying
; to tell the remote computer what Comm port the host is currently running
; through. Because garbage (line noise) is always a threat, remote must
; accurately determine which Comm port was sent.
;
PUSH CX ;Store register
PUSH DX ;Store register
XOR CX,CX ;Reset counters to zero
XOR DX,DX ;Reset counters to zero
JMP CM_180 ;Process AL data
CM_170:
MOV AH,0 ;Use input buffer
CALL GET_BUFF_DATA ;Receive a character
JNC CM_170 ;Did we get one yet ?
CMP AL,0 ;Sync byte ?
JE CM_220 ;Yes, determine host comm
CM_180:
CMP AL,1D ;One received ?
JNE CM_190 ;No
INC CL ;Yes, bump Comm 1 counter
CM_190:
CMP AL,2D ;Two received ?
JNE CM_200 ;No
INC CH ;Yes, bump Comm 2 counter
CM_200:
CMP AL,3D ;Three received ?
JNE CM_210 ;No
INC DL ;Yes, bump Comm 3 counter
CM_210:
CMP AL,4D ;Four received ?
JNE CM_170 ;No, get another character
INC DH ;Yes, bump Comm 4 counter
JMP CM_170 ;Get another character
CM_220:
MOV AL,'1' ;Assume Comm 1 for now
CMP CH,CL ;Comm2 count > Comm1 count ?
JLE CM_230 ;No
MOV AL,'2' ;Yes, assume Comm2 for now
MOV CL,CH ;Save Comm2 counter in CL
CM_230:
CMP DL,CL ;Comm3 count > CL (current)
JLE CM_240 ;No
MOV AL,'3' ;Yes, assume Comm3 for now
MOV CL,DL ;Save Comm3 counter in CL
CM_240:
CMP DH,CL ;Comm4 count > CL (current)
JLE CM_250 ;No
MOV AL,'4' ;Yes, Host port = Comm4
CM_250:
MOV HOST_PORT,AL ;Save largest port counter
POP DX ;Restore register
POP CX ;Restore register
CALL MAKE_PARM_STRING ;Make ZCOPY parm w/ baud & comm
CM_260:
CALL GET_BUFF_DATA ;Receive a character
JNC CM_260 ;Did we receive one yet ?
CMP AL,0 ;Sync Byte ?
JNE CM_270 ;Yes
CALL CLEAR_SCREEN ;Blank the screen
JMP MANNED ;We're in, let's run program
CM_270:
MOV DL,AL ;Prepare to display character
MOV AH,2 ; using DOS
INT 21H ;Display it
CM_280:
CALL CHECK_CARRIER ;Check for carrier loss
JNZ CM_290 ;No, then continue
JMP EXIT_MANNED ;Yes, then exit
CM_290:
CALL GET_KEYSTROKE ;Check for a keystroke
JZ CM_310 ;If none, skip next routine
;
; Check for exit code, if it is then exit
;
CMP AX,WORD PTR EXIT_CODE ;Check for exit code
JNZ CM_300 ;No, so continue
CALL CONFIRM_EXIT ;Yes, confirm exit
JNZ CM_310 ;No, so continue, don't send
JMP EXIT_MANNED ;Otherwise reset and exit
CM_300:
CALL SEND_KEYSTROKE ;Send to unattended system
CM_310:
MOV AH,0 ;Use input buffer
CALL GET_BUFF_DATA ; and check for data
JNC CM_280 ;No data, check for keys
JMP CM_140 ;Check for sync byte
CONNECT_MANNED ENDP
;----------------------------------------------------------------------
; MAKE_PARM_STRING creates the ZCOPY parameters using the current baud
; rate of the remote system. This PROC also creates REMOTE_COM using
; the COMM_FLAG. REMOTE_COM is used in MAKE_UP_COM & MAKE_DN_COM.
;----------------------------------------------------------------------
MAKE_PARM_STRING PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH AX ;Store registers & flags
PUSH CX
PUSH DS
PUSH ES
PUSH DI
PUSH SI
PUSHF
CLD ;Direction flag -> forward
PUSH CS
PUSH CS
POP DS ;DS->CS
POP ES ;ES->CS
MOV DI,OFFSET PARM_STRING ;DI->Parm string's first char
MOV SI,OFFSET PARM_$_1200 ;SI->1st char of 1200 var.
CMP BYTE PTR SPEED_FLAG,1D ;2400 Baud ?
JNE MPS_10 ;Yes, use 2400 baud variable
MOV SI,OFFSET PARM_$_2400 ;SI->1st char of 2400 var.
MPS_10:
CMP BYTE PTR SPEED_FLAG,2D ;4800 Baud ?
JNE MPS_20 ;Yes, use 4800 baud variable
MOV SI,OFFSET PARM_$_4800 ;SI->1st char of 4800 var.
MPS_20:
CMP BYTE PTR SPEED_FLAG,3D ;9600 Baud ?
JNE MPS_30
MOV SI,OFFSET PARM_$_9600 ;SI->1st char of 9600 var.
MPS_30:
CMP BYTE PTR SPEED_FLAG,4D ;19200 Baud ?
JNE MPS_32
MOV SI,OFFSET PARM_$_19200 ;SI->1st char of 19200 var.
MPS_32:
CMP BYTE PTR SPEED_FLAG,5D ;38400 Baud ?
JNE MPS_34
MOV SI,OFFSET PARM_$_38400 ;SI->1st char of 38400 var.
MPS_34:
MOV CX,8D ;Move 8 letters
MPS_40:
LODSB ;Pick off char. and place it
STOSB ; in the real ZCOPY parm string
LOOP MPS_40 ;11 characters done ?
;
; Remote comm must be set up using COMM_FLAG
;
MOV DI,OFFSET REMOTE_COM ;ES:DI-> (C)om var. 1st char
ADD DI,3D ;ES:DI-> COM( ) var. 4th char
MOV AL,'1' ;Assume remote using com1
CMP BYTE PTR COMM_FLAG,1D ;Using com2 ?
JNE MPS_50 ;No
MOV AL,'2' ;Remote using com2
MPS_50:
CMP BYTE PTR COMM_FLAG,2D ;Using com3 ?
JNE MPS_60 ;No
MOV AL,'3' ;Remote using com3
MPS_60:
CMP BYTE PTR COMM_FLAG,3D ;using com4?
JNE MPS_70 ;No
MOV AL,'4' ;Remote using com4
MPS_70:
STOSB ;Store com (1-4) variable
;
; HOST_COM must be set up using the HOST_PORT variable.
;
MOV AL,HOST_PORT ;Ready AL for STOSB
MOV DI,OFFSET HOST_COM ;ES:DI->1st char of HOST_COM
ADD DI,3D ;ES:DI->4th char of HOST_COM
STOSB ;Store HOST_COM into variable
POPF ;Restore flags & registers
POP SI
POP DI
POP ES
POP DS
POP CX
POP AX
RET
MAKE_PARM_STRING ENDP
;----------------------------------------------------------------------
; Manned portion of the program. Not RAM resident. Sends keystrokes
; to the unattended computer. Data from unattended computer is
; decoded and processed.
;----------------------------------------------------------------------
MANNED PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
;
; Check for loss of carrier
;
CALL CHECK_CARRIER ;No, check for carrier loss
JNZ M_10 ;No loss so continue
JMP EXIT_MANNED ;Otherwise reset and exit
;
; Check to see if shift status has changed, if so, put new status
; in the output buffer
;
M_10:
MOV AH,2 ; Prepare shift status
INT 16H ; Get shift status
CMP SHIFT_STATUS,AL ; See if the same
JE M_20 ; If so, next routine
MOV SHIFT_STATUS,AL ; Save new status
MOV AL,0FDH ; Sync, expect shift
MOV AH,1 ; Put into out buff
CALL PUT_BUFF_DATA ;
MOV AL,SHIFT_STATUS ; Get shift status
CALL PUT_BUFF_DATA ; Send to host system
;
; Check for keystoke, if so, put the ASCII code and scan code
; into the output buffer, check it for exit code
;
M_20:
CALL GET_KEYSTROKE ;Check for keystroke
JNZ M_30
JMP M_90 ;If none skip this routine
;
; Check for shell to DOS, if it is then shell & return
;
M_30:
CMP AX,WORD PTR SHELL_CODE ; Shell key pressed ?
JNE M_40 ; No....
MOV EXEC_VAL,1D ; Tell EXEC to shell
CALL EXEC_ZCOPY ; EXEC to shell
CALL INIT_SERIAL ; Re-initialize serial port
CALL CLEAR_SCREEN ; Clear the remote screen
MOV AX,WORD PTR CLEAR_CODE ; Send clear_code to
CALL SEND_KEYSTROKE ; rewrite entire screen
JMP M_90 ; Process next char
;
; Check for exit code, if it is then exit
;
M_40:
CMP AX,WORD PTR EXIT_CODE ;Check for exit code
JNZ M_50 ;No, so continue
PUSH DX ; Store DX
CALL GET_CURSOR ; Get cursor pos.
MOV OLD_CURSOR,DX ; Save Cursor pos.
MOV DH,25D ; Place cursor
MOV DL,79D ; off screen
CALL PUT_CURSOR ; Set cursor pos.
POP DX ; Restore DX
CALL CONFIRM_EXIT ;Yes, confirm exit
PUSH DX ; Store DX
MOV DX,OLD_CURSOR ; Restore cursor pos.
CALL PUT_CURSOR ; Set cursor pos.
POP DX ; Restore DX
JNZ M_90 ;No, so continue, don't send
JMP EXIT_MANNED ;Otherwise reset and exit
;
; Check for transfer code, if it is then ask to upload or download
;
M_50: ;
CMP AX,WORD PTR TRANSFER_CODE ; Check for transfer
JNZ M_70 ; No, so continue
PUSH DX ; Store register
CALL GET_CURSOR ; Get cursor position
MOV OLD_CURSOR,DX ; Save cursor in old cursor
MOV DH,25D ; Cursor Row = 25
MOV DL,79D ; Cursor Col = 79
CALL PUT_CURSOR ; Position Cursor
POP DX ; Restore DX register
CALL TRANSFER_TYPE ; Transfer file
CMP AX,WORD PTR CLEAR_CODE ; Transferred files ?
JNE M_60 ; Yes-reset remote scrn
CALL INIT_SERIAL ; Re-initialize serial port
CALL CLEAR_INBUFF
CALL CLEAR_OUTBUFF
JMP M_70 ; Send clear screen code
M_60:
PUSH DX ; Push DX register
MOV DX,OLD_CURSOR ; Put cursor back
CALL PUT_CURSOR ; where it was
POP DX ; Restore DX register
JMP M_90 ; Transfer complete
;
; Check for clear and resend entire screen code.
;
M_70: ;
CMP AX,WORD PTR CLEAR_CODE ; Clear screen pressed?
JNZ M_80 ; No...
PUSH AX ; Yes.... save key
CALL CLEAR_SCREEN ; Clear remote screen
POP AX ; Restore key
M_80: ;
CALL SEND_KEYSTROKE ; Send key to host
;
; Check for receive data, if available, get data and decode
;
M_90:
MOV AH,0 ;Get data from input buffer
CALL GET_BUFF_DATA
JC M_100 ;Data is there, so process
JMP M_EXIT ;No data,so loop again
M_100:
CMP BYTE PTR TYPE_TRANSFER,0FFH ;Check transfer type
JZ M_160 ;If ff, check for sync byte
CMP VID_RAM_OFFSET,0FFFFH ;Received block no. yet?
JNZ M_120 ;Yes, then process as data
MOV BYTE PTR BLOCK_DATA_COUNT,BLOCK_SIZE ;Data counter
MOV BX,BLOCK_SIZEX2 ;Get block size in bytes
MUL BX ;Block number X block size
ADD AL,TYPE_TRANSFER ;Adjust for char. or attr.
MOV VID_RAM_OFFSET,AX ;Save pointer to video RAM
JMP M_EXIT
M_120:
MOV DI,VID_RAM_OFFSET ;Point to video RAM
CMP BYTE PTR RPT_STATUS,0 ;Check the repeat flag
JZ M_140 ;Normal data transfer
MOV CL,BYTE PTR BLOCK_DATA_COUNT ;Number to repeat
XOR CH,CH
M_130:
CALL PUT_VIDEO_DATA ;Store the data in video RAM
INC DI ;Point to next video RAM loc.
LOOP M_130
JMP M_150 ;End of data, reset variables
M_140:
CALL PUT_VIDEO_DATA ;Store the data in video RAM
INC DI ;Point to next video RAM loc.
MOV VID_RAM_OFFSET,DI ;And save pointer
DEC BYTE PTR BLOCK_DATA_COUNT ;Dec. data counter
JZ M_150 ;End of data, reset variables
JMP M_EXIT ;Otherwise continue
M_150:
MOV BYTE PTR TYPE_TRANSFER,0FFH ;Reset type transfer flag
JMP M_EXIT
M_160:
CMP BYTE PTR CUR_STATUS,0 ;Check cursor status
JZ M_170 ;If 0, check for sync byte
XOR BX,BX ;Zero BX for index
MOV BL,BYTE PTR CUR_STATUS ;Use as index for cursor data
MOV DI,OFFSET CUR_STATUS ;Base address for cursor data
MOV [DI+BX],AL ;Save the register data
INC BL ;Increment count
MOV BYTE PTR CUR_STATUS,BL ;And save it
CMP BL,3 ;Check to see if we have 3 byte
JNZ M_EXIT ;No, so wait till enough data
MOV BH,0 ;Always use page one
MOV DX,WORD PTR CUR_LOW ;Get cursor position
MOV AH,2 ;Set cursor function
INT 10H
MOV BYTE PTR CUR_STATUS,0 ;Reset cursor status
JMP M_EXIT
M_170:
PUSH AX ;Save the data
AND AL,0FCH ;Mask out data type and repeat
CMP AL,0FCH ;Video data sync?
JNZ M_180 ;No, check for cursor sync
POP AX ;Restore data
PUSH AX
AND AL,1 ;Save data type
MOV TYPE_TRANSFER,AL ;Set transfer type flag
POP AX ;Restore data
AND AL,2 ;Save repeat flag
MOV RPT_STATUS,AL ;Set repeat flag
MOV VID_RAM_OFFSET,0FFFFH ;Prepare to receive block no.
JMP M_EXIT
M_180:
POP AX ;Restore data
CMP AL,0D2H ;Check for cursor data sync
JNZ M_EXIT ;If not, then throw away
MOV BYTE PTR CUR_STATUS,1 ;Set cursor status byte
M_EXIT:
JMP MANNED ;Do it again
MANNED ENDP
;----------------------------------------------------------------------
; Exit manned. The exit code is sent, interrupt vector reset, and
; the modem is hung up and reset
; Input - Nothing
; Output - DOS
; Changes - everything
;----------------------------------------------------------------------
EXIT_MANNED PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
MOV AX,WORD PTR EXIT_CODE ;Get the exit code
CALL SEND_KEYSTROKE ;Send the exit code
CALL CLEAR_SCREEN ;Blank the screen
MOV DX,OFFSET TERMINATE_MESS ;Display terminate call mess.
MOV AH,09H
INT 21H
XOR AL,AL ;Reset modem and exit
CALL RESET_MODEM
MOV AL,1 ;Wait a second
CALL DELAY
CALL RESET_COMM
LDS DX,DWORD PTR OLDINT_COMM ;Get original comm vector
MOV AX,SET_VEC ;and change it back
INT 21H
INT 20H ;Terminate program
EXIT_MANNED ENDP
;----------------------------------------------------------------------
; Reset comm port. Resets the comm port 8250 and disables interrupt
; driven I/O. Reset the 8259 mask.
;----------------------------------------------------------------------
RESET_COMM PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH ES
PUSH DS
PUSH CS
POP DS
CMP INSTALLED_SEG,0 ;Maybe this is uninstall
JZ EM_10
MOV ES,INSTALLED_SEG ;Get location of resident prog
MOV DX,ES:COMM_PORT ;Get the comm port it used
MOV CL,BYTE PTR ES:SET_VEC ;Determine mask bit to change
JMP EM_20
EM_10:
MOV DX,CS:COMM_PORT ;Get port address
MOV CL,BYTE PTR SET_VEC ;Determine mask bit to change
EM_20:
INC DX ;Interrupt enable reg.
XOR AL,AL
OUT DX,AL ;Disable all interrupts
SUB CL,8 ; and adjust
MOV AH,1
SHL AH,CL ;Select the mask bit to set
IN AL,21H ;Get current 8259 int mask
OR AL,AH ;Set appropriate int bit
OUT 21H,AL ;And set new 8259 mask
POP DS
POP ES ;Restore segment
RET
RESET_COMM ENDP
;----------------------------------------------------------------------
; Clear screen. This routine will blank the video display
; Input - Nothing
; Output - Screen is cleared
; Changes - AX, BX, CX, DX
;----------------------------------------------------------------------
CLEAR_SCREEN PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
MOV BX,0 ;Use video page one
MOV DX,0 ;Position cursor at row 0 col 0
MOV AH,2 ;Set cursor function
INT 10H
MOV AX,0700H ;Scroll down, clear screen
MOV BH,07H ;White on black
MOV CX,0 ;Upper left corner
MOV DH,24D ;Lower right corner
MOV DL,79D
INT 10H ;Video BIOS call
RET
CLEAR_SCREEN ENDP
;----------------------------------------------------------------------
; Display OK to exit message and wait for response
; Input - Nothing
; Output - Zero flag set - exit, zero flag reset - do not exit
; Changes - CX, SI, DI
;----------------------------------------------------------------------
CONFIRM_EXIT PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH AX ;Save the exit code
CE_10:
MOV AX,OUT_BUFF_HEAD ;Wait until the out buffer
CMP AX,OUT_BUFF_TAIL ; is empty
JNZ CE_10
;
; Save the existing video data in the output buffer
;
CALL SWITCH_DS_ES
MOV DI,ES:OUT_BUFF_END ;Use output buffer as temp stor.
MOV SI,0 ;Upper left corner of video
MOV CX,5 ;Transfer 5 lines
CE_20:
PUSH CX ;Save line counter
MOV CX,24D ;Transfer 24 char. per line
REPNZ MOVSW
ADD SI,112D ;Next line
POP CX ;Restore line counter
LOOP CE_20
;
; Display the ok to exit message
;
CALL SWITCH_DS_ES
MOV DI,0 ;Upper left corner of video
MOV SI,OFFSET EXIT_MESSAGE ;Exit message
MOV CX,5 ;Display 5 lines
CE_30:
PUSH CX ;Save line counter
MOV CX,24D ;Display 20 characters per line
CE_40:
LODSB
CALL PUT_VIDEO_DATA ;Display the character
MOV AL,70H ;White on black attribute
CALL PUT_VIDEO_DATA ;Store attribute
LOOP CE_40
ADD DI,112D ;Next line
POP CX ;Restore line counter
LOOP CE_30
;
; Wait for keystroke and convert to lower case
;
CE_50:
CALL GET_KEYSTROKE ;Check for keystroke
JZ CE_50 ;None there, try again
OR AL,20H ;Convert to lower case
;
; Restore the saved video data
;
MOV SI,OUT_BUFF_END ;Old video is in output buffer
MOV DI,0 ;Upper left corner of video
MOV CX,5 ;Transfer 5 lines
CE_60:
PUSH CX ;Save line counter
MOV CX,24D ;Transfer 24 char. per line
REPNZ MOVSW
ADD DI,112D ;Next line
POP CX ;Restore line counter
LOOP CE_60
CMP AL,'y' ;Check for yes, all others no
POP AX ;Restore exit code
RET
CONFIRM_EXIT ENDP
;---------------------------------------------------------------
; Draw the box and display the text in it.
; Input - SI points to the text strings
; Output - Current video stored in output buffer, text displayed
; in box.
; Changes - nothing
;---------------------------------------------------------------
DISPLAY_BOX PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH AX ;Save registers
PUSH BX
PUSH CX
PUSH DI
PUSH SI
;
; Save the current video area in the output buffer
;
CALL SWITCH_DS_ES
MOV DI,ES:OUT_BUFF_END ;Use output buffer as temp stor.
XOR SI,SI ;Upper left of video
MOV CX,12 ;Save 12 lines
DB_10:
PUSH CX ;Save the line counter
MOV CX,51 ;Save 51 columns
REPNZ MOVSW
ADD SI,58 ;Adjust to start of next line
POP CX ;Restore line counter
LOOP DB_10
CALL SWITCH_DS_ES
;
; Blank that area of the screen
;
XOR DI,DI ;Upper left of video
MOV CX,12 ;Blank 12 lines
DB_20:
PUSH CX ;Save line counter
MOV CX,51 ;Blank 51 characters
DB_30:
MOV AL,SPACE ;Space character
CALL PUT_VIDEO_DATA ;Display the character
MOV AL,70H ;Attribute
CALL PUT_VIDEO_DATA
LOOP DB_30
ADD DI,58 ;Adjust to start of next line
POP CX ;Restore line counter
LOOP DB_20
;
; Draw the box
;
MOV DI,166 ;First line of box
CALL DRAW_LINE ;Display the horizontal line
MOV DI,486 ;Second line of box
CALL DRAW_LINE ;Display the horizontal line
MOV DI,1286 ;Third line of box
CALL DRAW_LINE ;Display the horizontal line
MOV DI,1606 ;Fourth line of box
CALL DRAW_LINE ;Display the horizontal line
MOV BX,OFFSET BOX_CHAR ;Get a pointer to box corners
MOV CX,20 ;Corners and vertical lines
DB_40:
MOV DI,[BX] ;Get offset to char location
ADD BX,2 ;Point to character
MOV AL,[BX] ;Get the character
INC BX ;Next corner
CALL PUT_VIDEO_DATA
LOOP DB_40
;
; Draw the text in the box
;
POP SI ;Get pointer to text
PUSH SI
MOV DI,348 ;Location for title line
CALL DRAW_TEXT ;Display the line of text
MOV DI,648 ;Next line of text
CALL DRAW_TEXT ;Display the line of text
MOV DI,808 ;Next line of text
CALL DRAW_TEXT ;Display the line of text
MOV DI,968 ;Next line of text
CALL DRAW_TEXT ;Display the line of text
MOV DI,1128 ;Next line of text
CALL DRAW_TEXT ;Display the line of text
MOV DI,1458 ;Next line of text
MOV SI,OFFSET PRESS_ESC ;Display the press ESC to exit
CALL DRAW_TEXT ;Display the line of text
POP SI ;Restore registers
POP DI
POP CX
POP BX
POP AX
RET
DISPLAY_BOX ENDP
;---------------------------------------------------------------
; Draw horizontal line
; Input ES:DI points to location to start drawing the line
; Output - nothing
; Changes - AL, CX, DI
;---------------------------------------------------------------
DRAW_LINE PROC NEAR
MOV CX,45 ;45 Columns in line
MOV AL,'═' ;Line draw character
DL_10:
CALL PUT_VIDEO_DATA ;Display the character
INC DI ;Adjust past attribute
LOOP DL_10
RET
DRAW_LINE ENDP
;---------------------------------------------------------------
; Display line of text
; Input - SI points to text DI points to video location
; Output - line of text is displayed on the screen
; Changes - AL, SI, DI
;---------------------------------------------------------------
DRAW_TEXT PROC NEAR
LODSB ;Get the text
CMP AL,0 ;Is this the end of the string
JZ DT_10 ;Yes
CALL PUT_VIDEO_DATA ;Display the character
INC DI
JMP DRAW_TEXT
DT_10:
RET
DRAW_TEXT ENDP
;---------------------------------------------------------------
; Restore the video saved to display a box
; Input - nothing
; Output - nothing
; Changes - nothing
;---------------------------------------------------------------
RESTORE_BOX PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH AX ;Save registers
PUSH CX
PUSH DI
PUSH SI
MOV SI,OUT_BUFF_END ;Old video in output buffer
XOR DI,DI ;Upper left corner of screen
MOV CX,12 ;Line counter
RB_10:
PUSH CX ;Save line counter
MOV CX,51 ;51 characters per line
REPNZ MOVSW
ADD DI,58 ;Next line
POP CX ;Restore line counter
LOOP RB_10
POP SI ;Restore registers
POP DI
POP CX
POP AX
RET
RESTORE_BOX ENDP
;---------------------------------------------------------------
; Display (U)pload or (D)ownload message and wait for response
; Input - Nothing
; Output -
; Changes - CX, SI, DI
;---------------------------------------------------------------
TRANSFER_TYPE PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
MOV AX,OUT_BUFF_HEAD ;Wait until the out
CMP AX,OUT_BUFF_TAIL ;buffer is empty
JNZ TRANSFER_TYPE
;
; Display the (U)pload or (D)ownload message
;
MOV SI,OFFSET TRANSFER_MESS ;Transfer message
CALL DISPLAY_BOX
;
; Wait for a keystroke and convert to lower case
;
TT_10:
CALL GET_KEYSTROKE ;Check for a keystroke
JZ TT_10 ;None there, try again
OR AL,20H
CALL RESTORE_BOX
CMP AL,'u' ;Upload Requested ?
JZ TT_20 ;Yes
JMP TT_90 ;No, so continue
TT_20: ;UPLOAD CODING HERE
MOV LAST_KEY,0 ;Clear last key pressed
CALL UPLOAD ;Ask for upload file
CMP LAST_KEY,ESC_KEY ;ESC pressed ?
JNZ TT_30 ;No
JMP TT_180 ;Yes - return to PCREMOTE
TT_30:
MOV LAST_KEY,0 ;Clear last key pressed
MOV SI,OFFSET UP_PATH_MESS ; Path message for upload
CALL PATH ;Get destination Path
CMP LAST_KEY,ESC_KEY ;ESC pressed ?
JNZ TT_40 ;No
JMP TT_180 ;Yes - return to PCREMOTE
TT_40:
MOV LAST_KEY,0 ;Clear last key pressed
CALL MAKE_UP_COM ;Create ZCOPY EXEC com
CLD ;Forward direction ptr.
MOV SI,OFFSET ZCOPY ;DS:SI -- ZCOPY variable
CALL SEND_STRING ;Send ZCOPY command line
MOV SI,OFFSET HOST_COM ;DS:SI -- COM variable
CALL SEND_STRING ;Send COM to host
MOV AL,SPACE ;AL = SPACE
CALL GET_SEND_CODE ;Get & send scan-code
MOV SI,OFFSET PATH_STRING ;DS:SI -- Path variable
MOV CX,PATH_LENGTH ;CX = Length of PATH
CMP CX,0 ;Default Path ?
JE TT_60 ;Yes...
TT_50: ;No...
LODSB ;AL = next character
CALL GET_SEND_CODE ;Get & send scan-code
LOOP TT_50 ;All characters sent ?
MOV AL,SPACE ;AL = SPACE
CALL GET_SEND_CODE ;Get & send scan-code
TT_60:
MOV SI,OFFSET PARM_STRING ;DS:SI -- PARM variable
MOV CX,9D
TT_70:
LODSB ;AL = Next character
CALL GET_SEND_CODE ;Get & send scan-code
LOOP TT_70 ;All characters sent ?
MOV AL,CR ;AL = carriage return
CALL GET_SEND_CODE ;Get & send scan-code
TT_80:
MOV AX,OUT_BUFF_HEAD ;Get the buff head ptr
CMP AX,OUT_BUFF_TAIL ;Test for data
JNZ TT_80 ;Wait until buffer empty
MOV EXEC_VAL,3D ;Tell EXEC to upload
CALL EXEC_ZCOPY ;Shell to DOS & EXEC ZCOPY
JMP TT_170 ;Transfer complete, exit
TT_90:
CMP AL,'d' ;Download Requested ?
JZ TT_100 ;Yes
JMP TT_180 ;No so return to PCREMOTE
TT_100: ;DOWNLOAD CODING HERE
MOV LAST_KEY,0 ;Clear last key pressed
CALL DOWNLOAD ;Ask for filename
CMP LAST_KEY,ESC_KEY ;ESC pressed ?
JNZ TT_110 ;No
JMP TT_180 ;Yes, return to PC_REMOTE
TT_110:
MOV LAST_KEY,0 ;Clear last key pressed
MOV SI,OFFSET DN_PATH_MESS ; Path message for download
CALL PATH ;Get destination Path
CMP LAST_KEY,ESC_KEY ;ESC pressed ?
JNZ TT_120 ;No
JMP TT_180 ;Yes, return to PC_REMOTE
TT_120:
MOV LAST_KEY,0 ;Clear last key pressed
CALL MAKE_DN_COM ;Create ZCOPY EXEC com
CLD ;Forward direction flag
MOV SI,OFFSET ZCOPY ;DS:SI -- ZCOPY variable
CALL SEND_STRING ;Send ZCOPY command
MOV SI,OFFSET UPDN_STRING ;DS:SI -- file variable
MOV CX,DN_LENGTH ;CX = length of filename
CMP CX,0 ;Default Filename
JE TT_140 ;Yes...
TT_130: ;No...
LODSB ;AL = next character
CALL GET_SEND_CODE ;Get & send scan-code
LOOP TT_130 ;All characters sent ?
MOV AL,SPACE ;AL = SPACE
CALL GET_SEND_CODE ;Get & send scan-code
TT_140:
MOV SI,OFFSET HOST_COM ;DS:SI -- Com variable
CALL SEND_STRING ;Send COM variable
MOV AL,SPACE ;AL = SPACE
CALL GET_SEND_CODE ;Get & send scan-code
MOV SI,OFFSET PARM_STRING ;DS:SI -- PARM variable
MOV CX,9D
TT_150:
LODSB ;AL = next character
CALL GET_SEND_CODE ;Get & send scan-code
LOOP TT_150 ;All characters sent ?
MOV AL,CR ;AL = carriage return
CALL GET_SEND_CODE ;Get & send scan-code
TT_160:
MOV AX,OUT_BUFF_HEAD ;Get buffer head ptr
CMP AX,OUT_BUFF_TAIL ;Test for data in buff
JNZ TT_160 ;Wait for buffer empty
MOV EXEC_VAL,2D ;Tell EXEC to download
CALL EXEC_ZCOPY ;Shell to DOS - EXEC ZCOPY
JMP TT_170
TT_170:
MOV AX,WORD PTR CLEAR_CODE ;Tell the caller to clear
JMP TT_190 ;the remote's screen
TT_180:
MOV AX,WORD PTR TRANSFER_CODE ;Tell the caller that
TT_190: ;screen doesn't need to
RET ;be rewritten.
TRANSFER_TYPE ENDP
;------------------------------------------------------------
; Display upload message then wait for filename(s).
; Input - Nothing
; Output -
; Changes - CX,SI,DI
;
;------------------------------------------------------------
UPLOAD PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
MOV AX,OUT_BUFF_HEAD ;Wait until the out
CMP AX,OUT_BUFF_TAIL ;buffer is empty
JNZ UPLOAD
MOV SI,OFFSET UPLOAD_MESS ;Upload message
CALL DISPLAY_BOX
PUSH DX ;Save register
MOV DH,7 ;Put cursor in row 8
MOV DL,5 ;Put cursor in column 6
CALL PUT_CURSOR ;Set Cursor
POP DX ;Restore register
PUSH ES ;Store ES
PUSH DS ;Store DS
POP ES ;ES = DS
MOV DI,OFFSET UPDN_STRING ;ES:DI -> UP_string
MOV CX,42D ;MAX length = 42
CALL GETSTRING ;Receive file
MOV LAST_KEY,AL ;Save last key
MOV UP_LENGTH,CX ;Save length
CMP UP_LENGTH,0 ;Any file selected ?
JNE UP_10 ;Yes
MOV LAST_KEY,ESC_KEY ;No...Return (esc)
UP_10:
POP ES ;Restore ES
CALL RESTORE_BOX
RET
UPLOAD ENDP
;------------------------------------------------------------
; Display download message then wait for response.
; Input - Nothing
; Output -
; Changes - CX,SI,DI
;------------------------------------------------------------
DOWNLOAD PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
MOV AX,OUT_BUFF_HEAD ;Wait until the
CMP AX,OUT_BUFF_TAIL ;out buffer is empty
JNZ DOWNLOAD
MOV SI,OFFSET DOWNLOAD_MESS ;Download message
CALL DISPLAY_BOX
PUSH DX ;Save DX register
MOV DH,7 ;Put cursor in row 8
MOV DL,5 ;Put cursor in column 6
CALL PUT_CURSOR ;Put cursor there
POP DX ;Restore register
PUSH ES ;Store ES
PUSH DS ;Store DS
POP ES ;ES = DS
MOV DI,OFFSET UPDN_STRING ;ES:DI -> DN_string
MOV CX,42D ;MAX length = 42
CALL GETSTRING ;Get filename
MOV LAST_KEY,AL ;Save last key
MOV DN_LENGTH,CX ;Save length
CMP DN_LENGTH,0 ;File selected ?
JNE DN_10 ;Yes
MOV LAST_KEY,ESC_KEY ;No... return (esc)
DN_10:
POP ES ;Restore ES
CALL RESTORE_BOX
RET
DOWNLOAD ENDP
;----------------------------------------------------------------------
; Display the path request screen & prompt user to input path name.
; Input - SI points to display message for transfer
; Output - Path Message Displayed on screen.
; Changes - CX,SI,DI
;----------------------------------------------------------------------
PATH PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
MOV AX,OUT_BUFF_HEAD ; Wait until the
CMP AX,OUT_BUFF_TAIL ; out buffer is empty
JNZ PATH
CALL DISPLAY_BOX
PUSH DX ; Save DX Register
MOV DH,7 ; Put cursor in row 8
MOV DL,5 ; Put cursor in col 6
CALL PUT_CURSOR ; Put cursor there
POP DX ; Restore DX
PUSH ES ; Store ES
PUSH DS ; Store DS
POP ES ; ES = DS
MOV DI,OFFSET PATH_STRING ; ES:DI -> Path_string
MOV CX,42D ; Max length = 42
CALL GETSTRING ; Get path
MOV LAST_KEY,AL ; Save last key
MOV PATH_LENGTH,CX ; Save length
;
; Validate and correct (modify) pathname if ZCOPY will not accept the
; string entered for the pathname.
; i.e.- C:\ is acceptable whereas C: is unacceptable
; C:\DOS is acceptable whereas C:\DOS\ is unacceptable.
;
CMP LAST_KEY,ESC_KEY ; ESC key pressed ?
JE PATH_20 ; Yes, so skip pathname edit
MOV SI,OFFSET PATH_STRING ; SI->1st char of path name
ADD SI,PATH_LENGTH ; SI->1 char after pathname
DEC SI ; SI->Last char of pathname
LODSB ; Pick off last char
CMP AL,':' ; Is last char a colon
JNE PATH_10 ; No, check other chars.
PUSH SI ; Save SI into DI
POP DI ; DI = SI
MOV AL,'\' ; Add backslash to pathname
STOSB ; Store the backslash
INC PATH_LENGTH ; Add one to length of path
JMP PATH_20 ; Editting is complete
PATH_10:
CMP AL,'\' ; Is last char a backslash
JNE PATH_20 ; No, skip pathname edit
DEC SI ; SI -> Last char again
DEC SI ; SI -> 2nd last char
LODSB ; Pick off 2nd last char
CMP AL,':' ; 2nd last char a colon ?
JE PATH_20 ; Yes, so skip edit.
PUSH SI ; Store SI for DI
POP DI ; DI-> Last char of pathname
MOV AL,SPACE ; Clear last char of path
STOSB ; Store blank
DEC PATH_LENGTH ; Subtract 1 from path length
PATH_20:
POP ES
CALL RESTORE_BOX
RET
PATH ENDP
;----------------------------------------------------------------------
; Create the Upload command string that the REMOTE computer EXECS
;----------------------------------------------------------------------
MAKE_UP_COM PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH AX ;Store registers
PUSH CX
PUSH DS
PUSH ES
PUSH DI
PUSH SI
PUSHF
PUSH CS
PUSH CS
POP DS ;DS -> CS
POP ES ;ES -> CS
CLD ;Forward Direction Flag
MOV DI,OFFSET UPDNLOAD_COM ;DI -> 1st char of upload com
ADD DI,10D ;DI -> 10th char of upl. com
MOV AL,SPACE ;Reset com string w/ 89
MOV CX,89D ; blanks
MUC_10:
STOSB ;Fill sting with AL
LOOP MUC_10 ;89 chars complete ?
SUB DI,89D ;DI -> 10th char of upl. com
MOV SI,OFFSET UPDN_STRING ;SI -> 1st char of upl. file
MOV CX,UP_LENGTH ;CX = length of string
MUC_20:
LODSB ;AL = char from filename
STOSB ;Upl. com gets char
LOOP MUC_20 ;All chars copied ?
MOV AL,SPACE ;Place a blank char at the
STOSB ; end of filename
MOV SI,OFFSET REMOTE_COM ;SI -> 1st char of comm var.
MOV CX,4D ;Pick off 4 characters
MUC_30:
LODSB ;Pick off 1 char
STOSB ;Place in upl. com string
LOOP MUC_30 ;Entire string done ?
MOV AL,SPACE ;Place a blank at end of comm
STOSB ; string in upl. com string
MOV SI,OFFSET PARM_STRING ;SI -> 1st char of parm
ADD SI,3D ;SI -> 4th char of parm
MOV CX,5D ;Pick off 5 chars from parm
MUC_40:
LODSB ;Pick off 1 char
STOSB ;Place char in upl. com
LOOP MUC_40 ;6 characters done yet ?
MUC_50:
MOV AL,CR ;Carriage return
STOSB
MOV AL,0 ;0 to end string
STOSB
;
; Length of UPDNLOAD_COM must be inserted in the first character of the
; string ("?/c zcopy..."), therefore the length must be determined.
;
MOV SI,OFFSET UPDNLOAD_COM ;SI-> 1st char of string
CALL GET_STRING_LEN ;CX = Length of string
MOV AL,CL ;Ready AL for STOSB instruct.
MOV DI,OFFSET UPDNLOAD_COM ;DI-> 1st char of string
STOSB ;Store AL in string
MUC_RET:
POPF ;Restore registers & flags
POP SI
POP DI
POP ES
POP DS
POP CX
POP AX
RET
MAKE_UP_COM ENDP
;----------------------------------------------------------------------
; Creates the download command string that the REMOTE computer EXECS
;----------------------------------------------------------------------
MAKE_DN_COM PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH AX ;Store registers
PUSH CX
PUSH DS
PUSH ES
PUSH DI
PUSH SI
PUSHF
PUSH CS
PUSH CS
POP DS ;DS -> CS
POP ES ;ES -> CS
CLD ;Forward direction flag
MOV DI,OFFSET UPDNLOAD_COM ;DI -> Download command string
ADD DI,10D ;DI -> 11th char of command
MOV AL,SPACE ;Reset command w/ blanks
MOV CX,89D ; 89 of them...
MDC_10:
STOSB ;Store the blank in command
LOOP MDC_10 ;56 chars. complete ?
SUB DI,89D ;Reset DI to 11th char.
MOV SI,OFFSET REMOTE_COM ;SI -> (C)OMx
MOV CX,4D ;Transfer COMx to com. line
MDC_20:
LODSB ;Pick off a char into AL
STOSB ;Move AL into command
LOOP MDC_20 ;All 4 chars copied ?
MOV AL,SPACE ;Move a blank in after COMx
STOSB ;Store blank
CMP PATH_LENGTH,0 ;Does target directory exist?
JE MDC_40 ;No, skip target dir. copy
MOV SI,OFFSET PATH_STRING ;Yes, SI -> 1st char of dir.
MOV CX,PATH_LENGTH ;CX = length of path string
MDC_30:
LODSB ;Pick off one char
STOSB ;Store char in command line
LOOP MDC_30 ;All chars. copied ?
MOV AL,SPACE ;Move in a blank after dir.
STOSB ;Store blank in line
MDC_40:
MOV SI,OFFSET PARM_STRING ;SI -> 1st char of parm
ADD SI,3D ;SI -> 4th char of parm
MOV CX,5D ;Move in last 5 characters
MDC_50:
LODSB ;Pick off one char.
STOSB ;Copy char in command
LOOP MDC_50 ;All 6 chars copied ?
MDC_60:
MOV AL,CR ;Carriage return
STOSB
MOV AL,0 ;End string with a 0
STOSB
;
; Length of download_com must be inserted in the first character of the
; string ("?/c zcopy..."), therefore the length must be determined.
;
MOV SI,OFFSET UPDNLOAD_COM ;SI-> 1st char of string
CALL GET_STRING_LEN ;CX = Length of string
MOV AL,CL ;Ready AL for STOSB instruct.
MOV DI,OFFSET UPDNLOAD_COM ;DI-> 1st char of string
STOSB ;Store al in string
MDC_RET:
POPF ;Restore registers
POP SI
POP DI
POP ES
POP DS
POP CX
POP AX
RET
MAKE_DN_COM ENDP
;----------------------------------------------------------------------
; Get string length determines the length of the string that DS:SI is
; pointing to. The length is returned in the CX register.
; Input - DS:SI points to the first character of the associated string.
; Output - CX = Length of the string.
; Changes - CX
;----------------------------------------------------------------------
GET_STRING_LEN PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH AX ;Store registers
PUSH SI
PUSHF
CLD ;Go forward in variables
XOR CX,CX ;Reset CX (counter) to zero
GSL_10:
LODSB ;Pick off one character
OR AL,AL ;Is the character a zero ?
JZ GSL_20 ;Yes, return w/ length = CX
INC CX ;No... bump character counter
JMP GSL_10 ;Get another character
GSL_20:
POPF ;Restore registers
POP SI
POP AX
RET
GET_STRING_LEN ENDP
;----------------------------------------------------------------------
; Get current cursor position
; Input - Nothing
; Output - DX contains current cursor position
; Changes - DX
;----------------------------------------------------------------------
GET_CURSOR PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH AX ;Push registers
PUSH BX
MOV BH,0 ;First page
MOV AH,3
INT 10H ;DOS call
POP BX ;Restore registers
POP AX
RET
GET_CURSOR ENDP
;--------------------------------------------------------------------
; Places cursor in the DX position.
; Input - DX
; Output - Cursor placement
; Changes - Nothing
;--------------------------------------------------------------------
PUT_CURSOR PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH AX ;Push registers
PUSH BX
MOV AH,2
MOV BH,0 ;First page
INT 10H ;DOS call
POP BX ;Restore registers
POP AX
RET
PUT_CURSOR ENDP
;--------------------------------------------------------------------
; Inputs a character string from the keyboard. Characters will be
; accepted until the user presses the return, ESC or CX chars. have
; been received from keyboard.
; Input - ES:DI Points to the buffer that is to receive the string.
; CX Contains the length of the input buffer.
; Output -CX Contains the actual length of the character string.
; AX Contains the last keystroke
; The specified buffer contains the character string that was
; entered.
;---------------------------------------------------------------------
GETSTRING PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH BX
PUSH DI ;Store Registers
PUSH DX
PUSHF
CLD ;Direction Flag Forward
XOR BH,BH ;Screen page 0
XOR DX,DX ;Reset character counter
GS_10:
XOR AH,AH ;Function 0 -INT16H- Read key
INT 16H ;Read character from keys
CMP AL,CR ;Carriage Return ?
JE GS_30 ;Yes
CMP AL,ESC_KEY ;Escape key ?
JE GS_30 ;Yes
CMP AL,BS ;Back space ?
JNE GS_14 ;No
CMP DX,0 ;Yes, but 1st char. ?
JE GS_10 ;Yes, so skip BS & get a key
GS_14:
STOSB ;No... Store Character
INC DX ;Bump character counter
MOV AH,14 ;Function 14 -INT10H-
INT 10H ;Display character
CMP AL,BS ;Was last char a backspace ?
JNE GS_20 ;No
GS_15:
SUB DX,2 ;Decrement char count twice
SUB DI,2 ;Move PTR back 2 spaces
ADD CX,2 ;Move in two spaces
MOV AH,14 ;Display character interrupt
MOV AL,SPACE ;Space
INT 10H ;Display character
MOV AH,14 ;Display character interrupt
MOV AL,BS ;Backspace
INT 10H ;Display character
GS_20:
LOOP GS_10 ;Size = # of characters
GS_30:
MOV CX,DX ;Save # of chars. in CX
POPF ;Restore Registers
POP DX
POP DI
POP BX
RET
GETSTRING ENDP
;------------------------------------------------------------
; Input - DS:SI must point to the 1st char of the string to be
; sent to the host computer.
; Output - The entire string is sent to the host computer until
; a ZERO (end of string) is found.
; Changes - SI,AL
;------------------------------------------------------------
SEND_STRING PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSHF ;Store Direction Flag
CLD
SZ_10:
LODSB ;Get AL
CMP AL,0 ;Done with string ?
JE SZ_EXIT ;Yes...
CALL GET_SEND_CODE ;No...get & send scan
JMP SZ_10 ;Repeat until done
SZ_EXIT:
POPF ;Restore Direction Flag
RET
SEND_STRING ENDP
;------------------------------------------------------------
; Input - AL contains the ASCII code of the character to be
; sent to the host computer.
; Output - AX is sent to the host computer where
; AL is ASCII code
; AH is the associated scan code for the ASCII code
; Changes - Nothing
;------------------------------------------------------------
GET_SEND_CODE PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH AX ;Store Registers
PUSH BX
PUSH CX
PUSH SI
PUSHF
CMP AL,'a' ;Small Case letter ?
JL GSC_10 ;No ....
CMP AL,'z'
JG GSC_10 ;No ....
SUB AL,32D ;Yes ....
GSC_10:
MOV BL,AL ;Save ASCII code
MOV CX,0 ;Reset counter into var.
MOV SI,OFFSET ASCII_CODE ;DS:SI -> ASCII variable
CLD ;Forward
GSC_20:
CMP CX,70D ;Invalid ASCII ?
JE GSC_EXIT ;Yes...
INC CX ;Bump counter
LODSB ;AL = next char in var.
CMP AL,BL ;Find correct offset ?
JNE GSC_20 ;No...
GSC_30: ;Yes... so bump that far
MOV SI,OFFSET SCAN_CODE ;into scan_code var and
CLD ;pick off that scan_code.
GSC_40:
LODSB
LOOP GSC_40
GSC_50:
MOV AH,AL ;AH = scan-code
MOV AL,BL ;AL = ASCII code
CALL SEND_KEYSTROKE ;Send AX
GSC_EXIT:
POPF ;Restore registers
POP SI
POP CX
POP BX
POP AX
RET
GET_SEND_CODE ENDP
;-----------------------------------------------------------------
; Execute ZCOPY (upload/download) or shell to DOS and return to
; the calling program.
;-----------------------------------------------------------------
EXEC_ZCOPY PROC NEAR
CMP BYTE PTR NOEXEC,0FFH
JNZ EZ_10
JMP EZ_EXIT
EZ_10:
PUSH AX ;Store all registers
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH DS
PUSH ES
PUSH BP
PUSH CS
PUSH CS
POP DS
POP ES
CMP EXEC_VAL,1D ;Shelling to DOS ?
JE EZ_20 ;Yes, display shell prompt
CMP EXEC_VAL,2D ;Downloading from host ?
JE EZ_30 ;Yes, display transfer prompt
CMP EXEC_VAL,3D ;Uploading from host ?
JE EZ_30 ;Yes, display transfer prompt
JMP EZ_60 ;EXEC_VAL has wrong value !
EZ_20:
MOV AX,OFFSET NUL_TAIL ;Shell to DOS
MOV SI,OFFSET SHELL_PROMPT ;Notify user of shell
JMP EZ_40
EZ_30:
MOV AX,OFFSET UPDNLOAD_COM ;Uploading
MOV SI,OFFSET TRANSFER_PROMPT ;Notify transferring
EZ_40:
MOV PAR_BLK+2,AX ;EXEC
CALL CLEAR_SCREEN ;Clear remote screen
CALL GET_STRING_LEN ;Get string length of DS:SI
PUSH ES ;Store registers & flags
PUSH DI
PUSHF ;Store flag
MOV AX,VIDEO_SEGMENT ;AX->1st char of video segment
MOV ES,AX ;ES->1st char of video segment
XOR DI,DI ;ES:DI-> 1st char of video seg
CLD ;Forward in video segment
EZ_50:
LODSB ;Pick off char in string
CALL PUT_VIDEO_DATA ; and place in video segment
MOV AL,70H ;Place reverse video
CALL PUT_VIDEO_DATA ; in video segment
LOOP EZ_50 ;All characters displayed ?
POPF ;Restore flags
POP DI ;Restore registers
POP ES
MOV DH,2D ;Row 2
XOR DL,DL ;Col 0
CALL PUT_CURSOR ;Place cursor on screen
CALL SET_ENV
CMP BYTE PTR NOEXEC,0FFH
JZ EZ_60
PUSH DS
PUSH ES
MOV OLD_SS,SS
MOV OLD_SP,SP
MOV BX,OFFSET PAR_BLK
LDS DX,CS:COMSPC
MOV AX,4B00H
INT 21H
;
; return from DOS exec
;
MOV SS,CS:OLD_SS
MOV SP,CS:OLD_SP
MOV ES,CS:PAR_BLK
MOV AH,49H
INT 21H
POP ES
POP DS
EZ_60:
POP BP
POP ES
POP DS
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX
EZ_EXIT:
RET
EXEC_ZCOPY ENDP
;-----------------------------------------------------------------------
; Find the string pointed to by DS:SI in the segment pointed to by ES
; ES:0000 is assumed to contain null terminated stings.
; Input - ES points to environment segment
; SI points to search string
; Output - Zero set - could not locate string
; Zero reset - found the string, ES:DI points to end of string
; found. DI is also count of characters up to
; end of string.
; Changes -
;-----------------------------------------------------------------------
FIND_SI PROC NEAR
XOR DI,DI ;Zero environment pointer
FNDSI1: MOV BX,SI ;Save the source string
CMP BYTE PTR ES:[DI],00 ;End of environment space?
JNZ FNDSI2 ; no
RET ; yes, return with zero set
FNDSI2:
MOV AL,[BX] ;Get source string character
OR AL,AL ;End of string?
JZ FNDSI4 ; yes
CMP AL,ES:[DI] ; no, Same as environment char?
JNZ FNDSI3 ; no, string doesn't match
INC BX ; yes, check the next char
INC DI ; in both strings
JMP FNDSI2
FNDSI3:
XOR AL,AL ;Null string terminator
MOV CX,-0001 ;Make sure to find string end
CLD
REPNZ SCASB ;Find the end of this string
JMP FNDSI1 ;Test the next string
FNDSI4:
XOR AX,AX ;Located the string
INC AX ;Reset the zero flag
RET
FIND_SI ENDP
;-----------------------------------------------------------------
; SET NEW ENVIRONMENT
;
;-----------------------------------------------------------------
SET_ENV PROC NEAR
PUSH DS
PUSH ES
MOV ES,DS:[002CH] ;Environment segment pointer
MOV SI,OFFSET PMTSTR ;Pointer to "PROMPT="
CALL FIND_SI ;Is "PROMPT=" in environment?
JNZ GOTPMT ; yes
XOR DI,DI ; no, set length to 0
;
; DI = number of characters in environment to end of "PROMPT=" string.
;
GOTPMT:
MOV BX,DI ;Save the count
XOR DI,DI
MOV AX,DI
MOV CX,0FFFFH
CLD
REPNZ SCASW ;Locate the end of the string
MOV AX,PMTLGT
ADD AX,DI
CMP BX,0000
JNZ PMTHER
ADD AX,(OFFSET PCRSTR) - (OFFSET DFTPMT)
PMTHER:
MOV CL,04
SHR AX,CL
INC AX
SUB DI,BX
PUSH DI
PUSH BX
MOV BX,AX ;number of paragraphs request
MOV AH,48H ;malloc
INT 21H
JNC NOERR
MOV BYTE PTR NOEXEC,0FFH
NOERR: MOV PAR_BLK,AX ;segment to malloc
MOV ES,AX ;segment to malloc
XOR DI,DI
CLD
POP CX
CMP CX,0000
JNZ DOITAL
MOV CX,PMTLGT
MOV WORD PTR PMTLGT,0000
ADD CX,(OFFSET PCRSTR) - (OFFSET DFTPMT)
MOV SI,OFFSET DFTPMT
REP MOVSB
MOV SI,OFFSET GODPMT
MOV CX,(OFFSET PMTSTR) - (OFFSET GODPMT)
REP MOVSB
;
; FROM ADD TO USERS PROMPT
;
DOITAL:
MOV AX,DS:[002CH]
MOV DS,AX
XOR SI,SI
JCXZ PMTDON
REP MOVSB
;
; IF NO PROMPT=', NEW PROMPT STORED AND WHOLE ENV STORED NEXT
;
PMTDON:
PUSH DS
PUSH SI
PUSH CS
POP DS
MOV SI,OFFSET PCRSTR
MOV CX,PMTLGT
JCXZ NOPMT
REP MOVSB
;
; ANY PROMPT STORED?
;
NOPMT:
POP SI
POP DS
POP CX
REP MOVSB
POP ES
POP DS
RET
SET_ENV ENDP
;----------------------------------------------------------------------
GET_COMSPEC PROC NEAR
PUSH ES
MOV PAR_BLK+04,DS
MOV AX,DS:[002CH]
MOV PAR_BLK,AX
MOV ES,AX
MOV SI,OFFSET COM_VAR
CALL FIND_SI
MOV CS:COM_SEG,ES
MOV CS:COM_OFS,DI
JNZ NO_FND
MOV BYTE PTR NOEXEC,0FFH
NO_FND:
POP ES
RET
GET_COMSPEC ENDP
;----------------------------------------------------------------------
; Switch ES and DS
; Input - Nothing
; Output - ES is in DS and DS is in ES
; Changes - ES, DS
;----------------------------------------------------------------------
SWITCH_DS_ES PROC NEAR
PUSH ES ;Push ES
PUSH DS ;Push DS
POP ES ;Switch ES
POP DS ;with DS
RET
SWITCH_DS_ES ENDP
;----------------------------------------------------------------------
; Put the keystroke data into the output buffer to be sent to unattended
; system
; Input - AX - keystroke data
; Output - Nothing
; Changes - Nothing
;----------------------------------------------------------------------
SEND_KEYSTROKE PROC NEAR
ASSUME CS:CSEG,DS:CSEG,ES:NOTHING,SS:NOTHING
PUSH AX ;Save it
MOV AH,1 ;Use the output buffer
MOV AL,0FEH ;Sync byte, to expect key data
CALL PUT_BUFF_DATA ;Put AL into the output buffer
POP AX ;Get AL back
PUSH AX ;Save AH
MOV AH,1 ;Use the output buffer
CALL PUT_BUFF_DATA ;Put ASCII code in out buffer
POP AX ;Get AH back
PUSH AX ;Save keystroke
MOV AL,AH ;Move it to AL
MOV AH,1 ;Use the output buffer
CALL PUT_BUFF_DATA ;Put scan code in out buffer
POP AX ;Restore keystroke
RET
SEND_KEYSTROKE ENDP
;======================================================================
LAST_BYTE EQU $
CSEG ENDS
END START