;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; Copyright (C) KolibriOS team 2004-2024. 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.35b' ; 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_CHANNEL = 2 WINDOWTYPE_CHAT = 3 WINDOWTYPE_LIST = 4 WINDOWTYPE_DCC = 5 ; supported encodings CP866 = 0 CP1251 = 1 UTF8 = 2 ; settings USERCMD_MAX_SIZE = 400 WIN_MIN_X = 600 WIN_MIN_Y = 183 TEXT_X = 2 TEXT_Y = TOP_Y + 2 TOP_SPACE = 2 TAB_HEIGHT = 14 TAB_WIDTH = 120 TAB_SPACE = 5 TOP_Y = TOP_SPACE+ TAB_HEIGHT INPUTBOX_HEIGHT = 13 MAX_WINDOWS = 20 MAX_USERS = 4096 TEXT_BUFFERSIZE = 1024*1024 MAX_NICK_LEN = 32 MAX_REAL_LEN = 32 ; realname QUIT_MSG_LEN = 250 MAX_SERVER_NAME = 256 MAX_CHANNEL_LEN = 40 MAX_CHANNELS = 37 MAX_COMMAND_LEN = 512 PACKETBUF_SIZE = 1024 PATH_SIZE = 1024 PARAM_SIZE = 1024 SERVERCOMMAND_SIZE = 600 TIMESTAMP = 3 ; 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 USERLIST_WIDTH = 160 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+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 "../../develop/libraries/box_lib/trunk/box_lib.mac" struct window data_ptr dd ? flags db ? type db ? name rb MAX_WINDOWNAME_LEN users dd ? users_scroll dd ? selected dd ? ; selected user, 0 if none selected text_start dd ? ; pointer to current textbox data text_end dd ? text_print dd ? ; pointer to first character to print on screen text_line_print dd ? ; line number of that character text_write dd ? ; write pointer text_lines dd ? ; total number of lines text_scanned dd ? ; pointer to beginning of unscanned data (we still need to count number of lines, insert newline characters,..) ends struct window_data text rb TEXT_BUFFERSIZE names rb MAX_NICK_LEN * MAX_USERS ends include "encodings.inc" include "window.inc" include "serverparser.inc" include "userparser.inc" include "socket.inc" include "gui.inc" include "users.inc" include "textbox.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+EVM_MOUSE_FILTER ; 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, PATH_SIZE 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, SERVERCOMMAND_SIZE/4 rep stosd ; allocate window data block mov ebx, windows call window_create_textbox test eax, eax jz exit mov [ebx + window.type], WINDOWTYPE_SERVER ; 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 invoke ini.get_str, path, str_user, str_quitmsg, quit_msg, 250, default_quit ; Welcome user mov esi, str_welcome call print_asciiz ; Check if parameter contains an 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 ; wait for event 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_channel_text mov edi, [window_active] cmp [edi + window.type], WINDOWTYPE_CHANNEL 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 ; close program je quit cmp ax, WINDOW_BTN_CLOSE jne @f call cmd_usr_close_window jmp mainloop @@: cmp ax, WINDOW_BTN_LIST jne @f push eax mcall 37, 1 ; Get mouse position sub ax, TEXT_Y mov bl, FONT_HEIGHT div bl and eax, 0x000000ff inc eax add eax, [scroll1.position] mov ebx, [window_active] mov [ebx + window.selected], eax call draw_user_list pop eax test eax, 1 shl 25 ; Right mouse button pressed? jz mainloop ; TODO: check if selected nick is my nick! ; Right mouse BTN was pressed, open chat window mov ebx, [window_active] mov eax, [ebx + window.selected] dec eax imul eax, MAX_NICK_LEN mov ebx, [ebx + window.data_ptr] lea esi, [ebx + window_data.names + eax] ; Strip user prefixes cmp byte[esi], '~' je .inc cmp byte[esi], '&' je .inc cmp byte[esi], '@' je .inc cmp byte[esi], '%' je .inc cmp byte[esi], '+' je .inc .open: call window_open test ebx, ebx jz mainloop mov [window_active], ebx call redraw jmp mainloop .inc: inc esi jmp .open @@: sub ax, WINDOW_BTN_START jb quit cmp ax, MAX_WINDOWS ja quit ; Save users scrollbar position push [scroll1.position] mov edx, [window_active] pop [edx + window.users_scroll] ; OK, time to switch to another window. 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 [edx + window.users_scroll] pop [scroll1.position] call draw_window jmp mainloop quit: cmp [socketnum], 0 je @f mov esi, quit_msg call quit_server @@: exit: ; Close all open windows call window_close_all ; Erase RAM areas which could contain the connection details xor eax, eax mov edi, irc_server_name mov ecx, MAX_SERVER_NAME rep stosb mov edi, user_nick mov ecx, MAX_NICK_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_channel_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_CHANNEL 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_channel_text.scroll_to_pos @@: jmp mainloop ; DATA AREA encoding_text: db 'CP866 ' db 'CP1251' db 'UTF-8 ' encoding_text_len = 6 join_header db 3, '3* ', 0 quit_header db 3, '5* ', 0 nick_header db 3, '2* ', 0 kick_header db 3, '5* ', 0 mode_header db 3, '2* ', 0 part_header db 3, '5* ', 0 topic_header db 3, '3* ', 0 action_header db 3, '6* ', 0 ctcp_header db 3, '13-> [', 0 ctcp_header_recv db 3, '13', 0 msg_header db 3, '7-> *', 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 str_kicked db ' is kicked from ', 0 str_by db ' by ', 0 str_nickchange db 'Nickname is now ', 0 str_realchange db 'Real name is now ', 0 str_talking db 'Now talking in ', 0 str_topic db 'Topic is "', 0 str_topic_end db '"', 10, 0 str_setby db 'Set by ', 0 str_connecting db 3, '3* Connecting to ', 0 str_sockerr db 3, '5* Socket error', 10, 0 str_dnserr db 3, '5* Unable to resolve hostname', 10, 0 str_refused db 3, '5* Connection refused', 10, 0 str_srv_disconnected db 3, '5* Server disconnected', 10, 0 str_disconnected db 3, '5* Disconnected', 10, 0 str_reconnect db 3, '5* Connection reset by user', 10, 0 str_notconnected db 3, '5* You are not connected', 10, 0 str_notchannel db 3, '5* You are not on a channel', 10, 0 str_notloggedin db 3, '5* You are not logged in to the server', 10, 0 str_1 db 3, '13 -', 0 str_2 db '- ', 0 str_list db 'list', 0 str_help db 'The following commands are available:', 10 db 10 db '/nick : change nickname', 10 db '/real : change real name', 10 db '/server
: connect to server', 10 db '/code : change codepage (cp866, cp1251, or utf8)', 10 db '/join : join a channel', 10 db '/part : part from a channel', 10 db '/quit : quit server', 10 db '/msg : send a private message', 10 db '/ctcp : send a message using client-to-client protocol', 10 db 10 db 'Other commands are sent straight to a server', 10 db 10, 0 str_welcome db 3, '3 ___', 3, '7__________', 3, '6_________ ', 3, '4 __ __ __', 10 db 3, '3| \', 3, '7______ \', 3, '6_ ___ \ ', 3, '4 ____ | | |__| ____ _____/ |_', 10 db 3, '3| |', 3, '7| _/', 3, '6 \ \/ ', 3, '4 _/ ___\| | | |/ __ \ / \ __\', 10 db 3, '3| |', 3, '7| | \', 3, '6 \____', 3, '4 \ \___| |_| \ ___/| | \ |', 10 db 3, '3|___|', 3, '7|____|_ /', 3, '6\______ /', 3, '4 \___ >____/__|\___ >___| /__|', 10 db 3, '3 ', 3, '7 \/ ', 3, '6 \/ ', 3, '4 \/ \/ \/', 10 db 'Welcome to KolibriOS IRC client ', version, 10 db 'Type /help for help', 10, 0 str_version db 'VERSION KolibriOS ' str_programname db 'IRC client ', version, 0 str_user db 'user', 0 str_nick db 'nick', 0 str_real db 'realname', 0 str_email db 'email', 0 str_quitmsg db 'quitmsg', 0 default_nick db 'kolibri_user', 0 default_real db 'Kolibri User', 0 default_quit db 'KolibriOS forever', 0 closing_cross db 'x',0 irc_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 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_draw',\ edit_box_key, 'edit_box_key',\ edit_box_mouse, 'edit_box_mouse',\ scrollbar_draw, 'scrollbar_v_draw',\ scrollbar_mouse,'scrollbar_v_mouse' ; width, left, top edit1 edit_box 0, 0, 0, 0xffffff, 0x6f9480, 0, 0, 0x000000, USERCMD_MAX_SIZE, input_text, mouse_dd, ed_always_focus, 25, 25 ; 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 '/server irc.libera.chat', 0 rb MAX_COMMAND_LEN I_END: user_command rb MAX_COMMAND_LEN*4 .size dd ? utf8_bytes_rest dd ? ; bytes rest in current UTF8 sequence utf8_char dd ? ; first bits of current UTF8 character packetbuf rb PACKETBUF_SIZE ; buffer for packets to server path rb PATH_SIZE param rb PARAM_SIZE servercommand rb SERVERCOMMAND_SIZE thread_info process_information xsize dd ? ysize dd ? mouse_dd dd ? textbox_height dd ? ; in characters textbox_width dd ? ; in characters, not pixels ;) colors system_colors irc_server_name rb MAX_SERVER_NAME ; TODO: move this server URL into window struct socketnum dd ? ; TODO: same for socket user_nick rb MAX_NICK_LEN user_real_name rb MAX_REAL_LEN quit_msg rb QUIT_MSG_LEN windows rb MAX_WINDOWS*sizeof.window IM_END: