qulogic/pidgin

yahoo: Remove protocol plugin from tree
release-2.x.y
2016-10-05, Mike Ruprecht
da90fe7312d3
Parents f35cd65fd935
Children a00621dae17f
yahoo: Remove protocol plugin from tree

Yahoo has completely reimplemented their protocol, so this version
is no longer operable as of August 5th, 2016:
https://yahoo.tumblr.com/post/145715934739/q2-2016-progress-report-on-our-product

A new prpl has been written to support the new protocol. It can be
found here: https://github.com/EionRobb/funyahoo-plusplus

This also removes support for Yahoo! Japan. According to
http://messenger.yahoo.co.jp/ the service ended March 26th, 2014.
  • +8 -0
    ChangeLog
  • +1 -1
    README
  • +7 -17
    configure.ac
  • +2 -3
    doc/finch.1.in
  • +2 -3
    doc/pidgin.1.in
  • +0 -32
    libpurple/account.c
  • +0 -17
    libpurple/buddyicon.c
  • +0 -34
    libpurple/data/gconf/purple.schemas.in
  • +1 -1
    libpurple/plugins/psychic.c
  • +1 -1
    libpurple/protocols/Makefile.am
  • +1 -1
    libpurple/protocols/Makefile.mingw
  • +0 -60
    libpurple/protocols/yahoo/Makefile.am
  • +0 -105
    libpurple/protocols/yahoo/Makefile.mingw
  • +0 -348
    libpurple/protocols/yahoo/libyahoo.c
  • +0 -241
    libpurple/protocols/yahoo/libyahoojp.c
  • +0 -5513
    libpurple/protocols/yahoo/libymsg.c
  • +0 -402
    libpurple/protocols/yahoo/libymsg.h
  • +0 -986
    libpurple/protocols/yahoo/util.c
  • +0 -729
    libpurple/protocols/yahoo/yahoo_aliases.c
  • +0 -41
    libpurple/protocols/yahoo/yahoo_aliases.h
  • +0 -609
    libpurple/protocols/yahoo/yahoo_doodle.c
  • +0 -131
    libpurple/protocols/yahoo/yahoo_doodle.h
  • +0 -2048
    libpurple/protocols/yahoo/yahoo_filexfer.c
  • +0 -70
    libpurple/protocols/yahoo/yahoo_filexfer.h
  • +0 -330
    libpurple/protocols/yahoo/yahoo_friend.c
  • +0 -93
    libpurple/protocols/yahoo/yahoo_friend.h
  • +0 -403
    libpurple/protocols/yahoo/yahoo_packet.c
  • +0 -150
    libpurple/protocols/yahoo/yahoo_packet.h
  • +0 -611
    libpurple/protocols/yahoo/yahoo_picture.c
  • +0 -43
    libpurple/protocols/yahoo/yahoo_picture.h
  • +0 -1282
    libpurple/protocols/yahoo/yahoo_profile.c
  • +0 -1684
    libpurple/protocols/yahoo/yahoochat.c
  • +0 -66
    libpurple/protocols/yahoo/yahoochat.h
  • +0 -658
    libpurple/protocols/yahoo/ycht.c
  • +0 -97
    libpurple/protocols/yahoo/ycht.h
  • +3 -3
    libpurple/prpl.h
  • +0 -27
    libpurple/purple-url-handler
  • +2 -2
    libpurple/server.h
  • +0 -2
    libpurple/tests/Makefile.am
  • +0 -1
    libpurple/tests/check_libpurple.c
  • +0 -214
    libpurple/tests/test_yahoo_util.c
  • +0 -1
    libpurple/tests/tests.h
  • +2 -2
    libpurple/util.h
  • +2 -2
    pidgin.apspec.in
  • +3 -3
    pidgin.spec.in
  • +1 -1
    pidgin/data/pidgin.appdata.xml.in
  • +1 -1
    pidgin/data/pidgin.desktop.in.in
  • +1 -6
    pidgin/gtkblist.c
  • +0 -2
    pidgin/gtkwhiteboard.h
  • +0 -6
    pidgin/pixmaps/Makefile.am
  • +0 -185
    pidgin/pixmaps/emotes/default/24/default.theme.in
  • +0 -78
    pidgin/pixmaps/emotes/small/16/small.theme.in
  • +0 -138
    pidgin/pixmaps/protocols/16/scalable/yahoo.svg
  • +0 -0
    pidgin/pixmaps/protocols/16/yahoo.png
  • +0 -154
    pidgin/pixmaps/protocols/22/scalable/yahoo.svg
  • +0 -0
    pidgin/pixmaps/protocols/22/yahoo.png
  • +0 -0
    pidgin/pixmaps/protocols/48/yahoo.png
  • +0 -174
    pidgin/pixmaps/protocols/scalable/yahoo.svg
  • +4 -8
    pidgin/plugins/gevolution/add_buddy_dialog.c
  • +0 -15
    pidgin/plugins/gevolution/gevo-util.c
  • +0 -1
    pidgin/plugins/gevolution/gevolution.c
  • +0 -2
    pidgin/plugins/gevolution/new_person_dialog.c
  • +0 -5
    pidgin/win32/nsis/pidgin-installer.nsi
  • +0 -10
    po/POTFILES.in
  • --- a/ChangeLog Wed Oct 05 21:14:58 2016 +0200
    +++ b/ChangeLog Wed Oct 05 15:10:29 2016 -0500
    @@ -13,6 +13,14 @@
    https://pidgin.im/pipermail/devel/2016-September/024078.htm
    * Removed the MySpaceIM protocol plugin. The service has been defunct for a
    long time. (#15356)
    + * Remove the Yahoo! protocol plugin. Yahoo has completely
    + reimplemented their protocol, so this version is no longer operable as
    + of August 5th, 2016:
    + https://yahoo.tumblr.com/post/145715934739/q2-2016-progress-report-on-our-product
    + A new protocol plugin has been written to support the new protocol.
    + It can be found here: https://github.com/EionRobb/funyahoo-plusplus
    + This also removes support for Yahoo! Japan. According to
    + http://messenger.yahoo.co.jp/ the service ended March 26th, 2014.
    General
    * Replaced instances of d.pidgin.im with developer.pidgin.im and updated the
    --- a/README Wed Oct 05 21:14:58 2016 +0200
    +++ b/README Wed Oct 05 15:10:29 2016 -0500
    @@ -4,7 +4,7 @@
    libpurple is a library intended to be used by programmers seeking
    to write an IM client that connects to many IM networks. It supports
    -AIM, ICQ, XMPP, MSN and Yahoo!, among others.
    +AIM, ICQ, and XMPP, among others.
    Pidgin is a graphical IM client written in C which uses the GTK+
    toolkit.
    --- a/configure.ac Wed Oct 05 21:14:58 2016 +0200
    +++ b/configure.ac Wed Oct 05 15:10:29 2016 -0500
    @@ -1189,7 +1189,7 @@
    fi
    if test "x$STATIC_PRPLS" = "xall" ; then
    - STATIC_PRPLS="bonjour gg irc jabber novell oscar sametime silc simple yahoo zephyr"
    + STATIC_PRPLS="bonjour gg irc jabber novell oscar sametime silc simple zephyr"
    fi
    if test "x$have_meanwhile" != "xyes" ; then
    STATIC_PRPLS=`echo $STATIC_PRPLS | $sedpath 's/sametime//'`
    @@ -1209,19 +1209,13 @@
    load_proto=
    for i in $STATIC_PRPLS ; do
    dnl Ugly special case for "libsilcpurple.la":
    - dnl ... and Ugly special case for multi-protocol oscar and yahoo
    + dnl ... and Ugly special case for multi-protocol oscar
    if test \( "x$i" = "xoscar" -o "x$i" = "xaim" -o "x$i" = "xicq" \) -a "x$static_oscar" != "xyes"; then
    STATIC_LINK_LIBS="$STATIC_LINK_LIBS \$(top_builddir)/libpurple/protocols/oscar/liboscar.la"
    extern_init="$extern_init extern gboolean purple_init_aim_plugin();"
    extern_init="$extern_init extern gboolean purple_init_icq_plugin();"
    load_proto="$load_proto purple_init_aim_plugin();"
    load_proto="$load_proto purple_init_icq_plugin();"
    - elif test "x$i" = "xyahoo"; then
    - STATIC_LINK_LIBS="$STATIC_LINK_LIBS \$(top_builddir)/libpurple/protocols/yahoo/libymsg.la"
    - extern_init="$extern_init extern gboolean purple_init_yahoo_plugin();"
    - extern_init="$extern_init extern gboolean purple_init_yahoojp_plugin();"
    - load_proto="$load_proto purple_init_yahoo_plugin();"
    - load_proto="$load_proto purple_init_yahoojp_plugin();"
    else
    if test "x$i" = "xsilc"; then
    STATIC_LINK_LIBS="$STATIC_LINK_LIBS \$(top_builddir)/libpurple/protocols/$i/lib${i}purple.la"
    @@ -1246,7 +1240,6 @@
    silc) static_silc=yes ;;
    silc10) static_silc=yes ;;
    simple) static_simple=yes ;;
    - yahoo) static_yahoo=yes ;;
    zephyr) static_zephyr=yes ;;
    *) echo "Invalid static protocol $i!!" ; exit 1 ;;
    esac
    @@ -1260,7 +1253,6 @@
    AM_CONDITIONAL(STATIC_SAMETIME, test "x$static_sametime" = "xyes" -a "x$have_meanwhile" = "xyes")
    AM_CONDITIONAL(STATIC_SILC, test "x$static_silc" = "xyes" -a "x$have_silc" = "xyes")
    AM_CONDITIONAL(STATIC_SIMPLE, test "x$static_simple" = "xyes")
    -AM_CONDITIONAL(STATIC_YAHOO, test "x$static_yahoo" = "xyes")
    AM_CONDITIONAL(STATIC_ZEPHYR, test "x$static_zephyr" = "xyes")
    AC_SUBST(STATIC_LINK_LIBS)
    AC_DEFINE_UNQUOTED(STATIC_PROTO_INIT, $extern_init static void static_proto_init(void) { $load_proto },
    @@ -1268,7 +1260,7 @@
    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 novell oscar sametime silc simple yahoo zephyr"
    + DYNAMIC_PRPLS="bonjour gg irc jabber novell oscar sametime silc simple zephyr"
    fi
    if test "x$have_meanwhile" != "xyes"; then
    DYNAMIC_PRPLS=`echo $DYNAMIC_PRPLS | $sedpath 's/sametime//'`
    @@ -1298,7 +1290,6 @@
    silc) dynamic_silc=yes ;;
    silc10) dynamic_silc=yes ;;
    simple) dynamic_simple=yes ;;
    - yahoo) dynamic_yahoo=yes ;;
    zephyr) dynamic_zephyr=yes ;;
    *) echo "Invalid dynamic protocol $i!!" ; exit 1 ;;
    esac
    @@ -1785,7 +1776,7 @@
    [enable_nss="$enableval"],
    [enable_nss="yes"])
    -msg_ssl="None. Yahoo!, Novell Groupwise and Google Talk will not work without GnuTLS or NSS. OpenSSL is NOT usable!"
    +msg_ssl="None. Novell Groupwise and Google Talk will not work without GnuTLS or NSS. OpenSSL is NOT usable!"
    looked_for_gnutls="no"
    dnl #
    dnl # Check for GnuTLS if it's specified.
    @@ -2196,19 +2187,19 @@
    AC_MSG_ERROR([
    Neither GnuTLS or NSS SSL development headers found.
    Use --disable-nss --disable-gnutls if you do not need SSL support.
    -Yahoo!, Novell Groupwise and Google Talk will not work without GnuTLS or NSS. OpenSSL is NOT usable!
    +Novell Groupwise and Google Talk will not work without GnuTLS or NSS. OpenSSL is NOT usable!
    ])
    elif test "x$looked_for_gnutls" = "xyes" -a "x$force_deps" = "xyes" ; then
    AC_MSG_ERROR([
    GnuTLS SSL development headers not found.
    Use --disable-gnutls if you do not need SSL support.
    -Yahoo!, Novell Groupwise and Google Talk will not work without SSL support.
    +Novell Groupwise and Google Talk will not work without SSL support.
    ])
    elif test "x$looked_for_nss" = "xyes" -a "x$force_deps" = "xyes" ; then
    AC_MSG_ERROR([
    NSS SSL development headers not found.
    Use --disable-nss if you do not need SSL support.
    -Yahoo!, Novell Groupwise and Google Talk will not work without SSL support.
    +Novell Groupwise and Google Talk will not work without SSL support.
    ])
    fi
    @@ -2660,7 +2651,6 @@
    libpurple/protocols/silc/Makefile
    libpurple/protocols/silc10/Makefile
    libpurple/protocols/simple/Makefile
    - libpurple/protocols/yahoo/Makefile
    libpurple/protocols/zephyr/Makefile
    libpurple/tests/Makefile
    libpurple/purple.h
    --- a/doc/finch.1.in Wed Oct 05 21:14:58 2016 +0200
    +++ b/doc/finch.1.in Wed Oct 05 15:10:29 2016 -0500
    @@ -30,11 +30,10 @@
    .SH DESCRIPTION
    .PP
    \fBfinch\fR is a console-based modular messaging client based on libpurple
    -which is capable of connecting to AIM, Yahoo!, XMPP, ICQ, IRC, SILC,
    +which is capable of connecting to AIM, XMPP, ICQ, IRC, SILC,
    Novell GroupWise, Lotus Sametime, Zephyr, Gadu-Gadu, and QQ all at once. It has
    many common features found in other clients, as well as many unique features.
    -Finch is not endorsed by or affiliated with America Online, ICQ, Microsoft, or
    -Yahoo.
    +Finch is not endorsed by or affiliated with America Online, ICQ, or Microsoft.
    .SH OPTIONS
    The following options are provided by \fBfinch\fR using the standard GNU
    --- a/doc/pidgin.1.in Wed Oct 05 21:14:58 2016 +0200
    +++ b/doc/pidgin.1.in Wed Oct 05 15:10:29 2016 -0500
    @@ -29,11 +29,10 @@
    .SH DESCRIPTION
    .PP
    \fBpidgin\fR is a graphical modular messaging client based on libpurple
    -which is capable of connecting to AIM, Yahoo!, XMPP, ICQ, IRC, SILC,
    +which is capable of connecting to AIM, XMPP, ICQ, IRC, SILC,
    Novell GroupWise, Lotus Sametime, Zephyr, Gadu-Gadu, and QQ all at once. It has
    many common features found in other clients, as well as many unique features.
    -Pidgin is not endorsed by or affiliated with America Online, ICQ, Microsoft, or
    -Yahoo.
    +Pidgin is not endorsed by or affiliated with America Online, ICQ, or Microsoft.
    .PP
    Pidgin can be extended by plugins written in multiple programming languages and
    controlled through DBus or \fBpurple-remote\fR.
    --- a/libpurple/account.c Wed Oct 05 21:14:58 2016 +0200
    +++ b/libpurple/account.c Wed Oct 05 15:10:29 2016 -0500
    @@ -535,35 +535,6 @@
    * Reading from disk *
    *********************************************************************/
    static void
    -migrate_yahoo_japan(PurpleAccount *account)
    -{
    - /* detect a Yahoo! JAPAN account that existed prior to 2.6.0 and convert it
    - * to use the new prpl-yahoojp. Also remove the account-specific settings
    - * we no longer need */
    -
    - if(purple_strequal(purple_account_get_protocol_id(account), "prpl-yahoo")) {
    - if(purple_account_get_bool(account, "yahoojp", FALSE)) {
    - const char *serverjp = purple_account_get_string(account, "serverjp", NULL);
    - const char *xferjp_host = purple_account_get_string(account, "xferjp_host", NULL);
    -
    - g_return_if_fail(serverjp != NULL);
    - g_return_if_fail(xferjp_host != NULL);
    -
    - purple_account_set_string(account, "server", serverjp);
    - purple_account_set_string(account, "xfer_host", xferjp_host);
    -
    - purple_account_set_protocol_id(account, "prpl-yahoojp");
    - }
    -
    - /* these should always be nuked */
    - purple_account_remove_setting(account, "yahoojp");
    - purple_account_remove_setting(account, "serverjp");
    - purple_account_remove_setting(account, "xferjp_host");
    -
    - }
    -}
    -
    -static void
    migrate_icq_server(PurpleAccount *account)
    {
    /* Migrate the login server setting for ICQ accounts. See
    @@ -668,9 +639,6 @@
    }
    /* we do this here because we need access to account settings to determine
    - * if we can/should migrate an old Yahoo! JAPAN account */
    - migrate_yahoo_japan(account);
    - /* we do this here because we need access to account settings to determine
    * if we can/should migrate an ICQ account's server setting */
    migrate_icq_server(account);
    /* we do this here because we need to do it before the user views the
    --- a/libpurple/buddyicon.c Wed Oct 05 21:14:58 2016 +0200
    +++ b/libpurple/buddyicon.c Wed Oct 05 15:10:29 2016 -0500
    @@ -1095,23 +1095,6 @@
    purple_blist_node_set_string(node, "icon_checksum", hash);
    purple_blist_node_remove_setting(node, "avatar_hash");
    }
    - else
    - {
    - PurpleAccount *account = purple_buddy_get_account((PurpleBuddy *)node);
    - const char *prpl_id = purple_account_get_protocol_id(account);
    -
    - if (g_str_equal(prpl_id, "prpl-yahoo") || g_str_equal(prpl_id, "prpl-yahoojp"))
    - {
    - int checksum = purple_blist_node_get_int(node, "icon_checksum");
    - if (checksum != 0)
    - {
    - char *checksum_str = g_strdup_printf("%i", checksum);
    - purple_blist_node_remove_setting(node, "icon_checksum");
    - purple_blist_node_set_string(node, "icon_checksum", checksum_str);
    - g_free(checksum_str);
    - }
    - }
    - }
    }
    }
    else
    --- a/libpurple/data/gconf/purple.schemas.in Wed Oct 05 21:14:58 2016 +0200
    +++ b/libpurple/data/gconf/purple.schemas.in Wed Oct 05 15:10:29 2016 -0500
    @@ -204,39 +204,5 @@
    <long>True if the command used to handle this type of URL should be run in a terminal.</long>
    </locale>
    </schema>
    -
    - <schema>
    - <key>/schemas/desktop/gnome/url-handlers/ymsgr/enabled</key>
    - <applyto>/desktop/gnome/url-handlers/ymsgr/enabled</applyto>
    - <owner>purple</owner>
    - <type>bool</type>
    - <default>true</default>
    - <locale name="C">
    - <short>Whether the specified command should handle "ymsgr" URLs</short>
    - <long>True if the command specified in the "command" key should handle "ymsgr" URLs.</long>
    - </locale>
    - </schema>
    - <schema>
    - <key>/schemas/desktop/gnome/url-handlers/ymsgr/command</key>
    - <applyto>/desktop/gnome/url-handlers/ymsgr/command</applyto>
    - <owner>purple</owner>
    - <type>string</type>
    - <default>purple-url-handler "%s"</default>
    - <locale name="C">
    - <short>The handler for "ymsgr" URLs</short>
    - <long>The command used to handle "ymsgr" URLs, if enabled.</long>
    - </locale>
    - </schema>
    - <schema>
    - <key>/schemas/desktop/gnome/url-handlers/ymsgr/needs_terminal</key>
    - <applyto>/desktop/gnome/url-handlers/ymsgr/needs_terminal</applyto>
    - <owner>purple</owner>
    - <type>bool</type>
    - <default>false</default>
    - <locale name="C">
    - <short>Run the command in a terminal</short>
    - <long>True if the command used to handle this type of URL should be run in a terminal.</long>
    - </locale>
    - </schema>
    </schemalist>
    </gconfschemafile>
    --- a/libpurple/plugins/psychic.c Wed Oct 05 21:14:58 2016 +0200
    +++ b/libpurple/plugins/psychic.c Wed Oct 05 15:10:29 2016 -0500
    @@ -21,7 +21,7 @@
    #define PLUGIN_SUMMARY N_("Psychic mode for incoming conversation")
    #define PLUGIN_DESC N_("Causes conversation windows to appear as other" \
    " users begin to message you. This works for" \
    - " AIM, ICQ, XMPP, Sametime, and Yahoo!")
    + " AIM, ICQ, XMPP, and Sametime")
    #define PLUGIN_AUTHOR "Christopher O'Brien <siege@preoccupied.net>"
    --- a/libpurple/protocols/Makefile.am Wed Oct 05 21:14:58 2016 +0200
    +++ b/libpurple/protocols/Makefile.am Wed Oct 05 15:10:29 2016 -0500
    @@ -1,5 +1,5 @@
    EXTRA_DIST = Makefile.mingw
    -DIST_SUBDIRS = bonjour gg irc jabber novell null oscar sametime silc silc10 simple yahoo zephyr
    +DIST_SUBDIRS = bonjour gg irc jabber novell null oscar sametime silc silc10 simple zephyr
    SUBDIRS = $(DYNAMIC_PRPLS) $(STATIC_PRPLS)
    --- a/libpurple/protocols/Makefile.mingw Wed Oct 05 21:14:58 2016 +0200
    +++ b/libpurple/protocols/Makefile.mingw Wed Oct 05 15:10:29 2016 -0500
    @@ -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
    +SUBDIRS = gg irc jabber novell null oscar sametime silc simple bonjour
    .PHONY: all install clean
    --- a/libpurple/protocols/yahoo/Makefile.am Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,60 +0,0 @@
    -EXTRA_DIST = \
    - Makefile.mingw
    -
    -pkgdir = $(libdir)/purple-$(PURPLE_MAJOR_VERSION)
    -
    -YAHOOSOURCES = \
    - libymsg.c \
    - libymsg.h \
    - util.c \
    - yahoochat.h \
    - yahoochat.c \
    - yahoo_aliases.c \
    - yahoo_aliases.h \
    - yahoo_doodle.h \
    - yahoo_doodle.c \
    - yahoo_filexfer.h \
    - yahoo_filexfer.c \
    - yahoo_friend.h \
    - yahoo_friend.c \
    - yahoo_packet.h \
    - yahoo_packet.c \
    - yahoo_picture.c \
    - yahoo_picture.h \
    - yahoo_profile.c \
    - ycht.c \
    - ycht.h
    -
    -AM_CFLAGS = $(st)
    -
    -libyahoo_la_LDFLAGS = -module -avoid-version
    -libyahoojp_la_LDFLAGS = -module -avoid-version
    -
    -if STATIC_YAHOO
    -
    -st = -DPURPLE_STATIC_PRPL
    -noinst_LTLIBRARIES = libymsg.la
    -libymsg_la_SOURCES = $(YAHOOSOURCES) libyahoo.c libyahoojp.c
    -libymsg_la_CFLAGS = $(AM_CFLAGS)
    -
    -else
    -
    -st =
    -pkg_LTLIBRARIES = libymsg.la libyahoo.la libyahoojp.la
    -
    -libymsg_la_SOURCES = $(YAHOOSOURCES)
    -libymsg_la_LIBADD = $(GLIB_LIBS)
    -
    -libyahoo_la_SOURCES = libyahoo.c
    -libyahoo_la_LIBADD = libymsg.la
    -
    -libyahoojp_la_SOURCES = libyahoojp.c
    -libyahoojp_la_LIBADD = libymsg.la
    -
    -endif
    -
    -AM_CPPFLAGS = \
    - -I$(top_srcdir)/libpurple \
    - -I$(top_builddir)/libpurple \
    - $(GLIB_CFLAGS) \
    - $(DEBUG_CFLAGS)
    --- a/libpurple/protocols/yahoo/Makefile.mingw Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,105 +0,0 @@
    -#
    -# Makefile.mingw
    -#
    -# Description: Makefile for win32 (mingw) version of libyahoo
    -#
    -
    -PIDGIN_TREE_TOP := ../../..
    -include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
    -
    -TARGET = libymsg
    -YAHOO_TARGET = libyahoo
    -YAHOOJP_TARGET = libyahoojp
    -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. \
    - -L$(GTK_TOP)/lib \
    - -L$(PURPLE_TOP)
    -
    -##
    -## SOURCES, OBJECTS
    -##
    -C_SRC = util.c \
    - libymsg.c \
    - yahoochat.c \
    - yahoo_aliases.c \
    - yahoo_doodle.c \
    - yahoo_filexfer.c \
    - yahoo_friend.c \
    - yahoo_packet.c \
    - yahoo_picture.c \
    - yahoo_profile.c \
    - ycht.c
    -
    -OBJECTS = $(C_SRC:%.c=%.o)
    -
    -YAHOO_C_SRC = libyahoo.c
    -YAHOO_OBJECTS = $(YAHOO_C_SRC:%.c=%.o)
    -
    -YAHOOJP_C_SRC = libyahoojp.c
    -YAHOOJP_OBJECTS = $(YAHOOJP_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 $(YAHOO_TARGET).dll $(YAHOOJP_TARGET).dll
    -
    -install: all $(DLL_INSTALL_DIR)
    - cp $(YAHOO_TARGET).dll $(YAHOOJP_TARGET).dll $(DLL_INSTALL_DIR)
    - cp $(TARGET).dll $(PURPLE_INSTALL_DIR)
    -
    -$(OBJECTS): $(PURPLE_CONFIG_H)
    -
    -$(TARGET).dll.a $(TARGET).dll: $(PURPLE_DLL).a $(OBJECTS)
    - $(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -Wl,--output-def,$(TARGET).def,--out-implib,$(TARGET).dll.a -o $(TARGET).dll
    -
    -$(YAHOO_TARGET).dll: $(TARGET).dll.a $(YAHOO_OBJECTS)
    - $(CC) -shared $(YAHOO_OBJECTS) $(LIB_PATHS) $(LIBS) -lymsg $(DLL_LD_FLAGS) -o $(YAHOO_TARGET).dll
    -
    -$(YAHOOJP_TARGET).dll: $(TARGET).dll.a $(YAHOOJP_OBJECTS)
    - $(CC) -shared $(YAHOOJP_OBJECTS) $(LIB_PATHS) $(LIBS) -lymsg $(DLL_LD_FLAGS) -o $(YAHOOJP_TARGET).dll
    -
    -##
    -## CLEAN RULES
    -##
    -clean:
    - rm -f $(OBJECTS) $(TARGET).dll $(TARGET).dll.a
    - rm -f $(YAHOO_OBJECTS) $(YAHOO_TARGET).dll
    - rm -f $(YAHOOJP_OBJECTS) $(YAHOOJP_TARGET).dll
    -
    -include $(PIDGIN_COMMON_TARGETS)
    --- a/libpurple/protocols/yahoo/libyahoo.c Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,348 +0,0 @@
    -/*
    - * purple
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * This program is free software; you can redistribute it and/or modify
    - * it under the terms of the GNU General Public License as published by
    - * the Free Software Foundation; either version 2 of the License, or
    - * (at your option) any later version.
    - *
    - * This program is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    - * GNU General Public License for more details.
    - *
    - * You should have received a copy of the GNU General Public License
    - * along with this program; if not, write to the Free Software
    - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    - *
    - */
    -
    -#include "internal.h"
    -
    -#include <account.h>
    -#include <core.h>
    -
    -#include "libymsg.h"
    -#include "yahoochat.h"
    -#include "yahoo_aliases.h"
    -#include "yahoo_doodle.h"
    -#include "yahoo_filexfer.h"
    -#include "yahoo_picture.h"
    -
    -static PurplePlugin *my_protocol = NULL;
    -
    -static void yahoo_register_commands(void)
    -{
    - purple_cmd_register("join", "s", PURPLE_CMD_P_PRPL,
    - PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT |
    - PURPLE_CMD_FLAG_PRPL_ONLY,
    - "prpl-yahoo", yahoopurple_cmd_chat_join,
    - _("join &lt;room&gt;: Join a chat room on the Yahoo network"), NULL);
    - purple_cmd_register("list", "", PURPLE_CMD_P_PRPL,
    - PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT |
    - PURPLE_CMD_FLAG_PRPL_ONLY,
    - "prpl-yahoo", yahoopurple_cmd_chat_list,
    - _("list: List rooms on the Yahoo network"), NULL);
    - purple_cmd_register("buzz", "", PURPLE_CMD_P_PRPL,
    - PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PRPL_ONLY,
    - "prpl-yahoo", yahoopurple_cmd_buzz,
    - _("buzz: Buzz a user to get their attention"), NULL);
    - purple_cmd_register("doodle", "", PURPLE_CMD_P_PRPL,
    - PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PRPL_ONLY,
    - "prpl-yahoo", yahoo_doodle_purple_cmd_start,
    - _("doodle: Request user to start a Doodle session"), NULL);
    -}
    -
    -static PurpleAccount *find_acct(const char *prpl, const char *acct_id)
    -{
    - PurpleAccount *acct = NULL;
    -
    - /* If we have a specific acct, use it */
    - if (acct_id) {
    - acct = purple_accounts_find(acct_id, prpl);
    - if (acct && !purple_account_is_connected(acct))
    - acct = NULL;
    - } else { /* Otherwise find an active account for the protocol */
    - GList *l = purple_accounts_get_all();
    - while (l) {
    - if (!strcmp(prpl, purple_account_get_protocol_id(l->data))
    - && purple_account_is_connected(l->data)) {
    - acct = l->data;
    - break;
    - }
    - l = l->next;
    - }
    - }
    -
    - return acct;
    -}
    -
    -/* This may not be the best way to do this, but we find the first key w/o a value
    - * and assume it is the buddy name */
    -static void yahoo_find_uri_novalue_param(gpointer key, gpointer value, gpointer user_data)
    -{
    - char **retval = user_data;
    -
    - if (value == NULL && *retval == NULL) {
    - *retval = key;
    - }
    -}
    -
    -static gboolean yahoo_uri_handler(const char *proto, const char *cmd, GHashTable *params)
    -{
    - char *acct_id = g_hash_table_lookup(params, "account");
    - PurpleAccount *acct;
    -
    - if (g_ascii_strcasecmp(proto, "ymsgr"))
    - return FALSE;
    -
    - acct = find_acct(purple_plugin_get_id(my_protocol), acct_id);
    -
    - if (!acct)
    - return FALSE;
    -
    - /* ymsgr:SendIM?screename&m=The+Message */
    - if (!g_ascii_strcasecmp(cmd, "SendIM")) {
    - char *sname = NULL;
    - g_hash_table_foreach(params, yahoo_find_uri_novalue_param, &sname);
    - if (sname) {
    - char *message = g_hash_table_lookup(params, "m");
    -
    - PurpleConversation *conv = purple_find_conversation_with_account(
    - PURPLE_CONV_TYPE_IM, sname, acct);
    - if (conv == NULL)
    - conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, acct, sname);
    - purple_conversation_present(conv);
    -
    - if (message) {
    - /* Spaces are encoded as '+' */
    - g_strdelimit(message, "+", ' ');
    - purple_conv_send_confirm(conv, message);
    - }
    - }
    - /* else
    - **If pidgindialogs_im() was in the core, we could use it here.
    - * It is all purple_request_* based, but I'm not sure it really belongs in the core
    - pidgindialogs_im(); */
    -
    - return TRUE;
    - }
    - /* ymsgr:Chat?roomname */
    - else if (!g_ascii_strcasecmp(cmd, "Chat")) {
    - char *rname = NULL;
    - g_hash_table_foreach(params, yahoo_find_uri_novalue_param, &rname);
    - if (rname) {
    - /* This is somewhat hacky, but the params aren't useful after this command */
    - g_hash_table_insert(params, g_strdup("room"), g_strdup(rname));
    - g_hash_table_insert(params, g_strdup("type"), g_strdup("Chat"));
    - serv_join_chat(purple_account_get_connection(acct), params);
    - }
    - /* else
    - ** Same as above (except that this would have to be re-written using purple_request_*)
    - pidgin_blist_joinchat_show(); */
    -
    - return TRUE;
    - }
    - /* ymsgr:AddFriend?name */
    - else if (!g_ascii_strcasecmp(cmd, "AddFriend")) {
    - char *name = NULL;
    - g_hash_table_foreach(params, yahoo_find_uri_novalue_param, &name);
    - purple_blist_request_add_buddy(acct, name, NULL, NULL);
    - return TRUE;
    - }
    -
    - return FALSE;
    -}
    -
    -static GHashTable *
    -yahoo_get_account_text_table(PurpleAccount *account)
    -{
    - GHashTable *table;
    - table = g_hash_table_new(g_str_hash, g_str_equal);
    - g_hash_table_insert(table, "login_label", (gpointer)_("Yahoo! ID..."));
    - return table;
    -}
    -
    -static gboolean yahoo_unload_plugin(PurplePlugin *plugin)
    -{
    - yahoo_dest_colorht();
    -
    - return TRUE;
    -}
    -
    -static PurpleWhiteboardPrplOps yahoo_whiteboard_prpl_ops =
    -{
    - yahoo_doodle_start,
    - yahoo_doodle_end,
    - yahoo_doodle_get_dimensions,
    - NULL,
    - yahoo_doodle_get_brush,
    - yahoo_doodle_set_brush,
    - yahoo_doodle_send_draw_list,
    - yahoo_doodle_clear,
    -
    - /* padding */
    - NULL,
    - NULL,
    - NULL,
    - NULL
    -};
    -
    -static PurplePluginProtocolInfo prpl_info =
    -{
    - OPT_PROTO_MAIL_CHECK | OPT_PROTO_CHAT_TOPIC,
    - NULL, /* user_splits */
    - NULL, /* protocol_options */
    - {"png,gif,jpeg", 96, 96, 96, 96, 0, PURPLE_ICON_SCALE_SEND},
    - yahoo_list_icon,
    - yahoo_list_emblem,
    - yahoo_status_text,
    - yahoo_tooltip_text,
    - yahoo_status_types,
    - yahoo_blist_node_menu,
    - yahoo_c_info,
    - yahoo_c_info_defaults,
    - yahoo_login,
    - yahoo_close,
    - yahoo_send_im,
    - NULL, /* set info */
    - yahoo_send_typing,
    - yahoo_get_info,
    - yahoo_set_status,
    - yahoo_set_idle,
    - NULL, /* change_passwd*/
    - yahoo_add_buddy,
    - NULL, /* add_buddies */
    - yahoo_remove_buddy,
    - NULL, /* remove_buddies */
    - NULL, /* add_permit */
    - yahoo_add_deny,
    - NULL, /* rem_permit */
    - yahoo_rem_deny,
    - yahoo_set_permit_deny,
    - yahoo_c_join,
    - NULL, /* reject chat invite */
    - yahoo_get_chat_name,
    - yahoo_c_invite,
    - yahoo_c_leave,
    - NULL, /* chat whisper */
    - yahoo_c_send,
    - yahoo_keepalive,
    - NULL, /* register_user */
    - NULL, /* get_cb_info */
    - NULL, /* get_cb_away */
    - yahoo_update_alias, /* alias_buddy */
    - yahoo_change_buddys_group,
    - yahoo_rename_group,
    - NULL, /* buddy_free */
    - NULL, /* convo_closed */
    - purple_normalize_nocase, /* normalize */
    - yahoo_set_buddy_icon,
    - NULL, /* void (*remove_group)(PurpleConnection *gc, const char *group);*/
    - NULL, /* char *(*get_cb_real_name)(PurpleConnection *gc, int id, const char *who); */
    - NULL, /* set_chat_topic */
    - NULL, /* find_blist_chat */
    - yahoo_roomlist_get_list,
    - yahoo_roomlist_cancel,
    - yahoo_roomlist_expand_category,
    - yahoo_can_receive_file, /* can_receive_file */
    - yahoo_send_file,
    - yahoo_new_xfer,
    - yahoo_offline_message, /* offline_message */
    - &yahoo_whiteboard_prpl_ops,
    - NULL, /* send_raw */
    - NULL, /* roomlist_room_serialize */
    - NULL, /* unregister_user */
    -
    - yahoo_send_attention,
    - yahoo_attention_types,
    -
    - sizeof(PurplePluginProtocolInfo), /* struct_size */
    - yahoo_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 */
    -};
    -
    -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-yahoo", /**< id */
    - "Yahoo", /**< name */
    - DISPLAY_VERSION, /**< version */
    - /** summary */
    - N_("Yahoo! Protocol Plugin"),
    - /** description */
    - N_("Yahoo! Protocol Plugin"),
    - NULL, /**< author */
    - PURPLE_WEBSITE, /**< homepage */
    - NULL, /**< load */
    - yahoo_unload_plugin, /**< unload */
    - NULL, /**< destroy */
    - NULL, /**< ui_info */
    - &prpl_info, /**< extra_info */
    - NULL,
    - yahoo_actions,
    -
    - /* padding */
    - NULL,
    - NULL,
    - NULL,
    - NULL
    -};
    -
    -static void
    -init_plugin(PurplePlugin *plugin)
    -{
    - PurpleAccountOption *option;
    -
    - option = purple_account_option_int_new(_("Pager port"), "port", YAHOO_PAGER_PORT);
    - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
    -
    - option = purple_account_option_string_new(_("File transfer server"), "xfer_host", YAHOO_XFER_HOST);
    - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
    -
    - option = purple_account_option_int_new(_("File transfer port"), "xfer_port", YAHOO_XFER_PORT);
    - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
    -
    - option = purple_account_option_string_new(_("Chat room locale"), "room_list_locale", YAHOO_ROOMLIST_LOCALE);
    - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
    -
    - option = purple_account_option_string_new(_("Encoding"), "local_charset", "UTF-8");
    - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
    -
    - option = purple_account_option_bool_new(_("Ignore conference and chatroom invitations"), "ignore_invites", FALSE);
    - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
    -
    - option = purple_account_option_bool_new(_("Use account proxy for HTTP and HTTPS connections"), "proxy_ssl", FALSE);
    - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
    -
    -#if 0
    - option = purple_account_option_string_new(_("Chat room list URL"), "room_list", YAHOO_ROOMLIST_URL);
    - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
    -#endif
    -
    - my_protocol = plugin;
    - yahoo_register_commands();
    - yahoo_init_colorht();
    -
    - purple_signal_connect(purple_get_core(), "uri-handler", plugin,
    - PURPLE_CALLBACK(yahoo_uri_handler), NULL);
    -}
    -
    -PURPLE_INIT_PLUGIN(yahoo, init_plugin, info);
    --- a/libpurple/protocols/yahoo/libyahoojp.c Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,241 +0,0 @@
    -/*
    - * purple
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * This program is free software; you can redistribute it and/or modify
    - * it under the terms of the GNU General Public License as published by
    - * the Free Software Foundation; either version 2 of the License, or
    - * (at your option) any later version.
    - *
    - * This program is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    - * GNU General Public License for more details.
    - *
    - * You should have received a copy of the GNU General Public License
    - * along with this program; if not, write to the Free Software
    - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    - *
    - */
    -
    -#include "internal.h"
    -
    -#include <account.h>
    -
    -#include "libymsg.h"
    -#include "yahoochat.h"
    -#include "yahoo_aliases.h"
    -#include "yahoo_doodle.h"
    -#include "yahoo_filexfer.h"
    -#include "yahoo_picture.h"
    -
    -static void yahoojp_register_commands(void)
    -{
    - purple_cmd_register("join", "s", PURPLE_CMD_P_PRPL,
    - PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT |
    - PURPLE_CMD_FLAG_PRPL_ONLY,
    - "prpl-yahoojp", yahoopurple_cmd_chat_join,
    - _("join &lt;room&gt;: Join a chat room on the Yahoo network"), NULL);
    - purple_cmd_register("list", "", PURPLE_CMD_P_PRPL,
    - PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT |
    - PURPLE_CMD_FLAG_PRPL_ONLY,
    - "prpl-yahoojp", yahoopurple_cmd_chat_list,
    - _("list: List rooms on the Yahoo network"), NULL);
    - purple_cmd_register("buzz", "", PURPLE_CMD_P_PRPL,
    - PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PRPL_ONLY,
    - "prpl-yahoojp", yahoopurple_cmd_buzz,
    - _("buzz: Buzz a user to get their attention"), NULL);
    - purple_cmd_register("doodle", "", PURPLE_CMD_P_PRPL,
    - PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PRPL_ONLY,
    - "prpl-yahoojp", yahoo_doodle_purple_cmd_start,
    - _("doodle: Request user to start a Doodle session"), NULL);
    -}
    -
    -static GHashTable *
    -yahoojp_get_account_text_table(PurpleAccount *account)
    -{
    - GHashTable *table;
    - table = g_hash_table_new(g_str_hash, g_str_equal);
    - g_hash_table_insert(table, "login_label", (gpointer)_("Yahoo JAPAN ID..."));
    - return table;
    -}
    -
    -static gboolean yahoojp_unload_plugin(PurplePlugin *plugin)
    -{
    - yahoo_dest_colorht();
    -
    - return TRUE;
    -}
    -
    -static PurpleWhiteboardPrplOps yahoo_whiteboard_prpl_ops =
    -{
    - yahoo_doodle_start,
    - yahoo_doodle_end,
    - yahoo_doodle_get_dimensions,
    - NULL,
    - yahoo_doodle_get_brush,
    - yahoo_doodle_set_brush,
    - yahoo_doodle_send_draw_list,
    - yahoo_doodle_clear,
    -
    - /* padding */
    - NULL,
    - NULL,
    - NULL,
    - NULL
    -};
    -
    -static PurplePluginProtocolInfo prpl_info =
    -{
    - OPT_PROTO_MAIL_CHECK | OPT_PROTO_CHAT_TOPIC,
    - NULL, /* user_splits */
    - NULL, /* protocol_options */
    - {"png,gif,jpeg", 96, 96, 96, 96, 0, PURPLE_ICON_SCALE_SEND},
    - yahoo_list_icon,
    - yahoo_list_emblem,
    - yahoo_status_text,
    - yahoo_tooltip_text,
    - yahoo_status_types,
    - yahoo_blist_node_menu,
    - yahoo_c_info,
    - yahoo_c_info_defaults,
    - yahoo_login,
    - yahoo_close,
    - yahoo_send_im,
    - NULL, /* set info */
    - yahoo_send_typing,
    - yahoo_get_info,
    - yahoo_set_status,
    - yahoo_set_idle,
    - NULL, /* change_passwd*/
    - yahoo_add_buddy,
    - NULL, /* add_buddies */
    - yahoo_remove_buddy,
    - NULL, /* remove_buddies */
    - NULL, /* add_permit */
    - yahoo_add_deny,
    - NULL, /* rem_permit */
    - yahoo_rem_deny,
    - yahoo_set_permit_deny,
    - yahoo_c_join,
    - NULL, /* reject chat invite */
    - yahoo_get_chat_name,
    - yahoo_c_invite,
    - yahoo_c_leave,
    - NULL, /* chat whisper */
    - yahoo_c_send,
    - yahoo_keepalive,
    - NULL, /* register_user */
    - NULL, /* get_cb_info */
    - NULL, /* get_cb_away */
    - yahoo_update_alias, /* alias_buddy */
    - yahoo_change_buddys_group,
    - yahoo_rename_group,
    - NULL, /* buddy_free */
    - NULL, /* convo_closed */
    - purple_normalize_nocase, /* normalize */
    - yahoo_set_buddy_icon,
    - NULL, /* void (*remove_group)(PurpleConnection *gc, const char *group);*/
    - NULL, /* char *(*get_cb_real_name)(PurpleConnection *gc, int id, const char *who); */
    - NULL, /* set_chat_topic */
    - NULL, /* find_blist_chat */
    - yahoo_roomlist_get_list,
    - yahoo_roomlist_cancel,
    - yahoo_roomlist_expand_category,
    - NULL, /* can_receive_file */
    - yahoo_send_file,
    - yahoo_new_xfer,
    - yahoo_offline_message, /* offline_message */
    - &yahoo_whiteboard_prpl_ops,
    - NULL, /* send_raw */
    - NULL, /* roomlist_room_serialize */
    - NULL, /* unregister_user */
    -
    - yahoo_send_attention,
    - yahoo_attention_types,
    -
    - sizeof(PurplePluginProtocolInfo), /* struct_size */
    - yahoojp_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 */
    -};
    -
    -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-yahoojp", /**< id */
    - "Yahoo JAPAN", /**< name */
    - DISPLAY_VERSION, /**< version */
    - /** summary */
    - N_("Yahoo! JAPAN Protocol Plugin"),
    - /** description */
    - N_("Yahoo! JAPAN Protocol Plugin"),
    - NULL, /**< author */
    - PURPLE_WEBSITE, /**< homepage */
    - NULL, /**< load */
    - yahoojp_unload_plugin, /**< unload */
    - NULL, /**< destroy */
    - NULL, /**< ui_info */
    - &prpl_info, /**< extra_info */
    - NULL,
    - yahoo_actions,
    -
    - /* padding */
    - NULL,
    - NULL,
    - NULL,
    - NULL
    -};
    -
    -static void
    -init_plugin(PurplePlugin *plugin)
    -{
    - PurpleAccountOption *option;
    -
    - option = purple_account_option_int_new(_("Pager port"), "port", YAHOO_PAGER_PORT);
    - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
    -
    - option = purple_account_option_string_new(_("File transfer server"), "xfer_host", YAHOOJP_XFER_HOST);
    - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
    -
    - option = purple_account_option_int_new(_("File transfer port"), "xfer_port", YAHOO_XFER_PORT);
    - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
    -
    - option = purple_account_option_string_new(_("Chat room locale"), "room_list_locale", YAHOOJP_ROOMLIST_LOCALE);
    - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
    -
    - option = purple_account_option_string_new(_("Encoding"), "local_charset", "UTF-8");
    - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
    -
    - option = purple_account_option_bool_new(_("Ignore conference and chatroom invitations"), "ignore_invites", FALSE);
    - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
    -
    - option = purple_account_option_bool_new(_("Use account proxy for HTTP and HTTPS connections"), "proxy_ssl", FALSE);
    - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
    -
    -#if 0
    - option = purple_account_option_string_new(_("Chat room list URL"), "room_list", YAHOO_ROOMLIST_URL);
    - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
    -#endif
    -
    - yahoojp_register_commands();
    - yahoo_init_colorht();
    -}
    -
    -PURPLE_INIT_PLUGIN(yahoojp, init_plugin, info);
    -
    --- a/libpurple/protocols/yahoo/libymsg.c Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,5513 +0,0 @@
    -/*
    - * purple
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * This program is free software; you can redistribute it and/or modify
    - * it under the terms of the GNU General Public License as published by
    - * the Free Software Foundation; either version 2 of the License, or
    - * (at your option) any later version.
    - *
    - * This program is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    - * GNU General Public License for more details.
    - *
    - * You should have received a copy of the GNU General Public License
    - * along with this program; if not, write to the Free Software
    - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    - *
    - */
    -
    -/*
    - * Note: When handling the list of struct yahoo_pair's from an incoming
    - * packet the value might not be UTF-8. You should either validate that
    - * it is UTF-8 using g_utf8_validate() or use yahoo_string_decode().
    - */
    -
    -#include "internal.h"
    -
    -#include "account.h"
    -#include "accountopt.h"
    -#include "blist.h"
    -#include "cipher.h"
    -#include "cmds.h"
    -#include "core.h"
    -#include "debug.h"
    -#include "network.h"
    -#include "notify.h"
    -#include "privacy.h"
    -#include "prpl.h"
    -#include "proxy.h"
    -#include "request.h"
    -#include "server.h"
    -#include "util.h"
    -#include "version.h"
    -#include "xmlnode.h"
    -
    -#include "libymsg.h"
    -#include "yahoochat.h"
    -#include "yahoo_aliases.h"
    -#include "yahoo_doodle.h"
    -#include "yahoo_filexfer.h"
    -#include "yahoo_friend.h"
    -#include "yahoo_packet.h"
    -#include "yahoo_picture.h"
    -#include "ycht.h"
    -
    -/* #define YAHOO_DEBUG */
    -
    -/* #define TRY_WEBMESSENGER_LOGIN 0 */
    -
    -/* One hour */
    -#define PING_TIMEOUT 3600
    -
    -/* One minute */
    -#define KEEPALIVE_TIMEOUT 60
    -
    -#ifdef TRY_WEBMESSENGER_LOGIN
    -static void yahoo_login_page_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, size_t len, const gchar *error_message);
    -#endif /* TRY_WEBMESSENGER_LOGIN */
    -
    -static gboolean yahoo_is_japan(PurpleAccount *account)
    -{
    - return purple_strequal(purple_account_get_protocol_id(account), "prpl-yahoojp");
    -}
    -
    -static void yahoo_update_status(PurpleConnection *gc, const char *name, YahooFriend *f)
    -{
    - char *status = NULL;
    -
    - if (!gc || !name || !f || !purple_find_buddy(purple_connection_get_account(gc), name))
    - return;
    -
    - switch (f->status) {
    - case YAHOO_STATUS_OFFLINE:
    - status = YAHOO_STATUS_TYPE_OFFLINE;
    - break;
    - case YAHOO_STATUS_AVAILABLE:
    - status = YAHOO_STATUS_TYPE_AVAILABLE;
    - break;
    - case YAHOO_STATUS_BRB:
    - status = YAHOO_STATUS_TYPE_BRB;
    - break;
    - case YAHOO_STATUS_BUSY:
    - status = YAHOO_STATUS_TYPE_BUSY;
    - break;
    - case YAHOO_STATUS_NOTATHOME:
    - status = YAHOO_STATUS_TYPE_NOTATHOME;
    - break;
    - case YAHOO_STATUS_NOTATDESK:
    - status = YAHOO_STATUS_TYPE_NOTATDESK;
    - break;
    - case YAHOO_STATUS_NOTINOFFICE:
    - status = YAHOO_STATUS_TYPE_NOTINOFFICE;
    - break;
    - case YAHOO_STATUS_ONPHONE:
    - status = YAHOO_STATUS_TYPE_ONPHONE;
    - break;
    - case YAHOO_STATUS_ONVACATION:
    - status = YAHOO_STATUS_TYPE_ONVACATION;
    - break;
    - case YAHOO_STATUS_OUTTOLUNCH:
    - status = YAHOO_STATUS_TYPE_OUTTOLUNCH;
    - break;
    - case YAHOO_STATUS_STEPPEDOUT:
    - status = YAHOO_STATUS_TYPE_STEPPEDOUT;
    - break;
    - case YAHOO_STATUS_INVISIBLE: /* this should never happen? */
    - status = YAHOO_STATUS_TYPE_INVISIBLE;
    - break;
    - case YAHOO_STATUS_CUSTOM:
    - case YAHOO_STATUS_IDLE:
    - if (!f->away)
    - status = YAHOO_STATUS_TYPE_AVAILABLE;
    - else
    - status = YAHOO_STATUS_TYPE_AWAY;
    - break;
    - default:
    - purple_debug_warning("yahoo", "Warning, unknown status %d\n", f->status);
    - break;
    - }
    -
    - if (status) {
    - if (f->status == YAHOO_STATUS_CUSTOM)
    - purple_prpl_got_user_status(purple_connection_get_account(gc), name, status, "message",
    - yahoo_friend_get_status_message(f), NULL);
    - else
    - purple_prpl_got_user_status(purple_connection_get_account(gc), name, status, NULL);
    - }
    -
    - if (f->idle != 0)
    - purple_prpl_got_user_idle(purple_connection_get_account(gc), name, TRUE, f->idle);
    - else
    - purple_prpl_got_user_idle(purple_connection_get_account(gc), name, FALSE, 0);
    -
    - if (f->sms)
    - purple_prpl_got_user_status(purple_connection_get_account(gc), name, YAHOO_STATUS_TYPE_MOBILE, NULL);
    - else
    - purple_prpl_got_user_status_deactive(purple_connection_get_account(gc), name, YAHOO_STATUS_TYPE_MOBILE);
    -}
    -
    -static void yahoo_process_status(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - PurpleAccount *account = purple_connection_get_account(gc);
    - GSList *l = pkt->hash;
    - YahooFriend *f = NULL;
    - char *name = NULL;
    - gboolean unicode = FALSE;
    - char *message = NULL;
    - YahooFederation fed = YAHOO_FEDERATION_NONE;
    - char *fedname = NULL;
    -
    - if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) {
    - if (!purple_account_get_remember_password(account))
    - purple_account_set_password(account, NULL);
    - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NAME_IN_USE,
    - _("You have signed on from another location"));
    - return;
    - }
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 0: /* we won't actually do anything with this */
    - case 1: /* we won't actually do anything with this */
    - break;
    - case 8: /* how many online buddies we have */
    - break;
    - case 7: /* the current buddy */
    - /* update the previous buddy before changing the variables */
    - if (f) {
    - if (message)
    - yahoo_friend_set_status_message(f, yahoo_string_decode(gc, message, unicode));
    - if (name)
    - yahoo_update_status(gc, name, f);
    - }
    - name = message = NULL;
    - f = NULL;
    - if (pair->value && g_utf8_validate(pair->value, -1, NULL)) {
    - GSList *tmplist;
    -
    - name = pair->value;
    -
    - /* Look ahead to see if we have the federation info about the buddy */
    - for (tmplist = l->next; tmplist; tmplist = tmplist->next) {
    - struct yahoo_pair *p = tmplist->data;
    - if (p->key == 7)
    - break;
    - if (p->key == 241) {
    - fed = strtol(p->value, NULL, 10);
    - g_free(fedname);
    - switch (fed) {
    - case YAHOO_FEDERATION_MSN:
    - name = fedname = g_strconcat("msn/", name, NULL);
    - break;
    - case YAHOO_FEDERATION_OCS:
    - name = fedname = g_strconcat("ocs/", name, NULL);
    - break;
    - case YAHOO_FEDERATION_IBM:
    - name = fedname = g_strconcat("ibm/", name, NULL);
    - break;
    - case YAHOO_FEDERATION_NONE:
    - default:
    - fedname = NULL;
    - break;
    - }
    - break;
    - }
    - }
    - f = yahoo_friend_find_or_new(gc, name);
    - f->fed = fed;
    - }
    - break;
    - case 10: /* state */
    - if (!f)
    - break;
    -
    - f->status = strtol(pair->value, NULL, 10);
    - if ((f->status >= YAHOO_STATUS_BRB) && (f->status <= YAHOO_STATUS_STEPPEDOUT))
    - f->away = 1;
    - else
    - f->away = 0;
    -
    - if (f->status == YAHOO_STATUS_IDLE) {
    - /* Idle may have already been set in a more precise way in case 137 */
    - if (f->idle == 0)
    - {
    - if(pkt->service == YAHOO_SERVICE_STATUS_15)
    - f->idle = -1;
    - else
    - f->idle = time(NULL);
    - }
    - } else
    - f->idle = 0;
    -
    - if (f->status != YAHOO_STATUS_CUSTOM)
    - yahoo_friend_set_status_message(f, NULL);
    -
    - f->sms = 0;
    - break;
    - case 19: /* custom message */
    - if (f)
    - message = pair->value;
    - break;
    - case 11: /* this is the buddy's session id */
    - if (f)
    - f->session_id = strtol(pair->value, NULL, 10);
    - break;
    - case 17: /* in chat? */
    - break;
    - case 47: /* is custom status away or not? 2=idle*/
    - if (!f)
    - break;
    -
    - /* I have no idea what it means when this is
    - * set when someone's available, but it doesn't
    - * mean idle. */
    - if (f->status == YAHOO_STATUS_AVAILABLE)
    - break;
    -
    - f->away = strtol(pair->value, NULL, 10);
    - if (f->away == 2) {
    - /* Idle may have already been set in a more precise way in case 137 */
    - if (f->idle == 0)
    - {
    - if(pkt->service == YAHOO_SERVICE_STATUS_15)
    - f->idle = -1;
    - else
    - f->idle = time(NULL);
    - }
    - }
    -
    - break;
    - case 138: /* when value is 1, either we're not idle, or we are but won't say how long */
    - if (!f)
    - break;
    -
    - if( (strtol(pair->value, NULL, 10) == 1) && (f->idle) )
    - f->idle = -1;
    - break;
    - case 137: /* usually idle time in seconds, sometimes login time */
    - if (!f)
    - break;
    -
    - if (f->status != YAHOO_STATUS_AVAILABLE)
    - f->idle = time(NULL) - strtol(pair->value, NULL, 10);
    - break;
    - case 13: /* bitmask, bit 0 = pager, bit 1 = chat, bit 2 = game */
    - if (strtol(pair->value, NULL, 10) == 0) {
    - if (f)
    - f->status = YAHOO_STATUS_OFFLINE;
    - if (name) {
    - purple_prpl_got_user_status(account, name, "offline", NULL);
    - purple_prpl_got_user_status_deactive(account, name, YAHOO_STATUS_TYPE_MOBILE);
    - }
    - break;
    - }
    - break;
    - case 60: /* SMS */
    - if (f) {
    - f->sms = strtol(pair->value, NULL, 10);
    - yahoo_update_status(gc, name, f);
    - }
    - break;
    - case 197: /* Avatars */
    - {
    - guchar *decoded;
    - char *tmp;
    - gsize len;
    -
    - if (pair->value) {
    - decoded = purple_base64_decode(pair->value, &len);
    - if (decoded && len > 0) {
    - tmp = purple_str_binary_to_ascii(decoded, len);
    - purple_debug_info("yahoo", "Got key 197, value = %s\n", tmp);
    - g_free(tmp);
    - }
    - g_free(decoded);
    - }
    - break;
    - }
    - case 192: /* Pictures, aka Buddy Icons, checksum */
    - {
    - /* FIXME: Please, if you know this protocol,
    - * FIXME: fix up the strtol() stuff if possible. */
    - int cksum = strtol(pair->value, NULL, 10);
    - const char *locksum = NULL;
    - PurpleBuddy *b;
    -
    - if (!name)
    - break;
    -
    - b = purple_find_buddy(gc->account, name);
    -
    - if (!cksum || (cksum == -1)) {
    - if (f)
    - yahoo_friend_set_buddy_icon_need_request(f, TRUE);
    - purple_buddy_icons_set_for_user(gc->account, name, NULL, 0, NULL);
    - break;
    - }
    -
    - if (!f)
    - break;
    -
    - yahoo_friend_set_buddy_icon_need_request(f, FALSE);
    - if (b) {
    - locksum = purple_buddy_icons_get_checksum_for_user(b);
    - if (!locksum || (cksum != strtol(locksum, NULL, 10)))
    - yahoo_send_picture_request(gc, name);
    - }
    -
    - break;
    - }
    - case 16: /* Custom error message */
    - {
    - char *tmp = yahoo_string_decode(gc, pair->value, TRUE);
    - purple_notify_error(gc, NULL, tmp, NULL);
    - g_free(tmp);
    - }
    - break;
    - case 97: /* Unicode status message */
    - unicode = !strcmp(pair->value, "1");
    - break;
    - case 244: /* client version number. Yahoo Client Detection */
    - if(f && strtol(pair->value, NULL, 10))
    - f->version_id = strtol(pair->value, NULL, 10);
    - break;
    - case 241: /* Federated network buddy belongs to */
    - break; /* We process this when get '7' */
    - default:
    - purple_debug_warning("yahoo",
    - "Unknown status key %d\n", pair->key);
    - break;
    - }
    -
    - l = l->next;
    - }
    -
    - if (f) {
    - if (pkt->service == YAHOO_SERVICE_LOGOFF)
    - f->status = YAHOO_STATUS_OFFLINE;
    - if (message)
    - yahoo_friend_set_status_message(f, yahoo_string_decode(gc, message, unicode));
    -
    - if (name) /* update the last buddy */
    - yahoo_update_status(gc, name, f);
    - }
    -
    - g_free(fedname);
    -}
    -
    -static void yahoo_do_group_check(PurpleAccount *account, GHashTable *ht, const char *name, const char *group)
    -{
    - PurpleBuddy *b;
    - PurpleGroup *g;
    - GSList *list, *i;
    - gboolean onlist = FALSE;
    - char *oname = NULL;
    -
    - if (g_hash_table_lookup_extended(ht, name, (gpointer *)&oname, (gpointer *)&list))
    - g_hash_table_steal(ht, oname);
    - else
    - list = purple_find_buddies(account, name);
    -
    - for (i = list; i; i = i->next) {
    - b = i->data;
    - g = purple_buddy_get_group(b);
    - if (!purple_utf8_strcasecmp(group, purple_group_get_name(g))) {
    - purple_debug_misc("yahoo",
    - "Oh good, %s is in the right group (%s).\n", name, group);
    - list = g_slist_delete_link(list, i);
    - onlist = TRUE;
    - break;
    - }
    - }
    -
    - if (!onlist) {
    - purple_debug_misc("yahoo",
    - "Uhoh, %s isn't on the list (or not in this group), adding him to group %s.\n", name, group);
    - if (!(g = purple_find_group(group))) {
    - g = purple_group_new(group);
    - purple_blist_add_group(g, NULL);
    - }
    - b = purple_buddy_new(account, name, NULL);
    - purple_blist_add_buddy(b, NULL, g, NULL);
    - }
    -
    - if (list) {
    - if (!oname)
    - oname = g_strdup(name);
    - g_hash_table_insert(ht, oname, list);
    - } else
    - g_free(oname);
    -}
    -
    -static void yahoo_do_group_cleanup(gpointer key, gpointer value, gpointer user_data)
    -{
    - char *name = key;
    - GSList *list = value, *i;
    - PurpleBuddy *b;
    - PurpleGroup *g;
    -
    - for (i = list; i; i = i->next) {
    - b = i->data;
    - g = purple_buddy_get_group(b);
    - purple_debug_misc("yahoo", "Deleting Buddy %s from group %s.\n", name,
    - purple_group_get_name(g));
    - purple_blist_remove_buddy(b);
    - }
    -}
    -
    -static char *_getcookie(char *rawcookie)
    -{
    - char *cookie = NULL;
    - char *tmpcookie;
    - char *cookieend;
    -
    - if (strlen(rawcookie) < 2)
    - return NULL;
    - tmpcookie = g_strdup(rawcookie+2);
    - cookieend = strchr(tmpcookie, ';');
    -
    - if (cookieend)
    - *cookieend = '\0';
    -
    - cookie = g_strdup(tmpcookie);
    - g_free(tmpcookie);
    -
    - return cookie;
    -}
    -
    -static void yahoo_process_cookie(YahooData *yd, char *c)
    -{
    - if (c[0] == 'Y') {
    - if (yd->cookie_y)
    - g_free(yd->cookie_y);
    - yd->cookie_y = _getcookie(c);
    - } else if (c[0] == 'T') {
    - if (yd->cookie_t)
    - g_free(yd->cookie_t);
    - yd->cookie_t = _getcookie(c);
    - } else
    - purple_debug_info("yahoo", "Unrecognized cookie '%c'\n", c[0]);
    - yd->cookies = g_slist_prepend(yd->cookies, g_strdup(c));
    -}
    -
    -static void yahoo_process_list_15(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - GSList *l = pkt->hash;
    -
    - PurpleAccount *account = purple_connection_get_account(gc);
    - YahooData *yd = gc->proto_data;
    - GHashTable *ht;
    - char *norm_bud = NULL;
    - char *temp = NULL;
    - YahooFriend *f = NULL; /* It's your friends. They're going to want you to share your StarBursts. */
    - /* But what if you had no friends? */
    - YahooFederation fed = YAHOO_FEDERATION_NONE;
    - int stealth = 0;
    -
    - ht = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_slist_free);
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    - l = l->next;
    -
    - switch (pair->key) {
    - case 302:
    - /* This is always 318 before a group, 319 before the first s/n in a group, 320 before any ignored s/n.
    - * It is not sent for s/n's in a group after the first.
    - * All ignored s/n's are listed last, so when we see a 320 we clear the group and begin marking the
    - * s/n's as ignored. It is always followed by an identical 300 key.
    - */
    - if (pair->value && !strcmp(pair->value, "320")) {
    - /* No longer in any group; this indicates the start of the ignore list. */
    - g_free(yd->current_list15_grp);
    - yd->current_list15_grp = NULL;
    - }
    -
    - break;
    - case 301: /* This is 319 before all s/n's in a group after the first. It is followed by an identical 300. */
    - if(temp != NULL) {
    - switch (fed) {
    - case YAHOO_FEDERATION_MSN:
    - norm_bud = g_strconcat("msn/", temp, NULL);
    - break;
    - case YAHOO_FEDERATION_OCS:
    - norm_bud = g_strconcat("ocs/", temp, NULL);
    - break;
    - case YAHOO_FEDERATION_IBM:
    - norm_bud = g_strconcat("ibm/", temp, NULL);
    - break;
    - case YAHOO_FEDERATION_PBX:
    - norm_bud = g_strconcat("pbx/", temp, NULL);
    - break;
    - case YAHOO_FEDERATION_NONE:
    - norm_bud = g_strdup(temp);
    - break;
    - }
    - if (yd->current_list15_grp) {
    - /* This buddy is in a group */
    - f = yahoo_friend_find_or_new(gc, norm_bud);
    - if (!purple_find_buddy(account, norm_bud)) {
    - PurpleBuddy *b;
    - PurpleGroup *g;
    - if (!(g = purple_find_group(yd->current_list15_grp))) {
    - g = purple_group_new(yd->current_list15_grp);
    - purple_blist_add_group(g, NULL);
    - }
    - b = purple_buddy_new(account, norm_bud, NULL);
    - purple_blist_add_buddy(b, NULL, g, NULL);
    - }
    - yahoo_do_group_check(account, ht, norm_bud, yd->current_list15_grp);
    - if(fed) {
    - f->fed = fed;
    - purple_debug_info("yahoo", "Setting federation to %d\n", f->fed);
    - }
    - if(stealth == 2)
    - f->presence = YAHOO_PRESENCE_PERM_OFFLINE;
    -
    - /* set p2p status not connected and no p2p packet sent */
    - if(fed == YAHOO_FEDERATION_NONE) {
    - yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED);
    - f->p2p_packet_sent = 0;
    - } else
    - yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_DO_NOT_CONNECT);
    - } else {
    - /* This buddy is on the ignore list (and therefore in no group) */
    - purple_debug_info("yahoo", "%s adding %s to the deny list because of the ignore list / no group was found\n",account->username, norm_bud);
    - purple_privacy_deny_add(account, norm_bud, 1);
    - }
    -
    - g_free(norm_bud);
    - norm_bud=NULL;
    - fed = YAHOO_FEDERATION_NONE;
    - stealth = 0;
    - g_free(temp);
    - temp = NULL;
    - }
    - break;
    - case 300: /* This is 318 before a group, 319 before any s/n in a group, and 320 before any ignored s/n. */
    - break;
    - case 65: /* This is the group */
    - g_free(yd->current_list15_grp);
    - yd->current_list15_grp = yahoo_string_decode(gc, pair->value, FALSE);
    - break;
    - case 7: /* buddy's s/n */
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - g_free(temp);
    - temp = g_strdup(purple_normalize(account, pair->value));
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_list_15 "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 241: /* user on federated network */
    - fed = strtol(pair->value, NULL, 10);
    - break;
    - case 59: /* somebody told cookies come here too, but im not sure */
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - yahoo_process_cookie(yd, pair->value);
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_list_15 "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 317: /* Stealth Setting */
    - stealth = strtol(pair->value, NULL, 10);
    - break;
    - /* case 242: */ /* this seems related to 241 */
    - /* break; */
    - }
    - }
    -
    - g_hash_table_foreach(ht, yahoo_do_group_cleanup, NULL);
    -
    - /* The reporter of ticket #9745 determined that we weren't retrieving the
    - * aliases during buddy list retrieval, so we never updated aliases that
    - * changed while we were signed off. */
    - yahoo_fetch_aliases(gc);
    -
    - /* Now that we have processed the buddy list, we can say yahoo has connected */
    - purple_connection_set_display_name(gc, purple_normalize(account, purple_account_get_username(account)));
    - yd->logged_in = TRUE;
    - purple_debug_info("yahoo","Authentication: Connection established\n");
    - purple_connection_set_state(gc, PURPLE_CONNECTED);
    - if (yd->picture_upload_todo) {
    - yahoo_buddy_icon_upload(gc, yd->picture_upload_todo);
    - yd->picture_upload_todo = NULL;
    - }
    - yahoo_set_status(account, purple_account_get_active_status(account));
    -
    - g_hash_table_destroy(ht);
    - g_free(temp);
    -}
    -
    -static void yahoo_process_list(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - GSList *l = pkt->hash;
    - gboolean got_serv_list = FALSE;
    - YahooFriend *f = NULL;
    - PurpleAccount *account = purple_connection_get_account(gc);
    - YahooData *yd = gc->proto_data;
    - GHashTable *ht;
    -
    - char **lines;
    - char **split;
    - char **buddies;
    - char **tmp, **bud, *norm_bud;
    - char *grp = NULL;
    -
    - if (pkt->id)
    - yd->session_id = pkt->id;
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    - l = l->next;
    -
    - switch (pair->key) {
    - case 87:
    - if (!yd->tmp_serv_blist)
    - yd->tmp_serv_blist = g_string_new(pair->value);
    - else
    - g_string_append(yd->tmp_serv_blist, pair->value);
    - break;
    - case 88:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - if (!yd->tmp_serv_ilist)
    - yd->tmp_serv_ilist = g_string_new(pair->value);
    - else
    - g_string_append(yd->tmp_serv_ilist, pair->value);
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_list "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 89:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - yd->profiles = g_strsplit(pair->value, ",", -1);
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_list "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 59: /* cookies, yum */
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - yahoo_process_cookie(yd, pair->value);
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_list "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case YAHOO_SERVICE_PRESENCE_PERM:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - if (!yd->tmp_serv_plist)
    - yd->tmp_serv_plist = g_string_new(pair->value);
    - else
    - g_string_append(yd->tmp_serv_plist, pair->value);
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_list "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - }
    - }
    -
    - if (pkt->status != 0)
    - return;
    -
    - if (yd->tmp_serv_blist) {
    - ht = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_slist_free);
    -
    - lines = g_strsplit(yd->tmp_serv_blist->str, "\n", -1);
    - for (tmp = lines; *tmp; tmp++) {
    - split = g_strsplit(*tmp, ":", 2);
    - if (!split)
    - continue;
    - if (!split[0] || !split[1]) {
    - g_strfreev(split);
    - continue;
    - }
    - grp = yahoo_string_decode(gc, split[0], FALSE);
    - buddies = g_strsplit(split[1], ",", -1);
    - for (bud = buddies; bud && *bud; bud++) {
    - if (!g_utf8_validate(*bud, -1, NULL)) {
    - purple_debug_warning("yahoo", "yahoo_process_list "
    - "got non-UTF-8 string for bud\n");
    - continue;
    - }
    -
    - norm_bud = g_strdup(purple_normalize(account, *bud));
    - f = yahoo_friend_find_or_new(gc, norm_bud);
    -
    - if (!purple_find_buddy(account, norm_bud)) {
    - PurpleBuddy *b;
    - PurpleGroup *g;
    - if (!(g = purple_find_group(grp))) {
    - g = purple_group_new(grp);
    - purple_blist_add_group(g, NULL);
    - }
    - b = purple_buddy_new(account, norm_bud, NULL);
    - purple_blist_add_buddy(b, NULL, g, NULL);
    - }
    -
    - yahoo_do_group_check(account, ht, norm_bud, grp);
    - /* set p2p status not connected and no p2p packet sent */
    - yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED);
    - f->p2p_packet_sent = 0;
    -
    - g_free(norm_bud);
    - }
    - g_strfreev(buddies);
    - g_strfreev(split);
    - g_free(grp);
    - }
    - g_strfreev(lines);
    -
    - g_string_free(yd->tmp_serv_blist, TRUE);
    - yd->tmp_serv_blist = NULL;
    - g_hash_table_foreach(ht, yahoo_do_group_cleanup, NULL);
    - g_hash_table_destroy(ht);
    - }
    -
    - if (yd->tmp_serv_ilist) {
    - buddies = g_strsplit(yd->tmp_serv_ilist->str, ",", -1);
    - for (bud = buddies; bud && *bud; bud++) {
    - /* The server is already ignoring the user */
    - got_serv_list = TRUE;
    - purple_privacy_deny_add(account, *bud, 1);
    - }
    - g_strfreev(buddies);
    -
    - g_string_free(yd->tmp_serv_ilist, TRUE);
    - yd->tmp_serv_ilist = NULL;
    - }
    -
    - if (got_serv_list &&
    - ((account->perm_deny != PURPLE_PRIVACY_ALLOW_BUDDYLIST) &&
    - (account->perm_deny != PURPLE_PRIVACY_DENY_ALL) &&
    - (account->perm_deny != PURPLE_PRIVACY_ALLOW_USERS)))
    - {
    - account->perm_deny = PURPLE_PRIVACY_DENY_USERS;
    - purple_debug_info("yahoo", "%s privacy defaulting to PURPLE_PRIVACY_DENY_USERS.\n",
    - account->username);
    - }
    -
    - if (yd->tmp_serv_plist) {
    - buddies = g_strsplit(yd->tmp_serv_plist->str, ",", -1);
    - for (bud = buddies; bud && *bud; bud++) {
    - f = yahoo_friend_find(gc, *bud);
    - if (f) {
    - purple_debug_info("yahoo", "%s setting presence for %s to PERM_OFFLINE\n",
    - account->username, *bud);
    - f->presence = YAHOO_PRESENCE_PERM_OFFLINE;
    - }
    - }
    - g_strfreev(buddies);
    - g_string_free(yd->tmp_serv_plist, TRUE);
    - yd->tmp_serv_plist = NULL;
    -
    - }
    - /* Now that we've got the list, request aliases */
    - yahoo_fetch_aliases(gc);
    -}
    -
    -/* pkt_type is YAHOO_PKT_TYPE_SERVER if pkt arrives from yahoo server, YAHOO_PKT_TYPE_P2P if pkt arrives through p2p */
    -static void yahoo_process_notify(PurpleConnection *gc, struct yahoo_packet *pkt, yahoo_pkt_type pkt_type)
    -{
    - PurpleAccount *account;
    - char *msg = NULL;
    - char *from = NULL;
    - char *stat = NULL;
    - char *game = NULL;
    - YahooFriend *f = NULL;
    - GSList *l = pkt->hash;
    - gint val_11 = 0;
    - YahooData *yd = gc->proto_data;
    - YahooFederation fed = YAHOO_FEDERATION_NONE;
    -
    - account = purple_connection_get_account(gc);
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    - if (pair->key == 4 || pair->key == 1) {
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - from = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_notify "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - }
    - if (pair->key == 49)
    - msg = pair->value;
    - if (pair->key == 13)
    - stat = pair->value;
    - if (pair->key == 14) {
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - game = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_notify "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - }
    - if (pair->key == 11)
    - val_11 = strtol(pair->value, NULL, 10);
    - if (pair->key == 241)
    - fed = strtol(pair->value, NULL, 10);
    - l = l->next;
    - }
    -
    - if (!from || !msg)
    - return;
    -
    - /* disconnect the peer if connected through p2p and sends wrong value for session id */
    - if( (pkt_type == YAHOO_PKT_TYPE_P2P) && (val_11 != yd->session_id) ) {
    - purple_debug_warning("yahoo","p2p: %s sent us notify with wrong session id. Disconnecting p2p connection to peer\n", from);
    - /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
    - g_hash_table_remove(yd->peers, from);
    - return;
    - }
    -
    - if (!g_ascii_strncasecmp(msg, "TYPING", strlen("TYPING"))
    - && (purple_privacy_check(account, from)))
    - {
    - char *fed_from = from;
    - switch (fed) {
    - case YAHOO_FEDERATION_MSN:
    - fed_from = g_strconcat("msn/", from, NULL);
    - break;
    - case YAHOO_FEDERATION_OCS:
    - fed_from = g_strconcat("ocs/", from, NULL);
    - break;
    - case YAHOO_FEDERATION_IBM:
    - fed_from = g_strconcat("ibm/", from, NULL);
    - break;
    - case YAHOO_FEDERATION_PBX:
    - fed_from = g_strconcat("pbx/", from, NULL);
    - break;
    - case YAHOO_FEDERATION_NONE:
    - default:
    - break;
    - }
    -
    - if (stat && *stat == '1')
    - serv_got_typing(gc, fed_from, 0, PURPLE_TYPING);
    - else
    - serv_got_typing_stopped(gc, fed_from);
    -
    - if (fed_from != from)
    - g_free(fed_from);
    -
    - } else if (!g_ascii_strncasecmp(msg, "GAME", strlen("GAME"))) {
    - PurpleBuddy *bud = purple_find_buddy(account, from);
    -
    - if (!bud) {
    - purple_debug_warning("yahoo",
    - "%s is playing a game, and doesn't want you to know.\n", from);
    - }
    -
    - f = yahoo_friend_find(gc, from);
    - if (!f)
    - return; /* if they're not on the list, don't bother */
    -
    - yahoo_friend_set_game(f, NULL);
    -
    - if (stat && *stat == '1') {
    - yahoo_friend_set_game(f, game);
    - if (bud)
    - yahoo_update_status(gc, from, f);
    - }
    - } else if (!g_ascii_strncasecmp(msg, "WEBCAMINVITE", strlen("WEBCAMINVITE"))) {
    - PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, from, account);
    - char *buf = g_strdup_printf(_("%s has sent you a webcam invite, which is not yet supported."), from);
    - purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_SYSTEM|PURPLE_MESSAGE_NOTIFY, time(NULL));
    - g_free(buf);
    - }
    -}
    -
    -
    -struct _yahoo_im {
    - char *from;
    - char *active_id;
    - int time;
    - int utf8;
    - int buddy_icon;
    - char *id;
    - char *msg;
    - YahooFederation fed;
    - char *fed_from;
    -};
    -
    -static void yahoo_process_sms_message(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - PurpleAccount *account;
    - GSList *l = pkt->hash;
    - struct _yahoo_im *sms = NULL;
    - YahooData *yd;
    - char *server_msg = NULL;
    - char *m;
    -
    - yd = gc->proto_data;
    - account = purple_connection_get_account(gc);
    -
    - while (l != NULL) {
    - struct yahoo_pair *pair = l->data;
    - if (pair->key == 4) {
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - sms = g_new0(struct _yahoo_im, 1);
    - sms->from = g_strdup_printf("+%s", pair->value);
    - sms->time = time(NULL);
    - sms->utf8 = TRUE;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_sms_message "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - }
    - if (pair->key == 14) {
    - if (sms)
    - sms->msg = pair->value;
    - }
    - if (pair->key == 68)
    - if(sms)
    - g_hash_table_insert(yd->sms_carrier, g_strdup(sms->from), g_strdup(pair->value));
    - if (pair->key == 16) {
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - server_msg = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_sms_message "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - }
    - l = l->next;
    - }
    -
    - if(!sms) {
    - purple_debug_info("yahoo", "Received a malformed SMS packet!\n");
    - return;
    - }
    -
    - if ((int)pkt->status < 0)
    - pkt->status = YAHOO_STATUS_DISCONNECTED;
    - if (pkt->status == YAHOO_STATUS_DISCONNECTED) {
    - if (server_msg) {
    - PurpleConversation *c;
    - c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms->from, account);
    - if (c == NULL)
    - c = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sms->from);
    - purple_conversation_write(c, NULL, server_msg, PURPLE_MESSAGE_SYSTEM, time(NULL));
    - }
    - else
    - purple_notify_error(gc, NULL, _("Your SMS was not delivered"), NULL);
    -
    - g_free(sms->from);
    - g_free(sms);
    - return ;
    - }
    -
    - if (!sms->from || !sms->msg) {
    - g_free(sms);
    - return;
    - }
    -
    - m = yahoo_string_decode(gc, sms->msg, sms->utf8);
    - serv_got_im(gc, sms->from, m, 0, sms->time);
    -
    - g_free(m);
    - g_free(sms->from);
    - g_free(sms);
    -}
    -
    -/* pkt_type is YAHOO_PKT_TYPE_SERVER if pkt arrives from yahoo server, YAHOO_PKT_TYPE_P2P if pkt arrives through p2p */
    -static void yahoo_process_message(PurpleConnection *gc, struct yahoo_packet *pkt, yahoo_pkt_type pkt_type)
    -{
    - PurpleAccount *account;
    - YahooData *yd = gc->proto_data;
    - GSList *l = pkt->hash;
    - GSList *list = NULL;
    - struct _yahoo_im *im = NULL;
    -
    - account = purple_connection_get_account(gc);
    -
    - if (pkt->status <= 1 || pkt->status == 5 || pkt->status == YAHOO_STATUS_OFFLINE) {
    - /* messages are received with status YAHOO_STATUS_OFFLINE in case of p2p */
    - while (l != NULL) {
    - struct yahoo_pair *pair = l->data;
    - if (pair->key == 4 || pair->key == 1) {
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - im = g_new0(struct _yahoo_im, 1);
    - list = g_slist_append(list, im);
    - im->from = pair->value;
    - im->time = time(NULL);
    - im->utf8 = TRUE;
    - im->fed = YAHOO_FEDERATION_NONE;
    - im->fed_from = g_strdup(im->from);
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_message "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - }
    - if (im && pair->key == 5)
    - im->active_id = pair->value;
    - if (pair->key == 97)
    - if (im)
    - im->utf8 = strtol(pair->value, NULL, 10);
    - if (pair->key == 15)
    - if (im)
    - im->time = strtol(pair->value, NULL, 10);
    - if (pair->key == 206)
    - if (im)
    - im->buddy_icon = strtol(pair->value, NULL, 10);
    - if (pair->key == 14) {
    - if (im)
    - im->msg = pair->value;
    - }
    - if (im && pair->key == 241) {
    - im->fed = strtol(pair->value, NULL, 10);
    - g_free(im->fed_from);
    - switch (im->fed) {
    - case YAHOO_FEDERATION_MSN:
    - im->fed_from = g_strconcat("msn/",im->from, NULL);
    - break;
    - case YAHOO_FEDERATION_OCS:
    - im->fed_from = g_strconcat("ocs/",im->from, NULL);
    - break;
    - case YAHOO_FEDERATION_IBM:
    - im->fed_from = g_strconcat("ibm/",im->from, NULL);
    - break;
    - case YAHOO_FEDERATION_PBX:
    - im->fed_from = g_strconcat("pbx/",im->from, NULL);
    - break;
    - case YAHOO_FEDERATION_NONE:
    - default:
    - im->fed_from = g_strdup(im->from);
    - break;
    - }
    - purple_debug_info("yahoo", "Message from federated (%d) buddy %s.\n", im->fed, im->fed_from);
    -
    - }
    - /* peer session id */
    - if (im && (pair->key == 11)) {
    - /* disconnect the peer if connected through p2p and sends wrong value for session id */
    - if( (im->fed == YAHOO_FEDERATION_NONE) && (pkt_type == YAHOO_PKT_TYPE_P2P)
    - && (yd->session_id != strtol(pair->value, NULL, 10)) )
    - {
    - purple_debug_warning("yahoo","p2p: %s sent us message with wrong session id. Disconnecting p2p connection to peer\n", im->fed_from);
    - /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
    - g_hash_table_remove(yd->peers, im->fed_from);
    - g_free(im->fed_from);
    - g_free(im);
    - return; /* Not sure whether we should process remaining IMs in this packet */
    - }
    - }
    - /* IMV key */
    - if (im && pair->key == 63 && g_utf8_validate(pair->value, -1, NULL))
    - {
    - /* Check for the Doodle IMV, no IMvironment for federated buddies */
    - if (im->from != NULL && im->fed == YAHOO_FEDERATION_NONE)
    - {
    - g_hash_table_replace(yd->imvironments, g_strdup(im->from), g_strdup(pair->value));
    -
    - if (strstr(pair->value, "doodle;") != NULL)
    - {
    - PurpleWhiteboard *wb;
    -
    - if (!purple_privacy_check(account, im->from)) {
    - purple_debug_info("yahoo", "Doodle request from %s dropped.\n",
    - im->from);
    - g_free(im->fed_from);
    - g_free(im);
    - return;
    - }
    - /* I'm not sure the following ever happens -DAA */
    - wb = purple_whiteboard_get_session(account, im->from);
    -
    - /* If a Doodle session doesn't exist between this user */
    - if(wb == NULL)
    - {
    - doodle_session *ds;
    - wb = purple_whiteboard_create(account, im->from,
    - DOODLE_STATE_REQUESTED);
    - ds = wb->proto_data;
    - ds->imv_key = g_strdup(pair->value);
    -
    - yahoo_doodle_command_send_request(gc, im->from, pair->value);
    - yahoo_doodle_command_send_ready(gc, im->from, pair->value);
    - }
    - }
    - }
    - }
    - if (pair->key == 429)
    - if (im)
    - im->id = pair->value;
    - l = l->next;
    - }
    - } else if (pkt->status == 2) {
    - purple_notify_error(gc, NULL,
    - _("Your Yahoo! message did not get sent."), NULL);
    - }
    -
    - for (l = list; l; l = l->next) {
    - YahooFriend *f;
    - char *m, *m2;
    - im = l->data;
    -
    - if (!im->fed_from || !im->msg) {
    - g_free(im->fed_from);
    - g_free(im);
    - continue;
    - }
    -
    - if (!purple_privacy_check(account, im->fed_from)) {
    - purple_debug_info("yahoo", "Message from %s dropped.\n", im->fed_from);
    - return;
    - }
    -
    - /*
    - * TODO: Is there anything else we should check when determining whether
    - * we should send an acknowledgement?
    - */
    - if (im->id != NULL) {
    - /* Send acknowledgement. If we don't do this then the official
    - * Yahoo Messenger client for Windows will send us the same
    - * message 7 seconds later as an offline message. This is true
    - * for at least version 9.0.0.2162 on Windows XP. */
    - struct yahoo_packet *pkt2;
    - pkt2 = yahoo_packet_new(YAHOO_SERVICE_MESSAGE_ACK,
    - YAHOO_STATUS_AVAILABLE, pkt->id);
    - yahoo_packet_hash(pkt2, "ssisii",
    - 1, im->active_id, /* May not always be the connection's display name */
    - 5, im->from,
    - 302, 430,
    - 430, im->id,
    - 303, 430,
    - 450, 0);
    - yahoo_packet_send_and_free(pkt2, yd);
    - }
    -
    - m = yahoo_string_decode(gc, im->msg, im->utf8);
    - /* This may actually not be necessary, but it appears
    - * that at least at one point some clients were sending
    - * "\r\n" as line delimiters, so we want to avoid double
    - * lines. */
    - m2 = purple_strreplace(m, "\r\n", "\n");
    - g_free(m);
    - m = m2;
    - purple_util_chrreplace(m, '\r', '\n');
    - if (!strcmp(m, "<ding>")) {
    - char *username;
    -
    - username = g_markup_escape_text(im->fed_from, -1);
    - purple_prpl_got_attention(gc, username, YAHOO_BUZZ);
    - g_free(username);
    - g_free(m);
    - g_free(im->fed_from);
    - g_free(im);
    - continue;
    - }
    -
    - m2 = yahoo_codes_to_html(m);
    - g_free(m);
    -
    - serv_got_im(gc, im->fed_from, m2, 0, im->time);
    - g_free(m2);
    -
    - /* Official clients don't share buddy images with federated buddies */
    - if (im->fed == YAHOO_FEDERATION_NONE) {
    - if ((f = yahoo_friend_find(gc, im->from)) && im->buddy_icon == 2) {
    - if (yahoo_friend_get_buddy_icon_need_request(f)) {
    - yahoo_send_picture_request(gc, im->from);
    - yahoo_friend_set_buddy_icon_need_request(f, FALSE);
    - }
    - }
    - }
    -
    - g_free(im->fed_from);
    - g_free(im);
    - }
    -
    - g_slist_free(list);
    -}
    -
    -static void yahoo_process_sysmessage(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - GSList *l = pkt->hash;
    - char *prim, *me = NULL, *msg = NULL;
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    -
    - if (pair->key == 5) {
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - me = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_sysmessage "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - }
    - if (pair->key == 14) {
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - msg = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_sysmessage "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - }
    -
    - l = l->next;
    - }
    -
    - if (!msg || !g_utf8_validate(msg, -1, NULL))
    - return;
    -
    - prim = g_strdup_printf(_("Yahoo! system message for %s:"),
    - me?me:purple_connection_get_display_name(gc));
    - purple_notify_info(NULL, NULL, prim, msg);
    - g_free(prim);
    -}
    -
    -struct yahoo_add_request {
    - PurpleConnection *gc;
    - char *id;
    - char *who;
    - YahooFederation fed;
    -};
    -
    -static void
    -yahoo_buddy_add_authorize_cb(gpointer data)
    -{
    - struct yahoo_add_request *add_req = data;
    - struct yahoo_packet *pkt;
    - YahooData *yd = add_req->gc->proto_data;
    - const char *who = add_req->who;
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH_REQ_15, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - if (add_req->fed) {
    - who += 4;
    - yahoo_packet_hash(pkt, "ssiii",
    - 1, add_req->id,
    - 5, who,
    - 241, add_req->fed,
    - 13, 1,
    - 334, 0);
    - }
    - else {
    - yahoo_packet_hash(pkt, "ssii",
    - 1, add_req->id,
    - 5, who,
    - 13, 1,
    - 334, 0);
    - }
    -
    - yahoo_packet_send_and_free(pkt, yd);
    -
    - g_free(add_req->id);
    - g_free(add_req->who);
    - g_free(add_req);
    -}
    -
    -static void
    -yahoo_buddy_add_deny_cb(struct yahoo_add_request *add_req, const char *msg)
    -{
    - YahooData *yd = add_req->gc->proto_data;
    - struct yahoo_packet *pkt;
    - char *encoded_msg = NULL;
    - const char *who = add_req->who;
    -
    - if (msg && *msg)
    - encoded_msg = yahoo_string_encode(add_req->gc, msg, NULL);
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH_REQ_15,
    - YAHOO_STATUS_AVAILABLE, yd->session_id);
    -
    - if (add_req->fed) {
    - who += 4; /* Skip fed identifier (msn|ocs|ibm)/' */
    - yahoo_packet_hash(pkt, "ssiiiis",
    - 1, add_req->id,
    - 5, who,
    - 241, add_req->fed,
    - 13, 2,
    - 334, 0,
    - 97, 1,
    - 14, encoded_msg ? encoded_msg : "");
    - }
    - else {
    - yahoo_packet_hash(pkt, "ssiiis",
    - 1, add_req->id,
    - 5, who,
    - 13, 2,
    - 334, 0,
    - 97, 1,
    - 14, encoded_msg ? encoded_msg : "");
    - }
    -
    -
    - yahoo_packet_send_and_free(pkt, yd);
    -
    - g_free(encoded_msg);
    -
    - g_free(add_req->id);
    - g_free(add_req->who);
    - g_free(add_req);
    -}
    -
    -static void
    -yahoo_buddy_add_deny_noreason_cb(struct yahoo_add_request *add_req, const char*msg)
    -{
    - yahoo_buddy_add_deny_cb(add_req, NULL);
    -}
    -
    -static void
    -yahoo_buddy_add_deny_reason_cb(gpointer data) {
    - struct yahoo_add_request *add_req = data;
    - purple_request_input(add_req->gc, NULL, _("Authorization denied message:"),
    - NULL, _("No reason given."), TRUE, FALSE, NULL,
    - _("OK"), G_CALLBACK(yahoo_buddy_add_deny_cb),
    - _("Cancel"), G_CALLBACK(yahoo_buddy_add_deny_noreason_cb),
    - purple_connection_get_account(add_req->gc), add_req->who, NULL,
    - add_req);
    -}
    -
    -static void yahoo_buddy_denied_our_add(PurpleConnection *gc, const char *who, const char *reason)
    -{
    - char *notify_msg;
    - YahooData *yd = gc->proto_data;
    -
    - if (who == NULL)
    - return;
    -
    - if (reason != NULL) {
    - char *msg2 = yahoo_string_decode(gc, reason, FALSE);
    - notify_msg = g_strdup_printf(_("%s has (retroactively) denied your request to add them to your list for the following reason: %s."), who, msg2);
    - g_free(msg2);
    - } else
    - notify_msg = g_strdup_printf(_("%s has (retroactively) denied your request to add them to your list."), who);
    -
    - purple_notify_info(gc, NULL, _("Add buddy rejected"), notify_msg);
    - g_free(notify_msg);
    -
    - g_hash_table_remove(yd->friends, who);
    - purple_prpl_got_user_status(purple_connection_get_account(gc), who, "offline", NULL); /* FIXME: make this set not on list status instead */
    - /* TODO: Shouldn't we remove the buddy from our local list? */
    -}
    -
    -static void yahoo_buddy_auth_req_15(PurpleConnection *gc, struct yahoo_packet *pkt) {
    - PurpleAccount *account;
    - GSList *l = pkt->hash;
    - const char *msg = NULL;
    -
    - account = purple_connection_get_account(gc);
    -
    - /* Buddy authorized/declined our addition */
    - if (pkt->status == 1) {
    - char *temp = NULL;
    - char *who = NULL;
    - int response = 0;
    - YahooFederation fed = YAHOO_FEDERATION_NONE;
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 4:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - temp = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 13:
    - response = strtol(pair->value, NULL, 10);
    - break;
    - case 14:
    - msg = pair->value;
    - break;
    - case 241:
    - fed = strtol(pair->value, NULL, 10);
    - break;
    - }
    - l = l->next;
    - }
    -
    - switch (fed) {
    - case YAHOO_FEDERATION_MSN:
    - who = g_strconcat("msn/", temp, NULL);
    - break;
    - case YAHOO_FEDERATION_OCS:
    - who = g_strconcat("ocs/", temp, NULL);
    - break;
    - case YAHOO_FEDERATION_IBM:
    - who = g_strconcat("ibm/", temp, NULL);
    - break;
    - case YAHOO_FEDERATION_NONE:
    - default:
    - who = g_strdup(temp);
    - break;
    - }
    -
    - if (response == 1) /* Authorized */
    - purple_debug_info("yahoo", "Received authorization from buddy '%s'.\n", who ? who : "(Unknown Buddy)");
    - else if (response == 2) { /* Declined */
    - purple_debug_info("yahoo", "Received authorization decline from buddy '%s'.\n", who ? who : "(Unknown Buddy)");
    - yahoo_buddy_denied_our_add(gc, who, msg);
    - } else
    - purple_debug_error("yahoo", "Received unknown authorization response of %d from buddy '%s'.\n", response, who ? who : "(Unknown Buddy)");
    - g_free(who);
    - }
    - /* Buddy requested authorization to add us. */
    - else if (pkt->status == 3) {
    - struct yahoo_add_request *add_req;
    - const char *firstname = NULL, *lastname = NULL;
    - char *temp = NULL;
    -
    - add_req = g_new0(struct yahoo_add_request, 1);
    - add_req->gc = gc;
    - add_req->fed = YAHOO_FEDERATION_NONE;
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 4:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - temp = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 5:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - add_req->id = g_strdup(pair->value);
    - } else {
    - purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 14:
    - msg = pair->value;
    - break;
    - case 216:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - firstname = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 241:
    - add_req->fed = strtol(pair->value, NULL, 10);
    - break;
    - case 254:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - lastname = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    -
    - }
    - l = l->next;
    - }
    - switch (add_req->fed) {
    - case YAHOO_FEDERATION_MSN:
    - add_req->who = g_strconcat("msn/", temp, NULL);
    - break;
    - case YAHOO_FEDERATION_OCS:
    - add_req->who = g_strconcat("ocs/", temp, NULL);
    - break;
    - case YAHOO_FEDERATION_IBM:
    - add_req->who = g_strconcat("ibm/", temp, NULL);
    - break;
    - case YAHOO_FEDERATION_NONE:
    - default:
    - add_req->who = g_strdup(temp);
    - break;
    - }
    -
    - if (add_req->id && add_req->who) {
    - char *alias = NULL, *dec_msg = NULL;
    -
    - if (!purple_privacy_check(account, add_req->who))
    - {
    - purple_debug_misc("yahoo", "Auth. request from %s dropped and automatically denied due to privacy settings!\n",
    - add_req->who);
    - yahoo_buddy_add_deny_cb(add_req, NULL);
    - return;
    - }
    -
    - if (msg)
    - dec_msg = yahoo_string_decode(gc, msg, FALSE);
    -
    - if (firstname && lastname)
    - alias = g_strdup_printf("%s %s", firstname, lastname);
    - else if (firstname)
    - alias = g_strdup(firstname);
    - else if (lastname)
    - alias = g_strdup(lastname);
    -
    - /* DONE! this is almost exactly the same as what MSN does,
    - * this should probably be moved to the core.
    - */
    - purple_account_request_authorization(account, add_req->who, add_req->id,
    - alias, dec_msg,
    - purple_find_buddy(account, add_req->who) != NULL,
    - yahoo_buddy_add_authorize_cb,
    - yahoo_buddy_add_deny_reason_cb,
    - add_req);
    - g_free(alias);
    - g_free(dec_msg);
    - } else {
    - g_free(add_req->id);
    - g_free(add_req->who);
    - g_free(add_req);
    - }
    - } else {
    - purple_debug_error("yahoo", "Received authorization of unknown status (%d).\n", pkt->status);
    - }
    -}
    -
    -/* I don't think this happens anymore in Version 15 */
    -static void yahoo_buddy_added_us(PurpleConnection *gc, struct yahoo_packet *pkt) {
    - PurpleAccount *account;
    - struct yahoo_add_request *add_req;
    - char *msg = NULL;
    - GSList *l = pkt->hash;
    -
    - account = purple_connection_get_account(gc);
    -
    - add_req = g_new0(struct yahoo_add_request, 1);
    - add_req->gc = gc;
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 1:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - add_req->id = g_strdup(pair->value);
    - } else {
    - purple_debug_warning("yahoo", "yahoo_buddy_added_us "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 3:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - add_req->who = g_strdup(pair->value);
    - } else {
    - purple_debug_warning("yahoo", "yahoo_buddy_added_us "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 15: /* time, for when they add us and we're offline */
    - break;
    - case 14:
    - msg = pair->value;
    - break;
    - }
    - l = l->next;
    - }
    -
    - if (add_req->id && add_req->who) {
    - char *dec_msg = NULL;
    -
    - if (!purple_privacy_check(account, add_req->who)) {
    - purple_debug_misc("yahoo", "Auth. request from %s dropped and automatically denied due to privacy settings!\n",
    - add_req->who);
    - yahoo_buddy_add_deny_cb(add_req, NULL);
    - return;
    - }
    -
    - if (msg)
    - dec_msg = yahoo_string_decode(gc, msg, FALSE);
    -
    - /* DONE! this is almost exactly the same as what MSN does,
    - * this should probably be moved to the core.
    - */
    - purple_account_request_authorization(account, add_req->who, add_req->id,
    - NULL, dec_msg,
    - purple_find_buddy(account,add_req->who) != NULL,
    - yahoo_buddy_add_authorize_cb,
    - yahoo_buddy_add_deny_reason_cb, add_req);
    - g_free(dec_msg);
    - } else {
    - g_free(add_req->id);
    - g_free(add_req->who);
    - g_free(add_req);
    - }
    -}
    -
    -/* I have no idea if this every gets called in version 15 */
    -static void yahoo_buddy_denied_our_add_old(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - char *who = NULL;
    - char *msg = NULL;
    - GSList *l = pkt->hash;
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 3:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - who = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_buddy_denied_our_add_old "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 14:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - msg = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_buddy_denied_our_add_old "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - }
    - l = l->next;
    - }
    -
    - yahoo_buddy_denied_our_add(gc, who, msg);
    -}
    -
    -static void yahoo_process_contact(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - switch (pkt->status) {
    - case 1:
    - yahoo_process_status(gc, pkt);
    - return;
    - case 3:
    - yahoo_buddy_added_us(gc, pkt);
    - break;
    - case 7:
    - yahoo_buddy_denied_our_add_old(gc, pkt);
    - break;
    - default:
    - break;
    - }
    -}
    -
    -#define OUT_CHARSET "utf-8"
    -
    -static char *yahoo_decode(const char *text)
    -{
    - char *converted = NULL;
    - char *n, *new;
    - const char *end, *p;
    - int i, k;
    -
    - n = new = g_malloc(strlen (text) + 1);
    - end = text + strlen(text);
    -
    - for (p = text; p < end; p++, n++) {
    - if (*p == '\\') {
    - if (p[1] >= '0' && p[1] <= '7') {
    - p += 1;
    - for (i = 0, k = 0; k < 3; k += 1) {
    - char c = p[k];
    - if (c < '0' || c > '7') break;
    - i *= 8;
    - i += c - '0';
    - }
    - *n = i;
    - p += k - 1;
    - } else { /* bug 959248 */
    - /* If we see a \ not followed by an octal number,
    - * it means that it is actually a \\ with one \
    - * already eaten by some unknown function.
    - * This is arguably broken.
    - *
    - * I think wing is wrong here, there is no function
    - * called that I see that could have done it. I guess
    - * it is just really sending single \'s. That's yahoo
    - * for you.
    - */
    - *n = *p;
    - }
    - }
    - else
    - *n = *p;
    - }
    -
    - *n = '\0';
    -
    - if (strstr(text, "\033$B"))
    - converted = g_convert(new, n - new, OUT_CHARSET, "iso-2022-jp", NULL, NULL, NULL);
    - if (!converted)
    - converted = g_convert(new, n - new, OUT_CHARSET, "iso-8859-1", NULL, NULL, NULL);
    - g_free(new);
    -
    - return converted;
    -}
    -
    -static void yahoo_process_mail(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - PurpleAccount *account = purple_connection_get_account(gc);
    - YahooData *yd = gc->proto_data;
    - const char *who = NULL;
    - const char *email = NULL;
    - const char *subj = NULL;
    - const char *yahoo_mail_url = (yd->jp? YAHOOJP_MAIL_URL: YAHOO_MAIL_URL);
    - int count = 0;
    - GSList *l = pkt->hash;
    -
    - if (!purple_account_get_check_mail(account))
    - return;
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    - if (pair->key == 9)
    - count = strtol(pair->value, NULL, 10);
    - else if (pair->key == 43) {
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - who = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_mail "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - } else if (pair->key == 42) {
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - email = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_mail "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - } else if (pair->key == 18) {
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - subj = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_mail "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - }
    - l = l->next;
    - }
    -
    - if (who && subj && email && *email) {
    - char *dec_who = yahoo_decode(who);
    - char *dec_subj = yahoo_decode(subj);
    - char *from = g_strdup_printf("%s (%s)", dec_who, email);
    -
    - purple_notify_email(gc, dec_subj, from, purple_account_get_username(account),
    - yahoo_mail_url, NULL, NULL);
    -
    - g_free(dec_who);
    - g_free(dec_subj);
    - g_free(from);
    - } else if (count > 0) {
    - const char *tos[2] = { purple_account_get_username(account) };
    - const char *urls[2] = { yahoo_mail_url };
    -
    - purple_notify_emails(gc, count, FALSE, NULL, NULL, tos, urls,
    - NULL, NULL);
    - }
    -}
    -
    -/* We use this structure once while we authenticate */
    -struct yahoo_auth_data
    -{
    - PurpleConnection *gc;
    - char *seed;
    -};
    -
    -/* This is the y64 alphabet... it's like base64, but has a . and a _ */
    -static const char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._";
    -
    -/* This is taken from Sylpheed by Hiroyuki Yamamoto. We have our own tobase64 function
    - * in util.c, but it is different from the one yahoo uses */
    -static void to_y64(char *out, const unsigned char *in, gsize inlen)
    - /* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
    -{
    - for (; inlen >= 3; inlen -= 3)
    - {
    - *out++ = base64digits[in[0] >> 2];
    - *out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)];
    - *out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
    - *out++ = base64digits[in[2] & 0x3f];
    - in += 3;
    - }
    - if (inlen > 0)
    - {
    - unsigned char fragment;
    -
    - *out++ = base64digits[in[0] >> 2];
    - fragment = (in[0] << 4) & 0x30;
    - if (inlen > 1)
    - fragment |= in[1] >> 4;
    - *out++ = base64digits[fragment];
    - *out++ = (inlen < 2) ? '-' : base64digits[(in[1] << 2) & 0x3c];
    - *out++ = '-';
    - }
    - *out = '\0';
    -}
    -
    -static void yahoo_auth16_stage3(PurpleConnection *gc, const char *crypt)
    -{
    - YahooData *yd = gc->proto_data;
    - PurpleAccount *account = purple_connection_get_account(gc);
    - const char *name = purple_normalize(account, purple_account_get_username(account));
    - PurpleCipher *md5_cipher;
    - PurpleCipherContext *md5_ctx;
    - guchar md5_digest[16];
    - gchar base64_string[25];
    - struct yahoo_packet *pkt;
    -
    - purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage3\n");
    -
    - g_return_if_fail(crypt != NULL);
    -
    - md5_cipher = purple_ciphers_find_cipher("md5");
    - md5_ctx = purple_cipher_context_new(md5_cipher, NULL);
    - purple_cipher_context_append(md5_ctx, (guchar *)crypt, strlen(crypt));
    - purple_cipher_context_digest(md5_ctx, sizeof(md5_digest), md5_digest, NULL);
    -
    - to_y64(base64_string, md5_digest, 16);
    -
    - purple_debug_info("yahoo", "yahoo status: %d\n", yd->current_status);
    - pkt = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->current_status, yd->session_id);
    -
    - if(yd->cookie_b) { /* send B cookie if we have it */
    - yahoo_packet_hash(pkt, "ssssssssss",
    - 1, name,
    - 0, name,
    - 277, yd->cookie_y,
    - 278, yd->cookie_t,
    - 307, base64_string,
    - 244, yd->jp ? YAHOOJP_CLIENT_VERSION_ID : YAHOO_CLIENT_VERSION_ID,
    - 2, name,
    - 2, "1",
    - 59, yd->cookie_b,
    - 98, purple_account_get_string(account, "room_list_locale", yd->jp ? "jp" : "us"),
    - 135, yd->jp ? YAHOOJP_CLIENT_VERSION : YAHOO_CLIENT_VERSION);
    - } else { /* don't try to send an empty B cookie - the server will be mad */
    - yahoo_packet_hash(pkt, "sssssssss",
    - 1, name,
    - 0, name,
    - 277, yd->cookie_y,
    - 278, yd->cookie_t,
    - 307, base64_string,
    - 244, yd->jp ? YAHOOJP_CLIENT_VERSION_ID : YAHOO_CLIENT_VERSION_ID,
    - 2, name,
    - 2, "1",
    - 98, purple_account_get_string(account, "room_list_locale", yd->jp ? "jp" : "us"),
    - 135, yd->jp ? YAHOOJP_CLIENT_VERSION : YAHOO_CLIENT_VERSION);
    - }
    -
    - if (yd->picture_checksum)
    - yahoo_packet_hash_int(pkt, 192, yd->picture_checksum);
    - yahoo_packet_send_and_free(pkt, yd);
    -
    - purple_cipher_context_destroy(md5_ctx);
    -}
    -
    -static gchar *yahoo_auth16_get_cookie_b(gchar *headers)
    -{
    - gchar **splits = g_strsplit(headers, "\r\n", -1);
    - gchar *tmp = NULL, *tmp2 = NULL, *sem = NULL;
    - int elements = g_strv_length(splits), i;
    -
    - if(elements > 1) {
    - for(i = 0; i < elements; i++) {
    - if(g_ascii_strncasecmp(splits[i], "Set-Cookie: B=", 14) == 0) {
    - tmp = &splits[i][14];
    - sem = strchr(tmp, ';');
    -
    - if (sem != NULL) {
    - tmp2 = g_strndup(tmp, sem - tmp);
    - purple_debug_info("yahoo", "Got needed part of B cookie: %s\n",
    - tmp2 ? tmp2 : "(null)");
    - break;
    - }
    - }
    - }
    - }
    -
    - g_strfreev(splits);
    - return tmp2;
    -}
    -
    -static void yahoo_auth16_stage2(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *ret_data, size_t len, const gchar *error_message)
    -{
    - struct yahoo_auth_data *auth_data = user_data;
    - PurpleConnection *gc = auth_data->gc;
    - YahooData *yd = purple_connection_get_protocol_data(gc);
    -
    - purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage2\n");
    -
    - yd->url_datas = g_slist_remove(yd->url_datas, url_data);
    -
    - if (error_message != NULL) {
    - purple_debug_error("yahoo", "Login Failed, unable to retrieve stage 2 url: %s\n", error_message);
    - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_message);
    - g_free(auth_data->seed);
    - g_free(auth_data);
    - return;
    - }
    - else if (len > 0 && ret_data && *ret_data) {
    - gchar **splits = g_strsplit(ret_data, "\r\n\r\n", -1), **split_data = NULL;
    - int totalelements = 0;
    - int response_no = -1;
    - char *crumb = NULL;
    - char *crypt = NULL;
    -
    - if(g_strv_length(splits) > 1) {
    - yd->cookie_b = yahoo_auth16_get_cookie_b(splits[0]);
    - split_data = g_strsplit(splits[1], "\r\n", -1);
    - totalelements = g_strv_length(split_data);
    - }
    -
    - if (totalelements >= 4) {
    - int i;
    -
    - for(i = 0; i < totalelements; i++) {
    - /* I'm not exactly a fan of the magic numbers, but it's obvious,
    - * so no sense in wasting a bajillion vars or calls to strlen */
    -
    - if(g_ascii_isdigit(split_data[i][0])) {
    - /* if the current line and the next line both start with numbers,
    - * the current line is the length of the body, so skip. If not,
    - * then the current line is the response code from the login process. */
    - if(!g_ascii_isdigit(split_data[i + 1][0])) {
    - response_no = strtol(split_data[i], NULL, 10);
    - purple_debug_info("yahoo", "Got auth16 stage 2 response code: %d\n",
    - response_no);
    - }
    - } else if(strncmp(split_data[i], "crumb=", 6) == 0) {
    - crumb = g_strdup(&split_data[i][6]);
    -
    - if(purple_debug_is_unsafe())
    - purple_debug_info("yahoo", "Got crumb: %s\n", crumb);
    -
    - } else if(strncmp(split_data[i], "Y=", 2) == 0) {
    - yd->cookie_y = g_strdup(&split_data[i][2]);
    -
    - if(purple_debug_is_unsafe())
    - purple_debug_info("yahoo", "Got Y cookie: %s\n", yd->cookie_y);
    -
    - } else if(strncmp(split_data[i], "T=", 2) == 0) {
    - yd->cookie_t = g_strdup(&split_data[i][2]);
    -
    - if(purple_debug_is_unsafe())
    - purple_debug_info("yahoo", "Got T cookie: %s\n", yd->cookie_t);
    - }
    - }
    - }
    -
    - g_strfreev(splits);
    - g_strfreev(split_data);
    -
    - if (crumb == NULL)
    - response_no = -1;
    -
    - if(response_no != 0) {
    - /* Some error in the login process */
    - PurpleConnectionError error;
    - char *error_reason = NULL;
    -
    - switch(response_no) {
    - case -1:
    - /* Some error in the received stream */
    - error_reason = g_strdup(_("Received invalid data"));
    - error = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
    - break;
    - case 100:
    - /* Unknown error */
    - error_reason = g_strdup(_("Unknown error"));
    - error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
    - break;
    - default:
    - /* if we have everything we need, why not try to login irrespective of response */
    - if((crumb != NULL) && (yd->cookie_y != NULL) && (yd->cookie_t != NULL)) {
    -#if 0
    - try_login_on_error = TRUE;
    -#endif
    - break;
    - }
    - error_reason = g_strdup(_("Unknown error"));
    - error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
    - break;
    - }
    - if(error_reason) {
    - purple_debug_error("yahoo", "Authentication error: %s. "
    - "Code %d\n", error_reason, response_no);
    - purple_connection_error_reason(gc, error, error_reason);
    - g_free(error_reason);
    - g_free(auth_data->seed);
    - g_free(auth_data);
    - return;
    - }
    - }
    -
    - crypt = g_strconcat(crumb, auth_data->seed, NULL);
    - yahoo_auth16_stage3(gc, crypt);
    - g_free(crypt);
    - g_free(crumb);
    - }
    - g_free(auth_data->seed);
    - g_free(auth_data);
    -}
    -
    -static void yahoo_auth16_stage1_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *ret_data, size_t len, const gchar *error_message)
    -{
    - struct yahoo_auth_data *auth_data = user_data;
    - PurpleConnection *gc = auth_data->gc;
    - YahooData *yd = purple_connection_get_protocol_data(gc);
    -
    - purple_debug_info("yahoo","Authentication: In yahoo_auth16_stage1_cb\n");
    -
    - yd->url_datas = g_slist_remove(yd->url_datas, url_data);
    -
    - if (error_message != NULL) {
    - purple_debug_error("yahoo", "Login Failed, unable to retrieve login url: %s\n", error_message);
    - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_message);
    - g_free(auth_data->seed);
    - g_free(auth_data);
    - return;
    - }
    - else if (len > 0 && ret_data && *ret_data) {
    - PurpleAccount *account = purple_connection_get_account(gc);
    - gchar **split_data = g_strsplit(ret_data, "\r\n", -1);
    - int totalelements = 0;
    - int response_no = -1;
    - char *token = NULL;
    -
    - totalelements = g_strv_length(split_data);
    -
    - if(totalelements == 1) { /* Received an error code */
    - response_no = strtol(split_data[0], NULL, 10);
    - } else if(totalelements == 2 || totalelements == 3 ) { /* received valid data */
    - response_no = strtol(split_data[0], NULL, 10);
    - token = g_strdup(split_data[1] + strlen("ymsgr="));
    - } else { /* It looks like a transparent proxy has returned a document we don't want */
    - response_no = -1;
    - }
    -
    - g_strfreev(split_data);
    -
    - if(response_no != 0) {
    - /* Some error in the login process */
    - PurpleConnectionError error;
    - char *error_reason;
    -
    - switch(response_no) {
    - case -1:
    - /* Some error in the received stream */
    - error_reason = g_strdup(_("Received invalid data"));
    - error = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
    - break;
    - case 1212:
    - /* Password incorrect */
    - /* Set password to NULL. Avoids account locking. Brings dialog to enter password if clicked on Re-enable account */
    - if (!purple_account_get_remember_password(account))
    - purple_account_set_password(account, NULL);
    - error_reason = g_strdup(_("Incorrect password"));
    - error = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
    - break;
    - case 1213:
    - /* security lock from too many failed login attempts */
    - error_reason = g_strdup(_("Account locked: Too many failed login "
    - "attempts. Logging into the Yahoo! website may fix this."));
    - error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
    - break;
    - case 1235:
    - /* the username does not exist */
    - error_reason = g_strdup(_("Username does not exist"));
    - error = PURPLE_CONNECTION_ERROR_INVALID_USERNAME;
    - break;
    - case 1214:
    - /* indicates a lock of some description */
    - error_reason = g_strdup(_("Account locked: Unknown reason. Logging "
    - "into the Yahoo! website may fix this."));
    - error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
    - break;
    - case 1236:
    - /* indicates a lock due to logging in too frequently */
    - error_reason = g_strdup(_("Account locked: You have been logging in too "
    - "frequently. Wait a few minutes before trying to connect "
    - "again. Logging into the Yahoo! website may help."));
    - error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
    - break;
    - case 100:
    - /* username or password missing */
    - error_reason = g_strdup(_("Username or password missing"));
    - error = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
    - break;
    - default:
    - /* Unknown error! */
    - error_reason = g_strdup_printf(_("Unknown error (%d)"), response_no);
    - error = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
    - break;
    - }
    - purple_debug_error("yahoo", "Authentication error: %s. Code %d\n",
    - error_reason, response_no);
    - purple_connection_error_reason(gc, error, error_reason);
    - g_free(error_reason);
    - g_free(auth_data->seed);
    - g_free(auth_data);
    - g_free(token);
    - }
    - else {
    - /* OK to login, correct information provided */
    - PurpleUtilFetchUrlData *url_data = NULL;
    - char *url = NULL;
    - gboolean yahoojp = yahoo_is_japan(account);
    - gboolean proxy_ssl = purple_account_get_bool(account, "proxy_ssl", FALSE);
    -
    - url = g_strdup_printf(yahoojp ? YAHOOJP_LOGIN_URL : YAHOO_LOGIN_URL, token);
    - url_data = purple_util_fetch_url_request_len_with_account(
    - proxy_ssl ? account : NULL, url, TRUE, YAHOO_CLIENT_USERAGENT,
    - TRUE, NULL, TRUE, -1, yahoo_auth16_stage2, auth_data);
    - if (url_data)
    - yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
    - g_free(url);
    - g_free(token);
    - }
    - }
    -}
    -
    -static void yahoo_auth16_stage1(PurpleConnection *gc, const char *seed)
    -{
    - YahooData *yd = purple_connection_get_protocol_data(gc);
    - PurpleAccount *account = purple_connection_get_account(gc);
    - PurpleUtilFetchUrlData *url_data = NULL;
    - struct yahoo_auth_data *auth_data = NULL;
    - char *url = NULL;
    - char *encoded_username;
    - char *encoded_password;
    - gboolean yahoojp = yahoo_is_japan(account);
    - gboolean proxy_ssl = purple_account_get_bool(account, "proxy_ssl", FALSE);
    -
    - purple_debug_info("yahoo", "Authentication: In yahoo_auth16_stage1\n");
    -
    - if(!purple_ssl_is_supported()) {
    - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT, _("SSL support unavailable"));
    - return;
    - }
    -
    - auth_data = g_new0(struct yahoo_auth_data, 1);
    - auth_data->gc = gc;
    - auth_data->seed = g_strdup(seed);
    -
    - encoded_username = g_strdup(purple_url_encode(purple_account_get_username(purple_connection_get_account(gc))));
    - encoded_password = g_strdup(purple_url_encode(purple_connection_get_password(gc)));
    - url = g_strdup_printf(yahoojp ? YAHOOJP_TOKEN_URL : YAHOO_TOKEN_URL,
    - encoded_username, encoded_password, purple_url_encode(seed));
    - g_free(encoded_password);
    - g_free(encoded_username);
    -
    - url_data = purple_util_fetch_url_request_len_with_account(
    - proxy_ssl ? account : NULL, url, TRUE,
    - YAHOO_CLIENT_USERAGENT, TRUE, NULL, FALSE, -1,
    - yahoo_auth16_stage1_cb, auth_data);
    - if (url_data)
    - yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
    -
    - g_free(url);
    -}
    -
    -static void yahoo_process_auth(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - char *seed = NULL;
    - GSList *l = pkt->hash;
    - int m = 0;
    - gchar *buf;
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    - /* (pair->key == 1) -> sn */
    - if (pair->key == 94) {
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - seed = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_auth "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - } else if (pair->key == 13) {
    - m = atoi(pair->value);
    - }
    - l = l->next;
    - }
    -
    - if (seed) {
    - switch (m) {
    - case 0:
    - /* used to be for really old auth routine, dont support now */
    - case 1:
    - case 2: /* Yahoo ver 16 authentication */
    - yahoo_auth16_stage1(gc, seed);
    - break;
    - default:
    - {
    - GHashTable *ui_info = purple_core_get_ui_info();
    -
    - buf = g_strdup_printf(_("The Yahoo server has requested the use of an unrecognized "
    - "authentication method. You will probably not be able "
    - "to successfully sign on to Yahoo. Check %s for updates."),
    - ((ui_info && g_hash_table_lookup(ui_info, "website")) ? (char *)g_hash_table_lookup(ui_info, "website") : PURPLE_WEBSITE));
    - purple_notify_error(gc, "", _("Failed Yahoo! Authentication"),
    - buf);
    - g_free(buf);
    - yahoo_auth16_stage1(gc, seed); /* Can't hurt to try it anyway. */
    - break;
    - }
    - }
    - }
    -}
    -
    -static void ignore_buddy(PurpleBuddy *buddy) {
    - PurpleGroup *group;
    - PurpleAccount *account;
    - gchar *name;
    -
    - if (!buddy)
    - return;
    -
    - group = purple_buddy_get_group(buddy);
    - name = g_strdup(purple_buddy_get_name(buddy));
    - account = purple_buddy_get_account(buddy);
    -
    - purple_debug_info("yahoo", "blist: Removing '%s' from buddy list.\n", name);
    - purple_account_remove_buddy(account, buddy, group);
    - purple_blist_remove_buddy(buddy);
    -
    - serv_add_deny(purple_account_get_connection(account), name);
    -
    - g_free(name);
    -}
    -
    -static void keep_buddy(PurpleBuddy *b)
    -{
    - purple_privacy_deny_remove(purple_buddy_get_account(b),
    - purple_buddy_get_name(b), 1);
    -}
    -
    -static void yahoo_process_ignore(PurpleConnection *gc, struct yahoo_packet *pkt) {
    - PurpleBuddy *b;
    - GSList *l;
    - gchar *who = NULL;
    - gchar buf[BUF_LONG];
    - gboolean ignore = TRUE;
    - gint status = 0;
    -
    - for (l = pkt->hash; l; l = l->next) {
    - struct yahoo_pair *pair = l->data;
    - switch (pair->key) {
    - case 0:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - who = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_ignore "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - /* 1 -> me */
    - case 13:
    - /* 1 == ignore, 2 == unignore */
    - ignore = (strtol(pair->value, NULL, 10) == 1);
    - break;
    - case 66:
    - status = strtol(pair->value, NULL, 10);
    - break;
    - default:
    - break;
    - }
    - }
    -
    - /*
    - * status
    - * 0 - ok
    - * 2 - already in ignore list, could not add
    - * 3 - not in ignore list, could not delete
    - * 12 - is a buddy, could not add (and possibly also a not-in-ignore list condition?)
    - */
    - switch (status) {
    - case 12:
    - purple_debug_info("yahoo", "Server reported \"is a buddy\" for %s while %s",
    - who, (ignore ? "ignoring" : "unignoring"));
    -
    - if (ignore) {
    - b = purple_find_buddy(gc->account, who);
    - g_snprintf(buf, sizeof(buf), _("You have tried to ignore %s, but the "
    - "user is on your buddy list. Clicking \"Yes\" "
    - "will remove and ignore the buddy."), who);
    - purple_request_yes_no(gc, NULL, _("Ignore buddy?"), buf, 0,
    - gc->account, who, NULL,
    - b,
    - G_CALLBACK(ignore_buddy),
    - G_CALLBACK(keep_buddy));
    - break;
    - }
    - case 2:
    - purple_debug_info("yahoo", "Server reported that %s is already in the ignore list.\n",
    - who);
    - break;
    - case 3:
    - purple_debug_info("yahoo", "Server reported that %s is not in the ignore list; could not delete\n",
    - who);
    - case 0:
    - default:
    - break;
    - }
    -}
    -
    -static void yahoo_process_authresp(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    -#ifdef TRY_WEBMESSENGER_LOGIN
    - YahooData *yd = gc->proto_data;
    -#endif /* TRY_WEBMESSENGER_LOGIN */
    - GSList *l = pkt->hash;
    - int err = 0;
    - char *msg;
    - char *url = NULL;
    - char *fullmsg;
    - PurpleAccount *account = gc->account;
    - PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    -
    - if (pair->key == 66)
    - err = strtol(pair->value, NULL, 10);
    - else if (pair->key == 20) {
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - url = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_authresp "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - }
    -
    - l = l->next;
    - }
    -
    - switch (err) {
    - case 0:
    - msg = g_strdup(_("Unknown error"));
    - reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
    - break;
    - case 3:
    - msg = g_strdup(_("Username does not exist"));
    - reason = PURPLE_CONNECTION_ERROR_INVALID_USERNAME;
    - break;
    - case 13:
    -#ifdef TRY_WEBMESSENGER_LOGIN
    - if (!yd->wm) {
    - PurpleUtilFetchUrlData *url_data;
    - yd->wm = TRUE;
    - if (yd->fd >= 0)
    - close(yd->fd);
    - if (gc->inpa)
    - purple_input_remove(gc->inpa);
    - url_data = purple_util_fetch_url(WEBMESSENGER_URL, TRUE,
    - "Purple/" VERSION, FALSE, yahoo_login_page_cb, gc);
    - if (url_data != NULL)
    - yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
    - return;
    - }
    -#endif /* TRY_WEBMESSENGER_LOGIN */
    - if (!purple_account_get_remember_password(account))
    - purple_account_set_password(account, NULL);
    -
    - msg = g_strdup(_("Invalid username or password"));
    - reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
    - break;
    - case 14:
    - msg = g_strdup(_("Your account has been locked due to too many failed login attempts."
    - " Please try logging into the Yahoo! website."));
    - reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
    - break;
    - case 52:
    - /* See #9660. As much as we know, reconnecting shouldn't hurt */
    - purple_debug_info("yahoo", "Got error 52, Set to autoreconnect\n");
    - msg = g_strdup(_("Unknown error 52. Reconnecting should fix this."));
    - reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
    - break;
    - case 1013:
    - msg = g_strdup(_("Error 1013: The username you have entered is invalid."
    - " The most common cause of this error is entering your email"
    - " address instead of your Yahoo! ID."));
    - reason = PURPLE_CONNECTION_ERROR_INVALID_USERNAME;
    - break;
    - default:
    - msg = g_strdup_printf(_("Unknown error number %d. Logging into the Yahoo! website may fix this."), err);
    - }
    -
    - if (url)
    - fullmsg = g_strdup_printf("%s\n%s", msg, url);
    - else
    - fullmsg = g_strdup(msg);
    -
    - purple_connection_error_reason(gc, reason, fullmsg);
    - g_free(msg);
    - g_free(fullmsg);
    -}
    -
    -static void yahoo_process_addbuddy(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - int err = 0;
    - char *who = NULL;
    - char *temp = NULL;
    - char *group = NULL;
    - char *decoded_group;
    - char *buf;
    - YahooFriend *f;
    - GSList *l = pkt->hash;
    - YahooData *yd = gc->proto_data;
    - YahooFederation fed = YAHOO_FEDERATION_NONE;
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 66:
    - err = strtol(pair->value, NULL, 10);
    - break;
    - case 7:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - temp = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_addbuddy "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 65:
    - group = pair->value;
    - break;
    - case 241:
    - fed = strtol(pair->value, NULL, 10);
    - break;
    - }
    -
    - l = l->next;
    - }
    -
    - if (!temp)
    - return;
    - if (!group)
    - group = "";
    -
    - switch (fed) {
    - case YAHOO_FEDERATION_MSN:
    - who = g_strconcat("msn/", temp, NULL);
    - break;
    - case YAHOO_FEDERATION_OCS:
    - who = g_strconcat("ocs/", temp, NULL);
    - break;
    - case YAHOO_FEDERATION_IBM:
    - who = g_strconcat("ibm/", temp, NULL);
    - break;
    - case YAHOO_FEDERATION_NONE:
    - default:
    - who = g_strdup(temp);
    - break;
    - }
    -
    - if (!err || (err == 2)) { /* 0 = ok, 2 = already on serv list */
    - f = yahoo_friend_find_or_new(gc, who);
    - yahoo_update_status(gc, who, f);
    - f->fed = fed;
    -
    - if( !g_hash_table_lookup(yd->peers, who) ) {
    - /* we are not connected as client, so set friend to not connected */
    - if(fed)
    - yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_DO_NOT_CONNECT);
    - else {
    - yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED);
    - f->p2p_packet_sent = 0;
    - }
    - }
    - else /* we are already connected. set friend to YAHOO_P2PSTATUS_WE_ARE_CLIENT */
    - yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_WE_ARE_CLIENT);
    - g_free(who);
    - return;
    - }
    -
    - decoded_group = yahoo_string_decode(gc, group, FALSE);
    - buf = g_strdup_printf(_("Unable to add buddy %s to group %s to the server list on account %s."),
    - who, decoded_group, purple_connection_get_display_name(gc));
    - if (!purple_conv_present_error(who, purple_connection_get_account(gc), buf))
    - purple_notify_error(gc, NULL, _("Unable to add buddy to server list"), buf);
    - g_free(buf);
    - g_free(decoded_group);
    - g_free(who);
    -}
    -
    -/* write pkt to the source */
    -static void yahoo_p2p_write_pkt(gint source, struct yahoo_packet *pkt)
    -{
    - size_t pkt_len;
    - gssize written;
    - guchar *raw_packet;
    -
    - /*build the raw packet and send it to the host*/
    - pkt_len = yahoo_packet_build(pkt, 0, 0, 0, &raw_packet);
    - written = write(source, raw_packet, pkt_len);
    - if (written < 0 || (gsize)written != pkt_len)
    - purple_debug_warning("yahoo","p2p: couldn't write to the source\n");
    - g_free(raw_packet);
    -}
    -
    -static void yahoo_p2p_keepalive_cb(gpointer key, gpointer value, gpointer user_data)
    -{
    - struct yahoo_p2p_data *p2p_data = value;
    - PurpleConnection *gc = user_data;
    - struct yahoo_packet *pkt_to_send;
    - PurpleAccount *account;
    - YahooData *yd = gc->proto_data;
    -
    - account = purple_connection_get_account(gc);
    -
    - pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash(pkt_to_send, "ssisi",
    - 4, purple_normalize(account, purple_account_get_username(account)),
    - 5, p2p_data->host_username,
    - 241, 0, /* Protocol identifier */
    - 49, "PEERTOPEER",
    - 13, 7);
    - yahoo_p2p_write_pkt(p2p_data->source, pkt_to_send);
    -
    - yahoo_packet_free(pkt_to_send);
    -}
    -
    -static gboolean yahoo_p2p_keepalive(gpointer data)
    -{
    - PurpleConnection *gc = data;
    - YahooData *yd = gc->proto_data;
    -
    - g_hash_table_foreach(yd->peers, yahoo_p2p_keepalive_cb, gc);
    -
    - return TRUE;
    -}
    -
    -/* destroy p2p_data associated with a peer and close p2p connection.
    - * g_hash_table_remove() calls this function to destroy p2p_data associated with the peer,
    - * call g_hash_table_remove() instead of this fucntion if peer has an entry in the table */
    -static void yahoo_p2p_disconnect_destroy_data(gpointer data)
    -{
    - struct yahoo_p2p_data *p2p_data;
    - YahooFriend *f;
    -
    - if(!(p2p_data = data))
    - return ;
    -
    - /* If friend, set him not connected */
    - f = yahoo_friend_find(p2p_data->gc, p2p_data->host_username);
    - if (f)
    - yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED);
    -
    - if(p2p_data->source >= 0)
    - close(p2p_data->source);
    - if (p2p_data->input_event > 0)
    - purple_input_remove(p2p_data->input_event);
    - g_free(p2p_data->host_ip);
    - g_free(p2p_data->host_username);
    - g_free(p2p_data);
    -}
    -
    -/* exchange of initial p2pfilexfer packets, service type YAHOO_SERVICE_P2PFILEXFER */
    -static void yahoo_p2p_process_p2pfilexfer(gpointer data, gint source, struct yahoo_packet *pkt)
    -{
    - struct yahoo_p2p_data *p2p_data;
    - char *who = NULL;
    - GSList *l = pkt->hash;
    - struct yahoo_packet *pkt_to_send;
    - PurpleAccount *account;
    - int val_13_to_send = 0;
    - YahooData *yd;
    - YahooFriend *f;
    -
    - if(!(p2p_data = data))
    - return ;
    -
    - yd = p2p_data->gc->proto_data;
    -
    - /* lets see whats in the packet */
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 4:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - who = pair->value;
    - if(strncmp(who, p2p_data->host_username, strlen(p2p_data->host_username)) != 0) {
    - /* from whom are we receiving the packets ?? */
    - purple_debug_warning("yahoo","p2p: received data from wrong user\n");
    - return;
    - }
    - } else {
    - purple_debug_warning("yahoo", "yahoo_p2p_process_p2pfilexfer "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 13:
    - p2p_data->val_13 = strtol(pair->value, NULL, 10); /* Value should be 5-7 */
    - break;
    - /* case 5, 49 look laters, no use right now */
    - }
    - l = l->next;
    - }
    -
    - account = purple_connection_get_account(p2p_data->gc);
    -
    - /* key_13: sort of a counter.
    - * WHEN WE ARE CLIENT: yahoo server sends val_13 = 0, we send to peer val_13 = 1, receive back val_13 = 5,
    - * we send val_13=6, receive val_13=7, we send val_13=7, HALT. Keep sending val_13 = 7 as keep alive.
    - * WHEN WE ARE SERVER: we send val_13 = 0 to yahoo server, peer sends us val_13 = 1, we send val_13 = 5,
    - * receive val_13 = 6, send val_13 = 7, receive val_13 = 7. HALT. Keep sending val_13 = 7 as keep alive. */
    -
    - switch(p2p_data->val_13) {
    - case 1 : val_13_to_send = 5; break;
    - case 5 : val_13_to_send = 6; break;
    - case 6 : val_13_to_send = 7; break;
    - case 7 : if( g_hash_table_lookup(yd->peers, p2p_data->host_username) )
    - return;
    - val_13_to_send = 7; break;
    - default: purple_debug_warning("yahoo","p2p:Unknown value for key 13\n");
    - return;
    - }
    -
    - /* Build the yahoo packet */
    - pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash(pkt_to_send, "ssisi",
    - 4, purple_normalize(account, purple_account_get_username(account)),
    - 5, p2p_data->host_username,
    - 241, 0, /* Protocol identifier */
    - 49, "PEERTOPEER",
    - 13, val_13_to_send);
    -
    - /* build the raw packet and send it to the host */
    - yahoo_p2p_write_pkt(source, pkt_to_send);
    - yahoo_packet_free(pkt_to_send);
    -
    - if( val_13_to_send == 7 )
    - if( !g_hash_table_lookup(yd->peers, p2p_data->host_username) ) {
    - g_hash_table_insert(yd->peers, g_strdup(p2p_data->host_username), p2p_data);
    - /* If the peer is a friend, set him connected */
    - f = yahoo_friend_find(p2p_data->gc, p2p_data->host_username);
    - if (f) {
    - if(p2p_data->connection_type == YAHOO_P2P_WE_ARE_SERVER) {
    - p2p_data->session_id = f->session_id;
    - yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_WE_ARE_SERVER);
    - }
    - else
    - yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_WE_ARE_CLIENT);
    - }
    - }
    -}
    -
    -/* callback function associated with receiving of data, not considering receipt of multiple YMSG packets in a single TCP packet */
    -static void yahoo_p2p_read_pkt_cb(gpointer data, gint source, PurpleInputCondition cond)
    -{
    - guchar buf[1024]; /* is it safe to assume a fixed array length of 1024 ?? */
    - int len;
    - int pos = 0;
    - int pktlen;
    - struct yahoo_packet *pkt;
    - guchar *start;
    - struct yahoo_p2p_data *p2p_data;
    - YahooData *yd;
    -
    - if(!(p2p_data = data))
    - return ;
    - yd = p2p_data->gc->proto_data;
    -
    - len = read(source, buf, sizeof(buf));
    - if ((len < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
    - return ; /* No Worries*/
    - else if (len <= 0)
    - {
    - purple_debug_warning("yahoo","p2p: Error in connection, or host disconnected\n");
    - /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
    - if( g_hash_table_lookup(yd->peers, p2p_data->host_username) )
    - g_hash_table_remove(yd->peers,p2p_data->host_username);
    - else
    - yahoo_p2p_disconnect_destroy_data(data);
    - return;
    - }
    -
    - /* TODO: It looks like there's a bug here (and above) where an incorrect
    - * assumtion is being made that the buffer will be added to when this
    - * is next called, but that's not really the case! */
    - if(len < YAHOO_PACKET_HDRLEN)
    - return;
    -
    - if(strncmp((char *)buf, "YMSG", 4) != 0) {
    - /* Not a YMSG packet */
    - purple_debug_warning("yahoo", "p2p: Got something other than YMSG packet\n");
    -
    - start = (guchar *) g_strstr_len((char *) buf + 1, len - 1 ,"YMSG");
    - if (start == NULL) {
    - /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
    - if (g_hash_table_lookup(yd->peers, p2p_data->host_username))
    - g_hash_table_remove(yd->peers, p2p_data->host_username);
    - else
    - yahoo_p2p_disconnect_destroy_data(data);
    - return;
    - }
    - purple_debug_warning("yahoo","p2p: Got something other than YMSG packet\n");
    -
    - len -= (start - buf);
    - g_memmove(buf, start, len);
    - }
    -
    - pos += 4; /* YMSG */
    - pos += 2;
    - pos += 2;
    -
    - pktlen = yahoo_get16(buf + pos); pos += 2;
    - if (len < (YAHOO_PACKET_HDRLEN + pktlen)) {
    - purple_debug_error("yahoo", "p2p: packet length(%d) > buffer length(%d)\n",
    - pktlen, (len - pos));
    - /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
    - if (g_hash_table_lookup(yd->peers, p2p_data->host_username))
    - g_hash_table_remove(yd->peers, p2p_data->host_username);
    - else
    - yahoo_p2p_disconnect_destroy_data(data);
    - return;
    - } else
    - purple_debug_misc("yahoo", "p2p: %d bytes to read\n", pktlen);
    -
    - pkt = yahoo_packet_new(0, 0, 0);
    - pkt->service = yahoo_get16(buf + pos); pos += 2;
    - pkt->status = yahoo_get32(buf + pos); pos += 4;
    - pkt->id = yahoo_get32(buf + pos); pos += 4;
    -
    - purple_debug_misc("yahoo", "p2p: Yahoo Service: 0x%02x Status: %d\n",pkt->service, pkt->status);
    - yahoo_packet_read(pkt, buf + pos, pktlen);
    -
    - /* packet processing */
    - switch(pkt->service) {
    - case YAHOO_SERVICE_P2PFILEXFER:
    - yahoo_p2p_process_p2pfilexfer(data, source, pkt);
    - break;
    - case YAHOO_SERVICE_MESSAGE:
    - yahoo_process_message(p2p_data->gc, pkt, YAHOO_PKT_TYPE_P2P);
    - break;
    - case YAHOO_SERVICE_NOTIFY:
    - yahoo_process_notify(p2p_data->gc, pkt, YAHOO_PKT_TYPE_P2P);
    - break;
    - default:
    - purple_debug_warning("yahoo","p2p: p2p service %d Unhandled\n",pkt->service);
    - }
    -
    - yahoo_packet_free(pkt);
    -}
    -
    -static void yahoo_p2p_server_send_connected_cb(gpointer data, gint source, PurpleInputCondition cond)
    -{
    - int acceptfd;
    - struct yahoo_p2p_data *p2p_data;
    - YahooData *yd;
    -
    - if(!(p2p_data = data))
    - return ;
    - yd = p2p_data->gc->proto_data;
    -
    - acceptfd = accept(source, NULL, 0);
    - if(acceptfd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
    - return;
    - else if(acceptfd == -1) {
    - purple_debug_warning("yahoo","yahoo_p2p_server_send_connected_cb: accept: %s\n", g_strerror(errno));
    - yahoo_p2p_disconnect_destroy_data(data);
    - return;
    - }
    -
    - /* remove timeout */
    - if (yd->yahoo_p2p_server_timeout_handle) {
    - purple_timeout_remove(yd->yahoo_p2p_server_timeout_handle);
    - yd->yahoo_p2p_server_timeout_handle = 0;
    - }
    -
    - /* remove watcher and close p2p server */
    - if (yd->yahoo_p2p_server_watcher) {
    - purple_input_remove(yd->yahoo_p2p_server_watcher);
    - yd->yahoo_p2p_server_watcher = 0;
    - }
    - if (yd->yahoo_local_p2p_server_fd >= 0) {
    - close(yd->yahoo_local_p2p_server_fd);
    - yd->yahoo_local_p2p_server_fd = -1;
    - }
    -
    - /* Add an Input Read event to the file descriptor */
    - p2p_data->input_event = purple_input_add(acceptfd, PURPLE_INPUT_READ, yahoo_p2p_read_pkt_cb, data);
    - p2p_data->source = acceptfd;
    -}
    -
    -static gboolean yahoo_cancel_p2p_server_listen_cb(gpointer data)
    -{
    - struct yahoo_p2p_data *p2p_data;
    - YahooData *yd;
    -
    - if(!(p2p_data = data))
    - return FALSE;
    -
    - yd = p2p_data->gc->proto_data;
    -
    - purple_debug_warning("yahoo","yahoo p2p server timeout, peer failed to connect\n");
    - yahoo_p2p_disconnect_destroy_data(data);
    - purple_input_remove(yd->yahoo_p2p_server_watcher);
    - yd->yahoo_p2p_server_watcher = 0;
    - close(yd->yahoo_local_p2p_server_fd);
    - yd->yahoo_local_p2p_server_fd = -1;
    - yd->yahoo_p2p_server_timeout_handle = 0;
    -
    - return FALSE;
    -}
    -
    -static void yahoo_p2p_server_listen_cb(int listenfd, gpointer data)
    -{
    - struct yahoo_p2p_data *p2p_data;
    - YahooData *yd;
    -
    - if(!(p2p_data = data))
    - return ;
    -
    - yd = p2p_data->gc->proto_data;
    - yd->listen_data = NULL;
    -
    - if(listenfd == -1) {
    - purple_debug_warning("yahoo","p2p: error starting p2p server\n");
    - yahoo_p2p_disconnect_destroy_data(data);
    - return;
    - }
    -
    - /* Add an Input Read event to the file descriptor */
    - yd->yahoo_local_p2p_server_fd = listenfd;
    - yd->yahoo_p2p_server_watcher = purple_input_add(listenfd, PURPLE_INPUT_READ, yahoo_p2p_server_send_connected_cb,data);
    -
    - /* add timeout */
    - yd->yahoo_p2p_server_timeout_handle = purple_timeout_add_seconds(YAHOO_P2P_SERVER_TIMEOUT, yahoo_cancel_p2p_server_listen_cb, data);
    -}
    -
    -/* send p2p pkt containing our encoded ip, asking peer to connect to us */
    -void yahoo_send_p2p_pkt(PurpleConnection *gc, const char *who, int val_13)
    -{
    - const char *public_ip;
    - guint32 temp[4];
    - guint32 ip;
    - char temp_str[100];
    - gchar *base64_ip = NULL;
    - YahooFriend *f;
    - struct yahoo_packet *pkt;
    - PurpleAccount *account;
    - YahooData *yd = gc->proto_data;
    - struct yahoo_p2p_data *p2p_data;
    - const char *norm_username;
    -
    - f = yahoo_friend_find(gc, who);
    - account = purple_connection_get_account(gc);
    -
    - /* Do not send invitation if already listening for other connection */
    - if(yd->yahoo_local_p2p_server_fd >= 0)
    - return;
    -
    - /* One shouldn't try to connect to self */
    - if( strcmp(purple_normalize(account, purple_account_get_username(account)), who) == 0)
    - return;
    -
    - /* send packet to only those friends who arent p2p connected and to whom we havent already sent. Do not send if this condition doesn't hold good */
    - if( !( f && (yahoo_friend_get_p2p_status(f) == YAHOO_P2PSTATUS_NOT_CONNECTED) && (f->p2p_packet_sent == 0)) )
    - return;
    -
    - /* Dont send p2p packet to buddies of other protocols */
    - if(f->fed)
    - return;
    -
    - /* Finally, don't try to connect to buddies not online or on sms */
    - if( (f->status == YAHOO_STATUS_OFFLINE) || f->sms )
    - return;
    -
    - public_ip = purple_network_get_public_ip();
    - if( (sscanf(public_ip, "%u.%u.%u.%u", &temp[0], &temp[1], &temp[2], &temp[3])) !=4 )
    - return ;
    -
    - ip = (temp[3] << 24) | (temp[2] <<16) | (temp[1] << 8) | temp[0];
    - sprintf(temp_str, "%d", ip);
    - base64_ip = purple_base64_encode( (guchar *)temp_str, strlen(temp_str) );
    -
    - norm_username = purple_normalize(account, purple_account_get_username(account));
    - pkt = yahoo_packet_new(YAHOO_SERVICE_PEERTOPEER, YAHOO_STATUS_AVAILABLE, 0);
    - yahoo_packet_hash(pkt, "sssissis",
    - 1, norm_username,
    - 4, norm_username,
    - 12, base64_ip, /* base64 encode ip */
    - 61, 0, /* To-do : figure out what is 61 for?? */
    - 2, "",
    - 5, who,
    - 13, val_13,
    - 49, "PEERTOPEER");
    - yahoo_packet_send_and_free(pkt, yd);
    -
    - f->p2p_packet_sent = 1; /* set p2p_packet_sent to sent */
    -
    - p2p_data = g_new0(struct yahoo_p2p_data, 1);
    -
    - p2p_data->gc = gc;
    - p2p_data->host_ip = NULL;
    - p2p_data->host_username = g_strdup(who);
    - p2p_data->val_13 = val_13;
    - p2p_data->connection_type = YAHOO_P2P_WE_ARE_SERVER;
    - p2p_data->source = -1;
    -
    - /* FIXME: If the port is already used, purple_network_listener returns NULL and old listener won't be canceled
    - * in yahoo_close function. */
    - if (yd->listen_data)
    - purple_debug_warning("yahoo","p2p: Failed to create p2p server - server already exists\n");
    - else {
    - yd->listen_data = purple_network_listen(YAHOO_PAGER_PORT_P2P, SOCK_STREAM, yahoo_p2p_server_listen_cb, p2p_data);
    - if (yd->listen_data == NULL)
    - purple_debug_warning("yahoo","p2p: Failed to created p2p server\n");
    - }
    -
    - g_free(base64_ip);
    -}
    -
    -/* function called when connection to p2p host is setup */
    -static void yahoo_p2p_init_cb(gpointer data, gint source, const gchar *error_message)
    -{
    - struct yahoo_p2p_data *p2p_data;
    - struct yahoo_packet *pkt_to_send;
    - PurpleAccount *account;
    - YahooData *yd;
    -
    - p2p_data = data;
    - yd = p2p_data->gc->proto_data;
    -
    - if(error_message != NULL) {
    - purple_debug_warning("yahoo","p2p: %s\n",error_message);
    - yahoo_send_p2p_pkt(p2p_data->gc, p2p_data->host_username, 2);/* send p2p init packet with val_13=2 */
    -
    - yahoo_p2p_disconnect_destroy_data(p2p_data);
    - return;
    - }
    -
    - /* Add an Input Read event to the file descriptor */
    - p2p_data->input_event = purple_input_add(source, PURPLE_INPUT_READ, yahoo_p2p_read_pkt_cb, data);
    - p2p_data->source = source;
    -
    - account = purple_connection_get_account(p2p_data->gc);
    -
    - /* Build the yahoo packet */
    - pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash(pkt_to_send, "ssisi",
    - 4, purple_normalize(account, purple_account_get_username(account)),
    - 5, p2p_data->host_username,
    - 241, 0, /* Protocol identifier */
    - 49, "PEERTOPEER",
    - 13, 1); /* we receive key13= 0 or 2, we send key13=1 */
    -
    - yahoo_p2p_write_pkt(source, pkt_to_send); /* build raw packet and send */
    - yahoo_packet_free(pkt_to_send);
    -}
    -
    -static void yahoo_process_p2p(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - GSList *l = pkt->hash;
    - char *who = NULL;
    - char *base64 = NULL;
    - guchar *decoded;
    - gsize len;
    - gint val_13 = 0;
    - gint val_11 = 0;
    - PurpleAccount *account;
    - YahooFriend *f;
    -
    - /* if status is not YAHOO_STATUS_BRB or YAHOO_STATUS_P2P, the packet bounced back,
    - * so it contains our own ip */
    - if(pkt->status != YAHOO_STATUS_BRB && pkt->status != YAHOO_STATUS_P2P)
    - return ;
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 5:
    - /* our identity */
    - break;
    - case 4:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - who = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_p2p "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 1:
    - /* who again, the master identity this time? */
    - break;
    - case 12:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - base64 = pair->value;
    - /* so, this is an ip address. in base64. decoded it's in ascii.
    - after strtol, it's in reversed byte order. Who thought this up?*/
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_p2p "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 13:
    - val_13 = strtol(pair->value, NULL, 10);
    - break;
    - case 11:
    - val_11 = strtol(pair->value, NULL, 10); /* session id of peer */
    - if( (f = yahoo_friend_find(gc, who)) )
    - f->session_id = val_11;
    - break;
    - /*
    - TODO: figure these out
    - yahoo: Key: 61 Value: 0
    - yahoo: Key: 2 Value:
    - yahoo: Key: 13 Value: 0 packet count ??
    - yahoo: Key: 49 Value: PEERTOPEER
    - yahoo: Key: 140 Value: 1
    - */
    -
    - }
    -
    - l = l->next;
    - }
    -
    - if (base64) {
    - guint32 ip;
    - YahooFriend *f;
    - char *host_ip, *tmp;
    - struct yahoo_p2p_data *p2p_data;
    -
    - decoded = purple_base64_decode(base64, &len);
    - if (decoded == NULL) {
    - purple_debug_info("yahoo","p2p: Unable to decode base64 IP (%s) \n", base64);
    - return;
    - }
    - tmp = purple_str_binary_to_ascii(decoded, len);
    - purple_debug_info("yahoo", "Got P2P service packet (from server): who = %s, ip = %s\n", who, tmp);
    - g_free(tmp);
    -
    - ip = strtol((gchar *)decoded, NULL, 10);
    - g_free(decoded);
    - host_ip = g_strdup_printf("%u.%u.%u.%u", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff,
    - (ip >> 24) & 0xff);
    - f = yahoo_friend_find(gc, who);
    - if (f)
    - yahoo_friend_set_ip(f, host_ip);
    - purple_debug_info("yahoo", "IP : %s\n", host_ip);
    -
    - account = purple_connection_get_account(gc);
    -
    - if(val_11==0) {
    - if(!f)
    - return;
    - else
    - val_11 = f->session_id;
    - }
    -
    - p2p_data = g_new0(struct yahoo_p2p_data, 1);
    - p2p_data->host_username = g_strdup(who);
    - p2p_data->val_13 = val_13;
    - p2p_data->session_id = val_11;
    - p2p_data->host_ip = host_ip;
    - p2p_data->gc = gc;
    - p2p_data->connection_type = YAHOO_P2P_WE_ARE_CLIENT;
    - p2p_data->source = -1;
    -
    - /* connect to host */
    - if((purple_proxy_connect(gc, account, host_ip, YAHOO_PAGER_PORT_P2P, yahoo_p2p_init_cb, p2p_data))==NULL) {
    - purple_debug_info("yahoo","p2p: Connection to %s failed\n", host_ip);
    - g_free(p2p_data->host_ip);
    - g_free(p2p_data->host_username);
    - g_free(p2p_data);
    - }
    - }
    -}
    -
    -static void yahoo_process_audible(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - PurpleAccount *account;
    - char *who = NULL, *msg = NULL, *id = NULL;
    - GSList *l = pkt->hash;
    -
    - account = purple_connection_get_account(gc);
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 4:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - who = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_audible "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 5:
    - /* us */
    - break;
    - case 230:
    - /* the audible, in foo.locale.bar.baz format
    - eg: base.tw.smiley.smiley43 */
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - id = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_audible "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 231:
    - /* the text of the audible */
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - msg = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_audible "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 232:
    - /* SHA-1 hash of audible SWF file (eg: 4e8691499d9c0fb8374478ff9720f4a9ea4a4915) */
    - break;
    - }
    -
    - l = l->next;
    - }
    -
    - if (!msg)
    - msg = id;
    - if (!who || !msg)
    - return;
    - if (!g_utf8_validate(msg, -1, NULL)) {
    - purple_debug_misc("yahoo", "Warning, nonutf8 audible, ignoring!\n");
    - return;
    - }
    - if (!purple_privacy_check(account, who)) {
    - purple_debug_misc("yahoo", "Audible message from %s for %s dropped!\n",
    - purple_account_get_username(account), who);
    - return;
    - }
    - if (id) {
    - /* "http://l.yimg.com/pu/dl/aud/"+locale+"/"+id+".swf" */
    - char **audible_locale = g_strsplit(id, ".", 0);
    - char *buf = g_strdup_printf(_("[ Audible %s/%s/%s.swf ] %s"), YAHOO_AUDIBLE_URL, audible_locale[1], id, msg);
    - g_strfreev(audible_locale);
    -
    - serv_got_im(gc, who, buf, 0, time(NULL));
    - g_free(buf);
    - } else
    - serv_got_im(gc, who, msg, 0, time(NULL));
    -}
    -
    -static void yahoo_packet_process(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - switch (pkt->service) {
    - case YAHOO_SERVICE_LOGON:
    - case YAHOO_SERVICE_LOGOFF:
    - case YAHOO_SERVICE_ISAWAY:
    - case YAHOO_SERVICE_ISBACK:
    - case YAHOO_SERVICE_GAMELOGON:
    - case YAHOO_SERVICE_GAMELOGOFF:
    - case YAHOO_SERVICE_CHATLOGON:
    - case YAHOO_SERVICE_CHATLOGOFF:
    - case YAHOO_SERVICE_Y6_STATUS_UPDATE:
    - case YAHOO_SERVICE_STATUS_15:
    - yahoo_process_status(gc, pkt);
    - break;
    - case YAHOO_SERVICE_NOTIFY:
    - yahoo_process_notify(gc, pkt, YAHOO_PKT_TYPE_SERVER);
    - break;
    - case YAHOO_SERVICE_MESSAGE:
    - case YAHOO_SERVICE_GAMEMSG:
    - case YAHOO_SERVICE_CHATMSG:
    - yahoo_process_message(gc, pkt, YAHOO_PKT_TYPE_SERVER);
    - break;
    - case YAHOO_SERVICE_SYSMESSAGE:
    - yahoo_process_sysmessage(gc, pkt);
    - break;
    - case YAHOO_SERVICE_NEWMAIL:
    - yahoo_process_mail(gc, pkt);
    - break;
    - case YAHOO_SERVICE_NEWCONTACT:
    - yahoo_process_contact(gc, pkt);
    - break;
    - case YAHOO_SERVICE_AUTHRESP:
    - yahoo_process_authresp(gc, pkt);
    - break;
    - case YAHOO_SERVICE_LIST:
    - yahoo_process_list(gc, pkt);
    - break;
    - case YAHOO_SERVICE_LIST_15:
    - yahoo_process_list_15(gc, pkt);
    - break;
    - case YAHOO_SERVICE_AUTH:
    - yahoo_process_auth(gc, pkt);
    - break;
    - case YAHOO_SERVICE_AUTH_REQ_15:
    - yahoo_buddy_auth_req_15(gc, pkt);
    - break;
    - case YAHOO_SERVICE_ADDBUDDY:
    - yahoo_process_addbuddy(gc, pkt);
    - break;
    - case YAHOO_SERVICE_IGNORECONTACT:
    - yahoo_process_ignore(gc, pkt);
    - break;
    - case YAHOO_SERVICE_CONFINVITE:
    - case YAHOO_SERVICE_CONFADDINVITE:
    - yahoo_process_conference_invite(gc, pkt);
    - break;
    - case YAHOO_SERVICE_CONFDECLINE:
    - yahoo_process_conference_decline(gc, pkt);
    - break;
    - case YAHOO_SERVICE_CONFLOGON:
    - yahoo_process_conference_logon(gc, pkt);
    - break;
    - case YAHOO_SERVICE_CONFLOGOFF:
    - yahoo_process_conference_logoff(gc, pkt);
    - break;
    - case YAHOO_SERVICE_CONFMSG:
    - yahoo_process_conference_message(gc, pkt);
    - break;
    - case YAHOO_SERVICE_CHATONLINE:
    - yahoo_process_chat_online(gc, pkt);
    - break;
    - case YAHOO_SERVICE_CHATLOGOUT:
    - yahoo_process_chat_logout(gc, pkt);
    - break;
    - case YAHOO_SERVICE_CHATGOTO:
    - yahoo_process_chat_goto(gc, pkt);
    - break;
    - case YAHOO_SERVICE_CHATJOIN:
    - yahoo_process_chat_join(gc, pkt);
    - break;
    - case YAHOO_SERVICE_CHATLEAVE: /* XXX is this right? */
    - case YAHOO_SERVICE_CHATEXIT:
    - yahoo_process_chat_exit(gc, pkt);
    - break;
    - case YAHOO_SERVICE_CHATINVITE: /* XXX never seen this one, might not do it right */
    - case YAHOO_SERVICE_CHATADDINVITE:
    - yahoo_process_chat_addinvite(gc, pkt);
    - break;
    - case YAHOO_SERVICE_COMMENT:
    - yahoo_process_chat_message(gc, pkt);
    - break;
    - case YAHOO_SERVICE_PRESENCE_PERM:
    - case YAHOO_SERVICE_PRESENCE_SESSION:
    - yahoo_process_presence(gc, pkt);
    - break;
    - case YAHOO_SERVICE_P2PFILEXFER:
    - /* This case had no break and continued; thus keeping it this way.*/
    - yahoo_process_p2p(gc, pkt); /* P2PFILEXFER handled the same way as process_p2p */
    - yahoo_process_p2pfilexfer(gc, pkt); /* redundant ??, need to have a break now */
    - case YAHOO_SERVICE_FILETRANSFER:
    - yahoo_process_filetransfer(gc, pkt);
    - break;
    - case YAHOO_SERVICE_PEERTOPEER:
    - yahoo_process_p2p(gc, pkt);
    - break;
    - case YAHOO_SERVICE_PICTURE:
    - yahoo_process_picture(gc, pkt);
    - break;
    - case YAHOO_SERVICE_PICTURE_CHECKSUM:
    - yahoo_process_picture_checksum(gc, pkt);
    - break;
    - case YAHOO_SERVICE_PICTURE_UPLOAD:
    - yahoo_process_picture_upload(gc, pkt);
    - break;
    - case YAHOO_SERVICE_PICTURE_UPDATE:
    - case YAHOO_SERVICE_AVATAR_UPDATE:
    - yahoo_process_avatar_update(gc, pkt);
    - break;
    - case YAHOO_SERVICE_AUDIBLE:
    - yahoo_process_audible(gc, pkt);
    - break;
    - case YAHOO_SERVICE_CONTACT_DETAILS:
    - yahoo_process_contact_details(gc, pkt);
    - break;
    - case YAHOO_SERVICE_FILETRANS_15:
    - yahoo_process_filetrans_15(gc, pkt);
    - break;
    - case YAHOO_SERVICE_FILETRANS_INFO_15:
    - yahoo_process_filetrans_info_15(gc, pkt);
    - break;
    - case YAHOO_SERVICE_FILETRANS_ACC_15:
    - yahoo_process_filetrans_acc_15(gc, pkt);
    - break;
    - case YAHOO_SERVICE_SMS_MSG:
    - yahoo_process_sms_message(gc, pkt);
    - break;
    -
    - default:
    - purple_debug_error("yahoo", "Unhandled service 0x%02x\n", pkt->service);
    - break;
    - }
    -}
    -
    -static void yahoo_pending(gpointer data, gint source, PurpleInputCondition cond)
    -{
    - PurpleConnection *gc = data;
    - YahooData *yd = gc->proto_data;
    - char buf[1024];
    - int len;
    -
    - len = read(yd->fd, buf, sizeof(buf));
    -
    - if (len < 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 (len == 0) {
    - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
    - _("Server closed the connection"));
    - return;
    - }
    - gc->last_received = time(NULL);
    - yd->rxqueue = g_realloc(yd->rxqueue, len + yd->rxlen);
    - memcpy(yd->rxqueue + yd->rxlen, buf, len);
    - yd->rxlen += len;
    -
    - while (1) {
    - struct yahoo_packet *pkt;
    - int pos = 0;
    - int pktlen;
    -
    - if (yd->rxlen < YAHOO_PACKET_HDRLEN)
    - return;
    -
    - if (strncmp((char *)yd->rxqueue, "YMSG", MIN(4, yd->rxlen)) != 0) {
    - /* HEY! This isn't even a YMSG packet. What
    - * are you trying to pull? */
    - guchar *start;
    -
    - purple_debug_warning("yahoo", "Error in YMSG stream, got something not a YMSG packet!\n");
    -
    - start = memchr(yd->rxqueue + 1, 'Y', yd->rxlen - 1);
    - if (start) {
    - g_memmove(yd->rxqueue, start, yd->rxlen - (start - yd->rxqueue));
    - yd->rxlen -= start - yd->rxqueue;
    - continue;
    - } else {
    - g_free(yd->rxqueue);
    - yd->rxqueue = NULL;
    - yd->rxlen = 0;
    - return;
    - }
    - }
    -
    - pos += 4; /* YMSG */
    - pos += 2;
    - pos += 2;
    -
    - pktlen = yahoo_get16(yd->rxqueue + pos); pos += 2;
    - purple_debug_misc("yahoo", "%d bytes to read, rxlen is %d\n", pktlen, yd->rxlen);
    -
    - if (yd->rxlen < (YAHOO_PACKET_HDRLEN + pktlen))
    - return;
    -
    - yahoo_packet_dump(yd->rxqueue, YAHOO_PACKET_HDRLEN + pktlen);
    -
    - pkt = yahoo_packet_new(0, 0, 0);
    -
    - pkt->service = yahoo_get16(yd->rxqueue + pos); pos += 2;
    - pkt->status = yahoo_get32(yd->rxqueue + pos); pos += 4;
    - purple_debug_misc("yahoo", "Yahoo Service: 0x%02x Status: %d\n",
    - pkt->service, pkt->status);
    - pkt->id = yahoo_get32(yd->rxqueue + pos); pos += 4;
    -
    - yahoo_packet_read(pkt, yd->rxqueue + pos, pktlen);
    -
    - yd->rxlen -= YAHOO_PACKET_HDRLEN + pktlen;
    - if (yd->rxlen) {
    - guchar *tmp = g_memdup(yd->rxqueue + YAHOO_PACKET_HDRLEN + pktlen, yd->rxlen);
    - g_free(yd->rxqueue);
    - yd->rxqueue = tmp;
    - } else {
    - g_free(yd->rxqueue);
    - yd->rxqueue = NULL;
    - }
    -
    - yahoo_packet_process(gc, pkt);
    -
    - yahoo_packet_free(pkt);
    - }
    -}
    -
    -static void yahoo_got_connected(gpointer data, gint source, const gchar *error_message)
    -{
    - PurpleConnection *gc = data;
    - YahooData *yd;
    - struct yahoo_packet *pkt;
    -
    - if (source < 0) {
    - gchar *tmp;
    - 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;
    - }
    -
    - yd = gc->proto_data;
    - yd->fd = source;
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH, yd->current_status, yd->session_id);
    -
    - yahoo_packet_hash_str(pkt, 1, purple_normalize(gc->account, purple_account_get_username(purple_connection_get_account(gc))));
    - yahoo_packet_send_and_free(pkt, yd);
    -
    - gc->inpa = purple_input_add(yd->fd, PURPLE_INPUT_READ, yahoo_pending, gc);
    -}
    -
    -#ifdef TRY_WEBMESSENGER_LOGIN
    -static void yahoo_got_web_connected(gpointer data, gint source, const gchar *error_message)
    -{
    - PurpleConnection *gc = data;
    - YahooData *yd;
    - struct yahoo_packet *pkt;
    -
    - if (source < 0) {
    - gchar *tmp;
    - 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;
    - }
    -
    - yd = gc->proto_data;
    - yd->fd = source;
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_WEBLOGIN, YAHOO_STATUS_WEBLOGIN, yd->session_id);
    -
    - yahoo_packet_hash(pkt, "sss", 0,
    - purple_normalize(gc->account, purple_account_get_username(purple_connection_get_account(gc))),
    - 1, purple_normalize(gc->account, purple_account_get_username(purple_connection_get_account(gc))),
    - 6, yd->auth);
    - yahoo_packet_send_and_free(pkt, yd);
    -
    - g_free(yd->auth);
    - gc->inpa = purple_input_add(yd->fd, PURPLE_INPUT_READ, yahoo_pending, gc);
    -}
    -
    -static void yahoo_web_pending(gpointer data, gint source, PurpleInputCondition cond)
    -{
    - PurpleConnection *gc = data;
    - PurpleAccount *account = purple_connection_get_account(gc);
    - YahooData *yd = gc->proto_data;
    - char bufread[2048], *i = bufread, *buf = bufread;
    - int len;
    - GString *s;
    -
    - len = read(source, bufread, sizeof(bufread) - 1);
    -
    - if (len < 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 (len == 0) {
    - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
    - _("Server closed the connection"));
    - return;
    - }
    -
    - if (yd->rxlen > 0 || !g_strstr_len(buf, len, "\r\n\r\n")) {
    - yd->rxqueue = g_realloc(yd->rxqueue, yd->rxlen + len + 1);
    - memcpy(yd->rxqueue + yd->rxlen, buf, len);
    - yd->rxlen += len;
    - i = buf = (char *)yd->rxqueue;
    - len = yd->rxlen;
    - }
    - buf[len] = '\0';
    -
    - if ((strncmp(buf, "HTTP/1.0 302", strlen("HTTP/1.0 302")) &&
    - strncmp(buf, "HTTP/1.1 302", strlen("HTTP/1.1 302")))) {
    - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
    - _("Received unexpected HTTP response from server"));
    - purple_debug_misc("yahoo", "Unexpected HTTP response: %s\n", buf);
    - return;
    - }
    -
    - s = g_string_sized_new(len);
    -
    - while ((i = strstr(i, "Set-Cookie: "))) {
    -
    - i += strlen("Set-Cookie: ");
    - for (;*i != ';' && *i != '\0'; i++)
    - g_string_append_c(s, *i);
    -
    - g_string_append(s, "; ");
    - /* Should these cookies be included too when trying for xfer?
    - * It seems to work without these
    - */
    - }
    -
    - yd->auth = g_string_free(s, FALSE);
    - purple_input_remove(gc->inpa);
    - close(source);
    - g_free(yd->rxqueue);
    - yd->rxqueue = NULL;
    - yd->rxlen = 0;
    - /* Now we have our cookies to login with. I'll go get the milk. */
    - if (purple_proxy_connect(gc, account, "wcs2.msg.dcn.yahoo.com",
    - purple_account_get_int(account, "port", YAHOO_PAGER_PORT),
    - yahoo_got_web_connected, gc) == NULL) {
    - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
    - _("Unable to connect"));
    - return;
    - }
    -}
    -
    -static void yahoo_got_cookies_send_cb(gpointer data, gint source, PurpleInputCondition cond)
    -{
    - PurpleConnection *gc;
    - YahooData *yd;
    - int written, remaining;
    -
    - gc = data;
    - yd = gc->proto_data;
    -
    - remaining = strlen(yd->auth) - yd->auth_written;
    - written = write(source, yd->auth + yd->auth_written, remaining);
    -
    - if (written < 0 && errno == EAGAIN)
    - written = 0;
    - else if (written <= 0) {
    - gchar *tmp;
    - g_free(yd->auth);
    - yd->auth = NULL;
    - if (gc->inpa)
    - purple_input_remove(gc->inpa);
    - gc->inpa = 0;
    - tmp = g_strdup_printf(_("Lost connection with %s: %s"),
    - "login.yahoo.com:80", g_strerror(errno));
    - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
    - g_free(tmp);
    - return;
    - }
    -
    - if (written < remaining) {
    - yd->auth_written += written;
    - return;
    - }
    -
    - g_free(yd->auth);
    - yd->auth = NULL;
    - yd->auth_written = 0;
    - purple_input_remove(gc->inpa);
    - gc->inpa = purple_input_add(source, PURPLE_INPUT_READ, yahoo_web_pending, gc);
    -}
    -
    -static void yahoo_got_cookies(gpointer data, gint source, const gchar *error_message)
    -{
    - PurpleConnection *gc = data;
    -
    - if (source < 0) {
    - gchar *tmp;
    - tmp = g_strdup_printf(_("Unable to establish a connection with %s: %s"),
    - "login.yahoo.com:80", error_message);
    - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
    - g_free(tmp);
    - return;
    - }
    -
    - if (gc->inpa == 0)
    - {
    - gc->inpa = purple_input_add(source, PURPLE_INPUT_WRITE,
    - yahoo_got_cookies_send_cb, gc);
    - yahoo_got_cookies_send_cb(gc, source, PURPLE_INPUT_WRITE);
    - }
    -}
    -
    -static void yahoo_login_page_hash_iter(const char *key, const char *val, GString *url)
    -{
    - if (!strcmp(key, "passwd") || !strcmp(key, "login"))
    - return;
    - g_string_append_c(url, '&');
    - g_string_append(url, key);
    - g_string_append_c(url, '=');
    - if (!strcmp(key, ".save") || !strcmp(key, ".js"))
    - g_string_append_c(url, '1');
    - else if (!strcmp(key, ".challenge"))
    - g_string_append(url, val);
    - else
    - g_string_append(url, purple_url_encode(val));
    -}
    -
    -static GHashTable *yahoo_login_page_hash(const char *buf, size_t len)
    -{
    - GHashTable *hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
    - const char *c = buf;
    - char *d;
    - char name[64], value[64];
    - int count;
    - int input_len = strlen("<input ");
    - int name_len = strlen("name=\"");
    - int value_len = strlen("value=\"");
    - while ((len > ((c - buf) + input_len))
    - && (c = strstr(c, "<input "))) {
    - if (!(c = g_strstr_len(c, len - (c - buf), "name=\"")))
    - continue;
    - c += name_len;
    - count = sizeof(name)-1;
    - for (d = name; (len > ((c - buf) + 1)) && *c!='"'
    - && count; c++, d++, count--)
    - *d = *c;
    - *d = '\0';
    - count = sizeof(value)-1;
    - if (!(d = g_strstr_len(c, len - (c - buf), "value=\"")))
    - continue;
    - d += value_len;
    - if (strchr(c, '>') < d)
    - break;
    - for (c = d, d = value; (len > ((c - buf) + 1))
    - && *c!='"' && count; c++, d++, count--)
    - *d = *c;
    - *d = '\0';
    - g_hash_table_insert(hash, g_strdup(name), g_strdup(value));
    - }
    - return hash;
    -}
    -
    -static void
    -yahoo_login_page_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data,
    - const gchar *url_text, size_t len, const gchar *error_message)
    -{
    - PurpleConnection *gc = (PurpleConnection *)user_data;
    - PurpleAccount *account = purple_connection_get_account(gc);
    - YahooData *yd = gc->proto_data;
    - const char *sn = purple_account_get_username(account);
    - const char *pass = purple_connection_get_password(gc);
    - GHashTable *hash = yahoo_login_page_hash(url_text, len);
    - GString *url = g_string_new("GET http://login.yahoo.com/config/login?login=");
    - char md5[33], *hashp = md5, *chal;
    - int i;
    - PurpleCipher *cipher;
    - PurpleCipherContext *context;
    - guchar digest[16];
    -
    - yd->url_datas = g_slist_remove(yd->url_datas, url_data);
    -
    - if (error_message != NULL)
    - {
    - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
    - error_message);
    - return;
    - }
    -
    - url = g_string_append(url, sn);
    - url = g_string_append(url, "&passwd=");
    -
    - cipher = purple_ciphers_find_cipher("md5");
    - context = purple_cipher_context_new(cipher, NULL);
    -
    - purple_cipher_context_append(context, (const guchar *)pass, strlen(pass));
    - purple_cipher_context_digest(context, sizeof(digest), digest, NULL);
    - for (i = 0; i < 16; ++i) {
    - g_snprintf(hashp, 3, "%02x", digest[i]);
    - hashp += 2;
    - }
    -
    - chal = g_strconcat(md5, g_hash_table_lookup(hash, ".challenge"), NULL);
    - purple_cipher_context_reset(context, NULL);
    - purple_cipher_context_append(context, (const guchar *)chal, strlen(chal));
    - purple_cipher_context_digest(context, sizeof(digest), digest, NULL);
    - hashp = md5;
    - for (i = 0; i < 16; ++i) {
    - g_snprintf(hashp, 3, "%02x", digest[i]);
    - hashp += 2;
    - }
    - /*
    - * I dunno why this is here and commented out.. but in case it's needed
    - * I updated it..
    -
    - purple_cipher_context_reset(context, NULL);
    - purple_cipher_context_append(context, md5, strlen(md5));
    - purple_cipher_context_digest(context, sizeof(digest), digest, NULL);
    - hashp = md5;
    - for (i = 0; i < 16; ++i) {
    - g_snprintf(hashp, 3, "%02x", digest[i]);
    - hashp += 2;
    - }
    - */
    - g_free(chal);
    -
    - url = g_string_append(url, md5);
    - g_hash_table_foreach(hash, (GHFunc)yahoo_login_page_hash_iter, url);
    -
    - url = g_string_append(url, "&.hash=1&.md5=1 HTTP/1.1\r\n"
    - "Host: login.yahoo.com\r\n\r\n");
    - g_hash_table_destroy(hash);
    - yd->auth = g_string_free(url, FALSE);
    - if (purple_proxy_connect(gc, account, "login.yahoo.com", 80, yahoo_got_cookies, gc) == NULL) {
    - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
    - _("Unable to connect"));
    - return;
    - }
    -
    - purple_cipher_context_destroy(context);
    -}
    -#endif /* TRY_WEBMESSENGER_LOGIN */
    -
    -static void yahoo_picture_check(PurpleAccount *account)
    -{
    - PurpleConnection *gc = purple_account_get_connection(account);
    - PurpleStoredImage *img = purple_buddy_icons_find_account_icon(account);
    -
    - yahoo_set_buddy_icon(gc, img);
    - purple_imgstore_unref(img);
    -}
    -
    -static int get_yahoo_status_from_purple_status(PurpleStatus *status)
    -{
    - PurplePresence *presence;
    - const char *status_id;
    - const char *msg;
    -
    - presence = purple_status_get_presence(status);
    - status_id = purple_status_get_id(status);
    - msg = purple_status_get_attr_string(status, "message");
    -
    - if ((msg != NULL) && (*msg != '\0')) {
    - return YAHOO_STATUS_CUSTOM;
    - } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_AVAILABLE)) {
    - return YAHOO_STATUS_AVAILABLE;
    - } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_BRB)) {
    - return YAHOO_STATUS_BRB;
    - } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_BUSY)) {
    - return YAHOO_STATUS_BUSY;
    - } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_NOTATHOME)) {
    - return YAHOO_STATUS_NOTATHOME;
    - } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_NOTATDESK)) {
    - return YAHOO_STATUS_NOTATDESK;
    - } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_NOTINOFFICE)) {
    - return YAHOO_STATUS_NOTINOFFICE;
    - } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_ONPHONE)) {
    - return YAHOO_STATUS_ONPHONE;
    - } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_ONVACATION)) {
    - return YAHOO_STATUS_ONVACATION;
    - } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_OUTTOLUNCH)) {
    - return YAHOO_STATUS_OUTTOLUNCH;
    - } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_STEPPEDOUT)) {
    - return YAHOO_STATUS_STEPPEDOUT;
    - } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_INVISIBLE)) {
    - return YAHOO_STATUS_INVISIBLE;
    - } else if (!strcmp(status_id, YAHOO_STATUS_TYPE_AWAY)) {
    - return YAHOO_STATUS_CUSTOM;
    - } else if (purple_presence_is_idle(presence)) {
    - return YAHOO_STATUS_IDLE;
    - } else {
    - purple_debug_error("yahoo", "Unexpected PurpleStatus!\n");
    - return YAHOO_STATUS_AVAILABLE;
    - }
    -}
    -
    -static void yahoo_got_pager_server(PurpleUtilFetchUrlData *url_data,
    - gpointer user_data, const gchar *url_text, gsize len, const gchar *error_message)
    -{
    - YahooData *yd = user_data;
    - PurpleConnection *gc = yd->gc;
    - PurpleAccount *a = purple_connection_get_account(gc);
    - gchar **strings = NULL, *cs_server = NULL;
    - int port = purple_account_get_int(a, "port", YAHOO_PAGER_PORT);
    - int stringslen = 0;
    -
    - yd->url_datas = g_slist_remove(yd->url_datas, url_data);
    -
    - if(error_message != NULL || len == 0) {
    - purple_debug_error("yahoo", "Unable to retrieve server info. %"
    - G_GSIZE_FORMAT " bytes retrieved with error message: %s\n", len,
    - error_message ? error_message : "(null)");
    -
    - if(yahoo_is_japan(a)) { /* We don't know fallback hosts for Yahoo Japan :( */
    - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
    - _("Unable to connect: The server returned an empty response."));
    - } else {
    - if(purple_proxy_connect(gc, a, YAHOO_PAGER_HOST_FALLBACK, port,
    - yahoo_got_connected, gc) == NULL) {
    - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
    - _("Unable to connect"));
    - }
    - }
    - } else {
    - strings = g_strsplit(url_text, "\r\n", -1);
    -
    - if((stringslen = g_strv_length(strings)) > 1) {
    - int i;
    -
    - for(i = 0; i < stringslen; i++) {
    - if(g_ascii_strncasecmp(strings[i], "COLO_CAPACITY=", 14) == 0) {
    - purple_debug_info("yahoo", "Got COLO Capacity: %s\n", &(strings[i][14]));
    - } else if(g_ascii_strncasecmp(strings[i], "CS_IP_ADDRESS=", 14) == 0) {
    - cs_server = g_strdup(&strings[i][14]);
    - purple_debug_info("yahoo", "Got CS IP address: %s\n", cs_server);
    - }
    - }
    - }
    -
    - if(cs_server) { /* got an address; get on with connecting */
    - if(purple_proxy_connect(gc, a, cs_server, port, yahoo_got_connected, gc) == NULL)
    - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
    - _("Unable to connect"));
    - } else {
    - purple_debug_error("yahoo", "No CS address retrieved! Server "
    - "response:\n%s\n", url_text ? url_text : "(null)");
    -
    - if(yahoo_is_japan(a)) { /* We don't know fallback hosts for Yahoo Japan :( */
    - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
    - _("Unable to connect: The server's response did not contain "
    - "the necessary information"));
    - } else
    - if(purple_proxy_connect(gc, a, YAHOO_PAGER_HOST_FALLBACK, port,
    - yahoo_got_connected, gc) == NULL) {
    - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
    - _("Unable to connect"));
    - }
    - }
    - }
    -
    - g_strfreev(strings);
    - g_free(cs_server);
    -}
    -
    -void yahoo_login(PurpleAccount *account) {
    - PurpleConnection *gc = purple_account_get_connection(account);
    - YahooData *yd = gc->proto_data = g_new0(YahooData, 1);
    - PurpleStatus *status = purple_account_get_active_status(account);
    - gboolean use_whole_url = yahoo_account_use_http_proxy(gc);
    - gboolean proxy_ssl = purple_account_get_bool(account, "proxy_ssl", FALSE);
    - PurpleUtilFetchUrlData *url_data;
    -
    - gc->flags |= PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_NO_BGCOLOR | PURPLE_CONNECTION_NO_URLDESC;
    -
    - purple_connection_update_progress(gc, _("Connecting"), 1, 2);
    -
    - purple_connection_set_display_name(gc, purple_account_get_username(account));
    -
    - yd->gc = gc;
    - yd->jp = yahoo_is_japan(account);
    - yd->yahoo_local_p2p_server_fd = -1;
    - yd->fd = -1;
    - yd->txhandler = 0;
    - /* TODO: Is there a good grow size for the buffer? */
    - yd->txbuf = purple_circ_buffer_new(0);
    - yd->friends = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, yahoo_friend_free);
    - yd->imvironments = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
    - yd->xfer_peer_idstring_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
    - yd->peers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
    - yahoo_p2p_disconnect_destroy_data);
    - yd->sms_carrier = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
    - yd->yahoo_p2p_timer = purple_timeout_add_seconds(YAHOO_P2P_KEEPALIVE_SECS,
    - yahoo_p2p_keepalive, gc);
    - yd->confs = NULL;
    - yd->conf_id = 2;
    - yd->last_keepalive = yd->last_ping = time(NULL);
    -
    - yd->current_status = get_yahoo_status_from_purple_status(status);
    -
    - yahoo_picture_check(account);
    -
    - /* Get the pager server. Actually start connecting in the callback since we
    - * must have the contents of the HTTP response to proceed. */
    - url_data = purple_util_fetch_url_request_len_with_account(
    - proxy_ssl ? purple_connection_get_account(gc) : NULL,
    - yd->jp ? YAHOOJP_PAGER_HOST_REQ_URL : YAHOO_PAGER_HOST_REQ_URL,
    - use_whole_url ? TRUE : FALSE,
    - YAHOO_CLIENT_USERAGENT, FALSE, NULL, FALSE, -1,
    - yahoo_got_pager_server, yd);
    - if (url_data)
    - yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
    -
    - return;
    -}
    -
    -void yahoo_close(PurpleConnection *gc) {
    - YahooData *yd = (YahooData *)gc->proto_data;
    - GSList *l;
    -
    - if (gc->inpa)
    - purple_input_remove(gc->inpa);
    -
    - while (yd->url_datas) {
    - purple_util_fetch_url_cancel(yd->url_datas->data);
    - yd->url_datas = g_slist_delete_link(yd->url_datas, yd->url_datas);
    - }
    -
    - for (l = yd->confs; l; l = l->next) {
    - PurpleConversation *conv = l->data;
    -
    - yahoo_conf_leave(yd, purple_conversation_get_name(conv),
    - purple_connection_get_display_name(gc),
    - purple_conv_chat_get_users(PURPLE_CONV_CHAT(conv)));
    - }
    - g_slist_free(yd->confs);
    -
    - for (l = yd->cookies; l; l = l->next) {
    - g_free(l->data);
    - l->data=NULL;
    - }
    - g_slist_free(yd->cookies);
    -
    - yd->chat_online = FALSE;
    - if (yd->in_chat)
    - yahoo_c_leave(gc, 1); /* 1 = YAHOO_CHAT_ID */
    -
    - purple_timeout_remove(yd->yahoo_p2p_timer);
    - if(yd->yahoo_p2p_server_timeout_handle != 0) {
    - purple_timeout_remove(yd->yahoo_p2p_server_timeout_handle);
    - yd->yahoo_p2p_server_timeout_handle = 0;
    - }
    -
    - /* close p2p server if it is waiting for a peer to connect */
    - if (yd->yahoo_p2p_server_watcher) {
    - purple_input_remove(yd->yahoo_p2p_server_watcher);
    - yd->yahoo_p2p_server_watcher = 0;
    - }
    - if (yd->yahoo_local_p2p_server_fd >= 0) {
    - close(yd->yahoo_local_p2p_server_fd);
    - yd->yahoo_local_p2p_server_fd = -1;
    - }
    -
    - g_hash_table_destroy(yd->sms_carrier);
    - g_hash_table_destroy(yd->peers);
    - g_hash_table_destroy(yd->friends);
    - g_hash_table_destroy(yd->imvironments);
    - g_hash_table_destroy(yd->xfer_peer_idstring_map);
    - g_free(yd->chat_name);
    -
    - g_free(yd->cookie_y);
    - g_free(yd->cookie_t);
    - g_free(yd->cookie_b);
    -
    - if (yd->txhandler)
    - purple_input_remove(yd->txhandler);
    -
    - purple_circ_buffer_destroy(yd->txbuf);
    -
    - if (yd->fd >= 0)
    - close(yd->fd);
    -
    - g_free(yd->rxqueue);
    - yd->rxlen = 0;
    - g_free(yd->picture_url);
    -
    - if (yd->buddy_icon_connect_data)
    - purple_proxy_connect_cancel(yd->buddy_icon_connect_data);
    - if (yd->picture_upload_todo)
    - yahoo_buddy_icon_upload_data_free(yd->picture_upload_todo);
    - if (yd->ycht)
    - ycht_connection_close(yd->ycht);
    - if (yd->listen_data != NULL)
    - purple_network_listen_cancel(yd->listen_data);
    -
    - g_free(yd->pending_chat_room);
    - g_free(yd->pending_chat_id);
    - g_free(yd->pending_chat_topic);
    - g_free(yd->pending_chat_goto);
    - g_strfreev(yd->profiles);
    -
    - yahoo_personal_details_reset(&yd->ypd, TRUE);
    -
    - g_free(yd->current_list15_grp);
    -
    - g_free(yd);
    - gc->proto_data = NULL;
    -}
    -
    -const char *yahoo_list_icon(PurpleAccount *a, PurpleBuddy *b)
    -{
    - return "yahoo";
    -}
    -
    -const char *yahoo_list_emblem(PurpleBuddy *b)
    -{
    - PurpleAccount *account;
    - PurpleConnection *gc;
    - YahooFriend *f;
    - PurplePresence *presence;
    -
    - if (!b || !(account = purple_buddy_get_account(b)) ||
    - !(gc = purple_account_get_connection(account)) ||
    - !gc->proto_data)
    - return NULL;
    -
    - f = yahoo_friend_find(gc, purple_buddy_get_name(b));
    - if (!f) {
    - return "not-authorized";
    - }
    -
    - presence = purple_buddy_get_presence(b);
    -
    - if (purple_presence_is_online(presence)) {
    - if (yahoo_friend_get_game(f))
    - return "game";
    -
    - if (f->fed)
    - return "external";
    - }
    - return NULL;
    -}
    -
    -static const char *yahoo_get_status_string(enum yahoo_status a)
    -{
    - switch (a) {
    - case YAHOO_STATUS_BRB:
    - return _("Be Right Back");
    - case YAHOO_STATUS_BUSY:
    - return _("Busy");
    - case YAHOO_STATUS_NOTATHOME:
    - return _("Not at Home");
    - case YAHOO_STATUS_NOTATDESK:
    - return _("Not at Desk");
    - case YAHOO_STATUS_NOTINOFFICE:
    - return _("Not in Office");
    - case YAHOO_STATUS_ONPHONE:
    - return _("On the Phone");
    - case YAHOO_STATUS_ONVACATION:
    - return _("On Vacation");
    - case YAHOO_STATUS_OUTTOLUNCH:
    - return _("Out to Lunch");
    - case YAHOO_STATUS_STEPPEDOUT:
    - return _("Stepped Out");
    - case YAHOO_STATUS_INVISIBLE:
    - return _("Invisible");
    - case YAHOO_STATUS_IDLE:
    - return _("Idle");
    - case YAHOO_STATUS_OFFLINE:
    - return _("Offline");
    - default:
    - return _("Available");
    - }
    -}
    -
    -static void yahoo_initiate_conference(PurpleBlistNode *node, gpointer data) {
    -
    - PurpleBuddy *buddy;
    - PurpleConnection *gc;
    -
    - GHashTable *components;
    - YahooData *yd;
    - int id;
    -
    - g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
    -
    - buddy = (PurpleBuddy *) node;
    - gc = purple_account_get_connection(purple_buddy_get_account(buddy));
    - yd = gc->proto_data;
    - id = yd->conf_id;
    -
    - components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
    - g_hash_table_replace(components, g_strdup("room"),
    - g_strdup_printf("%s-%d", purple_connection_get_display_name(gc), id));
    - g_hash_table_replace(components, g_strdup("topic"), g_strdup("Join my conference..."));
    - g_hash_table_replace(components, g_strdup("type"), g_strdup("Conference"));
    - yahoo_c_join(gc, components);
    - g_hash_table_destroy(components);
    -
    - yahoo_c_invite(gc, id, "Join my conference...", purple_buddy_get_name(buddy));
    -}
    -
    -static void yahoo_presence_settings(PurpleBlistNode *node, gpointer data) {
    - PurpleBuddy *buddy;
    - PurpleConnection *gc;
    - int presence_val = GPOINTER_TO_INT(data);
    -
    - buddy = (PurpleBuddy *) node;
    - gc = purple_account_get_connection(purple_buddy_get_account(buddy));
    -
    - yahoo_friend_update_presence(gc, purple_buddy_get_name(buddy), presence_val);
    -}
    -
    -static void yahoo_game(PurpleBlistNode *node, gpointer data) {
    -
    - PurpleBuddy *buddy;
    - PurpleConnection *gc;
    -
    - const char *game;
    - char *game2;
    - char *t;
    - char url[256];
    - YahooFriend *f;
    -
    - g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
    -
    - buddy = (PurpleBuddy *) node;
    - gc = purple_account_get_connection(purple_buddy_get_account(buddy));
    -
    - f = yahoo_friend_find(gc, purple_buddy_get_name(buddy));
    - if (!f)
    - return;
    -
    - game = yahoo_friend_get_game(f);
    - if (!game)
    - return;
    -
    - t = game2 = g_strdup(strstr(game, "ante?room="));
    - while (*t && *t != '\t')
    - t++;
    - *t = 0;
    - g_snprintf(url, sizeof url, "http://games.yahoo.com/games/%s", game2);
    - purple_notify_uri(gc, url);
    - g_free(game2);
    -}
    -
    -char *yahoo_status_text(PurpleBuddy *b)
    -{
    - YahooFriend *f = NULL;
    - const char *msg;
    - char *msg2;
    - PurpleAccount *account;
    - PurpleConnection *gc;
    -
    - account = purple_buddy_get_account(b);
    - gc = purple_account_get_connection(account);
    - if (!gc || !purple_connection_get_protocol_data(gc))
    - return NULL;
    -
    - f = yahoo_friend_find(gc, purple_buddy_get_name(b));
    - if (!f)
    - return g_strdup(_("Not on server list"));
    -
    - switch (f->status) {
    - case YAHOO_STATUS_AVAILABLE:
    - return NULL;
    - case YAHOO_STATUS_IDLE:
    - if (f->idle == -1)
    - return g_strdup(yahoo_get_status_string(f->status));
    - return NULL;
    - case YAHOO_STATUS_CUSTOM:
    - if (!(msg = yahoo_friend_get_status_message(f)))
    - return NULL;
    - msg2 = g_markup_escape_text(msg, strlen(msg));
    - purple_util_chrreplace(msg2, '\n', ' ');
    - return msg2;
    -
    - default:
    - return g_strdup(yahoo_get_status_string(f->status));
    - }
    -}
    -
    -void yahoo_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full)
    -{
    - YahooFriend *f;
    - char *status = NULL;
    - const char *presence = NULL;
    - PurpleAccount *account;
    -
    - account = purple_buddy_get_account(b);
    - f = yahoo_friend_find(purple_account_get_connection(account), purple_buddy_get_name(b));
    - if (!f)
    - status = g_strdup_printf("\n%s", _("Not on server list"));
    - else {
    - switch (f->status) {
    - case YAHOO_STATUS_CUSTOM:
    - if (!yahoo_friend_get_status_message(f))
    - return;
    - status = g_strdup(yahoo_friend_get_status_message(f));
    - break;
    - case YAHOO_STATUS_OFFLINE:
    - break;
    - default:
    - status = g_strdup(yahoo_get_status_string(f->status));
    - break;
    - }
    -
    - switch (f->presence) {
    - case YAHOO_PRESENCE_ONLINE:
    - presence = _("Appear Online");
    - break;
    - case YAHOO_PRESENCE_PERM_OFFLINE:
    - presence = _("Appear Permanently Offline");
    - break;
    - case YAHOO_PRESENCE_DEFAULT:
    - break;
    - default:
    - purple_debug_error("yahoo", "Unknown presence in yahoo_tooltip_text\n");
    - break;
    - }
    - }
    -
    - if (status != NULL) {
    - purple_notify_user_info_add_pair_plaintext(user_info, _("Status"), status);
    - g_free(status);
    - }
    -
    - if (presence != NULL)
    - purple_notify_user_info_add_pair_plaintext(user_info, _("Presence"), presence);
    -
    - if (f && full) {
    - YahooPersonalDetails *ypd = &f->ypd;
    - int i;
    - struct {
    - char *id;
    - char *text;
    - char *value;
    - } yfields[] = {
    - {"hp", N_("Home Phone Number"), ypd->phone.home},
    - {"wp", N_("Work Phone Number"), ypd->phone.work},
    - {"mo", N_("Mobile Phone Number"), ypd->phone.mobile},
    - {NULL, NULL, NULL}
    - };
    - for (i = 0; yfields[i].id; i++) {
    - if (!yfields[i].value || !*yfields[i].value)
    - continue;
    - purple_notify_user_info_add_pair(user_info, _(yfields[i].text), yfields[i].value);
    - }
    - }
    -}
    -
    -static void yahoo_addbuddyfrommenu_cb(PurpleBlistNode *node, gpointer data)
    -{
    - PurpleBuddy *buddy;
    - PurpleConnection *gc;
    -
    - g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
    -
    - buddy = (PurpleBuddy *) node;
    - gc = purple_account_get_connection(purple_buddy_get_account(buddy));
    -
    - yahoo_add_buddy(gc, buddy, NULL);
    -}
    -
    -
    -static void yahoo_chat_goto_menu(PurpleBlistNode *node, gpointer data)
    -{
    - PurpleBuddy *buddy;
    - PurpleConnection *gc;
    -
    - g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
    -
    - buddy = (PurpleBuddy *) node;
    - gc = purple_account_get_connection(purple_buddy_get_account(buddy));
    -
    - yahoo_chat_goto(gc, purple_buddy_get_name(buddy));
    -}
    -
    -static GList *build_presence_submenu(YahooFriend *f, PurpleConnection *gc) {
    - GList *m = NULL;
    - PurpleMenuAction *act;
    - YahooData *yd = (YahooData *) gc->proto_data;
    -
    - if (yd->current_status == YAHOO_STATUS_INVISIBLE) {
    - if (f->presence != YAHOO_PRESENCE_ONLINE) {
    - act = purple_menu_action_new(_("Appear Online"),
    - PURPLE_CALLBACK(yahoo_presence_settings),
    - GINT_TO_POINTER(YAHOO_PRESENCE_ONLINE),
    - NULL);
    - m = g_list_append(m, act);
    - } else if (f->presence != YAHOO_PRESENCE_DEFAULT) {
    - act = purple_menu_action_new(_("Appear Offline"),
    - PURPLE_CALLBACK(yahoo_presence_settings),
    - GINT_TO_POINTER(YAHOO_PRESENCE_DEFAULT),
    - NULL);
    - m = g_list_append(m, act);
    - }
    - }
    -
    - if (f->presence == YAHOO_PRESENCE_PERM_OFFLINE) {
    - act = purple_menu_action_new(_("Don't Appear Permanently Offline"),
    - PURPLE_CALLBACK(yahoo_presence_settings),
    - GINT_TO_POINTER(YAHOO_PRESENCE_DEFAULT),
    - NULL);
    - m = g_list_append(m, act);
    - } else {
    - act = purple_menu_action_new(_("Appear Permanently Offline"),
    - PURPLE_CALLBACK(yahoo_presence_settings),
    - GINT_TO_POINTER(YAHOO_PRESENCE_PERM_OFFLINE),
    - NULL);
    - m = g_list_append(m, act);
    - }
    -
    - return m;
    -}
    -
    -static void yahoo_doodle_blist_node(PurpleBlistNode *node, gpointer data)
    -{
    - PurpleBuddy *b = (PurpleBuddy *)node;
    - PurpleAccount *account = purple_buddy_get_account(b);
    - PurpleConnection *gc = purple_account_get_connection(account);
    -
    - yahoo_doodle_initiate(gc, purple_buddy_get_name(b));
    -}
    -
    -static void
    -yahoo_userinfo_blist_node(PurpleBlistNode *node, gpointer data)
    -{
    - PurpleBuddy *b = (PurpleBuddy *)node;
    - PurpleAccount *account = purple_buddy_get_account(b);
    - PurpleConnection *gc = purple_account_get_connection(account);
    -
    - yahoo_set_userinfo_for_buddy(gc, b);
    -}
    -
    -static GList *yahoo_buddy_menu(PurpleBuddy *buddy)
    -{
    - GList *m = NULL;
    - PurpleMenuAction *act;
    -
    - PurpleConnection *gc = purple_account_get_connection(purple_buddy_get_account(buddy));
    - YahooData *yd = gc->proto_data;
    - static char buf2[1024];
    - YahooFriend *f;
    -
    - f = yahoo_friend_find(gc, purple_buddy_get_name(buddy));
    -
    - if (!f && !yd->wm) {
    - act = purple_menu_action_new(_("Add Buddy"),
    - PURPLE_CALLBACK(yahoo_addbuddyfrommenu_cb),
    - NULL, NULL);
    - m = g_list_append(m, act);
    -
    - return m;
    -
    - }
    -
    - if (f && f->status != YAHOO_STATUS_OFFLINE && f->fed == YAHOO_FEDERATION_NONE) {
    - if (!yd->wm) {
    - act = purple_menu_action_new(_("Join in Chat"),
    - PURPLE_CALLBACK(yahoo_chat_goto_menu),
    - NULL, NULL);
    - m = g_list_append(m, act);
    - }
    -
    - act = purple_menu_action_new(_("Initiate Conference"),
    - PURPLE_CALLBACK(yahoo_initiate_conference),
    - NULL, NULL);
    - m = g_list_append(m, act);
    -
    - if (yahoo_friend_get_game(f)) {
    - const char *game = yahoo_friend_get_game(f);
    - char *room;
    - char *t;
    -
    - if ((room = strstr(game, "&follow="))) {/* skip ahead to the url */
    - while (*room && *room != '\t') /* skip to the tab */
    - room++;
    - t = room++; /* room as now at the name */
    - while (*t != '\n')
    - t++; /* replace the \n with a space */
    - *t = ' ';
    - g_snprintf(buf2, sizeof buf2, "%s", room);
    -
    - act = purple_menu_action_new(buf2,
    - PURPLE_CALLBACK(yahoo_game),
    - NULL, NULL);
    - m = g_list_append(m, act);
    - }
    - }
    - }
    -
    - if (f) {
    - act = purple_menu_action_new(_("Presence Settings"), NULL, NULL,
    - build_presence_submenu(f, gc));
    - m = g_list_append(m, act);
    -
    - if (f->fed == YAHOO_FEDERATION_NONE) {
    - act = purple_menu_action_new(_("Start Doodling"),
    - PURPLE_CALLBACK(yahoo_doodle_blist_node),
    - NULL, NULL);
    - m = g_list_append(m, act);
    - }
    -
    - act = purple_menu_action_new(_("Set User Info..."),
    - PURPLE_CALLBACK(yahoo_userinfo_blist_node),
    - NULL, NULL);
    - m = g_list_append(m, act);
    - }
    -
    - return m;
    -}
    -
    -GList *yahoo_blist_node_menu(PurpleBlistNode *node)
    -{
    - if(PURPLE_BLIST_NODE_IS_BUDDY(node)) {
    - return yahoo_buddy_menu((PurpleBuddy *) node);
    - } else {
    - return NULL;
    - }
    -}
    -
    -static void yahoo_act_id(PurpleConnection *gc, PurpleRequestFields *fields)
    -{
    - YahooData *yd = gc->proto_data;
    - const char *name = yd->profiles[purple_request_fields_get_choice(fields, "id")];
    -
    - struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_IDACT, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash_str(pkt, 3, name);
    - yahoo_packet_send_and_free(pkt, yd);
    -
    - purple_connection_set_display_name(gc, name);
    -}
    -
    -static void
    -yahoo_get_inbox_token_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data,
    - const gchar *token, size_t len, const gchar *error_message)
    -{
    - PurpleConnection *gc = user_data;
    - gboolean set_cookie = FALSE;
    - gchar *url;
    - YahooData *yd = gc->proto_data;
    -
    - g_return_if_fail(PURPLE_CONNECTION_IS_VALID(gc));
    -
    - yd->url_datas = g_slist_remove(yd->url_datas, url_data);
    -
    - if (error_message != NULL)
    - purple_debug_error("yahoo", "Requesting mail login token failed: %s\n", error_message);
    - else if (len > 0 && token && *token) {
    - /* Should we not be hardcoding the rd url? */
    - url = g_strdup_printf(
    - "http://login.yahoo.com/config/reset_cookies_token?"
    - ".token=%s"
    - "&.done=http://us.rd.yahoo.com/messenger/client/%%3fhttp://mail.yahoo.com/",
    - token);
    - set_cookie = TRUE;
    - }
    -
    - if (!set_cookie) {
    - purple_debug_error("yahoo", "No mail login token; forwarding to login screen.\n");
    - url = g_strdup(yd->jp ? YAHOOJP_MAIL_URL : YAHOO_MAIL_URL);
    - }
    -
    - /* Open the mailbox with the parsed url data */
    - purple_notify_uri(gc, url);
    -
    - g_free(url);
    -}
    -
    -
    -static void yahoo_show_inbox(PurplePluginAction *action)
    -{
    - /* Setup a cookie that can be used by the browser */
    - /* XXX I have no idea how this will work with Yahoo! Japan. */
    -
    - PurpleConnection *gc = action->context;
    - YahooData *yd = gc->proto_data;
    -
    - PurpleUtilFetchUrlData *url_data;
    - const char* base_url = "http://login.yahoo.com";
    - /* use whole URL if using HTTP Proxy */
    - gboolean use_whole_url = yahoo_account_use_http_proxy(gc);
    - gchar *request = g_strdup_printf(
    - "POST %s/config/cookie_token HTTP/1.0\r\n"
    - "Cookie: T=%s; path=/; domain=.yahoo.com; Y=%s;\r\n"
    - "User-Agent: " YAHOO_CLIENT_USERAGENT "\r\n"
    - "Host: login.yahoo.com\r\n"
    - "Content-Length: 0\r\n\r\n",
    - use_whole_url ? base_url : "",
    - yd->cookie_t, yd->cookie_y);
    -
    - url_data = purple_util_fetch_url_request_len_with_account(
    - purple_connection_get_account(gc), base_url, use_whole_url,
    - YAHOO_CLIENT_USERAGENT, TRUE, request, FALSE, -1,
    - yahoo_get_inbox_token_cb, gc);
    -
    - g_free(request);
    -
    - if (url_data != NULL)
    - yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
    - else {
    - const char *yahoo_mail_url = (yd->jp ? YAHOOJP_MAIL_URL : YAHOO_MAIL_URL);
    - purple_debug_error("yahoo",
    - "Unable to request mail login token; forwarding to login screen.");
    - purple_notify_uri(gc, yahoo_mail_url);
    - }
    -}
    -
    -static void
    -yahoo_set_userinfo_fn(PurplePluginAction *action)
    -{
    - yahoo_set_userinfo(action->context);
    -}
    -
    -static void yahoo_show_act_id(PurplePluginAction *action)
    -{
    - PurpleRequestFields *fields;
    - PurpleRequestFieldGroup *group;
    - PurpleRequestField *field;
    - PurpleConnection *gc = (PurpleConnection *) action->context;
    - YahooData *yd = purple_connection_get_protocol_data(gc);
    - const char *name = purple_connection_get_display_name(gc);
    - int iter;
    -
    - fields = purple_request_fields_new();
    - group = purple_request_field_group_new(NULL);
    - purple_request_fields_add_group(fields, group);
    - field = purple_request_field_choice_new("id", _("Activate which ID?"), 0);
    - purple_request_field_group_add_field(group, field);
    -
    - for (iter = 0; yd->profiles[iter]; iter++) {
    - purple_request_field_choice_add(field, yd->profiles[iter]);
    - if (purple_strequal(yd->profiles[iter], name))
    - purple_request_field_choice_set_default_value(field, iter);
    - }
    -
    - purple_request_fields(gc, NULL, _("Select the ID you want to activate"), NULL,
    - fields,
    - _("OK"), G_CALLBACK(yahoo_act_id),
    - _("Cancel"), NULL,
    - purple_connection_get_account(gc), NULL, NULL,
    - gc);
    -}
    -
    -static void yahoo_show_chat_goto(PurplePluginAction *action)
    -{
    - PurpleConnection *gc = (PurpleConnection *) action->context;
    - purple_request_input(gc, NULL, _("Join whom in chat?"), NULL,
    - "", FALSE, FALSE, NULL,
    - _("OK"), G_CALLBACK(yahoo_chat_goto),
    - _("Cancel"), NULL,
    - purple_connection_get_account(gc), NULL, NULL,
    - gc);
    -}
    -
    -GList *yahoo_actions(PurplePlugin *plugin, gpointer context) {
    - GList *m = NULL;
    - PurplePluginAction *act;
    -
    - act = purple_plugin_action_new(_("Set User Info..."),
    - yahoo_set_userinfo_fn);
    - m = g_list_append(m, act);
    -
    - act = purple_plugin_action_new(_("Activate ID..."),
    - yahoo_show_act_id);
    - m = g_list_append(m, act);
    -
    - act = purple_plugin_action_new(_("Join User in Chat..."),
    - yahoo_show_chat_goto);
    - m = g_list_append(m, act);
    -
    - m = g_list_append(m, NULL);
    - act = purple_plugin_action_new(_("Open Inbox"),
    - yahoo_show_inbox);
    - m = g_list_append(m, act);
    -
    - return m;
    -}
    -
    -struct yahoo_sms_carrier_cb_data {
    - PurpleConnection *gc;
    - char *who;
    - char *what;
    -};
    -
    -static void yahoo_get_sms_carrier_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data,
    - const gchar *webdata, size_t len, const gchar *error_message)
    -{
    - struct yahoo_sms_carrier_cb_data *sms_cb_data = user_data;
    - PurpleConnection *gc = sms_cb_data->gc;
    - YahooData *yd = gc->proto_data;
    - char *status = NULL;
    - char *carrier = NULL;
    - PurpleAccount *account = purple_connection_get_account(gc);
    - PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms_cb_data->who, account);
    -
    - yd->url_datas = g_slist_remove(yd->url_datas, url_data);
    -
    - if (error_message != NULL) {
    - purple_conversation_write(conv, NULL, _("Can't send SMS. Unable to obtain mobile carrier."), PURPLE_MESSAGE_SYSTEM, time(NULL));
    -
    - g_free(sms_cb_data->who);
    - g_free(sms_cb_data->what);
    - g_free(sms_cb_data);
    - return ;
    - }
    - else if (len > 0 && webdata && *webdata) {
    - xmlnode *validate_data_root = xmlnode_from_str(webdata, -1);
    - xmlnode *validate_data_child = xmlnode_get_child(validate_data_root, "mobile_no");
    - const char *mobile_no = xmlnode_get_attrib(validate_data_child, "msisdn");
    -
    - validate_data_root = xmlnode_copy(validate_data_child);
    - validate_data_child = xmlnode_get_child(validate_data_root, "status");
    - status = xmlnode_get_data(validate_data_child);
    -
    - validate_data_child = xmlnode_get_child(validate_data_root, "carrier");
    - carrier = xmlnode_get_data(validate_data_child);
    -
    - purple_debug_info("yahoo", "SMS validate data: %s\n", webdata);
    -
    - if (status && g_str_equal(status, "Valid")) {
    - g_hash_table_insert(yd->sms_carrier,
    - g_strdup_printf("+%s", mobile_no), g_strdup(carrier));
    - yahoo_send_im(sms_cb_data->gc, sms_cb_data->who,
    - sms_cb_data->what, PURPLE_MESSAGE_SEND);
    - } else {
    - g_hash_table_insert(yd->sms_carrier,
    - g_strdup_printf("+%s", mobile_no), g_strdup("Unknown"));
    - purple_conversation_write(conv, NULL,
    - _("Can't send SMS. Unknown mobile carrier."),
    - PURPLE_MESSAGE_SYSTEM, time(NULL));
    - }
    -
    - xmlnode_free(validate_data_child);
    - xmlnode_free(validate_data_root);
    - g_free(sms_cb_data->who);
    - g_free(sms_cb_data->what);
    - g_free(sms_cb_data);
    - g_free(status);
    - g_free(carrier);
    - }
    -}
    -
    -static void yahoo_get_sms_carrier(PurpleConnection *gc, gpointer data)
    -{
    - YahooData *yd = gc->proto_data;
    - PurpleUtilFetchUrlData *url_data;
    - struct yahoo_sms_carrier_cb_data *sms_cb_data;
    - char *validate_request_str = NULL;
    - char *request = NULL;
    - gboolean use_whole_url = FALSE;
    - xmlnode *validate_request_root = NULL;
    - xmlnode *validate_request_child = NULL;
    -
    - if(!(sms_cb_data = data))
    - return;
    -
    - validate_request_root = xmlnode_new("validate");
    - xmlnode_set_attrib(validate_request_root, "intl", "us");
    - xmlnode_set_attrib(validate_request_root, "version", YAHOO_CLIENT_VERSION);
    - xmlnode_set_attrib(validate_request_root, "qos", "0");
    -
    - validate_request_child = xmlnode_new_child(validate_request_root, "mobile_no");
    - xmlnode_set_attrib(validate_request_child, "msisdn", sms_cb_data->who + 1);
    -
    - validate_request_str = xmlnode_to_str(validate_request_root, NULL);
    -
    - xmlnode_free(validate_request_child);
    - xmlnode_free(validate_request_root);
    -
    - request = g_strdup_printf(
    - "POST /mobileno?intl=us&version=%s HTTP/1.1\r\n"
    - "Cookie: T=%s; path=/; domain=.yahoo.com; Y=%s; path=/; domain=.yahoo.com;\r\n"
    - "User-Agent: " YAHOO_CLIENT_USERAGENT "\r\n"
    - "Host: validate.msg.yahoo.com\r\n"
    - "Content-Length: %" G_GSIZE_FORMAT "\r\n"
    - "Cache-Control: no-cache\r\n\r\n%s",
    - YAHOO_CLIENT_VERSION, yd->cookie_t, yd->cookie_y, strlen(validate_request_str), validate_request_str);
    -
    - /* use whole URL if using HTTP Proxy */
    - if ((gc->account->proxy_info) && (gc->account->proxy_info->type == PURPLE_PROXY_HTTP))
    - use_whole_url = TRUE;
    -
    - url_data = purple_util_fetch_url_request_len_with_account(
    - purple_connection_get_account(gc), YAHOO_SMS_CARRIER_URL, use_whole_url,
    - YAHOO_CLIENT_USERAGENT, TRUE, request, FALSE, -1,
    - yahoo_get_sms_carrier_cb, data);
    -
    - g_free(request);
    - g_free(validate_request_str);
    -
    - if (url_data)
    - yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
    - else {
    - PurpleAccount *account = purple_connection_get_account(gc);
    - PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms_cb_data->who, account);
    - purple_conversation_write(conv, NULL, _("Can't send SMS. Unable to obtain mobile carrier."), PURPLE_MESSAGE_SYSTEM, time(NULL));
    - g_free(sms_cb_data->who);
    - g_free(sms_cb_data->what);
    - g_free(sms_cb_data);
    - }
    -}
    -
    -int yahoo_send_im(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags)
    -{
    - YahooData *yd = gc->proto_data;
    - struct yahoo_packet *pkt = NULL;
    - char *msg = yahoo_html_to_codes(what);
    - char *msg2;
    - gboolean utf8 = TRUE;
    - PurpleWhiteboard *wb;
    - int ret = 1;
    - const char *fed_who;
    - gsize lenb = 0;
    - glong lenc = 0;
    - struct yahoo_p2p_data *p2p_data;
    - YahooFederation fed = YAHOO_FEDERATION_NONE;
    - msg2 = yahoo_string_encode(gc, msg, &utf8);
    -
    - if(msg2) {
    - lenb = strlen(msg2);
    - lenc = g_utf8_strlen(msg2, -1);
    -
    - if(lenb > YAHOO_MAX_MESSAGE_LENGTH_BYTES || lenc > YAHOO_MAX_MESSAGE_LENGTH_CHARS) {
    - purple_debug_info("yahoo", "Message too big. Length is %" G_GSIZE_FORMAT
    - " bytes, %ld characters. Max is %d bytes, %d chars."
    - " Message is '%s'.\n", lenb, lenc, YAHOO_MAX_MESSAGE_LENGTH_BYTES,
    - YAHOO_MAX_MESSAGE_LENGTH_CHARS, msg2);
    - g_free(msg);
    - g_free(msg2);
    - return -E2BIG;
    - }
    - }
    -
    - fed = yahoo_get_federation_from_name(who);
    -
    - if (who[0] == '+') {
    - /* we have an sms to be sent */
    - gchar *carrier = NULL;
    - const char *alias = NULL;
    - PurpleAccount *account = purple_connection_get_account(gc);
    - PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, account);
    -
    - carrier = g_hash_table_lookup(yd->sms_carrier, who);
    - if (!carrier) {
    - struct yahoo_sms_carrier_cb_data *sms_cb_data;
    - sms_cb_data = g_malloc(sizeof(struct yahoo_sms_carrier_cb_data));
    - sms_cb_data->gc = gc;
    - sms_cb_data->who = g_strdup(who);
    - sms_cb_data->what = g_strdup(what);
    -
    - purple_conversation_write(conv, NULL, _("Getting mobile carrier to send the SMS."), PURPLE_MESSAGE_SYSTEM, time(NULL));
    -
    - yahoo_get_sms_carrier(gc, sms_cb_data);
    -
    - g_free(msg);
    - g_free(msg2);
    - return ret;
    - }
    - else if( strcmp(carrier,"Unknown") == 0 ) {
    - purple_conversation_write(conv, NULL, _("Can't send SMS. Unknown mobile carrier."), PURPLE_MESSAGE_SYSTEM, time(NULL));
    -
    - g_free(msg);
    - g_free(msg2);
    - return -1;
    - }
    -
    - alias = purple_account_get_alias(account);
    - pkt = yahoo_packet_new(YAHOO_SERVICE_SMS_MSG, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash(pkt, "sssss",
    - 1, purple_connection_get_display_name(gc),
    - 69, alias,
    - 5, who + 1,
    - 68, carrier,
    - 14, msg2);
    - yahoo_packet_send_and_free(pkt, yd);
    -
    - g_free(msg);
    - g_free(msg2);
    -
    - return ret;
    - }
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE, YAHOO_STATUS_OFFLINE, yd->session_id);
    - fed_who = who;
    - switch (fed) {
    - case YAHOO_FEDERATION_MSN:
    - case YAHOO_FEDERATION_OCS:
    - case YAHOO_FEDERATION_IBM:
    - case YAHOO_FEDERATION_PBX:
    - fed_who += 4;
    - break;
    - case YAHOO_FEDERATION_NONE:
    - default:
    - break;
    - }
    - yahoo_packet_hash(pkt, "ss", 1, purple_connection_get_display_name(gc), 5, fed_who);
    - if (fed)
    - yahoo_packet_hash_int(pkt, 241, fed);
    -
    - if (utf8)
    - yahoo_packet_hash_str(pkt, 97, "1");
    - yahoo_packet_hash_str(pkt, 14, msg2);
    -
    - /*
    - * IMVironment.
    - *
    - * If this message is to a user who is also Doodling with the local user,
    - * format the chat packet with the correct IMV information (thanks Yahoo!)
    - *
    - * Otherwise attempt to use the same IMVironment as the remote user,
    - * just so that we don't inadvertantly reset their IMVironment back
    - * to nothing.
    - *
    - * If they have not set an IMVironment, then use the default.
    - */
    - wb = purple_whiteboard_get_session(gc->account, who);
    - if (wb)
    - yahoo_packet_hash_str(pkt, 63, DOODLE_IMV_KEY);
    - else
    - {
    - const char *imv;
    - imv = g_hash_table_lookup(yd->imvironments, who);
    - if (imv != NULL)
    - yahoo_packet_hash_str(pkt, 63, imv);
    - else
    - yahoo_packet_hash_str(pkt, 63, ";0");
    - }
    -
    - yahoo_packet_hash_str(pkt, 64, "0"); /* no idea */
    - yahoo_packet_hash_str(pkt, 1002, "1"); /* no idea, Yahoo 6 or later only it seems */
    - if (!yd->picture_url)
    - yahoo_packet_hash_str(pkt, 206, "0"); /* 0 = no picture, 2 = picture, maybe 1 = avatar? */
    - else
    - yahoo_packet_hash_str(pkt, 206, "2");
    -
    - /* We may need to not send any packets over 2000 bytes, but I'm not sure yet. */
    - if ((YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt)) <= 2000) {
    - /* if p2p link exists, send through it. To-do: key 15, time value to be sent in case of p2p */
    - if( (p2p_data = g_hash_table_lookup(yd->peers, who)) && !fed) {
    - yahoo_packet_hash_int(pkt, 11, p2p_data->session_id);
    - yahoo_p2p_write_pkt(p2p_data->source, pkt);
    - }
    - else {
    - yahoo_packet_send(pkt, yd);
    - if(!fed)
    - yahoo_send_p2p_pkt(gc, who, 0); /* send p2p packet, with val_13=0 */
    - }
    - }
    - else
    - ret = -E2BIG;
    -
    - yahoo_packet_free(pkt);
    -
    - g_free(msg);
    - g_free(msg2);
    -
    - return ret;
    -}
    -
    -unsigned int yahoo_send_typing(PurpleConnection *gc, const char *who, PurpleTypingState state)
    -{
    - YahooData *yd = gc->proto_data;
    - struct yahoo_p2p_data *p2p_data;
    - YahooFederation fed = YAHOO_FEDERATION_NONE;
    - struct yahoo_packet *pkt = NULL;
    -
    - fed = yahoo_get_federation_from_name(who);
    -
    - /* Don't do anything if sms is being typed */
    - if( strncmp(who, "+", 1) == 0 )
    - return 0;
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_TYPING, yd->session_id);
    -
    - /* check to see if p2p link exists, send through it */
    - if( (p2p_data = g_hash_table_lookup(yd->peers, who)) && !fed) {
    - yahoo_packet_hash(pkt, "sssssis", 49, "TYPING", 1, purple_connection_get_display_name(gc),
    - 14, " ", 13, state == PURPLE_TYPING ? "1" : "0",
    - 5, who, 11, p2p_data->session_id, 1002, "1"); /* To-do: key 15 to be sent in case of p2p */
    - yahoo_p2p_write_pkt(p2p_data->source, pkt);
    - yahoo_packet_free(pkt);
    - }
    - else { /* send through yahoo server */
    -
    - const char *fed_who = who;
    - switch (fed) {
    - case YAHOO_FEDERATION_MSN:
    - case YAHOO_FEDERATION_OCS:
    - case YAHOO_FEDERATION_IBM:
    - case YAHOO_FEDERATION_PBX:
    - fed_who += 4;
    - break;
    - case YAHOO_FEDERATION_NONE:
    - default:
    - break;
    - }
    -
    - yahoo_packet_hash(pkt, "ssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc),
    - 14, " ", 13, state == PURPLE_TYPING ? "1" : "0",
    - 5, fed_who, 1002, "1");
    - if (fed)
    - yahoo_packet_hash_int(pkt, 241, fed);
    - yahoo_packet_send_and_free(pkt, yd);
    - }
    -
    - return 0;
    -}
    -
    -static void yahoo_session_presence_remove(gpointer key, gpointer value, gpointer data)
    -{
    - YahooFriend *f = value;
    - if (f && f->presence == YAHOO_PRESENCE_ONLINE)
    - f->presence = YAHOO_PRESENCE_DEFAULT;
    -}
    -
    -void yahoo_set_status(PurpleAccount *account, PurpleStatus *status)
    -{
    - PurpleConnection *gc;
    - PurplePresence *presence;
    - YahooData *yd;
    - struct yahoo_packet *pkt;
    - int old_status;
    - const char *msg = NULL;
    - char *tmp = NULL;
    - char *conv_msg = NULL;
    - gboolean utf8 = TRUE;
    -
    - if (!purple_status_is_active(status))
    - return;
    -
    - gc = purple_account_get_connection(account);
    - presence = purple_status_get_presence(status);
    - yd = (YahooData *)gc->proto_data;
    - old_status = yd->current_status;
    -
    - yd->current_status = get_yahoo_status_from_purple_status(status);
    -
    - if (yd->current_status == YAHOO_STATUS_CUSTOM)
    - {
    - msg = purple_status_get_attr_string(status, "message");
    -
    - if (purple_status_is_available(status)) {
    - tmp = yahoo_string_encode(gc, msg, &utf8);
    - conv_msg = purple_markup_strip_html(tmp);
    - g_free(tmp);
    - } else {
    - if ((msg == NULL) || (*msg == '\0'))
    - msg = _("Away");
    - tmp = yahoo_string_encode(gc, msg, &utf8);
    - conv_msg = purple_markup_strip_html(tmp);
    - g_free(tmp);
    - }
    - }
    -
    - if (yd->current_status == YAHOO_STATUS_INVISIBLE) {
    - pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBLE_TOGGLE, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash_str(pkt, 13, "2");
    - yahoo_packet_send_and_free(pkt, yd);
    -
    - return;
    - }
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash_int(pkt, 10, yd->current_status);
    -
    - if (yd->current_status == YAHOO_STATUS_CUSTOM) {
    - yahoo_packet_hash_str(pkt, 97, utf8 ? "1" : 0);
    - yahoo_packet_hash_str(pkt, 19, conv_msg);
    - } else {
    - yahoo_packet_hash_str(pkt, 19, "");
    - }
    -
    - g_free(conv_msg);
    -
    - if (purple_presence_is_idle(presence))
    - yahoo_packet_hash_str(pkt, 47, "2");
    - else {
    - if (!purple_status_is_available(status))
    - yahoo_packet_hash_str(pkt, 47, "1");
    - else
    - yahoo_packet_hash_str(pkt, 47, "0");
    - }
    -
    - yahoo_packet_send_and_free(pkt, yd);
    -
    - if (old_status == YAHOO_STATUS_INVISIBLE) {
    - pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBLE_TOGGLE, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash_str(pkt, 13, "1");
    - yahoo_packet_send_and_free(pkt, yd);
    -
    - /* Any per-session presence settings are removed */
    - g_hash_table_foreach(yd->friends, yahoo_session_presence_remove, NULL);
    -
    - }
    -}
    -
    -void yahoo_set_idle(PurpleConnection *gc, int idle)
    -{
    - YahooData *yd = gc->proto_data;
    - struct yahoo_packet *pkt = NULL;
    - char *msg = NULL, *msg2 = NULL;
    - PurpleStatus *status = NULL;
    - gboolean invisible = FALSE;
    -
    - if (idle && yd->current_status != YAHOO_STATUS_CUSTOM)
    - yd->current_status = YAHOO_STATUS_IDLE;
    - else if (!idle && yd->current_status == YAHOO_STATUS_IDLE) {
    - status = purple_presence_get_active_status(purple_account_get_presence(purple_connection_get_account(gc)));
    - yd->current_status = get_yahoo_status_from_purple_status(status);
    - }
    -
    - invisible = (yd->current_status == YAHOO_STATUS_INVISIBLE);
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE, YAHOO_STATUS_AVAILABLE, yd->session_id);
    -
    - if (!idle && invisible)
    - yahoo_packet_hash_int(pkt, 10, YAHOO_STATUS_AVAILABLE);
    - else
    - yahoo_packet_hash_int(pkt, 10, yd->current_status);
    -
    - if (yd->current_status == YAHOO_STATUS_CUSTOM) {
    - const char *tmp;
    - if (status == NULL)
    - status = purple_presence_get_active_status(purple_account_get_presence(purple_connection_get_account(gc)));
    - tmp = purple_status_get_attr_string(status, "message");
    - if (tmp != NULL) {
    - gboolean utf8 = TRUE;
    - msg = yahoo_string_encode(gc, tmp, &utf8);
    - msg2 = purple_markup_strip_html(msg);
    - yahoo_packet_hash_str(pkt, 97, utf8 ? "1" : 0);
    - yahoo_packet_hash_str(pkt, 19, msg2);
    - } else {
    - /* get_yahoo_status_from_purple_status() returns YAHOO_STATUS_CUSTOM for
    - * the generic away state (YAHOO_STATUS_TYPE_AWAY) with no message */
    - yahoo_packet_hash_str(pkt, 19, _("Away"));
    - }
    - } else {
    - yahoo_packet_hash_str(pkt, 19, "");
    - }
    -
    - if (idle)
    - yahoo_packet_hash_str(pkt, 47, "2");
    - else if (yd->current_status == YAHOO_STATUS_CUSTOM &&
    - !purple_status_is_available(status))
    - /* We are still unavailable in this case.
    - * Make sure Yahoo knows that */
    - yahoo_packet_hash_str(pkt, 47, "1");
    -
    - yahoo_packet_send_and_free(pkt, yd);
    -
    - g_free(msg);
    - g_free(msg2);
    -}
    -
    -GList *yahoo_status_types(PurpleAccount *account)
    -{
    - PurpleStatusType *type;
    - GList *types = NULL;
    -
    - type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE, YAHOO_STATUS_TYPE_AVAILABLE,
    - NULL, TRUE, TRUE, FALSE,
    - "message", _("Message"),
    - purple_value_new(PURPLE_TYPE_STRING), NULL);
    - types = g_list_append(types, type);
    -
    - type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_AWAY,
    - NULL, TRUE, TRUE, FALSE,
    - "message", _("Message"),
    - purple_value_new(PURPLE_TYPE_STRING), NULL);
    - types = g_list_append(types, type);
    -
    - type = purple_status_type_new(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_BRB, _("Be Right Back"), TRUE);
    - types = g_list_append(types, type);
    -
    - type = purple_status_type_new_with_attrs(PURPLE_STATUS_UNAVAILABLE, YAHOO_STATUS_TYPE_BUSY,
    - _("Busy"), TRUE, TRUE, FALSE,
    - "message", _("Message"),
    - purple_value_new(PURPLE_TYPE_STRING), NULL);
    - types = g_list_append(types, type);
    -
    - type = purple_status_type_new(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_NOTATHOME, _("Not at Home"), TRUE);
    - types = g_list_append(types, type);
    -
    - type = purple_status_type_new(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_NOTATDESK, _("Not at Desk"), TRUE);
    - types = g_list_append(types, type);
    -
    - type = purple_status_type_new(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_NOTINOFFICE, _("Not in Office"), TRUE);
    - types = g_list_append(types, type);
    -
    - type = purple_status_type_new(PURPLE_STATUS_UNAVAILABLE, YAHOO_STATUS_TYPE_ONPHONE, _("On the Phone"), TRUE);
    - types = g_list_append(types, type);
    -
    - type = purple_status_type_new(PURPLE_STATUS_EXTENDED_AWAY, YAHOO_STATUS_TYPE_ONVACATION, _("On Vacation"), TRUE);
    - types = g_list_append(types, type);
    -
    - type = purple_status_type_new(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_OUTTOLUNCH, _("Out to Lunch"), TRUE);
    - types = g_list_append(types, type);
    -
    - type = purple_status_type_new(PURPLE_STATUS_AWAY, YAHOO_STATUS_TYPE_STEPPEDOUT, _("Stepped Out"), TRUE);
    - types = g_list_append(types, type);
    -
    -
    - type = purple_status_type_new(PURPLE_STATUS_INVISIBLE, YAHOO_STATUS_TYPE_INVISIBLE, NULL, TRUE);
    - types = g_list_append(types, type);
    -
    - type = purple_status_type_new(PURPLE_STATUS_OFFLINE, YAHOO_STATUS_TYPE_OFFLINE, NULL, TRUE);
    - types = g_list_append(types, type);
    -
    - type = purple_status_type_new_full(PURPLE_STATUS_MOBILE, YAHOO_STATUS_TYPE_MOBILE, NULL, FALSE, FALSE, TRUE);
    - types = g_list_append(types, type);
    -
    - return types;
    -}
    -
    -void yahoo_keepalive(PurpleConnection *gc)
    -{
    - struct yahoo_packet *pkt;
    - YahooData *yd = gc->proto_data;
    - time_t now = time(NULL);
    -
    - /* We're only allowed to send a ping once an hour or the servers will boot us */
    - if ((now - yd->last_ping) >= PING_TIMEOUT) {
    - yd->last_ping = now;
    -
    - /* The native client will only send PING or CHATPING */
    - if (yd->chat_online) {
    - if (yd->wm) {
    - ycht_chat_send_keepalive(yd->ycht);
    - } else {
    - pkt = yahoo_packet_new(YAHOO_SERVICE_CHATPING, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash_str(pkt, 109, purple_connection_get_display_name(gc));
    - yahoo_packet_send_and_free(pkt, yd);
    - }
    - } else {
    - pkt = yahoo_packet_new(YAHOO_SERVICE_PING, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_send_and_free(pkt, yd);
    - }
    - }
    -
    - if ((now - yd->last_keepalive) >= KEEPALIVE_TIMEOUT) {
    - yd->last_keepalive = now;
    - pkt = yahoo_packet_new(YAHOO_SERVICE_KEEPALIVE, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash_str(pkt, 0, purple_connection_get_display_name(gc));
    - yahoo_packet_send_and_free(pkt, yd);
    - }
    -
    -}
    -
    -void yahoo_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *g)
    -{
    - YahooData *yd = (YahooData *)gc->proto_data;
    - struct yahoo_packet *pkt;
    - const char *group = NULL;
    - char *group2;
    - const char *bname;
    - const char *fed_bname;
    - YahooFederation fed = YAHOO_FEDERATION_NONE;
    -
    - if (!yd->logged_in)
    - return;
    -
    - fed_bname = bname = purple_buddy_get_name(buddy);
    - if (!purple_privacy_check(purple_connection_get_account(gc), bname))
    - return;
    -
    - fed = yahoo_get_federation_from_name(bname);
    - if (fed != YAHOO_FEDERATION_NONE)
    - fed_bname += 4;
    -
    - g = purple_buddy_get_group(buddy);
    - if (g)
    - group = purple_group_get_name(g);
    - else
    - group = "Buddies";
    -
    - group2 = yahoo_string_encode(gc, group, NULL);
    - pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - if (fed) {
    - yahoo_packet_hash(pkt, "sssssssisss",
    - 14, "",
    - 65, group2,
    - 97, "1",
    - 1, purple_connection_get_display_name(gc),
    - 302, "319",
    - 300, "319",
    - 7, fed_bname,
    - 241, fed,
    - 334, "0",
    - 301, "319",
    - 303, "319"
    - );
    - }
    - else {
    - yahoo_packet_hash(pkt, "ssssssssss",
    - 14, "",
    - 65, group2,
    - 97, "1",
    - 1, purple_connection_get_display_name(gc),
    - 302, "319",
    - 300, "319",
    - 7, fed_bname,
    - 334, "0",
    - 301, "319",
    - 303, "319"
    - );
    - }
    -
    - yahoo_packet_send_and_free(pkt, yd);
    - g_free(group2);
    -}
    -
    -void yahoo_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
    -{
    - YahooData *yd = (YahooData *)gc->proto_data;
    - struct yahoo_packet *pkt;
    - GSList *buddies, *l;
    - PurpleGroup *g;
    - gboolean remove = TRUE;
    - char *cg;
    - const char *bname, *gname;
    - YahooFriend *f = NULL;
    - YahooFederation fed = YAHOO_FEDERATION_NONE;
    -
    - bname = purple_buddy_get_name(buddy);
    - f = yahoo_friend_find(gc, bname);
    - if (!f)
    - return;
    - fed = f->fed;
    -
    - gname = purple_group_get_name(group);
    - buddies = purple_find_buddies(purple_connection_get_account(gc), bname);
    - for (l = buddies; l; l = l->next) {
    - g = purple_buddy_get_group(l->data);
    - if (purple_utf8_strcasecmp(gname, purple_group_get_name(g))) {
    - remove = FALSE;
    - break;
    - }
    - }
    -
    - g_slist_free(buddies);
    -
    - if (remove) {
    - g_hash_table_remove(yd->friends, bname);
    - f = NULL; /* f no longer valid - Just making it clear */
    - }
    -
    - cg = yahoo_string_encode(gc, gname, NULL);
    - pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
    -
    - switch (fed) {
    - case YAHOO_FEDERATION_MSN:
    - case YAHOO_FEDERATION_OCS:
    - case YAHOO_FEDERATION_IBM:
    - bname += 4;
    - break;
    - case YAHOO_FEDERATION_NONE:
    - default:
    - break;
    - }
    -
    - yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc),
    - 7, bname, 65, cg);
    - if (fed)
    - yahoo_packet_hash_int(pkt, 241, fed);
    - yahoo_packet_send_and_free(pkt, yd);
    - g_free(cg);
    -}
    -
    -void yahoo_add_deny(PurpleConnection *gc, const char *who) {
    - YahooData *yd = (YahooData *)gc->proto_data;
    - struct yahoo_packet *pkt;
    - YahooFederation fed = YAHOO_FEDERATION_NONE;
    -
    - if (!yd->logged_in)
    - return;
    -
    - if (!who || who[0] == '\0')
    - return;
    -
    - fed = yahoo_get_federation_from_name(who);
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT, YAHOO_STATUS_AVAILABLE, yd->session_id);
    -
    - if(fed)
    - yahoo_packet_hash(pkt, "ssis", 1, purple_connection_get_display_name(gc), 7, who+4, 241, fed, 13, "1");
    - else
    - yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc), 7, who, 13, "1");
    -
    - yahoo_packet_send_and_free(pkt, yd);
    -}
    -
    -void yahoo_rem_deny(PurpleConnection *gc, const char *who) {
    - YahooData *yd = (YahooData *)gc->proto_data;
    - struct yahoo_packet *pkt;
    - YahooFederation fed = YAHOO_FEDERATION_NONE;
    -
    - if (!yd->logged_in)
    - return;
    -
    - if (!who || who[0] == '\0')
    - return;
    - fed = yahoo_get_federation_from_name(who);
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT, YAHOO_STATUS_AVAILABLE, yd->session_id);
    -
    - if(fed)
    - yahoo_packet_hash(pkt, "ssis", 1, purple_connection_get_display_name(gc), 7, who+4, 241, fed, 13, "2");
    - else
    - yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc), 7, who, 13, "2");
    -
    - yahoo_packet_send_and_free(pkt, yd);
    -}
    -
    -void yahoo_set_permit_deny(PurpleConnection *gc)
    -{
    - PurpleAccount *account;
    - GSList *deny;
    -
    - account = purple_connection_get_account(gc);
    -
    - switch (account->perm_deny)
    - {
    - case PURPLE_PRIVACY_ALLOW_ALL:
    - for (deny = account->deny; deny; deny = deny->next)
    - yahoo_rem_deny(gc, deny->data);
    - break;
    -
    - case PURPLE_PRIVACY_ALLOW_BUDDYLIST:
    - case PURPLE_PRIVACY_ALLOW_USERS:
    - case PURPLE_PRIVACY_DENY_USERS:
    - case PURPLE_PRIVACY_DENY_ALL:
    - for (deny = account->deny; deny; deny = deny->next)
    - yahoo_add_deny(gc, deny->data);
    - break;
    - }
    -}
    -
    -void yahoo_change_buddys_group(PurpleConnection *gc, const char *who,
    - const char *old_group, const char *new_group)
    -{
    - YahooData *yd = gc->proto_data;
    - struct yahoo_packet *pkt;
    - char *gpn, *gpo;
    - YahooFriend *f = yahoo_friend_find(gc, who);
    - const char *temp = NULL;
    -
    - /* Step 0: If they aren't on the server list anyway,
    - * don't bother letting the server know.
    - */
    - if (!f)
    - return;
    -
    - if(f->fed) {
    - temp = who+4;
    - } else
    - temp = who;
    -
    - /* If old and new are the same, we would probably
    - * end up deleting the buddy, which would be bad.
    - * This might happen because of the charset conversation.
    - */
    - gpn = yahoo_string_encode(gc, new_group, NULL);
    - gpo = yahoo_string_encode(gc, old_group, NULL);
    - if (!strcmp(gpn, gpo)) {
    - g_free(gpn);
    - g_free(gpo);
    - return;
    - }
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_CHGRP_15, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - if(f->fed)
    - yahoo_packet_hash(pkt, "ssssissss", 1, purple_connection_get_display_name(gc),
    - 302, "240", 300, "240", 7, temp, 241, f->fed, 224, gpo, 264, gpn, 301,
    - "240", 303, "240");
    - else
    - yahoo_packet_hash(pkt, "ssssssss", 1, purple_connection_get_display_name(gc),
    - 302, "240", 300, "240", 7, temp, 224, gpo, 264, gpn, 301,
    - "240", 303, "240");
    - yahoo_packet_send_and_free(pkt, yd);
    -
    - g_free(gpn);
    - g_free(gpo);
    -}
    -
    -void yahoo_rename_group(PurpleConnection *gc, const char *old_name,
    - PurpleGroup *group, GList *moved_buddies)
    -{
    - YahooData *yd = gc->proto_data;
    - struct yahoo_packet *pkt;
    - char *gpn, *gpo;
    -
    - gpn = yahoo_string_encode(gc, purple_group_get_name(group), NULL);
    - gpo = yahoo_string_encode(gc, old_name, NULL);
    - if (!strcmp(gpn, gpo)) {
    - g_free(gpn);
    - g_free(gpo);
    - return;
    - }
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_GROUPRENAME, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc),
    - 65, gpo, 67, gpn);
    - yahoo_packet_send_and_free(pkt, yd);
    - g_free(gpn);
    - g_free(gpo);
    -}
    -
    -/********************************* Commands **********************************/
    -
    -PurpleCmdRet
    -yahoopurple_cmd_buzz(PurpleConversation *c, const gchar *cmd, gchar **args, gchar **error, void *data) {
    - PurpleAccount *account = purple_conversation_get_account(c);
    -
    - if (*args && args[0])
    - return PURPLE_CMD_RET_FAILED;
    -
    - purple_prpl_send_attention(account->gc, c->name, YAHOO_BUZZ);
    -
    - return PURPLE_CMD_RET_OK;
    -}
    -
    -PurpleCmdRet
    -yahoopurple_cmd_chat_join(PurpleConversation *conv, const char *cmd,
    - char **args, char **error, void *data)
    -{
    - GHashTable *comp;
    - PurpleConnection *gc;
    -
    - if (!args || !args[0])
    - return PURPLE_CMD_RET_FAILED;
    -
    - gc = purple_conversation_get_gc(conv);
    - purple_debug_info("yahoo", "Trying to join %s \n", args[0]);
    -
    - comp = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
    - g_hash_table_replace(comp, g_strdup("room"), g_ascii_strdown(args[0], -1));
    - g_hash_table_replace(comp, g_strdup("type"), g_strdup("Chat"));
    -
    - yahoo_c_join(gc, comp);
    -
    - g_hash_table_destroy(comp);
    - return PURPLE_CMD_RET_OK;
    -}
    -
    -PurpleCmdRet
    -yahoopurple_cmd_chat_list(PurpleConversation *conv, const char *cmd,
    - char **args, char **error, void *data)
    -{
    - PurpleAccount *account = purple_conversation_get_account(conv);
    - if (*args && args[0])
    - return PURPLE_CMD_RET_FAILED;
    - purple_roomlist_show_with_account(account);
    - return PURPLE_CMD_RET_OK;
    -}
    -
    -gboolean yahoo_offline_message(const PurpleBuddy *buddy)
    -{
    - return TRUE;
    -}
    -
    -gboolean yahoo_send_attention(PurpleConnection *gc, const char *username, guint type)
    -{
    - PurpleConversation *c;
    -
    - c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
    - username, gc->account);
    -
    - g_return_val_if_fail(c != NULL, FALSE);
    -
    - purple_debug_info("yahoo", "Sending <ding> on account %s to buddy %s.\n",
    - username, c->name);
    - purple_conv_im_send_with_flags(PURPLE_CONV_IM(c), "<ding>", PURPLE_MESSAGE_INVISIBLE);
    -
    - return TRUE;
    -}
    -
    -GList *yahoo_attention_types(PurpleAccount *account)
    -{
    - static GList *list = NULL;
    -
    - if (!list) {
    - /* Yahoo only supports one attention command: the 'buzz'. */
    - /* This is index number YAHOO_BUZZ. */
    - list = g_list_append(list, purple_attention_type_new("Buzz", _("Buzz"),
    - _("%s has buzzed you!"), _("Buzzing %s...")));
    - }
    -
    - return list;
    -}
    -
    --- a/libpurple/protocols/yahoo/libymsg.h Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,402 +0,0 @@
    -/**
    - * @file libymsg.h The Yahoo! and Yahoo! JAPAN Protocol Plugins
    - *
    - * purple
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * This program is free software; you can redistribute it and/or modify
    - * it under the terms of the GNU General Public License as published by
    - * the Free Software Foundation; either version 2 of the License, or
    - * (at your option) any later version.
    - *
    - * This program is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    - * GNU General Public License for more details.
    - *
    - * You should have received a copy of the GNU General Public License
    - * along with this program; if not, write to the Free Software
    - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    - */
    -
    -#ifndef _LIBYMSG_H_
    -#define _LIBYMSG_H_
    -
    -#include "circbuffer.h"
    -#include "cmds.h"
    -#include "prpl.h"
    -#include "network.h"
    -
    -#define YAHOO_PAGER_HOST_REQ_URL "http://vcs2.msg.yahoo.com/capacity"
    -#define YAHOO_PAGER_HOST_FALLBACK "scsa.msg.yahoo.com"
    -#define YAHOO_PAGER_PORT 5050
    -#define YAHOO_PAGER_PORT_P2P 5101
    -#define YAHOO_LOGIN_URL "https://login.yahoo.com/config/pwtoken_login?src=ymsgr&ts=&token=%s"
    -#define YAHOO_TOKEN_URL "https://login.yahoo.com/config/pwtoken_get?src=ymsgr&ts=&login=%s&passwd=%s&chal=%s"
    -#define YAHOO_P2P_KEEPALIVE_SECS 300
    -#define YAHOO_P2P_SERVER_TIMEOUT 10
    -#define YAHOO_PROFILE_URL "http://profiles.yahoo.com/"
    -#define YAHOO_MAIL_URL "http://rd.yahoo.com/messenger/client/?http://mail.yahoo.com/"
    -#define YAHOO_XFER_HOST "filetransfer.msg.yahoo.com"
    -#define YAHOO_XFER_PORT 80
    -#define YAHOO_XFER_RELAY_HOST "relay.msg.yahoo.com"
    -#define YAHOO_XFER_RELAY_PORT 80
    -#define YAHOO_ROOMLIST_URL "http://insider.msg.yahoo.com/ycontent/"
    -#define YAHOO_ROOMLIST_LOCALE "us"
    -
    -/* Yahoo! JAPAN stuff */
    -#define YAHOOJP_PAGER_HOST_REQ_URL "http://cs1.yahoo.co.jp/capacity"
    -#define YAHOOJP_TOKEN_URL "https://login.yahoo.co.jp/config/pwtoken_get?src=ymsgr&ts=&login=%s&passwd=%s&chal=%s"
    -#define YAHOOJP_LOGIN_URL "https://login.yahoo.co.jp/config/pwtoken_login?src=ymsgr&ts=&token=%s"
    -#define YAHOOJP_PROFILE_URL "http://profiles.yahoo.co.jp/"
    -#define YAHOOJP_MAIL_URL "http://mail.yahoo.co.jp/"
    -#define YAHOOJP_XFER_HOST "filetransfer.msg.yahoo.co.jp"
    -#define YAHOOJP_WEBCAM_HOST "wc.yahoo.co.jp"
    -/* not sure, must test: */
    -#define YAHOOJP_XFER_RELAY_HOST "relay.msg.yahoo.co.jp"
    -#define YAHOOJP_XFER_RELAY_PORT 80
    -#define YAHOOJP_ROOMLIST_URL "http://insider.msg.yahoo.co.jp/ycontent/"
    -#define YAHOOJP_ROOMLIST_LOCALE "ja"
    -
    -#define YAHOO_AUDIBLE_URL "http://l.yimg.com/pu/dl/aud"
    -
    -#define WEBMESSENGER_URL "http://login.yahoo.com/config/login?.src=pg"
    -
    -#define YAHOO_SMS_CARRIER_URL "http://validate.msg.yahoo.com"
    -
    -#define YAHOO_USERINFO_URL "http://address.yahoo.com/yab/us?v=XM&sync=1&tags=short&useutf8=1&noclear=1&legenc=codepage-1252"
    -#define YAHOOJP_USERINFO_URL "http://address.yahoo.co.jp/yab/jp?v=XM&sync=1&tags=short&useutf8=1&noclear=1&legenc=codepage-1252"
    -
    -#define YAHOO_PICURL_SETTING "picture_url"
    -#define YAHOO_PICCKSUM_SETTING "picture_checksum"
    -#define YAHOO_PICEXPIRE_SETTING "picture_expire"
    -
    -#define YAHOO_STATUS_TYPE_OFFLINE "offline"
    -#define YAHOO_STATUS_TYPE_AVAILABLE "available"
    -#define YAHOO_STATUS_TYPE_BRB "brb"
    -#define YAHOO_STATUS_TYPE_BUSY "busy"
    -#define YAHOO_STATUS_TYPE_NOTATHOME "notathome"
    -#define YAHOO_STATUS_TYPE_NOTATDESK "notatdesk"
    -#define YAHOO_STATUS_TYPE_NOTINOFFICE "notinoffice"
    -#define YAHOO_STATUS_TYPE_ONPHONE "onphone"
    -#define YAHOO_STATUS_TYPE_ONVACATION "onvacation"
    -#define YAHOO_STATUS_TYPE_OUTTOLUNCH "outtolunch"
    -#define YAHOO_STATUS_TYPE_STEPPEDOUT "steppedout"
    -#define YAHOO_STATUS_TYPE_AWAY "away"
    -#define YAHOO_STATUS_TYPE_INVISIBLE "invisible"
    -#define YAHOO_STATUS_TYPE_MOBILE "mobile"
    -
    -#define YAHOO_CLIENT_VERSION_ID "4194239"
    -#define YAHOO_CLIENT_VERSION "9.0.0.2162"
    -
    -#define YAHOOJP_CLIENT_VERSION_ID "4186047"
    -#define YAHOOJP_CLIENT_VERSION "9.0.0.1727"
    -
    -#define YAHOO_CLIENT_USERAGENT "Mozilla/5.0"
    -#define YAHOO_CLIENT_USERAGENT_ALIAS "Mozilla/4.0 (compatible; MSIE 5.5)"
    -
    -/* Index into attention types list. */
    -#define YAHOO_BUZZ 0
    -
    -typedef enum {
    - YAHOO_PKT_TYPE_SERVER = 0,
    - YAHOO_PKT_TYPE_P2P
    -} yahoo_pkt_type;
    -
    -typedef enum {
    - YAHOO_P2P_WE_ARE_CLIENT =0,
    - YAHOO_P2P_WE_ARE_SERVER
    -} yahoo_p2p_connection_type;
    -
    -enum yahoo_status {
    - YAHOO_STATUS_AVAILABLE = 0,
    - YAHOO_STATUS_BRB,
    - YAHOO_STATUS_BUSY,
    - YAHOO_STATUS_NOTATHOME,
    - YAHOO_STATUS_NOTATDESK,
    - YAHOO_STATUS_NOTINOFFICE,
    - YAHOO_STATUS_ONPHONE,
    - YAHOO_STATUS_ONVACATION,
    - YAHOO_STATUS_OUTTOLUNCH,
    - YAHOO_STATUS_STEPPEDOUT,
    - YAHOO_STATUS_P2P = 11,
    - YAHOO_STATUS_INVISIBLE = 12,
    - YAHOO_STATUS_CUSTOM = 99,
    - YAHOO_STATUS_IDLE = 999,
    - YAHOO_STATUS_WEBLOGIN = 0x5a55aa55,
    - YAHOO_STATUS_OFFLINE = 0x5a55aa56, /* don't ask */
    - YAHOO_STATUS_TYPING = 0x16,
    - YAHOO_STATUS_DISCONNECTED = -1 /* 0xffffffff; in ymsg 15. doesnt mean the normal sense of 'disconnected' */
    -};
    -
    -/*
    - * Yahoo federated networks. Key 241 in ymsg.
    - * If it doesn't exist, it is on Yahoo's netowrk.
    - * It if does exist, send to another IM network.
    - */
    -
    -typedef enum {
    - YAHOO_FEDERATION_NONE = 0, /* No federation - Yahoo! network */
    - YAHOO_FEDERATION_OCS = 1, /* LCS or OCS private networks */
    - YAHOO_FEDERATION_MSN = 2, /* MSN or Windows Live network */
    - YAHOO_FEDERATION_IBM = 9, /* IBM/Sametime network */
    - YAHOO_FEDERATION_PBX = 100 /* Yahoo! Pingbox service */
    -} YahooFederation;
    -
    -
    -struct yahoo_buddy_icon_upload_data {
    - PurpleConnection *gc;
    - GString *str;
    - char *filename;
    - int pos;
    - int fd;
    - guint watcher;
    -};
    -
    -struct yahoo_p2p_data {
    - PurpleConnection *gc;
    - char *host_ip;
    - char *host_username;
    - int val_13;
    - guint input_event;
    - gint source;
    - int session_id;
    - yahoo_p2p_connection_type connection_type;
    -};
    -
    -struct _YchtConn;
    -
    -typedef struct _YahooPersonalDetails {
    - char *id;
    -
    - struct {
    - char *first;
    - char *last;
    - char *middle;
    - char *nick;
    - } names;
    -
    - struct {
    - char *work;
    - char *home;
    - char *mobile;
    - } phone;
    -} YahooPersonalDetails;
    -
    -typedef struct {
    - PurpleConnection *gc;
    - int fd;
    - guchar *rxqueue;
    - int rxlen;
    - PurpleCircBuffer *txbuf;
    - guint txhandler;
    - GHashTable *friends;
    -
    - char **profiles; /* Multiple profiles can be associated with an account */
    - YahooPersonalDetails ypd;
    -
    - /**
    - * This is used to keep track of the IMVironment chosen
    - * by people you talk to. We don't do very much with
    - * this right now... but at least now if the remote user
    - * selects an IMVironment we won't reset it back to the
    - * default of nothing.
    - */
    - GHashTable *imvironments;
    -
    - int current_status;
    - gboolean logged_in;
    - GString *tmp_serv_blist, *tmp_serv_ilist, *tmp_serv_plist;
    - GSList *confs;
    - unsigned int conf_id; /* just a counter */
    - gboolean chat_online;
    - gboolean in_chat;
    - char *chat_name;
    - char *pending_chat_room;
    - char *pending_chat_id;
    - char *pending_chat_topic;
    - char *pending_chat_goto;
    - char *auth;
    - gsize auth_written;
    - char *cookie_y;
    - char *cookie_t;
    - char *cookie_b;
    - int session_id;
    - gboolean jp;
    - gboolean wm; /* connected w/ web messenger method */
    - /* picture aka buddy icon stuff */
    - char *picture_url;
    - int picture_checksum;
    -
    - /* ew. we have to check the icon before we connect,
    - * but can't upload it til we're connected. */
    - struct yahoo_buddy_icon_upload_data *picture_upload_todo;
    - PurpleProxyConnectData *buddy_icon_connect_data;
    -
    - struct _YchtConn *ycht;
    -
    - /**
    - * This linked list contains PurpleUtilFetchUrlData structs
    - * for when we lookup people profile or photo information.
    - */
    - GSList *url_datas;
    - GHashTable *xfer_peer_idstring_map;/* Hey, i dont know, but putting this HashTable next to friends gives a run time fault... */
    - GSList *cookies;/* contains all cookies, including _y and _t */
    - PurpleNetworkListenData *listen_data;
    -
    - /**
    - * We may receive a list15 in multiple packets with no prior warning as to how many we'll be getting;
    - * the server expects us to keep track of the group for which it is sending us contact names.
    - */
    - char *current_list15_grp;
    - time_t last_ping;
    - time_t last_keepalive;
    - GHashTable *peers; /* information about p2p data */
    - int yahoo_p2p_timer;
    - int yahoo_local_p2p_server_fd;
    - int yahoo_p2p_server_watcher;
    - GHashTable *sms_carrier; /* sms carrier data */
    - guint yahoo_p2p_server_timeout_handle;
    -} YahooData;
    -
    -#define YAHOO_MAX_STATUS_MESSAGE_LENGTH (255)
    -
    -/*
    - * Current Maximum Length for Instant Messages
    - *
    - * This was found by experiment.
    - *
    - * The YMSG protocol allows a message of up to 948 bytes, but the official client
    - * limits to 800 characters. According to experiments I conducted, it seems that
    - * the discrepancy is to allow some leeway for messages with mixed single- and
    - * multi-byte characters, as I was able to send messages of 840 and 932 bytes
    - * by using some multibyte characters (some random Chinese or Japanese characters,
    - * to be precise). - rekkanoryo
    - */
    -#define YAHOO_MAX_MESSAGE_LENGTH_BYTES 948
    -#define YAHOO_MAX_MESSAGE_LENGTH_CHARS 800
    -
    -/* sometimes i wish prpls could #include things from other prpls. then i could just
    - * use the routines from libfaim and not have to admit to knowing how they work. */
    -#define yahoo_put16(buf, data) ( \
    - (*(buf) = (unsigned char)((data)>>8)&0xff), \
    - (*((buf)+1) = (unsigned char)(data)&0xff), \
    - 2)
    -#define yahoo_get16(buf) ((((*(buf))<<8)&0xff00) + ((*((buf)+1)) & 0xff))
    -#define yahoo_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)
    -#define yahoo_get32(buf) ((((*(buf))<<24)&0xff000000) + \
    - (((*((buf)+1))<<16)&0x00ff0000) + \
    - (((*((buf)+2))<< 8)&0x0000ff00) + \
    - (((*((buf)+3) )&0x000000ff)))
    -
    -/* util.c */
    -void yahoo_init_colorht(void);
    -void yahoo_dest_colorht(void);
    -char *yahoo_codes_to_html(const char *x);
    -
    -/**
    - * This function takes a normal HTML message and converts it to the message
    - * format used by Yahoo, which uses a frankensteinish combination of ANSI
    - * escape codes and broken HTML.
    - *
    - * It results in slightly different output than would be sent by official
    - * Yahoo clients. The two main differences are:
    - *
    - * 1. We always close all tags, whereas official Yahoo clients leave tags
    - * dangling open at the end of each message (and the client treats them
    - * as closed).
    - * 2. We always close inner tags first before closing outter tags.
    - *
    - * For example, if you want to send this message:
    - * <b> bold <i> bolditalic </i></b><i> italic </i>
    - * Official Yahoo clients would send:
    - * ESC[1m bold ESC[2m bolditalic ESC[x1m italic
    - * But we will send:
    - * ESC[1m bold ESC[2m bolditalic ESC[x2mESC[x1mESC[2m italic ESC[x2m
    - */
    -char *yahoo_html_to_codes(const char *src);
    -
    -gboolean
    -yahoo_account_use_http_proxy(PurpleConnection *conn);
    -
    -/**
    - * Encode some text to send to the yahoo server.
    - *
    - * @param gc The connection handle.
    - * @param str The null terminated utf8 string to encode.
    - * @param utf8 If not @c NULL, whether utf8 is okay or not.
    - * Even if it is okay, we may not use it. If we
    - * used it, we set this to @c TRUE, else to
    - * @c FALSE. If @c NULL, false is assumed, and
    - * it is not dereferenced.
    - * @return The g_malloced string in the appropriate encoding.
    - */
    -char *yahoo_string_encode(PurpleConnection *gc, const char *str, gboolean *utf8);
    -
    -/**
    - * Decode some text received from the server.
    - *
    - * @param gc The gc handle.
    - * @param str The null terminated string to decode.
    - * @param utf8 Did the server tell us it was supposed to be utf8?
    - * @return The decoded, utf-8 string, which must be g_free()'d.
    - */
    -char *yahoo_string_decode(PurpleConnection *gc, const char *str, gboolean utf8);
    -
    -char *yahoo_convert_to_numeric(const char *str);
    -
    -YahooFederation yahoo_get_federation_from_name(const char *who);
    -
    -/* yahoo_profile.c */
    -void yahoo_get_info(PurpleConnection *gc, const char *name);
    -
    -/* libymsg.h - these functions were formerly static but need not to be for the
    - * new two-prpl model. */
    -const char *yahoo_list_icon(PurpleAccount *a, PurpleBuddy *b);
    -const char *yahoo_list_emblem(PurpleBuddy *b);
    -char *yahoo_status_text(PurpleBuddy *b);
    -void yahoo_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full);
    -GList *yahoo_status_types(PurpleAccount *account);
    -GList *yahoo_blist_node_menu(PurpleBlistNode *node);
    -void yahoo_login(PurpleAccount *account);
    -void yahoo_close(PurpleConnection *gc);
    -int yahoo_send_im(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags);
    -unsigned int yahoo_send_typing(PurpleConnection *gc, const char *who, PurpleTypingState state);
    -void yahoo_set_status(PurpleAccount *account, PurpleStatus *status);
    -void yahoo_set_idle(PurpleConnection *gc, int idle);
    -void yahoo_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *g);
    -void yahoo_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
    -void yahoo_add_deny(PurpleConnection *gc, const char *who);
    -void yahoo_rem_deny(PurpleConnection *gc, const char *who);
    -void yahoo_set_permit_deny(PurpleConnection *gc);
    -void yahoo_keepalive(PurpleConnection *gc);
    -void yahoo_change_buddys_group(PurpleConnection *gc, const char *who, const char *old_group, const char *new_group);
    -void yahoo_rename_group(PurpleConnection *gc, const char *old_name, PurpleGroup *group, GList *moved_buddies);
    -gboolean yahoo_offline_message(const PurpleBuddy *buddy);
    -gboolean yahoo_send_attention(PurpleConnection *gc, const char *username, guint type);
    -GList *yahoo_attention_types(PurpleAccount *account);
    -
    -GList *yahoo_actions(PurplePlugin *plugin, gpointer context);
    -void yahoopurple_register_commands(void);
    -
    -PurpleCmdRet yahoopurple_cmd_buzz(PurpleConversation *c, const gchar *cmd, gchar **args, gchar **error, void *data);
    -PurpleCmdRet yahoopurple_cmd_chat_join(PurpleConversation *conv, const char *cmd, char **args, char **error, void *data);
    -PurpleCmdRet yahoopurple_cmd_chat_list(PurpleConversation *conv, const char *cmd, char **args, char **error, void *data);
    -/* needed for xfer, thought theyd be useful for other enhancements later on
    - Returns list of cookies stored in yahoo_data formatted as a single null terminated string
    - returned value must be g_freed
    -*/
    -gchar* yahoo_get_cookies(PurpleConnection *gc);
    -
    -/* send p2p pkt containing our encoded ip, asking peer to connect to us */
    -void yahoo_send_p2p_pkt(PurpleConnection *gc, const char *who, int val_13);
    -
    -#endif /* _LIBYMSG_H_ */
    --- a/libpurple/protocols/yahoo/util.c Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,986 +0,0 @@
    -/*
    - * purple
    - *
    - * Some code copyright 2003 Tim Ringenbach <omarvo@hotmail.com>
    - * (marv on irc.freenode.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
    - *
    - */
    -
    -#ifdef HAVE_CONFIG_H
    -#include "config.h"
    -#endif /* HAVE_CONFIG_H */
    -
    -#include "debug.h"
    -#include "internal.h"
    -#include "prpl.h"
    -
    -#include "libymsg.h"
    -
    -#include <string.h>
    -
    -gboolean
    -yahoo_account_use_http_proxy(PurpleConnection *pc)
    -{
    - PurpleAccount *account = purple_connection_get_account(pc);
    - PurpleProxyInfo *ppi = NULL;
    - PurpleProxyType type = PURPLE_PROXY_NONE;
    - gboolean proxy_ssl = purple_account_get_bool(account, "proxy_ssl", FALSE);
    -
    - if(proxy_ssl)
    - ppi = purple_proxy_get_setup(account);
    - else
    - ppi = purple_proxy_get_setup(NULL);
    -
    - type = purple_proxy_info_get_type(ppi);
    -
    - return (type == PURPLE_PROXY_HTTP || type == PURPLE_PROXY_USE_ENVVAR);
    -}
    -
    -/*
    - * Returns cookies formatted as a null terminated string for the given connection.
    - * Must g_free return value.
    - *
    - * TODO:will work, but must test for strict correctness
    - */
    -gchar* yahoo_get_cookies(PurpleConnection *gc)
    -{
    - gchar *ans = NULL;
    - gchar *cur;
    - char firstflag = 1;
    - gchar *t1,*t2,*t3;
    - GSList *tmp;
    - GSList *cookies;
    - cookies = ((YahooData*)(gc->proto_data))->cookies;
    - tmp = cookies;
    - while(tmp)
    - {
    - cur = tmp->data;
    - t1 = ans;
    - t2 = g_strrstr(cur, ";expires=");
    - if(t2 == NULL)
    - t2 = g_strrstr(cur, "; expires=");
    - if(t2 == NULL)
    - {
    - if(firstflag)
    - ans = g_strdup_printf("%c=%s", cur[0], cur+2);
    - else
    - ans = g_strdup_printf("%s; %c=%s", t1, cur[0], cur+2);
    - }
    - else
    - {
    - t3 = strstr(t2+1, ";");
    - if(t3 != NULL)
    - {
    - t2[0] = '\0';
    -
    - if(firstflag)
    - ans = g_strdup_printf("%c=%s%s", cur[0], cur+2, t3);
    - else
    - ans = g_strdup_printf("%s; %c=%s%s", t1, cur[0], cur+2, t3);
    -
    - t2[0] = ';';
    - }
    - else
    - {
    - t2[0] = '\0';
    -
    - if(firstflag)
    - ans = g_strdup_printf("%c=%s", cur[0], cur+2);
    - else
    - ans = g_strdup_printf("%s; %c=%s", t1, cur[0], cur+2);
    -
    - t2[0] = ';';
    - }
    - }
    - if(firstflag)
    - firstflag = 0;
    - else
    - g_free(t1);
    - tmp = g_slist_next(tmp);
    - }
    - return ans;
    -}
    -
    -/**
    - * Encode some text to send to the yahoo server.
    - *
    - * @param gc The connection handle.
    - * @param str The null terminated utf8 string to encode.
    - * @param utf8 If not @c NULL, whether utf8 is okay or not.
    - * Even if it is okay, we may not use it. If we
    - * used it, we set this to @c TRUE, else to
    - * @c FALSE. If @c NULL, false is assumed, and
    - * it is not dereferenced.
    - * @return The g_malloced string in the appropriate encoding.
    - */
    -char *yahoo_string_encode(PurpleConnection *gc, const char *str, gboolean *utf8)
    -{
    - YahooData *yd = gc->proto_data;
    - char *ret;
    - const char *to_codeset;
    - GError *error = NULL;
    -
    - if (yd->jp)
    - return g_strdup(str);
    -
    - if (utf8 && *utf8) /* FIXME: maybe don't use utf8 if it'll fit in latin1 */
    - return g_strdup(str);
    -
    - to_codeset = purple_account_get_string(purple_connection_get_account(gc), "local_charset", "ISO-8859-1");
    - ret = g_convert_with_fallback(str, -1, to_codeset, "UTF-8", "?", NULL, NULL, &error);
    - if (!ret) {
    - if (error) {
    - purple_debug_error("yahoo", "Could not convert %s from UTF-8 to "
    - "%s: %d - %s\n", str ? str : "(null)", to_codeset,
    - error->code,
    - error->message ? error->message : "(null)");
    - g_error_free(error);
    - } else {
    - purple_debug_error("yahoo", "Could not convert %s from UTF-8 to "
    - "%s: unkown error\n", str ? str : "(null)", to_codeset);
    - }
    - return g_strdup("");
    - }
    -
    - return ret;
    -}
    -
    -/**
    - * Decode some text received from the server.
    - *
    - * @param gc The gc handle.
    - * @param str The null terminated string to decode.
    - * @param utf8 Did the server tell us it was supposed to be utf8?
    - * @return The decoded, utf-8 string, which must be g_free()'d.
    - */
    -char *yahoo_string_decode(PurpleConnection *gc, const char *str, gboolean utf8)
    -{
    - YahooData *yd = gc->proto_data;
    - char *ret;
    - const char *from_codeset;
    - GError *error = NULL;
    -
    - if (utf8) {
    - if (g_utf8_validate(str, -1, NULL))
    - return g_strdup(str);
    - purple_debug_warning("yahoo", "Server told us a string was supposed "
    - "to be UTF-8, but it was not. Will try another encoding.\n");
    - }
    -
    - if (yd->jp)
    - from_codeset = "SHIFT_JIS";
    - else
    - from_codeset = purple_account_get_string(purple_connection_get_account(gc), "local_charset", "ISO-8859-1");
    -
    - ret = g_convert_with_fallback(str, -1, "UTF-8", from_codeset, NULL, NULL, NULL, &error);
    - if (!ret) {
    - if (error) {
    - purple_debug_error("yahoo", "Could not convert %s from %s to "
    - "UTF-8: %d - %s\n", str ? str : "(null)", from_codeset,
    - error->code, error->message ? error->message : "(null)");
    - g_error_free(error);
    - } else {
    - purple_debug_error("yahoo", "Could not convert %s from %s to "
    - "UTF-8: unkown error\n", str ? str : "(null)",
    - from_codeset);
    - }
    - return g_strdup("");
    - }
    -
    - return ret;
    -}
    -
    -char *yahoo_convert_to_numeric(const char *str)
    -{
    - GString *gstr = NULL;
    - const unsigned char *p;
    -
    - gstr = g_string_sized_new(strlen(str) * 6 + 1);
    -
    - for (p = (unsigned char *)str; *p; p++) {
    - g_string_append_printf(gstr, "&#%u;", *p);
    - }
    -
    - return g_string_free(gstr, FALSE);
    -}
    -
    -/*
    - * The values in this hash table should probably be lowercase, since that's
    - * what xhtml expects. Also because yahoo_codes_to_html() does
    - * case-sensitive comparisons.
    - *
    - * I found these on some website but i don't know that they actually
    - * work (or are supposed to work). I didn't implement them yet.
    - *
    - * [0;30m ---black
    - * [1;37m ---white
    - * [0;37m ---tan
    - * [0;38m ---light black
    - * [1;39m ---dark blue
    - * [0;32m ---green
    - * [0;33m ---yellow
    - * [0;35m ---pink
    - * [1;35m ---purple
    - * [1;30m ---light blue
    - * [0;31m ---red
    - * [0;34m ---blue
    - * [0;36m ---aqua
    - * (shift+comma)lyellow(shift+period) ---light yellow
    - * (shift+comma)lgreen(shift+period) ---light green
    - * [2;30m <--white out
    - */
    -
    -static GHashTable *esc_codes_ht = NULL;
    -static GHashTable *tags_ht = NULL;
    -
    -void yahoo_init_colorht()
    -{
    - if (esc_codes_ht != NULL)
    - /* Hash table has already been initialized */
    - return;
    -
    - /* Key is the escape code string. Value is the HTML that should be
    - * inserted in place of the escape code. */
    - esc_codes_ht = g_hash_table_new(g_str_hash, g_str_equal);
    -
    - /* Key is the name of the HTML tag, for example "font" or "/font"
    - * value is the HTML that should be inserted in place of the old tag */
    - tags_ht = g_hash_table_new(g_str_hash, g_str_equal);
    -
    - /* the numbers in comments are what gyach uses, but i think they're incorrect */
    -#ifdef USE_CSS_FORMATTING
    - g_hash_table_insert(esc_codes_ht, "30", "<span style=\"color: #000000\">"); /* black */
    - g_hash_table_insert(esc_codes_ht, "31", "<span style=\"color: #0000FF\">"); /* blue */
    - g_hash_table_insert(esc_codes_ht, "32", "<span style=\"color: #008080\">"); /* cyan */ /* 00b2b2 */
    - g_hash_table_insert(esc_codes_ht, "33", "<span style=\"color: #808080\">"); /* gray */ /* 808080 */
    - g_hash_table_insert(esc_codes_ht, "34", "<span style=\"color: #008000\">"); /* green */ /* 00c200 */
    - g_hash_table_insert(esc_codes_ht, "35", "<span style=\"color: #FF0080\">"); /* pink */ /* ffafaf */
    - g_hash_table_insert(esc_codes_ht, "36", "<span style=\"color: #800080\">"); /* purple */ /* b200b2 */
    - g_hash_table_insert(esc_codes_ht, "37", "<span style=\"color: #FF8000\">"); /* orange */ /* ffff00 */
    - g_hash_table_insert(esc_codes_ht, "38", "<span style=\"color: #FF0000\">"); /* red */
    - g_hash_table_insert(esc_codes_ht, "39", "<span style=\"color: #808000\">"); /* olive */ /* 546b50 */
    -#else
    - g_hash_table_insert(esc_codes_ht, "30", "<font color=\"#000000\">"); /* black */
    - g_hash_table_insert(esc_codes_ht, "31", "<font color=\"#0000FF\">"); /* blue */
    - g_hash_table_insert(esc_codes_ht, "32", "<font color=\"#008080\">"); /* cyan */ /* 00b2b2 */
    - g_hash_table_insert(esc_codes_ht, "33", "<font color=\"#808080\">"); /* gray */ /* 808080 */
    - g_hash_table_insert(esc_codes_ht, "34", "<font color=\"#008000\">"); /* green */ /* 00c200 */
    - g_hash_table_insert(esc_codes_ht, "35", "<font color=\"#FF0080\">"); /* pink */ /* ffafaf */
    - g_hash_table_insert(esc_codes_ht, "36", "<font color=\"#800080\">"); /* purple */ /* b200b2 */
    - g_hash_table_insert(esc_codes_ht, "37", "<font color=\"#FF8000\">"); /* orange */ /* ffff00 */
    - g_hash_table_insert(esc_codes_ht, "38", "<font color=\"#FF0000\">"); /* red */
    - g_hash_table_insert(esc_codes_ht, "39", "<font color=\"#808000\">"); /* olive */ /* 546b50 */
    -#endif /* !USE_CSS_FORMATTING */
    -
    - g_hash_table_insert(esc_codes_ht, "1", "<b>");
    - g_hash_table_insert(esc_codes_ht, "x1", "</b>");
    - g_hash_table_insert(esc_codes_ht, "2", "<i>");
    - g_hash_table_insert(esc_codes_ht, "x2", "</i>");
    - g_hash_table_insert(esc_codes_ht, "4", "<u>");
    - g_hash_table_insert(esc_codes_ht, "x4", "</u>");
    -
    - /* these just tell us the text they surround is supposed
    - * to be a link. purple figures that out on its own so we
    - * just ignore it.
    - */
    - g_hash_table_insert(esc_codes_ht, "l", ""); /* link start */
    - g_hash_table_insert(esc_codes_ht, "xl", ""); /* link end */
    -
    -#ifdef USE_CSS_FORMATTING
    - g_hash_table_insert(tags_ht, "black", "<span style=\"color: #000000\">");
    - g_hash_table_insert(tags_ht, "blue", "<span style=\"color: #0000FF\">");
    - g_hash_table_insert(tags_ht, "cyan", "<span style=\"color: #008284\">");
    - g_hash_table_insert(tags_ht, "gray", "<span style=\"color: #848284\">");
    - g_hash_table_insert(tags_ht, "green", "<span style=\"color: #008200\">");
    - g_hash_table_insert(tags_ht, "pink", "<span style=\"color: #FF0084\">");
    - g_hash_table_insert(tags_ht, "purple", "<span style=\"color: #840084\">");
    - g_hash_table_insert(tags_ht, "orange", "<span style=\"color: #FF8000\">");
    - g_hash_table_insert(tags_ht, "red", "<span style=\"color: #FF0000\">");
    - g_hash_table_insert(tags_ht, "yellow", "<span style=\"color: #848200\">");
    -
    - g_hash_table_insert(tags_ht, "/black", "</span>");
    - g_hash_table_insert(tags_ht, "/blue", "</span>");
    - g_hash_table_insert(tags_ht, "/cyan", "</span>");
    - g_hash_table_insert(tags_ht, "/gray", "</span>");
    - g_hash_table_insert(tags_ht, "/green", "</span>");
    - g_hash_table_insert(tags_ht, "/pink", "</span>");
    - g_hash_table_insert(tags_ht, "/purple", "</span>");
    - g_hash_table_insert(tags_ht, "/orange", "</span>");
    - g_hash_table_insert(tags_ht, "/red", "</span>");
    - g_hash_table_insert(tags_ht, "/yellow", "</span>");
    -#else
    - g_hash_table_insert(tags_ht, "black", "<font color=\"#000000\">");
    - g_hash_table_insert(tags_ht, "blue", "<font color=\"#0000FF\">");
    - g_hash_table_insert(tags_ht, "cyan", "<font color=\"#008284\">");
    - g_hash_table_insert(tags_ht, "gray", "<font color=\"#848284\">");
    - g_hash_table_insert(tags_ht, "green", "<font color=\"#008200\">");
    - g_hash_table_insert(tags_ht, "pink", "<font color=\"#FF0084\">");
    - g_hash_table_insert(tags_ht, "purple", "<font color=\"#840084\">");
    - g_hash_table_insert(tags_ht, "orange", "<font color=\"#FF8000\">");
    - g_hash_table_insert(tags_ht, "red", "<font color=\"#FF0000\">");
    - g_hash_table_insert(tags_ht, "yellow", "<font color=\"#848200\">");
    -
    - g_hash_table_insert(tags_ht, "/black", "</font>");
    - g_hash_table_insert(tags_ht, "/blue", "</font>");
    - g_hash_table_insert(tags_ht, "/cyan", "</font>");
    - g_hash_table_insert(tags_ht, "/gray", "</font>");
    - g_hash_table_insert(tags_ht, "/green", "</font>");
    - g_hash_table_insert(tags_ht, "/pink", "</font>");
    - g_hash_table_insert(tags_ht, "/purple", "</font>");
    - g_hash_table_insert(tags_ht, "/orange", "</font>");
    - g_hash_table_insert(tags_ht, "/red", "</font>");
    - g_hash_table_insert(tags_ht, "/yellow", "</font>");
    -#endif /* !USE_CSS_FORMATTING */
    -
    - /* We don't support these tags, so discard them */
    - g_hash_table_insert(tags_ht, "alt", "");
    - g_hash_table_insert(tags_ht, "fade", "");
    - g_hash_table_insert(tags_ht, "snd", "");
    - g_hash_table_insert(tags_ht, "/alt", "");
    - g_hash_table_insert(tags_ht, "/fade", "");
    -
    - /* Official clients don't seem to send b, i or u tags. They use
    - * the escape codes listed above. Official clients definitely send
    - * font tags, though. I wonder if we can remove the opening and
    - * closing b, i and u tags from here? */
    - g_hash_table_insert(tags_ht, "b", "<b>");
    - g_hash_table_insert(tags_ht, "i", "<i>");
    - g_hash_table_insert(tags_ht, "u", "<u>");
    - g_hash_table_insert(tags_ht, "font", "<font>");
    -
    - g_hash_table_insert(tags_ht, "/b", "</b>");
    - g_hash_table_insert(tags_ht, "/i", "</i>");
    - g_hash_table_insert(tags_ht, "/u", "</u>");
    - g_hash_table_insert(tags_ht, "/font", "</font>");
    -}
    -
    -void yahoo_dest_colorht()
    -{
    - if (esc_codes_ht == NULL)
    - /* Hash table has already been destroyed */
    - return;
    -
    - g_hash_table_destroy(esc_codes_ht);
    - esc_codes_ht = NULL;
    - g_hash_table_destroy(tags_ht);
    - tags_ht = NULL;
    -}
    -
    -#ifndef USE_CSS_FORMATTING
    -static int point_to_html(int x)
    -{
    - if (x < 9)
    - return 1;
    - if (x < 11)
    - return 2;
    - if (x < 13)
    - return 3;
    - if (x < 17)
    - return 4;
    - if (x < 25)
    - return 5;
    - if (x < 35)
    - return 6;
    - return 7;
    -}
    -#endif /* !USE_CSS_FORMATTING */
    -
    -static void append_attrs_datalist_foreach_cb(GQuark key_id, gpointer data, gpointer user_data)
    -{
    - const char *key;
    - const char *value;
    - xmlnode *cur;
    -
    - key = g_quark_to_string(key_id);
    - value = data;
    - cur = user_data;
    -
    - xmlnode_set_attrib(cur, key, value);
    -}
    -
    -/**
    - * @param cur A pointer to the position in the XML tree that we're
    - * currently building. This will be modified when opening a tag
    - * or closing an existing tag.
    - */
    -static void yahoo_codes_to_html_add_tag(xmlnode **cur, const char *tag, gboolean is_closing_tag, const gchar *tag_name, gboolean is_font_tag)
    -{
    - if (is_closing_tag) {
    - xmlnode *tmp;
    - GSList *dangling_tags = NULL;
    -
    - /* Move up the DOM until we find the opening tag */
    - for (tmp = *cur; tmp != NULL; tmp = xmlnode_get_parent(tmp)) {
    - /* Add one to tag_name when doing this comparison because it starts with a / */
    - if (g_str_equal(tmp->name, tag_name + 1))
    - /* Found */
    - break;
    - dangling_tags = g_slist_prepend(dangling_tags, tmp);
    - }
    - if (tmp == NULL) {
    - /* This is a closing tag with no opening tag. Useless. */
    - purple_debug_error("yahoo", "Ignoring unmatched tag %s", tag);
    - g_slist_free(dangling_tags);
    - return;
    - }
    -
    - /* Move our current position up, now that we've closed a tag */
    - *cur = xmlnode_get_parent(tmp);
    -
    - /* Re-open any tags that were nested below the tag we just closed */
    - while (dangling_tags != NULL) {
    - tmp = dangling_tags->data;
    - dangling_tags = g_slist_delete_link(dangling_tags, dangling_tags);
    -
    - /* Create a copy of this tag+attributes (but not child tags or
    - * data) at our new location */
    - *cur = xmlnode_new_child(*cur, tmp->name);
    - for (tmp = tmp->child; tmp != NULL; tmp = tmp->next)
    - if (tmp->type == XMLNODE_TYPE_ATTRIB)
    - xmlnode_set_attrib_full(*cur, tmp->name,
    - tmp->xmlns, tmp->prefix, tmp->data);
    - }
    - } else {
    - const char *start;
    - const char *end;
    - GData *attributes;
    - char *fontsize = NULL;
    -
    - if (!purple_markup_find_tag(tag_name, tag, &start, &end, &attributes))
    - g_return_if_reached();
    - *cur = xmlnode_new_child(*cur, tag_name);
    -
    - if (is_font_tag) {
    - /* Special case for the font size attribute */
    - fontsize = g_strdup(g_datalist_get_data(&attributes, "size"));
    - if (fontsize != NULL)
    - g_datalist_remove_data(&attributes, "size");
    - }
    -
    - /* Add all font tag attributes */
    - g_datalist_foreach(&attributes, append_attrs_datalist_foreach_cb, *cur);
    - g_datalist_clear(&attributes);
    -
    - if (fontsize != NULL) {
    -#ifdef USE_CSS_FORMATTING
    - /*
    - * The Yahoo font size value is given in pt, even though the HTML
    - * standard for <font size="x"> treats the size as a number on a
    - * scale between 1 and 7. So we insert the font size as a CSS
    - * style on a span tag.
    - */
    - gchar *tmp = g_strdup_printf("font-size: %spt", fontsize);
    - *cur = xmlnode_new_child(*cur, "span");
    - xmlnode_set_attrib(*cur, "style", tmp);
    - g_free(tmp);
    -#else
    - /*
    - * The Yahoo font size value is given in pt, even though the HTML
    - * standard for <font size="x"> treats the size as a number on a
    - * scale between 1 and 7. So we convert it to an appropriate
    - * value. This loses precision, which is why CSS formatting is
    - * preferred. The "absz" attribute remains here for backward
    - * compatibility with UIs that might use it, but it is totally
    - * not standard at all.
    - */
    - int size, htmlsize;
    - gchar tmp[11];
    - size = strtol(fontsize, NULL, 10);
    - htmlsize = point_to_html(size);
    - sprintf(tmp, "%u", htmlsize);
    - xmlnode_set_attrib(*cur, "size", tmp);
    - xmlnode_set_attrib(*cur, "absz", fontsize);
    -#endif /* !USE_CSS_FORMATTING */
    - g_free(fontsize);
    - }
    - }
    -}
    -
    -/**
    - * Similar to purple_markup_get_tag_name(), but works with closing tags.
    - *
    - * @return The lowercase name of the tag. If this is a closing tag then
    - * this value starts with a forward slash. The caller must free
    - * this string with g_free.
    - */
    -static gchar *yahoo_markup_get_tag_name(const char *tag, gboolean *is_closing_tag)
    -{
    - size_t len;
    -
    - *is_closing_tag = (tag[1] == '/');
    - if (*is_closing_tag)
    - len = strcspn(tag + 1, "> ");
    - else
    - len = strcspn(tag + 1, "> /");
    -
    - return g_utf8_strdown(tag + 1, len);
    -}
    -
    -/*
    - * Yahoo! messages generally aren't well-formed. Their markup is
    - * more of a flow from start to finish rather than a hierarchy from
    - * outer to inner. They tend to open tags and close them only when
    - * necessary.
    - *
    - * Example: <font size="8">size 8 <font size="16">size 16 <font size="8">size 8 again
    - *
    - * But we want to send well-formed HTML to the core, so we step through
    - * the input string and build an xmlnode tree containing sanitized HTML.
    - */
    -char *yahoo_codes_to_html(const char *x)
    -{
    - size_t x_len;
    - xmlnode *html, *cur;
    - GString *cdata = g_string_new(NULL);
    - guint i, j;
    - gboolean no_more_gt_brackets = FALSE;
    - const char *match;
    - gchar *xmlstr1, *xmlstr2, *esc;
    -
    - x_len = strlen(x);
    - html = xmlnode_new("html");
    -
    - cur = html;
    - for (i = 0; i < x_len; i++) {
    - if ((x[i] == 0x1b) && (x[i+1] == '[')) {
    - /* This escape sequence signifies the beginning of some
    - * text formatting code */
    - j = i + 1;
    -
    - while (j++ < x_len) {
    - gchar *code;
    -
    - if (x[j] != 'm')
    - /* Keep looking for the end of this sequence */
    - continue;
    -
    - /* We've reached the end of the formatting sequence, yay */
    -
    - /* Append any character data that belongs in the current node */
    - if (cdata->len > 0) {
    - xmlnode_insert_data(cur, cdata->str, cdata->len);
    - g_string_truncate(cdata, 0);
    - }
    -
    - code = g_strndup(x + i + 2, j - i - 2);
    - if (code[0] == '#') {
    -#ifdef USE_CSS_FORMATTING
    - gchar *tmp = g_strdup_printf("color: %s", code);
    - cur = xmlnode_new_child(cur, "span");
    - xmlnode_set_attrib(cur, "style", tmp);
    - g_free(tmp);
    -#else
    - cur = xmlnode_new_child(cur, "font");
    - xmlnode_set_attrib(cur, "color", code);
    -#endif /* !USE_CSS_FORMATTING */
    -
    - } else if ((match = g_hash_table_lookup(esc_codes_ht, code))) {
    - /* Some tags are in the hash table only because we
    - * want to ignore them */
    - if (match[0] != '\0') {
    - gboolean is_closing_tag;
    - gchar *tag_name;
    - tag_name = yahoo_markup_get_tag_name(match, &is_closing_tag);
    - yahoo_codes_to_html_add_tag(&cur, match, is_closing_tag, tag_name, FALSE);
    - g_free(tag_name);
    - }
    -
    - } else {
    - purple_debug_error("yahoo",
    - "Ignoring unknown ansi code 'ESC[%sm'.\n", code);
    - }
    -
    - g_free(code);
    - i = j;
    - break;
    - }
    -
    - } else if (x[i] == '<' && !no_more_gt_brackets) {
    - /* The start of an HTML tag */
    - j = i;
    -
    - while (j++ < x_len) {
    - gchar *tag;
    - gboolean is_closing_tag;
    - gchar *tag_name;
    -
    - if (x[j] != '>') {
    - if (x[j] == '"') {
    - /* We're inside a quoted attribute value. Skip to the end */
    - j++;
    - while (j != x_len && x[j] != '"')
    - j++;
    - } else if (x[j] == '\'') {
    - /* We're inside a quoted attribute value. Skip to the end */
    - j++;
    - while (j != x_len && x[j] != '\'')
    - j++;
    - }
    - if (j != x_len)
    - /* Keep looking for the end of this tag */
    - continue;
    -
    - /* This < has no corresponding > */
    - g_string_append_c(cdata, x[i]);
    - no_more_gt_brackets = TRUE;
    - break;
    - }
    -
    - tag = g_strndup(x + i, j - i + 1);
    - tag_name = yahoo_markup_get_tag_name(tag, &is_closing_tag);
    -
    - match = g_hash_table_lookup(tags_ht, tag_name);
    - if (match == NULL) {
    - /* Unknown tag. The user probably typed a less-than sign */
    - g_string_append_c(cdata, x[i]);
    - g_free(tag);
    - g_free(tag_name);
    - break;
    - }
    -
    - /* Some tags are in the hash table only because we
    - * want to ignore them */
    - if (match[0] != '\0') {
    - /* Append any character data that belongs in the current node */
    - if (cdata->len > 0) {
    - xmlnode_insert_data(cur, cdata->str, cdata->len);
    - g_string_truncate(cdata, 0);
    - }
    - if (g_str_equal(tag_name, "font"))
    - /* Font tags are a special case. We don't
    - * necessarily want to replace the whole thing--
    - * we just want to fix the size attribute. */
    - yahoo_codes_to_html_add_tag(&cur, tag, is_closing_tag, tag_name, TRUE);
    - else
    - yahoo_codes_to_html_add_tag(&cur, match, is_closing_tag, tag_name, FALSE);
    - }
    -
    - i = j;
    - g_free(tag);
    - g_free(tag_name);
    - break;
    - }
    -
    - } else {
    - g_string_append_c(cdata, x[i]);
    - }
    - }
    -
    - /* Append any remaining character data */
    - if (cdata->len > 0)
    - xmlnode_insert_data(cur, cdata->str, cdata->len);
    - g_string_free(cdata, TRUE);
    -
    - /* Serialize our HTML */
    - xmlstr1 = xmlnode_to_str(html, NULL);
    - xmlnode_free(html);
    -
    - /* Strip off the outter HTML node */
    - /* This probably isn't necessary, especially if we made the outter HTML
    - * node an empty span. But the HTML is simpler this way. */
    - if (!purple_strequal(xmlstr1, "<html/>"))
    - xmlstr2 = g_strndup(xmlstr1 + 6, strlen(xmlstr1) - 13);
    - else
    - xmlstr2 = g_strdup("");
    - g_free(xmlstr1);
    -
    - esc = g_strescape(x, NULL);
    - purple_debug_misc("yahoo", "yahoo_codes_to_html(%s)=%s\n", esc, xmlstr2);
    - g_free(esc);
    -
    - return xmlstr2;
    -}
    -
    -/* borrowed from gtkimhtml */
    -#define MAX_FONT_SIZE 7
    -#define POINT_SIZE(x) (_point_sizes [MIN ((x > 0 ? x : 1), MAX_FONT_SIZE) - 1])
    -static const gint _point_sizes [] = { 8, 10, 12, 14, 20, 30, 40 };
    -
    -typedef struct
    -{
    - gboolean bold;
    - gboolean italic;
    - gboolean underline;
    - gboolean in_link;
    - int font_size;
    - char *font_face;
    - char *font_color;
    -} CurrentMsgState;
    -
    -static void yahoo_htc_list_cleanup(GSList *l)
    -{
    - while (l != NULL) {
    - g_free(l->data);
    - l = g_slist_delete_link(l, l);
    - }
    -}
    -
    -static void parse_font_tag(GString *dest, const char *tag_name, const char *tag,
    - GSList **colors, GSList **tags)
    -{
    - const char *start;
    - const char *end;
    - GData *attributes;
    - const char *attribute;
    - gboolean needendtag;
    - GString *tmp;
    -
    - if (!purple_markup_find_tag(tag_name, tag, &start, &end, &attributes))
    - g_return_if_reached();
    -
    - needendtag = FALSE;
    - tmp = g_string_new(NULL);
    -
    - attribute = g_datalist_get_data(&attributes, "color");
    - if (attribute != NULL) {
    - g_string_append(tmp, *colors ? (*colors)->data : "\033[#000000m");
    - g_string_append_printf(dest, "\033[%sm", attribute);
    - *colors = g_slist_prepend(*colors,
    - g_strdup_printf("\033[%sm", attribute));
    - } else {
    - /* We need to add a value to the colors stack even if we're not
    - * setting a color because we ALWAYS pop exactly 1 element from
    - * this stack for every </font> tag. If we don't add anything
    - * then we'll pop something that we shouldn't when we hit this
    - * corresponding </font>. */
    - *colors = g_slist_prepend(*colors,
    - *colors ? g_strdup((*colors)->data) : g_strdup("\033[#000000m"));
    - }
    -
    - attribute = g_datalist_get_data(&attributes, "face");
    - if (attribute != NULL) {
    - needendtag = TRUE;
    - g_string_append(dest, "<font ");
    - g_string_append_printf(dest, "face=\"%s\" ", attribute);
    - }
    -
    - attribute = g_datalist_get_data(&attributes, "size");
    - if (attribute != NULL) {
    - if (!needendtag) {
    - needendtag = TRUE;
    - g_string_append(dest, "<font ");
    - }
    -
    - g_string_append_printf(dest, "size=\"%d\" ",
    - POINT_SIZE(strtol(attribute, NULL, 10)));
    - }
    -
    - if (needendtag) {
    - dest->str[dest->len-1] = '>';
    - *tags = g_slist_prepend(*tags, g_strdup("</font>"));
    - g_string_free(tmp, TRUE);
    - } else {
    - *tags = g_slist_prepend(*tags, tmp->str);
    - g_string_free(tmp, FALSE);
    - }
    -
    - g_datalist_clear(&attributes);
    -}
    -
    -char *yahoo_html_to_codes(const char *src)
    -{
    - GSList *colors = NULL;
    -
    - /**
    - * A stack of char*s where each char* is the string that should be
    - * appended to dest in order to close all the tags that were opened
    - * by a <font> tag.
    - */
    - GSList *tags = NULL;
    -
    - size_t src_len;
    - guint i, j;
    - GString *dest;
    - char *esc;
    - gboolean no_more_gt_brackets = FALSE;
    - gchar *tag, *tag_name;
    - gboolean is_closing_tag;
    - CurrentMsgState current_state;
    -
    - memset(&current_state, 0, sizeof(current_state));
    -
    - src_len = strlen(src);
    - dest = g_string_sized_new(src_len);
    -
    - for (i = 0; i < src_len; i++) {
    - if (src[i] == '<' && !no_more_gt_brackets) {
    - /* The start of an HTML tag */
    - j = i;
    -
    - while (j++ < src_len) {
    - if (src[j] != '>') {
    - if (src[j] == '"') {
    - /* We're inside a quoted attribute value. Skip to the end */
    - j++;
    - while (j != src_len && src[j] != '"')
    - j++;
    - } else if (src[j] == '\'') {
    - /* We're inside a quoted attribute value. Skip to the end */
    - j++;
    - while (j != src_len && src[j] != '\'')
    - j++;
    - }
    - if (j != src_len)
    - /* Keep looking for the end of this tag */
    - continue;
    -
    - /* This < has no corresponding > */
    - g_string_append_c(dest, src[i]);
    - no_more_gt_brackets = TRUE;
    - break;
    - }
    -
    - tag = g_strndup(src + i, j - i + 1);
    - tag_name = yahoo_markup_get_tag_name(tag, &is_closing_tag);
    -
    - if (g_str_equal(tag_name, "a")) {
    - const char *start;
    - const char *end;
    - GData *attributes;
    - const char *attribute;
    -
    - /*
    - * TODO: Ideally we would replace this:
    - * <a href="http://pidgin.im/">Pidgin</a>
    - * with this:
    - * Pidgin (http://pidgin.im/)
    - *
    - * Currently we drop the text within the <a> tag and
    - * just show the URL. Doing it the fancy way is
    - * complicated when dealing with HTML tags within the
    - * <a> tag.
    - */
    -
    - /* Append the URL */
    - if (!purple_markup_find_tag(tag_name,
    - tag, &start, &end, &attributes))
    - {
    - g_warn_if_reached();
    - i = j;
    - g_free(tag);
    - g_free(tag_name);
    - break;
    - }
    -
    - attribute = g_datalist_get_data(&attributes, "href");
    - if (attribute != NULL) {
    - if (purple_str_has_prefix(attribute, "mailto:"))
    - attribute += 7;
    - g_string_append(dest, attribute);
    - }
    - g_datalist_clear(&attributes);
    -
    - /* Skip past the closing </a> tag */
    - end = purple_strcasestr(src + j, "</a>");
    - if (end != NULL)
    - j = end - src + 3;
    -
    - } else if (g_str_equal(tag_name, "font")) {
    - parse_font_tag(dest, tag_name, tag, &colors, &tags);
    - } else if (g_str_equal(tag_name, "b")) {
    - g_string_append(dest, "\033[1m");
    - current_state.bold = TRUE;
    - } else if (g_str_equal(tag_name, "/b")) {
    - if (current_state.bold) {
    - g_string_append(dest, "\033[x1m");
    - current_state.bold = FALSE;
    - }
    - } else if (g_str_equal(tag_name, "i")) {
    - current_state.italic = TRUE;
    - g_string_append(dest, "\033[2m");
    - } else if (g_str_equal(tag_name, "/i")) {
    - if (current_state.italic) {
    - g_string_append(dest, "\033[x2m");
    - current_state.italic = FALSE;
    - }
    - } else if (g_str_equal(tag_name, "u")) {
    - current_state.underline = TRUE;
    - g_string_append(dest, "\033[4m");
    - } else if (g_str_equal(tag_name, "/u")) {
    - if (current_state.underline) {
    - g_string_append(dest, "\033[x4m");
    - current_state.underline = FALSE;
    - }
    - } else if (g_str_equal(tag_name, "/a")) {
    - /* Do nothing */
    - } else if (g_str_equal(tag_name, "br")) {
    - g_string_append_c(dest, '\n');
    - } else if (g_str_equal(tag_name, "/font")) {
    - if (tags != NULL) {
    - char *etag = tags->data;
    - tags = g_slist_delete_link(tags, tags);
    - g_string_append(dest, etag);
    - if (colors != NULL) {
    - g_free(colors->data);
    - colors = g_slist_delete_link(colors, colors);
    - }
    - g_free(etag);
    - }
    - } else if (g_str_equal(tag_name, "span") || g_str_equal(tag_name, "/span")) {
    - /* Do nothing */
    - } else {
    - /* We don't know what the tag is. Send it unmodified. */
    - g_string_append(dest, tag);
    - }
    -
    - i = j;
    - g_free(tag);
    - g_free(tag_name);
    - break;
    - }
    -
    - } else {
    - const char *entity;
    - int length;
    -
    - entity = purple_markup_unescape_entity(src + i, &length);
    - if (entity != NULL) {
    - /* src[i] is the start of an HTML entity */
    - g_string_append(dest, entity);
    - i += length - 1;
    - } else
    - /* src[i] is a normal character */
    - g_string_append_c(dest, src[i]);
    - }
    - }
    -
    - esc = g_strescape(dest->str, NULL);
    - purple_debug_misc("yahoo", "yahoo_html_to_codes(%s)=%s\n", src, esc);
    - g_free(esc);
    -
    - yahoo_htc_list_cleanup(colors);
    - yahoo_htc_list_cleanup(tags);
    -
    - return g_string_free(dest, FALSE);
    -}
    -
    -YahooFederation yahoo_get_federation_from_name(const char *who)
    -{
    - YahooFederation fed = YAHOO_FEDERATION_NONE;
    - if (who[3] == '/') {
    - if (!g_ascii_strncasecmp(who, "msn", 3))
    - fed = YAHOO_FEDERATION_MSN;
    - else if (!g_ascii_strncasecmp(who, "ocs", 3))
    - fed = YAHOO_FEDERATION_OCS;
    - else if (!g_ascii_strncasecmp(who, "ibm", 3))
    - fed = YAHOO_FEDERATION_IBM;
    - else if (!g_ascii_strncasecmp(who, "pbx", 3))
    - fed = YAHOO_FEDERATION_PBX;
    - }
    - return fed;
    -}
    -
    --- a/libpurple/protocols/yahoo/yahoo_aliases.c Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,729 +0,0 @@
    -/*
    - * purple
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * This program is free software; you can redistribute it and/or modify
    - * it under the terms of the GNU General Public License as published by
    - * the Free Software Foundation; either version 2 of the License, or
    - * (at your option) any later version.
    - *
    - * This program is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    - * GNU General Public License for more details.
    - *
    - * You should have received a copy of the GNU General Public License
    - * along with this program; if not, write to the Free Software
    - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    - *
    - */
    -
    -
    -#include "internal.h"
    -
    -#include "account.h"
    -#include "accountopt.h"
    -#include "blist.h"
    -#include "debug.h"
    -#include "util.h"
    -#include "request.h"
    -#include "version.h"
    -#include "libymsg.h"
    -#include "yahoo_aliases.h"
    -#include "yahoo_friend.h"
    -#include "yahoo_packet.h"
    -
    -/* I hate hardcoding this stuff, but Yahoo never sends us anything to use. Someone in the know may be able to tweak this URL */
    -#define YAHOO_ALIAS_FETCH_URL "http://address.yahoo.com/yab/us?v=XM&prog=ymsgr&.intl=us&diffs=1&t=0&tags=short&rt=0&prog-ver=" YAHOO_CLIENT_VERSION "&useutf8=1&legenc=codepage-1252"
    -#define YAHOO_ALIAS_UPDATE_URL "http://address.yahoo.com/yab/us?v=XM&prog=ymsgr&.intl=us&sync=1&tags=short&noclear=1&useutf8=1&legenc=codepage-1252"
    -#define YAHOOJP_ALIAS_FETCH_URL "http://address.yahoo.co.jp/yab/jp?v=XM&prog=ymsgr&.intl=jp&diffs=1&t=0&tags=short&rt=0&prog-ver=" YAHOOJP_CLIENT_VERSION
    -#define YAHOOJP_ALIAS_UPDATE_URL "http://address.yahoo.co.jp/yab/jp?v=XM&prog=ymsgr&.intl=jp&sync=1&tags=short&noclear=1"
    -
    -void yahoo_update_alias(PurpleConnection *gc, const char *who, const char *alias);
    -
    -/**
    - * Stuff we want passed to the callback function
    - */
    -struct callback_data {
    - PurpleConnection *gc;
    - gchar *id;
    - gchar *who;
    -};
    -
    -void yahoo_personal_details_reset(YahooPersonalDetails *ypd, gboolean all)
    -{
    - if (all)
    - g_free(ypd->id);
    - g_free(ypd->names.first);
    - g_free(ypd->names.last);
    - g_free(ypd->names.middle);
    - g_free(ypd->names.nick);
    - g_free(ypd->phone.work);
    - g_free(ypd->phone.home);
    - g_free(ypd->phone.mobile);
    -}
    -
    -/**************************************************************************
    - * Alias Fetch Functions
    - **************************************************************************/
    -
    -static void
    -yahoo_fetch_aliases_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, size_t len, const gchar *error_message)
    -{
    - PurpleConnection *gc = user_data;
    - YahooData *yd = gc->proto_data;
    -
    - yd->url_datas = g_slist_remove(yd->url_datas, url_data);
    -
    - if (len == 0) {
    - purple_debug_info("yahoo", "No Aliases to process.%s%s\n",
    - error_message ? " Error:" : "", error_message ? error_message : "");
    - } else {
    - gchar *full_name, *nick_name;
    - const char *yid, *id, *fn, *ln, *nn, *alias, *mn;
    - const char *hp, *wp, *mo;
    - YahooFriend *f;
    - PurpleBuddy *b;
    - xmlnode *item, *contacts;
    - PurpleAccount *account;
    -
    - account = purple_connection_get_account(gc);
    - /* Put our web response into a xmlnode for easy management */
    - contacts = xmlnode_from_str(url_text, -1);
    -
    - if (contacts == NULL) {
    - purple_debug_error("yahoo", "Badly formed Alias XML\n");
    - return;
    - }
    - purple_debug_info("yahoo", "Fetched %" G_GSIZE_FORMAT
    - " bytes of alias data\n", len);
    -
    - /* Loop around and around and around until we have gone through all the received aliases */
    - for(item = xmlnode_get_child(contacts, "ct"); item; item = xmlnode_get_next_twin(item)) {
    - /* Yahoo replies with two types of contact (ct) record, we are only interested in the alias ones */
    - if ((yid = xmlnode_get_attrib(item, "yi"))) {
    - YahooPersonalDetails *ypd = NULL;
    - /* Grab all the bits of information we can */
    - fn = xmlnode_get_attrib(item, "fn");
    - ln = xmlnode_get_attrib(item, "ln");
    - nn = xmlnode_get_attrib(item, "nn");
    - mn = xmlnode_get_attrib(item, "mn");
    - id = xmlnode_get_attrib(item, "id");
    -
    - hp = xmlnode_get_attrib(item, "hp");
    - wp = xmlnode_get_attrib(item, "wp");
    - mo = xmlnode_get_attrib(item, "mo");
    -
    - full_name = nick_name = NULL;
    - alias = NULL;
    -
    - /* Yahoo stores first and last names separately, lets put them together into a full name */
    - if (yd->jp)
    - full_name = g_strstrip(g_strdup_printf("%s %s", (ln != NULL ? ln : "") , (fn != NULL ? fn : "")));
    - else
    - full_name = g_strstrip(g_strdup_printf("%s %s", (fn != NULL ? fn : "") , (ln != NULL ? ln : "")));
    - nick_name = (nn != NULL ? g_strstrip(g_strdup(nn)) : NULL);
    -
    - if (nick_name != NULL)
    - alias = nick_name; /* If we have a nickname from Yahoo, let's use it */
    - else if (strlen(full_name) != 0)
    - alias = full_name; /* If no Yahoo nickname, we can use the full_name created above */
    -
    - /* Find the local buddy that matches */
    - f = yahoo_friend_find(gc, yid);
    - b = purple_find_buddy(account, yid);
    -
    - /* If we don't find a matching buddy, ignore the alias !! */
    - if (f != NULL && b != NULL) {
    - const char *buddy_alias = purple_buddy_get_alias(b);
    - yahoo_friend_set_alias_id(f, id);
    -
    - /* Finally, if we received an alias, we better update the buddy list */
    - if (alias != NULL) {
    - serv_got_alias(gc, yid, alias);
    - purple_debug_info("yahoo", "Fetched alias '%s' (%s)\n", alias, id);
    - } else if (buddy_alias && *buddy_alias && !g_str_equal(buddy_alias, yid)) {
    - /* Or if we have an alias that Yahoo doesn't, send it up */
    - yahoo_update_alias(gc, yid, buddy_alias);
    - purple_debug_info("yahoo", "Sent updated alias '%s'\n", buddy_alias);
    - }
    - }
    -
    - if (f != NULL)
    - ypd = &f->ypd;
    - else {
    - /* May be the alias is for the account? */
    - const char *yidn = purple_normalize(account, yid);
    - if (purple_strequal(yidn, purple_connection_get_display_name(gc))) {
    - ypd = &yd->ypd;
    - }
    - }
    -
    - if (ypd) {
    - yahoo_personal_details_reset(ypd, TRUE);
    - ypd->id = g_strdup(id);
    - ypd->names.first = g_strdup(fn);
    - ypd->names.middle = g_strdup(mn);
    - ypd->names.last = g_strdup(ln);
    - ypd->names.nick = g_strdup(nn);
    -
    - ypd->phone.work = g_strdup(wp);
    - ypd->phone.home = g_strdup(hp);
    - ypd->phone.mobile = g_strdup(mo);
    - }
    -
    - g_free(full_name);
    - g_free(nick_name);
    - }
    - }
    - xmlnode_free(contacts);
    - }
    -}
    -
    -void
    -yahoo_fetch_aliases(PurpleConnection *gc)
    -{
    - YahooData *yd = gc->proto_data;
    - const char *url;
    - gchar *request, *webpage, *webaddress;
    - PurpleUtilFetchUrlData *url_data;
    -
    - /* use whole URL if using HTTP Proxy */
    - gboolean use_whole_url = yahoo_account_use_http_proxy(gc);
    -
    - /* Build all the info to make the web request */
    - url = yd->jp ? YAHOOJP_ALIAS_FETCH_URL : YAHOO_ALIAS_FETCH_URL;
    - purple_url_parse(url, &webaddress, NULL, &webpage, NULL, NULL);
    - request = g_strdup_printf("GET %s%s/%s HTTP/1.1\r\n"
    - "User-Agent: " YAHOO_CLIENT_USERAGENT_ALIAS "\r\n"
    - "Cookie: T=%s; Y=%s\r\n"
    - "Host: %s\r\n"
    - "Cache-Control: no-cache\r\n\r\n",
    - use_whole_url ? "http://" : "", use_whole_url ? webaddress : "", webpage,
    - yd->cookie_t, yd->cookie_y,
    - webaddress);
    -
    - /* We have a URL and some header information, let's connect and get some aliases */
    - url_data = purple_util_fetch_url_request_len_with_account(purple_connection_get_account(gc),
    - url, use_whole_url, NULL, TRUE, request, FALSE, -1,
    - yahoo_fetch_aliases_cb, gc);
    - if (url_data != NULL)
    - yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
    -
    - g_free(webaddress);
    - g_free(webpage);
    - g_free(request);
    -}
    -
    -/**************************************************************************
    - * Alias Update Functions
    - **************************************************************************/
    -
    -static void
    -yahoo_update_alias_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, size_t len, const gchar *error_message)
    -{
    - xmlnode *node, *result;
    - struct callback_data *cb = user_data;
    - PurpleConnection *gc = cb->gc;
    - YahooData *yd;
    -
    - yd = gc->proto_data;
    - yd->url_datas = g_slist_remove(yd->url_datas, url_data);
    -
    - if (len == 0 || error_message != NULL) {
    - purple_debug_info("yahoo", "Error updating alias for %s: %s\n",
    - cb->who,
    - error_message ? error_message : "");
    - g_free(cb->who);
    - g_free(cb->id);
    - g_free(cb);
    - return;
    - }
    -
    - result = xmlnode_from_str(url_text, -1);
    -
    - if (result == NULL) {
    - purple_debug_error("yahoo", "Alias update for %s failed: Badly formed response\n",
    - cb->who);
    - g_free(cb->who);
    - g_free(cb->id);
    - g_free(cb);
    - return;
    - }
    -
    - if ((node = xmlnode_get_child(result, "ct"))) {
    - if (cb->id == NULL) {
    - const char *new_id = xmlnode_get_attrib(node, "id");
    - if (new_id != NULL) {
    - /* We now have an addressbook id for the friend; we should save it */
    - YahooFriend *f = yahoo_friend_find(cb->gc, cb->who);
    -
    - purple_debug_info("yahoo", "Alias creation for %s succeeded\n", cb->who);
    -
    - if (f)
    - yahoo_friend_set_alias_id(f, new_id);
    - else
    - purple_debug_error("yahoo", "Missing YahooFriend. Unable to store new addressbook id.\n");
    - } else
    - purple_debug_error("yahoo", "Missing new addressbook id in add response for %s (weird).\n",
    - cb->who);
    - } else {
    - if (g_ascii_strncasecmp(xmlnode_get_attrib(node, "id"), cb->id, strlen(cb->id))==0)
    - purple_debug_info("yahoo", "Alias update for %s succeeded\n", cb->who);
    - else
    - purple_debug_error("yahoo", "Alias update for %s failed (Contact record return mismatch)\n",
    - cb->who);
    - }
    - } else
    - purple_debug_info("yahoo", "Alias update for %s failed (No contact record returned)\n", cb->who);
    -
    - g_free(cb->who);
    - g_free(cb->id);
    - g_free(cb);
    - xmlnode_free(result);
    -}
    -
    -void
    -yahoo_update_alias(PurpleConnection *gc, const char *who, const char *alias)
    -{
    - YahooData *yd;
    - const char *url;
    - gchar *content, *request, *webpage, *webaddress;
    - struct callback_data *cb;
    - PurpleUtilFetchUrlData *url_data;
    - YahooFriend *f;
    - /* use whole URL if using HTTP Proxy */
    - gboolean use_whole_url = yahoo_account_use_http_proxy(gc);
    -
    - g_return_if_fail(who != NULL);
    - g_return_if_fail(gc != NULL);
    -
    - if (alias == NULL)
    - alias = "";
    -
    - f = yahoo_friend_find(gc, who);
    - if (f == NULL) {
    - purple_debug_error("yahoo", "Missing YahooFriend. Unable to set server alias.\n");
    - return;
    - }
    -
    - yd = gc->proto_data;
    -
    - /* Using callback_data so I have access to gc in the callback function */
    - cb = g_new0(struct callback_data, 1);
    - cb->who = g_strdup(who);
    - cb->id = g_strdup(yahoo_friend_get_alias_id(f));
    - cb->gc = gc;
    -
    - /* Build all the info to make the web request */
    - url = yd->jp ? YAHOOJP_ALIAS_UPDATE_URL: YAHOO_ALIAS_UPDATE_URL;
    - purple_url_parse(url, &webaddress, NULL, &webpage, NULL, NULL);
    -
    - if (cb->id == NULL) {
    - /* No id for this buddy, so create an address book entry */
    - purple_debug_info("yahoo", "Creating '%s' as new alias for user '%s'\n", alias, who);
    -
    - if (yd->jp) {
    - gchar *alias_jp = g_convert(alias, -1, "EUC-JP", "UTF-8", NULL, NULL, NULL);
    - gchar *converted_alias_jp = yahoo_convert_to_numeric(alias_jp);
    - content = g_strdup_printf("<ab k=\"%s\" cc=\"9\">\n"
    - "<ct a=\"1\" yi='%s' nn='%s' />\n</ab>\r\n",
    - purple_account_get_username(gc->account),
    - who, converted_alias_jp);
    - g_free(converted_alias_jp);
    - g_free(alias_jp);
    - } else {
    - gchar *escaped_alias = g_markup_escape_text(alias, -1);
    - content = g_strdup_printf("<?xml version=\"1.0\" encoding=\"utf-8\"?><ab k=\"%s\" cc=\"9\">\n"
    - "<ct a=\"1\" yi='%s' nn='%s' />\n</ab>\r\n",
    - purple_account_get_username(gc->account),
    - who, escaped_alias);
    - g_free(escaped_alias);
    - }
    - } else {
    - purple_debug_info("yahoo", "Updating '%s' as new alias for user '%s'\n", alias, who);
    -
    - if (yd->jp) {
    - gchar *alias_jp = g_convert(alias, -1, "EUC-JP", "UTF-8", NULL, NULL, NULL);
    - gchar *converted_alias_jp = yahoo_convert_to_numeric(alias_jp);
    - content = g_strdup_printf("<ab k=\"%s\" cc=\"1\">\n"
    - "<ct e=\"1\" yi='%s' id='%s' nn='%s' pr='0' />\n</ab>\r\n",
    - purple_account_get_username(gc->account),
    - who, cb->id, converted_alias_jp);
    - g_free(converted_alias_jp);
    - g_free(alias_jp);
    - } else {
    - gchar *escaped_alias = g_markup_escape_text(alias, -1);
    - content = g_strdup_printf("<?xml version=\"1.0\" encoding=\"utf-8\"?><ab k=\"%s\" cc=\"1\">\n"
    - "<ct e=\"1\" yi='%s' id='%s' nn='%s' pr='0' />\n</ab>\r\n",
    - purple_account_get_username(gc->account),
    - who, cb->id, escaped_alias);
    - g_free(escaped_alias);
    - }
    - }
    -
    - request = g_strdup_printf("POST %s%s/%s HTTP/1.1\r\n"
    - "User-Agent: " YAHOO_CLIENT_USERAGENT_ALIAS "\r\n"
    - "Cookie: T=%s; Y=%s\r\n"
    - "Host: %s\r\n"
    - "Content-Length: %" G_GSIZE_FORMAT "\r\n"
    - "Cache-Control: no-cache\r\n\r\n"
    - "%s",
    - use_whole_url ? "http://" : "", use_whole_url ? webaddress : "", webpage,
    - yd->cookie_t, yd->cookie_y,
    - webaddress,
    - strlen(content),
    - content);
    -
    - /* We have a URL and some header information, let's connect and update the alias */
    - url_data = purple_util_fetch_url_request_len_with_account(
    - purple_connection_get_account(gc), url, use_whole_url, NULL, TRUE,
    - request, FALSE, -1, yahoo_update_alias_cb, cb);
    - if (url_data != NULL)
    - yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
    -
    - g_free(webpage);
    - g_free(webaddress);
    - g_free(content);
    - g_free(request);
    -}
    -
    -
    -/**************************************************************************
    - * User Info Update Functions
    - **************************************************************************/
    -
    -#if 0
    -/* This block of code can be used to send our contact details to
    - * everyone in the buddylist. But with the official messenger,
    - * doing this pops a conversation window at the receiver's end,
    - * which is stupid, and thus not really surprising. */
    -
    -struct yahoo_userinfo {
    - YahooData *yd;
    - char *xml;
    -};
    -
    -static void
    -yahoo_send_userinfo_to_user(struct yahoo_userinfo *yui, const char *who)
    -{
    - struct yahoo_packet *pkt;
    - PurpleConnection *gc;
    -
    - gc = yui->yd->gc;
    - pkt = yahoo_packet_new(YAHOO_SERVICE_CONTACT_DETAILS, 0, 0);
    - yahoo_packet_hash(pkt, "siisis",
    - 1, purple_connection_get_display_name(gc),
    - 13, 1, /* This creates a conversation window in the official client */
    - 302, 5,
    - 5, who,
    - 303, 5,
    - 280, yui->xml);
    - yahoo_packet_send_and_free(pkt, yui->yd);
    -}
    -
    -static void
    -yahoo_send_userinfo_foreach(gpointer key, gpointer value, gpointer data)
    -{
    - const char *who = key;
    - YahooFriend *f = value;
    -
    - if (f->status != YAHOO_STATUS_OFFLINE) {
    - yahoo_send_userinfo_to_user(data, who);
    - }
    -}
    -
    -static void
    -yahoo_sent_userinfo_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, size_t len, const gchar *error_message)
    -{
    - struct yahoo_userinfo *yui = user_data;
    - yahoo_fetch_aliases_cb(url_data, yui->yd->gc, url_text, len, error_message);
    - g_hash_table_foreach(yui->yd->friends, yahoo_send_userinfo_foreach, yui);
    - g_free(yui->xml);
    - g_free(yui);
    -}
    -#endif
    -
    -static void
    -yahoo_set_userinfo_cb(PurpleConnection *gc, PurpleRequestFields *fields)
    -{
    - xmlnode *node = xmlnode_new("ab");
    - xmlnode *ct = xmlnode_new_child(node, "ct");
    - YahooData *yd = purple_connection_get_protocol_data(gc);
    - PurpleAccount *account;
    - PurpleUtilFetchUrlData *url_data;
    - char *webaddress, *webpage;
    - char *request, *content;
    - int len;
    - int i;
    - char * yfields[] = { "fn", "ln", "nn", "mn", "hp", "wp", "mo", NULL };
    -
    - account = purple_connection_get_account(gc);
    -
    - xmlnode_set_attrib(node, "k", purple_connection_get_display_name(gc));
    - xmlnode_set_attrib(node, "cc", "1"); /* XXX: ? */
    -
    - xmlnode_set_attrib(ct, "e", "1");
    - xmlnode_set_attrib(ct, "yi", purple_request_fields_get_string(fields, "yname"));
    - xmlnode_set_attrib(ct, "id", purple_request_fields_get_string(fields, "yid"));
    - xmlnode_set_attrib(ct, "pr", "0");
    -
    - for (i = 0; yfields[i]; i++) {
    - const char *v = purple_request_fields_get_string(fields, yfields[i]);
    - xmlnode_set_attrib(ct, yfields[i], v ? v : "");
    - }
    -
    - content = xmlnode_to_formatted_str(node, &len);
    - xmlnode_free(node);
    - purple_url_parse(yd->jp ? YAHOOJP_USERINFO_URL : YAHOO_USERINFO_URL, &webaddress, NULL, &webpage, NULL, NULL);
    -
    - request = g_strdup_printf("POST %s HTTP/1.1\r\n"
    - "User-Agent: " YAHOO_CLIENT_USERAGENT_ALIAS "\r\n"
    - "Cookie: T=%s; path=/; domain=.yahoo.com; Y=%s;\r\n"
    - "Host: %s\r\n"
    - "Content-Length: %d\r\n"
    - "Cache-Control: no-cache\r\n\r\n"
    - "%s\r\n\r\n",
    - webpage,
    - yd->cookie_t, yd->cookie_y,
    - webaddress,
    - len + 4,
    - content);
    -
    -#if 0
    - {
    - /* This is if we wanted to send our contact details to everyone
    - * in the buddylist. But this cannot be done now, because in the
    - * official messenger, doing this pops a conversation window at
    - * the receiver's end, which is stupid, and thus not really
    - * surprising. */
    - struct yahoo_userinfo *ui = g_new(struct yahoo_userinfo, 1);
    - node = xmlnode_new("contact");
    -
    - for (i = 0; yfields[i]; i++) {
    - const char *v = purple_request_fields_get_string(fields, yfields[i]);
    - if (v) {
    - xmlnode *nd = xmlnode_new_child(node, yfields[i]);
    - xmlnode_insert_data(nd, v, -1);
    - }
    - }
    -
    - ui->yd = yd;
    - ui->xml = xmlnode_to_str(node, NULL);
    - xmlnode_free(node);
    - }
    -#endif
    -
    - url_data = purple_util_fetch_url_request_len_with_account(account, webaddress, FALSE,
    - YAHOO_CLIENT_USERAGENT_ALIAS, TRUE, request, FALSE, -1,
    - yahoo_fetch_aliases_cb, gc);
    - if (url_data != NULL)
    - yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
    -
    - g_free(webaddress);
    - g_free(webpage);
    - g_free(content);
    - g_free(request);
    -}
    -
    -static PurpleRequestFields *
    -request_fields_from_personal_details(YahooPersonalDetails *ypd, const char *id)
    -{
    - PurpleRequestFields *fields;
    - PurpleRequestFieldGroup *group;
    - PurpleRequestField *field;
    - int i;
    - struct {
    - char *id;
    - char *text;
    - char *value;
    - } yfields[] = {
    - {"fn", N_("First Name"), ypd->names.first},
    - {"ln", N_("Last Name"), ypd->names.last},
    - {"nn", N_("Nickname"), ypd->names.nick},
    - {"mn", N_("Middle Name"), ypd->names.middle},
    - {"hp", N_("Home Phone Number"), ypd->phone.home},
    - {"wp", N_("Work Phone Number"), ypd->phone.work},
    - {"mo", N_("Mobile Phone Number"), ypd->phone.mobile},
    - {NULL, NULL, NULL}
    - };
    -
    - fields = purple_request_fields_new();
    - group = purple_request_field_group_new(NULL);
    - purple_request_fields_add_group(fields, group);
    -
    - field = purple_request_field_string_new("yname", "", id, FALSE);
    - purple_request_field_set_visible(field, FALSE);
    - purple_request_field_group_add_field(group, field);
    -
    - field = purple_request_field_string_new("yid", "", ypd->id, FALSE);
    - purple_request_field_set_visible(field, FALSE);
    - purple_request_field_group_add_field(group, field);
    -
    - for (i = 0; yfields[i].id; i++) {
    - field = purple_request_field_string_new(yfields[i].id, _(yfields[i].text),
    - yfields[i].value, FALSE);
    - purple_request_field_group_add_field(group, field);
    - }
    -
    - return fields;
    -}
    -
    -void yahoo_set_userinfo_for_buddy(PurpleConnection *gc, PurpleBuddy *buddy)
    -{
    - PurpleRequestFields *fields;
    - YahooFriend *f;
    - const char *name;
    -
    - name = purple_buddy_get_name(buddy);
    - f = yahoo_friend_find(gc, name);
    - if (!f)
    - return;
    -
    - fields = request_fields_from_personal_details(&f->ypd, name);
    - purple_request_fields(gc, NULL, _("Set User Info"), NULL, fields,
    - _("OK"), G_CALLBACK(yahoo_set_userinfo_cb),
    - _("Cancel"), NULL,
    - purple_connection_get_account(gc), NULL, NULL, gc);
    -}
    -
    -void yahoo_set_userinfo(PurpleConnection *gc)
    -{
    - YahooData *yd = purple_connection_get_protocol_data(gc);
    - PurpleRequestFields *fields = request_fields_from_personal_details(&yd->ypd,
    - purple_connection_get_display_name(gc));
    - purple_request_fields(gc, NULL, _("Set User Info"), NULL, fields,
    - _("OK"), G_CALLBACK(yahoo_set_userinfo_cb),
    - _("Cancel"), NULL,
    - purple_connection_get_account(gc), NULL, NULL, gc);
    -}
    -
    -static gboolean
    -parse_contact_details(YahooData *yd, const char *who, const char *xml)
    -{
    - xmlnode *node, *nd;
    - YahooFriend *f;
    - char *yid;
    -
    - node = xmlnode_from_str(xml, -1);
    - if (!node) {
    - purple_debug_info("yahoo", "Received malformed XML for contact details from '%s':\n%s\n",
    - who, xml);
    - return FALSE;
    - }
    -
    - nd = xmlnode_get_child(node, "yi");
    - if (!nd || !(yid = xmlnode_get_data(nd))) {
    - xmlnode_free(node);
    - return FALSE;
    - }
    -
    - if (!purple_strequal(yid, who)) {
    - /* The user may not want to set the contact details about folks in the buddylist
    - to what some random dude might have sent. So it would be good if we popped
    - up a prompt requiring the user to confirm the details before we set them.
    - However, someone could send details about hundreds of users at the same time,
    - which would make things really bad. So for now, until we have a better way of
    - dealing with this, ignore this details. */
    - purple_debug_info("yahoo", "Ignoring contact details sent by %s about %s\n",
    - who, yid);
    - g_free(yid);
    - xmlnode_free(node);
    - return FALSE;
    - }
    -
    - f = yahoo_friend_find(yd->gc, yid);
    - if (!f) {
    - g_free(yid);
    - xmlnode_free(node);
    - return FALSE;
    - } else {
    - int i;
    - YahooPersonalDetails *ypd = &f->ypd;
    - char *alias = NULL;
    - struct {
    - char *id;
    - char **field;
    - } details[] = {
    - {"fn", &ypd->names.first},
    - {"mn", &ypd->names.middle},
    - {"ln", &ypd->names.last},
    - {"nn", &ypd->names.nick},
    - {"wp", &ypd->phone.work},
    - {"hp", &ypd->phone.home},
    - {"mo", &ypd->phone.mobile},
    - {NULL, NULL}
    - };
    -
    - yahoo_personal_details_reset(ypd, FALSE);
    -
    - for (i = 0; details[i].id; i++) {
    - nd = xmlnode_get_child(node, details[i].id);
    - *details[i].field = nd ? xmlnode_get_data(nd) : NULL;
    - }
    -
    - if (ypd->names.nick)
    - alias = ypd->names.nick;
    - else if (ypd->names.first || ypd->names.last) {
    - alias = g_strstrip(g_strdup_printf("%s %s",
    - ypd->names.first ? ypd->names.first : "",
    - ypd->names.last ? ypd->names.last : ""));
    - }
    -
    - if (alias) {
    - serv_got_alias(yd->gc, yid, alias);
    - if (alias != ypd->names.nick)
    - g_free(alias);
    - }
    - }
    -
    - xmlnode_free(node);
    - g_free(yid);
    - return TRUE;
    -}
    -
    -/* I don't think this happens for MSN buddies. -- sad */
    -void yahoo_process_contact_details(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - GSList *l = pkt->hash;
    - const char *who = NULL, *xml = NULL;
    - YahooData *yd = purple_connection_get_protocol_data(gc);
    -
    - for (; l; l = l->next) {
    - struct yahoo_pair *pair = l->data;
    - switch (pair->key) {
    - case 4:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - /* This is the person who sent us the details.
    - But not necessarily about himself. */
    - who = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_contact_details "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 5:
    - break;
    - case 13:
    - /* This is '1' if 'who' is sending the contact details about herself,
    - '0' if 'who' is sending the contact details she has about buddies
    - in her list. However, in all cases, the xml in key 280 always seems
    - to contain the yid of the person, so we may as well ignore this field
    - and look into the xml instead to see who the information is about. */
    - break;
    - case 280:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - xml = pair->value;
    - parse_contact_details(yd, who, xml);
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_contact_details "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - }
    - }
    -}
    -
    --- a/libpurple/protocols/yahoo/yahoo_aliases.h Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,41 +0,0 @@
    -/*
    - * purple
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * This program is free software; you can redistribute it and/or modify
    - * it under the terms of the GNU General Public License as published by
    - * the Free Software Foundation; either version 2 of the License, or
    - * (at your option) any later version.
    - *
    - * This program is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    - * GNU General Public License for more details.
    - *
    - * You should have received a copy of the GNU General Public License
    - * along with this program; if not, write to the Free Software
    - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    - *
    - */
    -
    -
    -#include "internal.h"
    -
    -#include "account.h"
    -#include "accountopt.h"
    -#include "blist.h"
    -#include "debug.h"
    -#include "util.h"
    -#include "version.h"
    -#include "libymsg.h"
    -#include "yahoo_packet.h"
    -
    -void yahoo_update_alias(PurpleConnection *gc, const char *who, const char *alias);
    -void yahoo_fetch_aliases(PurpleConnection *gc);
    -void yahoo_set_userinfo(PurpleConnection *gc);
    -void yahoo_set_userinfo_for_buddy(PurpleConnection *gc, PurpleBuddy *buddy);
    -void yahoo_personal_details_reset(YahooPersonalDetails *ypd, gboolean all);
    -void yahoo_process_contact_details(PurpleConnection *gc, struct yahoo_packet *pkt);
    --- a/libpurple/protocols/yahoo/yahoo_doodle.c Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,609 +0,0 @@
    -/*
    - * purple
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * This program is free software; you can redistribute it and/or modify
    - * it under the terms of the GNU General Public License as published by
    - * the Free Software Foundation; either version 2 of the License, or
    - * (at your option) any later version.
    - *
    - * This program is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    - * GNU General Public License for more details.
    - *
    - * You should have received a copy of the GNU General Public License
    - * along with this program; if not, write to the Free Software
    - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    - *
    - */
    -
    -/******************************************************************************
    - * INCLUDES
    - *****************************************************************************/
    -#include "internal.h"
    -
    -#include "account.h"
    -#include "accountopt.h"
    -#include "blist.h"
    -#include "cipher.h"
    -#include "cmds.h"
    -#include "debug.h"
    -#include "notify.h"
    -#include "privacy.h"
    -#include "prpl.h"
    -#include "proxy.h"
    -#include "request.h"
    -#include "server.h"
    -#include "util.h"
    -#include "version.h"
    -
    -#include "libymsg.h"
    -#include "yahoo_packet.h"
    -#include "yahoo_friend.h"
    -#include "yahoochat.h"
    -#include "ycht.h"
    -#include "yahoo_filexfer.h"
    -#include "yahoo_picture.h"
    -
    -#include "whiteboard.h"
    -#include "yahoo_doodle.h"
    -
    -/******************************************************************************
    - * Globals
    - *****************************************************************************/
    -#if 0
    -const int DefaultColorRGB24[] =
    -{
    - DOODLE_COLOR_RED,
    - DOODLE_COLOR_ORANGE,
    - DOODLE_COLOR_YELLOW,
    - DOODLE_COLOR_GREEN,
    - DOODLE_COLOR_CYAN,
    - DOODLE_COLOR_BLUE,
    - DOODLE_COLOR_VIOLET,
    - DOODLE_COLOR_PURPLE,
    - DOODLE_COLOR_TAN,
    - DOODLE_COLOR_BROWN,
    - DOODLE_COLOR_BLACK,
    - DOODLE_COLOR_GREY,
    - DOODLE_COLOR_WHITE
    -};
    -#endif
    -
    -/******************************************************************************
    - * Functions
    - *****************************************************************************/
    -PurpleCmdRet yahoo_doodle_purple_cmd_start(PurpleConversation *conv, const char *cmd, char **args, char **error, void *data)
    -{
    - PurpleAccount *account;
    - PurpleConnection *gc;
    - const gchar *name;
    -
    - if(*args && args[0])
    - return PURPLE_CMD_RET_FAILED;
    -
    - account = purple_conversation_get_account(conv);
    - gc = purple_account_get_connection(account);
    - name = purple_conversation_get_name(conv);
    - yahoo_doodle_initiate(gc, name);
    -
    - /* Write a local message to this conversation showing that a request for a
    - * Doodle session has been made
    - */
    - purple_conv_im_write(PURPLE_CONV_IM(conv), "", _("Sent Doodle request."),
    - PURPLE_MESSAGE_NICK | PURPLE_MESSAGE_RECV, time(NULL));
    -
    - return PURPLE_CMD_RET_OK;
    -}
    -
    -void yahoo_doodle_initiate(PurpleConnection *gc, const char *name)
    -{
    - PurpleAccount *account;
    - char *to = (char*)name;
    -
    - g_return_if_fail(gc);
    - g_return_if_fail(name);
    -
    - account = purple_connection_get_account(gc);
    -
    - if(purple_whiteboard_get_session(account, to) == NULL)
    - {
    - /* Insert this 'session' in the list. At this point, it's only a
    - * requested session.
    - */
    - purple_whiteboard_create(account, to, DOODLE_STATE_REQUESTING);
    - }
    -
    - /* NOTE Perhaps some careful handling of remote assumed established
    - * sessions
    - */
    -
    - yahoo_doodle_command_send_ready(gc, to, DOODLE_IMV_KEY);
    - yahoo_doodle_command_send_request(gc, to, DOODLE_IMV_KEY);
    -
    -}
    -
    -static void yahoo_doodle_command_got_request(PurpleConnection *gc, const char *from, const char *imv_key)
    -{
    - PurpleAccount *account;
    - PurpleWhiteboard *wb;
    -
    - purple_debug_info("yahoo", "doodle: Got Request (%s)\n", from);
    -
    - account = purple_connection_get_account(gc);
    -
    - /* Only handle this if local client requested Doodle session (else local
    - * client would have sent one)
    - */
    - wb = purple_whiteboard_get_session(account, from);
    -
    - /* If a session with the remote user doesn't exist */
    - if(wb == NULL)
    - {
    - doodle_session *ds;
    - /* Ask user if they wish to accept the request for a doodle session */
    - /* TODO Ask local user to start Doodle session with remote user */
    - /* NOTE This if/else statement won't work right--must use dialog
    - * results
    - */
    -
    - /* char dialog_message[64];
    - g_sprintf(dialog_message, "%s is requesting to start a Doodle session with you.", from);
    -
    - purple_notify_message(NULL, PURPLE_NOTIFY_MSG_INFO, "Doodle",
    - dialog_message, NULL, NULL, NULL);
    - */
    -
    - wb = purple_whiteboard_create(account, from, DOODLE_STATE_REQUESTED);
    - ds = wb->proto_data;
    - ds->imv_key = g_strdup(imv_key);
    -
    - yahoo_doodle_command_send_ready(gc, from, imv_key);
    - }
    -
    - /* TODO Might be required to clear the canvas of an existing doodle
    - * session at this point
    - */
    -}
    -
    -static void yahoo_doodle_command_got_ready(PurpleConnection *gc, const char *from, const char *imv_key)
    -{
    - PurpleAccount *account;
    - PurpleWhiteboard *wb;
    -
    - purple_debug_info("yahoo", "doodle: Got Ready(%s)\n", from);
    -
    - account = purple_connection_get_account(gc);
    -
    - /* Only handle this if local client requested Doodle session (else local
    - * client would have sent one)
    - */
    - wb = purple_whiteboard_get_session(account, from);
    -
    - if(wb == NULL)
    - return;
    -
    - if(wb->state == DOODLE_STATE_REQUESTING)
    - {
    - doodle_session *ds = wb->proto_data;
    - purple_whiteboard_start(wb);
    -
    - wb->state = DOODLE_STATE_ESTABLISHED;
    -
    - yahoo_doodle_command_send_confirm(gc, from, imv_key);
    - /* Let's steal the imv_key and reuse it */
    - g_free(ds->imv_key);
    - ds->imv_key = g_strdup(imv_key);
    - }
    - else if(wb->state == DOODLE_STATE_ESTABLISHED)
    - {
    - /* TODO Ask whether to save picture too */
    - purple_whiteboard_clear(wb);
    - }
    -
    - /* NOTE Not sure about this... I am trying to handle if the remote user
    - * already thinks we're in a session with them (when their chat message
    - * contains the doodle imv key)
    - */
    - else if(wb->state == DOODLE_STATE_REQUESTED)
    - {
    - /* purple_whiteboard_start(wb); */
    - yahoo_doodle_command_send_ready(gc, from, imv_key);
    - }
    -}
    -
    -static void yahoo_doodle_command_got_draw(PurpleConnection *gc, const char *from, const char *message)
    -{
    - PurpleAccount *account;
    - PurpleWhiteboard *wb;
    - char **tokens;
    - int i;
    - GList *d_list = NULL; /* a local list of drawing info */
    -
    - g_return_if_fail(message != NULL);
    -
    - purple_debug_info("yahoo", "doodle: Got Draw (%s)\n", from);
    - purple_debug_info("yahoo", "doodle: Draw message: %s\n", message);
    -
    - account = purple_connection_get_account(gc);
    -
    - /* Only handle this if local client requested Doodle session (else local
    - * client would have sent one)
    - */
    - wb = purple_whiteboard_get_session(account, from);
    -
    - if(wb == NULL)
    - return;
    -
    - /* TODO Functionalize
    - * Convert drawing packet message to an integer list
    - */
    -
    - /* Check to see if the message begans and ends with quotes */
    - if((message[0] != '\"') || (message[strlen(message) - 1] != '\"'))
    - return;
    -
    - /* Ignore the inital quotation mark. */
    - message += 1;
    -
    - tokens = g_strsplit(message, ",", 0);
    -
    - /* Traverse and extract all integers divided by commas */
    - for (i = 0; tokens[i] != NULL; i++)
    - {
    - int last = strlen(tokens[i]) - 1;
    - if (tokens[i][last] == '"')
    - tokens[i][last] = '\0';
    -
    - d_list = g_list_prepend(d_list, GINT_TO_POINTER(atoi(tokens[i])));
    - }
    - d_list = g_list_reverse(d_list);
    -
    - g_strfreev(tokens);
    -
    - yahoo_doodle_draw_stroke(wb, d_list);
    -
    - /* goodle_doodle_session_set_canvas_as_icon(ds); */
    -
    - g_list_free(d_list);
    -}
    -
    -
    -static void yahoo_doodle_command_got_clear(PurpleConnection *gc, const char *from)
    -{
    - PurpleAccount *account;
    - PurpleWhiteboard *wb;
    -
    - purple_debug_info("yahoo", "doodle: Got Clear (%s)\n", from);
    -
    - account = purple_connection_get_account(gc);
    -
    - /* Only handle this if local client requested Doodle session (else local
    - * client would have sent one)
    - */
    - wb = purple_whiteboard_get_session(account, from);
    -
    - if(wb == NULL)
    - return;
    -
    - if(wb->state == DOODLE_STATE_ESTABLISHED)
    - {
    - /* TODO Ask user whether to save the image before clearing it */
    -
    - purple_whiteboard_clear(wb);
    - }
    -}
    -
    -
    -static void
    -yahoo_doodle_command_got_extra(PurpleConnection *gc, const char *from, const char *message, const char *imv_key)
    -{
    - purple_debug_info("yahoo", "doodle: Got Extra (%s)\n", from);
    -
    - /* I do not like these 'extra' features, so I'll only handle them in one
    - * way, which is returning them with the command/packet to turn them off
    - */
    - yahoo_doodle_command_send_extra(gc, from, DOODLE_EXTRA_NONE, imv_key);
    -}
    -
    -static void yahoo_doodle_command_got_confirm(PurpleConnection *gc, const char *from)
    -{
    - PurpleAccount *account;
    - PurpleWhiteboard *wb;
    -
    - purple_debug_info("yahoo", "doodle: Got Confirm (%s)\n", from);
    -
    - /* Get the doodle session */
    - account = purple_connection_get_account(gc);
    -
    - /* Only handle this if local client requested Doodle session (else local
    - * client would have sent one)
    - */
    - wb = purple_whiteboard_get_session(account, from);
    -
    - if(wb == NULL)
    - return;
    -
    - /* TODO Combine the following IF's? */
    -
    - /* Check if we requested a doodle session */
    - /*if(wb->state == DOODLE_STATE_REQUESTING)
    - {
    - wb->state = DOODLE_STATE_ESTABLISHED;
    -
    - purple_whiteboard_start(wb);
    -
    - yahoo_doodle_command_send_confirm(gc, from);
    - }*/
    -
    - /* Check if we accepted a request for a doodle session */
    - if(wb->state == DOODLE_STATE_REQUESTED)
    - {
    - wb->state = DOODLE_STATE_ESTABLISHED;
    -
    - purple_whiteboard_start(wb);
    - }
    -}
    -
    -void yahoo_doodle_command_got_shutdown(PurpleConnection *gc, const char *from)
    -{
    - PurpleAccount *account;
    - PurpleWhiteboard *wb;
    -
    - g_return_if_fail(from != NULL);
    -
    - purple_debug_info("yahoo", "doodle: Got Shutdown (%s)\n", from);
    -
    - account = purple_connection_get_account(gc);
    -
    - /* Only handle this if local client requested Doodle session (else local
    - * client would have sent one)
    - */
    - wb = purple_whiteboard_get_session(account, from);
    -
    - if(wb == NULL)
    - return;
    -
    - /* TODO Ask if user wants to save picture before the session is closed */
    -
    - wb->state = DOODLE_STATE_CANCELLED;
    - purple_whiteboard_destroy(wb);
    -}
    -
    -static void yahoo_doodle_command_send_generic(const char *type,
    - PurpleConnection *gc,
    - const char *to,
    - const char *message,
    - int command,
    - const char *imv,
    - const char *sixtyfour)
    -{
    - YahooData *yd;
    - struct yahoo_packet *pkt;
    -
    - purple_debug_info("yahoo", "doodle: Sent %s (%s)\n", type, to);
    -
    - yd = gc->proto_data;
    -
    - /* Make and send an acknowledge (ready) Doodle packet */
    - pkt = yahoo_packet_new(YAHOO_SERVICE_P2PFILEXFER, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash_str(pkt, 49, "IMVIRONMENT");
    - yahoo_packet_hash_str(pkt, 1, purple_account_get_username(gc->account));
    - yahoo_packet_hash_str(pkt, 14, message);
    - yahoo_packet_hash_int(pkt, 13, command);
    - yahoo_packet_hash_str(pkt, 5, to);
    - yahoo_packet_hash_str(pkt, 63, imv ? imv : DOODLE_IMV_KEY);
    - yahoo_packet_hash_str(pkt, 64, sixtyfour);
    - yahoo_packet_hash_str(pkt, 1002, "1");
    -
    - yahoo_packet_send_and_free(pkt, yd);
    -}
    -
    -void yahoo_doodle_command_send_ready(PurpleConnection *gc, const char *to, const char *imv_key)
    -{
    - yahoo_doodle_command_send_generic("Ready", gc, to, "1", DOODLE_CMD_READY, imv_key, "1");
    -}
    -
    -void yahoo_doodle_command_send_request(PurpleConnection *gc, const char *to, const char *imv_key)
    -{
    - yahoo_doodle_command_send_generic("Request", gc, to, "", DOODLE_CMD_REQUEST, imv_key, "0");
    -}
    -
    -void yahoo_doodle_command_send_draw(PurpleConnection *gc, const char *to, const char *message, const char *imv_key)
    -{
    - yahoo_doodle_command_send_generic("Draw", gc, to, message, DOODLE_CMD_DRAW, imv_key, "1");
    -}
    -
    -void yahoo_doodle_command_send_clear(PurpleConnection *gc, const char *to, const char *imv_key)
    -{
    - yahoo_doodle_command_send_generic("Clear", gc, to, " ", DOODLE_CMD_CLEAR, imv_key, "1");
    -}
    -
    -void yahoo_doodle_command_send_extra(PurpleConnection *gc, const char *to, const char *message, const char *imv_key)
    -{
    - yahoo_doodle_command_send_generic("Extra", gc, to, message, DOODLE_CMD_EXTRA, imv_key, "1");
    -}
    -
    -void yahoo_doodle_command_send_confirm(PurpleConnection *gc, const char *to, const char *imv_key)
    -{
    - yahoo_doodle_command_send_generic("Confirm", gc, to, "1", DOODLE_CMD_CONFIRM, imv_key, "1");
    -}
    -
    -void yahoo_doodle_command_send_shutdown(PurpleConnection *gc, const char *to)
    -{
    - yahoo_doodle_command_send_generic("Shutdown", gc, to, "", DOODLE_CMD_SHUTDOWN, ";0", "0");
    -}
    -
    -void yahoo_doodle_start(PurpleWhiteboard *wb)
    -{
    - doodle_session *ds = g_new0(doodle_session, 1);
    -
    - /* purple_debug_debug("yahoo", "doodle: yahoo_doodle_start()\n"); */
    -
    - /* Set default brush size and color */
    - ds->brush_size = DOODLE_BRUSH_SMALL;
    - ds->brush_color = DOODLE_COLOR_RED;
    -
    - wb->proto_data = ds;
    -}
    -
    -void yahoo_doodle_end(PurpleWhiteboard *wb)
    -{
    - PurpleConnection *gc = purple_account_get_connection(wb->account);
    - doodle_session *ds = wb->proto_data;
    -
    - /* g_debug_debug("yahoo", "doodle: yahoo_doodle_end()\n"); */
    -
    - if (gc && wb->state != DOODLE_STATE_CANCELLED)
    - yahoo_doodle_command_send_shutdown(gc, wb->who);
    -
    - g_free(ds->imv_key);
    - g_free(wb->proto_data);
    -}
    -
    -void yahoo_doodle_get_dimensions(const PurpleWhiteboard *wb, int *width, int *height)
    -{
    - /* standard Doodle canvases are of one size: 368x256 */
    - *width = DOODLE_CANVAS_WIDTH;
    - *height = DOODLE_CANVAS_HEIGHT;
    -}
    -
    -static char *yahoo_doodle_build_draw_string(doodle_session *ds, GList *draw_list)
    -{
    - GString *message;
    -
    - g_return_val_if_fail(draw_list != NULL, NULL);
    -
    - message = g_string_new("");
    - g_string_printf(message, "\"%d,%d", ds->brush_color, ds->brush_size);
    -
    - for(; draw_list != NULL; draw_list = draw_list->next)
    - {
    - g_string_append_printf(message, ",%d", GPOINTER_TO_INT(draw_list->data));
    - }
    - g_string_append_c(message, '"');
    -
    - return g_string_free(message, FALSE);
    -}
    -
    -void yahoo_doodle_send_draw_list(PurpleWhiteboard *wb, GList *draw_list)
    -{
    - doodle_session *ds = wb->proto_data;
    - char *message;
    -
    - g_return_if_fail(draw_list != NULL);
    -
    - message = yahoo_doodle_build_draw_string(ds, draw_list);
    - yahoo_doodle_command_send_draw(wb->account->gc, wb->who, message, ds->imv_key);
    - g_free(message);
    -}
    -
    -void yahoo_doodle_clear(PurpleWhiteboard *wb)
    -{
    - doodle_session *ds = wb->proto_data;
    - yahoo_doodle_command_send_clear(wb->account->gc, wb->who, ds->imv_key);
    -}
    -
    -
    -/* Traverse through the list and draw the points and lines */
    -void yahoo_doodle_draw_stroke(PurpleWhiteboard *wb, GList *draw_list)
    -{
    - int brush_color;
    - int brush_size;
    - int x;
    - int y;
    -
    - g_return_if_fail(draw_list != NULL);
    -
    - brush_color = GPOINTER_TO_INT(draw_list->data);
    - draw_list = draw_list->next;
    - g_return_if_fail(draw_list != NULL);
    -
    - brush_size = GPOINTER_TO_INT(draw_list->data);
    - draw_list = draw_list->next;
    - g_return_if_fail(draw_list != NULL);
    -
    - x = GPOINTER_TO_INT(draw_list->data);
    - draw_list = draw_list->next;
    - g_return_if_fail(draw_list != NULL);
    -
    - y = GPOINTER_TO_INT(draw_list->data);
    - draw_list = draw_list->next;
    - g_return_if_fail(draw_list != NULL);
    -
    - /*
    - purple_debug_debug("yahoo", "doodle: Drawing: color=%d, size=%d, (%d,%d)\n", brush_color, brush_size, x, y);
    - */
    -
    - while(draw_list != NULL && draw_list->next != NULL)
    - {
    - int dx = GPOINTER_TO_INT(draw_list->data);
    - int dy = GPOINTER_TO_INT(draw_list->next->data);
    -
    - purple_whiteboard_draw_line(wb,
    - x, y,
    - x + dx, y + dy,
    - brush_color, brush_size);
    -
    - x += dx;
    - y += dy;
    -
    - draw_list = draw_list->next->next;
    - }
    -}
    -
    -void yahoo_doodle_get_brush(const PurpleWhiteboard *wb, int *size, int *color)
    -{
    - doodle_session *ds = wb->proto_data;
    - *size = ds->brush_size;
    - *color = ds->brush_color;
    -}
    -
    -void yahoo_doodle_set_brush(PurpleWhiteboard *wb, int size, int color)
    -{
    - doodle_session *ds = wb->proto_data;
    - ds->brush_size = size;
    - ds->brush_color = color;
    -
    - /* Notify the core about the changes */
    - purple_whiteboard_set_brush(wb, size, color);
    -}
    -
    -void yahoo_doodle_process(PurpleConnection *gc, const char *me, const char *from,
    - const char *command, const char *message, const char *imv_key)
    -{
    - if(!command)
    - return;
    -
    - /* Now check to see what sort of Doodle message it is */
    - switch(atoi(command))
    - {
    - case DOODLE_CMD_REQUEST:
    - yahoo_doodle_command_got_request(gc, from, imv_key);
    - break;
    -
    - case DOODLE_CMD_READY:
    - yahoo_doodle_command_got_ready(gc, from, imv_key);
    - break;
    -
    - case DOODLE_CMD_CLEAR:
    - yahoo_doodle_command_got_clear(gc, from);
    - break;
    -
    - case DOODLE_CMD_DRAW:
    - yahoo_doodle_command_got_draw(gc, from, message);
    - break;
    -
    - case DOODLE_CMD_EXTRA:
    - yahoo_doodle_command_got_extra(gc, from, message, imv_key);
    - break;
    -
    - case DOODLE_CMD_CONFIRM:
    - yahoo_doodle_command_got_confirm(gc, from);
    - break;
    - }
    -}
    --- a/libpurple/protocols/yahoo/yahoo_doodle.h Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,131 +0,0 @@
    -/**
    - * @file yahoo_doodle.h The Yahoo! protocol plugin Doodle IMVironment object
    - *
    - * purple
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * This program is free software; you can redistribute it and/or modify
    - * it under the terms of the GNU General Public License as published by
    - * the Free Software Foundation; either version 2 of the License, or
    - * (at your option) any later version.
    - *
    - * This program is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    - * GNU General Public License for more details.
    - *
    - * You should have received a copy of the GNU General Public License
    - * along with this program; if not, write to the Free Software
    - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    - */
    -
    -#ifndef _YAHOO_DOODLE_H_
    -#define _YAHOO_DOODLE_H_
    -
    -/******************************************************************************
    - * Includes
    - *****************************************************************************/
    -#include "whiteboard.h"
    -#include "cmds.h"
    -
    -#define DOODLE_IMV_KEY "doodle;106"
    -
    -/******************************************************************************
    - * Defines
    - *****************************************************************************/
    -/* Doodle communication commands */
    -/* TODO: Should be an enum. */
    -#define DOODLE_CMD_REQUEST 0
    -#define DOODLE_CMD_CLEAR 1
    -#define DOODLE_CMD_DRAW 2
    -#define DOODLE_CMD_EXTRA 3
    -#define DOODLE_CMD_READY 4
    -#define DOODLE_CMD_CONFIRM 5
    -/* Doodle communication command for shutting down (also 0) */
    -#define DOODLE_CMD_SHUTDOWN 0
    -
    -#define DOODLE_EXTRA_NONE "\"1\""
    -#define DOODLE_EXTRA_TICTACTOE "\"3\""
    -#define DOODLE_EXTRA_DOTS "\"2\""
    -
    -/* Doodle session states */
    -/* TODO: Should be an enum. */
    -#define DOODLE_STATE_REQUESTING 0
    -#define DOODLE_STATE_REQUESTED 1
    -#define DOODLE_STATE_ESTABLISHED 2
    -#define DOODLE_STATE_CANCELLED 3
    -
    -/* Doodle canvas dimensions */
    -#define DOODLE_CANVAS_WIDTH 368
    -#define DOODLE_CANVAS_HEIGHT 256
    -
    -/* Doodle color codes (most likely RGB) */
    -/* TODO: Should be an enum and sorted by color name. */
    -#define DOODLE_COLOR_RED 13369344
    -#define DOODLE_COLOR_ORANGE 16737792
    -#define DOODLE_COLOR_YELLOW 15658496
    -#define DOODLE_COLOR_GREEN 52224
    -#define DOODLE_COLOR_CYAN 52428
    -#define DOODLE_COLOR_BLUE 204
    -#define DOODLE_COLOR_VIOLET 5381277
    -#define DOODLE_COLOR_PURPLE 13369548
    -#define DOODLE_COLOR_TAN 12093547
    -#define DOODLE_COLOR_BROWN 5256485
    -#define DOODLE_COLOR_BLACK 0
    -#define DOODLE_COLOR_GREY 11184810
    -#define DOODLE_COLOR_WHITE 16777215
    -
    -#define PALETTE_NUM_OF_COLORS 12
    -
    -/* Doodle brush sizes (most likely variable) */
    -#define DOODLE_BRUSH_SMALL 2
    -#define DOODLE_BRUSH_MEDIUM 5
    -#define DOODLE_BRUSH_LARGE 10
    -
    -#define DOODLE_MAX_BRUSH_MOTIONS 100
    -
    -/******************************************************************************
    - * Datatypes
    - *****************************************************************************/
    -typedef struct _doodle_session
    -{
    - int brush_size; /* Size of drawing brush */
    - int brush_color; /* Color of drawing brush */
    - gchar *imv_key;
    -} doodle_session;
    -
    -/******************************************************************************
    - * API
    - *****************************************************************************/
    -
    -PurpleCmdRet yahoo_doodle_purple_cmd_start(PurpleConversation *conv, const char *cmd, char **args,
    - char **error, void *data);
    -
    -void yahoo_doodle_process(PurpleConnection *gc, const char *me, const char *from,
    - const char *command, const char *message, const char *imv_key);
    -void yahoo_doodle_initiate(PurpleConnection *gc, const char *to);
    -
    -void yahoo_doodle_command_got_shutdown(PurpleConnection *gc, const char *from);
    -
    -void yahoo_doodle_command_send_request(PurpleConnection *gc, const char *to, const char *imv_key);
    -void yahoo_doodle_command_send_ready(PurpleConnection *gc, const char *to, const char *imv_key);
    -void yahoo_doodle_command_send_draw(PurpleConnection *gc, const char *to, const char *message, const char *imv_key);
    -void yahoo_doodle_command_send_clear(PurpleConnection *gc, const char *to, const char *imv_key);
    -void yahoo_doodle_command_send_extra(PurpleConnection *gc, const char *to, const char *message, const char *imv_key);
    -void yahoo_doodle_command_send_confirm(PurpleConnection *gc, const char *to, const char *imv_key);
    -void yahoo_doodle_command_send_shutdown(PurpleConnection *gc, const char *to);
    -
    -void yahoo_doodle_start(PurpleWhiteboard *wb);
    -void yahoo_doodle_end(PurpleWhiteboard *wb);
    -void yahoo_doodle_get_dimensions(const PurpleWhiteboard *wb, int *width, int *height);
    -void yahoo_doodle_send_draw_list(PurpleWhiteboard *wb, GList *draw_list);
    -void yahoo_doodle_clear(PurpleWhiteboard *wb);
    -
    -void yahoo_doodle_draw_stroke(PurpleWhiteboard *wb, GList *draw_list);
    -void yahoo_doodle_get_brush(const PurpleWhiteboard *wb, int *size, int *color);
    -void yahoo_doodle_set_brush(PurpleWhiteboard *wb, int size, int color);
    -
    -#endif /* _YAHOO_DOODLE_H_ */
    --- a/libpurple/protocols/yahoo/yahoo_filexfer.c Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,2048 +0,0 @@
    -/*
    - * @file yahoo_filexfer.c Yahoo Filetransfer
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * This program is free software; you can redistribute it and/or modify
    - * it under the terms of the GNU General Public License as published by
    - * the Free Software Foundation; either version 2 of the License, or
    - * (at your option) any later version.
    - *
    - * This program is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    - * GNU General Public License for more details.
    - *
    - * You should have received a copy of the GNU General Public License
    - * along with this program; if not, write to the Free Software
    - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    - */
    -
    -#include "internal.h"
    -#include "dnsquery.h"
    -
    -#include "prpl.h"
    -#include "util.h"
    -#include "debug.h"
    -#include "network.h"
    -#include "notify.h"
    -#include "proxy.h"
    -#include "ft.h"
    -#include "libymsg.h"
    -#include "yahoo_packet.h"
    -#include "yahoo_filexfer.h"
    -#include "yahoo_doodle.h"
    -#include "yahoo_friend.h"
    -
    -struct yahoo_xfer_data {
    - gchar *host;
    - gchar *path;
    - int port;
    - PurpleConnection *gc;
    - long expires;
    - gboolean started;
    - gchar *txbuf;
    - gsize txbuflen;
    - gsize txbuf_written;
    - guint tx_handler;
    - gchar *rxqueue;
    - guint rxlen;
    - gchar *xfer_peer_idstring;
    - gchar *xfer_idstring_for_relay;
    - int version; /* 0 for old, 15 for Y7(YMSG 15) */
    - int info_val_249;
    -
    - enum {
    - STARTED = 0,
    - HEAD_REQUESTED,
    - HEAD_REPLY_RECEIVED,
    - TRANSFER_PHASE,
    - ACCEPTED,
    - P2P_HEAD_REQUESTED,
    - P2P_HEAD_REPLIED,
    - P2P_GET_REQUESTED
    - } status_15;
    -
    - /* contains all filenames, in case of multiple transfers, with the first
    - * one in the list being the current file's name (ymsg15) */
    - GSList *filename_list;
    - GSList *size_list; /* corresponds to filename_list, with size as **STRING** */
    - gboolean firstoflist;
    - gchar *xfer_url; /* url of the file, used when we are p2p server */
    - int yahoo_local_p2p_ft_server_fd;
    - int yahoo_local_p2p_ft_server_port;
    - int yahoo_p2p_ft_server_watcher;
    - int input_event;
    -};
    -
    -static void yahoo_xfer_data_free(struct yahoo_xfer_data *xd)
    -{
    - PurpleConnection *gc;
    - YahooData *yd;
    - PurpleXfer *xfer;
    - GSList *l;
    -
    - gc = xd->gc;
    - yd = gc->proto_data;
    -
    - /* remove entry from map */
    - if(xd->xfer_peer_idstring) {
    - xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map, xd->xfer_peer_idstring);
    - if(xfer)
    - g_hash_table_remove(yd->xfer_peer_idstring_map, xd->xfer_peer_idstring);
    - }
    -
    - /* empty file & filesize list */
    - for (l = xd->filename_list; l; l = l->next) {
    - g_free(l->data);
    - l->data=NULL;
    - }
    - for (l = xd->size_list; l; l = l->next) {
    - g_free(l->data);
    - l->data=NULL;
    - }
    - g_slist_free(xd->filename_list);
    - g_slist_free(xd->size_list);
    -
    - g_free(xd->host);
    - g_free(xd->path);
    - g_free(xd->txbuf);
    - g_free(xd->xfer_peer_idstring);
    - g_free(xd->xfer_idstring_for_relay);
    - if (xd->tx_handler)
    - purple_input_remove(xd->tx_handler);
    - g_free(xd);
    -}
    -
    -static void yahoo_receivefile_send_cb(gpointer data, gint source, PurpleInputCondition condition)
    -{
    - PurpleXfer *xfer;
    - struct yahoo_xfer_data *xd;
    - int remaining, written;
    -
    - xfer = data;
    - xd = xfer->data;
    -
    - remaining = xd->txbuflen - xd->txbuf_written;
    - written = write(xfer->fd, xd->txbuf + xd->txbuf_written, remaining);
    -
    - if (written < 0 && errno == EAGAIN)
    - written = 0;
    - else if (written <= 0) {
    - purple_debug_error("yahoo", "Unable to write in order to start ft errno = %d\n", errno);
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    -
    - if (written < remaining) {
    - xd->txbuf_written += written;
    - return;
    - }
    -
    - purple_input_remove(xd->tx_handler);
    - xd->tx_handler = 0;
    - g_free(xd->txbuf);
    - xd->txbuf = NULL;
    - xd->txbuflen = 0;
    -
    - purple_xfer_start(xfer, source, NULL, 0);
    -
    -}
    -
    -static void yahoo_receivefile_connected(gpointer data, gint source, const gchar *error_message)
    -{
    - PurpleXfer *xfer;
    - struct yahoo_xfer_data *xd;
    -
    - purple_debug_info("yahoo", "in yahoo_receivefile_connected\n");
    -
    - if (!(xfer = data))
    - return;
    - if (!(xd = xfer->data))
    - return;
    - if ((source < 0) || (xd->path == NULL) || (xd->host == NULL)) {
    - purple_xfer_error(PURPLE_XFER_RECEIVE, purple_xfer_get_account(xfer),
    - xfer->who, _("Unable to connect."));
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    -
    - xfer->fd = source;
    -
    - /* The first time we get here, assemble the tx buffer */
    - if (xd->txbuflen == 0) {
    - xd->txbuf = g_strdup_printf("GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n",
    - xd->path, xd->host);
    - xd->txbuflen = strlen(xd->txbuf);
    - xd->txbuf_written = 0;
    - }
    -
    - if (!xd->tx_handler)
    - {
    - xd->tx_handler = purple_input_add(source, PURPLE_INPUT_WRITE,
    - yahoo_receivefile_send_cb, xfer);
    - yahoo_receivefile_send_cb(xfer, source, PURPLE_INPUT_WRITE);
    - }
    -}
    -
    -static void yahoo_sendfile_send_cb(gpointer data, gint source, PurpleInputCondition condition)
    -{
    - PurpleXfer *xfer;
    - struct yahoo_xfer_data *xd;
    - int written, remaining;
    -
    - xfer = data;
    - xd = xfer->data;
    -
    - remaining = xd->txbuflen - xd->txbuf_written;
    - written = write(xfer->fd, xd->txbuf + xd->txbuf_written, remaining);
    -
    - if (written < 0 && errno == EAGAIN)
    - written = 0;
    - else if (written <= 0) {
    - purple_debug_error("yahoo", "Unable to write in order to start ft errno = %d\n", errno);
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    -
    - if (written < remaining) {
    - xd->txbuf_written += written;
    - return;
    - }
    -
    - purple_input_remove(xd->tx_handler);
    - xd->tx_handler = 0;
    - g_free(xd->txbuf);
    - xd->txbuf = NULL;
    - xd->txbuflen = 0;
    -
    - purple_xfer_start(xfer, source, NULL, 0);
    -}
    -
    -static void yahoo_sendfile_connected(gpointer data, gint source, const gchar *error_message)
    -{
    - PurpleXfer *xfer;
    - struct yahoo_xfer_data *xd;
    - struct yahoo_packet *pkt;
    - gchar *size, *filename, *encoded_filename, *header;
    - guchar *pkt_buf;
    - const char *host;
    - int port;
    - size_t content_length, header_len, pkt_buf_len;
    - PurpleConnection *gc;
    - PurpleAccount *account;
    - YahooData *yd;
    -
    - purple_debug_info("yahoo", "in yahoo_sendfile_connected\n");
    -
    - if (!(xfer = data))
    - return;
    - if (!(xd = xfer->data))
    - return;
    -
    - if (source < 0) {
    - purple_xfer_error(PURPLE_XFER_RECEIVE, purple_xfer_get_account(xfer),
    - xfer->who, _("Unable to connect."));
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    -
    - xfer->fd = source;
    -
    - /* Assemble the tx buffer */
    - gc = xd->gc;
    - account = purple_connection_get_account(gc);
    - yd = gc->proto_data;
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANSFER,
    - YAHOO_STATUS_AVAILABLE, yd->session_id);
    -
    - size = g_strdup_printf("%" G_GSIZE_FORMAT, purple_xfer_get_size(xfer));
    - filename = g_path_get_basename(purple_xfer_get_local_filename(xfer));
    - encoded_filename = yahoo_string_encode(gc, filename, NULL);
    -
    - yahoo_packet_hash(pkt, "sssss", 0, purple_connection_get_display_name(gc),
    - 5, xfer->who, 14, "", 27, encoded_filename, 28, size);
    - g_free(size);
    - g_free(encoded_filename);
    - g_free(filename);
    -
    - content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt);
    -
    - pkt_buf_len = yahoo_packet_build(pkt, 4, FALSE, yd->jp, &pkt_buf);
    - yahoo_packet_free(pkt);
    -
    - host = purple_account_get_string(account, "xfer_host", YAHOO_XFER_HOST);
    - port = purple_account_get_int(account, "xfer_port", YAHOO_XFER_PORT);
    - header = g_strdup_printf(
    - "POST http://%s:%d/notifyft HTTP/1.0\r\n"
    - "Content-length: %" G_GSIZE_FORMAT "\r\n"
    - "Host: %s:%d\r\n"
    - "Cookie: Y=%s; T=%s\r\n"
    - "\r\n",
    - host, port, content_length + 4 + purple_xfer_get_size(xfer),
    - host, port, yd->cookie_y, yd->cookie_t);
    -
    - header_len = strlen(header);
    -
    - xd->txbuflen = header_len + pkt_buf_len + 4;
    - xd->txbuf = g_malloc(xd->txbuflen);
    -
    - memcpy(xd->txbuf, header, header_len);
    - g_free(header);
    - memcpy(xd->txbuf + header_len, pkt_buf, pkt_buf_len);
    - g_free(pkt_buf);
    - memcpy(xd->txbuf + header_len + pkt_buf_len, "29\xc0\x80", 4);
    -
    - xd->txbuf_written = 0;
    -
    - if (xd->tx_handler == 0)
    - {
    - xd->tx_handler = purple_input_add(source, PURPLE_INPUT_WRITE,
    - yahoo_sendfile_send_cb, xfer);
    - yahoo_sendfile_send_cb(xfer, source, PURPLE_INPUT_WRITE);
    - }
    -}
    -
    -static void yahoo_xfer_init(PurpleXfer *xfer)
    -{
    - struct yahoo_xfer_data *xfer_data;
    - PurpleConnection *gc;
    - PurpleAccount *account;
    - YahooData *yd;
    -
    - xfer_data = xfer->data;
    - gc = xfer_data->gc;
    - yd = gc->proto_data;
    - account = purple_connection_get_account(gc);
    -
    - if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND) {
    - if (yd->jp) {
    - if (purple_proxy_connect(gc, account, purple_account_get_string(account, "xferjp_host", YAHOOJP_XFER_HOST),
    - purple_account_get_int(account, "xfer_port", YAHOO_XFER_PORT),
    - yahoo_sendfile_connected, xfer) == NULL)
    - {
    - purple_notify_error(gc, NULL, _("File Transfer Failed"),
    - _("Unable to establish file descriptor."));
    - purple_xfer_cancel_remote(xfer);
    - }
    - } else {
    - if (purple_proxy_connect(gc, account, purple_account_get_string(account, "xfer_host", YAHOO_XFER_HOST),
    - purple_account_get_int(account, "xfer_port", YAHOO_XFER_PORT),
    - yahoo_sendfile_connected, xfer) == NULL)
    - {
    - purple_notify_error(gc, NULL, _("File Transfer Failed"),
    - _("Unable to establish file descriptor."));
    - purple_xfer_cancel_remote(xfer);
    - }
    - }
    - } else {
    - xfer->fd = -1;
    - if (purple_proxy_connect(gc, account, xfer_data->host, xfer_data->port,
    - yahoo_receivefile_connected, xfer) == NULL) {
    - purple_notify_error(gc, NULL, _("File Transfer Failed"),
    - _("Unable to establish file descriptor."));
    - purple_xfer_cancel_remote(xfer);
    - }
    - }
    -}
    -
    -static void yahoo_xfer_init_15(PurpleXfer *xfer)
    -{
    - struct yahoo_xfer_data *xfer_data;
    - PurpleConnection *gc;
    - PurpleAccount *account;
    - YahooData *yd;
    - struct yahoo_packet *pkt;
    -
    - xfer_data = xfer->data;
    - gc = xfer_data->gc;
    - yd = gc->proto_data;
    - account = purple_connection_get_account(gc);
    -
    - if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND) {
    - gchar *filename;
    - filename = g_path_get_basename(purple_xfer_get_local_filename(xfer));
    - pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_15,
    - YAHOO_STATUS_AVAILABLE,
    - yd->session_id);
    - yahoo_packet_hash(pkt, "sssiiiisiii",
    - 1, purple_normalize(account, purple_account_get_username(account)),
    - 5, xfer->who,
    - 265, xfer_data->xfer_peer_idstring,
    - 222, 1,
    - 266, 1,
    - 302, 268,
    - 300, 268,
    - 27, filename,
    - 28, xfer->size,
    - 301, 268,
    - 303, 268);
    - g_free(filename);
    - } else {
    - if(xfer_data->firstoflist == TRUE) {
    - pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_15,
    - YAHOO_STATUS_AVAILABLE, yd->session_id);
    -
    - yahoo_packet_hash(pkt, "sssi",
    - 1, purple_normalize(account, purple_account_get_username(account)),
    - 5, xfer->who,
    - 265, xfer_data->xfer_peer_idstring,
    - 222, 3);
    - } else {
    - pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_ACC_15,
    - YAHOO_STATUS_AVAILABLE, yd->session_id);
    -
    - yahoo_packet_hash(pkt, "sssi",
    - 1, purple_normalize(account, purple_account_get_username(account)),
    - 5, xfer->who,
    - 265, xfer_data->xfer_peer_idstring,
    - 271, 1);
    - }
    - }
    - yahoo_packet_send_and_free(pkt, yd);
    -}
    -
    -static void yahoo_xfer_start(PurpleXfer *xfer)
    -{
    - /* We don't need to do anything here, do we? */
    -}
    -
    -static guint calculate_length(const gchar *l, size_t len)
    -{
    - size_t i;
    -
    - for (i = 0; i < len; i++) {
    - if (!g_ascii_isdigit(l[i]))
    - continue;
    - return strtol(l + i, NULL, 10);
    - }
    - return 0;
    -}
    -
    -static gssize yahoo_xfer_read(guchar **buffer, PurpleXfer *xfer)
    -{
    - gchar buf[4096];
    - gssize len;
    - gchar *start = NULL;
    - gchar *length;
    - gchar *end;
    - int filelen;
    - struct yahoo_xfer_data *xd = xfer->data;
    -
    - if (purple_xfer_get_type(xfer) != PURPLE_XFER_RECEIVE) {
    - return 0;
    - }
    -
    - len = read(xfer->fd, buf, sizeof(buf));
    -
    - if (len <= 0) {
    - if ((purple_xfer_get_size(xfer) > 0) &&
    - (purple_xfer_get_bytes_sent(xfer) >= purple_xfer_get_size(xfer))) {
    - purple_xfer_set_completed(xfer, TRUE);
    - return 0;
    - } else
    - return -1;
    - }
    -
    - if (!xd->started) {
    - xd->rxqueue = g_realloc(xd->rxqueue, len + xd->rxlen);
    - memcpy(xd->rxqueue + xd->rxlen, buf, len);
    - xd->rxlen += len;
    -
    - length = g_strstr_len(xd->rxqueue, len, "Content-length:");
    - /* some proxies re-write this header, changing the capitalization :(
    - * technically that's allowed since headers are case-insensitive
    - * [RFC 2616, section 4.2] */
    - if (length == NULL)
    - length = g_strstr_len(xd->rxqueue, len, "Content-Length:");
    - if (length) {
    - end = g_strstr_len(length, length - xd->rxqueue, "\r\n");
    - if (!end)
    - return 0;
    - if ((filelen = calculate_length(length, len - (length - xd->rxqueue))))
    - purple_xfer_set_size(xfer, filelen);
    - }
    - start = g_strstr_len(xd->rxqueue, len, "\r\n\r\n");
    - if (start)
    - start += 4;
    - if (!start || start > (xd->rxqueue + len))
    - return 0;
    - xd->started = TRUE;
    -
    - len -= (start - xd->rxqueue);
    -
    - *buffer = g_malloc(len);
    - memcpy(*buffer, start, len);
    - g_free(xd->rxqueue);
    - xd->rxqueue = NULL;
    - xd->rxlen = 0;
    - } else {
    - *buffer = g_malloc(len);
    - memcpy(*buffer, buf, len);
    - }
    -
    - return len;
    -}
    -
    -static gssize yahoo_xfer_write(const guchar *buffer, size_t size, PurpleXfer *xfer)
    -{
    - gssize len;
    - struct yahoo_xfer_data *xd = xfer->data;
    -
    - if (!xd)
    - return -1;
    -
    - if (purple_xfer_get_type(xfer) != PURPLE_XFER_SEND) {
    - return -1;
    - }
    -
    - len = write(xfer->fd, buffer, size);
    -
    - if (len == -1) {
    - if (purple_xfer_get_bytes_sent(xfer) >= purple_xfer_get_size(xfer))
    - purple_xfer_set_completed(xfer, TRUE);
    - if ((errno != EAGAIN) && (errno != EINTR))
    - return -1;
    - return 0;
    - }
    -
    - return len;
    -}
    -
    -static void yahoo_xfer_cancel_send(PurpleXfer *xfer)
    -{
    - struct yahoo_xfer_data *xfer_data;
    -
    - xfer_data = xfer->data;
    -
    - if(purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL && xfer_data->version == 15)
    - {
    - PurpleConnection *gc;
    - PurpleAccount *account;
    - YahooData *yd;
    - struct yahoo_packet *pkt;
    -
    - gc = xfer_data->gc;
    - yd = gc->proto_data;
    - account = purple_connection_get_account(gc);
    - if(xfer_data->xfer_idstring_for_relay) /* hack to see if file trans acc/info packet has been received */
    - {
    - pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_INFO_15,
    - YAHOO_STATUS_DISCONNECTED,
    - yd->session_id);
    - yahoo_packet_hash(pkt, "sssi",
    - 1, purple_normalize(account, purple_account_get_username(account)),
    - 5, xfer->who,
    - 265, xfer_data->xfer_peer_idstring,
    - 66, -1);
    - }
    - else
    - {
    - pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_15,
    - YAHOO_STATUS_AVAILABLE,
    - yd->session_id);
    - yahoo_packet_hash(pkt, "sssi",
    - 1, purple_normalize(account, purple_account_get_username(account)),
    - 5, xfer->who,
    - 265, xfer_data->xfer_peer_idstring,
    - 222, 2);
    - }
    - yahoo_packet_send_and_free(pkt, yd);
    - }
    -
    -
    - if (xfer_data)
    - yahoo_xfer_data_free(xfer_data);
    - xfer->data = NULL;
    -}
    -
    -static void yahoo_xfer_cancel_recv(PurpleXfer *xfer)
    -{
    - struct yahoo_xfer_data *xfer_data;
    -
    - xfer_data = xfer->data;
    -
    - if(purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL && xfer_data->version == 15)
    - {
    -
    - PurpleConnection *gc;
    - PurpleAccount *account;
    - YahooData *yd;
    - struct yahoo_packet *pkt;
    -
    - gc = xfer_data->gc;
    - yd = gc->proto_data;
    - account = purple_connection_get_account(gc);
    - if(!xfer_data->xfer_idstring_for_relay) /* hack to see if file trans acc/info packet has been received */
    - {
    - pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_15,
    - YAHOO_STATUS_AVAILABLE,
    - yd->session_id);
    - yahoo_packet_hash(pkt, "sssi",
    - 1, purple_normalize(account, purple_account_get_username(account)),
    - 5, xfer->who,
    - 265, xfer_data->xfer_peer_idstring,
    - 222, 4);
    - }
    - else
    - {
    - pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_15,
    - YAHOO_STATUS_DISCONNECTED,
    - yd->session_id);
    - yahoo_packet_hash(pkt, "sssi",
    - 1, purple_normalize(account, purple_account_get_username(account)),
    - 5, xfer->who,
    - 265, xfer_data->xfer_peer_idstring,
    - 66, -1);
    - }
    - yahoo_packet_send_and_free(pkt, yd);
    - }
    -
    - if (xfer_data)
    - yahoo_xfer_data_free(xfer_data);
    - xfer->data = NULL;
    -}
    -
    -/* Send HTTP OK after receiving file */
    -static void yahoo_p2p_ft_server_send_OK(PurpleXfer *xfer)
    -{
    - char *tx = NULL;
    - int written;
    -
    - tx = g_strdup_printf("HTTP/1.1 200 OK\r\nContent-Length: 0\r\nContent-Type: application/octet-stream\r\nConnection: close\r\n\r\n");
    - written = write(xfer->fd, tx, strlen(tx));
    -
    - if (written < 0 && errno == EAGAIN)
    - written = 0;
    - else if (written <= 0)
    - purple_debug_info("yahoo", "p2p filetransfer: Unable to write HTTP OK");
    -
    - /* close connection */
    - close(xfer->fd);
    - xfer->fd = -1;
    - g_free(tx);
    -}
    -
    -static void yahoo_xfer_end(PurpleXfer *xfer_old)
    -{
    - struct yahoo_xfer_data *xfer_data;
    - PurpleXfer *xfer = NULL;
    - PurpleConnection *gc;
    - YahooData *yd;
    -
    - xfer_data = xfer_old->data;
    - if(xfer_data && xfer_data->version == 15
    - && purple_xfer_get_type(xfer_old) == PURPLE_XFER_RECEIVE
    - && xfer_data->filename_list) {
    -
    - /* Send HTTP OK in case of p2p transfer, when we act as server */
    - if((xfer_data->xfer_url != NULL) && (xfer_old->fd >=0) && (purple_xfer_get_status(xfer_old) == PURPLE_XFER_STATUS_DONE))
    - yahoo_p2p_ft_server_send_OK(xfer_old);
    -
    - /* removing top of filename & size list completely */
    - g_free( xfer_data->filename_list->data );
    - g_free( xfer_data->size_list->data );
    -
    - xfer_data->filename_list->data = NULL;
    - xfer_data->size_list->data = NULL;
    -
    - xfer_data->filename_list = g_slist_delete_link(xfer_data->filename_list, xfer_data->filename_list);
    - xfer_data->size_list = g_slist_delete_link(xfer_data->size_list, xfer_data->size_list);
    -
    - /* if there are still more files */
    - if(xfer_data->filename_list)
    - {
    - gchar* filename;
    - long filesize;
    -
    - filename = xfer_data->filename_list->data;
    - filesize = atol( xfer_data->size_list->data );
    -
    - gc = xfer_data->gc;
    - yd = gc->proto_data;
    -
    - /* setting up xfer_data for next file's tranfer */
    - g_free(xfer_data->host);
    - g_free(xfer_data->path);
    - g_free(xfer_data->txbuf);
    - g_free(xfer_data->rxqueue);
    - g_free(xfer_data->xfer_idstring_for_relay);
    - if (xfer_data->tx_handler)
    - purple_input_remove(xfer_data->tx_handler);
    - xfer_data->host = NULL;
    - xfer_data->host = NULL;
    - xfer_data->port = 0;
    - xfer_data->expires = 0;
    - xfer_data->started = FALSE;
    - xfer_data->txbuf = NULL;
    - xfer_data->txbuflen = 0;
    - xfer_data->txbuf_written = 0;
    - xfer_data->tx_handler = 0;
    - xfer_data->rxqueue = NULL;
    - xfer_data->rxlen = 0;
    - xfer_data->xfer_idstring_for_relay = NULL;
    - xfer_data->info_val_249 = 0;
    - xfer_data->status_15 = STARTED;
    - xfer_data->firstoflist = FALSE;
    -
    - /* Dereference xfer_data from old xfer */
    - xfer_old->data = NULL;
    -
    - /* Build the file transfer handle. */
    - xfer = purple_xfer_new(gc->account, PURPLE_XFER_RECEIVE, xfer_old->who);
    -
    -
    - if (xfer) {
    - /* Set the info about the incoming file. */
    - char *utf8_filename = yahoo_string_decode(gc, filename, TRUE);
    - purple_xfer_set_filename(xfer, utf8_filename);
    - g_free(utf8_filename);
    - purple_xfer_set_size(xfer, filesize);
    -
    - xfer->data = xfer_data;
    -
    - /* Setup our I/O op functions */
    - purple_xfer_set_init_fnc(xfer, yahoo_xfer_init_15);
    - purple_xfer_set_start_fnc(xfer, yahoo_xfer_start);
    - purple_xfer_set_end_fnc(xfer, yahoo_xfer_end);
    - purple_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send);
    - purple_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv);
    - purple_xfer_set_read_fnc(xfer, yahoo_xfer_read);
    - purple_xfer_set_write_fnc(xfer, yahoo_xfer_write);
    - purple_xfer_set_request_denied_fnc(xfer,yahoo_xfer_cancel_recv);
    -
    - /* update map to current xfer */
    - g_hash_table_remove(yd->xfer_peer_idstring_map, xfer_data->xfer_peer_idstring);
    - g_hash_table_insert(yd->xfer_peer_idstring_map, xfer_data->xfer_peer_idstring, xfer);
    -
    - /* Now perform the request */
    - purple_xfer_request(xfer);
    - }
    - return;
    - }
    - }
    - if (xfer_data)
    - yahoo_xfer_data_free(xfer_data);
    - xfer_old->data = NULL;
    -
    -}
    -
    -void yahoo_process_p2pfilexfer(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - GSList *l = pkt->hash;
    -
    - char *me = NULL;
    - char *from = NULL;
    - char *service = NULL;
    - char *message = NULL;
    - char *command = NULL;
    - char *imv = NULL;
    -
    - /* Get all the necessary values from this new packet */
    - while(l != NULL)
    - {
    - struct yahoo_pair *pair = l->data;
    -
    - switch(pair->key) {
    - case 5: /* Get who the packet is for */
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - me = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_p2pfilexfer "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 4: /* Get who the packet is from */
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - from = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_p2pfilexfer "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 49: /* Get the type of service */
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - service = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_p2pfilexfer "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 14: /* Get the 'message' of the packet */
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - message = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_p2pfilexfer "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 13: /* Get the command associated with this packet */
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - command = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_p2pfilexfer "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 63: /* IMVironment name and version */
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - imv = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_p2pfilexfer "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 64: /* Not sure, but it does vary with initialization of Doodle */
    - break;
    - }
    -
    - l = l->next;
    - }
    -
    - /* If this packet is an IMVIRONMENT, handle it accordingly */
    - if(service != NULL && imv != NULL && !strcmp(service, "IMVIRONMENT"))
    - {
    - /* Check for a Doodle packet and handle it accordingly */
    - if(strstr(imv, "doodle;") != NULL)
    - yahoo_doodle_process(gc, me, from, command, message, imv);
    -
    - /* If an IMVIRONMENT packet comes without a specific imviroment name */
    - if(!strcmp(imv, ";0"))
    - {
    - /* It is unfortunately time to close all IMVironments with the remote client */
    - yahoo_doodle_command_got_shutdown(gc, from);
    - }
    - }
    -}
    -
    -void yahoo_process_filetransfer(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - char *from = NULL;
    - char *msg = NULL;
    - char *url = NULL;
    - char *imv = NULL;
    - PurpleXfer *xfer;
    - YahooData *yd;
    - struct yahoo_xfer_data *xfer_data;
    - char *service = NULL;
    - char *filename = NULL;
    - unsigned long filesize = 0L;
    - GSList *l;
    -
    - yd = gc->proto_data;
    -
    - for (l = pkt->hash; l; l = l->next) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 4:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - from = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_filetransfer "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 5: /* to */
    - break;
    - case 14:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - msg = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_filetransfer "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 20:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - url = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_filetransfer "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 38: /* expires */
    - break;
    - case 27:
    - filename = pair->value;
    - break;
    - case 28:
    - filesize = atol(pair->value);
    - break;
    - case 49:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - service = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_filetransfer "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 63:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - imv = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_filetransfer "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - }
    - }
    -
    - /*
    - * The remote user has changed their IMVironment. We
    - * record it for later use.
    - */
    - if (from && imv && service && (strcmp("IMVIRONMENT", service) == 0)) {
    - g_hash_table_replace(yd->imvironments, g_strdup(from), g_strdup(imv));
    - return;
    - }
    -
    - if (pkt->service == YAHOO_SERVICE_P2PFILEXFER) {
    - if (service && (strcmp("FILEXFER", service) != 0)) {
    - purple_debug_misc("yahoo", "unhandled service 0x%02x\n", pkt->service);
    - return;
    - }
    - }
    -
    - if (msg) {
    - char *tmp;
    - tmp = strchr(msg, '\006');
    - if (tmp)
    - *tmp = '\0';
    - }
    -
    - if (!url || !from)
    - return;
    -
    - /* Setup the Yahoo-specific file transfer data */
    - xfer_data = g_new0(struct yahoo_xfer_data, 1);
    - xfer_data->gc = gc;
    - if (!purple_url_parse(url, &(xfer_data->host), &(xfer_data->port), &(xfer_data->path), NULL, NULL)) {
    - g_free(xfer_data);
    - return;
    - }
    -
    - purple_debug_misc("yahoo_filexfer", "Host is %s, port is %d, path is %s, and the full url was %s.\n",
    - xfer_data->host, xfer_data->port, xfer_data->path, url);
    -
    - /* Build the file transfer handle. */
    - xfer = purple_xfer_new(gc->account, PURPLE_XFER_RECEIVE, from);
    - if (xfer == NULL) {
    - g_free(xfer_data);
    - g_return_if_reached();
    - }
    -
    - xfer->data = xfer_data;
    -
    - /* Set the info about the incoming file. */
    - if (filename) {
    - char *utf8_filename = yahoo_string_decode(gc, filename, TRUE);
    - purple_xfer_set_filename(xfer, utf8_filename);
    - g_free(utf8_filename);
    - } else {
    - gchar *start, *end;
    - start = g_strrstr(xfer_data->path, "/");
    - if (start)
    - start++;
    - end = g_strrstr(xfer_data->path, "?");
    - if (start && *start && end) {
    - char *utf8_filename;
    - filename = g_strndup(start, end - start);
    - utf8_filename = yahoo_string_decode(gc, filename, TRUE);
    - g_free(filename);
    - purple_xfer_set_filename(xfer, utf8_filename);
    - g_free(utf8_filename);
    - filename = NULL;
    - }
    - }
    -
    - purple_xfer_set_size(xfer, filesize);
    -
    - /* Setup our I/O op functions */
    - purple_xfer_set_init_fnc(xfer, yahoo_xfer_init);
    - purple_xfer_set_start_fnc(xfer, yahoo_xfer_start);
    - purple_xfer_set_end_fnc(xfer, yahoo_xfer_end);
    - purple_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send);
    - purple_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv);
    - purple_xfer_set_read_fnc(xfer, yahoo_xfer_read);
    - purple_xfer_set_write_fnc(xfer, yahoo_xfer_write);
    -
    - /* Now perform the request */
    - purple_xfer_request(xfer);
    -}
    -
    -PurpleXfer *yahoo_new_xfer(PurpleConnection *gc, const char *who)
    -{
    - PurpleXfer *xfer;
    - struct yahoo_xfer_data *xfer_data;
    -
    - g_return_val_if_fail(who != NULL, NULL);
    -
    - xfer_data = g_new0(struct yahoo_xfer_data, 1);
    - xfer_data->gc = gc;
    -
    - /* Build the file transfer handle. */
    - xfer = purple_xfer_new(gc->account, PURPLE_XFER_SEND, who);
    - if (xfer == NULL)
    - {
    - g_free(xfer_data);
    - g_return_val_if_reached(NULL);
    - }
    -
    - xfer->data = xfer_data;
    -
    - /* Setup our I/O op functions */
    - purple_xfer_set_init_fnc(xfer, yahoo_xfer_init);
    - purple_xfer_set_start_fnc(xfer, yahoo_xfer_start);
    - purple_xfer_set_end_fnc(xfer, yahoo_xfer_end);
    - purple_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send);
    - purple_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv);
    - purple_xfer_set_read_fnc(xfer, yahoo_xfer_read);
    - purple_xfer_set_write_fnc(xfer, yahoo_xfer_write);
    -
    - return xfer;
    -}
    -
    -static gchar* yahoo_xfer_new_xfer_id(void)
    -{
    - gchar *ans;
    - int i,j;
    - ans = g_strnfill(24, ' ');
    - ans[23] = '$';
    - ans[22] = '$';
    - for(i = 0; i < 22; i++)
    - {
    - j = g_random_int_range (0,61);
    - if(j < 26)
    - ans[i] = j + 'a';
    - else if(j < 52)
    - ans[i] = j - 26 + 'A';
    - else
    - ans[i] = j - 52 + '0';
    - }
    - return ans;
    -}
    -
    -static void yahoo_xfer_dns_connected_15(GSList *hosts, gpointer data, const char *error_message)
    -{
    - PurpleXfer *xfer;
    - struct yahoo_xfer_data *xd;
    - struct sockaddr_in *addr;
    - struct yahoo_packet *pkt;
    - unsigned long actaddr;
    - unsigned char a,b,c,d;
    - PurpleConnection *gc;
    - PurpleAccount *account;
    - YahooData *yd;
    - gchar *url;
    - gchar *filename;
    -
    - if (!(xfer = data))
    - return;
    - if (!(xd = xfer->data))
    - return;
    - gc = xd->gc;
    - account = purple_connection_get_account(gc);
    - yd = gc->proto_data;
    -
    - if(!hosts)
    - {
    - purple_debug_error("yahoo", "Unable to find an IP address for relay.msg.yahoo.com\n");
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    -
    - /* Discard the length... */
    - hosts = g_slist_remove(hosts, hosts->data);
    - if(!hosts)
    - {
    - purple_debug_error("yahoo", "Unable to find an IP address for relay.msg.yahoo.com\n");
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    -
    - /* TODO:actually, u must try with addr no.1 , if its not working addr no.2 ..... */
    - addr = hosts->data;
    - actaddr = addr->sin_addr.s_addr;
    - d = actaddr & 0xff;
    - actaddr >>= 8;
    - c = actaddr & 0xff;
    - actaddr >>= 8;
    - b = actaddr & 0xff;
    - actaddr >>= 8;
    - a = actaddr & 0xff;
    - if(yd->jp)
    - xd->port = YAHOOJP_XFER_RELAY_PORT;
    - else
    - xd->port = YAHOO_XFER_RELAY_PORT;
    -
    - url = g_strdup_printf("%u.%u.%u.%u", d, c, b, a);
    -
    - /* Free the address... */
    - g_free(hosts->data);
    - hosts = g_slist_remove(hosts, hosts->data);
    - addr = NULL;
    - while (hosts != NULL)
    - {
    - /* Discard the length... */
    - hosts = g_slist_remove(hosts, hosts->data);
    - /* Free the address... */
    - g_free(hosts->data);
    - hosts = g_slist_remove(hosts, hosts->data);
    - }
    -
    - if (!purple_url_parse(url, &(xd->host), &(xd->port), &(xd->path), NULL, NULL)) {
    - purple_xfer_cancel_remote(xfer);
    - g_free(url);
    - return;
    - }
    - g_free(url);
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_INFO_15, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - filename = g_path_get_basename(purple_xfer_get_local_filename(xfer));
    -
    - yahoo_packet_hash(pkt, "ssssis",
    - 1, purple_normalize(account, purple_account_get_username(account)),
    - 5, xfer->who,
    - 265, xd->xfer_peer_idstring,
    - 27, filename,
    - 249, 3,
    - 250, xd->host);
    -
    - g_free(filename);
    - yahoo_packet_send_and_free(pkt, yd);
    -}
    -
    -gboolean yahoo_can_receive_file(PurpleConnection *gc, const char *who)
    -{
    - if (!who || yahoo_get_federation_from_name(who) != YAHOO_FEDERATION_NONE)
    - return FALSE;
    - return TRUE;
    -}
    -
    -void yahoo_send_file(PurpleConnection *gc, const char *who, const char *file)
    -{
    - struct yahoo_xfer_data *xfer_data;
    - YahooData *yd = gc->proto_data;
    - PurpleXfer *xfer = yahoo_new_xfer(gc, who);
    -
    - g_return_if_fail(xfer != NULL);
    -
    - /* if we don't have a p2p connection, try establishing it now */
    - if( !g_hash_table_lookup(yd->peers, who) )
    - yahoo_send_p2p_pkt(gc, who, 0);
    -
    - xfer_data = xfer->data;
    - xfer_data->status_15 = STARTED;
    - purple_xfer_set_init_fnc(xfer, yahoo_xfer_init_15);
    - xfer_data->version = 15;
    - xfer_data->xfer_peer_idstring = yahoo_xfer_new_xfer_id();
    - g_hash_table_insert(yd->xfer_peer_idstring_map, xfer_data->xfer_peer_idstring, xfer);
    -
    - /* Now perform the request */
    - if (file)
    - purple_xfer_request_accepted(xfer, file);
    - else
    - purple_xfer_request(xfer);
    -}
    -
    -static void yahoo_p2p_ft_server_listen_cb(int listenfd, gpointer data); /* using this in yahoo_xfer_send_cb_15 */
    -static void yahoo_xfer_connected_15(gpointer data, gint source, const gchar *error_message);/* using this in recv_cb */
    -
    -static void yahoo_xfer_recv_cb_15(gpointer data, gint source, PurpleInputCondition condition)
    -{
    - PurpleXfer *xfer;
    - struct yahoo_xfer_data *xd;
    - int did;
    - gchar* buf;
    - gchar* t;
    - PurpleAccount *account;
    - PurpleConnection *gc;
    -
    - xfer = data;
    - xd = xfer->data;
    - account = purple_connection_get_account(xd->gc);
    - gc = xd->gc;
    -
    - buf=g_strnfill(1000, 0);
    - while((did = read(source, buf, 998)) > 0)
    - {
    - xd->txbuflen += did;
    - buf[did] = '\0';
    - t = xd->txbuf;
    - xd->txbuf = g_strconcat(t,buf,NULL);
    - g_free(t);
    - }
    - g_free(buf);
    -
    - if (did < 0 && errno == EAGAIN)
    - return;
    - else if (did < 0) {
    - purple_debug_error("yahoo", "Unable to write in order to start ft errno = %d\n", errno);
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    -
    - purple_input_remove(xd->tx_handler);
    - xd->tx_handler = 0;
    - xd->txbuflen = 0;
    -
    - if(xd->status_15 == HEAD_REQUESTED) {
    - xd->status_15 = HEAD_REPLY_RECEIVED;
    - close(source);/* Is this required? */
    - g_free(xd->txbuf);
    - xd->txbuf = NULL;
    - if (purple_proxy_connect(gc, account, xd->host, xd->port, yahoo_xfer_connected_15, xfer) == NULL)
    - {
    - purple_notify_error(gc, NULL, _("File Transfer Failed"),
    - _("Unable to establish file descriptor."));
    - purple_xfer_cancel_remote(xfer);
    - }
    - } else {
    - purple_debug_error("yahoo","Unrecognized yahoo file transfer mode and stage (ymsg15):%d,%d\n",
    - purple_xfer_get_type(xfer),
    - xd->status_15);
    - return;
    - }
    -}
    -
    -static void yahoo_xfer_send_cb_15(gpointer data, gint source, PurpleInputCondition condition)
    -{
    - PurpleXfer *xfer;
    - struct yahoo_xfer_data *xd;
    - int remaining, written;
    -
    - xfer = data;
    - xd = xfer->data;
    - remaining = xd->txbuflen - xd->txbuf_written;
    - written = write(source, xd->txbuf + xd->txbuf_written, remaining);
    -
    - if (written < 0 && errno == EAGAIN)
    - written = 0;
    - else if (written <= 0) {
    - purple_debug_error("yahoo", "Unable to write in order to start ft errno = %d\n", errno);
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    -
    - if (written < remaining) {
    - xd->txbuf_written += written;
    - return;
    - }
    -
    - purple_input_remove(xd->tx_handler);
    - xd->tx_handler = 0;
    - g_free(xd->txbuf);
    - xd->txbuf = NULL;
    - xd->txbuflen = 0;
    - xd->txbuf_written = 0;
    -
    - if(purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE && xd->status_15 == STARTED)
    - {
    - xd->status_15 = HEAD_REQUESTED;
    - xd->tx_handler = purple_input_add(source, PURPLE_INPUT_READ, yahoo_xfer_recv_cb_15, xfer);
    - yahoo_xfer_recv_cb_15(xfer, source, PURPLE_INPUT_READ);
    - }
    - else if(purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE && xd->status_15 == HEAD_REPLY_RECEIVED)
    - {
    - xd->status_15 = TRANSFER_PHASE;
    - xfer->fd = source;
    - purple_xfer_start(xfer, source, NULL, 0);
    - }
    - else if(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND && (xd->status_15 == ACCEPTED || xd->status_15 == P2P_GET_REQUESTED) )
    - {
    - xd->status_15 = TRANSFER_PHASE;
    - xfer->fd = source;
    - /* Remove Read event */
    - purple_input_remove(xd->input_event);
    - xd->input_event = 0;
    - purple_xfer_start(xfer, source, NULL, 0);
    - }
    - else if(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND && xd->status_15 == P2P_HEAD_REQUESTED)
    - {
    - xd->status_15 = P2P_HEAD_REPLIED;
    - /* Remove Read event and close descriptor */
    - purple_input_remove(xd->input_event);
    - xd->input_event = 0;
    - close(source);
    - xfer->fd = -1;
    - /* start local server, listen for connections */
    - purple_network_listen(xd->yahoo_local_p2p_ft_server_port, SOCK_STREAM, yahoo_p2p_ft_server_listen_cb, xfer);
    - }
    - else
    - {
    - purple_debug_error("yahoo", "Unrecognized yahoo file transfer mode and stage (ymsg15):%d,%d\n", purple_xfer_get_type(xfer), xd->status_15);
    - return;
    - }
    -}
    -
    -static void yahoo_xfer_connected_15(gpointer data, gint source, const gchar *error_message)
    -{
    - PurpleXfer *xfer;
    - struct yahoo_xfer_data *xd;
    - PurpleAccount *account;
    - PurpleConnection *gc;
    -
    - if (!(xfer = data))
    - return;
    - if (!(xd = xfer->data))
    - return;
    - gc = xd->gc;
    - account = purple_connection_get_account(gc);
    - if ((source < 0) || (xd->path == NULL) || (xd->host == NULL)) {
    - purple_xfer_error(PURPLE_XFER_RECEIVE, purple_xfer_get_account(xfer),
    - xfer->who, _("Unable to connect."));
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    - /* The first time we get here, assemble the tx buffer */
    - if (xd->txbuflen == 0)
    - {
    - gchar* cookies;
    - YahooData *yd = gc->proto_data;
    -
    - /* cookies = yahoo_get_cookies(gc);
    - * This doesn't seem to be working. The function is returning NULL, which yahoo servers don't like
    - * For now let us not use this function */
    -
    - cookies = g_strdup_printf("Y=%s; T=%s", yd->cookie_y, yd->cookie_t);
    -
    - if(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND && xd->status_15 == ACCEPTED)
    - {
    - if(xd->info_val_249 == 2)
    - {
    - /* sending file via p2p, we are connected as client */
    - xd->txbuf = g_strdup_printf("POST /%s HTTP/1.1\r\n"
    - "User-Agent: " YAHOO_CLIENT_USERAGENT "\r\n"
    - "Host: %s\r\n"
    - "Content-Length: %ld\r\n"
    - "Cache-Control: no-cache\r\n\r\n",
    - xd->path,
    - xd->host,
    - (long int)xfer->size); /* to do, add Referer */
    - }
    - else
    - {
    - /* sending file via relaying */
    - xd->txbuf = g_strdup_printf("POST /relay?token=%s&sender=%s&recver=%s HTTP/1.1\r\n"
    - "Cookie:%s\r\n"
    - "User-Agent: " YAHOO_CLIENT_USERAGENT "\r\n"
    - "Host: %s\r\n"
    - "Content-Length: %ld\r\n"
    - "Cache-Control: no-cache\r\n\r\n",
    - purple_url_encode(xd->xfer_idstring_for_relay),
    - purple_normalize(account, purple_account_get_username(account)),
    - xfer->who,
    - cookies,
    - xd->host,
    - (long int)xfer->size);
    - }
    - }
    - else if(purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE && xd->status_15 == STARTED)
    - {
    - if(xd->info_val_249 == 1)
    - {
    - /* receiving file via p2p, connected as client */
    - xd->txbuf = g_strdup_printf("HEAD /%s HTTP/1.1\r\n"
    - "Accept: */*\r\n"
    - "User-Agent: " YAHOO_CLIENT_USERAGENT "\r\n"
    - "Host: %s\r\n"
    - "Content-Length: 0\r\n"
    - "Cache-Control: no-cache\r\n\r\n",
    - xd->path,xd->host);
    - }
    - else
    - {
    - /* receiving file via relaying */
    - xd->txbuf = g_strdup_printf("HEAD /relay?token=%s&sender=%s&recver=%s HTTP/1.1\r\n"
    - "Accept: */*\r\n"
    - "Cookie: %s\r\n"
    - "User-Agent: " YAHOO_CLIENT_USERAGENT "\r\n"
    - "Host: %s\r\n"
    - "Content-Length: 0\r\n"
    - "Cache-Control: no-cache\r\n\r\n",
    - purple_url_encode(xd->xfer_idstring_for_relay),
    - purple_normalize(account, purple_account_get_username(account)),
    - xfer->who,
    - cookies,
    - xd->host);
    - }
    - }
    - else if(purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE && xd->status_15 == HEAD_REPLY_RECEIVED)
    - {
    - if(xd->info_val_249 == 1)
    - {
    - /* receiving file via p2p, connected as client */
    - xd->txbuf = g_strdup_printf("GET /%s HTTP/1.1\r\n"
    - "User-Agent: " YAHOO_CLIENT_USERAGENT "\r\n"
    - "Host: %s\r\n"
    - "Connection: Keep-Alive\r\n\r\n",
    - xd->path, xd->host);
    - }
    - else
    - {
    - /* receiving file via relaying */
    - xd->txbuf = g_strdup_printf("GET /relay?token=%s&sender=%s&recver=%s HTTP/1.1\r\n"
    - "Cookie: %s\r\n"
    - "User-Agent: " YAHOO_CLIENT_USERAGENT "\r\n"
    - "Host: %s\r\n"
    - "Connection: Keep-Alive\r\n\r\n",
    - purple_url_encode(xd->xfer_idstring_for_relay),
    - purple_normalize(account, purple_account_get_username(account)),
    - xfer->who,
    - cookies,
    - xd->host);
    - }
    - }
    - else
    - {
    - purple_debug_error("yahoo", "Unrecognized yahoo file transfer mode and stage (ymsg15):%d,%d\n", purple_xfer_get_type(xfer), xd->status_15);
    - g_free(cookies);
    - return;
    - }
    - xd->txbuflen = strlen(xd->txbuf);
    - xd->txbuf_written = 0;
    - g_free(cookies);
    - }
    -
    - if (!xd->tx_handler)
    - {
    - xd->tx_handler = purple_input_add(source, PURPLE_INPUT_WRITE,
    - yahoo_xfer_send_cb_15, xfer);
    - yahoo_xfer_send_cb_15(xfer, source, PURPLE_INPUT_WRITE);
    - }
    -}
    -
    -static void yahoo_p2p_ft_POST_cb(gpointer data, gint source, PurpleInputCondition cond)
    -{
    - PurpleXfer *xfer;
    - struct yahoo_xfer_data *xd;
    -
    - xfer = data;
    - if (!(xd = xfer->data)) {
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    -
    - purple_input_remove(xd->input_event);
    - xd->status_15 = TRANSFER_PHASE;
    - xfer->fd = source;
    - purple_xfer_start(xfer, source, NULL, 0);
    -}
    -
    -static void yahoo_p2p_ft_HEAD_GET_cb(gpointer data, gint source, PurpleInputCondition cond)
    -{
    - PurpleXfer *xfer;
    - struct yahoo_xfer_data *xd;
    - guchar buf[1024];
    - int len;
    - char *url_head;
    - char *url_get;
    - time_t unix_time;
    - char *time_str;
    -
    - xfer = data;
    - if (!(xd = xfer->data)) {
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    -
    - len = read(source, buf, sizeof(buf));
    - if ((len < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
    - return ; /* No Worries*/
    - else if (len <= 0) {
    - purple_debug_warning("yahoo","p2p-ft: Error in connection, or host disconnected\n");
    - purple_input_remove(xd->input_event);
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    -
    - url_head = g_strdup_printf("HEAD %s", xd->xfer_url);
    - url_get = g_strdup_printf("GET %s", xd->xfer_url);
    -
    - if( strncmp(url_head, (char *)buf, strlen(url_head)) == 0 )
    - xd->status_15 = P2P_HEAD_REQUESTED;
    - else if( strncmp(url_get, (char *)buf, strlen(url_get)) == 0 )
    - xd->status_15 = P2P_GET_REQUESTED;
    - else {
    - purple_debug_warning("yahoo","p2p-ft: Wrong HEAD/GET request from peer, disconnecting host\n");
    - purple_input_remove(xd->input_event);
    - purple_xfer_cancel_remote(xfer);
    - g_free(url_head);
    - return;
    - }
    -
    - unix_time = time(NULL);
    - time_str = ctime(&unix_time);
    - time_str[strlen(time_str) - 1] = '\0';
    -
    - if (xd->txbuflen == 0) {
    - xd->txbuf = g_strdup_printf("HTTP/1.0 200 OK\r\n"
    - "Date: %s GMT\r\n"
    - "Server: Y!/1.0\r\n"
    - "MIME-version: 1.0\r\n"
    - "Last-modified: %s GMT\r\n"
    - "Content-length: %" G_GSIZE_FORMAT "\r\n\r\n",
    - time_str, time_str, xfer->size);
    - xd->txbuflen = strlen(xd->txbuf);
    - xd->txbuf_written = 0;
    - }
    -
    - if (!xd->tx_handler) {
    - xd->tx_handler = purple_input_add(source, PURPLE_INPUT_WRITE, yahoo_xfer_send_cb_15, xfer);
    - yahoo_xfer_send_cb_15(xfer, source, PURPLE_INPUT_WRITE);
    - }
    -
    - g_free(url_head);
    - g_free(url_get);
    -}
    -
    -static void yahoo_p2p_ft_server_send_connected_cb(gpointer data, gint source, PurpleInputCondition cond)
    -{
    - int acceptfd;
    - PurpleXfer *xfer;
    - struct yahoo_xfer_data *xd;
    -
    - xfer = data;
    - if (!(xd = xfer->data)) {
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    -
    - acceptfd = accept(source, NULL, 0);
    - if(acceptfd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
    - return;
    - else if(acceptfd == -1) {
    - purple_debug_warning("yahoo","yahoo_p2p_server_send_connected_cb: accept: %s\n", g_strerror(errno));
    - purple_xfer_cancel_remote(xfer);
    - /* remove watcher and close p2p ft server */
    - purple_input_remove(xd->yahoo_p2p_ft_server_watcher);
    - close(xd->yahoo_local_p2p_ft_server_fd);
    - return;
    - }
    -
    - /* remove watcher and close p2p ft server */
    - purple_input_remove(xd->yahoo_p2p_ft_server_watcher);
    - close(xd->yahoo_local_p2p_ft_server_fd);
    -
    - /* Add an Input Read event to the file descriptor */
    - xfer->fd = acceptfd;
    - if(xfer->type == PURPLE_XFER_RECEIVE)
    - xd->input_event = purple_input_add(acceptfd, PURPLE_INPUT_READ, yahoo_p2p_ft_POST_cb, data);
    - else
    - xd->input_event = purple_input_add(acceptfd, PURPLE_INPUT_READ, yahoo_p2p_ft_HEAD_GET_cb, data);
    -}
    -
    -static void yahoo_p2p_ft_server_listen_cb(int listenfd, gpointer data)
    -{
    - PurpleXfer *xfer;
    - struct yahoo_xfer_data *xd;
    - struct yahoo_packet *pkt;
    - PurpleAccount *account;
    - YahooData *yd;
    - gchar *filename;
    - const char *local_ip;
    - gchar *url_to_send = NULL;
    - char *filename_without_spaces = NULL;
    -
    - xfer = data;
    - if (!(xd = xfer->data) || (listenfd == -1)) {
    - purple_debug_warning("yahoo","p2p: error starting server for p2p file transfer\n");
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    -
    - if( (xfer->type == PURPLE_XFER_RECEIVE) || (xd->status_15 != P2P_HEAD_REPLIED) ) {
    - yd = xd->gc->proto_data;
    - account = purple_connection_get_account(xd->gc);
    - local_ip = purple_network_get_my_ip(listenfd);
    - xd->yahoo_local_p2p_ft_server_port = purple_network_get_port_from_fd(listenfd);
    -
    - filename = g_path_get_basename(purple_xfer_get_local_filename(xfer));
    - filename_without_spaces = g_strdup(filename);
    - purple_util_chrreplace(filename_without_spaces, ' ', '+');
    - xd->xfer_url = g_strdup_printf("/Messenger.%s.%d000%s?AppID=Messenger&UserID=%s&K=lc9lu2u89gz1llmplwksajkjx", xfer->who, (int)time(NULL), filename_without_spaces, xfer->who);
    - url_to_send = g_strdup_printf("http://%s:%d%s", local_ip, xd->yahoo_local_p2p_ft_server_port, xd->xfer_url);
    -
    - if(xfer->type == PURPLE_XFER_RECEIVE) {
    - xd->info_val_249 = 2; /* 249=2: we are p2p server, and receiving file */
    - pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_ACC_15,
    - YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash(pkt, "ssssis",
    - 1, purple_normalize(account, purple_account_get_username(account)),
    - 5, xfer->who,
    - 265, xd->xfer_peer_idstring,
    - 27, xfer->filename,
    - 249, 2,
    - 250, url_to_send);
    - }
    - else {
    - xd->info_val_249 = 1; /* 249=1: we are p2p server, and sending file */
    - pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_INFO_15, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash(pkt, "ssssis",
    - 1, purple_normalize(account, purple_account_get_username(account)),
    - 5, xfer->who,
    - 265, xd->xfer_peer_idstring,
    - 27, filename,
    - 249, 1,
    - 250, url_to_send);
    - }
    -
    - yahoo_packet_send_and_free(pkt, yd);
    -
    - g_free(filename);
    - g_free(url_to_send);
    - g_free(filename_without_spaces);
    - }
    -
    - /* Add an Input Read event to the file descriptor */
    - xd->yahoo_local_p2p_ft_server_fd = listenfd;
    - xd->yahoo_p2p_ft_server_watcher = purple_input_add(listenfd, PURPLE_INPUT_READ, yahoo_p2p_ft_server_send_connected_cb, data);
    -}
    -
    -/* send (p2p) file transfer information */
    -static void yahoo_p2p_client_send_ft_info(PurpleConnection *gc, PurpleXfer *xfer)
    -{
    - struct yahoo_xfer_data *xd;
    - struct yahoo_packet *pkt;
    - PurpleAccount *account;
    - YahooData *yd;
    - gchar *filename;
    - struct yahoo_p2p_data *p2p_data;
    -
    - if (!(xd = xfer->data))
    - return;
    -
    - account = purple_connection_get_account(gc);
    - yd = gc->proto_data;
    -
    - p2p_data = g_hash_table_lookup(yd->peers, xfer->who);
    - if( p2p_data->connection_type == YAHOO_P2P_WE_ARE_SERVER )
    - if(purple_network_listen_range(0, 0, SOCK_STREAM, yahoo_p2p_ft_server_listen_cb, xfer))
    - return;
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_INFO_15, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - filename = g_path_get_basename(purple_xfer_get_local_filename(xfer));
    -
    - yahoo_packet_hash(pkt, "ssssi",
    - 1, purple_normalize(account, purple_account_get_username(account)),
    - 5, xfer->who,
    - 265, xd->xfer_peer_idstring,
    - 27, filename,
    - 249, 2); /* 249=2: we are p2p client */
    - xd->info_val_249 = 2;
    - yahoo_packet_send_and_free(pkt, yd);
    -
    - g_free(filename);
    -}
    -
    -void yahoo_process_filetrans_15(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - char *from = NULL;
    - char *imv = NULL;
    - long val_222 = 0L;
    - PurpleXfer *xfer;
    - YahooData *yd;
    - struct yahoo_xfer_data *xfer_data;
    - char *service = NULL;
    - char *filename = NULL;
    - char *xfer_peer_idstring = NULL;
    - char *utf8_filename;
    - unsigned long filesize = 0L;
    - GSList *l;
    - GSList *filename_list = NULL;
    - GSList *size_list = NULL;
    - int nooffiles = 0;
    -
    - yd = gc->proto_data;
    -
    - for (l = pkt->hash; l; l = l->next) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 4:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - from = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_filetrans_15 "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 5: /* to */
    - break;
    - case 265:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - xfer_peer_idstring = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_filetrans_15 "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 27:
    - filename_list = g_slist_prepend(filename_list, g_strdup(pair->value));
    - nooffiles++;
    - break;
    - case 28:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - size_list = g_slist_prepend(size_list, g_strdup(pair->value));
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_filetrans_15 "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 222:
    - val_222 = atol(pair->value);
    - /* 1=send, 2=cancel, 3=accept, 4=reject */
    - break;
    -
    - /* check for p2p and imviron .... not sure it comes by this service packet. Since it was bundled with filexfer in old ymsg version, still keeping it. */
    - case 49:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - service = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_filetrans_15 "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 63:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - imv = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_filetrans_15 "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - /* end check */
    -
    - }
    - }
    - if(!xfer_peer_idstring)
    - return;
    -
    - if(val_222 == 2 || val_222 == 4)
    - {
    - xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map,
    - xfer_peer_idstring);
    - if(!xfer) return;
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    - if(val_222 == 3)
    - {
    - PurpleAccount *account;
    - xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map,
    - xfer_peer_idstring);
    - if(!xfer)
    - return;
    - /*
    - * In the file trans info packet that we must reply with, we are
    - * supposed to mention the ip address...
    - * purple connect does not give me a way of finding the ip address...
    - * so, purple dnsquery is used... but retries, trying with next ip
    - * address etc. is not implemented..TODO
    - */
    -
    - /* To send through p2p */
    - if( g_hash_table_lookup(yd->peers, from) ) {
    - /* send p2p file transfer information */
    - yahoo_p2p_client_send_ft_info(gc, xfer);
    - return;
    - }
    -
    - account = purple_connection_get_account(gc);
    - if (yd->jp)
    - {
    - purple_dnsquery_a_account(account, YAHOOJP_XFER_RELAY_HOST,
    - YAHOOJP_XFER_RELAY_PORT,
    - yahoo_xfer_dns_connected_15, xfer);
    - }
    - else
    - {
    - purple_dnsquery_a_account(account, YAHOO_XFER_RELAY_HOST,
    - YAHOO_XFER_RELAY_PORT,
    - yahoo_xfer_dns_connected_15, xfer);
    - }
    - return;
    - }
    -
    - /* processing for p2p and imviron .... not sure it comes by this service packet. Since it was bundled with filexfer in old ymsg version, still keeping it. */
    - /*
    - * The remote user has changed their IMVironment. We
    - * record it for later use.
    - */
    - if (from && imv && service && (strcmp("IMVIRONMENT", service) == 0)) {
    - g_hash_table_replace(yd->imvironments, g_strdup(from), g_strdup(imv));
    - return;
    - }
    -
    - if (pkt->service == YAHOO_SERVICE_P2PFILEXFER) {
    - if (service && (strcmp("FILEXFER", service) != 0)) {
    - purple_debug_misc("yahoo", "unhandled service 0x%02x\n", pkt->service);
    - return;
    - }
    - }
    - /* end processing */
    -
    - if(!filename_list)
    - return;
    - /* have to change list into order in which client at other end sends */
    - filename_list = g_slist_reverse(filename_list);
    - size_list = g_slist_reverse(size_list);
    - filename = filename_list->data;
    - filesize = atol(size_list->data);
    -
    - if(!from) return;
    - xfer_data = g_new0(struct yahoo_xfer_data, 1);
    - xfer_data->version = 15;
    - xfer_data->firstoflist = TRUE;
    - xfer_data->gc = gc;
    - xfer_data->xfer_peer_idstring = g_strdup(xfer_peer_idstring);
    - xfer_data->filename_list = filename_list;
    - xfer_data->size_list = size_list;
    -
    - /* Build the file transfer handle. */
    - xfer = purple_xfer_new(gc->account, PURPLE_XFER_RECEIVE, from);
    - if (xfer == NULL)
    - {
    - g_free(xfer_data);
    - g_return_if_reached();
    - }
    -
    - xfer->message = NULL;
    -
    - /* Set the info about the incoming file. */
    - utf8_filename = yahoo_string_decode(gc, filename, TRUE);
    - purple_xfer_set_filename(xfer, utf8_filename);
    - g_free(utf8_filename);
    - purple_xfer_set_size(xfer, filesize);
    -
    - xfer->data = xfer_data;
    -
    - /* Setup our I/O op functions */
    - purple_xfer_set_init_fnc(xfer, yahoo_xfer_init_15);
    - purple_xfer_set_start_fnc(xfer, yahoo_xfer_start);
    - purple_xfer_set_end_fnc(xfer, yahoo_xfer_end);
    - purple_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send);
    - purple_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv);
    - purple_xfer_set_read_fnc(xfer, yahoo_xfer_read);
    - purple_xfer_set_write_fnc(xfer, yahoo_xfer_write);
    - purple_xfer_set_request_denied_fnc(xfer,yahoo_xfer_cancel_recv);
    -
    - g_hash_table_insert(yd->xfer_peer_idstring_map,
    - xfer_data->xfer_peer_idstring,
    - xfer);
    -
    - if(nooffiles > 1) {
    - gchar* message;
    - message = g_strdup_printf(_("%s is trying to send you a group of %d files.\n"), xfer->who, nooffiles);
    - purple_xfer_conversation_write(xfer, message, FALSE);
    - g_free(message);
    - }
    - /* Now perform the request */
    - purple_xfer_request(xfer);
    -}
    -
    -void yahoo_process_filetrans_info_15(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - char *url = NULL;
    - long val_249 = 0;
    - long val_66 = 0;
    - PurpleXfer *xfer;
    - YahooData *yd;
    - struct yahoo_xfer_data *xfer_data;
    - char *xfer_peer_idstring = NULL;
    - char *xfer_idstring_for_relay = NULL;
    - GSList *l;
    - struct yahoo_packet *pkt_to_send;
    - struct yahoo_p2p_data *p2p_data;
    -
    - yd = gc->proto_data;
    -
    - for (l = pkt->hash; l; l = l->next) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 4: /* from */
    - break;
    - case 5: /* to */
    - break;
    - case 265:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - xfer_peer_idstring = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_filetrans_info_15 "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 27: /* filename */
    - break;
    - case 66:
    - val_66 = strtol(pair->value, NULL, 10);
    - break;
    - case 249:
    - val_249 = strtol(pair->value, NULL, 10);
    - /* 249 has value 1 or 2 when doing p2p transfer and value 3 when relaying through yahoo server */
    - break;
    - case 250:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - url = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_filetrans_info_15 "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 251:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - xfer_idstring_for_relay = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_filetrans_info_15 "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - }
    - }
    -
    - if(!xfer_peer_idstring)
    - return;
    -
    - xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map, xfer_peer_idstring);
    -
    - if(!xfer) return;
    -
    - if(val_66==-1)
    - {
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    -
    - xfer_data = xfer->data;
    -
    - xfer_data->info_val_249 = val_249;
    - xfer_data->xfer_idstring_for_relay = g_strdup(xfer_idstring_for_relay);
    - if(val_249 == 1 || val_249 == 3) {
    - PurpleAccount *account;
    - if (!purple_url_parse(url, &(xfer_data->host), &(xfer_data->port), &(xfer_data->path), NULL, NULL)) {
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    -
    - account = purple_connection_get_account(xfer_data->gc);
    -
    - pkt_to_send = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_ACC_15,
    - YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash(pkt_to_send, "ssssis",
    - 1, purple_normalize(account, purple_account_get_username(account)),
    - 5, xfer->who,
    - 265, xfer_data->xfer_peer_idstring,
    - 27, xfer->filename,
    - 249, xfer_data->info_val_249,
    - 251, xfer_data->xfer_idstring_for_relay);
    -
    - yahoo_packet_send_and_free(pkt_to_send, yd);
    -
    - if (purple_proxy_connect(gc, account, xfer_data->host, xfer_data->port,
    - yahoo_xfer_connected_15, xfer) == NULL) {
    - purple_notify_error(gc, NULL, _("File Transfer Failed"),
    - _("Unable to establish file descriptor."));
    - purple_xfer_cancel_remote(xfer);
    - }
    - }
    - else if(val_249 == 2) {
    - p2p_data = g_hash_table_lookup(yd->peers, xfer->who);
    - if( !( p2p_data && (p2p_data->connection_type == YAHOO_P2P_WE_ARE_SERVER) ) ) {
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    - if(!purple_network_listen_range(0, 0, SOCK_STREAM, yahoo_p2p_ft_server_listen_cb, xfer)) {
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    - }
    -}
    -
    -/* TODO: Check filename etc. No probs till some hacker comes in the way */
    -void yahoo_process_filetrans_acc_15(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - gchar *xfer_peer_idstring = NULL;
    - gchar *xfer_idstring_for_relay = NULL;
    - PurpleXfer *xfer;
    - YahooData *yd;
    - struct yahoo_xfer_data *xfer_data;
    - GSList *l;
    - PurpleAccount *account;
    - long val_66 = 0;
    - gchar *url = NULL;
    - int val_249 = 0;
    -
    - yd = gc->proto_data;
    - for (l = pkt->hash; l; l = l->next) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 251:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - xfer_idstring_for_relay = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_filetrans_acc_15 "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 265:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - xfer_peer_idstring = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_filetrans_acc_15 "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 66:
    - val_66 = atol(pair->value);
    - break;
    - case 249:
    - val_249 = atol(pair->value);
    - break;
    - case 250:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - /* we get a p2p url here when sending file, connected as client */
    - url = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_filetrans_acc_15 "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - }
    - }
    -
    - xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map, xfer_peer_idstring);
    - if(!xfer) return;
    -
    - if(val_66 == -1 || ( (!(xfer_idstring_for_relay)) && (val_249 != 2) ))
    - {
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    -
    - if( (val_249 == 2) && (!(url)) )
    - {
    - purple_xfer_cancel_remote(xfer);
    - return;
    - }
    -
    - xfer_data = xfer->data;
    - if(url)
    - purple_url_parse(url, &(xfer_data->host), &(xfer_data->port), &(xfer_data->path), NULL, NULL);
    -
    - xfer_data->xfer_idstring_for_relay = g_strdup(xfer_idstring_for_relay);
    - xfer_data->status_15 = ACCEPTED;
    - account = purple_connection_get_account(gc);
    -
    - if (purple_proxy_connect(gc, account, xfer_data->host, xfer_data->port,
    - yahoo_xfer_connected_15, xfer) == NULL)
    - {
    - purple_notify_error(gc, NULL, _("File Transfer Failed"),_("Unable to connect"));
    - purple_xfer_cancel_remote(xfer);
    - }
    -}
    --- a/libpurple/protocols/yahoo/yahoo_filexfer.h Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,70 +0,0 @@
    -/*
    - * purple
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * This program is free software; you can redistribute it and/or modify
    - * it under the terms of the GNU General Public License as published by
    - * the Free Software Foundation; either version 2 of the License, or
    - * (at your option) any later version.
    - *
    - * This program is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    - * GNU General Public License for more details.
    - *
    - * You should have received a copy of the GNU General Public License
    - * along with this program; if not, write to the Free Software
    - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    - */
    -#ifndef _YAHOO_FILEXFER_H_
    -#define _YAHOO_FILEXFER_H_
    -
    -#include "ft.h"
    -
    -/**
    - * Process ymsg events, particular IMViroments like Doodle
    - */
    -void yahoo_process_p2pfilexfer( PurpleConnection *gc, struct yahoo_packet *pkt );
    -
    -/**
    - * Process ymsg file receive invites.
    - */
    -void yahoo_process_filetransfer(PurpleConnection *gc, struct yahoo_packet *pkt);
    -
    -/**
    - * Create a new PurpleXfer
    - *
    - * @param gc The PurpleConnection handle.
    - * @param who Who will we be sending it to?
    - */
    -PurpleXfer *yahoo_new_xfer(PurpleConnection *gc, const char *who);
    -
    -/**
    - * Returns TRUE if the buddy can receive file, FALSE otherwise.
    - * Federated users cannot receive files. So this will return FALSE only
    - * for them.
    - *
    - * @param gc The connection
    - * @param who The name of the remote user
    - *
    - * @return TRUE or FALSE
    - */
    -gboolean yahoo_can_receive_file(PurpleConnection *gc, const char *who);
    -
    -/**
    - * Send a file.
    - *
    - * @param gc The PurpleConnection handle.
    - * @param who Who are we sending it to?
    - * @param file What file? If NULL, user will choose after this call.
    - */
    -void yahoo_send_file(PurpleConnection *gc, const char *who, const char *file);
    -
    -void yahoo_process_filetrans_15(PurpleConnection *gc, struct yahoo_packet *pkt);
    -void yahoo_process_filetrans_info_15(PurpleConnection *gc, struct yahoo_packet *pkt);
    -void yahoo_process_filetrans_acc_15(PurpleConnection *gc, struct yahoo_packet *pkt);
    -
    -#endif
    --- a/libpurple/protocols/yahoo/yahoo_friend.c Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,330 +0,0 @@
    -/*
    - * purple
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * This program is free software; you can redistribute it and/or modify
    - * it under the terms of the GNU General Public License as published by
    - * the Free Software Foundation; either version 2 of the License, or
    - * (at your option) any later version.
    - *
    - * This program is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    - * GNU General Public License for more details.
    - *
    - * You should have received a copy of the GNU General Public License
    - * along with this program; if not, write to the Free Software
    - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    - *
    - */
    -
    -#include "internal.h"
    -#include "prpl.h"
    -#include "util.h"
    -#include "debug.h"
    -
    -#include "yahoo_friend.h"
    -#include "yahoo_aliases.h"
    -
    -static YahooFriend *yahoo_friend_new(void)
    -{
    - YahooFriend *ret;
    -
    - ret = g_new0(YahooFriend, 1);
    - ret->status = YAHOO_STATUS_OFFLINE;
    - ret->presence = YAHOO_PRESENCE_DEFAULT;
    -
    - return ret;
    -}
    -
    -YahooFriend *yahoo_friend_find(PurpleConnection *gc, const char *name)
    -{
    - YahooData *yd;
    - const char *norm;
    -
    - g_return_val_if_fail(gc != NULL, NULL);
    - g_return_val_if_fail(gc->proto_data != NULL, NULL);
    -
    - yd = gc->proto_data;
    - norm = purple_normalize(purple_connection_get_account(gc), name);
    -
    - return g_hash_table_lookup(yd->friends, norm);
    -}
    -
    -YahooFriend *yahoo_friend_find_or_new(PurpleConnection *gc, const char *name)
    -{
    - YahooFriend *f;
    - YahooData *yd;
    - const char *norm;
    -
    - g_return_val_if_fail(gc != NULL, NULL);
    - g_return_val_if_fail(gc->proto_data != NULL, NULL);
    -
    - yd = gc->proto_data;
    - norm = purple_normalize(purple_connection_get_account(gc), name);
    -
    - f = g_hash_table_lookup(yd->friends, norm);
    - if (!f) {
    - f = yahoo_friend_new();
    - g_hash_table_insert(yd->friends, g_strdup(norm), f);
    - }
    -
    - return f;
    -}
    -
    -void yahoo_friend_set_ip(YahooFriend *f, const char *ip)
    -{
    - g_free(f->ip);
    - f->ip = g_strdup(ip);
    -}
    -
    -const char *yahoo_friend_get_ip(YahooFriend *f)
    -{
    - return f->ip;
    -}
    -
    -void yahoo_friend_set_game(YahooFriend *f, const char *game)
    -{
    - g_free(f->game);
    -
    - if (game)
    - f->game = g_strdup(game);
    - else
    - f->game = NULL;
    -}
    -
    -const char *yahoo_friend_get_game(YahooFriend *f)
    -{
    - return f->game;
    -}
    -
    -void yahoo_friend_set_status_message(YahooFriend *f, char *msg)
    -{
    - g_free(f->msg);
    -
    - f->msg = msg;
    -}
    -
    -const char *yahoo_friend_get_status_message(YahooFriend *f)
    -{
    - return f->msg;
    -}
    -
    -void yahoo_friend_set_buddy_icon_need_request(YahooFriend *f, gboolean needs)
    -{
    - f->bicon_sent_request = !needs;
    -}
    -
    -gboolean yahoo_friend_get_buddy_icon_need_request(YahooFriend *f)
    -{
    - return !f->bicon_sent_request;
    -}
    -
    -void yahoo_friend_set_alias_id(YahooFriend *f, const char *alias_id)
    -{
    - g_free(f->ypd.id);
    - f->ypd.id = g_strdup(alias_id);
    -}
    -
    -const char *yahoo_friend_get_alias_id(YahooFriend *f)
    -{
    - return f->ypd.id;
    -}
    -
    -void yahoo_friend_free(gpointer p)
    -{
    - YahooFriend *f = p;
    - g_free(f->msg);
    - g_free(f->game);
    - g_free(f->ip);
    - yahoo_personal_details_reset(&f->ypd, TRUE);
    - g_free(f);
    -}
    -
    -void yahoo_process_presence(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - GSList *l = pkt->hash;
    - YahooFriend *f;
    - char *temp = NULL;
    - char *who = NULL;
    - int value = 0;
    - YahooFederation fed = YAHOO_FEDERATION_NONE;
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 7:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - temp = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_presence "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 31:
    - value = strtol(pair->value, NULL, 10);
    - break;
    - case 241:
    - fed = strtol(pair->value, NULL, 10);
    - break;
    - }
    -
    - l = l->next;
    - }
    -
    - if (value != 1 && value != 2) {
    - purple_debug_error("yahoo", "Received unknown value for presence key: %d\n", value);
    - return;
    - }
    -
    - switch (fed) {
    - case YAHOO_FEDERATION_MSN:
    - who = g_strconcat("msn/", temp, NULL);
    - break;
    - case YAHOO_FEDERATION_OCS:
    - who = g_strconcat("ocs/", temp, NULL);
    - break;
    - case YAHOO_FEDERATION_IBM:
    - who = g_strconcat("ibm/", temp, NULL);
    - break;
    - case YAHOO_FEDERATION_PBX:
    - who = g_strconcat("pbx/", temp, NULL);
    - break;
    - case YAHOO_FEDERATION_NONE:
    - who = g_strdup(temp);
    - break;
    - }
    - g_return_if_fail(who != NULL);
    -
    - f = yahoo_friend_find(gc, who);
    - if (!f) {
    - g_free(who);
    - return;
    - }
    -
    - if (pkt->service == YAHOO_SERVICE_PRESENCE_PERM) {
    - purple_debug_info("yahoo", "Setting permanent presence for %s to %d.\n", who, (value == 1));
    - /* If setting from perm offline to online when in invisible status,
    - * this has already been taken care of (when the temp status changed) */
    - if (value == 2 && f->presence == YAHOO_PRESENCE_ONLINE) {
    - } else {
    - if (value == 1) /* Setting Perm offline */
    - f->presence = YAHOO_PRESENCE_PERM_OFFLINE;
    - else
    - f->presence = YAHOO_PRESENCE_DEFAULT;
    - }
    - } else {
    - purple_debug_info("yahoo", "Setting session presence for %s to %d.\n", who, (value == 1));
    - if (value == 1)
    - f->presence = YAHOO_PRESENCE_ONLINE;
    - else
    - f->presence = YAHOO_PRESENCE_DEFAULT;
    - }
    - g_free(who);
    -}
    -
    -void yahoo_friend_update_presence(PurpleConnection *gc, const char *name,
    - YahooPresenceVisibility presence)
    -{
    - YahooData *yd = gc->proto_data;
    - struct yahoo_packet *pkt = NULL;
    - YahooFriend *f;
    - const char *thirtyone, *thirteen;
    - int service = -1;
    - const char *temp = NULL;
    -
    - if (!yd->logged_in)
    - return;
    -
    - f = yahoo_friend_find(gc, name);
    - if (!f)
    - return;
    -
    - if(f->fed != YAHOO_FEDERATION_NONE)
    - temp = name+4;
    - else
    - temp = name;
    -
    - /* No need to change the value if it is already correct */
    - if (f->presence == presence) {
    - purple_debug_info("yahoo", "Not setting presence because there are no changes.\n");
    - return;
    - }
    -
    - if (presence == YAHOO_PRESENCE_PERM_OFFLINE) {
    - service = YAHOO_SERVICE_PRESENCE_PERM;
    - thirtyone = "1";
    - thirteen = "2";
    - } else if (presence == YAHOO_PRESENCE_DEFAULT) {
    - if (f->presence == YAHOO_PRESENCE_PERM_OFFLINE) {
    - service = YAHOO_SERVICE_PRESENCE_PERM;
    - thirtyone = "2";
    - thirteen = "2";
    - } else if (yd->current_status == YAHOO_STATUS_INVISIBLE) {
    - service = YAHOO_SERVICE_PRESENCE_SESSION;
    - thirtyone = "2";
    - thirteen = "1";
    - }
    - } else if (presence == YAHOO_PRESENCE_ONLINE) {
    - if (f->presence == YAHOO_PRESENCE_PERM_OFFLINE) {
    - pkt = yahoo_packet_new(YAHOO_SERVICE_PRESENCE_PERM,
    - YAHOO_STATUS_AVAILABLE, yd->session_id);
    - if(f->fed)
    - yahoo_packet_hash(pkt, "ssssssiss",
    - 1, purple_connection_get_display_name(gc),
    - 31, "2", 13, "2",
    - 302, "319", 300, "319",
    - 7, temp, 241, f->fed,
    - 301, "319", 303, "319");
    - else
    - yahoo_packet_hash(pkt, "ssssssss",
    - 1, purple_connection_get_display_name(gc),
    - 31, "2", 13, "2",
    - 302, "319", 300, "319",
    - 7, temp,
    - 301, "319", 303, "319");
    -
    - yahoo_packet_send_and_free(pkt, yd);
    - }
    -
    - service = YAHOO_SERVICE_PRESENCE_SESSION;
    - thirtyone = "1";
    - thirteen = "1";
    - }
    -
    - if (service > 0) {
    - pkt = yahoo_packet_new(service,
    - YAHOO_STATUS_AVAILABLE, yd->session_id);
    -
    - if(f->fed)
    - yahoo_packet_hash(pkt, "ssssssiss",
    - 1, purple_connection_get_display_name(gc),
    - 31, thirtyone, 13, thirteen,
    - 302, "319", 300, "319",
    - 7, temp, 241, f->fed,
    - 301, "319", 303, "319");
    - else
    - yahoo_packet_hash(pkt, "ssssssss",
    - 1, purple_connection_get_display_name(gc),
    - 31, thirtyone, 13, thirteen,
    - 302, "319", 300, "319",
    - 7, temp,
    - 301, "319", 303, "319");
    -
    - yahoo_packet_send_and_free(pkt, yd);
    - }
    -}
    -
    -void yahoo_friend_set_p2p_status(YahooFriend *f, YahooP2PStatus p2p_status)
    -{
    - f->p2p_status = p2p_status;
    -}
    -
    -YahooP2PStatus yahoo_friend_get_p2p_status(YahooFriend *f)
    -{
    - return f->p2p_status;
    -}
    --- a/libpurple/protocols/yahoo/yahoo_friend.h Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,93 +0,0 @@
    -/**
    - * @file yahoo_friend.h The Yahoo! protocol plugin YahooFriend object
    - *
    - * purple
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * This program is free software; you can redistribute it and/or modify
    - * it under the terms of the GNU General Public License as published by
    - * the Free Software Foundation; either version 2 of the License, or
    - * (at your option) any later version.
    - *
    - * This program is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    - * GNU General Public License for more details.
    - *
    - * You should have received a copy of the GNU General Public License
    - * along with this program; if not, write to the Free Software
    - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    - */
    -
    -#ifndef _YAHOO_FRIEND_H_
    -#define _YAHOO_FRIEND_H_
    -
    -#include "libymsg.h"
    -#include "yahoo_packet.h"
    -
    -typedef enum {
    - YAHOO_PRESENCE_DEFAULT = 0,
    - YAHOO_PRESENCE_ONLINE,
    - YAHOO_PRESENCE_PERM_OFFLINE
    -} YahooPresenceVisibility;
    -
    -typedef enum {
    - YAHOO_P2PSTATUS_NOT_CONNECTED = 0,
    - YAHOO_P2PSTATUS_DO_NOT_CONNECT,
    - YAHOO_P2PSTATUS_WE_ARE_SERVER,
    - YAHOO_P2PSTATUS_WE_ARE_CLIENT
    -} YahooP2PStatus;
    -
    -
    -/* these are called friends instead of buddies mainly so I can use variables
    - * named f and not confuse them with variables named b
    - */
    -typedef struct _YahooFriend {
    - enum yahoo_status status;
    - gchar *msg;
    - gchar *game;
    - int idle;
    - int away;
    - gboolean sms;
    - gchar *ip;
    - gboolean bicon_sent_request;
    - YahooPresenceVisibility presence;
    - YahooFederation fed;
    - long int version_id;
    - YahooPersonalDetails ypd;
    - YahooP2PStatus p2p_status;
    - gboolean p2p_packet_sent; /* 0:not sent, 1=sent */
    - gint session_id; /* session id of friend */
    -} YahooFriend;
    -
    -YahooFriend *yahoo_friend_find(PurpleConnection *gc, const char *name);
    -YahooFriend *yahoo_friend_find_or_new(PurpleConnection *gc, const char *name);
    -
    -void yahoo_friend_set_ip(YahooFriend *f, const char *ip);
    -const char *yahoo_friend_get_ip(YahooFriend *f);
    -
    -void yahoo_friend_set_game(YahooFriend *f, const char *game);
    -const char *yahoo_friend_get_game(YahooFriend *f);
    -
    -void yahoo_friend_set_status_message(YahooFriend *f, char *msg);
    -const char *yahoo_friend_get_status_message(YahooFriend *f);
    -
    -void yahoo_friend_set_alias_id(YahooFriend *f, const char *alias_id);
    -const char *yahoo_friend_get_alias_id(YahooFriend *f);
    -
    -void yahoo_friend_set_buddy_icon_need_request(YahooFriend *f, gboolean needs);
    -gboolean yahoo_friend_get_buddy_icon_need_request(YahooFriend *f);
    -
    -void yahoo_friend_free(gpointer p);
    -
    -void yahoo_process_presence(PurpleConnection *gc, struct yahoo_packet *pkt);
    -void yahoo_friend_update_presence(PurpleConnection *gc, const char *name,
    - YahooPresenceVisibility presence);
    -
    -void yahoo_friend_set_p2p_status(YahooFriend *f, YahooP2PStatus p2p_status);
    -YahooP2PStatus yahoo_friend_get_p2p_status(YahooFriend *f);
    -
    -#endif /* _YAHOO_FRIEND_H_ */
    --- a/libpurple/protocols/yahoo/yahoo_packet.c Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,403 +0,0 @@
    -/*
    - * purple
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * This program is free software; you can redistribute it and/or modify
    - * it under the terms of the GNU General Public License as published by
    - * the Free Software Foundation; either version 2 of the License, or
    - * (at your option) any later version.
    - *
    - * This program is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    - * GNU General Public License for more details.
    - *
    - * You should have received a copy of the GNU General Public License
    - * along with this program; if not, write to the Free Software
    - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    - *
    - */
    -
    -#include "internal.h"
    -#include "debug.h"
    -
    -#include "libymsg.h"
    -#include "yahoo_packet.h"
    -
    -struct yahoo_packet *yahoo_packet_new(enum yahoo_service service, enum yahoo_status status, int id)
    -{
    - struct yahoo_packet *pkt = g_new0(struct yahoo_packet, 1);
    -
    - pkt->service = service;
    - pkt->status = status;
    - pkt->id = id;
    -
    - return pkt;
    -}
    -
    -void yahoo_packet_hash_str(struct yahoo_packet *pkt, int key, const char *value)
    -{
    - struct yahoo_pair *pair;
    -
    - g_return_if_fail(value != NULL);
    -
    - pair = g_new0(struct yahoo_pair, 1);
    - pair->key = key;
    - pair->value = g_strdup(value);
    - pkt->hash = g_slist_prepend(pkt->hash, pair);
    -}
    -
    -void yahoo_packet_hash_int(struct yahoo_packet *pkt, int key, int value)
    -{
    - struct yahoo_pair *pair;
    -
    - pair = g_new0(struct yahoo_pair, 1);
    - pair->key = key;
    - pair->value = g_strdup_printf("%d", value);
    - pkt->hash = g_slist_prepend(pkt->hash, pair);
    -}
    -
    -void yahoo_packet_hash(struct yahoo_packet *pkt, const char *fmt, ...)
    -{
    - char *strval;
    - int key, intval;
    - const char *cur;
    - va_list ap;
    -
    - va_start(ap, fmt);
    - for (cur = fmt; *cur; cur++) {
    - key = va_arg(ap, int);
    - switch (*cur) {
    - case 'i':
    - intval = va_arg(ap, int);
    - yahoo_packet_hash_int(pkt, key, intval);
    - break;
    - case 's':
    - strval = va_arg(ap, char *);
    - yahoo_packet_hash_str(pkt, key, strval);
    - break;
    - default:
    - purple_debug_error("yahoo", "Invalid format character '%c'\n", *cur);
    - break;
    - }
    - }
    - va_end(ap);
    -}
    -
    -size_t yahoo_packet_length(struct yahoo_packet *pkt)
    -{
    - GSList *l;
    -
    - size_t len = 0;
    -
    - l = pkt->hash;
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    - int tmp = pair->key;
    - do {
    - tmp /= 10;
    - len++;
    - } while (tmp);
    - len += 2;
    - len += strlen(pair->value);
    - len += 2;
    - l = l->next;
    - }
    -
    - return len;
    -}
    -
    -/*
    - * 'len' is the value given to us by the server that is supposed to
    - * be the length of 'data'. But apparently there's a time when this
    - * length is incorrect. Christopher Layne thinks it might be a bug
    - * in their server code.
    - *
    - * The following information is from Christopher:
    - *
    - * It sometimes happens when Yahoo! sends a packet continuation within
    - * chat. Sometimes when joining a large chatroom the initial
    - * SERVICE_CHATJOIN packet will be so large that it will need to be
    - * split into multiple packets. That's fine, except that the length
    - * of the second packet is wrong. The packet has the same length as
    - * the first packet, and the length given in the header is the same,
    - * however the actual data in the packet is shorter than this length.
    - * So half of the packet contains good, valid data, and then the rest
    - * of the packet is junk. Luckily there is a null terminator after
    - * the valid data and before the invalid data.
    - *
    - * What does all this mean? It means that we parse through the data
    - * pulling out key/value pairs until we've parsed 'len' bytes, or until
    - * we run into a null terminator, whichever comes first.
    - */
    -void yahoo_packet_read(struct yahoo_packet *pkt, const guchar *data, int len)
    -{
    - int pos = 0;
    - char key[64];
    - const guchar *delimiter;
    - gboolean accept;
    - guint x;
    - struct yahoo_pair *pair;
    -
    - while (pos + 1 < len)
    - {
    - if (data[pos] == '\0')
    - break;
    -
    - pair = g_new0(struct yahoo_pair, 1);
    -
    - x = 0;
    - while (pos + 1 < len) {
    - if (data[pos] == 0xc0 && data[pos + 1] == 0x80)
    - break;
    - if (x >= sizeof(key)-1) {
    - x++;
    - pos++;
    - continue;
    - }
    - key[x++] = data[pos++];
    - }
    - if (x >= sizeof(key)-1) {
    - x = 0;
    - }
    - key[x] = 0;
    - pos += 2;
    - pair->key = strtol(key, NULL, 10);
    - accept = x; /* if x is 0 there was no key, so don't accept it */
    -
    - if (pos + 1 > len) {
    - /* Malformed packet! (Truncated--garbage or something) */
    - accept = FALSE;
    - }
    -
    - if (accept) {
    - delimiter = (const guchar *)g_strstr_len((const char *)&data[pos], len - pos, "\xc0\x80");
    - if (delimiter == NULL)
    - {
    - /* Malformed packet! (It doesn't end in 0xc0 0x80) */
    - g_free(pair);
    - pos = len;
    - continue;
    - }
    - x = delimiter - data;
    - pair->value = g_strndup((const gchar *)&data[pos], x - pos);
    - pos = x;
    - pkt->hash = g_slist_prepend(pkt->hash, pair);
    -
    - if (purple_debug_is_verbose() || g_getenv("PURPLE_YAHOO_DEBUG")) {
    - char *esc;
    - esc = g_strescape(pair->value, NULL);
    - purple_debug_misc("yahoo", "Key: %d \tValue: %s\n", pair->key, esc);
    - g_free(esc);
    - }
    - } else {
    - g_free(pair);
    - }
    - pos += 2;
    -
    - if (pos + 1 > len) break;
    -
    - /* Skip over garbage we've noticed in the mail notifications */
    - if (data[0] == '9' && data[pos] == 0x01)
    - pos++;
    - }
    -
    - /*
    - * Originally this function used g_slist_append(). I changed
    - * it to use g_slist_prepend() for improved performance.
    - * Ideally the Yahoo! PRPL code would be indifferent to the
    - * order of the key/value pairs, but I don't know if this is
    - * the case for all incoming messages. To be on the safe side
    - * we reverse the list.
    - */
    - pkt->hash = g_slist_reverse(pkt->hash);
    -}
    -
    -void yahoo_packet_write(struct yahoo_packet *pkt, guchar *data)
    -{
    - GSList *l;
    - int pos = 0;
    -
    - /* This is only called from one place, and the list is
    - * always backwards */
    -
    - l = pkt->hash = g_slist_reverse(pkt->hash);
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    - gchar buf[100];
    -
    - g_snprintf(buf, sizeof(buf), "%d", pair->key);
    - strcpy((char *)&data[pos], buf);
    - pos += strlen(buf);
    - data[pos++] = 0xc0;
    - data[pos++] = 0x80;
    -
    - strcpy((char *)&data[pos], pair->value);
    - pos += strlen(pair->value);
    - data[pos++] = 0xc0;
    - data[pos++] = 0x80;
    -
    - l = l->next;
    - }
    -}
    -
    -void yahoo_packet_dump(guchar *data, int len)
    -{
    -#ifdef YAHOO_DEBUG
    - int i;
    -
    - purple_debug_misc("yahoo", "");
    -
    - for (i = 0; i + 1 < len; i += 2) {
    - if ((i % 16 == 0) && i) {
    - purple_debug_misc(NULL, "\n");
    - purple_debug_misc("yahoo", "");
    - }
    -
    - purple_debug_misc(NULL, "%02x%02x ", data[i], data[i + 1]);
    - }
    - if (i < len)
    - purple_debug_misc(NULL, "%02x", data[i]);
    -
    - purple_debug_misc(NULL, "\n");
    - purple_debug_misc("yahoo", "");
    -
    - for (i = 0; i < len; i++) {
    - if ((i % 16 == 0) && i) {
    - purple_debug_misc(NULL, "\n");
    - purple_debug_misc("yahoo", "");
    - }
    -
    - if (g_ascii_isprint(data[i]))
    - purple_debug_misc(NULL, "%c ", data[i]);
    - else
    - purple_debug_misc(NULL, ". ");
    - }
    -
    - purple_debug_misc(NULL, "\n");
    -#endif /* YAHOO_DEBUG */
    -}
    -
    -static void
    -yahoo_packet_send_can_write(gpointer data, gint source, PurpleInputCondition cond)
    -{
    - YahooData *yd = data;
    - int ret, writelen;
    -
    - writelen = purple_circ_buffer_get_max_read(yd->txbuf);
    -
    - if (writelen == 0) {
    - purple_input_remove(yd->txhandler);
    - yd->txhandler = 0;
    - return;
    - }
    -
    - ret = write(yd->fd, yd->txbuf->outptr, writelen);
    -
    - if (ret < 0 && errno == EAGAIN)
    - return;
    - else if (ret < 0) {
    - /* TODO: what to do here - do we really have to disconnect? */
    - purple_connection_error_reason(yd->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
    - _("Write Error"));
    - return;
    - }
    -
    - purple_circ_buffer_mark_read(yd->txbuf, ret);
    -}
    -
    -
    -size_t yahoo_packet_build(struct yahoo_packet *pkt, int pad, gboolean wm,
    - gboolean jp, guchar **buf)
    -{
    - size_t pktlen = yahoo_packet_length(pkt);
    - size_t len = YAHOO_PACKET_HDRLEN + pktlen;
    - guchar *data;
    - int pos = 0;
    -
    - data = g_malloc0(len + 1);
    -
    - memcpy(data + pos, "YMSG", 4); pos += 4;
    -
    - if (wm)
    - pos += yahoo_put16(data + pos, YAHOO_WEBMESSENGER_PROTO_VER);
    - else if (jp)
    - pos += yahoo_put16(data + pos, YAHOO_PROTO_VER_JAPAN);
    - else
    - pos += yahoo_put16(data + pos, YAHOO_PROTO_VER);
    - pos += yahoo_put16(data + pos, 0x0000);
    - pos += yahoo_put16(data + pos, pktlen + pad);
    - pos += yahoo_put16(data + pos, pkt->service);
    - pos += yahoo_put32(data + pos, pkt->status);
    - pos += yahoo_put32(data + pos, pkt->id);
    -
    - yahoo_packet_write(pkt, data + pos);
    -
    - *buf = data;
    -
    - return len;
    -}
    -
    -int yahoo_packet_send(struct yahoo_packet *pkt, YahooData *yd)
    -{
    - size_t len;
    - gssize ret;
    - guchar *data;
    -
    - if (yd->fd < 0)
    - return -1;
    -
    - len = yahoo_packet_build(pkt, 0, yd->wm, yd->jp, &data);
    -
    - yahoo_packet_dump(data, len);
    - if (yd->txhandler == 0)
    - ret = write(yd->fd, data, len);
    - else {
    - ret = -1;
    - errno = EAGAIN;
    - }
    -
    - if (ret < 0 && errno == EAGAIN)
    - ret = 0;
    - else if (ret <= 0) {
    - purple_debug_warning("yahoo", "Only wrote %" G_GSSIZE_FORMAT
    - " of %" G_GSIZE_FORMAT " bytes!\n", ret, len);
    - g_free(data);
    - return ret;
    - }
    -
    - if ((gsize)ret < len) {
    - if (yd->txhandler == 0)
    - yd->txhandler = purple_input_add(yd->fd, PURPLE_INPUT_WRITE,
    - yahoo_packet_send_can_write, yd);
    - purple_circ_buffer_append(yd->txbuf, data + ret, len - ret);
    - }
    -
    - g_free(data);
    -
    - return ret;
    -}
    -
    -int yahoo_packet_send_and_free(struct yahoo_packet *pkt, YahooData *yd)
    -{
    - int ret;
    -
    - ret = yahoo_packet_send(pkt, yd);
    - yahoo_packet_free(pkt);
    - return ret;
    -}
    -
    -void yahoo_packet_free(struct yahoo_packet *pkt)
    -{
    - while (pkt->hash) {
    - struct yahoo_pair *pair = pkt->hash->data;
    - g_free(pair->value);
    - g_free(pair);
    - pkt->hash = g_slist_delete_link(pkt->hash, pkt->hash);
    - }
    - g_free(pkt);
    -}
    --- a/libpurple/protocols/yahoo/yahoo_packet.h Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,150 +0,0 @@
    -/**
    - * @file yahoo_packet.h The Yahoo! protocol plugin
    - *
    - * purple
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * This program is free software; you can redistribute it and/or modify
    - * it under the terms of the GNU General Public License as published by
    - * the Free Software Foundation; either version 2 of the License, or
    - * (at your option) any later version.
    - *
    - * This program is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    - * GNU General Public License for more details.
    - *
    - * You should have received a copy of the GNU General Public License
    - * along with this program; if not, write to the Free Software
    - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    - */
    -
    -#ifndef _YAHOO_PACKET_H_
    -#define _YAHOO_PACKET_H_
    -
    -enum yahoo_service { /* these are easier to see in hex */
    - YAHOO_SERVICE_LOGON = 1,
    - YAHOO_SERVICE_LOGOFF,
    - YAHOO_SERVICE_ISAWAY,
    - YAHOO_SERVICE_ISBACK,
    - YAHOO_SERVICE_IDLE, /* 5 (placemarker) */
    - YAHOO_SERVICE_MESSAGE,
    - YAHOO_SERVICE_IDACT,
    - YAHOO_SERVICE_IDDEACT,
    - YAHOO_SERVICE_MAILSTAT,
    - YAHOO_SERVICE_USERSTAT, /* 0xa */
    - YAHOO_SERVICE_NEWMAIL,
    - YAHOO_SERVICE_CHATINVITE,
    - YAHOO_SERVICE_CALENDAR,
    - YAHOO_SERVICE_NEWPERSONALMAIL,
    - YAHOO_SERVICE_NEWCONTACT,
    - YAHOO_SERVICE_ADDIDENT, /* 0x10 */
    - YAHOO_SERVICE_ADDIGNORE,
    - YAHOO_SERVICE_PING,
    - YAHOO_SERVICE_GOTGROUPRENAME,
    - YAHOO_SERVICE_SYSMESSAGE = 0x14,
    - YAHOO_SERVICE_SKINNAME = 0x15,
    - YAHOO_SERVICE_PASSTHROUGH2 = 0x16,
    - YAHOO_SERVICE_CONFINVITE = 0x18,
    - YAHOO_SERVICE_CONFLOGON,
    - YAHOO_SERVICE_CONFDECLINE,
    - YAHOO_SERVICE_CONFLOGOFF,
    - YAHOO_SERVICE_CONFADDINVITE,
    - YAHOO_SERVICE_CONFMSG,
    - YAHOO_SERVICE_CHATLOGON,
    - YAHOO_SERVICE_CHATLOGOFF,
    - YAHOO_SERVICE_CHATMSG = 0x20,
    - YAHOO_SERVICE_GAMELOGON = 0x28,
    - YAHOO_SERVICE_GAMELOGOFF,
    - YAHOO_SERVICE_GAMEMSG = 0x2a,
    - YAHOO_SERVICE_FILETRANSFER = 0x46,
    - YAHOO_SERVICE_VOICECHAT = 0x4A,
    - YAHOO_SERVICE_NOTIFY = 0x4B,
    - YAHOO_SERVICE_VERIFY,
    - YAHOO_SERVICE_P2PFILEXFER,
    - YAHOO_SERVICE_PEERTOPEER = 0x4F,
    - YAHOO_SERVICE_WEBCAM,
    - YAHOO_SERVICE_AUTHRESP = 0x54,
    - YAHOO_SERVICE_LIST = 0x55,
    - YAHOO_SERVICE_AUTH = 0x57,
    - YAHOO_SERVICE_AUTHBUDDY = 0x6d,
    - YAHOO_SERVICE_ADDBUDDY = 0x83,
    - YAHOO_SERVICE_REMBUDDY = 0x84,
    - YAHOO_SERVICE_IGNORECONTACT, /* > 1, 7, 13 < 1, 66, 13, 0*/
    - YAHOO_SERVICE_REJECTCONTACT,
    - YAHOO_SERVICE_GROUPRENAME = 0x89, /* > 1, 65(new), 66(0), 67(old) */
    - YAHOO_SERVICE_KEEPALIVE = 0x8A,
    - YAHOO_SERVICE_CHATONLINE = 0x96, /* > 109(id), 1, 6(abcde) < 0,1*/
    - YAHOO_SERVICE_CHATGOTO,
    - YAHOO_SERVICE_CHATJOIN, /* > 1 104-room 129-1600326591 62-2 */
    - YAHOO_SERVICE_CHATLEAVE,
    - YAHOO_SERVICE_CHATEXIT = 0x9b,
    - YAHOO_SERVICE_CHATADDINVITE = 0x9d,
    - YAHOO_SERVICE_CHATLOGOUT = 0xa0,
    - YAHOO_SERVICE_CHATPING,
    - YAHOO_SERVICE_COMMENT = 0xa8,
    - YAHOO_SERVICE_PRESENCE_PERM = 0xb9,
    - YAHOO_SERVICE_PRESENCE_SESSION = 0xba,
    - YAHOO_SERVICE_AVATAR = 0xbc,
    - YAHOO_SERVICE_PICTURE_CHECKSUM = 0xbd,
    - YAHOO_SERVICE_PICTURE = 0xbe,
    - YAHOO_SERVICE_PICTURE_UPDATE = 0xc1,
    - YAHOO_SERVICE_PICTURE_UPLOAD = 0xc2,
    - YAHOO_SERVICE_Y6_VISIBLE_TOGGLE = 0xc5,
    - YAHOO_SERVICE_Y6_STATUS_UPDATE = 0xc6,
    - YAHOO_SERVICE_AVATAR_UPDATE = 0xc7,
    - YAHOO_SERVICE_VERIFY_ID_EXISTS = 0xc8,
    - YAHOO_SERVICE_AUDIBLE = 0xd0,
    - YAHOO_SERVICE_CONTACT_DETAILS = 0xd3,
    - /* YAHOO_SERVICE_CHAT_SESSION = 0xd4,?? Reports start of chat session, gets an id from server */
    - YAHOO_SERVICE_AUTH_REQ_15 = 0xd6,
    - YAHOO_SERVICE_FILETRANS_15 = 0xdc,
    - YAHOO_SERVICE_FILETRANS_INFO_15 = 0xdd,
    - YAHOO_SERVICE_FILETRANS_ACC_15 = 0xde,
    - /* photo sharing services ?? - 0xd2, 0xd7, 0xd8, 0xda */
    - YAHOO_SERVICE_CHGRP_15 = 0xe7,
    - YAHOO_SERVICE_STATUS_15 = 0xf0,
    - YAHOO_SERVICE_LIST_15 = 0xf1,
    - YAHOO_SERVICE_MESSAGE_ACK = 0xfb,
    - YAHOO_SERVICE_WEBLOGIN = 0x0226,
    - YAHOO_SERVICE_SMS_MSG = 0x02ea
    - /* YAHOO_SERVICE_DISCONNECT = 0x07d1 Server forces us to disconnect. Is sent with TCP FIN flag set */
    -};
    -
    -struct yahoo_pair {
    - int key;
    - char *value;
    -};
    -
    -struct yahoo_packet {
    - guint16 service;
    - gint32 status;
    - guint32 id;
    - GSList *hash;
    -};
    -
    -#define YAHOO_WEBMESSENGER_PROTO_VER 0x0065
    -#define YAHOO_PROTO_VER 0x0010
    -#define YAHOO_PROTO_VER_JAPAN 0x0010
    -
    -#define YAHOO_PACKET_HDRLEN (4 + 2 + 2 + 2 + 2 + 4 + 4)
    -
    -struct yahoo_packet *yahoo_packet_new(enum yahoo_service service,
    - enum yahoo_status status, int id);
    -void yahoo_packet_hash(struct yahoo_packet *pkt, const char *fmt, ...);
    -void yahoo_packet_hash_str(struct yahoo_packet *pkt, int key, const char *value);
    -void yahoo_packet_hash_int(struct yahoo_packet *pkt, int key, int value);
    -int yahoo_packet_send(struct yahoo_packet *pkt, YahooData *yd);
    -int yahoo_packet_send_and_free(struct yahoo_packet *pkt, YahooData *yd);
    -size_t yahoo_packet_build(struct yahoo_packet *pkt, int pad, gboolean wm, gboolean jp,
    -guchar **buf);
    -void yahoo_packet_read(struct yahoo_packet *pkt, const guchar *data, int len);
    -void yahoo_packet_write(struct yahoo_packet *pkt, guchar *data);
    -void yahoo_packet_dump(guchar *data, int len);
    -size_t yahoo_packet_length(struct yahoo_packet *pkt);
    -void yahoo_packet_free(struct yahoo_packet *pkt);
    -
    -#endif /* _YAHOO_PACKET_H_ */
    --- a/libpurple/protocols/yahoo/yahoo_picture.c Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,611 +0,0 @@
    -/*
    - * purple
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * This program is free software; you can redistribute it and/or modify
    - * it under the terms of the GNU General Public License as published by
    - * the Free Software Foundation; either version 2 of the License, or
    - * (at your option) any later version.
    - *
    - * This program is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    - * GNU General Public License for more details.
    - *
    - * You should have received a copy of the GNU General Public License
    - * along with this program; if not, write to the Free Software
    - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    - *
    - */
    -
    -#include "internal.h"
    -
    -#include "account.h"
    -#include "accountopt.h"
    -#include "blist.h"
    -#include "debug.h"
    -#include "privacy.h"
    -#include "prpl.h"
    -#include "proxy.h"
    -#include "util.h"
    -
    -#include "libymsg.h"
    -#include "yahoo_packet.h"
    -#include "yahoo_friend.h"
    -#include "yahoo_picture.h"
    -
    -
    -struct yahoo_fetch_picture_data {
    - PurpleConnection *gc;
    - char *who;
    - int checksum;
    -};
    -
    -static void
    -yahoo_fetch_picture_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data,
    - const gchar *pic_data, size_t len, const gchar *error_message)
    -{
    - struct yahoo_fetch_picture_data *d;
    - YahooData *yd;
    -
    - d = user_data;
    - yd = d->gc->proto_data;
    - yd->url_datas = g_slist_remove(yd->url_datas, url_data);
    -
    - if (error_message != NULL) {
    - purple_debug_error("yahoo", "Fetching buddy icon failed: %s\n", error_message);
    - } else if (len == 0) {
    - purple_debug_error("yahoo", "Fetched an icon with length 0. Strange.\n");
    - } else {
    - char *checksum = g_strdup_printf("%i", d->checksum);
    - purple_buddy_icons_set_for_user(purple_connection_get_account(d->gc), d->who, g_memdup(pic_data, len), len, checksum);
    - g_free(checksum);
    - }
    -
    - g_free(d->who);
    - g_free(d);
    -}
    -
    -void yahoo_process_picture(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - YahooData *yd;
    - GSList *l = pkt->hash;
    - char *who = NULL;
    - gboolean got_icon_info = FALSE, send_icon_info = FALSE;
    - char *url = NULL;
    - int checksum = 0;
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 1:
    - case 4:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - who = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_picture "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 5: /* us */
    - break;
    - case 13: {
    - int tmp;
    - tmp = strtol(pair->value, NULL, 10);
    - if (tmp == 1) {
    - send_icon_info = TRUE;
    - } else if (tmp == 2) {
    - got_icon_info = TRUE;
    - }
    - break;
    - }
    - case 20:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - url = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_picture "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 192:
    - checksum = strtol(pair->value, NULL, 10);
    - break;
    - }
    -
    - l = l->next;
    - }
    -
    - if (!who)
    - return;
    -
    - if (!purple_privacy_check(purple_connection_get_account(gc), who)) {
    - purple_debug_info("yahoo", "Picture packet from %s dropped.\n", who);
    - return;
    - }
    -
    - /* Yahoo IM 6 spits out 0.png as the URL if the buddy icon is not set */
    - if (who && got_icon_info && url && !g_ascii_strncasecmp(url, "http://", 7)) {
    - /* TODO: make this work p2p, try p2p before the url */
    - PurpleUtilFetchUrlData *url_data;
    - struct yahoo_fetch_picture_data *data;
    - /* use whole URL if using HTTP Proxy */
    - gboolean use_whole_url = yahoo_account_use_http_proxy(gc);
    -
    - data = g_new0(struct yahoo_fetch_picture_data, 1);
    - data->gc = gc;
    - data->who = g_strdup(who);
    - data->checksum = checksum;
    - /* TODO: Does this need to be MSIE 5.0? */
    - url_data = purple_util_fetch_url(url, use_whole_url,
    - "Mozilla/4.0 (compatible; MSIE 5.5)", FALSE,
    - yahoo_fetch_picture_cb, data);
    - if (url_data != NULL) {
    - yd = gc->proto_data;
    - yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
    - }
    - } else if (who && send_icon_info) {
    - yahoo_send_picture_info(gc, who);
    - }
    -}
    -
    -void yahoo_process_picture_checksum(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - GSList *l = pkt->hash;
    - char *who = NULL;
    - int checksum = 0;
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 4:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - who = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_picture_checksum "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 5:
    - /* us */
    - break;
    - case 192:
    - checksum = strtol(pair->value, NULL, 10);
    - break;
    - }
    - l = l->next;
    - }
    -
    - if (who) {
    - PurpleBuddy *b = purple_find_buddy(gc->account, who);
    - const char *locksum = NULL;
    -
    - /* FIXME: Cleanup this strtol() stuff if possible. */
    - if (b) {
    - locksum = purple_buddy_icons_get_checksum_for_user(b);
    - if (!locksum || (checksum != strtol(locksum, NULL, 10)))
    - yahoo_send_picture_request(gc, who);
    - }
    - }
    -}
    -
    -void yahoo_process_picture_upload(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - PurpleAccount *account = purple_connection_get_account(gc);
    - YahooData *yd = gc->proto_data;
    - GSList *l = pkt->hash;
    - char *url = NULL;
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 5:
    - /* us */
    - break;
    - case 27:
    - /* filename on our computer. */
    - break;
    - case 20: /* url at yahoo */
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - url = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_picture_upload "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - case 38: /* timestamp */
    - break;
    - }
    - l = l->next;
    - }
    -
    - if (url) {
    - g_free(yd->picture_url);
    - yd->picture_url = g_strdup(url);
    - purple_account_set_string(account, YAHOO_PICURL_SETTING, url);
    - purple_account_set_int(account, YAHOO_PICCKSUM_SETTING, yd->picture_checksum);
    - yahoo_send_picture_checksum(gc);
    - yahoo_send_picture_update(gc, 2);
    - }
    -}
    -
    -void yahoo_process_avatar_update(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - GSList *l = pkt->hash;
    - char *who = NULL;
    - int avatar = 0;
    -
    - while (l) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 4:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - who = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_avatar_upload "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 5:
    - /* us */
    - break;
    - case 206: /* Older versions. Still needed? */
    - case 213: /* Newer versions */
    - /*
    - * 0 - No icon or avatar
    - * 1 - Using an avatar
    - * 2 - Using an icon
    - */
    - avatar = strtol(pair->value, NULL, 10);
    - break;
    - }
    - l = l->next;
    - }
    -
    - if (who) {
    - if (avatar == 2)
    - yahoo_send_picture_request(gc, who);
    - else if ((avatar == 0) || (avatar == 1)) {
    - YahooFriend *f;
    - purple_buddy_icons_set_for_user(gc->account, who, NULL, 0, NULL);
    - if ((f = yahoo_friend_find(gc, who)))
    - yahoo_friend_set_buddy_icon_need_request(f, TRUE);
    - purple_debug_misc("yahoo", "Setting user %s's icon to NULL.\n", who);
    - }
    - }
    -}
    -
    -void yahoo_send_picture_info(PurpleConnection *gc, const char *who)
    -{
    - YahooData *yd = gc->proto_data;
    - struct yahoo_packet *pkt;
    -
    - if (!yd->picture_url) {
    - purple_debug_warning("yahoo", "Attempted to send picture info without a picture\n");
    - return;
    - }
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash(pkt, "ssssi", 1, purple_connection_get_display_name(gc),
    - 5, who,
    - 13, "2", 20, yd->picture_url, 192, yd->picture_checksum);
    - yahoo_packet_send_and_free(pkt, yd);
    -}
    -
    -void yahoo_send_picture_request(PurpleConnection *gc, const char *who)
    -{
    - YahooData *yd = gc->proto_data;
    - struct yahoo_packet *pkt;
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash_str(pkt, 1, purple_connection_get_display_name(gc)); /* me */
    - yahoo_packet_hash_str(pkt, 5, who); /* the other guy */
    - yahoo_packet_hash_str(pkt, 13, "1"); /* 1 = request, 2 = reply */
    - yahoo_packet_send_and_free(pkt, yd);
    -}
    -
    -void yahoo_send_picture_checksum(PurpleConnection *gc)
    -{
    - YahooData *yd = gc->proto_data;
    - struct yahoo_packet *pkt;
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_CHECKSUM, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash(pkt, "ssi", 1, purple_connection_get_display_name(gc),
    - 212, "1", 192, yd->picture_checksum);
    - yahoo_packet_send_and_free(pkt, yd);
    -}
    -
    -void yahoo_send_picture_update_to_user(PurpleConnection *gc, const char *who, int type)
    -{
    - YahooData *yd = gc->proto_data;
    - struct yahoo_packet *pkt;
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_AVATAR_UPDATE, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash(pkt, "si", 3, who, 213, type);
    - yahoo_packet_send_and_free(pkt, yd);
    -}
    -
    -struct yspufe {
    - PurpleConnection *gc;
    - int type;
    -};
    -
    -static void yahoo_send_picture_update_foreach(gpointer key, gpointer value, gpointer data)
    -{
    - const char *who = key;
    - YahooFriend *f = value;
    - struct yspufe *d = data;
    -
    - if (f->status != YAHOO_STATUS_OFFLINE)
    - yahoo_send_picture_update_to_user(d->gc, who, d->type);
    -}
    -
    -void yahoo_send_picture_update(PurpleConnection *gc, int type)
    -{
    - YahooData *yd = gc->proto_data;
    - struct yspufe data;
    -
    - data.gc = gc;
    - data.type = type;
    -
    - g_hash_table_foreach(yd->friends, yahoo_send_picture_update_foreach, &data);
    -}
    -
    -void yahoo_buddy_icon_upload_data_free(struct yahoo_buddy_icon_upload_data *d)
    -{
    - purple_debug_misc("yahoo", "In yahoo_buddy_icon_upload_data_free()\n");
    -
    - if (d->str)
    - g_string_free(d->str, TRUE);
    - g_free(d->filename);
    - if (d->watcher)
    - purple_input_remove(d->watcher);
    - if (d->fd != -1)
    - close(d->fd);
    - g_free(d);
    -}
    -
    -/* we couldn't care less about the server's response, but yahoo gets grumpy if we close before it sends it */
    -static void yahoo_buddy_icon_upload_reading(gpointer data, gint source, PurpleInputCondition condition)
    -{
    - struct yahoo_buddy_icon_upload_data *d = data;
    - PurpleConnection *gc = d->gc;
    - char buf[1024];
    - int ret;
    -
    - if (!PURPLE_CONNECTION_IS_VALID(gc)) {
    - yahoo_buddy_icon_upload_data_free(d);
    - return;
    - }
    -
    - ret = read(d->fd, buf, sizeof(buf));
    -
    - if (ret < 0 && errno == EAGAIN)
    - return;
    - else if (ret <= 0) {
    - /* There are other problems if d->str->len overflows, so shut up the
    - * warning on 64-bit. */
    - purple_debug_info("yahoo", "Buddy icon upload response (%" G_GSIZE_FORMAT ") bytes (> ~400 indicates failure):\n%.*s\n",
    - d->str->len, (guint)d->str->len, d->str->str);
    -
    - yahoo_buddy_icon_upload_data_free(d);
    - return;
    - }
    -
    - g_string_append_len(d->str, buf, ret);
    -}
    -
    -static void yahoo_buddy_icon_upload_pending(gpointer data, gint source, PurpleInputCondition condition)
    -{
    - struct yahoo_buddy_icon_upload_data *d = data;
    - PurpleConnection *gc = d->gc;
    - gssize wrote;
    -
    - if (!PURPLE_CONNECTION_IS_VALID(gc)) {
    - yahoo_buddy_icon_upload_data_free(d);
    - return;
    - }
    -
    - wrote = write(d->fd, d->str->str + d->pos, d->str->len - d->pos);
    - if (wrote < 0 && errno == EAGAIN)
    - return;
    - if (wrote <= 0) {
    - purple_debug_info("yahoo", "Error uploading buddy icon.\n");
    - yahoo_buddy_icon_upload_data_free(d);
    - return;
    - }
    - d->pos += wrote;
    - if ((size_t)d->pos >= d->str->len) {
    - purple_debug_misc("yahoo", "Finished uploading buddy icon.\n");
    - purple_input_remove(d->watcher);
    - /* Clean out the sent buffer and reuse it to read the result */
    - g_string_free(d->str, TRUE);
    - d->str = g_string_new("");
    - d->watcher = purple_input_add(d->fd, PURPLE_INPUT_READ, yahoo_buddy_icon_upload_reading, d);
    - }
    -}
    -
    -static void yahoo_buddy_icon_upload_connected(gpointer data, gint source, const gchar *error_message)
    -{
    - struct yahoo_buddy_icon_upload_data *d = data;
    - struct yahoo_packet *pkt;
    - gchar *tmp, *header;
    - guchar *pkt_buf;
    - const char *host;
    - int port;
    - gsize pkt_buf_len;
    - PurpleConnection *gc = d->gc;
    - PurpleAccount *account;
    - YahooData *yd;
    - /* use whole URL if using HTTP Proxy */
    - gboolean use_whole_url = yahoo_account_use_http_proxy(gc);
    -
    - account = purple_connection_get_account(gc);
    - yd = gc->proto_data;
    -
    - /* Buddy icon connect is now complete; clear the PurpleProxyConnectData */
    - yd->buddy_icon_connect_data = NULL;
    -
    - if (source < 0) {
    - purple_debug_error("yahoo", "Buddy icon upload failed: %s\n", error_message);
    - yahoo_buddy_icon_upload_data_free(d);
    - return;
    - }
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_UPLOAD, YAHOO_STATUS_AVAILABLE, yd->session_id);
    -
    - tmp = g_strdup_printf("%" G_GSIZE_FORMAT, d->str->len);
    - /* 1 = me, 38 = expire time(?), 0 = me, 28 = size, 27 = filename, 14 = NULL, 29 = data */
    - yahoo_packet_hash_str(pkt, 1, purple_connection_get_display_name(gc));
    - yahoo_packet_hash_str(pkt, 38, "604800"); /* time til expire */
    - purple_account_set_int(account, YAHOO_PICEXPIRE_SETTING, time(NULL) + 604800);
    - yahoo_packet_hash_str(pkt, 0, purple_connection_get_display_name(gc));
    - yahoo_packet_hash_str(pkt, 28, tmp);
    - g_free(tmp);
    - yahoo_packet_hash_str(pkt, 27, d->filename);
    - yahoo_packet_hash_str(pkt, 14, "");
    - /* 4 padding for the 29 key name */
    - pkt_buf_len = yahoo_packet_build(pkt, 4, FALSE, yd->jp, &pkt_buf);
    - yahoo_packet_free(pkt);
    -
    - /* header + packet + "29" + 0xc0 + 0x80) + pictureblob */
    -
    - host = purple_account_get_string(account, "xfer_host", yd->jp? YAHOOJP_XFER_HOST : YAHOO_XFER_HOST);
    - port = purple_account_get_int(account, "xfer_port", YAHOO_XFER_PORT);
    - tmp = g_strdup_printf("%s:%d", host, port);
    - header = g_strdup_printf("POST %s%s/notifyft HTTP/1.1\r\n"
    - "User-Agent: " YAHOO_CLIENT_USERAGENT "\r\n"
    - "Cookie: T=%s; Y=%s\r\n"
    - "Host: %s\r\n"
    - "Content-Length: %" G_GSIZE_FORMAT "\r\n"
    - "Cache-Control: no-cache\r\n\r\n",
    - use_whole_url ? "http://" : "", use_whole_url ? tmp : "",
    - yd->cookie_t, yd->cookie_y,
    - tmp,
    - pkt_buf_len + 4 + d->str->len);
    - g_free(tmp);
    -
    - /* There's no magic here, we just need to prepend in reverse order */
    - g_string_prepend(d->str, "29\xc0\x80");
    -
    - g_string_prepend_len(d->str, (char *)pkt_buf, pkt_buf_len);
    - g_free(pkt_buf);
    -
    - g_string_prepend(d->str, header);
    - g_free(header);
    -
    - /* There are other problems if we're uploading over 4GB of data */
    - purple_debug_info("yahoo", "Buddy icon upload data:\n%.*s\n", (guint)d->str->len, d->str->str);
    -
    - d->fd = source;
    - d->watcher = purple_input_add(d->fd, PURPLE_INPUT_WRITE, yahoo_buddy_icon_upload_pending, d);
    -
    - yahoo_buddy_icon_upload_pending(d, d->fd, PURPLE_INPUT_WRITE);
    -}
    -
    -void yahoo_buddy_icon_upload(PurpleConnection *gc, struct yahoo_buddy_icon_upload_data *d)
    -{
    - PurpleAccount *account = purple_connection_get_account(gc);
    - YahooData *yd = gc->proto_data;
    -
    - if (yd->buddy_icon_connect_data != NULL) {
    - /* Cancel any in-progress buddy icon upload */
    - purple_proxy_connect_cancel(yd->buddy_icon_connect_data);
    - yd->buddy_icon_connect_data = NULL;
    - }
    -
    - yd->buddy_icon_connect_data = purple_proxy_connect(NULL, account,
    - purple_account_get_string(account, "xfer_host",
    - yd->jp? YAHOOJP_XFER_HOST : YAHOO_XFER_HOST),
    - purple_account_get_int(account, "xfer_port", YAHOO_XFER_PORT),
    - yahoo_buddy_icon_upload_connected, d);
    -
    - if (yd->buddy_icon_connect_data == NULL)
    - {
    - purple_debug_error("yahoo", "Uploading our buddy icon failed to connect.\n");
    - yahoo_buddy_icon_upload_data_free(d);
    - }
    -}
    -
    -static int yahoo_buddy_icon_calculate_checksum(const guchar *data, gsize len)
    -{
    - /* This code is borrowed from Kopete, which seems to be managing to calculate
    - checksums in such a manner that Yahoo!'s servers are happy */
    -
    - const guchar *p = data;
    - int checksum = 0, g, i = len;
    -
    - while(i--) {
    - checksum = (checksum << 4) + *p++;
    -
    - if((g = (checksum & 0xf0000000)) != 0)
    - checksum ^= g >> 23;
    -
    - checksum &= ~g;
    - }
    -
    - purple_debug_misc("yahoo", "Calculated buddy icon checksum: %d\n", checksum);
    -
    - return checksum;
    -}
    -
    -void yahoo_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img)
    -{
    - YahooData *yd = gc->proto_data;
    - PurpleAccount *account = gc->account;
    -
    - if (img == NULL) {
    - g_free(yd->picture_url);
    - yd->picture_url = NULL;
    -
    - /* TODO: don't we have to clear it on the server too?! */
    -
    - purple_account_set_string(account, YAHOO_PICURL_SETTING, NULL);
    - purple_account_set_int(account, YAHOO_PICCKSUM_SETTING, 0);
    - purple_account_set_int(account, YAHOO_PICEXPIRE_SETTING, 0);
    - if (yd->logged_in)
    - /* Tell everyone we ain't got one no more */
    - yahoo_send_picture_update(gc, 0);
    -
    - } else {
    - gconstpointer data = purple_imgstore_get_data(img);
    - size_t len = purple_imgstore_get_size(img);
    - GString *s = g_string_new_len(data, len);
    - struct yahoo_buddy_icon_upload_data *d;
    - int oldcksum = purple_account_get_int(account, YAHOO_PICCKSUM_SETTING, 0);
    - int expire = purple_account_get_int(account, YAHOO_PICEXPIRE_SETTING, 0);
    - const char *oldurl = purple_account_get_string(account, YAHOO_PICURL_SETTING, NULL);
    -
    - yd->picture_checksum = yahoo_buddy_icon_calculate_checksum(data, len);
    -
    - if ((yd->picture_checksum == oldcksum) &&
    - (expire > (time(NULL) + 60*60*24)) && oldurl)
    - {
    - purple_debug_misc("yahoo", "buddy icon is up to date. Not reuploading.\n");
    - g_string_free(s, TRUE);
    - g_free(yd->picture_url);
    - yd->picture_url = g_strdup(oldurl);
    - return;
    - }
    -
    - /* We use this solely for sending a filename to the server */
    - d = g_new0(struct yahoo_buddy_icon_upload_data, 1);
    - d->gc = gc;
    - d->str = s;
    - d->fd = -1;
    - d->filename = g_strdup(purple_imgstore_get_filename(img));
    -
    - if (!yd->logged_in) {
    - yd->picture_upload_todo = d;
    - return;
    - }
    -
    - yahoo_buddy_icon_upload(gc, d);
    -
    - }
    -}
    --- a/libpurple/protocols/yahoo/yahoo_picture.h Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,43 +0,0 @@
    -/*
    - * purple
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * This program is free software; you can redistribute it and/or modify
    - * it under the terms of the GNU General Public License as published by
    - * the Free Software Foundation; either version 2 of the License, or
    - * (at your option) any later version.
    - *
    - * This program is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    - * GNU General Public License for more details.
    - *
    - * You should have received a copy of the GNU General Public License
    - * along with this program; if not, write to the Free Software
    - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    - *
    - */
    -
    -#ifndef _YAHOO_PICTURE_H_
    -#define _YAHOO_PICTURE_H_
    -
    -void yahoo_send_picture_request(PurpleConnection *gc, const char *who);
    -void yahoo_send_picture_info(PurpleConnection *gc, const char *who);
    -void yahoo_send_picture_checksum(PurpleConnection *gc);
    -void yahoo_send_picture_update(PurpleConnection *gc, int type);
    -void yahoo_send_picture_update_to_user(PurpleConnection *gc, const char *who, int type);
    -
    -void yahoo_process_picture(PurpleConnection *gc, struct yahoo_packet *pkt);
    -void yahoo_process_picture_checksum(PurpleConnection *gc, struct yahoo_packet *pkt);
    -void yahoo_process_picture_upload(PurpleConnection *gc, struct yahoo_packet *pkt);
    -
    -void yahoo_process_avatar_update(PurpleConnection *gc, struct yahoo_packet *pkt);
    -
    -void yahoo_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img);
    -void yahoo_buddy_icon_upload(PurpleConnection *gc, struct yahoo_buddy_icon_upload_data *d);
    -void yahoo_buddy_icon_upload_data_free(struct yahoo_buddy_icon_upload_data *d);
    -
    -#endif /* _YAHOO_PICTURE_H_ */
    --- a/libpurple/protocols/yahoo/yahoo_profile.c Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,1282 +0,0 @@
    -/*
    - * purple
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * This program is free software; you can redistribute it and/or modify
    - * it under the terms of the GNU General Public License as published by
    - * the Free Software Foundation; either version 2 of the License, or
    - * (at your option) any later version.
    - *
    - * This program is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    - * GNU General Public License for more details.
    - *
    - * You should have received a copy of the GNU General Public License
    - * along with this program; if not, write to the Free Software
    - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    - *
    - */
    -
    -#define PHOTO_SUPPORT 1
    -
    -#include "internal.h"
    -#include "debug.h"
    -#include "notify.h"
    -#include "util.h"
    -#if PHOTO_SUPPORT
    -#include "imgstore.h"
    -#endif /* PHOTO_SUPPORT */
    -
    -#include "libymsg.h"
    -#include "yahoo_friend.h"
    -
    -typedef struct {
    - PurpleConnection *gc;
    - char *name;
    -} YahooGetInfoData;
    -
    -typedef enum profile_lang_id {
    - XX, DA, DE, EL,
    - EN, EN_GB,
    - ES_AR, ES_ES, ES_MX, ES_US,
    - FR_CA, FR_FR,
    - IT, JA, KO, NO, PT, SV,
    - ZH_CN, ZH_HK, ZH_TW, ZH_US, PT_BR
    -} profile_lang_id_t;
    -
    -typedef struct profile_lang_node {
    - profile_lang_id_t lang;
    - char *last_updated_string;
    - char *det;
    -} profile_lang_node_t;
    -
    -typedef struct profile_strings_node {
    - profile_lang_id_t lang;
    - char *lang_string; /* Only to make debugging output saner */
    - char *charset;
    - char *yahoo_id_string;
    - char *private_string;
    - char *no_answer_string;
    - char *my_email_string;
    - char *realname_string;
    - char *location_string;
    - char *age_string;
    - char *maritalstatus_string;
    - char *gender_string;
    - char *occupation_string;
    - char *hobbies_string;
    - char *latest_news_string;
    - char *favorite_quote_string;
    - char *links_string;
    - char *no_home_page_specified_string;
    - char *home_page_string;
    - char *no_cool_link_specified_string;
    - char *cool_link_1_string;
    - char *cool_link_2_string;
    - char *cool_link_3_string;
    - char *dummy;
    -} profile_strings_node_t;
    -
    -typedef enum profile_state {
    - PROFILE_STATE_DEFAULT,
    - PROFILE_STATE_NOT_FOUND,
    - PROFILE_STATE_UNKNOWN_LANGUAGE
    -} profile_state_t;
    -
    -typedef struct {
    - YahooGetInfoData *info_data;
    - PurpleNotifyUserInfo *user_info;
    - char *url_buffer;
    - char *photo_url_text;
    - char *profile_url_text;
    - const profile_strings_node_t *strings;
    - const char *last_updated_string;
    - const char *title;
    - profile_state_t profile_state;
    -} YahooGetInfoStepTwoData;
    -
    -/* Strings to determine the profile "language" (more accurately "locale").
    - * Strings in this list must be in the original charset in the profile.
    - * The "Last Updated" string is used, but sometimes is not sufficient to
    - * distinguish 2 locales with this (e.g., ES_ES from ES_US, or FR_CA from
    - * FR_FR, or EL from EN_GB), in which case a second string is added and
    - * such special cases must be placed before the more general case.
    - */
    -static const profile_lang_node_t profile_langs[] = {
    - { DA, "Opdateret sidste gang&nbsp;", NULL },
    - { DE, "Letzter Update&nbsp;", NULL },
    - { EL, "Last Updated:", "http://gr.profiles.yahoo.com" },
    - { EN_GB, "Last Update&nbsp;", "Favourite Quote" },
    - { EN, "Last Update:", NULL },
    - { EN, "Last Update&nbsp;", NULL },
    - { ES_AR, "\332ltima actualizaci\363n&nbsp;", NULL },
    - { ES_ES, "Actualizada el&nbsp;", "http://es.profiles.yahoo.com" },
    - { ES_MX, "Actualizada el &nbsp;", "http://mx.profiles.yahoo.com" },
    - { ES_US, "Actualizada el &nbsp;", NULL },
    - { FR_CA, "Derni\xe8re mise \xe0 jour", "http://cf.profiles.yahoo.com" },
    - { FR_FR, "Derni\xe8re mise \xe0 jour", NULL },
    - { IT, "Ultimo aggiornamento:", NULL },
    - { JA, "\xba\xc7\xbd\xaa\xb9\xb9\xbf\xb7\xc6\xfc\xa1\xa7", NULL },
    - { KO, "\xb0\xbb\xbd\xc5\x20\xb3\xaf\xc2\xa5&nbsp;", NULL },
    - { NO, "Sist oppdatert&nbsp;", NULL },
    - { PT, "\332ltima atualiza\347\343o&nbsp;", NULL },
    - { PT_BR, "\332ltima atualiza\347\343o:", NULL },
    - { SV, "Senast uppdaterad&nbsp;", NULL },
    - { ZH_CN, "\xd7\xee\xba\xf3\xd0\xde\xb8\xc4\xc8\xd5\xc6\xda", NULL },
    - { ZH_HK, "\xb3\xcc\xaa\xf1\xa7\xf3\xb7\x73\xae\xc9\xb6\xa1", NULL },
    - { ZH_US, "\xb3\xcc\xab\xe1\xad\xd7\xa7\xef\xa4\xe9\xb4\xc1", "http://chinese.profiles.yahoo.com" },
    - { ZH_TW, "\xb3\xcc\xab\xe1\xad\xd7\xa7\xef\xa4\xe9\xb4\xc1", NULL },
    - { XX, NULL, NULL }
    -};
    -
    -/* Strings in this list must be in UTF-8; &nbsp;'s should be specified as spaces. */
    -static const profile_strings_node_t profile_strings[] = {
    - { DA, "da", "ISO-8859-1",
    - "Yahoo! ID:",
    - "Privat",
    - "Intet svar",
    - "Min Email",
    - "Rigtige navn:",
    - "Opholdssted:",
    - "Alder:",
    - "Ægteskabelig status:",
    - "Køn:",
    - "Erhverv:",
    - "Hobbyer:",
    - "Sidste nyt:",
    - "Favoritcitat",
    - "Links",
    - "Ingen hjemmeside specificeret",
    - "Forside:",
    - "Intet cool link specificeret",
    - "Cool link 1:",
    - "Cool link 2:",
    - "Cool link 3:",
    - NULL
    - },
    - { DE, "de", "ISO-8859-1",
    - "Yahoo!-ID:",
    - "Privat",
    - "Keine Antwort",
    - "Meine E-Mail",
    - "Realer Name:",
    - "Ort:",
    - "Alter:",
    - "Familienstand:",
    - "Geschlecht:",
    - "Beruf:",
    - "Hobbys:",
    - "Neuste Nachrichten:",
    - "Mein Lieblingsspruch",
    - "Links",
    - "Keine Homepage angegeben",
    - "Homepage:",
    - "Keinen coolen Link angegeben",
    - "Cooler Link 1:",
    - "Cooler Link 2:",
    - "Cooler Link 3:",
    - NULL
    - },
    - { EL, "el", "ISO-8859-7", /* EL is identical to EN, except no_answer_string */
    - "Yahoo! ID:",
    - "Private",
    - "Καμία απάντηση",
    - "My Email",
    - "Real Name:",
    - "Location:",
    - "Age:",
    - "Marital Status:",
    - "Gender:",
    - "Occupation:",
    - "Hobbies:",
    - "Latest News",
    - "Favorite Quote",
    - "Links",
    - "No home page specified",
    - "Home Page:",
    - "No cool link specified",
    - "Cool Link 1:",
    - "Cool Link 2:",
    - "Cool Link 3:",
    - NULL
    - },
    - { EN, "en", "ISO-8859-1",
    - "Yahoo! ID:",
    - "Private",
    - "No Answer",
    - "My Email:",
    - "Real Name:",
    - "Location:",
    - "Age:",
    - "Marital Status:",
    - "Sex:",
    - "Occupation:",
    - "Hobbies",
    - "Latest News",
    - "Favorite Quote",
    - "Links",
    - "No home page specified",
    - "Home Page:",
    - "No cool link specified",
    - "Cool Link 1",
    - "Cool Link 2",
    - "Cool Link 3",
    - NULL
    - },
    - { EN_GB, "en_GB", "ISO-8859-1", /* Same as EN except spelling of "Favourite" */
    - "Yahoo! ID:",
    - "Private",
    - "No Answer",
    - "My Email:",
    - "Real Name:",
    - "Location:",
    - "Age:",
    - "Marital Status:",
    - "Sex:",
    - "Occupation:",
    - "Hobbies",
    - "Latest News",
    - "Favourite Quote",
    - "Links",
    - "No home page specified",
    - "Home Page:",
    - "No cool link specified",
    - "Cool Link 1",
    - "Cool Link 2",
    - "Cool Link 3",
    - NULL
    - },
    - { ES_AR, "es_AR", "ISO-8859-1",
    - "Usuario de Yahoo!:",
    - "Privado",
    - "No introdujiste una respuesta",
    - "Mi dirección de correo electrónico",
    - "Nombre real:",
    - "Ubicación:",
    - "Edad:",
    - "Estado civil:",
    - "Sexo:",
    - "Ocupación:",
    - "Pasatiempos:",
    - "Últimas noticias:",
    - "Tu cita favorita",
    - "Enlaces",
    - "Ninguna página de inicio especificada",
    - "Página de inicio:",
    - "Ningún enlace preferido",
    - "Enlace genial 1:",
    - "Enlace genial 2:",
    - "Enlace genial 3:",
    - NULL
    - },
    - { ES_ES, "es_ES", "ISO-8859-1",
    - "ID de Yahoo!:",
    - "Privado",
    - "Sin respuesta",
    - "Mi correo-e",
    - "Nombre verdadero:",
    - "Lugar:",
    - "Edad:",
    - "Estado civil:",
    - "Sexo:",
    - "Ocupación:",
    - "Aficiones:",
    - "Ultimas Noticias:",
    - "Tu cita Favorita",
    - "Enlace",
    - "Ninguna página personal especificada",
    - "Página de Inicio:",
    - "Ningún enlace preferido",
    - "Enlaces Preferidos 1:",
    - "Enlaces Preferidos 2:",
    - "Enlaces Preferidos 3:",
    - NULL
    - },
    - { ES_MX, "es_MX", "ISO-8859-1",
    - "ID de Yahoo!:",
    - "Privado",
    - "Sin responder",
    - "Mi Dirección de correo-e",
    - "Nombre real:",
    - "Ubicación:",
    - "Edad:",
    - "Estado civil:",
    - "Sexo:",
    - "Ocupación:",
    - "Pasatiempos:",
    - "Ultimas Noticias:",
    - "Su cita favorita",
    - "Enlaces",
    - "Ninguna Página predefinida",
    - "Página web:",
    - "Ningún Enlace preferido",
    - "Enlaces Preferidos 1:",
    - "Enlaces Preferidos 2:",
    - "Enlaces Preferidos 3:",
    - NULL
    - },
    - { ES_US, "es_US", "ISO-8859-1",
    - "ID de Yahoo!:",
    - "Privado",
    - "No introdujo una respuesta",
    - "Mi Dirección de correo-e",
    - "Nombre real:",
    - "Localidad:",
    - "Edad:",
    - "Estado civil:",
    - "Sexo:",
    - "Ocupación:",
    - "Pasatiempos:",
    - "Ultimas Noticias:",
    - "Su cita Favorita",
    - "Enlaces",
    - "Ninguna Página de inicio predefinida",
    - "Página de inicio:",
    - "Ningún Enlace preferido",
    - "Enlaces Preferidos 1:",
    - "Enlaces Preferidos 2:",
    - "Enlaces Preferidos 3:",
    - NULL
    - },
    - { FR_CA, "fr_CA", "ISO-8859-1",
    - "Compte Yahoo!:",
    - "Privé",
    - "Sans réponse",
    - "Mon courriel",
    - "Nom réel:",
    - "Lieu:",
    - "Âge:",
    - "État civil:",
    - "Sexe:",
    - "Profession:",
    - "Passe-temps:",
    - "Actualités:",
    - "Citation préférée",
    - "Liens",
    - "Pas de mention d'une page personnelle",
    - "Page personnelle:",
    - "Pas de mention d'un lien favori",
    - "Lien préféré 1:",
    - "Lien préféré 2:",
    - "Lien préféré 3:",
    - NULL
    - },
    - { FR_FR, "fr_FR", "ISO-8859-1",
    - "Compte Yahoo!:",
    - "Privé",
    - "Sans réponse",
    - "Mon E-mail",
    - "Nom réel:",
    - "Lieu:",
    - "Âge:",
    - "Situation de famille:",
    - "Sexe:",
    - "Profession:",
    - "Centres d'intérêts:",
    - "Actualités:",
    - "Citation préférée",
    - "Liens",
    - "Pas de mention d'une page perso",
    - "Page perso:",
    - "Pas de mention d'un lien favori",
    - "Lien préféré 1:",
    - "Lien préféré 2:",
    - "Lien préféré 3:",
    - NULL
    - },
    - { IT, "it", "ISO-8859-1",
    - "Yahoo! ID:",
    - "Non pubblica",
    - "Nessuna risposta",
    - "La mia e-mail:",
    - "Nome vero:",
    - "Località:",
    - "Età:",
    - "Stato civile:",
    - "Sesso:",
    - "Occupazione:",
    - "Hobby",
    - "Ultime notizie",
    - "Citazione preferita",
    - "Link",
    - "Nessuna home page specificata",
    - "Inizio:",
    - "Nessun link specificato",
    - "Cool Link 1",
    - "Cool Link 2",
    - "Cool Link 3",
    - NULL
    - },
    - { JA, "ja", "EUC-JP",
    - "Yahoo! JAPAN ID:",
    - "非公開",
    - "無回答",
    - "メール:",
    - "名前:",
    - "住所:",
    - "年齢:",
    - "未婚/既婚:",
    - "性別:",
    - "職業:",
    - "趣味:",
    - "最近の出来事:",
    - NULL,
    -#if 0
    - "おすすめサイト",
    -#else
    - "自己PR", /* "Self description" comes before "Links" for yahoo.co.jp */
    -#endif
    - NULL,
    - NULL,
    - NULL,
    - "おすすめサイト1:",
    - "おすすめサイト2:",
    - "おすすめサイト3:",
    - NULL
    - },
    - { KO, "ko", "EUC-KR",
    - "야후! ID:",
    - "비공개",
    - "비공개",
    - "My Email",
    - "실명:",
    - "거주지:",
    - "나이:",
    - "결혼 여부:",
    - "성별:",
    - "직업:",
    - "취미:",
    - "자기 소개:",
    - "좋아하는 명언",
    - "링크",
    - "홈페이지를 지정하지 않았습니다.",
    - "홈페이지:",
    - "추천 사이트가 없습니다.",
    - "추천 사이트 1:",
    - "추천 사이트 2:",
    - "추천 사이트 3:",
    - NULL
    - },
    - { NO, "no", "ISO-8859-1",
    - "Yahoo! ID:",
    - "Privat",
    - "Ikke noe svar",
    - "Min e-post",
    - "Virkelig navn:",
    - "Sted:",
    - "Alder:",
    - "Sivilstatus:",
    - "Kjønn:",
    - "Yrke:",
    - "Hobbyer:",
    - "Siste nytt:",
    - "Yndlingssitat",
    - "Lenker",
    - "Ingen hjemmeside angitt",
    - "Hjemmeside:",
    - "No cool link specified",
    - "Bra lenke 1:",
    - "Bra lenke 2:",
    - "Bra lenke 3:",
    - NULL
    - },
    - { PT, "pt", "ISO-8859-1",
    - "ID Yahoo!:",
    - "Particular",
    - "Sem resposta",
    - "Meu e-mail",
    - "Nome verdadeiro:",
    - "Local:",
    - "Idade:",
    - "Estado civil:",
    - "Sexo:",
    - "Ocupação:",
    - "Hobbies:",
    - "Últimas notícias:",
    - "Frase favorita",
    - "Links",
    - "Nenhuma página pessoal especificada",
    - "Página pessoal:",
    - "Nenhum site legal especificado",
    - "Site legal 1:",
    - "Site legal 2:",
    - "Site legal 3:",
    - NULL
    - },
    - { PT_BR, "pt_br", "ISO-8859-1",
    - "ID Yahoo!:",
    - "Particular",
    - "Sem resposta",
    - "Meu e-mail",
    - "Nome verdadeiro:",
    - "Localização:",
    - "Idade:",
    - "Estado civil:",
    - "Sexo:",
    - "Ocupação:",
    - "Pasatiempos:",
    - "Últimas novidades:",
    - "Frase preferida:",
    - "Links",
    - "Nenhuma home page especificada",
    - "Página Web:",
    - "Nenhum site legal especificado",
    - "Link legal 1",
    - "Link legal 2",
    - "Link legal 3",
    - NULL
    - },
    - { SV, "sv", "ISO-8859-1",
    - "Yahoo!-ID:",
    - "Privat",
    - "Inget svar",
    - "Min mail",
    - "Riktigt namn:",
    - "Plats:",
    - "Ålder:",
    - "Civilstånd:",
    - "Kön:",
    - "Yrke:",
    - "Hobby:",
    - "Senaste nytt:",
    - "Favoritcitat",
    - "Länkar",
    - "Ingen hemsida specificerad",
    - "Hemsida:",
    - "Ingen cool länk specificerad",
    - "Coola länkar 1:",
    - "Coola länkar 2:",
    - "Coola länkar 3:",
    - NULL
    - },
    - { ZH_CN, "zh_CN", "GB2312",
    - "Yahoo! ID:",
    - "没有提供",
    - "没有回答",
    - "个人电邮地址",
    - "真实姓名:",
    - "所在地点:",
    - "年龄:",
    - "婚姻状况:",
    - "性别:",
    - "职业:",
    - "业余爱好:",
    - "个人近况:",
    - "喜欢的引言",
    - "链接",
    - "没有个人主页",
    - "个人主页:",
    - "没有推荐网站链接",
    - "推荐网站链接 1:",
    - "推荐网站链接 2:",
    - "推荐网站链接 3:",
    - NULL
    - },
    - { ZH_HK, "zh_HK", "Big5",
    - "Yahoo! ID:",
    - "私人的",
    - "沒有回答",
    - "電子信箱",
    - "真實姓名:",
    - "地點:",
    - "年齡:",
    - "婚姻狀況:",
    - "性別:",
    - "職業:",
    - "嗜好:",
    - "最新消息:",
    - "最喜愛的股票叫價", /* [sic] Yahoo!'s translators don't check context */
    - "連結",
    - "沒有注明個人網頁", /* [sic] */
    - "個人網頁:",
    - "沒有注明 Cool 連結", /* [sic] */
    - "Cool 連結 1:", /* TODO */
    - "Cool 連結 2:", /* TODO */
    - "Cool 連結 3:", /* TODO */
    - NULL
    - },
    - { ZH_TW, "zh_TW", "Big5",
    - "帳 號:",
    - "沒有提供",
    - "沒有回應",
    - "電子信箱",
    - "姓名:",
    - "地點:",
    - "年齡:",
    - "婚姻狀態:",
    - "性別:",
    - "職業:",
    - "興趣:",
    - "個人近況:",
    - "喜歡的名句",
    - "連結",
    - "沒有個人網頁",
    - "個人網頁:",
    - "沒有推薦網站連結",
    - "推薦網站連結 1:",
    - "推薦網站連結 2:",
    - "推薦網站連結 3:",
    - NULL
    - },
    - { ZH_US, "zh_US", "Big5", /* ZH_US is like ZH_TW, but also a bit like ZH_HK */
    - "Yahoo! ID:",
    - "沒有提供",
    - "沒有回答",
    - "個人Email地址",
    - "真實姓名:",
    - "地點:",
    - "年齡:",
    - "婚姻狀態:",
    - "性別:",
    - "職業:",
    - "嗜好:",
    - "個人近況:",
    - "喜歡的名句",
    - "連結",
    - "沒有個人網頁",
    - "個人網頁:",
    - "沒有推薦網站連結",
    - "推薦網站連結 1:", /* TODO */
    - "推薦網站連結 2:", /* TODO */
    - "推薦網站連結 3:", /* TODO */
    - NULL
    - },
    - { XX, NULL, NULL,
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - NULL
    - },
    -};
    -
    -static char *yahoo_info_date_reformat(const char *field, size_t len)
    -{
    - char *tmp = g_strndup(field, len);
    - time_t t = purple_str_to_time(tmp, FALSE, NULL, NULL, NULL);
    -
    - g_free(tmp);
    - return g_strdup(purple_date_format_short(localtime(&t)));
    -}
    -
    -static char *yahoo_remove_nonbreaking_spaces(char *str)
    -{
    - char *p;
    - while ((p = strstr(str, "&nbsp;")) != NULL) {
    - *p = ' '; /* Turn &nbsp;'s into ordinary blanks */
    - p += 1;
    - memmove(p, p + 5, strlen(p + 5));
    - str[strlen(str) - 5] = '\0';
    - }
    - return str;
    -}
    -
    -static void yahoo_extract_user_info_text(PurpleNotifyUserInfo *user_info, YahooGetInfoData *info_data) {
    - PurpleBuddy *b;
    - YahooFriend *f;
    -
    - b = purple_find_buddy(purple_connection_get_account(info_data->gc),
    - info_data->name);
    -
    - if (b) {
    - const char *balias = purple_buddy_get_local_buddy_alias(b);
    - if(balias && balias[0]) {
    - purple_notify_user_info_add_pair_plaintext(user_info, _("Alias"), balias);
    - }
    - #if 0
    - if (b->idle > 0) {
    - char *idletime = purple_str_seconds_to_string(time(NULL) - b->idle);
    - purple_notify_user_info_add_pair_plaintext(user_info, _("Idle"), idletime);
    - g_free(idletime);
    - }
    - #endif
    -
    - /* Add the normal tooltip pairs */
    - yahoo_tooltip_text(b, user_info, TRUE);
    -
    - if ((f = yahoo_friend_find(info_data->gc, purple_buddy_get_name(b)))) {
    - const char *ip;
    - if ((ip = yahoo_friend_get_ip(f)))
    - purple_notify_user_info_add_pair_plaintext(user_info, _("IP Address"), ip);
    - }
    - }
    -}
    -
    -#if PHOTO_SUPPORT
    -
    -static char *yahoo_get_photo_url(const char *url_text, const char *name) {
    - GString *s = g_string_sized_new(strlen(name) + 8);
    - char *p;
    - char *it = NULL;
    -
    - /*g_string_printf(s, " alt=\"%s\">", name);*/
    - /* Y! newformat */
    - g_string_printf(s, " alt=%s>", name);
    - p = strstr(url_text, s->str);
    -
    - if (p) {
    - /* Search backwards for "http://". This is stupid, but it works. */
    - for (; !it && p > url_text; p -= 1) {
    - /*if (strncmp(p, "\"http://", 8) == 0) {*/
    - /* Y! newformat*/
    - if (strncmp(p, "=http://", 8) == 0) {
    - char *q;
    - p += 1; /* skip only the ' ' */
    - q = strchr(p, ' ');
    - if (q) {
    - g_free(it);
    - it = g_strndup(p, q - p);
    - }
    - }
    - }
    - }
    -
    - g_string_free(s, TRUE);
    - return it;
    -}
    -
    -static void
    -yahoo_got_photo(PurpleUtilFetchUrlData *url_data, gpointer data,
    - const gchar *url_text, size_t len, const gchar *error_message);
    -
    -#endif /* PHOTO_SUPPORT */
    -
    -static void yahoo_got_info(PurpleUtilFetchUrlData *url_data, gpointer user_data,
    - const gchar *url_text, size_t len, const gchar *error_message)
    -{
    - YahooGetInfoData *info_data = (YahooGetInfoData *)user_data;
    - PurpleNotifyUserInfo *user_info;
    - char *p;
    -#if PHOTO_SUPPORT
    - YahooGetInfoStepTwoData *info2_data;
    - char *photo_url_text = NULL;
    -#else
    - gboolean found = FALSE;
    - char *stripped;
    - int stripped_len;
    - char *last_updated_utf8_string = NULL;
    -#endif /* !PHOTO_SUPPORT */
    - const char *last_updated_string = NULL;
    - char *url_buffer;
    - GString *s;
    - char *tmp;
    - char *profile_url_text = NULL;
    - int lang, strid;
    - YahooData *yd;
    - const profile_strings_node_t *strings = NULL;
    - const char *title;
    - profile_state_t profile_state = PROFILE_STATE_DEFAULT;
    -
    - purple_debug_info("yahoo", "In yahoo_got_info\n");
    -
    - yd = info_data->gc->proto_data;
    - yd->url_datas = g_slist_remove(yd->url_datas, url_data);
    -
    - user_info = purple_notify_user_info_new();
    -
    - title = yd->jp ? _("Yahoo! Japan Profile") :
    - _("Yahoo! Profile");
    -
    - /* Get the tooltip info string */
    - yahoo_extract_user_info_text(user_info, info_data);
    -
    - /* We failed to grab the profile URL. This is not expected to actually
    - * happen except under unusual error conditions, as Yahoo is observed
    - * to send back HTML, with a 200 status code.
    - */
    - if (error_message != NULL || url_text == NULL || strcmp(url_text, "") == 0) {
    - purple_notify_user_info_add_pair(user_info, _("Error retrieving profile"), NULL);
    - purple_notify_userinfo(info_data->gc, info_data->name,
    - user_info, NULL, NULL);
    - purple_notify_user_info_destroy(user_info);
    - g_free(profile_url_text);
    - g_free(info_data->name);
    - g_free(info_data);
    - return;
    - }
    -
    - /* Construct the correct profile URL */
    - s = g_string_sized_new(80); /* wild guess */
    - g_string_printf(s, "%s%s", (yd->jp? YAHOOJP_PROFILE_URL: YAHOO_PROFILE_URL),
    - info_data->name);
    - profile_url_text = g_string_free(s, FALSE);
    - s = NULL;
    -
    - /* We don't yet support the multiple link level of the warning page for
    - * 'adult' profiles, not to mention the fact that yahoo wants you to be
    - * logged in (on the website) to be able to view an 'adult' profile. For
    - * now, just tell them that we can't help them, and provide a link to the
    - * profile if they want to do the web browser thing.
    - */
    - p = strstr(url_text, "Adult Profiles Warning Message");
    - if (!p) {
    - p = strstr(url_text, "Adult Content Warning"); /* TITLE element */
    - }
    - if (p) {
    - tmp = g_strdup_printf("<b>%s</b><br><br>"
    - "%s<br><a href=\"%s\">%s</a>",
    - _("Sorry, profiles marked as containing adult content "
    - "are not supported at this time."),
    - _("If you wish to view this profile, "
    - "you will need to visit this link in your web browser:"),
    - profile_url_text, profile_url_text);
    - purple_notify_user_info_add_pair(user_info, NULL, tmp);
    - g_free(tmp);
    -
    - purple_notify_userinfo(info_data->gc, info_data->name,
    - user_info, NULL, NULL);
    -
    - g_free(profile_url_text);
    - purple_notify_user_info_destroy(user_info);
    - g_free(info_data->name);
    - g_free(info_data);
    - return;
    - }
    -
    - /* Check whether the profile is written in a supported language */
    - for (lang = 0;; lang += 1) {
    - last_updated_string = profile_langs[lang].last_updated_string;
    - if (!last_updated_string)
    - break;
    -
    - p = strstr(url_text, last_updated_string);
    -
    - if (p) {
    - if (profile_langs[lang].det && !strstr(url_text, profile_langs[lang].det))
    - p = NULL;
    - else
    - break;
    - }
    - }
    -
    - if (p) {
    - for (strid = 0; profile_strings[strid].lang != XX; strid += 1) {
    - if (profile_strings[strid].lang == profile_langs[lang].lang) break;
    - }
    - strings = profile_strings + strid;
    - purple_debug_info("yahoo", "detected profile lang = %s (%d)\n", profile_strings[strid].lang_string, lang);
    - }
    -
    - /* Every user may choose his/her own profile language, and this language
    - * has nothing to do with the preferences of the user which looks at the
    - * profile. We try to support all languages, but nothing is guaranteed.
    - * If we cannot determine the language, it means either (1) the profile
    - * is written in an unsupported language, (2) our language support is
    - * out of date, or (3) the user is not found, or (4) Y! have changed their
    - * webpage layout
    - */
    - if (!p || strings->lang == XX) {
    - if (!strstr(url_text, "Yahoo! Member Directory - User not found")
    - && !strstr(url_text, "was not found on this server.")
    - && !strstr(url_text, "\xb8\xf8\xb3\xab\xa5\xd7\xa5\xed\xa5\xd5\xa5\xa3\xa1\xbc\xa5\xeb\xa4\xac\xb8\xab\xa4\xc4\xa4\xab\xa4\xea\xa4\xde\xa4\xbb\xa4\xf3")) {
    - profile_state = PROFILE_STATE_UNKNOWN_LANGUAGE;
    - } else {
    - profile_state = PROFILE_STATE_NOT_FOUND;
    - }
    - }
    -
    -#if PHOTO_SUPPORT
    - photo_url_text = yahoo_get_photo_url(url_text, info_data->name);
    -#endif /* PHOTO_SUPPORT */
    -
    - url_buffer = g_strdup(url_text);
    -
    - /*
    - * purple_markup_strip_html() doesn't strip out character entities like &nbsp;
    - * and &#183;
    - */
    - yahoo_remove_nonbreaking_spaces(url_buffer);
    -#if 1
    - while ((p = strstr(url_buffer, "&#183;")) != NULL) {
    - memmove(p, p + 6, strlen(p + 6));
    - url_buffer[strlen(url_buffer) - 6] = '\0';
    - }
    -#endif
    -
    - /* nuke the nasty \r's */
    - purple_str_strip_char(url_buffer, '\r');
    -
    -#if PHOTO_SUPPORT
    - /* Marshall the existing state */
    - info2_data = g_malloc(sizeof(YahooGetInfoStepTwoData));
    - info2_data->info_data = info_data;
    - info2_data->url_buffer = url_buffer;
    - info2_data->photo_url_text = photo_url_text;
    - info2_data->profile_url_text = profile_url_text;
    - info2_data->strings = strings;
    - info2_data->last_updated_string = last_updated_string;
    - info2_data->title = title;
    - info2_data->profile_state = profile_state;
    - info2_data->user_info = user_info;
    -
    - /* Try to put the photo in there too, if there's one */
    - if (photo_url_text) {
    - PurpleUtilFetchUrlData *url_data;
    - /* use whole URL if using HTTP Proxy */
    - gboolean use_whole_url = yahoo_account_use_http_proxy(info_data->gc);
    -
    - /* User-uploaded photos use a different server that requires the Host
    - * header, but Yahoo Japan will use the "chunked" content encoding if
    - * we specify HTTP 1.1. So we have to specify 1.0 & fix purple_util_fetch_url
    - */
    - url_data = purple_util_fetch_url(photo_url_text, use_whole_url, NULL,
    - FALSE, yahoo_got_photo, info2_data);
    - if (url_data != NULL)
    - yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
    - } else {
    - /* Emulate a callback */
    - yahoo_got_photo(NULL, info2_data, NULL, 0, NULL);
    - }
    -}
    -
    -static void
    -yahoo_got_photo(PurpleUtilFetchUrlData *url_data, gpointer data,
    - const gchar *url_text, size_t len, const gchar *error_message)
    -{
    - YahooGetInfoStepTwoData *info2_data = (YahooGetInfoStepTwoData *)data;
    - YahooData *yd;
    - gboolean found = FALSE;
    - int id = -1;
    -
    - /* Temporary variables */
    - char *p = NULL;
    - char *stripped;
    - int stripped_len;
    - char *last_updated_utf8_string = NULL;
    - char *tmp;
    -
    - /* Unmarshall the saved state */
    - YahooGetInfoData *info_data = info2_data->info_data;
    - char *url_buffer = info2_data->url_buffer;
    - PurpleNotifyUserInfo *user_info = info2_data->user_info;
    - char *photo_url_text = info2_data->photo_url_text;
    - char *profile_url_text = info2_data->profile_url_text;
    - const profile_strings_node_t *strings = info2_data->strings;
    - const char *last_updated_string = info2_data->last_updated_string;
    - profile_state_t profile_state = info2_data->profile_state;
    -
    - /* We continue here from yahoo_got_info, as if nothing has happened */
    -#endif /* PHOTO_SUPPORT */
    -
    - /* Jun 29 05 Bleeter: Y! changed their profile pages. Terminators now seem to be */
    - /* </dd> and not \n. The prpl's need to be audited before it can be moved */
    - /* in to purple_markup_strip_html*/
    - char *fudged_buffer;
    -
    - yd = info_data->gc->proto_data;
    - yd->url_datas = g_slist_remove(yd->url_datas, url_data);
    -
    - fudged_buffer = purple_strcasereplace(url_buffer, "</dd>", "</dd><br>");
    - /* nuke the html, it's easier than trying to parse the horrid stuff */
    - stripped = purple_markup_strip_html(fudged_buffer);
    - stripped_len = strlen(stripped);
    -
    - purple_debug_misc("yahoo", "stripped = %p\n", stripped);
    - purple_debug_misc("yahoo", "url_buffer = %p\n", url_buffer);
    -
    - /* convert to utf8 */
    - if (strings && strings->charset) {
    - p = g_convert(stripped, -1, "utf-8", strings->charset,
    - NULL, NULL, NULL);
    - if (!p) {
    - p = g_locale_to_utf8(stripped, -1, NULL, NULL, NULL);
    - if (!p) {
    - p = g_convert(stripped, -1, "utf-8", "windows-1252",
    - NULL, NULL, NULL);
    - }
    - }
    - if (p) {
    - g_free(stripped);
    - stripped = purple_utf8_ncr_decode(p);
    - stripped_len = strlen(stripped);
    - g_free(p);
    - }
    - }
    - p = NULL;
    -
    - /* "Last updated" should also be converted to utf8 and with &nbsp; killed */
    - if (strings && strings->charset) {
    - last_updated_utf8_string = g_convert(last_updated_string, -1, "utf-8",
    - strings->charset, NULL, NULL, NULL);
    - yahoo_remove_nonbreaking_spaces(last_updated_utf8_string);
    -
    - purple_debug_misc("yahoo", "after utf8 conversion: stripped = (%s)\n", stripped);
    - }
    -
    - if (strings && profile_state == PROFILE_STATE_DEFAULT) {
    -#if 0
    - /* extract their Yahoo! ID and put it in. Don't bother marking has_info as
    - * true, since the Yahoo! ID will always be there */
    - if (!purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - strings->yahoo_id_string, (yd->jp ? 2 : 10), "\n", 0,
    - NULL, _("Yahoo! ID"), 0, NULL, NULL))
    - ;
    -#endif
    -
    -#if PHOTO_SUPPORT
    - /* Try to put the photo in there too, if there's one and is readable */
    - if (url_text && len != 0) {
    - if (strstr(url_text, "400 Bad Request")
    - || strstr(url_text, "403 Forbidden")
    - || strstr(url_text, "404 Not Found")) {
    -
    - purple_debug_info("yahoo", "Error getting %s: %s\n",
    - photo_url_text, url_text);
    - } else {
    - purple_debug_info("yahoo", "%s is %" G_GSIZE_FORMAT
    - " bytes\n", photo_url_text, len);
    - id = purple_imgstore_add_with_id(g_memdup(url_text, len), len, NULL);
    -
    - tmp = g_strdup_printf("<img id=\"%d\"><br>", id);
    - purple_notify_user_info_add_pair(user_info, NULL, tmp);
    - g_free(tmp);
    - }
    - }
    -#endif /* PHOTO_SUPPORT */
    -
    - /* extract their Email address and put it in */
    - found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - strings->my_email_string, (yd->jp ? 4 : 1), " ", 0,
    - strings->private_string, _("Email"), 0, NULL, NULL);
    -
    - /* extract the Nickname if it exists */
    - found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - "Nickname:", 1, "\n", '\n',
    - NULL, _("Nickname"), 0, NULL, NULL);
    -
    - /* extract their RealName and put it in */
    - found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - strings->realname_string, (yd->jp ? 3 : 1), "\n", '\n',
    - NULL, _("Real Name"), 0, NULL, NULL);
    -
    - /* extract their Location and put it in */
    - found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - strings->location_string, (yd->jp ? 4 : 2), "\n", '\n',
    - NULL, _("Location"), 0, NULL, NULL);
    -
    - /* extract their Age and put it in */
    - found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - strings->age_string, (yd->jp ? 2 : 3), "\n", '\n',
    - NULL, _("Age"), 0, NULL, NULL);
    -
    - /* extract their MaritalStatus and put it in */
    - found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - strings->maritalstatus_string, (yd->jp ? 2 : 3), "\n", '\n',
    - strings->no_answer_string, _("Marital Status"), 0, NULL, NULL);
    -
    - /* extract their Gender and put it in */
    - found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - strings->gender_string, (yd->jp ? 2 : 3), "\n", '\n',
    - strings->no_answer_string, _("Gender"), 0, NULL, NULL);
    -
    - /* extract their Occupation and put it in */
    - found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - strings->occupation_string, 2, "\n", '\n',
    - NULL, _("Occupation"), 0, NULL, NULL);
    -
    - /* Hobbies, Latest News, and Favorite Quote are a bit different, since
    - * the values can contain embedded newlines... but any or all of them
    - * can also not appear. The way we delimit them is to successively
    - * look for the next one that _could_ appear, and if all else fails,
    - * we end the section by looking for the 'Links' heading, which is the
    - * next thing to follow this bunch. (For Yahoo Japan, we check for
    - * the "Description" ("Self PR") heading instead of "Links".)
    - */
    -
    - if (!purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - strings->hobbies_string, (yd->jp ? 3 : 1), strings->latest_news_string,
    - '\n', "\n", _("Hobbies"), 0, NULL, NULL))
    - {
    - if (!purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - strings->hobbies_string, 1, strings->favorite_quote_string,
    - '\n', "\n", _("Hobbies"), 0, NULL, NULL))
    - {
    - found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - strings->hobbies_string, 1, strings->links_string,
    - '\n', "\n", _("Hobbies"), 0, NULL, NULL);
    - }
    - else
    - found = TRUE;
    - }
    - else
    - found = TRUE;
    -
    - if (!purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - strings->latest_news_string, 1, strings->favorite_quote_string,
    - '\n', "\n", _("Latest News"), 0, NULL, NULL))
    - {
    - found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - strings->latest_news_string, (yd->jp ? 2 : 1), strings->links_string,
    - '\n', "\n", _("Latest News"), 0, NULL, NULL);
    - }
    - else
    - found = TRUE;
    -
    - found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - strings->favorite_quote_string, 1, strings->links_string,
    - '\n', "\n", _("Favorite Quote"), 0, NULL, NULL);
    -
    - /* Home Page will either be "No home page specified",
    - * or "Home Page: " and a link.
    - * For Yahoo! Japan, if there is no home page specified,
    - * neither "No home page specified" nor "Home Page:" is shown.
    - */
    - if (strings->home_page_string) {
    - p = !strings->no_home_page_specified_string? NULL:
    - strstr(stripped, strings->no_home_page_specified_string);
    - if(!p)
    - {
    - found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - strings->home_page_string, 1, "\n", 0, NULL,
    - _("Home Page"), 1, NULL, NULL);
    - }
    - }
    -
    - /* Cool Link {1,2,3} is also different. If "No cool link specified"
    - * exists, then we have none. If we have one however, we'll need to
    - * check and see if we have a second one. If we have a second one,
    - * we have to check to see if we have a third one.
    - */
    - p = !strings->no_cool_link_specified_string? NULL:
    - strstr(stripped,strings->no_cool_link_specified_string);
    - if (!p)
    - {
    - if (purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - strings->cool_link_1_string, 1, "\n", 0, NULL,
    - _("Cool Link 1"), 1, NULL, NULL))
    - {
    - found = TRUE;
    - if (purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - strings->cool_link_2_string, 1, "\n", 0, NULL,
    - _("Cool Link 2"), 1, NULL, NULL))
    - {
    - purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - strings->cool_link_3_string, 1, "\n", 0, NULL,
    - _("Cool Link 3"), 1, NULL, NULL);
    - }
    - }
    - }
    -
    - if (last_updated_utf8_string != NULL) {
    - /* see if Member Since is there, and if so, extract it. */
    - found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - "Member Since:", 1, last_updated_utf8_string,
    - '\n', NULL, _("Member Since"), 0, NULL, yahoo_info_date_reformat);
    -
    - /* extract the Last Updated date and put it in */
    - found |= purple_markup_extract_info_field(stripped, stripped_len, user_info,
    - last_updated_utf8_string, (yd->jp ? 2 : 1), (yd->jp ? "\n" : " "), (yd->jp ? 0 : '\n'), NULL,
    - _("Last Update"), 0, NULL, (yd->jp ? NULL : yahoo_info_date_reformat));
    - }
    - } /* if (profile_state == PROFILE_STATE_DEFAULT) */
    -
    - if(!found)
    - {
    - const gchar *str;
    -
    - purple_notify_user_info_add_section_break(user_info);
    - purple_notify_user_info_add_pair(user_info,
    - _("Error retrieving profile"), NULL);
    -
    - if (profile_state == PROFILE_STATE_UNKNOWN_LANGUAGE) {
    - str = _("This profile is in a language "
    - "or format that is not supported at this time.");
    -
    - } else if (profile_state == PROFILE_STATE_NOT_FOUND) {
    - PurpleBuddy *b = purple_find_buddy
    - (purple_connection_get_account(info_data->gc),
    - info_data->name);
    - YahooFriend *f = NULL;
    - if (b) {
    - /* Someone on the buddy list can be "not on server list",
    - * in which case the user may or may not actually exist.
    - * Hence this extra step.
    - */
    - PurpleAccount *account = purple_buddy_get_account(b);
    - f = yahoo_friend_find(purple_account_get_connection(account),
    - purple_buddy_get_name(b));
    - }
    - str = f ? _("Could not retrieve the user's profile. "
    - "This most likely is a temporary server-side problem. "
    - "Please try again later.") :
    - _("Could not retrieve the user's profile. "
    - "This most likely means that the user does not exist; "
    - "however, Yahoo! sometimes does fail to find a user's "
    - "profile. If you know that the user exists, "
    - "please try again later.");
    - } else {
    - str = _("The user's profile is empty.");
    - }
    -
    - purple_notify_user_info_add_pair(user_info, NULL, str);
    - }
    -
    - /* put a link to the actual profile URL */
    - purple_notify_user_info_add_section_break(user_info);
    - tmp = g_strdup_printf("<a href=\"%s\">%s</a>",
    - profile_url_text, _("View web profile"));
    - purple_notify_user_info_add_pair(user_info, NULL, tmp);
    - g_free(tmp);
    -
    - g_free(stripped);
    -
    - /* show it to the user */
    - purple_notify_userinfo(info_data->gc, info_data->name,
    - user_info, NULL, NULL);
    - purple_notify_user_info_destroy(user_info);
    -
    - g_free(last_updated_utf8_string);
    - g_free(url_buffer);
    - g_free(fudged_buffer);
    - g_free(profile_url_text);
    - g_free(info_data->name);
    - g_free(info_data);
    -
    -#if PHOTO_SUPPORT
    - g_free(photo_url_text);
    - g_free(info2_data);
    - if (id != -1)
    - purple_imgstore_unref_by_id(id);
    -#endif /* PHOTO_SUPPORT */
    -}
    -
    -void yahoo_get_info(PurpleConnection *gc, const char *name)
    -{
    - YahooData *yd = gc->proto_data;
    - YahooGetInfoData *data;
    - char *url;
    - PurpleUtilFetchUrlData *url_data;
    -
    - data = g_new0(YahooGetInfoData, 1);
    - data->gc = gc;
    - data->name = g_strdup(name);
    -
    - url = g_strdup_printf("%s%s",
    - (yd->jp ? YAHOOJP_PROFILE_URL : YAHOO_PROFILE_URL), name);
    -
    - url_data = purple_util_fetch_url(url, TRUE, NULL, FALSE, yahoo_got_info, data);
    - if (url_data != NULL)
    - yd->url_datas = g_slist_prepend(yd->url_datas, url_data);
    -
    - g_free(url);
    -}
    --- a/libpurple/protocols/yahoo/yahoochat.c Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,1684 +0,0 @@
    -/*
    - * purple
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * Some code copyright 2003 Tim Ringenbach <omarvo@hotmail.com>
    - * (marv on irc.freenode.net)
    - * Some code borrowed from libyahoo2, copyright (C) 2002, Philip
    - * S Tellis <philip . tellis AT gmx . 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
    - *
    - */
    -
    -#include "internal.h"
    -
    -#ifdef HAVE_CONFIG_H
    -#include "config.h"
    -#endif /* HAVE_CONFIG_H */
    -
    -#include "debug.h"
    -#include "privacy.h"
    -#include "prpl.h"
    -
    -#include "conversation.h"
    -#include "notify.h"
    -#include "util.h"
    -
    -#include "libymsg.h"
    -#include "yahoo_packet.h"
    -#include "yahoochat.h"
    -#include "ycht.h"
    -
    -#define YAHOO_CHAT_ID (1)
    -
    -/* prototype(s) */
    -static void yahoo_chat_leave(PurpleConnection *gc, const char *room, const char *dn, gboolean logout);
    -
    -/* special function to log us on to the yahoo chat service */
    -static void yahoo_chat_online(PurpleConnection *gc)
    -{
    - YahooData *yd = gc->proto_data;
    - struct yahoo_packet *pkt;
    - const char *rll;
    -
    - if (yd->wm) {
    - ycht_connection_open(gc);
    - return;
    - }
    -
    - rll = purple_account_get_string(purple_connection_get_account(gc),
    - "room_list_locale", YAHOO_ROOMLIST_LOCALE);
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_CHATONLINE, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash(pkt, "sssss",
    - 109, purple_connection_get_display_name(gc),
    - 1, purple_connection_get_display_name(gc),
    - 6, "abcde",
    - /* I'm not sure this is the correct way to set this. */
    - 98, rll,
    - 135, yd->jp ? YAHOO_CLIENT_VERSION : YAHOOJP_CLIENT_VERSION);
    - yahoo_packet_send_and_free(pkt, yd);
    -}
    -
    -/* this is slow, and different from the purple_* version in that it (hopefully) won't add a user twice */
    -void yahoo_chat_add_users(PurpleConvChat *chat, GList *newusers)
    -{
    - GList *i;
    -
    - for (i = newusers; i; i = i->next) {
    - if (purple_conv_chat_find_user(chat, i->data))
    - continue;
    - purple_conv_chat_add_user(chat, i->data, NULL, PURPLE_CBFLAGS_NONE, TRUE);
    - }
    -}
    -
    -void yahoo_chat_add_user(PurpleConvChat *chat, const char *user, const char *reason)
    -{
    - if (purple_conv_chat_find_user(chat, user))
    - return;
    -
    - purple_conv_chat_add_user(chat, user, reason, PURPLE_CBFLAGS_NONE, TRUE);
    -}
    -
    -static PurpleConversation *yahoo_find_conference(PurpleConnection *gc, const char *name)
    -{
    - YahooData *yd;
    - GSList *l;
    -
    - yd = gc->proto_data;
    -
    - for (l = yd->confs; l; l = l->next) {
    - PurpleConversation *c = l->data;
    - if (!purple_utf8_strcasecmp(purple_conversation_get_name(c), name))
    - return c;
    - }
    - return NULL;
    -}
    -
    -
    -void yahoo_process_conference_invite(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - PurpleAccount *account;
    - GSList *l;
    - char *room = NULL;
    - char *who = NULL;
    - char *msg = NULL;
    - GString *members = NULL;
    - GHashTable *components;
    -
    - if ( (pkt->status == 2) || (pkt->status == 11) )
    - return; /* Status is 11 when we are being notified about invitation being sent to someone else */
    -
    - account = purple_connection_get_account(gc);
    -
    - for (l = pkt->hash; l; l = l->next) {
    - struct yahoo_pair *pair = l->data;
    - if (pair->key == 57)
    - {
    - room = yahoo_string_decode(gc, pair->value, FALSE);
    - if (yahoo_find_conference(gc, room) != NULL)
    - {
    - /* Looks like we got invited to an already open conference. */
    - /* Laters: Should we accept this conference rather than ignoring the invitation ? */
    - purple_debug_info("yahoo","Ignoring invitation for an already existing chat, room:%s\n",room);
    - g_free(room);
    - return;
    - }
    - }
    - }
    -
    - members = g_string_sized_new(512);
    -
    - for (l = pkt->hash; l; l = l->next) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 1: /* us, but we already know who we are */
    - break;
    - case 57:
    - g_free(room);
    - room = yahoo_string_decode(gc, pair->value, FALSE);
    - break;
    - case 50: /* inviter */
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - who = pair->value;
    - g_string_append_printf(members, "%s\n", who);
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_conference_invite "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 51: /* This user is being invited to the conference. Comes with status = 11, so we wont reach here */
    - break;
    - case 52: /* Invited users. Assuming us invited, since we got this packet */
    - break; /* break needed, or else we add the users to the conference before they accept the invitation */
    - case 53: /* members who have already joined the conference */
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - g_string_append_printf(members, "%s\n", pair->value);
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_conference_invite "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 58:
    - g_free(msg);
    - msg = yahoo_string_decode(gc, pair->value, FALSE);
    - break;
    - case 13: /* ? */
    - break;
    - }
    - }
    -
    - if (!room) {
    - g_string_free(members, TRUE);
    - g_free(msg);
    - return;
    - }
    -
    - if (!purple_privacy_check(account, who) ||
    - (purple_account_get_bool(account, "ignore_invites", FALSE)))
    - {
    - purple_debug_info("yahoo",
    - "Invite to conference %s from %s has been dropped.\n", room, who);
    - g_free(room);
    - g_free(msg);
    - g_string_free(members, TRUE);
    - return;
    - }
    -
    - components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
    - g_hash_table_replace(components, g_strdup("room"), room);
    - if (msg)
    - g_hash_table_replace(components, g_strdup("topic"), msg);
    - g_hash_table_replace(components, g_strdup("type"), g_strdup("Conference"));
    - g_hash_table_replace(components, g_strdup("members"), g_string_free(members, FALSE));
    - serv_got_chat_invite(gc, room, who, msg, components);
    -
    -}
    -
    -void yahoo_process_conference_decline(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - GSList *l;
    - char *room = NULL;
    - char *who = NULL;
    - char *msg = NULL;
    - PurpleConversation *c = NULL;
    - int utf8 = 0;
    -
    - for (l = pkt->hash; l; l = l->next) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 57:
    - g_free(room);
    - room = yahoo_string_decode(gc, pair->value, FALSE);
    - break;
    - case 54:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - who = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_conference_decline "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 14:
    - g_free(msg);
    - msg = yahoo_string_decode(gc, pair->value, FALSE);
    - break;
    - case 97:
    - utf8 = strtol(pair->value, NULL, 10);
    - break;
    - }
    - }
    - if (!purple_privacy_check(purple_connection_get_account(gc), who))
    - {
    - g_free(room);
    - g_free(msg);
    - return;
    - }
    -
    - if (who && room) {
    - /* make sure we're in the room before we process a decline message for it */
    - if((c = yahoo_find_conference(gc, room))) {
    - char *tmp = NULL, *msg_tmp = NULL;
    - if(msg)
    - {
    - msg_tmp = yahoo_string_decode(gc, msg, utf8);
    - msg = yahoo_codes_to_html(msg_tmp);
    - serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(c)), who, 0, msg, time(NULL));
    - g_free(msg_tmp);
    - g_free(msg);
    - }
    -
    - tmp = g_strdup_printf(_("%s has declined to join."), who);
    - purple_conversation_write(c, NULL, tmp, PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LINKIFY, time(NULL));
    -
    - g_free(tmp);
    - }
    -
    - g_free(room);
    - }
    -}
    -
    -void yahoo_process_conference_logon(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - GSList *l;
    - char *room = NULL;
    - char *who = NULL;
    - PurpleConversation *c;
    -
    - for (l = pkt->hash; l; l = l->next) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 57:
    - g_free(room);
    - room = yahoo_string_decode(gc, pair->value, FALSE);
    - break;
    - case 53:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - who = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_conference_logon "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - }
    - }
    -
    - if (who && room) {
    - c = yahoo_find_conference(gc, room);
    - if (c)
    - { /* Prevent duplicate users in the chat */
    - if( !purple_conv_chat_find_user(PURPLE_CONV_CHAT(c), who) )
    - yahoo_chat_add_user(PURPLE_CONV_CHAT(c), who, NULL);
    - }
    - g_free(room);
    - }
    -}
    -
    -void yahoo_process_conference_logoff(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - GSList *l;
    - char *room = NULL;
    - char *who = NULL;
    - PurpleConversation *c;
    -
    - for (l = pkt->hash; l; l = l->next) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 57:
    - g_free(room);
    - room = yahoo_string_decode(gc, pair->value, FALSE);
    - break;
    - case 56:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - who = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_conference_logoff "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - }
    - }
    -
    - if (who && room) {
    - c = yahoo_find_conference(gc, room);
    - if (c)
    - purple_conv_chat_remove_user(PURPLE_CONV_CHAT(c), who, NULL);
    - g_free(room);
    - }
    -}
    -
    -void yahoo_process_conference_message(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - GSList *l;
    - char *room = NULL;
    - char *who = NULL;
    - char *msg = NULL;
    - int utf8 = 0;
    - PurpleConversation *c;
    -
    - for (l = pkt->hash; l; l = l->next) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 57:
    - g_free(room);
    - room = yahoo_string_decode(gc, pair->value, FALSE);
    - break;
    - case 3:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - who = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_conference_message "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 14:
    - msg = pair->value;
    - break;
    - case 97:
    - utf8 = strtol(pair->value, NULL, 10);
    - break;
    - }
    - }
    -
    - if (room && who && msg) {
    - char *msg2;
    -
    - c = yahoo_find_conference(gc, room);
    - if (!c) {
    - g_free(room);
    - return;
    - }
    -
    - msg2 = yahoo_string_decode(gc, msg, utf8);
    - msg = yahoo_codes_to_html(msg2);
    - serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(c)), who, 0, msg, time(NULL));
    - g_free(msg);
    - g_free(msg2);
    - }
    -
    - g_free(room);
    -}
    -
    -static void yahoo_chat_join(PurpleConnection *gc, const char *dn, const char *room, const char *topic, const char *id)
    -{
    - YahooData *yd = gc->proto_data;
    - struct yahoo_packet *pkt;
    - char *room2;
    - gboolean utf8 = TRUE;
    -
    - if (yd->wm) {
    - g_return_if_fail(yd->ycht != NULL);
    - ycht_chat_join(yd->ycht, room);
    - return;
    - }
    -
    - /* apparently room names are always utf8, or else always not utf8,
    - * so we don't have to actually pass the flag in the packet. Or something. */
    - room2 = yahoo_string_encode(gc, room, &utf8);
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_CHATJOIN, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash(pkt, "ssss",
    - 1, purple_connection_get_display_name(gc),
    - 104, room2,
    - 62, "2",
    - 129, id ? id : "0");
    - yahoo_packet_send_and_free(pkt, yd);
    - g_free(room2);
    -}
    -
    -/* this is a confirmation of yahoo_chat_online(); */
    -void yahoo_process_chat_online(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - YahooData *yd = (YahooData *) gc->proto_data;
    -
    - if (pkt->status == 1) {
    - yd->chat_online = TRUE;
    -
    - /* We need to goto a user in chat */
    - if (yd->pending_chat_goto) {
    - struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_CHATGOTO, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash(pkt, "sss",
    - 109, yd->pending_chat_goto,
    - 1, purple_connection_get_display_name(gc),
    - 62, "2");
    - yahoo_packet_send_and_free(pkt, yd);
    - } else if (yd->pending_chat_room) {
    - yahoo_chat_join(gc, purple_connection_get_display_name(gc), yd->pending_chat_room,
    - yd->pending_chat_topic, yd->pending_chat_id);
    - }
    -
    - g_free(yd->pending_chat_room);
    - yd->pending_chat_room = NULL;
    - g_free(yd->pending_chat_id);
    - yd->pending_chat_id = NULL;
    - g_free(yd->pending_chat_topic);
    - yd->pending_chat_topic = NULL;
    - g_free(yd->pending_chat_goto);
    - yd->pending_chat_goto = NULL;
    - }
    -}
    -
    -/* this is basicly the opposite of chat_online */
    -void yahoo_process_chat_logout(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - YahooData *yd = (YahooData *) gc->proto_data;
    - GSList *l;
    -
    - for (l = pkt->hash; l; l = l->next) {
    - struct yahoo_pair *pair = l->data;
    -
    - if (pair->key == 1)
    - if (g_ascii_strcasecmp(pair->value,
    - purple_connection_get_display_name(gc)))
    - return;
    - }
    -
    - if (pkt->status == 1) {
    - yd->chat_online = FALSE;
    - g_free(yd->pending_chat_room);
    - yd->pending_chat_room = NULL;
    - g_free(yd->pending_chat_id);
    - yd->pending_chat_id = NULL;
    - g_free(yd->pending_chat_topic);
    - yd->pending_chat_topic = NULL;
    - g_free(yd->pending_chat_goto);
    - yd->pending_chat_goto = NULL;
    - if (yd->in_chat)
    - yahoo_c_leave(gc, YAHOO_CHAT_ID);
    - }
    -}
    -
    -void yahoo_process_chat_join(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - PurpleAccount *account = purple_connection_get_account(gc);
    - YahooData *yd = (YahooData *) gc->proto_data;
    - PurpleConversation *c = NULL;
    - GSList *l;
    - GList *members = NULL;
    - GList *roomies = NULL;
    - char *room = NULL;
    - char *topic = NULL;
    -
    - if (pkt->status == -1) {
    - /* We can't join */
    - struct yahoo_pair *pair = pkt->hash->data;
    - gchar const *failed_to_join = _("Failed to join chat");
    - switch (atoi(pair->value)) {
    - case 0xFFFFFFFA: /* -6 */
    - purple_notify_error(gc, NULL, failed_to_join, _("Unknown room"));
    - break;
    - case 0xFFFFFFF1: /* -15 */
    - purple_notify_error(gc, NULL, failed_to_join, _("Maybe the room is full"));
    - break;
    - case 0xFFFFFFDD: /* -35 */
    - purple_notify_error(gc, NULL, failed_to_join, _("Not available"));
    - break;
    - default:
    - purple_notify_error(gc, NULL, failed_to_join,
    - _("Unknown error. You may need to logout and wait five minutes before being able to rejoin a chatroom"));
    - }
    - return;
    - }
    -
    - for (l = pkt->hash; l; l = l->next) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    -
    - case 104:
    - g_free(room);
    - room = yahoo_string_decode(gc, pair->value, TRUE);
    - break;
    - case 105:
    - g_free(topic);
    - topic = yahoo_string_decode(gc, pair->value, TRUE);
    - break;
    - case 128: /* some id */
    - break;
    - case 108: /* number of joiners */
    - break;
    - case 129: /* some other id */
    - break;
    - case 130: /* some base64 or hash or something */
    - break;
    - case 126: /* some negative number */
    - break;
    - case 13: /* this is 1. maybe its the type of room? (normal, user created, private, etc?) */
    - break;
    - case 61: /*this looks similar to 130 */
    - break;
    -
    - /* the previous section was just room info. this next section is
    - info about individual room members, (including us) */
    -
    - case 109: /* the yahoo id */
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - members = g_list_append(members, pair->value);
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_chat_join "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 110: /* age */
    - break;
    - case 141: /* nickname */
    - break;
    - case 142: /* location */
    - break;
    - case 113: /* bitmask */
    - break;
    - }
    - }
    -
    - if (room && yd->chat_name && purple_utf8_strcasecmp(room, yd->chat_name))
    - yahoo_chat_leave(gc, room,
    - purple_connection_get_display_name(gc), FALSE);
    -
    - c = purple_find_chat(gc, YAHOO_CHAT_ID);
    -
    - if (room && (!c || purple_conv_chat_has_left(PURPLE_CONV_CHAT(c))) &&
    - members && (members->next ||
    - !g_ascii_strcasecmp(members->data, purple_connection_get_display_name(gc)))) {
    - GList *l;
    - GList *flags = NULL;
    - for (l = members; l; l = l->next)
    - flags = g_list_prepend(flags, GINT_TO_POINTER(PURPLE_CBFLAGS_NONE));
    - if (c && purple_conv_chat_has_left(PURPLE_CONV_CHAT(c))) {
    - /* this might be a hack, but oh well, it should nicely */
    - char *tmpmsg;
    -
    - purple_conversation_set_name(c, room);
    -
    - c = serv_got_joined_chat(gc, YAHOO_CHAT_ID, room);
    - if (topic) {
    - purple_conv_chat_set_topic(PURPLE_CONV_CHAT(c), NULL, topic);
    - /* Also print the topic to the backlog so that the captcha link is clickable */
    - purple_conv_chat_write(PURPLE_CONV_CHAT(c), "", topic, PURPLE_MESSAGE_SYSTEM, time(NULL));
    - }
    - yd->in_chat = 1;
    - yd->chat_name = g_strdup(room);
    - purple_conv_chat_add_users(PURPLE_CONV_CHAT(c), members, NULL, flags, FALSE);
    -
    - tmpmsg = g_strdup_printf(_("You are now chatting in %s."), room);
    - purple_conv_chat_write(PURPLE_CONV_CHAT(c), "", tmpmsg, PURPLE_MESSAGE_SYSTEM, time(NULL));
    - g_free(tmpmsg);
    - } else {
    - c = serv_got_joined_chat(gc, YAHOO_CHAT_ID, room);
    - if (topic) {
    - purple_conv_chat_set_topic(PURPLE_CONV_CHAT(c), NULL, topic);
    - /* Also print the topic to the backlog so that the captcha link is clickable */
    - purple_conv_chat_write(PURPLE_CONV_CHAT(c), "", topic, PURPLE_MESSAGE_SYSTEM, time(NULL));
    - }
    - yd->in_chat = 1;
    - yd->chat_name = g_strdup(room);
    - purple_conv_chat_add_users(PURPLE_CONV_CHAT(c), members, NULL, flags, FALSE);
    - }
    - g_list_free(flags);
    - } else if (c) {
    - if (topic) {
    - const char *cur_topic = purple_conv_chat_get_topic(PURPLE_CONV_CHAT(c));
    - if (cur_topic == NULL || strcmp(cur_topic, topic) != 0)
    - purple_conv_chat_set_topic(PURPLE_CONV_CHAT(c), NULL, topic);
    - }
    - yahoo_chat_add_users(PURPLE_CONV_CHAT(c), members);
    - }
    -
    - if (account->deny && c) {
    - PurpleConversationUiOps *ops = purple_conversation_get_ui_ops(c);
    - for (l = account->deny; l != NULL; l = l->next) {
    - for (roomies = members; roomies; roomies = roomies->next) {
    - if (!purple_utf8_strcasecmp((char *)l->data, roomies->data)) {
    - purple_debug_info("yahoo", "Ignoring room member %s in room %s\n" , (char *)roomies->data, room ? room : "");
    - purple_conv_chat_ignore(PURPLE_CONV_CHAT(c),roomies->data);
    - ops->chat_update_user(c, roomies->data);
    - }
    - }
    - }
    - }
    - g_list_free(roomies);
    - g_list_free(members);
    - g_free(room);
    - g_free(topic);
    -}
    -
    -void yahoo_process_chat_exit(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - char *who = NULL;
    - char *room = NULL;
    - GSList *l;
    -
    - for (l = pkt->hash; l; l = l->next) {
    - struct yahoo_pair *pair = l->data;
    -
    - if (pair->key == 104) {
    - g_free(room);
    - room = yahoo_string_decode(gc, pair->value, TRUE);
    - }
    - if (pair->key == 109) {
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - who = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_chat_exit "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - }
    - }
    -
    - if (who && room) {
    - PurpleConversation *c = purple_find_chat(gc, YAHOO_CHAT_ID);
    - if (c && !purple_utf8_strcasecmp(purple_conversation_get_name(c), room))
    - purple_conv_chat_remove_user(PURPLE_CONV_CHAT(c), who, NULL);
    -
    - }
    - g_free(room);
    -}
    -
    -void yahoo_process_chat_message(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - char *room = NULL, *who = NULL, *msg = NULL, *msg2;
    - int msgtype = 1, utf8 = 1; /* default to utf8 */
    - PurpleConversation *c = NULL;
    - GSList *l;
    -
    - for (l = pkt->hash; l; l = l->next) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    -
    - case 97:
    - utf8 = strtol(pair->value, NULL, 10);
    - break;
    - case 104:
    - g_free(room);
    - room = yahoo_string_decode(gc, pair->value, TRUE);
    - break;
    - case 109:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - who = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_chat_message "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 117:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - msg = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_chat_message "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 124:
    - msgtype = strtol(pair->value, NULL, 10);
    - break;
    - }
    - }
    -
    - c = purple_find_chat(gc, YAHOO_CHAT_ID);
    - if (!who || !c) {
    - if (room)
    - g_free(room);
    - /* we still get messages after we part, funny that */
    - return;
    - }
    -
    - if (!msg) {
    - purple_debug_misc("yahoo", "Got a message packet with no message.\nThis probably means something important, but we're ignoring it.\n");
    - return;
    - }
    - msg2 = yahoo_string_decode(gc, msg, utf8);
    - msg = yahoo_codes_to_html(msg2);
    - g_free(msg2);
    -
    - if (msgtype == 2 || msgtype == 3) {
    - char *tmp;
    - tmp = g_strdup_printf("/me %s", msg);
    - g_free(msg);
    - msg = tmp;
    - }
    -
    - serv_got_chat_in(gc, YAHOO_CHAT_ID, who, 0, msg, time(NULL));
    - g_free(msg);
    - g_free(room);
    -}
    -
    -void yahoo_process_chat_addinvite(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - PurpleAccount *account;
    - GSList *l;
    - char *room = NULL;
    - char *msg = NULL;
    - char *who = NULL;
    -
    - account = purple_connection_get_account(gc);
    -
    - for (l = pkt->hash; l; l = l->next) {
    - struct yahoo_pair *pair = l->data;
    -
    - switch (pair->key) {
    - case 104:
    - g_free(room);
    - room = yahoo_string_decode(gc, pair->value, TRUE);
    - break;
    - case 129: /* room id? */
    - break;
    - case 126: /* ??? */
    - break;
    - case 117:
    - g_free(msg);
    - msg = yahoo_string_decode(gc, pair->value, FALSE);
    - break;
    - case 119:
    - if (g_utf8_validate(pair->value, -1, NULL)) {
    - who = pair->value;
    - } else {
    - purple_debug_warning("yahoo", "yahoo_process_chat_addinvite "
    - "got non-UTF-8 string for key %d\n", pair->key);
    - }
    - break;
    - case 118: /* us */
    - break;
    - }
    - }
    -
    - if (room && who) {
    - GHashTable *components;
    -
    - if (!purple_privacy_check(account, who) ||
    - (purple_account_get_bool(account, "ignore_invites", FALSE)))
    - {
    - purple_debug_info("yahoo", "Invite to room %s from %s has been dropped.\n", room, who);
    - g_free(room);
    - g_free(msg);
    - return;
    - }
    -
    - components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
    - g_hash_table_replace(components, g_strdup("room"), g_strdup(room));
    - serv_got_chat_invite(gc, room, who, msg, components);
    - }
    -
    - g_free(room);
    - g_free(msg);
    -}
    -
    -void yahoo_process_chat_goto(PurpleConnection *gc, struct yahoo_packet *pkt)
    -{
    - if (pkt->status == -1)
    - purple_notify_error(gc, NULL, _("Failed to join buddy in chat"),
    - _("Maybe they're not in a chat?"));
    -}
    -
    -/*
    - * Functions dealing with conferences
    - * I think conference names are always ascii.
    - */
    -
    -void yahoo_conf_leave(YahooData *yd, const char *room, const char *dn, GList *who)
    -{
    - struct yahoo_packet *pkt;
    - GList *w;
    -
    - purple_debug_misc("yahoo", "leaving conference %s\n", room);
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_CONFLOGOFF, YAHOO_STATUS_AVAILABLE, yd->session_id);
    -
    - yahoo_packet_hash_str(pkt, 1, dn);
    - for (w = who; w; w = w->next) {
    - const char *name = purple_conv_chat_cb_get_name(w->data);
    - yahoo_packet_hash_str(pkt, 3, name);
    - }
    -
    - yahoo_packet_hash_str(pkt, 57, room);
    - yahoo_packet_send_and_free(pkt, yd);
    -}
    -
    -static int yahoo_conf_send(PurpleConnection *gc, const char *dn, const char *room,
    - GList *members, const char *what)
    -{
    - YahooData *yd = gc->proto_data;
    - struct yahoo_packet *pkt;
    - GList *who;
    - char *msg, *msg2;
    - int utf8 = 1;
    -
    - msg = yahoo_html_to_codes(what);
    - msg2 = yahoo_string_encode(gc, msg, &utf8);
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_CONFMSG, YAHOO_STATUS_AVAILABLE, yd->session_id);
    -
    - yahoo_packet_hash_str(pkt, 1, dn);
    - for (who = members; who; who = who->next) {
    - const char *name = purple_conv_chat_cb_get_name(who->data);
    - yahoo_packet_hash_str(pkt, 53, name);
    - }
    - yahoo_packet_hash(pkt, "ss", 57, room, 14, msg2);
    - if (utf8)
    - yahoo_packet_hash_str(pkt, 97, "1"); /* utf-8 */
    -
    - yahoo_packet_send_and_free(pkt, yd);
    - g_free(msg);
    - g_free(msg2);
    -
    - return 0;
    -}
    -
    -static void yahoo_conf_join(YahooData *yd, PurpleConversation *c, const char *dn, const char *room,
    - const char *topic, const char *members)
    -{
    - struct yahoo_packet *pkt;
    - char **memarr = NULL;
    - int i;
    -
    - if (members)
    - memarr = g_strsplit(members, "\n", 0);
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_CONFLOGON, YAHOO_STATUS_AVAILABLE, yd->session_id);
    -
    - yahoo_packet_hash(pkt, "sss", 1, dn, 3, dn, 57, room);
    - if (memarr) {
    - for(i = 0 ; memarr[i]; i++) {
    - if (!strcmp(memarr[i], "") || !strcmp(memarr[i], dn))
    - continue;
    - yahoo_packet_hash_str(pkt, 3, memarr[i]);
    - purple_conv_chat_add_user(PURPLE_CONV_CHAT(c), memarr[i], NULL, PURPLE_CBFLAGS_NONE, TRUE);
    - }
    - }
    - yahoo_packet_send_and_free(pkt, yd);
    -
    - if (memarr)
    - g_strfreev(memarr);
    -}
    -
    -static void yahoo_conf_invite(PurpleConnection *gc, PurpleConversation *c,
    - const char *dn, const char *buddy, const char *room, const char *msg)
    -{
    - YahooData *yd = gc->proto_data;
    - struct yahoo_packet *pkt;
    - GList *members;
    - char *msg2 = NULL;
    -
    - if (msg)
    - msg2 = yahoo_string_encode(gc, msg, NULL);
    -
    - members = purple_conv_chat_get_users(PURPLE_CONV_CHAT(c));
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_CONFADDINVITE, YAHOO_STATUS_AVAILABLE, yd->session_id);
    -
    - yahoo_packet_hash(pkt, "sssss", 1, dn, 51, buddy, 57, room, 58, msg?msg2:"", 13, "0");
    - for(; members; members = members->next) {
    - const char *name = purple_conv_chat_cb_get_name(members->data);
    - if (!strcmp(name, dn))
    - continue;
    - yahoo_packet_hash(pkt, "ss", 52, name, 53, name);
    - }
    -
    - yahoo_packet_send_and_free(pkt, yd);
    - g_free(msg2);
    -}
    -
    -/*
    - * Functions dealing with chats
    - */
    -
    -static void yahoo_chat_leave(PurpleConnection *gc, const char *room, const char *dn, gboolean logout)
    -{
    - YahooData *yd = gc->proto_data;
    - struct yahoo_packet *pkt;
    -
    - char *eroom;
    - gboolean utf8 = 1;
    -
    - if (yd->wm) {
    - g_return_if_fail(yd->ycht != NULL);
    -
    - ycht_chat_leave(yd->ycht, room, logout);
    - return;
    - }
    -
    - eroom = yahoo_string_encode(gc, room, &utf8);
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_CHATEXIT, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash(pkt, "sss", 104, eroom, 109, dn, 108, "1");
    - yahoo_packet_hash_str(pkt, 112, "0"); /* what does this one mean? */
    - yahoo_packet_send_and_free(pkt, yd);
    -
    - yd->in_chat = 0;
    - if (yd->chat_name) {
    - g_free(yd->chat_name);
    - yd->chat_name = NULL;
    - }
    -
    - if (purple_find_chat(gc, YAHOO_CHAT_ID) != NULL)
    - serv_got_chat_left(gc, YAHOO_CHAT_ID);
    -
    - if (!logout)
    - return;
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_CHATLOGOUT,
    - YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash_str(pkt, 1, dn);
    - yahoo_packet_send_and_free(pkt, yd);
    -
    - yd->chat_online = FALSE;
    - g_free(yd->pending_chat_room);
    - yd->pending_chat_room = NULL;
    - g_free(yd->pending_chat_id);
    - yd->pending_chat_id = NULL;
    - g_free(yd->pending_chat_topic);
    - yd->pending_chat_topic = NULL;
    - g_free(yd->pending_chat_goto);
    - yd->pending_chat_goto = NULL;
    - g_free(eroom);
    -}
    -
    -static int yahoo_chat_send(PurpleConnection *gc, const char *dn, const char *room, const char *what, PurpleMessageFlags flags)
    -{
    - YahooData *yd = gc->proto_data;
    - struct yahoo_packet *pkt;
    - int me = 0;
    - char *msg1, *msg2, *room2;
    - gboolean utf8 = TRUE;
    -
    - if (yd->wm) {
    - g_return_val_if_fail(yd->ycht != NULL, 1);
    -
    - return ycht_chat_send(yd->ycht, room, what);
    - }
    -
    - msg1 = g_strdup(what);
    -
    - if (purple_message_meify(msg1, -1))
    - me = 1;
    -
    - msg2 = yahoo_html_to_codes(msg1);
    - g_free(msg1);
    - msg1 = yahoo_string_encode(gc, msg2, &utf8);
    - g_free(msg2);
    - room2 = yahoo_string_encode(gc, room, NULL);
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_COMMENT, YAHOO_STATUS_AVAILABLE, yd->session_id);
    -
    - yahoo_packet_hash(pkt, "sss", 1, dn, 104, room2, 117, msg1);
    - if (me)
    - yahoo_packet_hash_str(pkt, 124, "2");
    - else
    - yahoo_packet_hash_str(pkt, 124, "1");
    - /* fixme: what about /think? (124=3) */
    - if (utf8)
    - yahoo_packet_hash_str(pkt, 97, "1");
    -
    - yahoo_packet_send_and_free(pkt, yd);
    - g_free(msg1);
    - g_free(room2);
    -
    - return 0;
    -}
    -
    -
    -static void yahoo_chat_invite(PurpleConnection *gc, const char *dn, const char *buddy,
    - const char *room, const char *msg)
    -{
    - YahooData *yd = gc->proto_data;
    - struct yahoo_packet *pkt;
    - char *room2, *msg2 = NULL;
    - gboolean utf8 = TRUE;
    -
    - if (yd->wm) {
    - g_return_if_fail(yd->ycht != NULL);
    - ycht_chat_send_invite(yd->ycht, room, buddy, msg);
    - return;
    - }
    -
    - room2 = yahoo_string_encode(gc, room, &utf8);
    - if (msg)
    - msg2 = yahoo_string_encode(gc, msg, NULL);
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_CHATADDINVITE, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash(pkt, "sssss", 1, dn, 118, buddy, 104, room2, 117, (msg2?msg2:""), 129, "0");
    - yahoo_packet_send_and_free(pkt, yd);
    -
    - g_free(room2);
    - g_free(msg2);
    -}
    -
    -void yahoo_chat_goto(PurpleConnection *gc, const char *name)
    -{
    - YahooData *yd;
    - struct yahoo_packet *pkt;
    -
    - yd = gc->proto_data;
    -
    - if (yd->wm) {
    - g_return_if_fail(yd->ycht != NULL);
    - ycht_chat_goto_user(yd->ycht, name);
    - return;
    - }
    -
    - if (!yd->chat_online) {
    - yahoo_chat_online(gc);
    - g_free(yd->pending_chat_room);
    - yd->pending_chat_room = NULL;
    - g_free(yd->pending_chat_id);
    - yd->pending_chat_id = NULL;
    - g_free(yd->pending_chat_topic);
    - yd->pending_chat_topic = NULL;
    - g_free(yd->pending_chat_goto);
    - yd->pending_chat_goto = g_strdup(name);
    - return;
    - }
    -
    - pkt = yahoo_packet_new(YAHOO_SERVICE_CHATGOTO, YAHOO_STATUS_AVAILABLE, yd->session_id);
    - yahoo_packet_hash(pkt, "sss", 109, name, 1, purple_connection_get_display_name(gc), 62, "2");
    - yahoo_packet_send_and_free(pkt, yd);
    -}
    -/*
    - * These are the functions registered with the core
    - * which get called for both chats and conferences.
    - */
    -
    -void yahoo_c_leave(PurpleConnection *gc, int id)
    -{
    - YahooData *yd = (YahooData *) gc->proto_data;
    - PurpleConversation *c;
    -
    - if (!yd)
    - return;
    -
    - c = purple_find_chat(gc, id);
    - if (!c)
    - return;
    -
    - if (id != YAHOO_CHAT_ID) {
    - yahoo_conf_leave(yd, purple_conversation_get_name(c),
    - purple_connection_get_display_name(gc), purple_conv_chat_get_users(PURPLE_CONV_CHAT(c)));
    - yd->confs = g_slist_remove(yd->confs, c);
    - } else {
    - yahoo_chat_leave(gc, purple_conversation_get_name(c), purple_connection_get_display_name(gc), TRUE);
    - }
    -
    - serv_got_chat_left(gc, id);
    -}
    -
    -int yahoo_c_send(PurpleConnection *gc, int id, const char *what, PurpleMessageFlags flags)
    -{
    - PurpleConversation *c;
    - int ret;
    - YahooData *yd;
    -
    - yd = (YahooData *) gc->proto_data;
    - if (!yd)
    - return -1;
    -
    - c = purple_find_chat(gc, id);
    - if (!c)
    - return -1;
    -
    - if (id != YAHOO_CHAT_ID) {
    - ret = yahoo_conf_send(gc, purple_connection_get_display_name(gc),
    - purple_conversation_get_name(c), purple_conv_chat_get_users(PURPLE_CONV_CHAT(c)), what);
    - } else {
    - ret = yahoo_chat_send(gc, purple_connection_get_display_name(gc),
    - purple_conversation_get_name(c), what, flags);
    - if (!ret)
    - serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(c)),
    - purple_connection_get_display_name(gc), flags, what, time(NULL));
    - }
    - return ret;
    -}
    -
    -GList *yahoo_c_info(PurpleConnection *gc)
    -{
    - GList *m = NULL;
    - struct proto_chat_entry *pce;
    -
    - pce = g_new0(struct proto_chat_entry, 1);
    - pce->label = _("_Room:");
    - pce->identifier = "room";
    - pce->required = TRUE;
    - m = g_list_append(m, pce);
    -
    - return m;
    -}
    -
    -GHashTable *yahoo_c_info_defaults(PurpleConnection *gc, const char *chat_name)
    -{
    - GHashTable *defaults;
    -
    - defaults = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
    -
    - if (chat_name != NULL)
    - g_hash_table_insert(defaults, "room", g_strdup(chat_name));
    -
    - return defaults;
    -}
    -
    -char *yahoo_get_chat_name(GHashTable *data)
    -{
    - return g_strdup(g_hash_table_lookup(data, "room"));
    -}
    -
    -void yahoo_c_join(PurpleConnection *gc, GHashTable *data)
    -{
    - YahooData *yd;
    - char *room, *topic, *type;
    - PurpleConversation *c;
    -
    - yd = (YahooData *) gc->proto_data;
    - if (!yd)
    - return;
    -
    - room = g_hash_table_lookup(data, "room");
    - if (!room)
    - return;
    -
    - topic = g_hash_table_lookup(data, "topic");
    - if (!topic)
    - topic = "";
    -
    - if ((type = g_hash_table_lookup(data, "type")) && !strcmp(type, "Conference")) {
    - int id;
    - const char *members = g_hash_table_lookup(data, "members");
    - id = yd->conf_id++;
    - c = serv_got_joined_chat(gc, id, room);
    - yd->confs = g_slist_prepend(yd->confs, c);
    - purple_conv_chat_set_topic(PURPLE_CONV_CHAT(c), purple_connection_get_display_name(gc), topic);
    - yahoo_conf_join(yd, c, purple_connection_get_display_name(gc), room, topic, members);
    - return;
    - } else {
    - const char *id;
    - /*if (yd->in_chat)
    - yahoo_chat_leave(gc, room,
    - purple_connection_get_display_name(gc),
    - FALSE);*/
    -
    - id = g_hash_table_lookup(data, "id");
    -
    - if (!yd->chat_online) {
    - yahoo_chat_online(gc);
    - g_free(yd->pending_chat_room);
    - yd->pending_chat_room = g_strdup(room);
    - g_free(yd->pending_chat_id);
    - yd->pending_chat_id = g_strdup(id);
    - g_free(yd->pending_chat_topic);
    - yd->pending_chat_topic = g_strdup(topic);
    - g_free(yd->pending_chat_goto);
    - yd->pending_chat_goto = NULL;
    - } else {
    - yahoo_chat_join(gc, purple_connection_get_display_name(gc), room, topic, id);
    - }
    - return;
    - }
    -}
    -
    -void yahoo_c_invite(PurpleConnection *gc, int id, const char *msg, const char *name)
    -{
    - PurpleConversation *c;
    -
    - c = purple_find_chat(gc, id);
    - if (!c || !c->name)
    - return;
    -
    - if (id != YAHOO_CHAT_ID) {
    - yahoo_conf_invite(gc, c, purple_connection_get_display_name(gc), name,
    - purple_conversation_get_name(c), msg);
    - } else {
    - yahoo_chat_invite(gc, purple_connection_get_display_name(gc), name,
    - purple_conversation_get_name(c), msg);
    - }
    -}
    -
    -struct yahoo_roomlist {
    - int fd;
    - int inpa;
    - gchar *txbuf;
    - gsize tx_written;
    - guchar *rxqueue;
    - int rxlen;
    - gboolean started;
    - char *path;
    - char *host;
    - PurpleRoomlist *list;
    - PurpleRoomlistRoom *cat;
    - PurpleRoomlistRoom *ucat;
    - GMarkupParseContext *parse;
    -};
    -
    -static void yahoo_roomlist_destroy(struct yahoo_roomlist *yrl)
    -{
    - if (yrl->inpa)
    - purple_input_remove(yrl->inpa);
    - g_free(yrl->txbuf);
    - g_free(yrl->rxqueue);
    - g_free(yrl->path);
    - g_free(yrl->host);
    - if (yrl->parse)
    - g_markup_parse_context_free(yrl->parse);
    - g_free(yrl);
    -}
    -
    -enum yahoo_room_type {
    - yrt_yahoo,
    - yrt_user
    -};
    -
    -struct yahoo_chatxml_state {
    - PurpleRoomlist *list;
    - struct yahoo_roomlist *yrl;
    - GQueue *q;
    - struct {
    - enum yahoo_room_type type;
    - char *name;
    - char *topic;
    - char *id;
    - int users, voices, webcams;
    - } room;
    -};
    -
    -struct yahoo_lobby {
    - int count, users, voices, webcams;
    -};
    -
    -static struct yahoo_chatxml_state *yahoo_chatxml_state_new(PurpleRoomlist *list, struct yahoo_roomlist *yrl)
    -{
    - struct yahoo_chatxml_state *s;
    -
    - s = g_new0(struct yahoo_chatxml_state, 1);
    - s->list = list;
    - s->yrl = yrl;
    - s->q = g_queue_new();
    -
    - return s;
    -}
    -
    -static void yahoo_chatxml_state_destroy(struct yahoo_chatxml_state *s)
    -{
    - g_queue_free(s->q);
    - g_free(s->room.name);
    - g_free(s->room.topic);
    - g_free(s->room.id);
    - g_free(s);
    -}
    -
    -static void yahoo_chatlist_start_element(GMarkupParseContext *context,
    - const gchar *ename, const gchar **anames,
    - const gchar **avalues, gpointer user_data,
    - GError **error)
    -{
    - struct yahoo_chatxml_state *s = user_data;
    - PurpleRoomlist *list = s->list;
    - PurpleRoomlistRoom *r;
    - PurpleRoomlistRoom *parent;
    - int i;
    -
    - if (!strcmp(ename, "category")) {
    - const gchar *name = NULL, *id = NULL;
    -
    - for (i = 0; anames[i]; i++) {
    - if (!strcmp(anames[i], "id"))
    - id = avalues[i];
    - if (!strcmp(anames[i], "name"))
    - name = avalues[i];
    - }
    - if (!name || !id)
    - return;
    -
    - parent = g_queue_peek_head(s->q);
    - r = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_CATEGORY, name, parent);
    - purple_roomlist_room_add_field(list, r, (gpointer)name);
    - purple_roomlist_room_add_field(list, r, (gpointer)id);
    - purple_roomlist_room_add(list, r);
    - g_queue_push_head(s->q, r);
    - } else if (!strcmp(ename, "room")) {
    - s->room.users = s->room.voices = s->room.webcams = 0;
    -
    - for (i = 0; anames[i]; i++) {
    - if (!strcmp(anames[i], "id")) {
    - g_free(s->room.id);
    - s->room.id = g_strdup(avalues[i]);
    - } else if (!strcmp(anames[i], "name")) {
    - g_free(s->room.name);
    - s->room.name = g_strdup(avalues[i]);
    - } else if (!strcmp(anames[i], "topic")) {
    - g_free(s->room.topic);
    - s->room.topic = g_strdup(avalues[i]);
    - } else if (!strcmp(anames[i], "type")) {
    - if (!strcmp("yahoo", avalues[i]))
    - s->room.type = yrt_yahoo;
    - else
    - s->room.type = yrt_user;
    - }
    - }
    -
    - } else if (!strcmp(ename, "lobby")) {
    - struct yahoo_lobby *lob = g_new0(struct yahoo_lobby, 1);
    -
    - for (i = 0; anames[i]; i++) {
    - if (!strcmp(anames[i], "count")) {
    - lob->count = strtol(avalues[i], NULL, 10);
    - } else if (!strcmp(anames[i], "users")) {
    - s->room.users += lob->users = strtol(avalues[i], NULL, 10);
    - } else if (!strcmp(anames[i], "voices")) {
    - s->room.voices += lob->voices = strtol(avalues[i], NULL, 10);
    - } else if (!strcmp(anames[i], "webcams")) {
    - s->room.webcams += lob->webcams = strtol(avalues[i], NULL, 10);
    - }
    - }
    - g_queue_push_head(s->q, lob);
    - }
    -}
    -
    -static void yahoo_chatlist_end_element(GMarkupParseContext *context, const gchar *ename,
    - gpointer user_data, GError **error)
    -{
    - struct yahoo_chatxml_state *s = user_data;
    -
    - if (!strcmp(ename, "category")) {
    - g_queue_pop_head(s->q);
    - } else if (!strcmp(ename, "room")) {
    - struct yahoo_lobby *lob;
    - PurpleRoomlistRoom *r, *l;
    -
    - if (s->room.type == yrt_yahoo)
    - r = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_CATEGORY|PURPLE_ROOMLIST_ROOMTYPE_ROOM,
    - s->room.name, s->yrl->cat);
    - else
    - r = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_CATEGORY|PURPLE_ROOMLIST_ROOMTYPE_ROOM,
    - s->room.name, s->yrl->ucat);
    -
    - purple_roomlist_room_add_field(s->list, r, s->room.name);
    - purple_roomlist_room_add_field(s->list, r, s->room.id);
    - purple_roomlist_room_add_field(s->list, r, GINT_TO_POINTER(s->room.users));
    - purple_roomlist_room_add_field(s->list, r, GINT_TO_POINTER(s->room.voices));
    - purple_roomlist_room_add_field(s->list, r, GINT_TO_POINTER(s->room.webcams));
    - purple_roomlist_room_add_field(s->list, r, s->room.topic);
    - purple_roomlist_room_add(s->list, r);
    -
    - while ((lob = g_queue_pop_head(s->q))) {
    - char *name = g_strdup_printf("%s:%d", s->room.name, lob->count);
    - l = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_ROOM, name, r);
    -
    - purple_roomlist_room_add_field(s->list, l, name);
    - purple_roomlist_room_add_field(s->list, l, s->room.id);
    - purple_roomlist_room_add_field(s->list, l, GINT_TO_POINTER(lob->users));
    - purple_roomlist_room_add_field(s->list, l, GINT_TO_POINTER(lob->voices));
    - purple_roomlist_room_add_field(s->list, l, GINT_TO_POINTER(lob->webcams));
    - purple_roomlist_room_add_field(s->list, l, s->room.topic);
    - purple_roomlist_room_add(s->list, l);
    -
    - g_free(name);
    - g_free(lob);
    - }
    - }
    -}
    -
    -static GMarkupParser parser = {
    - yahoo_chatlist_start_element,
    - yahoo_chatlist_end_element,
    - NULL,
    - NULL,
    - NULL
    -};
    -
    -static void yahoo_roomlist_cleanup(PurpleRoomlist *list, struct yahoo_roomlist *yrl)
    -{
    - purple_roomlist_set_in_progress(list, FALSE);
    -
    - if (yrl) {
    - list->proto_data = g_list_remove(list->proto_data, yrl);
    - yahoo_roomlist_destroy(yrl);
    - }
    -
    - purple_roomlist_unref(list);
    -}
    -
    -static void yahoo_roomlist_pending(gpointer data, gint source, PurpleInputCondition cond)
    -{
    - struct yahoo_roomlist *yrl = data;
    - PurpleRoomlist *list = yrl->list;
    - char buf[1024];
    - int len;
    - guchar *start;
    - struct yahoo_chatxml_state *s;
    -
    - len = read(yrl->fd, buf, sizeof(buf));
    -
    - if (len < 0 && errno == EAGAIN)
    - return;
    -
    - if (len <= 0) {
    - if (yrl->parse)
    - g_markup_parse_context_end_parse(yrl->parse, NULL);
    - yahoo_roomlist_cleanup(list, yrl);
    - return;
    - }
    -
    - yrl->rxqueue = g_realloc(yrl->rxqueue, len + yrl->rxlen);
    - memcpy(yrl->rxqueue + yrl->rxlen, buf, len);
    - yrl->rxlen += len;
    -
    - if (!yrl->started) {
    - yrl->started = TRUE;
    - start = (guchar *)g_strstr_len((char *)yrl->rxqueue, yrl->rxlen, "\r\n\r\n");
    - if (!start || (start - yrl->rxqueue + 4) >= yrl->rxlen)
    - return;
    - start += 4;
    - } else {
    - start = yrl->rxqueue;
    - }
    -
    - if (yrl->parse == NULL) {
    - s = yahoo_chatxml_state_new(list, yrl);
    - yrl->parse = g_markup_parse_context_new(&parser, 0, s,
    - (GDestroyNotify)yahoo_chatxml_state_destroy);
    - }
    -
    - if (!g_markup_parse_context_parse(yrl->parse, (char *)start, (yrl->rxlen - (start - yrl->rxqueue)), NULL)) {
    -
    - yahoo_roomlist_cleanup(list, yrl);
    - return;
    - }
    -
    - yrl->rxlen = 0;
    -}
    -
    -static void yahoo_roomlist_send_cb(gpointer data, gint source, PurpleInputCondition cond)
    -{
    - struct yahoo_roomlist *yrl;
    - PurpleRoomlist *list;
    - int written, remaining;
    -
    - yrl = data;
    - list = yrl->list;
    -
    - remaining = strlen(yrl->txbuf) - yrl->tx_written;
    - written = write(yrl->fd, yrl->txbuf + yrl->tx_written, remaining);
    -
    - if (written < 0 && errno == EAGAIN)
    - written = 0;
    - else if (written <= 0) {
    - purple_input_remove(yrl->inpa);
    - yrl->inpa = 0;
    - g_free(yrl->txbuf);
    - yrl->txbuf = NULL;
    - purple_notify_error(purple_account_get_connection(list->account), NULL, _("Unable to connect"), _("Fetching the room list failed."));
    - yahoo_roomlist_cleanup(list, yrl);
    - return;
    - }
    -
    - if (written < remaining) {
    - yrl->tx_written += written;
    - return;
    - }
    -
    - g_free(yrl->txbuf);
    - yrl->txbuf = NULL;
    -
    - purple_input_remove(yrl->inpa);
    - yrl->inpa = purple_input_add(yrl->fd, PURPLE_INPUT_READ,
    - yahoo_roomlist_pending, yrl);
    -
    -}
    -
    -static void yahoo_roomlist_got_connected(gpointer data, gint source, const gchar *error_message)
    -{
    - struct yahoo_roomlist *yrl = data;
    - PurpleRoomlist *list = yrl->list;
    - YahooData *yd = purple_account_get_connection(list->account)->proto_data;
    -
    - if (source < 0) {
    - purple_notify_error(purple_account_get_connection(list->account), NULL, _("Unable to connect"), _("Fetching the room list failed."));
    - yahoo_roomlist_cleanup(list, yrl);
    - return;
    - }
    -
    - yrl->fd = source;
    -
    - yrl->txbuf = g_strdup_printf(
    - "GET http://%s/%s HTTP/1.0\r\n"
    - "Host: %s\r\n"
    - "Cookie: Y=%s; T=%s\r\n\r\n",
    - yrl->host, yrl->path, yrl->host, yd->cookie_y,
    - yd->cookie_t);
    -
    -
    - yrl->inpa = purple_input_add(yrl->fd, PURPLE_INPUT_WRITE,
    - yahoo_roomlist_send_cb, yrl);
    - yahoo_roomlist_send_cb(yrl, yrl->fd, PURPLE_INPUT_WRITE);
    -}
    -
    -PurpleRoomlist *yahoo_roomlist_get_list(PurpleConnection *gc)
    -{
    - PurpleAccount *account;
    - PurpleRoomlist *rl;
    - PurpleRoomlistField *f;
    - GList *fields = NULL;
    - struct yahoo_roomlist *yrl;
    - const char *rll, *rlurl;
    - char *url;
    -
    - account = purple_connection_get_account(gc);
    -
    - /* for Yahoo Japan, it appears there is only one valid URL and locale */
    - if(purple_account_get_bool(account, "yahoojp", FALSE)) {
    - rll = YAHOOJP_ROOMLIST_LOCALE;
    - rlurl = YAHOOJP_ROOMLIST_URL;
    - }
    - else { /* but for the rest of the world that isn't the case */
    - rll = purple_account_get_string(account, "room_list_locale", YAHOO_ROOMLIST_LOCALE);
    - rlurl = purple_account_get_string(account, "room_list", YAHOO_ROOMLIST_URL);
    - }
    -
    - url = g_strdup_printf("%s?chatcat=0&intl=%s", rlurl, rll);
    -
    - yrl = g_new0(struct yahoo_roomlist, 1);
    - rl = purple_roomlist_new(account);
    - yrl->list = rl;
    -
    - purple_url_parse(url, &(yrl->host), NULL, &(yrl->path), NULL, NULL);
    - g_free(url);
    -
    - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", "room", TRUE);
    - fields = g_list_append(fields, f);
    -
    - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", "id", TRUE);
    - fields = g_list_append(fields, f);
    -
    - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_INT, _("Users"), "users", FALSE);
    - fields = g_list_append(fields, f);
    -
    - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_INT, _("Voices"), "voices", FALSE);
    - fields = g_list_append(fields, f);
    -
    - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_INT, _("Webcams"), "webcams", FALSE);
    - fields = g_list_append(fields, f);
    -
    - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, _("Topic"), "topic", FALSE);
    - fields = g_list_append(fields, f);
    -
    - purple_roomlist_set_fields(rl, fields);
    -
    - if (purple_proxy_connect(gc, account, yrl->host, 80,
    - yahoo_roomlist_got_connected, yrl) == NULL)
    - {
    - purple_notify_error(gc, NULL, _("Connection problem"), _("Unable to fetch room list."));
    - yahoo_roomlist_cleanup(rl, yrl);
    - return NULL;
    - }
    -
    - rl->proto_data = g_list_append(rl->proto_data, yrl);
    -
    - purple_roomlist_set_in_progress(rl, TRUE);
    - return rl;
    -}
    -
    -void yahoo_roomlist_cancel(PurpleRoomlist *list)
    -{
    - GList *l, *k;
    -
    - k = l = list->proto_data;
    - list->proto_data = NULL;
    -
    - purple_roomlist_set_in_progress(list, FALSE);
    -
    - for (; l; l = l->next) {
    - yahoo_roomlist_destroy(l->data);
    - purple_roomlist_unref(list);
    - }
    - g_list_free(k);
    -}
    -
    -void yahoo_roomlist_expand_category(PurpleRoomlist *list, PurpleRoomlistRoom *category)
    -{
    - struct yahoo_roomlist *yrl;
    - char *url;
    - char *id;
    - const char *rll;
    -
    - if (category->type != PURPLE_ROOMLIST_ROOMTYPE_CATEGORY)
    - return;
    -
    - if (!(id = g_list_nth_data(category->fields, 1))) {
    - purple_roomlist_set_in_progress(list, FALSE);
    - return;
    - }
    -
    - rll = purple_account_get_string(list->account, "room_list_locale",
    - YAHOO_ROOMLIST_LOCALE);
    -
    - if (rll != NULL && *rll != '\0') {
    - url = g_strdup_printf("%s?chatroom_%s=0&intl=%s",
    - purple_account_get_string(list->account,"room_list",
    - YAHOO_ROOMLIST_URL), id, rll);
    - } else {
    - url = g_strdup_printf("%s?chatroom_%s=0",
    - purple_account_get_string(list->account,"room_list",
    - YAHOO_ROOMLIST_URL), id);
    - }
    -
    - yrl = g_new0(struct yahoo_roomlist, 1);
    - yrl->list = list;
    - yrl->cat = category;
    - list->proto_data = g_list_append(list->proto_data, yrl);
    -
    - purple_url_parse(url, &(yrl->host), NULL, &(yrl->path), NULL, NULL);
    - g_free(url);
    -
    - yrl->ucat = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_CATEGORY, _("User Rooms"), yrl->cat);
    - purple_roomlist_room_add(list, yrl->ucat);
    -
    - if (purple_proxy_connect(purple_account_get_connection(list->account),
    - list->account, yrl->host, 80,
    - yahoo_roomlist_got_connected, yrl) == NULL)
    - {
    - purple_notify_error(purple_account_get_connection(list->account),
    - NULL, _("Connection problem"), _("Unable to fetch room list."));
    - purple_roomlist_ref(list);
    - yahoo_roomlist_cleanup(list, yrl);
    - return;
    - }
    -
    - purple_roomlist_set_in_progress(list, TRUE);
    - purple_roomlist_ref(list);
    -}
    --- a/libpurple/protocols/yahoo/yahoochat.h Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,66 +0,0 @@
    -/**
    - * @file yahoochat.h The Yahoo! protocol plugin, chat and conference stuff
    - *
    - * purple
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * This program is free software; you can redistribute it and/or modify
    - * it under the terms of the GNU General Public License as published by
    - * the Free Software Foundation; either version 2 of the License, or
    - * (at your option) any later version.
    - *
    - * This program is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    - * GNU General Public License for more details.
    - *
    - * You should have received a copy of the GNU General Public License
    - * along with this program; if not, write to the Free Software
    - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    - */
    -
    -#ifndef _YAHOOCHAT_H_
    -#define _YAHOOCHAT_H_
    -
    -#include "roomlist.h"
    -#include "yahoo_packet.h"
    -
    -void yahoo_process_conference_invite(PurpleConnection *gc, struct yahoo_packet *pkt);
    -void yahoo_process_conference_decline(PurpleConnection *gc, struct yahoo_packet *pkt);
    -void yahoo_process_conference_logon(PurpleConnection *gc, struct yahoo_packet *pkt);
    -void yahoo_process_conference_logoff(PurpleConnection *gc, struct yahoo_packet *pkt);
    -void yahoo_process_conference_message(PurpleConnection *gc, struct yahoo_packet *pkt);
    -
    -void yahoo_process_chat_online(PurpleConnection *gc, struct yahoo_packet *pkt);
    -void yahoo_process_chat_logout(PurpleConnection *gc, struct yahoo_packet *pkt);
    -void yahoo_process_chat_join(PurpleConnection *gc, struct yahoo_packet *pkt);
    -void yahoo_process_chat_exit(PurpleConnection *gc, struct yahoo_packet *pkt);
    -void yahoo_process_chat_message(PurpleConnection *gc, struct yahoo_packet *pkt);
    -void yahoo_process_chat_addinvite(PurpleConnection *gc, struct yahoo_packet *pkt);
    -void yahoo_process_chat_goto(PurpleConnection *gc, struct yahoo_packet *pkt);
    -
    -void yahoo_c_leave(PurpleConnection *gc, int id);
    -int yahoo_c_send(PurpleConnection *gc, int id, const char *what, PurpleMessageFlags flags);
    -GList *yahoo_c_info(PurpleConnection *gc);
    -GHashTable *yahoo_c_info_defaults(PurpleConnection *gc, const char *chat_name);
    -void yahoo_c_join(PurpleConnection *gc, GHashTable *data);
    -char *yahoo_get_chat_name(GHashTable *data);
    -void yahoo_c_invite(PurpleConnection *gc, int id, const char *msg, const char *name);
    -
    -void yahoo_conf_leave(YahooData *yd, const char *room, const char *dn, GList *who);
    -
    -void yahoo_chat_goto(PurpleConnection *gc, const char *name);
    -
    -/* room listing functions */
    -PurpleRoomlist *yahoo_roomlist_get_list(PurpleConnection *gc);
    -void yahoo_roomlist_cancel(PurpleRoomlist *list);
    -void yahoo_roomlist_expand_category(PurpleRoomlist *list, PurpleRoomlistRoom *category);
    -
    -/* util */
    -void yahoo_chat_add_users(PurpleConvChat *chat, GList *newusers);
    -void yahoo_chat_add_user(PurpleConvChat *chat, const char *user, const char *reason);
    -
    -#endif /* _YAHOO_CHAT_H_ */
    --- a/libpurple/protocols/yahoo/ycht.c Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,658 +0,0 @@
    -/**
    - * @file ycht.c The Yahoo! protocol plugin, YCHT protocol stuff.
    - *
    - * purple
    - *
    - * Copyright (C) 2004 Timothy Ringenbach <omarvo@hotmail.com>
    - * Liberal amounts of code borrowed from the rest of the Yahoo! prpl.
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * This program is free software; you can redistribute it and/or modify
    - * it under the terms of the GNU General Public License as published by
    - * the Free Software Foundation; either version 2 of the License, or
    - * (at your option) any later version.
    - *
    - * This program is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    - * GNU General Public License for more details.
    - *
    - * You should have received a copy of the GNU General Public License
    - * along with this program; if not, write to the Free Software
    - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    - */
    -
    -#include "internal.h"
    -#include "prpl.h"
    -#include "notify.h"
    -#include "account.h"
    -#include "proxy.h"
    -#include "debug.h"
    -#include "conversation.h"
    -#include "util.h"
    -
    -#include "libymsg.h"
    -#include "yahoo_packet.h"
    -#include "ycht.h"
    -#include "yahoochat.h"
    -
    -/*
    - * dword: YCHT
    - * dword: 0x000000AE
    - * dword: service
    - * word: status
    - * word: size
    - */
    -#define YAHOO_CHAT_ID (1)
    -/************************************************************************************
    - * Functions to process various kinds of packets.
    - ************************************************************************************/
    -static void ycht_process_login(YchtConn *ycht, YchtPkt *pkt)
    -{
    - PurpleConnection *gc = ycht->gc;
    - YahooData *yd = gc->proto_data;
    -
    - if (ycht->logged_in)
    - return;
    -
    - yd->chat_online = TRUE;
    - ycht->logged_in = TRUE;
    -
    - if (ycht->room)
    - ycht_chat_join(ycht, ycht->room);
    -}
    -
    -static void ycht_process_logout(YchtConn *ycht, YchtPkt *pkt)
    -{
    - PurpleConnection *gc = ycht->gc;
    - YahooData *yd = gc->proto_data;
    -
    - yd->chat_online = FALSE;
    - ycht->logged_in = FALSE;
    -}
    -
    -static void ycht_process_chatjoin(YchtConn *ycht, YchtPkt *pkt)
    -{
    - char *room, *topic;
    - PurpleConnection *gc = ycht->gc;
    - PurpleConversation *c = NULL;
    - gboolean new_room = FALSE;
    - char **members;
    - int i;
    -
    - room = g_list_nth_data(pkt->data, 0);
    - topic = g_list_nth_data(pkt->data, 1);
    - if (!g_list_nth_data(pkt->data, 4))
    - return;
    - if (!room)
    - return;
    -
    - members = g_strsplit(g_list_nth_data(pkt->data, 4), "\001", 0);
    - for (i = 0; members[i]; i++) {
    - char *tmp = strchr(members[i], '\002');
    - if (tmp)
    - *tmp = '\0';
    - }
    -
    - if (g_list_length(pkt->data) > 5)
    - new_room = TRUE;
    -
    - if (new_room && ycht->changing_rooms) {
    - serv_got_chat_left(gc, YAHOO_CHAT_ID);
    - ycht->changing_rooms = FALSE;
    - c = serv_got_joined_chat(gc, YAHOO_CHAT_ID, room);
    - } else {
    - c = purple_find_chat(gc, YAHOO_CHAT_ID);
    - }
    -
    - if (topic)
    - purple_conv_chat_set_topic(PURPLE_CONV_CHAT(c), NULL, topic);
    -
    - for (i = 0; members[i]; i++) {
    - if (new_room) {
    - /*if (!strcmp(members[i], purple_connection_get_display_name(ycht->gc)))
    - continue;*/
    - purple_conv_chat_add_user(PURPLE_CONV_CHAT(c), members[i], NULL, PURPLE_CBFLAGS_NONE, TRUE);
    - } else {
    - yahoo_chat_add_user(PURPLE_CONV_CHAT(c), members[i], NULL);
    - }
    - }
    -
    - g_strfreev(members);
    -}
    -
    -static void ycht_process_chatpart(YchtConn *ycht, YchtPkt *pkt)
    -{
    - char *room, *who;
    -
    - room = g_list_nth_data(pkt->data, 0);
    - who = g_list_nth_data(pkt->data, 1);
    -
    - if (who && room) {
    - PurpleConversation *c = purple_find_chat(ycht->gc, YAHOO_CHAT_ID);
    - if (c && !purple_utf8_strcasecmp(purple_conversation_get_name(c), room))
    - purple_conv_chat_remove_user(PURPLE_CONV_CHAT(c), who, NULL);
    -
    - }
    -}
    -
    -static void ycht_progress_chatmsg(YchtConn *ycht, YchtPkt *pkt)
    -{
    - char *who, *what, *msg;
    - PurpleConversation *c;
    - PurpleConnection *gc = ycht->gc;
    -
    - who = g_list_nth_data(pkt->data, 1);
    - what = g_list_nth_data(pkt->data, 2);
    -
    - if (!who || !what)
    - return;
    -
    - c = purple_find_chat(gc, YAHOO_CHAT_ID);
    - if (!c)
    - return;
    -
    - msg = yahoo_string_decode(gc, what, 1);
    - what = yahoo_codes_to_html(msg);
    - g_free(msg);
    -
    - if (pkt->service == YCHT_SERVICE_CHATMSG_EMOTE) {
    - char *tmp = g_strdup_printf("/me %s", what);
    - g_free(what);
    - what = tmp;
    - }
    -
    - serv_got_chat_in(gc, YAHOO_CHAT_ID, who, 0, what, time(NULL));
    - g_free(what);
    -}
    -
    -static void ycht_progress_online_friends(YchtConn *ycht, YchtPkt *pkt)
    -{
    -#if 0
    - PurpleConnection *gc = ycht->gc;
    - YahooData *yd = gc->proto_data;
    -
    - if (ycht->logged_in)
    - return;
    -
    - yd->chat_online = TRUE;
    - ycht->logged_in = TRUE;
    -
    - if (ycht->room)
    - ycht_chat_join(ycht, ycht->room);
    -#endif
    -}
    -
    -/*****************************************************************************
    - * Functions dealing with YCHT packets and their contents directly.
    - *****************************************************************************/
    -static void ycht_packet_dump(const guchar *data, int len)
    -{
    -#ifdef YAHOO_YCHT_DEBUG
    - int i;
    -
    - purple_debug_misc("yahoo", "");
    -
    - for (i = 0; i + 1 < len; i += 2) {
    - if ((i % 16 == 0) && i) {
    - purple_debug_misc(NULL, "\n");
    - purple_debug_misc("yahoo", "");
    - }
    -
    - purple_debug_misc(NULL, "%02hhx%02hhx ", data[i], data[i + 1]);
    - }
    - if (i < len)
    - purple_debug_misc(NULL, "%02hhx", data[i]);
    -
    - purple_debug_misc(NULL, "\n");
    - purple_debug_misc("yahoo", "");
    -
    - for (i = 0; i < len; i++) {
    - if ((i % 16 == 0) && i) {
    - purple_debug_misc(NULL, "\n");
    - purple_debug_misc("yahoo", "");
    - }
    -
    - if (g_ascii_isprint(data[i]))
    - purple_debug_misc(NULL, "%c ", data[i]);
    - else
    - purple_debug_misc(NULL, ". ");
    - }
    -
    - purple_debug_misc(NULL, "\n");
    -#endif /* YAHOO_YCHT_DEBUG */
    -}
    -
    -static YchtPkt *ycht_packet_new(guint version, guint service, int status)
    -{
    - YchtPkt *ret;
    -
    - ret = g_new0(YchtPkt, 1);
    -
    - ret->version = version;
    - ret->service = service;
    - ret->status = status;
    -
    - return ret;
    -}
    -
    -static void ycht_packet_append(YchtPkt *pkt, const char *str)
    -{
    - g_return_if_fail(pkt != NULL);
    - g_return_if_fail(str != NULL);
    -
    - pkt->data = g_list_append(pkt->data, g_strdup(str));
    -}
    -
    -static int ycht_packet_length(YchtPkt *pkt)
    -{
    - int ret;
    - GList *l;
    -
    - ret = YCHT_HEADER_LEN;
    -
    - for (l = pkt->data; l; l = l->next) {
    - ret += strlen(l->data);
    - if (l->next)
    - ret += strlen(YCHT_SEP);
    - }
    -
    - return ret;
    -}
    -
    -static void ycht_packet_send_write_cb(gpointer data, gint source, PurpleInputCondition cond)
    -{
    - YchtConn *ycht = data;
    - int ret, writelen;
    -
    - writelen = purple_circ_buffer_get_max_read(ycht->txbuf);
    -
    - if (writelen == 0) {
    - purple_input_remove(ycht->tx_handler);
    - ycht->tx_handler = 0;
    - return;
    - }
    -
    - ret = write(ycht->fd, ycht->txbuf->outptr, writelen);
    -
    - if (ret < 0 && errno == EAGAIN)
    - return;
    - else if (ret <= 0) {
    - /* TODO: error handling */
    -/*
    - gchar *tmp = g_strdup_printf(_("Lost connection with server: %s"),
    - g_strerror(errno));
    - purple_connection_error_reason(purple_account_get_connection(irc->account),
    - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
    - g_free(tmp);
    -*/
    - return;
    - }
    -
    - purple_circ_buffer_mark_read(ycht->txbuf, ret);
    -
    -}
    -
    -static void ycht_packet_send(YchtConn *ycht, YchtPkt *pkt)
    -{
    - int len, pos, written;
    - char *buf;
    - GList *l;
    -
    - g_return_if_fail(ycht != NULL);
    - g_return_if_fail(pkt != NULL);
    - g_return_if_fail(ycht->fd != -1);
    -
    - pos = 0;
    - len = ycht_packet_length(pkt);
    - buf = g_malloc(len);
    -
    - memcpy(buf + pos, "YCHT", 4); pos += 4;
    - pos += yahoo_put32(buf + pos, pkt->version);
    - pos += yahoo_put32(buf + pos, pkt->service);
    - pos += yahoo_put16(buf + pos, pkt->status);
    - pos += yahoo_put16(buf + pos, len - YCHT_HEADER_LEN);
    -
    - for (l = pkt->data; l; l = l->next) {
    - int slen = strlen(l->data);
    - memcpy(buf + pos, l->data, slen); pos += slen;
    -
    - if (l->next) {
    - memcpy(buf + pos, YCHT_SEP, strlen(YCHT_SEP));
    - pos += strlen(YCHT_SEP);
    - }
    - }
    -
    - if (!ycht->tx_handler)
    - written = write(ycht->fd, buf, len);
    - else {
    - written = -1;
    - errno = EAGAIN;
    - }
    -
    - if (written < 0 && errno == EAGAIN)
    - written = 0;
    - else if (written <= 0) {
    - /* TODO: Error handling (was none before NBIO changes) */
    - written = 0;
    - }
    -
    - if (written < len) {
    - if (!ycht->tx_handler)
    - ycht->tx_handler = purple_input_add(ycht->fd,
    - PURPLE_INPUT_WRITE, ycht_packet_send_write_cb,
    - ycht);
    - purple_circ_buffer_append(ycht->txbuf, buf + written,
    - len - written);
    - }
    -
    - g_free(buf);
    -}
    -
    -static void ycht_packet_read(YchtPkt *pkt, const char *buf, int len)
    -{
    - const char *pos = buf;
    - const char *needle;
    - char *tmp, *tmp2;
    - int i = 0;
    -
    - while (len > 0 && (needle = g_strstr_len(pos, len, YCHT_SEP))) {
    - tmp = g_strndup(pos, needle - pos);
    - pkt->data = g_list_append(pkt->data, tmp);
    - len -= needle - pos + strlen(YCHT_SEP);
    - pos = needle + strlen(YCHT_SEP);
    - tmp2 = g_strescape(tmp, NULL);
    - purple_debug_misc("yahoo", "Data[%d]:\t%s\n", i++, tmp2);
    - g_free(tmp2);
    - }
    -
    - if (len) {
    - tmp = g_strndup(pos, len);
    - pkt->data = g_list_append(pkt->data, tmp);
    - tmp2 = g_strescape(tmp, NULL);
    - purple_debug_misc("yahoo", "Data[%d]:\t%s\n", i, tmp2);
    - g_free(tmp2);
    - };
    -
    - purple_debug_misc("yahoo", "--==End of incoming YCHT packet==--\n");
    -}
    -
    -static void ycht_packet_process(YchtConn *ycht, YchtPkt *pkt)
    -{
    - if (pkt->data && !strncmp(pkt->data->data, "*** Danger Will Robinson!!!", strlen("*** Danger Will Robinson!!!")))
    - return;
    -
    - switch (pkt->service) {
    - case YCHT_SERVICE_LOGIN:
    - ycht_process_login(ycht, pkt);
    - break;
    - case YCHT_SERVICE_LOGOUT:
    - ycht_process_logout(ycht, pkt);
    - break;
    - case YCHT_SERVICE_CHATJOIN:
    - ycht_process_chatjoin(ycht, pkt);
    - break;
    - case YCHT_SERVICE_CHATPART:
    - ycht_process_chatpart(ycht, pkt);
    - break;
    - case YCHT_SERVICE_CHATMSG:
    - case YCHT_SERVICE_CHATMSG_EMOTE:
    - ycht_progress_chatmsg(ycht, pkt);
    - break;
    - case YCHT_SERVICE_ONLINE_FRIENDS:
    - ycht_progress_online_friends(ycht, pkt);
    - break;
    - default:
    - purple_debug_warning("yahoo", "YCHT: warning, unhandled service 0x%02x\n", pkt->service);
    - }
    -}
    -
    -static void ycht_packet_free(YchtPkt *pkt)
    -{
    - GList *l;
    -
    - g_return_if_fail(pkt != NULL);
    -
    - for (l = pkt->data; l; l = l->next)
    - g_free(l->data);
    - g_list_free(pkt->data);
    - g_free(pkt);
    -}
    -
    -/************************************************************************************
    - * Functions dealing with connecting and disconnecting and reading data into YchtPkt
    - * structs, and all that stuff.
    - ************************************************************************************/
    -
    -void ycht_connection_close(YchtConn *ycht)
    -{
    - YahooData *yd = ycht->gc->proto_data;
    -
    - if (yd) {
    - yd->ycht = NULL;
    - yd->chat_online = FALSE;
    - }
    -
    - if (ycht->fd > 0)
    - close(ycht->fd);
    - if (ycht->inpa)
    - purple_input_remove(ycht->inpa);
    -
    - if (ycht->tx_handler)
    - purple_input_remove(ycht->tx_handler);
    -
    - purple_circ_buffer_destroy(ycht->txbuf);
    -
    - g_free(ycht->rxqueue);
    -
    - g_free(ycht);
    -}
    -
    -static void ycht_connection_error(YchtConn *ycht, const gchar *error)
    -{
    -
    - purple_notify_info(ycht->gc, NULL, _("Connection problem with the YCHT server"), error);
    - ycht_connection_close(ycht);
    -}
    -
    -static void ycht_pending(gpointer data, gint source, PurpleInputCondition cond)
    -{
    - YchtConn *ycht = data;
    - char buf[1024];
    - int len;
    -
    - len = read(ycht->fd, buf, sizeof(buf));
    -
    - if (len < 0) {
    - gchar *tmp;
    -
    - if (errno == EAGAIN)
    - /* No worries */
    - return;
    -
    - tmp = g_strdup_printf(_("Lost connection with server: %s"),
    - g_strerror(errno));
    - ycht_connection_error(ycht, tmp);
    - g_free(tmp);
    - return;
    - } else if (len == 0) {
    - ycht_connection_error(ycht, _("Server closed the connection"));
    - return;
    - }
    -
    - ycht->rxqueue = g_realloc(ycht->rxqueue, len + ycht->rxlen);
    - memcpy(ycht->rxqueue + ycht->rxlen, buf, len);
    - ycht->rxlen += len;
    -
    - while (1) {
    - YchtPkt *pkt;
    - int pos = 0;
    - guint pktlen;
    - guint service;
    - guint version;
    - gint status;
    -
    - if (ycht->rxlen < YCHT_HEADER_LEN)
    - return;
    -
    - if (strncmp("YCHT", (char *)ycht->rxqueue, 4) != 0)
    - purple_debug_error("yahoo", "YCHT: protocol error.\n");
    -
    - pos += 4; /* YCHT */
    -
    - version = yahoo_get32(ycht->rxqueue + pos); pos += 4;
    - service = yahoo_get32(ycht->rxqueue + pos); pos += 4;
    - status = yahoo_get16(ycht->rxqueue + pos); pos += 2;
    - pktlen = yahoo_get16(ycht->rxqueue + pos); pos += 2;
    - purple_debug_misc("yahoo", "ycht: %d bytes to read, rxlen is %d\n",
    - pktlen, ycht->rxlen);
    -
    - if (ycht->rxlen < (YCHT_HEADER_LEN + pktlen))
    - return;
    -
    - purple_debug_misc("yahoo", "--==Incoming YCHT packet==--\n");
    - purple_debug_misc("yahoo", "YCHT Service: 0x%02x Version: 0x%02x Status: 0x%02x\n",
    - service, version, status);
    - ycht_packet_dump(ycht->rxqueue, YCHT_HEADER_LEN + pktlen);
    -
    - pkt = ycht_packet_new(version, service, status);
    - ycht_packet_read(pkt, (char *)ycht->rxqueue + pos, pktlen);
    -
    - ycht->rxlen -= YCHT_HEADER_LEN + pktlen;
    - if (ycht->rxlen) {
    - guchar *tmp = g_memdup(ycht->rxqueue + YCHT_HEADER_LEN + pktlen, ycht->rxlen);
    - g_free(ycht->rxqueue);
    - ycht->rxqueue = tmp;
    - } else {
    - g_free(ycht->rxqueue);
    - ycht->rxqueue = NULL;
    - }
    -
    - ycht_packet_process(ycht, pkt);
    -
    - ycht_packet_free(pkt);
    - }
    -}
    -
    -static void ycht_got_connected(gpointer data, gint source, const gchar *error_message)
    -{
    - YchtConn *ycht = data;
    - PurpleConnection *gc = ycht->gc;
    - YahooData *yd = gc->proto_data;
    - YchtPkt *pkt;
    - char *buf;
    -
    - if (source < 0) {
    - ycht_connection_error(ycht, _("Unable to connect"));
    - return;
    - }
    -
    - ycht->fd = source;
    -
    - pkt = ycht_packet_new(YCHT_VERSION, YCHT_SERVICE_LOGIN, 0);
    -
    - buf = g_strdup_printf("%s\001Y=%s; T=%s", purple_connection_get_display_name(gc), yd->cookie_y, yd->cookie_t);
    - ycht_packet_append(pkt, buf);
    - g_free(buf);
    -
    - ycht_packet_send(ycht, pkt);
    -
    - ycht_packet_free(pkt);
    -
    - ycht->inpa = purple_input_add(ycht->fd, PURPLE_INPUT_READ, ycht_pending, ycht);
    -}
    -
    -void ycht_connection_open(PurpleConnection *gc)
    -{
    - YchtConn *ycht;
    - YahooData *yd = gc->proto_data;
    - PurpleAccount *account = purple_connection_get_account(gc);
    -
    - ycht = g_new0(YchtConn, 1);
    - ycht->gc = gc;
    - ycht->fd = -1;
    -
    - yd->ycht = ycht;
    -
    - if (purple_proxy_connect(gc, account,
    - purple_account_get_string(account, "ycht-server", YAHOO_YCHT_HOST),
    - purple_account_get_int(account, "ycht-port", YAHOO_YCHT_PORT),
    - ycht_got_connected, ycht) == NULL)
    - {
    - ycht_connection_error(ycht, _("Unable to connect"));
    - return;
    - }
    -}
    -
    -/*******************************************************************************************
    - * These are functions called because the user did something.
    - *******************************************************************************************/
    -
    -void ycht_chat_join(YchtConn *ycht, const char *room)
    -{
    - YchtPkt *pkt;
    - char *tmp;
    -
    - tmp = g_strdup(room);
    - g_free(ycht->room);
    - ycht->room = tmp;
    -
    - if (!ycht->logged_in)
    - return;
    -
    - ycht->changing_rooms = TRUE;
    - pkt = ycht_packet_new(YCHT_VERSION, YCHT_SERVICE_CHATJOIN, 0);
    - ycht_packet_append(pkt, ycht->room);
    - ycht_packet_send(ycht, pkt);
    - ycht_packet_free(pkt);
    -}
    -
    -int ycht_chat_send(YchtConn *ycht, const char *room, const char *what)
    -{
    - YchtPkt *pkt;
    - char *msg1, *msg2, *buf;
    -
    - if (strcmp(room, ycht->room))
    - purple_debug_warning("yahoo", "uhoh, sending to the wrong room!\n");
    -
    - pkt = ycht_packet_new(YCHT_VERSION, YCHT_SERVICE_CHATMSG, 0);
    -
    - msg1 = yahoo_html_to_codes(what);
    - msg2 = yahoo_string_encode(ycht->gc, msg1, NULL);
    - g_free(msg1);
    -
    - buf = g_strdup_printf("%s\001%s", ycht->room, msg2);
    - ycht_packet_append(pkt, buf);
    - g_free(msg2);
    - g_free(buf);
    -
    - ycht_packet_send(ycht, pkt);
    - ycht_packet_free(pkt);
    - return 1;
    -}
    -
    -void ycht_chat_leave(YchtConn *ycht, const char *room, gboolean logout)
    -{
    - if (logout)
    - ycht_connection_close(ycht);
    -}
    -
    -void ycht_chat_send_invite(YchtConn *ycht, const char *room, const char *buddy, const char *msg)
    -{
    -}
    -
    -void ycht_chat_goto_user(YchtConn *ycht, const char *name)
    -{
    -}
    -
    -void ycht_chat_send_keepalive(YchtConn *ycht)
    -{
    - YchtPkt *pkt;
    -
    - pkt = ycht_packet_new(YCHT_VERSION, YCHT_SERVICE_PING, 0);
    - ycht_packet_send(ycht, pkt);
    - ycht_packet_free(pkt);
    -}
    --- a/libpurple/protocols/yahoo/ycht.h Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,97 +0,0 @@
    -/**
    - * @file ycht.h The Yahoo! protocol plugin, YCHT protocol stuff.
    - *
    - * purple
    - *
    - * Copyright (C) 2004 Timothy Ringenbach <omarvo@hotmail.com>
    - *
    - * Purple is the legal property of its developers, whose names are too numerous
    - * to list here. Please refer to the COPYRIGHT file distributed with this
    - * source distribution.
    - *
    - * This program is free software; you can redistribute it and/or modify
    - * it under the terms of the GNU General Public License as published by
    - * the Free Software Foundation; either version 2 of the License, or
    - * (at your option) any later version.
    - *
    - * This program is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    - * GNU General Public License for more details.
    - *
    - * You should have received a copy of the GNU General Public License
    - * along with this program; if not, write to the Free Software
    - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    - */
    -
    -#ifndef _PURPLE_YCHT_H_
    -#define _PURPLE_YCHT_H_
    -
    -/* #define YAHOO_YCHT_DEBUG */
    -
    -#define YAHOO_YCHT_HOST "jcs3.chat.dcn.yahoo.com"
    -#define YAHOO_YCHT_PORT 8002
    -
    -#define YCHT_VERSION (0xae)
    -#define YCHT_HEADER_LEN (0x10)
    -
    -typedef enum {
    - YCHT_SERVICE_LOGIN = 0x01,
    - YCHT_SERVICE_LOGOUT = 0x02,
    - YCHT_SERVICE_CHATJOIN = 0x11,
    - YCHT_SERVICE_CHATPART = 0x12,
    - YCHT_SERVICE_CHATMSG = 0x41,
    - YCHT_SERVICE_CHATMSG_EMOTE = 0x43,
    - YCHT_SERVICE_PING = 0x62,
    - YCHT_SERVICE_ONLINE_FRIENDS = 0x68
    -} ycht_service;
    -/*
    -yahoo: YCHT Service: 0x11 Version: 0x100
    -yahoo: Data[0]: Linux, FreeBSD, Solaris:1
    -yahoo: Data[1]: Questions, problems and discussions about all flavors of Unix.
    -yahoo: Data[2]:
    -yahoo: Data[3]: 0
    -yahoo: Data[4]: sgooki888\0020\002 \0022769036\00258936\002
    -yahoo: --==End of incoming YCHT packet==--
    -
    -yahoo: --==Incoming YCHT packet==--
    -yahoo: YCHT Service: 0x12 Version: 0x100
    -yahoo: Data[0]: Linux, FreeBSD, Solaris:1
    -yahoo: Data[1]: cccc4cccc
    -yahoo: --==End of incoming YCHT packet==--
    -
    -*/
    -#define YCHT_SEP "\xc0\x80"
    -
    -typedef struct _YchtConn {
    - PurpleConnection *gc;
    - gchar *room;
    - int room_id;
    - gint fd;
    - gint inpa;
    - gboolean logged_in;
    - gboolean changing_rooms;
    - guchar *rxqueue;
    - guint rxlen;
    - PurpleCircBuffer *txbuf;
    - guint tx_handler;
    -} YchtConn;
    -
    -typedef struct {
    - guint version;
    - guint service;
    - gint status;
    - GList *data;
    -} YchtPkt;
    -
    -void ycht_connection_open(PurpleConnection *gc);
    -void ycht_connection_close(YchtConn *ycht);
    -
    -void ycht_chat_join(YchtConn *ycht, const char *room);
    -int ycht_chat_send(YchtConn *ycht, const char *room, const char *what);
    -void ycht_chat_leave(YchtConn *ycht, const char *room, gboolean logout);
    -void ycht_chat_send_invite(YchtConn *ycht, const char *room, const char *buddy, const char *msg);
    -void ycht_chat_goto_user(YchtConn *ycht, const char *name);
    -void ycht_chat_send_keepalive(YchtConn *ycht);
    -
    -#endif /* _PURPLE_YCHT_H_ */
    --- a/libpurple/prpl.h Wed Oct 05 21:14:58 2016 +0200
    +++ b/libpurple/prpl.h Wed Oct 05 15:10:29 2016 -0500
    @@ -162,7 +162,7 @@
    /**
    * Notify on new mail.
    *
    - * Yahoo notifies you when you have new mail.
    + * If a protocol notifies you when you have new mail.
    */
    OPT_PROTO_MAIL_CHECK = 0x00000020,
    @@ -921,8 +921,8 @@
    * @param gc The connection to send the message on.
    * @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 protocols are allowed to define more.
    + * of the attention request command to send. 0 if prpl only defines one,
    + * 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.
    --- a/libpurple/purple-url-handler Wed Oct 05 21:14:58 2016 +0200
    +++ b/libpurple/purple-url-handler Wed Oct 05 15:10:29 2016 -0500
    @@ -300,31 +300,6 @@
    # XXX V&V prompt to establish call
    goim(account, jid)
    -def ymsgr(uri):
    - protocol = "prpl-yahoo"
    - match = re.match(r"^ymsgr:([^?]*)(\?([^&]*)(&(.*))?)", uri)
    - if not match:
    - print("Invalid ymsgr URI: %s" % uri)
    - return
    -
    - command = unquote_plus(match.group(1))
    - screenname = unquote_plus(match.group(3))
    - paramstring = match.group(5)
    - params = {}
    - if paramstring:
    - for param in paramstring.split("&"):
    - key, value = extendlist(param.split("=", 1), 2, "")
    - params[key] = unquote_plus(value)
    -
    - account = findaccount(protocol)
    -
    - if command.lower() == "sendim":
    - goim(account, screenname, params.get("m"))
    - elif command.lower() == "chat":
    - gochat(account, {"room": screenname})
    - elif command.lower() == "addfriend":
    - addbuddy(account, screenname)
    -
    def main(argv=sys.argv):
    if len(argv) != 2 or argv[1] == "--help" or argv[1] == "-h":
    @@ -354,8 +329,6 @@
    xmpp(uri)
    elif type == "gtalk":
    gtalk(uri)
    - elif type == "ymsgr":
    - ymsgr(uri)
    else:
    print("Unknown protocol: %s" % type)
    except dbus.DBusException as e:
    --- a/libpurple/server.h Wed Oct 05 21:14:58 2016 +0200
    +++ b/libpurple/server.h Wed Oct 05 15:10:29 2016 -0500
    @@ -68,8 +68,8 @@
    * @param gc The connection to send the message on.
    * @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 protocols are allowed to define more.
    + * of the attention request command to send. 0 if prpl only defines one,
    + * 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.
    --- a/libpurple/tests/Makefile.am Wed Oct 05 21:14:58 2016 +0200
    +++ b/libpurple/tests/Makefile.am Wed Oct 05 15:10:29 2016 -0500
    @@ -15,7 +15,6 @@
    test_jabber_jutil.c \
    test_jabber_scram.c \
    test_oscar_util.c \
    - test_yahoo_util.c \
    test_util.c \
    test_xmlnode.c \
    $(top_builddir)/libpurple/util.h
    @@ -32,7 +31,6 @@
    check_libpurple_LDADD=\
    $(top_builddir)/libpurple/protocols/jabber/libjabber.la \
    $(top_builddir)/libpurple/protocols/oscar/liboscar.la \
    - $(top_builddir)/libpurple/protocols/yahoo/libymsg.la \
    $(top_builddir)/libpurple/libpurple.la \
    @CHECK_LIBS@ \
    $(GLIB_LIBS)
    --- a/libpurple/tests/check_libpurple.c Wed Oct 05 21:14:58 2016 +0200
    +++ b/libpurple/tests/check_libpurple.c Wed Oct 05 15:10:29 2016 -0500
    @@ -92,7 +92,6 @@
    srunner_add_suite(sr, jabber_jutil_suite());
    srunner_add_suite(sr, jabber_scram_suite());
    srunner_add_suite(sr, oscar_util_suite());
    - srunner_add_suite(sr, yahoo_util_suite());
    srunner_add_suite(sr, util_suite());
    srunner_add_suite(sr, xmlnode_suite());
    --- a/libpurple/tests/test_yahoo_util.c Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,214 +0,0 @@
    -#include <string.h>
    -
    -#include "tests.h"
    -#include "../protocols/yahoo/libymsg.h"
    -
    -static void setup_codes_to_html(void)
    -{
    - yahoo_init_colorht();
    -}
    -
    -static void teardown_codes_to_html(void)
    -{
    - yahoo_dest_colorht();
    -}
    -
    -START_TEST(test_codes_to_html)
    -{
    - assert_string_equal_free("",
    - yahoo_codes_to_html(""));
    - assert_string_equal_free("",
    - yahoo_codes_to_html("\x1B[12345m"));
    - assert_string_equal_free("plain",
    - yahoo_codes_to_html("plain"));
    - assert_string_equal_free("unknown ansi code",
    - yahoo_codes_to_html("unknown \x1B[12345m ansi code"));
    - assert_string_equal_free("plain &lt;peanut&gt;",
    - yahoo_codes_to_html("plain <peanut>"));
    - assert_string_equal_free("plain &lt;peanut",
    - yahoo_codes_to_html("plain <peanut"));
    - assert_string_equal_free("plain&gt; peanut",
    - yahoo_codes_to_html("plain> peanut"));
    - assert_string_equal_free("<font face='inva&gt;lid'>test</font>",
    - yahoo_codes_to_html("<font face='inva>lid'>test"));
    - assert_string_equal_free("&lt;font face=&apos;inva&gt;lid",
    - yahoo_codes_to_html("<font face='inva>lid"));
    -
    - /* bold/italic/underline */
    - assert_string_equal_free("<b>bold</b>",
    - yahoo_codes_to_html("\x1B[1mbold"));
    - assert_string_equal_free("<i>italic</i>",
    - yahoo_codes_to_html("\x1B[2mitalic"));
    - assert_string_equal_free("<u>underline</u>",
    - yahoo_codes_to_html("\x1B[4munderline"));
    - assert_string_equal_free("no markup",
    - yahoo_codes_to_html("no\x1B[x4m markup"));
    - assert_string_equal_free("<b>bold</b> <i>italic</i> <u>underline</u>",
    - yahoo_codes_to_html("\x1B[1mbold\x1B[x1m \x1B[2mitalic\x1B[x2m \x1B[4munderline"));
    - assert_string_equal_free("<b>bold <i>bolditalic</i></b><i> italic</i>",
    - yahoo_codes_to_html("\x1B[1mbold \x1B[2mbolditalic\x1B[x1m italic"));
    - assert_string_equal_free("<b>bold <i>bolditalic</i></b><i> <u>italicunderline</u></i>",
    - yahoo_codes_to_html("\x1B[1mbold \x1B[2mbolditalic\x1B[x1m \x1B[4mitalicunderline"));
    - assert_string_equal_free("<b>bold <i>bolditalic <u>bolditalicunderline</u></i><u> boldunderline</u></b>",
    - yahoo_codes_to_html("\x1B[1mbold \x1B[2mbolditalic \x1B[4mbolditalicunderline\x1B[x2m boldunderline"));
    - assert_string_equal_free("<b>bold <i>bolditalic <u>bolditalicunderline</u></i></b><i><u> italicunderline</u></i>",
    - yahoo_codes_to_html("\x1B[1mbold \x1B[2mbolditalic \x1B[4mbolditalicunderline\x1B[x1m italicunderline"));
    -
    - /* link */
    - assert_string_equal_free("http://pidgin.im/",
    - yahoo_codes_to_html("\x1B[lmhttp://pidgin.im/\x1B[xlm"));
    -
    -#ifdef USE_CSS_FORMATTING
    - /* font color */
    - assert_string_equal_free("<span style='color: #0000FF'>blue</span>",
    - yahoo_codes_to_html("\x1B[31mblue"));
    - assert_string_equal_free("<span style='color: #70ea15'>custom color</span>",
    - yahoo_codes_to_html("\x1B[#70ea15mcustom color"));
    -
    - /* font face */
    - assert_string_equal_free("<font face='Georgia'>test</font>",
    - yahoo_codes_to_html("<font face='Georgia'>test</font>"));
    -
    - /* font size */
    - assert_string_equal_free("<font><span style='font-size: 15pt'>test</span></font>",
    - yahoo_codes_to_html("<font size='15'>test"));
    - assert_string_equal_free("<font><span style='font-size: 32pt'>size 32</span></font>",
    - yahoo_codes_to_html("<font size='32'>size 32"));
    -
    - /* combinations */
    - assert_string_equal_free("<font face='Georgia'><span style='font-size: 32pt'>test</span></font>",
    - yahoo_codes_to_html("<font face='Georgia' size='32'>test"));
    - assert_string_equal_free("<span style='color: #FF0080'><font><span style='font-size: 15pt'>test</span></font></span>",
    - yahoo_codes_to_html("\x1B[35m<font size='15'>test"));
    -#else
    - /* font color */
    - assert_string_equal_free("<font color='#0000FF'>blue</font>",
    - yahoo_codes_to_html("\x1B[31mblue"));
    - assert_string_equal_free("<font color='#70ea15'>custom color</font>",
    - yahoo_codes_to_html("\x1B[#70ea15mcustom color"));
    - assert_string_equal_free("test",
    - yahoo_codes_to_html("<ALT #ff0000,#00ff00,#0000ff>test</ALT>"));
    -
    - /* font face */
    - assert_string_equal_free("<font face='Georgia'>test</font>",
    - yahoo_codes_to_html("<font face='Georgia'>test"));
    -
    - /* font size */
    - assert_string_equal_free("<font size='4' absz='15'>test</font>",
    - yahoo_codes_to_html("<font size='15'>test"));
    - assert_string_equal_free("<font size='6' absz='32'>size 32</font>",
    - yahoo_codes_to_html("<font size='32'>size 32"));
    -
    - /* combinations */
    - assert_string_equal_free("<font face='Georgia' size='6' absz='32'>test</font>",
    - yahoo_codes_to_html("<font face='Georgia' size='32'>test"));
    - assert_string_equal_free("<font color='#FF0080'><font size='4' absz='15'>test</font></font>",
    - yahoo_codes_to_html("\x1B[35m<font size='15'>test"));
    - assert_string_equal_free(":&lt;",
    - yahoo_codes_to_html("<FADE #ff0000,#00ff00,#0000ff>:<</FADE>"));
    -#endif /* !USE_CSS_FORMATTING */
    -}
    -END_TEST
    -
    -START_TEST(test_html_to_codes)
    -{
    - assert_string_equal_free("plain",
    - yahoo_html_to_codes("plain"));
    - assert_string_equal_free("plain <peanut>",
    - yahoo_html_to_codes("plain &lt;peanut&gt;"));
    - assert_string_equal_free("plain <peanut",
    - yahoo_html_to_codes("plain &lt;peanut"));
    - assert_string_equal_free("plain> peanut",
    - yahoo_html_to_codes("plain&gt; peanut"));
    - assert_string_equal_free("plain >",
    - yahoo_html_to_codes("plain &gt;"));
    - assert_string_equal_free("plain > ",
    - yahoo_html_to_codes("plain &gt; "));
    - assert_string_equal_free("plain <",
    - yahoo_html_to_codes("plain &lt;"));
    - assert_string_equal_free("plain < ",
    - yahoo_html_to_codes("plain &lt; "));
    - assert_string_equal_free("plain &lt",
    - yahoo_html_to_codes("plain &lt"));
    - assert_string_equal_free("plain &",
    - yahoo_html_to_codes("plain &amp;"));
    -
    - /* bold/italic/underline */
    - assert_string_equal_free("\x1B[1mbold\x1B[x1m",
    - yahoo_html_to_codes("<b>bold</b>"));
    - assert_string_equal_free("\x1B[2mitalic\x1B[x2m",
    - yahoo_html_to_codes("<i>italic</i>"));
    - assert_string_equal_free("\x1B[4munderline\x1B[x4m",
    - yahoo_html_to_codes("<u>underline</u>"));
    - assert_string_equal_free("no markup",
    - yahoo_html_to_codes("no</u> markup"));
    - assert_string_equal_free("\x1B[1mbold\x1B[x1m \x1B[2mitalic\x1B[x2m \x1B[4munderline\x1B[x4m",
    - yahoo_html_to_codes("<b>bold</b> <i>italic</i> <u>underline</u>"));
    - assert_string_equal_free("\x1B[1mbold \x1B[2mbolditalic\x1B[x2m\x1B[x1m\x1B[2m italic\x1B[x2m",
    - yahoo_html_to_codes("<b>bold <i>bolditalic</i></b><i> italic</i>"));
    - assert_string_equal_free("\x1B[1mbold \x1B[2mbolditalic\x1B[x2m\x1B[x1m\x1B[2m \x1B[4mitalicunderline\x1B[x4m\x1B[x2m",
    - yahoo_html_to_codes("<b>bold <i>bolditalic</i></b><i> <u>italicunderline</u></i>"));
    -
    - /* link */
    - assert_string_equal_free("http://pidgin.im/",
    - yahoo_html_to_codes("<A HREF=\"http://pidgin.im/\">http://pidgin.im/</A>"));
    - assert_string_equal_free("mark@example.com",
    - yahoo_html_to_codes("<A HREF=\"mailto:mark@example.com\">mark@example.com</A>"));
    -#if 0
    - assert_string_equal_free("Pidgin (http://pidgin.im/)",
    - yahoo_html_to_codes("<A HREF=\"http://pidgin.im/\">Pidgin</A>"));
    -#endif
    -
    - /* font nothing */
    - assert_string_equal_free("nothing",
    - yahoo_html_to_codes("<font>nothing</font>"));
    -
    - /* font color */
    - assert_string_equal_free("\x1B[#E71414mred\x1B[#000000m",
    - yahoo_html_to_codes("<font color=\"#E71414\">red</font>"));
    - assert_string_equal_free("\x1B[#FF0000mred\x1B[#000000m \x1B[#0000FFmblue\x1B[#000000m black",
    - yahoo_html_to_codes("<font color=\"#FF0000\">red</font> <font color=\"#0000FF\">blue</font> black"));
    -
    - /* font size */
    - assert_string_equal_free("<font size=\"10\">test</font>",
    - yahoo_html_to_codes("<font size=\"2\">test</font>"));
    - assert_string_equal_free("<font size=\"30\">test</font>",
    - yahoo_html_to_codes("<font size=\"6\">test</font>"));
    -
    - /* combinations */
    - assert_string_equal_free("\x1B[#FF0000m<font size=\"8\">redsmall</font> rednormal\x1B[#000000m",
    - yahoo_html_to_codes("<font color=\"#FF0000\"><font size=\"1\">redsmall</font> rednormal</font>"));
    -
    - assert_string_equal_free("\x1B[#FF0000m<font size=\"8\">redsmall</font> \x1B[#00FF00mgreennormal\x1B[#FF0000m rednormal\x1B[#000000m",
    - yahoo_html_to_codes("<font color=\"#FF0000\"><font size=\"1\">redsmall</font> <font color=\"#00FF00\">greennormal</font> rednormal</font>"));
    -
    - assert_string_equal_free("\x1B[1mbold \x1B[#FF0000mred <font face=\"Comic Sans MS\" size=\"20\">larger \x1B[#000000mbacktoblack <font size=\"12\">normalsize</font>\x1B[#FF0000m</font>\x1B[#000000m\x1B[x1m",
    - yahoo_html_to_codes("<b>bold <font color=\"#FF0000\">red <font face=\"Comic Sans MS\" size=\"5\">larger <font color=\"#000000\">backtoblack <font size=\"3\">normalsize</font></font></font></font></b>"));
    -
    - /* buzz/unknown tags */
    - assert_string_equal_free("<ding>",
    - yahoo_html_to_codes("<ding>"));
    - assert_string_equal_free("Unknown <tags>",
    - yahoo_html_to_codes("Unknown <tags>"));
    -}
    -END_TEST
    -
    -Suite *
    -yahoo_util_suite(void)
    -{
    - Suite *s;
    - TCase *tc;
    -
    - s = suite_create("Yahoo Utility Functions");
    -
    - tc = tcase_create("Convert IM from network format to HTML");
    - tcase_add_unchecked_fixture(tc, setup_codes_to_html, teardown_codes_to_html);
    - tcase_add_test(tc, test_codes_to_html);
    - suite_add_tcase(s, tc);
    -
    - tc = tcase_create("Convert IM from HTML to network format");
    - tcase_add_test(tc, test_html_to_codes);
    - suite_add_tcase(s, tc);
    -
    - return s;
    -}
    --- a/libpurple/tests/tests.h Wed Oct 05 21:14:58 2016 +0200
    +++ b/libpurple/tests/tests.h Wed Oct 05 15:10:29 2016 -0500
    @@ -14,7 +14,6 @@
    Suite * jabber_jutil_suite(void);
    Suite * jabber_scram_suite(void);
    Suite * oscar_util_suite(void);
    -Suite * yahoo_util_suite(void);
    Suite * util_suite(void);
    Suite * xmlnode_suite(void);
    --- a/libpurple/util.h Wed Oct 05 21:14:58 2016 +0200
    +++ b/libpurple/util.h Wed Oct 05 15:10:29 2016 -0500
    @@ -456,8 +456,8 @@
    /**
    * Extracts a field of data from HTML.
    *
    - * This is a scary function. See protocols/yahoo/yahoo_profile.c
    - * for example usage.
    + * This is a scary function. It used to be used for MSN and Yahoo prpls,
    + * but since those prpls have been removed, this is now deprecated.
    *
    * @param str The string to parse.
    * @param len The size of str.
    --- a/pidgin.apspec.in Wed Oct 05 21:14:58 2016 +0200
    +++ b/pidgin.apspec.in Wed Oct 05 15:10:29 2016 -0500
    @@ -14,7 +14,7 @@
    [Description]
    Pidgin allows you to talk to anyone using a variety of messaging protocols,
    -including AIM (Oscar and TOC), ICQ, IRC, Yahoo!, XMPP,
    +including AIM (Oscar and TOC), ICQ, IRC, XMPP,
    Gadu-Gadu, and Zephyr. These protocols are implemented using a
    modular, easy to use design. To use a protocol, just add an account using the
    account editor.
    @@ -23,7 +23,7 @@
    features, such as perl scripting, TCL scripting and C plugins.
    Pidgin is NOT affiliated with or endorsed by America Online, Inc., Microsoft
    -Corporation, Yahoo! Inc., or ICQ Inc.
    +Corporation, or ICQ Inc.
    [BuildPrepare]
    APBUILD_STATIC="Xss startup-notification-1" prepareBuild --enable-nss --enable-gnutls --enable-binreloc --disable-perl --disable-tcl --disable-gtktest --disable-glibtest --disable-vv --disable-fortify
    --- a/pidgin.spec.in Wed Oct 05 21:14:58 2016 +0200
    +++ b/pidgin.spec.in Wed Oct 05 15:10:29 2016 -0500
    @@ -161,7 +161,7 @@
    %description
    Pidgin allows you to talk to anyone using a variety of messaging
    -protocols including AIM, Yahoo!, XMPP, Bonjour, Gadu-Gadu,
    +protocols including AIM, XMPP, Bonjour, Gadu-Gadu,
    ICQ, IRC, Novell Groupwise, QQ, Lotus Sametime, SILC, Simple and
    Zephyr. These protocols are implemented using a modular, easy to
    use design. To use a protocol, just add an account using the
    @@ -171,7 +171,7 @@
    unique features, such as perl scripting, TCL scripting and C plugins.
    Pidgin is not affiliated with or endorsed by America Online, Inc.,
    -Microsoft Corporation, Yahoo! Inc., or ICQ Inc.
    +Microsoft Corporation, or ICQ Inc.
    %description devel
    The pidgin-devel package contains the header files, developer
    @@ -183,7 +183,7 @@
    and Finch.
    libpurple supports a variety of messaging protocols including AIM,
    -Yahoo!, XMPP, Bonjour, Gadu-Gadu, ICQ, IRC, Novell Groupwise, QQ,
    +XMPP, Bonjour, Gadu-Gadu, ICQ, IRC, Novell Groupwise, QQ,
    Lotus Sametime, SILC, Simple and Zephyr.
    %description -n libpurple-devel
    --- a/pidgin/data/pidgin.appdata.xml.in Wed Oct 05 21:14:58 2016 +0200
    +++ b/pidgin/data/pidgin.appdata.xml.in Wed Oct 05 15:10:29 2016 -0500
    @@ -14,7 +14,7 @@
    </_p>
    <_p>
    This means that you can be chatting with friends on AIM, talking to a
    - friend on Google Talk, and sitting in a Yahoo chat room all at the same
    + friend on Google Talk, and sitting in an IRC chat room all at the same
    time.
    </_p>
    </description>
    --- a/pidgin/data/pidgin.desktop.in.in Wed Oct 05 21:14:58 2016 +0200
    +++ b/pidgin/data/pidgin.desktop.in.in Wed Oct 05 15:10:29 2016 -0500
    @@ -1,7 +1,7 @@
    [Desktop Entry]
    _Name=Pidgin Internet Messenger
    _GenericName=Internet Messenger
    -_Comment=Chat over IM. Supports AIM, Google Talk, Jabber/XMPP, Yahoo and more
    +_Comment=Chat over IM. Supports AIM, Google Talk, Jabber/XMPP, and more
    Exec=pidgin
    Icon=pidgin
    StartupNotify=true
    --- a/pidgin/gtkblist.c Wed Oct 05 21:14:58 2016 +0200
    +++ b/pidgin/gtkblist.c Wed Oct 05 15:10:29 2016 -0500
    @@ -2130,7 +2130,6 @@
    char *alias = NULL;
    GList *aims = NULL;
    GList *icqs = NULL;
    - GList *yahoos = NULL;
    GList *jabbers = NULL;
    s = temp_vcard = g_strdup(vcard);
    @@ -2170,7 +2169,6 @@
    if (!strcmp(field, "FN"))
    alias = g_strdup(value);
    else if (!strcmp(field, "X-AIM") || !strcmp(field, "X-ICQ") ||
    - !strcmp(field, "X-YAHOO") ||
    !strcmp(field, "X-JABBER"))
    {
    char **values = g_strsplit(value, ":", 0);
    @@ -2182,8 +2180,6 @@
    aims = g_list_append(aims, g_strdup(*im));
    else if (!strcmp(field, "X-ICQ"))
    icqs = g_list_append(icqs, g_strdup(*im));
    - else if (!strcmp(field, "X-YAHOO"))
    - yahoos = g_list_append(yahoos, g_strdup(*im));
    else if (!strcmp(field, "X-JABBER"))
    jabbers = g_list_append(jabbers, g_strdup(*im));
    }
    @@ -2194,7 +2190,7 @@
    g_free(temp_vcard);
    - if (aims == NULL && icqs == NULL && yahoos == NULL && jabbers == NULL)
    + if (aims == NULL && icqs == NULL && jabbers == NULL)
    {
    g_free(alias);
    @@ -2203,7 +2199,6 @@
    add_buddies_from_vcard("prpl-aim", group, aims, alias);
    add_buddies_from_vcard("prpl-icq", group, icqs, alias);
    - add_buddies_from_vcard("prpl-yahoo", group, yahoos, alias);
    add_buddies_from_vcard("prpl-jabber", group, jabbers, alias);
    g_free(alias);
    --- a/pidgin/gtkwhiteboard.h Wed Oct 05 21:14:58 2016 +0200
    +++ b/pidgin/gtkwhiteboard.h Wed Oct 05 15:10:29 2016 -0500
    @@ -37,8 +37,6 @@
    #define BRUSH_STATE_DOWN 1
    #define BRUSH_STATE_MOTION 2
    -/* XXX: This seems duplicated with the Yahoo! Doodle prpl code.
    - * XXX: How should they work together? */
    #define PALETTE_NUM_COLORS 7
    /**
    --- a/pidgin/pixmaps/Makefile.am Wed Oct 05 21:14:58 2016 +0200
    +++ b/pidgin/pixmaps/Makefile.am Wed Oct 05 15:10:29 2016 -0500
    @@ -211,7 +211,6 @@
    protocols/16/scalable/meanwhile.svg \
    protocols/16/scalable/silc.svg \
    protocols/16/scalable/simple.svg \
    - protocols/16/scalable/yahoo.svg \
    protocols/16/scalable/zephyr.svg
    PROTOCOLS_16 = \
    @@ -227,7 +226,6 @@
    protocols/16/meanwhile.png \
    protocols/16/silc.png \
    protocols/16/simple.png \
    - protocols/16/yahoo.png \
    protocols/16/zephyr.png
    ICONS_16_SCALABLE = \
    @@ -262,7 +260,6 @@
    protocols/22/scalable/meanwhile.svg \
    protocols/22/scalable/silc.svg \
    protocols/22/scalable/simple.svg \
    - protocols/22/scalable/yahoo.svg \
    protocols/22/scalable/zephyr.svg
    PROTOCOLS_22 = \
    @@ -278,7 +275,6 @@
    protocols/22/meanwhile.png \
    protocols/22/silc.png \
    protocols/22/simple.png \
    - protocols/22/yahoo.png \
    protocols/22/zephyr.png
    PROTOCOLS_48 = \
    @@ -293,7 +289,6 @@
    protocols/48/meanwhile.png \
    protocols/48/silc.png \
    protocols/48/simple.png \
    - protocols/48/yahoo.png \
    protocols/48/zephyr.png
    PROTOCOLS_SCALABLE = \
    @@ -308,7 +303,6 @@
    protocols/scalable/meanwhile.svg \
    protocols/scalable/silc.svg \
    protocols/scalable/simple.svg \
    - protocols/scalable/yahoo.svg \
    protocols/scalable/zephyr.svg
    STATUS_11 = \
    --- a/pidgin/pixmaps/emotes/default/24/default.theme.in Wed Oct 05 21:14:58 2016 +0200
    +++ b/pidgin/pixmaps/emotes/default/24/default.theme.in Wed Oct 05 15:10:29 2016 -0500
    @@ -237,191 +237,6 @@
    ! cyclops.png O-) o-)
    -# Following Yahoo! Messenger 8.1
    -[Yahoo]
    -happy.png :) :-)
    -question.png :-/ :-\\
    -shocked.png :-O :O :-o :o
    -devil.png >:)
    -angel.png O:-) o:-) 0:-)
    -sick.png :-&
    -sleepy.png (:|
    -hypnotized.png @-)
    -on-the-phone.png :)]
    -sad.png :( :-(
    -amorous.png :x :-x :X :-X
    -angry.png X-( x-( X( x(
    -crying.png :((
    -glasses-nerdy.png :-B :-b
    -quiet.png :-$
    -drool.png =P~ =p~
    -lying.png :^O :^o
    -call-me.png :-c
    -wink.png ;) ;-)
    -embarrassed.png :">
    -mean.png :-> :>
    -laugh.png :)) :-))
    -bye.png =;
    -arrogant.png [-(
    -thinking.png :-?
    -waiting.png :-w :-W
    -at-wits-end.png ~x( ~X(
    -excited.png :D :-D :d :-d
    -tongue.png :-P :P :-p :p
    -glasses-cool.png B-) b-)
    -neutral.png :| :-|
    -sleeping.png I-) i-) |-)
    -clown.png :o) :O)
    -doh.png #-o #-O
    -weep.png :-<
    -go-away.png :-h
    -lashes.png ;;)
    -kiss.png :-* :*
    -confused.png :-S :-s
    -sarcastic.png /:)
    -eyeroll.png 8-|
    -silly.png 8-}
    -clap.png =D> =d>
    -mad-tongue.png >:P >:p
    -time-out.png :-t :-T
    -hug-left.png >:D< >:d<
    -love-over.png =((
    -hot.png #:-S #:-s
    -rotfl.png =)) :-j :-J
    -loser.png L-) l-)
    -party.png <:-P <:-p
    -nervous.png :-SS :-Ss :-sS :-ss
    -cowboy.png <):)
    -desire.png 8->
    -! skywalker.png C:-) c:-) C:) c:)
    -! monkey.png :-(|) :(|) 8-|)
    -! cyclops.png O-) o-)
    -
    -# Hidden Yahoo emotes
    -alien.png =:) >-)
    -beat-up.png b-( B-(
    -chicken.png ~:>
    -coffee.png ~o) ~O)
    -cow.png 3:-O 3:-o
    -dance.png \\:D/ \\:d/
    -rose.png @};-
    -dont-know.png :-L :-l
    -skeleton.png 8-X 8-x
    -lamp.png *-:)
    -monkey.png :(|)
    -coins.png $-)
    -peace.png :)>-
    -pig.png :@)
    -pray.png [-o< [-O<
    -pumpkin.png (~~)
    -shame.png [-X [-x
    -flag.png **==
    -clover.png %%-
    -musical-note.png :-"
    -giggle.png ;))
    -worship.png ^:)^
    -star.png (*)
    -waving.png >:/
    -talktohand.png :-@
    -
    -# Only available after activating the Yahoo! Fighter IMVironment
    -male-fighter1.png o-> O->
    -male-fighter2.png o=> O=>
    -female-fighter.png o-+ O-+
    -yin-yang.png (%)
    -
    -# Following Yahoo! Messenger 8.1
    -[Yahoo JAPAN]
    -happy.png :) :-)
    -question.png :-/ :-\\
    -shocked.png :-O :O :-o :o
    -devil.png >:)
    -angel.png O:-) o:-) 0:-)
    -sick.png :-&
    -sleepy.png (:|
    -hypnotized.png @-)
    -on-the-phone.png :)]
    -sad.png :( :-(
    -amorous.png :x :-x :X :-X
    -angry.png X-( x-( X( x(
    -crying.png :((
    -glasses-nerdy.png :-B :-b
    -quiet.png :-$
    -drool.png =P~ =p~
    -lying.png :^O :^o
    -call-me.png :-c
    -wink.png ;) ;-)
    -embarrassed.png :">
    -mean.png :-> :>
    -laugh.png :)) :-))
    -bye.png =;
    -arrogant.png [-(
    -thinking.png :-?
    -waiting.png :-w :-W
    -at-wits-end.png ~x( ~X(
    -excited.png :D :-D :d :-d
    -tongue.png :-P :P :-p :p
    -glasses-cool.png B-) b-)
    -neutral.png :| :-|
    -sleeping.png I-) i-) |-)
    -clown.png :o) :O)
    -doh.png #-o #-O
    -weep.png :-<
    -go-away.png :-h
    -lashes.png ;;)
    -kiss.png :-* :*
    -confused.png :-S :-s
    -sarcastic.png /:)
    -eyeroll.png 8-|
    -silly.png 8-}
    -clap.png =D> =d>
    -mad-tongue.png >:P >:p
    -time-out.png :-t :-T
    -hug-left.png >:D< >:d<
    -love-over.png =((
    -hot.png #:-S #:-s
    -rotfl.png =)) :-j :-J
    -loser.png L-) l-)
    -party.png <:-P <:-p
    -nervous.png :-SS :-Ss :-sS :-ss
    -cowboy.png <):)
    -desire.png 8->
    -! skywalker.png C:-) c:-) C:) c:)
    -! monkey.png :-(|) :(|)
    -
    -# Hidden Yahoo emotes
    -alien.png =:) >-)
    -beat-up.png b-( B-(
    -chicken.png ~:>
    -coffee.png ~o) ~O)
    -cow.png 3:-O 3:-o
    -dance.png \\:D/ \\:d/
    -rose.png @};-
    -dont-know.png :-L :-l
    -skeleton.png 8-X 8-x
    -lamp.png *-:)
    -monkey.png :(|)
    -coins.png $-)
    -peace.png :)>-
    -pig.png :@)
    -pray.png [-o< [-O<
    -pumpkin.png (~~)
    -shame.png [-X [-x
    -flag.png **==
    -clover.png %%-
    -musical-note.png :-"
    -giggle.png ;))
    -worship.png ^:)^
    -star.png (*)
    -waving.png >:/
    -talktohand.png :-@
    -
    -# Only available after activating the Yahoo! Fighter IMVironment
    -male-fighter1.png o-> O->
    -male-fighter2.png o=> O=>
    -female-fighter.png o-+ O-+
    -yin-yang.png (%)
    -
    # MXit standard emoticons
    [MXit]
    happy.png :-) :)
    --- a/pidgin/pixmaps/emotes/small/16/small.theme.in Wed Oct 05 21:14:58 2016 +0200
    +++ b/pidgin/pixmaps/emotes/small/16/small.theme.in Wed Oct 05 15:10:29 2016 -0500
    @@ -135,84 +135,6 @@
    amorous.png *IN\ LOVE*
    -# Following Yahoo! Messenger 8.1
    -[Yahoo]
    -happy.png :) :-)
    -question.png :-/ :-\\
    -shocked.png :-O :O :-o :o
    -devil.png >:)
    -angel.png O:-) o:-) 0:-)
    -sick.png :-&
    -sleepy.png (:|
    -sad.png :( :-(
    -amorous.png :x :-x :X :-X
    -angry.png X-( x-( X( x(
    -crying.png :((
    -drool.png =P~ =p~
    -lying.png :^O :^o
    -wink.png ;) ;-)
    -embarrassed.png :">
    -mean.png :-> :>
    -thinking.png :-?
    -excited.png :D :-D :d :-d
    -tongue.png :-P :P :-p :p
    -glasses-cool.png B-) b-)
    -neutral.png :| :-|
    -sleeping.png I-) i-) |-)
    -kiss.png :-* :*
    -confused.png :-S :-s
    -sarcastic.png /:)
    -eyeroll.png 8-|
    -hug-left.png >:D< >:d<
    -hot.png #:-S #:-s
    -party.png <:-P <:-p
    -nervous.png :-SS :-Ss :-sS :-ss
    -
    -# Hidden Yahoo emotes
    -coffee.png ~o) ~O)
    -rose.png @};-
    -dont-know.png :-L :-l
    -lamp.png *-:)
    -shame.png [-X [-x
    -musical-note.png :-"
    -star.png (*)
    -
    -# Following Yahoo! Messenger 8.1
    -[Yahoo JAPAN]
    -happy.png :) :-)
    -question.png :-/ :-\\
    -shocked.png :-O :O :-o :o
    -devil.png >:)
    -angel.png O:-) o:-) 0:-)
    -sick.png :-&
    -sleepy.png (:|
    -sad.png :( :-(
    -amorous.png :x :-x :X :-X
    -angry.png X-( x-( X( x(
    -crying.png :((
    -wink.png ;) ;-)
    -thinking.png :-?
    -excited.png :D :-D :d :-d
    -tongue.png :-P :P :-p :p
    -glasses-cool.png B-) b-)
    -neutral.png :| :-|
    -sleeping.png I-) i-) |-)
    -kiss.png :-* :*
    -confused.png :-S :-s
    -sarcastic.png /:)
    -eyeroll.png 8-|
    -hug-left.png >:D< >:d<
    -party.png <:-P <:-p
    -
    -# Hidden Yahoo emotes
    -coffee.png ~o) ~O)
    -rose.png @};-
    -dont-know.png :-L :-l
    -lamp.png *-:)
    -shame.png [-X [-x
    -musical-note.png :-"
    -star.png (*)
    -
    # MXit standard emoticons
    [MXit]
    happy.png :-) :)
    --- a/pidgin/pixmaps/protocols/16/scalable/yahoo.svg Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,138 +0,0 @@
    -<?xml version="1.0" encoding="UTF-8" standalone="no"?>
    -<!-- Created with Inkscape (http://www.inkscape.org/) -->
    -<svg
    - xmlns:dc="http://purl.org/dc/elements/1.1/"
    - xmlns:cc="http://creativecommons.org/ns#"
    - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    - xmlns:svg="http://www.w3.org/2000/svg"
    - xmlns="http://www.w3.org/2000/svg"
    - xmlns:xlink="http://www.w3.org/1999/xlink"
    - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
    - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
    - width="16px"
    - height="16px"
    - id="svg4248"
    - sodipodi:version="0.32"
    - inkscape:version="0.46"
    - sodipodi:docbase="/home/hbons/GUI/Tango/Gaim Refresh/protocols/16/scalable"
    - sodipodi:docname="yahoo.svg"
    - inkscape:export-filename="/home/hbons/Bureaublad/yahoo.png"
    - inkscape:export-xdpi="90"
    - inkscape:export-ydpi="90"
    - inkscape:output_extension="org.inkscape.output.svg.inkscape">
    - <defs
    - id="defs4250">
    - <inkscape:perspective
    - sodipodi:type="inkscape:persp3d"
    - inkscape:vp_x="0 : 8 : 1"
    - inkscape:vp_y="0 : 1000 : 0"
    - inkscape:vp_z="16 : 8 : 1"
    - inkscape:persp3d-origin="8 : 5.3333333 : 1"
    - id="perspective17" />
    - <linearGradient
    - id="linearGradient4123"
    - inkscape:collect="always">
    - <stop
    - id="stop4125"
    - offset="0"
    - style="stop-color:#ff0000;stop-opacity:1;" />
    - <stop
    - id="stop4127"
    - offset="1"
    - style="stop-color:#ff0000;stop-opacity:0;" />
    - </linearGradient>
    - <linearGradient
    - inkscape:collect="always"
    - xlink:href="#linearGradient4123"
    - id="linearGradient6737"
    - gradientUnits="userSpaceOnUse"
    - x1="20.181133"
    - y1="12.686874"
    - x2="20.181133"
    - y2="5.3694997" />
    - <linearGradient
    - inkscape:collect="always"
    - xlink:href="#linearGradient4123"
    - id="linearGradient6739"
    - gradientUnits="userSpaceOnUse"
    - x1="10.378018"
    - y1="18.430471"
    - x2="5.8631868"
    - y2="-0.23792659"
    - gradientTransform="matrix(0.676847,0,0,0.662872,0.3362294,0.7829564)" />
    - </defs>
    - <sodipodi:namedview
    - id="base"
    - pagecolor="#ffffff"
    - bordercolor="#666666"
    - borderopacity="1.0"
    - inkscape:pageopacity="0.0"
    - inkscape:pageshadow="2"
    - inkscape:zoom="36.060436"
    - inkscape:cx="15.360711"
    - inkscape:cy="8.3801083"
    - inkscape:current-layer="layer1"
    - showgrid="true"
    - inkscape:grid-bbox="true"
    - inkscape:document-units="px"
    - inkscape:window-width="1440"
    - inkscape:window-height="847"
    - inkscape:window-x="0"
    - inkscape:window-y="0"
    - inkscape:grid-points="false"
    - inkscape:guide-points="false"
    - gridtolerance="10"
    - inkscape:object-points="false"
    - inkscape:object-nodes="false"
    - objecttolerance="10"
    - inkscape:snap-bbox="true"
    - inkscape:snap-nodes="false">
    - <inkscape:grid
    - type="xygrid"
    - id="grid7857"
    - visible="true"
    - enabled="true" />
    - </sodipodi:namedview>
    - <metadata
    - id="metadata4253">
    - <rdf:RDF>
    - <cc:Work
    - rdf:about="">
    - <dc:format>image/svg+xml</dc:format>
    - <dc:type
    - rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
    - </cc:Work>
    - </rdf:RDF>
    - </metadata>
    - <g
    - id="layer1"
    - inkscape:label="Layer 1"
    - inkscape:groupmode="layer">
    - <path
    - style="fill:white;fill-opacity:1;stroke:none;stroke-width:1.49293232;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
    - d="M 0.24196135,4.148819 L 0.24910211,7.1529832 L 3.5563617,7.147764 L 7.6406917,12.763032 L 7.642012,14.664616 L 4.6774169,14.67713 L 4.6586789,17.695272 L 13.533193,17.684579 L 13.569765,14.669366 L 10.619662,14.679398 L 10.629019,12.755768 L 14.593143,8.6330885 L 16.51876,8.6465912 L 16.509766,5.6235735 L 12.050243,5.6188666 L 12.072495,7.7727612 L 10.847264,10.121315 L 8.9433829,10.071394 L 7.9521191,7.1118568 L 9.0229281,7.1259776 L 9.0246268,4.0988967 L 0.24196135,4.148819 z "
    - id="path6741"
    - sodipodi:nodetypes="cccccccccccccccccccccc"
    - transform="matrix(0.676847,0,0,0.662872,0.331396,0.782369)" />
    - <rect
    - style="opacity:0;fill:none;fill-opacity:1;stroke:#a40000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
    - id="rect3203"
    - width="0"
    - height="2.5118096"
    - x="6"
    - y="6.4881902"
    - transform="translate(-1.463597e-2,-4.995136)" />
    - <path
    - style="fill:url(#linearGradient6739);fill-opacity:1;stroke:#a40000;stroke-width:1.00000047999999997;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
    - d="M 6.5 3.5 L 0.5 3.53125 L 0.5 5.53125 L 2.75 5.53125 L 5.5 9.25 L 5.5 10.5 L 4.28125 10.5 C 3.3577546 10.5 3.5 11.5 3.5 11.5 L 3.5 12.5 L 6.5 12.5 L 9.5 12.5 L 9.5 11.21875 C 9.4999997 11.21875 9.4638896 10.5 8.71875 10.5 L 7.53125 10.5 L 7.53125 9.6875 L 10.21875 6.5 L 11.53125 6.5 L 11.5 4.5 L 8.5 4.5 L 8.5 5.8125 L 7.09375 7.5 L 6.65625 7.5 L 5.1875 5.5 L 6.5 5.5 L 6.5 3.5 z M 13.5 3.5 L 13.53125 9.9375 L 15.71875 3.5 L 13.5 3.5 z M 12.5 10.5 C 11.948 10.5 11.5 10.948002 11.5 11.5 C 11.5 12.051998 11.948 12.5 12.5 12.5 C 13.052 12.5 13.5 12.051998 13.5 11.5 C 13.5 10.948002 13.052001 10.5 12.5 10.5 z "
    - id="rect3219" />
    - <rect
    - style="fill:white;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
    - id="rect4115"
    - width="1"
    - height="1"
    - x="15"
    - y="12"
    - transform="matrix(0.672571,0,0,0.662714,0.148779,0.239809)" />
    - </g>
    -</svg>
    Binary file pidgin/pixmaps/protocols/16/yahoo.png has changed
    --- a/pidgin/pixmaps/protocols/22/scalable/yahoo.svg Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,154 +0,0 @@
    -<?xml version="1.0" encoding="UTF-8" standalone="no"?>
    -<!-- Created with Inkscape (http://www.inkscape.org/) -->
    -<svg
    - xmlns:dc="http://purl.org/dc/elements/1.1/"
    - xmlns:cc="http://creativecommons.org/ns#"
    - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    - xmlns:svg="http://www.w3.org/2000/svg"
    - xmlns="http://www.w3.org/2000/svg"
    - xmlns:xlink="http://www.w3.org/1999/xlink"
    - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
    - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
    - width="24"
    - height="24"
    - id="svg1307"
    - sodipodi:version="0.32"
    - inkscape:version="0.46"
    - version="1.0"
    - sodipodi:docbase="/home/hbons/GUI/Tango/Gaim Refresh/protocols/22/scalable"
    - sodipodi:docname="yahoo.svg"
    - inkscape:export-filename="/home/hbons/GUI/Tango/Gaim Refresh/protocols/22/yahoo.png"
    - inkscape:export-xdpi="90"
    - inkscape:export-ydpi="90"
    - inkscape:output_extension="org.inkscape.output.svg.inkscape">
    - <defs
    - id="defs1309">
    - <linearGradient
    - inkscape:collect="always"
    - id="linearGradient3150">
    - <stop
    - style="stop-color:#2e3436;stop-opacity:1;"
    - offset="0"
    - id="stop3152" />
    - <stop
    - style="stop-color:#2e3436;stop-opacity:0;"
    - offset="1"
    - id="stop3154" />
    - </linearGradient>
    - <radialGradient
    - inkscape:collect="always"
    - xlink:href="#linearGradient3150"
    - id="radialGradient3156"
    - cx="10.748654"
    - cy="10.457643"
    - fx="10.748654"
    - fy="10.457643"
    - r="6.6449099"
    - gradientTransform="matrix(-0.842757,5.698892e-16,-4.565819e-9,-0.35721,19.80716,14.19321)"
    - gradientUnits="userSpaceOnUse" />
    - <linearGradient
    - inkscape:collect="always"
    - id="linearGradient4123">
    - <stop
    - style="stop-color:#ff0000;stop-opacity:1;"
    - offset="0"
    - id="stop4125" />
    - <stop
    - style="stop-color:#ff0000;stop-opacity:0;"
    - offset="1"
    - id="stop4127" />
    - </linearGradient>
    - <linearGradient
    - inkscape:collect="always"
    - xlink:href="#linearGradient4123"
    - id="linearGradient4129"
    - x1="20.102123"
    - y1="10.489645"
    - x2="20.102123"
    - y2="3.0395992"
    - gradientUnits="userSpaceOnUse" />
    - <linearGradient
    - inkscape:collect="always"
    - xlink:href="#linearGradient4123"
    - id="linearGradient4131"
    - x1="9.7634506"
    - y1="11.499014"
    - x2="9.7634506"
    - y2="0.12942761"
    - gradientUnits="userSpaceOnUse" />
    - </defs>
    - <sodipodi:namedview
    - id="base"
    - pagecolor="#ffffff"
    - bordercolor="#666666"
    - borderopacity="1.0"
    - inkscape:pageopacity="0.0"
    - inkscape:pageshadow="2"
    - inkscape:zoom="29.290175"
    - inkscape:cx="18.292625"
    - inkscape:cy="12.739723"
    - inkscape:current-layer="layer1"
    - showgrid="true"
    - inkscape:grid-bbox="true"
    - inkscape:document-units="px"
    - fill="#a40000"
    - showguides="true"
    - inkscape:guide-bbox="true"
    - inkscape:window-width="1268"
    - inkscape:window-height="971"
    - inkscape:window-x="6"
    - inkscape:window-y="25" />
    - <metadata
    - id="metadata1312">
    - <rdf:RDF>
    - <cc:Work
    - rdf:about="">
    - <dc:format>image/svg+xml</dc:format>
    - <dc:type
    - rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
    - </cc:Work>
    - </rdf:RDF>
    - </metadata>
    - <g
    - id="layer1"
    - inkscape:label="Layer 1"
    - inkscape:groupmode="layer">
    - <rect
    - style="opacity:0;fill:none;fill-opacity:1;stroke:#a40000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
    - id="rect3203"
    - width="0"
    - height="2.5118096"
    - x="6"
    - y="6.4881902" />
    - <path
    - sodipodi:type="arc"
    - style="opacity:0.6;fill:url(#radialGradient3156);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
    - id="path3140"
    - sodipodi:cx="10.748654"
    - sodipodi:cy="10.457643"
    - sodipodi:rx="6.6449099"
    - sodipodi:ry="2.3675451"
    - d="M 17.393564 10.457643 A 6.6449099 2.3675451 0 1 1 4.1037445,10.457643 A 6.6449099 2.3675451 0 1 1 17.393564 10.457643 z"
    - transform="matrix(1.730648,0,0,1.300982,-7.102139,4.474929)" />
    - <path
    - style="opacity:1;fill:url(#linearGradient4131);fill-opacity:1.0;stroke:#a40000;stroke-width:0.99999958;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
    - d="M 0.49908419,5.4951356 L 0.49908419,7.5376225 L 3.3376273,7.5964463 L 8.515629,12.953307 L 8.515629,15.459996 L 5.4587364,15.459996 L 5.4587364,17.502482 L 13.56886,17.502482 L 13.56886,15.459996 L 10.463631,15.459996 L 10.463631,12.891414 L 14.972535,8.5279191 L 16.532174,8.5279191 L 16.532174,6.5473259 L 11.478943,6.5473259 L 11.478943,8.5279191 L 12.040413,8.5279191 L 9.8296564,10.446619 L 9.1979396,10.446619 L 5.9890137,7.5376225 L 9.5449908,7.5376225 L 9.5449908,5.4951356 L 0.49908419,5.4951356 z "
    - id="rect3219"
    - sodipodi:nodetypes="ccccccccccccccccccccccc" />
    - <path
    - sodipodi:type="arc"
    - style="opacity:1;fill:#ff0000;fill-opacity:1;stroke:#a40000;stroke-width:0.97808969;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
    - id="path4110"
    - sodipodi:cx="16.860584"
    - sodipodi:cy="16.429377"
    - sodipodi:rx="1.3865612"
    - sodipodi:ry="1.5252173"
    - d="M 18.247145 16.429377 A 1.3865612 1.5252173 0 1 1 15.474023,16.429377 A 1.3865612 1.5252173 0 1 1 18.247145 16.429377 z"
    - transform="matrix(1.06013,0,0,0.986015,-0.904476,0.796501)" />
    - <path
    - style="fill:url(#linearGradient4129);fill-opacity:1.0;stroke:#a40000;stroke-width:0.99999994;stroke-miterlimit:4;stroke-opacity:1"
    - d="M 18.485372,6.4981503 L 22.514636,6.4981503 L 18.576821,12.500953 L 18.485372,6.4981503 z "
    - id="rect4112"
    - sodipodi:nodetypes="cccc" />
    - </g>
    -</svg>
    Binary file pidgin/pixmaps/protocols/22/yahoo.png has changed
    Binary file pidgin/pixmaps/protocols/48/yahoo.png has changed
    --- a/pidgin/pixmaps/protocols/scalable/yahoo.svg Wed Oct 05 21:14:58 2016 +0200
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,174 +0,0 @@
    -<?xml version="1.0" encoding="UTF-8" standalone="no"?>
    -<!-- Created with Inkscape (http://www.inkscape.org/) -->
    -<svg
    - xmlns:dc="http://purl.org/dc/elements/1.1/"
    - xmlns:cc="http://creativecommons.org/ns#"
    - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    - xmlns:svg="http://www.w3.org/2000/svg"
    - xmlns="http://www.w3.org/2000/svg"
    - xmlns:xlink="http://www.w3.org/1999/xlink"
    - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
    - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
    - width="48"
    - height="48"
    - id="svg1307"
    - sodipodi:version="0.32"
    - inkscape:version="0.46"
    - version="1.0"
    - sodipodi:docbase="/home/hbons/Desktop/Gaim Refresh/protocols/48"
    - sodipodi:docname="yahoo.svg"
    - inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/protocols/48/yahoo.png"
    - inkscape:export-xdpi="90"
    - inkscape:export-ydpi="90"
    - inkscape:output_extension="org.inkscape.output.svg.inkscape">
    - <defs
    - id="defs1309">
    - <linearGradient
    - inkscape:collect="always"
    - id="linearGradient2211">
    - <stop
    - style="stop-color:#ffffff;stop-opacity:1;"
    - offset="0"
    - id="stop2213" />
    - <stop
    - style="stop-color:#ffffff;stop-opacity:0;"
    - offset="1"
    - id="stop2215" />
    - </linearGradient>
    - <linearGradient
    - inkscape:collect="always"
    - id="linearGradient3150">
    - <stop
    - style="stop-color:#2e3436;stop-opacity:1;"
    - offset="0"
    - id="stop3152" />
    - <stop
    - style="stop-color:#2e3436;stop-opacity:0;"
    - offset="1"
    - id="stop3154" />
    - </linearGradient>
    - <radialGradient
    - inkscape:collect="always"
    - xlink:href="#linearGradient3150"
    - id="radialGradient3156"
    - cx="10.748654"
    - cy="10.457643"
    - fx="10.748654"
    - fy="10.457643"
    - r="6.6449099"
    - gradientTransform="matrix(-0.842757,5.698892e-16,-4.565819e-9,-0.35721,19.80716,14.19321)"
    - gradientUnits="userSpaceOnUse" />
    - <linearGradient
    - inkscape:collect="always"
    - id="linearGradient4123">
    - <stop
    - style="stop-color:#ff0000;stop-opacity:1;"
    - offset="0"
    - id="stop4125" />
    - <stop
    - style="stop-color:#ff0000;stop-opacity:0;"
    - offset="1"
    - id="stop4127" />
    - </linearGradient>
    - <linearGradient
    - inkscape:collect="always"
    - xlink:href="#linearGradient4123"
    - id="linearGradient2206"
    - gradientUnits="userSpaceOnUse"
    - gradientTransform="matrix(1.871443,0,0,1.871443,1.990827,1.339082)"
    - x1="9.7634506"
    - y1="11.499014"
    - x2="9.7634506"
    - y2="0.12942761" />
    - <linearGradient
    - inkscape:collect="always"
    - xlink:href="#linearGradient2211"
    - id="linearGradient2217"
    - x1="36.249207"
    - y1="7.6495404"
    - x2="36.249207"
    - y2="23.063982"
    - gradientUnits="userSpaceOnUse" />
    - </defs>
    - <sodipodi:namedview
    - id="base"
    - pagecolor="#ffffff"
    - bordercolor="#666666"
    - borderopacity="1.0"
    - inkscape:pageopacity="0.0"
    - inkscape:pageshadow="2"
    - inkscape:zoom="11.098901"
    - inkscape:cx="49.54817"
    - inkscape:cy="29.700698"
    - inkscape:current-layer="layer1"
    - showgrid="true"
    - inkscape:grid-bbox="true"
    - inkscape:document-units="px"
    - fill="#a40000"
    - showguides="true"
    - inkscape:guide-bbox="true"
    - inkscape:window-width="1268"
    - inkscape:window-height="971"
    - inkscape:window-x="6"
    - inkscape:window-y="21" />
    - <metadata
    - id="metadata1312">
    - <rdf:RDF>
    - <cc:Work
    - rdf:about="">
    - <dc:format>image/svg+xml</dc:format>
    - <dc:type
    - rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
    - </cc:Work>
    - </rdf:RDF>
    - </metadata>
    - <g
    - id="layer1"
    - inkscape:label="Layer 1"
    - inkscape:groupmode="layer">
    - <rect
    - style="opacity:0;fill:none;fill-opacity:1;stroke:#a40000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
    - id="rect3203"
    - width="0"
    - height="2.5118096"
    - x="6"
    - y="6.4881902" />
    - <path
    - sodipodi:type="arc"
    - style="opacity:0.6;fill:url(#radialGradient3156);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
    - id="path3140"
    - sodipodi:cx="10.748654"
    - sodipodi:cy="10.457643"
    - sodipodi:rx="6.6449099"
    - sodipodi:ry="2.3675451"
    - d="M 17.393564 10.457643 A 6.6449099 2.3675451 0 1 1 4.1037445,10.457643 A 6.6449099 2.3675451 0 1 1 17.393564 10.457643 z"
    - transform="matrix(3.163562,0,0,2.111892,-10.02562,12.91459)" />
    - <path
    - style="opacity:1;fill:#ff0000;fill-opacity:1;stroke:#a40000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
    - d="M 36.593752,13.5 L 36.750002,24.71875 L 44.125002,13.5 L 36.593752,13.5 z M 33.406252,30.34375 C 32.052922,30.519922 31.000003,31.724054 31.000002,33.15625 C 31.000002,34.70982 32.231505,35.96875 33.750002,35.96875 C 35.268499,35.96875 36.500002,34.70982 36.500002,33.15625 C 36.500002,31.60268 35.268499,30.343751 33.750002,30.34375 C 33.631369,30.34375 33.520941,30.32882 33.406252,30.34375 z "
    - id="path4110" />
    - <path
    - sodipodi:type="inkscape:offset"
    - inkscape:radius="-1.0402364"
    - inkscape:original="M 36.59375 13.5 L 36.75 24.71875 L 44.125 13.5 L 36.59375 13.5 z M 33.40625 30.34375 C 32.052918 30.519922 31.000001 31.724054 31 33.15625 C 31 34.70982 32.231503 35.96875 33.75 35.96875 C 35.268495 35.96875 36.5 34.70982 36.5 33.15625 C 36.499998 31.60268 35.268497 30.343751 33.75 30.34375 C 33.631365 30.34375 33.520939 30.32882 33.40625 30.34375 z "
    - xlink:href="#path4110"
    - style="opacity:0.35;fill:url(#linearGradient2217);fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
    - id="path2209"
    - inkscape:href="#path4110"
    - d="M 37.625,15.0625 L 37.71875,21.875 L 42.1875,15.0625 L 37.625,15.0625 z M 33.53125,31.90625 C 32.711111,32.013013 32.031251,32.765143 32.03125,33.6875 C 32.031249,34.691344 32.806451,35.46875 33.75,35.46875 C 34.693551,35.46875 35.46875,34.691346 35.46875,33.6875 C 35.468751,32.683656 34.69355,31.906251 33.75,31.90625 C 33.544091,31.90625 33.473148,31.913814 33.53125,31.90625 z " />
    - <path
    - style="opacity:1;fill:url(#linearGradient2206);fill-opacity:1;stroke:#a40000;stroke-width:0.99999976;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
    - d="M 2.6545432,11.532816 L 4.353345,15.445312 L 7.741467,15.555398 L 17.47685,25.310159 L 17.4318,31.506326 L 12.428056,31.384739 L 11.665952,34.499424 L 27.339128,34.54589 L 26.551973,31.519888 L 21.572919,31.603085 L 21.572919,25.191498 L 28.209096,17.523843 L 31.468823,17.433744 L 32.573193,13.532585 L 23.168883,13.473142 L 21.694773,17.410562 L 23.776066,17.4644 L 19.977012,20.889333 L 13.198929,15.445312 L 17.758833,15.445312 L 20.124034,11.577865 L 2.6545432,11.532816 z "
    - id="rect3219"
    - sodipodi:nodetypes="cccccccccccccccccccccc" />
    - <path
    - sodipodi:type="inkscape:offset"
    - inkscape:radius="-0.98856229"
    - inkscape:original="M 2.65625 11.53125 L 4.34375 15.4375 L 7.75 15.5625 L 17.46875 25.3125 L 17.4375 31.5 L 12.4375 31.375 L 11.65625 34.5 L 27.34375 34.53125 L 26.5625 31.53125 L 21.5625 31.59375 L 21.5625 25.1875 L 28.21875 17.53125 L 31.46875 17.4375 L 32.5625 13.53125 L 23.15625 13.46875 L 21.6875 17.40625 L 23.78125 17.46875 L 19.96875 20.875 L 13.1875 15.4375 L 17.75 15.4375 L 20.125 11.5625 L 2.65625 11.53125 z "
    - xlink:href="#rect3219"
    - style="opacity:0.35;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.99999976;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
    - id="path2204"
    - inkscape:href="#rect3219"
    - d="M 4.15625,13.0625 L 5,15 L 7.78125,15.09375 C 8.0317447,15.110809 8.266366,15.222533 8.4375,15.40625 L 18.15625,25.15625 C 18.347286,25.335037 18.45966,25.58226 18.46875,25.84375 L 18.4375,32.03125 C 18.44087,32.30297 18.33225,32.564099 18.137167,32.75327 C 17.942084,32.942442 17.677738,33.042977 17.40625,33.03125 L 13.21875,32.9375 L 12.9375,34.03125 L 26.0625,34.0625 L 25.78125,33.0625 L 21.5625,33.125 C 21.296354,33.12807 21.040212,33.0237 20.852006,32.835494 C 20.6638,32.647288 20.55943,32.391146 20.5625,32.125 L 20.5625,25.71875 C 20.562717,25.476777 20.651667,25.243286 20.8125,25.0625 L 27.46875,17.40625 C 27.649517,17.19593 27.910308,17.071204 28.1875,17.0625 L 30.71875,17 L 31.28125,15.0625 L 23.84375,15 L 23.125,16.96875 L 23.8125,17 C 24.228223,17.002399 24.598033,17.264612 24.737859,17.656122 C 24.877684,18.047632 24.757648,18.48479 24.4375,18.75 L 20.625,22.15625 C 20.263408,22.479557 19.720674,22.492795 19.34375,22.1875 L 12.5625,16.75 C 12.215365,16.491727 12.076498,16.037735 12.219751,15.629463 C 12.363005,15.221191 12.755094,14.953499 13.1875,14.96875 L 17.1875,14.96875 L 18.34375,13.09375 L 4.15625,13.0625 z " />
    - </g>
    -</svg>
    --- a/pidgin/plugins/gevolution/add_buddy_dialog.c Wed Oct 05 21:14:58 2016 +0200
    +++ b/pidgin/plugins/gevolution/add_buddy_dialog.c Wed Oct 05 15:10:29 2016 -0500
    @@ -288,18 +288,17 @@
    {
    EContact *contact = E_CONTACT(c->data);
    const char *name;
    - GList *aims, *jabbers, *yahoos, *icqs, *novells, *ggs;
    + GList *aims, *jabbers, *icqs, *novells, *ggs;
    name = e_contact_get_const(contact, E_CONTACT_FULL_NAME);
    aims = e_contact_get(contact, E_CONTACT_IM_AIM);
    jabbers = e_contact_get(contact, E_CONTACT_IM_JABBER);
    - yahoos = e_contact_get(contact, E_CONTACT_IM_YAHOO);
    icqs = e_contact_get(contact, E_CONTACT_IM_ICQ);
    novells = e_contact_get(contact, E_CONTACT_IM_GROUPWISE);
    ggs = e_contact_get(contact, E_CONTACT_IM_GADUGADU);
    - if (aims == NULL && jabbers == NULL && yahoos == NULL &&
    + if (aims == NULL && jabbers == NULL &&
    icqs == NULL && novells == NULL && ggs == NULL)
    {
    GtkTreeIter iter;
    @@ -315,7 +314,6 @@
    {
    add_ims(dialog, contact, name, aims, "prpl-aim");
    add_ims(dialog, contact, name, jabbers, "prpl-jabber");
    - add_ims(dialog, contact, name, yahoos, "prpl-yahoo");
    add_ims(dialog, contact, name, icqs, "prpl-icq");
    add_ims(dialog, contact, name, novells, "prpl-novell");
    add_ims(dialog, contact, name, ggs, "prpl-gg");
    @@ -364,7 +362,7 @@
    {
    EContact *contact = E_CONTACT(l->data);
    const char *name;
    - GList *aims, *jabbers, *yahoos, *icqs, *novells, *ggs;
    + GList *aims, *jabbers, *icqs, *novells, *ggs;
    name = e_contact_get_const(contact, E_CONTACT_FULL_NAME);
    @@ -376,12 +374,11 @@
    aims = e_contact_get(contact, E_CONTACT_IM_AIM);
    jabbers = e_contact_get(contact, E_CONTACT_IM_JABBER);
    - yahoos = e_contact_get(contact, E_CONTACT_IM_YAHOO);
    icqs = e_contact_get(contact, E_CONTACT_IM_ICQ);
    novells = e_contact_get(contact, E_CONTACT_IM_GROUPWISE);
    ggs = e_contact_get(contact, E_CONTACT_IM_GADUGADU);
    - if (aims == NULL && jabbers == NULL && yahoos == NULL &&
    + if (aims == NULL && jabbers == NULL &&
    icqs == NULL && novells == NULL && ggs == NULL)
    {
    GtkTreeIter iter;
    @@ -397,7 +394,6 @@
    {
    add_ims(dialog, contact, name, aims, "prpl-aim");
    add_ims(dialog, contact, name, jabbers, "prpl-jabber");
    - add_ims(dialog, contact, name, yahoos, "prpl-yahoo");
    add_ims(dialog, contact, name, icqs, "prpl-icq");
    add_ims(dialog, contact, name, novells, "prpl-novell");
    add_ims(dialog, contact, name, ggs, "prpl-gg");
    --- a/pidgin/plugins/gevolution/gevo-util.c Wed Oct 05 21:14:58 2016 +0200
    +++ b/pidgin/plugins/gevolution/gevo-util.c Wed Oct 05 15:10:29 2016 -0500
    @@ -103,8 +103,6 @@
    protocol_field = E_CONTACT_IM_AIM;
    else if (!strcmp(protocol_id, "prpl-icq"))
    protocol_field = E_CONTACT_IM_ICQ;
    - else if (!strcmp(protocol_id, "prpl-yahoo"))
    - protocol_field = E_CONTACT_IM_YAHOO;
    else if (!strcmp(protocol_id, "prpl-jabber"))
    protocol_field = E_CONTACT_IM_JABBER;
    else if (!strcmp(protocol_id, "prpl-novell"))
    @@ -163,18 +161,5 @@
    g_object_unref(contact);
    }
    - if (mail == NULL)
    - {
    - PurpleAccount *account = purple_buddy_get_account(buddy);
    - const char *prpl_id = purple_account_get_protocol_id(account);
    -
    - if (!strcmp(prpl_id, "prpl-yahoo"))
    - {
    - mail = g_strdup_printf("%s@yahoo.com",
    - purple_normalize(account,
    - purple_buddy_get_name(buddy)));
    - }
    - }
    -
    return mail;
    }
    --- a/pidgin/plugins/gevolution/gevolution.c Wed Oct 05 21:14:58 2016 +0200
    +++ b/pidgin/plugins/gevolution/gevolution.c Wed Oct 05 15:10:29 2016 -0500
    @@ -121,7 +121,6 @@
    update_ims_from_contact(contact, name, "prpl-aim", E_CONTACT_IM_AIM);
    update_ims_from_contact(contact, name, "prpl-jabber", E_CONTACT_IM_JABBER);
    - update_ims_from_contact(contact, name, "prpl-yahoo", E_CONTACT_IM_YAHOO);
    update_ims_from_contact(contact, name, "prpl-icq", E_CONTACT_IM_ICQ);
    update_ims_from_contact(contact, name, "prpl-novell", E_CONTACT_IM_GROUPWISE);
    update_ims_from_contact(contact, name, "prpl-gg", E_CONTACT_IM_GADUGADU);
    --- a/pidgin/plugins/gevolution/new_person_dialog.c Wed Oct 05 21:14:58 2016 +0200
    +++ b/pidgin/plugins/gevolution/new_person_dialog.c Wed Oct 05 15:10:29 2016 -0500
    @@ -145,8 +145,6 @@
    field = E_CONTACT_IM_AIM;
    else if (!strcmp(im_service, "prpl-icq"))
    field = E_CONTACT_IM_ICQ;
    - else if (!strcmp(im_service, "prpl-yahoo"))
    - field = E_CONTACT_IM_YAHOO;
    else if (!strcmp(im_service, "prpl-jabber"))
    field = E_CONTACT_IM_JABBER;
    else if (!strcmp(im_service, "prpl-novell"))
    --- a/pidgin/win32/nsis/pidgin-installer.nsi Wed Oct 05 21:14:58 2016 +0200
    +++ b/pidgin/win32/nsis/pidgin-installer.nsi Wed Oct 05 15:10:29 2016 -0500
    @@ -388,7 +388,6 @@
    !macroend
    SectionGroup /e $(URIHANDLERSSECTIONTITLE) SecURIHandlers
    !insertmacro URI_SECTION "aim"
    - !insertmacro URI_SECTION "ymsgr"
    !insertmacro URI_SECTION "xmpp"
    SectionGroupEnd
    @@ -504,8 +503,6 @@
    ; I can't think of an easy way to maintain a list in a single place
    Push "aim"
    Call un.UnregisterURIHandler
    - Push "ymsgr"
    - Call un.UnregisterURIHandler
    Push "xmpp"
    Call un.UnregisterURIHandler
    @@ -564,8 +561,6 @@
    Delete "$INSTDIR\plugins\libsilc.dll"
    Delete "$INSTDIR\plugins\libsimple.dll"
    Delete "$INSTDIR\plugins\libtoc.dll"
    - Delete "$INSTDIR\plugins\libyahoo.dll"
    - Delete "$INSTDIR\plugins\libyahoojp.dll"
    Delete "$INSTDIR\plugins\libxmpp.dll"
    Delete "$INSTDIR\plugins\log_reader.dll"
    Delete "$INSTDIR\plugins\markerline.dll"
    --- a/po/POTFILES.in Wed Oct 05 21:14:58 2016 +0200
    +++ b/po/POTFILES.in Wed Oct 05 15:10:29 2016 -0500
    @@ -144,16 +144,6 @@
    libpurple/protocols/silc10/util.c
    libpurple/protocols/silc10/wb.c
    libpurple/protocols/simple/simple.c
    -libpurple/protocols/yahoo/libyahoo.c
    -libpurple/protocols/yahoo/libyahoojp.c
    -libpurple/protocols/yahoo/libymsg.c
    -libpurple/protocols/yahoo/yahoo_aliases.c
    -libpurple/protocols/yahoo/yahoo_doodle.c
    -libpurple/protocols/yahoo/yahoo_filexfer.c
    -libpurple/protocols/yahoo/yahoo_packet.c
    -libpurple/protocols/yahoo/yahoo_profile.c
    -libpurple/protocols/yahoo/yahoochat.c
    -libpurple/protocols/yahoo/ycht.c
    libpurple/protocols/zephyr/zephyr.c
    libpurple/proxy.c
    libpurple/prpl.c