0,0 → 1,928 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
|
server_parser: |
|
mov esi, servercommand |
|
cmp byte [esi], ':' |
jne .parse |
|
.spaceloop: |
lodsb |
test al, al |
jz .fail |
cmp al, ' ' |
jne .spaceloop |
|
.parse: |
mov eax, [esi] |
or eax, 0x20202020 |
mov edi, server_commands |
mov ecx, server_commands.number |
|
.loop: |
scasd |
je .got_cmd |
add edi, 4 |
dec ecx |
jnz .loop |
|
.fail: |
ret |
|
.got_cmd: |
jmp dword[edi] |
|
|
server_commands: |
|
dd '322 ', cmd_322 ; RPL_LIST |
dd '323 ', cmd_323 ; RPL_LISTEND |
dd '328 ', cmd_328 |
dd '332 ', cmd_topic |
dd '333 ', cmd_333 ; nickname and time of topic |
dd '353 ', cmd_353 ; name reply |
dd '366 ', cmd_366 ; end of names list |
dd '372 ', cmd_372 ; motd |
dd '375 ', cmd_375 ; start of motd |
dd '376 ', cmd_376 ; end of motd |
dd '421 ', cmd_421 ; unknown command |
dd 'join', cmd_join |
dd 'kick', cmd_kick |
dd 'mode', cmd_mode |
dd 'nick', cmd_nick |
dd 'part', cmd_part |
dd 'ping', cmd_ping |
dd 'priv', cmd_privmsg |
dd 'quit', cmd_quit |
dd 'noti', cmd_notice |
|
.number = ($ - server_commands) / 8 |
|
|
align 4 |
compare_to_nick: |
|
push esi |
mov ecx, MAX_NICK_LEN |
mov esi, user_nick |
.loop: |
lodsb |
cmp al, ' ' |
jbe .done |
cmp al, 'a' |
jb .ok |
cmp al, 'z' |
ja .ok |
sub al, 0x20 |
.ok: |
|
mov bl, byte[edi] |
cmp bl, 'a' |
jb .ok2 |
cmp bl, 'z' |
ja .ok2 |
sub bl, 0x20 |
.ok2: |
cmp bl, al |
jne .not_equal |
inc edi |
dec ecx |
jnz .loop |
|
.done: |
xor eax, eax |
pop esi |
ret |
|
.not_equal: |
or eax, -1 |
pop esi |
ret |
|
align 4 |
skip_nick: |
|
; First: skip the NICK (maybe we should verify it?) |
.nick: |
lodsb |
cmp al, ' ' |
je .skip |
cmp al, ':' |
je .skip |
jmp .nick |
|
; skip all leading spaces and semicolons |
.skip: |
lodsb |
cmp al, ' ' |
je .skip |
cmp al, ':' |
je .skip |
dec esi |
|
ret |
|
|
align 4 |
find_window: ; esi is ptr to windowname |
|
push esi |
|
mov edi, esi |
call compare_to_nick |
jne .nochat |
|
mov esi, servercommand+1 |
.nochat: |
|
; now search for window in list |
mov ebx, windows |
mov [window_print], ebx ; set first window (server window) as default output window |
.scanloop: |
cmp [ebx + window.data_ptr], 0 |
je .create_it |
push esi |
lea edi, [ebx + window.name] |
mov ecx, MAX_WINDOWNAME_LEN |
repe cmpsb |
pop esi |
cmp byte[edi-1], 0 |
je .got_it |
add ebx, sizeof.window |
; TODO: check buffer limits ? |
jmp .scanloop |
|
; create channel window - search for empty slot |
.create_it: |
mov ebx, windows |
mov ecx, MAX_WINDOWS |
.scanloop2: |
cmp [ebx + window.data_ptr], 0 |
je .free_found |
add ebx, sizeof.window |
dec ecx |
jnz .scanloop2 |
; Error: no more available windows! |
jmp .just_skip |
|
.free_found: |
push ebx |
call window_create |
pop ebx |
test eax, eax |
jz .just_skip |
mov [ebx + window.data_ptr], eax |
mov [ebx + window.type], WINDOWTYPE_CHAT |
mov [ebx + window.flags], 0 |
|
call window_set_name |
|
mov [window_open], ebx |
mov [window_print], ebx |
call window_refresh |
|
call draw_windownames |
jmp .just_skip |
|
; found it! |
.got_it: |
mov [window_print], ebx |
call window_refresh |
|
.just_skip: |
pop esi |
.skip1: |
; skip text |
lodsb |
test al, al |
jz .quit |
cmp al, ' ' |
jne .skip1 |
dec esi |
; now skip trailing spaces and semicolons |
.skip2: |
lodsb |
test al, al |
jz .quit |
cmp al, ' ' |
je .skip2 |
cmp al, ':' |
je .skip2 |
dec esi |
|
.quit: |
ret |
|
|
|
|
|
|
cmd_328: |
cmd_421: |
cmd_372: |
cmd_375: |
cmd_376: |
add esi, 4 |
jmp cmd_notice.loop |
|
cmd_notice: |
|
cmp byte[servercommand], ':' |
jne .gogogo |
|
mov byte [esi-1], 0 |
push esi |
mov esi, str_1 |
call print_text2 |
mov esi, servercommand+1 |
call print_text2 |
mov esi, str_2 |
call print_text2 |
pop esi |
|
.gogogo: |
add esi, 6 |
|
.loop: |
inc esi |
cmp byte [esi], 0 |
je .fail |
cmp byte [esi], ' ' |
jne .loop |
|
.loop2: |
inc esi |
cmp byte [esi], 0 |
je .fail |
cmp byte [esi], ' ' |
je .loop2 |
cmp byte [esi], ':' |
je .loop2 |
|
call print_text2 |
mov esi, str_newline |
call print_text2 |
|
.fail: |
|
ret |
|
|
|
cmd_ping: |
|
; Just change PING to PONG |
mov dword[esi], 'PONG' |
|
; Find the end of the command |
lea edi, [esi + 5] |
xor al, al |
repne scasb |
|
; Now send it back |
mov edx, esi |
mov esi, edi |
mov word [esi], 0x0d0a |
inc esi |
inc esi |
sub esi, edx |
mcall send, [socketnum], , , 0 |
|
ret |
|
|
|
cmd_privmsg: |
|
add esi, 8 ; skip 'PRIVMSG ' |
call find_window ; esi now points to end of destination name |
|
cmp byte[esi], 1 |
je cmd_ctcp |
|
cmp dword[esi], 'ACTI' ; Action? |
je .action |
|
; nope, just plain old privmsg |
if TIMESTAMP |
call print_timestamp |
end if |
|
push esi |
mov bl, '<' |
call print_character |
|
mov eax, servercommand+1 |
mov dl, '!' |
call print_text |
|
mov bl, '>' |
call print_character |
|
mov bl, ' ' |
call print_character |
|
pop esi |
call print_text2 |
|
mov bl, 10 |
call print_character |
|
.fail: |
ret |
|
.action: |
add esi, 8 |
push esi |
if TIMESTAMP |
call print_timestamp |
end if |
|
mov esi, action_header_short |
call print_text2 |
|
mov eax, servercommand+1 |
mov dl, ' ' |
call print_text |
|
mov bl, ' ' |
call print_character |
|
pop esi |
call print_text2 |
|
mov bl, 10 |
call print_character |
|
ret |
|
cmd_ctcp: |
inc esi |
|
cmp dword[esi], 'VERS' |
je .version |
|
cmp dword[esi], 'TIME' |
je .time |
|
cmp dword[esi], 'PING' |
je .ping |
|
ret |
|
.time: |
mov byte [esi+4], ' ' |
lea edi, [esi+5] |
|
; TODO: add system date (fn 29) in human readable format |
|
mcall 3 ; get system time |
|
mov ecx, 3 |
.timeloop: |
mov bl, al |
shr al, 4 |
add al, '0' |
stosb |
|
mov al, bl |
and al, 0x0f |
add al, '0' |
stosb |
|
dec ecx |
jz .timedone |
|
mov al, ':' |
stosb |
shr eax, 8 |
jmp .timeloop |
|
.timedone: |
xor al, al |
stosb |
call ctcp_reply |
|
if TIMESTAMP |
call print_timestamp |
end if |
|
mov esi, ctcp_header |
call print_text2 |
|
mov esi, servercommand+1 |
call print_text2 |
|
mov esi, ctcp_time |
call print_text2 |
|
ret |
|
.version: |
mov esi, str_version |
call ctcp_reply |
|
if TIMESTAMP |
call print_timestamp |
end if |
|
mov esi, ctcp_header |
call print_text2 |
|
mov esi, servercommand+1 |
call print_text2 |
|
mov esi, ctcp_version |
call print_text2 |
|
ret |
|
.ping: |
call ctcp_reply |
|
if TIMESTAMP |
call print_timestamp |
end if |
|
mov esi, ctcp_header |
call print_text2 |
|
mov esi, servercommand+1 |
call print_text2 |
|
mov esi, ctcp_ping |
call print_text2 |
|
ret |
|
|
|
ctcp_reply: |
|
push esi |
|
mov dword [usercommand], 'NOTI' |
mov dword [usercommand+4], 'CE ' |
|
mov esi, servercommand+1 |
mov edi, usercommand+7 |
.nickloop: |
lodsb |
cmp al, '!' |
je .done |
cmp al, ' ' |
je .done |
test al, al |
je .fail |
stosb |
jmp .nickloop |
.done: |
mov byte [esi-1], 0 |
mov ax, ' :' |
stosw |
mov al, 1 |
stosb |
|
pop esi |
.replyloop: |
lodsb |
cmp al, 1 |
jbe .done2 |
stosb |
jmp .replyloop |
.done2: |
|
mov al, 1 |
stosb |
mov ax, 0x0a0d |
stosw |
|
lea esi, [edi - usercommand] |
mcall send, [socketnum], usercommand, , 0 |
.fail: |
ret |
|
|
|
cmd_part: |
add esi, 5 ; skip 'PART ' |
push esi |
call skip_nick |
call find_window |
pop esi |
|
; Is it me who parted? |
mov edi, servercommand+1 |
call compare_to_nick |
jne .dont_close |
|
; yes, close the window |
mov edi, [window_print] |
mov [edi + window.flags], FLAG_UPDATED + FLAG_CLOSE |
|
ret |
|
; somebody else parted, just print message |
.dont_close: |
push esi |
mov esi, action_header |
call print_text2 |
|
mov eax, servercommand+1 |
mov dl, '!' |
mov cl, ' ' |
call print_text |
|
mov esi, has_left_channel |
call print_text2 |
|
pop esi |
call print_text2 |
|
mov esi, str_newline |
call print_text2 |
|
mov ebx, [window_print] |
mov esi, servercommand+1 |
call user_remove |
|
ret |
|
|
|
cmd_join: |
add esi, 5 ; skip 'JOIN ' |
|
; compare nick: did we join a channel? |
mov edi, servercommand+1 |
call compare_to_nick |
jne .no_new_window |
|
; create channel window - search for empty slot |
mov ebx, windows |
mov ecx, MAX_WINDOWS |
.loop: |
cmp [ebx + window.data_ptr], 0 |
je .free_found |
add ebx, sizeof.window |
dec ecx |
jnz .loop |
; Error: no more available windows!! ;;;;; TODO |
.fail: |
ret |
|
.free_found: |
push ebx |
call window_create |
pop ebx |
test eax, eax |
jz .fail |
mov [ebx + window.data_ptr], eax |
mov [ebx + window.type], WINDOWTYPE_CHANNEL |
mov [ebx + window.flags], 0 |
|
call window_set_name |
|
mov [window_open], ebx |
mov [window_print], ebx |
call window_refresh |
|
push esi |
mov esi, action_header |
call print_text2 |
|
mov esi, str_talking |
call print_text2 |
|
pop eax |
mov dl, ' ' |
call print_text |
|
mov esi, str_dotnewline |
call print_text2 |
|
call draw_window |
|
ret |
|
.no_new_window: |
push esi |
call find_window |
|
mov esi, action_header |
call print_text2 |
|
mov eax, servercommand+1 |
mov dl, '!' |
call print_text |
|
mov esi, joins_channel |
call print_text2 |
|
pop esi |
call print_text2 |
|
mov esi, str_newline |
call print_text2 |
|
mov ebx, [window_print] |
mov esi, servercommand+1 |
call user_add |
|
ret |
|
|
|
|
cmd_nick: |
; NOTE: This command applies to a user, and thus has no specific channel |
add esi, 5 ; skip 'NICK ' |
|
cmp byte[esi], ':' ; TODO: skip all spaces and semicolons? |
jne @f |
inc esi |
@@: |
|
; Change the nick in the current userlist. TODO: check other channels too! |
push esi |
mov ebx, [window_print] |
|
mov esi, servercommand+1 |
call user_remove |
|
mov esi, [esp] |
call user_add |
|
call redraw_channel_list |
|
; Is it me who changed nick? |
mov edi, servercommand+1 |
call compare_to_nick |
pop esi |
jne .not_me |
|
mov ecx, MAX_NICK_LEN-1 |
push esi |
.copyloop: |
lodsb |
test al, al |
jz .copydone |
cmp al, ' ' |
je .copydone |
stosb |
dec ecx |
jnz .copyloop |
.copydone: |
xor al, al |
stosb |
pop esi |
.not_me: |
|
; Now print a message on the current channel |
push esi |
mov esi, action_header_short |
call print_text2 |
|
mov eax, servercommand+1 |
mov dl, '!' |
call print_text |
|
mov esi, is_now_known_as |
call print_text2 |
|
pop esi |
call print_text2 |
|
mov esi, str_newline |
call print_text2 |
|
ret |
|
|
|
|
cmd_kick: |
add esi, 5 ; skip 'KICK ' |
; Is it me who got kicked? |
mov edi, servercommand+1 |
call compare_to_nick |
jne .not_me |
|
; TODO: mark channel as disconnected |
|
.not_me: |
; find the channel user has been kicked from |
push esi |
call skip_nick |
call find_window |
|
mov esi, action_header_short |
call print_text2 |
|
mov eax, servercommand+1 |
mov dl, '!' |
call print_text |
|
mov esi, kicked |
call print_text2 |
|
pop esi |
call print_text2 |
|
mov esi, str_newline |
call print_text2 |
|
mov ebx, [window_print] |
mov esi, servercommand+1 |
call user_remove |
|
ret |
|
|
|
cmd_quit: |
; NOTE: This command applies to a user, and thus has no specific channel |
|
mov esi, action_header |
call print_text2 |
|
mov eax, servercommand+1 |
mov dl, '!' |
call print_text |
|
mov esi, has_quit_irc |
call print_text2 |
|
; TODO: check other channels on same server too! |
mov ebx, [window_print] |
mov esi, servercommand+1 |
call user_remove |
|
ret |
|
|
|
cmd_mode: |
|
add esi, 5 ; skip 'MODE ' |
|
push esi |
mov esi, action_header_short |
call print_text2 |
|
mov eax, servercommand+1 |
mov dl, ' ' |
call print_text |
|
mov esi, sets_mode |
call print_text2 |
|
pop esi |
call print_text2 |
|
mov esi, str_newline |
call print_text2 |
|
;;; TODO: change username if needed |
|
ret |
|
|
cmd_353: ; channel usernames reply |
|
add esi, 4 ; skip '353 ' |
call skip_nick |
inc esi ; channel type '*', '=' or '@' |
inc esi ; ' ' |
call find_window |
|
; now find window ptr and check if this is the first 353 message |
mov ebx, [window_print] |
test [ebx + window.flags], FLAG_RECEIVING_NAMES |
jnz .add |
|
or [ebx + window.flags], FLAG_RECEIVING_NAMES |
; mov [ebx + window.users], 0 |
; TODO: remove all users? |
|
.add: |
push esi |
call user_add |
pop esi |
|
.namesloop: |
lodsb |
test al, al |
jz .done |
cmp al, ' ' ; names list is separated with spaces |
jne .namesloop |
jmp .add |
|
.done: |
call redraw_channel_list |
|
ret |
|
|
|
|
|
cmd_366: ; channel usernames end |
|
add esi, 4 ; skip '366 ' |
call skip_nick |
call find_window |
|
mov ebx, [window_print] |
and [ebx + window.flags], not FLAG_RECEIVING_NAMES |
|
ret |
|
|
|
|
cmd_topic: |
|
add esi, 4 ; skip '332 ' |
call skip_nick |
call find_window |
|
push esi |
mov esi, action_header |
call print_text2 |
|
mov esi, str_topic |
call print_text2 |
|
pop esi |
call print_text2 |
|
mov esi, str_newline |
call print_text2 |
|
ret |
|
|
cmd_333: |
|
add esi, 4 ; skip '333 ' |
call skip_nick ;;;; |
call find_window |
|
; mov ecx, 2 ; number of spaces to find ;;; CHECKME |
; .loop: |
; lodsb |
; test al, al |
; je .fail |
; cmp al, ' ' |
; jne .loop |
; dec ecx |
; jnz .loop ; find some more spaces |
|
push esi |
mov esi, action_header |
call print_text2 |
|
mov esi, str_setby |
call print_text2 |
|
; pop esi |
; call print_text2 |
|
pop eax |
mov dl, '!' |
call print_text |
|
mov esi, str_newline |
call print_text2 |
|
.fail: |
ret |
|
cmd_322: |
add esi, 4 |
|
call skip_nick |
|
call print_text2 |
|
mov esi, str_newline |
call print_text2 |
|
ret |
|
cmd_323: |
|
ret |