0,0 → 1,403 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; ftpc.asm - FTP client for KolibriOS ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
format binary as "" |
|
__DEBUG__ = 0 |
__DEBUG_LEVEL__ = 1 |
BUFFERSIZE = 1024 |
|
STATUS_CONNECTING = 0 |
STATUS_CONNECTED = 1 |
STATUS_NEEDPASSWORD = 2 |
STATUS_LOGGED_IN = 3 |
|
use32 |
; standard header |
db 'MENUET01' ; signature |
dd 1 ; header version |
dd start ; entry point |
dd i_end ; initialized size |
dd mem+0x1000 ; required memory |
dd mem+0x1000 ; stack pointer |
dd s ; parameters |
dd 0 ; path |
|
include '../../macros.inc' |
purge mov,add,sub |
include '../../proc32.inc' |
include '../../dll.inc' |
include '../../debug-fdo.inc' |
include '../../network.inc' |
|
include 'usercommands.inc' |
include 'servercommands.inc' |
|
; entry point |
start: |
|
DEBUGF 1, "hello" |
; load libraries |
stdcall dll.Load, @IMPORT |
test eax, eax |
jnz exit |
; initialize console |
push 1 |
call [con_start] |
push title |
push 25 |
push 80 |
push 25 |
push 80 |
call [con_init] |
|
; Check for parameters |
cmp byte [s], 0 |
jne resolve |
|
main: |
call [con_cls] |
; Welcome user |
push str1 |
call [con_write_asciiz] |
|
; write prompt |
push str2 |
call [con_write_asciiz] |
; read string |
mov esi, s |
push 256 |
push esi |
call [con_gets] |
; check for exit |
test eax, eax |
jz done |
cmp byte [esi], 10 |
jz done |
|
resolve: |
|
; delete terminating '\n' |
mov esi, s |
@@: |
lodsb |
cmp al, 0x20 |
ja @r |
mov byte [esi-1], 0 |
|
; call [con_cls] |
push str3 |
call [con_write_asciiz] |
push s |
call [con_write_asciiz] |
|
; resolve name |
push esp ; reserve stack place |
push esp ; fourth parameter |
push 0 ; third parameter |
push 0 ; second parameter |
push s ; first parameter |
call [getaddrinfo] |
pop esi |
; test for error |
test eax, eax |
jnz fail |
|
; write results |
push str8 |
call [con_write_asciiz] |
; mov edi, esi |
|
; convert IP address to decimal notation |
mov eax, [esi+addrinfo.ai_addr] |
mov eax, [eax+sockaddr_in.sin_addr] |
mov [sockaddr1.ip], eax |
push eax |
call [inet_ntoa] |
; write result |
push eax |
call [con_write_asciiz] |
; free allocated memory |
push esi |
call [freeaddrinfo] |
|
push str9 |
call [con_write_asciiz] |
|
mcall socket, AF_INET4, SOCK_STREAM, 0 |
cmp eax, -1 |
je fail2 |
mov [socketnum], eax |
|
push str11 |
call [con_write_asciiz] |
|
mcall connect, [socketnum], sockaddr1, 18 |
|
mcall 40, EVM_STACK |
|
mov [status], STATUS_CONNECTING |
mov [offset], buffer_ptr |
|
push str12 |
call [con_write_asciiz] |
|
wait_for_serverdata: |
mcall 10 |
|
call [con_get_flags] |
test eax, 0x200 ; con window closed? |
jnz exit |
|
; receive socket data |
mcall recv, [socketnum], [offset], BUFFERSIZE, 0 |
inc eax |
jz wait_for_serverdata |
dec eax |
jz wait_for_serverdata |
|
; extract commands, copy them to "s" buffer |
add eax, buffer_ptr ; eax = end pointer |
mov esi, buffer_ptr ; esi = current pointer |
.nextcommand: |
mov edi, s |
.byteloop: |
cmp esi, eax |
jae wait_for_serverdata |
lodsb |
cmp al, 10 ; excellent, we might have a command |
je .got_command |
cmp al, 13 ; just ignore this crap |
je .byteloop |
stosb |
jmp .byteloop |
|
; we have a newline check if its a command |
.got_command: |
xor al, al |
stosb |
; push esi eax |
|
; print it to the screen |
pushd s |
call [con_write_asciiz] |
pushd str4 ; newline |
call [con_write_asciiz] |
|
; cmp byte[s+2], " " |
; jne .not_command |
|
lea ecx, [edi - s] |
call server_parser |
|
; .not_command: |
; pop eax esi |
; jmp .nextcommand |
|
|
|
|
wait_for_usercommand: |
|
cmp [status], STATUS_CONNECTED |
je .connected |
|
cmp [status], STATUS_NEEDPASSWORD |
je .needpass |
|
; write prompt |
push str2 |
call [con_write_asciiz] |
; read string |
mov esi, s |
push 256 |
push esi |
call [con_gets] |
|
call [con_get_flags] |
test eax, 0x200 ; con window closed? |
jnz exit |
|
cmp dword[s], "list" |
je cmd_list |
|
cmp dword[s], "help" |
je cmd_help |
|
push str_unkown |
call [con_write_asciiz] |
|
jmp wait_for_usercommand |
|
|
.connected: |
|
push str_user |
call [con_write_asciiz] |
|
mov dword[s], "USER" |
mov byte[s+4], " " |
|
; mov [status], STATUS_NEEDPASSWORD |
inc [status] |
|
jmp .send |
|
|
.needpass: |
push str_pass |
call [con_write_asciiz] |
|
mov dword[s], "PASS" |
mov byte[s+4], " " |
|
; mov [status], STATUS_LOGGED_IN |
inc [status] |
|
.send: |
; read string |
mov esi, s+5 |
push 256 |
push esi |
call [con_gets] |
|
mov edi, s+5 |
mov ecx, 256 |
xor al, al |
repne scasb |
lea esi, [edi-s-1] |
mcall send, [socketnum], s |
|
jmp wait_for_usercommand |
|
|
|
|
|
|
open_dataconnection: |
cmp [status], STATUS_LOGGED_IN |
jne .fail |
|
mov dword[s], "PASV" |
mov byte[s+4], 10 |
mcall send, [socketnum], s, 5 |
|
ret |
|
.fail: |
push str6 |
call [con_write_asciiz] |
|
ret |
|
|
fail2: |
push str6 |
call [con_write_asciiz] |
|
jmp fail.wait |
|
fail: |
push str5 |
call [con_write_asciiz] |
.wait: |
push str10 |
call [con_write_asciiz] |
call [con_getch2] |
jmp main |
|
done: |
push 1 |
call [con_exit] |
exit: |
|
mcall close, [socketnum] |
mcall -1 |
|
|
|
; data |
title db 'FTP client',0 |
str1 db 'FTP client for KolibriOS v0.01',10,10,'Please enter ftp server address.',10,0 |
str2 db '> ',0 |
str3 db 'Resolving ',0 |
str4 db 10,0 |
str5 db 10,'Name resolution failed.',10,0 |
str6 db 10,'Socket error.',10,0 |
str8 db ' (',0 |
str9 db ')',10,0 |
str10 db 'Push any key to continue.',0 |
str11 db 'Connecting',10,0 |
str12 db 'Connected!',10,0 |
str_user db "username: ",0 |
str_pass db "password: ",0 |
str_unkown db "unkown command",10,0 |
str_help db "available commands:",10,10 |
db "help list",10,0 |
|
str_open db "opening data socket",10,0 |
|
sockaddr1: |
dw AF_INET4 |
.port dw 0x1500 ; 21 |
.ip dd 0 |
rb 10 |
|
sockaddr2: |
dw AF_INET4 |
.port dw 0 |
.ip dd 0 |
rb 10 |
|
include_debug_strings ; ALWAYS present in data section |
|
|
|
; import |
align 4 |
@IMPORT: |
|
library network, 'network.obj', console, 'console.obj' |
|
import network, \ |
getaddrinfo, 'getaddrinfo', \ |
freeaddrinfo, 'freeaddrinfo', \ |
inet_ntoa, 'inet_ntoa' |
|
import console, \ |
con_start, 'START', \ |
con_init, 'con_init', \ |
con_write_asciiz,'con_write_asciiz', \ |
con_exit, 'con_exit', \ |
con_gets, 'con_gets',\ |
con_cls, 'con_cls',\ |
con_getch2, 'con_getch2',\ |
con_set_cursor_pos, 'con_set_cursor_pos',\ |
con_write_string, 'con_write_string',\ |
con_get_flags, 'con_get_flags' |
|
|
i_end: |
|
active_passive db ? |
socketnum dd ? |
datasocket dd ? |
buffer_ptr rb 2*BUFFERSIZE |
status db ? |
offset dd ? |
|
s rb 1024 |
|
mem: |