add gui implementation of matrix client for kos

This commit is contained in:
DIlkhush00 committed 2026-03-22 06:43:30 +05:30
1 parent 668ff01ef9
commit 23c943a20a
9 files changed
+2653

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
if tup.getconfig("NO_FASM") ~= "" then return end
tup.rule("matrix.asm", "fasm %f %o " .. tup.getconfig("KPACK_CMD"), "matrix")
+294
View File
@@ -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
+757
View File
@@ -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
+606
View File
@@ -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:
+9
View File
@@ -0,0 +1,9 @@
[user]
nick = makora
realname = dilkhush
partmsg = KolibriOS forever!
[colors]
action1 = 0x000000aa
action2 = 0x0000aa00
action3 = 0x00aa0000
+22
View File
@@ -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
+463
View File
@@ -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
+273
View File
@@ -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
+227
View File
@@ -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