Mercurial > pidgin
diff src/protocols/msn/switchboard.c @ 5309:e2e53316a21d
[gaim-migrate @ 5681]
Announcing the new MSN prpl! It probably has some bugs, and for the time
being, there is no file transfer. That's good though, because the current
MSN file transfer is a little broken. I've had many corrupted files. I'll
commit new file transfer code when it's written.
I want this heavily tested before 0.63! If you use MSN, please talk to
people on it. Let me know of any oddities, crashes, bugs, whatever. I'll
fix things as I find them.
committer: Tailor Script <tailor@pidgin.im>
author | Christian Hammond <chipx86@chipx86.com> |
---|---|
date | Tue, 06 May 2003 02:06:56 +0000 |
parents | abe4d103e300 |
children | d5690ed70085 |
line wrap: on
line diff
--- a/src/protocols/msn/switchboard.c Tue May 06 00:34:54 2003 +0000 +++ b/src/protocols/msn/switchboard.c Tue May 06 02:06:56 2003 +0000 @@ -17,518 +17,535 @@ * * 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 - * +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "msn.h" +#include "switchboard.h" +#include "utils.h" -#ifdef _WIN32 -#include "win32dep.h" -#endif +static GHashTable *switchboard_commands = NULL; +static GHashTable *switchboard_msg_types = NULL; + -G_MODULE_IMPORT GSList *connections; +/************************************************************************** + * Catch-all commands + **************************************************************************/ +static gboolean +__blank_cmd(MsnServConn *servconn, const char *command, const char **params, + size_t param_count) +{ + return TRUE; +} -static char * -msn_parse_format(char *mime) +static gboolean +__unknown_cmd(MsnServConn *servconn, const char *command, const char **params, + size_t param_count) { - char *cur; - GString *ret = g_string_new(NULL); - guint colorbuf; - char *colors = (char *)(&colorbuf); - + gaim_debug(GAIM_DEBUG_ERROR, "msg", + "Handled switchboard message: %s\n", command); + + return FALSE; +} + +/************************************************************************** + * Switchboard Commands + **************************************************************************/ +static gboolean +__ans_cmd(MsnServConn *servconn, const char *command, const char **params, + size_t param_count) +{ + struct gaim_connection *gc = servconn->session->account->gc; + MsnSwitchBoard *swboard = servconn->data; + + if (swboard->chat != NULL) + gaim_chat_add_user(GAIM_CHAT(swboard->chat), gc->username, NULL); + + return TRUE; +} - cur = strstr(mime, "FN="); - if (cur && (*(cur = cur + 3) != ';')) { - ret = g_string_append(ret, "<FONT FACE=\""); - while (*cur && *cur != ';') { - ret = g_string_append_c(ret, *cur); - cur++; - } - ret = g_string_append(ret, "\">"); +static gboolean +__bye_cmd(MsnServConn *servconn, const char *command, const char **params, + size_t param_count) +{ + struct gaim_connection *gc = servconn->session->account->gc; + MsnSwitchBoard *swboard = servconn->data; + const char *user = params[0]; + + if (swboard->chat != NULL) + gaim_chat_remove_user(GAIM_CHAT(swboard->chat), user, NULL); + else { + const char *username; + struct gaim_conversation *conv; + struct buddy *b; + char buf[MSN_BUF_LEN]; + + if ((b = gaim_find_buddy(gc->account, user)) != NULL) + username = gaim_get_buddy_alias(b); + else + username = user; + + g_snprintf(buf, sizeof(buf), + _("%s has closed the conversation window."), username); + + if ((conv = gaim_find_conversation(user)) != NULL) + gaim_conversation_write(conv, NULL, buf, -1, WFLAG_SYSTEM, + time(NULL)); + + msn_switchboard_destroy(swboard); + + return FALSE; } - - cur = strstr(mime, "EF="); - if (cur && (*(cur = cur + 3) != ';')) { - while (*cur && *cur != ';') { - ret = g_string_append_c(ret, '<'); - ret = g_string_append_c(ret, *cur); - ret = g_string_append_c(ret, '>'); - cur++; - } + + return TRUE; +} + +static gboolean +__iro_cmd(MsnServConn *servconn, const char *command, const char **params, + size_t param_count) +{ + struct gaim_connection *gc = servconn->session->account->gc; + MsnSwitchBoard *swboard = servconn->data; + + swboard->total_users = atoi(params[2]); + + if (swboard->total_users > 1) { + if (swboard->chat == NULL) + swboard->chat = serv_got_joined_chat(gc, ++swboard->chat_id, + "MSN Chat"); + + gaim_chat_add_user(GAIM_CHAT(swboard->chat), params[3], NULL); } - - cur = strstr(mime, "CO="); - if (cur && (*(cur = cur + 3) != ';')) { - if (sscanf (cur, "%x;", &colorbuf) == 1) { - char tag[64]; - g_snprintf(tag, sizeof(tag), "<FONT COLOR=\"#%02hhx%02hhx%02hhx\">", colors[0], colors[1], colors[2]); - ret = g_string_append(ret, tag); - } - } - - cur = url_decode(ret->str); - g_string_free(ret, TRUE); - return cur; + + if (swboard->chat != NULL) + gaim_chat_add_user(GAIM_CHAT(swboard->chat), gc->username, NULL); + + return TRUE; } -static int -msn_process_switch(struct msn_switchboard *ms, char *buf) +static gboolean +__joi_cmd(MsnServConn *servconn, const char *command, const char **params, + size_t param_count) { - struct gaim_connection *gc = ms->gc; - char sendbuf[MSN_BUF_LEN]; - static int id = 0; - - if (!g_ascii_strncasecmp(buf, "ACK", 3)) { - } else if (!g_ascii_strncasecmp(buf, "ANS", 3)) { - if (ms->chat) - gaim_chat_add_user(GAIM_CHAT(ms->chat), gc->username, NULL); - } else if (!g_ascii_strncasecmp(buf, "BYE", 3)) { - char *user, *tmp = buf; - GET_NEXT(tmp); - user = tmp; - - if (ms->chat) { - gaim_chat_remove_user(GAIM_CHAT(ms->chat), user, NULL); - } else { - char msgbuf[256]; - const char *username; - struct gaim_conversation *cnv; - struct buddy *b; - - if ((b = gaim_find_buddy(gc->account, user)) != NULL) - username = gaim_get_buddy_alias(b); - else - username = user; - - g_snprintf(msgbuf, sizeof(msgbuf), - _("%s has closed the conversation window"), username); + struct gaim_connection *gc = servconn->session->account->gc; + MsnSwitchBoard *swboard = servconn->data; + const char *passport; - if ((cnv = gaim_find_conversation(user))) - gaim_conversation_write(cnv, NULL, msgbuf, -1, - WFLAG_SYSTEM, time(NULL)); - - msn_kill_switch(ms); - return 0; - } - } else if (!g_ascii_strncasecmp(buf, "CAL", 3)) { - } else if (!g_ascii_strncasecmp(buf, "IRO", 3)) { - char *tot, *user, *tmp = buf; + passport = params[0]; - GET_NEXT(tmp); - GET_NEXT(tmp); - GET_NEXT(tmp); - tot = tmp; - GET_NEXT(tmp); - ms->total = atoi(tot); - user = tmp; - GET_NEXT(tmp); - - if (ms->total > 1) { - if (!ms->chat) - ms->chat = serv_got_joined_chat(gc, ++id, "MSN Chat"); - - gaim_chat_add_user(GAIM_CHAT(ms->chat), user, NULL); - } - } else if (!g_ascii_strncasecmp(buf, "JOI", 3)) { - char *user, *tmp = buf; - GET_NEXT(tmp); - user = tmp; - GET_NEXT(tmp); + if (swboard->total_users == 1) { + swboard->chat = serv_got_joined_chat(gc, ++swboard->chat_id, + "MSN Chat"); + gaim_chat_add_user(GAIM_CHAT(swboard->chat), + msn_user_get_passport(swboard->user), NULL); + gaim_chat_add_user(GAIM_CHAT(swboard->chat), gc->username, NULL); - if (ms->total == 1) { - ms->chat = serv_got_joined_chat(gc, ++id, "MSN Chat"); - gaim_chat_add_user(GAIM_CHAT(ms->chat), ms->user, NULL); - gaim_chat_add_user(GAIM_CHAT(ms->chat), gc->username, NULL); - g_free(ms->user); - ms->user = NULL; - } - if (ms->chat) - gaim_chat_add_user(GAIM_CHAT(ms->chat), user, NULL); - ms->total++; - while (ms->txqueue) { - char *send = add_cr(ms->txqueue->data); - g_snprintf(sendbuf, sizeof(sendbuf), - "MSG %u N %d\r\n%s%s", ++ms->trId, - strlen(MIME_HEADER) + strlen(send), - MIME_HEADER, send); + msn_user_unref(swboard->user); + } - g_free(ms->txqueue->data); - ms->txqueue = g_slist_remove(ms->txqueue, ms->txqueue->data); + if (swboard->chat != NULL) + gaim_chat_add_user(GAIM_CHAT(swboard->chat), passport, NULL); - if (msn_write(ms->fd, sendbuf, strlen(sendbuf)) < 0) { - msn_kill_switch(ms); - return 0; - } - } - } else if (!g_ascii_strncasecmp(buf, "MSG", 3)) { - char *user, *tmp = buf; - int length; - - GET_NEXT(tmp); - user = tmp; - - GET_NEXT(tmp); + swboard->total_users++; - GET_NEXT(tmp); - length = atoi(tmp); + while (servconn->txqueue) { + char *buf = servconn->txqueue->data; - ms->msg = TRUE; - ms->msguser = g_strdup(user); - ms->msglen = length; - } else if (!g_ascii_strncasecmp(buf, "NAK", 3)) { - do_error_dialog(_("An MSN message may not have been received."), NULL, GAIM_ERROR); - } else if (!g_ascii_strncasecmp(buf, "NLN", 3)) { - } else if (!g_ascii_strncasecmp(buf, "OUT", 3)) { - if (ms->chat) - serv_got_chat_left(gc, gaim_chat_get_id(GAIM_CHAT(ms->chat))); - msn_kill_switch(ms); - return 0; - } else if (!g_ascii_strncasecmp(buf, "USR", 3)) { - /* good, we got USR, now we need to find out who we want to talk to */ - struct msn_switchboard *ms = msn_find_writable_switch(gc); + servconn->txqueue = g_slist_remove(servconn->txqueue, buf); - if (!ms) - return 0; - - g_snprintf(sendbuf, sizeof(sendbuf), "CAL %u %s\r\n", - ++ms->trId, ms->user); + if (msn_servconn_write(swboard->servconn, buf, strlen(buf)) < 0) { + msn_switchboard_destroy(swboard); - if (msn_write(ms->fd, sendbuf, strlen(sendbuf)) < 0) { - msn_kill_switch(ms); - return 0; + return FALSE; } - } else if (isdigit(*buf)) { - handle_errcode(buf, TRUE); - - if (atoi(buf) == 217) - msn_kill_switch(ms); - - } else { - gaim_debug(GAIM_DEBUG_WARNING, "msn", "Unhandled message!\n"); } - return 1; + return TRUE; +} + +static gboolean +__msg_cmd(MsnServConn *servconn, const char *command, const char **params, + size_t param_count) +{ + gaim_debug(GAIM_DEBUG_INFO, "msn", "Found message. Parsing.\n"); + + servconn->parsing_msg = TRUE; + servconn->msg_passport = g_strdup(params[0]); + servconn->msg_friendly = g_strdup(params[1]); + servconn->msg_len = atoi(params[2]); + + return TRUE; +} + +static gboolean +__nak_cmd(MsnServConn *servconn, const char *command, const char **params, + size_t param_count) +{ + /* + * TODO: Investigate this, as it seems to occur frequently with + * the old prpl. + */ + do_error_dialog(_("An MSN message may not have been received."), + NULL, GAIM_ERROR); + + return TRUE; } -static void -msn_process_switch_msg(struct msn_switchboard *ms, char *msg) +static gboolean +__out_cmd(MsnServConn *servconn, const char *command, const char **params, + size_t param_count) +{ + struct gaim_connection *gc = servconn->session->account->gc; + MsnSwitchBoard *swboard = servconn->data; + + if (swboard->chat != NULL) + serv_got_chat_left(gc, gaim_chat_get_id(GAIM_CHAT(swboard->chat))); + + msn_switchboard_destroy(swboard); + + return FALSE; +} + +static gboolean +__usr_cmd(MsnServConn *servconn, const char *command, const char **params, + size_t param_count) { - char *content, *agent, *format; - char *message = NULL; + MsnSwitchBoard *swboard = servconn->data; + + if (!msn_switchboard_send_command(swboard, "CAL", + msn_user_get_passport(swboard->user))) { + msn_switchboard_destroy(swboard); + + return FALSE; + } + + return TRUE; +} + +/************************************************************************** + * Message Types + **************************************************************************/ +static gboolean +__plain_msg(MsnServConn *servconn, const MsnMessage *msg) +{ + struct gaim_connection *gc = servconn->session->account->gc; + MsnSwitchBoard *swboard = servconn->data; + char *body; + const char *value; + char *format; int flags = 0; - agent = strstr(msg, "User-Agent: "); - if (agent) { - if (!g_ascii_strncasecmp(agent, "User-Agent: Gaim", - strlen("User-Agent: Gaim"))) + body = g_strdup(msn_message_get_body(msg)); + + if ((value = msn_message_get_attr(msg, "User-Agent")) != NULL) { + if (!g_ascii_strncasecmp(value, "Gaim", 4)) flags |= IM_FLAG_GAIMUSER; } - format = strstr(msg, "X-MMS-IM-Format: "); - if (format) { - format = msn_parse_format(format); - } else { - format = NULL; + if ((value = msn_message_get_attr(msg, "X-MMS-IM-Format")) != NULL) { + format = msn_parse_format(value); + + body = g_strdup_printf("%s%s", format, body); + + g_free(format); + } + + if (swboard->chat != NULL) + serv_got_chat_in(gc, gaim_chat_get_id(GAIM_CHAT(swboard->chat)), + servconn->msg_passport, flags, body, time(NULL)); + else + serv_got_im(gc, servconn->msg_passport, body, flags, time(NULL), -1); + + g_free(body); + + return TRUE; +} + +static gboolean +__control_msg(MsnServConn *servconn, const MsnMessage *msg) +{ + struct gaim_connection *gc = servconn->session->account->gc; + MsnSwitchBoard *swboard = servconn->data; + const char *value; + + if (swboard->chat == NULL && + (value = msn_message_get_attr(msg, "TypingUser")) != NULL) { + + serv_got_typing(gc, servconn->msg_passport, MSN_TYPING_RECV_TIMEOUT, + TYPING); } - content = strstr(msg, "Content-Type: "); - if (!content) - return; - if (!g_ascii_strncasecmp(content, "Content-Type: text/x-msmsgscontrol\r\n", - strlen( "Content-Type: text/x-msmsgscontrol\r\n"))) { - if (strstr(content,"TypingUser: ") && !ms->chat) { - serv_got_typing(ms->gc, ms->msguser, - MSN_TYPING_RECV_TIMEOUT, TYPING); - return; - } + return TRUE; +} - } else if (!g_ascii_strncasecmp(content, "Content-Type: text/x-msmsgsinvite;", - strlen("Content-Type: text/x-msmsgsinvite;"))) { +/************************************************************************** + * Connect stuff + **************************************************************************/ +static gboolean +__connect_cb(gpointer data, gint source, GaimInputCondition cond) +{ + MsnServConn *servconn = data; + MsnSwitchBoard *swboard = servconn->data; + char outparams[MSN_BUF_LEN]; - /* - * NOTE: Other things, such as voice communication, would go in - * here too (since they send the same Content-Type). However, - * this is the best check for file transfer messages, so I'm - * calling msn_process_ft_invite_msg(). If anybody adds support - * for anything else that sends a text/x-msmsgsinvite, perhaps - * this should be changed. For now, it stays. - */ - msn_process_ft_msg(ms, content); + if (servconn->fd != source) + servconn->fd = source; + + swboard->in_use = TRUE; + + gaim_debug(GAIM_DEBUG_INFO, "msn", "Connecting to switchboard...\n"); - } else if (!g_ascii_strncasecmp(content, "Content-Type: text/plain", - strlen("Content-Type: text/plain"))) { + if (msn_switchboard_is_invited(swboard)) { + g_snprintf(outparams, sizeof(outparams), "%s %s %s", + servconn->session->account->gc->username, + swboard->auth_key, swboard->session_id); - char *skiphead = strstr(msg, "\r\n\r\n"); - - if (!skiphead || !skiphead[4]) { - return; - } + if (!msn_switchboard_send_command(swboard, "ANS", outparams)) { + msn_switchboard_destroy(swboard); - skiphead += 4; - strip_linefeed(skiphead); - - if (format) { - message = g_strdup_printf("%s%s", format, skiphead); - } else { - message = g_strdup(skiphead); + return FALSE; } - - if (ms->chat) - serv_got_chat_in(ms->gc, gaim_chat_get_id(GAIM_CHAT(ms->chat)), - ms->msguser, flags, message, time(NULL)); - else - serv_got_im(ms->gc, ms->msguser, message, flags, time(NULL), -1); + } + else { + g_snprintf(outparams, sizeof(outparams), "%s %s", + servconn->session->account->gc->username, swboard->auth_key); - g_free(message); + if (!msn_switchboard_send_command(swboard, "USR", outparams)) { + msn_switchboard_destroy(swboard); + + return FALSE; + } } + + return TRUE; } static void -msn_switchboard_callback(gpointer data, gint source, GaimInputCondition cond) +__failed_read_cb(gpointer data, gint source, GaimInputCondition cond) +{ + MsnServConn *servconn = data; + + msn_switchboard_destroy(servconn->data); +} + +MsnSwitchBoard * +msn_switchboard_new(MsnSession *session) { - struct msn_switchboard *ms = data; - char buf[MSN_BUF_LEN]; - int cont = 1; - int len; - - ms->fd = source; - len = read(ms->fd, buf, sizeof(buf)); - if (len <= 0) { - msn_kill_switch(ms); - return; + MsnSwitchBoard *swboard; + MsnServConn *servconn; + + g_return_val_if_fail(session != NULL, NULL); + + swboard = g_new0(MsnSwitchBoard, 1); + + swboard->servconn = servconn = msn_servconn_new(session); + msn_servconn_set_connect_cb(servconn, __connect_cb); + msn_servconn_set_failed_read_cb(servconn, __failed_read_cb); + + servconn->data = swboard; + + session->switches = g_list_append(session->switches, swboard); + + if (switchboard_commands == NULL) { + /* Register the command callbacks. */ + msn_servconn_register_command(servconn, "ACK", __blank_cmd); + msn_servconn_register_command(servconn, "ANS", __ans_cmd); + msn_servconn_register_command(servconn, "BYE", __bye_cmd); + msn_servconn_register_command(servconn, "CAL", __blank_cmd); + msn_servconn_register_command(servconn, "IRO", __iro_cmd); + msn_servconn_register_command(servconn, "JOI", __joi_cmd); + msn_servconn_register_command(servconn, "MSG", __msg_cmd); + msn_servconn_register_command(servconn, "NAK", __nak_cmd); + msn_servconn_register_command(servconn, "NLN", __blank_cmd); + msn_servconn_register_command(servconn, "OUT", __out_cmd); + msn_servconn_register_command(servconn, "USR", __usr_cmd); + msn_servconn_register_command(servconn, "_unknown_", __unknown_cmd); + + /* Register the message type callbacks. */ + msn_servconn_register_msg_type(servconn, "text/plain", __plain_msg); + msn_servconn_register_msg_type(servconn, "text/x-msmsgscontrol", + __control_msg); + + /* Save these for future use. */ + switchboard_commands = servconn->commands; + switchboard_msg_types = servconn->msg_types; + } + else { + g_hash_table_destroy(servconn->commands); + g_hash_table_destroy(servconn->msg_types); + + servconn->commands = switchboard_commands; + servconn->msg_types = switchboard_msg_types; } - ms->rxqueue = g_realloc(ms->rxqueue, len + ms->rxlen); - memcpy(ms->rxqueue + ms->rxlen, buf, len); - ms->rxlen += len; - - while (cont) { - if (!ms->rxlen) - return; - - if (ms->msg) { - char *msg; - if (ms->msglen > ms->rxlen) - return; - msg = ms->rxqueue; - ms->rxlen -= ms->msglen; - if (ms->rxlen) { - ms->rxqueue = g_memdup(msg + ms->msglen, ms->rxlen); - } else { - ms->rxqueue = NULL; - msg = g_realloc(msg, ms->msglen + 1); - } - msg[ms->msglen] = 0; - ms->msglen = 0; - ms->msg = FALSE; - - msn_process_switch_msg(ms, msg); - - g_free(ms->msguser); - g_free(msg); - } else { - char *end = ms->rxqueue; - int cmdlen; - char *cmd; - int i = 0; - - while (i + 1 < ms->rxlen) { - if (*end == '\r' && end[1] == '\n') - break; - end++; i++; - } - if (i + 1 == ms->rxlen) - return; - - cmdlen = end - ms->rxqueue + 2; - cmd = ms->rxqueue; - ms->rxlen -= cmdlen; - if (ms->rxlen) { - ms->rxqueue = g_memdup(cmd + cmdlen, ms->rxlen); - } else { - ms->rxqueue = NULL; - cmd = g_realloc(cmd, cmdlen + 1); - } - cmd[cmdlen] = 0; - - gaim_debug(GAIM_DEBUG_MISC, "msn", "S: %s", cmd); - g_strchomp(cmd); - cont = msn_process_switch(ms, cmd); - - g_free(cmd); - } - } + return swboard; } void -msn_rng_connect(gpointer data, gint source, GaimInputCondition cond) +msn_switchboard_destroy(MsnSwitchBoard *swboard) { - struct msn_switchboard *ms = data; - struct gaim_connection *gc = ms->gc; - struct msn_data *md; - char buf[MSN_BUF_LEN]; + MsnSession *session; + + g_return_if_fail(swboard != NULL); + + session = swboard->servconn->session; - if (source == -1 || !g_slist_find(connections, gc)) { - close(source); - g_free(ms->sessid); - g_free(ms->auth); - g_free(ms); - return; - } + if (swboard->servconn->connected) + msn_switchboard_disconnect(swboard); + + if (swboard->user != NULL) + msn_user_unref(swboard->user); + + if (swboard->auth_key != NULL) + g_free(swboard->auth_key); - md = gc->proto_data; + if (swboard->session_id != NULL) + g_free(swboard->session_id); - if (ms->fd != source) - ms->fd = source; + session->switches = g_list_remove(session->switches, swboard); + + msn_servconn_destroy(swboard->servconn); - g_snprintf(buf, sizeof(buf), "ANS %u %s %s %s\r\n", ++ms->trId, gc->username, ms->auth, ms->sessid); - if (msn_write(ms->fd, buf, strlen(buf)) < 0) { - close(ms->fd); - g_free(ms->sessid); - g_free(ms->auth); - g_free(ms); - return; - } + g_free(swboard); +} - md->switches = g_slist_append(md->switches, ms); - ms->inpa = gaim_input_add(ms->fd, GAIM_INPUT_READ, - msn_switchboard_callback, ms); +void +msn_switchboard_set_user(MsnSwitchBoard *swboard, MsnUser *user) +{ + g_return_if_fail(swboard != NULL); + + swboard->user = user; + + msn_user_ref(user); } -static void -msn_ss_xfr_connect(gpointer data, gint source, GaimInputCondition cond) +MsnUser * +msn_switchboard_get_user(const MsnSwitchBoard *swboard) { - struct msn_switchboard *ms = data; - struct gaim_connection *gc = ms->gc; - char buf[MSN_BUF_LEN]; + g_return_val_if_fail(swboard != NULL, NULL); - if (source == -1 || !g_slist_find(connections, gc)) { - close(source); - if (g_slist_find(connections, gc)) { - msn_kill_switch(ms); - do_error_dialog(_("Gaim was unable to send an MSN message"), - _("Gaim encountered an error communicating with the " - "MSN switchboard server. Please try again later."), - GAIM_ERROR); - } + return swboard->user; +} - return; - } - - if (ms->fd != source) - ms->fd = source; - - g_snprintf(buf, sizeof(buf), "USR %u %s %s\r\n", - ++ms->trId, gc->username, ms->auth); +void +msn_switchboard_set_auth_key(MsnSwitchBoard *swboard, const char *key) +{ + g_return_if_fail(swboard != NULL); + g_return_if_fail(key != NULL); - if (msn_write(ms->fd, buf, strlen(buf)) < 0) { - g_free(ms->auth); - g_free(ms); - return; - } - - ms->inpa = gaim_input_add(ms->fd, GAIM_INPUT_READ, - msn_switchboard_callback, ms); + swboard->auth_key = g_strdup(key); } -struct msn_switchboard * -msn_find_switch(struct gaim_connection *gc, const char *username) +const char * +msn_switchboard_get_auth_key(const MsnSwitchBoard *swboard) { - struct msn_data *md = (struct msn_data *)gc->proto_data; - GSList *m = md->switches; + g_return_val_if_fail(swboard != NULL, NULL); - for (m = md->switches; m != NULL; m = m->next) { - struct msn_switchboard *ms = (struct msn_switchboard *)m->data; - - if (ms->total <= 1 && !gaim_utf8_strcasecmp(ms->user, username)) - return ms; - } - - return NULL; + return swboard->auth_key; } -struct msn_switchboard * -msn_find_switch_by_id(struct gaim_connection *gc, int chat_id) +void +msn_switchboard_set_session_id(MsnSwitchBoard *swboard, const char *id) { - struct msn_data *md = (struct msn_data *)gc->proto_data; - GSList *m; + g_return_if_fail(swboard != NULL); + g_return_if_fail(id != NULL); - for (m = md->switches; m != NULL; m = m->next) { - struct msn_switchboard *ms = (struct msn_switchboard *)m->data; + if (swboard->session_id != NULL) + g_free(swboard->session_id); - if (ms->chat && gaim_chat_get_id(GAIM_CHAT(ms->chat)) == chat_id) - return ms; - } - - return NULL; + swboard->session_id = g_strdup(id); } -struct msn_switchboard * -msn_find_writable_switch(struct gaim_connection *gc) +const char * +msn_switchboard_get_session_id(const MsnSwitchBoard *swboard) { - struct msn_data *md = (struct msn_data *)gc->proto_data; - GSList *m; - - for (m = md->switches; m != NULL; m = m->next) { - struct msn_switchboard *ms = (struct msn_switchboard *)m->data; + g_return_val_if_fail(swboard != NULL, NULL); - if (ms->txqueue != NULL) - return ms; - } - - return NULL; + return swboard->session_id; } void -msn_kill_switch(struct msn_switchboard *ms) +msn_switchboard_set_invited(MsnSwitchBoard *swboard, gboolean invited) +{ + g_return_if_fail(swboard != NULL); + + swboard->invited = invited; +} + +gboolean +msn_switchboard_is_invited(const MsnSwitchBoard *swboard) { - struct gaim_connection *gc = ms->gc; - struct msn_data *md = gc->proto_data; + g_return_val_if_fail(swboard != NULL, FALSE); + + return swboard->invited; +} - if (ms->inpa) - gaim_input_remove(ms->inpa); +gboolean +msn_switchboard_connect(MsnSwitchBoard *swboard, const char *server, int port) +{ + g_return_val_if_fail(swboard != NULL, FALSE); + + msn_servconn_set_server(swboard->servconn, server, port); + + if (msn_servconn_connect(swboard->servconn)) + swboard->in_use = TRUE; + + return swboard->in_use; +} - close(ms->fd); - g_free(ms->rxqueue); +void +msn_switchboard_disconnect(MsnSwitchBoard *swboard) +{ + g_return_if_fail(swboard != NULL); + g_return_if_fail(swboard->servconn->connected); + + msn_servconn_disconnect(swboard->servconn); + + swboard->in_use = FALSE; +} - if (ms->msg) g_free(ms->msguser); - if (ms->user) g_free(ms->user); - if (ms->sessid) g_free(ms->sessid); +gboolean +msn_switchboard_send_msg(MsnSwitchBoard *swboard, MsnMessage *msg) +{ + char *buf; + int ret; + + g_return_val_if_fail(swboard != NULL, FALSE); + g_return_val_if_fail(msg != NULL, FALSE); - g_free(ms->auth); + msn_message_set_transaction_id(msg, ++swboard->trId); + buf = msn_message_build_string(msg); - while (ms->txqueue) { - g_free(ms->txqueue->data); - ms->txqueue = g_slist_remove(ms->txqueue, ms->txqueue->data); + if (swboard->servconn->txqueue != NULL || !swboard->in_use) { + gaim_debug(GAIM_DEBUG_INFO, "msn", "Appending message to queue.\n"); + + swboard->servconn->txqueue = + g_slist_append(swboard->servconn->txqueue, buf); + + return TRUE; } - if (ms->chat) - serv_got_chat_left(gc, gaim_chat_get_id(GAIM_CHAT(ms->chat))); + ret = msn_servconn_write(swboard->servconn, buf, strlen(buf)); - md->switches = g_slist_remove(md->switches, ms); + g_free(buf); - g_free(ms); + return (ret > 0); } -struct msn_switchboard * -msn_switchboard_connect(struct gaim_connection *gc, const char *host, int port) +gboolean +msn_switchboard_send_command(MsnSwitchBoard *swboard, const char *command, + const char *params) { - struct msn_switchboard *ms; + char buf[MSN_BUF_LEN]; - if (host == NULL || port == 0) - return NULL; - - ms = msn_find_writable_switch(gc); + g_return_val_if_fail(swboard != NULL, FALSE); + g_return_val_if_fail(command != NULL, FALSE); - if (ms == NULL) - return NULL; + if (params == NULL) + g_snprintf(buf, sizeof(buf), "%s %u\r\n", command, + ++swboard->trId); + else + g_snprintf(buf, sizeof(buf), "%s %u %s\r\n", + command, ++swboard->trId, params); - if (proxy_connect(gc->account, (char *)host, port, msn_ss_xfr_connect, - ms) != 0) { - msn_kill_switch(ms); - - return NULL; - } - - return ms; + return (msn_servconn_write(swboard->servconn, buf, strlen(buf)) > 0); }