Subversion Repositories Kolibri OS

Compare Revisions

No changes between revisions

Regard whitespace Rev 3544 → Rev 3545

/programs/network/ircc/encodings.inc
0,0 → 1,317
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; 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 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 
get_next_byte:
; Load next byte from the packet, translating to cp866 if necessary
; At input esi = pointer to data, edx = limit of data
; Output is either (translated) byte in al with CF set or CF cleared.
mov eax, [encoding]
jmp [get_byte_table+eax*4]
 
get_byte_cp866:
cmp esi, edx
jae .nothing
lodsb
.nothing:
ret
 
get_byte_cp1251:
cmp esi, edx
jae .nothing
lodsb
cmp al, 0x80
jb @f
and eax, 0x7F
mov al, [cp1251_table+eax]
@@:
stc
.nothing:
ret
 
get_byte_utf8:
; UTF8 decoding is slightly complicated.
; One character can occupy one or more bytes.
; The boundary in packets theoretically can be anywhere in data,
; so this procedure keeps internal state between calls and handles
; one byte at a time, looping until character is read or packet is over.
; Globally, there are two distinct tasks: decode byte sequence to unicode char
; and convert this unicode char to our base encoding (that is cp866).
; 1. Check that there are data.
cmp esi, edx
jae .nothing
; 2. Load byte.
lodsb
movzx ecx, al
; 3. Bytes in an UTF8 sequence can be of any of three types.
; If most significant bit is cleared, sequence is one byte and usual ASCII char.
; First byte of a sequence must be 11xxxxxx, other bytes are 10yyyyyy.
and al, 0xC0
jns .single_byte
jp .first_byte
; 4. This byte is not first in UTF8 sequence.
; 4a. Check that the sequence was started. If no, it is invalid byte
; and we simply ignore it.
cmp [utf8_bytes_rest], 0
jz get_byte_utf8
; 4b. Otherwise, it is really next byte and it gives some more bits of char.
mov eax, [utf8_char]
shl eax, 6
lea eax, [eax+ecx-0x80]
; 4c. Decrement number of bytes rest in the sequence.
; If it goes to zero, character is read, so return it.
dec [utf8_bytes_rest]
jz .got_char
mov [utf8_char], eax
jmp get_byte_utf8
; 5. If the byte is first in UTF8 sequence, calculate the number of leading 1s
; - it equals total number of bytes in the sequence; some other bits rest for
; leading bits in the character.
.first_byte:
mov eax, -1
@@:
inc eax
add cl, cl
js @b
mov [utf8_bytes_rest], eax
xchg eax, ecx
inc ecx
shr al, cl
mov [utf8_char], eax
jmp get_byte_utf8
; 6. If the byte is ASCII char, it is the character.
.single_byte:
xchg eax, ecx
.got_char:
; We got the character, now abandon a possible sequence in progress.
and [utf8_bytes_rest], 0
; Now second task. The unicode character is in eax, and now we shall convert it
; to cp866.
cmp eax, 0x80
jb .done
; 0x410-0x43F -> 0x80-0xAF, 0x440-0x44F -> 0xE0-0xEF, 0x401 -> 0xF0, 0x451 -> 0xF1
cmp eax, 0x401
jz .YO
cmp eax, 0x451
jz .yo
cmp eax, 0x410
jb .unrecognized
cmp eax, 0x440
jb .part1
cmp eax, 0x450
jae .unrecognized
sub al, (0x40-0xE0) and 0xFF
ret
.part1:
sub al, 0x10-0x80
.nothing:
.done:
ret
.unrecognized:
mov al, '?'
stc
ret
.YO:
mov al, 0xF0
stc
ret
.yo:
mov al, 0xF1
stc
ret
 
 
 
print_character:
 
pusha
 
cmp bl, 13 ; line beginning
jne nobol
 
mov ecx, [pos]
inc ecx
boll1:
dec ecx
mov eax, ecx
xor edx, edx
mov ebx, [textbox_width]
div ebx
test edx, edx
jnz boll1
mov [pos], ecx
jmp newdata
nobol:
 
cmp bl, 10 ; line down
jne nolf
 
addx1:
inc [pos]
mov eax, [pos]
xor edx, edx
mov ecx, [textbox_width]
div ecx
test edx, edx
jnz addx1
mov eax, [pos]
jmp cm1
nolf:
no_lf_ret:
 
 
cmp bl, 15 ; character
jbe newdata
 
mov eax, [irc_data]
shl eax, 8
mov al, bl
mov [irc_data], eax
 
mov eax, [pos]
;---- draw data
pusha
 
and ebx, 0xff
add eax, [text_start]
mov [eax], bl
 
popa
;---- draw data
 
mov eax, [pos]
inc eax
cm1:
mov ebx, [scroll+4]
imul ebx, [textbox_width]
cmp eax, ebx
jb noeaxz
 
mov esi, [text_start]
add esi, [textbox_width]
 
mov edi, [text_start]
mov ecx, ebx
rep movsb
 
mov esi, [text_start]
mov ecx, [textbox_width]
imul ecx, 61
add esi, ecx
 
mov edi, [text_start]
mov ecx, [textbox_width]
imul ecx, 60
add edi, ecx
mov ecx, ebx
rep movsb
 
mov eax, ebx
sub eax, [textbox_width]
noeaxz:
mov [pos], eax
 
newdata:
mov eax, [window_print]
or [eax + window.flags], FLAG_UPDATED
 
popa
ret
 
 
 
recode_to_cp866:
rep movsb
ret
 
recode_to_cp1251:
xor eax, eax
jecxz .nothing
.loop:
lodsb
cmp al,0x80
jb @f
mov al, [cp866_table-0x80+eax]
@@: stosb
loop .loop
.nothing:
ret
 
recode_to_utf8:
jecxz .nothing
.loop:
lodsb
cmp al, 0x80
jb .single_byte
and eax, 0x7F
mov ax, [utf8_table+eax*2]
stosw
loop .loop
ret
.single_byte:
stosb
loop .loop
.nothing:
ret
 
recode:
mov eax, [encoding]
jmp [recode_proc+eax*4]
 
 
 
encoding dd UTF8
recode_proc dd recode_to_cp866, recode_to_cp1251, recode_to_utf8
get_byte_table dd get_byte_cp866, get_byte_cp1251, get_byte_utf8
 
 
cp1251_table:
db '?','?','?','?','?','?','?','?' , '?','?','?','?','?','?','?','?' ; 8
db '?','?','?','?','?',$F9,'?','?' , '?','?','?','?','?','?','?','?' ; 9
db '?',$F6,$F7,'?',$FD,'?','?','?' , $F0,'?',$F2,'?','?','?','?',$F4 ; A
db $F8,'?','?','?','?','?','?',$FA , $F1,$FC,$F3,'?','?','?','?',$F5 ; B
db $80,$81,$82,$83,$84,$85,$86,$87 , $88,$89,$8A,$8B,$8C,$8D,$8E,$8F ; C
db $90,$91,$92,$93,$94,$95,$96,$97 , $98,$99,$9A,$9B,$9C,$9D,$9E,$9F ; D
db $A0,$A1,$A2,$A3,$A4,$A5,$A6,$A7 , $A8,$A9,$AA,$AB,$AC,$AD,$AE,$AF ; E
db $E0,$E1,$E2,$E3,$E4,$E5,$E6,$E7 , $E8,$E9,$EA,$EB,$EC,$ED,$EE,$EF ; F
 
; 0 1 2 3 4 5 6 7 8 9 A B C D E F
 
utf8_table:
times 80h dw 0x98C3 ; default placeholder
 
; 0x80-0xAF -> 0x90D0-0xBFD0
repeat 0x30
store byte 0xD0 at utf8_table+2*(%-1)
store byte 0x90+%-1 at utf8_table+2*%-1
end repeat
 
; 0xE0-0xEF -> 0x80D1-0x8FD1
repeat 0x10
store byte 0xD1 at utf8_table+2*(0xE0-0x80+%-1)
store byte 0x80+%-1 at utf8_table+2*(0xE0-0x80+%)-1
end repeat
 
; 0xF0 -> 0x81D0, 0xF1 -> 0x91D1
store dword 0x91D181D0 at utf8_table+2*(0xF0-0x80)
 
cp866_table:
db $C0,$C1,$C2,$C3,$C4,$C5,$C6,$C7 , $C8,$C9,$CA,$CB,$CC,$CD,$CE,$CF ; 8
db $D0,$D1,$D2,$D3,$D4,$D5,$D6,$D7 , $D8,$D9,$DA,$DB,$DC,$DD,$DE,$DF ; 9
db $E0,$E1,$E2,$E3,$E4,$E5,$E6,$E7 , $E8,$E9,$EA,$EB,$EC,$ED,$EE,$EF ; A
db '?','?','?','?','?','?','?','?' , '?','?','?','?','?','?','?','?' ; B
db '?','?','?','?','?','?','?','?' , '?','?','?','?','?','?','?','?' ; C
db '?','?','?','?','?','?','?','?' , '?','?','?','?','?','?','?','?' ; D
db $F0,$F1,$F2,$F3,$F4,$F5,$F6,$F7 , $F8,$F9,$FA,$FB,$FC,$FD,$FE,$FF ; E
db $A8,$B8,$AA,$BA,$AF,$BF,$A1,$A2 , $B0,$95,$B7,'?',$B9,$A4,'?','?' ; F
 
; 0 1 2 3 4 5 6 7 8 9 A B C D E F
 
/programs/network/ircc/gui.inc
0,0 → 1,316
draw_window:
 
pusha
 
mcall 9, thread_info, -1 ; get current window size
mov eax, dword[thread_info+42] ; window xsize
mov ebx, dword[thread_info+46] ; ysize
mov edx, dword[thread_info+62] ; work area xsize
mov esi, dword[thread_info+66] ; 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
 
mcall 12, 1
xor eax, eax ; draw window
mov ebx, WIN_MIN_X
mov ecx, WIN_MIN_Y
mov edx, [colors.work]
add edx, 0x33000000
mov edi, str_programname
mcall
mcall 12, 2 ;; when do we actually need this??
 
mov ebx, [xsize]
mov ecx, [ysize]
sub cx, 15 ;;;;
push cx
shl ecx, 16
pop cx
mov edx, [colors.work_graph]
mcall 38 ; draw line
 
mov ecx, TOP_Y SHL 16 + TOP_Y
mcall
 
mov edi, [window_open]
cmp [edi + window.type], WINDOWTYPE_CHANNEL
jne .not_channel
 
; draw a vertical separator line
mov ebx, [xsize]
sub ebx, USERLIST_X + SCROLLBAR_WIDTH + 3
push bx
shl ebx, 16
pop bx
mov ecx, [ysize]
add ecx, TOP_Y SHL 16 -(15) ;;;;
mcall
 
call redraw_channel_list
 
.not_channel:
mov edx, [edi + window.data_ptr]
add edx, window_data.text
call draw_channel_text
 
; editbox
 
mov eax, [ysize]
sub eax, 12 ;;;;;;
mov [edit1.top], eax
 
mov eax, [xsize]
mov [edit1.width], eax
 
push dword edit1
call [edit_box_draw]
 
; tabs
 
call draw_windownames
 
popa
ret
 
 
 
redraw_channel_list:
 
; First, calculate scrollbar
 
mov ebx, [window_open]
mov eax, [ebx + window.users] ; number of users in the open window
mov [scroll1.max_area], eax
 
mov eax, [ysize]
sub eax, TOP_Y + 15 ;;;;
push eax
mov [scroll1.y_size], ax
 
mov eax, [xsize]
sub eax, SCROLLBAR_WIDTH
mov [scroll1.x_pos], ax
 
pop eax ; scrollbar height
xor edx, edx
mov ecx, 10
div ecx
mov [scroll1.cur_area], eax
 
; Do we need a scrollbar?
cmp eax, [scroll1.max_area]
jae .noscroll
 
; Is the current position greater then the max position?
cmp eax, [scroll1.position]
ja @f
mov [scroll1.position], eax
@@:
 
; OK, draw the scrollbar
mov [scroll1.all_redraw], 1
 
push dword scroll1
call [scrollbar_v_draw]
 
jmp print_channel_list
 
.noscroll:
mov [scroll1.position], 0
 
 
 
print_channel_list:
 
pusha
; Now, draw the usernames themselves
 
; first, draw an invisible button
mov ebx, [xsize]
sub ebx, USERLIST_X + SCROLLBAR_WIDTH
shl ebx, 16
push ebx
mov bx, USERLIST_X
mov ecx, [ysize]
add ecx, TEXT_Y shl 16 - (TEXT_Y + 15) ;;;;; + 10???
push ecx ebx
mov edx, 50 + 1 shl 29 + 1 shl 30
mcall 8
 
; now draw rectangle to clear the names
pop ebx ecx
mov edx, [colors.work]
mcall 13
 
; now draw the names according with scrollbar position and window size
mov eax, [scroll1.position]
xor edx, edx
mov ecx, MAX_NICK_LEN
mul ecx
mov edx, eax
mov eax, [window_open]
mov ebp, [eax + window.selected]
add edx, [eax + window.data_ptr]
sub ebp, [scroll1.position]
add edx, window_data.names
 
pop ebx
mov bx, TEXT_Y
mov ecx, [colors.work_text]
or ecx, 0x80000000 ; ASCIIZ string
mov eax, 4 ; draw text
 
mov edi, [ysize] ; Calculate how many names will fit on screen
sub edi, TEXT_Y + 15 ;+ 10 ;;;;;
.loop:
cmp byte[edx], 0 ; end of list?
je .done
 
dec ebp ; is this name selected?
jnz .nothighlight
; yes, highlight it
pusha
mov cx, bx
mov bx, USERLIST_X
shl ecx, 16
mov cx, 10 - 1
mov edx, 0x00000055 ; blue!
mcall 13
popa
 
mov ecx, 0x8000ffff ; cyan!
mcall
 
mov ecx, [colors.work_text]
or ecx, 0x80000000 ; ASCIIZ string
jmp .next
 
.nothighlight:
mcall
 
.next:
add edx, MAX_NICK_LEN ; next name
add ebx, 10 ; height distance between lines
sub edi, 10
ja .loop
 
.done:
popa
 
ret
 
 
 
 
draw_channel_text:
 
pusha
 
mov eax, 4 ; draw text
mov ebx, TEXT_X shl 16 + TEXT_Y
mov ecx, 12 ; 12 lines max ?
mov esi, [textbox_width]
 
.dct:
pusha
mov cx, bx
shl ecx, 16
mov cx, 9 ; character height
mov eax, 13 ; draw rectangle
mov ebx, TEXT_X shl 16
mov bx, word[textbox_width]
imul bx, 6 ; character width
mov edx, [colors.work]
mcall
popa
 
push ecx
mov ecx, [colors.work_text]
cmp word[edx], '* '
jne .no_red
mov ecx, 0x00aa0000
jmp .draw
.no_red:
 
cmp word[edx], '**'
jne .no_light_blue
cmp byte[edx+2], '*'
jne .no_light_blue
mov ecx, 0x000000aa
jmp .draw
.no_light_blue:
 
cmp byte[edx], '#'
jne .no_blue
mov ecx, 0x0000aa00
; jmp .draw
.no_blue:
 
.draw:
mcall
add edx, [textbox_width]
add ebx, 10 ; height distance between lines
 
pop ecx
loop .dct
 
popa
ret
 
 
 
draw_windownames:
 
mov eax, 8
mov ebx, 5 shl 16 + 120
mov ecx, 12 shl 16 + 12
mov edx, WINDOW_BTN_START
mov edi, windows
.more_btn:
mov esi, [colors.work_button]
cmp [window_open], edi
jne @f
not esi
and esi, 0x00ffffff
@@:
mcall
inc edx
add ebx, 125 shl 16
add edi, sizeof.window
cmp [edi + window.data_ptr], 0
jne .more_btn
 
mov eax, 4
mov ebx, 10 shl 16 + 15
mov ecx, [colors.work_button_text]
or ecx, 0x80000000 ; ASCIIZ string
lea edx, [windows + window.name]
mov esi, MAX_WINDOWS
.more:
mcall
add edx, sizeof.window
cmp byte[edx], 0
je .enough
add ebx, 125 shl 16
dec esi
jnz .more
.enough:
 
