Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 480 → Rev 481

/programs/network/ftps/trunk/FTPS.ASM
0,0 → 1,1624
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; FTPS
; FTP Server
;
; Compile with FASM for Menuet
;
 
; note: telnet == 23, ftp cmd == 21, data on 20
 
use32
 
org 0x0
 
db 'MENUET01' ; 8 byte id
dd 1 ; header version
dd START ; program start
dd I_END ; program image size
dd 0x170000 ; required amount of memory
dd 0x7FFF0 ; esp = 0x7FFF0
dd 0, 0 ; no params, no path
 
include 'macros.inc'
; Various states of client connection
USER_NONE equ 0 ; Awaiting a connection
USER_CONNECTED equ 1 ; User just connected, prompt given
USER_USERNAME equ 2 ; User given username
USER_LOGGED_IN equ 3 ; User given password
 
 
 
 
 
START: ; start of execution
; Clear the screen memory
mov eax, ' '
mov edi,text
mov ecx,80*30 /4
cld
rep stosd
 
call draw_window
 
; init the receive buffer pointer
mov [buffptr], buff
 
; Init FTP server state machine
mov [state], USER_NONE
 
; Open the listening socket
call connect
 
still:
; check connection status
mov eax,53
mov ebx,6 ; Get socket status
mov ecx,[CmdSocket]
int 0x40
 
mov ebx, [CmdSocketStatus]
mov [CmdSocketStatus], eax
 
cmp eax, ebx
je waitev
 
; If the socket closed by remote host, open it again.
cmp eax, 7
je con
; If socket closed by Reset, open it again
cmp eax, 11
je con
 
; If a user has just connected, start by outputting welcome msg
cmp eax, 4
jne noc
 
mov esi, loginStr0
mov edx, loginStr0_end - loginStr0
call outputStr
 
mov [state], USER_CONNECTED
jmp noc
 
 
con:
; Need to call disconnect, since a remote close does not fully
; close the socket
call disconnect
call connect
jmp noc
 
noc:
; Display the changed connected status
call draw_window
 
waitev:
mov eax,23 ; wait here for event
mov ebx,1 ; Delay for up to 1s
int 0x40
 
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 ; Get # of bytes in input queue
mov ecx, [CmdSocket]
int 0x40
test eax, eax
jz still
 
read_input:
mov eax, 53
mov ebx, 3 ; Get a byte from socket in bl
mov ecx, [CmdSocket]
int 0x40
 
call ftpRxCmdData ; process incoming ftp command
 
; Keep processing data until there is no more to process
mov eax, 53
mov ebx, 2 ; Get # of bytes in input queue
mov ecx, [CmdSocket]
int 0x40
cmp eax, 0
jne read_input
 
; Now redraw the text text field.
; Probably not required, since ftp requires no
; console i/o.
; Leave in for now, for debugging.
; (fall through to "red:")
; call draw_text
; jmp still
 
red: ; REDRAW WINDOW
call draw_window
jmp still
 
key: ; KEY
mov eax,2 ; get but ignore
int 0x40
jmp still
 
button:
mov eax,17
int 0x40
cmp ah,1
jne still
 
; Exit button pressed, so close socket and quit
mov eax,53
mov ebx,8
mov ecx,[CmdSocket]
int 0x40
 
; ... terminate program
mov eax,-1
int 0x40
jmp still
 
 
 
; *********************************************
; ******* WINDOW DEFINITIONS AND DRAW ********
; *********************************************
draw_window:
pusha
 
mov eax,12
mov ebx,1
int 0x40
 
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,labelt
int 0x40
 
; draw status bar
mov eax, 13
mov ebx, 4*65536+484 + 8 +15
mov ecx, 270*65536 + 3
mov edx, 0x00557799
int 0x40
 
 
mov esi,contlen-contt ; display connected status
mov edx, contt
cmp [CmdSocketStatus], 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
int 0x40
 
; Draw the text on the screen, clearing it first
; This can go when we loose debuggin info.
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
int 0x40
 
popa
 
ret
 
 
;***************************************************************************
; Function
; draw_text
;
; Description
; Updates the text on the screen. This is part of the debugging code
;
; Inputs
; Character to add in bl
;
;***************************************************************************
draw_text:
 
pusha
 
