kolibrios/kernel/branches/net/applications/ircc/serverparser.inc

934 lines
20 KiB
PHP
Raw Normal View History

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; 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 '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
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
find_window:
; mov [window_print],
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], 10 ; newline
; je server_parser.parse
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 '
; Check if it was destined for me privately
mov edi, servercommand+1
call compare_to_nick
;;; je .private
; If not, find the correct window ???
; now find the end of nick
mov edi, esi
.loop:
inc edi
cmp byte [edi], 0
je .fail
cmp byte [edi], ' '
jne .loop
.loop2:
inc edi
cmp byte [edi], 0
je .fail
cmp byte [edi], ' '
je .loop2
cmp byte [edi], ':'
je .loop2
cmp byte [edi], 1
je cmd_ctcp
; Action?
cmp dword[edi+1], 'ACTI'
je .action
; nope, just plain old privmsg
if TIMESTAMP
call print_timestamp
end if
push edi
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:
push edi
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
add esi, 8
call print_text2
mov bl, 10
call print_character
ret
cmd_ctcp:
cmp dword[edi+1], 'VERS'
je .version
cmp dword[edi+1], 'TIME'
je .time
cmp dword[edi+1], 'PING'
je .ping
ret
.time:
lea esi, [edi+1]
mov byte [edi+5], ' '
add edi, 6
; 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:
lea esi, [edi+1]
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 '
; 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
;;; TODO: dec [window.users], remove username from the userlist
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 window_set_name
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
;;; TODO: inc [window.users], add username to the userlist
ret
cmd_nick: ; FIXME
add esi, 5 ; skip 'NICK '
push esi
; test for change of my nick
mov esi, servercommand+1
mov edi, user_nick
mov ecx, MAX_NICK_LEN
rep cmpsb
cmp byte[edi-1], 0
jne .notmy
cmp byte[esi-1], '!'
jne .notmy
; yes, this is my nick, set to new
pop esi
or ecx, -1
mov edi, esi
xor eax, eax
repne scasb
neg ecx
cmp ecx, MAX_NICK_LEN
jb @f
mov ecx, MAX_NICK_LEN
@@:
mov edi, user_nick
rep movsb
.notmy:
; replace nick in all lists of users
mov ebx, windows
.channels:
mov esi, [ebx + window.data_ptr]
lea esi, [esi + window_data.names]
;;;;; mov edx, [esi + window_data.nameslen]
add edx, esi
.nicks:
mov edi, servercommand+1
cmp byte[esi], '@'
jne @f
inc esi
@@:
cmp esi, edx
jae .srcdone
lodsb
cmp al, ' '
je .srcdone
scasb
je @b
@@:
cmp esi, edx
jae .nextchannel
lodsb
cmp al, ' '
jne @b
.nextnick:
cmp esi, edx
jae .nextchannel
lodsb
cmp al, ' '
jz .nextnick
dec esi
jmp .nicks
.srcdone:
cmp byte [edi], '!'
jne .nextnick
; here we have esi -> end of nick which must be replaced to [servercommand_position]+6
lea edx, [edi-servercommand-1]
sub esi, edx
or ecx, -1
xor eax, eax
; mov edi, [servercommand_position] ;;;;; FIXME
repnz scasb
not ecx
dec ecx
push ecx
cmp ecx, edx
jb .decrease
jz .copy
.increase:
; new nick is longer than the old
push esi
lea edi, [ebx+120*10] ;;;;;;
lea esi, [edi+edx]
sub esi, ecx
mov ecx, esi
sub ecx, [esp]
dec esi
dec edi
std
rep movsb
cld
pop esi
jmp .copy
.decrease:
; new nick is shorter than the old
push esi
lea edi, [esi+ecx]
add esi, edx
lea ecx, [ebx+120*10]
sub ecx, edi
rep movsb
pop esi
.copy:
; copy nick
mov edi, esi
dec edi
; mov esi, [servercommand_position] ;;;;; FIXME
pop ecx
sub edx, ecx
sub [ebx-4], edx
rep movsb
mov al, ' '
stosb
.nextchannel:
add ebx, sizeof.window
cmp ebx, windows + sizeof.window*MAX_WINDOWS
jb .channels
; mov [text_start], window_text + 120*80
new_all_channels3:
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
; mov esi,[servercommand_position] ;;;;; FIXME
call print_text2
;;; call notify_channel_thread
; go to next window (and check if its a channel!)
; add [text_start], 120*80
; cmp [text_start], I_END+120*80*20
; jb new_all_channels3
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
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
;;; TODO: dec [window.users], remove username from the userlist
ret
cmd_quit:
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: dec [window.users], remove username from the userlist
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 '
; TODO: mark a bit that we are receiving names
; first, find the channel name
.loop1:
lodsb
cmp al, '#'
je .got_channel
test al, al
jnz .loop1
ret
.got_channel:
; call find_channel ;;;; ASSUME current channel for now
mov ebx, [window_print]
mov [ebx + window.users], 0 ;;; FIXME: Only if we have just set the receiving names bit
mov eax, [ebx + window.data_ptr]
lea edi, [eax + window_data.names]
lea edx, [edi + MAX_NICK_LEN]
; now find the semicolon separating channelname and usernames
.loop2:
lodsb
cmp al, ':'
je .namesloop
test al, al
jnz .loop2
ret
.namesloop:
; now the names list begins, separated with spaces
lodsb
test al, al
jz .done
cmp al, ' '
jz .next
stosb
jmp .namesloop
.next:
inc [ebx + window.users]
mov edi, edx
add edx, MAX_NICK_LEN
;;; cmp edi, .. ; TODO: Check for buffer overflow
jmp .namesloop
.done:
call users_calculate
call print_channel_list
ret
users_calculate:
mov eax, [ysize]
sub eax, TEXT_Y + 35 + 10 ;;;;
xor edx, edx
mov ecx, 10
div ecx
mov [scroll1.max_area], eax
mov ebx, [window_print]
mov eax, [ebx + window.users]
mov [scroll1.max_area], eax
; TODO: check if cur pos isnt greater then max
ret
cmd_366: ; channel usernames end
; TODO: clear the bit that we are receiving names
ret
cmd_topic:
add esi, 4 ; skip '332 '
.loop:
lodsb
test al, al
je .fail
cmp al, ':'
jne .loop
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
.fail:
ret
cmd_333:
add esi, 4 ; skip '333 '
; TODO: check channelname and change pointer accordingly
mov ecx, 3 ; number of spaces to find
.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
mov esi, str_newline
call print_text2
.fail:
ret