diff options
author | Mike Ruprecht <cmaiku@gmail.com> | 2016-10-02 15:41:50 -0500 |
---|---|---|
committer | Mike Ruprecht <cmaiku@gmail.com> | 2016-10-02 15:41:50 -0500 |
commit | 7bb46730da46048b505728ca1b5708dc89404831 (patch) | |
tree | 88294ef95ae34a32e1fd7675cef82ee7a0f0878a | |
parent | 4582a99d416116b07bc2d28ce1198200f2f2b11f (diff) | |
download | pidgin-7bb46730da46048b505728ca1b5708dc89404831.tar.gz |
msn: Remove protocol plugin from tree
The MSN prpl has been unusable and dormant for some time. MSNP18 has
been discontinued and this prpl would require a large update to start
working again. See: http://ismsndeadyet.com/
Pidgin SkypeWeb however, should provide enough functionality as a
replacement if people still want to use MSN:
https://github.com/EionRobb/skype4pidgin/tree/master/skypeweb
75 files changed, 8 insertions, 29925 deletions
diff --git a/configure.ac b/configure.ac index 7d0f00f2c7..528ac55ca5 100644 --- a/configure.ac +++ b/configure.ac @@ -1189,7 +1189,7 @@ if test "x$STATIC_PRPLS" != "x" -a "x$DYNAMIC_PRPLS" = "xall"; then fi if test "x$STATIC_PRPLS" = "xall" ; then - STATIC_PRPLS="bonjour gg irc jabber msn myspace novell oscar sametime silc simple yahoo zephyr" + STATIC_PRPLS="bonjour gg irc jabber myspace novell oscar sametime silc simple yahoo zephyr" fi if test "x$have_meanwhile" != "xyes" ; then STATIC_PRPLS=`echo $STATIC_PRPLS | $sedpath 's/sametime//'` @@ -1238,7 +1238,6 @@ for i in $STATIC_PRPLS ; do gg) static_gg=yes ;; irc) static_irc=yes ;; jabber) static_jabber=yes ;; - msn) static_msn=yes ;; myspace) static_myspace=yes ;; novell) static_novell=yes ;; oscar) static_oscar=yes ;; @@ -1257,7 +1256,6 @@ AM_CONDITIONAL(STATIC_BONJOUR, test "x$static_bonjour" = "xyes") AM_CONDITIONAL(STATIC_GG, test "x$static_gg" = "xyes") AM_CONDITIONAL(STATIC_IRC, test "x$static_irc" = "xyes") AM_CONDITIONAL(STATIC_JABBER, test "x$static_jabber" = "xyes") -AM_CONDITIONAL(STATIC_MSN, test "x$static_msn" = "xyes") AM_CONDITIONAL(STATIC_MYSPACE, test "x$static_myspace" = "xyes") AM_CONDITIONAL(STATIC_NOVELL, test "x$static_novell" = "xyes") AM_CONDITIONAL(STATIC_OSCAR, test "x$static_oscar" = "xyes") @@ -1272,7 +1270,7 @@ AC_DEFINE_UNQUOTED(STATIC_PROTO_INIT, $extern_init static void static_proto_init AC_ARG_WITH(dynamic_prpls, [AC_HELP_STRING([--with-dynamic-prpls], [specify which protocols to build dynamically])], [DYNAMIC_PRPLS=`echo $withval | $sedpath 's/,/ /g'`]) if test "x$DYNAMIC_PRPLS" = "xall" ; then - DYNAMIC_PRPLS="bonjour gg irc jabber msn myspace novell oscar sametime silc simple yahoo zephyr" + DYNAMIC_PRPLS="bonjour gg irc jabber myspace novell oscar sametime silc simple yahoo zephyr" fi if test "x$have_meanwhile" != "xyes"; then DYNAMIC_PRPLS=`echo $DYNAMIC_PRPLS | $sedpath 's/sametime//'` @@ -1293,7 +1291,6 @@ for i in $DYNAMIC_PRPLS ; do gg) dynamic_gg=yes ;; irc) dynamic_irc=yes ;; jabber) dynamic_jabber=yes ;; - msn) dynamic_msn=yes ;; myspace) dynamic_myspace=yes ;; novell) dynamic_novell=yes ;; null) dynamic_null=yes ;; @@ -1791,7 +1788,7 @@ AC_ARG_ENABLE(nss, [enable_nss="$enableval"], [enable_nss="yes"]) -msg_ssl="None. MSN, Yahoo!, Novell Groupwise and Google Talk will not work without GnuTLS or NSS. OpenSSL is NOT usable!" +msg_ssl="None. Yahoo!, Novell Groupwise and Google Talk will not work without GnuTLS or NSS. OpenSSL is NOT usable!" looked_for_gnutls="no" dnl # dnl # Check for GnuTLS if it's specified. @@ -2202,19 +2199,19 @@ elif test "x$looked_for_gnutls" = "xyes" -a "x$looked_for_nss" = "xyes" -a "x$fo AC_MSG_ERROR([ Neither GnuTLS or NSS SSL development headers found. Use --disable-nss --disable-gnutls if you do not need SSL support. -MSN, Yahoo!, Novell Groupwise and Google Talk will not work without GnuTLS or NSS. OpenSSL is NOT usable! +Yahoo!, Novell Groupwise and Google Talk will not work without GnuTLS or NSS. OpenSSL is NOT usable! ]) elif test "x$looked_for_gnutls" = "xyes" -a "x$force_deps" = "xyes" ; then AC_MSG_ERROR([ GnuTLS SSL development headers not found. Use --disable-gnutls if you do not need SSL support. -MSN, Yahoo!, Novell Groupwise and Google Talk will not work without SSL support. +Yahoo!, Novell Groupwise and Google Talk will not work without SSL support. ]) elif test "x$looked_for_nss" = "xyes" -a "x$force_deps" = "xyes" ; then AC_MSG_ERROR([ NSS SSL development headers not found. Use --disable-nss if you do not need SSL support. -MSN, Yahoo!, Novell Groupwise and Google Talk will not work without SSL support. +Yahoo!, Novell Groupwise and Google Talk will not work without SSL support. ]) fi @@ -2659,7 +2656,6 @@ AC_CONFIG_FILES([Makefile libpurple/protocols/gg/Makefile libpurple/protocols/irc/Makefile libpurple/protocols/jabber/Makefile - libpurple/protocols/msn/Makefile libpurple/protocols/myspace/Makefile libpurple/protocols/novell/Makefile libpurple/protocols/null/Makefile diff --git a/libpurple/protocols/Makefile.am b/libpurple/protocols/Makefile.am index 0e3a2989bd..675ee5818f 100644 --- a/libpurple/protocols/Makefile.am +++ b/libpurple/protocols/Makefile.am @@ -1,5 +1,5 @@ EXTRA_DIST = Makefile.mingw -DIST_SUBDIRS = bonjour gg irc jabber msn myspace novell null oscar sametime silc silc10 simple yahoo zephyr +DIST_SUBDIRS = bonjour gg irc jabber myspace novell null oscar sametime silc silc10 simple yahoo zephyr SUBDIRS = $(DYNAMIC_PRPLS) $(STATIC_PRPLS) diff --git a/libpurple/protocols/Makefile.mingw b/libpurple/protocols/Makefile.mingw index 0c959d0a8a..36000fc18b 100644 --- a/libpurple/protocols/Makefile.mingw +++ b/libpurple/protocols/Makefile.mingw @@ -8,7 +8,7 @@ PIDGIN_TREE_TOP := ../.. include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak -SUBDIRS = gg irc jabber msn novell null oscar sametime silc simple yahoo bonjour myspace +SUBDIRS = gg irc jabber novell null oscar sametime silc simple yahoo bonjour myspace .PHONY: all install clean diff --git a/libpurple/protocols/msn/Makefile.am b/libpurple/protocols/msn/Makefile.am deleted file mode 100644 index f2edc6454e..0000000000 --- a/libpurple/protocols/msn/Makefile.am +++ /dev/null @@ -1,102 +0,0 @@ -EXTRA_DIST = \ - directconn.c \ - directconn.h \ - Makefile.mingw - -pkgdir = $(libdir)/purple-$(PURPLE_MAJOR_VERSION) - -MSNSOURCES = \ - cmdproc.c \ - cmdproc.h \ - command.c \ - command.h \ - contact.c\ - contact.h\ - directconn.c \ - directconn.h \ - error.c \ - error.h \ - group.c \ - group.h \ - history.c \ - history.h \ - httpconn.c \ - httpconn.h \ - msg.c \ - msg.h \ - msn.c \ - msn.h \ - nexus.c \ - nexus.h \ - notification.c \ - notification.h \ - object.c \ - object.h \ - oim.c\ - oim.h\ - p2p.c \ - p2p.h \ - page.c \ - page.h \ - servconn.c \ - servconn.h \ - session.c \ - session.h \ - slp.c \ - slp.h \ - slpcall.c \ - slpcall.h \ - slplink.c \ - slplink.h \ - slpmsg.c \ - slpmsg.h \ - slpmsg_part.c \ - slpmsg_part.h \ - soap.c \ - soap.h \ - state.c \ - state.h \ - sbconn.c \ - sbconn.h \ - switchboard.c \ - switchboard.h \ - table.c \ - table.h \ - tlv.c \ - tlv.h \ - transaction.c \ - transaction.h \ - user.c \ - user.h \ - userlist.c \ - userlist.h \ - xfer.c \ - xfer.h \ - msnutils.c \ - msnutils.h - -AM_CFLAGS = $(st) - -libmsn_la_LDFLAGS = -module -avoid-version - -if STATIC_MSN - -st = -DPURPLE_STATIC_PRPL -noinst_LTLIBRARIES = libmsn.la -libmsn_la_SOURCES = $(MSNSOURCES) -libmsn_la_CFLAGS = $(AM_CFLAGS) - -else - -st = -pkg_LTLIBRARIES = libmsn.la -libmsn_la_SOURCES = $(MSNSOURCES) -libmsn_la_LIBADD = $(GLIB_LIBS) - -endif - -AM_CPPFLAGS = \ - -I$(top_srcdir)/libpurple \ - -I$(top_builddir)/libpurple \ - $(GLIB_CFLAGS) \ - $(DEBUG_CFLAGS) diff --git a/libpurple/protocols/msn/Makefile.mingw b/libpurple/protocols/msn/Makefile.mingw deleted file mode 100644 index 5d3072f97a..0000000000 --- a/libpurple/protocols/msn/Makefile.mingw +++ /dev/null @@ -1,110 +0,0 @@ -# -# Makefile.mingw -# -# Description: Makefile for win32 (mingw) version of libmsn -# - -PIDGIN_TREE_TOP := ../../.. -include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak - -TARGET = libmsn -TYPE = PLUGIN - -# Static or Plugin... -ifeq ($(TYPE),STATIC) - DEFINES += -DSTATIC - DLL_INSTALL_DIR = $(PURPLE_INSTALL_DIR) -else -ifeq ($(TYPE),PLUGIN) - DLL_INSTALL_DIR = $(PURPLE_INSTALL_PLUGINS_DIR) -endif -endif - -## -## INCLUDE PATHS -## -INCLUDE_PATHS += -I. \ - -I$(GTK_TOP)/include \ - -I$(GTK_TOP)/include/glib-2.0 \ - -I$(GTK_TOP)/lib/glib-2.0/include \ - -I$(PURPLE_TOP) \ - -I$(PURPLE_TOP)/win32 \ - -I$(PIDGIN_TREE_TOP) - -LIB_PATHS += -L$(GTK_TOP)/lib \ - -L$(PURPLE_TOP) - -## -## SOURCES, OBJECTS -## -C_SRC = cmdproc.c \ - command.c \ - contact.c\ - directconn.c \ - error.c \ - group.c \ - history.c \ - httpconn.c \ - msg.c \ - msn.c \ - nexus.c \ - notification.c \ - object.c \ - oim.c\ - p2p.c \ - page.c \ - servconn.c \ - session.c \ - slp.c \ - slpcall.c \ - slplink.c \ - slpmsg.c \ - slpmsg_part.c \ - soap.c\ - state.c \ - sbconn.c \ - switchboard.c \ - table.c \ - tlv.c \ - transaction.c \ - user.c \ - userlist.c \ - xfer.c \ - msnutils.c - -OBJECTS = $(C_SRC:%.c=%.o) - -## -## LIBRARIES -## -LIBS = \ - -lglib-2.0 \ - -lintl \ - -lws2_32 \ - -lpurple - -include $(PIDGIN_COMMON_RULES) - -## -## TARGET DEFINITIONS -## -.PHONY: all install clean - -all: $(TARGET).dll - -install: all $(DLL_INSTALL_DIR) - cp $(TARGET).dll $(DLL_INSTALL_DIR) - -$(OBJECTS): $(PURPLE_CONFIG_H) - -$(TARGET).dll: $(PURPLE_DLL).a $(OBJECTS) - $(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -o $(TARGET).dll - -## -## CLEAN RULES -## -clean: - rm -f $(OBJECTS) - rm -f $(TARGET).dll - -include $(PIDGIN_COMMON_TARGETS) diff --git a/libpurple/protocols/msn/cmdproc.c b/libpurple/protocols/msn/cmdproc.c deleted file mode 100644 index 7a27f633ac..0000000000 --- a/libpurple/protocols/msn/cmdproc.c +++ /dev/null @@ -1,339 +0,0 @@ -/** - * @file cmdproc.c MSN command processor functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "debug.h" - -#include "cmdproc.h" -#include "error.h" - -MsnCmdProc * -msn_cmdproc_new(MsnSession *session) -{ - MsnCmdProc *cmdproc; - - cmdproc = g_new0(MsnCmdProc, 1); - - cmdproc->session = session; - cmdproc->txqueue = g_queue_new(); - cmdproc->history = msn_history_new(); - - cmdproc->multiparts = g_hash_table_new_full(g_str_hash, g_str_equal, - NULL, (GDestroyNotify)msn_message_unref); - - return cmdproc; -} - -void -msn_cmdproc_destroy(MsnCmdProc *cmdproc) -{ - MsnTransaction *trans; - - while ((trans = g_queue_pop_head(cmdproc->txqueue)) != NULL) - msn_transaction_destroy(trans); - - g_queue_free(cmdproc->txqueue); - - msn_history_destroy(cmdproc->history); - - if (cmdproc->last_cmd != NULL) - msn_command_unref(cmdproc->last_cmd); - - g_hash_table_destroy(cmdproc->multiparts); - - g_free(cmdproc); -} - -void -msn_cmdproc_process_queue(MsnCmdProc *cmdproc) -{ - MsnTransaction *trans; - - while ((trans = g_queue_pop_head(cmdproc->txqueue)) != NULL) - msn_cmdproc_send_trans(cmdproc, trans); -} - -void -msn_cmdproc_queue_trans(MsnCmdProc *cmdproc, MsnTransaction *trans) -{ - g_return_if_fail(cmdproc != NULL); - g_return_if_fail(trans != NULL); - - g_queue_push_tail(cmdproc->txqueue, trans); -} - -static void -show_debug_cmd(MsnCmdProc *cmdproc, gboolean incoming, const char *command) -{ - MsnServConn *servconn; - const char *names[] = { "NS", "SB" }; - char *show; - char tmp; - size_t len; - - servconn = cmdproc->servconn; - len = strlen(command); - show = g_strdup(command); - - tmp = (incoming) ? 'S' : 'C'; - - if ((show[len - 1] == '\n') && (show[len - 2] == '\r')) - { - show[len - 2] = '\0'; - } - - purple_debug_misc("msn", "%c: %s %03d: %s\n", tmp, - names[servconn->type], servconn->num, show); - - g_free(show); -} - -gboolean -msn_cmdproc_send_trans(MsnCmdProc *cmdproc, MsnTransaction *trans) -{ - MsnServConn *servconn; - char *data; - size_t len; - gboolean ret; - - g_return_val_if_fail(cmdproc != NULL, TRUE); - g_return_val_if_fail(trans != NULL, TRUE); - - servconn = cmdproc->servconn; - - if (!servconn->connected) { - msn_transaction_destroy(trans); - return FALSE; - } - - if (trans->saveable) - msn_history_add(cmdproc->history, trans); - - data = msn_transaction_to_string(trans); - - len = strlen(data); - - show_debug_cmd(cmdproc, FALSE, data); - - if (trans->callbacks == NULL) - trans->callbacks = g_hash_table_lookup(cmdproc->cbs_table->cmds, - trans->command); - - if (trans->payload != NULL) - { - data = g_realloc(data, len + trans->payload_len); - memcpy(data + len, trans->payload, trans->payload_len); - len += trans->payload_len; - - /* - * We're done with trans->payload. Free it so that the memory - * doesn't sit around in cmdproc->history. - */ - g_free(trans->payload); - trans->payload = NULL; - trans->payload_len = 0; - } - - ret = msn_servconn_write(servconn, data, len) != -1; - - if (!trans->saveable) - msn_transaction_destroy(trans); - g_free(data); - return ret; -} - -void -msn_cmdproc_process_payload(MsnCmdProc *cmdproc, char *payload, - int payload_len) -{ - MsnCommand *last; - - g_return_if_fail(cmdproc != NULL); - - last = cmdproc->last_cmd; - last->payload = g_memdup(payload, payload_len); - last->payload_len = payload_len; - - if (last->payload_cb != NULL) - last->payload_cb(cmdproc, last, payload, payload_len); -} - -void -msn_cmdproc_process_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - MsnMsgTypeCb cb; - const char *message_id = NULL; - - /* Multi-part messages */ - message_id = msn_message_get_header_value(msg, "Message-ID"); - if (message_id != NULL) { - /* This is the first in a series of chunks */ - - const char *chunk_text = msn_message_get_header_value(msg, "Chunks"); - guint chunk; - if (chunk_text != NULL) { - chunk = strtol(chunk_text, NULL, 10); - /* 1024 chunks of ~1300 bytes is ~1MB, which seems OK to prevent - some random client causing pidgin to hog a ton of memory. - Probably should figure out the maximum that the official client - actually supports, though. */ - if (chunk > 0 && chunk < 1024) { - msg->total_chunks = chunk; - msg->received_chunks = 1; - g_hash_table_insert(cmdproc->multiparts, (gpointer)message_id, msn_message_ref(msg)); - purple_debug_info("msn", "Received chunked message, message_id: '%s', total chunks: %d\n", - message_id, chunk); - } else { - purple_debug_error("msn", "MessageId '%s' has too many chunks: %d\n", message_id, chunk); - } - return; - } else { - chunk_text = msn_message_get_header_value(msg, "Chunk"); - if (chunk_text != NULL) { - /* This is one chunk in a series of chunks */ - - MsnMessage *first = g_hash_table_lookup(cmdproc->multiparts, message_id); - chunk = strtol(chunk_text, NULL, 10); - if (first != NULL) { - if (first->received_chunks != chunk) { - /* - * We received an out of order chunk number (i.e. not the - * next one in the sequence). Not sure if this can happen - * legitimately, but we definitely don't handle it right - * now. - */ - g_hash_table_remove(cmdproc->multiparts, message_id); - return; - } - - /* Chunk is from 1 to total-1 (doesn't count first one) */ - purple_debug_info("msn", "Received chunk %d of %d, message_id: '%s'\n", - chunk + 1, first->total_chunks, message_id); - first->body = g_realloc(first->body, first->body_len + msg->body_len); - memcpy(first->body + first->body_len, msg->body, msg->body_len); - first->body_len += msg->body_len; - first->received_chunks++; - if (first->received_chunks != first->total_chunks) - /* We're waiting for more chunks */ - return; - - /* - * We have all the chunks for this message, great! Send - * it along... The caller takes care of freeing the old one. - */ - msg = first; - } else { - purple_debug_error("msn", - "Unable to find first chunk of message_id '%s' to correspond with chunk %d.\n", - message_id, chunk + 1); - } - } else { - purple_debug_error("msn", "Received MessageId '%s' with no chunk number!\n", message_id); - } - } - } - - if (msn_message_get_content_type(msg) == NULL) - { - purple_debug_misc("msn", "failed to find message content\n"); - return; - } - - cb = g_hash_table_lookup(cmdproc->cbs_table->msgs, - msn_message_get_content_type(msg)); - - if (cb != NULL) - cb(cmdproc, msg); - else - purple_debug_warning("msn", "Unhandled content-type '%s'\n", - msn_message_get_content_type(msg)); - - if (message_id != NULL) - g_hash_table_remove(cmdproc->multiparts, message_id); -} - -void -msn_cmdproc_process_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnTransCb cb = NULL; - MsnTransaction *trans = NULL; - - if (cmd->trId) - cmd->trans = trans = msn_history_find(cmdproc->history, cmd->trId); - - if (trans != NULL) - if (trans->timer) { - purple_timeout_remove(trans->timer); - trans->timer = 0; - } - - if (g_ascii_isdigit(cmd->command[0]) && trans != NULL) - { - MsnErrorCb error_cb; - int error; - - error = atoi(cmd->command); - - error_cb = trans->error_cb; - if (error_cb == NULL) - error_cb = g_hash_table_lookup(cmdproc->cbs_table->errors, trans->command); - - if (error_cb != NULL) - error_cb(cmdproc, trans, error); - else - msn_error_handle(cmdproc->session, error); - - return; - } - - cb = g_hash_table_lookup(cmdproc->cbs_table->async, cmd->command); - - if (cb == NULL && trans != NULL && trans->callbacks != NULL) - cb = g_hash_table_lookup(trans->callbacks, cmd->command); - - if (cb == NULL) - cb = g_hash_table_lookup(cmdproc->cbs_table->fallback, cmd->command); - - if (cb != NULL) - cb(cmdproc, cmd); - else - purple_debug_warning("msn", "Unhandled command '%s'\n", - cmd->command); - - if (trans != NULL && trans->pendent_cmd != NULL) - msn_transaction_unqueue_cmd(trans, cmdproc); -} - -void -msn_cmdproc_process_cmd_text(MsnCmdProc *cmdproc, const char *command) -{ - show_debug_cmd(cmdproc, TRUE, command); - - if (cmdproc->last_cmd != NULL) - msn_command_unref(cmdproc->last_cmd); - - cmdproc->last_cmd = msn_command_from_string(command); - - msn_cmdproc_process_cmd(cmdproc, cmdproc->last_cmd); -} diff --git a/libpurple/protocols/msn/cmdproc.h b/libpurple/protocols/msn/cmdproc.h deleted file mode 100644 index 9ec6c491da..0000000000 --- a/libpurple/protocols/msn/cmdproc.h +++ /dev/null @@ -1,100 +0,0 @@ -/** - * @file cmdproc.h MSN command processor functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_CMDPROC_H -#define MSN_CMDPROC_H - -typedef struct _MsnCmdProc MsnCmdProc; - -#include "command.h" -#include "history.h" -#include "servconn.h" -#include "session.h" -#include "table.h" - -struct _MsnCmdProc -{ - MsnSession *session; - MsnServConn *servconn; - - GQueue *txqueue; - - MsnCommand *last_cmd; - - MsnTable *cbs_table; - - MsnHistory *history; - - GHashTable *multiparts; /**< Multi-part message ID's */ - - void *data; /**< Extra data, like the switchboard. */ -}; - -/** - * Creates a MsnCmdProc structure. - * - * @param session The session to associate with. - * - * @return A new MsnCmdProc structure. - */ -MsnCmdProc *msn_cmdproc_new(MsnSession *session); - -/** - * Destroys an MsnCmdProc. - * - * @param cmdproc The object structure. - */ -void msn_cmdproc_destroy(MsnCmdProc *cmdproc); - -/** - * Process the queued transactions. - * - * @param cmdproc The MsnCmdProc. - */ -void msn_cmdproc_process_queue(MsnCmdProc *cmdproc); - -/** - * Sends transaction using this servconn. - * - * @param cmdproc The MsnCmdProc to be used. - * @param trans The MsnTransaction to be sent. - */ -gboolean msn_cmdproc_send_trans(MsnCmdProc *cmdproc, MsnTransaction *trans); - -/** - * Add a transaction to the queue to be processed latter. - * - * @param cmdproc The MsnCmdProc in which the transaction will be queued. - * @param trans The MsnTransaction to be queued. - */ -void msn_cmdproc_queue_trans(MsnCmdProc *cmdproc, - MsnTransaction *trans); - -void msn_cmdproc_process_msg(MsnCmdProc *cmdproc, - MsnMessage *msg); -void msn_cmdproc_process_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd); -void msn_cmdproc_process_cmd_text(MsnCmdProc *cmdproc, const char *command); -void msn_cmdproc_process_payload(MsnCmdProc *cmdproc, - char *payload, int payload_len); - -#endif /* MSN_CMDPROC_H */ diff --git a/libpurple/protocols/msn/command.c b/libpurple/protocols/msn/command.c deleted file mode 100644 index 0be77b4630..0000000000 --- a/libpurple/protocols/msn/command.c +++ /dev/null @@ -1,113 +0,0 @@ -/** - * @file command.c MSN command functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#include "internal.h" - -#include "command.h" - -static gboolean -is_num(const char *str) -{ - const char *c; - for (c = str; *c; c++) { - if (!(g_ascii_isdigit(*c))) - return FALSE; - } - - return TRUE; -} - -MsnCommand * -msn_command_from_string(const char *string) -{ - MsnCommand *cmd; - char *param_start; - - g_return_val_if_fail(string != NULL, NULL); - - cmd = g_new0(MsnCommand, 1); - cmd->command = g_strdup(string); - param_start = strchr(cmd->command, ' '); - - if (param_start) - { - *param_start++ = '\0'; - cmd->params = g_strsplit_set(param_start, " ", 0); - } - - if (cmd->params != NULL) - { - guint c; - - for (c = 0; cmd->params[c] && cmd->params[c][0]; c++); - cmd->param_count = c; - - if (cmd->param_count) { - char *param = cmd->params[0]; - cmd->trId = is_num(param) ? atoi(param) : 0; - } else { - cmd->trId = 0; - } - } - else - { - cmd->trId = 0; - } - - msn_command_ref(cmd); - - return cmd; -} - -static void -msn_command_destroy(MsnCommand *cmd) -{ - g_free(cmd->payload); - g_free(cmd->command); - g_strfreev(cmd->params); - g_free(cmd); -} - -MsnCommand * -msn_command_ref(MsnCommand *cmd) -{ - g_return_val_if_fail(cmd != NULL, NULL); - - cmd->ref_count++; - return cmd; -} - -void -msn_command_unref(MsnCommand *cmd) -{ - g_return_if_fail(cmd != NULL); - g_return_if_fail(cmd->ref_count > 0); - - cmd->ref_count--; - - if (cmd->ref_count == 0) - { - msn_command_destroy(cmd); - } -} - diff --git a/libpurple/protocols/msn/command.h b/libpurple/protocols/msn/command.h deleted file mode 100644 index d5d2d3a75d..0000000000 --- a/libpurple/protocols/msn/command.h +++ /dev/null @@ -1,84 +0,0 @@ -/** - * @file command.h MSN command functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_COMMAND_H -#define MSN_COMMAND_H - -typedef struct _MsnCommand MsnCommand; - -#include "cmdproc.h" -#include "transaction.h" - -typedef void (*MsnPayloadCb)(MsnCmdProc *cmdproc, MsnCommand *cmd, - char *payload, size_t len); - -/** - * A received command. - */ -struct _MsnCommand -{ - unsigned int trId; - - char *command; - char **params; - guint param_count; - - guint ref_count; - - MsnTransaction *trans; - - char *payload; - size_t payload_len; - - MsnPayloadCb payload_cb; - void *payload_cbdata; -}; - -/** - * Create a command object from the incoming string and ref it. - * - * @param string The incoming string. - * - * @return A MsnCommand object. - */ -MsnCommand *msn_command_from_string(const char *string); - -/** - * Increment the ref count. - * - * @param cmd The MsnCommand to be ref. - * - * @return The ref command. - */ -MsnCommand *msn_command_ref(MsnCommand *cmd); - -/** - * Decrement the ref count. If the count goes to 0, destroy it. - * - * @param cmd The MsnCommand to be unref. - * - */ -void msn_command_unref(MsnCommand *cmd); - -#endif /* MSN_COMMAND_H */ - diff --git a/libpurple/protocols/msn/contact.c b/libpurple/protocols/msn/contact.c deleted file mode 100644 index 4fba51ad90..0000000000 --- a/libpurple/protocols/msn/contact.c +++ /dev/null @@ -1,2048 +0,0 @@ -/** - * @file contact.c - * get MSN contacts via SOAP request - * created by MaYuan<mayuan2006@gmail.com> - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "internal.h" -#include "debug.h" - -#include "contact.h" -#include "xmlnode.h" -#include "group.h" -#include "msnutils.h" -#include "soap.h" -#include "nexus.h" -#include "user.h" - -const char *MsnSoapPartnerScenarioText[] = -{ - "Initial", - "ContactSave", - "MessengerPendingList", - "ContactMsgrAPI", - "BlockUnblock", - "Timer" -}; - -const char *MsnMemberRole[] = -{ - "Forward", - "Allow", - "Block", - "Reverse", - "Pending" -}; - -typedef struct { - MsnSession *session; - MsnSoapPartnerScenario which; -} GetContactListCbData; - -MsnCallbackState * -msn_callback_state_new(MsnSession *session) -{ - MsnCallbackState *state = g_new0(MsnCallbackState, 1); - - state->session = session; - - return state; -} - -MsnCallbackState * -msn_callback_state_dup(MsnCallbackState *state) -{ - MsnCallbackState *new_state = g_new0(MsnCallbackState, 1); - - new_state->session = state->session; - new_state->who = g_strdup(state->who); - new_state->uid = g_strdup(state->uid); - new_state->old_group_name = g_strdup(state->old_group_name); - new_state->new_group_name = g_strdup(state->new_group_name); - new_state->guid = g_strdup(state->guid); - /* The rest should be made new */ - - return new_state; -} - -void -msn_callback_state_free(MsnCallbackState *state) -{ - if (state == NULL) - return; - - g_free(state->who); - g_free(state->uid); - g_free(state->old_group_name); - g_free(state->new_group_name); - g_free(state->guid); - if (state->body) - xmlnode_free(state->body); - - g_free(state); -} - -void -msn_callback_state_set_who(MsnCallbackState *state, const gchar *who) -{ - g_return_if_fail(state != NULL); - - g_free(state->who); - state->who = g_strdup(who); -} - -void -msn_callback_state_set_uid(MsnCallbackState *state, const gchar *uid) -{ - g_return_if_fail(state != NULL); - - g_free(state->uid); - state->uid = g_strdup(uid); -} - -void -msn_callback_state_set_old_group_name(MsnCallbackState *state, const gchar *old_group_name) -{ - g_return_if_fail(state != NULL); - - g_free(state->old_group_name); - state->old_group_name = g_strdup(old_group_name); -} - -void -msn_callback_state_set_new_group_name(MsnCallbackState *state, const gchar *new_group_name) -{ - g_return_if_fail(state != NULL); - - g_free(state->new_group_name); - state->new_group_name = g_strdup(new_group_name); -} - -void -msn_callback_state_set_guid(MsnCallbackState *state, const gchar *guid) -{ - g_return_if_fail(state != NULL); - - g_free(state->guid); - state->guid = g_strdup(guid); -} - - -void -msn_callback_state_set_list_id(MsnCallbackState *state, MsnListId list_id) -{ - g_return_if_fail(state != NULL); - - state->list_id = list_id; -} - -void -msn_callback_state_set_action(MsnCallbackState *state, MsnCallbackAction action) -{ - g_return_if_fail(state != NULL); - - state->action |= action; -} - -/*************************************************************** - * General SOAP handling - ***************************************************************/ - -static const char * -msn_contact_operation_str(MsnCallbackAction action) -{ - /* Make sure this is large enough when adding more */ - static char buf[BUF_LEN]; - buf[0] = '\0'; - - if (action & MSN_ADD_BUDDY) - strcat(buf, "Adding Buddy,"); - if (action & MSN_MOVE_BUDDY) - strcat(buf, "Moving Buddy,"); - if (action & MSN_ACCEPTED_BUDDY) - strcat(buf, "Accepted Buddy,"); - if (action & MSN_DENIED_BUDDY) - strcat(buf, "Denied Buddy,"); - if (action & MSN_ADD_GROUP) - strcat(buf, "Adding Group,"); - if (action & MSN_DEL_GROUP) - strcat(buf, "Deleting Group,"); - if (action & MSN_RENAME_GROUP) - strcat(buf, "Renaming Group,"); - if (action & MSN_UPDATE_INFO) - strcat(buf, "Updating Contact Info,"); - if (action & MSN_ANNOTATE_USER) - strcat(buf, "Annotating Contact,"); - - return buf; -} - -static gboolean msn_contact_request(MsnCallbackState *state); - -static void -msn_contact_request_cb(MsnSoapMessage *req, MsnSoapMessage *resp, - gpointer data) -{ - MsnCallbackState *state = data; - xmlnode *fault; - char *faultcode_str; - xmlnode *cachekey; - char *changed; - - if (resp == NULL) { - purple_debug_error("msn", - "Operation {%s} failed. No response received from server.\n", - msn_contact_operation_str(state->action)); - msn_session_set_error(state->session, MSN_ERROR_BAD_BLIST, NULL); - msn_callback_state_free(state); - return; - } - - /* Update CacheKey if necessary */ - cachekey = xmlnode_get_child(resp->xml, "Header/ServiceHeader/CacheKeyChanged"); - if (cachekey != NULL) { - changed = xmlnode_get_data(cachekey); - if (changed && !strcmp(changed, "true")) { - cachekey = xmlnode_get_child(resp->xml, "Header/ServiceHeader/CacheKey"); - g_free(state->session->abch_cachekey); - state->session->abch_cachekey = xmlnode_get_data(cachekey); - purple_debug_info("msn", "Updated CacheKey for %s to '%s'.\n", - purple_account_get_username(state->session->account), - state->session->abch_cachekey); - } - g_free(changed); - } - - fault = xmlnode_get_child(resp->xml, "Body/Fault"); - - if (fault == NULL) { - /* No errors */ - if (state->cb) - state->cb(req, resp, data); - msn_callback_state_free(state); - return; - } - - faultcode_str = xmlnode_get_data(xmlnode_get_child(fault, "faultcode")); - - if (faultcode_str && g_str_equal(faultcode_str, "q0:BadContextToken")) { - purple_debug_info("msn", - "Contact Operation {%s} failed because of bad token." - " Updating token now and retrying operation.\n", - msn_contact_operation_str(state->action)); - /* Token has expired, so renew it, and try again later */ - msn_nexus_update_token(state->session->nexus, MSN_AUTH_CONTACTS, - (GSourceFunc)msn_contact_request, data); - } - else - { - if (state->cb) { - state->cb(req, resp, data); - } else { - /* We don't know how to respond to this faultcode, so log it */ - char *str = xmlnode_to_str(fault, NULL); - purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n", - msn_contact_operation_str(state->action), str); - g_free(str); - } - msn_callback_state_free(state); - } - - g_free(faultcode_str); -} - -static gboolean -msn_contact_request(MsnCallbackState *state) -{ - xmlnode *cachekey = xmlnode_get_child(state->body, - "Header/ABApplicationHeader/CacheKey"); - if (cachekey != NULL) - xmlnode_free(cachekey); - if (state->session->abch_cachekey != NULL) { - cachekey = xmlnode_new_child(xmlnode_get_child(state->body, "Header/ABApplicationHeader"), "CacheKey"); - xmlnode_insert_data(cachekey, state->session->abch_cachekey, -1); - } - if (state->token == NULL) - state->token = xmlnode_get_child(state->body, - "Header/ABAuthHeader/TicketToken"); - /* delete old & replace with new token */ - xmlnode_free(state->token->child); - xmlnode_insert_data(state->token, - msn_nexus_get_token_str(state->session->nexus, MSN_AUTH_CONTACTS), -1); - msn_soap_message_send(state->session, - msn_soap_message_new(state->post_action, xmlnode_copy(state->body)), - MSN_CONTACT_SERVER, state->post_url, FALSE, - msn_contact_request_cb, state); - return FALSE; -} - -/*************************************************************** - * Address Book and Membership List Operations - ***************************************************************/ - -/*get MSN member role utility*/ -static MsnListId -msn_get_memberrole(const char *role) -{ - g_return_val_if_fail(role != NULL, 0); - - if (!strcmp(role,"Allow")) { - return MSN_LIST_AL; - } else if (!strcmp(role,"Block")) { - return MSN_LIST_BL; - } else if (!strcmp(role,"Reverse")) { - return MSN_LIST_RL; - } else if (!strcmp(role,"Pending")) { - return MSN_LIST_PL; - } - return 0; -} - -/* Create the AddressBook in the server, if we don't have one */ -static void -msn_create_address_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) -{ - MsnCallbackState *state = data; - if (resp && xmlnode_get_child(resp->xml, "Body/Fault") == NULL) { - purple_debug_info("msn", "Address Book successfully created!\n"); - msn_get_address_book(state->session, MSN_PS_INITIAL, NULL, NULL); - } else { - purple_debug_info("msn", "Address Book creation failed!\n"); - } -} - -static void -msn_create_address_book(MsnSession *session) -{ - gchar *body; - MsnCallbackState *state; - - g_return_if_fail(session != NULL); - g_return_if_fail(session->user != NULL); - g_return_if_fail(session->user->passport != NULL); - - purple_debug_info("msn", "Creating an Address Book.\n"); - - body = g_strdup_printf(MSN_ADD_ADDRESSBOOK_TEMPLATE, - session->user->passport); - - state = msn_callback_state_new(session); - state->body = xmlnode_from_str(body, -1); - state->post_action = MSN_ADD_ADDRESSBOOK_SOAP_ACTION; - state->post_url = MSN_ADDRESS_BOOK_POST_URL; - state->cb = msn_create_address_cb; - msn_contact_request(state); - - g_free(body); -} - -static void -msn_parse_each_member(MsnSession *session, xmlnode *member, const char *node, - MsnListId list) -{ - char *passport; - char *type; - char *member_id; - MsnUser *user; - xmlnode *annotation; - guint nid = MSN_NETWORK_UNKNOWN; - char *invite = NULL; - - passport = xmlnode_get_data(xmlnode_get_child(member, node)); - if (!msn_email_is_valid(passport)) { - g_free(passport); - return; - } - - type = xmlnode_get_data(xmlnode_get_child(member, "Type")); - member_id = xmlnode_get_data(xmlnode_get_child(member, "MembershipId")); - - user = msn_userlist_find_add_user(session->userlist, passport, NULL); - - for (annotation = xmlnode_get_child(member, "Annotations/Annotation"); - annotation; - annotation = xmlnode_get_next_twin(annotation)) { - char *name = xmlnode_get_data(xmlnode_get_child(annotation, "Name")); - char *value = xmlnode_get_data(xmlnode_get_child(annotation, "Value")); - if (name && value) { - if (!strcmp(name, "MSN.IM.BuddyType")) { - nid = strtoul(value, NULL, 10); - } - else if (!strcmp(name, "MSN.IM.InviteMessage")) { - invite = value; - value = NULL; - } - } - g_free(name); - g_free(value); - } - - /* For EmailMembers, the network must be found in the annotations, above. - Otherwise, PassportMembers are on the Passport network. */ - if (!strcmp(node, "PassportName")) - nid = MSN_NETWORK_PASSPORT; - - purple_debug_info("msn", "CL: %s name: %s, Type: %s, MembershipID: %s, NetworkID: %u\n", - node, passport, type, member_id == NULL ? "(null)" : member_id, nid); - - msn_user_set_network(user, nid); - msn_user_set_invite_message(user, invite); - - if (list == MSN_LIST_PL && member_id) { - user->member_id_on_pending_list = atoi(member_id); - } - - msn_got_lst_user(session, user, 1 << list, NULL); - - g_free(passport); - g_free(type); - g_free(member_id); - g_free(invite); -} - -static void -msn_parse_each_service(MsnSession *session, xmlnode *service) -{ - xmlnode *type; - - if ((type = xmlnode_get_child(service, "Info/Handle/Type"))) { - char *type_str = xmlnode_get_data(type); - - if (g_str_equal(type_str, "Profile")) { - /* Process Windows Live 'Messenger Roaming Identity' */ - } else if (g_str_equal(type_str, "Messenger")) { - xmlnode *lastchange = xmlnode_get_child(service, "LastChange"); - char *lastchange_str = xmlnode_get_data(lastchange); - xmlnode *membership; - - purple_debug_info("msn", "CL last change: %s\n", lastchange_str); - purple_account_set_string(session->account, "CLLastChange", - lastchange_str); - - for (membership = xmlnode_get_child(service, - "Memberships/Membership"); - membership; membership = xmlnode_get_next_twin(membership)) { - - xmlnode *role = xmlnode_get_child(membership, "MemberRole"); - char *role_str = xmlnode_get_data(role); - MsnListId list = msn_get_memberrole(role_str); - xmlnode *member; - - purple_debug_info("msn", "CL MemberRole role: %s, list: %d\n", - role_str, list); - - for (member = xmlnode_get_child(membership, "Members/Member"); - member; member = xmlnode_get_next_twin(member)) { - const char *member_type = xmlnode_get_attrib(member, "type"); - if (g_str_equal(member_type, "PassportMember")) { - msn_parse_each_member(session, member, "PassportName", - list); - } else if (g_str_equal(member_type, "PhoneMember")) { - - } else if (g_str_equal(member_type, "EmailMember")) { - msn_parse_each_member(session, member, "Email", list); - } - } - - g_free(role_str); - } - - g_free(lastchange_str); - } - - g_free(type_str); - } -} - -/*parse contact list*/ -static gboolean -msn_parse_contact_list(MsnSession *session, xmlnode *node) -{ - xmlnode *fault, *faultnode; - - /* we may get a response if our cache data is too old: - * - * <faultstring>Need to do full sync. Can't sync deltas Client - * has too old a copy for us to do a delta sync</faultstring> - * - * this is not handled yet - */ - if ((fault = xmlnode_get_child(node, "Body/Fault"))) { - if ((faultnode = xmlnode_get_child(fault, "detail/errorcode"))) { - char *errorcode = xmlnode_get_data(faultnode); - - if (g_str_equal(errorcode, "ABDoesNotExist")) { - msn_create_address_book(session); - g_free(errorcode); - return FALSE; - } - - g_free(errorcode); - } - - if ((faultnode = xmlnode_get_child(fault, "faultstring"))) { - char *faultstring = xmlnode_get_data(faultnode); - purple_debug_info("msn", "Retrieving contact list failed: %s\n", - faultstring); - msn_session_set_error(session, MSN_ERROR_BAD_BLIST, faultstring); - g_free(faultstring); - } else { - msn_session_set_error(session, MSN_ERROR_BAD_BLIST, NULL); - } - return FALSE; - } else { - xmlnode *service; - - for (service = xmlnode_get_child(node, "Body/FindMembershipResponse/" - "FindMembershipResult/Services/Service"); - service; service = xmlnode_get_next_twin(service)) { - msn_parse_each_service(session, service); - } - return TRUE; - } -} - -static void -msn_get_contact_list_cb(MsnSoapMessage *req, MsnSoapMessage *resp, - gpointer data) -{ - MsnCallbackState *state = data; - MsnSession *session = state->session; - - g_return_if_fail(session != NULL); - - if (resp != NULL) { -#ifdef MSN_PARTIAL_LISTS - const char *abLastChange; - const char *dynamicItemLastChange; -#endif - - purple_debug_misc("msn", "Got the contact list!\n"); - - if (msn_parse_contact_list(session, resp->xml)) { -#ifdef MSN_PARTIAL_LISTS - abLastChange = purple_account_get_string(session->account, - "ablastChange", NULL); - dynamicItemLastChange = purple_account_get_string(session->account, - "DynamicItemLastChanged", NULL); -#endif - - if (state->partner_scenario == MSN_PS_INITIAL) { -#ifdef MSN_PARTIAL_LISTS - /* XXX: this should be enabled when we can correctly do partial - syncs with the server. Currently we need to retrieve the whole - list to detect sync issues */ - msn_get_address_book(session, MSN_PS_INITIAL, abLastChange, dynamicItemLastChange); -#else - msn_get_address_book(session, MSN_PS_INITIAL, NULL, NULL); -#endif - } - } - } -} - -/*SOAP get contact list*/ -void -msn_get_contact_list(MsnSession *session, - const MsnSoapPartnerScenario partner_scenario, const char *update_time) -{ - gchar *body = NULL; - gchar *update_str = NULL; - MsnCallbackState *state; - const gchar *partner_scenario_str = MsnSoapPartnerScenarioText[partner_scenario]; - - purple_debug_misc("msn", "Getting Contact List.\n"); - - if (update_time != NULL) { - purple_debug_info("msn", "CL Last update time: %s\n", update_time); - update_str = g_strdup_printf(MSN_GET_CONTACT_UPDATE_XML, update_time); - } - - body = g_strdup_printf(MSN_GET_CONTACT_TEMPLATE, partner_scenario_str, - update_str ? update_str : ""); - - state = msn_callback_state_new(session); - state->partner_scenario = partner_scenario; - state->body = xmlnode_from_str(body, -1); - state->post_action = MSN_GET_CONTACT_SOAP_ACTION; - state->post_url = MSN_GET_CONTACT_POST_URL; - state->cb = msn_get_contact_list_cb; - msn_contact_request(state); - - g_free(update_str); - g_free(body); -} - -static void -msn_parse_addressbook_groups(MsnSession *session, xmlnode *node) -{ - xmlnode *group; - - purple_debug_info("msn", "msn_parse_addressbook_groups()\n"); - - for(group = xmlnode_get_child(node, "Group"); group; - group = xmlnode_get_next_twin(group)){ - xmlnode *groupId, *groupInfo, *groupname; - char *group_id = NULL, *group_name = NULL; - - if ((groupId = xmlnode_get_child(group, "groupId"))) - group_id = xmlnode_get_data(groupId); - if ((groupInfo = xmlnode_get_child(group, "groupInfo")) && (groupname = xmlnode_get_child(groupInfo, "name"))) - group_name = xmlnode_get_data(groupname); - - if (group_id == NULL) { - /* Group of ungroupped buddies */ - g_free(group_name); - continue; - } - - msn_group_new(session->userlist, group_id, group_name); - - purple_debug_info("msn", "AB group_id: %s, name: %s\n", group_id, group_name ? group_name : "(null)"); - if ((purple_find_group(group_name)) == NULL) { - PurpleGroup *g = purple_group_new(group_name); - purple_blist_add_group(g, NULL); - } - g_free(group_id); - g_free(group_name); - } -} - -static gboolean -msn_parse_addressbook_mobile(xmlnode *contactInfo, char **inout_mobile_number) -{ - xmlnode *phones; - char *mobile_number = NULL; - gboolean mobile = FALSE; - - *inout_mobile_number = NULL; - - if ((phones = xmlnode_get_child(contactInfo, "phones"))) { - xmlnode *contact_phone; - char *phone_type = NULL; - - for (contact_phone = xmlnode_get_child(phones, "ContactPhone"); - contact_phone; - contact_phone = xmlnode_get_next_twin(contact_phone)) { - xmlnode *contact_phone_type; - - if (!(contact_phone_type = - xmlnode_get_child(contact_phone, "contactPhoneType"))) - continue; - - phone_type = xmlnode_get_data(contact_phone_type); - - if (phone_type && !strcmp(phone_type, "ContactPhoneMobile")) { - xmlnode *number; - - if ((number = xmlnode_get_child(contact_phone, "number"))) { - xmlnode *messenger_enabled; - char *is_messenger_enabled = NULL; - - g_free(mobile_number); - mobile_number = xmlnode_get_data(number); - - if (mobile_number && - (messenger_enabled = xmlnode_get_child(contact_phone, "isMessengerEnabled")) - && (is_messenger_enabled = xmlnode_get_data(messenger_enabled)) - && !strcmp(is_messenger_enabled, "true")) - mobile = TRUE; - - g_free(is_messenger_enabled); - } - } - - g_free(phone_type); - } - } - - *inout_mobile_number = mobile_number; - return mobile; -} - -static void -msn_parse_addressbook_contacts(MsnSession *session, xmlnode *node) -{ - xmlnode *contactNode; - char *passport = NULL, *Name = NULL, *uid = NULL, *type = NULL, *mobile_number = NULL, *alias = NULL; - gboolean mobile = FALSE; - PurpleConnection *pc = purple_account_get_connection(session->account); - - for(contactNode = xmlnode_get_child(node, "Contact"); contactNode; - contactNode = xmlnode_get_next_twin(contactNode)) { - xmlnode *contactId, *contactInfo, *contactType, *passportName, *displayName, *guid, *groupIds; - xmlnode *annotation; - MsnUser *user; - - g_free(passport); - g_free(Name); - g_free(uid); - g_free(type); - g_free(mobile_number); - g_free(alias); - passport = Name = uid = type = mobile_number = alias = NULL; - mobile = FALSE; - - if (!(contactId = xmlnode_get_child(contactNode,"contactId")) - || !(contactInfo = xmlnode_get_child(contactNode, "contactInfo")) - || !(contactType = xmlnode_get_child(contactInfo, "contactType"))) - continue; - - uid = xmlnode_get_data(contactId); - type = xmlnode_get_data(contactType); - - /* Find out our settings */ - if (type && !strcmp(type, "Me")) { - /* setup the Display Name */ - if (purple_connection_get_display_name(pc) == NULL) { - char *friendly = NULL; - if ((displayName = xmlnode_get_child(contactInfo, "displayName"))) - friendly = xmlnode_get_data(displayName); - purple_connection_set_display_name(pc, - friendly ? purple_url_decode(friendly) : NULL); - g_free(friendly); - } - - for (annotation = xmlnode_get_child(contactInfo, "annotations/Annotation"); - annotation; - annotation = xmlnode_get_next_twin(annotation)) { - char *name, *value; - name = xmlnode_get_data(xmlnode_get_child(annotation, "Name")); - value = xmlnode_get_data(xmlnode_get_child(annotation, "Value")); - if (name && g_str_equal(name, "MSN.IM.MPOP")) { - if (!value || atoi(value) != 0) - session->enable_mpop = TRUE; - else - session->enable_mpop = FALSE; - } - g_free(name); - g_free(value); - } - - continue; /* Not adding own account as buddy to buddylist */ - } - - passportName = xmlnode_get_child(contactInfo, "passportName"); - if (passportName == NULL) { - xmlnode *emailsNode, *contactEmailNode, *emailNode; - xmlnode *messengerEnabledNode; - char *msnEnabled; - - /*TODO: add it to the non-instant Messenger group and recognize as email Membership*/ - /* Yahoo/Federated User? */ - emailsNode = xmlnode_get_child(contactInfo, "emails"); - if (emailsNode == NULL) { - /*TODO: need to support the Mobile type*/ - continue; - } - for (contactEmailNode = xmlnode_get_child(emailsNode, "ContactEmail"); - contactEmailNode; - contactEmailNode = xmlnode_get_next_twin(contactEmailNode)) { - if ((messengerEnabledNode = xmlnode_get_child(contactEmailNode, "isMessengerEnabled"))) { - - msnEnabled = xmlnode_get_data(messengerEnabledNode); - - if (msnEnabled && !strcmp(msnEnabled, "true")) { - if ((emailNode = xmlnode_get_child(contactEmailNode, "email"))) - passport = xmlnode_get_data(emailNode); - - /* Messenger enabled, Get the Passport*/ - purple_debug_info("msn", "AB Yahoo/Federated User %s\n", passport ? passport : "(null)"); - g_free(msnEnabled); - break; - } - - g_free(msnEnabled); - } - } - } else { - xmlnode *messenger_user; - /* ignore non-messenger contacts */ - if ((messenger_user = xmlnode_get_child(contactInfo, "isMessengerUser"))) { - char *is_messenger_user = xmlnode_get_data(messenger_user); - - if (is_messenger_user && !strcmp(is_messenger_user, "false")) { - g_free(is_messenger_user); - continue; - } - - g_free(is_messenger_user); - } - - passport = xmlnode_get_data(passportName); - } - - /* Couldn't find anything */ - if (passport == NULL) - continue; - - if (!msn_email_is_valid(passport)) - continue; - - if ((displayName = xmlnode_get_child(contactInfo, "displayName"))) - Name = xmlnode_get_data(displayName); - else - Name = g_strdup(passport); - - for (annotation = xmlnode_get_child(contactInfo, "annotations/Annotation"); - annotation; - annotation = xmlnode_get_next_twin(annotation)) { - char *name; - name = xmlnode_get_data(xmlnode_get_child(annotation, "Name")); - if (!name) - continue; - if (!strcmp(name, "AB.NickName")) - alias = xmlnode_get_data(xmlnode_get_child(annotation, "Value")); - else if (!strcmp(name, "MSN.IM.HasSharedFolder")) - ; /* Do nothing yet... */ - else if (!strcmp(name, "AB.Spouse")) - ; /* Do nothing yet... */ - else if (!strcmp(name, "MSN.Mobile.ContactId")) - ; /* Do nothing yet... */ - else - purple_debug_info("msn", - "Unknown AB contact annotation: %s\n", name); - g_free(name); - } - - mobile = msn_parse_addressbook_mobile(contactInfo, &mobile_number); - - purple_debug_misc("msn", "AB passport:{%s} uid:{%s} display:{%s} alias: {%s} mobile:{%s} mobile number:{%s}\n", - passport, uid ? uid : "(null)", Name ? Name : "(null)", alias ? alias : "(null)", - mobile ? "true" : "false", mobile_number ? mobile_number : "(null)"); - - user = msn_userlist_find_add_user(session->userlist, passport, Name); - msn_user_set_uid(user, uid); - msn_user_set_mobile_phone(user, mobile_number); - - groupIds = xmlnode_get_child(contactInfo, "groupIds"); - if (groupIds) { - for (guid = xmlnode_get_child(groupIds, "guid"); guid; - guid = xmlnode_get_next_twin(guid)) { - char *group_id = xmlnode_get_data(guid); - msn_user_add_group_id(user, group_id); - purple_debug_misc("msn", "AB guid:%s\n", group_id ? group_id : "(null)"); - g_free(group_id); - } - } else { - purple_debug_info("msn", "User not in any groups, adding to default group.\n"); - /*not in any group,Then set default group*/ - msn_user_add_group_id(user, MSN_INDIVIDUALS_GROUP_ID); - } - - msn_got_lst_user(session, user, MSN_LIST_FL_OP, NULL); - - if (mobile && user) - { - user->mobile = TRUE; - purple_prpl_got_user_status(session->account, user->passport, "mobile", NULL); - purple_prpl_got_user_status(session->account, user->passport, "available", NULL); - } - if (alias) - purple_serv_got_private_alias(pc, passport, alias); - } - - g_free(passport); - g_free(Name); - g_free(uid); - g_free(type); - g_free(mobile_number); - g_free(alias); -} - -static void -msn_parse_addressbook_circles(MsnSession *session, xmlnode *node) -{ - xmlnode *ticket; - - /* TODO: Parse groups */ - - ticket = xmlnode_get_child(node, "CircleTicket"); - if (ticket) { - char *data = xmlnode_get_data(ticket); - msn_notification_send_circle_auth(session, data); - g_free(data); - } -} - -static gboolean -msn_parse_addressbook(MsnSession *session, xmlnode *node) -{ - xmlnode *result; - xmlnode *groups; - xmlnode *contacts; - xmlnode *abNode; - xmlnode *circleNode; - xmlnode *fault; - - if ((fault = xmlnode_get_child(node, "Body/Fault"))) { - xmlnode *faultnode; - - if ((faultnode = xmlnode_get_child(fault, "faultstring"))) { - gchar *faultstring = xmlnode_get_data(faultnode); - purple_debug_info("msn", "AB Faultstring: %s\n", faultstring); - g_free(faultstring); - } - - if ((faultnode = xmlnode_get_child(fault, "detail/errorcode"))) { - gchar *errorcode = xmlnode_get_data(faultnode); - - purple_debug_info("msn", "AB Error Code: %s\n", errorcode); - - if (g_str_equal(errorcode, "ABDoesNotExist")) { - g_free(errorcode); - return TRUE; - } - g_free(errorcode); - } - - return FALSE; - } - - result = xmlnode_get_child(node, "Body/ABFindContactsPagedResponse/ABFindContactsPagedResult"); - if (result == NULL) { - purple_debug_misc("msn", "Received no address book update\n"); - return TRUE; - } - - /* I don't see this "groups" tag documented on msnpiki, need to find out - if they are really there, and update msnpiki */ - /*Process Group List*/ - groups = xmlnode_get_child(result, "Groups"); - if (groups != NULL) { - msn_parse_addressbook_groups(session, groups); - } - - /* Add an "Other Contacts" group for buddies who aren't in a group */ - msn_group_new(session->userlist, MSN_INDIVIDUALS_GROUP_ID, - MSN_INDIVIDUALS_GROUP_NAME); - purple_debug_misc("msn", "AB group_id:%s name:%s\n", - MSN_INDIVIDUALS_GROUP_ID, MSN_INDIVIDUALS_GROUP_NAME); - if ((purple_find_group(MSN_INDIVIDUALS_GROUP_NAME)) == NULL){ - PurpleGroup *g = purple_group_new(MSN_INDIVIDUALS_GROUP_NAME); - purple_blist_add_group(g, NULL); - } - - /* Add a "Non-IM Contacts" group */ - msn_group_new(session->userlist, MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME); - purple_debug_misc("msn", "AB group_id:%s name:%s\n", MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME); - if ((purple_find_group(MSN_NON_IM_GROUP_NAME)) == NULL) { - PurpleGroup *g = purple_group_new(MSN_NON_IM_GROUP_NAME); - purple_blist_add_group(g, NULL); - } - - /*Process contact List*/ - purple_debug_info("msn", "Process contact list...\n"); - contacts = xmlnode_get_child(result, "Contacts"); - if (contacts != NULL) { - msn_parse_addressbook_contacts(session, contacts); - } - - abNode = xmlnode_get_child(result, "Ab"); - if (abNode != NULL) { - xmlnode *node2; - char *tmp = NULL; - - if ((node2 = xmlnode_get_child(abNode, "lastChange"))) - tmp = xmlnode_get_data(node2); - purple_debug_info("msn", "AB lastchanged Time:{%s}\n", tmp ? tmp : "(null)"); - purple_account_set_string(session->account, "ablastChange", tmp); - - g_free(tmp); tmp = NULL; - if ((node2 = xmlnode_get_child(abNode, "DynamicItemLastChanged"))) - tmp = xmlnode_get_data(node2); - purple_debug_info("msn", "AB DynamicItemLastChanged :{%s}\n", tmp ? tmp : "(null)"); - purple_account_set_string(session->account, "DynamicItemLastChanged", tmp); - g_free(tmp); - } - - circleNode = xmlnode_get_child(result, "CircleResult"); - if (circleNode != NULL) { - msn_parse_addressbook_circles(session, circleNode); - } - - return TRUE; -} - -static void -msn_get_address_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) -{ - MsnCallbackState *state = data; - MsnSession *session = state->session; - - g_return_if_fail(session != NULL); - - purple_debug_misc("msn", "Got the Address Book!\n"); - - if (msn_parse_addressbook(session, resp->xml)) { - msn_send_privacy(session->account->gc); - msn_notification_dump_contact(session); - } else { - /* This is making us loop infinitely when we fail to parse the - address book, disable for now (we should re-enable when we - send timestamps) - */ - /* - msn_get_address_book(session, NULL, NULL); - */ - msn_session_set_error(session, MSN_ERROR_BAD_BLIST, NULL); - } -} - -/*get the address book*/ -void -msn_get_address_book(MsnSession *session, - MsnSoapPartnerScenario partner_scenario, const char *LastChanged, - const char *dynamicItemLastChange) -{ - char *body, *update_str = NULL; - MsnCallbackState *state; - - purple_debug_misc("msn", "Getting Address Book\n"); - - /*build SOAP and POST it*/ - if (dynamicItemLastChange != NULL) - update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML, dynamicItemLastChange); - else if (LastChanged != NULL) - update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML, LastChanged); - - body = g_strdup_printf(MSN_GET_ADDRESS_TEMPLATE, - MsnSoapPartnerScenarioText[partner_scenario], - update_str ? update_str : ""); - - state = msn_callback_state_new(session); - state->body = xmlnode_from_str(body, -1); - state->post_action = MSN_GET_ADDRESS_SOAP_ACTION; - state->post_url = MSN_ADDRESS_BOOK_POST_URL; - state->cb = msn_get_address_cb; - msn_contact_request(state); - - g_free(update_str); - g_free(body); -} - -/*************************************************************** - * Contact Operations - ***************************************************************/ - -static void -msn_add_contact_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, - gpointer data) -{ - MsnCallbackState *state = data; - MsnSession *session = state->session; - - MsnUserList *userlist; - MsnUser *user; - xmlnode *guid; - - xmlnode *fault; - - g_return_if_fail(session != NULL); - userlist = session->userlist; - - fault = xmlnode_get_child(resp->xml, "Body/Fault"); - if (fault != NULL) { - char *errorcode = xmlnode_get_data(xmlnode_get_child(fault, "detail/errorcode")); - if (errorcode && !strcmp(errorcode, "EmailDomainIsFederated")) { - /* Do something special! */ - purple_debug_error("msn", "Contact is from a federated domain, but don't know what to do yet!\n"); - - } else if (errorcode && !strcmp(errorcode, "InvalidPassportUser")) { - PurpleBuddy *buddy = purple_find_buddy(session->account, state->who); - char *str = g_strdup_printf(_("Unable to add \"%s\"."), state->who); - purple_notify_error(state->session, _("Buddy Add error"), str, - _("The username specified does not exist.")); - g_free(str); - msn_userlist_rem_buddy(userlist, state->who); - if (buddy != NULL) - purple_blist_remove_buddy(buddy); - - } else { - /* We don't know how to respond to this faultcode, so log it */ - char *fault_str = xmlnode_to_str(fault, NULL); - if (fault_str != NULL) { - purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n", - msn_contact_operation_str(state->action), fault_str); - g_free(fault_str); - } - } - return; - } - - purple_debug_info("msn", "Contact added successfully\n"); - - msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL); - msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL); - - user = msn_userlist_find_add_user(userlist, state->who, state->who); - msn_user_add_group_id(user, state->guid); - - guid = xmlnode_get_child(resp->xml, - "Body/ABContactAddResponse/ABContactAddResult/guid"); - if (guid != NULL) { - char *uid = xmlnode_get_data(guid); - msn_user_set_uid(user, uid); - purple_debug_info("msn", "Set %s guid to %s.\n", state->who, uid); - g_free(uid); - } -} - -/* add a Contact in MSN_INDIVIDUALS_GROUP */ -void -msn_add_contact(MsnSession *session, MsnCallbackState *state, const char *passport) -{ - MsnUser *user; - gchar *body = NULL; - gchar *contact_xml = NULL; - - purple_debug_info("msn", "Adding contact %s to contact list\n", passport); - - user = msn_userlist_find_user(session->userlist, passport); - if (user == NULL) { - purple_debug_warning("msn", "Unable to retrieve user %s from the userlist!\n", passport); - return; /* guess this never happened! */ - } - - if (user->networkid != MSN_NETWORK_PASSPORT) { - contact_xml = g_strdup_printf(MSN_CONTACT_EMAIL_XML, - user->networkid == MSN_NETWORK_YAHOO ? - "Messenger2" : - "Messenger3", - passport, 0); - } else { - contact_xml = g_strdup_printf(MSN_CONTACT_XML, passport); - } - body = g_strdup_printf(MSN_ADD_CONTACT_TEMPLATE, contact_xml); - - state->body = xmlnode_from_str(body, -1); - state->post_action = MSN_CONTACT_ADD_SOAP_ACTION; - state->post_url = MSN_ADDRESS_BOOK_POST_URL; - state->cb = msn_add_contact_read_cb; - msn_contact_request(state); - - g_free(contact_xml); - g_free(body); -} - -static void -msn_add_contact_to_group_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, - gpointer data) -{ - MsnCallbackState *state = data; - MsnSession *session = state->session; - MsnUserList *userlist; - xmlnode *fault; - - g_return_if_fail(session != NULL); - userlist = session->userlist; - - fault = xmlnode_get_child(resp->xml, "Body/Fault"); - if (fault != NULL) { - char *errorcode = xmlnode_get_data(xmlnode_get_child(fault, "detail/errorcode")); - if (errorcode && !strcmp(errorcode, "EmailDomainIsFederated")) { - /* Do something special! */ - purple_debug_error("msn", "Contact is from a federated domain, but don't know what to do yet!\n"); - - } else if (errorcode && !strcmp(errorcode, "InvalidPassportUser")) { - PurpleBuddy *buddy = purple_find_buddy(session->account, state->who); - char *str = g_strdup_printf(_("Unable to add \"%s\"."), state->who); - purple_notify_error(session, _("Buddy Add error"), str, - _("The username specified does not exist.")); - g_free(str); - msn_userlist_rem_buddy(userlist, state->who); - if (buddy != NULL) - purple_blist_remove_buddy(buddy); - - } else { - /* We don't know how to respond to this faultcode, so log it */ - char *fault_str = xmlnode_to_str(fault, NULL); - if (fault_str != NULL) { - purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n", - msn_contact_operation_str(state->action), fault_str); - g_free(fault_str); - } - } - return; - } - - if (msn_userlist_add_buddy_to_group(userlist, state->who, - state->new_group_name)) { - purple_debug_info("msn", "Contact %s added to group %s successfully!\n", state->who, state->new_group_name); - } else { - purple_debug_info("msn", "Contact %s added to group %s successfully on server, but failed in the local list\n", state->who, state->new_group_name); - } - - if (state->action & MSN_ADD_BUDDY) { - MsnUser *user = msn_userlist_find_user(userlist, state->who); - xmlnode *guid = xmlnode_get_child(resp->xml, - "Body/ABGroupContactAddResponse/ABGroupContactAddResult/guid"); - - if (guid != NULL) { - char *uid = xmlnode_get_data(guid); - msn_user_set_uid(user, uid); - purple_debug_info("msn", "Set %s guid to %s.\n", state->who, uid); - g_free(uid); - } - - msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL); - msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL); - - if (msn_user_is_in_list(user, MSN_LIST_PL)) { - msn_del_contact_from_list(state->session, NULL, state->who, MSN_LIST_PL); - return; - } - } - - if (state->action & MSN_MOVE_BUDDY) { - msn_del_contact_from_group(state->session, state->who, state->old_group_name); - } -} - -void -msn_add_contact_to_group(MsnSession *session, MsnCallbackState *state, - const char *passport, const char *groupId) -{ - MsnUserList *userlist; - MsnUser *user; - gchar *body = NULL, *contact_xml, *invite; - - g_return_if_fail(passport != NULL); - g_return_if_fail(groupId != NULL); - - g_return_if_fail(session != NULL); - - userlist = session->userlist; - - if (!strcmp(groupId, MSN_INDIVIDUALS_GROUP_ID) || !strcmp(groupId, MSN_NON_IM_GROUP_ID)) { - - user = msn_userlist_find_add_user(userlist, passport, passport); - - if (state->action & MSN_ADD_BUDDY) { - msn_add_contact(session, state, passport); - return; - } - - if (state->action & MSN_MOVE_BUDDY) { - msn_user_add_group_id(user, groupId); - msn_del_contact_from_group(session, passport, state->old_group_name); - } - - return; - } - - purple_debug_info("msn", "Adding user %s to group %s\n", passport, - msn_userlist_find_group_name(userlist, groupId)); - - user = msn_userlist_find_user(userlist, passport); - if (user == NULL) { - purple_debug_warning("msn", "Unable to retrieve user %s from the userlist!\n", passport); - msn_callback_state_free(state); - return; /* guess this never happened! */ - } - - if (user->uid != NULL) { - contact_xml = g_strdup_printf(MSN_CONTACT_ID_XML, user->uid); - } else if (user->networkid != MSN_NETWORK_PASSPORT) { - contact_xml = g_strdup_printf(MSN_CONTACT_EMAIL_XML, - user->networkid == MSN_NETWORK_YAHOO ? - "Messenger2" : - "Messenger3", - passport, 0); - } else { - contact_xml = g_strdup_printf(MSN_CONTACT_XML, passport); - } - - if (user->invite_message) { - char *tmp; - body = g_markup_escape_text(user->invite_message, -1); - - /* Ignore the cast, we treat it as const anyway. */ - tmp = (char *)purple_connection_get_display_name(session->account->gc); - tmp = tmp ? g_markup_escape_text(tmp, -1) : g_strdup(""); - - invite = g_strdup_printf(MSN_CONTACT_INVITE_MESSAGE_XML, body, tmp); - - g_free(body); - g_free(tmp); - - /* We can free this now */ - g_free(user->invite_message); - user->invite_message = NULL; - - } else { - invite = g_strdup(""); - } - - body = g_strdup_printf(MSN_ADD_CONTACT_GROUP_TEMPLATE, groupId, contact_xml, invite); - - state->body = xmlnode_from_str(body, -1); - state->post_action = MSN_ADD_CONTACT_GROUP_SOAP_ACTION; - state->post_url = MSN_ADDRESS_BOOK_POST_URL; - state->cb = msn_add_contact_to_group_read_cb; - msn_contact_request(state); - - g_free(invite); - g_free(contact_xml); - g_free(body); -} - -static void -msn_delete_contact_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, - gpointer data) -{ - MsnCallbackState *state = data; - MsnUserList *userlist = state->session->userlist; - MsnUser *user = msn_userlist_find_user_with_id(userlist, state->uid); - xmlnode *fault; - - /* We don't know how to respond to this faultcode, so log it */ - fault = xmlnode_get_child(resp->xml, "Body/Fault"); - if (fault != NULL) { - char *fault_str = xmlnode_to_str(fault, NULL); - purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n", - msn_contact_operation_str(state->action), fault_str); - g_free(fault_str); - return; - } - - purple_debug_info("msn", "Delete contact successful\n"); - - if (user != NULL) { - msn_userlist_remove_user(userlist, user); - } -} - -/*delete a Contact*/ -void -msn_delete_contact(MsnSession *session, MsnUser *user) -{ - gchar *body = NULL; - gchar *contact_id_xml = NULL ; - MsnCallbackState *state; - - if (user->uid != NULL) { - contact_id_xml = g_strdup_printf(MSN_CONTACT_ID_XML, user->uid); - purple_debug_info("msn", "Deleting contact with contactId: %s\n", user->uid); - } else { - purple_debug_info("msn", "Unable to delete contact %s without a ContactId\n", user->passport); - return; - } - - state = msn_callback_state_new(session); - msn_callback_state_set_uid(state, user->uid); - - /* build SOAP request */ - body = g_strdup_printf(MSN_DEL_CONTACT_TEMPLATE, contact_id_xml); - - state->body = xmlnode_from_str(body, -1); - state->post_action = MSN_CONTACT_DEL_SOAP_ACTION; - state->post_url = MSN_ADDRESS_BOOK_POST_URL; - state->cb = msn_delete_contact_read_cb; - msn_contact_request(state); - - g_free(contact_id_xml); - g_free(body); -} - -static void -msn_del_contact_from_group_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, - gpointer data) -{ - MsnCallbackState *state = data; - xmlnode *fault; - - /* We don't know how to respond to this faultcode, so log it */ - fault = xmlnode_get_child(resp->xml, "Body/Fault"); - if (fault != NULL) { - char *fault_str = xmlnode_to_str(fault, NULL); - purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n", - msn_contact_operation_str(state->action), fault_str); - g_free(fault_str); - return; - } - - if (msn_userlist_rem_buddy_from_group(state->session->userlist, - state->who, state->old_group_name)) { - purple_debug_info("msn", "Contact %s deleted successfully from group %s\n", state->who, state->old_group_name); - } else { - purple_debug_info("msn", "Contact %s deleted successfully from group %s in the server, but failed in the local list\n", state->who, state->old_group_name); - } -} - -void -msn_del_contact_from_group(MsnSession *session, const char *passport, const char *group_name) -{ - MsnUserList * userlist; - MsnUser *user; - MsnCallbackState *state; - gchar *body, *contact_id_xml; - const gchar *groupId; - - g_return_if_fail(passport != NULL); - g_return_if_fail(group_name != NULL); - g_return_if_fail(session != NULL); - - userlist = session->userlist; - - groupId = msn_userlist_find_group_id(userlist, group_name); - if (groupId != NULL) { - purple_debug_info("msn", "Deleting user %s from group %s\n", passport, group_name); - } else { - purple_debug_warning("msn", "Unable to retrieve group id from group %s !\n", group_name); - return; - } - - user = msn_userlist_find_user(userlist, passport); - - if (user == NULL) { - purple_debug_warning("msn", "Unable to retrieve user from passport %s!\n", passport); - return; - } - - if ( !strcmp(groupId, MSN_INDIVIDUALS_GROUP_ID) || !strcmp(groupId, MSN_NON_IM_GROUP_ID)) { - msn_user_remove_group_id(user, groupId); - return; - } - - state = msn_callback_state_new(session); - msn_callback_state_set_who(state, passport); - msn_callback_state_set_guid(state, groupId); - msn_callback_state_set_old_group_name(state, group_name); - - if (user->uid != NULL) - contact_id_xml = g_strdup_printf(MSN_CONTACT_ID_XML, user->uid); - else - contact_id_xml = g_strdup_printf(MSN_CONTACT_XML, passport); - body = g_strdup_printf(MSN_CONTACT_DEL_GROUP_TEMPLATE, contact_id_xml, groupId); - - state->body = xmlnode_from_str(body, -1); - state->post_action = MSN_CONTACT_DEL_GROUP_SOAP_ACTION; - state->post_url = MSN_ADDRESS_BOOK_POST_URL; - state->cb = msn_del_contact_from_group_read_cb; - msn_contact_request(state); - - g_free(contact_id_xml); - g_free(body); -} - - -static void -msn_update_contact_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, - gpointer data) -{ - MsnCallbackState *state = (MsnCallbackState *)data; - xmlnode *fault; - - /* We don't know how to respond to this faultcode, so log it */ - fault = xmlnode_get_child(resp->xml, "Body/Fault"); - if (fault != NULL) { - char *fault_str = xmlnode_to_str(fault, NULL); - purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n", - msn_contact_operation_str(state->action), fault_str); - g_free(fault_str); - return; - } - - purple_debug_info("msn", "Contact updated successfully\n"); -} - -/* Update a contact's info */ -void -msn_update_contact(MsnSession *session, const char *passport, MsnContactUpdateType type, const char* value) -{ - MsnCallbackState *state; - xmlnode *contact; - xmlnode *contact_info; - xmlnode *changes; - MsnUser *user = NULL; - - purple_debug_info("msn", "Update contact information for %s with new %s: %s\n", - passport ? passport : "(null)", - type == MSN_UPDATE_DISPLAY ? "display name" : "alias", - value ? value : "(null)"); - g_return_if_fail(passport != NULL); - - if (strcmp(passport, "Me") != 0) { - user = msn_userlist_find_user(session->userlist, passport); - if (!user) - return; - } - - contact_info = xmlnode_new("contactInfo"); - changes = xmlnode_new("propertiesChanged"); - - switch (type) { - xmlnode *annotations; - xmlnode *display; - xmlnode *a, *n, *v; - case MSN_UPDATE_DISPLAY: - display = xmlnode_new_child(contact_info, "displayName"); - xmlnode_insert_data(display, value, -1); - xmlnode_insert_data(changes, "DisplayName", -1); - break; - - case MSN_UPDATE_ALIAS: - annotations = xmlnode_new_child(contact_info, "annotations"); - xmlnode_insert_data(changes, "Annotation ", -1); - - a = xmlnode_new_child(annotations, "Annotation"); - n = xmlnode_new_child(a, "Name"); - xmlnode_insert_data(n, "AB.NickName", -1); - v = xmlnode_new_child(a, "Value"); - xmlnode_insert_data(v, value, -1); - break; - - default: - g_return_if_reached(); - } - - state = msn_callback_state_new(session); - - state->body = xmlnode_from_str(MSN_CONTACT_UPDATE_TEMPLATE, -1); - state->action = MSN_UPDATE_INFO; - state->post_action = MSN_CONTACT_UPDATE_SOAP_ACTION; - state->post_url = MSN_ADDRESS_BOOK_POST_URL; - state->cb = msn_update_contact_read_cb; - - contact = xmlnode_get_child(state->body, "Body/ABContactUpdate/contacts/Contact"); - xmlnode_insert_child(contact, contact_info); - xmlnode_insert_child(contact, changes); - - xmlnode_insert_data(xmlnode_get_child(state->body, - "Header/ABApplicationHeader/PartnerScenario"), - MsnSoapPartnerScenarioText[MSN_PS_SAVE_CONTACT], -1); - - if (user) { - xmlnode *contactId = xmlnode_new_child(contact, "contactId"); - msn_callback_state_set_uid(state, user->uid); - xmlnode_insert_data(contactId, state->uid, -1); - } else { - xmlnode *contactType = xmlnode_new_child(contact_info, "contactType"); - xmlnode_insert_data(contactType, "Me", -1); - } - - msn_contact_request(state); -} - -static void -msn_annotate_contact_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, - gpointer data) -{ - MsnCallbackState *state = (MsnCallbackState *)data; - xmlnode *fault; - - /* We don't know how to respond to this faultcode, so log it */ - fault = xmlnode_get_child(resp->xml, "Body/Fault"); - if (fault != NULL) { - char *fault_str = xmlnode_to_str(fault, NULL); - purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n", - msn_contact_operation_str(state->action), fault_str); - g_free(fault_str); - return; - } - - purple_debug_info("msn", "Contact annotated successfully\n"); -} - -/* Update a contact's annotations */ -void -msn_annotate_contact(MsnSession *session, const char *passport, ...) -{ - va_list params; - MsnCallbackState *state; - xmlnode *contact; - xmlnode *contact_info; - xmlnode *annotations; - MsnUser *user = NULL; - - g_return_if_fail(passport != NULL); - - if (strcmp(passport, "Me") != 0) { - user = msn_userlist_find_user(session->userlist, passport); - if (!user) - return; - } - - contact_info = xmlnode_new("contactInfo"); - annotations = xmlnode_new_child(contact_info, "annotations"); - - va_start(params, passport); - while (TRUE) { - const char *name; - const char *value; - xmlnode *a, *n, *v; - - name = va_arg(params, const char *); - if (!name) - break; - - value = va_arg(params, const char *); - if (!value) - break; - - a = xmlnode_new_child(annotations, "Annotation"); - n = xmlnode_new_child(a, "Name"); - xmlnode_insert_data(n, name, -1); - v = xmlnode_new_child(a, "Value"); - xmlnode_insert_data(v, value, -1); - } - va_end(params); - - state = msn_callback_state_new(session); - - state->body = xmlnode_from_str(MSN_CONTACT_ANNOTATE_TEMPLATE, -1); - state->action = MSN_ANNOTATE_USER; - state->post_action = MSN_CONTACT_ANNOTATE_SOAP_ACTION; - state->post_url = MSN_ADDRESS_BOOK_POST_URL; - state->cb = msn_annotate_contact_read_cb; - - xmlnode_insert_data(xmlnode_get_child(state->body, - "Header/ABApplicationHeader/PartnerScenario"), - MsnSoapPartnerScenarioText[MSN_PS_SAVE_CONTACT], -1); - - contact = xmlnode_get_child(state->body, "Body/ABContactUpdate/contacts/Contact"); - xmlnode_insert_child(contact, contact_info); - - if (user) { - xmlnode *contactId = xmlnode_new_child(contact, "contactId"); - msn_callback_state_set_uid(state, user->uid); - xmlnode_insert_data(contactId, state->uid, -1); - } else { - xmlnode *contactType = xmlnode_new_child(contact_info, "contactType"); - xmlnode_insert_data(contactType, "Me", -1); - } - - msn_contact_request(state); -} - -static void -msn_del_contact_from_list_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, - gpointer data) -{ - MsnCallbackState *state = data; - MsnSession *session = state->session; - xmlnode *fault; - - /* We don't know how to respond to this faultcode, so log it */ - fault = xmlnode_get_child(resp->xml, "Body/Fault"); - if (fault != NULL) { - char *fault_str = xmlnode_to_str(fault, NULL); - purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n", - msn_contact_operation_str(state->action), fault_str); - g_free(fault_str); - return; - } - - purple_debug_info("msn", "Contact %s deleted successfully from %s list on server!\n", state->who, MsnMemberRole[state->list_id]); - - if (state->list_id == MSN_LIST_PL) { - MsnUser *user = msn_userlist_find_user(session->userlist, state->who); - MsnCallbackState *new_state = msn_callback_state_dup(state); - - if (user != NULL) - msn_user_unset_op(user, MSN_LIST_PL_OP); - - msn_add_contact_to_list(session, new_state, state->who, MSN_LIST_RL); - return; - } else if (state->list_id == MSN_LIST_AL) { - purple_privacy_permit_remove(session->account, state->who, TRUE); - msn_add_contact_to_list(session, NULL, state->who, MSN_LIST_BL); - } else if (state->list_id == MSN_LIST_BL) { - purple_privacy_deny_remove(session->account, state->who, TRUE); - msn_add_contact_to_list(session, NULL, state->who, MSN_LIST_AL); - } - -} - -void -msn_del_contact_from_list(MsnSession *session, MsnCallbackState *state, - const gchar *passport, const MsnListId list) -{ - gchar *body = NULL, *member = NULL; - MsnSoapPartnerScenario partner_scenario; - MsnUser *user; - - g_return_if_fail(session != NULL); - g_return_if_fail(session->userlist != NULL); - g_return_if_fail(passport != NULL); - g_return_if_fail(list < 5); - - purple_debug_info("msn", "Deleting contact %s from %s list\n", passport, MsnMemberRole[list]); - - if (state == NULL) { - state = msn_callback_state_new(session); - } - msn_callback_state_set_list_id(state, list); - msn_callback_state_set_who(state, passport); - - user = msn_userlist_find_user(session->userlist, passport); - g_return_if_fail(user != NULL); - - if (list == MSN_LIST_PL) { - partner_scenario = MSN_PS_CONTACT_API; - if (user->networkid != MSN_NETWORK_PASSPORT) - member = g_strdup_printf(MSN_MEMBER_MEMBERSHIPID_XML, - "EmailMember", "Email", - user->member_id_on_pending_list); - else - member = g_strdup_printf(MSN_MEMBER_MEMBERSHIPID_XML, - "PassportMember", "Passport", - user->member_id_on_pending_list); - } else { - /* list == MSN_LIST_AL || list == MSN_LIST_BL */ - partner_scenario = MSN_PS_BLOCK_UNBLOCK; - if (user && user->networkid != MSN_NETWORK_PASSPORT) - member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, - "EmailMember", "Email", - "Email", passport, "Email"); - else - member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, - "PassportMember", "Passport", - "PassportName", passport, "PassportName"); - } - - body = g_strdup_printf(MSN_CONTACT_DELETE_FROM_LIST_TEMPLATE, - MsnSoapPartnerScenarioText[partner_scenario], - MsnMemberRole[list], member); - - state->body = xmlnode_from_str(body, -1); - state->post_action = MSN_DELETE_MEMBER_FROM_LIST_SOAP_ACTION; - state->post_url = MSN_SHARE_POST_URL; - state->cb = msn_del_contact_from_list_read_cb; - msn_contact_request(state); - - g_free(member); - g_free(body); -} - -static void -msn_add_contact_to_list_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, - gpointer data) -{ - MsnCallbackState *state = data; - xmlnode *fault; - - /* We don't know how to respond to this faultcode, so log it */ - fault = xmlnode_get_child(resp->xml, "Body/Fault"); - if (fault != NULL) { - char *fault_str = xmlnode_to_str(fault, NULL); - purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n", - msn_contact_operation_str(state->action), fault_str); - g_free(fault_str); - return; - } - - g_return_if_fail(state->session != NULL); - - purple_debug_info("msn", "Contact %s added successfully to %s list on server!\n", state->who, MsnMemberRole[state->list_id]); - - if (state->list_id == MSN_LIST_RL) { - MsnUser *user = msn_userlist_find_user(state->session->userlist, state->who); - - if (user != NULL) { - msn_user_set_op(user, MSN_LIST_RL_OP); - } - - if (state->action & MSN_DENIED_BUDDY) { - msn_add_contact_to_list(state->session, NULL, state->who, MSN_LIST_BL); - } else if (state->list_id == MSN_LIST_AL) { - purple_privacy_permit_add(state->session->account, state->who, TRUE); - } else if (state->list_id == MSN_LIST_BL) { - purple_privacy_deny_add(state->session->account, state->who, TRUE); - } - } -} - -void -msn_add_contact_to_list(MsnSession *session, MsnCallbackState *state, - const gchar *passport, const MsnListId list) -{ - gchar *body = NULL, *member = NULL; - MsnSoapPartnerScenario partner_scenario; - MsnUser *user; - - g_return_if_fail(session != NULL); - g_return_if_fail(passport != NULL); - g_return_if_fail(list < 5); - - purple_debug_info("msn", "Adding contact %s to %s list\n", passport, MsnMemberRole[list]); - - if (state == NULL) { - state = msn_callback_state_new(session); - } - msn_callback_state_set_list_id(state, list); - msn_callback_state_set_who(state, passport); - - user = msn_userlist_find_user(session->userlist, passport); - - partner_scenario = (list == MSN_LIST_RL) ? MSN_PS_CONTACT_API : MSN_PS_BLOCK_UNBLOCK; - if (user && user->networkid != MSN_NETWORK_PASSPORT) - member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, - "EmailMember", "Email", - "Email", state->who, "Email"); - else - member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, - "PassportMember", "Passport", - "PassportName", state->who, "PassportName"); - - body = g_strdup_printf(MSN_CONTACT_ADD_TO_LIST_TEMPLATE, - MsnSoapPartnerScenarioText[partner_scenario], - MsnMemberRole[list], member); - - state->body = xmlnode_from_str(body, -1); - state->post_action = MSN_ADD_MEMBER_TO_LIST_SOAP_ACTION; - state->post_url = MSN_SHARE_POST_URL; - state->cb = msn_add_contact_to_list_read_cb; - msn_contact_request(state); - - g_free(member); - g_free(body); -} - -#if 0 -static void -msn_gleams_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) -{ - purple_debug_info("msn", "Gleams read done\n"); -} - -/*get the gleams info*/ -void -msn_get_gleams(MsnSession *session) -{ - MsnSoapReq *soap_request; - - purple_debug_info("msn", "msn get gleams info...\n"); - - state = msn_callback_state_new(session); - state->body = xmlnode_from_str(MSN_GLEAMS_TEMPLATE, -1); - state->post_action = MSN_GET_GLEAMS_SOAP_ACTION; - state->post_url = MSN_ADDRESS_BOOK_POST_URL; - state->cb = msn_gleams_read_cb; - msn_contact_request(state); -} -#endif - - -/*************************************************************** - * Group Operations - ***************************************************************/ - -static void -msn_group_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) -{ - MsnCallbackState *state = data; - MsnSession *session; - MsnUserList *userlist; - xmlnode *fault; - - /* We don't know how to respond to this faultcode, so log it */ - fault = xmlnode_get_child(resp->xml, "Body/Fault"); - if (fault != NULL) { - char *fault_str = xmlnode_to_str(fault, NULL); - purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n", - msn_contact_operation_str(state->action), fault_str); - g_free(fault_str); - return; - } - - purple_debug_info("msn", "Group request successful.\n"); - - g_return_if_fail(state->session != NULL); - g_return_if_fail(state->session->userlist != NULL); - - session = state->session; - userlist = session->userlist; - - if (state->action & MSN_RENAME_GROUP) { - msn_userlist_rename_group_id(session->userlist, - state->guid, - state->new_group_name); - } - - if (state->action & MSN_ADD_GROUP) { - /* the response is taken from - http://telepathy.freedesktop.org/wiki/Pymsn/MSNP/ContactListActions - should copy it to msnpiki some day */ - xmlnode *guid_node = xmlnode_get_child(resp->xml, - "Body/ABGroupAddResponse/ABGroupAddResult/guid"); - - if (guid_node) { - char *guid = xmlnode_get_data(guid_node); - - /* create and add the new group to the userlist */ - purple_debug_info("msn", "Adding group %s with guid = %s to the userlist\n", state->new_group_name, guid); - msn_group_new(session->userlist, guid, state->new_group_name); - - if (state->action & MSN_ADD_BUDDY) { - msn_userlist_add_buddy(session->userlist, - state->who, - state->new_group_name); - } else if (state->action & MSN_MOVE_BUDDY) { - /* This will be freed when the add contact callback fires */ - MsnCallbackState *new_state = msn_callback_state_dup(state); - msn_add_contact_to_group(session, new_state, state->who, guid); - g_free(guid); - return; - } - g_free(guid); - } else { - purple_debug_info("msn", "Adding group %s failed\n", - state->new_group_name); - } - } - - if (state->action & MSN_DEL_GROUP) { - GList *l; - - msn_userlist_remove_group_id(session->userlist, state->guid); - for (l = userlist->users; l != NULL; l = l->next) { - msn_user_remove_group_id( (MsnUser *)l->data, state->guid); - } - } -} - -/* add group */ -void -msn_add_group(MsnSession *session, MsnCallbackState *state, const char* group_name) -{ - char *body = NULL; - char *escaped_group_name = NULL; - - g_return_if_fail(session != NULL); - g_return_if_fail(group_name != NULL); - - purple_debug_info("msn", "Adding group %s to contact list.\n", group_name); - - if (state == NULL) { - state = msn_callback_state_new(session); - } - - msn_callback_state_set_action(state, MSN_ADD_GROUP); - msn_callback_state_set_new_group_name(state, group_name); - - /* escape group name's html special chars so it can safely be sent - * in a XML SOAP request - */ - escaped_group_name = g_markup_escape_text(group_name, -1); - body = g_strdup_printf(MSN_GROUP_ADD_TEMPLATE, escaped_group_name); - - state->body = xmlnode_from_str(body, -1); - state->post_action = MSN_GROUP_ADD_SOAP_ACTION; - state->post_url = MSN_ADDRESS_BOOK_POST_URL; - state->cb = msn_group_read_cb; - msn_contact_request(state); - - g_free(escaped_group_name); - g_free(body); -} - -/* delete group */ -void -msn_del_group(MsnSession *session, const gchar *group_name) -{ - MsnCallbackState *state; - char *body = NULL; - const gchar *guid; - - g_return_if_fail(session != NULL); - - g_return_if_fail(group_name != NULL); - purple_debug_info("msn", "Deleting group %s from contact list\n", group_name); - - guid = msn_userlist_find_group_id(session->userlist, group_name); - - /* if group uid we need to del is NULL, - * we need to delete nothing - */ - if (guid == NULL) { - purple_debug_info("msn", "Group %s guid not found, returning.\n", group_name); - return; - } - - if ( !strcmp(guid, MSN_INDIVIDUALS_GROUP_ID) || !strcmp(guid, MSN_NON_IM_GROUP_ID) ) { - /* XXX add back PurpleGroup since it isn't really removed in the server? */ - return; - } - - state = msn_callback_state_new(session); - msn_callback_state_set_action(state, MSN_DEL_GROUP); - msn_callback_state_set_guid(state, guid); - - body = g_strdup_printf(MSN_GROUP_DEL_TEMPLATE, guid); - - state->body = xmlnode_from_str(body, -1); - state->post_action = MSN_GROUP_DEL_SOAP_ACTION; - state->post_url = MSN_ADDRESS_BOOK_POST_URL; - state->cb = msn_group_read_cb; - msn_contact_request(state); - - g_free(body); -} - -/* rename group */ -void -msn_contact_rename_group(MsnSession *session, const char *old_group_name, const char *new_group_name) -{ - gchar *body = NULL; - const gchar * guid; - MsnCallbackState *state; - char *escaped_group_name; - - g_return_if_fail(session != NULL); - g_return_if_fail(session->userlist != NULL); - g_return_if_fail(old_group_name != NULL); - g_return_if_fail(new_group_name != NULL); - - purple_debug_info("msn", "Renaming group %s to %s.\n", old_group_name, new_group_name); - - guid = msn_userlist_find_group_id(session->userlist, old_group_name); - if (guid == NULL) - return; - - state = msn_callback_state_new(session); - msn_callback_state_set_guid(state, guid); - msn_callback_state_set_new_group_name(state, new_group_name); - - if ( !strcmp(guid, MSN_INDIVIDUALS_GROUP_ID) || !strcmp(guid, MSN_NON_IM_GROUP_ID) ) { - MsnCallbackState *new_state = msn_callback_state_dup(state); - msn_add_group(session, new_state, new_group_name); - /* XXX move every buddy there (we probably need to fix concurrent SOAP reqs first) */ - } - - msn_callback_state_set_action(state, MSN_RENAME_GROUP); - - escaped_group_name = g_markup_escape_text(new_group_name, -1); - body = g_strdup_printf(MSN_GROUP_RENAME_TEMPLATE, guid, escaped_group_name); - - state->body = xmlnode_from_str(body, -1); - state->post_action = MSN_GROUP_RENAME_SOAP_ACTION; - state->post_url = MSN_ADDRESS_BOOK_POST_URL; - state->cb = msn_group_read_cb; - msn_contact_request(state); - - g_free(escaped_group_name); - g_free(body); -} - diff --git a/libpurple/protocols/msn/contact.h b/libpurple/protocols/msn/contact.h deleted file mode 100644 index fcd60d73de..0000000000 --- a/libpurple/protocols/msn/contact.h +++ /dev/null @@ -1,747 +0,0 @@ -/** - * @file contact.h Header file for contact.c - * Author - * MaYuan<mayuan2006@gmail.com> - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ -#ifndef MSN_CONTACT_H -#define MSN_CONTACT_H - -typedef struct _MsnCallbackState MsnCallbackState; - -typedef enum -{ - MSN_ADD_BUDDY = 0x01, - MSN_MOVE_BUDDY = 0x02, - MSN_ACCEPTED_BUDDY = 0x04, - MSN_DENIED_BUDDY = 0x08, - MSN_ADD_GROUP = 0x10, - MSN_DEL_GROUP = 0x20, - MSN_RENAME_GROUP = 0x40, - MSN_UPDATE_INFO = 0x80, - MSN_ANNOTATE_USER = 0x100 -} MsnCallbackAction; - -typedef enum -{ - MSN_UPDATE_DISPLAY, /* Real display name */ - MSN_UPDATE_ALIAS, /* Aliased display name */ - MSN_UPDATE_COMMENT -} MsnContactUpdateType; - -typedef enum -{ - MSN_PS_INITIAL, - MSN_PS_SAVE_CONTACT, - MSN_PS_PENDING_LIST, - MSN_PS_CONTACT_API, - MSN_PS_BLOCK_UNBLOCK, - MSN_PS_TIMER -} MsnSoapPartnerScenario; - -#include "session.h" -#include "soap.h" - -/* Thanks to TReKiE on the #pidgin channel for this new ID. */ -#define MSN_APPLICATION_ID "F6D2794D-501F-443A-ADBE-8F1490FF30FD" - -#define MSN_CONTACT_SERVER "local-bay.contacts.msn.com" - -/* Get Contact List */ - -#define MSN_GET_CONTACT_POST_URL "/abservice/SharingService.asmx" -#define MSN_GET_CONTACT_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/FindMembership" - -#define MSN_GET_CONTACT_UPDATE_XML \ - "<View>Full</View>"\ - "<deltasOnly>true</deltasOnly>"\ - "<lastChange>%s</lastChange>" - -#define MSN_GET_CONTACT_TEMPLATE "<?xml version='1.0' encoding='utf-8'?>"\ -"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ - "<soap:Header xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ - "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId xmlns=\"http://www.msn.com/webservices/AddressBook\">" MSN_APPLICATION_ID "</ApplicationId>"\ - "<IsMigration xmlns=\"http://www.msn.com/webservices/AddressBook\">false</IsMigration>"\ - "<PartnerScenario xmlns=\"http://www.msn.com/webservices/AddressBook\">%s</PartnerScenario>"\ - "</ABApplicationHeader>"\ - "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ManagedGroupRequest xmlns=\"http://www.msn.com/webservices/AddressBook\">false</ManagedGroupRequest>"\ - "<TicketToken>EMPTY</TicketToken>"\ - "</ABAuthHeader>"\ - "</soap:Header>"\ - "<soap:Body xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ - "<FindMembership xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<serviceFilter xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<Types xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Messenger</ServiceType>"\ - "<ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Invitation</ServiceType>"\ - "<ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">SocialNetwork</ServiceType>"\ - "<ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Space</ServiceType>"\ - "<ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Profile</ServiceType>"\ - "</Types>"\ - "</serviceFilter>"\ - "%s"\ - "</FindMembership>"\ - "</soap:Body>"\ -"</soap:Envelope>" - -/************************************************ - * Address Book SOAP - * *********************************************/ - -#define MSN_ADDRESS_BOOK_POST_URL "/abservice/abservice.asmx" - -/* Create AddressBook template */ -#define MSN_ADD_ADDRESSBOOK_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABAdd" - -#define MSN_ADD_ADDRESSBOOK_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope"\ - " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ - " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ - " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ - " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ - "<soap:Header>"\ - "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ - "<IsMigration>false</IsMigration>"\ - "<PartnerScenario>Initial</PartnerScenario>"\ - "</ABApplicationHeader>"\ - "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ManagedGroupRequest>false</ManagedGroupRequest>"\ - "<TicketToken>EMPTY</TicketToken>"\ - "</ABAuthHeader>"\ - "</soap:Header>"\ - "<soap:Body>"\ - "<ABAdd xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<abInfo>"\ - "<name/>"\ - "<ownerPuid>0</ownerPuid>"\ - "<ownerEmail>%s</ownerEmail>"\ - "<fDefault>true</fDefault>"\ - "</abInfo>"\ - "</ABAdd>"\ - "</soap:Body>"\ -"</soap:Envelope>" - -/* Get AddressBook */ -#define MSN_GET_ADDRESS_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABFindContactsPaged" -#define MSN_GET_ADDRESS_FULL_TIME "0001-01-01T00:00:00.0000000-08:00" -#define MSN_GET_ADDRESS_UPDATE_XML \ - "<filterOptions>"\ - "<deltasOnly>true</deltasOnly>"\ - "<lastChange>%s</lastChange>"\ - "</filterOptions>" - -#define MSN_GET_GLEAM_UPDATE_XML \ - "%s"\ - "<dynamicItemView>Gleam</dynamicItemView>"\ - "<dynamicItemLastChange>%s</dynamicItemLastChange>" - -#define MSN_GET_ADDRESS_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope"\ - " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ - " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ - " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ - " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ - "<soap:Header>"\ - "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ - "<IsMigration>false</IsMigration>"\ - "<PartnerScenario>%s</PartnerScenario>"\ - "</ABApplicationHeader>"\ - "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ManagedGroupRequest>false</ManagedGroupRequest>"\ - "<TicketToken>EMPTY</TicketToken>"\ - "</ABAuthHeader>"\ - "</soap:Header>"\ - "<soap:Body>"\ - "<ABFindContactsPaged xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<abView>Full</abView>"\ - "<extendedContent>AB AllGroups CircleResult</extendedContent>"\ - "%s"\ - "</ABFindContactsPaged>"\ - "</soap:Body>"\ -"</soap:Envelope>" - - -/*Gleams SOAP request template*/ -#define MSN_GET_GLEAMS_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABFindAll" -#define MSN_GLEAMS_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope"\ - " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ - " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ - " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ - " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ - "<soap:Header>"\ - "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ - "<IsMigration>false</IsMigration>"\ - "<PartnerScenario>Initial</PartnerScenario>"\ - "</ABApplicationHeader>"\ - "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ManagedGroupRequest>false</ManagedGroupRequest>"\ - "<TicketToken>EMPTY</TicketToken>"\ - "</ABAuthHeader>"\ - "</soap:Header>"\ - "<soap:Body>"\ - "<ABFindAll xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<abId>00000000-0000-0000-0000-000000000000</abId>"\ - "<abView>Full</abView>"\ - "<dynamicItemView>Gleam</dynamicItemView>"\ - "<dynamicItemLastChange>0001-01-01T00:00:00.0000000-08:00</dynamicItemLastChange>"\ - "</ABFindAll>"\ - "</soap:Body>"\ -"</soap:Envelope>" - - -/******************************************************* - * Contact Management SOAP actions - *******************************************************/ - -/* Add a new contact */ -#define MSN_CONTACT_ADD_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABContactAdd" -#define MSN_CONTACT_LIVE_PENDING_XML \ - "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<contactInfo>"\ - "<contactType>LivePending</contactType>"\ - "<passportName>%s</passportName>"\ - "<isMessengerUser>true</isMessengerUser>"\ - "</contactInfo>"\ - "</Contact>" - -#define MSN_CONTACT_XML \ - "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<contactInfo>"\ - "<passportName>%s</passportName>"\ - "<isSmtp>false</isSmtp>"\ - "<isMessengerUser>true</isMessengerUser>"\ - "</contactInfo>"\ - "</Contact>" - -#define MSN_CONTACT_DISPLAYNAME_XML \ - "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<contactInfo>"\ - "<displayName>%s</displayName>"\ - "<passportName>%s</passportName>"\ - "<isMessengerUser>true</isMessengerUser>"\ - "</contactInfo>"\ - "</Contact>" - -#define MSN_CONTACT_ID_XML \ - "<Contact>"\ - "<contactId>%s</contactId>"\ - "</Contact>" - -#define MSN_CONTACT_EMAIL_XML \ - "<Contact>"\ - "<contactInfo>"\ - "<emails>"\ - "<ContactEmail>"\ - "<contactEmailType>%s</contactEmailType>"\ - "<email>%s</email>"\ - "<isMessengerEnabled>true</isMessengerEnabled>"\ - "<Capability>%d</Capability>"\ - "<MessengerEnabledExternally>false</MessengerEnabledExternally>"\ - "<propertiesChanged/>"\ - "</ContactEmail>"\ - "</emails>"\ - "</contactInfo>"\ - "</Contact>" - -#define MSN_CONTACT_INVITE_MESSAGE_XML \ - "<MessengerMemberInfo>"\ - "<PendingAnnotations>"\ - "<Annotation>"\ - "<Name>MSN.IM.InviteMessage</Name>"\ - "<Value>%s</Value>"\ - "</Annotation>"\ - "</PendingAnnotations>"\ - "<DisplayName>%s</DisplayName>"\ - "</MessengerMemberInfo>" - -#define MSN_ADD_CONTACT_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ - " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ - " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ - " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ - "<soap:Header>"\ - "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ - "<IsMigration>false</IsMigration>"\ - "<PartnerScenario>ContactSave</PartnerScenario>"\ - "</ABApplicationHeader>"\ - "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ManagedGroupRequest>false</ManagedGroupRequest>"\ - "<TicketToken>EMPTY</TicketToken>"\ - "</ABAuthHeader>"\ - "</soap:Header>"\ - "<soap:Body>"\ - "<ABContactAdd xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<abId>00000000-0000-0000-0000-000000000000</abId>"\ - "<contacts>%s</contacts>"\ - "<options>"\ - "<EnableAllowListManagement>true</EnableAllowListManagement>"\ - "</options>"\ - "</ABContactAdd>"\ - "</soap:Body>"\ -"</soap:Envelope>" - -/* Add a contact to a group */ -#define MSN_ADD_CONTACT_GROUP_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABGroupContactAdd" -#define MSN_ADD_CONTACT_GROUP_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ - " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ - " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ - " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ - "<soap:Header>"\ - "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ - "<IsMigration>false</IsMigration>"\ - "<PartnerScenario>ContactSave</PartnerScenario>"\ - "</ABApplicationHeader>"\ - "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ManagedGroupRequest>false</ManagedGroupRequest>"\ - "<TicketToken>EMPTY</TicketToken>"\ - "</ABAuthHeader>"\ - "</soap:Header>"\ - "<soap:Body>"\ - "<ABGroupContactAdd xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<abId>00000000-0000-0000-0000-000000000000</abId>"\ - "<groupFilter>"\ - "<groupIds>"\ - "<guid>%s</guid>"\ - "</groupIds>"\ - "</groupFilter>"\ - "<contacts>%s</contacts>"\ - "<groupContactAddOptions>"\ - "<fGenerateMissingQuickName>true</fGenerateMissingQuickName>"\ - "<EnableAllowListManagement>true</EnableAllowListManagement>"\ - "</groupContactAddOptions>"\ - "%s"\ - "</ABGroupContactAdd>"\ - "</soap:Body>"\ -"</soap:Envelope>" - -/* Delete a contact from the Contact List */ -#define MSN_CONTACT_DEL_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABContactDelete" -#define MSN_DEL_CONTACT_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope"\ - " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ - " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ - " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ - " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ - "<soap:Header>"\ - "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ - "<IsMigration>false</IsMigration>"\ - "<PartnerScenario>Timer</PartnerScenario>"\ - "</ABApplicationHeader>"\ - "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ManagedGroupRequest>false</ManagedGroupRequest>"\ - "<TicketToken>EMPTY</TicketToken>"\ - "</ABAuthHeader>"\ - "</soap:Header>"\ - "<soap:Body>"\ - "<ABContactDelete xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<abId>00000000-0000-0000-0000-000000000000</abId>"\ - "<contacts>%s</contacts>"\ - "</ABContactDelete>"\ - "</soap:Body>"\ -"</soap:Envelope>" - -/* Remove a contact from a group */ -#define MSN_CONTACT_DEL_GROUP_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABGroupContactDelete" -#define MSN_CONTACT_DEL_GROUP_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope"\ - " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ - " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ - " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ - " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ - "<soap:Header>"\ - "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ - "<IsMigration>false</IsMigration>"\ - "<PartnerScenario>Timer</PartnerScenario>"\ - "</ABApplicationHeader>"\ - "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ManagedGroupRequest>false</ManagedGroupRequest>"\ - "<TicketToken>EMPTY</TicketToken>"\ - "</ABAuthHeader>"\ - "</soap:Header>"\ - "<soap:Body>"\ - "<ABGroupContactDelete xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<abId>00000000-0000-0000-0000-000000000000</abId>"\ - "<contacts>%s</contacts>"\ - "<groupFilter>"\ - "<groupIds>"\ - "<guid>%s</guid>"\ - "</groupIds>"\ - "</groupFilter>"\ - "</ABGroupContactDelete>"\ - "</soap:Body>"\ -"</soap:Envelope>" - - -/* Update Contact Information */ -#define MSN_CONTACT_UPDATE_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABContactUpdate" -#define MSN_CONTACT_UPDATE_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope"\ - " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ - " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ - " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ - " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ - "<soap:Header>"\ - "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ - "<IsMigration>false</IsMigration>"\ - "<PartnerScenario></PartnerScenario>"\ - "</ABApplicationHeader>"\ - "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ManagedGroupRequest>false</ManagedGroupRequest>"\ - "<TicketToken>EMPTY</TicketToken>"\ - "</ABAuthHeader>"\ - "</soap:Header>"\ - "<soap:Body>"\ - "<ABContactUpdate xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<abId>00000000-0000-0000-0000-000000000000</abId>"\ - "<contacts>"\ - "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - ""\ - "</Contact>"\ - "</contacts>"\ - "</ABContactUpdate>"\ - "</soap:Body>"\ -"</soap:Envelope>" - -/* Update Contact Annotations */ -#define MSN_CONTACT_ANNOTATE_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABContactUpdate" -#define MSN_CONTACT_ANNOTATE_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope"\ - " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ - " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ - " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ - " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ - "<soap:Header>"\ - "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ - "<IsMigration>false</IsMigration>"\ - "<PartnerScenario></PartnerScenario>"\ - "</ABApplicationHeader>"\ - "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ManagedGroupRequest>false</ManagedGroupRequest>"\ - "<TicketToken>EMPTY</TicketToken>"\ - "</ABAuthHeader>"\ - "</soap:Header>"\ - "<soap:Body>"\ - "<ABContactUpdate xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<abId>00000000-0000-0000-0000-000000000000</abId>"\ - "<contacts>"\ - "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<propertiesChanged>Annotation</propertiesChanged>"\ - "</Contact>"\ - "</contacts>"\ - "</ABContactUpdate>"\ - "</soap:Body>"\ -"</soap:Envelope>" - -/******************************************************* - * Add/Delete contact from lists SOAP actions - *******************************************************/ - -/* block means delete from allow list and add contact to block list */ -#define MSN_SHARE_POST_URL "/abservice/SharingService.asmx" - -#define MSN_ADD_MEMBER_TO_LIST_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/AddMember" -#define MSN_DELETE_MEMBER_FROM_LIST_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/DeleteMember" - -#define MSN_MEMBER_PASSPORT_XML \ - "<Member xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"%s\">"\ - "<Type>%s</Type>"\ - "<State>Accepted</State>"\ - "<%s>%s</%s>"\ - "</Member>" - -#define MSN_MEMBER_MEMBERSHIPID_XML \ - "<Member xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"%s\">"\ - "<Type>%s</Type>"\ - "<MembershipId>%u</MembershipId>"\ - "<State>Accepted</State>"\ - "</Member>" - -/* first delete contact from allow list */ - -#define MSN_CONTACT_DELETE_FROM_LIST_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope"\ - " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ - " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ - " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ - " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ - "<soap:Header>"\ - "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ - "<IsMigration>false</IsMigration>"\ - "<PartnerScenario>%s</PartnerScenario>"\ - "</ABApplicationHeader>"\ - "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ManagedGroupRequest>false</ManagedGroupRequest>"\ - "<TicketToken>EMPTY</TicketToken>"\ - "</ABAuthHeader>"\ - "</soap:Header>"\ - "<soap:Body>"\ - "<DeleteMember xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<serviceHandle>"\ - "<Id>0</Id>"\ - "<Type>Messenger</Type>"\ - "<ForeignId></ForeignId>"\ - "</serviceHandle>"\ - "<memberships>"\ - "<Membership>"\ - "<MemberRole>%s</MemberRole>"\ - "<Members>"\ - "%s"\ - "</Members>"\ - "</Membership>"\ - "</memberships>"\ - "</DeleteMember>"\ - "</soap:Body>"\ -"</soap:Envelope>" - -#define MSN_CONTACT_ADD_TO_LIST_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope"\ - " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ - " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ - " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ - " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ - "<soap:Header>"\ - "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ - "<IsMigration>false</IsMigration>"\ - "<PartnerScenario>%s</PartnerScenario>"\ - "</ABApplicationHeader>"\ - "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ManagedGroupRequest>false</ManagedGroupRequest>"\ - "<TicketToken>EMPTY</TicketToken>"\ - "</ABAuthHeader>"\ - "</soap:Header>"\ - "<soap:Body>"\ - "<AddMember xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<serviceHandle>"\ - "<Id>0</Id>"\ - "<Type>Messenger</Type>"\ - "<ForeignId></ForeignId>"\ - "</serviceHandle>"\ - "<memberships>"\ - "<Membership>"\ - "<MemberRole>%s</MemberRole>"\ - "<Members>"\ - "%s"\ - "</Members>"\ - "</Membership>"\ - "</memberships>"\ - "</AddMember>"\ - "</soap:Body>"\ -"</soap:Envelope>" - - - -/******************************************************* - * Group management SOAP actions - *******************************************************/ - -/* add a group */ -#define MSN_GROUP_ADD_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABGroupAdd" -#define MSN_GROUP_ADD_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope"\ - " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ - " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ - " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ - " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ - "<soap:Header>"\ - "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ - "<IsMigration>false</IsMigration>"\ - "<PartnerScenario>GroupSave</PartnerScenario>"\ - "</ABApplicationHeader>"\ - "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ManagedGroupRequest>false</ManagedGroupRequest>"\ - "<TicketToken>EMPTY</TicketToken>"\ - "</ABAuthHeader>"\ - "</soap:Header>"\ - "<soap:Body>"\ - "<ABGroupAdd xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<abId>00000000-0000-0000-0000-000000000000</abId>"\ - "<groupAddOptions>"\ - "<fRenameOnMsgrConflict>false</fRenameOnMsgrConflict>"\ - "</groupAddOptions>"\ - "<groupInfo>"\ - "<GroupInfo>"\ - "<name>%s</name>"\ - "<groupType>C8529CE2-6EAD-434d-881F-341E17DB3FF8</groupType>"\ - "<fMessenger>false</fMessenger>"\ - "<annotations>"\ - "<Annotation>"\ - "<Name>MSN.IM.Display</Name>"\ - "<Value>1</Value>"\ - "</Annotation>"\ - "</annotations>"\ - "</GroupInfo>"\ - "</groupInfo>"\ - "</ABGroupAdd>"\ - "</soap:Body>"\ -"</soap:Envelope>" - -/* delete a group */ -#define MSN_GROUP_DEL_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABGroupDelete" -#define MSN_GROUP_DEL_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope"\ - " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ - " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ - " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ - " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ - "<soap:Header>"\ - "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ - "<IsMigration>false</IsMigration>"\ - "<PartnerScenario>Timer</PartnerScenario>"\ - "</ABApplicationHeader>"\ - "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ManagedGroupRequest>false</ManagedGroupRequest>"\ - "<TicketToken>EMPTY</TicketToken>"\ - "</ABAuthHeader>"\ - "</soap:Header>"\ - "<soap:Body>"\ - "<ABGroupDelete xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<abId>00000000-0000-0000-0000-000000000000</abId>"\ - "<groupFilter>"\ - "<groupIds>"\ - "<guid>%s</guid>"\ - "</groupIds>"\ - "</groupFilter>"\ - "</ABGroupDelete>"\ - "</soap:Body>"\ -"</soap:Envelope>" - -/* change a group's name */ -#define MSN_GROUP_RENAME_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABGroupUpdate" -#define MSN_GROUP_RENAME_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope"\ - " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ - " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ - " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ - " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ - "<soap:Header>"\ - "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ - "<IsMigration>false</IsMigration>"\ - "<PartnerScenario>Timer</PartnerScenario>"\ - "</ABApplicationHeader>"\ - "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ManagedGroupRequest>false</ManagedGroupRequest>"\ - "<TicketToken>EMPTY</TicketToken>"\ - "</ABAuthHeader>"\ - "</soap:Header>"\ - "<soap:Body>"\ - "<ABGroupUpdate xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<abId>00000000-0000-0000-0000-000000000000</abId>"\ - "<groups>"\ - "<Group>"\ - "<groupId>%s</groupId>"\ - "<groupInfo>"\ - "<name>%s</name>"\ - "</groupInfo>"\ - "<propertiesChanged>GroupName </propertiesChanged>"\ - "</Group>"\ - "</groups>"\ - "</ABGroupUpdate>"\ - "</soap:Body>"\ -"</soap:Envelope>" - -struct _MsnCallbackState -{ - gchar * who; - gchar * uid; - gchar * old_group_name; - gchar * new_group_name; - gchar * guid; - MsnListId list_id; - MsnCallbackAction action; - MsnSession *session; - xmlnode *body; - xmlnode *token; - const gchar *post_action; - const gchar *post_url; - MsnSoapCallback cb; - /* For msn_get_contact_list only */ - MsnSoapPartnerScenario partner_scenario; -}; - -/************************************************ - * function prototype - ************************************************/ -MsnCallbackState * msn_callback_state_new(MsnSession *session); -MsnCallbackState * msn_callback_state_dup(MsnCallbackState *state); -void msn_callback_state_free(MsnCallbackState *state); -void msn_callback_state_set_who(MsnCallbackState *state, const gchar *who); -void msn_callback_state_set_uid(MsnCallbackState *state, const gchar *uid); -void msn_callback_state_set_old_group_name(MsnCallbackState *state, - const gchar *old_group_name); -void msn_callback_state_set_new_group_name(MsnCallbackState *state, - const gchar *new_group_name); -void msn_callback_state_set_guid(MsnCallbackState *state, const gchar *guid); -void msn_callback_state_set_list_id(MsnCallbackState *state, MsnListId list_id); -void msn_callback_state_set_action(MsnCallbackState *state, - MsnCallbackAction action); - -void msn_get_contact_list(MsnSession *session, - const MsnSoapPartnerScenario partner_scenario, - const char *update); -void msn_get_address_book(MsnSession *session, - const MsnSoapPartnerScenario partner_scenario, - const char * update, const char * gupdate); - -/* contact SOAP operations */ -void msn_update_contact(MsnSession *session, const char *passport, MsnContactUpdateType type, const char* value); - -void msn_annotate_contact(MsnSession *session, const char *passport, ...) G_GNUC_NULL_TERMINATED; - -void msn_add_contact(MsnSession *session, MsnCallbackState *state, - const char *passport); -void msn_delete_contact(MsnSession *session, MsnUser *user); - -void msn_add_contact_to_group(MsnSession *session, MsnCallbackState *state, - const char *passport, const char *groupId); -void msn_del_contact_from_group(MsnSession *session, const char *passport, - const char *group_name); -/* group operations */ -void msn_add_group(MsnSession *session, MsnCallbackState *state, - const char* group_name); -void msn_del_group(MsnSession *session, const gchar *group_name); -void msn_contact_rename_group(MsnSession *session, const char *old_group_name, - const char *new_group_name); - -/* lists operations */ -void msn_add_contact_to_list(MsnSession *session, MsnCallbackState *state, - const gchar *passport, const MsnListId list); -void msn_del_contact_from_list(MsnSession *session, MsnCallbackState *state, - const gchar *passport, const MsnListId list); - -#endif /* MSN_CONTACT_H */ diff --git a/libpurple/protocols/msn/directconn.c b/libpurple/protocols/msn/directconn.c deleted file mode 100644 index cbffb9fffe..0000000000 --- a/libpurple/protocols/msn/directconn.c +++ /dev/null @@ -1,958 +0,0 @@ -/** - * @file directconn.c MSN direct connection functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "cipher.h" -#include "debug.h" - -#include "msn.h" -#include "msnutils.h" -#include "directconn.h" - -#include "slp.h" -#include "slpmsg.h" -#include "p2p.h" - -#define DC_MAX_BODY_SIZE 8*1024 -#define DC_MAX_PACKET_SIZE (P2P_PACKET_HEADER_SIZE + DC_MAX_BODY_SIZE) - -static void -msn_dc_calculate_nonce_hash(MsnDirectConnNonceType type, - const guchar *nonce, gsize nonce_len, gchar nonce_hash[37]) -{ - guchar digest[20]; - - if (type == DC_NONCE_SHA1) { - PurpleCipher *cipher = purple_ciphers_find_cipher("sha1"); - PurpleCipherContext *context = purple_cipher_context_new(cipher, NULL); - purple_cipher_context_append(context, nonce, nonce_len); - purple_cipher_context_digest(context, sizeof(digest), digest, NULL); - purple_cipher_context_destroy(context); - } else if (type == DC_NONCE_PLAIN) { - memcpy(digest, nonce, nonce_len); - } else { - nonce_hash[0] = '\0'; - g_return_if_reached(); - } - - g_sprintf(nonce_hash, - "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", - - digest[3], - digest[2], - digest[1], - digest[0], - - digest[5], - digest[4], - - digest[7], - digest[6], - - digest[8], - digest[9], - - digest[10], - digest[11], - digest[12], - digest[13], - digest[14], - digest[15] - ); -} - -static void -msn_dc_generate_nonce(MsnDirectConn *dc) -{ - guint32 *nonce; - int i; - - nonce = (guint32 *)&dc->nonce; - for (i = 0; i < 4; i++) - nonce[i] = rand(); - - msn_dc_calculate_nonce_hash(dc->nonce_type, dc->nonce, sizeof(dc->nonce), dc->nonce_hash); - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "DC %p generated nonce %s\n", dc, dc->nonce_hash); -} - -static MsnDirectConnPacket * -msn_dc_new_packet(guint32 length) -{ - MsnDirectConnPacket *p; - - p = g_new0(MsnDirectConnPacket, 1); - p->length = length; - p->data = g_malloc(length); - - return p; -} - -static void -msn_dc_destroy_packet(MsnDirectConnPacket *p) -{ - g_free(p->data); - - if (p->part) - msn_slpmsgpart_unref(p->part); - - g_free(p); -} - -MsnDirectConn * -msn_dc_new(MsnSlpCall *slpcall) -{ - MsnDirectConn *dc; - - g_return_val_if_fail(slpcall != NULL, NULL); - - dc = g_new0(MsnDirectConn, 1); - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "msn_dc_new %p\n", dc); - - dc->slplink = slpcall->slplink; - dc->slpcall = slpcall; - - if (dc->slplink->dc != NULL) - purple_debug_warning("msn", "msn_dc_new: slplink already has an allocated DC!\n"); - - dc->slplink->dc = dc; - - dc->msg_body = NULL; - dc->prev_ack = NULL; - dc->listen_data = NULL; - dc->connect_data = NULL; - dc->listenfd = -1; - dc->listenfd_handle = 0; - dc->connect_timeout_handle = 0; - dc->fd = -1; - dc->recv_handle = 0; - dc->send_handle = 0; - dc->state = DC_STATE_CLOSED; - dc->in_buffer = NULL; - dc->out_queue = g_queue_new(); - dc->msg_pos = -1; - dc->send_connection_info_msg_cb = NULL; - dc->ext_ip = NULL; - dc->timeout_handle = 0; - dc->progress = FALSE; - /*dc->num_calls = 1;*/ - - /* TODO: Probably should set this based on buddy caps */ - dc->nonce_type = DC_NONCE_PLAIN; - msn_dc_generate_nonce(dc); - - return dc; -} - -void -msn_dc_destroy(MsnDirectConn *dc) -{ - MsnSlpLink *slplink; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "msn_dc_destroy %p\n", dc); - - g_return_if_fail(dc != NULL); - - if (dc->slpcall != NULL) - dc->slpcall->wait_for_socket = FALSE; - - slplink = dc->slplink; - if (slplink) { - slplink->dc = NULL; - if (slplink->swboard == NULL) - msn_slplink_unref(slplink); - } - - g_free(dc->msg_body); - - if (dc->prev_ack) { - msn_slpmsg_destroy(dc->prev_ack); - } - - if (dc->listen_data != NULL) { - purple_network_listen_cancel(dc->listen_data); - } - - if (dc->connect_data != NULL) { - purple_proxy_connect_cancel(dc->connect_data); - } - - if (dc->listenfd != -1) { - purple_network_remove_port_mapping(dc->listenfd); - close(dc->listenfd); - } - - if (dc->listenfd_handle != 0) { - purple_input_remove(dc->listenfd_handle); - } - - if (dc->connect_timeout_handle != 0) { - purple_timeout_remove(dc->connect_timeout_handle); - } - - if (dc->fd != -1) { - close(dc->fd); - } - - if (dc->send_handle != 0) { - purple_input_remove(dc->send_handle); - } - - if (dc->recv_handle != 0) { - purple_input_remove(dc->recv_handle); - } - - g_free(dc->in_buffer); - - if (dc->out_queue != NULL) { - while (!g_queue_is_empty(dc->out_queue)) - msn_dc_destroy_packet( g_queue_pop_head(dc->out_queue) ); - - g_queue_free(dc->out_queue); - } - - g_free(dc->ext_ip); - - if (dc->timeout_handle != 0) { - purple_timeout_remove(dc->timeout_handle); - } - - g_free(dc); -} - -/* -void -msn_dc_ref(MsnDirectConn *dc) -{ - g_return_if_fail(dc != NULL); - - dc->num_calls++; -} - -void -msn_dc_unref(MsnDirectConn *dc) -{ - g_return_if_fail(dc != NULL); - - - if (dc->num_calls > 0) { - dc->num_calls--; - } -} -*/ - -void -msn_dc_send_invite(MsnDirectConn *dc) -{ - MsnSlpCall *slpcall; - MsnSlpMessage *msg; - gchar *header; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "msn_dc_send_invite %p\n", dc); - - g_return_if_fail(dc != NULL); - - slpcall = dc->slpcall; - g_return_if_fail(slpcall != NULL); - - header = g_strdup_printf( - "INVITE MSNMSGR:%s MSNSLP/1.0", - slpcall->slplink->remote_user - ); - - msg = msn_slpmsg_sip_new( - slpcall, - 0, - header, - slpcall->branch, - "application/x-msnmsgr-transrespbody", - dc->msg_body - ); - msg->info = "DC INVITE"; - msg->text_body = TRUE; - g_free(header); - g_free(dc->msg_body); - dc->msg_body = NULL; - - msn_slplink_queue_slpmsg(slpcall->slplink, msg); -} - -void -msn_dc_send_ok(MsnDirectConn *dc) -{ - if (purple_debug_is_verbose()) - purple_debug_info("msn", "msn_dc_send_ok %p\n", dc); - - g_return_if_fail(dc != NULL); - - msn_slp_send_ok(dc->slpcall, dc->slpcall->branch, - "application/x-msnmsgr-transrespbody", dc->msg_body); - g_free(dc->msg_body); - dc->msg_body = NULL; - - msn_slplink_send_slpmsg(dc->slpcall->slplink, dc->prev_ack); - msn_slpmsg_destroy(dc->prev_ack); - dc->prev_ack = NULL; - msn_slplink_send_queued_slpmsgs(dc->slpcall->slplink); -} - -void -msn_dc_fallback_to_sb(MsnDirectConn *dc) -{ - MsnSlpLink *slplink; - MsnSlpCall *slpcall; - GQueue *queue = NULL; - - purple_debug_info("msn", "msn_dc_fallback_to_sb %p\n", dc); - - g_return_if_fail(dc != NULL); - - slpcall = dc->slpcall; - slplink = msn_slplink_ref(dc->slplink); - if (slpcall && !g_queue_is_empty(dc->out_queue)) { - queue = dc->out_queue; - dc->out_queue = NULL; - } - - msn_dc_destroy(dc); - - if (slpcall) { - msn_slpcall_session_init(slpcall); - if (queue) { - while (!g_queue_is_empty(queue)) { - MsnDirectConnPacket *p = g_queue_pop_head(queue); - msn_slplink_send_msgpart(slplink, (MsnSlpMessage*)p->part->ack_data); - msn_dc_destroy_packet(p); - } - g_queue_free(queue); - } - } - msn_slplink_unref(slplink); -} - -static void -msn_dc_send_cb(gpointer data, gint fd, PurpleInputCondition cond) -{ - MsnDirectConn *dc = data; - MsnDirectConnPacket *p; - int bytes_to_send; - int bytes_sent; - - g_return_if_fail(dc != NULL); - g_return_if_fail(fd != -1); - - if (g_queue_is_empty(dc->out_queue)) { - if (dc->send_handle != 0) { - purple_input_remove(dc->send_handle); - dc->send_handle = 0; - } - return; - } - - p = g_queue_peek_head(dc->out_queue); - - if (dc->msg_pos < 0) { - /* First we send the length of the packet */ - guint32 len = GUINT32_TO_LE(p->length); - bytes_sent = send(fd, &len, 4, 0); - if (bytes_sent < 0) { - if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) - return; - - purple_debug_warning("msn", "msn_dc_send_cb: send error\n"); - msn_dc_destroy(dc); - return; - } - dc->msg_pos = 0; - } - - bytes_to_send = p->length - dc->msg_pos; - bytes_sent = send(fd, p->data + dc->msg_pos, bytes_to_send, 0); - if (bytes_sent < 0) { - if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) - return; - - purple_debug_warning("msn", "msn_dc_send_cb: send error\n"); - msn_dc_destroy(dc); - return; - } - - dc->progress = TRUE; - - dc->msg_pos += bytes_sent; - if ((guint32)dc->msg_pos == p->length) { - if (p->sent_cb != NULL) - p->sent_cb(p); - - g_queue_pop_head(dc->out_queue); - msn_dc_destroy_packet(p); - - dc->msg_pos = -1; - } -} - -static void -msn_dc_enqueue_packet(MsnDirectConn *dc, MsnDirectConnPacket *p) -{ - gboolean was_empty; - - was_empty = g_queue_is_empty(dc->out_queue); - g_queue_push_tail(dc->out_queue, p); - - if (was_empty && dc->send_handle == 0) { - dc->send_handle = purple_input_add(dc->fd, PURPLE_INPUT_WRITE, msn_dc_send_cb, dc); - msn_dc_send_cb(dc, dc->fd, PURPLE_INPUT_WRITE); - } -} - -static void -msn_dc_send_foo(MsnDirectConn *dc) -{ - MsnDirectConnPacket *p; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "msn_dc_send_foo %p\n", dc); - - p = msn_dc_new_packet(4); - - memcpy(p->data, "foo\0", 4); - - msn_dc_enqueue_packet(dc, p); -} - -#if 0 /* We don't actually need this */ -typedef struct { - guint32 null; - guint32 id; - guint32 null[5]; - guint32 flags; - guint8 nonce[16]; -} MsnDirectConnNoncePacket; -#endif -#define DC_NONCE_PACKET_SIZE (8 * 4 + 16) -#define DC_NONCE_PACKET_NONCE (8 * 4) - -static void -msn_dc_send_handshake(MsnDirectConn *dc) -{ - MsnDirectConnPacket *p; - gchar *h; - - p = msn_dc_new_packet(DC_NONCE_PACKET_SIZE); - h = (gchar *)p->data; - - msn_push32le(h, 0); /* NUL */ - - msn_push32le(h, dc->slpcall->slplink->slp_seq_id++); - - /* More NUL stuff */ - msn_push64le(h, 0); - msn_push64le(h, 0); - msn_push32le(h, 0); - - /* Flags */ - msn_push32le(h, P2P_DC_HANDSHAKE); - - /* The real Nonce, yay! */ - memcpy(h, dc->nonce, 16); - - msn_dc_enqueue_packet(dc, p); -} - -static gboolean -msn_dc_verify_handshake(MsnDirectConn *dc, guint32 packet_length) -{ - guchar nonce[16]; - gchar nonce_hash[37]; - - if (packet_length != DC_NONCE_PACKET_SIZE) - return FALSE; - - memcpy(nonce, dc->in_buffer + 4 + DC_NONCE_PACKET_NONCE, sizeof(nonce)); - - if (dc->nonce_type == DC_NONCE_PLAIN) { - if (memcmp(dc->nonce, nonce, sizeof(nonce)) == 0) { - purple_debug_info("msn", - "Nonce from buddy request and nonce from DC attempt match, " - "allowing direct connection\n"); - return TRUE; - } else { - purple_debug_warning("msn", - "Nonce from buddy request and nonce from DC attempt " - "don't match, ignoring direct connection\n"); - return FALSE; - } - - } else if (dc->nonce_type == DC_NONCE_SHA1) { - msn_dc_calculate_nonce_hash(dc->nonce_type, nonce, sizeof(nonce), nonce_hash); - - if (g_str_equal(dc->remote_nonce, nonce_hash)) { - purple_debug_info("msn", - "Received nonce %s from buddy request " - "and calculated nonce %s from DC attempt. " - "Nonces match, allowing direct connection\n", - dc->remote_nonce, nonce_hash); - return TRUE; - } else { - purple_debug_warning("msn", - "Received nonce %s from buddy request " - "and calculated nonce %s from DC attempt. " - "Nonces don't match, ignoring direct connection\n", - dc->remote_nonce, nonce_hash); - return FALSE; - } - } else - return FALSE; -} - -static void -msn_dc_send_packet_cb(MsnDirectConnPacket *p) -{ - if (p->part != NULL && p->part->ack_cb != NULL) - p->part->ack_cb(p->part, p->part->ack_data); -} - -void -msn_dc_enqueue_part(MsnDirectConn *dc, MsnSlpMessagePart *part) -{ - MsnDirectConnPacket *p; - size_t length; - - p = msn_dc_new_packet(0); - p->data = (guchar *)msn_slpmsgpart_serialize(part, &length); - p->length = length - P2P_PACKET_FOOTER_SIZE; /* DC doesn't need footer? */ - - p->sent_cb = msn_dc_send_packet_cb; - p->part = msn_slpmsgpart_ref(part); - - msn_dc_enqueue_packet(dc, p); -} - -static int -msn_dc_process_packet(MsnDirectConn *dc, guint32 packet_length) -{ - MsnSlpMessagePart *part; - - g_return_val_if_fail(dc != NULL, DC_PROCESS_ERROR); - - switch (dc->state) { - case DC_STATE_CLOSED: - break; - - case DC_STATE_FOO: - /* FOO message is always 4 bytes long */ - if (packet_length != 4 || memcmp(dc->in_buffer, "\4\0\0\0foo", 8) != 0) - return DC_PROCESS_FALLBACK; - - dc->state = DC_STATE_HANDSHAKE; - break; - - case DC_STATE_HANDSHAKE: - if (!msn_dc_verify_handshake(dc, packet_length)) - return DC_PROCESS_FALLBACK; - - msn_dc_send_handshake(dc); - dc->state = DC_STATE_ESTABLISHED; - - msn_slpcall_session_init(dc->slpcall); - dc->slpcall = NULL; - break; - - case DC_STATE_HANDSHAKE_REPLY: - if (!msn_dc_verify_handshake(dc, packet_length)) - return DC_PROCESS_FALLBACK; - - dc->state = DC_STATE_ESTABLISHED; - - msn_slpcall_session_init(dc->slpcall); - dc->slpcall = NULL; - break; - - case DC_STATE_ESTABLISHED: - if (packet_length) { - MsnP2PVersion p2p; - p2p = msn_slplink_get_p2p_version(dc->slplink); - part = msn_slpmsgpart_new_from_data(p2p, dc->in_buffer + 4, packet_length); - if (part) { - msn_slplink_process_msg(dc->slplink, part); - msn_slpmsgpart_unref(part); - } - } - - /* - if (dc->num_calls == 0) { - msn_dc_destroy(dc); - - return DC_PROCESS_CLOSE; - } - */ - break; - } - - return DC_PROCESS_OK; -} - -static void -msn_dc_recv_cb(gpointer data, gint fd, PurpleInputCondition cond) -{ - MsnDirectConn *dc; - int free_buf_space; - int bytes_received; - guint32 packet_length; - - g_return_if_fail(data != NULL); - g_return_if_fail(fd != -1); - - dc = data; - free_buf_space = dc->in_size - dc->in_pos; - - bytes_received = recv(fd, dc->in_buffer + dc->in_pos, free_buf_space, 0); - if (bytes_received < 0) { - if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) - return; - - purple_debug_warning("msn", "msn_dc_recv_cb: recv error\n"); - - if(dc->state != DC_STATE_ESTABLISHED) - msn_dc_fallback_to_sb(dc); - else - msn_dc_destroy(dc); - return; - - } else if (bytes_received == 0) { - /* EOF. Remote side closed connection. */ - purple_debug_info("msn", "msn_dc_recv_cb: recv EOF\n"); - - if(dc->state != DC_STATE_ESTABLISHED) - msn_dc_fallback_to_sb(dc); - else - msn_dc_destroy(dc); - return; - } - - dc->progress = TRUE; - - dc->in_pos += bytes_received; - - /* Wait for packet length */ - while (dc->in_pos >= 4) { - packet_length = GUINT32_FROM_LE(*((guint32*)dc->in_buffer)); - - if (packet_length > DC_MAX_PACKET_SIZE) { - /* Oversized packet */ - purple_debug_warning("msn", "msn_dc_recv_cb: oversized packet received\n"); - return; - } - - /* Wait for the whole packet to arrive */ - if ((guint32)dc->in_pos < 4 + packet_length) - return; - - switch (msn_dc_process_packet(dc, packet_length)) { - case DC_PROCESS_CLOSE: - return; - - case DC_PROCESS_FALLBACK: - purple_debug_warning("msn", "msn_dc_recv_cb: packet processing error, fall back to SB\n"); - msn_dc_fallback_to_sb(dc); - return; - - } - - if ((guint32)dc->in_pos > packet_length + 4) { - g_memmove(dc->in_buffer, dc->in_buffer + 4 + packet_length, dc->in_pos - packet_length - 4); - } - - dc->in_pos -= packet_length + 4; - } -} - -static gboolean -msn_dc_timeout(gpointer data) -{ - MsnDirectConn *dc = data; - - g_return_val_if_fail(dc != NULL, FALSE); - - if (dc->progress) { - dc->progress = FALSE; - return TRUE; - } else { - dc->timeout_handle = 0; - msn_dc_destroy(dc); - return FALSE; - } -} - -static void -msn_dc_init(MsnDirectConn *dc) -{ - g_return_if_fail(dc != NULL); - - dc->in_size = DC_MAX_PACKET_SIZE + 4; - dc->in_pos = 0; - dc->in_buffer = g_malloc(dc->in_size); - - dc->recv_handle = purple_input_add(dc->fd, PURPLE_INPUT_READ, msn_dc_recv_cb, dc); - dc->send_handle = purple_input_add(dc->fd, PURPLE_INPUT_WRITE, msn_dc_send_cb, dc); - - dc->timeout_handle = purple_timeout_add_seconds(DC_TIMEOUT, msn_dc_timeout, dc); -} - -void -msn_dc_connected_to_peer_cb(gpointer data, gint fd, const gchar *error_msg) -{ - MsnDirectConn *dc = data; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "msn_dc_connected_to_peer_cb %p\n", dc); - - g_return_if_fail(dc != NULL); - - dc->connect_data = NULL; - purple_timeout_remove(dc->connect_timeout_handle); - dc->connect_timeout_handle = 0; - - dc->fd = fd; - if (dc->fd != -1) { - msn_dc_init(dc); - msn_dc_send_foo(dc); - msn_dc_send_handshake(dc); - dc->state = DC_STATE_HANDSHAKE_REPLY; - } -} - -/* - * This callback will be called when we're the server - * and nobody has connected us in DC_INCOMING_TIMEOUT seconds - */ -static gboolean -msn_dc_incoming_connection_timeout_cb(gpointer data) { - MsnDirectConn *dc = data; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "msn_dc_incoming_connection_timeout_cb %p\n", dc); - - g_return_val_if_fail(dc != NULL, FALSE); - - if (dc->listen_data != NULL) { - purple_network_listen_cancel(dc->listen_data); - dc->listen_data = NULL; - } - - if (dc->listenfd_handle != 0) { - purple_input_remove(dc->listenfd_handle); - dc->listenfd_handle = 0; - } - - if (dc->listenfd != -1) { - purple_network_remove_port_mapping(dc->listenfd); - close(dc->listenfd); - dc->listenfd = -1; - } - - dc->connect_timeout_handle = 0; - msn_dc_fallback_to_sb(dc); - - return FALSE; -} - -/* - * This callback will be called when we're unable to connect to - * the remote host in DC_OUTGOING_TIMEOUT seconds. - */ -gboolean -msn_dc_outgoing_connection_timeout_cb(gpointer data) -{ - MsnDirectConn *dc = data; - - purple_debug_info("msn", "msn_dc_outgoing_connection_timeout_cb %p\n", dc); - - g_return_val_if_fail(dc != NULL, FALSE); - - dc->connect_timeout_handle = 0; - - if (dc->connect_data != NULL) { - purple_proxy_connect_cancel(dc->connect_data); - dc->connect_data = NULL; - } - - if (dc->ext_ip && dc->ext_port) { - /* Try external IP/port if available. */ - dc->connect_data = purple_proxy_connect( - NULL, - dc->slpcall->slplink->session->account, - dc->ext_ip, - dc->ext_port, - msn_dc_connected_to_peer_cb, - dc - ); - - g_free(dc->ext_ip); - dc->ext_ip = NULL; - - if (dc->connect_data) { - dc->connect_timeout_handle = purple_timeout_add_seconds( - DC_OUTGOING_TIMEOUT, - msn_dc_outgoing_connection_timeout_cb, - dc - ); - } else { - /* - * Connection failed - * Fall back to SB transfer - */ - msn_dc_outgoing_connection_timeout_cb(dc); - } - - } else { - /* - * Both internal and external connection attempts failed. - * Fall back to SB transfer. - */ - msn_dc_fallback_to_sb(dc); - } - - return FALSE; -} - -/* - * This callback will be called when we're the server - * and somebody has connected to us in DC_INCOMING_TIMEOUT seconds. - */ -static void -msn_dc_incoming_connection_cb(gpointer data, gint listenfd, PurpleInputCondition cond) -{ - MsnDirectConn *dc = data; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "msn_dc_incoming_connection_cb %p\n", dc); - - g_return_if_fail(dc != NULL); - - if (dc->connect_timeout_handle != 0) { - purple_timeout_remove(dc->connect_timeout_handle); - dc->connect_timeout_handle = 0; - } - - if (dc->listenfd_handle != 0) { - purple_input_remove(dc->listenfd_handle); - dc->listenfd_handle = 0; - } - - dc->fd = accept(listenfd, NULL, 0); - - purple_network_remove_port_mapping(dc->listenfd); - close(dc->listenfd); - dc->listenfd = -1; - - if (dc->fd != -1) { - msn_dc_init(dc); - dc->state = DC_STATE_FOO; - } -} - -void -msn_dc_listen_socket_created_cb(int listenfd, gpointer data) -{ - MsnDirectConn *dc = data; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "msn_dc_listen_socket_created_cb %p\n", dc); - - g_return_if_fail(dc != NULL); - - dc->listen_data = NULL; - - if (listenfd != -1) { - const char *ext_ip; - const char *int_ip; - int port; - - ext_ip = purple_network_get_my_ip(listenfd); - int_ip = purple_network_get_local_system_ip(listenfd); - port = purple_network_get_port_from_fd(listenfd); - - dc->listenfd = listenfd; - dc->listenfd_handle = purple_input_add( - listenfd, - PURPLE_INPUT_READ, - msn_dc_incoming_connection_cb, - dc - ); - dc->connect_timeout_handle = purple_timeout_add_seconds( - DC_INCOMING_TIMEOUT, - msn_dc_incoming_connection_timeout_cb, - dc - ); - - if (strcmp(int_ip, ext_ip) != 0) { - dc->msg_body = g_strdup_printf( - "Bridge: TCPv1\r\n" - "Listening: true\r\n" - "%sNonce: {%s}\r\n" - "IPv4External-Addrs: %s\r\n" - "IPv4External-Port: %d\r\n" - "IPv4Internal-Addrs: %s\r\n" - "IPv4Internal-Port: %d\r\n" - "\r\n", - - dc->nonce_type != DC_NONCE_PLAIN ? "Hashed-" : "", - dc->nonce_hash, - ext_ip, - port, - int_ip, - port - ); - - } else { - dc->msg_body = g_strdup_printf( - "Bridge: TCPv1\r\n" - "Listening: true\r\n" - "%sNonce: {%s}\r\n" - "IPv4External-Addrs: %s\r\n" - "IPv4External-Port: %d\r\n" - "\r\n", - - dc->nonce_type != DC_NONCE_PLAIN ? "Hashed-" : "", - dc->nonce_hash, - ext_ip, - port - ); - } - - if (dc->slpcall->wait_for_socket) { - if (dc->send_connection_info_msg_cb != NULL) - dc->send_connection_info_msg_cb(dc); - - dc->slpcall->wait_for_socket = FALSE; - } - } -} - diff --git a/libpurple/protocols/msn/directconn.h b/libpurple/protocols/msn/directconn.h deleted file mode 100644 index 41a05d274e..0000000000 --- a/libpurple/protocols/msn/directconn.h +++ /dev/null @@ -1,200 +0,0 @@ -/** - * @file directconn.h MSN direct connection functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_DIRECTCONN_H -#define MSN_DIRECTCONN_H - -typedef struct _MsnDirectConn MsnDirectConn; - -#include "network.h" -#include "proxy.h" -#include "circbuffer.h" - -#include "slp.h" -#include "slplink.h" -#include "slpmsg.h" -#include "slpmsg_part.h" -#include "p2p.h" - -#define MSN_DCCONN_MAX_SIZE 1352 - -typedef enum -{ - DC_STATE_CLOSED, /*< No socket opened yet */ - DC_STATE_FOO, /*< Waiting for FOO message */ - DC_STATE_HANDSHAKE, /*< Waiting for handshake message */ - DC_STATE_HANDSHAKE_REPLY, /*< Waiting for handshake reply message */ - DC_STATE_ESTABLISHED /*< Handshake complete */ -} MsnDirectConnState; - -typedef enum -{ - DC_PROCESS_OK = 0, - DC_PROCESS_ERROR, - DC_PROCESS_FALLBACK, - DC_PROCESS_CLOSE - -} MsnDirectConnProcessResult; - -typedef enum -{ - DC_NONCE_UNKNOWN, /**< Invalid scheme */ - DC_NONCE_PLAIN, /**< No hashing */ - DC_NONCE_SHA1 /**< First 16 bytes of SHA1 of nonce */ - -} MsnDirectConnNonceType; - -typedef struct _MsnDirectConnPacket MsnDirectConnPacket; - -struct _MsnDirectConnPacket { - guint32 length; - guchar *data; - - void (*sent_cb)(struct _MsnDirectConnPacket*); - MsnSlpMessagePart *part; -}; - -struct _MsnDirectConn -{ - MsnDirectConnState state; /**< Direct connection status */ - MsnSlpLink *slplink; /**< The slplink using this direct connection */ - MsnSlpCall *slpcall; /**< The slpcall which initiated the direct connection */ - char *msg_body; /**< The body of message sent by send_connection_info_msg_cb */ - MsnSlpMessage *prev_ack; /**< The saved SLP ACK message */ - - MsnDirectConnNonceType nonce_type; /**< The type of nonce hashing */ - guchar nonce[16]; /**< The nonce used for handshake */ - gchar nonce_hash[37]; /**< The hash of nonce */ - gchar remote_nonce[37]; /**< The remote side's nonce */ - - PurpleNetworkListenData *listen_data; /**< The pending socket creation request */ - PurpleProxyConnectData *connect_data; /**< The pending connection attempt */ - int listenfd; /**< The socket we're listening for incoming connections */ - guint listenfd_handle; /**< The timeout handle for incoming connection */ - guint connect_timeout_handle; /**< The timeout handle for outgoing connection */ - - int fd; /**< The direct connection socket */ - guint recv_handle; /**< The incoming data callback handle */ - guint send_handle; /**< The outgoing data callback handle */ - - gchar *in_buffer; /**< The receive buffer */ - int in_size; /**< The receive buffer size */ - int in_pos; /**< The first free position in receive buffer */ - GQueue *out_queue; /**< The outgoing packet queue */ - int msg_pos; /**< The position of next byte to be sent in the actual packet */ - - /** The callback used for sending information to the peer about the opened socket */ - void (*send_connection_info_msg_cb)(MsnDirectConn *); - - gchar *ext_ip; /**< Our external IP address */ - int ext_port; /**< Our external port */ - - guint timeout_handle; - gboolean progress; - - /*int num_calls;*/ /**< The number of slpcalls using this direct connection */ -}; - -/* Outgoing attempt */ -#define DC_OUTGOING_TIMEOUT (5) -/* Time for internal + external connection attempts */ -#define DC_INCOMING_TIMEOUT (DC_OUTGOING_TIMEOUT * 3) -/* Timeout for lack of activity */ -#define DC_TIMEOUT (60) - -/* - * Queues an MSN message to be sent via direct connection. - */ -void -msn_dc_enqueue_part(MsnDirectConn *dc, MsnSlpMessagePart *part); - -/* - * Creates, initializes, and returns a new MsnDirectConn structure. - */ -MsnDirectConn * -msn_dc_new(MsnSlpCall *slpcall); - -/* - * Destroys an MsnDirectConn structure. Frees every buffer allocated earlier - * restores saved callbacks, etc. - */ -void -msn_dc_destroy(MsnDirectConn *dc); - -/* - * Fallback to switchboard connection. Used when neither side is able to - * create a listening socket. - */ -void -msn_dc_fallback_to_sb(MsnDirectConn *dc); - -/* - * Increases the slpcall counter in DC. The direct connection remains open - * until all slpcalls using it are destroyed. - */ -void -msn_dc_ref(MsnDirectConn *dc); - -/* - * Decrease the slpcall counter in DC. The direct connection remains open - * until all slpcalls using it are destroyed. - */ -void -msn_dc_unref(MsnDirectConn *dc); - -/* - * Sends a direct connect INVITE message on the associated slplink - * with the corresponding connection type and information. - */ -void -msn_dc_send_invite(MsnDirectConn *dc); - -/* - * Sends a direct connect OK message as a response to an INVITE received earliaer - * on the corresponding slplink. - */ -void -msn_dc_send_ok(MsnDirectConn *dc); - -/* - * This callback will be called when we're successfully connected to - * the remote host. - */ -void -msn_dc_connected_to_peer_cb(gpointer data, gint fd, const gchar *error_msg); - -/* - * This callback will be called when we're unable to connect to - * the remote host in DC_CONNECT_TIMEOUT seconds. - */ -gboolean -msn_dc_outgoing_connection_timeout_cb(gpointer data); - -/* - * This callback will be called when the listening socket is successfully - * created and its parameters (IP/port) are available. - */ -void -msn_dc_listen_socket_created_cb(int listenfd, gpointer data); - -#endif /* MSN_DIRECTCONN_H */ diff --git a/libpurple/protocols/msn/error.c b/libpurple/protocols/msn/error.c deleted file mode 100644 index 68690ef384..0000000000 --- a/libpurple/protocols/msn/error.c +++ /dev/null @@ -1,384 +0,0 @@ -/** - * @file error.c Error functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "debug.h" -/* Masca: can we get rid of the sync issue dialog? */ -#include "request.h" - -#include "error.h" - -typedef struct -{ - MsnSession *session; - char *who; - char *group; - gboolean add; - -} MsnAddRemData; - -const char * -msn_error_get_text(unsigned int type, gboolean *debug) -{ - static char msg[256]; - const char *result; - *debug = FALSE; - - switch (type) { - case 0: - result = _("Unable to parse message"); - *debug = TRUE; - break; - case 200: - result = _("Syntax Error (probably a client bug)"); - *debug = TRUE; - break; - case 201: - result = _("Invalid email address"); - break; - case 205: - result = _("User does not exist"); - break; - case 206: - result = _("Fully qualified domain name missing"); - break; - case 207: - result = _("Already logged in"); - break; - case 208: - result = _("Invalid username"); - break; - case 209: - result = _("Invalid friendly name"); - break; - case 210: - result = _("List full"); - break; - case 215: - result = _("Already there"); - *debug = TRUE; - break; - case 216: - result = _("Not on list"); - break; - case 217: - result = _("User is offline"); - break; - case 218: - result = _("Already in the mode"); - *debug = TRUE; - break; - case 219: - result = _("Already in opposite list"); - *debug = TRUE; - break; - case 223: - result = _("Too many groups"); - break; - case 224: - result = _("Invalid group"); - break; - case 225: - result = _("User not in group"); - break; - case 229: - result = _("Group name too long"); - break; - case 230: - result = _("Cannot remove group zero"); - *debug = TRUE; - break; - case 231: - result = _("Tried to add a user to a group that doesn't exist"); - break; - case 280: - result = _("Switchboard failed"); - *debug = TRUE; - break; - case 281: - result = _("Notify transfer failed"); - *debug = TRUE; - break; - - case 300: - result = _("Required fields missing"); - *debug = TRUE; - break; - case 301: - result = _("Too many hits to a FND"); - *debug = TRUE; - break; - case 302: - result = _("Not logged in"); - break; - - case 500: - result = _("Service temporarily unavailable"); - break; - case 501: - result = _("Database server error"); - *debug = TRUE; - break; - case 502: - result = _("Command disabled"); - *debug = TRUE; - break; - case 510: - result = _("File operation error"); - *debug = TRUE; - break; - case 520: - result = _("Memory allocation error"); - *debug = TRUE; - break; - case 540: - result = _("Wrong CHL value sent to server"); - *debug = TRUE; - break; - - case 600: - result = _("Server busy"); - break; - case 601: - result = _("Server unavailable"); - break; - case 602: - result = _("Peer notification server down"); - *debug = TRUE; - break; - case 603: - result = _("Database connect error"); - *debug = TRUE; - break; - case 604: - result = _("Server is going down (abandon ship)"); - break; - case 605: - result = _("Server unavailable"); - break; - - case 707: - result = _("Error creating connection"); - *debug = TRUE; - break; - case 710: - result = _("CVR parameters are either unknown or not allowed"); - *debug = TRUE; - break; - case 711: - result = _("Unable to write"); - break; - case 712: - result = _("Session overload"); - *debug = TRUE; - break; - case 713: - result = _("User is too active"); - break; - case 714: - result = _("Too many sessions"); - break; - case 715: - result = _("Passport not verified"); - break; - case 717: - result = _("Bad friend file"); - *debug = TRUE; - break; - case 731: - result = _("Not expected"); - *debug = TRUE; - break; - - case 800: - result = _("Friendly name is changing too rapidly"); - break; - - case 910: - case 912: - case 918: - case 919: - case 921: - case 922: - result = _("Server too busy"); - break; - case 911: - case 917: - result = _("Authentication failed"); - break; - case 913: - result = _("Not allowed when offline"); - break; - case 914: - case 915: - case 916: - result = _("Server unavailable"); - break; - case 920: - result = _("Not accepting new users"); - break; - case 923: - result = _("Kids Passport without parental consent"); - break; - case 924: - result = _("Passport account not yet verified"); - break; - case 927: - result = _("Passport account suspended"); - break; - case 928: - result = _("Bad ticket"); - *debug = TRUE; - break; - - default: - g_snprintf(msg, sizeof(msg), - _("Unknown Error Code %d"), type); - *debug = TRUE; - result = msg; - break; - } - - return result; -} - -void -msn_error_handle(MsnSession *session, unsigned int type) -{ - char *buf; - gboolean debug; - - buf = g_strdup_printf(_("MSN Error: %s\n"), - msn_error_get_text(type, &debug)); - if (debug) - purple_debug_warning("msn", "error %d: %s\n", type, buf); - else - purple_notify_error(session->account->gc, NULL, buf, NULL); - g_free(buf); -} - -/* Remove the buddy referenced by the MsnAddRemData before the serverside list - * is changed. If the buddy will be added, he'll be added back; if he will be - * removed, he won't be. */ -/* Actually with our MSNP14 code that isn't true yet, he won't be added back :( - * */ -static void -msn_complete_sync_issue(MsnAddRemData *data) -{ - PurpleBuddy *buddy; - PurpleGroup *group = NULL; - - if (data->group != NULL) - group = purple_find_group(data->group); - - if (group != NULL) - buddy = purple_find_buddy_in_group(data->session->account, data->who, group); - else - buddy = purple_find_buddy(data->session->account, data->who); - - if (buddy != NULL) - purple_blist_remove_buddy(buddy); -} - - -static void -msn_add_cb(MsnAddRemData *data) -{ -#if 0 - /* this *should* be necessary !! */ - msn_complete_sync_issue(data); -#endif - MsnUserList *userlist = data->session->userlist; - - msn_userlist_add_buddy(userlist, data->who, data->group); - - g_free(data->group); - g_free(data->who); - g_free(data); -} - -static void -msn_rem_cb(MsnAddRemData *data) -{ - MsnUserList *userlist = data->session->userlist; - msn_complete_sync_issue(data); - - - if (data->group == NULL) { - msn_userlist_rem_buddy_from_list(userlist, data->who, MSN_LIST_FL); - } else { - g_free(data->group); - } - - g_free(data->who); - g_free(data); -} - -void -msn_error_sync_issue(MsnSession *session, const char *passport, - const char *group_name) -{ - PurpleConnection *gc; - PurpleAccount *account; - MsnAddRemData *data; - char *msg, *reason; - - account = session->account; - gc = purple_account_get_connection(account); - - data = g_new0(MsnAddRemData, 1); - data->who = g_strdup(passport); - data->group = g_strdup(group_name); - data->session = session; - - msg = g_strdup_printf(_("Buddy list synchronization issue in %s (%s)"), - purple_account_get_username(account), - purple_account_get_protocol_name(account)); - - if (group_name != NULL) - { - reason = g_strdup_printf(_("%s on the local list is " - "inside the group \"%s\" but not on " - "the server list. " - "Do you want this buddy to be added?"), - passport, group_name); - } - else - { - reason = g_strdup_printf(_("%s is on the local list but " - "not on the server list. " - "Do you want this buddy to be added?"), - passport); - } - - purple_request_action(gc, NULL, msg, reason, PURPLE_DEFAULT_ACTION_NONE, - account, data->who, NULL, - data, 2, - _("Yes"), G_CALLBACK(msn_add_cb), - _("No"), G_CALLBACK(msn_rem_cb)); - - g_free(reason); - g_free(msg); -} - diff --git a/libpurple/protocols/msn/error.h b/libpurple/protocols/msn/error.h deleted file mode 100644 index 5194eaaac3..0000000000 --- a/libpurple/protocols/msn/error.h +++ /dev/null @@ -1,57 +0,0 @@ -/** - * @file error.h Error functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_ERROR_H -#define MSN_ERROR_H - -#include "session.h" - -/** - * Returns the string representation of an error type. - * - * @param type The error type. - * @param debug Whether this should be treated as a debug log message or a user-visible error - * - * @return The string representation of the error type. - */ -const char *msn_error_get_text(unsigned int type, gboolean *debug); - -/** - * Handles an error. - * - * @param session The current session. - * @param type The error type. - */ -void msn_error_handle(MsnSession *session, unsigned int type); - -/** - * Show the sync issue in a dialog using request api - * - * @param sesion MsnSession associated to this error. - * @param passport The passport associated with the error. - * @param group_name The group in the buddy is suppoused to be - */ -void msn_error_sync_issue(MsnSession *session, const char *passport, - const char *group_name); - -#endif /* MSN_ERROR_H */ diff --git a/libpurple/protocols/msn/group.c b/libpurple/protocols/msn/group.c deleted file mode 100644 index ddb1541919..0000000000 --- a/libpurple/protocols/msn/group.c +++ /dev/null @@ -1,89 +0,0 @@ -/** - * @file group.c Group functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#include "msn.h" -#include "group.h" - -MsnGroup * -msn_group_new(MsnUserList *userlist, const char *id, const char *name) -{ - MsnGroup *group; - - g_return_val_if_fail(id != NULL, NULL); - g_return_val_if_fail(name != NULL, NULL); - - group = g_new0(MsnGroup, 1); - - msn_userlist_add_group(userlist, group); - - group->id = g_strdup(id); - group->name = g_strdup(name); - - return group; -} - -void -msn_group_destroy(MsnGroup *group) -{ - g_return_if_fail(group != NULL); - - g_free(group->id); - g_free(group->name); - g_free(group); -} - -void -msn_group_set_id(MsnGroup *group, const char *id) -{ - g_return_if_fail(group != NULL); - g_return_if_fail(id != NULL); - - g_free(group->id); - group->id = g_strdup(id); -} - -void -msn_group_set_name(MsnGroup *group, const char *name) -{ - g_return_if_fail(group != NULL); - g_return_if_fail(name != NULL); - - g_free(group->name); - group->name = g_strdup(name); -} - -char* -msn_group_get_id(const MsnGroup *group) -{ - g_return_val_if_fail(group != NULL, NULL); - - return group->id; -} - -const char * -msn_group_get_name(const MsnGroup *group) -{ - g_return_val_if_fail(group != NULL, NULL); - - return group->name; -} diff --git a/libpurple/protocols/msn/group.h b/libpurple/protocols/msn/group.h deleted file mode 100644 index 620d24124f..0000000000 --- a/libpurple/protocols/msn/group.h +++ /dev/null @@ -1,109 +0,0 @@ -/** - * @file group.h Group functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_GROUP_H -#define MSN_GROUP_H - -typedef struct _MsnGroup MsnGroup; - -#include "internal.h" - -#include "session.h" -#include "user.h" -#include "userlist.h" - -#define MSN_INDIVIDUALS_GROUP_ID "1983" -#define MSN_INDIVIDUALS_GROUP_NAME _("Other Contacts") - -#define MSN_NON_IM_GROUP_ID "email" -#define MSN_NON_IM_GROUP_NAME _("Non-IM Contacts") - -/** - * A group. - */ -struct _MsnGroup -{ - MsnSession *session; /**< The MSN session. */ - - char *id; /**< The group ID. */ - char *name; /**< The name of the group. */ -}; - -/************************************************************************** - ** @name Group API * - **************************************************************************/ -/*@{*/ - -/** - * Creates a new group structure. - * - * @param session The MSN session. - * @param id The group ID. - * @param name The name of the group. - * - * @return A new group structure. - */ -MsnGroup *msn_group_new(MsnUserList *userlist, const char *id, const char *name); - -/** - * Destroys a group structure. - * - * @param group The group to destroy. - */ -void msn_group_destroy(MsnGroup *group); - -/** - * Sets the ID for a group. - * - * @param group The group. - * @param id The ID. - */ -void msn_group_set_id(MsnGroup *group, const char *id); - -/** - * Sets the name for a group. - * - * @param group The group. - * @param name The name. - */ -void msn_group_set_name(MsnGroup *group, const char *name); - -/** - * Returns the ID for a group. - * - * @param group The group. - * - * @return The ID. - */ -char* msn_group_get_id(const MsnGroup *group); - -/** - * Returns the name for a group. - * - * @param group The group. - * - * @return The name. - */ -const char *msn_group_get_name(const MsnGroup *group); - -#endif /* MSN_GROUP_H */ diff --git a/libpurple/protocols/msn/history.c b/libpurple/protocols/msn/history.c deleted file mode 100644 index 2b23af5ba1..0000000000 --- a/libpurple/protocols/msn/history.c +++ /dev/null @@ -1,93 +0,0 @@ -/** - * @file history.c MSN history functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#include "msn.h" -#include "history.h" - -MsnHistory * -msn_history_new(void) -{ - MsnHistory *history = g_new0(MsnHistory, 1); - - history->trId = 1; - - history->queue = g_queue_new(); - - return history; -} - -void -msn_history_destroy(MsnHistory *history) -{ - MsnTransaction *trans; - - while ((trans = g_queue_pop_head(history->queue)) != NULL) - msn_transaction_destroy(trans); - - g_queue_free(history->queue); - g_free(history); -} - -MsnTransaction * -msn_history_find(MsnHistory *history, unsigned int trId) -{ - MsnTransaction *trans; - GList *list; - - for (list = history->queue->head; list != NULL; list = list->next) - { - trans = list->data; - if (trans->trId == trId) - return trans; - } - - return NULL; -} - -void -msn_history_add(MsnHistory *history, MsnTransaction *trans) -{ - GQueue *queue; - gsize max_elems; - - g_return_if_fail(history != NULL); - g_return_if_fail(trans != NULL); - - queue = history->queue; - - trans->trId = history->trId++; - - g_queue_push_tail(queue, trans); - - if (trans->cmdproc->servconn->type == MSN_SERVCONN_NS) - max_elems = MSN_NS_HIST_ELEMS; - else - max_elems = MSN_SB_HIST_ELEMS; - - if (queue->length > max_elems) - { - trans = g_queue_pop_head(queue); - msn_transaction_destroy(trans); - } -} - diff --git a/libpurple/protocols/msn/history.h b/libpurple/protocols/msn/history.h deleted file mode 100644 index 7ceef1fce4..0000000000 --- a/libpurple/protocols/msn/history.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @file history.h MSN history functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_HISTORY_H -#define MSN_HISTORY_H - -#include "internal.h" - -typedef struct _MsnHistory MsnHistory; - -#include "transaction.h" - -#define MSN_NS_HIST_ELEMS 0x300 -#define MSN_SB_HIST_ELEMS 0x30 - -/** - * The history. - */ -struct _MsnHistory -{ - GQueue *queue; - unsigned int trId; -}; - -MsnHistory *msn_history_new(void); -void msn_history_destroy(MsnHistory *history); -MsnTransaction *msn_history_find(MsnHistory *history, unsigned int triId); -void msn_history_add(MsnHistory *history, MsnTransaction *trans); - -#endif /* MSN_HISTORY_H */ diff --git a/libpurple/protocols/msn/httpconn.c b/libpurple/protocols/msn/httpconn.c deleted file mode 100644 index 2f52d1ec34..0000000000 --- a/libpurple/protocols/msn/httpconn.c +++ /dev/null @@ -1,739 +0,0 @@ -/** - * @file httpconn.c HTTP connection method - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#include "msn.h" -#include "debug.h" -#include "httpconn.h" - -typedef struct -{ - MsnHttpConn *httpconn; - char *body; - size_t body_len; -} MsnHttpQueueData; - -static void -msn_httpconn_process_queue(MsnHttpConn *httpconn) -{ - httpconn->waiting_response = FALSE; - - if (httpconn->queue != NULL) - { - MsnHttpQueueData *queue_data; - - queue_data = (MsnHttpQueueData *)httpconn->queue->data; - - httpconn->queue = g_list_remove(httpconn->queue, queue_data); - - msn_httpconn_write(queue_data->httpconn, - queue_data->body, - queue_data->body_len); - - g_free(queue_data->body); - g_free(queue_data); - } -} - -static gboolean -msn_httpconn_parse_data(MsnHttpConn *httpconn, const char *buf, - size_t size, char **ret_buf, size_t *ret_size, - gboolean *error) -{ - const char *s, *c; - char *header, *body; - const char *body_start; - char *tmp; - size_t body_len = 0; - - g_return_val_if_fail(httpconn != NULL, FALSE); - g_return_val_if_fail(buf != NULL, FALSE); - g_return_val_if_fail(size > 0, FALSE); - g_return_val_if_fail(ret_buf != NULL, FALSE); - g_return_val_if_fail(ret_size != NULL, FALSE); - g_return_val_if_fail(error != NULL, FALSE); - -#if 0 - purple_debug_info("msn", "HTTP: parsing data {%s}\n", buf); -#endif - - /* Healthy defaults. */ - body = NULL; - - *ret_buf = NULL; - *ret_size = 0; - *error = FALSE; - - /* First, some tests to see if we have a full block of stuff. */ - if (((strncmp(buf, "HTTP/1.1 200 OK\r\n", 17) != 0) && - (strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) != 0)) && - ((strncmp(buf, "HTTP/1.0 200 OK\r\n", 17) != 0) && - (strncmp(buf, "HTTP/1.0 100 Continue\r\n", 23) != 0))) - { - *error = TRUE; - - return FALSE; - } - - if (strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) == 0) - { - if ((s = strstr(buf, "\r\n\r\n")) == NULL) - return FALSE; - - s += 4; - - if (*s == '\0') - { - *ret_buf = g_strdup(""); - *ret_size = 0; - - msn_httpconn_process_queue(httpconn); - - return TRUE; - } - - size -= (s - buf); - buf = s; - } - - if ((s = strstr(buf, "\r\n\r\n")) == NULL) - /* Need to wait for the full HTTP header to arrive */ - return FALSE; - - s += 4; /* Skip \r\n\r\n */ - header = g_strndup(buf, s - buf); - body_start = s; - body_len = size - (body_start - buf); - - if ((s = purple_strcasestr(header, "Content-Length: ")) != NULL) - { - size_t tmp_len; - - s += strlen("Content-Length: "); - - if ((c = strchr(s, '\r')) == NULL) - { - g_free(header); - - return FALSE; - } - - tmp = g_strndup(s, c - s); - tmp_len = atoi(tmp); - g_free(tmp); - - if (body_len != tmp_len) - { - /* Need to wait for the full packet to arrive */ - - g_free(header); - -#if 0 - purple_debug_warning("msn", - "body length (%d) != content length (%d)\n", - body_len, tmp_len); -#endif - - return FALSE; - } - } - - body = g_malloc(body_len + 1); - memcpy(body, body_start, body_len); - body[body_len] = '\0'; - - if (purple_debug_is_verbose()) - purple_debug_misc("msn", "Incoming HTTP buffer (header): {%s}\n", - header); - - /* Now we should be able to process the data. */ - if ((s = purple_strcasestr(header, "X-MSN-Messenger: ")) != NULL) - { - gchar *full_session_id = NULL, *gw_ip = NULL, *session_action = NULL; - char *t, *session_id; - char **elems, **cur, **tokens; - - full_session_id = gw_ip = session_action = NULL; - - s += strlen("X-MSN-Messenger: "); - - if ((c = strchr(s, '\r')) == NULL) - { - msn_session_set_error(httpconn->session, - MSN_ERROR_HTTP_MALFORMED, NULL); - purple_debug_error("msn", "Malformed X-MSN-Messenger field.\n{%s}\n", - buf); - - g_free(header); - g_free(body); - return FALSE; - } - - tmp = g_strndup(s, c - s); - - elems = g_strsplit(tmp, "; ", 0); - - for (cur = elems; *cur != NULL; cur++) - { - tokens = g_strsplit(*cur, "=", 2); - - if (strcmp(tokens[0], "SessionID") == 0) { - g_free(full_session_id); - full_session_id = tokens[1]; - } else if (strcmp(tokens[0], "GW-IP") == 0) { - g_free(gw_ip); - gw_ip = tokens[1]; - } else if (strcmp(tokens[0], "Session") == 0) { - g_free(session_action); - session_action = tokens[1]; - } else - g_free(tokens[1]); - - g_free(tokens[0]); - /* Don't free each of the tokens, only the array. */ - g_free(tokens); - } - - g_strfreev(elems); - - g_free(tmp); - - t = full_session_id ? strchr(full_session_id, '.') : NULL; - if (t != NULL) - session_id = g_strndup(full_session_id, t - full_session_id); - else { - purple_debug_error("msn", "Malformed full_session_id[%s]\n", - full_session_id ? full_session_id : NULL); - session_id = g_strdup(full_session_id); - } - - if (session_action == NULL || strcmp(session_action, "close") != 0) - { - g_free(httpconn->full_session_id); - httpconn->full_session_id = full_session_id; - - g_free(httpconn->session_id); - httpconn->session_id = session_id; - - g_free(httpconn->host); - httpconn->host = gw_ip; - } - else - { - /* I'll be honest, I don't fully understand all this, but this - * causes crashes, Stu. */ -#if 0 - MsnServConn *servconn; - - /* It's going to die. */ - /* poor thing */ - - servconn = httpconn->servconn; - - if (servconn != NULL) - servconn->wasted = TRUE; -#endif - - g_free(full_session_id); - g_free(session_id); - g_free(gw_ip); - } - - g_free(session_action); - } - - g_free(header); - - *ret_buf = body; - *ret_size = body_len; - - msn_httpconn_process_queue(httpconn); - - return TRUE; -} - -static void -read_cb(gpointer data, gint source, PurpleInputCondition cond) -{ - MsnHttpConn *httpconn; - MsnServConn *servconn; - char buf[MSN_BUF_LEN]; - gssize len; - char *result_msg = NULL; - size_t result_len = 0; - gboolean error = FALSE; - - httpconn = data; - servconn = httpconn->servconn; - - if (servconn->type == MSN_SERVCONN_NS) - servconn->session->account->gc->last_received = time(NULL); - - len = read(httpconn->fd, buf, sizeof(buf) - 1); - if (len < 0 && errno == EAGAIN) - return; - if (len <= 0) { - purple_debug_error("msn", "HTTP: servconn %03d read error, " - "len: %" G_GSSIZE_FORMAT ", errno: %d, error: %s\n", - servconn->num, len, error, g_strerror(errno)); - msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_READ, NULL); - - return; - } - - buf[len] = '\0'; - - httpconn->rx_buf = g_realloc(httpconn->rx_buf, len + httpconn->rx_len + 1); - memcpy(httpconn->rx_buf + httpconn->rx_len, buf, len + 1); - httpconn->rx_len += len; - - if (!msn_httpconn_parse_data(httpconn, httpconn->rx_buf, httpconn->rx_len, - &result_msg, &result_len, &error)) - { - /* Either we must wait for more input, or something went wrong */ - if (error) - msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_READ, NULL); - - return; - } - - if (error) - { - purple_debug_error("msn", "HTTP: Special error\n"); - msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_READ, NULL); - - return; - } - - g_free(httpconn->rx_buf); - httpconn->rx_buf = NULL; - httpconn->rx_len = 0; - - if (result_len == 0) - { - /* Nothing to do here */ -#if 0 - purple_debug_info("msn", "HTTP: nothing to do here\n"); -#endif - g_free(result_msg); - return; - } - - g_free(servconn->rx_buf); - servconn->rx_buf = result_msg; - servconn->rx_len = result_len; - - msn_servconn_process_data(servconn); -} - -static void -httpconn_write_cb(gpointer data, gint source, PurpleInputCondition cond) -{ - MsnHttpConn *httpconn; - gssize ret; - int writelen; - - httpconn = data; - writelen = purple_circ_buffer_get_max_read(httpconn->tx_buf); - - if (writelen == 0) - { - purple_input_remove(httpconn->tx_handler); - httpconn->tx_handler = 0; - return; - } - - ret = write(httpconn->fd, httpconn->tx_buf->outptr, writelen); - if (ret <= 0) - { - if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) - /* No worries */ - return; - - /* Error! */ - msn_servconn_got_error(httpconn->servconn, MSN_SERVCONN_ERROR_WRITE, NULL); - return; - } - - purple_circ_buffer_mark_read(httpconn->tx_buf, ret); - - /* TODO: I don't think these 2 lines are needed. Remove them? */ - if (ret == writelen) - httpconn_write_cb(data, source, cond); -} - -static gboolean -write_raw(MsnHttpConn *httpconn, const char *data, size_t data_len) -{ - gssize res; /* result of the write operation */ - - if (httpconn->tx_handler == 0) - res = write(httpconn->fd, data, data_len); - else - { - res = -1; - errno = EAGAIN; - } - - if ((res <= 0) && ((errno != EAGAIN) && (errno != EWOULDBLOCK))) - { - msn_servconn_got_error(httpconn->servconn, MSN_SERVCONN_ERROR_WRITE, NULL); - return FALSE; - } - - if (res < 0 || (size_t)res < data_len) - { - if (res < 0) - res = 0; - if (httpconn->tx_handler == 0 && httpconn->fd) - httpconn->tx_handler = purple_input_add(httpconn->fd, - PURPLE_INPUT_WRITE, httpconn_write_cb, httpconn); - purple_circ_buffer_append(httpconn->tx_buf, data + res, - data_len - res); - } - - return TRUE; -} - -static char * -msn_httpconn_proxy_auth(MsnHttpConn *httpconn) -{ - PurpleAccount *account; - PurpleProxyInfo *gpi; - const char *username, *password; - char *auth = NULL; - - account = httpconn->session->account; - - gpi = purple_proxy_get_setup(account); - - if (gpi == NULL || !(purple_proxy_info_get_type(gpi) == PURPLE_PROXY_HTTP || - purple_proxy_info_get_type(gpi) == PURPLE_PROXY_USE_ENVVAR)) - return NULL; - - username = purple_proxy_info_get_username(gpi); - password = purple_proxy_info_get_password(gpi); - - if (username != NULL) { - char *tmp; - auth = g_strdup_printf("%s:%s", username, password ? password : ""); - tmp = purple_base64_encode((const guchar *)auth, strlen(auth)); - g_free(auth); - auth = g_strdup_printf("Proxy-Authorization: Basic %s\r\n", tmp); - g_free(tmp); - } - - return auth; -} - -static gboolean -msn_httpconn_poll(gpointer data) -{ - MsnHttpConn *httpconn; - char *header; - char *auth; - - httpconn = data; - - g_return_val_if_fail(httpconn != NULL, FALSE); - - if ((httpconn->host == NULL) || (httpconn->full_session_id == NULL)) - { - /* There's no need to poll if the session is not fully established */ - return TRUE; - } - - if (httpconn->waiting_response) - { - /* There's no need to poll if we're already waiting for a response */ - return TRUE; - } - - auth = msn_httpconn_proxy_auth(httpconn); - - header = g_strdup_printf( - "POST http://%s/gateway/gateway.dll?Action=poll&SessionID=%s HTTP/1.1\r\n" - "Accept: */*\r\n" - "Accept-Language: en-us\r\n" - "User-Agent: MSMSGS\r\n" - "Host: %s\r\n" - "Proxy-Connection: Keep-Alive\r\n" - "%s" /* Proxy auth */ - "Connection: Keep-Alive\r\n" - "Pragma: no-cache\r\n" - "Content-Type: application/x-msn-messenger\r\n" - "Content-Length: 0\r\n\r\n", - httpconn->host, - httpconn->full_session_id, - httpconn->host, - auth ? auth : ""); - - g_free(auth); - - if (write_raw(httpconn, header, strlen(header))) - httpconn->waiting_response = TRUE; - - g_free(header); - - return TRUE; -} - -gssize -msn_httpconn_write(MsnHttpConn *httpconn, const char *body, size_t body_len) -{ - char *params; - char *data; - int header_len; - char *auth; - const char *server_types[] = { "NS", "SB" }; - const char *server_type; - char *host; - MsnServConn *servconn; - - /* TODO: remove http data from servconn */ - - g_return_val_if_fail(httpconn != NULL, 0); - g_return_val_if_fail(body != NULL, 0); - g_return_val_if_fail(body_len > 0, 0); - - servconn = httpconn->servconn; - - if (httpconn->waiting_response) - { - MsnHttpQueueData *queue_data = g_new0(MsnHttpQueueData, 1); - - queue_data->httpconn = httpconn; - queue_data->body = g_memdup(body, body_len); - queue_data->body_len = body_len; - - httpconn->queue = g_list_append(httpconn->queue, queue_data); - - return body_len; - } - - server_type = server_types[servconn->type]; - - if (httpconn->virgin) - { - /* QuLogic: This doesn't look right to me, but it still seems to work */ - host = MSN_HTTPCONN_SERVER; - - /* The first time servconn->host is the host we should connect to. */ - params = g_strdup_printf("Action=open&Server=%s&IP=%s", - server_type, - servconn->host); - httpconn->virgin = FALSE; - } - else - { - /* The rest of the times servconn->host is the gateway host. */ - host = httpconn->host; - - if (host == NULL || httpconn->full_session_id == NULL) - { - purple_debug_warning("msn", "Attempted HTTP write before session is established\n"); - return -1; - } - - params = g_strdup_printf("SessionID=%s", - httpconn->full_session_id); - } - - auth = msn_httpconn_proxy_auth(httpconn); - - data = g_strdup_printf( - "POST http://%s/gateway/gateway.dll?%s HTTP/1.1\r\n" - "Accept: */*\r\n" - "Accept-Language: en-us\r\n" - "User-Agent: MSMSGS\r\n" - "Host: %s\r\n" - "Proxy-Connection: Keep-Alive\r\n" - "%s" /* Proxy auth */ - "Connection: Keep-Alive\r\n" - "Pragma: no-cache\r\n" - "Content-Type: application/x-msn-messenger\r\n" - "Content-Length: %d\r\n\r\n", - host, - params, - host, - auth ? auth : "", - (int) body_len); - - g_free(params); - - g_free(auth); - - header_len = strlen(data); - data = g_realloc(data, header_len + body_len); - memcpy(data + header_len, body, body_len); - - if (write_raw(httpconn, data, header_len + body_len)) - httpconn->waiting_response = TRUE; - - g_free(data); - - return body_len; -} - -MsnHttpConn * -msn_httpconn_new(MsnServConn *servconn) -{ - MsnHttpConn *httpconn; - - g_return_val_if_fail(servconn != NULL, NULL); - - httpconn = g_new0(MsnHttpConn, 1); - - purple_debug_info("msn", "new httpconn (%p)\n", httpconn); - - /* TODO: Remove this */ - httpconn->session = servconn->session; - - httpconn->servconn = servconn; - - httpconn->tx_buf = purple_circ_buffer_new(MSN_BUF_LEN); - httpconn->tx_handler = 0; - - httpconn->fd = -1; - - return httpconn; -} - -void -msn_httpconn_destroy(MsnHttpConn *httpconn) -{ - g_return_if_fail(httpconn != NULL); - - purple_debug_info("msn", "destroy httpconn (%p)\n", httpconn); - - if (httpconn->connected) - msn_httpconn_disconnect(httpconn); - - g_free(httpconn->full_session_id); - - g_free(httpconn->session_id); - - g_free(httpconn->host); - - while (httpconn->queue != NULL) { - MsnHttpQueueData *queue_data; - - queue_data = (MsnHttpQueueData *) httpconn->queue->data; - - httpconn->queue = g_list_delete_link(httpconn->queue, httpconn->queue); - - g_free(queue_data->body); - g_free(queue_data); - } - - purple_circ_buffer_destroy(httpconn->tx_buf); - if (httpconn->tx_handler > 0) - purple_input_remove(httpconn->tx_handler); - - g_free(httpconn); -} - -static void -connect_cb(gpointer data, gint source, const gchar *error_message) -{ - MsnHttpConn *httpconn; - - httpconn = data; - httpconn->connect_data = NULL; - httpconn->fd = source; - - if (source >= 0) - { - httpconn->inpa = purple_input_add(httpconn->fd, PURPLE_INPUT_READ, - read_cb, data); - - httpconn->timer = purple_timeout_add_seconds(2, msn_httpconn_poll, httpconn); - - msn_httpconn_process_queue(httpconn); - } - else - { - purple_debug_error("msn", "HTTP: Connection error: %s\n", - error_message ? error_message : "(null)"); - msn_servconn_got_error(httpconn->servconn, MSN_SERVCONN_ERROR_CONNECT, error_message); - } -} - -gboolean -msn_httpconn_connect(MsnHttpConn *httpconn, const char *host, int port) -{ - g_return_val_if_fail(httpconn != NULL, FALSE); - g_return_val_if_fail(host != NULL, FALSE); - g_return_val_if_fail(port > 0, FALSE); - - if (httpconn->connected) - msn_httpconn_disconnect(httpconn); - - httpconn->connect_data = purple_proxy_connect(NULL, httpconn->session->account, - host, 80, connect_cb, httpconn); - - if (httpconn->connect_data != NULL) - { - httpconn->waiting_response = TRUE; - httpconn->connected = TRUE; - } - - return httpconn->connected; -} - -void -msn_httpconn_disconnect(MsnHttpConn *httpconn) -{ - g_return_if_fail(httpconn != NULL); - - if (!httpconn->connected) - return; - - if (httpconn->connect_data != NULL) - { - purple_proxy_connect_cancel(httpconn->connect_data); - httpconn->connect_data = NULL; - } - - if (httpconn->timer) - { - purple_timeout_remove(httpconn->timer); - httpconn->timer = 0; - } - - if (httpconn->inpa > 0) - { - purple_input_remove(httpconn->inpa); - httpconn->inpa = 0; - } - - close(httpconn->fd); - httpconn->fd = -1; - - g_free(httpconn->rx_buf); - httpconn->rx_buf = NULL; - httpconn->rx_len = 0; - - httpconn->connected = FALSE; - - /* msn_servconn_disconnect(httpconn->servconn); */ -} diff --git a/libpurple/protocols/msn/httpconn.h b/libpurple/protocols/msn/httpconn.h deleted file mode 100644 index 381a27b85c..0000000000 --- a/libpurple/protocols/msn/httpconn.h +++ /dev/null @@ -1,112 +0,0 @@ -/** - * @file httpconn.h HTTP connection - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_HTTPCONN_H -#define MSN_HTTPCONN_H - -typedef struct _MsnHttpConn MsnHttpConn; - -#include "circbuffer.h" -#include "servconn.h" -#include "session.h" - -/** - * An HTTP Connection. - */ -struct _MsnHttpConn -{ - MsnSession *session; /**< The MSN Session. */ - MsnServConn *servconn; /**< The connection object. */ - - PurpleProxyConnectData *connect_data; - - char *full_session_id; /**< The full session id. */ - char *session_id; /**< The trimmed session id. */ - - int timer; /**< The timer for polling. */ - - gboolean waiting_response; /**< The flag that states if we are waiting - a response from the server. */ - gboolean connected; /**< The flag that states if the connection is on. */ - gboolean virgin; /**< The flag that states if this connection - should specify the host (not gateway) to - connect to. */ - - char *host; /**< The HTTP gateway host. */ - GList *queue; /**< The queue of data chunks to write. */ - - int fd; /**< The connection's file descriptor. */ - guint inpa; /**< The connection's input handler. */ - - char *rx_buf; /**< The receive buffer. */ - int rx_len; /**< The receive buffer length. */ - - PurpleCircBuffer *tx_buf; - guint tx_handler; -}; - -/** - * Creates a new HTTP connection object. - * - * @param servconn The connection object. - * - * @return The new object. - */ -MsnHttpConn *msn_httpconn_new(MsnServConn *servconn); - -/** - * Destroys an HTTP connection object. - * - * @param httpconn The HTTP connection object. - */ -void msn_httpconn_destroy(MsnHttpConn *httpconn); - -/** - * Writes a chunk of data to the HTTP connection. - * - * @param servconn The server connection. - * @param data The data to write. - * @param data_len The size of the data to write. - * - * @return The number of bytes written. - */ -gssize msn_httpconn_write(MsnHttpConn *httpconn, const char *data, size_t data_len); - -/** - * Connects the HTTP connection object to a host. - * - * @param httpconn The HTTP connection object. - * @param host The host to connect to. - * @param port The port to connect to. - */ -gboolean msn_httpconn_connect(MsnHttpConn *httpconn, - const char *host, int port); - -/** - * Disconnects the HTTP connection object. - * - * @param httpconn The HTTP connection object. - */ -void msn_httpconn_disconnect(MsnHttpConn *httpconn); - -#endif /* MSN_HTTPCONN_H */ diff --git a/libpurple/protocols/msn/msg.c b/libpurple/protocols/msn/msg.c deleted file mode 100644 index 4f9727392c..0000000000 --- a/libpurple/protocols/msn/msg.c +++ /dev/null @@ -1,1217 +0,0 @@ -/** - * @file msg.c Message functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "debug.h" - -#include "msn.h" -#include "msg.h" -#include "msnutils.h" -#include "slpmsg.h" -#include "slpmsg_part.h" - -MsnMessage * -msn_message_new(MsnMsgType type) -{ - MsnMessage *msg; - - msg = g_new0(MsnMessage, 1); - msg->type = type; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "message new (%p)(%d)\n", msg, type); - - msg->header_table = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, g_free); - - msn_message_ref(msg); - - return msg; -} - -/** - * Destroys a message. - * - * @param msg The message to destroy. - */ -static void -msn_message_destroy(MsnMessage *msg) -{ - g_return_if_fail(msg != NULL); - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "message destroy (%p)\n", msg); - - g_free(msg->remote_user); - g_free(msg->body); - g_free(msg->content_type); - g_free(msg->charset); - - g_hash_table_destroy(msg->header_table); - g_list_free(msg->header_list); - if (msg->part) - msn_slpmsgpart_unref(msg->part); - - g_free(msg); -} - -MsnMessage * -msn_message_ref(MsnMessage *msg) -{ - g_return_val_if_fail(msg != NULL, NULL); - - msg->ref_count++; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "message ref (%p)[%u]\n", msg, msg->ref_count); - - return msg; -} - -void -msn_message_unref(MsnMessage *msg) -{ - g_return_if_fail(msg != NULL); - g_return_if_fail(msg->ref_count > 0); - - msg->ref_count--; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "message unref (%p)[%u]\n", msg, msg->ref_count); - - if (msg->ref_count == 0) - msn_message_destroy(msg); -} - -MsnMessage * -msn_message_new_plain(const char *message) -{ - MsnMessage *msg; - char *message_cr; - - msg = msn_message_new(MSN_MSG_TEXT); - msg->retries = 1; - msn_message_set_header(msg, "User-Agent", PACKAGE_NAME "/" VERSION); - msn_message_set_content_type(msg, "text/plain"); - msn_message_set_charset(msg, "UTF-8"); - msn_message_set_flag(msg, 'A'); - msn_message_set_header(msg, "X-MMS-IM-Format", - "FN=Segoe%20UI; EF=; CO=0; CS=1;PF=0"); - - message_cr = purple_str_add_cr(message); - msn_message_set_bin_data(msg, message_cr, strlen(message_cr)); - g_free(message_cr); - - return msg; -} - -MsnMessage * -msn_message_new_msnslp(void) -{ - MsnMessage *msg; - - msg = msn_message_new(MSN_MSG_SLP); - - msn_message_set_header(msg, "User-Agent", NULL); - - msn_message_set_flag(msg, 'D'); - msn_message_set_content_type(msg, "application/x-msnmsgrp2p"); - - return msg; -} - -MsnMessage * -msn_message_new_nudge(void) -{ - MsnMessage *msg; - - msg = msn_message_new(MSN_MSG_NUDGE); - msn_message_set_content_type(msg, "text/x-msnmsgr-datacast"); - msn_message_set_flag(msg, 'N'); - msn_message_set_bin_data(msg, "ID: 1\r\n", 7); - - return msg; -} - -void -msn_message_parse_payload(MsnMessage *msg, - const char *payload, size_t payload_len, - const char *line_dem,const char *body_dem) -{ - char *tmp_base, *tmp; - const char *content_type; - char *end; - char **elems, **cur, **tokens; - - g_return_if_fail(payload != NULL); - tmp_base = tmp = g_malloc(payload_len + 1); - memcpy(tmp_base, payload, payload_len); - tmp_base[payload_len] = '\0'; - - /* Find the end of the headers */ - end = strstr(tmp, body_dem); - /* TODO? some clients use \r delimiters instead of \r\n, the official client - * doesn't send such messages, but does handle receiving them. We'll just - * avoid crashing for now */ - if (end == NULL) { - g_free(tmp_base); - g_return_if_reached(); - } - - /* NUL-terminate the end of the headers - it'll get skipped over below */ - *end = '\0'; - - /* Split the headers and parse each one */ - elems = g_strsplit(tmp, line_dem, 0); - for (cur = elems; *cur != NULL; cur++) - { - const char *key, *value; - - /* If this line starts with whitespace, it's been folded from the - previous line and won't have ':'. */ - if ((**cur == ' ') || (**cur == '\t')) { - tokens = g_strsplit(g_strchug(*cur), "=\"", 2); - key = tokens[0]; - value = tokens[1]; - - /* The only one I care about is 'boundary' (which is folded from - the key 'Content-Type'), so only process that. */ - if (!strcmp(key, "boundary") && value) { - char *end = strchr(value, '\"'); - if (end) { - *end = '\0'; - msn_message_set_header(msg, key, value); - } - } - - g_strfreev(tokens); - continue; - } - - tokens = g_strsplit(*cur, ": ", 2); - - key = tokens[0]; - value = tokens[1]; - - if (!strcmp(key, "MIME-Version")) - { - /* Ignore MIME-Version header */ - } - else if (!strcmp(key, "Content-Type")) - { - char *charset, *c; - - if (value && (c = strchr(value, ';')) != NULL) - { - if ((charset = strchr(c, '=')) != NULL) - { - charset++; - msn_message_set_charset(msg, charset); - } - - *c = '\0'; - } - - msn_message_set_content_type(msg, value); - } - else - { - msn_message_set_header(msg, key, value); - } - - g_strfreev(tokens); - } - g_strfreev(elems); - - /* Proceed to the end of the "\r\n\r\n" */ - tmp = end + strlen(body_dem); - - /* Now we *should* be at the body. */ - content_type = msn_message_get_content_type(msg); - - if (payload_len - (tmp - tmp_base) > 0) { - msg->body_len = payload_len - (tmp - tmp_base); - g_free(msg->body); - msg->body = g_malloc(msg->body_len + 1); - memcpy(msg->body, tmp, msg->body_len); - msg->body[msg->body_len] = '\0'; - } - - if (msg->body && content_type && purple_str_has_prefix(content_type, "text/")) { - char *body = NULL; - - if (msg->charset == NULL || g_str_equal(msg->charset, "UTF-8")) { - /* Charset is UTF-8 */ - if (!g_utf8_validate(msg->body, msg->body_len, NULL)) { - purple_debug_warning("msn", "Message contains invalid " - "UTF-8. Attempting to salvage.\n"); - body = purple_utf8_salvage(msg->body); - payload_len = strlen(body); - } - } else { - /* Charset is something other than UTF-8 */ - GError *err = NULL; - body = g_convert(msg->body, msg->body_len, "UTF-8", - msg->charset, NULL, &payload_len, &err); - if (!body || err) { - purple_debug_warning("msn", "Unable to convert message from " - "%s to UTF-8: %s\n", msg->charset, - err ? err->message : "Unknown error"); - if (err) - g_error_free(err); - - /* Fallback to ISO-8859-1 */ - g_free(body); - body = g_convert(msg->body, msg->body_len, "UTF-8", - "ISO-8859-1", NULL, &payload_len, NULL); - if (!body) { - g_free(msg->body); - msg->body = NULL; - msg->body_len = 0; - } - } - } - - if (body) { - g_free(msg->body); - msg->body = body; - msg->body_len = payload_len; - msn_message_set_charset(msg, "UTF-8"); - } - } - - g_free(tmp_base); -} - -MsnMessage * -msn_message_new_from_cmd(MsnSession *session, MsnCommand *cmd) -{ - MsnMessage *msg; - - g_return_val_if_fail(cmd != NULL, NULL); - - msg = msn_message_new(MSN_MSG_UNKNOWN); - - msg->remote_user = g_strdup(cmd->params[0]); - /* msg->size = atoi(cmd->params[2]); */ - msg->cmd = cmd; - - return msg; -} - -char * -msn_message_gen_payload(MsnMessage *msg, size_t *ret_size) -{ - GList *l; - char *n, *base, *end; - int len; - size_t body_len = 0; - const void *body; - - g_return_val_if_fail(msg != NULL, NULL); - - len = MSN_BUF_LEN; - - base = n = end = g_malloc(len + 1); - end += len; - - /* Standard header. */ - if (msg->charset == NULL) - { - g_snprintf(n, len, - "MIME-Version: 1.0\r\n" - "Content-Type: %s\r\n", - msg->content_type); - } - else - { - g_snprintf(n, len, - "MIME-Version: 1.0\r\n" - "Content-Type: %s; charset=%s\r\n", - msg->content_type, msg->charset); - } - - n += strlen(n); - - for (l = msg->header_list; l != NULL; l = l->next) - { - const char *key; - const char *value; - - key = l->data; - value = msn_message_get_header_value(msg, key); - - g_snprintf(n, end - n, "%s: %s\r\n", key, value); - n += strlen(n); - } - - if ((end - n) > 2) - n += g_strlcpy(n, "\r\n", end - n); - - body = msn_message_get_bin_data(msg, &body_len); - - if (body != NULL && (end - n) > (gssize)body_len) - { - memcpy(n, body, body_len); - n += body_len; - *n = '\0'; - } - - if (ret_size != NULL) - { - *ret_size = n - base; - - if (*ret_size > 1664) - *ret_size = 1664; - } - - return base; -} - -void -msn_message_set_flag(MsnMessage *msg, char flag) -{ - g_return_if_fail(msg != NULL); - g_return_if_fail(flag != 0); - - msg->flag = flag; -} - -char -msn_message_get_flag(const MsnMessage *msg) -{ - g_return_val_if_fail(msg != NULL, 0); - - return msg->flag; -} - -void -msn_message_set_bin_data(MsnMessage *msg, const void *data, size_t len) -{ - g_return_if_fail(msg != NULL); - - /* There is no need to waste memory on data we cannot send anyway */ - if (len > 1664) - len = 1664; - - if (msg->body != NULL) - g_free(msg->body); - - if (data != NULL && len > 0) - { - msg->body = g_malloc(len + 1); - memcpy(msg->body, data, len); - msg->body[len] = '\0'; - msg->body_len = len; - } - else - { - msg->body = NULL; - msg->body_len = 0; - } -} - -const void * -msn_message_get_bin_data(const MsnMessage *msg, size_t *len) -{ - g_return_val_if_fail(msg != NULL, NULL); - - if (len) - *len = msg->body_len; - - return msg->body; -} - -void -msn_message_set_content_type(MsnMessage *msg, const char *type) -{ - g_return_if_fail(msg != NULL); - - g_free(msg->content_type); - msg->content_type = g_strdup(type); -} - -const char * -msn_message_get_content_type(const MsnMessage *msg) -{ - g_return_val_if_fail(msg != NULL, NULL); - - return msg->content_type; -} - -void -msn_message_set_charset(MsnMessage *msg, const char *charset) -{ - g_return_if_fail(msg != NULL); - - g_free(msg->charset); - msg->charset = g_strdup(charset); -} - -const char * -msn_message_get_charset(const MsnMessage *msg) -{ - g_return_val_if_fail(msg != NULL, NULL); - - return msg->charset; -} - -void -msn_message_set_header(MsnMessage *msg, const char *name, const char *value) -{ - const char *temp; - char *new_name; - - g_return_if_fail(msg != NULL); - g_return_if_fail(name != NULL); - - temp = msn_message_get_header_value(msg, name); - - if (value == NULL) - { - if (temp != NULL) - { - GList *l; - - for (l = msg->header_list; l != NULL; l = l->next) - { - if (!g_ascii_strcasecmp(l->data, name)) - { - msg->header_list = g_list_remove(msg->header_list, l->data); - - break; - } - } - - g_hash_table_remove(msg->header_table, name); - } - - return; - } - - new_name = g_strdup(name); - - g_hash_table_insert(msg->header_table, new_name, g_strdup(value)); - - if (temp == NULL) - msg->header_list = g_list_append(msg->header_list, new_name); -} - -const char * -msn_message_get_header_value(const MsnMessage *msg, const char *name) -{ - g_return_val_if_fail(msg != NULL, NULL); - g_return_val_if_fail(name != NULL, NULL); - - return g_hash_table_lookup(msg->header_table, name); -} - -GHashTable * -msn_message_get_hashtable_from_body(const MsnMessage *msg) -{ - GHashTable *table; - size_t body_len; - const char *body; - char **elems, **cur, **tokens, *body_str; - - g_return_val_if_fail(msg != NULL, NULL); - - table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - - body = msn_message_get_bin_data(msg, &body_len); - - g_return_val_if_fail(body != NULL, NULL); - - body_str = g_strndup(body, body_len); - elems = g_strsplit(body_str, "\r\n", 0); - g_free(body_str); - - for (cur = elems; *cur != NULL; cur++) - { - if (**cur == '\0') - break; - - tokens = g_strsplit(*cur, ": ", 2); - - if (tokens[0] != NULL && tokens[1] != NULL) { - g_hash_table_insert(table, tokens[0], tokens[1]); - g_free(tokens); - } else - g_strfreev(tokens); - } - - g_strfreev(elems); - - return table; -} - -char * -msn_message_to_string(MsnMessage *msg) -{ - size_t body_len; - const char *body; - - g_return_val_if_fail(msg != NULL, NULL); - g_return_val_if_fail(msg->type == MSN_MSG_TEXT, NULL); - - body = msn_message_get_bin_data(msg, &body_len); - - return g_strndup(body, body_len); -} - -void -msn_message_show_readable(MsnMessage *msg, const char *info, - gboolean text_body) -{ - GString *str; - size_t body_len; - const char *body; - GList *l; - - g_return_if_fail(msg != NULL); - - str = g_string_new(NULL); - - /* Standard header. */ - if (msg->charset == NULL) - { - g_string_append_printf(str, - "MIME-Version: 1.0\r\n" - "Content-Type: %s\r\n", - msg->content_type); - } - else - { - g_string_append_printf(str, - "MIME-Version: 1.0\r\n" - "Content-Type: %s; charset=%s\r\n", - msg->content_type, msg->charset); - } - - for (l = msg->header_list; l; l = l->next) - { - char *key; - const char *value; - - key = l->data; - value = msn_message_get_header_value(msg, key); - - g_string_append_printf(str, "%s: %s\r\n", key, value); - } - - g_string_append(str, "\r\n"); - - body = msn_message_get_bin_data(msg, &body_len); - - if (body != NULL) - { - if (msg->type == MSN_MSG_TEXT) - { - g_string_append_len(str, body, body_len); - g_string_append(str, "\r\n"); - } - else - { - size_t i; - for (i = 0; i < body_len; i++, body++) - { - g_string_append_printf(str, "%02x ", (unsigned char)*body); - if (i % 16 == 0 && i != 0) - g_string_append_c(str, '\n'); - } - g_string_append_c(str, '\n'); - } - } - - purple_debug_info("msn", "Message %s:\n{%s}\n", info, str->str); - - g_string_free(str, TRUE); -} - -/************************************************************************** - * Message Handlers - **************************************************************************/ -void -msn_plain_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - PurpleConnection *gc; - const char *body; - char *body_enc; - char *body_final; - size_t body_len; - const char *passport; - const char *value; - - gc = cmdproc->session->account->gc; - - body = msn_message_get_bin_data(msg, &body_len); - body_enc = g_markup_escape_text(body, body_len); - - passport = msg->remote_user; - - if (!strcmp(passport, "messenger@microsoft.com") && - strstr(body, "immediate security update")) - { - return; - } - -#if 0 - if ((value = msn_message_get_header_value(msg, "User-Agent")) != NULL) - { - purple_debug_misc("msn", "User-Agent = '%s'\n", value); - } -#endif - - if ((value = msn_message_get_header_value(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; - } - - if (cmdproc->servconn->type == MSN_SERVCONN_SB) { - MsnSwitchBoard *swboard = cmdproc->data; - - swboard->flag |= MSN_SB_FLAG_IM; - - if (swboard->current_users > 1 || - ((swboard->conv != NULL) && - purple_conversation_get_type(swboard->conv) == PURPLE_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) - purple_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 = purple_find_chat(gc, swboard->chat_id); - swboard->flag |= MSN_SB_FLAG_IM; - } - } - else if (!g_str_equal(passport, purple_account_get_username(gc->account))) - { - /* Don't im ourselves ... */ - serv_got_im(gc, passport, body_final, 0, time(NULL)); - if (swboard->conv == NULL) - { - swboard->conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, - passport, purple_connection_get_account(gc)); - swboard->flag |= MSN_SB_FLAG_IM; - } - } - - } else { - serv_got_im(gc, passport, body_final, 0, time(NULL)); - } - - g_free(body_final); -} - -void -msn_control_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - PurpleConnection *gc; - char *passport; - - gc = cmdproc->session->account->gc; - passport = msg->remote_user; - - if (msn_message_get_header_value(msg, "TypingUser") == NULL) - return; - - if (cmdproc->servconn->type == MSN_SERVCONN_SB) { - MsnSwitchBoard *swboard = cmdproc->data; - - if (swboard->current_users == 1) - { - serv_got_typing(gc, passport, MSN_TYPING_RECV_TIMEOUT, - PURPLE_TYPING); - } - - } else { - serv_got_typing(gc, passport, MSN_TYPING_RECV_TIMEOUT, - PURPLE_TYPING); - } -} - -static void -datacast_inform_user(MsnSwitchBoard *swboard, const char *who, - const char *msg, const char *filename) -{ - char *username, *str; - PurpleAccount *account; - PurpleBuddy *b; - PurpleConnection *pc; - gboolean chat; - - account = swboard->session->account; - pc = purple_account_get_connection(account); - - if ((b = purple_find_buddy(account, who)) != NULL) - username = g_markup_escape_text(purple_buddy_get_alias(b), -1); - else - username = g_markup_escape_text(who, -1); - str = g_strdup_printf(msg, username, filename); - g_free(username); - - swboard->flag |= MSN_SB_FLAG_IM; - if (swboard->current_users > 1) - chat = TRUE; - else - chat = FALSE; - - if (swboard->conv == NULL) { - if (chat) - swboard->conv = purple_find_chat(account->gc, swboard->chat_id); - else { - swboard->conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, - who, account); - if (swboard->conv == NULL) - swboard->conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, who); - } - } - - if (chat) - serv_got_chat_in(pc, - purple_conv_chat_get_id(PURPLE_CONV_CHAT(swboard->conv)), - who, PURPLE_MESSAGE_RECV|PURPLE_MESSAGE_SYSTEM, str, - time(NULL)); - else - serv_got_im(pc, who, str, PURPLE_MESSAGE_RECV|PURPLE_MESSAGE_SYSTEM, - time(NULL)); - g_free(str); - -} - -/* TODO: Make these not be such duplicates of each other */ -static void -got_wink_cb(MsnSlpCall *slpcall, const guchar *data, gsize size) -{ - FILE *f = NULL; - char *path = NULL; - const char *who = slpcall->slplink->remote_user; - purple_debug_info("msn", "Received wink from %s\n", who); - - if ((f = purple_mkstemp(&path, TRUE)) && - (fwrite(data, 1, size, f) == size)) { - datacast_inform_user(slpcall->slplink->swboard, - who, - _("%s sent a wink. <a href='msn-wink://%s'>Click here to play it</a>"), - path); - } else { - purple_debug_error("msn", "Couldn\'t create temp file to store wink\n"); - datacast_inform_user(slpcall->slplink->swboard, - who, - _("%s sent a wink, but it could not be saved"), - NULL); - } - if (f) - fclose(f); - g_free(path); -} - -static void -got_voiceclip_cb(MsnSlpCall *slpcall, const guchar *data, gsize size) -{ - FILE *f = NULL; - char *path = NULL; - const char *who = slpcall->slplink->remote_user; - purple_debug_info("msn", "Received voice clip from %s\n", who); - - if ((f = purple_mkstemp(&path, TRUE)) && - (fwrite(data, 1, size, f) == size)) { - datacast_inform_user(slpcall->slplink->swboard, - who, - _("%s sent a voice clip. <a href='audio://%s'>Click here to play it</a>"), - path); - } else { - purple_debug_error("msn", "Couldn\'t create temp file to store sound\n"); - datacast_inform_user(slpcall->slplink->swboard, - who, - _("%s sent a voice clip, but it could not be saved"), - NULL); - } - if (f) - fclose(f); - g_free(path); -} - -void -msn_p2p_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - MsnSession *session; - MsnSlpLink *slplink; - MsnP2PVersion p2p; - - session = cmdproc->servconn->session; - slplink = msn_session_get_slplink(session, msg->remote_user); - - if (slplink->swboard == NULL) - { - /* - * We will need swboard in order to change its flags. If its - * NULL, something has probably gone wrong earlier on. I - * didn't want to do this, but MSN 7 is somehow causing us - * to crash here, I couldn't reproduce it to debug more, - * and people are reporting bugs. Hopefully this doesn't - * cause more crashes. Stu. - */ - if (cmdproc->data == NULL) - g_warning("msn_p2p_msg cmdproc->data was NULL\n"); - else { - slplink->swboard = (MsnSwitchBoard *)cmdproc->data; - slplink->swboard->slplinks = g_list_prepend(slplink->swboard->slplinks, slplink); - } - } - - p2p = msn_slplink_get_p2p_version(slplink); - msg->part = msn_slpmsgpart_new_from_data(p2p, msg->body, msg->body_len); - - if (msg->part) - msn_slplink_process_msg(slplink, msg->part); - else - purple_debug_warning("msn", "P2P message failed to parse.\n"); -} - -static void -got_emoticon(MsnSlpCall *slpcall, - const guchar *data, gsize size) -{ - PurpleConversation *conv; - MsnSwitchBoard *swboard; - - swboard = slpcall->slplink->swboard; - conv = swboard->conv; - - if (conv) { - /* FIXME: it would be better if we wrote the data as we received it - instead of all at once, calling write multiple times and - close once at the very end - */ - purple_conv_custom_smiley_write(conv, slpcall->data_info, data, size); - purple_conv_custom_smiley_close(conv, slpcall->data_info ); - } - if (purple_debug_is_verbose()) - purple_debug_info("msn", "Got smiley: %s\n", slpcall->data_info); -} - -void msn_emoticon_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - MsnSession *session; - MsnSlpLink *slplink; - MsnSwitchBoard *swboard; - MsnObject *obj; - char **tokens; - char *smile, *body_str; - const char *body, *who, *sha1; - guint tok; - size_t body_len; - - PurpleConversation *conv; - - session = cmdproc->servconn->session; - - if (!purple_account_get_bool(session->account, "custom_smileys", TRUE)) - return; - - swboard = cmdproc->data; - conv = swboard->conv; - - body = msn_message_get_bin_data(msg, &body_len); - if (!body || !body_len) - return; - body_str = g_strndup(body, body_len); - - /* MSN Messenger 7 may send more than one MSNObject in a single message... - * Maybe 10 tokens is a reasonable max value. */ - tokens = g_strsplit(body_str, "\t", 10); - - g_free(body_str); - - for (tok = 0; tok < 9; tok += 2) { - if (tokens[tok] == NULL || tokens[tok + 1] == NULL) { - break; - } - - smile = tokens[tok]; - obj = msn_object_new_from_string(purple_url_decode(tokens[tok + 1])); - - if (obj == NULL) - break; - - who = msn_object_get_creator(obj); - sha1 = msn_object_get_sha1(obj); - - slplink = msn_session_get_slplink(session, who); - if (slplink->swboard != swboard) { - if (slplink->swboard != NULL) - /* - * Apparently we're using a different switchboard now or - * something? I don't know if this is normal, but it - * definitely happens. So make sure the old switchboard - * doesn't still have a reference to us. - */ - slplink->swboard->slplinks = g_list_remove(slplink->swboard->slplinks, slplink); - slplink->swboard = swboard; - slplink->swboard->slplinks = g_list_prepend(slplink->swboard->slplinks, slplink); - } - - /* If the conversation doesn't exist then this is a custom smiley - * used in the first message in a MSN conversation: we need to create - * the conversation now, otherwise the custom smiley won't be shown. - * This happens because every GtkIMHtml has its own smiley tree: if - * the conversation doesn't exist then we cannot associate the new - * smiley with its GtkIMHtml widget. */ - if (!conv) { - conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, session->account, who); - } - - if (purple_conv_custom_smiley_add(conv, smile, "sha1", sha1, TRUE)) { - msn_slplink_request_object(slplink, smile, got_emoticon, NULL, obj); - } - - msn_object_destroy(obj); - obj = NULL; - who = NULL; - sha1 = NULL; - } - g_strfreev(tokens); -} - -void -msn_datacast_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - GHashTable *body; - const char *id; - body = msn_message_get_hashtable_from_body(msg); - - id = g_hash_table_lookup(body, "ID"); - - if (!strcmp(id, "1")) { - /* Nudge */ - PurpleAccount *account; - const char *user; - - account = cmdproc->session->account; - user = msg->remote_user; - - if (cmdproc->servconn->type == MSN_SERVCONN_SB) { - MsnSwitchBoard *swboard = cmdproc->data; - if (swboard->current_users > 1 || - ((swboard->conv != NULL) && - purple_conversation_get_type(swboard->conv) == PURPLE_CONV_TYPE_CHAT)) - purple_prpl_got_attention_in_chat(account->gc, swboard->chat_id, user, MSN_NUDGE); - - else - purple_prpl_got_attention(account->gc, user, MSN_NUDGE); - } else { - purple_prpl_got_attention(account->gc, user, MSN_NUDGE); - } - - } else if (!strcmp(id, "2")) { - /* Wink */ - MsnSession *session; - MsnSlpLink *slplink; - MsnObject *obj; - const char *who; - const char *data; - - session = cmdproc->session; - - data = g_hash_table_lookup(body, "Data"); - obj = msn_object_new_from_string(data); - who = msn_object_get_creator(obj); - - slplink = msn_session_get_slplink(session, who); - msn_slplink_request_object(slplink, data, got_wink_cb, NULL, obj); - - msn_object_destroy(obj); - - - } else if (!strcmp(id, "3")) { - /* Voiceclip */ - MsnSession *session; - MsnSlpLink *slplink; - MsnObject *obj; - const char *who; - const char *data; - - session = cmdproc->session; - - data = g_hash_table_lookup(body, "Data"); - obj = msn_object_new_from_string(data); - who = msn_object_get_creator(obj); - - slplink = msn_session_get_slplink(session, who); - msn_slplink_request_object(slplink, data, got_voiceclip_cb, NULL, obj); - - msn_object_destroy(obj); - - } else if (!strcmp(id, "4")) { - /* Action */ - - } else { - purple_debug_warning("msn", "Got unknown datacast with ID %s.\n", id); - } - - g_hash_table_destroy(body); -} - -void -msn_invite_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - GHashTable *body; - const gchar *command; - const gchar *cookie; - gboolean accepted = FALSE; - - g_return_if_fail(cmdproc != NULL); - g_return_if_fail(msg != NULL); - - body = msn_message_get_hashtable_from_body(msg); - - if (body == NULL) { - purple_debug_warning("msn", - "Unable to parse invite msg body.\n"); - return; - } - - /* - * GUID is NOT always present but Invitation-Command and Invitation-Cookie - * are mandatory. - */ - command = g_hash_table_lookup(body, "Invitation-Command"); - cookie = g_hash_table_lookup(body, "Invitation-Cookie"); - - if (command == NULL || cookie == NULL) { - purple_debug_warning("msn", - "Invalid invitation message: either Invitation-Command " - "or Invitation-Cookie is missing or invalid.\n" - ); - return; - - } else if (!strcmp(command, "INVITE")) { - const gchar *guid = g_hash_table_lookup(body, "Application-GUID"); - - if (guid == NULL) { - purple_debug_warning("msn", - "Invite msg missing Application-GUID.\n"); - - accepted = TRUE; - - } else if (!strcmp(guid, MSN_FT_GUID)) { - - } else if (!strcmp(guid, "{02D3C01F-BF30-4825-A83A-DE7AF41648AA}")) { - purple_debug_info("msn", "Computer call\n"); - - if (cmdproc->session) { - PurpleConversation *conv = NULL; - gchar *from = msg->remote_user; - gchar *buf = NULL; - - if (from) - conv = purple_find_conversation_with_account( - PURPLE_CONV_TYPE_IM, from, - cmdproc->session->account); - if (conv) - buf = g_strdup_printf( - _("%s sent you a voice chat " - "invite, which is not yet " - "supported."), from); - if (buf) { - purple_conversation_write(conv, NULL, buf, - PURPLE_MESSAGE_SYSTEM | - PURPLE_MESSAGE_NOTIFY, - time(NULL)); - g_free(buf); - } - } - } else { - const gchar *application = g_hash_table_lookup(body, "Application-Name"); - purple_debug_warning("msn", "Unhandled invite msg with GUID %s: %s.\n", - guid, application ? application : "(null)"); - } - - if (!accepted) { - MsnSwitchBoard *swboard = cmdproc->data; - char *text; - MsnMessage *cancel; - - cancel = msn_message_new(MSN_MSG_TEXT); - msn_message_set_content_type(cancel, "text/x-msmsgsinvite"); - msn_message_set_charset(cancel, "UTF-8"); - msn_message_set_flag(cancel, 'U'); - - text = g_strdup_printf("Invitation-Command: CANCEL\r\n" - "Invitation-Cookie: %s\r\n" - "Cancel-Code: REJECT_NOT_INSTALLED\r\n", - cookie); - msn_message_set_bin_data(cancel, text, strlen(text)); - g_free(text); - - msn_switchboard_send_msg(swboard, cancel, TRUE); - msn_message_unref(cancel); - } - - } else if (!strcmp(command, "CANCEL")) { - const gchar *code = g_hash_table_lookup(body, "Cancel-Code"); - purple_debug_info("msn", "MSMSGS invitation cancelled: %s.\n", - code ? code : "no reason given"); - - } else { - /* - * Some other already established invitation session. - * Can be retrieved by Invitation-Cookie. - */ - } - - g_hash_table_destroy(body); -} - -/* Only called from chats. Handwritten messages for IMs come as a SLP message */ -void -msn_handwritten_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - const char *body; - size_t body_len; - - body = msn_message_get_bin_data(msg, &body_len); - msn_switchboard_show_ink(cmdproc->data, msg->remote_user, body); -} - diff --git a/libpurple/protocols/msn/msg.h b/libpurple/protocols/msn/msg.h deleted file mode 100644 index 845a839466..0000000000 --- a/libpurple/protocols/msn/msg.h +++ /dev/null @@ -1,325 +0,0 @@ -/** - * @file msg.h Message functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_MSG_H -#define MSN_MSG_H - -typedef struct _MsnMessage MsnMessage; - -/* -typedef enum -{ - MSN_MSG_NORMAL, - MSN_MSG_SLP_SB, - MSN_MSG_SLP_DC -} MsnMsgType; -*/ - -typedef enum -{ - MSN_MSG_UNKNOWN, - MSN_MSG_TEXT, - MSN_MSG_TYPING, - MSN_MSG_CAPS, - MSN_MSG_SLP, - MSN_MSG_NUDGE -} MsnMsgType; - -typedef enum -{ - MSN_MSG_ERROR_NONE, /**< No error. */ - MSN_MSG_ERROR_TIMEOUT, /**< The message timedout. */ - MSN_MSG_ERROR_NAK, /**< The message could not be sent. */ - MSN_MSG_ERROR_SB, /**< The error comes from the switchboard. */ - MSN_MSG_ERROR_UNKNOWN /**< An unknown error occurred. */ -} MsnMsgErrorType; - -#include "command.h" -#include "session.h" -#include "transaction.h" -#include "user.h" -#include "slpmsg.h" -#include "slpmsg_part.h" - -typedef void (*MsnMsgCb)(MsnMessage *, void *data); - -#define MSG_BODY_DEM "\r\n\r\n" -#define MSG_LINE_DEM "\r\n" - -#define MSG_OIM_BODY_DEM "\n\n" -#define MSG_OIM_LINE_DEM "\n" - -/** - * A message. - */ -struct _MsnMessage -{ - guint ref_count; /**< The reference count. */ - - MsnMsgType type; - - MsnSlpMessagePart *part; - - char *remote_user; - char flag; - - char *content_type; - char *charset; - char *body; - gsize body_len; - guint total_chunks; /**< How many chunks in this multi-part message */ - guint received_chunks; /**< How many chunks we've received so far */ - - GHashTable *header_table; - GList *header_list; - - gboolean ack_ref; /**< A flag that states if this message has - been ref'ed for using it in a callback. */ - - MsnCommand *cmd; - - MsnMsgCb ack_cb; /**< The callback to call when we receive an ACK of this - message. */ - MsnMsgCb nak_cb; /**< The callback to call when we receive a NAK of this - message. */ - void *ack_data; /**< The data used by callbacks. */ - - guint32 retries; -}; - -/** - * Creates a new, empty message. - * - * @return A new message. - */ -MsnMessage *msn_message_new(MsnMsgType type); - -/** - * Creates a new, empty MSNSLP message. - * - * @return A new MSNSLP message. - */ -MsnMessage *msn_message_new_msnslp(void); - -/** - * Creates a new nudge message. - * - * @return A new nudge message. - */ -MsnMessage *msn_message_new_nudge(void); - -/** - * Creates a new plain message. - * - * @return A new plain message. - */ -MsnMessage *msn_message_new_plain(const char *message); - -/** - * Creates a new message based off a command. - * - * @param session The MSN session. - * @param cmd The command. - * - * @return The new message. - */ -MsnMessage *msn_message_new_from_cmd(MsnSession *session, MsnCommand *cmd); - -/** - * Parses the payload of a message. - * - * @param msg The message. - * @param payload The payload. - * @param payload_len The length of the payload. - */ -void msn_message_parse_payload(MsnMessage *msg, const char *payload, - size_t payload_len, - const char *line_dem,const char *body_dem); - -/** - * Increments the reference count on a message. - * - * @param msg The message. - * - * @return @a msg - */ -MsnMessage *msn_message_ref(MsnMessage *msg); - -/** - * Decrements the reference count on a message. - * - * This will destroy the structure if the count hits 0. - * - * @param msg The message. - * - * @return @a msg, or @c NULL if the new count is 0. - */ -void msn_message_unref(MsnMessage *msg); - -/** - * Generates the payload data of a message. - * - * @param msg The message. - * @param ret_size The returned size of the payload. - * - * @return The payload data of the message. - */ -char *msn_message_gen_payload(MsnMessage *msg, size_t *ret_size); - -/** - * Sets the flag for an outgoing message. - * - * @param msg The message. - * @param flag The flag. - */ -void msn_message_set_flag(MsnMessage *msg, char flag); - -/** - * Returns the flag for an outgoing message. - * - * @param msg The message. - * - * @return The flag. - */ -char msn_message_get_flag(const MsnMessage *msg); - -/** - * Sets the binary content of the message. - * - * @param msg The message. - * @param data The binary data. - * @param len The length of the data. - */ -void msn_message_set_bin_data(MsnMessage *msg, const void *data, size_t len); - -/** - * Returns the binary content of the message. - * - * @param msg The message. - * @param len The returned length of the data. - * - * @return The binary data. - */ -const void *msn_message_get_bin_data(const MsnMessage *msg, size_t *len); - -/** - * Sets the content type in a message. - * - * @param msg The message. - * @param type The content-type. - */ -void msn_message_set_content_type(MsnMessage *msg, const char *type); - -/** - * Returns the content type in a message. - * - * @param msg The message. - * - * @return The content-type. - */ -const char *msn_message_get_content_type(const MsnMessage *msg); - -/** - * Sets the charset in a message. - * - * @param msg The message. - * @param charset The charset. - */ -void msn_message_set_charset(MsnMessage *msg, const char *charset); - -/** - * Returns the charset in a message. - * - * @param msg The message. - * - * @return The charset. - */ -const char *msn_message_get_charset(const MsnMessage *msg); - -/** - * Sets a header in a message. - * - * @param msg The message. - * @param header The header name. - * @param value The header value. - */ -void msn_message_set_header(MsnMessage *msg, const char *name, - const char *value); - -/** - * Returns the value of a header from a message. - * - * @param msg The message. - * @param header The header value. - * - * @return The value, or @c NULL if not found. - */ -const char *msn_message_get_header_value(const MsnMessage *msg, const char *name); - -/** - * Parses the body and returns it in the form of a hashtable. - * - * @param msg The message. - * - * @return The resulting hashtable. - */ -GHashTable *msn_message_get_hashtable_from_body(const MsnMessage *msg); - -void msn_message_show_readable(MsnMessage *msg, const char *info, - gboolean text_body); - -char *msn_message_to_string(MsnMessage *msg); - -void msn_plain_msg(MsnCmdProc *cmdproc, MsnMessage *msg); - -void msn_control_msg(MsnCmdProc *cmdproc, MsnMessage *msg); - -/** - * Processes peer to peer messages. - * - * @param cmdproc The command processor. - * @param msg The message. - */ -void msn_p2p_msg(MsnCmdProc *cmdproc, MsnMessage *msg); - -/** - * Processes emoticon messages. - * - * @param cmdproc The command processor. - * @param msg The message. - */ -void msn_emoticon_msg(MsnCmdProc *cmdproc, MsnMessage *msg); - -void msn_datacast_msg(MsnCmdProc *cmdproc, MsnMessage *msg); - -/** - * Processes INVITE messages. - * - * @param cmdproc The command processor. - * @param msg The message. - */ -void msn_invite_msg(MsnCmdProc *cmdproc, MsnMessage *msg); - -void msn_handwritten_msg(MsnCmdProc *cmdproc, MsnMessage *msg); - -#endif /* MSN_MSG_H */ diff --git a/libpurple/protocols/msn/msn.c b/libpurple/protocols/msn/msn.c deleted file mode 100644 index 09ead6b945..0000000000 --- a/libpurple/protocols/msn/msn.c +++ /dev/null @@ -1,3069 +0,0 @@ -/** - * @file msn.c The MSN protocol plugin - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#define PHOTO_SUPPORT 1 - -#include "internal.h" - -#include "debug.h" -#include "request.h" - -#include "accountopt.h" -#include "contact.h" -#include "msg.h" -#include "page.h" -#include "pluginpref.h" -#include "prefs.h" -#include "session.h" -#include "smiley.h" -#include "state.h" -#include "util.h" -#include "cmds.h" -#include "core.h" -#include "prpl.h" -#include "msnutils.h" -#include "version.h" - -#include "error.h" -#include "msg.h" -#include "switchboard.h" -#include "notification.h" -#include "slplink.h" - -#if PHOTO_SUPPORT -#define MAX_HTTP_BUDDYICON_BYTES (200 * 1024) -#include "imgstore.h" -#endif - -typedef struct -{ - PurpleConnection *gc; - const char *passport; - -} MsnMobileData; - -typedef struct -{ - PurpleConnection *gc; - char *name; - -} MsnGetInfoData; - -typedef struct -{ - MsnGetInfoData *info_data; - char *stripped; - char *url_buffer; - PurpleNotifyUserInfo *user_info; - char *photo_url_text; - -} MsnGetInfoStepTwoData; - -typedef struct -{ - PurpleConnection *gc; - const char *who; - char *msg; - PurpleMessageFlags flags; - time_t when; -} MsnIMData; - -typedef struct -{ - char *smile; - PurpleSmiley *ps; - MsnObject *obj; -} MsnEmoticon; - -static const char * -msn_normalize(const PurpleAccount *account, const char *str) -{ - static char buf[BUF_LEN]; - char *tmp; - - g_return_val_if_fail(str != NULL, NULL); - - tmp = g_strchomp(g_utf8_strdown(str, -1)); - g_snprintf(buf, sizeof(buf), "%s%s", tmp, - (strchr(tmp, '@') ? "" : "@hotmail.com")); - g_free(tmp); - - return buf; -} - -static gboolean -msn_send_attention(PurpleConnection *gc, const char *username, guint type) -{ - MsnMessage *msg; - MsnSession *session; - MsnSwitchBoard *swboard; - - msg = msn_message_new_nudge(); - session = gc->proto_data; - swboard = msn_session_get_swboard(session, username, MSN_SB_FLAG_IM); - - msn_switchboard_send_msg(swboard, msg, TRUE); - msn_message_unref(msg); - - return TRUE; -} - -static GList * -msn_attention_types(PurpleAccount *account) -{ - static GList *list = NULL; - - if (!list) { - list = g_list_append(list, purple_attention_type_new("Nudge", _("Nudge"), - _("%s has nudged you!"), _("Nudging %s..."))); - } - - return list; -} - -static GHashTable * -msn_get_account_text_table(PurpleAccount *unused) -{ - GHashTable *table; - - table = g_hash_table_new(g_str_hash, g_str_equal); - - g_hash_table_insert(table, "login_label", (gpointer)_("Email Address...")); - - return table; -} - -static PurpleCmdRet -msn_cmd_nudge(PurpleConversation *conv, const gchar *cmd, gchar **args, gchar **error, void *data) -{ - PurpleAccount *account = purple_conversation_get_account(conv); - PurpleConnection *gc = purple_account_get_connection(account); - const gchar *username; - - username = purple_conversation_get_name(conv); - - purple_prpl_send_attention(gc, username, MSN_NUDGE); - - return PURPLE_CMD_RET_OK; -} - -struct public_alias_closure -{ - PurpleAccount *account; - gpointer success_cb; - gpointer failure_cb; -}; - -static gboolean -set_public_alias_length_error(gpointer data) -{ - struct public_alias_closure *closure = data; - PurpleSetPublicAliasFailureCallback failure_cb = closure->failure_cb; - - failure_cb(closure->account, _("Your new MSN friendly name is too long.")); - g_free(closure); - - return FALSE; -} - -static void -prp_success_cb(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - const char *type, *friendlyname; - struct public_alias_closure *closure; - - g_return_if_fail(cmd->param_count >= 3); - type = cmd->params[1]; - g_return_if_fail(!strcmp(type, "MFN")); - - closure = cmd->trans->data; - friendlyname = purple_url_decode(cmd->params[2]); - - msn_update_contact(cmdproc->session, "Me", MSN_UPDATE_DISPLAY, friendlyname); - - purple_connection_set_display_name( - purple_account_get_connection(closure->account), - friendlyname); - purple_account_set_string(closure->account, "display-name", friendlyname); - - if (closure->success_cb) { - PurpleSetPublicAliasSuccessCallback success_cb = closure->success_cb; - success_cb(closure->account, friendlyname); - } -} - -static void -prp_error_cb(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) -{ - struct public_alias_closure *closure = trans->data; - PurpleSetPublicAliasFailureCallback failure_cb = closure->failure_cb; - gboolean debug; - const char *error_text; - - error_text = msn_error_get_text(error, &debug); - failure_cb(closure->account, error_text); -} - -static void -prp_timeout_cb(MsnCmdProc *cmdproc, MsnTransaction *trans) -{ - struct public_alias_closure *closure = trans->data; - PurpleSetPublicAliasFailureCallback failure_cb = closure->failure_cb; - failure_cb(closure->account, _("Connection Timeout")); -} - -void -msn_set_public_alias(PurpleConnection *pc, const char *alias, - PurpleSetPublicAliasSuccessCallback success_cb, - PurpleSetPublicAliasFailureCallback failure_cb) -{ - MsnCmdProc *cmdproc; - MsnSession *session; - MsnTransaction *trans; - PurpleAccount *account; - char real_alias[BUDDY_ALIAS_MAXLEN + 1]; - struct public_alias_closure *closure; - - session = purple_connection_get_protocol_data(pc); - cmdproc = session->notification->cmdproc; - account = purple_connection_get_account(pc); - - if (alias && *alias) { - if (!msn_encode_spaces(alias, real_alias, BUDDY_ALIAS_MAXLEN + 1)) { - if (failure_cb) { - struct public_alias_closure *closure = - g_new0(struct public_alias_closure, 1); - closure->account = account; - closure->failure_cb = failure_cb; - purple_timeout_add(0, set_public_alias_length_error, closure); - } else { - purple_notify_error(pc, NULL, - _("Your new MSN friendly name is too long."), - NULL); - } - return; - } - - if (real_alias[0] == '\0') - g_strlcpy(real_alias, purple_account_get_username(account), sizeof(real_alias)); - } else - g_strlcpy(real_alias, purple_account_get_username(account), sizeof(real_alias)); - - closure = g_new0(struct public_alias_closure, 1); - closure->account = account; - closure->success_cb = success_cb; - closure->failure_cb = failure_cb; - - trans = msn_transaction_new(cmdproc, "PRP", "MFN %s", real_alias); - msn_transaction_set_data(trans, closure); - msn_transaction_set_data_free(trans, g_free); - msn_transaction_add_cb(trans, "PRP", prp_success_cb); - if (failure_cb) { - msn_transaction_set_error_cb(trans, prp_error_cb); - msn_transaction_set_timeout_cb(trans, prp_timeout_cb); - } - msn_cmdproc_send_trans(cmdproc, trans); -} - -static gboolean -get_public_alias_cb(gpointer data) -{ - struct public_alias_closure *closure = data; - PurpleGetPublicAliasSuccessCallback success_cb = closure->success_cb; - const char *alias; - - alias = purple_account_get_string(closure->account, "display-name", - purple_account_get_username(closure->account)); - success_cb(closure->account, alias); - g_free(closure); - - return FALSE; -} - -static void -msn_get_public_alias(PurpleConnection *pc, - PurpleGetPublicAliasSuccessCallback success_cb, - PurpleGetPublicAliasFailureCallback failure_cb) -{ - struct public_alias_closure *closure = g_new0(struct public_alias_closure, 1); - PurpleAccount *account = purple_connection_get_account(pc); - - closure->account = account; - closure->success_cb = success_cb; - purple_timeout_add(0, get_public_alias_cb, closure); -} - -static void -msn_act_id(PurpleConnection *gc, const char *entry) -{ - msn_set_public_alias(gc, entry, NULL, NULL); -} - -static void -msn_set_prp(PurpleConnection *gc, const char *type, const char *entry) -{ - MsnCmdProc *cmdproc; - MsnSession *session; - MsnTransaction *trans; - - session = gc->proto_data; - cmdproc = session->notification->cmdproc; - - if (entry == NULL || *entry == '\0') - { - trans = msn_transaction_new(cmdproc, "PRP", "%s", type); - } - else - { - trans = msn_transaction_new(cmdproc, "PRP", "%s %s", type, - purple_url_encode(entry)); - } - msn_cmdproc_send_trans(cmdproc, trans); -} - -static void -msn_set_home_phone_cb(PurpleConnection *gc, const char *entry) -{ - msn_set_prp(gc, "PHH", entry); -} - -static void -msn_set_work_phone_cb(PurpleConnection *gc, const char *entry) -{ - msn_set_prp(gc, "PHW", entry); -} - -static void -msn_set_mobile_phone_cb(PurpleConnection *gc, const char *entry) -{ - msn_set_prp(gc, "PHM", entry); -} - -static void -enable_msn_pages_cb(PurpleConnection *gc) -{ - msn_set_prp(gc, "MOB", "Y"); -} - -static void -disable_msn_pages_cb(PurpleConnection *gc) -{ - msn_set_prp(gc, "MOB", "N"); -} - -static void -send_to_mobile(PurpleConnection *gc, const char *who, const char *entry) -{ - MsnTransaction *trans; - MsnSession *session; - MsnCmdProc *cmdproc; - MsnPage *page; - MsnMessage *msg; - MsnUser *user; - char *payload = NULL; - const char *mobile_number = NULL; - gsize payload_len; - - session = gc->proto_data; - cmdproc = session->notification->cmdproc; - - page = msn_page_new(); - msn_page_set_body(page, entry); - - payload = msn_page_gen_payload(page, &payload_len); - - if ((user = msn_userlist_find_user(session->userlist, who)) && - (mobile_number = msn_user_get_mobile_phone(user)) && - mobile_number[0] == '+') { - /* if msn_user_get_mobile_phone() has a + in front, it's a number - that from the buddy's contact card */ - trans = msn_transaction_new(cmdproc, "PGD", "tel:%s 1 %" G_GSIZE_FORMAT, - mobile_number, payload_len); - } else { - /* otherwise we send to whatever phone number the buddy registered - with msn */ - trans = msn_transaction_new(cmdproc, "PGD", "%s 1 %" G_GSIZE_FORMAT, - who, payload_len); - } - - msn_transaction_set_payload(trans, payload, payload_len); - g_free(payload); - - msg = msn_message_new_plain(entry); - msn_transaction_set_data(trans, msg); - - msn_page_destroy(page); - - msn_cmdproc_send_trans(cmdproc, trans); -} - -static void -send_to_mobile_cb(MsnMobileData *data, const char *entry) -{ - send_to_mobile(data->gc, data->passport, entry); - g_free(data); -} - -static void -close_mobile_page_cb(MsnMobileData *data, const char *entry) -{ - g_free(data); -} - -/* -- */ - -static void -msn_show_set_friendly_name(PurplePluginAction *action) -{ - PurpleConnection *gc; - PurpleAccount *account; - char *tmp; - - gc = (PurpleConnection *) action->context; - account = purple_connection_get_account(gc); - - tmp = g_strdup_printf(_("Set friendly name for %s."), - purple_account_get_username(account)); - purple_request_input(gc, _("Set Friendly Name"), tmp, - _("This is the name that other MSN buddies will " - "see you as."), - purple_connection_get_display_name(gc), FALSE, FALSE, NULL, - _("OK"), G_CALLBACK(msn_act_id), - _("Cancel"), NULL, - account, NULL, NULL, - gc); - g_free(tmp); -} - -typedef struct MsnLocationData { - PurpleAccount *account; - MsnSession *session; - PurpleRequestFieldGroup *group; -} MsnLocationData; - -static void -update_endpoint_cb(MsnLocationData *data, PurpleRequestFields *fields) -{ - PurpleAccount *account; - MsnSession *session; - const char *old_name; - const char *name; - GList *others; - - session = data->session; - account = data->account; - - /* Update the current location's name */ - old_name = purple_account_get_string(account, "endpoint-name", NULL); - name = purple_request_fields_get_string(fields, "endpoint-name"); - if (!g_str_equal(old_name, name)) { - purple_account_set_string(account, "endpoint-name", name); - msn_notification_send_uux_private_endpointdata(session); - } - - /* Sign out other locations */ - for (others = purple_request_field_group_get_fields(data->group); - others; - others = g_list_next(others)) { - PurpleRequestField *field = others->data; - if (purple_request_field_get_type(field) != PURPLE_REQUEST_FIELD_BOOLEAN) - continue; - if (purple_request_field_bool_get_value(field)) { - const char *id = purple_request_field_get_id(field); - char *user; - purple_debug_info("msn", "Disconnecting Endpoint %s\n", id); - - user = g_strdup_printf("%s;%s", purple_account_get_username(account), id); - msn_notification_send_uun(session, user, MSN_UNIFIED_NOTIFICATION_MPOP, "goawyplzthxbye"); - g_free(user); - } - } - - g_free(data); -} - -static void -msn_show_locations(PurplePluginAction *action) -{ - PurpleConnection *pc; - PurpleAccount *account; - MsnSession *session; - PurpleRequestFields *fields; - PurpleRequestFieldGroup *group; - PurpleRequestField *field; - gboolean have_other_endpoints; - GSList *l; - MsnLocationData *data; - - pc = (PurpleConnection *)action->context; - account = purple_connection_get_account(pc); - session = purple_connection_get_protocol_data(pc); - - fields = purple_request_fields_new(); - - group = purple_request_field_group_new(_("This Location")); - purple_request_fields_add_group(fields, group); - field = purple_request_field_label_new("endpoint-label", _("This is the name that identifies this location")); - purple_request_field_group_add_field(group, field); - field = purple_request_field_string_new("endpoint-name", - _("Name"), - purple_account_get_string(account, "endpoint-name", NULL), - FALSE); - purple_request_field_set_required(field, TRUE); - purple_request_field_group_add_field(group, field); - - group = purple_request_field_group_new(_("Other Locations")); - purple_request_fields_add_group(fields, group); - - have_other_endpoints = FALSE; - for (l = session->user->endpoints; l; l = l->next) { - MsnUserEndpoint *ep = l->data; - - if (ep->id[0] != '\0' && strncasecmp(ep->id + 1, session->guid, 36) == 0) - /* Don't add myself to the list */ - continue; - - if (!have_other_endpoints) { - /* We do in fact have an endpoint other than ourselves... let's - add a label */ - field = purple_request_field_label_new("others-label", - _("You can sign out from other locations here")); - purple_request_field_group_add_field(group, field); - } - - have_other_endpoints = TRUE; - field = purple_request_field_bool_new(ep->id, ep->name, FALSE); - purple_request_field_group_add_field(group, field); - } - if (!have_other_endpoints) { - /* TODO: Due to limitations in our current request field API, the - following string will show up with a trailing colon. This should - be fixed either by adding an "include_colon" boolean, or creating - a separate purple_request_field_label_new_without_colon function, - or by never automatically adding the colon and requiring that - callers add the colon themselves. */ - field = purple_request_field_label_new("others-label", _("You are not signed in from any other locations.")); - purple_request_field_group_add_field(group, field); - } - - data = g_new0(MsnLocationData, 1); - data->account = account; - data->session = session; - data->group = group; - - purple_request_fields(pc, NULL, NULL, NULL, - fields, - _("OK"), G_CALLBACK(update_endpoint_cb), - _("Cancel"), G_CALLBACK(g_free), - account, NULL, NULL, - data); -} - -static void -enable_mpop_cb(PurpleConnection *pc) -{ - MsnSession *session = purple_connection_get_protocol_data(pc); - - purple_debug_info("msn", "Enabling MPOP\n"); - - session->enable_mpop = TRUE; - msn_annotate_contact(session, "Me", "MSN.IM.MPOP", "1", NULL); - - purple_prpl_got_account_actions(purple_connection_get_account(pc)); -} - -static void -disable_mpop_cb(PurpleConnection *pc) -{ - PurpleAccount *account = purple_connection_get_account(pc); - MsnSession *session = purple_connection_get_protocol_data(pc); - GSList *l; - - purple_debug_info("msn", "Disabling MPOP\n"); - - session->enable_mpop = FALSE; - msn_annotate_contact(session, "Me", "MSN.IM.MPOP", "0", NULL); - - for (l = session->user->endpoints; l; l = l->next) { - MsnUserEndpoint *ep = l->data; - char *user; - - if (ep->id[0] != '\0' && strncasecmp(ep->id + 1, session->guid, 36) == 0) - /* Don't kick myself */ - continue; - - purple_debug_info("msn", "Disconnecting Endpoint %s\n", ep->id); - - user = g_strdup_printf("%s;%s", purple_account_get_username(account), ep->id); - msn_notification_send_uun(session, user, MSN_UNIFIED_NOTIFICATION_MPOP, "goawyplzthxbye"); - g_free(user); - } - - purple_prpl_got_account_actions(account); -} - -static void -msn_show_set_mpop(PurplePluginAction *action) -{ - PurpleConnection *pc; - - pc = (PurpleConnection *)action->context; - - purple_request_action(pc, NULL, _("Allow multiple logins?"), - _("Do you want to allow or disallow connecting from " - "multiple locations simultaneously?"), - PURPLE_DEFAULT_ACTION_NONE, - purple_connection_get_account(pc), NULL, NULL, - pc, 3, - _("Allow"), G_CALLBACK(enable_mpop_cb), - _("Disallow"), G_CALLBACK(disable_mpop_cb), - _("Cancel"), NULL); -} - -static void -msn_show_set_home_phone(PurplePluginAction *action) -{ - PurpleConnection *gc; - MsnSession *session; - - gc = (PurpleConnection *) action->context; - session = gc->proto_data; - - purple_request_input(gc, NULL, _("Set your home phone number."), NULL, - msn_user_get_home_phone(session->user), FALSE, FALSE, NULL, - _("OK"), G_CALLBACK(msn_set_home_phone_cb), - _("Cancel"), NULL, - purple_connection_get_account(gc), NULL, NULL, - gc); -} - -static void -msn_show_set_work_phone(PurplePluginAction *action) -{ - PurpleConnection *gc; - MsnSession *session; - - gc = (PurpleConnection *) action->context; - session = gc->proto_data; - - purple_request_input(gc, NULL, _("Set your work phone number."), NULL, - msn_user_get_work_phone(session->user), FALSE, FALSE, NULL, - _("OK"), G_CALLBACK(msn_set_work_phone_cb), - _("Cancel"), NULL, - purple_connection_get_account(gc), NULL, NULL, - gc); -} - -static void -msn_show_set_mobile_phone(PurplePluginAction *action) -{ - PurpleConnection *gc; - MsnSession *session; - - gc = (PurpleConnection *) action->context; - session = gc->proto_data; - - purple_request_input(gc, NULL, _("Set your mobile phone number."), NULL, - msn_user_get_mobile_phone(session->user), FALSE, FALSE, NULL, - _("OK"), G_CALLBACK(msn_set_mobile_phone_cb), - _("Cancel"), NULL, - purple_connection_get_account(gc), NULL, NULL, - gc); -} - -static void -msn_show_set_mobile_pages(PurplePluginAction *action) -{ - PurpleConnection *gc; - - gc = (PurpleConnection *) action->context; - - purple_request_action(gc, NULL, _("Allow MSN Mobile pages?"), - _("Do you want to allow or disallow people on " - "your buddy list to send you MSN Mobile pages " - "to your cell phone or other mobile device?"), - PURPLE_DEFAULT_ACTION_NONE, - purple_connection_get_account(gc), NULL, NULL, - gc, 3, - _("Allow"), G_CALLBACK(enable_msn_pages_cb), - _("Disallow"), G_CALLBACK(disable_msn_pages_cb), - _("Cancel"), NULL); -} - -/* QuLogic: Disabled until confirmed correct. */ -#if 0 -static void -msn_show_blocked_text(PurplePluginAction *action) -{ - PurpleConnection *pc = (PurpleConnection *) action->context; - MsnSession *session; - char *title; - - session = pc->proto_data; - - title = g_strdup_printf(_("Blocked Text for %s"), session->account->username); - if (session->blocked_text == NULL) { - purple_notify_formatted(pc, title, title, NULL, _("No text is blocked for this account."), NULL, NULL); - } else { - char *blocked_text; - blocked_text = g_strdup_printf(_("MSN servers are currently blocking the following regular expressions:<br/>%s"), - session->blocked_text); - - purple_notify_formatted(pc, title, title, NULL, blocked_text, NULL, NULL); - g_free(blocked_text); - } - g_free(title); -} -#endif - -static void -msn_show_hotmail_inbox(PurplePluginAction *action) -{ - PurpleConnection *gc; - MsnSession *session; - - gc = (PurpleConnection *) action->context; - session = gc->proto_data; - - if (!session->passport_info.email_enabled) { - purple_notify_error(gc, NULL, - _("This account does not have email enabled."), NULL); - return; - } - - /** apparently the correct value is 777, use 750 as a failsafe */ - if ((session->passport_info.mail_url == NULL) - || (time (NULL) - session->passport_info.mail_timestamp >= 750)) { - MsnTransaction *trans; - MsnCmdProc *cmdproc; - - cmdproc = session->notification->cmdproc; - - trans = msn_transaction_new(cmdproc, "URL", "%s", "INBOX"); - msn_transaction_set_data(trans, GUINT_TO_POINTER(TRUE)); - - msn_cmdproc_send_trans(cmdproc, trans); - - } else - purple_notify_uri(gc, session->passport_info.mail_url); -} - -static void -show_send_to_mobile_cb(PurpleBlistNode *node, gpointer ignored) -{ - PurpleBuddy *buddy; - PurpleConnection *gc; - MsnMobileData *data; - PurpleAccount *account; - const char *name; - - g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); - - buddy = (PurpleBuddy *) node; - account = purple_buddy_get_account(buddy); - gc = purple_account_get_connection(account); - name = purple_buddy_get_name(buddy); - - data = g_new0(MsnMobileData, 1); - data->gc = gc; - data->passport = name; - - purple_request_input(gc, NULL, _("Send a mobile message."), NULL, - NULL, TRUE, FALSE, NULL, - _("Page"), G_CALLBACK(send_to_mobile_cb), - _("Close"), G_CALLBACK(close_mobile_page_cb), - account, name, NULL, - data); -} - -static gboolean -msn_offline_message(const PurpleBuddy *buddy) { - return TRUE; -} - -void -msn_send_privacy(PurpleConnection *gc) -{ - PurpleAccount *account; - MsnSession *session; - MsnCmdProc *cmdproc; - MsnTransaction *trans; - - account = purple_connection_get_account(gc); - session = gc->proto_data; - cmdproc = session->notification->cmdproc; - - if (account->perm_deny == PURPLE_PRIVACY_ALLOW_ALL || - account->perm_deny == PURPLE_PRIVACY_DENY_USERS) - trans = msn_transaction_new(cmdproc, "BLP", "%s", "AL"); - else - trans = msn_transaction_new(cmdproc, "BLP", "%s", "BL"); - - msn_cmdproc_send_trans(cmdproc, trans); -} - -static void -initiate_chat_cb(PurpleBlistNode *node, gpointer data) -{ - PurpleBuddy *buddy; - PurpleConnection *gc; - PurpleAccount *account; - - MsnSession *session; - MsnSwitchBoard *swboard; - - const char *alias; - - g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); - - buddy = (PurpleBuddy *) node; - account = purple_buddy_get_account(buddy); - gc = purple_account_get_connection(account); - - session = gc->proto_data; - - swboard = msn_switchboard_new(session); - msn_switchboard_request(swboard); - msn_switchboard_request_add_user(swboard, purple_buddy_get_name(buddy)); - - /* TODO: This might move somewhere else, after USR might be */ - swboard->chat_id = msn_switchboard_get_chat_id(); - swboard->conv = serv_got_joined_chat(gc, swboard->chat_id, "MSN Chat"); - swboard->flag = MSN_SB_FLAG_IM; - - /* Local alias > Display name > Username */ - if ((alias = purple_account_get_alias(account)) == NULL) - if ((alias = purple_connection_get_display_name(gc)) == NULL) - alias = purple_account_get_username(account); - - purple_conv_chat_add_user(PURPLE_CONV_CHAT(swboard->conv), - alias, NULL, PURPLE_CBFLAGS_NONE, TRUE); -} - -static void -t_msn_xfer_init(PurpleXfer *xfer) -{ - msn_request_ft(xfer); -} - -static void -t_msn_xfer_cancel_send(PurpleXfer *xfer) -{ - MsnSlpLink *slplink = xfer->data; - msn_slplink_unref(slplink); -} - -static PurpleXfer* -msn_new_xfer(PurpleConnection *gc, const char *who) -{ - MsnSession *session; - PurpleXfer *xfer; - - session = gc->proto_data; - - xfer = purple_xfer_new(gc->account, PURPLE_XFER_SEND, who); - - g_return_val_if_fail(xfer != NULL, NULL); - - xfer->data = msn_slplink_ref(msn_session_get_slplink(session, who)); - - purple_xfer_set_init_fnc(xfer, t_msn_xfer_init); - purple_xfer_set_cancel_send_fnc(xfer, t_msn_xfer_cancel_send); - - return xfer; -} - -static void -msn_send_file(PurpleConnection *gc, const char *who, const char *file) -{ - PurpleXfer *xfer = msn_new_xfer(gc, who); - - if (file) - purple_xfer_request_accepted(xfer, file); - else - purple_xfer_request(xfer); -} - -static gboolean -msn_can_receive_file(PurpleConnection *gc, const char *who) -{ - PurpleAccount *account; - gchar *normal; - gboolean ret; - - account = purple_connection_get_account(gc); - - normal = g_strdup(msn_normalize(account, purple_account_get_username(account))); - ret = strcmp(normal, msn_normalize(account, who)); - g_free(normal); - - if (ret) { - MsnSession *session = gc->proto_data; - if (session) { - MsnUser *user = msn_userlist_find_user(session->userlist, who); - if (user) { - /* Include these too: MSN_CAP_MOBILE_ON|MSN_CAP_WEB_WATCH ? */ - if ((user->clientid & MSN_CAP_VIA_WEBIM) || - user->networkid == MSN_NETWORK_YAHOO) - ret = FALSE; - else - ret = TRUE; - } - } else - ret = FALSE; - } - - return ret; -} - -/************************************************************************** - * Protocol Plugin ops - **************************************************************************/ - -static const char * -msn_list_icon(PurpleAccount *a, PurpleBuddy *b) -{ - return "msn"; -} - -static const char * -msn_list_emblems(PurpleBuddy *b) -{ - MsnUser *user = purple_buddy_get_protocol_data(b); - - if (user != NULL) { - if (user->clientid & MSN_CAP_BOT) - return "bot"; - if (user->clientid & MSN_CAP_VIA_MOBILE) - return "mobile"; -#if 0 - /* XXX: Since we don't support this, there's no point in showing it just yet */ - if (user->clientid & MSN_CAP_SCHANNEL) - return "secure"; -#endif - if (user->clientid & MSN_CAP_VIA_WEBIM) - return "external"; - if (user->networkid == MSN_NETWORK_YAHOO) - return "yahoo"; - } - - return NULL; -} - -/* - * Set the User status text - */ -static char * -msn_status_text(PurpleBuddy *buddy) -{ - PurplePresence *presence; - PurpleStatus *status; - const char *msg; - - presence = purple_buddy_get_presence(buddy); - status = purple_presence_get_active_status(presence); - - /* Official client says media takes precedence over message */ - /* I say message take precedence over media! Plus prpl-jabber agrees - too */ - msg = purple_status_get_attr_string(status, "message"); - if (msg && *msg) - return g_markup_escape_text(msg, -1); - - if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) { - const char *title, *game, *office; - char *media, *esc; - status = purple_presence_get_status(presence, "tune"); - title = purple_status_get_attr_string(status, PURPLE_TUNE_TITLE); - - game = purple_status_get_attr_string(status, "game"); - office = purple_status_get_attr_string(status, "office"); - - if (title && *title) { - const char *artist = purple_status_get_attr_string(status, PURPLE_TUNE_ARTIST); - const char *album = purple_status_get_attr_string(status, PURPLE_TUNE_ALBUM); - media = purple_util_format_song_info(title, artist, album, NULL); - return media; - } - else if (game && *game) - media = g_strdup_printf("Playing %s", game); - else if (office && *office) - media = g_strdup_printf("Editing %s", office); - else - return NULL; - esc = g_markup_escape_text(media, -1); - g_free(media); - return esc; - } - - return NULL; -} - -static void -msn_tooltip_text(PurpleBuddy *buddy, PurpleNotifyUserInfo *user_info, gboolean full) -{ - MsnUser *user; - PurplePresence *presence = purple_buddy_get_presence(buddy); - PurpleStatus *status = purple_presence_get_active_status(presence); - - user = purple_buddy_get_protocol_data(buddy); - - if (purple_presence_is_online(presence)) - { - const char *psm, *name; - const char *mediatype = NULL; - char *currentmedia = NULL; - - psm = purple_status_get_attr_string(status, "message"); - if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) { - PurpleStatus *tune = purple_presence_get_status(presence, "tune"); - const char *title = purple_status_get_attr_string(tune, PURPLE_TUNE_TITLE); - const char *game = purple_status_get_attr_string(tune, "game"); - const char *office = purple_status_get_attr_string(tune, "office"); - if (title && *title) { - const char *artist = purple_status_get_attr_string(tune, PURPLE_TUNE_ARTIST); - const char *album = purple_status_get_attr_string(tune, PURPLE_TUNE_ALBUM); - mediatype = _("Now Listening"); - currentmedia = purple_util_format_song_info(title, artist, album, NULL); - } else if (game && *game) { - mediatype = _("Playing a game"); - currentmedia = g_strdup(game); - } else if (office && *office) { - mediatype = _("Working"); - currentmedia = g_strdup(office); - } - } - - if (!purple_status_is_available(status)) { - name = purple_status_get_name(status); - } else { - name = NULL; - } - - if (name != NULL && *name) { - char *tmp2; - - tmp2 = g_markup_escape_text(name, -1); - if (purple_presence_is_idle(presence)) { - char *idle; - char *tmp3; - /* Never know what those translations might end up like... */ - idle = g_markup_escape_text(_("Idle"), -1); - tmp3 = g_strdup_printf("%s/%s", tmp2, idle); - g_free(idle); - g_free(tmp2); - tmp2 = tmp3; - } - - if (psm != NULL && *psm) { - purple_notify_user_info_add_pair_plaintext(user_info, tmp2, psm); - } else { - purple_notify_user_info_add_pair(user_info, _("Status"), tmp2); - } - - g_free(tmp2); - } else { - if (psm != NULL && *psm) { - if (purple_presence_is_idle(presence)) { - purple_notify_user_info_add_pair_plaintext(user_info, _("Idle"), psm); - } else { - purple_notify_user_info_add_pair_plaintext(user_info, _("Status"), psm); - } - } else { - if (purple_presence_is_idle(presence)) { - purple_notify_user_info_add_pair(user_info, _("Status"), - _("Idle")); - } else { - purple_notify_user_info_add_pair(user_info, _("Status"), - purple_status_get_name(status)); - } - } - } - - if (currentmedia) { - purple_notify_user_info_add_pair(user_info, mediatype, currentmedia); - g_free(currentmedia); - } - } - - /* XXX: This is being shown in non-full tooltips because the - * XXX: blocked icon overlay isn't always accurate for MSN. - * XXX: This can die as soon as purple_privacy_check() knows that - * XXX: this prpl always honors both the allow and deny lists. */ - /* While the above comment may be strictly correct (the privacy API needs - * rewriteing), purple_privacy_check() is going to be more accurate at - * indicating whether a particular buddy is going to be able to message - * you, which is the important information that this is trying to convey. - */ - if (full && user) - { - const char *phone; - - purple_notify_user_info_add_pair(user_info, _("Has you"), - ((user->list_op & (1 << MSN_LIST_RL)) ? _("Yes") : _("No"))); - - purple_notify_user_info_add_pair(user_info, _("Blocked"), - ((user->list_op & (1 << MSN_LIST_BL)) ? _("Yes") : _("No"))); - - phone = msn_user_get_home_phone(user); - if (phone != NULL) - purple_notify_user_info_add_pair(user_info, _("Home Phone Number"), phone); - - phone = msn_user_get_work_phone(user); - if (phone != NULL) - purple_notify_user_info_add_pair(user_info, _("Work Phone Number"), phone); - - phone = msn_user_get_mobile_phone(user); - if (phone != NULL) - purple_notify_user_info_add_pair(user_info, _("Mobile Phone Number"), phone); - } -} - -static GList * -msn_status_types(PurpleAccount *account) -{ - PurpleStatusType *status; - GList *types = NULL; - - status = purple_status_type_new_with_attrs( - PURPLE_STATUS_AVAILABLE, NULL, NULL, TRUE, TRUE, FALSE, - "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), - NULL); - types = g_list_append(types, status); - - status = purple_status_type_new_with_attrs( - PURPLE_STATUS_AWAY, NULL, NULL, TRUE, TRUE, FALSE, - "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), - NULL); - types = g_list_append(types, status); - - status = purple_status_type_new_with_attrs( - PURPLE_STATUS_AWAY, "brb", _("Be Right Back"), TRUE, TRUE, FALSE, - "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), - NULL); - types = g_list_append(types, status); - - status = purple_status_type_new_with_attrs( - PURPLE_STATUS_UNAVAILABLE, "busy", _("Busy"), TRUE, TRUE, FALSE, - "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), - NULL); - types = g_list_append(types, status); - status = purple_status_type_new_with_attrs( - PURPLE_STATUS_UNAVAILABLE, "phone", _("On the Phone"), TRUE, TRUE, FALSE, - "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), - NULL); - types = g_list_append(types, status); - status = purple_status_type_new_with_attrs( - PURPLE_STATUS_AWAY, "lunch", _("Out to Lunch"), TRUE, TRUE, FALSE, - "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), - NULL); - types = g_list_append(types, status); - - status = purple_status_type_new_full(PURPLE_STATUS_INVISIBLE, - NULL, NULL, TRUE, TRUE, FALSE); - types = g_list_append(types, status); - - status = purple_status_type_new_full(PURPLE_STATUS_OFFLINE, - NULL, NULL, TRUE, TRUE, FALSE); - types = g_list_append(types, status); - - status = purple_status_type_new_full(PURPLE_STATUS_MOBILE, - "mobile", NULL, FALSE, FALSE, TRUE); - types = g_list_append(types, status); - - status = purple_status_type_new_with_attrs(PURPLE_STATUS_TUNE, - "tune", NULL, FALSE, TRUE, TRUE, - PURPLE_TUNE_ARTIST, _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING), - PURPLE_TUNE_ALBUM, _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING), - PURPLE_TUNE_TITLE, _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING), - "game", _("Game Title"), purple_value_new(PURPLE_TYPE_STRING), - "office", _("Office Title"), purple_value_new(PURPLE_TYPE_STRING), - NULL); - types = g_list_append(types, status); - - return types; -} - -static GList * -msn_actions(PurplePlugin *plugin, gpointer context) -{ - PurpleConnection *gc; - MsnSession *session; - GList *m = NULL; - PurplePluginAction *act; - - gc = (PurpleConnection *) context; - session = gc->proto_data; - - act = purple_plugin_action_new(_("Set Friendly Name..."), - msn_show_set_friendly_name); - m = g_list_append(m, act); - m = g_list_append(m, NULL); - - if (session->enable_mpop) - { - act = purple_plugin_action_new(_("View Locations..."), - msn_show_locations); - m = g_list_append(m, act); - m = g_list_append(m, NULL); - } - - act = purple_plugin_action_new(_("Set Home Phone Number..."), - msn_show_set_home_phone); - m = g_list_append(m, act); - - act = purple_plugin_action_new(_("Set Work Phone Number..."), - msn_show_set_work_phone); - m = g_list_append(m, act); - - act = purple_plugin_action_new(_("Set Mobile Phone Number..."), - msn_show_set_mobile_phone); - m = g_list_append(m, act); - m = g_list_append(m, NULL); - -#if 0 - act = purple_plugin_action_new(_("Enable/Disable Mobile Devices..."), - msn_show_set_mobile_support); - m = g_list_append(m, act); -#endif - - act = purple_plugin_action_new(_("Allow/Disallow Multiple Logins..."), - msn_show_set_mpop); - m = g_list_append(m, act); - - act = purple_plugin_action_new(_("Allow/Disallow Mobile Pages..."), - msn_show_set_mobile_pages); - m = g_list_append(m, act); - -/* QuLogic: Disabled until confirmed correct. */ -#if 0 - m = g_list_append(m, NULL); - act = purple_plugin_action_new(_("View Blocked Text..."), - msn_show_blocked_text); - m = g_list_append(m, act); -#endif - - m = g_list_append(m, NULL); - act = purple_plugin_action_new(_("Open Hotmail Inbox"), - msn_show_hotmail_inbox); - m = g_list_append(m, act); - - return m; -} - -static GList * -msn_buddy_menu(PurpleBuddy *buddy) -{ - MsnUser *user; - - GList *m = NULL; - PurpleMenuAction *act; - - g_return_val_if_fail(buddy != NULL, NULL); - - user = purple_buddy_get_protocol_data(buddy); - - if (user != NULL) - { - if (user->mobile) - { - act = purple_menu_action_new(_("Send to Mobile"), - PURPLE_CALLBACK(show_send_to_mobile_cb), - NULL, NULL); - m = g_list_append(m, act); - } - } - - if (g_ascii_strcasecmp(purple_buddy_get_name(buddy), - purple_account_get_username(purple_buddy_get_account(buddy)))) - { - act = purple_menu_action_new(_("Initiate _Chat"), - PURPLE_CALLBACK(initiate_chat_cb), - NULL, NULL); - m = g_list_append(m, act); - } - - return m; -} - -static GList * -msn_blist_node_menu(PurpleBlistNode *node) -{ - if(PURPLE_BLIST_NODE_IS_BUDDY(node)) - { - return msn_buddy_menu((PurpleBuddy *) node); - } - else - { - return NULL; - } -} - -static void -msn_login(PurpleAccount *account) -{ - PurpleConnection *gc; - MsnSession *session; - const char *username; - const char *host; - gboolean http_method = FALSE; - int port; - - gc = purple_account_get_connection(account); - - if (!purple_ssl_is_supported()) - { - purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT, - _("SSL support is needed for MSN. Please install a supported " - "SSL library.")); - return; - } - - http_method = purple_account_get_bool(account, "http_method", FALSE); - - if (http_method) - host = purple_account_get_string(account, "http_method_server", MSN_HTTPCONN_SERVER); - else - host = purple_account_get_string(account, "server", MSN_SERVER); - port = purple_account_get_int(account, "port", MSN_PORT); - - session = msn_session_new(account); - - gc->proto_data = session; - gc->flags |= PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_FORMATTING_WBFO | PURPLE_CONNECTION_NO_BGCOLOR | - PURPLE_CONNECTION_NO_FONTSIZE | PURPLE_CONNECTION_NO_URLDESC | PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY; - - msn_session_set_login_step(session, MSN_LOGIN_STEP_START); - - /* Hmm, I don't like this. */ - /* XXX shx: Me neither */ - username = msn_normalize(account, purple_account_get_username(account)); - - if (strcmp(username, purple_account_get_username(account))) - purple_account_set_username(account, username); - - username = purple_account_get_string(account, "display-name", NULL); - purple_connection_set_display_name(gc, username); - - if (purple_account_get_string(account, "endpoint-name", NULL) == NULL) { - GHashTable *ui_info = purple_core_get_ui_info(); - const gchar *ui_name = ui_info ? g_hash_table_lookup(ui_info, "name") : NULL; - purple_account_set_string(account, "endpoint-name", - ui_name && *ui_name ? ui_name : PACKAGE_NAME); - } - - if (!msn_session_connect(session, host, port, http_method)) - purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Unable to connect")); -} - -static void -msn_close(PurpleConnection *gc) -{ - MsnSession *session; - - session = gc->proto_data; - - g_return_if_fail(session != NULL); - - msn_session_destroy(session); - - gc->proto_data = NULL; -} - -static gboolean -msn_send_me_im(gpointer data) -{ - MsnIMData *imdata = data; - serv_got_im(imdata->gc, imdata->who, imdata->msg, imdata->flags, imdata->when); - g_free(imdata->msg); - g_free(imdata); - return FALSE; -} - -static GString* -msn_msg_emoticon_add(GString *current, MsnEmoticon *emoticon) -{ - MsnObject *obj; - char *strobj; - - if (emoticon == NULL) - return current; - - obj = emoticon->obj; - - if (!obj) - return current; - - strobj = msn_object_to_string(obj); - - if (current) - g_string_append_printf(current, "\t%s\t%s", emoticon->smile, strobj); - else { - current = g_string_new(""); - g_string_printf(current, "%s\t%s", emoticon->smile, strobj); - } - - g_free(strobj); - - return current; -} - -static void -msn_send_emoticons(MsnSwitchBoard *swboard, GString *body) -{ - MsnMessage *msg; - - g_return_if_fail(body != NULL); - - msg = msn_message_new(MSN_MSG_SLP); - msn_message_set_content_type(msg, "text/x-mms-emoticon"); - msn_message_set_flag(msg, 'N'); - msn_message_set_bin_data(msg, body->str, body->len); - - msn_switchboard_send_msg(swboard, msg, TRUE); - msn_message_unref(msg); -} - -static void msn_emoticon_destroy(MsnEmoticon *emoticon) -{ - if (emoticon->obj) - msn_object_destroy(emoticon->obj); - g_free(emoticon->smile); - g_free(emoticon); -} - -static GSList* msn_msg_grab_emoticons(const char *msg, const char *username) -{ - GSList *list; - GList *smileys; - PurpleSmiley *smiley; - PurpleStoredImage *img; - char *ptr; - MsnEmoticon *emoticon; - int length; - - list = NULL; - smileys = purple_smileys_get_all(); - length = strlen(msg); - - for (; smileys; smileys = g_list_delete_link(smileys, smileys)) { - smiley = smileys->data; - - ptr = g_strstr_len(msg, length, purple_smiley_get_shortcut(smiley)); - - if (!ptr) - continue; - - img = purple_smiley_get_stored_image(smiley); - - emoticon = g_new0(MsnEmoticon, 1); - emoticon->smile = g_strdup(purple_smiley_get_shortcut(smiley)); - emoticon->ps = smiley; - emoticon->obj = msn_object_new_from_image(img, - purple_imgstore_get_filename(img), - username, MSN_OBJECT_EMOTICON); - - purple_imgstore_unref(img); - list = g_slist_prepend(list, emoticon); - } - - return list; -} - -void -msn_send_im_message(MsnSession *session, MsnMessage *msg) -{ - MsnEmoticon *smile; - GSList *smileys; - GString *emoticons = NULL; - const char *username = purple_account_get_username(session->account); - MsnSwitchBoard *swboard = msn_session_get_swboard(session, msg->remote_user, MSN_SB_FLAG_IM); - - smileys = msn_msg_grab_emoticons(msg->body, username); - while (smileys) { - smile = (MsnEmoticon *)smileys->data; - emoticons = msn_msg_emoticon_add(emoticons, smile); - msn_emoticon_destroy(smile); - smileys = g_slist_delete_link(smileys, smileys); - } - - if (emoticons) { - msn_send_emoticons(swboard, emoticons); - g_string_free(emoticons, TRUE); - } - - msn_switchboard_send_msg(swboard, msg, TRUE); -} - -static int -msn_send_im(PurpleConnection *gc, const char *who, const char *message, - PurpleMessageFlags flags) -{ - PurpleAccount *account; - PurpleBuddy *buddy = purple_find_buddy(gc->account, who); - MsnSession *session; - MsnSwitchBoard *swboard; - MsnMessage *msg; - char *msgformat; - char *msgtext; - size_t msglen; - const char *username; - - purple_debug_info("msn", "send IM {%s} to %s\n", message, who); - account = purple_connection_get_account(gc); - username = purple_account_get_username(account); - - session = gc->proto_data; - swboard = msn_session_find_swboard(session, who); - - if (!strncmp("tel:+", who, 5)) { - char *text = purple_markup_strip_html(message); - send_to_mobile(gc, who, text); - g_free(text); - return 1; - } - - if (buddy) { - PurplePresence *p = purple_buddy_get_presence(buddy); - if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_MOBILE)) { - char *text = purple_markup_strip_html(message); - send_to_mobile(gc, who, text); - g_free(text); - return 1; - } - } - - msn_import_html(message, &msgformat, &msgtext); - msglen = strlen(msgtext); - if (msglen == 0) { - /* Stuff like <hr> will be ignored. Don't send an empty message - if that's all there is. */ - g_free(msgtext); - g_free(msgformat); - - return 0; - } - - if (msglen + strlen(msgformat) + strlen(VERSION) > 1564) - { - g_free(msgformat); - g_free(msgtext); - - return -E2BIG; - } - - msg = msn_message_new_plain(msgtext); - msg->remote_user = g_strdup(who); - msn_message_set_header(msg, "X-MMS-IM-Format", msgformat); - - g_free(msgformat); - g_free(msgtext); - - if (g_ascii_strcasecmp(who, username)) - { - if (flags & PURPLE_MESSAGE_AUTO_RESP) { - msn_message_set_flag(msg, 'U'); - } - - if (msn_user_is_yahoo(account, who) || !(msn_user_is_online(account, who) || swboard != NULL)) { - /*we send the online and offline Message to Yahoo User via UBM*/ - purple_debug_info("msn", "send to offline or Yahoo user\n"); - msn_notification_send_uum(session, msg); - } else { - purple_debug_info("msn", "send via switchboard\n"); - msn_send_im_message(session, msg); - } - } - else - { - char *body_str, *body_enc, *pre, *post; - const char *format; - MsnIMData *imdata = g_new0(MsnIMData, 1); - /* - * In MSN, you can't send messages to yourself, so - * we'll fake like we received it ;) - */ - body_str = msn_message_to_string(msg); - body_enc = g_markup_escape_text(body_str, -1); - g_free(body_str); - - format = msn_message_get_header_value(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); - - serv_got_typing_stopped(gc, who); - imdata->gc = gc; - imdata->who = who; - imdata->msg = body_str; - imdata->flags = flags & ~PURPLE_MESSAGE_SEND; - imdata->when = time(NULL); - purple_timeout_add(0, msn_send_me_im, imdata); - } - - msn_message_unref(msg); - - return 1; -} - -static unsigned int -msn_send_typing(PurpleConnection *gc, const char *who, PurpleTypingState state) -{ - PurpleAccount *account; - MsnSession *session; - MsnSwitchBoard *swboard; - MsnMessage *msg; - - account = purple_connection_get_account(gc); - session = gc->proto_data; - - /* - * TODO: I feel like this should be "if (state != PURPLE_TYPING)" - * but this is how it was before, and I don't want to break - * anything. --KingAnt - */ - if (state == PURPLE_NOT_TYPING) - return 0; - - if (!g_ascii_strcasecmp(who, purple_account_get_username(account))) - { - /* We'll just fake it, since we're sending to ourself. */ - serv_got_typing(gc, who, MSN_TYPING_RECV_TIMEOUT, PURPLE_TYPING); - - return MSN_TYPING_SEND_TIMEOUT; - } - - swboard = msn_session_find_swboard(session, who); - - if (swboard == NULL || !msn_switchboard_can_send(swboard)) - return 0; - - swboard->flag |= MSN_SB_FLAG_IM; - - msg = msn_message_new(MSN_MSG_TYPING); - msn_message_set_content_type(msg, "text/x-msmsgscontrol"); - msn_message_set_flag(msg, 'U'); - msn_message_set_header(msg, "TypingUser", - purple_account_get_username(account)); - msn_message_set_bin_data(msg, "\r\n", 2); - - msn_switchboard_send_msg(swboard, msg, FALSE); - - msn_message_unref(msg); - - return MSN_TYPING_SEND_TIMEOUT; -} - -static void -msn_set_status(PurpleAccount *account, PurpleStatus *status) -{ - PurpleConnection *gc; - MsnSession *session; - - gc = purple_account_get_connection(account); - - if (gc != NULL) - { - session = gc->proto_data; - msn_change_status(session); - } -} - -static void -msn_set_idle(PurpleConnection *gc, int idle) -{ - MsnSession *session; - - session = gc->proto_data; - - msn_change_status(session); -} - -/* - * Actually adds a buddy once we have the response from FQY - */ -static void -add_pending_buddy(MsnSession *session, - const char *who, - MsnNetwork network, - MsnUser *user) -{ - char *group; - MsnUserList *userlist; - MsnUser *user2; - - g_return_if_fail(user != NULL); - - if (network == MSN_NETWORK_UNKNOWN) { - purple_debug_error("msn", "Network in FQY response was unknown. " - "Assuming %s is a passport user and adding anyway.\n", who); - network = MSN_NETWORK_PASSPORT; - } - - group = msn_user_remove_pending_group(user); - - userlist = session->userlist; - user2 = msn_userlist_find_user(userlist, who); - if (user2 != NULL) { - /* User already in userlist, so just update it. */ - msn_user_unref(user); - user = user2; - } else { - msn_userlist_add_user(userlist, user); - msn_user_unref(user); - } - - msn_user_set_network(user, network); - msn_userlist_add_buddy(userlist, who, group); - - g_free(group); -} - -static void -msn_add_buddy(PurpleConnection *pc, PurpleBuddy *buddy, PurpleGroup *group, const char *message) -{ - PurpleAccount *account; - const char *bname, *gname; - MsnSession *session; - MsnUserList *userlist; - MsnUser *user; - - account = purple_connection_get_account(pc); - session = purple_connection_get_protocol_data(pc); - bname = purple_buddy_get_name(buddy); - - if (!session->logged_in) - { - purple_debug_error("msn", "msn_add_buddy called before connected\n"); - - return; - } - - /* XXX - Would group ever be NULL here? I don't think so... - * shx: Yes it should; MSN handles non-grouped buddies, and this is only - * internal. - * KingAnt: But PurpleBuddys must always exist inside PurpleGroups, so - * won't group always be non-NULL here? - */ - bname = msn_normalize(account, bname); - gname = group ? purple_group_get_name(group) : NULL; - purple_debug_info("msn", "Add user:%s to group:%s\n", - bname, gname ? gname : "(null)"); - - if (!msn_email_is_valid(bname)) { - gchar *buf; - buf = g_strdup_printf(_("Unable to add the buddy %s because the username is invalid. Usernames must be valid email addresses."), bname); - if (!purple_conv_present_error(bname, account, buf)) - purple_notify_error(pc, NULL, _("Unable to Add"), buf); - g_free(buf); - - /* Remove from local list */ - purple_blist_remove_buddy(buddy); - - return; - } - - /* Make sure name is normalized */ - purple_blist_rename_buddy(buddy, bname); - - userlist = session->userlist; - user = msn_userlist_find_user(userlist, bname); - if (user && user->authorized) { - message = NULL; - } - if ((user != NULL) && (user->networkid != MSN_NETWORK_UNKNOWN)) { - /* We already know this buddy and their network. This function knows - what to do with users already in the list and stuff... */ - msn_user_set_invite_message(user, message); - msn_userlist_add_buddy(userlist, bname, gname); - } else { - char **tokens; - char *fqy; - /* We need to check the network for this buddy first */ - user = msn_user_new(userlist, bname, NULL); - msn_user_set_invite_message(user, message); - msn_user_set_pending_group(user, gname); - msn_user_set_network(user, MSN_NETWORK_UNKNOWN); - /* Should probably re-use the msn_add_contact_xml function here */ - tokens = g_strsplit(bname, "@", 2); - fqy = g_strdup_printf("<ml><d n=\"%s\"><c n=\"%s\"/></d></ml>", - tokens[1], - tokens[0]); - /* TODO: I think user will leak if we disconnect before receiving - a response to this FQY request */ - msn_notification_send_fqy(session, fqy, strlen(fqy), - (MsnFqyCb)add_pending_buddy, user); - g_free(fqy); - g_strfreev(tokens); - } -} - -static void -msn_rem_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) -{ - MsnSession *session; - MsnUserList *userlist; - - session = gc->proto_data; - userlist = session->userlist; - - if (!session->logged_in) - return; - - /* XXX - Does buddy->name need to be msn_normalize'd here? --KingAnt */ - msn_userlist_rem_buddy(userlist, purple_buddy_get_name(buddy)); -} - -static void -msn_add_permit(PurpleConnection *gc, const char *who) -{ - MsnSession *session; - MsnUserList *userlist; - MsnUser *user; - - session = gc->proto_data; - userlist = session->userlist; - user = msn_userlist_find_user(userlist, who); - - if (!session->logged_in) - return; - - if (user != NULL && user->list_op & MSN_LIST_BL_OP) { - msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_BL); - - /* delete contact from Block list and add it to Allow in the callback */ - msn_del_contact_from_list(session, NULL, who, MSN_LIST_BL); - } else { - /* just add the contact to Allow list */ - msn_add_contact_to_list(session, NULL, who, MSN_LIST_AL); - } - - - msn_userlist_add_buddy_to_list(userlist, who, MSN_LIST_AL); -} - -static void -msn_add_deny(PurpleConnection *gc, const char *who) -{ - MsnSession *session; - MsnUserList *userlist; - MsnUser *user; - - session = gc->proto_data; - userlist = session->userlist; - user = msn_userlist_find_user(userlist, who); - - if (!session->logged_in) - return; - - if (user != NULL && user->list_op & MSN_LIST_AL_OP) { - msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_AL); - - /* delete contact from Allow list and add it to Block in the callback */ - msn_del_contact_from_list(session, NULL, who, MSN_LIST_AL); - } else { - /* just add the contact to Block list */ - msn_add_contact_to_list(session, NULL, who, MSN_LIST_BL); - } - - msn_userlist_add_buddy_to_list(userlist, who, MSN_LIST_BL); -} - -static void -msn_rem_permit(PurpleConnection *gc, const char *who) -{ - MsnSession *session; - MsnUserList *userlist; - MsnUser *user; - - session = gc->proto_data; - userlist = session->userlist; - - if (!session->logged_in) - return; - - user = msn_userlist_find_user(userlist, who); - - msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_AL); - - msn_del_contact_from_list(session, NULL, who, MSN_LIST_AL); - - if (user != NULL && user->list_op & MSN_LIST_RL_OP) - msn_userlist_add_buddy_to_list(userlist, who, MSN_LIST_BL); -} - -static void -msn_rem_deny(PurpleConnection *gc, const char *who) -{ - MsnSession *session; - MsnUserList *userlist; - MsnUser *user; - - session = gc->proto_data; - userlist = session->userlist; - - if (!session->logged_in) - return; - - user = msn_userlist_find_user(userlist, who); - - msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_BL); - - msn_del_contact_from_list(session, NULL, who, MSN_LIST_BL); - - if (user != NULL && user->list_op & MSN_LIST_RL_OP) - msn_userlist_add_buddy_to_list(userlist, who, MSN_LIST_AL); -} - -static void -msn_set_permit_deny(PurpleConnection *gc) -{ - msn_send_privacy(gc); -} - -static void -msn_chat_invite(PurpleConnection *gc, int id, const char *msg, - const char *who) -{ - MsnSession *session; - MsnSwitchBoard *swboard; - - session = gc->proto_data; - - swboard = msn_session_find_swboard_with_id(session, id); - - if (swboard == NULL) - { - /* if we have no switchboard, everyone else left the chat already */ - swboard = msn_switchboard_new(session); - msn_switchboard_request(swboard); - swboard->chat_id = id; - swboard->conv = purple_find_chat(gc, id); - } - - swboard->flag |= MSN_SB_FLAG_IM; - - msn_switchboard_request_add_user(swboard, who); -} - -static void -msn_chat_leave(PurpleConnection *gc, int id) -{ - MsnSession *session; - MsnSwitchBoard *swboard; - PurpleConversation *conv; - - session = gc->proto_data; - - swboard = msn_session_find_swboard_with_id(session, id); - - /* if swboard is NULL we were the only person left anyway */ - if (swboard == NULL) - return; - - conv = swboard->conv; - - msn_switchboard_release(swboard, MSN_SB_FLAG_IM); - - /* If other switchboards managed to associate themselves with this - * conv, make sure they know it's gone! */ - if (conv != NULL) - { - while ((swboard = msn_session_find_swboard_with_conv(session, conv)) != NULL) - swboard->conv = NULL; - } -} - -static int -msn_chat_send(PurpleConnection *gc, int id, const char *message, PurpleMessageFlags flags) -{ - PurpleAccount *account; - MsnSession *session; - const char *username; - MsnSwitchBoard *swboard; - MsnMessage *msg; - char *msgformat; - char *msgtext; - size_t msglen; - MsnEmoticon *smile; - GSList *smileys; - GString *emoticons = NULL; - - account = purple_connection_get_account(gc); - session = gc->proto_data; - username = purple_account_get_username(account); - swboard = msn_session_find_swboard_with_id(session, id); - - if (swboard == NULL) - return -EINVAL; - - if (!swboard->ready) - return 0; - - swboard->flag |= MSN_SB_FLAG_IM; - - msn_import_html(message, &msgformat, &msgtext); - msglen = strlen(msgtext); - - if ((msglen == 0) || (msglen + strlen(msgformat) + strlen(VERSION) > 1564)) - { - g_free(msgformat); - g_free(msgtext); - - return -E2BIG; - } - - msg = msn_message_new_plain(msgtext); - msn_message_set_header(msg, "X-MMS-IM-Format", msgformat); - - smileys = msn_msg_grab_emoticons(msg->body, username); - while (smileys) { - smile = (MsnEmoticon *)smileys->data; - emoticons = msn_msg_emoticon_add(emoticons, smile); - if (purple_conv_custom_smiley_add(swboard->conv, smile->smile, - "sha1", purple_smiley_get_checksum(smile->ps), - FALSE)) { - gconstpointer data; - size_t len; - data = purple_smiley_get_data(smile->ps, &len); - purple_conv_custom_smiley_write(swboard->conv, smile->smile, data, len); - purple_conv_custom_smiley_close(swboard->conv, smile->smile); - } - msn_emoticon_destroy(smile); - smileys = g_slist_delete_link(smileys, smileys); - } - - if (emoticons) { - msn_send_emoticons(swboard, emoticons); - g_string_free(emoticons, TRUE); - } - - msn_switchboard_send_msg(swboard, msg, FALSE); - msn_message_unref(msg); - - g_free(msgformat); - g_free(msgtext); - - serv_got_chat_in(gc, id, purple_account_get_username(account), flags, - message, time(NULL)); - - return 0; -} - -static void -msn_keepalive(PurpleConnection *gc) -{ - MsnSession *session; - MsnTransaction *trans; - - session = gc->proto_data; - - if (!session->http_method) - { - MsnCmdProc *cmdproc; - - cmdproc = session->notification->cmdproc; - - trans = msn_transaction_new(cmdproc, "PNG", NULL); - msn_transaction_set_saveable(trans, FALSE); - msn_cmdproc_send_trans(cmdproc, trans); - } -} - -static void msn_alias_buddy(PurpleConnection *pc, const char *name, const char *alias) -{ - MsnSession *session; - - session = pc->proto_data; - - msn_update_contact(session, name, MSN_UPDATE_ALIAS, alias); -} - -static void -msn_group_buddy(PurpleConnection *gc, const char *who, - const char *old_group_name, const char *new_group_name) -{ - MsnSession *session; - MsnUserList *userlist; - - session = gc->proto_data; - userlist = session->userlist; - - msn_userlist_move_buddy(userlist, who, old_group_name, new_group_name); -} - -static void -msn_rename_group(PurpleConnection *gc, const char *old_name, - PurpleGroup *group, GList *moved_buddies) -{ - MsnSession *session; - const char *gname; - - session = gc->proto_data; - - g_return_if_fail(session != NULL); - g_return_if_fail(session->userlist != NULL); - - gname = purple_group_get_name(group); - if (msn_userlist_find_group_with_name(session->userlist, old_name) != NULL) - { - msn_contact_rename_group(session, old_name, gname); - } - else - { - /* not found */ - msn_add_group(session, NULL, gname); - } -} - -static void -msn_convo_closed(PurpleConnection *gc, const char *who) -{ - MsnSession *session; - MsnSwitchBoard *swboard; - PurpleConversation *conv; - - session = gc->proto_data; - - swboard = msn_session_find_swboard(session, who); - - /* - * Don't perform an assertion here. If swboard is NULL, then the - * switchboard was either closed by the other party, or the person - * is talking to himself. - */ - if (swboard == NULL) - return; - - conv = swboard->conv; - - /* If we release the switchboard here, it may still have messages - pending ACK which would result in incorrect unsent message errors. - Just let it timeout... This is *so* going to screw with people who - use dumb clients that report "User has closed the conversation window" */ - /* msn_switchboard_release(swboard, MSN_SB_FLAG_IM); */ - swboard->conv = NULL; - - /* If other switchboards managed to associate themselves with this - * conv, make sure they know it's gone! */ - if (conv != NULL) - { - while ((swboard = msn_session_find_swboard_with_conv(session, conv)) != NULL) - swboard->conv = NULL; - } -} - -static void -msn_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img) -{ - MsnSession *session; - MsnUser *user; - - session = gc->proto_data; - user = session->user; - - msn_user_set_buddy_icon(user, img); - - msn_change_status(session); -} - -static void -msn_remove_group(PurpleConnection *gc, PurpleGroup *group) -{ - MsnSession *session; - const char *gname; - - session = gc->proto_data; - gname = purple_group_get_name(group); - - purple_debug_info("msn", "Remove group %s\n", gname); - /*we can't delete the default group*/ - if(!strcmp(gname, MSN_INDIVIDUALS_GROUP_NAME)|| - !strcmp(gname, MSN_NON_IM_GROUP_NAME)) - { - purple_debug_info("msn", "This group can't be removed, returning.\n"); - return ; - } - - msn_del_group(session, gname); -} - -/** - * Extract info text from info_data and add it to user_info - */ -static gboolean -msn_tooltip_extract_info_text(PurpleNotifyUserInfo *user_info, MsnGetInfoData *info_data) -{ - PurpleBuddy *b; - - b = purple_find_buddy(purple_connection_get_account(info_data->gc), - info_data->name); - - if (b) - { - char *tmp; - const char *alias; - - alias = purple_buddy_get_local_buddy_alias(b); - if (alias && alias[0]) - { - purple_notify_user_info_add_pair_plaintext(user_info, _("Alias"), alias); - } - - if ((alias = purple_buddy_get_server_alias(b)) != NULL) - { - char *nicktext = g_markup_escape_text(alias, -1); - tmp = g_strdup_printf("<font sml=\"msn\">%s</font>", nicktext); - purple_notify_user_info_add_pair(user_info, _("Nickname"), tmp); - g_free(tmp); - g_free(nicktext); - } - - /* Add the tooltip information */ - msn_tooltip_text(b, user_info, TRUE); - - return TRUE; - } - - return FALSE; -} - -#if PHOTO_SUPPORT - -static char * -msn_get_photo_url(const char *url_text) -{ - char *p, *q; - - if ((p = strstr(url_text, PHOTO_URL)) != NULL) - { - p += strlen(PHOTO_URL); - } - if (p && (strncmp(p, "http://", strlen("http://")) == 0) && ((q = strchr(p, '"')) != NULL)) - return g_strndup(p, q - p); - - return NULL; -} - -static void msn_got_photo(PurpleUtilFetchUrlData *url_data, gpointer data, - const gchar *url_text, gsize len, const gchar *error_message); - -#endif - -#if 0 -static char *msn_info_date_reformat(const char *field, size_t len) -{ - char *tmp = g_strndup(field, len); - time_t t = purple_str_to_time(tmp, FALSE, NULL, NULL, NULL); - - g_free(tmp); - return g_strdup(purple_date_format_short(localtime(&t))); -} -#endif - -#define MSN_GOT_INFO_GET_FIELD(a, b) \ - found = purple_markup_extract_info_field(stripped, stripped_len, user_info, \ - "\n" a ":", 0, "\n", 0, "Undisclosed", b, 0, NULL, NULL); \ - if (found) \ - sect_info = TRUE; - -#define MSN_GOT_INFO_GET_FIELD_NO_SEARCH(a, b) \ - found = purple_markup_extract_info_field(stripped, stripped_len, user_info, \ - "\n" a ":", 0, "\n", 0, "Undisclosed", b, 0, NULL, msn_info_strip_search_link); \ - if (found) \ - sect_info = TRUE; - -static char * -msn_info_strip_search_link(const char *field, size_t len) -{ - const char *c; - if ((c = strstr(field, " (http://")) == NULL) - return g_strndup(field, len); - return g_strndup(field, c - field); -} - -static void -msn_got_info(PurpleUtilFetchUrlData *url_data, gpointer data, - const gchar *url_text, size_t len, const gchar *error_message) -{ - MsnGetInfoData *info_data = (MsnGetInfoData *)data; - MsnSession *session; - PurpleNotifyUserInfo *user_info; - char *stripped, *p, *q, *tmp; - char *user_url = NULL; - gboolean found; - gboolean has_tooltip_text = FALSE; - gboolean has_info = FALSE; - gboolean sect_info = FALSE; - gboolean has_contact_info = FALSE; - char *url_buffer; - int stripped_len; -#if PHOTO_SUPPORT - char *photo_url_text = NULL; - MsnGetInfoStepTwoData *info2_data = NULL; -#endif - - purple_debug_info("msn", "In msn_got_info,url_text:{%s}\n",url_text); - - session = purple_connection_get_protocol_data(info_data->gc); - session->url_datas = g_slist_remove(session->url_datas, url_data); - - user_info = purple_notify_user_info_new(); - has_tooltip_text = msn_tooltip_extract_info_text(user_info, info_data); - - if (error_message != NULL || url_text == NULL || strcmp(url_text, "") == 0) - { - purple_notify_user_info_add_pair(user_info, - _("Error retrieving profile"), NULL); - - purple_notify_userinfo(info_data->gc, info_data->name, user_info, NULL, NULL); - purple_notify_user_info_destroy(user_info); - - g_free(info_data->name); - g_free(info_data); - return; - } - - url_buffer = g_strdup(url_text); - - /* If they have a homepage link, MSN masks it such that we need to - * fetch the url out before purple_markup_strip_html() nukes it */ - /* I don't think this works with the new spaces profiles - Stu 3/2/06 */ - if ((p = strstr(url_text, - "Take a look at my </font><A class=viewDesc title=\"")) != NULL) - { - p += 50; - - if ((q = strchr(p, '"')) != NULL) - user_url = g_strndup(p, q - p); - } - - /* - * purple_markup_strip_html() doesn't strip out character entities like - * and · - */ - while ((p = strstr(url_buffer, " ")) != NULL) - { - *p = ' '; /* Turn 's into ordinary blanks */ - p += 1; - memmove(p, p + 5, strlen(p + 5)); - url_buffer[strlen(url_buffer) - 5] = '\0'; - } - - while ((p = strstr(url_buffer, "·")) != NULL) - { - memmove(p, p + 6, strlen(p + 6)); - url_buffer[strlen(url_buffer) - 6] = '\0'; - } - - /* Nuke the nasty \r's that just get in the way */ - purple_str_strip_char(url_buffer, '\r'); - - /* MSN always puts in ' for apostrophes...replace them */ - while ((p = strstr(url_buffer, "'")) != NULL) - { - *p = '\''; - memmove(p + 1, p + 5, strlen(p + 5)); - url_buffer[strlen(url_buffer) - 4] = '\0'; - } - - /* Nuke the html, it's easier than trying to parse the horrid stuff */ - stripped = purple_markup_strip_html(url_buffer); - stripped_len = strlen(stripped); - - purple_debug_misc("msn", "stripped = %p\n", stripped); - purple_debug_misc("msn", "url_buffer = %p\n", url_buffer); - - /* General section header */ - if (has_tooltip_text) - purple_notify_user_info_add_section_break(user_info); - - purple_notify_user_info_add_section_header(user_info, _("General")); - - /* Extract their Name and put it in */ - MSN_GOT_INFO_GET_FIELD("Name", _("Name")); - - /* General */ - MSN_GOT_INFO_GET_FIELD("Nickname", _("Nickname")); - MSN_GOT_INFO_GET_FIELD_NO_SEARCH("Age", _("Age")); - MSN_GOT_INFO_GET_FIELD_NO_SEARCH("Gender", _("Gender")); - MSN_GOT_INFO_GET_FIELD_NO_SEARCH("Occupation", _("Occupation")); - MSN_GOT_INFO_GET_FIELD_NO_SEARCH("Location", _("Location")); - - /* Extract their Interests and put it in */ - found = purple_markup_extract_info_field(stripped, stripped_len, user_info, - "\nInterests\t", 0, " (/default.aspx?page=searchresults", 0, - "Undisclosed", _("Hobbies and Interests") /* _("Interests") */, - 0, NULL, NULL); - - if (found) - sect_info = TRUE; - - MSN_GOT_INFO_GET_FIELD("More about me", _("A Little About Me")); - - if (sect_info) - { - has_info = TRUE; - sect_info = FALSE; - } - else - { - /* Remove the section header */ - purple_notify_user_info_remove_last_item(user_info); - if (has_tooltip_text) - purple_notify_user_info_remove_last_item(user_info); - } - - /* Social */ - purple_notify_user_info_add_section_break(user_info); - purple_notify_user_info_add_section_header(user_info, _("Social")); - - MSN_GOT_INFO_GET_FIELD_NO_SEARCH("Marital status", _("Marital Status")); - MSN_GOT_INFO_GET_FIELD_NO_SEARCH("Interested in", _("Interests")); - MSN_GOT_INFO_GET_FIELD_NO_SEARCH("Pets", _("Pets")); - MSN_GOT_INFO_GET_FIELD_NO_SEARCH("Hometown", _("Hometown")); - MSN_GOT_INFO_GET_FIELD("Places lived", _("Places Lived")); - MSN_GOT_INFO_GET_FIELD_NO_SEARCH("Fashion", _("Fashion")); - MSN_GOT_INFO_GET_FIELD_NO_SEARCH("Humor", _("Humor")); - MSN_GOT_INFO_GET_FIELD_NO_SEARCH("Music", _("Music")); - MSN_GOT_INFO_GET_FIELD_NO_SEARCH("Favorite quote", _("Favorite Quote")); - - if (sect_info) - { - has_info = TRUE; - sect_info = FALSE; - } - else - { - /* Remove the section header */ - purple_notify_user_info_remove_last_item(user_info); - purple_notify_user_info_remove_last_item(user_info); - } - - /* Contact Info */ - /* Personal */ - purple_notify_user_info_add_section_break(user_info); - purple_notify_user_info_add_section_header(user_info, _("Contact Info")); - purple_notify_user_info_add_section_header(user_info, _("Personal")); - - MSN_GOT_INFO_GET_FIELD("Name", _("Name")); - MSN_GOT_INFO_GET_FIELD("Significant other", _("Significant Other")); - MSN_GOT_INFO_GET_FIELD("Home phone", _("Home Phone")); - MSN_GOT_INFO_GET_FIELD("Home phone 2", _("Home Phone 2")); - MSN_GOT_INFO_GET_FIELD("Home address", _("Home Address")); - MSN_GOT_INFO_GET_FIELD("Personal Mobile", _("Personal Mobile")); - MSN_GOT_INFO_GET_FIELD("Home fax", _("Home Fax")); - MSN_GOT_INFO_GET_FIELD("Personal email", _("Personal Email")); - MSN_GOT_INFO_GET_FIELD("Personal IM", _("Personal IM")); - MSN_GOT_INFO_GET_FIELD("Birthday", _("Birthday")); - MSN_GOT_INFO_GET_FIELD("Anniversary", _("Anniversary")); - MSN_GOT_INFO_GET_FIELD("Notes", _("Notes")); - - if (sect_info) - { - has_info = TRUE; - sect_info = FALSE; - has_contact_info = TRUE; - } - else - { - /* Remove the section header */ - purple_notify_user_info_remove_last_item(user_info); - } - - /* Business */ - purple_notify_user_info_add_section_header(user_info, _("Work")); - MSN_GOT_INFO_GET_FIELD("Name", _("Name")); - MSN_GOT_INFO_GET_FIELD("Job title", _("Job Title")); - MSN_GOT_INFO_GET_FIELD("Company", _("Company")); - MSN_GOT_INFO_GET_FIELD("Department", _("Department")); - MSN_GOT_INFO_GET_FIELD("Profession", _("Profession")); - MSN_GOT_INFO_GET_FIELD("Work phone 1", _("Work Phone")); - MSN_GOT_INFO_GET_FIELD("Work phone 2", _("Work Phone 2")); - MSN_GOT_INFO_GET_FIELD("Work address", _("Work Address")); - MSN_GOT_INFO_GET_FIELD("Work mobile", _("Work Mobile")); - MSN_GOT_INFO_GET_FIELD("Work pager", _("Work Pager")); - MSN_GOT_INFO_GET_FIELD("Work fax", _("Work Fax")); - MSN_GOT_INFO_GET_FIELD("Work email", _("Work Email")); - MSN_GOT_INFO_GET_FIELD("Work IM", _("Work IM")); - MSN_GOT_INFO_GET_FIELD("Start date", _("Start Date")); - MSN_GOT_INFO_GET_FIELD("Notes", _("Notes")); - - if (sect_info) - { - has_info = TRUE; - sect_info = FALSE; - has_contact_info = TRUE; - } - else - { - /* Remove the section header */ - purple_notify_user_info_remove_last_item(user_info); - } - - if (!has_contact_info) - { - /* Remove the Contact Info section header */ - purple_notify_user_info_remove_last_item(user_info); - } - -#if 0 /* these probably don't show up any more */ - /* - * The fields, 'A Little About Me', 'Favorite Things', 'Hobbies - * and Interests', 'Favorite Quote', and 'My Homepage' may or may - * not appear, in any combination. However, they do appear in - * certain order, so we can successively search to pin down the - * distinct values. - */ - - /* Check if they have A Little About Me */ - found = purple_markup_extract_info_field(stripped, stripped_len, s, - " A Little About Me \n\n", 0, "Favorite Things", '\n', NULL, - _("A Little About Me"), 0, NULL, NULL); - - if (!found) - { - found = purple_markup_extract_info_field(stripped, stripped_len, s, - " A Little About Me \n\n", 0, "Hobbies and Interests", '\n', - NULL, _("A Little About Me"), 0, NULL, NULL); - } - - if (!found) - { - found = purple_markup_extract_info_field(stripped, stripped_len, s, - " A Little About Me \n\n", 0, "Favorite Quote", '\n', NULL, - _("A Little About Me"), 0, NULL, NULL); - } - - if (!found) - { - found = purple_markup_extract_info_field(stripped, stripped_len, s, - " A Little About Me \n\n", 0, "My Homepage \n\nTake a look", - '\n', - NULL, _("A Little About Me"), 0, NULL, NULL); - } - - if (!found) - { - purple_markup_extract_info_field(stripped, stripped_len, s, - " A Little About Me \n\n", 0, "last updated", '\n', NULL, - _("A Little About Me"), 0, NULL, NULL); - } - - if (found) - has_info = TRUE; - - /* Check if they have Favorite Things */ - found = purple_markup_extract_info_field(stripped, stripped_len, s, - " Favorite Things \n\n", 0, "Hobbies and Interests", '\n', NULL, - _("Favorite Things"), 0, NULL, NULL); - - if (!found) - { - found = purple_markup_extract_info_field(stripped, stripped_len, s, - " Favorite Things \n\n", 0, "Favorite Quote", '\n', NULL, - _("Favorite Things"), 0, NULL, NULL); - } - - if (!found) - { - found = purple_markup_extract_info_field(stripped, stripped_len, s, - " Favorite Things \n\n", 0, "My Homepage \n\nTake a look", '\n', - NULL, _("Favorite Things"), 0, NULL, NULL); - } - - if (!found) - { - purple_markup_extract_info_field(stripped, stripped_len, s, - " Favorite Things \n\n", 0, "last updated", '\n', NULL, - _("Favorite Things"), 0, NULL, NULL); - } - - if (found) - has_info = TRUE; - - /* Check if they have Hobbies and Interests */ - found = purple_markup_extract_info_field(stripped, stripped_len, s, - " Hobbies and Interests \n\n", 0, "Favorite Quote", '\n', NULL, - _("Hobbies and Interests"), 0, NULL, NULL); - - if (!found) - { - found = purple_markup_extract_info_field(stripped, stripped_len, s, - " Hobbies and Interests \n\n", 0, "My Homepage \n\nTake a look", - '\n', NULL, _("Hobbies and Interests"), 0, NULL, NULL); - } - - if (!found) - { - purple_markup_extract_info_field(stripped, stripped_len, s, - " Hobbies and Interests \n\n", 0, "last updated", '\n', NULL, - _("Hobbies and Interests"), 0, NULL, NULL); - } - - if (found) - has_info = TRUE; - - /* Check if they have Favorite Quote */ - found = purple_markup_extract_info_field(stripped, stripped_len, s, - "Favorite Quote \n\n", 0, "My Homepage \n\nTake a look", '\n', NULL, - _("Favorite Quote"), 0, NULL, NULL); - - if (!found) - { - purple_markup_extract_info_field(stripped, stripped_len, s, - "Favorite Quote \n\n", 0, "last updated", '\n', NULL, - _("Favorite Quote"), 0, NULL, NULL); - } - - if (found) - has_info = TRUE; - - /* Extract the last updated date and put it in */ - found = purple_markup_extract_info_field(stripped, stripped_len, s, - " last updated:", 1, "\n", 0, NULL, _("Last Updated"), 0, - NULL, msn_info_date_reformat); - - if (found) - has_info = TRUE; -#endif - - /* If we were able to fetch a homepage url earlier, stick it in there */ - if (user_url != NULL) - { - tmp = g_strdup_printf("<a href=\"%s\">%s</a>", user_url, user_url); - purple_notify_user_info_add_pair(user_info, _("Homepage"), tmp); - g_free(tmp); - g_free(user_url); - - has_info = TRUE; - } - - if (!has_info) - { - /* MSN doesn't actually distinguish between "unknown member" and - * a known member with an empty profile. Try to explain this fact. - * Note that if we have a nonempty tooltip_text, we know the user - * exists. - */ - /* This doesn't work with the new spaces profiles - Stu 3/2/06 - char *p = strstr(url_buffer, "Unknown Member </TITLE>"); - * This might not work for long either ... */ - /* Nope, it failed some time before 5/2/07 :( - char *p = strstr(url_buffer, "form id=\"SpacesSearch\" name=\"SpacesSearch\""); - * Let's see how long this one holds out for ... */ - char *p = strstr(url_buffer, "<form id=\"profile_form\" name=\"profile_form\" action=\"http://spaces.live.com/profile.aspx?cid=0\""); - PurpleBuddy *b = purple_find_buddy - (purple_connection_get_account(info_data->gc), info_data->name); - purple_notify_user_info_add_pair(user_info, - _("Error retrieving profile"), NULL); - purple_notify_user_info_add_pair(user_info, NULL, - ((p && b) ? _("The user has not created a public profile.") : - (p ? _("MSN reported not being able to find the user's profile. " - "This either means that the user does not exist, " - "or that the user exists " - "but has not created a public profile.") : - _("Could not find " /* This should never happen */ - "any information in the user's profile. " - "The user most likely does not exist.")))); - } - - /* put a link to the actual profile URL */ - purple_notify_user_info_add_section_break(user_info); - tmp = g_strdup_printf("<a href=\"%s%s\">%s</a>", - PROFILE_URL, info_data->name, _("View web profile")); - purple_notify_user_info_add_pair(user_info, NULL, tmp); - g_free(tmp); - -#if PHOTO_SUPPORT - /* Find the URL to the photo; must be before the marshalling [Bug 994207] */ - photo_url_text = msn_get_photo_url(url_text); - purple_debug_info("msn", "photo url:{%s}\n", photo_url_text ? photo_url_text : "(null)"); - - /* Marshall the existing state */ - info2_data = g_new0(MsnGetInfoStepTwoData, 1); - info2_data->info_data = info_data; - info2_data->stripped = stripped; - info2_data->url_buffer = url_buffer; - info2_data->user_info = user_info; - info2_data->photo_url_text = photo_url_text; - - /* Try to put the photo in there too, if there's one */ - if (photo_url_text) - { - url_data = purple_util_fetch_url_len(photo_url_text, FALSE, NULL, FALSE, - MAX_HTTP_BUDDYICON_BYTES, - msn_got_photo, info2_data); - session->url_datas = g_slist_prepend(session->url_datas, url_data); - } - else - { - /* Finish the Get Info and show the user something */ - msn_got_photo(NULL, info2_data, NULL, 0, NULL); - } -} - -static void -msn_got_photo(PurpleUtilFetchUrlData *url_data, gpointer user_data, - const gchar *url_text, gsize len, const gchar *error_message) -{ - MsnGetInfoStepTwoData *info2_data = (MsnGetInfoStepTwoData *)user_data; - int id = -1; - - /* Unmarshall the saved state */ - MsnGetInfoData *info_data = info2_data->info_data; - char *stripped = info2_data->stripped; - char *url_buffer = info2_data->url_buffer; - PurpleNotifyUserInfo *user_info = info2_data->user_info; - char *photo_url_text = info2_data->photo_url_text; - - if (url_data) { - MsnSession *session = purple_connection_get_protocol_data(info_data->gc); - session->url_datas = g_slist_remove(session->url_datas, url_data); - } - - if (url_text && error_message) - { - purple_debug_warning("msn", "invalid connection. ignoring buddy photo info.\n"); - g_free(stripped); - g_free(url_buffer); - purple_notify_user_info_destroy(user_info); - g_free(info_data->name); - g_free(info_data); - g_free(photo_url_text); - g_free(info2_data); - - return; - } - - /* Try to put the photo in there too, if there's one and is readable */ - if (url_text && len != 0) - { - if (strstr(url_text, "400 Bad Request") - || strstr(url_text, "403 Forbidden") - || strstr(url_text, "404 Not Found")) - { - - purple_debug_info("msn", "Error getting %s: %s\n", - photo_url_text, url_text); - } - else - { - char buf[1024]; - purple_debug_info("msn", "%s is %" G_GSIZE_FORMAT " bytes\n", photo_url_text, len); - id = purple_imgstore_add_with_id(g_memdup(url_text, len), len, NULL); - g_snprintf(buf, sizeof(buf), "<img id=\"%d\"><br>", id); - purple_notify_user_info_prepend_pair(user_info, NULL, buf); - } - } - - /* We continue here from msn_got_info, as if nothing has happened */ -#endif - purple_notify_userinfo(info_data->gc, info_data->name, user_info, NULL, NULL); - - g_free(stripped); - g_free(url_buffer); - purple_notify_user_info_destroy(user_info); - g_free(info_data->name); - g_free(info_data); -#if PHOTO_SUPPORT - g_free(photo_url_text); - g_free(info2_data); - if (id != -1) - purple_imgstore_unref_by_id(id); -#endif -} - -static void -msn_get_info(PurpleConnection *gc, const char *name) -{ - MsnSession *session = purple_connection_get_protocol_data(gc); - MsnGetInfoData *data; - char *url; - PurpleUtilFetchUrlData *url_data; - - data = g_new0(MsnGetInfoData, 1); - data->gc = gc; - data->name = g_strdup(name); - - url = g_strdup_printf("%s%s", PROFILE_URL, name); - - url_data = purple_util_fetch_url(url, FALSE, - "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)", - TRUE, msn_got_info, data); - session->url_datas = g_slist_prepend(session->url_datas, url_data); - - g_free(url); -} - -static gboolean msn_load(PurplePlugin *plugin) -{ - msn_notification_init(); - msn_switchboard_init(); - - return TRUE; -} - -static gboolean msn_unload(PurplePlugin *plugin) -{ - msn_notification_end(); - msn_switchboard_end(); - - return TRUE; -} - -static PurpleAccount *find_acct(const char *prpl, const char *acct_id) -{ - PurpleAccount *acct = NULL; - - /* If we have a specific acct, use it */ - if (acct_id) { - acct = purple_accounts_find(acct_id, prpl); - if (acct && !purple_account_is_connected(acct)) - acct = NULL; - } else { /* Otherwise find an active account for the protocol */ - GList *l = purple_accounts_get_all(); - while (l) { - if (!strcmp(prpl, purple_account_get_protocol_id(l->data)) - && purple_account_is_connected(l->data)) { - acct = l->data; - break; - } - l = l->next; - } - } - - return acct; -} - -static gboolean msn_uri_handler(const char *proto, const char *cmd, GHashTable *params) -{ - char *acct_id = g_hash_table_lookup(params, "account"); - PurpleAccount *acct; - - if (g_ascii_strcasecmp(proto, "msnim")) - return FALSE; - - acct = find_acct("prpl-msn", acct_id); - - if (!acct) - return FALSE; - - /* msnim:chat?contact=user@domain.tld */ - if (!g_ascii_strcasecmp(cmd, "Chat")) { - char *sname = g_hash_table_lookup(params, "contact"); - if (sname) { - PurpleConversation *conv = purple_find_conversation_with_account( - PURPLE_CONV_TYPE_IM, sname, acct); - if (conv == NULL) - conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, acct, sname); - purple_conversation_present(conv); - } - /*else - **If pidgindialogs_im() was in the core, we could use it here. - * It is all purple_request_* based, but I'm not sure it really belongs in the core - pidgindialogs_im();*/ - - return TRUE; - } - /* msnim:add?contact=user@domain.tld */ - else if (!g_ascii_strcasecmp(cmd, "Add")) { - char *name = g_hash_table_lookup(params, "contact"); - purple_blist_request_add_buddy(acct, name, NULL, NULL); - return TRUE; - } - - return FALSE; -} - - -static PurplePluginProtocolInfo prpl_info = -{ - OPT_PROTO_MAIL_CHECK|OPT_PROTO_INVITE_MESSAGE, - NULL, /* user_splits */ - NULL, /* protocol_options */ - {"png,gif", 0, 0, 96, 96, 0, PURPLE_ICON_SCALE_SEND}, /* icon_spec */ - msn_list_icon, /* list_icon */ - msn_list_emblems, /* list_emblems */ - msn_status_text, /* status_text */ - msn_tooltip_text, /* tooltip_text */ - msn_status_types, /* away_states */ - msn_blist_node_menu, /* blist_node_menu */ - NULL, /* chat_info */ - NULL, /* chat_info_defaults */ - msn_login, /* login */ - msn_close, /* close */ - msn_send_im, /* send_im */ - NULL, /* set_info */ - msn_send_typing, /* send_typing */ - msn_get_info, /* get_info */ - msn_set_status, /* set_away */ - msn_set_idle, /* set_idle */ - NULL, /* change_passwd */ - NULL, /* add_buddy */ - NULL, /* add_buddies */ - msn_rem_buddy, /* remove_buddy */ - NULL, /* remove_buddies */ - msn_add_permit, /* add_permit */ - msn_add_deny, /* add_deny */ - msn_rem_permit, /* rem_permit */ - msn_rem_deny, /* rem_deny */ - msn_set_permit_deny, /* set_permit_deny */ - NULL, /* join_chat */ - NULL, /* reject chat invite */ - NULL, /* get_chat_name */ - msn_chat_invite, /* chat_invite */ - msn_chat_leave, /* chat_leave */ - NULL, /* chat_whisper */ - msn_chat_send, /* chat_send */ - msn_keepalive, /* keepalive */ - NULL, /* register_user */ - NULL, /* get_cb_info */ - NULL, /* get_cb_away */ - msn_alias_buddy, /* alias_buddy */ - msn_group_buddy, /* group_buddy */ - msn_rename_group, /* rename_group */ - NULL, /* buddy_free */ - msn_convo_closed, /* convo_closed */ - msn_normalize, /* normalize */ - msn_set_buddy_icon, /* set_buddy_icon */ - msn_remove_group, /* remove_group */ - NULL, /* get_cb_real_name */ - NULL, /* set_chat_topic */ - NULL, /* find_blist_chat */ - NULL, /* roomlist_get_list */ - NULL, /* roomlist_cancel */ - NULL, /* roomlist_expand_category */ - msn_can_receive_file, /* can_receive_file */ - msn_send_file, /* send_file */ - msn_new_xfer, /* new_xfer */ - msn_offline_message, /* offline_message */ - NULL, /* whiteboard_prpl_ops */ - NULL, /* send_raw */ - NULL, /* roomlist_room_serialize */ - NULL, /* unregister_user */ - msn_send_attention, /* send_attention */ - msn_attention_types, /* attention_types */ - sizeof(PurplePluginProtocolInfo), /* struct_size */ - msn_get_account_text_table, /* get_account_text_table */ - NULL, /* initiate_media */ - NULL, /* get_media_caps */ - NULL, /* get_moods */ - msn_set_public_alias, /* set_public_alias */ - msn_get_public_alias, /* get_public_alias */ - msn_add_buddy, /* add_buddy_with_invite */ - NULL /* add_buddies_with_invite */ -}; - -static PurplePluginInfo info = -{ - PURPLE_PLUGIN_MAGIC, - PURPLE_MAJOR_VERSION, - PURPLE_MINOR_VERSION, - PURPLE_PLUGIN_PROTOCOL, /**< type */ - NULL, /**< ui_requirement */ - 0, /**< flags */ - NULL, /**< dependencies */ - PURPLE_PRIORITY_DEFAULT, /**< priority */ - - "prpl-msn", /**< id */ - "MSN", /**< name */ - DISPLAY_VERSION, /**< version */ - N_("Windows Live Messenger Protocol Plugin"), /**< summary */ - N_("Windows Live Messenger Protocol Plugin"), /**< description */ - NULL, /**< author */ - PURPLE_WEBSITE, /**< homepage */ - - msn_load, /**< load */ - msn_unload, /**< unload */ - NULL, /**< destroy */ - - NULL, /**< ui_info */ - &prpl_info, /**< extra_info */ - NULL, /**< prefs_info */ - msn_actions, - - /* padding */ - NULL, - NULL, - NULL, - NULL -}; - -static void -init_plugin(PurplePlugin *plugin) -{ - PurpleAccountOption *option; - - option = purple_account_option_string_new(_("Server"), "server", - MSN_SERVER); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, - option); - - option = purple_account_option_int_new(_("Port"), "port", MSN_PORT); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, - option); - - option = purple_account_option_bool_new(_("Use HTTP Method"), - "http_method", FALSE); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, - option); - - option = purple_account_option_string_new(_("HTTP Method Server"), - "http_method_server", MSN_HTTPCONN_SERVER); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, - option); - - option = purple_account_option_bool_new(_("Show custom smileys"), - "custom_smileys", TRUE); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, - option); - - option = purple_account_option_bool_new(_("Allow direct connections"), - "direct_connect", TRUE); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, - option); - - option = purple_account_option_bool_new(_("Allow connecting from multiple locations"), - "mpop", TRUE); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, - option); - - purple_cmd_register("nudge", "", PURPLE_CMD_P_PRPL, - PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PRPL_ONLY, - "prpl-msn", msn_cmd_nudge, - _("nudge: nudge a user to get their attention"), NULL); - - purple_prefs_remove("/plugins/prpl/msn"); - - purple_signal_connect(purple_get_core(), "uri-handler", plugin, - PURPLE_CALLBACK(msn_uri_handler), NULL); -} - -PURPLE_INIT_PLUGIN(msn, init_plugin, info); diff --git a/libpurple/protocols/msn/msn.h b/libpurple/protocols/msn/msn.h deleted file mode 100644 index 7af87eceb2..0000000000 --- a/libpurple/protocols/msn/msn.h +++ /dev/null @@ -1,158 +0,0 @@ -/** - * @file msn.h The MSN protocol plugin - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_H -#define MSN_H - -typedef enum -{ - MSN_CAP_VIA_MOBILE = 0x0000001, - MSN_CAP_VIA_TEXAS = 0x0000002, - MSN_CAP_INK_GIF = 0x0000004, - MSN_CAP_INK_ISF = 0x0000008, - MSN_CAP_VIDEO_CHAT = 0x0000010, - MSN_CAP_PACKET = 0x0000020, - MSN_CAP_MOBILE_ON = 0x0000040, - MSN_CAP_WEB_WATCH = 0x0000080, - MSN_CAP_ACTIVITIES = 0x0000100, - MSN_CAP_VIA_WEBIM = 0x0000200, - MSN_CAP_MOBILE_DEV = 0x0000400, - MSN_CAP_VIA_FEDERATED = 0x0000800, - MSN_CAP_SPACE = 0x0001000, - MSN_CAP_MCE = 0x0002000, - MSN_CAP_DIRECTIM = 0x0004000, - MSN_CAP_WINKS = 0x0008000, - MSN_CAP_SEARCH = 0x0010000, - MSN_CAP_BOT = 0x0020000, - MSN_CAP_VOICEIM = 0x0040000, - MSN_CAP_SCHANNEL = 0x0080000, - MSN_CAP_SIP_INVITE = 0x0100000, - MSN_CAP_MULTI_VV = 0x0200000, - MSN_CAP_SDRIVE = 0x0400000, - MSN_CAP_PAGEMODE_MSG = 0x080000, - MSN_CAP_ONECARE = 0x1000000, - MSN_CAP_P2P_TURN = 0x2000000, - MSN_CAP_P2P_BOOTSTRAP_VIA_UUN = 0x4000000, - MSN_CAP_ALIASED = 0x8000000 -} MsnClientCaps; - -typedef enum -{ - MSN_EXT_CAP_SMS_ONLY = 0x1, - MSN_EXT_CAP_VOICE_OVER_MSNP = 0x2, - MSN_EXT_CAP_UUCP_SIP = 0x4, - MSN_EXT_CAP_APP_MSGS = 0x8, - MSN_EXT_CAP_RTC_VIDEO = 0x10, - MSN_EXT_CAP_P2PV2 = 0x20, - MSN_EXT_CAP_AUTH_WEBIM = 0x40, - MSN_EXT_CAP_1ON1_VIA_GROUP = 0x80, - MSN_EXT_CAP_OFFLINEIM = 0x100, - MSN_EXT_CAP_SHARING_VIDEO = 0x200, - MSN_EXT_CAP_NUDGE = 0x400, - MSN_EXT_CAP_CIRCLE_VOICEIM = 0x800, - MSN_EXT_CAP_SHARING = 0x1000, - MSN_EXT_CAP_P2P_MIXER_RELAY = 0x8000, - MSN_EXT_CAP_CONV_WINDOW_FT = 0x20000, - MSN_EXT_CAP_VIDEO_16x9 = 0x40000, - MSN_EXT_CAP_P2P_ENVELOPE = 0x80000, - MSN_EXT_CAP_YAHOOIM_DISABLE = 0x400000, - MSN_EXT_CAP_SIP_TUNNELv2 = 0x800000, - MSN_EXT_CAP_VOICE_CLIP_WMA = 0x1000000, - MSN_EXT_CAP_VOICE_CLIP_CIRCLEIM = 0x2000000, - MSN_EXT_CAP_SOCIAL_NEWS = 0x4000000, - MSN_EXT_CAP_CUSTOM_SMILEY = 0x8000000, - MSN_EXT_CAP_UTF8_MOODS = 0x10000000, - MSN_EXT_CAP_FTURN = 0x20000000, - MSN_EXT_CAP_P4_ACTIVITY = 0x40000000, - MSN_EXT_CAP_MUC = 0x80000000 -} MsnClientExtCaps; - -typedef enum -{ - MSN_CLIENT_VER_5_0 = 0x00, - MSN_CLIENT_VER_6_0 = 0x10, /* MSNC1 */ - MSN_CLIENT_VER_6_1 = 0x20, /* MSNC2 */ - MSN_CLIENT_VER_6_2 = 0x30, /* MSNC3 */ - MSN_CLIENT_VER_7_0 = 0x40, /* MSNC4 */ - MSN_CLIENT_VER_7_5 = 0x50, /* MSNC5 */ - MSN_CLIENT_VER_8_0 = 0x60, /* MSNC6 */ - MSN_CLIENT_VER_8_1 = 0x70, /* MSNC7 */ - MSN_CLIENT_VER_8_5 = 0x80, /* MSNC8 */ - MSN_CLIENT_VER_9_0 = 0x90, /* MSNC9 */ - MSN_CLIENT_VER_14_0 = 0xA0, /* MSNC10 */ - MSN_CLIENT_VER_15_0 = 0xB0 /* MSNC11 */ -} MsnClientVerId; - -#include "internal.h" - -#include "session.h" - -#include "msg.h" - -#define MSN_BUF_LEN 8192 - -/* Windows Live Messenger Server*/ -#define MSN_SERVER "messenger.hotmail.com" -#define MSN_HTTPCONN_SERVER "gateway.messenger.hotmail.com" -#define MSN_PORT 1863 -#define WLM_PROT_VER 18 - -#define WLM_MAX_PROTOCOL 18 -#define WLM_MIN_PROTOCOL 18 - -#define MSN_TYPING_RECV_TIMEOUT 6 -#define MSN_TYPING_SEND_TIMEOUT 4 - -#define PROFILE_URL "http://spaces.live.com/profile.aspx?mem=" -#define PHOTO_URL " contactparams:photopreauthurl=\"" - -#define BUDDY_ALIAS_MAXLEN 387 - -#define MSN_CAM_GUID "4BD96FC0-AB17-4425-A14A-439185962DC8" -#define MSN_CAM_REQUEST_GUID "1C9AA97E-9C05-4583-A3BD-908A196F1E92" -#define MSN_FT_GUID "5D3E02AB-6190-11D3-BBBB-00C04F795683" -#define MSN_OBJ_GUID "A4268EEC-FEC5-49E5-95C3-F126696BDBF6" - -#define MSN_CLIENTINFO \ - "Client-Name: Purple/" VERSION "\r\n" \ - "Chat-Logging: Y\r\n" - -/* Index into attention_types */ -#define MSN_NUDGE 0 - -#define MSN_CLIENT_ID_VERSION MSN_CLIENT_VER_9_0 -#define MSN_CLIENT_ID_CAPABILITIES (MSN_CAP_PACKET|MSN_CAP_INK_GIF|MSN_CAP_VOICEIM) -#define MSN_CLIENT_ID_EXT_CAPS (0) - -#define MSN_CLIENT_ID \ - ((MSN_CLIENT_ID_VERSION << 24) | \ - (MSN_CLIENT_ID_CAPABILITIES)) - -void -msn_set_public_alias(PurpleConnection *gc, const char *alias, - PurpleSetPublicAliasSuccessCallback success_cb, - PurpleSetPublicAliasFailureCallback failure_cb); -void msn_send_privacy(PurpleConnection *gc); -void msn_send_im_message(MsnSession *session, MsnMessage *msg); - -#endif /* MSN_H */ diff --git a/libpurple/protocols/msn/msnutils.c b/libpurple/protocols/msn/msnutils.c deleted file mode 100644 index d2edd36fa0..0000000000 --- a/libpurple/protocols/msn/msnutils.c +++ /dev/null @@ -1,719 +0,0 @@ -/** - * @file msnutils.c Utility functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" - -#include "msn.h" -#include "msnutils.h" - -#include "cipher.h" - -/************************************************************************** - * Util - **************************************************************************/ -char * -rand_guid(void) -{ - return g_strdup_printf("%4X%4X-%4X-%4X-%4X-%4X%4X%4X", - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111); -} - -void -msn_parse_format(const char *mime, char **pre_ret, char **post_ret) -{ - char *cur; - GString *pre = g_string_new(NULL); - GString *post = g_string_new(NULL); - unsigned int colors[3]; - - if (pre_ret != NULL) *pre_ret = NULL; - if (post_ret != NULL) *post_ret = NULL; - - cur = strstr(mime, "FN="); - - if (cur && (*(cur = cur + 3) != ';')) - { - pre = g_string_append(pre, "<FONT FACE=\""); - - while (*cur && *cur != ';') - { - pre = g_string_append_c(pre, *cur); - cur++; - } - - pre = g_string_append(pre, "\">"); - post = g_string_prepend(post, "</FONT>"); - } - - cur = strstr(mime, "EF="); - - if (cur && (*(cur = cur + 3) != ';')) - { - while (*cur && *cur != ';') - { - pre = g_string_append_c(pre, '<'); - pre = g_string_append_c(pre, *cur); - pre = g_string_append_c(pre, '>'); - post = g_string_prepend_c(post, '>'); - post = g_string_prepend_c(post, *cur); - post = g_string_prepend_c(post, '/'); - post = g_string_prepend_c(post, '<'); - cur++; - } - } - - cur = strstr(mime, "CO="); - - if (cur && (*(cur = cur + 3) != ';')) - { - int i; - - i = sscanf(cur, "%02x%02x%02x;", &colors[0], &colors[1], &colors[2]); - - if (i > 0) - { - char tag[64]; - - if (i == 1) - { - colors[1] = 0; - colors[2] = 0; - } - else if (i == 2) - { - unsigned int temp = colors[0]; - - colors[0] = colors[1]; - colors[1] = temp; - colors[2] = 0; - } - else if (i == 3) - { - unsigned int temp = colors[2]; - - colors[2] = colors[0]; - colors[0] = temp; - } - - g_snprintf(tag, sizeof(tag), - "<FONT COLOR=\"#%02x%02x%02x\">", - colors[0] & 0xFF, colors[1] & 0xFF, - colors[2] & 0xFF); - - pre = g_string_append(pre, tag); - post = g_string_prepend(post, "</FONT>"); - } - } - - cur = strstr(mime, "RL="); - - if (cur && (*(cur = cur + 3) != ';')) - { - if (*cur == '1') - { - /* RTL text was received */ - pre = g_string_append(pre, "<SPAN style=\"direction:rtl;text-align:right;\">"); - post = g_string_prepend(post, "</SPAN>"); - } - } - - cur = g_strdup(purple_url_decode(pre->str)); - g_string_free(pre, TRUE); - - if (pre_ret != NULL) - *pre_ret = cur; - else - g_free(cur); - - cur = g_strdup(purple_url_decode(post->str)); - g_string_free(post, TRUE); - - if (post_ret != NULL) - *post_ret = cur; - else - g_free(cur); -} - -/*encode the str to RFC2047 style - * Currently only support the UTF-8 and base64 encode - */ -char * -msn_encode_mime(const char *str) -{ - gchar *base64, *retval; - - g_return_val_if_fail(str != NULL, NULL); - - base64 = purple_base64_encode((guchar *)str, strlen(str)); - retval = g_strdup_printf("=?utf-8?B?%s?=", base64); - g_free(base64); - - return retval; -} - -/* - * We need this because we're only supposed to encode spaces in the font - * names. purple_url_encode() isn't acceptable. - */ -gboolean -msn_encode_spaces(const char *str, char *buf, size_t len) -{ - char *nonspace = buf; - - while (isspace(*str)) - str++; - - for (; *str && len > 1; str++) { - if (*str == '%') { - if (len < 4) - break; - *buf++ = '%'; - *buf++ = '2'; - *buf++ = '5'; - len -= 3; - nonspace = buf; - } else if (*str == ' ') { - if (len < 4) - break; - *buf++ = '%'; - *buf++ = '2'; - *buf++ = '0'; - len -= 3; - } else { - *buf++ = *str; - len--; - nonspace = buf; - } - } - - *nonspace = '\0'; - - return (*str == '\0'); -} - -/* - * Taken from the zephyr plugin. - * This parses HTML formatting (put out by one of the gtkimhtml widgets - * and converts it to msn formatting. It doesn't deal with the tag closing, - * but gtkimhtml widgets give valid html. - * It currently deals properly with <b>, <u>, <i>, <font face=...>, - * <font color=...>, <span dir=...>, <span style="direction: ...">. - * It ignores <font back=...> and <font size=...> - */ -void -msn_import_html(const char *html, char **attributes, char **message) -{ - int len, retcount = 0; - const char *c; - char *msg; - char *fontface = NULL; - char fontface_encoded[BUF_LEN]; - char fonteffect[5]; - char fontcolor[7]; - char direction = '0'; - - gboolean has_bold = FALSE; - gboolean has_italic = FALSE; - gboolean has_underline = FALSE; - gboolean has_strikethrough = FALSE; - - g_return_if_fail(html != NULL); - g_return_if_fail(attributes != NULL); - g_return_if_fail(message != NULL); - - len = strlen(html); - msg = g_malloc0(len + 1); - - memset(fontcolor, 0, sizeof(fontcolor)); - strcat(fontcolor, "0"); - memset(fonteffect, 0, sizeof(fonteffect)); - - for (c = html; *c != '\0';) - { - if (*c == '<') - { - if (!g_ascii_strncasecmp(c + 1, "br>", 3)) - { - msg[retcount++] = '\r'; - msg[retcount++] = '\n'; - c += 4; - } - else if (!g_ascii_strncasecmp(c + 1, "i>", 2)) - { - if (!has_italic) - { - strcat(fonteffect, "I"); - has_italic = TRUE; - } - c += 3; - } - else if (!g_ascii_strncasecmp(c + 1, "b>", 2)) - { - if (!has_bold) - { - strcat(fonteffect, "B"); - has_bold = TRUE; - } - c += 3; - } - else if (!g_ascii_strncasecmp(c + 1, "u>", 2)) - { - if (!has_underline) - { - strcat(fonteffect, "U"); - has_underline = TRUE; - } - c += 3; - } - else if (!g_ascii_strncasecmp(c + 1, "s>", 2)) - { - if (!has_strikethrough) - { - strcat(fonteffect, "S"); - has_strikethrough = TRUE; - } - c += 3; - } - else if (!g_ascii_strncasecmp(c + 1, "a href=\"", 8)) - { - c += 9; - - if (!g_ascii_strncasecmp(c, "mailto:", 7)) - c += 7; - - while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2)) - msg[retcount++] = *c++; - - if (*c != '\0') - c += 2; - - /* ignore descriptive string */ - while ((*c != '\0') && g_ascii_strncasecmp(c, "</a>", 4)) - c++; - - if (*c != '\0') - c += 4; - } - else if (!g_ascii_strncasecmp(c + 1, "span", 4)) - { - /* Bi-directional text support using CSS properties in span tags */ - c += 5; - - while (*c != '\0' && *c != '>') - { - while (*c == ' ') - c++; - if (!g_ascii_strncasecmp(c, "dir=\"rtl\"", 9)) - { - c += 9; - direction = '1'; - } - else if (!g_ascii_strncasecmp(c, "style=\"", 7)) - { - /* Parse inline CSS attributes */ - char *attributes; - int attr_len = 0; - c += 7; - while (*(c + attr_len) != '\0' && *(c + attr_len) != '"') - attr_len++; - if (*(c + attr_len) == '"') - { - char *attr_dir; - attributes = g_strndup(c, attr_len); - attr_dir = purple_markup_get_css_property(attributes, "direction"); - if (attr_dir && (!g_ascii_strncasecmp(attr_dir, "RTL", 3))) - direction = '1'; - g_free(attr_dir); - g_free(attributes); - } - - } - else - { - c++; - } - } - if (*c == '>') - c++; - } - else if (!g_ascii_strncasecmp(c + 1, "font", 4)) - { - c += 5; - - while ((*c != '\0') && !g_ascii_strncasecmp(c, " ", 1)) - c++; - - if (!g_ascii_strncasecmp(c, "color=\"#", 7)) - { - c += 8; - - fontcolor[0] = *(c + 4); - fontcolor[1] = *(c + 5); - fontcolor[2] = *(c + 2); - fontcolor[3] = *(c + 3); - fontcolor[4] = *c; - fontcolor[5] = *(c + 1); - - c += 8; - } - else if (!g_ascii_strncasecmp(c, "face=\"", 6)) - { - const char *end = NULL; - const char *comma = NULL; - unsigned int namelen = 0; - - c += 6; - end = strchr(c, '\"'); - comma = strchr(c, ','); - - if (comma == NULL || comma > end) - namelen = (unsigned int)(end - c); - else - namelen = (unsigned int)(comma - c); - - fontface = g_strndup(c, namelen); - c = end + 2; - } - else - { - /* Drop all unrecognized/misparsed font tags */ - while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2)) - c++; - - if (*c != '\0') - c += 2; - } - } - else - { - while ((*c != '\0') && (*c != '>')) - c++; - if (*c != '\0') - c++; - } - } - else if (*c == '&') - { - if (!g_ascii_strncasecmp(c, "<", 4)) - { - msg[retcount++] = '<'; - c += 4; - } - else if (!g_ascii_strncasecmp(c, ">", 4)) - { - msg[retcount++] = '>'; - c += 4; - } - else if (!g_ascii_strncasecmp(c, " ", 6)) - { - msg[retcount++] = ' '; - c += 6; - } - else if (!g_ascii_strncasecmp(c, """, 6)) - { - msg[retcount++] = '"'; - c += 6; - } - else if (!g_ascii_strncasecmp(c, "&", 5)) - { - msg[retcount++] = '&'; - c += 5; - } - else if (!g_ascii_strncasecmp(c, "'", 6)) - { - msg[retcount++] = '\''; - c += 6; - } - else - msg[retcount++] = *c++; - } - else - msg[retcount++] = *c++; - } - - if (fontface == NULL) - fontface = g_strdup("Segoe UI"); - - msn_encode_spaces(fontface, fontface_encoded, BUF_LEN); - *attributes = g_strdup_printf("FN=%s; EF=%s; CO=%s; PF=0; RL=%c", - fontface_encoded, - fonteffect, fontcolor, direction); - *message = msg; - - g_free(fontface); -} - -void -msn_parse_socket(const char *str, char **ret_host, int *ret_port) -{ - char *host; - char *c; - int port; - - host = g_strdup(str); - - if ((c = strchr(host, ':')) != NULL) { - *c = '\0'; - port = atoi(c + 1); - } else { - port = 1863; - } - - *ret_host = host; - *ret_port = port; -} - -void -msn_parse_user(const char *str, char **ret_user, int *ret_network) -{ - char **tokens; - - tokens = g_strsplit(str, ":", 2); - - *ret_network = atoi(tokens[0]); - *ret_user = tokens[1]; - - g_free(tokens[0]); - /* tokens[1] is returned */ - g_free(tokens); -} - -gboolean -msn_email_is_valid(const char *passport) -{ - if (purple_email_is_valid(passport)) { - /* Special characters aren't allowed in domains, so only go to '@' */ - while (*passport != '@') { - if (*passport == '/') - return FALSE; - else if (*passport == '?') - return FALSE; - else if (*passport == '=') - return FALSE; - /* MSN also doesn't like colons, but that's checked already */ - - passport++; - } - - return TRUE; - } - - return FALSE; -} - -/*************************************************************************** - * MSN Challenge Computing Function - ***************************************************************************/ - -/* - * Handle MSN Challenge computation - * This algorithm references - * http://imfreedom.org/wiki/index.php/MSN:NS/Challenges - */ -#define BUFSIZE 256 -void -msn_handle_chl(char *input, char *output) -{ - PurpleCipher *cipher; - PurpleCipherContext *context; - const guchar productKey[] = MSNP15_WLM_PRODUCT_KEY; - const guchar productID[] = MSNP15_WLM_PRODUCT_ID; - const char hexChars[] = "0123456789abcdef"; - char buf[BUFSIZE]; - unsigned char md5Hash[16]; - unsigned char *newHash; - unsigned int *md5Parts; - unsigned int *chlStringParts; - unsigned int newHashParts[5]; - - long long nHigh = 0, nLow = 0; - - int len; - int i; - - /* Create the MD5 hash by using Purple MD5 algorithm */ - cipher = purple_ciphers_find_cipher("md5"); - context = purple_cipher_context_new(cipher, NULL); - - purple_cipher_context_append(context, (guchar *)input, strlen(input)); - purple_cipher_context_append(context, productKey, sizeof(productKey) - 1); - purple_cipher_context_digest(context, sizeof(md5Hash), md5Hash, NULL); - purple_cipher_context_destroy(context); - - /* Split it into four integers */ - md5Parts = (unsigned int *)md5Hash; - for (i = 0; i < 4; i++) { - /* adjust endianess */ - md5Parts[i] = GUINT_TO_LE(md5Parts[i]); - - /* & each integer with 0x7FFFFFFF */ - /* and save one unmodified array for later */ - newHashParts[i] = md5Parts[i]; - md5Parts[i] &= 0x7FFFFFFF; - } - - /* make a new string and pad with '0' to length that's a multiple of 8 */ - snprintf(buf, BUFSIZE - 5, "%s%s", input, productID); - len = strlen(buf); - if ((len % 8) != 0) { - int fix = 8 - (len % 8); - strncpy(&buf[len], "00000000", fix); - buf[len + fix] = '\0'; - len += fix; - } - - /* split into integers */ - chlStringParts = (unsigned int *)buf; - - /* this is magic */ - for (i = 0; i < (len / 4); i += 2) { - long long temp; - - chlStringParts[i] = GUINT_TO_LE(chlStringParts[i]); - chlStringParts[i + 1] = GUINT_TO_LE(chlStringParts[i + 1]); - - temp = (0x0E79A9C1 * (long long)chlStringParts[i]) % 0x7FFFFFFF; - temp = (md5Parts[0] * (temp + nLow) + md5Parts[1]) % 0x7FFFFFFF; - nHigh += temp; - - temp = ((long long)chlStringParts[i + 1] + temp) % 0x7FFFFFFF; - nLow = (md5Parts[2] * temp + md5Parts[3]) % 0x7FFFFFFF; - nHigh += nLow; - } - nLow = (nLow + md5Parts[1]) % 0x7FFFFFFF; - nHigh = (nHigh + md5Parts[3]) % 0x7FFFFFFF; - - newHashParts[0] ^= nLow; - newHashParts[1] ^= nHigh; - newHashParts[2] ^= nLow; - newHashParts[3] ^= nHigh; - - /* adjust endianness */ - for(i = 0; i < 4; i++) - newHashParts[i] = GUINT_TO_LE(newHashParts[i]); - - /* make a string of the parts */ - newHash = (unsigned char *)newHashParts; - - /* convert to hexadecimal */ - for (i = 0; i < 16; i++) - { - output[i * 2] = hexChars[(newHash[i] >> 4) & 0xF]; - output[(i * 2) + 1] = hexChars[newHash[i] & 0xF]; - } - - output[32] = '\0'; -} - -guint8 -msn_read8(const char *buf) -{ - return (guint8)buf[0]; -} - -guint16 -msn_read16le(const char *buf) -{ - return GUINT16_FROM_LE(*(guint16 *)buf); -} - -guint16 -msn_read16be(const char *buf) -{ - return GUINT16_FROM_BE(*(guint16 *)buf); -} - -guint32 -msn_read32le(const char *buf) -{ - return GUINT32_FROM_LE(*(guint32 *)buf); -} - -guint32 -msn_read32be(const char *buf) -{ - return GUINT32_FROM_BE(*(guint32 *)buf); -} - -guint64 -msn_read64le(const char *buf) -{ - return GUINT64_FROM_LE(*(guint64 *)buf); -} - -guint64 -msn_read64be(const char *buf) -{ - return GUINT64_FROM_BE(*(guint64 *)buf); -} - -void -msn_write8(char *buf, guint8 data) -{ - *(guint8 *)buf = data; -} - -void -msn_write16le(char *buf, guint16 data) -{ - *(guint16 *)buf = GUINT16_TO_LE(data); -} - -void -msn_write16be(char *buf, guint16 data) -{ - *(guint16 *)buf = GUINT16_TO_BE(data); -} - -void -msn_write32le(char *buf, guint32 data) -{ - *(guint32 *)buf = GUINT32_TO_LE(data); -} - -void -msn_write32be(char *buf, guint32 data) -{ - *(guint32 *)buf = GUINT32_TO_BE(data); -} - -void -msn_write64le(char *buf, guint64 data) -{ - *(guint64 *)buf = GUINT64_TO_LE(data); -} - -void -msn_write64be(char *buf, guint64 data) -{ - *(guint64 *)buf = GUINT64_TO_BE(data); -} - diff --git a/libpurple/protocols/msn/msnutils.h b/libpurple/protocols/msn/msnutils.h deleted file mode 100644 index c4ed8fcbdf..0000000000 --- a/libpurple/protocols/msn/msnutils.h +++ /dev/null @@ -1,244 +0,0 @@ -/** - * @file msnutils.h Utility functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_UTILS_H -#define MSN_UTILS_H - -/*encode the str to RFC2047 style*/ -char *msn_encode_mime(const char *str); - -/** - * Generate the Random GUID - */ -char *rand_guid(void); - -/** - * Encodes the spaces in a string - * - * @param str The string to be encoded. - * @param buf The buffer to hold the encoded string. - * @param len The maximum length (including NUL) to put in @buf. - * - * @return Whether @str was able to fit in @buf. - */ -gboolean -msn_encode_spaces(const char *str, char *buf, size_t len); - -/** - * Parses the MSN message formatting into a format compatible with Purple. - * - * @param mime The mime header with the formatting. - * @param pre_ret The returned prefix string. - * @param post_ret The returned postfix string. - * - * @return The new message. - */ -void msn_parse_format(const char *mime, char **pre_ret, char **post_ret); - -/** - * Parses the Purple message formatting (html) into the MSN format. - * - * @param html The html message to format. - * @param attributes The returned attributes string. - * @param message The returned message string. - * - * @return The new message. - */ -void msn_import_html(const char *html, char **attributes, char **message); - -/** - * Parses a socket string. - * - * @param str A host:port string. - * @param ret_host Return string value of the host. - * @param ret_port Return integer value of the port. - */ -void msn_parse_socket(const char *str, char **ret_host, int *ret_port); - -/** - * Parses a user name - * - * @param str A network:username string. - * @param ret_user Return of the user's passport. - * @param ret_network Return of the user's network. - */ -void msn_parse_user(const char *str, char **ret_user, int *ret_network); - -/** - * Verify if the email is a vaild passport. - * - * @param passport The email - * - * @return True if it is a valid passport, else FALSE - */ -gboolean msn_email_is_valid(const char *passport); - -/** - * Handle MSN Challenge Computation - * This algorithm references - * http://imfreedom.org/wiki/index.php/MSN:NS/Challenges - * - * @param input Challenge input. - * @param output Callenge output. - */ -void msn_handle_chl(char *input, char *output); - -/** - * Read a byte from a buffer - * - * @param buf Pointer to buffer. - * - * @return 8-bit byte - */ -guint8 msn_read8(const char *buf); - -/** - * Read a little-endian short from a buffer - * - * @param buf Pointer to buffer. - * - * @return 16-bit short - */ -guint16 msn_read16le(const char *buf); - -/** - * Read a big-endian short from a buffer - * - * @param buf Pointer to buffer. - * - * @return 16-bit short - */ -guint16 msn_read16be(const char *buf); - -/** - * Read a little-endian int from a buffer - * - * @param buf Pointer to buffer. - * - * @return 32-bit int - */ -guint32 msn_read32le(const char *buf); - -/** - * Read a big-endian int from a buffer - * - * @param buf Pointer to buffer. - * - * @return 32-bit int - */ -guint32 msn_read32be(const char *buf); - -/** - * Read a little-endian long from a buffer - * - * @param buf Pointer to buffer. - * - * @return 64-bit long - */ -guint64 msn_read64le(const char *buf); - -/** - * Read a big-endian long from a buffer - * - * @param buf Pointer to buffer. - * - * @return 64-bit long - */ -guint64 msn_read64be(const char *buf); - -/** - * Write a byte to a buffer - * - * @param buf Pointer to buffer. - * @param data 8-bit byte. - */ -void msn_write8(char *buf, guint8 data); - -/** - * Write a little-endian short to a buffer - * - * @param buf Pointer to buffer. - * @param data short. - */ -void msn_write16le(char *buf, guint16 data); - -/** - * Write a big-endian short to a buffer - * - * @param buf Pointer to buffer. - * @param data short. - */ -void msn_write16be(char *buf, guint16 data); - -/** - * Write a little-endian int to a buffer - * - * @param buf Pointer to buffer. - * @param data int. - */ -void msn_write32le(char *buf, guint32 data); - -/** - * Write a big-endian int to a buffer - * - * @param buf Pointer to buffer. - * @param data int. - */ -void msn_write32be(char *buf, guint32 data); - -/** - * Write a little-endian long to a buffer - * - * @param buf Pointer to buffer. - * @param data long. - */ -void msn_write64le(char *buf, guint64 data); - -/** - * Write a big-endian long to a buffer - * - * @param buf Pointer to buffer. - * @param data short - */ -void msn_write64be(char *buf, guint64 data); - -/** - * Same as above, but these increment the buf pointer. - */ -#define msn_pop8(buf) msn_read8((buf+=1)-1) -#define msn_pop16le(buf) msn_read16le((buf+=2)-2) -#define msn_pop16be(buf) msn_read16be((buf+=2)-2) -#define msn_pop32le(buf) msn_read32le((buf+=4)-4) -#define msn_pop32be(buf) msn_read32be((buf+=4)-4) -#define msn_pop64le(buf) msn_read64le((buf+=8)-8) -#define msn_pop64be(buf) msn_read64be((buf+=8)-8) -#define msn_push8(buf, data) msn_write8(buf, data), buf+=1 -#define msn_push16le(buf, data) msn_write16le(buf, data), buf+=2 -#define msn_push16be(buf, data) msn_write16be(buf, data), buf+=2 -#define msn_push32le(buf, data) msn_write32le(buf, data), buf+=4 -#define msn_push32be(buf, data) msn_write32be(buf, data), buf+=4 -#define msn_push64le(buf, data) msn_write64le(buf, data), buf+=8 -#define msn_push64be(buf, data) msn_write64be(buf, data), buf+=8 - -#endif /* MSN_UTILS_H */ - diff --git a/libpurple/protocols/msn/nexus.c b/libpurple/protocols/msn/nexus.c deleted file mode 100644 index 34e9f66e6f..0000000000 --- a/libpurple/protocols/msn/nexus.c +++ /dev/null @@ -1,670 +0,0 @@ -/** - * @file nexus.c MSN Nexus functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "cipher.h" -#include "debug.h" - -#include "msnutils.h" -#include "soap.h" -#include "nexus.h" -#include "notification.h" - -/************************************************************************** - * Valid Ticket Tokens - **************************************************************************/ - -#define SSO_VALID_TICKET_DOMAIN 0 -#define SSO_VALID_TICKET_POLICY 1 -static char *ticket_domains[][2] = { - /* http://msnpiki.msnfanatic.com/index.php/MSNP15:SSO */ - /* {"Domain", "Policy Ref URI"}, Purpose */ - {"messengerclear.live.com", NULL}, /* Authentication for messenger. */ - {"messenger.msn.com", "?id=507"}, /* Authentication for receiving OIMs. */ - {"contacts.msn.com", "MBI"}, /* Authentication for the Contact server. */ - {"messengersecure.live.com", "MBI_SSL"}, /* Authentication for sending OIMs. */ - {"storage.live.com", "MBI"}, /* Storage REST API */ - {"sup.live.com", "MBI"}, /* What's New service */ -}; - -/************************************************************************** - * Main - **************************************************************************/ - -MsnNexus * -msn_nexus_new(MsnSession *session) -{ - MsnNexus *nexus; - gsize i; - - nexus = g_new0(MsnNexus, 1); - nexus->session = session; - - nexus->token_len = sizeof(ticket_domains) / sizeof(char *[2]); - nexus->tokens = g_new0(MsnTicketToken, nexus->token_len); - - for (i = 0; i < nexus->token_len; i++) - nexus->tokens[i].token = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, g_free); - - return nexus; -} - -void -msn_nexus_destroy(MsnNexus *nexus) -{ - gsize i; - for (i = 0; i < nexus->token_len; i++) { - g_hash_table_destroy(nexus->tokens[i].token); - g_free(nexus->tokens[i].secret); - g_slist_free(nexus->tokens[i].updates); - } - - g_free(nexus->tokens); - g_free(nexus->policy); - g_free(nexus->nonce); - g_free(nexus->cipher); - g_free(nexus->secret); - g_free(nexus); -} - -/************************************************************************** - * RPS/SSO Authentication - **************************************************************************/ - -static char * -rps_create_key(const char *key, int key_len, const char *data, size_t data_len) -{ - const guchar magic[] = "WS-SecureConversation"; - const int magic_len = sizeof(magic) - 1; - - PurpleCipherContext *hmac; - guchar hash1[20], hash2[20], hash3[20], hash4[20]; - char *result; - - hmac = purple_cipher_context_new_by_name("hmac", NULL); - - purple_cipher_context_set_option(hmac, "hash", "sha1"); - purple_cipher_context_set_key_with_len(hmac, (guchar *)key, key_len); - purple_cipher_context_append(hmac, magic, magic_len); - purple_cipher_context_append(hmac, (guchar *)data, data_len); - purple_cipher_context_digest(hmac, sizeof(hash1), hash1, NULL); - - purple_cipher_context_reset(hmac, NULL); - purple_cipher_context_set_option(hmac, "hash", "sha1"); - purple_cipher_context_set_key_with_len(hmac, (guchar *)key, key_len); - purple_cipher_context_append(hmac, hash1, 20); - purple_cipher_context_append(hmac, magic, magic_len); - purple_cipher_context_append(hmac, (guchar *)data, data_len); - purple_cipher_context_digest(hmac, sizeof(hash2), hash2, NULL); - - purple_cipher_context_reset(hmac, NULL); - purple_cipher_context_set_option(hmac, "hash", "sha1"); - purple_cipher_context_set_key_with_len(hmac, (guchar *)key, key_len); - purple_cipher_context_append(hmac, hash1, 20); - purple_cipher_context_digest(hmac, sizeof(hash3), hash3, NULL); - - purple_cipher_context_reset(hmac, NULL); - purple_cipher_context_set_option(hmac, "hash", "sha1"); - purple_cipher_context_set_key_with_len(hmac, (guchar *)key, key_len); - purple_cipher_context_append(hmac, hash3, sizeof(hash3)); - purple_cipher_context_append(hmac, magic, magic_len); - purple_cipher_context_append(hmac, (guchar *)data, data_len); - purple_cipher_context_digest(hmac, sizeof(hash4), hash4, NULL); - - purple_cipher_context_destroy(hmac); - - result = g_malloc(24); - memcpy(result, hash2, sizeof(hash2)); - memcpy(result + sizeof(hash2), hash4, 4); - - return result; -} - -static char * -des3_cbc(const char *key, const char *iv, const char *data, int len, gboolean decrypt) -{ - PurpleCipherContext *des3; - char *out; - size_t outlen; - - des3 = purple_cipher_context_new_by_name("des3", NULL); - purple_cipher_context_set_key(des3, (guchar *)key); - purple_cipher_context_set_batch_mode(des3, PURPLE_CIPHER_BATCH_MODE_CBC); - purple_cipher_context_set_iv(des3, (guchar *)iv, 8); - - out = g_malloc(len); - if (decrypt) - purple_cipher_context_decrypt(des3, (guchar *)data, len, (guchar *)out, &outlen); - else - purple_cipher_context_encrypt(des3, (guchar *)data, len, (guchar *)out, &outlen); - - purple_cipher_context_destroy(des3); - - return out; -} - -#define MSN_USER_KEY_SIZE (7*4 + 8 + 20 + 72) -#define CRYPT_MODE_CBC 1 -#define CIPHER_TRIPLE_DES 0x6603 -#define HASH_SHA1 0x8004 -static char * -msn_rps_encrypt(MsnNexus *nexus) -{ - char usr_key_base[MSN_USER_KEY_SIZE], *usr_key; - const char magic1[] = "SESSION KEY HASH"; - const char magic2[] = "SESSION KEY ENCRYPTION"; - PurpleCipherContext *hmac; - size_t len; - guchar *hash; - char *key1, *key2, *key3; - gsize key1_len; - const char *iv; - char *nonce_fixed; - char *cipher; - char *response; - - usr_key = &usr_key_base[0]; - /* Header */ - msn_push32le(usr_key, 28); /* Header size */ - msn_push32le(usr_key, CRYPT_MODE_CBC); /* Crypt mode */ - msn_push32le(usr_key, CIPHER_TRIPLE_DES); /* Cipher type */ - msn_push32le(usr_key, HASH_SHA1); /* Hash type */ - msn_push32le(usr_key, 8); /* IV size */ - msn_push32le(usr_key, 20); /* Hash size */ - msn_push32le(usr_key, 72); /* Cipher size */ - /* Data */ - iv = usr_key; - msn_push32le(usr_key, rand()); - msn_push32le(usr_key, rand()); - hash = (guchar *)usr_key; - usr_key += 20; /* Remaining is cipher data */ - - key1 = (char *)purple_base64_decode((const char *)nexus->tokens[MSN_AUTH_MESSENGER].secret, &key1_len); - key2 = rps_create_key(key1, key1_len, magic1, sizeof(magic1) - 1); - key3 = rps_create_key(key1, key1_len, magic2, sizeof(magic2) - 1); - - len = strlen(nexus->nonce); - hmac = purple_cipher_context_new_by_name("hmac", NULL); - purple_cipher_context_set_option(hmac, "hash", "sha1"); - purple_cipher_context_set_key_with_len(hmac, (guchar *)key2, 24); - purple_cipher_context_append(hmac, (guchar *)nexus->nonce, len); - purple_cipher_context_digest(hmac, 20, hash, NULL); - purple_cipher_context_destroy(hmac); - - /* We need to pad this to 72 bytes, apparently */ - nonce_fixed = g_malloc(len + 8); - memcpy(nonce_fixed, nexus->nonce, len); - memset(nonce_fixed + len, 0x08, 8); - cipher = des3_cbc(key3, iv, nonce_fixed, len + 8, FALSE); - g_free(nonce_fixed); - - memcpy(usr_key, cipher, 72); - - g_free(key1); - g_free(key2); - g_free(key3); - g_free(cipher); - - response = purple_base64_encode((guchar *)usr_key_base, MSN_USER_KEY_SIZE); - - return response; -} - -/************************************************************************** - * Login - **************************************************************************/ - -/* Used to specify which token to update when only doing single updates */ -typedef struct _MsnNexusUpdateData MsnNexusUpdateData; -struct _MsnNexusUpdateData { - MsnNexus *nexus; - int id; -}; - -typedef struct _MsnNexusUpdateCallback MsnNexusUpdateCallback; -struct _MsnNexusUpdateCallback { - GSourceFunc cb; - gpointer data; -}; - -static gboolean -nexus_parse_token(MsnNexus *nexus, int id, xmlnode *node) -{ - char *token_str, *expiry_str; - const char *id_str; - char **elems, **cur, **tokens; - xmlnode *token = xmlnode_get_child(node, "RequestedSecurityToken/BinarySecurityToken"); - xmlnode *secret = xmlnode_get_child(node, "RequestedProofToken/BinarySecret"); - xmlnode *expires = xmlnode_get_child(node, "LifeTime/Expires"); - - if (!token) - return FALSE; - - /* Use the ID that the server sent us */ - if (id == -1) { - id_str = xmlnode_get_attrib(token, "Id"); - if (id_str == NULL) - return FALSE; - - id = atol(id_str + 7) - 1; /* 'Compact#' or 'PPToken#' */ - if (id < 0 || (gsize)id >= nexus->token_len) - return FALSE; /* Where did this come from? */ - } - - token_str = xmlnode_get_data(token); - if (token_str == NULL) - return FALSE; - - g_hash_table_remove_all(nexus->tokens[id].token); - - elems = g_strsplit(token_str, "&", 0); - - for (cur = elems; *cur != NULL; cur++) { - tokens = g_strsplit(*cur, "=", 2); - g_hash_table_insert(nexus->tokens[id].token, tokens[0], tokens[1]); - /* Don't free each of the tokens, only the array. */ - g_free(tokens); - } - g_strfreev(elems); - g_free(token_str); - - if (secret) - nexus->tokens[id].secret = xmlnode_get_data(secret); - else - nexus->tokens[id].secret = NULL; - - /* Yay for MS using ISO-8601 */ - expiry_str = xmlnode_get_data(expires); - nexus->tokens[id].expiry = purple_str_to_time(expiry_str, - FALSE, NULL, NULL, NULL); - g_free(expiry_str); - - purple_debug_info("msn", "Updated ticket for domain '%s', expires at %" G_GINT64_FORMAT ".\n", - ticket_domains[id][SSO_VALID_TICKET_DOMAIN], - (gint64)nexus->tokens[id].expiry); - return TRUE; -} - -static gboolean -nexus_parse_collection(MsnNexus *nexus, int id, xmlnode *collection) -{ - xmlnode *node; - gboolean result; - - node = xmlnode_get_child(collection, "RequestSecurityTokenResponse"); - - if (!node) - return FALSE; - - result = TRUE; - for (; node && result; node = node->next) { - xmlnode *endpoint = xmlnode_get_child(node, "AppliesTo/EndpointReference/Address"); - char *address = xmlnode_get_data(endpoint); - - if (g_str_equal(address, "http://Passport.NET/tb")) { - /* This node contains the stuff for updating tokens. */ - char *data; - xmlnode *cipher = xmlnode_get_child(node, "RequestedSecurityToken/EncryptedData/CipherData/CipherValue"); - xmlnode *secret = xmlnode_get_child(node, "RequestedProofToken/BinarySecret"); - - g_free(nexus->cipher); - nexus->cipher = xmlnode_get_data(cipher); - data = xmlnode_get_data(secret); - g_free(nexus->secret); - nexus->secret = (char *)purple_base64_decode(data, NULL); - g_free(data); - - } else { - result = nexus_parse_token(nexus, id, node); - } - g_free(address); - } - - return result; -} - -static void -nexus_got_response_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) -{ - MsnNexus *nexus = data; - MsnSession *session = nexus->session; - const char *ticket; - char *response; - - if (resp == NULL) { - msn_session_set_error(session, MSN_ERROR_SERVCONN, _("Windows Live ID authentication:Unable to connect")); - return; - } - - if (!nexus_parse_collection(nexus, -1, - xmlnode_get_child(resp->xml, - "Body/RequestSecurityTokenResponseCollection"))) { - msn_session_set_error(session, MSN_ERROR_SERVCONN, _("Windows Live ID authentication:Invalid response")); - return; - } - - ticket = msn_nexus_get_token_str(nexus, MSN_AUTH_MESSENGER); - response = msn_rps_encrypt(nexus); - msn_got_login_params(session, ticket, response); - g_free(response); -} - -/*when connect, do the SOAP Style windows Live ID authentication */ -void -msn_nexus_connect(MsnNexus *nexus) -{ - MsnSession *session = nexus->session; - const char *username; - const char *password; - char *password_xml; - GString *domains; - char *request; - gsize i; - - MsnSoapMessage *soap; - - purple_debug_info("msn", "Starting Windows Live ID authentication\n"); - msn_session_set_login_step(session, MSN_LOGIN_STEP_GET_COOKIE); - - username = purple_account_get_username(session->account); - password = purple_connection_get_password(session->account->gc); - if (g_utf8_strlen(password, -1) > 16) { - /* max byte size for 16 utf8 characters is 64 + 1 for the null */ - gchar truncated[65]; - g_utf8_strncpy(truncated, password, 16); - password_xml = g_markup_escape_text(truncated, -1); - } else { - password_xml = g_markup_escape_text(password, -1); - } - - purple_debug_info("msn", "Logging on %s, with policy '%s', nonce '%s'\n", - username, nexus->policy, nexus->nonce); - - domains = g_string_new(NULL); - for (i = 0; i < nexus->token_len; i++) { - g_string_append_printf(domains, MSN_SSO_RST_TEMPLATE, - (int)i+1, - ticket_domains[i][SSO_VALID_TICKET_DOMAIN], - ticket_domains[i][SSO_VALID_TICKET_POLICY] != NULL ? - ticket_domains[i][SSO_VALID_TICKET_POLICY] : - nexus->policy); - } - - request = g_strdup_printf(MSN_SSO_TEMPLATE, username, password_xml, domains->str); - g_free(password_xml); - g_string_free(domains, TRUE); - - soap = msn_soap_message_new(NULL, xmlnode_from_str(request, -1)); - g_free(request); - msn_soap_message_send(session, soap, MSN_SSO_SERVER, SSO_POST_URL, TRUE, - nexus_got_response_cb, nexus); -} - -static void -nexus_got_update_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) -{ - MsnNexusUpdateData *ud = data; - MsnNexus *nexus = ud->nexus; - char iv[8] = {0,0,0,0,0,0,0,0}; - xmlnode *enckey; - char *tmp; - char *nonce; - gsize len; - char *key; - GSList *updates; - -#if 0 - char *decrypted_pp; -#endif - char *decrypted_data; - - if (resp == NULL) - return; - - purple_debug_info("msn", "Got Update Response for %s.\n", ticket_domains[ud->id][SSO_VALID_TICKET_DOMAIN]); - - enckey = xmlnode_get_child(resp->xml, "Header/Security/DerivedKeyToken"); - while (enckey) { - if (g_str_equal(xmlnode_get_attrib(enckey, "Id"), "EncKey")) - break; - enckey = xmlnode_get_next_twin(enckey); - } - if (!enckey) { - purple_debug_error("msn", "Invalid response in token update.\n"); - return; - } - - tmp = xmlnode_get_data(xmlnode_get_child(enckey, "Nonce")); - nonce = (char *)purple_base64_decode(tmp, &len); - key = rps_create_key(nexus->secret, 24, nonce, len); - g_free(tmp); - g_free(nonce); - -#if 0 - /* Don't know what this is for yet */ - tmp = xmlnode_get_data(xmlnode_get_child(resp->xml, - "Header/EncryptedPP/EncryptedData/CipherData/CipherValue")); - if (tmp) { - decrypted_pp = des3_cbc(key, iv, tmp, len, TRUE); - g_free(tmp); - purple_debug_info("msn", "Got Response Header EncryptedPP: %s\n", decrypted_pp); - g_free(decrypted_pp); - } -#endif - - tmp = xmlnode_get_data(xmlnode_get_child(resp->xml, - "Body/EncryptedData/CipherData/CipherValue")); - if (tmp) { - char *unescaped; - xmlnode *rstresponse; - - unescaped = (char *)purple_base64_decode(tmp, &len); - g_free(tmp); - - decrypted_data = des3_cbc(key, iv, unescaped, len, TRUE); - g_free(unescaped); - purple_debug_info("msn", "Got Response Body EncryptedData: %s\n", decrypted_data); - - rstresponse = xmlnode_from_str(decrypted_data, -1); - if (g_str_equal(rstresponse->name, "RequestSecurityTokenResponse")) - nexus_parse_token(nexus, ud->id, rstresponse); - else - nexus_parse_collection(nexus, ud->id, rstresponse); - g_free(decrypted_data); - } - - updates = nexus->tokens[ud->id].updates; - nexus->tokens[ud->id].updates = NULL; - while (updates != NULL) { - MsnNexusUpdateCallback *update = updates->data; - if (update->cb) - purple_timeout_add(0, update->cb, update->data); - g_free(update); - updates = g_slist_delete_link(updates, updates); - } - - g_free(ud); - g_free(key); -} - -void -msn_nexus_update_token(MsnNexus *nexus, int id, GSourceFunc cb, gpointer data) -{ - MsnSession *session = nexus->session; - MsnNexusUpdateData *ud; - MsnNexusUpdateCallback *update; - PurpleCipherContext *sha1; - PurpleCipherContext *hmac; - - char *key; - - guchar digest[20]; - - struct tm *tm; - time_t now; - char *now_str; - char *timestamp; - char *timestamp_b64; - - char *domain; - char *domain_b64; - - char *signedinfo; - gint32 nonce[6]; - int i; - char *nonce_b64; - char *signature_b64; - guchar signature[20]; - - char *request; - MsnSoapMessage *soap; - - update = g_new0(MsnNexusUpdateCallback, 1); - update->cb = cb; - update->data = data; - - if (nexus->tokens[id].updates != NULL) { - /* Update already in progress. Just add to list and return. */ - purple_debug_info("msn", - "Ticket update for user '%s' on domain '%s' in progress. Adding request to queue.\n", - purple_account_get_username(session->account), - ticket_domains[id][SSO_VALID_TICKET_DOMAIN]); - nexus->tokens[id].updates = g_slist_prepend(nexus->tokens[id].updates, - update); - return; - } else { - purple_debug_info("msn", - "Updating ticket for user '%s' on domain '%s'\n", - purple_account_get_username(session->account), - ticket_domains[id][SSO_VALID_TICKET_DOMAIN]); - nexus->tokens[id].updates = g_slist_prepend(nexus->tokens[id].updates, - update); - } - - ud = g_new0(MsnNexusUpdateData, 1); - ud->nexus = nexus; - ud->id = id; - - sha1 = purple_cipher_context_new_by_name("sha1", NULL); - - domain = g_strdup_printf(MSN_SSO_RST_TEMPLATE, - id, - ticket_domains[id][SSO_VALID_TICKET_DOMAIN], - ticket_domains[id][SSO_VALID_TICKET_POLICY] != NULL ? - ticket_domains[id][SSO_VALID_TICKET_POLICY] : - nexus->policy); - purple_cipher_context_append(sha1, (guchar *)domain, strlen(domain)); - purple_cipher_context_digest(sha1, 20, digest, NULL); - domain_b64 = purple_base64_encode(digest, 20); - - now = time(NULL); - tm = gmtime(&now); - now_str = g_strdup(purple_utf8_strftime("%Y-%m-%dT%H:%M:%SZ", tm)); - now += 5*60; - tm = gmtime(&now); - timestamp = g_strdup_printf(MSN_SSO_TIMESTAMP_TEMPLATE, - now_str, - purple_utf8_strftime("%Y-%m-%dT%H:%M:%SZ", tm)); - purple_cipher_context_reset(sha1, NULL); - purple_cipher_context_append(sha1, (guchar *)timestamp, strlen(timestamp)); - purple_cipher_context_digest(sha1, 20, digest, NULL); - timestamp_b64 = purple_base64_encode(digest, 20); - g_free(now_str); - - purple_cipher_context_destroy(sha1); - - signedinfo = g_strdup_printf(MSN_SSO_SIGNEDINFO_TEMPLATE, - id, - domain_b64, - timestamp_b64); - - for (i = 0; i < 6; i++) - nonce[i] = rand(); - nonce_b64 = purple_base64_encode((guchar *)&nonce, sizeof(nonce)); - - key = rps_create_key(nexus->secret, 24, (char *)nonce, sizeof(nonce)); - hmac = purple_cipher_context_new_by_name("hmac", NULL); - purple_cipher_context_set_option(hmac, "hash", "sha1"); - purple_cipher_context_set_key_with_len(hmac, (guchar *)key, 24); - purple_cipher_context_append(hmac, (guchar *)signedinfo, strlen(signedinfo)); - purple_cipher_context_digest(hmac, 20, signature, NULL); - purple_cipher_context_destroy(hmac); - signature_b64 = purple_base64_encode(signature, 20); - - request = g_strdup_printf(MSN_SSO_TOKEN_UPDATE_TEMPLATE, - nexus->cipher, - nonce_b64, - timestamp, - signedinfo, - signature_b64, - domain); - - g_free(nonce_b64); - g_free(domain_b64); - g_free(timestamp_b64); - g_free(timestamp); - g_free(key); - g_free(signature_b64); - g_free(signedinfo); - g_free(domain); - - soap = msn_soap_message_new(NULL, xmlnode_from_str(request, -1)); - g_free(request); - msn_soap_message_send(session, soap, MSN_SSO_SERVER, SSO_POST_URL, TRUE, - nexus_got_update_cb, ud); -} - -GHashTable * -msn_nexus_get_token(MsnNexus *nexus, MsnAuthDomains id) -{ - g_return_val_if_fail(nexus != NULL, NULL); - g_return_val_if_fail(id < nexus->token_len, NULL); - - return nexus->tokens[id].token; -} - -const char * -msn_nexus_get_token_str(MsnNexus *nexus, MsnAuthDomains id) -{ - static char buf[1024]; - GHashTable *token = msn_nexus_get_token(nexus, id); - const char *msn_t; - const char *msn_p; - gint ret; - - g_return_val_if_fail(token != NULL, NULL); - - msn_t = g_hash_table_lookup(token, "t"); - msn_p = g_hash_table_lookup(token, "p"); - - g_return_val_if_fail(msn_t != NULL, NULL); - g_return_val_if_fail(msn_p != NULL, NULL); - - ret = g_snprintf(buf, sizeof(buf) - 1, "t=%s&p=%s", msn_t, msn_p); - g_return_val_if_fail(ret != -1, NULL); - - return buf; -} - diff --git a/libpurple/protocols/msn/nexus.h b/libpurple/protocols/msn/nexus.h deleted file mode 100644 index f6150780e9..0000000000 --- a/libpurple/protocols/msn/nexus.h +++ /dev/null @@ -1,219 +0,0 @@ -/** - * @file nexus.h MSN Nexus functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_NEXUS_H -#define MSN_NEXUS_H - -#include "internal.h" - -typedef struct _MsnNexus MsnNexus; -typedef struct _MsnTicketToken MsnTicketToken; - -/* Index into ticket_tokens in nexus.c Keep updated! */ -typedef enum -{ - MSN_AUTH_MESSENGER = 0, - MSN_AUTH_MESSENGER_WEB = 1, - MSN_AUTH_CONTACTS = 2, - MSN_AUTH_LIVE_SECURE = 3, - MSN_AUTH_STORAGE = 4, - MSN_AUTH_WHATSNEW = 5 -} MsnAuthDomains; - -#define MSN_SSO_SERVER "login.live.com" -#define SSO_POST_URL "/RST.srf" - -#define MSN_SSO_RST_TEMPLATE \ -"<wst:RequestSecurityToken xmlns=\"http://schemas.xmlsoap.org/ws/2004/04/trust\" Id=\"RST%d\">"\ - "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\ - "<wsp:AppliesTo xmlns=\"http://schemas.xmlsoap.org/ws/2002/12/policy\">"\ - "<wsa:EndpointReference xmlns=\"http://schemas.xmlsoap.org/ws/2004/03/addressing\">"\ - "<wsa:Address>%s</wsa:Address>"\ - "</wsa:EndpointReference>"\ - "</wsp:AppliesTo>"\ - "<wsse:PolicyReference xmlns=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" URI=\"%s\"></wsse:PolicyReference>"\ -"</wst:RequestSecurityToken>" - -#define MSN_SSO_TEMPLATE "<?xml version='1.0' encoding='utf-8'?>"\ -"<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\""\ - " xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2003/06/secext\""\ - " xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\""\ - " xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2002/12/policy\""\ - " xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\""\ - " xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/03/addressing\""\ - " xmlns:wssc=\"http://schemas.xmlsoap.org/ws/2004/04/sc\""\ - " xmlns:wst=\"http://schemas.xmlsoap.org/ws/2004/04/trust\">"\ - "<Header>"\ - "<ps:AuthInfo"\ - " xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\""\ - " Id=\"PPAuthInfo\">"\ - "<ps:HostingApp>{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}</ps:HostingApp>"\ - "<ps:BinaryVersion>4</ps:BinaryVersion>"\ - "<ps:UIVersion>1</ps:UIVersion>"\ - "<ps:Cookies></ps:Cookies>"\ - "<ps:RequestParams>AQAAAAIAAABsYwQAAAAxMDMz</ps:RequestParams>"\ - "</ps:AuthInfo>"\ - "<wsse:Security>"\ - "<wsse:UsernameToken Id=\"user\">"\ - "<wsse:Username>%s</wsse:Username>"\ - "<wsse:Password>%s</wsse:Password>"\ - "</wsse:UsernameToken>"\ - "</wsse:Security>"\ - "</Header>"\ - "<Body>"\ - "<ps:RequestMultipleSecurityTokens"\ - " xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\""\ - " Id=\"RSTS\">"\ - "<wst:RequestSecurityToken Id=\"RST0\">"\ - "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\ - "<wsp:AppliesTo>"\ - "<wsa:EndpointReference>"\ - "<wsa:Address>http://Passport.NET/tb</wsa:Address>"\ - "</wsa:EndpointReference>"\ - "</wsp:AppliesTo>"\ - "</wst:RequestSecurityToken>"\ - "%s" /* Other RSTn tokens */\ - "</ps:RequestMultipleSecurityTokens>"\ - "</Body>"\ -"</Envelope>" - -#define MSN_SSO_AUTHINFO_TEMPLATE \ -"<ps:AuthInfo xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"PPAuthInfo\">"\ - "<ps:HostingApp>{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}</ps:HostingApp>"\ - "<ps:BinaryVersion>4</ps:BinaryVersion>"\ - "<ps:UIVersion>1</ps:UIVersion>"\ - "<ps:Cookies></ps:Cookies>"\ - "<ps:RequestParams>AQAAAAIAAABsYwQAAAA0MTA1</ps:RequestParams>"\ -"</ps:AuthInfo>" -/* Not sure what's editable here, so I'll just hard-code the SHA1 hash */ -#define MSN_SSO_AUTHINFO_SHA1_BASE64 "d2IeTF4DAkPEa/tVETHznsivEpc=" - -#define MSN_SSO_TIMESTAMP_TEMPLATE \ -"<wsu:Timestamp xmlns=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" Id=\"Timestamp\">"\ - "<wsu:Created>%s</wsu:Created>"\ - "<wsu:Expires>%s</wsu:Expires>"\ -"</wsu:Timestamp>" - -#define MSN_SSO_SIGNEDINFO_TEMPLATE \ -"<SignedInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">"\ - "<CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></CanonicalizationMethod>"\ - "<SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#hmac-sha1\"></SignatureMethod>"\ - "<Reference URI=\"#RST%d\">"\ - "<Transforms>"\ - "<Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></Transform>"\ - "</Transforms>"\ - "<DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"></DigestMethod>"\ - "<DigestValue>%s</DigestValue>"\ - "</Reference>"\ - "<Reference URI=\"#Timestamp\">"\ - "<Transforms>"\ - "<Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></Transform>"\ - "</Transforms>"\ - "<DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"></DigestMethod>"\ - "<DigestValue>%s</DigestValue>"\ - "</Reference>"\ - "<Reference URI=\"#PPAuthInfo\">"\ - "<Transforms>"\ - "<Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></Transform>"\ - "</Transforms>"\ - "<DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"></DigestMethod>"\ - "<DigestValue>" MSN_SSO_AUTHINFO_SHA1_BASE64 "</DigestValue>"\ - "</Reference>"\ -"</SignedInfo>" - -#define MSN_SSO_TOKEN_UPDATE_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<Envelope"\ - " xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\""\ - " xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2003/06/secext\""\ - " xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\""\ - " xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2002/12/policy\""\ - " xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\""\ - " xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/03/addressing\""\ - " xmlns:wssc=\"http://schemas.xmlsoap.org/ws/2004/04/sc\""\ - " xmlns:wst=\"http://schemas.xmlsoap.org/ws/2004/04/trust\">"\ - "<Header>"\ - MSN_SSO_AUTHINFO_TEMPLATE /* ps:AuthInfo */ \ - "<wsse:Security>"\ - "<EncryptedData xmlns=\"http://www.w3.org/2001/04/xmlenc#\" Id=\"BinaryDAToken0\" Type=\"http://www.w3.org/2001/04/xmlenc#Element\">"\ - "<EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#tripledes-cbc\"></EncryptionMethod>"\ - "<ds:KeyInfo xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">"\ - "<ds:KeyName>http://Passport.NET/STS</ds:KeyName>"\ - "</ds:KeyInfo>"\ - "<CipherData>"\ - "<CipherValue>%s</CipherValue>"\ - "</CipherData>"\ - "</EncryptedData>"\ - "<wssc:DerivedKeyToken Id=\"SignKey\">"\ - "<wsse:RequestedTokenReference>"\ - "<wsse:KeyIdentifier ValueType=\"http://docs.oasis-open.org/wss/2004/XX/oasis-2004XX-wss-saml-token-profile-1.0#SAMLAssertionID\" />"\ - "<wsse:Reference URI=\"#BinaryDAToken0\" />"\ - "</wsse:RequestedTokenReference>"\ - "<wssc:Nonce>%s</wssc:Nonce>"\ - "</wssc:DerivedKeyToken>"\ - "%s" /* wsu:Timestamp */\ - "<Signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\">"\ - "%s" /* SignedInfo */\ - "<SignatureValue>%s</SignatureValue>"\ - "<KeyInfo>"\ - "<wsse:SecurityTokenReference>"\ - "<wsse:Reference URI=\"#SignKey\" />"\ - "</wsse:SecurityTokenReference>"\ - "</KeyInfo>"\ - "</Signature>"\ - "</wsse:Security>"\ - "</Header>"\ - "<Body>"\ - "%s" /* wst:RequestSecurityToken */ \ - "</Body>"\ -"</Envelope>" - -struct _MsnTicketToken { - GHashTable *token; - char *secret; - time_t expiry; - GSList *updates; -}; - -struct _MsnNexus -{ - MsnSession *session; - - /* From server via USR command */ - char *policy; - char *nonce; - - /* From server via SOAP stuff */ - char *cipher; - char *secret; - MsnTicketToken *tokens; - gsize token_len; -}; - -void msn_nexus_connect(MsnNexus *nexus); -MsnNexus *msn_nexus_new(MsnSession *session); -void msn_nexus_destroy(MsnNexus *nexus); -GHashTable *msn_nexus_get_token(MsnNexus *nexus, MsnAuthDomains id); -const char *msn_nexus_get_token_str(MsnNexus *nexus, MsnAuthDomains id); -void msn_nexus_update_token(MsnNexus *nexus, int id, GSourceFunc cb, gpointer data); - -#endif /* MSN_NEXUS_H */ diff --git a/libpurple/protocols/msn/notification.c b/libpurple/protocols/msn/notification.c deleted file mode 100644 index 2b3f3348b6..0000000000 --- a/libpurple/protocols/msn/notification.c +++ /dev/null @@ -1,2480 +0,0 @@ -/** - * @file notification.c Notification server functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "cipher.h" -#include "core.h" -#include "debug.h" - -#include "notification.h" - -#include "contact.h" -#include "error.h" -#include "msnutils.h" -#include "state.h" -#include "userlist.h" - -static MsnTable *cbs_table; - -/************************************************************************** - * Main - **************************************************************************/ - -static void -destroy_cb(MsnServConn *servconn) -{ - MsnNotification *notification; - - notification = servconn->cmdproc->data; - g_return_if_fail(notification != NULL); - - msn_notification_destroy(notification); -} - -MsnNotification * -msn_notification_new(MsnSession *session) -{ - MsnNotification *notification; - MsnServConn *servconn; - - g_return_val_if_fail(session != NULL, NULL); - - notification = g_new0(MsnNotification, 1); - - notification->session = session; - notification->servconn = servconn = msn_servconn_new(session, MSN_SERVCONN_NS); - msn_servconn_set_destroy_cb(servconn, destroy_cb); - - notification->cmdproc = servconn->cmdproc; - notification->cmdproc->data = notification; - notification->cmdproc->cbs_table = cbs_table; - - return notification; -} - -void -msn_notification_destroy(MsnNotification *notification) -{ - notification->cmdproc->data = NULL; - - msn_servconn_set_destroy_cb(notification->servconn, NULL); - - msn_servconn_destroy(notification->servconn); - - g_free(notification); -} - -/************************************************************************** - * Connect - **************************************************************************/ - -static void -connect_cb(MsnServConn *servconn) -{ - MsnCmdProc *cmdproc; - MsnSession *session; - MsnTransaction *trans; - GString *vers; - const char *ver_str; - int i; - - g_return_if_fail(servconn != NULL); - - cmdproc = servconn->cmdproc; - session = servconn->session; - - vers = g_string_new(""); - - for (i = WLM_MAX_PROTOCOL; i >= WLM_MIN_PROTOCOL; i--) - g_string_append_printf(vers, " MSNP%d", i); - - g_string_append(vers, " CVR0"); - - if (session->login_step == MSN_LOGIN_STEP_START) - msn_session_set_login_step(session, MSN_LOGIN_STEP_HANDSHAKE); - else - msn_session_set_login_step(session, MSN_LOGIN_STEP_HANDSHAKE2); - - /* Skip the initial space */ - ver_str = (vers->str + 1); - trans = msn_transaction_new(cmdproc, "VER", "%s", ver_str); - msn_cmdproc_send_trans(cmdproc, trans); - - g_string_free(vers, TRUE); -} - -gboolean -msn_notification_connect(MsnNotification *notification, const char *host, int port) -{ - MsnServConn *servconn; - - g_return_val_if_fail(notification != NULL, FALSE); - - servconn = notification->servconn; - - msn_servconn_set_connect_cb(servconn, connect_cb); - notification->in_use = msn_servconn_connect(servconn, host, port, TRUE); - - return notification->in_use; -} - -void -msn_notification_disconnect(MsnNotification *notification) -{ - g_return_if_fail(notification != NULL); - g_return_if_fail(notification->in_use); - - msn_servconn_disconnect(notification->servconn); - - notification->in_use = FALSE; -} - -/************************************************************************** - * Login - **************************************************************************/ - -void -msn_got_login_params(MsnSession *session, const char *ticket, const char *response) -{ - MsnCmdProc *cmdproc; - MsnTransaction *trans; - - cmdproc = session->notification->cmdproc; - - msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH_END); - - trans = msn_transaction_new(cmdproc, "USR", "SSO S %s %s %s", ticket, response, session->guid); - - msn_cmdproc_send_trans(cmdproc, trans); -} - -static void -cvr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - PurpleAccount *account; - MsnTransaction *trans; - - account = cmdproc->session->account; - - trans = msn_transaction_new(cmdproc, "USR", "SSO I %s", purple_account_get_username(account)); - msn_cmdproc_send_trans(cmdproc, trans); -} - -static void -usr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnSession *session = cmdproc->session; - - if (!g_ascii_strcasecmp(cmd->params[1], "OK")) - { - /* authenticate OK */ - msn_session_set_login_step(session, MSN_LOGIN_STEP_SYN); - } - else if (!g_ascii_strcasecmp(cmd->params[1], "SSO")) - { - /* RPS authentication */ - - if (session->nexus) - msn_nexus_destroy(session->nexus); - - session->nexus = msn_nexus_new(session); - - session->nexus->policy = g_strdup(cmd->params[3]); - session->nexus->nonce = g_strdup(cmd->params[4]); - - msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH_START); - - msn_nexus_connect(session->nexus); - } -} - -static void -usr_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) -{ - MsnErrorType msnerr = 0; - - switch (error) - { - case 500: - case 601: - case 910: - case 921: - msnerr = MSN_ERROR_SERV_UNAVAILABLE; - break; - case 911: - msnerr = MSN_ERROR_AUTH; - break; - default: - return; - break; - } - - msn_session_set_error(cmdproc->session, msnerr, NULL); -} - -static void -ver_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnSession *session; - MsnTransaction *trans; - PurpleAccount *account; - gboolean protocol_supported = FALSE; - guint proto_ver; - size_t i; - - session = cmdproc->session; - account = session->account; - - session->protocol_ver = 0; - for (i = 1; i < cmd->param_count; i++) - { - if (sscanf(cmd->params[i], "MSNP%d", &proto_ver) == 1) { - if (proto_ver >= WLM_MIN_PROTOCOL - && proto_ver <= WLM_MAX_PROTOCOL - && proto_ver > session->protocol_ver) { - protocol_supported = TRUE; - session->protocol_ver = proto_ver; - } - } - } - - if (!protocol_supported) - { - msn_session_set_error(session, MSN_ERROR_UNSUPPORTED_PROTOCOL, - NULL); - return; - } - - purple_debug_info("msn", "Negotiated protocol version %d with the server.\n", session->protocol_ver); - - /* - * Windows Live Messenger 8.5 - * Notice :CVR String discriminate! - * reference of http://www.microsoft.com/globaldev/reference/oslocversion.mspx - * to see the Local ID - */ - trans = msn_transaction_new(cmdproc, "CVR", - "0x0409 winnt 5.1 i386 MSNMSGR 8.5.1302 BC01 %s", - purple_account_get_username(account)); - msn_cmdproc_send_trans(cmdproc, trans); -} - -/************************************************************************** - * Log out - **************************************************************************/ - -static void -out_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - if (cmd->param_count == 0) - msn_session_set_error(cmdproc->session, -1, NULL); - else if (!g_ascii_strcasecmp(cmd->params[0], "OTH")) - msn_session_set_error(cmdproc->session, MSN_ERROR_SIGN_OTHER, - NULL); - else if (!g_ascii_strcasecmp(cmd->params[0], "SSD")) - msn_session_set_error(cmdproc->session, MSN_ERROR_SERV_DOWN, NULL); -} - -void -msn_notification_close(MsnNotification *notification) -{ - MsnTransaction *trans; - - g_return_if_fail(notification != NULL); - - if (!notification->in_use) - return; - - trans = msn_transaction_new(notification->cmdproc, "OUT", NULL); - msn_transaction_set_saveable(trans, FALSE); - msn_cmdproc_send_trans(notification->cmdproc, trans); - - msn_notification_disconnect(notification); -} - -/************************************************************************** - * Messages - **************************************************************************/ - -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); - if (purple_debug_is_verbose()) - msn_message_show_readable(msg, "Notification", TRUE); - - msn_cmdproc_process_msg(cmdproc, msg); - - msn_message_unref(msg); -} - -static void -msg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - purple_debug_info("msn", "Processing MSG... \n"); - - /* NOTE: cmd is not always cmdproc->last_cmd, sometimes cmd is a queued - * command and we are processing it */ - if (cmd->payload == NULL) { - cmdproc->last_cmd->payload_cb = msg_cmd_post; - cmd->payload_len = atoi(cmd->params[2]); - } else { - g_return_if_fail(cmd->payload_cb != NULL); - -#if 0 /* glib on win32 doesn't correctly support precision modifiers for a string */ - purple_debug_info("msn", "MSG payload:{%.*s}\n", (guint)cmd->payload_len, cmd->payload); -#endif - cmd->payload_cb(cmdproc, cmd, cmd->payload, cmd->payload_len); - } -} - -/*send Message to Yahoo Messenger*/ -void -msn_notification_send_uum(MsnSession *session, MsnMessage *msg) -{ - MsnCmdProc *cmdproc; - MsnTransaction *trans; - char *payload; - gsize payload_len; - int type; - MsnUser *user; - int network; - - g_return_if_fail(msg != NULL); - - cmdproc = session->notification->cmdproc; - - payload = msn_message_gen_payload(msg, &payload_len); - type = msg->type; - user = msn_userlist_find_user(session->userlist, msg->remote_user); - if (user) - network = msn_user_get_network(user); - else - network = MSN_NETWORK_PASSPORT; - - purple_debug_info("msn", - "send UUM, payload{%s}, strlen:%" G_GSIZE_FORMAT ", len:%" G_GSIZE_FORMAT "\n", - payload, strlen(payload), payload_len); - - trans = msn_transaction_new(cmdproc, "UUM", "%s %d %d %" G_GSIZE_FORMAT, - msg->remote_user, network, type, payload_len); - msn_transaction_set_payload(trans, payload, strlen(payload)); - msn_cmdproc_send_trans(cmdproc, trans); -} - -/*Yahoo msg process*/ -static void -ubm_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - purple_debug_info("msn", "Processing UBM... \n"); - - /* NOTE: cmd is not always cmdproc->last_cmd, sometimes cmd is a queued - * command and we are processing it */ - if (cmd->payload == NULL) { - cmdproc->last_cmd->payload_cb = msg_cmd_post; - cmd->payload_len = atoi(cmd->params[5]); - } else { - g_return_if_fail(cmd->payload_cb != NULL); - - purple_debug_info("msn", "UBM payload:{%.*s}\n", (guint)(cmd->payload_len), cmd->payload); - msg_cmd_post(cmdproc, cmd, cmd->payload, cmd->payload_len); - } -} - -/************************************************************************** - * Challenges - * we use MD5 to caculate the Challenges - **************************************************************************/ -static void -chl_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnTransaction *trans; - char buf[33]; - - msn_handle_chl(cmd->params[1], buf); - trans = msn_transaction_new(cmdproc, "QRY", "%s 32", MSNP15_WLM_PRODUCT_ID); - - msn_transaction_set_payload(trans, buf, 32); - - msn_cmdproc_send_trans(cmdproc, trans); -} - -/************************************************************************** - * Buddy Lists - **************************************************************************/ - -typedef struct MsnFqyCbData { - MsnFqyCb cb; - gpointer data; -} MsnFqyCbData; - -/* add contact to xmlnode */ -static void -msn_add_contact_xml(xmlnode *mlNode, const char *passport, MsnListOp list_op, MsnNetwork networkId) -{ - xmlnode *d_node,*c_node; - char **tokens; - const char *email,*domain; - char fmt_str[3]; - - g_return_if_fail(passport != NULL); - - purple_debug_info("msn", "Passport: %s, type: %d\n", passport, networkId); - tokens = g_strsplit(passport, "@", 2); - email = tokens[0]; - domain = tokens[1]; - - if (email == NULL || domain == NULL) { - purple_debug_error("msn", "Invalid passport (%s) specified to add to contact xml.\n", passport); - g_strfreev(tokens); - g_return_if_reached(); - } - - /*find a domain Node*/ - for (d_node = xmlnode_get_child(mlNode, "d"); d_node; - d_node = xmlnode_get_next_twin(d_node)) { - const char *attr = xmlnode_get_attrib(d_node,"n"); - if (attr == NULL) - continue; - if (!strcmp(attr, domain)) - break; - } - - if (d_node == NULL) { - /*domain not found, create a new domain Node*/ - purple_debug_info("msn", "Didn't find existing domain node, adding one.\n"); - d_node = xmlnode_new("d"); - xmlnode_set_attrib(d_node, "n", domain); - xmlnode_insert_child(mlNode, d_node); - } - - /*create contact node*/ - c_node = xmlnode_new("c"); - xmlnode_set_attrib(c_node, "n", email); - - if (list_op != 0) { - purple_debug_info("msn", "list_op: %d\n", list_op); - g_snprintf(fmt_str, sizeof(fmt_str), "%d", list_op); - xmlnode_set_attrib(c_node, "l", fmt_str); - } - - if (networkId != MSN_NETWORK_UNKNOWN) { - g_snprintf(fmt_str, sizeof(fmt_str), "%d", networkId); - /*mobile*/ - /*type_str = g_strdup_printf("4");*/ - xmlnode_set_attrib(c_node, "t", fmt_str); - } - - xmlnode_insert_child(d_node, c_node); - - g_strfreev(tokens); -} - -static void -msn_notification_post_adl(MsnCmdProc *cmdproc, const char *payload, int payload_len) -{ - MsnTransaction *trans; - purple_debug_info("msn", "Sending ADL with payload: %s\n", payload); - trans = msn_transaction_new(cmdproc, "ADL", "%i", payload_len); - msn_transaction_set_payload(trans, payload, payload_len); - msn_cmdproc_send_trans(cmdproc, trans); -} - -static void -msn_notification_post_rml(MsnCmdProc *cmdproc, const char *payload, int payload_len) -{ - MsnTransaction *trans; - purple_debug_info("msn", "Sending RML with payload: %s\n", payload); - trans = msn_transaction_new(cmdproc, "RML", "%i", payload_len); - msn_transaction_set_payload(trans, payload, payload_len); - msn_cmdproc_send_trans(cmdproc, trans); -} - -void -msn_notification_send_fqy(MsnSession *session, - const char *payload, int payload_len, - MsnFqyCb cb, - gpointer cb_data) -{ - MsnTransaction *trans; - MsnCmdProc *cmdproc; - MsnFqyCbData *data; - - cmdproc = session->notification->cmdproc; - - data = g_new(MsnFqyCbData, 1); - data->cb = cb; - data->data = cb_data; - - trans = msn_transaction_new(cmdproc, "FQY", "%d", payload_len); - msn_transaction_set_payload(trans, payload, payload_len); - msn_transaction_set_data(trans, data); - msn_transaction_set_data_free(trans, g_free); - msn_cmdproc_send_trans(cmdproc, trans); -} - -static void -update_contact_network(MsnSession *session, const char *passport, MsnNetwork network, gpointer unused) -{ - MsnUser *user; - - if (network == MSN_NETWORK_UNKNOWN) - { - purple_debug_warning("msn", - "Ignoring user %s about which server knows nothing.\n", - passport); - /* Decrement the count for unknown results so that we'll continue login. - Also, need to finish the login process here as well, because ADL OK - will not be called. */ - if (purple_debug_is_verbose()) - purple_debug_info("msn", "ADL/FQY count is %d\n", session->adl_fqy); - if (--session->adl_fqy == 0) - msn_session_finish_login(session); - return; - } - - /* TODO: Also figure out how to update membership lists */ - user = msn_userlist_find_user(session->userlist, passport); - if (user) { - xmlnode *adl_node; - char *payload; - int payload_len; - - msn_user_set_network(user, network); - - adl_node = xmlnode_new("ml"); - xmlnode_set_attrib(adl_node, "l", "1"); - msn_add_contact_xml(adl_node, passport, - user->list_op & MSN_LIST_OP_MASK, network); - payload = xmlnode_to_str(adl_node, &payload_len); - msn_notification_post_adl(session->notification->cmdproc, payload, payload_len); - g_free(payload); - xmlnode_free(adl_node); - } else { - purple_debug_error("msn", - "Got FQY update for unknown user %s on network %d.\n", - passport, network); - } -} - -/*dump contact info to NS*/ -void -msn_notification_dump_contact(MsnSession *session) -{ - MsnUser *user; - GList *l; - xmlnode *adl_node; - xmlnode *fqy_node; - char *payload; - int payload_len; - int adl_count = 0; - int fqy_count = 0; - PurpleConnection *pc; - const char *display_name; - - adl_node = xmlnode_new("ml"); - adl_node->child = NULL; - xmlnode_set_attrib(adl_node, "l", "1"); - fqy_node = xmlnode_new("ml"); - - /*get the userlist*/ - for (l = session->userlist->users; l != NULL; l = l->next) { - user = l->data; - - /* skip RL & PL during initial dump */ - if (!(user->list_op & MSN_LIST_OP_MASK)) - continue; - - if (user->passport && !strcmp(user->passport, "messenger@microsoft.com")) - continue; - - if ((user->list_op & MSN_LIST_OP_MASK & ~MSN_LIST_FL_OP) - == (MSN_LIST_AL_OP | MSN_LIST_BL_OP)) { - /* The server will complain if we send it a user on both the - Allow and Block lists. So assume they're on the Block list - and remove them from the Allow list in the membership lists to - stop this from happening again. */ - purple_debug_warning("msn", - "User %s is on both Allow and Block list; " - "removing from Allow list.\n", - user->passport); - msn_user_unset_op(user, MSN_LIST_AL_OP); - } - - if (user->networkid != MSN_NETWORK_UNKNOWN) { - if ((user->list_op & (MSN_LIST_OP_MASK | MSN_LIST_PL_OP)) == MSN_LIST_FL_OP) { - purple_debug_warning("msn", - "User %s is on neither Allow nor Block list, " - "and not Pending addition; " - "adding to Allow list.\n", - user->passport); - msn_user_set_op(user, MSN_LIST_AL_OP); - } - - msn_add_contact_xml(adl_node, user->passport, - user->list_op & MSN_LIST_OP_MASK, - user->networkid); - - /* each ADL command may contain up to 150 contacts */ - if (++adl_count % 150 == 0) { - payload = xmlnode_to_str(adl_node, &payload_len); - - /* ADL's are returned all-together */ - session->adl_fqy++; - if (purple_debug_is_verbose()) - purple_debug_info("msn", "Posting ADL, count is %d\n", - session->adl_fqy); - - msn_notification_post_adl(session->notification->cmdproc, - payload, payload_len); - - g_free(payload); - xmlnode_free(adl_node); - - adl_node = xmlnode_new("ml"); - adl_node->child = NULL; - xmlnode_set_attrib(adl_node, "l", "1"); - } - } else { - /* FQY's are returned one-at-a-time */ - session->adl_fqy++; - if (purple_debug_is_verbose()) - purple_debug_info("msn", "Adding FQY address, count is %d\n", - session->adl_fqy); - - msn_add_contact_xml(fqy_node, user->passport, 0, user->networkid); - - /* each FQY command may contain up to 150 contacts, probably */ - if (++fqy_count % 150 == 0) { - payload = xmlnode_to_str(fqy_node, &payload_len); - - msn_notification_send_fqy(session, payload, payload_len, - update_contact_network, NULL); - - g_free(payload); - xmlnode_free(fqy_node); - fqy_node = xmlnode_new("ml"); - } - } - } - - /* Send the rest, or just an empty one to let the server set us online */ - if (adl_count == 0 || adl_count % 150 != 0) { - payload = xmlnode_to_str(adl_node, &payload_len); - - /* ADL's are returned all-together */ - session->adl_fqy++; - if (purple_debug_is_verbose()) - purple_debug_info("msn", "Posting ADL, count is %d\n", - session->adl_fqy); - - msn_notification_post_adl(session->notification->cmdproc, payload, payload_len); - - g_free(payload); - } - - if (fqy_count % 150 != 0) { - payload = xmlnode_to_str(fqy_node, &payload_len); - - msn_notification_send_fqy(session, payload, payload_len, - update_contact_network, NULL); - - g_free(payload); - } - - xmlnode_free(adl_node); - xmlnode_free(fqy_node); - - msn_session_activate_login_timeout(session); - - pc = purple_account_get_connection(session->account); - display_name = purple_connection_get_display_name(pc); - if (display_name - && strcmp(display_name, - purple_account_get_username(session->account))) { - msn_set_public_alias(pc, display_name, NULL, NULL); - } - -} - -static void -blp_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ -} - -static void -adl_cmd_parse(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, - size_t len) -{ - xmlnode *root, *domain_node; - - purple_debug_misc("msn", "Parsing received ADL XML data\n"); - - g_return_if_fail(payload != NULL); - - root = xmlnode_from_str(payload, (gssize) len); - - if (root == NULL) { - purple_debug_info("msn", "Invalid XML in ADL!\n"); - return; - } - for (domain_node = xmlnode_get_child(root, "d"); - domain_node; - domain_node = xmlnode_get_next_twin(domain_node)) { - xmlnode *contact_node = NULL; - - for (contact_node = xmlnode_get_child(domain_node, "c"); - contact_node; - contact_node = xmlnode_get_next_twin(contact_node)) { - const gchar *list; - gint list_op = 0; - - list = xmlnode_get_attrib(contact_node, "l"); - if (list != NULL) { - list_op = atoi(list); - } - - if (list_op & MSN_LIST_RL_OP) { - /* someone is adding us */ - msn_get_contact_list(cmdproc->session, MSN_PS_PENDING_LIST, NULL); - } - } - } - - xmlnode_free(root); -} - -static void -adl_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnSession *session; - - g_return_if_fail(cmdproc != NULL); - g_return_if_fail(cmdproc->session != NULL); - g_return_if_fail(cmdproc->last_cmd != NULL); - g_return_if_fail(cmd != NULL); - - session = cmdproc->session; - - if (!strcmp(cmd->params[1], "OK")) { - /* ADL ack */ - if (purple_debug_is_verbose()) - purple_debug_info("msn", "ADL ACK, count is %d\n", - session->adl_fqy); - if (--session->adl_fqy == 0) - msn_session_finish_login(session); - } else { - cmdproc->last_cmd->payload_cb = adl_cmd_parse; - cmd->payload_len = atoi(cmd->params[1]); - } - - return; -} - -static void -adl_error_parse(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len) -{ - MsnSession *session; - PurpleAccount *account; - PurpleConnection *gc; - int error = GPOINTER_TO_INT(cmd->payload_cbdata); - - session = cmdproc->session; - account = session->account; - gc = purple_account_get_connection(account); - - if (error == 241) { - /* khc: some googling suggests that error 241 means the buddy is somehow - in the local list, but not the server list, and that we should add - those buddies to the addressbook. For now I will just notify the user - about the raw payload, because I am lazy */ - xmlnode *adl = xmlnode_from_str(payload, len); - GString *emails = g_string_new(NULL); - - xmlnode *domain = xmlnode_get_child(adl, "d"); - while (domain) { - const char *domain_str = xmlnode_get_attrib(domain, "n"); - xmlnode *contact = xmlnode_get_child(domain, "c"); - while (contact) { - g_string_append_printf(emails, "%s@%s\n", - xmlnode_get_attrib(contact, "n"), domain_str); - contact = xmlnode_get_next_twin(contact); - } - domain = xmlnode_get_next_twin(domain); - } - - purple_notify_error(gc, NULL, - _("The following users are missing from your addressbook"), - emails->str); - g_string_free(emails, TRUE); - xmlnode_free(adl); - } - else - { - char *adl = g_strndup(payload, len); - char *reason = g_strdup_printf(_("Unknown error (%d): %s"), - error, adl); - g_free(adl); - - purple_notify_error(gc, NULL, _("Unable to add user"), reason); - g_free(reason); - } -} - -static void -adl_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) -{ - MsnSession *session; - PurpleAccount *account; - PurpleConnection *gc; - MsnCommand *cmd = cmdproc->last_cmd; - - session = cmdproc->session; - account = session->account; - gc = purple_account_get_connection(account); - - purple_debug_error("msn", "ADL error\n"); - if (cmd->param_count > 1) { - cmd->payload_cb = adl_error_parse; - cmd->payload_len = atoi(cmd->params[1]); - cmd->payload_cbdata = GINT_TO_POINTER(error); - } else { - char *reason = g_strdup_printf(_("Unknown error (%d)"), error); - purple_notify_error(gc, NULL, _("Unable to add user"), reason); - g_free(reason); - } -} - -static void -rml_error_parse(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len) -{ - MsnSession *session; - PurpleAccount *account; - PurpleConnection *gc; - char *adl, *reason; - int error = GPOINTER_TO_INT(cmd->payload_cbdata); - - session = cmdproc->session; - account = session->account; - gc = purple_account_get_connection(account); - - adl = g_strndup(payload, len); - reason = g_strdup_printf(_("Unknown error (%d): %s"), - error, adl); - g_free(adl); - - purple_notify_error(gc, NULL, _("Unable to remove user"), reason); - g_free(reason); -} - -static void -rml_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) -{ - MsnSession *session; - PurpleAccount *account; - PurpleConnection *gc; - MsnCommand *cmd = cmdproc->last_cmd; - - session = cmdproc->session; - account = session->account; - gc = purple_account_get_connection(account); - - purple_debug_error("msn", "RML error\n"); - if (cmd->param_count > 1) { - cmd->payload_cb = rml_error_parse; - cmd->payload_len = atoi(cmd->params[1]); - cmd->payload_cbdata = GINT_TO_POINTER(error); - } else { - char *reason = g_strdup_printf(_("Unknown error (%d)"), error); - purple_notify_error(gc, NULL, _("Unable to remove user"), reason); - g_free(reason); - } -} - -static void -fqy_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, - size_t len) -{ - MsnSession *session; - xmlnode *ml, *d, *c; - const char *domain; - const char *local; - const char *type; - char *passport; - MsnNetwork network = MSN_NETWORK_PASSPORT; - - session = cmdproc->session; - - /* FQY response: - <ml><d n="domain.com"><c n="local-node" t="network" /></d></ml> */ - ml = xmlnode_from_str(payload, len); - for (d = xmlnode_get_child(ml, "d"); - d != NULL; - d = xmlnode_get_next_twin(d)) { - domain = xmlnode_get_attrib(d, "n"); - for (c = xmlnode_get_child(d, "c"); - c != NULL; - c = xmlnode_get_next_twin(c)) { - local = xmlnode_get_attrib(c, "n"); - type = xmlnode_get_attrib(c, "t"); - - passport = g_strdup_printf("%s@%s", local, domain); - - if (g_ascii_isdigit(cmd->command[0])) - network = MSN_NETWORK_UNKNOWN; - else if (type != NULL) - network = (MsnNetwork)strtoul(type, NULL, 10); - - purple_debug_info("msn", "FQY response says %s is from network %d\n", - passport, network); - if (cmd->trans->data) { - MsnFqyCbData *fqy_data = cmd->trans->data; - fqy_data->cb(session, passport, network, fqy_data->data); - /* Don't free fqy_data yet since the server responds to FQY multiple times. - It will be freed when cmd->trans is freed. */ - } - - g_free(passport); - } - } - - xmlnode_free(ml); -} - -static void -fqy_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) -{ - MsnCommand *cmd = cmdproc->last_cmd; - - purple_debug_warning("msn", "FQY error %d\n", error); - if (cmd->param_count > 1) { - cmd->payload_cb = fqy_cmd_post; - cmd->payload_len = atoi(cmd->params[1]); - cmd->payload_cbdata = GINT_TO_POINTER(error); - } -#if 0 - /* If the server didn't send us a corresponding email address for this - FQY error, it's probably going to disconnect us. So it isn't necessary - to tell the handler about it. */ - else if (trans->data) - ((MsnFqyCb)trans->data)(session, NULL, MSN_NETWORK_UNKNOWN, NULL); -#endif -} - -static void -fqy_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - purple_debug_info("msn", "Process FQY\n"); - cmdproc->last_cmd->payload_cb = fqy_cmd_post; - cmd->payload_len = atoi(cmd->params[1]); -} - -static void -rml_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, - size_t len) -{ - if (payload != NULL) - purple_debug_info("msn", "Received RML:\n%s\n", payload); -} - -static void -rml_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - purple_debug_info("msn", "Process RML\n"); - cmd->payload_len = atoi(cmd->params[1]); - cmdproc->last_cmd->payload_cb = rml_cmd_post; -} - -static void -qng_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - /* TODO: Call PNG after the timeout specified. */ -} - - -static void -fln_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnUser *user; - char *passport; - int networkid; - - /* Tell libpurple that the user has signed off */ - msn_parse_user(cmd->params[0], &passport, &networkid); - user = msn_userlist_find_user(cmdproc->session->userlist, passport); - msn_user_set_state(user, NULL); - msn_user_update(user); - - g_free(passport); -} - -static void -iln_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnSession *session; - MsnUser *user; - MsnObject *msnobj = NULL; - unsigned long clientid, extcaps; - char *extcap_str; - int networkid = 0; - const char *state, *passport; - char *friendly; - - session = cmdproc->session; - - state = cmd->params[1]; - passport = cmd->params[2]; - - user = msn_userlist_find_user(session->userlist, passport); - if (user == NULL) - /* Where'd this come from? */ - return; - - if (cmd->param_count == 8) { - /* Yahoo! Buddy, looks like */ - networkid = atoi(cmd->params[3]); - friendly = g_strdup(purple_url_decode(cmd->params[4])); - clientid = strtoul(cmd->params[5], &extcap_str, 10); - if (extcap_str && *extcap_str) - extcaps = strtoul(extcap_str+1, NULL, 10); - else - extcaps = 0; - - /* cmd->params[7] seems to be a URL to a Yahoo! icon: - https://sec.yimg.com/i/us/nt/b/purpley.1.0.png - ... and it's purple, HAH! - */ - } else if (cmd->param_count == 7) { - /* MSNP14+ with Display Picture object */ - networkid = atoi(cmd->params[3]); - friendly = g_strdup(purple_url_decode(cmd->params[4])); - clientid = strtoul(cmd->params[5], &extcap_str, 10); - if (extcap_str && *extcap_str) - extcaps = strtoul(extcap_str+1, NULL, 10); - else - extcaps = 0; - msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[6])); - } else if (cmd->param_count == 6) { - /* Yes, this is 5. The friendly name could start with a number, - but the display picture object can't... */ - if (isdigit(cmd->params[5][0])) { - /* MSNP14 without Display Picture object */ - networkid = atoi(cmd->params[3]); - friendly = g_strdup(purple_url_decode(cmd->params[4])); - clientid = strtoul(cmd->params[5], &extcap_str, 10); - if (extcap_str && *extcap_str) - extcaps = strtoul(extcap_str+1, NULL, 10); - else - extcaps = 0; - } else { - /* MSNP8+ with Display Picture object */ - friendly = g_strdup(purple_url_decode(cmd->params[3])); - clientid = strtoul(cmd->params[4], &extcap_str, 10); - if (extcap_str && *extcap_str) - extcaps = strtoul(extcap_str+1, NULL, 10); - else - extcaps = 0; - msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[5])); - } - } else if (cmd->param_count == 5) { - /* MSNP8+ without Display Picture object */ - friendly = g_strdup(purple_url_decode(cmd->params[3])); - clientid = strtoul(cmd->params[4], &extcap_str, 10); - if (extcap_str && *extcap_str) - extcaps = strtoul(extcap_str+1, NULL, 10); - else - extcaps = 0; - } else { - purple_debug_warning("msn", "Received ILN with unknown number of parameters.\n"); - return; - } - - if (msn_user_set_friendly_name(user, friendly)) { - msn_update_contact(session, passport, MSN_UPDATE_DISPLAY, friendly); - } - g_free(friendly); - - msn_user_set_object(user, msnobj); - - user->mobile = (clientid & MSN_CAP_MOBILE_ON) || (user->extinfo && user->extinfo->phone_mobile && user->extinfo->phone_mobile[0] == '+'); - msn_user_set_clientid(user, clientid); - msn_user_set_extcaps(user, extcaps); - msn_user_set_network(user, networkid); - - msn_user_set_state(user, state); - msn_user_update(user); -} - -static void -ipg_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len) -{ - PurpleConnection *gc; - MsnUserList *userlist; - const char *who = NULL; - char *text = NULL; - const char *id = NULL; - xmlnode *payloadNode, *from, *msg, *textNode; - - purple_debug_misc("msn", "Incoming Page: {%s}\n", payload); - - userlist = cmdproc->session->userlist; - gc = purple_account_get_connection(cmdproc->session->account); - - /* payload looks like this: - <?xml version="1.0"?> - <NOTIFICATION id="0" siteid="111100400" siteurl="http://mobile.msn.com/"> - <TO name="passport@example.com"> - <VIA agent="mobile"/> - </TO> - <FROM name="tel:+XXXXXXXXXXX"/> - <MSG pri="1" id="1"> - <CAT Id="110110001"/> - <ACTION url="2wayIM.asp"/> - <SUBSCR url="2wayIM.asp"/> - <BODY lcid="1033"> - <TEXT>Message was here</TEXT> - </BODY> - </MSG> - </NOTIFICATION> - */ - - /* This is the payload if your message was too long: - <NOTIFICATION id="TrID" siteid="111100400" siteurl="http://mobile.msn.com/"> - <TO name="passport@example.com"> - <VIA agent="mobile"/> - </TO> - <FROM name="tel:+XXXXXXXXXXX"/> - <MSG pri="1" id="407"> - <CAT Id="110110001"/> - <ACTION url="2wayIM.asp"/> - <SUBSCR url="2wayIM.asp"/> - <BODY lcid="1033"> - <TEXT></TEXT> - </BODY> - </MSG> - </NOTIFICATION> - */ - - payloadNode = xmlnode_from_str(payload, len); - if (!payloadNode) - return; - - if (!(from = xmlnode_get_child(payloadNode, "FROM")) || - !(msg = xmlnode_get_child(payloadNode, "MSG")) || - !(textNode = xmlnode_get_child(msg, "BODY/TEXT"))) { - xmlnode_free(payloadNode); - return; - } - - who = xmlnode_get_attrib(from, "name"); - if (!who) return; - - text = xmlnode_get_data(textNode); - - /* Match number to user's mobile number, FROM is a phone number if the - other side page you using your phone number */ - if (!strncmp(who, "tel:+", 5)) { - MsnUser *user = - msn_userlist_find_user_with_mobile_phone(userlist, who + 4); - - if (user && user->passport) - who = user->passport; - } - - id = xmlnode_get_attrib(msg, "id"); - - if (id && strcmp(id, "1")) { - PurpleConversation *conv - = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, - who, gc->account); - if (conv != NULL) { - const char *error; - if (!strcmp(id, "407")) - error = _("Mobile message was not sent because it was too long."); - else - error = _("Mobile message was not sent because an unknown error occurred."); - - purple_conversation_write(conv, NULL, error, - PURPLE_MESSAGE_ERROR, time(NULL)); - - if ((id = xmlnode_get_attrib(payloadNode, "id")) != NULL) { - unsigned int trId = atol(id); - MsnTransaction *trans; - - trans = msn_history_find(cmdproc->history, trId); - if (trans) { - MsnMessage *msg = (MsnMessage *)trans->data; - - if (msg) { - char *body_str = msn_message_to_string(msg); - char *body_enc = g_markup_escape_text(body_str, -1); - - purple_conversation_write(conv, NULL, body_enc, - PURPLE_MESSAGE_RAW, time(NULL)); - - g_free(body_str); - g_free(body_enc); - msn_message_unref(msg); - trans->data = NULL; - } - } - } - } - } else { - serv_got_im(gc, who, text, 0, time(NULL)); - } - - g_free(text); - xmlnode_free(payloadNode); -} - -static void -ipg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - cmd->payload_len = atoi(cmd->params[0]); - cmdproc->last_cmd->payload_cb = ipg_cmd_post; -} - -static void -nln_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnSession *session; - MsnUser *user; - MsnObject *msnobj; - unsigned long clientid, extcaps; - char *extcap_str; - char *passport; - int networkid; - const char *state, *friendly; - - session = cmdproc->session; - - state = cmd->params[0]; - msn_parse_user(cmd->params[1], &passport, &networkid); - friendly = purple_url_decode(cmd->params[2]); - - user = msn_userlist_find_user(session->userlist, passport); - if (user == NULL) return; - - if (msn_user_set_friendly_name(user, friendly) && user != session->user) - { - msn_update_contact(session, passport, MSN_UPDATE_DISPLAY, friendly); - } - - if (cmd->param_count == 5) - { - msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[4])); - msn_user_set_object(user, msnobj); - } - else - { - msn_user_set_object(user, NULL); - } - - clientid = strtoul(cmd->params[3], &extcap_str, 10); - if (extcap_str && *extcap_str) - extcaps = strtoul(extcap_str+1, NULL, 10); - else - extcaps = 0; - - user->mobile = (clientid & MSN_CAP_MOBILE_ON) || (user->extinfo && user->extinfo->phone_mobile && user->extinfo->phone_mobile[0] == '+'); - - msn_user_set_clientid(user, clientid); - msn_user_set_extcaps(user, extcaps); - msn_user_set_network(user, networkid); - - msn_user_set_state(user, state); - msn_user_update(user); - - g_free(passport); -} - -#if 0 -static void -chg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - char *state = cmd->params[1]; - int state_id = 0; - - if (!strcmp(state, "NLN")) - state_id = MSN_ONLINE; - else if (!strcmp(state, "BSY")) - state_id = MSN_BUSY; - else if (!strcmp(state, "IDL")) - state_id = MSN_IDLE; - else if (!strcmp(state, "BRB")) - state_id = MSN_BRB; - else if (!strcmp(state, "AWY")) - state_id = MSN_AWAY; - else if (!strcmp(state, "PHN")) - state_id = MSN_PHONE; - else if (!strcmp(state, "LUN")) - state_id = MSN_LUNCH; - else if (!strcmp(state, "HDN")) - state_id = MSN_HIDDEN; - - cmdproc->session->state = state_id; -} -#endif - - -static void -not_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len) -{ -#if 0 - MSN_SET_PARAMS("NOT %d\r\n%s", cmdproc->servconn->payload, payload); - purple_debug_misc("msn", "Notification: {%s}\n", payload); -#endif -} - -static void -not_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - cmd->payload_len = atoi(cmd->params[0]); - cmdproc->last_cmd->payload_cb = not_cmd_post; -} - -static void -prp_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnSession *session = cmdproc->session; - const char *type, *value; - - g_return_if_fail(cmd->param_count >= 3); - - type = cmd->params[2]; - - if (cmd->param_count == 4) - { - value = cmd->params[3]; - if (!strcmp(type, "PHH")) - msn_user_set_home_phone(session->user, purple_url_decode(value)); - else if (!strcmp(type, "PHW")) - msn_user_set_work_phone(session->user, purple_url_decode(value)); - else if (!strcmp(type, "PHM")) - msn_user_set_mobile_phone(session->user, purple_url_decode(value)); - } - else - { - if (!strcmp(type, "PHH")) - msn_user_set_home_phone(session->user, NULL); - else if (!strcmp(type, "PHW")) - msn_user_set_work_phone(session->user, NULL); - else if (!strcmp(type, "PHM")) - msn_user_set_mobile_phone(session->user, NULL); - } -} - -/************************************************************************** - * Misc commands - **************************************************************************/ - -static void -url_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnSession *session; - PurpleConnection *gc; - PurpleAccount *account; - const char *rru; - const char *url; - PurpleCipherContext *cipher; - gchar creds[33]; - char *buf; - - gulong tmp_timestamp; - - session = cmdproc->session; - account = session->account; - gc = account->gc; - - rru = cmd->params[1]; - url = cmd->params[2]; - - session->passport_info.mail_timestamp = time(NULL); - tmp_timestamp = session->passport_info.mail_timestamp - session->passport_info.sl; - - buf = g_strdup_printf("%s%lu%s", - session->passport_info.mspauth ? session->passport_info.mspauth : "BOGUS", - tmp_timestamp, - purple_connection_get_password(gc)); - - cipher = purple_cipher_context_new_by_name("md5", NULL); - purple_cipher_context_append(cipher, (const guchar *)buf, strlen(buf)); - purple_cipher_context_digest_to_str(cipher, sizeof(creds), creds, NULL); - purple_cipher_context_destroy(cipher); - g_free(buf); - - g_free(session->passport_info.mail_url); - session->passport_info.mail_url = - g_strdup_printf("%s&auth=%s&creds=%s&sl=%ld&username=%s&mode=ttl&sid=%s&id=2&rru=%s&svc=mail&js=yes", - url, - session->passport_info.mspauth ? purple_url_encode(session->passport_info.mspauth) : "BOGUS", - creds, - tmp_timestamp, - msn_user_get_passport(session->user), - session->passport_info.sid, - rru); - - /* The user wants to check his or her email */ - if (cmd->trans && cmd->trans->data) - purple_notify_uri(purple_account_get_connection(account), session->passport_info.mail_url); -} -/************************************************************************** - * Switchboards - **************************************************************************/ - -static void -rng_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnSession *session; - MsnSwitchBoard *swboard; - const char *session_id; - char *host; - int port; - - session = cmdproc->session; - session_id = cmd->params[0]; - - msn_parse_socket(cmd->params[1], &host, &port); - - if (session->http_method) - port = 80; - - swboard = msn_switchboard_new(session); - - msn_switchboard_set_invited(swboard, TRUE); - msn_switchboard_set_session_id(swboard, session_id); - msn_switchboard_set_auth_key(swboard, cmd->params[3]); - swboard->im_user = g_strdup(cmd->params[4]); - /* msn_switchboard_add_user(swboard, cmd->params[4]); */ - - if (!msn_switchboard_connect(swboard, host, port)) - msn_switchboard_destroy(swboard); - - g_free(host); -} - -static void -xfr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - char *host; - int port; - - if (strcmp(cmd->params[1], "SB") && strcmp(cmd->params[1], "NS")) - { - /* Maybe we can have a generic bad command error. */ - purple_debug_error("msn", "Bad XFR command (%s)\n", cmd->params[1]); - return; - } - - msn_parse_socket(cmd->params[2], &host, &port); - - if (!strcmp(cmd->params[1], "SB")) - { - purple_debug_error("msn", "This shouldn't be handled here.\n"); - } - else if (!strcmp(cmd->params[1], "NS")) - { - MsnSession *session; - - session = cmdproc->session; - - msn_session_set_login_step(session, MSN_LOGIN_STEP_TRANSFER); - - msn_notification_connect(session->notification, host, port); - } - - g_free(host); -} - -static void -gcf_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, - size_t len) -{ -/* QuLogic: Disabled until confirmed correct. */ -#if 0 - xmlnode *root; - xmlnode *policy; - - g_return_if_fail(cmd->payload != NULL); - - if ( (root = xmlnode_from_str(cmd->payload, cmd->payload_len)) == NULL) - { - purple_debug_error("msn", "Unable to parse GCF payload into a XML tree\n"); - return; - } - - - g_free(cmdproc->session->blocked_text); - cmdproc->session->blocked_text = NULL; - - /* We need a get_child with attrib... */ - policy = xmlnode_get_child(root, "Policy"); - while (policy) { - if (g_str_equal(xmlnode_get_attrib(policy, "type"), "SHIELDS")) - break; - policy = xmlnode_get_next_twin(policy); - } - - if (policy) { - GString *blocked = g_string_new(NULL); - xmlnode *imtext = xmlnode_get_child(policy, - "config/block/regexp/imtext"); - while (imtext) { - const char *value = xmlnode_get_attrib(imtext, "value"); - g_string_append_printf(blocked, "%s<br/>\n", - purple_base64_decode(value, NULL)); - imtext = xmlnode_get_next_twin(imtext); - } - - cmdproc->session->blocked_text = g_string_free(blocked, FALSE); - } - - xmlnode_free(root); -#endif -} - -static void -gcf_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - purple_debug_info("msn", "Processing GCF command\n"); - - cmdproc->last_cmd->payload_cb = gcf_cmd_post; - cmd->payload_len = atoi(cmd->params[1]); -} - -static void -sbs_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - purple_debug_info("msn", "Processing SBS... \n"); - /*get the payload content*/ -} - -static void -parse_user_endpoints(MsnUser *user, xmlnode *payloadNode) -{ - MsnSession *session; - xmlnode *epNode, *capsNode; - MsnUserEndpoint data; - const char *id; - char *caps, *tmp; - gboolean is_me; - - purple_debug_info("msn", "Get EndpointData\n"); - - session = user->userlist->session; - is_me = (user == session->user); - - msn_user_clear_endpoints(user); - for (epNode = xmlnode_get_child(payloadNode, "EndpointData"); - epNode; - epNode = xmlnode_get_next_twin(epNode)) { - id = xmlnode_get_attrib(epNode, "id"); - capsNode = xmlnode_get_child(epNode, "Capabilities"); - - /* Disconnect others, if MPOP is disabled */ - if (is_me - && !session->enable_mpop - && strncasecmp(id + 1, session->guid, 36) != 0) { - purple_debug_info("msn", "Disconnecting Endpoint %s\n", id); - - tmp = g_strdup_printf("%s;%s", user->passport, id); - msn_notification_send_uun(session, tmp, MSN_UNIFIED_NOTIFICATION_MPOP, "goawyplzthxbye"); - g_free(tmp); - } else { - if (capsNode != NULL) { - caps = xmlnode_get_data(capsNode); - - data.clientid = strtoul(caps, &tmp, 10); - if (tmp && *tmp) - data.extcaps = strtoul(tmp + 1, NULL, 10); - else - data.extcaps = 0; - - g_free(caps); - } else { - data.clientid = 0; - data.extcaps = 0; - } - - msn_user_set_endpoint_data(user, id, &data); - } - } - - if (is_me && session->enable_mpop) { - for (epNode = xmlnode_get_child(payloadNode, "PrivateEndpointData"); - epNode; - epNode = xmlnode_get_next_twin(epNode)) { - MsnUserEndpoint *ep; - xmlnode *nameNode, *clientNode; - - /* <PrivateEndpointData id='{GUID}'> - <EpName>Endpoint Name</EpName> - <Idle>true/false</Idle> - <ClientType>1</ClientType> - <State>NLN</State> - </PrivateEndpointData> - */ - id = xmlnode_get_attrib(epNode, "id"); - ep = msn_user_get_endpoint_data(user, id); - - if (ep != NULL) { - nameNode = xmlnode_get_child(epNode, "EpName"); - if (nameNode != NULL) { - g_free(ep->name); - ep->name = xmlnode_get_data(nameNode); - } - - clientNode = xmlnode_get_child(epNode, "ClientType"); - if (clientNode != NULL) { - tmp = xmlnode_get_data(clientNode); - ep->type = strtoul(tmp, NULL, 10); - g_free(tmp); - } - } - } - } -} - -static void parse_currentmedia(MsnUser *user, const char *cmedia) -{ - char **cmedia_array; - int strings = 0; - - if (!cmedia || cmedia[0] == '\0') { - purple_debug_info("msn", "No currentmedia string\n"); - return; - } - - purple_debug_info("msn", "Parsing currentmedia string: \"%s\"\n", cmedia); - - cmedia_array = g_strsplit(cmedia, "\\0", 0); - - /* - * 0: Application - * 1: 'Music'/'Games'/'Office' - * 2: '1' if enabled, '0' if not - * 3: Format (eg. {0} by {1}) - * 4: Title - * If 'Music': - * 5: Artist - * 6: Album - * 7: ? - */ - strings = g_strv_length(cmedia_array); - - if (strings >= 4 && !strcmp(cmedia_array[2], "1")) { - if (user->extinfo == NULL) - user->extinfo = g_new0(MsnUserExtendedInfo, 1); - else { - g_free(user->extinfo->media_album); - g_free(user->extinfo->media_artist); - g_free(user->extinfo->media_title); - } - - if (!strcmp(cmedia_array[1], "Music")) - user->extinfo->media_type = CURRENT_MEDIA_MUSIC; - else if (!strcmp(cmedia_array[1], "Games")) - user->extinfo->media_type = CURRENT_MEDIA_GAMES; - else if (!strcmp(cmedia_array[1], "Office")) - user->extinfo->media_type = CURRENT_MEDIA_OFFICE; - else - user->extinfo->media_type = CURRENT_MEDIA_UNKNOWN; - - user->extinfo->media_title = g_strdup(cmedia_array[strings == 4 ? 3 : 4]); - user->extinfo->media_artist = strings > 5 ? g_strdup(cmedia_array[5]) : NULL; - user->extinfo->media_album = strings > 6 ? g_strdup(cmedia_array[6]) : NULL; - } - - g_strfreev(cmedia_array); -} - -/* - * Get the UBX's PSM info - * Post it to the User status - * Thanks for Chris <ukdrizzle@yahoo.co.uk>'s code - */ -static void -ubx_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, - size_t len) -{ - MsnSession *session; - MsnUser *user; - char *passport; - int network; - xmlnode *payloadNode; - char *psm_str, *str; - - session = cmdproc->session; - - msn_parse_user(cmd->params[0], &passport, &network); - user = msn_userlist_find_user(session->userlist, passport); - - if (user == NULL) { - str = g_strndup(payload, len); - purple_debug_info("msn", "unknown user %s, payload is %s\n", - passport, str); - g_free(passport); - g_free(str); - return; - } - - g_free(passport); - - /* Free any existing media info for this user */ - if (user->extinfo) { - g_free(user->extinfo->media_album); - g_free(user->extinfo->media_artist); - g_free(user->extinfo->media_title); - user->extinfo->media_album = NULL; - user->extinfo->media_artist = NULL; - user->extinfo->media_title = NULL; - user->extinfo->media_type = CURRENT_MEDIA_UNKNOWN; - } - - if (len != 0) { - payloadNode = xmlnode_from_str(payload, len); - if (!payloadNode) { - purple_debug_error("msn", "UBX XML parse Error!\n"); - - msn_user_set_statusline(user, NULL); - - msn_user_update(user); - return; - } - - psm_str = msn_get_psm(payloadNode); - msn_user_set_statusline(user, psm_str); - g_free(psm_str); - - str = msn_get_currentmedia(payloadNode); - parse_currentmedia(user, str); - g_free(str); - - parse_user_endpoints(user, payloadNode); - - xmlnode_free(payloadNode); - - } else { - msn_user_set_statusline(user, NULL); - } - - msn_user_update(user); -} - -static void -ubx_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - purple_debug_misc("msn", "UBX received.\n"); - cmdproc->last_cmd->payload_cb = ubx_cmd_post; - cmd->payload_len = atoi(cmd->params[1]); -} - -static void -uux_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, - size_t len) -{ - /* Do Nothing, right now. */ - if (payload != NULL) - purple_debug_info("msn", "UUX payload:\n%s\n", payload); -} - -static void -uux_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - purple_debug_misc("msn", "UUX received.\n"); - cmdproc->last_cmd->payload_cb = uux_cmd_post; - cmd->payload_len = atoi(cmd->params[1]); -} - -void -msn_notification_send_uux(MsnSession *session, const char *payload) -{ - MsnTransaction *trans; - MsnCmdProc *cmdproc; - size_t len = strlen(payload); - - cmdproc = session->notification->cmdproc; - purple_debug_misc("msn", "Sending UUX command with payload: %s\n", payload); - trans = msn_transaction_new(cmdproc, "UUX", "%" G_GSIZE_FORMAT, len); - msn_transaction_set_payload(trans, payload, len); - msn_cmdproc_send_trans(cmdproc, trans); -} - -void msn_notification_send_uux_endpointdata(MsnSession *session) -{ - xmlnode *epDataNode; - xmlnode *capNode; - char *caps; - char *payload; - int length; - - epDataNode = xmlnode_new("EndpointData"); - - capNode = xmlnode_new_child(epDataNode, "Capabilities"); - caps = g_strdup_printf("%d:%02d", MSN_CLIENT_ID_CAPABILITIES, MSN_CLIENT_ID_EXT_CAPS); - xmlnode_insert_data(capNode, caps, -1); - g_free(caps); - - payload = xmlnode_to_str(epDataNode, &length); - - msn_notification_send_uux(session, payload); - - xmlnode_free(epDataNode); - g_free(payload); -} - -void msn_notification_send_uux_private_endpointdata(MsnSession *session) -{ - xmlnode *private; - const char *name; - xmlnode *epname; - xmlnode *idle; - GHashTable *ui_info; - const gchar *ui_type; - xmlnode *client_type; - xmlnode *state; - char *payload; - int length; - - private = xmlnode_new("PrivateEndpointData"); - - name = purple_account_get_string(session->account, "endpoint-name", NULL); - epname = xmlnode_new_child(private, "EpName"); - xmlnode_insert_data(epname, name, -1); - - idle = xmlnode_new_child(private, "Idle"); - xmlnode_insert_data(idle, "false", -1); - - /* ClientType info (from amsn guys): - 0: None - 1: Computer - 2: Website - 3: Mobile / none - 4: Xbox / phone /mobile - 9: MsnGroup - 32: Email member, currently Yahoo! - */ - client_type = xmlnode_new_child(private, "ClientType"); - ui_info = purple_core_get_ui_info(); - ui_type = ui_info ? g_hash_table_lookup(ui_info, "client_type") : NULL; - if (ui_type) { - if (strcmp(ui_type, "pc") == 0) - xmlnode_insert_data(client_type, "1", -1); - else if (strcmp(ui_type, "web") == 0) - xmlnode_insert_data(client_type, "2", -1); - else if (strcmp(ui_type, "phone") == 0) - xmlnode_insert_data(client_type, "3", -1); - else if (strcmp(ui_type, "handheld") == 0) - xmlnode_insert_data(client_type, "3", -1); - else - xmlnode_insert_data(client_type, "1", -1); - } - else - xmlnode_insert_data(client_type, "1", -1); - - state = xmlnode_new_child(private, "State"); - xmlnode_insert_data(state, msn_state_get_text(msn_state_from_account(session->account)), -1); - - payload = xmlnode_to_str(private, &length); - - msn_notification_send_uux(session, payload); - - xmlnode_free(private); - g_free(payload); -} - -static void -ubn_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, - size_t len) -{ - /* Do Nothing, right now. */ - if (payload != NULL) - purple_debug_info("msn", "UBN payload:\n%s\n", payload); -} - -static void -ubn_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - purple_debug_misc("msn", "UBN received from %s.\n", cmd->params[0]); - cmdproc->last_cmd->payload_cb = ubn_cmd_post; - cmd->payload_len = atoi(cmd->params[2]); -} - -static void -uun_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, - size_t len) -{ - /* Do Nothing, right now. */ - if (payload != NULL) - purple_debug_info("msn", "UUN payload:\n%s\n", payload); -} - -static void -uun_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - if (strcmp(cmd->params[1], "OK") != 0) { - purple_debug_misc("msn", "UUN received.\n"); - cmdproc->last_cmd->payload_cb = uun_cmd_post; - cmd->payload_len = atoi(cmd->params[1]); - } - else - purple_debug_misc("msn", "UUN OK received.\n"); -} - -void -msn_notification_send_uun(MsnSession *session, const char *user, - MsnUnifiedNotificationType type, const char *payload) -{ - MsnTransaction *trans; - MsnCmdProc *cmdproc; - size_t len = strlen(payload); - - cmdproc = session->notification->cmdproc; - purple_debug_misc("msn", "Sending UUN command %d to %s with payload: %s\n", - type, user, payload); - trans = msn_transaction_new(cmdproc, "UUN", "%s %d %" G_GSIZE_FORMAT, - user, type, len); - msn_transaction_set_payload(trans, payload, len); - msn_cmdproc_send_trans(cmdproc, trans); -} - -void -msn_notification_send_circle_auth(MsnSession *session, const char *ticket) -{ - MsnTransaction *trans; - MsnCmdProc *cmdproc; - char *encoded; - - cmdproc = session->notification->cmdproc; - - encoded = purple_base64_encode((guchar *)ticket, strlen(ticket)); - trans = msn_transaction_new(cmdproc, "USR", "SHA A %s", encoded); - msn_cmdproc_send_trans(cmdproc, trans); - - g_free(encoded); -} - -/************************************************************************** - * Message Types - **************************************************************************/ - -static void -profile_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - MsnSession *session; - const char *value; -#ifdef MSN_PARTIAL_LISTS - const char *clLastChange; -#endif - - session = cmdproc->session; - - if (strcmp(msg->remote_user, "Hotmail")) - /* This isn't an official message. */ - return; - - if ((value = msn_message_get_header_value(msg, "sid")) != NULL) - { - g_free(session->passport_info.sid); - session->passport_info.sid = g_strdup(value); - } - - if ((value = msn_message_get_header_value(msg, "MSPAuth")) != NULL) - { - g_free(session->passport_info.mspauth); - session->passport_info.mspauth = g_strdup(value); - } - - if ((value = msn_message_get_header_value(msg, "ClientIP")) != NULL) - { - g_free(session->passport_info.client_ip); - session->passport_info.client_ip = g_strdup(value); - } - - if ((value = msn_message_get_header_value(msg, "ClientPort")) != NULL) - { - session->passport_info.client_port = ntohs(atoi(value)); - } - - if ((value = msn_message_get_header_value(msg, "LoginTime")) != NULL) - session->passport_info.sl = atol(value); - - if ((value = msn_message_get_header_value(msg, "EmailEnabled")) != NULL) - session->passport_info.email_enabled = (gboolean)atol(value); - -#ifdef MSN_PARTIAL_LISTS - /*starting retrieve the contact list*/ - clLastChange = purple_account_get_string(session->account, "CLLastChange", NULL); - /* msn_userlist_load defeats all attempts at trying to detect blist sync issues */ - msn_userlist_load(session); - msn_get_contact_list(session, MSN_PS_INITIAL, clLastChange); -#else - /* always get the full list? */ - msn_get_contact_list(session, MSN_PS_INITIAL, NULL); -#endif -} - -static void -initial_email_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - MsnSession *session; - PurpleConnection *gc; - GHashTable *table; - const char *unread; - - session = cmdproc->session; - gc = session->account->gc; - - if (strcmp(msg->remote_user, "Hotmail")) - /* This isn't an official message. */ - return; - - if (session->passport_info.mail_url == NULL) - { - MsnTransaction *trans; - trans = msn_transaction_new(cmdproc, "URL", "%s", "INBOX"); - msn_transaction_queue_cmd(trans, msg->cmd); - - msn_cmdproc_send_trans(cmdproc, trans); - - return; - } - - if (!purple_account_get_check_mail(session->account)) - return; - - table = msn_message_get_hashtable_from_body(msg); - - unread = g_hash_table_lookup(table, "Inbox-Unread"); - - if (unread != NULL) - { - int count = atoi(unread); - - if (count > 0) - { - const char *passports[2] = { msn_user_get_passport(session->user) }; - const char *urls[2] = { session->passport_info.mail_url }; - - purple_notify_emails(gc, count, FALSE, NULL, NULL, - passports, urls, NULL, NULL); - } - } - - g_hash_table_destroy(table); -} - -/*offline Message notification process*/ -static void -initial_mdata_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - MsnSession *session; - PurpleConnection *gc; - GHashTable *table; - const char *mdata, *unread; - - session = cmdproc->session; - gc = session->account->gc; - - if (strcmp(msg->remote_user, "Hotmail")) - /* This isn't an official message. */ - return; - - table = msn_message_get_hashtable_from_body(msg); - - mdata = g_hash_table_lookup(table, "Mail-Data"); - - if (mdata != NULL) - msn_parse_oim_msg(session->oim, mdata); - - if (g_hash_table_lookup(table, "Inbox-URL") == NULL) - { - g_hash_table_destroy(table); - return; - } - - if (session->passport_info.mail_url == NULL) - { - MsnTransaction *trans; - trans = msn_transaction_new(cmdproc, "URL", "%s", "INBOX"); - msn_transaction_queue_cmd(trans, msg->cmd); - - msn_cmdproc_send_trans(cmdproc, trans); - - g_hash_table_destroy(table); - return; - } - - if (!purple_account_get_check_mail(session->account)) - { - g_hash_table_destroy(table); - return; - } - - unread = g_hash_table_lookup(table, "Inbox-Unread"); - - if (unread != NULL) - { - int count = atoi(unread); - - if (count > 0) - { - const char *passports[2] = { msn_user_get_passport(session->user) }; - const char *urls[2] = { session->passport_info.mail_url }; - - purple_notify_emails(gc, count, FALSE, NULL, NULL, - passports, urls, NULL, NULL); - } - } - - g_hash_table_destroy(table); -} - -/*offline Message Notification*/ -static void -delete_oim_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - purple_debug_misc("msn", "Delete OIM message.\n"); -} - -static void -email_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - MsnSession *session; - PurpleConnection *gc; - GHashTable *table; - char *from, *subject, *tmp; - - session = cmdproc->session; - gc = session->account->gc; - - if (strcmp(msg->remote_user, "Hotmail")) - /* This isn't an official message. */ - return; - - if (session->passport_info.mail_url == NULL) - { - MsnTransaction *trans; - trans = msn_transaction_new(cmdproc, "URL", "%s", "INBOX"); - msn_transaction_queue_cmd(trans, msg->cmd); - - msn_cmdproc_send_trans(cmdproc, trans); - - return; - } - - if (!purple_account_get_check_mail(session->account)) - return; - - table = msn_message_get_hashtable_from_body(msg); - - from = subject = NULL; - - tmp = g_hash_table_lookup(table, "From"); - if (tmp != NULL) - from = purple_mime_decode_field(tmp); - - tmp = g_hash_table_lookup(table, "Subject"); - if (tmp != NULL) - subject = purple_mime_decode_field(tmp); - - purple_notify_email(gc, - (subject != NULL ? subject : ""), - (from != NULL ? from : ""), - msn_user_get_passport(session->user), - session->passport_info.mail_url, NULL, NULL); - - g_free(from); - g_free(subject); - - g_hash_table_destroy(table); -} - -static void -system_msg(MsnCmdProc *cmdproc, MsnMessage *msg) -{ - GHashTable *table; - const char *type_s; - - if (strcmp(msg->remote_user, "Hotmail")) - /* This isn't an official message. */ - return; - - table = msn_message_get_hashtable_from_body(msg); - - if ((type_s = g_hash_table_lookup(table, "Type")) != NULL) - { - int type = atoi(type_s); - char buf[MSN_BUF_LEN] = ""; - int minutes; - - switch (type) - { - case 1: - minutes = atoi(g_hash_table_lookup(table, "Arg1")); - g_snprintf(buf, sizeof(buf), dngettext(PACKAGE, - "The MSN server will shut down for maintenance " - "in %d minute. You will automatically be " - "signed out at that time. Please finish any " - "conversations in progress.\n\nAfter the " - "maintenance has been completed, you will be " - "able to successfully sign in.", - "The MSN server will shut down for maintenance " - "in %d minutes. You will automatically be " - "signed out at that time. Please finish any " - "conversations in progress.\n\nAfter the " - "maintenance has been completed, you will be " - "able to successfully sign in.", minutes), - minutes); - default: - break; - } - - if (*buf != '\0') - purple_notify_info(cmdproc->session->account->gc, NULL, buf, NULL); - } - - g_hash_table_destroy(table); -} - -/************************************************************************** - * Dispatch server list management - **************************************************************************/ -typedef struct MsnAddRemoveListData { - MsnCmdProc *cmdproc; - MsnUser *user; - MsnListOp list_op; - gboolean add; -} MsnAddRemoveListData; - -static void -modify_unknown_buddy_on_list(MsnSession *session, const char *passport, - MsnNetwork network, gpointer data) -{ - MsnAddRemoveListData *addrem = data; - MsnCmdProc *cmdproc; - xmlnode *node; - char *payload; - int payload_len; - - cmdproc = addrem->cmdproc; - - /* Update user first */ - msn_user_set_network(addrem->user, network); - - node = xmlnode_new("ml"); - node->child = NULL; - - msn_add_contact_xml(node, passport, addrem->list_op, network); - - payload = xmlnode_to_str(node, &payload_len); - xmlnode_free(node); - - if (addrem->add) - msn_notification_post_adl(cmdproc, payload, payload_len); - else - msn_notification_post_rml(cmdproc, payload, payload_len); - - g_free(payload); - g_free(addrem); -} - -void -msn_notification_add_buddy_to_list(MsnNotification *notification, MsnListId list_id, - MsnUser *user) -{ - MsnAddRemoveListData *addrem; - MsnCmdProc *cmdproc; - MsnListOp list_op = 1 << list_id; - xmlnode *adl_node; - char *payload; - int payload_len; - - cmdproc = notification->servconn->cmdproc; - - adl_node = xmlnode_new("ml"); - adl_node->child = NULL; - - msn_add_contact_xml(adl_node, user->passport, list_op, user->networkid); - - payload = xmlnode_to_str(adl_node, &payload_len); - xmlnode_free(adl_node); - - if (user->networkid != MSN_NETWORK_UNKNOWN) { - msn_notification_post_adl(cmdproc, payload, payload_len); - - } else { - addrem = g_new(MsnAddRemoveListData, 1); - addrem->cmdproc = cmdproc; - addrem->user = user; - addrem->list_op = list_op; - addrem->add = TRUE; - - msn_notification_send_fqy(notification->session, payload, payload_len, - modify_unknown_buddy_on_list, addrem); - } - - g_free(payload); -} - -void -msn_notification_rem_buddy_from_list(MsnNotification *notification, MsnListId list_id, - MsnUser *user) -{ - MsnAddRemoveListData *addrem; - MsnCmdProc *cmdproc; - MsnListOp list_op = 1 << list_id; - xmlnode *rml_node; - char *payload; - int payload_len; - - cmdproc = notification->servconn->cmdproc; - - rml_node = xmlnode_new("ml"); - rml_node->child = NULL; - - msn_add_contact_xml(rml_node, user->passport, list_op, user->networkid); - - payload = xmlnode_to_str(rml_node, &payload_len); - xmlnode_free(rml_node); - - if (user->networkid != MSN_NETWORK_UNKNOWN) { - msn_notification_post_rml(cmdproc, payload, payload_len); - - } else { - addrem = g_new(MsnAddRemoveListData, 1); - addrem->cmdproc = cmdproc; - addrem->user = user; - addrem->list_op = list_op; - addrem->add = FALSE; - - msn_notification_send_fqy(notification->session, payload, payload_len, - modify_unknown_buddy_on_list, addrem); - } - - g_free(payload); -} - -/************************************************************************** - * Init - **************************************************************************/ -void -msn_notification_init(void) -{ - cbs_table = msn_table_new(); - - /* Synchronous */ - msn_table_add_cmd(cbs_table, "CHG", "CHG", NULL); - msn_table_add_cmd(cbs_table, "CHG", "ILN", iln_cmd); - msn_table_add_cmd(cbs_table, "ADL", "ILN", iln_cmd); - msn_table_add_cmd(cbs_table, "USR", "USR", usr_cmd); - msn_table_add_cmd(cbs_table, "USR", "XFR", xfr_cmd); - msn_table_add_cmd(cbs_table, "USR", "GCF", gcf_cmd); - msn_table_add_cmd(cbs_table, "CVR", "CVR", cvr_cmd); - msn_table_add_cmd(cbs_table, "VER", "VER", ver_cmd); - msn_table_add_cmd(cbs_table, "PRP", "PRP", prp_cmd); - msn_table_add_cmd(cbs_table, "BLP", "BLP", blp_cmd); - msn_table_add_cmd(cbs_table, "XFR", "XFR", xfr_cmd); - - /* Asynchronous */ - msn_table_add_cmd(cbs_table, NULL, "IPG", ipg_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, "GCF", gcf_cmd); - msn_table_add_cmd(cbs_table, NULL, "SBS", sbs_cmd); - msn_table_add_cmd(cbs_table, NULL, "NOT", not_cmd); - - msn_table_add_cmd(cbs_table, NULL, "CHL", chl_cmd); - msn_table_add_cmd(cbs_table, NULL, "RML", rml_cmd); - msn_table_add_cmd(cbs_table, NULL, "ADL", adl_cmd); - msn_table_add_cmd(cbs_table, NULL, "FQY", fqy_cmd); - - msn_table_add_cmd(cbs_table, NULL, "QRY", NULL); - msn_table_add_cmd(cbs_table, NULL, "QNG", qng_cmd); - msn_table_add_cmd(cbs_table, NULL, "FLN", fln_cmd); - msn_table_add_cmd(cbs_table, NULL, "NLN", nln_cmd); - msn_table_add_cmd(cbs_table, NULL, "ILN", iln_cmd); - msn_table_add_cmd(cbs_table, NULL, "OUT", out_cmd); - msn_table_add_cmd(cbs_table, NULL, "RNG", rng_cmd); - - msn_table_add_cmd(cbs_table, NULL, "UBX", ubx_cmd); - msn_table_add_cmd(cbs_table, NULL, "UUX", uux_cmd); - - msn_table_add_cmd(cbs_table, NULL, "UBN", ubn_cmd); - msn_table_add_cmd(cbs_table, NULL, "UUN", uun_cmd); - - msn_table_add_cmd(cbs_table, NULL, "URL", url_cmd); - - msn_table_add_cmd(cbs_table, "fallback", "XFR", xfr_cmd); - - msn_table_add_error(cbs_table, "ADL", adl_error); - msn_table_add_error(cbs_table, "RML", rml_error); - msn_table_add_error(cbs_table, "FQY", fqy_error); - msn_table_add_error(cbs_table, "USR", usr_error); - - msn_table_add_msg_type(cbs_table, - "text/x-msmsgsprofile", - profile_msg); - /*initial OIM notification*/ - msn_table_add_msg_type(cbs_table, - "text/x-msmsgsinitialmdatanotification", - initial_mdata_msg); - /*OIM notification when user online*/ - msn_table_add_msg_type(cbs_table, - "text/x-msmsgsoimnotification", - initial_mdata_msg); - msn_table_add_msg_type(cbs_table, - "text/x-msmsgsinitialemailnotification", - initial_email_msg); - msn_table_add_msg_type(cbs_table, - "text/x-msmsgsemailnotification", - email_msg); - /*delete an offline Message notification*/ - msn_table_add_msg_type(cbs_table, - "text/x-msmsgsactivemailnotification", - delete_oim_msg); - msn_table_add_msg_type(cbs_table, - "application/x-msmsgssystemmessage", - system_msg); - /* generic message handlers */ - msn_table_add_msg_type(cbs_table, "text/plain", - msn_plain_msg); - msn_table_add_msg_type(cbs_table, "text/x-msmsgscontrol", - msn_control_msg); - msn_table_add_msg_type(cbs_table, "text/x-msnmsgr-datacast", - msn_datacast_msg); -} - -void -msn_notification_end(void) -{ - msn_table_destroy(cbs_table); -} - diff --git a/libpurple/protocols/msn/notification.h b/libpurple/protocols/msn/notification.h deleted file mode 100644 index 4e9798dc6b..0000000000 --- a/libpurple/protocols/msn/notification.h +++ /dev/null @@ -1,124 +0,0 @@ -/** - * @file notification.h Notification server functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_NOTIFICATION_H -#define MSN_NOTIFICATION_H - -typedef struct _MsnNotification MsnNotification; - -/* MSN protocol challenge info */ - -/* MSNP18 challenge: WLM Version 2009 (Build 14.0.8089.726) */ -#define MSNP18_WLM_PRODUCT_KEY "C1BX{V4W}Q3*10SM" -#define MSNP18_WLM_PRODUCT_ID "PROD0120PW!CCV9@" - -/* MSNP15 challenge: WLM 8.5.1288.816 */ -#define MSNP15_WLM_PRODUCT_KEY "ILTXC!4IXB5FB*PX" -#define MSNP15_WLM_PRODUCT_ID "PROD0119GSJUC$18" - -/* MSNP13 challenge */ -#define MSNP13_WLM_PRODUCT_KEY "O4BG@C7BWLYQX?5G" -#define MSNP13_WLM_PRODUCT_ID "PROD01065C%ZFN6F" - -#define MSNP10_PRODUCT_KEY "VT6PX?UQTM4WM%YR" -#define MSNP10_PRODUCT_ID "PROD0038W!61ZTF9" - -#include "cmdproc.h" -#include "msg.h" -#include "session.h" -#include "servconn.h" -#include "state.h" -#include "user.h" -#include "userlist.h" - -struct _MsnNotification -{ - MsnSession *session; - - /** - * This is a convenience pointer that always points to - * servconn->cmdproc - */ - MsnCmdProc *cmdproc; - MsnServConn *servconn; - - gboolean in_use; -}; - -typedef void (*MsnFqyCb)(MsnSession *session, const char *passport, MsnNetwork network, gpointer data); - -/* Type used for msn_notification_send_uun */ -typedef enum { - MSN_UNIFIED_NOTIFICATION_SHARED_FOLDERS = 1, - MSN_UNIFIED_NOTIFICATION_UNKNOWN1 = 2, - MSN_UNIFIED_NOTIFICATION_P2P = 3, - MSN_UNIFIED_NOTIFICATION_MPOP = 4 - -} MsnUnifiedNotificationType; - -void msn_notification_end(void); -void msn_notification_init(void); - -void msn_notification_add_buddy_to_list(MsnNotification *notification, - MsnListId list_id, MsnUser *user); -void msn_notification_rem_buddy_from_list(MsnNotification *notification, - MsnListId list_id, MsnUser *user); - -void msn_notification_send_fqy(MsnSession *session, - const char *payload, int payload_len, - MsnFqyCb cb, gpointer cb_data); - -MsnNotification *msn_notification_new(MsnSession *session); -void msn_notification_destroy(MsnNotification *notification); -gboolean msn_notification_connect(MsnNotification *notification, - const char *host, int port); -void msn_notification_disconnect(MsnNotification *notification); -void msn_notification_dump_contact(MsnSession *session); - -void msn_notification_send_uum(MsnSession *session, MsnMessage *msg); - -void msn_notification_send_uux(MsnSession *session, const char *payload); - -void msn_notification_send_uux_endpointdata(MsnSession *session); - -void msn_notification_send_uux_private_endpointdata(MsnSession *session); - -void msn_notification_send_uun(MsnSession *session, - const char *user, - MsnUnifiedNotificationType type, - const char *payload); - -void msn_notification_send_circle_auth(MsnSession *session, const char *ticket); - -/** - * Closes a notification. - * - * It's first closed, and then disconnected. - * - * @param notification The notification object to close. - */ -void msn_notification_close(MsnNotification *notification); - -void msn_got_login_params(MsnSession *session, const char *ticket, const char *response); - -#endif /* MSN_NOTIFICATION_H */ diff --git a/libpurple/protocols/msn/object.c b/libpurple/protocols/msn/object.c deleted file mode 100644 index bee264109a..0000000000 --- a/libpurple/protocols/msn/object.c +++ /dev/null @@ -1,459 +0,0 @@ -/** - * @file object.c MSNObject API - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "msn.h" -#include "object.h" -#include "debug.h" -/* Sha1 stuff */ -#include "cipher.h" -/* Base64 stuff */ -#include "util.h" - -#define GET_STRING_TAG(field, id) \ - if ((tag = strstr(str, id "=\"")) != NULL) \ - { \ - tag += strlen(id "=\""); \ - c = strchr(tag, '"'); \ - if (c != NULL) \ - { \ - if (obj->field != NULL) \ - g_free(obj->field); \ - obj->field = g_strndup(tag, c - tag); \ - } \ - } - -#define GET_INT_TAG(field, id) \ - if ((tag = strstr(str, id "=\"")) != NULL) \ - { \ - char buf[16]; \ - size_t offset; \ - tag += strlen(id "=\""); \ - c = strchr(tag, '"'); \ - if (c != NULL) \ - { \ - memset(buf, 0, sizeof(buf)); \ - offset = c - tag; \ - if (offset >= sizeof(buf)) \ - offset = sizeof(buf) - 1; \ - strncpy(buf, tag, offset); \ - obj->field = atoi(buf); \ - } \ - } - -static GList *local_objs; - -MsnObject * -msn_object_new(void) -{ - MsnObject *obj; - - obj = g_new0(MsnObject, 1); - - msn_object_set_type(obj, MSN_OBJECT_UNKNOWN); - msn_object_set_friendly(obj, "AAA="); - - return obj; -} - -MsnObject * -msn_object_new_from_string(const char *str) -{ - MsnObject *obj; - char *tag, *c; - - g_return_val_if_fail(str != NULL, NULL); - - if (strncmp(str, "<msnobj ", 8)) - return NULL; - - obj = msn_object_new(); - - GET_STRING_TAG(creator, "Creator"); - GET_INT_TAG(size, "Size"); - GET_INT_TAG(type, "Type"); - GET_STRING_TAG(location, "Location"); - GET_STRING_TAG(friendly, "Friendly"); - GET_STRING_TAG(sha1d, "SHA1D"); - GET_STRING_TAG(sha1c, "SHA1C"); - GET_STRING_TAG(url, "Url"); - GET_STRING_TAG(url1, "Url1"); - - /* If we are missing any of the required elements then discard the object */ - if (obj->creator == NULL || obj->size == 0 || obj->type == 0 - || obj->sha1d == NULL) { - purple_debug_error("msn", "Discarding invalid msnobj: '%s'\n", str); - msn_object_destroy(obj); - return NULL; - } - - if (obj->location == NULL || obj->friendly == NULL) { - /* Location/friendly are required for non-buddyicon objects */ - if (obj->type != MSN_OBJECT_USERTILE) { - purple_debug_error("msn", "Discarding invalid msnobj: '%s'\n", str); - msn_object_destroy(obj); - return NULL; - /* Buddy icon object can contain Url/Url1 instead */ - } else if (obj->url == NULL || obj->url1 == NULL) { - purple_debug_error("msn", "Discarding invalid msnobj: '%s'\n", str); - msn_object_destroy(obj); - return NULL; - } - } - - return obj; -} - -MsnObject* -msn_object_new_from_image(PurpleStoredImage *img, const char *location, - const char *creator, MsnObjectType type) -{ - MsnObject *msnobj; - - PurpleCipherContext *ctx; - char *buf; - gconstpointer data; - size_t size; - char *base64; - unsigned char digest[20]; - - msnobj = NULL; - - if (img == NULL) - return msnobj; - - size = purple_imgstore_get_size(img); - data = purple_imgstore_get_data(img); - - /* New object */ - msnobj = msn_object_new(); - msn_object_set_local(msnobj); - msn_object_set_type(msnobj, type); - msn_object_set_location(msnobj, location); - msn_object_set_creator(msnobj, creator); - - msn_object_set_image(msnobj, img); - - /* Compute the SHA1D field. */ - memset(digest, 0, sizeof(digest)); - - ctx = purple_cipher_context_new_by_name("sha1", NULL); - purple_cipher_context_append(ctx, data, size); - purple_cipher_context_digest(ctx, sizeof(digest), digest, NULL); - - base64 = purple_base64_encode(digest, sizeof(digest)); - msn_object_set_sha1d(msnobj, base64); - g_free(base64); - - msn_object_set_size(msnobj, size); - - /* Compute the SHA1C field. */ - buf = g_strdup_printf( - "Creator%sSize%dType%dLocation%sFriendly%sSHA1D%s", - msn_object_get_creator(msnobj), - msn_object_get_size(msnobj), - msn_object_get_type(msnobj), - msn_object_get_location(msnobj), - msn_object_get_friendly(msnobj), - msn_object_get_sha1d(msnobj)); - - memset(digest, 0, sizeof(digest)); - - purple_cipher_context_reset(ctx, NULL); - purple_cipher_context_append(ctx, (const guchar *)buf, strlen(buf)); - purple_cipher_context_digest(ctx, sizeof(digest), digest, NULL); - purple_cipher_context_destroy(ctx); - g_free(buf); - - base64 = purple_base64_encode(digest, sizeof(digest)); - msn_object_set_sha1c(msnobj, base64); - g_free(base64); - - return msnobj; -} - -void -msn_object_destroy(MsnObject *obj) -{ - g_return_if_fail(obj != NULL); - - g_free(obj->creator); - g_free(obj->location); - g_free(obj->friendly); - g_free(obj->sha1d); - g_free(obj->sha1c); - g_free(obj->url); - g_free(obj->url1); - - purple_imgstore_unref(obj->img); - - if (obj->local) - local_objs = g_list_remove(local_objs, obj); - - g_free(obj); -} - -char * -msn_object_to_string(const MsnObject *obj) -{ - char *str; - const char *sha1c; - - g_return_val_if_fail(obj != NULL, NULL); - - sha1c = msn_object_get_sha1c(obj); - - str = g_strdup_printf("<msnobj Creator=\"%s\" Size=\"%d\" Type=\"%d\" " - "Location=\"%s\" Friendly=\"%s\" SHA1D=\"%s\"" - "%s%s%s/>", - msn_object_get_creator(obj), - msn_object_get_size(obj), - msn_object_get_type(obj), - msn_object_get_location(obj), - msn_object_get_friendly(obj), - msn_object_get_sha1d(obj), - sha1c ? " SHA1C=\"" : "", - sha1c ? sha1c : "", - sha1c ? "\"" : ""); - - return str; -} - -void -msn_object_set_creator(MsnObject *obj, const char *creator) -{ - g_return_if_fail(obj != NULL); - - g_free(obj->creator); - obj->creator = g_strdup(creator); -} - -void -msn_object_set_size(MsnObject *obj, int size) -{ - g_return_if_fail(obj != NULL); - - obj->size = size; -} - -void -msn_object_set_type(MsnObject *obj, MsnObjectType type) -{ - g_return_if_fail(obj != NULL); - - obj->type = type; -} - -void -msn_object_set_location(MsnObject *obj, const char *location) -{ - g_return_if_fail(obj != NULL); - - g_free(obj->location); - obj->location = g_strdup(location); -} - -void -msn_object_set_friendly(MsnObject *obj, const char *friendly) -{ - g_return_if_fail(obj != NULL); - - g_free(obj->friendly); - obj->friendly = g_strdup(friendly); -} - -void -msn_object_set_sha1d(MsnObject *obj, const char *sha1d) -{ - g_return_if_fail(obj != NULL); - - g_free(obj->sha1d); - obj->sha1d = g_strdup(sha1d); -} - -void -msn_object_set_sha1c(MsnObject *obj, const char *sha1c) -{ - g_return_if_fail(obj != NULL); - - g_free(obj->sha1c); - obj->sha1c = g_strdup(sha1c); -} - -void -msn_object_set_url(MsnObject *obj, const char *url) -{ - g_return_if_fail(obj != NULL); - - g_free(obj->url); - obj->url = g_strdup(url); -} - -void -msn_object_set_url1(MsnObject *obj, const char *url) -{ - g_return_if_fail(obj != NULL); - - g_free(obj->url1); - obj->url1 = g_strdup(url); -} - -const char * -msn_object_get_creator(const MsnObject *obj) -{ - g_return_val_if_fail(obj != NULL, NULL); - - return obj->creator; -} - -int -msn_object_get_size(const MsnObject *obj) -{ - g_return_val_if_fail(obj != NULL, 0); - - return obj->size; -} - -MsnObjectType -msn_object_get_type(const MsnObject *obj) -{ - g_return_val_if_fail(obj != NULL, MSN_OBJECT_UNKNOWN); - - return obj->type; -} - -const char * -msn_object_get_location(const MsnObject *obj) -{ - g_return_val_if_fail(obj != NULL, NULL); - - return obj->location; -} - -const char * -msn_object_get_friendly(const MsnObject *obj) -{ - g_return_val_if_fail(obj != NULL, NULL); - - return obj->friendly; -} - -const char * -msn_object_get_sha1d(const MsnObject *obj) -{ - g_return_val_if_fail(obj != NULL, NULL); - - return obj->sha1d; -} - -const char * -msn_object_get_sha1c(const MsnObject *obj) -{ - g_return_val_if_fail(obj != NULL, NULL); - - return obj->sha1c; -} - -const char * -msn_object_get_sha1(const MsnObject *obj) -{ - g_return_val_if_fail(obj != NULL, NULL); - - if(obj->sha1c != NULL) { - return obj->sha1c; - } else { - return obj->sha1d; - } -} - -const char * -msn_object_get_url(const MsnObject *obj) -{ - g_return_val_if_fail(obj != NULL, NULL); - - return obj->url; -} - -const char * -msn_object_get_url1(const MsnObject *obj) -{ - g_return_val_if_fail(obj != NULL, NULL); - - return obj->url1; -} - -MsnObject * -msn_object_find_local(const char *sha1) -{ - GList *l; - - g_return_val_if_fail(sha1 != NULL, NULL); - - for (l = local_objs; l != NULL; l = l->next) - { - MsnObject *local_obj = l->data; - - if (!strcmp(msn_object_get_sha1(local_obj), sha1)) - return local_obj; - } - - return NULL; - -} - -void -msn_object_set_local(MsnObject *obj) -{ - g_return_if_fail(obj != NULL); - - obj->local = TRUE; - - local_objs = g_list_append(local_objs, obj); -} - -void -msn_object_set_image(MsnObject *obj, PurpleStoredImage *img) -{ - g_return_if_fail(obj != NULL); - g_return_if_fail(img != NULL); - - /* obj->local = TRUE; */ - - purple_imgstore_unref(obj->img); - obj->img = purple_imgstore_ref(img); -} - -PurpleStoredImage * -msn_object_get_image(const MsnObject *obj) -{ - MsnObject *local_obj; - - g_return_val_if_fail(obj != NULL, NULL); - - local_obj = msn_object_find_local(msn_object_get_sha1(obj)); - - if (local_obj != NULL) - return local_obj->img; - - return NULL; -} diff --git a/libpurple/protocols/msn/object.h b/libpurple/protocols/msn/object.h deleted file mode 100644 index 81572dc799..0000000000 --- a/libpurple/protocols/msn/object.h +++ /dev/null @@ -1,276 +0,0 @@ -/** - * @file object.h MSNObject API - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_OBJECT_H -#define MSN_OBJECT_H - -typedef enum -{ - MSN_OBJECT_UNKNOWN = -1, /**< Unknown object */ - MSN_OBJECT_RESERVED1 = 1, /**< Reserved */ - MSN_OBJECT_EMOTICON = 2, /**< Custom Emoticon */ - MSN_OBJECT_USERTILE = 3, /**< UserTile (buddy icon) */ - MSN_OBJECT_RESERVED2 = 4, /**< Reserved */ - MSN_OBJECT_BACKGROUND = 5 /**< Background */ -} MsnObjectType; - -#include "internal.h" - -#include "imgstore.h" - -typedef struct -{ - gboolean local; - - char *creator; - int size; - MsnObjectType type; - PurpleStoredImage *img; - char *location; - char *friendly; - char *sha1d; - char *sha1c; - char *url; - char *url1; -} MsnObject; - -/** - * Creates a MsnObject structure. - * - * @return A new MsnObject structure. - */ -MsnObject *msn_object_new(void); - -/** - * Creates a MsnObject structure from a string. - * - * @param str The string. - * - * @return The new MsnObject structure. - */ -MsnObject *msn_object_new_from_string(const char *str); - -/** - * Creates a MsnObject structure from a stored image - * - * @param img The image associated to object - * @param location The object location as stored in MsnObject - * @param creator The creator of the object - * @param type The type of the object - * - * @return A new MsnObject structure - */ -MsnObject *msn_object_new_from_image(PurpleStoredImage *img, - const char *location, const char *creator, MsnObjectType type); - -/** - * Destroys an MsnObject structure. - * - * @param obj The object structure. - */ -void msn_object_destroy(MsnObject *obj); - -/** - * Outputs a string representation of an MsnObject. - * - * @param obj The object. - * - * @return The string representation. This must be freed. - */ -char *msn_object_to_string(const MsnObject *obj); - -/** - * Sets the creator field in a MsnObject. - * - * @param creator The creator value. - */ -void msn_object_set_creator(MsnObject *obj, const char *creator); - -/** - * Sets the size field in a MsnObject. - * - * @param size The size value. - */ -void msn_object_set_size(MsnObject *obj, int size); - -/** - * Sets the type field in a MsnObject. - * - * @param type The type value. - */ -void msn_object_set_type(MsnObject *obj, MsnObjectType type); - -/** - * Sets the location field in a MsnObject. - * - * @param location The location value. - */ -void msn_object_set_location(MsnObject *obj, const char *location); - -/** - * Sets the friendly name field in a MsnObject. - * - * @param friendly The friendly name value. - */ -void msn_object_set_friendly(MsnObject *obj, const char *friendly); - -/** - * Sets the SHA1D field in a MsnObject. - * - * @param sha1d The sha1d value. - */ -void msn_object_set_sha1d(MsnObject *obj, const char *sha1d); - -/** - * Sets the SHA1C field in a MsnObject. - * - * @param sha1c The sha1c value. - */ -void msn_object_set_sha1c(MsnObject *obj, const char *sha1c); - -/** - * Associates an image with a MsnObject. - * - * @param obj The object. - * @param img The image to associate. - */ -void msn_object_set_image(MsnObject *obj, PurpleStoredImage *img); - -/** - * Sets the url field in a MsnObject. - * - * @param url The url value. - */ -void msn_object_set_url(MsnObject *obj, const char *url); - -/** - * Sets the url1 field in a MsnObject. - * - * @param url1 The url1 value. - */ -void msn_object_set_url1(MsnObject *obj, const char *url); - -/** - * Returns a MsnObject's creator value. - * - * @param obj The object. - * - * @return The creator value. - */ -const char *msn_object_get_creator(const MsnObject *obj); - -/** - * Returns a MsnObject's size value. - * - * @param obj The object. - * - * @return The size value. - */ -int msn_object_get_size(const MsnObject *obj); - -/** - * Returns a MsnObject's type. - * - * @param obj The object. - * - * @return The object type. - */ -MsnObjectType msn_object_get_type(const MsnObject *obj); - -/** - * Returns a MsnObject's location value. - * - * @param obj The object. - * - * @return The location value. - */ -const char *msn_object_get_location(const MsnObject *obj); - -/** - * Returns a MsnObject's friendly name value. - * - * @param obj The object. - * - * @return The friendly name value. - */ -const char *msn_object_get_friendly(const MsnObject *obj); - -/** - * Returns a MsnObject's SHA1D value. - * - * @param obj The object. - * - * @return The SHA1D value. - */ -const char *msn_object_get_sha1d(const MsnObject *obj); - -/** - * Returns a MsnObject's SHA1C value. - * - * @param obj The object. - * - * @return The SHA1C value. - */ -const char *msn_object_get_sha1c(const MsnObject *obj); - -/** - * Returns a MsnObject's SHA1C value if it exists, otherwise SHA1D. - * - * @param obj The object. - * - * @return The SHA1C value. - */ -const char *msn_object_get_sha1(const MsnObject *obj); - -/** - * Returns the image associated with the MsnObject. - * - * @param obj The object. - * - * @return The associated image. - */ -PurpleStoredImage *msn_object_get_image(const MsnObject *obj); - -/** - * Returns a MsnObject's url value. - * - * @param obj The object. - * - * @return The url value. - */ -const char *msn_object_get_url(const MsnObject *obj); - -/** - * Returns a MsnObject's url1 value. - * - * @param obj The object. - * - * @return The url1 value. - */ -const char *msn_object_get_url1(const MsnObject *obj); - -MsnObject * msn_object_find_local(const char *sha1); - -void msn_object_set_local(MsnObject *obj); - -#endif /* MSN_OBJECT_H */ diff --git a/libpurple/protocols/msn/oim.c b/libpurple/protocols/msn/oim.c deleted file mode 100644 index 54b5a6648a..0000000000 --- a/libpurple/protocols/msn/oim.c +++ /dev/null @@ -1,886 +0,0 @@ -/** - * @file oim.c - * get and send MSN offline Instant Message via SOAP request - * Author - * MaYuan<mayuan2006@gmail.com> - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "internal.h" -#include "debug.h" - -#include "soap.h" -#include "oim.h" -#include "msnutils.h" - -typedef struct _MsnOimSendReq { - char *from_member; - char *friendname; - char *to_member; - char *oim_msg; -} MsnOimSendReq; - -typedef struct { - MsnOim *oim; - char *msg_id; -} MsnOimRecvData; - -/*Local Function Prototype*/ -static void msn_parse_oim_xml(MsnOim *oim, xmlnode *node); -static void msn_oim_free_send_req(MsnOimSendReq *req); -static void msn_oim_recv_data_free(MsnOimRecvData *data); -static void msn_oim_post_single_get_msg(MsnOim *oim, MsnOimRecvData *data); - -/*new a OIM object*/ -MsnOim * -msn_oim_new(MsnSession *session) -{ - MsnOim *oim; - - oim = g_new0(MsnOim, 1); - oim->session = session; - oim->oim_list = NULL; - oim->run_id = rand_guid(); - oim->challenge = NULL; - oim->send_queue = g_queue_new(); - oim->send_seq = 1; - return oim; -} - -/*destroy the oim object*/ -void -msn_oim_destroy(MsnOim *oim) -{ - MsnOimSendReq *request; - - purple_debug_info("msn", "destroy the OIM %p\n", oim); - g_free(oim->run_id); - g_free(oim->challenge); - - while ((request = g_queue_pop_head(oim->send_queue)) != NULL) - msn_oim_free_send_req(request); - g_queue_free(oim->send_queue); - - while (oim->oim_list != NULL) - msn_oim_recv_data_free((MsnOimRecvData *)oim->oim_list->data); - - g_free(oim); -} - -static MsnOimSendReq * -msn_oim_new_send_req(const char *from_member, const char*friendname, - const char* to_member, const char *msg) -{ - MsnOimSendReq *request; - - request = g_new0(MsnOimSendReq, 1); - request->from_member = g_strdup(from_member); - request->friendname = g_strdup(friendname); - request->to_member = g_strdup(to_member); - request->oim_msg = g_strdup(msg); - return request; -} - -static void -msn_oim_free_send_req(MsnOimSendReq *req) -{ - g_return_if_fail(req != NULL); - - g_free(req->from_member); - g_free(req->friendname); - g_free(req->to_member); - g_free(req->oim_msg); - - g_free(req); -} - -static MsnOimRecvData * -msn_oim_recv_data_new(MsnOim *oim, char *msg_id) -{ - MsnOimRecvData *data; - - data = g_new0(MsnOimRecvData, 1); - data->oim = oim; - data->msg_id = msg_id; - - oim->oim_list = g_list_append(oim->oim_list, data); - - return data; -} - -/* Probably only good for g_list_find_custom */ -static gint -msn_recv_data_equal(MsnOimRecvData *a, const char *msg_id) -{ - return strcmp(a->msg_id, msg_id); -} - -static void -msn_oim_recv_data_free(MsnOimRecvData *data) -{ - data->oim->oim_list = g_list_remove(data->oim->oim_list, data); - g_free(data->msg_id); - - g_free(data); -} - -/**************************************** - * Manage OIM Tokens - ****************************************/ -typedef struct _MsnOimRequestData { - MsnOim *oim; - gboolean send; - const char *action; - const char *host; - const char *url; - xmlnode *body; - MsnSoapCallback cb; - gpointer cb_data; -} MsnOimRequestData; - -static gboolean msn_oim_request_helper(MsnOimRequestData *data); - -static void -msn_oim_request_cb(MsnSoapMessage *request, MsnSoapMessage *response, - gpointer req_data) -{ - MsnOimRequestData *data = (MsnOimRequestData *)req_data; - xmlnode *fault = NULL; - xmlnode *faultcode = NULL; - - if (response != NULL) - fault = xmlnode_get_child(response->xml, "Body/Fault"); - - if (fault && (faultcode = xmlnode_get_child(fault, "faultcode"))) { - gchar *faultcode_str = xmlnode_get_data(faultcode); - gboolean need_token_update = FALSE; - - if (faultcode_str) { - if (g_str_equal(faultcode_str, "q0:BadContextToken") || - g_str_equal(faultcode_str, "AuthenticationFailed") || - g_str_equal(faultcode_str, "s:AuthenticationFailed")) - need_token_update = TRUE; - else if (g_str_equal(faultcode_str, "q0:AuthenticationFailed") && - xmlnode_get_child(fault, "detail/RequiredAuthPolicy") != NULL) - need_token_update = TRUE; - } - - if (need_token_update) { - purple_debug_warning("msn", "OIM Request Error, Updating token now.\n"); - msn_nexus_update_token(data->oim->session->nexus, - data->send ? MSN_AUTH_LIVE_SECURE : MSN_AUTH_MESSENGER_WEB, - (GSourceFunc)msn_oim_request_helper, data); - g_free(faultcode_str); - return; - - } - - g_free(faultcode_str); - } - - if (data->cb) - data->cb(request, response, data->cb_data); - xmlnode_free(data->body); - g_free(data); -} - -static gboolean -msn_oim_request_helper(MsnOimRequestData *data) -{ - MsnSession *session = data->oim->session; - - if (data->send) { - /* The Sending of OIM's uses a different token for some reason. */ - xmlnode *ticket; - ticket = xmlnode_get_child(data->body, "Header/Ticket"); - xmlnode_set_attrib(ticket, "passport", - msn_nexus_get_token_str(session->nexus, MSN_AUTH_LIVE_SECURE)); - } - else - { - xmlnode *passport; - xmlnode *xml_t; - xmlnode *xml_p; - GHashTable *token; - const char *msn_t; - const char *msn_p; - - token = msn_nexus_get_token(session->nexus, MSN_AUTH_MESSENGER_WEB); - g_return_val_if_fail(token != NULL, FALSE); - - msn_t = g_hash_table_lookup(token, "t"); - msn_p = g_hash_table_lookup(token, "p"); - - g_return_val_if_fail(msn_t != NULL, FALSE); - g_return_val_if_fail(msn_p != NULL, FALSE); - - passport = xmlnode_get_child(data->body, "Header/PassportCookie"); - xml_t = xmlnode_get_child(passport, "t"); - xml_p = xmlnode_get_child(passport, "p"); - - /* frees old token text, or the 'EMPTY' text if first time */ - xmlnode_free(xml_t->child); - xmlnode_free(xml_p->child); - - xmlnode_insert_data(xml_t, msn_t, -1); - xmlnode_insert_data(xml_p, msn_p, -1); - } - - msn_soap_message_send(session, - msn_soap_message_new(data->action, xmlnode_copy(data->body)), - data->host, data->url, FALSE, - msn_oim_request_cb, data); - - return FALSE; -} - - -static void -msn_oim_make_request(MsnOim *oim, gboolean send, const char *action, - const char *host, const char *url, xmlnode *body, MsnSoapCallback cb, - gpointer cb_data) -{ - MsnOimRequestData *data = g_new0(MsnOimRequestData, 1); - data->oim = oim; - data->send = send; - data->action = action; - data->host = host; - data->url = url; - data->body = body; - data->cb = cb; - data->cb_data = cb_data; - - msn_oim_request_helper(data); -} - -/**************************************** - * OIM GetMetadata request - * **************************************/ -static void -msn_oim_get_metadata_cb(MsnSoapMessage *request, MsnSoapMessage *response, - gpointer data) -{ - MsnOim *oim = data; - - if (response) { - msn_parse_oim_xml(oim, - xmlnode_get_child(response->xml, "Body/GetMetadataResponse/MD")); - } -} - -/* Post to get the OIM Metadata */ -static void -msn_oim_get_metadata(MsnOim *oim) -{ - msn_oim_make_request(oim, FALSE, MSN_OIM_GET_METADATA_ACTION, - MSN_OIM_RETRIEVE_HOST, MSN_OIM_RETRIEVE_URL, - xmlnode_from_str(MSN_OIM_GET_METADATA_TEMPLATE, -1), - msn_oim_get_metadata_cb, oim); -} - -/**************************************** - * OIM send SOAP request - * **************************************/ -/*encode the message to OIM Message Format*/ -static gchar * -msn_oim_msg_to_str(MsnOim *oim, const char *body) -{ - GString *oim_body; - char *oim_base64; - char *c; - int len; - size_t base64_len; - - purple_debug_info("msn", "Encoding OIM Message...\n"); - len = strlen(body); - c = oim_base64 = purple_base64_encode((const guchar *)body, len); - base64_len = strlen(oim_base64); - purple_debug_info("msn", "Encoded base64 body:{%s}\n", oim_base64); - - oim_body = g_string_new(NULL); - g_string_printf(oim_body, MSN_OIM_MSG_TEMPLATE, - oim->run_id, oim->send_seq); - -#define OIM_LINE_LEN 76 - while (base64_len > OIM_LINE_LEN) { - g_string_append_len(oim_body, c, OIM_LINE_LEN); - g_string_append_c(oim_body, '\n'); - c += OIM_LINE_LEN; - base64_len -= OIM_LINE_LEN; - } -#undef OIM_LINE_LEN - - g_string_append(oim_body, c); - - g_free(oim_base64); - - return g_string_free(oim_body, FALSE); -} - -/* - * Process the send return SOAP string - * If got SOAP Fault,get the lock key,and resend it. - */ -static void -msn_oim_send_read_cb(MsnSoapMessage *request, MsnSoapMessage *response, - gpointer data) -{ - MsnOim *oim = data; - MsnOimSendReq *msg = g_queue_pop_head(oim->send_queue); - - g_return_if_fail(msg != NULL); - - if (response == NULL) { - purple_debug_info("msn", "cannot send OIM: %s\n", msg->oim_msg); - } else { - xmlnode *faultNode = xmlnode_get_child(response->xml, "Body/Fault"); - - if (faultNode == NULL) { - /*Send OK! return*/ - purple_debug_info("msn", "sent OIM: %s\n", msg->oim_msg); - } else { - xmlnode *faultcode = xmlnode_get_child(faultNode, "faultcode"); - - if (faultcode) { - char *faultcode_str = xmlnode_get_data(faultcode); - - if (faultcode_str && g_str_equal(faultcode_str, "q0:AuthenticationFailed")) { - xmlnode *challengeNode = xmlnode_get_child(faultNode, - "detail/LockKeyChallenge"); - char *challenge = NULL; - - if (challengeNode == NULL || (challenge = xmlnode_get_data(challengeNode)) == NULL) { - if (oim->challenge) { - g_free(oim->challenge); - oim->challenge = NULL; - - purple_debug_info("msn", "Resending OIM: %s\n", - msg->oim_msg); - g_queue_push_head(oim->send_queue, msg); - msn_oim_send_msg(oim); - msg = NULL; - } else { - purple_debug_info("msn", - "Can't find lock key for OIM: %s\n", - msg->oim_msg); - } - } else { - char buf[33]; - - msn_handle_chl(challenge, buf); - - g_free(oim->challenge); - oim->challenge = g_strndup(buf, sizeof(buf)); - g_free(challenge); - purple_debug_info("msn", "Found lockkey:{%s}\n", oim->challenge); - - /*repost the send*/ - purple_debug_info("msn", "Resending OIM: %s\n", msg->oim_msg); - g_queue_push_head(oim->send_queue, msg); - msn_oim_send_msg(oim); - msg = NULL; - } - } else { - /* Report the error */ - const char *str_reason = NULL; - - if (faultcode_str) { - if (g_str_equal(faultcode_str, "q0:SystemUnavailable")) { - str_reason = _("Message was not sent because the system is " - "unavailable. This normally happens when the " - "user is blocked or does not exist."); - } else if (g_str_equal(faultcode_str, "q0:SenderThrottleLimitExceeded")) { - str_reason = _("Message was not sent because messages " - "are being sent too quickly."); - } else if (g_str_equal(faultcode_str, "q0:InvalidContent")) { - str_reason = _("Message was not sent because an unknown " - "encoding error occurred."); - } - } - - if (str_reason == NULL) { - str_reason = _("Message was not sent because an unknown " - "error occurred."); - } - - msn_session_report_user(oim->session, msg->to_member, - str_reason, PURPLE_MESSAGE_ERROR); - msn_session_report_user(oim->session, msg->to_member, - msg->oim_msg, PURPLE_MESSAGE_RAW); - } - - g_free(faultcode_str); - } - } - } - - if (msg) - msn_oim_free_send_req(msg); -} - -void -msn_oim_prep_send_msg_info(MsnOim *oim, const char *membername, - const char* friendname, const char *tomember, - const char * msg) -{ - g_return_if_fail(oim != NULL); - - g_queue_push_tail(oim->send_queue, - msn_oim_new_send_req(membername, friendname, tomember, msg)); -} - -/*post send single message request to oim server*/ -void -msn_oim_send_msg(MsnOim *oim) -{ - MsnOimSendReq *oim_request; - char *soap_body; - char *msg_body; - - g_return_if_fail(oim != NULL); - oim_request = g_queue_peek_head(oim->send_queue); - g_return_if_fail(oim_request != NULL); - - purple_debug_info("msn", "Sending OIM: %s\n", oim_request->oim_msg); - - /* if we got the challenge lock key, we compute it - * else we go for the SOAP fault and resend it. - */ - if (oim->challenge == NULL){ - purple_debug_info("msn", "No lock key challenge, waiting for SOAP Fault and Resend\n"); - } - - msg_body = msn_oim_msg_to_str(oim, oim_request->oim_msg); - soap_body = g_strdup_printf(MSN_OIM_SEND_TEMPLATE, - oim_request->from_member, - oim_request->friendname, - oim_request->to_member, - MSNP15_WLM_PRODUCT_ID, - oim->challenge ? oim->challenge : "", - oim->send_seq, - msg_body); - - msn_oim_make_request(oim, TRUE, MSN_OIM_SEND_SOAP_ACTION, MSN_OIM_SEND_HOST, - MSN_OIM_SEND_URL, xmlnode_from_str(soap_body, -1), msn_oim_send_read_cb, - oim); - - /*increase the offline Sequence control*/ - if (oim->challenge != NULL) { - oim->send_seq++; - } - - g_free(msg_body); - g_free(soap_body); -} - -/**************************************** - * OIM delete SOAP request - * **************************************/ -static void -msn_oim_delete_read_cb(MsnSoapMessage *request, MsnSoapMessage *response, - gpointer data) -{ - MsnOimRecvData *rdata = data; - - if (response && xmlnode_get_child(response->xml, "Body/Fault") == NULL) - purple_debug_info("msn", "Delete OIM success\n"); - else - purple_debug_info("msn", "Delete OIM failed\n"); - - msn_oim_recv_data_free(rdata); -} - -/*Post to get the Offline Instant Message*/ -static void -msn_oim_post_delete_msg(MsnOimRecvData *rdata) -{ - MsnOim *oim = rdata->oim; - char *msgid = rdata->msg_id; - char *soap_body; - - purple_debug_info("msn", "Delete single OIM Message {%s}\n",msgid); - - soap_body = g_strdup_printf(MSN_OIM_DEL_TEMPLATE, msgid); - - msn_oim_make_request(oim, FALSE, MSN_OIM_DEL_SOAP_ACTION, MSN_OIM_RETRIEVE_HOST, - MSN_OIM_RETRIEVE_URL, xmlnode_from_str(soap_body, -1), msn_oim_delete_read_cb, rdata); - - g_free(soap_body); -} - -/**************************************** - * OIM get SOAP request - * **************************************/ -/* like purple_str_to_time, but different. The format of the timestamp - * is like this: 5 Sep 2007 21:42:12 -0700 */ -static time_t -msn_oim_parse_timestamp(const char *timestamp) -{ - char month_str[4], tz_str[6]; - char *tz_ptr = tz_str; - static const char *months[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL - }; - time_t tval = 0; - struct tm t; - memset(&t, 0, sizeof(t)); - - time(&tval); - localtime_r(&tval, &t); - - if (sscanf(timestamp, "%02d %03s %04d %02d:%02d:%02d %05s", - &t.tm_mday, month_str, &t.tm_year, - &t.tm_hour, &t.tm_min, &t.tm_sec, tz_str) == 7) { - gboolean offset_positive = TRUE; - int tzhrs; - int tzmins; - - for (t.tm_mon = 0; - months[t.tm_mon] != NULL && - strcmp(months[t.tm_mon], month_str) != 0; t.tm_mon++); - if (months[t.tm_mon] != NULL) { - if (*tz_str == '-') { - offset_positive = FALSE; - tz_ptr++; - } else if (*tz_str == '+') { - tz_ptr++; - } - - if (sscanf(tz_ptr, "%02d%02d", &tzhrs, &tzmins) == 2) { - time_t tzoff = tzhrs * 60 * 60 + tzmins * 60; -#ifdef _WIN32 - long sys_tzoff; -#endif - - if (offset_positive) - tzoff *= -1; - - t.tm_year -= 1900; - -#ifdef _WIN32 - if ((sys_tzoff = wpurple_get_tz_offset()) != -1) - tzoff += sys_tzoff; -#else -#ifdef HAVE_TM_GMTOFF - tzoff += t.tm_gmtoff; -#else -# ifdef HAVE_TIMEZONE - tzset(); /* making sure */ - tzoff -= timezone; -# endif -#endif -#endif /* _WIN32 */ - - return mktime(&t) + tzoff; - } - } - } - - purple_debug_info("msn", "Can't parse timestamp %s\n", timestamp); - return tval; -} - -/*Post the Offline Instant Message to User Conversation*/ -static void -msn_oim_report_to_user(MsnOimRecvData *rdata, const char *msg_str) -{ - MsnMessage *message; - const char *date; - const char *from; - const char *boundary; - char *decode_msg = NULL, *clean_msg = NULL; - gsize body_len; - char **tokens; - char *passport = NULL; - time_t stamp; - const char *charset = NULL; - - message = msn_message_new(MSN_MSG_UNKNOWN); - - msn_message_parse_payload(message, msg_str, strlen(msg_str), - MSG_OIM_LINE_DEM, MSG_OIM_BODY_DEM); - purple_debug_info("msn", "oim body:{%s}\n", message->body); - - boundary = msn_message_get_header_value(message, "boundary"); - - if (boundary != NULL) { - char *bounds; - char **part; - - bounds = g_strdup_printf("--%s" MSG_OIM_LINE_DEM, boundary); - tokens = g_strsplit(message->body, bounds, 0); - - /* tokens+1 to skip the "This is a multipart message..." text */ - for (part = tokens+1; *part != NULL; part++) { - MsnMessage *multipart; - const char *type; - multipart = msn_message_new(MSN_MSG_UNKNOWN); - msn_message_parse_payload(multipart, *part, strlen(*part), - MSG_OIM_LINE_DEM, MSG_OIM_BODY_DEM); - - type = msn_message_get_content_type(multipart); - if (type && !strcmp(type, "text/plain")) { - decode_msg = (char *)purple_base64_decode(multipart->body, &body_len); - charset = msn_message_get_charset(multipart); - - msn_message_unref(multipart); - break; - } - msn_message_unref(multipart); - } - - g_strfreev(tokens); - g_free(bounds); - - if (decode_msg == NULL) { - purple_debug_error("msn", "Couldn't find text/plain OIM message.\n"); - msn_message_unref(message); - return; - } - } else { - decode_msg = (char *)purple_base64_decode(message->body, &body_len); - charset = msn_message_get_charset(message); - } - - if (charset && !((g_ascii_strncasecmp(charset, "UTF-8", 5) == 0) || (g_ascii_strncasecmp(charset, "UTF8", 4) == 0))) { - clean_msg = g_convert(decode_msg, body_len, "UTF-8", charset, NULL, NULL, NULL); - - if (!clean_msg) { - char *clean = purple_utf8_salvage(decode_msg); - - purple_debug_error("msn", "Failed to convert charset from %s to UTF-8 for OIM message: %s\n", charset, clean); - - clean_msg = g_strdup_printf(_("%s (There was an error receiving this message. " - "Converting the encoding from %s to UTF-8 failed.)"), - clean, charset); - g_free(clean); - } - - g_free(decode_msg); - - } else if (!g_utf8_validate(decode_msg, body_len, NULL)) { - char *clean = purple_utf8_salvage(decode_msg); - - purple_debug_error("msn", "Received an OIM message that is not UTF-8," - " and no encoding specified: %s\n", clean); - - if (charset) { - clean_msg = g_strdup_printf(_("%s (There was an error receiving this message." - " The charset was %s, but it was not valid UTF-8.)"), - clean, charset); - } else { - clean_msg = g_strdup_printf(_("%s (There was an error receiving this message." - " The charset was missing, but it was not valid UTF-8.)"), - clean); - } - - g_free(clean); - g_free(decode_msg); - - } else { - clean_msg = decode_msg; - } - - from = msn_message_get_header_value(message, "X-OIM-originatingSource"); - - /* Match number to user's mobile number, FROM is a phone number - if the other side pages you using your phone number */ - if (from && !strncmp(from, "tel:+", 5)) { - MsnUser *user = msn_userlist_find_user_with_mobile_phone( - rdata->oim->session->userlist, from + 4); - - if (user && user->passport) - passport = g_strdup(user->passport); - } - - if (passport == NULL) { - char *start, *end; - - from = msn_message_get_header_value(message, "From"); - - tokens = g_strsplit(from, " ", 2); - if (tokens[1] != NULL) - from = (const char *)tokens[1]; - - start = strchr(from, '<'); - if (start != NULL) { - start++; - end = strchr(from, '>'); - if (end != NULL) - passport = g_strndup(start, end - start); - } - if (passport == NULL) - passport = g_strdup(_("Unknown")); - - g_strfreev(tokens); - } - - date = msn_message_get_header_value(message, "Date"); - stamp = msn_oim_parse_timestamp(date); - purple_debug_info("msn", "oim Date:{%s},passport{%s}\n", - date, passport); - - serv_got_im(purple_account_get_connection(rdata->oim->session->account), passport, clean_msg, 0, - stamp); - - /*Now get the oim message ID from the oim_list. - * and append to read list to prepare for deleting the Offline Message when sign out - */ - msn_oim_post_delete_msg(rdata); - - g_free(passport); - g_free(clean_msg); - msn_message_unref(message); -} - -/* Parse the XML data, - * prepare to report the OIM to user - */ -static void -msn_oim_get_read_cb(MsnSoapMessage *request, MsnSoapMessage *response, - gpointer data) -{ - MsnOimRecvData *rdata = data; - - if (response != NULL) { - xmlnode *msg_node = xmlnode_get_child(response->xml, - "Body/GetMessageResponse/GetMessageResult"); - - if (msg_node) { - char *msg_str = xmlnode_get_data(msg_node); - msn_oim_report_to_user(rdata, msg_str); - g_free(msg_str); - } else { - char *str = xmlnode_to_str(response->xml, NULL); - purple_debug_info("msn", "Unknown OIM response: %s\n", str); - g_free(str); - msn_oim_recv_data_free(rdata); - } - } else { - purple_debug_info("msn", "Failed to get OIM\n"); - msn_oim_recv_data_free(rdata); - } - -} - -/* parse the oim XML data - * and post it to the soap server to get the Offline Message - * */ -void -msn_parse_oim_msg(MsnOim *oim,const char *xmlmsg) -{ - xmlnode *node; - - purple_debug_info("msn", "%s\n", xmlmsg); - - if (!strcmp(xmlmsg, "too-large")) { - /* Too many OIM's to send via NS, so we need to request them via SOAP. */ - msn_oim_get_metadata(oim); - } else { - node = xmlnode_from_str(xmlmsg, -1); - msn_parse_oim_xml(oim, node); - xmlnode_free(node); - } -} - -static void -msn_parse_oim_xml(MsnOim *oim, xmlnode *node) -{ - xmlnode *mNode; - xmlnode *iu_node; - MsnSession *session = oim->session; - - g_return_if_fail(node != NULL); - - if (strcmp(node->name, "MD") != 0) { - char *xmlmsg = xmlnode_to_str(node, NULL); - purple_debug_info("msn", "WTF is this? %s\n", xmlmsg); - g_free(xmlmsg); - return; - } - - iu_node = xmlnode_get_child(node, "E/IU"); - - if (iu_node != NULL && purple_account_get_check_mail(session->account)) - { - char *unread = xmlnode_get_data(iu_node); - const char *passports[2] = { msn_user_get_passport(session->user) }; - const char *urls[2] = { session->passport_info.mail_url }; - int count; - - /* XXX/khc: pretty sure this is wrong */ - if (unread && (count = atoi(unread)) > 0) - purple_notify_emails(session->account->gc, count, FALSE, NULL, - NULL, passports, urls, NULL, NULL); - g_free(unread); - } - - for(mNode = xmlnode_get_child(node, "M"); mNode; - mNode = xmlnode_get_next_twin(mNode)){ - char *passport, *msgid, *nickname, *rtime = NULL; - xmlnode *e_node, *i_node, *n_node, *rt_node; - - e_node = xmlnode_get_child(mNode, "E"); - passport = xmlnode_get_data(e_node); - - i_node = xmlnode_get_child(mNode, "I"); - msgid = xmlnode_get_data(i_node); - - n_node = xmlnode_get_child(mNode, "N"); - nickname = xmlnode_get_data(n_node); - - rt_node = xmlnode_get_child(mNode, "RT"); - if (rt_node != NULL) { - rtime = xmlnode_get_data(rt_node); - } -/* purple_debug_info("msn", "E:{%s},I:{%s},rTime:{%s}\n",passport,msgid,rTime); */ - - if (!g_list_find_custom(oim->oim_list, msgid, (GCompareFunc)msn_recv_data_equal)) { - MsnOimRecvData *data = msn_oim_recv_data_new(oim, msgid); - msn_oim_post_single_get_msg(oim, data); - msgid = NULL; - } - - g_free(passport); - g_free(msgid); - g_free(rtime); - g_free(nickname); - } -} - -/*Post to get the Offline Instant Message*/ -static void -msn_oim_post_single_get_msg(MsnOim *oim, MsnOimRecvData *data) -{ - char *soap_body; - - purple_debug_info("msn", "Get single OIM Message\n"); - - soap_body = g_strdup_printf(MSN_OIM_GET_TEMPLATE, data->msg_id); - - msn_oim_make_request(oim, FALSE, MSN_OIM_GET_SOAP_ACTION, MSN_OIM_RETRIEVE_HOST, - MSN_OIM_RETRIEVE_URL, xmlnode_from_str(soap_body, -1), msn_oim_get_read_cb, - data); - - g_free(soap_body); -} - diff --git a/libpurple/protocols/msn/oim.h b/libpurple/protocols/msn/oim.h deleted file mode 100644 index 17751ea27b..0000000000 --- a/libpurple/protocols/msn/oim.h +++ /dev/null @@ -1,163 +0,0 @@ -/** - * @file oim.h Header file for oim.c - * Author - * MaYuan<mayuan2006@gmail.com> - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ -#ifndef MSN_OIM_H -#define MSN_OIM_H - -typedef struct _MsnOim MsnOim; - -/* OIM Retrieval Info */ -#define MSN_OIM_RETRIEVE_HOST "rsi.hotmail.com" -#define MSN_OIM_RETRIEVE_URL "/rsi/rsi.asmx" - -/* OIM GetMetadata SOAP Template */ -#define MSN_OIM_GET_METADATA_ACTION "http://www.hotmail.msn.com/ws/2004/09/oim/rsi/GetMetadata" - -#define MSN_OIM_GET_METADATA_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope"\ - " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ - " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ - " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ - "<soap:Header>"\ - "<PassportCookie xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\">"\ - "<t>EMPTY</t>"\ - "<p>EMPTY</p>"\ - "</PassportCookie>"\ - "</soap:Header>"\ - "<soap:Body>"\ - "<GetMetadata xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\" />"\ - "</soap:Body>"\ -"</soap:Envelope>" - -/*OIM GetMessage SOAP Template*/ -#define MSN_OIM_GET_SOAP_ACTION "http://www.hotmail.msn.com/ws/2004/09/oim/rsi/GetMessage" - -#define MSN_OIM_GET_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope"\ - " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ - " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ - " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ - "<soap:Header>"\ - "<PassportCookie xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\">"\ - "<t>EMPTY</t>"\ - "<p>EMPTY</p>"\ - "</PassportCookie>"\ - "</soap:Header>"\ - "<soap:Body>"\ - "<GetMessage xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\">"\ - "<messageId>%s</messageId>"\ - "<alsoMarkAsRead>false</alsoMarkAsRead>"\ - "</GetMessage>"\ - "</soap:Body>"\ -"</soap:Envelope>" - -/*OIM DeleteMessages SOAP Template*/ -#define MSN_OIM_DEL_SOAP_ACTION "http://www.hotmail.msn.com/ws/2004/09/oim/rsi/DeleteMessages" - -#define MSN_OIM_DEL_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope"\ - " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ - " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ - " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ - "<soap:Header>"\ - "<PassportCookie xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\">"\ - "<t>EMPTY</t>"\ - "<p>EMPTY</p>"\ - "</PassportCookie>"\ - "</soap:Header>"\ - "<soap:Body>"\ - "<DeleteMessages xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\">"\ - "<messageIds>"\ - "<messageId>%s</messageId>"\ - "</messageIds>"\ - "</DeleteMessages>"\ - "</soap:Body>"\ -"</soap:Envelope>" - -/*OIM Send SOAP Template*/ -#define MSN_OIM_MSG_TEMPLATE "MIME-Version: 1.0\n"\ - "Content-Type: text/plain; charset=UTF-8\n"\ - "Content-Transfer-Encoding: base64\n"\ - "X-OIM-Message-Type: OfflineMessage\n"\ - "X-OIM-Run-Id: {%s}\n"\ - "X-OIM-Sequence-Num: %d\n\n" - -#define MSN_OIM_SEND_HOST "ows.messenger.msn.com" -#define MSN_OIM_SEND_URL "/OimWS/oim.asmx" -#define MSN_OIM_SEND_SOAP_ACTION "http://messenger.live.com/ws/2006/09/oim/Store2" -#define MSN_OIM_SEND_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope"\ - " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ - " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ - " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ - "<soap:Header>"\ - "<From"\ - " memberName=\"%s\""\ - " friendlyName=\"%s\""\ - " xml:lang=\"en-US\""\ - " proxy=\"MSNMSGR\""\ - " xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\""\ - " msnpVer=\"MSNP15\""\ - " buildVer=\"8.5.1288\"/>"\ - "<To memberName=\"%s\" xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\"/>"\ - "<Ticket passport=\"EMPTY\" appid=\"%s\" lockkey=\"%s\" xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\"/>"\ - "<Sequence xmlns=\"http://schemas.xmlsoap.org/ws/2003/03/rm\">"\ - "<Identifier xmlns=\"http://schemas.xmlsoap.org/ws/2002/07/utility\">http://messenger.msn.com</Identifier>"\ - "<MessageNumber>%d</MessageNumber>"\ - "</Sequence>"\ - "</soap:Header>"\ - "<soap:Body>"\ - "<MessageType xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\">text</MessageType>"\ - "<Content xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\">%s</Content>"\ - "</soap:Body>"\ -"</soap:Envelope>" - -struct _MsnOim -{ - MsnSession *session; - - GList * oim_list; - - char *challenge; - char *run_id; - gint send_seq; - GQueue *send_queue; -}; - -/**************************************************** - * function prototype - * **************************************************/ -MsnOim * msn_oim_new(MsnSession *session); -void msn_oim_destroy(MsnOim *oim); - -void msn_parse_oim_msg(MsnOim *oim,const char *xmlmsg); - -/*Send OIM Message*/ -void msn_oim_prep_send_msg_info(MsnOim *oim, const char *membername, - const char *friendname, const char *tomember, - const char * msg); - -void msn_oim_send_msg(MsnOim *oim); - -#endif/* MSN_OIM_H*/ diff --git a/libpurple/protocols/msn/p2p.c b/libpurple/protocols/msn/p2p.c deleted file mode 100644 index d39979edb1..0000000000 --- a/libpurple/protocols/msn/p2p.c +++ /dev/null @@ -1,872 +0,0 @@ -/** - * @file p2p.c MSN P2P functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "debug.h" - -#include "p2p.h" -#include "tlv.h" -#include "msnutils.h" - -MsnP2PInfo * -msn_p2p_info_new(MsnP2PVersion version) -{ - MsnP2PInfo *info = g_new0(MsnP2PInfo, 1); - info->version = version; - - switch (version) { - case MSN_P2P_VERSION_ONE: - case MSN_P2P_VERSION_TWO: - /* Nothing to do */ - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", version); - g_free(info); - info = NULL; - } - - return info; -} - -MsnP2PInfo * -msn_p2p_info_dup(MsnP2PInfo *info) -{ - MsnP2PInfo *new_info = g_new0(MsnP2PInfo, 1); - - new_info->version = info->version; - - switch (info->version) { - case MSN_P2P_VERSION_ONE: - *new_info = *info; - break; - - case MSN_P2P_VERSION_TWO: - *new_info = *info; - new_info->header.v2.header_tlv = msn_tlvlist_copy(info->header.v2.header_tlv); - new_info->header.v2.data_tlv = msn_tlvlist_copy(info->header.v2.data_tlv); - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - g_free(new_info); - new_info = NULL; - } - - return new_info; -} - -void -msn_p2p_info_free(MsnP2PInfo *info) -{ - switch (info->version) { - case MSN_P2P_VERSION_ONE: - /* Nothing to do! */ - break; - - case MSN_P2P_VERSION_TWO: - msn_tlvlist_free(info->header.v2.header_tlv); - msn_tlvlist_free(info->header.v2.data_tlv); - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - - g_free(info); -} - -size_t -msn_p2p_header_from_wire(MsnP2PInfo *info, const char *wire, size_t max_len) -{ - size_t len = 0; - - switch (info->version) { - case MSN_P2P_VERSION_ONE: { - MsnP2PHeader *header = &info->header.v1; - - if (max_len < P2P_PACKET_HEADER_SIZE) { - /* Invalid packet length */ - len = 0; - break; - } - - header->session_id = msn_pop32le(wire); - header->id = msn_pop32le(wire); - header->offset = msn_pop64le(wire); - header->total_size = msn_pop64le(wire); - header->length = msn_pop32le(wire); - header->flags = msn_pop32le(wire); - header->ack_id = msn_pop32le(wire); - header->ack_sub_id = msn_pop32le(wire); - header->ack_size = msn_pop64le(wire); - - len = P2P_PACKET_HEADER_SIZE; - break; - } - - case MSN_P2P_VERSION_TWO: { - MsnP2Pv2Header *header = &info->header.v2; - - header->header_len = msn_pop8(wire); - header->opcode = msn_pop8(wire); - header->message_len = msn_pop16be(wire); - header->base_id = msn_pop32be(wire); - if ((gsize)header->header_len + header->message_len + - P2P_PACKET_FOOTER_SIZE > max_len) - { - /* Invalid header and data length */ - len = 0; - break; - } - - if (header->header_len > 8) { - header->header_tlv = msn_tlvlist_read(wire, header->header_len - 8); - wire += header->header_len - 8; - } - - if (header->message_len > 0) { - /* Parse Data packet */ - - header->data_header_len = msn_pop8(wire); - if (header->data_header_len > header->message_len) { - /* Invalid data header length */ - len = 0; - break; - } - header->data_tf = msn_pop8(wire); - header->package_number = msn_pop16be(wire); - header->session_id = msn_pop32be(wire); - - if (header->data_header_len > 8) { - header->data_tlv = msn_tlvlist_read(wire, header->data_header_len - 8); - wire += header->data_header_len - 8; - } - } - - len = header->header_len + header->message_len; - - break; - } - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - - return len; -} - -char * -msn_p2p_header_to_wire(MsnP2PInfo *info, size_t *len) -{ - char *wire = NULL; - char *tmp; - - switch (info->version) { - case MSN_P2P_VERSION_ONE: { - MsnP2PHeader *header = &info->header.v1; - tmp = wire = g_new(char, P2P_PACKET_HEADER_SIZE); - - msn_push32le(tmp, header->session_id); - msn_push32le(tmp, header->id); - msn_push64le(tmp, header->offset); - msn_push64le(tmp, header->total_size); - msn_push32le(tmp, header->length); - msn_push32le(tmp, header->flags); - msn_push32le(tmp, header->ack_id); - msn_push32le(tmp, header->ack_sub_id); - msn_push64le(tmp, header->ack_size); - - if (len) - *len = P2P_PACKET_HEADER_SIZE; - - break; - } - - case MSN_P2P_VERSION_TWO: { - MsnP2Pv2Header *header = &info->header.v2; - char *header_wire = NULL; - char *data_header_wire = NULL; - - if (header->header_tlv != NULL) - header_wire = msn_tlvlist_write(header->header_tlv, &header->header_len); - else - header->header_len = 0; - - if (header->data_tlv != NULL) - data_header_wire = msn_tlvlist_write(header->data_tlv, &header->data_header_len); - else - header->data_header_len = 0; - - tmp = wire = g_new(char, 16 + header->header_len + header->data_header_len); - - msn_push8(tmp, header->header_len + 8); - msn_push8(tmp, header->opcode); - msn_push16be(tmp, header->data_header_len + 8 + header->message_len); - msn_push32be(tmp, header->base_id); - - if (header_wire != NULL) { - memcpy(tmp, header_wire, header->header_len); - tmp += header->header_len; - } - - msn_push8(tmp, header->data_header_len + 8); - msn_push8(tmp, header->data_tf); - msn_push16be(tmp, header->package_number); - msn_push32be(tmp, header->session_id); - - if (data_header_wire != NULL) { - memcpy(tmp, data_header_wire, header->data_header_len); - tmp += header->data_header_len; - } - - if (len) - *len = header->header_len + header->data_header_len + 16; - - break; - } - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - - return wire; -} - -size_t -msn_p2p_footer_from_wire(MsnP2PInfo *info, const char *wire) -{ - MsnP2PFooter *footer; - - footer = &info->footer; - - footer->value = msn_pop32be(wire); - - return P2P_PACKET_FOOTER_SIZE; -} - -char * -msn_p2p_footer_to_wire(MsnP2PInfo *info, size_t *len) -{ - MsnP2PFooter *footer; - char *wire; - char *tmp; - - footer = &info->footer; - tmp = wire = g_new(char, P2P_PACKET_FOOTER_SIZE); - - msn_push32be(tmp, footer->value); - - if (len) - *len = P2P_PACKET_FOOTER_SIZE; - - return wire; -} - -void -msn_p2p_info_to_string(MsnP2PInfo *info, GString *str) -{ - switch (info->version) { - case MSN_P2P_VERSION_ONE: { - MsnP2PHeader *header = &info->header.v1; - g_string_append_printf(str, "Session ID: %u\r\n", header->session_id); - g_string_append_printf(str, "ID: %u\r\n", header->id); - g_string_append_printf(str, "Offset: %" G_GUINT64_FORMAT "\r\n", header->offset); - g_string_append_printf(str, "Total size: %" G_GUINT64_FORMAT "\r\n", header->total_size); - g_string_append_printf(str, "Length: %u\r\n", header->length); - g_string_append_printf(str, "Flags: 0x%x\r\n", header->flags); - g_string_append_printf(str, "ACK ID: %u\r\n", header->ack_id); - g_string_append_printf(str, "SUB ID: %u\r\n", header->ack_sub_id); - g_string_append_printf(str, "ACK Size: %" G_GUINT64_FORMAT "\r\n", header->ack_size); - - break; - } - - case MSN_P2P_VERSION_TWO: - /* Nothing to do! */ - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - - g_string_append_printf(str, "Footer: 0x%08X\r\n", info->footer.value); -} - -gboolean -msn_p2p_msg_is_data(const MsnP2PInfo *info) -{ - gboolean data = FALSE; - - switch (info->version) { - case MSN_P2P_VERSION_ONE: { - guint32 flags = info->header.v1.flags; - data = (flags == P2P_MSN_OBJ_DATA || - flags == (P2P_WLM2009_COMP | P2P_MSN_OBJ_DATA) || - flags == P2P_FILE_DATA); - break; - } - - case MSN_P2P_VERSION_TWO: - data = info->header.v2.message_len > 0; - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - - return data; -} - -gboolean -msn_p2p_info_is_valid(MsnP2PInfo *info) -{ - gboolean valid = FALSE; - - switch (info->version) { - case MSN_P2P_VERSION_ONE: - valid = info->header.v1.total_size >= info->header.v1.length; - break; - - case MSN_P2P_VERSION_TWO: - /* Nothing to do! */ - valid = TRUE; - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - - return valid; -} - -gboolean -msn_p2p_info_is_first(MsnP2PInfo *info) -{ - gboolean first = FALSE; - - switch (info->version) { - case MSN_P2P_VERSION_ONE: - first = info->header.v1.offset == 0; - break; - - case MSN_P2P_VERSION_TWO: - /* Nothing to do! */ - first = info->header.v2.data_tf & TF_FIRST; - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - - return first; -} - -gboolean -msn_p2p_info_is_final(MsnP2PInfo *info) -{ - gboolean final = FALSE; - - switch (info->version) { - case MSN_P2P_VERSION_ONE: - final = info->header.v1.offset + info->header.v1.length >= info->header.v1.total_size; - break; - - case MSN_P2P_VERSION_TWO: - final = msn_tlv_gettlv(info->header.v2.data_tlv, P2P_DATA_TLV_REMAINING, 1) == NULL; - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - - return final; -} - -void -msn_p2p_info_create_ack(MsnP2PInfo *old_info, MsnP2PInfo *new_info) -{ - switch (old_info->version) { - case MSN_P2P_VERSION_ONE: { - MsnP2PHeader *old = &old_info->header.v1; - MsnP2PHeader *new = &new_info->header.v1; - - new->session_id = old->session_id; - new->flags = P2P_ACK; - new->ack_id = old->id; - new->ack_sub_id = old->ack_id; - new->ack_size = old->total_size; - break; - } - - case MSN_P2P_VERSION_TWO: { - MsnP2Pv2Header *old = &old_info->header.v2; - MsnP2Pv2Header *new = &new_info->header.v2; - - msn_tlvlist_add_32(&new->header_tlv, P2P_HEADER_TLV_TYPE_ACK, old->base_id + old->message_len); - new->opcode = P2P_OPCODE_NONE; - - if (old->message_len > 0) { - if (!msn_tlv_gettlv(old->header_tlv, P2P_HEADER_TLV_TYPE_ACK, 1)) { - if (old->opcode & P2P_OPCODE_SYN) { - msn_tlv_t *ack_tlv; - new->opcode |= P2P_OPCODE_RAK; - - ack_tlv = msn_tlv_gettlv(old->header_tlv, P2P_HEADER_TLV_TYPE_PEER_INFO, 1); - if (ack_tlv) { - msn_tlvlist_add_tlv(&new->header_tlv, ack_tlv); - new->opcode |= P2P_OPCODE_SYN; - } - } - } - } - break; - } - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", old_info->version); - } -} - -gboolean -msn_p2p_info_require_ack(MsnP2PInfo *info) -{ - gboolean ret = FALSE; - - switch (info->version) { - case MSN_P2P_VERSION_ONE: { - guint32 flags = msn_p2p_info_get_flags(info); - - ret = flags == P2P_NO_FLAG || flags == P2P_WLM2009_COMP || - msn_p2p_msg_is_data(info); - break; - } - - case MSN_P2P_VERSION_TWO: - ret = (info->header.v2.opcode & P2P_OPCODE_RAK) > 0; - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - - return ret; -} - -gboolean -msn_p2p_info_is_ack(MsnP2PInfo *info) -{ - gboolean ret = FALSE; - - switch (info->version) { - case MSN_P2P_VERSION_ONE: { - ret = msn_p2p_info_get_flags(info) == P2P_ACK; - break; - } - - case MSN_P2P_VERSION_TWO: - ret = msn_tlv_gettlv(info->header.v2.header_tlv, P2P_HEADER_TLV_TYPE_ACK, 1) != NULL; - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - - return ret; -} - -void -msn_p2p_info_init_first(MsnP2PInfo *info, MsnP2PInfo *old_info) -{ - switch (info->version) { - case MSN_P2P_VERSION_ONE: - info->header.v1.session_id = old_info->header.v1.session_id; - info->header.v1.flags = old_info->header.v1.flags; - break; - - case MSN_P2P_VERSION_TWO: - info->header.v2.data_tf = TF_FIRST; - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } -} - -guint32 -msn_p2p_info_get_session_id(MsnP2PInfo *info) -{ - guint32 session_id = 0; - - switch (info->version) { - case MSN_P2P_VERSION_ONE: - session_id = info->header.v1.session_id; - break; - - case MSN_P2P_VERSION_TWO: - session_id = info->header.v2.session_id; - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - - return session_id; -} - -guint32 -msn_p2p_info_get_id(MsnP2PInfo *info) -{ - guint32 id = 0; - - switch (info->version) { - case MSN_P2P_VERSION_ONE: - id = info->header.v1.id; - break; - - case MSN_P2P_VERSION_TWO: - id = info->header.v2.base_id; - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - - return id; -} - -guint64 -msn_p2p_info_get_offset(MsnP2PInfo *info) -{ - guint64 offset = 0; - - switch (info->version) { - case MSN_P2P_VERSION_ONE: - offset = info->header.v1.offset; - break; - - case MSN_P2P_VERSION_TWO: - /* Nothing to do! */ - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - - return offset; -} - -guint64 -msn_p2p_info_get_total_size(MsnP2PInfo *info) -{ - guint64 total_size = 0; - - switch (info->version) { - case MSN_P2P_VERSION_ONE: - total_size = info->header.v1.total_size; - break; - - case MSN_P2P_VERSION_TWO: - /* Nothing to do! */ - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - - return total_size; -} - -guint32 -msn_p2p_info_get_length(MsnP2PInfo *info) -{ - guint32 length = 0; - - switch (info->version) { - case MSN_P2P_VERSION_ONE: - length = info->header.v1.length; - break; - - case MSN_P2P_VERSION_TWO: - /* Nothing to do! */ - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - - return length; -} - -guint32 -msn_p2p_info_get_flags(MsnP2PInfo *info) -{ - guint32 flags = 0; - - switch (info->version) { - case MSN_P2P_VERSION_ONE: - flags = info->header.v1.flags; - break; - - case MSN_P2P_VERSION_TWO: - flags = info->header.v2.data_tf; - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - - return flags; -} - -guint32 -msn_p2p_info_get_ack_id(MsnP2PInfo *info) -{ - guint32 ack_id = 0; - - switch (info->version) { - case MSN_P2P_VERSION_ONE: - ack_id = info->header.v1.ack_id; - break; - - case MSN_P2P_VERSION_TWO: - /* Nothing to do! */ - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - - return ack_id; -} - -guint32 -msn_p2p_info_get_ack_sub_id(MsnP2PInfo *info) -{ - guint32 ack_sub_id = 0; - - switch (info->version) { - case MSN_P2P_VERSION_ONE: - ack_sub_id = info->header.v1.ack_sub_id; - break; - - case MSN_P2P_VERSION_TWO: - /* Nothing to do! */ - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - - return ack_sub_id; -} - -guint64 -msn_p2p_info_get_ack_size(MsnP2PInfo *info) -{ - guint64 ack_size = 0; - - switch (info->version) { - case MSN_P2P_VERSION_ONE: - ack_size = info->header.v1.ack_size; - break; - - case MSN_P2P_VERSION_TWO: - /* Nothing to do! */ - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - - return ack_size; -} - -guint32 -msn_p2p_info_get_app_id(MsnP2PInfo *info) -{ - return info->footer.value; -} - -void -msn_p2p_info_set_session_id(MsnP2PInfo *info, guint32 session_id) -{ - switch (info->version) { - case MSN_P2P_VERSION_ONE: - info->header.v1.session_id = session_id; - break; - - case MSN_P2P_VERSION_TWO: - info->header.v2.session_id = session_id; - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - -} - -void -msn_p2p_info_set_id(MsnP2PInfo *info, guint32 id) -{ - switch (info->version) { - case MSN_P2P_VERSION_ONE: - info->header.v1.id = id; - break; - - case MSN_P2P_VERSION_TWO: - info->header.v2.base_id = id; - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } - -} - -void -msn_p2p_info_set_offset(MsnP2PInfo *info, guint64 offset) -{ - switch (info->version) { - case MSN_P2P_VERSION_ONE: - info->header.v1.offset = offset; - break; - - case MSN_P2P_VERSION_TWO: - /* Nothing to do! */ - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } -} - -void -msn_p2p_info_set_total_size(MsnP2PInfo *info, guint64 total_size) -{ - switch (info->version) { - case MSN_P2P_VERSION_ONE: - info->header.v1.total_size = total_size; - break; - - case MSN_P2P_VERSION_TWO: - /* Nothing to do! */ - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } -} - -void -msn_p2p_info_set_length(MsnP2PInfo *info, guint32 length) -{ - switch (info->version) { - case MSN_P2P_VERSION_ONE: - info->header.v1.length = length; - break; - - case MSN_P2P_VERSION_TWO: - /* Nothing to do! */ - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } -} - -void -msn_p2p_info_set_flags(MsnP2PInfo *info, guint32 flags) -{ - switch (info->version) { - case MSN_P2P_VERSION_ONE: - info->header.v1.flags = flags; - break; - - case MSN_P2P_VERSION_TWO: - info->header.v2.data_tf = flags; - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } -} - -void -msn_p2p_info_set_ack_id(MsnP2PInfo *info, guint32 ack_id) -{ - switch (info->version) { - case MSN_P2P_VERSION_ONE: - info->header.v1.ack_id = ack_id; - break; - - case MSN_P2P_VERSION_TWO: - /* Nothing to do! */ - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } -} - -void -msn_p2p_info_set_ack_sub_id(MsnP2PInfo *info, guint32 ack_sub_id) -{ - switch (info->version) { - case MSN_P2P_VERSION_ONE: - info->header.v1.ack_sub_id = ack_sub_id; - break; - - case MSN_P2P_VERSION_TWO: - /* Nothing to do! */ - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } -} - -void -msn_p2p_info_set_ack_size(MsnP2PInfo *info, guint64 ack_size) -{ - switch (info->version) { - case MSN_P2P_VERSION_ONE: - info->header.v1.ack_size = ack_size; - break; - - case MSN_P2P_VERSION_TWO: - /* Nothing to do! */ - break; - - default: - purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); - } -} - -void -msn_p2p_info_set_app_id(MsnP2PInfo *info, guint32 app_id) -{ - info->footer.value = app_id; -} - diff --git a/libpurple/protocols/msn/p2p.h b/libpurple/protocols/msn/p2p.h deleted file mode 100644 index 89ac239486..0000000000 --- a/libpurple/protocols/msn/p2p.h +++ /dev/null @@ -1,264 +0,0 @@ -/** - * @file p2p.h MSN P2P functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef MSN_P2P_H -#define MSN_P2P_H - -typedef struct { - guint32 session_id; - guint32 id; - /** - * In a MsnSlpMessage: - * For outgoing messages this is the number of bytes from buffer that - * have already been sent out. For incoming messages this is the - * number of bytes that have been written to buffer. - */ - guint64 offset; - guint64 total_size; - guint32 length; - guint32 flags; - guint32 ack_id; - guint32 ack_sub_id; - guint64 ack_size; -/* guint8 body[1]; */ -} MsnP2PHeader; -#define P2P_PACKET_HEADER_SIZE (6 * 4 + 3 * 8) - -typedef struct { - guint8 header_len; - guint8 opcode; - guint16 message_len; - guint32 base_id; - GSList *header_tlv; - guint8 data_header_len; - guint8 data_tf; - guint16 package_number; - guint32 session_id; - GSList *data_tlv; -/* guint8 body[1]; */ -} MsnP2Pv2Header; - -typedef struct { - guint16 protocol_version; - guint16 implementation_id; - guint16 version; - guint16 reserved; - guint32 caps; -} P2PPeerInfo; - -typedef enum -{ - TF_FIRST = 0x01, /**< The first package. */ - TF_MSNOBJ = 0x04, /**< Payload contains binary data for MsnObject. */ - TF_FILE = 0x06 /**< Payload contains binary data. */ -} TF; - -typedef enum -{ - P2P_HEADER_TLV_TYPE_PEER_INFO = 0x01, /**< Client peer info */ - P2P_HEADER_TLV_TYPE_ACK = 0x02, /**< ACK */ - P2P_HEADER_TLV_TYPE_NAK = 0x03 /**< NAK */ -} P2PHeaderTLVType; - -typedef enum -{ - P2P_DATA_TLV_REMAINING = 0x01, /**< Indicates the remaining data to transfer.*/ -} P2PDataTLVType; - -typedef enum -{ - P2P_PI_PVER = 0x0200, - P2P_PI_IMP_ID = 0, - P2P_PI_VER = 0x0e00, - P2P_PI_RES = 0, - P2P_PI_CAPS = 0x0000010f -} P2PPeerInfoVal; - -typedef struct -{ - guint32 value; -} MsnP2PFooter; -#define P2P_PACKET_FOOTER_SIZE (1 * 4) - -typedef enum -{ - MSN_P2P_VERSION_ONE = 0, - MSN_P2P_VERSION_TWO = 1, -} MsnP2PVersion; - -typedef struct { - MsnP2PVersion version; - union { - MsnP2PHeader v1; - MsnP2Pv2Header v2; - } header; - MsnP2PFooter footer; -} MsnP2PInfo; - -typedef enum -{ - P2P_NO_FLAG = 0x0, /**< No flags specified */ - P2P_OUT_OF_ORDER = 0x1, /**< Chunk out-of-order */ - P2P_ACK = 0x2, /**< Acknowledgement */ - P2P_PENDING_INVITE = 0x4, /**< There is a pending invite */ - P2P_BINARY_ERROR = 0x8, /**< Error on the binary level */ - P2P_FILE = 0x10, /**< File */ - P2P_MSN_OBJ_DATA = 0x20, /**< MsnObject data */ - P2P_CLOSE = 0x40, /**< Close session */ - P2P_TLP_ERROR = 0x80, /**< Error at transport layer protocol */ - P2P_DC_HANDSHAKE = 0x100, /**< Direct Handshake */ - P2P_WLM2009_COMP = 0x1000000, /**< Compatibility with WLM 2009 */ - P2P_FILE_DATA = 0x1000030 /**< File transfer data */ -} MsnP2PHeaderFlag; -/* Info From: - * http://msnpiki.msnfanatic.com/index.php/MSNC:P2Pv1_Headers#Flags - * http://trac.kmess.org/changeset/ba04d0c825769d23370511031c47f6be75fe9b86 - * #7180 - */ - -typedef enum -{ - P2P_APPID_SESSION = 0x0, /**< Negotiating session */ - P2P_APPID_OBJ = 0x1, /**< MsnObject (Display or Emoticon) */ - P2P_APPID_FILE = 0x2, /**< File transfer */ - P2P_APPID_EMOTE = 0xB, /**< CustomEmoticon */ - P2P_APPID_DISPLAY = 0xC /**< Display Image */ -} MsnP2PAppId; - -typedef enum -{ - P2P_OPCODE_NONE = 0x00, - P2P_OPCODE_SYN = 0x01, - P2P_OPCODE_RAK = 0x02 -} MsnP2Pv2OpCode; - -MsnP2PInfo * -msn_p2p_info_new(MsnP2PVersion version); - -MsnP2PInfo * -msn_p2p_info_dup(MsnP2PInfo *info); - -void -msn_p2p_info_free(MsnP2PInfo *info); - -size_t -msn_p2p_header_from_wire(MsnP2PInfo *info, const char *wire, size_t max_len); - -char * -msn_p2p_header_to_wire(MsnP2PInfo *info, size_t *len); - -size_t -msn_p2p_footer_from_wire(MsnP2PInfo *info, const char *wire); - -char * -msn_p2p_footer_to_wire(MsnP2PInfo *info, size_t *len); - -void -msn_p2p_info_to_string(MsnP2PInfo *info, GString *str); - -gboolean -msn_p2p_msg_is_data(const MsnP2PInfo *info); - -gboolean -msn_p2p_info_is_valid(MsnP2PInfo *info); - -gboolean -msn_p2p_info_is_first(MsnP2PInfo *info); - -gboolean -msn_p2p_info_is_final(MsnP2PInfo *info); - -void -msn_p2p_info_create_ack(MsnP2PInfo *old_info, MsnP2PInfo *new_info); - -gboolean -msn_p2p_info_require_ack(MsnP2PInfo *info); - -gboolean -msn_p2p_info_is_ack(MsnP2PInfo *info); - -void -msn_p2p_info_init_first(MsnP2PInfo *new_info, MsnP2PInfo *old_info); - -guint32 -msn_p2p_info_get_session_id(MsnP2PInfo *info); - -guint32 -msn_p2p_info_get_id(MsnP2PInfo *info); - -guint64 -msn_p2p_info_get_offset(MsnP2PInfo *info); - -guint64 -msn_p2p_info_get_total_size(MsnP2PInfo *info); - -guint32 -msn_p2p_info_get_length(MsnP2PInfo *info); - -guint32 -msn_p2p_info_get_flags(MsnP2PInfo *info); - -guint32 -msn_p2p_info_get_ack_id(MsnP2PInfo *info); - -guint32 -msn_p2p_info_get_ack_sub_id(MsnP2PInfo *info); - -guint64 -msn_p2p_info_get_ack_size(MsnP2PInfo *info); - -guint32 -msn_p2p_info_get_app_id(MsnP2PInfo *info); - -void -msn_p2p_info_set_session_id(MsnP2PInfo *info, guint32 session_id); - -void -msn_p2p_info_set_id(MsnP2PInfo *info, guint32 id); - -void -msn_p2p_info_set_offset(MsnP2PInfo *info, guint64 offset); - -void -msn_p2p_info_set_total_size(MsnP2PInfo *info, guint64 total_size); - -void -msn_p2p_info_set_length(MsnP2PInfo *info, guint32 length); - -void -msn_p2p_info_set_flags(MsnP2PInfo *info, guint32 flags); - -void -msn_p2p_info_set_ack_id(MsnP2PInfo *info, guint32 ack_id); - -void -msn_p2p_info_set_ack_sub_id(MsnP2PInfo *info, guint32 ack_sub_id); - -void -msn_p2p_info_set_ack_size(MsnP2PInfo *info, guint64 ack_size); - -void -msn_p2p_info_set_app_id(MsnP2PInfo *info, guint32 app_id); - -#endif /* MSN_P2P_H */ diff --git a/libpurple/protocols/msn/page.c b/libpurple/protocols/msn/page.c deleted file mode 100644 index a357af4da7..0000000000 --- a/libpurple/protocols/msn/page.c +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @file page.c Paging functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#include "msn.h" -#include "page.h" - -MsnPage * -msn_page_new(void) -{ - MsnPage *page; - - page = g_new0(MsnPage, 1); - - return page; -} - -void -msn_page_destroy(MsnPage *page) -{ - g_return_if_fail(page != NULL); - - g_free(page->body); - g_free(page->from_location); - g_free(page->from_phone); - - g_free(page); -} - -char * -msn_page_gen_payload(const MsnPage *page, size_t *ret_size) -{ - char *str; - char *body; - - g_return_val_if_fail(page != NULL, NULL); - - body = g_markup_escape_text(msn_page_get_body(page), -1); - str = g_strdup_printf( - "<TEXT xml:space=\"preserve\" enc=\"utf-8\">%s</TEXT>", - body); - g_free(body); - - if (ret_size != NULL) - *ret_size = strlen(str); - - return str; -} - -void -msn_page_set_body(MsnPage *page, const char *body) -{ - g_return_if_fail(page != NULL); - g_return_if_fail(body != NULL); - - g_free(page->body); - page->body = g_strdup(body); -} - -const char * -msn_page_get_body(const MsnPage *page) -{ - g_return_val_if_fail(page != NULL, NULL); - - return page->body; -} diff --git a/libpurple/protocols/msn/page.h b/libpurple/protocols/msn/page.h deleted file mode 100644 index 4fb89f5380..0000000000 --- a/libpurple/protocols/msn/page.h +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @file page.h Paging functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_PAGE_H -#define MSN_PAGE_H - -typedef struct _MsnPage MsnPage; - -#include "session.h" - -/** - * A page. - */ -struct _MsnPage -{ - char *from_location; - char *from_phone; - - char *body; -}; - -/** - * Creates a new, empty page. - * - * @return A new page. - */ -MsnPage *msn_page_new(void); - -/** - * Destroys a page. - */ -void msn_page_destroy(MsnPage *page); - -/** - * Generates the payload data of a page. - * - * @param page The page. - * @param ret_size The returned size of the payload. - * - * @return The payload data of a page. - */ -char *msn_page_gen_payload(const MsnPage *page, size_t *ret_size); - -/** - * Sets the body of a page. - * - * @param page The page. - * @param body The body of the page. - */ -void msn_page_set_body(MsnPage *page, const char *body); - -/** - * Returns the body of the page. - * - * @param page The page. - * - * @return The body of the page. - */ -const char *msn_page_get_body(const MsnPage *page); - -#endif /* MSN_PAGE_H */ diff --git a/libpurple/protocols/msn/sbconn.c b/libpurple/protocols/msn/sbconn.c deleted file mode 100644 index a9a6288844..0000000000 --- a/libpurple/protocols/msn/sbconn.c +++ /dev/null @@ -1,174 +0,0 @@ -/** - * @file sbconn.c MSN Switchboard Connection - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "debug.h" - -#include "msg.h" -#include "sbconn.h" - -void msn_sbconn_send_part(MsnSlpLink *slplink, MsnSlpMessagePart *part) -{ - MsnMessage *msg; - const char *passport; - char *data; - size_t size; - - msg = msn_message_new_msnslp(); - - passport = purple_normalize(slplink->session->account, slplink->remote_user); - msn_message_set_header(msg, "P2P-Dest", passport); - - msg->part = msn_slpmsgpart_ref(part); - data = msn_slpmsgpart_serialize(part, &size); - msn_message_set_bin_data(msg, data, size); - g_free(data); - - if (slplink->swboard == NULL) - { - slplink->swboard = msn_session_get_swboard(slplink->session, - slplink->remote_user, MSN_SB_FLAG_FT); - - g_return_if_fail(slplink->swboard != NULL); - - /* If swboard is destroyed we will be too */ - slplink->swboard->slplinks = g_list_prepend(slplink->swboard->slplinks, slplink); - } - - msn_switchboard_send_msg(slplink->swboard, msg, TRUE); - msn_message_unref(msg); -} - -/** 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); -} - -static void -release_msg(MsnSwitchBoard *swboard, MsnMessage *msg) -{ - MsnCmdProc *cmdproc; - MsnTransaction *trans; - char *payload; - gsize payload_len; - char flag; - - g_return_if_fail(swboard != NULL); - g_return_if_fail(msg != NULL); - - cmdproc = swboard->cmdproc; - - payload = msn_message_gen_payload(msg, &payload_len); - - if (purple_debug_is_verbose()) { - purple_debug_info("msn", "SB length:{%" G_GSIZE_FORMAT "}\n", payload_len); - msn_message_show_readable(msg, "SB SEND", FALSE); - } - - flag = msn_message_get_flag(msg); - trans = msn_transaction_new(cmdproc, "MSG", "%c %" G_GSIZE_FORMAT, - flag, payload_len); - - /* Data for callbacks */ - msn_transaction_set_data(trans, msg); - - if (flag != 'U') { - 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; - - 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); - - purple_debug_info("msn", "Appending message to queue.\n"); - - g_queue_push_tail(swboard->msg_queue, msg); - - msn_message_ref(msg); -} - -void -msn_sbconn_process_queue(MsnSwitchBoard *swboard) -{ - MsnMessage *msg; - - g_return_if_fail(swboard != NULL); - - purple_debug_info("msn", "Processing queue\n"); - - while ((msg = g_queue_pop_head(swboard->msg_queue)) != NULL) - { - purple_debug_info("msn", "Sending message\n"); - release_msg(swboard, msg); - msn_message_unref(msg); - } -} - -void -msn_switchboard_send_msg(MsnSwitchBoard *swboard, MsnMessage *msg, - gboolean queue) -{ - g_return_if_fail(swboard != NULL); - g_return_if_fail(msg != NULL); - - purple_debug_info("msn", "switchboard send msg..\n"); - if (msn_switchboard_can_send(swboard)) - release_msg(swboard, msg); - else if (queue) - queue_msg(swboard, msg); -} diff --git a/libpurple/protocols/msn/sbconn.h b/libpurple/protocols/msn/sbconn.h deleted file mode 100644 index 3b59172ef5..0000000000 --- a/libpurple/protocols/msn/sbconn.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @file sbconn.h MSN Switchboard Connection - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef MSN_SBCONN_H -#define MSN_SBCONN_H - -#include "msg.h" -#include "slplink.h" - -#define MSN_SBCONN_MAX_SIZE 1202 - -void msn_sbconn_send_part(MsnSlpLink *slplink, MsnSlpMessagePart *part); - -void msn_switchboard_send_msg(MsnSwitchBoard *swboard, MsnMessage *msg, - gboolean queue); - -void -msn_sbconn_process_queue(MsnSwitchBoard *swboard); - -#endif /* MSN_SBCONN_H */ diff --git a/libpurple/protocols/msn/servconn.c b/libpurple/protocols/msn/servconn.c deleted file mode 100644 index 2d8ea83587..0000000000 --- a/libpurple/protocols/msn/servconn.c +++ /dev/null @@ -1,608 +0,0 @@ -/** - * @file servconn.c Server connection functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#include "internal.h" -#include "debug.h" - -#include "servconn.h" -#include "error.h" - -static void read_cb(gpointer data, gint source, PurpleInputCondition cond); -static void servconn_timeout_renew(MsnServConn *servconn); - -/************************************************************************** - * Main - **************************************************************************/ - -MsnServConn * -msn_servconn_new(MsnSession *session, MsnServConnType type) -{ - MsnServConn *servconn; - - g_return_val_if_fail(session != NULL, NULL); - - servconn = g_new0(MsnServConn, 1); - - servconn->type = type; - - servconn->session = session; - servconn->cmdproc = msn_cmdproc_new(session); - servconn->cmdproc->servconn = servconn; - - servconn->httpconn = msn_httpconn_new(servconn); - - servconn->num = session->servconns_count++; - - servconn->tx_buf = purple_circ_buffer_new(MSN_BUF_LEN); - servconn->tx_handler = 0; - servconn->timeout_sec = 0; - servconn->timeout_handle = 0; - - servconn->fd = -1; - - return servconn; -} - -void -msn_servconn_destroy(MsnServConn *servconn) -{ - g_return_if_fail(servconn != NULL); - - if (servconn->processing) - { - servconn->wasted = TRUE; - return; - } - - msn_servconn_disconnect(servconn); - - if (servconn->destroy_cb) - servconn->destroy_cb(servconn); - - if (servconn->httpconn != NULL) - msn_httpconn_destroy(servconn->httpconn); - - g_free(servconn->host); - - purple_circ_buffer_destroy(servconn->tx_buf); - if (servconn->tx_handler > 0) - purple_input_remove(servconn->tx_handler); - if (servconn->timeout_handle > 0) - purple_timeout_remove(servconn->timeout_handle); - - msn_cmdproc_destroy(servconn->cmdproc); - g_free(servconn); -} - -void -msn_servconn_set_connect_cb(MsnServConn *servconn, - void (*connect_cb)(MsnServConn *)) -{ - g_return_if_fail(servconn != NULL); - servconn->connect_cb = connect_cb; -} - -void -msn_servconn_set_disconnect_cb(MsnServConn *servconn, - void (*disconnect_cb)(MsnServConn *)) -{ - g_return_if_fail(servconn != NULL); - - servconn->disconnect_cb = disconnect_cb; -} - -void -msn_servconn_set_destroy_cb(MsnServConn *servconn, - void (*destroy_cb)(MsnServConn *)) -{ - g_return_if_fail(servconn != NULL); - - servconn->destroy_cb = destroy_cb; -} - -/************************************************************************** - * Utility - **************************************************************************/ - -void -msn_servconn_got_error(MsnServConn *servconn, MsnServConnError error, - const char *reason) -{ - MsnSession *session = servconn->session; - MsnServConnType type = servconn->type; - - const char *names[] = { "Notification", "Switchboard" }; - const char *name; - - name = names[type]; - - if (reason == NULL) { - switch (error) - { - case MSN_SERVCONN_ERROR_CONNECT: - reason = _("Unable to connect"); break; - case MSN_SERVCONN_ERROR_WRITE: - reason = _("Writing error"); break; - case MSN_SERVCONN_ERROR_READ: - reason = _("Reading error"); break; - default: - reason = _("Unknown error"); break; - } - } - - purple_debug_error("msn", "Connection error from %s server (%s): %s\n", - name, servconn->host, reason); - - if (type == MSN_SERVCONN_SB) - { - MsnSwitchBoard *swboard; - swboard = servconn->cmdproc->data; - if (swboard != NULL) - swboard->error = MSN_SB_ERROR_CONNECTION; - } - - /* servconn->disconnect_cb may destroy servconn, so don't use it again */ - msn_servconn_disconnect(servconn); - - if (type == MSN_SERVCONN_NS) - { - char *tmp = g_strdup_printf(_("Connection error from %s server:\n%s"), - name, reason); - msn_session_set_error(session, MSN_ERROR_SERVCONN, tmp); - g_free(tmp); - } -} - -/************************************************************************** - * Connect - **************************************************************************/ - -static void -connect_cb(gpointer data, gint source, const char *error_message) -{ - MsnServConn *servconn; - - servconn = data; - servconn->connect_data = NULL; - - servconn->fd = source; - - if (source >= 0) - { - servconn->connected = TRUE; - - /* Someone wants to know we connected. */ - servconn->connect_cb(servconn); - servconn->inpa = purple_input_add(servconn->fd, PURPLE_INPUT_READ, - read_cb, data); - servconn_timeout_renew(servconn); - } - else - { - purple_debug_error("msn", "Connection error: %s\n", error_message); - msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_CONNECT, error_message); - } -} - -gboolean -msn_servconn_connect(MsnServConn *servconn, const char *host, int port, gboolean force) -{ - MsnSession *session; - - g_return_val_if_fail(servconn != NULL, FALSE); - g_return_val_if_fail(host != NULL, FALSE); - g_return_val_if_fail(port > 0, FALSE); - - session = servconn->session; - - if (servconn->connected) - msn_servconn_disconnect(servconn); - - g_free(servconn->host); - servconn->host = g_strdup(host); - - if (session->http_method) - { - /* HTTP Connection. */ - - if (!servconn->httpconn->connected || force) - if (!msn_httpconn_connect(servconn->httpconn, host, port)) - return FALSE; - - servconn->connected = TRUE; - servconn->httpconn->virgin = TRUE; - servconn_timeout_renew(servconn); - - /* Someone wants to know we connected. */ - servconn->connect_cb(servconn); - - return TRUE; - } - - servconn->connect_data = purple_proxy_connect(NULL, session->account, - host, port, connect_cb, servconn); - - return (servconn->connect_data != NULL); -} - -void -msn_servconn_disconnect(MsnServConn *servconn) -{ - g_return_if_fail(servconn != NULL); - - if (servconn->connect_data != NULL) - { - purple_proxy_connect_cancel(servconn->connect_data); - servconn->connect_data = NULL; - } - - if (!servconn->connected) - { - /* We could not connect. */ - if (servconn->disconnect_cb != NULL) - servconn->disconnect_cb(servconn); - - return; - } - - if (servconn->session->http_method) - { - /* Fake disconnection. */ - if (servconn->disconnect_cb != NULL) - servconn->disconnect_cb(servconn); - - return; - } - - if (servconn->inpa > 0) - { - purple_input_remove(servconn->inpa); - servconn->inpa = 0; - } - - if (servconn->timeout_handle > 0) - { - purple_timeout_remove(servconn->timeout_handle); - servconn->timeout_handle = 0; - } - - close(servconn->fd); - - servconn->rx_buf = NULL; - servconn->rx_len = 0; - servconn->payload_len = 0; - - servconn->connected = FALSE; - - if (servconn->disconnect_cb != NULL) - servconn->disconnect_cb(servconn); -} - -static gboolean -servconn_idle_timeout_cb(MsnServConn *servconn) -{ - servconn->timeout_handle = 0; - msn_servconn_disconnect(servconn); - return FALSE; -} - -static void -servconn_timeout_renew(MsnServConn *servconn) -{ - if (servconn->timeout_handle) { - purple_timeout_remove(servconn->timeout_handle); - servconn->timeout_handle = 0; - } - - if (servconn->connected && servconn->timeout_sec) { - servconn->timeout_handle = purple_timeout_add_seconds( - servconn->timeout_sec, (GSourceFunc)servconn_idle_timeout_cb, servconn); - } -} - -void -msn_servconn_set_idle_timeout(MsnServConn *servconn, guint seconds) -{ - servconn->timeout_sec = seconds; - if (servconn->connected) - servconn_timeout_renew(servconn); -} - -static void -servconn_write_cb(gpointer data, gint source, PurpleInputCondition cond) -{ - MsnServConn *servconn = data; - gssize ret; - int writelen; - - writelen = purple_circ_buffer_get_max_read(servconn->tx_buf); - - if (writelen == 0) { - purple_input_remove(servconn->tx_handler); - servconn->tx_handler = 0; - return; - } - - ret = write(servconn->fd, servconn->tx_buf->outptr, writelen); - - if (ret < 0 && errno == EAGAIN) - return; - else if (ret <= 0) { - msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_WRITE, NULL); - return; - } - - purple_circ_buffer_mark_read(servconn->tx_buf, ret); - servconn_timeout_renew(servconn); -} - -gssize -msn_servconn_write(MsnServConn *servconn, const char *buf, size_t len) -{ - gssize ret = 0; - - g_return_val_if_fail(servconn != NULL, 0); - - if (!servconn->session->http_method) - { - if (servconn->tx_handler == 0) { - switch (servconn->type) - { - case MSN_SERVCONN_NS: - case MSN_SERVCONN_SB: - ret = write(servconn->fd, buf, len); - break; -#if 0 - case MSN_SERVCONN_DC: - ret = write(servconn->fd, &buf, sizeof(len)); - ret = write(servconn->fd, buf, len); - break; -#endif - default: - ret = write(servconn->fd, buf, len); - break; - } - } else { - ret = -1; - errno = EAGAIN; - } - - if (ret < 0 && errno == EAGAIN) - ret = 0; - if (ret >= 0 && (size_t)ret < len) { - if (servconn->tx_handler == 0) - servconn->tx_handler = purple_input_add( - servconn->fd, PURPLE_INPUT_WRITE, - servconn_write_cb, servconn); - purple_circ_buffer_append(servconn->tx_buf, buf + ret, - len - ret); - } - } - else - { - ret = msn_httpconn_write(servconn->httpconn, buf, len); - } - - if (ret == -1) - { - msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_WRITE, NULL); - } - - servconn_timeout_renew(servconn); - return ret; -} - -static void -read_cb(gpointer data, gint source, PurpleInputCondition cond) -{ - MsnServConn *servconn; - char buf[MSN_BUF_LEN]; - gssize len; - - servconn = data; - - if (servconn->type == MSN_SERVCONN_NS) - servconn->session->account->gc->last_received = time(NULL); - - len = read(servconn->fd, buf, sizeof(buf) - 1); - if (len < 0 && errno == EAGAIN) - return; - if (len <= 0) { - purple_debug_error("msn", "servconn %03d read error, " - "len: %" G_GSSIZE_FORMAT ", errno: %d, error: %s\n", - servconn->num, len, errno, g_strerror(errno)); - msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_READ, NULL); - - return; - } - - buf[len] = '\0'; - - servconn->rx_buf = g_realloc(servconn->rx_buf, len + servconn->rx_len + 1); - memcpy(servconn->rx_buf + servconn->rx_len, buf, len + 1); - servconn->rx_len += len; - - servconn = msn_servconn_process_data(servconn); - if (servconn) - servconn_timeout_renew(servconn); -} - -MsnServConn *msn_servconn_process_data(MsnServConn *servconn) -{ - char *cur, *end, *old_rx_buf; - int cur_len; - - end = old_rx_buf = servconn->rx_buf; - - servconn->processing = TRUE; - - do - { - cur = end; - - if (servconn->payload_len) - { - if (servconn->rx_len < 0 - || servconn->payload_len > (gsize)servconn->rx_len) - /* The payload is still not complete. */ - break; - - cur_len = servconn->payload_len; - end += cur_len; - } - else - { - end = strstr(cur, "\r\n"); - - if (end == NULL) - /* The command is still not complete. */ - break; - - *end = '\0'; - end += 2; - cur_len = end - cur; - } - - servconn->rx_len -= cur_len; - - if (servconn->payload_len) - { - msn_cmdproc_process_payload(servconn->cmdproc, cur, cur_len); - servconn->payload_len = 0; - } - else - { - msn_cmdproc_process_cmd_text(servconn->cmdproc, cur); - servconn->payload_len = servconn->cmdproc->last_cmd->payload_len; - } - } while (servconn->connected && !servconn->wasted && servconn->rx_len > 0); - - if (servconn->connected && !servconn->wasted) - { - if (servconn->rx_len > 0) - servconn->rx_buf = g_memdup(cur, servconn->rx_len); - else - servconn->rx_buf = NULL; - } - - servconn->processing = FALSE; - - if (servconn->wasted) { - msn_servconn_destroy(servconn); - servconn = NULL; - } - - g_free(old_rx_buf); - return servconn; -} - -#if 0 -static int -create_listener(int port) -{ - int fd; - int flags; - const int on = 1; - -#if 0 - struct addrinfo hints; - struct addrinfo *c, *res; - char port_str[5]; - - snprintf(port_str, sizeof(port_str), "%d", port); - - memset(&hints, 0, sizeof(hints)); - - hints.ai_flags = AI_PASSIVE; - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - - if (getaddrinfo(NULL, port_str, &hints, &res) != 0) - { - purple_debug_error("msn", "Could not get address info: %s.\n", - port_str); - return -1; - } - - for (c = res; c != NULL; c = c->ai_next) - { - fd = socket(c->ai_family, c->ai_socktype, c->ai_protocol); - - if (fd < 0) - continue; - - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - - if (bind(fd, c->ai_addr, c->ai_addrlen) == 0) - break; - - close(fd); - } - - if (c == NULL) - { - purple_debug_error("msn", "Could not find socket: %s.\n", port_str); - return -1; - } - - freeaddrinfo(res); -#else - struct sockaddr_in sockin; - - fd = socket(AF_INET, SOCK_STREAM, 0); - - if (fd < 0) - return -1; - - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0) - { - close(fd); - return -1; - } - - memset(&sockin, 0, sizeof(struct sockaddr_in)); - sockin.sin_family = AF_INET; - sockin.sin_port = htons(port); - - if (bind(fd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) - { - close(fd); - return -1; - } -#endif - - if (listen (fd, 4) != 0) - { - close (fd); - return -1; - } - - flags = fcntl(fd, F_GETFL); - fcntl(fd, F_SETFL, flags | O_NONBLOCK); -#ifndef _WIN32 - fcntl(fd, F_SETFD, FD_CLOEXEC); -#endif - - return fd; -} -#endif diff --git a/libpurple/protocols/msn/servconn.h b/libpurple/protocols/msn/servconn.h deleted file mode 100644 index b075fd08f2..0000000000 --- a/libpurple/protocols/msn/servconn.h +++ /dev/null @@ -1,193 +0,0 @@ -/** - * @file servconn.h Server connection functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_SERVCONN_H -#define MSN_SERVCONN_H - -typedef struct _MsnServConn MsnServConn; - -/** - * Connection error types. - */ -typedef enum -{ - MSN_SERVCONN_ERROR_NONE, - MSN_SERVCONN_ERROR_CONNECT, - MSN_SERVCONN_ERROR_WRITE, - MSN_SERVCONN_ERROR_READ -} MsnServConnError; - -/** - * Connection types. - */ -typedef enum -{ - MSN_SERVCONN_NS, - MSN_SERVCONN_SB -} MsnServConnType; - -#include "internal.h" -#include "proxy.h" - -#include "cmdproc.h" -#include "httpconn.h" -#include "session.h" - -/** - * A Connection. - */ -struct _MsnServConn -{ - MsnServConnType type; /**< The type of this connection. */ - MsnSession *session; /**< The MSN session of this connection. */ - MsnCmdProc *cmdproc; /**< The command processor of this connection. */ - - PurpleProxyConnectData *connect_data; - - gboolean connected; /**< A flag that states if it's connected. */ - gboolean processing; /**< A flag that states if something is working - with this connection. */ - gboolean wasted; /**< A flag that states if it should be destroyed. */ - - char *host; /**< The host this connection is connected or should be - connected to. */ - int num; /**< A number id of this connection. */ - - MsnHttpConn *httpconn; /**< The HTTP connection this connection should use. */ - - int fd; /**< The connection's file descriptor. */ - int inpa; /**< The connection's input handler. */ - - char *rx_buf; /**< The receive buffer. */ - int rx_len; /**< The receive buffer lenght. */ - - size_t payload_len; /**< The length of the payload. - It's only set when we've received a command that - has a payload. */ - - PurpleCircBuffer *tx_buf; - guint tx_handler; - guint timeout_sec; - guint timeout_handle; - - void (*connect_cb)(MsnServConn *); /**< The callback to call when connecting. */ - void (*disconnect_cb)(MsnServConn *); /**< The callback to call when disconnecting. */ - void (*destroy_cb)(MsnServConn *); /**< The callback to call when destroying. */ -}; - -/** - * Creates a new connection object. - * - * @param session The session. - * @param type The type of the connection. - */ -MsnServConn *msn_servconn_new(MsnSession *session, MsnServConnType type); - -/** - * Destroys a connection object. - * - * @param servconn The connection. - */ -void msn_servconn_destroy(MsnServConn *servconn); - -/** - * Connects to a host. - * - * @param servconn The connection. - * @param host The host. - * @param port The port. - * @param force Force this servconn to connect to a new server. - */ -gboolean msn_servconn_connect(MsnServConn *servconn, const char *host, int port, - gboolean force); - -/** - * Disconnects. - * - * @param servconn The connection. - */ -void msn_servconn_disconnect(MsnServConn *servconn); - -/** - * Sets the connect callback. - * - * @param servconn The servconn. - * @param connect_cb The connect callback. - */ -void msn_servconn_set_connect_cb(MsnServConn *servconn, - void (*connect_cb)(MsnServConn *)); -/** - * Sets the disconnect callback. - * - * @param servconn The servconn. - * @param disconnect_cb The disconnect callback. - */ -void msn_servconn_set_disconnect_cb(MsnServConn *servconn, - void (*disconnect_cb)(MsnServConn *)); -/** - * Sets the destroy callback. - * - * @param servconn The servconn that's being destroyed. - * @param destroy_cb The destroy callback. - */ -void msn_servconn_set_destroy_cb(MsnServConn *servconn, - void (*destroy_cb)(MsnServConn *)); - -/** - * Writes a chunck of data to the servconn. - * - * @param servconn The servconn. - * @param buf The data to write. - * @param size The size of the data. - */ -gssize msn_servconn_write(MsnServConn *servconn, const char *buf, - size_t size); - -/** - * Function to call whenever an error related to a switchboard occurs. - * - * @param servconn The servconn. - * @param error The error that happened. - */ -void msn_servconn_got_error(MsnServConn *servconn, MsnServConnError error, - const char *reason); - -/** - * Process the data in servconn->rx_buf. This is called after reading - * data from the socket. - * - * @param servconn The servconn. - * - * @return @c NULL if servconn was destroyed, 'servconn' otherwise. - */ -MsnServConn *msn_servconn_process_data(MsnServConn *servconn); - -/** - * Set a idle timeout fot this servconn - * - * @param servconn The servconn - * @param seconds The idle timeout in seconds - */ -void msn_servconn_set_idle_timeout(MsnServConn *servconn, guint seconds); - -#endif /* MSN_SERVCONN_H */ diff --git a/libpurple/protocols/msn/session.c b/libpurple/protocols/msn/session.c deleted file mode 100644 index 371800ad89..0000000000 --- a/libpurple/protocols/msn/session.c +++ /dev/null @@ -1,500 +0,0 @@ -/** - * @file session.c MSN session functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "debug.h" - -#include "error.h" -#include "msnutils.h" -#include "session.h" -#include "notification.h" -#include "oim.h" - -MsnSession * -msn_session_new(PurpleAccount *account) -{ - MsnSession *session; - - g_return_val_if_fail(account != NULL, NULL); - - session = g_new0(MsnSession, 1); - - session->account = account; - session->notification = msn_notification_new(session); - session->userlist = msn_userlist_new(session); - - session->user = msn_user_new(session->userlist, - purple_account_get_username(account), NULL); - msn_userlist_add_user(session->userlist, session->user); - session->oim = msn_oim_new(session); - - session->protocol_ver = 0; - session->enable_mpop = TRUE; /* Default only */ - - session->guid = rand_guid(); - - return session; -} - -void -msn_session_destroy(MsnSession *session) -{ - g_return_if_fail(session != NULL); - - session->destroying = TRUE; - - while (session->url_datas) { - purple_util_fetch_url_cancel(session->url_datas->data); - session->url_datas = g_slist_delete_link(session->url_datas, session->url_datas); - } - - if (session->connected) - msn_session_disconnect(session); - - if (session->soap_cleanup_handle) - purple_timeout_remove(session->soap_cleanup_handle); - - if (session->soap_table != NULL) - g_hash_table_destroy(session->soap_table); - - while (session->slplinks != NULL) - msn_slplink_unref(session->slplinks->data); - - while (session->switches != NULL) - msn_switchboard_destroy(session->switches->data); - - if (session->oim != NULL) - msn_oim_destroy(session->oim); - - if (session->nexus != NULL) - msn_nexus_destroy(session->nexus); - - if (session->user != NULL) - msn_user_unref(session->user); - - if (session->notification != NULL) - msn_notification_destroy(session->notification); - - msn_userlist_destroy(session->userlist); - - g_free(session->psm); - g_free(session->guid); - g_free(session->abch_cachekey); -#if 0 - g_free(session->blocked_text); -#endif - - g_free(session->passport_info.sid); - g_free(session->passport_info.mspauth); - g_free(session->passport_info.client_ip); - g_free(session->passport_info.mail_url); - - g_free(session); -} - -gboolean -msn_session_connect(MsnSession *session, const char *host, int port, - gboolean http_method) -{ - g_return_val_if_fail(session != NULL, FALSE); - g_return_val_if_fail(!session->connected, TRUE); - - session->connected = TRUE; - session->http_method = http_method; - - if (session->notification == NULL) - { - purple_debug_error("msn", "This shouldn't happen\n"); - g_return_val_if_reached(FALSE); - } - - return msn_notification_connect(session->notification, host, port); -} - -void -msn_session_disconnect(MsnSession *session) -{ - g_return_if_fail(session != NULL); - - if (!session->connected) - return; - - if (session->login_timeout) { - purple_timeout_remove(session->login_timeout); - session->login_timeout = 0; - } - - session->connected = FALSE; - - while (session->switches != NULL) - msn_switchboard_close(session->switches->data); - - if (session->notification != NULL) - msn_notification_close(session->notification); -} - -/* TODO: This must go away when conversation is redesigned */ -MsnSwitchBoard * -msn_session_find_swboard(MsnSession *session, const char *username) -{ - GList *l; - - g_return_val_if_fail(session != NULL, NULL); - g_return_val_if_fail(username != NULL, NULL); - - for (l = session->switches; l != NULL; l = l->next) - { - MsnSwitchBoard *swboard; - - swboard = l->data; - - if ((swboard->im_user != NULL) && !strcmp(username, swboard->im_user)) - return swboard; - } - - return NULL; -} - -static PurpleConversation * -msn_session_get_conv(MsnSession *session,const char *passport) -{ - PurpleAccount *account; - PurpleConversation * conv; - - g_return_val_if_fail(session != NULL, NULL); - account = session->account; - - conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, - passport, account); - if(conv == NULL){ - conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, passport); - } - return conv; -} - -/* put Message to User Conversation - * - * passport - the one want to talk to you - */ -void -msn_session_report_user(MsnSession *session,const char *passport,const char *msg,PurpleMessageFlags flags) -{ - PurpleConversation * conv; - - if ((conv = msn_session_get_conv(session,passport)) != NULL){ - purple_conversation_write(conv, NULL, msg, flags, time(NULL)); - } -} - -MsnSwitchBoard * -msn_session_find_swboard_with_conv(MsnSession *session, PurpleConversation *conv) -{ - GList *l; - - g_return_val_if_fail(session != NULL, NULL); - g_return_val_if_fail(conv != NULL, NULL); - - for (l = session->switches; l != NULL; l = l->next) - { - MsnSwitchBoard *swboard; - - swboard = l->data; - - if (swboard->conv == conv) - return swboard; - } - - return NULL; -} - -MsnSwitchBoard * -msn_session_find_swboard_with_id(const MsnSession *session, int chat_id) -{ - GList *l; - - g_return_val_if_fail(session != NULL, NULL); - g_return_val_if_fail(chat_id >= 0, NULL); - - for (l = session->switches; l != NULL; l = l->next) - { - MsnSwitchBoard *swboard; - - swboard = l->data; - - if (swboard->chat_id == chat_id) - return swboard; - } - - return NULL; -} - -MsnSwitchBoard * -msn_session_get_swboard(MsnSession *session, const char *username, - MsnSBFlag flag) -{ - MsnSwitchBoard *swboard; - - g_return_val_if_fail(session != NULL, NULL); - - swboard = msn_session_find_swboard(session, username); - - if (swboard == NULL) - { - swboard = msn_switchboard_new(session); - swboard->im_user = g_strdup(username); - if (msn_switchboard_request(swboard)) - msn_switchboard_request_add_user(swboard, username); - else - return NULL; - } - - swboard->flag |= flag; - - return swboard; -} - -static gboolean -msn_login_timeout_cb(gpointer data) -{ - MsnSession *session = data; - /* This forces the login process to finish, even though we haven't heard - a response for our FQY requests yet. We'll at least end up online to the - people we've already added. The rest will follow later. */ - msn_session_finish_login(session); - session->login_timeout = 0; - return FALSE; -} - -void -msn_session_activate_login_timeout(MsnSession *session) -{ - if (!session->logged_in && session->connected) { - if (session->login_timeout) - purple_timeout_remove(session->login_timeout); - session->login_timeout = - purple_timeout_add_seconds(MSN_LOGIN_FQY_TIMEOUT, - msn_login_timeout_cb, session); - } -} - -static void -msn_session_sync_users(MsnSession *session) -{ - PurpleConnection *gc = purple_account_get_connection(session->account); - GList *to_remove = NULL; - GSList *buddies; - - g_return_if_fail(gc != NULL); - - /* The core used to use msn_add_buddy to add all buddies before - * being logged in. This no longer happens, so we manually iterate - * over the whole buddy list to identify sync issues. - */ - for (buddies = purple_find_buddies(session->account, NULL); buddies; - buddies = g_slist_delete_link(buddies, buddies)) { - PurpleBuddy *buddy = buddies->data; - const gchar *buddy_name = purple_buddy_get_name(buddy); - const gchar *group_name = purple_group_get_name(purple_buddy_get_group(buddy)); - MsnUser *remote_user; - gboolean found = FALSE; - - remote_user = msn_userlist_find_user(session->userlist, buddy_name); - if (remote_user && remote_user->list_op & MSN_LIST_FL_OP) { - GList *l; - for (l = remote_user->group_ids; l; l = l->next) { - const char *name = msn_userlist_find_group_name(remote_user->userlist, l->data); - if (name && !g_ascii_strcasecmp(group_name, name)) { - found = TRUE; - break; - } - } - - /* We don't care if they're in a different group, as long as they're on the - * list somewhere. If we check for the group, we cause pain, agony and - * suffering for people who decide to re-arrange their buddy list elsewhere. - */ - if (!found) { - if ((remote_user == NULL) || !(remote_user->list_op & MSN_LIST_FL_OP)) { - /* The user is not on the server list */ - msn_error_sync_issue(session, buddy_name, group_name); - } else { - /* The user is not in that group on the server list */ - to_remove = g_list_prepend(to_remove, buddy); - } - } - } - } - - if (to_remove != NULL) { - g_list_foreach(to_remove, (GFunc)purple_blist_remove_buddy, NULL); - g_list_free(to_remove); - } -} - -void -msn_session_set_error(MsnSession *session, MsnErrorType error, - const char *info) -{ - PurpleConnection *gc; - PurpleConnectionError reason; - char *msg; - - if (session->destroying) - return; - - gc = purple_account_get_connection(session->account); - - switch (error) - { - case MSN_ERROR_SERVCONN: - reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR; - msg = g_strdup(info); - break; - case MSN_ERROR_UNSUPPORTED_PROTOCOL: - reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR; - msg = g_strdup(_("Our protocol is not supported by the " - "server")); - break; - case MSN_ERROR_HTTP_MALFORMED: - reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR; - msg = g_strdup(_("Error parsing HTTP")); - break; - case MSN_ERROR_SIGN_OTHER: - reason = PURPLE_CONNECTION_ERROR_NAME_IN_USE; - msg = g_strdup(_("You have signed on from another location")); - if (!purple_account_get_remember_password(session->account)) - purple_account_set_password(session->account, NULL); - break; - case MSN_ERROR_SERV_UNAVAILABLE: - reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR; - msg = g_strdup(_("The MSN servers are temporarily " - "unavailable. Please wait and try " - "again.")); - break; - case MSN_ERROR_SERV_DOWN: - reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR; - msg = g_strdup(_("The MSN servers are going down " - "temporarily")); - break; - case MSN_ERROR_AUTH: - reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED; - msg = g_strdup_printf(_("Unable to authenticate: %s"), - (info == NULL ) ? - _("Unknown error") : info); - /* Clear the password if it isn't being saved */ - if (!purple_account_get_remember_password(session->account)) - purple_account_set_password(session->account, NULL); - break; - case MSN_ERROR_BAD_BLIST: - reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR; - msg = g_strdup_printf(_("Your MSN buddy list is temporarily " - "unavailable: %s"), - (info == NULL) ? _("Unknown error") : info); - break; - default: - reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR; - msg = g_strdup(_("Unknown error")); - break; - } - - msn_session_disconnect(session); - - purple_connection_error_reason(gc, reason, msg); - - g_free(msg); -} - -static const char * -get_login_step_text(MsnSession *session) -{ - const char *steps_text[] = { - _("Connecting"), - _("Handshaking"), - _("Transferring"), - _("Handshaking"), - _("Starting authentication"), - _("Getting cookie"), - _("Authenticating"), - _("Sending cookie"), - _("Retrieving buddy list") - }; - - return steps_text[session->login_step]; -} - -void -msn_session_set_login_step(MsnSession *session, MsnLoginStep step) -{ - PurpleConnection *gc; - - /* Prevent the connection progress going backwards, eg. if we get - * transferred several times during login */ - if (session->login_step >= step) - return; - - /* If we're already logged in, we're probably here because of a - * mid-session XFR from the notification server, so we don't want to - * popup the connection progress dialog */ - if (session->logged_in) - return; - - gc = session->account->gc; - - session->login_step = step; - - purple_connection_update_progress(gc, get_login_step_text(session), step, - MSN_LOGIN_STEPS); -} - -void -msn_session_finish_login(MsnSession *session) -{ - PurpleAccount *account; - PurpleConnection *gc; - PurpleStoredImage *img; - - if (!session->logged_in) { - account = session->account; - gc = purple_account_get_connection(account); - - img = purple_buddy_icons_find_account_icon(session->account); - /* TODO: Do we really want to call this if img is NULL? */ - msn_user_set_buddy_icon(session->user, img); - if (img != NULL) - purple_imgstore_unref(img); - - session->logged_in = TRUE; - purple_connection_set_state(gc, PURPLE_CONNECTED); - - /* Sync users */ - msn_session_sync_users(session); - } - - /* TODO: Send this when updating status instead? */ - msn_notification_send_uux_endpointdata(session); - msn_notification_send_uux_private_endpointdata(session); - - msn_change_status(session); -} - diff --git a/libpurple/protocols/msn/session.h b/libpurple/protocols/msn/session.h deleted file mode 100644 index e94b3b73ac..0000000000 --- a/libpurple/protocols/msn/session.h +++ /dev/null @@ -1,245 +0,0 @@ -/** - * @file session.h MSN session functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_SESSION_H -#define MSN_SESSION_H - -typedef struct _MsnSession MsnSession; - -/** - * Types of errors. - */ -typedef enum -{ - MSN_ERROR_SERVCONN, - MSN_ERROR_UNSUPPORTED_PROTOCOL, - MSN_ERROR_HTTP_MALFORMED, - MSN_ERROR_AUTH, - MSN_ERROR_BAD_BLIST, - MSN_ERROR_SIGN_OTHER, - MSN_ERROR_SERV_DOWN, - MSN_ERROR_SERV_UNAVAILABLE -} MsnErrorType; - -/** - * Login steps. - */ -typedef enum -{ - MSN_LOGIN_STEP_START, - MSN_LOGIN_STEP_HANDSHAKE, - MSN_LOGIN_STEP_TRANSFER, - MSN_LOGIN_STEP_HANDSHAKE2, - MSN_LOGIN_STEP_AUTH_START, - MSN_LOGIN_STEP_GET_COOKIE, - MSN_LOGIN_STEP_AUTH_END, - MSN_LOGIN_STEP_SYN, - MSN_LOGIN_STEP_END -} MsnLoginStep; - -#define MSN_LOGIN_STEPS MSN_LOGIN_STEP_END - -#define MSN_LOGIN_FQY_TIMEOUT 30 - -#define MSN_LOGIN_FQY_TIMEOUT 30 - -#include "nexus.h" -#include "notification.h" -#include "oim.h" -#include "switchboard.h" -#include "user.h" -#include "userlist.h" - -struct _MsnSession -{ - PurpleAccount *account; - MsnUser *user; - - guint protocol_ver; - - MsnLoginStep login_step; /**< The current step in the login process. */ - - gboolean connected:1; - gboolean logged_in:1; /**< A temporal flag to ignore local buddy list adds. */ - gboolean destroying:1; /**< A flag that states if the session is being destroyed. */ - gboolean http_method:1; - gboolean enable_mpop:1; /**< Use Multiple Points of Presence? */ - int adl_fqy; /**< A count of ADL/FQY so status is only changed once. */ - guint login_timeout; /**< Timeout to force status change if ADL/FQY fail. */ - - MsnNotification *notification; - MsnNexus *nexus; - MsnOim *oim; - MsnUserList *userlist; - char *abch_cachekey; - - int servconns_count; /**< The count of server connections. */ - GList *switches; /**< The list of all the switchboards. */ - GList *slplinks; /**< The list of all the slplinks. */ - - /*psm info*/ - char *psm; - -#if 0 - char *blocked_text; -#endif - - struct - { - char *sid; - char *mspauth; - unsigned long sl; - char *client_ip; - int client_port; - char *mail_url; - gulong mail_timestamp; - gboolean email_enabled; - } passport_info; - - GHashTable *soap_table; - guint soap_cleanup_handle; - char *guid; - - GSList *url_datas; /**< PurpleUtilFetchUrlData to be cancelled on exit */ -}; - -/** - * Creates an MSN session. - * - * @param account The account. - * - * @return The new MSN session. - */ -MsnSession *msn_session_new(PurpleAccount *account); - -/** - * Destroys an MSN session. - * - * @param session The MSN session to destroy. - */ -void msn_session_destroy(MsnSession *session); - -/** - * Connects to and initiates an MSN session. - * - * @param session The MSN session. - * @param host The dispatch server host. - * @param port The dispatch server port. - * @param http_method Whether to use or not http_method. - * - * @return @c TRUE on success, @c FALSE on failure. - */ -gboolean msn_session_connect(MsnSession *session, - const char *host, int port, - gboolean http_method); - -/** - * Disconnects from an MSN session. - * - * @param session The MSN session. - */ -void msn_session_disconnect(MsnSession *session); - - /** - * Finds a switchboard with the given username. - * - * @param session The MSN session. - * @param username The username to search for. - * - * @return The switchboard, if found. - */ -MsnSwitchBoard *msn_session_find_swboard(MsnSession *session, - const char *username); - - /** - * Finds a switchboard with the given conversation. - * - * @param session The MSN session. - * @param conv The conversation to search for. - * - * @return The switchboard, if found. - */ -MsnSwitchBoard *msn_session_find_swboard_with_conv(MsnSession *session, - PurpleConversation *conv); -/** - * Finds a switchboard with the given chat ID. - * - * @param session The MSN session. - * @param chat_id The chat ID to search for. - * - * @return The switchboard, if found. - */ -MsnSwitchBoard *msn_session_find_swboard_with_id(const MsnSession *session, - int chat_id); - -/** - * Returns a switchboard to communicate with certain username. - * - * @param session The MSN session. - * @param username The username to search for. - * @param flag The flag of the switchboard - * - * @return The switchboard. - */ -MsnSwitchBoard *msn_session_get_swboard(MsnSession *session, - const char *username, MsnSBFlag flag); - -/** - * Sets an error for the MSN session. - * - * @param session The MSN session. - * @param error The error. - * @param info Extra information. - */ -void msn_session_set_error(MsnSession *session, MsnErrorType error, - const char *info); - -/** - * Starts a timeout to initiate finishing login. Sometimes the server ignores - * our FQY requests, so this forces ourselves online eventually. - * - * @param session The MSN session. - */ -void -msn_session_activate_login_timeout(MsnSession *session); - -/** - * Sets the current step in the login process. - * - * @param session The MSN session. - * @param step The current step. - */ -void msn_session_set_login_step(MsnSession *session, MsnLoginStep step); - -/** - * Finish the login proccess. - * - * @param session The MSN session. - */ -void msn_session_finish_login(MsnSession *session); - -/*post message to User*/ -void msn_session_report_user(MsnSession *session,const char *passport, - const char *msg,PurpleMessageFlags flags); - -#endif /* MSN_SESSION_H */ diff --git a/libpurple/protocols/msn/slp.c b/libpurple/protocols/msn/slp.c deleted file mode 100644 index 85c78b260a..0000000000 --- a/libpurple/protocols/msn/slp.c +++ /dev/null @@ -1,396 +0,0 @@ -/** - * @file msnslp.c MSNSLP support - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "debug.h" - -#include "slp.h" -#include "slpcall.h" -#include "slpmsg.h" -#include "msnutils.h" - -#include "object.h" -#include "user.h" -#include "sbconn.h" -#include "directconn.h" -#include "p2p.h" -#include "xfer.h" - -/* seconds to delay between sending buddy icon requests to the server. */ -#define BUDDY_ICON_DELAY 20 - -typedef struct { - MsnSession *session; - const char *remote_user; - const char *sha1; -} MsnFetchUserDisplayData; - -/************************************************************************** - * SLP Control - **************************************************************************/ - -void -msn_slp_send_ok(MsnSlpCall *slpcall, const char *branch, - const char *type, const char *content) -{ - MsnSlpLink *slplink; - MsnSlpMessage *slpmsg; - - slplink = slpcall->slplink; - - /* 200 OK */ - slpmsg = msn_slpmsg_sip_new(slpcall, 1, - "MSNSLP/1.0 200 OK", - branch, type, content); - - slpmsg->info = "SLP 200 OK"; - slpmsg->text_body = TRUE; - - msn_slplink_queue_slpmsg(slplink, slpmsg); -} - -void -msn_slp_send_decline(MsnSlpCall *slpcall, const char *branch, - const char *type, const char *content) -{ - MsnSlpLink *slplink; - MsnSlpMessage *slpmsg; - - slplink = slpcall->slplink; - - /* 603 Decline */ - slpmsg = msn_slpmsg_sip_new(slpcall, 1, - "MSNSLP/1.0 603 Decline", - branch, type, content); - - slpmsg->info = "SLP 603 Decline"; - slpmsg->text_body = TRUE; - - msn_slplink_queue_slpmsg(slplink, slpmsg); -} - -/************************************************************************** - * Msg Callbacks - **************************************************************************/ - -/* - * Called on a timeout from end_user_display(). Frees a buddy icon window slow and dequeues the next - * buddy icon request if there is one. - */ -static gboolean -msn_release_buddy_icon_request_timeout(gpointer data) -{ - MsnUserList *userlist = (MsnUserList *)data; - - /* Free one window slot */ - userlist->buddy_icon_window++; - - /* Clear the tag for our former request timer */ - userlist->buddy_icon_request_timer = 0; - - msn_release_buddy_icon_request(userlist); - - return FALSE; -} - -static void -got_user_display(MsnSlpCall *slpcall, - const guchar *data, gsize size) -{ - const char *info; - PurpleAccount *account; - - g_return_if_fail(slpcall != NULL); - - info = slpcall->data_info; - if (purple_debug_is_verbose()) - purple_debug_info("msn", "Got User Display: %s\n", slpcall->slplink->remote_user); - - account = slpcall->slplink->session->account; - - purple_buddy_icons_set_for_user(account, slpcall->slplink->remote_user, - g_memdup(data, size), size, info); -} - -static void -end_user_display(MsnSlpCall *slpcall, MsnSession *session) -{ - MsnUserList *userlist; - - g_return_if_fail(session != NULL); - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "End User Display\n"); - - userlist = session->userlist; - - /* If the session is being destroyed we better stop doing anything. */ - if (session->destroying) - return; - - /* Delay before freeing a buddy icon window slot and requesting the next icon, if appropriate. - * If we don't delay, we'll rapidly hit the MSN equivalent of AIM's rate limiting; the server will - * send us an error 800 like so: - * - * C: NS 000: XFR 21 SB - * S: NS 000: 800 21 - */ - if (userlist->buddy_icon_request_timer) { - /* Free the window slot used by this previous request */ - userlist->buddy_icon_window++; - - /* Clear our pending timeout */ - purple_timeout_remove(userlist->buddy_icon_request_timer); - } - - /* Wait BUDDY_ICON_DELAY s before freeing our window slot and requesting the next icon. */ - userlist->buddy_icon_request_timer = purple_timeout_add_seconds(BUDDY_ICON_DELAY, - msn_release_buddy_icon_request_timeout, userlist); -} - -static void -fetched_user_display(PurpleUtilFetchUrlData *url_data, gpointer user_data, - const gchar *url_text, gsize len, const gchar *error_message) -{ - MsnFetchUserDisplayData *data = user_data; - MsnSession *session = data->session; - - session->url_datas = g_slist_remove(session->url_datas, url_data); - - if (url_text) { - purple_buddy_icons_set_for_user(session->account, data->remote_user, - g_memdup(url_text, len), len, - data->sha1); - } - - end_user_display(NULL, session); - - g_free(user_data); -} - -static void -request_own_user_display(MsnUser *user) -{ - PurpleAccount *account; - MsnSession *session; - MsnObject *my_obj = NULL; - gconstpointer data = NULL; - const char *info = NULL; - size_t len = 0; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "Requesting our own user display\n"); - - session = user->userlist->session; - account = session->account; - my_obj = msn_user_get_object(user); - - if (my_obj != NULL) { - PurpleStoredImage *img = msn_object_get_image(my_obj); - data = purple_imgstore_get_data(img); - len = purple_imgstore_get_size(img); - info = msn_object_get_sha1(my_obj); - } - - purple_buddy_icons_set_for_user(account, user->passport, g_memdup(data, len), len, info); - - /* Free one window slot */ - session->userlist->buddy_icon_window++; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "msn_request_user_display(): buddy_icon_window++ yields =%d\n", - session->userlist->buddy_icon_window); - - msn_release_buddy_icon_request(session->userlist); -} - -void -msn_request_user_display(MsnUser *user) -{ - PurpleAccount *account; - MsnSession *session; - MsnSlpLink *slplink; - MsnObject *obj; - const char *info; - - session = user->userlist->session; - account = session->account; - - slplink = msn_session_get_slplink(session, user->passport); - - obj = msn_user_get_object(user); - - info = msn_object_get_sha1(obj); - - if (g_ascii_strcasecmp(user->passport, - purple_account_get_username(account))) - { - const char *url = msn_object_get_url1(obj); - if (url) { - MsnFetchUserDisplayData *data = g_new0(MsnFetchUserDisplayData, 1); - PurpleUtilFetchUrlData *url_data; - data->session = session; - data->remote_user = user->passport; - data->sha1 = info; - url_data = purple_util_fetch_url_len(url, TRUE, NULL, TRUE, 200*1024, - fetched_user_display, data); - session->url_datas = g_slist_prepend(session->url_datas, url_data); - } else { - msn_slplink_request_object(slplink, info, got_user_display, - end_user_display, obj); - } - } - else - request_own_user_display(user); -} - -static void -send_file_cb(MsnSlpCall *slpcall) -{ - MsnSlpMessage *slpmsg; - PurpleXfer *xfer; - - xfer = (PurpleXfer *)slpcall->xfer; - if (purple_xfer_get_status(xfer) >= PURPLE_XFER_STATUS_STARTED) - return; - - purple_xfer_ref(xfer); - purple_xfer_start(xfer, -1, NULL, 0); - if (purple_xfer_get_status(xfer) != PURPLE_XFER_STATUS_STARTED) { - purple_xfer_unref(xfer); - return; - } - purple_xfer_unref(xfer); - - slpmsg = msn_slpmsg_file_new(slpcall, purple_xfer_get_size(xfer)); - - msn_slplink_send_slpmsg(slpcall->slplink, slpmsg); -} - -static gchar * -gen_context(PurpleXfer *xfer, const char *file_name, const char *file_path) -{ - gsize size = 0; - MsnFileContext context; - gchar *u8 = NULL; - gchar *ret; - gunichar2 *uni = NULL; - glong currentChar = 0; - glong len = 0; - const char *preview; - gsize preview_len; - - size = purple_xfer_get_size(xfer); - - purple_xfer_prepare_thumbnail(xfer, "png"); - - if (!file_name) { - gchar *basename = g_path_get_basename(file_path); - u8 = purple_utf8_try_convert(basename); - g_free(basename); - file_name = u8; - } - - uni = g_utf8_to_utf16(file_name, -1, NULL, &len, NULL); - - if (u8) { - g_free(u8); - file_name = NULL; - u8 = NULL; - } - - preview = purple_xfer_get_thumbnail(xfer, &preview_len); - - context.length = MSN_FILE_CONTEXT_SIZE; - context.version = 2; /* V.3 contains additional unnecessary data */ - context.file_size = size; - if (preview) - context.type = 0; - else - context.type = 1; - - len = MIN(len, MAX_FILE_NAME_LEN); - for (currentChar = 0; currentChar < len; currentChar++) { - context.file_name[currentChar] = GUINT16_TO_LE(uni[currentChar]); - } - memset(&context.file_name[currentChar], 0x00, (MAX_FILE_NAME_LEN - currentChar) * 2); - - memset(&context.unknown1, 0, sizeof(context.unknown1)); - context.unknown2 = 0xffffffff; - - /* Mind the cast, as in, don't free it after! */ - context.preview = (char *)preview; - context.preview_len = preview_len; - - u8 = msn_file_context_to_wire(&context); - ret = purple_base64_encode((const guchar *)u8, MSN_FILE_CONTEXT_SIZE + preview_len); - - g_free(uni); - g_free(u8); - - return ret; -} - -void -msn_request_ft(PurpleXfer *xfer) -{ - MsnSlpCall *slpcall; - MsnSlpLink *slplink; - char *context; - const char *fn; - const char *fp; - - fn = purple_xfer_get_filename(xfer); - fp = purple_xfer_get_local_filename(xfer); - - slplink = xfer->data; - - g_return_if_fail(slplink != NULL); - g_return_if_fail(fp != NULL); - - slpcall = msn_slpcall_new(slplink); - msn_slpcall_init(slpcall, MSN_SLPCALL_DC); - - slpcall->session_init_cb = send_file_cb; - slpcall->end_cb = msn_xfer_end_cb; - slpcall->cb = msn_xfer_completed_cb; - slpcall->xfer = xfer; - purple_xfer_ref(slpcall->xfer); - - slpcall->pending = TRUE; - - purple_xfer_set_cancel_send_fnc(xfer, msn_xfer_cancel); - purple_xfer_set_read_fnc(xfer, msn_xfer_read); - purple_xfer_set_write_fnc(xfer, msn_xfer_write); - - xfer->data = slpcall; - - context = gen_context(xfer, fn, fp); - - msn_slpcall_invite(slpcall, MSN_FT_GUID, P2P_APPID_FILE, context); - msn_slplink_unref(slplink); - - g_free(context); -} - diff --git a/libpurple/protocols/msn/slp.h b/libpurple/protocols/msn/slp.h deleted file mode 100644 index 0be19f0358..0000000000 --- a/libpurple/protocols/msn/slp.h +++ /dev/null @@ -1,51 +0,0 @@ -/** - * @file slp.h MSNSLP support - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_SLP_H -#define MSN_SLP_H - -#include "internal.h" -#include "ft.h" - -#include "session.h" -#include "slpcall.h" -#include "slplink.h" -#include "user.h" - -void -msn_slp_send_ok(MsnSlpCall *slpcall, const char *branch, - const char *type, const char *content); - -void -msn_slp_send_decline(MsnSlpCall *slpcall, const char *branch, - const char *type, const char *content); - - -void send_bye(MsnSlpCall *slpcall, const char *type); - - -void msn_request_user_display(MsnUser *user); - -void msn_request_ft(PurpleXfer *xfer); - -#endif /* MSN_SLP_H */ diff --git a/libpurple/protocols/msn/slpcall.c b/libpurple/protocols/msn/slpcall.c deleted file mode 100644 index 2f06124921..0000000000 --- a/libpurple/protocols/msn/slpcall.c +++ /dev/null @@ -1,1157 +0,0 @@ -/** - * @file slpcall.c SLP Call Functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "debug.h" -#include "smiley.h" - -#include "msnutils.h" -#include "slpcall.h" - -#include "slp.h" -#include "p2p.h" -#include "xfer.h" - -/************************************************************************** - * Main - **************************************************************************/ - -static gboolean -msn_slpcall_timeout(gpointer data) -{ - MsnSlpCall *slpcall; - - slpcall = data; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "slpcall_timeout: slpcall(%p)\n", slpcall); - - if (!slpcall->pending && !slpcall->progress) - { - msn_slpcall_destroy(slpcall); - return TRUE; - } - - slpcall->progress = FALSE; - - return TRUE; -} - -MsnSlpCall * -msn_slpcall_new(MsnSlpLink *slplink) -{ - MsnSlpCall *slpcall; - - g_return_val_if_fail(slplink != NULL, NULL); - - slpcall = g_new0(MsnSlpCall, 1); - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "slpcall_new: slpcall(%p)\n", slpcall); - - slpcall->slplink = slplink; - - msn_slplink_add_slpcall(slplink, slpcall); - - slpcall->timer = purple_timeout_add_seconds(MSN_SLPCALL_TIMEOUT, msn_slpcall_timeout, slpcall); - - return slpcall; -} - -void -msn_slpcall_destroy(MsnSlpCall *slpcall) -{ - GList *e; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "slpcall_destroy: slpcall(%p)\n", slpcall); - - g_return_if_fail(slpcall != NULL); - - if (slpcall->timer) - purple_timeout_remove(slpcall->timer); - - for (e = slpcall->slplink->slp_msgs; e != NULL; ) - { - MsnSlpMessage *slpmsg = e->data; - e = e->next; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "slpcall_destroy: trying slpmsg(%p)\n", - slpmsg); - - if (slpmsg->slpcall == slpcall) - { - msn_slpmsg_destroy(slpmsg); - } - } - - if (slpcall->end_cb != NULL) - slpcall->end_cb(slpcall, slpcall->slplink->session); - - if (slpcall->xfer != NULL) { - if (purple_xfer_get_type(slpcall->xfer) == PURPLE_XFER_RECEIVE) - g_byte_array_free(slpcall->u.incoming_data, TRUE); - slpcall->xfer->data = NULL; - purple_xfer_unref(slpcall->xfer); - } - - - msn_slplink_remove_slpcall(slpcall->slplink, slpcall); - - g_free(slpcall->id); - g_free(slpcall->branch); - g_free(slpcall->data_info); - - g_free(slpcall); -} - -void -msn_slpcall_init(MsnSlpCall *slpcall, MsnSlpCallType type) -{ - slpcall->session_id = rand() % 0xFFFFFF00 + 4; - slpcall->id = rand_guid(); - slpcall->type = type; -} - -void -msn_slpcall_session_init(MsnSlpCall *slpcall) -{ - if (slpcall->session_init_cb) - slpcall->session_init_cb(slpcall); - - slpcall->started = TRUE; -} - -void -msn_slpcall_invite(MsnSlpCall *slpcall, const char *euf_guid, - MsnP2PAppId app_id, const char *context) -{ - MsnSlpLink *slplink; - MsnSlpMessage *slpmsg; - char *header; - char *content; - - g_return_if_fail(slpcall != NULL); - g_return_if_fail(context != NULL); - - slplink = slpcall->slplink; - - slpcall->branch = rand_guid(); - - content = g_strdup_printf( - "EUF-GUID: {%s}\r\n" - "SessionID: %lu\r\n" - "AppID: %d\r\n" - "Context: %s\r\n\r\n", - euf_guid, - slpcall->session_id, - app_id, - context); - - header = g_strdup_printf("INVITE MSNMSGR:%s MSNSLP/1.0", - slplink->remote_user); - - slpmsg = msn_slpmsg_sip_new(slpcall, 0, header, slpcall->branch, - "application/x-msnmsgr-sessionreqbody", content); - - slpmsg->info = "SLP INVITE"; - slpmsg->text_body = TRUE; - - msn_slplink_send_slpmsg(slplink, slpmsg); - - g_free(header); - g_free(content); -} - -void -msn_slpcall_close(MsnSlpCall *slpcall) -{ - g_return_if_fail(slpcall != NULL); - g_return_if_fail(slpcall->slplink != NULL); - - send_bye(slpcall, "application/x-msnmsgr-sessionclosebody"); - msn_slplink_send_queued_slpmsgs(slpcall->slplink); - msn_slpcall_destroy(slpcall); -} - -/***************************************************************************** - * Parse received SLP messages - ****************************************************************************/ - -/************************************************************************** - *** Util - **************************************************************************/ - -static char * -get_token(const char *str, const char *start, const char *end) -{ - const char *c, *c2; - - if ((c = strstr(str, start)) == NULL) - return NULL; - - c += strlen(start); - - if (end != NULL) - { - if ((c2 = strstr(c, end)) == NULL) - return NULL; - - return g_strndup(c, c2 - c); - } - else - { - /* This has to be changed */ - return g_strdup(c); - } - -} - -/* XXX: this could be improved if we tracked custom smileys - * per-protocol, per-account, per-session or (ideally) per-conversation - */ -static PurpleStoredImage * -find_valid_emoticon(PurpleAccount *account, const char *path) -{ - GList *smileys; - - if (!purple_account_get_bool(account, "custom_smileys", TRUE)) - return NULL; - - smileys = purple_smileys_get_all(); - - for (; smileys; smileys = g_list_delete_link(smileys, smileys)) { - PurpleSmiley *smiley; - PurpleStoredImage *img; - - smiley = smileys->data; - img = purple_smiley_get_stored_image(smiley); - - if (purple_strequal(path, purple_imgstore_get_filename(img))) { - g_list_free(smileys); - return img; - } - - purple_imgstore_unref(img); - } - - purple_debug_error("msn", "Received illegal request for file %s\n", path); - return NULL; -} - -static char * -parse_dc_nonce(const char *content, MsnDirectConnNonceType *ntype) -{ - char *nonce; - - *ntype = DC_NONCE_UNKNOWN; - - nonce = get_token(content, "Hashed-Nonce: {", "}\r\n"); - if (nonce) { - *ntype = DC_NONCE_SHA1; - } else { - guint32 n1, n6; - guint16 n2, n3, n4, n5; - nonce = get_token(content, "Nonce: {", "}\r\n"); - if (nonce - && sscanf(nonce, "%08x-%04hx-%04hx-%04hx-%04hx%08x", - &n1, &n2, &n3, &n4, &n5, &n6) == 6) { - *ntype = DC_NONCE_PLAIN; - g_free(nonce); - nonce = g_malloc(16); - *(guint32 *)(nonce + 0) = GUINT32_TO_LE(n1); - *(guint16 *)(nonce + 4) = GUINT16_TO_LE(n2); - *(guint16 *)(nonce + 6) = GUINT16_TO_LE(n3); - *(guint16 *)(nonce + 8) = GUINT16_TO_BE(n4); - *(guint16 *)(nonce + 10) = GUINT16_TO_BE(n5); - *(guint32 *)(nonce + 12) = GUINT32_TO_BE(n6); - } else { - /* Invalid nonce, so ignore request */ - g_free(nonce); - nonce = NULL; - } - } - - return nonce; -} - -static void -msn_slp_process_transresp(MsnSlpCall *slpcall, const char *content) -{ - /* A direct connection negotiation response */ - char *bridge; - char *nonce; - char *listening; - MsnDirectConn *dc = slpcall->slplink->dc; - MsnDirectConnNonceType ntype; - - purple_debug_info("msn", "process_transresp\n"); - - /* Direct connections are disabled. */ - if (!purple_account_get_bool(slpcall->slplink->session->account, "direct_connect", TRUE)) - return; - - g_return_if_fail(dc != NULL); - g_return_if_fail(dc->state == DC_STATE_CLOSED); - - bridge = get_token(content, "Bridge: ", "\r\n"); - nonce = parse_dc_nonce(content, &ntype); - listening = get_token(content, "Listening: ", "\r\n"); - if (listening && bridge && !strcmp(bridge, "TCPv1")) { - /* Ok, the client supports direct TCP connection */ - - /* We always need this. */ - if (ntype == DC_NONCE_SHA1) { - strncpy(dc->remote_nonce, nonce, 36); - dc->remote_nonce[36] = '\0'; - } - - if (!strcasecmp(listening, "false")) { - if (dc->listen_data != NULL) { - /* - * We'll listen for incoming connections but - * the listening socket isn't ready yet so we cannot - * send the INVITE packet now. Put the slpcall into waiting mode - * and let the callback send the invite. - */ - slpcall->wait_for_socket = TRUE; - - } else if (dc->listenfd != -1) { - /* The listening socket is ready. Send the INVITE here. */ - msn_dc_send_invite(dc); - - } else { - /* We weren't able to create a listener either. Use SB. */ - msn_dc_fallback_to_sb(dc); - } - - } else { - /* - * We should connect to the client so parse - * IP/port from response. - */ - char *ip, *port_str; - int port = 0; - - if (ntype == DC_NONCE_PLAIN) { - /* Only needed for listening side. */ - memcpy(dc->nonce, nonce, 16); - } - - /* Cancel any listen attempts because we don't need them. */ - if (dc->listenfd_handle != 0) { - purple_input_remove(dc->listenfd_handle); - dc->listenfd_handle = 0; - } - if (dc->connect_timeout_handle != 0) { - purple_timeout_remove(dc->connect_timeout_handle); - dc->connect_timeout_handle = 0; - } - if (dc->listenfd != -1) { - purple_network_remove_port_mapping(dc->listenfd); - close(dc->listenfd); - dc->listenfd = -1; - } - if (dc->listen_data != NULL) { - purple_network_listen_cancel(dc->listen_data); - dc->listen_data = NULL; - } - - /* Save external IP/port for later use. We'll try local connection first. */ - dc->ext_ip = get_token(content, "IPv4External-Addrs: ", "\r\n"); - port_str = get_token(content, "IPv4External-Port: ", "\r\n"); - if (port_str) { - dc->ext_port = atoi(port_str); - g_free(port_str); - } - - ip = get_token(content, "IPv4Internal-Addrs: ", "\r\n"); - port_str = get_token(content, "IPv4Internal-Port: ", "\r\n"); - if (port_str) { - port = atoi(port_str); - g_free(port_str); - } - - if (ip && port) { - /* Try internal address first */ - dc->connect_data = purple_proxy_connect( - NULL, - slpcall->slplink->session->account, - ip, - port, - msn_dc_connected_to_peer_cb, - dc - ); - - if (dc->connect_data) { - /* Add connect timeout handle */ - dc->connect_timeout_handle = purple_timeout_add_seconds( - DC_OUTGOING_TIMEOUT, - msn_dc_outgoing_connection_timeout_cb, - dc - ); - } else { - /* - * Connection failed - * Try external IP/port (if specified) - */ - msn_dc_outgoing_connection_timeout_cb(dc); - } - - } else { - /* - * Omitted or invalid internal IP address / port - * Try external IP/port (if specified) - */ - msn_dc_outgoing_connection_timeout_cb(dc); - } - - g_free(ip); - } - - } else { - /* - * Invalid direct connect invitation or - * TCP connection is not supported - */ - } - - g_free(listening); - g_free(nonce); - g_free(bridge); - - return; -} - -static void -got_sessionreq(MsnSlpCall *slpcall, const char *branch, - const char *euf_guid, const char *context) -{ - gboolean accepted = FALSE; - - if (!strcmp(euf_guid, MSN_OBJ_GUID)) - { - /* Emoticon or UserDisplay */ - char *content; - gsize len; - MsnSlpLink *slplink; - MsnSlpMessage *slpmsg; - MsnObject *obj; - char *msnobj_data; - PurpleStoredImage *img = NULL; - int type; - - /* Send Ok */ - content = g_strdup_printf("SessionID: %lu\r\n\r\n", - slpcall->session_id); - - msn_slp_send_ok(slpcall, branch, "application/x-msnmsgr-sessionreqbody", - content); - - g_free(content); - - slplink = slpcall->slplink; - - msnobj_data = (char *)purple_base64_decode(context, &len); - obj = msn_object_new_from_string(msnobj_data); - type = msn_object_get_type(obj); - g_free(msnobj_data); - if (type == MSN_OBJECT_EMOTICON) { - img = find_valid_emoticon(slplink->session->account, obj->location); - } else if (type == MSN_OBJECT_USERTILE) { - img = msn_object_get_image(obj); - if (img) - purple_imgstore_ref(img); - } - msn_object_destroy(obj); - - if (img != NULL) { - /* DATA PREP */ - slpmsg = msn_slpmsg_dataprep_new(slpcall); - msn_slplink_queue_slpmsg(slplink, slpmsg); - - /* DATA */ - slpmsg = msn_slpmsg_obj_new(slpcall, img); - msn_slplink_queue_slpmsg(slplink, slpmsg); - purple_imgstore_unref(img); - - accepted = TRUE; - - } else { - purple_debug_error("msn", "Wrong object.\n"); - } - } - - else if (!strcmp(euf_guid, MSN_FT_GUID)) - { - /* File Transfer */ - PurpleAccount *account; - PurpleXfer *xfer; - MsnFileContext *file_context; - char *buf; - gsize bin_len; - guint32 file_size; - char *file_name; - - account = slpcall->slplink->session->account; - - slpcall->end_cb = msn_xfer_end_cb; - slpcall->branch = g_strdup(branch); - - slpcall->pending = TRUE; - - xfer = purple_xfer_new(account, PURPLE_XFER_RECEIVE, - slpcall->slplink->remote_user); - - buf = (char *)purple_base64_decode(context, &bin_len); - file_context = msn_file_context_from_wire(buf, bin_len); - - if (file_context != NULL) { - file_size = file_context->file_size; - - file_name = g_convert((const gchar *)&file_context->file_name, - MAX_FILE_NAME_LEN * 2, - "UTF-8", "UTF-16LE", - NULL, NULL, NULL); - - purple_xfer_set_filename(xfer, file_name ? file_name : ""); - g_free(file_name); - purple_xfer_set_size(xfer, file_size); - purple_xfer_set_init_fnc(xfer, msn_xfer_init); - purple_xfer_set_request_denied_fnc(xfer, msn_xfer_cancel); - purple_xfer_set_cancel_recv_fnc(xfer, msn_xfer_cancel); - purple_xfer_set_read_fnc(xfer, msn_xfer_read); - purple_xfer_set_write_fnc(xfer, msn_xfer_write); - - slpcall->u.incoming_data = g_byte_array_new(); - - slpcall->xfer = xfer; - purple_xfer_ref(slpcall->xfer); - - xfer->data = slpcall; - - if (file_context->preview) { - purple_xfer_set_thumbnail(xfer, file_context->preview, - file_context->preview_len, - "image/png"); - g_free(file_context->preview); - } - - purple_xfer_request(xfer); - } - g_free(file_context); - g_free(buf); - - accepted = TRUE; - - } else if (!strcmp(euf_guid, MSN_CAM_REQUEST_GUID)) { - purple_debug_info("msn", "Cam request.\n"); - if (slpcall->slplink && slpcall->slplink->session) { - PurpleConversation *conv; - gchar *from = slpcall->slplink->remote_user; - conv = purple_find_conversation_with_account( - PURPLE_CONV_TYPE_IM, from, - slpcall->slplink->session->account); - if (conv) { - char *buf; - buf = g_strdup_printf( - _("%s requests to view your " - "webcam, but this request is " - "not yet supported."), from); - purple_conversation_write(conv, NULL, buf, - PURPLE_MESSAGE_SYSTEM | - PURPLE_MESSAGE_NOTIFY, - time(NULL)); - g_free(buf); - } - } - - } else if (!strcmp(euf_guid, MSN_CAM_GUID)) { - purple_debug_info("msn", "Cam invite.\n"); - if (slpcall->slplink && slpcall->slplink->session) { - PurpleConversation *conv; - gchar *from = slpcall->slplink->remote_user; - conv = purple_find_conversation_with_account( - PURPLE_CONV_TYPE_IM, from, - slpcall->slplink->session->account); - if (conv) { - char *buf; - buf = g_strdup_printf( - _("%s invited you to view his/her webcam, but " - "this is not yet supported."), from); - purple_conversation_write(conv, NULL, buf, - PURPLE_MESSAGE_SYSTEM | - PURPLE_MESSAGE_NOTIFY, - time(NULL)); - g_free(buf); - } - } - - } else - purple_debug_warning("msn", "SLP SessionReq with unknown EUF-GUID: %s\n", euf_guid); - - if (!accepted) { - char *content = g_strdup_printf("SessionID: %lu\r\n\r\n", - slpcall->session_id); - msn_slp_send_decline(slpcall, branch, "application/x-msnmsgr-sessionreqbody", content); - g_free(content); - } -} - -void -send_bye(MsnSlpCall *slpcall, const char *type) -{ - MsnSlpLink *slplink; - PurpleAccount *account; - MsnSlpMessage *slpmsg; - char *header; - - slplink = slpcall->slplink; - - g_return_if_fail(slplink != NULL); - - account = slplink->session->account; - - header = g_strdup_printf("BYE MSNMSGR:%s MSNSLP/1.0", - purple_account_get_username(account)); - - slpmsg = msn_slpmsg_sip_new(slpcall, 0, header, - "A0D624A6-6C0C-4283-A9E0-BC97B4B46D32", - type, - "\r\n"); - g_free(header); - - slpmsg->info = "SLP BYE"; - slpmsg->text_body = TRUE; - - msn_slplink_queue_slpmsg(slplink, slpmsg); -} - -static void -got_invite(MsnSlpCall *slpcall, - const char *branch, const char *type, const char *content) -{ - MsnSlpLink *slplink; - - slplink = slpcall->slplink; - - if (!strcmp(type, "application/x-msnmsgr-sessionreqbody")) - { - char *euf_guid, *context; - char *temp; - - euf_guid = get_token(content, "EUF-GUID: {", "}\r\n"); - - temp = get_token(content, "SessionID: ", "\r\n"); - if (temp != NULL) - slpcall->session_id = atoi(temp); - g_free(temp); - - temp = get_token(content, "AppID: ", "\r\n"); - if (temp != NULL) - slpcall->app_id = atoi(temp); - g_free(temp); - - context = get_token(content, "Context: ", "\r\n"); - - if (context != NULL) - got_sessionreq(slpcall, branch, euf_guid, context); - - g_free(context); - g_free(euf_guid); - } - else if (!strcmp(type, "application/x-msnmsgr-transreqbody")) - { - /* A direct connection negotiation request */ - char *bridges; - char *nonce; - MsnDirectConnNonceType ntype; - - purple_debug_info("msn", "got_invite: transreqbody received\n"); - - /* Direct connections may be disabled. */ - if (!purple_account_get_bool(slplink->session->account, "direct_connect", TRUE)) { - msn_slp_send_ok(slpcall, branch, - "application/x-msnmsgr-transrespbody", - "Bridge: TCPv1\r\n" - "Listening: false\r\n" - "Nonce: {00000000-0000-0000-0000-000000000000}\r\n" - "\r\n"); - msn_slpcall_session_init(slpcall); - - return; - } - - /* Don't do anything if we already have a direct connection */ - if (slplink->dc != NULL) - return; - - bridges = get_token(content, "Bridges: ", "\r\n"); - nonce = parse_dc_nonce(content, &ntype); - if (bridges && strstr(bridges, "TCPv1") != NULL) { - /* - * Ok, the client supports direct TCP connection - * Try to create a listening port - */ - MsnDirectConn *dc; - - dc = msn_dc_new(slpcall); - if (ntype == DC_NONCE_PLAIN) { - /* There is only one nonce for plain auth. */ - dc->nonce_type = ntype; - memcpy(dc->nonce, nonce, 16); - } else if (ntype == DC_NONCE_SHA1) { - /* Each side has a nonce in SHA1 auth. */ - dc->nonce_type = ntype; - strncpy(dc->remote_nonce, nonce, 36); - dc->remote_nonce[36] = '\0'; - } - - dc->listen_data = purple_network_listen_range( - 0, 0, - SOCK_STREAM, - msn_dc_listen_socket_created_cb, - dc - ); - - if (dc->listen_data == NULL) { - /* Listen socket creation failed */ - - purple_debug_info("msn", "got_invite: listening failed\n"); - - if (dc->nonce_type != DC_NONCE_PLAIN) - msn_slp_send_ok(slpcall, branch, - "application/x-msnmsgr-transrespbody", - "Bridge: TCPv1\r\n" - "Listening: false\r\n" - "Hashed-Nonce: {00000000-0000-0000-0000-000000000000}\r\n" - "\r\n"); - else - msn_slp_send_ok(slpcall, branch, - "application/x-msnmsgr-transrespbody", - "Bridge: TCPv1\r\n" - "Listening: false\r\n" - "Nonce: {00000000-0000-0000-0000-000000000000}\r\n" - "\r\n"); - - } else { - /* - * Listen socket created successfully. - * Don't send anything here because we don't know the parameters - * of the created socket yet. msn_dc_send_ok will be called from - * the callback function: dc_listen_socket_created_cb - */ - purple_debug_info("msn", "got_invite: listening socket created\n"); - - dc->send_connection_info_msg_cb = msn_dc_send_ok; - slpcall->wait_for_socket = TRUE; - } - - } else { - /* - * Invalid direct connect invitation or - * TCP connection is not supported. - */ - } - - g_free(nonce); - g_free(bridges); - } - else if (!strcmp(type, "application/x-msnmsgr-transrespbody")) - { - /* A direct connection negotiation response */ - msn_slp_process_transresp(slpcall, content); - } -} - -static void -got_ok(MsnSlpCall *slpcall, - const char *type, const char *content) -{ - g_return_if_fail(slpcall != NULL); - g_return_if_fail(type != NULL); - - if (!strcmp(type, "application/x-msnmsgr-sessionreqbody")) - { - char *content; - char *header; - char *nonce = NULL; - MsnSession *session = slpcall->slplink->session; - MsnSlpMessage *msg; - MsnDirectConn *dc; - MsnUser *user; - - if (!purple_account_get_bool(session->account, "direct_connect", TRUE)) { - /* Don't attempt a direct connection if disabled. */ - msn_slpcall_session_init(slpcall); - return; - } - - if (slpcall->slplink->dc != NULL) { - /* If we already have an established direct connection - * then just start the transfer. - */ - msn_slpcall_session_init(slpcall); - return; - } - - user = msn_userlist_find_user(session->userlist, - slpcall->slplink->remote_user); - if (!user || !(user->clientid & 0xF0000000)) { - /* Just start a normal SB transfer. */ - msn_slpcall_session_init(slpcall); - return; - } - - /* Try direct file transfer by sending a second INVITE */ - dc = msn_dc_new(slpcall); - g_free(slpcall->branch); - slpcall->branch = rand_guid(); - - dc->listen_data = purple_network_listen_range( - 0, 0, - SOCK_STREAM, - msn_dc_listen_socket_created_cb, - dc - ); - - header = g_strdup_printf( - "INVITE MSNMSGR:%s MSNSLP/1.0", - slpcall->slplink->remote_user - ); - - if (dc->nonce_type == DC_NONCE_SHA1) - nonce = g_strdup_printf("Hashed-Nonce: {%s}\r\n", dc->nonce_hash); - - if (dc->listen_data == NULL) { - /* Listen socket creation failed */ - purple_debug_info("msn", "got_ok: listening failed\n"); - - content = g_strdup_printf( - "Bridges: TCPv1\r\n" - "NetID: %u\r\n" - "Conn-Type: IP-Restrict-NAT\r\n" - "UPnPNat: false\r\n" - "ICF: false\r\n" - "%s" - "\r\n", - - rand() % G_MAXUINT32, - nonce ? nonce : "" - ); - - } else { - /* Listen socket created successfully. */ - purple_debug_info("msn", "got_ok: listening socket created\n"); - - content = g_strdup_printf( - "Bridges: TCPv1\r\n" - "NetID: 0\r\n" - "Conn-Type: Direct-Connect\r\n" - "UPnPNat: false\r\n" - "ICF: false\r\n" - "%s" - "\r\n", - - nonce ? nonce : "" - ); - } - - msg = msn_slpmsg_sip_new( - slpcall, - 0, - header, - slpcall->branch, - "application/x-msnmsgr-transreqbody", - content - ); - msg->info = "DC INVITE"; - msg->text_body = TRUE; - g_free(nonce); - g_free(header); - g_free(content); - - msn_slplink_queue_slpmsg(slpcall->slplink, msg); - } - else if (!strcmp(type, "application/x-msnmsgr-transreqbody")) - { - /* Do we get this? */ - purple_debug_info("msn", "OK with transreqbody\n"); - } - else if (!strcmp(type, "application/x-msnmsgr-transrespbody")) - { - msn_slp_process_transresp(slpcall, content); - } -} - -static void -got_error(MsnSlpCall *slpcall, - const char *error, const char *type, const char *content) -{ - /* It's not valid. Kill this off. */ - purple_debug_error("msn", "Received non-OK result: %s\n", - error ? error : "Unknown"); - - if (type && !strcmp(type, "application/x-msnmsgr-transreqbody")) { - MsnDirectConn *dc = slpcall->slplink->dc; - if (dc) { - msn_dc_fallback_to_sb(dc); - return; - } - } - - slpcall->wasted = TRUE; -} - -static MsnSlpCall * -msn_slp_sip_recv(MsnSlpLink *slplink, const char *body) -{ - MsnSlpCall *slpcall; - - if (body == NULL) - { - purple_debug_warning("msn", "received bogus message\n"); - return NULL; - } - - if (!strncmp(body, "INVITE", strlen("INVITE"))) - { - /* This is an INVITE request */ - char *branch; - char *call_id; - char *content; - char *content_type; - - /* From: <msnmsgr:buddy@hotmail.com> */ -#if 0 - slpcall->remote_user = get_token(body, "From: <msnmsgr:", ">\r\n"); -#endif - - branch = get_token(body, ";branch={", "}"); - - call_id = get_token(body, "Call-ID: {", "}"); - -#if 0 - long content_len = -1; - - temp = get_token(body, "Content-Length: ", "\r\n"); - if (temp != NULL) - content_len = atoi(temp); - g_free(temp); -#endif - content_type = get_token(body, "Content-Type: ", "\r\n"); - - content = get_token(body, "\r\n\r\n", NULL); - - slpcall = NULL; - if (branch && call_id) - { - slpcall = msn_slplink_find_slp_call(slplink, call_id); - if (slpcall) - { - g_free(slpcall->branch); - slpcall->branch = g_strdup(branch); - got_invite(slpcall, branch, content_type, content); - } - else if (content_type && content) - { - slpcall = msn_slpcall_new(slplink); - slpcall->id = g_strdup(call_id); - got_invite(slpcall, branch, content_type, content); - } - } - - g_free(call_id); - g_free(branch); - g_free(content_type); - g_free(content); - } - else if (!strncmp(body, "MSNSLP/1.0 ", strlen("MSNSLP/1.0 "))) - { - /* This is a response */ - char *content; - char *content_type; - /* Make sure this is "OK" */ - const char *status = body + strlen("MSNSLP/1.0 "); - char *call_id; - - call_id = get_token(body, "Call-ID: {", "}"); - slpcall = msn_slplink_find_slp_call(slplink, call_id); - g_free(call_id); - - g_return_val_if_fail(slpcall != NULL, NULL); - - content_type = get_token(body, "Content-Type: ", "\r\n"); - - content = get_token(body, "\r\n\r\n", NULL); - - if (strncmp(status, "200 OK", 6)) - { - char *error = NULL; - const char *c; - - /* Eww */ - if ((c = strchr(status, '\r')) || (c = strchr(status, '\n')) || - (c = strchr(status, '\0'))) - { - size_t len = c - status; - error = g_strndup(status, len); - } - - got_error(slpcall, error, content_type, content); - g_free(error); - - } else { - /* Everything's just dandy */ - got_ok(slpcall, content_type, content); - } - - g_free(content_type); - g_free(content); - } - else if (!strncmp(body, "BYE", strlen("BYE"))) - { - /* This is a BYE request */ - char *call_id; - - call_id = get_token(body, "Call-ID: {", "}"); - slpcall = msn_slplink_find_slp_call(slplink, call_id); - g_free(call_id); - - if (slpcall != NULL) - slpcall->wasted = TRUE; - - /* msn_slpcall_destroy(slpcall); */ - } - else - slpcall = NULL; - - return slpcall; -} - -MsnSlpCall * -msn_slp_process_msg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg) -{ - MsnSlpCall *slpcall; - const guchar *body; - gsize body_len; - guint32 session_id; - guint32 flags; - - slpcall = NULL; - body = slpmsg->buffer; - body_len = msn_p2p_info_get_offset(slpmsg->p2p_info); - - session_id = msn_p2p_info_get_session_id(slpmsg->p2p_info); - flags = msn_p2p_info_get_flags(slpmsg->p2p_info); - - if (flags == P2P_NO_FLAG || flags == P2P_WLM2009_COMP) - { - char *body_str; - - if (session_id == 64) - { - /* This is for handwritten messages (Ink) */ - GError *error = NULL; - gsize bytes_read, bytes_written; - - body_str = g_convert((const gchar *)body, body_len / 2, - "UTF-8", "UTF-16LE", - &bytes_read, &bytes_written, &error); - body_len -= bytes_read + 2; - body += bytes_read + 2; - if (body_str == NULL - || body_len <= 0 - || strstr(body_str, "image/gif") == NULL) - { - if (error != NULL) { - purple_debug_error("msn", - "Unable to convert Ink header from UTF-16 to UTF-8: %s\n", - error->message); - g_error_free(error); - } - else - purple_debug_error("msn", - "Received Ink in unknown format\n"); - g_free(body_str); - return NULL; - } - g_free(body_str); - - body_str = g_convert((const gchar *)body, body_len / 2, - "UTF-8", "UTF-16LE", - &bytes_read, &bytes_written, &error); - if (!body_str) - { - if (error != NULL) { - purple_debug_error("msn", - "Unable to convert Ink body from UTF-16 to UTF-8: %s\n", - error->message); - g_error_free(error); - } - else - purple_debug_error("msn", - "Received Ink in unknown format\n"); - return NULL; - } - - msn_switchboard_show_ink(slpmsg->slplink->swboard, - slplink->remote_user, - body_str); - } - else - { - body_str = g_strndup((const char *)body, body_len); - slpcall = msn_slp_sip_recv(slplink, body_str); - } - g_free(body_str); - } - else if (msn_p2p_msg_is_data(slpmsg->p2p_info)) - { - slpcall = msn_slplink_find_slp_call_with_session_id(slplink, session_id); - - if (slpcall != NULL) - { - if (slpcall->timer) { - purple_timeout_remove(slpcall->timer); - slpcall->timer = 0; - } - - if (slpcall->cb) - slpcall->cb(slpcall, body, body_len); - - slpcall->wasted = TRUE; - } - } - else if (msn_p2p_info_is_ack(slpmsg->p2p_info)) - { - /* Acknowledgement of previous message. Don't do anything currently. */ - } - else - purple_debug_warning("msn", "Unprocessed SLP message with flags 0x%04x\n", - flags); - - return slpcall; -} diff --git a/libpurple/protocols/msn/slpcall.h b/libpurple/protocols/msn/slpcall.h deleted file mode 100644 index 3cfacf0473..0000000000 --- a/libpurple/protocols/msn/slpcall.h +++ /dev/null @@ -1,98 +0,0 @@ -/** - * @file slpcall.h SLP Call functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_SLPCALL_H -#define MSN_SLPCALL_H - -typedef struct _MsnSlpCall MsnSlpCall; - -typedef enum -{ - MSN_SLPCALL_ANY, - MSN_SLPCALL_DC -} MsnSlpCallType; - -#include "internal.h" - -#include "slplink.h" - -/* The official client seems to timeout slp calls after 5 minutes */ -#define MSN_SLPCALL_TIMEOUT 300 - -struct _MsnSlpCall -{ - /* Our parent slplink */ - MsnSlpLink *slplink; - - MsnSlpCallType type; - - /* Call-ID */ - char *id; - char *branch; - - long session_id; - long app_id; - - gboolean pending; /**< A flag that states if we should wait for this - slpcall to start and do not time out. */ - gboolean progress; /**< A flag that states if there has been progress since - the last time out. */ - gboolean wasted; /**< A flag that states if this slpcall is going to be - destroyed. */ - gboolean started; /**< A flag that states if this slpcall's session has - been initiated. */ - - gboolean wait_for_socket; - - void (*progress_cb)(MsnSlpCall *slpcall, - gsize total_length, gsize len); - void (*session_init_cb)(MsnSlpCall *slpcall); - - /* Can be checksum, or smile */ - char *data_info; - - PurpleXfer *xfer; - union { - GByteArray *incoming_data; - struct { - gsize len; - const guchar *data; - } outgoing; - } u; - MsnSlpMessage *xfer_msg; /* A dirty hack */ - - MsnSlpCb cb; - void (*end_cb)(MsnSlpCall *slpcall, MsnSession *session); - - guint timer; -}; - -MsnSlpCall *msn_slpcall_new(MsnSlpLink *slplink); -void msn_slpcall_init(MsnSlpCall *slpcall, MsnSlpCallType type); -void msn_slpcall_session_init(MsnSlpCall *slpcall); -void msn_slpcall_destroy(MsnSlpCall *slpcall); -void msn_slpcall_invite(MsnSlpCall *slpcall, const char *euf_guid, - MsnP2PAppId app_id, const char *context); -void msn_slpcall_close(MsnSlpCall *slpcall); - -#endif /* MSN_SLPCALL_H */ diff --git a/libpurple/protocols/msn/slplink.c b/libpurple/protocols/msn/slplink.c deleted file mode 100644 index c2b5453f46..0000000000 --- a/libpurple/protocols/msn/slplink.c +++ /dev/null @@ -1,646 +0,0 @@ -/** - * @file slplink.c MSNSLP Link support - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "debug.h" - -#include "msn.h" -#include "slplink.h" -#include "slpmsg_part.h" - -#include "sbconn.h" -#include "switchboard.h" -#include "slp.h" -#include "p2p.h" - -#ifdef MSN_DEBUG_SLP_FILES -static int m_sc = 0; -static int m_rc = 0; - -static void -debug_part_to_file(MsnSlpMessage *msg, gboolean send) -{ - char *tmp; - char *dir; - char *data; - int c; - gsize data_size; - - dir = send ? "send" : "recv"; - c = send ? m_sc++ : m_rc++; - tmp = g_strdup_printf("%s/msntest/%s/%03d", purple_user_dir(), dir, c); - data = msn_slpmsg_serialize(msg, &data_size); - if (!purple_util_write_data_to_file_absolute(tmp, data, data_size)) - { - purple_debug_error("msn", "could not save debug file\n"); - } - g_free(tmp); -} -#endif - -/************************************************************************** - * Main - **************************************************************************/ - -static MsnSlpLink * -msn_slplink_new(MsnSession *session, const char *username) -{ - MsnSlpLink *slplink; - - g_return_val_if_fail(session != NULL, NULL); - - slplink = g_new0(MsnSlpLink, 1); - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "slplink_new: slplink(%p)\n", slplink); - - slplink->session = session; - slplink->slp_seq_id = rand() % 0xFFFFFF00 + 4; - - slplink->remote_user = g_strdup(username); - slplink->p2p_version = MSN_P2P_VERSION_ONE; - - slplink->slp_msg_queue = g_queue_new(); - - session->slplinks = - g_list_append(session->slplinks, slplink); - - return msn_slplink_ref(slplink); -} - -static void -msn_slplink_destroy(MsnSlpLink *slplink) -{ - MsnSession *session; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "slplink_destroy: slplink(%p)\n", slplink); - - if (slplink->swboard != NULL) { - slplink->swboard->slplinks = g_list_remove(slplink->swboard->slplinks, slplink); - slplink->swboard = NULL; - } - - session = slplink->session; - - if (slplink->dc != NULL) { - slplink->dc->slplink = NULL; - msn_dc_destroy(slplink->dc); - slplink->dc = NULL; - } - - while (slplink->slp_calls != NULL) - msn_slpcall_destroy(slplink->slp_calls->data); - - g_queue_free(slplink->slp_msg_queue); - - session->slplinks = - g_list_remove(session->slplinks, slplink); - - g_free(slplink->remote_user); - - g_free(slplink); -} - -MsnSlpLink * -msn_slplink_ref(MsnSlpLink *slplink) -{ - g_return_val_if_fail(slplink != NULL, NULL); - - slplink->refs++; - if (purple_debug_is_verbose()) - purple_debug_info("msn", "slplink ref (%p)[%d]\n", slplink, slplink->refs); - - return slplink; -} - -void -msn_slplink_unref(MsnSlpLink *slplink) -{ - g_return_if_fail(slplink != NULL); - - slplink->refs--; - if (purple_debug_is_verbose()) - purple_debug_info("msn", "slplink unref (%p)[%d]\n", slplink, slplink->refs); - - if (slplink->refs == 0) - msn_slplink_destroy(slplink); -} - -MsnSlpLink * -msn_session_find_slplink(MsnSession *session, const char *who) -{ - GList *l; - - for (l = session->slplinks; l != NULL; l = l->next) - { - MsnSlpLink *slplink; - - slplink = l->data; - - if (!strcmp(slplink->remote_user, who)) - return slplink; - } - - return NULL; -} - -MsnSlpLink * -msn_session_get_slplink(MsnSession *session, const char *username) -{ - MsnSlpLink *slplink; - - g_return_val_if_fail(session != NULL, NULL); - g_return_val_if_fail(username != NULL, NULL); - - slplink = msn_session_find_slplink(session, username); - - if (slplink == NULL) - slplink = msn_slplink_new(session, username); - - return slplink; -} - -void -msn_slplink_add_slpcall(MsnSlpLink *slplink, MsnSlpCall *slpcall) -{ - if (slplink->swboard != NULL) - slplink->swboard->flag |= MSN_SB_FLAG_FT; - - slplink->slp_calls = g_list_append(slplink->slp_calls, slpcall); - - /* - if (slplink->dc != NULL && slplink->dc->state == DC_STATE_ESTABLISHED) - msn_dc_ref(slplink->dc); - */ -} - -void -msn_slplink_remove_slpcall(MsnSlpLink *slplink, MsnSlpCall *slpcall) -{ - /* - if (slplink->dc != NULL && slplink->dc->state == DC_STATE_ESTABLISHED) - msn_dc_unref(slplink->dc); - */ - - slplink->slp_calls = g_list_remove(slplink->slp_calls, slpcall); - - /* The slplink has no slpcalls in it, release it from MSN_SB_FLAG_FT. - * If nothing else is using it then this might cause swboard to be - * destroyed. */ - if (slplink->slp_calls == NULL && slplink->swboard != NULL) { - slplink->swboard->slplinks = g_list_remove(slplink->swboard->slplinks, slplink); - msn_switchboard_release(slplink->swboard, MSN_SB_FLAG_FT); - slplink->swboard = NULL; - } - - if (slplink->dc != NULL) { - if ((slplink->dc->state != DC_STATE_ESTABLISHED && slplink->dc->slpcall == slpcall) - || (slplink->slp_calls == NULL)) { - /* The DC is not established and its corresponding slpcall is dead, - * or the slplink has no slpcalls in it and no longer needs the DC. - */ - slplink->dc->slplink = NULL; - msn_dc_destroy(slplink->dc); - slplink->dc = NULL; - } - } -} - -MsnSlpCall * -msn_slplink_find_slp_call(MsnSlpLink *slplink, const char *id) -{ - GList *l; - MsnSlpCall *slpcall; - - if (!id) - return NULL; - - for (l = slplink->slp_calls; l != NULL; l = l->next) - { - slpcall = l->data; - - if (slpcall->id && !strcmp(slpcall->id, id)) - return slpcall; - } - - return NULL; -} - -MsnSlpCall * -msn_slplink_find_slp_call_with_session_id(MsnSlpLink *slplink, long id) -{ - GList *l; - MsnSlpCall *slpcall; - - for (l = slplink->slp_calls; l != NULL; l = l->next) - { - slpcall = l->data; - - if (slpcall->session_id == id) - return slpcall; - } - - return NULL; -} - -MsnP2PVersion -msn_slplink_get_p2p_version(MsnSlpLink *slplink) -{ - return slplink->p2p_version; -} - -static void -msn_slplink_send_part(MsnSlpLink *slplink, MsnSlpMessagePart *part) -{ - if (slplink->dc != NULL && slplink->dc->state == DC_STATE_ESTABLISHED) - { - msn_dc_enqueue_part(slplink->dc, part); - } - else - { - msn_sbconn_send_part(slplink, part); - } -} - -void -msn_slplink_send_msgpart(MsnSlpLink *slplink, MsnSlpMessage *slpmsg) -{ - MsnSlpMessagePart *part; - MsnP2PInfo *info; - gsize real_size; - size_t len = 0; - guint64 offset; - - /* Maybe we will want to create a new msg for this slpmsg instead of - * reusing the same one all the time. */ - info = slpmsg->p2p_info; - part = msn_slpmsgpart_new(msn_p2p_info_dup(info)); - part->ack_data = slpmsg; - - real_size = msn_p2p_info_is_ack(info) ? 0 : slpmsg->size; - - offset = msn_p2p_info_get_offset(info); - if (offset < real_size) - { - if (slpmsg->slpcall && slpmsg->slpcall->xfer && purple_xfer_get_type(slpmsg->slpcall->xfer) == PURPLE_XFER_SEND && - purple_xfer_get_status(slpmsg->slpcall->xfer) == PURPLE_XFER_STATUS_STARTED) - { - len = MIN(MSN_SBCONN_MAX_SIZE, slpmsg->slpcall->u.outgoing.len); - msn_slpmsgpart_set_bin_data(part, slpmsg->slpcall->u.outgoing.data, len); - } - else - { - len = slpmsg->size - offset; - - if (len > MSN_SBCONN_MAX_SIZE) - len = MSN_SBCONN_MAX_SIZE; - - msn_slpmsgpart_set_bin_data(part, slpmsg->buffer + offset, len); - } - - msn_p2p_info_set_length(slpmsg->p2p_info, len); - } - -#if 0 - /* TODO: port this function to SlpMessageParts */ - if (purple_debug_is_verbose()) - msn_message_show_readable(msg, slpmsg->info, slpmsg->text_body); -#endif - -#ifdef MSN_DEBUG_SLP_FILES - debug_part_to_file(slpmsg, TRUE); -#endif - - slpmsg->parts = g_list_append(slpmsg->parts, part); - msn_slplink_send_part(slplink, part); - - - if (msn_p2p_msg_is_data(info) && slpmsg->slpcall != NULL) - { - slpmsg->slpcall->progress = TRUE; - - if (slpmsg->slpcall->progress_cb != NULL) - { - slpmsg->slpcall->progress_cb(slpmsg->slpcall, slpmsg->size, - len); - } - } - - /* slpmsg->offset += len; */ -} - -static void -msn_slplink_release_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg) -{ - MsnP2PInfo *info; - guint32 flags; - - info = slpmsg->p2p_info; - - flags = msn_p2p_info_get_flags(info); - if (flags == P2P_NO_FLAG) - { - msn_p2p_info_set_ack_id(info, rand() % 0xFFFFFF00); - } - else if (msn_p2p_msg_is_data(info)) - { - MsnSlpCall *slpcall; - slpcall = slpmsg->slpcall; - - g_return_if_fail(slpcall != NULL); - msn_p2p_info_set_session_id(info, slpcall->session_id); - msn_p2p_info_set_app_id(info, slpcall->app_id); - msn_p2p_info_set_ack_id(info, rand() % 0xFFFFFF00); - } - - msn_p2p_info_set_id(info, slpmsg->id); - - msn_p2p_info_set_total_size(info, slpmsg->size); - - msn_slplink_send_msgpart(slplink, slpmsg); -} - -void -msn_slplink_queue_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg) -{ - g_return_if_fail(slpmsg != NULL); - - slpmsg->id = slplink->slp_seq_id++; - - g_queue_push_tail(slplink->slp_msg_queue, slpmsg); -} - -void -msn_slplink_send_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg) -{ - slpmsg->id = slplink->slp_seq_id++; - - msn_slplink_release_slpmsg(slplink, slpmsg); -} - -void -msn_slplink_send_queued_slpmsgs(MsnSlpLink *slplink) -{ - MsnSlpMessage *slpmsg; - - /* Send the queued msgs in the order they were created */ - while ((slpmsg = g_queue_pop_head(slplink->slp_msg_queue)) != NULL) - { - msn_slplink_release_slpmsg(slplink, slpmsg); - } -} - -static void -msn_slplink_send_ack(MsnSlpLink *slplink, MsnP2PInfo *info) -{ - MsnSlpMessage *slpmsg = msn_slpmsg_ack_new(slplink, info); - - msn_slplink_send_slpmsg(slplink, slpmsg); - msn_slpmsg_destroy(slpmsg); -} - -static MsnSlpMessage * -msn_slplink_message_find(MsnSlpLink *slplink, guint32 session_id, long id) -{ - GList *e; - - for (e = slplink->slp_msgs; e != NULL; e = e->next) - { - MsnSlpMessage *slpmsg = e->data; - - if ((msn_p2p_info_get_session_id(slpmsg->p2p_info) == session_id) && (slpmsg->id == id)) - return slpmsg; - } - - return NULL; -} - -static MsnSlpMessage * -init_first_msg(MsnSlpLink *slplink, MsnP2PInfo *info) -{ - MsnSlpMessage *slpmsg; - guint32 session_id; - - slpmsg = msn_slpmsg_new(slplink, NULL); - slpmsg->id = msn_p2p_info_get_id(info); - session_id = msn_p2p_info_get_session_id(info); - slpmsg->size = msn_p2p_info_get_total_size(info); - msn_p2p_info_init_first(slpmsg->p2p_info, info); - - if (session_id) - { - slpmsg->slpcall = msn_slplink_find_slp_call_with_session_id(slplink, session_id); - if (slpmsg->slpcall != NULL) - { - if (msn_p2p_msg_is_data(info)) - { - PurpleXfer *xfer = slpmsg->slpcall->xfer; - if (xfer != NULL) - { - slpmsg->ft = TRUE; - slpmsg->slpcall->xfer_msg = slpmsg; - - purple_xfer_ref(xfer); - purple_xfer_start(xfer, -1, NULL, 0); - - if (xfer->data == NULL) { - purple_xfer_unref(xfer); - msn_slpmsg_destroy(slpmsg); - g_return_val_if_reached(NULL); - } else { - purple_xfer_unref(xfer); - } - } - } - } - } - if (!slpmsg->ft && slpmsg->size) - { - slpmsg->buffer = g_try_malloc(slpmsg->size); - if (slpmsg->buffer == NULL) - { - purple_debug_error("msn", "Failed to allocate buffer for slpmsg\n"); - msn_slpmsg_destroy(slpmsg); - return NULL; - } - } - - return slpmsg; -} - -static void -process_complete_msg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg, MsnP2PInfo *info) -{ - MsnSlpCall *slpcall; - - slpcall = msn_slp_process_msg(slplink, slpmsg); - - if (slpcall == NULL) { - msn_slpmsg_destroy(slpmsg); - return; - } - - purple_debug_info("msn", "msn_slplink_process_msg: slpmsg complete\n"); - - if (msn_p2p_info_require_ack(slpmsg->p2p_info)) - { - /* Release all the messages and send the ACK */ - - if (slpcall->wait_for_socket) { - /* - * Save ack for later because we have to send - * a 200 OK message to the previous direct connect - * invitation before ACK but the listening socket isn't - * created yet. - */ - purple_debug_info("msn", "msn_slplink_process_msg: save ACK\n"); - - slpcall->slplink->dc->prev_ack = msn_slpmsg_ack_new(slplink, info); - } else if (!slpcall->wasted) { - purple_debug_info("msn", "msn_slplink_process_msg: send ACK\n"); - - msn_slplink_send_ack(slplink, info); - msn_slplink_send_queued_slpmsgs(slplink); - } - } - - msn_slpmsg_destroy(slpmsg); - - if (!slpcall->wait_for_socket && slpcall->wasted) - msn_slpcall_destroy(slpcall); -} - -static void -slpmsg_add_part(MsnSlpMessage *slpmsg, MsnSlpMessagePart *part) -{ - if (slpmsg->ft) { - slpmsg->slpcall->u.incoming_data = - g_byte_array_append(slpmsg->slpcall->u.incoming_data, (const guchar *)part->buffer, part->size); - purple_xfer_prpl_ready(slpmsg->slpcall->xfer); - } - else if (slpmsg->size && slpmsg->buffer) { - guint64 offset = msn_p2p_info_get_offset(part->info); - if (G_MAXSIZE - part->size < offset - || (offset + part->size) > slpmsg->size - || msn_p2p_info_get_offset(slpmsg->p2p_info) != offset) { - purple_debug_error("msn", - "Oversized slpmsg - msgsize=%" G_GSIZE_FORMAT " offset=%" G_GUINT64_FORMAT " len=%" G_GSIZE_FORMAT "\n", - (gsize)slpmsg->size, offset, (gsize)part->size); - g_return_if_reached(); - } else { - memcpy(slpmsg->buffer + offset, part->buffer, part->size); - msn_p2p_info_set_offset(slpmsg->p2p_info, offset + part->size); - } - } -} - -void -msn_slplink_process_msg(MsnSlpLink *slplink, MsnSlpMessagePart *part) -{ - MsnSlpMessage *slpmsg; - MsnP2PInfo *info; - - info = part->info; - - if (!msn_p2p_info_is_valid(info)) - { - /* We seem to have received a bad header */ - purple_debug_warning("msn", "Total size listed in SLP binary header " - "was less than length of this particular message. This " - "should not happen. Dropping message.\n"); - return; - } - - if (msn_p2p_info_is_first(info)) - slpmsg = init_first_msg(slplink, info); - else { - guint32 session_id, id; - session_id = msn_p2p_info_get_session_id(info); - id = msn_p2p_info_get_id(info); - slpmsg = msn_slplink_message_find(slplink, session_id, id); - if (slpmsg == NULL) - { - /* Probably the transfer was cancelled */ - purple_debug_error("msn", "Couldn't find slpmsg\n"); - return; - } - } - - slpmsg_add_part(slpmsg, part); - - if (msn_p2p_msg_is_data(slpmsg->p2p_info) && slpmsg->slpcall != NULL) - { - slpmsg->slpcall->progress = TRUE; - - if (slpmsg->slpcall->progress_cb != NULL) - { - slpmsg->slpcall->progress_cb(slpmsg->slpcall, slpmsg->size, - part->size); - } - } - -#if 0 - if (slpmsg->buffer == NULL) - return; -#endif - - /* All the pieces of the slpmsg have been received */ - if (msn_p2p_info_is_final(info)) - process_complete_msg(slplink, slpmsg, info); - - /* NOTE: The slpmsg will be destroyed in process_complete_msg or left in - the slplink until fully received. Don't free it here! - */ -} - -void -msn_slplink_request_object(MsnSlpLink *slplink, - const char *info, - MsnSlpCb cb, - MsnSlpEndCb end_cb, - const MsnObject *obj) -{ - MsnSlpCall *slpcall; - char *msnobj_data; - char *msnobj_base64; - - g_return_if_fail(slplink != NULL); - g_return_if_fail(obj != NULL); - - msnobj_data = msn_object_to_string(obj); - msnobj_base64 = purple_base64_encode((const guchar *)msnobj_data, strlen(msnobj_data)); - g_free(msnobj_data); - - slpcall = msn_slpcall_new(slplink); - msn_slpcall_init(slpcall, MSN_SLPCALL_ANY); - - slpcall->data_info = g_strdup(info); - slpcall->cb = cb; - slpcall->end_cb = end_cb; - - msn_slpcall_invite(slpcall, MSN_OBJ_GUID, P2P_APPID_OBJ, msnobj_base64); - - g_free(msnobj_base64); -} diff --git a/libpurple/protocols/msn/slplink.h b/libpurple/protocols/msn/slplink.h deleted file mode 100644 index 2ce34e1032..0000000000 --- a/libpurple/protocols/msn/slplink.h +++ /dev/null @@ -1,98 +0,0 @@ -/** - * @file slplink.h MSNSLP Link support - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_SLPLINK_H -#define MSN_SLPLINK_H - -typedef struct _MsnSlpLink MsnSlpLink; - -#include "directconn.h" -#include "session.h" -#include "slpcall.h" -#include "slpmsg.h" -#include "switchboard.h" - -typedef void (*MsnSlpCb)(MsnSlpCall *slpcall, - const guchar *data, gsize size); -typedef void (*MsnSlpEndCb)(MsnSlpCall *slpcall, MsnSession *session); - -struct _MsnSlpLink -{ - MsnSession *session; - MsnSwitchBoard *swboard; - MsnDirectConn *dc; - - guint refs; - - char *remote_user; - MsnP2PVersion p2p_version; - - int slp_seq_id; - - GList *slp_calls; - GList *slp_msgs; - - GQueue *slp_msg_queue; -}; - -MsnSlpLink *msn_slplink_ref(MsnSlpLink *slplink); -void msn_slplink_unref(MsnSlpLink *slplink); - -/** - * @return An MsnSlpLink for the given user, or NULL if there is no - * existing MsnSlpLink. - */ -MsnSlpLink *msn_session_find_slplink(MsnSession *session, - const char *who); - -/** - * @return An MsnSlpLink for the given user. One will be created if - * it does not already exist. - */ -MsnSlpLink *msn_session_get_slplink(MsnSession *session, const char *username); - -void msn_slplink_add_slpcall(MsnSlpLink *slplink, MsnSlpCall *slpcall); -void msn_slplink_remove_slpcall(MsnSlpLink *slplink, MsnSlpCall *slpcall); -MsnSlpCall *msn_slplink_find_slp_call(MsnSlpLink *slplink, - const char *id); -MsnSlpCall *msn_slplink_find_slp_call_with_session_id(MsnSlpLink *slplink, long id); -MsnP2PVersion msn_slplink_get_p2p_version(MsnSlpLink *slplink); - -void msn_slplink_queue_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg); -void msn_slplink_send_slpmsg(MsnSlpLink *slplink, - MsnSlpMessage *slpmsg); -void msn_slplink_send_queued_slpmsgs(MsnSlpLink *slplink); -void msn_slplink_process_msg(MsnSlpLink *slplink, MsnSlpMessagePart *part); - -/* Only exported for msn_xfer_write */ -void msn_slplink_send_msgpart(MsnSlpLink *slplink, MsnSlpMessage *slpmsg); - -void msn_slplink_request_object(MsnSlpLink *slplink, - const char *info, - MsnSlpCb cb, - MsnSlpEndCb end_cb, - const MsnObject *obj); - -MsnSlpCall *msn_slp_process_msg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg); - -#endif /* MSN_SLPLINK_H */ diff --git a/libpurple/protocols/msn/slpmsg.c b/libpurple/protocols/msn/slpmsg.c deleted file mode 100644 index 4a75e3abc9..0000000000 --- a/libpurple/protocols/msn/slpmsg.c +++ /dev/null @@ -1,309 +0,0 @@ -/** - * @file slpmsg.c SLP Message functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "debug.h" - -#include "slpmsg.h" -#include "slpmsg_part.h" -#include "slplink.h" - -/************************************************************************** - * SLP Message - **************************************************************************/ - -MsnSlpMessage * -msn_slpmsg_new(MsnSlpLink *slplink, MsnSlpCall *slpcall) -{ - MsnSlpMessage *slpmsg; - MsnP2PVersion p2p; - - g_return_val_if_fail(slplink != NULL, NULL); - - slpmsg = g_new0(MsnSlpMessage, 1); - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "slpmsg new (%p)\n", slpmsg); - - msn_slpmsg_set_slplink(slpmsg, slplink); - slpmsg->slpcall = slpcall; - - p2p = msn_slplink_get_p2p_version(slplink); - slpmsg->p2p_info = msn_p2p_info_new(p2p); - - return slpmsg; -} - -void -msn_slpmsg_destroy(MsnSlpMessage *slpmsg) -{ - MsnSlpLink *slplink; - GList *cur; - - g_return_if_fail(slpmsg != NULL); - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "slpmsg destroy (%p)\n", slpmsg); - - slplink = slpmsg->slplink; - - purple_imgstore_unref(slpmsg->img); - - /* We don't want to free the data of the PurpleStoredImage, - * but to avoid code duplication, it's sharing buffer. */ - if (slpmsg->img == NULL) - g_free(slpmsg->buffer); - - for (cur = slpmsg->parts; cur != NULL; cur = g_list_delete_link(cur, cur)) - { - /* Something is pointing to this slpmsg, so we should remove that - * pointer to prevent a crash. */ - /* Ex: a user goes offline and after that we receive an ACK */ - - MsnSlpMessagePart *part = cur->data; - - part->ack_cb = NULL; - part->nak_cb = NULL; - part->ack_data = NULL; - msn_slpmsgpart_unref(part); - } - - slplink->slp_msgs = g_list_remove(slplink->slp_msgs, slpmsg); - - msn_p2p_info_free(slpmsg->p2p_info); - - g_free(slpmsg); -} - -void -msn_slpmsg_set_slplink(MsnSlpMessage *slpmsg, MsnSlpLink *slplink) -{ - g_return_if_fail(slplink != NULL); - - slpmsg->slplink = slplink; - - slplink->slp_msgs = - g_list_append(slplink->slp_msgs, slpmsg); -} - -void -msn_slpmsg_set_body(MsnSlpMessage *slpmsg, const char *body, - long long size) -{ - /* We can only have one data source at a time. */ - g_return_if_fail(slpmsg->buffer == NULL); - g_return_if_fail(slpmsg->img == NULL); - g_return_if_fail(slpmsg->ft == FALSE); - - if (body != NULL) - slpmsg->buffer = g_memdup(body, size); - else - slpmsg->buffer = g_new0(guchar, size); - - slpmsg->size = size; -} - -void -msn_slpmsg_set_image(MsnSlpMessage *slpmsg, PurpleStoredImage *img) -{ - /* We can only have one data source at a time. */ - g_return_if_fail(slpmsg->buffer == NULL); - g_return_if_fail(slpmsg->img == NULL); - g_return_if_fail(slpmsg->ft == FALSE); - - slpmsg->img = purple_imgstore_ref(img); - slpmsg->buffer = (guchar *)purple_imgstore_get_data(img); - slpmsg->size = purple_imgstore_get_size(img); -} - - -MsnSlpMessage * -msn_slpmsg_sip_new(MsnSlpCall *slpcall, int cseq, - const char *header, const char *branch, - const char *content_type, const char *content) -{ - MsnSlpLink *slplink; - PurpleAccount *account; - MsnSlpMessage *slpmsg; - char *body; - gsize body_len; - gsize content_len; - - g_return_val_if_fail(slpcall != NULL, NULL); - g_return_val_if_fail(header != NULL, NULL); - - slplink = slpcall->slplink; - account = slplink->session->account; - - /* Let's remember that "content" should end with a 0x00 */ - - content_len = (content != NULL) ? strlen(content) + 1 : 0; - - body = g_strdup_printf( - "%s\r\n" - "To: <msnmsgr:%s>\r\n" - "From: <msnmsgr:%s>\r\n" - "Via: MSNSLP/1.0/TLP ;branch={%s}\r\n" - "CSeq: %d\r\n" - "Call-ID: {%s}\r\n" - "Max-Forwards: 0\r\n" - "Content-Type: %s\r\n" - "Content-Length: %" G_GSIZE_FORMAT "\r\n" - "\r\n", - header, - slplink->remote_user, - purple_account_get_username(account), - branch, - cseq, - slpcall->id, - content_type, - content_len); - - body_len = strlen(body); - - if (content_len > 0) - { - body_len += content_len; - body = g_realloc(body, body_len); - g_strlcat(body, content, body_len); - } - - slpmsg = msn_slpmsg_new(slplink, slpcall); - msn_slpmsg_set_body(slpmsg, body, body_len); - - g_free(body); - - return slpmsg; -} - -MsnSlpMessage *msn_slpmsg_ack_new(MsnSlpLink *slplink, MsnP2PInfo *ack_info) -{ - MsnSlpMessage *slpmsg; - MsnP2PInfo *new_info; - - slpmsg = msn_slpmsg_new(slplink, NULL); - - new_info = slpmsg->p2p_info; - msn_p2p_info_create_ack(ack_info, new_info); - slpmsg->size = msn_p2p_info_get_total_size(ack_info); - slpmsg->info = "SLP ACK"; - - return slpmsg; -} - -MsnSlpMessage *msn_slpmsg_obj_new(MsnSlpCall *slpcall, PurpleStoredImage *img) -{ - MsnSlpMessage *slpmsg; - - slpmsg = msn_slpmsg_new(slpcall->slplink, slpcall); - msn_p2p_info_set_flags(slpmsg->p2p_info, P2P_MSN_OBJ_DATA); - slpmsg->info = "SLP DATA"; - - msn_slpmsg_set_image(slpmsg, img); - - return slpmsg; -} - -MsnSlpMessage *msn_slpmsg_dataprep_new(MsnSlpCall *slpcall) -{ - MsnSlpMessage *slpmsg; - - slpmsg = msn_slpmsg_new(slpcall->slplink, slpcall); - - msn_p2p_info_set_session_id(slpmsg->p2p_info, slpcall->session_id); - msn_slpmsg_set_body(slpmsg, NULL, 4); - slpmsg->info = "SLP DATA PREP"; - - return slpmsg; - -} - -MsnSlpMessage *msn_slpmsg_file_new(MsnSlpCall *slpcall, size_t size) -{ - MsnSlpMessage *slpmsg; - - slpmsg = msn_slpmsg_new(slpcall->slplink, slpcall); - - msn_p2p_info_set_flags(slpmsg->p2p_info, P2P_FILE_DATA); - slpmsg->info = "SLP FILE"; - slpmsg->size = size; - - return slpmsg; -} - -char *msn_slpmsg_serialize(MsnSlpMessage *slpmsg, size_t *ret_size) -{ - char *header; - char *footer; - char *base; - char *tmp; - size_t header_size, footer_size; - - header = msn_p2p_header_to_wire(slpmsg->p2p_info, &header_size); - footer = msn_p2p_footer_to_wire(slpmsg->p2p_info, &footer_size); - - base = g_malloc(header_size + slpmsg->size + footer_size); - tmp = base; - - /* Copy header */ - memcpy(tmp, header, header_size); - tmp += header_size; - - /* Copy body */ - memcpy(tmp, slpmsg->buffer, slpmsg->size); - tmp += slpmsg->size; - - /* Copy footer */ - memcpy(tmp, footer, footer_size); - tmp += footer_size; - - *ret_size = tmp - base; - - g_free(header); - g_free(footer); - - return base; -} - -void msn_slpmsg_show_readable(MsnSlpMessage *slpmsg) -{ - GString *str; - - str = g_string_new(NULL); - - msn_p2p_info_to_string(slpmsg->p2p_info, str); - - if (purple_debug_is_verbose() && slpmsg->buffer != NULL) { - g_string_append_len(str, (gchar*)slpmsg->buffer, slpmsg->size); - - if (slpmsg->buffer[slpmsg->size - 1] == '\0') { - str->len--; - g_string_append(str, " 0x00"); - } - g_string_append(str, "\r\n"); - - } - - purple_debug_info("msn", "SlpMessage %s:\n{%s}\n", slpmsg->info, str->str); -} diff --git a/libpurple/protocols/msn/slpmsg.h b/libpurple/protocols/msn/slpmsg.h deleted file mode 100644 index 45c755ebc5..0000000000 --- a/libpurple/protocols/msn/slpmsg.h +++ /dev/null @@ -1,150 +0,0 @@ -/** - * @file slpmsg.h SLP Message functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef _MSN_SLPMSG_H_ -#define _MSN_SLPMSG_H_ - -typedef struct _MsnSlpMessage MsnSlpMessage; - -#include "imgstore.h" - -#include "slpcall.h" -#include "slplink.h" -#include "session.h" -#include "p2p.h" - -#include "slp.h" - -/** - * A SLP Message This contains everything that we will need to send a SLP - * Message even if has to be sent in several parts. - */ -struct _MsnSlpMessage -{ - MsnSlpCall *slpcall; /**< The slpcall to which this slp message belongs (if applicable). */ - MsnSlpLink *slplink; /**< The slplink through which this slp message is being sent. */ - MsnSession *session; - - MsnP2PInfo *p2p_info; - - long id; - - gboolean ft; - PurpleStoredImage *img; - guchar *buffer; - - /** - * This is the size of buffer, unless this is an outgoing file transfer, - * in which case this is the size of the file. - */ - gsize size; - - GList *parts; /**< A list with the SlpMsgParts */ - - const char *info; - gboolean text_body; -}; - -/** - * Creates a new slp message - * - * @param slplink The slplink through which this slp message will be sent. - * If it's set to NULL, it is a temporary SlpMessage. - * @return The created slp message. - */ -MsnSlpMessage *msn_slpmsg_new(MsnSlpLink *slplink, MsnSlpCall *slpcall); - -/** - * Destroys a slp message - * - * @param slpmsg The slp message to destory. - */ -void msn_slpmsg_destroy(MsnSlpMessage *slpmsg); - -/** - * Relate this SlpMessage with an existing SlpLink - * - * @param slplink The SlpLink that will send this message. - */ -void msn_slpmsg_set_slplink(MsnSlpMessage *slpmsg, MsnSlpLink *slplink); - -void msn_slpmsg_set_body(MsnSlpMessage *slpmsg, const char *body, - long long size); -void msn_slpmsg_set_image(MsnSlpMessage *slpmsg, PurpleStoredImage *img); -MsnSlpMessage * msn_slpmsg_sip_new(MsnSlpCall *slpcall, int cseq, - const char *header, - const char *branch, - const char *content_type, - const char *content); - -/** - * Create a new SLP Ack message - * - * @param header the value of the header in this slpmsg. - * - * @return A new SlpMessage with ACK headers - */ -MsnSlpMessage *msn_slpmsg_ack_new(MsnSlpLink *slplink, MsnP2PInfo *info); - -/** - * Create a new SLP message for MsnObject data. - * - * @param slpcall The slpcall that manages this message. - * @param img The image to be sent in this message. - * - * @return A new SlpMessage with MsnObject info. - */ -MsnSlpMessage *msn_slpmsg_obj_new(MsnSlpCall *slpcall, PurpleStoredImage *img); - -/** - * Create a new SLP message for data preparation. - * - * @param slpcall The slpcall that manages this message. - * - * @return A new SlpMessage with data preparation info. - */ -MsnSlpMessage *msn_slpmsg_dataprep_new(MsnSlpCall *slpcall); - -/** - * Create a new SLP message for File transfer. - * - * @param slpcall The slpcall that manages this message. - * @param size The size of the file being transsmited. - * - * @return A new SlpMessage with the file transfer info. - */ -MsnSlpMessage *msn_slpmsg_file_new(MsnSlpCall *slpcall, size_t size); - -/** - * Serialize the MsnSlpMessage in a way it can be used to be transmited - * - * @param slpmsg The MsnSlpMessage. - * @param ret_size The size of the buffer cointaining the message. - * - * @return a buffer with the serialized data. - */ -char *msn_slpmsg_serialize(MsnSlpMessage *slpmsg, size_t *ret_size); - -void msn_slpmsg_show_readable(MsnSlpMessage *slpmsg); - -#endif /* _MSN_SLPMSG_H_ */ diff --git a/libpurple/protocols/msn/slpmsg_part.c b/libpurple/protocols/msn/slpmsg_part.c deleted file mode 100644 index add959a73a..0000000000 --- a/libpurple/protocols/msn/slpmsg_part.c +++ /dev/null @@ -1,232 +0,0 @@ -/** - * @file slpmsg_part.c MSNSLP Parts - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "debug.h" - -#include "slpmsg.h" -#include "slpmsg_part.h" - -MsnSlpMessagePart *msn_slpmsgpart_new(MsnP2PInfo *info) -{ - MsnSlpMessagePart *part; - - part = g_new0(MsnSlpMessagePart, 1); - - part->info = info; - - part->ack_cb = msn_slpmsgpart_ack; - part->nak_cb = msn_slpmsgpart_nak; - - return msn_slpmsgpart_ref(part); -} - -MsnSlpMessagePart * -msn_slpmsgpart_new_from_data(MsnP2PVersion p2p, const char *data, size_t data_len) -{ - MsnSlpMessagePart *part; - MsnP2PInfo *info; - size_t len; - int body_len; - - info = msn_p2p_info_new(p2p); - - /* Extract the binary SLP header */ - len = msn_p2p_header_from_wire(info, data, data_len); - if (len == 0) { - msn_p2p_info_free(info); - return NULL; - } - data += len; - part = msn_slpmsgpart_new(info); - - /* Extract the body */ - body_len = data_len - len - P2P_PACKET_FOOTER_SIZE; - /* msg->body_len = msg->msnslp_header.length; */ - - if (body_len > 0) { - part->size = body_len; - part->buffer = g_malloc(body_len); - memcpy(part->buffer, data, body_len); - data += body_len; - } - - /* Extract the footer */ - if (body_len >= 0) - msn_p2p_footer_from_wire(part->info, data); - - return part; -} - -static void msn_slpmsgpart_destroy(MsnSlpMessagePart *part) -{ - g_free(part->info); - g_free(part->buffer); - - g_free(part); - -} - -MsnSlpMessagePart *msn_slpmsgpart_ref(MsnSlpMessagePart *part) -{ - g_return_val_if_fail(part != NULL, NULL); - part->ref_count++; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "part ref (%p)[%u]\n", part, part->ref_count); - - return part; -} - -void msn_slpmsgpart_unref(MsnSlpMessagePart *part) -{ - g_return_if_fail(part != NULL); - g_return_if_fail(part->ref_count > 0); - - part->ref_count--; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "part unref (%p)[%u]\n", part, part->ref_count); - - if (part->ref_count == 0) { - msn_slpmsgpart_destroy(part); - } -} - -void msn_slpmsgpart_set_bin_data(MsnSlpMessagePart *part, const void *data, size_t len) -{ - g_return_if_fail(part != NULL); - - g_free(part->buffer); - - if (data != NULL && len > 0) { - part->buffer = g_malloc(len + 1); - memcpy(part->buffer, data, len); - part->buffer[len] = '\0'; - part->size = len; - } else { - part->buffer = NULL; - part->size = 0; - } - -} - -char *msn_slpmsgpart_serialize(MsnSlpMessagePart *part, size_t *ret_size) -{ - char *header; - char *footer; - char *base; - char *tmp; - size_t header_size, footer_size; - - header = msn_p2p_header_to_wire(part->info, &header_size); - footer = msn_p2p_footer_to_wire(part->info, &footer_size); - - base = g_malloc(header_size + part->size + footer_size); - tmp = base; - - /* Copy header */ - memcpy(tmp, header, header_size); - tmp += header_size; - - /* Copy body */ - memcpy(tmp, part->buffer, part->size); - tmp += part->size; - - /* Copy footer */ - memcpy(tmp, footer, footer_size); - tmp += footer_size; - - *ret_size = tmp - base; - - g_free(header); - g_free(footer); - - return base; -} - -/* We have received the message ack */ -void -msn_slpmsgpart_ack(MsnSlpMessagePart *part, void *data) -{ - MsnSlpMessage *slpmsg; - guint64 offset; - gsize real_size; - - slpmsg = data; - - real_size = msn_p2p_info_is_ack(slpmsg->p2p_info) ? 0 : slpmsg->size; - - offset = msn_p2p_info_get_offset(slpmsg->p2p_info); - offset += msn_p2p_info_get_length(part->info); - msn_p2p_info_set_offset(slpmsg->p2p_info, offset); - - slpmsg->parts = g_list_remove(slpmsg->parts, part); - msn_slpmsgpart_unref(part); - - if (offset < real_size) - { - if (slpmsg->slpcall->xfer && purple_xfer_get_status(slpmsg->slpcall->xfer) == PURPLE_XFER_STATUS_STARTED) - { - slpmsg->slpcall->xfer_msg = slpmsg; - purple_xfer_prpl_ready(slpmsg->slpcall->xfer); - } - else - msn_slplink_send_msgpart(slpmsg->slplink, slpmsg); - } - else - { - /* The whole message has been sent */ - if (msn_p2p_msg_is_data(slpmsg->p2p_info)) - { - if (slpmsg->slpcall != NULL) - { - if (slpmsg->slpcall->cb) - slpmsg->slpcall->cb(slpmsg->slpcall, - NULL, 0); - } - } - } -} - -/* We have received the message nak. */ -void -msn_slpmsgpart_nak(MsnSlpMessagePart *part, void *data) -{ - MsnSlpMessage *slpmsg; - - slpmsg = data; - - msn_slplink_send_msgpart(slpmsg->slplink, slpmsg); - - slpmsg->parts = g_list_remove(slpmsg->parts, part); - msn_slpmsgpart_unref(part); -} - -void -msn_slpmsgpart_to_string(MsnSlpMessagePart *part, GString *str) -{ - msn_p2p_info_to_string(part->info, str); -} - diff --git a/libpurple/protocols/msn/slpmsg_part.h b/libpurple/protocols/msn/slpmsg_part.h deleted file mode 100644 index 460eaa6986..0000000000 --- a/libpurple/protocols/msn/slpmsg_part.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - * @file slpmsg_part.h MSNSLP Parts - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef MSN_SLPMSG_PART_H -#define MSN_SLPMSG_PART_H - -#include "p2p.h" - -typedef struct _MsnSlpMessagePart MsnSlpMessagePart; -typedef void (*MsnSlpPartCb)(MsnSlpMessagePart *part, void *data); - -struct _MsnSlpMessagePart -{ - guint ref_count; - - MsnP2PInfo *info; - - MsnSlpPartCb ack_cb; - MsnSlpPartCb nak_cb; - void *ack_data; - - guchar *buffer; - size_t size; -}; - -MsnSlpMessagePart *msn_slpmsgpart_new(MsnP2PInfo *info); - -MsnSlpMessagePart *msn_slpmsgpart_new_from_data(MsnP2PVersion p2p, const char *data, size_t data_len); - -MsnSlpMessagePart *msn_slpmsgpart_ref(MsnSlpMessagePart *part); - -void msn_slpmsgpart_unref(MsnSlpMessagePart *part); - -void msn_slpmsgpart_set_bin_data(MsnSlpMessagePart *part, const void *data, size_t len); - -char *msn_slpmsgpart_serialize(MsnSlpMessagePart *part, size_t *ret_size); - -void msn_slpmsgpart_ack(MsnSlpMessagePart *part, void *data); - -void msn_slpmsgpart_nak(MsnSlpMessagePart *part, void *data); - -void msn_slpmsgpart_to_string(MsnSlpMessagePart *part, GString *str); - -#endif /* MSN_SLPMSG_PART_H */ - diff --git a/libpurple/protocols/msn/soap.c b/libpurple/protocols/msn/soap.c deleted file mode 100644 index 4cb571e51f..0000000000 --- a/libpurple/protocols/msn/soap.c +++ /dev/null @@ -1,688 +0,0 @@ -/** - * @file soap.c - * Functions relating to SOAP connections. - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "internal.h" - -#include "soap.h" - -#include "session.h" - -#include "debug.h" -#include "xmlnode.h" - -#include <glib.h> -#if !defined(_WIN32) || !defined(_WINERROR_) -#include <error.h> -#endif - -#define SOAP_TIMEOUT (5 * 60) - -typedef struct _MsnSoapRequest { - char *path; - MsnSoapMessage *message; - gboolean secure; - MsnSoapCallback cb; - gpointer cb_data; -} MsnSoapRequest; - -typedef struct _MsnSoapConnection { - MsnSession *session; - char *host; - - time_t last_used; - PurpleSslConnection *ssl; - gboolean connected; - - guint event_handle; - guint run_timer; - GString *buf; - gsize handled_len; - gsize body_len; - int response_code; - gboolean headers_done; - gboolean close_when_done; - - MsnSoapMessage *message; - - GQueue *queue; - MsnSoapRequest *current_request; -} MsnSoapConnection; - -static gboolean msn_soap_connection_run(gpointer data); - -static MsnSoapConnection * -msn_soap_connection_new(MsnSession *session, const char *host) -{ - MsnSoapConnection *conn = g_new0(MsnSoapConnection, 1); - conn->session = session; - conn->host = g_strdup(host); - conn->queue = g_queue_new(); - return conn; -} - -static void -msn_soap_message_destroy(MsnSoapMessage *message) -{ - g_slist_foreach(message->headers, (GFunc)g_free, NULL); - g_slist_free(message->headers); - g_free(message->action); - if (message->xml) - xmlnode_free(message->xml); - g_free(message); -} - -static void -msn_soap_request_destroy(MsnSoapRequest *req, gboolean keep_message) -{ - g_free(req->path); - if (!keep_message) - msn_soap_message_destroy(req->message); - g_free(req); -} - -static void -msn_soap_connection_sanitize(MsnSoapConnection *conn, gboolean disconnect) -{ - if (conn->event_handle) { - purple_input_remove(conn->event_handle); - conn->event_handle = 0; - } - - if (conn->run_timer) { - purple_timeout_remove(conn->run_timer); - conn->run_timer = 0; - } - - if (conn->message) { - msn_soap_message_destroy(conn->message); - conn->message = NULL; - } - - if (conn->buf) { - g_string_free(conn->buf, TRUE); - conn->buf = NULL; - } - - if (conn->ssl && (disconnect || conn->close_when_done)) { - purple_ssl_close(conn->ssl); - conn->ssl = NULL; - } - - if (conn->current_request) { - msn_soap_request_destroy(conn->current_request, FALSE); - conn->current_request = NULL; - } -} - -static void -msn_soap_connection_destroy_foreach_cb(gpointer item, gpointer data) -{ - MsnSoapRequest *req = item; - - req->cb(req->message, NULL, req->cb_data); - - msn_soap_request_destroy(req, FALSE); -} - -static void -msn_soap_connection_destroy(MsnSoapConnection *conn) -{ - if (conn->current_request) { - MsnSoapRequest *req = conn->current_request; - conn->current_request = NULL; - msn_soap_connection_destroy_foreach_cb(req, conn); - } - - msn_soap_connection_sanitize(conn, TRUE); - g_queue_foreach(conn->queue, msn_soap_connection_destroy_foreach_cb, conn); - g_queue_free(conn->queue); - - g_free(conn->host); - g_free(conn); -} - -static gboolean -msn_soap_cleanup_each(gpointer key, gpointer value, gpointer data) -{ - MsnSoapConnection *conn = value; - time_t *t = data; - - if ((*t - conn->last_used) > SOAP_TIMEOUT * 2) { - purple_debug_info("soap", "cleaning up soap conn %p\n", conn); - return TRUE; - } - - return FALSE; -} - -static gboolean -msn_soap_cleanup_for_session(gpointer data) -{ - MsnSession *sess = data; - time_t t = time(NULL); - - purple_debug_info("soap", "session cleanup timeout\n"); - - if (sess->soap_table) { - g_hash_table_foreach_remove(sess->soap_table, msn_soap_cleanup_each, - &t); - - if (g_hash_table_size(sess->soap_table) != 0) - return TRUE; - } - - sess->soap_cleanup_handle = 0; - return FALSE; -} - -static MsnSoapConnection * -msn_soap_get_connection(MsnSession *session, const char *host) -{ - MsnSoapConnection *conn = NULL; - - if (session->soap_table) { - conn = g_hash_table_lookup(session->soap_table, host); - } else { - session->soap_table = g_hash_table_new_full(g_str_hash, g_str_equal, - NULL, (GDestroyNotify)msn_soap_connection_destroy); - } - - if (session->soap_cleanup_handle == 0) - session->soap_cleanup_handle = purple_timeout_add_seconds(SOAP_TIMEOUT, - msn_soap_cleanup_for_session, session); - - if (conn == NULL) { - conn = msn_soap_connection_new(session, host); - g_hash_table_insert(session->soap_table, conn->host, conn); - } - - conn->last_used = time(NULL); - - return conn; -} - -static void -msn_soap_connection_handle_next(MsnSoapConnection *conn) -{ - msn_soap_connection_sanitize(conn, FALSE); - - conn->run_timer = purple_timeout_add(0, msn_soap_connection_run, conn); -} - -static void -msn_soap_message_send_internal(MsnSession *session, MsnSoapMessage *message, - const char *host, const char *path, gboolean secure, - MsnSoapCallback cb, gpointer cb_data, gboolean first) -{ - MsnSoapConnection *conn = msn_soap_get_connection(session, host); - MsnSoapRequest *req = g_new0(MsnSoapRequest, 1); - - req->path = g_strdup(path); - req->message = message; - req->secure = secure; - req->cb = cb; - req->cb_data = cb_data; - - if (first) { - g_queue_push_head(conn->queue, req); - } else { - g_queue_push_tail(conn->queue, req); - } - - if (conn->run_timer == 0) - conn->run_timer = purple_timeout_add(0, msn_soap_connection_run, - conn); -} - -void -msn_soap_message_send(MsnSession *session, MsnSoapMessage *message, - const char *host, const char *path, gboolean secure, - MsnSoapCallback cb, gpointer cb_data) -{ - g_return_if_fail(message != NULL); - g_return_if_fail(cb != NULL); - - msn_soap_message_send_internal(session, message, host, path, secure, - cb, cb_data, FALSE); -} - -static gboolean -msn_soap_handle_redirect(MsnSoapConnection *conn, const char *url) -{ - char *host; - char *path; - - if (purple_url_parse(url, &host, NULL, &path, NULL, NULL)) { - MsnSoapRequest *req = conn->current_request; - conn->current_request = NULL; - - msn_soap_message_send_internal(conn->session, req->message, host, path, - req->secure, req->cb, req->cb_data, TRUE); - - msn_soap_request_destroy(req, TRUE); - - g_free(host); - g_free(path); - - return TRUE; - } - - return FALSE; -} - -static gboolean -msn_soap_handle_body(MsnSoapConnection *conn, MsnSoapMessage *response) -{ - xmlnode *body = xmlnode_get_child(response->xml, "Body"); - xmlnode *fault = xmlnode_get_child(response->xml, "Fault"); - - if (fault) { - xmlnode *faultcode = xmlnode_get_child(fault, "faultcode"); - - if (faultcode != NULL) { - char *faultdata = xmlnode_get_data(faultcode); - - if (faultdata && g_str_equal(faultdata, "psf:Redirect")) { - xmlnode *url = xmlnode_get_child(fault, "redirectUrl"); - - if (url) { - char *urldata = xmlnode_get_data(url); - if (urldata) - msn_soap_handle_redirect(conn, urldata); - g_free(urldata); - } - - g_free(faultdata); - msn_soap_message_destroy(response); - return TRUE; - } else if (faultdata && g_str_equal(faultdata, "wsse:FailedAuthentication")) { - xmlnode *reason = xmlnode_get_child(fault, "faultstring"); - char *reasondata = NULL; - - if (reason) - reasondata = xmlnode_get_data(reason); - - msn_soap_connection_sanitize(conn, TRUE); - msn_session_set_error(conn->session, MSN_ERROR_AUTH, - reasondata); - - g_free(reasondata); - g_free(faultdata); - msn_soap_message_destroy(response); - return FALSE; - } - - g_free(faultdata); - } - } - - if (fault || body) { - if (conn->current_request) { - MsnSoapRequest *request = conn->current_request; - conn->current_request = NULL; - request->cb(request->message, response, - request->cb_data); - msn_soap_request_destroy(request, FALSE); - } - msn_soap_message_destroy(response); - } - - return TRUE; -} - -static void -msn_soap_message_add_header(MsnSoapMessage *message, - const char *name, const char *value) -{ - char *header = g_strdup_printf("%s: %s\r\n", name, value); - - message->headers = g_slist_prepend(message->headers, header); -} - -static void -msn_soap_process(MsnSoapConnection *conn) -{ - gboolean handled = FALSE; - char *cursor; - char *linebreak; - - cursor = conn->buf->str + conn->handled_len; - - if (!conn->headers_done) { - while ((linebreak = strstr(cursor, "\r\n")) != NULL) { - conn->handled_len = linebreak - conn->buf->str + 2; - - if (conn->response_code == 0) { - if (sscanf(cursor, "HTTP/1.1 %d", &conn->response_code) != 1) { - /* something horribly wrong */ - purple_ssl_close(conn->ssl); - conn->ssl = NULL; - handled = TRUE; - break; - } else if (conn->response_code == 503 && conn->session->login_step < MSN_LOGIN_STEP_END) { - msn_soap_connection_sanitize(conn, TRUE); - msn_session_set_error(conn->session, MSN_ERROR_SERV_UNAVAILABLE, NULL); - return; - } - } else if (cursor == linebreak) { - /* blank line */ - conn->headers_done = TRUE; - cursor = conn->buf->str + conn->handled_len; - break; - } else { - char *line = g_strndup(cursor, linebreak - cursor); - char *sep = strstr(line, ": "); - char *key = line; - char *value; - - if (sep == NULL) { - purple_debug_info("soap", "ignoring malformed line: %s\n", line); - g_free(line); - goto loop_end; - } - - value = sep + 2; - *sep = '\0'; - msn_soap_message_add_header(conn->message, key, value); - - if ((conn->response_code == 301 || conn->response_code == 300) - && strcmp(key, "Location") == 0) { - - msn_soap_handle_redirect(conn, value); - - handled = TRUE; - g_free(line); - break; - } else if (conn->response_code == 401 && - strcmp(key, "WWW-Authenticate") == 0) { - char *error = strstr(value, "cbtxt="); - - if (error) { - error += strlen("cbtxt="); - } - - msn_soap_connection_sanitize(conn, TRUE); - msn_session_set_error(conn->session, MSN_ERROR_AUTH, - error ? purple_url_decode(error) : NULL); - - g_free(line); - return; - } else if (strcmp(key, "Content-Length") == 0) { - if (sscanf(value, "%" G_GSIZE_FORMAT, &(conn->body_len)) != 1) - purple_debug_error("soap", "Unable to parse Content-Length\n"); - } else if (strcmp(key, "Connection") == 0) { - if (strcmp(value, "close") == 0) { - conn->close_when_done = TRUE; - } - } - g_free(line); - } - - loop_end: - cursor = conn->buf->str + conn->handled_len; - } - } - - if (!handled && conn->headers_done) { - if (conn->buf->len - conn->handled_len >= - conn->body_len) { - xmlnode *node = xmlnode_from_str(cursor, conn->body_len); - - if (node == NULL) { - purple_debug_info("soap", "Malformed SOAP response: %s\n", - cursor); - } else { - MsnSoapMessage *message = conn->message; - conn->message = NULL; - message->xml = node; - - if (!msn_soap_handle_body(conn, message)) { - return; - } - } - - msn_soap_connection_handle_next(conn); - } - - return; - } - - if (handled) { - msn_soap_connection_handle_next(conn); - } -} - -static void -msn_soap_read_cb(gpointer data, gint fd, PurpleInputCondition cond) -{ - MsnSoapConnection *conn = data; - int count = 0, cnt, perrno; - /* This buffer needs to be larger than any packets received from - login.live.com or Adium will fail to receive the packet - (something weird with the login.live.com server). With NSS it works - fine, so I believe it's some bug with OS X */ - char buf[16 * 1024]; - gsize cursor; - - if (conn->message == NULL) { - conn->message = msn_soap_message_new(NULL, NULL); - } - - if (conn->buf == NULL) { - conn->buf = g_string_new_len(buf, 0); - } - - cursor = conn->buf->len; - while ((cnt = purple_ssl_read(conn->ssl, buf, sizeof(buf))) > 0) { - purple_debug_info("soap", "read %d bytes\n", cnt); - count += cnt; - g_string_append_len(conn->buf, buf, cnt); - } - - perrno = errno; - if (cnt < 0 && perrno != EAGAIN) - purple_debug_info("soap", "read: %s\n", g_strerror(perrno)); - - if (conn->current_request && conn->current_request->secure && - !purple_debug_is_unsafe()) - purple_debug_misc("soap", "Received secure request.\n"); - else if (count != 0) - purple_debug_misc("soap", "current %s\n", conn->buf->str + cursor); - - /* && count is necessary for Adium, on OS X the last read always - return an error, so we want to proceed anyway. See #5212 for - discussion on this and the above buffer size issues */ - if(cnt < 0 && errno == EAGAIN && count == 0) - return; - - /* msn_soap_process could alter errno */ - msn_soap_process(conn); - - if ((cnt < 0 && perrno != EAGAIN) || cnt == 0) { - /* It's possible msn_soap_process closed the ssl connection */ - if (conn->ssl) { - purple_ssl_close(conn->ssl); - conn->ssl = NULL; - msn_soap_connection_handle_next(conn); - } - } -} - -static gboolean -msn_soap_write_cb_internal(gpointer data, gint fd, PurpleInputCondition cond, - gboolean initial) -{ - MsnSoapConnection *conn = data; - int written; - - if (cond != PURPLE_INPUT_WRITE) - return TRUE; - - written = purple_ssl_write(conn->ssl, conn->buf->str + conn->handled_len, - conn->buf->len - conn->handled_len); - - if (written < 0 && errno == EAGAIN) - return TRUE; - else if (written <= 0) { - purple_ssl_close(conn->ssl); - conn->ssl = NULL; - if (!initial) - msn_soap_connection_handle_next(conn); - return FALSE; - } - - conn->handled_len += written; - - if (conn->handled_len < conn->buf->len) - return TRUE; - - /* we are done! */ - g_string_free(conn->buf, TRUE); - conn->buf = NULL; - conn->handled_len = 0; - conn->body_len = 0; - conn->response_code = 0; - conn->headers_done = FALSE; - conn->close_when_done = FALSE; - - purple_input_remove(conn->event_handle); - conn->event_handle = purple_input_add(conn->ssl->fd, PURPLE_INPUT_READ, - msn_soap_read_cb, conn); - return TRUE; -} - -static void -msn_soap_write_cb(gpointer data, gint fd, PurpleInputCondition cond) -{ - msn_soap_write_cb_internal(data, fd, cond, FALSE); -} - -static void -msn_soap_error_cb(PurpleSslConnection *ssl, PurpleSslErrorType error, - gpointer data) -{ - MsnSoapConnection *conn = data; - - /* sslconn already frees the connection in case of error */ - conn->ssl = NULL; - - g_hash_table_remove(conn->session->soap_table, conn->host); -} - -static void -msn_soap_connected_cb(gpointer data, PurpleSslConnection *ssl, - PurpleInputCondition cond) -{ - MsnSoapConnection *conn = data; - - conn->connected = TRUE; - - if (conn->run_timer == 0) - conn->run_timer = purple_timeout_add(0, msn_soap_connection_run, conn); -} - -MsnSoapMessage * -msn_soap_message_new(const char *action, xmlnode *xml) -{ - MsnSoapMessage *message = g_new0(MsnSoapMessage, 1); - - message->action = g_strdup(action); - message->xml = xml; - - return message; -} - -static gboolean -msn_soap_connection_run(gpointer data) -{ - MsnSoapConnection *conn = data; - MsnSoapRequest *req = g_queue_peek_head(conn->queue); - - conn->run_timer = 0; - - if (req) { - if (conn->ssl == NULL) { - conn->ssl = purple_ssl_connect(conn->session->account, conn->host, - 443, msn_soap_connected_cb, msn_soap_error_cb, conn); - } else if (conn->connected) { - int len = -1; - char *body = xmlnode_to_str(req->message->xml, &len); - GSList *iter; - - g_queue_pop_head(conn->queue); - - conn->buf = g_string_new(""); - - g_string_append_printf(conn->buf, - "POST /%s HTTP/1.1\r\n" - "SOAPAction: %s\r\n" - "Content-Type:text/xml; charset=utf-8\r\n" - "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n" - "Accept: */*\r\n" - "Host: %s\r\n" - "Content-Length: %d\r\n" - "Connection: Keep-Alive\r\n" - "Cache-Control: no-cache\r\n", - req->path, req->message->action ? req->message->action : "", - conn->host, len); - - for (iter = req->message->headers; iter; iter = iter->next) { - g_string_append(conn->buf, (char *)iter->data); - g_string_append(conn->buf, "\r\n"); - } - - g_string_append(conn->buf, "\r\n"); - g_string_append(conn->buf, body); - - if (req->secure && !purple_debug_is_unsafe()) - purple_debug_misc("soap", "Sending secure request.\n"); - else - purple_debug_misc("soap", "%s\n", conn->buf->str); - - conn->handled_len = 0; - conn->current_request = req; - - if (conn->event_handle) - purple_input_remove(conn->event_handle); - conn->event_handle = purple_input_add(conn->ssl->fd, - PURPLE_INPUT_WRITE, msn_soap_write_cb, conn); - if (!msn_soap_write_cb_internal(conn, conn->ssl->fd, PURPLE_INPUT_WRITE, TRUE)) { - /* Not connected => reconnect and retry */ - purple_debug_info("soap", "not connected, reconnecting\n"); - - conn->connected = FALSE; - conn->current_request = NULL; - msn_soap_connection_sanitize(conn, FALSE); - - g_queue_push_head(conn->queue, req); - conn->run_timer = purple_timeout_add(0, msn_soap_connection_run, conn); - } - - g_free(body); - } - } - - return FALSE; -} diff --git a/libpurple/protocols/msn/soap.h b/libpurple/protocols/msn/soap.h deleted file mode 100644 index de4d50e3dd..0000000000 --- a/libpurple/protocols/msn/soap.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * @file soap.h - * header file for SOAP connection related process - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ -#ifndef MSN_SOAP_H -#define MSN_SOAP_H - -typedef struct _MsnSoapMessage MsnSoapMessage; - -#include <glib.h> - -#include "xmlnode.h" - -#include "session.h" -#include "sslconn.h" - -typedef void (*MsnSoapCallback)(MsnSoapMessage *request, - MsnSoapMessage *response, gpointer cb_data); - -struct _MsnSoapMessage { - char *action; - xmlnode *xml; - GSList *headers; -}; - -MsnSoapMessage *msn_soap_message_new(const char *action, xmlnode *xml); - -void msn_soap_message_send(MsnSession *session, MsnSoapMessage *message, - const char *host, const char *path, gboolean secure, - MsnSoapCallback cb, gpointer cb_data); - -#endif /* MSN_SOAP_H */ diff --git a/libpurple/protocols/msn/state.c b/libpurple/protocols/msn/state.c deleted file mode 100644 index 7157cfcd13..0000000000 --- a/libpurple/protocols/msn/state.c +++ /dev/null @@ -1,315 +0,0 @@ -/** - * @file state.c State functions and definitions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "debug.h" - -#include "core.h" - -#include "notification.h" -#include "state.h" - -static const char *away_text[] = -{ - N_("Available"), - N_("Available"), - N_("Busy"), - N_("Idle"), - N_("Be Right Back"), - N_("Away From Computer"), - N_("On The Phone"), - N_("Out To Lunch"), - N_("Available"), - N_("Available") -}; - -/* - * WLM media PSM info build prcedure - * - * Result can like: - * <CurrentMedia>\0Music\01\0{0} - {1}\0Song Title\0Song Artist\0Song Album\0\0</CurrentMedia>\ - * <CurrentMedia>\0Games\01\0Playing {0}\0Game Name\0</CurrentMedia>\ - * <CurrentMedia>\0Office\01\0Office Message\0Office App Name\0</CurrentMedia>" - */ -static char * -msn_build_psm(const char *psmstr,const char *mediastr, const char *guidstr, guint protocol_ver) -{ - xmlnode *dataNode,*psmNode,*mediaNode,*guidNode; - char *result; - int length; - - dataNode = xmlnode_new("Data"); - - psmNode = xmlnode_new("PSM"); - if(psmstr != NULL){ - xmlnode_insert_data(psmNode, psmstr, -1); - } - xmlnode_insert_child(dataNode, psmNode); - - mediaNode = xmlnode_new("CurrentMedia"); - if(mediastr != NULL){ - xmlnode_insert_data(mediaNode, mediastr, -1); - } - xmlnode_insert_child(dataNode, mediaNode); - - guidNode = xmlnode_new("MachineGuid"); - if(guidstr != NULL){ - xmlnode_insert_data(guidNode, guidstr, -1); - } - xmlnode_insert_child(dataNode, guidNode); - - if (protocol_ver >= 16) { - /* TODO: What is this for? */ - xmlnode *ddpNode = xmlnode_new("DDP"); - xmlnode_insert_child(dataNode, ddpNode); - } - - result = xmlnode_to_str(dataNode, &length); - xmlnode_free(dataNode); - return result; -} - -/* get the CurrentMedia info from the XML node */ -char * -msn_get_currentmedia(xmlnode *payloadNode) -{ - xmlnode *currentmediaNode; - char *currentmedia; - - purple_debug_info("msn", "Get CurrentMedia\n"); - currentmediaNode = xmlnode_get_child(payloadNode, "CurrentMedia"); - if (currentmediaNode == NULL) { - purple_debug_info("msn", "No CurrentMedia Node\n"); - return NULL; - } - currentmedia = xmlnode_get_data(currentmediaNode); - - return currentmedia; -} - -/* Get the PSM info from the XML node */ -char * -msn_get_psm(xmlnode *payloadNode) -{ - xmlnode *psmNode; - char *psm; - - purple_debug_info("msn", "msn get PSM\n"); - psmNode = xmlnode_get_child(payloadNode, "PSM"); - if (psmNode == NULL) { - purple_debug_info("msn", "No PSM status Node\n"); - return NULL; - } - psm = xmlnode_get_data(psmNode); - - return psm; -} - -static char * -create_media_string(PurplePresence *presence) -{ - const char *title, *game, *office; - char *ret; - PurpleStatus *status = purple_presence_get_status(presence, "tune"); - if (!status || !purple_status_is_active(status)) - return NULL; - - title = purple_status_get_attr_string(status, PURPLE_TUNE_TITLE); - game = purple_status_get_attr_string(status, "game"); - office = purple_status_get_attr_string(status, "office"); - - if (title && *title) { - const char *artist = purple_status_get_attr_string(status, PURPLE_TUNE_ARTIST); - const char *album = purple_status_get_attr_string(status, PURPLE_TUNE_ALBUM); - ret = g_strdup_printf("WMP\\0Music\\01\\0{0}%s%s\\0%s\\0%s\\0%s\\0", - artist ? " - {1}" : "", - album ? " ({2})" : "", - title, - artist ? artist : "", - album ? album : ""); - } - else if (game && *game) - ret = g_strdup_printf("\\0Games\\01\\0Playing {0}\\0%s\\0", game); - else if (office && *office) - ret = g_strdup_printf("\\0Office\\01\\0Editing {0}\\0%s\\0", office); - else - ret = NULL; - - return ret; -} - -/* set the MSN's PSM info,Currently Read from the status Line - * Thanks for Cris Code - */ -static void -msn_set_psm(MsnSession *session) -{ - PurpleAccount *account; - PurplePresence *presence; - PurpleStatus *status; - char *payload; - const char *statusline; - gchar *statusline_stripped, *media = NULL; - - g_return_if_fail(session != NULL); - g_return_if_fail(session->notification != NULL); - - account = session->account; - - /* Get the PSM string from Purple's Status Line */ - presence = purple_account_get_presence(account); - status = purple_presence_get_active_status(presence); - statusline = purple_status_get_attr_string(status, "message"); - - /* MSN expects plain text, not HTML */ - statusline_stripped = purple_markup_strip_html(statusline); - media = create_media_string(presence); - g_free(session->psm); - session->psm = msn_build_psm(statusline_stripped, media, session->guid, session->protocol_ver); - - payload = session->psm; - - msn_notification_send_uux(session, payload); - - g_free(statusline_stripped); - g_free(media); -} - -void -msn_change_status(MsnSession *session) -{ - PurpleAccount *account; - MsnCmdProc *cmdproc; - MsnTransaction *trans; - MsnUser *user; - MsnObject *msnobj; - const char *state_text; - GHashTable *ui_info = purple_core_get_ui_info(); - MsnClientCaps caps = MSN_CLIENT_ID; - - g_return_if_fail(session != NULL); - g_return_if_fail(session->notification != NULL); - - /* set client caps based on what the UI tells us it is... */ - if (ui_info) { - const gchar *client_type = g_hash_table_lookup(ui_info, "client_type"); - if (client_type) { - if (strcmp(client_type, "phone") == 0 || - strcmp(client_type, "handheld") == 0) { - caps |= MSN_CAP_VIA_MOBILE; - } else if (strcmp(client_type, "web") == 0) { - caps |= MSN_CAP_VIA_WEBIM; - } else if (strcmp(client_type, "bot") == 0) { - caps |= MSN_CAP_BOT; - } - /* MSN doesn't a "console" type... - What, they have no ncurses UI? :-) */ - } - } - - account = session->account; - cmdproc = session->notification->cmdproc; - user = session->user; - state_text = msn_state_get_text(msn_state_from_account(account)); - - /* If we're not logged in yet, don't send the status to the server, - * it will be sent when login completes - */ - if (!session->logged_in) - return; - - msn_set_psm(session); - - msnobj = msn_user_get_object(user); - - if (msnobj == NULL) - { - trans = msn_transaction_new(cmdproc, "CHG", "%s %u:%02u 0", state_text, - caps, MSN_CLIENT_ID_EXT_CAPS); - } - else - { - char *msnobj_str; - - msnobj_str = msn_object_to_string(msnobj); - - trans = msn_transaction_new(cmdproc, "CHG", "%s %u:%02u %s", state_text, - caps, MSN_CLIENT_ID_EXT_CAPS, - purple_url_encode(msnobj_str)); - - g_free(msnobj_str); - } - - msn_cmdproc_send_trans(cmdproc, trans); -} - -const char * -msn_away_get_text(MsnAwayType type) -{ - g_return_val_if_fail(type <= MSN_HIDDEN, NULL); - - return _(away_text[type]); -} - -const char * -msn_state_get_text(MsnAwayType state) -{ - static char *status_text[] = - { "NLN", "NLN", "BSY", "IDL", "BRB", "AWY", "PHN", "LUN", "HDN", "HDN" }; - - return status_text[state]; -} - -MsnAwayType -msn_state_from_account(PurpleAccount *account) -{ - MsnAwayType msnstatus; - PurplePresence *presence; - PurpleStatus *status; - const char *status_id; - - presence = purple_account_get_presence(account); - status = purple_presence_get_active_status(presence); - status_id = purple_status_get_id(status); - - if (!strcmp(status_id, "away")) - msnstatus = MSN_AWAY; - else if (!strcmp(status_id, "brb")) - msnstatus = MSN_BRB; - else if (!strcmp(status_id, "busy")) - msnstatus = MSN_BUSY; - else if (!strcmp(status_id, "phone")) - msnstatus = MSN_PHONE; - else if (!strcmp(status_id, "lunch")) - msnstatus = MSN_LUNCH; - else if (!strcmp(status_id, "invisible")) - msnstatus = MSN_HIDDEN; - else - msnstatus = MSN_ONLINE; - - if ((msnstatus == MSN_ONLINE) && purple_presence_is_idle(presence)) - msnstatus = MSN_IDLE; - - return msnstatus; -} diff --git a/libpurple/protocols/msn/state.h b/libpurple/protocols/msn/state.h deleted file mode 100644 index eca877729c..0000000000 --- a/libpurple/protocols/msn/state.h +++ /dev/null @@ -1,69 +0,0 @@ -/** - * @file state.h State functions and definitions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_STATE_H -#define MSN_STATE_H - -/** - * Away types. - */ -typedef enum -{ - MSN_ONLINE = 1, - MSN_BUSY = 2, - MSN_IDLE = 3, - MSN_BRB = 4, - MSN_AWAY = 5, - MSN_PHONE = 6, - MSN_LUNCH = 7, - MSN_OFFLINE = 8, - MSN_HIDDEN = 9 -} MsnAwayType; - -/** - * Changes the status of the user. - * - * @param session The MSN session. - */ -void msn_change_status(MsnSession *session); - -/** - * Returns the string representation of an away type. - * - * @param type The away type. - * - * @return The string representation of the away type. - */ -const char *msn_away_get_text(MsnAwayType type); - -const char *msn_state_get_text(MsnAwayType state); - -/* Get the CurrentMedia info from the XML node */ -char *msn_get_currentmedia(xmlnode *payloadNode); - -/* Get the PSM info from the XML node */ -char *msn_get_psm(xmlnode *payloadNode); - -MsnAwayType msn_state_from_account(PurpleAccount *account); - -#endif /* MSN_STATE_H */ diff --git a/libpurple/protocols/msn/switchboard.c b/libpurple/protocols/msn/switchboard.c deleted file mode 100644 index cc4ef75b5a..0000000000 --- a/libpurple/protocols/msn/switchboard.c +++ /dev/null @@ -1,1197 +0,0 @@ -/** - * @file switchboard.c MSN switchboard functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "debug.h" - -#include "msnutils.h" -#include "switchboard.h" -#include "sbconn.h" -#include "slplink.h" -#include "user.h" -#include "userlist.h" - -static MsnTable *cbs_table; - -/************************************************************************** - * Main - **************************************************************************/ - -MsnSwitchBoard * -msn_switchboard_new(MsnSession *session) -{ - MsnSwitchBoard *swboard; - - g_return_val_if_fail(session != NULL, NULL); - - swboard = g_new0(MsnSwitchBoard, 1); - - swboard->session = session; - swboard->servconn = msn_servconn_new(session, MSN_SERVCONN_SB); - msn_servconn_set_idle_timeout(swboard->servconn, 60); - swboard->cmdproc = swboard->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_prepend(session->switches, swboard); - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "switchboard new: swboard(%p)\n", swboard); - - return swboard; -} - -void -msn_switchboard_destroy(MsnSwitchBoard *swboard) -{ - MsnSession *session; - MsnMessage *msg; - GList *l; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "switchboard destroy: swboard(%p)\n", swboard); - - g_return_if_fail(swboard != NULL); - - if (swboard->destroying) - return; - - swboard->destroying = TRUE; - - if (swboard->reconn_timeout_h > 0) - purple_timeout_remove(swboard->reconn_timeout_h); - - /* If it linked us is because its looking for trouble */ - while (swboard->slplinks != NULL) { - MsnSlpLink *slplink = swboard->slplinks->data; - - swboard->slplinks = g_list_remove(swboard->slplinks, slplink); - - /* Destroy only those slplinks which use the switchboard */ - if (slplink->dc == NULL) - msn_slplink_unref(slplink); - else { - swboard->slplinks = g_list_remove(swboard->slplinks, slplink); - slplink->swboard = NULL; - } - } - - /* 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 (; swboard->users; swboard->users = g_list_delete_link(swboard->users, swboard->users)) - msn_user_unref(swboard->users->data); - - session = swboard->session; - session->switches = g_list_remove(session->switches, swboard); - - for (l = session->slplinks; l; l = l->next) { - MsnSlpLink *slplink = l->data; - if (slplink->swboard == swboard) slplink->swboard = NULL; - } - -#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); - - 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; -} - -int -msn_switchboard_get_chat_id(void) -{ - static int chat_id = 1; - - return chat_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_unref(msg); -} - -static void -msn_switchboard_add_user(MsnSwitchBoard *swboard, const char *user) -{ - MsnCmdProc *cmdproc; - PurpleAccount *account; - MsnUserList *userlist; - MsnUser *msnuser; - char *semicolon; - char *passport; - - g_return_if_fail(swboard != NULL); - - cmdproc = swboard->cmdproc; - account = cmdproc->session->account; - - semicolon = strchr(user, ';'); - /* We don't really care about the machine ID. */ - if (semicolon) - passport = g_strndup(user, semicolon - user); - else - passport = g_strdup(user); - - userlist = swboard->session->userlist; - msnuser = msn_userlist_find_user(userlist, passport); - - /* Don't add multiple endpoints to the conversation. */ - if (g_list_find_custom(swboard->users, passport, (GCompareFunc)msn_user_passport_cmp)) { - g_free(passport); - return; - } - - /* Don't add ourselves either... */ - if (g_str_equal(passport, purple_account_get_username(account))) { - g_free(passport); - return; - } - - if (!msnuser) { - purple_debug_info("msn","User %s is not on our list.\n", passport); - msnuser = msn_user_new(userlist, passport, NULL); - } else - msn_user_ref(msnuser); - - g_free(passport); - - swboard->users = g_list_prepend(swboard->users, msnuser); - swboard->current_users++; - swboard->empty = FALSE; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "user=[%s], total=%d\n", - user, swboard->current_users); - - if (!(swboard->flag & MSN_SB_FLAG_IM) && (swboard->conv != NULL)) - { - /* This is a helper switchboard. */ - purple_debug_error("msn", "switchboard_add_user: conv != NULL\n"); - return; - } - - if ((swboard->conv != NULL) && - (purple_conversation_get_type(swboard->conv) == PURPLE_CONV_TYPE_CHAT)) - { - purple_conv_chat_add_user(PURPLE_CONV_CHAT(swboard->conv), msnuser->passport, NULL, - PURPLE_CBFLAGS_NONE, TRUE); - msn_servconn_set_idle_timeout(swboard->servconn, 0); - } - else if (swboard->current_users > 1) - { - msn_servconn_set_idle_timeout(swboard->servconn, 0); - if (swboard->conv == NULL || - purple_conversation_get_type(swboard->conv) != PURPLE_CONV_TYPE_CHAT) - { - GList *l; - -#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) - purple_conversation_destroy(swboard->conv); -#endif - - swboard->chat_id = msn_switchboard_get_chat_id(); - 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 = ((MsnUser*)l->data)->passport; - - purple_conv_chat_add_user(PURPLE_CONV_CHAT(swboard->conv), - tmp_user, NULL, PURPLE_CBFLAGS_NONE, TRUE); - } - - purple_conv_chat_add_user(PURPLE_CONV_CHAT(swboard->conv), - purple_account_get_username(account), - NULL, PURPLE_CBFLAGS_NONE, TRUE); - - g_free(swboard->im_user); - swboard->im_user = NULL; - } - } - else if (swboard->conv == NULL) - { - swboard->conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, - msnuser->passport, account); - } - else - { - purple_debug_warning("msn", "switchboard_add_user: This should not happen!\n"); - } -} - -static PurpleConversation * -msn_switchboard_get_conv(MsnSwitchBoard *swboard) -{ - PurpleAccount *account; - - g_return_val_if_fail(swboard != NULL, NULL); - - if (swboard->conv != NULL) - return swboard->conv; - - purple_debug_error("msn", "Switchboard with unassigned conversation\n"); - - account = swboard->session->account; - - return (swboard->conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, - account, swboard->im_user)); -} - -static void -msn_switchboard_report_user(MsnSwitchBoard *swboard, PurpleMessageFlags flags, const char *msg) -{ - PurpleConversation *conv; - - g_return_if_fail(swboard != NULL); - g_return_if_fail(msg != NULL); - - if ((conv = msn_switchboard_get_conv(swboard)) != NULL) - { - purple_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); - - purple_debug_warning("msn", "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; - - purple_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 gboolean -msg_resend_cb(gpointer data) -{ - MsnSwitchBoard *swboard = data; - - purple_debug_info("msn", "unqueuing unsent message to %s\n", swboard->im_user); - - if (msn_switchboard_request(swboard)) { - msn_switchboard_request_add_user(swboard, swboard->im_user); - swboard->reconn_timeout_h = 0; - } - return FALSE; -} - -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) - { - MsnSession *session = swboard->session; - - if (!session->destroying && msg->retries && swboard->im_user && - (swboard->error == MSN_SB_ERROR_CONNECTION || - swboard->error == MSN_SB_ERROR_UNKNOWN)) { - MsnSwitchBoard *new_sw = msn_session_find_swboard(session, - swboard->im_user); - - if (new_sw == NULL || new_sw->reconn_timeout_h == 0) { - new_sw = msn_switchboard_new(session); - new_sw->im_user = g_strdup(swboard->im_user); - new_sw->reconn_timeout_h = purple_timeout_add_seconds(3, msg_resend_cb, new_sw); - new_sw->flag |= MSN_SB_FLAG_IM; - } - - body_str = msn_message_to_string(msg); - body_enc = g_markup_escape_text(body_str, -1); - g_free(body_str); - - purple_debug_info("msn", "queuing unsent message to %s: %s\n", - swboard->im_user, body_enc); - g_free(body_enc); - msn_send_im_message(session, msg); - msg->retries--; - - return; - } - - 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; - case MSN_SB_ERROR_AUTHFAILED: - str_reason = _("Message could not be sent " - "because we were unable to establish a " - "session with the server. This is " - "likely a server problem, try again in " - "a few minutes:"); - 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_header_value(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, PURPLE_MESSAGE_ERROR, - str_reason); - msn_switchboard_report_user(swboard, PURPLE_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 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); -} - -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; -} - -/************************************************************************** - * 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]; - - /* cmdproc->data is set to NULL when the switchboard is destroyed; - * we may get a bye shortly thereafter. */ - g_return_if_fail(swboard != NULL); - - if (!(swboard->flag & MSN_SB_FLAG_IM) && (swboard->conv != NULL)) - purple_debug_error("msn", "bye_cmd: helper bug\n"); - - if (swboard->conv == NULL) - { - /* This is a helper switchboard */ - msn_switchboard_destroy(swboard); - } - else if ((swboard->current_users > 1) || - (purple_conversation_get_type(swboard->conv) == PURPLE_CONV_TYPE_CHAT)) - { - GList *passport; - /* This is a switchboard used for a chat */ - purple_conv_chat_remove_user(PURPLE_CONV_CHAT(swboard->conv), user, NULL); - - passport = g_list_find_custom(swboard->users, user, (GCompareFunc)strcmp); - if (passport) - g_free(passport->data); - else - purple_debug_warning("msn", "Can't find user %s in the switchboard\n", user); - swboard->users = g_list_delete_link(swboard->users, passport); - 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) -{ - MsnSwitchBoard *swboard; - - 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; - MsnSwitchBoard *swboard; - const char *passport; - - passport = cmd->params[0]; - - session = cmdproc->session; - swboard = cmdproc->data; - - msn_switchboard_add_user(swboard, passport); - - msn_sbconn_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); - if (purple_debug_is_verbose()) - msn_message_show_readable(msg, "SB RECV", FALSE); - - g_free (msg->remote_user); - msg->remote_user = g_strdup(cmd->params[0]); - - msn_cmdproc_process_msg(cmdproc, msg); - - msn_message_unref(msg); -} - -static void -msg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - cmd->payload_len = atoi(cmd->params[2]); - cmdproc->last_cmd->payload_cb = msg_cmd_post; -} - -static void -ubm_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - purple_debug_misc("msn", "get UBM...\n"); - cmd->payload_len = atoi(cmd->params[5]); - 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); - cmd->trans->data = NULL; -} - -static void -ack_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnSwitchBoard *swboard; - MsnMessage *msg; - - msg = cmd->trans->data; - - if (msg->part && msg->part->ack_cb != NULL) - msg->part->ack_cb(msg->part, msg->part->ack_data); - - swboard = cmdproc->data; - if (swboard) - swboard->ack_list = g_list_remove(swboard->ack_list, msg); - msn_message_unref(msg); - cmd->trans->data = NULL; -} - -static void -out_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - PurpleConnection *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 -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 -} - -void -msn_switchboard_show_ink(MsnSwitchBoard *swboard, const char *passport, - const char *data) -{ - PurpleConnection *gc; - guchar *image_data; - size_t image_len; - int imgid; - char *image_msg; - - if (!purple_str_has_prefix(data, "base64:")) - { - purple_debug_error("msn", "Ignoring Ink not in Base64 format.\n"); - return; - } - - gc = purple_account_get_connection(swboard->session->account); - - data += sizeof("base64:") - 1; - image_data = purple_base64_decode(data, &image_len); - if (!image_data || !image_len) - { - purple_debug_error("msn", "Unable to decode Ink from Base64 format.\n"); - return; - } - - imgid = purple_imgstore_add_with_id(image_data, image_len, NULL); - image_msg = g_strdup_printf("<IMG ID='%d'>", imgid); - - if (swboard->current_users > 1 || - ((swboard->conv != NULL) && - purple_conversation_get_type(swboard->conv) == PURPLE_CONV_TYPE_CHAT)) - serv_got_chat_in(gc, swboard->chat_id, passport, 0, image_msg, - time(NULL)); - else - serv_got_im(gc, passport, image_msg, 0, time(NULL)); - - purple_imgstore_unref_by_id(imgid); - g_free(image_msg); -} - -/************************************************************************** - * Connect stuff - **************************************************************************/ -static void -ans_usr_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error); - -static void -connect_cb(MsnServConn *servconn) -{ - MsnSwitchBoard *swboard; - MsnTransaction *trans; - MsnCmdProc *cmdproc; - PurpleAccount *account; - char *username; - - cmdproc = servconn->cmdproc; - g_return_if_fail(cmdproc != NULL); - - account = cmdproc->session->account; - swboard = cmdproc->data; - g_return_if_fail(swboard != NULL); - - username = g_strdup_printf("%s;{%s}", - purple_account_get_username(account), - servconn->session->guid); - - if (msn_switchboard_is_invited(swboard)) - { - swboard->empty = FALSE; - - trans = msn_transaction_new(cmdproc, "ANS", "%s %s %s", - username, - swboard->auth_key, swboard->session_id); - } - else - { - trans = msn_transaction_new(cmdproc, "USR", "%s %s", - username, - swboard->auth_key); - } - - msn_transaction_set_error_cb(trans, ans_usr_error); - msn_transaction_set_data(trans, swboard); - msn_cmdproc_send_trans(cmdproc, trans); - - g_free(username); -} - -static void -ans_usr_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) -{ - MsnSwitchBoard *swboard; - char **params; - char *passport; - int reason = MSN_SB_ERROR_UNKNOWN; - - if (error == 911) - { - reason = MSN_SB_ERROR_AUTHFAILED; - } - - purple_debug_warning("msn", "ans_usr_error: command %s gave error %i\n", trans->command, error); - - params = g_strsplit(trans->params, " ", 0); - passport = params[0]; - swboard = trans->data; - - swboard_error_helper(swboard, reason, passport); - - g_strfreev(params); -} - -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, FALSE); -} - -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) -{ - purple_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) - { - purple_debug_info("msn", "Invited user already in switchboard\n"); - return; - } - else if (error == 217) - { - reason = MSN_SB_ERROR_USER_OFFLINE; - } - - purple_debug_warning("msn", "cal_error: command %s gave error %i\n", trans->command, error); - - while ((msg = g_queue_pop_head(swboard->msg_queue)) != NULL){ - purple_debug_warning("msn", "Unable to send msg: {%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); - } - 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; - - purple_debug_info("msn", "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; - - purple_debug_info("msn", - "xfr_error %i for %s: trans %p, 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); -} - -gboolean -msn_switchboard_request(MsnSwitchBoard *swboard) -{ - MsnCmdProc *cmdproc; - MsnTransaction *trans; - - g_return_val_if_fail(swboard != NULL, FALSE); - - 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); - - return 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; - MsnTransaction *trans; - cmdproc = swboard->cmdproc; - trans = msn_transaction_new(cmdproc, "OUT", NULL); - msn_transaction_set_saveable(trans, FALSE); - msn_cmdproc_send_trans(cmdproc, trans); - - msn_switchboard_destroy(swboard); - } - else - { - swboard->closed = TRUE; - } -} - -void -msn_switchboard_release(MsnSwitchBoard *swboard, MsnSBFlag flag) -{ - g_return_if_fail(swboard != NULL); - - 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) - /* Nothing else is using this switchboard, so close it */ - msn_switchboard_close(swboard); -} - -/************************************************************************** - * 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", - msn_plain_msg); - msn_table_add_msg_type(cbs_table, "text/x-msmsgscontrol", - msn_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", - msn_datacast_msg); - msn_table_add_msg_type(cbs_table, "text/x-msmsgsinvite", - msn_invite_msg); - msn_table_add_msg_type(cbs_table, "image/gif", - msn_handwritten_msg); -} - -void -msn_switchboard_end(void) -{ - msn_table_destroy(cbs_table); -} diff --git a/libpurple/protocols/msn/switchboard.h b/libpurple/protocols/msn/switchboard.h deleted file mode 100644 index 5a125384dd..0000000000 --- a/libpurple/protocols/msn/switchboard.h +++ /dev/null @@ -1,266 +0,0 @@ -/** - * @file switchboard.h MSN switchboard functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_SWITCHBOARD_H -#define MSN_SWITCHBOARD_H - -typedef struct _MsnSwitchBoard MsnSwitchBoard; - -/** - * A switchboard error. - */ -typedef enum -{ - MSN_SB_ERROR_NONE, /**< No error. */ - MSN_SB_ERROR_CAL, /**< The user could not join (answer the call). */ - MSN_SB_ERROR_OFFLINE, /**< The account is offline. */ - MSN_SB_ERROR_USER_OFFLINE, /**< The user to call is offline. */ - MSN_SB_ERROR_CONNECTION, /**< There was a connection error. */ - MSN_SB_ERROR_TOO_FAST, /**< We are sending too fast */ - MSN_SB_ERROR_AUTHFAILED, /**< Authentication failed joining the switchboard session */ - MSN_SB_ERROR_UNKNOWN /**< An unknown error occurred. */ -} MsnSBErrorType; - -/** - * A switchboard flag. - */ -typedef enum -{ - MSN_SB_FLAG_IM = 0x01, /**< This switchboard is being used for a conversation. */ - MSN_SB_FLAG_FT = 0x02 /**< This switchboard is being used for file transfer. */ -} MsnSBFlag; - -#include "cmdproc.h" -#include "msg.h" -#include "servconn.h" -#include "session.h" - -/** - * A switchboard. - * - * A place where a bunch of users send messages to the rest of the users. - */ -struct _MsnSwitchBoard -{ - MsnSession *session; /**< Our parent session. */ - MsnServConn *servconn; /**< The physical connection for this switchboard. */ - MsnCmdProc *cmdproc; /**< Convenience variable for servconn->cmdproc. */ - char *im_user; - - MsnSBFlag flag; - char *auth_key; - char *session_id; - - PurpleConversation *conv; /**< The conversation that displays the - messages of this switchboard, or @c NULL if - this is a helper switchboard. */ - - gboolean empty; /**< A flag that states if the swithcboard has no - users in it. */ - gboolean invited; /**< A flag that states if we were invited to the - switchboard. */ - gboolean ready; /**< A flag that states if this switchboard is - ready to be used. */ - gboolean closed; /**< A flag that states if the switchboard has - been closed by the user. */ - gboolean destroying; /**< A flag that states if the switchboard is - alredy on the process of destruction. */ - - int current_users; - int total_users; - GList *users; - - int chat_id; - - GQueue *msg_queue; /**< Queue of messages to send. */ - GList *ack_list; /**< List of messages waiting for an ack. */ - - MsnSBErrorType error; /**< The error that occurred in this switchboard - (if applicable). */ - GList *slplinks; /**< The list of slplinks that are using this switchboard. */ - guint reconn_timeout_h; -}; - -/** - * Initialize the variables for switchboard creation. - */ -void msn_switchboard_init(void); - -/** - * Destroy the variables for switchboard creation. - */ -void msn_switchboard_end(void); - -/** - * Creates a new switchboard. - * - * @param session The MSN session. - * - * @return The new switchboard. - */ -MsnSwitchBoard *msn_switchboard_new(MsnSession *session); - -/** - * Destroys a switchboard. - * - * @param swboard The switchboard to destroy. - */ -void msn_switchboard_destroy(MsnSwitchBoard *swboard); - -/** - * Sets the auth key the switchboard must use when connecting. - * - * @param swboard The switchboard. - * @param key The auth key. - */ -void msn_switchboard_set_auth_key(MsnSwitchBoard *swboard, const char *key); - -/** - * Returns the auth key the switchboard must use when connecting. - * - * @param swboard The switchboard. - * - * @return The auth key. - */ -const char *msn_switchboard_get_auth_key(MsnSwitchBoard *swboard); - -/** - * Sets the session ID the switchboard must use when connecting. - * - * @param swboard The switchboard. - * @param id The session ID. - */ -void msn_switchboard_set_session_id(MsnSwitchBoard *swboard, const char *id); - -/** - * Returns the session ID the switchboard must use when connecting. - * - * @param swboard The switchboard. - * - * @return The session ID. - */ -const char *msn_switchboard_get_session_id(MsnSwitchBoard *swboard); - -/** - * Returns the next chat ID for use by a switchboard. - * - * @return The chat ID. - */ -int msn_switchboard_get_chat_id(void); - -/** - * Sets whether or not we were invited to this switchboard. - * - * @param swboard The switchboard. - * @param invite @c TRUE if invited, @c FALSE otherwise. - */ -void msn_switchboard_set_invited(MsnSwitchBoard *swboard, gboolean invited); - -/** - * Returns whether or not we were invited to this switchboard. - * - * @param swboard The switchboard. - * - * @return @c TRUE if invited, @c FALSE otherwise. - */ -gboolean msn_switchboard_is_invited(MsnSwitchBoard *swboard); - -/** - * Connects to a switchboard. - * - * @param swboard The switchboard. - * @param host The switchboard server host. - * @param port The switcbharod server port. - * - * @return @c TRUE if able to connect, or @c FALSE otherwise. - */ -gboolean msn_switchboard_connect(MsnSwitchBoard *swboard, - const char *host, int port); - -/** - * Disconnects from a switchboard. - * - * @param swboard The switchboard to disconnect from. - */ -void msn_switchboard_disconnect(MsnSwitchBoard *swboard); - -/** - * Closes the switchboard. - * - * Called when a conversation is closed. - * - * @param swboard The switchboard to close. - */ -void msn_switchboard_close(MsnSwitchBoard *swboard); - -/** - * Release a switchboard from a certain function. - * - * @param swboard The switchboard to release. - * @param flag The flag that states the function. - */ -void msn_switchboard_release(MsnSwitchBoard *swboard, MsnSBFlag flag); - -/** - * Returns whether or not we currently can send a message through this - * switchboard. - * - * @param swboard The switchboard. - * - * @return @c TRUE if a message can be sent, @c FALSE otherwise. - */ -gboolean msn_switchboard_can_send(MsnSwitchBoard *swboard); - -/** - * Sends a message through this switchboard. - * - * @param swboard The switchboard. - * @param msg The message. - * @param queue A flag that states if we want this message to be queued (in - * the case it cannot currently be sent). - * - * @return @c TRUE if a message can be sent, @c FALSE otherwise. - */ -void msn_switchboard_send_msg(MsnSwitchBoard *swboard, MsnMessage *msg, - gboolean queue); - -void -msg_error_helper(MsnCmdProc *cmdproc, MsnMessage *msg, MsnMsgErrorType error); - -gboolean msn_switchboard_chat_leave(MsnSwitchBoard *swboard); -gboolean msn_switchboard_chat_invite(MsnSwitchBoard *swboard, const char *who); - -gboolean msn_switchboard_request(MsnSwitchBoard *swboard); -void msn_switchboard_request_add_user(MsnSwitchBoard *swboard, const char *user); - -/** - * Shows an ink message from this switchboard. - * - * @param swboard The switchboard. - * @param passport The user that sent the ink. - * @param data The ink data. - */ -void msn_switchboard_show_ink(MsnSwitchBoard *swboard, const char *passport, - const char *data); - -#endif /* MSN_SWITCHBOARD_H */ diff --git a/libpurple/protocols/msn/table.c b/libpurple/protocols/msn/table.c deleted file mode 100644 index c0642c7f28..0000000000 --- a/libpurple/protocols/msn/table.c +++ /dev/null @@ -1,132 +0,0 @@ -/** - * @file table.c MSN helper structure - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#include "msn.h" -#include "table.h" - -static void -null_cmd_cb(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ -} - -static void -null_error_cb(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) -{ -} - -MsnTable * -msn_table_new() -{ - MsnTable *table; - - table = g_new0(MsnTable, 1); - - table->cmds = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, (GDestroyNotify)g_hash_table_destroy); - table->msgs = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); - table->errors = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); - - table->async = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); - table->fallback = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); - - return table; -} - -void -msn_table_destroy(MsnTable *table) -{ - g_return_if_fail(table != NULL); - - g_hash_table_destroy(table->cmds); - g_hash_table_destroy(table->msgs); - g_hash_table_destroy(table->errors); - - g_hash_table_destroy(table->async); - g_hash_table_destroy(table->fallback); - - g_free(table); -} - -void -msn_table_add_cmd(MsnTable *table, - char *command, char *answer, MsnTransCb cb) -{ - GHashTable *cbs; - - g_return_if_fail(table != NULL); - g_return_if_fail(answer != NULL); - - cbs = NULL; - - if (command == NULL) - { - cbs = table->async; - } - else if (strcmp(command, "fallback") == 0) - { - cbs = table->fallback; - } - else - { - cbs = g_hash_table_lookup(table->cmds, command); - - if (cbs == NULL) - { - cbs = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); - g_hash_table_insert(table->cmds, command, cbs); - } - } - - if (cb == NULL) - cb = null_cmd_cb; - - g_hash_table_insert(cbs, answer, cb); -} - -void -msn_table_add_error(MsnTable *table, - char *answer, MsnErrorCb cb) -{ - g_return_if_fail(table != NULL); - g_return_if_fail(answer != NULL); - - if (cb == NULL) - cb = null_error_cb; - - g_hash_table_insert(table->errors, answer, cb); -} - -void -msn_table_add_msg_type(MsnTable *table, - char *type, MsnMsgTypeCb cb) -{ - g_return_if_fail(table != NULL); - g_return_if_fail(type != NULL); - g_return_if_fail(cb != NULL); - -#if 0 - if (cb == NULL) - cb = null_msg_cb; -#endif - - g_hash_table_insert(table->msgs, type, cb); -} diff --git a/libpurple/protocols/msn/table.h b/libpurple/protocols/msn/table.h deleted file mode 100644 index 83d9954d13..0000000000 --- a/libpurple/protocols/msn/table.h +++ /dev/null @@ -1,93 +0,0 @@ -/** - * @file table.h MSN helper structure - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_TABLE_H -#define MSN_TABLE_H - -typedef struct _MsnTable MsnTable; - -#include "cmdproc.h" -#include "transaction.h" -#include "msg.h" - -typedef void (*MsnMsgTypeCb)(MsnCmdProc *cmdproc, MsnMessage *msg); - -struct _MsnTable -{ - GHashTable *cmds; /**< Callbacks that manage command response. */ - GHashTable *msgs; /**< Callbacks that manage incoming messages. */ - GHashTable *errors; /**< Callbacks that manage command errors. */ - - GHashTable *async; /**< Callbacks that manage incoming asyncronous messages. */ - /* TODO: Does this one is really needed? */ - GHashTable *fallback; /**< Fallback callback. */ -}; - -/** - * Create a new instance of a MsnTable which map commands, errors and messages - * with callbacks that will handle it. - * - * @return A new MsnTable. - */ -MsnTable *msn_table_new(void); - -/** - * Destroy a MsnTable. - * - * @param table The MsnTable to be destroyed. - */ -void msn_table_destroy(MsnTable *table); - -/** - * Relate an incomming command from server with a callback able to handle - * the event. - * - * @param table The MsnTable. - * @param command If NULL this add an incoming asyncronous command set in answer. - * Else, the command sent. - * @param answer The server answer to 'command'. If 'command' is NULL, - * the asyncronous command sent by the server. - * @param cb Callback to handle this event. - */ -void msn_table_add_cmd(MsnTable *table, char *command, char *answer, - MsnTransCb cb); - -/** - * Set a callback to handle incoming command errors. - * - * @param table The MsnTable. - * @param answer Incoming command with error. - * @param cb Callback to handle this error. - */ -void msn_table_add_error(MsnTable *table, char *answer, MsnErrorCb cb); - -/** - * Relate a message Content-type with a callback able to handle it. - * - * @param table The MsnTable. - * @param type The Message Content-Type. - * @param cb Callback to handle this Content-type. - */ -void msn_table_add_msg_type(MsnTable *table, char *type, MsnMsgTypeCb cb); - -#endif /* MSN_TABLE_H */ diff --git a/libpurple/protocols/msn/tlv.c b/libpurple/protocols/msn/tlv.c deleted file mode 100644 index d05cf4b9e2..0000000000 --- a/libpurple/protocols/msn/tlv.c +++ /dev/null @@ -1,458 +0,0 @@ -/** - * @file tlv.c MSN TLV functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "tlv.h" -#include "msnutils.h" - -static msn_tlv_t * -createtlv(guint8 type, guint8 length, guint8 *value) -{ - msn_tlv_t *ret; - - ret = g_new(msn_tlv_t, 1); - ret->type = type; - ret->length = length; - ret->value = value; - - return ret; -} - -static void -freetlv(msn_tlv_t *oldtlv) -{ - g_free(oldtlv->value); - g_free(oldtlv); -} - -GSList * -msn_tlvlist_read(const char *bs, size_t bs_len) -{ - GSList *list = NULL; - - while (bs_len > 0) { - guint8 type, length; - msn_tlv_t *tlv; - - if (bs_len == 3 && *bs == 0) { - /* Padding to multiple of 4 */ - break; - } else if (bs_len == 2 && *bs == 0) { - /* Padding to multiple of 4 */ - break; - } else if (bs_len == 1) { - if (*bs == 0) { - /* Padding to multiple of 4 */ - break; - } else { - /* TLV is not small enough to fit here */ - msn_tlvlist_free(list); - return NULL; - } - } - - type = msn_pop8(bs); - length = msn_pop8(bs); - bs_len -= 2; - - if (length > bs_len) { - msn_tlvlist_free(list); - return NULL; - } - - tlv = createtlv(type, length, NULL); - if (length > 0) { - tlv->value = g_memdup(bs, length); - if (!tlv->value) { - freetlv(tlv); - msn_tlvlist_free(list); - return NULL; - } - } - - bs_len -= length; - bs += length; - - list = g_slist_prepend(list, tlv); - } - - return g_slist_reverse(list); -} - -GSList * -msn_tlvlist_copy(GSList *orig) -{ - GSList *new = NULL; - msn_tlv_t *tlv; - - while (orig != NULL) { - tlv = orig->data; - msn_tlvlist_add_raw(&new, tlv->type, tlv->length, (const char *)tlv->value); - orig = orig->next; - } - - return new; -} - -gboolean -msn_tlvlist_equal(GSList *one, GSList *two) -{ - while (one && two) { - msn_tlv_t *a = one->data; - msn_tlv_t *b = two->data; - - if (a->type != b->type) - return FALSE; - else if (a->length != b->length) - return FALSE; - else if (!a->value && b->value) - return FALSE; - else if (a->value && !b->value) - return FALSE; - else if (a->value && b->value && memcmp(a->value, b->value, a->length) != 0) - return FALSE; - - one = one->next; - two = two->next; - } - - return one == two; -} - -void -msn_tlvlist_free(GSList *list) -{ - while (list != NULL) { - freetlv(list->data); - list = g_slist_delete_link(list, list); - } -} - -int -msn_tlvlist_count(GSList *list) -{ - return g_slist_length(list); -} - -size_t -msn_tlvlist_size(GSList *list) -{ - int size; - - if (list == NULL) - return 0; - - for (size = 0; list; list = list->next) - size += (2 + ((msn_tlv_t *)list->data)->length); - - return size; -} - -int -msn_tlvlist_add_raw(GSList **list, const guint8 type, const guint8 length, const char *value) -{ - msn_tlv_t *tlv; - - if (list == NULL) - return 0; - - tlv = createtlv(type, length, NULL); - if (length > 0) - tlv->value = g_memdup(value, length); - - *list = g_slist_append(*list, tlv); - - return tlv->length; -} - -int -msn_tlvlist_add_8(GSList **list, const guint8 type, const guint8 value) -{ - char v8[1]; - - msn_write8(v8, value); - - return msn_tlvlist_add_raw(list, type, 1, v8); -} - -int -msn_tlvlist_add_16(GSList **list, const guint8 type, const guint16 value) -{ - char v16[2]; - - msn_write16be(v16, value); - - return msn_tlvlist_add_raw(list, type, 2, v16); -} - -int -msn_tlvlist_add_32(GSList **list, const guint8 type, const guint32 value) -{ - char v32[4]; - - msn_write32be(v32, value); - - return msn_tlvlist_add_raw(list, type, 4, v32); -} - -int -msn_tlvlist_add_str(GSList **list, const guint8 type, const char *value) -{ - return msn_tlvlist_add_raw(list, type, strlen(value), value); -} - -int -msn_tlvlist_add_empty(GSList **list, const guint8 type) -{ - return msn_tlvlist_add_raw(list, type, 0, NULL); -} - -int -msn_tlvlist_add_tlv(GSList **list, const msn_tlv_t *tlv) -{ - return msn_tlvlist_add_raw(list, tlv->type, tlv->length, (const char *)tlv->value); -} - -int -msn_tlvlist_replace_raw(GSList **list, const guint8 type, const guint8 length, const char *value) -{ - GSList *cur; - msn_tlv_t *tlv; - - if (list == NULL) - return 0; - - for (cur = *list; cur != NULL; cur = cur->next) { - tlv = cur->data; - if (tlv->type == type) - break; - } - - if (cur == NULL) - /* TLV does not exist, so add a new one */ - return msn_tlvlist_add_raw(list, type, length, value); - - g_free(tlv->value); - tlv->length = length; - if (length > 0) { - tlv->value = g_memdup(value, length); - } else - tlv->value = NULL; - - return length; -} - -int -msn_tlvlist_replace_str(GSList **list, const guint8 type, const char *str) -{ - return msn_tlvlist_replace_raw(list, type, strlen(str), str); -} - -int -msn_tlvlist_replace_empty(GSList **list, const guint8 type) -{ - return msn_tlvlist_replace_raw(list, type, 0, NULL); -} - -int -msn_tlvlist_replace_8(GSList **list, const guint8 type, const guint8 value) -{ - char v8[1]; - - msn_write8(v8, value); - - return msn_tlvlist_replace_raw(list, type, 1, v8); -} - -int -msn_tlvlist_replace_32(GSList **list, const guint8 type, const guint32 value) -{ - char v32[4]; - - msn_write32be(v32, value); - - return msn_tlvlist_replace_raw(list, type, 4, v32); -} - -int -msn_tlvlist_replace_tlv(GSList **list, const msn_tlv_t *tlv) -{ - return msn_tlvlist_replace_raw(list, tlv->type, tlv->length, (const char *)tlv->value); -} - -void -msn_tlvlist_remove(GSList **list, const guint8 type) -{ - GSList *cur, *next; - msn_tlv_t *tlv; - - if (list == NULL || *list == NULL) - return; - - cur = *list; - while (cur != NULL) { - tlv = cur->data; - next = cur->next; - - if (tlv->type == type) { - /* Delete this TLV */ - *list = g_slist_delete_link(*list, cur); - g_free(tlv->value); - g_free(tlv); - } - - cur = next; - } -} - -char * -msn_tlvlist_write(GSList *list, guint8 *out_len) -{ - char *buf; - char *tmp; - size_t bytes_left; - size_t total_len; - - tmp = buf = g_malloc(256); - bytes_left = total_len = 256; - - for (; list; list = g_slist_next(list)) { - msn_tlv_t *tlv = (msn_tlv_t *)list->data; - - if (G_UNLIKELY((gsize)tlv->length + 2 > bytes_left)) { - buf = g_realloc(buf, total_len + 256); - bytes_left += 256; - total_len += 256; - tmp = buf + (total_len - bytes_left); - } - - msn_push8(tmp, tlv->type); - msn_push8(tmp, tlv->length); - memcpy(tmp, tlv->value, tlv->length); - tmp += tlv->length; - - bytes_left -= (tlv->length + 2); - } - - /* Align length to multiple of 4 */ - total_len = total_len - bytes_left; - bytes_left = 4 - total_len % 4; - if (bytes_left != 4) - memset(tmp, 0, bytes_left); - else - bytes_left = 0; - - *out_len = total_len + bytes_left; - - return buf; -} - -msn_tlv_t * -msn_tlv_gettlv(GSList *list, const guint8 type, const int nth) -{ - msn_tlv_t *tlv; - int i; - - for (i = 0; list != NULL; list = list->next) { - tlv = list->data; - if (tlv->type == type) - i++; - if (i >= nth) - return tlv; - } - - return NULL; -} - -int -msn_tlv_getlength(GSList *list, const guint8 type, const int nth) -{ - msn_tlv_t *tlv; - - tlv = msn_tlv_gettlv(list, type, nth); - if (tlv == NULL) - return -1; - - return tlv->length; -} - -char * -msn_tlv_getvalue_as_string(msn_tlv_t *tlv) -{ - char *ret; - - ret = g_malloc(tlv->length + 1); - memcpy(ret, tlv->value, tlv->length); - ret[tlv->length] = '\0'; - - return ret; -} - -char * -msn_tlv_getstr(GSList *list, const guint8 type, const int nth) -{ - msn_tlv_t *tlv; - - tlv = msn_tlv_gettlv(list, type, nth); - if (tlv == NULL) - return NULL; - - return msn_tlv_getvalue_as_string(tlv); -} - -guint8 -msn_tlv_get8(GSList *list, const guint8 type, const int nth) -{ - msn_tlv_t *tlv; - - tlv = msn_tlv_gettlv(list, type, nth); - if (tlv == NULL) - return 0; /* erm */ - - return msn_read8((const char *)tlv->value); -} - -guint16 -msn_tlv_get16(GSList *list, const guint8 type, const int nth) -{ - msn_tlv_t *tlv; - - tlv = msn_tlv_gettlv(list, type, nth); - if (tlv == NULL) - return 0; /* erm */ - - return msn_read16be((const char *)tlv->value); -} - -guint32 -msn_tlv_get32(GSList *list, const guint8 type, const int nth) -{ - msn_tlv_t *tlv; - - tlv = msn_tlv_gettlv(list, type, nth); - if (tlv == NULL) - return 0; /* erm */ - - return msn_read32be((const char *)tlv->value); -} - diff --git a/libpurple/protocols/msn/tlv.h b/libpurple/protocols/msn/tlv.h deleted file mode 100644 index 065dee3388..0000000000 --- a/libpurple/protocols/msn/tlv.h +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @file tlv.h MSN TLV functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef MSN_TLV_H -#define MSN_TLV_H - -#include "msn.h" - -/* TLV structure */ -typedef struct msn_tlv_s -{ - guint8 type; - guint8 length; - guint8 *value; -} msn_tlv_t; - -/* TLV handling functions */ -char *msn_tlv_getvalue_as_string(msn_tlv_t *tlv); - -msn_tlv_t *msn_tlv_gettlv(GSList *list, const guint8 type, const int nth); -int msn_tlv_getlength(GSList *list, const guint8 type, const int nth); -char *msn_tlv_getstr(GSList *list, const guint8 type, const int nth); -guint8 msn_tlv_get8(GSList *list, const guint8 type, const int nth); -guint16 msn_tlv_get16(GSList *list, const guint8 type, const int nth); -guint32 msn_tlv_get32(GSList *list, const guint8 type, const int nth); - -/* TLV list handling functions */ -GSList *msn_tlvlist_read(const char *bs, size_t bs_len); -GSList *msn_tlvlist_copy(GSList *orig); - -int msn_tlvlist_count(GSList *list); -size_t msn_tlvlist_size(GSList *list); -gboolean msn_tlvlist_equal(GSList *one, GSList *two); -char *msn_tlvlist_write(GSList *list, guint8 *out_len); -void msn_tlvlist_free(GSList *list); - -int msn_tlvlist_add_raw(GSList **list, const guint8 type, const guint8 length, const char *value); -int msn_tlvlist_add_empty(GSList **list, const guint8 type); -int msn_tlvlist_add_8(GSList **list, const guint8 type, const guint8 value); -int msn_tlvlist_add_16(GSList **list, const guint8 type, const guint16 value); -int msn_tlvlist_add_32(GSList **list, const guint8 type, const guint32 value); -int msn_tlvlist_add_str(GSList **list, const guint8 type, const char *value); -int msn_tlvlist_add_tlv(GSList **list, const msn_tlv_t *tlv); - -int msn_tlvlist_replace_raw(GSList **list, const guint8 type, const guint8 lenth, const char *value); -int msn_tlvlist_replace_str(GSList **list, const guint8 type, const char *str); -int msn_tlvlist_replace_empty(GSList **list, const guint8 type); -int msn_tlvlist_replace_8(GSList **list, const guint8 type, const guint8 value); -int msn_tlvlist_replace_16(GSList **list, const guint8 type, const guint16 value); -int msn_tlvlist_replace_32(GSList **list, const guint8 type, const guint32 value); -int msn_tlvlist_replace_tlv(GSList **list, const msn_tlv_t *tlv); - -void msn_tlvlist_remove(GSList **list, const guint8 type); - -#endif /* MSN_TLV_H */ - diff --git a/libpurple/protocols/msn/transaction.c b/libpurple/protocols/msn/transaction.c deleted file mode 100644 index 57f3464553..0000000000 --- a/libpurple/protocols/msn/transaction.c +++ /dev/null @@ -1,247 +0,0 @@ -/** - * @file transaction.c MSN transaction functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "debug.h" - -#include "msn.h" -#include "transaction.h" - -MsnTransaction * -msn_transaction_new(MsnCmdProc *cmdproc, const char *command, - const char *format, ...) -{ - MsnTransaction *trans; - va_list arg; - - g_return_val_if_fail(command != NULL, NULL); - - trans = g_new0(MsnTransaction, 1); - - trans->cmdproc = cmdproc; - trans->command = g_strdup(command); - trans->saveable = TRUE; - - if (format != NULL) - { - va_start(arg, format); - trans->params = g_strdup_vprintf(format, arg); - va_end(arg); - } - - /* trans->queue = g_queue_new(); */ - - return trans; -} - -void -msn_transaction_destroy(MsnTransaction *trans) -{ - g_return_if_fail(trans != NULL); - - g_free(trans->command); - g_free(trans->params); - g_free(trans->payload); - - if (trans->data_free) - trans->data_free(trans->data); - -#if 0 - if (trans->pendent_cmd != NULL) - msn_message_unref(trans->pendent_msg); -#endif - -#if 0 - MsnTransaction *elem; - if (trans->queue != NULL) - { - while ((elem = g_queue_pop_head(trans->queue)) != NULL) - msn_transaction_destroy(elem); - - g_queue_free(trans->queue); - } -#endif - - if (trans->callbacks != NULL && trans->has_custom_callbacks) - g_hash_table_destroy(trans->callbacks); - - if (trans->timer) - purple_timeout_remove(trans->timer); - - g_free(trans); -} - -char * -msn_transaction_to_string(MsnTransaction *trans) -{ - char *str; - - g_return_val_if_fail(trans != NULL, FALSE); - - if (trans->params != NULL) - str = g_strdup_printf("%s %u %s\r\n", trans->command, trans->trId, trans->params); - else if (trans->saveable) - str = g_strdup_printf("%s %u\r\n", trans->command, trans->trId); - else - str = g_strdup_printf("%s\r\n", trans->command); - - return str; -} - -void -msn_transaction_queue_cmd(MsnTransaction *trans, MsnCommand *cmd) -{ - purple_debug_info("msn", "queueing command.\n"); - trans->pendent_cmd = cmd; - msn_command_ref(cmd); -} - -void -msn_transaction_unqueue_cmd(MsnTransaction *trans, MsnCmdProc *cmdproc) -{ - MsnCommand *cmd; - - if (!cmdproc->servconn->connected) - return; - - purple_debug_info("msn", "unqueueing command.\n"); - cmd = trans->pendent_cmd; - - g_return_if_fail(cmd != NULL); - - msn_cmdproc_process_cmd(cmdproc, cmd); - msn_command_unref(cmd); - - trans->pendent_cmd = NULL; -} - -#if 0 -void -msn_transaction_queue(MsnTransaction *trans, MsnTransaction *elem) -{ - if (trans->queue == NULL) - trans->queue = g_queue_new(); - - g_queue_push_tail(trans->queue, elem); -} - -void -msn_transaction_unqueue(MsnTransaction *trans, MsnCmdProc *cmdproc) -{ - MsnTransaction *elem; - - while ((elem = g_queue_pop_head(trans->queue)) != NULL) - msn_cmdproc_send_trans(cmdproc, elem); -} -#endif - -void -msn_transaction_set_payload(MsnTransaction *trans, - const char *payload, gsize payload_len) -{ - g_return_if_fail(trans != NULL); - g_return_if_fail(payload != NULL); - - trans->payload = g_strdup(payload); - trans->payload_len = payload_len ? payload_len : strlen(trans->payload); -} - -void -msn_transaction_set_data(MsnTransaction *trans, void *data) -{ - g_return_if_fail(trans != NULL); - - trans->data = data; -} - -void msn_transaction_set_data_free(MsnTransaction *trans, GDestroyNotify fn) -{ - g_return_if_fail(trans != NULL); - trans->data_free = fn; -} - -void -msn_transaction_set_saveable(MsnTransaction *trans, gboolean saveable) -{ - g_return_if_fail(trans != NULL); - - trans->saveable = saveable; -} - -void -msn_transaction_add_cb(MsnTransaction *trans, char *answer, - MsnTransCb cb) -{ - g_return_if_fail(trans != NULL); - g_return_if_fail(answer != NULL); - - if (trans->callbacks == NULL) - { - trans->has_custom_callbacks = TRUE; - trans->callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, - NULL); - } - else if (trans->has_custom_callbacks != TRUE) - g_return_if_reached (); - - g_hash_table_insert(trans->callbacks, answer, cb); -} - -static gboolean -transaction_timeout(gpointer data) -{ - MsnTransaction *trans; - - trans = data; - g_return_val_if_fail(trans != NULL, FALSE); - -#if 0 - purple_debug_info("msn", "timed out: %s %d %s\n", trans->command, trans->trId, trans->params); -#endif - - trans->timer = 0; - - if (trans->timeout_cb != NULL) - trans->timeout_cb(trans->cmdproc, trans); - - return FALSE; -} - -void -msn_transaction_set_timeout_cb(MsnTransaction *trans, MsnTimeoutCb cb) -{ - if (trans->timer) - { - purple_debug_error("msn", "This shouldn't be happening\n"); - purple_timeout_remove(trans->timer); - } - trans->timeout_cb = cb; - trans->timer = purple_timeout_add_seconds(60, transaction_timeout, trans); -} - -void -msn_transaction_set_error_cb(MsnTransaction *trans, MsnErrorCb cb) -{ - trans->error_cb = cb; -} diff --git a/libpurple/protocols/msn/transaction.h b/libpurple/protocols/msn/transaction.h deleted file mode 100644 index 10fe8fc0c3..0000000000 --- a/libpurple/protocols/msn/transaction.h +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @file transaction.h MSN transaction functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_TRANSACTION_H -#define MSN_TRANSACTION_H - -#include "internal.h" - -typedef struct _MsnTransaction MsnTransaction; - -#include "cmdproc.h" -#include "command.h" - -typedef void (*MsnTransCb)(MsnCmdProc *cmdproc, MsnCommand *cmd); -typedef void (*MsnTimeoutCb)(MsnCmdProc *cmdproc, MsnTransaction *trans); -typedef void (*MsnErrorCb)(MsnCmdProc *cmdproc, MsnTransaction *trans, - int error); - -/** - * A transaction. A sending command that will initiate the transaction. - */ -struct _MsnTransaction -{ - MsnCmdProc *cmdproc; - - gboolean saveable; /**< Whether to save this transaction in the history */ - unsigned int trId; /**< The ID of this transaction, if it's being saved */ - - char *command; - char *params; - - guint timer; - - void *data; /**< The data to be used on the different callbacks. */ - GDestroyNotify data_free; /**< The function to free 'data', or @c NULL */ - - GHashTable *callbacks; - gboolean has_custom_callbacks; - MsnErrorCb error_cb; - MsnTimeoutCb timeout_cb; - - char *payload; - size_t payload_len; - - GQueue *queue; - MsnCommand *pendent_cmd; /**< The command that is waiting for the result of - this transaction. */ -}; - -MsnTransaction *msn_transaction_new(MsnCmdProc *cmdproc, const char *command, - const char *format, ...) G_GNUC_PRINTF(3, 4); -void msn_transaction_destroy(MsnTransaction *trans); - -char *msn_transaction_to_string(MsnTransaction *trans); -void msn_transaction_queue_cmd(MsnTransaction *trans, MsnCommand *cmd); -void msn_transaction_unqueue_cmd(MsnTransaction *trans, MsnCmdProc *cmdproc); -void msn_transaction_set_payload(MsnTransaction *trans, - const char *payload, gsize payload_len); -void msn_transaction_set_data(MsnTransaction *trans, void *data); -void msn_transaction_set_data_free(MsnTransaction *trans, GDestroyNotify fn); -void msn_transaction_set_saveable(MsnTransaction *trans, gboolean saveable); -void msn_transaction_add_cb(MsnTransaction *trans, char *answer, - MsnTransCb cb); -void msn_transaction_set_error_cb(MsnTransaction *trans, MsnErrorCb cb); -void msn_transaction_set_timeout_cb(MsnTransaction *trans, MsnTimeoutCb cb); - -#endif /* MSN_TRANSACTION_H */ diff --git a/libpurple/protocols/msn/user.c b/libpurple/protocols/msn/user.c deleted file mode 100644 index a9565be27c..0000000000 --- a/libpurple/protocols/msn/user.c +++ /dev/null @@ -1,801 +0,0 @@ -/** - * @file user.c User functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "debug.h" -#include "util.h" - -#include "user.h" -#include "slp.h" - -static void free_user_endpoint(MsnUserEndpoint *data) -{ - g_free(data->id); - g_free(data->name); - g_free(data); -} - -/*new a user object*/ -MsnUser * -msn_user_new(MsnUserList *userlist, const char *passport, - const char *friendly_name) -{ - MsnUser *user; - - user = g_new0(MsnUser, 1); - - user->userlist = userlist; - - msn_user_set_passport(user, passport); - msn_user_set_friendly_name(user, friendly_name); - - return msn_user_ref(user); -} - -/*destroy a user object*/ -static void -msn_user_destroy(MsnUser *user) -{ - while (user->endpoints != NULL) { - free_user_endpoint(user->endpoints->data); - user->endpoints = g_slist_delete_link(user->endpoints, user->endpoints); - } - - if (user->clientcaps != NULL) - g_hash_table_destroy(user->clientcaps); - - if (user->group_ids != NULL) - { - GList *l; - for (l = user->group_ids; l != NULL; l = l->next) - { - g_free(l->data); - } - g_list_free(user->group_ids); - } - - if (user->msnobj != NULL) - msn_object_destroy(user->msnobj); - - g_free(user->passport); - g_free(user->friendly_name); - g_free(user->uid); - if (user->extinfo) { - g_free(user->extinfo->media_album); - g_free(user->extinfo->media_artist); - g_free(user->extinfo->media_title); - g_free(user->extinfo->phone_home); - g_free(user->extinfo->phone_mobile); - g_free(user->extinfo->phone_work); - g_free(user->extinfo); - } - g_free(user->statusline); - g_free(user->invite_message); - - g_free(user); -} - -MsnUser * -msn_user_ref(MsnUser *user) -{ - g_return_val_if_fail(user != NULL, NULL); - - user->refcount++; - - return user; -} - -void -msn_user_unref(MsnUser *user) -{ - g_return_if_fail(user != NULL); - - user->refcount--; - - if(user->refcount == 0) - msn_user_destroy(user); -} - -void -msn_user_update(MsnUser *user) -{ - PurpleAccount *account; - gboolean offline; - - g_return_if_fail(user != NULL); - - account = user->userlist->session->account; - - offline = (user->status == NULL); - - if (!offline) { - purple_prpl_got_user_status(account, user->passport, user->status, - "message", user->statusline, NULL); - } else { - if (user->mobile) { - purple_prpl_got_user_status(account, user->passport, "mobile", NULL); - purple_prpl_got_user_status(account, user->passport, "available", NULL); - } else { - purple_prpl_got_user_status(account, user->passport, "offline", NULL); - } - } - - if (!offline || !user->mobile) { - purple_prpl_got_user_status_deactive(account, user->passport, "mobile"); - } - - if (!offline && user->extinfo && user->extinfo->media_type != CURRENT_MEDIA_UNKNOWN) { - if (user->extinfo->media_type == CURRENT_MEDIA_MUSIC) { - purple_prpl_got_user_status(account, user->passport, "tune", - PURPLE_TUNE_ARTIST, user->extinfo->media_artist, - PURPLE_TUNE_ALBUM, user->extinfo->media_album, - PURPLE_TUNE_TITLE, user->extinfo->media_title, - NULL); - } else if (user->extinfo->media_type == CURRENT_MEDIA_GAMES) { - purple_prpl_got_user_status(account, user->passport, "tune", - "game", user->extinfo->media_title, - NULL); - } else if (user->extinfo->media_type == CURRENT_MEDIA_OFFICE) { - purple_prpl_got_user_status(account, user->passport, "tune", - "office", user->extinfo->media_title, - NULL); - } else { - purple_debug_warning("msn", "Got CurrentMedia with unknown type %d.\n", - user->extinfo->media_type); - } - } else { - purple_prpl_got_user_status_deactive(account, user->passport, "tune"); - } - - if (user->idle) - purple_prpl_got_user_idle(account, user->passport, TRUE, -1); - else - purple_prpl_got_user_idle(account, user->passport, FALSE, 0); -} - -void -msn_user_set_state(MsnUser *user, const char *state) -{ - const char *status; - - g_return_if_fail(user != NULL); - - if (state == NULL) { - user->status = NULL; - return; - } - - if (!g_ascii_strcasecmp(state, "BSY")) - status = "busy"; - else if (!g_ascii_strcasecmp(state, "BRB")) - status = "brb"; - else if (!g_ascii_strcasecmp(state, "AWY")) - status = "away"; - else if (!g_ascii_strcasecmp(state, "PHN")) - status = "phone"; - else if (!g_ascii_strcasecmp(state, "LUN")) - status = "lunch"; - else if (!g_ascii_strcasecmp(state, "HDN")) - status = NULL; - else - status = "available"; - - if (!g_ascii_strcasecmp(state, "IDL")) - user->idle = TRUE; - else - user->idle = FALSE; - - user->status = status; -} - -void -msn_user_set_passport(MsnUser *user, const char *passport) -{ - g_return_if_fail(user != NULL); - - g_free(user->passport); - user->passport = g_strdup(passport); -} - -gboolean -msn_user_set_friendly_name(MsnUser *user, const char *name) -{ - g_return_val_if_fail(user != NULL, FALSE); - - if (!name) - return FALSE; - - if (user->friendly_name && (!strcmp(user->friendly_name, name) || - !strcmp(user->passport, name))) - return FALSE; - - g_free(user->friendly_name); - user->friendly_name = g_strdup(name); - - serv_got_alias(purple_account_get_connection(user->userlist->session->account), - user->passport, name); - return TRUE; -} - -void -msn_user_set_statusline(MsnUser *user, const char *statusline) -{ - g_return_if_fail(user != NULL); - - g_free(user->statusline); - user->statusline = g_strdup(statusline); -} - -void -msn_user_set_uid(MsnUser *user, const char *uid) -{ - g_return_if_fail(user != NULL); - - g_free(user->uid); - user->uid = g_strdup(uid); -} - -void -msn_user_set_endpoint_data(MsnUser *user, const char *input, MsnUserEndpoint *newep) -{ - MsnUserEndpoint *ep; - char *endpoint; - GSList *l; - - g_return_if_fail(user != NULL); - g_return_if_fail(input != NULL); - - endpoint = g_ascii_strdown(input, -1); - - for (l = user->endpoints; l; l = l->next) { - ep = l->data; - if (g_str_equal(ep->id, endpoint)) { - /* We have info about this endpoint! */ - - g_free(endpoint); - - if (newep == NULL) { - /* Delete it and exit */ - user->endpoints = g_slist_delete_link(user->endpoints, l); - free_user_endpoint(ep); - return; - } - - /* Break out of our loop and update it */ - break; - } - } - if (l == NULL) { - /* Need to add a new endpoint */ - ep = g_new0(MsnUserEndpoint, 1); - ep->id = endpoint; - user->endpoints = g_slist_prepend(user->endpoints, ep); - } - - ep->clientid = newep->clientid; - ep->extcaps = newep->extcaps; -} - -void -msn_user_clear_endpoints(MsnUser *user) -{ - MsnUserEndpoint *ep; - GSList *l; - - g_return_if_fail(user != NULL); - - for (l = user->endpoints; l; l = g_slist_delete_link(l, l)) { - ep = l->data; - free_user_endpoint(ep); - } - - user->endpoints = NULL; -} - -void -msn_user_set_op(MsnUser *user, MsnListOp list_op) -{ - g_return_if_fail(user != NULL); - - user->list_op |= list_op; -} - -void -msn_user_unset_op(MsnUser *user, MsnListOp list_op) -{ - g_return_if_fail(user != NULL); - - user->list_op &= ~list_op; -} - -void -msn_user_set_buddy_icon(MsnUser *user, PurpleStoredImage *img) -{ - MsnObject *msnobj; - - g_return_if_fail(user != NULL); - - msnobj = msn_object_new_from_image(img, "TFR2C2.tmp", - user->passport, MSN_OBJECT_USERTILE); - - if (!msnobj) - purple_debug_error("msn", "Unable to open buddy icon from %s!\n", user->passport); - - msn_user_set_object(user, msnobj); -} - -/*add group id to User object*/ -void -msn_user_add_group_id(MsnUser *user, const char* group_id) -{ - MsnUserList *userlist; - PurpleAccount *account; - PurpleBuddy *b; - PurpleGroup *g; - const char *passport; - const char *group_name; - - g_return_if_fail(user != NULL); - g_return_if_fail(group_id != NULL); - - user->group_ids = g_list_append(user->group_ids, g_strdup(group_id)); - - userlist = user->userlist; - account = userlist->session->account; - passport = msn_user_get_passport(user); - - group_name = msn_userlist_find_group_name(userlist, group_id); - - purple_debug_info("msn", "User: group id:%s,name:%s,user:%s\n", group_id, group_name, passport); - - g = purple_find_group(group_name); - - if ((group_id == NULL) && (g == NULL)) - { - g = purple_group_new(group_name); - purple_blist_add_group(g, NULL); - } - - b = purple_find_buddy_in_group(account, passport, g); - if (b == NULL) - { - b = purple_buddy_new(account, passport, NULL); - purple_blist_add_buddy(b, NULL, g, NULL); - } - purple_buddy_set_protocol_data(b, user); - /*Update the blist Node info*/ -} - -/*check if the msn user is online*/ -gboolean -msn_user_is_online(PurpleAccount *account, const char *name) -{ - PurpleBuddy *buddy; - - buddy = purple_find_buddy(account, name); - return PURPLE_BUDDY_IS_ONLINE(buddy); -} - -gboolean -msn_user_is_yahoo(PurpleAccount *account, const char *name) -{ - MsnSession *session = NULL; - MsnUser *user; - PurpleConnection *gc; - - gc = purple_account_get_connection(account); - if (gc != NULL) - session = gc->proto_data; - - if ((session != NULL) && (user = msn_userlist_find_user(session->userlist, name)) != NULL) - { - return (user->networkid == MSN_NETWORK_YAHOO); - } - return (strstr(name,"@yahoo.") != NULL); -} - -void -msn_user_remove_group_id(MsnUser *user, const char *id) -{ - GList *l; - - g_return_if_fail(user != NULL); - g_return_if_fail(id != NULL); - - l = g_list_find_custom(user->group_ids, id, (GCompareFunc)strcmp); - - if (l == NULL) - return; - - g_free(l->data); - user->group_ids = g_list_delete_link(user->group_ids, l); -} - -void -msn_user_set_pending_group(MsnUser *user, const char *group) -{ - user->pending_group = g_strdup(group); -} - -char * -msn_user_remove_pending_group(MsnUser *user) -{ - char *group = user->pending_group; - user->pending_group = NULL; - return group; -} - -void -msn_user_set_home_phone(MsnUser *user, const char *number) -{ - g_return_if_fail(user != NULL); - - if (!number && !user->extinfo) - return; - - if (user->extinfo) - g_free(user->extinfo->phone_home); - else - user->extinfo = g_new0(MsnUserExtendedInfo, 1); - - user->extinfo->phone_home = g_strdup(number); -} - -void -msn_user_set_work_phone(MsnUser *user, const char *number) -{ - g_return_if_fail(user != NULL); - - if (!number && !user->extinfo) - return; - - if (user->extinfo) - g_free(user->extinfo->phone_work); - else - user->extinfo = g_new0(MsnUserExtendedInfo, 1); - - user->extinfo->phone_work = g_strdup(number); -} - -void -msn_user_set_mobile_phone(MsnUser *user, const char *number) -{ - g_return_if_fail(user != NULL); - - if (!number && !user->extinfo) - return; - - if (user->extinfo) - g_free(user->extinfo->phone_mobile); - else - user->extinfo = g_new0(MsnUserExtendedInfo, 1); - - user->extinfo->phone_mobile = g_strdup(number); -} - -void -msn_user_set_clientid(MsnUser *user, guint clientid) -{ - g_return_if_fail(user != NULL); - - user->clientid = clientid; -} - -void -msn_user_set_extcaps(MsnUser *user, guint extcaps) -{ - g_return_if_fail(user != NULL); - - user->extcaps = extcaps; -} - -void -msn_user_set_network(MsnUser *user, MsnNetwork network) -{ - g_return_if_fail(user != NULL); - - user->networkid = network; -} - -static gboolean -buddy_icon_cached(PurpleConnection *gc, MsnObject *obj) -{ - PurpleAccount *account; - PurpleBuddy *buddy; - const char *old; - const char *new; - - g_return_val_if_fail(obj != NULL, FALSE); - - account = purple_connection_get_account(gc); - - buddy = purple_find_buddy(account, msn_object_get_creator(obj)); - if (buddy == NULL) - return FALSE; - - old = purple_buddy_icons_get_checksum_for_user(buddy); - new = msn_object_get_sha1(obj); - - if (new == NULL) - return FALSE; - - /* If the old and new checksums are the same, and the file actually exists, - * then return TRUE */ - if (old != NULL && !strcmp(old, new)) - return TRUE; - - return FALSE; -} - -static void -queue_buddy_icon_request(MsnUser *user) -{ - PurpleAccount *account; - MsnObject *obj; - GQueue *queue; - - g_return_if_fail(user != NULL); - - account = user->userlist->session->account; - - obj = msn_user_get_object(user); - - if (obj == NULL) { - purple_buddy_icons_set_for_user(account, user->passport, NULL, 0, NULL); - return; - } - - if (!buddy_icon_cached(account->gc, obj)) { - MsnUserList *userlist; - - userlist = user->userlist; - queue = userlist->buddy_icon_requests; - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "Queueing buddy icon request for %s (buddy_icon_window = %i)\n", - user->passport, userlist->buddy_icon_window); - - g_queue_push_tail(queue, user); - - if (userlist->buddy_icon_window > 0) - msn_release_buddy_icon_request(userlist); - } -} - -void -msn_user_set_object(MsnUser *user, MsnObject *obj) -{ - g_return_if_fail(user != NULL); - - if (user->msnobj != NULL && !msn_object_find_local(msn_object_get_sha1(obj))) - msn_object_destroy(user->msnobj); - - user->msnobj = obj; - - if (user->list_op & MSN_LIST_FL_OP) - queue_buddy_icon_request(user); -} - -void -msn_user_set_client_caps(MsnUser *user, GHashTable *info) -{ - g_return_if_fail(user != NULL); - g_return_if_fail(info != NULL); - - if (user->clientcaps != NULL) - g_hash_table_destroy(user->clientcaps); - - user->clientcaps = info; -} - -void -msn_user_set_invite_message(MsnUser *user, const char *message) -{ - g_return_if_fail(user != NULL); - - g_free(user->invite_message); - user->invite_message = g_strdup(message); -} - -const char * -msn_user_get_passport(const MsnUser *user) -{ - g_return_val_if_fail(user != NULL, NULL); - - return user->passport; -} - -const char * -msn_user_get_friendly_name(const MsnUser *user) -{ - g_return_val_if_fail(user != NULL, NULL); - - return user->friendly_name; -} - -const char * -msn_user_get_home_phone(const MsnUser *user) -{ - g_return_val_if_fail(user != NULL, NULL); - - return user->extinfo ? user->extinfo->phone_home : NULL; -} - -const char * -msn_user_get_work_phone(const MsnUser *user) -{ - g_return_val_if_fail(user != NULL, NULL); - - return user->extinfo ? user->extinfo->phone_work : NULL; -} - -const char * -msn_user_get_mobile_phone(const MsnUser *user) -{ - g_return_val_if_fail(user != NULL, NULL); - - return user->extinfo ? user->extinfo->phone_mobile : NULL; -} - -guint -msn_user_get_clientid(const MsnUser *user) -{ - g_return_val_if_fail(user != NULL, 0); - - return user->clientid; -} - -guint -msn_user_get_extcaps(const MsnUser *user) -{ - g_return_val_if_fail(user != NULL, 0); - - return user->extcaps; -} - -MsnUserEndpoint * -msn_user_get_endpoint_data(MsnUser *user, const char *input) -{ - char *endpoint; - GSList *l; - MsnUserEndpoint *ep; - - g_return_val_if_fail(user != NULL, NULL); - g_return_val_if_fail(input != NULL, NULL); - - endpoint = g_ascii_strdown(input, -1); - - for (l = user->endpoints; l; l = l->next) { - ep = l->data; - if (g_str_equal(ep->id, endpoint)) { - g_free(endpoint); - return ep; - } - } - - g_free(endpoint); - - return NULL; -} - -MsnNetwork -msn_user_get_network(const MsnUser *user) -{ - g_return_val_if_fail(user != NULL, MSN_NETWORK_UNKNOWN); - - return user->networkid; -} - -MsnObject * -msn_user_get_object(const MsnUser *user) -{ - g_return_val_if_fail(user != NULL, NULL); - - return user->msnobj; -} - -GHashTable * -msn_user_get_client_caps(const MsnUser *user) -{ - g_return_val_if_fail(user != NULL, NULL); - - return user->clientcaps; -} - -const char * -msn_user_get_invite_message(const MsnUser *user) -{ - g_return_val_if_fail(user != NULL, NULL); - - return user->invite_message; -} - -gboolean -msn_user_is_capable(MsnUser *user, char *endpoint, guint capability, guint extcap) -{ - g_return_val_if_fail(user != NULL, FALSE); - - if (endpoint != NULL) { - MsnUserEndpoint *ep = msn_user_get_endpoint_data(user, endpoint); - if (ep != NULL) - return (ep->clientid & capability) && (ep->extcaps & extcap); - else - return FALSE; - } - - return (user->clientid & capability) && (user->extcaps & extcap); -} - -/************************************************************************** - * Utility functions - **************************************************************************/ - -int -msn_user_passport_cmp(MsnUser *user, const char *passport) -{ - const char *str; - char *pass; - int result; - - str = purple_normalize_nocase(NULL, msn_user_get_passport(user)); - pass = g_strdup(str); - -#if GLIB_CHECK_VERSION(2,16,0) - result = g_strcmp0(pass, purple_normalize_nocase(NULL, passport)); -#else - str = purple_normalize_nocase(NULL, passport); - if (!pass) - result = -(pass != str); - else if (!str) - result = pass != str; - else - result = strcmp(pass, str); -#endif /* GLIB < 2.16.0 */ - - g_free(pass); - - return result; -} - -gboolean -msn_user_is_in_group(MsnUser *user, const char * group_id) -{ - if (user == NULL) - return FALSE; - - if (group_id == NULL) - return FALSE; - - return (g_list_find_custom(user->group_ids, group_id, (GCompareFunc)strcmp)) != NULL; -} - -gboolean -msn_user_is_in_list(MsnUser *user, MsnListId list_id) -{ - if (user == NULL) - return FALSE; - - return (user->list_op & (1 << list_id)); -} - diff --git a/libpurple/protocols/msn/user.h b/libpurple/protocols/msn/user.h deleted file mode 100644 index 727c717a8f..0000000000 --- a/libpurple/protocols/msn/user.h +++ /dev/null @@ -1,533 +0,0 @@ -/** - * @file user.h User functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_USER_H -#define MSN_USER_H - -typedef struct _MsnUser MsnUser; - -typedef enum -{ - MSN_NETWORK_UNKNOWN = 0, - MSN_NETWORK_PASSPORT = 1, - MSN_NETWORK_COMMUNICATOR = 2, - MSN_NETWORK_MOBILE = 4, - MSN_NETWORK_MNI = 8, - MSN_NETWORK_CIRCLE = 9, - MSN_NETWORK_TEMP_GROUP = 10, - MSN_NETWORK_CID = 11, - MSN_NETWORK_CONNECT = 13, - MSN_NETWORK_REMOTE = 14, - MSN_NETWORK_SMTP = 16, - MSN_NETWORK_YAHOO = 32 -} MsnNetwork; - -/** - * Current media. - */ -typedef enum -{ - CURRENT_MEDIA_UNKNOWN, - CURRENT_MEDIA_MUSIC, - CURRENT_MEDIA_GAMES, - CURRENT_MEDIA_OFFICE -} CurrentMediaType; - -#include "object.h" -#include "session.h" -#include "userlist.h" - -/** - * Contains optional info about a user that is fairly uncommon. We - * put this info in in a separate struct to save memory because we - * allocate an MsnUser struct for each buddy, but we generally only - * need this information for a small percentage of our buddies - * (usually less than 1%). Putting it in a separate struct makes - * MsnUser smaller by the size of a few pointers. - */ -typedef struct _MsnUserExtendedInfo -{ - CurrentMediaType media_type; /**< Type of the user's current media. */ - char *media_title; /**< Title of the user's current media. */ - char *media_artist; /**< Artist of the user's current media. */ - char *media_album; /**< Album of the user's current media. */ - - char *phone_home; /**< E.T. uses this. */ - char *phone_work; /**< Work phone number. */ - char *phone_mobile; /**< Mobile phone number. */ -} MsnUserExtendedInfo; - -/** - * A user. - */ -struct _MsnUser -{ - MsnUserList *userlist; - - guint8 refcount; /**< The reference count of this object */ - - char *passport; /**< The passport account. */ - char *friendly_name; /**< The friendly name. */ - - char *uid; /*< User ID */ - GSList *endpoints; /*< Endpoint-specific data */ - - const char *status; /**< The state of the user. */ - char *statusline; /**< The state of the user. */ - - gboolean idle; /**< The idle state of the user. */ - - MsnUserExtendedInfo *extinfo; /**< Extended info for the user. */ - - gboolean authorized; /**< Authorized to add this user. */ - gboolean mobile; /**< Signed up with MSN Mobile. */ - - GList *group_ids; /**< The group IDs. */ - char *pending_group; /**< A pending group to add. */ - - MsnObject *msnobj; /**< The user's MSN Object. */ - - GHashTable *clientcaps; /**< The client's capabilities. */ - - guint clientid; /**< The client's ID */ - guint extcaps; /**< The client's extended capabilities */ - - MsnNetwork networkid; /**< The user's network */ - - MsnListOp list_op; /**< Which lists the user is in */ - - /** - * The membershipId for this buddy on our pending list. Sent by - * the contact's server - */ - guint member_id_on_pending_list; - - char *invite_message; /**< Invite message of user request */ -}; - -/** - * A specific user endpoint. - */ -typedef struct MsnUserEndpoint { - char *id; /**< The client's endpoint ID */ - char *name; /**< The client's endpoint's name */ - int type; /**< The client's endpoint type */ - guint clientid; /**< The client's ID */ - guint extcaps; /**< The client's extended capabilites */ - -} MsnUserEndpoint; - -/************************************************************************** - ** @name User API * - **************************************************************************/ -/*@{*/ - -/** - * Creates a new user structure. - * - * @param session The MSN session. - * @param passport The initial passport. - * @param stored_name The initial stored name. - * - * @return A new user structure. It will have a reference count of 1. - */ -MsnUser *msn_user_new(MsnUserList *userlist, const char *passport, - const char *friendly_name); - -/** - * Increment the reference count. - * - * @param user The user. - * - * @return user. - */ -MsnUser *msn_user_ref(MsnUser *user); - -/** - * Decrement the reference count. When the count reaches 0 the object is - * automatically freed. - * - * @param user The user - */ -void msn_user_unref(MsnUser *user); - -/** - * Updates the user. - * - * Communicates with the core to update the ui, etc. - * - * @param user The user to update. - */ -void msn_user_update(MsnUser *user); - - /** - * Sets the new statusline of user. - * - * @param user The user. - * @param state The statusline string. - */ -void msn_user_set_statusline(MsnUser *user, const char *statusline); - -/** - * Sets the new state of user. - * - * @param user The user. - * @param state The state string. - */ -void msn_user_set_state(MsnUser *user, const char *state); - -/** - * Sets the passport account for a user. - * - * @param user The user. - * @param passport The passport account. - */ -void msn_user_set_passport(MsnUser *user, const char *passport); - -/** - * Sets the friendly name for a user. - * - * @param user The user. - * @param name The friendly name. - * - * @returns TRUE is name actually changed, FALSE otherwise. - */ -gboolean msn_user_set_friendly_name(MsnUser *user, const char *name); - -/** - * Sets the buddy icon for a local user. - * - * @param user The user. - * @param img The buddy icon image - */ -void msn_user_set_buddy_icon(MsnUser *user, PurpleStoredImage *img); - -/** - * Sets the group ID list for a user. - * - * @param user The user. - * @param ids The group ID list. - */ -void msn_user_set_group_ids(MsnUser *user, GList *ids); - -/** - * Adds the group ID for a user. - * - * @param user The user. - * @param id The group ID. - */ -void msn_user_add_group_id(MsnUser *user, const char * id); - -/** - * Removes the group ID from a user. - * - * @param user The user. - * @param id The group ID. - */ -void msn_user_remove_group_id(MsnUser *user, const char * id); - -/** - * Sets the pending group for a user. - * - * @param user The user. - * @param group The group name. - */ -void msn_user_set_pending_group(MsnUser *user, const char *group); - -/** - * Removes the pending group from a user. - * - * @param user The user. - * - * @return Returns the pending group name. - */ -char *msn_user_remove_pending_group(MsnUser *user); - -/** - * Sets the home phone number for a user. - * - * @param user The user. - * @param number The home phone number. - */ -void msn_user_set_home_phone(MsnUser *user, const char *number); - -/** - * Sets the work phone number for a user. - * - * @param user The user. - * @param number The work phone number. - */ -void msn_user_set_work_phone(MsnUser *user, const char *number); - -void msn_user_set_uid(MsnUser *user, const char *uid); - -/** - * Sets endpoint data for a user. - * - * @param user The user. - * @param endpoint The endpoint. - * @param data The endpoint data. - */ -void -msn_user_set_endpoint_data(MsnUser *user, const char *endpoint, MsnUserEndpoint *data); - -/** - * Clears all endpoint data for a user. - * - * @param user The user. - */ -void -msn_user_clear_endpoints(MsnUser *user); - -/** - * Sets the client id for a user. - * - * @param user The user. - * @param clientid The client id. - */ -void msn_user_set_clientid(MsnUser *user, guint clientid); - -/** - * Sets the client id for a user. - * - * @param user The user. - * @param extcaps The client's extended capabilities. - */ -void msn_user_set_extcaps(MsnUser *user, guint extcaps); - -/** - * Sets the network id for a user. - * - * @param user The user. - * @param network The network id. - */ -void msn_user_set_network(MsnUser *user, MsnNetwork network); - -/** - * Sets the mobile phone number for a user. - * - * @param user The user. - * @param number The mobile phone number. - */ -void msn_user_set_mobile_phone(MsnUser *user, const char *number); - -/** - * Sets the MSNObject for a user. - * - * @param user The user. - * @param obj The MSNObject. - */ -void msn_user_set_object(MsnUser *user, MsnObject *obj); - -/** - * Sets the client information for a user. - * - * @param user The user. - * @param info The client information. - */ -void msn_user_set_client_caps(MsnUser *user, GHashTable *info); - -/** - * Sets the invite message for a user. - * - * @param user The user. - * @param message The invite message for a user. - */ -void msn_user_set_invite_message(MsnUser *user, const char *message); - - -/** - * Returns the passport account for a user. - * - * @param user The user. - * - * @return The passport account. - */ -const char *msn_user_get_passport(const MsnUser *user); - -/** - * Returns the friendly name for a user. - * - * @param user The user. - * - * @return The friendly name. - */ -const char *msn_user_get_friendly_name(const MsnUser *user); - -/** - * Returns the home phone number for a user. - * - * @param user The user. - * - * @return The user's home phone number. - */ -const char *msn_user_get_home_phone(const MsnUser *user); - -/** - * Returns the work phone number for a user. - * - * @param user The user. - * - * @return The user's work phone number. - */ -const char *msn_user_get_work_phone(const MsnUser *user); - -/** - * Returns the mobile phone number for a user. - * - * @param user The user. - * - * @return The user's mobile phone number. - */ -const char *msn_user_get_mobile_phone(const MsnUser *user); - -/** - * Gets endpoint data for a user. - * - * @param user The user. - * @param endpoint The endpoint. - * - * @return The user's endpoint data. - */ -MsnUserEndpoint * -msn_user_get_endpoint_data(MsnUser *user, const char *endpoint); - -/** - * Returns the client id for a user. - * - * @param user The user. - * - * @return The user's client id. - */ -guint msn_user_get_clientid(const MsnUser *user); - -/** - * Returns the extended capabilities for a user. - * - * @param user The user. - * - * @return The user's extended capabilities. - */ -guint msn_user_get_extcaps(const MsnUser *user); - -/************************************************************************** - * Utility functions - **************************************************************************/ - - -/** - * Check if the user is part of the group. - * - * @param user The user we are asking group membership. - * @param group_id The group where the user may be in. - * - * @return TRUE if user is part of the group. Otherwise, FALSE. - */ -gboolean msn_user_is_in_group(MsnUser *user, const char * group_id); - -/** - * Check if user is on list. - * - * @param user The user we are asking list membership. - * @param list_id The list where the user may be in. - * - * @return TRUE if the user is on the list, else FALSE. - */ -gboolean msn_user_is_in_list(MsnUser *user, MsnListId list_id); -/** - * Returns the network id for a user. - * - * @param user The user. - * - * @return The user's network id. - */ -MsnNetwork msn_user_get_network(const MsnUser *user); - -/** - * Returns the MSNObject for a user. - * - * @param user The user. - * - * @return The MSNObject. - */ -MsnObject *msn_user_get_object(const MsnUser *user); - -/** - * Returns the client information for a user. - * - * @param user The user. - * - * @return The client information. - */ -GHashTable *msn_user_get_client_caps(const MsnUser *user); - -/** - * Returns the invite message for a user. - * - * @param user The user. - * - * @return The user's invite message. - */ -const char *msn_user_get_invite_message(const MsnUser *user); - -/** - * check to see if user is online - */ -gboolean msn_user_is_online(PurpleAccount *account, const char *name); - -/** - * check to see if user is Yahoo User - */ -gboolean msn_user_is_yahoo(PurpleAccount *account, const char *name); - -void msn_user_set_op(MsnUser *user, MsnListOp list_op); -void msn_user_unset_op(MsnUser *user, MsnListOp list_op); - -/** - * Compare the given passport with the one of the user - * - * @param user User to compare. - * @oaran passport Passport to compare. - * - * @return Zero if the passport match with the one of the user, otherwise - * a positive integer if the user passport is greather than the one given - * and a negative integer if it is less. - */ -int msn_user_passport_cmp(MsnUser *user, const char *passport); - -/** - * Checks whether a user is capable of some task. - * - * @param user The user. - * @param endpoint The endpoint. Can be @NULL to check overall capabilities. - * @param capability The capability (including client version). - * @param extcap The extended capability. - * - * @return Whether the user supports the capability. - */ -gboolean -msn_user_is_capable(MsnUser *user, char *endpoint, guint capability, guint extcap); - -/*@}*/ - -#endif /* MSN_USER_H */ diff --git a/libpurple/protocols/msn/userlist.c b/libpurple/protocols/msn/userlist.c deleted file mode 100644 index 8ad73813ff..0000000000 --- a/libpurple/protocols/msn/userlist.c +++ /dev/null @@ -1,759 +0,0 @@ -/** - * @file userlist.c MSN user list support - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "debug.h" -#include "request.h" - -#include "msn.h" -#include "msnutils.h" -#include "userlist.h" - -#include "contact.h" - -const char *lists[] = { "FL", "AL", "BL", "RL" }; - -typedef struct -{ - PurpleConnection *gc; - char *who; - char *friendly; - -} MsnPermitAdd; - -/************************************************************************** - * Callbacks - **************************************************************************/ -static void -msn_accept_add_cb(gpointer data) -{ - MsnPermitAdd *pa = data; - - purple_debug_misc("msn", "Accepted the new buddy: %s\n", pa->who); - - if (PURPLE_CONNECTION_IS_VALID(pa->gc)) - { - MsnSession *session = pa->gc->proto_data; - MsnUserList *userlist = session->userlist; - PurpleAccount *account = purple_connection_get_account(pa->gc); - - msn_userlist_add_buddy_to_list(userlist, pa->who, MSN_LIST_AL); - purple_privacy_deny_remove(account, pa->who, TRUE); - purple_privacy_permit_add(account, pa->who, TRUE); - - msn_del_contact_from_list(session, NULL, pa->who, MSN_LIST_PL); - } - - g_free(pa->who); - g_free(pa->friendly); - g_free(pa); -} - -static void -msn_cancel_add_cb(gpointer data) -{ - MsnPermitAdd *pa = data; - - purple_debug_misc("msn", "Denied the new buddy: %s\n", pa->who); - - if (PURPLE_CONNECTION_IS_VALID(pa->gc)) - { - MsnSession *session = pa->gc->proto_data; - MsnUserList *userlist = session->userlist; - MsnCallbackState *state = msn_callback_state_new(session); - - msn_callback_state_set_action(state, MSN_DENIED_BUDDY); - - msn_userlist_add_buddy_to_list(userlist, pa->who, MSN_LIST_BL); - msn_del_contact_from_list(session, state, pa->who, MSN_LIST_PL); - } - - g_free(pa->who); - g_free(pa->friendly); - g_free(pa); -} - -static void -got_new_entry(PurpleConnection *gc, const char *passport, const char *friendly, const char *message) -{ - PurpleAccount *acct; - MsnPermitAdd *pa; - - pa = g_new0(MsnPermitAdd, 1); - pa->who = g_strdup(passport); - pa->friendly = g_strdup(friendly); - pa->gc = gc; - - acct = purple_connection_get_account(gc); - purple_account_request_authorization(acct, passport, NULL, friendly, message, - purple_find_buddy(acct, passport) != NULL, - msn_accept_add_cb, msn_cancel_add_cb, pa); - -} - -/************************************************************************** - * Server functions - **************************************************************************/ - -void -msn_got_lst_user(MsnSession *session, MsnUser *user, - MsnListOp list_op, GSList *group_ids) -{ - PurpleConnection *gc; - PurpleAccount *account; - const char *passport; - const char *store; - const char *message; - - account = session->account; - gc = purple_account_get_connection(account); - - passport = msn_user_get_passport(user); - store = msn_user_get_friendly_name(user); - message = msn_user_get_invite_message(user); - - msn_user_set_op(user, list_op); - - if (list_op & MSN_LIST_FL_OP) - { - GSList *c; - for (c = group_ids; c != NULL; c = g_slist_next(c)) - { - char *group_id = c->data; - msn_user_add_group_id(user, group_id); - } - - /* FIXME: It might be a real alias */ - /* Umm, what? This might fix bug #1385130 */ - serv_got_alias(gc, passport, store); - } - - if (list_op & MSN_LIST_AL_OP) - { - /* These are users who are allowed to see our status. */ - purple_privacy_deny_remove(account, passport, TRUE); - purple_privacy_permit_add(account, passport, TRUE); - } - - if (list_op & MSN_LIST_BL_OP) - { - /* These are users who are not allowed to see our status. */ - purple_privacy_permit_remove(account, passport, TRUE); - purple_privacy_deny_add(account, passport, TRUE); - } - - if (list_op & MSN_LIST_RL_OP) - { - /* These are users who have us on their buddy list. */ - /* - * TODO: What is store name set to when this happens? - * For one of my accounts "something@hotmail.com" - * the store name was "something." Maybe we - * should use the friendly name, instead? --KingAnt - */ - - if (!(list_op & (MSN_LIST_AL_OP | MSN_LIST_BL_OP))) - { -/* got_new_entry(gc, passport, store, NULL); */ - } - } - - if (list_op & MSN_LIST_PL_OP) - { - user->authorized = TRUE; - got_new_entry(gc, passport, store, message); - } -} - -/************************************************************************** - * UserList functions - **************************************************************************/ - -MsnUserList* -msn_userlist_new(MsnSession *session) -{ - MsnUserList *userlist; - - userlist = g_new0(MsnUserList, 1); - - userlist->session = session; - userlist->buddy_icon_requests = g_queue_new(); - - /* buddy_icon_window is the number of allowed simultaneous buddy icon requests. - * XXX With smarter rate limiting code, we could allow more at once... 5 was the limit set when - * we weren't retrieiving any more than 5 per MSN session. */ - userlist->buddy_icon_window = 1; - - return userlist; -} - -void -msn_userlist_destroy(MsnUserList *userlist) -{ - GList *l; - - /*destroy userlist*/ - for (l = userlist->users; l != NULL; l = l->next) - { - msn_user_unref(l->data); - } - g_list_free(userlist->users); - - /*destroy group list*/ - for (l = userlist->groups; l != NULL; l = l->next) - { - msn_group_destroy(l->data); - } - g_list_free(userlist->groups); - - g_queue_free(userlist->buddy_icon_requests); - - if (userlist->buddy_icon_request_timer) - purple_timeout_remove(userlist->buddy_icon_request_timer); - - g_free(userlist); -} - -MsnUser * -msn_userlist_find_add_user(MsnUserList *userlist, const char *passport, const char *friendly_name) -{ - MsnUser *user; - - user = msn_userlist_find_user(userlist, passport); - if (user == NULL) - { - user = msn_user_new(userlist, passport, friendly_name); - msn_userlist_add_user(userlist, user); - msn_user_unref(user); - } else { - msn_user_set_friendly_name(user, friendly_name); - } - return user; -} - -void -msn_userlist_add_user(MsnUserList *userlist, MsnUser *user) -{ - msn_user_ref(user); - userlist->users = g_list_prepend(userlist->users, user); -} - -void -msn_userlist_remove_user(MsnUserList *userlist, MsnUser *user) -{ - userlist->users = g_list_remove(userlist->users, user); - g_queue_remove(userlist->buddy_icon_requests, user); - msn_user_unref(user); -} - -MsnUser * -msn_userlist_find_user(MsnUserList *userlist, const char *passport) -{ - GList *l; - - g_return_val_if_fail(passport != NULL, NULL); - - for (l = userlist->users; l != NULL; l = l->next) - { - MsnUser *user = (MsnUser *)l->data; - - g_return_val_if_fail(user->passport != NULL, NULL); - - if (!g_ascii_strcasecmp(passport, user->passport)){ - return user; - } - } - - return NULL; -} - -MsnUser * -msn_userlist_find_user_with_id(MsnUserList *userlist, const char *uid) -{ - GList *l; - - g_return_val_if_fail(uid != NULL, NULL); - - for (l = userlist->users; l != NULL; l = l->next) { - MsnUser *user = (MsnUser *)l->data; - - if (user->uid == NULL) { - continue; - } - - if ( !g_ascii_strcasecmp(uid, user->uid) ) { - return user; - } - } - - return NULL; -} - -MsnUser * -msn_userlist_find_user_with_mobile_phone(MsnUserList *userlist, const char *number) -{ - GList *l; - - g_return_val_if_fail(number != NULL, NULL); - - for (l = userlist->users; l != NULL; l = l->next) { - MsnUser *user = (MsnUser *)l->data; - const char *user_number = msn_user_get_mobile_phone(user); - - if (user_number && !g_ascii_strcasecmp(number, user_number)) - return user; - } - - return NULL; -} - -void -msn_userlist_add_group(MsnUserList *userlist, MsnGroup *group) -{ - userlist->groups = g_list_append(userlist->groups, group); -} - -void -msn_userlist_remove_group(MsnUserList *userlist, MsnGroup *group) -{ - userlist->groups = g_list_remove(userlist->groups, group); -} - -MsnGroup * -msn_userlist_find_group_with_id(MsnUserList *userlist, const char * id) -{ - GList *l; - - g_return_val_if_fail(userlist != NULL, NULL); - g_return_val_if_fail(id != NULL, NULL); - - for (l = userlist->groups; l != NULL; l = l->next) - { - MsnGroup *group = l->data; - - if (!g_ascii_strcasecmp(group->id,id)) - return group; - } - - return NULL; -} - -MsnGroup * -msn_userlist_find_group_with_name(MsnUserList *userlist, const char *name) -{ - GList *l; - - g_return_val_if_fail(userlist != NULL, NULL); - g_return_val_if_fail(name != NULL, NULL); - - for (l = userlist->groups; l != NULL; l = l->next) - { - MsnGroup *group = l->data; - - if ((group->name != NULL) && !g_ascii_strcasecmp(name, group->name)) - return group; - } - - return NULL; -} - -const char * -msn_userlist_find_group_id(MsnUserList *userlist, const char *group_name) -{ - MsnGroup *group; - - group = msn_userlist_find_group_with_name(userlist, group_name); - - if (group != NULL) - return msn_group_get_id(group); - else - return NULL; -} - -const char * -msn_userlist_find_group_name(MsnUserList *userlist, const char * group_id) -{ - MsnGroup *group; - - group = msn_userlist_find_group_with_id(userlist, group_id); - - if (group != NULL) - return msn_group_get_name(group); - else - return NULL; -} - -void -msn_userlist_rename_group_id(MsnUserList *userlist, const char * group_id, - const char *new_name) -{ - MsnGroup *group; - - group = msn_userlist_find_group_with_id(userlist, group_id); - - if (group != NULL) - msn_group_set_name(group, new_name); -} - -void -msn_userlist_remove_group_id(MsnUserList *userlist, const char * group_id) -{ - MsnGroup *group; - - group = msn_userlist_find_group_with_id(userlist, group_id); - - if (group != NULL) - { - msn_userlist_remove_group(userlist, group); - msn_group_destroy(group); - } -} - -typedef struct { - MsnSession *session; - char *uid; -} MsnUserlistABData; - -static void -userlist_ab_delete_cb(void *data, int choice) -{ - MsnUserlistABData *ab = (MsnUserlistABData *)data; - - /* msn_delete_contact(ab->session, ab->uid, (gboolean)choice); */ - - g_free(ab->uid); - g_free(ab); -} - -void -msn_userlist_rem_buddy(MsnUserList *userlist, const char *who) -{ - MsnUser *user = NULL; - - g_return_if_fail(userlist != NULL); - g_return_if_fail(userlist->session != NULL); - g_return_if_fail(who != NULL); - - user = msn_userlist_find_user(userlist, who); - - msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_FL); - - /* delete the contact from address book via soap action */ - if (user != NULL) { - if (0 /*not ready yet*/ && userlist->session->passport_info.email_enabled) { - MsnUserlistABData *ab = g_new0(MsnUserlistABData, 1); - ab->session = userlist->session; - ab->uid = g_strdup(user->uid); /* Not necessary? */ - purple_request_yes_no(userlist->session->account, - _("Delete Buddy from Address Book?"), - _("Do you want to delete this buddy from your address book as well?"), - user->passport, 0, userlist->session->account, user->passport, - NULL, ab, - G_CALLBACK(userlist_ab_delete_cb), G_CALLBACK(userlist_ab_delete_cb)); - } else - msn_delete_contact(userlist->session, user); - } -} - -void -msn_userlist_rem_buddy_from_list(MsnUserList *userlist, const char *who, - MsnListId list_id) -{ - MsnUser *user; - const gchar *list; - MsnListOp list_op = 1 << list_id; - - user = msn_userlist_find_user(userlist, who); - - g_return_if_fail(user != NULL); - - if ( !msn_user_is_in_list(user, list_id)) { - list = lists[list_id]; - purple_debug_info("msn", "User %s is not in list %s, not removing.\n", who, list); - return; - } - - msn_user_unset_op(user, list_op); - - msn_notification_rem_buddy_from_list(userlist->session->notification, list_id, user); -} - -/*add buddy*/ -void -msn_userlist_add_buddy(MsnUserList *userlist, const char *who, const char *group_name) -{ - MsnUser *user; - MsnCallbackState *state = NULL; - const char *group_id = NULL, *new_group_name; - - new_group_name = group_name == NULL ? MSN_INDIVIDUALS_GROUP_NAME : group_name; - - g_return_if_fail(userlist != NULL); - g_return_if_fail(userlist->session != NULL); - - purple_debug_info("msn", "Add user: %s to group: %s\n", who, new_group_name); - - if (!msn_email_is_valid(who)) - { - /* only notify the user about problems adding to the friends list - * maybe we should do something else for other lists, but it probably - * won't cause too many problems if we just ignore it */ - - char *str = g_strdup_printf(_("Unable to add \"%s\"."), who); - - purple_notify_error(NULL, NULL, str, - _("The username specified is invalid.")); - g_free(str); - - return; - } - - state = msn_callback_state_new(userlist->session); - msn_callback_state_set_who(state, who); - msn_callback_state_set_new_group_name(state, new_group_name); - - group_id = msn_userlist_find_group_id(userlist, new_group_name); - - if (group_id == NULL) - { - /* Whoa, we must add that group first. */ - purple_debug_info("msn", "Adding user %s to a new group, creating group %s first\n", who, new_group_name); - - msn_callback_state_set_action(state, MSN_ADD_BUDDY); - - msn_add_group(userlist->session, state, new_group_name); - return; - } else { - msn_callback_state_set_guid(state, group_id); - } - - /* XXX: adding user here may not be correct (should add them in the - * ACK to the ADL command), but for now we need to make sure they exist - * early enough that the ILN command doesn't screw us up */ - - user = msn_userlist_find_add_user(userlist, who, who); - - if ( msn_user_is_in_list(user, MSN_LIST_FL) ) { - - purple_debug_info("msn", "User %s already exists\n", who); - - msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_BL); - - if (msn_user_is_in_group(user, group_id)) { - purple_debug_info("msn", "User %s is already in group %s, returning\n", who, new_group_name); - msn_callback_state_free(state); - return; - } - } - - purple_debug_info("msn", "Adding user: %s to group id: %s\n", who, group_id); - - msn_callback_state_set_action(state, MSN_ADD_BUDDY); - - /* Add contact in the Contact server with a SOAP request and if - successful, send ADL with MSN_LIST_AL and MSN_LIST_FL and a FQY */ - msn_add_contact_to_group(userlist->session, state, who, group_id); -} - -void -msn_userlist_add_buddy_to_list(MsnUserList *userlist, const char *who, - MsnListId list_id) -{ - MsnUser *user = NULL; - const gchar *list; - MsnListOp list_op = 1 << list_id; - - g_return_if_fail(userlist != NULL); - - user = msn_userlist_find_add_user(userlist, who, who); - - /* First we're going to check if it's already there. */ - if (msn_user_is_in_list(user, list_id)) - { - list = lists[list_id]; - purple_debug_info("msn", "User '%s' is already in list: %s\n", who, list); - return; - } - - /* XXX: see XXX above, this should really be done when we get the response from - the server */ - - msn_user_set_op(user, list_op); - - msn_notification_add_buddy_to_list(userlist->session->notification, list_id, user); -} - -gboolean -msn_userlist_add_buddy_to_group(MsnUserList *userlist, const char *who, - const char *group_name) -{ - MsnUser *user; - gchar * group_id; - - g_return_val_if_fail(userlist != NULL, FALSE); - g_return_val_if_fail(group_name != NULL, FALSE); - g_return_val_if_fail(who != NULL, FALSE); - - purple_debug_info("msn", "Adding buddy with passport %s to group %s\n", who, group_name); - - if ( (group_id = (gchar *)msn_userlist_find_group_id(userlist, group_name)) == NULL) { - purple_debug_error("msn", "Group %s has no guid!\n", group_name); - return FALSE; - } - - if ( (user = msn_userlist_find_user(userlist, who)) == NULL) { - purple_debug_error("msn", "User %s not found!\n", who); - return FALSE; - } - - msn_user_add_group_id(user, group_id); - - return TRUE; -} - - -gboolean -msn_userlist_rem_buddy_from_group(MsnUserList *userlist, const char *who, - const char *group_name) -{ - const gchar * group_id; - MsnUser *user; - - g_return_val_if_fail(userlist != NULL, FALSE); - g_return_val_if_fail(group_name != NULL, FALSE); - g_return_val_if_fail(who != NULL, FALSE); - - purple_debug_info("msn", "Removing buddy with passport %s from group %s\n", who, group_name); - - if ( (group_id = msn_userlist_find_group_id(userlist, group_name)) == NULL) { - purple_debug_error("msn", "Group %s has no guid!\n", group_name); - return FALSE; - } - - if ( (user = msn_userlist_find_user(userlist, who)) == NULL) { - purple_debug_error("msn", "User %s not found!\n", who); - return FALSE; - } - - msn_user_remove_group_id(user, group_id); - - return TRUE; -} - -void -msn_userlist_move_buddy(MsnUserList *userlist, const char *who, - const char *old_group_name, const char *new_group_name) -{ - const char *new_group_id; - MsnCallbackState *state; - - g_return_if_fail(userlist != NULL); - g_return_if_fail(userlist->session != NULL); - - state = msn_callback_state_new(userlist->session); - msn_callback_state_set_who(state, who); - msn_callback_state_set_action(state, MSN_MOVE_BUDDY); - msn_callback_state_set_old_group_name(state, old_group_name); - msn_callback_state_set_new_group_name(state, new_group_name); - - new_group_id = msn_userlist_find_group_id(userlist, new_group_name); - - if (new_group_id == NULL) - { - msn_add_group(userlist->session, state, new_group_name); - return; - } - - /* add the contact to the new group, and remove it from the old one in - * the callback - */ - msn_add_contact_to_group(userlist->session, state, who, new_group_id); -} - -void -msn_release_buddy_icon_request(MsnUserList *userlist) -{ - MsnUser *user; - - g_return_if_fail(userlist != NULL); - - if (purple_debug_is_verbose()) - purple_debug_info("msn", "Releasing buddy icon request\n"); - - if (userlist->buddy_icon_window > 0) { - GQueue *queue; - - queue = userlist->buddy_icon_requests; - - if (g_queue_is_empty(userlist->buddy_icon_requests)) - return; - - user = g_queue_pop_head(queue); - - userlist->buddy_icon_window--; - - msn_request_user_display(user); - - if (purple_debug_is_verbose()) - purple_debug_info("msn", - "msn_release_buddy_icon_request(): buddy_icon_window-- yields =%d\n", - userlist->buddy_icon_window); - } -} - -/*load userlist from the Blist file cache*/ -void -msn_userlist_load(MsnSession *session) -{ - PurpleAccount *account = session->account; - PurpleConnection *gc = purple_account_get_connection(account); - GSList *l; - MsnUser * user; - - g_return_if_fail(gc != NULL); - - for (l = purple_find_buddies(account, NULL); l != NULL; - l = g_slist_delete_link(l, l)) { - PurpleBuddy *buddy = l->data; - - user = msn_userlist_find_add_user(session->userlist, - purple_buddy_get_name(buddy), NULL); - purple_buddy_set_protocol_data(buddy, user); - msn_user_set_op(user, MSN_LIST_FL_OP); - } - for (l = session->account->permit; l != NULL; l = l->next) - { - user = msn_userlist_find_add_user(session->userlist, - (char *)l->data,NULL); - msn_user_set_op(user, MSN_LIST_AL_OP); - } - for (l = session->account->deny; l != NULL; l = l->next) - { - user = msn_userlist_find_add_user(session->userlist, - (char *)l->data,NULL); - msn_user_set_op(user, MSN_LIST_BL_OP); - } - -} - diff --git a/libpurple/protocols/msn/userlist.h b/libpurple/protocols/msn/userlist.h deleted file mode 100644 index 4e9582a756..0000000000 --- a/libpurple/protocols/msn/userlist.h +++ /dev/null @@ -1,112 +0,0 @@ -/** - * @file userlist.h MSN user list support - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#ifndef MSN_USERLIST_H -#define MSN_USERLIST_H - -typedef struct _MsnUserList MsnUserList; - -typedef enum -{ - MSN_LIST_FL, /**< Forward list */ - MSN_LIST_AL, /**< Allow list */ - MSN_LIST_BL, /**< Block list */ - MSN_LIST_RL, /**< Reverse list */ - MSN_LIST_PL /**< Pending list */ -} MsnListId; - -typedef enum -{ - MSN_LIST_FL_OP = 0x01, - MSN_LIST_AL_OP = 0x02, - MSN_LIST_BL_OP = 0x04, - MSN_LIST_RL_OP = 0x08, - MSN_LIST_PL_OP = 0x10 -} MsnListOp; -#define MSN_LIST_OP_MASK 0x07 - -#include "group.h" -#include "msn.h" -#include "user.h" - -struct _MsnUserList -{ - MsnSession *session; - - GList *users; /* Contains MsnUsers */ - GList *groups; /* Contains MsnGroups */ - - GQueue *buddy_icon_requests; - int buddy_icon_window; - guint buddy_icon_request_timer; - -}; - -void msn_got_lst_user(MsnSession *session, MsnUser *user, - MsnListOp list_op, GSList *group_ids); - -MsnUserList *msn_userlist_new(MsnSession *session); -void msn_userlist_destroy(MsnUserList *userlist); - -void msn_userlist_add_user(MsnUserList *userlist, MsnUser *user); -void msn_userlist_remove_user(MsnUserList *userlist, MsnUser *user); - -MsnUser * msn_userlist_find_user(MsnUserList *userlist, const char *passport); -MsnUser * msn_userlist_find_add_user(MsnUserList *userlist, - const char *passport, const char *friendly_name); -MsnUser * msn_userlist_find_user_with_id(MsnUserList *userlist, const char *uid); -MsnUser * msn_userlist_find_user_with_mobile_phone(MsnUserList *userlist, const char *number); - -void msn_userlist_add_group(MsnUserList *userlist, MsnGroup *group); -void msn_userlist_remove_group(MsnUserList *userlist, MsnGroup *group); -MsnGroup *msn_userlist_find_group_with_id(MsnUserList *userlist, const char *id); -MsnGroup *msn_userlist_find_group_with_name(MsnUserList *userlist, const char *name); -const char * msn_userlist_find_group_id(MsnUserList *userlist, - const char *group_name); -const char *msn_userlist_find_group_name(MsnUserList *userlist, const char *group_id); -void msn_userlist_rename_group_id(MsnUserList *userlist, const char *group_id, - const char *new_name); -void msn_userlist_remove_group_id(MsnUserList *userlist, const char *group_id); - -void msn_userlist_rem_buddy(MsnUserList *userlist, const char *who); -void msn_userlist_add_buddy(MsnUserList *userlist, - const char *who, const char *group_name); -void msn_userlist_move_buddy(MsnUserList *userlist, const char *who, - const char *old_group_name, - const char *new_group_name); - -gboolean msn_userlist_add_buddy_to_group(MsnUserList *userlist, const char *who, - const char *group_name); -gboolean msn_userlist_rem_buddy_from_group(MsnUserList *userlist, - const char *who, - const char *group_name); - -void msn_userlist_add_buddy_to_list(MsnUserList *userlist, const char *who, - MsnListId list_id); -void msn_userlist_rem_buddy_from_list(MsnUserList *userlist, const char *who, - MsnListId list_id); -void msn_release_buddy_icon_request(MsnUserList *userlist); - -void msn_userlist_load(MsnSession *session); - -#endif /* MSN_USERLIST_H */ diff --git a/libpurple/protocols/msn/xfer.c b/libpurple/protocols/msn/xfer.c deleted file mode 100644 index 4da276dacd..0000000000 --- a/libpurple/protocols/msn/xfer.c +++ /dev/null @@ -1,235 +0,0 @@ -/** - * @file xfer.c MSN File Transfer functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "debug.h" - -#include "msnutils.h" -#include "sbconn.h" -#include "xfer.h" - -/************************************************************************** - * Xfer - **************************************************************************/ - -void -msn_xfer_init(PurpleXfer *xfer) -{ - MsnSlpCall *slpcall; - /* MsnSlpLink *slplink; */ - char *content; - - purple_debug_info("msn", "xfer_init\n"); - - slpcall = xfer->data; - - /* Send Ok */ - content = g_strdup_printf("SessionID: %lu\r\n\r\n", - slpcall->session_id); - - msn_slp_send_ok(slpcall, slpcall->branch, "application/x-msnmsgr-sessionreqbody", - content); - - g_free(content); - msn_slplink_send_queued_slpmsgs(slpcall->slplink); -} - -void -msn_xfer_cancel(PurpleXfer *xfer) -{ - MsnSlpCall *slpcall; - char *content; - - g_return_if_fail(xfer != NULL); - g_return_if_fail(xfer->data != NULL); - - slpcall = xfer->data; - - if (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL) - { - if (slpcall->started) - { - msn_slpcall_close(slpcall); - } - else - { - content = g_strdup_printf("SessionID: %lu\r\n\r\n", - slpcall->session_id); - - msn_slp_send_decline(slpcall, slpcall->branch, "application/x-msnmsgr-sessionreqbody", - content); - - g_free(content); - msn_slplink_send_queued_slpmsgs(slpcall->slplink); - - if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND) - slpcall->wasted = TRUE; - else - msn_slpcall_destroy(slpcall); - } - } -} - -gssize -msn_xfer_write(const guchar *data, gsize len, PurpleXfer *xfer) -{ - MsnSlpCall *slpcall; - - g_return_val_if_fail(xfer != NULL, -1); - g_return_val_if_fail(data != NULL, -1); - g_return_val_if_fail(len > 0, -1); - - g_return_val_if_fail(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND, -1); - - slpcall = xfer->data; - /* Not sure I trust it'll be there */ - g_return_val_if_fail(slpcall != NULL, -1); - - g_return_val_if_fail(slpcall->xfer_msg != NULL, -1); - - slpcall->u.outgoing.len = len; - slpcall->u.outgoing.data = data; - msn_slplink_send_msgpart(slpcall->slplink, slpcall->xfer_msg); - - return MIN(MSN_SBCONN_MAX_SIZE, len); -} - -gssize -msn_xfer_read(guchar **data, PurpleXfer *xfer) -{ - MsnSlpCall *slpcall; - gsize len; - - g_return_val_if_fail(xfer != NULL, -1); - g_return_val_if_fail(data != NULL, -1); - - g_return_val_if_fail(purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE, -1); - - slpcall = xfer->data; - /* Not sure I trust it'll be there */ - g_return_val_if_fail(slpcall != NULL, -1); - - /* Just pass up the whole GByteArray. We'll make another. */ - *data = slpcall->u.incoming_data->data; - len = slpcall->u.incoming_data->len; - - g_byte_array_free(slpcall->u.incoming_data, FALSE); - slpcall->u.incoming_data = g_byte_array_new(); - - return len; -} - -void -msn_xfer_end_cb(MsnSlpCall *slpcall, MsnSession *session) -{ - if ((purple_xfer_get_status(slpcall->xfer) != PURPLE_XFER_STATUS_DONE) && - (purple_xfer_get_status(slpcall->xfer) != PURPLE_XFER_STATUS_CANCEL_REMOTE) && - (purple_xfer_get_status(slpcall->xfer) != PURPLE_XFER_STATUS_CANCEL_LOCAL)) - { - purple_xfer_cancel_remote(slpcall->xfer); - } -} - -void -msn_xfer_completed_cb(MsnSlpCall *slpcall, const guchar *body, - gsize size) -{ - PurpleXfer *xfer = slpcall->xfer; - - purple_xfer_set_completed(xfer, TRUE); - purple_xfer_end(xfer); -} - -gchar * -msn_file_context_to_wire(MsnFileContext *context) -{ - gchar *ret, *tmp; - - tmp = ret = g_new(gchar, MSN_FILE_CONTEXT_SIZE + context->preview_len + 1); - - msn_push32le(tmp, context->length); - msn_push32le(tmp, context->version); - msn_push64le(tmp, context->file_size); - msn_push32le(tmp, context->type); - memcpy(tmp, context->file_name, MAX_FILE_NAME_LEN * 2); - tmp += MAX_FILE_NAME_LEN * 2; - memcpy(tmp, context->unknown1, sizeof(context->unknown1)); - tmp += sizeof(context->unknown1); - msn_push32le(tmp, context->unknown2); - if (context->preview) { - memcpy(tmp, context->preview, context->preview_len); - } - tmp[context->preview_len] = '\0'; - - return ret; -} - -MsnFileContext * -msn_file_context_from_wire(const char *buf, gsize len) -{ - MsnFileContext *context; - - if (!buf || len < MSN_FILE_CONTEXT_SIZE) - return NULL; - - context = g_new(MsnFileContext, 1); - - context->length = msn_pop32le(buf); - context->version = msn_pop32le(buf); - if (context->version == 2) { - /* The length field is broken for this version. No check. */ - context->length = MSN_FILE_CONTEXT_SIZE; - } else if (context->version == 3) { - if (context->length != MSN_FILE_CONTEXT_SIZE + 63) { - g_free(context); - return NULL; - } else if (len < MSN_FILE_CONTEXT_SIZE + 63) { - g_free(context); - return NULL; - } - } else { - purple_debug_warning("msn", "Received MsnFileContext with unknown version: %d\n", context->version); - g_free(context); - return NULL; - } - - context->file_size = msn_pop64le(buf); - context->type = msn_pop32le(buf); - memcpy(context->file_name, buf, MAX_FILE_NAME_LEN * 2); - buf += MAX_FILE_NAME_LEN * 2; - memcpy(context->unknown1, buf, sizeof(context->unknown1)); - buf += sizeof(context->unknown1); - context->unknown2 = msn_pop32le(buf); - - if (context->type == 0 && len > context->length) { - context->preview_len = len - context->length; - context->preview = g_memdup(buf, context->preview_len); - } else { - context->preview_len = 0; - context->preview = NULL; - } - - return context; -} - diff --git a/libpurple/protocols/msn/xfer.h b/libpurple/protocols/msn/xfer.h deleted file mode 100644 index 23e19f37c3..0000000000 --- a/libpurple/protocols/msn/xfer.h +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @file xfer.h MSN File Transfer functions - * - * purple - * - * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef MSN_XFER_H -#define MSN_XFER_H - -#include "slpcall.h" - -#define MAX_FILE_NAME_LEN 260 /* MAX_PATH in Windows */ - -/** - * The context data for a file transfer request - */ -typedef struct -{ - guint32 length; /*< Length of header */ - guint32 version; /*< MSN version */ - guint64 file_size; /*< Size of file */ - guint32 type; /*< Transfer type */ - gunichar2 file_name[MAX_FILE_NAME_LEN]; /*< Self-explanatory */ - gchar unknown1[30]; /*< Used somehow for background sharing */ - guint32 unknown2; /*< Possibly for background sharing as well */ - gchar *preview; /*< File preview data, 96x96 PNG */ - gsize preview_len; -} MsnFileContext; - -#define MSN_FILE_CONTEXT_SIZE (4*4 + 1*8 + 2*MAX_FILE_NAME_LEN + 30) - -void msn_xfer_init(PurpleXfer *xfer); -void msn_xfer_cancel(PurpleXfer *xfer); - -gssize msn_xfer_write(const guchar *data, gsize len, PurpleXfer *xfer); -gssize msn_xfer_read(guchar **data, PurpleXfer *xfer); - -void msn_xfer_completed_cb(MsnSlpCall *slpcall, - const guchar *body, gsize size); -void msn_xfer_end_cb(MsnSlpCall *slpcall, MsnSession *session); - -gchar * -msn_file_context_to_wire(MsnFileContext *context); - -MsnFileContext * -msn_file_context_from_wire(const char *buf, gsize len); - -#endif /* MSN_XFER_H */ - diff --git a/pidgin/win32/nsis/pidgin-installer.nsi b/pidgin/win32/nsis/pidgin-installer.nsi index d09ec0c34d..ee2be32da4 100644 --- a/pidgin/win32/nsis/pidgin-installer.nsi +++ b/pidgin/win32/nsis/pidgin-installer.nsi @@ -564,7 +564,6 @@ Section Uninstall Delete "$INSTDIR\plugins\libgg.dll" Delete "$INSTDIR\plugins\libicq.dll" Delete "$INSTDIR\plugins\libirc.dll" - Delete "$INSTDIR\plugins\libmsn.dll" Delete "$INSTDIR\plugins\libmyspace.dll" Delete "$INSTDIR\plugins\libnapster.dll" Delete "$INSTDIR\plugins\libnovell.dll" diff --git a/po/POTFILES.in b/po/POTFILES.in index 6b4673eb7d..5e93928af2 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -107,21 +107,6 @@ libpurple/protocols/jabber/si.c libpurple/protocols/jabber/usermood.c libpurple/protocols/jabber/usernick.c libpurple/protocols/jabber/xdata.c -libpurple/protocols/msn/contact.c -libpurple/protocols/msn/error.c -libpurple/protocols/msn/group.h -libpurple/protocols/msn/msg.c -libpurple/protocols/msn/msn.c -libpurple/protocols/msn/nexus.c -libpurple/protocols/msn/notification.c -libpurple/protocols/msn/oim.c -libpurple/protocols/msn/servconn.c -libpurple/protocols/msn/session.c -libpurple/protocols/msn/slp.c -libpurple/protocols/msn/slpcall.c -libpurple/protocols/msn/state.c -libpurple/protocols/msn/switchboard.c -libpurple/protocols/msn/userlist.c libpurple/protocols/myspace/myspace.c libpurple/protocols/myspace/user.c libpurple/protocols/myspace/zap.c |