summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Vehse <robertvehse@fastmail.fm>2016-10-04 22:57:40 +0200
committerRobert Vehse <robertvehse@fastmail.fm>2016-10-04 22:57:40 +0200
commit59828aab27107feccf227ae16fd2cd64e40d3403 (patch)
tree91d651b4b0d982a4dc1b642a8730fb02b42c4ca4
parent6f1eed99dfb9cf7b6325da43b8727b4b8a4e32b4 (diff)
downloadpidgin-59828aab27107feccf227ae16fd2cd64e40d3403.tar.gz
Remove the MySpaceIM protocol plugin. The service has been defunct for a long time. References #15356.
-rw-r--r--ChangeLog4
-rw-r--r--configure.ac8
-rw-r--r--libpurple/protocols/Makefile.am2
-rw-r--r--libpurple/protocols/Makefile.mingw2
-rw-r--r--libpurple/protocols/myspace/Makefile.am44
-rw-r--r--libpurple/protocols/myspace/Makefile.mingw81
-rw-r--r--libpurple/protocols/myspace/README27
-rw-r--r--libpurple/protocols/myspace/markup.c763
-rw-r--r--libpurple/protocols/myspace/markup.h27
-rw-r--r--libpurple/protocols/myspace/message.c1413
-rw-r--r--libpurple/protocols/myspace/message.h109
-rw-r--r--libpurple/protocols/myspace/myspace.c3667
-rw-r--r--libpurple/protocols/myspace/myspace.h203
-rw-r--r--libpurple/protocols/myspace/persist.h92
-rw-r--r--libpurple/protocols/myspace/session.c98
-rw-r--r--libpurple/protocols/myspace/session.h60
-rw-r--r--libpurple/protocols/myspace/user.c892
-rw-r--r--libpurple/protocols/myspace/user.h60
-rw-r--r--libpurple/protocols/myspace/zap.c245
-rw-r--r--libpurple/protocols/myspace/zap.h28
-rw-r--r--libpurple/prpl.h2
-rwxr-xr-xlibpurple/purple-url-handler7
-rw-r--r--libpurple/server.h2
-rw-r--r--pidgin/pixmaps/Makefile.am3
-rw-r--r--pidgin/pixmaps/emotes/default/24/default.theme.in33
-rw-r--r--pidgin/pixmaps/emotes/small/16/small.theme.in17
-rw-r--r--pidgin/pixmaps/protocols/16/myspace.pngbin745 -> 0 bytes
-rw-r--r--pidgin/pixmaps/protocols/22/myspace.pngbin1103 -> 0 bytes
-rw-r--r--pidgin/pixmaps/protocols/48/myspace.pngbin2112 -> 0 bytes
-rw-r--r--pidgin/plugins/disco/xmppdisco.c1
-rw-r--r--pidgin/win32/nsis/pidgin-installer.nsi1
-rw-r--r--po/POTFILES.in3
32 files changed, 10 insertions, 7884 deletions
diff --git a/ChangeLog b/ChangeLog
index 6e5717de1d..009a2e6c6b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
+version 2.12.0 (06/21/16):
+ General:
+ * Remove the MySpaceIM protocol plugin. The service has been defunct for a long time. (#15356)
+
version 2.11.0 (06/21/16):
General:
* 2.10.12 was accidentally released with new additions to the API and
diff --git a/configure.ac b/configure.ac
index 528ac55ca5..d97920224f 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 myspace novell oscar sametime silc simple yahoo zephyr"
+ STATIC_PRPLS="bonjour gg irc jabber 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 ;;
- myspace) static_myspace=yes ;;
novell) static_novell=yes ;;
oscar) static_oscar=yes ;;
aim) static_oscar=yes ;;
@@ -1256,7 +1255,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_MYSPACE, test "x$static_myspace" = "xyes")
AM_CONDITIONAL(STATIC_NOVELL, test "x$static_novell" = "xyes")
AM_CONDITIONAL(STATIC_OSCAR, test "x$static_oscar" = "xyes")
AM_CONDITIONAL(STATIC_SAMETIME, test "x$static_sametime" = "xyes" -a "x$have_meanwhile" = "xyes")
@@ -1270,7 +1268,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 myspace novell oscar sametime silc simple yahoo zephyr"
+ DYNAMIC_PRPLS="bonjour gg irc jabber novell oscar sametime silc simple yahoo zephyr"
fi
if test "x$have_meanwhile" != "xyes"; then
DYNAMIC_PRPLS=`echo $DYNAMIC_PRPLS | $sedpath 's/sametime//'`
@@ -1291,7 +1289,6 @@ for i in $DYNAMIC_PRPLS ; do
gg) dynamic_gg=yes ;;
irc) dynamic_irc=yes ;;
jabber) dynamic_jabber=yes ;;
- myspace) dynamic_myspace=yes ;;
novell) dynamic_novell=yes ;;
null) dynamic_null=yes ;;
oscar) dynamic_oscar=yes ;;
@@ -2656,7 +2653,6 @@ AC_CONFIG_FILES([Makefile
libpurple/protocols/gg/Makefile
libpurple/protocols/irc/Makefile
libpurple/protocols/jabber/Makefile
- libpurple/protocols/myspace/Makefile
libpurple/protocols/novell/Makefile
libpurple/protocols/null/Makefile
libpurple/protocols/oscar/Makefile
diff --git a/libpurple/protocols/Makefile.am b/libpurple/protocols/Makefile.am
index 675ee5818f..db1a8b4fa7 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 myspace novell null oscar sametime silc silc10 simple yahoo zephyr
+DIST_SUBDIRS = bonjour gg irc jabber 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 36000fc18b..323ea9ae9f 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 novell null oscar sametime silc simple yahoo bonjour myspace
+SUBDIRS = gg irc jabber novell null oscar sametime silc simple yahoo bonjour
.PHONY: all install clean
diff --git a/libpurple/protocols/myspace/Makefile.am b/libpurple/protocols/myspace/Makefile.am
deleted file mode 100644
index 715cabc875..0000000000
--- a/libpurple/protocols/myspace/Makefile.am
+++ /dev/null
@@ -1,44 +0,0 @@
-EXTRA_DIST = \
- Makefile.mingw
-
-pkgdir = $(libdir)/purple-$(PURPLE_MAJOR_VERSION)
-
-MSIMSOURCES = markup.c \
- markup.h \
- message.c \
- message.h \
- myspace.c \
- myspace.h \
- persist.h \
- session.c \
- session.h \
- user.c \
- user.h \
- zap.c \
- zap.h
-
-AM_CFLAGS = $(st)
-
-libmyspace_la_LDFLAGS = -module -avoid-version
-
-if STATIC_MYSPACE
-
-st = -DPURPLE_STATIC_PRPL
-noinst_LTLIBRARIES = libmyspace.la
-libmyspace_la_SOURCES = $(MSIMSOURCES)
-libmyspace_la_CFLAGS = $(AM_CFLAGS)
-
-else
-
-st =
-pkg_LTLIBRARIES = libmyspace.la
-libmyspace_la_SOURCES = $(MSIMSOURCES)
-libmyspace_la_LIBADD = $(GLIB_LIBS)
-
-endif
-
-AM_CPPFLAGS = \
- -I$(top_srcdir)/libpurple \
- -I$(top_builddir)/libpurple \
- $(GLIB_CFLAGS) \
- $(DEBUG_CFLAGS)
diff --git a/libpurple/protocols/myspace/Makefile.mingw b/libpurple/protocols/myspace/Makefile.mingw
deleted file mode 100644
index 0fc7534760..0000000000
--- a/libpurple/protocols/myspace/Makefile.mingw
+++ /dev/null
@@ -1,81 +0,0 @@
-#
-# Makefile.mingw
-#
-# Description: Makefile for win32 (mingw) version of libmyspace
-#
-
-PIDGIN_TREE_TOP := ../../..
-include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
-
-TARGET = libmyspace
-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 = myspace.c message.c zap.c session.c markup.c user.c
-
-OBJECTS = $(C_SRC:%.c=%.o)
-
-##
-## LIBRARIES
-##
-LIBS = \
- -lglib-2.0 \
- -lws2_32 \
- -lintl \
- -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)
-
-##
-## BUILD DLL
-##
-$(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/myspace/README b/libpurple/protocols/myspace/README
deleted file mode 100644
index f9f062c9e6..0000000000
--- a/libpurple/protocols/myspace/README
+++ /dev/null
@@ -1,27 +0,0 @@
-MySpaceIM Protocol Plugin for libpurple by Jeff Connelly 2007-08-07
-
-Greetings. This package contains a plugin for libpurple (as used in
-Pidgin, formerly Gaim) to connect to the new MySpaceIM instant messaging
-network and send/receive messages. Functionality is only basic as of yet,
-and this code should be considered alpha quality.
-
-This code was initially developed under Google Summer of Code 2007.
-
-For features and TODO, see http://developer.pidgin.im/wiki/MySpaceIM
-
-Usage:
-
-Login using your _email address_ you use to login to myspace.com. You can't
-login using your numeric ID or alias.
-
-To test it out, send a message to yourself (by your username or numeric
-uid (email not yet supported)) or tom (6221). In either case you should
-get a reply. You should also be able to talk to other MySpaceIM users if
-you desire. Replies will always be shown as coming from a user's username,
-even if you IM by email or userid.
-
-Feedback welcome. You can IM my test account at "msimprpl" if you feel like it.
-
-Enjoy,
--Jeff Connelly
-msimprpl@xyzzy.cjb.net
diff --git a/libpurple/protocols/myspace/markup.c b/libpurple/protocols/myspace/markup.c
deleted file mode 100644
index 05d473e130..0000000000
--- a/libpurple/protocols/myspace/markup.c
+++ /dev/null
@@ -1,763 +0,0 @@
-/* MySpaceIM Protocol Plugin - markup
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * 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 "myspace.h"
-
-typedef int (*MSIM_XMLNODE_CONVERT)(MsimSession *, xmlnode *, gchar **, gchar **);
-
-/* Globals */
-
-/* The names in in emoticon_names (for <i n=whatever>) map to corresponding
- * entries in emoticon_symbols (for the ASCII representation of the emoticon).
- *
- * Multiple emoticon symbols in Pidgin can map to one name. List the
- * canonical form, as inserted by the "Smile!" dialog, first. For example,
- * :) comes before :-), because although both are recognized as 'happy',
- * the first is inserted by the smiley button (first symbol in theme).
- *
- * Note that symbols are case-sensitive in Pidgin -- :-X is not :-x. */
-static struct MSIM_EMOTICON
-{
- gchar *name;
- gchar *symbol;
-} msim_emoticons[] = {
- /* Unfortunately, this list duplicates much of the file
- * pidgin/pidgin/pixmaps/emotes/default/22/default.theme.in, because
- * that file is part of Pidgin, but we're part of libpurple.
- */
- { "bigsmile", ":D" },
- { "bigsmile", ":-D" },
- { "devil", "}:)" },
- { "frazzled", ":Z" },
- { "geek", "B)" },
- { "googles", "%)" },
- { "growl", ":E" },
- { "laugh", ":))" }, /* Must be before ':)' */
- { "happy", ":)" },
- { "happy", ":-)" },
- { "happi", ":)" },
- { "heart", ":X" },
- { "mohawk", "-:" },
- { "mad", "X(" },
- { "messed", "X)" },
- { "nerd", "Q)" },
- { "oops", ":G" },
- { "pirate", "P)" },
- { "scared", ":O" },
- { "sidefrown", ":{" },
- { "sinister", ":B" },
- { "smirk", ":," },
- { "straight", ":|" },
- { "tongue", ":P" },
- { "tongue", ":p" },
- { "tongy", ":P" },
- { "upset", "B|" },
- { "wink", ";-)" },
- { "wink", ";)" },
- { "winc", ";)" },
- { "worried", ":[" },
- { "kiss", ":x" },
- { NULL, NULL }
-};
-
-/* Indexes of this array + 1 map HTML font size to scale of normal font size. *
- * Based on _point_sizes from libpurple/gtkimhtml.c
- * 1 2 3 4 5 6 7 */
-static gdouble _font_scale[] = { .85, .95, 1, 1.2, 1.44, 1.728, 2.0736 };
-
-/* Purple maximum font size. Equivalent to sizeof(_font_scale) / sizeof(_font_scale[0]) */
-#define MAX_FONT_SIZE 7
-
-#define POINTS_PER_INCH 72 /* How many pt's in an inch */
-
-/* Text formatting bits for <f s=#> */
-#define MSIM_TEXT_BOLD 1
-#define MSIM_TEXT_ITALIC 2
-#define MSIM_TEXT_UNDERLINE 4
-
-/* Default baseline size of purple's fonts, in points. What is size 3 in points.
- * _font_scale specifies scaling factor relative to this point size. Note this
- * is only the default; it is configurable in account options. */
-#define MSIM_BASE_FONT_POINT_SIZE 8
-
-/* Default display's DPI. 96 is common but it can differ. Also configurable
- * in account options. */
-#define MSIM_DEFAULT_DPI 96
-
-/* round is part of C99, but sometimes is unavailable before then.
- * Based on http://forums.belution.com/en/cpp/000/050/13.shtml
- */
-static double msim_round(double value)
-{
- if (value < 0) {
- return -(floor(-value + 0.5));
- } else {
- return floor( value + 0.5);
- }
-}
-
-/**
- * Convert typographical font point size to HTML font size.
- * Based on libpurple/gtkimhtml.c
- */
-static guint
-msim_point_to_purple_size(MsimSession *session, guint point)
-{
- guint size, this_point, base;
-
- base = purple_account_get_int(session->account, "base_font_size", MSIM_BASE_FONT_POINT_SIZE);
-
- for (size = 0; size < MAX_FONT_SIZE; ++size) {
- this_point = (guint)msim_round(base * _font_scale[size]);
-
- if (this_point >= point) {
- purple_debug_info("msim", "msim_point_to_purple_size: %d pt -> size=%d\n",
- point, size);
- return size;
- }
- }
-
- /* No HTML font size was this big; return largest possible. */
- return this_point;
-}
-
-/**
- * Convert HTML font size to point size.
- */
-static guint
-msim_purple_size_to_point(MsimSession *session, guint size)
-{
- gdouble scale;
- guint point;
- guint base;
-
- scale = _font_scale[CLAMP(size, 1, MAX_FONT_SIZE) - 1];
-
- base = purple_account_get_int(session->account, "base_font_size", MSIM_BASE_FONT_POINT_SIZE);
-
- point = (guint)msim_round(scale * base);
-
- purple_debug_info("msim", "msim_purple_size_to_point: size=%d -> %d pt\n",
- size, point);
-
- return point;
-}
-
-/**
- * Convert a msim markup font pixel height to the more usual point size, for incoming messages.
- */
-static guint
-msim_height_to_point(MsimSession *session, guint height)
-{
- guint dpi;
-
- dpi = purple_account_get_int(session->account, "dpi", MSIM_DEFAULT_DPI);
-
- return (guint)msim_round((POINTS_PER_INCH * 1. / dpi) * height);
-
- /* See also: libpurple/protocols/bonjour/jabber.c
- * _font_size_ichat_to_purple */
-}
-
-/**
- * Convert point size to msim pixel height font size specification, for outgoing messages.
- */
-static guint
-msim_point_to_height(MsimSession *session, guint point)
-{
- guint dpi;
-
- dpi = purple_account_get_int(session->account, "dpi", MSIM_DEFAULT_DPI);
-
- return (guint)msim_round((dpi * 1. / POINTS_PER_INCH) * point);
-}
-
-/**
- * Convert the msim markup <f> (font) tag into HTML.
- */
-static void
-msim_markup_f_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
-{
- const gchar *face, *height_str, *decor_str;
- GString *gs_end, *gs_begin;
- guint decor, height;
-
- face = xmlnode_get_attrib(root, "f");
- height_str = xmlnode_get_attrib(root, "h");
- decor_str = xmlnode_get_attrib(root, "s");
-
- /* Validate the font face, to avoid constructing invalid HTML later */
- if (face != NULL && strchr(face, '\'') != NULL)
- face = NULL;
-
- height = height_str != NULL ? atol(height_str) : 12;
- decor = decor_str != NULL ? atol(decor_str) : 0;
-
- /*
- * The HTML we're constructing here is a bit redudant. Ideally we
- * would use only the font-family and font-size CSS span, but Pidgin
- * doesn't support it (it's included for other UIs). For Pidgin we
- * wrap the whole thing in an ugly font tag, and Pidgin will happily
- * ignore the <span>.
- */
- gs_begin = g_string_new("");
- if (height && !face) {
- guint point_size = msim_height_to_point(session, height);
- g_string_printf(gs_begin,
- "<font size='%d'><span style='font-size: %dpt'>",
- msim_point_to_purple_size(session, point_size),
- point_size);
- } else if (height && face) {
- guint point_size = msim_height_to_point(session, height);
- g_string_printf(gs_begin,
- "<font face='%s' size='%d'><span style='font-family: %s; font-size: %dpt'>",
- face, msim_point_to_purple_size(session, point_size),
- face, point_size);
- } else {
- g_string_printf(gs_begin, "<font><span>");
- }
-
- gs_end = g_string_new("</span></font>");
-
- if (decor & MSIM_TEXT_BOLD) {
- g_string_append(gs_begin, "<b>");
- g_string_prepend(gs_end, "</b>");
- }
-
- if (decor & MSIM_TEXT_ITALIC) {
- g_string_append(gs_begin, "<i>");
- g_string_append(gs_end, "</i>");
- }
-
- if (decor & MSIM_TEXT_UNDERLINE) {
- g_string_append(gs_begin, "<u>");
- g_string_append(gs_end, "</u>");
- }
-
- *begin = g_string_free(gs_begin, FALSE);
- *end = g_string_free(gs_end, FALSE);
-}
-
-/**
- * Convert a msim markup color to a color suitable for libpurple.
- *
- * @param msim Either a color name, or an rgb(x,y,z) code.
- *
- * @return A new string, either a color name or #rrggbb code. Must g_free().
- */
-static char *
-msim_color_to_purple(const char *msim)
-{
- guint red, green, blue;
-
- if (!msim) {
- return g_strdup("black");
- }
-
- if (sscanf(msim, "rgb(%d,%d,%d)", &red, &green, &blue) != 3) {
- /* Color name. */
- return g_strdup(msim);
- }
- /* TODO: rgba (alpha). */
-
- return g_strdup_printf("#%.2x%.2x%.2x", red, green, blue);
-}
-
-/**
- * Convert the msim markup <a> (anchor) tag into HTML.
- */
-static void
-msim_markup_a_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
-{
- const gchar *href;
-
- href = xmlnode_get_attrib(root, "h");
- if (!href) {
- href = "";
- }
-
- *begin = g_strdup_printf("<a href=\"%s\">%s", href, href);
- *end = g_strdup("</a>");
-}
-
-/**
- * Convert the msim markup <p> (paragraph) tag into HTML.
- */
-static void
-msim_markup_p_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
-{
- /* Just pass through unchanged.
- *
- * Note: attributes currently aren't passed, if there are any. */
- *begin = g_strdup("<p>");
- *end = g_strdup("</p>");
-}
-
-/**
- * Convert the msim markup <c> tag (text color) into HTML.
- */
-static void
-msim_markup_c_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
-{
- const gchar *color;
- gchar *purple_color;
-
- color = xmlnode_get_attrib(root, "v");
- if (!color) {
- purple_debug_info("msim", "msim_markup_c_to_html: <c> tag w/o v attr\n");
- *begin = g_strdup("");
- *end = g_strdup("");
- /* TODO: log as unrecognized */
- return;
- }
-
- purple_color = msim_color_to_purple(color);
-
-#ifdef USE_CSS_FORMATTING
- *begin = g_strdup_printf("<span style='color: %s'>", purple_color);
- *end = g_strdup("</span>");
-#else
- *begin = g_strdup_printf("<font color='%s'>", purple_color);
- *end = g_strdup("</font>");
-#endif
-
- g_free(purple_color);
-}
-
-/**
- * Convert the msim markup <b> tag (background color) into HTML.
- */
-static void
-msim_markup_b_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
-{
- const gchar *color;
- gchar *purple_color;
-
- color = xmlnode_get_attrib(root, "v");
- if (!color) {
- *begin = g_strdup("");
- *end = g_strdup("");
- purple_debug_info("msim", "msim_markup_b_to_html: <b> w/o v attr\n");
- /* TODO: log as unrecognized. */
- return;
- }
-
- purple_color = msim_color_to_purple(color);
-
-#ifdef USE_CSS_FORMATTING
- *begin = g_strdup_printf("<span style='background-color: %s'>", purple_color);
- *end = g_strdup("</span>");
-#else
- *begin = g_strdup_printf("<body bgcolor='%s'>", purple_color);
- *end = g_strdup("</body>");
-#endif
-
- g_free(purple_color);
-}
-
-/**
- * Convert the msim markup <i> tag (emoticon image) into HTML.
- */
-static void
-msim_markup_i_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
-{
- const gchar *name;
- guint i;
- struct MSIM_EMOTICON *emote;
-
- name = xmlnode_get_attrib(root, "n");
- if (!name) {
- purple_debug_info("msim", "msim_markup_i_to_html: <i> w/o n\n");
- *begin = g_strdup("");
- *end = g_strdup("");
- /* TODO: log as unrecognized */
- return;
- }
-
- /* Find and use canonical form of smiley symbol. */
- for (i = 0; (emote = &msim_emoticons[i]) && emote->name != NULL; ++i) {
- if (g_str_equal(name, emote->name)) {
- *begin = g_strdup(emote->symbol);
- *end = g_strdup("");
- return;
- }
- }
-
- /* Couldn't find it, sorry. Try to degrade gracefully. */
- *begin = g_strdup_printf("**%s**", name);
- *end = g_strdup("");
-}
-
-/**
- * Convert an individual msim markup tag to HTML.
- */
-static int
-msim_markup_tag_to_html(MsimSession *session, xmlnode *root, gchar **begin,
- gchar **end)
-{
- g_return_val_if_fail(root != NULL, 0);
-
- if (g_str_equal(root->name, "f")) {
- msim_markup_f_to_html(session, root, begin, end);
- } else if (g_str_equal(root->name, "a")) {
- msim_markup_a_to_html(session, root, begin, end);
- } else if (g_str_equal(root->name, "p")) {
- msim_markup_p_to_html(session, root, begin, end);
- } else if (g_str_equal(root->name, "c")) {
- msim_markup_c_to_html(session, root, begin, end);
- } else if (g_str_equal(root->name, "b")) {
- msim_markup_b_to_html(session, root, begin, end);
- } else if (g_str_equal(root->name, "i")) {
- msim_markup_i_to_html(session, root, begin, end);
- } else {
- purple_debug_info("msim", "msim_markup_tag_to_html: "
- "unknown tag name=%s, ignoring\n",
- root->name ? root->name : "(NULL)");
- *begin = g_strdup("");
- *end = g_strdup("");
- }
- return 0;
-}
-
-/**
- * Convert an individual HTML tag to msim markup.
- */
-static int
-html_tag_to_msim_markup(MsimSession *session, xmlnode *root, gchar **begin,
- gchar **end)
-{
- int ret = 0;
-
- if (!purple_utf8_strcasecmp(root->name, "root") ||
- !purple_utf8_strcasecmp(root->name, "html")) {
- *begin = g_strdup("");
- *end = g_strdup("");
- /* TODO: Coalesce nested tags into one <f> tag!
- * Currently, the 's' value will be overwritten when b/i/u is nested
- * within another one, and only the inner-most formatting will be
- * applied to the text. */
- } else if (!purple_utf8_strcasecmp(root->name, "b")) {
- if (root->child->type == XMLNODE_TYPE_DATA) {
- *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_BOLD);
- *end = g_strdup("</f>");
- } else {
- if (!purple_utf8_strcasecmp(root->child->name,"i")) {
- ret++;
- if (root->child->child->type == XMLNODE_TYPE_DATA) {
- *begin = g_strdup_printf("<f s='%d'>", (MSIM_TEXT_BOLD + MSIM_TEXT_ITALIC));
- *end = g_strdup("</f>");
- } else {
- if (!purple_utf8_strcasecmp(root->child->child->name,"u")) {
- ret++;
- *begin = g_strdup_printf("<f s='%d'>", (MSIM_TEXT_BOLD + MSIM_TEXT_ITALIC + MSIM_TEXT_UNDERLINE));
- *end = g_strdup("</f>");
- }
- }
- } else if (!purple_utf8_strcasecmp(root->child->name,"u")) {
- ret++;
- *begin = g_strdup_printf("<f s='%d'>", (MSIM_TEXT_BOLD + MSIM_TEXT_UNDERLINE));
- *end = g_strdup("</f>");
- }
- }
- } else if (!purple_utf8_strcasecmp(root->name, "i")) {
- if (root->child->type == XMLNODE_TYPE_DATA) {
- *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_ITALIC);
- *end = g_strdup("</f>");
- } else {
- if (!purple_utf8_strcasecmp(root->child->name,"u")) {
- ret++;
- *begin = g_strdup_printf("<f s='%d'>", (MSIM_TEXT_ITALIC + MSIM_TEXT_UNDERLINE));
- *end = g_strdup("</f>");
- }
- }
- } else if (!purple_utf8_strcasecmp(root->name, "u")) {
- *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_UNDERLINE);
- *end = g_strdup("</f>");
- } else if (!purple_utf8_strcasecmp(root->name, "a")) {
- const gchar *href;
- gchar *link_text;
-
- href = xmlnode_get_attrib(root, "href");
-
- if (!href) {
- href = xmlnode_get_attrib(root, "HREF");
- }
-
- link_text = xmlnode_get_data(root);
-
- if (href) {
- if (g_str_equal(link_text, href)) {
- /* Purple gives us: <a href="URL">URL</a>
- * Translate to <a h='URL' />
- * Displayed as text of URL with link to URL
- */
- *begin = g_strdup_printf("<a h='%s' />", href);
- } else {
- /* But if we get: <a href="URL">text</a>
- * Translate to: text: <a h='URL' />
- *
- * Because official client only supports self-closed <a>
- * tags; you can't change the link text.
- */
- *begin = g_strdup_printf("%s: <a h='%s' />", link_text, href);
- }
- } else {
- *begin = g_strdup("<a />");
- }
-
- /* Sorry, kid. MySpace doesn't support you within <a> tags. */
- xmlnode_free(root->child);
- g_free(link_text);
- root->child = NULL;
-
- *end = g_strdup("");
- } else if (!purple_utf8_strcasecmp(root->name, "font")) {
- GString *tmpbegin, *tmpend;
- const gchar *size;
- const gchar *face;
- const gchar *color;
-
- size = xmlnode_get_attrib(root, "size");
- face = xmlnode_get_attrib(root, "face");
- color = xmlnode_get_attrib(root, "color");
-
- tmpbegin = g_string_new("<f");
- tmpend = g_string_new("</f>");
-
- if (face != NULL)
- g_string_append_printf(tmpbegin, " f='%s'", face);
-
- if (size != NULL)
- g_string_append_printf(tmpbegin, " h='%d'",
- msim_point_to_height(session,
- msim_purple_size_to_point(session, atoi(size))));
-
- /* Close the <f> tag */
- g_string_append(tmpbegin, ">");
-
- if (color != NULL) {
- g_string_append_printf(tmpbegin, "<c v='%s'>", color);
- g_string_prepend(tmpend, "</c>");
- }
-
- *begin = g_string_free(tmpbegin, FALSE);
- *end = g_string_free(tmpend, FALSE);
-
- } else if (!purple_utf8_strcasecmp(root->name, "body")) {
- const gchar *bgcolor;
-
- bgcolor = xmlnode_get_attrib(root, "bgcolor");
-
- if (bgcolor != NULL) {
- *begin = g_strdup_printf("<b v='%s'>", bgcolor);
- *end = g_strdup("</b>");
- }
-
- } else {
- gchar *err;
-
-#ifdef MSIM_MARKUP_SHOW_UNKNOWN_TAGS
- *begin = g_strdup_printf("[%s]", root->name);
- *end = g_strdup_printf("[/%s]", root->name);
-#else
- *begin = g_strdup("");
- *end = g_strdup("");
-#endif
-
- err = g_strdup_printf("html_tag_to_msim_markup: unrecognized "
- "HTML tag %s was sent by the IM client; ignoring",
- root->name ? root->name : "(NULL)");
- msim_unrecognized(NULL, NULL, err);
- g_free(err);
- }
- return ret;
-}
-
-/**
- * Convert an xmlnode of msim markup or HTML to an HTML string or msim markup.
- *
- * @param f Function to convert tags.
- *
- * @return An HTML string. Caller frees.
- */
-static void
-msim_convert_xmlnode(MsimSession *session, GString *out, xmlnode *root, MSIM_XMLNODE_CONVERT f, int nodes_processed)
-{
- xmlnode *node;
- gchar *begin, *end, *tmp;
- int descended = nodes_processed;
-
- if (!root || !root->name)
- return;
-
- purple_debug_info("msim", "msim_convert_xmlnode: got root=%s\n",
- root->name);
-
- begin = end = NULL;
-
- if (descended == 0) /* We've not formatted this yet.. :) */
- descended = f(session, root, &begin, &end); /* Get the value that our format function has already descended for us */
-
- g_string_append(out, begin);
- g_free(begin);
-
- /* Loop over all child nodes. */
- for (node = root->child; node != NULL; node = node->next) {
- switch (node->type) {
- case XMLNODE_TYPE_ATTRIB:
- /* Attributes handled above. */
- break;
-
- case XMLNODE_TYPE_TAG:
- /* A tag or tag with attributes. Recursively descend. */
- msim_convert_xmlnode(session, out, node, f, descended);
-
- purple_debug_info("msim", " ** node name=%s\n",
- node->name ? node->name : "(NULL)");
- break;
-
- case XMLNODE_TYPE_DATA:
- /* Literal text. */
- /*
- * TODO: Why is it necessary to escape here? I thought
- * node->data was already escaped?
- */
- tmp = g_markup_escape_text(node->data, node->data_sz);
- g_string_append(out, tmp);
- g_free(tmp);
- break;
-
- default:
- purple_debug_warning("msim",
- "msim_convert_xmlnode: unknown node type\n");
- }
- }
-
- /* TODO: Note that msim counts each piece of text enclosed by <f> as
- * a paragraph and will display each on its own line. You actually have
- * to _nest_ <f> tags to intersperse different text in one paragraph!
- * Comment out this line below to see. */
- g_string_append(out, end);
- g_free(end);
-}
-
-/**
- * Convert XML to something based on MSIM_XMLNODE_CONVERT.
- */
-static gchar *
-msim_convert_xml(MsimSession *session, const gchar *raw, MSIM_XMLNODE_CONVERT f)
-{
- xmlnode *root;
- GString *str;
- gchar *enclosed_raw;
-
- g_return_val_if_fail(raw != NULL, NULL);
-
- /* Enclose text in one root tag, to try to make it valid XML for parsing. */
- enclosed_raw = g_strconcat("<root>", raw, "</root>", NULL);
-
- root = xmlnode_from_str(enclosed_raw, -1);
-
- if (!root) {
- purple_debug_warning("msim", "msim_markup_to_html: couldn't parse "
- "%s as XML, returning raw: %s\n", enclosed_raw, raw);
- /* TODO: msim_unrecognized */
- g_free(enclosed_raw);
- return g_strdup(raw);
- }
-
- g_free(enclosed_raw);
-
- str = g_string_new(NULL);
- msim_convert_xmlnode(session, str, root, f, 0);
- xmlnode_free(root);
-
- purple_debug_info("msim", "msim_markup_to_html: returning %s\n", str->str);
-
- return g_string_free(str, FALSE);
-}
-
-/**
- * Convert plaintext smileys to <i> markup tags.
- *
- * @param before Original text with ASCII smileys. Will be freed.
- * @return A new string with <i> tags, if applicable. Must be g_free()'d.
- */
-static gchar *
-msim_convert_smileys_to_markup(gchar *before)
-{
- gchar *old, *new, *replacement;
- guint i;
- struct MSIM_EMOTICON *emote;
-
- old = before;
- new = NULL;
-
- for (i = 0; (emote = &msim_emoticons[i]) && emote->name != NULL; ++i) {
- gchar *name, *symbol;
-
- name = emote->name;
- symbol = emote->symbol;
-
- replacement = g_strdup_printf("<i n=\"%s\"/>", name);
-
- purple_debug_info("msim", "msim_convert_smileys_to_markup: %s->%s\n",
- symbol ? symbol : "(NULL)",
- replacement ? replacement : "(NULL)");
- new = purple_strreplace(old, symbol, replacement);
-
- g_free(replacement);
- g_free(old);
-
- old = new;
- }
-
- return new;
-}
-
-/**
- * High-level function to convert MySpaceIM markup to Purple (HTML) markup.
- *
- * @return Purple markup string, must be g_free()'d. */
-gchar *
-msim_markup_to_html(MsimSession *session, const gchar *raw)
-{
- return msim_convert_xml(session, raw, msim_markup_tag_to_html);
-}
-
-/**
- * High-level function to convert Purple (HTML) to MySpaceIM markup.
- *
- * TODO: consider using purple_markup_html_to_xhtml() to make valid XML.
- *
- * @return HTML markup string, must be g_free()'d. */
-gchar *
-html_to_msim_markup(MsimSession *session, const gchar *raw)
-{
- gchar *markup;
-
- markup = msim_convert_xml(session, raw, html_tag_to_msim_markup);
-
- if (purple_account_get_bool(session->account, "emoticons", TRUE)) {
- /* Frees markup and allocates a new one. */
- markup = msim_convert_smileys_to_markup(markup);
- }
-
- return markup;
-}
diff --git a/libpurple/protocols/myspace/markup.h b/libpurple/protocols/myspace/markup.h
deleted file mode 100644
index dfbbebad1b..0000000000
--- a/libpurple/protocols/myspace/markup.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* MySpaceIM Protocol Plugin - markup
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * 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 _MYSPACE_MARKUP_H
-#define _MYSPACE_MARKUP_H
-
-/* High-level msim markup <=> Purple html conversion functions. */
-gchar *msim_markup_to_html(MsimSession *, const gchar *raw);
-gchar *html_to_msim_markup(MsimSession *, const gchar *raw);
-
-#endif /* !_MYSPACE_MARKUP_H */
diff --git a/libpurple/protocols/myspace/message.c b/libpurple/protocols/myspace/message.c
deleted file mode 100644
index 9eb44b3ade..0000000000
--- a/libpurple/protocols/myspace/message.c
+++ /dev/null
@@ -1,1413 +0,0 @@
-/** MySpaceIM protocol messages
- *
- * \author Jeff Connelly
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * 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 "myspace.h"
-#include "message.h"
-
-static void msim_msg_debug_string_element(gpointer data, gpointer user_data);
-
-/**
- * Escape codes and associated replacement text, used for protocol message
- * escaping and unescaping.
- */
-static struct MSIM_ESCAPE_REPLACEMENT {
- gchar *code;
- gchar text;
-} msim_escape_replacements[] = {
- { "/1", '/' },
- { "/2", '\\' },
- /* { "/3", "|" }, */ /* Not used here -- only for within arrays */
- { NULL, 0 }
-};
-
-/**
- * Escape a protocol message.
- *
- * @return The escaped message. Caller must g_free().
- */
-gchar *
-msim_escape(const gchar *msg)
-{
- GString *gs;
- guint i, j;
- guint msg_len;
-
- gs = g_string_new("");
- msg_len = strlen(msg);
-
- for (i = 0; i < msg_len; ++i) {
- struct MSIM_ESCAPE_REPLACEMENT *replacement;
- gchar *replace;
-
- replace = NULL;
-
- /* Check for characters that need to be escaped, and escape them. */
- for (j = 0; (replacement = &msim_escape_replacements[j]) &&
- replacement->code != NULL; ++j) {
- if (msg[i] == replacement->text) {
- replace = replacement->code;
- break;
- }
- }
-
- if (replace) {
- g_string_append(gs, replace);
- } else {
- g_string_append_c(gs, msg[i]);
- }
- }
-
-#ifdef MSIM_DEBUG_ESCAPE
- purple_debug_info("msim", "msim_escape: msg=%s, ret=%s\n", msg, gs->str);
-#endif
-
- return g_string_free(gs, FALSE);
-}
-
-/**
- * Unescape a protocol message.
- *
- * @return The unescaped message, caller must g_free().
- */
-gchar *
-msim_unescape(const gchar *msg)
-{
- GString *gs;
- guint i, j;
- guint msg_len;
-
- gs = g_string_new("");
- msg_len = strlen(msg);
-
- for (i = 0; i < msg_len; ++i) {
- struct MSIM_ESCAPE_REPLACEMENT *replacement;
- gchar replace;
-
- replace = msg[i];
-
- for (j = 0; (replacement = &msim_escape_replacements[j]) &&
- replacement->code != NULL; ++j) {
- if (msg[i] == replacement->code[0] &&
- i + 1 < msg_len &&
- msg[i + 1] == replacement->code[1]) {
- replace = replacement->text;
- ++i;
- break;
- }
- }
-
- g_string_append_c(gs, replace);
- }
-
-#ifdef MSIM_DEBUG_ESCAPE
- purple_debug_info("msim", "msim_unescape: msg=%s, ret=%s\n", msg, gs->str);
-#endif
-
- return g_string_free(gs, FALSE);
-}
-
-/**
- * Create a new message from va_list and its first argument.
- *
- * @param first_key The first argument (a key), or NULL to take all arguments
- * from argp.
- * @param argp A va_list of variadic arguments, already started with va_start().
- * @return New MsimMessage *, must be freed with msim_msg_free().
- *
- * For internal use - users probably want msim_msg_new() or msim_send().
- */
-static MsimMessage *
-msim_msg_new_v(gchar *first_key, va_list argp)
-{
- gchar *key, *value;
- MsimMessageType type;
- MsimMessage *msg;
- gboolean first;
-
- GString *gs;
- GList *gl;
- MsimMessage *dict;
-
- /* Begin with an empty message. */
- msg = NULL;
-
- /* First parameter can be given explicitly. */
- first = first_key != NULL;
-
- /* Read key, type, value triplets until NULL. */
- do {
- if (first) {
- key = first_key;
- first = FALSE;
- } else {
- key = va_arg(argp, gchar *);
- if (!key) {
- break;
- }
- }
-
- type = va_arg(argp, int);
-
- /* Interpret variadic arguments. */
- switch (type) {
- case MSIM_TYPE_INTEGER:
- case MSIM_TYPE_BOOLEAN:
- msg = msim_msg_append(msg, key, type, GUINT_TO_POINTER(va_arg(argp, int)));
- break;
-
- case MSIM_TYPE_STRING:
- value = va_arg(argp, char *);
-
- g_return_val_if_fail(value != NULL, FALSE);
-
- msg = msim_msg_append(msg, key, type, value);
- break;
-
- case MSIM_TYPE_BINARY:
- gs = va_arg(argp, GString *);
-
- g_return_val_if_fail(gs != NULL, FALSE);
-
- /* msim_msg_free() will free this GString the caller created. */
- msg = msim_msg_append(msg, key, type, gs);
- break;
-
- case MSIM_TYPE_LIST:
- gl = va_arg(argp, GList *);
-
- g_return_val_if_fail(gl != NULL, FALSE);
-
- msg = msim_msg_append(msg, key, type, gl);
- break;
-
- case MSIM_TYPE_DICTIONARY:
- dict = va_arg(argp, MsimMessage *);
-
- g_return_val_if_fail(dict != NULL, FALSE);
-
- msg = msim_msg_append(msg, key, type, dict);
- break;
-
- default:
- purple_debug_info("msim", "msim_send: unknown type %d\n", type);
- break;
- }
- } while(key);
-
- return msg;
-}
-
-/**
- * Create a new MsimMessage.
- *
- * @param first_key The first key in the sequence, or NULL for an empty message.
- * @param ... A sequence of gchar* key/type/value triplets, terminated with NULL.
- *
- * See msim_msg_append() documentation for details on types.
- */
-MsimMessage *
-msim_msg_new(gchar *first_key, ...)
-{
- MsimMessage *ret = NULL;
- va_list argp;
-
- if (first_key) {
- va_start(argp, first_key);
- ret = msim_msg_new_v(first_key, argp);
- va_end(argp);
- }
-
- return ret;
-}
-
-/**
- * Pack a string using the given GFunc and seperator.
- * Used by msim_msg_dump() and msim_msg_pack().
- */
-static gchar *
-msim_msg_pack_using(MsimMessage *msg,
- GFunc gf,
- const gchar *sep,
- const gchar *begin, const gchar *end)
-{
- int num_items;
- gchar **strings;
- gchar **strings_tmp;
- gchar *joined;
- gchar *final;
- int i;
-
- g_return_val_if_fail(msg != NULL, NULL);
-
- num_items = g_list_length(msg);
-
- /* Add one for NULL terminator for g_strjoinv(). */
- strings = (gchar **)g_new0(gchar *, num_items + 1);
-
- strings_tmp = strings;
- g_list_foreach(msg, gf, &strings_tmp);
-
- joined = g_strjoinv(sep, strings);
- final = g_strconcat(begin, joined, end, NULL);
- g_free(joined);
-
- /* Clean up. */
- for (i = 0; i < num_items; ++i) {
- g_free(strings[i]);
- }
-
- g_free(strings);
-
- return final;
-}
-
-/**
- * Return a human-readable string of the message.
- *
- * @return A new gchar *, must be g_free()'d.
- */
-static gchar *
-msim_msg_dump_to_str(MsimMessage *msg)
-{
- gchar *debug_str;
-
- if (!msg) {
- debug_str = g_strdup("<MsimMessage: empty>");
- } else {
- debug_str = msim_msg_pack_using(msg, msim_msg_debug_string_element,
- "\n", "<MsimMessage: \n", "\n/MsimMessage>");
- }
-
- return debug_str;
-}
-
-/**
- * Store a human-readable string describing the element.
- *
- * @param data Pointer to an MsimMessageElement.
- * @param user_data
- */
-static void
-msim_msg_debug_string_element(gpointer data, gpointer user_data)
-{
- MsimMessageElement *elem;
- gchar *string;
- GString *gs;
- gchar *binary;
- gchar ***items; /* wow, a pointer to a pointer to a pointer */
-
- gchar *s;
- GList *gl;
- guint i;
-
- elem = (MsimMessageElement *)data;
- items = user_data;
-
- switch (elem->type) {
- case MSIM_TYPE_INTEGER:
- string = g_strdup_printf("%s(integer): %d", elem->name,
- GPOINTER_TO_UINT(elem->data));
- break;
-
- case MSIM_TYPE_RAW:
- string = g_strdup_printf("%s(raw): %s", elem->name,
- elem->data ? (gchar *)elem->data : "(NULL)");
- break;
-
- case MSIM_TYPE_STRING:
- string = g_strdup_printf("%s(string): %s", elem->name,
- elem->data ? (gchar *)elem->data : "(NULL)");
- break;
-
- case MSIM_TYPE_BINARY:
- gs = (GString *)elem->data;
- binary = purple_base64_encode((guchar*)gs->str, gs->len);
- string = g_strdup_printf("%s(binary, %d bytes): %s", elem->name, (int)gs->len, binary);
- g_free(binary);
- break;
-
- case MSIM_TYPE_BOOLEAN:
- string = g_strdup_printf("%s(boolean): %s", elem->name,
- elem->data ? "TRUE" : "FALSE");
- break;
-
- case MSIM_TYPE_DICTIONARY:
- if (!elem->data) {
- s = g_strdup("(NULL)");
- } else {
- s = msim_msg_dump_to_str((MsimMessage *)elem->data);
- }
-
- if (!s) {
- s = g_strdup("(NULL, couldn't msim_msg_dump_to_str)");
- }
-
- string = g_strdup_printf("%s(dict): %s", elem->name, s);
-
- g_free(s);
- break;
-
- case MSIM_TYPE_LIST:
- gs = g_string_new("");
- g_string_append_printf(gs, "%s(list): \n", elem->name);
-
- i = 0;
- for (gl = (GList *)elem->data; gl != NULL; gl = g_list_next(gl)) {
- g_string_append_printf(gs, " %d. %s\n", i, (gchar *)(gl->data));
- ++i;
- }
-
- string = g_string_free(gs, FALSE);
- break;
-
- default:
- string = g_strdup_printf("%s(unknown type %d",
- elem->name ? elem->name : "(NULL)", elem->type);
- break;
- }
-
- **items = string;
- ++(*items);
-}
-
-/**
- * Search for and return the node in msg, matching name, or NULL.
- *
- * @param msg Message to search within.
- * @param name Field name to search for.
- *
- * @return The GList * node for the MsimMessageElement with the given name, or NULL if not found or name is NULL.
- *
- * For internal use - users probably want to use msim_msg_get() to
- * access the MsimMessageElement *, instead of the GList * container.
- *
- */
-static GList *
-msim_msg_get_node(const MsimMessage *msg, const gchar *name)
-{
- GList *node;
-
- if (!name || !msg) {
- return NULL;
- }
-
- /* Linear search for the given name. O(n) but n is small. */
- for (node = (GList*)msg; node != NULL; node = g_list_next(node)) {
- MsimMessageElement *elem;
-
- elem = (MsimMessageElement *)node->data;
-
- g_return_val_if_fail(elem != NULL, NULL);
- g_return_val_if_fail(elem->name != NULL, NULL);
-
- if (strcmp(elem->name, name) == 0) {
- return node;
- }
- }
- return NULL;
-}
-
-/**
- * Create a new MsimMessageElement * - must be g_free()'d.
- *
- * For internal use; users probably want msim_msg_append() or msim_msg_insert_before().
- *
- * @param dynamic_name Whether 'name' should be freed when the message is destroyed.
- */
-static MsimMessageElement *
-msim_msg_element_new(const gchar *name, MsimMessageType type, gpointer data, gboolean dynamic_name)
-{
- MsimMessageElement *elem;
-
- elem = g_new0(MsimMessageElement, 1);
-
- elem->name = name;
- elem->dynamic_name = dynamic_name;
- elem->type = type;
- elem->data = data;
-
- return elem;
-}
-
-/**
- * Append a new element to a message.
- *
- * @param name Textual name of element (static string, neither copied nor freed).
- * @param type An MSIM_TYPE_* code.
- * @param data Pointer to data, see below.
- *
- * @return The new message - must be assigned to as with GList*. For example:
- *
- * msg = msim_msg_append(msg, ...)
- *
- * The data parameter depends on the type given:
- *
- * * MSIM_TYPE_INTEGER: Use GUINT_TO_POINTER(x).
- *
- * * MSIM_TYPE_BINARY: Same as integer, non-zero is TRUE and zero is FALSE.
- *
- * * MSIM_TYPE_STRING: gchar *. The data WILL BE FREED - use g_strdup() if needed.
- *
- * * MSIM_TYPE_RAW: gchar *. The data WILL BE FREED - use g_strdup() if needed.
- *
- * * MSIM_TYPE_BINARY: g_string_new_len(data, length). The data AND GString will be freed.
- *
- * * MSIM_TYPE_DICTIONARY: An MsimMessage *. Freed when message is destroyed.
- *
- * * MSIM_TYPE_LIST: GList * of gchar *. Again, everything will be freed.
- *
- * */
-MsimMessage *
-msim_msg_append(MsimMessage *msg, const gchar *name,
- MsimMessageType type, gpointer data)
-{
- return g_list_append(msg, msim_msg_element_new(name, type, data, FALSE));
-}
-
-/**
- * Append a new element, but with a dynamically-allocated name.
- * Exactly the same as msim_msg_append(), except 'name' will be freed when
- * the message is destroyed. Normally, it isn't, because a static string is given.
- */
-static MsimMessage *
-msim_msg_append_dynamic_name(MsimMessage *msg, gchar *name,
- MsimMessageType type, gpointer data)
-{
- return g_list_append(msg, msim_msg_element_new(name, type, data, TRUE));
-}
-
-/**
- * Insert a new element into a message, before the given element name.
- *
- * @param name_before Name of the element to insert the new element before. If
- * could not be found or NULL, new element will be inserted at end.
- *
- * See msim_msg_append() for usage of other parameters, and an important note about return value.
- */
-MsimMessage *
-msim_msg_insert_before(MsimMessage *msg, const gchar *name_before,
- const gchar *name, MsimMessageType type, gpointer data)
-{
- MsimMessageElement *new_elem;
- GList *node_before;
-
- new_elem = msim_msg_element_new(name, type, data, FALSE);
-
- node_before = msim_msg_get_node(msg, name_before);
-
- return g_list_insert_before(msg, node_before, new_elem);
-}
-
-/**
- * Perform a deep copy on a GList * of gchar * strings. Free with msim_msg_list_free().
- */
-static GList *
-msim_msg_list_copy(const GList *old)
-{
- GList *new_list;
-
- new_list = NULL;
-
- /* Deep copy (g_list_copy is shallow). Copy each string. */
- for (; old != NULL; old = g_list_next(old)) {
- new_list = g_list_append(new_list, g_strdup(old->data));
- }
-
- return new_list;
-}
-
-/**
- * Clone an individual element.
- *
- * @param data MsimMessageElement * to clone.
- * @param user_data Pointer to MsimMessage * to add cloned element to.
- */
-static void
-msim_msg_clone_element(gpointer data, gpointer user_data)
-{
- MsimMessageElement *elem;
- MsimMessage **new;
- gpointer new_data;
-
- GString *gs;
- MsimMessage *dict;
-
- elem = (MsimMessageElement *)data;
- new = (MsimMessage **)user_data;
-
- switch (elem->type) {
- case MSIM_TYPE_BOOLEAN:
- case MSIM_TYPE_INTEGER:
- new_data = elem->data;
- break;
-
- case MSIM_TYPE_RAW:
- case MSIM_TYPE_STRING:
- new_data = g_strdup((gchar *)elem->data);
- break;
-
- case MSIM_TYPE_LIST:
- new_data = (gpointer)msim_msg_list_copy((GList *)(elem->data));
- break;
-
- case MSIM_TYPE_BINARY:
- gs = (GString *)elem->data;
-
- new_data = g_string_new_len(gs->str, gs->len);
- break;
- case MSIM_TYPE_DICTIONARY:
- dict = (MsimMessage *)elem->data;
-
- new_data = msim_msg_clone(dict);
- break;
-
- default:
- purple_debug_info("msim", "msim_msg_clone_element: unknown type %d\n", elem->type);
- g_return_if_reached();
- }
-
- /* Append cloned data. Note that the 'name' field is a static string, so it
- * never needs to be copied nor freed. */
- if (elem->dynamic_name)
- *new = msim_msg_append_dynamic_name(*new, g_strdup(elem->name), elem->type, new_data);
- else
- *new = msim_msg_append(*new, elem->name, elem->type, new_data);
-}
-
-/**
- * Clone an existing MsimMessage.
- *
- * @return Cloned message; caller should free with msim_msg_free().
- */
-MsimMessage *
-msim_msg_clone(MsimMessage *old)
-{
- MsimMessage *new;
-
- if (old == NULL) {
- return NULL;
- }
-
- new = msim_msg_new(FALSE);
-
- g_list_foreach(old, msim_msg_clone_element, &new);
-
- return new;
-}
-
-/**
- * Free the data of a message element.
- *
- * @param elem The MsimMessageElement *
- *
- * Note this only frees the element data; you may also want to free the
- * element itself with g_free() (see msim_msg_free_element()).
- */
-void
-msim_msg_free_element_data(MsimMessageElement *elem)
-{
- switch (elem->type) {
- case MSIM_TYPE_BOOLEAN:
- case MSIM_TYPE_INTEGER:
- /* Integer value stored in gpointer - no need to free(). */
- break;
-
- case MSIM_TYPE_RAW:
- case MSIM_TYPE_STRING:
- /* Always free strings - caller should have g_strdup()'d if
- * string was static or temporary and not to be freed. */
- g_free(elem->data);
- break;
-
- case MSIM_TYPE_BINARY:
- /* Free the GString itself and the binary data. */
- g_string_free((GString *)elem->data, TRUE);
- break;
-
- case MSIM_TYPE_DICTIONARY:
- msim_msg_free((MsimMessage *)elem->data);
- break;
-
- case MSIM_TYPE_LIST:
- g_list_free((GList *)elem->data);
- break;
-
- default:
- purple_debug_info("msim", "msim_msg_free_element_data: "
- "not freeing unknown type %d\n", elem->type);
- break;
- }
-}
-
-/**
- * Free a GList * of MsimMessageElement *'s.
- */
-void
-msim_msg_list_free(GList *l)
-{
-
- for (; l != NULL; l = g_list_next(l)) {
- MsimMessageElement *elem;
-
- elem = (MsimMessageElement *)l->data;
-
- /* Note that name is almost never dynamically allocated elsewhere;
- * it is usually a static string, but not in lists. So cast it. */
- g_free((gchar *)elem->name);
- g_free(elem->data);
- g_free(elem);
- }
- g_list_free(l);
-}
-
-/**
- * Free an individual message element.
- *
- * @param data MsimMessageElement * to free.
- * @param user_data Not used; required to match g_list_foreach() callback prototype.
- *
- * Frees both the element data and the element itself.
- * Also frees the name if dynamic_name is TRUE.
- */
-static void
-msim_msg_free_element(gpointer data, gpointer user_data)
-{
- MsimMessageElement *elem;
-
- elem = (MsimMessageElement *)data;
-
- msim_msg_free_element_data(elem);
-
- if (elem->dynamic_name)
- /* Need to cast to remove const-ness, because
- * elem->name is almost always a constant, static
- * string, but not in this case. */
- g_free((gchar *)elem->name);
-
- g_free(elem);
-}
-
-/**
- * Free a complete message.
- */
-void
-msim_msg_free(MsimMessage *msg)
-{
- if (!msg) {
- /* already free as can be */
- return;
- }
-
- g_list_foreach(msg, msim_msg_free_element, NULL);
- g_list_free(msg);
-}
-
-/**
- * Pack an element into its protocol representation.
- *
- * @param data Pointer to an MsimMessageElement.
- * @param user_data Pointer to a gchar ** array of string items.
- *
- * Called by msim_msg_pack(). Will pack the MsimMessageElement into
- * a part of the protocol string and append it to the array. Caller
- * is responsible for creating array to correct dimensions, and
- * freeing each string element of the array added by this function.
- */
-static void
-msim_msg_pack_element(gpointer data, gpointer user_data)
-{
- MsimMessageElement *elem;
- gchar *string, *data_string;
- gchar ***items;
-
- elem = (MsimMessageElement *)data;
- items = (gchar ***)user_data;
-
- /* Exclude elements beginning with '_' from packed protocol messages. */
- if (elem->name[0] == '_') {
- return;
- }
-
- data_string = msim_msg_pack_element_data(elem);
-
- switch (elem->type) {
- /* These types are represented by key name/value pairs (converted above). */
- case MSIM_TYPE_INTEGER:
- case MSIM_TYPE_RAW:
- case MSIM_TYPE_STRING:
- case MSIM_TYPE_BINARY:
- case MSIM_TYPE_DICTIONARY:
- case MSIM_TYPE_LIST:
- string = g_strconcat(elem->name, "\\", data_string, NULL);
- break;
-
- /* Boolean is represented by absence or presence of name. */
- case MSIM_TYPE_BOOLEAN:
- if (GPOINTER_TO_UINT(elem->data)) {
- /* True - leave in, with blank value. */
- string = g_strdup_printf("%s\\", elem->name);
- } else {
- /* False - leave out. */
- string = g_strdup("");
- }
- break;
-
- default:
- g_free(data_string);
- g_return_if_reached();
- break;
- }
-
- g_free(data_string);
-
- **items = string;
- ++(*items);
-}
-
-/**
- * Pack an element into its protcol representation inside a dictionary.
- *
- * See msim_msg_pack_element().
- */
-static void
-msim_msg_pack_element_dict(gpointer data, gpointer user_data)
-{
- MsimMessageElement *elem;
- gchar *string, *data_string, ***items;
-
- elem = (MsimMessageElement *)data;
- items = (gchar ***)user_data;
-
- /* Exclude elements beginning with '_' from packed protocol messages. */
- if (elem->name[0] == '_') {
- return;
- }
-
- data_string = msim_msg_pack_element_data(elem);
-
- g_return_if_fail(data_string != NULL);
-
- switch (elem->type) {
- /* These types are represented by key name/value pairs (converted above). */
- case MSIM_TYPE_INTEGER:
- case MSIM_TYPE_RAW:
- case MSIM_TYPE_STRING:
- case MSIM_TYPE_BINARY:
- case MSIM_TYPE_DICTIONARY:
- case MSIM_TYPE_LIST:
- case MSIM_TYPE_BOOLEAN: /* Boolean is On or Off */
- string = g_strconcat(elem->name, "=", data_string, NULL);
- break;
-
- default:
- g_free(data_string);
- g_return_if_fail(FALSE);
- break;
- }
-
- g_free(data_string);
-
- **items = string;
- ++(*items);
-}
-
-/**
- * Return a packed string of a message suitable for sending over the wire.
- *
- * @return A string. Caller must g_free().
- */
-gchar *
-msim_msg_pack(MsimMessage *msg)
-{
- g_return_val_if_fail(msg != NULL, NULL);
-
- return msim_msg_pack_using(msg, msim_msg_pack_element, "\\", "\\", "\\final\\");
-}
-
-/**
- * Return a packed string of a dictionary, suitable for embedding in MSIM_TYPE_DICTIONARY.
- *
- * @return A string; caller must g_free().
- */
-static gchar *
-msim_msg_pack_dict(MsimMessage *msg)
-{
- g_return_val_if_fail(msg != NULL, NULL);
-
- return msim_msg_pack_using(msg, msim_msg_pack_element_dict, "\034", "", "");
-}
-
-/**
- * Send an existing MsimMessage.
- */
-gboolean
-msim_msg_send(MsimSession *session, MsimMessage *msg)
-{
- gchar *raw;
- gboolean success;
-
- raw = msim_msg_pack(msg);
- g_return_val_if_fail(raw != NULL, FALSE);
- success = msim_send_raw(session, raw);
- g_free(raw);
-
- return success;
-}
-
-/**
- * Return a message element data as a new string for a raw protocol message,
- * converting from other types (integer, etc.) if necessary.
- *
- * @return const gchar * The data as a string, or NULL. Caller must g_free().
- *
- * Returns a string suitable for inclusion in a raw protocol message, not necessarily
- * optimal for human consumption. For example, strings are escaped. Use
- * msim_msg_get_string() if you want a string, which in some cases is same as this.
- */
-gchar *
-msim_msg_pack_element_data(MsimMessageElement *elem)
-{
- GString *gs;
- GList *gl;
-
- g_return_val_if_fail(elem != NULL, NULL);
-
- switch (elem->type) {
- case MSIM_TYPE_INTEGER:
- return g_strdup_printf("%d", GPOINTER_TO_UINT(elem->data));
-
- case MSIM_TYPE_RAW:
- /* Not un-escaped - this is a raw element, already escaped if necessary. */
- return (gchar *)g_strdup((gchar *)elem->data);
-
- case MSIM_TYPE_STRING:
- /* Strings get escaped. msim_escape() creates a new string. */
- g_return_val_if_fail(elem->data != NULL, NULL);
- return elem->data ? msim_escape((gchar *)elem->data) :
- g_strdup("(NULL)");
-
- case MSIM_TYPE_BINARY:
- gs = (GString *)elem->data;
- /* Do not escape! */
- return purple_base64_encode((guchar *)gs->str, gs->len);
-
- case MSIM_TYPE_BOOLEAN:
- /* Not used by messages in the wire protocol * -- see msim_msg_pack_element.
- * Only used by dictionaries, see msim_msg_pack_element_dict. */
- return elem->data ? g_strdup("On") : g_strdup("Off");
-
- case MSIM_TYPE_DICTIONARY:
- return msim_msg_pack_dict((MsimMessage *)elem->data);
-
- case MSIM_TYPE_LIST:
- /* Pack using a|b|c|d|... */
- gs = g_string_new("");
-
- for (gl = (GList *)elem->data; gl != NULL; gl = g_list_next(gl)) {
- g_string_append_printf(gs, "%s", (gchar*)(gl->data));
-
- /* All but last element is separated by a bar. */
- if (g_list_next(gl))
- g_string_append(gs, "|");
- }
-
- return g_string_free(gs, FALSE);
-
- default:
- purple_debug_info("msim", "field %s, unknown type %d\n",
- elem->name ? elem->name : "(NULL)",
- elem->type);
- return NULL;
- }
-}
-
-/**
- * Send a message to the server, whose contents is specified using
- * variable arguments.
- *
- * @param session
- * @param ... A sequence of gchar* key/type/value triplets, terminated with NULL.
- *
- * This function exists for coding convenience: it allows a message to be created
- * and sent in one line of code. Internally it calls msim_msg_send().
- *
- * IMPORTANT: See msim_msg_append() documentation for details on element types.
- *
- */
-gboolean
-msim_send(MsimSession *session, ...)
-{
- gboolean success;
- MsimMessage *msg;
- va_list argp;
-
- va_start(argp, session);
- msg = msim_msg_new_v(NULL, argp);
- va_end(argp);
-
- /* Actually send the message. */
- success = msim_msg_send(session, msg);
-
- /* Cleanup. */
- msim_msg_free(msg);
-
- return success;
-}
-
-/**
- * Print a human-readable string of the message to Purple's debug log.
- *
- * @param fmt_string A static string, in which '%s' will be replaced.
- */
-void
-msim_msg_dump(const gchar *fmt_string, MsimMessage *msg)
-{
- gchar *debug_str;
-
- g_return_if_fail(fmt_string != NULL);
-
- debug_str = msim_msg_dump_to_str(msg);
-
- g_return_if_fail(debug_str != NULL);
-
- purple_debug_info("msim", fmt_string, debug_str);
-
- g_free(debug_str);
-}
-
-/**
- * Parse a raw protocol message string into a MsimMessage *.
- *
- * @param raw The raw message string to parse, will be g_free()'d.
- *
- * @return MsimMessage *. Caller should msim_msg_free() when done.
- */
-MsimMessage *
-msim_parse(const gchar *raw)
-{
- MsimMessage *msg;
- gchar *token;
- gchar **tokens;
- gchar *key;
- gchar *value;
- int i;
-
- g_return_val_if_fail(raw != NULL, NULL);
-
- purple_debug_info("msim", "msim_parse: got <%s>\n", raw);
-
- key = NULL;
-
- /* All messages begin with a \. */
- if (raw[0] != '\\' || raw[1] == 0) {
- purple_debug_info("msim", "msim_parse: incomplete/bad string, "
- "missing initial backslash: <%s>\n", raw);
- /* XXX: Should we try to recover, and read to first backslash? */
-
- return NULL;
- }
-
- msg = msim_msg_new(FALSE);
-
- for (tokens = g_strsplit(raw + 1, "\\", 0), i = 0;
- (token = tokens[i]);
- i++) {
-#ifdef MSIM_DEBUG_PARSE
- purple_debug_info("msim", "tok=<%s>, i%2=%d\n", token, i % 2);
-#endif
- if (i % 2) {
- /* Odd-numbered ordinal is a value. */
-
- value = token;
-
- /* Incoming protocol messages get tagged as MSIM_TYPE_RAW, which
- * represents an untyped piece of data. msim_msg_get_* will
- * convert to appropriate types for caller, and handle unescaping if needed. */
- msg = msim_msg_append_dynamic_name(msg, g_strdup(key), MSIM_TYPE_RAW, g_strdup(value));
-#ifdef MSIM_DEBUG_PARSE
- purple_debug_info("msim", "insert string: |%s|=|%s|\n", key, value);
-#endif
- } else {
- /* Even numbered indexes are key names. */
- key = token;
- }
- }
- g_strfreev(tokens);
-
- return msg;
-}
-
-/**
- * Return the first MsimMessageElement * with given name in the MsimMessage *.
- *
- * @param name Name to search for.
- *
- * @return MsimMessageElement * matching name, or NULL.
- *
- * Note: useful fields of MsimMessageElement are 'data' and 'type', which
- * you can access directly. But it is often more convenient to use
- * another msim_msg_get_* that converts the data to what type you want.
- */
-MsimMessageElement *
-msim_msg_get(const MsimMessage *msg, const gchar *name)
-{
- GList *node;
-
- node = msim_msg_get_node(msg, name);
- if (node) {
- return (MsimMessageElement *)node->data;
- } else {
- return NULL;
- }
-}
-
-gchar *
-msim_msg_get_string_from_element(MsimMessageElement *elem)
-{
- g_return_val_if_fail(elem != NULL, NULL);
- switch (elem->type) {
- case MSIM_TYPE_INTEGER:
- return g_strdup_printf("%d", GPOINTER_TO_UINT(elem->data));
-
- case MSIM_TYPE_RAW:
- /* Raw element from incoming message - if its a string, it'll
- * be escaped. */
- return msim_unescape((gchar *)elem->data);
-
- case MSIM_TYPE_STRING:
- /* Already unescaped. */
- return g_strdup((gchar *)elem->data);
-
- default:
- purple_debug_info("msim", "msim_msg_get_string_element: type %d unknown, name %s\n",
- elem->type, elem->name ? elem->name : "(NULL)");
- return NULL;
- }
-}
-
-/**
- * Return the data of an element of a given name, as a string.
- *
- * @param name Name of element.
- *
- * @return gchar * The data as a string, or NULL if not found.
- * Caller must g_free().
- *
- * Note that msim_msg_pack_element_data() is similar, but returns a string
- * for inclusion into a raw protocol string (escaped and everything).
- * This function unescapes the string for you, if needed.
- */
-gchar *
-msim_msg_get_string(const MsimMessage *msg, const gchar *name)
-{
- MsimMessageElement *elem;
-
- elem = msim_msg_get(msg, name);
- if (!elem) {
- return NULL;
- }
-
- return msim_msg_get_string_from_element(elem);
-}
-
-/**
- * Parse a |-separated string into a new GList. Free with msim_msg_list_free().
- */
-static GList *
-msim_msg_list_parse(const gchar *raw)
-{
- gchar **array;
- GList *list;
- guint i;
-
- array = g_strsplit(raw, "|", 0);
- list = NULL;
-
- /* TODO: escape/unescape /3 <-> | within list elements */
-
- for (i = 0; array[i] != NULL; ++i) {
- MsimMessageElement *elem;
-
- /* Freed in msim_msg_list_free() */
- elem = g_new0(MsimMessageElement, 1);
-
- /* Give the element a name for debugging purposes.
- * Not supposed to be looked up by this name; instead,
- * lookup the elements by indexing the array. */
- elem->name = g_strdup_printf("(list item #%d)", i);
- elem->type = MSIM_TYPE_RAW;
- elem->data = g_strdup(array[i]);
-
- list = g_list_append(list, elem);
- }
-
- g_strfreev(array);
-
- return list;
-}
-
-static GList *
-msim_msg_get_list_from_element(MsimMessageElement *elem)
-{
- g_return_val_if_fail(elem != NULL, NULL);
- switch (elem->type) {
- case MSIM_TYPE_LIST:
- return msim_msg_list_copy((GList *)elem->data);
-
- case MSIM_TYPE_RAW:
- return msim_msg_list_parse((gchar *)elem->data);
-
- default:
- purple_debug_info("msim_msg_get_list", "type %d unknown, name %s\n",
- elem->type, elem->name ? elem->name : "(NULL)");
- return NULL;
- }
-}
-
-/**
- * Return an element as a new list. Caller frees with msim_msg_list_free().
- */
-GList *
-msim_msg_get_list(const MsimMessage *msg, const gchar *name)
-{
- MsimMessageElement *elem;
-
- elem = msim_msg_get(msg, name);
- if (!elem) {
- return NULL;
- }
-
- return msim_msg_get_list_from_element(elem);
-}
-
-/**
- * Parse a \x1c-separated "dictionary" of key=value pairs into a hash table.
- *
- * @param raw The text of the dictionary to parse. Often the
- * value for the 'body' field.
- *
- * @return A new MsimMessage *. Must msim_msg_free() when done.
- */
-static MsimMessage *
-msim_msg_dictionary_parse(const gchar *raw)
-{
- MsimMessage *dict;
- gchar *item;
- gchar **items;
- gchar **elements;
- guint i;
-
- g_return_val_if_fail(raw != NULL, NULL);
-
- dict = msim_msg_new(NULL);
-
- for (items = g_strsplit(raw, "\x1c", 0), i = 0;
- (item = items[i]);
- i++) {
- gchar *key, *value;
-
- elements = g_strsplit(item, "=", 2);
-
- key = elements[0];
- if (!key) {
- purple_debug_info("msim", "msim_msg_dictionary_parse(%s): null key\n",
- raw);
- g_strfreev(elements);
- break;
- }
-
- value = elements[1];
- if (!value) {
- purple_debug_info("msim", "msim_msg_dictionary_prase(%s): null value\n",
- raw);
- g_strfreev(elements);
- break;
- }
-
-#ifdef MSIM_DEBUG_PARSE
- purple_debug_info("msim_msg_dictionary_parse","-- %s: %s\n", key ? key : "(NULL)",
- value ? value : "(NULL)");
-#endif
- /* Append with _dynamic_name since g_strdup(key) is dynamic, and
- * needs to be freed when the message is destroyed. It isn't static as usual. */
- dict = msim_msg_append_dynamic_name(dict, g_strdup(key), MSIM_TYPE_RAW, g_strdup(value));
-
- g_strfreev(elements);
- }
-
- g_strfreev(items);
-
- return dict;
-}
-
-static MsimMessage *
-msim_msg_get_dictionary_from_element(MsimMessageElement *elem)
-{
- g_return_val_if_fail(elem != NULL, NULL);
- switch (elem->type) {
- case MSIM_TYPE_DICTIONARY:
- return msim_msg_clone((MsimMessage *)elem->data);
-
- case MSIM_TYPE_RAW:
- return msim_msg_dictionary_parse(elem->data);
-
- default:
- purple_debug_info("msim_msg_get_dictionary", "type %d unknown, name %s\n",
- elem->type, elem->name ? elem->name : "(NULL)");
- return NULL;
- }
-}
-
-/**
- * Return an element as a new dictionary. Caller frees with msim_msg_free().
- */
-MsimMessage *
-msim_msg_get_dictionary(const MsimMessage *msg, const gchar *name)
-{
- MsimMessageElement *elem;
-
- elem = msim_msg_get(msg, name);
- if (!elem) {
- return NULL;
- }
-
- return msim_msg_get_dictionary_from_element(elem);
-}
-
-guint
-msim_msg_get_integer_from_element(MsimMessageElement *elem)
-{
- g_return_val_if_fail(elem != NULL, 0);
- switch (elem->type) {
- case MSIM_TYPE_INTEGER:
- return GPOINTER_TO_UINT(elem->data);
-
- case MSIM_TYPE_RAW:
- case MSIM_TYPE_STRING:
- /* TODO: find out if we need larger integers */
- return (guint)atoi((gchar *)elem->data);
-
- default:
- return 0;
- }
-}
-
-/**
- * Return the data of an element of a given name, as an unsigned integer.
- *
- * @param name Name of element.
- *
- * @return guint Numeric representation of data, or 0 if could not be converted / not found.
- *
- * Useful to obtain an element's data if you know it should be an integer,
- * even if it is not stored as an MSIM_TYPE_INTEGER. MSIM_TYPE_STRING will
- * be converted handled correctly, for example.
- */
-guint
-msim_msg_get_integer(const MsimMessage *msg, const gchar *name)
-{
- MsimMessageElement *elem;
-
- elem = msim_msg_get(msg, name);
-
- if (!elem) {
- return 0;
- }
-
- return msim_msg_get_integer_from_element(elem);
-}
-
-static gboolean
-msim_msg_get_binary_from_element(MsimMessageElement *elem, gchar **binary_data, gsize *binary_length)
-{
- GString *gs;
-
- g_return_val_if_fail(elem != NULL, FALSE);
-
- switch (elem->type) {
- case MSIM_TYPE_RAW:
- /* Incoming messages are tagged with MSIM_TYPE_RAW, and
- * converted appropriately. They can still be "strings", just they won't
- * be tagged as MSIM_TYPE_STRING (as MSIM_TYPE_STRING is intended to be used
- * by msimprpl code for things like instant messages - stuff that should be
- * escaped if needed). DWIM.
- */
-
- /* Previously, incoming messages were stored as MSIM_TYPE_STRING.
- * This was fine for integers and strings, since they can easily be
- * converted in msim_get_*, as desirable. However, it does not work
- * well for binary strings. Consider:
- *
- * If incoming base64'd elements were tagged as MSIM_TYPE_STRING.
- * msim_msg_get_binary() sees MSIM_TYPE_STRING, base64 decodes, returns.
- * everything is fine.
- * But then, msim_send() is called on the incoming message, which has
- * a base64'd MSIM_TYPE_STRING that really is encoded binary. The values
- * will be escaped since strings are escaped, and / becomes /2; no good.
- *
- */
- *binary_data = (gchar *)purple_base64_decode((const gchar *)elem->data, binary_length);
- return ((*binary_data) != NULL);
-
- case MSIM_TYPE_BINARY:
- gs = (GString *)elem->data;
-
- /* Duplicate data, so caller can g_free() it. */
- *binary_data = g_memdup(gs->str, gs->len);
- *binary_length = gs->len;
-
- return TRUE;
-
-
- /* Rejected because if it isn't already a GString, have to g_new0 it and
- * then caller has to ALSO free the GString!
- *
- * return (GString *)elem->data; */
-
- default:
- purple_debug_info("msim", "msim_msg_get_binary: unhandled type %d for key %s\n",
- elem->type, elem->name ? elem->name : "(NULL)");
- return FALSE;
- }
-}
-
-/**
- * Return the data of an element of a given name, as a binary GString.
- *
- * @param binary_data A pointer to a new pointer, which will be filled in with the binary data. CALLER MUST g_free().
- *
- * @param binary_length A pointer to an integer, which will be set to the binary data length.
- *
- * @return TRUE if successful, FALSE if not.
- */
-gboolean
-msim_msg_get_binary(const MsimMessage *msg, const gchar *name,
- gchar **binary_data, gsize *binary_length)
-{
- MsimMessageElement *elem;
-
- elem = msim_msg_get(msg, name);
- if (!elem) {
- return FALSE;
- }
-
- return msim_msg_get_binary_from_element(elem, binary_data, binary_length);
-}
diff --git a/libpurple/protocols/myspace/message.h b/libpurple/protocols/myspace/message.h
deleted file mode 100644
index 5f1bcc852b..0000000000
--- a/libpurple/protocols/myspace/message.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/** MySpaceIM protocol messages
- *
- * \author Jeff Connelly
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * 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 _MYSPACE_MESSAGE_H
-#define _MYSPACE_MESSAGE_H
-
-#include <glib.h>
-
-#define MsimMessage GList /* #define instead of typedef to avoid casting */
-typedef gchar MsimMessageType;
-typedef struct _MsimMessageElement MsimMessageElement;
-
-#include "session.h"
-
-/* Types */
-struct _MsimMessageElement
-{
- const gchar *name; /**< Textual name of element. */
- gboolean dynamic_name; /**< TRUE if 'name' is a dynamic string to be freed, not static. */
- guint type; /**< MSIM_TYPE_* code. */
- gpointer data; /**< Pointer to data, or GUINT_TO_POINTER for int/bool. */
-};
-
-#define msim_msg_get_next_element_node(msg) ((MsimMessage *)(msg->next))
-
-/* Protocol field types */
-#define MSIM_TYPE_RAW '-'
-#define MSIM_TYPE_INTEGER 'i'
-#define MSIM_TYPE_STRING 's'
-#define MSIM_TYPE_BINARY 'b'
-#define MSIM_TYPE_BOOLEAN 'f'
-#define MSIM_TYPE_DICTIONARY 'd'
-#define MSIM_TYPE_LIST 'l'
-
-gchar *msim_escape(const gchar *msg);
-gchar *msim_unescape(const gchar *msg);
-
-MsimMessage *msim_msg_new(gchar *first_key, ...);
-/* No sentinel attribute, because can leave off varargs if not_empty is FALSE. */
-
-MsimMessage *msim_msg_clone(MsimMessage *old);
-void msim_msg_free_element_data(MsimMessageElement *elem);
-void msim_msg_free(MsimMessage *msg);
-MsimMessage *msim_msg_append(MsimMessage *msg, const gchar *name, MsimMessageType type, gpointer data);
-MsimMessage *msim_msg_insert_before(MsimMessage *msg, const gchar *name_before, const gchar *name, MsimMessageType type, gpointer data);
-gchar *msim_msg_pack_element_data(MsimMessageElement *elem);
-void msim_msg_dump(const char *fmt_string, MsimMessage *msg);
-gchar *msim_msg_pack(MsimMessage *msg);
-
-void msim_msg_list_free(GList *l);
-
-/* Based on http://permalink.gmane.org/gmane.comp.parsers.sparse/695
- * Define macros for useful gcc attributes. */
-#ifdef __GNUC__
-#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
-#define FORMAT_ATTR(pos) __attribute__ ((__format__ (__printf__, pos, pos+1)))
-#define NORETURN_ATTR __attribute__ ((__noreturn__))
-/* __sentinel__ attribute was introduced in gcc 3.5 */
-#if (GCC_VERSION >= 3005)
- #define SENTINEL_ATTR __attribute__ ((__sentinel__(0)))
-#else
- #define SENTINEL_ATTR
-#endif /* gcc >= 3.5 */
-#else
- #define FORMAT_ATTR(pos)
- #define NORETURN_ATTR
- #define SENTINEL_ATTR
-#endif
-
-/* Cause gcc to emit "a missing sentinel in function call" if forgot
- * to write NULL as last, terminating parameter. */
-gboolean msim_send(struct _MsimSession *session, ...) SENTINEL_ATTR;
-
-gboolean msim_msg_send(struct _MsimSession *session, MsimMessage *msg);
-
-MsimMessage *msim_parse(const gchar *raw);
-
-MsimMessageElement *msim_msg_get(const MsimMessage *msg, const gchar *name);
-
-/* Retrieve data by name */
-gchar *msim_msg_get_string(const MsimMessage *msg, const gchar *name);
-GList *msim_msg_get_list(const MsimMessage *msg, const gchar *name);
-MsimMessage *msim_msg_get_dictionary(const MsimMessage *msg, const gchar *name);
-guint msim_msg_get_integer(const MsimMessage *msg, const gchar *name);
-gboolean msim_msg_get_binary(const MsimMessage *msg, const gchar *name, gchar **binary_data, gsize *binary_length);
-
-/* Retrieve data by element (MsimMessageElement *), returned from msim_msg_get() */
-gchar *msim_msg_get_string_from_element(MsimMessageElement *elem);
-guint msim_msg_get_integer_from_element(MsimMessageElement *elem);
-
-#endif /* _MYSPACE_MESSAGE_H */
diff --git a/libpurple/protocols/myspace/myspace.c b/libpurple/protocols/myspace/myspace.c
deleted file mode 100644
index 4a261192a0..0000000000
--- a/libpurple/protocols/myspace/myspace.c
+++ /dev/null
@@ -1,3667 +0,0 @@
-/**
- * MySpaceIM Protocol Plugin
- *
- * \author Jeff Connelly
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * Based on Purple's "C Plugin HOWTO" hello world example.
- *
- * Code also drawn from mockprpl:
- * http://snarfed.org/space/purple+mock+protocol+plugin
- * Copyright (C) 2004-2007, Ryan Barrett <mockprpl@ryanb.org>
- *
- * and some constructs also based on existing Purple plugins, which are:
- * Copyright (C) 2003, Robbert Haarman <purple@inglorion.net>
- * Copyright (C) 2003, Ethan Blanton <eblanton@cs.purdue.edu>
- * Copyright (C) 2000-2003, Rob Flynn <rob@tgflinux.com>
- * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
- *
- * 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 PURPLE_PLUGIN
-
-#include "myspace.h"
-
-#include "privacy.h"
-
-static void msim_set_status(PurpleAccount *account, PurpleStatus *status);
-static void msim_set_idle(PurpleConnection *gc, int time);
-
-/**
- * Perform actual postprocessing on a message, adding userid as specified.
- *
- * @param msg The message to postprocess.
- * @param uid_before Name of field where to insert new field before, or NULL for end.
- * @param uid_field_name Name of field to add uid to.
- * @param uid The userid to insert.
- *
- * If the field named by uid_field_name already exists, then its string contents will
- * be used for the field, except "<uid>" will be replaced by the userid.
- *
- * If the field named by uid_field_name does not exist, it will be added before the
- * field named by uid_before, as an integer, with the userid.
- *
- * Does not handle sending, or scheduling userid lookup. For that, see msim_postprocess_outgoing().
- */
-static MsimMessage *
-msim_do_postprocessing(MsimMessage *msg, const gchar *uid_before,
- const gchar *uid_field_name, guint uid)
-{
- MsimMessageElement *elem;
-
- /* First, check - if the field already exists, replace <uid> within it */
- if ((elem = msim_msg_get(msg, uid_field_name)) != NULL) {
- gchar *fmt_string;
- gchar *uid_str, *new_str;
-
- /* Get the packed element, flattening it. This allows <uid> to be
- * replaced within nested data structures, since the replacement is done
- * on the linear, packed data, not on a complicated data structure.
- *
- * For example, if the field was originally a dictionary or a list, you
- * would have to iterate over all the items in it to see what needs to
- * be replaced. But by packing it first, the <uid> marker is easily replaced
- * just by a string replacement.
- */
- fmt_string = msim_msg_pack_element_data(elem);
-
- uid_str = g_strdup_printf("%d", uid);
- new_str = purple_strreplace(fmt_string, "<uid>", uid_str);
- g_free(uid_str);
- g_free(fmt_string);
-
- /* Free the old element data */
- msim_msg_free_element_data(elem->data);
-
- /* Replace it with our new data */
- elem->data = new_str;
- elem->type = MSIM_TYPE_RAW;
-
- } else {
- /* Otherwise, insert new field into outgoing message. */
- msg = msim_msg_insert_before(msg, uid_before, uid_field_name, MSIM_TYPE_INTEGER, GUINT_TO_POINTER(uid));
- }
-
- return msg;
-}
-
-/**
- * Callback for msim_postprocess_outgoing() to add a userid to a message, and send it (once receiving userid).
- *
- * @param session
- * @param userinfo The user information reply message, containing the user ID
- * @param data The message to postprocess and send.
- *
- * The data message should contain these fields:
- *
- * _uid_field_name: string, name of field to add with userid from userinfo message
- * _uid_before: string, name of field before field to insert, or NULL for end
- */
-static void
-msim_postprocess_outgoing_cb(MsimSession *session, const MsimMessage *userinfo,
- gpointer data)
-{
- gchar *uid_field_name, *uid_before, *username;
- guint uid;
- MsimMessage *msg, *body;
-
- msg = (MsimMessage *)data;
-
- /* Obtain userid from userinfo message. */
- body = msim_msg_get_dictionary(userinfo, "body");
- g_return_if_fail(body != NULL);
-
- uid = msim_msg_get_integer(body, "UserID");
- msim_msg_free(body);
-
- username = msim_msg_get_string(msg, "_username");
-
- if (!uid) {
- gchar *msg;
-
- msg = g_strdup_printf(_("No such user: %s"), username);
- if (!purple_conv_present_error(username, session->account, msg)) {
- purple_notify_error(NULL, NULL, _("User lookup"), msg);
- }
-
- g_free(msg);
- g_free(username);
- /* TODO: free
- * msim_msg_free(msg);
- */
- return;
- }
-
- uid_field_name = msim_msg_get_string(msg, "_uid_field_name");
- uid_before = msim_msg_get_string(msg, "_uid_before");
-
- msg = msim_do_postprocessing(msg, uid_before, uid_field_name, uid);
-
- /* Send */
- if (!msim_msg_send(session, msg)) {
- msim_msg_dump("msim_postprocess_outgoing_cb: sending failed for message: %s\n", msg);
- }
-
-
- /* Free field names AFTER sending message, because MsimMessage does NOT copy
- * field names - instead, treats them as static strings (which they usually are).
- */
- g_free(uid_field_name);
- g_free(uid_before);
- g_free(username);
- /* TODO: free
- * msim_msg_free(msg);
- */
-}
-
-/**
- * Postprocess and send a message.
- *
- * @param session
- * @param msg Message to postprocess. Will NOT be freed.
- * @param username Username to resolve. Assumed to be a static string (will not be freed or copied).
- * @param uid_field_name Name of new field to add, containing uid of username. Static string.
- * @param uid_before Name of existing field to insert username field before. Static string.
- *
- * @return TRUE if successful.
- */
-static gboolean
-msim_postprocess_outgoing(MsimSession *session, MsimMessage *msg,
- const gchar *username, const gchar *uid_field_name,
- const gchar *uid_before)
-{
- PurpleBuddy *buddy;
- guint uid;
- gboolean rc;
-
- g_return_val_if_fail(msg != NULL, FALSE);
-
- /* Store information for msim_postprocess_outgoing_cb(). */
- msg = msim_msg_append(msg, "_username", MSIM_TYPE_STRING, g_strdup(username));
- msg = msim_msg_append(msg, "_uid_field_name", MSIM_TYPE_STRING, g_strdup(uid_field_name));
- msg = msim_msg_append(msg, "_uid_before", MSIM_TYPE_STRING, g_strdup(uid_before));
-
- /* First, try the most obvious. If numeric userid is given, use that directly. */
- if (msim_is_userid(username)) {
- uid = atol(username);
- } else {
- /* Next, see if on buddy list and know uid. */
- buddy = purple_find_buddy(session->account, username);
- if (buddy) {
- uid = purple_blist_node_get_int(PURPLE_BLIST_NODE(buddy), "UserID");
- } else {
- uid = 0;
- }
-
- if (!buddy || !uid) {
- /* Don't have uid offhand - need to ask for it, and wait until hear back before sending. */
- purple_debug_info("msim", ">>> msim_postprocess_outgoing: couldn't find username %s in blist\n",
- username ? username : "(NULL)");
- msim_lookup_user(session, username, msim_postprocess_outgoing_cb, msim_msg_clone(msg));
- return TRUE; /* not sure of status yet - haven't sent! */
- }
- }
-
- /* Already have uid, postprocess and send msg immediately. */
- purple_debug_info("msim", "msim_postprocess_outgoing: found username %s has uid %d\n",
- username ? username : "(NULL)", uid);
-
- msg = msim_do_postprocessing(msg, uid_before, uid_field_name, uid);
-
- rc = msim_msg_send(session, msg);
-
- /* TODO: free
- * msim_msg_free(msg);
- */
-
- return rc;
-}
-
-/**
- * Send a buddy message of a given type.
- *
- * @param session
- * @param who Username to send message to.
- * @param text Message text to send. Not freed; will be copied.
- * @param type A MSIM_BM_* constant.
- *
- * @return TRUE if success, FALSE if fail.
- *
- * Buddy messages ('bm') include instant messages, action messages, status messages, etc.
- */
-gboolean
-msim_send_bm(MsimSession *session, const gchar *who, const gchar *text,
- int type)
-{
- gboolean rc;
- MsimMessage *msg;
- const gchar *from_username;
-
- g_return_val_if_fail(who != NULL, FALSE);
- g_return_val_if_fail(text != NULL, FALSE);
-
- from_username = session->account->username;
-
- g_return_val_if_fail(from_username != NULL, FALSE);
-
- purple_debug_info("msim", "sending %d message from %s to %s: %s\n",
- type, from_username, who, text);
-
- msg = msim_msg_new(
- "bm", MSIM_TYPE_INTEGER, GUINT_TO_POINTER(type),
- "sesskey", MSIM_TYPE_INTEGER, GUINT_TO_POINTER(session->sesskey),
- /* 't' will be inserted here */
- "cv", MSIM_TYPE_INTEGER, GUINT_TO_POINTER(MSIM_CLIENT_VERSION),
- "msg", MSIM_TYPE_STRING, g_strdup(text),
- NULL);
-
- rc = msim_postprocess_outgoing(session, msg, who, "t", "cv");
-
- msim_msg_free(msg);
-
- return rc;
-}
-
-/**
- * Lookup a username by userid, from buddy list.
- *
- * @param wanted_uid
- *
- * @return Username of wanted_uid, if on blist, or NULL.
- * This is a static string, so don't free it. Copy it if needed.
- *
- */
-static const gchar *
-msim_uid2username_from_blist(PurpleAccount *account, guint wanted_uid)
-{
- GSList *buddies, *cur;
- const gchar *ret;
-
- buddies = purple_find_buddies(account, NULL);
-
- if (!buddies)
- {
- purple_debug_info("msim", "msim_uid2username_from_blist: no buddies?\n");
- return NULL;
- }
-
- ret = NULL;
-
- for (cur = buddies; cur != NULL; cur = g_slist_next(cur))
- {
- PurpleBuddy *buddy;
- guint uid;
- const gchar *name;
-
- /* See finch/gnthistory.c */
- buddy = cur->data;
-
- uid = purple_blist_node_get_int(PURPLE_BLIST_NODE(buddy), "UserID");
- name = purple_buddy_get_name(buddy);
-
- if (uid == wanted_uid)
- {
- ret = name;
- break;
- }
- }
-
- g_slist_free(buddies);
- return ret;
-}
-
-/**
- * Setup a callback, to be called when a reply is received with the returned rid.
- *
- * @param cb The callback, an MSIM_USER_LOOKUP_CB.
- * @param data Arbitrary user data to be passed to callback (probably an MsimMessage *).
- *
- * @return The request/reply ID, used to link replies with requests, or -1.
- * Put the rid in your request, 'rid' field.
- *
- * TODO: Make more generic and more specific:
- * 1) MSIM_USER_LOOKUP_CB - make it for PERSIST_REPLY, not just user lookup
- * 2) data - make it an MsimMessage?
- */
-guint
-msim_new_reply_callback(MsimSession *session, MSIM_USER_LOOKUP_CB cb,
- gpointer data)
-{
- guint rid;
-
- rid = session->next_rid++;
-
- g_hash_table_insert(session->user_lookup_cb, GUINT_TO_POINTER(rid), cb);
- g_hash_table_insert(session->user_lookup_cb_data, GUINT_TO_POINTER(rid), data);
-
- return rid;
-}
-
-/**
- * Return the icon name for a buddy and account.
- *
- * @param acct The account to find the icon for, or NULL for protocol icon.
- * @param buddy The buddy to find the icon for, or NULL for the account icon.
- *
- * @return The base icon name string.
- */
-static const gchar *
-msim_list_icon(PurpleAccount *acct, PurpleBuddy *buddy)
-{
- /* Use a MySpace icon submitted by hbons at
- * http://developer.pidgin.im/wiki/MySpaceIM. */
- return "myspace";
-}
-
-/**
- * Obtain the status text for a buddy.
- *
- * @param buddy The buddy to obtain status text for.
- *
- * @return Status text, or NULL if error. Caller g_free()'s.
- */
-static char *
-msim_status_text(PurpleBuddy *buddy)
-{
- MsimUser *user;
- const gchar *display_name = NULL, *headline = NULL;
- PurpleAccount *account;
-
- g_return_val_if_fail(buddy != NULL, NULL);
-
- account = purple_buddy_get_account(buddy);
-
- user = msim_get_user_from_buddy(buddy, FALSE);
- if (user != NULL) {
- /* Retrieve display name and/or headline, depending on user preference. */
- if (purple_account_get_bool(account, "show_headline", TRUE)) {
- headline = user->headline;
- }
-
- if (purple_account_get_bool(account, "show_display_name", FALSE)) {
- display_name = user->display_name;
- }
- }
-
- /* Return appropriate combination of display name and/or headline, or neither. */
-
- if (display_name && headline) {
- return g_strconcat(display_name, " ", headline, NULL);
- } else if (display_name) {
- return g_strdup(display_name);
- } else if (headline) {
- return g_strdup(headline);
- }
-
- return NULL;
-}
-
-/**
- * Obtain the tooltip text for a buddy.
- *
- * @param buddy Buddy to obtain tooltip text on.
- * @param user_info Variable modified to have the tooltip text.
- * @param full TRUE if should obtain full tooltip text.
- */
-static void
-msim_tooltip_text(PurpleBuddy *buddy, PurpleNotifyUserInfo *user_info,
- gboolean full)
-{
- MsimUser *user;
-
- g_return_if_fail(buddy != NULL);
- g_return_if_fail(user_info != NULL);
-
- user = msim_get_user_from_buddy(buddy, TRUE);
-
- if (PURPLE_BUDDY_IS_ONLINE(buddy)) {
- MsimSession *session;
- PurpleAccount *account = purple_buddy_get_account(buddy);
- PurpleConnection *gc = purple_account_get_connection(account);
-
- session = (MsimSession *)gc->proto_data;
-
- /* TODO: if (full), do something different? */
-
- /* TODO: request information? have to figure out how to do
- * the asynchronous lookup like oscar does (tooltip shows
- * 'retrieving...' if not yet available, then changes when it is).
- *
- * Right now, only show what we have on hand.
- */
-
- /* Show abbreviated user info. */
- msim_append_user_info(session, user_info, user, FALSE);
- }
-}
-
-/**
- * Get possible user status types. Based on mockprpl.
- *
- * @return GList of status types.
- */
-static GList *
-msim_status_types(PurpleAccount *acct)
-{
- GList *types;
- PurpleStatusType *status;
-
- purple_debug_info("myspace", "returning status types\n");
-
- types = NULL;
-
- /* Statuses are almost all the same. Define a macro to reduce code repetition. */
-#define _MSIM_ADD_NEW_STATUS(prim) status = \
- purple_status_type_new_with_attrs( \
- prim, /* PurpleStatusPrimitive */ \
- NULL, /* id - use default */ \
- NULL, /* name - use default */ \
- TRUE, /* saveable */ \
- TRUE, /* user_settable */ \
- FALSE, /* not independent */ \
- \
- /* Attributes - each status can have a message. */ \
- "message", \
- _("Message"), \
- purple_value_new(PURPLE_TYPE_STRING), \
- NULL); \
- \
- \
- types = g_list_append(types, status)
-
-
- _MSIM_ADD_NEW_STATUS(PURPLE_STATUS_AVAILABLE);
- _MSIM_ADD_NEW_STATUS(PURPLE_STATUS_AWAY);
- _MSIM_ADD_NEW_STATUS(PURPLE_STATUS_OFFLINE);
- _MSIM_ADD_NEW_STATUS(PURPLE_STATUS_INVISIBLE);
-
- /* Except tune status is different... */
- status = purple_status_type_new_with_attrs(
- PURPLE_STATUS_TUNE, /* primitive */
- "tune", /* ID */
- NULL, /* name - use default */
- FALSE, /* saveable */
- TRUE, /* should be user_settable some day */
- TRUE, /* independent */
-
- PURPLE_TUNE_ARTIST, _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING),
- PURPLE_TUNE_TITLE, _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING),
- NULL);
-
- types = g_list_append(types, status);
-
- return types;
-}
-
-/*
- * TODO: This define is stolen from oscar.h.
- * It's also in yahoo.h.
- * It should be in libpurple/util.c
- */
-#define msim_put32(buf, data) ( \
- (*((buf)) = (unsigned char)((data)>>24)&0xff), \
- (*((buf)+1) = (unsigned char)((data)>>16)&0xff), \
- (*((buf)+2) = (unsigned char)((data)>>8)&0xff), \
- (*((buf)+3) = (unsigned char)(data)&0xff), \
- 4)
-
-/**
- * Compute the base64'd login challenge response based on username, password, nonce, and IPs.
- *
- * @param nonce The base64 encoded nonce ('nc') field from the server.
- * @param email User's email address (used as login name).
- * @param password User's cleartext password.
- * @param response_len Will be written with response length.
- *
- * @return Binary login challenge response, ready to send to the server.
- * Must be g_free()'d when finished. NULL if error.
- */
-static gchar *
-msim_compute_login_response(const gchar nonce[2 * NONCE_SIZE],
- const gchar *email, const gchar *password, guint *response_len)
-{
- PurpleCipherContext *key_context;
- PurpleCipher *sha1;
- PurpleCipherContext *rc4;
-
- guchar hash_pw[HASH_SIZE];
- guchar key[HASH_SIZE];
- gchar *password_truncated, *password_utf16le, *password_utf8_lc;
- GString *data;
- guchar *data_out;
- size_t data_out_len;
- gsize conv_bytes_read, conv_bytes_written;
- GError *conv_error;
-#ifdef MSIM_DEBUG_LOGIN_CHALLENGE
- int i;
-#endif
-
- g_return_val_if_fail(nonce != NULL, NULL);
- g_return_val_if_fail(email != NULL, NULL);
- g_return_val_if_fail(password != NULL, NULL);
- g_return_val_if_fail(response_len != NULL, NULL);
-
- /*
- * Truncate password to 10 characters. Their "change password"
- * web page doesn't let you enter more than 10 characters, but you
- * can enter more than 10 when logging in on myspace.com and they
- * truncate it.
- */
- password_truncated = g_strndup(password, 10);
-
- /* Convert password to lowercase (required for passwords containing
- * uppercase characters). MySpace passwords are lowercase,
- * see ticket #2066. */
- password_utf8_lc = g_utf8_strdown(password_truncated, -1);
- g_free(password_truncated);
-
- /* Convert ASCII password to UTF16 little endian */
- purple_debug_info("msim", "converting password to UTF-16LE\n");
- conv_error = NULL;
- password_utf16le = g_convert(password_utf8_lc, -1, "UTF-16LE", "UTF-8",
- &conv_bytes_read, &conv_bytes_written, &conv_error);
- g_free(password_utf8_lc);
-
- if (conv_error != NULL) {
- purple_debug_error("msim",
- "g_convert password UTF8->UTF16LE failed: %s",
- conv_error->message);
- g_error_free(conv_error);
- return NULL;
- }
-
- /* Compute password hash */
- purple_cipher_digest_region("sha1", (guchar *)password_utf16le,
- conv_bytes_written, sizeof(hash_pw), hash_pw, NULL);
- g_free(password_utf16le);
-
-#ifdef MSIM_DEBUG_LOGIN_CHALLENGE
- purple_debug_info("msim", "pwhash = ");
- for (i = 0; i < sizeof(hash_pw); i++)
- purple_debug_info("msim", "%.2x ", hash_pw[i]);
- purple_debug_info("msim", "\n");
-#endif
-
- /* key = sha1(sha1(pw) + nonce2) */
- sha1 = purple_ciphers_find_cipher("sha1");
- key_context = purple_cipher_context_new(sha1, NULL);
- purple_cipher_context_append(key_context, hash_pw, HASH_SIZE);
- purple_cipher_context_append(key_context, (guchar *)(nonce + NONCE_SIZE), NONCE_SIZE);
- purple_cipher_context_digest(key_context, sizeof(key), key, NULL);
- purple_cipher_context_destroy(key_context);
-
-#ifdef MSIM_DEBUG_LOGIN_CHALLENGE
- purple_debug_info("msim", "key = ");
- for (i = 0; i < sizeof(key); i++) {
- purple_debug_info("msim", "%.2x ", key[i]);
- }
- purple_debug_info("msim", "\n");
-#endif
-
- rc4 = purple_cipher_context_new_by_name("rc4", NULL);
-
- /* Note: 'key' variable is 0x14 bytes (from SHA-1 hash),
- * but only first 0x10 used for the RC4 key. */
- purple_cipher_context_set_option(rc4, "key_len", (gpointer)0x10);
- purple_cipher_context_set_key(rc4, key);
-
- /* rc4 encrypt:
- * nonce1+email+IP list */
-
- data = g_string_new(NULL);
- g_string_append_len(data, nonce, NONCE_SIZE);
-
- /* Include the null terminator */
- g_string_append_len(data, email, strlen(email) + 1);
-
- while (data->len % 4 != 0)
- g_string_append_c(data, 0xfb);
-
-#ifdef SEND_OUR_IP_ADDRESSES
- /* TODO: Obtain IPs of network interfaces instead of using this hardcoded value */
- g_string_set_size(data, data->len + 4);
- (void)msim_put32(data->str + data->len - 4, MSIM_LOGIN_IP_LIST_LEN);
- g_string_append_len(data, MSIM_LOGIN_IP_LIST, MSIM_LOGIN_IP_LIST_LEN);
-#else
- g_string_set_size(data, data->len + 4);
- (void)msim_put32(data->str + data->len - 4, 0);
-#endif /* !SEND_OUR_IP_ADDRESSES */
-
- data_out = g_new0(guchar, data->len);
-
- purple_cipher_context_encrypt(rc4, (const guchar *)data->str,
- data->len, data_out, &data_out_len);
- purple_cipher_context_destroy(rc4);
-
- if (data_out_len != data->len) {
- purple_debug_info("msim", "msim_compute_login_response: "
- "data length mismatch: %" G_GSIZE_FORMAT " != %"
- G_GSIZE_FORMAT "\n", data_out_len, data->len);
- }
-
- g_string_free(data, TRUE);
-
-#ifdef MSIM_DEBUG_LOGIN_CHALLENGE
- purple_debug_info("msim", "response=<%s>\n", data_out);
-#endif
-
- *response_len = data_out_len;
-
- return (gchar *)data_out;
-}
-
-/**
- * Process a login challenge, sending a response.
- *
- * @param session
- * @param msg Login challenge message.
- *
- * @return TRUE if successful, FALSE if not
- */
-static gboolean
-msim_login_challenge(MsimSession *session, MsimMessage *msg)
-{
- PurpleAccount *account;
- gchar *response;
- guint response_len;
- gchar *nc;
- gsize nc_len;
- gboolean ret;
-
- g_return_val_if_fail(msg != NULL, FALSE);
-
- g_return_val_if_fail(msim_msg_get_binary(msg, "nc", &nc, &nc_len), FALSE);
-
- account = session->account;
-
- g_return_val_if_fail(account != NULL, FALSE);
-
- purple_connection_update_progress(session->gc, _("Reading challenge"), 1, 4);
-
- purple_debug_info("msim", "nc is %" G_GSIZE_FORMAT
- " bytes, decoded\n", nc_len);
-
- if (nc_len != MSIM_AUTH_CHALLENGE_LENGTH) {
- purple_debug_info("msim", "bad nc length: %" G_GSIZE_MODIFIER
- "x != 0x%x\n", nc_len, MSIM_AUTH_CHALLENGE_LENGTH);
- purple_connection_error_reason (session->gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- _("Unexpected challenge length from server"));
- return FALSE;
- }
-
- purple_connection_update_progress(session->gc, _("Logging in"), 2, 4);
-
- response_len = 0;
- response = msim_compute_login_response(nc, account->username, account->password, &response_len);
-
- g_free(nc);
-
- ret = msim_send(session,
- "login2", MSIM_TYPE_INTEGER, MSIM_AUTH_ALGORITHM,
- /* This is actually user's email address. */
- "username", MSIM_TYPE_STRING, g_strdup(account->username),
- /* GString will be freed in msim_msg_free() in msim_send(). */
- "response", MSIM_TYPE_BINARY, g_string_new_len(response, response_len),
- "clientver", MSIM_TYPE_INTEGER, MSIM_CLIENT_VERSION,
- "langid", MSIM_TYPE_INTEGER, MSIM_LANGUAGE_ID_ENGLISH,
- "imlang", MSIM_TYPE_STRING, g_strdup(MSIM_LANGUAGE_NAME_ENGLISH),
- "reconn", MSIM_TYPE_INTEGER, 0,
- "status", MSIM_TYPE_INTEGER, 100,
- "id", MSIM_TYPE_INTEGER, 1,
- NULL);
-
- g_free(response);
-
- return ret;
-}
-
-/**
- * Process unrecognized information.
- *
- * @param session
- * @param msg An MsimMessage that was unrecognized, or NULL.
- * @param note Information on what was unrecognized, or NULL.
- */
-void
-msim_unrecognized(MsimSession *session, MsimMessage *msg, gchar *note)
-{
- /* TODO: Some more context, outwardly equivalent to a backtrace,
- * for helping figure out what this msg is for. What was going on?
- * But not too much information so that a user
- * posting this dump reveals confidential information.
- */
-
- /* TODO: dump unknown msgs to file, so user can send them to me
- * if they wish, to help add support for new messages (inspired
- * by Alexandr Shutko, who maintains OSCAR protocol documentation).
- *
- * Filed enhancement ticket for libpurple as #4688.
- */
-
- purple_debug_info("msim", "Unrecognized data on account for %s\n",
- (session && session->account && session->account->username) ?
- session->account->username : "(NULL)");
- if (note) {
- purple_debug_info("msim", "(Note: %s)\n", note);
- }
-
- if (msg) {
- msim_msg_dump("Unrecognized message dump: %s\n", msg);
- }
-}
-
-/** Called when the session key arrives to check whether the user
- * has a username, and set one if desired. */
-static gboolean
-msim_is_username_set(MsimSession *session, MsimMessage *msg)
-{
- g_return_val_if_fail(msg != NULL, FALSE);
- g_return_val_if_fail(session->gc != NULL, FALSE);
-
- session->sesskey = msim_msg_get_integer(msg, "sesskey");
- purple_debug_info("msim", "SESSKEY=<%d>\n", session->sesskey);
-
- /* What is proof? Used to be uid, but now is 52 base64'd bytes... */
-
- /* Comes with: proof,profileid,userid,uniquenick -- all same values
- * some of the time, but can vary. This is our own user ID. */
- session->userid = msim_msg_get_integer(msg, "userid");
-
- /* Save uid to account so this account can be looked up by uid. */
- purple_account_set_int(session->account, "uid", session->userid);
-
- /* Not sure what profileid is used for. */
- if (msim_msg_get_integer(msg, "profileid") != session->userid) {
- msim_unrecognized(session, msg,
- "Profile ID didn't match user ID, don't know why");
- }
-
- /* We now know are our own username, only after we're logged in..
- * which is weird, but happens because you login with your email
- * address and not username. Will be freed in msim_session_destroy(). */
- session->username = msim_msg_get_string(msg, "uniquenick");
-
- /* If user lacks a username, help them get one. */
- if (msim_msg_get_integer(msg, "uniquenick") == session->userid) {
- purple_debug_info("msim_is_username_set", "no username is set\n");
- purple_request_yes_no(session->gc,
- _("MySpaceIM - No Username Set"),
- _("You appear to have no MySpace username."),
- _("Would you like to set one now? (Note: THIS CANNOT BE CHANGED!)"),
- 0,
- session->account,
- NULL,
- NULL,
- session->gc,
- G_CALLBACK(msim_set_username_cb),
- G_CALLBACK(msim_do_not_set_username_cb));
- purple_debug_info("msim_is_username_set","'username not set' alert prompted\n");
- return FALSE;
- }
- return TRUE;
-}
-
-#ifdef MSIM_USE_KEEPALIVE
-/**
- * Check if the connection is still alive, based on last communication.
- */
-static gboolean
-msim_check_alive(gpointer data)
-{
- MsimSession *session;
- time_t delta;
-
- session = (MsimSession *)data;
-
- delta = time(NULL) - session->last_comm;
-
- /* purple_debug_info("msim", "msim_check_alive: delta=%d\n", delta); */
- if (delta >= MSIM_KEEPALIVE_INTERVAL) {
- purple_debug_info("msim",
- "msim_check_alive: %zu > interval of %d, presumed dead\n",
- delta, MSIM_KEEPALIVE_INTERVAL);
- purple_connection_error_reason(session->gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- _("Lost connection with server"));
-
- return FALSE;
- }
-
- return TRUE;
-}
-#endif
-
-/**
- * Handle mail reply checks.
- */
-static void
-msim_check_inbox_cb(MsimSession *session, const MsimMessage *reply, gpointer data)
-{
- MsimMessage *body;
- guint i, n;
- /* Information for each new inbox message type. */
- static struct
- {
- const gchar *key;
- guint bit;
- const gchar *url;
- const gchar *text;
- } message_types[] = {
- { "Mail", MSIM_INBOX_MAIL, "http://messaging.myspace.com/index.cfm?fuseaction=mail.inbox", NULL },
- { "BlogComment", MSIM_INBOX_BLOG_COMMENT, "http://blog.myspace.com/index.cfm?fuseaction=blog", NULL },
- { "ProfileComment", MSIM_INBOX_PROFILE_COMMENT, "http://home.myspace.com/index.cfm?fuseaction=user", NULL },
- { "FriendRequest", MSIM_INBOX_FRIEND_REQUEST, "http://messaging.myspace.com/index.cfm?fuseaction=mail.friendRequests", NULL },
- { "PictureComment", MSIM_INBOX_PICTURE_COMMENT, "http://home.myspace.com/index.cfm?fuseaction=user", NULL }
- };
- const gchar *froms[G_N_ELEMENTS(message_types) + 1] = { "" },
- *tos[G_N_ELEMENTS(message_types) + 1] = { "" },
- *urls[G_N_ELEMENTS(message_types) + 1] = { "" },
- *subjects[G_N_ELEMENTS(message_types) + 1] = { "" };
-
- g_return_if_fail(reply != NULL);
-
- /* Can't write _()'d strings in array initializers. Workaround. */
- /* khc: then use N_() in the array initializer and use _() when they are
- used */
- message_types[0].text = _("New mail messages");
- message_types[1].text = _("New blog comments");
- message_types[2].text = _("New profile comments");
- message_types[3].text = _("New friend requests!");
- message_types[4].text = _("New picture comments");
-
- body = msim_msg_get_dictionary(reply, "body");
-
- if (body == NULL)
- return;
-
- n = 0;
-
- for (i = 0; i < G_N_ELEMENTS(message_types); ++i) {
- const gchar *key;
- guint bit;
-
- key = message_types[i].key;
- bit = message_types[i].bit;
-
- if (msim_msg_get(body, key)) {
- /* Notify only on when _changes_ from no mail -> has mail
- * (edge triggered) */
- if (!(session->inbox_status & bit)) {
- purple_debug_info("msim", "msim_check_inbox_cb: got %s, at %d\n",
- key ? key : "(NULL)", n);
-
- subjects[n] = message_types[i].text;
- froms[n] = _("MySpace");
- tos[n] = session->username;
- /* TODO: append token, web challenge, so automatically logs in.
- * Would also need to free strings because they won't be static
- */
- urls[n] = message_types[i].url;
-
- ++n;
- } else {
- purple_debug_info("msim",
- "msim_check_inbox_cb: already notified of %s\n",
- key ? key : "(NULL)");
- }
-
- session->inbox_status |= bit;
- }
- }
-
- if (n) {
- purple_debug_info("msim",
- "msim_check_inbox_cb: notifying of %d\n", n);
-
- /* TODO: free strings with callback _if_ change to dynamic (w/ token) */
- purple_notify_emails(session->gc, /* handle */
- n, /* count */
- TRUE, /* detailed */
- subjects, froms, tos, urls,
- NULL, /* PurpleNotifyCloseCallback cb */
- NULL); /* gpointer user_data */
-
- }
-
- msim_msg_free(body);
-}
-
-/**
- * Send request to check if there is new mail.
- */
-static gboolean
-msim_check_inbox(gpointer data)
-{
- MsimSession *session;
-
- session = (MsimSession *)data;
-
- purple_debug_info("msim", "msim_check_inbox: checking mail\n");
- g_return_val_if_fail(msim_send(session,
- "persist", MSIM_TYPE_INTEGER, 1,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_GET,
- "dsn", MSIM_TYPE_INTEGER, MG_CHECK_MAIL_DSN,
- "lid", MSIM_TYPE_INTEGER, MG_CHECK_MAIL_LID,
- "uid", MSIM_TYPE_INTEGER, session->userid,
- "rid", MSIM_TYPE_INTEGER,
- msim_new_reply_callback(session, msim_check_inbox_cb, NULL),
- "body", MSIM_TYPE_STRING, g_strdup(""),
- NULL), TRUE);
-
- /* Always return true, so that we keep checking for mail. */
- return TRUE;
-}
-
-/**
- * Add contact from server to buddy list, after looking up username.
- * Callback from msim_add_contact_from_server().
- *
- * @param data An MsimMessage * of the contact information. Will be freed.
- */
-static void
-msim_add_contact_from_server_cb(MsimSession *session, const MsimMessage *user_lookup_info, gpointer data)
-{
- MsimMessage *contact_info, *user_lookup_info_body;
- PurpleGroup *group;
- PurpleBuddy *buddy;
- MsimUser *user;
- gchar *username, *group_name, *display_name;
- guint uid, visibility;
-
- contact_info = (MsimMessage *)data;
- purple_debug_info("msim_add_contact_from_server_cb", "contact_info addr=%p\n", contact_info);
- uid = msim_msg_get_integer(contact_info, "ContactID");
-
- if (!user_lookup_info) {
- username = g_strdup(msim_uid2username_from_blist(session->account, uid));
- display_name = NULL;
- g_return_if_fail(username != NULL);
- } else {
- user_lookup_info_body = msim_msg_get_dictionary(user_lookup_info, "body");
- username = msim_msg_get_string(user_lookup_info_body, "UserName");
- display_name = msim_msg_get_string(user_lookup_info_body, "DisplayName");
- msim_msg_free(user_lookup_info_body);
- g_return_if_fail(username != NULL);
- }
-
- purple_debug_info("msim_add_contact_from_server_cb",
- "*** about to add/update username=%s\n", username);
-
- /* 1. Creates a new group, or gets existing group if it exists (or so
- * the documentation claims). */
- group_name = msim_msg_get_string(contact_info, "GroupName");
- if (!group_name || (*group_name == '\0')) {
- g_free(group_name);
- group_name = g_strdup(_("IM Friends"));
- purple_debug_info("myspace", "No GroupName specified, defaulting to '%s'.\n", group_name);
- }
- group = purple_find_group(group_name);
- if (!group) {
- group = purple_group_new(group_name);
- /* Add group to beginning. See #2752. */
- purple_blist_add_group(group, NULL);
- }
- g_free(group_name);
-
- visibility = msim_msg_get_integer(contact_info, "Visibility");
- if (visibility == 2) {
- /* This buddy is blocked (and therefore not on our buddy list */
- purple_privacy_deny_add(session->account, username, TRUE);
- msim_msg_free(contact_info);
- g_free(username);
- g_free(display_name);
- return;
- }
-
- /* 2. Get or create buddy */
- buddy = purple_find_buddy(session->account, username);
- if (!buddy) {
- purple_debug_info("msim_add_contact_from_server_cb",
- "creating new buddy: %s\n", username);
- buddy = purple_buddy_new(session->account, username, NULL);
- }
-
- /* TODO: use 'Position' in contact_info to take into account where buddy is */
- purple_blist_add_buddy(buddy, NULL, group, NULL /* insertion point */);
-
- if (strtoul(username, NULL, 10) == uid) {
- /*
- * This user has not set their username! Set their server
- * alias to their display name so that we don't see a bunch
- * of numbers in the buddy list.
- */
- if (display_name != NULL) {
- purple_blist_node_set_string(PURPLE_BLIST_NODE(buddy), "DisplayName", display_name);
- serv_got_alias(session->gc, username, display_name);
- } else {
- serv_got_alias(session->gc, username,
- purple_blist_node_get_string(PURPLE_BLIST_NODE(buddy), "DisplayName"));
- }
- }
- g_free(display_name);
-
- /* 3. Update buddy information */
- user = msim_get_user_from_buddy(buddy, TRUE);
-
- user->id = uid;
- /* Keep track of the user ID across sessions */
- purple_blist_node_set_int(PURPLE_BLIST_NODE(buddy), "UserID", uid);
-
- /* Stores a few fields in the MsimUser, relevant to the buddy itself.
- * AvatarURL, Headline, ContactID. */
- msim_store_user_info(session, contact_info, NULL);
-
- /* TODO: other fields, store in 'user' */
- msim_msg_free(contact_info);
-
- g_free(username);
-}
-
-/**
- * Add first ContactID in contact_info to buddy's list. Used to add
- * server-side buddies to client-side list.
- *
- * @return TRUE if added.
- */
-static gboolean
-msim_add_contact_from_server(MsimSession *session, MsimMessage *contact_info)
-{
- guint uid;
- const gchar *username;
-
- uid = msim_msg_get_integer(contact_info, "ContactID");
- g_return_val_if_fail(uid != 0, FALSE);
-
- /* Lookup the username, since NickName and IMName is unreliable */
- username = msim_uid2username_from_blist(session->account, uid);
- if (!username) {
- gchar *uid_str;
-
- uid_str = g_strdup_printf("%d", uid);
- purple_debug_info("msim_add_contact_from_server",
- "contact_info addr=%p\n", contact_info);
- msim_lookup_user(session, uid_str, msim_add_contact_from_server_cb, (gpointer)msim_msg_clone(contact_info));
- g_free(uid_str);
- } else {
- msim_add_contact_from_server_cb(session, NULL, (gpointer)msim_msg_clone(contact_info));
- }
-
- /* Say that the contact was added, even if we're still looking up
- * their username. */
- return TRUE;
-}
-
-/**
- * Called when contact list is received from server.
- */
-static void
-msim_got_contact_list(MsimSession *session, const MsimMessage *reply, gpointer user_data)
-{
- MsimMessage *body, *body_node;
- gchar *msg;
- guint buddy_count;
-
- body = msim_msg_get_dictionary(reply, "body");
-
- buddy_count = 0;
-
- for (body_node = body;
- body_node != NULL;
- body_node = msim_msg_get_next_element_node(body_node))
- {
- MsimMessageElement *elem;
-
- elem = (MsimMessageElement *)body_node->data;
-
- if (g_str_equal(elem->name, "ContactID"))
- {
- /* Will look for first contact in body_node */
- if (msim_add_contact_from_server(session, body_node)) {
- ++buddy_count;
- }
- }
- }
-
- switch (GPOINTER_TO_UINT(user_data)) {
- case MSIM_CONTACT_LIST_IMPORT_ALL_FRIENDS:
- msg = g_strdup_printf(ngettext("%d buddy was added or updated from the server (including buddies already on the server-side list)",
- "%d buddies were added or updated from the server (including buddies already on the server-side list)",
- buddy_count),
- buddy_count);
- purple_notify_info(session->account, _("Add contacts from server"), msg, NULL);
- g_free(msg);
- break;
-
- case MSIM_CONTACT_LIST_IMPORT_TOP_FRIENDS:
- /* TODO */
- break;
-
- case MSIM_CONTACT_LIST_INITIAL_FRIENDS:
- /* The session is now set up, ready to be connected. This emits the
- * signedOn signal, so clients can now do anything with msimprpl, and
- * we're ready for it (session key, userid, username all setup). */
- purple_connection_update_progress(session->gc, _("Connected"), 3, 4);
- purple_connection_set_state(session->gc, PURPLE_CONNECTED);
- break;
- }
-
- msim_msg_free(body);
-}
-
-/**
- * Get contact list, calling msim_got_contact_list() with
- * what_to_do_after as user_data gpointer.
- *
- * @param what_to_do_after should be one of the MSIM_CONTACT_LIST_* #defines.
- */
-static gboolean
-msim_get_contact_list(MsimSession *session, int what_to_do_after)
-{
- return msim_send(session,
- "persist", MSIM_TYPE_INTEGER, 1,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_GET,
- "dsn", MSIM_TYPE_INTEGER, MG_LIST_ALL_CONTACTS_DSN,
- "lid", MSIM_TYPE_INTEGER, MG_LIST_ALL_CONTACTS_LID,
- "uid", MSIM_TYPE_INTEGER, session->userid,
- "rid", MSIM_TYPE_INTEGER,
- msim_new_reply_callback(session, msim_got_contact_list, GUINT_TO_POINTER(what_to_do_after)),
- "body", MSIM_TYPE_STRING, g_strdup(""),
- NULL);
-}
-
-/** Called after username is set, if necessary and we're open for business. */
-gboolean msim_we_are_logged_on(MsimSession *session)
-{
- MsimMessage *body;
-
- /* Set display name to username (otherwise will show email address) */
- purple_connection_set_display_name(session->gc, session->username);
-
- body = msim_msg_new(
- "UserID", MSIM_TYPE_INTEGER, session->userid,
- NULL);
-
- /* Request IM info about ourself. */
- msim_send(session,
- "persist", MSIM_TYPE_INTEGER, 1,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_GET,
- "dsn", MSIM_TYPE_INTEGER, MG_OWN_MYSPACE_INFO_DSN,
- "lid", MSIM_TYPE_INTEGER, MG_OWN_MYSPACE_INFO_LID,
- "rid", MSIM_TYPE_INTEGER, session->next_rid++,
- "UserID", MSIM_TYPE_INTEGER, session->userid,
- "body", MSIM_TYPE_DICTIONARY, body,
- NULL);
-
- /* Request MySpace info about ourself. */
- msim_send(session,
- "persist", MSIM_TYPE_INTEGER, 1,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_GET,
- "dsn", MSIM_TYPE_INTEGER, MG_OWN_IM_INFO_DSN,
- "lid", MSIM_TYPE_INTEGER, MG_OWN_IM_INFO_LID,
- "rid", MSIM_TYPE_INTEGER, session->next_rid++,
- "body", MSIM_TYPE_STRING, g_strdup(""),
- NULL);
-
- /* TODO: set options (persist cmd=514,dsn=1,lid=10) */
- /* TODO: set blocklist */
-
- /* Notify servers of our current status. */
- purple_debug_info("msim", "msim_we_are_logged_on: notifying servers of status\n");
- msim_set_status(session->account,
- purple_account_get_active_status(session->account));
-
- /* TODO: setinfo */
- /*
- body = msim_msg_new(
- "TotalFriends", MSIM_TYPE_INTEGER, 666,
- NULL);
- msim_send(session,
- "setinfo", MSIM_TYPE_BOOLEAN, TRUE,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "info", MSIM_TYPE_DICTIONARY, body,
- NULL);
- */
-
- /* Disable due to problems with timeouts. TODO: fix. */
-#ifdef MSIM_USE_KEEPALIVE
- purple_timeout_add_seconds(MSIM_KEEPALIVE_INTERVAL_CHECK,
- (GSourceFunc)msim_check_alive, session);
-#endif
-
- /* Check mail if they want to. */
- if (purple_account_get_check_mail(session->account)) {
- session->inbox_handle = purple_timeout_add(MSIM_MAIL_INTERVAL_CHECK,
- (GSourceFunc)msim_check_inbox, session);
- msim_check_inbox(session);
- }
-
- msim_get_contact_list(session, MSIM_CONTACT_LIST_INITIAL_FRIENDS);
-
- return TRUE;
-}
-
-/**
- * Record the client version in the buddy list, from an incoming message.
- */
-static gboolean
-msim_incoming_bm_record_cv(MsimSession *session, MsimMessage *msg)
-{
- gchar *username, *cv;
- gboolean ret;
- MsimUser *user;
-
- username = msim_msg_get_string(msg, "_username");
- cv = msim_msg_get_string(msg, "cv");
-
- g_return_val_if_fail(username != NULL, FALSE);
- if (!cv) {
- /* No client version to record, don't worry about it. */
- g_free(username);
- return FALSE;
- }
-
- user = msim_find_user(session, username);
-
- if (user) {
- user->client_cv = atol(cv);
- ret = TRUE;
- } else {
- ret = FALSE;
- }
-
- g_free(username);
- g_free(cv);
-
- return ret;
-}
-
-#ifdef MSIM_SEND_CLIENT_VERSION
-/**
- * Send our client version to another unofficial client that understands it.
- */
-static gboolean
-msim_send_unofficial_client(MsimSession *session, gchar *username)
-{
- gchar *our_info;
- gboolean ret;
-
- our_info = g_strdup_printf("Libpurple %d.%d.%d - msimprpl %s",
- PURPLE_MAJOR_VERSION,
- PURPLE_MINOR_VERSION,
- PURPLE_MICRO_VERSION,
- MSIM_PRPL_VERSION_STRING);
-
- ret = msim_send_bm(session, username, our_info, MSIM_BM_UNOFFICIAL_CLIENT);
-
- return ret;
-}
-#endif
-/**
- * Process incoming status mood messages.
- *
- * @param session
- * @param msg Status mood update message. Caller frees.
- *
- * @return TRUE if successful.
- */
-static gboolean
-msim_incoming_status_mood(MsimSession *session, MsimMessage *msg) {
- /* TODO: I dont know too much about this yet,
- * so until I see how the official client handles
- * this and decide if libpurple should as well,
- * well just say we used it
- */
- gchar *ss;
- ss = msim_msg_get_string(msg, "msg");
- purple_debug_info("msim", "Incoming Status Message: %s", ss ? ss : "(NULL)");
- g_free(ss);
- return TRUE;
-}
-
-/**
- * Process incoming status messages.
- *
- * @param session
- * @param msg Status update message. Caller frees.
- *
- * @return TRUE if successful.
- */
-static gboolean
-msim_incoming_status(MsimSession *session, MsimMessage *msg)
-{
- MsimUser *user;
- GList *list;
- gchar *status_headline, *status_headline_escaped;
- gint status_code, purple_status_code;
- gchar *username;
- gchar *unrecognized_msg;
-
- g_return_val_if_fail(msg != NULL, FALSE);
-
- /* Helpfully looked up by msim_incoming_resolve() for us. */
- username = msim_msg_get_string(msg, "_username");
- g_return_val_if_fail(username != NULL, FALSE);
-
- {
- gchar *ss;
-
- ss = msim_msg_get_string(msg, "msg");
- purple_debug_info("msim",
- "msim_status: updating status for <%s> to <%s>\n",
- username, ss ? ss : "(NULL)");
- g_free(ss);
- }
-
- /* Example fields:
- * |s|0|ss|Offline
- * |s|1|ss|:-)|ls||ip|0|p|0
- */
- list = msim_msg_get_list(msg, "msg");
-
- status_code = msim_msg_get_integer_from_element(g_list_nth_data(list, MSIM_STATUS_ORDINAL_ONLINE));
- purple_debug_info("msim", "msim_status: %s's status code = %d\n", username, status_code);
- status_headline = msim_msg_get_string_from_element(g_list_nth_data(list, MSIM_STATUS_ORDINAL_HEADLINE));
-
- /* Add buddy if not found.
- * TODO: Could this be responsible for #3444? */
- user = msim_find_user(session, username);
- if (!user) {
- PurpleBuddy *buddy;
-
- purple_debug_info("msim",
- "msim_status: making new buddy for %s\n", username);
- buddy = purple_buddy_new(session->account, username, NULL);
- purple_blist_add_buddy(buddy, NULL, NULL, NULL);
-
- user = msim_get_user_from_buddy(buddy, TRUE);
- user->id = msim_msg_get_integer(msg, "f");
-
- /* Keep track of the user ID across sessions */
- purple_blist_node_set_int(PURPLE_BLIST_NODE(buddy), "UserID", user->id);
-
- msim_store_user_info(session, msg, NULL);
- } else {
- purple_debug_info("msim", "msim_status: found buddy %s\n", username);
- }
-
- if (status_headline && strcmp(status_headline, "") != 0) {
- /* The status headline is plaintext, but libpurple treats it as HTML,
- * so escape any HTML characters to their entity equivalents. */
- status_headline_escaped = g_markup_escape_text(status_headline, -1);
- } else {
- status_headline_escaped = NULL;
- }
-
- g_free(status_headline);
-
- /* don't copy; let the MsimUser own the headline, memory-wise */
- g_free(user->headline);
- user->headline = status_headline_escaped;
-
- /* Set user status */
- switch (status_code) {
- case MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN:
- purple_status_code = PURPLE_STATUS_OFFLINE;
- break;
-
- case MSIM_STATUS_CODE_ONLINE:
- purple_status_code = PURPLE_STATUS_AVAILABLE;
- break;
-
- case MSIM_STATUS_CODE_AWAY:
- purple_status_code = PURPLE_STATUS_AWAY;
- break;
-
- case MSIM_STATUS_CODE_IDLE:
- /* Treat idle as an available status. */
- purple_status_code = PURPLE_STATUS_AVAILABLE;
- break;
-
- default:
- purple_debug_info("msim", "msim_incoming_status for %s, unknown status code %d, treating as available\n",
- username, status_code);
- purple_status_code = PURPLE_STATUS_AVAILABLE;
-
- unrecognized_msg = g_strdup_printf("msim_incoming_status, unrecognized status code: %d\n",
- status_code);
- msim_unrecognized(session, NULL, unrecognized_msg);
- g_free(unrecognized_msg);
- }
-
- purple_prpl_got_user_status(session->account, username, purple_primitive_get_id_from_type(purple_status_code), NULL);
-
- if (status_code == MSIM_STATUS_CODE_IDLE) {
- purple_debug_info("msim", "msim_status: got idle: %s\n", username);
- purple_prpl_got_user_idle(session->account, username, TRUE, 0);
- } else {
- /* All other statuses indicate going back to non-idle. */
- purple_prpl_got_user_idle(session->account, username, FALSE, 0);
- }
-
-#ifdef MSIM_SEND_CLIENT_VERSION
- if (status_code == MSIM_STATUS_CODE_ONLINE) {
- /* Secretly whisper to unofficial clients our own version as they come online */
- msim_send_unofficial_client(session, username);
- }
-#endif
-
- if (status_code != MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN) {
- /* Get information when they come online.
- * TODO: periodically refresh?
- */
- purple_debug_info("msim_incoming_status", "%s came online, looking up\n", username);
- msim_lookup_user(session, username, NULL, NULL);
- }
-
- g_free(username);
- msim_msg_list_free(list);
-
- return TRUE;
-}
-
-/**
- * Handle an incoming instant message.
- *
- * @param session The session
- * @param msg Message from the server, containing 'f' (userid from) and 'msg'.
- * Should also contain username in _username from preprocessing.
- *
- * @return TRUE if successful.
- */
-static gboolean
-msim_incoming_im(MsimSession *session, MsimMessage *msg, const gchar *username)
-{
- gchar *msg_msim_markup, *msg_purple_markup;
- gchar *userid;
- time_t time_received;
- PurpleConversation *conv;
-
- /* I know this isn't really a string... but we need it to be one for
- * purple_find_conversation_with_account(). */
- userid = msim_msg_get_string(msg, "f");
-
- purple_debug_info("msim_incoming_im", "UserID is %s", userid);
-
- if (msim_is_userid(username)) {
- purple_debug_info("msim", "Ignoring message from spambot (%s) on account %s\n",
- username, purple_account_get_username(session->account));
- return FALSE;
- }
-
- /* See if a conversation with their UID already exists...*/
- conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, userid, session->account);
- if (conv) {
- /* Since the conversation exists... We need to normalize it */
- purple_conversation_set_name(conv, username);
- }
-
- msg_msim_markup = msim_msg_get_string(msg, "msg");
- g_return_val_if_fail(msg_msim_markup != NULL, FALSE);
-
- msg_purple_markup = msim_markup_to_html(session, msg_msim_markup);
- g_free(msg_msim_markup);
-
- time_received = msim_msg_get_integer(msg, "date");
- if (!time_received) {
- purple_debug_info("msim_incoming_im", "date in message not set.\n");
- time_received = time(NULL);
- }
-
- serv_got_im(session->gc, username, msg_purple_markup, PURPLE_MESSAGE_RECV, time_received);
-
- g_free(msg_purple_markup);
-
- return TRUE;
-}
-
-/**
- * Handle an incoming action message or an IM.
- *
- * @param session
- * @param msg
- *
- * @return TRUE if successful.
- */
-static gboolean
-msim_incoming_action_or_im(MsimSession *session, MsimMessage *msg)
-{
- gchar *msg_text, *username;
- gboolean rc;
-
- g_return_val_if_fail(msg != NULL, FALSE);
-
- msg_text = msim_msg_get_string(msg, "msg");
- g_return_val_if_fail(msg_text != NULL, FALSE);
-
- username = msim_msg_get_string(msg, "_username");
- g_return_val_if_fail(username != NULL, FALSE);
-
- purple_debug_info("msim",
- "msim_incoming_action_or_im: action <%s> from <%s>\n",
- msg_text, username);
-
- if (g_str_equal(msg_text, "%typing%")) {
- serv_got_typing(session->gc, username, 0, PURPLE_TYPING);
- rc = TRUE;
- } else if (g_str_equal(msg_text, "%stoptyping%")) {
- serv_got_typing_stopped(session->gc, username);
- rc = TRUE;
- } else if (strstr(msg_text, "!!!ZAP_SEND!!!=RTE_BTN_ZAPS_")) {
- rc = msim_incoming_zap(session, msg);
- } else if (strstr(msg_text, "!!!GroupCount=")) {
- /* TODO: support group chats. I think the number in msg_text has
- * something to do with the 'gid' field. */
- purple_debug_info("msim",
- "msim_incoming_action_or_im: "
- "TODO: implement #4691, group chats: %s\n", msg_text);
-
- rc = TRUE;
- } else if (strstr(msg_text, "!!!Offline=")) {
- /* TODO: support group chats. This one might mean a user
- * went offline or exited the chat. */
- purple_debug_info("msim", "msim_incoming_action_or_im: "
- "TODO: implement #4691, group chats: %s\n", msg_text);
-
- rc = TRUE;
- } else if (msim_msg_get_integer(msg, "aid") != 0) {
- purple_debug_info("msim", "TODO: implement #4691, group chat from %d on %d: %s\n",
- msim_msg_get_integer(msg, "aid"),
- msim_msg_get_integer(msg, "f"),
- msg_text);
-
- rc = TRUE;
- } else {
- rc = msim_incoming_im(session, msg, username);
- }
-
- g_free(msg_text);
- g_free(username);
-
- return rc;
-}
-
-/**
- * Process an incoming media (message background?) message.
- */
-static gboolean
-msim_incoming_media(MsimSession *session, MsimMessage *msg)
-{
- gchar *username, *text;
-
- username = msim_msg_get_string(msg, "_username");
- text = msim_msg_get_string(msg, "msg");
-
- g_return_val_if_fail(username != NULL, FALSE);
- g_return_val_if_fail(text != NULL, FALSE);
-
- purple_debug_info("msim", "msim_incoming_media: from %s, got msg=%s\n", username, text);
-
- /* Media messages are sent when the user opens a window to someone.
- * Tell libpurple they started typing and stopped typing, to inform the Psychic
- * Mode plugin so it too can open a window to the user. */
- serv_got_typing(session->gc, username, 0, PURPLE_TYPING);
- serv_got_typing_stopped(session->gc, username);
-
- g_free(username);
-
- return TRUE;
-}
-
-/**
- * Process an incoming "unofficial client" message. The plugin for
- * Miranda IM sends this message with the plugin information.
- */
-static gboolean
-msim_incoming_unofficial_client(MsimSession *session, MsimMessage *msg)
-{
- MsimUser *user;
- gchar *username, *client_info;
-
- username = msim_msg_get_string(msg, "_username");
- client_info = msim_msg_get_string(msg, "msg");
-
- g_return_val_if_fail(username != NULL, FALSE);
- g_return_val_if_fail(client_info != NULL, FALSE);
-
- purple_debug_info("msim", "msim_incoming_unofficial_client: %s is using client %s\n",
- username, client_info);
-
- user = msim_find_user(session, username);
-
- g_return_val_if_fail(user != NULL, FALSE);
-
- if (user->client_info) {
- g_free(user->client_info);
- }
- user->client_info = client_info;
-
- g_free(username);
- /* Do not free client_info - the MsimUser now owns it. */
-
- return TRUE;
-}
-
-/**
- * Handle an incoming buddy message.
- */
-static gboolean
-msim_incoming_bm(MsimSession *session, MsimMessage *msg)
-{
- guint bm;
-
- bm = msim_msg_get_integer(msg, "bm");
-
- msim_incoming_bm_record_cv(session, msg);
-
- switch (bm) {
- case MSIM_BM_STATUS:
- return msim_incoming_status(session, msg);
- case MSIM_BM_ACTION_OR_IM_DELAYABLE:
- case MSIM_BM_ACTION_OR_IM_INSTANT:
- return msim_incoming_action_or_im(session, msg);
- case MSIM_BM_MEDIA:
- return msim_incoming_media(session, msg);
- case MSIM_BM_UNOFFICIAL_CLIENT:
- return msim_incoming_unofficial_client(session, msg);
- case MSIM_BM_STATUS_MOOD:
- return msim_incoming_status_mood(session, msg);
- default:
- /*
- * Unknown message type! We used to call
- * msim_incoming_action_or_im(session, msg);
- * for these, but that doesn't help anything, and it means
- * we'll show broken gibberish if MySpace starts sending us
- * other message types.
- */
- purple_debug_warning("myspace", "Received unknown imcoming "
- "message, bm=%u\n", bm);
- return TRUE;
- }
-}
-
-/**
- * Process the initial server information from the server.
- */
-static gboolean
-msim_process_server_info(MsimSession *session, MsimMessage *msg)
-{
- MsimMessage *body;
-
- body = msim_msg_get_dictionary(msg, "body");
- g_return_val_if_fail(body != NULL, FALSE);
-
- /* Example body:
-AdUnitRefreshInterval=10.
-AlertPollInterval=360.
-AllowChatRoomEmoticonSharing=False.
-ChatRoomUserIDs=78744676;163733130;1300326231;123521495;142663391.
-CurClientVersion=673.
-EnableIMBrowse=True.
-EnableIMStuffAvatars=False.
-EnableIMStuffZaps=False.
-MaxAddAllFriends=100.
-MaxContacts=1000.
-MinClientVersion=594.
-MySpaceIM_ENGLISH=78744676.
-MySpaceNowTimer=720.
-PersistenceDataTimeout=900.
-UseWebChallenge=1.
-WebTicketGoHome=False
-
- Anything useful? TODO: use what is useful, and use it.
-*/
- purple_debug_info("msim_process_server_info",
- "maximum contacts: %d\n",
- msim_msg_get_integer(body, "MaxContacts"));
-
- session->server_info = body;
- /* session->server_info freed in msim_session_destroy */
-
- return TRUE;
-}
-
-/**
- * Process a web challenge, used to login to the web site.
- */
-static gboolean
-msim_web_challenge(MsimSession *session, MsimMessage *msg)
-{
- /* TODO: web challenge, store token. #2659. */
- return FALSE;
-}
-
-/**
- * Process a persistance message reply from the server.
- *
- * @param session
- * @param msg Message reply from server.
- *
- * @return TRUE if successful.
- *
- * msim_lookup_user sets callback for here
- */
-static gboolean
-msim_process_reply(MsimSession *session, MsimMessage *msg)
-{
- MSIM_USER_LOOKUP_CB cb;
- gpointer data;
- guint rid, cmd, dsn, lid;
-
- g_return_val_if_fail(msg != NULL, FALSE);
-
- msim_store_user_info(session, msg, NULL);
-
- rid = msim_msg_get_integer(msg, "rid");
- cmd = msim_msg_get_integer(msg, "cmd");
- dsn = msim_msg_get_integer(msg, "dsn");
- lid = msim_msg_get_integer(msg, "lid");
-
- /* Unsolicited messages */
- if (cmd == (guint)(MSIM_CMD_BIT_REPLY | MSIM_CMD_GET)) {
- if (dsn == (guint)MG_SERVER_INFO_DSN && lid == (guint)MG_SERVER_INFO_LID) {
- return msim_process_server_info(session, msg);
- } else if (dsn == (guint)MG_WEB_CHALLENGE_DSN && lid == (guint)MG_WEB_CHALLENGE_LID) {
- return msim_web_challenge(session, msg);
- }
- }
-
- /* If a callback is registered for this userid lookup, call it. */
- cb = g_hash_table_lookup(session->user_lookup_cb, GUINT_TO_POINTER(rid));
- data = g_hash_table_lookup(session->user_lookup_cb_data, GUINT_TO_POINTER(rid));
-
- if (cb) {
- purple_debug_info("msim", "msim_process_reply: calling callback now\n");
- /* Clone message, so that the callback 'cb' can use it (needs to free it also). */
- cb(session, msg, data);
- g_hash_table_remove(session->user_lookup_cb, GUINT_TO_POINTER(rid));
- g_hash_table_remove(session->user_lookup_cb_data, GUINT_TO_POINTER(rid));
- } else {
- purple_debug_info("msim",
- "msim_process_reply: no callback for rid %d\n", rid);
- }
-
- return TRUE;
-}
-
-/**
- * Handle an error from the server.
- *
- * @param session
- * @param msg The message.
- *
- * @return TRUE if successfully reported error.
- */
-static gboolean
-msim_error(MsimSession *session, MsimMessage *msg)
-{
- gchar *errmsg, *full_errmsg;
- guint err;
-
- g_return_val_if_fail(msg != NULL, FALSE);
-
- err = msim_msg_get_integer(msg, "err");
- errmsg = msim_msg_get_string(msg, "errmsg");
-
- full_errmsg = g_strdup_printf(_("Protocol error, code %d: %s"), err,
- errmsg ? errmsg : "no 'errmsg' given");
-
- g_free(errmsg);
-
- purple_debug_info("msim", "msim_error (sesskey=%d): %s\n",
- session->sesskey, full_errmsg);
-
- /* Destroy session if fatal. */
- if (msim_msg_get(msg, "fatal")) {
- PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
- purple_debug_info("msim", "fatal error, closing\n");
-
- switch (err) {
- case MSIM_ERROR_INCORRECT_PASSWORD: /* Incorrect password */
- reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
- if (!purple_account_get_remember_password(session->account))
- purple_account_set_password(session->account, NULL);
-#ifdef MSIM_MAX_PASSWORD_LENGTH
- if (session->account->password && (strlen(session->account->password) > MSIM_MAX_PASSWORD_LENGTH)) {
- gchar *suggestion;
-
- suggestion = g_strdup_printf(_("%s Your password is "
- "%zu characters, which is longer than the "
- "maximum length of %d. Please shorten your "
- "password at http://profileedit.myspace.com/index.cfm?fuseaction=accountSettings.changePassword and try again."),
- full_errmsg,
- strlen(session->account->password),
- MSIM_MAX_PASSWORD_LENGTH);
-
- /* Replace full_errmsg. */
- g_free(full_errmsg);
- full_errmsg = suggestion;
- } else {
- g_free(full_errmsg);
- full_errmsg = g_strdup(_("Incorrect username or password"));
- }
-#endif
- break;
- case MSIM_ERROR_LOGGED_IN_ELSEWHERE: /* Logged in elsewhere */
- reason = PURPLE_CONNECTION_ERROR_NAME_IN_USE;
- if (!purple_account_get_remember_password(session->account))
- purple_account_set_password(session->account, NULL);
- break;
- }
- purple_connection_error_reason(session->gc, reason, full_errmsg);
- } else {
- purple_notify_error(session->account, _("MySpaceIM Error"), full_errmsg, NULL);
- }
-
- g_free(full_errmsg);
-
- return TRUE;
-}
-
-/**
- * Process a message.
- *
- * @param session
- * @param msg A message from the server, ready for processing (possibly with resolved username information attached). Caller frees.
- *
- * @return TRUE if successful. FALSE if processing failed.
- */
-static gboolean
-msim_process(MsimSession *session, MsimMessage *msg)
-{
- g_return_val_if_fail(session != NULL, FALSE);
- g_return_val_if_fail(msg != NULL, FALSE);
-
- if (msim_msg_get_integer(msg, "lc") == 1) {
- return msim_login_challenge(session, msg);
- } else if (msim_msg_get_integer(msg, "lc") == 2) {
- /* return msim_we_are_logged_on(session, msg); */
- if (msim_is_username_set(session, msg)) {
- return msim_we_are_logged_on(session);
- } else {
- /* No username is set... We'll wait for the callbacks to do their work */
- /* When they're all done, the last one will call msim_we_are_logged_on() and pick up where we left off */
- return FALSE;
- }
- } else if (msim_msg_get(msg, "bm")) {
- return msim_incoming_bm(session, msg);
- } else if (msim_msg_get(msg, "rid")) {
- return msim_process_reply(session, msg);
- } else if (msim_msg_get(msg, "error")) {
- return msim_error(session, msg);
- } else if (msim_msg_get(msg, "ka")) {
- return TRUE;
- } else {
- msim_unrecognized(session, msg, "in msim_process");
- return FALSE;
- }
-}
-
-/**
- * After a uid is resolved to username, tag it with the username and submit for processing.
- *
- * @param session
- * @param userinfo Response messsage to resolving request.
- * @param data MsimMessage *, the message to attach information to.
- */
-static void
-msim_incoming_resolved(MsimSession *session, const MsimMessage *userinfo,
- gpointer data)
-{
- gchar *username;
- MsimMessage *msg, *body;
-
- g_return_if_fail(userinfo != NULL);
-
- body = msim_msg_get_dictionary(userinfo, "body");
- g_return_if_fail(body != NULL);
-
- username = msim_msg_get_string(body, "UserName");
- g_return_if_fail(username != NULL);
- /* Note: username will be owned by 'msg' below. */
-
- msg = (MsimMessage *)data;
- g_return_if_fail(msg != NULL);
-
- /* TODO: more elegant solution than below. attach whole message? */
- /* Special elements name beginning with '_', we'll use internally within the
- * program (did not come directly from the wire). */
- msg = msim_msg_append(msg, "_username", MSIM_TYPE_STRING, username); /* This makes 'msg' the owner of 'username' */
-
- /* TODO: attach more useful information, like ImageURL */
-
- msim_process(session, msg);
-
- msim_msg_free(msg);
- msim_msg_free(body);
-}
-
-/**
- * Preprocess incoming messages, resolving as needed, calling
- * msim_process() when ready to process.
- *
- * @param session
- * @param msg MsimMessage *, freed by caller.
- */
-static gboolean
-msim_preprocess_incoming(MsimSession *session, MsimMessage *msg)
-{
- g_return_val_if_fail(msg != NULL, FALSE);
-
- if (msim_msg_get(msg, "bm") && msim_msg_get(msg, "f")) {
- guint uid;
- const gchar *username;
-
- /* 'f' = userid message is from, in buddy messages */
- uid = msim_msg_get_integer(msg, "f");
-
- username = msim_uid2username_from_blist(session->account, uid);
-
- if (username) {
- /* Know username already, use it. */
- purple_debug_info("msim", "msim_preprocess_incoming: tagging with _username=%s\n",
- username);
- msg = msim_msg_append(msg, "_username", MSIM_TYPE_STRING, g_strdup(username));
- return msim_process(session, msg);
-
- } else {
- gchar *from;
-
- /* Send lookup request. */
- /* XXX: where is msim_msg_get_string() freed? make _strdup and _nonstrdup. */
- purple_debug_info("msim", "msim_incoming: sending lookup, setting up callback\n");
- from = msim_msg_get_string(msg, "f");
- msim_lookup_user(session, from, msim_incoming_resolved, msim_msg_clone(msg));
- g_free(from);
-
- /* indeterminate */
- return TRUE;
- }
- } else {
- /* Nothing to resolve - send directly to processing. */
- return msim_process(session, msg);
- }
-}
-
-/**
- * Callback when input available.
- *
- * @param gc_uncasted A PurpleConnection pointer.
- * @param source File descriptor.
- * @param cond PURPLE_INPUT_READ
- *
- * Reads the input, and calls msim_preprocess_incoming() to handle it.
- */
-static void
-msim_input_cb(gpointer gc_uncasted, gint source, PurpleInputCondition cond)
-{
- PurpleConnection *gc;
- MsimSession *session;
- gchar *end;
- int n;
-
- g_return_if_fail(gc_uncasted != NULL);
- g_return_if_fail(source >= 0); /* Note: 0 is a valid fd */
-
- gc = (PurpleConnection *)(gc_uncasted);
- session = gc->proto_data;
-
- /* libpurple/eventloop.h only defines these two */
- if (cond != PURPLE_INPUT_READ && cond != PURPLE_INPUT_WRITE) {
- purple_debug_info("msim_input_cb", "unknown condition=%d\n", cond);
- purple_connection_error_reason (gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- _("Invalid input condition"));
- return;
- }
-
- g_return_if_fail(cond == PURPLE_INPUT_READ);
-
- /* Mark down that we got data, so we don't timeout. */
- session->last_comm = time(NULL);
-
- /* If approaching end of buffer, reallocate some more memory. */
- if (session->rxsize < session->rxoff + MSIM_READ_BUF_SIZE) {
- purple_debug_info("msim",
- "msim_input_cb: %d-byte read buffer full, rxoff=%d, " "growing by %d bytes\n",
- session->rxsize, session->rxoff, MSIM_READ_BUF_SIZE);
- session->rxsize += MSIM_READ_BUF_SIZE;
- session->rxbuf = g_realloc(session->rxbuf, session->rxsize);
-
- return;
- }
-
- purple_debug_info("msim", "dynamic buffer at %d (max %d), reading up to %d\n",
- session->rxoff, session->rxsize,
- MSIM_READ_BUF_SIZE - session->rxoff - 1);
-
- /* Read into buffer. On Win32, need recv() not read(). session->fd also holds
- * the file descriptor, but it sometimes differs from the 'source' parameter.
- */
- n = recv(session->fd,
- session->rxbuf + session->rxoff,
- session->rxsize - session->rxoff - 1, 0);
-
- if (n < 0) {
- gchar *tmp;
-
- if (errno == EAGAIN)
- /* No worries */
- return;
-
- tmp = g_strdup_printf(_("Lost connection with server: %s"),
- g_strerror(errno));
- purple_connection_error_reason(gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
- g_free(tmp);
- return;
- } else if (n == 0) {
- purple_connection_error_reason(gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- _("Server closed the connection"));
- return;
- }
-
- /* Null terminate */
- purple_debug_info("msim", "msim_input_cb: going to null terminate "
- "at n=%d\n", n);
- session->rxbuf[session->rxoff + n] = 0;
-
-#ifdef MSIM_CHECK_EMBEDDED_NULLS
- /* Check for embedded NULs. I don't handle them, and they shouldn't occur. */
- if (strlen(session->rxbuf + session->rxoff) != n) {
- /* Occurs after login, but it is not a null byte. */
- purple_debug_info("msim", "msim_input_cb: strlen=%d, but read %d bytes"
- "--null byte encountered?\n",
- strlen(session->rxbuf + session->rxoff), n);
- /*purple_connection_error_reason (gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- "Invalid message - null byte on input"); */
- return;
- }
-#endif
-
- session->rxoff += n;
- purple_debug_info("msim", "msim_input_cb: read=%d\n", n);
-
-#ifdef MSIM_DEBUG_RXBUF
- purple_debug_info("msim", "buf=<%s>\n", session->rxbuf);
-#endif
-
- /* Look for \\final\\ end markers. If found, process message. */
- while((end = strstr(session->rxbuf, MSIM_FINAL_STRING))) {
- MsimMessage *msg;
-
-#ifdef MSIM_DEBUG_RXBUF
- purple_debug_info("msim", "in loop: buf=<%s>\n", session->rxbuf);
-#endif
- *end = 0;
- msg = msim_parse(session->rxbuf);
- if (!msg) {
- purple_debug_info("msim", "msim_input_cb: couldn't parse rxbuf\n");
- purple_connection_error_reason (gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- _("Unable to parse message"));
- break;
- } else {
- /* Process message and then free it (processing function should
- * clone message if it wants to keep it afterwards.) */
- if (!msim_preprocess_incoming(session, msg)) {
- msim_msg_dump("msim_input_cb: preprocessing message failed on msg: %s\n", msg);
- }
- msim_msg_free(msg);
- }
-
- /* Move remaining part of buffer to beginning. */
- session->rxoff -= strlen(session->rxbuf) + strlen(MSIM_FINAL_STRING);
- memmove(session->rxbuf, end + strlen(MSIM_FINAL_STRING),
- session->rxsize - (end + strlen(MSIM_FINAL_STRING) - session->rxbuf));
-
- /* Clear end of buffer
- * memset(end, 0, MSIM_READ_BUF_SIZE - (end - session->rxbuf));
- */
- }
-}
-
-/**
- * Callback when connected. Sets up input handlers.
- *
- * @param data A PurpleConnection pointer.
- * @param source File descriptor.
- * @param error_message
- */
-static void
-msim_connect_cb(gpointer data, gint source, const gchar *error_message)
-{
- PurpleConnection *gc;
- MsimSession *session;
-
- g_return_if_fail(data != NULL);
-
- gc = (PurpleConnection *)data;
- session = (MsimSession *)gc->proto_data;
-
- if (source < 0) {
- gchar *tmp = g_strdup_printf(_("Unable to connect: %s"),
- error_message);
- purple_connection_error_reason (gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
- g_free(tmp);
- return;
- }
-
- session->fd = source;
-
- gc->inpa = purple_input_add(source, PURPLE_INPUT_READ, msim_input_cb, gc);
-}
-
-/**
- * Start logging in to the MSIM servers.
- *
- * @param acct Account information to use to login.
- */
-static void
-msim_login(PurpleAccount *acct)
-{
- PurpleConnection *gc;
- const gchar *host;
- int port;
-
- g_return_if_fail(acct != NULL);
- g_return_if_fail(acct->username != NULL);
-
- purple_debug_info("msim", "logging in %s\n", acct->username);
-
- gc = purple_account_get_connection(acct);
- gc->proto_data = msim_session_new(acct);
- gc->flags |= PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_NO_URLDESC;
-
- /*
- * Lets wipe out our local list of blocked buddies. We'll get a
- * list of all blocked buddies from the server, and we shouldn't
- * have stuff in the local list that isn't on the server list.
- */
- while (acct->deny != NULL)
- purple_privacy_deny_remove(acct, acct->deny->data, TRUE);
-
- /* 1. connect to server */
- purple_connection_update_progress(gc, _("Connecting"),
- 0, /* which connection step this is */
- 4); /* total number of steps */
-
- host = purple_account_get_string(acct, "server", MSIM_SERVER);
- port = purple_account_get_int(acct, "port", MSIM_PORT);
-
- /* From purple.sf.net/api:
- * """Note that this function name can be misleading--although it is called
- * "proxy connect," it is used for establishing any outgoing TCP connection,
- * whether through a proxy or not.""" */
-
- /* Calls msim_connect_cb when connected. */
- if (!purple_proxy_connect(gc, acct, host, port, msim_connect_cb, gc)) {
- /* TODO: try other ports if in auto mode, then save
- * working port and try that first next time. */
- purple_connection_error_reason (gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- _("Unable to connect"));
- return;
- }
-}
-
-static void
-msim_buddy_free(PurpleBuddy *buddy)
-{
- msim_user_free(purple_buddy_get_protocol_data(buddy));
- purple_buddy_set_protocol_data(buddy, NULL);
-}
-
-/**
- * Close the connection.
- *
- * @param gc The connection.
- */
-static void
-msim_close(PurpleConnection *gc)
-{
- GSList *buddies;
- MsimSession *session;
-
- if (gc == NULL) {
- return;
- }
-
- /*
- * Free our protocol-specific buddy data. It almost seems like libpurple
- * should call our buddy_free prpl callback so that we don't need to do
- * this... but it doesn't, so we do.
- */
- buddies = purple_find_buddies(purple_connection_get_account(gc), NULL);
- while (buddies != NULL) {
- msim_buddy_free(buddies->data);
- buddies = g_slist_delete_link(buddies, buddies);
- }
-
- session = (MsimSession *)gc->proto_data;
- if (session == NULL)
- return;
-
- gc->proto_data = NULL;
-
- if (session->gc->inpa) {
- purple_input_remove(session->gc->inpa);
- }
- if (session->fd >= 0) {
- close(session->fd);
- session->fd = -1;
- }
-
- msim_session_destroy(session);
-}
-
-/**
- * Schedule an IM to be sent once the user ID is looked up.
- *
- * @param gc Connection.
- * @param who A user id, email, or username to send the message to.
- * @param message Instant message text to send.
- * @param flags Flags.
- *
- * @return 1 if successful or postponed, -1 if failed
- *
- * Allows sending to a user by username, email address, or userid. If
- * a username or email address is given, the userid must be looked up.
- * This function does that by calling msim_postprocess_outgoing().
- */
-static int
-msim_send_im(PurpleConnection *gc, const gchar *who, const gchar *message,
- PurpleMessageFlags flags)
-{
- MsimSession *session;
- gchar *message_msim;
- int rc;
-
- g_return_val_if_fail(gc != NULL, -1);
- g_return_val_if_fail(who != NULL, -1);
- g_return_val_if_fail(message != NULL, -1);
-
- /* 'flags' has many options, not used here. */
-
- session = (MsimSession *)gc->proto_data;
-
- message_msim = html_to_msim_markup(session, message);
-
- if (msim_send_bm(session, who, message_msim, MSIM_BM_ACTION_OR_IM_DELAYABLE)) {
- /* Return 1 to have Purple show this IM as being sent, 0 to not. I always
- * return 1 even if the message could not be sent, since I don't know if
- * it has failed yet--because the IM is only sent after the userid is
- * retrieved from the server (which happens after this function returns).
- * If an error does occur, it should be logged to the IM window.
- */
- rc = 1;
- } else {
- rc = -1;
- }
-
- g_free(message_msim);
-
- return rc;
-}
-
-/**
- * Handle when our user starts or stops typing to another user.
- *
- * @param gc
- * @param name The buddy name to which our user is typing to
- * @param state PURPLE_TYPING, PURPLE_TYPED, PURPLE_NOT_TYPING
- *
- * @return 0
- */
-static unsigned int
-msim_send_typing(PurpleConnection *gc, const gchar *name,
- PurpleTypingState state)
-{
- const gchar *typing_str;
- MsimSession *session;
-
- g_return_val_if_fail(gc != NULL, 0);
- g_return_val_if_fail(name != NULL, 0);
-
- session = (MsimSession *)gc->proto_data;
-
- switch (state) {
- case PURPLE_TYPING:
- typing_str = "%typing%";
- break;
-
- case PURPLE_TYPED:
- case PURPLE_NOT_TYPING:
- default:
- typing_str = "%stoptyping%";
- break;
- }
-
- purple_debug_info("msim", "msim_send_typing(%s): %d (%s)\n", name, state, typing_str);
- msim_send_bm(session, name, typing_str, MSIM_BM_ACTION_OR_IM_INSTANT);
- return 0;
-}
-
-/**
- * Callback for msim_get_info(), for when user info is received.
- */
-static void
-msim_get_info_cb(MsimSession *session, const MsimMessage *user_info_msg,
- gpointer data)
-{
- MsimMessage *msg;
- gchar *username;
- PurpleNotifyUserInfo *user_info;
- MsimUser *user;
-
- /* Get user{name,id} from msim_get_info, passed as an MsimMessage for
- orthogonality. */
- msg = (MsimMessage *)data;
- g_return_if_fail(msg != NULL);
-
- username = msim_msg_get_string(msg, "user");
- if (!username) {
- purple_debug_info("msim", "msim_get_info_cb: no 'user' in msg\n");
- return;
- }
-
- msim_msg_free(msg);
- purple_debug_info("msim", "msim_get_info_cb: got for user: %s\n", username);
-
- user = msim_find_user(session, username);
-
- if (!user) {
- /* User isn't on blist, create a temporary user to store info. */
- user = g_new0(MsimUser, 1);
- user->temporary_user = TRUE;
- }
-
- /* Update user structure with new information */
- msim_store_user_info(session, user_info_msg, user);
-
- user_info = purple_notify_user_info_new();
-
- /* Append data from MsimUser to PurpleNotifyUserInfo for display, full */
- msim_append_user_info(session, user_info, user, TRUE);
-
- purple_notify_userinfo(session->gc, username, user_info, NULL, NULL);
- purple_debug_info("msim", "msim_get_info_cb: username=%s\n", username);
-
- purple_notify_user_info_destroy(user_info);
-
- if (user->temporary_user)
- msim_user_free(user);
- g_free(username);
-}
-
-/**
- * Retrieve a user's profile.
- * @param username Username, user ID, or email address to lookup.
- */
-static void
-msim_get_info(PurpleConnection *gc, const gchar *username)
-{
- MsimSession *session;
- MsimUser *user;
- gchar *user_to_lookup;
- MsimMessage *user_msg;
-
- g_return_if_fail(gc != NULL);
- g_return_if_fail(username != NULL);
-
- session = (MsimSession *)gc->proto_data;
-
- /* Obtain uid of buddy. */
- user = msim_find_user(session, username);
-
- /* If is on buddy list, lookup by uid since it is faster. */
- if (user && user->id) {
- user_to_lookup = g_strdup_printf("%d", user->id);
- } else {
- /* Looking up buddy not on blist. Lookup by whatever user entered. */
- user_to_lookup = g_strdup(username);
- }
-
- /* Pass the username to msim_get_info_cb(), because since we lookup
- * by userid, the userinfo message will only contain the uid (not
- * the username) but it would be useful to display the username too.
- */
- user_msg = msim_msg_new(
- "user", MSIM_TYPE_STRING, g_strdup(username),
- NULL);
- purple_debug_info("msim", "msim_get_info, setting up lookup, user=%s\n", username);
-
- msim_lookup_user(session, user_to_lookup, msim_get_info_cb, user_msg);
-
- g_free(user_to_lookup);
-}
-
-/**
- * Set status using an MSIM_STATUS_CODE_* value.
- * @param status_code An MSIM_STATUS_CODE_* value.
- * @param statstring Status string, must be a dynamic string (will be freed by msim_send).
- */
-static void
-msim_set_status_code(MsimSession *session, guint status_code, gchar *statstring)
-{
- g_return_if_fail(statstring != NULL);
-
- purple_debug_info("msim", "msim_set_status_code: going to set status to code=%d,str=%s\n",
- status_code, statstring);
-
- if (!msim_send(session,
- "status", MSIM_TYPE_INTEGER, status_code,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "statstring", MSIM_TYPE_STRING, statstring,
- "locstring", MSIM_TYPE_STRING, g_strdup(""),
- NULL))
- {
- purple_debug_info("msim", "msim_set_status: failed to set status\n");
- }
-}
-
-/**
- * Set your status - callback for when user manually sets it.
- */
-static void
-msim_set_status(PurpleAccount *account, PurpleStatus *status)
-{
- PurpleStatusType *type;
- PurplePresence *pres;
- MsimSession *session;
- guint status_code;
- const gchar *message;
- gchar *stripped;
- gchar *unrecognized_msg;
-
- session = (MsimSession *)account->gc->proto_data;
-
- type = purple_status_get_type(status);
- pres = purple_status_get_presence(status);
-
- switch (purple_status_type_get_primitive(type)) {
- case PURPLE_STATUS_AVAILABLE:
- purple_debug_info("msim", "msim_set_status: available (%d->%d)\n", PURPLE_STATUS_AVAILABLE,
- MSIM_STATUS_CODE_ONLINE);
- status_code = MSIM_STATUS_CODE_ONLINE;
- break;
-
- case PURPLE_STATUS_INVISIBLE:
- purple_debug_info("msim", "msim_set_status: invisible (%d->%d)\n", PURPLE_STATUS_INVISIBLE,
- MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN);
- status_code = MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN;
- break;
-
- case PURPLE_STATUS_AWAY:
- purple_debug_info("msim", "msim_set_status: away (%d->%d)\n", PURPLE_STATUS_AWAY,
- MSIM_STATUS_CODE_AWAY);
- status_code = MSIM_STATUS_CODE_AWAY;
- break;
-
- default:
- purple_debug_info("msim", "msim_set_status: unknown "
- "status interpreting as online");
- status_code = MSIM_STATUS_CODE_ONLINE;
-
- unrecognized_msg = g_strdup_printf("msim_set_status, unrecognized status type: %d\n",
- purple_status_type_get_primitive(type));
- msim_unrecognized(session, NULL, unrecognized_msg);
- g_free(unrecognized_msg);
-
- break;
- }
-
- message = purple_status_get_attr_string(status, "message");
-
- /* Status strings are plain text. */
- if (message != NULL)
- stripped = purple_markup_strip_html(message);
- else
- stripped = g_strdup("");
-
- msim_set_status_code(session, status_code, stripped);
-
- /* If we should be idle, set that status. Time is irrelevant here. */
- if (purple_presence_is_idle(pres) && status_code != MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN)
- msim_set_idle(account->gc, 1);
-}
-
-/**
- * Go idle.
- */
-static void
-msim_set_idle(PurpleConnection *gc, int time)
-{
- MsimSession *session;
- PurpleStatus *status;
-
- g_return_if_fail(gc != NULL);
-
- session = (MsimSession *)gc->proto_data;
-
- status = purple_account_get_active_status(session->account);
-
- if (time == 0) {
- /* Going back from idle. In msim, idle is mutually exclusive
- * from the other states (you can only be away or idle, but not
- * both, for example), so by going non-idle I go back to what
- * libpurple says I should be.
- */
- msim_set_status(session->account, status);
- } else {
- const gchar *message;
- gchar *stripped;
-
- /* Set the idle message to the status message from the real
- * current status.
- */
- message = purple_status_get_attr_string(status, "message");
- if (message != NULL)
- stripped = purple_markup_strip_html(message);
- else
- stripped = g_strdup("");
-
- /* msim doesn't support idle time, so just go idle */
- msim_set_status_code(session, MSIM_STATUS_CODE_IDLE, stripped);
- }
-}
-
-/**
- * @return TRUE if everything was ok, FALSE if something went awry.
- */
-static gboolean
-msim_update_blocklist_for_buddy(MsimSession *session, const char *name, gboolean allow, gboolean block)
-{
- MsimMessage *msg;
- GList *list;
-
- list = NULL;
- list = g_list_prepend(list, allow ? "a+" : "a-");
- list = g_list_prepend(list, "<uid>");
- list = g_list_prepend(list, block ? "b+" : "b-");
- list = g_list_prepend(list, "<uid>");
- list = g_list_reverse(list);
-
- msg = msim_msg_new(
- "blocklist", MSIM_TYPE_BOOLEAN, TRUE,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- /* TODO: MsimMessage lists. Currently <uid> isn't replaced in lists. */
- /* "idlist", MSIM_TYPE_STRING, g_strdup("a-|<uid>|b-|<uid>"), */
- "idlist", MSIM_TYPE_LIST, list,
- NULL);
-
- if (!msim_postprocess_outgoing(session, msg, name, "idlist", NULL)) {
- purple_debug_error("myspace",
- "blocklist command failed for %s, allow=%d, block=%d\n",
- name, allow, block);
- msim_msg_free(msg);
- return FALSE;
- }
-
- msim_msg_free(msg);
-
- return TRUE;
-}
-
-/**
- * Add a buddy to user's buddy list.
- */
-static void
-msim_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
-{
- MsimSession *session;
- MsimMessage *msg;
- MsimMessage *msg_persist;
- MsimMessage *body;
- const char *name, *gname;
-
- session = (MsimSession *)gc->proto_data;
- name = purple_buddy_get_name(buddy);
- gname = group ? purple_group_get_name(group) : NULL;
-
- if (msim_get_user_from_buddy(buddy, FALSE) != NULL)
- return;
-
- purple_debug_info("msim", "msim_add_buddy: want to add %s to %s\n",
- name, gname ? gname : "(no group)");
-
- msg = msim_msg_new(
- "addbuddy", MSIM_TYPE_BOOLEAN, TRUE,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- /* "newprofileid" will be inserted here with uid. */
- "reason", MSIM_TYPE_STRING, g_strdup(""),
- NULL);
-
- if (!msim_postprocess_outgoing(session, msg, name, "newprofileid", "reason")) {
- purple_notify_error(NULL, NULL, _("Failed to add buddy"), _("'addbuddy' command failed."));
- msim_msg_free(msg);
- return;
- }
- msim_msg_free(msg);
-
- /* TODO: if addbuddy fails ('error' message is returned), delete added buddy from
- * buddy list since Purple adds it locally. */
-
- body = msim_msg_new(
- "ContactID", MSIM_TYPE_STRING, g_strdup("<uid>"),
- "GroupName", MSIM_TYPE_STRING, g_strdup(gname),
- "Position", MSIM_TYPE_INTEGER, 1000,
- "Visibility", MSIM_TYPE_INTEGER, 1,
- "NickName", MSIM_TYPE_STRING, g_strdup(""),
- "NameSelect", MSIM_TYPE_INTEGER, 0,
- NULL);
-
- /* TODO: Update blocklist. */
-
- msg_persist = msim_msg_new(
- "persist", MSIM_TYPE_INTEGER, 1,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_BIT_ACTION | MSIM_CMD_PUT,
- "dsn", MSIM_TYPE_INTEGER, MC_CONTACT_INFO_DSN,
- "uid", MSIM_TYPE_INTEGER, session->userid,
- "lid", MSIM_TYPE_INTEGER, MC_CONTACT_INFO_LID,
- /* TODO: Use msim_new_reply_callback to get rid. */
- "rid", MSIM_TYPE_INTEGER, session->next_rid++,
- "body", MSIM_TYPE_DICTIONARY, body,
- NULL);
-
- if (!msim_postprocess_outgoing(session, msg_persist, name, "body", NULL))
- {
- purple_notify_error(NULL, NULL, _("Failed to add buddy"), _("persist command failed"));
- msim_msg_free(msg_persist);
- return;
- }
- msim_msg_free(msg_persist);
-
- /* Add to allow list, remove from block list */
- msim_update_blocklist_for_buddy(session, name, TRUE, FALSE);
-}
-
-/**
- * Remove a buddy from the user's buddy list.
- */
-static void
-msim_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
-{
- MsimSession *session;
- MsimMessage *delbuddy_msg;
- MsimMessage *persist_msg;
- const char *name;
-
- session = (MsimSession *)gc->proto_data;
- name = purple_buddy_get_name(buddy);
-
- delbuddy_msg = msim_msg_new(
- "delbuddy", MSIM_TYPE_BOOLEAN, TRUE,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- /* 'delprofileid' with uid will be inserted here. */
- NULL);
-
- if (!msim_postprocess_outgoing(session, delbuddy_msg, name, "delprofileid", NULL)) {
- purple_notify_error(NULL, NULL, _("Failed to remove buddy"), _("'delbuddy' command failed"));
- msim_msg_free(delbuddy_msg);
- return;
- }
- msim_msg_free(delbuddy_msg);
-
- persist_msg = msim_msg_new(
- "persist", MSIM_TYPE_INTEGER, 1,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_BIT_ACTION | MSIM_CMD_DELETE,
- "dsn", MSIM_TYPE_INTEGER, MD_DELETE_BUDDY_DSN,
- "lid", MSIM_TYPE_INTEGER, MD_DELETE_BUDDY_LID,
- "uid", MSIM_TYPE_INTEGER, session->userid,
- "rid", MSIM_TYPE_INTEGER, session->next_rid++,
- /* <uid> will be replaced by postprocessing */
- "body", MSIM_TYPE_STRING, g_strdup("ContactID=<uid>"),
- NULL);
-
- if (!msim_postprocess_outgoing(session, persist_msg, name, "body", NULL)) {
- purple_notify_error(NULL, NULL, _("Failed to remove buddy"), _("persist command failed"));
- msim_msg_free(persist_msg);
- return;
- }
- msim_msg_free(persist_msg);
-
- /*
- * Remove from our approve list and from our block list (this
- * doesn't seem like it would be necessary, but the official client
- * does it)
- */
- if (!msim_update_blocklist_for_buddy(session, name, FALSE, FALSE)) {
- purple_notify_error(NULL, NULL,
- _("Failed to remove buddy"), _("blocklist command failed"));
- return;
- }
- msim_buddy_free(buddy);
-}
-
-/**
- * Remove a buddy from the user's buddy list and add them to the block list.
- */
-static void
-msim_add_deny(PurpleConnection *gc, const char *name)
-{
- MsimSession *session;
- MsimMessage *msg, *body;
-
- session = (MsimSession *)gc->proto_data;
-
- /* Remove from buddy list */
- msg = msim_msg_new(
- "delbuddy", MSIM_TYPE_BOOLEAN, TRUE,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- /* 'delprofileid' with uid will be inserted here. */
- NULL);
- if (!msim_postprocess_outgoing(session, msg, name, "delprofileid", NULL))
- purple_debug_error("myspace", "delbuddy command failed\n");
- msim_msg_free(msg);
-
- /* Remove from our approve list and add to our block list */
- msim_update_blocklist_for_buddy(session, name, FALSE, TRUE);
-
- /*
- * Add the buddy to our list of blocked contacts, so we know they
- * are blocked if we log in with another client
- */
- body = msim_msg_new(
- "ContactID", MSIM_TYPE_STRING, g_strdup("<uid>"),
- "Visibility", MSIM_TYPE_INTEGER, 2,
- NULL);
- msg = msim_msg_new(
- "persist", MSIM_TYPE_INTEGER, 1,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_BIT_ACTION | MSIM_CMD_PUT,
- "dsn", MSIM_TYPE_INTEGER, MC_CONTACT_INFO_DSN,
- "lid", MSIM_TYPE_INTEGER, MC_CONTACT_INFO_LID,
- "rid", MSIM_TYPE_INTEGER, session->next_rid++,
- "body", MSIM_TYPE_DICTIONARY, body,
- NULL);
- if (!msim_postprocess_outgoing(session, msg, name, "body", NULL))
- purple_debug_error("myspace", "add to block list command failed\n");
- msim_msg_free(msg);
-
- /*
- * TODO: MySpace doesn't allow blocked buddies on our buddy list,
- * do they? If not then we need to remove the buddy from
- * libpurple's buddy list.
- */
-}
-
-/**
- * Remove a buddy from the user's block list.
- */
-static void
-msim_rem_deny(PurpleConnection *gc, const char *name)
-{
- MsimSession *session;
- MsimMessage *msg, *body;
-
- session = (MsimSession *)gc->proto_data;
-
- /*
- * Remove from our list of blocked contacts, so we know they
- * are no longer blocked if we log in with another client
- */
- body = msim_msg_new(
- "ContactID", MSIM_TYPE_STRING, g_strdup("<uid>"),
- NULL);
- msg = msim_msg_new(
- "persist", MSIM_TYPE_INTEGER, 1,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_BIT_ACTION | MSIM_CMD_DELETE,
- "dsn", MSIM_TYPE_INTEGER, MC_DELETE_CONTACT_INFO_DSN,
- "lid", MSIM_TYPE_INTEGER, MC_DELETE_CONTACT_INFO_LID,
- "rid", MSIM_TYPE_INTEGER, session->next_rid++,
- "body", MSIM_TYPE_DICTIONARY, body,
- NULL);
- if (!msim_postprocess_outgoing(session, msg, name, "body", NULL))
- purple_debug_error("myspace", "remove from block list command failed\n");
- msim_msg_free(msg);
-
- /* Remove from our approve list and our block list */
- msim_update_blocklist_for_buddy(session, name, FALSE, FALSE);
-}
-
-/**
- * Returns a string of a username in canonical form. Basically removes all the
- * spaces, lowercases the string, and looks up user IDs to usernames.
- * Normalizing tom, TOM, Tom, and 6221 wil all return 'tom'.
- *
- * Borrowed this code from oscar_normalize. Added checking for
- * "if userid, get name before normalizing"
- */
-static const char *msim_normalize(const PurpleAccount *account, const char *str) {
- static char normalized[BUF_LEN];
- char *tmp1, *tmp2;
- int i, j;
- guint id;
-
- g_return_val_if_fail(str != NULL, NULL);
-
- if (msim_is_userid(str)) {
- /* Have user ID, we need to get their username first :) */
- const char *username;
-
- /* If the account does not exist, we can't look up the user. */
- if (!account || !account->gc)
- return str;
-
- id = atol(str);
- username = msim_uid2username_from_blist((PurpleAccount *)account, id);
- if (!username) {
- /* Not in buddy list... scheisse... TODO: Manual Lookup! Bug #4631 */
- /* Note: manual lookup using msim_lookup_user() is a problem inside
- * msim_normalize(), because msim_lookup_user() calls a callback function
- * when the user information has been looked up, but msim_normalize() expects
- * the result immediately. */
- strncpy(normalized, str, BUF_LEN);
- } else {
- strncpy(normalized, username, BUF_LEN);
- }
- } else {
- /* Have username. */
- strncpy(normalized, str, BUF_LEN);
- }
-
- /* Strip spaces. */
- for (i=0, j=0; normalized[j]; j++) {
- if (normalized[j] != ' ')
- normalized[i++] = normalized[j];
- }
- normalized[i] = '\0';
-
- /* Lowercase and perform UTF-8 normalization. */
- tmp1 = g_utf8_strdown(normalized, -1);
- tmp2 = g_utf8_normalize(tmp1, -1, G_NORMALIZE_DEFAULT);
- g_snprintf(normalized, sizeof(normalized), "%s", tmp2);
- g_free(tmp2);
- g_free(tmp1);
-
- /* TODO: re-add caps and spacing back to what the user wanted.
- * User can format their own names, for example 'msimprpl' is shown
- * as 'MsIm PrPl' in the official client.
- *
- * TODO: file a ticket to add this enhancement.
- */
-
- return normalized;
-}
-
-/**
- * Return whether the buddy can be messaged while offline.
- *
- * The protocol supports offline messages in just the same way as online
- * messages.
- */
-static gboolean
-msim_offline_message(const PurpleBuddy *buddy)
-{
- return TRUE;
-}
-
-/**
- * Send raw data to the server, possibly with embedded NULs.
- *
- * Used in prpl_info struct, so that plugins can have the most possible
- * control of what is sent over the connection. Inside this prpl,
- * msim_send_raw() is used, since it sends NUL-terminated strings (easier).
- *
- * @param gc PurpleConnection
- * @param buf Buffer to send
- * @param total_bytes Size of buffer to send
- *
- * @return Bytes successfully sent, or -1 on error.
- */
-/*
- * TODO: This needs to do non-blocking writes and use a watcher to check
- * when the fd is available to be written to.
- */
-static int
-msim_send_really_raw(PurpleConnection *gc, const char *buf, int total_bytes)
-{
- int total_bytes_sent;
- MsimSession *session;
-
- g_return_val_if_fail(gc != NULL, -1);
- g_return_val_if_fail(buf != NULL, -1);
- g_return_val_if_fail(total_bytes >= 0, -1);
-
- session = (MsimSession *)gc->proto_data;
-
- /* Loop until all data is sent, or a failure occurs. */
- total_bytes_sent = 0;
- do {
- int bytes_sent;
-
- bytes_sent = send(session->fd, buf + total_bytes_sent,
- total_bytes - total_bytes_sent, 0);
-
- if (bytes_sent < 0) {
- purple_debug_info("msim", "msim_send_raw(%s): send() failed: %s\n",
- buf, g_strerror(errno));
- return total_bytes_sent;
- }
- total_bytes_sent += bytes_sent;
-
- } while(total_bytes_sent < total_bytes);
-
- return total_bytes_sent;
-}
-
-/**
- * Send raw data (given as a NUL-terminated string) to the server.
- *
- * @param session
- * @param msg The raw data to send, in a NUL-terminated string.
- *
- * @return TRUE if succeeded, FALSE if not.
- *
- */
-gboolean
-msim_send_raw(MsimSession *session, const gchar *msg)
-{
- size_t len;
-
- g_return_val_if_fail(msg != NULL, FALSE);
-
- purple_debug_info("msim", "msim_send_raw: writing <%s>\n", msg);
- len = strlen(msg);
-
- return msim_send_really_raw(session->gc, msg, len) == (int)len;
-}
-
-static GHashTable *
-msim_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;
-}
-
-/**
- * Callbacks called by Purple, to access this plugin.
- */
-static PurplePluginProtocolInfo prpl_info = {
- /* options */
- OPT_PROTO_USE_POINTSIZE /* specify font size in sane point size */
- | OPT_PROTO_MAIL_CHECK,
-
- /* | OPT_PROTO_IM_IMAGE - TODO: direct images. */
- NULL, /* user_splits */
- NULL, /* protocol_options */
- NO_BUDDY_ICONS, /* icon_spec - TODO: eventually should add this */
- msim_list_icon, /* list_icon */
- NULL, /* list_emblems */
- msim_status_text, /* status_text */
- msim_tooltip_text, /* tooltip_text */
- msim_status_types, /* status_types */
- msim_blist_node_menu, /* blist_node_menu */
- NULL, /* chat_info */
- NULL, /* chat_info_defaults */
- msim_login, /* login */
- msim_close, /* close */
- msim_send_im, /* send_im */
- NULL, /* set_info */
- msim_send_typing, /* send_typing */
- msim_get_info, /* get_info */
- msim_set_status, /* set_status */
- msim_set_idle, /* set_idle */
- NULL, /* change_passwd */
- msim_add_buddy, /* add_buddy */
- NULL, /* add_buddies */
- msim_remove_buddy, /* remove_buddy */
- NULL, /* remove_buddies */
- NULL, /* add_permit */
- msim_add_deny, /* add_deny */
- NULL, /* rem_permit */
- msim_rem_deny, /* rem_deny */
- NULL, /* set_permit_deny */
- NULL, /* join_chat */
- NULL, /* reject chat invite */
- NULL, /* get_chat_name */
- NULL, /* chat_invite */
- NULL, /* chat_leave */
- NULL, /* chat_whisper */
- NULL, /* chat_send */
- NULL, /* keepalive */
- NULL, /* register_user */
- NULL, /* get_cb_info */
- NULL, /* get_cb_away */
- NULL, /* alias_buddy */
- NULL, /* group_buddy */
- NULL, /* rename_group */
- msim_buddy_free, /* buddy_free */
- NULL, /* convo_closed */
- msim_normalize, /* normalize */
- NULL, /* set_buddy_icon */
- NULL, /* 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 */
- NULL, /* can_receive_file */
- NULL, /* send_file */
- NULL, /* new_xfer */
- msim_offline_message, /* offline_message */
- NULL, /* whiteboard_prpl_ops */
- msim_send_really_raw, /* send_raw */
- NULL, /* roomlist_room_serialize */
- NULL, /* unregister_user */
- msim_send_attention, /* send_attention */
- msim_attention_types, /* attention_types */
- sizeof(PurplePluginProtocolInfo), /* struct_size */
- msim_get_account_text_table, /* get_account_text_table */
- NULL, /* initiate_media */
- NULL, /* get_media_caps */
- NULL, /* get_moods */
- NULL, /* set_public_alias */
- NULL, /* get_public_alias */
- NULL, /* add_buddy_with_invite */
- NULL /* add_buddies_with_invite */
-};
-
-/**
- * Load the plugin.
- */
-static gboolean
-msim_load(PurplePlugin *plugin)
-{
- /* If compiled to use RC4 from libpurple, check if it is really there. */
- if (!purple_ciphers_find_cipher("rc4")) {
- purple_debug_error("msim", "rc4 not in libpurple, but it is required - not loading MySpaceIM plugin!\n");
- purple_notify_error(plugin, _("Missing Cipher"),
- _("The RC4 cipher could not be found"),
- _("Upgrade "
- "to a libpurple with RC4 support (>= 2.0.1). MySpaceIM "
- "plugin will not be loaded."));
- return FALSE;
- }
- return TRUE;
-}
-
-/**
- * Called when friends have been imported to buddy list on server.
- */
-static void
-msim_import_friends_cb(MsimSession *session, const MsimMessage *reply, gpointer user_data)
-{
- MsimMessage *body;
- gchar *completed;
-
- /* Check if the friends were imported successfully. */
- body = msim_msg_get_dictionary(reply, "body");
- g_return_if_fail(body != NULL);
- completed = msim_msg_get_string(body, "Completed");
- msim_msg_free(body);
- g_return_if_fail(completed != NULL);
- if (!g_str_equal(completed, "True"))
- {
- purple_debug_info("msim_import_friends_cb",
- "failed to import friends: %s", completed);
- purple_notify_error(session->account, _("Add friends from MySpace.com"),
- _("Importing friends failed"), NULL);
- g_free(completed);
- return;
- }
- g_free(completed);
-
- purple_debug_info("msim_import_friends_cb",
- "added friends to server-side buddy list, requesting new contacts from server");
-
- msim_get_contact_list(session, MSIM_CONTACT_LIST_IMPORT_ALL_FRIENDS);
-
- /* TODO: show, X friends have been added */
-}
-
-/**
- * Import friends from myspace.com.
- */
-static void msim_import_friends(PurplePluginAction *action)
-{
- PurpleConnection *gc;
- MsimSession *session;
- gchar *group_name;
-
- gc = (PurpleConnection *)action->context;
- session = (MsimSession *)gc->proto_data;
-
- group_name = "MySpace Friends";
-
- g_return_if_fail(msim_send(session,
- "persist", MSIM_TYPE_INTEGER, 1,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_PUT,
- "dsn", MSIM_TYPE_INTEGER, MC_IMPORT_ALL_FRIENDS_DSN,
- "lid", MSIM_TYPE_INTEGER, MC_IMPORT_ALL_FRIENDS_LID,
- "uid", MSIM_TYPE_INTEGER, session->userid,
- "rid", MSIM_TYPE_INTEGER,
- msim_new_reply_callback(session, msim_import_friends_cb, NULL),
- "body", MSIM_TYPE_STRING,
- g_strdup_printf("GroupName=%s", group_name),
- NULL));
-}
-
-/**
- * Actions menu for account.
- */
-static GList *
-msim_actions(PurplePlugin *plugin, gpointer context /* PurpleConnection* */)
-{
- GList *menu;
- PurplePluginAction *act;
-
- menu = NULL;
-
-#if 0
- /* TODO: find out how */
- act = purple_plugin_action_new(_("Find people..."), msim_);
- menu = g_list_append(menu, act);
-
- act = purple_plugin_action_new(_("Change IM name..."), NULL);
- menu = g_list_append(menu, act);
-#endif
-
- act = purple_plugin_action_new(_("Add friends from MySpace.com"), msim_import_friends);
- menu = g_list_append(menu, act);
-
- return menu;
-}
-
-/**
- * Based on MSN's plugin info comments.
- */
-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-myspace", /**< id */
- "MySpaceIM", /**< name */
- MSIM_PRPL_VERSION_STRING, /**< version */
- /** summary */
- "MySpaceIM Protocol Plugin",
- /** description */
- "MySpaceIM Protocol Plugin",
- "Jeff Connelly <jeff2@soc.pidgin.im>", /**< author */
- "http://developer.pidgin.im/wiki/MySpaceIM/", /**< homepage */
-
- msim_load, /**< load */
- NULL, /**< unload */
- NULL, /**< destroy */
- NULL, /**< ui_info */
- &prpl_info, /**< extra_info */
- NULL, /**< prefs_info */
- msim_actions, /**< msim_actions */
- NULL, /**< reserved1 */
- NULL, /**< reserved2 */
- NULL, /**< reserved3 */
- NULL /**< reserved4 */
-};
-
-#ifdef MSIM_SELF_TEST
-/*
- * Test functions.
- * Used to test or try out the internal workings of msimprpl. If you're reading
- * this code for the first time, these functions can be instructive in learning
- * how msimprpl is architected.
- */
-
-/**
- * Test MsimMessage for basic functionality.
- */
-static int
-msim_test_msg(void)
-{
- MsimMessage *msg, *msg_cloned, *msg2;
- GList *list;
- gchar *packed, *packed_expected, *packed_cloned;
- guint failures;
-
- failures = 0;
-
- purple_debug_info("msim", "\n\nTesting MsimMessage\n");
- msg = msim_msg_new(NULL); /* Create a new, empty message. */
-
- /* Append some new elements. */
- msg = msim_msg_append(msg, "bx", MSIM_TYPE_BINARY, g_string_new_len("XXX", 3));
- msg = msim_msg_append(msg, "k1", MSIM_TYPE_STRING, g_strdup("v1"));
- msg = msim_msg_append(msg, "k1", MSIM_TYPE_INTEGER, GUINT_TO_POINTER(42));
- msg = msim_msg_append(msg, "k1", MSIM_TYPE_STRING, g_strdup("v43"));
- msg = msim_msg_append(msg, "k1", MSIM_TYPE_STRING, g_strdup("v52/xxx\\yyy"));
- msg = msim_msg_append(msg, "k1", MSIM_TYPE_STRING, g_strdup("v7"));
- msim_msg_dump("msg debug str=%s\n", msg);
- packed = msim_msg_pack(msg);
-
- purple_debug_info("msim", "msg packed=%s\n", packed);
-
- packed_expected = "\\bx\\WFhY\\k1\\v1\\k1\\42\\k1"
- "\\v43\\k1\\v52/1xxx/2yyy\\k1\\v7\\final\\";
-
- if (!g_str_equal(packed, packed_expected)) {
- purple_debug_info("msim", "!!!(%d), msim_msg_pack not what expected: %s != %s\n",
- ++failures, packed, packed_expected);
- }
-
-
- msg_cloned = msim_msg_clone(msg);
- packed_cloned = msim_msg_pack(msg_cloned);
-
- purple_debug_info("msim", "msg cloned=%s\n", packed_cloned);
- if (!g_str_equal(packed, packed_cloned)) {
- purple_debug_info("msim", "!!!(%d), msim_msg_pack on cloned message not equal to original: %s != %s\n",
- ++failures, packed_cloned, packed);
- }
-
- g_free(packed);
- g_free(packed_cloned);
- msim_msg_free(msg_cloned);
- msim_msg_free(msg);
-
- /* Try some of the more advanced functionality */
- list = NULL;
-
- list = g_list_prepend(list, "item3");
- list = g_list_prepend(list, "item2");
- list = g_list_prepend(list, "item1");
- list = g_list_prepend(list, "item0");
-
- msg = msim_msg_new(NULL);
- msg = msim_msg_append(msg, "string", MSIM_TYPE_STRING, g_strdup("string value"));
- msg = msim_msg_append(msg, "raw", MSIM_TYPE_RAW, g_strdup("raw value"));
- msg = msim_msg_append(msg, "integer", MSIM_TYPE_INTEGER, GUINT_TO_POINTER(3140));
- msg = msim_msg_append(msg, "boolean", MSIM_TYPE_BOOLEAN, GUINT_TO_POINTER(FALSE));
- msg = msim_msg_append(msg, "list", MSIM_TYPE_LIST, list);
-
- msim_msg_dump("msg with list=%s\n", msg);
- purple_debug_info("msim", "msg with list packed=%s\n", msim_msg_pack(msg));
-
- msg2 = msim_msg_new(NULL);
- msg2 = msim_msg_append(msg2, "outer", MSIM_TYPE_STRING, g_strdup("outer value"));
- msg2 = msim_msg_append(msg2, "body", MSIM_TYPE_DICTIONARY, msg);
- msim_msg_dump("msg with dict=%s\n", msg2); /* msg2 now 'owns' msg */
- purple_debug_info("msim", "msg with dict packed=%s\n", msim_msg_pack(msg2));
-
- msim_msg_free(msg2);
-
- return failures;
-}
-
-/**
- * Test protocol-level escaping/unescaping.
- */
-static int
-msim_test_escaping(void)
-{
- guint failures;
- gchar *raw, *escaped, *unescaped, *expected;
-
- failures = 0;
-
- purple_debug_info("msim", "\n\nTesting escaping\n");
-
- raw = "hello/world\\hello/world";
-
- escaped = msim_escape(raw);
- purple_debug_info("msim", "msim_test_escaping: raw=%s, escaped=%s\n", raw, escaped);
- expected = "hello/1world/2hello/1world";
- if (!g_str_equal(escaped, expected)) {
- purple_debug_info("msim", "!!!(%d), msim_escape failed: %s != %s\n",
- ++failures, escaped, expected);
- }
-
-
- unescaped = msim_unescape(escaped);
- g_free(escaped);
- purple_debug_info("msim", "msim_test_escaping: unescaped=%s\n", unescaped);
- if (!g_str_equal(raw, unescaped)) {
- purple_debug_info("msim", "!!!(%d), msim_unescape failed: %s != %s\n",
- ++failures, raw, unescaped);
- }
-
- return failures;
-}
-
-static void
-msim_test_all(void)
-{
- guint failures;
-
- failures = 0;
- failures += msim_test_msg();
- failures += msim_test_escaping();
-
- if (failures) {
- purple_debug_info("msim", "msim_test_all HAD FAILURES: %d\n", failures);
- } else {
- purple_debug_info("msim", "msim_test_all - all tests passed!\n");
- }
- exit(0);
-}
-#endif
-
-#ifdef MSIM_CHECK_NEWER_VERSION
-/**
- * Callback for when a currentversion.txt has been downloaded.
- */
-static void
-msim_check_newer_version_cb(PurpleUtilFetchUrlData *url_data,
- gpointer user_data,
- const gchar *url_text,
- gsize len,
- const gchar *error_message)
-{
- GKeyFile *keyfile;
- GError *error;
- GString *data;
- gchar *newest_filever;
-
- if (!url_text) {
- purple_debug_info("msim_check_newer_version_cb",
- "got error: %s\n", error_message);
- return;
- }
-
- purple_debug_info("msim_check_newer_version_cb",
- "url_text=%s\n", url_text ? url_text : "(NULL)");
-
- /* Prepend [group] so that GKeyFile can parse it (requires a group). */
- data = g_string_new(url_text);
- purple_debug_info("msim", "data=%s\n", data->str
- ? data->str : "(NULL)");
- data = g_string_prepend(data, "[group]\n");
-
- purple_debug_info("msim", "data=%s\n", data->str
- ? data->str : "(NULL)");
-
- /* url_text is variable=data\n...†*/
-
- /* Check FILEVER, 1.0.716.0. 716 is build, MSIM_CLIENT_VERSION */
- /* New (english) version can be downloaded from SETUPURL+SETUPFILE */
-
- error = NULL;
- keyfile = g_key_file_new();
-
- /* Default list seperator is ;, but currentversion.txt doesn't have
- * these, so set to an unused character to avoid parsing problems. */
- g_key_file_set_list_separator(keyfile, '\0');
-
- g_key_file_load_from_data(keyfile, data->str, data->len,
- G_KEY_FILE_NONE, &error);
- g_string_free(data, TRUE);
-
- if (error != NULL) {
- purple_debug_info("msim_check_newer_version_cb",
- "couldn't parse, error: %d %d %s\n",
- error->domain, error->code, error->message);
- g_error_free(error);
- return;
- }
-
- gchar **ks;
- guint n;
- ks = g_key_file_get_keys(keyfile, "group", &n, NULL);
- purple_debug_info("msim", "n=%d\n", n);
- guint i;
- for (i = 0; ks[i] != NULL; ++i)
- {
- purple_debug_info("msim", "%d=%s\n", i, ks[i]);
- }
-
- newest_filever = g_key_file_get_string(keyfile, "group",
- "FILEVER", &error);
-
- purple_debug_info("msim_check_newer_version_cb",
- "newest filever: %s\n", newest_filever ?
- newest_filever : "(NULL)");
- if (error != NULL) {
- purple_debug_info("msim_check_newer_version_cb",
- "error: %d %d %s\n",
- error->domain, error->code, error->message);
- g_error_free(error);
- }
-
- g_key_file_free(keyfile);
-
- exit(0);
-}
-#endif
-
-/**
- Handle a myim:addContact command, after username has been looked up.
- */
-static void
-msim_uri_handler_addContact_cb(MsimSession *session, MsimMessage *userinfo, gpointer data)
-{
- MsimMessage *body;
- gchar *username;
-
- body = msim_msg_get_dictionary(userinfo, "body");
- username = msim_msg_get_string(body, "UserName");
- msim_msg_free(body);
-
- if (!username) {
- guint uid;
-
- uid = msim_msg_get_integer(userinfo, "UserID");
- g_return_if_fail(uid != 0);
-
- username = g_strdup_printf("%d", uid);
- }
-
- purple_blist_request_add_buddy(session->account, username, _("Buddies"), NULL);
-
- g_free(username);
-}
-
-/* TODO: move uid->username resolving to IM sending and buddy adding functions,
- * so that user can manually add or IM by userid and username automatically
- * looked up if possible? */
-
-/**
- * Handle a myim:sendIM URI command, after username has been looked up.
- */
-static void
-msim_uri_handler_sendIM_cb(MsimSession *session, MsimMessage *userinfo, gpointer data)
-{
- PurpleConversation *conv;
- MsimMessage *body;
- gchar *username;
-
- body = msim_msg_get_dictionary(userinfo, "body");
- username = msim_msg_get_string(body, "UserName");
- msim_msg_free(body);
-
- if (!username) {
- guint uid;
-
- uid = msim_msg_get_integer(userinfo, "UserID");
- g_return_if_fail(uid != 0);
-
- username = g_strdup_printf("%d", uid);
- }
-
-
- conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, username, session->account);
- if (!conv) {
- purple_debug_info("msim_uri_handler", "creating new conversation for %s\n", username);
- conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, session->account, username);
- }
-
- /* Just open the window so the user can send an IM. */
- purple_conversation_present(conv);
-
- g_free(username);
-}
-
-static gboolean
-msim_uri_handler(const gchar *proto, const gchar *cmd, GHashTable *params)
-{
- PurpleAccount *account;
- MsimSession *session;
- GList *l;
- gchar *uid_str, *cid_str;
- guint uid, cid;
-
- if (g_ascii_strcasecmp(proto, "myim"))
- return FALSE;
-
- /* Parameters are case-insensitive. */
- uid_str = g_hash_table_lookup(params, "uid");
- cid_str = g_hash_table_lookup(params, "cid");
-
- uid = uid_str ? atol(uid_str) : 0;
- cid = cid_str ? atol(cid_str) : 0;
-
- /* Need a contact. */
- g_return_val_if_fail(cid != 0, FALSE);
-
- /* TODO: if auto=true, "Add all the people on this page to my IM List!", on
- * http://collect.myspace.com/index.cfm?fuseaction=im.friendslist. Don't need a cid. */
-
- /* Convert numeric contact ID back to a string. Needed for looking up. Don't just
- * directly use cid directly from parameters, because it might not be numeric.
- * It is trivial to change this to allow cID to be a username, but that's not how
- * the official MySpaceIM client works, so don't provide that functionality. */
- cid_str = g_strdup_printf("%d", cid);
-
-
- /* Find our account with specified user id, or use first connected account if uid=0. */
- account = NULL;
- l = purple_accounts_get_all();
- while (l) {
- if (purple_account_is_connected(l->data) &&
- (uid == 0 || purple_account_get_int(l->data, "uid", 0) == (int)uid)) {
- account = l->data;
- break;
- }
- l = l->next;
- }
-
- if (!account) {
- purple_notify_error(NULL, _("myim URL handler"),
- _("No suitable MySpaceIM account could be found to open this myim URL."),
- _("Enable the proper MySpaceIM account and try again."));
- g_free(cid_str);
- return FALSE;
- }
-
- session = (MsimSession *)account->gc->proto_data;
- g_return_val_if_fail(session != NULL, FALSE);
-
- /* Lookup userid to username. TODO: push this down, to IM sending/contact
- * adding functions. */
-
- /* myim:sendIM?uID=USERID&cID=CONTACTID */
- if (!g_ascii_strcasecmp(cmd, "sendIM")) {
- msim_lookup_user(session, cid_str, (MSIM_USER_LOOKUP_CB)msim_uri_handler_sendIM_cb, NULL);
- g_free(cid_str);
- return TRUE;
-
- /* myim:addContact?uID=USERID&cID=CONTACTID */
- } else if (!g_ascii_strcasecmp(cmd, "addContact")) {
- msim_lookup_user(session, cid_str, (MSIM_USER_LOOKUP_CB)msim_uri_handler_addContact_cb, NULL);
- g_free(cid_str);
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- * Initialize plugin.
- */
-static void
-init_plugin(PurplePlugin *plugin)
-{
-#ifdef MSIM_SELF_TEST
- msim_test_all();
- exit(0);
-#endif /* MSIM_SELF_TEST */
-
- PurpleAccountOption *option;
- static gboolean initialized = FALSE;
-
-#ifdef MSIM_CHECK_NEWER_VERSION
- /* PROBLEM: MySpace's servers always return Content-Location, and
- * libpurple redirects to it, infinitely, even though it is the same
- * location we requested! */
- purple_util_fetch_url("http://im.myspace.com/nsis/currentversion.txt",
- FALSE, /* not full URL */
- "MSIMAutoUpdateAgent", /* user agent */
- TRUE, /* use HTTP/1.1 */
- msim_check_newer_version_cb, NULL);
-#endif
-
- /* TODO: default to automatically try different ports. Make the user be
- * able to set the first port to try (like LastConnectedPort in Windows client). */
- option = purple_account_option_string_new(_("Connect server"), "server", MSIM_SERVER);
- prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
- option = purple_account_option_int_new(_("Connect port"), "port", MSIM_PORT);
- prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
-#ifdef MSIM_USER_WANTS_TO_CONFIGURE_STATUS_TEXT
- option = purple_account_option_bool_new(_("Show display name in status text"), "show_display_name", TRUE);
- prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
- option = purple_account_option_bool_new(_("Show headline in status text"), "show_headline", TRUE);
- prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-#endif
-
-#ifdef MSIM_USER_WANTS_TO_DISABLE_EMOTICONS
- option = purple_account_option_bool_new(_("Send emoticons"), "emoticons", TRUE);
- prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-#endif
-
-#ifdef MSIM_USER_REALLY_CARES_ABOUT_PRECISE_FONT_SIZES
- option = purple_account_option_int_new(_("Screen resolution (dots per inch)"), "dpi", MSIM_DEFAULT_DPI);
- prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-
- option = purple_account_option_int_new(_("Base font size (points)"), "base_font_size", MSIM_BASE_FONT_POINT_SIZE);
- prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-#endif
-
- /* Code below only runs once. Based on oscar.c's oscar_init(). */
- if (initialized)
- return;
-
- initialized = TRUE;
-
- purple_signal_connect(purple_get_core(), "uri-handler", &initialized,
- PURPLE_CALLBACK(msim_uri_handler), NULL);
-}
-
-PURPLE_INIT_PLUGIN(myspace, init_plugin, info);
diff --git a/libpurple/protocols/myspace/myspace.h b/libpurple/protocols/myspace/myspace.h
deleted file mode 100644
index eecfc20db9..0000000000
--- a/libpurple/protocols/myspace/myspace.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/* MySpaceIM Protocol Plugin, header file
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * 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 _MYSPACE_MYSPACE_H
-#define _MYSPACE_MYSPACE_H
-
-#include "internal.h"
-
-/* Other includes */
-#include <string.h>
-#include <errno.h>/* for EAGAIN */
-#include <stdarg.h>
-#include <math.h>
-
-#include <glib.h>
-
-#ifdef _WIN32
-#include "win32dep.h"
-#else
-/* For recv() and send(); needed to match Win32 */
-#include <sys/types.h>
-#include <sys/socket.h>
-#endif
-
-#include "notify.h"
-#include "plugin.h"
-#include "accountopt.h"
-#include "version.h"
-#include "cipher.h" /* for SHA-1 */
-#include "util.h" /* for base64 */
-#include "debug.h" /* for purple_debug_info */
-#include "request.h" /* For dialogs used in setting the username */
-#include "xmlnode.h"
-#include "core.h"
-#include "conversation.h" /* For late normalization */
-
-/* MySpaceIM includes */
-#include "persist.h"
-#include "message.h"
-#include "session.h"
-#include "zap.h"
-#include "markup.h"
-#include "user.h"
-
-/* Conditional compilation options */
-/* Send third-party client version? (Recognized by us and Miranda's plugin) */
-/*#define MSIM_SEND_CLIENT_VERSION */
-
-/* Debugging options */
-/* Low-level and rarely needed */
-/*#define MSIM_DEBUG_PARSE */
-/*#define MSIM_DEBUG_LOGIN_CHALLENGE*/
-/*#define MSIM_DEBUG_RXBUF */
-
-/* Encode unknown HTML tags from IM clients in messages as [tag], instead of
- * ignoring. Useful for debugging */
-/*#define MSIM_MARKUP_SHOW_UNKNOWN_TAGS */
-
-/* Define to cause init_plugin() to run some tests and print
- * the results to the Purple debug log, then exit. Useful to
- * run with 'pidgin -d' to see the output. Don't define if
- * you want to actually use the plugin! */
-/*#define MSIM_SELF_TEST */
-
-/* Constants */
-
-/* Maximum length of a password that is acceptable. This is the limit
- * on the official client (build 679) and on the 'new password' field at
- * http://settings.myspace.com/index.cfm?fuseaction=user.changepassword
- * (though curiously, not on the 'current password' field). */
-
-/* After login fails, if password is greater than this many characters,
- * warn user that it may be too long. */
-#define MSIM_MAX_PASSWORD_LENGTH 10
-
-/* Maximum length of usernames, when setting. */
-#define MSIM_MAX_USERNAME_LENGTH 25
-
-/* Build version of MySpaceIM to report to servers (1.0.xxx.0) */
-#define MSIM_CLIENT_VERSION 697
-
-/* Check for a newer official MySpaceIM client on startup?
- * (Mostly useful for developers) */
-/*#define MSIM_CHECK_NEWER_VERSION*/
-
-/* Language codes from http://www.microsoft.com/globaldev/reference/oslocversion.mspx */
-#define MSIM_LANGUAGE_ID_ENGLISH 1033
-#define MSIM_LANGUAGE_NAME_ENGLISH "ENGLISH"
-
-/* msimprpl version string of this plugin */
-#define MSIM_PRPL_VERSION_STRING "0.18"
-
-/* Default server */
-#define MSIM_SERVER "im.myspace.akadns.net"
-#define MSIM_PORT 1863 /* TODO: alternate ports and automatic */
-
-/* Time between keepalives (seconds) - if no data within this time, is dead. */
-#define MSIM_KEEPALIVE_INTERVAL (3 * 60)
-/*#define MSIM_USE_KEEPALIVE*/
-
-/* Time to check if alive (seconds) */
-#define MSIM_KEEPALIVE_INTERVAL_CHECK 30
-
-/* Time to check for new mail (milliseconds) */
-#define MSIM_MAIL_INTERVAL_CHECK (60 * 1000)
-
-/* Constants */
-#define HASH_SIZE 0x14 /**< Size of SHA-1 hash for login */
-#define NONCE_SIZE 0x20 /**< Half of decoded 'nc' field */
-#define MSIM_READ_BUF_SIZE (15 * 1024) /**< Receive buffer size */
-#define MSIM_FINAL_STRING "\\final\\" /**< Message end marker */
-
-/* Messages */
-#define MSIM_BM_ACTION_OR_IM_DELAYABLE 1
-#define MSIM_BM_STATUS 100
-#define MSIM_BM_ACTION_OR_IM_INSTANT 121
-#define MSIM_BM_MEDIA 122
-#define MSIM_BM_PROFILE 124
-#define MSIM_BM_STATUS_MOOD 126
-#define MSIM_BM_UNOFFICIAL_CLIENT 200
-
-/* Authentication algorithm for login2 */
-#define MSIM_AUTH_ALGORITHM 196610
-
-/* Recognized challenge length */
-#define MSIM_AUTH_CHALLENGE_LENGTH 0x40
-
-#ifdef SEND_OUR_IP_ADDRESSES
-/* TODO: obtain IPs of network interfaces from user's machine, instead of
- * hardcoding these values below (used in msim_compute_login_response).
- * This is not immediately
- * important because you can still connect and perform basic
- * functions of the protocol. There is also a high chance that the addreses
- * are RFC1918 private, so the servers couldn't do anything with them
- * anyways except make note of that fact. Probably important for any
- * kind of direct connection, or file transfer functionality.
- */
-
-#define MSIM_LOGIN_IP_LIST "\x00\x00\x00\x00\x05\x7f\x00\x00\x01\x00\x00\x00\x00\x0a\x00\x00\x40\xc0\xa8\x58\x01\xc0\xa8\x3c\x01"
-#define MSIM_LOGIN_IP_LIST_LEN 25
-#endif /* SEND_OUR_IP_ADDRESSES */
-
-/* Indexes into status string (0|1|2|3|..., but 0 always empty) */
-#define MSIM_STATUS_ORDINAL_EMPTY 0
-#define MSIM_STATUS_ORDINAL_UNKNOWNs 1
-#define MSIM_STATUS_ORDINAL_ONLINE 2
-#define MSIM_STATUS_ORDINAL_UNKNOWNss 3
-#define MSIM_STATUS_ORDINAL_HEADLINE 4
-#define MSIM_STATUS_ORDINAL_UNKNOWNls 5
-#define MSIM_STATUS_ORDINAL_UNKNOWN 6
-#define MSIM_STATUS_ORDINAL_UNKNOWN1 7
-#define MSIM_STATUS_ORDINAL_UNKNOWNp 8
-#define MSIM_STATUS_ORDINAL_UNKNOWN2 9
-
-/* Status codes - states a buddy (or you!) can be in. */
-#define MSIM_STATUS_CODE_OFFLINE_OR_HIDDEN 0
-#define MSIM_STATUS_CODE_ONLINE 1
-#define MSIM_STATUS_CODE_IDLE 2
-#define MSIM_STATUS_CODE_AWAY 5
-
-/* Inbox status bitfield values for MsimSession.inbox_status. */
-#define MSIM_INBOX_MAIL (1 << 0)
-#define MSIM_INBOX_BLOG_COMMENT (1 << 1)
-#define MSIM_INBOX_PROFILE_COMMENT (1 << 2)
-#define MSIM_INBOX_FRIEND_REQUEST (1 << 3)
-#define MSIM_INBOX_PICTURE_COMMENT (1 << 4)
-
-/* Codes for msim_got_contact_list(), to tell what to do afterwards. */
-#define MSIM_CONTACT_LIST_INITIAL_FRIENDS 0
-#define MSIM_CONTACT_LIST_IMPORT_ALL_FRIENDS 1
-#define MSIM_CONTACT_LIST_IMPORT_TOP_FRIENDS 2
-
-/* Error codes */
-#define MSIM_ERROR_INCORRECT_PASSWORD 260
-#define MSIM_ERROR_LOGGED_IN_ELSEWHERE 6
-
-/* Functions */
-gboolean msim_send_raw(MsimSession *session, const gchar *msg);
-
-gboolean msim_send_bm(MsimSession *session, const gchar *who, const gchar *text, int type);
-
-gboolean msim_we_are_logged_on(MsimSession *session);
-
-void msim_unrecognized(MsimSession *session, MsimMessage *msg, gchar *note);
-guint msim_new_reply_callback(MsimSession *session, MSIM_USER_LOOKUP_CB cb, gpointer data);
-
-#endif /* !_MYSPACE_MYSPACE_H */
diff --git a/libpurple/protocols/myspace/persist.h b/libpurple/protocols/myspace/persist.h
deleted file mode 100644
index 09712c9143..0000000000
--- a/libpurple/protocols/myspace/persist.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/* MySpaceIM Protocol Plugin, persist commands
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * 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 _MYSPACE_PERSIST_H
-#define _MYSPACE_PERSIST_H
-
-/** Command codes */
-#define MSIM_CMD_GET 1
-#define MSIM_CMD_PUT 2
-#define MSIM_CMD_DELETE 3
-
-/** Command bit fields */
-#define MSIM_CMD_BIT_CODE 255 /*< Bits specifying command code */
-#define MSIM_CMD_BIT_REPLY 256 /**< 1=reply, 0=request */
-#define MSIM_CMD_BIT_ACTION 512 /**< 1=action, 0=information */
-#define MSIM_CMD_BIT_ERROR 1024 /**< 1=error, 0=normal */
-
-/** Macros to read cmd bitfield. */
-#define MSIM_CMD_GET_CODE(x) (x & MSIM_CMD_BIT_CODE)
-#define MSIM_CMD_IS_REPLY(x) (x & MSIM_CMD_BIT_REPLY)
-#define MSIM_CMD_IS_REQUEST(x) !(x & MSIM_CMD_BIT_REPLY)
-#define MSIM_CMD_IS_ACTION(x) (x & MSIM_CMD_BIT_ACTION)
-#define MSIM_CMD_IS_INFO(x) !(x & MSIM_CMD_BIT_ACTION)
-#define MSIM_CMD_IS_ERROR(x) (x & MSIM_CMD_BIT_ERROR)
-#define MSIM_CMD_IS_NORMAL(x) !(x & MSIM_CMD_BIT_ERROR)
-
-/** Define a set of _DSN and _LID constants for a persistance request. */
-#define MSIM_PERSIST_DSN_LID(name,dsn,lid) \
- static const int name##_DSN = dsn; \
- static const int name##_LID = lid;
-
-/* Can't do this, errors:
- * persist.h:51:3: error: '#' is not followed by a macro parameter
- * In file included from myspace.c:37:
- * persist.h:56: error: expected ')' before numeric constant
- * So instead, I define const ints above.
-#define MSIM_PERSIST_DSN_LID(name,dsn,lid) \
- #define name##_DSN dsn \
- #define name##_LID lid
-#endif
-*/
-
-/** Messages to Get information dsn lid */
-MSIM_PERSIST_DSN_LID(MG_LIST_ALL_CONTACTS, 0, 1)
-MSIM_PERSIST_DSN_LID(MG_USER_INFO_BY_ID, 0, 2)
-MSIM_PERSIST_DSN_LID(MG_OWN_IM_INFO, 1, 4)
-MSIM_PERSIST_DSN_LID(MG_IM_INFO_BY_ID, 1, 17)
-MSIM_PERSIST_DSN_LID(MG_LIST_ALL_GROUPS, 2, 6)
-MSIM_PERSIST_DSN_LID(MG_MYSPACE_INFO_BY_ID, 4, 3)
-MSIM_PERSIST_DSN_LID(MG_OWN_MYSPACE_INFO, 4, 5)
-MSIM_PERSIST_DSN_LID(MG_MYSPACE_INFO_BY_STRING, 5, 7)
-MSIM_PERSIST_DSN_LID(MG_CHECK_MAIL, 7, 18)
-MSIM_PERSIST_DSN_LID(MG_WEB_CHALLENGE, 17, 26)
-MSIM_PERSIST_DSN_LID(MG_USER_SONG, 21, 28)
-MSIM_PERSIST_DSN_LID(MG_SERVER_INFO, 101, 20)
-
-/** Messages to Change/send information */
-MSIM_PERSIST_DSN_LID(MC_USER_PREFERENCES, 1, 10)
-MSIM_PERSIST_DSN_LID(MC_DELETE_CONTACT_INFO, 0, 8)
-MSIM_PERSIST_DSN_LID(MC_CONTACT_INFO, 0, 9)
-MSIM_PERSIST_DSN_LID(MC_SET_USERNAME, 9, 14)
-MSIM_PERSIST_DSN_LID(MC_IMPORT_ALL_FRIENDS, 14, 21)
-MSIM_PERSIST_DSN_LID(MC_INVITE, 16, 25)
-
-/** Messages to Delete information */
-MSIM_PERSIST_DSN_LID(MD_DELETE_BUDDY, 0, 8)
-
-/** Error codes */
-#define MERR_PARSE 1
-#define MERR_NOT_LOGGED_IN 2
-#define MERR_ANOTHER_LOGIN 6
-#define MERR_BAD_EMAIL 259
-#define MERR_BAD_PASSWORD 260
-#define MERR_BAD_UID_IN_PERSISTR 4352
-
-#endif /* !_MYSPACE_PERSIST_H */
diff --git a/libpurple/protocols/myspace/session.c b/libpurple/protocols/myspace/session.c
deleted file mode 100644
index 2d6e6c98d4..0000000000
--- a/libpurple/protocols/myspace/session.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/* MySpaceIM Protocol Plugin, session
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * 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 "myspace.h"
-
-/* Session methods */
-
-/**
- * Create a new MSIM session.
- *
- * @param acct The account to create the session from.
- *
- * @return Pointer to a new session. Free with msim_session_destroy.
- */
-MsimSession *
-msim_session_new(PurpleAccount *acct)
-{
- MsimSession *session;
-
- g_return_val_if_fail(acct != NULL, NULL);
-
- session = g_new0(MsimSession, 1);
-
- session->magic = MSIM_SESSION_STRUCT_MAGIC;
- session->account = acct;
- session->gc = purple_account_get_connection(acct);
- session->sesskey = 0;
- session->userid = 0;
- session->username = NULL;
- session->fd = -1;
-
- /* TODO: Remove. */
- session->user_lookup_cb = g_hash_table_new_full(g_direct_hash,
- g_direct_equal, NULL, NULL); /* do NOT free function pointers! (values) */
- session->user_lookup_cb_data = g_hash_table_new_full(g_direct_hash,
- g_direct_equal, NULL, NULL);/* TODO: we don't know what the values are,
- they could be integers inside gpointers
- or strings, so I don't freed them.
- Figure this out, once free cache. */
-
- /* Created in msim_process_server_info() */
- session->server_info = NULL;
-
- session->rxoff = 0;
- session->rxsize = MSIM_READ_BUF_SIZE;
- session->rxbuf = g_new0(gchar, session->rxsize);
- session->next_rid = 1;
- session->last_comm = time(NULL);
- session->inbox_status = 0;
- session->inbox_handle = 0;
-
- return session;
-}
-
-/**
- * Free a session.
- *
- * @param session The session to destroy.
- */
-void
-msim_session_destroy(MsimSession *session)
-{
- session->magic = -1;
-
- g_free(session->rxbuf);
- g_free(session->username);
-
- /* TODO: Remove. */
- g_hash_table_destroy(session->user_lookup_cb);
- g_hash_table_destroy(session->user_lookup_cb_data);
-
- if (session->server_info) {
- msim_msg_free(session->server_info);
- }
-
- /* Stop checking the inbox at the end of the session. */
- if (session->inbox_handle) {
- purple_timeout_remove(session->inbox_handle);
- }
-
- g_free(session);
-}
diff --git a/libpurple/protocols/myspace/session.h b/libpurple/protocols/myspace/session.h
deleted file mode 100644
index 34e1ba96cd..0000000000
--- a/libpurple/protocols/myspace/session.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* MySpaceIM Protocol Plugin, session
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * 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 _MYSPACE_SESSION_H
-#define _MYSPACE_SESSION_H
-
-#include "account.h"
-
-/* Random number in every MsimSession, to ensure it is valid. */
-#define MSIM_SESSION_STRUCT_MAGIC 0xe4a6752b
-
-/* Everything needed to keep track of a session (proto_data field in PurpleConnection) */
-typedef struct _MsimSession
-{
- guint magic; /**< MSIM_SESSION_STRUCT_MAGIC */
- PurpleAccount *account;
- PurpleConnection *gc;
- guint sesskey; /**< Session key from server */
- guint userid; /**< This user's numeric user ID */
- gchar *username; /**< This user's unique username */
- gboolean show_only_to_list;
- int privacy_mode; /**< This is a bitmask */
- int offline_message_mode;
- gint fd; /**< File descriptor to/from server */
-
- /* TODO: Remove. */
- GHashTable *user_lookup_cb; /**< Username -> userid lookup callback */
- GHashTable *user_lookup_cb_data; /**< Username -> userid lookup callback data */
-
- MsimMessage *server_info; /**< Parameters from server */
-
- gchar *rxbuf; /**< Receive buffer */
- guint rxoff; /**< Receive buffer offset */
- guint rxsize; /**< Receive buffer size */
- guint next_rid; /**< Next request/response ID */
- time_t last_comm; /**< Time received last communication */
- guint inbox_status; /**< Bit field of inbox notifications */
- guint inbox_handle; /**< The handle for the mail check timer */
-} MsimSession;
-
-MsimSession *msim_session_new(PurpleAccount *acct);
-void msim_session_destroy(MsimSession *session);
-
-#endif /* !_MYSPACE_SESSION_H */
diff --git a/libpurple/protocols/myspace/user.c b/libpurple/protocols/myspace/user.c
deleted file mode 100644
index a2b65fc972..0000000000
--- a/libpurple/protocols/myspace/user.c
+++ /dev/null
@@ -1,892 +0,0 @@
-/* MySpaceIM Protocol Plugin, header file
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * 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 "myspace.h"
-
-static void msim_check_username_availability_cb(PurpleConnection *gc, const char *username_to_check);
-
-static char *msim_username_to_set;
-
-/**
- * Format the "now playing" indicator, showing the artist and song.
- *
- * @return Return a new string (must be g_free()'d), or NULL.
- */
-static gchar *
-msim_format_now_playing(const gchar *band, const gchar *song)
-{
- if ((band && *band) || (song && *song)) {
- return g_strdup_printf("%s - %s",
- (band && *band) ? band : "Unknown Artist",
- (song && *song) ? song : "Unknown Song");
- } else {
- return NULL;
- }
-}
-
-/**
- * Get the MsimUser from a PurpleBuddy, optionally creating it if needed.
- */
-MsimUser *
-msim_get_user_from_buddy(PurpleBuddy *buddy, gboolean create)
-{
- MsimUser *user;
-
- if (!buddy) {
- return NULL;
- }
-
- user = purple_buddy_get_protocol_data(buddy);
- if (create && !user) {
- PurpleBlistNode *node = PURPLE_BLIST_NODE(buddy);
-
- /* No MsimUser for this buddy; make one. */
-
- user = g_new0(MsimUser, 1);
- user->buddy = buddy;
- user->id = purple_blist_node_get_int(node, "UserID");
- purple_buddy_set_protocol_data(buddy, user);
- }
-
- return user;
-}
-
-void msim_user_free(MsimUser *user)
-{
- if (!user)
- return;
-
- if (user->url_data != NULL)
- purple_util_fetch_url_cancel(user->url_data);
-
- g_free(user->client_info);
- g_free(user->gender);
- g_free(user->location);
- g_free(user->headline);
- g_free(user->display_name);
- g_free(user->username);
- g_free(user->band_name);
- g_free(user->song_name);
- g_free(user->image_url);
- g_free(user);
-}
-
-/**
- * Find and return an MsimUser * representing a user on the buddy list, or NULL.
- */
-MsimUser *
-msim_find_user(MsimSession *session, const gchar *username)
-{
- PurpleBuddy *buddy;
-
- buddy = purple_find_buddy(session->account, username);
- if (!buddy) {
- return NULL;
- }
-
- return msim_get_user_from_buddy(buddy, TRUE);
-}
-
-/**
- * Append user information to a PurpleNotifyUserInfo, given an MsimUser.
- * Used by msim_tooltip_text() and msim_get_info_cb() to show a user's profile.
- */
-void
-msim_append_user_info(MsimSession *session, PurpleNotifyUserInfo *user_info, MsimUser *user, gboolean full)
-{
- PurplePresence *presence;
- gchar *str;
- guint cv;
-
- /* Useful to identify the account the tooltip refers to.
- * Other prpls show this. */
- if (user->username) {
- purple_notify_user_info_add_pair(user_info, _("User"), user->username);
- }
-
- /* a/s/l...the vitals */
- if (user->age) {
- char age[16];
- g_snprintf(age, sizeof(age), "%d", user->age);
- purple_notify_user_info_add_pair(user_info, _("Age"), age);
- }
-
- if (user->gender && *user->gender) {
- purple_notify_user_info_add_pair(user_info, _("Gender"), user->gender);
- }
-
- if (user->location && *user->location) {
- purple_notify_user_info_add_pair(user_info, _("Location"), user->location);
- }
-
- /* Other information */
- if (user->headline && *user->headline) {
- purple_notify_user_info_add_pair(user_info, _("Headline"), user->headline);
- }
-
- if (user->buddy != NULL) {
- presence = purple_buddy_get_presence(user->buddy);
-
- if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) {
- PurpleStatus *status;
- const char *artist, *title;
-
- status = purple_presence_get_status(presence, "tune");
- title = purple_status_get_attr_string(status, PURPLE_TUNE_TITLE);
- artist = purple_status_get_attr_string(status, PURPLE_TUNE_ARTIST);
-
- str = msim_format_now_playing(artist, title);
- if (str && *str) {
- purple_notify_user_info_add_pair(user_info, _("Song"), str);
- }
- g_free(str);
- }
- }
-
- /* Note: total friends only available if looked up by uid, not username. */
- if (user->total_friends) {
- char friends[16];
- g_snprintf(friends, sizeof(friends), "%d", user->total_friends);
- purple_notify_user_info_add_pair(user_info, _("Total Friends"), friends);
- }
-
- if (full) {
- /* Client information */
- char *client = NULL;
-
- str = user->client_info;
- cv = user->client_cv;
-
- if (str && cv != 0) {
- client = g_strdup_printf("%s (build %d)", str, cv);
- } else if (str) {
- client = g_strdup(str);
- } else if (cv) {
- client = g_strdup_printf("Build %d", cv);
- }
- if (client && *client)
- purple_notify_user_info_add_pair(user_info, _("Client Version"), client);
- g_free(client);
- }
-
- if (full && user->id) {
- /* TODO: link to username, if available */
- char *profile;
- purple_notify_user_info_add_section_break(user_info);
- if (user->buddy != NULL)
- profile = g_strdup_printf("<a href=\"http://myspace.com/%s\">%s</a>",
- purple_buddy_get_name(user->buddy), _("View web profile"));
- else
- profile = g_strdup_printf("<a href=\"http://myspace.com/%d\">%s</a>",
- user->id, _("View web profile"));
- purple_notify_user_info_add_pair(user_info, NULL, profile);
- g_free(profile);
- }
-}
-
-/**
- * Callback for when a buddy icon finished being downloaded.
- */
-static void
-msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data,
- gpointer user_data,
- const gchar *url_text,
- gsize len,
- const gchar *error_message)
-{
- MsimUser *user = (MsimUser *)user_data;
- const char *name = purple_buddy_get_name(user->buddy);
- PurpleAccount *account;
-
- user->url_data = NULL;
-
- purple_debug_info("msim_downloaded_buddy_icon",
- "Downloaded %" G_GSIZE_FORMAT " bytes\n", len);
-
- if (!url_text) {
- purple_debug_info("msim_downloaded_buddy_icon",
- "failed to download icon for %s",
- name);
- return;
- }
-
- account = purple_buddy_get_account(user->buddy);
- purple_buddy_icons_set_for_user(account, name,
- g_memdup((gchar *)url_text, len), len,
- /* Use URL itself as buddy icon "checksum" (TODO: ETag) */
- user->image_url); /* checksum */
-}
-
-/**
- * Set the currently playing song artist and or title.
- *
- * @param user User associated with the now playing information.
- *
- * @param new_artist New artist to set, or NULL/empty to not change artist.
- *
- * @param new_title New title to set, or NULL/empty to not change title.
- *
- * If new_artist and new_title are NULL/empty, deactivate PURPLE_STATUS_TUNE.
- *
- * This function is useful because it lets you set the artist or title
- * individually, which purple_prpl_got_user_status() doesn't do.
- */
-static void msim_set_artist_or_title(MsimUser *user, const char *new_artist, const char *new_title)
-{
- PurplePresence *presence;
- PurpleAccount *account;
- const char *prev_artist, *prev_title;
- const char *name;
-
- if (user->buddy == NULL)
- /* User not on buddy list so nothing to do */
- return;
-
- prev_artist = NULL;
- prev_title = NULL;
-
- if (new_artist && !*new_artist)
- new_artist = NULL;
- if (new_title && !*new_title)
- new_title = NULL;
-
- account = purple_buddy_get_account(user->buddy);
- name = purple_buddy_get_name(user->buddy);
-
- if (!new_artist && !new_title) {
- purple_prpl_got_user_status_deactive(account, name, "tune");
- return;
- }
-
- presence = purple_buddy_get_presence(user->buddy);
-
- if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) {
- PurpleStatus *status;
-
- status = purple_presence_get_status(presence, "tune");
- prev_title = purple_status_get_attr_string(status, PURPLE_TUNE_TITLE);
- prev_artist = purple_status_get_attr_string(status, PURPLE_TUNE_ARTIST);
- }
-
- if (!new_artist)
- new_artist = prev_artist;
-
- if (!new_title)
- new_title = prev_title;
-
- purple_prpl_got_user_status(account, name, "tune",
- PURPLE_TUNE_TITLE, new_title,
- PURPLE_TUNE_ARTIST, new_artist,
- NULL);
-}
-
-/**
- * Store a field of information about a buddy.
- *
- * @param key_str Key to store.
- * @param value_str Value string, either user takes ownership of this string
- * or it is freed if MsimUser doesn't store the string.
- * @param user User to store data in. Existing data will be replaced.
- */
-static void
-msim_store_user_info_each(const gchar *key_str, gchar *value_str, MsimUser *user)
-{
- const char *name = user->buddy ? purple_buddy_get_name(user->buddy) : NULL;
-
- if (g_str_equal(key_str, "UserID") || g_str_equal(key_str, "ContactID")) {
- /* Save to buddy list, if it exists, for quick cached uid lookup with msim_uid2username_from_blist(). */
- user->id = atol(value_str);
- g_free(value_str);
- if (user->buddy)
- {
- purple_debug_info("msim", "associating uid %s with username %s\n", key_str, name);
- purple_blist_node_set_int(PURPLE_BLIST_NODE(user->buddy), "UserID", user->id);
- }
- /* Need to store in MsimUser, too? What if not on blist? */
- } else if (g_str_equal(key_str, "Age")) {
- user->age = atol(value_str);
- g_free(value_str);
- } else if (g_str_equal(key_str, "Gender")) {
- g_free(user->gender);
- user->gender = value_str;
- } else if (g_str_equal(key_str, "Location")) {
- g_free(user->location);
- user->location = value_str;
- } else if (g_str_equal(key_str, "TotalFriends")) {
- user->total_friends = atol(value_str);
- g_free(value_str);
- } else if (g_str_equal(key_str, "DisplayName")) {
- g_free(user->display_name);
- user->display_name = value_str;
- } else if (g_str_equal(key_str, "BandName")) {
- msim_set_artist_or_title(user, value_str, NULL);
- g_free(value_str);
- } else if (g_str_equal(key_str, "SongName")) {
- msim_set_artist_or_title(user, NULL, value_str);
- g_free(value_str);
- } else if (g_str_equal(key_str, "UserName") || g_str_equal(key_str, "IMName") || g_str_equal(key_str, "NickName")) {
- /* Ignore because PurpleBuddy knows this already */
- g_free(value_str);
- } else if (g_str_equal(key_str, "ImageURL") || g_str_equal(key_str, "AvatarURL")) {
- const gchar *previous_url;
-
- if (user->temporary_user) {
- /* This user will be destroyed soon; don't try to look up its image or avatar,
- * since that won't return immediately and we will end up accessing freed data.
- */
- g_free(value_str);
- return;
- }
-
- g_free(user->image_url);
-
- user->image_url = value_str;
-
- /* Instead of showing 'no photo' picture, show nothing. */
- if (g_str_equal(user->image_url, "http://x.myspace.com/images/no_pic.gif"))
- {
- purple_buddy_icons_set_for_user(purple_buddy_get_account(user->buddy),
- name, NULL, 0, NULL);
- return;
- }
-
- /* TODO: use ETag for checksum */
- previous_url = purple_buddy_icons_get_checksum_for_user(user->buddy);
-
- /* Only download if URL changed */
- if (!previous_url || !g_str_equal(previous_url, user->image_url)) {
- if (user->url_data != NULL)
- purple_util_fetch_url_cancel(user->url_data);
- user->url_data = purple_util_fetch_url(user->image_url, TRUE, NULL, TRUE, msim_downloaded_buddy_icon, (gpointer)user);
- }
- } else if (g_str_equal(key_str, "LastImageUpdated")) {
- /* TODO: use somewhere */
- user->last_image_updated = atol(value_str);
- g_free(value_str);
- } else if (g_str_equal(key_str, "Headline")) {
- g_free(user->headline);
- user->headline = value_str;
- } else {
- /* TODO: other fields in MsimUser */
- gchar *msg;
-
- msg = g_strdup_printf("msim_store_user_info_each: unknown field %s=%s",
- key_str, value_str);
- g_free(value_str);
-
- msim_unrecognized(NULL, NULL, msg);
-
- g_free(msg);
- }
-}
-
-/**
- * Save buddy information to the buddy list from a user info reply message.
- *
- * @param session
- * @param msg The user information reply, with any amount of information.
- * @param user The structure to save to, or NULL to save in PurpleBuddy->proto_data.
- *
- * Variable information is saved to the passed MsimUser structure. Permanent
- * information (UserID) is stored in the blist node of the buddy list (and
- * ends up in blist.xml, persisted to disk) if it exists.
- *
- * If the function has no buddy information, this function
- * is a no-op (and returns FALSE).
- */
-gboolean
-msim_store_user_info(MsimSession *session, const MsimMessage *msg, MsimUser *user)
-{
- gchar *username;
- MsimMessage *body, *body_node;
-
- g_return_val_if_fail(msg != NULL, FALSE);
-
- body = msim_msg_get_dictionary(msg, "body");
- if (!body) {
- return FALSE;
- }
-
- if (msim_msg_get_integer(msg, "dsn") == (guint)MG_OWN_IM_INFO_DSN &&
- msim_msg_get_integer(msg, "lid") == (guint)MG_OWN_IM_INFO_LID)
- {
- /*
- * Some of this info will be available on the buddy list if the
- * user has themselves as their own buddy.
- *
- * Much of the info is already available in MsimSession,
- * stored in msim_we_are_logged_on().
- */
- gchar *tmpstr;
-
- tmpstr = msim_msg_get_string(body, "ShowOnlyToList");
- if (tmpstr != NULL) {
- session->show_only_to_list = g_str_equal(tmpstr, "True");
- g_free(tmpstr);
- }
-
- session->privacy_mode = msim_msg_get_integer(body, "PrivacyMode");
- session->offline_message_mode = msim_msg_get_integer(body, "OfflineMessageMode");
-
- msim_send(session,
- "blocklist", MSIM_TYPE_BOOLEAN, TRUE,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "idlist", MSIM_TYPE_STRING,
- g_strdup_printf("w%d|c%d",
- session->show_only_to_list ? 1 : 0,
- session->privacy_mode & 1),
- NULL);
- } else if (msim_msg_get_integer(msg, "dsn") == (guint)MG_OWN_MYSPACE_INFO_DSN &&
- msim_msg_get_integer(msg, "lid") == (guint)MG_OWN_MYSPACE_INFO_LID) {
- /* TODO: same as above, but for MySpace info. */
- }
-
- username = msim_msg_get_string(body, "UserName");
-
- if (!username) {
- purple_debug_info("msim",
- "msim_process_reply: not caching body, no UserName\n");
- msim_msg_free(body);
- g_free(username);
- return FALSE;
- }
-
- /* Null user = find and store in PurpleBuddy's proto_data */
- if (!user) {
- user = msim_find_user(session, username);
- if (!user) {
- msim_msg_free(body);
- g_free(username);
- return FALSE;
- }
- }
-
- /* TODO: make looping over MsimMessage's easier. */
- for (body_node = body;
- body_node != NULL;
- body_node = msim_msg_get_next_element_node(body_node))
- {
- const gchar *key_str;
- gchar *value_str;
- MsimMessageElement *elem;
-
- elem = (MsimMessageElement *)body_node->data;
- key_str = elem->name;
-
- value_str = msim_msg_get_string_from_element(elem);
- msim_store_user_info_each(key_str, value_str, user);
- }
-
- msim_msg_free(body);
- g_free(username);
-
- return TRUE;
-}
-
-#if 0
-/**
- * Return whether a given username is syntactically valid.
- * Note: does not actually check that the user exists.
- */
-static gboolean
-msim_is_valid_username(const gchar *user)
-{
- return !msim_is_userid(user) && /* Not all numeric */
- strlen(user) <= MSIM_MAX_USERNAME_LENGTH
- && strspn(user, "0123456789"
- "abcdefghijklmnopqrstuvwxyz"
- "_"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ") == strlen(user);
-}
-#endif
-
-/**
- * Check if a string is a userid (all numeric).
- *
- * @param user The user id, email, or name.
- *
- * @return TRUE if is userid, FALSE if not.
- */
-gboolean
-msim_is_userid(const gchar *user)
-{
- g_return_val_if_fail(user != NULL, FALSE);
-
- return strspn(user, "0123456789") == strlen(user);
-}
-
-/**
- * Check if a string is an email address (contains an @).
- *
- * @param user The user id, email, or name.
- *
- * @return TRUE if is an email, FALSE if not.
- *
- * This function is not intended to be used as a generic
- * means of validating email addresses, but to distinguish
- * between a user represented by an email address from
- * other forms of identification.
- */
-static gboolean
-msim_is_email(const gchar *user)
-{
- g_return_val_if_fail(user != NULL, FALSE);
-
- return strchr(user, '@') != NULL;
-}
-
-/**
- * Asynchronously lookup user information, calling callback when receive result.
- *
- * @param session
- * @param user The user id, email address, or username. Not freed.
- * @param cb Callback, called with user information when available.
- * @param data An arbitray data pointer passed to the callback.
- */
-/* TODO: change to not use callbacks */
-void
-msim_lookup_user(MsimSession *session, const gchar *user, MSIM_USER_LOOKUP_CB cb, gpointer data)
-{
- MsimMessage *body;
- gchar *field_name;
- guint rid, dsn, lid;
-
- g_return_if_fail(user != NULL);
- /* Callback can be null to not call anything, just lookup & store information. */
- /*g_return_if_fail(cb != NULL);*/
-
- purple_debug_info("msim", "msim_lookup_userid: "
- "asynchronously looking up <%s>\n", user);
-
- /* Setup callback. Response will be associated with request using 'rid'. */
- rid = msim_new_reply_callback(session, cb, data);
-
- /* Send request */
-
- if (msim_is_userid(user)) {
- field_name = "UserID";
- dsn = MG_MYSPACE_INFO_BY_ID_DSN;
- lid = MG_MYSPACE_INFO_BY_ID_LID;
- } else if (msim_is_email(user)) {
- field_name = "Email";
- dsn = MG_MYSPACE_INFO_BY_STRING_DSN;
- lid = MG_MYSPACE_INFO_BY_STRING_LID;
- } else {
- field_name = "UserName";
- dsn = MG_MYSPACE_INFO_BY_STRING_DSN;
- lid = MG_MYSPACE_INFO_BY_STRING_LID;
- }
-
- body = msim_msg_new(
- field_name, MSIM_TYPE_STRING, g_strdup(user),
- NULL);
-
- g_return_if_fail(msim_send(session,
- "persist", MSIM_TYPE_INTEGER, 1,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_GET,
- "dsn", MSIM_TYPE_INTEGER, dsn,
- "uid", MSIM_TYPE_INTEGER, session->userid,
- "lid", MSIM_TYPE_INTEGER, lid,
- "rid", MSIM_TYPE_INTEGER, rid,
- "body", MSIM_TYPE_DICTIONARY, body,
- NULL));
-}
-
-/**
- * Called after username is set.
- */
-static void msim_username_is_set_cb(MsimSession *session, const MsimMessage *userinfo, gpointer data)
-{
- gchar *username;
- const gchar *errmsg;
- MsimMessage *body;
-
- guint rid;
- gint cmd,dsn,lid,code;
- /* \persistr\\cmd\258\dsn\9\uid\204084363\lid\14\rid\369\body\UserName=TheAlbinoRhino1.Code=0\final\ */
-
- purple_debug_info("msim","username_is_set made\n");
-
- cmd = msim_msg_get_integer(userinfo, "cmd");
- dsn = msim_msg_get_integer(userinfo, "dsn");
-#if 0
- uid = msim_msg_get_integer(userinfo, "uid");
-#endif
- lid = msim_msg_get_integer(userinfo, "lid");
- body = msim_msg_get_dictionary(userinfo, "body");
- errmsg = _("An error occurred while trying to set the username. "
- "Please try again, or visit http://editprofile.myspace.com/index.cfm?"
- "fuseaction=profile.username to set your username.");
-
- if (!body) {
- purple_debug_info("msim_username_is_set_cb", "No body");
- /* Error: No body! */
- purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg);
- }
- username = msim_msg_get_string(body, "UserName");
- code = msim_msg_get_integer(body,"Code");
-
- msim_msg_free(body);
-
- purple_debug_info("msim_username_is_set_cb",
- "cmd = %d, dsn = %d, lid = %d, code = %d, username = %s\n",
- cmd, dsn, lid, code, username);
-
- if (cmd == (MSIM_CMD_BIT_REPLY | MSIM_CMD_PUT)
- && dsn == MC_SET_USERNAME_DSN
- && lid == MC_SET_USERNAME_LID)
- {
- purple_debug_info("msim_username_is_set_cb", "Proper cmd,dsn,lid for username_is_set!\n");
- purple_debug_info("msim_username_is_set_cb", "Username Set with return code %d\n",code);
- if (code == 0) {
- /* Good! */
- session->username = username;
- msim_we_are_logged_on(session);
- } else {
- purple_debug_info("msim_username_is_set", "code is %d",code);
- /* TODO: what to do here? */
- }
- } else if (cmd == (MSIM_CMD_BIT_REPLY | MSIM_CMD_GET)
- && dsn == MG_MYSPACE_INFO_BY_STRING_DSN
- && lid == MG_MYSPACE_INFO_BY_STRING_LID) {
- /* Not quite done... ONE MORE STEP :) */
- rid = msim_new_reply_callback(session, msim_username_is_set_cb, data);
- body = msim_msg_new("UserName", MSIM_TYPE_STRING, g_strdup(username), NULL);
- if (!msim_send(session, "persist", MSIM_TYPE_INTEGER, 1,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_PUT,
- "dsn", MSIM_TYPE_INTEGER, MC_SET_USERNAME_DSN,
- "uid", MSIM_TYPE_INTEGER, session->userid,
- "lid", MSIM_TYPE_INTEGER, MC_SET_USERNAME_LID,
- "rid", MSIM_TYPE_INTEGER, rid,
- "body", MSIM_TYPE_DICTIONARY, body,
- NULL)) {
- /* Error! */
- /* Can't set... Disconnect */
- purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg);
- }
-
- } else {
- /* Error! */
- purple_debug_info("msim","username_is_set Error: Invalid cmd/dsn/lid combination");
- purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg);
- }
-}
-
-/**
- * Asynchronously set new username, calling callback when receive result.
- *
- * @param session
- * @param username The username we're setting for ourselves. Not freed.
- * @param cb Callback, called with user information when available.
- * @param data An arbitray data pointer passed to the callback.
- */
-static void
-msim_set_username(MsimSession *session, const gchar *username,
- MSIM_USER_LOOKUP_CB cb, gpointer data)
-{
- MsimMessage *body;
- guint rid;
-
- g_return_if_fail(username != NULL);
- g_return_if_fail(cb != NULL);
-
- purple_debug_info("msim", "msim_set_username: "
- "Setting username %s\n", username);
-
- /* Setup callback. Response will be associated with request using 'rid'. */
- rid = msim_new_reply_callback(session, cb, data);
-
- /* TODO: I dont know if the ContactType is -/ALWAYS/- 1 */
-
- body = msim_msg_new("UserName", MSIM_TYPE_STRING, g_strdup(username),NULL);
-/* \setinfo\\sesskey\469958979\info\Age=21.AvatarUrl=.BandName=.ContactType=1.DisplayName=Msim.Gender=M.ImageURL=http:/1/1x.myspace.com/1images/1no_pic.gif.LastLogin=128335268400000000.Location=US.ShowAvatar=False.SongName=.TotalFriends=1.UserName=msimprpl2\final\
-*/
-
- /* Send request */
- g_return_if_fail(msim_send(session,
- "setinfo", MSIM_TYPE_BOOLEAN, TRUE,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "info", MSIM_TYPE_DICTIONARY, body,
- NULL));
- body = msim_msg_new("UserName", MSIM_TYPE_STRING, g_strdup(username),NULL);
- g_return_if_fail(msim_send(session,
- "persist", MSIM_TYPE_INTEGER, 1,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_GET,
- "dsn", MSIM_TYPE_INTEGER, MG_MYSPACE_INFO_BY_STRING_DSN,
- "uid", MSIM_TYPE_INTEGER, session->userid,
- "lid", MSIM_TYPE_INTEGER, MG_MYSPACE_INFO_BY_STRING_LID,
- "rid", MSIM_TYPE_INTEGER, rid,
- "body", MSIM_TYPE_DICTIONARY, body,
- NULL));
-}
-
-/**
- * They've confirmed that username that was available, Lets make the call to set it
- */
-static void msim_set_username_confirmed_cb(PurpleConnection *gc)
-{
- MsimMessage *user_msg;
- MsimSession *session;
-
- g_return_if_fail(gc != NULL);
-
- session = (MsimSession *)gc->proto_data;
-
- user_msg = msim_msg_new(
- "user", MSIM_TYPE_STRING, g_strdup(msim_username_to_set),
- NULL);
-
- purple_debug_info("msim_set_username_confirmed_cb", "Setting username to %s\n", msim_username_to_set);
-
- /* Sets our username... keep your fingers crossed :) */
- msim_set_username(session, msim_username_to_set, msim_username_is_set_cb, user_msg);
- g_free(msim_username_to_set);
-}
-
-/**
- * This is where we do a bit more than merely prompt the user.
- * Now we have some real data to tell us the state of their requested username
- * \persistr\\cmd\257\dsn\5\uid\204084363\lid\7\rid\367\body\UserName=TheAlbinoRhino1\final\
- */
-static void msim_username_is_available_cb(MsimSession *session, const MsimMessage *userinfo, gpointer data)
-{
- MsimMessage *msg;
- gchar *username;
- MsimMessage *body;
- gint userid;
-
- purple_debug_info("msim_username_is_available_cb", "Look up username callback made\n");
-
- msg = (MsimMessage *)data;
- g_return_if_fail(msg != NULL);
-
- username = msim_msg_get_string(msg, "user");
- body = msim_msg_get_dictionary(userinfo, "body");
-
- if (!body) {
- purple_debug_info("msim_username_is_available_cb", "No body for %s?!\n", username);
- purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
- _("An error occurred while trying to set the username. "
- "Please try again, or visit http://editprofile.myspace.com/index.cfm?"
- "fuseaction=profile.username to set your username."));
- return;
- }
-
- userid = msim_msg_get_integer(body, "UserID");
-
- purple_debug_info("msim_username_is_available_cb", "Returned username is %s and userid is %d\n", username, userid);
- msim_msg_free(body);
- msim_msg_free(msg);
-
- /* The response for a free username will ONLY have the UserName in it..
- * thus making UserID return 0 when we msg_get_integer it */
- if (userid == 0) {
- /* This username is currently unused */
- purple_debug_info("msim_username_is_available_cb", "Username available. Prompting to Confirm.\n");
- msim_username_to_set = g_strdup(username);
- g_free(username);
- purple_request_yes_no(session->gc,
- _("MySpaceIM - Username Available"),
- _("This username is available. Would you like to set it?"),
- _("ONCE SET, THIS CANNOT BE CHANGED!"),
- 0,
- session->account,
- NULL,
- NULL,
- session->gc,
- G_CALLBACK(msim_set_username_confirmed_cb),
- G_CALLBACK(msim_do_not_set_username_cb));
- } else {
- /* Looks like its in use or we have an invalid response */
- purple_debug_info("msim_username_is_available_cb", "Username unavaiable. Prompting for new entry.\n");
- purple_request_input(session->gc, _("MySpaceIM - Please Set a Username"),
- _("This username is unavailable."),
- _("Please try another username:"),
- "", FALSE, FALSE, NULL,
- _("OK"), G_CALLBACK(msim_check_username_availability_cb),
- _("Cancel"), G_CALLBACK(msim_do_not_set_username_cb),
- session->account,
- NULL,
- NULL,
- session->gc);
- }
-}
-
-/**
- * Once they've submitted their desired new username,
- * check if it is available here.
- */
-static void msim_check_username_availability_cb(PurpleConnection *gc, const char *username_to_check)
-{
- MsimMessage *user_msg;
- MsimSession *session;
-
- g_return_if_fail(gc != NULL);
-
- session = (MsimSession *)gc->proto_data;
-
- purple_debug_info("msim_check_username_availability_cb", "Checking username: %s\n", username_to_check);
-
- user_msg = msim_msg_new(
- "user", MSIM_TYPE_STRING, g_strdup(username_to_check),
- NULL);
-
- /* 25 characters: letters, numbers, underscores */
- /* TODO: VERIFY ABOVE */
-
- /* \persist\1\sesskey\288500516\cmd\1\dsn\5\uid\204084363\lid\7\rid\367\body\UserName=Jaywalker\final\ */
- /* Official client uses a standard lookup... So do we! */
- msim_lookup_user(session, username_to_check, msim_username_is_available_cb, user_msg);
-}
-
-/***
- * If they hit cancel or no at any point in the Setting Username process,
- * we come here. Currently we're safe letting them get by without
- * setting it, unless we hear otherwise. So for now give them a menu.
- * If this becomes an issue with the official client then boot them here.
- */
-void msim_do_not_set_username_cb(PurpleConnection *gc)
-{
- purple_debug_info("msim", "Don't set username");
-
- /* Protocol won't log in now without a username set.. Disconnect */
- purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("No username set"));
-}
-
-/**
- * They've decided to set a username! Yay!
- */
-void msim_set_username_cb(PurpleConnection *gc)
-{
- g_return_if_fail(gc != NULL);
- purple_debug_info("msim","Set username\n");
- purple_request_input(gc, _("MySpaceIM - Please Set a Username"),
- _("Please enter a username to check its availability:"),
- NULL,
- "", FALSE, FALSE, NULL,
- _("OK"), G_CALLBACK(msim_check_username_availability_cb),
- _("Cancel"), G_CALLBACK(msim_do_not_set_username_cb),
- purple_connection_get_account(gc),
- NULL,
- NULL,
- gc);
-}
diff --git a/libpurple/protocols/myspace/user.h b/libpurple/protocols/myspace/user.h
deleted file mode 100644
index acc0c2604d..0000000000
--- a/libpurple/protocols/myspace/user.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* MySpaceIM Protocol Plugin, header file
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * 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 _MYSPACE_USER_H
-#define _MYSPACE_USER_H
-
-/* Hold ephemeral information about buddies, for proto_data of PurpleBuddy. */
-/* GHashTable? */
-typedef struct _MsimUser
-{
- PurpleBuddy *buddy;
- /* Note: id is also &buddy->node (set_blist_node_int), when buddy is non-NULL */
- int id;
- guint client_cv;
- gchar *client_info;
- guint age;
- gchar *gender;
- gchar *location;
- guint total_friends;
- gchar *headline;
- gchar *display_name;
- gchar *username;
- gchar *band_name, *song_name;
- gchar *image_url;
- guint last_image_updated;
- gboolean temporary_user;
- PurpleUtilFetchUrlData *url_data;
-} MsimUser;
-
-/* Callback function pointer type for when a user's information is received,
- * initiated from a user lookup. */
-typedef void (*MSIM_USER_LOOKUP_CB)(MsimSession *session, const MsimMessage *userinfo, gpointer data);
-
-MsimUser *msim_get_user_from_buddy(PurpleBuddy *buddy, gboolean create);
-void msim_user_free(MsimUser *user);
-MsimUser *msim_find_user(MsimSession *session, const gchar *username);
-void msim_append_user_info(MsimSession *session, PurpleNotifyUserInfo *user_info, MsimUser *user, gboolean full);
-gboolean msim_store_user_info(MsimSession *session, const MsimMessage *msg, MsimUser *user);
-gboolean msim_is_userid(const gchar *user);
-void msim_lookup_user(MsimSession *session, const gchar *user, MSIM_USER_LOOKUP_CB cb, gpointer data);
-void msim_set_username_cb(PurpleConnection *gc);
-void msim_do_not_set_username_cb(PurpleConnection *gc);
-
-#endif /* !_MYSPACE_USER_H */
diff --git a/libpurple/protocols/myspace/zap.c b/libpurple/protocols/myspace/zap.c
deleted file mode 100644
index 509b48949d..0000000000
--- a/libpurple/protocols/myspace/zap.c
+++ /dev/null
@@ -1,245 +0,0 @@
-/* MySpaceIM Protocol Plugin - zap support
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * 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 "myspace.h"
-#include "zap.h"
-
-/** Get zap types. */
-GList *
-msim_attention_types(PurpleAccount *acct)
-{
- static GList *types = NULL;
- PurpleAttentionType* attn;
-
- if (!types) {
-#define _MSIM_ADD_NEW_ATTENTION(icn, ulname, nme, incoming, outgoing) \
- attn = purple_attention_type_new(ulname, nme, incoming, outgoing); \
- purple_attention_type_set_icon_name(attn, icn); \
- types = g_list_append(types, attn);
-
- /* TODO: icons for each zap */
-
- /* Lots of comments for translators: */
-
- /* Zap means "to strike suddenly and forcefully as if with a
- * projectile or weapon." This term often has an electrical
- * connotation, for example, "he was zapped by electricity when
- * he put a fork in the toaster." */
- _MSIM_ADD_NEW_ATTENTION(NULL, "Zap", _("Zap"), _("%s has zapped you!"),
- _("Zapping %s..."));
-
- /* Whack means "to hit or strike someone with a sharp blow" */
- _MSIM_ADD_NEW_ATTENTION(NULL, "Whack", _("Whack"),
- _("%s has whacked you!"), _("Whacking %s..."));
-
- /* Torch means "to set on fire." Don't worry, this doesn't
- * make a whole lot of sense in English, either. Feel free
- * to translate it literally. */
- _MSIM_ADD_NEW_ATTENTION(NULL, "Torch", _("Torch"),
- _("%s has torched you!"), _("Torching %s..."));
-
- /* Smooch means "to kiss someone, often enthusiastically" */
- _MSIM_ADD_NEW_ATTENTION(NULL, "Smooch", _("Smooch"),
- _("%s has smooched you!"), _("Smooching %s..."));
-
- /* A hug is a display of affection; wrapping your arms around someone */
- _MSIM_ADD_NEW_ATTENTION(NULL, "Hug", _("Hug"), _("%s has hugged you!"),
- _("Hugging %s..."));
-
- /* Slap means "to hit someone with an open/flat hand" */
- _MSIM_ADD_NEW_ATTENTION(NULL, "Slap", _("Slap"),
- _("%s has slapped you!"), _("Slapping %s..."));
-
- /* Goose means "to pinch someone on their butt" */
- _MSIM_ADD_NEW_ATTENTION(NULL, "Goose", _("Goose"),
- _("%s has goosed you!"), _("Goosing %s..."));
-
- /* A high-five is when two people's hands slap each other
- * in the air above their heads. It is done to celebrate
- * something, often a victory, or to congratulate someone. */
- _MSIM_ADD_NEW_ATTENTION(NULL, "High-five", _("High-five"),
- _("%s has high-fived you!"), _("High-fiving %s..."));
-
- /* We're not entirely sure what the MySpace people mean by
- * this... but we think it's the equivalent of "prank." Or, for
- * someone to perform a mischievous trick or practical joke. */
- _MSIM_ADD_NEW_ATTENTION(NULL, "Punk", _("Punk"),
- _("%s has punk'd you!"), _("Punking %s..."));
-
- /* Raspberry is a slang term for the vibrating sound made
- * when you stick your tongue out of your mouth with your
- * lips closed and blow. It is typically done when
- * gloating or bragging. Nowadays it's a pretty silly
- * gesture, so it does not carry a harsh negative
- * connotation. It is generally used in a playful tone
- * with friends. */
- _MSIM_ADD_NEW_ATTENTION(NULL, "Raspberry", _("Raspberry"),
- _("%s has raspberried you!"), _("Raspberrying %s..."));
- }
-
- return types;
-}
-
-/** Send a zap to a user. */
-static gboolean
-msim_send_zap(MsimSession *session, const gchar *username, guint code)
-{
- gchar *zap_string;
- gboolean rc;
-
- g_return_val_if_fail(session != NULL, FALSE);
- g_return_val_if_fail(username != NULL, FALSE);
-
- /* Construct and send the actual zap command. */
- zap_string = g_strdup_printf("!!!ZAP_SEND!!!=RTE_BTN_ZAPS_%d", code);
-
- if (!msim_send_bm(session, username, zap_string, MSIM_BM_ACTION_OR_IM_INSTANT)) {
- purple_debug_info("msim_send_zap",
- "msim_send_bm failed: zapping %s with %s\n",
- username, zap_string);
- rc = FALSE;
- } else {
- rc = TRUE;
- }
-
- g_free(zap_string);
-
- return rc;
-}
-
-/** Send a zap */
-gboolean
-msim_send_attention(PurpleConnection *gc, const gchar *username, guint code)
-{
- GList *types;
- MsimSession *session;
- PurpleAttentionType *attn;
- PurpleBuddy *buddy;
-
- session = (MsimSession *)gc->proto_data;
-
- /* Look for this attention type, by the code index given. */
- types = msim_attention_types(gc->account);
- attn = (PurpleAttentionType *)g_list_nth_data(types, code);
-
- if (!attn) {
- purple_debug_info("msim_send_attention", "got invalid zap code %d\n", code);
- return FALSE;
- }
-
- buddy = purple_find_buddy(session->account, username);
- if (!buddy) {
- return FALSE;
- }
-
- msim_send_zap(session, username, code);
-
- return TRUE;
-}
-
-/** Zap someone. Callback from msim_blist_node_menu zap menu. */
-static void
-msim_send_zap_from_menu(PurpleBlistNode *node, gpointer zap_num_ptr)
-{
- PurpleBuddy *buddy;
- PurpleAccount *account;
- PurpleConnection *gc;
- MsimSession *session;
- guint zap;
-
- if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) {
- /* Only know about buddies for now. */
- return;
- }
-
- g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
-
- buddy = (PurpleBuddy *)node;
-
- /* Find the session */
- account = purple_buddy_get_account(buddy);
- gc = purple_account_get_connection(account);
- session = (MsimSession *)gc->proto_data;
-
- zap = GPOINTER_TO_INT(zap_num_ptr);
-
- purple_prpl_send_attention(session->gc, purple_buddy_get_name(buddy), zap);
-}
-
-/** Return menu, if any, for a buddy list node. */
-GList *
-msim_blist_node_menu(PurpleBlistNode *node)
-{
- GList *menu, *zap_menu;
- GList *types;
- PurpleMenuAction *act;
- guint i;
-
- if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) {
- /* Only know about buddies for now. */
- return NULL;
- }
-
- zap_menu = NULL;
-
- /* TODO: get rid of once is accessible directly in GUI */
- types = msim_attention_types(NULL);
- i = 0;
- for (; types; types = g_list_next(types)) {
- PurpleAttentionType *attn;
-
- attn = (PurpleAttentionType *)types->data;
-
- act = purple_menu_action_new(purple_attention_type_get_name(attn),
- PURPLE_CALLBACK(msim_send_zap_from_menu), GUINT_TO_POINTER(i), NULL);
- zap_menu = g_list_append(zap_menu, act);
-
- ++i;
- }
-
- act = purple_menu_action_new(_("Zap"), NULL, NULL, zap_menu);
- menu = g_list_append(NULL, act);
-
- return menu;
-}
-
-/** Process an incoming zap. */
-gboolean
-msim_incoming_zap(MsimSession *session, MsimMessage *msg)
-{
- gchar *msg_text, *username;
- gint zap;
-
- msg_text = msim_msg_get_string(msg, "msg");
- username = msim_msg_get_string(msg, "_username");
-
- g_return_val_if_fail(msg_text != NULL, FALSE);
- g_return_val_if_fail(username != NULL, FALSE);
-
- g_return_val_if_fail(sscanf(msg_text, "!!!ZAP_SEND!!!=RTE_BTN_ZAPS_%d", &zap) == 1, FALSE);
-
- zap = CLAMP(zap, 0, 9);
-
- purple_prpl_got_attention(session->gc, username, zap);
-
- g_free(msg_text);
- g_free(username);
-
- return TRUE;
-}
diff --git a/libpurple/protocols/myspace/zap.h b/libpurple/protocols/myspace/zap.h
deleted file mode 100644
index d6bf52c364..0000000000
--- a/libpurple/protocols/myspace/zap.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* MySpaceIM Protocol Plugin - zap support
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * 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 _MYSPACE_ZAP_H
-#define _MYSPACE_ZAP_H
-
-GList *msim_attention_types(PurpleAccount *acct);
-gboolean msim_send_attention(PurpleConnection *gc, const gchar *username, guint code);
-GList *msim_blist_node_menu(PurpleBlistNode *node);
-gboolean msim_incoming_zap(MsimSession *session, MsimMessage *msg);
-
-#endif /* !_MYSPACE_ZAP_H */
diff --git a/libpurple/prpl.h b/libpurple/prpl.h
index 9584aa370e..2a7471119e 100644
--- a/libpurple/prpl.h
+++ b/libpurple/prpl.h
@@ -922,7 +922,7 @@ GList *purple_prpl_get_statuses(PurpleAccount *account, PurplePresence *presence
* @param who Whose attention to request.
* @param type_code An index into the prpl's attention_types list determining the type
* of the attention request command to send. 0 if prpl only defines one
- * (for example, Yahoo), but some protocols define more (MySpaceIM).
+ * (for example, Yahoo), but protocols are allowed to define more.
*
* Note that you can't send arbitrary PurpleAttentionType's, because there is
* only a fixed set of attention commands.
diff --git a/libpurple/purple-url-handler b/libpurple/purple-url-handler
index 9c269abefa..74e635d909 100755
--- a/libpurple/purple-url-handler
+++ b/libpurple/purple-url-handler
@@ -224,11 +224,6 @@ def irc(uri):
channel = "#" + channel
gochat(account, {"server": server, "channel": channel, "password": params.get("key", "")}, params.get("msg"))
-def myim(uri):
- protocol = "prpl-myspace"
- print "TODO: send uri: ", uri
- assert False, "Not implemented"
-
def sip(uri):
protocol = "prpl-simple"
match = re.match(r"^sip:(.*)", uri)
@@ -353,8 +348,6 @@ def main(argv=sys.argv):
icq(uri)
elif type == "irc":
irc(uri)
- elif type == "myim":
- myim(uri)
elif type == "sip":
sip(uri)
elif type == "xmpp":
diff --git a/libpurple/server.h b/libpurple/server.h
index f2c5134624..aa10ed10bb 100644
--- a/libpurple/server.h
+++ b/libpurple/server.h
@@ -69,7 +69,7 @@ PurpleAttentionType *purple_get_attention_type_from_code(PurpleAccount *account,
* @param who Whose attention to request.
* @param type_code An index into the prpl's attention_types list determining the type
* of the attention request command to send. 0 if prpl only defines one
- * (for example, Yahoo), but some protocols define more (MySpaceIM).
+ * (for example, Yahoo), but protocols are allowed to define more.
*
* Note that you can't send arbitrary PurpleAttentionType's, because there is
* only a fixed set of attention commands.
diff --git a/pidgin/pixmaps/Makefile.am b/pidgin/pixmaps/Makefile.am
index 4b32dcad4d..8a112c0f50 100644
--- a/pidgin/pixmaps/Makefile.am
+++ b/pidgin/pixmaps/Makefile.am
@@ -225,7 +225,6 @@ PROTOCOLS_16 = \
protocols/16/irc.png \
protocols/16/jabber.png \
protocols/16/meanwhile.png \
- protocols/16/myspace.png \
protocols/16/silc.png \
protocols/16/simple.png \
protocols/16/yahoo.png \
@@ -277,7 +276,6 @@ PROTOCOLS_22 = \
protocols/22/irc.png \
protocols/22/jabber.png \
protocols/22/meanwhile.png \
- protocols/22/myspace.png \
protocols/22/silc.png \
protocols/22/simple.png \
protocols/22/yahoo.png \
@@ -293,7 +291,6 @@ PROTOCOLS_48 = \
protocols/48/irc.png \
protocols/48/jabber.png \
protocols/48/meanwhile.png \
- protocols/48/myspace.png \
protocols/48/silc.png \
protocols/48/simple.png \
protocols/48/yahoo.png \
diff --git a/pidgin/pixmaps/emotes/default/24/default.theme.in b/pidgin/pixmaps/emotes/default/24/default.theme.in
index dad4508a39..c0a7f7273b 100644
--- a/pidgin/pixmaps/emotes/default/24/default.theme.in
+++ b/pidgin/pixmaps/emotes/default/24/default.theme.in
@@ -422,39 +422,6 @@ male-fighter2.png o=> O=>
female-fighter.png o-+ O-+
yin-yang.png (%)
-
-# Following MySpaceIM Beta 1.0.697.0
-[MySpaceIM]
-excited.png :D :-D
-devil.png }:)
-confused.png :Z
-glasses-nerdy.png B)
-bulgy-eyes.png %)
-freaked-out.png :E
-happy.png :) :-)
-amorous.png :X
-laugh.png :))
-mohawk.png -:
-mad-tongue.png X(
-messed.png X)
-glasses-nerdy.png Q)
-doh.png :G
-pirate.png P)
-shocked.png :O
-sidefrown.png :{
-sinister.png :B
-smirk.png :,
-neutral.png :|
-tongue.png :P :p
-pissed-off.png B|
-wink.png ;-) ;)
-sad.png :[
-kiss.png :x
-! skywalker.png C:-) c:-) C:) c:)
-! monkey.png :-(|) :(|) 8-|)
-! cyclops.png O-) o-)
-
-
# MXit standard emoticons
[MXit]
happy.png :-) :)
diff --git a/pidgin/pixmaps/emotes/small/16/small.theme.in b/pidgin/pixmaps/emotes/small/16/small.theme.in
index 36aa59cc1c..366ccfdc49 100644
--- a/pidgin/pixmaps/emotes/small/16/small.theme.in
+++ b/pidgin/pixmaps/emotes/small/16/small.theme.in
@@ -213,23 +213,6 @@ shame.png [-X [-x
musical-note.png :-"
star.png (*)
-
-# Following MySpaceIM Beta 1.0.697.0
-[MySpaceIM]
-excited.png :D :-D
-devil.png }:)
-confused.png :Z
-happy.png :) :-)
-amorous.png :X
-pirate.png P)
-shocked.png :O
-neutral.png :|
-tongue.png :P :p
-pissed-off.png B|
-wink.png ;-) ;)
-sad.png :[
-kiss.png :x
-
# MXit standard emoticons
[MXit]
happy.png :-) :)
diff --git a/pidgin/pixmaps/protocols/16/myspace.png b/pidgin/pixmaps/protocols/16/myspace.png
deleted file mode 100644
index e7c3034cc9..0000000000
--- a/pidgin/pixmaps/protocols/16/myspace.png
+++ /dev/null
Binary files differ
diff --git a/pidgin/pixmaps/protocols/22/myspace.png b/pidgin/pixmaps/protocols/22/myspace.png
deleted file mode 100644
index 2b6020b58c..0000000000
--- a/pidgin/pixmaps/protocols/22/myspace.png
+++ /dev/null
Binary files differ
diff --git a/pidgin/pixmaps/protocols/48/myspace.png b/pidgin/pixmaps/protocols/48/myspace.png
deleted file mode 100644
index d9740ef5ff..0000000000
--- a/pidgin/pixmaps/protocols/48/myspace.png
+++ /dev/null
Binary files differ
diff --git a/pidgin/plugins/disco/xmppdisco.c b/pidgin/plugins/disco/xmppdisco.c
index 07efa34fc4..50bc368bdd 100644
--- a/pidgin/plugins/disco/xmppdisco.c
+++ b/pidgin/plugins/disco/xmppdisco.c
@@ -252,7 +252,6 @@ static const struct {
} disco_type_mappings[] = {
{ "gadu-gadu", "gadu-gadu" }, /* the prpl is prpl-gg, but list_icon returns "gadu-gadu" */
{ "sametime", "meanwhile" },
- { "myspaceim", "myspace" },
{ "xmpp", "jabber" }, /* prpl-jabber (mentioned in case the prpl is renamed so this line will match) */
{ NULL, NULL }
};
diff --git a/pidgin/win32/nsis/pidgin-installer.nsi b/pidgin/win32/nsis/pidgin-installer.nsi
index 601f90ebed..a18d4f7922 100644
--- a/pidgin/win32/nsis/pidgin-installer.nsi
+++ b/pidgin/win32/nsis/pidgin-installer.nsi
@@ -388,7 +388,6 @@ SectionGroupEnd
!macroend
SectionGroup /e $(URIHANDLERSSECTIONTITLE) SecURIHandlers
!insertmacro URI_SECTION "aim"
- !insertmacro URI_SECTION "myim"
!insertmacro URI_SECTION "ymsgr"
!insertmacro URI_SECTION "xmpp"
SectionGroupEnd
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 5e93928af2..a2773188d4 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -107,9 +107,6 @@ libpurple/protocols/jabber/si.c
libpurple/protocols/jabber/usermood.c
libpurple/protocols/jabber/usernick.c
libpurple/protocols/jabber/xdata.c
-libpurple/protocols/myspace/myspace.c
-libpurple/protocols/myspace/user.c
-libpurple/protocols/myspace/zap.c
libpurple/protocols/novell/nmuser.c
libpurple/protocols/novell/novell.c
libpurple/protocols/oscar/authorization.c