;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;    TERMINAL
;
;    Compile with FASM for Menuet
;

use32
 org	0x0
 db	'MENUET01'    ; header
 dd	0x01	      ; header version
 dd	START	      ; entry point
 dd	I_END	      ; image size
 dd	I_END+0x10000 ; required memory
 dd	I_END+0x10000 ; esp
 dd	0x0 , 0x0     ; I_Param , I_Path


include 'lang.inc'
include '..\..\..\macros.inc'

START:				; start of execution

    ; Clear the screen memory
    mov     eax, '    '
    mov     edi,text
    mov     ecx,80*30 /4
    cld
    rep     stosd


    call draw_window


still:
    ; check connection status
    mov  eax,53
    mov  ebx,6
    mov  ecx,[socket]
    mcall

    mov     ebx, [socket_status]
    mov     [socket_status], eax

    cmp     eax, ebx
    je	    waitev

red:
    call    draw_window

waitev:
    mov  eax,23 		; wait here for event
    mov  ebx,20
    mcall

    cmp  eax,1			; redraw request ?
    je	 red
    cmp  eax,2			; key in buffer ?
    je	 key
    cmp  eax,3			; button in buffer ?
    je	 button

    ; any data from the socket?

    mov     eax, 53
    mov     ebx, 2
    mov     ecx, [socket]
    mcall
    cmp     eax, 0
    jne      read_input

    jmp  still


read_input:

    push ecx
    mov     eax, 53
    mov     ebx, 3
    mov     ecx, [socket]
    mcall
    pop  ecx

    call    handle_data

    push    ecx
    mov     eax, 53
    mov     ebx, 2
    mov     ecx, [socket]
    mcall
    pop     ecx
    cmp     eax, 0


    jne   read_input
    call draw_text
    jmp  still



handle_data:
    ; Telnet servers will want to negotiate options about our terminal window
    ; just reject them all.
    ; Telnet options start with the byte 0xff and are 3 bytes long.

    mov     al, [telnetstate]
    cmp     al, 0
    je	    state0
    cmp     al, 1
    je	    state1
    cmp     al, 2
    je	    state2
    jmp     hd001

state0:
    cmp     bl, 255
    jne     hd001
    mov     al, 1
    mov     [telnetstate], al
    ret

state1:
    mov     al, 2
    mov     [telnetstate], al
    ret

state2:
    mov     al, 0
    mov     [telnetstate], al
    mov     [telnetrep+2], bl

    mov     edx, 3
    mov     eax,53
    mov     ebx,7
    mov     ecx,[socket]
    mov     esi, telnetrep
    mcall
    ret

