;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; Copyright (C) KolibriOS team 2010-2015. All rights reserved. ;; ;; Distributed under terms of the GNU General Public License ;; ;; ;; ;; VNC client for KolibriOS ;; ;; ;; ;; Written by hidnplayr@kolibrios.org ;; ;; ;; ;; GNU GENERAL PUBLIC LICENSE ;; ;; Version 2, June 1991 ;; ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; format binary as "" __DEBUG__ = 1 __DEBUG_LEVEL__ = 2 BITS_PER_PIXEL = 32 ; 8, 16, 24 or 32 SERVERADDRLEN = 4096 use32 org 0x0 db "MENUET01" ; 8 byte id dd 0x01 ; header version dd START ; start of code dd I_END ; size of image dd IM_END ; memory for app dd IM_END ; esp dd serveraddr, 0x0 ; I_Param , I_Path include "../../macros.inc" include "../../debug-fdo.inc" include "../../proc32.inc" include "../../dll.inc" include "../../struct.inc" include "../../develop/libraries/box_lib/trunk/box_lib.mac" include "../../network.inc" struct 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 ends struct ServerInit width dw ? height dw ? pixelformat PixelFormat name_length dd ? name db ? ends xpos = 4 ypos = 21 TIMEOUT = 5 ; timeout in seconds RECEIVE_BUFFER_SIZE = 8*1024*1024 ; 8 Mib STATUS_CONNECT = 0 STATUS_CONNECTING = 1 STATUS_REQ_LOGIN = 2 STATUS_LOGIN = 3 STATUS_CONNECTED = 4 STATUS_CLOSED = 5 STATUS_DISCONNECTED = 10 STATUS_DNS_ERR = 11 STATUS_SOCK_ERR = 12 STATUS_CONNECT_ERR = 13 STATUS_PROTO_ERR = 14 STATUS_SECURITY_ERR = 15 STATUS_LIB_ERR = 16 STATUS_THREAD_ERR = 17 STATUS_LOGIN_FAILED = 18 STATUS_SECURITY_ERR_C = 19 WORK_FRAMEBUFFER = 1 shl 0 WORK_CURSOR = 1 shl 1 WORK_GUI = 1 shl 2 BYTES_PER_PIXEL = (BITS_PER_PIXEL + 7) / 8 if BITS_PER_PIXEL = 32 BYTES_PER_CPIXEL= 3 else BYTES_PER_CPIXEL= BYTES_PER_PIXEL end if include "keymap.inc" include "gui.inc" include "network.inc" include "raw.inc" include "copyrect.inc" include "rre.inc" include "trle.inc" include "zrle.inc" include "cursor.inc" include "des.inc" if BITS_PER_PIXEL = 8 create_lut: mov edi, lut_8bpp ; 332 format xor eax, eax call green add eax, 0x240000 call green add eax, 0x250000 call green add eax, 0x240000 call green add eax, 0x250000 call green add eax, 0x240000 call green add eax, 0x250000 call green add eax, 0x240000 call green ret green: mov ah, 0 call blue mov ah, 36 call blue add ah, 37 call blue add ah, 36 call blue add ah, 37 call blue add ah, 36 call blue add ah, 37 call blue add ah, 36 call blue ret blue: mov al, 0 stosd mov al, 85 stosd mov al, 170 stosd mov al, 255 stosd ret end if START: mcall 68, 11 ; init heap ; Load libraries stdcall dll.Load, @IMPORT test eax, eax jz @f mov [status], STATUS_LIB_ERR jmp draw_gui.first_time @@: ; When using 8BPP, create lookup table if BITS_PER_PIXEL = 8 call create_lut end if ; Check if we got a server address through parameters cmp byte[serveraddr], 0 je @f xor al, al mov edi, serveraddr mov ecx, SERVERADDRLEN repne scasb sub edi, serveraddr+1 mov [URLbox.size], edi mov [URLbox.pos], edi call open_connection @@: ; Present the user with the GUI and wait for network connection jmp draw_gui.first_time ; Create main window connected: mcall 71, 1, name ; reset window caption (add server name) mov edx, dword[screen] movzx esi, dx shr edx, 16 add edx, 2*xpos add esi, ypos+xpos mcall 67, 10, 10 ; resize the window mcall 40, EVM_CURSOR_FILTER + EVM_MOUSE_FILTER + EVM_MOUSE + EVM_KEY + EVM_REDRAW + EVM_BUTTON mcall 66, 1, 1 ; Switch keyboard to scancode mode call generate_keymap redraw: mcall 12, 1 mov ebx, dword[screen] movzx ecx, bx shr ebx, 16 mov edx, 0x74ffffff mov edi, name mcall 0 ; draw window mcall 12, 2 draw_framebuffer: DEBUGF 1, "Drawing framebuffer\n" mcall 7, framebuffer, dword[screen], 0 and [work], not WORK_FRAMEBUFFER mainloop: cmp [status], STATUS_CONNECTED jne draw_gui test [work], WORK_FRAMEBUFFER jnz draw_framebuffer test [work], WORK_CURSOR jnz update_cursor mcall 23, 10 ; Check for event with 0,1s timeout dec eax jz redraw dec eax jz key dec eax jz button sub eax, 3 jz mouse jmp mainloop key: mcall 66, 3 mov ebx, eax ; get modifier keys mcall 2 ; get key scancode cmp ah, 224 ; extended keycode? je .extended xor al, al test ah, 0x80 ; key up? jnz @f inc al and ah, 0x7f @@: mov byte[KeyEvent.down], al movzx eax, ah test ebx, 100000b ; alt? jz .no_alt mov ax, [keymap_alt+eax*2] jmp .key .no_alt: test ebx, 11b ; shift? jz .no_shift mov ax, [keymap_shift+eax*2] jmp .key .no_shift: test ebx, 10000000b ; numlock ? jz .no_numlock cmp al, 71 jb .no_numlock cmp al, 83 ja .no_numlock mov ah, [keymap_numlock+eax-71] xor al, al jmp .key .extended: ; extended keys always use regular keymap mcall 2 shr eax, 8 jz mainloop xor ah, ah test al, 0x80 ; key up? jnz @f inc ah @@: mov byte[KeyEvent.down], ah and ax, 0x007f .no_numlock: mov ax, [keymap+eax*2] .key: test ax, ax jz mainloop mov word[KeyEvent.key+2], ax DEBUGF 1, "Sending key: 0x%x\n", ax mcall send, [socketnum], KeyEvent, 8, 0 jmp mainloop mouse: ; DEBUGF 1, "Sending pointer event\n" mcall 37, 1 ; get mouse pos bswap eax mov [PointerEvent.x], ax shr eax, 16 mov [PointerEvent.y], ax mcall 37, 2 ; get mouse buttons test al, 00000010b ; test if right button was pressed (bit 1 in kolibri) jz @f add al, 00000010b ; in RFB protocol it is bit 2, so if we add bit 2 again, we"ll get bit 3 and bit 1 will remain the same @@: mov [PointerEvent.mask], al mcall send, [socketnum], PointerEvent, 6, 0 jmp mainloop button: mcall 17 ; get id mov [status], STATUS_CLOSED mcall close, [socketnum] mcall -1 update_cursor: ; load cursor mov dx, word[cursor.y] shl edx, 16 mov dx, 2 mcall 37, 4, cursor.image test eax, eax jz .fail ; set cursor mov ecx, eax mcall 37, 5 ; delete previously set cursor mov ecx, eax mcall 37, 6 .fail: and [work], not WORK_CURSOR jmp mainloop ; DATA AREA include_debug_strings keymap_numlock: db '7', '8', '9', '-' db '4', '5', '6', '+' db '1', '2', '3' db '0', '.' HandShake db "RFB 003.003", 10 ClientInit db 0 ; not shared if BITS_PER_PIXEL = 32 SetPixelFormat db 0 ; setPixelformat db 0, 0, 0 ; padding .bpp db 32 ; bits per pixel .depth db 24 ; 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_shift db 16 ; red-shift .green_shift db 8 ; green-shift .blue_shift db 0 ; blue-shift db 0, 0, 0 ; padding else if BITS_PER_PIXEL = 24 SetPixelFormat db 0 ; setPixelformat db 0, 0, 0 ; padding .bpp db 24 ; bits per pixel .depth db 24 ; 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_shift db 16 ; red-shift .green_shift db 8 ; green-shift .blue_shift db 0 ; blue-shift db 0, 0, 0 ; padding else if BITS_PER_PIXEL = 16 SetPixelFormat db 0 ; setPixelformat db 0, 0, 0 ; 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, 31 ; red-max .green_max db 0, 63 ; green-max .blue_max db 0, 31 ; blue-max .red_shift db 11 ; red-shift .green_shift db 5 ; green-shift .blue_shift db 0 ; blue-shift db 0, 0, 0 ; padding else if BITS_PER_PIXEL = 8 SetPixelFormat db 0 ; setPixelformat db 0, 0, 0 ; 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_shift db 5 ; red-shift .green_shift db 2 ; green-shift .blue_shift db 0 ; blue-shift db 0, 0, 0 ; padding end if SetEncodings db 2 ; setEncodings db 0 ; padding db 0, 5 ; number of encodings ; db 0, 0, 0, 16 ; ZRLE db 0, 0, 0, 15 ; TRLE db 0, 0, 0, 2 ; RRE db 0, 0, 0, 1 ; Copyrect encoding db 0xff, 0xff, 0xff, 0x11 ; Cursor pseudo encoding db 0, 0, 0, 0 ; raw encoding .length = $ - SetEncodings FramebufferUpdateRequest db 3 .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 sockaddr1: dw AF_INET4 .port dw 0x0c17 ; 5900 .ip dd 0 rb 10 beep db 0x85, 0x25, 0x85, 0x40, 0 status dd STATUS_CONNECT work dd 0 mouse_dd dd 0 thread_id dd 0 deflate_buffer dd 0 deflate_length dd ? deflate_str dd ? URLbox edit_box 235, 70, 20, 0xffffff, 0x6f9480, 0, 0, 0x90000000, SERVERADDRLEN, serveraddr, mouse_dd, ed_focus, 0, 0 USERbox edit_box 215, 90, 10, 0xffffff, 0x6f9480, 0, 0, 0x90000000, 127, username, mouse_dd, ed_focus, 0, 0 PASSbox edit_box 215, 90, 35, 0xffffff, 0x6f9480, 0, 0, 0x10000000, 127, password, mouse_dd, ed_pass, 0, 0 serverstr db "server:" userstr db "username:" passstr db "password:" connectstr db "Connect" loginstr db "Log in" cancelstr db "Cancel" okstr db "OK" okstr_e: sz_err_disconnected db "The server has closed the connection unexpectedly.", 0 sz_err_dns db "Could not resolve hostname.", 0 sz_err_sock db "Could not open socket.", 0 sz_err_connect db "Could not connect to the server.", 0 sz_err_proto db "A protocol error has occured.", 0 sz_err_security db "An authentication problem has occured.", 0 sz_err_library db "Could not load needed libraries.", 0 sz_err_thread db "Could not create thread.", 0 sz_err_login_failed db "Login failed.", 0 err_msg dd sz_err_disconnected dd sz_err_dns dd sz_err_sock dd sz_err_connect dd sz_err_proto dd sz_err_security dd sz_err_library dd sz_err_thread dd sz_err_login_failed dd sz_err_security_c ; import align 4 @IMPORT: library network, "network.obj",\ box_lib, "box_lib.obj",\ archiver, "archiver.obj" import network,\ getaddrinfo, "getaddrinfo", \ freeaddrinfo, "freeaddrinfo", \ inet_ntoa, "inet_ntoa" import box_lib,\ edit_box_draw, "edit_box",\ edit_box_key, "edit_box_key",\ edit_box_mouse, "edit_box_mouse",\ scrollbar_v_draw, "scrollbar_v_draw",\ scrollbar_v_mouse, "scrollbar_v_mouse",\ scrollbar_h_draw, "scrollbar_h_draw",\ scrollbar_h_mouse, "scrollbar_h_mouse" import archiver,\ deflate_unpack2, "deflate_unpack2" name db "VNC viewer " .dash db 0, " " port_notice db "Example: 192.168.0.3:5900" port_notice_e: I_END: servername rb 64+1 serveraddr db 0 rb SERVERADDRLEN socketnum dd ? datapointer dd ? rectangles dw ? rectangle: .x dd ? .y dd ? .width dd ? .height dd ? subrectangles dd ? subrectangle: .x dd ? .y dd ? .width dd ? .height dd ? screen: ; Remote screen resolution .height dw ? .width dw ? palette rd 128 ; TRLE/ZRLE palettesize db ? ; TRLE/ZRLE keymap rw 128 keymap_shift rw 128 keymap_alt rw 128 username rb 128 password rb 128 keys rd 32*2 ; DES keys for VNC authentication cursor: .y db ? .x db ? .image rd 32*32 align 4 if BITS_PER_PIXEL = 8 lut_8bpp rd 256 end if sz_err_security_c rb 512+1 receive_buffer rb RECEIVE_BUFFER_SIZE framebuffer rb 1280*1024*3 ; framebuffer rb 0x1000 thread_stack: rb 0x1000 IM_END: