diff --git a/programs/network/VNCclient/ETH.INC b/programs/network/VNCclient/ETH.INC new file mode 100644 index 0000000000..7b80e8fa93 --- /dev/null +++ b/programs/network/VNCclient/ETH.INC @@ -0,0 +1,671 @@ +; +; ETH.INC +; +; made by hidnplayr (hidnplayr@gmail.com) for KolibriOS +; +; The given code before every macro is only a simple example +; +; +; HISTORY +; +; v1.0: 18 august 2006 original release +; v1.1: december 2006 bugfixes and improvements +; + + +macro mov arg1,arg2 { + if arg1 eq arg2 + else + mov arg1,arg2 + end if +} + +TCB_LISTEN = 1 +TCB_SYN_SENT = 2 +TCB_SYN_RECEIVED = 3 +TCB_ESTABLISHED = 4 +TCB_FIN_WAIT_1 = 5 +TCB_FIN_WAIT_2 = 6 +TCB_CLOSE_WAIT = 7 +TCB_CLOSING = 8 +TCB_LAST_ASK = 9 +TCB_TIME_WAIT = 10 +TCB_CLOSED = 11 + +PASSIVE = 0 +ACTIVE = 1 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; eth.get_IP eax +; +; gets the current IP that is defined in Stack (return in eax in this example) +macro eth.get_IP IP { + mov ebx,1 + mov eax,52 + int 0x40 + + mov IP ,eax +} + +; eth.get_GATEWAY eax +; +; gets the current GATEWAY that is defined in Stack (return in eax in this example) +macro eth.get_GATEWAY GATEWAY { + mov ebx,9 + mov eax,52 + int 0x40 + move GATEWAY ,eax +} + +; eth.get_SUBNET eax +; +; gets the current SUBNET that is defined in Stack (return in eax in this example) +macro eth.get_SUBNET SUBNET { + mov ebx,10 + mov eax,52 + int 0x40 + mov SUBNET ,eax +} + +; eth.get_DNS eax +; +; gets the current DNS that is defined in Stack (return in eax in this example) +macro eth.get_DNS DNS { + mov ebx,13 + mov eax,52 + int 0x40 + mov DNS ,eax +} + +; eth.set_IP eax +; +; set a new IP in stack (input in eax in this example) +macro eth.set_IP IP { + mov ecx,IP + mov ebx,3 + mov eax,52 + int 0x40 +} + +; eth.set_GATEWAY eax +; +; set a new GATEWAY in stack (input in eax in this example) +macro eth.set_GATEWAY GATEWAY { + mov ecx,GATEWAY + mov ebx,11 + mov eax,52 + int 0x40 +} + +; eth.set_SUBNET eax +; +; set a new SUBNET in stack (input in eax in this example) +macro eth.set_SUBNET SUBNET { + mov ecx,SUBNET + mov ebx,12 + mov eax,52 + int 0x40 +} + +; eth.set_DNS eax +; +; set a new DNS in stack (input in eax in this example) +macro eth.set_DNS DNS { + mov ecx,DNS + mov ebx,14 + mov eax,52 + int 0x40 +} + +; eth.open eax,80,ebx,[socket] +; +; open a socket on local port in eax to port 80 on server on ebx +; the socketnumber will be returned in [socket] (dword) +macro eth.open_udp local,remote,ip,socket { + mov ecx, local + mov edx, remote + mov esi, ip + mov ebx, 0 + mov eax, 53 + int 0x40 + + mov socket,eax +} + +; eth.close [socket] +; +; closes socket on socketnumber [socket] +macro eth.close_udp socket { + mov ecx, socket + mov ebx, 1 + mov eax, 53 + int 0x40 +} + +; eth.poll [socket],eax +; +; polls [socket] for data +; eax = 0 when there is data +macro eth.poll socket { + mov ecx, socket + mov ebx, 2 + mov eax, 53 + int 0x40 +} + +; eth.read_byte [socket], bl +; +; reads a byte from the socket and returns in bl +macro eth.read_byte socket, result { + mov ecx, socket + mov ebx, 3 + mov eax, 53 + int 0x40 + + mov result,bl +} + +; eth.read_byte [socket], bl +; +; reads a byte from the socket and returns in bl +macro eth.read_packet socket, result { + mov edx, result + mov ecx, socket + mov ebx, 10 + mov eax, 53 + int 0x40 +} + +; eth.write [socket],12,msg +; msg db 'hello world!' +; +; send message msg to socket +macro eth.write_udp socket,length,msg,verify { + mov ecx, socket + mov edx, length + mov esi, msg + mov ebx, 4 + mov eax, 53 + int 0x40 + + if verify eq 1 + call verifysend + end if + +} + +verifysend: + test eax,eax + jnz @f + ret +@@: + pusha + mov eax,5 + mov ebx,100 + int 0x40 + popa + int 0x40 +ret + +; eth.open_tcp 80,80,eax,0,[socket] +; +; opens a tcp socket on port 80 to port 80 on IP eax with passive open +; returns socket number in eax +macro eth.open_tcp local,remote,ip,passive,socket { + + mov ecx, local + mov edx, remote + mov esi, ip + mov edi, passive ; 0 = PASSIVE open + mov ebx, 5 + mov eax, 53 + int 0x40 + + mov socket,eax +} + +; eth.socket_status [socket],eax +; +; returns socket status in eax +macro eth.socket_status socket,result { + mov ecx, socket + mov ebx, 6 + mov eax, 53 + int 0x40 + + mov result,eax +} + +; eth.write_tcp [socket],12,msg +; +; msg db 'hello world!' +; +; send message to TCP socket +macro eth.write_tcp socket,length,msg,verify { + mov ecx, socket + mov edx, length + mov esi, msg + mov ebx, 7 + mov eax, 53 + int 0x40 + + if verify eq 1 + call verifysend + end if +} + +; eth.close_tcp [socket] +; +; closes tcp socket [socket] +macro eth.close_tcp socket { + mov ecx, socket + mov ebx, 8 + mov eax, 53 + int 0x40 +} + +; eth.check_port 165,eax +; +; checks if port 165 is used +; return is 0 when port is free +macro eth.check_port port,result { + mov ecx, port + mov ebx, 9 + mov eax, 53 + int 0x40 + + mov result,eax +} + +; eth.status eax +; +; returns socket status in eax +macro eth.status status { + mov ebx, 255 + mov ecx, 6 + mov eax, 53 + int 0x40 + + mov status,eax +} + +; eth.search 165,edx +; +; searches a free local port starting from 166 (165 + 1 !) +; returns in edx +macro eth.search_port port,result { + mov edx,port + @@: + inc edx + eth.check_port edx,eax + cmp eax,0 + je @r + mov result,edx +} + + + +; eth.read_data [socket],buffer,512 +; buffer rb 512 +; socket dd ? +; +; reads data from socket into a buffer, stops when there is no more data or buffer is full. +macro eth.read_data socket,dest,endptr,bufferl { +local .getdata,.loop,.end + mov eax, dest + mov endptr, eax + + ; we have data - this will be the response +.getdata: + mov eax,endptr + cmp eax,bufferl + jg .end + + eth.read_byte socket,bl + + ; Store the data in the response buffer + mov eax, endptr + mov [eax], bl + inc dword endptr + + eth.poll socket + + cmp eax,0 + jne .getdata ; yes, so get it + + ; now we are going to wait 30 times 10 ms (300ms) + + mov edx,0 +.loop: + mov eax,5 + mov ebx,1 + int 0x40 + + eth.poll socket + + cmp eax, 0 + jne .getdata ; yes, so get it + + inc edx + cmp edx,100 + jl .loop + +.end: + +} + +; eth.wait_for_data [socket],60,abort +; eth.read_data .... +; abort: +; +; Waits for data with timeout + +macro eth.wait_for_data socket,TIMEOUT,abort { + + mov edx,TIMEOUT + + @@: + eth.poll socket + + cmp eax,0 + jne @f + + dec edx + jz abort + + mov eax,5 ; wait here for event + mov ebx,10 + int 0x40 + + jmp @r + @@: + +} + + +; The function 'resolve' resolves the address in edx and puts the resulting IP in eax. +; When the input is an IP-adress, the function will output this IP in eax. +; If something goes wrong, the result in eax should be 0 +; +; example: +; +; resolve query1,IP,PORT +; resolve '192.168.0.1',IP,PORT +; resolve query2,IP,PORT +; +; query1 db 'www.google.com',0 +; query2 db '49.78.84.45',0 +; IP dd ? +; PORT dd ? + +macro resolve query,result { + +if query eqtype 0 + mov edx,query +else + local ..string, ..label + jmp ..label + ..string db query,0 + ..label: + mov edx,..string +end if + +call __resolve + +mov result,eax + +} + +if used __resolve + +__resolve: + +if __DEBUG__ eq 1 +DEBUGF 1,'Resolving started\n' +end if + + ; This code validates if the query is an IP containing 4 numbers and 3 dots + + + push edx ; push edx (query address) onto stack + xor al, al ; make al (dot count) zero + + @@: + cmp byte[edx],'0' ; check if this byte is a number, if not jump to no_IP + jl no_IP ; + cmp byte[edx],'9' ; + jg no_IP ; + + inc edx ; the byte was a number, so lets check the next byte + + cmp byte[edx],0 ; is this byte zero? (have we reached end of query?) + jz @f ; jump to next @@ then + cmp byte[edx],':' + jz @f + + cmp byte[edx],'.' ; is this byte a dot? + jne @r ; if not, jump to previous @@ + + inc al ; the byte was a dot so increment al(dot count) + inc edx ; next byte + jmp @r ; lets check for numbers again (jump to previous @@) + + @@: ; we reach this when end of query reached + cmp al,3 ; check if there where 3 dots + jnz no_IP ; if not, jump to no_IP (this is where the DNS will take over) + + ; The following code will convert this IP into a dword and output it in eax + ; If there is also a port number specified, this will be returned in ebx, otherwise ebx is -1 + + pop esi ; edx (query address) was pushed onto stack and is now popped in esi + + xor edx, edx ; result + xor eax, eax ; current character + xor ebx, ebx ; current byte + +.outer_loop: + shl edx, 8 + add edx, ebx + xor ebx, ebx +.inner_loop: + lodsb + test eax, eax + jz .finish + cmp al, '.' + jz .outer_loop + sub eax, '0' + imul ebx, 10 + add ebx, eax + jmp .inner_loop +.finish: + shl edx, 8 + add edx, ebx + + bswap edx ; we want little endian order + mov eax, edx + + ret + + +no_IP: + + pop edx + + ; The query is not an IP address, we will send the query to a DNS server and hope for answer ;) +if __DEBUG__ eq 1 + DEBUGF 1,'The query is no ip, Building request string from:%u\n',edx +end if + + ; 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 ecx, 12 ; total string length so far + +td002: + mov [esi], byte 0 + inc ecx + +td0021: + mov al, [edx] + + cmp al, 0 + je td001 ; we have finished the string translation + + cmp al, '.' + je td004 ; we have finished the label + + 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 ; We'll need the length of the message when we send it + ; Now, lets send this and wait for an answer + + eth.search_port 1024,edx ; Find a free port starting from 1025 and store in edx + eth.get_DNS esi ; Read DNS IP from stack into esi + eth.open_udp edx,53,esi,[socketNum] ; First, open socket +if __DEBUG__ eq 1 + DEBUGF 1,'Socket opened: %u (port %u)\n',[socketNum],ecx +end if + eth.write_udp [socketNum],[dnsMsgLen],dnsMsg ; Write to socket ( request DNS lookup ) +if __DEBUG__ eq 1 + DEBUGF 1,'Data written, length:%u offset:%u\n',[dnsMsgLen],dnsMsg + DEBUGF 1,'Waiting for data: (timeout is %us)\n',TIMEOUT +end if + eth.wait_for_data [socketNum],TIMEOUT,abort ; Now, we wait for data from remote + eth.read_data [socketNum],dnsMsg,[dnsMsgLen],dnsMsg+BUFFER ; Read the data into the buffer +if __DEBUG__ eq 1 + DEBUGF 1,'Data received, offset:%u buffer size:%u length:%u\n',dnsMsg,BUFFER,esi-dnsMsg +end if + eth.close_udp [socketNum] ; We're done, close the socket +if __DEBUG__ eq 1 + DEBUGF 1,'Closed Socket\n' +end if + + ; Now parse the message to get the host IP. Man, this is complicated. It's described in RFC 1035 + ; 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] + + mov esi, dnsMsg + + mov al, [esi+2] ; Is this a response to my question? + and al, 0x80 + cmp al, 0x80 + jne abort +if __DEBUG__ eq 1 + DEBUGF 1,'It was a response to my question\n' +end if + + mov al, [esi+3] ; Were there any errors? + and al, 0x0F + cmp al, 0x00 + jne abort + +if __DEBUG__ eq 1 + DEBUGF 1,'There were no errors\n' +end if + + mov ax, [esi+6] ; Is there ( at least 1 ) answer? + cmp ax, 0x00 + je abort + + ; Header validated. Scan through and get my answer + add esi, 12 ; Skip to the question field + call skipName ; Skip through the question field + 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 + add esi, 10 ; Yes! Point eax to the first byte of the IP address + mov eax,[esi] + + 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 + + cmp esi, [dnsMsgLen] ; Have we reached the end of the msg? This is an error condition, should not happen + jl ctr002z ; Check next answer + +abort: +if __DEBUG__ eq 1 + DEBUGF 1,'Something went wrong, aborting\n' +end if + xor eax,eax + + ret + + +skipName: + ; Increment esi to the first byte past the name field + ; Names may use compressed labels. Normally do. + ; RFC 1035 page 30 gives details + 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 + +dnsMsgLen: dd 0 +socketNum: dd 0xFFFF + +if ~defined dnsMsg +dnsMsg: rb BUFFER +end if + +end if + + + + diff --git a/programs/network/VNCclient/copyrect.inc b/programs/network/VNCclient/copyrect.inc new file mode 100644 index 0000000000..d24878b3c6 --- /dev/null +++ b/programs/network/VNCclient/copyrect.inc @@ -0,0 +1,5 @@ + encoding_copyrect: + DEBUGF 1,'FRAME: copyrect\n' + + + jmp next_rectangle \ No newline at end of file diff --git a/programs/network/VNCclient/fdo.inc b/programs/network/VNCclient/fdo.inc new file mode 100644 index 0000000000..bd160a155e --- /dev/null +++ b/programs/network/VNCclient/fdo.inc @@ -0,0 +1,343 @@ +; +; Formatted Debug Output (FDO) +; Copyright (c) 2005-2006, mike.dld +; Created: 2005-01-29, Changed: 2006-07-20 +; +; For questions and bug reports, mail to mike.dld@gmail.com +; +; Available format specifiers are: %s, %d, %u, %x (with partial width support) +; + +; to be defined: +; __DEBUG__ equ 1 +; __DEBUG_LEVEL__ equ 5 + +macro debug_func name { + if used name + name@of@func equ name +} + +macro debug_beginf { + align 4 + name@of@func: +} + +debug_endf fix end if + +macro DEBUGS _sign,[_str] { + common + pushf + pushad + local ..str,..label,is_str + is_str = 0 + forward + if _str eqtype '' + is_str = 1 + end if + common + if is_str = 1 + jmp ..label + ..str db _str,0 + ..label: + add esp,4*8+4 + mov edx,..str + sub esp,4*8+4 + call fdo_debug_outstr + else + mov edx,_str + call fdo_debug_outstr + end if + popad + popf +} + +macro DEBUGD _sign,_dec { + pushf + pushad + if _dec eqtype eax + if _dec in + mov eax,_dec + else if ~_dec eq eax + if _sign = 1 + movsx eax,_dec + else + movzx eax,_dec + end if + end if + else if _dec eqtype 0 + mov eax,_dec + else + add esp,4*8+4 + local tp + tp equ 0 + match _num[_arg],_dec \{ + if _num = 1 + if _sign = 1 + movsx eax,byte[_arg] + else + movzx eax,byte[_arg] + end if + else if _num = 2 + if _sign = 1 + movsx eax,word[_arg] + else + movzx eax,word[_arg] + end if + else + mov eax,dword[_arg] + end if + tp equ 1 + \} + match =0 [_arg],tp _dec \{ + mov eax,dword[_arg] + \} + sub esp,4*8+4 + end if + mov cl,_sign + call fdo_debug_outdec + popad + popf +} + +macro DEBUGH _sign,_hex { + pushf + pushad + if _hex eqtype eax + if _hex in + if ~_hex eq eax + mov eax,_hex + end if + mov edx,8 + else if _hex in + if ~_hex eq ax + movzx eax,_hex + end if + shl eax,16 + mov edx,4 + else if _hex in + if ~_hex eq al + movzx eax,_hex + end if + shl eax,24 + mov edx,2 + end if + else if _hex eqtype 0 + mov eax,_hex + mov edx,8 + else + add esp,4*8+4 + local tp + tp equ 0 + match _num[_arg],_hex \{ + mov eax,dword[_arg] + mov edx,_num + tp equ 1 + \} + match =0 [_arg],tp _hex \{ + mov eax,dword[_arg] + mov edx,8 + \} + sub esp,4*8+4 + end if + call fdo_debug_outhex + popad + popf +} + +;----------------------------------------------------------------------------- + +debug_func fdo_debug_outchar +debug_beginf + pushad + mov cl,al + mov ebx,1 + mov eax,63 + int 0x40 + popad + ret +debug_endf + +debug_func fdo_debug_outstr +debug_beginf + mov eax,63 + mov ebx,1 + .l1: mov cl,[edx] + or cl,cl + jz .l2 + int 0x40 + inc edx + jmp .l1 + .l2: ret +debug_endf + +debug_func fdo_debug_outdec +debug_beginf + or cl,cl + jz @f + or eax,eax + jns @f + neg eax + push eax + mov al,'-' + call fdo_debug_outchar + pop eax + @@: push 10 + pop ecx + push -'0' + .l1: xor edx,edx + div ecx + push edx + test eax,eax + jnz .l1 + .l2: pop eax + add al,'0' + jz .l3 + call fdo_debug_outchar + jmp .l2 + .l3: ret +debug_endf + +debug_func fdo_debug_outhex + __fdo_hexdigits db '0123456789ABCDEF' +debug_beginf + mov cl,dl + neg cl + add cl,8 + shl cl,2 + rol eax,cl + .l1: rol eax,4 + push eax + and eax,0x0000000F + mov al,[__fdo_hexdigits+eax] + call fdo_debug_outchar + pop eax + dec edx + jnz .l1 + ret +debug_endf + +;----------------------------------------------------------------------------- + +macro DEBUGF _level,_format,[_arg] { + common + if __DEBUG__ = 1 & _level >= __DEBUG_LEVEL__ + local ..f1,f2,a1,a2,c1,c2,c3,..lbl + _debug_str_ equ __debug_str_ # a1 + a1 = 0 + c2 = 0 + c3 = 0 + f2 = 0 + repeat ..lbl-..f1 + virtual at 0 + db _format,0,0 + load c1 word from %-1 + end virtual + if c1 = '%s' + virtual at 0 + db _format,0,0 + store word 0 at %-1 + load c1 from f2-c2 + end virtual + if c1 <> 0 + DEBUGS 0,_debug_str_+f2-c2 + end if + c2 = c2 + 1 + f2 = %+1 + DEBUGF_HELPER S,a1,0,_arg + else if c1 = '%x' + virtual at 0 + db _format,0,0 + store word 0 at %-1 + load c1 from f2-c2 + end virtual + if c1 <> 0 + DEBUGS 0,_debug_str_+f2-c2 + end if + c2 = c2 + 1 + f2 = %+1 + DEBUGF_HELPER H,a1,0,_arg + else if c1 = '%d' | c1 = '%u' + local c4 + if c1 = '%d' + c4 = 1 + else + c4 = 0 + end if + virtual at 0 + db _format,0,0 + store word 0 at %-1 + load c1 from f2-c2 + end virtual + if c1 <> 0 + DEBUGS 0,_debug_str_+f2-c2 + end if + c2 = c2 + 1 + f2 = %+1 + DEBUGF_HELPER D,a1,c4,_arg + else if c1 = '\n' + c3 = c3 + 1 + end if + end repeat + virtual at 0 + db _format,0,0 + load c1 from f2-c2 + end virtual + if (c1<>0)&(f2<>..lbl-..f1-1) + DEBUGS 0,_debug_str_+f2-c2 + end if + virtual at 0 + ..f1 db _format,0 + ..lbl: + __debug_strings equ __debug_strings,_debug_str_,<_format>,..lbl-..f1-1-c2-c3 + end virtual + end if +} + +macro __include_debug_strings dummy,[_id,_fmt,_len] { + common + local c1,a1,a2 + forward + if defined _len & ~_len eq + _id: + a1 = 0 + a2 = 0 + repeat _len + virtual at 0 + db _fmt,0,0 + load c1 word from %+a2-1 + end virtual + if (c1='%s')|(c1='%x')|(c1='%d')|(c1='%u') + db 0 + a2 = a2 + 1 + else if (c1='\n') + dw $0A0D + a1 = a1 + 1 + a2 = a2 + 1 + else + db c1 and 0x0FF + end if + end repeat + db 0 + end if +} + +macro DEBUGF_HELPER _letter,_num,_sign,[_arg] { + common + local num + num = 0 + forward + if num = _num + DEBUG#_letter _sign,_arg + end if + num = num+1 + common + _num = _num+1 +} + +macro include_debug_strings { + if __DEBUG__ = 1 + match dbg_str,__debug_strings \{ + __include_debug_strings dbg_str + \} + end if +} diff --git a/programs/network/VNCclient/logon.inc b/programs/network/VNCclient/logon.inc new file mode 100644 index 0000000000..a6edd9024b --- /dev/null +++ b/programs/network/VNCclient/logon.inc @@ -0,0 +1,263 @@ +red_logon: + call draw_window_logon ; at first, draw the window + +still_logon: ; main cycle of application begins here + mov eax,10 ; wait here for event + int 0x40 + +checkevent_logon: ; Check what event was called _logon: this will be used to return from textbox focus + + dec eax ; redraw request ? + jz red_logon + dec eax ; key in buffer ? + jz key_logon + dec eax ; button in buffer ? + jz button_logon + + jmp still_logon + + key_logon: ; key event handler + mov al,2 ; eax was zero so will now be 2 + int 0x40 ; just read it and ignore + + cmp ah,13 + jne still_logon ; return to main loop + + ret ; enter key was pressed => return to logon + + button_logon: ; eax was zero so will now be 17 + mov al,17 ; get id + int 0x40 + + cmp ah,1 ; close ? + jz close_logon + cmp ah,2 ; logon ? + je connect_logon + cmp ah,5 ; first ? + jz dstbtn_logon + + srcbtn_logon: + mov dword[addr],first + jmp rk_logon + + dstbtn_logon: + mov dword[addr],second + + rk_logon: + mov edi,[addr] ; load the address of the string + xor al,al ; mov al,0 ; the symbol we will search for + mov ecx,STRLEN+1 ; length of the string (+1) + cld ; search forward + repne scasb ; do search now + inc ecx ; we've found a zero or ecx became 0 + mov eax,STRLEN+1 + sub eax,ecx ; eax = address of <0> character + mov [temp],eax ; position + + cmp dword[addr],dword second + jne @f + mov dword [passlen],eax + @@: + + call print_text_logon + + mov edi,[addr] ; address of string + add edi,[temp] ; cursor position + + .waitev_logon: + mov eax,10 ; wait for event + int 0x40 + cmp eax,2 ; button presed ? + jne checkevent_logon ; a key is pressed or redraw is nessesary, goto checkevent + int 0x40 ; eax = 2, read button + shr eax,8 + cmp eax,8 + jnz .nobs_logon ; BACKSPACE + cmp edi,[addr] + jz .waitev_logon + dec edi + mov byte[edi],0 + + cmp dword[addr],second + jne @f + dec [passlen] + @@: + + call print_text_logon + jmp .waitev_logon + .nobs_logon: + cmp eax,13 ; ENTER + je still_logon + cmp eax,192 + jne .noclear_logon + xor al,al + mov edi,[addr] + mov ecx,STRLEN + rep stosb + mov edi,[addr] + call print_text_logon + jmp .waitev_logon + + .noclear_logon: + mov [edi],al + + cmp dword[addr],second + jne @f + inc [passlen] + @@: + + call print_text_logon + + inc edi + mov esi,[addr] + add esi,STRLEN + cmp esi,edi + jnz .waitev_logon + + jmp still_logon + + +; print strings (source & destination) +print_text_logon: +pusha + + mov eax, 8 + mov ebx, 105*65536+200 + mov ecx, 33*65536+12 + mov edx, 4 + mov esi, 0xEBEBEB + int 0x40 + + cmp byte[mode],0 + je @f + + mov ecx, 49*65536+12 + inc edx + int 0x40 + + @@: + mov eax, 4 ; function 4 _logon: write text to window + mov ebx, 107*65536+34 ; [x start] *65536 + [y start] + xor ecx, ecx ; color of text RRGGBB + mov edx, first ; pointer to text beginning + mov esi, STRLEN ; text length + int 0x40 + + cmp byte[mode],0 + je dont_draw_pass + + add ebx,16 + mov edi,[passlen] + + @@: + cmp edi,0 + jle dont_draw_pass + + dec edi + mov edx, passchar + mov esi, 1 + int 0x40 + add ebx,6*65536 + jmp @r + + dont_draw_pass: + +popa + ret + +close_logon: + mov eax,-1 + int 0x40 + +connect_logon: + ret + +draw_window_logon: + + mov eax, 12 ; function 12_logon:tell os about windowdraw + mov ebx, 1 ; 1, start of draw + int 0x40 + pusha + ; DRAW WINDOW + xor eax, eax ; function 0 _logon: define and draw window + mov ebx, 160*65536+330 ; [x start] *65536 + [x size] + mov ecx, 160*65536+100 ; [y start] *65536 + [y size] + mov edx, 0x03DDDDDD ; color of work area RRGGBB + int 0x40 + + mov eax, 8 ; LOGON BUTTON + mov ebx, 220*65536+85 + mov ecx, 63*65536+16 + mov edx, 2 + mov esi, 0xCCCCCC + int 0x40 + + call print_text_logon + ; WINDOW LABEL + mov eax, 4 ; function 4 _logon: write text to window + mov ebx, 8*65536+8 ; [x start] *65536 + [y start] + mov ecx, 0x10ffffff ; color of text RRGGBB + mov edx, labelt ; pointer to text beginning + mov esi, labellen-labelt ; text length + int 0x40 + + cmp byte[mode],0 + je servermode_ + + mov ebx, 25*65536+33 ; [x start] *65536 + [y start] + xor ecx, ecx + mov edx, userstr ; pointer to text beginning + mov esi, passstr-userstr ; text length + int 0x40 + + add bl,16 + mov edx, passstr ; pointer to text beginning + mov esi, connect-passstr ; text length + int 0x40 + + jmp drawtherest_ + + servermode_: + + mov ebx, 25*65536+33 ; [x start] *65536 + [y start] + xor ecx, ecx + mov edx, serverstr ; pointer to text beginning + mov esi, userstr-serverstr ; text length + int 0x40 + + drawtherest_: + + mov ebx, 240*65536+67 ; [x start] *65536 + [y start] + mov edx, connect ; pointer to text beginning + mov esi, connect_e-connect ; text length + int 0x40 + + popa + inc ebx + int 0x40 + + ret + + +; DATA AREA +labelt: db 'Kolibrios VNC client by HIDNPLAYR' +labellen: + +first: db '192.168.1.5' + rb STRLEN +second: rb STRLEN + +passchar db '*' +passlen dd 0 + +addr dd 0 +temp dd 0 +mode db 0 ; 0 = connection details, 1 = authentication + +serverstr: db 'server:' +userstr: db 'username:' +passstr: db 'password:' +connect: db 'connect !' +connect_e: + +I_END_logon: diff --git a/programs/network/VNCclient/raw.inc b/programs/network/VNCclient/raw.inc new file mode 100644 index 0000000000..0744261be3 --- /dev/null +++ b/programs/network/VNCclient/raw.inc @@ -0,0 +1,145 @@ + encoding_raw: + DEBUGF 1,'FRAME: RAW\n' + + mov ax,[screen.width] ; + mov bx,[frame.y] ; + mul bx ; + DEBUGF 1,'screen.width*frame.y=%u\n',ax + mov bx,3 ; + mul bx ; + shl edx,16 ; + mov dx,ax ; + mov ebx,edx ; mov ebx,[screen.width]*[frame.y]*3 + push ebx + DEBUGF 1,'screen.width*frame.y*3=%u\n',edx + mov ax,[frame.x] ; + mov bx,3 ; + mul bx ; + shl edx,16 ; + mov dx,ax ; + pop ebx + add ebx,edx ; add ebx,[frame.x]*3 + add ebx,framebuffer_data ; add ebx,framebuffer_data + push ebx + DEBUGF 1,'frame.x*3=%u\n',edx + + mov ax,[frame.width] ; + mov bx,3 ; + mul bx ; + shl edx,16 ; + mov dx,ax ; + DEBUGF 1,'frame.width*3=%u\n',edx + pop ebx + add edx,ebx ; mov edx,ebx+[frame.width]*3 + + push ebx + push edx ; + mov ax,[frame.height] ; + mov bx,3 ; + mul bx ; + mov bx,[screen.width] ; + mul bx ; + shl edx,16 ; + mov dx,ax ; + mov ecx,edx ; + pop edx ; + DEBUGF 1,'frame.height*screen.width*3=%u\n',ecx + add ecx,edx ; mov ecx,edx+[frame.height]*[screen.width]*3 + pop ebx + + DEBUGF 1,'FRAME: framebuffer:%u ebx:%u ecx:%u edx:%u\n',framebuffer_data,ebx,ecx,edx + + .pixelloop32: + cmp ebx,ecx + jge next_rectangle + + add esi,2 ; 32 bit code RAW + mov al,[esi] ; + mov [ebx],al ; + inc ebx ; + dec esi ; + ; + mov al,[esi] ; + mov [ebx],al ; + inc ebx ; + dec esi ; + ; + mov al,[esi] ; + mov [ebx],al ; + inc ebx ; + add esi,4 ; + +; mov ax,[esi] ; 16 bit code RAW +; and ax,32 +; mov [ebx],al +; inc ebx +; +; mov ax,[esi] +; shr ax,5 +; and ax,32 +; mov [ebx],al +; inc ebx +; +; mov ax,[esi] +; shr ax,10 +; and ax,64 +; mov [ebx],al +; inc ebx +; inc esi +; inc esi + + +; mov al,[esi] ; 8 bit code RAW +; and al,7 ; +; mov byte[ebx],0xff;al ; +; inc ebx ; +; ; +; mov al,[esi] ; +; shr al,3 ; +; and al,7 ; +; mov [ebx],al ; +; inc ebx ; +; ; +; mov al,[esi] ; +; shr al,6 ; +; and al,3 ; +; mov [ebx],al ; +; inc ebx ; +; ; +; inc esi ; + + + cmp ebx,edx + jl .pixelloop32 + + push edx + push ebx + mov ax,[screen.width] + mov bx,3 + mul bx + shl edx,16 + mov dx,ax + mov eax,edx + pop ebx + pop edx + + add ebx,eax ; eax = [screen.width]*3 + add edx,eax + + push edx + push ebx + mov ax,[frame.width] + mov bx,3 + mul bx + shl edx,16 + mov dx,ax + mov eax,edx + pop ebx + pop edx + + sub ebx,eax ; eax = [frame.width]*3 + + jmp .pixelloop32 + + + diff --git a/programs/network/VNCclient/vnc.asm b/programs/network/VNCclient/vnc.asm new file mode 100644 index 0000000000..11e542a818 --- /dev/null +++ b/programs/network/VNCclient/vnc.asm @@ -0,0 +1,508 @@ +; +; +; VNC Client for kolibrios by hidnplayr +; +; +; WORK IN PROGRESS... +; +; FEEL FREE TO CONTRIBUTE ! +; +; hidnplayr@gmail.com +; + +use32 + + org 0x0 + + db 'MENUET00' ; 8 byte id + dd 38 ; required os + dd START ; program start + dd I_END ; program image size + dd IM_END ; required amount of memory + dd 0 ; reserved=no extended header + +__DEBUG__ equ 1 +__DEBUG_LEVEL__ equ 1 +STRLEN = 64 +xpos = 4 +ypos = 22 + +TIMEOUT = 60 ; timeout in seconds +BUFFER = 512 ; Buffer size for DNS + +include 'fdo.inc' +include 'ETH.INC' +include 'logon.inc' +include 'raw.inc' +include 'copyrect.inc' + + +START: ; start of execution + call red_logon + + mov eax,40 ; Report events + mov ebx,10000000b ; Only Stack + int 0x40 + + mov eax,67 ; resize the window (hide it) + xor ebx,ebx + mov ecx,ebx + mov edx,ebx + mov esi,ebx + int 0x40 + + resolve first,[server_ip] ; the input window putted the server @ 'first', resolve it into a real ip + mov [server_port],5900 ; no port input for now, only standard port 5900 + + DEBUGF 1,'connecting to %u.%u.%u.%u:%u\n',1[server_ip],1[server_ip+1],1[server_ip+2],1[server_ip+3],4[server_port] + eth.search_port 1000,edx ; Find a free port starting from 1001 and store in edx + eth.open_tcp edx,[server_port],[server_ip],1,[socket] ; open socket + DEBUGF 1,'Socket opened: %u (port %u)\n',[socket],ecx + + call read_data + cmp dword[receive_buffer+1],'RFB ' + jne no_rfb + eth.write_tcp [socket],12,handshake + DEBUGF 1,'Sending handshake: protocol version\n' + + call read_data + mov eax,receive_buffer+1 + mov eax,[eax] + bswap eax + cmp eax,0 + je invalid_security + cmp eax,1 + je no_security + cmp eax,2 + je vnc_security + + jmp close + + vnc_security: + mov byte[mode],1 + call red_logon + + no_security: + eth.write_tcp [socket],1,shared + DEBUGF 1,'Sending handshake: shared session?\n' + + eth.wait_for_data [socket],TIMEOUT*10,close + eth.read_data [socket],framebuffer,[datapointer],IM_END-receive_buffer ; now the server should send init message + DEBUGF 1,'Serverinit: bpp:%u depth:%u bigendian:%u truecolor:%u\n',1[pixelformat.bpp],1[pixelformat.depth],1[pixelformat.big_endian],1[pixelformat.true_color] + mov eax,dword[framebuffer] + bswap eax + mov dword[screen],eax + + eth.write_tcp [socket],20,pixel_format32 + DEBUGF 1,'Sending pixel format\n' + call read_data + +; eth.write_tcp [socket],8,encodings +; DEBUGF 1,'Sending encoding info\n' +; call read_data + + mov eax,dword[framebuffer.width] + mov dword[fbur.width],eax + + mov eax,40 ; report events + mov ebx,10100111b ; stack, mouse, button, key, redraw + int 0x40 + + mov eax,67 ; resize the window + mov ebx,10 + mov ecx,10 + mov edx,dword[framebuffer] + bswap edx + movzx esi,dx + shr edx,16 + add edx,2*xpos + add esi,ypos+xpos + int 0x40 + +; mov byte[fbur.inc],0 ; request a framebufferupdate +; eth.write_tcp [socket],10,fbur + + mainloop: + eth.socket_status [socket],eax + cmp al,TCB_CLOSE_WAIT + je close + + mov eax,23 ; wait for event with timeout + mov ebx,50 ; 0,5 s + int 0x40 + + cmp eax,1 ; redraw + je redraw + cmp eax,2 ; key + je key + cmp eax,3 ; button + je button + cmp eax,6 ; mouse + je mouse + cmp eax,8 + je network + + ; request an FRB update + jmp mainloop + + + network: + call read_data ; Read the data into the buffer + + mov eax,[datapointer] ; at least 2 bytes should be received + sub eax,receive_buffer + cmp eax,1 + jle mainloop + + DEBUGF 1,'Data received, %u bytes\n',eax + + cmp byte[receive_buffer],0 + je framebufferupdate + + cmp byte[receive_buffer],1 + je setcolourmapentries + + cmp byte[receive_buffer],2 + je bell + + cmp byte[receive_buffer],3 + je servercuttext + + jmp mainloop + + + framebufferupdate: + DEBUGF 1,'Framebufferupdate!\n' + mov di,word[receive_buffer+2] + bswap edi + shr edi,16 + mov esi,receive_buffer+4 + + rectangle_loop: + mov edx,[esi] + bswap edx + mov ebx,edx + shr edx,16 + mov [frame.x],dx + mov [frame.y],bx + add esi,4 + mov ecx,[esi] + bswap ecx + mov eax,ecx + shr ecx,16 + mov [frame.width],cx + mov [frame.height],ax + add esi,4 + mov eax,[esi] + add esi,4 + + DEBUGF 1,'screen: width=%u height=%u\nframe: width=%u height=%u x=%u y=%u\n',2[screen.width],2[screen.height],2[frame.width],2[frame.height],2[frame.x],2[frame.y] + + cmp eax,0 + je encoding_raw + + cmp eax,1 + je encoding_copyrect + + cmp eax,2 + je encoding_RRE + + cmp eax,5 + je encoding_hextile + + cmp eax,16 + je encoding_ZRLE + + DEBUGF 1,'FRAME: unknown encoding\n' + jmp mainloop + + next_rectangle: + dec di + pusha + call drawbuffer + popa + cmp di,0 + jg rectangle_loop + jmp mainloop + + encoding_RRE: + DEBUGF 1,'FRAME: RRE\n' + + jmp next_rectangle + + encoding_hextile: + DEBUGF 1,'FRAME: hextile\n' + + jmp next_rectangle + + encoding_ZRLE: + DEBUGF 1,'FRAME: ZRLE\n' + + jmp next_rectangle + + + setcolourmapentries: + + DEBUGF 1,'Server sended an SetColourMapEntries message\n' + + jmp mainloop + + + bell: + mov eax,55 + mov ebx,eax + mov esi,beep + int 0x40 + + jmp mainloop + + + servercuttext: + + jmp mainloop + + + key: + DEBUGF 1,'Sending key event\n' + + mov eax,2 + int 0x40 + mov byte[keyevent.key+3],ah + +; eth.write_tcp [socket],8,keyevent + + cmp ah,13 + jne @f + + mov byte[fbur.inc],1 + eth.write_tcp [socket],10,fbur + jmp mainloop + @@: + + cmp ah,30 + jne @f + + mov byte[fbur.inc],12 + eth.write_tcp [socket],10,fbur + jmp mainloop + @@: + + mov byte[fbur.inc],0 + eth.write_tcp [socket],10,fbur + + jmp mainloop + + mouse: + DEBUGF 1,'Sending mouse event\n' + + mov eax,37 + mov ebx,1 + int 0x40 + + sub eax,xpos*65536+ypos + bswap eax + mov word[pointerevent.x],ax + shr eax,16 + mov word[pointerevent.y],ax + + mov eax,37 + mov ebx,2 + int 0x40 + + cmp al,2 + jne @f ; in kolibri right click is 2 (decimal), in RFB protocol it is bit 2 (counting from 0) + mov al,100b + @@: + + mov byte[pointerevent.mask],al + + eth.write_tcp [socket],6,pointerevent + + jmp mainloop + + redraw: + + DEBUGF 1,'Drawing window\n' + + mov eax,12 + mov ebx,1 + int 0x40 + + mov eax,0 ; draw window + mov ebx,dword[framebuffer] + bswap ebx + movzx ecx,bx + shr ebx,16 + add ebx,2*xpos + add ecx,ypos+xpos + mov edx,0x03ffffff + mov esi,0x80555599 + mov edi,0x00ffffff + int 0x40 + + mov eax,4 ; label + mov ebx,9*65536+8 + mov ecx,0x10ffffff + mov edx,name + mov esi,[name_length] + bswap esi + int 0x40 + + call drawbuffer + + mov eax,12 + mov ebx,2 + int 0x40 + + jmp mainloop + + drawbuffer: + + mov eax,7 + mov ebx,framebuffer_data + mov ecx,dword[screen] + mov edx,xpos*65536+ypos + int 0x40 + + ret + + + button: ; button + mov eax,17 ; get id + int 0x40 + + close: + call read_data +; eth.close_tcp [socket] ; We're done, close the socket ;;; BUG WHEN CLOSING SCOKET !! + DEBUGF 1,'Socket closed\n' + + mov eax,-1 + int 0x40 + + no_rfb: + DEBUGF 1,'This is no vnc server!\n' + jmp close + + invalid_security: + DEBUGF 1,'Security error: %s\n',receive_buffer+5 + jmp close + +read_data: + eth.read_data [socket],receive_buffer,[datapointer],IM_END-receive_buffer +ret + +; DATA AREA + +include_debug_strings ; ALWAYS present in data section + +handshake db 'RFB 003.003',0x0a +shared db 0 +beep db 0x85,0x25,0x85,0x40,0 + +pixel_format32 db 0 ; setPixelformat + rb 3 ; padding +.bpp db 32 ; bits per pixel +.depth db 32 ; depth +.big_endian db 0 ; big-endian flag +.true_color db 1 ; true-colour flag +.red_max db 0,255 ; red-max +.green_max db 0,255 ; green-max +.blue_max db 0,255 ; blue-max +.red_shif db 0 ; red-shift +.green_shift db 8 ; green-shift +.blue_shift db 16 ; blue-shift + rb 3 ; padding + +pixel_format16 db 0 ; setPixelformat + rb 3 ; padding +.bpp db 16 ; bits per pixel +.depth db 16 ; depth +.big_endian db 0 ; big-endian flag +.true_color db 1 ; true-colour flag +.red_max db 0,32 ; red-max +.green_max db 0,32 ; green-max +.blue_max db 0,64 ; blue-max +.red_shif db 0 ; red-shift +.green_shift db 5 ; green-shift +.blue_shift db 10 ; blue-shift + rb 3 ; padding + +pixel_format8 db 0 ; setPixelformat + rb 3 ; padding +.bpp db 8 ; bits per pixel +.depth db 8 ; depth +.big_endian db 0 ; big-endian flag +.true_color db 1 ; true-colour flag +.red_max db 0,7 ; red-max +.green_max db 0,7 ; green-max +.blue_max db 0,3 ; blue-max +.red_shif db 0 ; red-shift +.green_shift db 3 ; green-shift +.blue_shift db 6 ; blue-shift + rb 3 ; padding + +encodings db 2 ; setEncodings + rb 1 ; padding + db 1,0 ; number of encodings + db 0,0,0,0 ; raw encoding (DWORD, Big endian order) + db 1,0,0,0 ; Copyrect encoding + +fbur db 3 ; frame buffer update request +.inc db 0 ; incremental +.x dw 0 +.y dw 0 +.width dw 0 +.height dw 0 + +keyevent db 4 ; keyevent +.down db 0 ; down-flag + dw 0 ; padding +.key dd 0 ; key + +pointerevent db 5 ; pointerevent +.mask db 0 ; button-mask +.x dw 0 ; x-position +.y dw 0 ; y-position + +I_END: + +framebuffer: +.width dw ? +.height dw ? +pixelformat: +.bpp db ? +.depth db ? +.big_endian db ? +.true_color db ? +.red_max dw ? +.green_max dw ? +.blue_max dw ? +.red_shift db ? +.green_shift db ? +.blue_shift db ? +.padding rb 3 +name_length dd ? +name rb 256 + +server_ip dd 0 +server_port dd 0 +socket dd 0 +datapointer dd 0 + +frame: +.width dw 0 +.height dw 0 +.x dw 0 +.y dw 0 + +screen: +.height dw 0 +.width dw 0 + +dnsMsg: +receive_buffer rb 5*1024*1024 ; 5 mb buffer for received data (incoming frbupdate etc) +framebuffer_data rb 1024*768*3 ; framebuffer + +IM_END: + +