hd001:
    cmp  bl,13				; BEGINNING OF LINE
    jne  nobol
    mov  ecx,[pos]
    add  ecx,1
  boll1:
    sub  ecx,1
    mov  eax,ecx
    xor  edx,edx
    mov  ebx,80
    div  ebx
    cmp  edx,0
    jne  boll1
    mov  [pos],ecx
    jmp  newdata
  nobol:

    cmp  bl,10				  ; LINE DOWN
    jne  nolf
   addx1:
    add  [pos],dword 1
    mov  eax,[pos]
    xor  edx,edx
    mov  ecx,80
    div  ecx
    cmp  edx,0
    jnz  addx1
    mov  eax,[pos]
    jmp  cm1
  nolf:

    cmp  bl,8				 ; BACKSPACE
    jne  nobasp
    mov  eax,[pos]
    dec  eax
    mov  [pos],eax
    mov  [eax+text],byte 32
    mov  [eax+text+60*80],byte 0
    jmp  newdata
   nobasp:

    cmp  bl,15				 ; CHARACTER
    jbe  newdata
    mov  eax,[pos]
    mov  [eax+text],bl
    mov  eax,[pos]
    add  eax,1
  cm1:
    mov  ebx,[scroll+4]
    imul ebx,80
    cmp  eax,ebx
    jb	 noeaxz
    mov  esi,text+80
    mov  edi,text
    mov  ecx,ebx
    cld
    rep  movsb
    mov  eax,ebx
    sub  eax,80
  noeaxz:
    mov  [pos],eax
  newdata:
    ret

  key:				; KEY
    mov  eax,2			; send to modem
    mcall

    mov     ebx, [socket_status]
    cmp     ebx, 4		; connection open?
    jne     still		; no, so ignore key

    shr  eax,8
    cmp  eax,178		; ARROW KEYS
    jne  noaup
    mov  al,'A'
    call arrow
    jmp  still
  noaup:
    cmp  eax,177
    jne  noadown
    mov  al,'B'
    call arrow
    jmp  still
  noadown:
    cmp  eax,179
    jne  noaright
    mov  al,'C'
    call arrow
    jmp  still
  noaright:
    cmp  eax,176
    jne  noaleft
    mov  al,'D'
    call arrow
    jmp  still
  noaleft:
  modem_out:

    call    to_modem

    jmp  still

  button:			; BUTTON
    mov  eax,17
    mcall
    cmp  ah,1			; CLOSE PROGRAM
    jne  noclose

    mov  eax,53
    mov  ebx,8
    mov  ecx,[socket]
    mcall

     or   eax,-1
     mcall
  noclose:
    cmp     ah, 2		; Set IP
    jne     notip

    mov  [string_x], dword 78
    mov  [string_y], dword 276
    mov  [string_length], dword 15
    call read_string
    mov   esi,string-1
    mov   edi,ip_address
    xor   eax,eax
   ip1:
    inc   esi
    cmp   [esi],byte '0'
    jb	  ip2
    cmp   [esi],byte '9'
    jg	  ip2
    imul  eax,10
    movzx ebx,byte [esi]
    sub   ebx,48
    add   eax,ebx
    jmp   ip1
   ip2:
    mov   [edi],al
    xor   eax,eax
    inc   edi
    cmp   edi,ip_address+3
    jbe   ip1
    call draw_window


    jmp     still

notip:
    cmp     ah, 3		; set port
    jne     notport

    mov  [string_x], dword 215
    mov  [string_y], dword 276
    mov  [string_length], dword 4
    call read_string
    mov   esi,string-1
    mov   edi,port
    xor   eax,eax
   ip11:
    inc   esi
    cmp   [esi],byte '0'
    jb	  ip21
    cmp   [esi],byte '9'
    jg	  ip21
    imul  eax,10
    movzx ebx,byte [esi]
    sub   ebx,48
    add   eax,ebx
    jmp   ip11
   ip21:
    mov   [edi],al
    inc   edi
    mov   [edi],ah
    call draw_window


    jmp     still

notport:
    cmp     ah, 4		; connect
    jne     notcon

    mov     eax, [socket_status]
    cmp     eax, 4
    je	   still
    call    connect

    jmp     still

notcon:
    cmp     ah,5		; disconnect
    jne     notdiscon

    call    disconnect
    jmp  still

notdiscon:			; Echo Toggle
    cmp     ah, 6
    jne     still

    mov     al, [echo]
    not     al
    mov     [echo], al

    call    draw_window
    jmp     still

arrow:

    push eax
    mov  al,27
    call to_modem
    mov  al,'['
    call to_modem
    pop  eax
    call to_modem

    ret


to_modem:
    pusha
    push    ax
    mov     [tx_buff], al
    mov     edx, 1
    cmp     al, 13
    jne     tm_000
    mov     edx, 2
tm_000:
    mov     eax,53
    mov     ebx,7
    mov     ecx,[socket]
    mov     esi, tx_buff
    mcall
    pop     bx
    mov     al, [echo]
    cmp     al, 0
    je	    tm_001

    push    bx
    call    handle_data
    pop     bx

    cmp     bl, 13
    jne     tm_002

    mov     bl, 10
    call    handle_data

tm_002:
    call    draw_text

tm_001:
    popa
    ret



disconnect:
    mov  eax,53
    mov  ebx,8
    mov  ecx,[socket]
    mcall
    ret



connect:
    pusha

 mov	 ecx, 1000  ; local port starting at 1000

getlp:
 inc	 ecx
 push ecx
 mov	 eax, 53
 mov	 ebx, 9
 mcall
 pop	 ecx
 cmp	 eax, 0   ; is this local port in use?
 jz  getlp	; yes - so try next

    mov     eax,53
    mov     ebx,5
    mov     dl, [ip_address + 3]
    shl     edx, 8
    mov     dl, [ip_address + 2]
    shl     edx, 8
    mov     dl, [ip_address + 1]
    shl     edx, 8
    mov     dl, [ip_address]
    mov     esi, edx
    movzx   edx, word [port]	  ; telnet port id
    mov     edi,1      ; active open
    mcall
    mov     [socket], eax

    popa

    ret



;   *********************************************
;   *******  WINDOW DEFINITIONS AND DRAW ********
;   *********************************************


draw_window:

    pusha

    mov  eax,12
    mov  ebx,1
    mcall

    xor  eax,eax		     ; DRAW WINDOW
    mov  ebx,100*65536+491 + 8 +15
    mov  ecx,100*65536+270 + 20     ; 20 for status bar
    mov  edx,0x13000000
    mov  edi,title
    mcall

    ; draw status bar
    mov     eax, 13
    mov     ebx, 4*65536+484 + 8 +15
    mov     ecx, 270*65536 + 3
    mov     edx, 0x00557799
    mcall

    mov  eax,8			   ; BUTTON 2: SET IP
    mov  ebx,4*65536+70
    mov  ecx,273*65536+12
    mov     esi, 0x00557799
    mov  edx,2
    mcall

    mov  eax,4			   ; Button text
    mov  ebx,6*65536+276
    mov  ecx,0x00ffffff
    mov  edx,setipt
    mov  esi,setiplen-setipt
    mcall


    mov  eax,47
    mov  edi,ip_address 	    ; display IP address
    mov  edx,78*65536+276
    mov  esi,0x00ffffff
    mov  ebx,3*65536
  ipdisplay:
    movzx ecx,byte [edi]
    mcall
    add  edx,6*4*65536
    inc  edi
    cmp  edi,ip_address+4
    jb	 ipdisplay

    mov  eax,8			   ; BUTTON 3: SET PORT
    mov  ebx,173*65536+38
    mov  ecx,273*65536+12
    mov  edx,3
    mov     esi, 0x00557799
    mcall

    mov  eax,4			   ; Button text
    mov  ebx,178*65536+276
    mov  ecx,0x00ffffff
    mov  edx,setportt
    mov  esi,setportlen-setportt
    mcall


    mov  edx,216*65536+276	     ; display port
    mov  esi,0x00ffffff
    mov  ebx,4*65536
    mov  eax,47
    movzx  ecx,word [port]
    mcall

    mov  eax,8			   ; BUTTON 4: Connect
    mov  ebx,250*65536+50
    mov  ecx,273*65536+12
    mov     esi, 0x00557799
    mov  edx,4
    mcall

    mov  eax,4			   ; Button text
    mov  ebx,255*65536+276
    mov  ecx,0x00ffffff
    mov  edx,cont
    mov  esi,conlen-cont
    mcall


    mov  eax,8			   ; BUTTON 5: disconnect
    mov  ebx,303*65536+70
    mov  ecx,273*65536+12
    mov  edx,5
    mov     esi, 0x00557799
    mcall


    mov  eax,4			   ; Button text
    mov  ebx,307*65536+276
    mov  ecx,0x00ffffff
    mov  edx,dist
    mov  esi,dislen-dist
    mcall


    mov  esi,contlen-contt	    ; display connected status
    mov     edx, contt
    mov     eax, [socket_status]
    cmp     eax, 4		    ; 4 is connected
    je	    pcon
    mov     esi,discontlen-discontt
    mov     edx, discontt
pcon:

    mov  eax,4			   ; status text
    mov  ebx,380*65536+276
    mov  ecx,0x00ffffff
    mcall


    mov  eax,8			   ; BUTTON 6: echo
    mov  ebx,460*65536+50
    mov  ecx,273*65536+12
    mov  edx,6
    mov     esi, 0x00557799
    mcall

    mov  edx,echot
    mov  esi,echolen-echot
    mov     al, [echo]
    cmp     al, 0
    jne     peo
    mov  edx,echoot
    mov  esi,echoolen-echoot