ret
 
 
/programs/network/ircc/ircc.asm
0,0 → 1,476
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; IRC client for KolibriOS ;;
;; ;;
;; Written by hidnplayr@kolibrios.org, ;;
;; text encoder/decoder by Clevermouse. ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
version equ '0.1'
 
; connection status
STATUS_DISCONNECTED = 0
STATUS_RESOLVING = 1
STATUS_CONNECTING = 2
STATUS_CONNECTED = 3
 
; window flags
FLAG_UPDATED = 1 shl 0
FLAG_CLOSE = 1 shl 1
FLAG_RECEIVING_NAMES = 1 shl 2
 
; window types
WINDOWTYPE_SERVER = 0
WINDOWTYPE_CHANNEL = 1
WINDOWTYPE_CHAT = 2
WINDOWTYPE_LIST = 3
WINDOWTYPE_DCC = 4
 
; supported encodings
CP866 = 0
CP1251 = 1
UTF8 = 2
 
; settings
USERCMD_MAX_SIZE = 400
 
WIN_MIN_X = 600
WIN_MIN_Y = 165
 
TEXT_X = 5
TEXT_Y = 30
 
TOP_Y = 25
 
MAX_WINDOWS = 20
MAX_USERS = 4096
 
MAX_NICK_LEN = 32
MAX_REAL_LEN = 32 ; realname
MAX_SERVER_NAME = 256
 
MAX_CHANNEL_LEN = 40
MAX_CHANNELS = 37
 
MAX_COMMAND_LEN = 512
 
TIMESTAMP = 3 ; 3 = hh:mm:ss, 2 = hh:mm, 0 = no timestamp
 
MAX_WINDOWNAME_LEN = 256
 
WINDOW_BTN_START = 100
 
SCROLLBAR_WIDTH = 12
 
USERLIST_X = 98
 
 
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+2048 ; required amount of memory
dd IM_END+2048
dd param
dd path
 
include "../macros.inc"
include "../proc32.inc"
include "../dll.inc"
include "../network.inc"
include "../struct.inc"
include '../../../../../programs/develop/libraries/box_lib/trunk/box_lib.mac'
 
struct window
data_ptr dd ? ; zero if not used
flags db ?
type db ?
name rb MAX_WINDOWNAME_LEN
users dd ?
users_scroll dd ?
selected dd ? ; selected user, 0 if none selected
ends
 
struct window_data
text rb 120*60
title rb 256
names rb MAX_NICK_LEN * MAX_USERS
usertext rb 256
usertextlen dd ?
ends
 
include "encodings.inc"
include "window.inc" ; also contains text print routines
include "serverparser.inc"
include "userparser.inc"
include "socket.inc"
include "gui.inc"
include "users.inc"
 
 
START:
 
mcall 68, 11 ; init heap so we can allocate memory dynamically
 
; wanted events
mcall 40, EVM_REDRAW + EVM_KEY + EVM_BUTTON + EVM_STACK + EVM_MOUSE
 
; load libraries
stdcall dll.Load, @IMPORT
test eax, eax
jnz exit
 
; find path to main settings file (ircc.ini)
mov edi, path ; Calculate the length of zero-terminated string
xor al, al
mov ecx, 1024
repne scasb
dec edi
mov eax, '.ini'
stosd
xor al, al
stosb
 
; Fill the window buffer with zeros
mov edi, windows
mov ecx, (sizeof.window*MAX_WINDOWS+3)/4
xor eax, eax
rep stosd
 
; clear command area too
mov edi, servercommand
mov ecx, 600/4
rep stosd
 
; allocate window data block
call window_create
mov ebx, windows
mov [ebx + window.data_ptr], eax
mov [ebx + window.flags], 0
mov [ebx + window.type], WINDOWTYPE_SERVER
add eax, window_data.text
mov [text_start], eax
 
call window_refresh
 
; get system colors
mcall 48, 3, colors, 40
 
; set edit box and scrollbar colors
mov eax, [colors.work]
mov [scroll1.bg_color], eax
 
mov eax, [colors.work_button]
mov [scroll1.front_color], eax
 
mov eax, [colors.work_text]
mov [scroll1.line_color], eax
 
; get settings from ini
invoke ini.get_str, path, str_user, str_nick, user_nick, MAX_NICK_LEN, default_nick
invoke ini.get_str, path, str_user, str_real, user_real_name, MAX_REAL_LEN, default_real
 
; Welcome user
mov esi, str_welcome
call print_text2
 
call draw_window ;;; FIXME (gui is not correctly drawn first time)
 
redraw:
call draw_window
 
still:
 
; wait here for event
mcall 10
 
dec eax
jz redraw
 
dec eax
jz main_window_key
 
dec eax
jz button
 
cmp al, 3
je mouse
 
call process_network_event
 
mov edx, [window_open]
test [edx + window.flags], FLAG_UPDATED
jz .no_update
and [edx + window.flags], not FLAG_UPDATED
mov edx, [edx + window.data_ptr]
add edx, window_data.text
call draw_channel_text
.no_update:
call print_channel_list
 
jmp still
 
button:
 
mcall 17 ; get id
shr eax, 8
 
cmp ax, 1 ; close program
je exit
 
cmp ax, 50
jne @f
 
mcall 37, 1 ; Get mouse position
sub ax, TEXT_Y
mov bl, 10
div bl
and eax, 0x000000ff
inc eax
add eax, [scroll1.position]
mov ebx, [window_open]
mov [ebx + window.selected], eax
 
call print_channel_list
 
jmp still
 
@@:
sub ax, WINDOW_BTN_START
jb exit
 
cmp ax, MAX_WINDOWS
ja exit
 
mov dx, sizeof.window
mul dx
shl edx, 16
mov dx, ax
add edx, windows
cmp [edx + window.data_ptr], 0
je exit
mov [window_open], edx
call window_refresh
call draw_window
 
jmp still
exit:
mcall -1
 
 
 
main_window_key:
 
mcall 2
 
push dword edit1
call [edit_box_key]
 
cmp ah, 13 ; enter
jne no_send2
 
call user_parser
 
mov [edit1.size], 0
mov [edit1.pos], 0
 
push dword edit1
call [edit_box_draw]
 
mov edx, [window_open]
mov edx, [edx + window.data_ptr]
add edx, window_data.text
call draw_channel_text
 
jmp still
no_send2:
 
jmp still
 
mouse:
push dword edit1
call [edit_box_mouse]
 
; TODO: check if scrollbar is active
push [scroll1.position]
push dword scroll1
call [scrollbar_v_mouse]
pop eax
cmp eax, [scroll1.position] ; did the scrollbar move?
je @f
call print_channel_list
@@:
 
jmp still
 
 
; DATA AREA
 
encoding_text:
db 'CP866 '
db 'CP1251'
db 'UTF-8 '
encoding_text_len = 6
 
action_header db '*** ', 0
action_header_short db '* ', 0
ctcp_header db '-> [',0
ctcp_version db '] VERSION',10,0
ctcp_ping db '] PING',10,0
ctcp_time db '] TIME',10,0
has_left_channel db ' has left ', 0
joins_channel db ' has joined ', 0
is_now_known_as db ' is now known as ', 0
has_quit_irc db ' has quit IRC', 10, 0
sets_mode db ' sets mode ', 0
kicked db ' is kicked from ', 0
str_talking db 'Now talking in ',0
str_topic db 'Topic is ',0
str_setby db 'Set by ',0
 
str_version db 'VERSION '
str_programname db 'KolibriOS IRC client ', version, 0
 
str_user db 'user', 0
str_nick db 'nick', 0
str_real db 'realname', 0
str_email db 'email', 0
 
default_nick db 'kolibri_user', 0
default_real db 'Kolibri User', 0
 
str_welcome db 10
db ' ______________________ __ __ __',10
db '| \______ \_ ___ \ ____ | | |__| ____ _____/ |_',10
db '| || _/ \ \/ _/ ___\| | | |/ __ \ / \ __\',10
db '| || | \ \____ \ \___| |_| \ ___/| | \ |',10
db '|___||____|_ /\______ / \___ >____/__|\___ >___| /__|',10
db ' \/ \/ \/ \/ \/',10
db 10
db 'Welcome to IRC client ',version,' for KolibriOS',10
db 10
db 'Type /help for help',10,0
 
str_nickchange db 'Nickname is now ',0
str_realchange db 'Real name is now ',0
str_dotnewline db '.',10, 0
str_newline db 10, 0
str_connecting db 10,'* Connecting to ',0
str_help db 10,'following commands are available:',10
db 10
db '/nick <nick> : change nickname to <nick>',10
db '/real <real name> : change real name to <real name>',10
db '/server <address> : connect to server <address>',10
db '/code <code> : change codepage to cp866, cp1251, or utf8',10,0
 
str_1 db ' -',0
str_2 db '- ',0
 
str_sockerr db 'Socket Error',10,0
str_dnserr db 'Unable to resolve hostname.',10,0
str_refused db 'Connection refused',10,0
 
sockaddr1:
dw AF_INET4
.port dw 0x0b1a ; 6667
.ip dd 0
rb 10
 
 
status dd STATUS_DISCONNECTED
 
text_start dd ? ; pointer to current textbox data
irc_data dd 0x0 ; encoder
textbox_width dd 80 ; in characters, not pixels ;)
pos dd 66 * 11 ; encoder
 
window_open dd windows
window_print dd windows
 
scroll dd 1
dd 12
 
align 4
@IMPORT:
 
library network, 'network.obj',\
libini, 'libini.obj',\
boxlib, 'box_lib.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' ,\
edit_box_key ,'edit_box_key' ,\
edit_box_mouse ,'edit_box_mouse' ,\
scrollbar_v_draw ,'scrollbar_v_draw' ,\
scrollbar_v_mouse,'scrollbar_v_mouse'
 
 
usercommand db '/server chat.freenode.net', 0
rb MAX_COMMAND_LEN
 
I_END:
 
; width, left, top
edit1 edit_box 0, 0, 0, 0xffffff, 0x6f9480, 0, 0, 0, USERCMD_MAX_SIZE, usercommand, mouse_dd, ed_focus, 25, 25
; xsize, xpos, ysize, ypos, max, cur, pos, bgcol, frcol, linecol
scroll1 scrollbar SCROLLBAR_WIDTH, 300, 150, TOP_Y, 10, 100, 0, 0, 0, 0, 0, 1
scroll2 scrollbar SCROLLBAR_WIDTH, 300, 150, TOP_Y, 10, 100, 0, 0, 0, 0, 0, 1
 
main_PID dd ? ; identifier of main thread
utf8_bytes_rest dd ? ; bytes rest in current UTF8 sequence
utf8_char dd ? ; first bits of current UTF8 character
gai_reqdata rb 32 ; buffer for getaddrinfo_start/process
ip_list dd ? ; will be filled as pointer to addrinfo list
packetbuf rb 1024 ; buffer for packets to server
path rb 1024
param rb 1024
 
socketnum dd ?
 
servercommand rb 600
 
thread_info rb 1024
xsize dd ?
ysize dd ?
 
colors system_colors
 
irc_server_name rb MAX_SERVER_NAME
 
user_nick rb MAX_NICK_LEN
user_real_name rb MAX_REAL_LEN
 
windows rb MAX_WINDOWS*sizeof.window
 
mouse_dd dd ?
 
IM_END:
 
 
 
 
 
 
 
/programs/network/ircc/ircc.ini
0,0 → 1,8
[user]
nick = kolibri_user
realname = tetten
 
[colors]
action1 = 0x000000aa
action2 = 0x0000aa00
action3 = 0x00aa0000
/programs/network/ircc/serverparser.inc
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
/programs/network/ircc/socket.inc
0,0 → 1,242
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; 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 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 
socket_connect:
 
; cmp [status], STATUS_CONNECTED ; TODO
; je disconnect
 
; ignore if status is not "disconnected"
cmp [status], STATUS_DISCONNECTED
jne .nothing
 
mov esi, str_connecting
call print_text2
mov esi, irc_server_name
call print_text2
mov esi, str_dotnewline
call print_text2
 
; update status
inc [status] ; was STATUS_DISCONNECTED, now STATUS_RESOLVING
 
; resolve name
push esp ; reserve stack place
push esp ; fourth parameter
push 0 ; third parameter
push 0 ; second parameter
push irc_server_name
call [getaddrinfo]
pop esi
; test for error
test eax, eax
jnz .fail_dns
 
; fill in ip in sockstruct
mov eax, [esi + addrinfo.ai_addr]
mov eax, [eax + sockaddr_in.sin_addr]
mov [sockaddr1.ip], eax
 
; free allocated memory
push esi
call [freeaddrinfo]
 
; update status
inc [status]
 
; connect
mcall socket, AF_INET4, SOCK_STREAM, 0
cmp eax, -1
jz .fail
mov [socketnum], eax
 
mcall connect, [socketnum], sockaddr1, 18
cmp eax, -1
jz .fail_refused
 
.nothing:
ret
 
.fail:
mov [status], STATUS_DISCONNECTED
 
mov esi, str_sockerr
call print_text2
 
ret
 
.fail_dns:
mov [status], STATUS_DISCONNECTED
 
mov esi, str_dnserr
call print_text2
 
ret
 
.fail_refused:
mov [status], STATUS_DISCONNECTED
 
mov esi, str_refused
call print_text2
 
ret
 
 
 
socket_write_userinfo:
 
; create packet in packetbuf
mov edi, packetbuf
 
mov eax, 'NICK'
stosd
mov al, ' '
stosb
mov esi, user_nick
mov ecx, MAX_NICK_LEN
.loop:
lodsb
test al, al
jz .done
stosb
dec ecx
jnz .loop
.done:
mov ax, 0x0d0a
stosw
 
mov eax, 'USER'
stosd
mov al, ' '
stosb
mov esi, user_nick
mov ecx, MAX_NICK_LEN
.loop2:
lodsb
test al, al
jz .done2
stosb
dec ecx
jnz .loop2
.done2:
mov eax, ' 8 *'
stosd
mov ax, ' :'
stosw
mov al, ' '
stosb
mov esi, user_real_name
mov ecx, MAX_REAL_LEN
.loop3:
lodsb
test al, al
jz .done3
stosb
dec ecx
jnz .loop3
.done3:
mov ax, 0x0d0a
stosw
 
lea esi, [edi - packetbuf]
mcall send, [socketnum], packetbuf, , 0
 
ret
 
 
 
 
process_network_event:
; values for status: 0, 1, 2, 3
mov eax, [status]
dec eax
; 0 = STATUS_DISCONNECTED - do nothing
; (ignore network events if we are disconnected from network)
js .nothing
; 1 = STATUS_RESOLVING
jz .nothing
; 2 = STATUS_CONNECTING
dec eax
jz .connecting
; 3 = STATUS_CONNECTED
jmp .connected
 
.nothing:
ret
 
.connecting:
call socket_write_userinfo
 
; The connection has been established, change status from "connecting" to "connected".
inc [status]
 
.connected:
call read_incoming_data
ret
 
 
disconnect:
 
cmp [status], STATUS_DISCONNECTED
je .nothing
 
mcall close, [socketnum]
 
mov [status], STATUS_DISCONNECTED
 
.nothing:
ret
 
 
 
read_incoming_data:
 
pusha
 
; TODO: read more data if we receive one full packet
 
.nextpacket:
mcall recv, [socketnum], packetbuf, 1024 ; read a packet
inc eax ; check if we got one
jz .done
dec eax
jz .done
 
; ok we have data, now feed it to the recoder
 
lea edx, [packetbuf + eax] ; edx = end pointer
mov esi, packetbuf ; esi = start pointer
.nextcommand:
mov edi, servercommand
.byteloop:
call get_next_byte ; reads byte from [esi] to al
jnc .nextpacket ; if CF is set, we need more data
cmp al, 10
je .got_command
cmp al, 13
je .got_command
stosb
jmp .byteloop
 
; we have a command, call the serverparser
 
.got_command:
mov byte[edi], 0 ; mark the end of the command
push esi edx
call server_parser
pop edx esi
jmp .nextcommand
 
.done:
popa
 
ret
/programs/network/ircc/userparser.inc
0,0 → 1,318
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; 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 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 
user_parser:
 
mov eax, [edit1.size]
mov word [usercommand + eax], 0x0a0d ; terminate the line
 
cmp byte[usercommand], '/' ; is it a server command ?
je server_command
 
; Ignore data commands when not connected.
cmp [status], STATUS_CONNECTED
jne sdts_ret
 
; Ok, we said something, print it to our textbox
 
; TODO: dont send if it's a server window?
 
push [window_open] ; print to the current window
pop [window_print]
call window_refresh
 
if TIMESTAMP
call print_timestamp
end if
 
mov bl, '<'
call print_character
 
mov esi, user_nick
call print_text2
 
mov bl,'>'
call print_character
mov bl,' '
call print_character
 
mov eax, [edit1.size]
mov byte[usercommand + eax],0
 
mov esi, usercommand
call print_text2
 
mov bl, 10
call print_character
 
; and now send it to the server
 
mov dword[packetbuf], 'priv'
mov dword[packetbuf+4], 'msg '
 
mov esi, [window_open]
add esi, window.name
mov edi, packetbuf+8
mov ecx, MAX_WINDOWNAME_LEN
.loop:
lodsb
test al, al
jz .done
stosb
dec ecx
jnz .loop
.done:
 
mov ax, ' :'
stosw
 
mov esi, usercommand
mov ecx, [edit1.size]
inc ecx
call recode
 
mov al, 10
stosb
 
lea esi, [edi - packetbuf]
mcall send, [socketnum], packetbuf, , 0
 
sdts_ret:
 
ret
 
 
 
user_commands:
dd 'nick', cmd_usr_nick
dd 'real', cmd_usr_real
dd 'serv', cmd_usr_server
dd 'help', cmd_usr_help
dd 'code', cmd_usr_code
; TODO: All other commands require a connection to the server.
dd 'quer', cmd_usr_quer
dd 'quit', cmd_usr_quit
 
.number = ($ - user_commands) / 8
 
 
 
server_command:
 
mov eax, dword[usercommand+1]
or eax, 0x20202020
 
mov edi, user_commands
mov ecx, user_commands.number
.loop:
scasd
je .got_cmd
add edi, 4
dec ecx
jnz .loop
jmp cmd_usr_send ; If none of the previous commands, just send to server
 
.got_cmd:
jmp dword[edi]
 
 
 
 
 
cmd_usr_quit:
 
cmp [edit1.size], 5
je .ok
jb cmd_usr_send
cmp byte[usercommand+5], ' '
jne cmd_usr_send
 
.ok:
call cmd_usr_send
 
mcall close, [socketnum]
 
mov ecx, MAX_WINDOWS
mov edi, windows
.loop:
mov [edi + window.flags], FLAG_CLOSE
add edi, sizeof.window
dec ecx
jnz .loop
 
ret
 
 
 
 
cmd_usr_nick:
 
cmp [edit1.size], 5
je .justprint
cmp byte[usercommand+5], ' '
jne cmd_usr_send
 
mov ecx, MAX_NICK_LEN
mov esi, usercommand+6
mov edi, user_nick
.loop:
lodsb
cmp al, 13
je .done
stosb
dec ecx
jnz .loop
.done:
xor al, al
stosb
 
cmp [socketnum], 0
je .justprint
 
lea esi, [edi - usercommand]
mcall send, [socketnum], usercommand+1, , 0
 
.justprint:
mov esi, str_nickchange
call print_text2
mov esi, user_nick
call print_text2
mov esi, str_dotnewline
call print_text2
 
ret
 
 
 
cmd_usr_real:
 
cmp byte[usercommand+5], ' '
jne cmd_usr_send
 
mov ecx, MAX_REAL_LEN
mov esi, usercommand+6
mov edi, user_real_name
.loop:
lodsb
cmp al, 13
je .done
stosb
dec ecx
jnz .loop
.done:
xor al, al
stosb
 
mov esi, str_realchange
call print_text2
mov esi, user_real_name
call print_text2
mov esi, str_dotnewline
call print_text2
 
ret
 
 
 
cmd_usr_server:
 
mov eax, dword[usercommand+5] ; check for 'er ', we only checked 'serv'
or eax, 0x00002020
and eax, 0x00ffffff
cmp eax, 'er '
jne cmd_usr_send
 
mov ecx, [edit1.size] ; ok now set the address
sub ecx, 8
 
mov esi, usercommand+8
push esi
mov edi, irc_server_name
rep movsb
xor al, al
stosb
pop esi
 
; set it also in window name
mov ebx, [window_print]
call window_set_name
 
; now connect
call socket_connect
 
ret
 
 
cmd_usr_quer:
 
mov ecx, MAX_WINDOWS
mov ebx, windows
.loop:
cmp [ebx + window.data_ptr], 0
je .found
add ebx, sizeof.window
dec ecx
jnz .loop
 
; error: no available channels ! FIXME
 
ret
 
 
.found:
call window_create
test eax, eax
jz .error
mov [ebx + window.data_ptr], eax
 
mov esi, usercommand+7
call window_set_name
 
mov [ebx + window.type], WINDOWTYPE_CHAT
mov [ebx + window.flags], 0
 
.error:
 
ret
 
 
 
cmd_usr_help:
 
mov esi, str_help
call print_text2
 
ret
 
 
 
cmd_usr_code:
 
; TODO
 
ret
 
 
 
cmd_usr_send:
 
mov esi, usercommand+1
mov ecx, [edit1.size]
inc ecx
mov edi, packetbuf
call recode
 
lea esi, [edi - packetbuf]
mcall send, [socketnum], packetbuf, , 0
 
ret
 
/programs/network/ircc/users.inc
0,0 → 1,164
 
 
; esi is ptr to nick
; ebx is ptr to window
align 4
user_add:
 
cmp [ebx + window.users], MAX_USERS
jae fail
 
mov edi, [ebx + window.data_ptr]
add edi, window_data.names
mov ebp, [ebx + window.users]
inc ebp ; CHECKME
 
push esi edi
.restart:
mov ecx, MAX_NICK_LEN
.loop1:
lodsb
cmp al, '@'
jne @f
mov al, ' ' ; give @ highest priority
@@:
cmp al, 'A'
jb @f
cmp al, 'Z'
ja @f
add al, 'a' - 'A' ; convert to lowercase
@@:
dec ecx
jz .got_it
 
.loop2:
mov dl, [edi]
cmp dl, 0
je .got_it
cmp dl, '@'
jne @f
mov dl, ' ' ; give @ highest priority
@@:
cmp dl, 'A'
jb @f
cmp dl, 'Z'
ja @f
add dl, 'a' - 'A' ; convert to lowercase
@@:
cmp al, dl
jb .got_it
je .check_next
 
pop edi esi
add edi, MAX_NICK_LEN
push esi edi
 
dec ebp
jnz .restart
 
.check_next:
inc edi
jmp .loop1
 
.got_it:
pop edi esi
 
; OK, insert it here..
 
; mov all trailing usernames by MAX_NICK_LEN bytes
push esi edi
mov esi, [ebx + window.data_ptr]
add esi, window_data.names + MAX_NICK_LEN * (MAX_USERS - 1)
 
mov ecx, esi
sub ecx, edi
add ecx, MAX_NICK_LEN
shr ecx, 2
lea edi, [esi + MAX_NICK_LEN]
std
rep movsd
cld
pop edi esi
 
; Now insert our new username
mov ecx, MAX_NICK_LEN-1
.fill:
lodsb
cmp al, ' '
je .done
cmp al, '!'
je .done
stosb
loop .fill
.done:
xor al, al
stosb
 
inc [ebx + window.users]
 
ret
 
 
 
 
 
; esi is ptr to nick
; ebx is ptr to window
align 4
user_remove:
 
call user_find
jz fail
 
lea esi, [edi + MAX_NICK_LEN]
mov ecx, [ebx + window.data_ptr]
add ecx, window_data.names + MAX_NICK_LEN * MAX_USERS
sub ecx, esi
shr ecx, 2
rep movsd
 
dec [ebx + window.users]
xor eax, eax
 
ret
 
 
 
; IN:
; esi is ptr to nick
; ebx is ptr to window
; OUT:
; edi is ptr to nick in userlist
align 4
user_find:
 
mov eax, [ebx + window.users]
test eax, eax
jz fail
mov edi, [ebx + window.data_ptr]
add edi, window_data.names
 
.loop:
push esi edi
mov ecx, MAX_NICK_LEN
repe cmpsb
cmp byte[edi-1], 0
je .got_it
; TODO: check byte[esi] too!
pop edi esi
add edi, MAX_NICK_LEN
dec eax
jnz .loop
jmp fail
 
.got_it:
pop edi esi
test edi, edi ; to clear zero flag
 
ret
 
 
fail:
 
xor edi, edi
ret
/programs/network/ircc/window.inc
0,0 → 1,167
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; 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 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 
window_create:
 
; allocate the window data block
mcall 68, 12, sizeof.window_data
test eax, eax
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
 
.fail:
ret
 
 
window_set_name: ; esi = ptr to name, ebx = window ptr
 
pusha
 
; Skip heading spaces
.spaceloop:
cmp byte[esi], ' '
jne .done
inc esi
jmp .spaceloop
.done:
 
; Now copy it
lea edi, [ebx + window.name]
mov ecx, MAX_WINDOWNAME_LEN
.loop:
lodsb
cmp al, 0x21
jbe .addzero
stosb
dec ecx
jnz .loop
.addzero:
xor al, al
stosb
 
call draw_windownames ; redraw it
 
popa
 
ret
 
 
 
window_refresh:
 
; set the correct buffer pointers ; FIXME: what is it good for?
mov eax, [textbox_width] ;
imul eax, 11 ;
mov [pos], eax ;
 
mov eax, [window_print]
mov eax, [eax + window.data_ptr]
add eax, window_data.text
mov [text_start], eax
 
ret
 
 
window_updated:
 
mov edi, [window_print]
test [edi + window.flags], FLAG_UPDATED
jnz .skip
 
or [edi + window.flags], FLAG_UPDATED
 
; now play a sound :)
 
.skip:
 
ret
 
 
print_text: ; eax = start ptr
; dl = end char
pusha
ptr2:
mov bl, [eax]
 
cmp bl, dl
je ptr_ret
cmp bl, 0
je ptr_ret
call print_character
 
inc eax
jmp ptr2
 
ptr_ret:
popa
ret
 
 
print_text2: ; esi = ptr to ASCIIZ string
 
pusha
.loop:
lodsb
test al, al
jz .done
mov bl, al
call print_character
jmp .loop
 
.done:
popa
ret
 
 
if TIMESTAMP
print_timestamp:
 
pusha
mcall 3 ; get system time
 
mov bl, '['
call print_character
mov ecx, TIMESTAMP
.loop:
mov bl, al
shr bl, 4
add bl, '0'
call print_character
 
mov bl, al
and bl, 0x0f
add bl, '0'
call print_character
 
dec ecx
jz .done
 
mov bl, ':'
call print_character
shr eax, 8
jmp .loop
.done:
mov bl, ']'
call print_character
mov bl, ' '
call print_character
 
popa
ret
end if
/programs/network/ircc/.
Property changes:
Added: tsvn:logminsize
+5
\ No newline at end of property