mov esi,text
mov eax,0
mov ebx,0
newletter:
mov cl,[esi]
cmp cl,[esi+30*80]
jz 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
int 0x40
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
int 0x40
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
 
 
 
;***************************************************************************
; Function
; ftpRxCmdData
;
; Description
; Prcoesses incoming command data, calling a handler for each command.
; Commands are built up in buff before being processed.
;
; Inputs
; Character to add in bl
;
;***************************************************************************
ftpRxCmdData:
; Quit if we are not connected
;( This case shouldn't be necessary, but be safe )
mov al, [state]
cmp al, USER_NONE
je frcd_exit
 
; Store the incoming character
mov esi, [buffptr]
mov [esi], bl
inc esi
mov [buffptr], esi
 
; For debugging, show the data coming in
pusha
call printChar
popa
 
; Do we have an end of line? (LF)
; if not, just exit
cmp bl, 0x0a
jne frcd_exit
 
; OK we have a complete command.
; Process, and send response
 
; There are a number of states involved in ftp,
; to do with logging in.
 
mov al, [state]
cmp al, USER_CONNECTED
jne fs001
 
; This should be the username
 
; TODO validate username
 
; OK, username accepted - ask for password
mov esi, loginStr1
mov edx, loginStr1_end - loginStr1
call outputStr
 
mov [state], USER_USERNAME
 
; init the receive buffer pointer
mov [buffptr], buff
 
jmp frcd_exit
 
fs001:
cmp al, USER_USERNAME
jne fs002
 
; This should be the password
 
; TODO validate password
 
; OK, password accepted - show they are logged in
mov esi, loginStr2
mov edx, loginStr2_end - loginStr2
call outputStr
 
mov [state], USER_LOGGED_IN
 
; init the receive buffer pointer
mov [buffptr], buff
 
jmp frcd_exit
 
fs002:
cmp al, USER_LOGGED_IN
jne fs003
 
; This should be a cmd
call findCmd
mov eax, [cmdPtr]
cmp eax, 0
 
je fs002b
 
call [cmdPtr]
 
fs002a:
; init the receive buffer pointer
mov [buffptr], buff
 
jmp frcd_exit
 
fs002b:
; an unsupported command was entered.
; Tell user that the command is not supported
 
mov esi, unsupStr
mov edx, unsupStr_end - unsupStr
call outputStr
 
jmp fs002a
 
fs003:
frcd_exit:
ret
 
 
 
;***************************************************************************
; Function
; outputStr
;
; Description
; Sends a string over the 'Command' socket
;
; Inputs
; String in esi
; Length in edx
;
;***************************************************************************
outputStr:
push esi
push edx
mov eax,53
mov ebx,7
mov ecx,[CmdSocket]
int 0x40
pop edx
pop esi
cmp eax, 0
je os_exit
; The TCP/IP transmit queue is full; Wait a bit, then retry
pusha
mov eax,5
mov ebx,1 ; Delay for up 100ms
int 0x40
popa
jmp outputStr
os_exit:
ret
 
 
 
;***************************************************************************
; Function
; outputDataStr
;
; Description
; Sends a string over the 'Data' socket
;
; Inputs
; String in esi
; Length in edx
;
;***************************************************************************
outputDataStr:
push esi
push edx
mov eax,53
mov ebx,7
mov ecx,[DataSocket]
int 0x40
pop edx
pop esi
 
cmp eax, 0
je ods_exit
 
; The TCP/IP transmit queue is full; Wait a bit, then retry
pusha
mov eax,5
mov ebx,20 ; Delay for upto 200ms
int 0x40
popa
jmp outputDataStr
ods_exit:
ret
 
 
 
;***************************************************************************
; Function
; printChar
;
; Description
; Writes a character to the screen; Used to display the data coming
; in from the user. Really only useful for debugging.
;
; Inputs
; Character in bl
;
;***************************************************************************
printChar:
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
putcha:
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
 
 
;***************************************************************************
; Function
; disconnect
;
; Description
; Closes the command socket
;
; Inputs
; None
;
;***************************************************************************
disconnect:
mov eax, 53 ; Stack Interface
mov ebx,8 ; Close TCP socket
mov ecx,[CmdSocket]
int 0x40
ret
 
 
;***************************************************************************
; Function
; disconnectData
;
; Description
; Closes the data socket
;
; Inputs
; None
;
;***************************************************************************
disconnectData:
; This delay would be better done by allowing the socket code
; to wait for all data to pass through the stack before closing
pusha
mov eax,5
mov ebx,200 ; Delay for 2s
int 0x40
popa
 
mov eax, 53 ; Stack Interface
mov ebx,8 ; Close TCP socket
mov ecx,[DataSocket]
int 0x40
ret
 
 
 
 
;***************************************************************************
; Function
; connect
;
; Description
; Opens the command socket
;
; Inputs
; None
;
;***************************************************************************
connect:
pusha
 
mov eax, 53 ; Stack Interface
mov ebx, 5 ; Open TCP socket
mov esi, 0 ; No remote IP address
mov edx, 0 ; No remote port
mov ecx, 21 ; ftp command port id
mov edi, 0 ; passive open
int 0x40
mov [CmdSocket], eax
 
popa
 
ret
 
 
 
;***************************************************************************
; Function
; connectData
;
; Description
; Opens the data socket
;
; Inputs
; None
;
;***************************************************************************
connectData:
pusha
 
mov eax, 53 ; Stack Interface
mov ebx, 5 ; Open TCP socket
mov esi, [DataIP] ; remote IP address
mov edx, [DataPort] ; remote port
mov ecx, 20 ; ftp data port id
mov edi, 1 ; active open
int 0x40
mov [DataSocket], eax
 
popa
 
ret
 
 
 
 
;***************************************************************************
; Function
; findCmd
;
; Description
; Scans the command string for a valid command. The command string
; is in the global variable buff.
;
; Returns result in cmdPtr. This will be zero if none found
;
; Inputs
; None
;
;***************************************************************************
findCmd:
; Setup to return 'none' in cmdPtr, if we find no cmd
mov eax, 0
mov [cmdPtr], eax
cld
mov esi, buff
mov edi, CMDList
 
fc000:
cmp [edi], byte 0 ; Are we at the end of the CMDList?
je fc_exit
 
fc000a:
cmpsb
 
je fc_nextbyte
 
; Command is different - move to the next entry in cmd table
mov esi, buff
 
fc001:
; skip to the next command in the list
cmp [edi], byte 0
je fc002
inc edi
jmp fc001
fc002:
add edi, 5
jmp fc000
 
fc_nextbyte:
; Have we reached the end of the CMD text?
cmp [edi], byte 0
je fc_got ; Yes - so we have a match
jmp fc000a ; No - loop back
 
fc_got:
; Copy the function pointer for the selected command
inc edi
mov eax, [edi]
mov [cmdPtr], eax
 
fc_exit:
ret
 
 
 
;***************************************************************************
; Function
; decStr2Byte
;
; Description
; Converts the decimal string pointed to by esi to a byte
;
; Inputs
; string ptr in esi
;
; Outputs
; esi points to next character not in string
; eax holds result ( 0..255)
;
;***************************************************************************
decStr2Byte:
xor eax, eax
xor ebx, ebx
mov ecx, 3
 
dsb001:
mov bl, [esi]
 
cmp bl, '0'
jb dsb_exit
cmp bl, '9'
ja dsb_exit
 
imul eax, 10
add eax, ebx
sub eax, '0'
inc esi
loop dsb001
 
dsb_exit:
ret
 
 
 
;***************************************************************************
; Function
; parsePortStr
;
; Description
; Converts the parameters of the PORT command, and stores them in the
; appropriate variables.
;
; Inputs
; None ( string in global variable buff )
;
; Outputs
; None
;
;***************************************************************************
parsePortStr:
; skip past the PORT text to get the the parameters. The command format
; is
; PORT i,i,i,i,p,p,0x0d,0x0a
; where i and p are decimal byte values, high byte first.
xor eax, eax
mov [DataIP], eax
mov [DataPort], eax
mov esi, buff + 4 ; Start at first space character
 
pps001:
cmp [esi], byte ' ' ; Look for first non space character
jne pps002
inc esi
jmp pps001
 
pps002:
call decStr2Byte
add [DataIP], eax
ror dword [DataIP], 8
inc esi
call decStr2Byte
add [DataIP], eax
ror dword [DataIP], 8
inc esi
call decStr2Byte
add [DataIP], eax
ror dword [DataIP], 8
inc esi
call decStr2Byte
add [DataIP], eax
ror dword [DataIP], 8
inc esi
call decStr2Byte
add [DataPort], eax
shl [DataPort], 8
inc esi
call decStr2Byte
add [DataPort], eax
 
ret
 
 
 
;***************************************************************************
; Function
; sendDir
;
; Description
; Transmits the directory listing over the data connection.
; The data connection is already open.
;
; Inputs
; None
;
; Outputs
; None
;
;***************************************************************************
sendDir:
mov ebx, dirinfoblock
and dword [ebx+4], 0 ; start from zero block
sd001:
; Read the next DirBlocksPerCall (=16) blocks
mov eax, 70
int 0x40
; Did we read anything?
test eax, eax
jz @f
cmp eax, 6
jnz sd_exit
@@:
test ebx, ebx
jz sd_exit
; Parse these blocks. There could be up to 16 files specified
mov esi, text + 0x1300 + 0x20
sd002:
dec ebx
js sd004
push ebx
; OK, lets parse the entry. Ignore volume entries
test byte [esi], 8
jnz sd003
; Valid file or directory. Start to compose the string we will send
mov edi, dirStr
; If we have been called as a result of an NLST command, we only display
; the filename
cmp [buff], byte 'N'
jz sd006
 
mov [edi], byte '-'
test byte [esi], 10h
jz @f
mov [edi], byte 'd'
@@:
; Ok, now copy across the directory listing text that will be constant
; ( I dont bother looking at the read only or archive bits )
 
mov ebx, tmplStr
@@:
inc edi
mov al, [ebx]
test al, al
jz @f
mov [edi], al
inc ebx
jmp @b
@@:
; point to the last character of the string;
; We will write the file size here, backwards
push edi ; Remember where the string ends
 
dec edi
; eax holds the number
mov eax, [esi+32]
mov ebx, 10
@@:
xor edx, edx
div ebx
add dl, '0'
mov [edi], dl
dec edi
test eax, eax
jnz @b
 
pop edi
; now create the time & date fields
;timeStr: db ' Jan 1 2000 ',0
mov al, ' '
stosb
movzx eax, byte [esi+28+1]
mov eax, dword [months + (eax-1)*4]
stosd
mov al, byte [esi+28]
aam
test ah, ah
jz sd005a
xchg al, ah
add ax, '00'
jmp sd005b
sd005a:
add al, '0'
mov ah, ' '
sd005b:
stosw
mov al, ' '
mov ecx, 6
rep stosb
push edi
movzx eax, word [esi+28+2]
@@:
xor edx, edx
div ebx
add dl, '0'
mov [edi], dl
dec edi
test eax, eax
jnz @b
pop edi
inc edi
mov al, ' '
stosb
sd006:
; ** End of copying
 
; now copy the filename across
lea ebx, [esi+40]
@@:
mov al, [ebx]
inc ebx
test al, al
jz @f
stosb
jmp @b
@@:
terminate:
; Now terminate the line by putting CRLF sequence in
mov al, 0x0D
stosb
mov al, 0x0A
stosb
; Send the completed line to the user over data socket
push esi
mov esi, dirStr
mov edx, edi
sub edx, esi
call outputDataStr
pop esi
 
sd003: ; Move to next entry in the block
pop ebx
add esi, 304
jmp sd002
sd004:
mov ebx, dirinfoblock
add dword [ebx+4], DirBlocksPerCall
jmp sd001
 
sd_exit:
ret
 
 
 
 
 
;***************************************************************************
; Function
; setupFilePath
;
; Description
; Copies the file name from the input request string into the
; file descriptor
;
; Inputs
; None
;
; Outputs
; None
;
;***************************************************************************
setupFilePath:
mov esi, buff + 4 ; Point to (1 before) first character of file
; Skip any trailing spaces or / character
sfp001:
inc esi
cmp [esi], byte ' '
je sfp001
cmp [esi], byte '/'
je sfp001
; esi points to start of filename.
; Copy across the directory path '/'
; into the fileinfoblock
mov edi, filename
mov dword [edi], '/RD/'
mov word [edi+4], '1/'
add edi, 6
; Copy across the filename
sfp002:
cld
movsb
cmp [esi], byte 0x0d
jne sfp002
mov [edi], byte 0
ret
 
 
 
 
;***************************************************************************
; Function
; sendFile
;
; Description
; Transmits the requested file over the open data socket
; The file to send is named in the buff string
;
; Inputs
; None
;
; Outputs
; None
;
;***************************************************************************
sendFile:
call setupFilePath
 
; init fileblock descriptor, for file read
mov ebx, fileinfoblock
and dword [ebx], 0 ; read cmd
and dword [ebx+4], 0 ; first block
 
sf002a:
; now read the file..
mov eax,70
int 0x40
test eax, eax
jz @f
cmp eax, 6
jnz sf_exit
@@:
push eax
mov esi, text + 0x1300
mov edx, ebx
call outputDataStr
pop eax
test eax, eax
jnz sf_exit
; wait a bit
mov eax, 5
mov ebx, 10
int 0x40
mov ebx, fileinfoblock
add dword [ebx+4], edx
jmp sf002a
 
sf_exit:
ret
 
;***************************************************************************
; Function
; getFile
;
; Description
; Receives the specified file over the open data socket
; The file to receive is named in the buff string
;
; Inputs
; None
;
; Outputs
; None
;
;***************************************************************************
getFile:
call setupFilePath
; init fileblock descriptor, for file write
xor eax, eax
mov [fsize], eax ; Start filelength at 0
mov [fileinfoblock+4], eax ; set to 0
inc eax
inc eax
mov [fileinfoblock], eax ; write cmd
; Read data from the socket until the socket closes
; loop
; loop
; read byte from socket
; write byte to file buffer
; until no more bytes in socket
; sleep 100ms
; until socket no longer connected
; write file to ram
gf000:
mov eax, 53
mov ebx, 2 ; Get # of bytes in input queue
mov ecx, [DataSocket]
int 0x40
test eax, eax
je gf_sleep
mov eax, 53
mov ebx, 3 ; Get a byte from socket in bl
mov ecx, [DataSocket]
int 0x40 ; returned data in bl
mov esi, text + 0x1300
add esi, dword [fsize]
mov [esi], bl
inc dword [fsize]
; dummy, write to screen
;call printChar
jmp gf000
 
gf_sleep:
; Check to see if socket closed...
mov eax,53
mov ebx,6 ; Get socket status
mov ecx,[DataSocket]
int 0x40
 
cmp eax, 7
jne gf001 ; still open, so just sleep a bit
 
; Finished, so write the file
mov eax, [fsize]
mov [fileinfoblock+12], eax
mov eax,70
mov ebx,fileinfoblock
int 0x40
 
ret ; Finished
 
gf001:
; wait a bit
mov eax,5
mov ebx,10 ; Delay for up 100ms
int 0x40
jmp gf000 ; try for more data
 
 
 
;***************************************************************************
; COMMAND HANDLERS FOLLOW
;
; These handlers implement the functionality of each supported FTP Command
;
;***************************************************************************
 
cmdPWD:
; OK, show the directory name text
mov esi, ramdir
mov edx, ramdir_end - ramdir
call outputStr
 
; TODO give real directory
 
ret
 
 
cmdCWD:
; Only / is valid for the ramdisk
cmp [buff+5], byte 0x0d
jne ccwd_000
; OK, show the directory name text
mov esi, chdir
mov edx, chdir_end - chdir
jmp ccwd_001
ccwd_000:
; Tell user there is no such directory
mov esi, noFileStr
mov edx, noFileStr_end - noFileStr
 
ccwd_001:
call outputStr
 
ret
 
 
cmdQUIT:
; The remote end will do the close; We just
; say goodbye.
mov esi, byeStr
mov edx, byeStr_end - byeStr
call outputStr
ret
 
 
cmdABOR:
 
; Close port
call disconnectData
 
mov esi, abortStr
mov edx, abortStr_end - abortStr
call outputStr
 
ret
 
cmdPORT:
; TODO
; Copy the IP and port values to DataIP and DataPort
 
call parsePortStr
 
; Indicate the command was accepted
mov esi, cmdOKStr
mov edx, cmdOKStr_end - cmdOKStr
call outputStr
ret
 
cmdnoop:
; Indicate the command was accepted
mov esi, cmdOKStr
mov edx, cmdOKStr_end - cmdOKStr
call outputStr
ret
 
 
cmdTYPE:
; TODO
; Note the type field selected - reject if needed.
 
; Indicate the command was accepted
mov esi, cmdOKStr
mov edx, cmdOKStr_end - cmdOKStr
call outputStr
ret
 
cmdsyst:
; Indicate the system type
mov esi, systStr
mov edx, systStr_end - systStr
call outputStr
ret
 
 
cmdDELE:
call setupFilePath
 
mov ebx, fileinfoblock
mov dword [ebx], 8
and dword [ebx+4], 0
push dword [ebx+12]
push dword [ebx+16]
and dword [ebx+12], 0
and dword [ebx+16], 0
mov eax, 70
int 0x40
pop dword [ebx+16]
pop dword [ebx+12]
test eax, eax
jne cmdDele_err
 
mov esi, delokStr
mov edx, delokStr_end - delokStr
call outputStr
jmp cmdDele_exit
cmdDele_err:
mov esi, noFileStr
mov edx, noFileStr_end - noFileStr
call outputStr
cmdDele_exit:
ret
 
 
cmdNLST:
cmdLIST:
; Indicate the command was accepted
mov esi, startStr
mov edx, startStr_end - startStr
call outputStr
 
call connectData
 
; Wait for socket to establish
 
cl001:
; wait a bit
mov eax,5
mov ebx,10 ; Delay for up 100ms
int 0x40
 
; check connection status
mov eax,53
mov ebx,6 ; Get socket status
mov ecx,[DataSocket]
int 0x40
 
cmp eax, 4
jne cl001
 
; send directory listing
call sendDir
; Close port
call disconnectData
 
mov esi, endStr
mov edx, endStr_end - endStr
call outputStr
ret
 
cmdRETR:
; Indicate the command was accepted
mov esi, startStr
mov edx, startStr_end - startStr
call outputStr
 
call connectData
 
; Wait for socket to establish
 
cr001:
; wait a bit
mov eax,5
mov ebx,10 ; Delay for up 100ms
int 0x40
 
; check connection status
mov eax,53
mov ebx,6 ; Get socket status
mov ecx,[DataSocket]
int 0x40
 
cmp eax, 4
jne cr001
 
; send data to remote user
call sendFile
; Close port
call disconnectData
 
mov esi, endStr
mov edx, endStr_end - endStr
call outputStr
 
 
ret
 
 
cmdSTOR:
; Indicate the command was accepted
mov esi, storStr
mov edx, storStr_end - storStr
call outputStr
 
call connectData
 
; Wait for socket to establish
 
cs001:
; wait a bit
mov eax,5
mov ebx,10 ; Delay for up 100ms
int 0x40
 
; check connection status
mov eax,53
mov ebx,6 ; Get socket status
mov ecx,[DataSocket]
int 0x40
 
cmp eax, 4
je @f
cmp eax, 7
jne cs001
@@:
 
; get data file from remote user
call getFile
mov esi, endStr
mov edx, endStr_end - endStr
call outputStr
 
; Close port
call disconnectData
 
ret
 
 
 
; DATA AREA
 
; This is the list of supported commands, and the function to call
; The list end with a NULL.
CMDList:
db 'pwd',0
dd cmdPWD
 
db 'PWD',0
dd cmdPWD
 
db 'XPWD',0
dd cmdPWD
 
db 'xpwd',0
dd cmdPWD
 
db 'QUIT',0
dd cmdQUIT
 
db 'quit',0
dd cmdQUIT
 
db 'PORT',0
dd cmdPORT
 
db 'port',0
dd cmdPORT
 
db 'LIST',0
dd cmdLIST
 
db 'list',0
dd cmdLIST
 
db 'NLST',0
dd cmdNLST
 
db 'nlst',0
dd cmdNLST
 
db 'TYPE',0
dd cmdTYPE
 
db 'type',0
dd cmdTYPE
 
db 'syst',0
dd cmdsyst
 
db 'noop',0
dd cmdnoop
 
db 'CWD',0
dd cmdCWD
 
db 'cwd',0
dd cmdCWD
 
db 'RETR',0
dd cmdRETR
 
db 'retr',0
dd cmdRETR
 
db 'DELE',0
dd cmdDELE
 
db 'dele',0
dd cmdDELE
 
db 'stor',0
dd cmdSTOR
 
db 'STOR',0
dd cmdSTOR
 
db 'ABOR',0
dd cmdABOR
 
db 'abor',0
dd cmdABOR
 
db 0xff,0xf4,0xff,0xf2,'ABOR',0
dd cmdABOR
 
db 0
 
 
cmdPtr dd 0
CmdSocket dd 0x0
CmdSocketStatus dd 0x0
DataSocket dd 0x0
DataSocketStatus dd 0x0
DataPort dd 0x00
DataIP dd 0x00
pos dd 80 * 1
scroll dd 1
dd 24
 
labelt db 'FTP Server v0.1',0
contt db 'Connected'
contlen:
discontt db 'Disconnected'
discontlen:
 
cmdOKStr: db '200 Command OK',0x0d,0x0a
cmdOKStr_end:
 
loginStr0: db '220- Menuet FTP Server v0.1',0x0d,0x0a
db '220 Username and Password required',0x0d,0x0a
loginStr0_end:
 
loginStr1: db '331 Password now required',0x0d,0x0a
loginStr1_end:
 
loginStr2: db '230 You are now logged in.',0x0d,0x0a
loginStr2_end:
 
byeStr: db '221 Bye bye!',0x0d,0x0a
byeStr_end:
 
systStr: db '215 UNIX system type',0x0d,0x0a
systStr_end:
 
ramdir: db '257 "/"',0x0d,0x0a
ramdir_end:
 
chdir: db '200 directory changed to /',0x0d,0x0a
chdir_end:
 
unsupStr: db '500 Unsupported command',0x0d,0x0a
unsupStr_end:
 
noFileStr: db '550 No such file',0x0d,0x0a
noFileStr_end:
 
delokStr: db '250 DELE command successful',0x0d,0x0a
delokStr_end:
 
startStr: db '150 Here it comes...',0x0d,0x0a
startStr_end:
 
storStr: db '150 Connecting for STOR',0x0d,0x0a
storStr_end:
 
endStr: db '226 Transfer OK, Closing connection',0x0d,0x0a
endStr_end:
 
abortStr: db '225 Abort successful',0x0d,0x0a
abortStr_end:
 
; This is the buffer used for building up a directory listing line
dirStr: times 128 db 0
 
; This is template string used in building up a directory listing line
tmplStr: db 'rw-rw-rw- 1 0 0 ',0
 
months:
dd 'Jan ','Feb ','Mar ','Apr ','May ','Jun '
dd 'Jul ','Aug ','Sep ','Oct ','Nov ','Dec '
 
fileinfoblock:
dd 0x00
dd 0x00
dd 0x00
dd 0x200 ; bytes to read
dd text + 0x1300 ; data area
filename: times 256 db 0
 
; The following lines define data for reading a directory block
DirBlocksPerCall = 16
dirinfoblock:
dd 1
dd 0x00
dd 0x00
dd DirBlocksPerCall
dd text + 0x1300 ; data area
; The 'filename' for a directory listing
dirpath db '/RD/1',0
 
fsize: dd 0
state db 0
buffptr dd 0
buff: times 256 db 0 ; Could put this after iend
 
; Ram use at the end of the application:
; text : 2400 bytes for screen memory
; text + 0x1300 : file data area
text:
I_END:
/programs/network/ftps/trunk/build.bat
0,0 → 1,2
@fasm ftps.asm ftps
@pause
/programs/network/ftps/trunk/macros.inc
0,0 → 1,269
; new application structure
macro meos_app_start
{
use32
org 0x0
 
db 'MENUET01'
dd 0x01
dd __start
dd __end
dd __memory
dd __stack
 
if used __params & ~defined __params
dd __params
else
dd 0x0
end if
 
dd 0x0
}
MEOS_APP_START fix meos_app_start
 
macro code
{
__start:
}
CODE fix code
 
macro data
{
__data:
}
DATA fix data
 
macro udata
{
if used __params & ~defined __params
__params:
db 0
__end:
rb 255
else
__end:
end if
__udata:
}
UDATA fix udata
 
macro meos_app_end
{
align 32
rb 2048
__stack:
__memory:
}
MEOS_APP_END fix meos_app_end
 
 
; macro for defining multiline text data
struc mstr [sstring]
{
forward
local ssize
virtual at 0
db sstring
ssize = $
end virtual
dd ssize
db sstring
common
dd -1
}
 
 
; strings
macro sz name,[data] { ; from MFAR [mike.dld]
common
if used name
label name
end if
forward
if used name
db data
end if
common
if used name
.size = $-name
end if
}
 
macro lsz name,[lng,data] { ; from MFAR [mike.dld]
common
if used name
label name
end if
forward
if (used name)&(lang eq lng)
db data
end if
common
if used name
.size = $-name
end if
}
 
 
 
; easy system call macro
macro mpack dest, hsrc, lsrc
{
if (hsrc eqtype 0) & (lsrc eqtype 0)
mov dest, (hsrc) shl 16 + lsrc
else
if (hsrc eqtype 0) & (~lsrc eqtype 0)
mov dest, (hsrc) shl 16
add dest, lsrc
else
mov dest, hsrc
shl dest, 16
add dest, lsrc
end if
end if
}
 
macro __mov reg,a,b { ; mike.dld
if (~a eq)&(~b eq)
mpack reg,a,b
else if (~a eq)&(b eq)
mov reg,a
end if
}
 
macro mcall a,b,c,d,e,f { ; mike.dld
__mov eax,a
__mov ebx,b
__mov ecx,c
__mov edx,d
__mov esi,e
__mov edi,f
int 0x40
}
 
 
 
; optimize the code for size
__regs fix <eax,ebx,ecx,edx,esi,edi,ebp,esp>
 
macro add arg1,arg2
{
if (arg2 eqtype 0)
if (arg2) = 1
inc arg1
else
add arg1,arg2
end if
else
add arg1,arg2
end if
}
 
macro sub arg1,arg2
{
if (arg2 eqtype 0)
if (arg2) = 1
dec arg1
else
sub arg1,arg2
end if
else
sub arg1,arg2
end if
}
 
macro mov arg1,arg2
{
if (arg1 in __regs) & ((arg2 eqtype 0) | (arg2 eqtype '0'))
if (arg2) = 0
xor arg1,arg1
else if (arg2) = 1
xor arg1,arg1
inc arg1
else if (arg2) = -1
or arg1,-1
else if (arg2) > -128 & (arg2) < 128
push arg2
pop arg1
else
mov arg1,arg2
end if
else
mov arg1,arg2
end if
}
 
 
macro struct name
{
virtual at 0
name name
sizeof.#name = $ - name
end virtual
}
 
; structures used in MeOS
struc process_information
{
.cpu_usage dd ? ; +0
.window_stack_position dw ? ; +4
.window_stack_value dw ? ; +6
.not_used1 dw ? ; +8
.process_name rb 12 ; +10
.memory_start dd ? ; +22
.used_memory dd ? ; +26
.PID dd ? ; +30
.x_start dd ? ; +34
.y_start dd ? ; +38
.x_size dd ? ; +42
.y_size dd ? ; +46
.slot_state dw ? ; +50
dw ? ; +52 - reserved
.client_left dd ? ; +54
.client_top dd ? ; +58
.client_width dd ? ; +62
.client_height dd ? ; +66
.wnd_state db ? ; +70
rb (1024-71)
}
struct process_information
 
struc system_colors
{
.frame dd ?
.grab dd ?
.grab_button dd ?
.grab_button_text dd ?
.grab_text dd ?
.work dd ?
.work_button dd ?
.work_button_text dd ?
.work_text dd ?
.work_graph dd ?
}
struct system_colors
 
 
; constants
 
; events
EV_IDLE = 0
EV_TIMER = 0
EV_REDRAW = 1
EV_KEY = 2
EV_BUTTON = 3
EV_EXIT = 4
EV_BACKGROUND = 5
EV_MOUSE = 6
EV_IPC = 7
EV_STACK = 8
 
; event mask bits for function 40
EVM_REDRAW = 1b
EVM_KEY = 10b
EVM_BUTTON = 100b
EVM_EXIT = 1000b
EVM_BACKGROUND = 10000b
EVM_MOUSE = 100000b
EVM_IPC = 1000000b
EVM_STACK = 10000000b