--- a/src/protocols/msn/switchboard.c Wed Oct 18 16:28:51 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1287 +0,0 @@ -/** - * @file switchboard.c MSN switchboard functions - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * 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 - */ -#include "msn.h" -#include "prefs.h" -#include "switchboard.h" -#include "notification.h" -#include "msn-utils.h" - -#include "error.h" - -#define MSN_DEBUG_SB - -static MsnTable *cbs_table; - -static void msg_error_helper(MsnCmdProc *cmdproc, MsnMessage *msg, - MsnMsgErrorType error); - -/************************************************************************** - * Main - **************************************************************************/ - -MsnSwitchBoard * -msn_switchboard_new(MsnSession *session) -{ - MsnSwitchBoard *swboard; - MsnServConn *servconn; - - g_return_val_if_fail(session != NULL, NULL); - - swboard = g_new0(MsnSwitchBoard, 1); - - swboard->session = session; - swboard->servconn = servconn = msn_servconn_new(session, MSN_SERVCONN_SB); - swboard->cmdproc = servconn->cmdproc; - - swboard->msg_queue = g_queue_new(); - swboard->empty = TRUE; - - swboard->cmdproc->data = swboard; - swboard->cmdproc->cbs_table = cbs_table; - - session->switches = g_list_append(session->switches, swboard); - - return swboard; -} - -void -msn_switchboard_destroy(MsnSwitchBoard *swboard) -{ - MsnSession *session; - MsnMessage *msg; - GList *l; - -#ifdef MSN_DEBUG_SB - gaim_debug_info("msn", "switchboard_destroy: swboard(%p)\n", swboard); -#endif - - g_return_if_fail(swboard != NULL); - - if (swboard->destroying) - return; - - swboard->destroying = TRUE; - - /* If it linked us is because its looking for trouble */ - if (swboard->slplink != NULL) - msn_slplink_destroy(swboard->slplink); - - /* Destroy the message queue */ - while ((msg = g_queue_pop_head(swboard->msg_queue)) != NULL) - { - if (swboard->error != MSN_SB_ERROR_NONE) - { - /* The messages could not be sent due to a switchboard error */ - msg_error_helper(swboard->cmdproc, msg, - MSN_MSG_ERROR_SB); - } - msn_message_unref(msg); - } - - g_queue_free(swboard->msg_queue); - - /* msg_error_helper will both remove the msg from ack_list and - unref it, so we don't need to do either here */ - while ((l = swboard->ack_list) != NULL) - msg_error_helper(swboard->cmdproc, l->data, MSN_MSG_ERROR_SB); - - g_free(swboard->im_user); - g_free(swboard->auth_key); - g_free(swboard->session_id); - - for (l = swboard->users; l != NULL; l = l->next) - g_free(l->data); - - session = swboard->session; - session->switches = g_list_remove(session->switches, swboard); - -#if 0 - /* This should never happen or we are in trouble. */ - if (swboard->servconn != NULL) - msn_servconn_destroy(swboard->servconn); -#endif - - swboard->cmdproc->data = NULL; - - msn_servconn_set_disconnect_cb(swboard->servconn, NULL); - - msn_servconn_destroy(swboard->servconn); - - g_free(swboard); -} - -void -msn_switchboard_set_auth_key(MsnSwitchBoard *swboard, const char *key) -{ - g_return_if_fail(swboard != NULL); - g_return_if_fail(key != NULL); - - swboard->auth_key = g_strdup(key); -} - -const char * -msn_switchboard_get_auth_key(MsnSwitchBoard *swboard) -{ - g_return_val_if_fail(swboard != NULL, NULL); - - return swboard->auth_key; -} - -void -msn_switchboard_set_session_id(MsnSwitchBoard *swboard, const char *id) -{ - g_return_if_fail(swboard != NULL); - g_return_if_fail(id != NULL); - - if (swboard->session_id != NULL) - g_free(swboard->session_id); - - swboard->session_id = g_strdup(id); -} - -const char * -msn_switchboard_get_session_id(MsnSwitchBoard *swboard) -{ - g_return_val_if_fail(swboard != NULL, NULL); - - return swboard->session_id; -} - -void -msn_switchboard_set_invited(MsnSwitchBoard *swboard, gboolean invited) -{ - g_return_if_fail(swboard != NULL); - - swboard->invited = invited; -} - -gboolean -msn_switchboard_is_invited(MsnSwitchBoard *swboard) -{ - g_return_val_if_fail(swboard != NULL, FALSE); - - return swboard->invited; -} - -/************************************************************************** - * Utility - **************************************************************************/ - -static void -send_clientcaps(MsnSwitchBoard *swboard) -{ - MsnMessage *msg; - - msg = msn_message_new(MSN_MSG_CAPS); - msn_message_set_content_type(msg, "text/x-clientcaps"); - msn_message_set_flag(msg, 'U'); - msn_message_set_bin_data(msg, MSN_CLIENTINFO, strlen(MSN_CLIENTINFO)); - - msn_switchboard_send_msg(swboard, msg, TRUE); - - msn_message_destroy(msg); -} - -static void -msn_switchboard_add_user(MsnSwitchBoard *swboard, const char *user) -{ - MsnCmdProc *cmdproc; - GaimAccount *account; - - g_return_if_fail(swboard != NULL); - - cmdproc = swboard->cmdproc; - account = cmdproc->session->account; - - swboard->users = g_list_prepend(swboard->users, g_strdup(user)); - swboard->current_users++; - swboard->empty = FALSE; - -#ifdef MSN_DEBUG_CHAT - gaim_debug_info("msn", "user=[%s], total=%d\n", user, - swboard->current_users); -#endif - - if (!(swboard->flag & MSN_SB_FLAG_IM) && (swboard->conv != NULL)) - { - /* This is a helper switchboard. */ - gaim_debug_error("msn", "switchboard_add_user: conv != NULL\n"); - return; - } - - if ((swboard->conv != NULL) && - (gaim_conversation_get_type(swboard->conv) == GAIM_CONV_TYPE_CHAT)) - { - gaim_conv_chat_add_user(GAIM_CONV_CHAT(swboard->conv), user, NULL, - GAIM_CBFLAGS_NONE, TRUE); - } - else if (swboard->current_users > 1 || swboard->total_users > 1) - { - if (swboard->conv == NULL || - gaim_conversation_get_type(swboard->conv) != GAIM_CONV_TYPE_CHAT) - { - GList *l; - -#ifdef MSN_DEBUG_CHAT - gaim_debug_info("msn", "[chat] Switching to chat.\n"); -#endif - -#if 0 - /* this is bad - it causes msn_switchboard_close to be called on the - * switchboard we're in the middle of using :( */ - if (swboard->conv != NULL) - gaim_conversation_destroy(swboard->conv); -#endif - - cmdproc->session->conv_seq++; - swboard->chat_id = cmdproc->session->conv_seq; - swboard->flag |= MSN_SB_FLAG_IM; - swboard->conv = serv_got_joined_chat(account->gc, - swboard->chat_id, - "MSN Chat"); - - for (l = swboard->users; l != NULL; l = l->next) - { - const char *tmp_user; - - tmp_user = l->data; - -#ifdef MSN_DEBUG_CHAT - gaim_debug_info("msn", "[chat] Adding [%s].\n", tmp_user); -#endif - - gaim_conv_chat_add_user(GAIM_CONV_CHAT(swboard->conv), - tmp_user, NULL, GAIM_CBFLAGS_NONE, TRUE); - } - -#ifdef MSN_DEBUG_CHAT - gaim_debug_info("msn", "[chat] We add ourselves.\n"); -#endif - - gaim_conv_chat_add_user(GAIM_CONV_CHAT(swboard->conv), - gaim_account_get_username(account), - NULL, GAIM_CBFLAGS_NONE, TRUE); - - g_free(swboard->im_user); - swboard->im_user = NULL; - } - } - else if (swboard->conv == NULL) - { - swboard->conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, - user, account); - } - else - { - gaim_debug_warning("msn", "switchboard_add_user: This should not happen!\n"); - } -} - -static GaimConversation * -msn_switchboard_get_conv(MsnSwitchBoard *swboard) -{ - GaimAccount *account; - - g_return_val_if_fail(swboard != NULL, NULL); - - if (swboard->conv != NULL) - return swboard->conv; - - gaim_debug_error("msn", "Switchboard with unassigned conversation\n"); - - account = swboard->session->account; - - return (swboard->conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, - account, swboard->im_user)); -} - -static void -msn_switchboard_report_user(MsnSwitchBoard *swboard, GaimMessageFlags flags, const char *msg) -{ - GaimConversation *conv; - - g_return_if_fail(swboard != NULL); - g_return_if_fail(msg != NULL); - - if ((conv = msn_switchboard_get_conv(swboard)) != NULL) - { - gaim_conversation_write(conv, NULL, msg, flags, time(NULL)); - } -} - -static void -swboard_error_helper(MsnSwitchBoard *swboard, int reason, const char *passport) -{ - g_return_if_fail(swboard != NULL); - - gaim_debug_warning("msg", "Error: Unable to call the user %s for reason %i\n", - passport ? passport : "(null)", reason); - - /* TODO: if current_users > 0, this is probably a chat and an invite failed, - * we should report that in the chat or something */ - if (swboard->current_users == 0) - { - swboard->error = reason; - msn_switchboard_close(swboard); - } -} - -static void -cal_error_helper(MsnTransaction *trans, int reason) -{ - MsnSwitchBoard *swboard; - const char *passport; - char **params; - - params = g_strsplit(trans->params, " ", 0); - - passport = params[0]; - - swboard = trans->data; - - gaim_debug_warning("msn", "cal_error_helper: command %s failed for reason %i\n",trans->command,reason); - - swboard_error_helper(swboard, reason, passport); - - g_strfreev(params); -} - -static void -msg_error_helper(MsnCmdProc *cmdproc, MsnMessage *msg, MsnMsgErrorType error) -{ - MsnSwitchBoard *swboard; - - g_return_if_fail(cmdproc != NULL); - g_return_if_fail(msg != NULL); - - if ((error != MSN_MSG_ERROR_SB) && (msg->nak_cb != NULL)) - msg->nak_cb(msg, msg->ack_data); - - swboard = cmdproc->data; - - /* This is not good, and should be fixed somewhere else. */ - g_return_if_fail(swboard != NULL); - - if (msg->type == MSN_MSG_TEXT) - { - const char *format, *str_reason; - char *body_str, *body_enc, *pre, *post; - -#if 0 - if (swboard->conv == NULL) - { - if (msg->ack_ref) - msn_message_unref(msg); - - return; - } -#endif - - if (error == MSN_MSG_ERROR_TIMEOUT) - { - str_reason = _("Message may have not been sent " - "because a timeout occurred:"); - } - else if (error == MSN_MSG_ERROR_SB) - { - switch (swboard->error) - { - case MSN_SB_ERROR_OFFLINE: - str_reason = _("Message could not be sent, " - "not allowed while invisible:"); - break; - case MSN_SB_ERROR_USER_OFFLINE: - str_reason = _("Message could not be sent " - "because the user is offline:"); - break; - case MSN_SB_ERROR_CONNECTION: - str_reason = _("Message could not be sent " - "because a connection error occurred:"); - break; - case MSN_SB_ERROR_TOO_FAST: - str_reason = _("Message could not be sent " - "because we are sending too quickly:"); - break; - default: - str_reason = _("Message could not be sent " - "because an error with " - "the switchboard occurred:"); - break; - } - } - else - { - str_reason = _("Message may have not been sent " - "because an unknown error occurred:"); - } - - body_str = msn_message_to_string(msg); - body_enc = g_markup_escape_text(body_str, -1); - g_free(body_str); - - format = msn_message_get_attr(msg, "X-MMS-IM-Format"); - msn_parse_format(format, &pre, &post); - body_str = g_strdup_printf("%s%s%s", pre ? pre : "", - body_enc ? body_enc : "", post ? post : ""); - g_free(body_enc); - g_free(pre); - g_free(post); - - msn_switchboard_report_user(swboard, GAIM_MESSAGE_ERROR, - str_reason); - msn_switchboard_report_user(swboard, GAIM_MESSAGE_RAW, - body_str); - - g_free(body_str); - } - - /* If a timeout occures we will want the msg around just in case we - * receive the ACK after the timeout. */ - if (msg->ack_ref && error != MSN_MSG_ERROR_TIMEOUT) - { - swboard->ack_list = g_list_remove(swboard->ack_list, msg); - msn_message_unref(msg); - } -} - -/************************************************************************** - * Message Stuff - **************************************************************************/ - -/** Called when a message times out. */ -static void -msg_timeout(MsnCmdProc *cmdproc, MsnTransaction *trans) -{ - MsnMessage *msg; - - msg = trans->data; - - msg_error_helper(cmdproc, msg, MSN_MSG_ERROR_TIMEOUT); -} - -/** Called when we receive an error of a message. */ -static void -msg_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) -{ - msg_error_helper(cmdproc, trans->data, MSN_MSG_ERROR_UNKNOWN); -} - -#if 0 -/** Called when we receive an ack of a special message. */ -static void -msg_ack(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnMessage *msg; - - msg = cmd->trans->data; - - if (msg->ack_cb != NULL) - msg->ack_cb(msg->ack_data); - - msn_message_unref(msg); -} - -/** Called when we receive a nak of a special message. */ -static void -msg_nak(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnMessage *msg; - - msg = cmd->trans->data; - - msn_message_unref(msg); -} -#endif - -static void -release_msg(MsnSwitchBoard *swboard, MsnMessage *msg) -{ - MsnCmdProc *cmdproc; - MsnTransaction *trans; - char *payload; - gsize payload_len; - - g_return_if_fail(swboard != NULL); - g_return_if_fail(msg != NULL); - - cmdproc = swboard->cmdproc; - - payload = msn_message_gen_payload(msg, &payload_len); - -#ifdef MSN_DEBUG_SB - gaim_debug_info("MaYuan","SB length:{%d}",payload_len); - msn_message_show_readable(msg, "SB SEND", FALSE); -#endif - - trans = msn_transaction_new(cmdproc, "MSG", "%c %d", - msn_message_get_flag(msg), payload_len); - - /* Data for callbacks */ - msn_transaction_set_data(trans, msg); - - if (msg->type == MSN_MSG_TEXT) - { - msg->ack_ref = TRUE; - msn_message_ref(msg); - swboard->ack_list = g_list_append(swboard->ack_list, msg); - msn_transaction_set_timeout_cb(trans, msg_timeout); - } - else if (msg->type == MSN_MSG_SLP) - { - msg->ack_ref = TRUE; - msn_message_ref(msg); - swboard->ack_list = g_list_append(swboard->ack_list, msg); - msn_transaction_set_timeout_cb(trans, msg_timeout); -#if 0 - if (msg->ack_cb != NULL) - { - msn_transaction_add_cb(trans, "ACK", msg_ack); - msn_transaction_add_cb(trans, "NAK", msg_nak); - } -#endif - } - - trans->payload = payload; - trans->payload_len = payload_len; - - msg->trans = trans; - - msn_cmdproc_send_trans(cmdproc, trans); -} - -static void -queue_msg(MsnSwitchBoard *swboard, MsnMessage *msg) -{ - g_return_if_fail(swboard != NULL); - g_return_if_fail(msg != NULL); - - gaim_debug_info("msn", "Appending message to queue.\n"); - - g_queue_push_tail(swboard->msg_queue, msg); - - msn_message_ref(msg); -} - -static void -process_queue(MsnSwitchBoard *swboard) -{ - MsnMessage *msg; - - g_return_if_fail(swboard != NULL); - - gaim_debug_info("msn", "Processing queue\n"); - - while ((msg = g_queue_pop_head(swboard->msg_queue)) != NULL) - { - gaim_debug_info("msn", "Sending message\n"); - release_msg(swboard, msg); - msn_message_unref(msg); - } -} - -gboolean -msn_switchboard_can_send(MsnSwitchBoard *swboard) -{ - g_return_val_if_fail(swboard != NULL, FALSE); - - if (swboard->empty || !g_queue_is_empty(swboard->msg_queue)) - return FALSE; - - return TRUE; -} - -void -msn_switchboard_send_msg(MsnSwitchBoard *swboard, MsnMessage *msg, - gboolean queue) -{ - g_return_if_fail(swboard != NULL); - g_return_if_fail(msg != NULL); - - gaim_debug_info("Ma Yuan","switchboard send msg..\n"); - if (msn_switchboard_can_send(swboard)) - release_msg(swboard, msg); - else if (queue) - queue_msg(swboard, msg); -} - -/************************************************************************** - * Switchboard Commands - **************************************************************************/ - -static void -ans_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnSwitchBoard *swboard; - - swboard = cmdproc->data; - swboard->ready = TRUE; -} - -static void -bye_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnSwitchBoard *swboard; - const char *user; - - swboard = cmdproc->data; - user = cmd->params[0]; - - if (!(swboard->flag & MSN_SB_FLAG_IM) && (swboard->conv != NULL)) - gaim_debug_error("msn_switchboard", "bye_cmd: helper bug\n"); - - if (swboard->conv == NULL) - { - /* This is a helper switchboard */ - msn_switchboard_destroy(swboard); - } - else if ((swboard->current_users > 1) || - (gaim_conversation_get_type(swboard->conv) == GAIM_CONV_TYPE_CHAT)) - { - /* This is a switchboard used for a chat */ - gaim_conv_chat_remove_user(GAIM_CONV_CHAT(swboard->conv), user, NULL); - swboard->current_users--; - if (swboard->current_users == 0) - msn_switchboard_destroy(swboard); - } - else - { - /* This is a switchboard used for a im session */ - msn_switchboard_destroy(swboard); - } -} - -static void -iro_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - GaimAccount *account; - GaimConnection *gc; - MsnSwitchBoard *swboard; - - account = cmdproc->session->account; - gc = account->gc; - swboard = cmdproc->data; - - swboard->total_users = atoi(cmd->params[2]); - - msn_switchboard_add_user(swboard, cmd->params[3]); -} - -static void -joi_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnSession *session; - GaimAccount *account; - GaimConnection *gc; - MsnSwitchBoard *swboard; - const char *passport; - - passport = cmd->params[0]; - - session = cmdproc->session; - account = session->account; - gc = account->gc; - swboard = cmdproc->data; - - msn_switchboard_add_user(swboard, passport); - - process_queue(swboard); - - if (!session->http_method) - send_clientcaps(swboard); - - if (swboard->closed) - msn_switchboard_close(swboard); -} - -static void -msg_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len) -{ - MsnMessage *msg; - - msg = msn_message_new_from_cmd(cmdproc->session, cmd); - - msn_message_parse_payload(msg, payload, len, - MSG_LINE_DEM,MSG_BODY_DEM); -#ifdef MSN_DEBUG_SB - msn_message_show_readable(msg, "SB RECV", FALSE); -#endif - - if (msg->remote_user != NULL) - g_free (msg->remote_user); - - msg->remote_user = g_strdup(cmd->params[0]); - msn_cmdproc_process_msg(cmdproc, msg); - - msn_message_destroy(msg); -} - -static void -msg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - cmdproc->servconn->payload_len = atoi(cmd->params[2]); - cmdproc->last_cmd->payload_cb = msg_cmd_post; -} - -static void -ubm_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - gaim_debug_misc("MaYuan","get UBM...\n"); - cmdproc->servconn->payload_len = atoi(cmd->params[4]); - cmdproc->last_cmd->payload_cb = msg_cmd_post; -} - -static void -nak_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnMessage *msg; - - msg = cmd->trans->data; - g_return_if_fail(msg != NULL); - - msg_error_helper(cmdproc, msg, MSN_MSG_ERROR_NAK); -} - -static void -ack_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnSwitchBoard *swboard; - MsnMessage *msg; - - msg = cmd->trans->data; - - if (msg->ack_cb != NULL) - msg->ack_cb(msg, msg->ack_data); - - swboard = cmdproc->data; - swboard->ack_list = g_list_remove(swboard->ack_list, msg); - msn_message_unref(msg); -} - -static void -out_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - GaimConnection *gc; - MsnSwitchBoard *swboard; - - gc = cmdproc->session->account->gc; - swboard = cmdproc->data; - - if (swboard->current_users > 1) - serv_got_chat_left(gc, swboard->chat_id); - - msn_switchboard_disconnect(swboard); -} - -static void -usr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnSwitchBoard *swboard; - - swboard = cmdproc->data; - -#if 0 - GList *l; - - for (l = swboard->users; l != NULL; l = l->next) - { - const char *user; - user = l->data; - - msn_cmdproc_send(cmdproc, "CAL", "%s", user); - } -#endif - - swboard->ready = TRUE; - msn_cmdproc_process_queue(cmdproc); -} - -/************************************************************************** - * Message Handlers - **************************************************************************/ -static void -plain_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - GaimConnection *gc; - MsnSwitchBoard *swboard; - const char *body; - char *body_str; - char *body_enc; - char *body_final; - size_t body_len; - const char *passport; - const char *value; - - gc = cmdproc->session->account->gc; - swboard = cmdproc->data; - - body = msn_message_get_bin_data(msg, &body_len); - body_str = g_strndup(body, body_len); - body_enc = g_markup_escape_text(body_str, -1); - g_free(body_str); - - passport = msg->remote_user; - - if (!strcmp(passport, "messenger@microsoft.com") && - strstr(body, "immediate security update")) - { - return; - } - -#if 0 - if ((value = msn_message_get_attr(msg, "User-Agent")) != NULL) - { - gaim_debug_misc("msn", "User-Agent = '%s'\n", value); - } -#endif - - if ((value = msn_message_get_attr(msg, "X-MMS-IM-Format")) != NULL) - { - char *pre, *post; - - msn_parse_format(value, &pre, &post); - - body_final = g_strdup_printf("%s%s%s", pre ? pre : "", - body_enc ? body_enc : "", post ? post : ""); - - g_free(pre); - g_free(post); - g_free(body_enc); - } - else - { - body_final = body_enc; - } - - swboard->flag |= MSN_SB_FLAG_IM; - - if (swboard->current_users > 1 || - ((swboard->conv != NULL) && - gaim_conversation_get_type(swboard->conv) == GAIM_CONV_TYPE_CHAT)) - { - /* If current_users is always ok as it should then there is no need to - * check if this is a chat. */ - if (swboard->current_users <= 1) - gaim_debug_misc("msn", "plain_msg: current_users(%d)\n", - swboard->current_users); - - serv_got_chat_in(gc, swboard->chat_id, passport, 0, body_final, - time(NULL)); - if (swboard->conv == NULL) - { - swboard->conv = gaim_find_chat(gc, swboard->chat_id); - swboard->flag |= MSN_SB_FLAG_IM; - } - } - else - { - serv_got_im(gc, passport, body_final, 0, time(NULL)); - if (swboard->conv == NULL) - { - swboard->conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, - passport, gaim_connection_get_account(gc)); - swboard->flag |= MSN_SB_FLAG_IM; - } - } - - g_free(body_final); -} - -static void -control_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - GaimConnection *gc; - MsnSwitchBoard *swboard; - char *passport; - - gc = cmdproc->session->account->gc; - swboard = cmdproc->data; - passport = msg->remote_user; - - if (swboard->current_users == 1 && - msn_message_get_attr(msg, "TypingUser") != NULL) - { - serv_got_typing(gc, passport, MSN_TYPING_RECV_TIMEOUT, - GAIM_TYPING); - } -} - -static void -clientcaps_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ -#if 0 - MsnSession *session; - MsnSwitchBoard *swboard; - MsnUser *user; - GHashTable *clientcaps; - const char *value; - - char *passport = msg->sender; - - session = cmdproc->session; - swboard = cmdproc->servconn->swboard; - - clientcaps = msn_message_get_hashtable_from_body(msg); -#endif -} - -static void -nudge_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - MsnSwitchBoard *swboard; - char *username, *str; - GaimAccount *account; - GaimBuddy *buddy; - const char *user; - - swboard = cmdproc->data; - account = cmdproc->session->account; - user = msg->remote_user; - - if ((buddy = gaim_find_buddy(account, user)) != NULL) - username = g_markup_escape_text(gaim_buddy_get_alias(buddy), -1); - else - username = g_markup_escape_text(user, -1); - - str = g_strdup_printf(_("%s just sent you a Nudge!"), username); - g_free(username); - msn_switchboard_report_user(swboard, GAIM_MESSAGE_SYSTEM, str); - g_free(str); -} - -/************************************************************************** - * Connect stuff - **************************************************************************/ -static void -connect_cb(MsnServConn *servconn) -{ - MsnSwitchBoard *swboard; - MsnCmdProc *cmdproc; - GaimAccount *account; - - cmdproc = servconn->cmdproc; - g_return_if_fail(cmdproc != NULL); - - account = cmdproc->session->account; - swboard = cmdproc->data; - g_return_if_fail(swboard != NULL); - - if (msn_switchboard_is_invited(swboard)){ - swboard->empty = FALSE; - - msn_cmdproc_send(cmdproc, "ANS", "%s %s %s", - gaim_account_get_username(account), - swboard->auth_key, swboard->session_id); - }else{ - msn_cmdproc_send(cmdproc, "USR", "%s %s", - gaim_account_get_username(account), - swboard->auth_key); - } -} - -static void -disconnect_cb(MsnServConn *servconn) -{ - MsnSwitchBoard *swboard; - - swboard = servconn->cmdproc->data; - g_return_if_fail(swboard != NULL); - - msn_servconn_set_disconnect_cb(swboard->servconn, NULL); - - msn_switchboard_destroy(swboard); -} - -gboolean -msn_switchboard_connect(MsnSwitchBoard *swboard, const char *host, int port) -{ - g_return_val_if_fail(swboard != NULL, FALSE); - - msn_servconn_set_connect_cb(swboard->servconn, connect_cb); - msn_servconn_set_disconnect_cb(swboard->servconn, disconnect_cb); - - return msn_servconn_connect(swboard->servconn, host, port); -} - -void -msn_switchboard_disconnect(MsnSwitchBoard *swboard) -{ - g_return_if_fail(swboard != NULL); - - msn_servconn_disconnect(swboard->servconn); -} - -/************************************************************************** - * Call stuff - **************************************************************************/ -static void -got_cal(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ -#if 0 - MsnSwitchBoard *swboard; - const char *user; - - swboard = cmdproc->data; - - user = cmd->params[0]; - - msn_switchboard_add_user(swboard, user); -#endif -} - -static void -cal_timeout(MsnCmdProc *cmdproc, MsnTransaction *trans) -{ - gaim_debug_warning("msn", "cal_timeout: command %s timed out\n", trans->command); - - cal_error_helper(trans, MSN_SB_ERROR_UNKNOWN); -} - -static void -cal_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) -{ - int reason = MSN_SB_ERROR_UNKNOWN; - MsnMessage *msg; - MsnSwitchBoard *swboard = trans->data; - - if (error == 215) - { - gaim_debug_info("msn", "Invited user already in switchboard\n"); - return; - } - else if (error == 217) - { - reason = MSN_SB_ERROR_USER_OFFLINE; - } - - gaim_debug_warning("msn", "cal_error: command %s gave error %i\n", trans->command, error); - gaim_debug_warning("msn", "Will Use Offline Message to sendit\n"); - -// cal_error_helper(trans, reason); - /*offline Message send Process*/ - - while ((msg = g_queue_pop_head(swboard->msg_queue)) != NULL){ - gaim_debug_warning("Ma Yuan","offline msg to send:{%s}\n",msg->body); - /* The messages could not be sent due to a switchboard error */ - swboard->error = MSN_SB_ERROR_USER_OFFLINE; - msg_error_helper(swboard->cmdproc, msg, - MSN_MSG_ERROR_SB); - msn_message_unref(msg); - } - cal_error_helper(trans, reason); -} - -void -msn_switchboard_request_add_user(MsnSwitchBoard *swboard, const char *user) -{ - MsnTransaction *trans; - MsnCmdProc *cmdproc; - - g_return_if_fail(swboard != NULL); - - cmdproc = swboard->cmdproc; - - trans = msn_transaction_new(cmdproc, "CAL", "%s", user); - /* this doesn't do anything, but users seem to think that - * 'Unhandled command' is some kind of error, so we don't report it */ - msn_transaction_add_cb(trans, "CAL", got_cal); - - msn_transaction_set_data(trans, swboard); - msn_transaction_set_timeout_cb(trans, cal_timeout); - - if (swboard->ready) - msn_cmdproc_send_trans(cmdproc, trans); - else - msn_cmdproc_queue_trans(cmdproc, trans); -} - -/************************************************************************** - * Create & Transfer stuff - **************************************************************************/ - -static void -got_swboard(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnSwitchBoard *swboard; - char *host; - int port; - swboard = cmd->trans->data; - - if (g_list_find(cmdproc->session->switches, swboard) == NULL) - /* The conversation window was closed. */ - return; - - gaim_debug_info("MaYuan","Switchboard:auth:{%s} socket:{%s}\n",cmd->params[4],cmd->params[2]); - msn_switchboard_set_auth_key(swboard, cmd->params[4]); - - msn_parse_socket(cmd->params[2], &host, &port); - - if (!msn_switchboard_connect(swboard, host, port)) - msn_switchboard_destroy(swboard); - - g_free(host); -} - -static void -xfr_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) -{ - MsnSwitchBoard *swboard; - int reason = MSN_SB_ERROR_UNKNOWN; - - if (error == 913) - reason = MSN_SB_ERROR_OFFLINE; - else if (error == 800) - reason = MSN_SB_ERROR_TOO_FAST; - - swboard = trans->data; - - gaim_debug_info("msn", "xfr_error %i for %s: trans %x, command %s, reason %i\n", - error, (swboard->im_user ? swboard->im_user : "(null)"), trans, - (trans->command ? trans->command : "(null)"), reason); - - swboard_error_helper(swboard, reason, swboard->im_user); -} - -void -msn_switchboard_request(MsnSwitchBoard *swboard) -{ - MsnCmdProc *cmdproc; - MsnTransaction *trans; - - g_return_if_fail(swboard != NULL); - - cmdproc = swboard->session->notification->cmdproc; - - trans = msn_transaction_new(cmdproc, "XFR", "%s", "SB"); - msn_transaction_add_cb(trans, "XFR", got_swboard); - - msn_transaction_set_data(trans, swboard); - msn_transaction_set_error_cb(trans, xfr_error); - - msn_cmdproc_send_trans(cmdproc, trans); -} - -void -msn_switchboard_close(MsnSwitchBoard *swboard) -{ - g_return_if_fail(swboard != NULL); - - if (swboard->error != MSN_SB_ERROR_NONE) - { - msn_switchboard_destroy(swboard); - } - else if (g_queue_is_empty(swboard->msg_queue) || - !swboard->session->connected) - { - MsnCmdProc *cmdproc; - cmdproc = swboard->cmdproc; - msn_cmdproc_send_quick(cmdproc, "OUT", NULL, NULL); - - msn_switchboard_destroy(swboard); - } - else - { - swboard->closed = TRUE; - } -} - -gboolean -msn_switchboard_release(MsnSwitchBoard *swboard, MsnSBFlag flag) -{ - g_return_val_if_fail(swboard != NULL, FALSE); - - swboard->flag &= ~flag; - - if (flag == MSN_SB_FLAG_IM) - /* Forget any conversation that used to be associated with this - * swboard. */ - swboard->conv = NULL; - - if (swboard->flag == 0) - { - msn_switchboard_close(swboard); - return TRUE; - } - - return FALSE; -} - -/************************************************************************** - * Init stuff - **************************************************************************/ - -void -msn_switchboard_init(void) -{ - cbs_table = msn_table_new(); - - msn_table_add_cmd(cbs_table, "ANS", "ANS", ans_cmd); - msn_table_add_cmd(cbs_table, "ANS", "IRO", iro_cmd); - - msn_table_add_cmd(cbs_table, "MSG", "ACK", ack_cmd); - msn_table_add_cmd(cbs_table, "MSG", "NAK", nak_cmd); - - msn_table_add_cmd(cbs_table, "USR", "USR", usr_cmd); - - msn_table_add_cmd(cbs_table, NULL, "MSG", msg_cmd); - msn_table_add_cmd(cbs_table, NULL, "UBM", ubm_cmd); - msn_table_add_cmd(cbs_table, NULL, "JOI", joi_cmd); - msn_table_add_cmd(cbs_table, NULL, "BYE", bye_cmd); - msn_table_add_cmd(cbs_table, NULL, "OUT", out_cmd); - -#if 0 - /* They might skip the history */ - msn_table_add_cmd(cbs_table, NULL, "ACK", NULL); -#endif - - msn_table_add_error(cbs_table, "MSG", msg_error); - msn_table_add_error(cbs_table, "CAL", cal_error); - - /* Register the message type callbacks. */ - msn_table_add_msg_type(cbs_table, "text/plain", - plain_msg); - msn_table_add_msg_type(cbs_table, "text/x-msmsgscontrol", - control_msg); - msn_table_add_msg_type(cbs_table, "text/x-clientcaps", - clientcaps_msg); - msn_table_add_msg_type(cbs_table, "text/x-clientinfo", - clientcaps_msg); - msn_table_add_msg_type(cbs_table, "application/x-msnmsgrp2p", - msn_p2p_msg); - msn_table_add_msg_type(cbs_table, "text/x-mms-emoticon", - msn_emoticon_msg); - msn_table_add_msg_type(cbs_table, "text/x-mms-animemoticon", - msn_emoticon_msg); - msn_table_add_msg_type(cbs_table, "text/x-msnmsgr-datacast", - nudge_msg); -#if 0 - msn_table_add_msg_type(cbs_table, "text/x-msmmsginvite", - msn_invite_msg); -#endif -} - -void -msn_switchboard_end(void) -{ - msn_table_destroy(cbs_table); -}