diff --git a/programs/develop/libraries/box_lib/trunk/tl_nod_16_w.bmp b/programs/develop/libraries/box_lib/trunk/tl_nod_16_w.bmp new file mode 100755 index 0000000000..0e4cc1426f Binary files /dev/null and b/programs/develop/libraries/box_lib/trunk/tl_nod_16_w.bmp differ diff --git a/programs/develop/libraries/box_lib/trunk/tl_sys_16_w.bmp b/programs/develop/libraries/box_lib/trunk/tl_sys_16_w.bmp new file mode 100755 index 0000000000..4ef44bdefa Binary files /dev/null and b/programs/develop/libraries/box_lib/trunk/tl_sys_16_w.bmp differ diff --git a/programs/network/ftpc/README.txt b/programs/network/ftpc/README.txt new file mode 100755 index 0000000000..5ed8a38291 --- /dev/null +++ b/programs/network/ftpc/README.txt @@ -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 diff --git a/programs/network/ftpc/console.inc b/programs/network/ftpc/console.inc new file mode 100755 index 0000000000..af92208d95 --- /dev/null +++ b/programs/network/ftpc/console.inc @@ -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' \ No newline at end of file diff --git a/programs/network/ftpc/ftpc.asm b/programs/network/ftpc/ftpc.asm index a9458b6911..d2fc31c970 100644 --- a/programs/network/ftpc/ftpc.asm +++ b/programs/network/ftpc/ftpc.asm @@ -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 ; ,')',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,41 +408,45 @@ 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? cmp [queued], 0 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 @@ -628,7 +811,7 @@ str_help db "available commands:",10 db "retr - retreive file from the server",10 db "rmd - remove directory from the server",10 db "stor - store file on the server",10 - db "rdir - retreive all files from current server dir",10 + db "rdir - retreive all files from current server dir",10 db 10,0 str_ini db '.ini', 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', \ +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',\ +import libini, \ + 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: diff --git a/programs/network/ftpc/ftpc.ini b/programs/network/ftpc/ftpc.ini index c793f98861..af35cedfa6 100644 --- a/programs/network/ftpc/ftpc.ini +++ b/programs/network/ftpc/ftpc.ini @@ -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 diff --git a/programs/network/ftpc/gui.inc b/programs/network/ftpc/gui.inc new file mode 100755 index 0000000000..1ae65f48ba --- /dev/null +++ b/programs/network/ftpc/gui.inc @@ -0,0 +1,1191 @@ +@use_library_mem mem.Alloc, mem.Free, mem.ReAlloc, dll.Load + +fn_icon1 db '../../develop/libraries/box_lib/trunk/tl_sys_16_w.bmp', 0 +fn_icon2 db '../../develop/libraries/box_lib/trunk/tl_nod_16_w.bmp', 0 +bmp_icon dd 0 + +TLIST_SZ = 325+16 ;=341. 16 is x-size of scroll bar +TLIST1_X = 50 +TLIST2_X = 409 +BT_SZ_X = 40 +SYS_COL = 0xe6e6e6 +BT_COL = 0xcccccc +STR_COL = 0x595959 ;0x000000 + +; TODO: automatic resizing of GUI elements on window resizing + +align 4 +;;================================================================================================;; +gui: ;////////////////////////////////////////////////////////////////////////////////////////////;; +;;------------------------------------------------------------------------------------------------;; +;? GUI-specific functions ;; +;;------------------------------------------------------------------------------------------------;; +;> none ;; +;;------------------------------------------------------------------------------------------------;; +;< 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 libraries + stdcall dll.Load, @IMPORT_BOXLIB + test eax, eax + jnz .exit + + mcall 48, 3, sc, sizeof.system_colors + mcall 40, 0xC0000027 ; set event mask + ret + + .server_addr: + mov [auto_list], 1 + jmp login_gui.server_addr + + .get_username: + jmp login_gui.get_username + + +;;================================================================================================;; + .main: ;//////////////////////////////////////////////////////////////////////////////////////;; +;;------------------------------------------------------------------------------------------------;; +;? Initialize tree list, editbox and textedit elements ;; +;;------------------------------------------------------------------------------------------------;; +;> none ;; +;;------------------------------------------------------------------------------------------------;; +;< none ;; +;;================================================================================================;; + + stdcall [ted_init], tedit0 + mov dword[tedit0.rec.width], 9 + mov dword[tedit0.rec.height], 16 + + stdcall dword[edit_box_set_text], edit_volume, root_dir + + ; initialize tree list elements + stdcall dword[tl_data_init], tree1 + stdcall dword[tl_data_init], tree2 + + ; read *.bmp file system icons + copy_path fn_icon1,path,filestruct.name, 0 + + mov ecx, 3*256*13 + stdcall mem.Alloc, ecx + mov [bmp_icon], eax + + mov [filestruct.ptr], eax + mov [filestruct.subfn], 0 + mov [filestruct.offset], 54 + mov [filestruct.size], ecx + mcall 70, filestruct + cmp ebx, 0 + jl @f + m2m dword[tree1.data_img_sys], dword[bmp_icon] + m2m dword[tree2.data_img_sys], dword[bmp_icon] + + @@: + ; read * .bmp file with the icon of nodes + copy_path fn_icon2, path, filestruct.name, 0 + + mov ecx, 3*256*13 + stdcall mem.Alloc, ecx + mov [bmp_icon], eax + + mov [filestruct.ptr], eax + ;mov [filestruct.subfn], 0 + ;mov [filestruct.offset], 54 + mov [filestruct.size], ecx + mcall 70, filestruct + cmp ebx, 0 + jl @f + m2m dword[tree1.data_img], dword[bmp_icon] + m2m dword[tree2.data_img], dword[bmp_icon] + + @@: + mcall 67, 35, 20, 830, 555 ; resize to main gui window's coordinates + call .draw + ; create initial tree list for root_dir + call populate_local_tree_list + jmp arg_handler.connect + + .get_cmd: + dec [auto_list] + jnz .redraw + call .clear_remote_tree + jmp cmd_list + + .redraw: + call .draw + + align 4 + .still: + mcall 10 + + dec eax + jz .redraw + dec eax + jz .key + dec eax + jz .button + sub eax, 3 + jz .mouse + + jmp .still + + .error: + jmp login_gui.error + + .exit: + ; stdcall mem.Free,[bmp_icon] + stdcall dword[tl_data_clear], tree1 + stdcall dword[tl_data_clear], tree2 + stdcall [ted_delete], tedit0 + jmp exit + + align 4 + .draw: + mcall 12, 1 + ; main window + mcall 0, <35,830>, <20,555>, 0x34000000+SYS_COL, 0x805080DD, hed + + ;------------------------- + ; textedit components + ;------------------------- + mcall 9, procinfo, -1 + mov edi, tedit0 + call EvSize + + movzx ebx,word[procinfo.client_box.width] + inc bx + mcall 13, , ted_wnd_t + stdcall [ted_draw], tedit0 + + ; draw "disconnect" button + mcall 8, <50,85>, <25,25>, 3, BT_COL + ; string "disconnect" + mcall 4, <50+5,25+5>, 0xb0000000+STR_COL, str_disconnect + ; draw "Copy" button + mcall 8, <50,40>, <326,25>, 4, BT_COL + ; string "copy" + mcall 4, <50+5,326+5>, 0xb0000000+STR_COL, str_copy + ; draw "Search" button + mcall 8, , <20,25>, 5, BT_COL + ; string "Search" + mcall 4, , 0xb0000000+STR_COL, str_search + + ; draw "LIST" button + mcall 8, , <50,25>, 12, BT_COL + ; string "LIST" + mcall 4, , 0xb0000000+STR_COL, str_list + ; draw "DELE" button + mcall 8, , <50,25>, 7, BT_COL + ; string "DELE" + mcall 4, , 0xb0000000+STR_COL, str_dele + ; draw "RDIR" button + mcall 8, , <50,25>, 8, BT_COL + ; string "RDIR" + mcall 4, , 0xb0000000+STR_COL, str_rdir + ; draw "RMD" button + mcall 8, , <50,25>, 9, BT_COL + ; string "RMD" + mcall 4, , 0xb0000000+STR_COL, str_rmd + + ; draw "mkd" button + mcall 8, , <80,20>, 6, BT_COL + ; string "mkd" + mcall 4, , 0xb0000000+STR_COL, str_mkd + + ; draw "cancel" button + mcall 8, <555,55>, <308,25>, 10, BT_COL + ; string "Cancel" + mcall 4, <555+5,308+5>, 0xb0000000+STR_COL, str_abort + ; draw "change volume" button + mcall 8, , <100-20,22>, 11, BT_COL + ; string "Change" + mcall 4, , 0xb0000000+STR_COL, str_change + + ;-------------------------- + ; tree list components + ;-------------------------- + stdcall dword[tl_draw], tree1 + stdcall dword[tl_draw], tree2 + + mov dword[wScr.all_redraw], 1 + stdcall [scrollbar_ver_draw], wScr + + mov dword[wScr2.all_redraw],1 + stdcall [scrollbar_ver_draw], wScr2 + + stdcall [edit_box_draw], edit_mkd + stdcall [edit_box_draw], edit_volume + stdcall [edit_box_draw], edit_search + + ; progress bar + stdcall [progressbar_draw], pb + + mcall 12,2 + ret + + align 16 + .mouse: + mcall 37, 1 + cmp word[tedit0.wnd.top], ax + jg .no_edit + + shr eax, 16 + cmp word[tedit0.wnd.left], ax + jg .no_edit + + mcall 37, 3 + bt eax, 24 + jnc @f + + stdcall [ted_but_select_word], tedit0 + jmp .still + + @@: + stdcall [ted_mouse], tedit0 + jmp .still + + .no_edit: + stdcall [tl_mouse], tree1 + stdcall [tl_mouse], tree2 + stdcall [edit_box_mouse], edit_mkd + stdcall [edit_box_mouse], edit_volume + stdcall [edit_box_mouse], edit_search + jmp .still + + align 16 + .key: + mcall 2 + stdcall [tl_key], tree1 + stdcall [tl_key], tree2 + stdcall [edit_box_key], edit_mkd + stdcall [edit_box_key], edit_volume + stdcall [edit_box_key], edit_search + jmp .still + + align 16 + .button: + mcall 17 + + cmp ah, 3 + jne @f + ijmp eax, interface_addr, interface.server_addr + jmp .still + + @@: + cmp ah, 4 + jne @f + stdcall [ted_but_copy], tedit0 + jmp .still + + @@: + cmp ah, 5 + jne @f + je filter_remote_list + + @@: + cmp ah, 6 + je create_remote_dir + + cmp ah, 7 + je delete_file + + cmp ah, 8 + je cmd_rdir + + cmp ah, 9 + je remove_dir + + cmp ah, 10 + je cmd_abor + + cmp ah, 11 + jne @f + call populate_local_tree_list + + @@: + cmp ah, 12 + jne @f + call .clear_remote_tree + je cmd_list + + @@: + cmp ah, 1 + je .exit + + jmp .still + + .print: + pushad + mov ebx, ted_opt_ed_change_time + ted_opt_ed_move_cursor + mov ecx, 2 ; 0a0d + mov esi, [esp+36] + mov word[tedit_buffer], 0x0a0d + lea edi, [tedit_buffer+2] + + @@: + movsb + inc ecx + cmp byte[esi], 0 + jne @b + stdcall [ted_text_add], tedit0, tedit_buffer, ecx, ebx + stdcall [ted_draw], tedit0 + ; write to log file + mov eax, [esp+36] + cmp [logfile_offset], -1 ; disabled logging? + je @f + call write_to_file + + @@: + popad + ret 4 + + .set_flags: + ret 4 + + +;;================================================================================================;; + .list: ;//////////////////////////////////////////////////////////////////////////////////////;; +;;------------------------------------------------------------------------------------------------;; +;? update tree2 with remote directory listing ;; +;;------------------------------------------------------------------------------------------------;; +;> buf_buffer2 = received data buffer ;; +;> eax = size of data ;; +;> remote_list_buf = buffer containing last incomplete entry (if any) ;; +;;------------------------------------------------------------------------------------------------;; +;< none ;; +;;================================================================================================;; + + push edx + push eax + ; check if any incomplete entry to be parsed + cmp byte[remote_list_buf], 0 + je .no_backlog + ; find end of remote_list_buf + mov edi, remote_list_buf + mov al, 0 + repne scasb + ; copy rest of the incomplete entry to remote_list_buf + mov esi, buf_buffer2 + dec edi + + @@: + movsb + cmp word[esi-2], 0x0a0d + jne @b + mov byte[edi], 0 + mov ecx, edi + sub ecx, remote_list_buf ; ecx = length of remote_list_buf + mov ebx, esi ; ebx = address at which next parse should start + mov edi, remote_list_buf + jmp .start_parsing + + .no_backlog: + mov ecx, eax ; ecx = number of bytes remaining to parse in buf_buffer2 + mov edi, buf_buffer2 + + .start_parsing: + ; find pointer to name + cmp byte[edi], 'd' ; file is a directory + je @f + cmp byte[edi], 'l' ; link + je @f + mov word[node_entry2], 'fi' + jmp .parse + + @@: + mov word[node_entry2], 'fo' + + .parse: + mov edx, 8 + + @@: + mov al, ' ' + mov ecx, [esp] + add ecx, buf_buffer2 + sub ecx, edi + + repne scasb + + ; check if the (last) entry is incomplete + test ecx, ecx + jz .store_last_entry + + rep scasb + test ecx, ecx + jz .store_last_entry + + dec edx + jnz @b + + lea esi, [edi-1] + lea edi, [node_entry2+4] + @@: + movsb + cmp word[esi], 0x0a0d ; end of entry + jne @b + mov byte[edi], 0 + + ; add node to tree list + cmp word[node_entry2], 'fi' + jne @f + stdcall dword[tl_node_add], tree2, 0, node_entry2 + jmp .added_remote_node + + @@: + stdcall dword[tl_node_add], tree2, 0x10000, node_entry2 + + .added_remote_node: + ; check whether we are parsing remote_list_buf + cmp byte[remote_list_buf], 0 + je @f + mov byte[remote_list_buf], 0 ; done parsing remote_list_buf + mov edi, ebx + mov eax, [esp] + mov ecx, buf_buffer2 + add ecx, eax + sub ecx, ebx + jmp .start_parsing + + @@: + ; any more entries to parse? + lea edi, [esi+2] ; skip 0a0d + cmp byte[edi], 0 + jne .start_parsing + jmp .done_parsing + + .store_last_entry: + ; find index of the last incomplete entry + mov ecx, -1 + mov eax, [esp] + lea edi, [buf_buffer2+eax-2] + mov al, 0x0a + std + repne scasb + cld + + ; copy last (incomplete) entry of buf_buffer2 to remote_list_buf + lea esi, [edi+2] + mov edi, remote_list_buf + @@: + movsb + cmp byte[esi-1], 0 + jne @b + + .done_parsing: + call .draw ; to update tree list immediately in case of "auto_list" + pop eax + pop edx + jmp data_loop + + ; clear tree list and add ".." node before executing "LIST" + .clear_remote_tree: + stdcall dword[tl_info_clear], tree2 + mov dword[node_entry2+4], 0x2E2E + stdcall dword[tl_node_add], tree2, 0x10000, node_entry2 + ret + + +;;================================================================================================;; + .progress: ;//////////////////////////////////////////////////////////////////////////////////;; +;;------------------------------------------------------------------------------------------------;; +;? Update progress bar every time new data is received from data_loop block ;; +;;------------------------------------------------------------------------------------------------;; +;> edx = no. of bytes downloaded ;; +;;------------------------------------------------------------------------------------------------;; +;< none ;; +;;================================================================================================;; + + ; detect abort + mcall 17 + cmp ah, 10 + je cmd_abor + + push eax ebx ecx edx + mov ebx, [file_size] + mov ecx, 100 + mov eax, edx + mul ecx + div ebx + cmp eax, 100 + jle @f + mov eax, 100 + + @@: + mov dword[pb], eax + push pb + call [progressbar_draw] + pop edx ecx ebx eax + ret + + +remove_dir: + + stdcall dword[tl_node_get_data], tree2 + cmp word[eax], 'fo' + jne gui.still + lea esi, [eax+4] + lea edi, [buf_cmd+4] + @@: + movsb + cmp byte[esi], 0 + jne @b + mov word[edi], 0x000a + jmp cmd_rmd + + +delete_file: + + stdcall dword[tl_node_get_data], tree2 + cmp word[eax], 'fi' + jne gui.still + lea esi, [eax+4] + lea edi, [buf_cmd+5] + @@: + movsb + cmp byte[esi], 0 + jne @b + mov word[edi], 0x000a + jmp cmd_dele + + +create_remote_dir: + + lea edi, [buf_cmd+4] + mov esi, new_dir_buf + @@: + movsb + cmp byte[esi], 0 + jne @b + mov word[edi], 0x000a + jmp cmd_mkd + + +; Function to call when you press [Enter] +align 4 +fun_on_enter: + + stdcall dword[tl_node_get_data], tree1 + cmp word[eax], 'fi' + je @f + lea ecx, [eax+4] ; discard first 4 bytes + call populate_local_tree_list.read_new_dir + ;stdcall dword[tl_draw], tree1 + ret + + @@: + lea esi, [eax+4] + lea edi, [buf_cmd+5] + @@: + movsb + cmp byte[esi], 0 + jne @b + mov word[edi], 0x000a + jmp cmd_stor + + +; Function to call when you press [Enter] +; for treelist with remote directory listing +align 4 +fun_on_enter2: + + stdcall dword[tl_node_get_data], tree2 + lea esi, [eax+4] + cmp dword[esi], 0x2E2E + jne @f + mov [auto_list], 1 + jmp cmd_cdup + + @@: + cmp word[eax], 'fo' + je @f + lea edi, [buf_cmd+5] + jmp .copy + + @@: + lea edi, [buf_cmd+4] + + .copy: + movsb + cmp byte[esi], 0 + jne .copy + mov word[edi], 0x000a ; extra character before 0 to compensate for + ; newline in console code + cmp word[eax], 'fo' + je @f + jmp cmd_retr + + @@: + stdcall dword[tl_info_clear], tree2 + mov [auto_list], 1 + jmp cmd_cwd + + +;;================================================================================================;; +populate_local_tree_list: ;///////////////////////////////////////////////////////////////////////;; +;;------------------------------------------------------------------------------------------------;; +;? Update tree1 with file names from current working directory ;; +;;------------------------------------------------------------------------------------------------;; +;> none ;; +;;------------------------------------------------------------------------------------------------;; +;< none ;; +;;================================================================================================;; + + mov [filestruct.subfn], 1 + mov [filestruct.size], 32 + mov [filestruct.ptr], folder_data + mov ecx, root_dir + + .read_new_dir: ; ecx = pointer to folder name + ; parse ".." + cmp word[ecx], '..' + jne @f + cmp byte[ecx+2], 0 + jne @f + + ; removes last file name from filestruct.name + mcall 30, 2, filestruct.name,1024 ; get absolute path for cwd + lea edi, [filestruct.name+eax] ; edi = pointer to the tail of file name + mov al, '/' + mov ecx, -1 + std + repne scasb + cld + mov byte[edi+1], 0 + mov ecx, filestruct.name + + @@: + mcall 30, 1, ; set cwd + mcall 30, 2, filestruct.name, 1024 ; get absolute path for cwd + ; clear all nodes in tree list + stdcall dword[tl_info_clear], tree1 + mov [filestruct.offset], 0 + + ; read 32 blocks + .outer: + mcall 70, filestruct + ;int3 + test eax, eax + jz @f + cmp eax, 6 ; EOF + je @f + call error_fs + jmp .done + @@: + test ebx, ebx + je .done ; when no. of blocks is multiple of 32 + add [filestruct.offset], ebx + mov ecx, ebx + mov edx, folder_data+32+40 ; pointer to first file's name in BDFE + + .inner: ; ebx = total number of BDFEs + ; ecx = number of BDFEs remaining + ; edx = pointer to file's name in BDFE + ; ignore "." entry + cmp word[edx], 0x002E + je .added + ; copy file/folder name to node_entry + mov esi, edx + mov edi, node_entry+4 + @@: + movsb + cmp byte [esi-1], 0 + jne @b + ; check whether this is a file or a folder + mov al, byte[edx-40] + and al, 0x10 + jz @f + ; add a folder to tree + mov word[node_entry], 'fo' + stdcall dword[tl_node_add], tree1, 0x10000, node_entry + jmp .added + + @@: + ; add a file to tree + mov word[node_entry], 'fi' + stdcall dword[tl_node_add], tree1, 0, node_entry + + .added: + add edx, 304 ; 304 = length of BDFE. jump to next file's name + loop .inner + stdcall dword[tl_draw], tree1 + cmp ebx, 32 + je .outer ; more BDFEs to come + + .done: + ret + + +MIN_M_WND_H equ 500 ; +;input: +; edi = pointer to tedit struct +align 4 +EvSize: + pushad + mov ebx, ted_scr_h + mov esi, ted_scr_w + + m2m ted_wnd_w, [procinfo.client_box.width] + mov eax, ted_wnd_l + sub ted_wnd_w, eax + sub ted_wnd_w, 70 + movzx eax, word[esi+sb_offs_size_x] + sub ted_wnd_w, eax + + ;m2m ted_wnd_h,[procinfo.client_box.height] ; + ;cmp ted_wnd_h,MIN_M_WND_H + ;jg @f + mov ted_wnd_h, MIN_M_WND_H + ;@@: + + movzx eax, word[ebx+sb_offs_size_y] + sub ted_wnd_h, eax + mov eax, ted_wnd_t + sub ted_wnd_h, eax + + stdcall [ted_init_scroll_bars], tedit0,2 + + popad + ret + + +;;================================================================================================;; +filter_remote_list: ;/////////////////////////////////////////////////////////////////////////////;; +;;------------------------------------------------------------------------------------------------;; +;? Filter tree list according to pattern specified in 'filter' ;; +;;------------------------------------------------------------------------------------------------;; +;> none ;; +;;------------------------------------------------------------------------------------------------;; +;< none ;; +;;================================================================================================;; + stdcall dword[tl_cur_beg], tree2 + + .next_node: + stdcall dword[tl_node_get_data], tree2 + ; check whether any nodes left + test eax, eax + jnz @f + stdcall dword[tl_draw], tree2 + stdcall dword[edit_box_set_text], edit_search, str_null + je gui.still + + @@: + cmp byte[filter], 0 + je gui.still + + ; calculate size of node entry + lea esi, [eax+4] + mov edi, esi + mov ecx, -1 + @@: + lodsb + inc ecx + test al, al + jnz @b + + ; calculate size of pattern + mov esi, filter + mov edx, -1 + @@: + lodsb + inc edx + test al, al + jnz @b + + mov esi, filter + + call search + pop esi + test al, al + + jnz .get_next + stdcall dword[tl_node_delete], tree2 + jmp @f + + .get_next: + stdcall dword[tl_cur_next], tree2 + + @@: + jmp .next_node + + +;;================================================================================================;; +search: ;/////////////////////////////////////////////////////////////////////////////////////////;; +;;------------------------------------------------------------------------------------------------;; +;? Search for a substring within a string ;; +;;------------------------------------------------------------------------------------------------;; +;> edi = pointer to haystack ;; +;> ecx = size of haystack ;; +;> esi = pointer to needle ;; +;> edx = size of needle ;; +;;------------------------------------------------------------------------------------------------;; +;< al = 0 (not found) / 1 (found) ;; +;;================================================================================================;; + + push ebx ecx edx esi edi + ; if length of haystack < length of needle + cmp ecx, edx + jge @f + mov bh, 0 + jmp .done + @@: + mov bh, 1 ; flag (0 = not found, 1 = found) + sub ecx, edx + dec edi + + .outer: + cmp ecx, 0 + jl .done + dec ecx + inc edi + mov bh, 1 ; flag (0 = not found, 1 = found) + mov edx, [esp+8] + mov esi, [esp+4] + + .inner: + test edx, edx + jz .done + dec edx + + mov eax, esi + sub eax, [esp+4] + mov al, byte[edi+eax] + mov bl, byte[esi] + + inc esi + cmp al, bl + je .inner + mov bh, 0 + jmp .outer + + + .done: + mov al, bh + pop edi esi edx ecx ebx + ret + +;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + +hed db 'FTP Client - KolibriOS',0 +str_change db 'Change',0 +str_disconnect db 'Disconnect',0 +str_copy db 'Copy',0 +str_mkd db 'MKD',0 +str_dele db 'DELE',0 +str_rdir db 'RDIR',0 +str_rmd db 'RMD',0 +str_abort db 'Cancel',0 +str_search db 'Search',0 +str_list db 'LIST',0 +str_null db 0 + +;---------------------- +; tree list elements +;---------------------- +tree1 tree_list 64, 500, tl_list_box_mode, 16, 16, \ + 0xffffff, BT_COL, 0x000000, TLIST1_X, 105, TLIST_SZ-16, 185, 14, 4,\ + 0, el_focus, wScr, fun_on_enter + +tree2 tree_list 64, 500, tl_list_box_mode, 16, 16, \ + 0xffffff, BT_COL, 0x000000, TLIST2_X, 105, TLIST_SZ-16, 185, 14, 4, \ + 0, el_focus, wScr2, fun_on_enter2 + +; editbox for mkd +edit_mkd edit_box TLIST_SZ-45, TLIST2_X, 82, 0xffffff, 0x6a9480, 0, \ + 0xAABBCC, 0, 99, new_dir_buf, mouse_dd, 0 + +; editbox for default volume +edit_volume edit_box TLIST_SZ-60, TLIST1_X, 105-20, 0xffffff, 0x6a9480, 0, \ + 0xAABBCC, 0, 99, root_dir, mouse_dd, 0 + +; editbox for search +edit_search edit_box TLIST_SZ-60, TLIST2_X, 25, 0xffffff, 0x6a9480, 0, \ + 0xAABBCC, 0, 99, filter,mouse_dd, 0 + +; A subsidiary structure for scrolling +align 4 +wScr: + .x: + .size_x dw 16 ;+0 + .start_x dw 250+50-16 ;+2 + .y: + .size_y dw 185 ;+4 + .start_y dw 105 ;+6 + .btn_high dd 15 ;+8 + .type dd 1 ;+12 + .max_area dd 100 ;+16 + .cur_area dd 30 ;+20 + .position dd 0 ;+24 + .bckg_col dd 0xeeeeee ;+28 + .frnt_col dd 0xbbddff ;+32 + .line_col dd 0 ;+36 + .redraw dd 0 ;+40 + .delta dw 0 ;+44 + .delta2 dw 0 ;+46 + .run_x: + .r_size_x dw 0 ;+48 + .r_start_x dw 0 ;+50 + .run_y: + .r_size_y dw 0 ;+52 + .r_start_y dw 0 ;+54 + .m_pos dd 0 ;+56 + .m_pos_2 dd 0 ;+60 + .m_keys dd 0 ;+64 + .run_size dd 0 ;+68 + .position2 dd 0 ;+72 + .work_size dd 0 ;+76 + .all_redraw dd 0 ;+80 + .ar_offset dd 1 ;+84 + +align 4 +wScr2: + .x: + .size_x dw 16 ;+0 + .start_x dw 675+50-16 ;+2 + .y: + .size_y dw 185 ;+4 + .start_y dw 105 ;+6 + .btn_high dd 15 ;+8 + .type dd 1 ;+12 + .max_area dd 100 ;+16 + .cur_area dd 30 ;+20 + .position dd 0 ;+24 + .bckg_col dd 0xeeeeee ;+28 + .frnt_col dd 0xbbddff ;+32 + .line_col dd 0 ;+36 + .redraw dd 0 ;+40 + .delta dw 0 ;+44 + .delta2 dw 0 ;+46 + .run_x: + .r_size_x dw 0 ;+48 + .r_start_x dw 0 ;+50 + .run_y: + .r_size_y dw 0 ;+52 + .r_start_y dw 0 ;+54 + .m_pos dd 0 ;+56 + .m_pos_2 dd 0 ;+60 + .m_keys dd 0 ;+64 + .run_size dd 0 ;+68 + .position2 dd 0 ;+72 + .work_size dd 0 ;+76 + .all_redraw dd 0 ;+80 + .ar_offset dd 1 ;+84 +;---------------------- +; end tree list element +;---------------------- + +;---------------------- +; textedit elements +;---------------------- +align 4 +tedit0: + .wnd BOX 50,355,325,240 ;+ 0 195,5+40,325,240 + .rec BOX 30,13,7,10 ;+16 + .drag_m db 0 ;+32 + .drag_k db 0 ;+33 + .sel rb 16 ;+34 + .seln rb 16 ;+50 + .tex dd 0 ;+66 text memory pointer + .tex_1 dd 0 ;+70 text first symbol pointer + .tex_end dd 0 ;+74 text end memory pointer + .cur_x dd 0 ;+78 + .cur_y dd 0 ;+82 + .max_chars dd 4096 ;+86 + .count_colors_text dd 1 ;+90 + .count_key_words dd 0 ;+94 + .color_cursor dd SYS_COL ;+98 + .color_wnd_capt dd BT_COL ;+102 + .color_wnd_work dd 0xffffff ;+106 + .color_wnd_bord dd 0x737373 ;+110 + .color_select dd 0x0000ff ;+114 + .color_cur_text dd 0xffff00 ;+118 + .color_wnd_text dd 0x000000 ;+122 + .syntax_file dd 0 ;+126 + .syntax_file_size dd 500 ;+130 + .text_colors dd 0 ;+134 + .help_text_f1 dd 0 ;+138 + .help_id dd -1 ;+142 + .key_words_data dd 0 ;+146 + .tim_ch dd ? ;+150 + .tim_undo dd ? ;+154 + .tim_ls dd ? ;+158 + .tim_co dd ? ;+162 + .el_focus dd el_focus ;+166 + .err_save db 0 ;+170 + .panel_id db 0 ;+171 + .key_new db 0 ;+172 + .symbol_new_line db 20 ;+173 + .scr_w dd scrol_w1 ;+174 + .scr_h dd scrol_h1 ;+178 + .arr_key_pos dd 0 ;+182 + .buffer dd ed_buffer ;+186 + .buffer_find dd 0 ;+190 + .cur_ins db 1 ;+194 + .mode_color db 1 ;+195 + .mode_invis db 0 ;+196 + .gp_opt db 0 ;+197 + dd 0;.fun_on_key_ctrl_o dd but_ctrl_o ;+198 + .fun_on_key_ctrl_f dd 0 ;+202 ... Ctrl+F + dd 0;.fun_on_key_ctrl_n dd but_ctrl_n ;+206 ... Ctrl+N + .fun_on_key_ctrl_s dd 0 ;+210 ... Ctrl+S + .buffer_size dd 4096 ;+214 + .fun_find_err dd 0 ;+218 + .fun_init_synt_err dd 0 ;+222 + .fun_draw_panel_buttons dd 0 ;+226 + .fun_draw_panel_find dd 0 ;+230 + .fun_draw_panel_syntax dd 0 ;+234 + .fun_save_err dd 0 ;+238 + .increase_size dd 1000 ;+242 + .ptr_free_symb dd ? ;+246 + .font_size dd 16 shl 24 ; +250 + +align 4 +scrol_w1: + .x: + .size_x dw 16 ;+0 + .start_x dw 85 ;+2 + .y: + .size_y dw 100 ; +4 + .start_y dw 15 ; +6 + .btn_high dd 15 ; +8 + .type dd 1 ;+12 + .max_area dd 100 ;+16 + rb 4+4 + .bckg_col dd 0xeeeeee ;+28 + .frnt_col dd 0xbbddff ;+32 + .line_col dd 0x808080 ;+36 + .redraw dd 0 ;+40 + .delta dw 0 ;+44 + .delta2 dw 0 ;+46 + .run_x: + rb 2*4+4*6 + .all_redraw dd 0 ;+80 + .ar_offset dd 1 ;+84 +;--------------------------------------------------------------------- +align 4 +scrol_h1: + .x: + .size_x dw 85 ;+0 + .start_x dw 30 ;+2 + .y: + .size_y dw 16 ;+4 + .start_y dw 100 ;+6 + .btn_high dd 15 ;+8 + .type dd 1 ;+12 + .max_area dd 100 ;+16 + rb 4+4 + .bckg_col dd 0xeeeeee ;+28 + .frnt_col dd 0xbbddff ;+32 + .line_col dd 0x808080 ;+36 + .redraw dd 0 ;+40 + .delta dw 0 ;+44 + .delta2 dw 0 ;+46 + .run_x: + rb 2*4+4*6 + .all_redraw dd 0 ;+80 + .ar_offset dd 1 ;+84 + +;------------ +;Progress bar +;------------ +struc pb +{ + dd 0 ; PB_VALUE equ +0 + dd (TLIST2_X+TLIST1_X+TLIST_SZ)/2-150 ; PB_LEFT equ +4. 150 = PB_WIDTH/2 + dd 315; PB_TOP equ +8 + dd 300; PB_WIDTH equ +12 + dd 15 ; PB_HEIGHT equ +16 + dd ? ; PB_STYLE equ +20 + dd 0 ; PB_MIN equ +24 + dd 100; PB_MAX equ +28 + dd 0xffffff; PB_BACK_COLOR equ +32 + dd 0x00ff40; PB_PROGRESS_COLOR equ +36 + dd 0x808080; PB_FRAME_COLOR equ +40 +} +pb pb + + +align 4 +@IMPORT_BOXLIB: + +library box_lib, 'box_lib.obj' + +import box_lib, \ + edit_box_draw, 'edit_box', \ + edit_box_key, 'edit_box_key', \ + edit_box_mouse, 'edit_box_mouse', \ + edit_box_set_text, 'edit_box_set_text', \ + version_ed, 'version_ed', \ + scrollbar_ver_draw ,'scrollbar_v_draw', \ + scrollbar_ver_mouse,'scrollbar_v_mouse', \ + scrollbar_hor_draw, 'scrollbar_h_draw', \ + scrollbar_hor_mouse,'scrollbar_h_mouse', \ + version_scrollbar, 'version_scrollbar', \ + tl_data_init, 'tl_data_init', \ + tl_data_clear, 'tl_data_clear', \ + tl_info_clear, 'tl_info_clear', \ + tl_key, 'tl_key', \ + tl_mouse, 'tl_mouse', \ + tl_draw, 'tl_draw', \ + tl_node_add, 'tl_node_add', \ + tl_node_set_data, 'tl_node_set_data', \ + tl_node_get_data, 'tl_node_get_data', \ + tl_node_delete, 'tl_node_delete', \ + tl_cur_beg, 'tl_cur_beg', \ + tl_cur_next, 'tl_cur_next', \ + tl_cur_perv, 'tl_cur_perv', \ + tl_node_close_open, 'tl_node_close_open', \ + ted_but_sumb_upper, 'ted_but_sumb_upper', \ + ted_but_sumb_lover, 'ted_but_sumb_lover', \ + ted_can_save, 'ted_can_save', \ + ted_clear, 'ted_clear', \ + ted_delete, 'ted_delete', \ + ted_draw, 'ted_draw', \ + ted_init, 'ted_init', \ + ted_init_scroll_bars, 'ted_init_scroll_bars', \ + ted_init_syntax_file, 'ted_init_syntax_file', \ + ted_is_select, 'ted_is_select', \ + ted_key, 'ted_key', \ + ted_mouse, 'ted_mouse', \ + ted_open_file, 'ted_open_file', \ + ted_save_file, 'ted_save_file', \ + ted_text_add, 'ted_text_add', \ + ted_but_select_word,'ted_but_select_word', \ + ted_but_cut, 'ted_but_cut', \ + ted_but_copy, 'ted_but_copy', \ + ted_but_paste, 'ted_but_paste', \ + ted_but_undo, 'ted_but_undo', \ + ted_but_redo, 'ted_but_redo', \ + ted_but_reverse, 'ted_but_reverse', \ + ted_but_find_next, 'ted_but_find_next', \ + ted_text_colored, 'ted_text_colored', \ + progressbar_draw, 'progressbar_draw' + + +auto_list db 1 ; to run LIST immediately after CWD +filter rb 512 +root_dir db '/rd/1' + rb 507 +new_dir_buf rb 512 +folder_data rb 32+32*304 +node_entry db '1111' + rb 512 +node_entry2 db '1111' + rb 512 +remote_list_buf rb 1024 +conv_tabl rb 128 +ed_buffer rb 100 +tedit_buffer rb 1024 +el_focus dd 0 +;----------------------- + +procinfo process_information \ No newline at end of file diff --git a/programs/network/ftpc/login_gui.inc b/programs/network/ftpc/login_gui.inc new file mode 100755 index 0000000000..fd644e9d98 --- /dev/null +++ b/programs/network/ftpc/login_gui.inc @@ -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 \ No newline at end of file diff --git a/programs/network/ftpc/parser.inc b/programs/network/ftpc/parser.inc index 6c8a1a60a8..1c3fac56c9 100644 --- a/programs/network/ftpc/parser.inc +++ b/programs/network/ftpc/parser.inc @@ -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 diff --git a/programs/network/ftpc/servercommands.inc b/programs/network/ftpc/servercommands.inc index 45e6d8a98c..17f8486e15 100644 --- a/programs/network/ftpc/servercommands.inc +++ b/programs/network/ftpc/servercommands.inc @@ -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 @@ -135,19 +172,34 @@ 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 diff --git a/programs/network/ftpc/usercommands.inc b/programs/network/ftpc/usercommands.inc index c5b77722a4..2cba28ddc3 100644 --- a/programs/network/ftpc/usercommands.inc +++ b/programs/network/ftpc/usercommands.inc @@ -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: