refactor code, add GUI and fix bugs

git-svn-id: svn://kolibrios.org@6582 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
nisargshah95 2016-10-07 17:11:07 +00:00
parent e401a92cbf
commit dd8a86960b
11 changed files with 2068 additions and 303 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@ -0,0 +1,32 @@
Usage instructions -
1) By default log file is created in /usbhd0/1. If the folder is uavailable,
the program will throw an error. Configure the folder from ftpc.ini
2) Browse the local and remote folders using UP/DOWN arrow keys and press ENTER
to download/upload the file. Scrolling might not work due to lack of support
from the boxlib library
3) It might be difficult to read log file contents using certain text editors.
gedit works fine
Known issues -
1) Uploading large files may not work. I do not know whether this is an FTPC
issue or a network-stack realted issue
2) FTPC may freeze on rare occasions. Simply close and restart it
3) Download may fail abruptly if disk becomes full. Unfortunately, as of now,
there is no support for checking available disk space beforehand from kernel
itself
4) Text in console and log file is not properly formatted
Future improvements -
1) Display more informative error messages (especially in GUI)
2) Allow resizing of GUI window and align GUI elements automatically

155
programs/network/ftpc/console.inc Executable file
View File

@ -0,0 +1,155 @@
;;================================================================================================;;
console: ;////////////////////////////////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Console-specific functions - initialization, clear screen, ;;
;? .get_cmd - Takes user command as input from the console ;;
;? .server_addr - Gets server address from user in the form address:port ;;
;? .get_username/.get_pass - Takes username/password as input from the user ;;
;;------------------------------------------------------------------------------------------------;;
;> ;;
;;------------------------------------------------------------------------------------------------;;
;< none ;;
;;================================================================================================;;
dd .init
dd .server_addr
dd .get_username
dd .get_cmd
dd .print
dd .set_flags
dd .list
dd .progress
dd .error
.init:
; load console library
stdcall dll.Load, @IMPORT_CONSOLE
; initialize console
invoke con_start, 1
invoke con_init, 120, 43, 120, 300, str_title
invoke con_cls
; Welcome user
invoke con_write_asciiz, str_welcome
ret
.server_addr:
mov [initial_login], 1
invoke con_cls
invoke con_set_flags, 0x07
; ask for server addr
invoke con_write_asciiz, str_srv_addr
; write prompt (in green color)
invoke con_set_flags, 0x0a
invoke con_write_asciiz, str_prompt
; read string
invoke con_gets, param_server_addr, 256
; check for exit
test eax, eax
jz .exit
cmp byte [param_server_addr], 10
jz .exit
.port:
invoke con_write_asciiz, str_port
invoke con_gets, param_port, 256
; read username
.get_username:
invoke con_set_flags, 0x0a
invoke con_write_asciiz, str_user
invoke con_gets, param_user, 256
; read password
.get_pass:
invoke con_write_asciiz, str_pass
invoke con_set_flags, 0x00 ; black text on black background for password
invoke con_gets, param_password, 256
invoke con_set_flags, 0x0a
cmp [initial_login], 1
jne arg_handler.copy_user
mov [initial_login], 0
; get initial path
.get_path:
invoke con_write_asciiz, str_path
invoke con_gets, param_path, 256
invoke con_write_asciiz, str_newline
jmp arg_handler.connect
.get_cmd:
; write prompt
invoke con_write_asciiz, str_prompt
; read string
invoke con_gets, buf_cmd, 256
; print a newline and reset the color back to grey
invoke con_write_asciiz, str_newline
invoke con_set_flags, 0x07
jmp wait_for_usercommand.parse_cmd
.print:
pushad
invoke con_write_asciiz, [esp+36]
mov esi, [esp+36]
mov ecx, -1
@@:
inc ecx
lodsb
test al, al
jnz @b
; write to log file
mov eax, [esp+36]
cmp [logfile_offset], -1
je @f
call write_to_file
@@:
popad
ret 4
.set_flags:
invoke con_set_flags, [esp+4]
ret 4
.list:
invoke con_write_asciiz, buf_buffer2
jmp data_loop
.progress: ; edx = no. of bytes transferred
mov eax, edx
mov edi, str_bytes_done
call dword_ascii
mov byte[edi],0
icall eax, interface_addr, interface.print, str_downloaded, str_bytes_done, str_bytes
ret
.error:
invoke con_getch2
jmp .server_addr
.exit:
invoke con_exit, 1
jmp exit
align 4
@IMPORT_CONSOLE:
library console, 'console.obj'
import console, \
con_start, 'START', \
con_init, 'con_init', \
con_write_asciiz, 'con_write_asciiz', \
con_exit, 'con_exit', \
con_gets, 'con_gets', \
con_cls, 'con_cls', \
con_getch2, 'con_getch2', \
con_set_cursor_pos, 'con_set_cursor_pos', \
con_write_string, 'con_write_string', \
con_get_flags, 'con_get_flags', \
con_set_flags, 'con_set_flags'

View File

@ -6,6 +6,7 @@
;; ftpc.asm - FTP client for KolibriOS ;; ;; ftpc.asm - FTP client for KolibriOS ;;
;; ;; ;; ;;
;; Written by hidnplayr@kolibrios.org ;; ;; Written by hidnplayr@kolibrios.org ;;
;; Modified by nisargshah323@gmail.com (2016) ;;
;; ;; ;; ;;
;; GNU GENERAL PUBLIC LICENSE ;; ;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;; ;; Version 2, June 1991 ;;
@ -41,16 +42,49 @@ use32
dd path ; path dd path ; path
include '../../macros.inc' include '../../macros.inc'
macro ijmp reg, addr, method
{
mov reg, [addr]
add reg, [method]
jmp dword[reg]
}
macro icall reg, addr, method, [arg]
{
mov reg, [addr]
add reg, [method]
if ~ arg eq
pushd arg
end if
call dword[reg]
}
purge mov,add,sub purge mov,add,sub
include '../../proc32.inc' include '../../proc32.inc'
include '../../dll.inc' include '../../dll.inc'
include '../../network.inc' include '../../network.inc'
include '../../develop/libraries/box_lib/trunk/box_lib.mac'
include '../../develop/libraries/box_lib/load_lib.mac'
include 'console.inc'
include 'gui.inc'
include 'login_gui.inc'
include 'usercommands.inc' include 'usercommands.inc'
include 'servercommands.inc' include 'servercommands.inc'
include 'parser.inc' include 'parser.inc'
start: ; TODO: Add Pasta support to FTPC
;;================================================================================================;;
start: ;//////////////////////////////////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Program entry point - initialize heap, load libraries and settings ;;
;;------------------------------------------------------------------------------------------------;;
;> ;;
;;------------------------------------------------------------------------------------------------;;
;< none ;;
;;================================================================================================;;
; initialize heap for using dynamic blocks ; initialize heap for using dynamic blocks
mcall 68,11 mcall 68,11
test eax,eax test eax,eax
@ -62,9 +96,6 @@ start:
stdcall dll.Load, @IMPORT stdcall dll.Load, @IMPORT
test eax, eax test eax, eax
jnz exit jnz exit
; initialize console
invoke con_start, 1
invoke con_init, 80, 25, 80, 250, str_title
; find path to main settings file (ftpc.ini) ; find path to main settings file (ftpc.ini)
mov edi, path ; Calculate the length of zero-terminated string mov edi, path ; Calculate the length of zero-terminated string
xor al, al xor al, al
@ -99,48 +130,144 @@ start:
invoke ini.get_str, path, str_general, str_dir, buf_buffer1, BUFFERSIZE, 0 invoke ini.get_str, path, str_general, str_dir, buf_buffer1, BUFFERSIZE, 0
mcall 30, 1, buf_buffer1 ; set working directory mcall 30, 1, buf_buffer1 ; set working directory
; Check for parameters, if there are some, resolve the address right away ; initialize log file
; TODO: parse ftp://user:password@server.com:port/folder/subfolder type urls. invoke ini.get_str, path, str_general, str_logfile, log_file, 512, 0
mov [filestruct2.subfn], 2
mov [filestruct2.offset], 0
mov [filestruct2.size], 0
mov [filestruct2.ptr], 0
mov [filestruct2.name], log_file
mcall 70, filestruct2
; Usage: ftpc [-cli] [ftp://username:password@server:port/path]
; mov dword[buf_cmd], '-cli' ;;;; to test CLI ;;;;;
cmp byte[buf_cmd], 0 cmp byte[buf_cmd], 0
jne resolve jne @f
mov [interface_addr], gui
jmp .args_ok
@@: cmp dword[buf_cmd], '-cli'
jne .error
mov [interface_addr], console
jmp .args_ok
main: .args_ok:
; Clear screen
invoke con_cls
; Welcome user
invoke con_write_asciiz, str_welcome
; write prompt (in green color)
invoke con_set_flags, 0x0a
invoke con_write_asciiz, str_prompt
; read string
invoke con_gets, buf_cmd, 256
; check for exit
test eax, eax
jz done
cmp byte [buf_cmd], 10
jz done
; reset color back to grey and print newline
invoke con_set_flags, 0x07
invoke con_write_asciiz, str_newline
no_resolve: icall eax, interface_addr, interface.init
mov [sockaddr1.port], 21 shl 8 ; check for ftp://username:pass@server:port/path urls
cmp dword[buf_cmd], 'ftp:'
je parse_args
cmp dword[buf_cmd+5], 'ftp:'
je parse_args
ijmp eax, interface_addr, interface.server_addr
; delete terminating '\n' .error:
mov esi, buf_cmd call console.init
invoke con_write_asciiz, str_args_err
invoke con_getch2
call console.exit
jmp exit
;;================================================================================================;;
arg_handler: ;////////////////////////////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Passes initial connection info from console/GUI to FTP core and the other way around ;;
;;------------------------------------------------------------------------------------------------;;
;> esp+4 = pointer to the argument passed to the function ;;
;;------------------------------------------------------------------------------------------------;;
;< none ;;
;;================================================================================================;;
.get_username:
; request username
ijmp eax, interface_addr, interface.get_username
.copy_user:
mov dword[buf_cmd], "USER"
mov byte[buf_cmd+4], " "
; copy user name to buf_cmd (for command line args)
mov edi, buf_cmd+5
mov esi, param_user
@@:
movsb
cmp byte [esi-1], 0
jne @b
mov word[edi-1], 0x0a0d
lea esi, [edi+1-buf_cmd]
jmp server_connect.send
.get_pass:
mov dword[buf_cmd], "PASS"
mov byte[buf_cmd+4], " "
; copy password to buf_cmd (for command line args)
mov edi, buf_cmd+5
mov esi, param_password
@@:
movsb
cmp byte[esi-1], 0
jne @b
mov word[edi-1], 0x0a0d
lea esi, [edi+1-buf_cmd]
jmp server_connect.send
.get_path:
; copy path from param_path to buf_cmd
mov dword[buf_cmd], "CWD "
mov edi, buf_cmd+4
mov esi, param_path
@@: @@:
lodsb lodsb
cmp al, ':' stosb
je .do_port cmp al, 0x20
ja @b
mov word[edi-1], 0x0a0d
lea esi, [edi+1-buf_cmd]
jmp server_connect.send
.connect:
; copy server address to buf_cmd
mov esi, param_server_addr
mov edi, buf_cmd
@@:
lodsb
stosb
cmp al, 0x20 cmp al, 0x20
ja @r ja @r
mov byte [esi-1], 0 mov byte[edi-1], 0 ; delete terminating '\n'
jmp .done
cmp [param_port], 0x20
jbe server_connect.default_port
mov esi, param_port
jmp server_connect.do_port
;;================================================================================================;;
server_connect: ;/////////////////////////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Establishes a connection to the FTP server (common block for all interfaces) ;;
;? .do_port - Port is specified by the user and needs to be converted from ASCII ;;
;;------------------------------------------------------------------------------------------------;;
;> esi = pointer to port no. ;;
;;------------------------------------------------------------------------------------------------;;
;< none ;;
;;================================================================================================;;
.send:
; send username/password/path to the server
mcall send, [controlsocket], buf_cmd, , 0
icall eax, interface_addr, interface.print, str_newline
icall eax, interface_addr, interface.set_flags, 0x07 ; reset color
jmp wait_for_servercommand
; resolve port if specified
.do_port: .do_port:
xor eax, eax xor eax, eax
xor ebx, ebx xor ebx, ebx
mov byte [esi-1], 0
.portloop: .portloop:
lodsb lodsb
cmp al, 0x20 cmp al, 0x20
@ -161,11 +288,15 @@ no_resolve:
.port_done: .port_done:
xchg bl, bh xchg bl, bh
mov [sockaddr1.port], bx mov [sockaddr1.port], bx
jmp .done
.default_port:
mov [sockaddr1.port], 21 shl 8
.done: .done:
; Say to the user that we're resolving ; Say to the user that we're resolving
invoke con_write_asciiz, str_resolve icall eax, interface_addr, interface.set_flags, 0x07 ; reset color
invoke con_write_asciiz, buf_cmd icall eax, interface_addr, interface.print, str_resolve, buf_cmd
; resolve name ; resolve name
push esp ; reserve stack place push esp ; reserve stack place
invoke getaddrinfo, buf_cmd, 0, 0, esp invoke getaddrinfo, buf_cmd, 0, 0, esp
@ -177,14 +308,13 @@ no_resolve:
jmp error jmp error
@@: @@:
; write results ; write results
invoke con_write_asciiz, str8 ; ' (',0 icall eax, interface_addr, interface.print, str8 ; ' (',0
mov eax, [esi+addrinfo.ai_addr] ; convert IP address to decimal notation mov eax, [esi+addrinfo.ai_addr] ; convert IP address to decimal notation
mov eax, [eax+sockaddr_in.sin_addr] ; mov eax, [eax+sockaddr_in.sin_addr] ;
mov [sockaddr1.ip], eax ; mov [sockaddr1.ip], eax ;
invoke inet_ntoa, eax ; invoke inet_ntoa, eax ;
invoke con_write_asciiz, eax ; print ip icall ebx, interface_addr, interface.print, eax, str9 ; <ip>,')',10,0
invoke freeaddrinfo, esi ; free allocated memory invoke freeaddrinfo, esi ; free allocated memory
invoke con_write_asciiz, str9 ; ')',10,0
; open the socket ; open the socket
mcall socket, AF_INET4, SOCK_STREAM, 0 mcall socket, AF_INET4, SOCK_STREAM, 0
cmp eax, -1 cmp eax, -1
@ -193,7 +323,7 @@ no_resolve:
jmp error jmp error
@@: mov [controlsocket], eax @@: mov [controlsocket], eax
; connect to the server ; connect to the server
invoke con_write_asciiz, str_connect icall eax, interface_addr, interface.print, str_connect
mcall connect, [controlsocket], sockaddr1, 18 mcall connect, [controlsocket], sockaddr1, 18
cmp eax, -1 cmp eax, -1
jne @f jne @f
@ -201,12 +331,22 @@ no_resolve:
jmp error jmp error
@@: mov [status], STATUS_CONNECTING @@: mov [status], STATUS_CONNECTING
; Tell the user we're waiting for the server now. ; Tell the user we're waiting for the server now.
invoke con_write_asciiz, str_waiting icall eax, interface_addr, interface.print, str_waiting
; Reset 'offset' variable, it's used by the data receiver ; Reset 'offset' variable, it's used by the data receiver
mov [offset], 0 mov [offset], 0
wait_for_servercommand:
;;================================================================================================;;
wait_for_servercommand: ;/////////////////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Checks if any data received from the server is present in buffer. ;;
;? If not, receives and processes it ;;
;;------------------------------------------------------------------------------------------------;;
;> ;;
;;------------------------------------------------------------------------------------------------;;
;< none ;;
;;================================================================================================;;
; Any commands still in our buffer? ; Any commands still in our buffer?
cmp [offset], 0 cmp [offset], 0
je .receive ; nope, receive some more je .receive ; nope, receive some more
@ -268,16 +408,25 @@ wait_for_servercommand:
xor al, al xor al, al
stosb stosb
invoke con_set_flags, 0x03 ; change color icall eax, interface_addr, interface.set_flags, 0x03 ; change color
invoke con_write_asciiz, buf_cmd ; print servercommand icall eax, interface_addr, interface.print, buf_cmd, str_newline
invoke con_write_asciiz, str_newline icall eax, interface_addr, interface.set_flags, 0x07 ; reset color
invoke con_set_flags, 0x07 ; reset color
jmp server_parser ; parse command jmp server_parser ; parse command
wait_for_usercommand: ;;================================================================================================;;
wait_for_usercommand: ;///////////////////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Reads the FTP command entered by the user and compares it with valid FTP commands. ;;
;? Jumps to appropriate handling routine in usercommands.inc ;;
;;------------------------------------------------------------------------------------------------;;
;> status = socket connection status ;;
;> buf_cmd = command entered by the user ;;
;;------------------------------------------------------------------------------------------------;;
;< none ;;
;;================================================================================================;;
; Are there any files in the transfer queue? ; Are there any files in the transfer queue?
@ -285,24 +434,19 @@ wait_for_usercommand:
ja transfer_queued ; Yes, transfer those first. ja transfer_queued ; Yes, transfer those first.
; change color to green for user input ; change color to green for user input
invoke con_set_flags, 0x0a icall eax, interface_addr, interface.set_flags, 0x0a
; If we are not yet connected, request username/password ; If we are not yet connected, request username/password
cmp [status], STATUS_CONNECTED cmp [status], STATUS_CONNECTED
je .connected je arg_handler.get_username
cmp [status], STATUS_NEEDPASSWORD cmp [status], STATUS_NEEDPASSWORD
je .needpass je arg_handler.get_pass
; write prompt ijmp eax, interface_addr, interface.get_cmd
invoke con_write_asciiz, str_prompt
; read string
invoke con_gets, buf_cmd, 256
; print a newline and reset the color back to grey
invoke con_write_asciiz, str_newline
invoke con_set_flags, 0x07
.parse_cmd:
cmp dword[buf_cmd], "cwd " cmp dword[buf_cmd], "cwd "
je cmd_cwd je cmd_cwd
@ -349,78 +493,15 @@ wait_for_usercommand:
cmp dword[buf_cmd], "cdup" cmp dword[buf_cmd], "cdup"
je cmd_cdup je cmd_cdup
cmp dword[buf_cmd], "abor"
je cmd_abor
@@: @@:
; Uh oh.. unknown command, tell the user and wait for new input ; Uh oh.. unknown command, tell the user and wait for new input
invoke con_write_asciiz, str_unknown icall eax, interface_addr, interface.print, str_unknown
jmp wait_for_usercommand jmp wait_for_usercommand
.connected:
; request username
cmp [use_params], 1
je .copy_user
invoke con_write_asciiz, str_user
mov dword[buf_cmd], "USER"
mov byte[buf_cmd+4], " "
jmp .send
.copy_user:
; copy user name to buf_cmd
mov edi, buf_cmd
mov esi, param_user
@@:
lodsb
stosb
cmp byte [esi-1], 0
jne @b
jmp .send
.needpass:
; request password
cmp [use_params], 1
je .copy_password
invoke con_write_asciiz, str_pass
mov dword[buf_cmd], "PASS"
mov byte[buf_cmd+4], " "
invoke con_set_flags, 0x00 ; black text on black background for password
jmp .send
.copy_password:
; copy password to buf_cmd
mov edi, buf_cmd
mov esi, param_password
@@:
lodsb
stosb
cmp byte [esi-1], 0
jne @b
.send:
; read string
cmp [use_params], 1
je @f
mov esi, buf_cmd+5
invoke con_gets, esi, 256
@@:
; find end of string
mov edi, buf_cmd+5
mov ecx, 256
xor al, al
repne scasb
lea esi, [edi-buf_cmd]
mov word[edi-2], 0x0a0d
; and send it to the server
mcall send, [controlsocket], buf_cmd, , 0
invoke con_write_asciiz, str_newline
invoke con_set_flags, 0x07 ; reset color
jmp wait_for_servercommand
; files for rdir operation are queued ; files for rdir operation are queued
transfer_queued: transfer_queued:
@ -551,26 +632,112 @@ dword_ascii:
pop ecx ebx edx pop ecx ebx edx
ret ret
error:
;;================================================================================================;;
write_to_file: ;//////////////////////////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Writes input buffer to log file ;;
;;------------------------------------------------------------------------------------------------;;
;> eax = pointer to buffer ;;
;> ecx = size of buffer ;;
;;------------------------------------------------------------------------------------------------;;
;< eax = status of SF 70.3 ;;
;;================================================================================================;;
mov [filestruct2.subfn], 3
m2m [filestruct2.offset], [logfile_offset]
mov [filestruct2.size], ecx
mov [filestruct2.ptr], eax
mov [filestruct2.name], log_file
mcall 70, filestruct2
test eax, eax
jz @f
mov [logfile_offset], -1 ; disable logging
call error_fs
icall ebx, interface_addr, interface.print, str_no_logging
ret
@@:
mov eax, [logfile_offset]
add eax, ecx
mov [logfile_offset], eax
ret
;;================================================================================================;;
error: ;//////////////////////////////////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Generic error routine. Prints the error string passed to it. ;;
;;------------------------------------------------------------------------------------------------;;
;> eax = pointer to the error string ;;
;;------------------------------------------------------------------------------------------------;;
;< none ;;
;;================================================================================================;;
push eax push eax
invoke con_set_flags, 0x0c ; print errors in red icall ebx, interface_addr, interface.set_flags, 0x0c ; print errors in red
pop eax pop eax
invoke con_write_asciiz, eax icall ebx, interface_addr, interface.print, eax
jmp wait_for_keypress jmp wait_for_keypress
; Error handling block for filesystem errors
error_fs:
cmp eax, 12
jne @f
mov ebx, str_fs_err_12
@@:
cmp eax, 11
jne @f
mov ebx, str_fs_err_11
@@:
cmp eax, 10
jne @f
mov ebx, str_fs_err_10
@@:
cmp eax, 9
jne @f
mov ebx, str_fs_err_9
@@:
cmp eax, 8
jne @f
mov ebx, str_fs_err_8
@@:
cmp eax, 7
jne @f
mov ebx, str_fs_err_7
@@:
cmp eax, 6
jne @f
mov ebx, str_fs_err_6
@@:
cmp eax, 5
jne @f
mov ebx, str_fs_err_5
@@:
cmp eax, 3
jne @f
mov ebx, str_fs_err_3
@@:
cmp eax, 2
jne @f
mov ebx, str_fs_err_2
@@:
mov edi, fs_error_code
call dword_ascii ; convert error code in eax to ascii
icall eax, interface_addr, interface.set_flags, 0x0c ; print errors in red
icall eax, interface_addr, interface.print, str_err_fs, fs_error_code, ebx
mov word[fs_error_code], ' ' ; clear error code for next time
icall eax, interface_addr, interface.set_flags, 0x0a
ret
error_heap: error_heap:
invoke con_set_flags, 0x0c ; print errors in red icall eax, interface_addr, interface.set_flags, 0x0c ; print errors in red
invoke con_write_asciiz, str_err_heap icall eax, interface_addr, interface.print, str_err_heap
wait_for_keypress: wait_for_keypress:
invoke con_set_flags, 0x07 ; reset color to grey
invoke con_write_asciiz, str_push
invoke con_getch2
mcall close, [controlsocket] mcall close, [controlsocket]
jmp main icall eax, interface_addr, interface.set_flags, 0x07 ; reset color to grey
icall eax, interface_addr, interface.print, str_push
done: ijmp eax, interface_addr, interface.error
invoke con_exit, 1
exit: exit:
mcall close, [controlsocket] mcall close, [controlsocket]
@ -582,10 +749,8 @@ exit2:
; data ; data
str_title db 'FTP client',0 str_title db 'FTP client',0
str_welcome db 'FTP client for KolibriOS v0.12',10 str_welcome db 'FTP client for KolibriOS v0.12',10
db 10 db 10,0
db 'Please enter ftp server address.',10,0 str_srv_addr db 'Please enter ftp server address.',10,0
str_ftp db 'ftp://',0
str_prompt db '> ',0 str_prompt db '> ',0
str_resolve db 'Resolving ',0 str_resolve db 'Resolving ',0
@ -601,6 +766,18 @@ str_err_timeout db 10,'Timeout - no response from server.',10,0
str_err_connect db 10,'[75,4 connect]: Cannot connect to the server.',10,0 str_err_connect db 10,'[75,4 connect]: Cannot connect to the server.',10,0
str_err_host db 10,'Invalid hostname.',10,0 str_err_host db 10,'Invalid hostname.',10,0
str_err_params db 10,'Invalid parameters',10,0 str_err_params db 10,'Invalid parameters',10,0
str_err_fs db 10,'File system error: code ',0
fs_error_code db ' ',0 ; file system error code
str_fs_err_2 db ' [Function is not supported for the given file system]',10,0
str_fs_err_3 db ' [Unknown file system]',10,0
str_fs_err_5 db ' [File/Folder not found]',10,0
str_fs_err_6 db ' [End of file, EOF]',10,0
str_fs_err_7 db ' [Pointer lies outside of application memory]',10,0
str_fs_err_8 db ' [Disk is full]',10,0
str_fs_err_9 db ' [File system error]',10,0
str_fs_err_10 db ' [Access denied]',10,0
str_fs_err_11 db ' [Device error]',10,0
str_fs_err_12 db ' [File system requires more memory]',10,0
str8 db ' (',0 str8 db ' (',0
str9 db ')',10,0 str9 db ')',10,0
str_push db 'Push any key to continue.',0 str_push db 'Push any key to continue.',0
@ -608,8 +785,14 @@ str_connect db 'Connecting...',10,0
str_waiting db 'Waiting for welcome message.',10,0 str_waiting db 'Waiting for welcome message.',10,0
str_user db "username: ",0 str_user db "username: ",0
str_pass db "password: ",0 str_pass db "password: ",0
str_port db "port (default 21): ",0
str_path db "path (optional): ",0
str_unknown db "Unknown command or insufficient parameters - type help for more information.",10,0 str_unknown db "Unknown command or insufficient parameters - type help for more information.",10,0
str_lcwd db "Local working directory is now: ",0 str_lcwd db "Local working directory is now: ",0
str_bytes_done db ' ',0
str_downloaded db 'Downloaded ',0
str_bytes db ' bytes',13,0
str_args_err db 'Invalid arguments. USAGE: ftpc [-cli] [ftp://username:password@server:port/path]',10,0
str_open db "opening data socket",10,0 str_open db "opening data socket",10,0
str_close db 10,"closing data socket",10,0 str_close db 10,"closing data socket",10,0
@ -638,10 +821,13 @@ str_port_stop db 'port_stop', 0
str_ip db 'ip', 0 str_ip db 'ip', 0
str_dir db 'dir', 0 str_dir db 'dir', 0
str_general db 'general', 0 str_general db 'general', 0
str_logfile db 'logfile',0
str_no_logging db 'Error writing to log file. Logging disabled',0
queued dd 0 queued dd 0
mode db 0 ; passive = 0, active = 1 mode db 0 ; passive = 0, active = 1
; FTP strings ; FTP strings
str_PASV db 'PASV',13,10 str_PASV db 'PASV',13,10
@ -659,30 +845,31 @@ sockaddr2:
.ip dd ? .ip dd ?
rb 10 rb 10
struc interface
{
.init dd 0
.server_addr dd 4
.get_username dd 8
.get_cmd dd 12
.print dd 16
.set_flags dd 20
.list dd 24
.progress dd 28
.error dd 32
}
interface interface
; import ; import
align 4 align 4
@IMPORT: @IMPORT:
library network, 'network.obj', console, 'console.obj', libini, 'libini.obj' library network, 'network.obj', libini, 'libini.obj'
import network, \ import network, \
getaddrinfo, 'getaddrinfo', \ getaddrinfo, 'getaddrinfo', \
freeaddrinfo, 'freeaddrinfo', \ freeaddrinfo, 'freeaddrinfo', \
inet_ntoa, 'inet_ntoa' inet_ntoa, 'inet_ntoa'
import console, \
con_start, 'START', \
con_init, 'con_init', \
con_write_asciiz,'con_write_asciiz', \
con_exit, 'con_exit', \
con_gets, 'con_gets',\
con_cls, 'con_cls',\
con_getch2, 'con_getch2',\
con_set_cursor_pos, 'con_set_cursor_pos',\
con_write_string, 'con_write_string',\
con_get_flags, 'con_get_flags', \
con_set_flags, 'con_set_flags'
import libini, \ import libini, \
ini.get_str, 'ini_get_str', \ ini.get_str, 'ini_get_str', \
ini.get_int, 'ini_get_int' ini.get_int, 'ini_get_int'
@ -692,8 +879,12 @@ i_end:
; uninitialised data ; uninitialised data
interface_addr rd 1
status db ? status db ?
file_size dd ?
controlsocket dd ? controlsocket dd ?
datasocket dd ? datasocket dd ?
offset dd ? offset dd ?
@ -719,16 +910,34 @@ filestruct:
.ptr dd ? .ptr dd ?
.name rb 1024 .name rb 1024
filestruct2:
.subfn dd ?
.offset dd ?
dd 0
.size dd ?
.ptr dd ?
db 0
.name dd ?
folder_buf rb 40
buf_buffer1 rb BUFFERSIZE+1 buf_buffer1 rb BUFFERSIZE+1
buf_buffer2 rb BUFFERSIZE+1 buf_buffer2 rb BUFFERSIZE+1
buf_cmd rb 1024 ; buffer for holding command string buf_cmd rb 1024 ; buffer for holding command string
log_file rb 512 ; holds log file path
logfile_offset rd 1
path rb 1024 path rb 1024
use_params db 0 initial_login rb 1
param_user rb 1024 param_user rb 1024
param_password rb 1024 param_password rb 1024
param_server_addr rb 1024 param_server_addr rb 1024
param_path rb 1024 param_path rb 1024
param_port rb 6
sc system_colors
rb 1024
mem: mem:

View File

@ -2,7 +2,7 @@
; 0 = passive / 1 = active ; 0 = passive / 1 = active
mode=0 mode=0
dir=/tmp0/1/ dir=/tmp0/1/
logfile=/usbhd0/1/ftpc.log
[active] [active]
; Local starting port for active connections ; Local starting port for active connections
port_start=2000 port_start=2000

1191
programs/network/ftpc/gui.inc Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,123 @@
SYS_COL = 0xe6e6e6
BT_COL = 0xcccccc
STR_COL = 0x595959 ;0x000000
;;================================================================================================;;
login_gui: ;//////////////////////////////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Login GUI-specific functions ;;
;;------------------------------------------------------------------------------------------------;;
;> none ;;
;;------------------------------------------------------------------------------------------------;;
;< none ;;
;;================================================================================================;;
; TODO: print error strings (wrong user, pass, etc.)
.server_addr:
mov [initial_login], 1
.get_username:
; in case of error when either login_gui.server_addr or
; login_gui.get_username is called, should resize window
mcall 67, 320, 300, 390, 200 ; resize to login gui window size
.redraw:
call .draw
jmp .still
align 4
.draw:
mcall 12, 1
mcall 0, <320,390>, <300,200>, 0x34000000+SYS_COL, 0x805080DD, hed
stdcall [edit_box_draw], edit_usr
stdcall [edit_box_draw], edit_pass
stdcall [edit_box_draw], edit_server
stdcall [edit_box_draw], edit_port
stdcall [edit_box_draw], edit_path
; draw "connect" button
mcall 8, <162,65>, <140,25>, 2, BT_COL
; draw strings
mcall 4, <3,5>, 0xb0000000, gui_str_usr
mcall 4, <3,25>, 0xb0000000, gui_str_pass
mcall 4, <3,45>, 0xb0000000, gui_str_server
mcall 4, <3,65>, 0xb0000000, gui_str_port
mcall 4, <3,85>, 0xb0000000, gui_str_path
mcall 4, <167,145>, 0xb0000000+STR_COL, gui_str_connect
mcall 4, <3,115>, 0xb0ff0000, [str_error_addr]
mov [str_error_addr], gui_str_null ; reset error string address
mcall 12, 2
ret
align 4
.still:
mcall 10 ; wait for event
dec eax
jz .redraw
dec eax
jz .key
dec eax
jz .button
stdcall [edit_box_mouse], edit_usr
stdcall [edit_box_mouse], edit_pass
stdcall [edit_box_mouse], edit_server
stdcall [edit_box_mouse], edit_port
stdcall [edit_box_mouse], edit_path
jmp .still
.button:
mcall 17
dec ah
jz .exit
dec ah ; 'Connect' button clicked
jz gui.main
jmp .still
.key:
mcall 2
stdcall [edit_box_key], edit_usr
stdcall [edit_box_key], edit_pass
stdcall [edit_box_key], edit_server
stdcall [edit_box_key], edit_port
stdcall [edit_box_key], edit_path
jmp .still
.error:
mov [str_error_addr], gui_str_error
jmp .server_addr
.exit:
jmp gui.exit
gui_str_connect db 'Connect',0
gui_str_usr db 'Username:',0
gui_str_pass db 'Password:',0
gui_str_server db 'Server:',0
gui_str_port db 'Port:',0
gui_str_path db 'Path:',0
gui_str_error db 'ERROR! Check log file for details',0
gui_str_null db ' ',0
str_error_addr dd gui_str_null
; login window components
edit_usr edit_box 300,75,5, 0xffffff,0x6f9480,0,0xAABBCC,0,99,param_user,mouse_dd,ed_focus
edit_pass edit_box 300,75,25,0xffffff,0x6a9480,0,0xAABBCC,0,99,param_password,mouse_dd,ed_pass
edit_server edit_box 300,75,45,0xffffff,0x6a9480,0,0xAABBCC,0,99,param_server_addr,mouse_dd,0
edit_port edit_box 50,75,65,0xffffff,0x6a9480,0,0xAABBCC,0,99,param_port,mouse_dd,ed_figure_only
edit_path edit_box 300,75,85,0xffffff,0x6a9480,0,0xAABBCC,0,99,param_path,mouse_dd,0
mouse_dd rd 1

View File

@ -1,126 +1,88 @@
resolve: ;;================================================================================================;;
parse_args: ;/////////////////////////////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? parses command line arguments of type ;;
;? ftp://user:password@server:port/folder/subfolder type urls and attempts to connect ;;
;? automatically ;;
;;------------------------------------------------------------------------------------------------;;
;> buf_cmd = pointer to command line arguments ;;
;;------------------------------------------------------------------------------------------------;;
;< none ;;
;;================================================================================================;;
; parse command line parameters of type cmp dword[buf_cmd], 'ftp:'
; ftp://user:password@server.com:port/folder/subfolder type urls jne @f
; check ftp://
xor edx, edx
mov esi, buf_cmd mov esi, buf_cmd
mov edi, str_ftp jmp .start
xor ecx, ecx
@@: @@:
mov al, byte [esi+edx] mov esi, buf_cmd+5
mov bl, byte [edi+edx]
inc edx .start:
cmp al, bl ; check ftp://
jne main cmp dword[esi], 'ftp:'
cmp byte [edi+edx], '/' jne .error
jne @b cmp word[esi+4], '//'
inc ecx jne .error
cmp ecx, 2
jne @b
; parse user ; parse user
mov dword[param_user], "USER" lea edi, [param_user]
mov byte[param_user+4], " " @@:
inc edx
add esi, edx
lea edi, [param_user+5]
.user:
lodsb lodsb
cmp al, 0 test al, al
jne @f jz .error
mov eax, str_err_params stosb
jmp error
@@: stosb
cmp byte [esi], ':' cmp byte [esi], ':'
jne .user jne @b
mov word [edi], 0x0a0d mov byte [edi], 0
mov byte [edi+2], 0
; parse password ; parse password
inc esi inc esi
mov dword[param_password], "PASS" lea edi, [param_password]
mov byte[param_password+4], " " @@:
lea edi, [param_password+5]
.pass:
lodsb lodsb
cmp al, 0 test al, al
jne @f jz .error
mov eax, str_err_params stosb
jmp error
@@: stosb
cmp byte [esi], '@' cmp byte [esi], '@'
jne .pass jne @b
mov word [edi], 0x0a0d mov byte [edi], 0
mov byte [edi+2], 0
; parse server address ; parse server address
inc esi inc esi
mov edi, param_server_addr mov edi, param_server_addr
.addr: @@:
lodsb lodsb
cmp al, 0 test al, al
jne @f jz .error
mov eax, str_err_params stosb
jmp error
@@: stosb
cmp byte [esi], ':' cmp byte [esi], ':'
jne .addr jne @b
mov byte [edi], 0 mov byte [edi], 0
; parse port ; parse port
inc esi inc esi
xor eax, eax lea edi, [param_port]
xor ebx, ebx @@:
mov [sockaddr1.port], 21 shl 8
.port:
lodsb lodsb
cmp al, 0 test al, al
jne @f jz .error
mov eax, str_err_params stosb
jmp error cmp byte [esi], '/'
@@: cmp al, '/' jne @b
jbe .port_done mov byte [edi], 0
sub al, '0'
jnb @f
mov eax, str_err_host
jmp error
@@: cmp al, 9
jna @f
mov eax, str_err_host
jmp error
@@: lea ebx, [ebx*4 + ebx]
shl ebx, 1
add ebx, eax
jmp .port
.port_done:
xchg bl, bh
mov [sockaddr1.port], bx
; parse path ; parse path
mov dword[param_path], "CWD " inc esi
lea edi, [param_path+4] lea edi, [param_path]
.path: @@:
lodsb movsb
stosb
cmp byte [esi], 0 cmp byte [esi], 0
jne .path jne @b
mov word [edi], 0x0a0d mov byte [edi], 0
mov byte [edi+2], 0
; parameters resolved successfully ; parameters parsed successfully
mov [use_params], 1 jmp arg_handler.connect
; copy server address to buf_cmd
mov esi, param_server_addr
mov edi, buf_cmd
.copy:
lodsb
stosb
cmp byte [edi], 0
jne .copy
mov byte [esi], 0
jmp no_resolve.done
.error:
mov eax, str_err_params
jmp error

View File

@ -5,11 +5,14 @@ server_parser:
; first lines will have a dash instead of space after numbers, ; first lines will have a dash instead of space after numbers,
; thus they are simply ignored in this simple command parser. ; thus they are simply ignored in this simple command parser.
cmp dword[buf_cmd+4], "Open"
je init_download_count
cmp dword[buf_cmd], "150 " cmp dword[buf_cmd], "150 "
je data_loop je data_loop
cmp dword[buf_cmd], "220 " cmp dword[buf_cmd], "220 "
je welcome je connect_ok
; cmp dword[buf_cmd], "226 " ; cmp dword[buf_cmd], "226 "
; je transfer_ok ; je transfer_ok
@ -33,7 +36,6 @@ server_parser:
je welcome je welcome
cmp dword[buf_cmd], "530 " ; password incorrect cmp dword[buf_cmd], "530 " ; password incorrect
mov [use_params], 0
je welcome je welcome
cmp dword[buf_cmd], "550 " cmp dword[buf_cmd], "550 "
@ -50,6 +52,11 @@ welcome:
jmp wait_for_usercommand jmp wait_for_usercommand
connect_ok:
mov [status], STATUS_CONNECTED
jmp arg_handler.copy_user
pass: pass:
mov [status], STATUS_NEEDPASSWORD mov [status], STATUS_NEEDPASSWORD
@ -59,20 +66,13 @@ pass:
login_ok: login_ok:
mov [status], STATUS_LOGGED_IN mov [status], STATUS_LOGGED_IN
cmp [use_params], 0
je wait_for_usercommand
cmp [param_path+4], 0 cmp [param_path], 0x20 ; no path specified
je wait_for_usercommand jbe wait_for_usercommand
; copy path to buf_cmd and execute CWD ; copy path to buf_cmd and execute CWD
mov edi, buf_cmd jmp arg_handler.get_path
mov esi, param_path
@@:
lodsb
stosb
cmp byte[esi-1], 0
jne @b
jmp cmd_cwd
pasv_ok: pasv_ok:
@ -104,7 +104,7 @@ pasv_ok:
call ascii_dec call ascii_dec
mov byte[sockaddr2.port+1], bl mov byte[sockaddr2.port+1], bl
invoke con_write_asciiz, str_open icall eax, interface_addr, interface.print, str_open
mcall connect, [datasocket], sockaddr2, 18 mcall connect, [datasocket], sockaddr2, 18
cmp eax, -1 cmp eax, -1
jne @f jne @f
@ -113,19 +113,56 @@ pasv_ok:
@@: jmp wait_for_servercommand @@: jmp wait_for_servercommand
.fail: .fail:
invoke con_write_asciiz, str_unknown icall eax, interface_addr, interface.print, str_unknown
jmp wait_for_servercommand jmp wait_for_servercommand
data_loop: ; get file size, initialize count for number of bytes downloaded
init_download_count:
invoke con_write_asciiz, str_dot mov edx, 0
; search for 'Open' in buf_cmd
lea esi, [buf_cmd+3]
@@:
inc esi
cmp dword[esi], 'Open'
je @f
cmp byte[esi], 0
jne @b
jmp data_loop
@@:
; get file size
mov al, '('
mov ecx, -1
mov edi, buf_cmd
repne scasb
xor eax, eax
mov ebx, 10
xor ecx, ecx
mov esi, edi
@@:
push eax
lodsb
sub al, '0'
mov cl, al
pop eax
mul ebx
add eax, ecx
cmp byte[esi], ' '
jne @b
mov [file_size], eax
data_loop:
cmp [operation], OPERATION_STOR cmp [operation], OPERATION_STOR
je .stor je .stor
push edx
; we are receiving data ; we are receiving data
mcall recv, [datasocket], buf_buffer2, BUFFERSIZE, 0 mcall recv, [datasocket], buf_buffer2, BUFFERSIZE, 0
pop edx ; get byte count
add edx, eax
test ebx, ebx test ebx, ebx
jnz .done jnz .done
mov byte[buf_buffer2 + eax], 0 mov byte[buf_buffer2 + eax], 0
@ -136,18 +173,33 @@ data_loop:
cmp [operation], OPERATION_RDIR cmp [operation], OPERATION_RDIR
je .rdir je .rdir
cmp [operation], OPERATION_LIST
je .list
; not retreiving, just print to console ; not retreiving, just print to console
invoke con_write_asciiz, buf_buffer2 icall eax, interface_addr, interface.print, buf_buffer2
jmp data_loop jmp data_loop
; for console, simply print. for gui, add name to tree list
.list:
ijmp ebx, interface_addr, interface.list
; retreiving, save to file ; retreiving, save to file
.retr: .retr:
mov [filestruct.ptr], buf_buffer2 mov [filestruct.ptr], buf_buffer2
mov [filestruct.size], eax mov [filestruct.size], eax
push eax push eax
mcall 70, filestruct mcall 70, filestruct
test eax, eax
jz @f
call error_fs
jmp close_datacon
@@:
pop eax pop eax
add [filestruct.offset], eax add [filestruct.offset], eax
icall eax, interface_addr, interface.progress
jmp data_loop jmp data_loop
; storing, send all data ; storing, send all data
@ -156,18 +208,25 @@ data_loop:
cmp eax, 6 ; end of file cmp eax, 6 ; end of file
je .last_call je .last_call
test eax, eax ; error test eax, eax ; error
; jne .fileerror jz @f
call error_fs
jmp close_datacon
@@:
add [filestruct.offset], ebx add [filestruct.offset], ebx
mov esi, ebx mov esi, ebx
mcall send, [datasocket], buf_buffer2, , 0 mcall send, [datasocket], buf_buffer2, , 0
mov edx, [filestruct.offset]
icall eax, interface_addr, interface.progress
jmp .stor jmp .stor
.last_call: .last_call:
mov esi, ebx mov esi, ebx
mcall send, [datasocket], buf_buffer2, , 0 mcall send, [datasocket], buf_buffer2, , 0
mov edx, [filestruct.offset]
icall eax, interface_addr, interface.progress
.done: .done:
invoke con_write_asciiz, str_close icall eax, interface_addr, interface.print, str_close
mcall close, [datasocket] mcall close, [datasocket]
mov [operation], OPERATION_NONE mov [operation], OPERATION_NONE
jmp wait_for_servercommand jmp wait_for_servercommand
@ -209,7 +268,7 @@ data_loop:
close_datacon: close_datacon:
cmp [operation], OPERATION_NONE cmp [operation], OPERATION_NONE
je wait_for_usercommand je wait_for_usercommand
invoke con_write_asciiz, str_close icall eax, interface_addr, interface.print, str_close
mcall close, [datasocket] mcall close, [datasocket]
jmp wait_for_usercommand jmp wait_for_usercommand

View File

@ -15,7 +15,7 @@ cmd_bye:
; Close the control connection ; Close the control connection
mcall close, [controlsocket] mcall close, [controlsocket]
jmp main ijmp eax, interface_addr, interface.server_addr
cmd_pwd: cmd_pwd:
@ -46,7 +46,7 @@ cmd_cwd:
cmd_dele: cmd_dele:
mov dword[buf_cmd], "DELE" mov dword[buf_cmd], "DELE"
mov byte[buf_cmd], " " mov byte[buf_cmd+4], " "
mov ecx, 256 mov ecx, 256
xor al, al xor al, al
@ -76,8 +76,7 @@ cmd_retr:
call open_dataconnection call open_dataconnection
; Create/open the file ; Create/open the file
; TODO: check beforehand if the disk has enough free space available to store the file
; Create/open the file
mov esi, buf_cmd+5 mov esi, buf_cmd+5
mov ecx, 256-5 mov ecx, 256-5
@ -90,9 +89,11 @@ cmd_retr:
mov [filestruct.ptr], 0 mov [filestruct.ptr], 0
mcall 70, filestruct mcall 70, filestruct
cmp eax, -1 test eax, eax
; je fileerror jz @f
call error_fs
jmp close_datacon
@@:
; Prepare to write to the file ; Prepare to write to the file
mov [filestruct.subfn], 3 ; write to file mov [filestruct.subfn], 3 ; write to file
@ -111,7 +112,7 @@ cmd_retr:
mov dword[edi - 2], 0x0a0d mov dword[edi - 2], 0x0a0d
mcall send, [controlsocket], buf_cmd, , 0 mcall send, [controlsocket], buf_cmd, , 0
invoke con_write_asciiz, buf_cmd ; print command icall eax, interface_addr, interface.print, buf_cmd
jmp wait_for_servercommand jmp wait_for_servercommand
cmd_rdir: cmd_rdir:
@ -136,16 +137,28 @@ cmd_stor:
mov [operation], OPERATION_STOR mov [operation], OPERATION_STOR
mov [filestruct.subfn], 0 ; read file ; get file size
mov [filestruct.subfn], 5
mov [filestruct.offset], 0 mov [filestruct.offset], 0
mov [filestruct.offset+4], 0 mov [filestruct.offset+4], 0
mov [filestruct.size], BUFFERSIZE mov [filestruct.size], 0
mov [filestruct.ptr], buf_buffer2 mov [filestruct.ptr], folder_buf
mov esi, buf_cmd+5 mov esi, buf_cmd+5
mov ecx, 256-5 mov ecx, 256-5
call set_filename call set_filename
mcall 70, filestruct
mov eax, dword[folder_buf+32] ; supports file size upto 4GB
mov [file_size], eax
mov [filestruct.subfn], 0 ; read file
; mov [filestruct.offset], 0
; mov [filestruct.offset+4], 0
mov [filestruct.size], BUFFERSIZE
mov [filestruct.ptr], buf_buffer2
mov dword[buf_cmd], "STOR" mov dword[buf_cmd], "STOR"
mov byte[buf_cmd+4], " " mov byte[buf_cmd+4], " "
@ -169,19 +182,34 @@ cmd_lcwd:
.loop: .loop:
lodsb lodsb
cmp al, 10 cmp al, 10
je .done je .check
test al, al test al, al
je .done je .check
loop .loop loop .loop
.done:
.check:
mov byte[esi-1], 0 mov byte[esi-1], 0
; check whether entered path is valid (folder exists)
mov [filestruct2.subfn], 5
mov [filestruct2.offset], 0
mov [filestruct2.size], 0
mov [filestruct2.ptr], folder_buf
mov [filestruct2.name], buf_cmd+5
mcall 70, filestruct2
test eax, eax
jz @f
cmp eax, 2
je @f
call error_fs
jmp wait_for_usercommand
@@:
mcall 30, 1, buf_cmd+5 ; set working directory mcall 30, 1, buf_cmd+5 ; set working directory
.print: .print:
mcall 30, 2, buf_cmd, 256 ; and read it again mcall 30, 2, buf_cmd, 256 ; and read it again
icall eax, interface_addr, interface.print, str_lcwd, buf_cmd, str_newline
invoke con_write_asciiz, str_lcwd
invoke con_write_asciiz, buf_cmd
invoke con_write_asciiz, str_newline
jmp wait_for_usercommand jmp wait_for_usercommand
@ -189,7 +217,7 @@ cmd_lcwd:
cmd_cdup: cmd_cdup:
mov dword[buf_cmd], "CDUP" mov dword[buf_cmd], "CDUP"
mov word[buf_cmd+4], 0x0d0a mov word[buf_cmd+4], 0x0a0d
mcall send, [controlsocket], buf_cmd, 6, 0 mcall send, [controlsocket], buf_cmd, 6, 0
jmp wait_for_servercommand jmp wait_for_servercommand
@ -227,6 +255,12 @@ cmd_mkd:
jmp wait_for_servercommand jmp wait_for_servercommand
cmd_abor:
mcall close, [datasocket]
jmp wait_for_servercommand
; esi = source ptr ; esi = source ptr
; ecx = max length of source buffer ; ecx = max length of source buffer
set_filename: set_filename: