Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 3531 → Rev 3545

/kernel/branches/net/applications/downloader/downloader.asm
0,0 → 1,1201
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2009-2013. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; downloader.asm - HTTP client for KolibriOS ;;
;; ;;
;; Based on HTTPC.asm for menuetos by ville turjanmaa ;;
;; ;;
;; Programmers: Barsuk, Clevermouse, Marat Zakiyanov, ;;
;; Kirill Lipatov, dunkaist, HidnPlayr ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
URLMAXLEN = 1024
primary_buffer_size = 4096
 
__DEBUG__ = 1
__DEBUG_LEVEL__ = 1
 
format binary as ""
 
use32
org 0x0
 
db 'MENUET01' ; header
dd 0x01 ; header version
dd START ; entry point
dd IM_END ; image size
dd I_END ; required memory
dd I_END ; esp
dd params ; I_PARAM
dd 0x0 ; I_Path
 
include '../macros.inc'
include '../proc32.inc'
include '../network.inc'
include '../../../../../programs/develop/libraries/box_lib/trunk/box_lib.mac'
include '../dll.inc'
include '../debug-fdo.inc'
 
START:
 
mcall 68, 11 ; init heap so we can allocate memory dynamically
 
mcall 40, EV_STACK
 
; load libraries
stdcall dll.Load, @IMPORT
test eax, eax
jnz exit
 
; prepare webAddr area
 
mov al, ' '
mov edi, webAddr
mov ecx, URLMAXLEN
rep stosb
xor eax, eax
stosb
 
; prepare document area
mov al, '/'
mov edi, document
stosb
mov al, ' '
mov ecx, URLMAXLEN-1
rep stosb
 
call load_settings
cmp byte[params], 0
je prepare_event ;red
 
; we have an url
mov edi, document_user
mov al, ' '
mov ecx, URLMAXLEN
rep stosb
mov esi, params
mov edi, document_user
 
; copy untill space or 0
.copy_param:
mov al, [esi]
test al, al
jz .done
 
cmp al, ' '
jz .done_inc
 
mov [edi], al
inc esi
inc edi
jmp .copy_param
 
.done_inc:
 
; url is followed by shared memory name.
inc esi
.done:
mov [shared_name], esi
 
mov ah, 22 ; strange way to tell that socket should be opened...
call socket_commands
 
jmp still
 
prepare_event:
; Report events
; Stack 8 + defaults
mcall 40, 10100111b
 
red: ; redraw
call draw_window
 
still:
mcall 23, 1 ; wait here for event
cmp eax, 1 ; redraw request ?
je red
 
cmp eax, 2 ; key in buffer ?
je key
 
cmp eax, 3 ; button in buffer ?
je button
cmp eax, 6 ; mouse in buffer ?
je mouse
 
; Get the web page data from the remote server
cmp eax, 8
jne still
 
call read_incoming_data
 
cmp [status], 4
je .no_send
 
mov [onoff], 1
call send_request
 
.no_send:
call print_status
 
cmp [prev_status], 4
jne no_close
cmp [status], 4 ; connection closed by server
jbe no_close ; respond to connection close command
; draw page
call read_incoming_data
mcall close, [socketnum]
mov [onoff], 0
 
no_close:
jmp still
 
key:
mcall 2 ; read key
 
stdcall [edit_box_key], dword edit1
 
shr eax, 8
cmp eax, 13
je retkey
jmp still
 
button:
 
mcall 17 ; get id
cmp ah, 26
je save
cmp ah, 1 ; button id=1 ?
jne noclose
; DEBUGF 1, "Closing socket before exit...\n"
 
close_end_exit:
 
exit:
or eax, -1 ; close this program
mcall
mouse:
stdcall [edit_box_mouse], edit1
jmp still
 
save:
DEBUGF 1, "file saved\n"
mcall 70, fileinfo
 
mov ecx, [sc.work_text]
or ecx, 0x80000000
mcall 4, <10, 93>, , download_complete
 
jmp still
 
noclose:
cmp ah, 31
jne noup
sub [display_from], 20
jmp still
 
noup:
cmp ah, 32
jne nourl
add [display_from], 20
jmp still
 
 
retkey:
mov ah, 22 ; start load
 
