kolibrios-fun/programs/network/downloader/trunk/downloader.asm
Marat Zakiyanov (Mario79) 97f05bd867 Downloader v0.5
1) reducing the size of the binary code,
2) program uses far less memory while running (>0x7000, the old version used >0x100000)
3) process only net event at start with parameter (URL)

git-svn-id: svn://kolibrios.org@1646 a494cfbc-eb01-0410-851d-a64ba20cac60
2010-10-07 09:38:59 +00:00

1723 lines
32 KiB
NASM
Raw Blame History

; version: 0.5
; last update: 07/10/2010
; written by: Marat Zakiyanov aka Mario79, aka Mario
; changes: reducing the size of the binary code,
; program uses far less memory while running
; (>0x7000, the old version used >0x100000),
; process only net event at start with parameter
;-----------------------------------------------------------
; version 0.3 -0.4
; written by: CleverMouse
;
;-----------------------------------------------------------
; wget 0.2 by barsuk
; based on Menuet Httpc
; Enabling debugging puts stuff to the debug board
DEBUGGING_ENABLED equ 1
DEBUGGING_DISABLED equ 0
DEBUGGING_STATE equ DEBUGGING_ENABLED
use32
org 0x0
db 'MENUET01' ; header
dd 0x01 ; header version
dd START ; entry point
dd IM_END ; image size
dd I_END ;0x100000 ; required memory
dd stacktop ; esp
dd params ; I_PARAM
dd 0x0 ; I_Path
include 'lang.inc'
include '../../../macros.inc'
include "../../../proc32.inc"
include "dll.inc"
include "debug.inc"
URLMAXLEN equ 256 ; maximum length of url string
primary_buffer_size equ 4096
; Memory usage
; webpage headers at buf_headers
START: ; start of execution
;dps <"Program started",13,10>
; prepare webAddr area
mov al,' '
mov edi,webAddr
mov ecx,URLMAXLEN
cld
rep stosb
xor eax,eax
stosb
; prepare document area
mov al,'/'
mov edi,document
cld
stosb
mov al,' '
mov ecx,URLMAXLEN-1
rep stosb
; create local heap
mcall 68,11
call load_settings
cmp [params],byte 0
jz prepare_event ;red
mcall 40,10000000b ; only net event!!!
; we have an url
mov edi,document_user
mov al,' '
mov ecx,URLMAXLEN
rep stosb
mov esi,params
mov edi,document_user
.copy_param:
mov al,[esi]
cmp al,0
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,10000111b
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
; Get the web page data from the remote server
call read_incoming_data
mov eax,[status]
mov [prev_status],eax
mcall 53,6,[socket]
mov [status],eax
cmp [prev_status],4
jge no_send
cmp [status],4
jne 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 53,8,[socket]
call draw_page
mov [onoff],0
no_close:
jmp still
key: ; key
mcall 2 ; just read it and ignore
shr eax,8
cmp eax,184
jne no_down
cmp [display_from],25
jb no_down
sub [display_from],25
call display_page
no_down:
cmp eax,183
jne no_up
add [display_from],25
call display_page
no_up:
jmp still
button: ; button
;dps <"Button pressed",13,10>
mcall 17 ; get id
cmp ah,26
je save
cmp ah,1 ; button id=1 ?
jne noclose
; dps "Closing socket before exit... "
close_end_exit:
;dpd eax
;dps <13,10>
exit:
or eax,-1 ; close this program
mcall
save:
dps "saving"
newline
mcall 70,fileinfo
;pregs
jmp still
noclose:
cmp ah,31
jne noup
sub [display_from],20
call display_page
jmp still
noup:
cmp ah,32
jne nodown
add [display_from],20
call display_page
jmp still
nodown:
cmp ah,10 ; Enter url
jne nourl
mov [addr],dword document_user
mov [ya],dword 38
mov [len],dword URLMAXLEN
mov ecx,URLMAXLEN
mov edi,[addr]
mov al,' '
rep stosb
call print_text
mov edi,[addr]
f11:
mcall 10
cmp eax,2 ; key?
jz fbu
jmp still
fbu:
mcall 2 ; get key
shr eax,8
cmp eax,8
jnz nobs
cmp edi,[addr]
jz f11
sub edi,1
mov [edi],byte ' '
call print_text
jmp f11
nobs:
cmp eax,10
je retkey
cmp eax,13
je retkey
cmp eax,31
jbe f11
; Removed in v0.4
; cmp eax,95
; jb keyok
; sub eax,32
keyok:
mov [edi],al
call print_text
add edi,1
mov esi,[addr]
add esi,URLMAXLEN
cmp esi,edi
jnz f11
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 [proxyAddr],byte 0
jz .noproxy
mov dword [edi],'http'
mov [edi+4],byte ':'
mov [edi+5],word '//'
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 [proxyUser],byte 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 edx,edi
sub edx,request
;;;;now write \r\nConnection: Close \r\n\r\n
mcall 53,7,[socket],,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*65536+10
mcall 13,<5,100>,,0xffffff
mov edx,12*65536-18
add edx,[winys]
xor esi,esi
mcall 47,<3,0>,[status],,
mov edx,40*65536-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
dps "rid"
newline
newbyteread:
;call print_status
mcall 53,2,[socket]
cmp eax,0
je no_more_data
mcall 53,11,[socket],primary_buf,primary_buffer_size
;dps "part "
;dph eax
;newline
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:
mcall 53,6,[socket]
cmp eax,4
jne no_more_data.finish
jmp newbyteread
.finish:
;dps "finish "
;pregs
call parse_result
mov ecx,[shared_name]
cmp [ecx],byte 0
jnz save_in_shared
mcall 70,fileinfo
;dps "saving "
;pregs
; jmp close_end_exit
pop edi
pop esi
; if called from command line, then exit
cmp [params],byte 0
jnz 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 53,8,[socket]
dps "close socket: "
dph eax
newline
mov edi,[buf_ptr]
mov edx,[pos]
mov [buf_size],edx
; mcall 70,fileinfo_tmp
dps "pos = "
dph edx
newline
; first, find end of headers
.next_byte:
cmp [edi],dword 0x0d0a0d0a ; <20><><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
je .end_of_headers
cmp [edi],dword 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
;dps "eoh "
;newline
sub edi,[buf_ptr]
add edi,3
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:
;pregs
;newline
;dph esi
;dps " content-length not found "
; find 'chunked'
; <20><>, <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>, <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
; <20> <20><><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
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
;dps "transfer-encoding: chunked not found "
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
inc eax ; bugfix :)
.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]
;dps "check cl eax==ebx "
;pregs
; 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:
;dps "parse chunks"
;newline
; 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
;dps "rs "
;pregs
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
;dps "sz "
;pregs
; 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
;dps "re "
;pregs
pop edi
pop esi
pop ecx
; add [pos],ecx
add edi,[final_buffer]
;dps "cp "
;pregs
rep movsb
jmp .read_size
chunks_end:
; free old buffer
dps "chunks end"
newline
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]
;dph ebx
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
jz .done
inc esi
jmp .next
.done:
pop ebx
;newline
;dps "strtoint eax "
;pregs
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
; pushf
; pushad
; mov edx,deba
; call debug_outstr
; popad
; popf
xor eax,eax
xor ecx,ecx
.next:
mov cl,[ebx]
inc ebx
cmp cl,0x0d
jz .done
;dph ebx
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:
;newline
;dps "hextoint eax "
;pregs
ret
;****************************************************************************
; Function
; draw_page
;
; Description
; parses the web page data, storing displayable data at 0x20000
; and attributes at 0x30000. It then calls display_page to render
; the data
;
;****************************************************************************
draw_page:
ret
;****************************************************************************
; Function
; linefeed
;
; Description
;
;
;****************************************************************************
linefeed:
ret
;****************************************************************************
; Function
; display_page
;
; Description
; Renders the text decoded by draw_page
;
;****************************************************************************
display_page:
ret
;****************************************************************************
; Function
; socket_commands
;
; Description
; opens or closes the socket
;
;****************************************************************************
socket_commands:
cmp ah,22 ; open socket
jnz tst3
dps "opening socket"
newline
; 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
; Get a free port number
mov ecx,1000 ; local port starting at 1000
getlp1:
inc ecx
push ecx
mcall 53,9
pop ecx
cmp eax,0 ; is this local port in use?
jz getlp1 ; yes - so try next
mov edx,80
cmp [proxyAddr],byte 0
jz sc000
mov edx,[proxyPort]
sc000:
mcall 53,5,,,[server_ip],1
mov [socket],eax
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
jnz no_24
mcall 53,8,[socket]
call draw_page
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
cld
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
cld
pu_006:
movsb
cmp esi,ecx
je pu_007 ; end of string?
cmp [esi],byte ' ' ; end of text
; je pu_007 ; <20><><EFBFBD><EFBFBD>-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
; jmp pu_006 ; <20><> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
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
cld
pu_008:
movsb
cmp esi,ecx
; je pu_009 ; <20><><EFBFBD><EFBFBD>-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
; jmp pu_008 ; <20><> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
jne pu_008
pu_009:
; For debugging, display resulting strings
if DEBUGGING_STATE = DEBUGGING_ENABLED
mov esi,document_user
call debug_print_string
mov esi,webAddr
call debug_print_string
mov esi,document
call debug_print_string
end if
; 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
if DEBUGGING_STATE = DEBUGGING_ENABLED
mov esi,str2 ; print gotip
call debug_print_string
end if
; Convert address
; If proxy is given, get proxy address instead of server
mov esi,proxyAddr-1
cmp byte [esi+1],0
jnz 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'
jg 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:
if DEBUGGING_STATE = DEBUGGING_ENABLED
mov esi,str1 ; print resolving
call debug_print_string
end if
; Resolve Address
call translateData ; Convert domain & DNS IP address
call resolveDomain ; get ip address
if DEBUGGING_STATE = DEBUGGING_ENABLED
mov esi,str3
call debug_print_string
end if
pu_011:
; Done
ret
;***************************************************************************
; Function
; translateData
;
; Description
; Coverts the domain name and DNS IP address typed in by the user into
; a format suitable for the IP layer.
;
; The ename, in query, is converted and stored in dnsMsg
;
;***************************************************************************
translateData:
; first, get the IP address of the DNS server
; Then, build up the request string.
; Build the request string
mov eax,0x00010100
mov [dnsMsg],eax
mov eax,0x00000100
mov [dnsMsg+4],eax
mov eax,0x00000000
mov [dnsMsg+8],eax
; domain name goes in at dnsMsg+12
mov esi,dnsMsg +12 ;location of label length
mov edi,dnsMsg + 13 ;label start
mov edx,proxyAddr
cmp byte [edx],0
jnz td000
mov edx,webAddr
td000:
mov ecx,12 ; total string length so far
td002:
mov [esi],byte 0
inc ecx
td0021:
mov al,[edx]
cmp al,' '
je td001 ; we have finished the string translation
cmp al,0
je td001
cmp al,'.' ; we have finished the label
je td004
inc byte [esi]
inc ecx
mov [edi],al
inc edi
inc edx
jmp td0021
td004:
mov esi,edi
inc edi
inc edx
jmp td002
; write label len + label text
td001:
mov [edi],byte 0
inc ecx
inc edi
mov [edi],dword 0x01000100
add ecx,4
mov [dnsMsgLen],ecx
ret
;***************************************************************************
; Function
; resolveDomain
;
; Description
; Sends a question to the dns server
; works out the IP address from the response from the DNS server
;
;***************************************************************************
resolveDomain:
; Get a free port number
mov ecx,1000 ; local port starting at 1000
getlp:
inc ecx
push ecx
mcall 53,9
pop ecx
cmp eax,0 ; is this local port in use?
jz getlp ; yes - so try next
; Get DNS IP
mcall 52,13
mov esi,eax
; First, open socket
mov edx,53 ; remote port - dns
; mov esi,dword [dns_ip]
xor ebx,ebx ; 0
mcall 53
mov [socketNum],eax
; write to socket ( request DNS lookup )
mcall 53,4,[socketNum],[dnsMsgLen],dnsMsg
; Setup the DNS response buffer
mov eax,dnsMsg
mov [dnsMsgLen],eax
; now, we wait for
; UI redraw
; UI close
; or data from remote
ctr001:
mcall 10 ; wait here for event
cmp eax,1 ; redraw request ?
je ctr003
cmp eax,2 ; key in buffer ?
je ctr004
cmp eax,3 ; button in buffer ?
je ctr005
; Any data in the UDP receive buffer?
mcall 53,2,[socketNum]
cmp eax,0
je ctr001
; we have data - this will be the response
ctr002:
mcall 53,3,[socketNum] ; read byte - block (high byte)
; Store the data in the response buffer
mov eax,[dnsMsgLen]
mov [eax],bl
inc dword [dnsMsgLen]
mcall 53,2,[socketNum] ; any more data?
cmp eax,0
jne ctr002 ; yes, so get it
; close socket
mcall 53,1,[socketNum]
mov [socketNum],dword 0xFFFF
; Now parse the message to get the host IP
; Man, this is complicated. It's described in
; RFC 1035
if DEBUGGING_STATE = DEBUGGING_ENABLED
mov esi,str4
call debug_print_string
end if
; 1) Validate that we have an answer with > 0 responses
; 2) Find the answer record with TYPE 0001 ( host IP )
; 3) Finally, copy the IP address to the display
; Note: The response is in dnsMsg
; The end of the buffer is pointed to by [dnsMsgLen]
; Clear the IP address text
mov [server_ip],dword 0
mov esi,dnsMsg
; Is this a response to my question?
mov al,[esi+2]
and al,0x80
cmp al,0x80
jne ctr002a
; Were there any errors?
mov al,[esi+3]
and al,0x0F
cmp al,0x00
jne ctr002a
; Is there ( at least 1 ) answer?
mov ax,[esi+6]
cmp ax,0x00
je ctr002a
; Header valdated. Scan through and get my answer
if DEBUGGING_STATE = DEBUGGING_ENABLED
pusha
mov esi,str4
call debug_print_string
popa
end if
add esi,12 ; Skip to the question field
; Skip through the question field
call skipName
add esi,4 ; skip past the questions qtype, qclass
ctr002z:
; Now at the answer. There may be several answers,
; find the right one ( TYPE = 0x0001 )
call skipName
mov ax,[esi]
cmp ax,0x0100 ; Is this the IP address answer?
jne ctr002c
; Yes! Point esi to the first byte of the IP address
add esi,10
mov eax,[esi]
mov [server_ip],eax
ret
ctr002c: ; Skip through the answer, move to the next
add esi,8
movzx eax,byte [esi+1]
mov ah,[esi]
add esi,eax
add esi,2
; Have we reached the end of the msg?
; This is an error condition, should not happen
cmp esi,[dnsMsgLen]
jl ctr002z ; Check next answer
jmp ctr002a ; abort
ctr002a:
jmp ctr001
ctr003: ; redraw
call draw_window
jmp ctr001
ctr004: ; key
mcall 2 ; just read it and ignore
jmp ctr001
ctr005: ; button
mcall 17 ; get id
mov dl,ah
; close socket
mcall 53,1,[socketNum]
cmp dl,1
je exit
mov [socketNum],dword 0xFFFF
mov [server_ip],dword 0
ret
;***************************************************************************
; Function
; skipName
;
; Description
; Increment esi to the first byte past the name field
; Names may use compressed labels. Normally do.
; RFC 1035 page 30 gives details
;
;***************************************************************************
skipName:
mov al,[esi]
cmp al,0
je sn_exit
and al,0xc0
cmp al,0xc0
je sn001
movzx eax,byte [esi]
inc eax
add esi,eax
jmp skipName
sn001:
add esi,2 ; A pointer is always at the end
ret
sn_exit:
inc esi
ret
;***************************************************************************
; Function
; load_settings
;
; Description
; Load settings from configuration file network.ini
;
;***************************************************************************
load_settings:
stdcall dll.Load,@IMPORT
test eax,eax
jnz ls001
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
ls001:
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
if DEBUGGING_STATE = DEBUGGING_ENABLED
;****************************************************************************
; Function
; debug_print_string
;
; Description
; prints a string to the debug board, in quotes
;
; esi holds ptr to msg to display, which is space or 0 terminated
;
; Nothing preserved; I'm assuming a pusha/popa is done before calling
;
;****************************************************************************
debug_print_string:
push esi
mov cl,'"'
mcall 63,1
pop esi
dps_000:
mov cl,[esi]
cmp cl,0
je dps_exit
cmp cl,' '
je dps_exit
jmp dps_001
dps_exit:
mov cl,'"'
mcall 63,1
mov cl,13
mcall
mov cl,10
mcall
ret
dps_001:
push esi
mcall 63,1
pop esi
inc esi
jmp dps_000
end if
;****************************************************************************
; Function
; print_text
;
; Description
; display the url (full path) text
;
;****************************************************************************
print_text:
; Draw a bar to blank out previous text
mov ebx,30*65536+URLMAXLEN*6 ; 50 should really be [len] and 103 [xa]
mov ecx,[ya]
shl ecx,16
mov cx,9
mcall 13,,,0xFFFFFF
; write text
mov ebx,30*65536
add ebx,[ya]
xor ecx,ecx
mcall 4,,,[addr],URLMAXLEN
ret
; *********************************************
; ******* WINDOW DEFINITIONS AND DRAW ********
; *********************************************
draw_window:
; function 12: tell os about windowdraw
; 1 start of draw
mcall 12,1
; cmp [params],byte 0
; jz .noret
; <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD>.
; DRAW WINDOW
; eax function 0 : define and draw window
; xor eax,eax
; ebx [x start] *65536 + [x size]
; xor ebx,ebx
; ecx [y start] *65536 + [y size]
; xor ecx,ecx
; edx color of work area RRGGBB,8->color gl
; esi color of bar and flags
; xor esi,esi
; mcall ,,,0x14ffffff,,title
; function 12: tell os about windowdraw
; 2, end of draw
; mcall 12,2
; ret
;.noret:
; DRAW WINDOW
; eax function 0 : define and draw window
xor eax,eax
; ebx [x start] *65536 + [x size]
; ecx [y start] *65536 + [y size]
; edx color of work area RRGGBB,8->color gl
; esi color of bar and flags
xor esi,esi
; edi WINDOW LABEL
mcall ,<50,600>,<350,200>,0x14ffffff,,title
; eax function 4: write text to window
; ebx [x start] *65536 + [y start]
; ecx color of text RRGGBB
; edx pointer to text beginning
; esi max lenght
xor ecx,ecx
mcall 4,<30,38>,,document_user,URLMAXLEN
; xor edx,edx
; mcall 38,<5,545>,<60,60>
; mov ecx,[winys]
; shl ecx,16
; add ecx,[winys]
; sub ecx,26*65536+26
; mcall 38,<5,545>
; RELOAD
; eax function 8 : define and draw button
; ebx [x start] *65536 + [x size]
; ecx [y start] *65536 + [y size]
; edx button id
; esi button color RRGGBB
mcall 8,<388,50>,<34,14>,22,0x5588dd
; URL
mcall ,<10,12>,<34,12>,10
; STOP
mcall ,<443,50>,<34,14>,24
; SAVE
mcall ,<498,50>,,26
; BUTTON TEXT
; eax function 4 : write text to window
; ebx [x start] *65536 + [y start]
; ecx color of text RRGGBB
; edx pointer to text beginning
; esi text length
mcall 4,<390,38>,0xffffff,button_text,30
call display_page
; function 12: tell os about windowdraw
; 2, end of draw
mcall 12,2
ret
;-----------------------------------------------------------------------------
; Data area
;-----------------------------------------------------------------------------
align 4
@IMPORT:
library libini,'libini.obj'
import libini, \
ini.get_str,'ini_get_str', \
ini.get_int,'ini_get_int'
;---------------------------------------------------------------------
fileinfo dd 2,0,0
final_size dd 0
final_buffer dd 0
db '/rd/1/.download',0
body_pos dd 0
;fileinfo_tmp dd 2,0,0
buf_size dd 0
buf_ptr dd 0
; db '/rd/1/1',0
deba dd 0
db 0
;---------------------------------------------------------------------
if DEBUGGING_STATE = DEBUGGING_ENABLED
str1: db "Resolving...",0
str3: db "Resolved",0
str2: db "GotIP",0
str4: db "GotResponse",0
end if
;---------------------------------------------------------------------
button_text db ' RELOAD STOP SAVE '
dpx dd 25 ; x - start of html page in pixels in window
dpy dd 65 ; for y
lastletter db 0
pageyinc dd 0
display_from dd 20
pos dd 0x0
pagex dd 0x0
pagey dd 0x0
pagexs dd 80
command_on_off dd 0x0
text_type db 1
com2 dd 0x0
script dd 0x0
socket dd 0x0
addr dd 0x0
ya dd 0x0
len dd 0x00
title db 'Downloader',0
server_ip: db 207,44,212,20
;dns_ip: db 194,145,128,1
;---------------------------------------------------------------------
;webAddr:
;times URLMAXLEN db ' '
;db 0
;document_user: db 'Click on the button to the left to enter a URL',0
;times URLMAXLEN+document_user-$ db 0
;document: db '/'
;times URLMAXLEN-1 db ' '
;---------------------------------------------------------------------
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/zeroconf.ini',0
sec_proxy:
key_proxy db 'proxy',0
key_proxyport db 'port',0
key_user db 'user',0
key_password db 'password',0
proxyPort dd 80
shared_name dd 0
;yandex: db 'menuetos.net'
;yandex_end:
status dd 0x0
prev_status dd 0x0
onoff dd 0x0
nextupdate: dd 0
winys: dd 400
dnsMsgLen: dd 0
socketNum: dd 0xFFFF
;---------------------------------------------------------------------
document_user: db 'Click on the button to the left to enter a URL',0
;---------------------------------------------------------------------
IM_END:
rb URLMAXLEN-(IM_END - document_user)
;---------------------------------------------------------------------
align 4
document:
rb URLMAXLEN
;---------------------------------------------------------------------
align 4
webAddr:
rb URLMAXLEN+1
;---------------------------------------------------------------------
align 4
primary_buf:
rb primary_buffer_size
;---------------------------------------------------------------------
align 4
params: ; db 1024 dup(0)
rb 1024
;---------------------------------------------------------------------
align 4
request: ; db 256 dup(0)
rb 256
;---------------------------------------------------------------------
align 4
proxyAddr: ; db 256 dup(0)
rb 256
;---------------------------------------------------------------------
align 4
proxyUser: ; db 256 dup(0)
rb 256
;---------------------------------------------------------------------
align 4
proxyPassword: ; db 256 dup(0)
rb 256
;---------------------------------------------------------------------
align 4
dnsMsg:
rb 4096
; rb 0x100000
;---------------------------------------------------------------------
align 4
rb 4096
stacktop:
;---------------------------------------------------------------------
I_END:
;---------------------------------------------------------------------