/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 |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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' |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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 |
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 |
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 |
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. |
; 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 |
; Usage: ftpc [-cli] [ftp://username:password@server:port/path] |
; mov dword[buf_cmd], '-cli' ;;;; to test CLI ;;;;; |
cmp byte [buf_cmd], 0 |
jne resolve |
jne @f |
mov [interface_addr], gui |
jmp .args_ok |
@@: cmp dword[buf_cmd], '-cli' |
jne .error |
mov [interface_addr], console |
jmp .args_ok |
main: |
; 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 |
.args_ok: |
no_resolve: |
mov [sockaddr1.port], 21 shl 8 |
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 |
; delete terminating '\n' |
mov esi, buf_cmd |
.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 |
.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 |
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 |
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 |
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 |
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 |
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 |
ijmp eax, interface_addr, interface.get_cmd |
; print a newline and reset the color back to grey |
invoke con_write_asciiz, str_newline |
invoke con_set_flags, 0x07 |
.parse_cmd: |
cmp dword[buf_cmd], "cwd " |
je cmd_cwd |
349,78 → 493,15 |
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,27 → 632,113 |
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 |
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 |
done: |
invoke con_exit, 1 |
exit: |
mcall close, [controlsocket] |
exit2: |
582,11 → 749,9 |
; 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 |
db 10,0 |
str_srv_addr db 'Please enter ftp server address.',10,0 |
str_ftp db 'ftp://',0 |
str_prompt db '> ',0 |
str_resolve db 'Resolving ',0 |
str_newline db 10,0 |
601,6 → 766,18 |
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_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_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,11 → 845,25 |
.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', \ |
670,19 → 870,6 |
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_int, 'ini_get_int' |
692,8 → 879,12 |
; uninitialised data |
interface_addr rd 1 |
status db ? |
file_size dd ? |
controlsocket dd ? |
datasocket dd ? |
offset dd ? |
719,16 → 910,34 |
.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: |
/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 |
/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, <TLIST2_X+TLIST_SZ-55,55>, <20,25>, 5, BT_COL |
; string "Search" |
mcall 4, <TLIST2_X+TLIST_SZ-55+5,20+5>, 0xb0000000+STR_COL, str_search |
; draw "LIST" button |
mcall 8, <TLIST2_X+TLIST_SZ-4*BT_SZ_X-15,BT_SZ_X>, <50,25>, 12, BT_COL |
; string "LIST" |
mcall 4, <TLIST2_X+TLIST_SZ-4*BT_SZ_X-15+5,50+5>, 0xb0000000+STR_COL, str_list |
; draw "DELE" button |
mcall 8, <TLIST2_X+TLIST_SZ-3*BT_SZ_X-10,BT_SZ_X>, <50,25>, 7, BT_COL |
; string "DELE" |
mcall 4, <TLIST2_X+TLIST_SZ-3*BT_SZ_X-10+5,50+5>, 0xb0000000+STR_COL, str_dele |
; draw "RDIR" button |
mcall 8, <TLIST2_X+TLIST_SZ-2*BT_SZ_X-5,BT_SZ_X>, <50,25>, 8, BT_COL |
; string "RDIR" |
mcall 4, <TLIST2_X+TLIST_SZ-2*BT_SZ_X-5+5,50+5>, 0xb0000000+STR_COL, str_rdir |
; draw "RMD" button |
mcall 8, <TLIST2_X+TLIST_SZ-BT_SZ_X,BT_SZ_X>, <50,25>, 9, BT_COL |
; string "RMD" |
mcall 4, <TLIST2_X+TLIST_SZ-BT_SZ_X+5,50+5>, 0xb0000000+STR_COL, str_rmd |
; draw "mkd" button |
mcall 8, <TLIST2_X+TLIST_SZ-BT_SZ_X,BT_SZ_X>, <80,20>, 6, BT_COL |
; string "mkd" |
mcall 4, <TLIST2_X+TLIST_SZ-BT_SZ_X+5,80+5>, 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, <TLIST1_X+TLIST_SZ-55,55>, <100-20,22>, 11, BT_COL |
; string "Change" |
mcall 4, <TLIST1_X+TLIST_SZ-55+5,100-20+5>, 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 |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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 |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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 |
; parameters parsed successfully |
jmp arg_handler.connect |
; copy server address to buf_cmd |
mov esi, param_server_addr |
mov edi, buf_cmd |
.copy: |
lodsb |
stosb |
cmp byte [edi], 0 |
jne .copy |
mov byte [esi], 0 |
jmp no_resolve.done |
.error: |
mov eax, str_err_params |
jmp error |
/programs/network/ftpc/servercommands.inc |
---|
5,11 → 5,14 |
; 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 |
je welcome |
cmp dword[buf_cmd], "530 " ; password incorrect |
mov [use_params], 0 |
je welcome |
cmp dword[buf_cmd], "550 " |
50,6 → 52,11 |
jmp wait_for_usercommand |
connect_ok: |
mov [status], STATUS_CONNECTED |
jmp arg_handler.copy_user |
pass: |
mov [status], STATUS_NEEDPASSWORD |
59,21 → 66,14 |
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: |
sub ecx, 4 |
104,7 → 104,7 |
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 |
@@: jmp wait_for_servercommand |
.fail: |
invoke con_write_asciiz, str_unknown |
icall eax, interface_addr, interface.print, str_unknown |
jmp wait_for_servercommand |
; get file size, initialize count for number of bytes downloaded |
init_download_count: |
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: |
invoke con_write_asciiz, str_dot |
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,10 → 173,18 |
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 |
146,8 → 191,15 |
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 |
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 |
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 |
/programs/network/ftpc/usercommands.inc |
---|
15,7 → 15,7 |
; Close the control connection |
mcall close, [controlsocket] |
jmp main |
ijmp eax, interface_addr, interface.server_addr |
cmd_pwd: |
46,7 → 46,7 |
cmd_dele: |
mov dword[buf_cmd], "DELE" |
mov byte[buf_cmd], " " |
mov byte[buf_cmd+4], " " |
mov ecx, 256 |
xor al, al |
76,9 → 76,8 |
call open_dataconnection |
; Create/open the file |
; TODO: check beforehand if the disk has enough free space available to store the file |
; Create/open the file |
mov esi, buf_cmd+5 |
mov ecx, 256-5 |
call set_filename |
90,9 → 89,11 |
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 |
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 |
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,20 → 182,35 |
.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 |
icall eax, interface_addr, interface.print, str_lcwd, buf_cmd, str_newline |
invoke con_write_asciiz, str_lcwd |
invoke con_write_asciiz, buf_cmd |
invoke con_write_asciiz, str_newline |
jmp wait_for_usercommand |
189,7 → 217,7 |
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 |
jmp wait_for_servercommand |
cmd_abor: |
mcall close, [datasocket] |
jmp wait_for_servercommand |
; esi = source ptr |
; ecx = max length of source buffer |
set_filename: |