nourl:
call socket_commands ; opens or closes the connection
jmp still
 
 
;****************************************************************************
; Function
; send_request
;
; Description
; Transmits the GET request to the server.
; This is done as GET then URL then HTTP/1.1', 13, 10, 13, 10 in 3 packets
;
;****************************************************************************
send_request:
pusha
mov esi, string0
mov edi, request
movsd
; If proxy is used, make absolute URI - prepend http://<host>
cmp byte[proxyAddr], 0
jz .noproxy
mov dword[edi], 'http'
mov byte[edi+4], ':'
mov word[edi+5], '//'
add edi, 7
mov esi, webAddr
 
.copy_host_loop:
lodsb
cmp al, ' '
jz .noproxy
stosb
jmp .copy_host_loop
 
.noproxy:
xor edx, edx ; 0
 
.next_edx:
; Determine the length of the url to send in the GET request
mov al, [edx+document]
cmp al, ' '
je .document_done
mov [edi], al
inc edi
inc edx
jmp .next_edx
 
.document_done:
mov esi, stringh
mov ecx, stringh_end-stringh
rep movsb
xor edx, edx ; 0
 
.webaddr_next:
mov al, [webAddr + edx]
cmp al, ' '
je .webaddr_done
mov [edi], al
inc edi
inc edx
jmp .webaddr_next
 
.webaddr_done:
cmp byte[proxyUser], 0
jz @f
call append_proxy_auth_header
@@:
mov esi, connclose
mov ecx, connclose_end-connclose
rep movsb
 
pusha
mov eax, 63
mov ebx, 1
mov edx, request
@@:
mov cl, [edx]
cmp edx, edi
jz @f
mcall
inc edx
jmp @b
@@:
popa
 
mov esi, edi
sub esi, request ; length
xor edi, edi ; flags
;;;;now write \r\nConnection: Close \r\n\r\n
mcall send, [socketnum], request ;' HTTP/1.1 .. '
popa
ret
 
;****************************************************************************
; Function
; print_status
;
; Description
; displays the socket/data received status information
;
;****************************************************************************
print_status:
pusha
mcall 26, 9
cmp eax, [nextupdate]
jb status_return
 
add eax, 25
mov [nextupdate], eax
 
mov ecx, [winys]
shl ecx, 16
add ecx, -18 shl 16 + 10
mcall 13, <5, 100>, , 0xffffff
 
mov edx, 12 shl 16 - 18
add edx, [winys]
xor esi, esi
mcall 47, <3, 0>, [status], ,
 
mov edx, 40 shl 16 - 18
add edx, [winys]
mcall , <6, 0>, [pos]
 
status_return:
popa
ret
 
;****************************************************************************
; Function
; read_incoming_data
;
; Description
; receive the web page from the server, storing it without processing
;
;****************************************************************************
read_incoming_data:
cmp [onoff], 1
je .rid
ret
 
.rid:
push esi
push edi
DEBUGF 1, "rid\n"
 
.read:
mcall recv, [socketnum], primary_buf, primary_buffer_size, 0
inc eax ; -1 = error (socket closed?)
jz .no_more_data
dec eax ; 0 bytes...
jz .read
mov edi, [pos]
add [pos], eax
push eax
mcall 68, 20, [pos], [buf_ptr]
mov [buf_ptr], eax
add edi, eax
mov esi, primary_buf
pop ecx ; number of recently read bytes
lea edx, [ecx - 3]
rep movsb
.no_more_data:
 
; mov [status], 4 ; connection closed by server
 
call parse_result
mov ecx, [shared_name]
test ecx, ecx
jz @f
cmp [ecx], byte 0
jnz save_in_shared
@@:
 
mcall 70, fileinfo
mov ecx, [sc.work_text]
or ecx, 0x80000000
mcall 4, <10, 93>, , download_complete
DEBUGF 1, "file saved\n"
 
pop edi
pop esi
 
; if called from command line, then exit
cmp byte[params], 0
jne exit
 
ret
save_in_shared:
 
mov esi, 1 ; SHM_OPEN+SHM_WRITE
mcall 68, 22
test eax, eax
jz save_in_shared_done
 
sub edx, 4
jbe save_in_shared_done
 
mov ecx, [final_size]
cmp ecx, edx
jb @f
 
mov ecx, edx
@@:
mov [eax], ecx
lea edi, [eax+4]
mov esi, [final_buffer]
mov edx, ecx
shr ecx, 2
rep movsd
mov ecx, edx
and ecx, 3
rep movsb
 
save_in_shared_done:
pop edi
pop esi
jmp exit
; this function cuts header, and removes chunk sizes if doc is chunked
; in: buf_ptr, pos; out: buf_ptr, pos.
parse_result:
; close socket
mcall close, [socketnum]
DEBUGF 1, "close socketnum: 0x%x\n", eax
mov edi, [buf_ptr]
mov edx, [pos]
mov [buf_size], edx
; mcall 70, fileinfo_tmp
DEBUGF 1, "pos = 0x%x\n", edx
 
; first, find end of headers
.next_byte:
cmp dword[edi], 0x0d0a0d0a ; ìíå ëåíü ÷èòàòü ñòàíäàðò, ïóñòü áóäóò îáà âàðèàíòà
je .end_of_headers
cmp dword[edi], 0x0a0d0a0d
je .end_of_headers
inc edi
dec edx
jne .next_byte
; no end of headers. it's an error. let client see all those headers.
ret
 
.end_of_headers:
; here we look at headers and search content-length or transfer-encoding headers
; DEBUGF 1, "eoh\n"
 
sub edi, [buf_ptr]
add edi, 4
mov [body_pos], edi ; store position where document body starts
mov [is_chunked], 0
; find content-length in headers
; not good method, but should work for 'Content-Length:'
mov esi, [buf_ptr]
mov edi, s_contentlength
mov ebx, [body_pos]
xor edx, edx ; 0
.cl_next:
mov al, [esi]
cmp al, [edi + edx]
jne .cl_fail
inc edx
cmp edx, len_contentlength
je .cl_found
jmp .cl_incr
.cl_fail:
xor edx, edx ; 0
.cl_incr:
inc esi
dec ebx
je .cl_error
jmp .cl_next
.cl_error:
; DEBUGF 1, "content-length not found\n"
 
; find 'chunked'
; äà, ÿ êîïèðóþ êîä, ýòî óæàñíî, íî ìíå õî÷åòñÿ, ÷òîáû ïîñêîðåå çàðàáîòàëî
; à òàì óæ îòðåôàêòîðþ
mov esi, [buf_ptr]
mov edi, s_chunked
mov ebx, [body_pos]
xor edx, edx ; 0
 
.ch_next:
mov al, [esi]
cmp al, [edi + edx]
jne .ch_fail
inc edx
cmp edx, len_chunked
je .ch_found
jmp .ch_incr
 
.ch_fail:
xor edx, edx ; 0
 
.ch_incr:
inc esi
dec ebx
je .ch_error
jmp .ch_next
 
.ch_error:
; if neither of the 2 headers is found, it's an error
; DEBUGF 1, "transfer-encoding: chunked not found\n"
mov eax, [pos]
sub eax, [body_pos]
jmp .write_final_size
 
.ch_found:
mov [is_chunked], 1
mov eax, [body_pos]
add eax, [buf_ptr]
sub eax, 2
mov [prev_chunk_end], eax
jmp parse_chunks
.cl_found:
call read_number ; eax = number from *esi
 
.write_final_size:
mov [final_size], eax ; if this works, i will b very happy...
mov ebx, [pos] ; we well check if it is right
sub ebx, [body_pos]
 
; everything is ok, so we return
mov eax, [body_pos]
mov ebx, [buf_ptr]
add ebx, eax
mov [final_buffer], ebx
; mov ebx, [pos]
; sub ebx, eax
; mov [final_size], ebx
ret
parse_chunks:
; DEBUGF 1, "parse chunks\n"
; we have to look through the data and remove sizes of chunks we see
; 1. read size of next chunk
; 2. if 0, it's end. if not, continue.
; 3. make a good buffer and copy a chunk there
xor eax, eax
mov [final_buffer], eax ; 0
mov [final_size], eax ; 0
.read_size:
mov eax, [prev_chunk_end]
mov ebx, eax
sub ebx, [buf_ptr]
mov edx, eax
; DEBUGF 1, "rs "
cmp ebx, [pos]
jae chunks_end ; not good
call read_hex ; in: eax=pointer to text. out:eax=hex number, ebx=end of text.
cmp eax, 0
jz chunks_end
 
add ebx, 1
mov edx, ebx ; edx = size of size of chunk
add ebx, eax
mov [prev_chunk_end], ebx
; DEBUGF 1, "sz "
 
; do copying: from buf_ptr+edx to final_buffer+prev_final_size count eax
; realloc final buffer
push eax
push edx
push dword [final_size]
add [final_size], eax
mcall 68, 20, [final_size], [final_buffer]
mov [final_buffer], eax
; DEBUGF 1, "re "
pop edi
pop esi
pop ecx
; add [pos], ecx
add edi, [final_buffer]
; DEBUGF 1, "cp "
 
rep movsb
jmp .read_size
chunks_end:
; free old buffer
DEBUGF 1, "chunks end\n"
 
mcall 68, 13, [buf_ptr]
; done!
ret
 
; reads content-length from [edi+ecx], result in eax
read_number:
push ebx
xor eax, eax
xor ebx, ebx
 
.next:
mov bl, [esi]
 
cmp bl, '0'
jb .not_number
cmp bl, '9'
ja .not_number
sub bl, '0'
shl eax, 1
lea eax, [eax + eax * 4] ; eax *= 10
add eax, ebx
 
.not_number:
cmp bl, 13
je .done
inc esi
jmp .next
 
.done:
pop ebx
ret
; reads hex from eax, result in eax, end of text in ebx
read_hex:
add eax, 2
mov ebx, eax
mov eax, [ebx]
mov [deba], eax
 
xor eax, eax
xor ecx, ecx
.next:
mov cl, [ebx]
inc ebx
cmp cl, 0x0d
jz .done
 
or cl, 0x20
sub cl, '0'
jb .bad
 
cmp cl, 0x9
jbe .adding
 
sub cl, 'a'-'0'-10
cmp cl, 0x0a
jb .bad
 
cmp cl, 0x0f
ja .bad
 
.adding:
shl eax, 4
or eax, ecx
; jmp .not_number
;.bad:
.bad:
jmp .next
.done:
 
ret
 
;****************************************************************************
; Function
; socket_commands
;
; Description
; opens or closes the socket
;
;****************************************************************************
socket_commands:
cmp ah, 22 ; open socket
jne tst3
 
DEBUGF 1, "opening socket\n"
 
; Clear all page memory
xor eax, eax
mov [prev_chunk_end], eax ; 0
cmp [buf_ptr], eax ; 0
jz no_free
 
mcall 68, 13, [buf_ptr] ; free buffer
 
no_free:
xor eax, eax
mov [buf_size], eax ; 0
; Parse the entered url
call parse_url
 
mov edx, 80
cmp byte [proxyAddr], 0
jz @f
mov eax, [proxyPort]
xchg al, ah
mov [server_port], ax
@@:
 
mcall socket, AF_INET4, SOCK_STREAM, 0
mov [socketnum], eax
mcall connect, [socketnum], sockaddr1, 18
mov [pagexs], 80
push eax
xor eax, eax ; 0
mov [pos], eax
mov [pagex], eax
mov [pagey], eax
mov [command_on_off], eax
mov [is_body], eax
pop eax
ret
 
tst3:
cmp ah, 24 ; close socket
jne no_24
 
mcall close, [socketnum]
no_24:
ret
 
;****************************************************************************
; Function
; parse_url
;
; Description
; parses the full url typed in by the user into a web address ( that
; can be turned into an IP address by DNS ) and the page to display
; DNS will be used to translate the web address into an IP address, if
; needed.
; url is at document_user and will be space terminated.
; web address goes to webAddr and is space terminated.
; ip address goes to server_ip
; page goes to document and is space terminated.
;
; Supported formats:
; <protocol://>address<page>
; <protocol> is optional, removed and ignored - only http supported
; <address> is required. It can be an ip address or web address
; <page> is optional and must start with a leading / character
;
;****************************************************************************
parse_url:
; First, reset destination variables
mov al, ' '
mov edi, document
mov ecx, URLMAXLEN
rep stosb
mov edi, webAddr
mov ecx, URLMAXLEN
rep stosb
 
mov al, '/'
mov [document], al
 
mov esi, document_user
; remove any leading protocol text
mov ecx, URLMAXLEN
mov ax, '//'
 
pu_000:
cmp [esi], byte ' ' ; end of text?
je pu_002 ; yep, so not found
cmp [esi], ax
je pu_001 ; Found it, so esi+2 is start
inc esi
loop pu_000
 
pu_002:
; not found, so reset esi to start
mov esi, document_user-2
 
pu_001:
add esi, 2
mov ebx, esi ; save address of start of web address
mov edi, document_user + URLMAXLEN ; end of string
; look for page delimiter - it's a '/' character
pu_003:
cmp [esi], byte ' ' ; end of text?
je pu_004 ; yep, so none found
cmp esi, edi ; end of string?
je pu_004 ; yep, so none found
cmp [esi], byte '/' ; delimiter?
je pu_005 ; yep - process it
inc esi
jmp pu_003
 
pu_005:
; copy page to document address
; esi = delimiter
push esi
mov ecx, edi ; end of document_user
mov edi, document
 
pu_006:
movsb
cmp esi, ecx
je pu_007 ; end of string?
cmp [esi], byte ' ' ; end of text
; je pu_007 ; äçåí-àññåìáëåð
; jmp pu_006 ; íå íàäî ïëîäèòü ñóùíîñòè ïî íàïðàñíó
jne pu_006
 
pu_007:
pop esi ; point esi to '/' delimiter
 
pu_004:
; copy web address to webAddr
; start in ebx, end in esi-1
mov ecx, esi
mov esi, ebx
mov edi, webAddr
 
pu_008:
movsb
cmp esi, ecx
; je pu_009 ; äçåí-àññåìáëåð
; jmp pu_008 ; íå íàäî ïëîäèòü ñóùíîñòè ïî íàïðàñíó
jne pu_008
 
pu_009:
; For debugging, display resulting strings
DEBUGF 1, "%s", document_user
DEBUGF 1, "%s", webAddr
DEBUGF 1, "%s", document
 
; Look up the ip address, or was it specified?
mov al, [proxyAddr]
cmp al, 0
jnz pu_015
mov al, [webAddr]
pu_015:
cmp al, '0'
jb pu_010 ; Resolve address
cmp al, '9'
ja pu_010 ; Resolve address
 
DEBUGF 1, "GotIP\n"
 
; Convert address
; If proxy is given, get proxy address instead of server
mov esi, proxyAddr-1
cmp byte[esi+1], 0
jne pu_020
mov esi, webAddr-1
 
pu_020:
mov edi, server_ip
xor eax, eax
 
ip1:
inc esi
cmp [esi], byte '0'
jb ip2
cmp [esi], byte '9'
ja ip2
imul eax, 10
movzx ebx, byte [esi]
sub ebx, 48
add eax, ebx
jmp ip1
 
ip2:
mov [edi], al
xor eax, eax
inc edi
cmp edi, server_ip+3
jbe ip1
jmp pu_011
 
pu_010:
DEBUGF 1, "Resolving...\n"
 
; resolve name
push esp ; reserve stack place
push esp ; fourth parameter
push 0 ; third parameter
push 0 ; second parameter
push webAddr
call [getaddrinfo]
pop esi
; test for error
test eax, eax
; jnz .fail_dns
 
; fill in ip in sockstruct
mov eax, [esi + addrinfo.ai_addr]
mov eax, [eax + sockaddr_in.sin_addr]
mov [server_ip], eax
 
 
DEBUGF 1, "Resolved\n"
 
pu_011:
 
ret
 
;***************************************************************************
; Function
; load_settings
;
; Description
; Load settings from configuration file network.ini
;
;***************************************************************************
load_settings:
 
invoke ini.get_str, inifile, sec_proxy, key_proxy, proxyAddr, 256, proxyAddr
invoke ini.get_int, inifile, sec_proxy, key_proxyport, 80
mov [proxyPort], eax
invoke ini.get_str, inifile, sec_proxy, key_user, proxyUser, 256, proxyUser
invoke ini.get_str, inifile, sec_proxy, key_password, proxyPassword, 256, proxyPassword
 
ret
 
;***************************************************************************
; Function
; append_proxy_auth_header
;
; Description
; Append header to HTTP request for proxy authentification
;
;***************************************************************************
append_proxy_auth_header:
mov esi, proxy_auth_basic
mov ecx, proxy_auth_basic_end - proxy_auth_basic
rep movsb
; base64-encode string <user>:<password>
mov esi, proxyUser
 
apah000:
lodsb
test al, al
jz apah001
call encode_base64_byte
jmp apah000
 
apah001:
mov al, ':'
call encode_base64_byte
mov esi, proxyPassword
 
apah002:
lodsb
test al, al
jz apah003
call encode_base64_byte
jmp apah002
 
apah003:
call encode_base64_final
ret
 
encode_base64_byte:
inc ecx
shl edx, 8
mov dl, al
cmp ecx, 3
je ebb001
ret
 
ebb001:
shl edx, 8
inc ecx
 
ebb002:
rol edx, 6
xor eax, eax
xchg al, dl
mov al, [base64_table+eax]
stosb
loop ebb002
ret
 
encode_base64_final:
mov al, 0
test ecx, ecx
jz ebf000
call encode_base64_byte
test ecx, ecx
jz ebf001
call encode_base64_byte
mov byte [edi-2], '='
 
ebf001:
mov byte [edi-1], '='
 
ebf000:
ret
 
; *********************************************
; ******* WINDOW DEFINITIONS AND DRAW ********
; *********************************************
 
draw_window:
 
mcall 12, 1
 
mcall 48, 3, sc, 40 ;get system colors
 
mov edx, [sc.work]
or edx, 0x34000000
mcall 0, <50, 370>, <350, 140>, , 0, title ;draw window
mov ecx, [sc.work_text]
or ecx, 80000000h
mcall 4, <14, 14>, , type_pls ;"URL:"
 
edit_boxes_set_sys_color edit1, editboxes_end, sc
stdcall [edit_box_draw], edit1
 
; RELOAD
mcall 8, <90, 68>, <54, 16>, 22, [sc.work_button]
; STOP
mcall , <166, 50>, <54, 16>, 24
; SAVE
mcall , <224, 54>, , 26
; BUTTON TEXT
mov ecx, [sc.work_button_text]
or ecx, 80000000h
mcall 4, <102, 59>, , button_text
 
mcall 12, 2 ; end window redraw
ret
;-----------------------------------------------------------------------------
; Data area
;-----------------------------------------------------------------------------
align 4
@IMPORT:
 
library libini, 'libini.obj', \
box_lib, 'box_lib.obj', \
network, 'network.obj'
 
import libini, \
ini.get_str, 'ini_get_str', \
ini.get_int, 'ini_get_int'
 
import box_lib, \
edit_box_draw, 'edit_box', \
edit_box_key, 'edit_box_key', \
edit_box_mouse, 'edit_box_mouse'
 
import network,\
getaddrinfo, 'getaddrinfo',\
freeaddrinfo, 'freeaddrinfo',\
inet_ntoa, 'inet_ntoa'
 
;---------------------------------------------------------------------
fileinfo dd 2, 0, 0
final_size dd 0
final_buffer dd 0
db '/rd/1/.download', 0
body_pos dd 0
 
buf_size dd 0
buf_ptr dd 0
 
deba dd 0
db 0
 
;---------------------------------------------------------------------
 
mouse_dd dd 0
edit1 edit_box 295, 48, 10, 0xffffff, 0xff, 0x80ff, 0, 0x8000, URLMAXLEN, document_user, mouse_dd, ed_focus+ed_always_focus, 7, 7
editboxes_end:
 
;---------------------------------------------------------------------
 
include_debug_strings
 
;---------------------------------------------------------------------
 
type_pls db 'URL:', 0
button_text db 'DOWNLOAD STOP RESAVE', 0
download_complete db 'File saved as /rd/1/.download', 0
display_from dd 20
pos dd 0
pagex dd 0
pagey dd 0
pagexs dd 80
command_on_off dd 0
text_type db 1
com2 dd 0
script dd 0
socketnum dd 0
 
addr dd 0
ya dd 0
len dd 0
 
title db 'HTTP Downloader', 0
 
;---------------------------------------------------------------------
s_contentlength db 'Content-Length:'
len_contentlength = 15
 
s_chunked db 'Transfer-Encoding: chunked'
len_chunked = $ - s_chunked
 
is_body dd 0 ; 0 if headers, 1 if content
is_chunked dd 0
prev_chunk_end dd 0
cur_chunk_size dd 0
 
string0: db 'GET '
 
stringh db ' HTTP/1.1', 13, 10, 'Host: '
stringh_end:
proxy_auth_basic db 13, 10, 'Proxy-Authorization: Basic '
proxy_auth_basic_end:
connclose db 13, 10, 'User-Agent: Kolibrios Downloader', 13, 10, 'Connection: Close', 13, 10, 13, 10
connclose_end:
 
base64_table db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
db '0123456789+/'
 
inifile db '/sys/network.ini', 0
 
sec_proxy:
key_proxy db 'proxy', 0
key_proxyport db 'port', 0
key_user db 'user', 0
key_password db 'password', 0
 
sockaddr1:
dw AF_INET4
server_port dw 0x5000 ; 80
server_ip dd 0
rb 10
 
proxyPort dd 80
 
shared_name dd 0
 
status dd 0x0
prev_status dd 0x0
 
onoff dd 0x0
 
nextupdate dd 0
winys dd 400
 
;---------------------------------------------------------------------
document_user db 'http://', 0
;---------------------------------------------------------------------
IM_END:
;---------------------------------------------------------------------
rb URLMAXLEN-(IM_END - document_user)
;---------------------------------------------------------------------
sc system_colors
;---------------------------------------------------------------------
align 4
document rb URLMAXLEN
;---------------------------------------------------------------------
align 4
webAddr rb URLMAXLEN+1
;---------------------------------------------------------------------
 
align 4
primary_buf rb primary_buffer_size
 
params rb 1024
 
request rb 256
 
proxyAddr rb 256
proxyUser rb 256
proxyPassword rb 256
 
rb 4096 ; stack
 
I_END:
 
 
 
/kernel/branches/net/applications/ftpc/ftpc.asm
0,0 → 1,390
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; 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 = 1
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
jz fail2
mov [socketnum], eax
 
mcall connect, [socketnum], sockaddr1, 18
 
mcall 40, 1 shl 7
 
mov [status], STATUS_CONNECTING
mov [offset], buffer_ptr
 
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], " "
 
jmp .send
 
 
.needpass:
push str_pass
call [con_write_asciiz]
 
mov dword[s], "PASS"
mov byte[s+4], " "
 
.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 'Connecting to ',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
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:
/kernel/branches/net/applications/ftpc/servercommands.inc
0,0 → 1,114
server_parser:
 
; Commands are always 3 numbers and followed by a space
; If a server decides it needs multiline output,
; first lines will have a dash instead of space after numbers,
; thus they are simply ignored.
 
cmp dword[s], "150 "
je data_ok
 
cmp dword[s], "220 "
je welcome
 
cmp dword[s], "227 "
je pasv_ok
 
cmp dword[s], "230 "
je login_ok
 
cmp dword[s], "331 "
je pass
 
ret
 
 
welcome:
 
mov [status], STATUS_CONNECTED
ret
 
 
pass:
 
mov [status], STATUS_NEEDPASSWORD
ret
 
 
login_ok:
 
mov [status], STATUS_LOGGED_IN
ret
 
 
pasv_ok:
 
sub ecx, 5
jb .fail
mov al, "("
mov edi, s + 5
repne scasb
 
mcall socket, AF_INET4, SOCK_STREAM, 0
cmp eax, -1
je fail
mov [datasocket], eax
 
mov esi, edi
call ascii_dec
mov byte[sockaddr2.ip+0], bl
call ascii_dec
mov byte[sockaddr2.ip+1], bl
call ascii_dec
mov byte[sockaddr2.ip+2], bl
call ascii_dec
mov byte[sockaddr2.ip+3], bl
 
call ascii_dec
mov byte[sockaddr2.port+1], bl
call ascii_dec
mov byte[sockaddr2.port+0], bl
 
push str_open
call [con_write_asciiz]
 
mcall connect, [datasocket], sockaddr2, 18
 
.fail:
ret
 
 
data_ok:
 
mcall recv, [datasocket], buffer_ptr, BUFFERSIZE, 0 ; fixme: use other buffer
inc eax
jz .fail
dec eax
jz .fail
 
mov byte[buffer_ptr + eax], 0
pushd buffer_ptr
call [con_write_asciiz]
 
.fail:
ret
 
 
ascii_dec:
 
xor ebx, ebx
mov cl, 3
.loop:
lodsb
sub al, '0'
jb .done
cmp al, 9
ja .done
lea ebx, [ebx*4+ebx]
shl ebx, 1
add bl, al
dec cl
jnz .loop
 
.done:
ret
/kernel/branches/net/applications/ftpc/usercommands.inc
0,0 → 1,17
cmd_list:
 
call open_dataconnection
 
mov dword[s], "LIST"
mov word[s+4], 0x0d0a
mcall send, [socketnum], s, 6
 
jmp wait_for_serverdata
 
 
cmd_help:
 
push str_help
call [con_write_asciiz]
 
jmp wait_for_usercommand
/kernel/branches/net/applications/ircc/window.inc
78,6 → 78,21
ret
 
 
window_updated:
 
mov edi, [window_print]
test [edi + window.flags], FLAG_UPDATED
jnz .skip
 
or [edi + window.flags], FLAG_UPDATED
 
; now play a sound :)
 
.skip:
 
ret
 
 
print_text: ; eax = start ptr
; dl = end char
pusha
/kernel/branches/net/applications/libio.inc
78,7 → 78,7
FileSizeHigh dd ?
ends
ends
FileName rb 252
FileName rb 264
ends
 
struct FileInfoW
94,7 → 94,7
FileSizeHigh dd ?
ends
ends
FileName rw 260
FileName rw 264
ends
 
virtual at 0
109,4 → 109,5
FA_LABEL = 00001000b
FA_FOLDER = 00010000b
FA_ARCHIVED = 00100000b
FA_ANY = 00111111b
FA_NORMAL = 01000000b
FA_ANY = 01111111b
/kernel/branches/net/data32.inc
500,4 → 500,5
BiosDiskCaches rb 80h*(cache_ide1-cache_ide0)
BiosDiskPartitions rd 80h
 
tetten:
IncludeUGlobals
/kernel/branches/net/gui/event.inc
527,7 → 527,7
cmp eax, 5
je .mouse_check ; eax=5, retvals=eax+1 (event 6)
 
ja .FlagAutoReset ; eax=[6..8], retvals=eax+1 (event 7...10)
ja .FlagAutoReset ; eax=[6..9], retvals=eax+1 (event 7...10)
 
cmp eax, 1
jae .BtKy ; eax=[1,2], retvals=eax+1 (event 2,3)
/kernel/branches/net/kernel.asm
77,11 → 77,12
USE_COM_IRQ equ 1 ; make irq 3 and irq 4 available for PCI devices
 
; Enabling the next line will enable serial output console
;debug_com_base equ 0x3f8 ; 0x3f8 is com1, 0x2f8 is com2, 0x3e8 is com3, 0x2e8 is com4, no irq's are used
debug_com_base equ 0x3f8 ; 0x3f8 is com1, 0x2f8 is com2, 0x3e8 is com3, 0x2e8 is com4, no irq's are used
 
include "proc32.inc"
include "kglobals.inc"
include "lang.inc"
;include "lang.inc"
lang fix en
 
include "const.inc"
max_processes equ 255
136,7 → 137,7
if lang eq sp
include "kernelsp.inc" ; spanish kernel messages
else
version db 'Kolibri OS version 0.7.7.0+ ',13,10,13,10,0
version db 'Kolibri OS network development ',13,10,13,10,0
end if
 
include "boot/bootstr.inc" ; language-independent boot messages