/* * Miranda-IM Vypress Chat/quickChat plugins * Copyright (C) Saulius Menkevicius * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: msghandler.c,v 1.41 2005/03/22 16:12:29 bobas Exp $ */ #include #include "miranda.h" #include #include "libvqproto/vqproto.h" #include "main.h" #include "msghandler.h" #include "user.h" #include "userlist.h" #include "contacts.h" #include "chatroom.h" #include "chanlist.h" #include "util.h" #include "service.h" #include "skin.h" /* static data */ static struct vqp_parse_func_struct s_parseFuncs; /* static routines */ static void msghandler_refresh_req( const vqp_msg_t msg, void * user_data, const char * r_src, enum vqp_codepage src_codepage) { char * src = util_vqp2utf(src_codepage, r_src); if(!user_is_my_nickname(src)) { char * r_nickname = util_utf2vqp(src_codepage, user_nickname()); /* send refresh ack, without delaying */ msgloop_send_to( vqp_msg_refresh_ack( vqp_msg_link(msg), r_nickname, r_src, user_vqp_status(), VQP_ACTIVE_ACTIVE, user_gender(), VQCHAT_VQP_SWVERSION, user_p_uuid(), user_codepage(), 0), 1, vqp_msg_src_addr(msg) ); free(r_nickname); } free(src); } static void msghandler_refresh_ack( const vqp_msg_t msg, void * user_data, const char * r_src, const char * r_dst, enum vqp_status src_status, enum vqp_active src_active, enum vqp_gender src_gender, unsigned int src_swversion, const vqp_uuid_t * src_uuid, enum vqp_codepage src_codepage, unsigned int src_pref_color) { char * src = util_vqp2utf(src_codepage, r_src), * dst = util_vqp2utf(src_codepage, r_dst); if(!user_is_my_nickname(src) && user_is_my_nickname(dst)) { userlist_add( src, src_status, src_gender, src_uuid, src_codepage, src_swversion, vqp_msg_src_addr(msg), 0); } free(dst); free(src); } #ifdef VYPRESSCHAT static void msghandler_ping( const vqp_msg_t msg, void * user_data, const char * r_src, const char * r_dst, const char * r_timestamp) { enum vqp_codepage cp = userlist_user_codepage_vqp(r_src); char * dst = util_vqp2utf(cp, r_dst), * src = util_vqp2utf(cp, r_src); if(!user_is_my_nickname(src) && user_is_my_nickname(dst)) { /* send pong, without waiting */ msgloop_send_to( vqp_msg_pong(vqp_msg_link(msg), r_dst, r_src, r_timestamp), 1, vqp_msg_src_addr(msg)); } free(src); free(dst); } static void msghandler_pong( const vqp_msg_t msg, void * user_data, const char * r_src, const char * r_dst, const char * r_timestamp) { /* we don't use or need ping/pong mechanism, * at least for now */ } static void msghandler_flood_notification( const vqp_msg_t msg, void * user_data, const char * r_src, const char * r_dst, const char * r_secs_blocked) { enum vqp_codepage cp = userlist_user_codepage_vqp(r_src); char * src = util_vqp2utf(cp, r_src), * dst = util_vqp2utf(cp, r_dst); if(!user_is_my_nickname(src) && user_is_my_nickname(dst)) { char * secs_blocked = util_vqp2utf(cp, r_secs_blocked); HANDLE hContact = contacts_find_contact(src); if(hContact) { int len = strlen(secs_blocked); char * fmt = malloc(len + 64); sprintf(fmt, "*** YOU'RE BLOCKED FOR %s SECONDS FOR FLOOD ***", secs_blocked); contacts_input_contact_message(hContact, fmt); free(fmt); } free(secs_blocked); } free(src); free(dst); } #endif static void msghandler_nick_change( vqp_msg_t msg, void * user_data, const char * r_src, const char * r_src_new_nick, enum vqp_gender src_gender) { enum vqp_codepage cp = userlist_user_codepage_vqp(r_src); char * src = util_vqp2utf(cp, r_src), * src_new_nick = util_vqp2utf(cp, r_src_new_nick); if(!user_is_my_nickname(src)) { userlist_name_change(src, src_new_nick); } free(src); free(src_new_nick); } static void msghandler_status_change( vqp_msg_t msg, void * user_data, const char * r_src, enum vqp_status src_status, enum vqp_gender src_gender, const char * r_src_autoanswer) { enum vqp_codepage cp = userlist_user_codepage_vqp(r_src); char * src = util_vqp2utf(cp, r_src), * src_autoanswer = util_vqp2utf(cp, r_src_autoanswer); if(!user_is_my_nickname(src)) userlist_status_change(src, src_status, src_gender, src_autoanswer, 1); free(src); free(src_autoanswer); } static void msghandler_active_change( vqp_msg_t msg, void * user_data, const char * r_src, enum vqp_active src_is_active) { /* XXX: we'll ignore 'active change' for now */ } static void msghandler_channel_join( vqp_msg_t msg, void * user_data, const char * r_channel, const char * r_src, enum vqp_status src_status, enum vqp_gender src_gender, unsigned int src_swversion, const vqp_uuid_t * src_uuid, enum vqp_codepage src_codepage, unsigned int src_pref_color) { char * channel = util_vqp2utf(src_codepage, r_channel), * src = util_vqp2utf(src_codepage, r_src); if(!user_is_my_nickname(src)) { const char * topic; char * my_chanlist; /* add user to userlist and update it's channel list */ userlist_add( src, src_status, src_gender, src_uuid, src_codepage, src_swversion, vqp_msg_src_addr(msg), 1); userlist_user_channel_join(src, channel, 1); /* reply with refresh ack (if the channel is #Main), who-here ack, * and topic ack if we're in this channel */ my_chanlist = chanlist_copy(*user_p_chanlist()); my_chanlist = chanlist_add(my_chanlist, VQP_MAIN_CHANNEL); if(chanlist_contains(my_chanlist, channel)) { char * r_nickname = util_utf2vqp(src_codepage, user_nickname()); if(!strcmp(channel, VQP_MAIN_CHANNEL)) { /* reply with refresh ack (without waiting) */ msgloop_send_to( vqp_msg_refresh_ack( vqp_msg_link(msg), r_nickname, r_src, user_vqp_status(), VQP_ACTIVE_ACTIVE, user_gender(), VQCHAT_VQP_SWVERSION, user_p_uuid(), user_codepage(), 0), 1, vqp_msg_src_addr(msg) ); } else { /* on channels not #Main, reply with who-here ack */ msgloop_send_to( vqp_msg_channel_whohere_ack( vqp_msg_link(msg), r_channel, r_nickname, r_src, VQCHAT_UNDEF_ACTIVE), 0, vqp_msg_src_addr(msg) ); } /* reply the user with channel's topic */ topic = chatroom_channel_get_topic(channel); if(topic) { char * r_topic_text = util_utf2vqp(src_codepage, topic); msgloop_send_to( vqp_msg_channel_current_topic( vqp_msg_link(msg), r_src, r_channel, r_topic_text), 0, vqp_msg_src_addr(msg) ); free(r_topic_text); } /* free strings */ free(r_nickname); } chanlist_free(my_chanlist); } free(channel); free(src); } static void msghandler_channel_leave( const vqp_msg_t msg, void * user_data, const char * r_channel, const char * r_src, enum vqp_gender src_gender) { enum vqp_codepage cp = userlist_user_codepage_vqp(r_src); char * channel = util_vqp2utf(cp, r_channel), * src = util_vqp2utf(cp, r_src); if(!user_is_my_nickname(src)) { if(!strcmp(channel, VQCHAT_MAIN_CHANNEL)) { /* user has left the network */ userlist_remove(src, 1); } else { /* user has left the specified channel */ userlist_user_channel_part(src, channel, 1); } } free(channel); free(src); } static void msghandler_channel_text( vqp_msg_t msg, void * user_data, const char * r_channel, const char * r_src, const char * r_text, int is_action_text) { enum vqp_codepage cp = userlist_user_codepage_vqp(r_src); char * src = util_vqp2utf(cp, r_src); if(!user_is_my_nickname(src)) { char * channel = util_vqp2utf(cp, r_channel), * text = util_vqp2utf(cp, r_text); userlist_user_channel_text( src, channel, text, vqp_msg_src_addr(msg), is_action_text); free(channel); free(text); } free(src); } #ifdef QUICKCHAT static int msghandler_channel_topic_change_chan_enum_fn( const char * channel, void * fn_data) { const char * topic_text = ((const char **)fn_data)[0], * notify_user = ((const char **)fn_data)[1]; ASSERT_RETURNVALIFFAIL(VALIDPTR(channel) && VALIDPTR(topic_text), 0); chatroom_channel_topic_change(channel, (const char *)topic_text, 0, (int)notify_user); return 1; } #endif static void msghandler_channel_topic_change( vqp_msg_t msg, void * user_data, const char * r_channel, const char * r_topic_text) { char * channel = util_vqp2utf(user_codepage(), r_channel), * topic_text = util_vqp2utf(user_codepage(), r_topic_text); #ifdef VYPRESSCHAT chatroom_channel_topic_change(channel, topic_text, 0, 1); #endif #ifdef QUICKCHAT /* there's a single topic for all the channels in quickChat: * enumerate all of them and set their topics */ const char * fn_data[2]; fn_data[0] = topic_text; fn_data[1] = (const char *)1; chanlist_enum( *user_p_chanlist(), msghandler_channel_topic_change_chan_enum_fn, (void *) fn_data); #endif free(channel); free(topic_text); } static void msghandler_channel_current_topic( vqp_msg_t msg, void * user_data, const char * r_dst, const char * r_channel, const char * r_topic_text) { enum vqp_codepage cp = user_codepage(); char * dst = util_vqp2utf(cp, r_dst); if(user_is_my_nickname(dst)) { char * channel = util_vqp2utf(cp, r_channel), * topic_text = util_vqp2utf(cp, r_topic_text); #ifdef VYPRESSCHAT chatroom_channel_topic_change(channel, topic_text, 0, 0); #endif #ifdef QUICKCHAT /* there's a single topic for all the channels in quickChat: * enumerate all of them and set their topics */ const char * fn_data[2]; fn_data[0] = topic_text; fn_data[1] = (const char *)0; chanlist_enum( *user_p_chanlist(), msghandler_channel_topic_change_chan_enum_fn, (void *) fn_data); #endif free(channel); free(topic_text); } free(dst); } static void msghandler_channel_whohere_req( vqp_msg_t msg, void * user_data, const char * r_channel, const char * r_src) { enum vqp_codepage cp = userlist_user_codepage_vqp(r_src); char * src = util_vqp2utf(cp, r_src); if(!user_is_my_nickname(src)) { char * channel = util_vqp2utf(cp, r_channel); if(chanlist_contains(*user_p_chanlist(), channel)) { char * r_user_nickname = util_utf2vqp(cp, user_nickname()); /* reply, that we're on this channel */ msgloop_send_to( vqp_msg_channel_whohere_ack( vqp_msg_link(msg), r_channel, r_user_nickname, r_src, VQCHAT_UNDEF_ACTIVE), 0, vqp_msg_src_addr(msg) ); free(r_user_nickname); } free(channel); } free(src); } static void msghandler_channel_whohere_ack( vqp_msg_t msg, void * user_data, const char * r_channel, const char * r_src, const char * r_dst, enum vqp_active src_is_active) { enum vqp_codepage cp = userlist_user_codepage_vqp(r_src); char * src = util_vqp2utf(cp, r_src), * dst = util_vqp2utf(cp, r_dst); if(!user_is_my_nickname(src) && user_is_my_nickname(dst)) { char * channel = util_vqp2utf(cp, r_channel); /* add channel to user's chanlist */ userlist_user_channel_join(src, channel, 0); free(channel); } free(src); free(dst); } static void msghandler_channel_list_req( vqp_msg_t msg, void * user_data, const char * r_src) { enum vqp_codepage cp = userlist_user_codepage_vqp(r_src); char * src = util_vqp2utf(cp, r_src); if(!user_is_my_nickname(src)) { /* make sure our chanlist contains the #Main channel */ char * chanlist, * vqp_chanlist, * r_chanlist; chanlist = chanlist_copy(*user_p_chanlist()); chanlist = chanlist_add(chanlist, VQCHAT_MAIN_CHANNEL); vqp_chanlist = chanlist_make_vqp_chanlist(chanlist); free(chanlist); r_chanlist = util_utf2vqp(cp, vqp_chanlist); free(vqp_chanlist); /* reply with ack */ msgloop_send(vqp_msg_channel_list_ack(vqp_msg_link(msg), r_src, r_chanlist), 0); free(r_chanlist); } free(src); } static void msghandler_channel_list_ack( vqp_msg_t msg, void * user_data, const char * r_dst, const char * r_channel_list) { enum vqp_codepage cp = user_codepage(); char * dst = util_vqp2utf(cp, r_dst), * channel_list = util_vqp2utf(cp, r_channel_list); if(user_is_my_nickname(dst)) { char * chanlist = chanlist_parse_vqp_chanlist(channel_list); service_join_channel_merge_chanlist(chanlist); free(chanlist); } free(dst); free(channel_list); } static void msghandler_message( vqp_msg_t msg, void * user_data, const char * r_src, const char * r_dst, const char * r_text, int is_multiaddress_msg) { enum vqp_codepage cp = userlist_user_codepage_vqp(r_src); char * src = util_vqp2utf(cp, r_src), * dst = util_vqp2utf(cp, r_dst); if(!user_is_my_nickname(src) && user_is_my_nickname(dst)) { char * text = util_vqp2utf(cp, r_text); HANDLE hContact; hContact = contacts_find_contact(src); if(!hContact) hContact = contacts_add_contact(src, 0); if(hContact) { char * r_autoanswer = util_utf2vqp(cp, user_awaymsg()); /* write message event to contact window/history */ contacts_input_contact_message(hContact, text); /* send message ack */ msgloop_send_to( vqp_msg_message_ack( vqp_msg_link(msg), dst, src, user_vqp_status(), user_gender(), r_autoanswer, vqp_msg_signature(msg)), 0, vqp_msg_src_addr(msg) ); free(r_autoanswer); } free(text); } free(src); free(dst); } static void msghandler_message_ack( vqp_msg_t msg, void * user_data, const char * r_src, const char * r_dst, enum vqp_status src_status, enum vqp_gender src_gender, const char * r_src_autoanswer, const char * orig_packetsig) { /* we don't send any messages for now */ } static void msghandler_info_req( vqp_msg_t msg, void * user_data, const char * r_src, const char * r_dst) { enum vqp_codepage cp = userlist_user_codepage_vqp(r_src); char * src = util_vqp2utf(cp, r_src), * dst = util_vqp2utf(cp, r_dst); if(!user_is_my_nickname(r_src) && user_is_my_nickname(r_dst)) { wchar_t w_computer_name[MAX_COMPUTERNAME_LENGTH + 1], w_user_name[UNLEN + 1]; char * computer_name, * r_computer_name; char * user_name, * r_user_name; char * netgroup_name, * r_netgroup_name; char * chanlist, * vqp_chanlist, * r_chanlist; char * r_autoanswer; DWORD computer_name_len, user_name_len; /* LPWKSTA_INFO_100 wksta_info100; */ /* get computer name */ computer_name_len = MAX_COMPUTERNAME_LENGTH; w_computer_name[0] = '\0'; /* in case the call fails */ GetComputerNameW(w_computer_name, &computer_name_len); computer_name = util_uni2utf(w_computer_name); r_computer_name = util_utf2vqp(cp, computer_name); free(computer_name); /* get user name */ user_name_len = UNLEN; w_user_name[0] = '\0'; /* in case the call fails */ GetUserNameW(w_user_name, &user_name_len); user_name = util_uni2utf(w_user_name); r_user_name = util_utf2vqp(cp, user_name); free(user_name); /* get netgroup name */ /* if(NetWkstaGetInfo(NULL, 100, (LPBYTE *) &wksta_info100) == NERR_Success) { r_netgroup_name = util_uni2utf(wksta_info100->wki100_langroup); NetApiBufferFree(wksta_info100); } else { r_netgroup_name = strdup(""); } */ r_netgroup_name = strdup(""); /* make vqp chanlist */ chanlist = chanlist_copy(*user_p_chanlist()); chanlist = chanlist_add(chanlist, VQP_MAIN_CHANNEL); vqp_chanlist = chanlist_make_vqp_chanlist(chanlist); free(chanlist); r_chanlist = util_utf2vqp(cp, vqp_chanlist); free(vqp_chanlist); /* make autoanswer */ r_autoanswer = util_utf2vqp(cp, user_awaymsg()); /* return info request reply */ /* XXX: add real ip/port address string */ msgloop_send_to( vqp_msg_info_ack( vqp_msg_link(msg), r_dst, r_src, r_computer_name, r_user_name, "0.0.0.0:0", r_chanlist, r_autoanswer, r_netgroup_name, VQCHAT_VQP_SWPLATFORM, VQCHAT_VQP_SWNAME ), 0, vqp_msg_src_addr(msg) ); free(r_autoanswer); free(r_chanlist); free(r_user_name); free(r_computer_name); free(r_netgroup_name); } free(src); free(dst); } static void msghandler_info_ack( vqp_msg_t msg, void * user_data, const char * r_src, const char * r_dst, const char * r_src_computer_name, const char * r_src_user_name, const char * r_src_node_address, const char * r_src_channel_list, const char * r_src_autoanswer, const char * r_src_netgroup, const char * r_src_platform, const char * r_src_software) { enum vqp_codepage cp = userlist_user_codepage_vqp(r_src); char * src = util_vqp2utf(cp, r_src), * dst = util_vqp2utf(cp, r_dst); if(!user_is_my_nickname(r_src) && user_is_my_nickname(r_dst)) { char * computer_name = util_vqp2utf(cp, r_src_computer_name), * user_name = util_vqp2utf(cp, r_src_user_name), * awaymsg = util_vqp2utf(cp, r_src_autoanswer), * netgroup = util_vqp2utf(cp, r_src_netgroup), * platform = util_vqp2utf(cp, r_src_platform), * software = util_vqp2utf(cp, r_src_software), * vqp_chanlist = util_vqp2utf(cp, r_src_channel_list); HANDLE hContact = contacts_find_contact(src); if(hContact) { char * chanlist; /* store contact info */ contacts_set_contact_addr(hContact, vqp_msg_src_addr(msg)); contacts_set_contact_about(hContact, awaymsg); contacts_set_contact_property(hContact, CONTACT_COMPUTER, computer_name); contacts_set_contact_property(hContact, CONTACT_USER, user_name); contacts_set_contact_property(hContact, CONTACT_WORKGROUP, netgroup); contacts_set_contact_property(hContact, CONTACT_PLATFORM, platform); contacts_set_contact_property(hContact, CONTACT_SOFTWARE, software); contacts_set_contact_gender(hContact, userlist_user_gender(src)); /* update user's channel list */ chanlist = chanlist_parse_vqp_chanlist(vqp_chanlist); userlist_user_chanlist_update(src, chanlist); chanlist_free(chanlist); /* confirm we've received the info correctly */ ProtoBroadcastAck( VQCHAT_PROTO, hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE)2, (LPARAM)1); } free(vqp_chanlist); free(computer_name); free(user_name); free(awaymsg); free(netgroup); free(platform); free(software); } free(src); free(dst); } static void msghandler_beep_signal(/*{{{*/ vqp_msg_t msg, void * user_data, const char * r_src, const char * r_dst) { enum vqp_codepage cp = userlist_user_codepage_vqp(r_src); char * src = util_vqp2utf(cp, r_src), * dst = util_vqp2utf(cp, r_dst); if(!user_is_my_nickname(src) && user_is_my_nickname(dst)) { HANDLE hContact = contacts_find_contact(src); if(hContact) { /* play beep sound and emit msg, if configured */ SkinPlaySound(SKIN_SOUND_ALERT_BEEP); if(db_byte_get(NULL, VQCHAT_PROTO, "MsgOnAlertBeep", 0)) contacts_input_contact_message(hContact, "*** ALERT BEEP ***"); /* send beep ack */ msgloop_send_to( vqp_msg_beep_ack(vqp_msg_link(msg), r_dst, r_src, user_gender()), 0, vqp_msg_src_addr(msg)); } } free(src); free(dst); } static void msghandler_beep_ack( vqp_msg_t msg, void * user_data, const char * r_src, const char * r_dst, enum vqp_gender src_gender) { /* we don't make any use of this ack, at least for now */ } static void msghandler_private_open( vqp_msg_t msg, void * user_data, const char * r_src, const char * r_dst, enum vqp_gender src_gender) { enum vqp_codepage cp = userlist_user_codepage_vqp(r_src); char * src = util_vqp2utf(cp, r_src), * dst = util_vqp2utf(cp, r_dst); if(!user_is_my_nickname(src) && user_is_my_nickname(dst)) { /* open chat */ if(!userlist_user_is_chat_open(src)) { /* send chat open reply */ msgloop_send_to( vqp_msg_private_open( vqp_msg_link(msg), r_dst, r_src, user_gender()), 0, vqp_msg_src_addr(msg)); /* mark the chat as open */ userlist_user_set_chat_open(src, 1); } } free(src); free(dst); } static void msghandler_private_close( vqp_msg_t msg, void * user_data, const char * r_src, const char * r_dst, enum vqp_gender src_gender) { enum vqp_codepage cp = userlist_user_codepage_vqp(r_src); char * src = util_vqp2utf(cp, r_src), * dst = util_vqp2utf(cp, r_dst); if(!user_is_my_nickname(src) && user_is_my_nickname(dst)) { userlist_user_set_chat_open(src, 0); } free(src); free(dst); } static void msghandler_private_text( vqp_msg_t msg, void * user_data, const char * r_src, const char * r_dst, const char * r_text, int is_action_text) { enum vqp_codepage cp = userlist_user_codepage_vqp(r_src); char * src = util_vqp2utf(cp, r_src), * dst = util_vqp2utf(cp, r_dst); if(!user_is_my_nickname(src) && user_is_my_nickname(dst)) { HANDLE hContact = contacts_find_contact(src); if(!hContact) hContact = contacts_add_contact(src, 0); if(hContact) { char * text = util_vqp2utf(cp, r_text); /* check that we have chat open with the user */ if(!userlist_user_is_chat_open(src)) { msgloop_send_to( vqp_msg_private_open( vqp_msg_link(msg), r_dst, r_src, user_gender()), 0, vqp_msg_src_addr(msg)); /* mark the chat as open */ userlist_user_set_chat_open(src, 1); } if(is_action_text) { /* make the ' ' - style action text */ int text_len = strlen(text); int src_len = strlen(src); char * action_text = malloc(src_len + text_len + 10); memcpy(action_text, src, src_len); action_text[src_len] = ' '; memcpy(action_text + src_len + 1, text, text_len + 1); contacts_input_contact_message(hContact, action_text); free(action_text); } else { contacts_input_contact_message(hContact, text); } free(text); } } free(src); free(dst); } /* exported routines */ /* msghandler_init: * setups msghandler module */ void msghandler_init() { memset(&s_parseFuncs, 0, sizeof(s_parseFuncs)); s_parseFuncs.struct_size = sizeof(s_parseFuncs); /* add handler funcs */ s_parseFuncs.func_refresh_req = msghandler_refresh_req;/*{{{*/ s_parseFuncs.func_refresh_ack = msghandler_refresh_ack; #ifdef VYPRESSCHAT s_parseFuncs.func_ping = msghandler_ping; s_parseFuncs.func_pong = msghandler_pong; s_parseFuncs.func_flood_notification = msghandler_flood_notification; #endif /* s_parseFuncs.func_remote_exec = msghandler_remote_exec; s_parseFuncs.func_remote_exec_ack = msghandler_remote_exec_ack; */ s_parseFuncs.func_nick_change = msghandler_nick_change; s_parseFuncs.func_status_change = msghandler_status_change; s_parseFuncs.func_active_change = msghandler_active_change; s_parseFuncs.func_channel_join = msghandler_channel_join; s_parseFuncs.func_channel_leave = msghandler_channel_leave; s_parseFuncs.func_channel_text = msghandler_channel_text; s_parseFuncs.func_channel_topic_change = msghandler_channel_topic_change; s_parseFuncs.func_channel_current_topic = msghandler_channel_current_topic; s_parseFuncs.func_channel_whohere_req = msghandler_channel_whohere_req; s_parseFuncs.func_channel_whohere_ack = msghandler_channel_whohere_ack; s_parseFuncs.func_channel_list_req = msghandler_channel_list_req; s_parseFuncs.func_channel_list_ack = msghandler_channel_list_ack; s_parseFuncs.func_message = msghandler_message; s_parseFuncs.func_message_ack = msghandler_message_ack; s_parseFuncs.func_info_req = msghandler_info_req; s_parseFuncs.func_info_ack = msghandler_info_ack; s_parseFuncs.func_beep_signal = msghandler_beep_signal; s_parseFuncs.func_beep_ack = msghandler_beep_ack; s_parseFuncs.func_private_open = msghandler_private_open; s_parseFuncs.func_private_close = msghandler_private_close; s_parseFuncs.func_private_text = msghandler_private_text;/*}}}*/ } /* msghandler_uninit: * cleansup user status module */ void msghandler_uninit() { /* nothing here */ } /* msghandler_apc: * invoked from msgloop thread with QueueUserAPC, * the param is vqp_msg_t, which gets free'd after use */ void CALLBACK msghandler_apc(ULONG_PTR vqmsg) { vqp_msg_parse(&s_parseFuncs, (vqp_msg_t) vqmsg, 0); vqp_msg_free((vqp_msg_t)vqmsg); }