peo:
    mov  eax,4			   ; Button text
    mov  ebx,463*65536+276
    mov  ecx,0x00ffffff
    mcall


    xor  eax,eax
    mov  edi,text+80*30
    mov  ecx,80*30 /4
    cld
    rep  stosd

    call draw_text

    mov  eax,12
    mov  ebx,2
    mcall

    popa

    ret


draw_text:

    pusha

    mov  esi,text
    mov  eax,0
    mov  ebx,0
  newletter:
    mov  cl,[esi]
    cmp  cl,[esi+30*80]
    jne  yesletter
    jmp  noletter
  yesletter:
    mov  [esi+30*80],cl

    ; erase character

    pusha
    mov     edx, 0		    ; bg colour
    mov     ecx, ebx
    add     ecx, 26
    shl     ecx, 16
    mov     cx, 9
    mov     ebx, eax
    add     ebx, 6
    shl     ebx, 16
    mov     bx, 6
    mov     eax, 13
    mcall
    popa

    ; draw character

    pusha
    mov     ecx, 0x00ffffff
    push bx
    mov  ebx,eax
    add  ebx,6
    shl  ebx,16
    pop  bx
    add  bx,26
    mov  eax,4
    mov  edx,esi
    mov  esi,1
    mcall
    popa

  noletter:

    add  esi,1
    add  eax,6
    cmp  eax,80*6
    jb	 newletter
    mov  eax,0
    add  ebx,10
    cmp  ebx,24*10
    jb	 newletter

    popa
    ret


read_string:

    mov  edi,string
    mov  eax,'_'
    mov  ecx,[string_length]
    inc     ecx
    cld
    rep  stosb
    call print_text

    mov  edi,string
  f11:
    mov  eax,10
    mcall
    cmp  eax,2
    jne  read_done
    mov  eax,2
    mcall
    shr  eax,8
    cmp  eax,13
    je	 read_done
    cmp  eax,8
    jnz  nobsl
    cmp  edi,string
    jz	 f11
    sub  edi,1
    mov  [edi],byte '_'
    call print_text
    jmp  f11
  nobsl:
    cmp  eax,dword 31
    jbe  f11
    cmp  eax,dword 95
    jb	 keyok
    sub  eax,32
  keyok:
    mov  [edi],al
    call print_text

    inc  edi
    mov  esi,string
    add  esi,[string_length]
    cmp  esi,edi
    jnz  f11

  read_done:

    call print_text

    ret


print_text:

    pusha

    mov  eax,13
    mov  ebx,[string_x]
    shl  ebx,16
    add  ebx,[string_length]
    imul bx,6
    mov  ecx,[string_y]
    shl  ecx,16
    mov  cx,8
    mov  edx,0x00000000
    mcall

    mov  eax,4
    mov  ebx,[string_x]
    shl  ebx,16
    add  ebx,[string_y]
    mov  ecx,0x00ffffff
    mov  edx,string
    mov  esi,[string_length]
    mcall

    popa
    ret




; DATA AREA

telnetrep	db 0xff,0xfc,0x00
telnetstate	db 0

string_length  dd    16
string_x       dd    200
string_y       dd    60

string	       db    '________________'

tx_buff 	db  0, 10
ip_address	db  001,002,003,004
port		db  0,0
echo		db  0
socket		dd  0x0
socket_status	dd  0x0
pos		dd  80 * 1
scroll		dd  1
		dd  24
wcolor		dd  0x000000
title		db  'Telnet v0.1',0
setipt		db  'IP Address:    .   .   .'
setiplen:
setportt	db  'Port:'
setportlen:
cont		db  'Connect'
conlen:
dist		db  'Disconnect'
dislen:
contt		db  'Connected'
contlen:
discontt	db  'Disconnected'
discontlen:
echot	     db  'Echo On'
echolen:
echoot	      db  'Echo Off'
echoolen:



text:
I_END:
