add gui implementation of matrix client for kos
This commit is contained in:
1 parent
668ff01ef9
commit
23c943a20a
9 files changed
+2653
No files matched your search
@@ -0,0 +1,2 @@
|
||||
if tup.getconfig("NO_FASM") ~= "" then return end
|
||||
tup.rule("matrix.asm", "fasm %f %o " .. tup.getconfig("KPACK_CMD"), "matrix")
|
||||
@@ -0,0 +1,294 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2024. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;; Written by hidnplayr@kolibrios.org ;;
|
||||
;; ;;
|
||||
;; GNU GENERAL PUBLIC LICENSE ;;
|
||||
;; Version 2, June 1991 ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
draw_window: ; Completely redraw the window, recalculate all coordinates and sizes
|
||||
|
||||
pusha
|
||||
|
||||
; get system colors
|
||||
mcall 48, 3, colors, 40
|
||||
call set_edit_box_and_scrollbar_colors
|
||||
|
||||
mcall 9, thread_info, -1 ; get information about this thread
|
||||
mov eax, [thread_info.box.width] ; window xsize
|
||||
mov ebx, [thread_info.box.height] ; ysize
|
||||
mov edx, [thread_info.client_box.width] ; work area xsize
|
||||
mov esi, [thread_info.client_box.height] ; ysize
|
||||
sub eax, edx
|
||||
sub ebx, esi
|
||||
|
||||
cmp edx, WIN_MIN_X
|
||||
jae .x_ok
|
||||
mov edx, WIN_MIN_X
|
||||
.x_ok:
|
||||
mov [xsize], edx
|
||||
add edx, eax
|
||||
|
||||
cmp esi, WIN_MIN_Y
|
||||
jae .y_ok
|
||||
mov esi, WIN_MIN_Y
|
||||
.y_ok:
|
||||
mov [ysize], esi
|
||||
add esi, ebx
|
||||
mcall 67, -1, -1 ; set the new sizes
|
||||
|
||||
popa
|
||||
|
||||
.dont_resize:
|
||||
|
||||
pusha
|
||||
|
||||
mcall 12, 1
|
||||
xor eax, eax ; draw window
|
||||
mov ebx, WIN_MIN_X+10
|
||||
mov ecx, WIN_MIN_Y+30
|
||||
mov edx, [colors.work]
|
||||
add edx, 0x33000000
|
||||
mov edi, str_programname
|
||||
mcall
|
||||
|
||||
test [thread_info.wnd_state], 100b ; skip if window is rolled up
|
||||
jne .exit
|
||||
|
||||
cmp [window_active], 0
|
||||
je .no_window
|
||||
|
||||
; calculate available space for textbox and coordinates for scrollbars
|
||||
mov eax, [ysize]
|
||||
sub eax, TOP_Y + INPUTBOX_HEIGHT - 1
|
||||
mov [scroll2.y_size], ax
|
||||
mov [scroll1.y_size], ax
|
||||
sub eax, 4
|
||||
xor edx, edx
|
||||
mov ecx, FONT_HEIGHT
|
||||
div ecx
|
||||
mov [textbox_height], eax
|
||||
mov [scroll2.cur_area], eax
|
||||
mov [scroll1.cur_area], eax
|
||||
|
||||
mov eax, [xsize]
|
||||
sub eax, SCROLLBAR_WIDTH
|
||||
mov [scroll1.x_pos], ax
|
||||
mov edi, [window_active]
|
||||
cmp [edi + window.type], WINDOWTYPE_ROOM
|
||||
jne @f
|
||||
sub eax, SCROLLBAR_WIDTH + 2
|
||||
@@:
|
||||
mov [scroll2.x_pos], ax
|
||||
sub eax, 10
|
||||
xor edx, edx
|
||||
mov ecx, FONT_WIDTH
|
||||
div ecx
|
||||
mov [textbox_width], eax
|
||||
|
||||
; recalculate text line breaks (because height/width might have changed..)
|
||||
; meanwhile, recalculate line number of current line
|
||||
mov esi, [edi + window.text_print]
|
||||
mov al, byte[esi]
|
||||
push eax
|
||||
mov byte[esi], 0
|
||||
push esi
|
||||
|
||||
mov esi, [edi + window.text_start]
|
||||
call text_insert_newlines
|
||||
mov [edi + window.text_lines], edx
|
||||
mov [edi + window.text_scanned], esi
|
||||
mov [edi + window.text_line_print], edx
|
||||
|
||||
pop esi
|
||||
pop eax
|
||||
mov byte[esi], al
|
||||
|
||||
; and redraw the textbox (and scrollbar if needed)
|
||||
mov [scroll2.all_redraw], 1
|
||||
call draw_chat_text
|
||||
|
||||
; Draw userlist if active window is a channel
|
||||
mov edi, [window_active]
|
||||
cmp [edi + window.type], WINDOWTYPE_ROOM
|
||||
jne .not_room
|
||||
|
||||
mov [scroll1.all_redraw], 1
|
||||
call draw_user_list
|
||||
|
||||
; draw a vertical separator line when there is no scrollbar
|
||||
cmp [scroll2.all_redraw], 1
|
||||
jne .not_room
|
||||
|
||||
mov ebx, [xsize]
|
||||
sub ebx, SCROLLBAR_WIDTH + 3
|
||||
push bx
|
||||
shl ebx, 16
|
||||
pop bx
|
||||
mov ecx, [ysize]
|
||||
add ecx, TOP_Y shl 16 - (INPUTBOX_HEIGHT)
|
||||
mov edx, [colors.work_graph]
|
||||
mcall 38
|
||||
.not_room:
|
||||
.no_window:
|
||||
|
||||
; draw editbox
|
||||
mov eax, [ysize]
|
||||
sub eax, INPUTBOX_HEIGHT
|
||||
mov [edit1.top], eax
|
||||
|
||||
mov eax, [xsize]
|
||||
mov [edit1.width], eax
|
||||
|
||||
invoke edit_box_draw, edit1
|
||||
|
||||
; draw tabs
|
||||
call draw_window_tabs
|
||||
|
||||
.exit:
|
||||
mcall 12, 2
|
||||
popa
|
||||
ret
|
||||
|
||||
|
||||
|
||||
draw_user_list:
|
||||
ret
|
||||
|
||||
pusha
|
||||
|
||||
; Do we need a scrollbar?
|
||||
mov ebx, [window_active]
|
||||
|
||||
ret
|
||||
|
||||
|
||||
draw_window_tabs:
|
||||
|
||||
; Draw horizontal line
|
||||
|
||||
mov ebx, [xsize]
|
||||
mov edx, [colors.work_graph]
|
||||
mov ecx, TOP_Y SHL 16 + TOP_Y
|
||||
mcall 38
|
||||
|
||||
;; Create the buttons
|
||||
|
||||
; mov eax, 8
|
||||
; mov ebx, TAB_WIDTH
|
||||
; mov ecx, TOP_SPACE shl 16 + TAB_HEIGHT
|
||||
; mov edx, WINDOW_BTN_START
|
||||
; mov edi, windows
|
||||
; .more_btn:
|
||||
; mov esi, [colors.work]
|
||||
; cmp [window_active], edi
|
||||
; jne @f
|
||||
; ;not esi
|
||||
; ;and esi, 0x00ffffff
|
||||
; mov esi, [colors.work_light]
|
||||
; @@:
|
||||
; mcall
|
||||
; inc edx
|
||||
; add ebx, (TAB_WIDTH + TAB_SPACE) shl 16
|
||||
; add edi, sizeof.window
|
||||
; cmp [edi + window.data_ptr], 0
|
||||
; jne .more_btn
|
||||
|
||||
;; Draw the close window button
|
||||
; mov edi, [window_active]
|
||||
; cmp [edi + window.type], WINDOWTYPE_SERVER ; don't let the user close server window
|
||||
; je @f
|
||||
|
||||
;; mov eax, 8
|
||||
; mov ebx, [xsize]
|
||||
; sub ebx, SCROLLBAR_WIDTH
|
||||
; shl ebx, 16
|
||||
; mov bx, SCROLLBAR_WIDTH
|
||||
; mov ecx, TOP_SPACE shl 16 + TAB_HEIGHT - 1
|
||||
; mov edx, WINDOW_BTN_CLOSE
|
||||
; mov esi, 0x00aa0000 ; red !
|
||||
; mcall
|
||||
|
||||
; pusha
|
||||
; ; write closing cross
|
||||
; mov ebx, [xsize]
|
||||
; sub ebx, 9
|
||||
; shl ebx, 16
|
||||
; add ebx, TOP_SPACE+3
|
||||
; mov ecx, 0x80FFFfff
|
||||
; mov edx, closing_cross
|
||||
; mcall 4
|
||||
; popa
|
||||
; @@:
|
||||
|
||||
;; Draw the windownames onto the buttons
|
||||
|
||||
; mov eax, 4
|
||||
; mov ebx, 5 shl 16 + TOP_SPACE + 4 ;;;;
|
||||
; mov esi, MAX_WINDOWS
|
||||
; mov edi, windows
|
||||
; .more:
|
||||
; mov ecx, [colors.work_text]
|
||||
; test [edi + window.flags], FLAG_UPDATED
|
||||
; jz @f
|
||||
; mov ecx, 0x00aa0000 ; RED!
|
||||
; @@:
|
||||
; or ecx, 0x80000000 ; ASCIIZ string
|
||||
; lea edx, [edi + window.name]
|
||||
; mcall
|
||||
; add edi, sizeof.window ; get ptr to next window
|
||||
; cmp [edi + window.data_ptr], 0
|
||||
; je .enough
|
||||
; add ebx, (TAB_WIDTH + TAB_SPACE) shl 16
|
||||
; dec esi
|
||||
; jnz .more
|
||||
; .enough:
|
||||
|
||||
; ret
|
||||
|
||||
|
||||
|
||||
highlight_updated_tabs:
|
||||
mov eax, 4
|
||||
mov ebx, 5 shl 16 + TOP_SPACE + 4 ;;;;
|
||||
mov ecx, 0x80aa0000
|
||||
mov esi, MAX_WINDOWS
|
||||
mov edi, windows
|
||||
.more_:
|
||||
test [edi + window.flags], FLAG_UPDATED
|
||||
jz .next
|
||||
lea edx, [edi + window.name]
|
||||
mcall
|
||||
.next:
|
||||
add edi, sizeof.window ; get ptr to next window
|
||||
cmp [edi + window.data_ptr], 0
|
||||
je .enough_
|
||||
add ebx, (TAB_WIDTH + TAB_SPACE) shl 16
|
||||
dec esi
|
||||
jnz .more_
|
||||
.enough_:
|
||||
|
||||
ret
|
||||
|
||||
set_edit_box_and_scrollbar_colors:
|
||||
mov eax, [colors.work]
|
||||
mov [scroll1.bg_color], eax
|
||||
mov [scroll2.bg_color], eax
|
||||
|
||||
mov eax, [colors.work_button]
|
||||
mov [scroll1.front_color], eax
|
||||
mov [scroll2.front_color], eax
|
||||
|
||||
mov eax, [colors.work_text]
|
||||
mov [scroll1.line_color], eax
|
||||
mov [scroll2.line_color], eax
|
||||
|
||||
mov [scroll1.type], 0 ; 0 = simple, 1 = skinned
|
||||
mov [scroll2.type], 0
|
||||
|
||||
ret
|
||||
@@ -0,0 +1,757 @@
|
||||
init_tls:
|
||||
pusha
|
||||
DEBUGF 1, 'matrix_connect start\n'
|
||||
cinvoke mbedtls_init
|
||||
test eax, eax
|
||||
jnz .fail_init
|
||||
|
||||
cinvoke mbedtls_net_init, server_fd
|
||||
cinvoke mbedtls_ssl_init, ssl
|
||||
cinvoke mbedtls_ssl_config_init, conf
|
||||
cinvoke mbedtls_x509_crt_init, cacert
|
||||
|
||||
cinvoke mbedtls_ctr_drbg_init, ctr_drbg
|
||||
cinvoke mbedtls_entropy_init, entropy
|
||||
cinvoke mbedtls_ctr_drbg_seed, ctr_drbg, [mbedtls_entropy_func], entropy, pers, pers.len
|
||||
test eax, eax
|
||||
jnz .fail_seed
|
||||
|
||||
; for demo purposes, let's just skip it...
|
||||
; mov eax, [mbedtls_test_cas_pem_len]
|
||||
; cinvoke mbedtls_x509_crt_parse
|
||||
test eax, eax
|
||||
; jnz .fail_parse
|
||||
|
||||
popa
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.fail_init:
|
||||
DEBUGF 1, 'init_tls failed at mbedtls_init with code %d\n', eax
|
||||
jmp .fail_common
|
||||
.fail_seed:
|
||||
DEBUGF 1, 'init_tls failed at drbg_seed with code %d\n', eax
|
||||
jmp .fail_common
|
||||
.fail_parse:
|
||||
DEBUGF 1, 'init_tls failed at crt_parse with code %d\n', eax
|
||||
jmp .fail_common
|
||||
.fail:
|
||||
.fail_common:
|
||||
popa
|
||||
mov eax, -1
|
||||
ret
|
||||
|
||||
matrix_connect:
|
||||
; input: none
|
||||
; ret: eax = 0 on success
|
||||
pusha
|
||||
DEBUGF 1, 'matrix_connect start\n'
|
||||
cinvoke mbedtls_net_connect, server_fd, matrix_host, matrix_port, MBEDTLS_NET_PROTO_TCP
|
||||
test eax, eax
|
||||
jnz .fail
|
||||
|
||||
cinvoke mbedtls_ssl_config_defaults, conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT
|
||||
test eax, eax
|
||||
jnz .fail
|
||||
|
||||
cinvoke mbedtls_ssl_conf_authmode, conf, MBEDTLS_SSL_VERIFY_NONE
|
||||
; cinvoke mbedtls_ssl_conf_ca_chain, conf, cacert, 0
|
||||
cinvoke mbedtls_ssl_conf_rng, conf, [mbedtls_ctr_drbg_random], ctr_drbg
|
||||
DEBUGF 1, 'ssl_setup\n'
|
||||
cinvoke mbedtls_ssl_setup, ssl, conf
|
||||
test eax, eax
|
||||
jnz .fail
|
||||
|
||||
DEBUGF 1, 'ssl_set_hostname\n'
|
||||
cinvoke mbedtls_ssl_set_hostname, ssl, matrix_host
|
||||
DEBUGF 1, 'ssl_set_bio\n'
|
||||
cinvoke mbedtls_ssl_set_bio, ssl, server_fd, [mbedtls_net_send], [mbedtls_net_recv], 0
|
||||
|
||||
DEBUGF 1, 'handshake_loop\n'
|
||||
.handshake_loop:
|
||||
cinvoke mbedtls_ssl_handshake, ssl
|
||||
cmp eax, MBEDTLS_ERR_SSL_WANT_READ
|
||||
je .handshake_loop
|
||||
cmp eax, MBEDTLS_ERR_SSL_WANT_WRITE
|
||||
je .handshake_loop
|
||||
test eax, eax
|
||||
jnz .fail
|
||||
|
||||
popa
|
||||
xor eax, eax
|
||||
ret
|
||||
.fail:
|
||||
popa
|
||||
mov eax, -1
|
||||
ret
|
||||
|
||||
matrix_disconnect:
|
||||
pusha
|
||||
DEBUGF 1, 'matrix_connect start\n'
|
||||
cinvoke mbedtls_ssl_close_notify, ssl
|
||||
cinvoke mbedtls_net_free, server_fd
|
||||
cinvoke mbedtls_ssl_free, ssl
|
||||
cinvoke mbedtls_ssl_config_free, conf
|
||||
cinvoke mbedtls_x509_crt_free, cacert
|
||||
cinvoke mbedtls_ctr_drbg_free, ctr_drbg
|
||||
cinvoke mbedtls_entropy_free, entropy
|
||||
popa
|
||||
ret
|
||||
|
||||
; basic string copy
|
||||
; esi = source
|
||||
; edi = destination
|
||||
; returns edi = end of copied string (null terminator not included)
|
||||
strcpy:
|
||||
.loop:
|
||||
lodsb
|
||||
test al, al
|
||||
jz .done
|
||||
stosb
|
||||
jmp .loop
|
||||
.done:
|
||||
ret
|
||||
|
||||
str_json_p1 db '{"type":"m.login.password","user":"', 0
|
||||
str_json_p2 db '","password":"', 0
|
||||
str_json_p3 db '"}', 0
|
||||
|
||||
str_http_p1 db 'POST /_matrix/client/v3/login HTTP/1.0', 13, 10
|
||||
db 'Host: matrix.org', 13, 10
|
||||
db 'Content-Type: application/json', 13, 10
|
||||
db 'Content-Length: ', 0
|
||||
str_http_p2 db 13, 10, 'Connection: close', 13, 10, 13, 10, 0
|
||||
|
||||
str_http_logout_p1 db 'POST /_matrix/client/v3/logout HTTP/1.0', 13, 10
|
||||
db 'Host: matrix.org', 13, 10
|
||||
db 'Authorization: Bearer ', 0
|
||||
|
||||
str_http_logout_p2 db 13, 10
|
||||
db 'Content-Length: 2', 13, 10
|
||||
db 'Connection: close', 13, 10, 13, 10
|
||||
db '{}', 0
|
||||
|
||||
str_http_rooms_p1 db 'GET /_matrix/client/v3/joined_rooms HTTP/1.0', 13, 10
|
||||
db 'Host: matrix.org', 13, 10
|
||||
db 'Authorization: Bearer ', 0
|
||||
|
||||
str_http_rooms_p2 db 13, 10
|
||||
db 'Connection: close', 13, 10, 13, 10, 0
|
||||
|
||||
str_http_peek_p1 db 'GET /_matrix/client/v3/rooms/', 0
|
||||
str_http_peek_p2 db '/messages?dir=b&limit=5 HTTP/1.0', 13, 10
|
||||
db 'Host: matrix.org', 13, 10
|
||||
db 'Authorization: Bearer ', 0
|
||||
str_body_key db '"body":"', 0
|
||||
|
||||
str_access_token_key db '"access_token":"', 0
|
||||
|
||||
; substr search
|
||||
; ebx = text, edi = pattern
|
||||
; returns eax = pointer to match, or 0
|
||||
strstr:
|
||||
push ebx edi esi edx
|
||||
test ebx, ebx
|
||||
jz .not_found
|
||||
test edi, edi
|
||||
jz .not_found
|
||||
.loop:
|
||||
mov al, byte [ebx]
|
||||
test al, al
|
||||
jz .not_found
|
||||
mov esi, ebx
|
||||
mov edx, edi
|
||||
.check:
|
||||
mov ah, byte [edx]
|
||||
test ah, ah
|
||||
jz .found
|
||||
lodsb
|
||||
test al, al
|
||||
jz .not_found
|
||||
cmp al, ah
|
||||
jne .next
|
||||
inc edx
|
||||
jmp .check
|
||||
.next:
|
||||
inc ebx
|
||||
jmp .loop
|
||||
.found:
|
||||
mov eax, ebx
|
||||
pop edx esi edi ebx
|
||||
ret
|
||||
.not_found:
|
||||
xor eax, eax
|
||||
pop edx esi edi ebx
|
||||
ret
|
||||
|
||||
; parse ascii to int
|
||||
; esi = ascii ptr
|
||||
; returns eax = int, 0 if it fails
|
||||
atoi:
|
||||
push ebx ecx esi
|
||||
xor eax, eax
|
||||
xor ecx, ecx
|
||||
.atoi_loop:
|
||||
mov cl, byte [esi]
|
||||
test cl, cl
|
||||
jz .atoi_done
|
||||
sub cl, '0'
|
||||
cmp cl, 9
|
||||
ja .atoi_error
|
||||
imul eax, 10
|
||||
add eax, ecx
|
||||
inc esi
|
||||
jmp .atoi_loop
|
||||
.atoi_error:
|
||||
xor eax, eax
|
||||
.atoi_done:
|
||||
pop esi ecx ebx
|
||||
ret
|
||||
|
||||
; int to string
|
||||
; eax = number
|
||||
; edi = output buffer
|
||||
; returns edi = end of string
|
||||
itoa:
|
||||
push ebx ecx edx
|
||||
mov ecx, 10
|
||||
xor ebx, ebx
|
||||
.div_loop:
|
||||
xor edx, edx
|
||||
div ecx
|
||||
push edx
|
||||
inc ebx
|
||||
test eax, eax
|
||||
jnz .div_loop
|
||||
.pop_loop:
|
||||
pop eax
|
||||
add al, '0'
|
||||
stosb
|
||||
dec ebx
|
||||
jnz .pop_loop
|
||||
pop edx ecx ebx
|
||||
ret
|
||||
|
||||
; inputs:
|
||||
; esi = username
|
||||
; edx = password
|
||||
matrix_login_api:
|
||||
pusha
|
||||
DEBUGF 1, 'matrix_connect start\n'
|
||||
|
||||
; build the json
|
||||
DEBUGF 1, 'building JSON\n'
|
||||
DEBUGF 1, 'building JSON\n'
|
||||
mov edi, json_req_buf
|
||||
push esi
|
||||
mov esi, str_json_p1
|
||||
call strcpy
|
||||
pop esi
|
||||
call strcpy
|
||||
|
||||
push esi
|
||||
mov esi, str_json_p2
|
||||
call strcpy
|
||||
mov esi, edx
|
||||
call strcpy
|
||||
mov esi, str_json_p3
|
||||
call strcpy
|
||||
pop esi
|
||||
|
||||
; find json length
|
||||
DEBUGF 1, 'calculating JSON len\n'
|
||||
DEBUGF 1, 'calculating JSON len\n'
|
||||
mov ebx, edi
|
||||
sub ebx, json_req_buf ; ebx is content len
|
||||
|
||||
; build HTTP header + body
|
||||
DEBUGF 1, 'building HTTP header\n'
|
||||
DEBUGF 1, 'building HTTP header\n'
|
||||
mov edi, http_req_buf
|
||||
mov esi, str_http_p1
|
||||
call strcpy
|
||||
|
||||
mov eax, ebx
|
||||
call itoa
|
||||
|
||||
mov esi, str_http_p2
|
||||
call strcpy
|
||||
|
||||
; append body
|
||||
DEBUGF 1, 'appending JSON\n'
|
||||
DEBUGF 1, 'appending JSON\n'
|
||||
mov esi, json_req_buf
|
||||
mov ecx, ebx
|
||||
rep movsb
|
||||
mov byte [edi], 0
|
||||
|
||||
; set buf length
|
||||
mov ecx, edi
|
||||
sub ecx, http_req_buf
|
||||
|
||||
; send block via tls
|
||||
mov esi, http_req_buf
|
||||
.send_req:
|
||||
DEBUGF 1, 'calling ssl_write\n'
|
||||
DEBUGF 1, 'calling ssl_write\n'
|
||||
push ecx
|
||||
cinvoke mbedtls_ssl_write, ssl, esi, ecx
|
||||
pop ecx
|
||||
cmp eax, 0
|
||||
jle .send_error
|
||||
add esi, eax
|
||||
sub ecx, eax
|
||||
jnz .send_req
|
||||
|
||||
; drain tls socket
|
||||
mov edi, http_resp_buf
|
||||
mov ecx, 32000 ; max buf size
|
||||
.read_resp:
|
||||
DEBUGF 1, 'calling ssl_write\n'
|
||||
DEBUGF 1, 'calling ssl_write\n'
|
||||
push ecx
|
||||
DEBUGF 1, 'calling ssl_read\n'
|
||||
DEBUGF 1, 'calling ssl_read\n'
|
||||
cinvoke mbedtls_ssl_read, ssl, edi, ecx
|
||||
pop ecx
|
||||
cmp eax, MBEDTLS_ERR_SSL_WANT_READ
|
||||
je .read_resp
|
||||
cmp eax, MBEDTLS_ERR_SSL_WANT_WRITE
|
||||
je .read_resp
|
||||
cmp eax, 0
|
||||
jle .read_done
|
||||
add edi, eax
|
||||
sub ecx, eax
|
||||
jnz .read_resp
|
||||
.read_done:
|
||||
mov byte [edi], 0
|
||||
|
||||
; grab access token
|
||||
mov ebx, http_resp_buf
|
||||
mov edi, str_access_token_key
|
||||
call strstr
|
||||
test eax, eax
|
||||
jz .no_token
|
||||
add eax, 16 ; length of '"access_token":"'
|
||||
mov esi, eax
|
||||
mov edi, auth_token
|
||||
.copy_token:
|
||||
lodsb
|
||||
cmp al, '"'
|
||||
je .token_done
|
||||
cmp al, 0
|
||||
je .token_done
|
||||
stosb
|
||||
jmp .copy_token
|
||||
.token_done:
|
||||
mov byte [edi], 0
|
||||
mov dword [login_status], 1
|
||||
|
||||
.no_token:
|
||||
|
||||
; print on gui & dump to board
|
||||
DEBUGF 1, 'printing response\n'
|
||||
|
||||
; make sure esi is cool
|
||||
cld ; cld just because C libs mess with it
|
||||
mov esi, http_resp_buf
|
||||
call print_asciiz
|
||||
|
||||
; line break
|
||||
mov al, 10
|
||||
call print_char
|
||||
mov al, 13
|
||||
call print_char
|
||||
|
||||
popa
|
||||
xor eax, eax
|
||||
ret
|
||||
.send_error:
|
||||
popa
|
||||
mov eax, -1
|
||||
ret
|
||||
|
||||
|
||||
matrix_logout_api:
|
||||
pusha
|
||||
|
||||
; build http req + body
|
||||
DEBUGF 1, 'building logout request\n'
|
||||
mov edi, http_req_buf
|
||||
mov esi, str_http_logout_p1
|
||||
call strcpy
|
||||
|
||||
mov esi, auth_token
|
||||
call strcpy
|
||||
|
||||
mov esi, str_http_logout_p2
|
||||
call strcpy
|
||||
|
||||
; set buf length
|
||||
mov ecx, edi
|
||||
sub ecx, http_req_buf
|
||||
|
||||
; send block via tls
|
||||
mov esi, http_req_buf
|
||||
.send_req:
|
||||
DEBUGF 1, 'calling ssl_write\n'
|
||||
push ecx
|
||||
cinvoke mbedtls_ssl_write, ssl, esi, ecx
|
||||
pop ecx
|
||||
cmp eax, 0
|
||||
jle .send_error
|
||||
add esi, eax
|
||||
sub ecx, eax
|
||||
jnz .send_req
|
||||
|
||||
; drain tls socket
|
||||
mov edi, http_resp_buf
|
||||
mov ecx, 32000
|
||||
.read_resp:
|
||||
push ecx
|
||||
DEBUGF 1, 'calling ssl_read\n'
|
||||
cinvoke mbedtls_ssl_read, ssl, edi, ecx
|
||||
pop ecx
|
||||
cmp eax, MBEDTLS_ERR_SSL_WANT_READ
|
||||
je .read_resp
|
||||
cmp eax, MBEDTLS_ERR_SSL_WANT_WRITE
|
||||
je .read_resp
|
||||
cmp eax, 0
|
||||
jle .read_done
|
||||
add edi, eax
|
||||
sub ecx, eax
|
||||
jnz .read_resp
|
||||
.read_done:
|
||||
mov byte [edi], 0
|
||||
|
||||
; clear token
|
||||
mov byte [auth_token], 0
|
||||
|
||||
; print to gui
|
||||
DEBUGF 1, 'printing logout response\n'
|
||||
cld
|
||||
mov esi, http_resp_buf
|
||||
call print_asciiz
|
||||
|
||||
; line break
|
||||
mov al, 10
|
||||
call print_char
|
||||
mov al, 13
|
||||
call print_char
|
||||
|
||||
popa
|
||||
xor eax, eax
|
||||
ret
|
||||
.send_error:
|
||||
popa
|
||||
mov eax, -1
|
||||
ret
|
||||
|
||||
|
||||
matrix_get_rooms_api:
|
||||
pusha
|
||||
; almost same steps as other reqs
|
||||
; build http req
|
||||
DEBUGF 1, 'building rooms request\n'
|
||||
mov edi, http_req_buf
|
||||
mov esi, str_http_rooms_p1
|
||||
call strcpy
|
||||
|
||||
mov esi, auth_token
|
||||
call strcpy
|
||||
|
||||
mov esi, str_http_rooms_p2
|
||||
call strcpy
|
||||
|
||||
; set buf length
|
||||
mov ecx, edi
|
||||
sub ecx, http_req_buf
|
||||
|
||||
; send block via tls
|
||||
mov esi, http_req_buf
|
||||
.send_req:
|
||||
DEBUGF 1, 'calling ssl_write\n'
|
||||
push ecx
|
||||
cinvoke mbedtls_ssl_write, ssl, esi, ecx
|
||||
pop ecx
|
||||
cmp eax, 0
|
||||
jle .send_error
|
||||
add esi, eax
|
||||
sub ecx, eax
|
||||
jnz .send_req
|
||||
|
||||
; drain tls socket
|
||||
mov edi, http_resp_buf
|
||||
mov ecx, 32000
|
||||
.read_resp:
|
||||
push ecx
|
||||
DEBUGF 1, 'calling ssl_read\n'
|
||||
cinvoke mbedtls_ssl_read, ssl, edi, ecx
|
||||
pop ecx
|
||||
cmp eax, MBEDTLS_ERR_SSL_WANT_READ
|
||||
je .read_resp
|
||||
cmp eax, MBEDTLS_ERR_SSL_WANT_WRITE
|
||||
je .read_resp
|
||||
cmp eax, 0
|
||||
jle .read_done
|
||||
add edi, eax
|
||||
sub ecx, eax
|
||||
jnz .read_resp
|
||||
.read_done:
|
||||
mov byte [edi], 0
|
||||
|
||||
; parse rooms
|
||||
DEBUGF 1, 'parsing rooms response\n'
|
||||
mov ebx, http_resp_buf
|
||||
mov edi, str_joined_rooms_key
|
||||
call strstr
|
||||
test eax, eax
|
||||
jz .no_rooms
|
||||
|
||||
add eax, 16 ; skip '"joined_rooms":['
|
||||
mov esi, eax
|
||||
|
||||
mov dword [room_count], 0
|
||||
.find_room:
|
||||
; find next quote
|
||||
mov ebx, esi
|
||||
mov edi, str_quote
|
||||
call strstr
|
||||
test eax, eax
|
||||
jz .no_rooms
|
||||
|
||||
add eax, 1
|
||||
mov esi, eax
|
||||
; esi points to room_id
|
||||
|
||||
; find end quote
|
||||
mov ebx, esi
|
||||
mov edi, str_quote
|
||||
call strstr
|
||||
test eax, eax
|
||||
jz .no_rooms
|
||||
|
||||
; cap the room id string
|
||||
mov byte [eax], 0
|
||||
mov edx, eax
|
||||
add edx, 1 ; edx points to after quote
|
||||
|
||||
; print room counter
|
||||
inc dword [room_count]
|
||||
push eax
|
||||
push edx
|
||||
push esi ; stash ptr
|
||||
|
||||
mov eax, [room_count]
|
||||
mov edi, itoa_buf
|
||||
call itoa
|
||||
mov byte [edi], 0
|
||||
mov esi, itoa_buf
|
||||
call print_asciiz
|
||||
mov al, '.'
|
||||
call print_char
|
||||
mov al, ' '
|
||||
call print_char
|
||||
|
||||
pop esi ; pop back
|
||||
pop edx
|
||||
pop eax
|
||||
|
||||
; copy room id into safe chunk
|
||||
mov ecx, [room_count]
|
||||
cmp ecx, 64
|
||||
jg .limit_reached
|
||||
dec ecx
|
||||
|
||||
pusha
|
||||
mov eax, ecx
|
||||
imul eax, 128
|
||||
add eax, room_ids_buf
|
||||
mov edi, eax
|
||||
|
||||
; esi already points to null-terminated room id from the JSON
|
||||
call strcpy
|
||||
mov byte [edi], 0
|
||||
|
||||
; keep a pointer array to the safe buffer blocks
|
||||
mov eax, ecx
|
||||
imul eax, 128
|
||||
add eax, room_ids_buf
|
||||
imul ecx, 4
|
||||
add ecx, room_pointers
|
||||
mov dword [ecx], eax
|
||||
popa
|
||||
|
||||
call print_asciiz
|
||||
|
||||
mov al, 10
|
||||
call print_char
|
||||
mov al, 13
|
||||
call print_char
|
||||
|
||||
mov esi, edx
|
||||
jmp .find_room
|
||||
|
||||
.limit_reached:
|
||||
.no_rooms:
|
||||
mov al, 10
|
||||
call print_char
|
||||
mov al, 13
|
||||
call print_char
|
||||
|
||||
popa
|
||||
xor eax, eax
|
||||
ret
|
||||
.send_error:
|
||||
popa
|
||||
mov eax, -1
|
||||
ret
|
||||
|
||||
|
||||
; eax = room number requested
|
||||
matrix_peek_api:
|
||||
pusha
|
||||
|
||||
cmp eax, 0
|
||||
jle .peek_end
|
||||
cmp eax, [room_count]
|
||||
jg .peek_end
|
||||
|
||||
; point at the room id
|
||||
dec eax
|
||||
imul eax, 4
|
||||
add eax, room_pointers
|
||||
mov ebx, dword [eax] ; ebx is our room id ptr
|
||||
|
||||
; then again build http req
|
||||
DEBUGF 1, 'building peek request\n'
|
||||
mov edi, http_req_buf
|
||||
|
||||
mov esi, str_http_peek_p1
|
||||
call strcpy
|
||||
|
||||
mov esi, ebx
|
||||
call strcpy
|
||||
|
||||
mov esi, str_http_peek_p2
|
||||
call strcpy
|
||||
|
||||
mov esi, auth_token
|
||||
call strcpy
|
||||
|
||||
mov esi, str_http_rooms_p2
|
||||
call strcpy
|
||||
|
||||
; set buf length
|
||||
mov ecx, edi
|
||||
sub ecx, http_req_buf
|
||||
|
||||
; send block via tls
|
||||
mov esi, http_req_buf
|
||||
.send_req:
|
||||
DEBUGF 1, 'calling ssl_write\n'
|
||||
push ecx
|
||||
cinvoke mbedtls_ssl_write, ssl, esi, ecx
|
||||
pop ecx
|
||||
cmp eax, 0
|
||||
jle .send_error_peek
|
||||
add esi, eax
|
||||
sub ecx, eax
|
||||
jnz .send_req
|
||||
|
||||
; drain tls socket
|
||||
mov edi, http_resp_buf
|
||||
mov ecx, 32000
|
||||
.read_resp:
|
||||
push ecx
|
||||
DEBUGF 1, 'calling ssl_read_peek\n'
|
||||
cinvoke mbedtls_ssl_read, ssl, edi, ecx
|
||||
pop ecx
|
||||
cmp eax, MBEDTLS_ERR_SSL_WANT_READ
|
||||
je .read_resp
|
||||
cmp eax, MBEDTLS_ERR_SSL_WANT_WRITE
|
||||
je .read_resp
|
||||
cmp eax, 0
|
||||
jle .read_done
|
||||
add edi, eax
|
||||
sub ecx, eax
|
||||
jnz .read_resp
|
||||
.read_done:
|
||||
mov byte [edi], 0
|
||||
|
||||
; parse msgs
|
||||
DEBUGF 1, 'parsing peek response\n'
|
||||
|
||||
mov dword [msg_count], 0
|
||||
mov esi, http_resp_buf
|
||||
.find_msg:
|
||||
mov ecx, [msg_count]
|
||||
cmp ecx, 5
|
||||
jge .print_msgs
|
||||
|
||||
mov ebx, esi
|
||||
mov edi, str_body_key
|
||||
call strstr
|
||||
test eax, eax
|
||||
jz .print_msgs
|
||||
|
||||
add eax, 8 ; skip '"body":"'
|
||||
mov esi, eax
|
||||
|
||||
; find end quote
|
||||
mov ebx, esi
|
||||
mov edi, str_quote
|
||||
call strstr
|
||||
test eax, eax
|
||||
jz .print_msgs
|
||||
|
||||
mov byte [eax], 0 ; null terminate message body
|
||||
mov edx, eax
|
||||
add edx, 1
|
||||
|
||||
; old to new msg pointer array
|
||||
mov ecx, [msg_count]
|
||||
imul ecx, 4
|
||||
add ecx, msg_pointers
|
||||
mov dword [ecx], esi
|
||||
inc dword [msg_count]
|
||||
|
||||
mov esi, edx
|
||||
jmp .find_msg
|
||||
|
||||
.print_msgs:
|
||||
mov ecx, [msg_count]
|
||||
test ecx, ecx
|
||||
jz .peek_end
|
||||
|
||||
.print_loop:
|
||||
dec ecx
|
||||
|
||||
push ecx
|
||||
imul ecx, 4
|
||||
add ecx, msg_pointers
|
||||
mov esi, dword [ecx]
|
||||
|
||||
mov al, '>'
|
||||
call print_char
|
||||
mov al, ' '
|
||||
call print_char
|
||||
|
||||
call print_asciiz
|
||||
mov al, 10
|
||||
call print_char
|
||||
|
||||
pop ecx
|
||||
test ecx, ecx
|
||||
jg .print_loop
|
||||
|
||||
.no_more_msgs:
|
||||
.peek_end:
|
||||
popa
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.send_error_peek:
|
||||
popa
|
||||
mov eax, -1
|
||||
ret
|
||||
@@ -0,0 +1,606 @@
|
||||
MAX_SERVER_NAME = 256
|
||||
|
||||
version equ '0.1b'
|
||||
|
||||
; connection status
|
||||
STATUS_DISCONNECTED = 0
|
||||
STATUS_RESOLVING = 1
|
||||
STATUS_CONNECTING = 2
|
||||
STATUS_CONNECTED = 3
|
||||
STATUS_LOGGED_IN = 4
|
||||
|
||||
; window flags
|
||||
FLAG_UPDATED = 1 shl 0
|
||||
FLAG_RECEIVING_NAMES = 1 shl 1
|
||||
FLAG_SCROLL_LOW = 1 shl 2
|
||||
|
||||
; window types
|
||||
WINDOWTYPE_NONE = 0
|
||||
WINDOWTYPE_SERVER = 1
|
||||
WINDOWTYPE_ROOM = 2
|
||||
WINDOWTYPE_CHAT = 3
|
||||
WINDOWTYPE_LIST = 4
|
||||
WINDOWTYPE_DCC = 5
|
||||
|
||||
|
||||
; settings
|
||||
USERCMD_MAX_SIZE = 400
|
||||
|
||||
WIN_MIN_X = 600
|
||||
WIN_MIN_Y = 350
|
||||
|
||||
TEXT_X = 2
|
||||
TEXT_Y = TOP_Y + 2
|
||||
|
||||
TOP_SPACE = 0
|
||||
TAB_HEIGHT = 0
|
||||
TAB_WIDTH = 120
|
||||
TAB_SPACE = 5
|
||||
TOP_Y = TOP_SPACE+ TAB_HEIGHT
|
||||
INPUTBOX_HEIGHT = 15
|
||||
|
||||
MAX_WINDOWS = 20
|
||||
TEXT_BUFFERSIZE = 1024*1024
|
||||
|
||||
MAX_USERNAME_LEN = 32
|
||||
MAX_REAL_LEN = 32 ; realname
|
||||
QUIT_MSG_LEN = 250
|
||||
|
||||
|
||||
MAX_COMMAND_LEN = 512
|
||||
|
||||
PACKETBUF_SIZE = 1024
|
||||
PATH_SIZE = 1024
|
||||
PARAM_SIZE = 1024
|
||||
|
||||
|
||||
TIMESTAMP = 0 ; 3 = hh:mm:ss, 2 = hh:mm, 0 = no timestamp
|
||||
|
||||
MAX_WINDOWNAME_LEN = 256
|
||||
|
||||
WINDOW_BTN_START = 100
|
||||
WINDOW_BTN_CLOSE = 2
|
||||
WINDOW_BTN_LIST = 3
|
||||
|
||||
SCROLLBAR_WIDTH = 14
|
||||
|
||||
FONT_WIDTH = 8
|
||||
FONT_HEIGHT = 16
|
||||
|
||||
format binary as ""
|
||||
|
||||
use32
|
||||
|
||||
org 0x0
|
||||
|
||||
db 'MENUET01' ; 8 byte id
|
||||
dd 1 ; header version
|
||||
dd START ; program start
|
||||
dd I_END ; program image size
|
||||
dd IM_END+65536 ; memory size
|
||||
dd IM_END+65536 ; stack top
|
||||
dd param
|
||||
dd path
|
||||
|
||||
include "../../macros.inc"
|
||||
include "../../proc32.inc"
|
||||
__DEBUG__ = 1
|
||||
__DEBUG_LEVEL__ = 1
|
||||
include "../../debug-fdo.inc"
|
||||
include "../../dll.inc"
|
||||
include "../../network.inc"
|
||||
include "../../struct.inc"
|
||||
include "../../develop/libraries/box_lib/trunk/box_lib.mac"
|
||||
|
||||
struct window
|
||||
data_ptr dd ?
|
||||
flags db ?
|
||||
type db ?
|
||||
name rb MAX_WINDOWNAME_LEN
|
||||
text_start dd ?
|
||||
text_print dd ?
|
||||
text_write dd ?
|
||||
text_scanned dd ?
|
||||
text_lines dd ?
|
||||
text_line_print dd ?
|
||||
text_end dd ?
|
||||
ends
|
||||
|
||||
struct window_data
|
||||
text rb TEXT_BUFFERSIZE
|
||||
ends
|
||||
|
||||
include "window.inc"
|
||||
include "userparser.inc"
|
||||
include "gui.inc"
|
||||
include "http_client.inc"
|
||||
include "textbox.inc"
|
||||
include "mbedtls.inc"
|
||||
|
||||
|
||||
|
||||
|
||||
START:
|
||||
|
||||
mcall 68, 11 ; init heap
|
||||
|
||||
; wanted events
|
||||
mcall 40, EVM_REDRAW+EVM_KEY+EVM_BUTTON+EVM_STACK+EVM_MOUSE+EVM_MOUSE_FILTER
|
||||
|
||||
; load libraries
|
||||
stdcall dll.Load, @IMPORT
|
||||
test eax, eax
|
||||
jnz exit
|
||||
|
||||
; get settings ini path
|
||||
mov edi, path ; strlen
|
||||
xor al, al
|
||||
mov ecx, PATH_SIZE
|
||||
repne scasb
|
||||
dec edi
|
||||
mov eax, '.ini'
|
||||
stosd
|
||||
xor al, al
|
||||
stosb
|
||||
|
||||
; zero out window buff
|
||||
mov edi, windows
|
||||
mov ecx, (sizeof.window*MAX_WINDOWS+3)/4
|
||||
xor eax, eax
|
||||
rep stosd
|
||||
|
||||
|
||||
|
||||
; alloc window
|
||||
mov ebx, windows
|
||||
call window_create_textbox
|
||||
test eax, eax
|
||||
jz exit
|
||||
mov [ebx + window.type], WINDOWTYPE_SERVER
|
||||
|
||||
; suck in settings
|
||||
invoke ini.get_str, path, str_user, str_username, user_name, MAX_USERNAME_LEN, default_username
|
||||
invoke ini.get_str, path, str_user, str_real, user_real_name, MAX_REAL_LEN, default_real
|
||||
invoke ini.get_str, path, str_user, str_quitmsg, quit_msg, 250, default_quit
|
||||
|
||||
; echo welcome
|
||||
mov esi, str_welcome
|
||||
call print_asciiz
|
||||
|
||||
; check for param url
|
||||
cmp byte[param], 0
|
||||
je @f
|
||||
mov esi, param
|
||||
mov ecx, PARAM_SIZE
|
||||
; call cmd_usr_server.now
|
||||
@@:
|
||||
|
||||
redraw:
|
||||
call draw_window
|
||||
|
||||
mainloop:
|
||||
mcall 10 ; event loop
|
||||
|
||||
dec eax
|
||||
jz redraw
|
||||
|
||||
dec eax
|
||||
jz main_window_key
|
||||
|
||||
dec eax
|
||||
jz button
|
||||
|
||||
cmp al, 3
|
||||
je mouse
|
||||
|
||||
; call process_network_event
|
||||
|
||||
mov edi, [window_active]
|
||||
test [edi + window.flags], FLAG_UPDATED
|
||||
jz .no_update
|
||||
call draw_chat_text
|
||||
mov edi, [window_active]
|
||||
cmp [edi + window.type], WINDOWTYPE_ROOM
|
||||
jne .no_update
|
||||
call draw_user_list
|
||||
.no_update:
|
||||
call highlight_updated_tabs
|
||||
|
||||
jmp mainloop
|
||||
|
||||
button:
|
||||
|
||||
mcall 17 ; get id
|
||||
ror eax, 8
|
||||
|
||||
cmp ax, 1 ; kill
|
||||
je quit
|
||||
|
||||
cmp ax, WINDOW_BTN_CLOSE
|
||||
jne @f
|
||||
; call cmd_usr_close_window
|
||||
jmp mainloop
|
||||
|
||||
@@:
|
||||
|
||||
|
||||
@@:
|
||||
sub ax, WINDOW_BTN_START
|
||||
jb quit
|
||||
|
||||
cmp ax, MAX_WINDOWS
|
||||
ja quit
|
||||
|
||||
; save scroll pos
|
||||
push [scroll1.position]
|
||||
mov edx, [window_active]
|
||||
add esp, 4
|
||||
|
||||
; switch tab
|
||||
mov dx, sizeof.window
|
||||
mul dx
|
||||
shl edx, 16
|
||||
mov dx, ax
|
||||
add edx, windows
|
||||
cmp [edx + window.type], WINDOWTYPE_NONE
|
||||
je quit
|
||||
mov [window_active], edx
|
||||
|
||||
push [edx + window.text_line_print]
|
||||
pop [scroll2.position]
|
||||
|
||||
push 0
|
||||
pop [scroll1.position]
|
||||
|
||||
call draw_window
|
||||
jmp mainloop
|
||||
|
||||
quit:
|
||||
cmp [socketnum], 0
|
||||
je @f
|
||||
mov esi, quit_msg
|
||||
; call quit_server
|
||||
@@:
|
||||
|
||||
exit:
|
||||
|
||||
; nuke windows
|
||||
call window_close_all
|
||||
|
||||
; zero connection strings from memory
|
||||
xor eax, eax
|
||||
mov edi, homeserver_url
|
||||
mov ecx, MAX_SERVER_NAME
|
||||
rep stosb
|
||||
|
||||
mov edi, user_name
|
||||
mov ecx, MAX_USERNAME_LEN
|
||||
rep stosb
|
||||
|
||||
mov edi, user_real_name
|
||||
mov ecx, MAX_REAL_LEN
|
||||
rep stosb
|
||||
|
||||
mov edi, sockaddr1
|
||||
mov ecx, SOCKADDR1_SIZE
|
||||
rep stosb
|
||||
|
||||
mcall -1
|
||||
|
||||
|
||||
|
||||
main_window_key:
|
||||
|
||||
mcall 2
|
||||
|
||||
push dword edit1
|
||||
call [edit_box_key]
|
||||
|
||||
; cmp ah, 178
|
||||
; jne .no_up
|
||||
;
|
||||
; jmp mainloop
|
||||
;
|
||||
;
|
||||
; .no_up:
|
||||
; cmp ah, 177
|
||||
; jne .no_down
|
||||
;
|
||||
; jmp mainloop
|
||||
;
|
||||
; .no_down:
|
||||
cmp ah, 13 ; enter
|
||||
jne no_send2
|
||||
|
||||
call user_parser
|
||||
|
||||
mov eax, [edit1.size]
|
||||
|
||||
mov [edit1.size], 0
|
||||
mov [edit1.pos], 0
|
||||
|
||||
invoke edit_box_draw, edit1
|
||||
|
||||
call draw_chat_text
|
||||
|
||||
jmp mainloop
|
||||
no_send2:
|
||||
|
||||
jmp mainloop
|
||||
|
||||
mouse:
|
||||
invoke edit_box_mouse, edit1
|
||||
|
||||
; mcall 37, 7
|
||||
; movsx eax, ax
|
||||
; add [scroll2.position], eax
|
||||
|
||||
; TODO: check if scrollbar is active?
|
||||
mov edi, [window_active]
|
||||
cmp [edi + window.type], WINDOWTYPE_ROOM
|
||||
jne @f
|
||||
push [scroll1.position]
|
||||
invoke scrollbar_mouse, scroll1
|
||||
pop eax
|
||||
cmp eax, [scroll1.position] ; did the scrollbar move?
|
||||
je @f
|
||||
call draw_user_list
|
||||
@@:
|
||||
|
||||
; TODO: check if scrollbar is active?
|
||||
mov edi, [window_active]
|
||||
mov eax, [edi + window.text_lines]
|
||||
cmp eax, [textbox_height]
|
||||
jbe @f
|
||||
invoke scrollbar_mouse, scroll2
|
||||
mov edi, [window_active]
|
||||
and [edi+window.flags], not FLAG_SCROLL_LOW
|
||||
mov edx, [scroll2.position]
|
||||
add edx, [scroll2.cur_area]
|
||||
sub edx, [scroll2.max_area]
|
||||
jne .not_low
|
||||
or [edi+window.flags], FLAG_SCROLL_LOW
|
||||
.not_low:
|
||||
mov edx, [scroll2.position]
|
||||
sub edx, [edi + window.text_line_print]
|
||||
je @f
|
||||
call draw_chat_text.scroll_to_pos
|
||||
@@:
|
||||
|
||||
jmp mainloop
|
||||
|
||||
|
||||
; data seg
|
||||
|
||||
encoding_text:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
str_help db 'The following commands are available:', 10
|
||||
db '/help : show all commands', 10
|
||||
db '/login <user> <pass> : login to matrix', 10
|
||||
db '/rooms : show rooms', 10
|
||||
db '/peek <count> : show last messages of a room', 10
|
||||
db '/logout : logout from matrix', 10
|
||||
db 10, 0
|
||||
|
||||
str_logged_in db 'User logged in.', 10, 0
|
||||
str_tls_err db 'TLS init failed.', 10, 0
|
||||
str_conn_err db 'TLS connection failed.', 10, 0
|
||||
str_not_logged_in db 'Error: You are not logged in. Use /login first.', 10, 0
|
||||
str_rooms_msg db '1: !roomA:matrix.org', 10, '2: !roomB:matrix.org', 10, 0
|
||||
str_peek_usage_err db 'Usage: /peek <room_number>', 10, 0
|
||||
str_peek_bounds_err db 'Error: Invalid room number.', 10, 0
|
||||
str_logout_msg db 'Logged out.', 10, 0
|
||||
str_invalid_cmd db 'Invalid command. Type /help for a list of commands.', 10, 0
|
||||
str_welcome db 'Welcome to KolibriOS Matrix client ', version, 10
|
||||
db 'Type /help for help', 10, 0
|
||||
|
||||
str_programname db 'Matrix client ', version, 0
|
||||
|
||||
cmd_help db '/help', 0
|
||||
cmd_login db '/login', 0
|
||||
cmd_rooms db '/rooms', 0
|
||||
cmd_peek db '/peek', 0
|
||||
cmd_logout db '/logout', 0
|
||||
|
||||
str_user db 'user', 0
|
||||
str_username db 'username', 0
|
||||
str_real db 'realname', 0
|
||||
str_email db 'email', 0
|
||||
str_quitmsg db 'quitmsg', 0
|
||||
|
||||
default_username db 'makora', 0
|
||||
default_real db 'dilkhush', 0
|
||||
default_quit db 'KolibriOS forever!', 0
|
||||
|
||||
closing_cross db 'x',0
|
||||
|
||||
chat_colors dd 0xffffff ; 0 white
|
||||
dd 0x000000 ; 1 black
|
||||
dd 0x00007f ; 2 blue (navy)
|
||||
dd 0x009300 ; 3 green
|
||||
dd 0xff0000 ; 4 red
|
||||
dd 0x7f0000 ; 5 brown (maroon)
|
||||
dd 0x9c009c ; 6 purple
|
||||
dd 0xfc7f00 ; 7 olive
|
||||
dd 0xffff00 ; 8 yellow
|
||||
dd 0x00fc00 ; 9 light green
|
||||
dd 0x009393 ; 10 teal
|
||||
dd 0x00ffff ; 11 cyan
|
||||
dd 0x0000fc ; 12 royal blue
|
||||
dd 0xff00ff ; 13 pink
|
||||
dd 0x7f7f7f ; 14 grey
|
||||
dd 0xd4d0c4 ; 15 light grey (silver)
|
||||
|
||||
sockaddr1:
|
||||
dw AF_INET4
|
||||
.port dw 0x0b1a ; 6667 FIXMEEEEEE
|
||||
.ip dd 0
|
||||
rb 10
|
||||
|
||||
SOCKADDR1_SIZE = 18
|
||||
|
||||
status dd STATUS_DISCONNECTED
|
||||
|
||||
window_active dd windows
|
||||
window_print dd windows
|
||||
|
||||
cmd_remaining dd 0
|
||||
|
||||
align 4
|
||||
|
||||
|
||||
; width, left, top
|
||||
edit1 edit_box 0, 0, 0, 0xffffff, 0x6f9480, 0, 0, 0x000000, USERCMD_MAX_SIZE, input_text, mouse_dd, ed_always_focus, 0, 0
|
||||
; xsize, xpos, ysize, ypos, btn_height, max, cur, pos, bgcol, frcol, linecol
|
||||
scroll1 scrollbar SCROLLBAR_WIDTH, 0, 0, TOP_Y, SCROLLBAR_WIDTH, 0, 0, 0, 0, 0, 0, 1
|
||||
scroll2 scrollbar SCROLLBAR_WIDTH, 0, 0, TOP_Y, SCROLLBAR_WIDTH, 0, 0, 0, 0, 0, 0, 1
|
||||
|
||||
input_text db 0
|
||||
rb MAX_COMMAND_LEN
|
||||
|
||||
|
||||
@IMPORT:
|
||||
|
||||
|
||||
|
||||
library network, 'network.obj',\
|
||||
libini, 'libini.obj',\
|
||||
boxlib, 'box_lib.obj',\
|
||||
lib_mbedtls, '/hd0/1/NETWORK/MBEDTLS.OBJ'
|
||||
|
||||
import network,\
|
||||
getaddrinfo, 'getaddrinfo',\
|
||||
freeaddrinfo, 'freeaddrinfo',\
|
||||
inet_ntoa, 'inet_ntoa'
|
||||
|
||||
import libini,\
|
||||
ini.get_str, 'ini_get_str',\
|
||||
ini.get_int, 'ini_get_int'
|
||||
|
||||
import boxlib,\
|
||||
edit_box_draw, 'edit_box_draw',\
|
||||
edit_box_key, 'edit_box_key',\
|
||||
edit_box_mouse, 'edit_box_mouse',\
|
||||
scrollbar_draw, 'scrollbar_v_draw',\
|
||||
scrollbar_mouse,'scrollbar_v_mouse'
|
||||
|
||||
import lib_mbedtls, \
|
||||
mbedtls_init , 'mbedtls_init' ,\
|
||||
mbedtls_strerror , 'mbedtls_strerror' ,\
|
||||
mbedtls_test_cas_pem , 'mbedtls_test_cas_pem' ,\
|
||||
mbedtls_test_cas_pem_len , 'mbedtls_test_cas_pem_len' ,\
|
||||
mbedtls_x509_crt_free , 'mbedtls_x509_crt_free' ,\
|
||||
mbedtls_x509_crt_init , 'mbedtls_x509_crt_init' ,\
|
||||
mbedtls_x509_crt_parse , 'mbedtls_x509_crt_parse' ,\
|
||||
mbedtls_x509_crt_verify_info , 'mbedtls_x509_crt_verify_info' ,\
|
||||
mbedtls_ctr_drbg_free , 'mbedtls_ctr_drbg_free' ,\
|
||||
mbedtls_ctr_drbg_init , 'mbedtls_ctr_drbg_init' ,\
|
||||
mbedtls_ctr_drbg_random , 'mbedtls_ctr_drbg_random' ,\
|
||||
mbedtls_ctr_drbg_seed , 'mbedtls_ctr_drbg_seed' ,\
|
||||
mbedtls_debug_set_threshold , 'mbedtls_debug_set_threshold' ,\
|
||||
mbedtls_entropy_free , 'mbedtls_entropy_free' ,\
|
||||
mbedtls_entropy_func , 'mbedtls_entropy_func' ,\
|
||||
mbedtls_entropy_init , 'mbedtls_entropy_init' ,\
|
||||
mbedtls_net_connect , 'mbedtls_net_connect' ,\
|
||||
mbedtls_net_free , 'mbedtls_net_free' ,\
|
||||
mbedtls_net_init , 'mbedtls_net_init' ,\
|
||||
mbedtls_net_recv , 'mbedtls_net_recv' ,\
|
||||
mbedtls_net_send , 'mbedtls_net_send' ,\
|
||||
mbedtls_ssl_close_notify , 'mbedtls_ssl_close_notify' ,\
|
||||
mbedtls_ssl_conf_authmode , 'mbedtls_ssl_conf_authmode' ,\
|
||||
mbedtls_ssl_conf_ca_chain , 'mbedtls_ssl_conf_ca_chain' ,\
|
||||
mbedtls_ssl_conf_dbg , 'mbedtls_ssl_conf_dbg' ,\
|
||||
mbedtls_ssl_config_defaults , 'mbedtls_ssl_config_defaults' ,\
|
||||
mbedtls_ssl_config_free , 'mbedtls_ssl_config_free' ,\
|
||||
mbedtls_ssl_config_init , 'mbedtls_ssl_config_init' ,\
|
||||
mbedtls_ssl_conf_rng , 'mbedtls_ssl_conf_rng' ,\
|
||||
mbedtls_ssl_free , 'mbedtls_ssl_free' ,\
|
||||
mbedtls_ssl_get_verify_result , 'mbedtls_ssl_get_verify_result' ,\
|
||||
mbedtls_ssl_handshake , 'mbedtls_ssl_handshake' ,\
|
||||
mbedtls_ssl_init , 'mbedtls_ssl_init' ,\
|
||||
mbedtls_ssl_read , 'mbedtls_ssl_read' ,\
|
||||
mbedtls_ssl_set_bio , 'mbedtls_ssl_set_bio' ,\
|
||||
mbedtls_ssl_set_hostname , 'mbedtls_ssl_set_hostname' ,\
|
||||
mbedtls_ssl_setup , 'mbedtls_ssl_setup' ,\
|
||||
mbedtls_ssl_write , 'mbedtls_ssl_write'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cmd_args dd 0
|
||||
matrix_host db "matrix.org", 0
|
||||
matrix_port db "443", 0
|
||||
pers db "matrix_client"
|
||||
.len = $ - pers
|
||||
login_status dd 0
|
||||
|
||||
|
||||
str_joined_rooms_key db '"joined_rooms":[', 0
|
||||
str_quote db '"', 0
|
||||
include_debug_strings
|
||||
I_END:
|
||||
|
||||
align 4
|
||||
server_fd rb 64
|
||||
align 4
|
||||
ssl rb 65536
|
||||
align 4
|
||||
conf rb 32768
|
||||
align 4
|
||||
cacert rb 16384
|
||||
align 4
|
||||
ctr_drbg rb 8192
|
||||
align 4
|
||||
entropy rb 8192
|
||||
align 4
|
||||
json_req_buf rb 2048
|
||||
http_req_buf rb 4096
|
||||
http_resp_buf rb 32768
|
||||
auth_token rb 2048
|
||||
current_room rb 256
|
||||
current_user rb 256
|
||||
user_command rb MAX_COMMAND_LEN*4
|
||||
.size dd ?
|
||||
utf8_bytes_rest dd ?
|
||||
utf8_char dd ?
|
||||
packetbuf rb PACKETBUF_SIZE
|
||||
path rb PATH_SIZE
|
||||
param rb PARAM_SIZE
|
||||
thread_info process_information
|
||||
xsize dd ?
|
||||
ysize dd ?
|
||||
mouse_dd dd ?
|
||||
textbox_height dd ?
|
||||
textbox_width dd ?
|
||||
colors system_colors
|
||||
homeserver_url rb MAX_SERVER_NAME
|
||||
socketnum dd ?
|
||||
user_name rb MAX_USERNAME_LEN
|
||||
user_real_name rb MAX_REAL_LEN
|
||||
quit_msg rb QUIT_MSG_LEN
|
||||
windows rb MAX_WINDOWS*sizeof.window
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
itoa_buf rb 16
|
||||
room_count dd ?
|
||||
room_pointers rb 1024
|
||||
room_ids_buf rb 8192
|
||||
msg_count dd ?
|
||||
msg_pointers rb 32
|
||||
|
||||
IM_END:
|
||||
@@ -0,0 +1,9 @@
|
||||
[user]
|
||||
nick = makora
|
||||
realname = dilkhush
|
||||
partmsg = KolibriOS forever!
|
||||
|
||||
[colors]
|
||||
action1 = 0x000000aa
|
||||
action2 = 0x0000aa00
|
||||
action3 = 0x00aa0000
|
||||
@@ -0,0 +1,22 @@
|
||||
macro mbedtls_net_context [args] { common match any,args \{ rb 4 \} match ,args \{ rb 4 \} }
|
||||
macro mbedtls_entropy_context [args] { common match any,args \{ rb 256 \} match ,args \{ rb 256 \} }
|
||||
macro mbedtls_ctr_drbg_context [args] { common match any,args \{ rb 352 \} match ,args \{ rb 352 \} }
|
||||
macro mbedtls_ssl_context [args] { common match any,args \{ rb 600 \} match ,args \{ rb 600 \} }
|
||||
macro mbedtls_ssl_config [args] { common match any,args \{ rb 360 \} match ,args \{ rb 360 \} }
|
||||
macro mbedtls_x509_crt [args] { common match any,args \{ rb 1320 \} match ,args \{ rb 1320 \} }
|
||||
|
||||
MBEDTLS_ERR_NET_SOCKET_FAILED = -0x0042
|
||||
MBEDTLS_ERR_NET_CONNECT_FAILED = -0x0044
|
||||
MBEDTLS_ERR_SSL_WANT_READ = -0x6900
|
||||
MBEDTLS_ERR_SSL_WANT_WRITE = -0x6880
|
||||
|
||||
MBEDTLS_NET_PROTO_TCP = 0
|
||||
MBEDTLS_NET_PROTO_UDP = 1
|
||||
MBEDTLS_SSL_IS_CLIENT = 0
|
||||
MBEDTLS_SSL_IS_SERVER = 1
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM = 0
|
||||
MBEDTLS_SSL_TRANSPORT_DATAGRAM = 1
|
||||
MBEDTLS_SSL_PRESET_DEFAULT = 0
|
||||
MBEDTLS_SSL_VERIFY_NONE = 0
|
||||
MBEDTLS_SSL_VERIFY_OPTIONAL = 1
|
||||
MBEDTLS_SSL_VERIFY_REQUIRED = 2
|
||||
@@ -0,0 +1,463 @@
|
||||
text_insert_newlines: ; esi = ASCIIZ string
|
||||
|
||||
xor edx, edx ; number of lines of text
|
||||
cmp byte[esi], 0
|
||||
je .done
|
||||
.next_line:
|
||||
xor ebx, ebx
|
||||
mov ecx, [textbox_width]
|
||||
inc ecx
|
||||
.more:
|
||||
dec ecx
|
||||
jz .end_of_line
|
||||
.next_byte:
|
||||
lodsb ; get one character of the string
|
||||
test al, al ; end of string?
|
||||
jz .almost_done
|
||||
cmp al, ' ' ; it's a space! remember its position
|
||||
je .space
|
||||
cmp al, 13 ; we already inserted a newline once, make it a space again
|
||||
je .soft_nl
|
||||
cmp al, 10 ; it's a newline, continue onto the next line
|
||||
je .newline
|
||||
and al, 0xc0 ; Is it a multi byte UTF8 char?
|
||||
cmp al, 0x80
|
||||
je .next_byte
|
||||
jmp .more
|
||||
.newline:
|
||||
inc edx
|
||||
jmp .next_line
|
||||
.soft_nl:
|
||||
mov byte[esi-1], ' '
|
||||
.space:
|
||||
mov ebx, esi ; last detected space
|
||||
jmp .more
|
||||
.end_of_line:
|
||||
inc edx
|
||||
test ebx, ebx ; did we detect any spaces on this line?
|
||||
jz .next_line ; no: just continue onto the next line
|
||||
mov byte[ebx-1], 13 ; yes: replace last space on line with a soft newline
|
||||
mov esi, ebx ; and continue parsing just after last space
|
||||
jmp .next_line ;
|
||||
.almost_done:
|
||||
dec esi
|
||||
.done:
|
||||
|
||||
ret
|
||||
|
||||
|
||||
;----------------------------------
|
||||
; scan untill next line is reached
|
||||
;
|
||||
; When you set the direction flag before calling, you can also scan for previous line!
|
||||
; IN: esi
|
||||
; OUT: esi
|
||||
;----------------------------------
|
||||
text_nextline:
|
||||
|
||||
mov ecx, [textbox_width]
|
||||
.loop:
|
||||
lodsb
|
||||
test al, al
|
||||
jz .done
|
||||
cmp al, 10
|
||||
je .done
|
||||
cmp al, 13
|
||||
je .done
|
||||
and al, 0xc0
|
||||
cmp al, 0x80
|
||||
je .loop ; This byte is the second, third or fourth byte of a multi-byte UTF8 char
|
||||
dec ecx
|
||||
jnz .loop
|
||||
.done:
|
||||
ret
|
||||
|
||||
;----------------------------------
|
||||
; print string
|
||||
;
|
||||
; IN: esi = ptr to string
|
||||
; bl = char which marks end of string
|
||||
; OUT: esi = ptr to end of str
|
||||
;----------------------------------
|
||||
print_string:
|
||||
|
||||
push eax
|
||||
.loop:
|
||||
lodsb
|
||||
cmp al, bl
|
||||
je .done
|
||||
cmp al, 13
|
||||
je .loop
|
||||
test al, al
|
||||
jz .done
|
||||
call print_char
|
||||
jmp .loop
|
||||
.done:
|
||||
pop eax
|
||||
|
||||
ret
|
||||
|
||||
|
||||
;----------------------------------
|
||||
; print ASCIIZ string
|
||||
;
|
||||
; IN: esi = ptr to ASCIIZ string
|
||||
; OUT: esi = ptr to end of str
|
||||
;----------------------------------
|
||||
print_asciiz:
|
||||
|
||||
push eax
|
||||
.loop:
|
||||
lodsb
|
||||
test al, al
|
||||
jz .done
|
||||
call print_char
|
||||
jmp .loop
|
||||
.done:
|
||||
pop eax
|
||||
|
||||
ret
|
||||
|
||||
|
||||
;----------------------------------
|
||||
; print character
|
||||
;
|
||||
; IN: al = char to print
|
||||
; OUT: /
|
||||
;----------------------------------
|
||||
print_char:
|
||||
|
||||
push esi edi
|
||||
mov esi, [window_print]
|
||||
mov edi, [esi + window.text_write]
|
||||
stosb
|
||||
cmp edi, [esi + window.text_end]
|
||||
jae .uh_ow
|
||||
mov [esi + window.text_write], edi
|
||||
.continue:
|
||||
or [esi + window.flags], FLAG_UPDATED
|
||||
pop edi esi
|
||||
|
||||
ret
|
||||
|
||||
.uh_ow:
|
||||
pusha
|
||||
mov edi, [esi + window.text_start]
|
||||
mov [esi + window.text_print], edi
|
||||
lea esi, [edi + TEXT_BUFFERSIZE/2]
|
||||
call text_nextline
|
||||
mov ecx, TEXT_BUFFERSIZE/8
|
||||
rep movsd
|
||||
mov esi, edi
|
||||
call text_insert_newlines
|
||||
|
||||
mov ebx, [window_print]
|
||||
mov [ebx + window.text_lines], edx
|
||||
mov [ebx + window.text_scanned], esi
|
||||
mov [ebx + window.text_write], esi
|
||||
mov [ebx + window.text_line_print], 0
|
||||
popa
|
||||
|
||||
jmp .continue
|
||||
|
||||
|
||||
|
||||
;-----------------------------------------------
|
||||
; Draw text of the current window to the screen
|
||||
;
|
||||
; IN: /
|
||||
; OUT: /
|
||||
;-----------------------------------------------
|
||||
draw_chat_text:
|
||||
|
||||
mov edi, [window_active]
|
||||
and [edi + window.flags], not FLAG_UPDATED ; clear the 'window is updated' flag
|
||||
|
||||
; Scan new text for newlines
|
||||
mov esi, [edi + window.text_scanned]
|
||||
call text_insert_newlines
|
||||
add [edi + window.text_lines], edx
|
||||
mov [edi + window.text_scanned], esi
|
||||
|
||||
; Is scrollbar at lowest position?
|
||||
test [edi + window.flags], FLAG_SCROLL_LOW
|
||||
jnz .yesscroll ; Yes
|
||||
cmp [scroll2.all_redraw], 1 ; No
|
||||
jnz .noscroll
|
||||
mov edx, [textbox_height]
|
||||
add edx, [edi + window.text_line_print]
|
||||
cmp edx, [edi + window.text_lines]
|
||||
jl .noscroll
|
||||
.yesscroll:
|
||||
; Scrollbar was at lowest position, scroll down automatically when new text arrived.
|
||||
mov edx, [edi + window.text_lines]
|
||||
sub edx, [textbox_height]
|
||||
jg @f
|
||||
mov [edi + window.text_line_print], 0
|
||||
jmp .noscroll ; There are less lines of text than fit into the window, dont scroll..
|
||||
@@:
|
||||
sub edx, [edi + window.text_line_print]
|
||||
je .noscroll ; We are already at the bottom pos, dont scroll..
|
||||
.scroll_to_pos: ; edx = number of lines to go up/down (flags must indicate direction)
|
||||
pushf
|
||||
add [edi + window.text_line_print], edx
|
||||
mov esi, [edi + window.text_print]
|
||||
popf
|
||||
jg .loop_forward
|
||||
std ; set direction flag so we can scan backwards
|
||||
dec esi
|
||||
dec esi ; move our cursor just in front of newline, for scanning backwards
|
||||
.loop_backward:
|
||||
call text_nextline
|
||||
inc edx
|
||||
jnz .loop_backward
|
||||
inc esi
|
||||
inc esi ; move the cursor just after last newline
|
||||
cld
|
||||
jmp .ok
|
||||
|
||||
.loop_forward:
|
||||
call text_nextline
|
||||
dec edx
|
||||
jnz .loop_forward
|
||||
.ok:
|
||||
mov [edi + window.text_print], esi
|
||||
.noscroll:
|
||||
|
||||
; Update and draw scrollbar when nescessary
|
||||
mov edx, [edi + window.text_lines]
|
||||
cmp edx, [textbox_height]
|
||||
jbe .scroll_done
|
||||
|
||||
mov [scroll2.max_area], edx
|
||||
mov eax, [edi + window.text_line_print]
|
||||
mov [scroll2.position], eax
|
||||
|
||||
push dword scroll2 ; redraw scrollbar
|
||||
call [scrollbar_draw]
|
||||
mov [scroll2.all_redraw], 0 ; next time, dont redraw it completely
|
||||
.scroll_done:
|
||||
|
||||
; Calculate start offset coordinates (align text to bottom)
|
||||
mov ebx, [textbox_height]
|
||||
sub ebx, [edi + window.text_lines]
|
||||
jb .no_offset
|
||||
imul ebx, FONT_HEIGHT
|
||||
push [edi + window.text_start]
|
||||
pop [edi + window.text_print]
|
||||
jmp .draw_text
|
||||
.no_offset:
|
||||
xor ebx, ebx
|
||||
.draw_text:
|
||||
|
||||
; Prepare to actually draw some text
|
||||
add ebx, TEXT_X shl 16 + TEXT_Y ; text coordinates
|
||||
mov ecx, [colors.work_text] ; default text color
|
||||
or ecx, 0x30000000
|
||||
mov edx, [edi + window.text_print] ; start of text to print
|
||||
|
||||
; Scan backwards on line for color escape codes
|
||||
mov esi, edx
|
||||
push edx
|
||||
std
|
||||
@@:
|
||||
lodsb
|
||||
cmp al, 0 ; end of text
|
||||
je @f
|
||||
cmp al, 10 ; hard newline
|
||||
je @f
|
||||
cmp al, 3 ; chat escape code
|
||||
jne @b
|
||||
|
||||
cld
|
||||
lea edx, [esi+2]
|
||||
call dec_to_esi
|
||||
jz @f
|
||||
mov ecx, [chat_colors + 4*esi]
|
||||
or ecx, 0x30000000 ; UTF-8 text
|
||||
|
||||
cmp byte[edx], ',' ; background color?
|
||||
jne @f
|
||||
inc edx
|
||||
call dec_to_esi
|
||||
jz @f
|
||||
mov edi, [chat_colors + 4*esi]
|
||||
or ecx, 0x40000000 ; enable background color
|
||||
@@:
|
||||
cld
|
||||
|
||||
pop edx
|
||||
mov eax, [textbox_height] ; max number of lines to draw
|
||||
.drawloop:
|
||||
cmp byte[edx], 0
|
||||
je .end_of_text
|
||||
|
||||
; Clear one row of characters
|
||||
pusha
|
||||
mov cx, bx
|
||||
shl ecx, 16
|
||||
mov cx, FONT_HEIGHT
|
||||
mov ebx, TEXT_X shl 16
|
||||
mov bx, word[textbox_width]
|
||||
imul bx, FONT_WIDTH
|
||||
mov edx, [colors.work]
|
||||
mcall 13 ; draw rectangle
|
||||
popa
|
||||
|
||||
push eax
|
||||
.line:
|
||||
cmp byte[edx], 0x20
|
||||
jae .printable
|
||||
cmp byte[edx], 0
|
||||
jne @f
|
||||
pop eax
|
||||
jmp .end_of_text
|
||||
@@:
|
||||
cmp byte[edx], 13
|
||||
je .newline_soft
|
||||
cmp byte[edx], 10
|
||||
je .newline_hard
|
||||
|
||||
cmp byte[edx], 3 ; escape code for chat colors
|
||||
jne .no_colors
|
||||
inc edx
|
||||
call dec_to_esi
|
||||
jz .line
|
||||
mov ecx, [chat_colors + 4*esi]
|
||||
or ecx, 0x30000000
|
||||
|
||||
cmp byte[edx], ',' ; background color?
|
||||
jne .line
|
||||
inc edx
|
||||
call dec_to_esi
|
||||
jz .line
|
||||
mov edi, [chat_colors + 4*esi]
|
||||
or ecx, 0x40000000
|
||||
.no_colors:
|
||||
|
||||
; Some non-printable, just skip it
|
||||
inc edx
|
||||
jmp .line
|
||||
|
||||
;-------------------------------------------
|
||||
; Count characters until 0, 10, 13 or 3 byte
|
||||
|
||||
.printable:
|
||||
push edx
|
||||
xor esi, esi
|
||||
dec esi
|
||||
.next_char:
|
||||
inc esi
|
||||
cmp esi, [textbox_width]
|
||||
je .cnt_done
|
||||
mov al, byte[edx]
|
||||
cmp al, 0x20
|
||||
jb .cnt_done
|
||||
|
||||
inc edx
|
||||
test al, 10000000b
|
||||
jz .next_char ; 1 byte wide
|
||||
|
||||
add edx, 3
|
||||
and al, 11111000b
|
||||
cmp al, 11110000b
|
||||
je .next_char ; 4 bytes wide
|
||||
|
||||
dec edx
|
||||
and al, 11110000b
|
||||
cmp al, 11100000b
|
||||
je .next_char ; 3 bytes wide
|
||||
dec edx ; 2 bytes wide
|
||||
jmp .next_char
|
||||
.cnt_done:
|
||||
mov eax, edx
|
||||
pop edx
|
||||
push eax
|
||||
mcall 4 ; draw text
|
||||
pop edx ; next start ptr
|
||||
|
||||
cmp esi, [textbox_width]
|
||||
je .line_full
|
||||
imul esi, FONT_WIDTH shl 16
|
||||
add ebx, esi
|
||||
jmp .line
|
||||
|
||||
.newline_hard:
|
||||
mov ecx, [colors.work_text]
|
||||
or ecx, 0x30000000
|
||||
.newline_soft:
|
||||
inc edx
|
||||
.line_full:
|
||||
and ebx, 0x0000ffff
|
||||
add ebx, TEXT_X shl 16 + FONT_HEIGHT
|
||||
pop eax
|
||||
dec eax
|
||||
jnz .drawloop
|
||||
.end_of_text:
|
||||
|
||||
ret
|
||||
|
||||
|
||||
|
||||
|
||||
dec_to_esi:
|
||||
|
||||
xor esi, esi
|
||||
.loop:
|
||||
movzx eax, byte[edx]
|
||||
sub al, '0'
|
||||
jb .done
|
||||
cmp al, 9
|
||||
ja .done
|
||||
inc edx
|
||||
lea esi, [esi*4 + esi] ; esi * 5
|
||||
lea esi, [esi*2 + eax] ; esi * 2 + eax
|
||||
jmp .loop
|
||||
.done:
|
||||
cmp esi, 16
|
||||
jae .fail
|
||||
ret
|
||||
|
||||
.fail:
|
||||
xor esi, esi
|
||||
ret
|
||||
|
||||
|
||||
|
||||
if TIMESTAMP
|
||||
print_timestamp:
|
||||
|
||||
pusha
|
||||
mcall 3 ; get system time
|
||||
mov ebx, eax
|
||||
|
||||
mov al, '['
|
||||
call print_char
|
||||
mov ecx, TIMESTAMP
|
||||
.loop:
|
||||
mov al, bl
|
||||
shr al, 4
|
||||
add al, '0'
|
||||
call print_char
|
||||
|
||||
mov al, bl
|
||||
and al, 0x0f
|
||||
add al, '0'
|
||||
call print_char
|
||||
|
||||
dec ecx
|
||||
jz .done
|
||||
|
||||
mov al, ':'
|
||||
call print_char
|
||||
shr ebx, 8
|
||||
jmp .loop
|
||||
.done:
|
||||
mov al, ']'
|
||||
call print_char
|
||||
mov al, ' '
|
||||
call print_char
|
||||
|
||||
popa
|
||||
ret
|
||||
end if
|
||||
@@ -0,0 +1,273 @@
|
||||
user_parser:
|
||||
mov ebp, [window_active] ; print to the current window
|
||||
mov [window_print], ebp
|
||||
|
||||
mov ecx, [edit1.size]
|
||||
test ecx, ecx
|
||||
jz .ret ; nothing to do here
|
||||
|
||||
; copy input straight to cmd buffer
|
||||
mov esi, input_text
|
||||
mov edi, user_command
|
||||
rep movsb ; copies ecx bytes
|
||||
mov byte[edi], 0x0 ; null terminate
|
||||
|
||||
mov eax, [edit1.size]
|
||||
mov [user_command.size], eax
|
||||
|
||||
; is it a slash command?
|
||||
cmp byte [user_command], '/'
|
||||
je .command
|
||||
|
||||
.send_privmsg:
|
||||
mov al, '<'
|
||||
call print_char
|
||||
|
||||
mov esi, user_name
|
||||
call print_asciiz
|
||||
|
||||
mov al, '>'
|
||||
call print_char
|
||||
mov al, ' '
|
||||
call print_char
|
||||
|
||||
mov esi, user_command
|
||||
call print_asciiz
|
||||
|
||||
mov al, 10
|
||||
call print_char
|
||||
|
||||
.ret:
|
||||
ret
|
||||
|
||||
.command:
|
||||
; slice the command string at the first space
|
||||
mov esi, user_command
|
||||
mov [cmd_args], 0
|
||||
.find_space:
|
||||
lodsb
|
||||
test al, al
|
||||
jz .cmd_end
|
||||
cmp al, ' '
|
||||
jne .find_space
|
||||
|
||||
; space found, terminate here
|
||||
mov byte [esi-1], 0
|
||||
mov [cmd_args], esi
|
||||
.cmd_end:
|
||||
|
||||
; /help
|
||||
mov esi, user_command
|
||||
mov edi, cmd_help
|
||||
call streq
|
||||
test eax, eax
|
||||
jnz .do_help
|
||||
|
||||
; /login
|
||||
mov esi, user_command
|
||||
mov edi, cmd_login
|
||||
call streq
|
||||
test eax, eax
|
||||
jnz .do_login
|
||||
|
||||
; /rooms
|
||||
mov esi, user_command
|
||||
mov edi, cmd_rooms
|
||||
call streq
|
||||
test eax, eax
|
||||
jnz .do_rooms
|
||||
|
||||
; /peek
|
||||
mov esi, user_command
|
||||
mov edi, cmd_peek
|
||||
call streq
|
||||
test eax, eax
|
||||
jnz .do_peek
|
||||
|
||||
; /logout
|
||||
mov esi, user_command
|
||||
mov edi, cmd_logout
|
||||
call streq
|
||||
test eax, eax
|
||||
jnz .do_logout
|
||||
|
||||
; invalid command
|
||||
mov esi, str_invalid_cmd
|
||||
call print_asciiz
|
||||
jmp .done_cmd
|
||||
|
||||
.do_help:
|
||||
mov esi, str_help
|
||||
call print_asciiz
|
||||
jmp .done_cmd
|
||||
|
||||
.do_login:
|
||||
; get username/pass from args
|
||||
mov esi, [cmd_args]
|
||||
test esi, esi
|
||||
jz .login_err
|
||||
push esi ; username starts at esi
|
||||
|
||||
.find_pw_space:
|
||||
lodsb
|
||||
test al, al
|
||||
jz .login_err_pop
|
||||
cmp al, ' '
|
||||
jne .find_pw_space
|
||||
|
||||
mov byte [esi-1], 0 ; null terminate username
|
||||
mov edx, esi ; password starts at esi
|
||||
pop esi
|
||||
; we now have ESI = user, EDX = pass
|
||||
|
||||
cmp dword [login_status], 0
|
||||
je .start_conn
|
||||
call matrix_disconnect
|
||||
|
||||
.start_conn:
|
||||
call init_tls
|
||||
test eax, eax
|
||||
jnz .login_tls_err
|
||||
|
||||
call matrix_connect
|
||||
test eax, eax
|
||||
jnz .login_conn_err
|
||||
call matrix_login_api
|
||||
|
||||
jmp .done_cmd
|
||||
|
||||
.login_err_pop:
|
||||
pop esi
|
||||
.login_err:
|
||||
; invalid usage
|
||||
mov esi, str_invalid_cmd
|
||||
call print_asciiz
|
||||
jmp .done_cmd
|
||||
.login_tls_err:
|
||||
mov esi, str_tls_err
|
||||
call print_asciiz
|
||||
jmp .done_cmd
|
||||
.login_conn_err:
|
||||
mov esi, str_conn_err
|
||||
call print_asciiz
|
||||
jmp .done_cmd
|
||||
|
||||
.do_rooms:
|
||||
cmp dword [login_status], 0
|
||||
je .not_logged_in_err
|
||||
|
||||
call matrix_disconnect
|
||||
call init_tls
|
||||
test eax, eax
|
||||
jnz .rooms_conn_err
|
||||
|
||||
call matrix_connect
|
||||
test eax, eax
|
||||
jnz .rooms_conn_err
|
||||
|
||||
call matrix_get_rooms_api
|
||||
|
||||
jmp .done_cmd
|
||||
|
||||
.not_logged_in_err:
|
||||
mov esi, str_not_logged_in
|
||||
call print_asciiz
|
||||
jmp .done_cmd
|
||||
.rooms_conn_err:
|
||||
mov esi, str_conn_err
|
||||
call print_asciiz
|
||||
jmp .done_cmd
|
||||
|
||||
.do_peek:
|
||||
cmp dword [login_status], 0
|
||||
je .not_logged_in_err
|
||||
|
||||
mov esi, [cmd_args]
|
||||
test esi, esi
|
||||
jz .peek_usage_err
|
||||
|
||||
call atoi
|
||||
test eax, eax
|
||||
jz .peek_usage_err
|
||||
|
||||
cmp eax, [room_count] ; now eax = room index (1-based)
|
||||
jg .peek_bounds_err
|
||||
|
||||
; reconnect
|
||||
push eax
|
||||
call matrix_disconnect
|
||||
call init_tls
|
||||
test eax, eax
|
||||
jnz .peek_conn_err_pop
|
||||
|
||||
call matrix_connect
|
||||
test eax, eax
|
||||
jnz .peek_conn_err_pop
|
||||
pop eax
|
||||
|
||||
call matrix_peek_api
|
||||
jmp .done_cmd
|
||||
|
||||
.peek_conn_err_pop:
|
||||
pop eax
|
||||
.peek_conn_err:
|
||||
mov esi, str_conn_err
|
||||
call print_asciiz
|
||||
jmp .done_cmd
|
||||
|
||||
.peek_usage_err:
|
||||
mov esi, str_peek_usage_err
|
||||
call print_asciiz
|
||||
jmp .done_cmd
|
||||
.peek_bounds_err:
|
||||
mov esi, str_peek_bounds_err
|
||||
call print_asciiz
|
||||
jmp .done_cmd
|
||||
|
||||
.do_logout:
|
||||
cmp dword [login_status], 0
|
||||
je .already_logged_out
|
||||
mov dword [login_status], 0
|
||||
mov dword [login_status], 0
|
||||
|
||||
call matrix_disconnect
|
||||
call init_tls
|
||||
test eax, eax
|
||||
jnz .already_logged_out
|
||||
|
||||
call matrix_connect
|
||||
test eax, eax
|
||||
jnz .already_logged_out
|
||||
|
||||
call matrix_logout_api
|
||||
|
||||
call matrix_disconnect
|
||||
|
||||
.already_logged_out:
|
||||
mov esi, str_logout_msg
|
||||
call print_asciiz
|
||||
jmp .done_cmd
|
||||
|
||||
.done_cmd:
|
||||
ret
|
||||
|
||||
; basic strcmp
|
||||
; in: esi = str1, edi = str2
|
||||
; out: eax = 1 if match else 0
|
||||
streq:
|
||||
push esi edi ecx
|
||||
.str_loop:
|
||||
lodsb
|
||||
mov ah, byte [edi]
|
||||
inc edi
|
||||
cmp al, ah
|
||||
jne .not_equal
|
||||
test al, al
|
||||
jnz .str_loop
|
||||
mov eax, 1
|
||||
pop ecx edi esi
|
||||
ret
|
||||
.not_equal:
|
||||
xor eax, eax
|
||||
pop ecx edi esi
|
||||
ret
|
||||
@@ -0,0 +1,227 @@
|
||||
; window_create_textbox
|
||||
; Initialises the data structure for our multiline textbox
|
||||
;
|
||||
; in: window ptr in ebx
|
||||
; out: eax = 0 on error
|
||||
; ecx, edi = destroyed
|
||||
|
||||
window_create_textbox:
|
||||
|
||||
push ebx
|
||||
; allocate the window data block
|
||||
mcall 68, 12, sizeof.window_data
|
||||
test eax, eax
|
||||
pop ebx
|
||||
jz .fail
|
||||
|
||||
; fill it with all zeros
|
||||
push eax
|
||||
mov edi, eax
|
||||
mov ecx, (sizeof.window_data+3)/4
|
||||
xor eax, eax
|
||||
rep stosd
|
||||
pop eax
|
||||
|
||||
mov [ebx + window.data_ptr], eax
|
||||
mov [ebx + window.flags], FLAG_SCROLL_LOW
|
||||
|
||||
add eax, window_data.text+2 ; let text begin at offset 2, this way the text will be prepended with two null bytes
|
||||
mov [ebx + window.text_start], eax
|
||||
mov [ebx + window.text_print], eax
|
||||
mov [ebx + window.text_write], eax
|
||||
mov [ebx + window.text_scanned], eax
|
||||
mov [ebx + window.text_lines], 0
|
||||
mov [ebx + window.text_line_print], 0
|
||||
add eax, TEXT_BUFFERSIZE-1
|
||||
mov [ebx + window.text_end], eax
|
||||
|
||||
.fail:
|
||||
ret
|
||||
|
||||
|
||||
; window_set_name
|
||||
; Fills in the window name in window structure
|
||||
;
|
||||
; IN: esi = ptr to name
|
||||
; ebx = window ptr
|
||||
; OUT: esi = ptr to next parameter
|
||||
; ebx = window ptr
|
||||
; eax, ecx, edx, edi = destroyed
|
||||
|
||||
window_set_name:
|
||||
|
||||
lea edi, [ebx + window.name]
|
||||
mov ecx, MAX_WINDOWNAME_LEN
|
||||
.loop:
|
||||
lodsb
|
||||
cmp al, 0x21 ; name ends with 0, space or !
|
||||
jbe .addzero
|
||||
stosb
|
||||
dec ecx
|
||||
jnz .loop
|
||||
.addzero:
|
||||
xor al, al
|
||||
stosb
|
||||
|
||||
push esi ebx
|
||||
call draw_window_tabs
|
||||
pop ebx esi
|
||||
|
||||
ret
|
||||
|
||||
window_close_all:
|
||||
|
||||
.loop:
|
||||
call window_close
|
||||
|
||||
cmp [window_print], 0
|
||||
jne .loop
|
||||
|
||||
ret
|
||||
|
||||
|
||||
window_close: ; closes the 'print' window
|
||||
|
||||
; Remove the window (overwrite current structure with trailing ones)
|
||||
mov edi, [window_print]
|
||||
push [edi + window.data_ptr] ; remember data ptr so we can free it later
|
||||
lea esi, [edi + sizeof.window]
|
||||
mov ecx, windows + MAX_WINDOWS*sizeof.window
|
||||
sub ecx, esi
|
||||
rep movsb
|
||||
|
||||
; Completely zero the trailing window block (there will always be one!)
|
||||
mov ecx, sizeof.window
|
||||
xor al, al
|
||||
rep stosb
|
||||
|
||||
; Clear the window data block to erase the chat history and nicknames
|
||||
mov edi, [esp]
|
||||
mov ecx, sizeof.window_data ; TEXT_BUFFERSIZE + MAX_USERNAME_LEN * MAX_USERS
|
||||
rep stosb
|
||||
|
||||
; And now free the window data block
|
||||
pop ecx
|
||||
mcall 68, 13
|
||||
|
||||
; We closed this window so we need to show another
|
||||
; Is there still a window in the active position?
|
||||
mov edi, [window_active]
|
||||
cmp [edi + window.data_ptr], 0
|
||||
jne .redraw
|
||||
; Did we just close the last window?
|
||||
cmp edi, windows
|
||||
je .closed_last
|
||||
; Nope, move one window to the left
|
||||
sub edi, sizeof.window
|
||||
mov [window_active], edi
|
||||
mov [window_print], edi
|
||||
jmp .redraw
|
||||
|
||||
.closed_last:
|
||||
xor edi, edi
|
||||
mov [window_active], edi
|
||||
mov [window_print], edi
|
||||
|
||||
; At last, redraw everything
|
||||
.redraw:
|
||||
call draw_window
|
||||
|
||||
ret
|
||||
|
||||
|
||||
; window_find:
|
||||
; search for a window with given name in the window list
|
||||
;
|
||||
; IN: esi = ptr to start of window name
|
||||
; OUT: ebx = window ptr, or 0 if none found
|
||||
; esi = ptr to end of window name, if window was found
|
||||
|
||||
window_find:
|
||||
|
||||
mov ebx, windows
|
||||
mov eax, MAX_WINDOWS
|
||||
.scanloop:
|
||||
push esi
|
||||
cmp [ebx + window.type], WINDOWTYPE_NONE
|
||||
je .try_next
|
||||
lea edi, [ebx + window.name]
|
||||
mov ecx, MAX_WINDOWNAME_LEN
|
||||
repe cmpsb
|
||||
cmp byte[edi-1], 0 ; last equall character was null? yes, the strings match!
|
||||
je .got_it
|
||||
cmp byte[edi], 0 ; we're at the end of string1.. ?
|
||||
jne .try_next
|
||||
cmp byte[esi], 0x21 ; and the end of string2? yes!
|
||||
jbe .got_it
|
||||
.try_next:
|
||||
pop esi
|
||||
add ebx, sizeof.window
|
||||
dec eax
|
||||
jnz .scanloop
|
||||
|
||||
xor ebx, ebx
|
||||
ret
|
||||
|
||||
.got_it:
|
||||
add esp, 4
|
||||
ret
|
||||
|
||||
|
||||
|
||||
; window_open:
|
||||
; open a window with a given name, if it does not exist, create it
|
||||
; This procedure only affects window_print ptr, not window_active!
|
||||
;
|
||||
; IN: esi = ptr to ASCIIZ windowname
|
||||
; OUT: esi = ptr to next parameter
|
||||
; ebx = window ptr/0 on error
|
||||
|
||||
window_open:
|
||||
|
||||
; Skip heading spaces
|
||||
lodsb
|
||||
cmp al, ' '
|
||||
je window_open
|
||||
cmp al, ':'
|
||||
je window_open
|
||||
dec esi
|
||||
|
||||
call window_find
|
||||
test ebx, ebx
|
||||
jnz .got_it
|
||||
|
||||
; create channel window - search for empty slot
|
||||
.create_it:
|
||||
mov ebx, windows
|
||||
mov ecx, MAX_WINDOWS
|
||||
.scanloop2:
|
||||
cmp [ebx + window.type], WINDOWTYPE_NONE
|
||||
je .free_found
|
||||
add ebx, sizeof.window
|
||||
dec ecx
|
||||
jnz .scanloop2
|
||||
jmp .error
|
||||
|
||||
.free_found:
|
||||
call window_create_textbox
|
||||
test eax, eax
|
||||
jz .error
|
||||
mov [ebx + window.type], WINDOWTYPE_CHAT ; FIXME: let caller handle this ?
|
||||
|
||||
call window_set_name
|
||||
|
||||
.got_it:
|
||||
lodsb
|
||||
cmp al, ' '
|
||||
je .got_it
|
||||
cmp al, ':'
|
||||
je .got_it
|
||||
dec esi
|
||||
|
||||
mov [window_print], ebx
|
||||
ret
|
||||
|
||||
.error:
|
||||
xor ebx, ebx
|
||||
ret
|
||||
Reference in new issue
Block a user