diff --git a/programs/network/ftpc/ftpc.asm b/programs/network/ftpc/ftpc.asm index 01cdcc543c..55d017f847 100644 --- a/programs/network/ftpc/ftpc.asm +++ b/programs/network/ftpc/ftpc.asm @@ -27,7 +27,8 @@ OPERATION_NONE = 0 OPERATION_LIST = 1 OPERATION_RETR = 2 OPERATION_STOR = 3 - +OPERATION_RDIR = 4 + use32 ; standard header db 'MENUET01' ; signature @@ -36,7 +37,7 @@ use32 dd i_end ; initialized size dd mem+0x1000 ; required memory dd mem+0x1000 ; stack pointer - dd s ; parameters + dd buf_cmd ; parameters dd 0 ; path include '../../macros.inc' @@ -49,6 +50,11 @@ include 'usercommands.inc' include 'servercommands.inc' start: +; initialize heap for using dynamic blocks + mcall 68,11 + test eax,eax + je exit2 + ; disable all events except network event mcall 40, EV_STACK ; load libraries @@ -59,7 +65,7 @@ start: invoke con_start, 1 invoke con_init, 80, 25, 80, 250, str_title ; Check for parameters, if there are some, resolve the address right away - cmp byte [s], 0 + cmp byte [buf_cmd], 0 jne resolve main: @@ -71,11 +77,11 @@ main: invoke con_set_flags, 0x0a invoke con_write_asciiz, str_prompt ; read string - invoke con_gets, s, 256 + invoke con_gets, buf_cmd, 256 ; check for exit test eax, eax jz done - cmp byte [s], 10 + cmp byte [buf_cmd], 10 jz done ; reset color back to grey and print newline invoke con_set_flags, 0x07 @@ -83,7 +89,7 @@ main: resolve: ; delete terminating '\n' - mov esi, s + mov esi, buf_cmd @@: lodsb cmp al, 0x20 @@ -91,10 +97,10 @@ resolve: mov byte [esi-1], 0 ; Say to the user that we're resolving invoke con_write_asciiz, str_resolve - invoke con_write_asciiz, s + invoke con_write_asciiz, buf_cmd ; resolve name push esp ; reserve stack place - invoke getaddrinfo, s, 0, 0, esp + invoke getaddrinfo, buf_cmd, 0, 0, esp pop esi ; test for error test eax, eax @@ -130,7 +136,7 @@ wait_for_servercommand: cmp [offset], 0 je .receive ; nope, receive some more mov esi, [offset] - mov edi, s + mov edi, buf_cmd mov ecx, [size] add ecx, esi jmp .byteloop @@ -145,7 +151,7 @@ wait_for_servercommand: mcall 26, 9 cmp eax, [timeout] jge error_timeout - mcall recv, [socketnum], buffer_ptr, BUFFERSIZE, MSG_DONTWAIT + mcall recv, [socketnum], buf_buffer1, BUFFERSIZE, MSG_DONTWAIT test eax, eax jnz .got_data cmp ebx, EWOULDBLOCK @@ -155,10 +161,10 @@ wait_for_servercommand: .got_data: mov [offset], 0 -; extract commands, copy them to "s" buffer - lea ecx, [eax + buffer_ptr] ; ecx = end pointer - mov esi, buffer_ptr ; esi = current pointer - mov edi, s +; extract commands, copy them to "buf_cmd" buffer + lea ecx, [eax + buf_buffer1] ; ecx = end pointer + mov esi, buf_buffer1 ; esi = current pointer + mov edi, buf_cmd .byteloop: cmp esi, ecx jae wait_for_servercommand @@ -179,12 +185,12 @@ wait_for_servercommand: .no_more_data: mov [offset], 0 .go_cmd: - lea ecx, [edi - s] ; length of command + lea ecx, [edi - buf_cmd] ; length of command xor al, al stosb invoke con_set_flags, 0x03 ; change color - invoke con_write_asciiz, s ; print servercommand + invoke con_write_asciiz, buf_cmd ; print servercommand invoke con_write_asciiz, str_newline invoke con_set_flags, 0x07 ; reset color @@ -194,6 +200,11 @@ wait_for_servercommand: wait_for_usercommand: +; 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 @@ -207,53 +218,56 @@ wait_for_usercommand: ; write prompt invoke con_write_asciiz, str_prompt ; read string - invoke con_gets, s, 256 + 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 - cmp dword[s], "cwd " + cmp dword[buf_cmd], "cwd " je cmd_cwd - cmp dword[s], "mkd " + cmp dword[buf_cmd], "mkd " je cmd_mkd - cmp dword[s], "rmd " + cmp dword[buf_cmd], "rmd " je cmd_rmd - cmp dword[s], "pwd" + 10 shl 24 + cmp dword[buf_cmd], "pwd" + 10 shl 24 je cmd_pwd - cmp dword[s], "bye" + 10 shl 24 + cmp dword[buf_cmd], "bye" + 10 shl 24 je cmd_bye - cmp byte[s+4], " " + cmp dword[buf_cmd], "rdir" + je cmd_rdir + + cmp byte[buf_cmd+4], " " jne @f - cmp dword[s], "lcwd" + cmp dword[buf_cmd], "lcwd" je cmd_lcwd - cmp dword[s], "retr" + cmp dword[buf_cmd], "retr" je cmd_retr - cmp dword[s], "stor" + cmp dword[buf_cmd], "stor" je cmd_stor - cmp dword[s], "dele" + cmp dword[buf_cmd], "dele" je cmd_dele @@: - cmp byte[s+4], 10 + cmp byte[buf_cmd+4], 10 jne @f - cmp dword[s], "list" + cmp dword[buf_cmd], "list" je cmd_list - cmp dword[s], "help" + cmp dword[buf_cmd], "help" je cmd_help - cmp dword[s], "cdup" + cmp dword[buf_cmd], "cdup" je cmd_cdup @@: @@ -265,32 +279,32 @@ wait_for_usercommand: .connected: ; request username invoke con_write_asciiz, str_user - mov dword[s], "USER" - mov byte[s+4], " " + mov dword[buf_cmd], "USER" + mov byte[buf_cmd+4], " " jmp .send .needpass: ; request password invoke con_write_asciiz, str_pass - mov dword[s], "PASS" - mov byte[s+4], " " + mov dword[buf_cmd], "PASS" + mov byte[buf_cmd+4], " " invoke con_set_flags, 0x00 ; black text on black background for password .send: ; read string - mov esi, s+5 + mov esi, buf_cmd+5 invoke con_gets, esi, 256 ; find end of string - mov edi, s+5 + mov edi, buf_cmd+5 mov ecx, 256 xor al, al repne scasb - lea esi, [edi-s] + lea esi, [edi-buf_cmd] mov word[edi-2], 0x0a0d ; and send it to the server - mcall send, [socketnum], s, , 0 + mcall send, [socketnum], buf_cmd, , 0 invoke con_write_asciiz, str_newline invoke con_set_flags, 0x07 ; reset color @@ -332,6 +346,10 @@ error_resolve: invoke con_set_flags, 0x0c ; print errors in red invoke con_write_asciiz, str_err_resolve +error_heap: + invoke con_set_flags, 0x0c ; print errors in red + invoke con_write_asciiz, str_err_heap + wait_for_keypress: invoke con_set_flags, 0x07 ; reset color to grey invoke con_write_asciiz, str_push @@ -344,6 +362,7 @@ done: exit: mcall close, [socketnum] +exit2: mcall -1 @@ -359,6 +378,7 @@ str_resolve db 'Resolving ',0 str_newline db 10,0 str_err_resolve db 10,'Name resolution failed.',10,0 str_err_socket db 10,'Socket error.',10,0 +str_err_heap db 10,'Cannot allocate memory from heap.',10,0 str_err_timeout db 10,'Timeout - no response from server.',10,0 str_err_connect db 10,'Cannot connect to the server.',10,0 str8 db ' (',0 @@ -372,8 +392,8 @@ str_unknown db "Unknown command or insufficient parameters - type help for m str_lcwd db "Local working directory is now: ",0 str_open db "opening data socket",10,0 -str_close db "closing data socket",10,0 -str2b db '.',0 +str_close db 10,"closing data socket",10,0 +str_dot db '.',0 str_help db "available commands:",10 db 10 @@ -388,8 +408,10 @@ 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 10,0 +queued dd 0 ; FTP strings @@ -446,7 +468,10 @@ offset dd ? size dd ? operation dd ? +size_fname dd ? +ptr_queue dd ? timeout dd ? +ptr_fname_start dd ? filestruct: .subfn dd ? @@ -456,9 +481,8 @@ filestruct: .ptr dd ? .name rb 1024 -buffer_ptr rb BUFFERSIZE+1 -buffer_ptr2 rb BUFFERSIZE+1 - -s rb 1024 +buf_buffer1 rb BUFFERSIZE+1 +buf_buffer2 rb BUFFERSIZE+1 +buf_cmd rb 1024 ; buffer for holding command string mem: diff --git a/programs/network/ftpc/servercommands.inc b/programs/network/ftpc/servercommands.inc index c4c0991053..3fd4afa8ec 100644 --- a/programs/network/ftpc/servercommands.inc +++ b/programs/network/ftpc/servercommands.inc @@ -5,40 +5,40 @@ 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[s], "150 " + cmp dword[buf_cmd], "150 " je data_loop - cmp dword[s], "220 " + cmp dword[buf_cmd], "220 " je welcome -; cmp dword[s], "226 " +; cmp dword[buf_cmd], "226 " ; je transfer_ok - cmp dword[s], "227 " + cmp dword[buf_cmd], "227 " je pasv_ok - cmp dword[s], "230 " + cmp dword[buf_cmd], "230 " je login_ok -; cmp dword[s], "250" +; cmp dword[buf_cmd], "250" ; je op_ok - cmp dword[s], "331 " + cmp dword[buf_cmd], "331 " je pass -; cmp dword[s], "421 " +; cmp dword[buf_cmd], "421 " ; je timeout - cmp dword[s], "503 " ; login first + cmp dword[buf_cmd], "503 " ; login first je welcome - cmp dword[s], "530 " ; password incorrect + cmp dword[buf_cmd], "530 " ; password incorrect je welcome - cmp dword[s], "550 " + cmp dword[buf_cmd], "550 " je close_datacon - cmp byte[s+3], "-" + cmp byte[buf_cmd+3], "-" je wait_for_servercommand jmp wait_for_usercommand @@ -66,7 +66,7 @@ pasv_ok: sub ecx, 4 jb .fail mov al, "(" - mov edi, s + 4 + mov edi, buf_cmd + 4 repne scasb mcall socket, AF_INET4, SOCK_STREAM, 0 @@ -102,27 +102,30 @@ pasv_ok: data_loop: - invoke con_write_asciiz, str2b + invoke con_write_asciiz, str_dot cmp [operation], OPERATION_STOR je .stor ; we are receiving data - mcall recv, [datasocket], buffer_ptr2, BUFFERSIZE, 0 + mcall recv, [datasocket], buf_buffer2, BUFFERSIZE, 0 test ebx, ebx jnz .done - mov byte[buffer_ptr2 + eax], 0 + mov byte[buf_buffer2 + eax], 0 cmp [operation], OPERATION_RETR je .retr + cmp [operation], OPERATION_RDIR + je .rdir + ; not retreiving, just print to console - invoke con_write_asciiz, buffer_ptr2 + invoke con_write_asciiz, buf_buffer2 jmp data_loop ; retreiving, save to file .retr: - mov [filestruct.ptr], buffer_ptr2 + mov [filestruct.ptr], buf_buffer2 mov [filestruct.size], eax push eax mcall 70, filestruct @@ -139,12 +142,12 @@ data_loop: ; jne .fileerror add [filestruct.offset], ebx mov esi, ebx - mcall send, [datasocket], buffer_ptr2, , 0 + mcall send, [datasocket], buf_buffer2, , 0 jmp .stor .last_call: mov esi, ebx - mcall send, [datasocket], buffer_ptr2, , 0 + mcall send, [datasocket], buf_buffer2, , 0 .done: invoke con_write_asciiz, str_close @@ -153,6 +156,108 @@ data_loop: jmp wait_for_servercommand + .rdir: + cmp [size_fname], 0 + jne .realloc + + .malloc: ; create a new dynamic block + mov ecx, eax + inc ecx + + mcall 68,12 ; eax now points to new buffer + + test eax,eax + je error_heap + + mov [ptr_fname_start], eax + + jmp .rdir_init + + .realloc: ; expand block created with .malloc + + mov ecx, eax ; eax is size of buffer received + inc ecx + + add ecx, [size_fname] ; added old size to form new required size + + mcall 68,20,,[ptr_fname_start] + + test eax, eax + je error_heap + + mov [ptr_fname_start], eax ; eax contains the new block now + add eax, [size_fname] + + .rdir_init: ; copies filenames into our buffer + + mov esi, buf_buffer2 + mov edi, eax + + .copy_buf: + lodsb + cmp al,13 ; ignore any \r character + je .copy_buf + stosb + + cmp al, 10 + jne .not_end + inc [queued] + + .not_end: + test al,al + jne .copy_buf + + dec edi + dec edi + + mov eax, [ptr_fname_start] + mov [ptr_queue], eax + + sub edi, eax ; edi contains the current size now + mov [size_fname], edi + + jmp data_loop + + +; files for rdir operation are queued +transfer_queued: + + mov esi, [ptr_queue] ; always pointing to current part of ptr_fname_start + mov edi, buf_cmd+5 ; always point to filename for retr command + + .build_filename: + lodsb + stosb + + cmp al,10 + je .get_file ; filename ends with character 10 + test al,al + jz .null_found ; this should be end of buffer + jmp .build_filename + + .null_found: + + mov [queued],0 + jmp .free + + .get_file: + dec [queued] + jnz .after_free + + .free: + mcall 68,13,[ptr_fname_start] ; freeing the buffer + test eax,eax + jz error_heap + jmp wait_for_usercommand + + .after_free: + xor al,al ; appending 0 after retr command + stosb + mov eax, esi + mov [ptr_queue], eax + + jmp cmd_retr + close_datacon: cmp [operation], OPERATION_NONE je wait_for_usercommand diff --git a/programs/network/ftpc/usercommands.inc b/programs/network/ftpc/usercommands.inc index d180b12eb2..55b250c195 100644 --- a/programs/network/ftpc/usercommands.inc +++ b/programs/network/ftpc/usercommands.inc @@ -9,9 +9,9 @@ cmd_help: cmd_bye: ; Send BYE message to the server - mov dword[s], "BYE" + 13 shl 24 - mov byte[s+4], 10 - mcall send, [socketnum], s, 5, 0 + mov dword[buf_cmd], "BYE" + 13 shl 24 + mov byte[buf_cmd+4], 10 + mcall send, [socketnum], buf_cmd, 5, 0 ; Close the control connection mcall close, [socketnum] @@ -20,42 +20,42 @@ cmd_bye: cmd_pwd: - mov dword[s], "PWD" + 13 shl 24 - mov byte[s+4], 10 - mcall send, [socketnum], s, 5, 0 + mov dword[buf_cmd], "PWD" + 13 shl 24 + mov byte[buf_cmd+4], 10 + mcall send, [socketnum], buf_cmd, 5, 0 jmp wait_for_servercommand cmd_cwd: - mov dword[s], "CWD " + mov dword[buf_cmd], "CWD " mov ecx, 256 xor al, al - mov edi, s + mov edi, buf_cmd repne scasb - lea esi, [edi - s] + lea esi, [edi - buf_cmd] mov word [edi - 2], 0x0a0d - mcall send, [socketnum], s, , 0 + mcall send, [socketnum], buf_cmd, , 0 jmp wait_for_servercommand cmd_dele: - mov dword[s], "DELE" - mov byte[s], " " + mov dword[buf_cmd], "DELE" + mov byte[buf_cmd], " " mov ecx, 256 xor al, al - mov edi, s + mov edi, buf_cmd repne scasb - lea esi, [edi - s] + lea esi, [edi - buf_cmd] mov word [edi - 2], 0x0a0d - mcall send, [socketnum], s, , 0 + mcall send, [socketnum], buf_cmd, , 0 jmp wait_for_servercommand @@ -65,9 +65,9 @@ cmd_list: mov [operation], OPERATION_LIST - mov dword[s], "LIST" - mov word[s+4], 0x0a0d - mcall send, [socketnum], s, 6, 0 + mov dword[buf_cmd], "LIST" + mov word[buf_cmd+4], 0x0a0d + mcall send, [socketnum], buf_cmd, 6, 0 jmp wait_for_servercommand @@ -77,7 +77,9 @@ cmd_retr: ; Create/open the file - mov esi, s+5 +; Create/open the file + + mov esi, buf_cmd+5 mov ecx, 256-5 call set_filename @@ -97,22 +99,36 @@ cmd_retr: mov [operation], OPERATION_RETR ; Request the file from server - - mov dword[s], "RETR" - mov byte[s+4], " " + + mov dword[buf_cmd], "RETR" + mov byte[buf_cmd+4], " " mov ecx, 256 xor al, al - mov edi, s + mov edi, buf_cmd repne scasb - lea esi, [edi - s] + lea esi, [edi - buf_cmd] mov dword[edi - 2], 0x0a0d - mcall send, [socketnum], s, , 0 + mcall send, [socketnum], buf_cmd, , 0 - invoke con_write_asciiz, s ; print command + invoke con_write_asciiz, buf_cmd ; print command jmp wait_for_servercommand +cmd_rdir: + mov [operation], OPERATION_RDIR + +; Request filename list from the server + + call open_dataconnection + + mov [size_fname], 0 + mov dword[buf_cmd], "NLST" + mov word[buf_cmd+4], 0x0a0d + mcall send, [socketnum], buf_cmd, 6, 0 + + jmp wait_for_servercommand + cmd_stor: call open_dataconnection @@ -123,29 +139,29 @@ cmd_stor: mov [filestruct.offset], 0 mov [filestruct.offset+4], 0 mov [filestruct.size], BUFFERSIZE - mov [filestruct.ptr], buffer_ptr2 + mov [filestruct.ptr], buf_buffer2 - mov esi, s+5 + mov esi, buf_cmd+5 mov ecx, 256-5 call set_filename - mov dword[s], "STOR" - mov byte[s+4], " " + mov dword[buf_cmd], "STOR" + mov byte[buf_cmd+4], " " mov ecx, 256 xor al, al - mov edi, s + mov edi, buf_cmd repne scasb - lea esi, [edi - s] + lea esi, [edi - buf_cmd] mov word [edi - 2], 0x0a0d - mcall send, [socketnum], s, , 0 + mcall send, [socketnum], buf_cmd, , 0 jmp wait_for_servercommand cmd_lcwd: - mov esi, s+5 + mov esi, buf_cmd+5 mov ecx, 256-5 .loop: lodsb @@ -156,11 +172,11 @@ cmd_lcwd: loop .loop .done: mov byte[esi-1], 0 - mcall 30, 1, s+5 ; set working directory - mcall 30, 2, s, 256 ; and read it again + mcall 30, 1, buf_cmd+5 ; set working directory + mcall 30, 2, buf_cmd, 256 ; and read it again invoke con_write_asciiz, str_lcwd - invoke con_write_asciiz, s + invoke con_write_asciiz, buf_cmd invoke con_write_asciiz, str_newline jmp wait_for_usercommand @@ -168,41 +184,41 @@ cmd_lcwd: cmd_cdup: - mov dword[s], "CDUP" - mov word[s+4], 0x0d0a - mcall send, [socketnum], s, 6, 0 + mov dword[buf_cmd], "CDUP" + mov word[buf_cmd+4], 0x0d0a + mcall send, [socketnum], buf_cmd, 6, 0 jmp wait_for_servercommand cmd_rmd: - mov dword[s], "RMD " + mov dword[buf_cmd], "RMD " mov ecx, 256 xor al, al - mov edi, s + mov edi, buf_cmd repne scasb - lea esi, [edi - s] + lea esi, [edi - buf_cmd] mov word [edi - 2], 0x0a0d - mcall send, [socketnum], s, , 0 + mcall send, [socketnum], buf_cmd, , 0 jmp wait_for_servercommand cmd_mkd: - mov dword[s], "MKD " + mov dword[buf_cmd], "MKD " mov ecx, 256 xor al, al - mov edi, s + mov edi, buf_cmd repne scasb - lea esi, [edi - s] + lea esi, [edi - buf_cmd] mov word [edi - 2], 0x0a0d - mcall send, [socketnum], s, , 0 + mcall send, [socketnum], buf_cmd, , 0 jmp wait_for_servercommand