mirror of
https://github.com/bobbimanners/emailler.git
synced 2024-10-31 13:08:40 +00:00
511 lines
12 KiB
HTML
511 lines
12 KiB
HTML
|
<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><link rel="stylesheet" type="text/css" href="ca65-doc-style.css"/></head><body><a href="ref_index.html"><h1>ip65 technical reference</h1></a><h1>File : ip65/telnet.s</h1><pre>minimal telnet implementation (dumb terminal emulation only)
|
||
|
to use:
|
||
|
set the following variables - telnet_use_native_charset,telnet_port,telnet_ip
|
||
|
then call telnet_connect
|
||
|
you must also define (and export) these function
|
||
|
telnet_menu - called whenever the F1 key is pressed.
|
||
|
telnet_on_connection - called after succesful connection
|
||
|
</pre><h2 id="functions">functions</h2><table><tr><th>function</th><th>description</th></tr><tr><td id="telnet_connect">telnet_connect</td><td><pre>connect to a remote telnet server
|
||
|
inputs:
|
||
|
telnet_use_native_charset: set to 0 if remote server uses standard ASCII, 1 if remote server uses the 'native' charset (i.e. PETSCII)
|
||
|
telnet_port: port number to connect to
|
||
|
telnet_ip: ip address of remote server
</pre></td></tr></table><h2 id="variables">variables</h2><table><tr><th>variable</th><th>description</th><th>size (bytes)</th></tr><tr><td id="telnet_ip">telnet_ip</td><td>ip address of remote server
</td><td>4</td></tr><tr><td id="telnet_port">telnet_port</td><td>port number to connect to
</td><td>2</td></tr><tr><td id="telnet_use_native_charset">telnet_use_native_charset</td><td> 0 means all data is translated to/from NVT ASCII
</td><td>1</td></tr></table><h2>implementation</h2><pre id="code">;minimal telnet implementation (dumb terminal emulation only)
|
||
|
;to use:
|
||
|
;set the following variables - telnet_use_native_charset,telnet_port,telnet_ip
|
||
|
;then call telnet_connect
|
||
|
;you must also define (and export) these function
|
||
|
; telnet_menu - called whenever the F1 key is pressed.
|
||
|
; telnet_on_connection - called after succesful connection
|
||
|
|
||
|
.include "../inc/common.i"
|
||
|
|
||
|
.import tcp_connect
|
||
|
.import tcp_callback
|
||
|
.import tcp_connect_ip
|
||
|
.import tcp_listen
|
||
|
.importzp KEYCODE_F1
|
||
|
.import tcp_inbound_data_ptr
|
||
|
.import tcp_inbound_data_length
|
||
|
.import tcp_send
|
||
|
.import tcp_send_data_len
|
||
|
.import tcp_close
|
||
|
.import print_a
|
||
|
.import print_cr
|
||
|
.import vt100_init_terminal
|
||
|
.import vt100_process_inbound_char
|
||
|
.import vt100_transform_outbound_char
|
||
|
.import tcp_send_keep_alive
|
||
|
.import timer_read
|
||
|
|
||
|
.import ip65_process
|
||
|
.import get_key_if_available
|
||
|
.import get_filtered_input
|
||
|
.import check_for_abort_key
|
||
|
.import ok_msg
|
||
|
.import failed_msg
|
||
|
.import print
|
||
|
.import print_errorcode
|
||
|
.import native_to_ascii
|
||
|
.import ascii_to_native
|
||
|
|
||
|
.export telnet_connect
|
||
|
.export telnet_use_native_charset
|
||
|
.export telnet_port
|
||
|
.export telnet_ip
|
||
|
|
||
|
.import telnet_menu
|
||
|
.import telnet_on_connection
|
||
|
|
||
|
.segment "IP65ZP" : zeropage
|
||
|
|
||
|
; pointer for moving through buffers
|
||
|
buffer_ptr: .res 2 ; source pointer
|
||
|
|
||
|
.code
|
||
|
|
||
|
;connect to a remote telnet server
|
||
|
;inputs:
|
||
|
;telnet_use_native_charset: set to 0 if remote server uses standard ASCII, 1 if remote server uses the 'native' charset (i.e. PETSCII)
|
||
|
;telnet_port: port number to connect to
|
||
|
;telnet_ip: ip address of remote server
|
||
|
telnet_connect:
|
||
|
lda telnet_use_native_charset
|
||
|
bne :+
|
||
|
jsr vt100_init_terminal
|
||
|
:
|
||
|
ldax #telnet_callback
|
||
|
stax tcp_callback
|
||
|
ldx #3
|
||
|
@copy_dest_ip:
|
||
|
lda telnet_ip,x
|
||
|
sta tcp_connect_ip,x
|
||
|
dex
|
||
|
bpl @copy_dest_ip
|
||
|
|
||
|
ldax telnet_port
|
||
|
jsr tcp_connect
|
||
|
|
||
|
bcc @connect_ok
|
||
|
jsr print_cr
|
||
|
ldax #failed_msg
|
||
|
jsr print
|
||
|
jsr print_cr
|
||
|
jsr print_errorcode
|
||
|
rts
|
||
|
@connect_ok:
|
||
|
|
||
|
jsr telnet_on_connection
|
||
|
|
||
|
ldax #ok_msg
|
||
|
jsr print
|
||
|
jsr print_cr
|
||
|
lda #0
|
||
|
sta connection_closed
|
||
|
sta iac_response_buffer_length
|
||
|
|
||
|
@main_polling_loop:
|
||
|
|
||
|
jsr check_for_abort_key
|
||
|
bcc @no_abort
|
||
|
jsr tcp_close
|
||
|
jmp @disconnected
|
||
|
|
||
|
@no_abort:
|
||
|
jsr timer_read
|
||
|
txa
|
||
|
adc #$20 ;32 x 1/4 = ~ 8seconds
|
||
|
sta telnet_timeout
|
||
|
@wait_for_keypress:
|
||
|
jsr timer_read
|
||
|
cpx telnet_timeout
|
||
|
bne @no_timeout
|
||
|
jsr tcp_send_keep_alive
|
||
|
jmp @main_polling_loop
|
||
|
@no_timeout:
|
||
|
jsr ip65_process
|
||
|
lda connection_closed
|
||
|
beq @not_disconnected
|
||
|
@disconnected:
|
||
|
ldax #disconnected
|
||
|
jsr print
|
||
|
rts
|
||
|
@not_disconnected:
|
||
|
lda iac_response_buffer_length
|
||
|
beq @no_iac_response
|
||
|
ldx #0
|
||
|
stax tcp_send_data_len
|
||
|
stx iac_response_buffer_length
|
||
|
ldax #iac_response_buffer
|
||
|
jsr tcp_send
|
||
|
@no_iac_response:
|
||
|
|
||
|
|
||
|
|
||
|
jsr get_key_if_available
|
||
|
beq @wait_for_keypress
|
||
|
|
||
|
cmp #KEYCODE_F1
|
||
|
bne @not_telnet_menu
|
||
|
jsr telnet_menu
|
||
|
jmp @main_polling_loop
|
||
|
@not_telnet_menu:
|
||
|
|
||
|
ldx #0
|
||
|
stx tcp_send_data_len
|
||
|
stx tcp_send_data_len+1
|
||
|
|
||
|
ldx telnet_use_native_charset
|
||
|
bne @no_conversion_required
|
||
|
|
||
|
|
||
|
jsr vt100_transform_outbound_char
|
||
|
|
||
|
sta temp_a
|
||
|
tya
|
||
|
bne :+
|
||
|
jmp @main_polling_loop ;Y=0 means nothing to send
|
||
|
:
|
||
|
|
||
|
cmp #2
|
||
|
beq :+
|
||
|
lda temp_a
|
||
|
jmp @no_conversion_required
|
||
|
:
|
||
|
|
||
|
|
||
|
lda temp_a
|
||
|
stax buffer_ptr
|
||
|
ldy #0
|
||
|
:
|
||
|
lda (buffer_ptr),y
|
||
|
beq @send_char
|
||
|
sta scratch_buffer,y
|
||
|
inc tcp_send_data_len
|
||
|
iny
|
||
|
bne :-
|
||
|
jmp @send_char
|
||
|
|
||
|
@no_conversion_required:
|
||
|
ldy tcp_send_data_len
|
||
|
sta scratch_buffer,y
|
||
|
inc tcp_send_data_len
|
||
|
|
||
|
@send_char:
|
||
|
|
||
|
ldax #scratch_buffer
|
||
|
jsr tcp_send
|
||
|
bcs @error_on_send
|
||
|
jmp @main_polling_loop
|
||
|
|
||
|
@error_on_send:
|
||
|
ldax #transmission_error
|
||
|
jsr print
|
||
|
jmp print_errorcode
|
||
|
|
||
|
|
||
|
;tcp callback - will be executed whenever data arrives on the TCP connection
|
||
|
telnet_callback:
|
||
|
|
||
|
lda tcp_inbound_data_length+1
|
||
|
cmp #$ff
|
||
|
bne @not_eof
|
||
|
lda #1
|
||
|
sta connection_closed
|
||
|
rts
|
||
|
@not_eof:
|
||
|
|
||
|
ldax tcp_inbound_data_ptr
|
||
|
stax buffer_ptr
|
||
|
lda tcp_inbound_data_length
|
||
|
sta buffer_length
|
||
|
lda tcp_inbound_data_length+1
|
||
|
sta buffer_length+1
|
||
|
|
||
|
@next_byte:
|
||
|
ldy #0
|
||
|
lda (buffer_ptr),y
|
||
|
tax
|
||
|
lda telnet_use_native_charset
|
||
|
beq :+
|
||
|
jmp @no_conversion_req
|
||
|
:
|
||
|
|
||
|
;if we get here, we are in ASCII 'char at a time' mode, so look for (and process) Telnet style IAC bytes
|
||
|
lda telnet_state
|
||
|
cmp #telnet_state_got_command
|
||
|
bne :+
|
||
|
jmp @waiting_for_option
|
||
|
:
|
||
|
cmp #telnet_state_got_iac
|
||
|
beq @waiting_for_command
|
||
|
cmp #telnet_state_got_suboption
|
||
|
beq @waiting_for_suboption_end
|
||
|
; we must be in 'normal' mode
|
||
|
txa
|
||
|
cmp #255
|
||
|
beq :+
|
||
|
jmp @not_iac
|
||
|
:
|
||
|
lda #telnet_state_got_iac
|
||
|
sta telnet_state
|
||
|
jmp @byte_processed
|
||
|
|
||
|
@waiting_for_suboption_end:
|
||
|
txa
|
||
|
|
||
|
ldx iac_suboption_buffer_length
|
||
|
sta iac_suboption_buffer,x
|
||
|
inc iac_suboption_buffer_length
|
||
|
cmp #$f0 ;SE - suboption end
|
||
|
bne @exit_suboption
|
||
|
|
||
|
lda #telnet_state_normal
|
||
|
sta telnet_state
|
||
|
lda iac_suboption_buffer
|
||
|
cmp #$18
|
||
|
bne @not_terminal_type
|
||
|
|
||
|
ldx #0
|
||
|
:
|
||
|
lda terminal_type_response,x
|
||
|
ldy iac_response_buffer_length
|
||
|
inc iac_response_buffer_length
|
||
|
sta iac_response_buffer,y
|
||
|
inx
|
||
|
txa
|
||
|
cmp #terminal_type_response_length
|
||
|
bne :-
|
||
|
|
||
|
@not_terminal_type:
|
||
|
|
||
|
@exit_suboption:
|
||
|
jmp @byte_processed
|
||
|
@waiting_for_command:
|
||
|
txa
|
||
|
sta telnet_command
|
||
|
cmp #$fa ; SB - suboption begin
|
||
|
beq @suboption
|
||
|
cmp #$fb ;WILL
|
||
|
beq @option
|
||
|
cmp #$fc ;WONT
|
||
|
beq @option
|
||
|
cmp #$fd ; DO
|
||
|
beq @option
|
||
|
cmp #$fe ;DONT
|
||
|
beq @option
|
||
|
;we got a command we don't understand - just ignore it
|
||
|
lda #telnet_state_normal
|
||
|
sta telnet_state
|
||
|
jmp @byte_processed
|
||
|
@suboption:
|
||
|
|
||
|
lda #telnet_state_got_suboption
|
||
|
sta telnet_state
|
||
|
lda #0
|
||
|
sta iac_suboption_buffer_length
|
||
|
jmp @byte_processed
|
||
|
|
||
|
@option:
|
||
|
lda #telnet_state_got_command
|
||
|
sta telnet_state
|
||
|
jmp @byte_processed
|
||
|
|
||
|
@waiting_for_option:
|
||
|
;we have now got IAC, <command>, <option>
|
||
|
txa
|
||
|
sta telnet_option
|
||
|
lda telnet_command
|
||
|
|
||
|
cmp #$fb
|
||
|
beq @iac_will
|
||
|
|
||
|
cmp #$fc
|
||
|
beq @iac_wont
|
||
|
|
||
|
cmp #$fe
|
||
|
beq @iac_dont
|
||
|
|
||
|
;if we get here, then it's a "do"
|
||
|
|
||
|
|
||
|
lda telnet_option
|
||
|
|
||
|
cmp #$18 ;terminal type
|
||
|
beq @do_terminaltype
|
||
|
|
||
|
cmp #$1f
|
||
|
beq @do_naws
|
||
|
|
||
|
|
||
|
;if we get here, then it's a "do" command we don't honour
|
||
|
|
||
|
@iac_dont:
|
||
|
lda #$fc ;wont
|
||
|
@add_iac_response:
|
||
|
ldx iac_response_buffer_length
|
||
|
sta iac_response_buffer+1,x
|
||
|
lda #255
|
||
|
sta iac_response_buffer,x
|
||
|
lda telnet_option
|
||
|
sta iac_response_buffer+2,x
|
||
|
|
||
|
inc iac_response_buffer_length
|
||
|
inc iac_response_buffer_length
|
||
|
inc iac_response_buffer_length
|
||
|
@after_set_iac_response:
|
||
|
lda #telnet_state_normal
|
||
|
sta telnet_state
|
||
|
jmp @byte_processed
|
||
|
@iac_will:
|
||
|
lda telnet_option
|
||
|
cmp #$01 ;ECHO
|
||
|
beq @will_echo
|
||
|
cmp #$03 ;DO SUPPRESS GA
|
||
|
beq @will_suppress_ga
|
||
|
|
||
|
@iac_wont:
|
||
|
lda #$fe ;dont
|
||
|
jmp @add_iac_response
|
||
|
|
||
|
@will_echo:
|
||
|
lda #$fd ;DO
|
||
|
jmp @add_iac_response
|
||
|
|
||
|
@will_suppress_ga:
|
||
|
lda #$fd ;DO
|
||
|
jmp @add_iac_response
|
||
|
|
||
|
@do_naws:
|
||
|
ldx #0
|
||
|
:
|
||
|
lda naws_response,x
|
||
|
ldy iac_response_buffer_length
|
||
|
inc iac_response_buffer_length
|
||
|
sta iac_response_buffer,y
|
||
|
inx
|
||
|
txa
|
||
|
cmp #naws_response_length
|
||
|
bne :-
|
||
|
|
||
|
jmp @after_set_iac_response
|
||
|
|
||
|
@do_terminaltype:
|
||
|
lda #$fb ;WILL
|
||
|
jmp @add_iac_response
|
||
|
|
||
|
|
||
|
@not_iac:
|
||
|
@convert_to_native:
|
||
|
txa
|
||
|
jsr vt100_process_inbound_char
|
||
|
jmp @byte_processed
|
||
|
@no_conversion_req:
|
||
|
txa
|
||
|
jsr print_a
|
||
|
@byte_processed:
|
||
|
inc buffer_ptr
|
||
|
bne :+
|
||
|
inc buffer_ptr+1
|
||
|
:
|
||
|
lda buffer_length+1
|
||
|
beq @last_page
|
||
|
lda buffer_length
|
||
|
bne @not_end_of_page
|
||
|
dec buffer_length+1
|
||
|
@not_end_of_page:
|
||
|
dec buffer_length
|
||
|
jmp @next_byte
|
||
|
@last_page:
|
||
|
dec buffer_length
|
||
|
beq @finished
|
||
|
|
||
|
jmp @next_byte
|
||
|
|
||
|
@finished:
|
||
|
|
||
|
rts
|
||
|
|
||
|
;constants
|
||
|
closing_connection: .byte "CLOSING CONNECTION",13,0
|
||
|
disconnected: .byte 13,"CONNECTION CLOSED",13,0
|
||
|
transmission_error: .byte "ERROR WHILE SENDING ",0
|
||
|
|
||
|
;initial_telnet_options:
|
||
|
; .byte $ff,$fb,$1F ;IAC WILL NAWS
|
||
|
; .byte $ff,$fb,$18 ;IAC WILL TERMINAL TYPE
|
||
|
|
||
|
;initial_telnet_options_length=*-initial_telnet_options
|
||
|
|
||
|
terminal_type_response:
|
||
|
.byte $ff ; IAC
|
||
|
.byte $fa; SB
|
||
|
.byte $18 ; TERMINAL TYPE
|
||
|
.byte $0 ; IS
|
||
|
.byte "vt100" ;what we pretend to be
|
||
|
.byte $ff ; IAC
|
||
|
.byte $f0 ; SE
|
||
|
terminal_type_response_length=*-terminal_type_response
|
||
|
|
||
|
|
||
|
naws_response:
|
||
|
.byte $ff,$fb,$1F ;IAC WILL NAWS
|
||
|
.byte $ff ; IAC
|
||
|
.byte $fa; SB
|
||
|
.byte $1F ; NAWS
|
||
|
.byte $00 ; width (high byte)
|
||
|
.byte 40 ; width (low byte)
|
||
|
.byte $00 ; height (high byte)
|
||
|
.byte 25 ; height (low byte)
|
||
|
|
||
|
.byte $ff ; IAC
|
||
|
.byte $f0 ; SE
|
||
|
|
||
|
naws_response_length=*-naws_response
|
||
|
|
||
|
|
||
|
;variables
|
||
|
.segment "APP_SCRATCH"
|
||
|
telnet_ip: .res 4 ;ip address of remote server
|
||
|
telnet_port: .res 2 ;port number to connect to
|
||
|
telnet_timeout: .res 1
|
||
|
connection_closed: .res 1
|
||
|
telnet_use_native_charset: .res 1 ; 0 means all data is translated to/from NVT ASCII
|
||
|
buffer_offset: .res 1
|
||
|
telnet_command: .res 1
|
||
|
telnet_option: .res 1
|
||
|
|
||
|
telnet_state_normal = 0
|
||
|
telnet_state_got_iac = 1
|
||
|
telnet_state_got_command = 2
|
||
|
telnet_state_got_suboption=3
|
||
|
|
||
|
buffer_length: .res 2
|
||
|
|
||
|
telnet_state: .res 1
|
||
|
temp_a: .res 1
|
||
|
iac_response_buffer: .res 64
|
||
|
iac_response_buffer_length: .res 1
|
||
|
scratch_buffer : .res 40
|
||
|
iac_suboption_buffer: .res 64
|
||
|
iac_suboption_buffer_length: .res 1
|
||
|
|
||
|
|
||
|
;-- LICENSE FOR telnet.s --
|
||
|
; The contents of this file are subject to the Mozilla Public License
|
||
|
; Version 1.1 (the "License"); you may not use this file except in
|
||
|
; compliance with the License. You may obtain a copy of the License at
|
||
|
; http://www.mozilla.org/MPL/
|
||
|
;
|
||
|
; Software distributed under the License is distributed on an "AS IS"
|
||
|
; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||
|
; License for the specific language governing rights and limitations
|
||
|
; under the License.
|
||
|
;
|
||
|
; The Original Code is ip65.
|
||
|
;
|
||
|
; The Initial Developer of the Original Code is Jonno Downes,
|
||
|
; jonno@jamtronix.com.
|
||
|
; Portions created by the Initial Developer are Copyright (C) 2009
|
||
|
; Jonno Downes. All Rights Reserved.
|
||
|
; -- LICENSE END --
|
||
|
</pre></body></html>
|