;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; 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] mov edx, edi ; now find the semicolon separating channelname and usernames .loop2: lodsb cmp al, ':' je .newname test al, al jnz .loop2 ret .next: add edx, MAX_NICK_LEN mov edi, edx ;;; cmp edi, .. ; TODO: Check for buffer overflow .newname: inc [ebx + window.users] .namesloop: ; now the names list begins, separated with spaces lodsb test al, al jz .done cmp al, ' ' jz .next stosb jmp .namesloop .done: call redraw_channel_list 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