diff options
author | dequis <dx@dxzone.com.ar> | 2015-03-09 05:35:50 -0300 |
---|---|---|
committer | dequis <dx@dxzone.com.ar> | 2015-04-10 14:10:40 -0300 |
commit | 11e42dcf7366ee547b9651648724d35d12e36091 (patch) | |
tree | afc7c81e586d1fb119c5e2856be0742db9963430 /protocols/msn/sb.c | |
parent | 254a4dab408b67f78b94054514bbf6f629dd6bba (diff) |
msn: removed switchboards, implemented SDG message
Diffstat (limited to 'protocols/msn/sb.c')
-rw-r--r-- | protocols/msn/sb.c | 712 |
1 files changed, 0 insertions, 712 deletions
diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c deleted file mode 100644 index 673d65c7..00000000 --- a/protocols/msn/sb.c +++ /dev/null @@ -1,712 +0,0 @@ -/********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2012 Wilmer van der Gaast and others * - \********************************************************************/ - -/* MSN module - Switchboard server callbacks and utilities */ - -/* - 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 with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 51 Franklin St., - Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include <ctype.h> -#include "nogaim.h" -#include "msn.h" -#include "md5.h" -#include "soap.h" - -static gboolean msn_sb_callback(gpointer data, gint source, b_input_condition cond); -static int msn_sb_command(struct msn_handler_data *handler, char **cmd, int num_parts); -static int msn_sb_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts); - -int msn_sb_write(struct msn_switchboard *sb, const char *fmt, ...) -{ - va_list params; - char *out; - size_t len; - int st; - - va_start(params, fmt); - out = g_strdup_vprintf(fmt, params); - va_end(params); - - if (getenv("BITLBEE_DEBUG")) { - fprintf(stderr, "->SB%d:%s\n", sb->fd, out); - } - - len = strlen(out); - st = write(sb->fd, out, len); - g_free(out); - if (st != len) { - msn_sb_destroy(sb); - return 0; - } - - return 1; -} - -int msn_sb_write_msg(struct im_connection *ic, struct msn_message *m) -{ - struct msn_data *md = ic->proto_data; - struct msn_switchboard *sb; - - /* FIXME: *CHECK* the reliability of using spare sb's! */ - if ((sb = msn_sb_spare(ic))) { - debug("Trying to use a spare switchboard to message %s", m->who); - - sb->who = g_strdup(m->who); - if (msn_sb_write(sb, "CAL %d %s\r\n", ++sb->trId, m->who)) { - /* He/She should join the switchboard soon, let's queue the message. */ - sb->msgq = g_slist_append(sb->msgq, m); - return(1); - } - } - - debug("Creating a new switchboard to message %s", m->who); - - /* If we reach this line, there was no spare switchboard, so let's make one. */ - if (!msn_ns_write(ic, -1, "XFR %d SB\r\n", ++md->trId)) { - g_free(m->who); - g_free(m->text); - g_free(m); - - return(0); - } - - /* And queue the message to md. We'll pick it up when the switchboard comes up. */ - md->msgq = g_slist_append(md->msgq, m); - - /* FIXME: If the switchboard creation fails, the message will not be sent. */ - - return(1); -} - -struct msn_switchboard *msn_sb_create(struct im_connection *ic, char *host, int port, char *key, int session) -{ - struct msn_data *md = ic->proto_data; - struct msn_switchboard *sb = g_new0(struct msn_switchboard, 1); - - sb->fd = proxy_connect(host, port, msn_sb_connected, sb); - if (sb->fd < 0) { - g_free(sb); - return(NULL); - } - - sb->ic = ic; - sb->key = g_strdup(key); - sb->session = session; - - msn_switchboards = g_slist_append(msn_switchboards, sb); - md->switchboards = g_slist_append(md->switchboards, sb); - - return(sb); -} - -struct msn_switchboard *msn_sb_by_handle(struct im_connection *ic, const char *handle) -{ - struct msn_data *md = ic->proto_data; - struct msn_switchboard *sb; - GSList *l; - - for (l = md->switchboards; l; l = l->next) { - sb = l->data; - if (sb->who && strcmp(sb->who, handle) == 0) { - return(sb); - } - } - - return(NULL); -} - -struct msn_switchboard *msn_sb_by_chat(struct groupchat *c) -{ - struct msn_data *md = c->ic->proto_data; - struct msn_switchboard *sb; - GSList *l; - - for (l = md->switchboards; l; l = l->next) { - sb = l->data; - if (sb->chat == c) { - return(sb); - } - } - - return(NULL); -} - -struct msn_switchboard *msn_sb_spare(struct im_connection *ic) -{ - struct msn_data *md = ic->proto_data; - struct msn_switchboard *sb; - GSList *l; - - for (l = md->switchboards; l; l = l->next) { - sb = l->data; - if (!sb->who && !sb->chat) { - return(sb); - } - } - - return(NULL); -} - -int msn_sb_sendmessage(struct msn_switchboard *sb, char *text) -{ - if (sb->ready) { - char *buf; - int i, j; - - /* Build the message. Convert LF to CR-LF for normal messages. */ - if (strcmp(text, TYPING_NOTIFICATION_MESSAGE) == 0) { - i = strlen(MSN_TYPING_HEADERS) + strlen(sb->ic->acc->user); - buf = g_new0(char, i); - i = g_snprintf(buf, i, MSN_TYPING_HEADERS, sb->ic->acc->user); - } else if (strcmp(text, NUDGE_MESSAGE) == 0) { - buf = g_strdup(MSN_NUDGE_HEADERS); - i = strlen(buf); - } else if (strcmp(text, SB_KEEPALIVE_MESSAGE) == 0) { - buf = g_strdup(MSN_SB_KEEPALIVE_HEADERS); - i = strlen(buf); - } else { - buf = g_new0(char, sizeof(MSN_MESSAGE_HEADERS) + strlen(text) * 2 + 1); - i = strlen(MSN_MESSAGE_HEADERS); - - strcpy(buf, MSN_MESSAGE_HEADERS); - for (j = 0; text[j]; j++) { - if (text[j] == '\n') { - buf[i++] = '\r'; - } - - buf[i++] = text[j]; - } - } - - /* Build the final packet (MSG command + the message). */ - if (msn_sb_write(sb, "MSG %d N %d\r\n%s", ++sb->trId, i, buf)) { - g_free(buf); - return 1; - } else { - g_free(buf); - return 0; - } - } else if (sb->who) { - struct msn_message *m = g_new0(struct msn_message, 1); - - m->who = g_strdup(""); - m->text = g_strdup(text); - sb->msgq = g_slist_append(sb->msgq, m); - - return(1); - } else { - return(0); - } -} - -struct groupchat *msn_sb_to_chat(struct msn_switchboard *sb) -{ - struct im_connection *ic = sb->ic; - struct groupchat *c = NULL; - char buf[1024]; - - /* Create the groupchat structure. */ - g_snprintf(buf, sizeof(buf), "MSN groupchat session %d", sb->session); - if (sb->who) { - c = bee_chat_by_title(ic->bee, ic, sb->who); - } - if (c && !msn_sb_by_chat(c)) { - sb->chat = c; - } else { - sb->chat = imcb_chat_new(ic, buf); - } - - /* Populate the channel. */ - if (sb->who) { - imcb_chat_add_buddy(sb->chat, sb->who); - } - imcb_chat_add_buddy(sb->chat, ic->acc->user); - - /* And make sure the switchboard doesn't look like a regular chat anymore. */ - if (sb->who) { - g_free(sb->who); - sb->who = NULL; - } - - return sb->chat; -} - -void msn_sb_destroy(struct msn_switchboard *sb) -{ - struct im_connection *ic = sb->ic; - struct msn_data *md = ic->proto_data; - - debug("Destroying switchboard: %s", sb->who ? sb->who : sb->key ? sb->key : ""); - - msn_msgq_purge(ic, &sb->msgq); - msn_sb_stop_keepalives(sb); - - if (sb->key) { - g_free(sb->key); - } - if (sb->who) { - g_free(sb->who); - } - - if (sb->chat) { - imcb_chat_free(sb->chat); - } - - if (sb->handler) { - if (sb->handler->rxq) { - g_free(sb->handler->rxq); - } - if (sb->handler->cmd_text) { - g_free(sb->handler->cmd_text); - } - g_free(sb->handler); - } - - if (sb->inp) { - b_event_remove(sb->inp); - } - closesocket(sb->fd); - - msn_switchboards = g_slist_remove(msn_switchboards, sb); - md->switchboards = g_slist_remove(md->switchboards, sb); - g_free(sb); -} - -gboolean msn_sb_connected(gpointer data, gint source, b_input_condition cond) -{ - struct msn_switchboard *sb = data; - struct im_connection *ic; - struct msn_data *md; - char buf[1024]; - - /* Are we still alive? */ - if (!g_slist_find(msn_switchboards, sb)) { - return FALSE; - } - - ic = sb->ic; - md = ic->proto_data; - - if (source != sb->fd) { - debug("Error %d while connecting to switchboard server", 1); - msn_sb_destroy(sb); - return FALSE; - } - - /* Prepare the callback */ - sb->handler = g_new0(struct msn_handler_data, 1); - sb->handler->fd = sb->fd; - sb->handler->rxq = g_new0(char, 1); - sb->handler->data = sb; - sb->handler->exec_command = msn_sb_command; - sb->handler->exec_message = msn_sb_message; - - if (sb->session == MSN_SB_NEW) { - g_snprintf(buf, sizeof(buf), "USR %d %s;{%s} %s\r\n", ++sb->trId, ic->acc->user, md->uuid, sb->key); - } else { - g_snprintf(buf, sizeof(buf), "ANS %d %s;{%s} %s %d\r\n", ++sb->trId, ic->acc->user, md->uuid, sb->key, - sb->session); - } - - if (msn_sb_write(sb, "%s", buf)) { - sb->inp = b_input_add(sb->fd, B_EV_IO_READ, msn_sb_callback, sb); - } else { - debug("Error %d while connecting to switchboard server", 2); - } - - return FALSE; -} - -static gboolean msn_sb_callback(gpointer data, gint source, b_input_condition cond) -{ - struct msn_switchboard *sb = data; - struct im_connection *ic = sb->ic; - struct msn_data *md = ic->proto_data; - - if (msn_handler(sb->handler) != -1) { - return TRUE; - } - - if (sb->msgq != NULL) { - time_t now = time(NULL); - - if (now - md->first_sb_failure > 600) { - /* It's not really the first one, but the start of this "series". - With this, the warning below will be shown only if this happens - at least three times in ten minutes. This algorithm isn't - perfect, but for this purpose it will do. */ - md->first_sb_failure = now; - md->sb_failures = 0; - } - - debug("Error: Switchboard died"); - if (++md->sb_failures >= 3) { - imcb_log(ic, "Warning: Many switchboard failures on MSN connection. " - "There might be problems delivering your messages."); - } - - if (md->msgq == NULL) { - md->msgq = sb->msgq; - } else { - GSList *l; - - for (l = md->msgq; l->next; l = l->next) { - ; - } - l->next = sb->msgq; - } - sb->msgq = NULL; - - debug("Moved queued messages back to the main queue, " - "creating a new switchboard to retry."); - if (!msn_ns_write(ic, -1, "XFR %d SB\r\n", ++md->trId)) { - return FALSE; - } - } - - msn_sb_destroy(sb); - return FALSE; -} - -static int msn_sb_command(struct msn_handler_data *handler, char **cmd, int num_parts) -{ - struct msn_switchboard *sb = handler->data; - struct im_connection *ic = sb->ic; - - if (!num_parts) { - /* Hrrm... Empty command...? Ignore? */ - return(1); - } - - if (strcmp(cmd[0], "XFR") == 0) { - imcb_error(ic, - "Received an XFR from a switchboard server, unable to comply! This is likely to be a bug, please report it!"); - imc_logout(ic, TRUE); - return(0); - } else if (strcmp(cmd[0], "USR") == 0) { - if (num_parts < 5) { - msn_sb_destroy(sb); - return(0); - } - - if (strcmp(cmd[2], "OK") != 0) { - msn_sb_destroy(sb); - return(0); - } - - if (sb->who) { - return msn_sb_write(sb, "CAL %d %s\r\n", ++sb->trId, sb->who); - } else { - debug("Just created a switchboard, but I don't know what to do with it."); - } - } else if (strcmp(cmd[0], "IRO") == 0) { - int num, tot; - - if (num_parts < 6) { - msn_sb_destroy(sb); - return(0); - } - - num = atoi(cmd[2]); - tot = atoi(cmd[3]); - - if (tot <= 0) { - msn_sb_destroy(sb); - return(0); - } else if (tot > 1) { - char buf[1024]; - - /* For as much as I understand this MPOP stuff now, a - switchboard has two (or more) roster entries per - participant. One "bare JID" and one JID;UUID. Ignore - the latter. */ - if (!strchr(cmd[4], ';')) { - /* HACK: Since even 1:1 chats now have >2 participants - (ourselves included) it gets hard to tell them apart - from rooms. Let's hope this is enough: */ - if (sb->chat == NULL && num != tot) { - g_snprintf(buf, sizeof(buf), "MSN groupchat session %d", sb->session); - sb->chat = imcb_chat_new(ic, buf); - - g_free(sb->who); - sb->who = NULL; - } - - if (sb->chat) { - imcb_chat_add_buddy(sb->chat, cmd[4]); - } - } - - /* We have the full roster, start showing the channel to - the user. */ - if (num == tot && sb->chat) { - imcb_chat_add_buddy(sb->chat, ic->acc->user); - } - } - } else if (strcmp(cmd[0], "ANS") == 0) { - if (num_parts < 3) { - msn_sb_destroy(sb); - return(0); - } - - if (strcmp(cmd[2], "OK") != 0) { - debug("Switchboard server sent a negative ANS reply"); - msn_sb_destroy(sb); - return(0); - } - - sb->ready = 1; - - msn_sb_start_keepalives(sb, FALSE); - } else if (strcmp(cmd[0], "CAL") == 0) { - if (num_parts < 4 || !g_ascii_isdigit(cmd[3][0])) { - msn_sb_destroy(sb); - return(0); - } - - sb->session = atoi(cmd[3]); - } else if (strcmp(cmd[0], "JOI") == 0) { - if (num_parts < 3) { - msn_sb_destroy(sb); - return(0); - } - - /* See IRO above. Handle "bare JIDs" only. */ - if (strchr(cmd[1], ';')) { - return 1; - } - - if (sb->who && g_strcasecmp(cmd[1], sb->who) == 0) { - /* The user we wanted to talk to is finally there, let's send the queued messages then. */ - struct msn_message *m; - GSList *l; - int st = 1; - - debug("%s arrived in the switchboard session, now sending queued message(s)", cmd[1]); - - /* Without this, sendmessage() will put everything back on the queue... */ - sb->ready = 1; - - while ((l = sb->msgq)) { - m = l->data; - if (st) { - /* This hack is meant to convert a regular new chat into a groupchat */ - if (strcmp(m->text, GROUPCHAT_SWITCHBOARD_MESSAGE) == 0) { - msn_sb_to_chat(sb); - } else { - st = msn_sb_sendmessage(sb, m->text); - } - } - sb->msgq = g_slist_remove(sb->msgq, m); - g_free(m->text); - g_free(m->who); - g_free(m); - } - - msn_sb_start_keepalives(sb, FALSE); - - return(st); - } else if (strcmp(cmd[1], ic->acc->user) == 0) { - /* Well, gee thanks. Thanks for letting me know I've arrived.. */ - } else if (sb->who) { - debug("Converting chat with %s to a groupchat because %s joined the session.", sb->who, cmd[1]); - - /* This SB is a one-to-one chat right now, but someone else is joining. */ - msn_sb_to_chat(sb); - - imcb_chat_add_buddy(sb->chat, cmd[1]); - } else if (sb->chat) { - imcb_chat_add_buddy(sb->chat, cmd[1]); - sb->ready = 1; - } else { - /* PANIC! */ - } - } else if (strcmp(cmd[0], "MSG") == 0) { - if (num_parts < 4) { - msn_sb_destroy(sb); - return(0); - } - - sb->handler->msglen = atoi(cmd[3]); - - if (sb->handler->msglen <= 0) { - debug("Received a corrupted message on the switchboard, the switchboard will be closed"); - msn_sb_destroy(sb); - return(0); - } - } else if (strcmp(cmd[0], "NAK") == 0) { - if (sb->who) { - imcb_log(ic, "The MSN servers could not deliver one of your messages to %s.", sb->who); - } else { - imcb_log(ic, - "The MSN servers could not deliver one of your groupchat messages to all participants."); - } - } else if (strcmp(cmd[0], "BYE") == 0) { - if (num_parts < 2) { - msn_sb_destroy(sb); - return(0); - } - - /* if( cmd[2] && *cmd[2] == '1' ) -=> Chat is being cleaned up because of idleness */ - - if (sb->who) { - msn_sb_stop_keepalives(sb); - - /* This is a single-person chat, and the other person is leaving. */ - g_free(sb->who); - sb->who = NULL; - sb->ready = 0; - - debug("Person %s left the one-to-one switchboard connection. Keeping it around as a spare...", - cmd[1]); - - /* We could clean up the switchboard now, but keeping it around - as a spare for a next conversation sounds more sane to me. - The server will clean it up when it's idle for too long. */ - } else if (sb->chat && !strchr(cmd[1], ';')) { - imcb_chat_remove_buddy(sb->chat, cmd[1], ""); - } else { - /* PANIC! */ - } - } else if (g_ascii_isdigit(cmd[0][0])) { - int num = atoi(cmd[0]); - const struct msn_status_code *err = msn_status_by_number(num); - - /* If the person is offline, send an offline message instead, - and don't report an error. */ - if (num == 217) { - msn_ns_oim_send_queue(ic, &sb->msgq); - } else { - imcb_error(ic, "Error reported by switchboard server: %s", err->text); - } - - if (err->flags & STATUS_SB_FATAL) { - msn_sb_destroy(sb); - return 0; - } else if (err->flags & STATUS_FATAL) { - imc_logout(ic, TRUE); - return 0; - } else if (err->flags & STATUS_SB_IM_SPARE) { - if (sb->who) { - /* Apparently some invitation failed. We might want to use this - board later, so keep it as a spare. */ - g_free(sb->who); - sb->who = NULL; - - /* Also clear the msgq, otherwise someone else might get them. */ - msn_msgq_purge(ic, &sb->msgq); - } - - /* Do NOT return 0 here, we want to keep this sb. */ - } - } else { - /* debug( "Received unknown command from switchboard server: %s", cmd[0] ); */ - } - - return(1); -} - -static int msn_sb_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts) -{ - struct msn_switchboard *sb = handler->data; - struct im_connection *ic = sb->ic; - char *body; - - if (!num_parts) { - return(1); - } - - if ((body = strstr(msg, "\r\n\r\n"))) { - body += 4; - } - - if (strcmp(cmd[0], "MSG") == 0) { - char *ct = get_rfc822_header(msg, "Content-Type:", msglen); - - if (!ct) { - return(1); - } - - if (g_strncasecmp(ct, "text/plain", 10) == 0) { - g_free(ct); - - if (!body) { - return(1); - } - - if (sb->who) { - imcb_buddy_msg(ic, cmd[1], body, 0, 0); - } else if (sb->chat) { - imcb_chat_msg(sb->chat, cmd[1], body, 0, 0); - } else { - /* PANIC! */ - } - } - else if (g_strncasecmp(ct, "application/x-msnmsgrp2p", 24) == 0) { - /* Not currently implemented. Don't warn about it since - this seems to be used for avatars now. */ - g_free(ct); - } else if (g_strncasecmp(ct, "text/x-msmsgscontrol", 20) == 0) { - char *who = get_rfc822_header(msg, "TypingUser:", msglen); - - if (who) { - imcb_buddy_typing(ic, who, OPT_TYPING); - g_free(who); - } - - g_free(ct); - } else { - g_free(ct); - } - } - - return(1); -} - -static gboolean msn_sb_keepalive(gpointer data, gint source, b_input_condition cond) -{ - struct msn_switchboard *sb = data; - - return sb->ready && msn_sb_sendmessage(sb, SB_KEEPALIVE_MESSAGE); -} - -void msn_sb_start_keepalives(struct msn_switchboard *sb, gboolean initial) -{ - bee_user_t *bu; - - if (sb && sb->who && sb->keepalive == 0 && - (bu = bee_user_by_handle(sb->ic->bee, sb->ic, sb->who)) && - !(bu->flags & BEE_USER_ONLINE) && - set_getbool(&sb->ic->acc->set, "switchboard_keepalives")) { - if (initial) { - msn_sb_keepalive(sb, 0, 0); - } - - sb->keepalive = b_timeout_add(20000, msn_sb_keepalive, sb); - } -} - -void msn_sb_stop_keepalives(struct msn_switchboard *sb) -{ - if (sb && sb->keepalive > 0) { - b_event_remove(sb->keepalive); - sb->keepalive = 0; - } -} |