pidgin/pidgin

Merged pidgin/main into default

2017-06-30, Arkadiy Illarionov
5f88ba22172b
Merged pidgin/main into default
  • +1 -4
    .hgignore
  • +6 -34
    ChangeLog.API
  • +0 -6
    config.h.mingw
  • +30 -138
    configure.ac
  • +0 -4
    doc/reference/libpurple/Makefile.am
  • +0 -12
    doc/reference/libpurple/libpurple-docs.xml
  • +0 -1
    doc/reference/libpurple/ui_ops.xml
  • +0 -1
    doc/reference/pidgin/Makefile.am
  • +0 -2
    doc/reference/pidgin/pidgin-docs.xml
  • +0 -99
    finch/libfinch.c
  • +1 -18
    finch/libgnt/Makefile.am
  • +0 -11
    finch/libgnt/genmarshal
  • +1 -2
    finch/libgnt/gntcheckbox.c
  • +1 -2
    finch/libgnt/gntclipboard.c
  • +1 -3
    finch/libgnt/gntcombobox.c
  • +2 -5
    finch/libgnt/gntentry.c
  • +1 -3
    finch/libgnt/gntfilesel.c
  • +1 -2
    finch/libgnt/gntmenuitem.c
  • +1 -2
    finch/libgnt/gntslider.c
  • +4 -9
    finch/libgnt/gnttree.c
  • +15 -31
    finch/libgnt/gntwidget.c
  • +2 -4
    finch/libgnt/gntwindow.c
  • +11 -23
    finch/libgnt/gntwm.c
  • +11 -51
    libpurple/Makefile.am
  • +2 -19
    libpurple/Makefile.mingw
  • +0 -555
    libpurple/cipher.c
  • +0 -421
    libpurple/cipher.h
  • +0 -725
    libpurple/ciphers/aescipher.c
  • +0 -65
    libpurple/ciphers/aescipher.h
  • +0 -524
    libpurple/ciphers/des3cipher.c
  • +0 -66
    libpurple/ciphers/des3cipher.h
  • +0 -581
    libpurple/ciphers/descipher.c
  • +0 -67
    libpurple/ciphers/descipher.h
  • +0 -311
    libpurple/ciphers/md4hash.c
  • +0 -66
    libpurple/ciphers/md4hash.h
  • +0 -392
    libpurple/ciphers/pbkdf2cipher.c
  • +0 -68
    libpurple/ciphers/pbkdf2cipher.h
  • +0 -262
    libpurple/ciphers/rc4cipher.c
  • +0 -70
    libpurple/ciphers/rc4cipher.h
  • +0 -1
    libpurple/core.c
  • +56 -81
    libpurple/eventloop.c
  • +0 -143
    libpurple/eventloop.h
  • +0 -82
    libpurple/example/nullclient.c
  • +5 -0
    libpurple/glibcompat.h
  • +0 -10
    libpurple/marshallers.list
  • +8 -17
    libpurple/media.c
  • +5 -12
    libpurple/media/backend-iface.c
  • +4 -9
    libpurple/mediamanager.c
  • +2 -12
    libpurple/plugins/Makefile.am
  • +0 -212
    libpurple/plugins/caesarcipher.c
  • +0 -67
    libpurple/plugins/caesarcipher.h
  • +0 -117
    libpurple/plugins/caesarcipher_consumer.c
  • +11 -3
    libpurple/plugins/keyrings/Makefile.am
  • +64 -51
    libpurple/plugins/keyrings/internalkeyring.c
  • +1 -15
    libpurple/protocols/facebook/Makefile.am
  • +1 -9
    libpurple/protocols/facebook/Makefile.mingw
  • +417 -89
    libpurple/protocols/facebook/api.c
  • +60 -7
    libpurple/protocols/facebook/api.h
  • +4 -0
    libpurple/protocols/facebook/data.c
  • +161 -50
    libpurple/protocols/facebook/facebook.c
  • +0 -6
    libpurple/protocols/facebook/marshaller.list
  • +22 -31
    libpurple/protocols/facebook/mqtt.c
  • +1 -2
    libpurple/protocols/jabber/tests/Makefile.am
  • +1 -2
    libpurple/protocols/oscar/tests/Makefile.am
  • +4 -2
    libpurple/protocols/simple/Makefile.am
  • +19 -15
    libpurple/protocols/simple/ntlm.c
  • +17 -3
    libpurple/protocols/simple/simple.c
  • +0 -1
    libpurple/protocols/simple/simple.h
  • +0 -1
    libpurple/purple.h.in
  • +2 -0
    libpurple/smiley-list.c
  • +1 -1
    libpurple/stun.c
  • +1 -14
    libpurple/tests/Makefile.am
  • +0 -91
    libpurple/tests/test_des.c
  • +0 -245
    libpurple/tests/test_des3.c
  • +1 -0
    libpurple/tests/test_image.c
  • +0 -107
    libpurple/tests/test_md4.c
  • +1 -0
    libpurple/tests/test_smiley.c
  • +4 -2
    libpurple/xfer.c
  • +14 -13
    pidgin/Makefile.am
  • +0 -1
    pidgin/Makefile.mingw
  • +23 -2
    pidgin/gtkdebug.c
  • +0 -6
    pidgin/gtkdialogs.c
  • +0 -124
    pidgin/gtkeventloop.c
  • +0 -46
    pidgin/gtkeventloop.h
  • +0 -414
    pidgin/gtksession.c
  • +0 -60
    pidgin/gtksession.h
  • +8 -10
    pidgin/gtkwebview.c
  • +50 -15
    pidgin/libpidgin.c
  • +6 -0
    pidgin/pidgin.gresource.xml
  • +0 -2
    po/POTFILES.in
  • --- a/.hgignore Thu Jun 15 10:48:26 2017 +0300
    +++ b/.hgignore Fri Jun 30 15:03:16 2017 +0300
    @@ -64,7 +64,6 @@
    doc/reference/.*/xml/.*
    doc/reference/.*/version.xml
    finch/finch$
    -finch/libgnt/gntmarshal.[ch]
    gtk-doc.make
    install-sh
    intltool-.*
    @@ -75,9 +74,7 @@
    libpurple/example/nullclient
    libpurple/data/purple-url-handler.desktop$
    libpurple/data/purple-url-handler.desktop.in$
    -libpurple/marshallers.[ch]
    libpurple/plugins/dbus-example-bindings.c
    -libpurple/protocols/facebook/marshal.[ch]
    libpurple/purple-client-bindings.[ch]
    libpurple/purple-client-example
    libpurple/purple.h$
    @@ -108,7 +105,7 @@
    pidgin-.*.tar.gz
    pidgin-[0-9a-z.-]+/
    pidgin.apspec$
    -pidgin/.*\.html\.h$
    +pidgin/.*\.gresource\.[ch]$
    pidgin/pidgin$
    pidgin/data/pidgin.appdata.xml$
    pidgin/data/pidgin.desktop$
    --- a/ChangeLog.API Thu Jun 15 10:48:26 2017 +0300
    +++ b/ChangeLog.API Fri Jun 30 15:03:16 2017 +0300
    @@ -23,14 +23,6 @@
    * purple_account_presence_new
    * purple_buddy_presence_new
    * purple_account_register_completed
    - * PurpleAESCipher, PurpleDESCipher, PurpleDES3Cipher, PurpleHMACCipher,
    - PurplePBKDF2Cipher and PurpleRC4Cipher inherit PurpleCipher
    - * purple_aes_cipher_new
    - * purple_des3_cipher_new
    - * purple_des_cipher_new
    - * purple_hmac_cipher_new
    - * purple_pbkdf2_cipher_new
    - * purple_rc4_cipher_new
    * purple_blist_node_is_transient
    * purple_blist_node_set_transient
    * purple_certificate_get_der_data
    @@ -55,13 +47,6 @@
    * purple_counting_node_get_*
    * purple_counting_node_change_*
    * purple_counting_node_set_*
    - * PurpleHash and purple_hash_* API
    - * PurpleMD4Hash, PurpleMD5Hash, PurpleSHA1Hash and PurpleSHA265Hash
    - inherit PurpleHash
    - * purple_md4_hash_new
    - * purple_md5_hash_new
    - * purple_sha1_hash_new
    - * purple_sha256_hash_new
    * PurpleIMConversation and PurpleChatConversation inherit
    PurpleConversation
    * purple_notify_emails_pending
    @@ -197,8 +182,6 @@
    * conversation.h has been split into conversation.h
    (PurpleConversation), conversationtypes.h (PurpleIMConversation and
    PurpleChatConversation) and conversations.h (Conversations subsystem)
    - * Files in libpurple/ciphers have been renamed. To use a particular
    - cipher, include its header.
    * Renamed ft.h file to xfer.h
    * Renamed plugin.h file to plugins.h
    * prpl.h has been split into protocol.h (PurpleProtocol GObject and
    @@ -259,9 +242,6 @@
    * Replaced 'chat-buddy' with 'chat-user' in conversation signals
    * Replaced chatname, buddyname arguments of 'chat-user-flags' (formerly
    'chat-buddy-flags') signal with PurpleChatUser *
    - * PurpleCipher split into PurpleCipher and PurpleHash, both are
    - GObjects. Please see the documentation for details.
    - * purple_cipher_context_* functions are now purple_cipher_*
    * PurpleCircBuffer changed to PurpleCircularBuffer, is now a GObject.
    Please see the documentation for details.
    * purple_circ_buffer_* functions are now purple_circular_buffer_*
    @@ -403,7 +383,6 @@
    * buddy-added and buddy-removed blist signals
    * privacy.h file
    * value.h file
    - * _PurpleCipherBatchMode
    * _PurpleCmdFlag
    * _PurpleCmdPriority
    * _PurpleCmdRet
    @@ -430,19 +409,8 @@
    purple_certificate_check_signature_chain, instead
    * purple_certificate_display_x509. Use purple_request_certificate,
    instead
    - * PurpleCipherContext
    - * purple_cipher_context_destroy
    - * purple_cipher_context_get_data
    - * purple_cipher_context_get_option
    - * purple_cipher_context_new
    - * purple_cipher_context_new_by_name
    - * purple_cipher_context_set_data
    - * purple_cipher_context_set_option
    - * purple_cipher_get_capabilities
    - * purple_cipher_get_name
    - * PurpleCipherOps
    - * purple_ciphers_*
    - * PurpleCipher's init and uninit operations
    + * Purple Cipher API (PurpleCipherContext and friends).
    + Use GLib's GHmac or GChecksum instead.
    * purple_connection_error_reason
    * purple_connection_new
    * purple_connection_new_unregister
    @@ -453,6 +421,10 @@
    * PurpleConversationType
    * purple_core_migrate
    * purple_dnsquery_a_account
    + * purple_event_loop_{get|set}_ui_ops. Manually drive the GLib
    + event loop yourself. See GLib Main Event Loop docs.
    + * PurpleEventLoopUiOps. Manually drive the GLib event loop
    + yourself. See GLib Main Event Loop docs.
    * purple_network_listen_family. Use purple_network_listen, instead.
    * purple_network_listen_map_external
    * purple_network_listen_range_family. Use purple_network_listen,
    --- a/config.h.mingw Thu Jun 15 10:48:26 2017 +0300
    +++ b/config.h.mingw Fri Jun 30 15:03:16 2017 +0300
    @@ -287,9 +287,6 @@
    /* Define to 1 if you have X11 */
    /* #define HAVE_X11 1 */
    -/* Define to 1 if you have the <X11/SM/SMlib.h> header file. */
    -/* #define HAVE_X11_SM_SMLIB_H 1 */
    -
    /* whether or not we have xsltproc for devhelp index */
    /* #define HAVE_XSLTPROC 1 */
    @@ -360,9 +357,6 @@
    /* Define if we're using XScreenSaver. */
    #define USE_SCREENSAVER 1
    -/* Define if we're using X Session Management. */
    -/* #define USE_SM 1 */
    -
    /* Use voice and video */
    /* #define USE_VV 1 */
    --- a/configure.ac Thu Jun 15 10:48:26 2017 +0300
    +++ b/configure.ac Fri Jun 30 15:03:16 2017 +0300
    @@ -109,7 +109,6 @@
    AC_SUBST(GNT_LT_VERSION_INFO)
    AC_PATH_PROG(sedpath, sed)
    -AC_PATH_PROG(xxdpath, xxd)
    dnl Storing configure arguments
    AC_DEFINE_UNQUOTED(CONFIG_ARGS, "$ac_configure_args", [configure arguments])
    @@ -488,6 +487,8 @@
    GLIB_MKENUMS=`$PKG_CONFIG --variable=glib_mkenums glib-2.0`
    AC_SUBST(GLIB_MKENUMS)
    +AC_PATH_PROG(GLIB_COMPILE_RESOURCES, [glib-compile-resources])
    +
    AC_PATH_PROG(GTESTER, gtester)
    GLIB_TESTS
    @@ -522,10 +523,6 @@
    [AS_HELP_STRING([--disable-screensaver],
    [compile without X screensaver extension (used to detect idleness)])],
    enable_screensaver="$enableval", enable_screensaver="yes")
    -AC_ARG_ENABLE(sm,
    - [AS_HELP_STRING([--disable-sm],
    - [compile without X session management support])],
    - enable_sm="$enableval", enable_sm="yes")
    AC_ARG_ENABLE(startup-notification,
    [AS_HELP_STRING([--disable-startup-notification],
    [compile without startup notification support])],
    @@ -644,7 +641,6 @@
    AC_SUBST(X11_CFLAGS)
    else
    enable_screensaver=no
    - enable_sm=no
    enable_gestures=no
    fi
    @@ -690,36 +686,6 @@
    fi
    dnl #######################################################################
    - dnl # Check for X session management libs
    - dnl #######################################################################
    - if test "x$enable_sm" = "xyes"; then
    - if test "x$with_x" = "xyes" ; then
    - enable_sm=no
    - AC_CHECK_LIB(SM, SmcSaveYourselfDone, found_sm_lib=true, , [$x_libpath_add -lICE])
    - if test "x$found_sm_lib" = "xtrue"; then
    - oldCPPFLAGS="$CPPFLAGS"
    - CPPFLAGS="$CPPFLAGS $x_incpath_add"
    - AC_CHECK_HEADERS(X11/SM/SMlib.h, SM_LIBS="$x_libpath_add -lSM -lICE" enable_sm=yes)
    - CPPFLAGS="$oldCPPFLAGS"
    - fi
    -
    - if test "x$enable_sm" = "xyes"; then
    - AC_DEFINE(USE_SM, 1, [Define if we're using X Session Management.])
    - AC_SUBST(SM_LIBS)
    - else
    - if test "x$force_deps" = "xyes" ; then
    - AC_MSG_ERROR([
    -X session management development headers not found.
    -Use --disable-sm if you do not need session management support.
    -])
    - fi
    - fi
    - else
    - AC_MSG_ERROR([X support is required to build with X session management support])
    - fi
    - fi
    -
    - dnl #######################################################################
    dnl # Check for X11 to allow the gestures plugin
    dnl #######################################################################
    if test "x$enable_gestures" = "xyes"; then
    @@ -787,7 +753,6 @@
    enable_cap=no
    enable_gevolution=no
    enable_screensaver=no
    - enable_sm=no
    enable_startup_notification=no
    fi # GTK
    @@ -1865,105 +1830,6 @@
    fi
    AM_CONDITIONAL(INSTALL_SSL_CERTIFICATES, test "x$SSL_CERTIFICATES_DIR" = "x")
    -dnl These two are inverses of each other <-- stolen from evolution!
    -
    -AC_ARG_ENABLE(gnutls,
    - [ --enable-gnutls=[yes,no] attempt to use GnuTLS for SSL support [default=yes]],
    - [enable_gnutls="$enableval"],
    - [enable_gnutls="yes"])
    -
    -AC_ARG_ENABLE(nss,
    - [ --enable-nss=[yes,no,static] attempt to use Mozilla libnss for SSL support [default=yes]],
    - [enable_nss="$enableval"],
    - [enable_nss="yes"])
    -
    -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 isn't disabled
    -dnl #
    -if test "x$enable_gnutls" != "xno"; then
    - looked_for_gnutls="yes"
    -
    - if `$PKG_CONFIG --exists gnutls`; then
    - dnl # minimum required version should almost certainly be higher
    - PKG_CHECK_MODULES(GNUTLS, [gnutls >= 2.10], [
    - have_gnutls="yes"
    - ], [
    - AC_MSG_RESULT(no)
    - have_gnutls="no"
    - ])
    - fi
    -
    - if test "x$have_gnutls" = "xyes"; then
    - AC_DEFINE(HAVE_GNUTLS, 1, [Define if you have GnuTLS])
    - msg_gnutls="GnuTLS"
    - fi
    -fi
    -
    -AM_CONDITIONAL(USE_GNUTLS, test "x$have_gnutls" = "xyes")
    -
    -
    -dnl #
    -dnl # Check for NSS if it isn't disabled
    -dnl #
    -looked_for_nss="no"
    -if test "x$enable_nss" != "xno"; then
    - looked_for_nss="yes"
    -
    - if `$PKG_CONFIG --exists mozilla-nss`; then
    - dnl # TODO: set required minimum version
    - PKG_CHECK_MODULES(NSS, mozilla-nss, [
    - have_nss="yes"
    - ], [
    - AC_MSG_RESULT(no)
    - have_nss="no"
    - ])
    - elif `$PKG_CONFIG --exists nss`; then
    - dnl # TODO: set required minimum version
    - PKG_CHECK_MODULES(NSS, nss, [
    - have_nss="yes"
    - ], [
    - AC_MSG_RESULT(no)
    - have_nss="no"
    - ])
    - fi
    -
    - if test "x$have_nss" = "xyes"; then
    - AC_DEFINE(HAVE_NSS, 1, [Define if you have Mozilla NSS])
    - msg_nss="Mozilla NSS"
    - fi
    -fi
    -
    -AM_CONDITIONAL(USE_NSS, test "x$have_nss" = "xyes")
    -
    -
    -if test "x$msg_nss" != "x" -a "x$msg_gnutls" != "x"; then
    - msg_ssl="$msg_nss and $msg_gnutls"
    -elif test "x$msg_nss" != "x"; then
    - msg_ssl=$msg_nss
    -elif test "x$msg_gnutls" != "x"; then
    - msg_ssl=$msg_gnutls
    -elif test "x$looked_for_gnutls" = "xyes" -a "x$looked_for_nss" = "xyes" -a "x$force_deps" = "xyes" ; then
    - AC_MSG_ERROR([
    -Neither GnuTLS or NSS SSL development headers found.
    -Use --disable-nss --disable-gnutls if you do not need SSL support.
    -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.
    -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.
    -Novell Groupwise and Google Talk will not work without SSL support.
    -])
    -fi
    -
    if test "$ac_cv_cygwin" = yes ; then
    LDADD="$LDADD -static"
    AC_DEFINE(DEBUG, 1, [Define if debugging is enabled.])
    @@ -1985,6 +1851,33 @@
    AC_SUBST(PLUGINS_DEFINE)
    dnl #######################################################################
    +dnl # Check for Nettle (Crypto Library)
    +dnl #######################################################################
    +AC_ARG_ENABLE(nettle,
    + [AC_HELP_STRING([--disable-nettle], [disable Nettle support])],
    + enable_nettle="$enableval", enable_nettle="yes")
    +
    +if test "x$enable_nettle" = "xyes" ; then
    + PKG_CHECK_MODULES(NETTLE, [nettle >= 3.0], [
    + enable_nettle="yes"
    + AC_SUBST(NETTLE_CFLAGS)
    + AC_SUBST(NETTLE_LIBS)
    + AC_DEFINE(HAVE_NETTLE, 1, [Define if we have Nettle.])
    + ], [
    + enable_nettle="no"
    + ])
    +
    + if test "x$enable_nettle" != "xyes" -a "x$force_deps" = "xyes" ; then
    + AC_MSG_ERROR([
    +Nettle development headers not found
    +Use --disable-nettle if you do not need it.
    +])
    + fi
    +fi
    +
    +AM_CONDITIONAL(ENABLE_NETTLE, test "x$enable_nettle" = "xyes")
    +
    +dnl #######################################################################
    dnl # Check for Cyrus-SASL (for xmpp/irc)
    dnl #######################################################################
    dnl AC_CHECK_SIZEOF(short)
    @@ -2230,10 +2123,10 @@
    eval eval echo D-Bus services directory...... : $DBUS_SERVICES_DIR
    fi
    echo Build with GNU Libidn......... : $enable_idn
    -echo SSL Library/Libraries......... : $msg_ssl
    if test "x$SSL_CERTIFICATES_DIR" != "x" ; then
    eval eval echo SSL CA certificates directory. : $SSL_CERTIFICATES_DIR
    fi
    +echo Build with Nettle support..... : $enable_nettle
    echo Build with Cyrus SASL support. : $enable_cyrus_sasl
    echo Use kerberos 4 with zephyr.... : $kerberos
    echo Use external libzephyr........ : $zephyr
    @@ -2243,7 +2136,6 @@
    echo Has you....................... : yes
    echo
    echo Use XScreenSaver Extension.... : $enable_screensaver
    -echo Use X Session Management...... : $enable_sm
    echo Use startup notification...... : $enable_startup_notification
    echo Build with Enchant support.... : $use_enchant
    echo Build with GCR widgets........ : $enable_gcr
    --- a/doc/reference/libpurple/Makefile.am Thu Jun 15 10:48:26 2017 +0300
    +++ b/doc/reference/libpurple/Makefile.am Fri Jun 30 15:03:16 2017 +0300
    @@ -135,8 +135,6 @@
    $(IDN_CFLAGS) \
    $(NETWORKMANAGER_CFLAGS) \
    $(JSON_CFLAGS) \
    - $(GNUTLS_CFLAGS) \
    - $(NSS_CFLAGS) \
    $(ZLIB_CFLAGS) \
    $(INTROSPECTION_CFLAGS)
    @@ -155,8 +153,6 @@
    $(GSTINTERFACES_LIBS) \
    $(IDN_LIBS) \
    $(JSON_LIBS) \
    - $(GNUTLS_LIBS) \
    - $(NSS_LIBS) \
    $(ZLIB_LIBS) \
    $(INTROSPECTION_LIBS) \
    -lm
    --- a/doc/reference/libpurple/libpurple-docs.xml Thu Jun 15 10:48:26 2017 +0300
    +++ b/doc/reference/libpurple/libpurple-docs.xml Fri Jun 30 15:03:16 2017 +0300
    @@ -38,7 +38,6 @@
    <xi:include href="xml/pounce.xml" />
    <xi:include href="xml/chat.xml" />
    <xi:include href="xml/circularbuffer.xml" />
    - <xi:include href="xml/cipher.xml" />
    <xi:include href="xml/contact.xml" />
    <xi:include href="xml/connection.xml" />
    <xi:include href="xml/conversation.xml" />
    @@ -104,17 +103,6 @@
    <xi:include href="xml/cmds.xml" />
    </chapter>
    - <chapter id="ciphers">
    - <title>Ciphers and Hashes</title>
    -
    - <xi:include href="xml/aescipher.xml" />
    - <xi:include href="xml/descipher.xml" />
    - <xi:include href="xml/des3cipher.xml" />
    - <xi:include href="xml/pbkdf2cipher.xml" />
    - <xi:include href="xml/rc4cipher.xml" />
    - <xi:include href="xml/md4hash.xml" />
    - </chapter>
    -
    <chapter id="smiley">
    <title>Smiley APIs</title>
    --- a/doc/reference/libpurple/ui_ops.xml Thu Jun 15 10:48:26 2017 +0300
    +++ b/doc/reference/libpurple/ui_ops.xml Fri Jun 30 15:03:16 2017 +0300
    @@ -17,7 +17,6 @@
    <listitem><link linkend="PurpleCoreUiOps"><literal>PurpleCoreUiOps</literal></link></listitem>
    <listitem><link linkend="PurpleDebugUiOps"><literal>PurpleDebugUiOps</literal></link></listitem>
    <listitem><link linkend="PurpleDnsQueryUiOps"><literal>PurpleDnsQueryUiOps</literal></link></listitem>
    -<listitem><link linkend="PurpleEventLoopUiOps"><literal>PurpleEventLoopUiOps</literal></link> (without this, nothing will work and you will cry)</listitem>
    <listitem><link linkend="PurpleIdleUiOps"><literal>PurpleIdleUiOps</literal></link></listitem>
    <listitem><link linkend="PurpleNotifyUiOps"><literal>PurpleNotifyUiOps</literal></link></listitem>
    <listitem><link linkend="PurpleRequestUiOps"><literal>PurpleRequestUiOps</literal></link></listitem>
    --- a/doc/reference/pidgin/Makefile.am Thu Jun 15 10:48:26 2017 +0300
    +++ b/doc/reference/pidgin/Makefile.am Fri Jun 30 15:03:16 2017 +0300
    @@ -120,7 +120,6 @@
    $(GSTVIDEO_LIBS) \
    $(GSTINTERFACES_LIBS) \
    $(XSS_LIBS) \
    - $(SM_LIBS) \
    $(INTLLIBS) \
    $(LIBXML_LIBS) \
    $(WEBKIT_LIBS) \
    --- a/doc/reference/pidgin/pidgin-docs.xml Thu Jun 15 10:48:26 2017 +0300
    +++ b/doc/reference/pidgin/pidgin-docs.xml Fri Jun 30 15:03:16 2017 +0300
    @@ -35,7 +35,6 @@
    <xi:include href="xml/gtkdebug.xml" />
    <xi:include href="xml/gtkdocklet.xml" />
    <xi:include href="xml/gtkdnd-hints.xml" />
    - <xi:include href="xml/gtkeventloop.xml" />
    <xi:include href="xml/gtkxfer.xml" />
    <xi:include href="xml/gtkicon-theme.xml" />
    <xi:include href="xml/gtkidle.xml" />
    @@ -65,7 +64,6 @@
    <xi:include href="xml/gtkwebview.xml" />
    <xi:include href="xml/gtkwebviewtoolbar.xml" />
    <xi:include href="xml/gtkwhiteboard.xml" />
    - <xi:include href="xml/gtksession.xml" />
    <xi:include href="xml/pidgin.xml" />
    </part>
    --- a/finch/libfinch.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/finch/libfinch.c Fri Jun 30 15:03:16 2017 +0300
    @@ -26,7 +26,6 @@
    #include "conversation.h"
    #include "core.h"
    #include "debug.h"
    -#include "eventloop.h"
    #include "glibcompat.h"
    #include "log.h"
    #include "notify.h"
    @@ -134,103 +133,6 @@
    return &core_ops;
    }
    -/* Anything IO-related is directly copied from gtkpurple's source tree */
    -
    -#define FINCH_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR)
    -#define FINCH_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL)
    -
    -typedef struct _PurpleGntIOClosure {
    - PurpleInputFunction function;
    - guint result;
    - gpointer data;
    -
    -} PurpleGntIOClosure;
    -
    -static void purple_gnt_io_destroy(gpointer data)
    -{
    - g_free(data);
    -}
    -
    -static gboolean purple_gnt_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data)
    -{
    - PurpleGntIOClosure *closure = data;
    - PurpleInputCondition purple_cond = 0;
    -
    - if (condition & FINCH_READ_COND)
    - purple_cond |= PURPLE_INPUT_READ;
    - if (condition & FINCH_WRITE_COND)
    - purple_cond |= PURPLE_INPUT_WRITE;
    -
    -#if 0
    - purple_debug(PURPLE_DEBUG_MISC, "gtk_eventloop",
    - "CLOSURE: callback for %d, fd is %d\n",
    - closure->result, g_io_channel_unix_get_fd(source));
    -#endif
    -
    -#ifdef _WIN32
    - if(! purple_cond) {
    -#if 0
    - purple_debug_misc("gnt_eventloop",
    - "CLOSURE received GIOCondition of 0x%x, which does not"
    - " match 0x%x (READ) or 0x%x (WRITE)\n",
    - condition, FINCH_READ_COND, FINCH_WRITE_COND);
    -#endif /* DEBUG */
    -
    - return TRUE;
    - }
    -#endif /* _WIN32 */
    -
    - closure->function(closure->data, g_io_channel_unix_get_fd(source),
    - purple_cond);
    -
    - return TRUE;
    -}
    -
    -static guint gnt_input_add(gint fd, PurpleInputCondition condition, PurpleInputFunction function,
    - gpointer data)
    -{
    - PurpleGntIOClosure *closure = g_new0(PurpleGntIOClosure, 1);
    - GIOChannel *channel;
    - GIOCondition cond = 0;
    -
    - closure->function = function;
    - closure->data = data;
    -
    - if (condition & PURPLE_INPUT_READ)
    - cond |= FINCH_READ_COND;
    - if (condition & PURPLE_INPUT_WRITE)
    - cond |= FINCH_WRITE_COND;
    -
    - channel = g_io_channel_unix_new(fd);
    - closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond,
    - purple_gnt_io_invoke, closure, purple_gnt_io_destroy);
    -
    - g_io_channel_unref(channel);
    - return closure->result;
    -}
    -
    -static PurpleEventLoopUiOps eventloop_ops =
    -{
    - g_timeout_add,
    - g_source_remove,
    - gnt_input_add,
    - g_source_remove,
    - NULL, /* input_get_error */
    - g_timeout_add_seconds,
    -
    - /* padding */
    - NULL,
    - NULL,
    - NULL,
    - NULL
    -};
    -
    -static PurpleEventLoopUiOps *
    -gnt_eventloop_get_ui_ops(void)
    -{
    - return &eventloop_ops;
    -}
    -
    /* This is mostly copied from gtkpurple's source tree */
    static void
    show_usage(const char *name, gboolean terse)
    @@ -348,7 +250,6 @@
    purple_debug_set_enabled(debug_enabled);
    purple_core_set_ui_ops(gnt_core_get_ui_ops());
    - purple_eventloop_set_ui_ops(gnt_eventloop_get_ui_ops());
    purple_idle_set_ui_ops(finch_idle_get_ui_ops());
    if (!purple_core_init(FINCH_UI))
    --- a/finch/libgnt/Makefile.am Thu Jun 15 10:48:26 2017 +0300
    +++ b/finch/libgnt/Makefile.am Fri Jun 30 15:03:16 2017 +0300
    @@ -1,5 +1,3 @@
    -EXTRA_DIST=genmarshal
    -
    SUBDIRS = . wms
    pkgconfigdir = $(libdir)/pkgconfig
    pkgconfig_DATA = gnt.pc
    @@ -8,10 +6,7 @@
    noinst_HEADERS = gntinternal.h
    -BUILT_SOURCES = gntmarshal.h
    -
    libgnt_la_SOURCES = \
    - gntmarshal.c \
    gntwidget.c \
    gntbindable.c \
    gntbox.c \
    @@ -53,7 +48,6 @@
    gntkeys.h \
    gntlabel.h \
    gntline.h \
    - gntmarshal.h \
    gntmenu.h \
    gntmenuitem.h \
    gntmenuitemcheck.h \
    @@ -68,17 +62,6 @@
    gntws.h \
    gnt.h
    -CLEANFILES = \
    - gntmarshal.h \
    - gntmarshal.c
    -
    -gntmarshal.c: $(srcdir)/genmarshal gntmarshal.h
    - $(AM_V_GEN)echo "#include \"gntmarshal.h\"" > $@
    - $(AM_V_at)glib-genmarshal --prefix=gnt_closure_marshal --body $(srcdir)/genmarshal >> $@
    -
    -gntmarshal.h: $(srcdir)/genmarshal
    - $(AM_V_GEN)glib-genmarshal --prefix=gnt_closure_marshal --header $(srcdir)/genmarshal > $@
    -
    libgnt_laincludedir=$(includedir)/gnt
    libgnt_lainclude_HEADERS = \
    $(libgnt_la_headers)
    @@ -147,5 +130,5 @@
    $(INTROSPECTION_TYPELIBDIR)
    typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
    -CLEANFILES += $(gir_DATA) $(typelib_DATA)
    +CLEANFILES = $(gir_DATA) $(typelib_DATA)
    endif
    --- a/finch/libgnt/genmarshal Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,11 +0,0 @@
    -BOOLEAN:VOID
    -BOOLEAN:STRING
    -VOID:INT,INT,INT,INT
    -VOID:INT,INT
    -VOID:POINTER,POINTER
    -BOOLEAN:INT,INT
    -BOOLEAN:INT,INT,INT
    -BOOLEAN:POINTER,POINTER,POINTER
    -BOOLEAN:INT,INT,INT,POINTER
    -VOID:STRING,STRING
    -VOID:POINTER,BOOLEAN
    --- a/finch/libgnt/gntcheckbox.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/finch/libgnt/gntcheckbox.c Fri Jun 30 15:03:16 2017 +0300
    @@ -105,8 +105,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntCheckBoxClass, toggled),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__VOID,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 0);
    GNTDEBUG;
    }
    --- a/finch/libgnt/gntclipboard.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/finch/libgnt/gntclipboard.c Fri Jun 30 15:03:16 2017 +0300
    @@ -37,8 +37,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    0,
    - NULL, NULL,
    - g_cclosure_marshal_VOID__POINTER,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 1, G_TYPE_POINTER);
    }
    --- a/finch/libgnt/gntcombobox.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/finch/libgnt/gntcombobox.c Fri Jun 30 15:03:16 2017 +0300
    @@ -24,7 +24,6 @@
    #include "gntbox.h"
    #include "gntcombobox.h"
    #include "gnttree.h"
    -#include "gntmarshal.h"
    #include "gntstyle.h"
    #include "gntutils.h"
    @@ -283,8 +282,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    0,
    - NULL, NULL,
    - gnt_closure_marshal_VOID__POINTER_POINTER,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
    gnt_bindable_class_register_action(bindable, "dropdown", dropdown_menu,
    --- a/finch/libgnt/gntentry.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/finch/libgnt/gntentry.c Fri Jun 30 15:03:16 2017 +0300
    @@ -26,7 +26,6 @@
    #include "gntinternal.h"
    #include "gntbox.h"
    #include "gntentry.h"
    -#include "gntmarshal.h"
    #include "gntstyle.h"
    #include "gnttree.h"
    #include "gntutils.h"
    @@ -951,16 +950,14 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntEntryClass, text_changed),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__VOID,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 0);
    signals[SIG_COMPLETION] =
    g_signal_new("completion",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    - 0, NULL, NULL,
    - gnt_closure_marshal_VOID__POINTER_POINTER,
    + 0, NULL, NULL, NULL,
    G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
    gnt_bindable_class_register_action(bindable, "cursor-home", move_start,
    --- a/finch/libgnt/gntfilesel.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/finch/libgnt/gntfilesel.c Fri Jun 30 15:03:16 2017 +0300
    @@ -28,7 +28,6 @@
    #include "gntentry.h"
    #include "gntfilesel.h"
    #include "gntlabel.h"
    -#include "gntmarshal.h"
    #include "gntstyle.h"
    #include "gnttree.h"
    @@ -506,8 +505,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntFileSelClass, file_selected),
    - NULL, NULL,
    - gnt_closure_marshal_VOID__STRING_STRING,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
    gnt_bindable_class_register_action(bindable, "toggle-tag", toggle_tag_selection, "t", NULL);
    --- a/finch/libgnt/gntmenuitem.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/finch/libgnt/gntmenuitem.c Fri Jun 30 15:03:16 2017 +0300
    @@ -57,8 +57,7 @@
    g_signal_new("activate",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    - 0, NULL, NULL,
    - g_cclosure_marshal_VOID__VOID,
    + 0, NULL, NULL, NULL,
    G_TYPE_NONE, 0);
    }
    --- a/finch/libgnt/gntslider.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/finch/libgnt/gntslider.c Fri Jun 30 15:03:16 2017 +0300
    @@ -202,8 +202,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntSliderClass, changed),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__INT,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 1, G_TYPE_INT);
    gnt_bindable_class_register_action(bindable, "step-backward", step_back, GNT_KEY_LEFT, NULL);
    --- a/finch/libgnt/gnttree.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/finch/libgnt/gnttree.c Fri Jun 30 15:03:16 2017 +0300
    @@ -21,7 +21,6 @@
    */
    #include "gntinternal.h"
    -#include "gntmarshal.h"
    #include "gntstyle.h"
    #include "gnttree.h"
    #include "gntutils.h"
    @@ -1072,32 +1071,28 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntTreeClass, selection_changed),
    - NULL, NULL,
    - gnt_closure_marshal_VOID__POINTER_POINTER,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
    signals[SIG_SCROLLED] =
    g_signal_new("scrolled",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    0,
    - NULL, NULL,
    - g_cclosure_marshal_VOID__INT,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 1, G_TYPE_INT);
    signals[SIG_TOGGLED] =
    g_signal_new("toggled",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntTreeClass, toggled),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__POINTER,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 1, G_TYPE_POINTER);
    signals[SIG_COLLAPSED] =
    g_signal_new("collapse-toggled",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    0,
    - NULL, NULL,
    - gnt_closure_marshal_VOID__POINTER_BOOLEAN,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_BOOLEAN);
    gnt_bindable_class_register_action(bindable, "move-up", action_up,
    --- a/finch/libgnt/gntwidget.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/finch/libgnt/gntwidget.c Fri Jun 30 15:03:16 2017 +0300
    @@ -25,7 +25,6 @@
    #include "gntinternal.h"
    #include "gntwidget.h"
    #include "gntstyle.h"
    -#include "gntmarshal.h"
    #include "gntutils.h"
    enum
    @@ -135,104 +134,91 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWidgetClass, destroy),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__VOID,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 0);
    signals[SIG_GIVE_FOCUS] =
    g_signal_new("gained-focus",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWidgetClass, gained_focus),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__VOID,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 0);
    signals[SIG_LOST_FOCUS] =
    g_signal_new("lost-focus",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWidgetClass, lost_focus),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__VOID,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 0);
    signals[SIG_ACTIVATE] =
    g_signal_new("activate",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWidgetClass, activate),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__VOID,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 0);
    signals[SIG_MAP] =
    g_signal_new("map",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWidgetClass, map),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__VOID,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 0);
    signals[SIG_DRAW] =
    g_signal_new("draw",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWidgetClass, draw),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__VOID,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 0);
    signals[SIG_HIDE] =
    g_signal_new("hide",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWidgetClass, hide),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__VOID,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 0);
    signals[SIG_EXPOSE] =
    g_signal_new("expose",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWidgetClass, expose),
    - NULL, NULL,
    - gnt_closure_marshal_VOID__INT_INT_INT_INT,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 4, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
    signals[SIG_POSITION] =
    g_signal_new("position-set",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWidgetClass, set_position),
    - NULL, NULL,
    - gnt_closure_marshal_VOID__INT_INT,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
    signals[SIG_SIZE_REQUEST] =
    g_signal_new("size_request",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWidgetClass, size_request),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__VOID,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 0);
    signals[SIG_SIZE_CHANGED] =
    g_signal_new("size_changed",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWidgetClass, size_changed),
    - NULL, NULL,
    - gnt_closure_marshal_VOID__INT_INT,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
    signals[SIG_CONFIRM_SIZE] =
    g_signal_new("confirm_size",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWidgetClass, confirm_size),
    - NULL, NULL,
    - gnt_closure_marshal_BOOLEAN__INT_INT,
    + NULL, NULL, NULL,
    G_TYPE_BOOLEAN, 2, G_TYPE_INT, G_TYPE_INT);
    signals[SIG_KEY_PRESSED] =
    g_signal_new("key_pressed",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWidgetClass, key_pressed),
    - gnt_boolean_handled_accumulator, NULL,
    - gnt_closure_marshal_BOOLEAN__STRING,
    + gnt_boolean_handled_accumulator, NULL, NULL,
    G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
    signals[SIG_CLICKED] =
    @@ -240,8 +226,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWidgetClass, clicked),
    - gnt_boolean_handled_accumulator, NULL,
    - gnt_closure_marshal_BOOLEAN__INT_INT_INT,
    + gnt_boolean_handled_accumulator, NULL, NULL,
    G_TYPE_BOOLEAN, 3, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
    signals[SIG_CONTEXT_MENU] =
    @@ -249,8 +234,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    0,
    - gnt_boolean_handled_accumulator, NULL,
    - gnt_closure_marshal_BOOLEAN__VOID,
    + gnt_boolean_handled_accumulator, NULL, NULL,
    G_TYPE_BOOLEAN, 0);
    /* This is relevant for all widgets */
    --- a/finch/libgnt/gntwindow.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/finch/libgnt/gntwindow.c Fri Jun 30 15:03:16 2017 +0300
    @@ -94,8 +94,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    0,
    - NULL, NULL,
    - g_cclosure_marshal_VOID__VOID,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 0);
    signals[SIG_WORKSPACE_SHOW] =
    @@ -103,8 +102,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    0,
    - NULL, NULL,
    - g_cclosure_marshal_VOID__VOID,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 0);
    gnt_bindable_class_register_action(bindable, "show-menu", show_menu,
    --- a/finch/libgnt/gntwm.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/finch/libgnt/gntwm.c Fri Jun 30 15:03:16 2017 +0300
    @@ -50,7 +50,6 @@
    #include "gntwm.h"
    #include "gntstyle.h"
    -#include "gntmarshal.h"
    #include "gnt.h"
    #include "gntbox.h"
    #include "gntbutton.h"
    @@ -1421,32 +1420,28 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWMClass, new_window),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__POINTER,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 1, G_TYPE_POINTER);
    signals[SIG_DECORATE_WIN] =
    g_signal_new("decorate_win",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWMClass, decorate_window),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__POINTER,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 1, G_TYPE_POINTER);
    signals[SIG_CLOSE_WIN] =
    g_signal_new("close_win",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWMClass, close_window),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__POINTER,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 1, G_TYPE_POINTER);
    signals[SIG_CONFIRM_RESIZE] =
    g_signal_new("confirm_resize",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWMClass, window_resize_confirm),
    - gnt_boolean_handled_accumulator, NULL,
    - gnt_closure_marshal_BOOLEAN__POINTER_POINTER_POINTER,
    + gnt_boolean_handled_accumulator, NULL, NULL,
    G_TYPE_BOOLEAN, 3, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER);
    signals[SIG_CONFIRM_MOVE] =
    @@ -1454,8 +1449,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWMClass, window_move_confirm),
    - gnt_boolean_handled_accumulator, NULL,
    - gnt_closure_marshal_BOOLEAN__POINTER_POINTER_POINTER,
    + gnt_boolean_handled_accumulator, NULL, NULL,
    G_TYPE_BOOLEAN, 3, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER);
    signals[SIG_RESIZED] =
    @@ -1463,24 +1457,21 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWMClass, window_resized),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__POINTER,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 1, G_TYPE_POINTER);
    signals[SIG_MOVED] =
    g_signal_new("window_moved",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWMClass, window_moved),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__POINTER,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 1, G_TYPE_POINTER);
    signals[SIG_UPDATE_WIN] =
    g_signal_new("window_update",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWMClass, window_update),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__POINTER,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 1, G_TYPE_POINTER);
    signals[SIG_GIVE_FOCUS] =
    @@ -1488,8 +1479,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWMClass, give_focus),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__POINTER,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 1, G_TYPE_POINTER);
    signals[SIG_MOUSE_CLICK] =
    @@ -1497,8 +1487,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWMClass, mouse_clicked),
    - gnt_boolean_handled_accumulator, NULL,
    - gnt_closure_marshal_BOOLEAN__INT_INT_INT_POINTER,
    + gnt_boolean_handled_accumulator, NULL, NULL,
    G_TYPE_BOOLEAN, 4, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_POINTER);
    signals[SIG_TERMINAL_REFRESH] =
    @@ -1506,8 +1495,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(GntWMClass, terminal_refresh),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__VOID,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 0);
    gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "window-next", window_next,
    --- a/libpurple/Makefile.am Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/Makefile.am Fri Jun 30 15:03:16 2017 +0300
    @@ -5,7 +5,6 @@
    enums.c.in \
    enums.h.in \
    glibcompat.h \
    - marshallers.list \
    purple-notifications-example \
    purple-remote \
    purple-send \
    @@ -40,13 +39,6 @@
    buddylist.c \
    buddyicon.c \
    chat.c \
    - ciphers/aescipher.c \
    - ciphers/descipher.c \
    - ciphers/des3cipher.c \
    - ciphers/md4hash.c \
    - ciphers/pbkdf2cipher.c \
    - ciphers/rc4cipher.c \
    - cipher.c \
    circularbuffer.c \
    cmds.c \
    connection.c \
    @@ -121,8 +113,7 @@
    xmlnode.c
    purple_builtsources = \
    - enums.c \
    - marshallers.c
    + enums.c
    purple_coreheaders = \
    account.h \
    @@ -133,7 +124,6 @@
    buddylist.h \
    buddyicon.h \
    chat.h \
    - cipher.h \
    circularbuffer.h \
    cmds.h \
    connection.h \
    @@ -233,20 +223,11 @@
    codec.h \
    enum-types.h
    -purple_cipherheaders = \
    - aescipher.h \
    - descipher.h \
    - des3cipher.h \
    - md4hash.h \
    - pbkdf2cipher.h \
    - rc4cipher.h
    -
    -purple_builtheaders = purple.h version.h enums.h marshallers.h
    +purple_builtheaders = purple.h version.h enums.h
    purple_enumheaders = \
    $(srcdir)/account.h \
    $(srcdir)/buddyicon.h \
    - $(srcdir)/cipher.h \
    $(srcdir)/connection.h \
    $(srcdir)/conversation.h \
    $(srcdir)/conversationtypes.h \
    @@ -263,13 +244,6 @@
    $(srcdir)/xmlnode.h
    -marshallers.h: marshallers.list
    - $(AM_V_GEN)$(GLIB_GENMARSHAL) --prefix=purple_smarshal $(srcdir)/marshallers.list --header > marshallers.h
    -
    -marshallers.c: marshallers.list marshallers.h
    - $(AM_V_GEN)echo "#include \"marshallers.h\"" > marshallers.c
    - $(AM_V_at)$(GLIB_GENMARSHAL) --prefix=purple_smarshal $(srcdir)/marshallers.list --body >> marshallers.c
    -
    # glib-mkenums doesn't handle VPATHs well, sed is used here to fix the
    # include paths and documentation.
    # Escaping possible . in $(srcdir) to \. for sed pattern.
    @@ -283,9 +257,7 @@
    CLEANFILES = \
    enums.c \
    - enums.h \
    - marshallers.c \
    - marshallers.h
    + enums.h
    DISTCLEANFILES = \
    data/purple-url-handler.desktop
    @@ -314,14 +286,13 @@
    prefs.h presence.h roomlist.h savedstatuses.h smiley.h smiley-list.h \
    status.h server.h util.h xmlnode.h protocol.h protocols.h
    -# Filter out enums.h and marshallers.h as they don't actually generate
    -# anything. This way making from a VPATH and distcheck doesn't fail due
    -# to not being able to find the enums.h or marshallers.h files if
    -# they've already been generated in the $(srcdir).
    +# Filter out enums.h as it doesn't actually generate anything.
    +# This way making from a VPATH and distcheck doesn't fail due
    +# to not being able to find the enums.h file if it's already
    +# been generated in the $(srcdir).
    purple_build_coreheaders = $(addprefix $(srcdir)/, $(purple_coreheaders)) \
    - $(addprefix $(srcdir)/ciphers/, $(purple_cipherheaders)) \
    $(addprefix $(srcdir)/media/, $(purple_mediaheaders)) \
    - $(filter-out: enums.h marshallers.h, $(purple_builtheaders))
    + $(filter-out: enums.h, $(purple_builtheaders))
    dbus_build_exported = $(addprefix $(srcdir)/, $(dbus_exported))
    # We should probably make this better
    dbus_signals = $(addprefix $(srcdir)/, $(purple_coresources)) \
    @@ -345,7 +316,7 @@
    # Declare these as dependencies so they're built even if `make distcheck`
    # is run immediately after configuring.
    -$(libpurple_la_OBJECTS): dbus-types.h enums.h marshallers.h
    +$(libpurple_la_OBJECTS): dbus-types.h enums.h
    # libpurple-client
    @@ -358,7 +329,7 @@
    purple-client-bindings.c: dbus-analyze-functions.py $(dbus_exported)
    $(AM_V_GEN) $(PYTHON) $(srcdir)/dbus-analyze-functions.py --client -o $@ $(dbus_build_exported)
    -purple-client-bindings.h: dbus-analyze-types.py dbus-analyze-functions.py $(purple_coreheaders) $(addprefix ciphers/, $(purple_cipherheaders)) $(addprefix media/, $(purple_mediaheaders)) $(purple_builtheaders) $(dbus_exported)
    +purple-client-bindings.h: dbus-analyze-types.py dbus-analyze-functions.py $(purple_coreheaders) $(addprefix media/, $(purple_mediaheaders)) $(purple_builtheaders) $(dbus_exported)
    $(AM_V_GEN) $(PYTHON) $(srcdir)/dbus-analyze-types.py --keyword=enum --verbatim -o $@ $(purple_build_coreheaders)
    $(AM_V_at) $(PYTHON) $(srcdir)/dbus-analyze-functions.py --client --headers --append -o $@ $(dbus_build_exported)
    @@ -398,7 +369,7 @@
    # Declare these as dependencies so they're built even if `make distcheck`
    # is run immediately after configuring.
    -$(libpurple_la_OBJECTS): enums.h marshallers.h
    +$(libpurple_la_OBJECTS): enums.h
    endif
    @@ -420,10 +391,6 @@
    $(purple_builtheaders) \
    $(dbus_headers)
    -cipherincludedir=$(includedir)/libpurple/ciphers
    -cipherinclude_HEADERS = \
    - $(addprefix $(srcdir)/ciphers/, $(purple_cipherheaders))
    -
    mediaincludedir=$(includedir)/libpurple/media
    mediainclude_HEADERS = \
    $(addprefix $(srcdir)/media/, $(purple_mediaheaders))
    @@ -467,8 +434,6 @@
    $(GSTINTERFACES_LIBS) \
    $(IDN_LIBS) \
    $(JSON_LIBS) \
    - $(GNUTLS_LIBS) \
    - $(NSS_LIBS) \
    $(ZLIB_LIBS) \
    $(INTROSPECTION_LIBS) \
    -lm
    @@ -487,8 +452,6 @@
    $(IDN_CFLAGS) \
    $(NETWORKMANAGER_CFLAGS) \
    $(JSON_CFLAGS) \
    - $(GNUTLS_CFLAGS) \
    - $(NSS_CFLAGS) \
    $(ZLIB_CFLAGS) \
    $(INTROSPECTION_CFLAGS)
    @@ -500,7 +463,6 @@
    if HAVE_INTROSPECTION
    introspection_sources = \
    $(libpurpleinclude_HEADERS) \
    - $(addprefix ciphers/, $(purple_cipherheaders)) \
    $(addprefix media/, $(purple_mediaheaders))
    Purple-$(PURPLE_MAJOR_VERSION).$(PURPLE_MINOR_VERSION).gir: $(builddir)/libpurple.la
    @@ -530,8 +492,6 @@
    $(IDN_CFLAGS) \
    $(NETWORKMANAGER_CFLAGS) \
    $(JSON_CFLAGS) \
    - $(GNUTLS_CFLAGS) \
    - $(NSS_CFLAGS) \
    $(ZLIB_CFLAGS) \
    $(INTROSPECTION_CFLAGS)
    --- a/libpurple/Makefile.mingw Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/Makefile.mingw Fri Jun 30 15:03:16 2017 +0300
    @@ -56,7 +56,7 @@
    VV_SRC =
    endif
    -BUILT_SRC = marshallers.c enums.c
    +BUILT_SRC = enums.c
    C_SRC = \
    $(BUILT_SRC) \
    @@ -68,13 +68,6 @@
    buddylist.c \
    buddyicon.c \
    certificate.c \
    - ciphers/aescipher.c \
    - ciphers/descipher.c \
    - ciphers/des3cipher.c \
    - ciphers/md4hash.c \
    - ciphers/pbkdf2cipher.c \
    - ciphers/rc4cipher.c \
    - cipher.c \
    circularbuffer.c \
    cmds.c \
    connection.c \
    @@ -146,7 +139,6 @@
    ENUM_HEADERS = \
    account.h \
    - cipher.h \
    connection.h \
    conversation.h \
    conversationtypes.h \
    @@ -209,15 +201,6 @@
    $(OBJECTS): $(PURPLE_CONFIG_H) $(PURPLE_VERSION_H) $(PURPLE_PURPLE_H)
    -marshallers.h: marshallers.list
    - @echo -e " GEN\t$@"
    - @$(GLIB_GENMARSHAL) --prefix=purple_smarshal $< --header > marshallers.h
    -
    -marshallers.c: marshallers.list marshallers.h
    - @echo -e " GEN\t$@"
    - @echo "#include \"marshallers.h\"" > marshallers.c
    - @$(GLIB_GENMARSHAL) --prefix=purple_smarshal $< --body >> marshallers.c
    -
    enums.h: enums.h.in $(ENUM_HEADERS)
    @echo -e " GEN\t$@"
    @$(GLIB_MKENUMS) --template enums.h.in $(ENUM_HEADERS) > enums.h
    @@ -233,7 +216,7 @@
    ## CLEAN RULES
    ##
    clean:
    - rm -f $(OBJECTS) $(RC_SRC) $(PURPLE_VERSION_H) $(PURPLE_PURPLE_H) marshallers.h marshallers.c enums.h enums.c
    + rm -f $(OBJECTS) $(RC_SRC) $(PURPLE_VERSION_H) $(PURPLE_PURPLE_H) enums.h enums.c
    rm -f $(TARGET).dll $(TARGET).dll.a $(TARGET).def
    $(MAKE_at) $(MAKE) -C $(PURPLE_PROTOS_TOP) -f $(MINGW_MAKEFILE) clean
    $(MAKE_at) $(MAKE) -C $(PURPLE_PLUGINS_TOP) -f $(MINGW_MAKEFILE) clean
    --- a/libpurple/cipher.c Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,555 +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 "cipher.h"
    -#include "debug.h"
    -
    -/******************************************************************************
    - * PurpleCipher API
    - *****************************************************************************/
    -GType
    -purple_cipher_get_type(void) {
    - static GType type = 0;
    -
    - if(type == 0) {
    - static const GTypeInfo info = {
    - sizeof(PurpleCipherClass),
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - sizeof(PurpleCipher),
    - 0,
    - NULL,
    - NULL
    - };
    -
    - type = g_type_register_static(G_TYPE_OBJECT,
    - "PurpleCipher",
    - &info, G_TYPE_FLAG_ABSTRACT);
    - }
    -
    - return type;
    -}
    -
    -static const gchar *
    -purple_cipher_get_name(PurpleCipher *cipher)
    -{
    - PurpleCipherClass *klass;
    - const gchar *name;
    -
    - if (!PURPLE_IS_CIPHER(cipher))
    - return "(error: not a cipher)";
    -
    - klass = PURPLE_CIPHER_GET_CLASS(cipher);
    - if (!klass)
    - return "(error: unknown cipher class)";
    -
    - name = g_type_name(G_TYPE_FROM_CLASS(klass));
    - if (!name)
    - return "(error: unknown cipher name)";
    -
    - return name;
    -}
    -
    -static const gchar *
    -purple_hash_get_name(PurpleHash *hash)
    -{
    - PurpleHashClass *klass;
    - const gchar *name;
    -
    - if (!PURPLE_IS_HASH(hash))
    - return "(error: not a hash)";
    -
    - klass = PURPLE_HASH_GET_CLASS(hash);
    - if (!klass)
    - return "(error: unknown hash class)";
    -
    - name = g_type_name(G_TYPE_FROM_CLASS(klass));
    - if (!name)
    - return "(error: unknown hash name)";
    -
    - return name;
    -}
    -
    -void
    -purple_cipher_reset(PurpleCipher *cipher) {
    - PurpleCipherClass *klass = NULL;
    -
    - g_return_if_fail(PURPLE_IS_CIPHER(cipher));
    -
    - klass = PURPLE_CIPHER_GET_CLASS(cipher);
    -
    - if (klass && klass->reset)
    - klass->reset(cipher);
    - else {
    - purple_debug_warning("cipher", "the %s cipher does not "
    - "implement the reset method",
    - purple_cipher_get_name(cipher));
    - }
    -}
    -
    -void
    -purple_cipher_reset_state(PurpleCipher *cipher) {
    - PurpleCipherClass *klass = NULL;
    -
    - g_return_if_fail(PURPLE_IS_CIPHER(cipher));
    -
    - klass = PURPLE_CIPHER_GET_CLASS(cipher);
    -
    - if (klass && klass->reset_state)
    - klass->reset_state(cipher);
    - else {
    - purple_debug_warning("cipher", "the %s cipher does not "
    - "implement the reset_state method",
    - purple_cipher_get_name(cipher));
    - }
    -}
    -
    -void
    -purple_cipher_set_iv(PurpleCipher *cipher, guchar *iv, size_t len)
    -{
    - PurpleCipherClass *klass = NULL;
    -
    - g_return_if_fail(PURPLE_IS_CIPHER(cipher));
    - g_return_if_fail(iv);
    -
    - klass = PURPLE_CIPHER_GET_CLASS(cipher);
    -
    - if (klass && klass->set_iv)
    - klass->set_iv(cipher, iv, len);
    - else {
    - purple_debug_warning("cipher", "the %s cipher does not "
    - "implement the set_iv method",
    - purple_cipher_get_name(cipher));
    - }
    -}
    -
    -void
    -purple_cipher_append(PurpleCipher *cipher, const guchar *data,
    - size_t len)
    -{
    - PurpleCipherClass *klass = NULL;
    -
    - g_return_if_fail(PURPLE_IS_CIPHER(cipher));
    -
    - klass = PURPLE_CIPHER_GET_CLASS(cipher);
    -
    - if (klass && klass->append)
    - klass->append(cipher, data, len);
    - else {
    - purple_debug_warning("cipher", "the %s cipher does not "
    - "implement the append method",
    - purple_cipher_get_name(cipher));
    - }
    -}
    -
    -gboolean
    -purple_cipher_digest(PurpleCipher *cipher, guchar digest[], size_t len)
    -{
    - PurpleCipherClass *klass = NULL;
    -
    - g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), FALSE);
    -
    - klass = PURPLE_CIPHER_GET_CLASS(cipher);
    -
    - if (klass && klass->digest)
    - return klass->digest(cipher, digest, len);
    - else {
    - purple_debug_warning("cipher", "the %s cipher does not "
    - "implement the digest method",
    - purple_cipher_get_name(cipher));
    - }
    -
    - return FALSE;
    -}
    -
    -gboolean
    -purple_cipher_digest_to_str(PurpleCipher *cipher, gchar digest_s[], size_t len)
    -{
    - /* 8k is a bit excessive, will tweak later. */
    - guchar digest[BUF_LEN * 4];
    - size_t digest_size, n;
    -
    - g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), FALSE);
    - g_return_val_if_fail(digest_s, FALSE);
    -
    - digest_size = purple_cipher_get_digest_size(cipher);
    -
    - g_return_val_if_fail(digest_size <= BUF_LEN * 4, FALSE);
    -
    - if(!purple_cipher_digest(cipher, digest, sizeof(digest)))
    - return FALSE;
    -
    - /* Every digest byte occupies 2 chars + the NUL at the end. */
    - g_return_val_if_fail(digest_size * 2 + 1 <= len, FALSE);
    -
    - for(n = 0; n < digest_size; n++)
    - sprintf(digest_s + (n * 2), "%02x", digest[n]);
    -
    - digest_s[n * 2] = '\0';
    -
    - return TRUE;
    -}
    -
    -size_t
    -purple_cipher_get_digest_size(PurpleCipher *cipher)
    -{
    - PurpleCipherClass *klass = NULL;
    -
    - g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), FALSE);
    -
    - klass = PURPLE_CIPHER_GET_CLASS(cipher);
    -
    - if (klass && klass->get_digest_size)
    - return klass->get_digest_size(cipher);
    - else {
    - purple_debug_warning("cipher", "the %s cipher does not "
    - "implement the get_digest_size method",
    - purple_cipher_get_name(cipher));
    - }
    -
    - return FALSE;
    -}
    -
    -ssize_t
    -purple_cipher_encrypt(PurpleCipher *cipher, const guchar input[],
    - size_t in_len, guchar output[], size_t out_size)
    -{
    - PurpleCipherClass *klass = NULL;
    -
    - g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), -1);
    - g_return_val_if_fail(input != NULL, -1);
    - g_return_val_if_fail(output != NULL, -1);
    - g_return_val_if_fail(out_size >= in_len, -1);
    -
    - klass = PURPLE_CIPHER_GET_CLASS(cipher);
    -
    - if (klass && klass->encrypt)
    - return klass->encrypt(cipher, input, in_len, output, out_size);
    - else {
    - purple_debug_warning("cipher", "the %s cipher does not "
    - "implement the encrypt method",
    - purple_cipher_get_name(cipher));
    - }
    -
    - return -1;
    -}
    -
    -ssize_t
    -purple_cipher_decrypt(PurpleCipher *cipher, const guchar input[],
    - size_t in_len, guchar output[], size_t out_size)
    -{
    - PurpleCipherClass *klass = NULL;
    -
    - g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), -1);
    - g_return_val_if_fail(input != NULL, -1);
    - g_return_val_if_fail(output != NULL, -1);
    -
    - klass = PURPLE_CIPHER_GET_CLASS(cipher);
    -
    - if (klass && klass->decrypt)
    - return klass->decrypt(cipher, input, in_len, output, out_size);
    - else {
    - purple_debug_warning("cipher", "the %s cipher does not "
    - "implement the decrypt method",
    - purple_cipher_get_name(cipher));
    - }
    -
    - return -1;
    -}
    -
    -void
    -purple_cipher_set_salt(PurpleCipher *cipher, const guchar *salt, size_t len) {
    - PurpleCipherClass *klass = NULL;
    -
    - g_return_if_fail(PURPLE_IS_CIPHER(cipher));
    -
    - klass = PURPLE_CIPHER_GET_CLASS(cipher);
    -
    - if (klass && klass->set_salt)
    - klass->set_salt(cipher, salt, len);
    - else {
    - purple_debug_warning("cipher", "the %s cipher does not "
    - "implement the set_salt method",
    - purple_cipher_get_name(cipher));
    - }
    -}
    -
    -void
    -purple_cipher_set_key(PurpleCipher *cipher, const guchar *key, size_t len) {
    - PurpleCipherClass *klass = NULL;
    -
    - g_return_if_fail(PURPLE_IS_CIPHER(cipher));
    -
    - klass = PURPLE_CIPHER_GET_CLASS(cipher);
    -
    - if (klass && klass->set_key)
    - klass->set_key(cipher, key, len);
    - else {
    - purple_debug_warning("cipher", "the %s cipher does not "
    - "implement the set_key method",
    - purple_cipher_get_name(cipher));
    - }
    -}
    -
    -size_t
    -purple_cipher_get_key_size(PurpleCipher *cipher) {
    - PurpleCipherClass *klass = NULL;
    -
    - g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), -1);
    -
    - klass = PURPLE_CIPHER_GET_CLASS(cipher);
    -
    - if (klass && klass->get_key_size)
    - return klass->get_key_size(cipher);
    - else {
    - purple_debug_warning("cipher", "the %s cipher does not "
    - "implement the get_key_size method",
    - purple_cipher_get_name(cipher));
    - }
    -
    - return -1;
    -}
    -
    -void
    -purple_cipher_set_batch_mode(PurpleCipher *cipher,
    - PurpleCipherBatchMode mode)
    -{
    - PurpleCipherClass *klass = NULL;
    -
    - g_return_if_fail(PURPLE_IS_CIPHER(cipher));
    -
    - klass = PURPLE_CIPHER_GET_CLASS(cipher);
    -
    - if (klass && klass->set_batch_mode)
    - klass->set_batch_mode(cipher, mode);
    - else {
    - purple_debug_warning("cipher", "the %s cipher does not "
    - "implement the set_batch_mode method",
    - purple_cipher_get_name(cipher));
    - }
    -}
    -
    -PurpleCipherBatchMode
    -purple_cipher_get_batch_mode(PurpleCipher *cipher)
    -{
    - PurpleCipherClass *klass = NULL;
    -
    - g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), -1);
    -
    - klass = PURPLE_CIPHER_GET_CLASS(cipher);
    -
    - if (klass && klass->get_batch_mode)
    - return klass->get_batch_mode(cipher);
    - else {
    - purple_debug_warning("cipher", "the %s cipher does not "
    - "implement the get_batch_mode method",
    - purple_cipher_get_name(cipher));
    - }
    -
    - return -1;
    -}
    -
    -size_t
    -purple_cipher_get_block_size(PurpleCipher *cipher)
    -{
    - PurpleCipherClass *klass = NULL;
    -
    - g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), -1);
    -
    - klass = PURPLE_CIPHER_GET_CLASS(cipher);
    -
    - if (klass && klass->get_block_size)
    - return klass->get_block_size(cipher);
    - else {
    - purple_debug_warning("cipher", "the %s cipher does not "
    - "implement the get_block_size method",
    - purple_cipher_get_name(cipher));
    - }
    -
    - return -1;
    -}
    -
    -/******************************************************************************
    - * PurpleHash API
    - *****************************************************************************/
    -GType
    -purple_hash_get_type(void) {
    - static GType type = 0;
    -
    - if(type == 0) {
    - static const GTypeInfo info = {
    - sizeof(PurpleHashClass),
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - NULL,
    - sizeof(PurpleHash),
    - 0,
    - NULL,
    - NULL
    - };
    -
    - type = g_type_register_static(G_TYPE_OBJECT,
    - "PurpleHash",
    - &info, G_TYPE_FLAG_ABSTRACT);
    - }
    -
    - return type;
    -}
    -
    -void
    -purple_hash_reset(PurpleHash *hash) {
    - PurpleHashClass *klass = NULL;
    -
    - g_return_if_fail(PURPLE_IS_HASH(hash));
    -
    - klass = PURPLE_HASH_GET_CLASS(hash);
    -
    - if (klass && klass->reset)
    - klass->reset(hash);
    - else {
    - purple_debug_warning("hash", "the %s hash does not implement "
    - "the reset method", purple_hash_get_name(hash));
    - }
    -}
    -
    -void
    -purple_hash_reset_state(PurpleHash *hash) {
    - PurpleHashClass *klass = NULL;
    -
    - g_return_if_fail(PURPLE_IS_HASH(hash));
    -
    - klass = PURPLE_HASH_GET_CLASS(hash);
    -
    - if (klass && klass->reset_state)
    - klass->reset_state(hash);
    - else {
    - purple_debug_warning("hash", "the %s hash does not implement "
    - "the reset_state method", purple_hash_get_name(hash));
    - }
    -}
    -
    -void
    -purple_hash_append(PurpleHash *hash, const guchar *data,
    - size_t len)
    -{
    - PurpleHashClass *klass = NULL;
    -
    - g_return_if_fail(PURPLE_IS_HASH(hash));
    -
    - klass = PURPLE_HASH_GET_CLASS(hash);
    -
    - if (klass && klass->append)
    - klass->append(hash, data, len);
    - else {
    - purple_debug_warning("hash", "the %s hash does not implement "
    - "the append method", purple_hash_get_name(hash));
    - }
    -}
    -
    -gboolean
    -purple_hash_digest(PurpleHash *hash, guchar digest[], size_t len)
    -{
    - PurpleHashClass *klass = NULL;
    -
    - g_return_val_if_fail(PURPLE_IS_HASH(hash), FALSE);
    -
    - klass = PURPLE_HASH_GET_CLASS(hash);
    -
    - if (klass && klass->digest)
    - return klass->digest(hash, digest, len);
    - else {
    - purple_debug_warning("hash", "the %s hash does not implement "
    - "the digest method", purple_hash_get_name(hash));
    - }
    -
    - return FALSE;
    -}
    -
    -gboolean
    -purple_hash_digest_to_str(PurpleHash *hash, gchar digest_s[], size_t len)
    -{
    - /* 8k is a bit excessive, will tweak later. */
    - guchar digest[BUF_LEN * 4];
    - size_t digest_size, n;
    -
    - g_return_val_if_fail(PURPLE_IS_HASH(hash), FALSE);
    - g_return_val_if_fail(digest_s, FALSE);
    -
    - digest_size = purple_hash_get_digest_size(hash);
    -
    - g_return_val_if_fail(digest_size <= BUF_LEN * 4, FALSE);
    -
    - if(!purple_hash_digest(hash, digest, sizeof(digest)))
    - return FALSE;
    -
    - /* Every digest byte occupies 2 chars + the NUL at the end. */
    - g_return_val_if_fail(digest_size * 2 + 1 <= len, FALSE);
    -
    - for(n = 0; n < digest_size; n++)
    - sprintf(digest_s + (n * 2), "%02x", digest[n]);
    -
    - digest_s[n * 2] = '\0';
    -
    - return TRUE;
    -}
    -
    -size_t
    -purple_hash_get_digest_size(PurpleHash *hash)
    -{
    - PurpleHashClass *klass = NULL;
    -
    - g_return_val_if_fail(PURPLE_IS_HASH(hash), FALSE);
    -
    - klass = PURPLE_HASH_GET_CLASS(hash);
    -
    - if (klass && klass->get_digest_size)
    - return klass->get_digest_size(hash);
    - else {
    - purple_debug_warning("hash", "the %s hash does not implement "
    - "the get_digest_size method", purple_hash_get_name(hash));
    - }
    -
    - return FALSE;
    -}
    -
    -size_t
    -purple_hash_get_block_size(PurpleHash *hash)
    -{
    - PurpleHashClass *klass = NULL;
    -
    - g_return_val_if_fail(PURPLE_IS_HASH(hash), -1);
    -
    - klass = PURPLE_HASH_GET_CLASS(hash);
    -
    - if (klass && klass->get_block_size)
    - return klass->get_block_size(hash);
    - else {
    - purple_debug_warning("hash", "the %s hash does not implement "
    - "the get_block_size method", purple_hash_get_name(hash));
    - }
    -
    - return -1;
    -}
    --- a/libpurple/cipher.h Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,421 +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 PURPLE_CIPHER_H
    -#define PURPLE_CIPHER_H
    -/**
    - * SECTION:cipher
    - * @section_id: libpurple-cipher
    - * @short_description: <filename>cipher.h</filename>
    - * @title: Cipher and Hash API
    - */
    -
    -#include <glib.h>
    -#include <glib-object.h>
    -#include <string.h>
    -
    -#define PURPLE_TYPE_CIPHER (purple_cipher_get_type())
    -#define PURPLE_CIPHER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_CIPHER, PurpleCipher))
    -#define PURPLE_CIPHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_CIPHER, PurpleCipherClass))
    -#define PURPLE_IS_CIPHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_CIPHER))
    -#define PURPLE_IS_CIPHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_CIPHER))
    -#define PURPLE_CIPHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_CIPHER, PurpleCipherClass))
    -
    -typedef struct _PurpleCipher PurpleCipher;
    -typedef struct _PurpleCipherClass PurpleCipherClass;
    -
    -#define PURPLE_TYPE_HASH (purple_hash_get_type())
    -#define PURPLE_HASH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_HASH, PurpleHash))
    -#define PURPLE_HASH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_HASH, PurpleHashClass))
    -#define PURPLE_IS_HASH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_HASH))
    -#define PURPLE_IS_HASH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_HASH))
    -#define PURPLE_HASH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_HASH, PurpleHashClass))
    -
    -typedef struct _PurpleHash PurpleHash;
    -typedef struct _PurpleHashClass PurpleHashClass;
    -
    -/**
    - * PurpleCipherBatchMode:
    - * @PURPLE_CIPHER_BATCH_MODE_ECB: Electronic Codebook Mode
    - * @PURPLE_CIPHER_BATCH_MODE_CBC: Cipher Block Chaining Mode
    - *
    - * Modes for batch encrypters
    - */
    -typedef enum {
    - PURPLE_CIPHER_BATCH_MODE_ECB,
    - PURPLE_CIPHER_BATCH_MODE_CBC
    -} PurpleCipherBatchMode;
    -
    -/**
    - * PurpleCipher:
    - *
    - * Purple Cipher is an opaque data structure and should not be used directly.
    - */
    -struct _PurpleCipher {
    - GObject gparent;
    -};
    -
    -struct _PurpleCipherClass {
    - GObjectClass parent_class;
    -
    - /** The reset function */
    - void (*reset)(PurpleCipher *cipher);
    -
    - /** The reset state function */
    - void (*reset_state)(PurpleCipher *cipher);
    -
    - /** The set initialization vector function */
    - void (*set_iv)(PurpleCipher *cipher, guchar *iv, size_t len);
    -
    - /** The append data function */
    - void (*append)(PurpleCipher *cipher, const guchar *data, size_t len);
    -
    - /** The digest function */
    - gboolean (*digest)(PurpleCipher *cipher, guchar digest[], size_t len);
    -
    - /** The get digest size function */
    - size_t (*get_digest_size)(PurpleCipher *cipher);
    -
    - /** The encrypt function */
    - ssize_t (*encrypt)(PurpleCipher *cipher, const guchar input[], size_t in_len, guchar output[], size_t out_size);
    -
    - /** The decrypt function */
    - ssize_t (*decrypt)(PurpleCipher *cipher, const guchar input[], size_t in_len, guchar output[], size_t out_size);
    -
    - /** The set salt function */
    - void (*set_salt)(PurpleCipher *cipher, const guchar *salt, size_t len);
    -
    - /** The set key function */
    - void (*set_key)(PurpleCipher *cipher, const guchar *key, size_t len);
    -
    - /** The get key size function */
    - size_t (*get_key_size)(PurpleCipher *cipher);
    -
    - /** The set batch mode function */
    - void (*set_batch_mode)(PurpleCipher *cipher, PurpleCipherBatchMode mode);
    -
    - /** The get batch mode function */
    - PurpleCipherBatchMode (*get_batch_mode)(PurpleCipher *cipher);
    -
    - /** The get block size function */
    - size_t (*get_block_size)(PurpleCipher *cipher);
    -
    - /*< private >*/
    - void (*_purple_reserved1)(void);
    - void (*_purple_reserved2)(void);
    - void (*_purple_reserved3)(void);
    - void (*_purple_reserved4)(void);
    -};
    -
    -/**
    - * PurpleHash:
    - *
    - * Purple Hash is an opaque data structure and should not be used directly.
    - */
    -struct _PurpleHash {
    - GObject gparent;
    -};
    -
    -struct _PurpleHashClass {
    - GObjectClass parent_class;
    -
    - /** The reset function */
    - void (*reset)(PurpleHash *hash);
    -
    - /** The reset state function */
    - void (*reset_state)(PurpleHash *hash);
    -
    - /** The append data function */
    - void (*append)(PurpleHash *hash, const guchar *data, size_t len);
    -
    - /** The digest function */
    - gboolean (*digest)(PurpleHash *hash, guchar digest[], size_t len);
    -
    - /** The get digest size function */
    - size_t (*get_digest_size)(PurpleHash *hash);
    -
    - /** The get block size function */
    - size_t (*get_block_size)(PurpleHash *hash);
    -
    - /*< private >*/
    - void (*_purple_reserved1)(void);
    - void (*_purple_reserved2)(void);
    - void (*_purple_reserved3)(void);
    - void (*_purple_reserved4)(void);
    -};
    -
    -G_BEGIN_DECLS
    -
    -/*****************************************************************************/
    -/* PurpleCipher API */
    -/*****************************************************************************/
    -
    -/**
    - * purple_cipher_get_type:
    - *
    - * Returns: The #GType for the Cipher object.
    - */
    -GType purple_cipher_get_type(void);
    -
    -/**
    - * purple_cipher_reset:
    - * @cipher: The cipher
    - *
    - * Resets a cipher to it's default value
    - * Note: If you have set an IV you will have to set it after resetting
    - */
    -void purple_cipher_reset(PurpleCipher *cipher);
    -
    -/**
    - * purple_cipher_reset_state:
    - * @cipher: The cipher
    - *
    - * Resets a cipher state to it's default value, but doesn't touch stateless
    - * configuration.
    - *
    - * That means, IV and digest will be wiped out, but keys, ops or salt
    - * will remain untouched.
    - */
    -void purple_cipher_reset_state(PurpleCipher *cipher);
    -
    -/**
    - * purple_cipher_set_iv:
    - * @cipher: The cipher
    - * @iv: The initialization vector to set
    - * @len: The len of the IV
    - *
    - * Sets the initialization vector for a cipher
    - * Note: This should only be called right after a cipher is created or reset
    - */
    -void purple_cipher_set_iv(PurpleCipher *cipher, guchar *iv, size_t len);
    -
    -/**
    - * purple_cipher_append:
    - * @cipher: The cipher
    - * @data: The data to append
    - * @len: The length of the data
    - *
    - * Appends data to the cipher context
    - */
    -void purple_cipher_append(PurpleCipher *cipher, const guchar *data, size_t len);
    -
    -/**
    - * purple_cipher_digest:
    - * @cipher: The cipher
    - * @digest: The return buffer for the digest
    - * @len: The length of the buffer
    - *
    - * Digests a cipher context
    - */
    -gboolean purple_cipher_digest(PurpleCipher *cipher, guchar digest[], size_t len);
    -
    -/**
    - * purple_cipher_digest_to_str:
    - * @cipher: The cipher
    - * @digest_s: The return buffer for the string digest
    - * @len: The length of the buffer
    - *
    - * Converts a guchar digest into a hex string
    - */
    -gboolean purple_cipher_digest_to_str(PurpleCipher *cipher, gchar digest_s[], size_t len);
    -
    -/**
    - * purple_cipher_get_digest_size:
    - * @cipher: The cipher whose digest size to get
    - *
    - * Gets the digest size of a cipher
    - *
    - * Returns: The digest size of the cipher
    - */
    -size_t purple_cipher_get_digest_size(PurpleCipher *cipher);
    -
    -/**
    - * purple_cipher_encrypt:
    - * @cipher: The cipher
    - * @input: The data to encrypt
    - * @in_len: The length of the data
    - * @output: The output buffer
    - * @out_size: The size of the output buffer
    - *
    - * Encrypts data using the cipher
    - *
    - * Returns: A length of data that was outputed or -1, if failed
    - */
    -ssize_t purple_cipher_encrypt(PurpleCipher *cipher, const guchar input[], size_t in_len, guchar output[], size_t out_size);
    -
    -/**
    - * purple_cipher_decrypt:
    - * @cipher: The cipher
    - * @input: The data to encrypt
    - * @in_len: The length of the returned value
    - * @output: The output buffer
    - * @out_size: The size of the output buffer
    - *
    - * Decrypts data using the cipher
    - *
    - * Returns: A length of data that was outputed or -1, if failed
    - */
    -ssize_t purple_cipher_decrypt(PurpleCipher *cipher, const guchar input[], size_t in_len, guchar output[], size_t out_size);
    -
    -/**
    - * purple_cipher_set_salt:
    - * @cipher: The cipher whose salt to set
    - * @salt: The salt
    - * @len: The length of the salt
    - *
    - * Sets the salt on a cipher
    - */
    -void purple_cipher_set_salt(PurpleCipher *cipher, const guchar *salt, size_t len);
    -
    -/**
    - * purple_cipher_set_key:
    - * @cipher: The cipher whose key to set
    - * @key: The key
    - * @len: The size of the key
    - *
    - * Sets the key on a cipher
    - */
    -void purple_cipher_set_key(PurpleCipher *cipher, const guchar *key, size_t len);
    -
    -/**
    - * purple_cipher_get_key_size:
    - * @cipher: The cipher whose key size to get
    - *
    - * Gets the size of the key if the cipher supports it
    - *
    - * Returns: The size of the key
    - */
    -size_t purple_cipher_get_key_size(PurpleCipher *cipher);
    -
    -/**
    - * purple_cipher_set_batch_mode:
    - * @cipher: The cipher whose batch mode to set
    - * @mode: The batch mode under which the cipher should operate
    - *
    - * Sets the batch mode of a cipher
    - */
    -void purple_cipher_set_batch_mode(PurpleCipher *cipher, PurpleCipherBatchMode mode);
    -
    -/**
    - * purple_cipher_get_batch_mode:
    - * @cipher: The cipher whose batch mode to get
    - *
    - * Gets the batch mode of a cipher
    - *
    - * Returns: The batch mode under which the cipher is operating
    - */
    -PurpleCipherBatchMode purple_cipher_get_batch_mode(PurpleCipher *cipher);
    -
    -/**
    - * purple_cipher_get_block_size:
    - * @cipher: The cipher whose block size to get
    - *
    - * Gets the block size of a cipher
    - *
    - * Returns: The block size of the cipher
    - */
    -size_t purple_cipher_get_block_size(PurpleCipher *cipher);
    -
    -/*****************************************************************************/
    -/* PurpleHash API */
    -/*****************************************************************************/
    -
    -/**
    - * purple_hash_get_type:
    - *
    - * Returns: The #GType for the Hash object.
    - */
    -GType purple_hash_get_type(void);
    -
    -/**
    - * purple_hash_reset:
    - * @hash: The hash
    - *
    - * Resets a hash to it's default value
    - * Note: If you have set an IV you will have to set it after resetting
    - */
    -void purple_hash_reset(PurpleHash *hash);
    -
    -/**
    - * purple_hash_reset_state:
    - * @hash: The hash
    - *
    - * Resets a hash state to it's default value, but doesn't touch stateless
    - * configuration.
    - *
    - * That means, IV and digest will be wiped out, but keys, ops or salt
    - * will remain untouched.
    - */
    -void purple_hash_reset_state(PurpleHash *hash);
    -
    -/**
    - * purple_hash_append:
    - * @hash: The hash
    - * @data: The data to append
    - * @len: The length of the data
    - *
    - * Appends data to the hash context
    - */
    -void purple_hash_append(PurpleHash *hash, const guchar *data, size_t len);
    -
    -/**
    - * purple_hash_digest:
    - * @hash: The hash
    - * @digest: The return buffer for the digest
    - * @len: The length of the buffer
    - *
    - * Digests a hash context
    - */
    -gboolean purple_hash_digest(PurpleHash *hash, guchar digest[], size_t len);
    -
    -/**
    - * purple_hash_digest_to_str:
    - * @hash: The hash
    - * @digest_s: The return buffer for the string digest
    - * @len: The length of the buffer
    - *
    - * Converts a guchar digest into a hex string
    - */
    -gboolean purple_hash_digest_to_str(PurpleHash *hash, gchar digest_s[], size_t len);
    -
    -/**
    - * purple_hash_get_digest_size:
    - * @hash: The hash whose digest size to get
    - *
    - * Gets the digest size of a hash
    - *
    - * Returns: The digest size of the hash
    - */
    -size_t purple_hash_get_digest_size(PurpleHash *hash);
    -
    -/**
    - * purple_hash_get_block_size:
    - * @hash: The hash whose block size to get
    - *
    - * Gets the block size of a hash
    - *
    - * Returns: The block size of the hash
    - */
    -size_t purple_hash_get_block_size(PurpleHash *hash);
    -
    -G_END_DECLS
    -
    -#endif /* PURPLE_CIPHER_H */
    --- a/libpurple/ciphers/aescipher.c Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,725 +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
    - *
    - * Written by Tomek Wasilczyk <twasilczyk@pidgin.im>
    - */
    -
    -#include "internal.h"
    -#include "glibcompat.h"
    -
    -#include "aescipher.h"
    -#include "debug.h"
    -#include "enums.h"
    -
    -#include <string.h>
    -
    -#if defined(HAVE_GNUTLS)
    -# define PURPLE_AES_USE_GNUTLS 1
    -# include <gnutls/gnutls.h>
    -# include <gnutls/crypto.h>
    -#elif defined(HAVE_NSS)
    -# define PURPLE_AES_USE_NSS 1
    -# include <nss.h>
    -# include <pk11pub.h>
    -# include <prerror.h>
    -#else
    -# warning "No GnuTLS or NSS support"
    -#endif
    -
    -/* 128bit */
    -#define PURPLE_AES_BLOCK_SIZE 16
    -
    -/******************************************************************************
    - * Structs
    - *****************************************************************************/
    -#define PURPLE_AES_CIPHER_GET_PRIVATE(obj) \
    - (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_AES_CIPHER, PurpleAESCipherPrivate))
    -
    -typedef struct {
    - guchar iv[PURPLE_AES_BLOCK_SIZE];
    - guchar key[32];
    - guint key_size;
    - gboolean failure;
    - PurpleCipherBatchMode batch_mode;
    -} PurpleAESCipherPrivate;
    -
    -/******************************************************************************
    - * Enums
    - *****************************************************************************/
    -enum {
    - PROP_NONE,
    - PROP_BATCH_MODE,
    - PROP_IV,
    - PROP_KEY,
    - PROP_LAST,
    -};
    -
    -/*******************************************************************************
    - * Globals
    - ******************************************************************************/
    -static GParamSpec *properties[PROP_LAST];
    -
    -/******************************************************************************
    - * Cipher Stuff
    - *****************************************************************************/
    -
    -typedef gboolean (*purple_aes_cipher_crypt_func)(
    - const guchar *input, guchar *output, size_t len,
    - guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size,
    - PurpleCipherBatchMode batch_mode);
    -
    -static void
    -purple_aes_cipher_reset(PurpleCipher *cipher)
    -{
    - PurpleAESCipherPrivate *priv = PURPLE_AES_CIPHER_GET_PRIVATE(cipher);
    -
    - g_return_if_fail(priv != NULL);
    -
    - memset(priv->iv, 0, sizeof(priv->iv));
    - memset(priv->key, 0, sizeof(priv->key));
    - priv->key_size = 32; /* 256bit */
    - priv->failure = FALSE;
    -}
    -
    -static void
    -purple_aes_cipher_set_iv(PurpleCipher *cipher, guchar *iv, size_t len)
    -{
    - PurpleAESCipherPrivate *priv = PURPLE_AES_CIPHER_GET_PRIVATE(cipher);
    -
    - if ((len > 0 && iv == NULL) ||
    - (len != 0 && len != sizeof(priv->iv))) {
    - purple_debug_error("cipher-aes", "invalid IV length\n");
    - priv->failure = TRUE;
    - return;
    - }
    -
    - if (len == 0)
    - memset(priv->iv, 0, sizeof(priv->iv));
    - else
    - memcpy(priv->iv, iv, len);
    -
    - g_object_notify_by_pspec(G_OBJECT(cipher), properties[PROP_IV]);
    -}
    -
    -static void
    -purple_aes_cipher_set_key(PurpleCipher *cipher, const guchar *key, size_t len)
    -{
    - PurpleAESCipherPrivate *priv = PURPLE_AES_CIPHER_GET_PRIVATE(cipher);
    -
    - if ((len > 0 && key == NULL) ||
    - (len != 0 && len != 16 && len != 24 && len != 32)) {
    - purple_debug_error("cipher-aes", "invalid key length\n");
    - priv->failure = TRUE;
    - return;
    - }
    -
    - priv->key_size = len;
    - memset(priv->key, 0, sizeof(priv->key));
    - if (len > 0)
    - memcpy(priv->key, key, len);
    -
    - g_object_notify_by_pspec(G_OBJECT(cipher), properties[PROP_KEY]);
    -}
    -
    -static guchar *
    -purple_aes_cipher_pad_pkcs7(const guchar input[], size_t in_len, size_t *out_len)
    -{
    - int padding_len, total_len;
    - guchar *padded;
    -
    - g_return_val_if_fail(input != NULL, NULL);
    - g_return_val_if_fail(out_len != NULL, NULL);
    -
    - padding_len = PURPLE_AES_BLOCK_SIZE - (in_len % PURPLE_AES_BLOCK_SIZE);
    - total_len = in_len + padding_len;
    - g_assert((total_len % PURPLE_AES_BLOCK_SIZE) == 0);
    -
    - padded = g_new(guchar, total_len);
    - *out_len = total_len;
    -
    - memcpy(padded, input, in_len);
    - memset(padded + in_len, padding_len, padding_len);
    -
    - return padded;
    -}
    -
    -static ssize_t
    -purple_aes_cipher_unpad_pkcs7(guchar input[], size_t in_len)
    -{
    - guchar padding_len, i;
    - size_t out_len;
    -
    - g_return_val_if_fail(input != NULL, -1);
    - g_return_val_if_fail(in_len > 0, -1);
    -
    - padding_len = input[in_len - 1];
    - if (padding_len == 0 || padding_len > PURPLE_AES_BLOCK_SIZE ||
    - padding_len > in_len) {
    - purple_debug_warning("cipher-aes",
    - "Invalid padding length: %d (total %" G_GSIZE_FORMAT ") - "
    - "most probably, the key was invalid\n",
    - padding_len, in_len);
    - return -1;
    - }
    -
    - out_len = in_len - padding_len;
    - for (i = 0; i < padding_len; i++) {
    - if (input[out_len + i] != padding_len) {
    - purple_debug_warning("cipher-aes",
    - "Padding doesn't match at pos %d (found %02x, "
    - "expected %02x) - "
    - "most probably, the key was invalid\n",
    - i, input[out_len + i], padding_len);
    - return -1;
    - }
    - }
    -
    - memset(input + out_len, 0, padding_len);
    - return out_len;
    -}
    -
    -#ifdef PURPLE_AES_USE_GNUTLS
    -
    -static gnutls_cipher_hd_t
    -purple_aes_cipher_gnutls_crypt_init(guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32],
    - guint key_size)
    -{
    - gnutls_cipher_hd_t handle;
    - gnutls_cipher_algorithm_t algorithm;
    - gnutls_datum_t key_info, iv_info;
    - int ret;
    -
    - if (key_size == 16)
    - algorithm = GNUTLS_CIPHER_AES_128_CBC;
    - else if (key_size == 24)
    - algorithm = GNUTLS_CIPHER_AES_192_CBC;
    - else if (key_size == 32)
    - algorithm = GNUTLS_CIPHER_AES_256_CBC;
    - else
    - g_return_val_if_reached(NULL);
    -
    - key_info.data = key;
    - key_info.size = key_size;
    -
    - iv_info.data = iv;
    - iv_info.size = PURPLE_AES_BLOCK_SIZE;
    -
    - ret = gnutls_cipher_init(&handle, algorithm, &key_info, &iv_info);
    - if (ret != 0) {
    - purple_debug_error("cipher-aes",
    - "gnutls_cipher_init failed: %d\n", ret);
    - return NULL;
    - }
    -
    - return handle;
    -}
    -
    -static gboolean
    -purple_aes_cipher_gnutls_encrypt(const guchar *input, guchar *output, size_t len,
    - guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size,
    - PurpleCipherBatchMode batch_mode)
    -{
    - gnutls_cipher_hd_t handle;
    - int ret;
    -
    - /* We have to simulate ECB mode, which is not supported by GnuTLS. */
    - if (batch_mode == PURPLE_CIPHER_BATCH_MODE_ECB) {
    - size_t i;
    - for (i = 0; i < len / PURPLE_AES_BLOCK_SIZE; i++) {
    - int offset = i * PURPLE_AES_BLOCK_SIZE;
    - guchar iv_local[PURPLE_AES_BLOCK_SIZE];
    - gboolean succ;
    -
    - memcpy(iv_local, iv, sizeof(iv_local));
    - succ = purple_aes_cipher_gnutls_encrypt(
    - input + offset, output + offset,
    - PURPLE_AES_BLOCK_SIZE,
    - iv_local, key, key_size,
    - PURPLE_CIPHER_BATCH_MODE_CBC);
    - if (!succ)
    - return FALSE;
    - }
    - return TRUE;
    - }
    -
    - handle = purple_aes_cipher_gnutls_crypt_init(iv, key, key_size);
    - if (handle == NULL)
    - return FALSE;
    -
    - ret = gnutls_cipher_encrypt2(handle, (guchar *)input, len, output, len);
    - gnutls_cipher_deinit(handle);
    -
    - if (ret != 0) {
    - purple_debug_error("cipher-aes",
    - "gnutls_cipher_encrypt2 failed: %d\n", ret);
    - return FALSE;
    - }
    -
    - return TRUE;
    -}
    -
    -static gboolean
    -purple_aes_cipher_gnutls_decrypt(const guchar *input, guchar *output, size_t len,
    - guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size,
    - PurpleCipherBatchMode batch_mode)
    -{
    - gnutls_cipher_hd_t handle;
    - int ret;
    -
    - /* We have to simulate ECB mode, which is not supported by GnuTLS. */
    - if (batch_mode == PURPLE_CIPHER_BATCH_MODE_ECB) {
    - size_t i;
    - for (i = 0; i < len / PURPLE_AES_BLOCK_SIZE; i++) {
    - int offset = i * PURPLE_AES_BLOCK_SIZE;
    - guchar iv_local[PURPLE_AES_BLOCK_SIZE];
    - gboolean succ;
    -
    - memcpy(iv_local, iv, sizeof(iv_local));
    - succ = purple_aes_cipher_gnutls_decrypt(
    - input + offset, output + offset,
    - PURPLE_AES_BLOCK_SIZE,
    - iv_local, key, key_size,
    - PURPLE_CIPHER_BATCH_MODE_CBC);
    - if (!succ)
    - return FALSE;
    - }
    - return TRUE;
    - }
    -
    - handle = purple_aes_cipher_gnutls_crypt_init(iv, key, key_size);
    - if (handle == NULL)
    - return FALSE;
    -
    - ret = gnutls_cipher_decrypt2(handle, input, len, output, len);
    - gnutls_cipher_deinit(handle);
    -
    - if (ret != 0) {
    - purple_debug_error("cipher-aes",
    - "gnutls_cipher_decrypt2 failed: %d\n", ret);
    - return FALSE;
    - }
    -
    - return TRUE;
    -}
    -
    -#elif defined(PURPLE_AES_USE_NSS)
    -
    -typedef struct {
    - PK11SlotInfo *slot;
    - PK11SymKey *sym_key;
    - SECItem *sec_param;
    - PK11Context *enc_context;
    -} PurpleAESCipherNSSContext;
    -
    -static void
    -purple_aes_cipher_nss_cleanup(PurpleAESCipherNSSContext *context)
    -{
    - g_return_if_fail(context != NULL);
    -
    - if (context->enc_context != NULL)
    - PK11_DestroyContext(context->enc_context, TRUE);
    - if (context->sec_param != NULL)
    - SECITEM_FreeItem(context->sec_param, TRUE);
    - if (context->sym_key != NULL)
    - PK11_FreeSymKey(context->sym_key);
    - if (context->slot != NULL)
    - PK11_FreeSlot(context->slot);
    -
    - memset(context, 0, sizeof(PurpleAESCipherNSSContext));
    -}
    -
    -static gboolean
    -purple_aes_cipher_nss_crypt(const guchar *input, guchar *output, size_t len,
    - guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size,
    - CK_ATTRIBUTE_TYPE operation, CK_MECHANISM_TYPE cipher_mech)
    -{
    - PurpleAESCipherNSSContext context;
    - SECItem key_item, iv_item;
    - SECStatus ret;
    - int outlen = 0;
    - unsigned int outlen_tmp = 0;
    -
    - memset(&context, 0, sizeof(PurpleAESCipherNSSContext));
    -
    - if (NSS_NoDB_Init(NULL) != SECSuccess) {
    - purple_debug_error("cipher-aes",
    - "NSS_NoDB_Init failed: %d\n", PR_GetError());
    - return FALSE;
    - }
    -
    - context.slot = PK11_GetBestSlot(cipher_mech, NULL);
    - if (context.slot == NULL) {
    - purple_debug_error("cipher-aes",
    - "PK11_GetBestSlot failed: %d\n", PR_GetError());
    - return FALSE;
    - }
    -
    - key_item.type = siBuffer;
    - key_item.data = key;
    - key_item.len = key_size;
    - context.sym_key = PK11_ImportSymKey(context.slot, cipher_mech,
    - PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, NULL);
    - if (context.sym_key == NULL) {
    - purple_debug_error("cipher-aes",
    - "PK11_ImportSymKey failed: %d\n", PR_GetError());
    - purple_aes_cipher_nss_cleanup(&context);
    - return FALSE;
    - }
    -
    - iv_item.type = siBuffer;
    - iv_item.data = iv;
    - iv_item.len = PURPLE_AES_BLOCK_SIZE;
    - context.sec_param = PK11_ParamFromIV(cipher_mech, &iv_item);
    - if (context.sec_param == NULL) {
    - purple_debug_error("cipher-aes",
    - "PK11_ParamFromIV failed: %d\n", PR_GetError());
    - purple_aes_cipher_nss_cleanup(&context);
    - return FALSE;
    - }
    -
    - context.enc_context = PK11_CreateContextBySymKey(cipher_mech, operation,
    - context.sym_key, context.sec_param);
    - if (context.enc_context == NULL) {
    - purple_debug_error("cipher-aes",
    - "PK11_CreateContextBySymKey failed: %d\n",
    - PR_GetError());
    - purple_aes_cipher_nss_cleanup(&context);
    - return FALSE;
    - }
    -
    - ret = PK11_CipherOp(context.enc_context, output, &outlen, len,
    - (guchar *)input, len);
    - if (ret != SECSuccess) {
    - purple_debug_error("cipher-aes",
    - "PK11_CipherOp failed: %d\n", PR_GetError());
    - purple_aes_cipher_nss_cleanup(&context);
    - return FALSE;
    - }
    -
    - ret = PK11_DigestFinal(context.enc_context, output + outlen, &outlen_tmp,
    - len - outlen);
    - if (ret != SECSuccess) {
    - purple_debug_error("cipher-aes",
    - "PK11_DigestFinal failed: %d\n", PR_GetError());
    - purple_aes_cipher_nss_cleanup(&context);
    - return FALSE;
    - }
    -
    - purple_aes_cipher_nss_cleanup(&context);
    -
    - outlen += outlen_tmp;
    - if (outlen != (int)len) {
    - purple_debug_error("cipher-aes",
    - "resulting length doesn't match: %d (expected: %"
    - G_GSIZE_FORMAT ")\n", outlen, len);
    - return FALSE;
    - }
    -
    - return TRUE;
    -}
    -
    -static CK_MECHANISM_TYPE
    -purple_aes_cipher_nss_batch_mode(PurpleCipherBatchMode batch_mode)
    -{
    - switch (batch_mode) {
    - case PURPLE_CIPHER_BATCH_MODE_CBC:
    - return CKM_AES_CBC;
    - case PURPLE_CIPHER_BATCH_MODE_ECB:
    - return CKM_AES_ECB;
    - }
    -
    - return CKM_AES_CBC;
    -}
    -
    -static gboolean
    -purple_aes_cipher_nss_encrypt(const guchar *input, guchar *output, size_t len,
    - guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size,
    - PurpleCipherBatchMode batch_mode)
    -{
    - return purple_aes_cipher_nss_crypt(input, output, len, iv, key, key_size,
    - CKA_ENCRYPT, purple_aes_cipher_nss_batch_mode(batch_mode));
    -}
    -
    -static gboolean
    -purple_aes_cipher_nss_decrypt(const guchar *input, guchar *output, size_t len,
    - guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size,
    - PurpleCipherBatchMode batch_mode)
    -{
    - return purple_aes_cipher_nss_crypt(input, output, len, iv, key, key_size,
    - CKA_DECRYPT, purple_aes_cipher_nss_batch_mode(batch_mode));
    -}
    -
    -#endif /* PURPLE_AES_USE_NSS */
    -
    -static ssize_t
    -purple_aes_cipher_encrypt(PurpleCipher *cipher, const guchar input[],
    - size_t in_len, guchar output[], size_t out_size)
    -{
    - PurpleAESCipherPrivate *priv = PURPLE_AES_CIPHER_GET_PRIVATE(cipher);
    - purple_aes_cipher_crypt_func encrypt_func;
    - guchar *input_padded;
    - size_t out_len = 0;
    - gboolean succ;
    -
    - if (priv->failure)
    - return -1;
    -
    - input_padded = purple_aes_cipher_pad_pkcs7(input, in_len, &out_len);
    -
    - if (out_len > out_size) {
    - purple_debug_error("cipher-aes", "Output buffer too small (%"
    - G_GSIZE_FORMAT " > %" G_GSIZE_FORMAT ")",
    - out_len, out_size);
    - memset(input_padded, 0, out_len);
    - g_free(input_padded);
    - return -1;
    - }
    -
    -#if defined(PURPLE_AES_USE_GNUTLS)
    - encrypt_func = purple_aes_cipher_gnutls_encrypt;
    -#elif defined(PURPLE_AES_USE_NSS)
    - encrypt_func = purple_aes_cipher_nss_encrypt;
    -#else
    - purple_debug_error("cipher-aes", "No matching encrypt_func\n");
    - return -1;
    -#endif
    -
    - succ = encrypt_func(input_padded, output, out_len, priv->iv,
    - priv->key, priv->key_size, priv->batch_mode);
    -
    - memset(input_padded, 0, out_len);
    - g_free(input_padded);
    -
    - if (!succ) {
    - memset(output, 0, out_len);
    - return -1;
    - }
    -
    - return out_len;
    -}
    -
    -static ssize_t
    -purple_aes_cipher_decrypt(PurpleCipher *cipher, const guchar input[],
    - size_t in_len, guchar output[], size_t out_size)
    -{
    - PurpleAESCipherPrivate *priv = PURPLE_AES_CIPHER_GET_PRIVATE(cipher);
    - purple_aes_cipher_crypt_func decrypt_func;
    - gboolean succ;
    - ssize_t out_len;
    -
    - if (priv->failure)
    - return -1;
    -
    - if (in_len > out_size) {
    - purple_debug_error("cipher-aes", "Output buffer too small\n");
    - return -1;
    - }
    -
    - if ((in_len % PURPLE_AES_BLOCK_SIZE) != 0 || in_len == 0) {
    - purple_debug_error("cipher-aes", "Malformed data\n");
    - return -1;
    - }
    -
    -#if defined(PURPLE_AES_USE_GNUTLS)
    - decrypt_func = purple_aes_cipher_gnutls_decrypt;
    -#elif defined(PURPLE_AES_USE_NSS)
    - decrypt_func = purple_aes_cipher_nss_decrypt;
    -#else
    - purple_debug_error("cipher-aes", "No matching decrypt_func\n");
    - return -1;
    -#endif
    -
    - succ = decrypt_func(input, output, in_len, priv->iv, priv->key,
    - priv->key_size, priv->batch_mode);
    -
    - if (!succ) {
    - memset(output, 0, in_len);
    - return -1;
    - }
    -
    - out_len = purple_aes_cipher_unpad_pkcs7(output, in_len);
    - if (out_len < 0) {
    - memset(output, 0, in_len);
    - return -1;
    - }
    -
    - return out_len;
    -}
    -
    -static size_t
    -purple_aes_cipher_get_key_size(PurpleCipher *cipher)
    -{
    - PurpleAESCipherPrivate *priv = PURPLE_AES_CIPHER_GET_PRIVATE(cipher);
    -
    - return priv->key_size;
    -}
    -
    -static void
    -purple_aes_cipher_set_batch_mode(PurpleCipher *cipher,
    - PurpleCipherBatchMode mode)
    -{
    - PurpleAESCipherPrivate *priv = PURPLE_AES_CIPHER_GET_PRIVATE(cipher);
    -
    - if (mode != PURPLE_CIPHER_BATCH_MODE_CBC &&
    - mode != PURPLE_CIPHER_BATCH_MODE_ECB)
    - {
    - purple_debug_error("cipher-aes", "unsupported batch mode\n");
    - priv->failure = TRUE;
    - }
    -
    - priv->batch_mode = mode;
    -
    - g_object_notify_by_pspec(G_OBJECT(cipher), properties[PROP_BATCH_MODE]);
    -}
    -
    -static PurpleCipherBatchMode
    -purple_aes_cipher_get_batch_mode(PurpleCipher *cipher)
    -{
    - PurpleAESCipherPrivate *priv = PURPLE_AES_CIPHER_GET_PRIVATE(cipher);
    -
    - return priv->batch_mode;
    -}
    -
    -static size_t
    -purple_aes_cipher_get_block_size(PurpleCipher *cipher)
    -{
    - return PURPLE_AES_BLOCK_SIZE;
    -}
    -
    -/******************************************************************************
    - * Object Stuff
    - *****************************************************************************/
    -static void
    -purple_aes_cipher_get_property(GObject *obj, guint param_id, GValue *value,
    - GParamSpec *pspec)
    -{
    - PurpleCipher *cipher = PURPLE_CIPHER(obj);
    -
    - switch(param_id) {
    - case PROP_BATCH_MODE:
    - g_value_set_enum(value,
    - purple_cipher_get_batch_mode(cipher));
    - break;
    - default:
    - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
    - break;
    - }
    -}
    -
    -static void
    -purple_aes_cipher_set_property(GObject *obj, guint param_id,
    - const GValue *value, GParamSpec *pspec)
    -{
    - PurpleCipher *cipher = PURPLE_CIPHER(obj);
    -
    - switch(param_id) {
    - case PROP_BATCH_MODE:
    - purple_cipher_set_batch_mode(cipher,
    - g_value_get_enum(value));
    - break;
    - case PROP_IV:
    - {
    - guchar *iv = (guchar *)g_value_get_string(value);
    - purple_cipher_set_iv(cipher, iv, strlen((gchar*)iv));
    - }
    - break;
    - case PROP_KEY:
    - purple_cipher_set_key(cipher, (guchar *)g_value_get_string(value),
    - purple_aes_cipher_get_key_size(cipher));
    - break;
    - default:
    - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
    - break;
    - }
    -}
    -
    -static void
    -purple_aes_cipher_class_init(PurpleAESCipherClass *klass) {
    - GObjectClass *obj_class = G_OBJECT_CLASS(klass);
    - PurpleCipherClass *cipher_class = PURPLE_CIPHER_CLASS(klass);
    -
    - obj_class->get_property = purple_aes_cipher_get_property;
    - obj_class->set_property = purple_aes_cipher_set_property;
    -
    - cipher_class->reset = purple_aes_cipher_reset;
    - cipher_class->set_iv = purple_aes_cipher_set_iv;
    - cipher_class->encrypt = purple_aes_cipher_encrypt;
    - cipher_class->decrypt = purple_aes_cipher_decrypt;
    - cipher_class->set_key = purple_aes_cipher_set_key;
    - cipher_class->get_key_size = purple_aes_cipher_get_key_size;
    - cipher_class->set_batch_mode = purple_aes_cipher_set_batch_mode;
    - cipher_class->get_batch_mode = purple_aes_cipher_get_batch_mode;
    - cipher_class->get_block_size = purple_aes_cipher_get_block_size;
    -
    - g_type_class_add_private(klass, sizeof(PurpleAESCipherPrivate));
    -
    - properties[PROP_BATCH_MODE] = g_param_spec_enum("batch-mode",
    - "batch-mode", "batch-mode", PURPLE_TYPE_CIPHER_BATCH_MODE,
    - PURPLE_CIPHER_BATCH_MODE_CBC,
    - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
    -
    - properties[PROP_IV] = g_param_spec_string("iv", "iv", "iv", NULL,
    - G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS);
    -
    - properties[PROP_KEY] = g_param_spec_string("key", "key", "key", NULL,
    - G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS);
    -
    - g_object_class_install_properties(obj_class, PROP_LAST, properties);
    -}
    -
    -static void
    -purple_aes_cipher_init(PurpleCipher *cipher) {
    - purple_cipher_reset(cipher);
    -}
    -
    -/******************************************************************************
    - * API
    - *****************************************************************************/
    -GType
    -purple_aes_cipher_get_type(void) {
    - static GType type = 0;
    -
    - if(type == 0) {
    - static const GTypeInfo info = {
    - sizeof(PurpleAESCipherClass),
    - NULL,
    - NULL,
    - (GClassInitFunc)purple_aes_cipher_class_init,
    - NULL,
    - NULL,
    - sizeof(PurpleAESCipher),
    - 0,
    - (GInstanceInitFunc)purple_aes_cipher_init,
    - NULL
    - };
    -
    - type = g_type_register_static(PURPLE_TYPE_CIPHER,
    - "PurpleAESCipher",
    - &info, 0);
    - }
    -
    - return type;
    -}
    -
    -PurpleCipher *
    -purple_aes_cipher_new(void) {
    - return g_object_new(PURPLE_TYPE_AES_CIPHER, NULL);
    -}
    --- a/libpurple/ciphers/aescipher.h Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,65 +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 PURPLE_AES_CIPHER_H
    -#define PURPLE_AES_CIPHER_H
    -/**
    - * SECTION:aescipher
    - * @section_id: libpurple-aescipher
    - * @short_description: <filename>ciphers/aescipher.h</filename>
    - * @title: AES Cipher
    - */
    -
    -#include "cipher.h"
    -
    -#define PURPLE_TYPE_AES_CIPHER (purple_aes_cipher_get_type())
    -#define PURPLE_AES_CIPHER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_AES_CIPHER, PurpleAESCipher))
    -#define PURPLE_AES_CIPHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_AES_CIPHER, PurpleAESCipherClass))
    -#define PURPLE_IS_AES_CIPHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_AES_CIPHER))
    -#define PURPLE_IS_AES_CIPHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((obj), PURPLE_TYPE_AES_CIPHER))
    -#define PURPLE_AES_CIPHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_AES_CIPHER, PurpleAESCipherClass))
    -
    -typedef struct _PurpleAESCipher PurpleAESCipher;
    -typedef struct _PurpleAESCipherClass PurpleAESCipherClass;
    -
    -struct _PurpleAESCipher {
    - PurpleCipher gparent;
    -};
    -
    -struct _PurpleAESCipherClass {
    - PurpleCipherClass gparent;
    -
    - /*< private >*/
    - void (*_purple_reserved1)(void);
    - void (*_purple_reserved2)(void);
    - void (*_purple_reserved3)(void);
    - void (*_purple_reserved4)(void);
    -};
    -
    -G_BEGIN_DECLS
    -
    -GType purple_aes_cipher_get_type(void);
    -
    -PurpleCipher *purple_aes_cipher_new(void);
    -
    -G_END_DECLS
    -
    -#endif /* PURPLE_AES_CIPHER_H */
    --- a/libpurple/ciphers/des3cipher.c Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,524 +0,0 @@
    -/*
    - * Original des taken from gpg
    - *
    - * des.c - Triple-DES encryption/decryption Algorithm
    - * Copyright (C) 1998 Free Software Foundation, Inc.
    - *
    - * Please see below for more legal information!
    - *
    - * According to the definition of DES in FIPS PUB 46-2 from December 1993.
    - * For a description of triple encryption, see:
    - * Bruce Schneier: Applied Cryptography. Second Edition.
    - * John Wiley & Sons, 1996. ISBN 0-471-12845-7. Pages 358 ff.
    - *
    - * 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 "glibcompat.h"
    -
    -#include "des3cipher.h"
    -#include "descipher.h"
    -#include "enums.h"
    -
    -#include <string.h>
    -
    -/******************************************************************************
    - * Structs
    - *****************************************************************************/
    -
    -#define PURPLE_DES3_CIPHER_GET_PRIVATE(obj) \
    - (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_DES3_CIPHER, PurpleDES3CipherPrivate))
    -
    -typedef struct _PurpleDES3CipherPrivate PurpleDES3CipherPrivate;
    -struct _PurpleDES3CipherPrivate
    -{
    - PurpleCipherBatchMode mode;
    - guchar iv[8];
    - /* First key for encryption */
    - PurpleCipher *key1;
    - /* Second key for decryption */
    - PurpleCipher *key2;
    - /* Third key for encryption */
    - PurpleCipher *key3;
    -};
    -
    -/******************************************************************************
    - * Enums
    - *****************************************************************************/
    -enum {
    - PROP_NONE,
    - PROP_BATCH_MODE,
    - PROP_IV,
    - PROP_KEY,
    - PROP_LAST,
    -};
    -
    -/******************************************************************************
    - * Globals
    - *****************************************************************************/
    -static GObjectClass *parent_class = NULL;
    -static GParamSpec *properties[PROP_LAST];
    -
    -/******************************************************************************
    - * Cipher Stuff
    - *****************************************************************************/
    -
    -static size_t
    -purple_des3_cipher_get_key_size(PurpleCipher *cipher)
    -{
    - return 24;
    -}
    -
    -/*
    - * Fill a DES3 context with subkeys calculated from 3 64bit key.
    - * Does not check parity bits, but simply ignore them.
    - * Does not check for weak keys.
    - **/
    -static void
    -purple_des3_cipher_set_key(PurpleCipher *cipher, const guchar *key, size_t len)
    -{
    - PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher);
    - PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
    -
    - g_return_if_fail(len == 24);
    -
    - purple_cipher_set_key(PURPLE_CIPHER(priv->key1), key + 0,
    - purple_cipher_get_key_size(PURPLE_CIPHER(priv->key1)));
    - purple_cipher_set_key(PURPLE_CIPHER(priv->key2), key + 8,
    - purple_cipher_get_key_size(PURPLE_CIPHER(priv->key2)));
    - purple_cipher_set_key(PURPLE_CIPHER(priv->key3), key + 16,
    - purple_cipher_get_key_size(PURPLE_CIPHER(priv->key3)));
    -
    - g_object_notify_by_pspec(G_OBJECT(cipher), properties[PROP_KEY]);
    -}
    -
    -static ssize_t
    -purple_des3_cipher_ecb_encrypt(PurpleDES3Cipher *des3_cipher, const guchar input[],
    - size_t in_len, guchar output[], size_t out_size)
    -{
    - gsize offset = 0;
    - int i = 0;
    - gsize tmp;
    - guint8 buf[8] = {0,0,0,0,0,0,0,0};
    - gsize out_len;
    - PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
    -
    - g_return_val_if_fail(out_size >= in_len, -1);
    -
    - while (offset + 8 <= in_len) {
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1),
    - input + offset, output + offset, 0);
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2),
    - output + offset, buf, 1);
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3),
    - buf, output + offset, 0);
    -
    - offset += 8;
    - }
    -
    - out_len = in_len;
    - if (offset < in_len) {
    - g_return_val_if_fail(in_len >= offset, -1);
    - out_len += in_len - offset;
    - g_return_val_if_fail(out_size >= out_len, -1);
    - tmp = offset;
    - memset(buf, 0, 8);
    - while (tmp < in_len) {
    - buf[i++] = input[tmp];
    - tmp++;
    - }
    -
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1),
    - buf, output + offset, 0);
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2),
    - output + offset, buf, 1);
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3),
    - buf, output + offset, 0);
    - }
    -
    - return out_len;
    -}
    -
    -static ssize_t
    -purple_des3_cipher_cbc_encrypt(PurpleDES3Cipher *des3_cipher, const guchar input[],
    - size_t in_len, guchar output[], size_t out_size)
    -{
    - gsize offset = 0;
    - int i = 0;
    - gsize tmp;
    - guint8 buf[8];
    - gsize out_len;
    - PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
    -
    - memcpy(buf, priv->iv, 8);
    -
    - g_return_val_if_fail(out_size >= in_len, -1);
    -
    - while (offset + 8 <= in_len) {
    - for (i = 0; i < 8; i++)
    - buf[i] ^= input[offset + i];
    -
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1),
    - buf, output + offset, 0);
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2),
    - output + offset, buf, 1);
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3),
    - buf, output + offset, 0);
    -
    - memcpy(buf, output+offset, 8);
    - offset += 8;
    - }
    -
    - out_len = in_len;
    - if (offset < in_len) {
    - g_return_val_if_fail(in_len >= offset, -1);
    - out_len += in_len - offset;
    - g_return_val_if_fail(out_size >= out_len, -1);
    - tmp = offset;
    - i = 0;
    - while (tmp < in_len) {
    - buf[i++] ^= input[tmp];
    - tmp++;
    - }
    -
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1),
    - buf, output + offset, 0);
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2),
    - output + offset, buf, 1);
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3),
    - buf, output + offset, 0);
    - }
    -
    - return out_len;
    -}
    -
    -static ssize_t
    -purple_des3_cipher_encrypt(PurpleCipher *cipher, const guchar input[],
    - size_t in_len, guchar output[], size_t out_size)
    -{
    - PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher);
    - PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
    -
    - if (priv->mode == PURPLE_CIPHER_BATCH_MODE_ECB) {
    - return purple_des3_cipher_ecb_encrypt(des3_cipher, input, in_len, output, out_size);
    - } else if (priv->mode == PURPLE_CIPHER_BATCH_MODE_CBC) {
    - return purple_des3_cipher_cbc_encrypt(des3_cipher, input, in_len, output, out_size);
    - } else {
    - g_return_val_if_reached(0);
    - }
    -
    - return 0;
    -}
    -
    -static ssize_t
    -purple_des3_cipher_ecb_decrypt(PurpleDES3Cipher *des3_cipher, const guchar input[],
    - size_t in_len, guchar output[], size_t out_size)
    -{
    - gsize offset = 0;
    - int i = 0;
    - gsize tmp;
    - guint8 buf[8] = {0,0,0,0,0,0,0,0};
    - gsize out_len;
    - PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
    -
    - g_return_val_if_fail(out_size >= in_len, -1);
    -
    - while (offset + 8 <= in_len) {
    - /* NOTE: Apply key in reverse */
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3),
    - input + offset, output + offset, 1);
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2),
    - output + offset, buf, 0);
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1),
    - buf, output + offset, 1);
    -
    - offset += 8;
    - }
    -
    - out_len = in_len;
    - if (offset < in_len) {
    - g_return_val_if_fail(in_len >= offset, -1);
    - out_len += in_len - offset;
    - g_return_val_if_fail(out_size >= out_len, -1);
    - tmp = offset;
    - memset(buf, 0, 8);
    - while (tmp < in_len) {
    - buf[i++] = input[tmp];
    - tmp++;
    - }
    -
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3),
    - buf, output + offset, 1);
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2),
    - output + offset, buf, 0);
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1),
    - buf, output + offset, 1);
    - }
    -
    - return out_len;
    -}
    -
    -static ssize_t
    -purple_des3_cipher_cbc_decrypt(PurpleDES3Cipher *des3_cipher, const guchar input[],
    - size_t in_len, guchar output[], size_t out_size)
    -{
    - gsize offset = 0;
    - int i = 0;
    - gsize tmp;
    - guint8 buf[8] = {0,0,0,0,0,0,0,0};
    - guint8 link[8];
    - gsize out_len;
    - PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
    -
    - g_return_val_if_fail(out_size >= in_len, -1);
    -
    - memcpy(link, priv->iv, 8);
    - while (offset + 8 <= in_len) {
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3),
    - input + offset, output + offset, 1);
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2),
    - output + offset, buf, 0);
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1),
    - buf, output + offset, 1);
    -
    - for (i = 0; i < 8; i++)
    - output[offset + i] ^= link[i];
    -
    - memcpy(link, input + offset, 8);
    -
    - offset+=8;
    - }
    -
    - out_len = in_len;
    - if(offset<in_len) {
    - g_return_val_if_fail(in_len >= offset, -1);
    - out_len += in_len - offset;
    - g_return_val_if_fail(out_size >= out_len, -1);
    - tmp = offset;
    - memset(buf, 0, 8);
    - i = 0;
    - while(tmp<in_len) {
    - buf[i++] = input[tmp];
    - tmp++;
    - }
    -
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3),
    - buf, output + offset, 1);
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2),
    - output + offset, buf, 0);
    - purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1),
    - buf, output + offset, 1);
    -
    - for (i = 0; i < 8; i++)
    - output[offset + i] ^= link[i];
    - }
    -
    - return out_len;
    -}
    -
    -static ssize_t
    -purple_des3_cipher_decrypt(PurpleCipher *cipher, const guchar input[],
    - size_t in_len, guchar output[], size_t out_size)
    -{
    - PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher);
    - PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(cipher);
    -
    - if (priv->mode == PURPLE_CIPHER_BATCH_MODE_ECB) {
    - return purple_des3_cipher_ecb_decrypt(des3_cipher, input, in_len, output, out_size);
    - } else if (priv->mode == PURPLE_CIPHER_BATCH_MODE_CBC) {
    - return purple_des3_cipher_cbc_decrypt(des3_cipher, input, in_len, output, out_size);
    - } else {
    - g_return_val_if_reached(0);
    - }
    -
    - return 0;
    -}
    -
    -static void
    -purple_des3_cipher_set_batch_mode(PurpleCipher *cipher, PurpleCipherBatchMode mode)
    -{
    - PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher);
    - PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
    -
    - priv->mode = mode;
    -
    - g_object_notify_by_pspec(G_OBJECT(cipher), properties[PROP_BATCH_MODE]);
    -}
    -
    -static PurpleCipherBatchMode
    -purple_des3_cipher_get_batch_mode(PurpleCipher *cipher)
    -{
    - PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher);
    - PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
    -
    - return priv->mode;
    -}
    -
    -static void
    -purple_des3_cipher_set_iv(PurpleCipher *cipher, guchar *iv, size_t len)
    -{
    - PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher);
    - PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
    -
    - g_return_if_fail(len == 8);
    -
    - memcpy(priv->iv, iv, len);
    -
    - g_object_notify_by_pspec(G_OBJECT(cipher), properties[PROP_IV]);
    -}
    -
    -/******************************************************************************
    - * Object Stuff
    - *****************************************************************************/
    -static void
    -purple_des3_cipher_get_property(GObject *obj, guint param_id, GValue *value,
    - GParamSpec *pspec)
    -{
    - PurpleCipher *cipher = PURPLE_CIPHER(obj);
    -
    - switch(param_id) {
    - case PROP_BATCH_MODE:
    - g_value_set_enum(value,
    - purple_cipher_get_batch_mode(cipher));
    - break;
    - default:
    - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
    - break;
    - }
    -}
    -
    -static void
    -purple_des3_cipher_set_property(GObject *obj, guint param_id,
    - const GValue *value, GParamSpec *pspec)
    -{
    - PurpleCipher *cipher = PURPLE_CIPHER(obj);
    -
    - switch(param_id) {
    - case PROP_BATCH_MODE:
    - purple_cipher_set_batch_mode(cipher,
    - g_value_get_enum(value));
    - break;
    - case PROP_IV:
    - {
    - guchar *iv = (guchar *)g_value_get_string(value);
    - purple_cipher_set_iv(cipher, iv, strlen((gchar*)iv));
    - }
    - break;
    - case PROP_KEY:
    - purple_cipher_set_key(cipher, (guchar *)g_value_get_string(value),
    - purple_des3_cipher_get_key_size(cipher));
    - break;
    - default:
    - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
    - break;
    - }
    -}
    -
    -static void
    -purple_des3_cipher_finalize(GObject *obj)
    -{
    - PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(obj);
    - PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
    -
    - g_object_unref(G_OBJECT(priv->key1));
    - g_object_unref(G_OBJECT(priv->key2));
    - g_object_unref(G_OBJECT(priv->key3));
    -
    - memset(priv->iv, 0, sizeof(priv->iv));
    -
    - parent_class->finalize(obj);
    -}
    -
    -static void
    -purple_des3_cipher_class_init(PurpleDES3CipherClass *klass) {
    - GObjectClass *obj_class = G_OBJECT_CLASS(klass);
    - PurpleCipherClass *cipher_class = PURPLE_CIPHER_CLASS(klass);
    -
    - parent_class = g_type_class_peek_parent(klass);
    -
    - obj_class->finalize = purple_des3_cipher_finalize;
    - obj_class->get_property = purple_des3_cipher_get_property;
    - obj_class->set_property = purple_des3_cipher_set_property;
    -
    - cipher_class->set_iv = purple_des3_cipher_set_iv;
    - cipher_class->encrypt = purple_des3_cipher_encrypt;
    - cipher_class->decrypt = purple_des3_cipher_decrypt;
    - cipher_class->set_key = purple_des3_cipher_set_key;
    - cipher_class->set_batch_mode = purple_des3_cipher_set_batch_mode;
    - cipher_class->get_batch_mode = purple_des3_cipher_get_batch_mode;
    - cipher_class->get_key_size = purple_des3_cipher_get_key_size;
    -
    - g_type_class_add_private(klass, sizeof(PurpleDES3CipherPrivate));
    -
    - properties[PROP_BATCH_MODE] = g_param_spec_enum("batch-mode", "batch-mode",
    - "batch-mode", PURPLE_TYPE_CIPHER_BATCH_MODE, 0,
    - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
    -
    - properties[PROP_IV] = g_param_spec_string("iv", "iv", "iv", NULL,
    - G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS);
    -
    - properties[PROP_KEY] = g_param_spec_string("key", "key", "key", NULL,
    - G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS);
    -
    - g_object_class_install_properties(obj_class, PROP_LAST, properties);
    -}
    -
    -static void
    -purple_des3_cipher_init(PurpleCipher *cipher) {
    - PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher);
    - PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher);
    -
    - priv->key1 = purple_des_cipher_new();
    - priv->key2 = purple_des_cipher_new();
    - priv->key3 = purple_des_cipher_new();
    -}
    -
    -/******************************************************************************
    - * API
    - *****************************************************************************/
    -GType
    -purple_des3_cipher_get_type(void) {
    - static GType type = 0;
    -
    - if(type == 0) {
    - static const GTypeInfo info = {
    - sizeof(PurpleDES3CipherClass),
    - NULL,
    - NULL,
    - (GClassInitFunc)purple_des3_cipher_class_init,
    - NULL,
    - NULL,
    - sizeof(PurpleDES3Cipher),
    - 0,
    - (GInstanceInitFunc)purple_des3_cipher_init,
    - NULL
    - };
    -
    - type = g_type_register_static(PURPLE_TYPE_CIPHER,
    - "PurpleDES3Cipher",
    - &info, 0);
    - }
    -
    - return type;
    -}
    -
    -PurpleCipher *
    -purple_des3_cipher_new(void) {
    - return g_object_new(PURPLE_TYPE_DES3_CIPHER, NULL);
    -}
    --- a/libpurple/ciphers/des3cipher.h Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,66 +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 PURPLE_DES3_CIPHER_H
    -#define PURPLE_DES3_CIPHER_H
    -/**
    - * SECTION:des3cipher
    - * @section_id: libpurple-des3cipher
    - * @short_description: <filename>ciphers/des3cipher.h</filename>
    - * @title: Triple-DES Cipher
    - */
    -
    -#include "cipher.h"
    -
    -#define PURPLE_TYPE_DES3_CIPHER (purple_des3_cipher_get_type())
    -#define PURPLE_DES3_CIPHER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_DES3_CIPHER, PurpleDES3Cipher))
    -#define PURPLE_DES3_CIPHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_DES3_CIPHER, PurpleDES3CipherClass))
    -#define PURPLE_IS_DES3_CIPHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_DES3_CIPHER))
    -#define PURPLE_IS_DES3_CIPHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((obj), PURPLE_TYPE_DES3_CIPHER))
    -#define PURPLE_DES3_CIPHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_DES3_CIPHER, PurpleDES3CipherClass))
    -
    -typedef struct _PurpleDES3Cipher PurpleDES3Cipher;
    -typedef struct _PurpleDES3CipherClass PurpleDES3CipherClass;
    -
    -struct _PurpleDES3Cipher {
    - PurpleCipher gparent;
    -};
    -
    -struct _PurpleDES3CipherClass {
    - PurpleCipherClass gparent;
    -
    - /*< private >*/
    - void (*_purple_reserved1)(void);
    - void (*_purple_reserved2)(void);
    - void (*_purple_reserved3)(void);
    - void (*_purple_reserved4)(void);
    -};
    -
    -G_BEGIN_DECLS
    -
    -GType purple_des3_cipher_get_type(void);
    -
    -PurpleCipher *purple_des3_cipher_new(void);
    -
    -G_END_DECLS
    -
    -#endif /* PURPLE_DES3_CIPHER_H */
    -
    --- a/libpurple/ciphers/descipher.c Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,581 +0,0 @@
    -/*
    - * Original des taken from gpg
    - *
    - * des.c - DES encryption/decryption Algorithm
    - * Copyright (C) 1998 Free Software Foundation, Inc.
    - *
    - * Please see below for more legal information!
    - *
    - * According to the definition of DES in FIPS PUB 46-2 from December 1993.
    - * For a description of triple encryption, see:
    - * Bruce Schneier: Applied Cryptography. Second Edition.
    - * John Wiley & Sons, 1996. ISBN 0-471-12845-7. Pages 358 ff.
    - *
    - * 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 "glibcompat.h"
    -
    -#include "descipher.h"
    -#include "enums.h"
    -
    -#include <string.h>
    -
    -/******************************************************************************
    - * Structs
    - *****************************************************************************/
    -#define PURPLE_DES_CIPHER_GET_PRIVATE(obj) \
    - (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_DES_CIPHER, PurpleDESCipherPrivate))
    -
    -typedef struct {
    - guint32 encrypt_subkeys[32];
    - guint32 decrypt_subkeys[32];
    -} PurpleDESCipherPrivate;
    -
    -/******************************************************************************
    - * Enums
    - *****************************************************************************/
    -enum {
    - PROP_NONE,
    - PROP_KEY,
    - PROP_LAST,
    -};
    -
    -/******************************************************************************
    - * Globals
    - *****************************************************************************/
    -static GObjectClass *parent_class = NULL;
    -static GParamSpec *properties[PROP_LAST];
    -
    -/*
    - * The s-box values are permuted according to the 'primitive function P'
    - */
    -static guint32 sbox1[64] = {
    - 0x00808200, 0x00000000, 0x00008000, 0x00808202, 0x00808002, 0x00008202,
    - 0x00000002, 0x00008000, 0x00000200, 0x00808200, 0x00808202, 0x00000200,
    - 0x00800202, 0x00808002, 0x00800000, 0x00000002, 0x00000202, 0x00800200,
    - 0x00800200, 0x00008200, 0x00008200, 0x00808000, 0x00808000, 0x00800202,
    - 0x00008002, 0x00800002, 0x00800002, 0x00008002, 0x00000000, 0x00000202,
    - 0x00008202, 0x00800000, 0x00008000, 0x00808202, 0x00000002, 0x00808000,
    - 0x00808200, 0x00800000, 0x00800000, 0x00000200, 0x00808002, 0x00008000,
    - 0x00008200, 0x00800002, 0x00000200, 0x00000002, 0x00800202, 0x00008202,
    - 0x00808202, 0x00008002, 0x00808000, 0x00800202, 0x00800002, 0x00000202,
    - 0x00008202, 0x00808200, 0x00000202, 0x00800200, 0x00800200, 0x00000000,
    - 0x00008002, 0x00008200, 0x00000000, 0x00808002
    -};
    -
    -static guint32 sbox2[64] = {
    - 0x40084010, 0x40004000, 0x00004000, 0x00084010, 0x00080000, 0x00000010,
    - 0x40080010, 0x40004010, 0x40000010, 0x40084010, 0x40084000, 0x40000000,
    - 0x40004000, 0x00080000, 0x00000010, 0x40080010, 0x00084000, 0x00080010,
    - 0x40004010, 0x00000000, 0x40000000, 0x00004000, 0x00084010, 0x40080000,
    - 0x00080010, 0x40000010, 0x00000000, 0x00084000, 0x00004010, 0x40084000,
    - 0x40080000, 0x00004010, 0x00000000, 0x00084010, 0x40080010, 0x00080000,
    - 0x40004010, 0x40080000, 0x40084000, 0x00004000, 0x40080000, 0x40004000,
    - 0x00000010, 0x40084010, 0x00084010, 0x00000010, 0x00004000, 0x40000000,
    - 0x00004010, 0x40084000, 0x00080000, 0x40000010, 0x00080010, 0x40004010,
    - 0x40000010, 0x00080010, 0x00084000, 0x00000000, 0x40004000, 0x00004010,
    - 0x40000000, 0x40080010, 0x40084010, 0x00084000
    -};
    -
    -static guint32 sbox3[64] = {
    - 0x00000104, 0x04010100, 0x00000000, 0x04010004, 0x04000100, 0x00000000,
    - 0x00010104, 0x04000100, 0x00010004, 0x04000004, 0x04000004, 0x00010000,
    - 0x04010104, 0x00010004, 0x04010000, 0x00000104, 0x04000000, 0x00000004,
    - 0x04010100, 0x00000100, 0x00010100, 0x04010000, 0x04010004, 0x00010104,
    - 0x04000104, 0x00010100, 0x00010000, 0x04000104, 0x00000004, 0x04010104,
    - 0x00000100, 0x04000000, 0x04010100, 0x04000000, 0x00010004, 0x00000104,
    - 0x00010000, 0x04010100, 0x04000100, 0x00000000, 0x00000100, 0x00010004,
    - 0x04010104, 0x04000100, 0x04000004, 0x00000100, 0x00000000, 0x04010004,
    - 0x04000104, 0x00010000, 0x04000000, 0x04010104, 0x00000004, 0x00010104,
    - 0x00010100, 0x04000004, 0x04010000, 0x04000104, 0x00000104, 0x04010000,
    - 0x00010104, 0x00000004, 0x04010004, 0x00010100
    -};
    -
    -static guint32 sbox4[64] = {
    - 0x80401000, 0x80001040, 0x80001040, 0x00000040, 0x00401040, 0x80400040,
    - 0x80400000, 0x80001000, 0x00000000, 0x00401000, 0x00401000, 0x80401040,
    - 0x80000040, 0x00000000, 0x00400040, 0x80400000, 0x80000000, 0x00001000,
    - 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x80001000, 0x00001040,
    - 0x80400040, 0x80000000, 0x00001040, 0x00400040, 0x00001000, 0x00401040,
    - 0x80401040, 0x80000040, 0x00400040, 0x80400000, 0x00401000, 0x80401040,
    - 0x80000040, 0x00000000, 0x00000000, 0x00401000, 0x00001040, 0x00400040,
    - 0x80400040, 0x80000000, 0x80401000, 0x80001040, 0x80001040, 0x00000040,
    - 0x80401040, 0x80000040, 0x80000000, 0x00001000, 0x80400000, 0x80001000,
    - 0x00401040, 0x80400040, 0x80001000, 0x00001040, 0x00400000, 0x80401000,
    - 0x00000040, 0x00400000, 0x00001000, 0x00401040
    -};
    -
    -static guint32 sbox5[64] = {
    - 0x00000080, 0x01040080, 0x01040000, 0x21000080, 0x00040000, 0x00000080,
    - 0x20000000, 0x01040000, 0x20040080, 0x00040000, 0x01000080, 0x20040080,
    - 0x21000080, 0x21040000, 0x00040080, 0x20000000, 0x01000000, 0x20040000,
    - 0x20040000, 0x00000000, 0x20000080, 0x21040080, 0x21040080, 0x01000080,
    - 0x21040000, 0x20000080, 0x00000000, 0x21000000, 0x01040080, 0x01000000,
    - 0x21000000, 0x00040080, 0x00040000, 0x21000080, 0x00000080, 0x01000000,
    - 0x20000000, 0x01040000, 0x21000080, 0x20040080, 0x01000080, 0x20000000,
    - 0x21040000, 0x01040080, 0x20040080, 0x00000080, 0x01000000, 0x21040000,
    - 0x21040080, 0x00040080, 0x21000000, 0x21040080, 0x01040000, 0x00000000,
    - 0x20040000, 0x21000000, 0x00040080, 0x01000080, 0x20000080, 0x00040000,
    - 0x00000000, 0x20040000, 0x01040080, 0x20000080
    -};
    -
    -static guint32 sbox6[64] = {
    - 0x10000008, 0x10200000, 0x00002000, 0x10202008, 0x10200000, 0x00000008,
    - 0x10202008, 0x00200000, 0x10002000, 0x00202008, 0x00200000, 0x10000008,
    - 0x00200008, 0x10002000, 0x10000000, 0x00002008, 0x00000000, 0x00200008,
    - 0x10002008, 0x00002000, 0x00202000, 0x10002008, 0x00000008, 0x10200008,
    - 0x10200008, 0x00000000, 0x00202008, 0x10202000, 0x00002008, 0x00202000,
    - 0x10202000, 0x10000000, 0x10002000, 0x00000008, 0x10200008, 0x00202000,
    - 0x10202008, 0x00200000, 0x00002008, 0x10000008, 0x00200000, 0x10002000,
    - 0x10000000, 0x00002008, 0x10000008, 0x10202008, 0x00202000, 0x10200000,
    - 0x00202008, 0x10202000, 0x00000000, 0x10200008, 0x00000008, 0x00002000,
    - 0x10200000, 0x00202008, 0x00002000, 0x00200008, 0x10002008, 0x00000000,
    - 0x10202000, 0x10000000, 0x00200008, 0x10002008
    -};
    -
    -static guint32 sbox7[64] = {
    - 0x00100000, 0x02100001, 0x02000401, 0x00000000, 0x00000400, 0x02000401,
    - 0x00100401, 0x02100400, 0x02100401, 0x00100000, 0x00000000, 0x02000001,
    - 0x00000001, 0x02000000, 0x02100001, 0x00000401, 0x02000400, 0x00100401,
    - 0x00100001, 0x02000400, 0x02000001, 0x02100000, 0x02100400, 0x00100001,
    - 0x02100000, 0x00000400, 0x00000401, 0x02100401, 0x00100400, 0x00000001,
    - 0x02000000, 0x00100400, 0x02000000, 0x00100400, 0x00100000, 0x02000401,
    - 0x02000401, 0x02100001, 0x02100001, 0x00000001, 0x00100001, 0x02000000,
    - 0x02000400, 0x00100000, 0x02100400, 0x00000401, 0x00100401, 0x02100400,
    - 0x00000401, 0x02000001, 0x02100401, 0x02100000, 0x00100400, 0x00000000,
    - 0x00000001, 0x02100401, 0x00000000, 0x00100401, 0x02100000, 0x00000400,
    - 0x02000001, 0x02000400, 0x00000400, 0x00100001
    -};
    -
    -static guint32 sbox8[64] = {
    - 0x08000820, 0x00000800, 0x00020000, 0x08020820, 0x08000000, 0x08000820,
    - 0x00000020, 0x08000000, 0x00020020, 0x08020000, 0x08020820, 0x00020800,
    - 0x08020800, 0x00020820, 0x00000800, 0x00000020, 0x08020000, 0x08000020,
    - 0x08000800, 0x00000820, 0x00020800, 0x00020020, 0x08020020, 0x08020800,
    - 0x00000820, 0x00000000, 0x00000000, 0x08020020, 0x08000020, 0x08000800,
    - 0x00020820, 0x00020000, 0x00020820, 0x00020000, 0x08020800, 0x00000800,
    - 0x00000020, 0x08020020, 0x00000800, 0x00020820, 0x08000800, 0x00000020,
    - 0x08000020, 0x08020000, 0x08020020, 0x08000000, 0x00020000, 0x08000820,
    - 0x00000000, 0x08020820, 0x00020020, 0x08000020, 0x08020000, 0x08000800,
    - 0x08000820, 0x00000000, 0x08020820, 0x00020800, 0x00020800, 0x00000820,
    - 0x00000820, 0x00020020, 0x08000000, 0x08020800
    -};
    -
    -/*
    - * These two tables are part of the 'permuted choice 1' function.
    - * In this implementation several speed improvements are done.
    - */
    -static guint32 leftkey_swap[16] = {
    - 0x00000000, 0x00000001, 0x00000100, 0x00000101, 0x00010000, 0x00010001,
    - 0x00010100, 0x00010101, 0x01000000, 0x01000001, 0x01000100, 0x01000101,
    - 0x01010000, 0x01010001, 0x01010100, 0x01010101
    -};
    -
    -static guint32 rightkey_swap[16] = {
    - 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100,
    - 0x00010100, 0x01010100, 0x00000001, 0x01000001, 0x00010001, 0x01010001,
    - 0x00000101, 0x01000101, 0x00010101, 0x01010101,
    -};
    -
    -/*
    - * Numbers of left shifts per round for encryption subkey schedule
    - * To calculate the decryption key scheduling we just reverse the
    - * ordering of the subkeys so we can omit the table for decryption
    - * subkey schedule.
    - */
    -static guint8 encrypt_rotate_tab[16] = {
    - 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
    -};
    -
    -
    -/******************************************************************************
    - * Helpers
    - *****************************************************************************/
    -/*
    - * Macro to swap bits across two words
    - */
    -#define DO_PERMUTATION(a, temp, b, offset, mask) \
    - temp = ((a>>offset) ^ b) & mask; \
    - b ^= temp; \
    - a ^= temp<<offset;
    -
    -/*
    - * This performs the 'initial permutation' for the data to be encrypted or
    - * decrypted
    - */
    -#define INITIAL_PERMUTATION(left, temp, right) \
    - DO_PERMUTATION(left, temp, right, 4, 0x0f0f0f0f) \
    - DO_PERMUTATION(left, temp, right, 16, 0x0000ffff) \
    - DO_PERMUTATION(right, temp, left, 2, 0x33333333) \
    - DO_PERMUTATION(right, temp, left, 8, 0x00ff00ff) \
    - DO_PERMUTATION(left, temp, right, 1, 0x55555555)
    -
    -/*
    - * The 'inverse initial permutation'
    - */
    -#define FINAL_PERMUTATION(left, temp, right) \
    - DO_PERMUTATION(left, temp, right, 1, 0x55555555) \
    - DO_PERMUTATION(right, temp, left, 8, 0x00ff00ff) \
    - DO_PERMUTATION(right, temp, left, 2, 0x33333333) \
    - DO_PERMUTATION(left, temp, right, 16, 0x0000ffff) \
    - DO_PERMUTATION(left, temp, right, 4, 0x0f0f0f0f)
    -
    -/*
    - * A full DES round including 'expansion function', 'sbox substitution'
    - * and 'primitive function P' but without swapping the left and right word.
    - */
    -#define DES_ROUND(from, to, work, subkey) \
    - work = ((from<<1) | (from>>31)) ^ *subkey++; \
    - to ^= sbox8[ work & 0x3f ]; \
    - to ^= sbox6[ (work>>8) & 0x3f ]; \
    - to ^= sbox4[ (work>>16) & 0x3f ]; \
    - to ^= sbox2[ (work>>24) & 0x3f ]; \
    - work = ((from>>3) | (from<<29)) ^ *subkey++; \
    - to ^= sbox7[ work & 0x3f ]; \
    - to ^= sbox5[ (work>>8) & 0x3f ]; \
    - to ^= sbox3[ (work>>16) & 0x3f ]; \
    - to ^= sbox1[ (work>>24) & 0x3f ];
    -
    -
    -/*
    - * Macros to convert 8 bytes from/to 32bit words
    - */
    -#define READ_64BIT_DATA(data, left, right) \
    - left = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; \
    - right = (data[4] << 24) | (data[5] << 16) | (data[6] << 8) | data[7];
    -
    -#define WRITE_64BIT_DATA(data, left, right) \
    - data[0] = (left >> 24) &0xff; data[1] = (left >> 16) &0xff; \
    - data[2] = (left >> 8) &0xff; data[3] = left &0xff; \
    - data[4] = (right >> 24) &0xff; data[5] = (right >> 16) &0xff; \
    - data[6] = (right >> 8) &0xff; data[7] = right &0xff;
    -
    -/******************************************************************************
    - * Cipher Stuff
    - *****************************************************************************/
    -/*
    - * des_key_schedule(): Calculate 16 subkeys pairs (even/odd) for
    - * 16 encryption rounds.
    - * To calculate subkeys for decryption the caller
    - * have to reorder the generated subkeys.
    - *
    - * rawkey: 8 Bytes of key data
    - * subkey: Array of at least 32 guint32s. Will be filled
    - * with calculated subkeys.
    - *
    - */
    -static void
    -purple_des_cipher_key_schedule(const guint8 * rawkey, guint32 * subkey) {
    - guint32 left, right, work;
    - int round;
    -
    - READ_64BIT_DATA (rawkey, left, right)
    -
    - DO_PERMUTATION (right, work, left, 4, 0x0f0f0f0f)
    - DO_PERMUTATION (right, work, left, 0, 0x10101010)
    -
    - left = (leftkey_swap[(left >> 0) & 0xf] << 3)
    - | (leftkey_swap[(left >> 8) & 0xf] << 2)
    - | (leftkey_swap[(left >> 16) & 0xf] << 1)
    - | (leftkey_swap[(left >> 24) & 0xf] )
    - | (leftkey_swap[(left >> 5) & 0xf] << 7)
    - | (leftkey_swap[(left >> 13) & 0xf] << 6)
    - | (leftkey_swap[(left >> 21) & 0xf] << 5)
    - | (leftkey_swap[(left >> 29) & 0xf] << 4);
    -
    - left &= 0x0fffffff;
    -
    - right = (rightkey_swap[(right >> 1) & 0xf] << 3)
    - | (rightkey_swap[(right >> 9) & 0xf] << 2)
    - | (rightkey_swap[(right >> 17) & 0xf] << 1)
    - | (rightkey_swap[(right >> 25) & 0xf] )
    - | (rightkey_swap[(right >> 4) & 0xf] << 7)
    - | (rightkey_swap[(right >> 12) & 0xf] << 6)
    - | (rightkey_swap[(right >> 20) & 0xf] << 5)
    - | (rightkey_swap[(right >> 28) & 0xf] << 4);
    -
    - right &= 0x0fffffff;
    -
    - for (round = 0; round < 16; ++round) {
    - left = ((left << encrypt_rotate_tab[round]) |
    - (left >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff;
    - right = ((right << encrypt_rotate_tab[round]) |
    - (right >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff;
    -
    - *subkey++ = ((left << 4) & 0x24000000)
    - | ((left << 28) & 0x10000000)
    - | ((left << 14) & 0x08000000)
    - | ((left << 18) & 0x02080000)
    - | ((left << 6) & 0x01000000)
    - | ((left << 9) & 0x00200000)
    - | ((left >> 1) & 0x00100000)
    - | ((left << 10) & 0x00040000)
    - | ((left << 2) & 0x00020000)
    - | ((left >> 10) & 0x00010000)
    - | ((right >> 13) & 0x00002000)
    - | ((right >> 4) & 0x00001000)
    - | ((right << 6) & 0x00000800)
    - | ((right >> 1) & 0x00000400)
    - | ((right >> 14) & 0x00000200)
    - | (right & 0x00000100)
    - | ((right >> 5) & 0x00000020)
    - | ((right >> 10) & 0x00000010)
    - | ((right >> 3) & 0x00000008)
    - | ((right >> 18) & 0x00000004)
    - | ((right >> 26) & 0x00000002)
    - | ((right >> 24) & 0x00000001);
    -
    - *subkey++ = ((left << 15) & 0x20000000)
    - | ((left << 17) & 0x10000000)
    - | ((left << 10) & 0x08000000)
    - | ((left << 22) & 0x04000000)
    - | ((left >> 2) & 0x02000000)
    - | ((left << 1) & 0x01000000)
    - | ((left << 16) & 0x00200000)
    - | ((left << 11) & 0x00100000)
    - | ((left << 3) & 0x00080000)
    - | ((left >> 6) & 0x00040000)
    - | ((left << 15) & 0x00020000)
    - | ((left >> 4) & 0x00010000)
    - | ((right >> 2) & 0x00002000)
    - | ((right << 8) & 0x00001000)
    - | ((right >> 14) & 0x00000808)
    - | ((right >> 9) & 0x00000400)
    - | ((right) & 0x00000200)
    - | ((right << 7) & 0x00000100)
    - | ((right >> 7) & 0x00000020)
    - | ((right >> 3) & 0x00000011)
    - | ((right << 2) & 0x00000004)
    - | ((right >> 21) & 0x00000002);
    - }
    -}
    -
    -/*
    - * Fill a DES context with subkeys calculated from a 64bit key.
    - * Does not check parity bits, but simply ignore them.
    - * Does not check for weak keys.
    - */
    -static void
    -purple_des_cipher_set_key(PurpleCipher *cipher, const guchar *key, size_t len) {
    - PurpleDESCipher *des_cipher = PURPLE_DES_CIPHER(cipher);
    - PurpleDESCipherPrivate *priv = PURPLE_DES_CIPHER_GET_PRIVATE(des_cipher);
    - int i;
    -
    - g_return_if_fail(len == 8);
    -
    - purple_des_cipher_key_schedule(key, priv->encrypt_subkeys);
    -
    - for(i = 0; i < 32; i += 2) {
    - priv->decrypt_subkeys[i] = priv->encrypt_subkeys[30 - i];
    - priv->decrypt_subkeys[i + 1] = priv->encrypt_subkeys[31 - i];
    - }
    -
    - g_object_notify_by_pspec(G_OBJECT(cipher), properties[PROP_KEY]);
    -}
    -
    -static size_t
    -purple_des_cipher_get_key_size(PurpleCipher *cipher)
    -{
    - return 8;
    -}
    -
    -/*
    - * Electronic Codebook Mode DES encryption/decryption of data according to
    - * 'mode'.
    - */
    -int
    -purple_des_cipher_ecb_crypt(PurpleDESCipher *des_cipher, const guint8 * from, guint8 * to,
    - int mode)
    -{
    - guint32 left, right, work;
    - guint32 *keys;
    - PurpleDESCipherPrivate *priv = PURPLE_DES_CIPHER_GET_PRIVATE(des_cipher);
    -
    - keys = mode ? priv->decrypt_subkeys :
    - priv->encrypt_subkeys;
    -
    - READ_64BIT_DATA (from, left, right)
    - INITIAL_PERMUTATION (left, work, right)
    -
    - DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
    - DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
    - DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
    - DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
    - DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
    - DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
    - DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
    - DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
    -
    - FINAL_PERMUTATION (right, work, left)
    - WRITE_64BIT_DATA (to, right, left)
    -
    - return 0;
    -}
    -
    -static ssize_t
    -purple_des_cipher_encrypt(PurpleCipher *cipher, const guchar input[],
    - size_t in_len, guchar output[], size_t out_size)
    -{
    - PurpleDESCipher *des_cipher = PURPLE_DES_CIPHER(cipher);
    -
    - gsize offset = 0;
    - int i = 0;
    - gsize tmp;
    - guint8 buf[8] = {0,0,0,0,0,0,0,0};
    - gsize out_len;
    -
    - g_return_val_if_fail(out_size >= in_len, -1);
    -
    - while(offset + 8 <= in_len) {
    - purple_des_cipher_ecb_crypt(des_cipher, input + offset, output + offset, 0);
    - offset += 8;
    - }
    -
    - out_len = in_len;
    -
    - if(offset<in_len) {
    - g_return_val_if_fail(in_len >= offset, -1);
    - out_len += in_len - offset;
    - g_return_val_if_fail(out_size >= out_len, -1);
    - tmp = offset;
    - while(tmp<in_len) {
    - buf[i++] = input[tmp];
    - tmp++;
    - }
    -
    - purple_des_cipher_ecb_crypt(des_cipher, buf, output + offset, 0);
    - }
    -
    - return out_len;
    -}
    -
    -static ssize_t
    -purple_des_cipher_decrypt(PurpleCipher *cipher, const guchar input[],
    - size_t in_len, guchar output[], size_t out_size)
    -{
    - PurpleDESCipher *des_cipher = PURPLE_DES_CIPHER(cipher);
    -
    - gsize offset = 0;
    - int i = 0;
    - gsize tmp;
    - guint8 buf[8] = {0,0,0,0,0,0,0,0};
    - gsize out_len;
    -
    - g_return_val_if_fail(out_size >= in_len, -1);
    -
    - while(offset + 8 <= in_len) {
    - purple_des_cipher_ecb_crypt(des_cipher, input + offset, output + offset, 1);
    - offset += 8;
    - }
    -
    - out_len = in_len;
    - if(offset<in_len) {
    - g_return_val_if_fail(in_len >= offset, -1);
    - out_len += in_len - offset;
    - g_return_val_if_fail(out_size >= out_len, -1);
    - tmp = offset;
    - while(tmp<in_len) {
    - buf[i++] = input[tmp];
    - tmp++;
    - }
    -
    - purple_des_cipher_ecb_crypt(des_cipher, buf, output + offset, 1);
    - }
    -
    - return out_len;
    -}
    -
    -/******************************************************************************
    - * Object Stuff
    - *****************************************************************************/
    -static void
    -purple_des_cipher_set_property(GObject *obj, guint param_id,
    - const GValue *value, GParamSpec *pspec)
    -{
    - PurpleCipher *cipher = PURPLE_CIPHER(obj);
    -
    - switch(param_id) {
    - case PROP_KEY:
    - purple_cipher_set_key(cipher, (guchar *)g_value_get_string(value),
    - purple_des_cipher_get_key_size(cipher));
    - break;
    - default:
    - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
    - break;
    - }
    -}
    -
    -static void
    -purple_des_cipher_class_init(PurpleDESCipherClass *klass)
    -{
    - GObjectClass *obj_class = G_OBJECT_CLASS(klass);
    - PurpleCipherClass *cipher_class = PURPLE_CIPHER_CLASS(klass);
    -
    - parent_class = g_type_class_peek_parent(klass);
    -
    - obj_class->set_property = purple_des_cipher_set_property;
    -
    - cipher_class->encrypt = purple_des_cipher_encrypt;
    - cipher_class->decrypt = purple_des_cipher_decrypt;
    - cipher_class->set_key = purple_des_cipher_set_key;
    - cipher_class->get_key_size = purple_des_cipher_get_key_size;
    -
    - g_type_class_add_private(klass, sizeof(PurpleDESCipherPrivate));
    -
    - properties[PROP_KEY] = g_param_spec_string("key", "key", "key", NULL,
    - G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS);
    -
    - g_object_class_install_properties(obj_class, PROP_LAST, properties);
    -}
    -
    -/******************************************************************************
    - * API
    - *****************************************************************************/
    -GType
    -purple_des_cipher_get_type(void) {
    - static GType type = 0;
    -
    - if(type == 0) {
    - static const GTypeInfo info = {
    - .class_size = sizeof(PurpleDESCipherClass),
    - .class_init = (GClassInitFunc)purple_des_cipher_class_init,
    - .instance_size = sizeof(PurpleDESCipher),
    - .instance_init = (GInstanceInitFunc)purple_cipher_reset,
    - };
    -
    - type = g_type_register_static(PURPLE_TYPE_CIPHER,
    - "PurpleDESCipher",
    - &info, 0);
    - }
    -
    - return type;
    -}
    -
    -/**
    - * purple_des_cipher_new:
    - *
    - * Creates a new #PurpleCipher instance which implements the DES block cipher.
    - *
    - * Return Value: The new DES implementation of #PurpleCipher.
    - */
    -PurpleCipher *
    -purple_des_cipher_new(void) {
    - return g_object_new(PURPLE_TYPE_DES_CIPHER, NULL);
    -}
    --- a/libpurple/ciphers/descipher.h Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,67 +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    - */
    -
    -#ifndef PURPLE_DES_CIPHER_H
    -#define PURPLE_DES_CIPHER_H
    -/**
    - * SECTION:descipher
    - * @section_id: libpurple-descipher
    - * @short_description: <filename>ciphers/descipher.h</filename>
    - * @title: DES Cipher
    - */
    -
    -#include "cipher.h"
    -
    -#define PURPLE_TYPE_DES_CIPHER (purple_des_cipher_get_type())
    -#define PURPLE_DES_CIPHER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_DES_CIPHER, PurpleDESCipher))
    -#define PURPLE_DES_CIPHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_DES_CIPHER, PurpleDESCipherClass))
    -#define PURPLE_IS_DES_CIPHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_DES_CIPHER))
    -#define PURPLE_IS_DES_CIPHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((obj), PURPLE_TYPE_DES_CIPHER))
    -#define PURPLE_DES_CIPHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_DES_CIPHER, PurpleDESCipherClass))
    -
    -typedef struct _PurpleDESCipher PurpleDESCipher;
    -typedef struct _PurpleDESCipherClass PurpleDESCipherClass;
    -
    -struct _PurpleDESCipher {
    - PurpleCipher gparent;
    -};
    -
    -struct _PurpleDESCipherClass {
    - PurpleCipherClass gparent;
    -
    - /*< private >*/
    - void (*_purple_reserved1)(void);
    - void (*_purple_reserved2)(void);
    - void (*_purple_reserved3)(void);
    - void (*_purple_reserved4)(void);
    -};
    -
    -G_BEGIN_DECLS
    -
    -GType purple_des_cipher_get_type(void);
    -
    -PurpleCipher *purple_des_cipher_new(void);
    -
    -int purple_des_cipher_ecb_crypt(PurpleDESCipher *des_cipher, const guint8 * from, guint8 * to, int mode);
    -
    -G_END_DECLS
    -
    -#endif /* PURPLE_DES_CIPHER_H */
    --- a/libpurple/ciphers/md4hash.c Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,311 +0,0 @@
    -/*
    - * Original md4 taken from linux kernel
    - * MD4 Message Digest Algorithm (RFC1320).
    - *
    - * Implementation derived from Andrew Tridgell and Steve French's
    - * CIFS MD4 implementation, and the cryptoapi implementation
    - * originally based on the public domain implementation written
    - * by Colin Plumb in 1993.
    - *
    - * Copyright (c) Andrew Tridgell 1997-1998.
    - * Modified by Steve French (sfrench@us.ibm.com) 2002
    - * Copyright (c) Cryptoapi developers.
    - * Copyright (c) 2002 David S. Miller (davem@redhat.com)
    - * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
    - */
    -#include "internal.h"
    -#include "md4hash.h"
    -
    -#include <string.h>
    -
    -#define MD4_DIGEST_SIZE 16
    -#define MD4_BLOCK_WORDS 16
    -#define MD4_HASH_WORDS 4
    -
    -#define PURPLE_MD4_HASH_GET_PRIVATE(obj) \
    - (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MD4_HASH, PurpleMD4HashPrivate))
    -
    -/******************************************************************************
    - * Structs
    - *****************************************************************************/
    -typedef struct {
    - guint32 hash[MD4_HASH_WORDS];
    - guint32 block[MD4_BLOCK_WORDS];
    - guint64 byte_count;
    -} PurpleMD4HashPrivate;
    -
    -/******************************************************************************
    - * Globals
    - *****************************************************************************/
    -static GObjectClass *parent_class = NULL;
    -
    -/******************************************************************************
    - * Helpers
    - *****************************************************************************/
    -#define ROUND1(a,b,c,d,k,s) \
    - (a = lshift(a + F(b,c,d) + k, s))
    -
    -#define ROUND2(a,b,c,d,k,s) \
    - (a = lshift(a + G(b,c,d) + k + (guint32)0x5a827999,s))
    -
    -#define ROUND3(a,b,c,d,k,s) \
    - (a = lshift(a + H(b,c,d) + k + (guint32)0x6ed9eba1,s))
    -
    -static inline guint32
    -lshift(guint32 x, unsigned int s) {
    - x &= 0xffffffff;
    - return (((x << s) & 0xffffffff) | (x >> (32 - s)));
    -}
    -
    -static inline guint32
    -F(guint32 x, guint32 y, guint32 z) {
    - return ((x & y) | ((~x) & z));
    -}
    -
    -static inline guint32
    -G(guint32 x, guint32 y, guint32 z) {
    - return ((x & y) | (x & z) | (y & z));
    -}
    -
    -static inline guint32
    -H(guint32 x, guint32 y, guint32 z) {
    - return (x ^ y ^ z);
    -}
    -
    -static inline void
    -le32_to_cpu_array(guint32 *buf, unsigned int words) {
    - while(words--) {
    - *buf = GUINT_FROM_LE(*buf);
    - buf++;
    - }
    -}
    -
    -static inline void
    -cpu_to_le32_array(guint32 *buf, unsigned int words) {
    - while(words--) {
    - *buf = GUINT_TO_LE(*buf);
    - buf++;
    - }
    -}
    -
    -static void
    -md4_transform(guint32 *hash, guint32 const *in) {
    - guint32 a, b, c, d;
    -
    - a = hash[0];
    - b = hash[1];
    - c = hash[2];
    - d = hash[3];
    -
    - ROUND1(a, b, c, d, in[0], 3);
    - ROUND1(d, a, b, c, in[1], 7);
    - ROUND1(c, d, a, b, in[2], 11);
    - ROUND1(b, c, d, a, in[3], 19);
    - ROUND1(a, b, c, d, in[4], 3);
    - ROUND1(d, a, b, c, in[5], 7);
    - ROUND1(c, d, a, b, in[6], 11);
    - ROUND1(b, c, d, a, in[7], 19);
    - ROUND1(a, b, c, d, in[8], 3);
    - ROUND1(d, a, b, c, in[9], 7);
    - ROUND1(c, d, a, b, in[10], 11);
    - ROUND1(b, c, d, a, in[11], 19);
    - ROUND1(a, b, c, d, in[12], 3);
    - ROUND1(d, a, b, c, in[13], 7);
    - ROUND1(c, d, a, b, in[14], 11);
    - ROUND1(b, c, d, a, in[15], 19);
    -
    - ROUND2(a, b, c, d,in[ 0], 3);
    - ROUND2(d, a, b, c, in[4], 5);
    - ROUND2(c, d, a, b, in[8], 9);
    - ROUND2(b, c, d, a, in[12], 13);
    - ROUND2(a, b, c, d, in[1], 3);
    - ROUND2(d, a, b, c, in[5], 5);
    - ROUND2(c, d, a, b, in[9], 9);
    - ROUND2(b, c, d, a, in[13], 13);
    - ROUND2(a, b, c, d, in[2], 3);
    - ROUND2(d, a, b, c, in[6], 5);
    - ROUND2(c, d, a, b, in[10], 9);
    - ROUND2(b, c, d, a, in[14], 13);
    - ROUND2(a, b, c, d, in[3], 3);
    - ROUND2(d, a, b, c, in[7], 5);
    - ROUND2(c, d, a, b, in[11], 9);
    - ROUND2(b, c, d, a, in[15], 13);
    -
    - ROUND3(a, b, c, d,in[ 0], 3);
    - ROUND3(d, a, b, c, in[8], 9);
    - ROUND3(c, d, a, b, in[4], 11);
    - ROUND3(b, c, d, a, in[12], 15);
    - ROUND3(a, b, c, d, in[2], 3);
    - ROUND3(d, a, b, c, in[10], 9);
    - ROUND3(c, d, a, b, in[6], 11);
    - ROUND3(b, c, d, a, in[14], 15);
    - ROUND3(a, b, c, d, in[1], 3);
    - ROUND3(d, a, b, c, in[9], 9);
    - ROUND3(c, d, a, b, in[5], 11);
    - ROUND3(b, c, d, a, in[13], 15);
    - ROUND3(a, b, c, d, in[3], 3);
    - ROUND3(d, a, b, c, in[11], 9);
    - ROUND3(c, d, a, b, in[7], 11);
    - ROUND3(b, c, d, a, in[15], 15);
    -
    - hash[0] += a;
    - hash[1] += b;
    - hash[2] += c;
    - hash[3] += d;
    -}
    -
    -static inline void
    -md4_transform_helper(PurpleHash *hash) {
    - PurpleMD4HashPrivate *priv = PURPLE_MD4_HASH_GET_PRIVATE(hash);
    -
    - le32_to_cpu_array(priv->block, sizeof(priv->block) / sizeof(guint32));
    - md4_transform(priv->hash, priv->block);
    -}
    -
    -/******************************************************************************
    - * Hash Stuff
    - *****************************************************************************/
    -static void
    -purple_md4_hash_reset(PurpleHash *hash) {
    - PurpleMD4HashPrivate *priv = PURPLE_MD4_HASH_GET_PRIVATE(hash);
    -
    - priv->hash[0] = 0x67452301;
    - priv->hash[1] = 0xefcdab89;
    - priv->hash[2] = 0x98badcfe;
    - priv->hash[3] = 0x10325476;
    -
    - priv->byte_count = 0;
    -
    - memset(priv->block, 0, sizeof(priv->block));
    -}
    -
    -static void
    -purple_md4_hash_append(PurpleHash *hash, const guchar *data, size_t len) {
    - PurpleMD4HashPrivate *priv = PURPLE_MD4_HASH_GET_PRIVATE(hash);
    - const guint32 avail = sizeof(priv->block) - (priv->byte_count & 0x3f);
    -
    - priv->byte_count += len;
    -
    - if(avail > len) {
    - memcpy((char *)priv->block +
    - (sizeof(priv->block) - avail),
    - data, len);
    - return;
    - }
    -
    - memcpy((char *)priv->block +
    - (sizeof(priv->block) - avail),
    - data, avail);
    -
    - md4_transform_helper(hash);
    - data += avail;
    - len -= avail;
    -
    - while(len >= sizeof(priv->block)) {
    - memcpy(priv->block, data, sizeof(priv->block));
    - md4_transform_helper(hash);
    - data += sizeof(priv->block);
    - len -= sizeof(priv->block);
    - }
    -
    - memcpy(priv->block, data, len);
    -}
    -
    -static gboolean
    -purple_md4_hash_digest(PurpleHash *hash, guchar *out, size_t len)
    -{
    - PurpleMD4HashPrivate *priv = PURPLE_MD4_HASH_GET_PRIVATE(hash);
    - const unsigned int offset = priv->byte_count & 0x3f;
    - gchar *p = (gchar *)priv->block + offset;
    - gint padding = 56 - (offset + 1);
    -
    - if(len < 16)
    - return FALSE;
    -
    - *p++ = 0x80;
    -
    - if(padding < 0) {
    - memset(p, 0x00, padding + sizeof(guint64));
    - md4_transform_helper(hash);
    - p = (gchar *)priv->block;
    - padding = 56;
    - }
    -
    - memset(p, 0, padding);
    - priv->block[14] = priv->byte_count << 3;
    - priv->block[15] = priv->byte_count >> 29;
    - le32_to_cpu_array(priv->block,
    - (sizeof(priv->block) - sizeof(guint64)) /
    - sizeof(guint32));
    - md4_transform(priv->hash, priv->block);
    - cpu_to_le32_array(priv->hash, sizeof(priv->hash) / sizeof(guint32));
    - memcpy(out, priv->hash, sizeof(priv->hash));
    -
    - return TRUE;
    -}
    -
    -static size_t
    -purple_md4_hash_get_digest_size(PurpleHash *hash)
    -{
    - return 16;
    -}
    -
    -static size_t
    -purple_md4_hash_get_block_size(PurpleHash *hash)
    -{
    - /* This does not change (in this case) */
    - return 64;
    -}
    -
    -/******************************************************************************
    - * Object Stuff
    - *****************************************************************************/
    -static void
    -purple_md4_hash_class_init(PurpleMD4HashClass *klass) {
    - PurpleHashClass *hash_class = PURPLE_HASH_CLASS(klass);
    -
    - parent_class = g_type_class_peek_parent(klass);
    -
    - g_type_class_add_private(klass, sizeof(PurpleMD4HashPrivate));
    -
    - hash_class->reset = purple_md4_hash_reset;
    - hash_class->reset_state = purple_md4_hash_reset;
    - hash_class->append = purple_md4_hash_append;
    - hash_class->digest = purple_md4_hash_digest;
    - hash_class->get_digest_size = purple_md4_hash_get_digest_size;
    - hash_class->get_block_size = purple_md4_hash_get_block_size;
    -}
    -
    -/******************************************************************************
    - * API
    - *****************************************************************************/
    -GType
    -purple_md4_hash_get_type(void) {
    - static GType type = 0;
    -
    - if(type == 0) {
    - static const GTypeInfo info = {
    - sizeof(PurpleMD4HashClass),
    - NULL,
    - NULL,
    - (GClassInitFunc)purple_md4_hash_class_init,
    - NULL,
    - NULL,
    - sizeof(PurpleMD4Hash),
    - 0,
    - (GInstanceInitFunc)purple_hash_reset,
    - NULL,
    - };
    -
    - type = g_type_register_static(PURPLE_TYPE_HASH,
    - "PurpleMD4Hash",
    - &info, 0);
    - }
    -
    - return type;
    -}
    -
    -PurpleHash *
    -purple_md4_hash_new(void) {
    - return g_object_new(PURPLE_TYPE_MD4_HASH, NULL);
    -}
    --- a/libpurple/ciphers/md4hash.h Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,66 +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    - */
    -
    -#ifndef PURPLE_MD4_HASH_H
    -#define PURPLE_MD4_HASH_H
    -/**
    - * SECTION:md4hash
    - * @section_id: libpurple-md4hash
    - * @short_description: <filename>ciphers/md4hash.h</filename>
    - * @title: MD4 Hash
    - */
    -
    -#include "cipher.h"
    -
    -#define PURPLE_TYPE_MD4_HASH (purple_md4_hash_get_type())
    -#define PURPLE_MD4_HASH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_MD4_HASH, PurpleMD4Hash))
    -#define PURPLE_MD4_HASH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_MD4_HASH, PurpleMD4HashClass))
    -#define PURPLE_IS_MD4_HASH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_MD4_HASH))
    -#define PURPLE_IS_MD4_HASH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((obj), PURPLE_TYPE_MD4_HASH))
    -#define PURPLE_MD4_HASH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_MD4_HASH, PurpleMD4HashClass))
    -
    -typedef struct _PurpleMD4Hash PurpleMD4Hash;
    -typedef struct _PurpleMD4HashClass PurpleMD4HashClass;
    -
    -struct _PurpleMD4Hash {
    - PurpleHash parent;
    -};
    -
    -struct _PurpleMD4HashClass {
    - PurpleHashClass parent;
    -
    - /*< private >*/
    - void (*_purple_reserved1)(void);
    - void (*_purple_reserved2)(void);
    - void (*_purple_reserved3)(void);
    - void (*_purple_reserved4)(void);
    -};
    -
    -G_BEGIN_DECLS
    -
    -GType purple_md4_hash_get_type(void);
    -
    -PurpleHash *purple_md4_hash_new(void);
    -
    -G_END_DECLS
    -
    -#endif /* PURPLE_MD4_HASH_H */
    --- a/libpurple/ciphers/pbkdf2cipher.c Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,392 +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
    - *
    - * Written by Tomek Wasilczyk <twasilczyk@pidgin.im>
    - */
    -#include "internal.h"
    -#include "glibcompat.h"
    -
    -#include "pbkdf2cipher.h"
    -#include "debug.h"
    -
    -/* 1024bit */
    -#define PBKDF2_HASH_MAX_LEN 128
    -
    -/******************************************************************************
    - * Structs
    - *****************************************************************************/
    -#define PURPLE_PBKDF2_CIPHER_GET_PRIVATE(obj) \
    - (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_PBKDF2_CIPHER, PurplePBKDF2CipherPrivate))
    -
    -typedef struct {
    - GChecksumType hash_type;
    - guint iter_count;
    - size_t out_len;
    -
    - guchar *salt;
    - size_t salt_len;
    - guchar *passphrase;
    - size_t passphrase_len;
    -} PurplePBKDF2CipherPrivate;
    -
    -/******************************************************************************
    - * Enums
    - *****************************************************************************/
    -enum {
    - PROP_NONE,
    - PROP_HASH_TYPE,
    - PROP_ITER_COUNT,
    - PROP_OUT_LEN,
    - PROP_LAST,
    -};
    -
    -/*******************************************************************************
    - * Globals
    - ******************************************************************************/
    -static GObjectClass *parent_class = NULL;
    -static GParamSpec *properties[PROP_LAST];
    -
    -/******************************************************************************
    - * Cipher Stuff
    - *****************************************************************************/
    -static void
    -purple_pbkdf2_cipher_reset(PurpleCipher *cipher)
    -{
    - PurplePBKDF2CipherPrivate *priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
    -
    - g_return_if_fail(priv != NULL);
    -
    - priv->iter_count = 1;
    - priv->out_len = 256;
    -
    - purple_cipher_reset_state(cipher);
    -}
    -
    -static void
    -purple_pbkdf2_cipher_reset_state(PurpleCipher *cipher)
    -{
    - PurplePBKDF2CipherPrivate *priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
    -
    - g_return_if_fail(priv != NULL);
    -
    - purple_cipher_set_salt(cipher, NULL, 0);
    - purple_cipher_set_key(cipher, NULL, 0);
    -}
    -
    -static size_t
    -purple_pbkdf2_cipher_get_digest_size(PurpleCipher *cipher)
    -{
    - PurplePBKDF2CipherPrivate *priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
    -
    - g_return_val_if_fail(priv != NULL, 0);
    -
    - return priv->out_len;
    -}
    -
    -static void
    -purple_pbkdf2_cipher_set_salt(PurpleCipher *cipher, const guchar *salt, size_t len)
    -{
    - PurplePBKDF2CipherPrivate *priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
    -
    - g_return_if_fail(priv != NULL);
    -
    - g_free(priv->salt);
    - priv->salt = NULL;
    - priv->salt_len = 0;
    -
    - if (len == 0)
    - return;
    - g_return_if_fail(salt != NULL);
    -
    - priv->salt = g_memdup(salt, len);
    - priv->salt_len = len;
    -}
    -
    -static void
    -purple_pbkdf2_cipher_set_key(PurpleCipher *cipher, const guchar *key,
    - size_t len)
    -{
    - PurplePBKDF2CipherPrivate *priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
    -
    - g_return_if_fail(priv != NULL);
    -
    - if (priv->passphrase != NULL) {
    - memset(priv->passphrase, 0, priv->passphrase_len);
    - g_free(priv->passphrase);
    - priv->passphrase = NULL;
    - }
    - priv->passphrase_len = 0;
    -
    - if (len == 0)
    - return;
    - g_return_if_fail(key != NULL);
    -
    - priv->passphrase = g_memdup(key, len);
    - priv->passphrase_len = len;
    -}
    -
    -/* inspired by gnutls 3.1.10, pbkdf2-sha1.c */
    -static gboolean
    -purple_pbkdf2_cipher_digest(PurpleCipher *cipher, guchar digest[], size_t len)
    -{
    - PurplePBKDF2CipherPrivate *priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
    -
    - guchar halfkey[PBKDF2_HASH_MAX_LEN], halfkey_hash[PBKDF2_HASH_MAX_LEN];
    - guint halfkey_count, halfkey_pad, halfkey_no;
    - gsize halfkey_len;
    - guchar *salt_ext;
    - size_t salt_ext_len;
    - guint iter_no;
    -
    - g_return_val_if_fail(priv != NULL, FALSE);
    - g_return_val_if_fail(digest != NULL, FALSE);
    - g_return_val_if_fail(len >= priv->out_len, FALSE);
    -
    - g_return_val_if_fail(priv->iter_count > 0, FALSE);
    - g_return_val_if_fail(priv->passphrase != NULL ||
    - priv->passphrase_len == 0, FALSE);
    - g_return_val_if_fail(priv->salt != NULL || priv->salt_len == 0,
    - FALSE);
    - g_return_val_if_fail(priv->out_len > 0, FALSE);
    - g_return_val_if_fail(priv->out_len < 0xFFFFFFFFU, FALSE);
    -
    - salt_ext_len = priv->salt_len + 4;
    -
    - halfkey_len = g_checksum_type_get_length(priv->hash_type);
    - if (halfkey_len <= 0 || halfkey_len > PBKDF2_HASH_MAX_LEN) {
    - purple_debug_error("pbkdf2", "Unsupported hash function. "
    - "(digest size: %" G_GSIZE_FORMAT ")\n", halfkey_len);
    - return FALSE;
    - }
    -
    - halfkey_count = ((priv->out_len - 1) / halfkey_len) + 1;
    - halfkey_pad = priv->out_len - (halfkey_count - 1) * halfkey_len;
    -
    - salt_ext = g_new(guchar, salt_ext_len);
    - if (priv->salt_len > 0)
    - memcpy(salt_ext, priv->salt, priv->salt_len);
    -
    - for (halfkey_no = 1; halfkey_no <= halfkey_count; halfkey_no++) {
    - memset(halfkey, 0, halfkey_len);
    -
    - for (iter_no = 1; iter_no <= priv->iter_count; iter_no++) {
    - GHmac *hmac;
    - guint i;
    -
    - hmac = g_hmac_new(priv->hash_type,
    - (const guchar*)priv->passphrase,
    - priv->passphrase_len);
    - if (hmac == NULL) {
    - purple_debug_error("pbkdf2",
    - "Couldn't create new hmac cipher\n");
    - g_free(salt_ext);
    - return FALSE;
    - }
    -
    - if (iter_no == 1) {
    - salt_ext[salt_ext_len - 4] =
    - (halfkey_no & 0xff000000) >> 24;
    - salt_ext[salt_ext_len - 3] =
    - (halfkey_no & 0x00ff0000) >> 16;
    - salt_ext[salt_ext_len - 2] =
    - (halfkey_no & 0x0000ff00) >> 8;
    - salt_ext[salt_ext_len - 1] =
    - (halfkey_no & 0x000000ff) >> 0;
    -
    - g_hmac_update(hmac, salt_ext, salt_ext_len);
    - }
    - else
    - g_hmac_update(hmac, halfkey_hash, halfkey_len);
    -
    - g_hmac_get_digest(hmac, halfkey_hash, &halfkey_len);
    - g_hmac_unref(hmac);
    -
    - for (i = 0; i < halfkey_len; i++)
    - halfkey[i] ^= halfkey_hash[i];
    - }
    -
    - memcpy(digest + (halfkey_no - 1) * halfkey_len, halfkey,
    - (halfkey_no == halfkey_count) ? halfkey_pad :
    - halfkey_len);
    - }
    -
    - g_free(salt_ext);
    -
    - return TRUE;
    -}
    -
    -/******************************************************************************
    - * Object Stuff
    - *****************************************************************************/
    -static void
    -purple_pbkdf2_cipher_get_property(GObject *obj, guint param_id, GValue *value,
    - GParamSpec *pspec)
    -{
    - PurplePBKDF2Cipher *cipher = PURPLE_PBKDF2_CIPHER(obj);
    - PurplePBKDF2CipherPrivate *priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
    -
    - switch(param_id) {
    - case PROP_HASH_TYPE:
    - g_value_set_int(value, priv->hash_type);
    - break;
    - case PROP_ITER_COUNT:
    - g_value_set_uint(value, priv->iter_count);
    - break;
    - case PROP_OUT_LEN:
    - g_value_set_uint(value, priv->out_len);
    - break;
    - default:
    - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
    - break;
    - }
    -}
    -
    -static void
    -purple_pbkdf2_cipher_set_property(GObject *obj, guint param_id,
    - const GValue *value, GParamSpec *pspec)
    -{
    - PurpleCipher *cipher = PURPLE_CIPHER(obj);
    - PurplePBKDF2CipherPrivate *priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
    -
    - switch(param_id) {
    - case PROP_HASH_TYPE:
    - priv->hash_type = g_value_get_int(value);
    - break;
    - case PROP_ITER_COUNT:
    - priv->iter_count = g_value_get_uint(value);
    - break;
    - case PROP_OUT_LEN:
    - priv->out_len = g_value_get_uint(value);
    - break;
    - default:
    - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
    - break;
    - }
    -}
    -
    -static void
    -purple_pbkdf2_cipher_finalize(GObject *obj)
    -{
    - PurpleCipher *cipher = PURPLE_CIPHER(obj);
    -
    - purple_pbkdf2_cipher_reset(cipher);
    -
    - parent_class->finalize(obj);
    -}
    -
    -static void
    -purple_pbkdf2_cipher_class_init(PurplePBKDF2CipherClass *klass) {
    - GObjectClass *obj_class = G_OBJECT_CLASS(klass);
    - PurpleCipherClass *cipher_class = PURPLE_CIPHER_CLASS(klass);
    -
    - parent_class = g_type_class_peek_parent(klass);
    -
    - obj_class->finalize = purple_pbkdf2_cipher_finalize;
    - obj_class->get_property = purple_pbkdf2_cipher_get_property;
    - obj_class->set_property = purple_pbkdf2_cipher_set_property;
    -
    - cipher_class->reset = purple_pbkdf2_cipher_reset;
    - cipher_class->reset_state = purple_pbkdf2_cipher_reset_state;
    - cipher_class->digest = purple_pbkdf2_cipher_digest;
    - cipher_class->get_digest_size = purple_pbkdf2_cipher_get_digest_size;
    - cipher_class->set_salt = purple_pbkdf2_cipher_set_salt;
    - cipher_class->set_key = purple_pbkdf2_cipher_set_key;
    -
    - g_type_class_add_private(klass, sizeof(PurplePBKDF2CipherPrivate));
    -
    - properties[PROP_HASH_TYPE] = g_param_spec_int("hash-type", "hash-type", "hash-type",
    - G_MININT, G_MAXINT, -1,
    - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
    - G_PARAM_STATIC_STRINGS);
    -
    - properties[PROP_ITER_COUNT] = g_param_spec_uint("iter-count", "iter-count",
    - "iter-count", 0,
    - G_MAXUINT, 0, G_PARAM_READWRITE |
    - G_PARAM_STATIC_STRINGS);
    -
    - properties[PROP_OUT_LEN] = g_param_spec_uint("out-len", "out-len",
    - "out-len", 0,
    - G_MAXUINT, 0, G_PARAM_READWRITE |
    - G_PARAM_STATIC_STRINGS);
    -
    - g_object_class_install_properties(obj_class, PROP_LAST, properties);
    -}
    -
    -static void
    -purple_pbkdf2_cipher_init(PurpleCipher *cipher)
    -{
    - PurplePBKDF2CipherPrivate *priv =
    - PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
    -
    - priv->hash_type = -1;
    -
    - purple_cipher_reset(cipher);
    -}
    -
    -/******************************************************************************
    - * API
    - *****************************************************************************/
    -GType
    -purple_pbkdf2_cipher_get_type(void) {
    - static GType type = 0;
    -
    - if(type == 0) {
    - static const GTypeInfo info = {
    - sizeof(PurplePBKDF2CipherClass),
    - NULL,
    - NULL,
    - (GClassInitFunc)purple_pbkdf2_cipher_class_init,
    - NULL,
    - NULL,
    - sizeof(PurplePBKDF2Cipher),
    - 0,
    - (GInstanceInitFunc)purple_pbkdf2_cipher_init,
    - NULL
    - };
    -
    - type = g_type_register_static(PURPLE_TYPE_CIPHER,
    - "PurplePBKDF2Cipher",
    - &info, 0);
    - }
    -
    - return type;
    -}
    -
    -PurpleCipher *
    -purple_pbkdf2_cipher_new(GChecksumType hash_type) {
    - return g_object_new(PURPLE_TYPE_PBKDF2_CIPHER,
    - "hash-type", hash_type,
    - NULL);
    -}
    -
    -GChecksumType
    -purple_pbkdf2_cipher_get_hash_type(const PurplePBKDF2Cipher *cipher) {
    - PurplePBKDF2CipherPrivate *priv = NULL;
    -
    - g_return_val_if_fail(PURPLE_IS_PBKDF2_CIPHER(cipher), -1);
    -
    - priv = PURPLE_PBKDF2_CIPHER_GET_PRIVATE(cipher);
    -
    - if(priv)
    - return priv->hash_type;
    -
    - return -1;
    -}
    --- a/libpurple/ciphers/pbkdf2cipher.h Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,68 +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 PURPLE_PBKDF2_CIPHER_H
    -#define PURPLE_PBKDF2_CIPHER_H
    -/**
    - * SECTION:pbkdf2cipher
    - * @section_id: libpurple-pbkdf2cipher
    - * @short_description: <filename>ciphers/pbkdf2cipher.h</filename>
    - * @title: PBKDF2 Cipher
    - */
    -
    -#include "cipher.h"
    -
    -#define PURPLE_TYPE_PBKDF2_CIPHER (purple_pbkdf2_cipher_get_type())
    -#define PURPLE_PBKDF2_CIPHER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_PBKDF2_CIPHER, PurplePBKDF2Cipher))
    -#define PURPLE_PBKDF2_CIPHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_PBKDF2_CIPHER, PurplePBKDF2CipherClass))
    -#define PURPLE_IS_PBKDF2_CIPHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_PBKDF2_CIPHER))
    -#define PURPLE_IS_PBKDF2_CIPHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((obj), PURPLE_TYPE_PBKDF2_CIPHER))
    -#define PURPLE_PBKDF2_CIPHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_PBKDF2_CIPHER, PurplePBKDF2CipherClass))
    -
    -typedef struct _PurplePBKDF2Cipher PurplePBKDF2Cipher;
    -typedef struct _PurplePBKDF2CipherClass PurplePBKDF2CipherClass;
    -
    -struct _PurplePBKDF2Cipher {
    - PurpleCipher gparent;
    -};
    -
    -struct _PurplePBKDF2CipherClass {
    - PurpleCipherClass gparent;
    -
    - /*< private >*/
    - void (*_purple_reserved1)(void);
    - void (*_purple_reserved2)(void);
    - void (*_purple_reserved3)(void);
    - void (*_purple_reserved4)(void);
    -};
    -
    -G_BEGIN_DECLS
    -
    -GType purple_pbkdf2_cipher_get_type(void);
    -
    -PurpleCipher *purple_pbkdf2_cipher_new(GChecksumType hash_type);
    -
    -GChecksumType purple_pbkdf2_cipher_get_hash_type(const PurplePBKDF2Cipher *cipher);
    -
    -G_END_DECLS
    -
    -#endif /* PURPLE_PBKDF2_CIPHER_H */
    -
    --- a/libpurple/ciphers/rc4cipher.c Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,262 +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 "glibcompat.h"
    -
    -#include "rc4cipher.h"
    -
    -/*******************************************************************************
    - * Structs
    - ******************************************************************************/
    -#define PURPLE_RC4_CIPHER_GET_PRIVATE(obj) \
    - (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_RC4_CIPHER, PurpleRC4CipherPrivate))
    -
    -typedef struct {
    - guchar state[256];
    - guchar x;
    - guchar y;
    - gint key_len;
    -} PurpleRC4CipherPrivate;
    -
    -/******************************************************************************
    - * Enums
    - *****************************************************************************/
    -enum {
    - PROP_ZERO,
    - PROP_KEY_LEN,
    - PROP_KEY,
    - PROP_LAST,
    -};
    -
    -/******************************************************************************
    - * Globals
    - *****************************************************************************/
    -static GObjectClass *parent_class = NULL;
    -static GParamSpec *properties[PROP_LAST];
    -
    -/******************************************************************************
    - * Cipher Stuff
    - *****************************************************************************/
    -static void
    -purple_rc4_cipher_reset(PurpleCipher *cipher) {
    - PurpleRC4Cipher *rc4_cipher = PURPLE_RC4_CIPHER(cipher);
    - PurpleRC4CipherPrivate *priv = PURPLE_RC4_CIPHER_GET_PRIVATE(rc4_cipher);
    - guint i;
    -
    - for(i = 0; i < 256; i++)
    - priv->state[i] = i;
    - priv->x = 0;
    - priv->y = 0;
    -
    - /* default is 5 bytes (40bit key) */
    - priv->key_len = 5;
    -}
    -
    -static void
    -purple_rc4_cipher_set_key(PurpleCipher *cipher, const guchar *key, size_t len) {
    - PurpleRC4Cipher *rc4_cipher = PURPLE_RC4_CIPHER(cipher);
    - PurpleRC4CipherPrivate *priv = PURPLE_RC4_CIPHER_GET_PRIVATE(rc4_cipher);
    - guchar *state;
    - guchar temp_swap;
    - guchar x, y;
    - guint i;
    -
    - x = 0;
    - y = 0;
    - state = &priv->state[0];
    - priv->key_len = len;
    - for(i = 0; i < 256; i++)
    - {
    - y = (key[x] + state[i] + y) % 256;
    - temp_swap = state[i];
    - state[i] = state[y];
    - state[y] = temp_swap;
    - x = (x + 1) % len;
    - }
    -
    - g_object_notify_by_pspec(G_OBJECT(cipher), properties[PROP_KEY]);
    -}
    -
    -static ssize_t
    -purple_rc4_cipher_encrypt(PurpleCipher *cipher, const guchar input[], size_t in_len,
    - guchar output[], size_t out_size)
    -{
    - PurpleRC4Cipher *rc4_cipher = PURPLE_RC4_CIPHER(cipher);
    - guchar temp_swap;
    - guchar x, y, z;
    - guchar *state;
    - guint i;
    - PurpleRC4CipherPrivate *priv = PURPLE_RC4_CIPHER_GET_PRIVATE(rc4_cipher);
    -
    - x = priv->x;
    - y = priv->y;
    - state = &priv->state[0];
    -
    - for(i = 0; i < in_len; i++)
    - {
    - x = (x + 1) % 256;
    - y = (state[x] + y) % 256;
    - temp_swap = state[x];
    - state[x] = state[y];
    - state[y] = temp_swap;
    - z = state[x] + (state[y]) % 256;
    - output[i] = input[i] ^ state[z];
    - }
    - priv->x = x;
    - priv->y = y;
    -
    - return in_len;
    -}
    -
    -/******************************************************************************
    - * Object Stuff
    - *****************************************************************************/
    -static void
    -purple_rc4_cipher_set_property(GObject *obj, guint param_id,
    - const GValue *value, GParamSpec *pspec)
    -{
    - PurpleCipher *cipher = PURPLE_CIPHER(obj);
    - PurpleRC4Cipher *rc4_cipher = PURPLE_RC4_CIPHER(obj);
    -
    - switch(param_id) {
    - case PROP_KEY_LEN:
    - purple_rc4_cipher_set_key_len(rc4_cipher, g_value_get_int(value));
    - break;
    - case PROP_KEY:
    - {
    - guchar *key = (guchar *)g_value_get_string(value);
    - purple_rc4_cipher_set_key(cipher, key, strlen((gchar *) key));
    - }
    - break;
    - default:
    - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
    - break;
    - }
    -}
    -
    -static void
    -purple_rc4_cipher_get_property(GObject *obj, guint param_id, GValue *value,
    - GParamSpec *pspec)
    -{
    - PurpleRC4Cipher *rc4_cipher = PURPLE_RC4_CIPHER(obj);
    -
    - switch(param_id) {
    - case PROP_KEY_LEN:
    - g_value_set_int(value,
    - purple_rc4_cipher_get_key_len(rc4_cipher));
    - break;
    - default:
    - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
    - break;
    - }
    -}
    -
    -static void
    -purple_rc4_cipher_class_init(PurpleRC4CipherClass *klass) {
    - GObjectClass *obj_class = G_OBJECT_CLASS(klass);
    - PurpleCipherClass *cipher_class = PURPLE_CIPHER_CLASS(klass);
    -
    - parent_class = g_type_class_peek_parent(klass);
    -
    - obj_class->set_property = purple_rc4_cipher_set_property;
    - obj_class->get_property = purple_rc4_cipher_get_property;
    -
    - cipher_class->reset = purple_rc4_cipher_reset;
    - cipher_class->encrypt = purple_rc4_cipher_encrypt;
    - cipher_class->set_key = purple_rc4_cipher_set_key;
    -
    - g_type_class_add_private(klass, sizeof(PurpleRC4CipherPrivate));
    -
    - properties[PROP_KEY_LEN] = g_param_spec_int("key-len", "key-len", "key-len",
    - G_MININT, G_MAXINT, 0,
    - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
    -
    - properties[PROP_KEY] = g_param_spec_string("key", "key", "key", NULL,
    - G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS);
    -
    - g_object_class_install_properties(obj_class, PROP_LAST, properties);
    -}
    -
    -static void
    -purple_rc4_cipher_init(PurpleCipher *cipher) {
    - purple_rc4_cipher_reset(cipher);
    -}
    -
    -/******************************************************************************
    - * API
    - *****************************************************************************/
    -GType
    -purple_rc4_cipher_get_type(void) {
    - static GType type = 0;
    -
    - if(type == 0) {
    - static const GTypeInfo info = {
    - sizeof(PurpleRC4CipherClass),
    - NULL,
    - NULL,
    - (GClassInitFunc)purple_rc4_cipher_class_init,
    - NULL,
    - NULL,
    - sizeof(PurpleRC4Cipher),
    - 0,
    - (GInstanceInitFunc)purple_rc4_cipher_init,
    - NULL,
    - };
    -
    - type = g_type_register_static(PURPLE_TYPE_CIPHER,
    - "PurpleRC4Cipher",
    - &info, 0);
    - }
    -
    - return type;
    -}
    -
    -PurpleCipher *
    -purple_rc4_cipher_new(void) {
    - return g_object_new(PURPLE_TYPE_RC4_CIPHER, NULL);
    -}
    -
    -void
    -purple_rc4_cipher_set_key_len(PurpleRC4Cipher *rc4_cipher,
    - gint key_len)
    -{
    - PurpleRC4CipherPrivate *priv;
    -
    - g_return_if_fail(PURPLE_IS_RC4_CIPHER(rc4_cipher));
    -
    - priv = PURPLE_RC4_CIPHER_GET_PRIVATE(rc4_cipher);
    - priv->key_len = key_len;
    -
    - g_object_notify_by_pspec(G_OBJECT(rc4_cipher), properties[PROP_KEY_LEN]);
    -}
    -
    -gint
    -purple_rc4_cipher_get_key_len(PurpleRC4Cipher *rc4_cipher)
    -{
    - PurpleRC4CipherPrivate *priv;
    -
    - g_return_val_if_fail(PURPLE_IS_RC4_CIPHER(rc4_cipher), 0);
    -
    - priv = PURPLE_RC4_CIPHER_GET_PRIVATE(rc4_cipher);
    -
    - return priv->key_len;
    -}
    --- a/libpurple/ciphers/rc4cipher.h Thu Jun 15 10:48:26 2017 +0300
    +++ /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 PURPLE_RC4_CIPHER_H
    -#define PURPLE_RC4_CIPHER_H
    -/**
    - * SECTION:rc4cipher
    - * @section_id: libpurple-rc4cipher
    - * @short_description: <filename>ciphers/rc4cipher.h</filename>
    - * @title: RC4 Cipher
    - */
    -
    -#include "cipher.h"
    -
    -#define PURPLE_TYPE_RC4_CIPHER (purple_rc4_cipher_get_type())
    -#define PURPLE_RC4_CIPHER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_RC4_CIPHER, PurpleRC4Cipher))
    -#define PURPLE_RC4_CIPHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_RC4_CIPHER, PurpleRC4CipherClass))
    -#define PURPLE_IS_RC4_CIPHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_RC4_CIPHER))
    -#define PURPLE_IS_RC4_CIPHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((obj), PURPLE_TYPE_RC4_CIPHER))
    -#define PURPLE_RC4_CIPHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_RC4_CIPHER, PurpleRC4CipherClass))
    -
    -typedef struct _PurpleRC4Cipher PurpleRC4Cipher;
    -typedef struct _PurpleRC4CipherClass PurpleRC4CipherClass;
    -
    -struct _PurpleRC4Cipher {
    - PurpleCipher gparent;
    -};
    -
    -struct _PurpleRC4CipherClass {
    - PurpleCipherClass gparent;
    -
    - /*< private >*/
    - void (*_purple_reserved1)(void);
    - void (*_purple_reserved2)(void);
    - void (*_purple_reserved3)(void);
    - void (*_purple_reserved4)(void);
    -};
    -
    -G_BEGIN_DECLS
    -
    -GType purple_rc4_cipher_get_type(void);
    -
    -PurpleCipher *purple_rc4_cipher_new(void);
    -
    -gint purple_rc4_cipher_get_key_len(PurpleRC4Cipher *rc4_cipher);
    -void purple_rc4_cipher_set_key_len(PurpleRC4Cipher *rc4_cipher, gint key_len);
    -
    -G_END_DECLS
    -
    -#endif /* PURPLE_RC4_CIPHER_H */
    -
    -
    --- a/libpurple/core.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/core.c Fri Jun 30 15:03:16 2017 +0300
    @@ -19,7 +19,6 @@
    * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
    */
    #include "internal.h"
    -#include "cipher.h"
    #include "cmds.h"
    #include "connection.h"
    #include "conversation.h"
    --- a/libpurple/eventloop.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/eventloop.c Fri Jun 30 15:03:16 2017 +0300
    @@ -21,69 +21,88 @@
    #include "internal.h"
    #include "eventloop.h"
    -static PurpleEventLoopUiOps *eventloop_ui_ops = NULL;
    +#define PURPLE_GLIB_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR)
    +#define PURPLE_GLIB_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL)
    +
    +typedef struct _PurpleIOClosure {
    + PurpleInputFunction function;
    + guint result;
    + gpointer data;
    +} PurpleIOClosure;
    guint
    purple_timeout_add(guint interval, GSourceFunc function, gpointer data)
    {
    - PurpleEventLoopUiOps *ops = purple_eventloop_get_ui_ops();
    -
    - return ops->timeout_add(interval, function, data);
    + return g_timeout_add(interval, function, data);
    }
    guint
    purple_timeout_add_seconds(guint interval, GSourceFunc function, gpointer data)
    {
    - PurpleEventLoopUiOps *ops = purple_eventloop_get_ui_ops();
    -
    - if (ops->timeout_add_seconds)
    - return ops->timeout_add_seconds(interval, function, data);
    - else
    - return ops->timeout_add(1000 * interval, function, data);
    + return g_timeout_add_seconds(interval, function, data);
    }
    gboolean
    purple_timeout_remove(guint tag)
    {
    - PurpleEventLoopUiOps *ops = purple_eventloop_get_ui_ops();
    + return g_source_remove(tag);
    +}
    +
    +static gboolean
    +purple_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data)
    +{
    + PurpleIOClosure *closure = data;
    + PurpleInputCondition purple_cond = 0;
    - return ops->timeout_remove(tag);
    + if (condition & PURPLE_GLIB_READ_COND)
    + purple_cond |= PURPLE_INPUT_READ;
    + if (condition & PURPLE_GLIB_WRITE_COND)
    + purple_cond |= PURPLE_INPUT_WRITE;
    +
    +#ifdef _WIN32
    + if(!purple_cond) {
    + return TRUE;
    + }
    +#endif /* _WIN32 */
    +
    + closure->function(closure->data, g_io_channel_unix_get_fd(source),
    + purple_cond);
    +
    + return TRUE;
    }
    guint
    purple_input_add(int source, PurpleInputCondition condition, PurpleInputFunction func, gpointer user_data)
    {
    - PurpleEventLoopUiOps *ops = purple_eventloop_get_ui_ops();
    + PurpleIOClosure *closure = g_new0(PurpleIOClosure, 1);
    + GIOChannel *channel;
    + GIOCondition cond = 0;
    +
    + closure->function = func;
    + closure->data = user_data;
    +
    + if (condition & PURPLE_INPUT_READ)
    + cond |= PURPLE_GLIB_READ_COND;
    + if (condition & PURPLE_INPUT_WRITE)
    + cond |= PURPLE_GLIB_WRITE_COND;
    - return ops->input_add(source, condition, func, user_data);
    +#ifdef _WIN32
    + channel = g_io_channel_win32_new_socket(source);
    +#else
    + channel = g_io_channel_unix_new(source);
    +#endif
    +
    + closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT,
    + cond, purple_io_invoke, closure, g_free);
    +
    + g_io_channel_unref(channel);
    + return closure->result;
    }
    gboolean
    purple_input_remove(guint tag)
    {
    - PurpleEventLoopUiOps *ops = purple_eventloop_get_ui_ops();
    -
    - return ops->input_remove(tag);
    -}
    -
    -int
    -purple_input_get_error(int fd, int *error)
    -{
    - PurpleEventLoopUiOps *ops = purple_eventloop_get_ui_ops();
    -
    - if (ops->input_get_error)
    - {
    - int ret = ops->input_get_error(fd, error);
    - errno = *error;
    - return ret;
    - }
    - else
    - {
    - socklen_t len;
    - len = sizeof(*error);
    -
    - return getsockopt(fd, SOL_SOCKET, SO_ERROR, error, &len);
    - }
    + return g_source_remove(tag);
    }
    int
    @@ -95,47 +114,3 @@
    return pipe(pipefd);
    #endif
    }
    -
    -void
    -purple_eventloop_set_ui_ops(PurpleEventLoopUiOps *ops)
    -{
    - eventloop_ui_ops = ops;
    -}
    -
    -PurpleEventLoopUiOps *
    -purple_eventloop_get_ui_ops(void)
    -{
    - g_return_val_if_fail(eventloop_ui_ops != NULL, NULL);
    -
    - return eventloop_ui_ops;
    -}
    -
    -/**************************************************************************
    - * GBoxed code
    - **************************************************************************/
    -static PurpleEventLoopUiOps *
    -purple_eventloop_ui_ops_copy(PurpleEventLoopUiOps *ops)
    -{
    - PurpleEventLoopUiOps *ops_new;
    -
    - g_return_val_if_fail(ops != NULL, NULL);
    -
    - ops_new = g_new(PurpleEventLoopUiOps, 1);
    - *ops_new = *ops;
    -
    - return ops_new;
    -}
    -
    -GType
    -purple_eventloop_ui_ops_get_type(void)
    -{
    - static GType type = 0;
    -
    - if (type == 0) {
    - type = g_boxed_type_register_static("PurpleEventLoopUiOps",
    - (GBoxedCopyFunc)purple_eventloop_ui_ops_copy,
    - (GBoxedFreeFunc)g_free);
    - }
    -
    - return type;
    -}
    --- a/libpurple/eventloop.h Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/eventloop.h Fri Jun 30 15:03:16 2017 +0300
    @@ -31,8 +31,6 @@
    #include <glib.h>
    #include <glib-object.h>
    -#define PURPLE_TYPE_EVENTLOOP_UI_OPS (purple_eventloop_ui_ops_get_type())
    -
    /**
    * PurpleInputCondition:
    * @PURPLE_INPUT_READ: A read condition.
    @@ -57,99 +55,6 @@
    */
    typedef void (*PurpleInputFunction)(gpointer, gint, PurpleInputCondition);
    -typedef struct _PurpleEventLoopUiOps PurpleEventLoopUiOps;
    -
    -/**
    - * PurpleEventLoopUiOps:
    - * @timeout_add: Should create a callback timer with an interval measured in
    - * milliseconds. The supplied @function should be called every
    - * @interval seconds until it returns %FALSE, after which it
    - * should not be called again.
    - * <sbr/>Analogous to g_timeout_add in glib.
    - * <sbr/>Note: On Win32, this function may be called from a thread
    - * other than the libpurple thread. You should make sure to detect
    - * this situation and to only call "function" from the libpurple
    - * thread.
    - * <sbr/>See purple_timeout_add().
    - * <sbr/>@interval: the interval in
    - * <emphasis>milliseconds</emphasis> between
    - * calls to @function.
    - * <sbr/>@data: arbitrary data to be passed to @function at each
    - * call.
    - * <sbr/>Returns: a handle for the timeout, which can be passed to
    - * @timeout_remove.
    - * @timeout_remove: Should remove a callback timer. Analogous to
    - * g_source_remove() in glib.
    - * <sbr/>See purple_timeout_remove().
    - * <sbr/>@handle: an identifier for a timeout, as returned by
    - * @timeout_add.
    - * <sbr/>Returns: %TRUE if the timeout identified by @handle
    - * was found and removed.
    - * @input_add: Should add an input handler. Analogous to g_io_add_watch_full()
    - * in glib.
    - * <sbr/>See purple_input_add().
    - * <sbr/>@fd: a file descriptor to watch for events
    - * <sbr/>@cond: a bitwise OR of events on @fd for which @func
    - * should be called.
    - * <sbr/>@func: a callback to fire whenever a relevant event on
    - * @fd occurs.
    - * <sbr/>@user_data: arbitrary data to pass to @fd.
    - * <sbr/>Returns: an identifier for this input handler, which can
    - * be passed to @input_remove.
    - * @input_remove: Should remove an input handler. Analogous to g_source_remove()
    - * in glib.
    - * <sbr/>See purple_input_remove().
    - * <sbr/>@handle: an identifier, as returned by #input_add.
    - * <sbr/>Returns: %TRUE if the input handler was found and
    - * removed.
    - * @input_get_error: If implemented, should get the current error status for an
    - * input.
    - * <sbr/>Implementation of this UI op is optional. Implement
    - * it if the UI's sockets or event loop needs to customize
    - * determination of socket error status. If unimplemented,
    - * <literal>getsockopt(2)</literal> will be used instead.
    - * <sbr/>See purple_input_get_error().
    - * @timeout_add_seconds: If implemented, should create a callback timer with an
    - * interval measured in seconds. Analogous to
    - * g_timeout_add_seconds() in glib.
    - * <sbr/>This allows UIs to group timers for better power
    - * efficiency. For this reason, @interval may be rounded
    - * by up to a second.
    - * <sbr/>Implementation of this UI op is optional. If it's
    - * not implemented, calls to purple_timeout_add_seconds()
    - * will be serviced by @timeout_add.
    - * <sbr/>See purple_timeout_add_seconds().
    - *
    - * An abstraction of an application's mainloop; libpurple will use this to
    - * watch file descriptors and schedule timed callbacks. If your application
    - * uses the glib mainloop, there is an implementation of this struct in
    - * <filename>libpurple/example/nullclient.c</filename> which you can use
    - * verbatim.
    - */
    -struct _PurpleEventLoopUiOps
    -{
    - /* TODO Who is responsible for freeing @data? */
    - guint (*timeout_add)(guint interval, GSourceFunc function, gpointer data);
    -
    - gboolean (*timeout_remove)(guint handle);
    -
    - guint (*input_add)(int fd, PurpleInputCondition cond,
    - PurpleInputFunction func, gpointer user_data);
    -
    - gboolean (*input_remove)(guint handle);
    -
    - int (*input_get_error)(int fd, int *error);
    -
    - guint (*timeout_add_seconds)(guint interval, GSourceFunc function,
    - gpointer data);
    -
    - /*< private >*/
    - void (*_purple_reserved1)(void);
    - void (*_purple_reserved2)(void);
    - void (*_purple_reserved3)(void);
    - void (*_purple_reserved4)(void);
    -};
    -
    G_BEGIN_DECLS
    /**************************************************************************/
    @@ -231,24 +136,6 @@
    gboolean purple_input_remove(guint handle);
    /**
    - * purple_input_get_error:
    - * @fd: The input file descriptor.
    - * @error: A pointer to an #int which on return will have the error, or
    - * 0 if no error.
    - *
    - * Get the current error status for an input.
    - *
    - * The return value and error follow getsockopt() with a level of SOL_SOCKET and an
    - * option name of SO_ERROR, and this is how the error is determined if the UI does not
    - * implement the input_get_error UI op.
    - *
    - * Returns: 0 if there is no error; -1 if there is an error, in which case
    - * #errno will be set.
    - */
    -int
    -purple_input_get_error(int fd, int *error);
    -
    -/**
    * purple_input_pipe:
    * @pipefd: Array used to return file descriptors for both ends of pipe.
    *
    @@ -267,36 +154,6 @@
    int
    purple_input_pipe(int pipefd[2]);
    -
    -
    -/**************************************************************************/
    -/* UI Registration Functions */
    -/**************************************************************************/
    -
    -/**
    - * purple_eventloop_ui_ops_get_type:
    - *
    - * Returns: The #GType for the #PurpleEventLoopUiOps boxed structure.
    - */
    -GType purple_eventloop_ui_ops_get_type(void);
    -
    -/**
    - * purple_eventloop_set_ui_ops:
    - * @ops: The UI operations structure.
    - *
    - * Sets the UI operations structure to be used for accounts.
    - */
    -void purple_eventloop_set_ui_ops(PurpleEventLoopUiOps *ops);
    -
    -/**
    - * purple_eventloop_get_ui_ops:
    - *
    - * Returns the UI operations structure used for accounts.
    - *
    - * Returns: The UI operations structure in use.
    - */
    -PurpleEventLoopUiOps *purple_eventloop_get_ui_ops(void);
    -
    G_END_DECLS
    #endif /* _PURPLE_EVENTLOOP_H_ */
    --- a/libpurple/example/nullclient.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/example/nullclient.c Fri Jun 30 15:03:16 2017 +0300
    @@ -36,84 +36,6 @@
    #include "defines.h"
    -/**
    - * The following eventloop functions are used in both pidgin and purple-text. If your
    - * application uses glib mainloop, you can safely use this verbatim.
    - */
    -#define PURPLE_GLIB_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR)
    -#define PURPLE_GLIB_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL)
    -
    -typedef struct _PurpleGLibIOClosure {
    - PurpleInputFunction function;
    - guint result;
    - gpointer data;
    -} PurpleGLibIOClosure;
    -
    -static void purple_glib_io_destroy(gpointer data)
    -{
    - g_free(data);
    -}
    -
    -static gboolean purple_glib_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data)
    -{
    - PurpleGLibIOClosure *closure = data;
    - PurpleInputCondition purple_cond = 0;
    -
    - if (condition & PURPLE_GLIB_READ_COND)
    - purple_cond |= PURPLE_INPUT_READ;
    - if (condition & PURPLE_GLIB_WRITE_COND)
    - purple_cond |= PURPLE_INPUT_WRITE;
    -
    - closure->function(closure->data, g_io_channel_unix_get_fd(source),
    - purple_cond);
    -
    - return TRUE;
    -}
    -
    -static guint glib_input_add(gint fd, PurpleInputCondition condition,
    - PurpleInputFunction function, gpointer data)
    -{
    - PurpleGLibIOClosure *closure = g_new0(PurpleGLibIOClosure, 1);
    - GIOChannel *channel;
    - GIOCondition cond = 0;
    -
    - closure->function = function;
    - closure->data = data;
    -
    - if (condition & PURPLE_INPUT_READ)
    - cond |= PURPLE_GLIB_READ_COND;
    - if (condition & PURPLE_INPUT_WRITE)
    - cond |= PURPLE_GLIB_WRITE_COND;
    -
    -#ifdef _WIN32
    - channel = g_io_channel_win32_new_socket(fd);
    -#else
    - channel = g_io_channel_unix_new(fd);
    -#endif
    - closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT,
    - cond, purple_glib_io_invoke, closure, purple_glib_io_destroy);
    -
    - g_io_channel_unref(channel);
    - return closure->result;
    -}
    -
    -static PurpleEventLoopUiOps glib_eventloops =
    -{
    - g_timeout_add,
    - g_source_remove,
    - glib_input_add,
    - g_source_remove,
    - NULL,
    - g_timeout_add_seconds,
    -
    - /* padding */
    - NULL,
    - NULL,
    - NULL,
    - NULL
    -};
    -/*** End of the eventloop functions. ***/
    -
    /*** Conversation uiops ***/
    static void
    null_write_conv(PurpleConversation *conv, PurpleMessage *msg)
    @@ -189,10 +111,6 @@
    */
    purple_core_set_ui_ops(&null_core_uiops);
    - /* Set the uiops for the eventloop. If your client is glib-based, you can safely
    - * copy this verbatim. */
    - purple_eventloop_set_ui_ops(&glib_eventloops);
    -
    /* Now that all the essential stuff has been set, let's try to init the core. It's
    * necessary to provide a non-NULL name for the current ui to the core. This name
    * is used by stuff that depends on this ui, for example the ui-specific plugins. */
    --- a/libpurple/glibcompat.h Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/glibcompat.h Fri Jun 30 15:03:16 2017 +0300
    @@ -63,6 +63,11 @@
    #endif /* __clang__ */
    +
    +#if !GLIB_CHECK_VERSION(2, 44, 0)
    +#define G_IO_ERROR_CONNECTION_CLOSED G_IO_ERROR_BROKEN_PIPE
    +#endif
    +
    /******************************************************************************
    * g_assert_* macros
    *****************************************************************************/
    --- a/libpurple/marshallers.list Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,10 +0,0 @@
    -VOID:POINTER,POINTER,OBJECT
    -BOOLEAN:OBJECT,POINTER,STRING
    -VOID:STRING,STRING
    -VOID:STRING,STRING,DOUBLE
    -VOID:ENUM,STRING,STRING
    -VOID:ENUM,STRING,STRING,BOOLEAN
    -VOID:FLAGS,FLAGS
    -VOID:STRING,STRING,OBJECT,OBJECT
    -BOOLEAN:OBJECT
    -VOID:POINTER,POINTER,OBJECT,OBJECT
    --- a/libpurple/media.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/media.c Fri Jun 30 15:03:16 2017 +0300
    @@ -29,7 +29,6 @@
    #ifdef USE_GSTREAMER
    #include "media/backend-fs2.h"
    -#include "marshallers.h"
    #include "media-gst.h"
    #endif /* USE_GSTREAMER */
    @@ -224,41 +223,33 @@
    G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
    purple_media_signals[S_ERROR] = g_signal_new("error", G_TYPE_FROM_CLASS(klass),
    - G_SIGNAL_RUN_LAST, 0, NULL, NULL,
    - g_cclosure_marshal_VOID__STRING,
    + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
    G_TYPE_NONE, 1, G_TYPE_STRING);
    purple_media_signals[CANDIDATES_PREPARED] = g_signal_new("candidates-prepared", G_TYPE_FROM_CLASS(klass),
    - G_SIGNAL_RUN_LAST, 0, NULL, NULL,
    - purple_smarshal_VOID__STRING_STRING,
    + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
    G_TYPE_NONE, 2, G_TYPE_STRING,
    G_TYPE_STRING);
    purple_media_signals[CODECS_CHANGED] = g_signal_new("codecs-changed", G_TYPE_FROM_CLASS(klass),
    - G_SIGNAL_RUN_LAST, 0, NULL, NULL,
    - g_cclosure_marshal_VOID__STRING,
    + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
    G_TYPE_NONE, 1, G_TYPE_STRING);
    purple_media_signals[LEVEL] = g_signal_new("level", G_TYPE_FROM_CLASS(klass),
    - G_SIGNAL_RUN_LAST, 0, NULL, NULL,
    - purple_smarshal_VOID__STRING_STRING_DOUBLE,
    + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
    G_TYPE_NONE, 3, G_TYPE_STRING,
    G_TYPE_STRING, G_TYPE_DOUBLE);
    purple_media_signals[NEW_CANDIDATE] = g_signal_new("new-candidate", G_TYPE_FROM_CLASS(klass),
    - G_SIGNAL_RUN_LAST, 0, NULL, NULL,
    - purple_smarshal_VOID__POINTER_POINTER_OBJECT,
    + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
    G_TYPE_NONE, 3, G_TYPE_POINTER,
    G_TYPE_POINTER, PURPLE_TYPE_MEDIA_CANDIDATE);
    purple_media_signals[STATE_CHANGED] = g_signal_new("state-changed", G_TYPE_FROM_CLASS(klass),
    - G_SIGNAL_RUN_LAST, 0, NULL, NULL,
    - purple_smarshal_VOID__ENUM_STRING_STRING,
    + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
    G_TYPE_NONE, 3, PURPLE_MEDIA_TYPE_STATE,
    G_TYPE_STRING, G_TYPE_STRING);
    purple_media_signals[STREAM_INFO] = g_signal_new("stream-info", G_TYPE_FROM_CLASS(klass),
    - G_SIGNAL_RUN_LAST, 0, NULL, NULL,
    - purple_smarshal_VOID__ENUM_STRING_STRING_BOOLEAN,
    + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
    G_TYPE_NONE, 4, PURPLE_MEDIA_TYPE_INFO_TYPE,
    G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
    purple_media_signals[CANDIDATE_PAIR_ESTABLISHED] = g_signal_new("candidate-pair-established", G_TYPE_FROM_CLASS(klass),
    - G_SIGNAL_RUN_LAST, 0, NULL, NULL,
    - purple_smarshal_VOID__POINTER_POINTER_OBJECT_OBJECT,
    + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
    G_TYPE_NONE, 4, G_TYPE_POINTER, G_TYPE_POINTER,
    PURPLE_TYPE_MEDIA_CANDIDATE, PURPLE_TYPE_MEDIA_CANDIDATE);
    g_type_class_add_private(klass, sizeof(PurpleMediaPrivate));
    --- a/libpurple/media/backend-iface.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/media/backend-iface.c Fri Jun 30 15:03:16 2017 +0300
    @@ -23,8 +23,6 @@
    #include "backend-iface.h"
    -#include "marshallers.h"
    -
    enum {
    S_ERROR,
    CANDIDATES_PREPARED,
    @@ -67,34 +65,29 @@
    G_PARAM_STATIC_STRINGS));
    purple_media_backend_signals[S_ERROR] =
    g_signal_new("error", G_TYPE_FROM_CLASS(iface),
    - G_SIGNAL_RUN_LAST, 0, NULL, NULL,
    - g_cclosure_marshal_VOID__STRING,
    + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
    G_TYPE_NONE, 1, G_TYPE_STRING);
    purple_media_backend_signals[CANDIDATES_PREPARED] =
    g_signal_new("candidates-prepared",
    G_TYPE_FROM_CLASS(iface),
    - G_SIGNAL_RUN_LAST, 0, NULL, NULL,
    - purple_smarshal_VOID__STRING_STRING,
    + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
    G_TYPE_NONE, 2, G_TYPE_STRING,
    G_TYPE_STRING);
    purple_media_backend_signals[CODECS_CHANGED] =
    g_signal_new("codecs-changed",
    G_TYPE_FROM_CLASS(iface),
    - G_SIGNAL_RUN_LAST, 0, NULL, NULL,
    - g_cclosure_marshal_VOID__STRING,
    + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
    G_TYPE_NONE, 1, G_TYPE_STRING);
    purple_media_backend_signals[NEW_CANDIDATE] =
    g_signal_new("new-candidate",
    G_TYPE_FROM_CLASS(iface),
    - G_SIGNAL_RUN_LAST, 0, NULL, NULL,
    - purple_smarshal_VOID__POINTER_POINTER_OBJECT,
    + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
    G_TYPE_NONE, 3, G_TYPE_POINTER,
    G_TYPE_POINTER, PURPLE_TYPE_MEDIA_CANDIDATE);
    purple_media_backend_signals[ACTIVE_CANDIDATE_PAIR] =
    g_signal_new("active-candidate-pair",
    G_TYPE_FROM_CLASS(iface),
    - G_SIGNAL_RUN_LAST, 0, NULL, NULL,
    - purple_smarshal_VOID__STRING_STRING_OBJECT_OBJECT,
    + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
    G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_STRING,
    PURPLE_TYPE_MEDIA_CANDIDATE,
    PURPLE_TYPE_MEDIA_CANDIDATE);
    --- a/libpurple/mediamanager.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/mediamanager.c Fri Jun 30 15:03:16 2017 +0300
    @@ -27,7 +27,6 @@
    #include "mediamanager.h"
    #ifdef USE_GSTREAMER
    -#include "marshallers.h"
    #include "media-gst.h"
    #include <media/backend-fs2.h>
    #endif /* USE_GSTREAMER */
    @@ -172,8 +171,7 @@
    purple_media_manager_signals[INIT_MEDIA] = g_signal_new ("init-media",
    G_TYPE_FROM_CLASS (klass),
    G_SIGNAL_RUN_LAST,
    - 0, NULL, NULL,
    - purple_smarshal_BOOLEAN__OBJECT_POINTER_STRING,
    + 0, NULL, NULL, NULL,
    G_TYPE_BOOLEAN, 3, PURPLE_TYPE_MEDIA,
    G_TYPE_POINTER, G_TYPE_STRING);
    @@ -181,16 +179,14 @@
    g_signal_new ("init-private-media",
    G_TYPE_FROM_CLASS (klass),
    G_SIGNAL_RUN_LAST,
    - 0, NULL, NULL,
    - purple_smarshal_BOOLEAN__OBJECT_POINTER_STRING,
    + 0, NULL, NULL, NULL,
    G_TYPE_BOOLEAN, 3, PURPLE_TYPE_MEDIA,
    G_TYPE_POINTER, G_TYPE_STRING);
    purple_media_manager_signals[UI_CAPS_CHANGED] = g_signal_new ("ui-caps-changed",
    G_TYPE_FROM_CLASS (klass),
    G_SIGNAL_RUN_LAST,
    - 0, NULL, NULL,
    - purple_smarshal_VOID__FLAGS_FLAGS,
    + 0, NULL, NULL, NULL,
    G_TYPE_NONE, 2, PURPLE_MEDIA_TYPE_CAPS,
    PURPLE_MEDIA_TYPE_CAPS);
    @@ -198,8 +194,7 @@
    g_signal_new("elements-changed",
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
    - 0, NULL, NULL,
    - g_cclosure_marshal_VOID__VOID,
    + 0, NULL, NULL, NULL,
    G_TYPE_NONE, 0);
    g_type_class_add_private(klass, sizeof(PurpleMediaManagerPrivate));
    --- a/libpurple/plugins/Makefile.am Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/plugins/Makefile.am Fri Jun 30 15:03:16 2017 +0300
    @@ -11,8 +11,6 @@
    autoaccept_la_LDFLAGS = -module @PLUGIN_LDFLAGS@
    buddynote_la_LDFLAGS = -module @PLUGIN_LDFLAGS@
    -caesarcipher_la_LDFLAGS = -module @PLUGIN_LDFLAGS@
    -caesarcipher_consumer_la_LDFLAGS = -module @PLUGIN_LDFLAGS@
    codeinline_la_LDFLAGS = -module @PLUGIN_LDFLAGS@
    debug_example_la_LDFLAGS = -module @PLUGIN_LDFLAGS@
    helloworld_la_LDFLAGS = -module @PLUGIN_LDFLAGS@
    @@ -44,8 +42,6 @@
    statenotify.la
    noinst_LTLIBRARIES = \
    - caesarcipher.la \
    - caesarcipher_consumer.la \
    codeinline.la \
    debug_example.la \
    helloworld.la \
    @@ -58,8 +54,6 @@
    autoaccept_la_SOURCES = autoaccept.c
    buddynote_la_SOURCES = buddynote.c
    -caesarcipher_la_SOURCES = caesarcipher.c caesarcipher.h
    -caesarcipher_consumer_la_SOURCES = caesarcipher_consumer.c
    codeinline_la_SOURCES = codeinline.c
    debug_example_la_SOURCES = debug_example.c
    helloworld_la_SOURCES = helloworld.c
    @@ -77,8 +71,6 @@
    autoaccept_la_LIBADD = @PURPLE_LIBS@
    buddynote_la_LIBADD = @PURPLE_LIBS@
    -caesarcipher_la_LIBADD = @PURPLE_LIBS@
    -caesarcipher_consumer_la_LIBADD = @PURPLE_LIBS@
    codeinline_la_LIBADD = @PURPLE_LIBS@
    idle_la_LIBADD = @PURPLE_LIBS@
    joinpart_la_LIBADD = @PURPLE_LIBS@
    @@ -128,11 +120,9 @@
    $(GLIB_CFLAGS) \
    $(GPLUGIN_CFLAGS) \
    $(PLUGIN_CFLAGS) \
    - $(DBUS_CFLAGS) \
    - $(NSS_CFLAGS)
    + $(DBUS_CFLAGS)
    -PLUGIN_LIBS = \
    - $(NSS_LIBS)
    +PLUGIN_LIBS =
    #
    # This part allows people to build their own plugins in here.
    --- a/libpurple/plugins/caesarcipher.c Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,212 +0,0 @@
    -/*
    - * An example plugin that demonstrates exporting of a cipher object
    - * type to be used in another plugin.
    - *
    - * This plugin only provides the CaesarCipher type. See caesarcipher_consumer
    - * plugin for its use.
    - *
    - * Copyright (C) 2013, Ankit Vani <a@nevitus.org>
    - *
    - * 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.
    - */
    -
    -/* When writing a third-party plugin, do not include libpurple's internal.h
    - * included below. This file is for internal libpurple use only. We're including
    - * it here for our own convenience. */
    -#include "internal.h"
    -
    -/* This file defines PURPLE_PLUGINS and includes all the libpurple headers */
    -#include <purple.h>
    -
    -#include "caesarcipher.h"
    -
    -#define CAESAR_CIPHER_GET_PRIVATE(obj) \
    - (G_TYPE_INSTANCE_GET_PRIVATE((obj), CAESAR_TYPE_CIPHER, CaesarCipherPrivate))
    -
    -typedef struct {
    - gint8 offset;
    -} CaesarCipherPrivate;
    -
    -enum {
    - PROP_NONE,
    - PROP_OFFSET,
    - PROP_LAST,
    -};
    -
    -/******************************************************************************
    - * Cipher stuff
    - *****************************************************************************/
    -static void
    -caesar_shift(const guchar input[], size_t in_len, guchar output[], gint8 offset)
    -{
    - size_t i;
    -
    - for (i = 0; i < in_len; ++i) {
    - if (input[i] >= 'a' && input[i] <= 'z')
    - output[i] = (((input[i] - 'a') + offset + 26) % 26) + 'a';
    - else if (input[i] >= 'A' && input[i] <= 'Z')
    - output[i] = (((input[i] - 'A') + offset + 26) % 26) + 'A';
    - else
    - output[i] = input[i];
    - }
    -
    - output[i] = '\0';
    -}
    -
    -static void
    -caesar_cipher_set_offset(PurpleCipher *cipher, gint8 offset)
    -{
    - CaesarCipherPrivate *priv = CAESAR_CIPHER_GET_PRIVATE(cipher);
    -
    - priv->offset = offset % 26;
    -}
    -
    -static ssize_t
    -caesar_cipher_encrypt(PurpleCipher *cipher, const guchar input[], size_t in_len,
    - guchar output[], size_t out_size)
    -{
    - CaesarCipherPrivate *priv = CAESAR_CIPHER_GET_PRIVATE(cipher);
    -
    - g_return_val_if_fail(out_size > in_len, -1);
    -
    - caesar_shift(input, in_len, output, priv->offset);
    -
    - return in_len;
    -}
    -
    -static ssize_t
    -caesar_cipher_decrypt(PurpleCipher *cipher, const guchar input[], size_t in_len,
    - guchar output[], size_t out_size)
    -{
    - CaesarCipherPrivate *priv = CAESAR_CIPHER_GET_PRIVATE(cipher);
    -
    - g_return_val_if_fail(out_size > in_len, -1);
    -
    - caesar_shift(input, in_len, output, -priv->offset);
    -
    - return in_len;
    -}
    -
    -static void
    -caesar_cipher_set_key(PurpleCipher *cipher, const guchar *key, size_t len)
    -{
    - caesar_cipher_set_offset(cipher, len);
    -}
    -
    -/******************************************************************************
    - * Object stuff
    - *****************************************************************************/
    -static void
    -caesar_cipher_set_property(GObject *obj, guint param_id, const GValue *value,
    - GParamSpec *pspec)
    -{
    - PurpleCipher *cipher = PURPLE_CIPHER(obj);
    -
    - switch(param_id) {
    - case PROP_OFFSET:
    - caesar_cipher_set_offset(cipher, g_value_get_schar(value));
    - break;
    - default:
    - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
    - break;
    - }
    -}
    -
    -/* initialize the cipher object. used in PURPLE_DEFINE_TYPE. */
    -static void
    -caesar_cipher_init(CaesarCipher *cipher)
    -{
    - /* classic caesar cipher uses a shift of 3 */
    - CAESAR_CIPHER_GET_PRIVATE(cipher)->offset = 3;
    -}
    -
    -/* initialize the cipher class. used in PURPLE_DEFINE_TYPE. */
    -static void
    -caesar_cipher_class_init(PurpleCipherClass *klass)
    -{
    - GObjectClass *obj_class = G_OBJECT_CLASS(klass);
    -
    - obj_class->set_property = caesar_cipher_set_property;
    - g_type_class_add_private(obj_class, sizeof(CaesarCipherPrivate));
    -
    - klass->encrypt = caesar_cipher_encrypt;
    - klass->decrypt = caesar_cipher_decrypt;
    - klass->set_key = caesar_cipher_set_key;
    -
    - g_object_class_install_property(obj_class, PROP_OFFSET,
    - g_param_spec_char("offset", "offset",
    - "The offset by which to shift alphabets",
    - -25, 25, 3,
    - G_PARAM_WRITABLE)
    - );
    -}
    -
    -/*
    - * define the CaesarCipher type. this function defines
    - * caesar_cipher_get_type() and caesar_cipher_register_type().
    - */
    -PURPLE_DEFINE_TYPE(CaesarCipher, caesar_cipher, PURPLE_TYPE_CIPHER);
    -
    -G_MODULE_EXPORT PurpleCipher *
    -caesar_cipher_new(void)
    -{
    - return g_object_new(CAESAR_TYPE_CIPHER, NULL);
    -}
    -
    -/******************************************************************************
    - * Plugin stuff
    - *****************************************************************************/
    -static PurplePluginInfo *
    -plugin_query(GError **error)
    -{
    - const gchar * const authors[] = {
    - "Ankit Vani <a@nevitus.org>",
    - NULL
    - };
    -
    - return purple_plugin_info_new(
    - "id", "core-caesarcipher",
    - "name", N_("Caesar Cipher Provider Example"),
    - "version", DISPLAY_VERSION,
    - "category", N_("Example"),
    - "summary", N_("An example plugin that demonstrates exporting of a "
    - "cipher type."),
    - "description", N_("An example plugin that demonstrates exporting of "
    - "a cipher object type to be used in another "
    - "plugin."),
    - "authors", authors,
    - "website", PURPLE_WEBSITE,
    - "abi-version", PURPLE_ABI_VERSION,
    - NULL
    - );
    -}
    -
    -static gboolean
    -plugin_load(PurplePlugin *plugin, GError **error)
    -{
    - /* register the CaesarCipher type in the type system */
    - caesar_cipher_register_type(plugin);
    -
    - return TRUE;
    -}
    -
    -static gboolean
    -plugin_unload(PurplePlugin *plugin, GError **error)
    -{
    - return TRUE;
    -}
    -
    -PURPLE_PLUGIN_INIT(caesarcipher, plugin_query, plugin_load, plugin_unload);
    --- a/libpurple/plugins/caesarcipher.h Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,67 +0,0 @@
    -/*
    - * An example plugin that demonstrates exporting of a cipher object
    - * type to be used in another plugin.
    - *
    - * Copyright (C) 2013, Ankit Vani <a@nevitus.org>
    - *
    - * 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 _CAESAR_CIPHER_H_
    -#define _CAESAR_CIPHER_H_
    -
    -#include "cipher.h"
    -
    -#define CAESAR_TYPE_CIPHER (caesar_cipher_get_type())
    -#define CAESAR_CIPHER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), CAESAR_TYPE_CIPHER, CaesarCipher))
    -#define CAESAR_CIPHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), CAESAR_TYPE_CIPHER, CaesarCipherClass))
    -#define CAESAR_IS_CIPHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), CAESAR_TYPE_CIPHER))
    -#define CAESAR_IS_CIPHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), CAESAR_TYPE_CIPHER))
    -#define CAESAR_CIPHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), CAESAR_TYPE_CIPHER, CaesarCipherClass))
    -
    -typedef struct _CaesarCipher CaesarCipher;
    -typedef struct _CaesarCipherClass CaesarCipherClass;
    -
    -/*
    - * A caesar cipher object.
    - *
    - * The Caesar cipher is one of the simplest and most widely known encryption
    - * techniques. It is a type of substitution cipher in which each letter in the
    - * plaintext is replaced by a letter some fixed number of positions down the
    - * alphabet.
    - */
    -struct _CaesarCipher
    -{
    - PurpleCipher gparent;
    -};
    -
    -/* The base class for all CaesarCipher's. */
    -struct _CaesarCipherClass
    -{
    - PurpleCipherClass gparent;
    -};
    -
    -/*
    - * Returns the GType for the CaesarCipher object.
    - */
    -G_MODULE_EXPORT GType caesar_cipher_get_type(void);
    -
    -/*
    - * Creates a new CaesarCipher instance and returns it.
    - */
    -G_MODULE_EXPORT PurpleCipher *caesar_cipher_new(void);
    -
    -#endif /* _CAESAR_CIPHER_H_ */
    --- a/libpurple/plugins/caesarcipher_consumer.c Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,117 +0,0 @@
    -/*
    - * An example plugin that demonstrates usage of a cipher object type
    - * registered in another plugin.
    - *
    - * This plugin requires the caesarcipher plugin to be loaded to use the
    - * CaesarCipher type.
    - *
    - * Copyright (C) 2013, Ankit Vani <a@nevitus.org>
    - *
    - * 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.
    - */
    -
    -/* When writing a third-party plugin, do not include libpurple's internal.h
    - * included below. This file is for internal libpurple use only. We're including
    - * it here for our own convenience. */
    -#include "internal.h"
    -
    -/* This file defines PURPLE_PLUGINS and includes all the libpurple headers */
    -#include <purple.h>
    -
    -#include "caesarcipher.h"
    -
    -static void
    -debug_cipher(PurpleCipher *cipher, const gchar *input)
    -{
    - gchar ciphertext[512], plaintext[512];
    -
    - purple_debug_info("caesarcipher_consumer", "Encrypting...");
    -
    - purple_debug_info("caesarcipher_consumer", "INPUT: %s\n", input);
    - purple_cipher_encrypt(cipher, (const guchar *)input, strlen(input),
    - (guchar *)ciphertext, 512);
    - purple_debug_info("caesarcipher_consumer", "OUTPUT: %s\n", ciphertext);
    -
    - purple_debug_info("caesarcipher_consumer", "Decrypting...");
    -
    - purple_debug_info("caesarcipher_consumer", "INPUT: %s\n", ciphertext);
    - purple_cipher_decrypt(cipher, (const guchar *)ciphertext,
    - strlen(ciphertext), (guchar *)plaintext, 512);
    - purple_debug_info("caesarcipher_consumer", "OUTPUT: %s\n", plaintext);
    -}
    -
    -static PurplePluginInfo *
    -plugin_query(GError **error)
    -{
    - const gchar * const authors[] = {
    - "Ankit Vani <a@nevitus.org>",
    - NULL
    - };
    -
    - /* we need to ensure the object provider is loaded for its type to be
    - * registered in the type system. */
    - const gchar * const dependencies[] = {
    - "core-caesarcipher",
    - NULL
    - };
    -
    - return purple_plugin_info_new(
    - "id", "core-caesarcipher_consumer",
    - "name", N_("Caesar Cipher Consumer Example"),
    - "version", DISPLAY_VERSION,
    - "category", N_("Example"),
    - "summary", N_("An example plugin that demonstrates usage of a "
    - "loaded cipher type."),
    - "description", N_("An example plugin that demonstrates usage of "
    - "a cipher object type registered in another "
    - "plugin."),
    - "authors", authors,
    - "website", PURPLE_WEBSITE,
    - "abi-version", PURPLE_ABI_VERSION,
    - "dependencies", dependencies,
    -
    - NULL
    - );
    -}
    -
    -static gboolean
    -plugin_load(PurplePlugin *plugin, GError **error)
    -{
    - PurpleCipher *cipher = caesar_cipher_new();
    - purple_debug_info("caesarcipher_consumer", "Created caesar cipher "
    - "object.\n");
    -
    - debug_cipher(cipher, "Input string for cipher!");
    -
    - purple_cipher_set_key(cipher, NULL, 13);
    - purple_debug_info("caesarcipher_consumer", "Offset set to 13.\n");
    -
    - debug_cipher(cipher, "An0ther input 4 cipher..");
    -
    - g_object_unref(cipher);
    - purple_debug_info("caesarcipher_consumer", "Destroyed caesar cipher "
    - "object.\n");
    -
    - return TRUE;
    -}
    -
    -static gboolean
    -plugin_unload(PurplePlugin *plugin, GError **error)
    -{
    - return TRUE;
    -}
    -
    -PURPLE_PLUGIN_INIT(caesarcipher_consumer, plugin_query, plugin_load, plugin_unload);
    --- a/libpurple/plugins/keyrings/Makefile.am Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/plugins/keyrings/Makefile.am Fri Jun 30 15:03:16 2017 +0300
    @@ -5,10 +5,14 @@
    plugindir = @PURPLE_PLUGINDIR@
    -internalkeyring_la_CFLAGS = $(AM_CPPFLAGS)
    +if ENABLE_NETTLE
    +
    +internalkeyring_la_CFLAGS = $(AM_CPPFLAGS) $(NETTLE_CFLAGS)
    internalkeyring_la_LDFLAGS = -module @PLUGIN_LDFLAGS@
    internalkeyring_la_SOURCES = internalkeyring.c
    -internalkeyring_la_LIBADD = @PURPLE_LIBS@
    +internalkeyring_la_LIBADD = @PURPLE_LIBS@ $(NETTLE_LIBS)
    +
    +endif
    if ENABLE_SECRETSERVICE
    @@ -56,8 +60,12 @@
    if PLUGINS
    -plugin_LTLIBRARIES = \
    +plugin_LTLIBRARIES =
    +
    +if ENABLE_NETTLE
    +plugin_LTLIBRARIES += \
    internalkeyring.la
    +endif
    if ENABLE_SECRETSERVICE
    plugin_LTLIBRARIES += \
    --- a/libpurple/plugins/keyrings/internalkeyring.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/plugins/keyrings/internalkeyring.c Fri Jun 30 15:03:16 2017 +0300
    @@ -31,8 +31,9 @@
    #include "plugins.h"
    #include "version.h"
    -#include "ciphers/aescipher.h"
    -#include "ciphers/pbkdf2cipher.h"
    +#include <nettle/aes.h>
    +#include <nettle/cbc.h>
    +#include <nettle/pbkdf2.h>
    #define INTKEYRING_NAME N_("Internal keyring")
    #define INTKEYRING_DESCRIPTION N_("This plugin provides the default password " \
    @@ -45,7 +46,7 @@
    #define INTKEYRING_PBKDF2_ITERATIONS 10000
    #define INTKEYRING_PBKDF2_ITERATIONS_MIN 1000
    #define INTKEYRING_PBKDF2_ITERATIONS_MAX 1000000000
    -#define INTKEYRING_KEY_LEN (256/8)
    +#define INTKEYRING_KEY_LEN AES256_KEY_SIZE
    #define INTKEYRING_ENCRYPT_BUFF_LEN 1000
    #define INTKEYRING_ENCRYPTED_MIN_LEN 50
    #define INTKEYRING_ENCRYPTION_METHOD "pbkdf2-sha256-aes256"
    @@ -150,33 +151,16 @@
    static intkeyring_buff_t *
    intkeyring_derive_key(const gchar *passphrase, intkeyring_buff_t *salt)
    {
    - PurpleCipher *cipher;
    - gboolean succ;
    intkeyring_buff_t *ret;
    g_return_val_if_fail(passphrase != NULL, NULL);
    - cipher = purple_pbkdf2_cipher_new(G_CHECKSUM_SHA256);
    -
    - g_object_set(G_OBJECT(cipher), "iter_count",
    - GUINT_TO_POINTER(purple_prefs_get_int(INTKEYRING_PREFS
    - "pbkdf2_iterations")), NULL);
    - g_object_set(G_OBJECT(cipher), "out_len", GUINT_TO_POINTER(
    - INTKEYRING_KEY_LEN), NULL);
    - purple_cipher_set_salt(cipher, salt->data, salt->len);
    - purple_cipher_set_key(cipher, (const guchar*)passphrase,
    - strlen(passphrase));
    -
    ret = intkeyring_buff_new(g_new(guchar, INTKEYRING_KEY_LEN),
    INTKEYRING_KEY_LEN);
    - succ = purple_cipher_digest(cipher, ret->data, ret->len);
    - g_object_unref(cipher);
    -
    - if (!succ) {
    - intkeyring_buff_free(ret);
    - return NULL;
    - }
    + pbkdf2_hmac_sha256(strlen(passphrase), (const uint8_t *)passphrase,
    + purple_prefs_get_int(INTKEYRING_PREFS"pbkdf2_iterations"),
    + salt->len, salt->data, ret->len, ret->data);
    return ret;
    }
    @@ -230,10 +214,11 @@
    static gchar *
    intkeyring_encrypt(intkeyring_buff_t *key, const gchar *str)
    {
    - PurpleCipher *cipher;
    + struct CBC_CTX(struct aes256_ctx, AES_BLOCK_SIZE) ctx;
    intkeyring_buff_t *iv;
    guchar plaintext[INTKEYRING_ENCRYPT_BUFF_LEN];
    size_t plaintext_len, text_len, verify_len;
    + int padding_len;
    guchar encrypted_raw[INTKEYRING_ENCRYPT_BUFF_LEN];
    ssize_t encrypted_size;
    @@ -249,31 +234,38 @@
    g_return_val_if_fail(plaintext_len + verify_len <= sizeof(plaintext),
    NULL);
    - cipher = purple_aes_cipher_new();
    - g_return_val_if_fail(cipher != NULL, NULL);
    -
    memset(plaintext, 0, plaintext_len);
    memcpy(plaintext, str, text_len);
    memcpy(plaintext + plaintext_len, INTKEYRING_VERIFY_STR, verify_len);
    plaintext_len += verify_len;
    - iv = intkeyring_gen_salt(purple_cipher_get_block_size(cipher));
    + /* Pad PKCS7 */
    + padding_len = AES_BLOCK_SIZE - (plaintext_len % AES_BLOCK_SIZE);
    +
    + if (plaintext_len + padding_len > INTKEYRING_ENCRYPT_BUFF_LEN) {
    + purple_debug_error("keyring-internal",
    + "Internal keyring encrypt buffer too small");
    + return NULL;
    + }
    +
    + memset(plaintext + plaintext_len, padding_len, padding_len);
    + plaintext_len += padding_len;
    +
    + /* Encrypt */
    + iv = intkeyring_gen_salt(AES_BLOCK_SIZE);
    g_return_val_if_fail(iv != NULL, NULL);
    - purple_cipher_set_iv(cipher, iv->data, iv->len);
    - purple_cipher_set_key(cipher, key->data, key->len);
    - purple_cipher_set_batch_mode(cipher,
    - PURPLE_CIPHER_BATCH_MODE_CBC);
    + aes256_set_encrypt_key(&ctx.ctx, key->data);
    + CBC_SET_IV(&ctx, iv->data);
    memcpy(encrypted_raw, iv->data, iv->len);
    - encrypted_size = purple_cipher_encrypt(cipher,
    - plaintext, plaintext_len, encrypted_raw + iv->len,
    - sizeof(encrypted_raw) - iv->len);
    + CBC_ENCRYPT(&ctx, aes256_encrypt, plaintext_len,
    + encrypted_raw + iv->len, plaintext);
    + encrypted_size = plaintext_len;
    encrypted_size += iv->len;
    memset(plaintext, 0, plaintext_len);
    intkeyring_buff_free(iv);
    - g_object_unref(cipher);
    if (encrypted_size < 0)
    return NULL;
    @@ -285,42 +277,63 @@
    static gchar *
    intkeyring_decrypt(intkeyring_buff_t *key, const gchar *str)
    {
    - PurpleCipher *cipher;
    + struct CBC_CTX(struct aes256_ctx, AES_BLOCK_SIZE) ctx;
    guchar *encrypted_raw;
    gsize encrypted_size;
    size_t iv_len, verify_len, text_len;
    guchar plaintext[INTKEYRING_ENCRYPT_BUFF_LEN];
    const gchar *verify_str = NULL;
    - ssize_t plaintext_len;
    + size_t plaintext_len;
    + guint padding_len;
    + guint i;
    gchar *ret;
    g_return_val_if_fail(key != NULL, NULL);
    g_return_val_if_fail(str != NULL, NULL);
    - cipher = purple_aes_cipher_new();
    - g_return_val_if_fail(cipher != NULL, NULL);
    -
    encrypted_raw = g_base64_decode(str, &encrypted_size);
    g_return_val_if_fail(encrypted_raw != NULL, NULL);
    - iv_len = purple_cipher_get_block_size(cipher);
    + iv_len = AES_BLOCK_SIZE;
    if (encrypted_size < iv_len) {
    g_free(encrypted_raw);
    return NULL;
    }
    - purple_cipher_set_iv(cipher, encrypted_raw, iv_len);
    - purple_cipher_set_key(cipher, key->data, key->len);
    - purple_cipher_set_batch_mode(cipher,
    - PURPLE_CIPHER_BATCH_MODE_CBC);
    + /* Decrypt */
    + aes256_set_decrypt_key(&ctx.ctx, key->data);
    + CBC_SET_IV(&ctx, encrypted_raw);
    + CBC_DECRYPT(&ctx, aes256_decrypt, encrypted_size - iv_len,
    + plaintext, encrypted_raw + iv_len);
    + plaintext_len = encrypted_size - iv_len;
    + g_free(encrypted_raw);
    - plaintext_len = purple_cipher_decrypt(cipher,
    - encrypted_raw + iv_len, encrypted_size - iv_len,
    - plaintext, sizeof(plaintext));
    + /* Unpad PKCS7 */
    + padding_len = plaintext[plaintext_len - 1];
    + if (padding_len == 0 || padding_len > AES_BLOCK_SIZE ||
    + padding_len > plaintext_len) {
    + purple_debug_warning("internal-keyring",
    + "Invalid padding length: %d (total %" G_GSIZE_FORMAT
    + ") - most probably, the key was invalid\n",
    + padding_len, plaintext_len);
    + return NULL;
    + }
    - g_free(encrypted_raw);
    - g_object_unref(cipher);
    + plaintext_len -= padding_len;
    + for (i = 0; i < padding_len; ++i) {
    + if (plaintext[plaintext_len + i] != padding_len) {
    + purple_debug_warning("internal-keyring",
    + "Padding doesn't match at pos %d (found %02x, "
    + "expected %02x) - "
    + "most probably, the key was invalid\n",
    + i, plaintext[plaintext_len + i], padding_len);
    + return NULL;
    + }
    + }
    + memset(plaintext + plaintext_len, 0, padding_len);
    +
    + /* Verify */
    verify_len = strlen(INTKEYRING_VERIFY_STR);
    /* Don't remove the len > 0 check! */
    if (plaintext_len > 0 && (gsize)plaintext_len > verify_len &&
    --- a/libpurple/protocols/facebook/Makefile.am Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/protocols/facebook/Makefile.am Fri Jun 30 15:03:16 2017 +0300
    @@ -1,12 +1,9 @@
    EXTRA_DIST = \
    - Makefile.mingw \
    - marshaller.list
    + Makefile.mingw
    pkgdir = @PURPLE_PLUGINDIR@
    FACEBOOKSOURCES = \
    - marshal.c \
    - marshal.h \
    api.c \
    api.h \
    data.c \
    @@ -25,17 +22,6 @@
    util.c \
    util.h
    -CLEANFILES = \
    - marshal.c \
    - marshal.h
    -
    -marshal.c: $(srcdir)/marshaller.list marshal.h
    - $(AM_V_GEN)echo "#include \"marshal.h\"" > $@
    - $(AM_V_at)$(GLIB_GENMARSHAL) --prefix=fb_marshal --body $(srcdir)/marshaller.list >> $@
    -
    -marshal.h: $(srcdir)/marshaller.list
    - $(AM_V_GEN)$(GLIB_GENMARSHAL) --prefix=fb_marshal --header $(srcdir)/marshaller.list > $@
    -
    AM_CFLAGS = $(st)
    libfacebook_la_LDFLAGS = -module @PLUGIN_LDFLAGS@
    --- a/libpurple/protocols/facebook/Makefile.mingw Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/protocols/facebook/Makefile.mingw Fri Jun 30 15:03:16 2017 +0300
    @@ -42,7 +42,6 @@
    ## SOURCES, OBJECTS
    ##
    C_SRC = \
    - marshal.c \
    api.c \
    data.c \
    facebook.c \
    @@ -85,18 +84,11 @@
    $(TARGET).dll: $(PURPLE_DLL).a $(OBJECTS)
    $(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -o $(TARGET).dll
    -marshal.c: marshaller.list marshal.h
    - @echo "#include \"marshal.h\"" > $@
    - @$(GLIB_GENMARSHAL) --prefix=fb_marshal --body marshaller.list >> $@
    -
    -marshal.h: marshaller.list
    - @$(GLIB_GENMARSHAL) --prefix=fb_marshal --header marshaller.list > $@
    -
    ##
    ## CLEAN RULES
    ##
    clean:
    - rm -f $(OBJECTS) marshal.c marshal.h
    + rm -f $(OBJECTS)
    rm -f $(TARGET).dll
    include $(PIDGIN_COMMON_TARGETS)
    --- a/libpurple/protocols/facebook/api.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/protocols/facebook/api.c Fri Jun 30 15:03:16 2017 +0300
    @@ -28,7 +28,6 @@
    #include "api.h"
    #include "http.h"
    #include "json.h"
    -#include "marshal.h"
    #include "thrift.h"
    #include "util.h"
    @@ -68,6 +67,7 @@
    gboolean invisible;
    guint unread;
    FbId lastmid;
    + gchar *contacts_delta;
    };
    struct _FbApiData
    @@ -88,6 +88,9 @@
    static void
    fb_api_sticker(FbApi *api, FbId sid, FbApiMessage *msg);
    +void
    +fb_api_contacts_delta(FbApi *api, const gchar *delta_cursor);
    +
    G_DEFINE_TYPE(FbApi, fb_api, G_TYPE_OBJECT);
    static void
    @@ -185,6 +188,7 @@
    g_free(priv->did);
    g_free(priv->stoken);
    g_free(priv->token);
    + g_free(priv->contacts_delta);
    }
    static void
    @@ -287,8 +291,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_ACTION,
    0,
    - NULL, NULL,
    - fb_marshal_VOID__VOID,
    + NULL, NULL, NULL,
    G_TYPE_NONE,
    0);
    @@ -303,8 +306,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_ACTION,
    0,
    - NULL, NULL,
    - fb_marshal_VOID__VOID,
    + NULL, NULL, NULL,
    G_TYPE_NONE,
    0);
    @@ -320,8 +322,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_ACTION,
    0,
    - NULL, NULL,
    - fb_marshal_VOID__POINTER,
    + NULL, NULL, NULL,
    G_TYPE_NONE,
    1, G_TYPE_POINTER);
    @@ -341,12 +342,27 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_ACTION,
    0,
    - NULL, NULL,
    - fb_marshal_VOID__POINTER_BOOLEAN,
    + NULL, NULL, NULL,
    G_TYPE_NONE,
    2, G_TYPE_POINTER, G_TYPE_BOOLEAN);
    /**
    + * FbApi::contacts-delta:
    + * @api: The #FbApi.
    + * @added: The #GSList of added #FbApiUser's.
    + * @removed: The #GSList of strings with removed user ids.
    + *
    + * Like 'contacts', but only the deltas.
    + */
    + g_signal_new("contacts-delta",
    + G_TYPE_FROM_CLASS(klass),
    + G_SIGNAL_ACTION,
    + 0,
    + NULL, NULL, NULL,
    + G_TYPE_NONE,
    + 2, G_TYPE_POINTER, G_TYPE_POINTER);
    +
    + /**
    * FbApi::error:
    * @api: The #FbApi.
    * @error: The #GError.
    @@ -358,10 +374,9 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_ACTION,
    0,
    - NULL, NULL,
    - fb_marshal_VOID__OBJECT,
    + NULL, NULL, NULL,
    G_TYPE_NONE,
    - 1, G_TYPE_ERROR);
    + 1, G_TYPE_POINTER);
    /**
    * FbApi::events:
    @@ -374,8 +389,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_ACTION,
    0,
    - NULL, NULL,
    - fb_marshal_VOID__POINTER,
    + NULL, NULL, NULL,
    G_TYPE_NONE,
    1, G_TYPE_POINTER);
    @@ -390,8 +404,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_ACTION,
    0,
    - NULL, NULL,
    - fb_marshal_VOID__POINTER,
    + NULL, NULL, NULL,
    G_TYPE_NONE,
    1, G_TYPE_POINTER);
    @@ -406,8 +419,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_ACTION,
    0,
    - NULL, NULL,
    - fb_marshal_VOID__POINTER,
    + NULL, NULL, NULL,
    G_TYPE_NONE,
    1, G_TYPE_POINTER);
    @@ -423,8 +435,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_ACTION,
    0,
    - NULL, NULL,
    - fb_marshal_VOID__POINTER,
    + NULL, NULL, NULL,
    G_TYPE_NONE,
    1, G_TYPE_POINTER);
    @@ -441,12 +452,27 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_ACTION,
    0,
    - NULL, NULL,
    - fb_marshal_VOID__INT64,
    + NULL, NULL, NULL,
    G_TYPE_NONE,
    1, FB_TYPE_ID);
    /**
    + * FbApi::thread-kicked:
    + * @api: The #FbApi.
    + * @thrd: The #FbApiThread.
    + *
    + * Emitted upon the reply of a thread request when the user is no longer
    + * part of that thread. This is emitted as a result of #fb_api_thread().
    + */
    + g_signal_new("thread-kicked",
    + G_TYPE_FROM_CLASS(klass),
    + G_SIGNAL_ACTION,
    + 0,
    + NULL, NULL, NULL,
    + G_TYPE_NONE,
    + 1, G_TYPE_POINTER);
    +
    + /**
    * FbApi::threads:
    * @api: The #FbApi.
    * @thrds: The #GSList of #FbApiThread's.
    @@ -458,8 +484,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_ACTION,
    0,
    - NULL, NULL,
    - fb_marshal_VOID__POINTER,
    + NULL, NULL, NULL,
    G_TYPE_NONE,
    1, G_TYPE_POINTER);
    @@ -474,8 +499,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_ACTION,
    0,
    - NULL, NULL,
    - fb_marshal_VOID__POINTER,
    + NULL, NULL, NULL,
    G_TYPE_NONE,
    1, G_TYPE_POINTER);
    }
    @@ -762,6 +786,9 @@
    g_free(data);
    }
    + purple_http_request_header_set(req, "User-Agent", FB_API_AGENT);
    + purple_http_request_header_set(req, "Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
    +
    data = fb_http_params_close(params, NULL);
    purple_http_request_set_contents(req, data, -1);
    ret = purple_http_request(priv->gc, req, callback, api);
    @@ -794,12 +821,16 @@
    case FB_API_QUERY_CONTACTS_AFTER:
    name = "FetchContactsFullWithAfterQuery";
    break;
    + case FB_API_QUERY_CONTACTS_DELTA:
    + name = "FetchContactsDeltaQuery";
    + break;
    case FB_API_QUERY_STICKER:
    name = "FetchStickersWithPreviewsQuery";
    break;
    case FB_API_QUERY_THREAD:
    name = "ThreadQuery";
    break;
    + case FB_API_QUERY_SEQ_ID:
    case FB_API_QUERY_THREADS:
    name = "ThreadListQuery";
    break;
    @@ -883,7 +914,7 @@
    /* Write the information string */
    fb_thrift_write_field(thft, FB_THRIFT_TYPE_STRING, 2, 1);
    - fb_thrift_write_str(thft, "");
    + fb_thrift_write_str(thft, FB_API_MQTT_AGENT);
    /* Write the UNKNOWN ("cp"?) */
    fb_thrift_write_field(thft, FB_THRIFT_TYPE_I64, 3, 2);
    @@ -1029,7 +1060,7 @@
    }
    values = fb_json_values_new(root);
    - fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE,
    + fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
    "$.viewer.message_threads.sync_sequence_id");
    fb_json_values_add(values, FB_JSON_TYPE_INT, TRUE,
    "$.viewer.message_threads.unread_count");
    @@ -1045,7 +1076,13 @@
    priv->sid = g_ascii_strtoll(str, NULL, 10);
    priv->unread = fb_json_values_next_int(values, 0);
    - fb_api_connect_queue(api);
    + if (priv->sid == 0) {
    + fb_api_error(api, FB_API_ERROR_GENERAL,
    + _("Failed to get sync_sequence_id"));
    + } else {
    + fb_api_connect_queue(api);
    + }
    +
    g_object_unref(values);
    json_node_free(root);
    }
    @@ -1087,7 +1124,7 @@
    if (priv->sid == 0) {
    bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
    fb_json_bldr_add_str(bldr, "1", "0");
    - fb_api_http_query(api, FB_API_QUERY_THREADS, bldr,
    + fb_api_http_query(api, FB_API_QUERY_SEQ_ID, bldr,
    fb_api_cb_seqid);
    } else {
    fb_api_connect_queue(api);
    @@ -1363,7 +1400,11 @@
    if (purple_strequal(str, "ExternalUrl")) {
    params = fb_http_params_new_parse(url, TRUE);
    - text = fb_http_params_dup_str(params, "u", NULL);
    + if (g_str_has_prefix(url, FB_API_FBRPC_PREFIX)) {
    + text = fb_http_params_dup_str(params, "target_url", NULL);
    + } else {
    + text = fb_http_params_dup_str(params, "u", NULL);
    + }
    fb_http_params_free(params);
    } else {
    text = g_strdup(url);
    @@ -1396,8 +1437,7 @@
    values = fb_json_values_new(root);
    fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE, "$.xmaGraphQL");
    fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE, "$.fbid");
    - fb_json_values_set_array(values, FALSE, "$.deltaNewMessage"
    - ".attachments");
    + fb_json_values_set_array(values, FALSE, "$.attachments");
    while (fb_json_values_update(values, &err)) {
    str = fb_json_values_next_str(values, NULL);
    @@ -1439,25 +1479,40 @@
    return msgs;
    }
    +
    +static GSList *
    +fb_api_cb_publish_ms_new_message(FbApi *api, JsonNode *root, GSList *msgs, GError **error);
    +
    +static GSList *
    +fb_api_cb_publish_ms_event(FbApi *api, JsonNode *root, GSList *events, FbApiEventType type, GError **error);
    +
    static void
    fb_api_cb_publish_ms(FbApi *api, GByteArray *pload)
    {
    - const gchar *body;
    const gchar *data;
    - const gchar *str;
    - FbApiMessage *dmsg;
    - FbApiMessage msg;
    FbApiPrivate *priv = api->priv;
    - FbId id;
    - FbId oid;
    FbJsonValues *values;
    FbThrift *thft;
    gchar *stoken;
    GError *err = NULL;
    + GList *elms, *l;
    GSList *msgs = NULL;
    + GSList *events = NULL;
    guint size;
    JsonNode *root;
    JsonNode *node;
    + JsonArray *arr;
    +
    + static const struct {
    + const gchar *member;
    + FbApiEventType type;
    + gboolean is_message;
    + } event_types[] = {
    + {"deltaNewMessage", 0, 1},
    + {"deltaThreadName", FB_API_EVENT_TYPE_THREAD_TOPIC, 0},
    + {"deltaParticipantsAddedToGroupThread", FB_API_EVENT_TYPE_THREAD_USER_ADDED, 0},
    + {"deltaParticipantLeftGroupThread", FB_API_EVENT_TYPE_THREAD_USER_REMOVED, 0},
    + };
    /* Read identifier string (for Facebook employees) */
    thft = fb_thrift_new(pload, 0);
    @@ -1497,39 +1552,100 @@
    return;
    }
    + arr = fb_json_node_get_arr(root, "$.deltas", NULL);
    + elms = json_array_get_elements(arr);
    +
    + for (l = elms; l != NULL; l = l->next) {
    + guint i = 0;
    + JsonObject *o = json_node_get_object(l->data);
    +
    + for (i = 0; i < G_N_ELEMENTS(event_types); i++) {
    + if ((node = json_object_get_member(o, event_types[i].member))) {
    + if (event_types[i].is_message) {
    + msgs = fb_api_cb_publish_ms_new_message(
    + api, node, msgs, &err
    + );
    + } else {
    + events = fb_api_cb_publish_ms_event(
    + api, node, events, event_types[i].type, &err
    + );
    + }
    + }
    + }
    +
    + if (G_UNLIKELY(err != NULL)) {
    + break;
    + }
    + }
    +
    + g_list_free(elms);
    + json_array_unref(arr);
    +
    + if (G_LIKELY(err == NULL)) {
    + if (msgs) {
    + msgs = g_slist_reverse(msgs);
    + g_signal_emit_by_name(api, "messages", msgs);
    + }
    +
    + if (events) {
    + events = g_slist_reverse(events);
    + g_signal_emit_by_name(api, "events", events);
    + }
    + } else {
    + fb_api_error_emit(api, err);
    + }
    +
    + g_slist_free_full(msgs, (GDestroyNotify) fb_api_message_free);
    + g_slist_free_full(events, (GDestroyNotify) fb_api_event_free);
    + json_node_free(root);
    +}
    +
    +static GSList *
    +fb_api_cb_publish_ms_new_message(FbApi *api, JsonNode *root, GSList *msgs, GError **error)
    +{
    + const gchar *body;
    + const gchar *str;
    + GError *err = NULL;
    + FbApiPrivate *priv = api->priv;
    + FbApiMessage *dmsg;
    + FbApiMessage msg;
    + FbId id;
    + FbId oid;
    + FbJsonValues *values;
    + JsonNode *node;
    +
    values = fb_json_values_new(root);
    fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
    - "$.deltaNewMessage.messageMetadata.offlineThreadingId");
    + "$.messageMetadata.offlineThreadingId");
    fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
    - "$.deltaNewMessage.messageMetadata.actorFbId");
    + "$.messageMetadata.actorFbId");
    fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
    - "$.deltaNewMessage.messageMetadata"
    + "$.messageMetadata"
    ".threadKey.otherUserFbId");
    fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
    - "$.deltaNewMessage.messageMetadata"
    + "$.messageMetadata"
    ".threadKey.threadFbId");
    fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
    - "$.deltaNewMessage.messageMetadata.timestamp");
    + "$.messageMetadata.timestamp");
    fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
    - "$.deltaNewMessage.body");
    + "$.body");
    fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
    - "$.deltaNewMessage.stickerId");
    + "$.stickerId");
    fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
    - "$.deltaNewMessage.messageMetadata.messageId");
    - fb_json_values_set_array(values, TRUE, "$.deltas");
    -
    - while (fb_json_values_update(values, &err)) {
    + "$.messageMetadata.messageId");
    +
    + if (fb_json_values_update(values, &err)) {
    id = fb_json_values_next_int(values, 0);
    /* Ignore everything but new messages */
    if (id == 0) {
    - continue;
    + goto beach;
    }
    /* Ignore sequential duplicates */
    if (id == priv->lastmid) {
    fb_util_debug_info("Ignoring duplicate %" FB_ID_FORMAT, id);
    - continue;
    + goto beach;
    }
    priv->lastmid = id;
    @@ -1565,7 +1681,7 @@
    str = fb_json_values_next_str(values, NULL);
    if (str == NULL) {
    - continue;
    + goto beach;
    }
    node = fb_json_values_get_root(values);
    @@ -1573,20 +1689,97 @@
    node, &err);
    if (G_UNLIKELY(err != NULL)) {
    - break;
    + g_propagate_error(error, err);
    + goto beach;
    }
    }
    - if (G_LIKELY(err == NULL)) {
    - msgs = g_slist_reverse(msgs);
    - g_signal_emit_by_name(api, "messages", msgs);
    - } else {
    - fb_api_error_emit(api, err);
    +beach:
    + g_object_unref(values);
    + return msgs;
    +}
    +
    +static GSList *
    +fb_api_cb_publish_ms_event(FbApi *api, JsonNode *root, GSList *events, FbApiEventType type, GError **error)
    +{
    + FbApiEvent *event;
    + FbJsonValues *values = NULL;
    + FbJsonValues *values_inner = NULL;
    + GError *err = NULL;
    +
    + values = fb_json_values_new(root);
    + fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
    + "$.messageMetadata.threadKey.threadFbId");
    + fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
    + "$.messageMetadata.actorFbId");
    +
    + switch (type) {
    + case FB_API_EVENT_TYPE_THREAD_TOPIC:
    + fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
    + "$.name");
    + break;
    +
    + case FB_API_EVENT_TYPE_THREAD_USER_ADDED:
    + values_inner = fb_json_values_new(root);
    +
    + fb_json_values_add(values_inner, FB_JSON_TYPE_INT, FALSE,
    + "$.userFbId");
    +
    + /* use the text field for the full name */
    + fb_json_values_add(values_inner, FB_JSON_TYPE_STR, FALSE,
    + "$.fullName");
    +
    + fb_json_values_set_array(values_inner, FALSE,
    + "$.addedParticipants");
    + break;
    +
    + case FB_API_EVENT_TYPE_THREAD_USER_REMOVED:
    + fb_json_values_add(values, FB_JSON_TYPE_INT, FALSE,
    + "$.leftParticipantFbId");
    +
    + /* use the text field for the kick message */
    + fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
    + "$.messageMetadata.adminText");
    + break;
    }
    - g_slist_free_full(msgs, (GDestroyNotify) fb_api_message_free);
    + fb_json_values_update(values, &err);
    +
    + event = fb_api_event_dup(NULL, FALSE);
    + event->type = type;
    + event->tid = fb_json_values_next_int(values, 0);
    + event->uid = fb_json_values_next_int(values, 0);
    +
    + if (type == FB_API_EVENT_TYPE_THREAD_TOPIC) {
    + event->text = fb_json_values_next_str_dup(values, NULL);
    + } else if (type == FB_API_EVENT_TYPE_THREAD_USER_REMOVED) {
    + /* overwrite actor with subject */
    + event->uid = fb_json_values_next_int(values, 0);
    + event->text = fb_json_values_next_str_dup(values, NULL);
    + } else if (type == FB_API_EVENT_TYPE_THREAD_USER_ADDED) {
    +
    + while (fb_json_values_update(values_inner, &err)) {
    + FbApiEvent *devent = fb_api_event_dup(event, FALSE);
    +
    + devent->uid = fb_json_values_next_int(values_inner, 0);
    + devent->text = fb_json_values_next_str_dup(values_inner, NULL);
    +
    + events = g_slist_prepend(events, devent);
    + }
    + fb_api_event_free(event);
    + event = NULL;
    + g_object_unref(values_inner);
    + }
    +
    g_object_unref(values);
    - json_node_free(root);
    +
    + if (G_UNLIKELY(err != NULL)) {
    + g_propagate_error(error, err);
    + } else if (event) {
    + events = g_slist_prepend(events, event);
    + }
    +
    + return events;
    }
    static void
    @@ -2043,25 +2236,16 @@
    fb_api_http_query(api, FB_API_QUERY_CONTACT, bldr, fb_api_cb_contact);
    }
    -static void
    -fb_api_cb_contacts(PurpleHttpConnection *con, PurpleHttpResponse *res,
    - gpointer data)
    +static GSList *
    +fb_api_cb_contacts_nodes(FbApi *api, JsonNode *root, GSList *users)
    {
    - const gchar *cursor;
    const gchar *str;
    - FbApi *api = data;
    FbApiPrivate *priv = api->priv;
    FbApiUser *user;
    FbId uid;
    FbJsonValues *values;
    - gboolean complete;
    + gboolean is_array;
    GError *err = NULL;
    - GSList *users = NULL;
    - JsonNode *root;
    -
    - if (!fb_api_http_chk(api, con, res, &root)) {
    - return;
    - }
    values = fb_json_values_new(root);
    fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
    @@ -2072,8 +2256,12 @@
    "$.structured_name.text");
    fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
    "$.hugePictureUrl.uri");
    - fb_json_values_set_array(values, FALSE, "$.viewer.messenger_contacts"
    - ".nodes");
    +
    + is_array = (JSON_NODE_TYPE(root) == JSON_NODE_ARRAY);
    +
    + if (is_array) {
    + fb_json_values_set_array(values, FALSE, "$");
    + }
    while (fb_json_values_update(values, &err)) {
    str = fb_json_values_next_str(values, "0");
    @@ -2083,6 +2271,9 @@
    if ((!purple_strequal(str, "ARE_FRIENDS") &&
    (uid != priv->uid)) || (uid == 0))
    {
    + if (!is_array) {
    + break;
    + }
    continue;
    }
    @@ -2094,20 +2285,123 @@
    user->csum = fb_api_user_icon_checksum(user->icon);
    users = g_slist_prepend(users, user);
    +
    + if (!is_array) {
    + break;
    + }
    }
    g_object_unref(values);
    - values = fb_json_values_new(root);
    + return users;
    +}
    +
    +/* base64(contact:<our id>:<their id>:<whatever>) */
    +static GSList *
    +fb_api_cb_contacts_parse_removed(FbApi *api, JsonNode *node, GSList *users)
    +{
    + gsize len;
    + char **split;
    + char *decoded = (char *) g_base64_decode(json_node_get_string(node), &len);
    +
    + g_return_val_if_fail(decoded[len] == '\0', users);
    + g_return_val_if_fail(len == strlen(decoded), users);
    + g_return_val_if_fail(g_str_has_prefix(decoded, "contact:"), users);
    +
    + split = g_strsplit_set(decoded, ":", 4);
    +
    + g_return_val_if_fail(g_strv_length(split) == 4, users);
    +
    + users = g_slist_prepend(users, g_strdup(split[2]));
    +
    + g_strfreev(split);
    + g_free(decoded);
    +
    + return users;
    +}
    +
    +static void
    +fb_api_cb_contacts(PurpleHttpConnection *con, PurpleHttpResponse *res,
    + gpointer data)
    +{
    + const gchar *cursor;
    + const gchar *delta_cursor;
    + FbApi *api = data;
    + FbApiPrivate *priv = api->priv;
    + FbJsonValues *values;
    + gboolean complete;
    + gboolean is_delta;
    + GError *err = NULL;
    + GList *l;
    + GSList *users = NULL;
    + JsonNode *root;
    + JsonNode *croot;
    + JsonNode *node;
    +
    + if (!fb_api_http_chk(api, con, res, &root)) {
    + return;
    + }
    +
    + croot = fb_json_node_get(root, "$.viewer.messenger_contacts.deltas", NULL);
    + is_delta = (croot != NULL);
    +
    + if (!is_delta) {
    + croot = fb_json_node_get(root, "$.viewer.messenger_contacts", NULL);
    + node = fb_json_node_get(croot, "$.nodes", NULL);
    + users = fb_api_cb_contacts_nodes(api, node, users);
    + json_node_free(node);
    +
    + } else {
    + GSList *added = NULL;
    + GSList *removed = NULL;
    + JsonArray *arr = fb_json_node_get_arr(croot, "$.nodes", NULL);
    + GList *elms = json_array_get_elements(arr);
    +
    + for (l = elms; l != NULL; l = l->next) {
    + if ((node = fb_json_node_get(l->data, "$.added", NULL))) {
    + added = fb_api_cb_contacts_nodes(api, node, added);
    + json_node_free(node);
    + }
    +
    + if ((node = fb_json_node_get(l->data, "$.removed", NULL))) {
    + removed = fb_api_cb_contacts_parse_removed(api, node, removed);
    + json_node_free(node);
    + }
    + }
    +
    + g_signal_emit_by_name(api, "contacts-delta", added, removed);
    +
    + g_slist_free_full(added, (GDestroyNotify) fb_api_user_free);
    + g_slist_free_full(removed, (GDestroyNotify) g_free);
    +
    + g_list_free(elms);
    + json_array_unref(arr);
    + }
    +
    + values = fb_json_values_new(croot);
    + fb_json_values_add(values, FB_JSON_TYPE_BOOL, FALSE,
    + "$.page_info.has_next_page");
    fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
    - "$.viewer.messenger_contacts.page_info.end_cursor");
    + "$.page_info.delta_cursor");
    + fb_json_values_add(values, FB_JSON_TYPE_STR, FALSE,
    + "$.page_info.end_cursor");
    fb_json_values_update(values, NULL);
    + complete = !fb_json_values_next_bool(values, FALSE);
    +
    + delta_cursor = fb_json_values_next_str(values, NULL);
    +
    cursor = fb_json_values_next_str(values, NULL);
    if (G_UNLIKELY(err == NULL)) {
    - complete = (cursor == NULL);
    - g_signal_emit_by_name(api, "contacts", users, complete);
    + if (is_delta || complete) {
    + g_free(priv->contacts_delta);
    + priv->contacts_delta = g_strdup(is_delta ? cursor : delta_cursor);
    + }
    +
    + if (users) {
    + g_signal_emit_by_name(api, "contacts", users, complete);
    + }
    if (!complete) {
    fb_api_contacts_after(api, cursor);
    @@ -2118,14 +2412,25 @@
    g_slist_free_full(users, (GDestroyNotify) fb_api_user_free);
    g_object_unref(values);
    +
    + json_node_free(croot);
    json_node_free(root);
    }
    void
    fb_api_contacts(FbApi *api)
    {
    + FbApiPrivate *priv;
    JsonBuilder *bldr;
    + g_return_if_fail(FB_IS_API(api));
    + priv = api->priv;
    +
    + if (priv->contacts_delta) {
    + fb_api_contacts_delta(api, priv->contacts_delta);
    + return;
    + }
    +
    bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
    fb_json_bldr_arr_begin(bldr, "0");
    fb_json_bldr_add_str(bldr, NULL, "user");
    @@ -2153,6 +2458,24 @@
    }
    void
    +fb_api_contacts_delta(FbApi *api, const gchar *delta_cursor)
    +{
    + JsonBuilder *bldr;
    +
    + bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
    +
    + fb_json_bldr_add_str(bldr, "0", delta_cursor);
    +
    + fb_json_bldr_arr_begin(bldr, "1");
    + fb_json_bldr_add_str(bldr, NULL, "user");
    + fb_json_bldr_arr_end(bldr);
    +
    + fb_json_bldr_add_str(bldr, "2", G_STRINGIFY(FB_API_CONTACTS_COUNT));
    + fb_api_http_query(api, FB_API_QUERY_CONTACTS_DELTA, bldr,
    + fb_api_cb_contacts);
    +}
    +
    +void
    fb_api_connect(FbApi *api, gboolean invisible)
    {
    FbApiPrivate *priv;
    @@ -2603,6 +2926,7 @@
    FbId uid;
    FbJsonValues *values;
    gboolean haself = FALSE;
    + guint num_users = 0;
    GError *err = NULL;
    values = fb_json_values_new(root);
    @@ -2638,6 +2962,7 @@
    while (fb_json_values_update(values, &err)) {
    str = fb_json_values_next_str(values, "0");
    uid = FB_ID_FROM_STR(str);
    + num_users++;
    if (uid != priv->uid) {
    user = fb_api_user_dup(NULL, FALSE);
    @@ -2656,8 +2981,7 @@
    return FALSE;
    }
    - if ((g_slist_length(thrd->users) < 2) || !haself) {
    - fb_api_thread_reset(thrd, TRUE);
    + if (num_users < 2 || !haself) {
    g_object_unref(values);
    return FALSE;
    }
    @@ -2693,8 +3017,12 @@
    if (!fb_api_thread_parse(api, &thrd, node, &err)) {
    if (G_LIKELY(err == NULL)) {
    - fb_api_error(api, FB_API_ERROR_GENERAL,
    - _("Failed to parse thread information"));
    + if (thrd.tid) {
    + g_signal_emit_by_name(api, "thread-kicked", &thrd);
    + } else {
    + fb_api_error(api, FB_API_ERROR_GENERAL,
    + _("Failed to parse thread information"));
    + }
    } else {
    fb_api_error_emit(api, err);
    }
    @@ -2738,7 +3066,7 @@
    }
    values = fb_json_values_new(root);
    - fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.thread_fbid");
    + fb_json_values_add(values, FB_JSON_TYPE_STR, TRUE, "$.id");
    fb_json_values_update(values, &err);
    FB_API_ERROR_EMIT(api, err,
    @@ -2785,8 +3113,8 @@
    json = fb_json_bldr_close(bldr, JSON_NODE_ARRAY, NULL);
    prms = fb_http_params_new();
    - fb_http_params_set_str(prms, "to", json);
    - fb_api_http_req(api, FB_API_URL_THREADS, "createThread", "POST",
    + fb_http_params_set_str(prms, "recipients", json);
    + fb_api_http_req(api, FB_API_URL_THREADS, "createGroup", "POST",
    prms, fb_api_cb_thread_create);
    g_free(json);
    }
    @@ -2807,7 +3135,7 @@
    prms = fb_http_params_new();
    fb_http_params_set_str(prms, "to", json);
    - fb_http_params_set_strf(prms, "id", "t_id.%" FB_ID_FORMAT, tid);
    + fb_http_params_set_strf(prms, "id", "t_%" FB_ID_FORMAT, tid);
    fb_api_http_req(api, FB_API_URL_PARTS, "addMembers", "POST",
    prms, fb_api_cb_http_bool);
    g_free(json);
    @@ -2825,7 +3153,7 @@
    priv = api->priv;
    prms = fb_http_params_new();
    - fb_http_params_set_strf(prms, "id", "t_id.%" FB_ID_FORMAT, tid);
    + fb_http_params_set_strf(prms, "id", "t_%" FB_ID_FORMAT, tid);
    if (uid == 0) {
    uid = priv->uid;
    @@ -2850,7 +3178,7 @@
    prms = fb_http_params_new();
    fb_http_params_set_str(prms, "name", topic);
    - fb_http_params_set_strf(prms, "tid", "t_id.%" FB_ID_FORMAT, tid);
    + fb_http_params_set_int(prms, "tid", tid);
    fb_api_http_req(api, FB_API_URL_TOPIC, "setThreadName",
    "messaging.setthreadname", prms,
    fb_api_cb_http_bool);
    --- a/libpurple/protocols/facebook/api.h Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/protocols/facebook/api.h Fri Jun 30 15:03:16 2017 +0300
    @@ -77,6 +77,13 @@
    #define FB_API_WHOST "https://www.facebook.com"
    /**
    + * FB_API_FBRPC_PREFIX
    + *
    + * The fbrpc URL prefix used in links shared from the mobile app.
    + */
    +#define FB_API_FBRPC_PREFIX "fbrpc://facebook/nativethirdparty"
    +
    +/**
    * FB_API_KEY:
    *
    * The Facebook API key.
    @@ -91,6 +98,30 @@
    #define FB_API_SECRET "374e60f8b9bb6b8cbb30f78030438895"
    /**
    + * FB_ORCA_AGENT
    + *
    + * The part of the user agent that looks like the official client, since the
    + * server started checking this.
    + */
    +
    +#define FB_ORCA_AGENT "[FBAN/Orca-Android;FBAV/109.0.0.17.70;FBPN/com.facebook.orca;FBLC/en_US;FBBV/52182662]"
    +
    +/**
    + * FB_API_AGENT:
    + *
    + * The HTTP User-Agent header.
    + */
    +#define FB_API_AGENT "Facebook plugin / Purple / 0.9.5 " FB_ORCA_AGENT
    +
    +/**
    + * FB_API_MQTT_AGENT
    + *
    + * The client information string sent in the MQTT CONNECT message
    + */
    +
    +#define FB_API_MQTT_AGENT FB_API_AGENT
    +
    +/**
    * FB_API_URL_ATTACH:
    *
    * The URL for attachment URL requests.
    @@ -131,7 +162,7 @@
    *
    * The URL for thread management requests.
    */
    -#define FB_API_URL_THREADS FB_API_GHOST "/me/threads"
    +#define FB_API_URL_THREADS FB_API_GHOST "/me/group_threads"
    /**
    * FB_API_URL_TOPIC:
    @@ -165,10 +196,8 @@
    * 2: big_img_size
    * 3: huge_img_size
    * 4: small_img_size
    - * 5: low_res_cover_size
    - * 6: media_type
    */
    -#define FB_API_QUERY_CONTACTS 10153856456271729
    +#define FB_API_QUERY_CONTACTS 10154444360806729
    /**
    * FB_API_QUERY_CONTACTS_AFTER:
    @@ -182,10 +211,24 @@
    * 3: big_img_size
    * 4: huge_img_size
    * 5: small_img_size
    - * 6: low_res_cover_size
    - * 7: media_type
    */
    -#define FB_API_QUERY_CONTACTS_AFTER 10153856456281729
    +#define FB_API_QUERY_CONTACTS_AFTER 10154444360816729
    +
    +
    +/**
    + * FB_API_QUERY_CONTACTS_DELTA:
    + *
    + * The query hash for the `FetchContactsDeltaQuery`.
    + *
    + * Key mapping:
    + * 0: after
    + * 1: profile_types
    + * 2: limit
    + * 3: big_img_size
    + * 4: huge_img_size
    + * 5: small_img_size
    + */
    +#define FB_API_QUERY_CONTACTS_DELTA 10154444360801729
    /**
    * FB_API_QUERY_STICKER:
    @@ -256,6 +299,16 @@
    #define FB_API_QUERY_THREADS 10153919752026729
    /**
    + * FB_API_QUERY_SEQ_ID:
    + *
    + * A variant of ThreadListQuery with sequence ID
    + *
    + * TODO: parameters.
    + */
    +
    +#define FB_API_QUERY_SEQ_ID 10155268192741729
    +
    +/**
    * FB_API_QUERY_XMA:
    *
    * The query hash for the `XMAQuery`.
    --- a/libpurple/protocols/facebook/data.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/protocols/facebook/data.c Fri Jun 30 15:03:16 2017 +0300
    @@ -243,6 +243,10 @@
    g_object_get_property(G_OBJECT(priv->api), fb_props_strs[i],
    &val);
    str = g_value_get_string(&val);
    +
    + if (purple_strequal(fb_props_strs[i], "token") && !purple_account_get_remember_password(acct)) {
    + str = "";
    + }
    purple_account_set_string(acct, fb_props_strs[i], str);
    g_value_unset(&val);
    }
    --- a/libpurple/protocols/facebook/facebook.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/protocols/facebook/facebook.c Fri Jun 30 15:03:16 2017 +0300
    @@ -68,15 +68,18 @@
    PurpleBlistNode *n;
    PurpleBlistNode *node;
    PurpleGroup *grp;
    + const gchar *title;
    if (friend) {
    - return purple_blist_get_default_group();
    + title = _("Facebook Friends");
    + } else {
    + title = _("Facebook Non-Friends");
    }
    - grp = purple_blist_find_group(_("Facebook Non-Friends"));
    + grp = purple_blist_find_group(title);
    if (G_UNLIKELY(grp == NULL)) {
    - grp = purple_group_new(_("Facebook Non-Friends"));
    + grp = purple_group_new(title);
    node = NULL;
    for (n = purple_blist_get_root(); n != NULL; n = n->next) {
    @@ -86,9 +89,10 @@
    /* Append to the end of the buddy list */
    purple_blist_add_group(grp, node);
    - node = PURPLE_BLIST_NODE(grp);
    - purple_blist_node_set_transient(node, TRUE);
    - purple_blist_node_set_bool(node, "collapsed", TRUE);
    + if (!friend) {
    + node = PURPLE_BLIST_NODE(grp);
    + purple_blist_node_set_bool(node, "collapsed", TRUE);
    + }
    }
    return grp;
    @@ -98,16 +102,13 @@
    fb_buddy_add_nonfriend(PurpleAccount *acct, FbApiUser *user)
    {
    gchar uid[FB_ID_STRMAX];
    - PurpleBlistNode *node;
    PurpleBuddy *bdy;
    PurpleGroup *grp;
    FB_ID_TO_STR(user->uid, uid);
    - bdy = purple_buddy_new(acct, uid, NULL);
    + bdy = purple_buddy_new(acct, uid, user->name);
    grp = fb_get_group(FALSE);
    - node = PURPLE_BLIST_NODE(bdy);
    - purple_blist_node_set_transient(node, TRUE);
    purple_buddy_set_server_alias(bdy, user->name);
    purple_blist_add_buddy(bdy, NULL, grp, NULL);
    }
    @@ -212,6 +213,28 @@
    }
    static void
    +fb_sync_contacts_add_timeout(FbData *fata)
    +{
    + gint sync;
    + PurpleConnection *gc;
    + PurpleAccount *acct;
    +
    + gc = fb_data_get_connection(fata);
    + acct = purple_connection_get_account(gc);
    +
    + sync = purple_account_get_int(acct, "sync-interval", 5);
    +
    + if (sync < 1) {
    + purple_account_set_int(acct, "sync-interval", 1);
    + sync = 1;
    + }
    +
    + sync *= 60 * 1000;
    + fb_data_add_timeout(fata, "sync-contacts", sync, fb_cb_sync_contacts,
    + fata);
    +}
    +
    +static void
    fb_cb_api_contacts(FbApi *api, GSList *users, gboolean complete, gpointer data)
    {
    const gchar *alias;
    @@ -220,9 +243,6 @@
    FbData *fata = data;
    FbId muid;
    gchar uid[FB_ID_STRMAX];
    - gint sync;
    - gpointer bata;
    - GSList *buddies;
    GSList *l;
    GValue val = G_VALUE_INIT;
    PurpleAccount *acct;
    @@ -272,7 +292,6 @@
    purple_blist_add_buddy(bdy, NULL, grp, NULL);
    }
    - purple_buddy_set_protocol_data(bdy, GINT_TO_POINTER(TRUE));
    purple_buddy_set_server_alias(bdy, user->name);
    csum = purple_buddy_icons_get_checksum_for_user(bdy);
    @@ -288,20 +307,6 @@
    return;
    }
    - buddies = purple_blist_find_buddies(acct, NULL);
    -
    - while (buddies != NULL) {
    - bdy = buddies->data;
    - bata = purple_buddy_get_protocol_data(bdy);
    - buddies = g_slist_delete_link(buddies, buddies);
    -
    - if (GPOINTER_TO_INT(bata)) {
    - purple_buddy_set_protocol_data(bdy, NULL);
    - } else if (purple_buddy_get_group(bdy) != grpn) {
    - purple_blist_remove_buddy(bdy);
    - }
    - }
    -
    if (state != PURPLE_CONNECTION_CONNECTED) {
    status = purple_account_get_active_status(acct);
    type = purple_status_get_status_type(status);
    @@ -311,16 +316,52 @@
    fb_api_connect(api, pstat == PURPLE_STATUS_INVISIBLE);
    }
    - sync = purple_account_get_int(acct, "sync-interval", 30);
    + fb_sync_contacts_add_timeout(fata);
    +}
    +
    +static void
    +fb_cb_api_contacts_delta(FbApi *api, GSList *added, GSList *removed, gpointer data)
    +{
    + FbApiUser *user;
    + FbData *fata = data;
    + gchar uid[FB_ID_STRMAX];
    + GSList *l;
    + PurpleAccount *acct;
    + PurpleBuddy *bdy;
    + PurpleConnection *gc;
    + PurpleGroup *grp;
    + PurpleGroup *grpn;
    - if (sync < 5) {
    - purple_account_set_int(acct, "sync-interval", 5);
    - sync = 5;
    + gc = fb_data_get_connection(fata);
    + acct = purple_connection_get_account(gc);
    + grp = fb_get_group(TRUE);
    + grpn = fb_get_group(FALSE);
    +
    + for (l = added; l != NULL; l = l->next) {
    + user = l->data;
    + FB_ID_TO_STR(user->uid, uid);
    +
    + bdy = purple_blist_find_buddy(acct, uid);
    +
    + if ((bdy != NULL) && (purple_buddy_get_group(bdy) == grpn)) {
    + purple_blist_remove_buddy(bdy);
    + }
    +
    + bdy = purple_buddy_new(acct, uid, NULL);
    + purple_blist_add_buddy(bdy, NULL, grp, NULL);
    +
    + purple_buddy_set_server_alias(bdy, user->name);
    }
    - sync *= 60 * 1000;
    - fb_data_add_timeout(fata, "sync-contacts", sync, fb_cb_sync_contacts,
    - fata);
    + for (l = removed; l != NULL; l = l->next) {
    + bdy = purple_blist_find_buddy(acct, l->data);
    +
    + if (bdy != NULL) {
    + purple_blist_remove_buddy(bdy);
    + }
    + }
    +
    + fb_sync_contacts_add_timeout(fata);
    }
    static void
    @@ -397,8 +438,18 @@
    case FB_API_EVENT_TYPE_THREAD_USER_ADDED:
    if (purple_blist_find_buddy(acct, uid) == NULL) {
    - g_hash_table_insert(fetch, &event->tid, event);
    - break;
    + if (event->text) {
    + FbApiUser *user = fb_api_user_dup(NULL, FALSE);
    + user->uid = event->uid;
    + user->name = g_strdup(event->text);
    +
    + fb_buddy_add_nonfriend(acct, user);
    +
    + fb_api_user_free(user);
    + } else {
    + g_hash_table_insert(fetch, &event->tid, event);
    + break;
    + }
    }
    purple_chat_conversation_add_user(chat, uid, NULL, 0,
    @@ -406,7 +457,7 @@
    break;
    case FB_API_EVENT_TYPE_THREAD_USER_REMOVED:
    - purple_chat_conversation_remove_user(chat, uid, NULL);
    + purple_chat_conversation_remove_user(chat, uid, event->text);
    break;
    }
    }
    @@ -664,6 +715,39 @@
    }
    static void
    +fb_cb_api_thread_kicked(FbApi *api, FbApiThread *thrd, gpointer data)
    +{
    + FbData *fata = data;
    + gchar tid[FB_ID_STRMAX];
    + PurpleAccount *acct;
    + PurpleConnection *gc;
    + PurpleChatConversation *chat;
    +
    + FB_ID_TO_STR(thrd->tid, tid);
    +
    + gc = fb_data_get_connection(fata);
    + acct = purple_connection_get_account(gc);
    + chat = purple_conversations_find_chat_with_account(tid, acct);
    +
    + if (chat == NULL) {
    + PurpleRequestCommonParameters *cpar;
    +
    + cpar = purple_request_cpar_from_connection(gc);
    + purple_notify_error(gc,
    + _("Join a Chat"),
    + _("Failed to Join Chat"),
    + _("You have been removed from this chat"),
    + cpar);
    + return;
    + }
    +
    + purple_conversation_write_system_message(PURPLE_CONVERSATION(chat),
    + _("You have been removed from this chat"), 0);
    +
    + purple_serv_got_chat_left(gc, purple_chat_conversation_get_id(chat));
    +}
    +
    +static void
    fb_cb_api_threads(FbApi *api, GSList *thrds, gpointer data)
    {
    const gchar *alias;
    @@ -743,11 +827,32 @@
    }
    }
    +static void
    +fb_mark_read(FbData *fata, FbId id, gboolean thread)
    +{
    + FbApi *api;
    + PurpleAccount *acct;
    + PurpleConnection *gc;
    +
    + gc = fb_data_get_connection(fata);
    + acct = purple_connection_get_account(gc);
    + api = fb_data_get_api(fata);
    +
    + if (!fb_data_get_unread(fata, id) ||
    + (purple_account_get_bool(acct, "mark-read-available", FALSE) &&
    + fb_api_is_invisible(api)))
    + {
    + return;
    + }
    +
    + fb_data_set_unread(fata, id, FALSE);
    + fb_api_read(api, id, thread);
    +}
    +
    static gboolean
    fb_cb_conv_read(gpointer data)
    {
    const gchar *name;
    - FbApi *api;
    FbData *fata;
    FbId id;
    gchar *tname;
    @@ -763,15 +868,9 @@
    fb_data_clear_timeout(fata, tname, FALSE);
    g_free(tname);
    - if (!purple_conversation_has_focus(conv) ||
    - !fb_data_get_unread(fata, id))
    - {
    - return FALSE;
    + if (purple_conversation_has_focus(conv)) {
    + fb_mark_read(fata, id, PURPLE_IS_CHAT_CONVERSATION(conv));
    }
    -
    - api = fb_data_get_api(fata);
    - fb_data_set_unread(fata, id, FALSE);
    - fb_api_read(api, id, PURPLE_IS_CHAT_CONVERSATION(conv));
    return FALSE;
    }
    @@ -918,6 +1017,10 @@
    G_CALLBACK(fb_cb_api_contacts),
    fata);
    g_signal_connect(api,
    + "contacts-delta",
    + G_CALLBACK(fb_cb_api_contacts_delta),
    + fata);
    + g_signal_connect(api,
    "error",
    G_CALLBACK(fb_cb_api_error),
    fata);
    @@ -942,6 +1045,10 @@
    G_CALLBACK(fb_cb_api_thread_create),
    fata);
    g_signal_connect(api,
    + "thread-kicked",
    + G_CALLBACK(fb_cb_api_thread_kicked),
    + fata);
    + g_signal_connect(api,
    "threads",
    G_CALLBACK(fb_cb_api_threads),
    fata);
    @@ -961,7 +1068,7 @@
    G_CALLBACK(fb_cb_conv_deleting),
    fata);
    - if (!fb_data_load(fata)) {
    + if (!fb_data_load(fata) || !purple_account_get_remember_password(acct)) {
    user = purple_account_get_username(acct);
    pass = purple_connection_get_password(gc);
    purple_connection_update_progress(gc, _("Authenticating"),
    @@ -1437,13 +1544,17 @@
    protocol->options = OPT_PROTO_CHAT_TOPIC;
    opt = purple_account_option_int_new(_("Buddy list sync interval"),
    - "sync-interval", 30);
    + "sync-interval", 5);
    opts = g_list_prepend(opts, opt);
    - opt = purple_account_option_bool_new(_("Mark messages as read"),
    + opt = purple_account_option_bool_new(_("Mark messages as read on focus"),
    "mark-read", TRUE);
    opts = g_list_prepend(opts, opt);
    + opt = purple_account_option_bool_new(_("Mark messages as read only when available"),
    + "mark-read-available", FALSE);
    + opts = g_list_prepend(opts, opt);
    +
    opt = purple_account_option_bool_new(_("Show self messages"),
    "show-self", TRUE);
    opts = g_list_prepend(opts, opt);
    --- a/libpurple/protocols/facebook/marshaller.list Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,6 +0,0 @@
    -VOID:INT64
    -VOID:OBJECT
    -VOID:POINTER
    -VOID:POINTER,BOOLEAN
    -VOID:STRING,BOXED
    -VOID:VOID
    --- a/libpurple/protocols/facebook/mqtt.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/protocols/facebook/mqtt.c Fri Jun 30 15:03:16 2017 +0300
    @@ -31,7 +31,6 @@
    #include "purple-gio.h"
    #include "queuedoutputstream.h"
    -#include "marshal.h"
    #include "mqtt.h"
    #include "util.h"
    @@ -97,8 +96,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_ACTION,
    0,
    - NULL, NULL,
    - fb_marshal_VOID__VOID,
    + NULL, NULL, NULL,
    G_TYPE_NONE,
    0);
    @@ -114,8 +112,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_ACTION,
    0,
    - NULL, NULL,
    - fb_marshal_VOID__OBJECT,
    + NULL, NULL, NULL,
    G_TYPE_NONE,
    1, G_TYPE_ERROR);
    @@ -131,8 +128,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_ACTION,
    0,
    - NULL, NULL,
    - fb_marshal_VOID__VOID,
    + NULL, NULL, NULL,
    G_TYPE_NONE,
    0);
    @@ -148,8 +144,7 @@
    G_TYPE_FROM_CLASS(klass),
    G_SIGNAL_ACTION,
    0,
    - NULL, NULL,
    - fb_marshal_VOID__STRING_BOXED,
    + NULL, NULL, NULL,
    G_TYPE_NONE,
    2, G_TYPE_STRING, G_TYPE_BYTE_ARRAY);
    }
    @@ -440,8 +435,10 @@
    do {
    if (pos >= count) {
    /* Not enough data yet, try again later */
    - size = 0;
    - break;
    + g_buffered_input_stream_fill_async(priv->input, -1,
    + G_PRIORITY_DEFAULT, priv->cancellable,
    + fb_mqtt_cb_fill, mqtt);
    + return;
    }
    byte = *(buf + pos++);
    @@ -450,28 +447,22 @@
    mult *= 128;
    } while ((byte & 128) != 0);
    - if (size > 0) {
    - /* Add header to size */
    - size += pos;
    + /* Add header to size */
    + size += pos;
    - g_byte_array_set_size(priv->rbuf, size);
    - priv->remz = size;
    + g_byte_array_set_size(priv->rbuf, size);
    + priv->remz = size;
    - /* TODO: Use g_input_stream_read_all_async() when available. */
    - /* TODO: Alternately, it would be nice to let the
    - * FbMqttMessage directly use the GBufferedInputStream
    - * buffer instead of copying it, provided it's consumed
    - * before the next read.
    - */
    - g_input_stream_read_async(G_INPUT_STREAM(priv->input),
    - priv->rbuf->data, priv->rbuf->len,
    - G_PRIORITY_DEFAULT, priv->cancellable,
    - fb_mqtt_cb_read_packet, mqtt);
    - } else {
    - g_buffered_input_stream_fill_async(priv->input, -1,
    - G_PRIORITY_DEFAULT, priv->cancellable,
    - fb_mqtt_cb_fill, mqtt);
    - }
    + /* TODO: Use g_input_stream_read_all_async() when available. */
    + /* TODO: Alternately, it would be nice to let the
    + * FbMqttMessage directly use the GBufferedInputStream
    + * buffer instead of copying it, provided it's consumed
    + * before the next read.
    + */
    + g_input_stream_read_async(G_INPUT_STREAM(priv->input),
    + priv->rbuf->data, priv->rbuf->len,
    + G_PRIORITY_DEFAULT, priv->cancellable,
    + fb_mqtt_cb_read_packet, mqtt);
    }
    void
    --- a/libpurple/protocols/jabber/tests/Makefile.am Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/protocols/jabber/tests/Makefile.am Fri Jun 30 15:03:16 2017 +0300
    @@ -33,5 +33,4 @@
    $(GPLUGIN_CFLAGS) \
    $(PLUGIN_CFLAGS) \
    $(DBUS_CFLAGS) \
    - $(LIBXML_CFLAGS) \
    - $(NSS_CFLAGS)
    + $(LIBXML_CFLAGS)
    --- a/libpurple/protocols/oscar/tests/Makefile.am Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/protocols/oscar/tests/Makefile.am Fri Jun 30 15:03:16 2017 +0300
    @@ -19,5 +19,4 @@
    $(GLIB_CFLAGS) \
    $(GPLUGIN_CFLAGS) \
    $(PLUGIN_CFLAGS) \
    - $(DBUS_CFLAGS) \
    - $(NSS_CFLAGS)
    + $(DBUS_CFLAGS)
    --- a/libpurple/protocols/simple/Makefile.am Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/protocols/simple/Makefile.am Fri Jun 30 15:03:16 2017 +0300
    @@ -14,6 +14,7 @@
    AM_CFLAGS = $(st)
    libsimple_la_LDFLAGS = -module @PLUGIN_LDFLAGS@
    +libsimple_la_LIBADD = $(NETTLE_LIBS)
    if STATIC_SIMPLE
    @@ -27,7 +28,7 @@
    st =
    pkg_LTLIBRARIES = libsimple.la
    libsimple_la_SOURCES = $(SIMPLESOURCES)
    -libsimple_la_LIBADD = @PURPLE_LIBS@
    +libsimple_la_LIBADD += @PURPLE_LIBS@
    endif
    @@ -36,4 +37,5 @@
    -I$(top_builddir)/libpurple \
    $(GLIB_CFLAGS) \
    $(GPLUGIN_CFLAGS) \
    - $(DEBUG_CFLAGS)
    + $(DEBUG_CFLAGS) \
    + $(NETTLE_CFLAGS)
    --- a/libpurple/protocols/simple/ntlm.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/protocols/simple/ntlm.c Fri Jun 30 15:03:16 2017 +0300
    @@ -26,8 +26,10 @@
    #include "ntlm.h"
    #include "debug.h"
    -#include "ciphers/descipher.h"
    -#include "ciphers/md4hash.h"
    +#ifdef HAVE_NETTLE
    +#include <nettle/des.h>
    +#include <nettle/md4.h>
    +#endif
    #include <string.h>
    @@ -112,6 +114,7 @@
    return nonce;
    }
    +#ifdef HAVE_NETTLE
    /*
    * Create a 64bit DES key by taking a 56bit key and adding
    * a parity bit after every 7th bit.
    @@ -130,19 +133,15 @@
    }
    /*
    - * helper function for purple cipher.c
    + * helper function for des encryption
    */
    static void
    des_ecb_encrypt(const guint8 *plaintext, guint8 *result, const guint8 *key)
    {
    - PurpleCipher *cipher;
    - gssize encsiz;
    + struct des_ctx ctx;
    - cipher = purple_des_cipher_new();
    - purple_cipher_set_key(cipher, key, 8);
    - encsiz = purple_cipher_encrypt(cipher, plaintext, 8, result, 8);
    - g_warn_if_fail(encsiz == 8);
    - g_object_unref(cipher);
    + des_set_key(&ctx, key);
    + des_encrypt(&ctx, DES_BLOCK_SIZE, result, plaintext);
    }
    /*
    @@ -201,10 +200,12 @@
    buffer[i] = (char)(g_random_int() & 0xff);
    }
    }
    +#endif /* HAVE_NETTLE */
    gchar *
    purple_ntlm_gen_type3(const gchar *username, const gchar *passw, const gchar *hostname, const gchar *domain, const guint8 *nonce, guint32 *flags)
    {
    +#ifdef HAVE_NETTLE
    char lm_pw[14];
    unsigned char lm_hpw[21];
    char sesskey[16];
    @@ -219,7 +220,7 @@
    unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
    unsigned char nt_hpw[21];
    char nt_pw[128];
    - PurpleHash *hash;
    + struct md4_ctx ctx;
    char *tmp;
    int idx;
    gchar *ucs2le;
    @@ -320,10 +321,9 @@
    nt_pw[2 * idx + 1] = 0;
    }
    - hash = purple_md4_hash_new();
    - purple_hash_append(hash, (guint8 *)nt_pw, 2 * lennt);
    - purple_hash_digest(hash, nt_hpw, sizeof(nt_hpw));
    - g_object_unref(hash);
    + md4_init(&ctx);
    + md4_update(&ctx, 2 * lennt, (uint8_t *)nt_pw);
    + md4_digest(&ctx, MD4_DIGEST_SIZE, nt_hpw);
    memset(nt_hpw + 16, 0, 5);
    calc_resp(nt_hpw, nonce, nt_resp);
    @@ -344,4 +344,8 @@
    g_free(tmsg);
    return tmp;
    +#else
    + /* Used without support enabled */
    + g_return_val_if_reached(NULL);
    +#endif /* HAVE_NETTLE */
    }
    --- a/libpurple/protocols/simple/simple.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/protocols/simple/simple.c Fri Jun 30 15:03:16 2017 +0300
    @@ -265,11 +265,8 @@
    gchar noncecount[9];
    gchar *response;
    gchar *ret;
    - gchar *tmp;
    - const char *authdomain;
    const char *authuser;
    - authdomain = purple_account_get_string(sip->account, "authdomain", "");
    authuser = purple_account_get_string(sip->account, "authuser", sip->username);
    if(!authuser || strlen(authuser) < 1) {
    @@ -287,6 +284,13 @@
    g_free(response);
    return ret;
    } else if(auth->type == 2) { /* NTLM */
    +#ifdef HAVE_NETTLE
    + const gchar *authdomain;
    + gchar *tmp;
    +
    + authdomain = purple_account_get_string(sip->account,
    + "authdomain", "");
    +
    if(auth->nc == 3 && auth->nonce) {
    /* TODO: Don't hardcode "purple" as the hostname */
    ret = purple_ntlm_gen_type3(authuser, sip->password, "purple", authdomain, (const guint8 *)auth->nonce, &auth->flags);
    @@ -296,6 +300,10 @@
    }
    tmp = g_strdup_printf("NTLM qop=\"auth\", realm=\"%s\", targetname=\"%s\", gssapi-data=\"\"", auth->realm, auth->target);
    return tmp;
    +#else
    + /* Used without support enabled */
    + g_return_val_if_reached(NULL);
    +#endif /* HAVE_NETTLE */
    }
    sprintf(noncecount, "%08d", auth->nc++);
    @@ -350,6 +358,7 @@
    }
    if(!g_ascii_strncasecmp(hdr, "NTLM", 4)) {
    +#ifdef HAVE_NETTLE
    purple_debug_info("simple", "found NTLM\n");
    auth->type = 2;
    parts = g_strsplit(hdr+5, "\",", 0);
    @@ -382,6 +391,11 @@
    }
    return;
    +#else
    + purple_debug_error("simple", "NTLM auth unsupported without "
    + "libnettle support. Please rebuild with "
    + "libnettle support for this feature.\n");
    +#endif /* HAVE_NETTLE */
    } else if(!g_ascii_strncasecmp(hdr, "DIGEST", 6)) {
    purple_debug_info("simple", "found DIGEST\n");
    --- a/libpurple/protocols/simple/simple.h Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/protocols/simple/simple.h Fri Jun 30 15:03:16 2017 +0300
    @@ -28,7 +28,6 @@
    #include <gio/gio.h>
    #include <time.h>
    -#include "cipher.h"
    #include "circularbuffer.h"
    #include "network.h"
    #include "proxy.h"
    --- a/libpurple/purple.h.in Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/purple.h.in Fri Jun 30 15:03:16 2017 +0300
    @@ -53,7 +53,6 @@
    #include <accountopt.h>
    #include <buddylist.h>
    #include <buddyicon.h>
    -#include <cipher.h>
    #include <circularbuffer.h>
    #include <cmds.h>
    #include <connection.h>
    --- a/libpurple/smiley-list.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/smiley-list.c Fri Jun 30 15:03:16 2017 +0300
    @@ -26,6 +26,8 @@
    #include "smiley-parser.h"
    #include "trie.h"
    +#include <string.h>
    +
    #define PURPLE_SMILEY_LIST_GET_PRIVATE(obj) \
    (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_SMILEY_LIST, \
    PurpleSmileyListPrivate))
    --- a/libpurple/stun.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/stun.c Fri Jun 30 15:03:16 2017 +0300
    @@ -254,7 +254,7 @@
    ifc.ifc_req = buffer_ifr;
    ioctl(source, SIOCGIFCONF, &ifc);
    - it = buffer;
    + it = (guchar *)buffer_ifr;
    it_end = it + ifc.ifc_len;
    while (it < it_end) {
    ifr = (struct ifreq*)(gpointer)it;
    --- a/libpurple/tests/Makefile.am Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/tests/Makefile.am Fri Jun 30 15:03:16 2017 +0300
    @@ -6,28 +6,16 @@
    $(GPLUGIN_LIBS)
    test_programs=\
    - test_des \
    - test_des3 \
    test_image \
    - test_md4 \
    test_smiley \
    test_smiley_list \
    test_trie \
    test_util \
    test_xmlnode
    -test_des_SOURCES=test_des.c
    -test_des_LDADD=$(COMMON_LIBS)
    -
    -test_des3_SOURCES=test_des3.c
    -test_des3_LDADD=$(COMMON_LIBS)
    -
    test_image_SOURCES=test_image.c
    test_image_LDADD=$(COMMON_LIBS)
    -test_md4_SOURCES=test_md4.c
    -test_md4_LDADD=$(COMMON_LIBS)
    -
    test_smiley_SOURCES=test_smiley.c
    test_smiley_LDADD=$(COMMON_LIBS)
    @@ -51,8 +39,7 @@
    $(GLIB_CFLAGS) \
    $(GPLUGIN_CFLAGS) \
    $(PLUGIN_CFLAGS) \
    - $(DBUS_CFLAGS) \
    - $(NSS_CFLAGS)
    + $(DBUS_CFLAGS)
    EXTRA_DIST += \
    data/test-image.png
    --- a/libpurple/tests/test_des.c Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,91 +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 <glib.h>
    -
    -#include <purple.h>
    -
    -#include "ciphers/descipher.h"
    -
    -static void
    -test_des_cipher(const gchar *in, const gchar *key, const gchar *out, size_t len) {
    - PurpleCipher *cipher = NULL;
    - guchar *decrypt = NULL, *encrypt = NULL, *answer = NULL;
    - size_t ret = 0;
    -
    - decrypt = g_memdup(in, len + 1);
    - encrypt = g_memdup(out, len + 1);
    -
    - cipher = purple_des_cipher_new();
    -
    - purple_cipher_set_key(cipher, (const guchar *)key, 8);
    -
    - answer = g_new0(guchar, len + 1);
    - ret = purple_cipher_encrypt(cipher, decrypt, len, answer, len);
    - g_assert(ret == len);
    - g_assert_cmpmem(encrypt, len, answer, len);
    - g_free(answer);
    -
    - answer = g_new0(guchar, len + 1);
    - ret = purple_cipher_decrypt(cipher, encrypt, len, answer, len);
    - g_assert(ret == len);
    - g_assert_cmpmem(decrypt, len, answer, len);
    - g_free(answer);
    -
    - g_free(encrypt);
    - g_free(decrypt);
    -
    - g_object_unref(G_OBJECT(cipher));
    -}
    -
    -static void
    -test_des_cipher_12345678(void) {
    - test_des_cipher(
    - "12345678",
    - "\x3b\x38\x98\x37\x15\x20\xf7\x5e",
    - "\x06\x22\x05\xac\x6a\x0d\x55\xdd",
    - 8
    - );
    -}
    -
    -static void
    -test_des_cipher_abcdefgh(void) {
    - test_des_cipher(
    - "abcdefgh",
    - "\x3b\x38\x98\x37\x15\x20\xf7\x5e",
    - "\x62\xe0\xc6\x8c\x48\xe4\x75\xed",
    - 8
    - );
    -}
    -
    -gint
    -main(gint argc, gchar **argv) {
    - g_test_init(&argc, &argv, NULL);
    -
    - g_test_add_func("/cipher/des/12345678",
    - test_des_cipher_12345678);
    -
    - g_test_add_func("/cipher/des/abcdefgh",
    - test_des_cipher_abcdefgh);
    -
    - return g_test_run();
    -}
    --- a/libpurple/tests/test_des3.c Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,245 +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 <glib.h>
    -
    -#include <purple.h>
    -
    -#include "ciphers/des3cipher.h"
    -
    -/******************************************************************************
    - * DES3 Tests
    - * See http://csrc.nist.gov/groups/ST/toolkit/examples.html
    - * and some NULL things I made up
    - *****************************************************************************/
    -static void
    -test_des3_cipher(const gchar *in, const gchar *key, const gchar *iv,
    - const gchar *out, size_t len, PurpleCipherBatchMode mode)
    -{
    - PurpleCipher *cipher = NULL;
    - guchar *decrypt = NULL, *encrypt = NULL, *answer = NULL;
    - size_t ret = 0;
    -
    - decrypt = g_memdup(in, len + 1);
    - encrypt = g_memdup(out, len + 1);
    -
    - cipher = purple_des3_cipher_new();
    -
    - purple_cipher_set_key(cipher, (const guchar *)key, 24);
    - purple_cipher_set_batch_mode(cipher, mode);
    - purple_cipher_set_iv(cipher, (guchar *)iv, 8);
    -
    - answer = g_new0(guchar, len + 1);
    - ret = purple_cipher_encrypt(cipher, decrypt, len, answer, len);
    - g_assert(ret == len);
    - g_assert_cmpmem(encrypt, len, answer, len);
    - g_free(answer);
    -
    - answer = g_new0(guchar, len + 1);
    - ret = purple_cipher_decrypt(cipher, encrypt, len, answer, len);
    - g_assert(ret == len);
    - g_assert_cmpmem(decrypt, len, answer, len);
    - g_free(answer);
    -
    - g_free(encrypt);
    - g_free(decrypt);
    -
    - g_object_unref(G_OBJECT(cipher));
    -}
    -
    -static void
    -test_des3_cipher_ecb_nist1(void) {
    - test_des3_cipher(
    - "\x6B\xC1\xBE\xE2\x2E\x40\x9F\x96\xE9\x3D\x7E\x11\x73\x93\x17\x2A"
    - "\xAE\x2D\x8A\x57\x1E\x03\xAC\x9C\x9E\xB7\x6F\xAC\x45\xAF\x8E\x51",
    - "\x01\x23\x45\x67\x89\xAB\xCD\xEF"
    - "\x23\x45\x67\x89\xAB\xCD\xEF\x01"
    - "\x45\x67\x89\xAB\xCD\xEF\x01\x23",
    - "00000000", /* ignored */
    - "\x71\x47\x72\xF3\x39\x84\x1D\x34\x26\x7F\xCC\x4B\xD2\x94\x9C\xC3"
    - "\xEE\x11\xC2\x2A\x57\x6A\x30\x38\x76\x18\x3F\x99\xC0\xB6\xDE\x87",
    - 32,
    - PURPLE_CIPHER_BATCH_MODE_ECB
    - );
    -}
    -
    -static void
    -test_des3_cipher_ecb_nist2(void) {
    - test_des3_cipher(
    - "\x6B\xC1\xBE\xE2\x2E\x40\x9F\x96\xE9\x3D\x7E\x11\x73\x93\x17\x2A"
    - "\xAE\x2D\x8A\x57\x1E\x03\xAC\x9C\x9E\xB7\x6F\xAC\x45\xAF\x8E\x51",
    - "\x01\x23\x45\x67\x89\xAB\xCD\xEF"
    - "\x23\x45\x67\x89\xAB\xCD\xEF\x01"
    - "\x01\x23\x45\x67\x89\xAB\xCD\xEF",
    - "00000000", /* ignored */
    - "\x06\xED\xE3\xD8\x28\x84\x09\x0A\xFF\x32\x2C\x19\xF0\x51\x84\x86"
    - "\x73\x05\x76\x97\x2A\x66\x6E\x58\xB6\xC8\x8C\xF1\x07\x34\x0D\x3D",
    - 32,
    - PURPLE_CIPHER_BATCH_MODE_ECB
    - );
    -}
    -
    -static void
    -test_des3_cipher_ecb_null_key(void) {
    - test_des3_cipher(
    - "\x16\xf4\xb3\x77\xfd\x4b\x9e\xca",
    - "\x38\x00\x88\x6a\xef\xcb\x00\xad"
    - "\x5d\xe5\x29\x00\x7d\x98\x64\x4c"
    - "\x86\x00\x7b\xd3\xc7\x00\x7b\x32",
    - "00000000", /* ignored */
    - "\xc0\x60\x30\xa1\xb7\x25\x42\x44",
    - 8,
    - PURPLE_CIPHER_BATCH_MODE_ECB
    - );
    -}
    -
    -static void
    -test_des3_cipher_ecb_null_text(void) {
    - test_des3_cipher(
    - "\x65\x73\x34\xc1\x19\x00\x79\x65",
    - "\x32\x64\xda\x10\x13\x6a\xfe\x1e"
    - "\x37\x54\xd1\x2c\x41\x04\x10\x40"
    - "\xaf\x1c\x75\x2b\x51\x3a\x03\xf5",
    - "00000000", /* ignored */
    - "\xe5\x80\xf6\x12\xf8\x4e\xd9\x6c",
    - 8,
    - PURPLE_CIPHER_BATCH_MODE_ECB
    - );
    -}
    -
    -static void
    -test_des3_cipher_ecb_null_key_and_text(void) {
    - test_des3_cipher(
    - "\xdf\x7f\x00\x92\xe7\xc1\x49\xd2",
    - "\x0e\x41\x00\xc4\x8b\xf0\x6e\xa1"
    - "\x66\x49\x42\x63\x22\x00\xf0\x99"
    - "\x6b\x22\xc1\x37\x9c\x00\xe4\x8f",
    - "00000000", /* ignored */
    - "\x73\xd8\x1f\x1f\x50\x01\xe4\x79",
    - 8,
    - PURPLE_CIPHER_BATCH_MODE_ECB
    - );
    -}
    -
    -static void
    -test_des3_cipher_cbc_nist1(void) {
    - test_des3_cipher(
    - "\x6B\xC1\xBE\xE2\x2E\x40\x9F\x96\xE9\x3D\x7E\x11\x73\x93\x17\x2A"
    - "\xAE\x2D\x8A\x57\x1E\x03\xAC\x9C\x9E\xB7\x6F\xAC\x45\xAF\x8E\x51",
    - "\x01\x23\x45\x67\x89\xAB\xCD\xEF"
    - "\x23\x45\x67\x89\xAB\xCD\xEF\x01"
    - "\x45\x67\x89\xAB\xCD\xEF\x01\x23",
    - "\xF6\x9F\x24\x45\xDF\x4F\x9B\x17",
    - "\x20\x79\xC3\xD5\x3A\xA7\x63\xE1\x93\xB7\x9E\x25\x69\xAB\x52\x62"
    - "\x51\x65\x70\x48\x1F\x25\xB5\x0F\x73\xC0\xBD\xA8\x5C\x8E\x0D\xA7",
    - 32,
    - PURPLE_CIPHER_BATCH_MODE_CBC
    - );
    -}
    -
    -static void
    -test_des3_cipher_cbc_nist2(void) {
    - test_des3_cipher(
    - "\x6B\xC1\xBE\xE2\x2E\x40\x9F\x96\xE9\x3D\x7E\x11\x73\x93\x17\x2A"
    - "\xAE\x2D\x8A\x57\x1E\x03\xAC\x9C\x9E\xB7\x6F\xAC\x45\xAF\x8E\x51",
    - "\x01\x23\x45\x67\x89\xAB\xCD\xEF"
    - "\x23\x45\x67\x89\xAB\xCD\xEF\x01"
    - "\x01\x23\x45\x67\x89\xAB\xCD\xEF",
    - "\xF6\x9F\x24\x45\xDF\x4F\x9B\x17",
    - "\x74\x01\xCE\x1E\xAB\x6D\x00\x3C\xAF\xF8\x4B\xF4\x7B\x36\xCC\x21"
    - "\x54\xF0\x23\x8F\x9F\xFE\xCD\x8F\x6A\xCF\x11\x83\x92\xB4\x55\x81",
    - 32,
    - PURPLE_CIPHER_BATCH_MODE_CBC
    - );
    -}
    -
    -static void
    -test_des3_cipher_cbc_null_key(void) {
    - test_des3_cipher(
    - "\x16\xf4\xb3\x77\xfd\x4b\x9e\xca",
    - "\x38\x00\x88\x6a\xef\xcb\x00\xad"
    - "\x5d\xe5\x29\x00\x7d\x98\x64\x4c"
    - "\x86\x00\x7b\xd3\xc7\x00\x7b\x32",
    - "\x31\x32\x33\x34\x35\x36\x37\x38",
    - "\x52\xe7\xde\x96\x39\x87\x87\xdb",
    - 8,
    - PURPLE_CIPHER_BATCH_MODE_CBC
    - );
    -}
    -
    -static void
    -test_des3_cipher_cbc_null_text(void) {
    - test_des3_cipher(
    - "\x65\x73\x34\xc1\x19\x00\x79\x65",
    - "\x32\x64\xda\x10\x13\x6a\xfe\x1e"
    - "\x37\x54\xd1\x2c\x41\x04\x10\x40"
    - "\xaf\x1c\x75\x2b\x51\x3a\x03\xf5",
    - "\x7C\xAF\x0D\x57\x1E\x57\x10\xDA",
    - "\x40\x12\x0e\x00\x85\xff\x6c\xc2",
    - 8,
    - PURPLE_CIPHER_BATCH_MODE_CBC
    - );
    -}
    -
    -static void
    -test_des3_cipher_cbc_null_key_and_text(void) {
    - test_des3_cipher(
    - "\xdf\x7f\x00\x92\xe7\xc1\x49\xd2",
    - "\x0e\x41\x00\xc4\x8b\xf0\x6e\xa1"
    - "\x66\x49\x42\x63\x22\x00\xf0\x99"
    - "\x6b\x22\xc1\x37\x9c\x00\xe4\x8f",
    - "\x01\x19\x0D\x2c\x40\x67\x89\x67",
    - "\xa7\xc1\x10\xbe\x9b\xd5\x8a\x67",
    - 8,
    - PURPLE_CIPHER_BATCH_MODE_CBC
    - );
    -}
    -
    -
    -gint
    -main(gint argc, gchar **argv) {
    - g_test_init(&argc, &argv, NULL);
    -
    - g_test_add_func("/cipher/des3/ecb nist1",
    - test_des3_cipher_ecb_nist1);
    - g_test_add_func("/cipher/des3/ecb nist2",
    - test_des3_cipher_ecb_nist2);
    - g_test_add_func("/cipher/des3/ecb null key",
    - test_des3_cipher_ecb_null_key);
    - g_test_add_func("/cipher/des3/ecb null text",
    - test_des3_cipher_ecb_null_text);
    - g_test_add_func("/cipher/des3/ebc null key and text",
    - test_des3_cipher_ecb_null_key_and_text);
    -
    - g_test_add_func("/cipher/des3/cbc nist1",
    - test_des3_cipher_cbc_nist1);
    - g_test_add_func("/cipher/des3/cbc nist2",
    - test_des3_cipher_cbc_nist2);
    - g_test_add_func("/cipher/des3/cbc null key",
    - test_des3_cipher_cbc_null_key);
    - g_test_add_func("/cipher/des3/cbc null text",
    - test_des3_cipher_cbc_null_text);
    - g_test_add_func("/cipher/des3/cbc null key and text",
    - test_des3_cipher_cbc_null_key_and_text);
    -
    - return g_test_run();
    -}
    --- a/libpurple/tests/test_image.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/tests/test_image.c Fri Jun 30 15:03:16 2017 +0300
    @@ -21,6 +21,7 @@
    */
    #include <glib.h>
    +#include <string.h>
    #include <purple.h>
    --- a/libpurple/tests/test_md4.c Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,107 +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 <glib.h>
    -
    -#include <purple.h>
    -
    -#include "ciphers/md4hash.h"
    -
    -static void
    -test_md4hash(gchar *data, gchar *digest) {
    - PurpleHash *hash = NULL;
    - gchar cdigest[33];
    - gboolean ret = FALSE;
    -
    - hash = purple_md4_hash_new();
    -
    - purple_hash_append(hash, (guchar *)data, strlen(data));
    -
    - ret = purple_hash_digest_to_str(hash, cdigest, sizeof(cdigest));
    -
    - g_assert(ret);
    - g_assert_cmpstr(digest, ==, cdigest);
    -}
    -
    -static void
    -test_md4hash_empty_string(void) {
    - test_md4hash("",
    - "31d6cfe0d16ae931b73c59d7e0c089c0");
    -}
    -
    -static void
    -test_md4hash_a(void) {
    - test_md4hash("a",
    - "bde52cb31de33e46245e05fbdbd6fb24");
    -}
    -
    -static void
    -test_md4hash_abc(void) {
    - test_md4hash("abc",
    - "a448017aaf21d8525fc10ae87aa6729d");
    -}
    -
    -static void
    -test_md4hash_message_digest(void) {
    - test_md4hash("message digest",
    - "d9130a8164549fe818874806e1c7014b");
    -}
    -
    -static void
    -test_md4hash_a_to_z(void) {
    - test_md4hash("abcdefghijklmnopqrstuvwxyz",
    - "d79e1c308aa5bbcdeea8ed63df412da9");
    -}
    -
    -static void
    -test_md4hash_A_to_Z_a_to_z_0_to_9(void) {
    - test_md4hash("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
    - "043f8582f241db351ce627e153e7f0e4");
    -}
    -
    -static void
    -test_md4hash_1_to_0_eight_times(void) {
    - test_md4hash("12345678901234567890123456789012345678901234567890123456789012345678901234567890",
    - "e33b4ddc9c38f2199c3e7b164fcc0536");
    -}
    -
    -gint
    -main(gint argc, gchar **argv) {
    - g_test_init(&argc, &argv, NULL);
    -
    - g_test_add_func("/hash/md4/empty-string",
    - test_md4hash_empty_string);
    - g_test_add_func("/hash/md4/a",
    - test_md4hash_a);
    - g_test_add_func("/hash/md4/abc",
    - test_md4hash_abc);
    - g_test_add_func("/hash/md4/message digest",
    - test_md4hash_message_digest);
    - g_test_add_func("/hash/md4/a to z",
    - test_md4hash_a_to_z);
    - g_test_add_func("/hash/md4/A to Z, a to z, 0 to 9" ,
    - test_md4hash_A_to_Z_a_to_z_0_to_9);
    - g_test_add_func("/hash/md4/1 to 0 eight times",
    - test_md4hash_1_to_0_eight_times);
    -
    - return g_test_run();
    -}
    --- a/libpurple/tests/test_smiley.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/tests/test_smiley.c Fri Jun 30 15:03:16 2017 +0300
    @@ -21,6 +21,7 @@
    */
    #include <glib.h>
    +#include <string.h>
    #include <purple.h>
    --- a/libpurple/xfer.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/libpurple/xfer.c Fri Jun 30 15:03:16 2017 +0300
    @@ -1920,12 +1920,14 @@
    gsize size, const gchar *mimetype)
    {
    PurpleXferPrivate *priv = PURPLE_XFER_GET_PRIVATE(xfer);
    + gpointer old_thumbnail_data;
    + gchar *old_mimetype;
    g_return_if_fail(priv != NULL);
    /* Hold onto these in case they are equal to passed-in pointers */
    - gpointer *old_thumbnail_data = priv->thumbnail_data;
    - const gchar *old_mimetype = priv->thumbnail_mimetype;
    + old_thumbnail_data = priv->thumbnail_data;
    + old_mimetype = priv->thumbnail_mimetype;
    if (thumbnail && size > 0) {
    priv->thumbnail_data = g_memdup(thumbnail, size);
    --- a/pidgin/Makefile.am Thu Jun 15 10:48:26 2017 +0300
    +++ b/pidgin/Makefile.am Fri Jun 30 15:03:16 2017 +0300
    @@ -4,6 +4,7 @@
    getopt1.c \
    gtk3compat.h \
    gtkdebug.html \
    + pidgin.gresource.xml \
    Makefile.mingw \
    data/pidgin.appdata.xml.in \
    data/pidgin.desktop.in \
    @@ -55,7 +56,6 @@
    gtkdialogs.c \
    gtkdnd-hints.c \
    gtkdocklet.c \
    - gtkeventloop.c \
    gtkicon-theme.c \
    gtkicon-theme-loader.c \
    gtkidle.c \
    @@ -72,7 +72,6 @@
    gtkroomlist.c \
    gtksavedstatuses.c \
    gtkscrollbook.c \
    - gtksession.c \
    gtksmiley-manager.c \
    gtksmiley-theme.c \
    gtksound.c \
    @@ -85,6 +84,7 @@
    gtkxfer.c \
    libpidgin.c \
    minidialog.c \
    + pidgin.gresource.c \
    pidgintooltip.c
    libpidgin_la_headers = \
    @@ -103,7 +103,6 @@
    gtkdialogs.h \
    gtkdnd-hints.h \
    gtkdocklet.h \
    - gtkeventloop.h \
    gtkicon-theme.h \
    gtkicon-theme-loader.h \
    gtkidle.h \
    @@ -121,7 +120,6 @@
    gtkroomlist.h \
    gtksavedstatuses.h \
    gtkscrollbook.h \
    - gtksession.h \
    gtksmiley-manager.h \
    gtksmiley-theme.h \
    gtksound.h \
    @@ -172,18 +170,22 @@
    libpidgininclude_HEADERS = \
    $(libpidgin_la_headers)
    -libpidgin_la_builtheaders = gtkdebug.html.h
    +libpidgin_la_builtheaders = pidgin.gresource.h
    +libpidgin_la_builtsources = pidgin.gresource.c
    -BUILT_SOURCES = $(libpidgin_la_builtheaders)
    +BUILT_SOURCES = $(libpidgin_la_builtheaders) $(libpidgin_la_builtsources)
    -CLEANFILES = gtkdebug.html.h
    +CLEANFILES = pidgin.gresource.h pidgin.gresource.c
    -%.html.h: %.html
    - $(AM_V_GEN)echo "static const char $*_html[] = {" > $@
    - $(AM_V_at)$(sedpath) -e 's/^[ ]\+//g' -e 's/[ ]\+/ /g' $< | $(xxdpath) -i | sed -e 's/\(0x[0-9a-f][0-9a-f]\)$$/\1, 0x00/' >> $@
    - $(AM_V_at)echo "};" >> $@
    +%.gresource.h: %.gresource.xml
    + $(AM_V_GEN)$(GLIB_COMPILE_RESOURCES) --generate-header --target $@ --c-name $* --sourcedir $(srcdir) $<
    -gtkdebug.c: gtkdebug.html.h
    +%.gresource.c: %.gresource.xml
    + $(AM_V_GEN)$(GLIB_COMPILE_RESOURCES) --generate-source --target $@ --c-name $* --sourcedir $(srcdir) $<
    +
    +pidgin.gresource.c: gtkdebug.html
    +pidgin.gresource.h: gtkdebug.html
    +gtkdebug.c: pidgin.gresource.h
    libpidgin_la_DEPENDENCIES = @LIBOBJS@ $(LIBPIDGIN_WIN32RES)
    libpidgin_la_LDFLAGS = -export-dynamic -no-undefined \
    @@ -199,7 +201,6 @@
    $(GSTVIDEO_LIBS) \
    $(GSTINTERFACES_LIBS) \
    $(XSS_LIBS) \
    - $(SM_LIBS) \
    $(INTLLIBS) \
    $(LIBXML_LIBS) \
    $(WEBKIT_LIBS) \
    --- a/pidgin/Makefile.mingw Thu Jun 15 10:48:26 2017 +0300
    +++ b/pidgin/Makefile.mingw Fri Jun 30 15:03:16 2017 +0300
    @@ -71,7 +71,6 @@
    gtkdialogs.c \
    gtkdnd-hints.c \
    gtkdocklet.c \
    - gtkeventloop.c \
    gtkicon-theme-loader.c \
    gtkicon-theme.c \
    gtkidle.c \
    --- a/pidgin/gtkdebug.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/pidgin/gtkdebug.c Fri Jun 30 15:03:16 2017 +0300
    @@ -40,7 +40,7 @@
    #include "gtk3compat.h"
    -#include "gtkdebug.html.h"
    +#include "pidgin.gresource.h"
    typedef struct
    {
    @@ -409,7 +409,10 @@
    static DebugWindow *
    debug_window_new(void)
    {
    + GError *error;
    DebugWindow *win;
    + GResource *resource;
    + GBytes *resource_bytes;
    GtkWidget *vbox;
    GtkWidget *toolbar;
    GtkWidget *frame;
    @@ -586,7 +589,25 @@
    frame = pidgin_create_webview(FALSE, &win->text, NULL);
    pidgin_webview_set_format_functions(PIDGIN_WEBVIEW(win->text),
    PIDGIN_WEBVIEW_ALL ^ PIDGIN_WEBVIEW_SMILEY ^ PIDGIN_WEBVIEW_IMAGE);
    - pidgin_webview_load_html_string(PIDGIN_WEBVIEW(win->text), gtkdebug_html);
    + resource = pidgin_get_resource();
    + error = NULL;
    + resource_bytes = g_resource_lookup_data(resource,
    + "/im/pidgin/Pidgin/gtkdebug.html",
    + G_RESOURCE_LOOKUP_FLAGS_NONE,
    + &error);
    + if (G_UNLIKELY(resource_bytes == NULL || error != NULL)) {
    + gchar *msg = g_strdup_printf("Unable to load debug window HTML: %s\n",
    + error ? error->message : "Unknown error");
    + g_clear_error(&error);
    + pidgin_webview_load_html_string(PIDGIN_WEBVIEW(win->text), msg);
    + g_free(msg);
    + } else {
    + gconstpointer gtkdebug_html;
    + gtkdebug_html = g_bytes_get_data(resource_bytes, NULL);
    + pidgin_webview_load_html_string(PIDGIN_WEBVIEW(win->text),
    + gtkdebug_html);
    + }
    + g_bytes_unref(resource_bytes);
    gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
    gtk_widget_show(frame);
    --- a/pidgin/gtkdialogs.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/pidgin/gtkdialogs.c Fri Jun 30 15:03:16 2017 +0300
    @@ -696,12 +696,6 @@
    #endif
    #ifndef _WIN32
    -#ifdef USE_SM
    - g_string_append(str, "<dt>X Session Management:</dt><dd>Enabled</dd>");
    -#else
    - g_string_append(str, "<dt>X Session Management:</dt><dd>Disabled</dd>");
    -#endif
    -
    #ifdef USE_SCREENSAVER
    g_string_append(str, "<dt>XScreenSaver:</dt><dd>Enabled</dd>");
    #else
    --- a/pidgin/gtkeventloop.c Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,124 +0,0 @@
    -/* pidgin
    - *
    - * Pidgin 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 <glib.h>
    -#include "gtkeventloop.h"
    -#include "eventloop.h"
    -#include "internal.h"
    -
    -#define PIDGIN_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR)
    -#define PIDGIN_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL)
    -
    -typedef struct _PidginIOClosure {
    - PurpleInputFunction function;
    - guint result;
    - gpointer data;
    -
    -} PidginIOClosure;
    -
    -static gboolean pidgin_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data)
    -{
    - PidginIOClosure *closure = data;
    - PurpleInputCondition purple_cond = 0;
    -
    - if (condition & PIDGIN_READ_COND)
    - purple_cond |= PURPLE_INPUT_READ;
    - if (condition & PIDGIN_WRITE_COND)
    - purple_cond |= PURPLE_INPUT_WRITE;
    -
    -#if 0
    - purple_debug_misc("gtk_eventloop",
    - "CLOSURE: callback for %d, fd is %d\n",
    - closure->result, g_io_channel_unix_get_fd(source));
    -#endif
    -
    -#ifdef _WIN32
    - if(! purple_cond) {
    -#if 0
    - purple_debug_misc("gtk_eventloop",
    - "CLOSURE received GIOCondition of 0x%x, which does not"
    - " match 0x%x (READ) or 0x%x (WRITE)\n",
    - condition, PIDGIN_READ_COND, PIDGIN_WRITE_COND);
    -#endif /* DEBUG */
    -
    - return TRUE;
    - }
    -#endif /* _WIN32 */
    -
    - closure->function(closure->data, g_io_channel_unix_get_fd(source),
    - purple_cond);
    -
    - return TRUE;
    -}
    -
    -static guint pidgin_input_add(gint fd, PurpleInputCondition condition, PurpleInputFunction function,
    - gpointer data)
    -{
    - PidginIOClosure *closure = g_new0(PidginIOClosure, 1);
    - GIOChannel *channel;
    - GIOCondition cond = 0;
    -
    - closure->function = function;
    - closure->data = data;
    -
    - if (condition & PURPLE_INPUT_READ)
    - cond |= PIDGIN_READ_COND;
    - if (condition & PURPLE_INPUT_WRITE)
    - cond |= PIDGIN_WRITE_COND;
    -
    -#ifdef _WIN32
    - channel = g_io_channel_win32_new_socket(fd);
    -#else
    - channel = g_io_channel_unix_new(fd);
    -#endif
    -
    - closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond,
    - pidgin_io_invoke, closure, g_free);
    -
    -#if 0
    - purple_debug_misc("gtk_eventloop",
    - "CLOSURE: adding input watcher %d for fd %d\n",
    - closure->result, fd);
    -#endif
    -
    - g_io_channel_unref(channel);
    - return closure->result;
    -}
    -
    -static PurpleEventLoopUiOps eventloop_ops =
    -{
    - g_timeout_add,
    - g_source_remove,
    - pidgin_input_add,
    - g_source_remove,
    - NULL, /* input_get_error */
    - g_timeout_add_seconds,
    - NULL,
    - NULL,
    - NULL,
    - NULL
    -};
    -
    -PurpleEventLoopUiOps *
    -pidgin_eventloop_get_ui_ops(void)
    -{
    - return &eventloop_ops;
    -}
    --- a/pidgin/gtkeventloop.h Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,46 +0,0 @@
    -/* pidgin
    - *
    - * Pidgin 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 _PIDGINEVENTLOOP_H_
    -#define _PIDGINEVENTLOOP_H_
    -/**
    - * SECTION:gtkeventloop
    - * @section_id: pidgin-gtkeventloop
    - * @short_description: <filename>gtkeventloop.h</filename>
    - * @title: Event Loop Implementation
    - */
    -
    -#include "eventloop.h"
    -
    -G_BEGIN_DECLS
    -
    -/**
    - * pidgin_eventloop_get_ui_ops:
    - *
    - * Returns the GTK+ event loop UI operations structure.
    - *
    - * Returns: The GTK+ event loop UI operations structure.
    - */
    -PurpleEventLoopUiOps *pidgin_eventloop_get_ui_ops(void);
    -
    -G_END_DECLS
    -
    -#endif /* _PIDGINEVENTLOOP_H_ */
    --- a/pidgin/gtksession.c Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,414 +0,0 @@
    -/* Pidgin 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 "core.h"
    -#include "debug.h"
    -#include "eventloop.h"
    -#include "gtksession.h"
    -
    -#ifdef USE_SM
    -
    -#include <X11/ICE/ICElib.h>
    -#include <X11/SM/SMlib.h>
    -#include <gdk/gdkx.h>
    -#include <unistd.h>
    -#include <fcntl.h>
    -#include <gdk/gdk.h>
    -#include <gtk/gtk.h>
    -
    -#include "gtk3compat.h"
    -
    -#define ERROR_LENGTH 512
    -
    -static IceIOErrorHandler ice_installed_io_error_handler;
    -static SmcConn session = NULL;
    -static gchar *myself = NULL;
    -static gboolean had_first_save = FALSE;
    -static gboolean session_managed = FALSE;
    -
    -/* ICE belt'n'braces stuff */
    -
    -struct ice_connection_info {
    - IceConn connection;
    - guint input_id;
    -};
    -
    -static void ice_process_messages(gpointer data, gint fd,
    - PurpleInputCondition condition) {
    - struct ice_connection_info *conninfo = (struct ice_connection_info*) data;
    - IceProcessMessagesStatus status;
    -
    - /* please don't block... please! */
    - status = IceProcessMessages(conninfo->connection, NULL, NULL);
    -
    - if (status == IceProcessMessagesIOError) {
    - purple_debug(PURPLE_DEBUG_INFO, "Session Management",
    - "ICE IO error, closing connection... ");
    -
    - /* IO error, please disconnect */
    - IceSetShutdownNegotiation(conninfo->connection, False);
    - IceCloseConnection(conninfo->connection);
    -
    - if (purple_debug_is_verbose()) {
    - purple_debug_misc("Session Management",
    - "Connection closed.");
    - }
    -
    - /* cancel the handler */
    - purple_input_remove(conninfo->input_id);
    - }
    -}
    -
    -static void ice_connection_watch(IceConn connection, IcePointer client_data,
    - Bool opening, IcePointer *watch_data) {
    - struct ice_connection_info *conninfo = NULL;
    -
    - if (opening) {
    - purple_debug_misc("Session Management",
    - "Handling new ICE connection...");
    -
    - /* ensure ICE connection is not passed to child processes */
    - if (fcntl(IceConnectionNumber(connection), F_SETFD, FD_CLOEXEC) != 0)
    - purple_debug_warning("gtksession", "couldn't set FD_CLOEXEC\n");
    -
    - conninfo = g_new(struct ice_connection_info, 1);
    - conninfo->connection = connection;
    -
    - /* watch the connection */
    - conninfo->input_id = purple_input_add(IceConnectionNumber(connection), PURPLE_INPUT_READ,
    - ice_process_messages, conninfo);
    - *watch_data = conninfo;
    - } else {
    - purple_debug(PURPLE_DEBUG_INFO, "Session Management",
    - "Handling closed ICE connection... \n");
    -
    - /* get the input ID back and stop watching it */
    - conninfo = (struct ice_connection_info*) *watch_data;
    - purple_input_remove(conninfo->input_id);
    - g_free(conninfo);
    - }
    -
    - if (purple_debug_is_verbose()) {
    - purple_debug_misc("Session Management",
    - "ICE connection handled.");
    - }
    -}
    -
    -/* We call any handler installed before (or after) ice_init but
    - * avoid calling the default libICE handler which does an exit().
    - *
    - * This means we do nothing by default, which is probably correct,
    - * the connection will get closed by libICE
    - */
    -
    -static void ice_io_error_handler(IceConn connection) {
    - purple_debug(PURPLE_DEBUG_INFO, "Session Management",
    - "Handling ICE IO error... ");
    -
    - if (ice_installed_io_error_handler)
    - (*ice_installed_io_error_handler)(connection);
    -
    - if (purple_debug_is_verbose()) {
    - purple_debug_misc("Session Management",
    - "ICE IO error handled.");
    - }
    -}
    -
    -static void ice_init(void) {
    - IceIOErrorHandler default_handler;
    -
    - ice_installed_io_error_handler = IceSetIOErrorHandler(NULL);
    - default_handler = IceSetIOErrorHandler(ice_io_error_handler);
    -
    - if (ice_installed_io_error_handler == default_handler)
    - ice_installed_io_error_handler = NULL;
    -
    - IceAddConnectionWatch(ice_connection_watch, NULL);
    -
    - if (purple_debug_is_verbose()) {
    - purple_debug_misc("Session Management", "ICE initialized.");
    - }
    -}
    -
    -/* my magic utility function */
    -
    -static gchar **session_make_command(gchar *client_id, gchar *config_dir) {
    - gint i = 4;
    - gint j = 0;
    - gchar **ret;
    -
    - if (client_id) i += 2;
    - if (config_dir) i += 2; /* we will specify purple's user dir */
    -
    - ret = g_new(gchar *, i);
    - ret[j++] = g_strdup(myself);
    -
    - if (client_id) {
    - ret[j++] = g_strdup("--session");
    - ret[j++] = g_strdup(client_id);
    - }
    -
    - if (config_dir) {
    - ret[j++] = g_strdup("--config");
    - ret[j++] = g_strdup(config_dir);
    - }
    -
    - ret[j++] = g_strdup("--display");
    - ret[j++] = g_strdup((gchar *)gdk_display_get_name(gdk_display_get_default()));
    -
    - ret[j] = NULL;
    -
    - return ret;
    -}
    -
    -/* SM callback handlers */
    -
    -static void session_save_yourself(SmcConn conn, SmPointer data, int save_type,
    - Bool shutdown, int interact_style, Bool fast) {
    - if (had_first_save == FALSE && save_type == SmSaveLocal &&
    - interact_style == SmInteractStyleNone && !shutdown &&
    - !fast) {
    - /* this is just a dry run, spit it back */
    - purple_debug(PURPLE_DEBUG_INFO, "Session Management",
    - "Received first save_yourself\n");
    - SmcSaveYourselfDone(conn, True);
    - had_first_save = TRUE;
    - return;
    - }
    -
    - /* tum ti tum... don't add anything else here without *
    - * reading SMlib.PS from an X.org ftp server near you */
    -
    - purple_debug(PURPLE_DEBUG_INFO, "Session Management",
    - "Received save_yourself\n");
    -
    - if (save_type == SmSaveGlobal || save_type == SmSaveBoth) {
    - /* may as well do something ... */
    - /* or not -- save_prefs(); */
    - }
    -
    - SmcSaveYourselfDone(conn, True);
    -}
    -
    -static void session_die(SmcConn conn, SmPointer data) {
    - purple_debug(PURPLE_DEBUG_INFO, "Session Management",
    - "Received die\n");
    - purple_core_quit();
    -}
    -
    -static void session_save_complete(SmcConn conn, SmPointer data) {
    - purple_debug(PURPLE_DEBUG_INFO, "Session Management",
    - "Received save_complete\n");
    -}
    -
    -static void session_shutdown_cancelled(SmcConn conn, SmPointer data) {
    - purple_debug(PURPLE_DEBUG_INFO, "Session Management",
    - "Received shutdown_cancelled\n");
    -}
    -
    -/* utility functions stolen from Gnome-client */
    -
    -static void session_set_value(SmcConn conn, gchar *name, char *type,
    - int num_vals, SmPropValue *vals) {
    - SmProp *proplist[1];
    - SmProp prop;
    -
    - g_return_if_fail(conn);
    -
    - prop.name = name;
    - prop.type = type;
    - prop.num_vals = num_vals;
    - prop.vals = vals;
    -
    - proplist[0] = &prop;
    - SmcSetProperties(conn, 1, proplist);
    -}
    -
    -static void session_set_string(SmcConn conn, gchar *name, gchar *value) {
    - SmPropValue val;
    -
    - g_return_if_fail(name);
    -
    - val.length = strlen (value)+1;
    - val.value = value;
    -
    - session_set_value(conn, name, SmARRAY8, 1, &val);
    -}
    -
    -static void session_set_gchar(SmcConn conn, gchar *name, gchar value) {
    - SmPropValue val;
    -
    - g_return_if_fail(name);
    -
    - val.length = 1;
    - val.value = &value;
    -
    - session_set_value(conn, name, SmCARD8, 1, &val);
    -}
    -
    -static void session_set_array(SmcConn conn, gchar *name, gchar *array[]) {
    - gint argc;
    - gchar **ptr;
    - gint i;
    -
    - SmPropValue *vals;
    -
    - g_return_if_fail (name);
    -
    - /* We count the number of elements in our array. */
    - for (ptr = array, argc = 0; *ptr ; ptr++, argc++) /* LOOP */;
    -
    - /* Now initialize the 'vals' array. */
    - vals = g_new (SmPropValue, argc);
    - for (ptr = array, i = 0 ; i < argc ; ptr++, i++) {
    - vals[i].length = strlen (*ptr);
    - vals[i].value = *ptr;
    - }
    -
    - session_set_value(conn, name, SmLISTofARRAY8, argc, vals);
    -
    - g_free (vals);
    -}
    -
    -#endif /* USE_SM */
    -
    -/* setup functions */
    -
    -void
    -pidgin_session_init(gchar *argv0, gchar *previous_id, gchar *config_dir)
    -{
    -#ifdef USE_SM
    - SmcCallbacks callbacks;
    - gchar *client_id = NULL;
    - gchar error[ERROR_LENGTH] = "";
    - gchar *tmp = NULL;
    - gchar **cmd = NULL;
    -
    - if (session != NULL) {
    - /* session is already established, what the hell is going on? */
    - purple_debug(PURPLE_DEBUG_WARNING, "Session Management",
    - "Duplicated call to pidgin_session_init!\n");
    - return;
    - }
    -
    - if (g_getenv("SESSION_MANAGER") == NULL) {
    - purple_debug(PURPLE_DEBUG_ERROR, "Session Management",
    - "No SESSION_MANAGER found, aborting.\n");
    - return;
    - }
    -
    - ice_init();
    -
    - callbacks.save_yourself.callback = session_save_yourself;
    - callbacks.die.callback = session_die;
    - callbacks.save_complete.callback = session_save_complete;
    - callbacks.shutdown_cancelled.callback = session_shutdown_cancelled;
    -
    - callbacks.save_yourself.client_data = NULL;
    - callbacks.die.client_data = NULL;
    - callbacks.save_complete.client_data = NULL;
    - callbacks.shutdown_cancelled.client_data = NULL;
    -
    - if (previous_id) {
    - purple_debug(PURPLE_DEBUG_INFO, "Session Management",
    - "Connecting with previous ID %s\n", previous_id);
    - } else {
    - purple_debug(PURPLE_DEBUG_INFO, "Session Management",
    - "Connecting with no previous ID\n");
    - }
    -
    - session = SmcOpenConnection(NULL, "session", SmProtoMajor, SmProtoMinor, SmcSaveYourselfProcMask |
    - SmcDieProcMask | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
    - &callbacks, previous_id, &client_id, ERROR_LENGTH, error);
    -
    - if (session == NULL) {
    - if (error[0] != '\0') {
    - purple_debug(PURPLE_DEBUG_ERROR, "Session Management",
    - "Connection failed with error: %s\n", error);
    - } else {
    - purple_debug(PURPLE_DEBUG_ERROR, "Session Management",
    - "Connetion failed with unknown error.\n");
    - }
    - return;
    - }
    -
    - tmp = SmcVendor(session);
    - purple_debug(PURPLE_DEBUG_INFO, "Session Management",
    - "Connected to manager (%s) with client ID %s\n",
    - tmp, client_id);
    - free(tmp);
    -
    - session_managed = TRUE;
    - gdk_x11_set_sm_client_id(client_id);
    -
    - tmp = g_get_current_dir();
    - session_set_string(session, SmCurrentDirectory, tmp);
    - g_free(tmp);
    -
    - tmp = g_strdup_printf("%d", (int) getpid());
    - session_set_string(session, SmProcessID, tmp);
    - g_free(tmp);
    -
    - tmp = g_strdup(g_get_user_name());
    - session_set_string(session, SmUserID, tmp);
    - g_free(tmp);
    -
    - session_set_gchar(session, SmRestartStyleHint, (gchar) SmRestartIfRunning);
    - session_set_string(session, SmProgram, (gchar *) g_get_prgname());
    -
    - myself = g_strdup(argv0);
    - purple_debug(PURPLE_DEBUG_MISC, "Session Management",
    - "Using %s as command\n", myself);
    -
    - cmd = session_make_command(NULL, config_dir);
    - session_set_array(session, SmCloneCommand, cmd);
    - g_strfreev(cmd);
    -
    - /* this is currently useless, but gnome-session warns 'the following applications will not
    - save their current status' bla bla if we don't have it and the user checks 'Save Session'
    - when they log out */
    - cmd = g_new(gchar *, 2);
    - cmd[0] = g_strdup("/bin/true");
    - cmd[1] = NULL;
    - session_set_array(session, SmDiscardCommand, cmd);
    - g_strfreev(cmd);
    -
    - cmd = session_make_command(client_id, config_dir);
    - session_set_array(session, SmRestartCommand, cmd);
    - g_strfreev(cmd);
    -
    - g_free(client_id);
    -#endif /* USE_SM */
    -}
    -
    -void
    -pidgin_session_end()
    -{
    -#ifdef USE_SM
    - if (session == NULL) /* no session to close */
    - return;
    -
    - SmcCloseConnection(session, 0, NULL);
    -
    - purple_debug(PURPLE_DEBUG_INFO, "Session Management",
    - "Connection closed.\n");
    -#endif /* USE_SM */
    -}
    --- a/pidgin/gtksession.h Thu Jun 15 10:48:26 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,60 +0,0 @@
    -/* pidgin
    - *
    - * Pidgin 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 _PIDGINSESSION_H_
    -#define _PIDGINSESSION_H_
    -/**
    - * SECTION:gtksession
    - * @section_id: pidgin-gtksession
    - * @short_description: <filename>gtksession.h</filename>
    - * @title: X Windows Session Management
    - */
    -
    -G_BEGIN_DECLS
    -
    -/**************************************************************************/
    -/* X Windows session subsystem */
    -/**************************************************************************/
    -
    -/**
    - * pidgin_session_init:
    - * @argv0: The first argument passed into the program. This
    - * will be the name of the executable, e.g. 'purple'
    - * @previous_id: An optional session ID to use. This can be NULL.
    - * @config_dir: The path to the configuration directory used by
    - * this instance of this program, e.g. '/home/user/.purple'
    - *
    - * Register this instance of Pidgin with the user's current session
    - * manager.
    - */
    -void pidgin_session_init(gchar *argv0, gchar *previous_id, gchar *config_dir);
    -
    -/**
    - * pidgin_session_end:
    - *
    - * Unregister this instance of Pidgin with the user's current session
    - * manager.
    - */
    -void pidgin_session_end(void);
    -
    -G_END_DECLS
    -
    -#endif /* _PIDGINSESSION_H_ */
    --- a/pidgin/gtkwebview.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/pidgin/gtkwebview.c Fri Jun 30 15:03:16 2017 +0300
    @@ -24,7 +24,6 @@
    #include "debug.h"
    #include "glibcompat.h"
    #include "image-store.h"
    -#include "marshallers.h"
    #include "pidgin.h"
    #include "pidginstock.h"
    @@ -1344,45 +1343,44 @@
    G_TYPE_FROM_CLASS(gobject_class),
    G_SIGNAL_RUN_FIRST,
    G_STRUCT_OFFSET(PidginWebViewClass, buttons_update),
    - NULL, 0, g_cclosure_marshal_VOID__INT,
    + NULL, 0, NULL,
    G_TYPE_NONE, 1, G_TYPE_INT);
    signals[TOGGLE_FORMAT] = g_signal_new("format-toggled",
    G_TYPE_FROM_CLASS(gobject_class),
    G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
    G_STRUCT_OFFSET(PidginWebViewClass, toggle_format),
    - NULL, 0, g_cclosure_marshal_VOID__INT,
    + NULL, 0, NULL,
    G_TYPE_NONE, 1, G_TYPE_INT);
    signals[CLEAR_FORMAT] = g_signal_new("format-cleared",
    G_TYPE_FROM_CLASS(gobject_class),
    G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
    G_STRUCT_OFFSET(PidginWebViewClass, clear_format),
    - NULL, 0, g_cclosure_marshal_VOID__VOID,
    + NULL, 0, NULL,
    G_TYPE_NONE, 0);
    signals[UPDATE_FORMAT] = g_signal_new("format-updated",
    G_TYPE_FROM_CLASS(gobject_class),
    G_SIGNAL_RUN_FIRST,
    G_STRUCT_OFFSET(PidginWebViewClass, update_format),
    - NULL, 0, g_cclosure_marshal_VOID__VOID,
    + NULL, 0, NULL,
    G_TYPE_NONE, 0);
    signals[CHANGED] = g_signal_new("changed",
    G_TYPE_FROM_CLASS(gobject_class),
    G_SIGNAL_RUN_FIRST,
    G_STRUCT_OFFSET(PidginWebViewClass, changed),
    - NULL, NULL, g_cclosure_marshal_VOID__VOID,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 0);
    signals[HTML_APPENDED] = g_signal_new("html-appended",
    G_TYPE_FROM_CLASS(gobject_class),
    G_SIGNAL_RUN_FIRST,
    G_STRUCT_OFFSET(PidginWebViewClass, html_appended),
    - NULL, NULL,
    - g_cclosure_marshal_VOID__OBJECT,
    + NULL, NULL, NULL,
    G_TYPE_NONE, 1, WEBKIT_TYPE_DOM_RANGE,
    NULL);
    signals[INSERT_IMAGE] = g_signal_new("insert-image",
    G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST,
    G_STRUCT_OFFSET(PidginWebViewClass, insert_image),
    - pidgin_webview_insert_image_accu, NULL,
    - purple_smarshal_BOOLEAN__OBJECT, G_TYPE_BOOLEAN, 1,
    + pidgin_webview_insert_image_accu, NULL, NULL,
    + G_TYPE_BOOLEAN, 1,
    PURPLE_TYPE_IMAGE);
    /* Class Methods */
    --- a/pidgin/libpidgin.c Thu Jun 15 10:48:26 2017 +0300
    +++ b/pidgin/libpidgin.c Fri Jun 30 15:03:16 2017 +0300
    @@ -29,7 +29,6 @@
    #include "core.h"
    #include "dbus-maybe.h"
    #include "debug.h"
    -#include "eventloop.h"
    #include "glibcompat.h"
    #include "log.h"
    #include "network.h"
    @@ -50,7 +49,6 @@
    #include "gtkdebug.h"
    #include "gtkdialogs.h"
    #include "gtkdocklet.h"
    -#include "gtkeventloop.h"
    #include "gtkxfer.h"
    #include "gtkidle.h"
    #include "gtklog.h"
    @@ -63,7 +61,6 @@
    #include "gtkrequest.h"
    #include "gtkroomlist.h"
    #include "gtksavedstatuses.h"
    -#include "gtksession.h"
    #include "gtksmiley-theme.h"
    #include "gtksound.h"
    #include "gtkutils.h"
    @@ -294,11 +291,6 @@
    static void
    pidgin_quit(void)
    {
    -#ifdef USE_SM
    - /* unplug */
    - pidgin_session_end();
    -#endif
    -
    /* Uninit */
    pidgin_utils_uninit();
    pidgin_notify_uninit();
    @@ -317,7 +309,7 @@
    g_hash_table_destroy(ui_info);
    /* and end it all... */
    - gtk_main_quit();
    + g_application_quit(g_application_get_default());
    }
    static GHashTable *pidgin_ui_get_info(void)
    @@ -378,6 +370,12 @@
    }
    static void
    +pidgin_activate_cb(GApplication *application, gpointer user_data)
    +{
    + purple_blist_set_visible(TRUE);
    +}
    +
    +static void
    show_usage(const char *name, gboolean terse)
    {
    char *text;
    @@ -422,6 +420,7 @@
    int pidgin_start(int argc, char *argv[])
    {
    + GApplication *app;
    gboolean opt_force_online = FALSE;
    gboolean opt_help = FALSE;
    gboolean opt_login = FALSE;
    @@ -452,6 +451,7 @@
    GList *active_accounts;
    GStatBuf st;
    GError *error;
    + int ret;
    struct option long_options[] = {
    {"config", required_argument, NULL, 'c'},
    @@ -689,6 +689,9 @@
    purple_debug_set_enabled(debug_enabled);
    purple_debug_set_colored(debug_colored);
    + /* Call this here as GtkApplication calls gtk_init() in
    + * g_application_register() and we don't necessarily want to exit().
    + */
    gui_check = gtk_init_check(&argc, &argv);
    if (!gui_check) {
    const char *display = gdk_display_get_name(gdk_display_get_default());
    @@ -703,6 +706,26 @@
    return 1;
    }
    + app = G_APPLICATION(gtk_application_new("im.pidgin.Pidgin",
    + G_APPLICATION_NON_UNIQUE));
    +
    + g_object_set(app, "register-session", TRUE, NULL);
    +
    + g_signal_connect(app, "activate",
    + G_CALLBACK(pidgin_activate_cb), NULL);
    +
    + if (!g_application_register(app, NULL, &error)) {
    + purple_debug_error("gtk",
    + "Unable to register GApplication: %s\n",
    + error->message);
    + g_clear_error(&error);
    + g_object_unref(app);
    +#ifndef _WIN32
    + g_free(segfault_message);
    +#endif
    + return 1;
    + }
    +
    search_path = g_build_filename(purple_user_dir(), "gtk-3.0.css", NULL);
    error = NULL;
    @@ -726,7 +749,6 @@
    #endif
    purple_core_set_ui_ops(pidgin_core_get_ui_ops());
    - purple_eventloop_set_ui_ops(pidgin_eventloop_get_ui_ops());
    if (!purple_core_init(PIDGIN_UI)) {
    fprintf(stderr,
    @@ -771,9 +793,6 @@
    ui_main();
    -#ifdef USE_SM
    - pidgin_session_init(argv[0], opt_session_arg, opt_config_dir_arg);
    -#endif
    g_free(opt_session_arg);
    opt_session_arg = NULL;
    g_free(opt_config_dir_arg);
    @@ -845,7 +864,23 @@
    winpidgin_post_init();
    #endif
    - gtk_main();
    + /* TODO: Use GtkApplicationWindow or add a window instead */
    + g_application_hold(app);
    +
    + ret = g_application_run(app, 0, NULL);
    +
    + /* Make sure purple has quit in case something in GApplication
    + * has caused g_application_run() to finish on its own. This can
    + * happen, for example, if the desktop session is ending.
    + */
    + if (purple_get_core() != NULL) {
    + purple_core_quit();
    + }
    +
    + /* Now that we're sure purple_core_quit() has been called,
    + * this can be freed.
    + */
    + g_object_unref(app);
    #ifndef _WIN32
    g_free(segfault_message);
    @@ -858,5 +893,5 @@
    winpidgin_cleanup();
    #endif
    - return 0;
    + return ret;
    }
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/pidgin.gresource.xml Fri Jun 30 15:03:16 2017 +0300
    @@ -0,0 +1,6 @@
    +<?xml version="1.0" encoding="UTF-8"?>
    +<gresources>
    + <gresource prefix="/im/pidgin/Pidgin">
    + <file compressed="true">gtkdebug.html</file>
    + </gresource>
    +</gresources>
    --- a/po/POTFILES.in Thu Jun 15 10:48:26 2017 +0300
    +++ b/po/POTFILES.in Fri Jun 30 15:03:16 2017 +0300
    @@ -57,8 +57,6 @@
    libpurple/plugins.c
    libpurple/plugins/autoaccept.c
    libpurple/plugins/buddynote.c
    -libpurple/plugins/caesarcipher.c
    -libpurple/plugins/caesarcipher_consumer.c
    libpurple/plugins/dbus-example.c
    libpurple/plugins/filectl.c
    libpurple/plugins/idle.c