summaryrefslogtreecommitdiff
path: root/plugins/!NotAdopted/VypressChat/msghandler.c
diff options
context:
space:
mode:
authorVadim Dashevskiy <watcherhd@gmail.com>2013-04-02 13:54:21 +0000
committerVadim Dashevskiy <watcherhd@gmail.com>2013-04-02 13:54:21 +0000
commitff5a775b94465b30897964630af600fe5915fc51 (patch)
treef79e36c79faf7095ca6f02f6b7fea0f6e81bf085 /plugins/!NotAdopted/VypressChat/msghandler.c
parent8d3307adf7ba64b75fb4de363f873c97286b0e9b (diff)
VypressChat added (not adopted)
git-svn-id: http://svn.miranda-ng.org/main/trunk@4285 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/!NotAdopted/VypressChat/msghandler.c')
-rw-r--r--plugins/!NotAdopted/VypressChat/msghandler.c839
1 files changed, 839 insertions, 0 deletions
diff --git a/plugins/!NotAdopted/VypressChat/msghandler.c b/plugins/!NotAdopted/VypressChat/msghandler.c
new file mode 100644
index 0000000000..7123577b33
--- /dev/null
+++ b/plugins/!NotAdopted/VypressChat/msghandler.c
@@ -0,0 +1,839 @@
+/*
+ * 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 <time.h>
+
+#include "miranda.h"
+#include <lm.h>
+
+#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 '<nickname> <text>' - 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);
+}
+