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 ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; Modified by nisargshah323@gmail.com (2016) ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
@ -41,16 +42,49 @@ use32
dd path ; path
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
include '../../proc32.inc'
include '../../dll.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 'servercommands.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
mcall 68,11
test eax,eax
@ -62,9 +96,6 @@ start:
stdcall dll.Load, @IMPORT
test eax, eax
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)
mov edi, path ; Calculate the length of zero-terminated string
xor al, al
@ -99,48 +130,144 @@ start:
invoke ini.get_str, path, str_general, str_dir, buf_buffer1, BUFFERSIZE, 0
mcall 30, 1, buf_buffer1 ; set working directory
; Check for parameters, if there are some, resolve the address right away
; TODO: parse ftp://user:password@server.com:port/folder/subfolder type urls.
cmp byte [buf_cmd], 0
jne resolve
; initialize log file
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
main:
; 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
; Usage: ftpc [-cli] [ftp://username:password@server:port/path]
no_resolve:
mov [sockaddr1.port], 21 shl 8
; mov dword[buf_cmd], '-cli' ;;;; to test CLI ;;;;;
; delete terminating '\n'
mov esi, buf_cmd
cmp byte[buf_cmd], 0
jne @f
mov [interface_addr], gui
jmp .args_ok
@@: cmp dword[buf_cmd], '-cli'
jne .error
mov [interface_addr], console
jmp .args_ok
.args_ok:
icall eax, interface_addr, interface.init
; 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
.error:
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
cmp al, ':'
je .do_port
stosb
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
ja @r
mov byte [esi-1], 0
jmp .done
mov byte[edi-1], 0 ; delete terminating '\n'
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:
xor eax, eax
xor ebx, ebx
mov byte [esi-1], 0
.portloop:
lodsb
cmp al, 0x20
@ -161,11 +288,15 @@ no_resolve:
.port_done:
xchg bl, bh
mov [sockaddr1.port], bx
jmp .done
.default_port:
mov [sockaddr1.port], 21 shl 8
.done:
; Say to the user that we're resolving
invoke con_write_asciiz, str_resolve
invoke con_write_asciiz, buf_cmd
icall eax, interface_addr, interface.set_flags, 0x07 ; reset color
icall eax, interface_addr, interface.print, str_resolve, buf_cmd
; resolve name
push esp ; reserve stack place
invoke getaddrinfo, buf_cmd, 0, 0, esp
@ -177,14 +308,13 @@ no_resolve:
jmp error
@@:
; 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, [eax+sockaddr_in.sin_addr] ;
mov [sockaddr1.ip], 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 con_write_asciiz, str9 ; ')',10,0
; open the socket
mcall socket, AF_INET4, SOCK_STREAM, 0
cmp eax, -1
@ -193,7 +323,7 @@ no_resolve:
jmp error
@@: mov [controlsocket], eax
; connect to the server
invoke con_write_asciiz, str_connect
icall eax, interface_addr, interface.print, str_connect
mcall connect, [controlsocket], sockaddr1, 18
cmp eax, -1
jne @f
@ -201,12 +331,22 @@ no_resolve:
jmp error
@@: mov [status], STATUS_CONNECTING
; 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
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?
cmp [offset], 0
je .receive ; nope, receive some more
@ -268,16 +408,25 @@ wait_for_servercommand:
xor al, al
stosb
invoke con_set_flags, 0x03 ; change color
invoke con_write_asciiz, buf_cmd ; print servercommand
invoke con_write_asciiz, str_newline
invoke con_set_flags, 0x07 ; reset color
icall eax, interface_addr, interface.set_flags, 0x03 ; change color
icall eax, interface_addr, interface.print, buf_cmd, str_newline
icall eax, interface_addr, interface.set_flags, 0x07 ; reset color
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?
@ -285,24 +434,19 @@ wait_for_usercommand:
ja transfer_queued ; Yes, transfer those first.
; 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
cmp [status], STATUS_CONNECTED
je .connected
je arg_handler.get_username
cmp [status], STATUS_NEEDPASSWORD
je .needpass
je arg_handler.get_pass
; 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
ijmp eax, interface_addr, interface.get_cmd
.parse_cmd:
cmp dword[buf_cmd], "cwd "
je cmd_cwd
@ -349,78 +493,15 @@ wait_for_usercommand:
cmp dword[buf_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
invoke con_write_asciiz, str_unknown
icall eax, interface_addr, interface.print, str_unknown
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
transfer_queued:
@ -551,26 +632,112 @@ dword_ascii:
pop ecx ebx edx
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
invoke con_set_flags, 0x0c ; print errors in red
icall ebx, interface_addr, interface.set_flags, 0x0c ; print errors in red
pop eax
invoke con_write_asciiz, eax
icall ebx, interface_addr, interface.print, eax
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:
invoke con_set_flags, 0x0c ; print errors in red
invoke con_write_asciiz, str_err_heap
icall eax, interface_addr, interface.set_flags, 0x0c ; print errors in red
icall eax, interface_addr, interface.print, str_err_heap
wait_for_keypress:
invoke con_set_flags, 0x07 ; reset color to grey
invoke con_write_asciiz, str_push
invoke con_getch2
mcall close, [controlsocket]
jmp main
done:
invoke con_exit, 1
icall eax, interface_addr, interface.set_flags, 0x07 ; reset color to grey
icall eax, interface_addr, interface.print, str_push
ijmp eax, interface_addr, interface.error
exit:
mcall close, [controlsocket]
@ -582,10 +749,8 @@ exit2:
; data
str_title db 'FTP client',0
str_welcome db 'FTP client for KolibriOS v0.12',10
db 10
db 'Please enter ftp server address.',10,0
str_ftp db 'ftp://',0
db 10,0
str_srv_addr db 'Please enter ftp server address.',10,0
str_prompt db '> ',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_host db 10,'Invalid hostname.',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
str9 db ')',10,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_user db "username: ",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_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_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_dir db 'dir', 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
mode db 0 ; passive = 0, active = 1
; FTP strings
str_PASV db 'PASV',13,10
@ -659,32 +845,33 @@ sockaddr2:
.ip dd ?
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
align 4
@IMPORT:
library network, 'network.obj', console, 'console.obj', libini, 'libini.obj'
library network, 'network.obj', libini, 'libini.obj'
import network, \
getaddrinfo, 'getaddrinfo', \
freeaddrinfo, 'freeaddrinfo', \
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, \
ini.get_str, 'ini_get_str',\
ini.get_str, 'ini_get_str', \
ini.get_int, 'ini_get_int'
@ -692,8 +879,12 @@ i_end:
; uninitialised data
interface_addr rd 1
status db ?
file_size dd ?
controlsocket dd ?
datasocket dd ?
offset dd ?
@ -719,16 +910,34 @@ filestruct:
.ptr dd ?
.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_buffer2 rb BUFFERSIZE+1
buf_cmd rb 1024 ; buffer for holding command string
log_file rb 512 ; holds log file path
logfile_offset rd 1
path rb 1024
use_params db 0
initial_login rb 1
param_user rb 1024
param_password rb 1024
param_server_addr rb 1024
param_path rb 1024
param_port rb 6
sc system_colors
rb 1024
mem:

View File

@ -2,7 +2,7 @@
; 0 = passive / 1 = active
mode=0
dir=/tmp0/1/
logfile=/usbhd0/1/ftpc.log
[active]
; Local starting port for active connections
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
; ftp://user:password@server.com:port/folder/subfolder type urls
; check ftp://
xor edx, edx
cmp dword[buf_cmd], 'ftp:'
jne @f
mov esi, buf_cmd
mov edi, str_ftp
xor ecx, ecx
jmp .start
@@:
mov al, byte [esi+edx]
mov bl, byte [edi+edx]
inc edx
cmp al, bl
jne main
cmp byte [edi+edx], '/'
jne @b
inc ecx
cmp ecx, 2
jne @b
mov esi, buf_cmd+5
.start:
; check ftp://
cmp dword[esi], 'ftp:'
jne .error
cmp word[esi+4], '//'
jne .error
; parse user
mov dword[param_user], "USER"
mov byte[param_user+4], " "
inc edx
add esi, edx
lea edi, [param_user+5]
.user:
lea edi, [param_user]
@@:
lodsb
cmp al, 0
jne @f
mov eax, str_err_params
jmp error
@@: stosb
test al, al
jz .error
stosb
cmp byte [esi], ':'
jne .user
mov word [edi], 0x0a0d
mov byte [edi+2], 0
jne @b
mov byte [edi], 0
; parse password
inc esi
mov dword[param_password], "PASS"
mov byte[param_password+4], " "
lea edi, [param_password+5]
.pass:
lea edi, [param_password]
@@:
lodsb
cmp al, 0
jne @f
mov eax, str_err_params
jmp error
@@: stosb
test al, al
jz .error
stosb
cmp byte [esi], '@'
jne .pass
mov word [edi], 0x0a0d
mov byte [edi+2], 0
jne @b
mov byte [edi], 0
; parse server address
inc esi
mov edi, param_server_addr
.addr:
@@:
lodsb
cmp al, 0
jne @f
mov eax, str_err_params
jmp error
@@: stosb
test al, al
jz .error
stosb
cmp byte [esi], ':'
jne .addr
jne @b
mov byte [edi], 0
; parse port
inc esi
xor eax, eax
xor ebx, ebx
mov [sockaddr1.port], 21 shl 8
.port:
lea edi, [param_port]
@@:
lodsb
cmp al, 0
jne @f
mov eax, str_err_params
jmp error
@@: cmp al, '/'
jbe .port_done
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
test al, al
jz .error
stosb
cmp byte [esi], '/'
jne @b
mov byte [edi], 0
; parse path
mov dword[param_path], "CWD "
lea edi, [param_path+4]
.path:
lodsb
stosb
inc esi
lea edi, [param_path]
@@:
movsb
cmp byte [esi], 0
jne .path
mov word [edi], 0x0a0d
mov byte [edi+2], 0
jne @b
mov byte [edi], 0
; parameters resolved successfully
mov [use_params], 1
; 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
; parameters parsed successfully
jmp arg_handler.connect
.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,
; 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 "
je data_loop
cmp dword[buf_cmd], "220 "
je welcome
je connect_ok
; cmp dword[buf_cmd], "226 "
; je transfer_ok
@ -33,7 +36,6 @@ server_parser:
je welcome
cmp dword[buf_cmd], "530 " ; password incorrect
mov [use_params], 0
je welcome
cmp dword[buf_cmd], "550 "
@ -50,6 +52,11 @@ welcome:
jmp wait_for_usercommand
connect_ok:
mov [status], STATUS_CONNECTED
jmp arg_handler.copy_user
pass:
mov [status], STATUS_NEEDPASSWORD
@ -59,20 +66,13 @@ pass:
login_ok:
mov [status], STATUS_LOGGED_IN
cmp [use_params], 0
je wait_for_usercommand
cmp [param_path+4], 0
je wait_for_usercommand
cmp [param_path], 0x20 ; no path specified
jbe wait_for_usercommand
; copy path to buf_cmd and execute CWD
mov edi, buf_cmd
mov esi, param_path
@@:
lodsb
stosb
cmp byte[esi-1], 0
jne @b
jmp cmd_cwd
jmp arg_handler.get_path
pasv_ok:
@ -104,7 +104,7 @@ pasv_ok:
call ascii_dec
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
cmp eax, -1
jne @f
@ -113,19 +113,56 @@ pasv_ok:
@@: jmp wait_for_servercommand
.fail:
invoke con_write_asciiz, str_unknown
icall eax, interface_addr, interface.print, str_unknown
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
je .stor
push edx
; we are receiving data
mcall recv, [datasocket], buf_buffer2, BUFFERSIZE, 0
pop edx ; get byte count
add edx, eax
test ebx, ebx
jnz .done
mov byte[buf_buffer2 + eax], 0
@ -136,18 +173,33 @@ data_loop:
cmp [operation], OPERATION_RDIR
je .rdir
cmp [operation], OPERATION_LIST
je .list
; not retreiving, just print to console
invoke con_write_asciiz, buf_buffer2
icall eax, interface_addr, interface.print, buf_buffer2
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
.retr:
mov [filestruct.ptr], buf_buffer2
mov [filestruct.size], eax
push eax
mcall 70, filestruct
test eax, eax
jz @f
call error_fs
jmp close_datacon
@@:
pop eax
add [filestruct.offset], eax
icall eax, interface_addr, interface.progress
jmp data_loop
; storing, send all data
@ -156,18 +208,25 @@ data_loop:
cmp eax, 6 ; end of file
je .last_call
test eax, eax ; error
; jne .fileerror
jz @f
call error_fs
jmp close_datacon
@@:
add [filestruct.offset], ebx
mov esi, ebx
mcall send, [datasocket], buf_buffer2, , 0
mov edx, [filestruct.offset]
icall eax, interface_addr, interface.progress
jmp .stor
.last_call:
mov esi, ebx
mcall send, [datasocket], buf_buffer2, , 0
mov edx, [filestruct.offset]
icall eax, interface_addr, interface.progress
.done:
invoke con_write_asciiz, str_close
icall eax, interface_addr, interface.print, str_close
mcall close, [datasocket]
mov [operation], OPERATION_NONE
jmp wait_for_servercommand
@ -209,7 +268,7 @@ data_loop:
close_datacon:
cmp [operation], OPERATION_NONE
je wait_for_usercommand
invoke con_write_asciiz, str_close
icall eax, interface_addr, interface.print, str_close
mcall close, [datasocket]
jmp wait_for_usercommand

View File

@ -15,7 +15,7 @@ cmd_bye:
; Close the control connection
mcall close, [controlsocket]
jmp main
ijmp eax, interface_addr, interface.server_addr
cmd_pwd:
@ -46,7 +46,7 @@ cmd_cwd:
cmd_dele:
mov dword[buf_cmd], "DELE"
mov byte[buf_cmd], " "
mov byte[buf_cmd+4], " "
mov ecx, 256
xor al, al
@ -76,8 +76,7 @@ cmd_retr:
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
mov esi, buf_cmd+5
mov ecx, 256-5
@ -90,9 +89,11 @@ cmd_retr:
mov [filestruct.ptr], 0
mcall 70, filestruct
cmp eax, -1
; je fileerror
test eax, eax
jz @f
call error_fs
jmp close_datacon
@@:
; Prepare to write to the file
mov [filestruct.subfn], 3 ; write to file
@ -111,7 +112,7 @@ cmd_retr:
mov dword[edi - 2], 0x0a0d
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
cmd_rdir:
@ -136,16 +137,28 @@ cmd_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+4], 0
mov [filestruct.size], BUFFERSIZE
mov [filestruct.ptr], buf_buffer2
mov [filestruct.size], 0
mov [filestruct.ptr], folder_buf
mov esi, buf_cmd+5
mov ecx, 256-5
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 byte[buf_cmd+4], " "
@ -169,19 +182,34 @@ cmd_lcwd:
.loop:
lodsb
cmp al, 10
je .done
je .check
test al, al
je .done
je .check
loop .loop
.done:
.check:
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
.print:
mcall 30, 2, buf_cmd, 256 ; and read it again
invoke con_write_asciiz, str_lcwd
invoke con_write_asciiz, buf_cmd
invoke con_write_asciiz, str_newline
icall eax, interface_addr, interface.print, str_lcwd, buf_cmd, str_newline
jmp wait_for_usercommand
@ -189,7 +217,7 @@ cmd_lcwd:
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
jmp wait_for_servercommand
@ -227,6 +255,12 @@ cmd_mkd:
jmp wait_for_servercommand
cmd_abor:
mcall close, [datasocket]
jmp wait_for_servercommand
; esi = source ptr
; ecx = max length of source buffer
set_filename: