pidgin/pidgin

Merged default into xdg-dirs
xdg-dirs
2017-10-08, Arkadiy Illarionov
10d4a5ed5d67
Merged default into xdg-dirs
  • +6 -5
    .hgignore
  • +5 -0
    ChangeLog.API
  • +0 -1
    INSTALL
  • +0 -6
    config.h.mingw
  • +7 -81
    configure.ac
  • +21 -0
    doc/meson.build
  • +2 -4
    doc/reference/finch/Makefile.am
  • +21 -0
    doc/reference/finch/finch-docs.xml
  • +37 -0
    doc/reference/finch/meson.build
  • +1 -4
    doc/reference/libpurple/Makefile.am
  • +6 -0
    doc/reference/libpurple/libpurple-docs.xml
  • +70 -0
    doc/reference/libpurple/meson.build
  • +1 -2
    doc/reference/libpurple/ui_ops.xml
  • +10 -0
    doc/reference/meson.build
  • +3 -4
    doc/reference/pidgin/Makefile.am
  • +48 -0
    doc/reference/pidgin/meson.build
  • +1 -3
    doc/reference/protocols/facebook/Makefile.am
  • +27 -0
    doc/reference/protocols/facebook/meson.build
  • +1 -0
    doc/reference/protocols/meson.build
  • +0 -3
    finch/Makefile.am
  • +0 -1
    finch/finch.c
  • +0 -735
    finch/getopt.c
  • +0 -136
    finch/getopt.h
  • +0 -177
    finch/getopt1.c
  • +17 -12
    finch/gntblist.c
  • +40 -19
    finch/gntdebug.c
  • +26 -17
    finch/gntdebug.h
  • +25 -13
    finch/gntlog.c
  • +1 -1
    finch/gntsound.c
  • +4 -4
    finch/gntxfer.c
  • +0 -2
    finch/gntxfer.h
  • +38 -68
    finch/libfinch.c
  • +98 -0
    finch/libgnt/meson.build
  • +14 -0
    finch/libgnt/wms/meson.build
  • +116 -0
    finch/meson.build
  • +2 -2
    finch/plugins/gntgf.c
  • +6 -2
    finch/plugins/gnthistory.c
  • +31 -0
    finch/plugins/meson.build
  • +15 -18
    libpurple/Makefile.am
  • +14 -7
    libpurple/account.c
  • +11 -11
    libpurple/account.h
  • +9 -8
    libpurple/accountopt.h
  • +2 -2
    libpurple/accounts.c
  • +3 -4
    libpurple/accounts.h
  • +2 -4
    libpurple/blistnode.h
  • +2 -2
    libpurple/buddylist.c
  • +4 -6
    libpurple/buddylist.h
  • +6 -6
    libpurple/circularbuffer.h
  • +29 -28
    libpurple/cmds.h
  • +12 -9
    libpurple/connection.c
  • +7 -4
    libpurple/connection.h
  • +1 -1
    libpurple/contact.h
  • +8 -2
    libpurple/conversation.c
  • +3 -3
    libpurple/conversation.h
  • +3 -3
    libpurple/conversations.h
  • +4 -4
    libpurple/conversationtypes.c
  • +2 -2
    libpurple/core.h
  • +2 -2
    libpurple/data/purple-url-handler.desktop.in.in
  • +3 -3
    libpurple/dbus-server.c
  • +2 -0
    libpurple/dbus-server.h
  • +27 -40
    libpurple/debug.c
  • +50 -25
    libpurple/debug.h
  • +2 -4
    libpurple/e2ee.h
  • +1 -1
    libpurple/enums.h.in
  • +0 -18
    libpurple/eventloop.c
  • +0 -48
    libpurple/eventloop.h
  • +3 -0
    libpurple/example/meson.build
  • +5 -5
    libpurple/group.h
  • +39 -47
    libpurple/http.c
  • +6 -3
    libpurple/http.h
  • +6 -6
    libpurple/idle.c
  • +2 -2
    libpurple/image-store.c
  • +47 -12
    libpurple/image.c
  • +3 -1
    libpurple/keyring.h
  • +98 -143
    libpurple/log.c
  • +11 -17
    libpurple/log.h
  • +29 -3
    libpurple/media-gst.h
  • +12 -6
    libpurple/media.h
  • +3 -3
    libpurple/media/backend-fs2.c
  • +5 -5
    libpurple/media/backend-iface.h
  • +5 -3
    libpurple/media/candidate.h
  • +7 -7
    libpurple/media/codec.h
  • +7 -7
    libpurple/mediamanager.c
  • +7 -7
    libpurple/mediamanager.h
  • +473 -0
    libpurple/meson.build
  • +1 -1
    libpurple/message.h
  • +10 -5
    libpurple/mime.h
  • +3 -3
    libpurple/network.c
  • +1 -1
    libpurple/network.h
  • +1 -1
    libpurple/notify.h
  • +1 -1
    libpurple/pluginpref.h
  • +3 -3
    libpurple/plugins/Makefile.am
  • +1 -1
    libpurple/plugins/dbus-example.c
  • +2 -2
    libpurple/plugins/filectl.c
  • +2 -2
    libpurple/plugins/joinpart.c
  • +38 -0
    libpurple/plugins/keyrings/meson.build
  • +100 -140
    libpurple/plugins/log_reader.c
  • +88 -0
    libpurple/plugins/meson.build
  • +2 -2
    libpurple/pounce.c
  • +2 -3
    libpurple/pounce.h
  • +2 -2
    libpurple/prefs.c
  • +27 -16
    libpurple/prefs.h
  • +15 -6
    libpurple/presence.c
  • +1 -1
    libpurple/presence.h
  • +3 -3
    libpurple/protocols.h
  • +1 -1
    libpurple/protocols/bonjour/bonjour.c
  • +2 -2
    libpurple/protocols/bonjour/jabber.c
  • +36 -0
    libpurple/protocols/bonjour/meson.build
  • +0 -1
    libpurple/protocols/facebook/Makefile.am
  • +11 -1
    libpurple/protocols/facebook/api.c
  • +3 -3
    libpurple/protocols/facebook/data.c
  • +35 -0
    libpurple/protocols/facebook/meson.build
  • +4 -4
    libpurple/protocols/facebook/mqtt.c
  • +2 -2
    libpurple/protocols/gg/avatar.c
  • +1 -1
    libpurple/protocols/gg/chat.c
  • +62 -0
    libpurple/protocols/gg/meson.build
  • +2 -2
    libpurple/protocols/gg/roster.c
  • +1 -1
    libpurple/protocols/irc/irc.c
  • +18 -0
    libpurple/protocols/irc/meson.build
  • +1 -1
    libpurple/protocols/irc/msgs.c
  • +3 -3
    libpurple/protocols/jabber/bosh.c
  • +4 -4
    libpurple/protocols/jabber/buddy.c
  • +2 -2
    libpurple/protocols/jabber/caps.c
  • +8 -8
    libpurple/protocols/jabber/jabber.c
  • +116 -0
    libpurple/protocols/jabber/meson.build
  • +1 -1
    libpurple/protocols/jabber/ping.c
  • +10 -10
    libpurple/protocols/jabber/si.c
  • +8 -0
    libpurple/protocols/jabber/tests/meson.build
  • +12 -0
    libpurple/protocols/meson.build
  • +34 -0
    libpurple/protocols/novell/meson.build
  • +11 -0
    libpurple/protocols/null/meson.build
  • +1 -1
    libpurple/protocols/null/nullprpl.c
  • +4 -4
    libpurple/protocols/oscar/flap_connection.c
  • +68 -0
    libpurple/protocols/oscar/meson.build
  • +6 -6
    libpurple/protocols/oscar/oft.c
  • +5 -5
    libpurple/protocols/oscar/oscar.c
  • +1 -1
    libpurple/protocols/oscar/oscar_data.c
  • +5 -5
    libpurple/protocols/oscar/peer.c
  • +8 -0
    libpurple/protocols/oscar/tests/meson.build
  • +15 -0
    libpurple/protocols/sametime/meson.build
  • +2 -2
    libpurple/protocols/sametime/sametime.c
  • +22 -0
    libpurple/protocols/silc/meson.build
  • +4 -4
    libpurple/protocols/silc/silc.c
  • +18 -0
    libpurple/protocols/simple/meson.build
  • +5 -5
    libpurple/protocols/simple/simple.c
  • +84 -0
    libpurple/protocols/zephyr/meson.build
  • +5 -5
    libpurple/protocols/zephyr/zephyr.c
  • +1 -1
    libpurple/purple-client.c
  • +8 -8
    libpurple/queuedoutputstream.h
  • +2 -2
    libpurple/request-datasheet.h
  • +10 -10
    libpurple/request.h
  • +5 -4
    libpurple/roomlist.h
  • +2 -2
    libpurple/savedstatuses.c
  • +3 -5
    libpurple/savedstatuses.h
  • +1 -1
    libpurple/server.c
  • +16 -0
    libpurple/signals.c
  • +2 -0
    libpurple/signals.h
  • +1 -1
    libpurple/smiley-list.c
  • +2 -4
    libpurple/smiley-list.h
  • +1 -2
    libpurple/smiley-parser.h
  • +1 -1
    libpurple/smiley-theme.h
  • +1 -0
    libpurple/smiley.c
  • +1 -1
    libpurple/smiley.h
  • +3 -3
    libpurple/sound.c
  • +2 -2
    libpurple/sslconn.c
  • +3 -2
    libpurple/sslconn.h
  • +2 -1
    libpurple/status.c
  • +4 -3
    libpurple/status.h
  • +1 -1
    libpurple/stringref.c
  • +6 -6
    libpurple/stun.c
  • +2 -2
    libpurple/tests.h
  • +16 -0
    libpurple/tests/meson.build
  • +43 -1
    libpurple/tests/test_image.c
  • +15 -1
    libpurple/tests/test_smiley.c
  • +4 -0
    libpurple/tests/test_smiley_list.c
  • +43 -0
    libpurple/tests/test_util.c
  • +1 -1
    libpurple/theme-loader.h
  • +4 -2
    libpurple/theme-manager.h
  • +4 -4
    libpurple/tls-certificate.h
  • +15 -15
    libpurple/upnp.c
  • +123 -21
    libpurple/util.c
  • +22 -21
    libpurple/util.h
  • +1 -0
    libpurple/win32/libc_interface.c
  • +1415 -0
    meson.build
  • +116 -0
    meson_options.txt
  • +70 -0
    mkmesonconf.py
  • +1 -0
    package_revision.h.in
  • +24 -19
    pidgin/Makefile.am
  • +22 -0
    pidgin/about.html
  • +20 -0
    pidgin/about.md
  • +279 -0
    pidgin/about.ui
  • +736 -0
    pidgin/credits.json
  • +39 -0
    pidgin/data/im.pidgin.Pidgin.appdata.xml.in
  • +11 -0
    pidgin/data/im.pidgin.Pidgin.desktop.in.in
  • +0 -29
    pidgin/data/pidgin.appdata.xml.in
  • +0 -11
    pidgin/data/pidgin.desktop.in.in
  • +0 -735
    pidgin/getopt.c
  • +0 -136
    pidgin/getopt.h
  • +0 -177
    pidgin/getopt1.c
  • +12 -0
    pidgin/gtk3compat.h
  • +1 -2
    pidgin/gtkaccount.c
  • +49 -50
    pidgin/gtkblist.c
  • +28 -35
    pidgin/gtkconv.c
  • +74 -35
    pidgin/gtkdebug.c
  • +23 -18
    pidgin/gtkdebug.h
  • +3 -640
    pidgin/gtkdialogs.c
  • +0 -4
    pidgin/gtkdialogs.h
  • +7 -11
    pidgin/gtkdocklet.c
  • +95 -53
    pidgin/gtkidle.c
  • +77 -69
    pidgin/gtklog.c
  • +79 -58
    pidgin/gtkmedia.c
  • +0 -3
    pidgin/gtknotify.c
  • +0 -2
    pidgin/gtkplugin.c
  • +1 -2
    pidgin/gtkpounce.c
  • +0 -2
    pidgin/gtkprefs.c
  • +0 -2
    pidgin/gtkrequest.c
  • +3 -4
    pidgin/gtkroomlist.c
  • +0 -2
    pidgin/gtksavedstatuses.c
  • +0 -1
    pidgin/gtksmiley-manager.c
  • +3 -3
    pidgin/gtksound.c
  • +12 -13
    pidgin/gtkstatusbox.c
  • +33 -3
    pidgin/gtkutils.c
  • +7 -21
    pidgin/gtkutils.h
  • +5 -6
    pidgin/gtkwebview.c
  • +1 -1
    pidgin/gtkwebview.h
  • +18 -4
    pidgin/gtkwebviewtoolbar.c
  • +2 -2
    pidgin/gtkwhiteboard.c
  • +4 -5
    pidgin/gtkxfer.c
  • +91 -148
    pidgin/libpidgin.c
  • +0 -0
    pidgin/logo.png
  • +235 -0
    pidgin/meson.build
  • +3 -1
    pidgin/pidgin.c
  • +9 -1
    pidgin/pidgin.gresource.xml
  • +488 -0
    pidgin/pidginabout.c
  • +25 -0
    pidgin/pidginabout.h
  • +32 -0
    pidgin/pixmaps/dialogs/meson.build
  • +204 -0
    pidgin/pixmaps/emotes/default/24/meson.build
  • +104 -0
    pidgin/pixmaps/emotes/small/16/meson.build
  • +14 -0
    pidgin/pixmaps/icons/meson.build
  • +28 -0
    pidgin/pixmaps/meson.build
  • +10 -0
    pidgin/pixmaps/protocols/meson.build
  • +4 -0
    pidgin/pixmaps/status/meson.build
  • +5 -0
    pidgin/pixmaps/toolbar/meson.build
  • +33 -0
    pidgin/pixmaps/tray/meson.build
  • +5 -5
    pidgin/plugins/cap/cap.c
  • +6 -0
    pidgin/plugins/cap/meson.build
  • +2 -4
    pidgin/plugins/disco/gtkdisco.c
  • +13 -0
    pidgin/plugins/disco/meson.build
  • +14 -0
    pidgin/plugins/gestures/meson.build
  • +0 -1
    pidgin/plugins/gevolution/add_buddy_dialog.c
  • +0 -1
    pidgin/plugins/gevolution/assoc-buddy.c
  • +0 -1
    pidgin/plugins/gevolution/gevolution.c
  • +16 -0
    pidgin/plugins/gevolution/meson.build
  • +6 -5
    pidgin/plugins/history.c
  • +4 -4
    pidgin/plugins/mailchk.c
  • +105 -0
    pidgin/plugins/meson.build
  • +3 -3
    pidgin/plugins/musicmessaging/Makefile.am
  • +14 -0
    pidgin/plugins/musicmessaging/meson.build
  • +1 -1
    pidgin/plugins/musicmessaging/musicmessaging.c
  • +2 -2
    pidgin/plugins/screencap.c
  • +0 -1
    pidgin/plugins/spellchk.c
  • +12 -0
    pidgin/plugins/ticker/meson.build
  • +4 -0
    pidgin/plugins/win32/transparency/meson.build
  • +10 -0
    pidgin/plugins/win32/winprefs/meson.build
  • +6 -0
    pidgin/themes/meson.build
  • +3 -3
    pidgin/win32/gtkdocklet-win32.c
  • +49 -30
    pidgin/win32/gtkwin32dep.c
  • +7 -4
    pidgin/win32/gtkwin32dep.h
  • +8 -8
    pidgin/win32/pidgin_dll_rc.rc.in
  • +1 -1
    pidgin/win32/pidgin_exe_rc.rc.in
  • +6 -3
    po/POTFILES.in
  • +3 -3
    po/POTFILES.skip
  • +5 -0
    po/meson.build
  • +18 -0
    share/ca-certs/meson.build
  • +10 -0
    share/sounds/meson.build
  • --- a/.hgignore Fri Jul 07 11:50:28 2017 +0300
    +++ b/.hgignore Sun Oct 08 20:44:26 2017 +0300
    @@ -38,7 +38,7 @@
    aclocal.m4
    autogen.args
    autom4te.*\.cache
    -^build\/
    +^build(.+)?\/
    compile
    config.cache
    config.guess
    @@ -75,7 +75,8 @@
    libpurple/data/purple-url-handler.desktop$
    libpurple/data/purple-url-handler.desktop.in$
    libpurple/plugins/dbus-example-bindings.c
    -libpurple/purple-client-bindings.[ch]
    +libpurple/purple-client-bindings.ch
    +libpurple/purple-client-bindings.h
    libpurple/purple-client-example
    libpurple/purple.h$
    libpurple/tests/core
    @@ -107,9 +108,9 @@
    pidgin.apspec$
    pidgin/.*\.gresource\.[ch]$
    pidgin/pidgin$
    -pidgin/data/pidgin.appdata.xml$
    -pidgin/data/pidgin.desktop$
    -pidgin/data/pidgin.desktop.in$
    +pidgin/data/im.pidgin.Pidgin.appdata.xml$
    +pidgin/data/im.pidgin.Pidgin.desktop$
    +pidgin/data/im.pidgin.Pidgin.desktop.in$
    pidgin/pixmaps/emotes/default/24/theme
    pidgin/pixmaps/emotes/none/theme
    pidgin/pixmaps/emotes/small/16/theme
    --- a/ChangeLog.API Fri Jul 07 11:50:28 2017 +0300
    +++ b/ChangeLog.API Sun Oct 08 20:44:26 2017 +0300
    @@ -259,6 +259,9 @@
    * PurpleIconScaleRules renamed to PurpleBuddyIconScaleFlags
    * purple_imgstore_add renamed to purple_imgstore_new
    * purple_imgstore_add_with_id renamed to purple_imgstore_new_with_id
    + * PurpleLog, purple_log_new, purple_log_write and
    + PurpleLogLogger->write take a GDateTime instead of a time_t
    + and struct tm
    * purple_network_listen now takes the protocol family as the second
    parameter
    * purple_network_listen now takes a boolean indicating external port
    @@ -468,6 +471,7 @@
    * purple_presence_new
    * purple_presence_new_for_account
    * purple_presence_new_for_buddy
    + * purple_print_utf8_to_console
    * PurplePluginProtocolInfo
    * purple_proxy_connect_socks5
    * purple_request_field_list_add
    @@ -484,6 +488,7 @@
    * purple_status_type_set_primary_attr
    * purple_strlcat
    * purple_strlcpy
    + * purple_timeout_*. Use g_timeout_* or g_idle_* instead.
    * purple_txt_cancel
    * purple_txt_resolve_account
    * PurpleType, use GType instead.
    --- a/INSTALL Fri Jul 07 11:50:28 2017 +0300
    +++ b/INSTALL Sun Oct 08 20:44:26 2017 +0300
    @@ -150,7 +150,6 @@
    Optional Packages:
    - `--with-silc-includes=DIR' and `--with-silc-libs=DIR' can be used if your silc libraries are installed to a location not in your path.
    `--with-static-prpls' takes a list of comma separated protocols to build in statically (rather than as plugins). Use this with care.
    --- a/config.h.mingw Fri Jul 07 11:50:28 2017 +0300
    +++ b/config.h.mingw Sun Oct 08 20:44:26 2017 +0300
    @@ -90,9 +90,6 @@
    /* Define to 1 if you have the `getifaddrs' function. */
    /* #undef HAVE_GETIFADDRS */
    -/* Define to 1 if you have the `getopt_long' function. */
    -/* #define HAVE_GETOPT_LONG 1 */
    -
    /* Define if the GNU gettext() function is already present or preinstalled. */
    /* #define HAVE_GETTEXT 1 */
    @@ -354,9 +351,6 @@
    /* Define if python headers are available. */
    /* #undef USE_PYTHON */
    -/* Define if we're using XScreenSaver. */
    -#define USE_SCREENSAVER 1
    -
    /* Use voice and video */
    /* #define USE_VV 1 */
    --- a/configure.ac Fri Jul 07 11:50:28 2017 +0300
    +++ b/configure.ac Sun Oct 08 20:44:26 2017 +0300
    @@ -249,19 +249,12 @@
    dnl Checks for library functions.
    AC_CHECK_FUNCS(strdup)
    -dnl Checks for getopt in standard library
    -AC_CHECK_FUNCS(getopt_long,,
    -[
    - AC_LIBOBJ(getopt)
    - AC_LIBOBJ(getopt1)
    -])
    dnl Check for inet_aton
    if test "x$is_win32" != "xyes" ; then
    AC_CHECK_FUNC(inet_aton, , [AC_CHECK_LIB(resolv, inet_aton, ,
    [AC_MSG_ERROR([inet_aton not found])])])
    fi
    -AC_CHECK_LIB(resolv, __res_query)
    AC_CHECK_LIB(nsl, gethostent)
    if test "x$is_win32" = "xyes" ; then
    AC_DEFINE(HAVE_GETADDRINFO, 1, [Define to 1 if you have the getaddrinfo function.])
    @@ -407,8 +400,6 @@
    # before gettexting, in case iconv matters
    case "$host_os" in
    darwin*)
    - AC_CHECK_LIB(resolv, res_query)
    -
    AC_CHECK_HEADER(CoreFoundation/CoreFoundation.h, [
    AC_CHECK_HEADER(IOKit/IOKitLib.h, [
    AC_DEFINE(HAVE_IOKIT, 1, [Define if we have IOKit])
    @@ -467,13 +458,13 @@
    AM_CONDITIONAL(INSTALL_I18N, test "x$enable_i18n" = "xyes")
    dnl #######################################################################
    -dnl # Check for GLib 2.36 (required)
    +dnl # Check for GLib 2.40 (required)
    dnl #######################################################################
    -PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.36.0 gio-2.0 gobject-2.0 gthread-2.0], , [
    +PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.40.0 gio-2.0 gobject-2.0 gthread-2.0], , [
    AC_MSG_RESULT(no)
    AC_MSG_ERROR([
    -You must have GLib 2.36.0 or newer development headers installed to build.
    +You must have GLib 2.40.0 or newer development headers installed to build.
    If you have these installed already you may need to install pkg-config so
    I can find them.
    @@ -519,14 +510,6 @@
    dnl #######################################################################
    dnl # Check for GTK+ 2.18 and other things used by the GTK UI
    dnl #######################################################################
    -AC_ARG_ENABLE(screensaver,
    - [AS_HELP_STRING([--disable-screensaver],
    - [compile without X screensaver extension (used to detect idleness)])],
    - enable_screensaver="$enableval", enable_screensaver="yes")
    -AC_ARG_ENABLE(startup-notification,
    - [AS_HELP_STRING([--disable-startup-notification],
    - [compile without startup notification support])],
    - enable_startup_notification="$enableval", enable_startup_notification="yes")
    AC_ARG_ENABLE(enchant,
    [AS_HELP_STRING([--disable-enchant],
    [compile without Enchant spell checking support])],
    @@ -640,52 +623,10 @@
    AC_SUBST(X11_LIBS)
    AC_SUBST(X11_CFLAGS)
    else
    - enable_screensaver=no
    enable_gestures=no
    fi
    dnl #######################################################################
    - dnl # Check for XScreenSaver
    - dnl #######################################################################
    - if test "x$enable_screensaver" = "xyes" ; then
    - if test "x$with_x" = "xyes" ; then
    - old_LIBS="$LIBS"
    - LIBS="$LIBS $GTK_LIBS $x_libpath_add"
    - XSS_LIBS=""
    - XSS_HEADERS=""
    - AC_CHECK_LIB(Xext, XScreenSaverRegister,[XSS_LIBS="$X_LIBS $X_PRE_LIBS -lX11 -lXext $X_EXTRA_LIBS"],[],[-lX11 -lXext -lm])
    - AC_CHECK_LIB(Xss, XScreenSaverRegister,[XSS_LIBS="$X_LIBS $X_PRE_LIBS -lX11 -lXext $X_LIBS $X_EXTRA_LIBS -lXss"],[],[-lX11 -lXext -lm])
    - if test "x$XSS_LIBS" != "x"; then
    - oldCPPFLAGS="$CPPFLAGS"
    - CPPFLAGS="$CPPFLAGS $x_incpath_add"
    - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
    - #include <X11/Xlib.h>
    - #include <X11/extensions/scrnsaver.h>
    - ]], [[]])], [], [enable_screensaver=no])
    - CPPFLAGS="$oldCPPFLAGS"
    - else
    - enable_screensaver=no
    - fi
    - LIBS="$old_LIBS"
    -
    - if test "x$enable_screensaver" = "xyes" ; then
    - AC_DEFINE(USE_SCREENSAVER, 1, [Define if we're using XScreenSaver.])
    - AC_SUBST(XSS_LIBS)
    - else
    - if test "x$force_deps" = "xyes" ; then
    - AC_MSG_ERROR([
    -XScreenSaver extension development headers (libXScrnSaver-devel or libxss-dev) not found.
    -Use --disable-screensaver if you do not need XScreenSaver extension support,
    -this is required for detecting idle time by mouse and keyboard usage.
    -])
    - fi
    - fi
    - else
    - AC_MSG_ERROR([X support is required to build with XScreenSaver extensions])
    - fi
    - fi
    -
    - dnl #######################################################################
    dnl # Check for X11 to allow the gestures plugin
    dnl #######################################################################
    if test "x$enable_gestures" = "xyes"; then
    @@ -752,8 +693,6 @@
    enable_gcr=no
    enable_cap=no
    enable_gevolution=no
    - enable_screensaver=no
    - enable_startup_notification=no
    fi # GTK
    AM_CONDITIONAL(ENABLE_GTK, test "x$enable_gtkui" = "xyes")
    @@ -890,17 +829,6 @@
    AC_SUBST(JSON_LIBS)
    dnl #######################################################################
    -dnl # Check for zlib (required)
    -dnl #######################################################################
    -
    -PKG_CHECK_MODULES(ZLIB, [zlib >= 1.2.0], , [
    - AC_SEARCH_LIBS([deflate], [z], [], AC_MSG_ERROR([You must have zlib >= 1.2.0 development headers installed to build.]), [])
    -])
    -
    -AC_SUBST(ZLIB_CFLAGS)
    -AC_SUBST(ZLIB_LIBS)
    -
    -dnl #######################################################################
    dnl # Check for GStreamer
    dnl #######################################################################
    AC_ARG_ENABLE(gstreamer,
    @@ -1184,8 +1112,6 @@
    AC_SUBST(LIBGADU_CFLAGS)
    -AC_ARG_ENABLE(distrib,,,enable_distrib=no)
    -AM_CONDITIONAL(DISTRIB, test "x$enable_distrib" = "xyes")
    DYNAMIC_PRPLS=all
    AC_ARG_WITH(static-prpls, [AS_HELP_STRING([--with-static-prpls], [Link to certain protocols statically])], [STATIC_PRPLS=`echo $withval | $sedpath 's/,/ /g'`], [STATIC_PRPLS=""])
    if test "x$STATIC_PRPLS" != "x" -a "x$DYNAMIC_PRPLS" = "xall"; then
    @@ -1334,6 +1260,7 @@
    "-Wendif-labels" \
    "-Werror-implicit-function-declaration" \
    "-Wextra -Wno-unused-parameter" \
    + "-Wno-missing-field-initializers" \
    "-Wformat-security" \
    "-Werror=format-security" \
    "-Winit-self" \
    @@ -1456,6 +1383,7 @@
    dnl #######################################################################
    dnl # Check for Unity and Messaging Menu
    +dnl # Remove when Ubuntu 16.04 is EOL
    dnl #######################################################################
    AC_ARG_ENABLE(unity, [AC_HELP_STRING([--enable-unity],
    [compile with support for unity integration plugin])], enable_unity="$enableval", enable_unity="no")
    @@ -2045,7 +1973,7 @@
    doc/reference/pidgin/version.xml
    m4macros/Makefile
    pidgin/Makefile
    - pidgin/data/pidgin.desktop.in
    + pidgin/data/im.pidgin.Pidgin.desktop.in
    pidgin/data/pidgin-3.pc
    pidgin/data/pidgin-3-uninstalled.pc
    pidgin/pixmaps/Makefile
    @@ -2135,8 +2063,6 @@
    echo Install translations.......... : $enable_i18n
    echo Has you....................... : yes
    echo
    -echo Use XScreenSaver Extension.... : $enable_screensaver
    -echo Use startup notification...... : $enable_startup_notification
    echo Build with Enchant support.... : $use_enchant
    echo Build with GCR widgets........ : $enable_gcr
    echo Build Unity integration plugin.: $enable_unity
    @@ -2169,7 +2095,7 @@
    if test "x$enable_i18n" = "xno" ; then
    echo
    echo Warning: You have disabled the building and installation of translation
    - echo data. This will prevent building pidgin.desktop and the GConf schemas.
    + echo data. This will prevent building Pidgin desktop files.
    echo Be sure you know what you are doing.
    fi
    echo
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/doc/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,21 @@
    +if ENABLE_DOC
    + subdir('reference')
    +endif
    +
    +if ENABLE_GTK
    + pidgin_man = configure_file(
    + input : 'pidgin.1.in',
    + output : 'pidgin.1',
    + configuration : man_conf,
    + install : true,
    + install_dir : get_option('mandir') + '/man1')
    +endif
    +
    +if enable_consoleui
    + finch_man = configure_file(
    + input : 'finch.1.in',
    + output : 'finch.1',
    + configuration : man_conf,
    + install : true,
    + install_dir : get_option('mandir') + '/man1')
    +endif
    --- a/doc/reference/finch/Makefile.am Fri Jul 07 11:50:28 2017 +0300
    +++ b/doc/reference/finch/Makefile.am Sun Oct 08 20:44:26 2017 +0300
    @@ -35,7 +35,7 @@
    # Extra options to supply to gtkdoc-mkdb.
    # e.g. MKDB_OPTIONS=--xml-mode --output-format=xml
    -MKDB_OPTIONS=--xml-mode --output-format=xml
    +MKDB_OPTIONS=--xml-mode --output-format=xml --ignore-files="$(IGNORE_HFILES)"
    # Extra options to supply to gtkdoc-mktmpl
    # e.g. MKTMPL_OPTIONS=--only-section-tmpl
    @@ -63,10 +63,8 @@
    IGNORE_HFILES=\
    plugins \
    test \
    - wms \
    - getopt.h \
    + libgnt/wms \
    gntinternal.h \
    - gntmarshal.h \
    gnt-skel.h
    # Images to copy into HTML directory.
    --- a/doc/reference/finch/finch-docs.xml Fri Jul 07 11:50:28 2017 +0300
    +++ b/doc/reference/finch/finch-docs.xml Sun Oct 08 20:44:26 2017 +0300
    @@ -64,6 +64,7 @@
    <!-- TODO: document not found. Find it.
    <xi:include href="xml/gntid.xml" />
    -->
    + <xi:include href="xml/gntlabel.xml" />
    <xi:include href="xml/gntline.xml" />
    <xi:include href="xml/gntmenu.xml" />
    <xi:include href="xml/gntmenuitem.xml" />
    @@ -87,6 +88,26 @@
    <title>Index of deprecated symbols</title>
    <xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
    </index>
    + <index id="api-index-2.8.0" role="2.8.0">
    + <title>Index of new symbols in 2.8.0</title>
    + <xi:include href="xml/api-index-2.8.0.xml"><xi:fallback /></xi:include>
    + </index>
    + <index id="api-index-2.4.0" role="2.4.0">
    + <title>Index of new symbols in 2.4.0</title>
    + <xi:include href="xml/api-index-2.4.0.xml"><xi:fallback /></xi:include>
    + </index>
    + <index id="api-index-2.3.0" role="2.3.0">
    + <title>Index of new symbols in 2.3.0</title>
    + <xi:include href="xml/api-index-2.3.0.xml"><xi:fallback /></xi:include>
    + </index>
    + <index id="api-index-2.2.0" role="2.2.0">
    + <title>Index of new symbols in 2.2.0</title>
    + <xi:include href="xml/api-index-2.2.0.xml"><xi:fallback /></xi:include>
    + </index>
    + <index id="api-index-2.0.0" role="2.0.0">
    + <title>Index of new symbols in 2.0.0</title>
    + <xi:include href="xml/api-index-2.0.0.xml"><xi:fallback /></xi:include>
    + </index>
    <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
    </book>
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/doc/reference/finch/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,37 @@
    +DOC_MODULE = 'finch'
    +
    +# Header files or dirs to ignore when scanning. Use base file/dir names
    +ignore_hfiles = [
    + 'plugins',
    + 'test',
    + 'libgnt/wms',
    + 'gntinternal.h',
    + 'gnt-skel.h'
    +]
    +
    +# Extra options to supply to gtkdoc-scan.
    +scan_args = [
    + '--deprecated-guards=PURPLE_DISABLE_DEPRECATED|GNT_DISABLE_DEPRECATED|FINCH_DISABLE_DEPRECATED',
    + '--rebuild-types',
    + '--rebuild-sections',
    + '--ignore-headers=' + ' '.join(ignore_hfiles),
    +]
    +
    +# Extra options to supply to gtkdoc-mkdb.
    +mkdb_args = [
    + '--ignore-files=' + ' '.join(ignore_hfiles),
    +]
    +
    +configure_file(
    + input : 'version.xml.in',
    + output : 'version.xml',
    + configuration : version_conf)
    +
    +gnome.gtkdoc(DOC_MODULE,
    + main_xml : DOC_MODULE + '-docs.xml',
    + src_dir : libfinch_inc,
    + dependencies : libfinch_dep,
    + install : true,
    + scan_args : scan_args,
    + mkdb_args : mkdb_args,
    + gobject_typesfile : DOC_MODULE + '.types')
    --- a/doc/reference/libpurple/Makefile.am Fri Jul 07 11:50:28 2017 +0300
    +++ b/doc/reference/libpurple/Makefile.am Sun Oct 08 20:44:26 2017 +0300
    @@ -35,7 +35,7 @@
    # Extra options to supply to gtkdoc-mkdb.
    # e.g. MKDB_OPTIONS=--xml-mode --output-format=xml
    -MKDB_OPTIONS=--xml-mode --output-format=xml
    +MKDB_OPTIONS=--xml-mode --output-format=xml --ignore-files="$(IGNORE_HFILES)"
    # Extra options to supply to gtkdoc-mktmpl
    # e.g. MKTMPL_OPTIONS=--only-section-tmpl
    @@ -76,7 +76,6 @@
    dbus-types.h \
    glibcompat.h \
    internal.h \
    - marshallers.h \
    purple-client.h \
    purple-client-bindings.h \
    valgrind.h
    @@ -135,7 +134,6 @@
    $(IDN_CFLAGS) \
    $(NETWORKMANAGER_CFLAGS) \
    $(JSON_CFLAGS) \
    - $(ZLIB_CFLAGS) \
    $(INTROSPECTION_CFLAGS)
    GTKDOC_LIBS = \
    @@ -153,7 +151,6 @@
    $(GSTINTERFACES_LIBS) \
    $(IDN_LIBS) \
    $(JSON_LIBS) \
    - $(ZLIB_LIBS) \
    $(INTROSPECTION_LIBS) \
    -lm
    --- a/doc/reference/libpurple/libpurple-docs.xml Fri Jul 07 11:50:28 2017 +0300
    +++ b/doc/reference/libpurple/libpurple-docs.xml Sun Oct 08 20:44:26 2017 +0300
    @@ -65,6 +65,8 @@
    <xi:include href="xml/protocol.xml" />
    <xi:include href="xml/protocols.xml" />
    <xi:include href="xml/proxy.xml" />
    + <xi:include href="xml/purple-gio.xml" />
    + <xi:include href="xml/queuedoutputstream.xml" />
    <xi:include href="xml/signals.xml" />
    <xi:include href="xml/stringref.xml" />
    <xi:include href="xml/request.xml" />
    @@ -176,6 +178,10 @@
    <title>Index of deprecated symbols</title>
    <xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
    </index>
    + <index id="api-index-2.11.0" role="2.11.0">
    + <title>Index of new symbols in 2.11.0</title>
    + <xi:include href="xml/api-index-2.11.0.xml"><xi:fallback /></xi:include>
    + </index>
    <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
    </book>
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/doc/reference/libpurple/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,70 @@
    +DOC_MODULE = 'libpurple'
    +
    +# Header files or dirs to ignore when scanning. Use base file/dir names
    +ignore_hfiles = [
    + 'example',
    + 'plugins',
    + 'protocols',
    + 'tests',
    + 'win32',
    + 'backend-fs2.h',
    + 'dbus-define-api.h',
    + 'dbus-types.h',
    + 'glibcompat.h',
    + 'internal.h',
    + 'purple-client.h',
    + 'purple-client-bindings.h',
    + 'valgrind.h'
    +]
    +
    +# Extra options to supply to gtkdoc-scan.
    +scan_args = [
    + '--deprecated-guards=PURPLE_DISABLE_DEPRECATED',
    + '--rebuild-types',
    + '--rebuild-sections',
    + '--ignore-headers=' + ' '.join(ignore_hfiles),
    +]
    +
    +# Extra options to supply to gtkdoc-mkdb.
    +mkdb_args = [
    + '--ignore-files=' + ' '.join(ignore_hfiles),
    +]
    +
    +libpurple_version_xml = configure_file(
    + input : 'version.xml.in',
    + output : 'version.xml',
    + configuration : version_conf)
    +
    +content_files = [
    + 'plugin_i18n.xml',
    + 'plugin_ids.xml',
    + 'signals_account.xml',
    + 'signals_blist.xml',
    + 'signals_certificate.xml',
    + 'signals_cmd.xml',
    + 'signals_connection.xml',
    + 'signals_conversation.xml',
    + 'signals_core.xml',
    + 'signals_dbus_server.xml',
    + 'signals_jabber.xml',
    + 'signals_log.xml',
    + 'signals_notify.xml',
    + 'signals_plugin.xml',
    + 'signals_protocol.xml',
    + 'signals_savedstatus.xml',
    + 'signals_sound.xml',
    + 'signals_xfer.xml',
    + 'tut_c_plugins.xml',
    + 'tut_signals.xml',
    + 'ui_ops.xml',
    +]
    +
    +gnome.gtkdoc(DOC_MODULE,
    + main_xml : DOC_MODULE + '-docs.xml',
    + src_dir : libpurple_inc,
    + dependencies : libpurple_dep,
    + install : true,
    + scan_args : scan_args,
    + mkdb_args : mkdb_args,
    + gobject_typesfile : DOC_MODULE + '.types',
    + content_files : content_files)
    --- a/doc/reference/libpurple/ui_ops.xml Fri Jul 07 11:50:28 2017 +0300
    +++ b/doc/reference/libpurple/ui_ops.xml Sun Oct 08 20:44:26 2017 +0300
    @@ -12,17 +12,16 @@
    <itemizedlist>
    <listitem><link linkend="PurpleAccountUiOps"><literal>PurpleAccountUiOps</literal></link></listitem>
    <listitem><link linkend="PurpleBlistUiOps"><literal>PurpleBlistUiOps</literal></link></listitem>
    +<listitem><link linkend="PurpleCommandsUiOps"><literal>PurpleCommandsUiOps</literal></link></listitem>
    <listitem><link linkend="PurpleConnectionUiOps"><literal>PurpleConnectionUiOps</literal></link></listitem>
    <listitem><link linkend="PurpleConversationUiOps"><literal>PurpleConversationUiOps</literal></link></listitem>
    <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="PurpleIdleUiOps"><literal>PurpleIdleUiOps</literal></link></listitem>
    <listitem><link linkend="PurpleNotifyUiOps"><literal>PurpleNotifyUiOps</literal></link></listitem>
    <listitem><link linkend="PurpleRequestUiOps"><literal>PurpleRequestUiOps</literal></link></listitem>
    <listitem><link linkend="PurpleRoomlistUiOps"><literal>PurpleRoomlistUiOps</literal></link></listitem>
    <listitem><link linkend="PurpleSoundUiOps"><literal>PurpleSoundUiOps</literal></link></listitem>
    -<listitem><link linkend="PurpleSrvTxtQueryUiOps"><literal>PurpleSrvTxtQueryUiOps</literal></link></listitem>
    <listitem><link linkend="PurpleWhiteboardUiOps"><literal>PurpleWhiteboardUiOps</literal></link></listitem>
    <listitem><link linkend="PurpleXferUiOps"><literal>PurpleXferUiOps</literal></link></listitem>
    </itemizedlist>
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/doc/reference/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,10 @@
    +subdir('libpurple')
    +subdir('protocols')
    +
    +if ENABLE_GTK
    + subdir('pidgin')
    +endif
    +
    +if enable_consoleui
    + subdir('finch')
    +endif
    --- a/doc/reference/pidgin/Makefile.am Fri Jul 07 11:50:28 2017 +0300
    +++ b/doc/reference/pidgin/Makefile.am Sun Oct 08 20:44:26 2017 +0300
    @@ -35,7 +35,7 @@
    # Extra options to supply to gtkdoc-mkdb.
    # e.g. MKDB_OPTIONS=--xml-mode --output-format=xml
    -MKDB_OPTIONS=--xml-mode --output-format=xml
    +MKDB_OPTIONS=--xml-mode --output-format=xml --ignore-files="$(IGNORE_HFILES)"
    # Extra options to supply to gtkdoc-mktmpl
    # e.g. MKTMPL_OPTIONS=--only-section-tmpl
    @@ -65,9 +65,9 @@
    plugins \
    themes \
    win32 \
    - getopt.h \
    gtk3compat.h \
    - gtkinternal.h
    + gtkinternal.h \
    + pidgin.gresource.h
    # Images to copy into HTML directory.
    # e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
    @@ -119,7 +119,6 @@
    $(GSTREAMER_LIBS) \
    $(GSTVIDEO_LIBS) \
    $(GSTINTERFACES_LIBS) \
    - $(XSS_LIBS) \
    $(INTLLIBS) \
    $(LIBXML_LIBS) \
    $(WEBKIT_LIBS) \
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/doc/reference/pidgin/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,48 @@
    +DOC_MODULE = 'pidgin'
    +
    +# Header files or dirs to ignore when scanning. Use base file/dir names
    +ignore_hfiles = [
    + 'pixmaps',
    + 'plugins',
    + 'themes',
    + 'win32',
    + 'gtk3compat.h',
    + 'gtkinternal.h',
    + 'pidgin.gresource.h'
    +]
    +
    +# Extra options to supply to gtkdoc-scan.
    +scan_args = [
    + '--deprecated-guards=PURPLE_DISABLE_DEPRECATED|PIDGIN_DISABLE_DEPRECATED',
    + '--rebuild-types',
    + '--rebuild-sections',
    + '--ignore-headers=' + ' '.join(ignore_hfiles),
    +]
    +
    +# Extra options to supply to gtkdoc-mkdb.
    +mkdb_args = [
    + '--ignore-files=' + ' '.join(ignore_hfiles),
    +]
    +
    +configure_file(
    + input : 'version.xml.in',
    + output : 'version.xml',
    + configuration : version_conf)
    +
    +# Extra SGML files that are included by $(DOC_MAIN_XML_FILE).
    +content_files = [
    + 'signals_gtkaccount.xml',
    + 'signals_gtkblist.xml',
    + 'signals_gtkconv.xml',
    + 'signals_gtklog.xml',
    +]
    +
    +gnome.gtkdoc(DOC_MODULE,
    + main_xml : DOC_MODULE + '-docs.xml',
    + src_dir : libpidgin_inc,
    + dependencies : libpidgin_dep,
    + install : true,
    + scan_args : scan_args,
    + mkdb_args : mkdb_args,
    + gobject_typesfile : DOC_MODULE + '.types',
    + content_files : content_files)
    --- a/doc/reference/protocols/facebook/Makefile.am Fri Jul 07 11:50:28 2017 +0300
    +++ b/doc/reference/protocols/facebook/Makefile.am Sun Oct 08 20:44:26 2017 +0300
    @@ -61,7 +61,7 @@
    # Header files or dirs to ignore when scanning. Use base file/dir names
    # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
    -IGNORE_HFILES=marshal.h
    +IGNORE_HFILES=
    # Images to copy into HTML directory.
    # e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
    @@ -88,7 +88,6 @@
    $(GPLUGIN_CFLAGS) \
    $(DEBUG_CFLAGS) \
    $(JSON_CFLAGS) \
    - $(ZLIB_CFLAGS) \
    $(INTROSPECTION_CFLAGS)
    GTKDOC_LIBS = \
    @@ -98,7 +97,6 @@
    $(GPLUGIN_LIBS) \
    $(INTLLIBS) \
    $(JSON_LIBS) \
    - $(ZLIB_LIBS) \
    $(INTROSPECTION_LIBS)
    # This includes the standard gtk-doc make rules, copied by gtkdocize.
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/doc/reference/protocols/facebook/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,27 @@
    +DOC_MODULE = 'facebook'
    +
    +# Header files or dirs to ignore when scanning. Use base file/dir names
    +ignore_hfiles = [
    +]
    +
    +# Extra options to supply to gtkdoc-scan.
    +scan_args = [
    + '--deprecated-guards=PURPLE_DISABLE_DEPRECATED',
    + '--rebuild-types',
    + '--rebuild-sections',
    + '--ignore-headers=' + ' '.join(ignore_hfiles),
    +]
    +
    +# Extra SGML files that are included by $(DOC_MAIN_XML_FILE).
    +content_files = [
    + libpurple_version_xml,
    +]
    +
    +gnome.gtkdoc(DOC_MODULE,
    + main_xml : DOC_MODULE + '-docs.xml',
    + src_dir : facebook_inc,
    + dependencies : facebook_dep,
    + install : true,
    + scan_args : scan_args,
    + gobject_typesfile : DOC_MODULE + '.types',
    + content_files : content_files)
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/doc/reference/protocols/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,1 @@
    +subdir('facebook')
    --- a/finch/Makefile.am Fri Jul 07 11:50:28 2017 +0300
    +++ b/finch/Makefile.am Sun Oct 08 20:44:26 2017 +0300
    @@ -1,7 +1,4 @@
    EXTRA_DIST = \
    - getopt.c \
    - getopt.h \
    - getopt1.c \
    finch.pc.in
    pkgconfigdir = $(libdir)/pkgconfig
    --- a/finch/finch.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/finch/finch.c Sun Oct 08 20:44:26 2017 +0300
    @@ -32,7 +32,6 @@
    signal(SIGPIPE, SIG_IGN);
    #endif
    - g_set_prgname("Finch");
    g_set_application_name(_("Finch"));
    if (finch_start(&argc, &argv)) {
    --- a/finch/getopt.c Fri Jul 07 11:50:28 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,735 +0,0 @@
    -/* Getopt for GNU.
    - NOTE: getopt is now part of the C library, so if you don't know what
    - "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
    - before changing it!
    -
    - Finch 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, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
    -
    -/* NOTE!!! AIX requires this to be the first thing in the file.
    - Do not put ANYTHING before it! */
    -#if !defined (__GNUC__) && defined (_AIX)
    - #pragma alloca
    -#endif
    -
    -#ifdef HAVE_CONFIG_H
    -#include "config.h"
    -#endif
    -
    -/* Alver says we need this for IRIX. */
    -#include "string.h"
    -
    -#ifdef __GNUC__
    -#define alloca __builtin_alloca
    -#else /* not __GNUC__ */
    -#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
    -#include <alloca.h>
    -#else
    -#ifndef _AIX
    -char *alloca ();
    -#endif
    -#endif /* alloca.h */
    -#endif /* not __GNUC__ */
    -
    -#if !__STDC__ && !defined(const) && IN_GCC
    -#define const
    -#endif
    -
    -/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */
    -#ifndef _NO_PROTO
    -#define _NO_PROTO
    -#endif
    -
    -#include <stdio.h>
    -
    -/* Comment out all this code if we are using the GNU C Library, and are not
    - actually compiling the library itself. This code is part of the GNU C
    - Library, but also included in many other GNU distributions. Compiling
    - and linking in this code is a waste when using the GNU C library
    - (especially if it is a shared library). Rather than having every GNU
    - program understand `configure --with-gnu-libc' and omit the object files,
    - it is simpler to just do this in the source for each such file. */
    -
    -#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
    -
    -
    -/* This needs to come after some library #include
    - to get __GNU_LIBRARY__ defined. */
    -#ifdef __GNU_LIBRARY__
    -#undef alloca
    -/* Don't include stdlib.h for non-GNU C libraries because some of them
    - contain conflicting prototypes for getopt. */
    -#include <stdlib.h>
    -#else /* Not GNU C library. */
    -#define __alloca alloca
    -#endif /* GNU C library. */
    -
    -/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
    - long-named option. Because this is not POSIX.2 compliant, it is
    - being phased out. */
    -/* #define GETOPT_COMPAT */
    -
    -/* This version of `getopt' appears to the caller like standard Unix `getopt'
    - but it behaves differently for the user, since it allows the user
    - to intersperse the options with the other arguments.
    -
    - As `getopt' works, it permutes the elements of ARGV so that,
    - when it is done, all the options precede everything else. Thus
    - all application programs are extended to handle flexible argument order.
    -
    - Setting the environment variable POSIXLY_CORRECT disables permutation.
    - Then the behavior is completely standard.
    -
    - GNU application programs can use a third alternative mode in which
    - they can distinguish the relative order of options and other arguments. */
    -
    -#include "getopt.h"
    -
    -/* For communication from `getopt' to the caller.
    - When `getopt' finds an option that takes an argument,
    - the argument value is returned here.
    - Also, when `ordering' is RETURN_IN_ORDER,
    - each non-option ARGV-element is returned here. */
    -
    -char *optarg = NULL;
    -
    -/* Index in ARGV of the next element to be scanned.
    - This is used for communication to and from the caller
    - and for communication between successive calls to `getopt'.
    -
    - On entry to `getopt', zero means this is the first call; initialize.
    -
    - When `getopt' returns EOF, this is the index of the first of the
    - non-option elements that the caller should itself scan.
    -
    - Otherwise, `optind' communicates from one call to the next
    - how much of ARGV has been scanned so far. */
    -
    -/* XXX 1003.2 says this must be 1 before any call. */
    -int optind = 0;
    -
    -/* The next char to be scanned in the option-element
    - in which the last option character we returned was found.
    - This allows us to pick up the scan where we left off.
    -
    - If this is zero, or a null string, it means resume the scan
    - by advancing to the next ARGV-element. */
    -
    -static char *nextchar;
    -
    -/* Callers store zero here to inhibit the error message
    - for unrecognized options. */
    -
    -int opterr = 1;
    -
    -/* Set to an option character which was unrecognized.
    - This must be initialized on some systems to avoid linking in the
    - system's own getopt implementation. */
    -
    -int optopt = '?';
    -
    -/* Describe how to deal with options that follow non-option ARGV-elements.
    -
    - If the caller did not specify anything,
    - the default is REQUIRE_ORDER if the environment variable
    - POSIXLY_CORRECT is defined, PERMUTE otherwise.
    -
    - REQUIRE_ORDER means don't recognize them as options;
    - stop option processing when the first non-option is seen.
    - This is what Unix does.
    - This mode of operation is selected by either setting the environment
    - variable POSIXLY_CORRECT, or using `+' as the first character
    - of the list of option characters.
    -
    - PERMUTE is the default. We permute the contents of ARGV as we scan,
    - so that eventually all the non-options are at the end. This allows options
    - to be given in any order, even with programs that were not written to
    - expect this.
    -
    - RETURN_IN_ORDER is an option available to programs that were written
    - to expect options and other ARGV-elements in any order and that care about
    - the ordering of the two. We describe each non-option ARGV-element
    - as if it were the argument of an option with character code 1.
    - Using `-' as the first character of the list of option characters
    - selects this mode of operation.
    -
    - The special argument `--' forces an end of option-scanning regardless
    - of the value of `ordering'. In the case of RETURN_IN_ORDER, only
    - `--' can cause `getopt' to return EOF with `optind' != ARGC. */
    -
    -static enum
    -{
    - REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
    -} ordering;
    -
    -#ifdef __GNU_LIBRARY__
    -/* We want to avoid inclusion of string.h with non-GNU libraries
    - because there are many ways it can cause trouble.
    - On some systems, it contains special magic macros that don't work
    - in GCC. */
    -#include <string.h>
    -#define my_index strchr
    -#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n))
    -#else
    -
    -/* Avoid depending on library functions or files
    - whose names are inconsistent. */
    -
    -char *getenv ();
    -
    -static char *
    -my_index (str, chr)
    - const char *str;
    - int chr;
    -{
    - while (*str)
    - {
    - if (*str == chr)
    - return (char *) str;
    - str++;
    - }
    - return 0;
    -}
    -
    -static void
    -my_bcopy (from, to, size)
    - const char *from;
    - char *to;
    - int size;
    -{
    - int i;
    - for (i = 0; i < size; i++)
    - to[i] = from[i];
    -}
    -#endif /* GNU C library. */
    -
    -/* Handle permutation of arguments. */
    -
    -/* Describe the part of ARGV that contains non-options that have
    - been skipped. `first_nonopt' is the index in ARGV of the first of them;
    - `last_nonopt' is the index after the last of them. */
    -
    -static int first_nonopt;
    -static int last_nonopt;
    -
    -/* Exchange two adjacent subsequences of ARGV.
    - One subsequence is elements [first_nonopt,last_nonopt)
    - which contains all the non-options that have been skipped so far.
    - The other is elements [last_nonopt,optind), which contains all
    - the options processed since those non-options were skipped.
    -
    - `first_nonopt' and `last_nonopt' are relocated so that they describe
    - the new indices of the non-options in ARGV after they are moved. */
    -
    -static void
    -exchange (argv)
    - char **argv;
    -{
    - int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
    - char **temp = (char **) __alloca (nonopts_size);
    -
    - /* Interchange the two blocks of data in ARGV. */
    -
    - my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
    - my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
    - (optind - last_nonopt) * sizeof (char *));
    - my_bcopy ((char *) temp,
    - (char *) &argv[first_nonopt + optind - last_nonopt],
    - nonopts_size);
    -
    - /* Update records for the slots the non-options now occupy. */
    -
    - first_nonopt += (optind - last_nonopt);
    - last_nonopt = optind;
    -}
    -
    -/* Scan elements of ARGV (whose length is ARGC) for option characters
    - given in OPTSTRING.
    -
    - If an element of ARGV starts with '-', and is not exactly "-" or "--",
    - then it is an option element. The characters of this element
    - (aside from the initial '-') are option characters. If `getopt'
    - is called repeatedly, it returns successively each of the option characters
    - from each of the option elements.
    -
    - If `getopt' finds another option character, it returns that character,
    - updating `optind' and `nextchar' so that the next call to `getopt' can
    - resume the scan with the following option character or ARGV-element.
    -
    - If there are no more option characters, `getopt' returns `EOF'.
    - Then `optind' is the index in ARGV of the first ARGV-element
    - that is not an option. (The ARGV-elements have been permuted
    - so that those that are not options now come last.)
    -
    - OPTSTRING is a string containing the legitimate option characters.
    - If an option character is seen that is not listed in OPTSTRING,
    - return '?' after printing an error message. If you set `opterr' to
    - zero, the error message is suppressed but we still return '?'.
    -
    - If a char in OPTSTRING is followed by a colon, that means it wants an arg,
    - so the following text in the same ARGV-element, or the text of the following
    - ARGV-element, is returned in `optarg'. Two colons mean an option that
    - wants an optional arg; if there is text in the current ARGV-element,
    - it is returned in `optarg', otherwise `optarg' is set to zero.
    -
    - If OPTSTRING starts with `-' or `+', it requests different methods of
    - handling the non-option ARGV-elements.
    - See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
    -
    - Long-named options begin with `--' instead of `-'.
    - Their names may be abbreviated as long as the abbreviation is unique
    - or is an exact match for some defined option. If they have an
    - argument, it follows the option name in the same ARGV-element, separated
    - from the option name by a `=', or else the in next ARGV-element.
    - When `getopt' finds a long-named option, it returns 0 if that option's
    - `flag' field is nonzero, the value of the option's `val' field
    - if the `flag' field is zero.
    -
    - The elements of ARGV aren't really const, because we permute them.
    - But we pretend they're const in the prototype to be compatible
    - with other systems.
    -
    - LONGOPTS is a vector of `struct option' terminated by an
    - element containing a name which is zero.
    -
    - LONGIND returns the index in LONGOPT of the long-named option found.
    - It is only valid when a long-named option has been found by the most
    - recent call.
    -
    - If LONG_ONLY is nonzero, '-' as well as '--' can introduce
    - long-named options. */
    -
    -int
    -_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
    - int argc;
    - char *const *argv;
    - const char *optstring;
    - const struct option *longopts;
    - int *longind;
    - int long_only;
    -{
    - int option_index;
    -
    - optarg = NULL;
    -
    - /* Initialize the internal data when the first call is made.
    - Start processing options with ARGV-element 1 (since ARGV-element 0
    - is the program name); the sequence of previously skipped
    - non-option ARGV-elements is empty. */
    -
    - if (optind == 0)
    - {
    - first_nonopt = last_nonopt = optind = 1;
    -
    - nextchar = NULL;
    -
    - /* Determine how to handle the ordering of options and nonoptions. */
    -
    - if (optstring[0] == '-')
    - {
    - ordering = RETURN_IN_ORDER;
    - ++optstring;
    - }
    - else if (optstring[0] == '+')
    - {
    - ordering = REQUIRE_ORDER;
    - ++optstring;
    - }
    - else if (getenv ("POSIXLY_CORRECT") != NULL)
    - ordering = REQUIRE_ORDER;
    - else
    - ordering = PERMUTE;
    - }
    -
    - if (nextchar == NULL || *nextchar == '\0')
    - {
    - if (ordering == PERMUTE)
    - {
    - /* If we have just processed some options following some non-options,
    - exchange them so that the options come first. */
    -
    - if (first_nonopt != last_nonopt && last_nonopt != optind)
    - exchange ((char **) argv);
    - else if (last_nonopt != optind)
    - first_nonopt = optind;
    -
    - /* Now skip any additional non-options
    - and extend the range of non-options previously skipped. */
    -
    - while (optind < argc
    - && (argv[optind][0] != '-' || argv[optind][1] == '\0')
    -#ifdef GETOPT_COMPAT
    - && (longopts == NULL
    - || argv[optind][0] != '+' || argv[optind][1] == '\0')
    -#endif /* GETOPT_COMPAT */
    - )
    - optind++;
    - last_nonopt = optind;
    - }
    -
    - /* Special ARGV-element `--' means premature end of options.
    - Skip it like a null option,
    - then exchange with previous non-options as if it were an option,
    - then skip everything else like a non-option. */
    -
    - if (optind != argc && !strcmp (argv[optind], "--"))
    - {
    - optind++;
    -
    - if (first_nonopt != last_nonopt && last_nonopt != optind)
    - exchange ((char **) argv);
    - else if (first_nonopt == last_nonopt)
    - first_nonopt = optind;
    - last_nonopt = argc;
    -
    - optind = argc;
    - }
    -
    - /* If we have done all the ARGV-elements, stop the scan
    - and back over any non-options that we skipped and permuted. */
    -
    - if (optind == argc)
    - {
    - /* Set the next-arg-index to point at the non-options
    - that we previously skipped, so the caller will digest them. */
    - if (first_nonopt != last_nonopt)
    - optind = first_nonopt;
    - return EOF;
    - }
    -
    - /* If we have come to a non-option and did not permute it,
    - either stop the scan or describe it to the caller and pass it by. */
    -
    - if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
    -#ifdef GETOPT_COMPAT
    - && (longopts == NULL
    - || argv[optind][0] != '+' || argv[optind][1] == '\0')
    -#endif /* GETOPT_COMPAT */
    - )
    - {
    - if (ordering == REQUIRE_ORDER)
    - return EOF;
    - optarg = argv[optind++];
    - return 1;
    - }
    -
    - /* We have found another option-ARGV-element.
    - Start decoding its characters. */
    -
    - nextchar = (argv[optind] + 1
    - + (longopts != NULL && argv[optind][1] == '-'));
    - }
    -
    - if (longopts != NULL
    - && ((argv[optind][0] == '-'
    - && (argv[optind][1] == '-' || long_only))
    -#ifdef GETOPT_COMPAT
    - || argv[optind][0] == '+'
    -#endif /* GETOPT_COMPAT */
    - ))
    - {
    - const struct option *p;
    - char *s = nextchar;
    - int exact = 0;
    - int ambig = 0;
    - const struct option *pfound = NULL;
    - int indfound;
    -
    - while (*s && *s != '=')
    - s++;
    -
    - /* Test all options for either exact match or abbreviated matches. */
    - for (p = longopts, option_index = 0; p->name;
    - p++, option_index++)
    - if (!strncmp (p->name, nextchar, s - nextchar))
    - {
    - if (s - nextchar == strlen (p->name))
    - {
    - /* Exact match found. */
    - pfound = p;
    - indfound = option_index;
    - exact = 1;
    - break;
    - }
    - else if (pfound == NULL)
    - {
    - /* First nonexact match found. */
    - pfound = p;
    - indfound = option_index;
    - }
    - else
    - /* Second nonexact match found. */
    - ambig = 1;
    - }
    -
    - if (ambig && !exact)
    - {
    - if (opterr)
    - fprintf (stderr, "%s: option `%s' is ambiguous\n",
    - argv[0], argv[optind]);
    - nextchar += strlen (nextchar);
    - optind++;
    - return '?';
    - }
    -
    - if (pfound != NULL)
    - {
    - option_index = indfound;
    - optind++;
    - if (*s)
    - {
    - /* Don't test has_arg with >, because some C compilers don't
    - allow it to be used on enums. */
    - if (pfound->has_arg)
    - optarg = s + 1;
    - else
    - {
    - if (opterr)
    - {
    - if (argv[optind - 1][1] == '-')
    - /* --option */
    - fprintf (stderr,
    - "%s: option `--%s' doesn't allow an argument\n",
    - argv[0], pfound->name);
    - else
    - /* +option or -option */
    - fprintf (stderr,
    - "%s: option `%c%s' doesn't allow an argument\n",
    - argv[0], argv[optind - 1][0], pfound->name);
    - }
    - nextchar += strlen (nextchar);
    - return '?';
    - }
    - }
    - else if (pfound->has_arg == 1)
    - {
    - if (optind < argc)
    - optarg = argv[optind++];
    - else
    - {
    - if (opterr)
    - fprintf (stderr, "%s: option `%s' requires an argument\n",
    - argv[0], argv[optind - 1]);
    - nextchar += strlen (nextchar);
    - return optstring[0] == ':' ? ':' : '?';
    - }
    - }
    - nextchar += strlen (nextchar);
    - if (longind != NULL)
    - *longind = option_index;
    - if (pfound->flag)
    - {
    - *(pfound->flag) = pfound->val;
    - return 0;
    - }
    - return pfound->val;
    - }
    - /* Can't find it as a long option. If this is not getopt_long_only,
    - or the option starts with '--' or is not a valid short
    - option, then it's an error.
    - Otherwise interpret it as a short option. */
    - if (!long_only || argv[optind][1] == '-'
    -#ifdef GETOPT_COMPAT
    - || argv[optind][0] == '+'
    -#endif /* GETOPT_COMPAT */
    - || my_index (optstring, *nextchar) == NULL)
    - {
    - if (opterr)
    - {
    - if (argv[optind][1] == '-')
    - /* --option */
    - fprintf (stderr, "%s: unrecognized option `--%s'\n",
    - argv[0], nextchar);
    - else
    - /* +option or -option */
    - fprintf (stderr, "%s: unrecognized option `%c%s'\n",
    - argv[0], argv[optind][0], nextchar);
    - }
    - nextchar = (char *) "";
    - optind++;
    - return '?';
    - }
    - }
    -
    - /* Look at and handle the next option-character. */
    -
    - {
    - char c = *nextchar++;
    - char *temp = my_index (optstring, c);
    -
    - /* Increment `optind' when we start to process its last character. */
    - if (*nextchar == '\0')
    - ++optind;
    -
    - if (temp == NULL || c == ':')
    - {
    - if (opterr)
    - {
    -#if 0
    - if (c < 040 || c >= 0177)
    - fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
    - argv[0], c);
    - else
    - fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
    -#else
    - /* 1003.2 specifies the format of this message. */
    - fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
    -#endif
    - }
    - optopt = c;
    - return '?';
    - }
    - if (temp[1] == ':')
    - {
    - if (temp[2] == ':')
    - {
    - /* This is an option that accepts an argument optionally. */
    - if (*nextchar != '\0')
    - {
    - optarg = nextchar;
    - optind++;
    - }
    - else
    - optarg = NULL;
    - nextchar = NULL;
    - }
    - else
    - {
    - /* This is an option that requires an argument. */
    - if (*nextchar != '\0')
    - {
    - optarg = nextchar;
    - /* If we end this ARGV-element by taking the rest as an arg,
    - we must advance to the next element now. */
    - optind++;
    - }
    - else if (optind == argc)
    - {
    - if (opterr)
    - {
    -#if 0
    - fprintf (stderr, "%s: option `-%c' requires an argument\n",
    - argv[0], c);
    -#else
    - /* 1003.2 specifies the format of this message. */
    - fprintf (stderr, "%s: option requires an argument -- %c\n",
    - argv[0], c);
    -#endif
    - }
    - optopt = c;
    - if (optstring[0] == ':')
    - c = ':';
    - else
    - c = '?';
    - }
    - else
    - /* We already incremented `optind' once;
    - increment it again when taking next ARGV-elt as argument. */
    - optarg = argv[optind++];
    - nextchar = NULL;
    - }
    - }
    - return c;
    - }
    -}
    -
    -int
    -getopt (argc, argv, optstring)
    - int argc;
    - char *const *argv;
    - const char *optstring;
    -{
    - return _getopt_internal (argc, argv, optstring,
    - (const struct option *) 0,
    - (int *) 0,
    - 0);
    -}
    -
    -#endif /* _LIBC or not __GNU_LIBRARY__. */
    -
    -#ifdef TEST
    -
    -/* Compile with -DTEST to make an executable for use in testing
    - the above definition of `getopt'. */
    -
    -int
    -main (argc, argv)
    - int argc;
    - char **argv;
    -{
    - int c;
    - int digit_optind = 0;
    -
    - while (1)
    - {
    - int this_option_optind = optind ? optind : 1;
    -
    - c = getopt (argc, argv, "abc:d:0123456789");
    - if (c == EOF)
    - break;
    -
    - switch (c)
    - {
    - case '0':
    - case '1':
    - case '2':
    - case '3':
    - case '4':
    - case '5':
    - case '6':
    - case '7':
    - case '8':
    - case '9':
    - if (digit_optind != 0 && digit_optind != this_option_optind)
    - printf ("digits occur in two different argv-elements.\n");
    - digit_optind = this_option_optind;
    - printf ("option %c\n", c);
    - break;
    -
    - case 'a':
    - printf ("option a\n");
    - break;
    -
    - case 'b':
    - printf ("option b\n");
    - break;
    -
    - case 'c':
    - printf ("option c with value `%s'\n", optarg);
    - break;
    -
    - case '?':
    - break;
    -
    - default:
    - printf ("?? getopt returned character code 0%o ??\n", c);
    - }
    - }
    -
    - if (optind < argc)
    - {
    - printf ("non-option ARGV-elements: ");
    - while (optind < argc)
    - printf ("%s ", argv[optind++]);
    - printf ("\n");
    - }
    -
    - exit (0);
    -}
    -
    -#endif /* TEST */
    --- a/finch/getopt.h Fri Jul 07 11:50:28 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,136 +0,0 @@
    -/* Declarations for getopt.
    -
    - NOTE: getopt is now part of the C library, so if you don't know what
    - "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
    - before changing it!
    -
    - Finch 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, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
    -
    -#ifndef _GETOPT_H
    -#define _GETOPT_H 1
    -
    -#ifdef __cplusplus
    -extern "C" {
    -#endif
    -
    -/* For communication from `getopt' to the caller.
    - When `getopt' finds an option that takes an argument,
    - the argument value is returned here.
    - Also, when `ordering' is RETURN_IN_ORDER,
    - each non-option ARGV-element is returned here. */
    -
    -extern char *optarg;
    -
    -/* Index in ARGV of the next element to be scanned.
    - This is used for communication to and from the caller
    - and for communication between successive calls to `getopt'.
    -
    - On entry to `getopt', zero means this is the first call; initialize.
    -
    - When `getopt' returns EOF, this is the index of the first of the
    - non-option elements that the caller should itself scan.
    -
    - Otherwise, `optind' communicates from one call to the next
    - how much of ARGV has been scanned so far. */
    -
    -extern int optind;
    -
    -/* Callers store zero here to inhibit the error message `getopt' prints
    - for unrecognized options. */
    -
    -extern int opterr;
    -
    -/* Set to an option character which was unrecognized. */
    -
    -extern int optopt;
    -
    -/* Describe the long-named options requested by the application.
    - The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
    - of `struct option' terminated by an element containing a name which is
    - zero.
    -
    - The field `has_arg' is:
    - no_argument (or 0) if the option does not take an argument,
    - required_argument (or 1) if the option requires an argument,
    - optional_argument (or 2) if the option takes an optional argument.
    -
    - If the field `flag' is not NULL, it points to a variable that is set
    - to the value given in the field `val' when the option is found, but
    - left unchanged if the option is not found.
    -
    - To have a long-named option do something other than set an `int' to
    - a compiled-in constant, such as set a value from `optarg', set the
    - option's `flag' field to zero and its `val' field to a nonzero
    - value (the equivalent single-letter option character, if there is
    - one). For long options that have a zero `flag' field, `getopt'
    - returns the contents of the `val' field. */
    -
    -struct option
    -{
    -#if __STDC__
    - const char *name;
    -#else
    - char *name;
    -#endif
    - /* has_arg can't be an enum because some compilers complain about
    - type mismatches in all the code that assumes it is an int. */
    - int has_arg;
    - int *flag;
    - int val;
    -};
    -
    -/* Names for the values of the `has_arg' field of `struct option'. */
    -
    -#define no_argument 0
    -#define required_argument 1
    -#define optional_argument 2
    -
    -#if __STDC__
    -#if defined(__GNU_LIBRARY__)
    -/* Many other libraries have conflicting prototypes for getopt, with
    - differences in the consts, in stdlib.h. To avoid compilation
    - errors, only prototype getopt for the GNU C library. */
    -extern int getopt (int argc, char *const *argv, const char *shortopts);
    -#else /* not __GNU_LIBRARY__ */
    -extern int getopt ();
    -#endif /* not __GNU_LIBRARY__ */
    -extern int getopt_long (int argc, char *const *argv, const char *shortopts,
    - const struct option *longopts, int *longind);
    -extern int getopt_long_only (int argc, char *const *argv,
    - const char *shortopts,
    - const struct option *longopts, int *longind);
    -
    -/* Internal only. Users should not call this directly. */
    -extern int _getopt_internal (int argc, char *const *argv,
    - const char *shortopts,
    - const struct option *longopts, int *longind,
    - int long_only);
    -#else /* not __STDC__ */
    -extern int getopt ();
    -extern int getopt_long ();
    -extern int getopt_long_only ();
    -
    -extern int _getopt_internal ();
    -#endif /* not __STDC__ */
    -
    -#ifdef __cplusplus
    -}
    -#endif
    -
    -#endif /* _GETOPT_H */
    --- a/finch/getopt1.c Fri Jul 07 11:50:28 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,177 +0,0 @@
    -/* getopt_long and getopt_long_only entry points for GNU getopt.
    - Finch 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, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
    -
    -#ifdef HAVE_CONFIG_H
    -#include "config.h"
    -#endif
    -
    -#include "getopt.h"
    -
    -#if !__STDC__ && !defined(const) && IN_GCC
    -#define const
    -#endif
    -
    -#include <stdio.h>
    -
    -/* Comment out all this code if we are using the GNU C Library, and are not
    - actually compiling the library itself. This code is part of the GNU C
    - Library, but also included in many other GNU distributions. Compiling
    - and linking in this code is a waste when using the GNU C library
    - (especially if it is a shared library). Rather than having every GNU
    - program understand `configure --with-gnu-libc' and omit the object files,
    - it is simpler to just do this in the source for each such file. */
    -
    -#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
    -
    -
    -/* This needs to come after some library #include
    - to get __GNU_LIBRARY__ defined. */
    -#ifdef __GNU_LIBRARY__
    -#include <stdlib.h>
    -#else
    -char *getenv ();
    -#endif
    -
    -#ifndef NULL
    -#define NULL 0
    -#endif
    -
    -int
    -getopt_long (argc, argv, options, long_options, opt_index)
    - int argc;
    - char *const *argv;
    - const char *options;
    - const struct option *long_options;
    - int *opt_index;
    -{
    - return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
    -}
    -
    -/* Like getopt_long, but '-' as well as '--' can indicate a long option.
    - If an option that starts with '-' (not '--') doesn't match a long option,
    - but does match a short option, it is parsed as a short option
    - instead. */
    -
    -int
    -getopt_long_only (argc, argv, options, long_options, opt_index)
    - int argc;
    - char *const *argv;
    - const char *options;
    - const struct option *long_options;
    - int *opt_index;
    -{
    - return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
    -}
    -
    -
    -#endif /* _LIBC or not __GNU_LIBRARY__. */
    -
    -#ifdef TEST
    -
    -#include <stdio.h>
    -
    -int
    -main (argc, argv)
    - int argc;
    - char **argv;
    -{
    - int c;
    - int digit_optind = 0;
    -
    - while (1)
    - {
    - int this_option_optind = optind ? optind : 1;
    - int option_index = 0;
    - static struct option long_options[] =
    - {
    - {"add", 1, 0, 0},
    - {"append", 0, 0, 0},
    - {"delete", 1, 0, 0},
    - {"verbose", 0, 0, 0},
    - {"create", 0, 0, 0},
    - {"file", 1, 0, 0},
    - {0, 0, 0, 0}
    - };
    -
    - c = getopt_long (argc, argv, "abc:d:0123456789",
    - long_options, &option_index);
    - if (c == EOF)
    - break;
    -
    - switch (c)
    - {
    - case 0:
    - printf ("option %s", long_options[option_index].name);
    - if (optarg)
    - printf (" with arg %s", optarg);
    - printf ("\n");
    - break;
    -
    - case '0':
    - case '1':
    - case '2':
    - case '3':
    - case '4':
    - case '5':
    - case '6':
    - case '7':
    - case '8':
    - case '9':
    - if (digit_optind != 0 && digit_optind != this_option_optind)
    - printf ("digits occur in two different argv-elements.\n");
    - digit_optind = this_option_optind;
    - printf ("option %c\n", c);
    - break;
    -
    - case 'a':
    - printf ("option a\n");
    - break;
    -
    - case 'b':
    - printf ("option b\n");
    - break;
    -
    - case 'c':
    - printf ("option c with value `%s'\n", optarg);
    - break;
    -
    - case 'd':
    - printf ("option d with value `%s'\n", optarg);
    - break;
    -
    - case '?':
    - break;
    -
    - default:
    - printf ("?? getopt returned character code 0%o ??\n", c);
    - }
    - }
    -
    - if (optind < argc)
    - {
    - printf ("non-option ARGV-elements: ");
    - while (optind < argc)
    - printf ("%s ", argv[optind++]);
    - printf ("\n");
    - }
    -
    - exit (0);
    -}
    -
    -#endif /* TEST */
    --- a/finch/gntblist.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/finch/gntblist.c Sun Oct 08 20:44:26 2017 +0300
    @@ -338,7 +338,7 @@
    if (fnode == NULL)
    return;
    if (fnode->signed_timer)
    - purple_timeout_remove(fnode->signed_timer);
    + g_source_remove(fnode->signed_timer);
    g_free(fnode);
    purple_blist_node_set_ui_data(node, NULL);
    }
    @@ -816,8 +816,8 @@
    * to turn on 'show empty groups' setting */
    ggblist->new_group = g_list_prepend(ggblist->new_group, grp);
    if (ggblist->new_group_timeout)
    - purple_timeout_remove(ggblist->new_group_timeout);
    - ggblist->new_group_timeout = purple_timeout_add_seconds(SHOW_EMPTY_GROUP_TIMEOUT,
    + g_source_remove(ggblist->new_group_timeout);
    + ggblist->new_group_timeout = g_timeout_add_seconds(SHOW_EMPTY_GROUP_TIMEOUT,
    remove_new_empty_group, NULL);
    /* Select the group */
    @@ -1171,6 +1171,11 @@
    g_signal_connect_swapped(G_OBJECT(menu), "destroy",
    G_CALLBACK(purple_menu_action_free), action);
    + /* Protocol actions */
    + append_proto_menu(menu,
    + purple_account_get_connection(purple_chat_get_account(chat)),
    + (PurpleBlistNode*)chat);
    +
    add_custom_action(menu, _("Edit Settings"), (PurpleCallback)chat_components_edit, chat);
    }
    @@ -1970,13 +1975,13 @@
    }
    if (ggblist->typing)
    - purple_timeout_remove(ggblist->typing);
    + g_source_remove(ggblist->typing);
    remove_peripherals(ggblist);
    if (ggblist->tagged)
    g_list_free(ggblist->tagged);
    if (ggblist->new_group_timeout)
    - purple_timeout_remove(ggblist->new_group_timeout);
    + g_source_remove(ggblist->new_group_timeout);
    if (ggblist->new_group)
    g_list_free(ggblist->new_group);
    @@ -2209,7 +2214,7 @@
    end:
    g_free(escnewmessage);
    if (ggblist->typing)
    - purple_timeout_remove(ggblist->typing);
    + g_source_remove(ggblist->typing);
    ggblist->typing = 0;
    return FALSE;
    }
    @@ -2228,7 +2233,7 @@
    /* Move the focus to the entry box */
    /* XXX: Make sure the selected status can have a message */
    gnt_box_move_focus(GNT_BOX(ggblist->window), 1);
    - ggblist->typing = purple_timeout_add_seconds(TYPING_TIMEOUT_S, (GSourceFunc)remove_typing_cb, NULL);
    + ggblist->typing = g_timeout_add_seconds(TYPING_TIMEOUT_S, (GSourceFunc)remove_typing_cb, NULL);
    }
    else if (now->type == STATUS_SAVED_ALL)
    {
    @@ -2254,7 +2259,7 @@
    return FALSE;
    if (ggblist->typing)
    - purple_timeout_remove(ggblist->typing);
    + g_source_remove(ggblist->typing);
    ggblist->typing = 0;
    if (text[0] == '\r' && text[1] == 0)
    @@ -2264,7 +2269,7 @@
    return TRUE;
    }
    - ggblist->typing = purple_timeout_add_seconds(TYPING_TIMEOUT_S, (GSourceFunc)remove_typing_cb, NULL);
    + ggblist->typing = g_timeout_add_seconds(TYPING_TIMEOUT_S, (GSourceFunc)remove_typing_cb, NULL);
    return FALSE;
    }
    @@ -2506,7 +2511,7 @@
    PurpleBlistNode *node = data;
    FinchBlistNode *fnode = purple_blist_node_get_ui_data(node);
    - purple_timeout_remove(fnode->signed_timer);
    + g_source_remove(fnode->signed_timer);
    fnode->signed_timer = 0;
    if (!ggblist->manager->can_add_node(node)) {
    @@ -2530,10 +2535,10 @@
    return FALSE;
    if (fnode->signed_timer)
    - purple_timeout_remove(fnode->signed_timer);
    + g_source_remove(fnode->signed_timer);
    g_object_ref(node);
    - fnode->signed_timer = purple_timeout_add_seconds(6, (GSourceFunc)buddy_recent_signed_on_off, data);
    + fnode->signed_timer = g_timeout_add_seconds(6, (GSourceFunc)buddy_recent_signed_on_off, data);
    update_node_display(node, ggblist);
    if (purple_blist_node_get_parent(node) && PURPLE_IS_CONTACT(purple_blist_node_get_parent(node)))
    update_node_display(purple_blist_node_get_parent(node), ggblist);
    --- a/finch/gntdebug.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/finch/gntdebug.c Sun Oct 08 20:44:26 2017 +0300
    @@ -41,6 +41,20 @@
    #define PREF_ROOT "/finch/debug"
    +struct _FinchDebugUi
    +{
    + GObject parent;
    +
    + /* Other members, including private data. */
    +};
    +
    +static void finch_debug_ui_finalize(GObject *gobject);
    +static void finch_debug_ui_interface_init(PurpleDebugUiInterface *iface);
    +
    +G_DEFINE_TYPE_WITH_CODE(FinchDebugUi, finch_debug_ui, G_TYPE_OBJECT,
    + G_IMPLEMENT_INTERFACE(PURPLE_TYPE_DEBUG_UI,
    + finch_debug_ui_interface_init));
    +
    static gboolean
    handle_fprintf_stderr_cb(GIOChannel *source, GIOCondition cond, gpointer null)
    {
    @@ -108,8 +122,9 @@
    }
    static void
    -finch_debug_print(PurpleDebugLevel level, const char *category,
    - const char *args)
    +finch_debug_print(PurpleDebugUi *self,
    + PurpleDebugLevel level, const char *category,
    + const char *args)
    {
    if (debug.window && !debug.paused && match_string(category, args))
    {
    @@ -147,26 +162,16 @@
    }
    static gboolean
    -finch_debug_is_enabled(PurpleDebugLevel level, const char *category)
    +finch_debug_is_enabled(PurpleDebugUi *self, PurpleDebugLevel level, const char *category)
    {
    return debug.window && !debug.paused;
    }
    -static PurpleDebugUiOps uiops =
    +static void
    +finch_debug_ui_interface_init(PurpleDebugUiInterface *iface)
    {
    - finch_debug_print,
    - finch_debug_is_enabled,
    -
    - /* padding */
    - NULL,
    - NULL,
    - NULL,
    - NULL
    -};
    -
    -PurpleDebugUiOps *finch_debug_get_ui_ops()
    -{
    - return &uiops;
    + iface->print = finch_debug_print;
    + iface->is_enabled = finch_debug_is_enabled;
    }
    static void
    @@ -371,7 +376,16 @@
    return FALSE;
    }
    -void finch_debug_init()
    +static void
    +finch_debug_ui_class_init(FinchDebugUiClass *klass)
    +{
    + GObjectClass *object_class = G_OBJECT_CLASS(klass);
    +
    + object_class->finalize = finch_debug_ui_finalize;
    +}
    +
    +static void
    +finch_debug_ui_init(FinchDebugUi *self)
    {
    /* Xerox */
    #define REGISTER_G_LOG_HANDLER(name) \
    @@ -405,8 +419,15 @@
    g_timeout_add(0, start_with_debugwin, NULL);
    }
    -void finch_debug_uninit()
    +static void
    +finch_debug_ui_finalize(GObject *gobject)
    {
    handle_fprintf_stderr(TRUE);
    + G_OBJECT_CLASS(finch_debug_ui_parent_class)->finalize(gobject);
    }
    +FinchDebugUi *
    +finch_debug_ui_new(void)
    +{
    + return g_object_new(FINCH_TYPE_DEBUG_UI, NULL);
    +}
    --- a/finch/gntdebug.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/finch/gntdebug.h Sun Oct 08 20:44:26 2017 +0300
    @@ -30,32 +30,39 @@
    #include "debug.h"
    +G_BEGIN_DECLS
    +
    /**********************************************************************
    * GNT Debug API
    **********************************************************************/
    -/**
    - * finch_debug_get_ui_ops:
    - *
    - * Get the ui-functions.
    - *
    - * Returns: The PurpleDebugUiOps structure populated with the appropriate functions.
    - */
    -PurpleDebugUiOps *finch_debug_get_ui_ops(void);
    +#define FINCH_TYPE_DEBUG_UI (finch_debug_ui_get_type())
    +#if GLIB_CHECK_VERSION(2,44,0)
    +G_DECLARE_FINAL_TYPE(FinchDebugUi, finch_debug_ui, FINCH, DEBUG_UI, GObject)
    +#else
    +GType finch_debug_ui_get_type(void);
    +G_GNUC_BEGIN_IGNORE_DEPRECATIONS
    +typedef struct _FinchDebugUi FinchDebugUi;
    +typedef struct { GObjectClass parent_class; } FinchDebugUiClass;
    +static inline FinchDebugUi *
    +FINCH_DEBUG_UI(gpointer ptr)
    +{
    + return G_TYPE_CHECK_INSTANCE_CAST(ptr, finch_debug_ui_get_type(), FinchDebugUi);
    +}
    +static inline gboolean
    +FINCH_IS_DEBUG_UI(gpointer ptr)
    +{
    + return G_TYPE_CHECK_INSTANCE_TYPE(ptr, finch_debug_ui_get_type());
    +}
    +G_GNUC_END_IGNORE_DEPRECATIONS
    +#endif
    /**
    - * finch_debug_init:
    + * finch_debug_ui_new:
    *
    * Perform necessary initializations.
    */
    -void finch_debug_init(void);
    -
    -/**
    - * finch_debug_uninit:
    - *
    - * Perform necessary uninitializations.
    - */
    -void finch_debug_uninit(void);
    +FinchDebugUi *finch_debug_ui_new(void);
    /**
    * finch_debug_window_show:
    @@ -64,4 +71,6 @@
    */
    void finch_debug_window_show(void);
    +G_END_DECLS
    +
    #endif
    --- a/finch/gntlog.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/finch/gntlog.c Sun Oct 08 20:44:26 2017 +0300
    @@ -96,12 +96,14 @@
    return ret;
    }
    -static const char *log_get_date(PurpleLog *log)
    +static gchar *log_get_date(PurpleLog *log)
    {
    - if (log->tm)
    - return purple_date_format_full(log->tm);
    - else
    - return purple_date_format_full(localtime(&log->time));
    + GDateTime *dt;
    + gchar *ret;
    + dt = g_date_time_to_local(log->time);
    + ret = g_date_time_format(dt, "%c");
    + g_date_time_unref(dt);
    + return ret;
    }
    static void search_cb(GntWidget *button, FinchLogViewer *lv)
    @@ -132,11 +134,13 @@
    char *read = purple_log_read((PurpleLog*)logs->data, NULL);
    if (read && *read && purple_strcasestr(read, search_term)) {
    PurpleLog *log = logs->data;
    + gchar *log_date = log_get_date(log);
    gnt_tree_add_row_last(GNT_TREE(lv->tree),
    log,
    - gnt_tree_create_row(GNT_TREE(lv->tree), log_get_date(log)),
    + gnt_tree_create_row(GNT_TREE(lv->tree), log_date),
    NULL);
    + g_free(log_date);
    }
    g_free(read);
    }
    @@ -183,15 +187,17 @@
    return;
    if (log->type != PURPLE_LOG_SYSTEM) {
    + gchar *log_date = log_get_date(log);
    char *title;
    if (log->type == PURPLE_LOG_CHAT)
    title = g_strdup_printf(_("Conversation in %s on %s"),
    - log->name, log_get_date(log));
    + log->name, log_date);
    else
    title = g_strdup_printf(_("Conversation with %s on %s"),
    - log->name, log_get_date(log));
    + log->name, log_date);
    gnt_label_set_text(GNT_LABEL(viewer->label), title);
    + g_free(log_date);
    g_free(title);
    }
    @@ -223,16 +229,18 @@
    /* Logs are made from trees in real life.
    This is a tree made from logs */
    {
    - const char *pmonth;
    - char *month = NULL;
    + gchar *pmonth;
    + gchar *month = NULL;
    char prev_top_month[30] = "";
    GList *logs = lv->logs;
    while (logs != NULL) {
    PurpleLog *log = logs->data;
    + GDateTime *dt;
    + gchar *log_date;
    - pmonth = purple_utf8_strftime(_("%B %Y"),
    - log->tm ? log->tm : localtime(&log->time));
    + dt = g_date_time_to_local(log->time);
    + pmonth = g_date_time_format(dt, _("%B %Y"));
    if (!purple_strequal(pmonth, prev_top_month)) {
    month = g_strdup(pmonth);
    @@ -247,11 +255,15 @@
    }
    /* sub */
    + log_date = g_date_time_format(dt, "%c");
    gnt_tree_add_row_last(GNT_TREE(lv->tree),
    log,
    - gnt_tree_create_row(GNT_TREE(lv->tree), log_get_date(log)),
    + gnt_tree_create_row(GNT_TREE(lv->tree), log_date),
    month);
    + g_free(log_date);
    + g_free(pmonth);
    + g_date_time_unref(dt);
    logs = logs->next;
    }
    }
    --- a/finch/gntsound.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/finch/gntsound.c Sun Oct 08 20:44:26 2017 +0300
    @@ -281,7 +281,7 @@
    if (mute_login_sounds_timeout != 0)
    g_source_remove(mute_login_sounds_timeout);
    mute_login_sounds = TRUE;
    - mute_login_sounds_timeout = purple_timeout_add_seconds(10, unmute_login_sounds_cb, NULL);
    + mute_login_sounds_timeout = g_timeout_add_seconds(10, unmute_login_sounds_cb, NULL);
    }
    static void *
    --- a/finch/gntxfer.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/finch/gntxfer.c Sun Oct 08 20:44:26 2017 +0300
    @@ -55,7 +55,7 @@
    typedef struct
    {
    - time_t last_updated_time;
    + gint64 last_updated_time;
    gboolean in_list;
    char *name;
    @@ -390,7 +390,7 @@
    {
    PurpleGntXferUiData *data;
    char *size_str, *remaining_str;
    - time_t current_time;
    + gint64 current_time;
    char prog_str[5];
    double kb_sent;
    double kbps = 0.0;
    @@ -414,8 +414,8 @@
    if (data->in_list == FALSE || data->notified)
    return;
    - current_time = time(NULL);
    - if (((current_time - data->last_updated_time) == 0) &&
    + current_time = g_get_monotonic_time();
    + if (((current_time - data->last_updated_time) < G_USEC_PER_SEC) &&
    (!purple_xfer_is_completed(xfer))) {
    /* Don't update the window more than once per second */
    return;
    --- a/finch/gntxfer.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/finch/gntxfer.h Sun Oct 08 20:44:26 2017 +0300
    @@ -39,8 +39,6 @@
    * finch_xfer_dialog_new:
    *
    * Creates a new file transfer dialog.
    - *
    - * Returns: The new dialog.
    */
    void finch_xfer_dialog_new(void);
    --- a/finch/libfinch.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/finch/libfinch.c Sun Oct 08 20:44:26 2017 +0300
    @@ -44,17 +44,14 @@
    #include "gntui.h"
    #include "gntidle.h"
    -#define _GNU_SOURCE
    -#include <getopt.h>
    -
    #include "config.h"
    #include "package_revision.h"
    static void
    debug_init(void)
    {
    - finch_debug_init();
    - purple_debug_set_ui_ops(finch_debug_get_ui_ops());
    + FinchDebugUi *ui = finch_debug_ui_new();
    + purple_debug_set_ui(PURPLE_DEBUG_UI(ui));
    }
    static GHashTable *ui_info = NULL;
    @@ -133,46 +130,32 @@
    return &core_ops;
    }
    -/* This is mostly copied from gtkpurple's source tree */
    -static void
    -show_usage(const char *name, gboolean terse)
    -{
    - char *text;
    -
    - if (terse) {
    - text = g_strdup_printf(_("%s. Try `%s -h' for more information.\n"), DISPLAY_VERSION, name);
    - } else {
    - text = g_strdup_printf(_("%s\n"
    - "Usage: %s [OPTION]...\n\n"
    - " -c, --config=DIR use DIR for config files\n"
    - " -d, --debug print debugging messages to stderr\n"
    - " -h, --help display this help and exit\n"
    - " -n, --nologin don't automatically login\n"
    - " -v, --version display the current version and exit\n"), DISPLAY_VERSION, name);
    - }
    -
    - purple_print_utf8_to_console(stdout, text);
    - g_free(text);
    -}
    -
    static int
    init_libpurple(int argc, char **argv)
    {
    char *path;
    - int opt;
    - gboolean opt_help = FALSE;
    gboolean opt_nologin = FALSE;
    gboolean opt_version = FALSE;
    char *opt_config_dir_arg = NULL;
    gboolean debug_enabled = FALSE;
    + GOptionContext *context;
    + gchar **args;
    + GError *error = NULL;
    - struct option long_options[] = {
    - {"config", required_argument, NULL, 'c'},
    - {"debug", no_argument, NULL, 'd'},
    - {"help", no_argument, NULL, 'h'},
    - {"nologin", no_argument, NULL, 'n'},
    - {"version", no_argument, NULL, 'v'},
    - {0, 0, 0, 0}
    + GOptionEntry option_entries[] = {
    + {"config", 'c', 0,
    + G_OPTION_ARG_FILENAME, &opt_config_dir_arg,
    + _("use DIR for config files"), _("DIR")},
    + {"debug", 'd', 0,
    + G_OPTION_ARG_NONE, &debug_enabled,
    + _("print debugging messages to stderr"), NULL},
    + {"nologin", 'n', 0,
    + G_OPTION_ARG_NONE, &opt_nologin,
    + _("don't automatically login"), NULL},
    + {"version", 'v', 0,
    + G_OPTION_ARG_NONE, &opt_version,
    + _("display the current version and exit"), NULL},
    + {NULL}
    };
    #ifdef ENABLE_NLS
    @@ -183,40 +166,27 @@
    setlocale(LC_ALL, "");
    - /* scan command-line options */
    - opterr = 1;
    - while ((opt = getopt_long(argc, argv, "c:dhn::v",
    - long_options, NULL)) != -1) {
    - switch (opt) {
    - case 'c': /* config dir */
    - g_free(opt_config_dir_arg);
    - opt_config_dir_arg = g_strdup(optarg);
    - break;
    - case 'd': /* debug */
    - debug_enabled = TRUE;
    - break;
    - case 'h': /* help */
    - opt_help = TRUE;
    - break;
    - case 'n': /* no autologin */
    - opt_nologin = TRUE;
    - break;
    - case 'v': /* version */
    - opt_version = TRUE;
    - break;
    - case '?': /* show terse help */
    - default:
    - show_usage(argv[0], TRUE);
    - return 0;
    - break;
    - }
    + context = g_option_context_new(NULL);
    + g_option_context_set_summary(context, DISPLAY_VERSION);
    + g_option_context_add_main_entries(context, option_entries, PACKAGE);
    +
    +#ifdef G_OS_WIN32
    + /* Handle Unicode filenames on Windows. See GOptionContext docs. */
    + args = g_win32_get_command_line();
    +#else
    + args = g_strdupv(argv);
    +#endif
    +
    + if (!g_option_context_parse_strv(context, &args, &error)) {
    + g_strfreev(args);
    + g_printerr(_("%s: %s\nTry `%s -h' for more information.\n"),
    + DISPLAY_VERSION, error->message, argv[0]);
    + g_clear_error(&error);
    + return 1;
    }
    - /* show help message */
    - if (opt_help) {
    - show_usage(argv[0], FALSE);
    - return 0;
    - }
    + g_strfreev(args);
    +
    /* show version message */
    if (opt_version) {
    /* Translators may want to transliterate the name.
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/finch/libgnt/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,98 @@
    +libgnt_SOURCES = [
    + 'gntwidget.c',
    + 'gntbindable.c',
    + 'gntbox.c',
    + 'gntbutton.c',
    + 'gntcheckbox.c',
    + 'gntclipboard.c',
    + 'gntcolors.c',
    + 'gntcombobox.c',
    + 'gntentry.c',
    + 'gntfilesel.c',
    + 'gntkeys.c',
    + 'gntlabel.c',
    + 'gntline.c',
    + 'gntmenu.c',
    + 'gntmenuitem.c',
    + 'gntmenuitemcheck.c',
    + 'gntprogressbar.c',
    + 'gntslider.c',
    + 'gntstyle.c',
    + 'gnttextview.c',
    + 'gnttree.c',
    + 'gntutils.c',
    + 'gntwindow.c',
    + 'gntwm.c',
    + 'gntws.c',
    + 'gntmain.c'
    +]
    +
    +libgnt_headers = [
    + 'gntwidget.h',
    + 'gntbindable.h',
    + 'gntbox.h',
    + 'gntbutton.h',
    + 'gntcheckbox.h',
    + 'gntclipboard.h',
    + 'gntcolors.h',
    + 'gntcombobox.h',
    + 'gntentry.h',
    + 'gntfilesel.h',
    + 'gntkeys.h',
    + 'gntlabel.h',
    + 'gntline.h',
    + 'gntmenu.h',
    + 'gntmenuitem.h',
    + 'gntmenuitemcheck.h',
    + 'gntprogressbar.h',
    + 'gntslider.h',
    + 'gntstyle.h',
    + 'gnttextview.h',
    + 'gnttree.h',
    + 'gntutils.h',
    + 'gntwindow.h',
    + 'gntwm.h',
    + 'gntws.h',
    + 'gnt.h'
    +]
    +
    +if enable_consoleui
    +
    +install_headers(libgnt_headers, subdir : 'gnt')
    +
    +if IS_WIN32
    + libgnt_SOURCES += windows.compile_resources('libgnt_winres.rc')
    +endif
    +
    +libgnt_inc = include_directories('.')
    +libgnt = library('gnt',
    + libgnt_SOURCES,
    + include_directories : [toplevel_inc],
    + install : true,
    + version : GNT_LIB_VERSION,
    + dependencies : [ncurses, libxml, glib, gobject, gmodule, python_dep])
    +libgnt_dep = declare_dependency(
    + include_directories : [toplevel_inc, libgnt_inc],
    + link_with : libgnt,
    + dependencies : [ncurses, glib])
    +
    +configure_file(input : 'gnt.pc.in',
    + output : 'gnt.pc',
    + configuration : pkg_conf,
    + install : true,
    + install_dir : get_option('libdir') + '/pkgconfig')
    +
    +if enable_introspection
    + libgnt_gir = gnome.generate_gir(libgnt,
    + sources : libgnt_headers,
    + includes : 'GObject-2.0',
    + namespace : 'Gnt',
    + symbol_prefix : 'gnt',
    + identifier_prefix : 'Gnt',
    + nsversion : '@0@.@1@'.format(gnt_major_version, gnt_minor_version),
    + install : true)
    +endif
    +
    +subdir('wms')
    +
    +endif # enable_consoleui
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/finch/libgnt/wms/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,14 @@
    +plugindir = get_option('libdir') + '/gnt'
    +
    +irssi = library('irssi', 'irssi.c',
    + dependencies : [ncurses, gobject, libgnt_dep],
    + name_prefix : '',
    + install : true, install_dir : plugindir)
    +
    +if PURPLE_AVAILABLE
    + # These custom wms depend on libpurple
    + s = library('s', 's.c',
    + dependencies : [ncurses, gobject, libgnt_dep, libpurple_dep],
    + name_prefix : '',
    + install : true, install_dir : plugindir)
    +endif
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/finch/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,116 @@
    +subdir('libgnt')
    +
    +libfinch_SOURCES = [
    + 'gntaccount.c',
    + 'gntblist.c',
    + 'gntcertmgr.c',
    + 'gntconn.c',
    + 'gntconv.c',
    + 'gntdebug.c',
    + 'gntidle.c',
    + 'gntlog.c',
    + 'gntmedia.c',
    + 'gntmenuutil.c',
    + 'gntnotify.c',
    + 'gntplugin.c',
    + 'gntpounce.c',
    + 'gntprefs.c',
    + 'gntrequest.c',
    + 'gntroomlist.c',
    + 'gntsound.c',
    + 'gntstatus.c',
    + 'gntui.c',
    + 'gntxfer.c',
    + package_revision,
    + 'libfinch.c'
    +]
    +
    +libfinch_headers = [
    + 'gntaccount.h',
    + 'gntblist.h',
    + 'gntcertmgr.h',
    + 'gntconn.h',
    + 'gntconv.h',
    + 'gntdebug.h',
    + 'finch.h',
    + 'gntidle.h',
    + 'gntlog.h',
    + 'gntmedia.h',
    + 'gntmenuutil.h',
    + 'gntnotify.h',
    + 'gntplugin.h',
    + 'gntpounce.h',
    + 'gntprefs.h',
    + 'gntrequest.h',
    + 'gntroomlist.h',
    + 'gntsound.h',
    + 'gntstatus.h',
    + 'gntui.h',
    + 'gntxfer.h'
    +]
    +
    +finch_SOURCES = [
    + 'finch.c'
    +]
    +
    +if IS_WIN32
    +# libfinch_la_LIBADD += \
    +# -lwinmm
    +
    + finch_winres = configure_file(
    + input : 'finch_winres.rc.in',
    + output : 'finch_winres.rc',
    + configuration : version_conf)
    + finch_SOURCES += windows.compile_resources(finch_winres)
    + libfinch_winres = configure_file(
    + input : 'libfinch_winres.rc.in',
    + output : 'libfinch_winres.rc',
    + configuration : version_conf)
    + libfinch_SOURCES += windows.compile_resources(libfinch_winres)
    +endif
    +
    +if enable_consoleui
    + install_headers(libfinch_headers, subdir : 'finch')
    +
    + libfinch_inc = include_directories('.')
    + libfinch = shared_library('finch',
    + libfinch_SOURCES,
    + c_args : '-DSTANDALONE',
    + include_directories : [toplevel_inc],
    + version : PURPLE_LIB_VERSION,
    + dependencies : [libpurple_dep, libgnt_dep, glib],
    + install : true)
    + libfinch_dep = declare_dependency(
    + include_directories : [toplevel_inc, libfinch_inc],
    + link_with : libfinch,
    + dependencies : [libpurple_dep, libgnt_dep, glib])
    +
    + finch = executable('finch',
    + finch_SOURCES,
    + c_args : '-DSTANDALONE',
    + dependencies : [libpurple_dep, libgnt_dep, libfinch_dep],
    + install : true)
    +
    + configure_file(input : 'finch.pc.in',
    + output : 'finch.pc',
    + configuration : pkg_conf,
    + install : true,
    + install_dir : get_option('libdir') + '/pkgconfig')
    +
    + if enable_introspection
    + introspection_sources = libfinch_headers
    +
    + gnome.generate_gir(libfinch,
    + sources : introspection_sources,
    + includes : [libgnt_gir[0], libpurple_gir[0]],
    + namespace : 'Finch',
    + symbol_prefix : 'finch',
    + identifier_prefix : 'Finch',
    + export_packages : 'finch',
    + nsversion : '@0@.@1@'.format(purple_major_version,
    + purple_minor_version),
    + install : true)
    + endif
    +
    + subdir('plugins')
    +endif # enable_consoleui
    --- a/finch/plugins/gntgf.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/finch/plugins/gntgf.c Sun Oct 08 20:44:26 2017 +0300
    @@ -76,7 +76,7 @@
    {
    toasters = g_list_remove(toasters, toast);
    gnt_widget_destroy(toast->window);
    - purple_timeout_remove(toast->timer);
    + g_source_remove(toast->timer);
    g_free(toast);
    }
    @@ -221,7 +221,7 @@
    }
    gnt_widget_draw(window);
    - toast->timer = purple_timeout_add_seconds(4, (GSourceFunc)remove_toaster, toast);
    + toast->timer = g_timeout_add_seconds(4, (GSourceFunc)remove_toaster, toast);
    toasters = g_list_prepend(toasters, toast);
    }
    --- a/finch/plugins/gnthistory.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/finch/plugins/gnthistory.c Sun Oct 08 20:44:26 2017 +0300
    @@ -46,6 +46,8 @@
    GList *logs = NULL;
    const char *alias = name;
    PurpleLogReadFlags flags;
    + GDateTime *dt;
    + char *date;
    char *history;
    char *header;
    PurpleMessageFlags mflag;
    @@ -113,9 +115,11 @@
    mflag = PURPLE_MESSAGE_NO_LOG | PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_DELAYED;
    history = purple_log_read((PurpleLog*)logs->data, &flags);
    - header = g_strdup_printf(_("<b>Conversation with %s on %s:</b><br>"), alias,
    - purple_date_format_full(localtime(&((PurpleLog *)logs->data)->time)));
    + dt = g_date_time_to_local(((PurpleLog *)logs->data)->time);
    + date = g_date_time_format(dt, "%c");
    + header = g_strdup_printf(_("<b>Conversation with %s on %s:</b><br>"), alias, date);
    purple_conversation_write_system_message(c, header, mflag);
    + g_free(date);
    g_free(header);
    if (flags & PURPLE_LOG_READ_NO_NEWLINE)
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/finch/plugins/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,31 @@
    +if PLUGINS
    + gntclipboard = library('gntclipboard', 'gntclipboard.c',
    + dependencies : [x11, libpurple_dep, libfinch_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : FINCH_PLUGINDIR)
    +
    + gntgf = library('gntgf', 'gntgf.c',
    + dependencies : [x11, libpurple_dep, libfinch_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : FINCH_PLUGINDIR)
    +
    + gnthistory = library('gnthistory', 'gnthistory.c',
    + dependencies : [libpurple_dep, libfinch_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : FINCH_PLUGINDIR)
    +
    + gntlastlog = library('gntlastlog', 'lastlog.c',
    + dependencies : [libpurple_dep, libfinch_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : FINCH_PLUGINDIR)
    +
    + gnttinyurl = library('gnttinyurl', 'gnttinyurl.c',
    + dependencies : [libpurple_dep, libfinch_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : FINCH_PLUGINDIR)
    +
    + grouping = library('grouping', 'grouping.c',
    + dependencies : [libpurple_dep, libfinch_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : FINCH_PLUGINDIR)
    +endif # PLUGINS
    --- a/libpurple/Makefile.am Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/Makefile.am Sun Oct 08 20:44:26 2017 +0300
    @@ -265,13 +265,13 @@
    if ENABLE_DBUS
    CLEANFILES += \
    - dbus-bindings.c \
    + dbus-bindings.ch \
    dbus-client-binding.c \
    dbus-client-binding.h \
    - dbus-signals.c \
    - dbus-types.c \
    + dbus-signals.ch \
    + dbus-types.ch \
    dbus-types.h \
    - purple-client-bindings.c \
    + purple-client-bindings.ch \
    purple-client-bindings.h \
    purple.service
    @@ -299,20 +299,20 @@
    $(srcdir)/protocols/irc/irc.c \
    $(srcdir)/protocols/jabber/jabber.c
    -dbus-types.c: dbus-analyze-types.py $(purple_build_coreheaders)
    +dbus-types.ch: dbus-analyze-types.py $(purple_build_coreheaders)
    $(AM_V_GEN) $(PYTHON) $(srcdir)/dbus-analyze-types.py --pattern=PURPLE_DBUS_DEFINE_TYPE\(%s\) -o $@ $(purple_build_coreheaders)
    dbus-types.h: dbus-analyze-types.py $(purple_build_coreheaders)
    $(AM_V_GEN) $(PYTHON) $(srcdir)/dbus-analyze-types.py --pattern=PURPLE_DBUS_DECLARE_TYPE\(%s\) -o $@ $(purple_build_coreheaders)
    -dbus-bindings.c: dbus-analyze-functions.py $(dbus_exported)
    +dbus-bindings.ch: dbus-analyze-functions.py $(dbus_exported)
    $(AM_V_GEN)$(PYTHON) $(srcdir)/dbus-analyze-functions.py -o $@ $(dbus_build_exported)
    -dbus-signals.c: dbus-analyze-signals.py $(dbus_signals)
    +dbus-signals.ch: dbus-analyze-signals.py $(dbus_signals)
    $(AM_V_GEN) $(PYTHON) $(srcdir)/dbus-analyze-signals.py -o $@ $(dbus_signals)
    -dbus-server.$(OBJEXT): dbus-bindings.c dbus-signals.c dbus-types.c dbus-types.h
    -dbus-server.lo: dbus-bindings.c dbus-signals.c dbus-types.c dbus-types.h
    +dbus-server.$(OBJEXT): dbus-bindings.ch dbus-signals.ch dbus-types.ch dbus-types.h
    +dbus-server.lo: dbus-bindings.ch dbus-signals.ch dbus-types.ch dbus-types.h
    # Declare these as dependencies so they're built even if `make distcheck`
    # is run immediately after configuring.
    @@ -326,14 +326,14 @@
    libpurple_client_la_LDFLAGS = -version-info $(PURPLE_LT_VERSION_INFO) -no-undefined
    libpurple_client_la_LIBADD = $(DBUS_LIBS)
    -purple-client-bindings.c: dbus-analyze-functions.py $(dbus_exported)
    +purple-client-bindings.ch: 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 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)
    -$(libpurple_client_la_OBJECTS): purple-client-bindings.h purple-client-bindings.c
    +$(libpurple_client_la_OBJECTS): purple-client-bindings.h purple-client-bindings.ch
    # purple-client-example
    @@ -356,11 +356,11 @@
    BUILT_SOURCES = $(purple_builtheaders) \
    $(purple_builtsources) \
    - dbus-bindings.c \
    - dbus-signals.c \
    - dbus-types.c \
    + dbus-bindings.ch \
    + dbus-signals.ch \
    + dbus-types.ch \
    dbus-types.h \
    - purple-client-bindings.c \
    + purple-client-bindings.ch \
    purple-client-bindings.h
    else
    @@ -434,7 +434,6 @@
    $(GSTINTERFACES_LIBS) \
    $(IDN_LIBS) \
    $(JSON_LIBS) \
    - $(ZLIB_LIBS) \
    $(INTROSPECTION_LIBS) \
    -lm
    @@ -452,7 +451,6 @@
    $(IDN_CFLAGS) \
    $(NETWORKMANAGER_CFLAGS) \
    $(JSON_CFLAGS) \
    - $(ZLIB_CFLAGS) \
    $(INTROSPECTION_CFLAGS)
    -include $(INTROSPECTION_MAKEFILE)
    @@ -492,7 +490,6 @@
    $(IDN_CFLAGS) \
    $(NETWORKMANAGER_CFLAGS) \
    $(JSON_CFLAGS) \
    - $(ZLIB_CFLAGS) \
    $(INTROSPECTION_CFLAGS)
    Purple_3_0_gir_LIBS = $(builddir)/libpurple.la
    --- a/libpurple/account.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/account.c Sun Oct 08 20:44:26 2017 +0300
    @@ -217,7 +217,7 @@
    closure->account = g_object_ref(account);
    closure->succeeded = succeeded;
    - purple_timeout_add(0, purple_account_register_completed_cb, closure);
    + g_timeout_add(0, purple_account_register_completed_cb, closure);
    }
    void
    @@ -1066,7 +1066,7 @@
    g_new0(struct public_alias_closure, 1);
    closure->account = g_object_ref(account);
    closure->failure_cb = failure_cb;
    - purple_timeout_add(0, set_public_alias_unsupported, closure);
    + g_timeout_add(0, set_public_alias_unsupported, closure);
    }
    }
    @@ -1106,7 +1106,7 @@
    g_new0(struct public_alias_closure, 1);
    closure->account = g_object_ref(account);
    closure->failure_cb = failure_cb;
    - purple_timeout_add(0, get_public_alias_unsupported, closure);
    + g_timeout_add(0, get_public_alias_unsupported, closure);
    }
    }
    @@ -2218,13 +2218,20 @@
    if(!priv->system_log && create){
    PurplePresence *presence;
    int login_time;
    + GDateTime *dt;
    presence = purple_account_get_presence(account);
    login_time = purple_presence_get_login_time(presence);
    -
    - priv->system_log = purple_log_new(PURPLE_LOG_SYSTEM,
    - purple_account_get_username(account), account, NULL,
    - (login_time != 0) ? login_time : time(NULL), NULL);
    + if (login_time != 0) {
    + dt = g_date_time_new_from_unix_local(login_time);
    + } else {
    + dt = g_date_time_new_now_local();
    + }
    +
    + priv->system_log = purple_log_new(PURPLE_LOG_SYSTEM,
    + purple_account_get_username(account),
    + account, NULL, dt);
    + g_date_time_unref(dt);
    }
    return priv->system_log;
    --- a/libpurple/account.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/account.h Sun Oct 08 20:44:26 2017 +0300
    @@ -446,7 +446,7 @@
    /**
    * purple_account_set_status_types:
    * @account: The account.
    - * @status_types: The list of status types.
    + * @status_types: (element-type PurpleStatusType): The list of status types.
    *
    * Sets the account's status types.
    */
    @@ -476,7 +476,7 @@
    * @status_id: The ID of the status.
    * @active: Whether @a status_id is to be activated (%TRUE) or
    * deactivated (%FALSE).
    - * @attrs: A list of <type>const char *</type> attribute names followed by
    + * @attrs: (element-type utf8): A list of <type>const char *</type> attribute names followed by
    * <type>const char *</type> attribute values for the status.
    * (For example, one pair might be <literal>"message"</literal>
    * followed by <literal>"hello, talk to me!"</literal>.)
    @@ -946,7 +946,7 @@
    *
    * Returns the account's permit list.
    *
    - * Returns: (transfer none): A list of the permitted users
    + * Returns: (transfer none) (element-type utf8): A list of the permitted users
    */
    GSList *purple_account_privacy_get_permitted(PurpleAccount *account);
    @@ -956,7 +956,7 @@
    *
    * Returns the account's deny list.
    *
    - * Returns: (transfer none): A list of the denied users
    + * Returns: (transfer none) (element-type utf8): A list of the denied users
    */
    GSList *purple_account_privacy_get_denied(PurpleAccount *account);
    @@ -982,7 +982,7 @@
    * PurpleStatus that has its active flag set to "TRUE." There can be
    * only one active PurpleStatus in a PurplePresence.
    *
    - * Returns: The active status.
    + * Returns: (transfer none): The active status.
    */
    PurpleStatus *purple_account_get_active_status(const PurpleAccount *account);
    @@ -993,7 +993,7 @@
    *
    * Returns the account status with the specified ID.
    *
    - * Returns: The status, or %NULL if it was never registered.
    + * Returns: (transfer none): The status, or %NULL if it was never registered.
    */
    PurpleStatus *purple_account_get_status(const PurpleAccount *account,
    const char *status_id);
    @@ -1032,7 +1032,7 @@
    *
    * Returns the account's presence.
    *
    - * Returns: The account's presence.
    + * Returns: (transfer none): The account's presence.
    */
    PurplePresence *purple_account_get_presence(const PurpleAccount *account);
    @@ -1054,7 +1054,7 @@
    *
    * Returns the account's status types.
    *
    - * Returns: (transfer none): The account's status types.
    + * Returns: (transfer none) (element-type PurpleStatusType): The account's status types.
    */
    GList *purple_account_get_status_types(const PurpleAccount *account);
    @@ -1179,7 +1179,7 @@
    /**
    * purple_account_add_buddies:
    * @account: The account.
    - * @buddies: The list of PurpleBlistNodes representing the buddies to add.
    + * @buddies: (element-type PurpleBuddy): The list of PurpleBlistNodes representing the buddies to add.
    * @message: The invite message. This may be ignored by a protocol.
    *
    * Adds a list of buddies to the server-side buddy list.
    @@ -1200,8 +1200,8 @@
    /**
    * purple_account_remove_buddies:
    * @account: The account.
    - * @buddies: The list of buddies to remove.
    - * @groups: The list of groups to remove buddies from. Each node of this
    + * @buddies: (element-type PurpleBuddy): The list of buddies to remove.
    + * @groups: (element-type PurpleGroup): The list of groups to remove buddies from. Each node of this
    * list should match the corresponding node of buddies.
    *
    * Removes a list of buddies from the server-side buddy list.
    --- a/libpurple/accountopt.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/accountopt.h Sun Oct 08 20:44:26 2017 +0300
    @@ -119,7 +119,7 @@
    * purple_account_option_list_new:
    * @text: The text of the option.
    * @pref_name: The account preference name for the option.
    - * @list: The key, value list.
    + * @list: (element-type PurpleKeyValuePair) (transfer full): The key, value list.
    *
    * Creates a new list account option.
    *
    @@ -189,7 +189,7 @@
    /**
    * purple_account_option_string_set_hints:
    * @option: The account option.
    - * @hints: The list of hints, stored as strings.
    + * @hints: (element-type utf8) (transfer full): The list of hints, stored as strings.
    *
    * Sets the hint list for an account option.
    *
    @@ -202,7 +202,8 @@
    /**
    * purple_account_option_set_list:
    * @option: The account option.
    - * @values: The default list value.
    + * @values: (element-type PurpleKeyValuePair) (transfer full): The default list
    + * value.
    *
    * Sets the list values for an account option.
    *
    @@ -318,7 +319,7 @@
    *
    * Returns the list of hints for an account option.
    *
    - * Returns: (transfer none): A list of hints, stored as strings.
    + * Returns: (element-type utf8) (transfer none): A list of hints.
    */
    const GSList * purple_account_option_string_get_hints(const PurpleAccountOption *option);
    @@ -328,10 +329,10 @@
    *
    * Returns the list values for an account option.
    *
    - * Returns: (transfer none): A list of #PurpleKeyValuePair, mapping the human-readable
    - * description of the value to the <type>(const char *)</type> that
    - * should be passed to purple_account_set_string() to set the
    - * option.
    + * Returns: (element-type PurpleKeyValuePair) (transfer none): A list of
    + * #PurpleKeyValuePair, mapping the human-readable description of the
    + * value to the <type>(const char *)</type> that should be passed to
    + * purple_account_set_string() to set the option.
    */
    GList *purple_account_option_get_list(const PurpleAccountOption *option);
    --- a/libpurple/accounts.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/accounts.c Sun Oct 08 20:44:26 2017 +0300
    @@ -86,7 +86,7 @@
    purple_accounts_schedule_save(void)
    {
    if (save_timer == 0)
    - save_timer = purple_timeout_add_seconds(5, save_cb, NULL);
    + save_timer = g_timeout_add_seconds(5, save_cb, NULL);
    }
    static void
    @@ -998,7 +998,7 @@
    gpointer handle = purple_accounts_get_handle();
    if (save_timer != 0)
    {
    - purple_timeout_remove(save_timer);
    + g_source_remove(save_timer);
    save_timer = 0;
    sync_accounts();
    }
    --- a/libpurple/accounts.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/accounts.h Sun Oct 08 20:44:26 2017 +0300
    @@ -146,7 +146,7 @@
    *
    * Returns a list of all accounts.
    *
    - * Returns: (transfer none): A list of all accounts.
    + * Returns: (element-type PurpleAccount) (transfer none): A list of all accounts.
    */
    GList *purple_accounts_get_all(void);
    @@ -155,9 +155,8 @@
    *
    * Returns a list of all enabled accounts
    *
    - * Returns: A list of all enabled accounts. The list is owned
    - * by the caller, and must be g_list_free()d to avoid
    - * leaking the nodes.
    + * Returns: (element-type PurpleAccount) (transfer container): A list of all
    + * enabled accounts.
    */
    GList *purple_accounts_get_all_active(void);
    --- a/libpurple/blistnode.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/blistnode.h Sun Oct 08 20:44:26 2017 +0300
    @@ -289,10 +289,8 @@
    * purple_blist_node_get_extended_menu:
    * @n: The blist node for which to obtain the extended menu items.
    *
    - * Retrieves the extended menu items for a buddy list node.
    - *
    - * Returns: A list of PurpleMenuAction items, as harvested by the
    - * blist-node-extended-menu signal.
    + * Returns: (element-type PurpleMenuAction): The extended menu items for a buddy
    + * list node, as harvested by the blist-node-extended-menu signal.
    */
    GList *purple_blist_node_get_extended_menu(PurpleBlistNode *n);
    --- a/libpurple/buddylist.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/buddylist.c Sun Oct 08 20:44:26 2017 +0300
    @@ -433,7 +433,7 @@
    _purple_blist_schedule_save()
    {
    if (save_timer == 0)
    - save_timer = purple_timeout_add_seconds(5, save_cb, NULL);
    + save_timer = g_timeout_add_seconds(5, save_cb, NULL);
    }
    static void
    @@ -2045,7 +2045,7 @@
    return;
    if (save_timer != 0) {
    - purple_timeout_remove(save_timer);
    + g_source_remove(save_timer);
    save_timer = 0;
    purple_blist_sync();
    }
    --- a/libpurple/buddylist.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/buddylist.h Sun Oct 08 20:44:26 2017 +0300
    @@ -195,8 +195,8 @@
    *
    * See purple_blist_find_buddies().
    *
    - * Returns: A list of every buddy in the list. Caller is responsible for
    - * freeing the list.
    + * Returns: (element-type PurpleBlistNode) (transfer container): A list of every
    + * buddy in the list.
    */
    GSList *purple_blist_get_buddies(void);
    @@ -380,10 +380,8 @@
    *
    * Finds all PurpleBuddy structs given a name and an account
    *
    - * Returns: NULL if the buddy doesn't exist, or a GSList of
    - * PurpleBuddy structs. You must free the GSList using
    - * g_slist_free. Do not free the PurpleBuddy structs that
    - * the list points to.
    + * Returns: (element-type PurpleBuddy) (transfer container): %NULL if the buddy
    + * doesn't exist, or a GSList of PurpleBuddy structs.
    */
    GSList *purple_blist_find_buddies(PurpleAccount *account, const char *name);
    --- a/libpurple/circularbuffer.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/circularbuffer.h Sun Oct 08 20:44:26 2017 +0300
    @@ -78,18 +78,18 @@
    /**
    * purple_circular_buffer_append:
    - * @buf: The PurpleCircularBuffer to which to append the data
    + * @buffer: The PurpleCircularBuffer to which to append the data
    * @src: pointer to the data to copy into the buffer
    * @len: number of bytes to copy into the buffer
    *
    * Append data to the PurpleCircularBuffer. This will grow the internal
    * buffer to fit the added data, if needed.
    */
    -void purple_circular_buffer_append(PurpleCircularBuffer *buf, gconstpointer src, gsize len);
    +void purple_circular_buffer_append(PurpleCircularBuffer *buffer, gconstpointer src, gsize len);
    /**
    * purple_circular_buffer_get_max_read:
    - * @buf: the PurpleCircularBuffer for which to determine the maximum
    + * @buffer: the PurpleCircularBuffer for which to determine the maximum
    * contiguous bytes that can be read.
    *
    * Determine the maximum number of contiguous bytes that can be read from the
    @@ -100,11 +100,11 @@
    *
    * Returns: the number of bytes that can be read from the PurpleCircularBuffer
    */
    -gsize purple_circular_buffer_get_max_read(const PurpleCircularBuffer *buf);
    +gsize purple_circular_buffer_get_max_read(const PurpleCircularBuffer *buffer);
    /**
    * purple_circular_buffer_mark_read:
    - * @buf: The PurpleCircularBuffer to mark bytes read from
    + * @buffer: The PurpleCircularBuffer to mark bytes read from
    * @len: The number of bytes to mark as read
    *
    * Mark the number of bytes that have been read from the buffer.
    @@ -112,7 +112,7 @@
    * Returns: TRUE if we successfully marked the bytes as having been read, FALSE
    * otherwise.
    */
    -gboolean purple_circular_buffer_mark_read(PurpleCircularBuffer *buf, gsize len);
    +gboolean purple_circular_buffer_mark_read(PurpleCircularBuffer *buffer, gsize len);
    /**
    * purple_circular_buffer_grow:
    --- a/libpurple/cmds.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/cmds.h Sun Oct 08 20:44:26 2017 +0300
    @@ -120,25 +120,27 @@
    } PurpleCmdFlag;
    /**
    + * PurpleCommandsUiOps:
    + * @register_command: If implemented, the UI is responsible for handling
    + * commands. See @purple_cmd_register for the argument values.
    + * @unregister_command: Should be implemented if register_command is
    + * implemented. @name and @prpl_id will have the same value
    + * that were used for the register_command call.
    + *
    * Command UI operations; UIs should implement this if they want to handle
    * commands themselves, rather than relying on the core.
    *
    - * @see @ref ui-ops
    + * See <link linkend="chapter-ui-ops">List of <literal>UiOps</literal>
    + * Structures</link>
    */
    -typedef struct
    -{
    - /** If implemented, the UI is responsible for handling commands. */
    - /* @see purple_cmd_register for the argument values. */
    +typedef struct {
    void (*register_command)(const gchar *name, PurpleCmdPriority priority,
    PurpleCmdFlag flags, const gchar *prpl_id,
    const gchar *help, PurpleCmdId id);
    - /** Should be implemented if register_command is implemented.
    - * name and prpl_id will have the same value that were used
    - * for the register_command call.
    - */
    void (*unregister_command)(const gchar *name, const gchar *prpl_id);
    + /*< private >*/
    void (*_purple_reserved1)(void);
    void (*_purple_reserved2)(void);
    void (*_purple_reserved3)(void);
    @@ -246,18 +248,20 @@
    const gchar *markup, gchar **errormsg);
    /**
    + * purple_cmd_execute:
    + * @id: The command to execute.
    + * @conv: The conversation the command was typed in.
    + * @cmdline: The command the user typed (only the arguments).
    + * The caller should remove the prefix and the command name.
    + * It should not contain any formatting, and should be
    + * in plain text (no HTML entities).
    + *
    * Execute a specific command.
    *
    * The UI calls this to execute a command, after parsing the
    * command name.
    *
    - * @param c The command to execute.
    - * @param conv The conversation the command was typed in.
    - * @param cmdline The command the user typed (only the arguments).
    - * The caller should remove the prefix and the command name.
    - * It should not contain any formatting, and should be
    - * in plain text (no HTML entities).
    - * @return TRUE if the command handled the @a cmdline, FALSE otherwise.
    + * Returns: %TRUE if the command handled the @cmdline, %FALSE otherwise.
    */
    gboolean purple_cmd_execute(PurpleCmdId id, PurpleConversation *conv,
    const gchar *cmdline);
    @@ -268,14 +272,11 @@
    *
    * List registered commands.
    *
    - * Returns a #GList (which must be freed by the caller) of all commands
    + * Returns: (element-type utf8) (transfer container): All commands
    * that are valid in the context of @conv, or all commands, if @conv is
    * %NULL. Don't keep this list around past the main loop, or anything else that
    * might unregister a command, as the <type>const char *</type>'s used get freed
    * then.
    - *
    - * Returns: A #GList of <type>const char *</type>, which must be freed with
    - * g_list_free().
    */
    GList *purple_cmd_list(PurpleConversation *conv);
    @@ -287,11 +288,8 @@
    *
    * Get the help string for a command.
    *
    - * Returns the help strings for a given command in the form of a GList,
    - * one node for each matching command.
    - *
    - * Returns: A #GList of <type>const char *</type>s, which is the help string
    - * for that command.
    + * Returns: (element-type utf8) (transfer container): the help strings for a
    + * given command, one node for each matching command.
    */
    GList *purple_cmd_help(PurpleConversation *conv, const gchar *cmd);
    @@ -305,19 +303,22 @@
    gpointer purple_cmds_get_handle(void);
    /**
    + * purple_cmds_set_ui_ops:
    + * @ops: The UI operations structure.
    + *
    * Sets the UI operations structure to be used when registering and
    * unregistering commands. The UI operations need only be set if the
    * UI wants to handle the commands itself; otherwise, leave it as NULL.
    - *
    - * @param ops The UI operations structure.
    */
    void purple_cmds_set_ui_ops(PurpleCommandsUiOps *ops);
    /**
    + * purple_cmds_get_ui_ops:
    + *
    * Returns the UI operations structure to be used when registering and
    * unregistering commands.
    *
    - * @return The UI operations structure.
    + * Returns: (transfer none): The UI operations structure.
    */
    PurpleCommandsUiOps *purple_cmds_get_ui_ops(void);
    --- a/libpurple/connection.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/connection.c Sun Oct 08 20:44:26 2017 +0300
    @@ -146,12 +146,12 @@
    if (on && !priv->keepalive)
    {
    purple_debug_info("connection", "Activating keepalive.\n");
    - priv->keepalive = purple_timeout_add_seconds(KEEPALIVE_INTERVAL, send_keepalive, gc);
    + priv->keepalive = g_timeout_add_seconds(KEEPALIVE_INTERVAL, send_keepalive, gc);
    }
    else if (!on && priv->keepalive > 0)
    {
    purple_debug_info("connection", "Deactivating keepalive.\n");
    - purple_timeout_remove(priv->keepalive);
    + g_source_remove(priv->keepalive);
    priv->keepalive = 0;
    }
    }
    @@ -206,10 +206,11 @@
    {
    char *msg = g_strdup_printf(_("+++ %s signed on"),
    purple_account_get_username(account));
    + GDateTime *dt = g_date_time_new_from_unix_local(purple_presence_get_login_time(presence));
    purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
    - purple_account_get_username(account),
    - purple_presence_get_login_time(presence),
    - msg);
    + purple_account_get_username(account),
    + dt, msg);
    + g_date_time_unref(dt);
    g_free(msg);
    }
    }
    @@ -237,9 +238,11 @@
    {
    char *msg = g_strdup_printf(_("+++ %s signed off"),
    purple_account_get_username(account));
    + GDateTime *dt = g_date_time_new_now_utc();
    purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
    - purple_account_get_username(account), time(NULL),
    - msg);
    + purple_account_get_username(account),
    + dt, msg);
    + g_date_time_unref(dt);
    g_free(msg);
    }
    }
    @@ -504,7 +507,7 @@
    purple_signal_emit(purple_connections_get_handle(), "connection-error",
    gc, reason, description);
    - priv->disconnect_timeout = purple_timeout_add(0, purple_connection_disconnect_cb,
    + priv->disconnect_timeout = g_timeout_add(0, purple_connection_disconnect_cb,
    purple_connection_get_account(gc));
    }
    @@ -868,7 +871,7 @@
    purple_connection_error_info_free(priv->error_info);
    if (priv->disconnect_timeout > 0)
    - purple_timeout_remove(priv->disconnect_timeout);
    + g_source_remove(priv->disconnect_timeout);
    purple_str_wipe(priv->password);
    g_free(priv->display_name);
    --- a/libpurple/connection.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/connection.h Sun Oct 08 20:44:26 2017 +0300
    @@ -435,7 +435,8 @@
    *
    * Returns a list of active chat conversations on a connection.
    *
    - * Returns: The active chats on the connection.
    + * Returns: (element-type PurpleChatConversation) (transfer none): The active
    + * chats on the connection.
    */
    GSList *purple_connection_get_active_chats(const PurpleConnection *gc);
    @@ -598,7 +599,8 @@
    * Returns a list of all active connections. This does not
    * include connections that are in the process of connecting.
    *
    - * Returns: (transfer none): A list of all active connections.
    + * Returns: (element-type PurpleConnection) (transfer none): A list of all
    + * active connections.
    */
    GList *purple_connections_get_all(void);
    @@ -607,7 +609,8 @@
    *
    * Returns a list of all connections in the process of connecting.
    *
    - * Returns: (transfer none): A list of connecting connections.
    + * Returns: (element-type PurpleConnection) (transfer none): A list of
    + * connecting connections.
    */
    GList *purple_connections_get_connecting(void);
    @@ -669,4 +672,4 @@
    G_END_DECLS
    -#endif /* _PURPLE_CONNECTION_H_ */
    \ No newline at end of file
    +#endif /* _PURPLE_CONNECTION_H_ */
    --- a/libpurple/contact.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/contact.h Sun Oct 08 20:44:26 2017 +0300
    @@ -22,7 +22,7 @@
    #ifndef PURPLE_CONTACT_H
    #define PURPLE_CONTACT_H
    /**
    - * SECTION:contact.h
    + * SECTION:contact
    * @section_id: libpurple-contact
    * @short_description: <filename>contact.h</filename>
    * @title: Contact Object
    --- a/libpurple/conversation.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/conversation.c Sun Oct 08 20:44:26 2017 +0300
    @@ -197,12 +197,15 @@
    open_log(PurpleConversation *conv)
    {
    PurpleConversationPrivate *priv = PURPLE_CONVERSATION_GET_PRIVATE(conv);
    + GDateTime *dt;
    g_return_if_fail(priv != NULL);
    + dt = g_date_time_new_now_local();
    priv->logs = g_list_append(NULL, purple_log_new(PURPLE_IS_CHAT_CONVERSATION(conv) ? PURPLE_LOG_CHAT :
    PURPLE_LOG_IM, priv->name, priv->account,
    - conv, time(NULL), NULL));
    + conv, dt));
    + g_date_time_unref(dt);
    }
    /* Functions that deal with PurpleMessage history */
    @@ -611,16 +614,19 @@
    if (!(purple_message_get_flags(pmsg) & PURPLE_MESSAGE_NO_LOG) && purple_conversation_is_logging(conv)) {
    GList *log;
    + GDateTime *dt;
    + dt = g_date_time_new_from_unix_local(purple_message_get_time(pmsg));
    log = priv->logs;
    while (log != NULL) {
    purple_log_write((PurpleLog *)log->data,
    purple_message_get_flags(pmsg),
    purple_message_get_author_alias(pmsg),
    - purple_message_get_time(pmsg),
    + dt,
    purple_message_get_contents(pmsg));
    log = log->next;
    }
    + g_date_time_unref(dt);
    }
    if (ops) {
    --- a/libpurple/conversation.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/conversation.h Sun Oct 08 20:44:26 2017 +0300
    @@ -212,16 +212,16 @@
    * @destroy_conversation: Called just before @conv is freed.
    * @write_chat: Write a message to a chat. If this field is %NULL, libpurple
    * will fall back to using @write_conv.
    - * See purple_conversation_write().
    + * See purple_conversation_write_message().
    * @write_im: Write a message to an IM conversation. If this field is %NULL,
    * libpurple will fall back to using @write_conv.
    - * See purple_conversation_write().
    + * See purple_conversation_write_message().
    * @write_conv: Write a message to a conversation. This is used rather than the
    * chat- or im-specific ops for errors, system messages (such as "x
    * is now know as y"), and as the fallback if @write_im and
    * @write_chat are not implemented. It should be implemented, or
    * the UI will miss conversation error messages and your users will
    - * hate you. See purple_conversation_write().
    + * hate you. See purple_conversation_write_message().
    * @chat_add_users: Add @cbuddies to a chat.
    * <sbr/>@cbuddies: A GList of #PurpleChatUser structs.
    * <sbr/>@new_arrivals: Whether join notices should be shown.
    --- a/libpurple/conversations.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/conversations.h Sun Oct 08 20:44:26 2017 +0300
    @@ -61,7 +61,7 @@
    *
    * This list includes both IMs and chats.
    *
    - * Returns: (transfer none): A GList of all conversations.
    + * Returns: (element-type PurpleConversation) (transfer none): A GList of all conversations.
    */
    GList *purple_conversations_get_all(void);
    @@ -70,7 +70,7 @@
    *
    * Returns a list of all IMs.
    *
    - * Returns: (transfer none): A GList of all IMs.
    + * Returns: (element-type PurpleIMConversation) (transfer none): All IMs.
    */
    GList *purple_conversations_get_ims(void);
    @@ -79,7 +79,7 @@
    *
    * Returns a list of all chats.
    *
    - * Returns: (transfer none): A GList of all chats.
    + * Returns: (element-type PurpleChatConversation) (transfer none): All chats.
    */
    GList *purple_conversations_get_chats(void);
    --- a/libpurple/conversationtypes.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/conversationtypes.c Sun Oct 08 20:44:26 2017 +0300
    @@ -258,7 +258,7 @@
    if (priv->typing_timeout > 0)
    purple_im_conversation_stop_typing_timeout(im);
    - priv->typing_timeout = purple_timeout_add_seconds(timeout, reset_typing_cb, im);
    + priv->typing_timeout = g_timeout_add_seconds(timeout, reset_typing_cb, im);
    }
    void
    @@ -271,7 +271,7 @@
    if (priv->typing_timeout == 0)
    return;
    - purple_timeout_remove(priv->typing_timeout);
    + g_source_remove(priv->typing_timeout);
    priv->typing_timeout = 0;
    }
    @@ -315,7 +315,7 @@
    g_return_if_fail(priv != NULL);
    - priv->send_typed_timeout = purple_timeout_add_seconds(SEND_TYPED_TIMEOUT_SECONDS,
    + priv->send_typed_timeout = g_timeout_add_seconds(SEND_TYPED_TIMEOUT_SECONDS,
    send_typed_cb, im);
    }
    @@ -329,7 +329,7 @@
    if (priv->send_typed_timeout == 0)
    return;
    - purple_timeout_remove(priv->send_typed_timeout);
    + g_source_remove(priv->send_typed_timeout);
    priv->send_typed_timeout = 0;
    }
    --- a/libpurple/core.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/core.h Sun Oct 08 20:44:26 2017 +0300
    @@ -109,13 +109,13 @@
    * purple_core_quit_cb:
    *
    * Calls purple_core_quit(). This can be used as the function
    - * passed to purple_timeout_add() when you want to shutdown Purple
    + * passed to g_timeout_add() when you want to shutdown Purple
    * in a specified amount of time. When shutting down Purple
    * from a plugin, you must use this instead of purple_core_quit();
    * for an immediate exit, use a timeout value of 0:
    *
    * <programlisting>
    - * purple_timeout_add(0, purple_core_quitcb, NULL)
    + * g_timeout_add(0, purple_core_quitcb, NULL)
    * </programlisting>
    *
    * This is ensures that code from your plugin is not being
    --- a/libpurple/data/purple-url-handler.desktop.in.in Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/data/purple-url-handler.desktop.in.in Sun Oct 08 20:44:26 2017 +0300
    @@ -1,7 +1,7 @@
    [Desktop Entry]
    -_Name=Pidgin Internet Messenger
    +_Name=Pidgin
    _GenericName=Internet Messenger
    -_Comment=Chat over IM. Supports AIM, Google Talk, Jabber/XMPP, MSN, Yahoo and more
    +_Comment=Chat over IM. Supports AIM, Google Talk, Jabber/XMPP, and more
    Exec=purple-url-handler %u
    TryExec=purple-url-handler
    Icon=pidgin
    --- a/libpurple/dbus-server.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/dbus-server.c Sun Oct 08 20:44:26 2017 +0300
    @@ -61,7 +61,7 @@
    * #dbus-analyze-types.py script.
    */
    -#include "dbus-types.c"
    +#include "dbus-types.ch"
    /*
    * The following three hashtables map are used to translate between
    @@ -411,8 +411,8 @@
    return purple_dbus_connection;
    }
    -#include "dbus-bindings.c"
    -#include "dbus-signals.c"
    +#include "dbus-bindings.ch"
    +#include "dbus-signals.ch"
    static gboolean
    purple_dbus_dispatch_cb(DBusConnection *connection,
    --- a/libpurple/dbus-server.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/dbus-server.h Sun Oct 08 20:44:26 2017 +0300
    @@ -29,6 +29,8 @@
    * @see_also: <link linkend="chapter-signals-dbus-server">D-Bus Server signals</link>
    */
    +#include <glib.h>
    +
    #include "dbus-purple.h"
    G_BEGIN_DECLS
    --- a/libpurple/debug.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/debug.c Sun Oct 08 20:44:26 2017 +0300
    @@ -23,7 +23,7 @@
    #include "prefs.h"
    #include "util.h"
    -static PurpleDebugUiOps *debug_ui_ops = NULL;
    +static PurpleDebugUi *debug_ui = NULL;
    /*
    * This determines whether debug info should be written to the
    @@ -51,16 +51,22 @@
    purple_debug_vargs(PurpleDebugLevel level, const char *category,
    const char *format, va_list args)
    {
    - PurpleDebugUiOps *ops;
    + PurpleDebugUi *ops;
    + PurpleDebugUiInterface *iface;
    char *arg_s = NULL;
    g_return_if_fail(level != PURPLE_DEBUG_ALL);
    g_return_if_fail(format != NULL);
    - ops = purple_debug_get_ui_ops();
    + ops = purple_debug_get_ui();
    + if (!ops)
    + return;
    + iface = PURPLE_DEBUG_UI_GET_IFACE(ops);
    + if (!iface)
    + return;
    - if (!debug_enabled && ((ops == NULL) || (ops->print == NULL) ||
    - (ops->is_enabled && !ops->is_enabled(level, category))))
    + if (!debug_enabled && ((iface == NULL) || (iface->print == NULL) ||
    + (iface->is_enabled && !iface->is_enabled(ops, level, category))))
    return;
    arg_s = g_strdup_vprintf(format, args);
    @@ -102,8 +108,8 @@
    g_free(ts_s);
    }
    - if (ops != NULL && ops->print != NULL)
    - ops->print(level, category, arg_s);
    + if (iface != NULL && iface->print != NULL)
    + iface->print(ops, level, category, arg_s);
    g_free(arg_s);
    }
    @@ -194,37 +200,10 @@
    return debug_enabled;
    }
    -static PurpleDebugUiOps *
    -purple_debug_ui_ops_copy(PurpleDebugUiOps *ops)
    -{
    - PurpleDebugUiOps *ops_new;
    -
    - g_return_val_if_fail(ops != NULL, NULL);
    -
    - ops_new = g_new(PurpleDebugUiOps, 1);
    - *ops_new = *ops;
    -
    - return ops_new;
    -}
    -
    -GType
    -purple_debug_ui_ops_get_type(void)
    +void
    +purple_debug_set_ui(PurpleDebugUi *ops)
    {
    - static GType type = 0;
    -
    - if (type == 0) {
    - type = g_boxed_type_register_static("PurpleDebugUiOps",
    - (GBoxedCopyFunc)purple_debug_ui_ops_copy,
    - (GBoxedFreeFunc)g_free);
    - }
    -
    - return type;
    -}
    -
    -void
    -purple_debug_set_ui_ops(PurpleDebugUiOps *ops)
    -{
    - debug_ui_ops = ops;
    + g_set_object(&debug_ui, ops);
    }
    gboolean
    @@ -257,10 +236,18 @@
    debug_colored = colored;
    }
    -PurpleDebugUiOps *
    -purple_debug_get_ui_ops(void)
    +PurpleDebugUi *
    +purple_debug_get_ui(void)
    {
    - return debug_ui_ops;
    + return debug_ui;
    +}
    +
    +G_DEFINE_INTERFACE(PurpleDebugUi, purple_debug_ui, G_TYPE_OBJECT);
    +
    +static void
    +purple_debug_ui_default_init(PurpleDebugUiInterface *iface)
    +{
    + /* add properties and signals to the interface here */
    }
    void
    --- a/libpurple/debug.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/debug.h Sun Oct 08 20:44:26 2017 +0300
    @@ -33,9 +33,33 @@
    #include <stdarg.h>
    -#define PURPLE_TYPE_DEBUG_UI_OPS (purple_debug_ui_ops_get_type())
    +G_BEGIN_DECLS
    -typedef struct _PurpleDebugUiOps PurpleDebugUiOps;
    +#define PURPLE_TYPE_DEBUG_UI (purple_debug_ui_get_type())
    +#if GLIB_CHECK_VERSION(2,44,0)
    +G_DECLARE_INTERFACE(PurpleDebugUi, purple_debug_ui, PURPLE, DEBUG_UI, GObject)
    +#else
    +GType purple_debug_ui_get_type(void);
    +G_GNUC_BEGIN_IGNORE_DEPRECATIONS
    +typedef struct _PurpleDebugUi PurpleDebugUi;
    +typedef struct _PurpleDebugUiInterface PurpleDebugUiInterface;
    +static inline PurpleDebugUi *
    +PURPLE_DEBUG_UI(gpointer ptr)
    +{
    + return G_TYPE_CHECK_INSTANCE_CAST(ptr, purple_debug_ui_get_type(), PurpleDebugUi);
    +}
    +static inline gboolean
    +PURPLE_IS_DEBUG_UI(gpointer ptr)
    +{
    + return G_TYPE_CHECK_INSTANCE_TYPE(ptr, purple_debug_ui_get_type());
    +}
    +static inline PurpleDebugUiInterface *
    +PURPLE_DEBUG_UI_GET_IFACE(gpointer ptr)
    +{
    + return G_TYPE_INSTANCE_GET_INTERFACE(ptr, purple_debug_ui_get_type(), PurpleDebugUiInterface);
    +}
    +G_GNUC_END_IGNORE_DEPRECATIONS
    +#endif
    /**
    * PurpleDebugLevel:
    @@ -60,26 +84,28 @@
    } PurpleDebugLevel;
    /**
    - * PurpleDebugUiOps:
    + * PurpleDebugUiInterface:
    *
    * Debug UI operations.
    */
    -struct _PurpleDebugUiOps
    +struct _PurpleDebugUiInterface
    {
    - void (*print)(PurpleDebugLevel level, const char *category,
    - const char *arg_s);
    - gboolean (*is_enabled)(PurpleDebugLevel level,
    - const char *category);
    + GTypeInterface parent_iface;
    +
    + void (*print)(PurpleDebugUi *self,
    + PurpleDebugLevel level, const char *category,
    + const char *arg_s);
    + gboolean (*is_enabled)(PurpleDebugUi *self,
    + PurpleDebugLevel level,
    + const char *category);
    /*< private >*/
    - void (*_purple_reserved1)(void);
    - void (*_purple_reserved2)(void);
    - void (*_purple_reserved3)(void);
    - void (*_purple_reserved4)(void);
    + void (*_purple_reserved1)(PurpleDebugUi *self);
    + void (*_purple_reserved2)(PurpleDebugUi *self);
    + void (*_purple_reserved3)(PurpleDebugUi *self);
    + void (*_purple_reserved4)(PurpleDebugUi *self);
    };
    -G_BEGIN_DECLS
    -
    /**************************************************************************/
    /* Debug API */
    /**************************************************************************/
    @@ -88,6 +114,7 @@
    * @level: The debug level.
    * @category: The category (or %NULL).
    * @format: The format string.
    + * @...: The parameters to insert into the format string.
    *
    * Outputs debug information.
    */
    @@ -98,6 +125,7 @@
    * purple_debug_misc:
    * @category: The category (or %NULL).
    * @format: The format string.
    + * @...: The parameters to insert into the format string.
    *
    * Outputs misc. level debug information.
    *
    @@ -112,6 +140,7 @@
    * purple_debug_info:
    * @category: The category (or %NULL).
    * @format: The format string.
    + * @...: The parameters to insert into the format string.
    *
    * Outputs info level debug information.
    *
    @@ -126,6 +155,7 @@
    * purple_debug_warning:
    * @category: The category (or %NULL).
    * @format: The format string.
    + * @...: The parameters to insert into the format string.
    *
    * Outputs warning level debug information.
    *
    @@ -140,6 +170,7 @@
    * purple_debug_error:
    * @category: The category (or %NULL).
    * @format: The format string.
    + * @...: The parameters to insert into the format string.
    *
    * Outputs error level debug information.
    *
    @@ -154,6 +185,7 @@
    * purple_debug_fatal:
    * @category: The category (or %NULL).
    * @format: The format string.
    + * @...: The parameters to insert into the format string.
    *
    * Outputs fatal error level debug information.
    *
    @@ -236,30 +268,23 @@
    /**************************************************************************/
    /**
    - * purple_debug_ui_ops_get_type:
    - *
    - * Returns: The #GType for the #PurpleDebugUiOps boxed structure.
    - */
    -GType purple_debug_ui_ops_get_type(void);
    -
    -/**
    - * purple_debug_set_ui_ops:
    + * purple_debug_set_ui:
    * @ops: The UI operations structure.
    *
    * Sets the UI operations structure to be used when outputting debug
    * information.
    */
    -void purple_debug_set_ui_ops(PurpleDebugUiOps *ops);
    +void purple_debug_set_ui(PurpleDebugUi *ops);
    /**
    - * purple_debug_get_ui_ops:
    + * purple_debug_get_ui:
    *
    * Returns the UI operations structure used when outputting debug
    * information.
    *
    * Returns: The UI operations structure in use.
    */
    -PurpleDebugUiOps *purple_debug_get_ui_ops(void);
    +PurpleDebugUi *purple_debug_get_ui(void);
    /**************************************************************************/
    /* Debug Subsystem */
    --- a/libpurple/e2ee.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/e2ee.h Sun Oct 08 20:44:26 2017 +0300
    @@ -245,10 +245,8 @@
    * @provider: The E2EE provider.
    * @conv: The conversation.
    *
    - * Returns the list of actions for an E2EE menu.
    - *
    - * Returns: (transfer full): the #GList of #PurpleMenuAction's. Should be
    - * #g_list_free or #g_list_free_full'd when done using it.
    + * Returns: (element-type PurpleMenuAction) (transfer full): The list of
    + * actions for an E2EE menu.
    */
    GList *
    purple_e2ee_provider_get_conv_menu_actions(PurpleE2eeProvider *provider,
    --- a/libpurple/enums.h.in Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/enums.h.in Sun Oct 08 20:44:26 2017 +0300
    @@ -38,7 +38,7 @@
    /*** BEGIN file-production ***/
    -/* enumerations from "@filename@" */
    +/* enumerations from "@basename@" */
    /*** END file-production ***/
    /*** BEGIN value-header ***/
    GType @enum_name@_get_type(void) G_GNUC_CONST;
    --- a/libpurple/eventloop.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/eventloop.c Sun Oct 08 20:44:26 2017 +0300
    @@ -30,24 +30,6 @@
    gpointer data;
    } PurpleIOClosure;
    -guint
    -purple_timeout_add(guint interval, GSourceFunc function, gpointer data)
    -{
    - return g_timeout_add(interval, function, data);
    -}
    -
    -guint
    -purple_timeout_add_seconds(guint interval, GSourceFunc function, gpointer data)
    -{
    - return g_timeout_add_seconds(interval, function, data);
    -}
    -
    -gboolean
    -purple_timeout_remove(guint tag)
    -{
    - return g_source_remove(tag);
    -}
    -
    static gboolean
    purple_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data)
    {
    --- a/libpurple/eventloop.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/eventloop.h Sun Oct 08 20:44:26 2017 +0300
    @@ -62,54 +62,6 @@
    /**************************************************************************/
    /**
    - * purple_timeout_add:
    - * @interval: The time between calls of the function, in milliseconds.
    - * @function: (scope call): The function to call.
    - * @data: data to pass to @function.
    - *
    - * Creates a callback timer.
    - *
    - * The timer will repeat until the function returns %FALSE. The
    - * first call will be at the end of the first interval.
    - *
    - * If the timer is in a multiple of seconds, use purple_timeout_add_seconds()
    - * instead as it allows UIs to group timers for power efficiency.
    - *
    - * Returns: A handle to the timer which can be passed to
    - * purple_timeout_remove() to remove the timer.
    - */
    -guint purple_timeout_add(guint interval, GSourceFunc function, gpointer data);
    -
    -/**
    - * purple_timeout_add_seconds:
    - * @interval: The time between calls of the function, in seconds.
    - * @function: (scope call): The function to call.
    - * @data: data to pass to @function.
    - *
    - * Creates a callback timer.
    - *
    - * The timer will repeat until the function returns %FALSE. The
    - * first call will be at the end of the first interval.
    - *
    - * This function allows UIs to group timers for better power efficiency. For
    - * this reason, @interval may be rounded by up to a second.
    - *
    - * Returns: A handle to the timer which can be passed to
    - * purple_timeout_remove() to remove the timer.
    - */
    -guint purple_timeout_add_seconds(guint interval, GSourceFunc function, gpointer data);
    -
    -/**
    - * purple_timeout_remove:
    - * @handle: The handle, as returned by purple_timeout_add().
    - *
    - * Removes a timeout handler.
    - *
    - * Returns: %TRUE if the handler was successfully removed.
    - */
    -gboolean purple_timeout_remove(guint handle);
    -
    -/**
    * purple_input_add:
    * @fd: The input file descriptor.
    * @cond: The condition type.
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/example/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,3 @@
    +nullclient = executable('nullclient', 'nullclient.c', 'defines.h',
    + c_args : ['-DSTANDALONE'],
    + dependencies : [libpurple_dep, glib])
    --- a/libpurple/group.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/group.h Sun Oct 08 20:44:26 2017 +0300
    @@ -22,9 +22,9 @@
    #ifndef PURPLE_GROUP_H
    #define PURPLE_GROUP_H
    /**
    - * SECTION:blistnodetypes
    - * @section_id: libpurple-blistnodetypes
    - * @short_description: <filename>blistnodetypes.h</filename>
    + * SECTION:group
    + * @section_id: libpurple-group
    + * @short_description: <filename>group.h</filename>
    * @title: Buddy, Chat, Contact and Group node Objects
    */
    @@ -105,8 +105,8 @@
    *
    * Returns a list of accounts that have buddies in this group
    *
    - * Returns: A GSList of accounts (which must be freed), or NULL if the group
    - * has no accounts.
    + * Returns: (element-type PurpleAccount) (transfer container): A list of
    + * accounts, or %NULL if the group has no accounts.
    */
    GSList *purple_group_get_accounts(PurpleGroup *g);
    --- a/libpurple/http.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/http.c Sun Oct 08 20:44:26 2017 +0300
    @@ -29,11 +29,6 @@
    #include "proxy.h"
    #include "purple-gio.h"
    -#include <zlib.h>
    -#ifndef z_const
    -#define z_const
    -#endif
    -
    #define PURPLE_HTTP_URL_CREDENTIALS_CHARS "a-z0-9.,~_/*!&%?=+\\^-"
    #define PURPLE_HTTP_MAX_RECV_BUFFER_LEN 10240
    #define PURPLE_HTTP_MAX_READ_BUFFER_LEN 10240
    @@ -223,7 +218,7 @@
    struct _PurpleHttpGzStream
    {
    gboolean failed;
    - z_stream zs;
    + GZlibDecompressor *decompressor;
    gsize max_output;
    gsize decompressed;
    GString *pending;
    @@ -371,19 +366,14 @@
    purple_http_gz_new(gsize max_output, gboolean is_deflate)
    {
    PurpleHttpGzStream *gzs = g_new0(PurpleHttpGzStream, 1);
    - int windowBits;
    + GZlibCompressorFormat format;
    if (is_deflate)
    - windowBits = -MAX_WBITS;
    + format = G_ZLIB_COMPRESSOR_FORMAT_RAW;
    else /* is gzip */
    - windowBits = MAX_WBITS + 32;
    -
    - if (inflateInit2(&gzs->zs, windowBits) != Z_OK) {
    - purple_debug_error("http", "Cannot initialize zlib stream\n");
    - g_free(gzs);
    - return NULL;
    - }
    -
    + format = G_ZLIB_COMPRESSOR_FORMAT_GZIP;
    +
    + gzs->decompressor = g_zlib_decompressor_new(format);
    gzs->max_output = max_output;
    return gzs;
    @@ -395,7 +385,6 @@
    const gchar *compressed_buff;
    gsize compressed_len;
    GString *ret;
    - z_stream *zs;
    g_return_val_if_fail(gzs != NULL, NULL);
    g_return_val_if_fail(buf != NULL, NULL);
    @@ -403,8 +392,6 @@
    if (gzs->failed)
    return NULL;
    - zs = &gzs->zs;
    -
    if (gzs->pending) {
    g_string_append_len(gzs->pending, buf, len);
    compressed_buff = gzs->pending->str;
    @@ -414,22 +401,26 @@
    compressed_len = len;
    }
    - zs->next_in = (z_const Bytef*)compressed_buff;
    - zs->avail_in = compressed_len;
    -
    ret = g_string_new(NULL);
    - while (zs->avail_in > 0) {
    - int gzres;
    + while (compressed_len > 0) {
    + GConverterResult gzres;
    gchar decompressed_buff[PURPLE_HTTP_GZ_BUFF_LEN];
    - gsize decompressed_len;
    -
    - zs->next_out = (Bytef*)decompressed_buff;
    - zs->avail_out = sizeof(decompressed_buff);
    - decompressed_len = zs->avail_out = sizeof(decompressed_buff);
    - gzres = inflate(zs, Z_FULL_FLUSH);
    - decompressed_len -= zs->avail_out;
    -
    - if (gzres == Z_OK || gzres == Z_STREAM_END) {
    + gsize decompressed_len = 0;
    + gsize bytes_read = 0;
    + GError *error = NULL;
    +
    + gzres = g_converter_convert(G_CONVERTER(gzs->decompressor),
    + compressed_buff, compressed_len,
    + decompressed_buff, sizeof(decompressed_buff),
    + G_CONVERTER_NO_FLAGS,
    + &bytes_read,
    + &decompressed_len,
    + &error);
    +
    + compressed_buff += bytes_read;
    + compressed_len -= bytes_read;
    +
    + if (gzres == G_CONVERTER_CONVERTED || gzres == G_CONVERTER_FINISHED) {
    if (decompressed_len == 0)
    break;
    if (gzs->decompressed + decompressed_len >=
    @@ -439,17 +430,18 @@
    " decompressed data is reached\n");
    decompressed_len = gzs->max_output -
    gzs->decompressed;
    - gzres = Z_STREAM_END;
    + gzres = G_CONVERTER_FINISHED;
    }
    gzs->decompressed += decompressed_len;
    g_string_append_len(ret, decompressed_buff,
    decompressed_len);
    - if (gzres == Z_STREAM_END)
    + if (gzres == G_CONVERTER_FINISHED)
    break;
    } else {
    purple_debug_error("http",
    "Decompression failed (%d): %s\n", gzres,
    - zs->msg);
    + error->message);
    + g_clear_error(&error);
    gzs->failed = TRUE;
    return NULL;
    }
    @@ -460,9 +452,9 @@
    gzs->pending = NULL;
    }
    - if (zs->avail_in > 0) {
    - gzs->pending = g_string_new_len((gchar*)zs->next_in,
    - zs->avail_in);
    + if (compressed_len > 0) {
    + gzs->pending = g_string_new_len(compressed_buff,
    + compressed_len);
    }
    return ret;
    @@ -473,7 +465,7 @@
    {
    if (gzs == NULL)
    return;
    - inflateEnd(&gzs->zs);
    + g_object_unref(gzs->decompressor);
    if (gzs->pending)
    g_string_free(gzs->pending, TRUE);
    g_free(gzs);
    @@ -1782,7 +1774,7 @@
    _purple_http_reconnect(hc);
    - hc->timeout_handle = purple_timeout_add_seconds(request->timeout,
    + hc->timeout_handle = g_timeout_add_seconds(request->timeout,
    purple_http_request_timeout, hc);
    return hc;
    @@ -1822,9 +1814,9 @@
    static void purple_http_connection_free(PurpleHttpConnection *hc)
    {
    if (hc->timeout_handle)
    - purple_timeout_remove(hc->timeout_handle);
    + g_source_remove(hc->timeout_handle);
    if (hc->watcher_delayed_handle)
    - purple_timeout_remove(hc->watcher_delayed_handle);
    + g_source_remove(hc->watcher_delayed_handle);
    if (hc->connection_set != NULL)
    purple_http_connection_set_remove(hc->connection_set, hc);
    @@ -2011,14 +2003,14 @@
    {
    if (hc->watcher_delayed_handle)
    return;
    - hc->watcher_delayed_handle = purple_timeout_add_seconds(
    + hc->watcher_delayed_handle = g_timeout_add_seconds(
    1 + hc->watcher_interval_threshold / 1000000,
    purple_http_conn_notify_progress_watcher_timeout, hc);
    return;
    }
    if (hc->watcher_delayed_handle)
    - purple_timeout_remove(hc->watcher_delayed_handle);
    + g_source_remove(hc->watcher_delayed_handle);
    hc->watcher_delayed_handle = 0;
    hc->watcher_last_call = now;
    @@ -2275,7 +2267,7 @@
    (GDestroyNotify)purple_http_socket_close_free);
    if (host->process_queue_timeout > 0) {
    - purple_timeout_remove(host->process_queue_timeout);
    + g_source_remove(host->process_queue_timeout);
    host->process_queue_timeout = 0;
    }
    @@ -2475,7 +2467,7 @@
    if (host->process_queue_timeout > 0)
    return;
    - host->process_queue_timeout = purple_timeout_add(0,
    + host->process_queue_timeout = g_timeout_add(0,
    _purple_http_keepalive_host_process_queue_cb, host);
    }
    --- a/libpurple/http.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/http.h Sun Oct 08 20:44:26 2017 +0300
    @@ -174,6 +174,7 @@
    * @callback: (scope call): The callback function.
    * @user_data: The user data to pass to the callback function.
    * @format: The format string.
    + * @...: The parameters to insert into the format string.
    *
    * Constructs an URL and fetches the data from it with GET request, then passes
    * it to a callback function.
    @@ -529,6 +530,7 @@
    * purple_http_request_set_url_printf:
    * @request: The request.
    * @format: The format string.
    + * @...: The parameters to insert into the format string.
    *
    * Constructs and sets an URL for HTTP request.
    */
    @@ -756,6 +758,7 @@
    /**
    * purple_http_request_header_add:
    + * @request: The request.
    * @key: A header to be set.
    * @value: A value to set.
    *
    @@ -905,8 +908,8 @@
    *
    * Gets all headers got with response.
    *
    - * Returns: GList of PurpleKeyValuePair, which keys are header field
    - * names (gchar*) and values are its contents (gchar*).
    + * Returns: (element-type PurpleKeyValuePair) (transfer none): Keys are header
    + * field names (gchar*) and values are its contents (gchar*).
    */
    const GList * purple_http_response_get_all_headers(PurpleHttpResponse *response);
    @@ -917,7 +920,7 @@
    *
    * Gets all headers with specified name got with response.
    *
    - * Returns: GList of header field records contents (gchar*).
    + * Returns: (element-type gchar*) (transfer none): Header field record contents.
    */
    const GList * purple_http_response_get_headers_by_name(
    PurpleHttpResponse *response, const gchar *name);
    --- a/libpurple/idle.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/idle.c Sun Oct 08 20:44:26 2017 +0300
    @@ -224,7 +224,7 @@
    {
    /* +1 for the boundary,
    * +1 more for g_timeout_add_seconds rounding. */
    - idle_timer = purple_timeout_add_seconds(time_until_next_idle_event + 2, (GSourceFunc)check_idleness_timer, NULL);
    + idle_timer = g_timeout_add_seconds(time_until_next_idle_event + 2, (GSourceFunc)check_idleness_timer, NULL);
    }
    return FALSE;
    }
    @@ -256,7 +256,7 @@
    idle_reporting_cb(const char *name, PurplePrefType type, gconstpointer val, gpointer data)
    {
    if (idle_timer)
    - purple_timeout_remove(idle_timer);
    + g_source_remove(idle_timer);
    idle_timer = 0;
    check_idleness_timer();
    }
    @@ -268,7 +268,7 @@
    if (!no_away)
    {
    if (idle_timer)
    - purple_timeout_remove(idle_timer);
    + g_source_remove(idle_timer);
    idle_timer = 0;
    check_idleness_timer();
    }
    @@ -332,7 +332,7 @@
    int idle_poll_minutes = purple_prefs_get_int("/purple/away/mins_before_away");
    /* +1 more for g_timeout_add_seconds rounding. */
    - idle_timer = purple_timeout_add_seconds((idle_poll_minutes * 60) + 2, (GSourceFunc)check_idleness_timer, NULL);
    + idle_timer = g_timeout_add_seconds((idle_poll_minutes * 60) + 2, (GSourceFunc)check_idleness_timer, NULL);
    purple_idle_touch();
    @@ -358,7 +358,7 @@
    /* Initialize the idleness asynchronously so it doesn't check idleness,
    * and potentially try to change the status before the UI is initialized */
    - purple_timeout_add(0, _do_purple_idle_touch_cb, NULL);
    + g_timeout_add(0, _do_purple_idle_touch_cb, NULL);
    }
    @@ -370,6 +370,6 @@
    /* Remove the idle timer */
    if (idle_timer > 0)
    - purple_timeout_remove(idle_timer);
    + g_source_remove(idle_timer);
    idle_timer = 0;
    }
    --- a/libpurple/image-store.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/image-store.c Sun Oct 08 20:44:26 2017 +0300
    @@ -124,7 +124,7 @@
    static void
    cancel_temporary(gpointer key, gpointer value, gpointer _unused)
    {
    - purple_timeout_remove(GPOINTER_TO_INT(key));
    + g_source_remove(GPOINTER_TO_INT(key));
    }
    guint
    @@ -143,7 +143,7 @@
    id = image_set_id(image);
    g_object_ref(image);
    - handle = purple_timeout_add_seconds(TEMP_IMAGE_TIMEOUT,
    + handle = g_timeout_add_seconds(TEMP_IMAGE_TIMEOUT,
    remove_temporary, image);
    g_object_set_data(G_OBJECT(image), "purple-image-store-handle",
    GINT_TO_POINTER(handle));
    --- a/libpurple/image.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/image.c Sun Oct 08 20:44:26 2017 +0300
    @@ -41,6 +41,7 @@
    enum {
    PROP_0,
    + PROP_PATH,
    PROP_CONTENTS,
    PROP_SIZE,
    PROP_LAST
    @@ -52,6 +53,15 @@
    * Helpers
    ******************************************************************************/
    static void
    +_purple_image_set_path(PurpleImage *image, const gchar *path) {
    + PurpleImagePrivate *priv = PURPLE_IMAGE_GET_PRIVATE(image);
    +
    + g_free(priv->path);
    +
    + priv->path = g_strdup(path);
    +}
    +
    +static void
    _purple_image_set_contents(PurpleImage *image, GBytes *bytes) {
    PurpleImagePrivate *priv = PURPLE_IMAGE_GET_PRIVATE(image);
    @@ -91,6 +101,9 @@
    PurpleImage *image = PURPLE_IMAGE(obj);
    switch (param_id) {
    + case PROP_PATH:
    + _purple_image_set_path(image, g_value_get_string(value));
    + break;
    case PROP_CONTENTS:
    _purple_image_set_contents(image, g_value_get_boxed(value));
    break;
    @@ -107,6 +120,9 @@
    PurpleImage *image = PURPLE_IMAGE(obj);
    switch (param_id) {
    + case PROP_PATH:
    + g_value_set_string(value, purple_image_get_path(image));
    + break;
    case PROP_CONTENTS:
    g_value_set_boxed(value, purple_image_get_contents(image));
    break;
    @@ -127,6 +143,14 @@
    gobj_class->get_property = purple_image_get_property;
    gobj_class->set_property = purple_image_set_property;
    + properties[PROP_PATH] = g_param_spec_string(
    + "path",
    + "path",
    + "The filepath for the image if one was provided",
    + NULL,
    + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS
    + );
    +
    properties[PROP_CONTENTS] = g_param_spec_boxed(
    "contents",
    "contents",
    @@ -173,7 +197,12 @@
    bytes = g_bytes_new_take(contents, length);
    - image = purple_image_new_from_bytes(bytes);
    + image = g_object_new(
    + PURPLE_TYPE_IMAGE,
    + "contents", bytes,
    + "path", path,
    + NULL
    + );
    g_bytes_unref(bytes);
    @@ -252,7 +281,7 @@
    g_return_val_if_fail(priv != NULL, NULL);
    - return priv->path;
    + return priv->path ? priv->path : purple_image_generate_filename(image);
    }
    gsize
    @@ -347,28 +376,34 @@
    const gchar *
    purple_image_generate_filename(PurpleImage *image) {
    - PurpleImagePrivate *priv = PURPLE_IMAGE_GET_PRIVATE(image);
    + PurpleImagePrivate *priv = NULL;
    gconstpointer data;
    gsize len;
    - const gchar *ext;
    + const gchar *ext = NULL;
    gchar *checksum;
    - g_return_val_if_fail(priv != NULL, NULL);
    + g_return_val_if_fail(PURPLE_IS_IMAGE(image), NULL);
    +
    + priv = PURPLE_IMAGE_GET_PRIVATE(image);
    if (priv->gen_filename)
    return priv->gen_filename;
    - ext = purple_image_get_extension(image);
    + /* grab the image's data and size of that data */
    data = purple_image_get_data(image);
    len = purple_image_get_data_size(image);
    - g_return_val_if_fail(ext != NULL, NULL);
    - g_return_val_if_fail(data != NULL, NULL);
    - g_return_val_if_fail(len > 0, NULL);
    + /* create a checksum of it and use it as the start of our filename */
    + checksum = g_compute_checksum_for_data(G_CHECKSUM_SHA1, data, len);
    - checksum = g_compute_checksum_for_data(G_CHECKSUM_SHA1, data, len);
    - priv->gen_filename = g_strdup_printf("%s.%s", checksum, ext);
    - g_free(checksum);
    + /* if the image has a known format, set the extension appropriately */
    + ext = purple_image_get_extension(image);
    + if(ext != NULL) {
    + priv->gen_filename = g_strdup_printf("%s.%s", checksum, ext);
    + g_free(checksum);
    + } else {
    + priv->gen_filename = checksum;
    + }
    return priv->gen_filename;
    }
    --- a/libpurple/keyring.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/keyring.h Sun Oct 08 20:44:26 2017 +0300
    @@ -154,6 +154,7 @@
    * @account: The account.
    * @mode: A keyring specific option that was stored. Can be NULL.
    * @data: Data that was stored. Can be NULL.
    + * @error: Error that may have occurred.
    *
    * Import serialized (and maybe encrypted) password.
    *
    @@ -277,7 +278,7 @@
    * Returns a GList containing the IDs and names of the registered
    * keyrings.
    *
    - * Returns: The list of IDs and names.
    + * Returns: (element-type utf8) (transfer container): The list of IDs and names.
    */
    GList *
    purple_keyring_get_options(void);
    @@ -292,6 +293,7 @@
    * @keyring_id: The plugin ID that was stored in the xml file. Can be NULL.
    * @mode: A keyring specific option that was stored. Can be NULL.
    * @data: Data that was stored, can be NULL.
    + * @error: Error that may have occurred.
    *
    * Import serialized (and maybe encrypted) password into current keyring.
    *
    --- a/libpurple/log.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/log.c Sun Oct 08 20:44:26 2017 +0300
    @@ -47,7 +47,7 @@
    static void log_get_log_sets_common(GHashTable *sets);
    static gsize html_logger_write(PurpleLog *log, PurpleMessageFlags type,
    - const char *from, time_t time, const char *message);
    + const char *from, GDateTime *time, const char *message);
    static void html_logger_finalize(PurpleLog *log);
    static GList *html_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account);
    static GList *html_logger_list_syslog(PurpleAccount *account);
    @@ -61,9 +61,8 @@
    static void old_logger_get_log_sets(PurpleLogSetCallback cb, GHashTable *sets);
    static void old_logger_finalize(PurpleLog *log);
    -static gsize txt_logger_write(PurpleLog *log,
    - PurpleMessageFlags type,
    - const char *from, time_t time, const char *message);
    +static gsize txt_logger_write(PurpleLog *log, PurpleMessageFlags type,
    + const char *from, GDateTime *time, const char *message);
    static void txt_logger_finalize(PurpleLog *log);
    static GList *txt_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account);
    static GList *txt_logger_list_syslog(PurpleAccount *account);
    @@ -75,7 +74,7 @@
    **************************************************************************/
    PurpleLog *purple_log_new(PurpleLogType type, const char *name, PurpleAccount *account,
    - PurpleConversation *conv, time_t time, const struct tm *tm)
    + PurpleConversation *conv, GDateTime *time)
    {
    PurpleLog *log;
    @@ -87,33 +86,13 @@
    log->name = g_strdup(purple_normalize(account, name));
    log->account = account;
    log->conv = conv;
    - log->time = time;
    + if (time)
    + log->time = g_date_time_ref(time);
    + else
    + log->time = NULL;
    log->logger = purple_log_logger_get();
    log->logger_data = NULL;
    - if (tm == NULL)
    - log->tm = NULL;
    - else
    - {
    - /* There's no need to zero this as we immediately do a direct copy. */
    - log->tm = g_slice_new(struct tm);
    -
    - *(log->tm) = *tm;
    -
    -#ifdef HAVE_STRUCT_TM_TM_ZONE
    - /* XXX: This is so wrong... */
    - if (log->tm->tm_zone != NULL)
    - {
    - char *tmp = g_locale_from_utf8(log->tm->tm_zone, -1, NULL, NULL, NULL);
    - if (tmp != NULL)
    - log->tm->tm_zone = tmp;
    - else
    - /* Just shove the UTF-8 bytes in and hope... */
    - log->tm->tm_zone = g_strdup(log->tm->tm_zone);
    - }
    -#endif
    - }
    -
    if (log->logger && log->logger->create)
    log->logger->create(log);
    return log;
    @@ -125,22 +104,15 @@
    if (log->logger && log->logger->finalize)
    log->logger->finalize(log);
    g_free(log->name);
    -
    - if (log->tm != NULL)
    - {
    -#ifdef HAVE_STRUCT_TM_TM_ZONE
    - /* XXX: This is so wrong... */
    - g_free((char *)log->tm->tm_zone);
    -#endif
    - g_slice_free(struct tm, log->tm);
    - }
    + if (log->time)
    + g_date_time_unref(log->time);
    PURPLE_DBUS_UNREGISTER_POINTER(log);
    g_slice_free(PurpleLog, log);
    }
    void purple_log_write(PurpleLog *log, PurpleMessageFlags type,
    - const char *from, time_t time, const char *message)
    + const char *from, GDateTime *time, const char *message)
    {
    struct _purple_logsize_user *lu;
    gsize written, total = 0;
    @@ -266,8 +238,6 @@
    int score;
    GSList *n;
    struct _purple_logsize_user *lu;
    - time_t now;
    - time(&now);
    lu = g_new(struct _purple_logsize_user, 1);
    lu->name = g_strdup(purple_normalize(account, name));
    @@ -278,6 +248,7 @@
    g_free(lu->name);
    g_free(lu);
    } else {
    + GDateTime *now = g_date_time_new_now_utc();
    double score_double = 0.0;
    for (n = loggers; n; n = n->next) {
    PurpleLogLogger *logger = n->data;
    @@ -294,12 +265,13 @@
    /* Activity score counts bytes in the log, exponentially
    decayed with a half-life of 14 days. */
    score_double += purple_log_get_size(log) *
    - pow(0.5, difftime(now, log->time)/1209600.0);
    + pow(0.5, g_date_time_difference(now, log->time)/(14LL*G_TIME_SPAN_DAY));
    purple_log_free(log);
    logs = g_list_delete_link(logs, logs);
    }
    }
    }
    + g_date_time_unref(now);
    score = (gint) ceil(score_double);
    g_hash_table_replace(logsize_users_decayed, lu, GINT_TO_POINTER(score));
    @@ -394,7 +366,7 @@
    {
    #if 0
    void(*create)(PurpleLog *),
    - gsize(*write)(PurpleLog *, PurpleMessageFlags, const char *, time_t, const char *),
    + gsize(*write)(PurpleLog *, PurpleMessageFlags, const char *, GDateTime *, const char *),
    void(*finalize)(PurpleLog *),
    GList*(*list)(PurpleLogType type, const char*, PurpleAccount*),
    char*(*read)(PurpleLog*, PurpleLogReadFlags*),
    @@ -508,7 +480,8 @@
    const PurpleLog *a = y;
    const PurpleLog *b = z;
    - return b->time - a->time;
    + /* Sort in reverse order. */
    + return g_date_time_compare(b->time, a->time);
    }
    GList *purple_log_get_logs(PurpleLogType type, const char *name, PurpleAccount *account)
    @@ -693,22 +666,10 @@
    purple_log_logger_add(old_logger);
    purple_signal_register(handle, "log-timestamp",
    -#if SIZEOF_TIME_T == 4
    - purple_marshal_POINTER__POINTER_INT_BOOLEAN,
    -#elif SIZEOF_TIME_T == 8
    - purple_marshal_POINTER__POINTER_INT64_BOOLEAN,
    -#else
    -#error Unknown size of time_t
    -#endif
    + purple_marshal_POINTER__POINTER_POINTER_BOOLEAN,
    G_TYPE_STRING, 3,
    PURPLE_TYPE_LOG,
    -#if SIZEOF_TIME_T == 4
    - G_TYPE_INT,
    -#elif SIZEOF_TIME_T == 8
    - G_TYPE_INT64,
    -#else
    -# error Unknown size of time_t
    -#endif
    + G_TYPE_OBJECT,
    G_TYPE_BOOLEAN);
    purple_prefs_connect_callback(NULL, "/purple/logging/format",
    @@ -775,13 +736,15 @@
    * LOGGERS ******************************************************************
    ****************************************************************************/
    -static char *log_get_timestamp(PurpleLog *log, time_t when)
    +static char *log_get_timestamp(PurpleLog *log, GDateTime *when)
    {
    gboolean show_date;
    char *date;
    - struct tm *tm;
    + GDateTime *dt;
    - show_date = (log->type == PURPLE_LOG_SYSTEM) || (time(NULL) > when + 20*60);
    + dt = g_date_time_new_now_utc();
    + show_date = (log->type == PURPLE_LOG_SYSTEM) || (g_date_time_difference(dt, when) > 20L * G_TIME_SPAN_MINUTE);
    + g_date_time_unref(dt);
    date = purple_signal_emit_return_1(purple_log_get_handle(),
    "log-timestamp",
    @@ -789,11 +752,14 @@
    if (date != NULL)
    return date;
    - tm = localtime(&when);
    + dt = g_date_time_to_local(when);
    if (show_date)
    - return g_strdup(purple_date_format_long(tm));
    + date = g_date_time_format(dt, _("%x %X"));
    else
    - return g_strdup(purple_time_format(tm));
    + date = g_date_time_format(dt, "%X");
    + g_date_time_unref(dt);
    +
    + return date;
    }
    /* NOTE: This can return msg (which you may or may not want to g_free())
    @@ -910,9 +876,9 @@
    {
    /* This log is new */
    char *dir;
    - struct tm *tm;
    + GDateTime *dt;
    const char *tz;
    - const char *date;
    + gchar *date;
    char *filename;
    char *path;
    @@ -922,14 +888,16 @@
    purple_build_dir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
    - tm = localtime(&log->time);
    - tz = purple_escape_filename(purple_utf8_strftime("%Z", tm));
    - date = purple_utf8_strftime("%Y-%m-%d.%H%M%S%z", tm);
    + dt = g_date_time_to_local(log->time);
    + tz = purple_escape_filename(g_date_time_get_timezone_abbreviation(dt));
    + date = g_date_time_format(dt, "%Y-%m-%d.%H%M%S%z");
    + g_date_time_unref(dt);
    filename = g_strdup_printf("%s%s%s", date, tz, ext ? ext : "");
    path = g_build_filename(dir, filename, NULL);
    g_free(dir);
    + g_free(date);
    g_free(filename);
    log->logger_data = data = g_slice_new0(PurpleLogCommonLoggerData);
    @@ -979,39 +947,16 @@
    {
    PurpleLog *log;
    PurpleLogCommonLoggerData *data;
    - struct tm tm;
    -#if defined (HAVE_TM_GMTOFF) && defined (HAVE_STRUCT_TM_TM_ZONE)
    - long tz_off;
    - const char *rest, *end;
    - time_t stamp = purple_str_to_time(purple_unescape_filename(filename), FALSE, &tm, &tz_off, &rest);
    -
    - /* As zero is a valid offset, PURPLE_NO_TZ_OFF means no offset was
    - * provided. See util.h. Yes, it's kinda ugly. */
    - if (tz_off != PURPLE_NO_TZ_OFF)
    - tm.tm_gmtoff = tz_off - tm.tm_gmtoff;
    + GDateTime *stamp = purple_str_to_date_time(purple_unescape_filename(filename), FALSE);
    - if (stamp == 0 || rest == NULL || (end = strchr(rest, '.')) == NULL || strchr(rest, ' ') != NULL)
    - {
    - log = purple_log_new(type, name, account, NULL, stamp, NULL);
    - }
    - else
    - {
    - char *tmp = g_strndup(rest, end - rest);
    - tm.tm_zone = tmp;
    - log = purple_log_new(type, name, account, NULL, stamp, &tm);
    - g_free(tmp);
    - }
    -#else
    - time_t stamp = purple_str_to_time(filename, FALSE, &tm, NULL, NULL);
    -
    - log = purple_log_new(type, name, account, NULL, stamp, (stamp != 0) ? &tm : NULL);
    -#endif
    -
    + log = purple_log_new(type, name, account, NULL, stamp);
    log->logger = logger;
    log->logger_data = data = g_slice_new0(PurpleLogCommonLoggerData);
    data->path = g_build_filename(path, filename, NULL);
    list = g_list_prepend(list, log);
    +
    + g_date_time_unref(stamp);
    }
    }
    g_dir_close(dir);
    @@ -1289,7 +1234,7 @@
    ****************************/
    static gsize html_logger_write(PurpleLog *log, PurpleMessageFlags type,
    - const char *from, time_t time, const char *message)
    + const char *from, GDateTime *time, const char *message)
    {
    char *msg_fixed;
    char *image_corrected_msg;
    @@ -1303,7 +1248,8 @@
    if(!data) {
    const char *proto = purple_protocol_class_list_icon(protocol, log->account, NULL);
    - const char *date;
    + GDateTime *dt;
    + gchar *date;
    purple_log_common_writer(log, ".html");
    data = log->logger_data;
    @@ -1312,7 +1258,9 @@
    if(!data->file)
    return 0;
    - date = purple_date_format_full(localtime(&log->time));
    + dt = g_date_time_to_local(log->time);
    + date = g_date_time_format(dt, "%c");
    + g_date_time_unref(dt);
    written += fprintf(data->file, "<html><head>");
    written += fprintf(data->file, "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">");
    @@ -1327,6 +1275,7 @@
    written += fprintf(data->file, "%s", header);
    written += fprintf(data->file, "</title></head><body>");
    written += fprintf(data->file, "<h3>%s</h3>\n", header);
    + g_free(date);
    g_free(header);
    }
    @@ -1444,9 +1393,8 @@
    ** PLAIN TEXT LOGGER *******
    ****************************/
    -static gsize txt_logger_write(PurpleLog *log,
    - PurpleMessageFlags type,
    - const char *from, time_t time, const char *message)
    +static gsize txt_logger_write(PurpleLog *log, PurpleMessageFlags type,
    + const char *from, GDateTime *time, const char *message)
    {
    char *date;
    PurpleProtocol *protocol =
    @@ -1462,6 +1410,8 @@
    * that you open a convo with someone, but don't say anything.
    */
    const char *proto = purple_protocol_class_list_icon(protocol, log->account, NULL);
    + GDateTime *dt;
    + gchar *date;
    purple_log_common_writer(log, ".txt");
    data = log->logger_data;
    @@ -1470,14 +1420,18 @@
    if(!data || !data->file)
    return 0;
    + dt = g_date_time_to_local(log->time);
    + date = g_date_time_format(dt, "%c");
    if (log->type == PURPLE_LOG_SYSTEM)
    written += fprintf(data->file, "System log for account %s (%s) connected at %s\n",
    purple_account_get_username(log->account), proto,
    - purple_date_format_full(localtime(&log->time)));
    + date);
    else
    written += fprintf(data->file, "Conversation with %s at %s on %s (%s)\n",
    - log->name, purple_date_format_full(localtime(&log->time)),
    + log->name, date,
    purple_account_get_username(log->account), proto);
    + g_free(date);
    + g_date_time_unref(dt);
    }
    /* if we can't write to the file, give up before we hurt ourselves */
    @@ -1594,13 +1548,13 @@
    int file_fd, index_fd;
    char *index_tmp;
    char buf[BUF_LONG];
    - struct tm tm;
    - char month[4];
    + gint year, month, day, hour, minute, second;
    + char month_str[4];
    struct old_logger_data *data = NULL;
    int logfound = 0;
    int lastoff = 0;
    int newlen;
    - time_t lasttime = 0;
    + GDateTime *lasttime = NULL;
    PurpleLog *log = NULL;
    GList *list = NULL;
    @@ -1657,9 +1611,9 @@
    unsigned long idx_time;
    if (sscanf(buf, "%d\t%d\t%lu", &lastoff, &newlen, &idx_time) == 3)
    {
    - log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, -1, NULL);
    + log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, NULL);
    log->logger = old_logger;
    - log->time = (time_t)idx_time;
    + log->time = g_date_time_new_from_unix_local(idx_time);
    /* IMPORTANT: Always set all members of struct old_logger_data */
    data = g_slice_new(struct old_logger_data);
    @@ -1734,9 +1688,8 @@
    newlen--;
    if (newlen != 0) {
    - log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, -1, NULL);
    + log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, lasttime);
    log->logger = old_logger;
    - log->time = lasttime;
    /* IMPORTANT: Always set all members of struct old_logger_data */
    data = g_slice_new(struct old_logger_data);
    @@ -1757,49 +1710,49 @@
    lastoff = offset;
    g_snprintf(convostart, length, "%s", temp);
    - memset(&tm, 0, sizeof(tm));
    - if (sscanf(convostart, "%*s %3s %d %d:%d:%d %d", month,
    - &tm.tm_mday, &tm.tm_hour, &tm.tm_min,
    - &tm.tm_sec, &tm.tm_year) != 6)
    + year = month = day = hour = minute = second = 0;
    + if (sscanf(convostart, "%*s %3s %d %d:%d:%d %d", month_str,
    + &day, &hour, &minute, &second, &year) != 6)
    {
    purple_debug_warning("log", "invalid date format\n");
    }
    /* Ugly hack, in case current locale is not English */
    - if (purple_strequal(month, "Jan")) {
    - tm.tm_mon= 0;
    - } else if (purple_strequal(month, "Feb")) {
    - tm.tm_mon = 1;
    - } else if (purple_strequal(month, "Mar")) {
    - tm.tm_mon = 2;
    - } else if (purple_strequal(month, "Apr")) {
    - tm.tm_mon = 3;
    - } else if (purple_strequal(month, "May")) {
    - tm.tm_mon = 4;
    - } else if (purple_strequal(month, "Jun")) {
    - tm.tm_mon = 5;
    - } else if (purple_strequal(month, "Jul")) {
    - tm.tm_mon = 6;
    - } else if (purple_strequal(month, "Aug")) {
    - tm.tm_mon = 7;
    - } else if (purple_strequal(month, "Sep")) {
    - tm.tm_mon = 8;
    - } else if (purple_strequal(month, "Oct")) {
    - tm.tm_mon = 9;
    - } else if (purple_strequal(month, "Nov")) {
    - tm.tm_mon = 10;
    - } else if (purple_strequal(month, "Dec")) {
    - tm.tm_mon = 11;
    + if (purple_strequal(month_str, "Jan")) {
    + month = 1;
    + } else if (purple_strequal(month_str, "Feb")) {
    + month = 2;
    + } else if (purple_strequal(month_str, "Mar")) {
    + month = 3;
    + } else if (purple_strequal(month_str, "Apr")) {
    + month = 4;
    + } else if (purple_strequal(month_str, "May")) {
    + month = 5;
    + } else if (purple_strequal(month_str, "Jun")) {
    + month = 6;
    + } else if (purple_strequal(month_str, "Jul")) {
    + month = 7;
    + } else if (purple_strequal(month_str, "Aug")) {
    + month = 8;
    + } else if (purple_strequal(month_str, "Sep")) {
    + month = 9;
    + } else if (purple_strequal(month_str, "Oct")) {
    + month = 10;
    + } else if (purple_strequal(month_str, "Nov")) {
    + month = 11;
    + } else if (purple_strequal(month_str, "Dec")) {
    + month = 12;
    }
    - tm.tm_year -= 1900;
    - lasttime = mktime(&tm);
    + if (lasttime)
    + g_date_time_unref(lasttime);
    + lasttime = g_date_time_new_local(year, month, day,
    + hour, minute, second);
    }
    }
    if (logfound) {
    if ((newlen = ftell(file) - lastoff) != 0) {
    - log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, -1, NULL);
    + log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, lasttime);
    log->logger = old_logger;
    - log->time = lasttime;
    /* IMPORTANT: Always set all members of struct old_logger_data */
    data = g_slice_new(struct old_logger_data);
    @@ -1816,6 +1769,8 @@
    }
    }
    + if (lasttime)
    + g_date_time_unref(lasttime);
    purple_stringref_unref(pathref);
    fclose(file);
    if (index != NULL)
    --- a/libpurple/log.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/log.h Sun Oct 08 20:44:26 2017 +0300
    @@ -101,7 +101,7 @@
    gsize (*write)(PurpleLog *log,
    PurpleMessageFlags type,
    const char *from,
    - time_t time,
    + GDateTime *time,
    const char *message);
    void (*finalize)(PurpleLog *log);
    @@ -139,10 +139,6 @@
    * timezone
    * @logger: The logging mechanism this log is to use
    * @logger_data: Data used by the log logger
    - * @tm: The time this conversation started, saved with original
    - * timezone data, if available and if struct tm has the BSD
    - * timezone fields, else %NULL. Do NOT modify anything in this
    - * struct.
    *
    * A log. Not the wooden type.
    */
    @@ -151,11 +147,10 @@
    char *name;
    PurpleAccount *account;
    PurpleConversation *conv;
    - time_t time;
    + GDateTime *time;
    PurpleLogLogger *logger;
    void *logger_data;
    - struct tm *tm;
    /* IMPORTANT: Some code in log.c allocates these without zeroing them.
    * IMPORTANT: Update that code if you add members here. */
    @@ -225,15 +220,13 @@
    * @account: The account the conversation is occurring on
    * @conv: The conversation being logged
    * @time: The time this conversation started
    - * @tm: The time this conversation started, with timezone data,
    - * if available and if struct tm has the BSD timezone fields.
    *
    * Creates a new log
    *
    * Returns: The new log
    */
    PurpleLog *purple_log_new(PurpleLogType type, const char *name, PurpleAccount *account,
    - PurpleConversation *conv, time_t time, const struct tm *tm);
    + PurpleConversation *conv, GDateTime *time);
    /**
    * purple_log_free:
    @@ -257,7 +250,7 @@
    void purple_log_write(PurpleLog *log,
    PurpleMessageFlags type,
    const char *from,
    - time_t time,
    + GDateTime *time,
    const char *message);
    /**
    @@ -279,7 +272,7 @@
    *
    * Returns a list of all available logs
    *
    - * Returns: A sorted list of PurpleLogs
    + * Returns: (element-type PurpleLog): A sorted list of logs
    */
    GList *purple_log_get_logs(PurpleLogType type, const char *name, PurpleAccount *account);
    @@ -299,7 +292,8 @@
    * destroyed. If a PurpleLogSet is removed from the GHashTable, it
    * must be freed with purple_log_set_free().
    *
    - * Returns: A GHashTable of all available unique PurpleLogSets
    + * Returns: (element-type PurpleLogSet PurpleLogSet): All available unique log
    + * sets.
    */
    GHashTable *purple_log_get_log_sets(void);
    @@ -309,7 +303,7 @@
    *
    * Returns a list of all available system logs
    *
    - * Returns: A sorted list of PurpleLogs
    + * Returns: (element-type PurpleLog): A sorted list of logs
    */
    GList *purple_log_get_system_logs(PurpleAccount *account);
    @@ -447,7 +441,7 @@
    * @ext: The file extension this log format uses.
    * @logger: A reference to the logger struct for this log.
    *
    - * Returns a sorted GList of PurpleLogs of the requested type.
    + * Returns a sorted list of logs of the requested type.
    *
    * This function should only be used with logs that are written
    * with purple_log_common_writer(). It's intended to be used as
    @@ -455,7 +449,7 @@
    * It should only be passed to purple_log_logger_new() and never
    * called directly.
    *
    - * Returns: A sorted GList of PurpleLogs matching the parameters.
    + * Returns: (element-type PurpleLog): A sorted list of logs matching the parameters.
    */
    GList *purple_log_common_lister(PurpleLogType type, const char *name,
    PurpleAccount *account, const char *ext,
    @@ -611,7 +605,7 @@
    * Returns a GList containing the IDs and names of the registered
    * loggers.
    *
    - * Returns: The list of IDs and names.
    + * Returns: (element-type utf8) (transfer container): The list of IDs and names.
    */
    GList *purple_log_logger_get_options(void);
    --- a/libpurple/media-gst.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/media-gst.h Sun Oct 08 20:44:26 2017 +0300
    @@ -145,7 +145,7 @@
    *
    * Gets the pipeline from the media manager.
    *
    - * Returns: The pipeline.
    + * Returns: (transfer none): The pipeline.
    */
    GstElement *purple_media_manager_get_pipeline(PurpleMediaManager *manager);
    @@ -157,7 +157,7 @@
    * @session_id: The id of the session this element is requested for or NULL.
    * @participant: The remote user this element is requested for or NULL.
    *
    - * Returns: A GStreamer source or sink for audio or video.
    + * Returns: (transfer full): A GStreamer source or sink for audio or video.
    */
    GstElement *purple_media_manager_get_element(PurpleMediaManager *manager,
    PurpleMediaSessionType type, PurpleMedia *media,
    @@ -168,20 +168,36 @@
    * @manager: The media manager to use to obtain the element infos.
    * @type: The type of element infos to get.
    *
    - * Returns: A #GList of registered #PurpleMediaElementInfo instances that match
    + * Returns: (transfer container) (element-type PurpleMediaElementInfo): A #GList of registered #PurpleMediaElementInfo instances that match
    * @type.
    */
    GList *purple_media_manager_enumerate_elements(PurpleMediaManager *manager,
    PurpleMediaElementType type);
    +/**
    + * purple_media_manager_get_element_info:
    + * @manager: The #PurpleMediaManager instance
    + * @name: The name of the element to get.
    + *
    + * Returns: (transfer full): The #PurpleMediaElementInfo for @name or NULL.
    + */
    PurpleMediaElementInfo *purple_media_manager_get_element_info(
    PurpleMediaManager *manager, const gchar *name);
    +
    gboolean purple_media_manager_register_element(PurpleMediaManager *manager,
    PurpleMediaElementInfo *info);
    gboolean purple_media_manager_unregister_element(PurpleMediaManager *manager,
    const gchar *name);
    gboolean purple_media_manager_set_active_element(PurpleMediaManager *manager,
    PurpleMediaElementInfo *info);
    +
    +/**
    + * purple_media_manager_get_active_element:
    + * @manager: The #PurpleMediaManager instance
    + * @type: The #PurpleMediaElementType who's info to get
    + *
    + * Returns: (transfer none): The #PurpleMediaElementInfo for @type.
    + */
    PurpleMediaElementInfo *purple_media_manager_get_active_element(
    PurpleMediaManager *manager, PurpleMediaElementType type);
    @@ -212,6 +228,16 @@
    gchar *purple_media_element_info_get_name(PurpleMediaElementInfo *info);
    PurpleMediaElementType purple_media_element_info_get_element_type(
    PurpleMediaElementInfo *info);
    +
    +/**
    + * purple_media_element_info_call_create:
    + * @info: The #PurpleMediaElementInfo to create the element from
    + * @media:
    + * @session_id:
    + * @participant:
    + *
    + * Returns: (transfer full): The new GstElement.
    + */
    GstElement *purple_media_element_info_call_create(
    PurpleMediaElementInfo *info, PurpleMedia *media,
    const gchar *session_id, const gchar *participant);
    --- a/libpurple/media.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/media.h Sun Oct 08 20:44:26 2017 +0300
    @@ -100,7 +100,7 @@
    *
    * Gets a list of session IDs.
    *
    - * Returns: GList of session IDs. The caller must free the list.
    + * Returns: (element-type utf8) (transfer container): List of session IDs.
    */
    GList *purple_media_get_session_ids(PurpleMedia *media);
    @@ -262,7 +262,7 @@
    *
    * Gets the codecs from a session.
    *
    - * Returns: The retreieved codecs.
    + * Returns: (element-type PurpleMediaCodec): The retrieved codecs.
    */
    GList *purple_media_get_codecs(PurpleMedia *media, const gchar *sess_id);
    @@ -271,7 +271,8 @@
    * @media: The media object to find the session in.
    * @sess_id: The session id of the session find the stream in.
    * @participant: The name of the remote user to add the candidates for.
    - * @remote_candidates: The remote candidates to add.
    + * @remote_candidates: (element-type PurpleMediaCandidate) (transfer none): The
    + * remote candidates to add.
    *
    * Adds remote candidates to the stream.
    */
    @@ -287,6 +288,8 @@
    * @participant: The name of the remote user to get the candidates from.
    *
    * Gets the local candidates from a stream.
    + *
    + * Returns: (element-type PurpleMediaCandidate): The local candidates.
    */
    GList *purple_media_get_local_candidates(PurpleMedia *media,
    const gchar *sess_id,
    @@ -301,7 +304,8 @@
    *
    * Gets the active local candidates for the stream.
    *
    - * Returns: The active candidates retrieved.
    + * Returns: (element-type PurpleMediaCandidate): The active
    + * candidates retrieved.
    */
    GList *purple_media_get_active_local_candidates(PurpleMedia *media,
    const gchar *sess_id, const gchar *participant);
    @@ -315,7 +319,8 @@
    *
    * Gets the active remote candidates for the stream.
    *
    - * Returns: The remote candidates retrieved.
    + * Returns: (element-type PurpleMediaCandidate): The remote
    + * candidates retrieved.
    */
    GList *purple_media_get_active_remote_candidates(PurpleMedia *media,
    const gchar *sess_id, const gchar *participant);
    @@ -325,7 +330,8 @@
    * @media: The media object to find the session in.
    * @sess_id: The session id of the session find the stream in.
    * @participant: The name of the remote user to set the codecs for.
    - * @codecs: The list of remote codecs to set.
    + * @codecs: (element-type PurpleMediaCodec) (transfer none): The list of remote
    + * codecs to set.
    *
    * Sets remote codecs from the stream.
    *
    --- a/libpurple/media/backend-fs2.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/media/backend-fs2.c Sun Oct 08 20:44:26 2017 +0300
    @@ -1888,7 +1888,7 @@
    gst_pad_link(srcpad, sinkpad);
    gst_object_unref(sinkpad);
    - stream->connected_cb_id = purple_timeout_add(0,
    + stream->connected_cb_id = g_timeout_add(0,
    (GSourceFunc)src_pad_added_cb_cb, stream);
    }
    @@ -2071,7 +2071,7 @@
    {
    /* Remove the connected_cb timeout */
    if (stream->connected_cb_id != 0)
    - purple_timeout_remove(stream->connected_cb_id);
    + g_source_remove(stream->connected_cb_id);
    g_free(stream->participant);
    @@ -2558,7 +2558,7 @@
    if (duration <= 50) {
    fs_session_stop_telephony_event(session->session);
    } else {
    - purple_timeout_add(duration, send_dtmf_callback,
    + g_timeout_add(duration, send_dtmf_callback,
    session->session);
    }
    --- a/libpurple/media/backend-iface.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/media/backend-iface.h Sun Oct 08 20:44:26 2017 +0300
    @@ -132,7 +132,7 @@
    * @self: The backend the stream is in.
    * @sess_id: The session id associated with the stream.
    * @participant: The participant associated with the stream.
    - * @remote_candidates: The list of remote candidates to add.
    + * @remote_candidates: (element-type PurpleMediaCandidate): The list of remote candidates to add.
    *
    * Add remote candidates to a stream.
    */
    @@ -165,7 +165,7 @@
    * The intersection list consists of all codecs that are compatible
    * between the local and remote software.
    *
    - * Returns: The codec intersection list.
    + * Returns: (transfer full) (element-type PurpleMediaCodec): The codec intersection list.
    */
    GList *purple_media_backend_get_codecs(PurpleMediaBackend *self,
    const gchar *sess_id);
    @@ -178,7 +178,7 @@
    *
    * Gets the list of local candidates for a stream.
    *
    - * Returns: The list of local candidates.
    + * Return Value: (transfer full) (element-type PurpleMediaCandidate): The list of local candidates.
    */
    GList *purple_media_backend_get_local_candidates(PurpleMediaBackend *self,
    const gchar *sess_id, const gchar *participant);
    @@ -188,7 +188,7 @@
    * @self: The media backend the stream is in.
    * @sess_id: The session id the stream is associated with.
    * @participant: The participant the stream is associated with.
    - * @codecs: The list of remote codecs to set.
    + * @codecs: (element-type PurpleMediaCodec) The list of remote codecs to set.
    *
    * Sets the remote codecs on a stream.
    *
    @@ -264,7 +264,7 @@
    * Gets the list of optional parameters supported by the media backend.
    * The list should NOT be freed.
    *
    - * Returns: NULL-terminated array of names of supported parameters.
    + * Return Value: (transfer none): NULL-terminated array of names of supported parameters.
    */
    const gchar **purple_media_backend_get_available_params(PurpleMediaBackend *self);
    --- a/libpurple/media/candidate.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/media/candidate.h Sun Oct 08 20:44:26 2017 +0300
    @@ -90,17 +90,19 @@
    /**
    * purple_media_candidate_list_copy:
    - * @candidates: The list of candidates to be copied.
    + * @candidates: (element-type PurpleMediaCandidate) (transfer none): The list
    + * of candidates to be copied.
    *
    * Copies a GList of PurpleMediaCandidate and its contents.
    *
    - * Returns: The copy of the GList.
    + * Returns: (element-type PurpleMediaCandidate): The copy of the GList.
    */
    GList *purple_media_candidate_list_copy(GList *candidates);
    /**
    * purple_media_candidate_list_free:
    - * @candidates: The list of candidates to be freed.
    + * @candidates: (element-type PurpleMediaCandidate) (transfer full): The list
    + * of candidates to be freed.
    *
    * Frees a GList of PurpleMediaCandidate and its contents.
    */
    --- a/libpurple/media/codec.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/media/codec.h Sun Oct 08 20:44:26 2017 +0300
    @@ -120,10 +120,8 @@
    *
    * Gets a list of the optional parameters.
    *
    - * The list consists of PurpleKeyValuePair's.
    - *
    - * Returns: The list of optional parameters. The list is owned by the codec and
    - * should not be freed.
    + * Returns: (element-type PurpleKeyValuePair) (transfer none): The list of
    + * optional parameters.
    */
    GList *purple_media_codec_get_optional_parameters(PurpleMediaCodec *codec);
    @@ -174,17 +172,19 @@
    /**
    * purple_media_codec_list_copy:
    - * @codecs: The list of codecs to be copied.
    + * @codecs: (element-type PurpleMediaCodec) (transfer none): The list of codecs
    + * to be copied.
    *
    * Copies a GList of PurpleMediaCodec and its contents.
    *
    - * Returns: The copy of the GList.
    + * Returns: (element-type PurpleMediaCodec): The copy of the GList.
    */
    GList *purple_media_codec_list_copy(GList *codecs);
    /**
    * purple_media_codec_list_free:
    - * @codecs: The list of codecs to be freed.
    + * @codecs: (element-type PurpleMediaCodec) (transfer full): The list of codecs
    + * to be freed.
    *
    * Frees a GList of PurpleMediaCodec and its contents.
    */
    --- a/libpurple/mediamanager.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/mediamanager.c Sun Oct 08 20:44:26 2017 +0300
    @@ -581,12 +581,12 @@
    info->writable_cb_token = 0;
    if (info->readable_timer_id) {
    - purple_timeout_remove (info->readable_timer_id);
    + g_source_remove (info->readable_timer_id);
    info->readable_timer_id = 0;
    }
    if (info->writable_timer_id) {
    - purple_timeout_remove (info->writable_timer_id);
    + g_source_remove (info->writable_timer_id);
    info->writable_timer_id = 0;
    }
    @@ -811,10 +811,10 @@
    /* We can't use writable_timer_id as a token, because the timeout is added
    * into libpurple's main event loop, which runs in a different thread than
    * from where call_appsrc_writable_locked() was called. Consequently, the
    - * callback may run even before purple_timeout_add() returns the timer ID
    + * callback may run even before g_timeout_add() returns the timer ID
    * to us. */
    info->writable_cb_token = ++manager->priv->appdata_cb_token;
    - info->writable_timer_id = purple_timeout_add (0, appsrc_writable, info);
    + info->writable_timer_id = g_timeout_add (0, appsrc_writable, info);
    }
    static void
    @@ -1001,7 +1001,7 @@
    return;
    info->readable_cb_token = ++manager->priv->appdata_cb_token;
    - info->readable_timer_id = purple_timeout_add (0, appsink_readable, info);
    + info->readable_timer_id = g_timeout_add (0, appsink_readable, info);
    }
    static GstFlowReturn
    @@ -1718,12 +1718,12 @@
    info->notify (info->user_data);
    if (info->readable_cb_token) {
    - purple_timeout_remove (info->readable_timer_id);
    + g_source_remove (info->readable_timer_id);
    info->readable_cb_token = 0;
    }
    if (info->writable_cb_token) {
    - purple_timeout_remove (info->writable_timer_id);
    + g_source_remove (info->writable_timer_id);
    info->writable_cb_token = 0;
    }
    --- a/libpurple/mediamanager.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/mediamanager.h Sun Oct 08 20:44:26 2017 +0300
    @@ -119,7 +119,7 @@
    *
    * Gets the "global" media manager object. It's created if it doesn't already exist.
    *
    - * Returns: The "global" instance of the media manager object.
    + * Returns: (transfer none): The "global" instance of the media manager object.
    */
    PurpleMediaManager *purple_media_manager_get(void);
    @@ -133,7 +133,7 @@
    *
    * Creates a media session.
    *
    - * Returns: A newly created media session.
    + * Returns: (transfer full): A newly created media session.
    */
    PurpleMedia *purple_media_manager_create_media(PurpleMediaManager *manager,
    PurpleAccount *account,
    @@ -147,7 +147,7 @@
    *
    * Gets all of the media sessions.
    *
    - * Returns: A list of all the media sessions.
    + * Returns: (transfer none) (element-type PurpleMedia): A list of all the media sessions.
    */
    GList *purple_media_manager_get_media(PurpleMediaManager *manager);
    @@ -158,7 +158,7 @@
    *
    * Gets all of the media sessions for a given account.
    *
    - * Returns: A list of the media sessions on the given account.
    + * Returns: (transfer container) (element-type PurpleMedia): A list of the media sessions on the given account.
    */
    GList *purple_media_manager_get_media_by_account(
    PurpleMediaManager *manager, PurpleAccount *account);
    @@ -188,7 +188,7 @@
    * get notified about. It is useful especially for sessions with a type of
    * PURPLE_MEDIA_APPLICATION which the front-end wouldn't know how to handle.
    *
    - * Returns: A newly created media session.
    + * Returns: (transfer full): A newly created media session.
    */
    PurpleMedia *purple_media_manager_create_private_media(
    PurpleMediaManager *manager,
    @@ -203,7 +203,7 @@
    *
    * Gets all of the private media sessions.
    *
    - * Returns: A list of all the private media sessions.
    + * Returns: (transfer none) (element-type PurpleMedia): A list of all the private media sessions.
    */
    GList *purple_media_manager_get_private_media(PurpleMediaManager *manager);
    @@ -214,7 +214,7 @@
    *
    * Gets all of the private media sessions for a given account.
    *
    - * Returns: A list of the private media sessions on the given account.
    + * Returns: (transfer container) (element-type PurpleMedia): A list of the private media sessions on the given account.
    */
    GList *purple_media_manager_get_private_media_by_account(
    PurpleMediaManager *manager, PurpleAccount *account);
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,473 @@
    +purple_coresources = [
    + 'account.c',
    + 'accounts.c',
    + 'accountopt.c',
    + 'blistnode.c',
    + 'buddy.c',
    + 'buddylist.c',
    + 'buddyicon.c',
    + 'chat.c',
    + 'circularbuffer.c',
    + 'cmds.c',
    + 'connection.c',
    + 'contact.c',
    + 'conversation.c',
    + 'conversationtypes.c',
    + 'conversations.c',
    + 'core.c',
    + 'countingnode.c',
    + 'debug.c',
    + 'e2ee.c',
    + 'eventloop.c',
    + 'group.c',
    + 'http.c',
    + 'idle.c',
    + 'image.c',
    + 'image-store.c',
    + 'keyring.c',
    + 'log.c',
    + 'media/backend-fs2.c',
    + 'media/backend-iface.c',
    + 'media/candidate.c',
    + 'media/codec.c',
    + 'media/enum-types.c',
    + 'media.c',
    + 'mediamanager.c',
    + 'memorypool.c',
    + 'message.c',
    + 'mime.c',
    + 'nat-pmp.c',
    + 'network.c',
    + 'notify.c',
    + 'plugins.c',
    + 'pluginpref.c',
    + 'pounce.c',
    + 'prefs.c',
    + 'presence.c',
    + 'proxy.c',
    + 'protocol.c',
    + 'protocols.c',
    + 'purple-gio.c',
    + 'queuedoutputstream.c',
    + 'request.c',
    + 'request-datasheet.c',
    + 'roomlist.c',
    + 'savedstatuses.c',
    + 'server.c',
    + 'signals.c',
    + 'smiley-custom.c',
    + 'smiley-list.c',
    + 'smiley-parser.c',
    + 'smiley-theme.c',
    + 'smiley.c',
    + 'status.c',
    + 'stringref.c',
    + 'stun.c',
    + 'sound.c',
    + 'sound-theme.c',
    + 'sound-theme-loader.c',
    + 'sslconn.c',
    + 'theme.c',
    + 'theme-loader.c',
    + 'theme-manager.c',
    + 'tls-certificate.c',
    + 'tls-certificate-info.c',
    + 'trie.c',
    + 'upnp.c',
    + 'util.c',
    + 'version.c',
    + 'whiteboard.c',
    + 'xfer.c',
    + 'xmlnode.c'
    +]
    +
    +purple_coreheaders = [
    + 'account.h',
    + 'accounts.h',
    + 'accountopt.h',
    + 'blistnode.h',
    + 'buddy.h',
    + 'buddylist.h',
    + 'buddyicon.h',
    + 'chat.h',
    + 'circularbuffer.h',
    + 'cmds.h',
    + 'connection.h',
    + 'contact.h',
    + 'conversation.h',
    + 'conversationtypes.h',
    + 'conversations.h',
    + 'core.h',
    + 'countingnode.h',
    + 'dbus-maybe.h',
    + 'debug.h',
    + 'e2ee.h',
    + 'eventloop.h',
    + 'group.h',
    + 'http.h',
    + 'idle.h',
    + 'image.h',
    + 'image-store.h',
    + 'keyring.h',
    + 'log.h',
    + 'media.h',
    + 'mediamanager.h',
    + 'memorypool.h',
    + 'message.h',
    + 'mime.h',
    + 'nat-pmp.h',
    + 'network.h',
    + 'notify.h',
    + 'plugins.h',
    + 'pluginpref.h',
    + 'pounce.h',
    + 'prefs.h',
    + 'presence.h',
    + 'proxy.h',
    + 'protocol.h',
    + 'protocols.h',
    + 'purple-gio.h',
    + 'queuedoutputstream.h',
    + 'request.h',
    + 'request-datasheet.h',
    + 'roomlist.h',
    + 'savedstatuses.h',
    + 'server.h',
    + 'signals.h',
    + 'smiley-custom.h',
    + 'smiley-list.h',
    + 'smiley-parser.h',
    + 'smiley-theme.h',
    + 'smiley.h',
    + 'status.h',
    + 'stringref.h',
    + 'stun.h',
    + 'sound.h',
    + 'sound-theme.h',
    + 'sound-theme-loader.h',
    + 'sslconn.h',
    + 'tests.h',
    + 'theme.h',
    + 'theme-loader.h',
    + 'theme-manager.h',
    + 'tls-certificate.h',
    + 'tls-certificate-info.h',
    + 'trie.h',
    + 'upnp.h',
    + 'util.h',
    + 'whiteboard.h',
    + 'xfer.h',
    + 'xmlnode.h',
    +]
    +
    +if enable_vv
    + purple_coreheaders += 'media-gst.h'
    +endif
    +
    +if IS_WIN32
    + purple_coresources += [
    + 'win32/libc_interface.c',
    + 'win32/win32dep.c'
    + ]
    +
    + purple_coreheaders += [
    + 'win32/libc_interface.h',
    + 'win32/libc_internal.h',
    + 'win32/win32dep.h',
    + 'win32/wpurpleerror.h'
    + ]
    +
    + libpurplerc = configure_file(
    + input : 'win32/libpurplerc.rc.in',
    + output : 'libpurplerc.rc',
    + configuration : version_conf)
    + purple_coresources += windows.compile_resources(libpurplerc)
    +endif
    +
    +purple_mediaheaders = [
    + 'media/backend-iface.h',
    + 'media/candidate.h',
    + 'media/codec.h',
    + 'media/enum-types.h'
    +]
    +
    +purple_enumheaders = [
    + 'account.h',
    + 'buddyicon.h',
    + 'connection.h',
    + 'conversation.h',
    + 'conversationtypes.h',
    + 'debug.h',
    + 'eventloop.h',
    + 'notify.h',
    + 'plugins.h',
    + 'protocol.h',
    + 'protocols.h',
    + 'roomlist.h',
    + 'status.h',
    + 'sound.h',
    + 'xfer.h',
    + 'xmlnode.h'
    +]
    +
    +
    +enums = gnome.mkenums('enums',
    + sources : purple_enumheaders,
    + h_template : 'enums.h.in',
    + c_template : 'enums.c.in',
    + install_header : true,
    + install_dir : get_option('includedir') + '/libpurple')
    +enums_c = enums[0]
    +enums_h = enums[1]
    +
    +purple_h = configure_file(input : 'purple.h.in',
    + output : 'purple.h',
    + configuration : conf,
    + install : true,
    + install_dir : get_option('includedir') + '/libpurple')
    +version_h = configure_file(input : 'version.h.in',
    + output : 'version.h',
    + configuration : version_conf,
    + install : true,
    + install_dir : get_option('includedir') + '/libpurple')
    +
    +purple_builtsources = [
    + enums_c,
    +]
    +
    +purple_builtheaders = [
    + purple_h,
    + version_h,
    + enums_h,
    +]
    +
    +if enable_dbus
    +
    +# purple dbus server
    +
    +dbus_sources = [
    + 'dbus-server.c',
    + 'dbus-useful.c'
    +]
    +dbus_headers = [
    + 'dbus-server.h',
    + 'dbus-bindings.h',
    + 'dbus-purple.h',
    + 'dbus-useful.h',
    + 'dbus-define-api.h',
    +]
    +dbus_exported = [
    + 'dbus-useful.h',
    + 'dbus-define-api.h',
    + 'account.h',
    + 'accounts.h',
    + 'blistnode.h',
    + 'buddy.h',
    + 'buddylist.h',
    + 'buddyicon.h',
    + 'connection.h',
    + 'conversation.h',
    + 'conversationtypes.h',
    + 'conversations.h',
    + 'core.h',
    + 'xfer.h',
    + 'log.h',
    + 'notify.h',
    + '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'
    +]
    +
    +purple_build_coreheaders = purple_coreheaders + purple_mediaheaders
    +purple_build_coreheaders += purple_builtheaders
    +
    +
    +# We should probably make this better
    +dbus_signals = purple_coresources + ['protocols/irc/irc.c', 'protocols/jabber/jabber.c']
    +
    +dbus_analyze_functions = files('dbus-analyze-functions.py')[0]
    +dbus_analyze_signals = files('dbus-analyze-signals.py')[0]
    +dbus_analyze_types = files('dbus-analyze-types.py')[0]
    +
    +dbus_types_c = custom_target('dbus_types_c',
    + input : purple_build_coreheaders,
    + output : 'dbus-types.ch',
    + command : [python, dbus_analyze_types, '-o', '@OUTPUT@',
    + '--pattern=PURPLE_DBUS_DEFINE_TYPE(%s)', '@INPUT@'])
    +
    +dbus_types_h = custom_target('dbus_types_h',
    + input : purple_build_coreheaders,
    + output : 'dbus-types.h',
    + command : [python, dbus_analyze_types, '-o', '@OUTPUT@',
    + '--pattern=PURPLE_DBUS_DECLARE_TYPE(%s)', '@INPUT@'],
    + install : true,
    + install_dir : join_paths(get_option('includedir'), 'libpurple'))
    +
    +dbus_bindings_c = custom_target('dbus_bindings_c',
    + input : dbus_exported,
    + output : 'dbus-bindings.ch',
    + command : [python, dbus_analyze_functions, '-o', '@OUTPUT@',
    + '@INPUT@'])
    +
    +dbus_signals_c = custom_target('dbus_signals_c',
    + input : dbus_signals,
    + output : 'dbus-signals.ch',
    + command : [python, dbus_analyze_signals, '-o', '@OUTPUT@',
    + '@INPUT@'])
    +
    +dbus_builtheaders = [dbus_types_h]
    +dbus_builtsources = [dbus_types_c, dbus_bindings_c, dbus_signals_c]
    +
    +# libpurple-client
    +
    +purple_client_bindings_h1 = custom_target('purple_client_bindings_h1',
    + input : purple_build_coreheaders,
    + output : 'purple-client-bindings1.h',
    + command : [
    + python, dbus_analyze_types,
    + '--keyword=enum', '--verbatim', '-o', '@OUTPUT@', '@INPUT@'
    + ]
    +)
    +
    +purple_client_bindings_h2 = custom_target('purple_client_bindings_h2',
    + input : dbus_exported,
    + output : 'purple-client-bindings2.h',
    + command : [
    + python, dbus_analyze_functions,
    + '--client', '--headers', '-o', '@OUTPUT@', '@INPUT@'
    + ]
    +)
    +
    +purple_client_bindings_h = custom_target('purple_client_bindings_h',
    + input : [purple_client_bindings_h1, purple_client_bindings_h2],
    + output : 'purple-client-bindings.h',
    + capture : true,
    + command : ['cat', '@INPUT@'])
    +
    +purple_client_bindings_c = custom_target('purple_client_bindings_c',
    + input : dbus_exported,
    + output : 'purple-client-bindings.ch',
    + command : [
    + python, dbus_analyze_functions,
    + '--client', '-o', '@OUTPUT@', '@INPUT@'
    + ]
    +)
    +
    +libpurple_client = library('purple-client',
    + 'purple-client.c', purple_client_bindings_c, purple_client_bindings_h,
    + version : PURPLE_LIB_VERSION,
    + dependencies : [dbus, dbus_glib],
    + install : true)
    +
    +# scripts
    +
    +install_data(['purple-remote', 'purple-send', 'purple-send-async', 'purple-url-handler'],
    + install_dir : get_option('bindir'))
    +
    +else
    +
    +dbus_sources = []
    +dbus_headers = []
    +dbus_builtsources = []
    +dbus_builtheaders = []
    +
    +endif
    +
    +libpurple_inc = include_directories('.')
    +libpurple = library('purple',
    + purple_coresources + purple_builtsources +
    + dbus_sources + dbus_builtsources +
    + purple_builtheaders + dbus_builtheaders,
    + include_directories : [toplevel_inc, libpurple_inc],
    + install : true,
    + version : PURPLE_LIB_VERSION,
    + dependencies : # static_link_libs
    + [dbus, dbus_glib, dnsapi, ws2_32, glib, gio, gplugin, libxml,
    + farstream, gstreamer, gstreamer_video,
    + gstreamer_app, idn, json, math])
    +libpurple_dep = declare_dependency(
    + sources : purple_builtheaders, # Ensure built before any dependencies.
    + include_directories : [toplevel_inc, libpurple_inc],
    + link_with : libpurple,
    + dependencies : [gstreamer, gplugin, glib, gio])
    +
    +if enable_dbus
    +
    +# purple-client-example
    +
    +purple_client_example = executable('purple-client-example',
    + 'purple-client-example.c', purple_client_bindings_h,
    + link_with : [libpurple_client, libpurple],
    + dependencies : [dbus, dbus_glib, glib],
    + install : true)
    +
    +endif
    +
    +install_headers(purple_coreheaders + dbus_headers,
    + subdir : 'libpurple')
    +
    +install_headers(purple_mediaheaders,
    + subdir : 'libpurple/media')
    +
    +configure_file(input : 'data/purple-3.pc.in',
    + output : 'purple-3.pc',
    + configuration : pkg_conf,
    + install : true,
    + install_dir : get_option('libdir') + '/pkgconfig')
    +
    +if INSTALL_I18N
    + DESKTOP_FILE = 'purple-url-handler.desktop'
    + desktop_file_in = configure_file(
    + input : 'data/' + DESKTOP_FILE + '.in.in',
    + output : DESKTOP_FILE + '.in',
    + configuration : conf)
    + desktop_file = custom_target(DESKTOP_FILE,
    + input : desktop_file_in,
    + output : DESKTOP_FILE,
    + command : [intltool_merge, '--desktop-style', '-u',
    + '-c', '@BUILD_DIR@/po/.intltool-merge-cache',
    + meson.source_root() + '/po', '@INPUT@', '@OUTPUT@'],
    + install : true,
    + install_dir : get_option('datadir') + '/applications')
    +endif # INSTALL_I18N
    +
    +if enable_introspection
    + introspection_sources = (purple_coreheaders + purple_builtheaders +
    + dbus_headers + purple_mediaheaders)
    +
    + Purple_gir_includes = ['GObject-2.0', 'Gio-2.0']
    + if PLUGINS
    + Purple_gir_includes += ['GPlugin-0.0']
    + endif
    + if enable_dbus
    + Purple_gir_includes += ['DBus-1.0', 'DBusGLib-1.0']
    + endif
    + if enable_gst
    + Purple_gir_includes += ['Gst-1.0']
    + endif
    +
    + libpurple_gir = gnome.generate_gir(libpurple,
    + sources : introspection_sources,
    + includes : Purple_gir_includes,
    + namespace : 'Purple',
    + symbol_prefix : 'purple',
    + identifier_prefix : 'Purple',
    + export_packages : 'purple-@0@'.format(purple_major_version),
    + nsversion : '@0@.@1@'.format(purple_major_version,
    + purple_minor_version),
    + install : true)
    +endif
    +
    +subdir('tests')
    +subdir('example')
    +subdir('plugins')
    +subdir('protocols')
    --- a/libpurple/message.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/message.h Sun Oct 08 20:44:26 2017 +0300
    @@ -103,7 +103,7 @@
    * @who: Message's author.
    * @contents: The contents of a message.
    * @flags: The message flags.
    - * @timestamp: The time of transmitting a message. May be %0 for a current time.
    + * @timestamp: The time of transmitting a message. May be 0 for a current time.
    *
    * Creates new incoming message (the user is the recipient).
    *
    --- a/libpurple/mime.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/mime.h Sun Oct 08 20:44:26 2017 +0300
    @@ -89,6 +89,8 @@
    /**
    * purple_mime_document_write:
    + * @doc: The MIME document.
    + * @str: The string to write the MIME document to.
    *
    * Write (append) a MIME document onto a GString.
    */
    @@ -100,8 +102,8 @@
    *
    * The list of fields in the header of a document
    *
    - * Returns: (transfer none): A list of strings indicating the fields (but not
    - * the values of the fields) in the header of doc.
    + * Returns: (element-type utf8) (transfer none): A list of strings indicating
    + * the fields (but not the values of the fields) in the header of doc.
    */
    GList *purple_mime_document_get_fields(PurpleMimeDocument *doc);
    @@ -138,7 +140,8 @@
    *
    * The list of parts in a multipart document.
    *
    - * Returns: (transfer none): List of PurpleMimePart contained within doc.
    + * Returns: (element-type PurpleMimePart) (transfer none): List of MIME parts
    + * contained within doc.
    */
    GList *purple_mime_document_get_parts(PurpleMimeDocument *doc);
    @@ -157,8 +160,8 @@
    *
    * The list of fields in the header of a document part.
    *
    - * Returns: (transfer none): List of strings indicating the fields (but not the
    - * values of the fields) in the header of part.
    + * Returns: (element-type utf8) (transfer none): List of strings indicating the
    + * fields (but not the values of the fields) in the header of part.
    */
    GList *purple_mime_part_get_fields(PurpleMimePart *part);
    @@ -178,6 +181,8 @@
    /**
    * purple_mime_part_get_field_decoded:
    + * @part: The MIME document part.
    + * @field: Case-insensitive name of the header field.
    *
    * Get the decoded value of a specific field in the header of a
    * document part.
    --- a/libpurple/network.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/network.c Sun Oct 08 20:44:26 2017 +0300
    @@ -468,7 +468,7 @@
    {
    purple_debug_info("network", "Skipping external port mapping.\n");
    /* The pmp_map_cb does what we want to do */
    - listen_data->timer = purple_timeout_add(0, purple_network_finish_pmp_map_cb, listen_data);
    + listen_data->timer = g_timeout_add(0, purple_network_finish_pmp_map_cb, listen_data);
    }
    /* Attempt a NAT-PMP Mapping, which will return immediately */
    else if (purple_pmp_create_map(((socket_type == SOCK_STREAM) ? PURPLE_PMP_TYPE_TCP : PURPLE_PMP_TYPE_UDP),
    @@ -476,7 +476,7 @@
    {
    purple_debug_info("network", "Created NAT-PMP mapping on port %i\n", actual_port);
    /* We want to return listen_data now, and on the next run loop trigger the cb and destroy listen_data */
    - listen_data->timer = purple_timeout_add(0, purple_network_finish_pmp_map_cb, listen_data);
    + listen_data->timer = g_timeout_add(0, purple_network_finish_pmp_map_cb, listen_data);
    }
    else
    {
    @@ -532,7 +532,7 @@
    purple_upnp_cancel_port_mapping(listen_data->mapping_data);
    if (listen_data->timer > 0)
    - purple_timeout_remove(listen_data->timer);
    + g_source_remove(listen_data->timer);
    g_free(listen_data);
    }
    --- a/libpurple/network.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/network.h Sun Oct 08 20:44:26 2017 +0300
    @@ -87,7 +87,7 @@
    * Note: The caller must free this list. If libpurple was built with
    * support for it, this function also enumerates IPv6 addresses.
    *
    - * Returns: A list of local IP addresses.
    + * Returns: (element-type utf8): A list of local IP addresses.
    */
    GList *purple_network_get_all_local_system_ips(void);
    --- a/libpurple/notify.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/notify.h Sun Oct 08 20:44:26 2017 +0300
    @@ -371,7 +371,7 @@
    /**
    * purple_notify_searchresults_row_add:
    * @results: The search results object.
    - * @row: The row of the results.
    + * @row: (element-type utf8) (transfer full): The row of the results.
    *
    * Adds a new row of the results to the search results object.
    */
    --- a/libpurple/pluginpref.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/pluginpref.h Sun Oct 08 20:44:26 2017 +0300
    @@ -100,7 +100,7 @@
    *
    * Get the plugin preferences from a plugin preference frame
    *
    - * Returns: (transfer none): a GList of plugin preferences
    + * Returns: (element-type PurplePluginPref) (transfer none): a list of plugin preferences
    */
    GList *purple_plugin_pref_frame_get_prefs(PurplePluginPrefFrame *frame);
    --- a/libpurple/plugins/Makefile.am Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/plugins/Makefile.am Sun Oct 08 20:44:26 2017 +0300
    @@ -86,7 +86,7 @@
    if ENABLE_DBUS
    -CLEANFILES = dbus-example-bindings.c
    +CLEANFILES = dbus-example-bindings.ch
    dbus_example_la_SOURCES = dbus-example.c
    dbus_example_la_LIBADD = @PURPLE_LIBS@ $(DBUS_LIBS)
    @@ -96,11 +96,11 @@
    $(top_builddir)/libpurple/dbus-types.h: always
    $(AM_V_GEN)cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F)
    -dbus-example-bindings.c: $(top_srcdir)/libpurple/dbus-analyze-functions.py $(dbus_example_la_SOURCES)
    +dbus-example-bindings.ch: $(top_srcdir)/libpurple/dbus-analyze-functions.py $(dbus_example_la_SOURCES)
    $(AM_V_GEN)cat $(srcdir)/$(dbus_example_la_SOURCES) | \
    $(PYTHON) $(top_srcdir)/libpurple/dbus-analyze-functions.py --export-only > $@
    -$(dbus_example_la_OBJECTS) dbus-example.so: dbus-example-bindings.c $(top_builddir)/libpurple/dbus-types.h
    +$(dbus_example_la_OBJECTS) dbus-example.so: dbus-example-bindings.ch $(top_builddir)/libpurple/dbus-types.h
    endif # ENABLE_DBUS
    --- a/libpurple/plugins/dbus-example.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/plugins/dbus-example.c Sun Oct 08 20:44:26 2017 +0300
    @@ -73,7 +73,7 @@
    /* This file has been generated by the #dbus-analize-functions.py
    script. It contains dbus wrappers for the four functions declared
    above. */
    -#include "dbus-example-bindings.c"
    +#include "dbus-example-bindings.ch"
    /* This is the PurpleText object we want to make publicly visible. */
    static PurpleText hello;
    --- a/libpurple/plugins/filectl.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/plugins/filectl.c Sun Oct 08 20:44:26 2017 +0300
    @@ -242,7 +242,7 @@
    plugin_load(PurplePlugin *plugin, GError **error)
    {
    init_file();
    - check = purple_timeout_add_seconds(5, (GSourceFunc)check_file, NULL);
    + check = g_timeout_add_seconds(5, (GSourceFunc)check_file, NULL);
    return TRUE;
    }
    @@ -250,7 +250,7 @@
    static gboolean
    plugin_unload(PurplePlugin *plugin, GError **error)
    {
    - purple_timeout_remove(check);
    + g_source_remove(check);
    return TRUE;
    }
    --- a/libpurple/plugins/joinpart.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/plugins/joinpart.c Sun Oct 08 20:44:26 2017 +0300
    @@ -255,7 +255,7 @@
    PURPLE_CALLBACK(received_chat_msg_cb), users);
    /* Cleanup every 5 minutes */
    - id = purple_timeout_add_seconds(60 * 5, (GSourceFunc)clean_users_hash, users);
    + id = g_timeout_add_seconds(60 * 5, (GSourceFunc)clean_users_hash, users);
    g_object_set_data(G_OBJECT(plugin), "users", users);
    g_object_set_data(G_OBJECT(plugin), "id", GUINT_TO_POINTER(id));
    @@ -270,7 +270,7 @@
    * we don't have to worry one will be called after this. */
    g_hash_table_destroy((GHashTable *)g_object_get_data(G_OBJECT(plugin), "users"));
    - purple_timeout_remove(GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(plugin), "id")));
    + g_source_remove(GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(plugin), "id")));
    return TRUE;
    }
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/plugins/keyrings/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,38 @@
    +if PLUGINS
    + if enable_nettle
    + internalkeyring_plugin = library('internalkeyring', 'internalkeyring.c',
    + dependencies : [nettle, libpurple_dep],
    + name_prefix : '',
    + install : true, install_dir : PURPLE_PLUGINDIR)
    + endif
    +
    + if enable_secret_service
    + secretsservice_plugin = library('secretservice', 'secretservice.c',
    + dependencies : [secretservice, libpurple_dep],
    + name_prefix : '',
    + install : true, install_dir : PURPLE_PLUGINDIR)
    + endif
    +
    + if enable_gnome_keyring
    + gnomekeyring_plugin = library('gnomekeyring', 'gnomekeyring.c',
    + dependencies : [gnome_keyring, libpurple_dep],
    + name_prefix : '',
    + install : true, install_dir : PURPLE_PLUGINDIR)
    + endif
    +
    + if IS_WIN32
    + wincred_plugin = library('wincred', 'wincred.c',
    + dependencies : [libpurple_dep],
    + name_prefix : '',
    + install : true, install_dir : PURPLE_PLUGINDIR)
    + endif
    +
    + if enable_kwallet
    + kwallet_moc = moc.process('kwallet.cpp')
    +
    + kwallet_plugin = library('kwallet', 'kwallet.cpp', kwallet_moc,
    + dependencies : [kwallet, qt4, libpurple_dep],
    + name_prefix : '',
    + install : true, install_dir : PURPLE_PLUGINDIR)
    + endif
    +endif # PLUGINS
    --- a/libpurple/plugins/log_reader.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/plugins/log_reader.c Sun Oct 08 20:44:26 2017 +0300
    @@ -95,12 +95,12 @@
    if (!purple_str_has_prefix(file, sn))
    continue;
    if (purple_str_has_suffix(file, ".html") || purple_str_has_suffix(file, ".AdiumHTMLLog")) {
    - struct tm tm;
    + GDateTime *dt;
    + gint year, month, day, hour, minute, second;
    const char *date = file;
    date += strlen(sn) + 2;
    - if (sscanf(date, "%u|%u|%u",
    - &tm.tm_year, &tm.tm_mon, &tm.tm_mday) != 3) {
    + if (sscanf(date, "%u|%u|%u", &year, &month, &day) != 3) {
    purple_debug_error("Adium log parse",
    "Filename timestamp parsing error\n");
    @@ -134,7 +134,7 @@
    contents2++;
    if (sscanf(contents2, "%u.%u.%u",
    - &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 3) {
    + &hour, &minute, &second) != 3) {
    purple_debug_error("Adium log parse",
    "Contents timestamp parsing error\n");
    @@ -146,23 +146,24 @@
    data->path = filename;
    data->type = ADIUM_HTML;
    - tm.tm_year -= 1900;
    - tm.tm_mon -= 1;
    -
    - /* XXX: Look into this later... Should we pass in a struct tm? */
    - log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, mktime(&tm), NULL);
    + /* XXX: Look into this later... Should we figure out a timezone? */
    + dt = g_date_time_new_local(year, month, day, hour, minute, second);
    +
    + log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, dt);
    log->logger = adium_logger;
    log->logger_data = data;
    + g_date_time_unref(dt);
    +
    list = g_list_prepend(list, log);
    }
    } else if (purple_str_has_suffix(file, ".adiumLog")) {
    - struct tm tm;
    + GDateTime *dt;
    + gint year, month, day, hour, minute, second;
    const char *date = file;
    date += strlen(sn) + 2;
    - if (sscanf(date, "%u|%u|%u",
    - &tm.tm_year, &tm.tm_mon, &tm.tm_mday) != 3) {
    + if (sscanf(date, "%u|%u|%u", &year, &month, &day) != 3) {
    purple_debug_error("Adium log parse",
    "Filename timestamp parsing error\n");
    @@ -190,8 +191,7 @@
    if (*contents2)
    contents2++;
    - if (sscanf(contents2, "%u.%u.%u",
    - &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 3) {
    + if (sscanf(contents2, "%u.%u.%u", &hour, &minute, &second) != 3) {
    purple_debug_error("Adium log parse",
    "Contents timestamp parsing error\n");
    @@ -199,18 +199,19 @@
    continue;
    }
    - tm.tm_year -= 1900;
    - tm.tm_mon -= 1;
    -
    data = g_new0(struct adium_logger_data, 1);
    data->path = filename;
    data->type = ADIUM_TEXT;
    - /* XXX: Look into this later... Should we pass in a struct tm? */
    - log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, mktime(&tm), NULL);
    + /* XXX: Look into this later... Should we figure out a timezone? */
    + dt = g_date_time_new_local(year, month, day, hour, minute, second);
    +
    + log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, dt);
    log->logger = adium_logger;
    log->logger_data = data;
    + g_date_time_unref(dt);
    +
    list = g_list_prepend(list, log);
    }
    }
    @@ -337,11 +338,11 @@
    /* This function is really confusing. It makes baby rlaager cry...
    In other news: "You lost a lot of blood but we found most of it."
    */
    -static time_t msn_logger_parse_timestamp(PurpleXmlNode *message, struct tm **tm_out)
    +static GDateTime *
    +msn_logger_parse_timestamp(PurpleXmlNode *message)
    {
    const char *datetime;
    - static struct tm tm2;
    - time_t stamp;
    + GDateTime *stamp;
    const char *date;
    const char *time;
    int month;
    @@ -352,47 +353,26 @@
    int sec;
    char am_pm;
    char *str;
    - static struct tm tm;
    - time_t t;
    - time_t diff;
    -
    -#ifndef G_DISABLE_CHECKS
    - if (message != NULL)
    - {
    - *tm_out = NULL;
    -
    - /* Trigger the usual warning. */
    - g_return_val_if_fail(message != NULL, (time_t)0);
    - }
    -#endif
    + GDateTime *t;
    + GTimeSpan diff;
    +
    + g_return_val_if_fail(message != NULL, NULL);
    datetime = purple_xmlnode_get_attrib(message, "DateTime");
    if (!(datetime && *datetime))
    {
    purple_debug_error("MSN log timestamp parse",
    "Attribute missing: %s\n", "DateTime");
    - return (time_t)0;
    + return NULL;
    }
    - stamp = purple_str_to_time(datetime, TRUE, &tm2, NULL, NULL);
    -#ifdef HAVE_TM_GMTOFF
    - tm2.tm_gmtoff = 0;
    -#endif
    -#ifdef HAVE_STRUCT_TM_TM_ZONE
    - /* This is used in the place of a timezone abbreviation if the
    - * offset is way off. The user should never really see it, but
    - * it's here just in case. The parens are to make it clear it's
    - * not a real timezone. */
    - tm2.tm_zone = _("(UTC)");
    -#endif
    -
    + stamp = purple_str_to_date_time(datetime, TRUE);
    date = purple_xmlnode_get_attrib(message, "Date");
    if (!(date && *date))
    {
    purple_debug_error("MSN log timestamp parse",
    "Attribute missing: %s\n", "Date");
    - *tm_out = &tm2;
    return stamp;
    }
    @@ -401,7 +381,6 @@
    {
    purple_debug_error("MSN log timestamp parse",
    "Attribute missing: %s\n", "Time");
    - *tm_out = &tm2;
    return stamp;
    }
    @@ -409,7 +388,6 @@
    {
    purple_debug_error("MSN log timestamp parse",
    "%s parsing error\n", "Date");
    - *tm_out = &tm2;
    return stamp;
    }
    else
    @@ -426,7 +404,6 @@
    {
    purple_debug_error("MSN log timestamp parse",
    "%s parsing error\n", "Time");
    - *tm_out = &tm2;
    return stamp;
    }
    @@ -438,34 +415,30 @@
    }
    str = g_strdup_printf("%04i-%02i-%02iT%02i:%02i:%02i", year, month, day, hour, min, sec);
    - t = purple_str_to_time(str, TRUE, &tm, NULL, NULL);
    -
    -
    - if (stamp > t)
    - diff = stamp - t;
    + t = purple_str_to_date_time(str, TRUE);
    +
    + if (g_date_time_compare(stamp, t) > 0)
    + diff = g_date_time_difference(stamp, t);
    else
    - diff = t - stamp;
    -
    - if (diff > (14 * 60 * 60))
    - {
    + diff = g_date_time_difference(t, stamp);
    +
    + if (diff > (14LL * G_TIME_SPAN_HOUR)) {
    if (day <= 12)
    {
    /* Swap day & month variables, to see if it's a non-US date. */
    g_free(str);
    str = g_strdup_printf("%04i-%02i-%02iT%02i:%02i:%02i", year, month, day, hour, min, sec);
    - t = purple_str_to_time(str, TRUE, &tm, NULL, NULL);
    -
    - if (stamp > t)
    - diff = stamp - t;
    + t = purple_str_to_date_time(str, TRUE);
    +
    + if (g_date_time_compare(stamp, t) > 0)
    + diff = g_date_time_difference(stamp, t);
    else
    - diff = t - stamp;
    -
    - if (diff > (14 * 60 * 60))
    - {
    + diff = g_date_time_difference(t, stamp);
    +
    + if (diff > (14LL * G_TIME_SPAN_HOUR)) {
    /* We got a time, it's not impossible, but
    * the diff is too large. Display the UTC time. */
    g_free(str);
    - *tm_out = &tm2;
    return stamp;
    }
    else
    @@ -479,26 +452,19 @@
    /* We got a time, it's not impossible, but
    * the diff is too large. Display the UTC time. */
    g_free(str);
    - *tm_out = &tm2;
    return stamp;
    }
    }
    /* If we got here, the time is legal with a reasonable offset.
    * Let's find out if it's in our TZ. */
    - if (purple_str_to_time(str, FALSE, &tm, NULL, NULL) == stamp)
    + if (purple_str_to_date_time(str, FALSE) == stamp)
    {
    g_free(str);
    - *tm_out = &tm;
    return stamp;
    }
    g_free(str);
    - /* The time isn't in our TZ, but it's reasonable. */
    -#ifdef HAVE_STRUCT_TM_TM_ZONE
    - tm.tm_zone = " ";
    -#endif
    - *tm_out = &tm;
    return stamp;
    }
    @@ -737,8 +703,7 @@
    * The session ID differs from the last message.
    * Thus, this is the start of a new conversation.
    */
    - struct tm *tm;
    - time_t stamp;
    + GDateTime *stamp;
    PurpleLog *log;
    data = g_new0(struct msn_logger_data, 1);
    @@ -748,12 +713,14 @@
    data->text = NULL;
    data->last_log = FALSE;
    - stamp = msn_logger_parse_timestamp(message, &tm);
    -
    - log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, stamp, tm);
    + stamp = msn_logger_parse_timestamp(message);
    +
    + log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, stamp);
    log->logger = msn_logger;
    log->logger_data = data;
    + g_date_time_unref(stamp);
    +
    list = g_list_prepend(list, log);
    }
    old_session_id = session_id;
    @@ -808,7 +775,7 @@
    PurpleXmlNode *to;
    enum name_guesses name_guessed = NAME_GUESS_UNKNOWN;
    const char *their_name;
    - struct tm *tm = NULL;
    + GDateTime *dt = NULL;
    char *timestamp;
    char *tmp;
    const char *style;
    @@ -987,12 +954,13 @@
    text = g_string_append(text, ";\">");
    }
    - if (msn_logger_parse_timestamp(message, &tm)) {
    - timestamp = g_strdup_printf(
    - "<font size=\"2\">(%02u:%02u:%02u)</font> ",
    - tm->tm_hour, tm->tm_min, tm->tm_sec);
    + if ((dt = msn_logger_parse_timestamp(message)) != NULL) {
    + timestamp = g_date_time_format(
    + dt,
    + "<font size=\"2\">(%H:%M:%s)</font> ");
    text = g_string_append(text, timestamp);
    g_free(timestamp);
    + g_date_time_unref(dt);
    } else {
    text = g_string_append(text,
    "<font size=\"2\">(00:00:00)</font> ");
    @@ -1208,8 +1176,9 @@
    timestamp++;
    if (*timestamp == ')') {
    - char *month;
    - struct tm tm;
    + char *month_str;
    + gint year, month, day, hour, minute, second;
    + GDateTime *dt;
    *timestamp = '\0';
    if (line[0] && line[1] && line[2])
    @@ -1224,7 +1193,7 @@
    timestamp++;
    /* Parse out the month. */
    - month = timestamp;
    + month_str = timestamp;
    while (*timestamp && (*timestamp != ' '))
    timestamp++;
    *timestamp = '\0';
    @@ -1232,22 +1201,16 @@
    /* Parse the day, time, and year. */
    if (sscanf(timestamp, "%u %u:%u:%u %u",
    - &tm.tm_mday, &tm.tm_hour,
    - &tm.tm_min, &tm.tm_sec,
    - &tm.tm_year) != 5) {
    + &day, &hour,
    + &minute, &second,
    + &year) != 5) {
    purple_debug_error("Trillian log timestamp parse",
    "Session Start parsing error\n");
    } else {
    PurpleLog *log;
    - tm.tm_year -= 1900;
    -
    - /* Let the C library deal with
    - * daylight savings time.
    - */
    - tm.tm_isdst = -1;
    - tm.tm_mon = get_month(month);
    + month = get_month(month_str);
    data = g_new0(
    struct trillian_logger_data, 1);
    @@ -1257,12 +1220,16 @@
    data->their_nickname =
    g_strdup(their_nickname);
    - /* XXX: Look into this later... Should we pass in a struct tm? */
    + /* XXX: Look into this later... Should we figure out a timezone? */
    + dt = g_date_time_new_local(year, month, day, hour, minute, second);
    +
    log = purple_log_new(PURPLE_LOG_IM,
    - sn, account, NULL, mktime(&tm), NULL);
    + sn, account, NULL, dt);
    log->logger = trillian_logger;
    log->logger_data = data;
    + g_date_time_unref(dt);
    +
    list = g_list_prepend(list, log);
    }
    }
    @@ -1634,7 +1601,7 @@
    #define QIP_LOG_OUT_MESSAGE (QIP_LOG_DELIMITER ">-")
    #define QIP_LOG_IN_MESSAGE_ESC (QIP_LOG_DELIMITER "&lt;-")
    #define QIP_LOG_OUT_MESSAGE_ESC (QIP_LOG_DELIMITER "&gt;-")
    -#define QIP_LOG_TIMEOUT (60*60)
    +#define QIP_LOG_TIMEOUT (G_TIME_SPAN_HOUR)
    static PurpleLogLogger *qip_logger;
    @@ -1655,9 +1622,9 @@
    char *path;
    char *contents;
    struct qip_logger_data *data = NULL;
    - struct tm prev_tm;
    - struct tm tm;
    - gboolean prev_tm_init = FALSE;
    + GDateTime *prev_dt = NULL;
    + GDateTime *dt = NULL;
    + gint year, month, day, hour, minute, second;
    gboolean main_cycle = TRUE;
    char *c;
    char *start_log;
    @@ -1668,8 +1635,6 @@
    g_return_val_if_fail(sn != NULL, NULL);
    g_return_val_if_fail(account != NULL, NULL);
    - memset(&tm, 0, sizeof(tm));
    -
    /* QIP only supports ICQ. */
    if (!purple_strequal(purple_account_get_protocol_id(account), "prpl-icq"))
    return NULL;
    @@ -1740,24 +1705,18 @@
    /* Parse the time, day, month and year */
    if (sscanf(timestamp, "%u:%u:%u %u/%u/%u",
    - &tm.tm_hour, &tm.tm_min, &tm.tm_sec,
    - &tm.tm_mday, &tm.tm_mon, &tm.tm_year) != 6) {
    + &hour, &minute, &second,
    + &day, &month, &year) != 6) {
    purple_debug_error("QIP logger list",
    "Parsing timestamp error\n");
    } else {
    - tm.tm_mon -= 1;
    - tm.tm_year -= 1900;
    -
    - /* Let the C library deal with
    - * daylight savings time. */
    - tm.tm_isdst = -1;
    -
    - if (!prev_tm_init) {
    - prev_tm = tm;
    - prev_tm_init = TRUE;
    + g_date_time_unref(dt);
    + dt = g_date_time_new_local(year, month, day, hour, minute, second);
    + if (!prev_dt) {
    + prev_dt = dt;
    } else {
    - add_new_log = difftime(mktime(&tm), mktime(&prev_tm)) > QIP_LOG_TIMEOUT;
    + add_new_log = g_date_time_difference(dt, prev_dt) > QIP_LOG_TIMEOUT;
    }
    }
    }
    @@ -1769,7 +1728,7 @@
    }
    /* adding log */
    - if (add_new_log && prev_tm_init) {
    + if (add_new_log && prev_dt) {
    PurpleLog *log;
    /* filling data */
    @@ -1782,16 +1741,18 @@
    "Creating log: path = (%s); length = (%d); offset = (%d)\n",
    data->path, data->length, data->offset);
    - /* XXX: Look into this later... Should we pass in a struct tm? */
    + /* XXX: Look into this later... Should we figure out a timezone? */
    + dt = g_date_time_new_local(year, month, day, hour, minute, second);
    log = purple_log_new(PURPLE_LOG_IM, sn, account,
    - NULL, mktime(&prev_tm), NULL);
    + NULL, prev_dt);
    log->logger = qip_logger;
    log->logger_data = data;
    list = g_list_prepend(list, log);
    - prev_tm = tm;
    + g_date_time_unref(prev_dt);
    + prev_dt = dt;
    start_log = new_line;
    }
    @@ -2042,26 +2003,21 @@
    gboolean found_start = FALSE;
    char *start_log = c;
    int offset = 0;
    - struct tm tm;
    + gint year, month, day, hour, minute, second;
    + GDateTime *dt;
    while (c && *c) {
    if (purple_str_has_prefix(c, AMSN_LOG_CONV_START)) {
    - char month[4];
    + char month_str[4];
    if (sscanf(c + strlen(AMSN_LOG_CONV_START),
    "%u %3s %u %u:%u:%u",
    - &tm.tm_mday, (char*)&month, &tm.tm_year,
    - &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
    + &day, (char*)&month_str, &year,
    + &hour, &minute, &second) != 6) {
    found_start = FALSE;
    purple_debug_error("aMSN logger",
    "Error parsing start date for %s\n",
    filename);
    } else {
    - tm.tm_year -= 1900;
    -
    - /* Let the C library deal with
    - * daylight savings time.
    - */
    - tm.tm_isdst = -1;
    - tm.tm_mon = get_month(month);
    + month = get_month(month_str);
    found_start = TRUE;
    offset = c - contents;
    @@ -2074,11 +2030,13 @@
    data->length = c - start_log
    + strlen(AMSN_LOG_CONV_END)
    + strlen(AMSN_LOG_CONV_EXTRA);
    - log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, mktime(&tm), NULL);
    + dt = g_date_time_new_local(year, month, day, hour, minute, second);
    + log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, dt);
    log->logger = amsn_logger;
    log->logger_data = data;
    list = g_list_prepend(list, log);
    found_start = FALSE;
    + g_date_time_unref(dt);
    purple_debug_info("aMSN logger",
    "Found log for %s:"
    @@ -2100,10 +2058,12 @@
    data->length = c - start_log
    + strlen(AMSN_LOG_CONV_END)
    + strlen(AMSN_LOG_CONV_EXTRA);
    - log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, mktime(&tm), NULL);
    + dt = g_date_time_new_local(year, month, day, hour, minute, second);
    + log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, dt);
    log->logger = amsn_logger;
    log->logger_data = data;
    list = g_list_prepend(list, log);
    + g_date_time_unref(dt);
    purple_debug_info("aMSN logger",
    "Found log for %s:"
    @@ -2522,7 +2482,7 @@
    g_free(path);
    path = NULL;
    }
    -
    +
    if (path && !g_file_get_contents(path, &contents, NULL, &error)) {
    purple_debug_error("Trillian talk.ini read",
    "Error reading talk.ini: %s\n",
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/plugins/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,88 @@
    +subdir('keyrings')
    +
    +if PLUGINS
    + autoaccept = library('autoaccept', 'autoaccept.c',
    + dependencies : [libpurple_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PURPLE_PLUGINDIR)
    +
    + buddynote = library('buddynote', 'buddynote.c',
    + dependencies : [libpurple_dep],
    + name_prefix : '',
    + install : true, install_dir : PURPLE_PLUGINDIR)
    +
    + codeinline = library('codeinline', 'codeinline.c',
    + dependencies : [libpurple_dep],
    + name_prefix : '')
    +
    + debug_example = library('debug_example', 'debug_example.c',
    + dependencies : [libpurple_dep],
    + name_prefix : '')
    +
    + helloworld = library('helloworld', 'helloworld.c',
    + dependencies : [libpurple_dep],
    + name_prefix : '')
    +
    + idle = library('idle', 'idle.c',
    + dependencies : [libpurple_dep],
    + name_prefix : '',
    + install : true, install_dir : PURPLE_PLUGINDIR)
    +
    + joinpart = library('joinpart', 'joinpart.c',
    + dependencies : [libpurple_dep],
    + name_prefix : '',
    + install : true, install_dir : PURPLE_PLUGINDIR)
    +
    + log_reader = library('log_reader', 'log_reader.c',
    + dependencies : [libpurple_dep],
    + name_prefix : '',
    + install : true, install_dir : PURPLE_PLUGINDIR)
    +
    + notify_example = library('notify_example', 'notify_example.c',
    + dependencies : [libpurple_dep],
    + name_prefix : '')
    +
    + offlinemsg = library('offlinemsg', 'offlinemsg.c',
    + dependencies : [libpurple_dep],
    + name_prefix : '',
    + install : true, install_dir : PURPLE_PLUGINDIR)
    +
    + one_time_password = library('one_time_password', 'one_time_password.c',
    + dependencies : [libpurple_dep],
    + name_prefix : '')
    +
    + pluginpref_example = library('pluginpref_example', 'pluginpref_example.c',
    + dependencies : [libpurple_dep],
    + name_prefix : '')
    +
    + psychic = library('psychic', 'psychic.c',
    + dependencies : [libpurple_dep],
    + name_prefix : '',
    + install : true, install_dir : PURPLE_PLUGINDIR)
    +
    + signals_test = library('signals-test', 'signals-test.c',
    + dependencies : [libpurple_dep],
    + name_prefix : '')
    +
    + simple = library('simple-plugin', 'simple.c',
    + dependencies : [libpurple_dep],
    + name_prefix : '')
    +
    + statenotify = library('statenotify', 'statenotify.c',
    + dependencies : [libpurple_dep],
    + name_prefix : '',
    + install : true, install_dir : PURPLE_PLUGINDIR)
    +
    + if enable_dbus
    + dbus_example_bindings_c = custom_target('dbus_example_bindings_c',
    + input : 'dbus-example.c',
    + output : 'dbus-example-bindings.ch',
    + command : [python,
    + meson.source_root() + '/libpurple/dbus-analyze-functions.py',
    + '--export-only', '-o', '@OUTPUT@', '@INPUT@'])
    +
    + dbus_example = library('dbus-example', 'dbus-example.c', dbus_example_bindings_c,
    + dependencies : [libpurple_dep, dbus],
    + name_prefix : '')
    + endif # enable_dbus
    +endif # PLUGINS
    --- a/libpurple/pounce.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/pounce.c Sun Oct 08 20:44:26 2017 +0300
    @@ -295,7 +295,7 @@
    schedule_pounces_save(void)
    {
    if (save_timer == 0)
    - save_timer = purple_timeout_add_seconds(5, save_cb, NULL);
    + save_timer = g_timeout_add_seconds(5, save_cb, NULL);
    }
    @@ -1194,7 +1194,7 @@
    {
    if (save_timer != 0)
    {
    - purple_timeout_remove(save_timer);
    + g_source_remove(save_timer);
    save_timer = 0;
    sync_pounces();
    }
    --- a/libpurple/pounce.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/pounce.h Sun Oct 08 20:44:26 2017 +0300
    @@ -358,7 +358,7 @@
    *
    * Returns a list of all registered buddy pounces.
    *
    - * Returns: (transfer none): The list of buddy pounces.
    + * Returns: (element-type PurplePounce) (transfer none): The list of buddy pounces.
    */
    GList *purple_pounces_get_all(void);
    @@ -368,8 +368,7 @@
    *
    * Returns a list of registered buddy pounces for the ui-type.
    *
    - * Returns: The list of buddy pounces. The list should be freed by
    - * the caller when it's no longer used.
    + * Returns: (element-type PurplePounce) (transfer container): The list of buddy pounces.
    */
    GList *purple_pounces_get_all_for_ui(const char *ui);
    --- a/libpurple/prefs.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/prefs.c Sun Oct 08 20:44:26 2017 +0300
    @@ -261,7 +261,7 @@
    PURPLE_PREFS_UI_OP_CALL(schedule_save);
    if (save_timer == 0)
    - save_timer = purple_timeout_add_seconds(5, save_cb, NULL);
    + save_timer = g_timeout_add_seconds(5, save_cb, NULL);
    }
    @@ -1743,7 +1743,7 @@
    {
    if (save_timer != 0)
    {
    - purple_timeout_remove(save_timer);
    + g_source_remove(save_timer);
    save_cb(NULL);
    }
    --- a/libpurple/prefs.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/prefs.h Sun Oct 08 20:44:26 2017 +0300
    @@ -75,9 +75,11 @@
    gconstpointer val, gpointer data);
    /**
    + * PurplePrefCallbackData:
    + *
    * Opaque type to carry callback information
    *
    - * @since 2.11.0
    + * Since: 2.11.0
    */
    typedef struct _PurplePrefCallbackData PurplePrefCallbackData;
    @@ -85,6 +87,8 @@
    typedef struct _PurplePrefsUiOps PurplePrefsUiOps;
    /**
    + * PurplePrefsUiOps:
    + *
    * Prefs UI operations. This allows overriding the prefs.xml storage with
    * anything else.
    *
    @@ -92,7 +96,7 @@
    * corresponding purple_prefs_* method, and disables the prefs.xml code for it.
    * This means that to do anything useful, all the methods must be implemented.
    *
    - * @since 2.11.0
    + * Since: 2.11.0
    */
    struct _PurplePrefsUiOps
    {
    @@ -159,18 +163,23 @@
    *****************************************************************************/
    /**
    + * purple_prefs_set_ui_ops:
    + * @ops: The UI operations structure.
    + *
    * Sets the UI operations structure to be used for preferences.
    *
    - * @param ops The UI operations structure.
    - * @since 2.11.0
    + * Since: 2.11.0
    */
    void purple_prefs_set_ui_ops(PurplePrefsUiOps *ops);
    /**
    + * purple_prefs_get_ui_ops:
    + *
    * Returns the UI operations structure used for preferences.
    *
    - * @return The UI operations structure in use.
    - * @since 2.11.0
    + * Returns: (transfer none): The UI operations structure in use.
    + *
    + * Since: 2.11.0
    */
    PurplePrefsUiOps *purple_prefs_get_ui_ops(void);
    @@ -241,7 +250,7 @@
    /**
    * purple_prefs_add_string_list:
    * @name: The name of the pref
    - * @value: The initial value to set
    + * @value: (element-type utf8) (transfer none): The initial value to set
    *
    * Add a new string list pref.
    *
    @@ -263,7 +272,7 @@
    /**
    * purple_prefs_add_path_list:
    * @name: The name of the pref
    - * @value: The initial value to set
    + * @value: (element-type utf8) (transfer none): The initial value to set
    *
    * Add a new path list pref.
    *
    @@ -337,7 +346,7 @@
    /**
    * purple_prefs_set_string_list:
    * @name: The name of the pref
    - * @value: The value to set
    + * @value: (element-type utf8) (transfer none): The value to set
    *
    * Set string list pref value
    */
    @@ -355,7 +364,7 @@
    /**
    * purple_prefs_set_path_list:
    * @name: The name of the pref
    - * @value: The value to set
    + * @value: (element-type utf8) (transfer none): The value to set
    *
    * Set path list pref value
    */
    @@ -418,7 +427,7 @@
    *
    * Get string list pref value
    *
    - * Returns: The value of the pref
    + * Returns: (element-type utf8): The value of the pref
    */
    GList *purple_prefs_get_string_list(const char *name);
    @@ -438,7 +447,7 @@
    *
    * Get path list pref value
    *
    - * Returns: The value of the pref
    + * Returns: (element-type utf8): The value of the pref
    */
    GList *purple_prefs_get_path_list(const char *name);
    @@ -448,9 +457,9 @@
    *
    * Returns a list of children for a pref
    *
    - * Returns: A list of newly allocated strings denoting the names of the children.
    - * Returns %NULL if there are no children or if pref doesn't exist.
    - * The caller must free all the strings and the list.
    + * Returns: (element-type utf8): A list of newly allocated strings denoting the
    + * names of the children. Returns %NULL if there are no children or if
    + * pref doesn't exist. The caller must free all the strings and the list.
    */
    GList *purple_prefs_get_children_names(const char *name);
    @@ -492,10 +501,12 @@
    void purple_prefs_trigger_callback(const char *name);
    /**
    + * purple_prefs_trigger_callback_object:
    + *
    * Trigger callbacks as if the pref changed, taking a #PurplePrefCallbackData
    * instead of a name
    *
    - * @since 2.11.0
    + * Since: 2.11.0
    */
    void purple_prefs_trigger_callback_object(PurplePrefCallbackData *data);
    --- a/libpurple/presence.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/presence.c Sun Oct 08 20:44:26 2017 +0300
    @@ -572,17 +572,22 @@
    if (log != NULL)
    {
    char *msg, *tmp;
    + GDateTime *dt;
    - if (idle)
    + if (idle) {
    tmp = g_strdup_printf(_("+++ %s became idle"), purple_account_get_username(account));
    - else
    + dt = g_date_time_new_from_unix_local(idle_time);
    + } else {
    tmp = g_strdup_printf(_("+++ %s became unidle"), purple_account_get_username(account));
    + dt = g_date_time_new_now_utc();
    + }
    msg = g_markup_escape_text(tmp, -1);
    g_free(tmp);
    purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
    purple_account_get_username(account),
    - (idle ? idle_time : current_time), msg);
    + dt, msg);
    + g_date_time_unref(dt);
    g_free(msg);
    }
    }
    @@ -806,7 +811,7 @@
    purple_buddy_presence_update_idle(PurplePresence *presence, gboolean old_idle)
    {
    PurpleBuddy *buddy = purple_buddy_presence_get_buddy(PURPLE_BUDDY_PRESENCE(presence));
    - time_t current_time = time(NULL);
    + GDateTime *current_time = g_date_time_new_now_utc();
    PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
    PurpleAccount *account = purple_buddy_get_account(buddy);
    gboolean idle = purple_presence_is_idle(presence);
    @@ -826,7 +831,8 @@
    g_free(tmp);
    purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
    - purple_buddy_get_alias(buddy), current_time, tmp2);
    + purple_buddy_get_alias(buddy),
    + current_time, tmp2);
    g_free(tmp2);
    }
    }
    @@ -846,7 +852,8 @@
    g_free(tmp);
    purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
    - purple_buddy_get_alias(buddy), current_time, tmp2);
    + purple_buddy_get_alias(buddy),
    + current_time, tmp2);
    g_free(tmp2);
    }
    }
    @@ -864,6 +871,8 @@
    if (ops != NULL && ops->update != NULL)
    ops->update(purple_blist_get_buddy_list(), (PurpleBlistNode *)buddy);
    +
    + g_date_time_unref(current_time);
    }
    PurpleBuddy *
    --- a/libpurple/presence.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/presence.h Sun Oct 08 20:44:26 2017 +0300
    @@ -302,7 +302,7 @@
    *
    * Returns all the statuses in a presence.
    *
    - * Returns: (transfer none): The statuses.
    + * Returns: (element-type PurpleStatus) (transfer none): The statuses.
    */
    GList *purple_presence_get_statuses(const PurplePresence *presence);
    --- a/libpurple/protocols.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols.h Sun Oct 08 20:44:26 2017 +0300
    @@ -466,7 +466,7 @@
    *
    * Retrieves the list of stock status types from a protocol.
    *
    - * Returns: List of statuses
    + * Returns: (element-type PurpleStatus): List of statuses
    */
    GList *purple_protocol_get_statuses(PurpleAccount *account,
    PurplePresence *presence);
    @@ -608,8 +608,8 @@
    *
    * Returns a list of all loaded protocols.
    *
    - * Returns: A list of all loaded protocols. The list is owned by the caller, and
    - * must be g_list_free()d to avoid leaking the nodes.
    + * Returns: (element-type PurpleProtocol) (transfer container): A list of all
    + * loaded protocols.
    */
    GList *purple_protocols_get_all(void);
    --- a/libpurple/protocols/bonjour/bonjour.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/bonjour/bonjour.c Sun Oct 08 20:44:26 2017 +0300
    @@ -564,7 +564,7 @@
    fullname = g_utf16_to_utf8(username, -1, NULL, NULL, NULL);
    }
    - purple_timeout_add(0, _set_default_name_cb, fullname);
    + g_timeout_add(0, _set_default_name_cb, fullname);
    return NULL;
    }
    --- a/libpurple/protocols/bonjour/jabber.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/bonjour/jabber.c Sun Oct 08 20:44:26 2017 +0300
    @@ -1139,7 +1139,7 @@
    bb->conversation = NULL;
    }
    - bconv->close_timeout = purple_timeout_add(0, _async_bonjour_jabber_close_conversation_cb, bconv);
    + bconv->close_timeout = g_timeout_add(0, _async_bonjour_jabber_close_conversation_cb, bconv);
    }
    void
    @@ -1210,7 +1210,7 @@
    bonjour_parser_setup(bconv);
    if (bconv->close_timeout != 0)
    - purple_timeout_remove(bconv->close_timeout);
    + g_source_remove(bconv->close_timeout);
    g_free(bconv->buddy_name);
    g_free(bconv->ip);
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/protocols/bonjour/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,36 @@
    +BONJOURSOURCES = [
    + 'bonjour.c',
    + 'bonjour.h',
    + 'buddy.c',
    + 'buddy.h',
    + 'jabber.c',
    + 'jabber.h',
    + 'mdns_common.c',
    + 'mdns_common.h',
    + 'mdns_interface.h',
    + 'mdns_types.h',
    + 'parser.c',
    + 'parser.h',
    + 'bonjour_ft.c',
    + 'bonjour_ft.h'
    +]
    +
    +if IS_WIN32
    + BONJOURSOURCES += ['dns_sd_proxy.c', 'mdns_dns_sd.c']
    + bonjour_link_args = ['-lnetapi32']
    +else
    + BONJOURSOURCES += ['mdns_avahi.c']
    + bonjour_link_args = []
    +endif
    +
    +if STATIC_BONJOUR
    + bonjour_prpl = static_library('bonjour', BONJOURSOURCES,
    + c_args : '-DPURPLE_STATIC_PRPL',
    + link_args : bonjour_link_args,
    + dependencies : [libxml, avahi, libpurple_dep, glib, ws2_32])
    +elif DYNAMIC_BONJOUR
    + bonjour_prpl = shared_library('bonjour', BONJOURSOURCES,
    + link_args : bonjour_link_args,
    + dependencies : [libxml, avahi, libpurple_dep, glib, ws2_32],
    + install : true, install_dir : PURPLE_PLUGINDIR)
    +endif
    --- a/libpurple/protocols/facebook/Makefile.am Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/facebook/Makefile.am Sun Oct 08 20:44:26 2017 +0300
    @@ -48,6 +48,5 @@
    -I$(top_srcdir) \
    $(GLIB_CFLAGS) \
    $(JSON_CFLAGS) \
    - $(ZLIB_CFLAGS) \
    $(GPLUGIN_CFLAGS) \
    $(DEBUG_CFLAGS)
    --- a/libpurple/protocols/facebook/api.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/facebook/api.c Sun Oct 08 20:44:26 2017 +0300
    @@ -1858,8 +1858,18 @@
    FB_API_TCHK(fb_thrift_read_i64(thft, NULL));
    break;
    + case 6:
    + /* Unknown new field */
    + FB_API_TCHK(type == FB_THRIFT_TYPE_I64);
    + FB_API_TCHK(fb_thrift_read_i64(thft, NULL));
    + break;
    +
    default:
    - FB_API_TCHK(FALSE);
    + /* Try to read unknown fields as varint */
    + FB_API_TCHK(type == FB_THRIFT_TYPE_I16 ||
    + type == FB_THRIFT_TYPE_I32 ||
    + type == FB_THRIFT_TYPE_I64);
    + FB_API_TCHK(fb_thrift_read_i64(thft, NULL));
    break;
    }
    }
    --- a/libpurple/protocols/facebook/data.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/facebook/data.c Sun Oct 08 20:44:26 2017 +0300
    @@ -73,7 +73,7 @@
    g_hash_table_iter_init(&iter, priv->evs);
    while (g_hash_table_iter_next(&iter, NULL, &ptr)) {
    - purple_timeout_remove(GPOINTER_TO_UINT(ptr));
    + g_source_remove(GPOINTER_TO_UINT(ptr));
    }
    if (G_LIKELY(priv->api != NULL)) {
    @@ -284,7 +284,7 @@
    fb_data_clear_timeout(fata, name, TRUE);
    key = g_strdup(name);
    - id = purple_timeout_add(interval, func, data);
    + id = g_timeout_add(interval, func, data);
    g_hash_table_replace(priv->evs, key, GUINT_TO_POINTER(id));
    }
    @@ -302,7 +302,7 @@
    id = GPOINTER_TO_UINT(ptr);
    if ((id > 0) && remove) {
    - purple_timeout_remove(id);
    + g_source_remove(id);
    }
    g_hash_table_remove(priv->evs, name);
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/protocols/facebook/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,35 @@
    +FACEBOOKSOURCES = [
    + 'api.c',
    + 'api.h',
    + 'data.c',
    + 'data.h',
    + 'facebook.h',
    + 'facebook.c',
    + 'http.c',
    + 'http.h',
    + 'id.h',
    + 'json.c',
    + 'json.h',
    + 'mqtt.c',
    + 'mqtt.h',
    + 'thrift.c',
    + 'thrift.h',
    + 'util.c',
    + 'util.h'
    +]
    +
    +if STATIC_FACEBOOK
    + facebook_prpl = static_library('facebook', FACEBOOKSOURCES,
    + c_args : '-DPURPLE_STATIC_PRPL',
    + dependencies : [json, libpurple_dep, glib])
    +elif DYNAMIC_FACEBOOK
    + facebook_prpl = shared_library('facebook', FACEBOOKSOURCES,
    + dependencies : [json, libpurple_dep, glib],
    + install : true, install_dir : PURPLE_PLUGINDIR)
    +endif
    +
    +# Used to produce docs.
    +facebook_inc = include_directories('.')
    +facebook_dep = declare_dependency(
    + link_with : facebook_prpl,
    + dependencies : [json, libpurple_dep, glib])
    --- a/libpurple/protocols/facebook/mqtt.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/facebook/mqtt.c Sun Oct 08 20:44:26 2017 +0300
    @@ -225,7 +225,7 @@
    priv = mqtt->priv;
    if (priv->tev > 0) {
    - purple_timeout_remove(priv->tev);
    + g_source_remove(priv->tev);
    priv->tev = 0;
    }
    @@ -300,7 +300,7 @@
    FbMqttPrivate *priv = mqtt->priv;
    if (priv->tev > 0) {
    - purple_timeout_remove(priv->tev);
    + g_source_remove(priv->tev);
    priv->tev = 0;
    }
    }
    @@ -311,7 +311,7 @@
    FbMqttPrivate *priv = mqtt->priv;
    fb_mqtt_timeout_clear(mqtt);
    - priv->tev = purple_timeout_add(FB_MQTT_TIMEOUT_CONN,
    + priv->tev = g_timeout_add(FB_MQTT_TIMEOUT_CONN,
    fb_mqtt_cb_timeout, mqtt);
    }
    @@ -337,7 +337,7 @@
    FbMqttPrivate *priv = mqtt->priv;
    fb_mqtt_timeout_clear(mqtt);
    - priv->tev = purple_timeout_add(FB_MQTT_TIMEOUT_PING,
    + priv->tev = g_timeout_add(FB_MQTT_TIMEOUT_PING,
    fb_mqtt_cb_ping, mqtt);
    }
    --- a/libpurple/protocols/gg/avatar.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/gg/avatar.c Sun Oct 08 20:44:26 2017 +0300
    @@ -90,14 +90,14 @@
    avdata->current_update = NULL;
    avdata->own_data = g_new0(ggp_avatar_own_data, 1);
    - avdata->timer = purple_timeout_add_seconds(1, ggp_avatar_timer_cb, gc);
    + avdata->timer = g_timeout_add_seconds(1, ggp_avatar_timer_cb, gc);
    }
    void ggp_avatar_cleanup(PurpleConnection *gc)
    {
    ggp_avatar_session_data *avdata = ggp_avatar_get_avdata(gc);
    - purple_timeout_remove(avdata->timer);
    + g_source_remove(avdata->timer);
    if (avdata->current_update != NULL) {
    ggp_avatar_buddy_update_req *current_update =
    --- a/libpurple/protocols/gg/chat.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/gg/chat.c Sun Oct 08 20:44:26 2017 +0300
    @@ -610,6 +610,6 @@
    * purple_roomlist_set_in_progress(roomlist, FALSE);
    */
    g_object_ref(roomlist);
    - purple_timeout_add(1, ggp_chat_roomlist_get_list_finish, roomlist);
    + g_timeout_add(1, ggp_chat_roomlist_get_list_finish, roomlist);
    return roomlist;
    }
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/protocols/gg/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,62 @@
    +GGSOURCES = [
    + 'avatar.c',
    + 'avatar.h',
    + 'blist.c',
    + 'blist.h',
    + 'chat.c',
    + 'chat.h',
    + 'edisc.c',
    + 'edisc.h',
    + 'gg.c',
    + 'gg.h',
    + 'html.c',
    + 'html.h',
    + 'image-prpl.c',
    + 'image-prpl.h',
    + 'keymapper.c',
    + 'keymapper.h',
    + 'libgadu-events.c',
    + 'libgadu-events.h',
    + 'libgaduw.c',
    + 'libgaduw.h',
    + 'message-prpl.c',
    + 'message-prpl.h',
    + 'multilogon.c',
    + 'multilogon.h',
    + 'pubdir-prpl.c',
    + 'pubdir-prpl.h',
    + 'purplew.c',
    + 'purplew.h',
    + 'resolver-purple.c',
    + 'resolver-purple.h',
    + 'roster.c',
    + 'roster.h',
    + 'servconn.c',
    + 'servconn.h',
    + 'status.c',
    + 'status.h',
    + 'tcpsocket.c',
    + 'tcpsocket.h',
    + 'utils.c',
    + 'utils.h',
    + 'validator.c',
    + 'validator.h',
    + 'xml.c',
    + 'xml.h',
    + 'oauth/oauth.c',
    + 'oauth/oauth.h',
    + 'oauth/oauth-parameter.c',
    + 'oauth/oauth-parameter.h',
    + 'oauth/oauth-purple.c',
    + 'oauth/oauth-purple.h'
    +]
    +
    +if STATIC_GG
    + gg_prpl = static_library('gg', GGSOURCES,
    + c_args : '-DPURPLE_STATIC_PRPL',
    + dependencies : [libgadu, json, libpurple_dep, glib])
    +elif DYNAMIC_GG
    + gg_prpl = shared_library('gg', GGSOURCES,
    + dependencies : [libgadu, json, libpurple_dep, glib],
    + install : true, install_dir : PURPLE_PLUGINDIR)
    +endif
    --- a/libpurple/protocols/gg/roster.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/gg/roster.c Sun Oct 08 20:44:26 2017 +0300
    @@ -237,7 +237,7 @@
    rdata->is_updating = FALSE;
    if (ggp_roster_enabled())
    - rdata->timer = purple_timeout_add_seconds(2,
    + rdata->timer = g_timeout_add_seconds(2,
    ggp_roster_timer_cb, gc);
    }
    @@ -246,7 +246,7 @@
    ggp_roster_session_data *rdata = ggp_roster_get_rdata(gc);
    if (rdata->timer)
    - purple_timeout_remove(rdata->timer);
    + g_source_remove(rdata->timer);
    ggp_roster_content_free(rdata->content);
    g_list_free_full(rdata->sent_updates, ggp_roster_change_free);
    g_list_free_full(rdata->pending_updates, ggp_roster_change_free);
    --- a/libpurple/protocols/irc/irc.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/irc/irc.c Sun Oct 08 20:44:26 2017 +0300
    @@ -463,7 +463,7 @@
    g_clear_object(&irc->conn);
    if (irc->timer)
    - purple_timeout_remove(irc->timer);
    + g_source_remove(irc->timer);
    g_hash_table_destroy(irc->cmds);
    g_hash_table_destroy(irc->msgs);
    g_hash_table_destroy(irc->buddies);
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/protocols/irc/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,18 @@
    +IRCSOURCES = [
    + 'cmds.c',
    + 'dcc_send.c',
    + 'irc.c',
    + 'irc.h',
    + 'msgs.c',
    + 'parse.c'
    +]
    +
    +if STATIC_IRC
    + irc_prpl = static_library('irc', IRCSOURCES,
    + c_args : '-DPURPLE_STATIC_PRPL',
    + dependencies : [sasl, libpurple_dep, glib, gio, ws2_32])
    +elif DYNAMIC_IRC
    + irc_prpl = shared_library('irc', IRCSOURCES,
    + dependencies : [sasl, libpurple_dep, glib, gio, ws2_32],
    + install : true, install_dir : PURPLE_PLUGINDIR)
    +endif
    --- a/libpurple/protocols/irc/msgs.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/irc/msgs.c Sun Oct 08 20:44:26 2017 +0300
    @@ -123,7 +123,7 @@
    irc_blist_timeout(irc);
    if (!irc->timer)
    - irc->timer = purple_timeout_add_seconds(45, (GSourceFunc)irc_blist_timeout, (gpointer)irc);
    + irc->timer = g_timeout_add_seconds(45, (GSourceFunc)irc_blist_timeout, (gpointer)irc);
    }
    /* This function is ugly, but it's really an error handler. */
    --- a/libpurple/protocols/jabber/bosh.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/jabber/bosh.c Sun Oct 08 20:44:26 2017 +0300
    @@ -150,7 +150,7 @@
    conn->payload_reqs = NULL;
    if (conn->send_timer)
    - purple_timeout_remove(conn->send_timer);
    + g_source_remove(conn->send_timer);
    purple_http_conn_cancel(conn->sc_req);
    conn->sc_req = NULL;
    @@ -270,7 +270,7 @@
    g_return_if_fail(conn != NULL);
    if (conn->send_timer != 0) {
    - purple_timeout_remove(conn->send_timer);
    + g_source_remove(conn->send_timer);
    conn->send_timer = 0;
    }
    @@ -340,7 +340,7 @@
    g_string_append(conn->send_buff, data);
    if (conn->send_timer == 0) {
    - conn->send_timer = purple_timeout_add(
    + conn->send_timer = g_timeout_add(
    JABBER_BOSH_SEND_DELAY,
    jabber_bosh_connection_send_delayed, conn);
    }
    --- a/libpurple/protocols/jabber/buddy.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/jabber/buddy.c Sun Oct 08 20:44:26 2017 +0300
    @@ -485,7 +485,7 @@
    }
    if (js->vcard_timer) {
    - purple_timeout_remove(js->vcard_timer);
    + g_source_remove(js->vcard_timer);
    js->vcard_timer = 0;
    }
    @@ -709,7 +709,7 @@
    {
    /* Remove the timeout, which would otherwise trigger jabber_buddy_get_info_timeout() */
    if (jbi->timeout_handle > 0)
    - purple_timeout_remove(jbi->timeout_handle);
    + g_source_remove(jbi->timeout_handle);
    g_free(jbi->jid);
    g_hash_table_destroy(jbi->resources);
    @@ -977,7 +977,7 @@
    * <error code="500" type="wait"><internal-server-error/></error>.
    */
    if (js->googletalk)
    - js->vcard_timer = purple_timeout_add_seconds(10, set_own_vcard_cb,
    + js->vcard_timer = g_timeout_add_seconds(10, set_own_vcard_cb,
    js);
    else
    jabber_set_info(js->gc, purple_account_get_user_info(account));
    @@ -1644,7 +1644,7 @@
    }
    js->pending_buddy_info_requests = g_slist_prepend(js->pending_buddy_info_requests, jbi);
    - jbi->timeout_handle = purple_timeout_add_seconds(30, jabber_buddy_get_info_timeout, jbi);
    + jbi->timeout_handle = g_timeout_add_seconds(30, jabber_buddy_get_info_timeout, jbi);
    }
    void jabber_buddy_get_info(PurpleConnection *gc, const char *who)
    --- a/libpurple/protocols/jabber/caps.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/jabber/caps.c Sun Oct 08 20:44:26 2017 +0300
    @@ -221,7 +221,7 @@
    schedule_caps_save(void)
    {
    if (save_timer == 0)
    - save_timer = purple_timeout_add_seconds(5, do_jabber_caps_store, NULL);
    + save_timer = g_timeout_add_seconds(5, do_jabber_caps_store, NULL);
    }
    static void
    @@ -336,7 +336,7 @@
    void jabber_caps_uninit(void)
    {
    if (save_timer != 0) {
    - purple_timeout_remove(save_timer);
    + g_source_remove(save_timer);
    save_timer = 0;
    do_jabber_caps_store(NULL);
    }
    --- a/libpurple/protocols/jabber/jabber.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/jabber/jabber.c Sun Oct 08 20:44:26 2017 +0300
    @@ -640,7 +640,7 @@
    js->last_ping = now;
    jabber_keepalive_ping(js);
    - js->keepalive_timeout = purple_timeout_add_seconds(120,
    + js->keepalive_timeout = g_timeout_add_seconds(120,
    (GSourceFunc)(jabber_keepalive_timeout), gc);
    }
    }
    @@ -1165,7 +1165,7 @@
    static void
    jabber_connection_schedule_close(JabberStream *js)
    {
    - js->conn_close_timeout = purple_timeout_add(0, conn_close_cb, js);
    + js->conn_close_timeout = g_timeout_add(0, conn_close_cb, js);
    }
    static void
    @@ -1725,14 +1725,14 @@
    g_free(js->old_track);
    if (js->vcard_timer != 0)
    - purple_timeout_remove(js->vcard_timer);
    + g_source_remove(js->vcard_timer);
    if (js->keepalive_timeout != 0)
    - purple_timeout_remove(js->keepalive_timeout);
    + g_source_remove(js->keepalive_timeout);
    if (js->inactivity_timer != 0)
    - purple_timeout_remove(js->inactivity_timer);
    + g_source_remove(js->inactivity_timer);
    if (js->conn_close_timeout != 0)
    - purple_timeout_remove(js->conn_close_timeout);
    + g_source_remove(js->conn_close_timeout);
    g_cancellable_cancel(js->cancellable);
    g_object_unref(G_OBJECT(js->cancellable));
    @@ -2123,14 +2123,14 @@
    void jabber_stream_restart_inactivity_timer(JabberStream *js)
    {
    if (js->inactivity_timer != 0) {
    - purple_timeout_remove(js->inactivity_timer);
    + g_source_remove(js->inactivity_timer);
    js->inactivity_timer = 0;
    }
    g_return_if_fail(js->max_inactivity > 0);
    js->inactivity_timer =
    - purple_timeout_add_seconds(js->max_inactivity,
    + g_timeout_add_seconds(js->max_inactivity,
    inactivity_cb, js);
    }
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/protocols/jabber/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,116 @@
    +JABBERSOURCES = [
    + 'adhoccommands.c',
    + 'adhoccommands.h',
    + 'auth.c',
    + 'auth.h',
    + 'auth_digest_md5.c',
    + 'auth_digest_md5.h',
    + 'auth_plain.c',
    + 'auth_scram.c',
    + 'auth_scram.h',
    + 'buddy.c',
    + 'buddy.h',
    + 'bosh.c',
    + 'bosh.h',
    + 'caps.c',
    + 'caps.h',
    + 'chat.c',
    + 'chat.h',
    + 'data.c',
    + 'data.h',
    + 'disco.c',
    + 'disco.h',
    + 'google/gmail.c',
    + 'google/gmail.h',
    + 'google/google.c',
    + 'google/google.h',
    + 'google/google_p2p.c',
    + 'google/google_p2p.h',
    + 'google/google_presence.c',
    + 'google/google_presence.h',
    + 'google/google_roster.c',
    + 'google/google_roster.h',
    + 'google/google_session.c',
    + 'google/google_session.h',
    + 'google/jingleinfo.c',
    + 'google/jingleinfo.h',
    + 'google/relay.c',
    + 'google/relay.h',
    + 'gtalk.c',
    + 'gtalk.h',
    + 'ibb.c',
    + 'ibb.h',
    + 'iq.c',
    + 'iq.h',
    + 'jabber.c',
    + 'jabber.h',
    + 'jingle/jingle.c',
    + 'jingle/jingle.h',
    + 'jingle/content.c',
    + 'jingle/content.h',
    + 'jingle/iceudp.c',
    + 'jingle/iceudp.h',
    + 'jingle/rawudp.c',
    + 'jingle/rawudp.h',
    + 'jingle/rtp.c',
    + 'jingle/rtp.h',
    + 'jingle/session.c',
    + 'jingle/session.h',
    + 'jingle/transport.c',
    + 'jingle/transport.h',
    + 'jutil.c',
    + 'jutil.h',
    + 'message.c',
    + 'message.h',
    + 'namespaces.h',
    + 'oob.c',
    + 'oob.h',
    + 'parser.c',
    + 'parser.h',
    + 'pep.c',
    + 'pep.h',
    + 'ping.c',
    + 'ping.h',
    + 'presence.c',
    + 'presence.h',
    + 'roster.c',
    + 'roster.h',
    + 'si.c',
    + 'si.h',
    + 'useravatar.c',
    + 'useravatar.h',
    + 'usermood.c',
    + 'usermood.h',
    + 'usernick.c',
    + 'usernick.h',
    + 'usertune.c',
    + 'usertune.h',
    + 'xdata.c',
    + 'xdata.h',
    + 'xmpp.c',
    + 'xmpp.h'
    +]
    +
    +if enable_cyrus_sasl
    + JABBERSOURCES += ['auth_cyrus.c']
    +endif
    +
    +if IS_WIN32
    + jabber_link_args = ['-Wl,--export-all-symbols']
    +else
    + jabber_link_args = []
    +endif
    +
    +if STATIC_JABBER
    + jabber_prpl = static_library('jabber', JABBERSOURCES,
    + c_args : '-DPURPLE_STATIC_PRPL',
    + link_args : jabber_link_args,
    + dependencies : [gstreamer, idn, libxml, sasl, libpurple_dep, glib, gio, math, ws2_32])
    +elif DYNAMIC_JABBER
    + jabber_prpl = shared_library('jabber', JABBERSOURCES,
    + link_args : jabber_link_args,
    + dependencies : [gstreamer, idn, libxml, sasl, libpurple_dep, glib, gio, math, ws2_32],
    + install : true, install_dir : PURPLE_PLUGINDIR)
    +endif
    +
    +subdir('tests')
    --- a/libpurple/protocols/jabber/ping.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/jabber/ping.c Sun Oct 08 20:44:26 2017 +0300
    @@ -35,7 +35,7 @@
    PurpleXmlNode *packet, gpointer data)
    {
    if (js->keepalive_timeout != 0) {
    - purple_timeout_remove(js->keepalive_timeout);
    + g_source_remove(js->keepalive_timeout);
    js->keepalive_timeout = 0;
    }
    }
    --- a/libpurple/protocols/jabber/si.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/jabber/si.c Sun Oct 08 20:44:26 2017 +0300
    @@ -128,7 +128,7 @@
    jsx->connect_data = NULL;
    if (jsx->connect_timeout > 0)
    - purple_timeout_remove(jsx->connect_timeout);
    + g_source_remove(jsx->connect_timeout);
    jsx->connect_timeout = 0;
    if(source < 0) {
    @@ -194,7 +194,7 @@
    jabber_si_bytestreams_ibb_timeout_remove(JabberSIXfer *jsx)
    {
    if (jsx->ibb_timeout_handle) {
    - purple_timeout_remove(jsx->ibb_timeout_handle);
    + g_source_remove(jsx->ibb_timeout_handle);
    jsx->ibb_timeout_handle = 0;
    }
    }
    @@ -252,7 +252,7 @@
    jabber_si_xfer_ibb_send_init(jsx->js, xfer);
    } else {
    /* setup a timeout to cancel waiting for IBB open */
    - jsx->ibb_timeout_handle = purple_timeout_add_seconds(30,
    + jsx->ibb_timeout_handle = g_timeout_add_seconds(30,
    jabber_si_bytestreams_ibb_timeout_cb, xfer);
    }
    /* if we are the receiver, just wait for IBB open, callback is
    @@ -273,7 +273,7 @@
    purple_proxy_connect_cancel(jsx->connect_data);
    jsx->connect_data = NULL;
    if (jsx->connect_timeout > 0)
    - purple_timeout_remove(jsx->connect_timeout);
    + g_source_remove(jsx->connect_timeout);
    jsx->connect_timeout = 0;
    }
    if (jsx->gpi != NULL)
    @@ -313,7 +313,7 @@
    /* When selecting a streamhost, timeout after STREAMHOST_CONNECT_TIMEOUT seconds, otherwise it takes forever */
    if (purple_xfer_get_xfer_type(xfer) != PURPLE_XFER_TYPE_SEND && jsx->connect_data != NULL)
    - jsx->connect_timeout = purple_timeout_add_seconds(
    + jsx->connect_timeout = g_timeout_add_seconds(
    STREAMHOST_CONNECT_TIMEOUT, connect_timeout_cb, xfer);
    jabber_id_free(dstjid);
    @@ -734,7 +734,7 @@
    && !jsx->ibb_session) {
    jabber_si_xfer_ibb_send_init(js, xfer);
    } else {
    - jsx->ibb_timeout_handle = purple_timeout_add_seconds(30,
    + jsx->ibb_timeout_handle = g_timeout_add_seconds(30,
    jabber_si_bytestreams_ibb_timeout_cb, xfer);
    }
    /* if we are receiver, just wait for IBB open stanza, callback
    @@ -775,7 +775,7 @@
    if (purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_SEND) {
    jabber_si_xfer_ibb_send_init(jsx->js, xfer);
    } else {
    - jsx->ibb_timeout_handle = purple_timeout_add_seconds(30,
    + jsx->ibb_timeout_handle = g_timeout_add_seconds(30,
    jabber_si_bytestreams_ibb_timeout_cb, xfer);
    }
    /* if we are the receiver, we are already set up...*/
    @@ -926,7 +926,7 @@
    /* if we are the sender, init the IBB session... */
    jabber_si_xfer_ibb_send_init(jsx->js, xfer);
    } else {
    - jsx->ibb_timeout_handle = purple_timeout_add_seconds(30,
    + jsx->ibb_timeout_handle = g_timeout_add_seconds(30,
    jabber_si_bytestreams_ibb_timeout_cb, xfer);
    }
    /* if we are the receiver, we should just wait... the IBB open
    @@ -1314,9 +1314,9 @@
    purple_network_remove_port_mapping(purple_xfer_get_fd(xfer));
    }
    if (jsx->connect_timeout > 0)
    - purple_timeout_remove(jsx->connect_timeout);
    + g_source_remove(jsx->connect_timeout);
    if (jsx->ibb_timeout_handle > 0)
    - purple_timeout_remove(jsx->ibb_timeout_handle);
    + g_source_remove(jsx->ibb_timeout_handle);
    if (jsx->streamhosts) {
    g_list_foreach(jsx->streamhosts, jabber_si_free_streamhost, NULL);
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/protocols/jabber/tests/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,8 @@
    +foreach prog : ['caps', 'digest_md5', 'scram', 'jutil']
    + e = executable(
    + 'test_jabber_' + prog, 'test_jabber_@0@.c'.format(prog),
    + link_with : [jabber_prpl],
    + dependencies : [libxml, libpurple_dep, glib])
    +
    + test('jabber_' + prog, e)
    +endforeach
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/protocols/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,12 @@
    +subdir('bonjour')
    +subdir('facebook')
    +subdir('gg')
    +subdir('irc')
    +subdir('jabber')
    +subdir('novell')
    +subdir('null')
    +subdir('oscar')
    +subdir('sametime')
    +subdir('silc')
    +subdir('simple')
    +subdir('zephyr')
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/protocols/novell/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,34 @@
    +NOVELLSOURCES = [
    + 'nmfield.h',
    + 'nmfield.c',
    + 'nmconn.h',
    + 'nmconn.c',
    + 'nmconference.h',
    + 'nmconference.c',
    + 'nmcontact.h',
    + 'nmcontact.c',
    + 'nmevent.h',
    + 'nmevent.c',
    + 'nmmessage.h',
    + 'nmmessage.c',
    + 'nmrequest.h',
    + 'nmrequest.c',
    + 'nmrtf.h',
    + 'nmrtf.c',
    + 'nmuser.h',
    + 'nmuser.c',
    + 'nmuserrecord.h',
    + 'nmuserrecord.c',
    + 'novell.h',
    + 'novell.c'
    +]
    +
    +if STATIC_NOVELL
    + novell_prpl = static_library('novell', NOVELLSOURCES,
    + c_args : '-DPURPLE_STATIC_PRPL',
    + dependencies : [libpurple_dep, glib, ws2_32])
    +elif DYNAMIC_NOVELL
    + novell_prpl = shared_library('novell', NOVELLSOURCES,
    + dependencies : [libpurple_dep, glib, ws2_32],
    + install : true, install_dir : PURPLE_PLUGINDIR)
    +endif
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/protocols/null/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,11 @@
    +NULLSOURCES = [
    + 'nullprpl.h',
    + 'nullprpl.c'
    +]
    +
    +# nullprpl isn't built by default; when it is built, it's dynamically linked
    +if DYNAMIC_NULL
    + null_prpl = shared_library('null', NULLSOURCES,
    + dependencies : [libpurple_dep, glib],
    + install : true, install_dir : PURPLE_PLUGINDIR)
    +endif
    --- a/libpurple/protocols/null/nullprpl.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/null/nullprpl.c Sun Oct 08 20:44:26 2017 +0300
    @@ -957,7 +957,7 @@
    }
    g_list_free(seen_ids);
    - purple_timeout_add(1 /* ms */, null_finish_get_roomlist, g_object_ref(roomlist));
    + g_timeout_add(1 /* ms */, null_finish_get_roomlist, g_object_ref(roomlist));
    return roomlist;
    }
    --- a/libpurple/protocols/oscar/flap_connection.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/oscar/flap_connection.c Sun Oct 08 20:44:26 2017 +0300
    @@ -271,7 +271,7 @@
    }
    if (conn->queued_timeout == 0)
    - conn->queued_timeout = purple_timeout_add(500, flap_connection_send_queued, conn);
    + conn->queued_timeout = g_timeout_add(500, flap_connection_send_queued, conn);
    return;
    }
    @@ -531,7 +531,7 @@
    }
    if (conn->queued_timeout > 0)
    - purple_timeout_remove(conn->queued_timeout);
    + g_source_remove(conn->queued_timeout);
    g_free(conn);
    @@ -546,7 +546,7 @@
    flap_connection_destroy(FlapConnection *conn, OscarDisconnectReason reason, const gchar *error_message)
    {
    if (conn->destroy_timeout != 0)
    - purple_timeout_remove(conn->destroy_timeout);
    + g_source_remove(conn->destroy_timeout);
    conn->disconnect_reason = reason;
    g_free(conn->error_message);
    conn->error_message = g_strdup(error_message);
    @@ -580,7 +580,7 @@
    conn->disconnect_reason = reason;
    g_free(conn->error_message);
    conn->error_message = g_strdup(error_message);
    - conn->destroy_timeout = purple_timeout_add(0, flap_connection_destroy_cb, conn);
    + conn->destroy_timeout = g_timeout_add(0, flap_connection_destroy_cb, conn);
    }
    /**
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/protocols/oscar/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,68 @@
    +OSCARSOURCES = [
    + 'authorization.c',
    + 'aim.c',
    + 'aim.h',
    + 'bstream.c',
    + 'clientlogin.c',
    + 'kerberos.c',
    + 'encoding.c',
    + 'encoding.h',
    + 'family_admin.c',
    + 'family_alert.c',
    + 'family_auth.c',
    + 'family_bart.c',
    + 'family_bos.c',
    + 'family_buddy.c',
    + 'family_chat.c',
    + 'family_chatnav.c',
    + 'family_icq.c',
    + 'family_icbm.c',
    + 'family_locate.c',
    + 'family_oservice.c',
    + 'family_popup.c',
    + 'family_feedbag.c',
    + 'family_stats.c',
    + 'family_userlookup.c',
    + 'flap_connection.c',
    + 'icq.c',
    + 'icq.h',
    + 'misc.c',
    + 'msgcookie.c',
    + 'odc.c',
    + 'oft.c',
    + 'oscar.c',
    + 'oscar.h',
    + 'oscarcommon.h',
    + 'oscar_data.c',
    + 'peer.c',
    + 'peer.h',
    + 'peer_proxy.c',
    + 'rxhandlers.c',
    + 'snac.c',
    + 'snactypes.h',
    + 'tlv.c',
    + 'userinfo.c',
    + 'util.c',
    + 'visibility.c',
    + 'visibility.h'
    +]
    +
    +if IS_WIN32
    + oscar_link_args = ['-Wl,--export-all-symbols']
    +else
    + oscar_link_args = []
    +endif
    +
    +if STATIC_OSCAR
    + oscar_prpl = static_library('oscar', OSCARSOURCES,
    + c_args : '-DPURPLE_STATIC_PRPL',
    + link_args : oscar_link_args,
    + dependencies : [libpurple_dep, glib, ws2_32])
    +elif DYNAMIC_OSCAR
    + oscar_prpl = shared_library('oscar', OSCARSOURCES,
    + link_args : oscar_link_args,
    + dependencies : [libpurple_dep, glib, ws2_32],
    + install : true, install_dir : PURPLE_PLUGINDIR)
    +endif
    +
    +subdir('tests')
    --- a/libpurple/protocols/oscar/oft.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/oscar/oft.c Sun Oct 08 20:44:26 2017 +0300
    @@ -79,7 +79,7 @@
    checksum_data->conn->checksum_data = NULL;
    fclose(checksum_data->file);
    if (checksum_data->timer > 0)
    - purple_timeout_remove(checksum_data->timer);
    + g_source_remove(checksum_data->timer);
    g_free(checksum_data);
    }
    @@ -218,7 +218,7 @@
    }
    else
    {
    - checksum_data->timer = purple_timeout_add(10,
    + checksum_data->timer = g_timeout_add(10,
    peer_oft_checksum_file_piece, checksum_data);
    conn->checksum_data = checksum_data;
    }
    @@ -251,7 +251,7 @@
    if (conn->sending_data_timer != 0)
    {
    - purple_timeout_remove(conn->sending_data_timer);
    + g_source_remove(conn->sending_data_timer);
    conn->sending_data_timer = 0;
    }
    }
    @@ -411,7 +411,7 @@
    /* Remove our watchers and use the file transfer watchers in the core */
    purple_input_remove(conn->watcher_incoming);
    conn->watcher_incoming = 0;
    - conn->sending_data_timer = purple_timeout_add(100,
    + conn->sending_data_timer = g_timeout_add(100,
    start_transfer_when_done_sending_data, conn);
    }
    @@ -433,7 +433,7 @@
    /* Remove our watchers and use the file transfer watchers in the core */
    purple_input_remove(conn->watcher_incoming);
    conn->watcher_incoming = 0;
    - conn->sending_data_timer = purple_timeout_add(100,
    + conn->sending_data_timer = g_timeout_add(100,
    start_transfer_when_done_sending_data, conn);
    }
    @@ -607,7 +607,7 @@
    peer_oft_send_done(conn);
    conn->disconnect_reason = OSCAR_DISCONNECT_DONE;
    - conn->sending_data_timer = purple_timeout_add(100,
    + conn->sending_data_timer = g_timeout_add(100,
    destroy_connection_when_done_sending_data, conn);
    }
    --- a/libpurple/protocols/oscar/oscar.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/oscar/oscar.c Sun Oct 08 20:44:26 2017 +0300
    @@ -449,8 +449,8 @@
    aim_ssi_reqrights(od);
    aim_ssi_reqdata(od);
    if (od->getblisttimer > 0)
    - purple_timeout_remove(od->getblisttimer);
    - od->getblisttimer = purple_timeout_add_seconds(30, purple_ssi_rerequestdata, od);
    + g_source_remove(od->getblisttimer);
    + od->getblisttimer = g_timeout_add_seconds(30, purple_ssi_rerequestdata, od);
    aim_locate_reqrights(od);
    aim_buddylist_reqrights(od, conn);
    @@ -3683,7 +3683,7 @@
    if (reason == 0x0005) {
    if (od->getblisttimer > 0)
    - purple_timeout_remove(od->getblisttimer);
    + g_source_remove(od->getblisttimer);
    else
    /* We only show this error the first time it happens */
    purple_notify_error(gc, NULL,
    @@ -3692,7 +3692,7 @@
    "your buddy list. Your buddy list is not lost, and "
    "will probably become available in a few minutes."),
    purple_request_cpar_from_connection(gc));
    - od->getblisttimer = purple_timeout_add_seconds(30, purple_ssi_rerequestdata, od);
    + od->getblisttimer = g_timeout_add_seconds(30, purple_ssi_rerequestdata, od);
    return 1;
    }
    @@ -3755,7 +3755,7 @@
    /* Don't attempt to re-request our buddy list later */
    if (od->getblisttimer != 0) {
    - purple_timeout_remove(od->getblisttimer);
    + g_source_remove(od->getblisttimer);
    od->getblisttimer = 0;
    }
    --- a/libpurple/protocols/oscar/oscar_data.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/oscar/oscar_data.c Sun Oct 08 20:44:26 2017 +0300
    @@ -117,7 +117,7 @@
    g_free(od->newp);
    g_free(od->oldp);
    if (od->getblisttimer > 0)
    - purple_timeout_remove(od->getblisttimer);
    + g_source_remove(od->getblisttimer);
    while (od->oscar_connections != NULL)
    flap_connection_destroy(od->oscar_connections->data,
    OSCAR_DISCONNECT_DONE, NULL);
    --- a/libpurple/protocols/oscar/peer.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/oscar/peer.c Sun Oct 08 20:44:26 2017 +0300
    @@ -155,7 +155,7 @@
    if (conn->connect_timeout_timer != 0)
    {
    - purple_timeout_remove(conn->connect_timeout_timer);
    + g_source_remove(conn->connect_timeout_timer);
    conn->connect_timeout_timer = 0;
    }
    @@ -243,7 +243,7 @@
    peer_connection_destroy(PeerConnection *conn, OscarDisconnectReason reason, const gchar *error_message)
    {
    if (conn->destroy_timeout != 0)
    - purple_timeout_remove(conn->destroy_timeout);
    + g_source_remove(conn->destroy_timeout);
    conn->disconnect_reason = reason;
    g_free(conn->error_message);
    conn->error_message = g_strdup(error_message);
    @@ -261,7 +261,7 @@
    conn->disconnect_reason = reason;
    g_free(conn->error_message);
    conn->error_message = g_strdup(error_message);
    - conn->destroy_timeout = purple_timeout_add(0, peer_connection_destroy_cb, conn);
    + conn->destroy_timeout = g_timeout_add(0, peer_connection_destroy_cb, conn);
    }
    /*******************************************************************/
    @@ -554,7 +554,7 @@
    return;
    }
    - purple_timeout_remove(conn->connect_timeout_timer);
    + g_source_remove(conn->connect_timeout_timer);
    conn->connect_timeout_timer = 0;
    if (conn->client_connect_data != NULL)
    @@ -854,7 +854,7 @@
    (conn->client_connect_data != NULL))
    {
    /* Connecting... */
    - conn->connect_timeout_timer = purple_timeout_add_seconds(5,
    + conn->connect_timeout_timer = g_timeout_add_seconds(5,
    peer_connection_tooktoolong, conn);
    return;
    }
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/protocols/oscar/tests/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,8 @@
    +foreach prog : ['util']
    + e = executable(
    + 'test_oscar_' + prog, 'test_oscar_@0@.c'.format(prog),
    + link_with : [oscar_prpl],
    + dependencies : [libpurple_dep, glib])
    +
    + test('oscar_' + prog, e)
    +endforeach
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/protocols/sametime/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,15 @@
    +SAMETIMESOURCES = [
    + 'sametime.c',
    + 'sametime.h'
    +]
    +
    +if STATIC_SAMETIME
    + sametime_prpl = static_library('sametime', SAMETIMESOURCES,
    + c_args : ['-DG_LOG_DOMAIN="sametime"', '-DPURPLE_STATIC_PRPL'],
    + dependencies : [meanwhile, libpurple_dep, glib])
    +elif DYNAMIC_SAMETIME
    + sametime_prpl = shared_library('sametime', SAMETIMESOURCES,
    + c_args : ['-DG_LOG_DOMAIN="sametime"'],
    + dependencies : [meanwhile, libpurple_dep, glib],
    + install : true, install_dir : PURPLE_PLUGINDIR)
    +endif
    --- a/libpurple/protocols/sametime/sametime.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/sametime/sametime.c Sun Oct 08 20:44:26 2017 +0300
    @@ -814,7 +814,7 @@
    static void blist_schedule(struct mwPurpleProtocolData *pd) {
    if(pd->save_event) return;
    - pd->save_event = purple_timeout_add_seconds(BLIST_SAVE_SECONDS,
    + pd->save_event = g_timeout_add_seconds(BLIST_SAVE_SECONDS,
    blist_save_cb, pd);
    }
    @@ -3747,7 +3747,7 @@
    /* get rid of the blist save timeout */
    if(pd->save_event) {
    - purple_timeout_remove(pd->save_event);
    + g_source_remove(pd->save_event);
    pd->save_event = 0;
    blist_store(pd);
    }
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/protocols/silc/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,22 @@
    +SILCSOURCES = [
    + 'buddy.c',
    + 'chat.c',
    + 'ft.c',
    + 'ops.c',
    + 'pk.c',
    + 'silc.c',
    + 'silcpurple.h',
    + 'util.c',
    + 'wb.c',
    + 'wb.h'
    +]
    +
    +if STATIC_SILC
    + silc_prpl = static_library('silcpurple', SILCSOURCES,
    + c_args : '-DPURPLE_STATIC_PRPL',
    + dependencies : [silc, libpurple_dep, glib])
    +elif DYNAMIC_SILC
    + silc_prpl = shared_library('silcpurple', SILCSOURCES,
    + dependencies : [silc, libpurple_dep, glib],
    + install : true, install_dir : PURPLE_PLUGINDIR)
    +endif
    --- a/libpurple/protocols/silc/silc.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/silc/silc.c Sun Oct 08 20:44:26 2017 +0300
    @@ -221,7 +221,7 @@
    /* Add timeout */
    ptask = silc_calloc(1, sizeof(*ptask));
    ptask->sg = sg;
    - ptask->tag = purple_timeout_add((seconds * 1000) +
    + ptask->tag = g_timeout_add((seconds * 1000) +
    (useconds / 1000),
    silcpurple_scheduler_timeout,
    ptask);
    @@ -646,7 +646,7 @@
    #if __SILC_TOOLKIT_VERSION < SILC_VERSION(1,1,1)
    /* Schedule SILC using Glib's event loop */
    - sg->scheduler = purple_timeout_add(300, (GSourceFunc)silcpurple_scheduler, client);
    + sg->scheduler = g_timeout_add(300, (GSourceFunc)silcpurple_scheduler, client);
    #else
    /* Run SILC scheduler */
    sg->tasks = silc_dlist_init();
    @@ -723,10 +723,10 @@
    #endif /* __SILC_TOOLKIT_VERSION */
    if (sg->scheduler)
    - purple_timeout_remove(sg->scheduler);
    + g_source_remove(sg->scheduler);
    purple_debug_info("silc", "Scheduling destruction of SilcPurple %p\n", sg);
    - purple_timeout_add(1, (GSourceFunc)silcpurple_close_final, sg);
    + g_timeout_add(1, (GSourceFunc)silcpurple_close_final, sg);
    }
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/protocols/simple/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,18 @@
    +SIMPLESOURCES = [
    + 'ntlm.c',
    + 'ntlm.h',
    + 'simple.c',
    + 'simple.h',
    + 'sipmsg.c',
    + 'sipmsg.h'
    +]
    +
    +if STATIC_SIMPLE
    + simple_prpl = static_library('simple', SIMPLESOURCES,
    + c_args : '-DPURPLE_STATIC_PRPL',
    + dependencies : [libpurple_dep, nettle, glib, gio, ws2_32])
    +elif DYNAMIC_SIMPLE
    + simple_prpl = shared_library('simple', SIMPLESOURCES,
    + dependencies : [libpurple_dep, nettle, glib, gio, ws2_32],
    + install : true, install_dir : PURPLE_PLUGINDIR)
    +endif
    --- a/libpurple/protocols/simple/simple.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/simple/simple.c Sun Oct 08 20:44:26 2017 +0300
    @@ -1766,7 +1766,7 @@
    conn = connection_create(sip, source);
    - sip->registertimeout = purple_timeout_add(g_random_int_range(10000, 100000), (GSourceFunc)subscribe_timeout, sip);
    + sip->registertimeout = g_timeout_add(g_random_int_range(10000, 100000), (GSourceFunc)subscribe_timeout, sip);
    do_register(sip);
    @@ -1808,8 +1808,8 @@
    sip->listenpa = purple_input_add(sip->fd, PURPLE_INPUT_READ, simple_udp_process, sip->gc);
    - sip->resendtimeout = purple_timeout_add(2500, (GSourceFunc) resend_timeout, sip);
    - sip->registertimeout = purple_timeout_add(g_random_int_range(10000, 100000), (GSourceFunc)subscribe_timeout, sip);
    + sip->resendtimeout = g_timeout_add(2500, (GSourceFunc) resend_timeout, sip);
    + sip->registertimeout = g_timeout_add(g_random_int_range(10000, 100000), (GSourceFunc)subscribe_timeout, sip);
    do_register(sip);
    }
    @@ -2051,9 +2051,9 @@
    if (sip->tx_handler)
    purple_input_remove(sip->tx_handler);
    if (sip->resendtimeout)
    - purple_timeout_remove(sip->resendtimeout);
    + g_source_remove(sip->resendtimeout);
    if (sip->registertimeout)
    - purple_timeout_remove(sip->registertimeout);
    + g_source_remove(sip->registertimeout);
    g_cancellable_cancel(sip->cancellable);
    g_object_unref(G_OBJECT(sip->cancellable));
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/protocols/zephyr/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,84 @@
    +ZEPHYRSOURCES = [
    + 'ZAsyncLocate.c',
    + 'ZCkAuth.c',
    + 'ZCkIfNot.c',
    + 'ZClosePort.c',
    + 'ZCmpUID.c',
    + 'ZCmpUIDP.c',
    + 'ZFlsLocs.c',
    + 'ZFlsSubs.c',
    + 'ZFmtAuth.c',
    + 'ZFmtList.c',
    + 'ZFmtNotice.c',
    + 'ZFmtRaw.c',
    + 'ZFmtRawLst.c',
    + 'ZFmtSmRLst.c',
    + 'ZFmtSmRaw.c',
    + 'ZFreeNot.c',
    + 'ZGetLocs.c',
    + 'ZGetSender.c',
    + 'ZGetSubs.c',
    + 'ZGetWGPort.c',
    + 'ZIfNotice.c',
    + 'ZInit.c',
    + 'ZLocations.c',
    + 'ZMakeAscii.c',
    + 'ZMkAuth.c',
    + 'ZNewLocU.c',
    + 'ZOpenPort.c',
    + 'ZParseNot.c',
    + 'ZPeekIfNot.c',
    + 'ZPeekNot.c',
    + 'ZPeekPkt.c',
    + 'ZPending.c',
    + 'ZReadAscii.c',
    + 'ZRecvNot.c',
    + 'ZRecvPkt.c',
    + 'ZRetSubs.c',
    + 'ZSendList.c',
    + 'ZSendNot.c',
    + 'ZSendPkt.c',
    + 'ZSendRLst.c',
    + 'ZSendRaw.c',
    + 'ZSetDest.c',
    + 'ZSetFD.c',
    + 'ZSetSrv.c',
    + 'ZSubs.c',
    + 'ZVariables.c',
    + 'ZWait4Not.c',
    + 'ZhmStat.c',
    + 'Zinternal.c',
    + 'com_err.h',
    + 'error_message.c',
    + 'error_table.h',
    + 'et_name.c',
    + 'init_et.c',
    + 'internal.h',
    + 'mit-copyright.h',
    + 'mit-sipb-copyright.h',
    + 'sysdep.h',
    + 'zephyr_err.c',
    + 'zephyr_err.h',
    + 'zephyr_internal.h',
    + 'zephyr.c',
    + 'zephyr.h'
    +]
    +
    +ZEPHYRSOURCESEXT = ['zephyr.c', 'zephyr.h']
    +
    +extdep = krb4
    +if EXTERNAL_LIBZEPHYR
    + ZEPHYRSOURCES = ZEPHYRSOURCESEXT
    + extdep = ext_zephyr
    +endif
    +
    +if STATIC_ZEPHYR
    + zephyr_prpl = static_library('zephyr', ZEPHYRSOURCES,
    + c_args : ['-Dlint', '-DPURPLE_STATIC_PRPL'],
    + dependencies : [extdep, libpurple_dep, glib])
    +elif DYNAMIC_ZEPHYR
    + zephyr_prpl = shared_library('zephyr', ZEPHYRSOURCES,
    + c_args : '-Dlint',
    + dependencies : [extdep, libpurple_dep, glib],
    + install : true, install_dir : PURPLE_PLUGINDIR)
    +endif
    --- a/libpurple/protocols/zephyr/zephyr.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/protocols/zephyr/zephyr.c Sun Oct 08 20:44:26 2017 +0300
    @@ -1876,11 +1876,11 @@
    process_zsubs(zephyr);
    if (use_zeph02(zephyr)) {
    - zephyr->nottimer = purple_timeout_add(100, check_notify_zeph02, gc);
    + zephyr->nottimer = g_timeout_add(100, check_notify_zeph02, gc);
    } else if (use_tzc(zephyr)) {
    - zephyr->nottimer = purple_timeout_add(100, check_notify_tzc, gc);
    + zephyr->nottimer = g_timeout_add(100, check_notify_tzc, gc);
    }
    - zephyr->loctimer = purple_timeout_add_seconds(20, check_loc, gc);
    + zephyr->loctimer = g_timeout_add_seconds(20, check_loc, gc);
    }
    @@ -2007,10 +2007,10 @@
    g_slist_free(zephyr->subscrips);
    if (zephyr->nottimer)
    - purple_timeout_remove(zephyr->nottimer);
    + g_source_remove(zephyr->nottimer);
    zephyr->nottimer = 0;
    if (zephyr->loctimer)
    - purple_timeout_remove(zephyr->loctimer);
    + g_source_remove(zephyr->loctimer);
    zephyr->loctimer = 0;
    gc = NULL;
    if (use_zeph02(zephyr)) {
    --- a/libpurple/purple-client.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/purple-client.c Sun Oct 08 20:44:26 2017 +0300
    @@ -58,7 +58,7 @@
    return list;
    }
    -#include "purple-client-bindings.c"
    +#include "purple-client-bindings.ch"
    static void lose(const char *fmt, ...) G_GNUC_NORETURN G_GNUC_PRINTF (1, 2);
    static void lose_gerror(const char *prefix, GError *error) G_GNUC_NORETURN;
    --- a/libpurple/queuedoutputstream.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/queuedoutputstream.h Sun Oct 08 20:44:26 2017 +0300
    @@ -24,14 +24,14 @@
    #ifndef _PURPLE_QUEUED_OUTPUT_STREAM_H
    #define _PURPLE_QUEUED_OUTPUT_STREAM_H
    /**
    - * SECTION:queued-output-stream
    - * @section_id: libpurple-queued-output-stream
    + * SECTION:queuedoutputstream
    + * @section_id: libpurple-queuedoutputstream
    * @short_description: GOutputStream for queuing data to output
    * @title: GOutputStream class
    *
    - * A #GQueuedOutputStream is a #GOutputStream which allows data to be queued
    - * for outputting. It differs from a #GBufferedOutputStream in that it allows
    - * for data to be queued while other operations are in progress.
    + * A #PurpleQueuedOutputStream is a #GOutputStream which allows data to be
    + * queued for outputting. It differs from a #GBufferedOutputStream in that
    + * it allows for data to be queued while other operations are in progress.
    */
    #include <gio/gio.h>
    @@ -40,10 +40,10 @@
    #define PURPLE_TYPE_QUEUED_OUTPUT_STREAM (purple_queued_output_stream_get_type())
    #define PURPLE_QUEUED_OUTPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST((o), PURPLE_TYPE_QUEUED_OUTPUT_STREAM, PurpleQueuedOutputStream))
    -#define PURPLE_QUEUED_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PURPLE_TYPE_QUEUED_OUTPUT_STREAM, GQueuedOutputStreamClass))
    -#define PURPLE_IS_QUEUED_OUTPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), PURPLE_TYPE_QUEUED_OUTPUT_STREAM)
    +#define PURPLE_QUEUED_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PURPLE_TYPE_QUEUED_OUTPUT_STREAM, PurpleQueuedOutputStreamClass))
    +#define PURPLE_IS_QUEUED_OUTPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), PURPLE_TYPE_QUEUED_OUTPUT_STREAM))
    #define PURPLE_IS_QUEUED_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), PURPLE_TYPE_QUEUED_OUTPUT_STREAM))
    -#define PURPLE_IS_QUEUED_OUTPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), PURPLE_TYPE_UEUED_OUTPUT_STREAM, GQueuedOutputStreamClass))
    +#define PURPLE_IS_QUEUED_OUTPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), PURPLE_TYPE_QUEUED_OUTPUT_STREAM, PurpleQueuedOutputStreamClass))
    /**
    * PurpleQueuedOutputStream:
    --- a/libpurple/request-datasheet.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/request-datasheet.h Sun Oct 08 20:44:26 2017 +0300
    @@ -129,7 +129,7 @@
    *
    * You shouldn't modify datasheet's data while iterating through it.
    *
    - * Returns: (transfer none): The list of records.
    + * Returns: (element-type PurpleRequestDatasheetRecord) (transfer none): The list of records.
    */
    const GList *
    purple_request_datasheet_get_records(PurpleRequestDatasheet *sheet);
    @@ -153,7 +153,7 @@
    *
    * Returns the list of actions in a datasheet.
    *
    - * Returns: (transfer none): The list of actions.
    + * Returns: (element-type PurpleRequestDatasheetAction) (transfer none): The list of actions.
    */
    const GList *
    purple_request_datasheet_get_actions(PurpleRequestDatasheet *sheet);
    --- a/libpurple/request.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/request.h Sun Oct 08 20:44:26 2017 +0300
    @@ -543,7 +543,7 @@
    *
    * Returns a list of all groups in a field list.
    *
    - * Returns: (transfer none): A list of groups.
    + * Returns: (element-type PurpleRequestFieldGroup) (transfer none): A list of groups.
    */
    GList *purple_request_fields_get_groups(const PurpleRequestFields *fields);
    @@ -588,7 +588,7 @@
    *
    * Returns a list of all required fields.
    *
    - * Returns: (transfer none): The list of required fields.
    + * Returns: (element-type PurpleRequestField) (transfer none): The list of required fields.
    */
    const GList *purple_request_fields_get_required(
    const PurpleRequestFields *fields);
    @@ -599,7 +599,7 @@
    *
    * Returns a list of all validated fields.
    *
    - * Returns: (transfer none): The list of validated fields.
    + * Returns: (element-type PurpleRequestField) (transfer none): The list of validated fields.
    */
    const GList *purple_request_fields_get_validatable(
    const PurpleRequestFields *fields);
    @@ -610,8 +610,8 @@
    *
    * Returns a list of all fields with sensitivity callback added.
    *
    - * Returns: (transfer none): The list of fields with automatic sensitivity
    - * callback.
    + * Returns: (element-type PurpleRequestField) (transfer none): The list of
    + * fields with automatic sensitivity callback.
    */
    const GList *
    purple_request_fields_get_autosensitive(const PurpleRequestFields *fields);
    @@ -816,7 +816,7 @@
    *
    * Returns a list of all fields in a group.
    *
    - * Returns: (transfer none): The list of fields in the group.
    + * Returns: (element-type PurpleRequestField) (transfer none): The list of fields in the group.
    */
    GList *purple_request_field_group_get_fields(
    const PurpleRequestFieldGroup *group);
    @@ -1521,7 +1521,7 @@
    /**
    * purple_request_field_list_set_selected:
    * @field: The field.
    - * @items: The list of selected items, which is not modified or freed.
    + * @items: (element-type utf8) (transfer none): The list of selected items.
    *
    * Sets a list of selected items in a list field.
    */
    @@ -1549,7 +1549,7 @@
    * To retrieve the data for each item, use
    * purple_request_field_list_get_data().
    *
    - * Returns: (transfer none): The list of selected items.
    + * Returns: (element-type utf8) (transfer none): The list of selected items.
    */
    GList *purple_request_field_list_get_selected(
    const PurpleRequestField *field);
    @@ -1560,7 +1560,7 @@
    *
    * Returns a list of items in a list field.
    *
    - * Returns: (transfer none): The list of items.
    + * Returns: (element-type utf8) (transfer none): The list of items.
    */
    GList *purple_request_field_list_get_items(const PurpleRequestField *field);
    @@ -1572,7 +1572,7 @@
    *
    * The icons will correspond with the items, in order.
    *
    - * Returns: (transfer none): The list of icons or %NULL (i.e. the empty #GList)
    + * Returns: (element-type utf8) (transfer none): The list of icons or %NULL (i.e. the empty #GList)
    * if no items have icons.
    */
    GList *purple_request_field_list_get_icons(const PurpleRequestField *field);
    --- a/libpurple/roomlist.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/roomlist.h Sun Oct 08 20:44:26 2017 +0300
    @@ -181,6 +181,7 @@
    /**
    * purple_roomlist_get_account:
    + * @list: The room list.
    *
    * Retrieve the PurpleAccount that was given when the room list was
    * created.
    @@ -192,8 +193,8 @@
    /**
    * purple_roomlist_set_fields:
    * @list: The room list.
    - * @fields: A GList of PurpleRoomlistField's. UI's are encouraged
    - * to default to displaying them in the order given.
    + * @fields: (element-type PurpleRoomlistField) (transfer full): UI's are
    + * encouraged to default to displaying these fields in the order given.
    *
    * Set the different field types and their names for this protocol.
    *
    @@ -279,7 +280,7 @@
    *
    * Get the list of fields for a roomlist.
    *
    - * Returns: (transfer none): A list of fields
    + * Returns: (element-type PurpleRoomlistField) (transfer none): A list of fields
    */
    GList *purple_roomlist_get_fields(PurpleRoomlist *roomlist);
    @@ -423,7 +424,7 @@
    *
    * Get the list of fields for a room.
    *
    - * Returns: (transfer none): A list of fields
    + * Returns: (element-type PurpleRoomlistField) (transfer none): A list of fields
    */
    GList * purple_roomlist_room_get_fields(PurpleRoomlistRoom *room);
    --- a/libpurple/savedstatuses.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/savedstatuses.c Sun Oct 08 20:44:26 2017 +0300
    @@ -359,7 +359,7 @@
    schedule_save(void)
    {
    if (save_timer == 0)
    - save_timer = purple_timeout_add_seconds(5, save_cb, NULL);
    + save_timer = g_timeout_add_seconds(5, save_cb, NULL);
    }
    @@ -1260,7 +1260,7 @@
    if (save_timer != 0)
    {
    - purple_timeout_remove(save_timer);
    + g_source_remove(save_timer);
    save_timer = 0;
    sync_statuses();
    }
    --- a/libpurple/savedstatuses.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/savedstatuses.h Sun Oct 08 20:44:26 2017 +0300
    @@ -184,7 +184,7 @@
    *
    * Returns all saved statuses.
    *
    - * Returns: (transfer none): A list of saved statuses.
    + * Returns: (element-type PurpleSavedStatus) (transfer none): A list of saved statuses.
    */
    GList *purple_savedstatuses_get_all(void);
    @@ -199,10 +199,8 @@
    * how many times it has been used. Transient statuses without
    * messages are not included in the list.
    *
    - * Returns: A linked list containing at most how_many
    - * PurpleSavedStatuses. This list should be
    - * g_list_free'd by the caller (but the
    - * PurpleSavedStatuses must not be free'd).
    + * Returns: (element-type PurpleSavedStatus) (transfer container): A list containing
    + * at most how_many saved statuses.
    */
    GList *purple_savedstatuses_get_popular(unsigned int how_many);
    --- a/libpurple/server.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/server.c Sun Oct 08 20:44:26 2017 +0300
    @@ -90,7 +90,7 @@
    /* because we're modifying or creating a lar, schedule the
    * function to expire them as the pref dictates */
    - purple_timeout_add_seconds((SECS_BEFORE_RESENDING_AUTORESPONSE + 1), expire_last_auto_responses, NULL);
    + g_timeout_add_seconds((SECS_BEFORE_RESENDING_AUTORESPONSE + 1), expire_last_auto_responses, NULL);
    tmp = last_auto_responses;
    --- a/libpurple/signals.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/signals.c Sun Oct 08 20:44:26 2017 +0300
    @@ -1107,6 +1107,22 @@
    }
    void
    +purple_marshal_POINTER__POINTER_POINTER_BOOLEAN(
    + PurpleCallback cb, va_list args, void *data,
    + void **return_val)
    +{
    + gpointer ret_val;
    + void *arg1 = va_arg(args, void *);
    + void *arg2 = va_arg(args, void *);
    + gboolean arg3 = va_arg(args, gboolean);
    +
    + ret_val = ((gpointer(*)(void *, void *, gboolean, void *))cb)(arg1, arg2, arg3, data);
    +
    + if (return_val != NULL)
    + *return_val = ret_val;
    +}
    +
    +void
    purple_marshal_POINTER__POINTER_POINTER(PurpleCallback cb, va_list args, void *data,
    void **return_val)
    {
    --- a/libpurple/signals.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/signals.h Sun Oct 08 20:44:26 2017 +0300
    @@ -396,6 +396,8 @@
    PurpleCallback cb, va_list args, void *data, void **return_val);
    void purple_marshal_POINTER__POINTER_INT64_BOOLEAN(
    PurpleCallback cb, va_list args, void *data, void **return_val);
    +void purple_marshal_POINTER__POINTER_POINTER_BOOLEAN(
    + PurpleCallback cb, va_list args, void *data, void **return_val);
    void purple_marshal_POINTER__POINTER_POINTER(
    PurpleCallback cb, va_list args, void *data, void **return_val);
    --- a/libpurple/smiley-list.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/smiley-list.c Sun Oct 08 20:44:26 2017 +0300
    @@ -138,7 +138,7 @@
    obj_class->finalize = purple_smiley_list_finalize;
    properties[PROP_DROP_FAILED_REMOTES] = g_param_spec_boolean(
    - "drop-failed-remotes", "Drop failed PurpleRemoteSmileys",
    + "drop-failed-remotes", "Drop failed remote PurpleSmileys",
    "Watch added remote smileys and remove them from the list, "
    "if they change their state to failed", FALSE,
    G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
    --- a/libpurple/smiley-list.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/smiley-list.h Sun Oct 08 20:44:26 2017 +0300
    @@ -156,8 +156,7 @@
    *
    * Returns the list of smileys with unique image file paths.
    *
    - * Returns: (transfer container): the #GList of unique smileys. Use #g_list_free
    - * when done using it.
    + * Returns: (element-type PurpleSmiley) (transfer container): the list of unique smileys.
    */
    GList *purple_smiley_list_get_unique(PurpleSmileyList *list_);
    @@ -167,8 +166,7 @@
    *
    * Returns the list of all smileys added to the @list_.
    *
    - * Returns: (transfer container): the #GList of smileys. Use #g_list_free
    - * when done using it.
    + * Returns: (element-type PurpleSmiley) (transfer container): the list of smileys.
    */
    GList *purple_smiley_list_get_all(PurpleSmileyList *list_);
    --- a/libpurple/smiley-parser.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/smiley-parser.h Sun Oct 08 20:44:26 2017 +0300
    @@ -112,8 +112,7 @@
    * text. However, distinct smileys may share common image file (thus, their
    * paths will be the same).
    *
    - * Returns: (transfer container): the #GList of found smileys. Use #g_list_free
    - * when no longer need it.
    + * Returns: (element-type PurpleSmiley) (transfer container): the list of found smileys.
    */
    GList *
    purple_smiley_parser_find(PurpleSmileyList *smileys, const gchar *message,
    --- a/libpurple/smiley-theme.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/smiley-theme.h Sun Oct 08 20:44:26 2017 +0300
    @@ -126,7 +126,7 @@
    *
    * Returns the currently used smiley theme.
    *
    - * Returns: the #PurpleSmileyTheme or %NULL, if none is set.
    + * Returns: (transfer none): the #PurpleSmileyTheme or %NULL, if none is set.
    */
    PurpleSmileyTheme *
    purple_smiley_theme_get_current(void);
    --- a/libpurple/smiley.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/smiley.c Sun Oct 08 20:44:26 2017 +0300
    @@ -146,6 +146,7 @@
    smiley = g_object_new(
    PURPLE_TYPE_SMILEY,
    + "path", path,
    "contents", bytes,
    "shortcut", shortcut,
    NULL
    --- a/libpurple/smiley.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/smiley.h Sun Oct 08 20:44:26 2017 +0300
    @@ -32,7 +32,7 @@
    * A #PurpleSmiley is a base class for associating emoticon images and their
    * textual representation. It's intended for various smiley-related tasks:
    * parsing the text against them, displaying in the smiley selector, or handling
    - * remote data (using #PurpleRemoteSmiley).
    + * remote data.
    *
    * The #PurpleSmiley:shortcut is always unescaped, but <link linkend="libpurple-smiley-parser">smiley parser</link>
    * may deal with special characters.
    --- a/libpurple/sound.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/sound.c Sun Oct 08 20:44:26 2017 +0300
    @@ -29,7 +29,7 @@
    #include "theme-manager.h"
    static PurpleSoundUiOps *sound_ui_ops = NULL;
    -static time_t last_played[PURPLE_NUM_SOUNDS];
    +static gint64 last_played[PURPLE_NUM_SOUNDS];
    static gboolean
    purple_sound_play_required(const PurpleAccount *account)
    @@ -79,9 +79,9 @@
    g_return_if_fail(event < PURPLE_NUM_SOUNDS);
    - if (time(NULL) - last_played[event] < 2)
    + if (g_get_monotonic_time() - last_played[event] < 2 * G_USEC_PER_SEC)
    return;
    - last_played[event] = time(NULL);
    + last_played[event] = g_get_monotonic_time();
    if(sound_ui_ops && sound_ui_ops->play_event) {
    int plugin_return;
    --- a/libpurple/sslconn.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/sslconn.c Sun Oct 08 20:44:26 2017 +0300
    @@ -271,7 +271,7 @@
    {
    GError *error = NULL;
    - purple_timeout_remove(GPOINTER_TO_UINT(timeout_id));
    + g_source_remove(GPOINTER_TO_UINT(timeout_id));
    g_io_stream_close_finish(G_IO_STREAM(stream), result, &error);
    @@ -318,7 +318,7 @@
    g_object_weak_ref(G_OBJECT(gsc->conn), cleanup_cancellable_cb,
    cancellable);
    - timer_id = purple_timeout_add_seconds(CONNECTION_CLOSE_TIMEOUT,
    + timer_id = g_timeout_add_seconds(CONNECTION_CLOSE_TIMEOUT,
    (GSourceFunc)g_cancellable_cancel, cancellable);
    g_io_stream_close_async(G_IO_STREAM(gsc->conn),
    --- a/libpurple/sslconn.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/sslconn.h Sun Oct 08 20:44:26 2017 +0300
    @@ -238,8 +238,9 @@
    *
    * Obtains the peer's presented certificates
    *
    - * Returns: The peer certificate chain, in the order of certificate, issuer,
    - * issuer's issuer, etc. %NULL if no certificates have been provided,
    + * Returns: (element-type GTlsCertificate): The peer certificate chain, in the
    + * order of certificate, issuer, issuer's issuer, etc. %NULL if no
    + * certificates have been provided.
    */
    GList * purple_ssl_get_peer_certificates(PurpleSslConnection *gsc);
    --- a/libpurple/status.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/status.c Sun Oct 08 20:44:26 2017 +0300
    @@ -505,7 +505,7 @@
    {
    if (purple_prefs_get_bool("/purple/logging/log_system"))
    {
    - time_t current_time = time(NULL);
    + GDateTime *current_time = g_date_time_new_now_utc();
    const char *buddy_alias = purple_buddy_get_alias(buddy);
    char *tmp, *logtmp;
    PurpleLog *log;
    @@ -545,6 +545,7 @@
    current_time, logtmp);
    }
    + g_date_time_unref(current_time);
    g_free(tmp);
    g_free(logtmp);
    }
    --- a/libpurple/status.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/status.h Sun Oct 08 20:44:26 2017 +0300
    @@ -69,7 +69,6 @@
    /**
    * PurpleStatusPrimitive:
    - *
    * @PURPLE_STATUS_UNSET: The status is not set
    * @PURPLE_STATUS_OFFLINE: The status is offline
    * @PURPLE_STATUS_AVAILABLE: The status is available
    @@ -80,6 +79,7 @@
    * @PURPLE_STATUS_MOBILE: The status is mobile
    * @PURPLE_STATUS_TUNE: The status includes a song title
    * @PURPLE_STATUS_MOOD: The status includes a mood
    + *
    * A primitive defining the basic structure of a status type.
    */
    /*
    @@ -408,13 +408,14 @@
    *
    * Returns a list of all attributes in a status type.
    *
    - * Returns: (transfer none): The list of attributes.
    + * Returns: (element-type PurpleStatusAttribute) (transfer none): The list of attributes.
    */
    GList *purple_status_type_get_attrs(const PurpleStatusType *status_type);
    /**
    * purple_status_type_find_with_id:
    - * @status_types: A list of status types. Often account->status_types.
    + * @status_types: (element-type PurpleStatus) (transfer none): A list of status
    + * types. Often account->status_types.
    * @id: The unique ID of the status type you wish to find.
    *
    * Find the PurpleStatusType with the given id.
    --- a/libpurple/stringref.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/stringref.c Sun Oct 08 20:44:26 2017 +0300
    @@ -88,7 +88,7 @@
    newref->ref = 0x80000000;
    if (gclist == NULL)
    - purple_timeout_add(0, gs_idle_cb, NULL);
    + g_timeout_add(0, gs_idle_cb, NULL);
    gclist = g_list_prepend(gclist, newref);
    return newref;
    --- a/libpurple/stun.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/stun.c Sun Oct 08 20:44:26 2017 +0300
    @@ -100,7 +100,7 @@
    purple_input_remove(sc->incb);
    if (sc->timeout)
    - purple_timeout_remove(sc->timeout);
    + g_source_remove(sc->timeout);
    if (sc->fd)
    close(sc->fd);
    @@ -167,7 +167,7 @@
    sc->retry = 0;
    sc->test = 2;
    sendto(sc->fd, sc->packet, sc->packetsize, 0, (struct sockaddr *)&(sc->addr), sizeof(struct sockaddr_in));
    - sc->timeout = purple_timeout_add(500, (GSourceFunc) timeoutfunc, sc);
    + sc->timeout = g_timeout_add(500, (GSourceFunc) timeoutfunc, sc);
    }
    #endif /* 0 */
    @@ -275,7 +275,7 @@
    close_stun_conn(sc);
    do_callbacks();
    #else
    - purple_timeout_remove(sc->timeout);
    + g_source_remove(sc->timeout);
    sc->timeout = 0;
    do_test2(sc);
    @@ -341,7 +341,7 @@
    sc->test = 1;
    sc->packet = &hdr_data;
    sc->packetsize = sizeof(struct stun_header);
    - sc->timeout = purple_timeout_add(500, (GSourceFunc) timeoutfunc, sc);
    + sc->timeout = g_timeout_add(500, (GSourceFunc) timeoutfunc, sc);
    }
    static void
    @@ -442,7 +442,7 @@
    if (use_cached_result) {
    if(cb)
    - purple_timeout_add(10, call_callback, cb);
    + g_timeout_add(10, call_callback, cb);
    return &nattype;
    }
    }
    @@ -451,7 +451,7 @@
    nattype.status = PURPLE_STUN_STATUS_UNKNOWN;
    nattype.lookup_time = time(NULL);
    if(cb)
    - purple_timeout_add(10, call_callback, cb);
    + g_timeout_add(10, call_callback, cb);
    return &nattype;
    }
    --- a/libpurple/tests.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/tests.h Sun Oct 08 20:44:26 2017 +0300
    @@ -33,7 +33,7 @@
    typedef const gchar *(*PurpleTestStringFunc)(const gchar *);
    typedef gchar *(*PurpleTestStringFreeFunc)(const gchar *);
    -inline void
    +static inline void
    purple_test_string_compare(PurpleTestStringFunc func,
    PurpleTestStringData data[])
    {
    @@ -43,7 +43,7 @@
    g_assert_cmpstr(data[i].output, ==, func(data[i].input));
    }
    -inline void
    +static inline void
    purple_test_string_compare_free(PurpleTestStringFreeFunc func,
    PurpleTestStringData data[])
    {
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/libpurple/tests/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,16 @@
    +PROGS = [
    + 'image',
    + 'smiley',
    + 'smiley_list',
    + 'trie',
    + 'util',
    + 'xmlnode'
    +]
    +foreach prog : PROGS
    + e = executable('test_' + prog, 'test_@0@.c'.format(prog),
    + c_args : [
    + '-DTEST_DATA_DIR="@0@/data"'.format(meson.current_source_dir())
    + ],
    + dependencies : [libpurple_dep, glib])
    + test(prog, e)
    +endforeach
    --- a/libpurple/tests/test_image.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/tests/test_image.c Sun Oct 08 20:44:26 2017 +0300
    @@ -58,6 +58,7 @@
    _test_image(PurpleImage *image,
    const guint8 *edata,
    gsize elen,
    + const gchar *path,
    const gchar *ext,
    const gchar *mimetype)
    {
    @@ -72,12 +73,45 @@
    g_assert_cmpmem(adata, alen, edata, elen);
    g_bytes_unref(bytes);
    + /* if the caller provided a path, check it, otherwise just make sure we
    + * have something.
    + */
    + if(path != NULL) {
    + g_assert_cmpstr(purple_image_get_path(image), ==, path);
    + } else {
    + const gchar *apath = purple_image_get_path(image);
    +
    + g_assert(apath);
    + g_assert_cmpstr(apath, !=, "");
    + }
    +
    g_assert_cmpstr(purple_image_get_extension(image), ==, ext);
    g_assert_cmpstr(purple_image_get_mimetype(image), ==, mimetype);
    g_object_unref(G_OBJECT(image));
    }
    +/******************************************************************************
    + * Tests
    + *****************************************************************************/
    +static void
    +test_image_new_from_bytes(void) {
    + GBytes *bytes = g_bytes_new(test_image_data, test_image_data_len);
    + PurpleImage *image = purple_image_new_from_bytes(bytes);
    +
    + _test_image(
    + image,
    + g_bytes_get_data(bytes, NULL),
    + g_bytes_get_size(bytes),
    + NULL,
    + "png",
    + "image/png"
    + );
    +
    + g_bytes_unref(bytes);
    +}
    +
    +
    static void
    test_image_new_from_data(void) {
    PurpleImage *image = purple_image_new_from_data(
    @@ -89,6 +123,7 @@
    image,
    test_image_data,
    test_image_data_len,
    + NULL,
    "png",
    "image/png"
    );
    @@ -107,16 +142,18 @@
    g_assert_no_error(error);
    g_file_get_contents(path, &edata, &elen, &error);
    - g_free(path);
    g_assert_no_error(error);
    _test_image(
    image,
    (guint8 *)edata,
    elen,
    + path,
    "png",
    "image/png"
    );
    +
    + g_free(path);
    }
    /******************************************************************************
    @@ -126,6 +163,11 @@
    main(gint argc, gchar **argv) {
    g_test_init(&argc, &argv, NULL);
    + #if GLIB_CHECK_VERSION(2, 38, 0)
    + g_test_set_nonfatal_assertions();
    + #endif /* GLIB_CHECK_VERSION(2, 38, 0) */
    +
    + g_test_add_func("/image/new-from-bytes", test_image_new_from_bytes);
    g_test_add_func("/image/new-from-data", test_image_new_from_data);
    g_test_add_func("/image/new-from-file", test_image_new_from_file);
    --- a/libpurple/tests/test_smiley.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/tests/test_smiley.c Sun Oct 08 20:44:26 2017 +0300
    @@ -56,6 +56,7 @@
    *****************************************************************************/
    static void
    _test_smiley(PurpleSmiley *smiley,
    + const gchar *path,
    const guint8 *edata,
    gsize elen,
    const gchar *ext,
    @@ -85,9 +86,15 @@
    );
    g_assert_cmpstr(purple_smiley_get_shortcut(smiley), ==, shortcut);
    + if(path)
    + g_assert_cmpstr(purple_image_get_path(PURPLE_IMAGE(smiley)), ==, path);
    +
    g_object_unref(G_OBJECT(smiley));
    }
    +/******************************************************************************
    + * Tests
    + *****************************************************************************/
    static void
    test_smiley_new_from_data(void) {
    PurpleSmiley *smiley = purple_smiley_new_from_data(
    @@ -98,6 +105,7 @@
    _test_smiley(
    smiley,
    + NULL,
    test_image_data,
    test_image_data_len,
    "png",
    @@ -119,17 +127,19 @@
    g_assert_no_error(error);
    g_file_get_contents(path, &edata, &elen, &error);
    - g_free(path);
    g_assert_no_error(error);
    _test_smiley(
    smiley,
    + path,
    (guint8 *)edata,
    elen,
    "png",
    "image/png",
    "^_^"
    );
    +
    + g_free(path);
    }
    /******************************************************************************
    @@ -139,6 +149,10 @@
    main(gint argc, gchar **argv) {
    g_test_init(&argc, &argv, NULL);
    + #if GLIB_CHECK_VERSION(2, 38, 0)
    + g_test_set_nonfatal_assertions();
    + #endif /* GLIB_CHECK_VERSION(2, 38, 0) */
    +
    g_test_add_func("/smiley/new-from-data", test_smiley_new_from_data);
    g_test_add_func("/smiley/new-from-file", test_smiley_new_from_file);
    --- a/libpurple/tests/test_smiley_list.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/tests/test_smiley_list.c Sun Oct 08 20:44:26 2017 +0300
    @@ -87,6 +87,10 @@
    main(gint argc, gchar **argv) {
    g_test_init(&argc, &argv, NULL);
    + #if GLIB_CHECK_VERSION(2, 38, 0)
    + g_test_set_nonfatal_assertions();
    + #endif /* GLIB_CHECK_VERSION(2, 38, 0) */
    +
    g_test_add_func("/smiley_list/new", test_smiley_list_new);
    g_test_add_func("/smiley_list/add-remove", test_smiley_list_add_remove);
    --- a/libpurple/tests/test_util.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/tests/test_util.c Sun Oct 08 20:44:26 2017 +0300
    @@ -199,6 +199,46 @@
    }
    /******************************************************************************
    + * str_to_date_time tests
    + *****************************************************************************/
    +static void
    +test_util_str_to_date_time(void)
    +{
    + GDateTime *dt;
    +
    + dt = purple_str_to_date_time("19811214T12:50:00", TRUE);
    + g_assert_cmpint(377182200, ==, g_date_time_to_unix(dt));
    + g_assert_cmpint(0, ==, g_date_time_get_utc_offset(dt));
    + g_date_time_unref(dt);
    +
    + dt = purple_str_to_date_time("20070407T04:14:21.1234", TRUE);
    + g_assert_cmpint(1175919261, ==, g_date_time_to_unix(dt));
    + g_assert_cmpint(0, ==, g_date_time_get_utc_offset(dt));
    + g_assert_cmpint(123400, ==, g_date_time_get_microsecond(dt));
    + g_date_time_unref(dt);
    +
    + dt = purple_str_to_date_time("2010-08-27.204202", TRUE);
    + g_assert_cmpint(1282941722, ==, g_date_time_to_unix(dt));
    + g_assert_cmpint(0, ==, g_date_time_get_utc_offset(dt));
    + g_date_time_unref(dt);
    +
    + dt = purple_str_to_date_time("2010-08-27.204202.123456", TRUE);
    + g_assert_cmpint(1282941722, ==, g_date_time_to_unix(dt));
    + g_assert_cmpint(0, ==, g_date_time_get_utc_offset(dt));
    + g_assert_cmpint(123456, ==, g_date_time_get_microsecond(dt));
    + g_date_time_unref(dt);
    +
    + dt = purple_str_to_date_time("2010-08-27.134202-0700PDT", FALSE);
    + g_assert_cmpint(1282941722, ==, g_date_time_to_unix(dt));
    + g_assert_cmpint((-7LL * 60 * 60 * G_USEC_PER_SEC), ==, g_date_time_get_utc_offset(dt));
    +
    + dt = purple_str_to_date_time("2010-08-27.134202.1234-0700PDT", FALSE);
    + g_assert_cmpint(1282941722, ==, g_date_time_to_unix(dt));
    + g_assert_cmpint(123400, ==, g_date_time_get_microsecond(dt));
    + g_assert_cmpint((-7LL * 60 * 60 * G_USEC_PER_SEC), ==, g_date_time_get_utc_offset(dt));
    +}
    +
    +/******************************************************************************
    * Markup tests
    *****************************************************************************/
    typedef struct {
    @@ -515,6 +555,9 @@
    g_test_add_func("/util/str to time",
    test_util_str_to_time);
    + g_test_add_func("/util/str to date time",
    + test_util_str_to_date_time);
    +
    g_test_add_func("/util/markup/html to xhtml",
    test_util_markup_html_to_xhtml);
    --- a/libpurple/theme-loader.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/theme-loader.h Sun Oct 08 20:44:26 2017 +0300
    @@ -97,7 +97,7 @@
    *
    * Creates a new PurpleTheme
    *
    - * Returns: A PurpleTheme containing the information from the directory
    + * Returns: (transfer full): A PurpleTheme containing the information from the directory
    */
    PurpleTheme *purple_theme_loader_build(PurpleThemeLoader *loader, const gchar *dir);
    --- a/libpurple/theme-manager.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/theme-manager.h Sun Oct 08 20:44:26 2017 +0300
    @@ -102,7 +102,7 @@
    *
    * Finds the PurpleTheme object stored by the theme manager.
    *
    - * Returns: The PurpleTheme, or NULL if it wasn't found.
    + * Returns: (transfer none): The PurpleTheme, or NULL if it wasn't found.
    */
    PurpleTheme *purple_theme_manager_find_theme(const gchar *name, const gchar *type);
    @@ -141,7 +141,7 @@
    /**
    * purple_theme_manager_for_each_theme:
    - * @func: The PurpleThemeFunc to be applied to each theme.
    + * @func: (scope call): The PurpleThemeFunc to be applied to each theme.
    *
    * Calls the given function on each purple theme.
    */
    @@ -153,6 +153,8 @@
    * @type: the type of theme to load
    *
    * Loads a theme of the given type without adding it to the manager
    + *
    + * Returns: (transfer full): The newly loaded theme.
    */
    PurpleTheme *purple_theme_manager_load_theme(const gchar *theme_dir, const gchar *type);
    --- a/libpurple/tls-certificate.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/tls-certificate.h Sun Oct 08 20:44:26 2017 +0300
    @@ -43,10 +43,10 @@
    *
    * Returns a list of the IDs for certificates trusted with
    * purple_tls_certificate_trust() and friends. These IDs can then be passed
    - * to purple_certificate_path() or used directly, if desired.
    + * to purple_tls_certificate_new_from_id() or used directly, if desired.
    *
    * Returns: (transfer full) (element-type utf8): #GList of IDs described above
    - * Free with purple_certificate_free_ids()
    + * Free with purple_tls_certificate_free_ids()
    */
    GList *
    purple_tls_certificate_list_ids(void);
    @@ -54,9 +54,9 @@
    /**
    * purple_tls_certificate_free_ids:
    * @ids: (transfer full) (element-type utf8): List of ids retrieved from
    - * purple_certificate_list_ids()
    + * purple_tls_certificate_list_ids()
    *
    - * Frees the list of IDs returned from purple_certificate_list_ids().
    + * Frees the list of IDs returned from purple_tls_certificate_list_ids().
    */
    void
    purple_tls_certificate_free_ids(GList *ids);
    --- a/libpurple/upnp.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/upnp.c Sun Oct 08 20:44:26 2017 +0300
    @@ -118,7 +118,7 @@
    typedef struct {
    guint inpa; /* purple_input_add handle */
    - guint tima; /* purple_timeout_add handle */
    + guint tima; /* g_timeout_add handle */
    int fd;
    struct sockaddr_in server;
    gchar service_type[20];
    @@ -134,7 +134,7 @@
    PurpleUPnPCallback cb;
    gpointer cb_data;
    gboolean success;
    - guint tima; /* purple_timeout_add handle */
    + guint tima; /* g_timeout_add handle */
    PurpleHttpConnection *hc;
    };
    @@ -404,7 +404,7 @@
    if (dd->inpa > 0)
    purple_input_remove(dd->inpa);
    if (dd->tima > 0)
    - purple_timeout_remove(dd->tima);
    + g_source_remove(dd->tima);
    g_free(dd);
    }
    @@ -417,7 +417,7 @@
    /* Remove the timeout because everything it is waiting for has
    * successfully completed */
    - purple_timeout_remove(dd->tima);
    + g_source_remove(dd->tima);
    dd->tima = 0;
    /* Extract base url out of the descriptionURL.
    @@ -494,7 +494,7 @@
    if (dd->inpa)
    purple_input_remove(dd->inpa);
    if (dd->tima > 0)
    - purple_timeout_remove(dd->tima);
    + g_source_remove(dd->tima);
    dd->inpa = 0;
    dd->tima = 0;
    @@ -588,7 +588,7 @@
    g_free(sendMessage);
    if(sentSuccess) {
    - dd->tima = purple_timeout_add(DISCOVERY_TIMEOUT,
    + dd->tima = g_timeout_add(DISCOVERY_TIMEOUT,
    purple_upnp_discover_timeout, dd);
    dd->inpa = purple_input_add(dd->fd, PURPLE_INPUT_READ,
    purple_upnp_discover_udp_read, dd);
    @@ -599,7 +599,7 @@
    /* We have already done all our retries. Make sure that the callback
    * doesn't get called before the original function returns */
    - dd->tima = purple_timeout_add(10, purple_upnp_discover_timeout, dd);
    + dd->tima = g_timeout_add(10, purple_upnp_discover_timeout, dd);
    }
    void
    @@ -636,7 +636,7 @@
    "purple_upnp_discover(): Failed In sock creation\n");
    /* Short circuit the retry attempts */
    dd->retry_count = NUM_UDP_ATTEMPTS;
    - dd->tima = purple_timeout_add(10, purple_upnp_discover_timeout, dd);
    + dd->tima = g_timeout_add(10, purple_upnp_discover_timeout, dd);
    return;
    }
    @@ -646,7 +646,7 @@
    "purple_upnp_discover(): Failed In gethostbyname\n");
    /* Short circuit the retry attempts */
    dd->retry_count = NUM_UDP_ATTEMPTS;
    - dd->tima = purple_timeout_add(10, purple_upnp_discover_timeout, dd);
    + dd->tima = g_timeout_add(10, purple_upnp_discover_timeout, dd);
    return;
    }
    @@ -826,7 +826,7 @@
    purple_debug_info("upnp", "Successfully completed port mapping operation\n");
    ar->success = success;
    - ar->tima = purple_timeout_add(0, fire_ar_cb_async_and_free, ar);
    + ar->tima = g_timeout_add(0, fire_ar_cb_async_and_free, ar);
    }
    static void
    @@ -844,7 +844,7 @@
    purple_debug_error("upnp",
    "purple_upnp_set_port_mapping(): couldn't get local ip\n");
    ar->success = FALSE;
    - ar->tima = purple_timeout_add(0, fire_ar_cb_async_and_free, ar);
    + ar->tima = g_timeout_add(0, fire_ar_cb_async_and_free, ar);
    return;
    }
    strncpy(action_name, "AddPortMapping",
    @@ -868,7 +868,7 @@
    }
    ar->success = FALSE;
    - ar->tima = purple_timeout_add(0, fire_ar_cb_async_and_free, ar);
    + ar->tima = g_timeout_add(0, fire_ar_cb_async_and_free, ar);
    }
    static gboolean
    @@ -903,7 +903,7 @@
    }
    if (ar->tima > 0)
    - purple_timeout_remove(ar->tima);
    + g_source_remove(ar->tima);
    purple_http_conn_cancel(ar->hc);
    @@ -944,7 +944,7 @@
    } else if(control_info.status == PURPLE_UPNP_STATUS_UNABLE_TO_DISCOVER) {
    if (cb) {
    /* Asynchronously trigger a failed response */
    - ar->tima = purple_timeout_add(10, fire_port_mapping_failure_cb, ar);
    + ar->tima = g_timeout_add(10, fire_port_mapping_failure_cb, ar);
    } else {
    /* No need to do anything if nobody expects a response*/
    g_free(ar);
    @@ -989,7 +989,7 @@
    } else if(control_info.status == PURPLE_UPNP_STATUS_UNABLE_TO_DISCOVER) {
    if (cb) {
    /* Asynchronously trigger a failed response */
    - ar->tima = purple_timeout_add(10, fire_port_mapping_failure_cb, ar);
    + ar->tima = g_timeout_add(10, fire_port_mapping_failure_cb, ar);
    } else {
    /* No need to do anything if nobody expects a response*/
    g_free(ar);
    --- a/libpurple/util.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/util.c Sun Oct 08 20:44:26 2017 +0300
    @@ -900,6 +900,129 @@
    return retval;
    }
    +GDateTime *
    +purple_str_to_date_time(const char *timestamp, gboolean utc)
    +{
    + const gchar *str;
    + gint year = 0;
    + gint month = 0;
    + gint day = 0;
    + gint hour = 0;
    + gint minute = 0;
    + gint seconds = 0;
    + gint microseconds = 0;
    + int chars = 0;
    + GTimeZone *tz = NULL;
    + GDateTime *retval;
    +
    + g_return_val_if_fail(timestamp != NULL, NULL);
    +
    + str = timestamp;
    +
    + /* Strip leading whitespace */
    + while (g_ascii_isspace(*str))
    + str++;
    +
    + if (*str == '\0') {
    + return NULL;
    + }
    +
    + if (!g_ascii_isdigit(*str) && *str != '-' && *str != '+') {
    + return NULL;
    + }
    +
    + /* 4 digit year */
    + if (sscanf(str, "%04d", &year) && year > 0) {
    + str += 4;
    +
    + if (*str == '-' || *str == '/')
    + str++;
    + }
    +
    + /* 2 digit month */
    + if (!sscanf(str, "%02d", &month)) {
    + return NULL;
    + }
    +
    + str += 2;
    +
    + if (*str == '-' || *str == '/')
    + str++;
    +
    + /* 2 digit day */
    + if (!sscanf(str, "%02d", &day)) {
    + return NULL;
    + }
    +
    + str += 2;
    +
    + /* Grab the year off the end if there's still stuff */
    + if (*str == '/' || *str == '-') {
    + /* But make sure we don't read the year twice */
    + if (year > 0) {
    + return NULL;
    + }
    +
    + str++;
    +
    + if (!sscanf(str, "%04d", &year)) {
    + return NULL;
    + }
    + } else if (*str == 'T' || *str == '.') {
    + str++;
    +
    + /* Continue grabbing the hours/minutes/seconds */
    + if ((sscanf(str, "%02d:%02d:%02d", &hour, &minute, &seconds) == 3 &&
    + (str += 8)) ||
    + (sscanf(str, "%02d%02d%02d", &hour, &minute, &seconds) == 3 &&
    + (str += 6)))
    + {
    + if (*str == '.') {
    + str++;
    + if (sscanf(str, "%d%n", &microseconds, &chars) == 1) {
    + str += chars;
    + }
    + }
    +
    + if (*str) {
    + const gchar *end = str;
    + if (*end == '+' || *end == '-') {
    + end++;
    + }
    +
    + while (isdigit(*end) || *end == ':') {
    + end++;
    + }
    +
    + if (str != end) {
    + /* Trim anything trailing a purely numeric time zone. */
    + gchar *tzstr = g_strndup(str, end - str);
    + tz = g_time_zone_new(tzstr);
    + g_free(tzstr);
    + } else {
    + /* Just try whatever is there. */
    + tz = g_time_zone_new(str);
    + }
    + }
    + }
    + }
    +
    + if (!tz) {
    + /* No timezone specified. */
    + if (utc) {
    + tz = g_time_zone_new_utc();
    + } else {
    + tz = g_time_zone_new_local();
    + }
    + }
    +
    + retval = g_date_time_new(tz, year, month, day, hour, minute,
    + seconds + microseconds * pow(10, -chars));
    + g_time_zone_unref(tz);
    +
    + return retval;
    +}
    +
    char *
    purple_uts35_to_str(const char *format, size_t len, struct tm *tm)
    {
    @@ -4577,27 +4700,6 @@
    return ret;
    }
    -void
    -purple_print_utf8_to_console(FILE *filestream, char *message)
    -{
    - gchar *message_conv;
    - GError *error = NULL;
    -
    - /* Try to convert 'message' to user's locale */
    - message_conv = g_locale_from_utf8(message, -1, NULL, NULL, &error);
    - if (message_conv != NULL) {
    - fputs(message_conv, filestream);
    - g_free(message_conv);
    - }
    - else
    - {
    - /* use 'message' as a fallback */
    - g_warning("%s\n", error->message);
    - g_error_free(error);
    - fputs(message, filestream);
    - }
    -}
    -
    gboolean purple_message_meify(char *message, gssize len)
    {
    char *c;
    --- a/libpurple/util.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/util.h Sun Oct 08 20:44:26 2017 +0300
    @@ -78,8 +78,8 @@
    * @callback: The function to be called when the action is used on
    * the selected item.
    * @data: Additional data to be passed to the callback.
    - * @children: A GList of PurpleMenuActions to be added as a submenu
    - * of the action.
    + * @children: (element-type PurpleMenuAction) (transfer full): Menu actions to
    + * be added as a submenu of this action.
    *
    * Creates a new PurpleMenuAction.
    *
    @@ -132,7 +132,7 @@
    *
    * Returns the children of the PurpleMenuAction.
    *
    - * Returns: The GList of children.
    + * Returns: (element-type PurpleMenuAction) (transfer none): The menu children.
    */
    GList* purple_menu_action_get_children(const PurpleMenuAction *act);
    @@ -166,7 +166,7 @@
    /**
    * purple_menu_action_set_children:
    * @act: The menu action.
    - * @children: The PurpleMenuAtion children
    + * @children: (element-type PurpleMenuAction) (transfer full): The menu children
    *
    * Set the children of the PurpleMenuAction.
    */
    @@ -482,6 +482,18 @@
    struct tm *tm, long *tz_off, const char **rest);
    /**
    + * purple_str_to_date_time:
    + * @timestamp: The timestamp
    + * @utc: Assume UTC if no timezone specified
    + *
    + * Parses a timestamp in jabber, ISO8601, or MM/DD/YYYY format and returns
    + * a GDateTime.
    + *
    + * Returns: (transfer full): A GDateTime.
    + */
    +GDateTime *purple_str_to_date_time(const char *timestamp, gboolean utc);
    +
    +/**
    * purple_uts35_to_str:
    * @format: The formatting string, according to UTS \#35
    * See http://unicode.org/reports/tr35/
    @@ -1463,8 +1475,8 @@
    * This function extracts a list of URIs from the a "text/uri-list"
    * string. It was "borrowed" from gnome_uri_list_extract_uris
    *
    - * Returns: A GList containing strings allocated with g_malloc
    - * that have been splitted from uri-list.
    + * Returns: (element-type utf8): A GList containing strings allocated with
    + * g_malloc that have been split from uri-list.
    */
    GList *purple_uri_list_extract_uris(const gchar *uri_list);
    @@ -1476,10 +1488,10 @@
    * "text/uri-list" string. It was "borrowed" from
    * gnome_uri_list_extract_filenames
    *
    - * Returns: A GList containing strings allocated with g_malloc that
    - * contain the filenames in the uri-list. Note that unlike
    - * purple_uri_list_extract_uris() function, this will discard
    - * any non-file uri from the result value.
    + * Returns: (element-type utf8): A GList containing strings allocated with
    + * g_malloc that contain the filenames in the uri-list. Note that
    + * unlike the purple_uri_list_extract_uris() function, this will
    + * discard any non-file uri from the result value.
    */
    GList *purple_uri_list_extract_filenames(const gchar *uri_list);
    @@ -1567,17 +1579,6 @@
    gboolean purple_utf8_has_word(const char *haystack, const char *needle);
    /**
    - * purple_print_utf8_to_console:
    - * @filestream: The file stream (e.g. STDOUT or STDERR)
    - * @message: The message to print.
    - *
    - * Prints a UTF-8 message to the given file stream. The function
    - * tries to convert the UTF-8 message to user's locale. If this
    - * is not possible, the original UTF-8 text will be printed.
    - */
    -void purple_print_utf8_to_console(FILE *filestream, char *message);
    -
    -/**
    * purple_message_meify:
    * @message: The message to check
    * @len: The message length, or -1
    --- a/libpurple/win32/libc_interface.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/libpurple/win32/libc_interface.c Sun Oct 08 20:44:26 2017 +0300
    @@ -34,6 +34,7 @@
    #include "debug.h"
    #include "libc_internal.h"
    #include <glib/gstdio.h>
    +#include "util.h"
    /** This is redefined here because we can't include internal.h */
    #ifdef ENABLE_NLS
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,1415 @@
    +project('pidgin', 'c', meson_version : '>=0.37.0')
    +
    +# UPDATING VERSION NUMBERS FOR RELEASES
    +#
    +# purple_micro_version += 1
    +#
    +# If any functions have been added to libpurple, Pidgin, or Finch:
    +# purple_micro_version = 0
    +# purple_minor_version += 1
    +# purple_lt_current += 1
    +#
    +# If backwards compatibility has been broken in libpurple, Pidgin, or Finch:
    +# purple_micro_version = 0
    +# purple_minor_version = 0
    +# purple_major_version += 1;
    +# purple_lt_current += 1
    +#
    +# purple_version_suffix should be similar to one of the following:
    +# For beta releases: 'beta2'
    +# For code under development: 'devel'
    +# For production releases: ''
    +#
    +#
    +# If any code has changed in libgnt:
    +# gnt_micro_version += 1
    +#
    +# If any functions have been added to libgnt:
    +# gnt_micro_version = 0
    +# gnt_minor_version += 1
    +# gnt_lt_current += 1
    +#
    +# If backwards compatibility has been broken in libgnt:
    +# gnt_micro_version = 0
    +# gnt_minor_version = 0
    +# gnt_major_version += 1;
    +# gnt_lt_current += 1
    +#
    +# gnt_version_suffix should be similar to one of the following:
    +# For beta releases: 'beta2'
    +# For code under development: 'devel'
    +# For production releases: ''
    +#
    +# Make sure to update finch/libgnt/configure.ac with libgnt version changes.
    +#
    +purple_lt_current = 20
    +purple_major_version = 3
    +purple_minor_version = 0
    +purple_micro_version = 0
    +purple_version_suffix = 'devel'
    +purple_version = '@0@.@1@.@2@'.format(purple_major_version,
    + purple_minor_version,
    + purple_micro_version)
    +purple_display_version = '@0@@1@'.format(purple_version,
    + purple_version_suffix)
    +
    +# the last version for Finch 2 was 2.8.10,
    +# the first version for Finch 3 was 2.9.0
    +gnt_lt_current = 9
    +gnt_major_version = 2
    +gnt_minor_version = 9
    +gnt_micro_version = 0
    +gnt_version_suffix = 'devel'
    +gnt_version = '@0@.@1@.@2@'.format(gnt_major_version,
    + gnt_minor_version,
    + gnt_micro_version)
    +gnt_display_version = '@0@@1@'.format(gnt_version,
    + gnt_version_suffix)
    +
    +
    +add_project_arguments('-DHAVE_CONFIG_H=1', language : 'c')
    +conf = configuration_data()
    +man_conf = configuration_data()
    +pkg_conf = configuration_data()
    +version_conf = configuration_data()
    +
    +conf.set_quoted('PACKAGE', meson.project_name())
    +conf.set_quoted('PACKAGE_NAME', meson.project_name())
    +conf.set_quoted('VERSION', purple_display_version)
    +
    +version_conf.set('PURPLE_MAJOR_VERSION', purple_major_version)
    +version_conf.set('PURPLE_MINOR_VERSION', purple_minor_version)
    +version_conf.set('PURPLE_MICRO_VERSION', purple_micro_version)
    +version_conf.set('PURPLE_VERSION', purple_display_version)
    +version_conf.set('PURPLE_API_VERSION',
    + purple_lt_current - purple_minor_version)
    +
    +PURPLE_LIB_VERSION = '@0@.@1@.@2@'.format(purple_lt_current - purple_minor_version,
    + purple_minor_version,
    + purple_micro_version)
    +
    +version_conf.set('GNT_MAJOR_VERSION', gnt_major_version)
    +version_conf.set('GNT_MINOR_VERSION', gnt_minor_version)
    +version_conf.set('GNT_MICRO_VERSION', gnt_micro_version)
    +version_conf.set('GNT_VERSION', gnt_display_version)
    +version_conf.set('GNT_API_VERSION', gnt_lt_current - gnt_minor_version)
    +
    +GNT_LIB_VERSION = '@0@.@1@.@2@'.format(gnt_lt_current - gnt_minor_version,
    + gnt_minor_version,
    + gnt_micro_version)
    +
    +package_revision = vcs_tag(
    + input : 'package_revision.h.in',
    + output : 'package_revision.h',
    + fallback : meson.project_version())
    +
    +# For man pages.
    +man_conf.set('VERSION', purple_display_version)
    +man_conf.set('prefix', get_option('prefix'))
    +
    +# This is used for pkg-config files. This probably can be removed and the
    +# builtin generator used instead once we drop the Autotools build.
    +pkg_conf.set('VERSION', purple_display_version)
    +pkg_conf.set('PURPLE_MAJOR_VERSION', purple_major_version)
    +pkg_conf.set('prefix', get_option('prefix'))
    +pkg_conf.set('exec_prefix', '${prefix}')
    +pkg_conf.set('libdir', join_paths('${exec_prefix}', get_option('libdir')))
    +pkg_conf.set('includedir', join_paths('${prefix}', get_option('includedir')))
    +pkg_conf.set('datarootdir', join_paths('${prefix}', get_option('datadir')))
    +pkg_conf.set('datadir', '${datarootdir}')
    +pkg_conf.set('sysconfdir', join_paths('${prefix}', get_option('sysconfdir')))
    +
    +sedpath = find_program('sed')
    +
    +# Storing build arguments
    +if meson.version().version_compare('>=0.42.0')
    + meson.add_postconf_script('mkmesonconf.py')
    + conf.set('HAVE_MESON_CONFIG', true)
    +endif
    +
    +# Checks for programs.
    +compiler = meson.get_compiler('c')
    +
    +if compiler.has_function('alloca') # FIXME: Probably not enough.
    + conf.set('HAVE_ALLOCA_H', true)
    +else
    + error('alloca could not be found')
    +endif
    +
    +# Check for Sun compiler
    +SUNCC = compiler.compiles('void main() {__SUNPRO_C;};')
    +
    +# Check for Win32
    +if host_machine.system() == 'windows'
    + windows = import('windows')
    +
    + IS_WIN32 = true
    + ws2_32 = compiler.find_library('ws2_32')
    + dnsapi = compiler.find_library('dnsapi')
    + if build_machine.system() != 'windows'
    + conf.set('IS_WIN32_CROSS_COMPILED', true)
    + endif
    + conf.set('WIN32_LEAN_AND_MEAN', true)
    +else
    + IS_WIN32 = false
    + ws2_32 = []
    + dnsapi = []
    +endif
    +
    +# Checks for header files.
    +# AC_HEADER_SYS_WAIT:
    +conf.set('HAVE_SYS_WAIT_H', compiler.has_header('sys/wait.h'))
    +
    +foreach h : ['fcntl.h', 'unistd.h', 'stdint.h']
    + if compiler.has_header(h)
    + conf.set('HAVE_' + h.to_upper().underscorify(), true)
    + else
    + error(h + ' is required.')
    + endif
    +endforeach
    +
    +# Checks for typedefs, structures, and compiler characteristics.
    +time_t_size = compiler.sizeof('time_t',
    + prefix : '''
    +#include <stdio.h>
    +#include <time.h>
    +''')
    +conf.set('SIZEOF_TIME_T', time_t_size)
    +
    +conf.set('WORDS_BIGENDIAN', host_machine.endian() != 'little')
    +
    +conf.set('USE_WIN32_FHS',
    + IS_WIN32 and get_option('win32-dirs') == 'fhs')
    +
    +# Check for directories
    +if IS_WIN32
    + if get_option('win32-dirs') == 'fhs'
    + foreach dir : ['bin', 'lib', 'data', 'sysconf', 'locale']
    + path = join_paths(get_option('prefix'), get_option(dir + 'dir'))
    + conf.set('WIN32_FHS_@0@DIR'.format(dir.to_upper()), path)
    + endforeach
    +
    + conf.set('PURPLE_LIBDIR',
    + 'wpurple_lib_dir("purple-@0@")'.format(purple_major_version))
    + conf.set('PIDGIN_LIBDIR',
    + 'wpurple_lib_dir("pidgin-@0@")'.format(purple_major_version))
    + conf.set('FINCH_LIBDIR',
    + 'wpurple_lib_dir("finch-@0@")'.format(purple_major_version))
    + else
    + conf.set('PURPLE_LIBDIR', 'wpurple_lib_dir(NULL)')
    + conf.set('PIDGIN_LIBDIR', 'wpurple_lib_dir(NULL)')
    + conf.set('FINCH_LIBDIR', 'wpurple_lib_dir(NULL)')
    + endif
    +
    + conf.set('PURPLE_DATADIR', 'wpurple_data_dir()')
    + conf.set('PURPLE_SYSCONFDIR', 'wpurple_sysconf_dir()')
    + conf.set('PURPLE_LOCALEDIR', 'wpurple_locale_dir()')
    +else
    + foreach dir : ['data', 'sysconf', 'locale']
    + path = join_paths(get_option('prefix'), get_option(dir + 'dir'))
    + conf.set_quoted('PURPLE_@0@DIR'.format(dir.to_upper()), path)
    + endforeach
    +
    + common_libdir = join_paths(get_option('prefix'), get_option('libdir'))
    + conf.set_quoted('PURPLE_LIBDIR',
    + join_paths(common_libdir,
    + 'purple-@0@'.format(purple_major_version)))
    + conf.set_quoted('PIDGIN_LIBDIR',
    + join_paths(common_libdir,
    + 'pidgin-@0@'.format(purple_major_version)))
    + conf.set_quoted('FINCH_LIBDIR',
    + join_paths(common_libdir,
    + 'finch-@0@'.format(purple_major_version)))
    +endif
    +
    +abslibdir = join_paths(get_option('prefix'), get_option('libdir'))
    +PURPLE_PLUGINDIR = join_paths(abslibdir, 'purple-@0@'.format(purple_major_version))
    +conf.set_quoted('PURPLE_PLUGINDIR', PURPLE_PLUGINDIR)
    +PIDGIN_PLUGINDIR = join_paths(abslibdir, 'pidgin-@0@'.format(purple_major_version))
    +conf.set_quoted('PIDGIN_PLUGINDIR', PIDGIN_PLUGINDIR)
    +FINCH_PLUGINDIR = join_paths(abslibdir, 'finch-@0@'.format(purple_major_version))
    +conf.set_quoted('FINCH_PLUGINDIR', FINCH_PLUGINDIR)
    +
    +# Checks for library functions.
    +foreach func : ['strdup']
    + conf.set('HAVE_' + func.to_upper(),
    + compiler.has_function(func))
    +endforeach
    +
    +# Check for inet_aton
    +if not IS_WIN32
    + if not compiler.has_function('inet_aton')
    + if not compiler.has_function('inet_aton', args : '-lresolv')
    + # FIXME: Someone needs to link with -lresolv if needed.
    + error('inet_aton not found')
    + endif
    + endif
    +endif
    +if compiler.has_function('gethostent', args : '-lnsl')
    + conf.set('HAVE_LIBNSL', true)
    +endif
    +if IS_WIN32
    + conf.set('HAVE_GETADDRINFO', true)
    + conf.set('HAVE_INET_NTOP', true)
    +else
    + if not compiler.has_function('socket')
    + if not compiler.has_function('socket', args : '-lsocket')
    + error('socket not found')
    + endif
    + endif
    + # If all goes well, by this point the previous two checks will have
    + # pulled in -lsocket and -lnsl if we need them.
    + if compiler.has_function('getaddrinfo')
    + conf.set('HAVE_GETADDRINFO', true)
    + else
    + if compiler.has_function('getaddrinfo', args : '-lsocket -lnsl')
    + conf.set('HAVE_GETADDRINFO', true)
    + # FIXME: LIBS += declare_dependency(link_with : ['socket', 'nsl'])
    + endif
    + endif
    + conf.set('HAVE_INET_NTOP',
    + compiler.has_function('inet_ntop'))
    +endif
    +conf.set('HAVE_GETIFADDRS',
    + compiler.has_function('getifaddrs'))
    +
    +# Check for socklen_t (in Unix98)
    +if IS_WIN32
    + socket_header = 'ws2tcpip.h'
    +else
    + socket_header = 'sys/socket.h'
    +endif
    +if not compiler.has_header_symbol(socket_header, 'socklen_t')
    + code = '''
    +#include <sys/types.h>
    +#include <@0@>
    +int accept(int, struct sockaddr *, size_t *);
    +int main() {}
    +'''.format(socket_header)
    + if compiler.compiles(code, name : 'socklen_t is size_t')
    + conf.set('socklen_t', 'size_t')
    + else
    + conf.set('socklen_t', 'int')
    + endif
    +endif
    +
    +# Some systems do not have sa_len field for struct sockaddr.
    +conf.set('HAVE_STRUCT_SOCKADDR_SA_LEN',
    + compiler.has_member('struct sockaddr', 'sa_len',
    + prefix : '#include <@0@>'.format(socket_header)))
    +
    +# Check for v6-only sockets
    +if IS_WIN32
    + header = 'ws2tcpip.h'
    +else
    + header = 'netinet/in.h'
    +endif
    +conf.set('HAVE_IPV6_V6ONLY',
    + compiler.has_header_symbol(header, 'IPV6_V6ONLY'))
    +
    +# Windows and Haiku do not use libm for the math functions, they are part
    +# of the C library
    +math = compiler.find_library('m')
    +
    +code = '''
    +#include <stdio.h>
    +
    +int main(int argc, char *argv[])
    +{
    + int fd;
    +
    + fd = fileno(stdout);
    +
    + return !(fd > 0);
    +}
    +'''
    +result = compiler.run(code, name : 'fileno()')
    +conf.set('HAVE_FILENO', result.returncode() == 0)
    +
    +code = '''
    +#include <time.h>
    +#include <stdio.h>
    +
    +int main()
    +{
    + char buf[64];
    + time_t t = time(NULL);
    +
    + if (strftime(buf, sizeof(buf), "%z", localtime(&t)) != 5)
    + return 1;
    +
    + fprintf(stderr, "strftime(\"%%z\") yields: \"%s\"\n", buf);
    +
    + return !((buf[0] == '-' || buf[0] == '+') &&
    + (buf[1] >= '0' && buf[1] <= '9') &&
    + (buf[2] >= '0' && buf[2] <= '9') &&
    + (buf[3] >= '0' && buf[3] <= '9') &&
    + (buf[4] >= '0' && buf[4] <= '9')
    + );
    +}
    +'''
    +result = compiler.run(code, name : 'the %z format string in strftime()')
    +conf.set('HAVE_STRFTIME_Z_FORMAT', result.returncode() == 0)
    +
    +# before gettexting, in case iconv matters
    +IOKIT = []
    +if host_machine.system() == 'darwin'
    + if compiler.has_header('CoreFoundation/CoreFoundation.h')
    + if compiler.has_header('IOKit/IOKitLib.h')
    + conf.set('HAVE_IOKIT', true)
    + IOKIT = dependency('appleframeworks',
    + modules : ['IOKit', 'CoreFoundation'])
    + endif
    + endif
    +
    + if run_command('test', '-d', '/sw').returncode() == 0
    + # FIXME: Not done...
    + #CPPFLAGS="$CPPFLAGS -I/sw/include"
    + #LDFLAGS="$LDFLAGS -L/sw/lib"
    + endif
    +endif
    +
    +# #######################################################################
    +# # Disable creation and installation of translation files
    +# #######################################################################
    +
    +INSTALL_I18N = get_option('nls')
    +
    +if INSTALL_I18N
    + subdir('po')
    +
    + intltool_merge = find_program('intltool-merge')
    +endif
    +
    +# #######################################################################
    +# # Check for GLib 2.40 (required)
    +# #######################################################################
    +glib = dependency('glib-2.0', version : '>= 2.40.0')
    +gio = dependency('gio-2.0')
    +gmodule = dependency('gmodule-2.0')
    +gobject = dependency('gobject-2.0')
    +gthread = dependency('gthread-2.0')
    +gnome = import('gnome')
    +
    +if get_option('extraversion') != ''
    + DISPLAY_VERSION = '@0@-@1@'.format(meson.project_version(),
    + get_option('extraversion'))
    +else
    + DISPLAY_VERSION = meson.project_version()
    +endif
    +conf.set_quoted('DISPLAY_VERSION', DISPLAY_VERSION)
    +
    +force_deps = not get_option('missing-dependencies')
    +
    +with_x = get_option('x') and not IS_WIN32
    +
    +# #######################################################################
    +# # Check for GTK+ 2.18 and other things used by the GTK UI
    +# #######################################################################
    +enable_enchant = get_option('enchant')
    +enable_gevolution = get_option('gevolution')
    +enable_cap = get_option('cap')
    +enable_gestures = get_option('gestures')
    +enable_gcr = get_option('gcr')
    +
    +# #######################################################################
    +# Check Pidgin dependencies
    +# #######################################################################
    +if get_option('gtkui')
    + gtk = dependency('gtk+-3.0', version : '>= 3.4.2')
    + # We only really need Pango >= 1.4 for decent RTL support
    + pango = dependency('pango', version : '>= 1.4.0')
    + conf.set('HAVE_PANGO14', pango.found())
    +
    + webkit = dependency('webkitgtk-3.0', version : '>= 1.3.7')
    +
    + #######################################################################
    + # Check if we should compile with enchant support
    + #######################################################################
    + # We need enchant for spell checking dictionary enumeration,
    + # because webkit1 doesn't have this.
    + use_enchant = false
    + if enable_enchant
    + use_enchant = true
    + enchant = dependency('enchant', required : force_deps)
    + use_enchant = enchant.found()
    + conf.set('USE_ENCHANT', use_enchant)
    + else
    + enchant = []
    + endif
    +
    + #######################################################################
    + # Check if we should compile with X support
    + #######################################################################
    + if with_x
    + x11 = dependency('x11')
    + if x11.found()
    + conf.set('HAVE_X11', true)
    + else
    + with_x = false
    + if force_deps
    + error('''
    +X11 development headers not found.
    +Use -Dx=false if you do not need X11 support.
    +''')
    + endif
    + endif
    + endif
    + if not with_x
    + enable_gestures = false
    + x11 = []
    + endif
    +
    + #######################################################################
    + # Check for stuff needed by the Evolution integration plugin.
    + #######################################################################
    + if enable_gevolution
    + evo_deps = [
    + ['libebook-1.2', []],
    + ['libedata-book-1.2', []],
    + ['evolution-data-server-1.2', '>= 3.6']
    + ]
    + EVOLUTION_ADDRESSBOOK = []
    + foreach dep : evo_deps
    + EVOLUTION_ADDRESSBOOK += [
    + dependency(dep[0], version : dep[1], required : force_deps)
    + ]
    + if not EVOLUTION_ADDRESSBOOK[-1].found()
    + enable_gevolution = false
    + endif
    + endforeach
    + endif
    + conf.set('HAVE_EVOLUTION_ADDRESSBOOK', enable_gevolution)
    + if not enable_gevolution
    + EVOLUTION_ADDRESSBOOK = []
    + endif
    +
    + #######################################################################
    + # Check for libsqlite3 (for the Contact Availability Prediction plugin)
    + #######################################################################
    + if enable_cap
    + SQLITE3 = dependency('sqlite3', version : '>= 3.3', required : force_deps)
    + enable_cap = SQLITE3.found()
    + endif
    +
    + #######################################################################
    + # Check for GCR for its certificate widgets
    + #######################################################################
    + if enable_gcr
    + GCR = dependency('gcr-3', required : force_deps)
    + if GCR.found()
    + conf.set('ENABLE_GCR', true)
    + else
    + enable_gcr = false
    + endif
    + else
    + GCR = []
    + endif
    +
    +
    +else # GTK
    + enable_cap = false
    + enable_gcr = false
    + enable_gevolution = false
    + use_enchant = false
    +endif # GTK
    +
    +ENABLE_GTK = get_option('gtkui')
    +
    +
    +#######################################################################
    +# Check for ncurses and other things used by the console UI
    +#######################################################################
    +ncurses_inc = []
    +ncurses_libs = []
    +enable_consoleui = get_option('consoleui')
    +force_finch = enable_consoleui
    +if enable_consoleui
    + ncurses_libs = [
    + compiler.find_library('ncursesw', required : false),
    + compiler.find_library('panelw', required : false)
    + ]
    + if not ncurses_libs[0].found() or not ncurses_libs[1].found()
    + enable_consoleui = false
    + endif
    +
    + if IS_WIN32
    + # FIXME: $host ?
    + ncurses_sys_prefix = '/usr/$host/sys-root/mingw'
    + else
    + ncurses_sys_prefix = '/usr'
    + endif
    +
    + ncurses_sys_dirs = [ncurses_sys_prefix + '/include/ncursesw',
    + ncurses_sys_prefix + '/include']
    +
    + if enable_consoleui
    + # Some distros put the headers in ncursesw/, some don't
    + found_ncurses_h = false
    + foreach location : ncurses_sys_dirs
    + f = location + '/ncurses.h'
    + if not found_ncurses_h
    + if compiler.has_header_symbol(f, 'get_wch',
    + prefix : '#define _XOPEN_SOURCE_EXTENDED')
    + if location != '.'
    + ncurses_inc += [include_directories(location)]
    + endif
    + found_ncurses_h = true
    + endif
    + endif
    + endforeach
    +
    + if not found_ncurses_h
    + ncurses_inc = []
    + ncurses_libs = []
    + enable_consoleui = false
    + endif
    + else
    + # ncursesw was not found. Look for plain old ncurses
    + ncurses_libs = [
    + compiler.find_library('ncurses', required : false),
    + compiler.find_library('panel', required : false)
    + ]
    + enable_consoleui = ncurses_libs[0].found() and ncurses_libs[1].found()
    + conf.set('NO_WIDECHAR', true)
    + endif
    +endif
    +ncurses = declare_dependency(
    + include_directories : ncurses_inc,
    + dependencies : ncurses_libs
    +)
    +
    +if force_finch and not enable_consoleui
    + error('''
    +
    +Finch will not be built. You need to install ncursesw (or ncurses) and its development headers.
    +
    +''')
    +endif
    +
    +#conf.set('HAVE_WCWIDTH', compiler.has_function('wcwidth'))
    +
    +#######################################################################
    +# Check for LibXML2 (required)
    +#######################################################################
    +libxml = dependency('libxml-2.0', version : '>= 2.6.0')
    +if libxml.version().version_compare('<2.6.18')
    + message('Versions of libxml2 < 2.6.18 may contain bugs that could cause XMPP messages to be discarded.')
    +endif
    +
    +#######################################################################
    +# Check for JSON-GLib (required)
    +#######################################################################
    +
    +json = dependency('json-glib-1.0', version : '>= 0.14.0')
    +
    +#######################################################################
    +# Check for GStreamer
    +#######################################################################
    +
    +enable_gst = get_option('gstreamer')
    +if enable_gst
    + gstreamer = dependency('gstreamer-1.0', required : force_deps)
    + if gstreamer.found()
    + conf.set('USE_GSTREAMER', true)
    + else
    + enable_gst = false
    + endif
    +else
    + gstreamer = []
    +endif
    +
    +#######################################################################
    +# Check for GStreamer Video
    +#######################################################################
    +enable_gstvideo = enable_gst and get_option('gstreamer-video')
    +if enable_gstvideo
    + gstreamer_video = dependency('gstreamer-video-1.0',
    + required : false)
    + if gstreamer_video.found()
    + conf.set('USE_GSTVIDEO', true)
    + else
    + enable_gstvideo = false
    + endif
    +else
    + gstreamer_video = []
    +endif
    +
    +#######################################################################
    +# Check for Farstream
    +#######################################################################
    +if get_option('farstream')
    + farstream = dependency('farstream-0.2', version : '>= 0.2.7',
    + required : false)
    + enable_farstream = farstream.found()
    +else
    + farstream = []
    + enable_farstream = false
    +endif
    +
    +#######################################################################
    +# Check for Voice and Video support
    +#######################################################################
    +if get_option('vv')
    + if enable_gst and enable_gstvideo and enable_farstream
    + conf.set('USE_VV', true)
    + enable_vv = true
    + else
    + if force_deps
    + error('''
    +Dependencies for voice/video were not met.
    +Install the necessary gstreamer and farstream packages first.
    +Or use -Dvv=false if you do not need voice/video support.
    + ''')
    + endif
    + enable_vv = false
    + endif
    +else
    + enable_vv = false
    +endif
    +
    +#######################################################################
    +# Check for Raw data streams support in Farstream
    +#######################################################################
    +if enable_vv
    + gstreamer_app = dependency('gstreamer-app-1.0',
    + required : false)
    + if gstreamer_app.found()
    + conf.set('USE_GSTAPP', true)
    + conf.set('HAVE_MEDIA_APPLICATION', true)
    + endif
    +else
    + gstreamer_app = []
    +endif
    +
    +#######################################################################
    +# Check for Internationalized Domain Name support
    +#######################################################################
    +
    +if get_option('idn')
    + idn = dependency('libidn', version : '>= 0.0.0', required : force_deps)
    + conf.set('USE_IDN', idn.found())
    +else
    + idn = []
    +endif
    +
    +#######################################################################
    +# Check for Meanwhile headers (for Sametime)
    +#######################################################################
    +if get_option('meanwhile')
    + meanwhile = dependency('meanwhile', version : ['>= 1.0.0', '< 2.0.0'], required : force_deps)
    + enable_meanwhile = meanwhile.found()
    +else
    + enable_meanwhile = false
    + meanwhile = []
    +endif
    +
    +#######################################################################
    +# Check for Native Avahi headers (for Bonjour)
    +#######################################################################
    +
    +enable_avahi = get_option('avahi')
    +avahi = []
    +if enable_avahi and IS_WIN32
    + # Just keep enabled.
    +elif enable_avahi
    + # Attempt to autodetect Avahi
    + avahi_client = dependency('avahi-client', required : false)
    + avahi_glib = dependency('avahi-glib', required : false)
    + if avahi_client.found() and avahi_glib.found()
    + avahi = [avahi_client, avahi_glib]
    + else
    + enable_avahi = false
    + if force_deps
    + error('''
    +avahi development package not found.
    +Use -Davahi=false if you do not need avahi (Bonjour) support.
    +''')
    + endif
    + endif
    +endif
    +
    +
    +#######################################################################
    +# Check for SILC client includes and libraries
    +#######################################################################
    +have_silc = false
    +if get_option('silc')
    + silc = dependency('silcclient', version : '>= 1.1', required : false)
    + if silc.found()
    + have_silc = true
    + # SILC Toolkit >= 1.0.1 has a new MIME API
    + conf.set('HAVE_SILCMIME_H', true)
    + else
    + if force_deps
    + error('''
    +SILC development package not found.
    +Use -Dsilc=false if you do not need SILC support.
    +''')
    + endif
    + endif
    +endif
    +
    +#######################################################################
    +# Check for Gadu-Gadu protocol library (libgadu)
    +#######################################################################
    +
    +enable_libgadu = get_option('libgadu')
    +if enable_libgadu
    + libgadu = dependency('libgadu', version : '>= 1.12.0', required : false)
    + have_libgadu = libgadu.found()
    +
    + if have_libgadu
    + if not compiler.has_function('gg_is_gpl_compliant', dependencies : libgadu)
    + have_libgadu = false
    + message('''
    +libgadu is not compatible with the GPL when compiled with OpenSSL support.
    +
    +To link against libgadu, please recompile it using:
    +./configure --with-openssl=no
    +Then rerun this Meson build
    + ''')
    + endif
    + endif
    +
    + if not have_libgadu and force_deps
    + error('''
    +Libgadu development headers not found.
    +Use -Dlibgadu=false if you do not need GG (GaduGadu) support.
    +''')
    + endif
    +else
    + have_libgadu = false
    +endif
    +
    +
    +DEFAULT_PRPLS = ['bonjour', 'facebook', 'gg', 'irc', 'jabber', 'novell',
    + 'oscar', 'sametime', 'silc', 'simple', 'zephyr']
    +ALL_PRPLS = DEFAULT_PRPLS + ['null']
    +
    +dynamic_list = get_option('dynamic-prpls').split(',')
    +static_list = get_option('static-prpls').split(',')
    +if (static_list != [''] and static_list != []) and dynamic_list == ['all']
    + dynamic_list = []
    +endif
    +
    +if static_list == ['all']
    + static_list = DEFAULT_PRPLS
    +endif
    +STATIC_PRPLS = []
    +foreach prpl : static_list
    + if prpl == ''
    + # The list was empty; do nothing.
    + elif prpl == 'sametime' and not enable_meanwhile
    + # Do nothing
    + elif prpl == 'bonjour' and not enable_avahi
    + # Do nothing
    + elif prpl == 'silc' and not have_silc
    + # Do nothing
    + elif prpl == 'gg' and not have_libgadu
    + # Do nothing
    + elif prpl == 'zephyr' and IS_WIN32
    + # Do nothing
    + else
    + STATIC_PRPLS += [prpl]
    + endif
    +endforeach
    +STATIC_LINK_LIBS = []
    +extern_load = []
    +load_proto = []
    +extern_unload = []
    +unload_proto = []
    +foreach prpl : STATIC_PRPLS
    + # Ugly special case for 'libsilcpurple.la':
    + if prpl == 'silc'
    + STATIC_LINK_LIBS.append('\$(top_builddir)/libpurple/protocols/@1@/lib@1@purple.la'.format(meson.build_root(), prpl))
    + else
    + # FIXME: Shouldn't be libtool:
    + STATIC_LINK_LIBS.append('\$(top_builddir)/libpurple/protocols/@1@/lib@1@.la'.format(meson.build_root(), prpl))
    + endif
    + extern_load.append('extern gboolean @0@_plugin_load();'.format(prpl))
    + load_proto.append('@0@_plugin_load();'.format(prpl))
    + extern_unload.append('extern gboolean @0@_plugin_unload();'.format(prpl))
    + unload_proto.append('@0@_plugin_unload();'.format(prpl))
    +endforeach
    +STATIC_BONJOUR = STATIC_PRPLS.contains('bonjour')
    +STATIC_FACEBOOK = STATIC_PRPLS.contains('facebook')
    +STATIC_GG = STATIC_PRPLS.contains('gg')
    +STATIC_IRC = STATIC_PRPLS.contains('irc')
    +STATIC_JABBER = STATIC_PRPLS.contains('jabber')
    +STATIC_NOVELL = STATIC_PRPLS.contains('novell')
    +STATIC_OSCAR = STATIC_PRPLS.contains('oscar') or STATIC_PRPLS.contains('aim') or STATIC_PRPLS.contains('icq')
    +STATIC_SAMETIME = STATIC_PRPLS.contains('sametime')
    +STATIC_SILC = STATIC_PRPLS.contains('silc')
    +STATIC_SIMPLE = STATIC_PRPLS.contains('simple')
    +STATIC_ZEPHYR = STATIC_PRPLS.contains('zephyr')
    +conf.set('STATIC_PROTO_LOAD',
    + ' '.join(extern_load) +
    + ' static void static_proto_load(void) { ' + ' '.join(load_proto) + ' }')
    +conf.set('STATIC_PROTO_UNLOAD',
    + ' '.join(extern_unload) +
    + ' static void static_proto_unload(void) { ' + ' '.join(unload_proto) + ' }')
    +
    +if dynamic_list == ['all']
    + dynamic_list = DEFAULT_PRPLS
    +endif
    +DYNAMIC_PRPLS = []
    +foreach prpl : dynamic_list
    + if prpl == ''
    + # The list was empty; do nothing.
    + elif prpl == 'sametime' and not enable_meanwhile
    + # Do nothing.
    + elif prpl == 'bonjour' and not enable_avahi
    + # Do nothing.
    + elif prpl == 'silc' and not have_silc
    + # Do nothing.
    + elif prpl == 'gg' and not have_libgadu
    + # Do nothing.
    + elif prpl == 'zephyr' and IS_WIN32
    + # Do nothing.
    + else
    + DYNAMIC_PRPLS += [prpl]
    + endif
    +endforeach
    +
    +DYNAMIC_BONJOUR = DYNAMIC_PRPLS.contains('bonjour')
    +DYNAMIC_FACEBOOK = DYNAMIC_PRPLS.contains('facebook')
    +DYNAMIC_GG = DYNAMIC_PRPLS.contains('gg ')
    +DYNAMIC_IRC = DYNAMIC_PRPLS.contains('irc')
    +DYNAMIC_JABBER = DYNAMIC_PRPLS.contains('jabber')
    +DYNAMIC_NOVELL = DYNAMIC_PRPLS.contains('novell')
    +DYNAMIC_NULL = DYNAMIC_PRPLS.contains('null')
    +DYNAMIC_OSCAR = DYNAMIC_PRPLS.contains('oscar') or DYNAMIC_PRPLS.contains('aim') or DYNAMIC_PRPLS.contains('icq')
    +DYNAMIC_SAMETIME = DYNAMIC_PRPLS.contains('sametime')
    +DYNAMIC_SILC = DYNAMIC_PRPLS.contains('silc')
    +DYNAMIC_SIMPLE = DYNAMIC_PRPLS.contains('simple')
    +DYNAMIC_ZEPHYR = DYNAMIC_PRPLS.contains('zephyr')
    +
    +conf.set('HAVE_SYS_UTSNAME_H',
    + compiler.has_header('sys/utsname.h'))
    +conf.set('HAVE_UNAME',
    + compiler.has_function('uname'))
    +
    +
    +add_project_arguments(
    + '-DPURPLE_DISABLE_DEPRECATED',
    + '-DPIDGIN_DISABLE_DEPRECATED',
    + '-DFINCH_DISABLE_DEPRECATED',
    + '-DGNT_DISABLE_DEPRECATED',
    + language : 'c')
    +if compiler.get_id() == 'gcc'
    + # We enable -Wall later.
    + # If it's set after the warning CFLAGS in the compiler invocation, it counteracts the -Wno... flags.
    + # This leads to warnings we don't want.
    +# CFLAGS=`echo $CFLAGS |$sedpath 's/-Wall//'`
    +
    + # ENABLE WARNINGS SUPPORTED BY THE VERSION OF GCC IN USE
    + #
    + # Future Possibilities
    + #
    + # Consider adding -Wbad-function-cast.
    + # This leads to spurious warnings using GPOINTER_TO_INT(), et al. directly on a function call.
    + # We'd need an intermediate variable.
    + #
    + foreach newflag : [
    + '-Waggregate-return',
    + '-Wcast-align',
    + '-Wdeclaration-after-statement',
    + '-Wendif-labels',
    + '-Werror-implicit-function-declaration',
    + '-Wextra -Wno-unused-parameter',
    + '-Wformat-security',
    + '-Werror=format-security',
    + '-Winit-self',
    + '-Wmissing-declarations',
    + '-Wmissing-noreturn',
    + '-Wmissing-prototypes',
    + '-Wpointer-arith',
    + '-Wfloat-equal',
    + '-Wundef']
    + if compiler.has_argument(newflag)
    + add_project_arguments(newflag, language : 'c')
    + endif
    + endforeach
    +
    + if get_option('fortify')
    +# AC_MSG_CHECKING(for FORTIFY_SOURCE support)
    +# AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <features.h>]], [[
    +# #if !(__GNUC_PREREQ (4, 1) \
    +# || (defined __GNUC_RH_RELEASE__ && __GNUC_PREREQ (4, 0)) \
    +# || (defined __GNUC_RH_RELEASE__ && __GNUC_PREREQ (3, 4) \
    +# && __GNUC_MINOR__ == 4 \
    +# && (__GNUC_PATCHLEVEL__ > 2 \
    +# || (__GNUC_PATCHLEVEL__ == 2 && __GNUC_RH_RELEASE__ >= 8))))
    +# #error No FORTIFY_SOURCE support
    +# #endif
    +# return 0;
    +# ]])], [
    +# AC_MSG_RESULT(yes)
    +# DEBUG_CFLAGS='$DEBUG_CFLAGS -Wp,-D_FORTIFY_SOURCE=2'
    +# ], [
    +# AC_MSG_RESULT(no)
    +# ])
    + endif
    +endif
    +if SUNCC
    + add_project_arguments('-features=extensions', language : 'c')
    +endif
    +
    +pidginpath = find_program('pidgin', required : false)
    +
    +if get_option('glib-errors-trace')
    + if compiler.get_id() == 'clang'
    + error('--enable-glib-errors-trace doesn\'t work with clang')
    + endif
    + conf.set('ENABLE_GLIBTRACE', true)
    + add_project_arguments('-rdynamic', language : 'c')
    +endif
    +
    +#######################################################################
    +# Check for D-Bus libraries
    +#######################################################################
    +
    +# dbus doesn't compile for win32 at the moment
    +enable_dbus = get_option('dbus') and not IS_WIN32
    +
    +if enable_dbus
    + dbus_binding_tool = find_program('dbus-binding-tool')
    + enable_dbus = dbus_binding_tool.found()
    +endif
    +
    +if enable_dbus
    + dbus = dependency('dbus-1', version : '>= 0.60', required : force_deps)
    + dbus_glib = dependency('dbus-glib-1', version : '>= 0.60', required : force_deps)
    + enable_dbus = dbus.found() and dbus_glib.found()
    +else
    + dbus = []
    + dbus_glib = []
    +endif
    +
    +if enable_dbus
    + conf.set('HAVE_DBUS', true)
    +endif
    +
    +#######################################################################
    +# Check for Unity and Messaging Menu
    +# Remove when Ubuntu 16.04 is EOL
    +#######################################################################
    +enable_unity = get_option('unity-integration')
    +if enable_unity
    + UNITY = [
    + dependency('unity', version : '>= 6.8'),
    + dependency('messaging-menu', version : '>= 12.10')
    + ]
    + conf.set('USES_MM_CHAT_SECTION', 'X-MessagingMenu-UsesChatSection=true')
    +else
    + conf.set('USES_MM_CHAT_SECTION', '')
    +endif
    +
    +#######################################################################
    +# Check for Secret Service headers
    +#######################################################################
    +
    +enable_secret_service = get_option('secret-service')
    +if enable_secret_service
    + secretservice = dependency('libsecret-1', required : force_deps)
    + if secretservice.found()
    + else
    + enable_secret_service = false
    + endif
    +endif
    +
    +#######################################################################
    +# Check for GNOME Keyring headers
    +#######################################################################
    +
    +enable_gnome_keyring = get_option('gnome-keyring') and not IS_WIN32
    +
    +if enable_gnome_keyring
    + gnome_keyring = dependency('gnome-keyring-1', required : force_deps)
    + if gnome_keyring.found()
    + conf.set('HAVE_GNOMEKEYRING', true)
    + else
    + enable_gnome_keyring = false
    + endif
    +else
    + gnome_keyring = []
    +endif
    +
    +#######################################################################
    +# Check for KWallet headers
    +#######################################################################
    +
    +enable_kwallet = get_option('kwallet') and not IS_WIN32
    +enable_kwallet = false
    +
    +if enable_kwallet
    + # Ensure C++ compiler works
    + add_languages('cpp')
    + cxx_compiler = meson.get_compiler('cpp')
    +
    + qt4 = dependency('qt4', modules : 'Core', required : force_deps)
    + enable_kwallet = qt4.found()
    +endif
    +
    +if enable_kwallet
    +# AC_MSG_CHECKING([for metaobject compiler])
    +# MOC=`$PKG_CONFIG --variable=moc_location QtCore`
    +# AC_SUBST(MOC)
    +# AC_MSG_RESULT([$MOC])
    +#
    +# KWALLET_CXXFLAGS=''
    +# KWALLET_LIBS=''
    +# if test -z '$with_kwallet_includes' || test -z '$with_kwallet_libs'; then
    +# AC_CHECK_PROG(KDE4_CONFIG, kde4-config, kde4-config, no)
    +# if test 'x$KDE4_CONFIG' = 'xno'; then
    +# enable_kwallet = false
    +# if test 'x$force_deps' = 'xyes'; then
    +# AC_MSG_ERROR([
    +#kde4-config not found. $KDE4_CONFIG
    +#Use -Dkwallet=false if you do not need KWallet support.
    +#])
    +# fi
    +# fi
    +# fi
    +endif
    +
    +if enable_kwallet
    +# if test 'x$KDE4_CONFIG' != 'xno'; then
    +# KWALLET_CXXFLAGS='$QT4_CFLAGS -I`$KDE4_CONFIG --path include`'
    +# fi
    +# CPPFLAGS='$CPPFLAGS $KWALLET_CXXFLAGS'
    +# AC_CHECK_HEADER([kwallet.h], , [
    +# enable_kwallet = false
    +# if test 'x$force_deps' = 'xyes'; then
    +# AC_MSG_ERROR([
    +#KWallet development headers not found.
    +#Use -Dkwallet=false if you do not need KWallet support.
    +#])
    +# fi
    +#])
    +endif
    +
    +if enable_kwallet
    +# AC_MSG_CHECKING([for KWallet libraries])
    +# if test 'x$KDE4_CONFIG' != 'xno'; then
    +# KWALLET_LIBS='-L`$KDE4_CONFIG --install lib`/kde4/devel -lkdeui'
    +# else
    +# KWALLET_LIBS='-lkdeui'
    +# fi
    +# KWALLET_LIBS='$KWALLET_LIBS'
    +# LIBS='$LIBS $KWALLET_LIBS $QT4_LIBS'
    +# AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <kwallet.h>],
    +# [KWallet::Wallet::LocalWallet();])], [AC_MSG_RESULT([yes])],
    +# [
    +# AC_MSG_RESULT(no)
    +# enable_kwallet = false
    +# if test 'x$force_deps' = 'xyes'; then
    +# AC_MSG_ERROR([
    +#KWallet development libraries not found.
    +#Use -Dkwallet=false if you do not need KWallet support.
    +#])
    +# fi
    +# ])
    +endif
    +
    +#######################################################################
    +# Check for GPlugin 0.0.17
    +#######################################################################
    +if get_option('plugins')
    + gplugin = dependency('gplugin', version : '>= 0.0.17')
    + # GPLUGIN_REQ sets pkg-config requirements in the .pc file
    + pkg_conf.set('GPLUGIN_REQ', ', gplugin')
    + enable_introspection = dependency('gobject-introspection-1.0',
    + version : '>= 1.30.0', required : false).found()
    +else
    + gplugin = []
    + enable_introspection = false
    +endif
    +
    +if enable_introspection
    + conf.set('ENABLE_INTROSPECTION', true)
    +endif
    +
    +#######################################################################
    +# Check for Python
    +#######################################################################
    +
    +# Python scripts are used to auto-generate about 3000 lines of C
    +# and XML code that wraps (part of) the existing API so that
    +# it is now accessible through D-Bus.
    +
    +if enable_dbus or enable_consoleui
    + if meson.version().version_compare('>=0.38.0')
    + python3_mod = import('python3')
    + python = python3_mod.find_python()
    + else
    + python = find_program('python3')
    + endif
    +endif
    +
    +# Check for Python headers (currently useful only for libgnt)
    +if enable_consoleui
    + python_dep = dependency('python3')
    + conf.set('USE_PYTHON', python_dep.found())
    +endif
    +
    +#######################################################################
    +# SSL support
    +#######################################################################
    +
    +ssl_certificates_dir = get_option('system-ssl-certs')
    +
    +SSL_CERTIFICATES_DIR = ''
    +if ssl_certificates_dir != ''
    + if run_command('test', '-d', ssl_certificates_dir).returncode() != 0
    + if IS_WIN32
    + message(ssl_certificates_dir + ' does not exist. It may be OK when cross-compiling, but please make sure about it.')
    + else
    + error(ssl_certificates_dir + ' does not exist, if this is the correct location please make sure that it exists.')
    + endif
    + endif
    + SSL_CERTIFICATES_DIR = ssl_certificates_dir
    +endif
    +if SSL_CERTIFICATES_DIR != ''
    + conf.set_quoted('SSL_CERTIFICATES_DIR', SSL_CERTIFICATES_DIR)
    +endif
    +INSTALL_SSL_CERTIFICATES = SSL_CERTIFICATES_DIR == ''
    +
    +if get_option('plugins')
    + conf.set('PURPLE_PLUGINS', 1)
    + PLUGINS = true
    + conf.set('PLUGINS_DEFINE', '#define PURPLE_PLUGINS 1')
    +else
    + PLUGINS = false
    + conf.set('PLUGINS_DEFINE', '#undef PURPLE_PLUGINS')
    +endif
    +
    +#######################################################################
    +# Check for Nettle (Crypto Library)
    +#######################################################################
    +
    +enable_nettle = get_option('nettle')
    +
    +if enable_nettle
    + nettle = dependency('nettle', version : '>= 3.0')
    + enable_nettle = nettle.found()
    + conf.set('HAVE_NETTLE', enable_nettle)
    +
    + if not enable_nettle and force_deps
    + error('''
    +Nettle development headers not found
    +Use -Dnettle=false if you do not need it.
    +''')
    + endif
    +endif
    +
    +#######################################################################
    +# Check for Cyrus-SASL (for xmpp/irc)
    +#######################################################################
    +foreach func : ['snprintf', 'connect']
    + conf.set('HAVE_' + func.to_upper(),
    + compiler.has_function(func))
    +endforeach
    +enable_cyrus_sasl = get_option('cyrus-sasl')
    +if enable_cyrus_sasl
    + if compiler.has_function('sasl_client_init', args : '-lsasl2')
    + conf.set('HAVE_CYRUS_SASL', true)
    + sasl = declare_dependency(link_args : '-lsasl2')
    + else
    + error('Cyrus SASL library not found')
    + endif
    +else
    + enable_cyrus_sasl = false
    + sasl = []
    +endif
    +
    +#######################################################################
    +# Check for Kerberos (for Zephyr)
    +#######################################################################
    +conf.set('ZEPHYR_INT32', 'long')
    +#AC_SUBST(KRB4_CFLAGS)
    +#AC_SUBST(KRB4_LDFLAGS)
    +#AC_SUBST(KRB4_LIBS)
    +kerberos = get_option('krb4')
    +if kerberos
    + if kerberos != 'yes'
    +# KRB4_CFLAGS='-I${kerberos}/include'
    +# if test -d '$kerberos/include/kerberosIV' ; then
    +# KRB4_CFLAGS='$KRB4_CFLAGS -I${kerberos}/include/kerberosIV'
    +# fi
    +# KRB4_LDFLAGS='-L${kerberos}/lib'
    + elif run_command('test', '-d', '/usr/local/include/kerberosIV').returncode() == 0
    +# KRB4_CFLAGS='-I/usr/local/include/kerberosIV'
    + elif run_command('test', '-d', '/usr/include/kerberosIV').returncode() == 0
    +# KRB4_CFLAGS='-I/usr/include/kerberosIV'
    + endif
    + conf.set('ZEPHYR_USES_KERBEROS', true)
    +
    +# AC_CHECK_LIB(krb4, krb_rd_req,
    +# [KRB4_LIBS='-lkrb4 -ldes425 -lkrb5 -lk5crypto -lcom_err'],
    +# [AC_CHECK_LIB(krb, krb_rd_req,
    +# [KRB4_LIBS='-lkrb -ldes'],
    +# [AC_MSG_ERROR([Kerberos 4 libraries not found])],
    +# -ldes)],
    +# -ldes425 -lkrb5 -lk5crypto -lcom_err)
    +# AC_CHECK_FUNCS(krb_set_key krb_rd_req krb_get_lrealm)
    +# AC_CHECK_FUNCS(krb_get_err_text krb_log)
    + krb4 = []
    +endif
    +if not kerberos
    + krb4 = []
    +endif
    +
    +#######################################################################
    +# Check for external libzephyr
    +#######################################################################
    +zephyr = get_option('zephyr')
    +if zephyr
    + ext_zephyr = dependency('zephyr', required : force_deps)
    + zephyr = ext_zephyr.found()
    +else
    + ext_zephyr = []
    +endif
    +EXTERNAL_LIBZEPHYR = zephyr
    +conf.set('LIBZEPHYR_EXT', EXTERNAL_LIBZEPHYR)
    +
    +#AC_MSG_CHECKING(for me pot o' gold)
    +#AC_MSG_RESULT(no)
    +foreach func : ['gethostid', 'timegm']
    + conf.set('HAVE_' + func.to_upper(),
    + compiler.has_function(func))
    +endforeach
    +foreach header : 'paths.h sgtty.h sys/cdefs.h sys/file.h sys/filio.h sys/ioctl.h sys/msgbuf.h sys/select.h sys/uio.h sys/utsname.h sys/wait.h termios.h'.split()
    + conf.set('HAVE_' + header.to_upper().underscorify(),
    + compiler.has_header(header))
    +endforeach
    +
    +# sys/sysctl.h on OpenBSD 4.2 requires sys/param.h
    +# sys/sysctl.h on FreeBSD requires sys/types.h
    +have_sys_param_h = compiler.has_header('sys/param.h')
    +conf.set('HAVE_SYS_PARAM_H', have_sys_param_h)
    +prefix = '''
    +#include <sys/types.h>
    +'''
    +if have_sys_param_h
    + prefix += '''
    +#include <sys/param.h>
    +'''
    +endif
    +conf.set('HAVE_SYS_SYSCTL_H',
    + compiler.has_header('sys/sysctl.h', prefix : prefix))
    +conf.set('HAVE_SYS_SOCKET_H',
    + compiler.has_header('sys/socket.h'))
    +#AC_VAR_TIMEZONE_EXTERNALS
    +
    +conf.set('HAVE_TM_GMTOFF',
    + compiler.has_member('struct tm', 'tm_gmtoff',
    + prefix : '#include<time.h>'))
    +
    +#######################################################################
    +# Disable pixmap installation
    +#######################################################################
    +INSTALL_PIXMAPS = get_option('pixmaps-install')
    +
    +#######################################################################
    +# Tweak status tray icon installation directory
    +#######################################################################
    +ENABLE_TRAYCOMPAT = get_option('trayicon-compat')
    +
    +# check for gtk-doc
    +ENABLE_DOC = get_option('doc')
    +if ENABLE_DOC
    + if meson.version().version_compare('<0.41.2')
    + if force_deps
    + error('Meson 0.41.2 or newer is required to build documentation.')
    + endif
    + ENABLE_DOC = false
    + endif
    +endif
    +
    +enable_debug = get_option('debug')
    +conf.set('DEBUG', enable_debug)
    +
    +PURPLE_AVAILABLE = true
    +
    +# So that config.h may be found.
    +toplevel_inc = include_directories('.')
    +
    +subdir('libpurple')
    +subdir('share/sounds')
    +subdir('share/ca-certs')
    +subdir('finch')
    +subdir('pidgin')
    +subdir('doc')
    +
    +configure_file(output : 'config.h',
    + configuration : conf)
    +
    +message('')
    +message('pidgin ' + purple_display_version)
    +
    +message('')
    +message('Build GTK+ UI................. : ' + get_option('gtkui').to_string())
    +message('Build console UI.............. : ' + enable_consoleui.to_string())
    +message('Build for X11................. : ' + with_x.to_string())
    +message('')
    +message('Enable Gestures............... : ' + enable_gestures.to_string())
    +message('Protocols to build dynamically : @0@'.format(DYNAMIC_PRPLS))
    +message('Protocols to link statically.. : @0@'.format(STATIC_PRPLS))
    +message('')
    +message('Build with GStreamer support.. : ' + enable_gst.to_string())
    +message('Build with D-Bus support...... : ' + enable_dbus.to_string())
    +message('Build with voice and video.... : ' + enable_vv.to_string())
    +message('Build with GNU Libidn......... : ' + get_option('idn').to_string())
    +if SSL_CERTIFICATES_DIR != ''
    + message('SSL CA certificates directory. : ' + SSL_CERTIFICATES_DIR)
    +endif
    +message('Build with Nettle support..... : ' + enable_nettle.to_string())
    +message('Build with Cyrus SASL support. : ' + enable_cyrus_sasl.to_string())
    +message('Use kerberos 4 with zephyr.... : ' + kerberos.to_string())
    +message('Use external libzephyr........ : ' + zephyr.to_string())
    +message('Install pixmaps............... : ' + INSTALL_PIXMAPS.to_string())
    +message('Old tray icon compatibility... : ' + ENABLE_TRAYCOMPAT.to_string())
    +message('Install translations.......... : ' + INSTALL_I18N.to_string())
    +message('Has you....................... : yes')
    +message('')
    +message('Build with Enchant support.... : ' + use_enchant.to_string())
    +message('Build with GCR widgets........ : ' + enable_gcr.to_string())
    +message('Build Unity integration plugin.: ' + enable_unity.to_string())
    +message('')
    +message('Build with GNOME Keyring...... : ' + enable_gnome_keyring.to_string())
    +message('Build with KWallet............ : ' + enable_kwallet.to_string())
    +message('Build with Secret Service..... : ' + enable_secret_service.to_string())
    +message('')
    +message('Build with plugin support..... : ' + PLUGINS.to_string())
    +message('Enable Introspection...........: ' + enable_introspection.to_string())
    +
    +if IS_WIN32
    + message('')
    + message('Win32 directory structure..... : ' + get_option('win32-dirs'))
    +endif
    +
    +message('')
    +message('Print debugging messages...... : ' + enable_debug.to_string())
    +message('Generate documentation........ : ' + ENABLE_DOC.to_string())
    +message('')
    +bindir = join_paths(get_option('prefix'), get_option('bindir'))
    +message('Pidgin will be installed in @0@.'.format(bindir))
    +if pidginpath.found()
    + message('Warning: You have an old copy of Pidgin at @0@.'.format(pidginpath.path()))
    +endif
    +if not INSTALL_PIXMAPS
    + message('')
    + message('Warning: You have disabled the installation of pixmap data, but Pidgin')
    + message('still requires installed pixmaps. Be sure you know what you are doing.')
    +endif
    +if not INSTALL_I18N
    + message('')
    + message('Warning: You have disabled the building and installation of translation')
    + message('data. This will prevent building Pidgin desktop files.')
    + message('Be sure you know what you are doing.')
    +endif
    +message('')
    +message('configure complete, now type \'ninja\'')
    +message('')
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/meson_options.txt Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,116 @@
    +option('win32-dirs', type : 'combo', choices : ['classic', 'fhs'], value : 'classic',
    + description : 'use win32 "classic" (Program Files-like) or "fhs" (unix-like) directory structure (default: "classic")')
    +
    +option('nls', type : 'boolean', value : true,
    + description : 'enable installation of translation files')
    +
    +option('extraversion', type : 'string',
    + description : 'extra version number to be displayed in Help->About and --help (for packagers)')
    +
    +option('missing-dependencies', type : 'boolean', value : false,
    + description : 'skip missing dependencies instead of aborting configuration')
    +
    +option('x', type : 'boolean', value : true)
    +
    +option('gtkui', type : 'boolean', value : true,
    + description : 'compile with GTK+ user interface')
    +option('consoleui', type : 'boolean', value : true,
    + description : 'compile with console user interface')
    +
    +option('doc', type : 'boolean', value : false,
    + description : 'build documentation with gtk-doc')
    +
    +option('enchant', type : 'boolean', value : true,
    + description : 'compile with Enchange spell checking support')
    +
    +option('gevolution', type : 'boolean', value : false,
    + description : 'compile with the Evolution plugin')
    +
    +option('cap', type : 'boolean', value : false,
    + description : 'compile with Contact Availability Prediction plugin')
    +
    +option('gestures', type : 'boolean', value : true,
    + description : 'compile with the gestures plugin')
    +
    +option('gcr', type : 'boolean', value : false,
    + description : 'compile with GCR certificate widgets')
    +
    +option('gstreamer', type : 'boolean', value : true,
    + description : 'compile with GStreamer audio support')
    +
    +option('gstreamer-video', type : 'boolean', value : true,
    + description : 'compile with GStreamer 1.0 Video Overlay support')
    +
    +option('farstream', type : 'boolean', value : true,
    + description : 'compile with farstream support')
    +
    +option('vv', type : 'boolean', value : true,
    + description : 'compile with voice and video support')
    +
    +option('idn', type : 'boolean', value : true,
    + description : 'compile with IDN support')
    +
    +option('meanwhile', type : 'boolean', value : true,
    + description : 'compile with meanwhile')
    +
    +option('avahi', type : 'boolean', value : true,
    + description : 'compile with avahi (required for Bonjour support)')
    +
    +option('libgadu', type : 'boolean', value : true,
    + description : 'compile with libgadu (required for GaduGadu support)')
    +
    +option('silc', type : 'boolean', value : true,
    + description : 'compile with SILC plugin')
    +
    +option('static-prpls', type : 'string',
    + description : 'Link to certain protocols statically')
    +
    +option('dynamic-prpls', type : 'string', value: 'all',
    + description : 'specify which protocols to build dynamically')
    +
    +option('plugins', type : 'boolean', value : true,
    + description : 'compile with plugin support')
    +
    +option('krb4', type : 'boolean', value : false,
    + description : 'compile Zephyr plugin with Kerberos 4 support')
    +
    +option('zephyr', type : 'boolean', value : false,
    + description : 'compile Zephyr plugin against external libzephyr')
    +
    +option('fortify', type : 'boolean', value : true,
    + description : 'compile with FORTIFY_SOURCE support')
    +
    +option('glib-errors-trace', type : 'boolean', value : false,
    + description : 'print backtraces for glib errors')
    +
    +option('dbus', type : 'boolean', value : true,
    + description : 'enable D-Bus support')
    +
    +option('unity-integration', type : 'boolean', value : false,
    + description : 'compile with support for unity integration plugin')
    +
    +option('secret-service', type : 'boolean', value : true,
    + description : 'enable Secret Service support')
    +
    +option('gnome-keyring', type : 'boolean', value : true,
    + description : 'enable GNOME Keyring support')
    +
    +option('kwallet', type : 'boolean', value : true,
    + description : 'enable KWallet support')
    +
    +option('system-ssl-certs', type : 'string',
    + description : 'directory containing system-wide SSL CA certificates')
    +option('nettle', type : 'boolean', value : true,
    + description : 'enable Nettle support')
    +
    +option('cyrus-sasl', type : 'boolean', value : false,
    + description : 'enable Cyrus SASL support for XMPP/IRC')
    +
    +option('pixmaps-install', type : 'boolean', value : true,
    + description : 'enable installation of pixmap files - Pidgin still needs them!')
    +
    +option('trayicon-compat', type : 'boolean', value : false,
    + description : 'install tray icons in location compatible with older releases of hicolor-icon-theme')
    +
    +option('debug', type : 'boolean', value : false,
    + description : 'compile with debugging support')
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/mkmesonconf.py Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,70 @@
    +#!/usr/bin/env python3
    +#
    +# 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
    +
    +"""
    +Produce meson-config.h in a build directory.
    +
    +This should not really be run manually. It is used by Meson as a
    +post-configuration script to create meson-config.h which for now simply
    +contains information about the configuration used to create the build
    +directory.
    +"""
    +
    +import html
    +import json
    +import os
    +import shlex
    +import subprocess
    +import sys
    +
    +
    +try:
    + introspect = os.environ['MESONINTROSPECT']
    +except KeyError:
    + print('Meson is too old; '
    + 'it does not set MESONINTROSPECT for postconf scripts.')
    + sys.exit(1)
    +else:
    + introspect = shlex.split(introspect)
    +
    +try:
    + build_root = os.environ['MESON_BUILD_ROOT']
    +except KeyError:
    + print('Meson is too old; '
    + 'it does not set MESON_BUILD_ROOT for postconf scripts.')
    + sys.exit(1)
    +
    +
    +def tostr(obj):
    + if isinstance(obj, str):
    + return html.escape(repr(obj))
    + else:
    + return repr(obj)
    +
    +
    +conf = subprocess.check_output(introspect + ['--buildoptions', build_root],
    + universal_newlines=True)
    +conf = json.loads(conf)
    +
    +settings = ' '.join('{}={}'.format(option['name'], tostr(option['value']))
    + for option in sorted(conf, key=lambda x: x['name']))
    +
    +with open(os.path.join(build_root, 'meson-config.h'), 'w') as f:
    + f.write('#define MESON_ARGS "{}"'.format(settings))
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/package_revision.h.in Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,1 @@
    +#define REVISION "@VCS_TAG@"
    --- a/pidgin/Makefile.am Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/Makefile.am Sun Oct 08 20:44:26 2017 +0300
    @@ -1,13 +1,15 @@
    EXTRA_DIST = \
    - getopt.c \
    - getopt.h \
    - getopt1.c \
    + about.ui \
    + about.html \
    + about.md \
    + credits.json \
    gtk3compat.h \
    gtkdebug.html \
    + logo.png \
    pidgin.gresource.xml \
    Makefile.mingw \
    - data/pidgin.appdata.xml.in \
    - data/pidgin.desktop.in \
    + data/im.pidgin.Pidgin.appdata.xml.in \
    + data/im.pidgin.Pidgin.desktop.in \
    data/pidgin-3.pc.in \
    data/pidgin-3-uninstalled.pc.in \
    win32/MinimizeToTray.h \
    @@ -84,7 +86,8 @@
    gtkxfer.c \
    libpidgin.c \
    minidialog.c \
    - pidgin.gresource.c \
    + pidginabout.c \
    + pidginresources.c \
    pidgintooltip.c
    libpidgin_la_headers = \
    @@ -132,6 +135,7 @@
    gtkwhiteboard.h \
    gtkxfer.h \
    minidialog.h \
    + pidginabout.h \
    pidgintooltip.h \
    pidgin.h
    @@ -170,22 +174,22 @@
    libpidgininclude_HEADERS = \
    $(libpidgin_la_headers)
    -libpidgin_la_builtheaders = pidgin.gresource.h
    -libpidgin_la_builtsources = pidgin.gresource.c
    +libpidgin_la_builtheaders = pidginresources.h
    +libpidgin_la_builtsources = pidginresources.c
    BUILT_SOURCES = $(libpidgin_la_builtheaders) $(libpidgin_la_builtsources)
    -CLEANFILES = pidgin.gresource.h pidgin.gresource.c
    +CLEANFILES = pidginresources.h pidginresources.c
    -%.gresource.h: %.gresource.xml
    +%resources.h: %.gresource.xml
    $(AM_V_GEN)$(GLIB_COMPILE_RESOURCES) --generate-header --target $@ --c-name $* --sourcedir $(srcdir) $<
    -%.gresource.c: %.gresource.xml
    +%resources.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
    +pidginresources.c: gtkdebug.html
    +pidginresources.h: gtkdebug.html
    +gtkdebug.c: pidginresources.h
    libpidgin_la_DEPENDENCIES = @LIBOBJS@ $(LIBPIDGIN_WIN32RES)
    libpidgin_la_LDFLAGS = -export-dynamic -no-undefined \
    @@ -200,8 +204,8 @@
    $(GSTREAMER_LIBS) \
    $(GSTVIDEO_LIBS) \
    $(GSTINTERFACES_LIBS) \
    - $(XSS_LIBS) \
    $(INTLLIBS) \
    + $(JSON_LIBS) \
    $(LIBXML_LIBS) \
    $(WEBKIT_LIBS) \
    $(GTK_LIBS) \
    @@ -232,6 +236,7 @@
    $(GSTINTERFACES_CFLAGS) \
    $(DEBUG_CFLAGS) \
    $(GTK_CFLAGS) \
    + $(JSON_CFLAGS) \
    $(X11_CFLAGS) \
    $(DBUS_CFLAGS) \
    $(LIBXML_CFLAGS) \
    @@ -242,19 +247,19 @@
    pkgconfig_DATA = data/pidgin-3.pc
    if INSTALL_I18N
    -DESKTOP_FILE=data/pidgin.desktop
    +DESKTOP_FILE=data/im.pidgin.Pidgin.desktop
    appsdir = $(datadir)/applications
    -apps_in_files = data/pidgin.desktop.in
    +apps_in_files = data/im.pidgin.Pidgin.desktop.in
    apps_DATA = $(apps_in_files:.desktop.in=.desktop)
    # silenced INTLTOOL_DESKTOP_RULE
    %.desktop: %.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po)
    $(AM_V_GEN) LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@ > /dev/null
    -appdatadir = $(datarootdir)/appdata
    +appdatadir = $(datarootdir)/metainfo
    appdata_DATA = $(appdata_in_files:.xml.in=.xml)
    -appdata_in_files = data/pidgin.appdata.xml.in
    +appdata_in_files = data/im.pidgin.Pidgin.appdata.xml.in
    @INTLTOOL_XML_RULE@
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/about.html Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,22 @@
    +<h2>Pidgin</h2>
    +
    +<p>Pidgin is a messaging client based on libpurple which is capable of connecting to multiple messaging services at once. Pidgin is written in C using GTK+. Pidgin is released, and may be modified and redistributed, under the terms of the GPL version 2 (or later). A copy of the GPL is distributed with Pidgin. Pidgin is copyrighted by its contributors, a list of whom is also distributed with Pidgin. There is no warranty for Pidgin.</p>
    +
    +<h3>Helpful Resources</h3>
    +
    +<ul>
    +<li><a href="https://pidgin.im">Website</a></li>
    +<li><a href="https://developer.pidgin.im/wiki/FAQ">Frequently Asked Questions</a></li>
    +<li>IRC Channel: #pidgin on irc.freenode.net</li>
    +<li>XMPP MUC: devel@conference.pidgin.im</li>
    +</ul>
    +
    +<p><strong>Help for Oracle Employees</strong> is available from your normal internal helpdesk or IT department. The Pidgin developer and user communities cannot assist you in the configuration or use of Pidgin within Oracle, as we know nothing of Oracle's infrastructure.</p>
    +
    +<p><strong>Help from other Pidgin users</strong> is available by e-mailing <a href="mailto:support@pidgin.im">support@pidgin.im</a>.</p>
    +
    +<p>This is a <strong>public</strong> mailing list with a <strong>public</strong> <a href="https://pidgin.im/pipermail/support/">archive</a>.</p>
    +
    +<p>We can't help with third-party protocols or plugins, but you may be able to find support via the <a href="https://developer.pidgin.im/wiki/ThirdPartyPlugins">ThirdPartyPlugins WIKI Page</a>.</p>
    +
    +<p>The list's primary language is English. You are welcome to post in another language, but the responses may be less helpful.</p>
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/about.md Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,20 @@
    +## Pidgin
    +
    +Pidgin is a messaging client based on libpurple which is capable of connecting to multiple messaging services at once. Pidgin is written in C using GTK+. Pidgin is released, and may be modified and redistributed, under the terms of the GPL version 2 (or later). A copy of the GPL is distributed with Pidgin. Pidgin is copyrighted by its contributors, a list of whom is also distributed with Pidgin. There is no warranty for Pidgin.
    +
    +### Helpful Resources
    +
    + * [Website](https://pidgin.im)
    + * [Frequently Asked Questions](https://developer.pidgin.im/wiki/FAQ)
    + * IRC Channel: #pidgin on irc.freenode.net
    + * XMPP MUC: devel@conference.pidgin.im
    +
    +**Help for Oracle Employees** is available from your normal internal helpdesk or IT department. The Pidgin developer and user communities cannot assist you in the configuration or use of Pidgin within Oracle, as we know nothing of Oracle's infrastructure.
    +
    +**Help from other Pidgin users** is available by e-mailing [support@pidgin.im](mailto:support@pidgin.im).
    +
    +This is a **public** mailing list with a **public** [archive](https://pidgin.im/pipermail/support/).
    +
    +We can't help with third-party protocols or plugins, but you may be able to find support via the [ThirdPartyPlugins WIKI Page](https://developer.pidgin.im/wiki/ThirdPartyPlugins).
    +
    +The list's primary language is English. You are welcome to post in another language, but the responses may be less helpful.
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/about.ui Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,279 @@
    +<?xml version="1.0" encoding="UTF-8"?>
    +<!-- Generated with glade 3.20.0 -->
    +<interface>
    + <requires lib="gtk+" version="3.10"/>
    + <object class="GtkTreeStore" id="build_info_store">
    + <columns>
    + <!-- column-name title -->
    + <column type="gchararray"/>
    + <!-- column-name value -->
    + <column type="gchararray"/>
    + </columns>
    + </object>
    + <object class="GtkTreeStore" id="developers_store">
    + <columns>
    + <!-- column-name markup -->
    + <column type="gchararray"/>
    + <!-- column-name align -->
    + <column type="gfloat"/>
    + </columns>
    + </object>
    + <object class="GtkTreeStore" id="translators_store">
    + <columns>
    + <!-- column-name markup -->
    + <column type="gchararray"/>
    + <!-- column-name align -->
    + <column type="gfloat"/>
    + </columns>
    + </object>
    + <template class="PidginAboutDialog" parent="GtkDialog">
    + <property name="can_focus">False</property>
    + <property name="border_width">5</property>
    + <property name="resizable">False</property>
    + <property name="window_position">center</property>
    + <property name="type_hint">dialog</property>
    + <child internal-child="vbox">
    + <object class="GtkBox">
    + <property name="can_focus">False</property>
    + <property name="orientation">vertical</property>
    + <property name="spacing">2</property>
    + <child internal-child="action_area">
    + <object class="GtkButtonBox">
    + <property name="can_focus">False</property>
    + <property name="layout_style">spread</property>
    + <child>
    + <object class="GtkStackSwitcher" id="switcher">
    + <property name="visible">True</property>
    + <property name="can_focus">False</property>
    + <property name="stack">stack</property>
    + </object>
    + <packing>
    + <property name="expand">True</property>
    + <property name="fill">True</property>
    + <property name="position">0</property>
    + </packing>
    + </child>
    + <child>
    + <object class="GtkButton" id="close_button">
    + <property name="label" translatable="yes">Close</property>
    + <property name="visible">True</property>
    + <property name="can_focus">True</property>
    + <property name="receives_default">True</property>
    + </object>
    + <packing>
    + <property name="expand">True</property>
    + <property name="fill">True</property>
    + <property name="position">1</property>
    + </packing>
    + </child>
    + </object>
    + <packing>
    + <property name="expand">False</property>
    + <property name="fill">False</property>
    + <property name="position">0</property>
    + </packing>
    + </child>
    + <child>
    + <object class="GtkBox">
    + <property name="visible">True</property>
    + <property name="can_focus">False</property>
    + <property name="border_width">12</property>
    + <property name="orientation">vertical</property>
    + <property name="spacing">5</property>
    + <child>
    + <object class="GtkEventBox" id="event-box">
    + <property name="visible">True</property>
    + <property name="can_focus">False</property>
    + <property name="above_child">True</property>
    + <child>
    + <object class="GtkImage" id="logo">
    + <property name="visible">True</property>
    + <property name="can_focus">False</property>
    + <property name="resource">/im/pidgin/Pidgin/logo.png</property>
    + <property name="icon_size">6</property>
    + </object>
    + </child>
    + </object>
    + <packing>
    + <property name="expand">True</property>
    + <property name="fill">True</property>
    + <property name="position">0</property>
    + </packing>
    + </child>
    + <child>
    + <object class="GtkLabel" id="application_name">
    + <property name="visible">True</property>
    + <property name="can_focus">False</property>
    + <property name="label" translatable="yes">Pidgin</property>
    + <property name="justify">center</property>
    + <property name="selectable">True</property>
    + <attributes>
    + <attribute name="weight" value="bold"/>
    + </attributes>
    + </object>
    + <packing>
    + <property name="expand">False</property>
    + <property name="fill">True</property>
    + <property name="position">1</property>
    + </packing>
    + </child>
    + <child>
    + <object class="GtkStack" id="stack">
    + <property name="width_request">400</property>
    + <property name="height_request">150</property>
    + <property name="visible">True</property>
    + <property name="can_focus">False</property>
    + <property name="margin_bottom">2</property>
    + <property name="transition_type">slide-up</property>
    + <child>
    + <object class="GtkScrolledWindow" id="main_scrolled_window">
    + <property name="visible">True</property>
    + <property name="can_focus">True</property>
    + <property name="hscrollbar_policy">never</property>
    + <property name="shadow_type">in</property>
    + <child>
    + <placeholder/>
    + </child>
    + </object>
    + <packing>
    + <property name="name">main</property>
    + <property name="title" translatable="yes">General</property>
    + </packing>
    + </child>
    + <child>
    + <object class="GtkScrolledWindow" id="developers_page">
    + <property name="visible">True</property>
    + <property name="can_focus">True</property>
    + <property name="hscrollbar_policy">never</property>
    + <property name="shadow_type">in</property>
    + <child>
    + <object class="GtkTreeView" id="developers_treeview">
    + <property name="visible">True</property>
    + <property name="can_focus">True</property>
    + <property name="model">developers_store</property>
    + <property name="headers_visible">False</property>
    + <property name="show_expanders">False</property>
    + <child internal-child="selection">
    + <object class="GtkTreeSelection"/>
    + </child>
    + <child>
    + <object class="GtkTreeViewColumn" id="developers_column">
    + <property name="resizable">True</property>
    + <property name="sizing">autosize</property>
    + <child>
    + <object class="GtkCellRendererText" id="developers_cell_renderer"/>
    + <attributes>
    + <attribute name="xalign">1</attribute>
    + <attribute name="markup">0</attribute>
    + </attributes>
    + </child>
    + </object>
    + </child>
    + </object>
    + </child>
    + </object>
    + <packing>
    + <property name="name">developers</property>
    + <property name="title" translatable="yes">Developers</property>
    + <property name="position">1</property>
    + </packing>
    + </child>
    + <child>
    + <object class="GtkScrolledWindow" id="translators_page">
    + <property name="visible">True</property>
    + <property name="can_focus">True</property>
    + <property name="shadow_type">in</property>
    + <child>
    + <object class="GtkTreeView" id="translators_treeview">
    + <property name="visible">True</property>
    + <property name="can_focus">True</property>
    + <property name="model">translators_store</property>
    + <property name="headers_visible">False</property>
    + <property name="show_expanders">False</property>
    + <child internal-child="selection">
    + <object class="GtkTreeSelection"/>
    + </child>
    + <child>
    + <object class="GtkTreeViewColumn" id="translators_column">
    + <child>
    + <object class="GtkCellRendererText" id="translators_cell_renderer"/>
    + <attributes>
    + <attribute name="xalign">1</attribute>
    + <attribute name="markup">0</attribute>
    + </attributes>
    + </child>
    + </object>
    + </child>
    + </object>
    + </child>
    + </object>
    + <packing>
    + <property name="name">translators</property>
    + <property name="title" translatable="yes">Translators</property>
    + <property name="position">2</property>
    + </packing>
    + </child>
    + <child>
    + <object class="GtkScrolledWindow" id="build_info_page">
    + <property name="visible">True</property>
    + <property name="can_focus">True</property>
    + <property name="hscrollbar_policy">never</property>
    + <property name="shadow_type">in</property>
    + <child>
    + <object class="GtkTreeView" id="build_info_treeview">
    + <property name="visible">True</property>
    + <property name="can_focus">True</property>
    + <property name="model">build_info_store</property>
    + <property name="headers_visible">False</property>
    + <property name="show_expanders">False</property>
    + <child internal-child="selection">
    + <object class="GtkTreeSelection"/>
    + </child>
    + <child>
    + <object class="GtkTreeViewColumn">
    + <child>
    + <object class="GtkCellRendererText"/>
    + <attributes>
    + <attribute name="markup">0</attribute>
    + </attributes>
    + </child>
    + </object>
    + </child>
    + <child>
    + <object class="GtkTreeViewColumn">
    + <child>
    + <object class="GtkCellRendererText"/>
    + <attributes>
    + <attribute name="sensitive">10</attribute>
    + <attribute name="markup">1</attribute>
    + </attributes>
    + </child>
    + </object>
    + </child>
    + </object>
    + </child>
    + </object>
    + <packing>
    + <property name="name">build-info</property>
    + <property name="title" translatable="yes">Build Information</property>
    + <property name="position">3</property>
    + </packing>
    + </child>
    + </object>
    + <packing>
    + <property name="expand">True</property>
    + <property name="fill">True</property>
    + <property name="position">2</property>
    + </packing>
    + </child>
    + </object>
    + <packing>
    + <property name="expand">True</property>
    + <property name="fill">True</property>
    + <property name="position">1</property>
    + </packing>
    + </child>
    + </object>
    + </child>
    + </template>
    +</interface>
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/credits.json Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,736 @@
    +{
    + "developers": [{
    + "title": "Developers",
    + "people": [
    + "Daniel 'datallah' Atallah",
    + "Ethan 'Paco-Paco' Blanton",
    + "Gary 'grim' Kramlich",
    + "Richard 'rlaager' Laager",
    + "Etan 'deryni' Reisner",
    + "Michael 'Maiku' Ruprecht",
    + "Elliott 'QuLogic' Sales de Andrade",
    + "Kevin 'SimGuy' Stange",
    + "Tomasz Wasilczyk",
    +
    + "Paul 'darkrain42' Aurich (Retired)",
    + "John 'rekkanoryo' Bailey (Retired)",
    + "Herman Bloggs (Retired)",
    + "Thomas Butter (Retired)",
    + "Ka-Hing Cheung (Retired)",
    + "Sadrul Habib Chowdhury (Retired)",
    + "Mark 'KingAnt' Doliner (Retired)",
    + "Jim Duchek (Retired)",
    + "Sean Egan (Retired)",
    + "Rob Flynn (Retired)",
    + "Adam Fritzler (Retired)",
    + "Christian 'ChipX86' Hammond (Retired)",
    + "Casey Harkins (Retired)",
    + "Ivan Komarov (Retired)",
    + "Syd Logan (Retired)",
    + "Marcus 'malu' Lundblad (Retired)",
    + "Sulabh 'sulabh_m' Mahajan (Retired)",
    + "Richard 'wabs' Nelson (Retired)",
    + "Christopher 'siege' O'Brien (Retired)",
    + "Bartosz Oler (Retired)",
    + "Tim 'marv' Rigenbach (Retired)",
    + "Luke 'LSchiere' Schierer (Retired)",
    + "Megan 'Cae' Schneider (Retired)",
    + "Evan Schoenberg (Retired)",
    + "Jim Seymour (Retired)",
    + "Mark Spencer (Retired)",
    + "Will 'resiak' Thompson (Retired)",
    + "Stu 'nosnilmot' Tomlinson (Retired)",
    + "Jorge 'Masca' Villaseñor (Retired)",
    + "Nathan 'faceprint' Walp (Retired)",
    + "Eric Warmenhoven (Retired)"
    + ]
    + }, {
    + "title": "Crazy Patch Writers",
    + "people": [
    + "Jakub 'haakon' Adam",
    + "Eion Robb",
    +
    + "Felipe 'shx' Contreras (Retired)",
    + "Decklin Foster (Retired)",
    + "Krzysztof Klinikowski (Retired)",
    + "Peter 'Bleeter' Lawler (Retired)",
    + "Robert 'Robot101' McQueen (Retired)",
    + "Benjamin Miller (Retired)",
    + "Dennis 'EvilDennisR' Ristuccia (Retired)",
    + "Peter 'Fmoo' Ruibal (Retired)",
    + "Gabriel 'Nix' Schulhof (Retired)",
    + "Ankit Vani (Retired)"
    + ]
    + }, {
    + "title": "Artists",
    + "people": [
    + "Hylke Bons"
    + ]
    + }, {
    + "title": "Google Summer of Code 2015",
    + "people": [
    + "Abel Serrano Juste",
    + "Igor Gajowiak",
    + "James Geboski",
    + "Koosha Khajehmoogahi",
    + "Michael McConville",
    + "Nakul Gulati"
    + ]
    + }, {
    + "title": "Google Summer of Code 2013",
    + "people": [
    + "Ashish Gupta",
    + "Bhaskar Kandiyal",
    + "Phil Hannent",
    + "Ankit Vani"
    + ]
    + }, {
    + "title": "Google Summer of Code 2012",
    + "people": [
    + "Michael Zangl",
    + "Nikhil Bafna",
    + "Sanket Agarwal",
    + "Tomasz Wasilczyk"
    + ]
    + }, {
    + "title": "Google Summer of Code 2010",
    + "people": [
    + "Ivan Komarov",
    + "Adam Fowler",
    + "Gilles Bedel",
    + "Jorge Villaseñor Salinas"
    + ]
    + }, {
    + "title": "Google Summer of Code 2009",
    + "people": [
    + "Felix Kerekes",
    + "Wade Fagen",
    + "Sulabh Mahajan",
    + "Eric Polino",
    + "Gregor Dick",
    + "Jan Kaluza",
    + "Arnold Noronha"
    + ]
    + }, {
    + "title": "Google Summer of Code 2008",
    + "people": [
    + "Mark Schneider",
    + "Justin Rodriguez",
    + "Vivien Bernet-Rollande",
    + "Sulabh Mahajan",
    + "Mike Ruprecht",
    + "Tobias Markmann"
    + ]
    + }, {
    + "title": "Google Summer of Code 2007",
    + "people": [
    + "Eion Coffey",
    + "Jeffery Connelly",
    + "Michael Shkutkov",
    + "William Ehlhardt",
    + "Eric Polino",
    + "Prekshu Ajmera",
    + "Carlos Silva",
    + "Will Thompson"
    + ]
    + }, {
    + "title": "Google Summer of Code 2006",
    + "people": [
    + "Sadrul Habib Chowdhury",
    + "Ma Yuan",
    + "Geoffrey Foster",
    + "Brian Chu",
    + "Mark Huetsch",
    + "Aaron Sheldon"
    + ]
    + }, {
    + "title": "Google Summer of Code 2005",
    + "people": [
    + "Adam Warrington",
    + "Bartosz Oler",
    + "Christian Muise",
    + "Jonathan Clark",
    + "Juanjo Molinero Horno",
    + "Piotr Zielinski",
    + "Thomas Butter"
    + ]
    + }],
    + "languages": [{
    + "title": "Afrikaans (af)",
    + "people": [
    + "Samuel Murray",
    + "Friedel Wolff"
    + ]
    + }, {
    + "title": "Amharic (am)",
    + "people": [
    + "Daniel Yacob (Retired)"
    + ]
    + }, {
    + "title": "Arabic (ar)",
    + "people": [
    + "Khaled Hosny",
    + "Mohamed Magdy (Retired)"
    + ]
    + }, {
    + "title": "Assamese (as)",
    + "people": [
    + "Amitakhya Phukan"
    + ]
    + }, {
    + "title": "Asturian (ast)",
    + "people": [
    + "Llumex03"
    + ]
    + }, {
    + "title": "Belarusian Latin (be@latin)",
    + "people": [
    + "Ihar Hrachyshka"
    + ]
    + }, {
    + "title": "Bulgarian (bg)",
    + "people": [
    + "Vladimira Girginova",
    + "Vladimir (Kaladan) Petkov",
    + "Hristo Todorov (Retired)"
    + ]
    + }, {
    + "title": "Bengali (bn)",
    + "people": [
    + "Jamil Ahmed",
    + "Israt Jahan",
    + "Samia Nimatullah",
    + "Indranil Das Gupta (Retired)",
    + "Tisa Nafisa (Retired)"
    + ]
    + }, {
    + "title": "Bengali-India (bn_IN)",
    + "people": [
    + "Runa Bhattacharjee"
    + ]
    + }, {
    + "title": "Breton (br)",
    + "people": [
    + "Gwenn Meynier"
    + ]
    + }, {
    + "title": "Bodo (brx)",
    + "people": [
    + "Chandrakant Dhutadmal"
    + ]
    + }, {
    + "title": "Bosnian (bs)",
    + "people": [
    + "Lejla Hadzialic"
    + ]
    + }, {
    + "title": "Catalan (ca)",
    + "people": [
    + "Josep Puigdemont",
    + "JM Pérez Cáncer (Retired)",
    + "Robert Millan (Retired)"
    + ]
    + }, {
    + "title": "Valencian-Catalan (ca@valencia)",
    + "people": [
    + "Toni Hermoso",
    + "Josep Puigdemont"
    + ]
    + }, {
    + "title": "Czech (cs)",
    + "people": [
    + "David Vachulka",
    + "Honza Král (Retired)",
    + "Miloslav Trmac (Retired)"
    + ]
    + }, {
    + "title": "Danish (da)",
    + "people": [
    + "Nicky Thomassen",
    + "Peter Bach (Retired)",
    + "Morten Brix Pedersen (Retired)"
    + ]
    + }, {
    + "title": "German (de)",
    + "people": [
    + "Björn Voigt",
    + "Daniel Seifert (Retired)",
    + "Karsten Weiss (Retired)",
    + "Jochen Kemnade (Retired)"
    + ]
    + }, {
    + "title": "Dzongkha (dz)",
    + "people": [
    + "Norbu",
    + "Jurmey Rabgay",
    + "Wangmo Sherpa"
    + ]
    + }, {
    + "title": "Greek (el)",
    + "people": [
    + "Katsaloulis Panayotis",
    + "Panos Bouklis"
    + ]
    + }, {
    + "title": "Australian English (en_AU)",
    + "people": [
    + "Michael Findlay",
    + "Peter Lawler (Retired)"
    + ]
    + }, {
    + "title": "British English (en_GB)",
    + "people": [
    + "Phil Hannent",
    + "Luke Ross (Retired)"
    + ]
    + }, {
    + "title": "Canadian English (en_CA)",
    + "people": [
    + "Adam Weinberger"
    + ]
    + }, {
    + "title": "Esperanto (eo)",
    + "people": [
    + "Stéphane Fillod"
    + ]
    + }, {
    + "title": "Spanish (es)",
    + "people": [
    + "Javier Fernández-Sanguino Peña",
    + "JM Pérez Cáncer (Retired)",
    + "Nicolás Lichtmaier (Retired)",
    + "Amaya Rodrigo (Retired)",
    + "Alejandro G Villar (Retired)"
    + ]
    + }, {
    + "title": "Argentine Spanish (es_AR)",
    + "people": [
    + "KNTRO"
    + ]
    + }, {
    + "title": "Estonian (et)",
    + "people": [
    + "Ivar Smolin"
    + ]
    + }, {
    + "title": "Basque (eu)",
    + "people": [
    + "Mikel Pascual Aldabaldetreku",
    + "Iñaki Larrañaga Murgoitio (Retired)",
    + "Hizkuntza Politikarako Sailburuordetza (Retired)"
    + ]
    + }, {
    + "title": "Persian (fa)",
    + "people": [
    + "Elnaz Sarbar",
    + "Roozbeh Pournader",
    + "Meelad Zakaria"
    + ]
    + }, {
    + "title": "Finnish (fi)",
    + "people": [
    + "Timo Jyrinki",
    + "Arto Alakulju (Retired)",
    + "Tero Kuusela (Retired)"
    + ]
    + }, {
    + "title": "French (fr)",
    + "people": [
    + "Sébastien François (Retired)",
    + "Loïc Jeannin (Retired)",
    + "Stéphane Pontier (Retired)",
    + "Stéphane Wirtel (Retired)",
    + "Éric Boumaour (Retired)"
    + ]
    + }, {
    + "title": "Irish (ga)",
    + "people": [
    + "Aaron Kearns",
    + "Kevin Scannell"
    + ]
    + }, {
    + "title": "Galician (gl)",
    + "people": [
    + "Mar Castro",
    + "Frco. Javier Rial",
    + "Ignacio Casal Quinteiro (Retired)"
    + ]
    + }, {
    + "title": "Gujarati (gu)",
    + "people": [
    + "Ankit Patel",
    + "Gujarati Language Team"
    + ]
    + }, {
    + "title": "Hebrew (he)",
    + "people": [
    + "Shalom Craimer",
    + "Pavel Bibergal (Retired)"
    + ]
    + }, {
    + "title": "Hindi (hi)",
    + "people": [
    + "Sangeeta Kumari",
    + "Rajesh Ranjan",
    + "Ravishankar Shrivastava (Retired)"
    + ]
    + }, {
    + "title": "Croatian (hr)",
    + "people": [
    + "Sabina Drempetić"
    + ]
    + }, {
    + "title": "Hungarian (hu)",
    + "people": [
    + "Kelemen Gábor",
    + "Zoltan Sutto (Retired)"
    + ]
    + }, {
    + "title": "Armenian (hy)",
    + "people": [
    + "David Avsharyan (Retired)"
    + ]
    + }, {
    + "title": "Indonesian (id)",
    + "people": [
    + "Rai S. Regawa"
    + ]
    + }, {
    + "title": "Italian (it)",
    + "people": [
    + "Claudio Satriano",
    + "Salvatore di Maggio (Retired)"
    + ]
    + }, {
    + "title": "Japanese (ja)",
    + "people": [
    + "Takayuki Kusano",
    + "Takashi Aihana (Retired)",
    + "Ryosuke Kutsuna (Retired)",
    + "Junichi Uekawa (Retired)",
    + "Taku Yasui (Retired)"
    + ]
    + }, {
    + "title": "Georgian (ka)",
    + "people": [
    + "Ubuntu Georgian Translators",
    + "Temuri Doghonadze (Retired)"
    + ]
    + }, {
    + "title": "Kazakh (kk)",
    + "people": [
    + "Baurzhan Muftakhidinov"
    + ]
    + }, {
    + "title": "Khmer (km)",
    + "people": [
    + "Khoem Sokhem"
    + ]
    + }, {
    + "title": "Kannada (kn)",
    + "people": [
    + "Kannada Translation team"
    + ]
    + }, {
    + "title": "Korean (ko)",
    + "people": [
    + "Sushizang",
    + "Sang-hyun S (Retired)",
    + "A Ho-seok Lee (Retired)",
    + "Kyeong-uk Son (Retired)"
    + ]
    + }, {
    + "title": "Kashmiri (kas)",
    + "people": [
    + "Chandrakant Dhutadmal"
    + ]
    + }, {
    + "title": "Kurdish (ku)",
    + "people": [
    + "Amed Ç. Jiyan",
    + "Erdal Ronahi",
    + "Rizoyê Xerzî"
    + ]
    + }, {
    + "title": "Kurdish (Sorani) (ku_IQ)",
    + "people": [
    + "Haval A. Ahmed"
    + ]
    + }, {
    + "title": "Laotian (lo)",
    + "people": [
    + "Anousak Souphavah (Retired)"
    + ]
    + }, {
    + "title": "Lithuanian (lt)",
    + "people": [
    + "Algimantas Margevičius",
    + "Laurynas Biveinis (Retired)",
    + "Gediminas Čičinskas (Retired)",
    + "Andrius Štikonas (Retired)"
    + ]
    + }, {
    + "title": "Latvian (lv)",
    + "people": [
    + "Rudolfs Mazurs",
    + "Ingmārs Dīriņš"
    + ]
    + }, {
    + "title": "Maithili (mai)",
    + "people": [
    + "Sangeeta Kumari",
    + "Rajesh Ranjan"
    + ]
    + }, {
    + "title": "Meadow Mari (mhr)",
    + "people": [
    + "David Preece"
    + ]
    + }, {
    + "title": "Macedonian (mk)",
    + "people": [
    + "Arangel Angov",
    + "Ivana Kirkovska",
    + "Jovan Naumovski",
    + "Tomislav Markovski (Retired)"
    + ]
    + }, {
    + "title": "Malayalam (ml)",
    + "people": [
    + "Ani Peter"
    + ]
    + }, {
    + "title": "Mongolian (mn)",
    + "people": [
    + "gooyo"
    + ]
    + }, {
    + "title": "Marathi (mr)",
    + "people": [
    + "Sandeep Shedmake"
    + ]
    + }, {
    + "title": "Malay (ms_MY)",
    + "people": [
    + "abuyop",
    + "Muhammad Najmi bin Ahmad Zabidi (Retired)"
    + ]
    + }, {
    + "title": "Burmese (my_MM)",
    + "people": [
    + "Thura Hlaing"
    + ]
    + }, {
    + "title": "Bokmål Norwegian (nb)",
    + "people": [
    + "Allan Nordhøy",
    + "Hans Fredrik Nordhaug (Retired)",
    + "Hallvard Glad (Retired)",
    + "Petter Johan Olsen (Retired)",
    + "Espen Stefansen (Retired)"
    + ]
    + }, {
    + "title": "Nepali (ne)",
    + "people": [
    + "Saroj Dhakal",
    + "Shyam Krishna Bal (Retired)"
    + ]
    + }, {
    + "title": "Dutch, Flemish (nl)",
    + "people": [
    + "Gideon van Melle",
    + "Vincent van Adrighem (Retired)"
    + ]
    + }, {
    + "title": "Norwegian Nynorsk (nn)",
    + "people": [
    + "Yngve Spjeld Landro"
    + ]
    + }, {
    + "title": "Occitan (oc)",
    + "people": [
    + "Cédric Valmary",
    + "Yannig Marchegay (Retired)"
    + ]
    + }, {
    + "title": "Oriya (or)",
    + "people": [
    + "Manoj Kumar Giri"
    + ]
    + }, {
    + "title": "Punjabi (pa)",
    + "people": [
    + "Amanpreet Singh Alam"
    + ]
    + }, {
    + "title": "Polish (pl)",
    + "people": [
    + "Piotr Drąg",
    + "Krzysztof Foltman (Retired)",
    + "Paweł Godlewski (Retired)",
    + "Piotr Makowski (Retired)",
    + "Emil Nowak (Retired)",
    + "Przemysław Sułek (Retired)"
    + ]
    + }, {
    + "title": "Portuguese (pt)",
    + "people": [
    + "Paulo Ribeiro",
    + "Duarte Henriques (Retired)"
    + ]
    + }, {
    + "title": "Portuguese-Brazil (pt_BR)",
    + "people": [
    + "Renato Silva",
    + "Maurício de Lemos Rodrigues Collares Neto (Retired)",
    + "Rodrigo Luiz Marques Flores (Retired)"
    + ]
    + }, {
    + "title": "Pashto (ps)",
    + "people": [
    + "Kashif Masood"
    + ]
    + }, {
    + "title": "Romanian (ro)",
    + "people": [
    + "Mișu Moldovan",
    + "Andrei Popescu"
    + ]
    + }, {
    + "title": "Russian (ru)",
    + "people": [
    + "Антон Самохвалов",
    + "Dmitry Beloglazov (Retired)",
    + "Alexandre Prokoudine (Retired)",
    + "Sergey Volozhanin (Retired)"
    + ]
    + }, {
    + "title": "Sindhi (sd)",
    + "people": [
    + "Chandrakant Dhutadmal"
    + ]
    + }, {
    + "title": "Slovak (sk)",
    + "people": [
    + "Jozef Káčer",
    + "loptosko",
    + "Daniel Režný (Retired)",
    + "Richard Golier (Retired)",
    + "helix84 (Retired)"
    + ]
    + }, {
    + "title": "Slovenian (sl)",
    + "people": [
    + "Martin Srebotnjak",
    + "Matjaz Horvat (Retired)"
    + ]
    + }, {
    + "title": "Albanian (sq)",
    + "people": [
    + "Besnik Bleta"
    + ]
    + }, {
    + "title": "Serbian (sr)",
    + "people": [
    + "Miloš Popović",
    + "Danilo Šegan (Retired)",
    + "Aleksandar Urosevic (Retired)"
    + ]
    + }, {
    + "title": "Serbian Latin (sr@latin)",
    + "people": [
    + "Miloš Popović"
    + ]
    + }, {
    + "title": "Sinhala (si)",
    + "people": [
    + "Yajith Ajantha Dayarathna",
    + "Danishka Navin"
    + ]
    + }, {
    + "title": "Swedish (sv)",
    + "people": [
    + "Josef Andersson",
    + "Peter Hjalmarsson (Retired)",
    + "Tore Lundqvist (Retired)",
    + "Christian Rose (Retired)"
    + ]
    + }, {
    + "title": "Swahili (sw)",
    + "people": [
    + "Paul Msegeya"
    + ]
    + }, {
    + "title": "Tamil (ta)",
    + "people": [
    + "I. Felix",
    + "Viveka Nathan K"
    + ]
    + }, {
    + "title": "Telugu (te)",
    + "people": [
    + "Krishnababu Krottapalli",
    + "Mr. Subbaramaih (Retired)"
    + ]
    + }, {
    + "title": "Thai (th)",
    + "people": [
    + "Isriya Paireepairit"
    + ]
    + }, {
    + "title": "Turkish (tr)",
    + "people": [
    + "Serdar Soytetir (Retired)",
    + "Ahmet Alp Balkan (Retired)"
    + ]
    + }, {
    + "title": "Tatar (tt)",
    + "people": [
    + "ILDAR Valeev"
    + ]
    + }, {
    + "title": "Ukranian (uk)",
    + "people": [
    + "Oleksandr Kovalenko"
    + ]
    + }, {
    + "title": "Urdu (ur)",
    + "people": [
    + "RKVS Raman"
    + ]
    + }, {
    + "title": "Uzbek (uz)",
    + "people": [
    + "Akmal Khushvakov"
    + ]
    + }, {
    + "title": "Vietnamese (vi)",
    + "people": [
    + "Nguyễn Vũ Hưng",
    + "T.M.Thanh and the Gnome-Vi Team (Retired)"
    + ]
    + }, {
    + "title": "Simplified Chinese (zh_CN)",
    + "people": [
    + "Aron Xu",
    + "Hashao (Retired)",
    + "Rocky S. Lee (Retired)",
    + "Funda Wang (Retired)"
    + ]
    + }, {
    + "title": "Hong Kong Chinese (zh_HK)",
    + "people": [
    + "Abel Cheung",
    + "Ambrose C. Li",
    + "Paladin R. Liu"
    + ]
    + }, {
    + "title": "Traditional Chinese (zh_TW)",
    + "people": [
    + "Ambrose C. Li",
    + "Paladin R. Liu",
    + "Hashao (Retired)",
    + "Rocky S. Lee (Retired)"
    + ]
    + }]
    +}
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/data/im.pidgin.Pidgin.appdata.xml.in Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,39 @@
    +<?xml version="1.0" encoding="UTF-8"?>
    +<!-- Copyright 2014 Richard Hughes <richard@hughsie.com> -->
    +<!-- Copyright 2014-2017 Pidgin Developers <devel@pidgin.im> -->
    +
    +<component type="desktop-application">
    + <id>im.pidgin.Pidgin.desktop</id>
    + <metadata_license>CC0-1.0</metadata_license>
    + <project_license>GPL-2.0</project_license>
    + <description>
    + <_p>
    + Pidgin is a chat program which lets you log in to accounts on multiple
    + chat networks simultaneously.
    + </_p>
    + <_p>
    + This means that you can be chatting with friends on AIM, talking to a
    + friend on Google Talk, and sitting in an IRC chat room all at the same
    + time.
    + </_p>
    + </description>
    +
    + <launchable type="desktop-id">im.pidgin.Pidgin.desktop</launchable>
    + <provides>
    + <id>pidgin.desktop</id>
    + </provides>
    +
    + <screenshots>
    + <screenshot type="default">
    + <image>https://www.pidgin.im/shared/img/contact_window.png</image>
    + <_caption>Buddy list showing friends on different networks</_caption>
    + </screenshot>
    + </screenshots>
    +
    + <url type="homepage">https://pidgin.im/</url>
    + <url type="bugtracker">https://developer.pidgin.im/timeline</url>
    + <url type="faq">https://developer.pidgin.im/wiki/FAQ</url>
    + <url type="help">https://developer.pidgin.im/wiki</url>
    +
    + <update_contact>devel@pidgin.im</update_contact>
    +</component>
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/data/im.pidgin.Pidgin.desktop.in.in Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,11 @@
    +[Desktop Entry]
    +_Name=Pidgin
    +_GenericName=Internet Messenger
    +_Comment=Chat over IM. Supports AIM, Google Talk, Jabber/XMPP, and more
    +Exec=pidgin
    +Icon=pidgin
    +StartupNotify=true
    +Terminal=false
    +Type=Application
    +Categories=Network;InstantMessaging;
    +@USES_MM_CHAT_SECTION@
    --- a/pidgin/data/pidgin.appdata.xml.in Fri Jul 07 11:50:28 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,29 +0,0 @@
    -<?xml version="1.0" encoding="UTF-8"?>
    -<!-- Copyright 2014 Richard Hughes <richard@hughsie.com> -->
    -<!-- Copyright 2014 Pidgin Developers <devel@pidgin.im> -->
    -
    -<application>
    - <id type="desktop">pidgin.desktop</id>
    - <metadata_license>CC0-1.0</metadata_license>
    - <project_license>GPL-2.0</project_license>
    - <_summary>Instant Messaging Client</_summary>
    - <description>
    - <_p>
    - Pidgin is a chat program which lets you log in to accounts on multiple
    - chat networks simultaneously.
    - </_p>
    - <_p>
    - This means that you can be chatting with friends on AIM, talking to a
    - friend on Google Talk, and sitting in an IRC chat room all at the same
    - time.
    - </_p>
    - </description>
    - <url type="homepage">http://www.pidgin.im/</url>
    - <screenshots>
    - <screenshot type="default">
    - <image>http://www.pidgin.im/shared/img/contact_window.png</image>
    - <_caption>The buddy list showing friends on different networks.</_caption>
    - </screenshot>
    - </screenshots>
    - <updatecontact>devel@pidgin.im</updatecontact>
    -</application>
    --- a/pidgin/data/pidgin.desktop.in.in Fri Jul 07 11:50:28 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,11 +0,0 @@
    -[Desktop Entry]
    -_Name=Pidgin Internet Messenger
    -_GenericName=Internet Messenger
    -_Comment=Chat over IM. Supports AIM, Google Talk, Jabber/XMPP, and more
    -Exec=pidgin
    -Icon=pidgin
    -StartupNotify=true
    -Terminal=false
    -Type=Application
    -Categories=Network;InstantMessaging;
    -@USES_MM_CHAT_SECTION@
    --- a/pidgin/getopt.c Fri Jul 07 11:50:28 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,735 +0,0 @@
    -/* Getopt for GNU.
    - NOTE: getopt is now part of the C library, so if you don't know what
    - "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
    - before changing it!
    -
    - 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, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
    -
    -/* NOTE!!! AIX requires this to be the first thing in the file.
    - Do not put ANYTHING before it! */
    -#if !defined (__GNUC__) && defined (_AIX)
    - #pragma alloca
    -#endif
    -
    -#ifdef HAVE_CONFIG_H
    -#include "config.h"
    -#endif
    -
    -/* Alver says we need this for IRIX. */
    -#include "string.h"
    -
    -#ifdef __GNUC__
    -#define alloca __builtin_alloca
    -#else /* not __GNUC__ */
    -#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
    -#include <alloca.h>
    -#else
    -#ifndef _AIX
    -char *alloca ();
    -#endif
    -#endif /* alloca.h */
    -#endif /* not __GNUC__ */
    -
    -#if !__STDC__ && !defined(const) && IN_GCC
    -#define const
    -#endif
    -
    -/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */
    -#ifndef _NO_PROTO
    -#define _NO_PROTO
    -#endif
    -
    -#include <stdio.h>
    -
    -/* Comment out all this code if we are using the GNU C Library, and are not
    - actually compiling the library itself. This code is part of the GNU C
    - Library, but also included in many other GNU distributions. Compiling
    - and linking in this code is a waste when using the GNU C library
    - (especially if it is a shared library). Rather than having every GNU
    - program understand `configure --with-gnu-libc' and omit the object files,
    - it is simpler to just do this in the source for each such file. */
    -
    -#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
    -
    -
    -/* This needs to come after some library #include
    - to get __GNU_LIBRARY__ defined. */
    -#ifdef __GNU_LIBRARY__
    -#undef alloca
    -/* Don't include stdlib.h for non-GNU C libraries because some of them
    - contain conflicting prototypes for getopt. */
    -#include <stdlib.h>
    -#else /* Not GNU C library. */
    -#define __alloca alloca
    -#endif /* GNU C library. */
    -
    -/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
    - long-named option. Because this is not POSIX.2 compliant, it is
    - being phased out. */
    -/* #define GETOPT_COMPAT */
    -
    -/* This version of `getopt' appears to the caller like standard Unix `getopt'
    - but it behaves differently for the user, since it allows the user
    - to intersperse the options with the other arguments.
    -
    - As `getopt' works, it permutes the elements of ARGV so that,
    - when it is done, all the options precede everything else. Thus
    - all application programs are extended to handle flexible argument order.
    -
    - Setting the environment variable POSIXLY_CORRECT disables permutation.
    - Then the behavior is completely standard.
    -
    - GNU application programs can use a third alternative mode in which
    - they can distinguish the relative order of options and other arguments. */
    -
    -#include "getopt.h"
    -
    -/* For communication from `getopt' to the caller.
    - When `getopt' finds an option that takes an argument,
    - the argument value is returned here.
    - Also, when `ordering' is RETURN_IN_ORDER,
    - each non-option ARGV-element is returned here. */
    -
    -char *optarg = NULL;
    -
    -/* Index in ARGV of the next element to be scanned.
    - This is used for communication to and from the caller
    - and for communication between successive calls to `getopt'.
    -
    - On entry to `getopt', zero means this is the first call; initialize.
    -
    - When `getopt' returns EOF, this is the index of the first of the
    - non-option elements that the caller should itself scan.
    -
    - Otherwise, `optind' communicates from one call to the next
    - how much of ARGV has been scanned so far. */
    -
    -/* XXX 1003.2 says this must be 1 before any call. */
    -int optind = 0;
    -
    -/* The next char to be scanned in the option-element
    - in which the last option character we returned was found.
    - This allows us to pick up the scan where we left off.
    -
    - If this is zero, or a null string, it means resume the scan
    - by advancing to the next ARGV-element. */
    -
    -static char *nextchar;
    -
    -/* Callers store zero here to inhibit the error message
    - for unrecognized options. */
    -
    -int opterr = 1;
    -
    -/* Set to an option character which was unrecognized.
    - This must be initialized on some systems to avoid linking in the
    - system's own getopt implementation. */
    -
    -int optopt = '?';
    -
    -/* Describe how to deal with options that follow non-option ARGV-elements.
    -
    - If the caller did not specify anything,
    - the default is REQUIRE_ORDER if the environment variable
    - POSIXLY_CORRECT is defined, PERMUTE otherwise.
    -
    - REQUIRE_ORDER means don't recognize them as options;
    - stop option processing when the first non-option is seen.
    - This is what Unix does.
    - This mode of operation is selected by either setting the environment
    - variable POSIXLY_CORRECT, or using `+' as the first character
    - of the list of option characters.
    -
    - PERMUTE is the default. We permute the contents of ARGV as we scan,
    - so that eventually all the non-options are at the end. This allows options
    - to be given in any order, even with programs that were not written to
    - expect this.
    -
    - RETURN_IN_ORDER is an option available to programs that were written
    - to expect options and other ARGV-elements in any order and that care about
    - the ordering of the two. We describe each non-option ARGV-element
    - as if it were the argument of an option with character code 1.
    - Using `-' as the first character of the list of option characters
    - selects this mode of operation.
    -
    - The special argument `--' forces an end of option-scanning regardless
    - of the value of `ordering'. In the case of RETURN_IN_ORDER, only
    - `--' can cause `getopt' to return EOF with `optind' != ARGC. */
    -
    -static enum
    -{
    - REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
    -} ordering;
    -
    -#ifdef __GNU_LIBRARY__
    -/* We want to avoid inclusion of string.h with non-GNU libraries
    - because there are many ways it can cause trouble.
    - On some systems, it contains special magic macros that don't work
    - in GCC. */
    -#include <string.h>
    -#define my_index strchr
    -#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n))
    -#else
    -
    -/* Avoid depending on library functions or files
    - whose names are inconsistent. */
    -
    -char *getenv ();
    -
    -static char *
    -my_index (str, chr)
    - const char *str;
    - int chr;
    -{
    - while (*str)
    - {
    - if (*str == chr)
    - return (char *) str;
    - str++;
    - }
    - return 0;
    -}
    -
    -static void
    -my_bcopy (from, to, size)
    - const char *from;
    - char *to;
    - int size;
    -{
    - int i;
    - for (i = 0; i < size; i++)
    - to[i] = from[i];
    -}
    -#endif /* GNU C library. */
    -
    -/* Handle permutation of arguments. */
    -
    -/* Describe the part of ARGV that contains non-options that have
    - been skipped. `first_nonopt' is the index in ARGV of the first of them;
    - `last_nonopt' is the index after the last of them. */
    -
    -static int first_nonopt;
    -static int last_nonopt;
    -
    -/* Exchange two adjacent subsequences of ARGV.
    - One subsequence is elements [first_nonopt,last_nonopt)
    - which contains all the non-options that have been skipped so far.
    - The other is elements [last_nonopt,optind), which contains all
    - the options processed since those non-options were skipped.
    -
    - `first_nonopt' and `last_nonopt' are relocated so that they describe
    - the new indices of the non-options in ARGV after they are moved. */
    -
    -static void
    -exchange (argv)
    - char **argv;
    -{
    - int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
    - char **temp = (char **) __alloca (nonopts_size);
    -
    - /* Interchange the two blocks of data in ARGV. */
    -
    - my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
    - my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
    - (optind - last_nonopt) * sizeof (char *));
    - my_bcopy ((char *) temp,
    - (char *) &argv[first_nonopt + optind - last_nonopt],
    - nonopts_size);
    -
    - /* Update records for the slots the non-options now occupy. */
    -
    - first_nonopt += (optind - last_nonopt);
    - last_nonopt = optind;
    -}
    -
    -/* Scan elements of ARGV (whose length is ARGC) for option characters
    - given in OPTSTRING.
    -
    - If an element of ARGV starts with '-', and is not exactly "-" or "--",
    - then it is an option element. The characters of this element
    - (aside from the initial '-') are option characters. If `getopt'
    - is called repeatedly, it returns successively each of the option characters
    - from each of the option elements.
    -
    - If `getopt' finds another option character, it returns that character,
    - updating `optind' and `nextchar' so that the next call to `getopt' can
    - resume the scan with the following option character or ARGV-element.
    -
    - If there are no more option characters, `getopt' returns `EOF'.
    - Then `optind' is the index in ARGV of the first ARGV-element
    - that is not an option. (The ARGV-elements have been permuted
    - so that those that are not options now come last.)
    -
    - OPTSTRING is a string containing the legitimate option characters.
    - If an option character is seen that is not listed in OPTSTRING,
    - return '?' after printing an error message. If you set `opterr' to
    - zero, the error message is suppressed but we still return '?'.
    -
    - If a char in OPTSTRING is followed by a colon, that means it wants an arg,
    - so the following text in the same ARGV-element, or the text of the following
    - ARGV-element, is returned in `optarg'. Two colons mean an option that
    - wants an optional arg; if there is text in the current ARGV-element,
    - it is returned in `optarg', otherwise `optarg' is set to zero.
    -
    - If OPTSTRING starts with `-' or `+', it requests different methods of
    - handling the non-option ARGV-elements.
    - See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
    -
    - Long-named options begin with `--' instead of `-'.
    - Their names may be abbreviated as long as the abbreviation is unique
    - or is an exact match for some defined option. If they have an
    - argument, it follows the option name in the same ARGV-element, separated
    - from the option name by a `=', or else the in next ARGV-element.
    - When `getopt' finds a long-named option, it returns 0 if that option's
    - `flag' field is nonzero, the value of the option's `val' field
    - if the `flag' field is zero.
    -
    - The elements of ARGV aren't really const, because we permute them.
    - But we pretend they're const in the prototype to be compatible
    - with other systems.
    -
    - LONGOPTS is a vector of `struct option' terminated by an
    - element containing a name which is zero.
    -
    - LONGIND returns the index in LONGOPT of the long-named option found.
    - It is only valid when a long-named option has been found by the most
    - recent call.
    -
    - If LONG_ONLY is nonzero, '-' as well as '--' can introduce
    - long-named options. */
    -
    -int
    -_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
    - int argc;
    - char *const *argv;
    - const char *optstring;
    - const struct option *longopts;
    - int *longind;
    - int long_only;
    -{
    - int option_index;
    -
    - optarg = NULL;
    -
    - /* Initialize the internal data when the first call is made.
    - Start processing options with ARGV-element 1 (since ARGV-element 0
    - is the program name); the sequence of previously skipped
    - non-option ARGV-elements is empty. */
    -
    - if (optind == 0)
    - {
    - first_nonopt = last_nonopt = optind = 1;
    -
    - nextchar = NULL;
    -
    - /* Determine how to handle the ordering of options and nonoptions. */
    -
    - if (optstring[0] == '-')
    - {
    - ordering = RETURN_IN_ORDER;
    - ++optstring;
    - }
    - else if (optstring[0] == '+')
    - {
    - ordering = REQUIRE_ORDER;
    - ++optstring;
    - }
    - else if (getenv ("POSIXLY_CORRECT") != NULL)
    - ordering = REQUIRE_ORDER;
    - else
    - ordering = PERMUTE;
    - }
    -
    - if (nextchar == NULL || *nextchar == '\0')
    - {
    - if (ordering == PERMUTE)
    - {
    - /* If we have just processed some options following some non-options,
    - exchange them so that the options come first. */
    -
    - if (first_nonopt != last_nonopt && last_nonopt != optind)
    - exchange ((char **) argv);
    - else if (last_nonopt != optind)
    - first_nonopt = optind;
    -
    - /* Now skip any additional non-options
    - and extend the range of non-options previously skipped. */
    -
    - while (optind < argc
    - && (argv[optind][0] != '-' || argv[optind][1] == '\0')
    -#ifdef GETOPT_COMPAT
    - && (longopts == NULL
    - || argv[optind][0] != '+' || argv[optind][1] == '\0')
    -#endif /* GETOPT_COMPAT */
    - )
    - optind++;
    - last_nonopt = optind;
    - }
    -
    - /* Special ARGV-element `--' means premature end of options.
    - Skip it like a null option,
    - then exchange with previous non-options as if it were an option,
    - then skip everything else like a non-option. */
    -
    - if (optind != argc && !strcmp (argv[optind], "--"))
    - {
    - optind++;
    -
    - if (first_nonopt != last_nonopt && last_nonopt != optind)
    - exchange ((char **) argv);
    - else if (first_nonopt == last_nonopt)
    - first_nonopt = optind;
    - last_nonopt = argc;
    -
    - optind = argc;
    - }
    -
    - /* If we have done all the ARGV-elements, stop the scan
    - and back over any non-options that we skipped and permuted. */
    -
    - if (optind == argc)
    - {
    - /* Set the next-arg-index to point at the non-options
    - that we previously skipped, so the caller will digest them. */
    - if (first_nonopt != last_nonopt)
    - optind = first_nonopt;
    - return EOF;
    - }
    -
    - /* If we have come to a non-option and did not permute it,
    - either stop the scan or describe it to the caller and pass it by. */
    -
    - if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
    -#ifdef GETOPT_COMPAT
    - && (longopts == NULL
    - || argv[optind][0] != '+' || argv[optind][1] == '\0')
    -#endif /* GETOPT_COMPAT */
    - )
    - {
    - if (ordering == REQUIRE_ORDER)
    - return EOF;
    - optarg = argv[optind++];
    - return 1;
    - }
    -
    - /* We have found another option-ARGV-element.
    - Start decoding its characters. */
    -
    - nextchar = (argv[optind] + 1
    - + (longopts != NULL && argv[optind][1] == '-'));
    - }
    -
    - if (longopts != NULL
    - && ((argv[optind][0] == '-'
    - && (argv[optind][1] == '-' || long_only))
    -#ifdef GETOPT_COMPAT
    - || argv[optind][0] == '+'
    -#endif /* GETOPT_COMPAT */
    - ))
    - {
    - const struct option *p;
    - char *s = nextchar;
    - int exact = 0;
    - int ambig = 0;
    - const struct option *pfound = NULL;
    - int indfound;
    -
    - while (*s && *s != '=')
    - s++;
    -
    - /* Test all options for either exact match or abbreviated matches. */
    - for (p = longopts, option_index = 0; p->name;
    - p++, option_index++)
    - if (!strncmp (p->name, nextchar, s - nextchar))
    - {
    - if (s - nextchar == strlen (p->name))
    - {
    - /* Exact match found. */
    - pfound = p;
    - indfound = option_index;
    - exact = 1;
    - break;
    - }
    - else if (pfound == NULL)
    - {
    - /* First nonexact match found. */
    - pfound = p;
    - indfound = option_index;
    - }
    - else
    - /* Second nonexact match found. */
    - ambig = 1;
    - }
    -
    - if (ambig && !exact)
    - {
    - if (opterr)
    - fprintf (stderr, "%s: option `%s' is ambiguous\n",
    - argv[0], argv[optind]);
    - nextchar += strlen (nextchar);
    - optind++;
    - return '?';
    - }
    -
    - if (pfound != NULL)
    - {
    - option_index = indfound;
    - optind++;
    - if (*s)
    - {
    - /* Don't test has_arg with >, because some C compilers don't
    - allow it to be used on enums. */
    - if (pfound->has_arg)
    - optarg = s + 1;
    - else
    - {
    - if (opterr)
    - {
    - if (argv[optind - 1][1] == '-')
    - /* --option */
    - fprintf (stderr,
    - "%s: option `--%s' doesn't allow an argument\n",
    - argv[0], pfound->name);
    - else
    - /* +option or -option */
    - fprintf (stderr,
    - "%s: option `%c%s' doesn't allow an argument\n",
    - argv[0], argv[optind - 1][0], pfound->name);
    - }
    - nextchar += strlen (nextchar);
    - return '?';
    - }
    - }
    - else if (pfound->has_arg == 1)
    - {
    - if (optind < argc)
    - optarg = argv[optind++];
    - else
    - {
    - if (opterr)
    - fprintf (stderr, "%s: option `%s' requires an argument\n",
    - argv[0], argv[optind - 1]);
    - nextchar += strlen (nextchar);
    - return optstring[0] == ':' ? ':' : '?';
    - }
    - }
    - nextchar += strlen (nextchar);
    - if (longind != NULL)
    - *longind = option_index;
    - if (pfound->flag)
    - {
    - *(pfound->flag) = pfound->val;
    - return 0;
    - }
    - return pfound->val;
    - }
    - /* Can't find it as a long option. If this is not getopt_long_only,
    - or the option starts with '--' or is not a valid short
    - option, then it's an error.
    - Otherwise interpret it as a short option. */
    - if (!long_only || argv[optind][1] == '-'
    -#ifdef GETOPT_COMPAT
    - || argv[optind][0] == '+'
    -#endif /* GETOPT_COMPAT */
    - || my_index (optstring, *nextchar) == NULL)
    - {
    - if (opterr)
    - {
    - if (argv[optind][1] == '-')
    - /* --option */
    - fprintf (stderr, "%s: unrecognized option `--%s'\n",
    - argv[0], nextchar);
    - else
    - /* +option or -option */
    - fprintf (stderr, "%s: unrecognized option `%c%s'\n",
    - argv[0], argv[optind][0], nextchar);
    - }
    - nextchar = (char *) "";
    - optind++;
    - return '?';
    - }
    - }
    -
    - /* Look at and handle the next option-character. */
    -
    - {
    - char c = *nextchar++;
    - char *temp = my_index (optstring, c);
    -
    - /* Increment `optind' when we start to process its last character. */
    - if (*nextchar == '\0')
    - ++optind;
    -
    - if (temp == NULL || c == ':')
    - {
    - if (opterr)
    - {
    -#if 0
    - if (c < 040 || c >= 0177)
    - fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
    - argv[0], c);
    - else
    - fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
    -#else
    - /* 1003.2 specifies the format of this message. */
    - fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
    -#endif
    - }
    - optopt = c;
    - return '?';
    - }
    - if (temp[1] == ':')
    - {
    - if (temp[2] == ':')
    - {
    - /* This is an option that accepts an argument optionally. */
    - if (*nextchar != '\0')
    - {
    - optarg = nextchar;
    - optind++;
    - }
    - else
    - optarg = NULL;
    - nextchar = NULL;
    - }
    - else
    - {
    - /* This is an option that requires an argument. */
    - if (*nextchar != '\0')
    - {
    - optarg = nextchar;
    - /* If we end this ARGV-element by taking the rest as an arg,
    - we must advance to the next element now. */
    - optind++;
    - }
    - else if (optind == argc)
    - {
    - if (opterr)
    - {
    -#if 0
    - fprintf (stderr, "%s: option `-%c' requires an argument\n",
    - argv[0], c);
    -#else
    - /* 1003.2 specifies the format of this message. */
    - fprintf (stderr, "%s: option requires an argument -- %c\n",
    - argv[0], c);
    -#endif
    - }
    - optopt = c;
    - if (optstring[0] == ':')
    - c = ':';
    - else
    - c = '?';
    - }
    - else
    - /* We already incremented `optind' once;
    - increment it again when taking next ARGV-elt as argument. */
    - optarg = argv[optind++];
    - nextchar = NULL;
    - }
    - }
    - return c;
    - }
    -}
    -
    -int
    -getopt (argc, argv, optstring)
    - int argc;
    - char *const *argv;
    - const char *optstring;
    -{
    - return _getopt_internal (argc, argv, optstring,
    - (const struct option *) 0,
    - (int *) 0,
    - 0);
    -}
    -
    -#endif /* _LIBC or not __GNU_LIBRARY__. */
    -
    -#ifdef TEST
    -
    -/* Compile with -DTEST to make an executable for use in testing
    - the above definition of `getopt'. */
    -
    -int
    -main (argc, argv)
    - int argc;
    - char **argv;
    -{
    - int c;
    - int digit_optind = 0;
    -
    - while (1)
    - {
    - int this_option_optind = optind ? optind : 1;
    -
    - c = getopt (argc, argv, "abc:d:0123456789");
    - if (c == EOF)
    - break;
    -
    - switch (c)
    - {
    - case '0':
    - case '1':
    - case '2':
    - case '3':
    - case '4':
    - case '5':
    - case '6':
    - case '7':
    - case '8':
    - case '9':
    - if (digit_optind != 0 && digit_optind != this_option_optind)
    - printf ("digits occur in two different argv-elements.\n");
    - digit_optind = this_option_optind;
    - printf ("option %c\n", c);
    - break;
    -
    - case 'a':
    - printf ("option a\n");
    - break;
    -
    - case 'b':
    - printf ("option b\n");
    - break;
    -
    - case 'c':
    - printf ("option c with value `%s'\n", optarg);
    - break;
    -
    - case '?':
    - break;
    -
    - default:
    - printf ("?? getopt returned character code 0%o ??\n", c);
    - }
    - }
    -
    - if (optind < argc)
    - {
    - printf ("non-option ARGV-elements: ");
    - while (optind < argc)
    - printf ("%s ", argv[optind++]);
    - printf ("\n");
    - }
    -
    - exit (0);
    -}
    -
    -#endif /* TEST */
    --- a/pidgin/getopt.h Fri Jul 07 11:50:28 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,136 +0,0 @@
    -/* Declarations for getopt.
    -
    - NOTE: getopt is now part of the C library, so if you don't know what
    - "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
    - before changing it!
    -
    - 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, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
    -
    -#ifndef _GETOPT_H
    -#define _GETOPT_H 1
    -
    -#ifdef __cplusplus
    -extern "C" {
    -#endif
    -
    -/* For communication from `getopt' to the caller.
    - When `getopt' finds an option that takes an argument,
    - the argument value is returned here.
    - Also, when `ordering' is RETURN_IN_ORDER,
    - each non-option ARGV-element is returned here. */
    -
    -extern char *optarg;
    -
    -/* Index in ARGV of the next element to be scanned.
    - This is used for communication to and from the caller
    - and for communication between successive calls to `getopt'.
    -
    - On entry to `getopt', zero means this is the first call; initialize.
    -
    - When `getopt' returns EOF, this is the index of the first of the
    - non-option elements that the caller should itself scan.
    -
    - Otherwise, `optind' communicates from one call to the next
    - how much of ARGV has been scanned so far. */
    -
    -extern int optind;
    -
    -/* Callers store zero here to inhibit the error message `getopt' prints
    - for unrecognized options. */
    -
    -extern int opterr;
    -
    -/* Set to an option character which was unrecognized. */
    -
    -extern int optopt;
    -
    -/* Describe the long-named options requested by the application.
    - The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
    - of `struct option' terminated by an element containing a name which is
    - zero.
    -
    - The field `has_arg' is:
    - no_argument (or 0) if the option does not take an argument,
    - required_argument (or 1) if the option requires an argument,
    - optional_argument (or 2) if the option takes an optional argument.
    -
    - If the field `flag' is not NULL, it points to a variable that is set
    - to the value given in the field `val' when the option is found, but
    - left unchanged if the option is not found.
    -
    - To have a long-named option do something other than set an `int' to
    - a compiled-in constant, such as set a value from `optarg', set the
    - option's `flag' field to zero and its `val' field to a nonzero
    - value (the equivalent single-letter option character, if there is
    - one). For long options that have a zero `flag' field, `getopt'
    - returns the contents of the `val' field. */
    -
    -struct option
    -{
    -#if __STDC__
    - const char *name;
    -#else
    - char *name;
    -#endif
    - /* has_arg can't be an enum because some compilers complain about
    - type mismatches in all the code that assumes it is an int. */
    - int has_arg;
    - int *flag;
    - int val;
    -};
    -
    -/* Names for the values of the `has_arg' field of `struct option'. */
    -
    -#define no_argument 0
    -#define required_argument 1
    -#define optional_argument 2
    -
    -#if __STDC__
    -#if defined(__GNU_LIBRARY__)
    -/* Many other libraries have conflicting prototypes for getopt, with
    - differences in the consts, in stdlib.h. To avoid compilation
    - errors, only prototype getopt for the GNU C library. */
    -extern int getopt (int argc, char *const *argv, const char *shortopts);
    -#else /* not __GNU_LIBRARY__ */
    -extern int getopt ();
    -#endif /* not __GNU_LIBRARY__ */
    -extern int getopt_long (int argc, char *const *argv, const char *shortopts,
    - const struct option *longopts, int *longind);
    -extern int getopt_long_only (int argc, char *const *argv,
    - const char *shortopts,
    - const struct option *longopts, int *longind);
    -
    -/* Internal only. Users should not call this directly. */
    -extern int _getopt_internal (int argc, char *const *argv,
    - const char *shortopts,
    - const struct option *longopts, int *longind,
    - int long_only);
    -#else /* not __STDC__ */
    -extern int getopt ();
    -extern int getopt_long ();
    -extern int getopt_long_only ();
    -
    -extern int _getopt_internal ();
    -#endif /* not __STDC__ */
    -
    -#ifdef __cplusplus
    -}
    -#endif
    -
    -#endif /* _GETOPT_H */
    --- a/pidgin/getopt1.c Fri Jul 07 11:50:28 2017 +0300
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,177 +0,0 @@
    -/* getopt_long and getopt_long_only entry points for GNU getopt.
    - 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, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
    -
    -#ifdef HAVE_CONFIG_H
    -#include "config.h"
    -#endif
    -
    -#include "getopt.h"
    -
    -#if !__STDC__ && !defined(const) && IN_GCC
    -#define const
    -#endif
    -
    -#include <stdio.h>
    -
    -/* Comment out all this code if we are using the GNU C Library, and are not
    - actually compiling the library itself. This code is part of the GNU C
    - Library, but also included in many other GNU distributions. Compiling
    - and linking in this code is a waste when using the GNU C library
    - (especially if it is a shared library). Rather than having every GNU
    - program understand `configure --with-gnu-libc' and omit the object files,
    - it is simpler to just do this in the source for each such file. */
    -
    -#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
    -
    -
    -/* This needs to come after some library #include
    - to get __GNU_LIBRARY__ defined. */
    -#ifdef __GNU_LIBRARY__
    -#include <stdlib.h>
    -#else
    -char *getenv ();
    -#endif
    -
    -#ifndef NULL
    -#define NULL 0
    -#endif
    -
    -int
    -getopt_long (argc, argv, options, long_options, opt_index)
    - int argc;
    - char *const *argv;
    - const char *options;
    - const struct option *long_options;
    - int *opt_index;
    -{
    - return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
    -}
    -
    -/* Like getopt_long, but '-' as well as '--' can indicate a long option.
    - If an option that starts with '-' (not '--') doesn't match a long option,
    - but does match a short option, it is parsed as a short option
    - instead. */
    -
    -int
    -getopt_long_only (argc, argv, options, long_options, opt_index)
    - int argc;
    - char *const *argv;
    - const char *options;
    - const struct option *long_options;
    - int *opt_index;
    -{
    - return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
    -}
    -
    -
    -#endif /* _LIBC or not __GNU_LIBRARY__. */
    -
    -#ifdef TEST
    -
    -#include <stdio.h>
    -
    -int
    -main (argc, argv)
    - int argc;
    - char **argv;
    -{
    - int c;
    - int digit_optind = 0;
    -
    - while (1)
    - {
    - int this_option_optind = optind ? optind : 1;
    - int option_index = 0;
    - static struct option long_options[] =
    - {
    - {"add", 1, 0, 0},
    - {"append", 0, 0, 0},
    - {"delete", 1, 0, 0},
    - {"verbose", 0, 0, 0},
    - {"create", 0, 0, 0},
    - {"file", 1, 0, 0},
    - {0, 0, 0, 0}
    - };
    -
    - c = getopt_long (argc, argv, "abc:d:0123456789",
    - long_options, &option_index);
    - if (c == EOF)
    - break;
    -
    - switch (c)
    - {
    - case 0:
    - printf ("option %s", long_options[option_index].name);
    - if (optarg)
    - printf (" with arg %s", optarg);
    - printf ("\n");
    - break;
    -
    - case '0':
    - case '1':
    - case '2':
    - case '3':
    - case '4':
    - case '5':
    - case '6':
    - case '7':
    - case '8':
    - case '9':
    - if (digit_optind != 0 && digit_optind != this_option_optind)
    - printf ("digits occur in two different argv-elements.\n");
    - digit_optind = this_option_optind;
    - printf ("option %c\n", c);
    - break;
    -
    - case 'a':
    - printf ("option a\n");
    - break;
    -
    - case 'b':
    - printf ("option b\n");
    - break;
    -
    - case 'c':
    - printf ("option c with value `%s'\n", optarg);
    - break;
    -
    - case 'd':
    - printf ("option d with value `%s'\n", optarg);
    - break;
    -
    - case '?':
    - break;
    -
    - default:
    - printf ("?? getopt returned character code 0%o ??\n", c);
    - }
    - }
    -
    - if (optind < argc)
    - {
    - printf ("non-option ARGV-elements: ");
    - while (optind < argc)
    - printf ("%s ", argv[optind++]);
    - printf ("\n");
    - }
    -
    - exit (0);
    -}
    -
    -#endif /* TEST */
    --- a/pidgin/gtk3compat.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtk3compat.h Sun Oct 08 20:44:26 2017 +0300
    @@ -33,6 +33,16 @@
    #include <gtk/gtk.h>
    +#if !GTK_CHECK_VERSION(3,22,0)
    +
    +static inline void
    +gtk_menu_popup_at_pointer(GtkMenu *menu, const GdkEvent *trigger_event)
    +{
    + const GdkEventButton *event = (const GdkEventButton *)trigger_event;
    + gtk_menu_popup(menu, NULL, NULL, NULL, NULL,
    + event ? event->button : 0, gdk_event_get_time(event));
    +}
    +
    #if !GTK_CHECK_VERSION(3,16,0)
    static inline void
    @@ -49,5 +59,7 @@
    #endif /* 3.16.0 */
    +#endif /* 3.22.0 */
    +
    #endif /* _PIDGINGTK3COMPAT_H_ */
    --- a/pidgin/gtkaccount.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkaccount.c Sun Oct 08 20:44:26 2017 +0300
    @@ -2248,7 +2248,7 @@
    gtk_tree_path_free(path);
    gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, COLUMN_DATA, &account, -1);
    - if ((account != NULL) && (event->button == 1) &&
    + if ((account != NULL) && (event->button == GDK_BUTTON_PRIMARY) &&
    (event->type == GDK_2BUTTON_PRESS))
    {
    pidgin_account_dialog_show(PIDGIN_MODIFY_ACCOUNT_DIALOG, account);
    @@ -2313,7 +2313,6 @@
    /* And now the actual treeview */
    treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model));
    dialog->treeview = treeview;
    - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
    g_object_unref(G_OBJECT(dialog->model));
    sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
    --- a/pidgin/gtkblist.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkblist.c Sun Oct 08 20:44:26 2017 +0300
    @@ -59,6 +59,7 @@
    #include "gtkblist-theme-loader.h"
    #include "gtkutils.h"
    #include "pidgin/minidialog.h"
    +#include "pidgin/pidginabout.h"
    #include "pidgin/pidgintooltip.h"
    #include <gdk/gdkkeysyms.h>
    @@ -183,7 +184,6 @@
    gint recent_signonoff_timer;
    struct {
    PurpleConversation *conv;
    - time_t last_message; /* timestamp for last displayed message */
    PidginBlistNodeFlags flags;
    } conv;
    } PidginBlistNode;
    @@ -1869,11 +1869,7 @@
    }
    static gboolean
    -pidgin_blist_show_context_menu(PurpleBlistNode *node,
    - GtkMenuPositionFunc func,
    - GtkWidget *tv,
    - guint button,
    - guint32 time)
    +pidgin_blist_show_context_menu(GtkWidget *tv, PurpleBlistNode *node, GdkEvent *event)
    {
    struct _pidgin_blist_node *gtknode = purple_blist_node_get_ui_data(node);
    GtkWidget *menu = NULL;
    @@ -1916,7 +1912,13 @@
    /* Now display the menu */
    if (menu != NULL) {
    gtk_widget_show_all(menu);
    - gtk_menu_popup(GTK_MENU(menu), NULL, NULL, func, tv, button, time);
    + if (event != NULL) {
    + /* Pointer event */
    + gtk_menu_popup_at_pointer(GTK_MENU(menu), event);
    + } else {
    + /* Keyboard event */
    + pidgin_menu_popup_at_treeview_selection(menu, tv);
    + }
    handled = TRUE;
    }
    @@ -1942,11 +1944,11 @@
    gtknode = purple_blist_node_get_ui_data(node);
    /* Right click draws a context menu */
    - if ((event->button == 3) && (event->type == GDK_BUTTON_PRESS)) {
    - handled = pidgin_blist_show_context_menu(node, NULL, tv, 3, event->time);
    + if (gdk_event_triggers_context_menu((GdkEvent *)event)) {
    + handled = pidgin_blist_show_context_menu(tv, node, (GdkEvent *)event);
    /* CTRL+middle click expands or collapse a contact */
    - } else if ((event->button == 2) && (event->type == GDK_BUTTON_PRESS) &&
    + } else if ((event->button == GDK_BUTTON_MIDDLE) && (event->type == GDK_BUTTON_PRESS) &&
    (event->state & GDK_CONTROL_MASK) && (PURPLE_IS_CONTACT(node))) {
    if (gtknode->contact_expanded)
    pidgin_blist_collapse_contact_cb(NULL, node);
    @@ -1955,7 +1957,7 @@
    handled = TRUE;
    /* Double middle click gets info */
    - } else if ((event->button == 2) && (event->type == GDK_2BUTTON_PRESS) &&
    + } else if ((event->button == GDK_BUTTON_MIDDLE) && (event->type == GDK_2BUTTON_PRESS) &&
    ((PURPLE_IS_CONTACT(node)) || (PURPLE_IS_BUDDY(node)))) {
    PurpleBuddy *b;
    if(PURPLE_IS_CONTACT(node))
    @@ -2006,7 +2008,7 @@
    gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &node, -1);
    /* Shift+F10 draws a context menu */
    - handled = pidgin_blist_show_context_menu(node, pidgin_treeview_popup_menu_position_func, tv, 0, GDK_CURRENT_TIME);
    + handled = pidgin_blist_show_context_menu(tv, node, NULL);
    return handled;
    }
    @@ -3605,6 +3607,15 @@
    /***************************************************
    * Crap *
    ***************************************************/
    +static void
    +_pidgin_about_cb(GtkAction *action, GtkWidget *window) {
    + GtkWidget *about = pidgin_about_dialog_new();
    +
    + gtk_window_set_transient_for(GTK_WINDOW(about), GTK_WINDOW(window));
    +
    + gtk_widget_show_all(about);
    +}
    +
    /* TODO: fill out tooltips... */
    static const GtkActionEntry blist_menu_entries[] = {
    /* NOTE: Do not set any accelerator to Control+O. It is mapped by
    @@ -3642,12 +3653,9 @@
    /* Help */
    { "HelpMenu", NULL, N_("_Help"), NULL, NULL, NULL },
    { "OnlineHelp", GTK_STOCK_HELP, N_("Online _Help"), "F1", NULL, gtk_blist_show_onlinehelp_cb },
    - { "BuildInformation", NULL, N_("_Build Information"), NULL, NULL, pidgin_dialogs_buildinfo },
    { "DebugWindow", NULL, N_("_Debug Window"), NULL, NULL, toggle_debug },
    - { "DeveloperInformation", NULL, N_("De_veloper Information"), NULL, NULL, pidgin_dialogs_developers },
    { "PluginInformation", NULL, N_("_Plugin Information"), NULL, NULL, pidgin_dialogs_plugins_info },
    - { "TranslatorInformation", NULL, N_("_Translator Information"), NULL, NULL, pidgin_dialogs_translators },
    - { "About", GTK_STOCK_ABOUT, N_("_About"), NULL, NULL, pidgin_dialogs_about },
    + { "About", GTK_STOCK_ABOUT, N_("_About"), NULL, NULL, _pidgin_about_cb },
    };
    /* Toggle items */
    @@ -3709,11 +3717,8 @@
    "<menu action='HelpMenu'>"
    "<menuitem action='OnlineHelp'/>"
    "<separator/>"
    - "<menuitem action='BuildInformation'/>"
    "<menuitem action='DebugWindow'/>"
    - "<menuitem action='DeveloperInformation'/>"
    "<menuitem action='PluginInformation'/>"
    - "<menuitem action='TranslatorInformation'/>"
    "<separator/>"
    "<menuitem action='About'/>"
    "</menu>"
    @@ -4588,7 +4593,7 @@
    }
    static void
    -unseen_conv_menu(void)
    +unseen_conv_menu(GdkEvent *event)
    {
    static GtkWidget *menu = NULL;
    GList *convs = NULL;
    @@ -4619,8 +4624,7 @@
    pidgin_conversations_fill_menu(menu, convs);
    g_list_free(convs);
    gtk_widget_show_all(menu);
    - gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3,
    - gtk_get_current_event_time());
    + gtk_menu_popup_at_pointer(GTK_MENU(menu), event);
    }
    static gboolean
    @@ -4628,21 +4632,20 @@
    {
    GList *convs;
    - switch (event->button) {
    - case 1:
    - convs = pidgin_conversations_get_unseen_ims(PIDGIN_UNSEEN_TEXT, FALSE, 1);
    -
    - if(!convs)
    - convs = pidgin_conversations_get_unseen_chats(PIDGIN_UNSEEN_NICK, FALSE, 1);
    - if (convs) {
    - pidgin_conv_present_conversation((PurpleConversation*)convs->data);
    - g_list_free(convs);
    - }
    - break;
    - case 3:
    - unseen_conv_menu();
    - break;
    - }
    + if (event->button == GDK_BUTTON_PRIMARY) {
    + convs = pidgin_conversations_get_unseen_ims(PIDGIN_UNSEEN_TEXT, FALSE, 1);
    + if(!convs)
    + convs = pidgin_conversations_get_unseen_chats(PIDGIN_UNSEEN_NICK, FALSE, 1);
    +
    + if (convs) {
    + pidgin_conv_present_conversation((PurpleConversation*)convs->data);
    + g_list_free(convs);
    + }
    +
    + } else if (gdk_event_triggers_context_menu((GdkEvent *)event)) {
    + unseen_conv_menu((GdkEvent *)event);
    + }
    +
    return TRUE;
    }
    @@ -4732,7 +4735,6 @@
    return;
    ui->conv.conv = NULL;
    ui->conv.flags = 0;
    - ui->conv.last_message = 0;
    }
    static void
    @@ -4753,7 +4755,6 @@
    if (PURPLE_IS_CHAT_CONVERSATION(conv) && (purple_message_get_flags(msg) & PURPLE_MESSAGE_NICK))
    ui->conv.flags |= PIDGIN_BLIST_CHAT_HAS_PENDING_MESSAGE_WITH_NICK;
    - ui->conv.last_message = time(NULL); /* XXX: for lack of better data */
    pidgin_blist_update(purple_blist_get_buddy_list(), node);
    }
    @@ -4783,7 +4784,6 @@
    continue;
    ui->conv.conv = conv;
    ui->conv.flags = 0;
    - ui->conv.last_message = 0;
    purple_signal_connect(purple_conversations_get_handle(), "deleting-conversation",
    ui, PURPLE_CALLBACK(conversation_deleted_update_ui_cb), ui);
    purple_signal_connect(purple_conversations_get_handle(), "wrote-im-msg",
    @@ -4801,7 +4801,6 @@
    return;
    ui->conv.conv = conv;
    ui->conv.flags = 0;
    - ui->conv.last_message = 0;
    purple_signal_connect(purple_conversations_get_handle(), "deleting-conversation",
    ui, PURPLE_CALLBACK(conversation_deleted_update_ui_cb), ui);
    purple_signal_connect(purple_conversations_get_handle(), "wrote-chat-msg",
    @@ -4981,7 +4980,7 @@
    static void pidgin_blist_select_notebook_page(PidginBuddyList *gtkblist)
    {
    PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist);
    - priv->select_notebook_page_timeout = purple_timeout_add(0,
    + priv->select_notebook_page_timeout = g_timeout_add(0,
    pidgin_blist_select_notebook_page_cb, gtkblist);
    }
    @@ -6042,7 +6041,7 @@
    purple_blist_set_visible(purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/list_visible"));
    /* start the refresh timer */
    - gtkblist->refresh_timer = purple_timeout_add_seconds(30, (GSourceFunc)pidgin_blist_refresh_timer, list);
    + gtkblist->refresh_timer = g_timeout_add_seconds(30, (GSourceFunc)pidgin_blist_refresh_timer, list);
    handle = pidgin_blist_get_handle();
    @@ -6165,7 +6164,7 @@
    blist = purple_blist_get_buddy_list();
    gtkblist = PIDGIN_BLIST(purple_blist_get_buddy_list());
    - gtkblist->refresh_timer = purple_timeout_add_seconds(30,(GSourceFunc)pidgin_blist_refresh_timer, blist);
    + gtkblist->refresh_timer = g_timeout_add_seconds(30,(GSourceFunc)pidgin_blist_refresh_timer, blist);
    }
    static gboolean get_iter_from_node(PurpleBlistNode *node, GtkTreeIter *iter) {
    @@ -6218,7 +6217,7 @@
    if(gtknode) {
    if(gtknode->recent_signonoff_timer > 0)
    - purple_timeout_remove(gtknode->recent_signonoff_timer);
    + g_source_remove(gtknode->recent_signonoff_timer);
    purple_signals_disconnect_by_handle(gtknode);
    g_free(gtknode);
    @@ -6882,7 +6881,7 @@
    pidgin_blist_tooltip_destroy();
    if (gtkblist->refresh_timer)
    - purple_timeout_remove(gtkblist->refresh_timer);
    + g_source_remove(gtkblist->refresh_timer);
    if (gtkblist->timeout)
    g_source_remove(gtkblist->timeout);
    if (gtkblist->drag_timeout)
    @@ -6902,7 +6901,7 @@
    if (priv->current_theme)
    g_object_unref(priv->current_theme);
    if (priv->select_notebook_page_timeout)
    - purple_timeout_remove(priv->select_notebook_page_timeout);
    + g_source_remove(priv->select_notebook_page_timeout);
    g_free(priv);
    g_free(gtkblist);
    @@ -7494,10 +7493,10 @@
    gtknode->recent_signonoff = TRUE;
    if(gtknode->recent_signonoff_timer > 0)
    - purple_timeout_remove(gtknode->recent_signonoff_timer);
    -
    + g_source_remove(gtknode->recent_signonoff_timer);
    +
    g_object_ref(buddy);
    - gtknode->recent_signonoff_timer = purple_timeout_add_seconds(10,
    + gtknode->recent_signonoff_timer = g_timeout_add_seconds(10,
    (GSourceFunc)buddy_signonoff_timeout_cb, buddy);
    }
    --- a/pidgin/gtkconv.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkconv.c Sun Oct 08 20:44:26 2017 +0300
    @@ -1383,8 +1383,8 @@
    if (closetimer) {
    guint timer = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(conv), "close-timer"));
    if (timer)
    - purple_timeout_remove(timer);
    - timer = purple_timeout_add_seconds(CLOSE_CONV_TIMEOUT_SECS, close_already, conv);
    + g_source_remove(timer);
    + timer = g_timeout_add_seconds(CLOSE_CONV_TIMEOUT_SECS, close_already, conv);
    g_object_set_data(G_OBJECT(conv), "close-timer", GINT_TO_POINTER(timer));
    }
    #if 0
    @@ -1796,9 +1796,7 @@
    gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHAT_USERS_NAME_COLUMN, &who, -1);
    menu = create_chat_menu (PURPLE_CHAT_CONVERSATION(conv), who, gc);
    - gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
    - pidgin_treeview_popup_menu_position_func, widget,
    - 0, GDK_CURRENT_TIME);
    + pidgin_menu_popup_at_treeview_selection(menu, widget);
    g_free(who);
    return TRUE;
    @@ -1850,19 +1848,18 @@
    goto handled;
    }
    - if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) {
    + if (event->button == GDK_BUTTON_PRIMARY && event->type == GDK_2BUTTON_PRESS) {
    chat_do_im(gtkconv, who);
    - } else if (event->button == 2 && event->type == GDK_BUTTON_PRESS) {
    + } else if (event->button == GDK_BUTTON_MIDDLE && event->type == GDK_BUTTON_PRESS) {
    /* Move to user's anchor */
    WebKitDOMNode *node = get_mark_for_user(gtkconv, who);
    if (node != NULL)
    webkit_dom_element_scroll_into_view(WEBKIT_DOM_ELEMENT(node), TRUE);
    - } else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
    + } else if (gdk_event_triggers_context_menu((GdkEvent *)event)) {
    GtkWidget *menu = create_chat_menu (PURPLE_CHAT_CONVERSATION(conv), who, gc);
    - gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
    - event->button, event->time);
    + gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
    }
    handled:
    @@ -2003,7 +2000,7 @@
    is_empty = pidgin_webview_is_empty(PIDGIN_WEBVIEW(gtkconv->entry));
    if (!is_empty)
    - purple_timeout_add(0, (GSourceFunc)update_typing_deleting_cb, gtkconv);
    + g_timeout_add(0, (GSourceFunc)update_typing_deleting_cb, gtkconv);
    }
    static gboolean
    @@ -2289,7 +2286,7 @@
    static gboolean
    entry_stop_rclick_cb(GtkWidget *widget, GdkEventButton *event, gpointer data)
    {
    - if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
    + if (event->button == GDK_BUTTON_SECONDARY && event->type == GDK_BUTTON_PRESS) {
    /* Right single click */
    g_signal_stop_emission_by_name(G_OBJECT(widget), "button_press_event");
    @@ -2962,12 +2959,12 @@
    PurpleConversation *conv;
    PurpleBuddy *buddy;
    - if (e->button == 1 && e->type == GDK_BUTTON_PRESS) {
    + if (e->button == GDK_BUTTON_PRIMARY && e->type == GDK_BUTTON_PRESS) {
    change_size_cb(NULL, gtkconv);
    return TRUE;
    }
    - if (e->button != 3 || e->type != GDK_BUTTON_PRESS) {
    + if (!gdk_event_triggers_context_menu((GdkEvent *)e)) {
    return FALSE;
    }
    @@ -3015,7 +3012,7 @@
    }
    }
    - gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, e->button, e->time);
    + gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)e);
    return TRUE;
    }
    @@ -5883,7 +5880,7 @@
    * So if Stu accidentally aims high and middle clicks on the pane-handle,
    * it causes a conversation tab to close. Let's stop that from happening.
    */
    - if (e->button == 2 && e->type == GDK_BUTTON_PRESS)
    + if (e->button == GDK_BUTTON_MIDDLE && e->type == GDK_BUTTON_PRESS)
    return TRUE;
    return FALSE;
    }
    @@ -6132,7 +6129,7 @@
    if (conv) {
    timer = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(conv), "close-timer"));
    if (timer) {
    - purple_timeout_remove(timer);
    + g_source_remove(timer);
    g_object_set_data(G_OBJECT(conv), "close-timer", GINT_TO_POINTER(0));
    }
    }
    @@ -6246,17 +6243,17 @@
    }
    }
    - if (btn_event->button == 1 && event->type == GDK_2BUTTON_PRESS) {
    + if (btn_event->button == GDK_BUTTON_PRIMARY && event->type == GDK_2BUTTON_PRESS) {
    chat_do_im(PIDGIN_CONVERSATION(conv), buddyname);
    g_free(name);
    return TRUE;
    - } else if (btn_event->button == 2 && event->type == GDK_2BUTTON_PRESS) {
    + } else if (btn_event->button == GDK_BUTTON_MIDDLE && event->type == GDK_2BUTTON_PRESS) {
    chat_do_info(PIDGIN_CONVERSATION(conv), buddyname);
    g_free(name);
    return TRUE;
    - } else if (btn_event->button == 3 && event->type == GDK_BUTTON_PRESS) {
    + } else if (gdk_event_triggers_context_menu(event)) {
    GtkTextIter start, end;
    /* we shouldn't display the popup
    @@ -6268,12 +6265,8 @@
    PurpleConnection *gc =
    purple_conversation_get_connection(conv);
    -
    menu = create_chat_menu(conv, buddyname, gc);
    - gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
    - NULL, GTK_WIDGET(imhtml),
    - btn_event->button,
    - btn_event->time);
    + gtk_menu_popup_at_pointer(GTK_MENU(menu), event);
    g_free(name);
    @@ -8576,7 +8569,7 @@
    private_gtkconv_new(conv, FALSE);
    timer = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(conv), "close-timer"));
    if (timer) {
    - purple_timeout_remove(timer);
    + g_source_remove(timer);
    g_object_set_data(G_OBJECT(conv), "close-timer", NULL);
    }
    }
    @@ -9357,7 +9350,7 @@
    static gboolean
    infopane_press_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *gtkconv)
    {
    - if (e->type == GDK_2BUTTON_PRESS && e->button == 1) {
    + if (e->type == GDK_2BUTTON_PRESS && e->button == GDK_BUTTON_PRIMARY) {
    if (infopane_entry_activate(gtkconv))
    return TRUE;
    }
    @@ -9365,7 +9358,7 @@
    if (e->type != GDK_BUTTON_PRESS)
    return FALSE;
    - if (e->button == 1) {
    + if (e->button == GDK_BUTTON_PRIMARY) {
    int nb_x, nb_y;
    GtkAllocation allocation;
    @@ -9391,7 +9384,7 @@
    return FALSE;
    }
    - if (e->button == 3) {
    + if (gdk_event_triggers_context_menu((GdkEvent *)e)) {
    /* Right click was pressed. Popup the context menu. */
    GtkWidget *menu = gtk_menu_new(), *sub;
    gboolean populated = populate_menu_with_options(menu, gtkconv, TRUE);
    @@ -9411,7 +9404,7 @@
    }
    gtk_widget_show_all(menu);
    - gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, e->button, e->time);
    + gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)e);
    return TRUE;
    }
    return FALSE;
    @@ -9426,7 +9419,7 @@
    GtkWidget *tab;
    GtkAllocation allocation;
    - if (e->button == 2 && e->type == GDK_BUTTON_PRESS) {
    + if (e->button == GDK_BUTTON_MIDDLE && e->type == GDK_BUTTON_PRESS) {
    PidginConversation *gtkconv;
    tab_clicked = pidgin_conv_get_tab_at_xy(win, e->x_root, e->y_root, NULL);
    @@ -9439,7 +9432,7 @@
    }
    - if (e->button != 1 || e->type != GDK_BUTTON_PRESS)
    + if (e->button != GDK_BUTTON_PRIMARY || e->type != GDK_BUTTON_PRESS)
    return FALSE;
    @@ -9522,7 +9515,7 @@
    * widget's, because we may be getting an event passed on from the
    * close button.
    */
    - if (e->button != 1 && e->type != GDK_BUTTON_RELEASE)
    + if (e->button != GDK_BUTTON_PRIMARY && e->type != GDK_BUTTON_RELEASE)
    return FALSE;
    device = gdk_event_get_device((GdkEvent *)e);
    @@ -9804,7 +9797,7 @@
    GtkWidget *menu;
    PidginConversation *gtkconv;
    - if (event->type != GDK_BUTTON_PRESS || event->button != 3)
    + if (!gdk_event_triggers_context_menu((GdkEvent *)event))
    return FALSE;
    gtkconv = pidgin_conv_window_get_gtkconv_at_index(win,
    @@ -9814,7 +9807,7 @@
    menu = win->notebook_menu;
    - gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, event->time);
    + gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
    return TRUE;
    }
    --- a/pidgin/gtkdebug.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkdebug.c Sun Oct 08 20:44:26 2017 +0300
    @@ -40,7 +40,7 @@
    #include "gtk3compat.h"
    -#include "pidgin.gresource.h"
    +#include "pidginresources.h"
    typedef struct
    {
    @@ -59,7 +59,21 @@
    } DebugWindow;
    static DebugWindow *debug_win = NULL;
    -static guint debug_enabled_timer = 0;
    +
    +struct _PidginDebugUi
    +{
    + GObject parent;
    +
    + /* Other members, including private data. */
    + guint debug_enabled_timer;
    +};
    +
    +static void pidgin_debug_ui_finalize(GObject *gobject);
    +static void pidgin_debug_ui_interface_init(PurpleDebugUiInterface *iface);
    +
    +G_DEFINE_TYPE_WITH_CODE(PidginDebugUi, pidgin_debug_ui, G_TYPE_OBJECT,
    + G_IMPLEMENT_INTERFACE(PURPLE_TYPE_DEBUG_UI,
    + pidgin_debug_ui_interface_init));
    static gint
    debug_window_destroy(GtkWidget *w, GdkEvent *event, void *unused)
    @@ -69,7 +83,7 @@
    if(debug_win->timer != 0) {
    const gchar *text;
    - purple_timeout_remove(debug_win->timer);
    + g_source_remove(debug_win->timer);
    text = gtk_entry_get_text(GTK_ENTRY(debug_win->expression));
    purple_prefs_set_string(PIDGIN_PREFS_ROOT "/debug/regex", text);
    @@ -261,7 +275,7 @@
    }
    if (win->timer == 0)
    - win->timer = purple_timeout_add_seconds(5, (GSourceFunc)regex_timer_cb, win);
    + win->timer = g_timeout_add_seconds(5, (GSourceFunc)regex_timer_cb, win);
    text = gtk_entry_get_text(GTK_ENTRY(win->expression));
    @@ -382,7 +396,7 @@
    GtkToolbarStyle value[3];
    int i;
    - if (!(event->button == 3 && event->type == GDK_BUTTON_PRESS))
    + if (!gdk_event_triggers_context_menu((GdkEvent *)event))
    return FALSE;
    text[0] = _("_Icon Only"); value[0] = GTK_TOOLBAR_ICONS;
    @@ -402,7 +416,7 @@
    gtk_widget_show_all(menu);
    - gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, event->time);
    + gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
    return FALSE;
    }
    @@ -592,7 +606,7 @@
    resource = pidgin_get_resource();
    error = NULL;
    resource_bytes = g_resource_lookup_data(resource,
    - "/im/pidgin/Pidgin/gtkdebug.html",
    + "/im/pidgin/Pidgin/Debug/gtkdebug.html",
    G_RESOURCE_LOOKUP_FLAGS_NONE,
    &error);
    if (G_UNLIKELY(resource_bytes == NULL || error != NULL)) {
    @@ -621,12 +635,23 @@
    static gboolean
    debug_enabled_timeout_cb(gpointer data)
    {
    - debug_enabled_timer = 0;
    + PidginDebugUi *ui = PIDGIN_DEBUG_UI(data);
    +
    + ui->debug_enabled_timer = 0;
    +
    + pidgin_debug_window_show();
    +
    + return FALSE;
    +}
    - if (data)
    - pidgin_debug_window_show();
    - else
    - pidgin_debug_window_hide();
    +static gboolean
    +debug_disabled_timeout_cb(gpointer data)
    +{
    + PidginDebugUi *ui = PIDGIN_DEBUG_UI(data);
    +
    + ui->debug_enabled_timer = 0;
    +
    + pidgin_debug_window_hide();
    return FALSE;
    }
    @@ -635,7 +660,12 @@
    debug_enabled_cb(const char *name, PurplePrefType type,
    gconstpointer value, gpointer data)
    {
    - debug_enabled_timer = g_timeout_add(0, debug_enabled_timeout_cb, GINT_TO_POINTER(GPOINTER_TO_INT(value)));
    + PidginDebugUi *ui = PIDGIN_DEBUG_UI(data);
    +
    + if (GPOINTER_TO_INT(value))
    + ui->debug_enabled_timer = g_timeout_add(0, debug_enabled_timeout_cb, data);
    + else
    + ui->debug_enabled_timer = g_timeout_add(0, debug_disabled_timeout_cb, data);
    }
    static void
    @@ -701,8 +731,8 @@
    }
    #endif
    -void
    -pidgin_debug_init(void)
    +static void
    +pidgin_debug_ui_init(PidginDebugUi *self)
    {
    /* Debug window preferences. */
    /*
    @@ -730,7 +760,7 @@
    purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/debug/highlight", FALSE);
    purple_prefs_connect_callback(NULL, PIDGIN_PREFS_ROOT "/debug/enabled",
    - debug_enabled_cb, NULL);
    + debug_enabled_cb, self);
    #define REGISTER_G_LOG_HANDLER(name) \
    g_log_set_handler((name), G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL \
    @@ -757,13 +787,16 @@
    #endif
    }
    -void
    -pidgin_debug_uninit(void)
    +static void
    +pidgin_debug_ui_finalize(GObject *gobject)
    {
    - purple_debug_set_ui_ops(NULL);
    + PidginDebugUi *self = PIDGIN_DEBUG_UI(gobject);
    - if (debug_enabled_timer != 0)
    - g_source_remove(debug_enabled_timer);
    + if (self->debug_enabled_timer != 0)
    + g_source_remove(self->debug_enabled_timer);
    + self->debug_enabled_timer = 0;
    +
    + G_OBJECT_CLASS(pidgin_debug_ui_parent_class)->finalize(gobject);
    }
    void
    @@ -787,8 +820,9 @@
    }
    static void
    -pidgin_debug_print(PurpleDebugLevel level, const char *category,
    - const char *arg_s)
    +pidgin_debug_print(PurpleDebugUi *self,
    + PurpleDebugLevel level, const char *category,
    + const char *arg_s)
    {
    gchar *esc_s;
    const char *mdate;
    @@ -814,26 +848,31 @@
    }
    static gboolean
    -pidgin_debug_is_enabled(PurpleDebugLevel level, const char *category)
    +pidgin_debug_is_enabled(PurpleDebugUi *self, PurpleDebugLevel level, const char *category)
    {
    return (debug_win != NULL &&
    purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/debug/enabled"));
    }
    -static PurpleDebugUiOps ops =
    +static void
    +pidgin_debug_ui_interface_init(PurpleDebugUiInterface *iface)
    +{
    + iface->print = pidgin_debug_print;
    + iface->is_enabled = pidgin_debug_is_enabled;
    +}
    +
    +static void
    +pidgin_debug_ui_class_init(PidginDebugUiClass *klass)
    {
    - pidgin_debug_print,
    - pidgin_debug_is_enabled,
    - NULL,
    - NULL,
    - NULL,
    - NULL
    -};
    + GObjectClass *object_class = G_OBJECT_CLASS(klass);
    +
    + object_class->finalize = pidgin_debug_ui_finalize;
    +}
    -PurpleDebugUiOps *
    -pidgin_debug_get_ui_ops(void)
    +PidginDebugUi *
    +pidgin_debug_ui_new(void)
    {
    - return &ops;
    + return g_object_new(PIDGIN_TYPE_DEBUG_UI, NULL);
    }
    void *
    --- a/pidgin/gtkdebug.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkdebug.h Sun Oct 08 20:44:26 2017 +0300
    @@ -32,19 +32,33 @@
    G_BEGIN_DECLS
    +#define PIDGIN_TYPE_DEBUG_UI (pidgin_debug_ui_get_type())
    +#if GLIB_CHECK_VERSION(2,44,0)
    +G_DECLARE_FINAL_TYPE(PidginDebugUi, pidgin_debug_ui, PIDGIN, DEBUG_UI, GObject)
    +#else
    +GType pidgin_debug_ui_get_type(void);
    +G_GNUC_BEGIN_IGNORE_DEPRECATIONS
    +typedef struct _PidginDebugUi PidginDebugUi;
    +typedef struct { GObjectClass parent_class; } PidginDebugUiClass;
    +static inline PidginDebugUi *
    +PIDGIN_DEBUG_UI(gpointer ptr)
    +{
    + return G_TYPE_CHECK_INSTANCE_CAST(ptr, pidgin_debug_ui_get_type(), PidginDebugUi);
    +}
    +static inline gboolean
    +PIDGIN_IS_DEBUG_UI(gpointer ptr)
    +{
    + return G_TYPE_CHECK_INSTANCE_TYPE(ptr, pidgin_debug_ui_get_type());
    +}
    +G_GNUC_END_IGNORE_DEPRECATIONS
    +#endif
    +
    /**
    - * pidgin_debug_init:
    + * pidgin_debug_ui_new:
    *
    * Initializes the GTK+ debug system.
    */
    -void pidgin_debug_init(void);
    -
    -/**
    - * pidgin_debug_uninit:
    - *
    - * Uninitialized the GTK+ debug system.
    - */
    -void pidgin_debug_uninit(void);
    +PidginDebugUi *pidgin_debug_ui_new(void);
    /**
    * pidgin_debug_get_handle:
    @@ -69,15 +83,6 @@
    */
    void pidgin_debug_window_hide(void);
    -/**
    - * pidgin_debug_get_ui_ops:
    - *
    - * Returns the UI operations structure for GTK+ debug output.
    - *
    - * Returns: The GTK+ UI debug operations structure.
    - */
    -PurpleDebugUiOps *pidgin_debug_get_ui_ops(void);
    -
    G_END_DECLS
    #endif /* _PIDGINDEBUG_H_ */
    --- a/pidgin/gtkdialogs.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkdialogs.c Sun Oct 08 20:44:26 2017 +0300
    @@ -23,6 +23,9 @@
    #include "internal.h"
    #include "pidgin.h"
    #include "package_revision.h"
    +#ifdef HAVE_MESON_CONFIG
    +#include "meson-config.h"
    +#endif
    #include "debug.h"
    #include "notify.h"
    @@ -52,359 +55,6 @@
    char *new_name;
    };
    -struct developer {
    - char *name;
    - char *role;
    - char *email;
    -};
    -
    -struct translator {
    - char *language;
    - char *abbr;
    - char *name;
    - char *email;
    -};
    -
    -struct artist {
    - char *name;
    - char *email;
    -};
    -
    -/* Order: Alphabetical by Last Name */
    -static const struct developer developers[] = {
    - {"Daniel 'datallah' Atallah", NULL, NULL},
    - {"Paul 'darkrain42' Aurich", NULL, NULL},
    - {"Ethan 'Paco-Paco' Blanton", NULL, NULL},
    - {"Hylke Bons", N_("artist"), "hylkebons@gmail.com"},
    - {"Sadrul Habib Chowdhury", NULL, NULL},
    - {"Gary 'grim' Kramlich", NULL, "grim@pidgin.im"},
    - {"Richard 'rlaager' Laager", NULL, "rlaager@pidgin.im"},
    - {"Marcus 'malu' Lundblad", NULL, NULL},
    - {"Sulabh 'sulabh_m' Mahajan", NULL, NULL},
    - {"Richard 'wabz' Nelson", NULL, NULL},
    - {"Etan 'deryni' Reisner", NULL, NULL},
    - {"Michael 'Maiku' Ruprecht", N_("voice and video"), NULL},
    - {"Elliott 'QuLogic' Sales de Andrade", NULL, NULL},
    - {"Luke 'LSchiere' Schierer", N_("support"), "lschiere@users.sf.net"},
    - {"Evan Schoenberg", NULL, NULL},
    - {"Kevin 'SimGuy' Stange", N_("webmaster"), NULL},
    - {"Will 'resiak' Thompson", NULL, NULL},
    - {"Stu 'nosnilmot' Tomlinson", NULL, NULL},
    - {"Jorge 'Masca' Villaseñor", NULL, NULL},
    - {"Tomasz Wasilczyk", NULL, "https://www.wasilczyk.pl"},
    - {NULL, NULL, NULL}
    -};
    -
    -/* Order: Alphabetical by Last Name */
    -static const struct developer patch_writers[] = {
    - {"Jakub 'haakon' Adam", NULL, NULL},
    - {"Krzysztof Klinikowski", NULL, NULL},
    - {"Eion Robb", NULL, NULL},
    - {"Ankit Vani", NULL, NULL},
    - {NULL, NULL, NULL}
    -};
    -
    -/* Order: Alphabetical by Last Name */
    -static const struct developer retired_developers[] = {
    - {"John 'rekkanoryo' Bailey", NULL, NULL},
    - {"Herman Bloggs", N_("win32 port"), "herman@bluedigits.com"},
    - {"Thomas Butter", NULL, NULL},
    - /* Translators: This is a person's name. For most languages we recommend
    - not translating it. */
    - {N_("Ka-Hing Cheung"), NULL, NULL},
    - {"Mark 'KingAnt' Doliner", NULL, "mark@kingant.net"},
    - {"Jim Duchek", N_("maintainer"), "jim@linuxpimps.com"},
    - {"Sean Egan", NULL, "sean.egan@gmail.com"},
    - {"Rob Flynn", N_("maintainer"), NULL},
    - {"Adam Fritzler", N_("libfaim maintainer"), NULL},
    - {"Christian 'ChipX86' Hammond", N_("webmaster"), NULL},
    - {"Casey Harkins", NULL, NULL},
    - {"Ivan Komarov", NULL, "ivan.komarov@pidgin.im"},
    - /* If "lazy bum" translates literally into a serious insult, use something else or omit it. */
    - {"Syd Logan", N_("hacker and designated driver [lazy bum]"), NULL},
    - {"Christopher 'siege' O'Brien", NULL, "taliesein@users.sf.net"},
    - {"Bartosz Oler", NULL, NULL},
    - {"Tim 'marv' Ringenbach", NULL, NULL},
    - {"Megan 'Cae' Schneider", N_("support/QA"), NULL},
    - {"Jim Seymour", N_("XMPP"), NULL},
    - {"Mark Spencer", N_("original author"), "markster@marko.net"},
    - {"Nathan 'faceprint' Walp", NULL, NULL},
    - {"Eric Warmenhoven", N_("lead developer"), "warmenhoven@yahoo.com"},
    - {NULL, NULL, NULL}
    -};
    -
    -/* Order: Alphabetical by Last Name */
    -static const struct developer retired_patch_writers[] = {
    - {"Felipe 'shx' Contreras", NULL, NULL},
    - {"Decklin Foster", NULL, NULL},
    - {"Peter 'Bleeter' Lawler", NULL, NULL},
    - {"Robert 'Robot101' McQueen", NULL, NULL},
    - {"Benjamin Miller", NULL, NULL},
    - {"Dennis 'EvilDennisR' Ristuccia", N_("Senior Contributor/QA"), NULL},
    - {"Peter 'Fmoo' Ruibal", NULL, NULL},
    - {"Gabriel 'Nix' Schulhof", NULL, NULL},
    - {NULL, NULL, NULL}
    -};
    -
    -/* Order: Code, then Alphabetical by Last Name
    - Use NULL language and code for secondary translators. */
    -static const struct translator translators[] = {
    - {N_("Afrikaans"), "af", "Samuel Murray", "afrikaans@gmail.com"},
    - {NULL, NULL, "Friedel Wolff", "friedel@translate.org.za"},
    - {N_("Arabic"), "ar", "Khaled Hosny", "khaledhosny@eglug.org"},
    - {N_("Assamese"), "as", "Amitakhya Phukan", "aphukan@fedoraproject.org"},
    - {N_("Asturian"), "ast", "Llumex03", "l.lumex03.tornes@gmail.com"},
    - {N_("Belarusian Latin"), "be@latin", "Ihar Hrachyshka", "ihar.hrachyshka@gmail.com"},
    - {N_("Bulgarian"), "bg", "Vladimira Girginova", "missing@here.is"},
    - {NULL, NULL, "Vladimir (Kaladan) Petkov", "kaladan@gmail.com"},
    - {N_("Bengali"), "bn", "Jamil Ahmed", "jamil@bengalinux.org"},
    - {NULL, NULL, "Israt Jahan", "israt@ankur.org.bd"},
    - {NULL, NULL, "Samia Nimatullah", "mailsamia2001@yahoo.com"},
    - {N_("Bengali-India"), "bn_IN", "Runa Bhattacharjee", "runab@fedoraproject.org"},
    - {N_("Breton"), "br", "Gwenn Meynier", "tornoz@laposte.net"},
    - {N_("Bodo"), "brx", "Chandrakant Dhutadmal", "cpdhutadmal@yahoo.com"},
    - {N_("Bosnian"), "bs", "Lejla Hadzialic", "lejlah@gmail.com"},
    - {N_("Catalan"), "ca", "Josep Puigdemont", "josep.puigdemont@gmail.com"},
    - {N_("Valencian-Catalan"), "ca@valencia", "Toni Hermoso", "toniher@softcatala.org"},
    - {NULL, NULL, "Josep Puigdemont", "tradgnome@softcatala.org"},
    - {N_("Czech"), "cs", "David Vachulka", "david@konstrukce-cad.com"},
    - {N_("Danish"), "da", "Nicky Thomassen", "nicky@aptget.dk"},
    - {N_("German"), "de", "Björn Voigt", "bjoernv@arcor.de"},
    - {N_("Dzongkha"), "dz", "Norbu", "nor_den@hotmail.com"},
    - {NULL, NULL, "Jurmey Rabgay", "jur_gay@yahoo.com"},
    - {NULL, NULL, "Wangmo Sherpa", "rinwanshe@yahoo.com"},
    - {N_("Greek"), "el", "Katsaloulis Panayotis", "panayotis@panayotis.com"},
    - {NULL, NULL, "Panos Bouklis", "panos@echidna-band.com"},
    - {N_("Australian English"), "en_AU", "Michael Findlay", "keltoiboy@gmail.com"},
    - {N_("British English"), "en_GB", "Phil Hannent", "phil@hannent.co.uk"},
    - {N_("Canadian English"), "en_CA", "Adam Weinberger", "adamw@gnome.org"},
    - {N_("Esperanto"), "eo", "Stéphane Fillod", "fillods@users.sourceforge.net"},
    - {N_("Spanish"), "es", "Javier Fernández-Sanguino Peña", "jfs@debian.org"},
    - {N_("Argentine Spanish"), "es_AR", "KNTRO", "kntro@msn.com"},
    - {N_("Estonian"), "et", "Ivar Smolin", "okul@linux.ee"},
    - {N_("Basque"), "eu", "Mikel Pascual Aldabaldetreku", "mikel.paskual@gmail.com"},
    - {N_("Persian"), "fa", "Elnaz Sarbar", "elnaz@farsiweb.info"},
    - {NULL, NULL, "Roozbeh Pournader", "roozbeh@farsiweb.info"},
    - {NULL, NULL, "Meelad Zakaria", "meelad@farsiweb.info"},
    - {N_("Finnish"), "fi", "Timo Jyrinki", "timo.jyrinki@iki.fi"},
    - {N_("Irish"), "ga", "Aaron Kearns", "ajkearns6@gmail.com"},
    - {N_("Irish"), "ga", "Kevin Scannell", NULL},
    - {N_("Galician"), "gl", "Mar Castro", "mariamarcp@gmail.com"},
    - {NULL, NULL, "Frco. Javier Rial", "fjrial@cesga.es"},
    - {N_("Gujarati"), "gu", "Ankit Patel", "ankit_patel@users.sf.net"},
    - {NULL, NULL, N_("Gujarati Language Team"), "indianoss-gujarati@lists.sourceforge.net"},
    - {N_("Hebrew"), "he", "Shalom Craimer", "scraimer@gmail.com"},
    - {N_("Hindi"), "hi", "Sangeeta Kumari", "sangeeta_0975@yahoo.com"},
    - {NULL, NULL, "Rajesh Ranjan", "rajeshkajha@yahoo.com"},
    - {N_("Croatian"), "hr", "Sabina Drempetić", "bina91991@googlemail.com"},
    - {N_("Hungarian"), "hu", "Kelemen Gábor", "kelemeng@gnome.hu"},
    - {N_("Indonesian"), "id", "Rai S. Regawa", "raireg@yahoo.com"},
    - {N_("Italian"), "it", "Claudio Satriano", "satriano@gmail.com"},
    - {N_("Japanese"), "ja", "Takayuki Kusano", "AE5T-KSN@asahi-net.or.jp"},
    - {N_("Georgian"), "ka", N_("Ubuntu Georgian Translators"), "alexander.didebulidze@stusta.mhn.de"},
    - {N_("Kazakh"), "kk", "Baurzhan Muftakhidinov", "baurthefirst@gmail.com"},
    - {N_("Khmer"), "km", "Khoem Sokhem", "khoemsokhem@khmeros.info"},
    - {N_("Kannada"), "kn", N_("Kannada Translation team"), "translation@sampada.info"},
    - {N_("Korean"), "ko", "Sushizang", "sushizang@empal.com"},
    - {N_("Kashmiri"), "kas", "Chandrakant Dhutadmal", "cpdhutadmal@yahoo.com"},
    - {N_("Kurdish"), "ku", "Amed Ç. Jiyan", "amedcj@hotmail.com"},
    - {NULL, NULL, "Erdal Ronahi", "erdal.ronahi@gmail.com"},
    - {NULL, NULL, "Rizoyê Xerzî", "rizoxerzi@hotmail.com"},
    - {N_("Kurdish (Sorani)"), "ku_IQ", "Haval A. Ahmed", "haval.abdulkarim@gmail.com"},
    - {N_("Lithuanian"), "lt", "Algimantas Margevičius", "margevicius.algimantas@gmail.com"},
    - {N_("Latvian"), "lv", "Rudolfs Mazurs", "rudolfs.mazurs@gmail.com"},
    - {N_("Latvian"), "lv", "Ingmārs Dīriņš", "melhiors14@gmail.com"},
    - {N_("Maithili"), "mai", "Sangeeta Kumari", "sangeeta_0975@yahoo.com"},
    - {NULL, NULL, "Rajesh Ranjan", "rajeshkajha@yahoo.com"},
    - {N_("Meadow Mari"), "mhr", "David Preece", "davidpreece1@gmail.com"},
    - {N_("Macedonian"), "mk", "Arangel Angov ", "arangel@linux.net.mk"},
    - {NULL, NULL, "Ivana Kirkovska", "ivana.kirkovska@gmail.com"},
    - {NULL, NULL, "Jovan Naumovski", "jovan@lugola.net"},
    - {N_("Malayalam"), "ml", "Ani Peter", "apeter@redhat.com"},
    - {N_("Mongolian"), "mn", "gooyo", NULL},
    - {N_("Marathi"), "mr", "Sandeep Shedmake", "sandeep.shedmake@gmail.com"},
    - {N_("Malay"), "ms_MY", "abuyop", "abuyop@gmail.com"},
    - {N_("Burmese"), "my_MM", "Thura Hlaing", "trhura@gmail.com"},
    - {N_("Bokmål Norwegian"), "nb", "Allan Nordhøy", "epost@anotheragency.no"},
    - {N_("Nepali"), "ne", "Saroj Dhakal", "lotusnagarkot@gmail.com"},
    - {N_("Dutch, Flemish"), "nl", "Gideon van Melle", "translations@gvmelle.com"},
    - {N_("Norwegian Nynorsk"), "nn", "Yngve Spjeld Landro", "l10n@landro.net"},
    - {N_("Occitan"), "oc", "Cédric Valmary", "cvalmary@yahoo.fr"},
    - {N_("Oriya"), "or", "Manoj Kumar Giri", "giri.manojkr@gmail.com"},
    - {N_("Punjabi"), "pa", "Amanpreet Singh Alam", "aalam@users.sf.net"},
    - {N_("Polish"), "pl", "Piotr Drąg", "piotrdrag@gmail.com"},
    - {N_("Portuguese"), "pt", "Paulo Ribeiro", "paulo@diffraction.pt"},
    - {N_("Portuguese-Brazil"), "pt_BR", "Renato Silva", "br.renatosilva@gmail.com"},
    - {N_("Pashto"), "ps", "Kashif Masood", "masudmails@yahoo.com"},
    - {N_("Romanian"), "ro", "Mișu Moldovan", "dumol@gnome.org"},
    - {NULL, NULL, "Andrei Popescu", "andreimpopescu@gmail.com"},
    - {N_("Russian"), "ru", "Антон Самохвалов", "samant.ua@mail.ru"},
    - {N_("Sindhi"), "sd", "Chandrakant Dhutadmal", "cpdhutadmal@yahoo.com"},
    - {N_("Slovak"), "sk", "Jozef Káčer", "quickparser@gmail.com"},
    - {NULL, NULL, "loptosko", "loptosko@gmail.com"},
    - {N_("Slovenian"), "sl", "Martin Srebotnjak", "miles@filmsi.net"},
    - {N_("Albanian"), "sq", "Besnik Bleta", "besnik@programeshqip.org"},
    - {N_("Serbian"), "sr", "Miloš Popović", "gpopac@gmail.com"},
    - {N_("Serbian Latin"), "sr@latin", "Miloš Popović", "gpopac@gmail.com"},
    - {N_("Sinhala"), "si", "Yajith Ajantha Dayarathna", "yajith@gmail.com"},
    - {NULL, NULL, "Danishka Navin", "snavin@redhat.com"},
    - {N_("Swedish"), "sv", "Josef Andersson", "josef.andersson@gmail.com"},
    - {N_("Swahili"), "sw", "Paul Msegeya", "msegeya@gmail.com"},
    - {N_("Tamil"), "ta", "I. Felix", "ifelix25@gmail.com"},
    - {NULL, NULL, "Viveka Nathan K", "vivekanathan@users.sourceforge.net"},
    - {N_("Telugu"), "te", "Krishnababu Krottapalli", "krottapalli@ymail.com"},
    - {N_("Thai"), "th", "Isriya Paireepairit", "markpeak@gmail.com"},
    - {N_("Tatar"), "tt", "ILDAR Valeev", "v_ildar@bk.ru"},
    - {N_("Ukranian"), "uk", "Oleksandr Kovalenko", "alx.kovalenko@gmail.com"},
    - {N_("Urdu"), "ur", "RKVS Raman", "rkvsraman@gmail.com"},
    - {N_("Uzbek"), "uz",
    - /* Translators: This is a person's name. For most languages we recommend
    - not translating it. */
    - N_("Akmal Khushvakov"), "uzbadmin@gmail.com"},
    - {N_("Vietnamese"), "vi", "Nguyễn Vũ Hưng", "vuhung16plus@gmail.com"},
    - {N_("Simplified Chinese"), "zh_CN", "Aron Xu", "happyaron.xu@gmail.com"},
    - {N_("Hong Kong Chinese"), "zh_HK", "Abel Cheung", "abelindsay@gmail.com"},
    - {NULL, NULL, "Ambrose C. Li", "acli@ada.dhs.org"},
    - {NULL, NULL, "Paladin R. Liu", "paladin@ms1.hinet.net"},
    - {N_("Traditional Chinese"), "zh_TW", "Ambrose C. Li", "acli@ada.dhs.org"},
    - {NULL, NULL, "Paladin R. Liu", "paladin@ms1.hinet.net"},
    - {NULL, NULL, NULL, NULL}
    -};
    -
    -
    -static const struct translator past_translators[] = {
    - {N_("Amharic"), "am", "Daniel Yacob", NULL},
    - {N_("Arabic"), "ar", "Mohamed Magdy", NULL},
    - {N_("Bulgarian"), "bg", "Hristo Todorov", NULL},
    - {N_("Bengali"), "bn", "Indranil Das Gupta", NULL},
    - {NULL, NULL, "Tisa Nafisa", NULL},
    - {N_("Catalan"), "ca", "JM Pérez Cáncer", NULL},
    - {NULL, NULL, "Robert Millan", NULL},
    - {N_("Czech"), "cs", "Honza Král", NULL},
    - {NULL, NULL, "Miloslav Trmac", NULL},
    - {N_("Danish"), "da", "Peter Bach", NULL},
    - {NULL, NULL, "Morten Brix Pedersen", NULL},
    - {N_("German"), "de", "Daniel Seifert", NULL},
    - {NULL, NULL, "Karsten Weiss", NULL},
    - {NULL, NULL, "Jochen Kemnade", NULL},
    - {N_("Australian English"), "en_AU", "Peter Lawler", NULL},
    - {N_("British English"), "en_GB", "Luke Ross", NULL},
    - {N_("Spanish"), "es", "JM Pérez Cáncer", NULL},
    - {NULL, NULL, "Nicolás Lichtmaier", NULL},
    - {NULL, NULL, "Amaya Rodrigo", NULL},
    - {NULL, NULL, "Alejandro G Villar", NULL},
    - {N_("Basque"), "eu", "Iñaki Larrañaga Murgoitio", NULL},
    - {NULL, NULL, "Hizkuntza Politikarako Sailburuordetza", NULL},
    - {N_("Finnish"), "fi", "Arto Alakulju", NULL},
    - {NULL, NULL, "Tero Kuusela", NULL},
    - {N_("French"), "fr", "Sébastien François", NULL},
    - {NULL, NULL, "Loïc Jeannin", NULL},
    - {NULL, NULL, "Stéphane Pontier", NULL},
    - {NULL, NULL, "Stéphane Wirtel", NULL},
    - {NULL, NULL, "Éric Boumaour", NULL},
    - {N_("Galician"), "gl", "Ignacio Casal Quinteiro", NULL},
    - {N_("Hebrew"), "he", "Pavel Bibergal", NULL},
    - {N_("Hindi"), "hi", "Ravishankar Shrivastava", NULL},
    - {N_("Hungarian"), "hu", "Zoltan Sutto", NULL},
    - {N_("Armenian"), "hy", "David Avsharyan", NULL},
    - {N_("Italian"), "it", "Salvatore di Maggio", NULL},
    - {N_("Japanese"), "ja", "Takashi Aihana", NULL},
    - {NULL, NULL, "Ryosuke Kutsuna", NULL},
    - {NULL, NULL, "Junichi Uekawa", NULL},
    - {NULL, NULL, "Taku Yasui", NULL},
    - {N_("Georgian"), "ka", "Temuri Doghonadze", NULL},
    - {N_("Korean"), "ko", "Sang-hyun S", NULL},
    - {NULL, NULL, "A Ho-seok Lee", NULL},
    - {NULL, NULL, "Kyeong-uk Son", NULL},
    - {N_("Lao"), "lo", "Anousak Souphavah", NULL},
    - {N_("Lithuanian"), "lt", "Laurynas Biveinis", NULL},
    - {NULL, NULL, "Gediminas Čičinskas", NULL},
    - {NULL, NULL, "Andrius Štikonas", NULL},
    - {N_("Macedonian"), "mk", "Tomislav Markovski", NULL},
    - {N_("Malay"), "ms_MY", "Muhammad Najmi bin Ahmad Zabidi", NULL},
    - {N_("Bokmål Norwegian"), "nb", "Hans Fredrik Nordhaug", NULL},
    - {NULL, NULL, "Hallvard Glad", NULL},
    - {NULL, NULL, "Petter Johan Olsen", NULL},
    - {NULL, NULL, "Espen Stefansen", NULL},
    - {N_("Nepali"), "ne", "Shyam Krishna Bal", NULL},
    - {N_("Dutch, Flemish"), "nl", "Vincent van Adrighem", NULL},
    - {N_("Occitan"), "oc", "Yannig Marchegay", NULL},
    - {N_("Polish"), "pl", "Krzysztof Foltman", NULL},
    - {NULL, NULL, "Paweł Godlewski", NULL},
    - {NULL, NULL, "Piotr Makowski", NULL},
    - {NULL, NULL, "Emil Nowak", NULL},
    - {NULL, NULL, "Przemysław Sułek", NULL},
    - {N_("Portuguese"), "pt", "Duarte Henriques", NULL},
    - {N_("Portuguese-Brazil"), "pt_BR", "Maurício de Lemos Rodrigues Collares Neto", NULL},
    - {N_("Portuguese-Brazil"), "pt_BR", "Rodrigo Luiz Marques Flores", NULL},
    - {N_("Russian"), "ru", "Dmitry Beloglazov", NULL},
    - {NULL, NULL, "Alexandre Prokoudine", NULL},
    - {NULL, NULL, "Sergey Volozhanin", NULL},
    - {N_("Slovak"), "sk", "Daniel Režný", NULL},
    - {NULL, NULL, "Richard Golier", NULL},
    - {NULL, NULL, "helix84", NULL},
    - {N_("Slovenian"), "sl", "Matjaz Horvat", NULL},
    - {N_("Serbian"), "sr", "Danilo Šegan", NULL},
    - {NULL, NULL, "Aleksandar Urosevic", NULL},
    - {N_("Swedish"), "sv", "Peter Hjalmarsson", NULL},
    - {N_("Swedish"), NULL, "Tore Lundqvist", NULL},
    - {NULL, NULL, "Christian Rose", NULL},
    - {N_("Telugu"), "te", "Mr. Subbaramaih", NULL},
    - {N_("Turkish"), "tr", "Serdar Soytetir", NULL},
    - {NULL, "tr", "Ahmet Alp Balkan", NULL},
    - {N_("Vietnamese"), "vi", N_("T.M.Thanh and the Gnome-Vi Team"), NULL},
    - {N_("Simplified Chinese"), "zh_CN", "Hashao", NULL},
    - {NULL, NULL, "Rocky S. Lee", NULL},
    - {NULL, NULL, "Funda Wang", NULL},
    - {N_("Traditional Chinese"), "zh_TW", "Hashao", NULL},
    - {NULL, NULL, "Rocky S. Lee", NULL},
    - {NULL, NULL, NULL, NULL}
    -};
    -
    -static void
    -add_developers(GString *str, const struct developer *list)
    -{
    - for (; list->name != NULL; list++) {
    - if (list->email != NULL) {
    - const gchar *proto = "mailto:";
    - if (strchr(list->email, ':') != NULL)
    - proto = "";
    - g_string_append_printf(str,
    - "<li><a href=\"%s%s\" title=\"%s\">%s</a>%s%s%s</li>",
    - proto,
    - list->email, list->email, _(list->name),
    - list->role ? " (" : "",
    - list->role ? _(list->role) : "",
    - list->role ? ")" : "");
    - } else {
    - g_string_append_printf(str, "<li>%s%s%s%s</li>",
    - _(list->name),
    - list->role ? " (" : "",
    - list->role ? _(list->role) : "",
    - list->role ? ")" : "");
    - }
    - }
    -}
    -
    -static void
    -add_translators(GString *str, const struct translator *list)
    -{
    - for (; list->name != NULL; list++) {
    - if (list->language && list->abbr) {
    - g_string_append_printf(str, "<dt>%s (%s)</dt>",
    - _(list->language), list->abbr);
    - }
    - if (list->email != NULL) {
    - g_string_append_printf(str,
    - "<dd><a href=\"mailto:%s\" title=\"%s\">%s</a></dd>",
    - list->email, list->email,
    - _(list->name));
    - } else {
    - g_string_append_printf(str, "<dd>%s</dd>", _(list->name));
    - }
    - }
    -}
    -
    void
    pidgin_dialogs_destroy_all()
    {
    @@ -512,293 +162,6 @@
    return win;
    }
    -void pidgin_dialogs_about(void)
    -{
    - GString *str;
    - char *tmp;
    - static GtkWidget *about = NULL;
    -
    - if (about != NULL) {
    - gtk_window_present(GTK_WINDOW(about));
    - return;
    - }
    -
    - str = g_string_sized_new(4096);
    -
    - g_string_append_printf(str,
    - "<h2>%s %s</h2>"
    - "<strong>(libpurple %s)<br/>%s</strong>",
    - PIDGIN_NAME, DISPLAY_VERSION,
    - purple_core_get_version(), REVISION);
    -
    - g_string_append_printf(str,
    - _("<p>%s is a messaging client based on libpurple which is capable of "
    - "connecting to multiple messaging services at once. %s is written "
    - "in C using GTK+. %s is released, and may be modified and "
    - "redistributed, under the terms of the GPL version 2 (or later). "
    - "A copy of the GPL is distributed with %s. %s is copyrighted by "
    - "its contributors, a list of whom is also distributed with %s. "
    - "There is no warranty for %s.</p>"), PIDGIN_NAME, PIDGIN_NAME,
    - PIDGIN_NAME, PIDGIN_NAME, PIDGIN_NAME, PIDGIN_NAME, PIDGIN_NAME);
    -
    - g_string_append_printf(str,
    - _("<h3>Helpful Resources</h3>"
    - "<ul>"
    - "<li><a href=\"%s\" title=\"%s\">Website</a></li>"
    - "<li><a href=\"%s\" title=\"%s\">Frequently Asked Questions</a></li>"
    - "<li>IRC Channel: #pidgin on irc.freenode.net</li>"
    - "<li>XMPP MUC: devel@conference.pidgin.im</li>"
    - "</ul>"),
    - PURPLE_WEBSITE, PURPLE_WEBSITE,
    - "https://developer.pidgin.im/wiki/FAQ",
    - "https://developer.pidgin.im/wiki/FAQ");
    -
    - g_string_append(str,
    - "<p><strong>Help for Oracle Employees</strong> is "
    - "available from your normal internal helpdesk or IT department. "
    - "The Pidgin developer and user communities cannot assist you in "
    - "the configuration or use of Pidgin within Oracle, as we know "
    - "nothing of Oracle's infrastructure.</p>");
    -
    - g_string_append_printf(str,
    - _("<p><strong>Help from other Pidgin users</strong> is available "
    - "by e-mailing <a href=\"mailto:%s\">%s</a>.<br/>"
    - "This is a <strong>public</strong> mailing list! "
    - "(<a href=\"%s\" title=\"%s\">archive</a>)<br/>"
    - "We can't help with third-party protocols or plugins!<br/>"
    - "This list's primary language is English. You "
    - "are welcome to post in another language, but the responses may "
    - "be less helpful.</p>"),
    - "support@pidgin.im", "support@pidgin.im",
    - "https://pidgin.im/pipermail/support/",
    - "https://pidgin.im/pipermail/support/");
    -
    - tmp = g_strdup_printf(_("About %s"), PIDGIN_NAME);
    - about = pidgin_build_help_dialog(tmp, "about", str);
    - g_signal_connect(G_OBJECT(about), "destroy", G_CALLBACK(gtk_widget_destroyed), &about);
    - g_free(tmp);
    -}
    -
    -void pidgin_dialogs_buildinfo(void)
    -{
    - GString *str;
    - char *tmp;
    - static GtkWidget *buildinfo = NULL;
    -
    - if (buildinfo != NULL) {
    - gtk_window_present(GTK_WINDOW(buildinfo));
    - return;
    - }
    -
    - str = g_string_sized_new(4096);
    -
    - g_string_append_printf(str,
    - "<h2>%s %s</h2>"
    - "<strong>(libpurple %s)<br/>%s</strong>",
    - PIDGIN_NAME, DISPLAY_VERSION, purple_core_get_version(), REVISION);
    -
    - g_string_append_printf(str, "<h3>%s</h3><dl>", _("Build Information"));
    -
    - /* The following is primarily intended for user/developer interaction and
    - thus ought not be translated */
    -
    -#ifdef CONFIG_ARGS /* win32 build doesn't use configure */
    - g_string_append(str, "<dt>Arguments to <em>./configure</em>:</dt><dd>" CONFIG_ARGS "</dd>");
    -#endif
    -
    -#ifndef _WIN32
    -#ifdef DEBUG
    - g_string_append(str, "<dt>Print debugging messages:</dt><dd>Yes</dd>");
    -#else
    - g_string_append(str, "<dt>Print debugging messages:</dt><dd>No</dd>");
    -#endif
    -#endif
    -
    -#ifdef PURPLE_PLUGINS
    - g_string_append(str, "<dt>Plugins:</dt><dd>Enabled</dd>");
    -#else
    - g_string_append(str, "<dt>Plugins:</dt><dd>Disabled</dd>");
    -#endif
    -
    - g_string_append(str, "<dt>SSL:</dt><dd>SSL support is present.</dd>");
    -
    - g_string_append_printf(str, "<dt>GTK+ Runtime:</dt><dd>%u.%u.%u</dd>"
    - "<dt>GLib Runtime:</dt><dd>%u.%u.%u</dd>",
    - gtk_major_version, gtk_minor_version, gtk_micro_version,
    - glib_major_version, glib_minor_version, glib_micro_version);
    -
    - g_string_append(str, "</dl><h3>Library Support</h3><dl>");
    -
    -#ifdef HAVE_CYRUS_SASL
    - g_string_append_printf(str, "<dt>Cyrus SASL:</dt><dd>Enabled</dd>");
    -#else
    - g_string_append_printf(str, "<dt>Cyrus SASL:</dt><dd>Disabled</dd>");
    -#endif
    -
    -#ifndef _WIN32
    -#ifdef HAVE_DBUS
    - g_string_append_printf(str, "<dt>D-Bus:</dt><dd>Enabled</dd>");
    -#else
    - g_string_append_printf(str, "<dt>D-Bus:</dt><dd>Disabled</dd>");
    -#endif
    -
    -#ifdef HAVE_EVOLUTION_ADDRESSBOOK
    - g_string_append_printf(str, "<dt>Evolution Addressbook:</dt><dd>Enabled</dd>");
    -#else
    - g_string_append_printf(str, "<dt>Evolution Addressbook:</dt><dd>Disabled</dd>");
    -#endif
    -#endif
    -
    -#ifdef HAVE_LIBGADU
    - g_string_append(str, "<dt>Gadu-Gadu library (libgadu):</dt><dd>External</dd>");
    -#else
    - g_string_append(str, "<dt>Gadu-Gadu library (libgadu):</dt><dd>Internal</dd>");
    -#endif
    -
    -#ifdef HAVE_GNUTLS
    - g_string_append(str, "<dt>GnuTLS:</dt><dd>Enabled</dd>");
    -#else
    - g_string_append(str, "<dt>GnuTLS:</dt><dd>Disabled</dd>");
    -#endif
    -
    -#ifdef USE_GSTREAMER
    - tmp = gst_version_string();
    - g_string_append_printf(str, "<dt>GStreamer:</dt><dd>%s</dd>", tmp);
    - g_free(tmp);
    -#else
    - g_string_append(str, "<dt>GStreamer:</dt><dd>Disabled</dd>");
    -#endif
    -
    -#ifndef _WIN32
    -#ifdef ENABLE_MONO
    - g_string_append(str, "<dt>Mono:</dt><dd>Enabled</dd>");
    -#else
    - g_string_append(str, "<dt>Mono:</dt><dd>Disabled</dd>");
    -#endif
    -#endif
    -
    -#ifdef HAVE_NSS
    - g_string_append(str, "<dt>Network Security Services (NSS):</dt><dd>Enabled</dd>");
    -#else
    - g_string_append(str, "<dt>Network Security Services (NSS):</dt><dd>Disabled</dd>");
    -#endif
    -
    -#ifdef USE_IDN
    - g_string_append(str, "<dt>UTF-8 DNS (IDN):</dt><dd>Enabled</dd>");
    -#else
    - g_string_append(str, "<dt>UTF-8 DNS (IDN):</dt><dd>Disabled</dd>");
    -#endif
    -
    -#ifdef USE_VV
    - g_string_append(str, "<dt>Voice and Video:</dt><dd>Enabled</dd>");
    -#else
    - g_string_append(str, "<dt>Voice and Video:</dt><dd>Disabled</dd>");
    -#endif
    -
    -#ifndef _WIN32
    -#ifdef USE_SCREENSAVER
    - g_string_append(str, "<dt>XScreenSaver:</dt><dd>Enabled</dd>");
    -#else
    - g_string_append(str, "<dt>XScreenSaver:</dt><dd>Disabled</dd>");
    -#endif
    -
    -#ifdef LIBZEPHYR_EXT
    - g_string_append(str, "<dt>Zephyr library (libzephyr):</dt><dd>External</dd>");
    -#else
    - g_string_append(str, "<dt>Zephyr library (libzephyr):</dt><dd>Internal</dd>");
    -#endif
    -
    -#ifdef ZEPHYR_USES_KERBEROS
    - g_string_append(str, "<dt>Zephyr uses Kerberos:</dt><dd>Yes</dd>");
    -#else
    - g_string_append(str, "<dt>Zephyr uses Kerberos:</dt><dd>No</dd>");
    -#endif
    -#endif
    -
    - g_string_append(str, "</dl>");
    -
    - /* End of not to be translated section */
    -
    - tmp = g_strdup_printf(_("%s Build Information"), PIDGIN_NAME);
    - buildinfo = pidgin_build_help_dialog(tmp, "buildinfo", str);
    - g_signal_connect(G_OBJECT(buildinfo), "destroy", G_CALLBACK(gtk_widget_destroyed), &buildinfo);
    - g_free(tmp);
    -}
    -
    -void pidgin_dialogs_developers(void)
    -{
    - GString *str;
    - char *tmp;
    - static GtkWidget *developer_info = NULL;
    -
    - if (developer_info != NULL) {
    - gtk_window_present(GTK_WINDOW(developer_info));
    - return;
    - }
    -
    - str = g_string_sized_new(4096);
    -
    - /* Current Developers */
    - g_string_append_printf(str, "<h3>%s</h3><ul>",
    - _("Current Developers"));
    - add_developers(str, developers);
    - g_string_append(str, "</ul>");
    -
    - /* Crazy Patch Writers */
    - g_string_append_printf(str, "<h3>%s</h3><ul>",
    - _("Crazy Patch Writers"));
    - add_developers(str, patch_writers);
    - g_string_append(str, "</ul>");
    -
    - /* Retired Developers */
    - g_string_append_printf(str, "<h3>%s</h3><ul>",
    - _("Retired Developers"));
    - add_developers(str, retired_developers);
    - g_string_append(str, "</ul>");
    -
    - /* Retired Crazy Patch Writers */
    - g_string_append_printf(str, "<h3>%s</h3><ul>",
    - _("Retired Crazy Patch Writers"));
    - add_developers(str, retired_patch_writers);
    - g_string_append(str, "</ul>");
    -
    - tmp = g_strdup_printf(_("%s Developer Information"), PIDGIN_NAME);
    - developer_info = pidgin_build_help_dialog(tmp, "developer_info", str);
    - g_signal_connect(G_OBJECT(developer_info), "destroy", G_CALLBACK(gtk_widget_destroyed), &developer_info);
    - g_free(tmp);
    -}
    -
    -void pidgin_dialogs_translators(void)
    -{
    - GString *str;
    - char *tmp;
    - static GtkWidget *translator_info = NULL;
    -
    - if (translator_info != NULL) {
    - gtk_window_present(GTK_WINDOW(translator_info));
    - return;
    - }
    -
    - str = g_string_sized_new(4096);
    -
    - /* Current Translators */
    - g_string_append_printf(str, "<h3>%s</h3><dl>",
    - _("Current Translators"));
    - add_translators(str, translators);
    - g_string_append(str, "</dl>");
    -
    - /* Past Translators */
    - g_string_append_printf(str, "<h3>%s</h3><dl>",
    - _("Past Translators"));
    - add_translators(str, past_translators);
    - g_string_append(str, "</dl>");
    -
    - tmp = g_strdup_printf(_("%s Translator Information"), PIDGIN_NAME);
    - translator_info = pidgin_build_help_dialog(tmp, "translator_info", str);
    - g_signal_connect(G_OBJECT(translator_info), "destroy", G_CALLBACK(gtk_widget_destroyed), &translator_info);
    - g_free(tmp);
    -}
    -
    void pidgin_dialogs_plugins_info(void)
    {
    GString *str;
    --- a/pidgin/gtkdialogs.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkdialogs.h Sun Oct 08 20:44:26 2017 +0300
    @@ -37,10 +37,6 @@
    /* Functions in gtkdialogs.c (these should actually stay in this file) */
    void pidgin_dialogs_destroy_all(void);
    -void pidgin_dialogs_about(void);
    -void pidgin_dialogs_buildinfo(void);
    -void pidgin_dialogs_developers(void);
    -void pidgin_dialogs_translators(void);
    void pidgin_dialogs_plugins_info(void);
    void pidgin_dialogs_im(void);
    void pidgin_dialogs_im_with_user(PurpleAccount *, const char *);
    --- a/pidgin/gtkdocklet.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkdocklet.c Sun Oct 08 20:44:26 2017 +0300
    @@ -358,7 +358,7 @@
    purple_debug(PURPLE_DEBUG_INFO, "docklet", "menu leave-notify-event\n");
    /* Add some slop so that the menu doesn't annoyingly disappear when mousing around */
    if (hide_docklet_timer == 0) {
    - hide_docklet_timer = purple_timeout_add(500,
    + hide_docklet_timer = g_timeout_add(500,
    hide_docklet_menu, menu);
    }
    } else if (event->type == GDK_ENTER_NOTIFY && event->detail == GDK_NOTIFY_ANCESTOR) {
    @@ -366,7 +366,7 @@
    if (hide_docklet_timer != 0) {
    /* Cancel the hiding if we reenter */
    - purple_timeout_remove(hide_docklet_timer);
    + g_source_remove(hide_docklet_timer);
    hide_docklet_timer = 0;
    }
    }
    @@ -681,7 +681,6 @@
    {
    static GtkWidget *menu = NULL;
    GtkWidget *menuitem;
    - GtkMenuPositionFunc pos_func = gtk_status_icon_position_menu;
    if (menu) {
    gtk_widget_destroy(menu);
    @@ -761,12 +760,9 @@
    #ifdef _WIN32
    g_signal_connect(menu, "leave-notify-event", G_CALLBACK(docklet_menu_leave_enter), NULL);
    g_signal_connect(menu, "enter-notify-event", G_CALLBACK(docklet_menu_leave_enter), NULL);
    - pos_func = NULL;
    #endif
    gtk_widget_show_all(menu);
    - gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
    - pos_func,
    - docklet, 0, gtk_get_current_event_time());
    + gtk_menu_popup_at_pointer(GTK_MENU(menu), NULL);
    }
    static void
    @@ -840,7 +836,7 @@
    docklet_gtk_embedded_cb(GtkWidget *widget, gpointer data)
    {
    if (embed_timeout) {
    - purple_timeout_remove(embed_timeout);
    + g_source_remove(embed_timeout);
    embed_timeout = 0;
    }
    @@ -885,7 +881,7 @@
    pidgin_docklet_remove();
    if (embed_timeout) {
    - purple_timeout_remove(embed_timeout);
    + g_source_remove(embed_timeout);
    embed_timeout = 0;
    }
    @@ -933,9 +929,9 @@
    pidgin_docklet_embedded();
    #ifndef _WIN32
    if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded")) {
    - embed_timeout = purple_timeout_add_seconds(LONG_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL);
    + embed_timeout = g_timeout_add_seconds(LONG_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL);
    } else {
    - embed_timeout = purple_timeout_add_seconds(SHORT_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL);
    + embed_timeout = g_timeout_add_seconds(SHORT_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL);
    }
    #endif
    }
    --- a/pidgin/gtkidle.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkidle.c Sun Oct 08 20:44:26 2017 +0300
    @@ -26,50 +26,48 @@
    #ifdef HAVE_IOKIT
    # include <CoreFoundation/CoreFoundation.h>
    # include <IOKit/IOKitLib.h>
    -#else
    -# ifdef USE_SCREENSAVER
    -# ifdef _WIN32
    -# include "gtkwin32dep.h"
    -# else
    - /* We're on X11 and not MacOS X with IOKit. */
    -# include <X11/Xlib.h>
    -# include <X11/Xutil.h>
    -# include <X11/extensions/scrnsaver.h>
    -# include <gdk/gdkx.h>
    -# endif /* !_WIN32 */
    -# endif /* USE_SCREENSAVER */
    -#endif /* !HAVE_IOKIT */
    +#elif defined (_WIN32)
    +# include "win32/gtkwin32dep.h"
    +#endif
    #include "idle.h"
    +#if !defined(HAVE_IOKIT) && !defined(_WIN32)
    +typedef struct {
    + gchar *bus_name;
    + gchar *object_path;
    + gchar *iface_name;
    +} PidginDBusScreenSaverInfo;
    +
    +static const PidginDBusScreenSaverInfo screensavers[] = {
    + {
    + "org.freedesktop.ScreenSaver",
    + "/org/freedesktop/ScreenSaver",
    + "org.freedesktop.ScreenSaver"
    + }, {
    + "org.gnome.ScreenSaver",
    + "/org/gnome/ScreenSaver",
    + "org.gnome.ScreenSaver"
    + }, {
    + "org.kde.ScreenSaver",
    + "/org/kde/ScreenSaver",
    + "org.kde.ScreenSaver"
    + },
    +};
    +#endif /* !HAVE_IOKIT && !_WIN32 */
    +
    /*
    * pidgin_get_time_idle:
    *
    * Get the number of seconds the user has been idle. In Unix-world
    - * this is based on the X Windows usage. In MS Windows this is
    - * based on keyboard/mouse usage information obtained from the OS.
    + * this is based on the DBus ScreenSaver interfaces. In MS Windows this
    + * is based on keyboard/mouse usage information obtained from the OS.
    * In MacOS X, this is based on keyboard/mouse usage information
    * obtained from the OS, if configure detected IOKit. Otherwise,
    - * MacOS X is handled as a case of X Windows.
    - *
    - * In Debian bug #271639, jwz says:
    - *
    - * Purple should simply ask xscreensaver how long the user has been idle:
    - * % xscreensaver-command -time
    - * XScreenSaver 4.18: screen blanked since Tue Sep 14 14:10:45 2004
    - *
    - * Or you can monitor the _SCREENSAVER_STATUS property on root window #0.
    - * Element 0 is the status (0, BLANK, LOCK), element 1 is the time_t since
    - * the last state change, and subsequent elements are which hack is running
    - * on the various screens:
    - * % xprop -f _SCREENSAVER_STATUS 32ac -root _SCREENSAVER_STATUS
    - * _SCREENSAVER_STATUS(INTEGER) = BLANK, 1095196626, 10, 237
    - *
    - * See watch() in xscreensaver/driver/xscreensaver-command.c.
    + * MacOS X is handled as a case of Unix.
    *
    * Returns: The number of seconds the user has been idle.
    */
    -#if defined(USE_SCREENSAVER) || defined(HAVE_IOKIT)
    static time_t
    pidgin_get_time_idle(void)
    {
    @@ -101,40 +99,84 @@
    /* Query Windows */
    return (GetTickCount() - winpidgin_get_lastactive()) / 1000;
    # else
    - /* We're on X11 and not MacOS X with IOKit. */
    + static guint idx = 0;
    + GApplication *app;
    + GDBusConnection *conn;
    + GVariant *reply = NULL;
    + guint32 active_time = 0;
    + GError *error = NULL;
    +
    + app = g_application_get_default();
    +
    + if (app == NULL) {
    + purple_debug_error("gtkidle",
    + "Unable to retrieve GApplication");
    + return 0;
    + }
    +
    + conn = g_application_get_dbus_connection(app);
    - /* Query xscreensaver */
    - static XScreenSaverInfo *mit_info = NULL;
    - static int has_extension = -1;
    - int event_base, error_base;
    + if (conn == NULL) {
    + purple_debug_misc("gtkidle",
    + "GApplication lacking DBus connection. "
    + "Skip checking ScreenSaver interface");
    + return 0;
    + }
    - if (has_extension == -1)
    - has_extension = XScreenSaverQueryExtension(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()),
    - &event_base, &error_base);
    + for (; idx < G_N_ELEMENTS(screensavers); ++idx) {
    + const PidginDBusScreenSaverInfo *info = &screensavers[idx];
    +
    + reply = g_dbus_connection_call_sync(conn,
    + info->bus_name, info->object_path,
    + info->iface_name, "GetActiveTime",
    + NULL, G_VARIANT_TYPE("(u)"),
    + G_DBUS_CALL_FLAGS_NO_AUTO_START, 1000,
    + NULL, &error);
    - if (has_extension)
    - {
    - if (mit_info == NULL)
    - mit_info = XScreenSaverAllocInfo();
    + if (reply != NULL) {
    + break;
    + }
    - XScreenSaverQueryInfo(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()),
    - GDK_ROOT_WINDOW(), mit_info);
    - return (mit_info->idle) / 1000;
    + if (g_error_matches(error, G_DBUS_ERROR,
    + G_DBUS_ERROR_NOT_SUPPORTED)) {
    + purple_debug_info("gtkidle",
    + "Querying idle time on '%s' "
    + "unsupported. Trying the next one",
    + info->bus_name);
    + } else if (g_error_matches(error, G_DBUS_ERROR,
    + G_DBUS_ERROR_NAME_HAS_NO_OWNER)) {
    + purple_debug_info("gtkidle",
    + "Querying idle time on '%s' "
    + "not found. Trying the next one",
    + info->bus_name);
    + } else {
    + purple_debug_error("gtkidle",
    + "Querying idle time on '%s' "
    + "error: %s", info->bus_name,
    + error->message);
    + }
    +
    + g_clear_error(&error);
    }
    - else
    +
    + if (reply == NULL) {
    + purple_debug_warning("gtkidle",
    + "Failed to query ScreenSaver active time: "
    + "No working ScreenSaver interfaces");
    return 0;
    + }
    +
    + g_variant_get(reply, "(u)", &active_time);
    + g_variant_unref(reply);
    +
    + return active_time;
    # endif /* !_WIN32 */
    # endif /* !HAVE_IOKIT */
    }
    -#endif /* USE_SCREENSAVER || HAVE_IOKIT */
    static PurpleIdleUiOps ui_ops =
    {
    -#if defined(USE_SCREENSAVER) || defined(HAVE_IOKIT)
    pidgin_get_time_idle,
    -#else
    - NULL,
    -#endif /* USE_SCREENSAVER || HAVE_IOKIT */
    NULL,
    NULL,
    NULL,
    --- a/pidgin/gtklog.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtklog.c Sun Oct 08 20:44:26 2017 +0300
    @@ -108,12 +108,14 @@
    gtk_tree_path_free(path);
    }
    -static const char *log_get_date(PurpleLog *log)
    +static gchar *log_get_date(PurpleLog *log)
    {
    - if (log->tm)
    - return purple_date_format_full(log->tm);
    - else
    - return purple_date_format_full(localtime(&log->time));
    + GDateTime *dt;
    + gchar *ret;
    + dt = g_date_time_to_local(log->time);
    + ret = g_date_time_format(dt, "%c");
    + g_date_time_unref(dt);
    + return ret;
    }
    static void search_cb(GtkWidget *button, PidginLogViewer *lv)
    @@ -152,11 +154,13 @@
    if (read && *read && purple_strcasestr(read, search_term)) {
    GtkTreeIter iter;
    PurpleLog *log = logs->data;
    + gchar *log_date = log_get_date(log);
    gtk_tree_store_append (lv->treestore, &iter, NULL);
    gtk_tree_store_set(lv->treestore, &iter,
    - 0, log_get_date(log),
    + 0, log_date,
    1, log, -1);
    + g_free(log_date);
    }
    g_free(read);
    }
    @@ -270,7 +274,8 @@
    {
    PidginLogViewer *lv = data[0];
    PurpleLog *log = data[1];
    - const char *time = log_get_date(log);
    + GtkTreeIter *iter = data[2];
    + gchar *time = log_get_date(log);
    const char *name;
    char *tmp;
    gpointer *data2;
    @@ -302,8 +307,11 @@
    tmp = g_strdup_printf(_("Are you sure you want to permanently delete the system log "
    "which started at %s?"), time);
    }
    - else
    + else {
    + g_free(time);
    + g_free(iter);
    g_return_if_reached();
    + }
    /* The only way to free data in all cases is to tie it to the menuitem with
    * g_object_set_data_full(). But, since we need to get some data down to
    @@ -312,68 +320,73 @@
    * either way. */
    data2 = g_new(gpointer, 3);
    data2[0] = lv->treestore;
    - data2[1] = data[3]; /* iter */
    + data2[1] = iter;
    data2[2] = log;
    purple_request_action(lv, NULL, _("Delete Log?"), tmp, 0,
    NULL,
    data2, 2,
    _("Delete"), delete_log_cb,
    _("Cancel"), delete_log_cleanup_cb);
    + g_free(time);
    g_free(tmp);
    }
    -static void log_show_popup_menu(GtkWidget *treeview, GdkEventButton *event, gpointer *data)
    +static GtkWidget *
    +log_create_popup_menu(GtkWidget *treeview, PidginLogViewer *lv, GtkTreeIter *iter)
    {
    - GtkWidget *menu = gtk_menu_new();
    - GtkWidget *menuitem = gtk_menu_item_new_with_label(_("Delete Log..."));
    + GValue val;
    + PurpleLog *log;
    + GtkWidget *menu;
    + GtkWidget *menuitem;
    - if (!purple_log_is_deletable((PurpleLog *)data[1]))
    - gtk_widget_set_sensitive(menuitem, FALSE);
    + val.g_type = 0;
    + gtk_tree_model_get_value(GTK_TREE_MODEL(lv->treestore), iter, 1, &val);
    + log = g_value_get_pointer(&val);
    + if (log == NULL) {
    + g_free(iter);
    + return NULL;
    + }
    +
    + menu = gtk_menu_new();
    + menuitem = gtk_menu_item_new_with_label(_("Delete Log..."));
    - g_signal_connect(menuitem, "activate", G_CALLBACK(log_delete_log_cb), data);
    - g_object_set_data_full(G_OBJECT(menuitem), "log-viewer-data", data, g_free);
    + if (purple_log_is_deletable(log)) {
    + gpointer *data = g_new(gpointer, 3);
    + data[0] = lv;
    + data[1] = log;
    + data[2] = iter;
    +
    + g_signal_connect(menuitem, "activate", G_CALLBACK(log_delete_log_cb), data);
    + g_object_set_data_full(G_OBJECT(menuitem), "log-viewer-data", data, g_free);
    + } else {
    + gtk_widget_set_sensitive(menuitem, FALSE);
    + }
    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
    gtk_widget_show_all(menu);
    - gtk_menu_popup(GTK_MENU(menu), NULL, NULL, (GtkMenuPositionFunc)data[2], NULL,
    - (event != NULL) ? event->button : 0,
    - gdk_event_get_time((GdkEvent *)event));
    + return menu;
    }
    static gboolean log_button_press_cb(GtkWidget *treeview, GdkEventButton *event, PidginLogViewer *lv)
    {
    - if (event->type == GDK_BUTTON_PRESS && event->button == 3)
    - {
    + if (gdk_event_triggers_context_menu((GdkEvent *)event)) {
    GtkTreePath *path;
    GtkTreeIter *iter;
    - GValue val;
    - PurpleLog *log;
    - gpointer *data;
    + GtkWidget *menu;
    if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview), event->x, event->y, &path, NULL, NULL, NULL))
    return FALSE;
    iter = g_new(GtkTreeIter, 1);
    gtk_tree_model_get_iter(GTK_TREE_MODEL(lv->treestore), iter, path);
    - val.g_type = 0;
    - gtk_tree_model_get_value(GTK_TREE_MODEL(lv->treestore), iter, 1, &val);
    gtk_tree_path_free(path);
    - log = g_value_get_pointer(&val);
    -
    - if (log == NULL)
    - {
    - g_free(iter);
    + menu = log_create_popup_menu(treeview, lv, iter);
    + if (menu) {
    + gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
    + return TRUE;
    + } else {
    return FALSE;
    }
    -
    - data = g_new(gpointer, 4);
    - data[0] = lv;
    - data[1] = log;
    - data[2] = NULL;
    - data[3] = iter;
    -
    - log_show_popup_menu(treeview, event, data);
    - return TRUE;
    }
    return FALSE;
    @@ -383,34 +396,22 @@
    {
    GtkTreeSelection *sel;
    GtkTreeIter *iter;
    - GValue val;
    - PurpleLog *log;
    - gpointer *data;
    + GtkWidget *menu;
    iter = g_new(GtkTreeIter, 1);
    sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(lv->treeview));
    - if (!gtk_tree_selection_get_selected(sel, NULL, iter))
    - {
    + if (!gtk_tree_selection_get_selected(sel, NULL, iter)) {
    + g_free(iter);
    return FALSE;
    }
    - val.g_type = 0;
    - gtk_tree_model_get_value(GTK_TREE_MODEL(lv->treestore),
    - iter, NODE_COLUMN, &val);
    -
    - log = g_value_get_pointer(&val);
    -
    - if (log == NULL)
    + menu = log_create_popup_menu(treeview, lv, iter);
    + if (menu) {
    + pidgin_menu_popup_at_treeview_selection(menu, treeview);
    + return TRUE;
    + } else {
    return FALSE;
    -
    - data = g_new(gpointer, 4);
    - data[0] = lv;
    - data[1] = log;
    - data[2] = pidgin_treeview_popup_menu_position_func;
    - data[3] = iter;
    -
    - log_show_popup_menu(treeview, NULL, data);
    - return TRUE;
    + }
    }
    static gboolean search_find_cb(gpointer data)
    @@ -444,15 +445,17 @@
    pidgin_set_cursor(viewer->window, GDK_WATCH);
    if (log->type != PURPLE_LOG_SYSTEM) {
    + gchar *log_date = log_get_date(log);
    char *title;
    if (log->type == PURPLE_LOG_CHAT)
    title = g_strdup_printf(_("<span size='larger' weight='bold'>Conversation in %s on %s</span>"),
    - log->name, log_get_date(log));
    + log->name, log_date);
    else
    title = g_strdup_printf(_("<span size='larger' weight='bold'>Conversation with %s on %s</span>"),
    - log->name, log_get_date(log));
    + log->name, log_date);
    gtk_label_set_markup(viewer->label, title);
    + g_free(log_date);
    g_free(title);
    }
    @@ -492,19 +495,20 @@
    /* Logs are made from trees in real life.
    This is a tree made from logs */
    {
    - const char *month;
    + gchar *month;
    char prev_top_month[30] = "";
    GtkTreeIter toplevel, child;
    GList *logs = lv->logs;
    while (logs != NULL) {
    PurpleLog *log = logs->data;
    + GDateTime *dt;
    + gchar *log_date;
    - month = purple_utf8_strftime(_("%B %Y"),
    - log->tm ? log->tm : localtime(&log->time));
    + dt = g_date_time_to_local(log->time);
    + month = g_date_time_format(dt, _("%B %Y"));
    - if (!purple_strequal(month, prev_top_month))
    - {
    + if (!purple_strequal(month, prev_top_month)) {
    /* top level */
    gtk_tree_store_append(lv->treestore, &toplevel, NULL);
    gtk_tree_store_set(lv->treestore, &toplevel, 0, month, 1, NULL, -1);
    @@ -513,12 +517,16 @@
    }
    /* sub */
    + log_date = g_date_time_format(dt, "%c");
    gtk_tree_store_append(lv->treestore, &child, &toplevel);
    gtk_tree_store_set(lv->treestore, &child,
    - 0, log_get_date(log),
    + 0, log_date,
    1, log,
    -1);
    + g_free(log_date);
    + g_free(month);
    + g_date_time_unref(dt);
    logs = logs->next;
    }
    }
    --- a/pidgin/gtkmedia.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkmedia.c Sun Oct 08 20:44:26 2017 +0300
    @@ -72,12 +72,12 @@
    struct _PidginMediaClass
    {
    - GtkWindowClass parent_class;
    + GtkApplicationWindowClass parent_class;
    };
    struct _PidginMedia
    {
    - GtkWindow parent;
    + GtkApplicationWindow parent;
    PidginMediaPrivate *priv;
    };
    @@ -87,7 +87,7 @@
    gchar *screenname;
    gulong level_handler_id;
    - GtkUIManager *ui;
    + GtkBuilder *ui;
    GtkWidget *menubar;
    GtkWidget *statusbar;
    @@ -155,7 +155,8 @@
    (GInstanceInitFunc) pidgin_media_init,
    NULL
    };
    - type = g_type_register_static(GTK_TYPE_WINDOW, "PidginMedia", &info, 0);
    + type = g_type_register_static(GTK_TYPE_APPLICATION_WINDOW,
    + "PidginMedia", &info, 0);
    }
    return type;
    }
    @@ -190,30 +191,55 @@
    }
    static void
    -pidgin_media_hold_toggled(GtkToggleButton *toggle, PidginMedia *media)
    +pidgin_media_hangup_activate_cb(GSimpleAction *action, GVariant *parameter,
    + gpointer user_data)
    {
    + PidginMedia *media = PIDGIN_MEDIA(user_data);
    +
    purple_media_stream_info(media->priv->media,
    - gtk_toggle_button_get_active(toggle) ?
    + PURPLE_MEDIA_INFO_HANGUP, NULL, NULL, TRUE);
    +}
    +
    +static void
    +pidgin_media_hold_change_state_cb(GSimpleAction *action, GVariant *value,
    + gpointer user_data)
    +{
    + PidginMedia *media = PIDGIN_MEDIA(user_data);
    +
    + purple_media_stream_info(media->priv->media,
    + g_variant_get_boolean(value) ?
    PURPLE_MEDIA_INFO_HOLD : PURPLE_MEDIA_INFO_UNHOLD,
    NULL, NULL, TRUE);
    +
    + g_simple_action_set_state(action, value);
    }
    static void
    -pidgin_media_mute_toggled(GtkToggleButton *toggle, PidginMedia *media)
    +pidgin_media_mute_change_state_cb(GSimpleAction *action, GVariant *value,
    + gpointer user_data)
    {
    + PidginMedia *media = PIDGIN_MEDIA(user_data);
    +
    purple_media_stream_info(media->priv->media,
    - gtk_toggle_button_get_active(toggle) ?
    + g_variant_get_boolean(value) ?
    PURPLE_MEDIA_INFO_MUTE : PURPLE_MEDIA_INFO_UNMUTE,
    NULL, NULL, TRUE);
    +
    + g_simple_action_set_state(action, value);
    }
    static void
    -pidgin_media_pause_toggled(GtkToggleButton *toggle, PidginMedia *media)
    +pidgin_media_pause_change_state_cb(GSimpleAction *action, GVariant *value,
    + gpointer user_data)
    {
    + PidginMedia *media = PIDGIN_MEDIA(user_data);
    +
    purple_media_stream_info(media->priv->media,
    - gtk_toggle_button_get_active(toggle) ?
    + g_variant_get_boolean(value) ?
    PURPLE_MEDIA_INFO_PAUSE : PURPLE_MEDIA_INFO_UNPAUSE,
    NULL, NULL, TRUE);
    +
    + g_simple_action_set_state(action, value);
    }
    static gboolean
    @@ -221,8 +247,8 @@
    GdkEvent *event, PidginMedia *media)
    {
    if (media->priv->media)
    - purple_media_stream_info(media->priv->media,
    - PURPLE_MEDIA_INFO_HANGUP, NULL, NULL, TRUE);
    + g_action_group_activate_action(G_ACTION_GROUP(media),
    + "Hangup", NULL);
    return FALSE;
    }
    @@ -262,61 +288,52 @@
    }
    #endif
    -static void
    -menu_hangup(GtkAction *action, gpointer data)
    -{
    - PidginMedia *gtkmedia = PIDGIN_MEDIA(data);
    - purple_media_stream_info(gtkmedia->priv->media,
    - PURPLE_MEDIA_INFO_HANGUP, NULL, NULL, TRUE);
    -}
    -
    -static const GtkActionEntry menu_entries[] = {
    - { "MediaMenu", NULL, N_("_Media"), NULL, NULL, NULL },
    - { "Hangup", NULL, N_("_Hangup"), NULL, NULL, G_CALLBACK(menu_hangup) },
    +static const GActionEntry media_action_entries[] = {
    + { "Hangup", pidgin_media_hangup_activate_cb },
    + { "Hold", NULL, NULL, "false", pidgin_media_hold_change_state_cb },
    + { "Mute", NULL, NULL, "false", pidgin_media_mute_change_state_cb },
    + { "Pause", NULL, NULL, "false", pidgin_media_pause_change_state_cb },
    };
    -static const char *media_menu =
    -"<ui>"
    - "<menubar name='Media'>"
    - "<menu action='MediaMenu'>"
    - "<menuitem action='Hangup'/>"
    - "</menu>"
    - "</menubar>"
    -"</ui>";
    +static const gchar *media_menu =
    +"<interface>"
    + "<menu id='MediaMenu'>"
    + "<submenu>"
    + "<attribute name='label' translatable='yes'>_Media</attribute>"
    + "<section>"
    + "<item>"
    + "<attribute name='label' translatable='yes'>_Hangup</attribute>"
    + "<attribute name='action'>win.Hangup</attribute>"
    + "</item>"
    + "</section>"
    + "</submenu>"
    + "</menu>"
    +"</interface>";
    static GtkWidget *
    setup_menubar(PidginMedia *window)
    {
    - GtkActionGroup *action_group;
    GError *error;
    - GtkAccelGroup *accel_group;
    GtkWidget *menu;
    - action_group = gtk_action_group_new("MediaActions");
    + window->priv->ui = gtk_builder_new();
    +
    #ifdef ENABLE_NLS
    - gtk_action_group_set_translation_domain(action_group,
    - PACKAGE);
    + gtk_builder_set_translation_domain(window->priv->ui, PACKAGE);
    #endif
    - gtk_action_group_add_actions(action_group,
    - menu_entries,
    - G_N_ELEMENTS(menu_entries),
    - GTK_WINDOW(window));
    -
    - window->priv->ui = gtk_ui_manager_new();
    - gtk_ui_manager_insert_action_group(window->priv->ui, action_group, 0);
    -
    - accel_group = gtk_ui_manager_get_accel_group(window->priv->ui);
    - gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
    error = NULL;
    - if (!gtk_ui_manager_add_ui_from_string(window->priv->ui, media_menu, -1, &error))
    + if (!gtk_builder_add_from_string(window->priv->ui, media_menu, -1,
    + &error))
    {
    g_message("building menus failed: %s", error->message);
    g_error_free(error);
    exit(EXIT_FAILURE);
    }
    - menu = gtk_ui_manager_get_widget(window->priv->ui, "/Media");
    + menu = gtk_menu_bar_new_from_model(G_MENU_MODEL(
    + gtk_builder_get_object(window->priv->ui,
    + "MediaMenu")));
    gtk_widget_show(menu);
    return menu;
    @@ -332,6 +349,10 @@
    XSetErrorHandler(pidgin_x_error_handler);
    #endif
    + g_action_map_add_action_entries(G_ACTION_MAP(media),
    + media_action_entries,
    + G_N_ELEMENTS(media_action_entries), media);
    +
    vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    gtk_container_add(GTK_CONTAINER(media), vbox);
    @@ -857,7 +878,7 @@
    GtkWidget *grid = gtk_grid_new();
    GtkWidget *button;
    gint index = 0;
    - GtkWindow *win = &gtkmedia->parent;
    + GtkApplicationWindow *win = &gtkmedia->parent;
    gtk_grid_set_row_homogeneous(GTK_GRID(grid), TRUE);
    gtk_grid_set_column_homogeneous(GTK_GRID(grid), TRUE);
    @@ -922,9 +943,9 @@
    gtk_box_pack_end(GTK_BOX(button_widget), gtkmedia->priv->hold,
    FALSE, FALSE, 0);
    gtk_widget_show(gtkmedia->priv->hold);
    - g_signal_connect(gtkmedia->priv->hold, "toggled",
    - G_CALLBACK(pidgin_media_hold_toggled),
    - gtkmedia);
    + gtk_actionable_set_action_name(
    + GTK_ACTIONABLE(gtkmedia->priv->hold),
    + "win.Hold");
    } else {
    send_widget = gtkmedia->priv->send_widget;
    button_widget = gtkmedia->priv->button_widget;
    @@ -989,9 +1010,9 @@
    gtk_box_pack_end(GTK_BOX(button_widget), gtkmedia->priv->pause,
    FALSE, FALSE, 0);
    gtk_widget_show(gtkmedia->priv->pause);
    - g_signal_connect(gtkmedia->priv->pause, "toggled",
    - G_CALLBACK(pidgin_media_pause_toggled),
    - gtkmedia);
    + gtk_actionable_set_action_name(
    + GTK_ACTIONABLE(gtkmedia->priv->pause),
    + "win.Pause");
    gtkmedia->priv->local_video = local_video;
    }
    @@ -1007,9 +1028,9 @@
    gtk_box_pack_end(GTK_BOX(button_widget), gtkmedia->priv->mute,
    FALSE, FALSE, 0);
    gtk_widget_show(gtkmedia->priv->mute);
    - g_signal_connect(gtkmedia->priv->mute, "toggled",
    - G_CALLBACK(pidgin_media_mute_toggled),
    - gtkmedia);
    + gtk_actionable_set_action_name(
    + GTK_ACTIONABLE(gtkmedia->priv->mute),
    + "win.Mute");
    gtk_box_pack_end(GTK_BOX(recv_widget),
    pidgin_media_add_audio_widget(gtkmedia,
    --- a/pidgin/gtknotify.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtknotify.c Sun Oct 08 20:44:26 2017 +0300
    @@ -1064,7 +1064,6 @@
    /* Setup the treeview */
    treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
    g_object_unref(G_OBJECT(model));
    - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
    gtk_widget_set_size_request(treeview, 500, 400);
    gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)),
    GTK_SELECTION_SINGLE);
    @@ -1620,8 +1619,6 @@
    spec_dialog->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
    g_object_unref(G_OBJECT(model));
    - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(spec_dialog->treeview), TRUE);
    -
    if (type == PIDGIN_NOTIFY_MAIL) {
    gtk_window_set_title(GTK_WINDOW(dialog), _("New Mail"));
    gtk_window_set_role(GTK_WINDOW(dialog), "new_mail_detailed");
    --- a/pidgin/gtkplugin.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkplugin.c Sun Oct 08 20:44:26 2017 +0300
    @@ -994,8 +994,6 @@
    event_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(ls));
    - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(event_view), TRUE);
    -
    g_signal_connect(G_OBJECT(event_view), "row-activated",
    G_CALLBACK(show_plugin_prefs_cb), plugin_dialog);
    --- a/pidgin/gtkpounce.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkpounce.c Sun Oct 08 20:44:26 2017 +0300
    @@ -1187,7 +1187,7 @@
    gtk_tree_path_free(path);
    gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, POUNCES_MANAGER_COLUMN_POUNCE, &pounce, -1);
    - if ((pounce != NULL) && (event->button == 1) &&
    + if ((pounce != NULL) && (event->button == GDK_BUTTON_PRIMARY) &&
    (event->type == GDK_2BUTTON_PRESS))
    {
    pidgin_pounce_editor_show(NULL, NULL, pounce);
    @@ -1254,7 +1254,6 @@
    treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model));
    g_object_unref(G_OBJECT(dialog->model));
    dialog->treeview = treeview;
    - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
    sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
    gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
    --- a/pidgin/gtkprefs.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkprefs.c Sun Oct 08 20:44:26 2017 +0300
    @@ -3269,9 +3269,7 @@
    PURPLE_PREF_STRING, "/purple/away/idle_reporting",
    _("Never"), "none",
    _("From last sent message"), "purple",
    -#if defined(USE_SCREENSAVER) || defined(HAVE_IOKIT)
    _("Based on keyboard or mouse use"), "system",
    -#endif
    NULL);
    gtk_size_group_add_widget(sg, dd);
    gtk_widget_set_halign(dd, GTK_ALIGN_START);
    --- a/pidgin/gtkrequest.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkrequest.c Sun Oct 08 20:44:26 2017 +0300
    @@ -1911,8 +1911,6 @@
    i + 1, NULL);
    }
    - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
    -
    gtk_widget_set_size_request(GTK_WIDGET(view), 400, 250);
    scrollable = pidgin_make_scrollable(GTK_WIDGET(view),
    --- a/pidgin/gtkroomlist.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkroomlist.c Sun Oct 08 20:44:26 2017 +0300
    @@ -84,7 +84,7 @@
    purple_roomlist_cancel_get_list(dialog->roomlist);
    if (dialog->pg_update_to > 0)
    - purple_timeout_remove(dialog->pg_update_to);
    + g_source_remove(dialog->pg_update_to);
    if (dialog->roomlist) {
    PidginRoomlist *rl = purple_roomlist_get_ui_data(dialog->roomlist);
    @@ -298,7 +298,7 @@
    GtkWidget *menu;
    static struct _menu_cb_info info; /* XXX? */
    - if (event->button != 3 || event->type != GDK_BUTTON_PRESS)
    + if (!gdk_event_triggers_context_menu((GdkEvent *)event))
    return FALSE;
    /* Here we figure out which room was clicked */
    @@ -323,7 +323,7 @@
    G_CALLBACK(do_add_room_cb), &info);
    gtk_widget_show_all(menu);
    - gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, event->time);
    + gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
    return FALSE;
    }
    @@ -728,7 +728,6 @@
    g_free(types);
    tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
    - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree), TRUE);
    selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
    g_signal_connect(G_OBJECT(selection), "changed",
    --- a/pidgin/gtksavedstatuses.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtksavedstatuses.c Sun Oct 08 20:44:26 2017 +0300
    @@ -449,7 +449,6 @@
    /* Create the treeview */
    treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model));
    dialog->treeview = treeview;
    - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
    g_signal_connect(G_OBJECT(treeview), "row-activated",
    G_CALLBACK(savedstatus_activated_cb), dialog);
    @@ -1175,7 +1174,6 @@
    /* Create the treeview */
    dialog->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model));
    - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(dialog->treeview), TRUE);
    gtk_widget_set_size_request(dialog->treeview, -1, 150);
    gtk_box_pack_start(GTK_BOX(dbox),
    pidgin_make_scrollable(dialog->treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1),
    --- a/pidgin/gtksmiley-manager.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtksmiley-manager.c Sun Oct 08 20:44:26 2017 +0300
    @@ -641,7 +641,6 @@
    manager->tree = tree = GTK_TREE_VIEW(gtk_tree_view_new_with_model(
    GTK_TREE_MODEL(manager->model)));
    - gtk_tree_view_set_rules_hint(tree, TRUE);
    gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(manager->model),
    SMILEY_LIST_MODEL_SHORTCUT, GTK_SORT_ASCENDING);
    --- a/pidgin/gtksound.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtksound.c Sun Oct 08 20:44:26 2017 +0300
    @@ -232,9 +232,9 @@
    account_signon_cb(PurpleConnection *gc, gpointer data)
    {
    if (mute_login_sounds_timeout != 0)
    - purple_timeout_remove(mute_login_sounds_timeout);
    + g_source_remove(mute_login_sounds_timeout);
    mute_login_sounds = TRUE;
    - mute_login_sounds_timeout = purple_timeout_add_seconds(10, unmute_login_sounds_cb, NULL);
    + mute_login_sounds_timeout = g_timeout_add_seconds(10, unmute_login_sounds_cb, NULL);
    }
    const char *
    @@ -507,7 +507,7 @@
    error->message);
    g_error_free(error);
    } else {
    - purple_timeout_add_seconds(15, expire_old_child, GINT_TO_POINTER(pid));
    + g_timeout_add_seconds(15, expire_old_child, GINT_TO_POINTER(pid));
    }
    g_strfreev(argv);
    --- a/pidgin/gtkstatusbox.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkstatusbox.c Sun Oct 08 20:44:26 2017 +0300
    @@ -301,7 +301,7 @@
    static gboolean
    icon_box_press_cb(GtkWidget *widget, GdkEventButton *event, PidginStatusBox *box)
    {
    - if (event->button == 3) {
    + if (gdk_event_triggers_context_menu((GdkEvent *)event)) {
    GtkWidget *menu_item;
    const char *path;
    @@ -320,8 +320,7 @@
    || !*path)
    gtk_widget_set_sensitive(menu_item, FALSE);
    - gtk_menu_popup(GTK_MENU(box->icon_box_menu), NULL, NULL, NULL, NULL,
    - event->button, event->time);
    + gtk_menu_popup_at_pointer(GTK_MENU(box->icon_box_menu), (GdkEvent *)event);
    } else {
    choose_buddy_icon_cb(widget, box);
    @@ -1094,7 +1093,7 @@
    /* Reset the status if Escape was pressed */
    if (event->keyval == GDK_KEY_Escape)
    {
    - purple_timeout_remove(status_box->typing);
    + g_source_remove(status_box->typing);
    status_box->typing = 0;
    #if 0
    /* TODO WebKit: Doesn't do this? */
    @@ -1112,8 +1111,8 @@
    }
    pidgin_status_box_pulse_typing(status_box);
    - purple_timeout_remove(status_box->typing);
    - status_box->typing = purple_timeout_add_seconds(TYPING_TIMEOUT, (GSourceFunc)remove_typing_cb, status_box);
    + g_source_remove(status_box->typing);
    + status_box->typing = g_timeout_add_seconds(TYPING_TIMEOUT, (GSourceFunc)remove_typing_cb, status_box);
    return FALSE;
    }
    @@ -1209,7 +1208,7 @@
    static gboolean button_released_cb(GtkWidget *widget, GdkEventButton *event, PidginStatusBox *box)
    {
    - if (event->button != 1)
    + if (event->button != GDK_BUTTOM_PRIMARY)
    return FALSE;
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(box->toggle_button), FALSE);
    if (!box->webview_visible)
    @@ -1219,7 +1218,7 @@
    static gboolean button_pressed_cb(GtkWidget *widget, GdkEventButton *event, PidginStatusBox *box)
    {
    - if (event->button != 1)
    + if (event->button != GDK_BUTTOM_PRIMARY)
    return FALSE;
    gtk_combo_box_popup(GTK_COMBO_BOX(box));
    /* Disabled until button_released_cb works */
    @@ -2562,7 +2561,7 @@
    PIDGIN_WEBVIEW(status_box->webview), TRUE);
    #endif
    - purple_timeout_remove(status_box->typing);
    + g_source_remove(status_box->typing);
    status_box->typing = 0;
    activate_currently_selected_status(status_box);
    @@ -2591,7 +2590,7 @@
    DATA_COLUMN, &data,
    -1);
    if ((wastyping = (status_box->typing != 0)))
    - purple_timeout_remove(status_box->typing);
    + g_source_remove(status_box->typing);
    status_box->typing = 0;
    if (gtk_widget_get_sensitive(GTK_WIDGET(status_box)))
    @@ -2661,7 +2660,7 @@
    if (status_box->webview_visible)
    {
    gtk_widget_show_all(status_box->vbox);
    - status_box->typing = purple_timeout_add_seconds(TYPING_TIMEOUT, (GSourceFunc)remove_typing_cb, status_box);
    + status_box->typing = g_timeout_add_seconds(TYPING_TIMEOUT, (GSourceFunc)remove_typing_cb, status_box);
    gtk_widget_grab_focus(status_box->webview);
    #if 0
    /* TODO WebKit: Doesn't do this? */
    @@ -2718,9 +2717,9 @@
    {
    if (status_box->typing != 0) {
    pidgin_status_box_pulse_typing(status_box);
    - purple_timeout_remove(status_box->typing);
    + g_source_remove(status_box->typing);
    }
    - status_box->typing = purple_timeout_add_seconds(TYPING_TIMEOUT, (GSourceFunc)remove_typing_cb, status_box);
    + status_box->typing = g_timeout_add_seconds(TYPING_TIMEOUT, (GSourceFunc)remove_typing_cb, status_box);
    }
    pidgin_status_box_refresh(status_box);
    }
    --- a/pidgin/gtkutils.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkutils.c Sun Oct 08 20:44:26 2017 +0300
    @@ -884,7 +884,7 @@
    "accel changed, scheduling save.\n");
    if (!accels_save_timer)
    - accels_save_timer = purple_timeout_add_seconds(5, pidgin_save_accels,
    + accels_save_timer = g_timeout_add_seconds(5, pidgin_save_accels,
    NULL);
    }
    @@ -1183,7 +1183,6 @@
    gpointer data)
    {
    GtkWidget *widget;
    - GtkStyleContext *context;
    GtkRequisition requisition;
    GdkScreen *screen;
    GdkRectangle monitor;
    @@ -1309,7 +1308,8 @@
    }
    -void
    +#if !GTK_CHECK_VERSION(3,22,0)
    +static void
    pidgin_treeview_popup_menu_position_func(GtkMenu *menu,
    gint *x,
    gint *y,
    @@ -1330,6 +1330,36 @@
    *y += rect.y + rect.height;
    pidgin_menu_position_func_helper(menu, x, y, push_in, data);
    }
    +#endif
    +
    +
    +void
    +pidgin_menu_popup_at_treeview_selection(GtkWidget *menu, GtkWidget *treeview)
    +{
    +#if GTK_CHECK_VERSION(3,22,0)
    + GtkTreePath *path;
    + GtkTreeViewColumn *column;
    + GdkWindow *bin_window;
    + GdkRectangle rect;
    +
    + gtk_tree_view_get_cursor(GTK_TREE_VIEW(treeview), &path, &column);
    + g_return_if_fail(path != NULL);
    + if (column == NULL)
    + column = gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), 0);
    + bin_window = gtk_tree_view_get_bin_window(GTK_TREE_VIEW(treeview));
    + gtk_tree_view_get_cell_area(GTK_TREE_VIEW(treeview), path, column, &rect);
    + gtk_menu_popup_at_rect(GTK_MENU(menu), bin_window, &rect,
    + GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST,
    + NULL);
    +
    + gtk_tree_path_free(path);
    +#else
    + gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
    + pidgin_treeview_popup_menu_position_func, treeview,
    + 0, GDK_CURRENT_TIME);
    +#endif
    +}
    +
    static void dnd_image_ok_callback(_DndData *data, int choice)
    {
    --- a/pidgin/gtkutils.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkutils.h Sun Oct 08 20:44:26 2017 +0300
    @@ -258,9 +258,6 @@
    * or %NULL for no icon.
    * @cb: A function to call when the menu item is activated.
    * @data: Data to pass to the signal function.
    - * @accel_key: Something.
    - * @accel_mods: Something.
    - * @mod: Something.
    *
    * Creates a menu item.
    *
    @@ -493,26 +490,15 @@
    gboolean *push_in, gpointer data);
    /**
    - * pidgin_treeview_popup_menu_position_func:
    - * @menu: The menu we are positioning.
    - * @x: Address of the gint representing the horizontal position
    - * where the menu shall be drawn. This is an output parameter.
    - * @y: Address of the gint representing the vertical position
    - * where the menu shall be drawn. This is an output parameter.
    - * @push_in: This is an output parameter?
    - * @user_data: Not used by this particular position function.
    + * pidgin_menu_popup_at_treeview_selection:
    + * @menu: The menu to show.
    + * @treeview: The treeview to use for positioning.
    *
    - * A valid GtkMenuPositionFunc. This is used to determine where
    - * to draw context menus when the menu is activated with the
    - * keyboard (shift+F10). If the menu is activated with the mouse,
    - * then you should just use GTK's built-in position function,
    - * because it does a better job of positioning the menu.
    + * Open a menu popup at the position determined by the selection of a given
    + * treeview. This function is similar to @gtk_menu_popup_at_pointer, but should
    + * be used when the menu is activated via a keyboard shortcut.
    */
    -void pidgin_treeview_popup_menu_position_func(GtkMenu *menu,
    - gint *x,
    - gint *y,
    - gboolean *push_in,
    - gpointer user_data);
    +void pidgin_menu_popup_at_treeview_selection(GtkWidget *menu, GtkWidget *treeview);
    /**
    * pidgin_dnd_file_manage:
    --- a/pidgin/gtkwebview.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkwebview.c Sun Oct 08 20:44:26 2017 +0300
    @@ -745,7 +745,7 @@
    }
    static void
    -do_popup_menu(WebKitWebView *webview, int button, int time, int context,
    +do_popup_menu(WebKitWebView *webview, GdkEvent *event, int context,
    WebKitDOMNode *node, const char *uri)
    {
    GtkWidget *menu;
    @@ -929,7 +929,7 @@
    g_signal_emit_by_name(G_OBJECT(webview), "populate-popup", menu);
    gtk_menu_attach_to_widget(GTK_MENU(menu), GTK_WIDGET(webview), NULL);
    - gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, button, time);
    + gtk_menu_popup_at_pointer(GTK_MENU(menu), event);
    }
    static gboolean
    @@ -958,8 +958,7 @@
    }
    }
    - do_popup_menu(webview, 0, gtk_get_current_event_time(),
    - context, node, uri);
    + do_popup_menu(webview, NULL, context, node, uri);
    g_free(uri);
    @@ -969,7 +968,7 @@
    static gboolean
    webview_button_pressed(WebKitWebView *webview, GdkEventButton *event)
    {
    - if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
    + if (gdk_event_triggers_context_menu((GdkEvent *)event)) {
    WebKitHitTestResult *hit;
    int context;
    WebKitDOMNode *node;
    @@ -982,7 +981,7 @@
    "link-uri", &uri,
    NULL);
    - do_popup_menu(webview, event->button, event->time, context,
    + do_popup_menu(webview, (GdkEvent *)event, context,
    node, uri);
    g_free(uri);
    --- a/pidgin/gtkwebview.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkwebview.h Sun Oct 08 20:44:26 2017 +0300
    @@ -426,7 +426,7 @@
    *
    * Checks, if the @webview is empty.
    *
    - * Returns %TRUES, if the @webview is empty, %FALSE otherwise.
    + * Returns %TRUE, if the @webview is empty, %FALSE otherwise.
    */
    gboolean
    pidgin_webview_is_empty(PidginWebView *webview);
    --- a/pidgin/gtkwebviewtoolbar.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkwebviewtoolbar.c Sun Oct 08 20:44:26 2017 +0300
    @@ -667,7 +667,7 @@
    PidginWebViewToolbar *toolbar)
    {
    if ((event->type == GDK_KEY_PRESS && event->key.keyval == GDK_KEY_Escape) ||
    - (event->type == GDK_BUTTON_PRESS && event->button.button == 1))
    + (event->type == GDK_BUTTON_PRESS && event->button.button == GDK_BUTTON_PRIMARY))
    {
    close_smiley_dialog(toolbar);
    return TRUE;
    @@ -1187,6 +1187,19 @@
    update_buttons(toolbar);
    }
    +#if GTK_CHECK_VERSION(3,22,0)
    +
    +static void
    +pidgin_menu_clicked(GtkWidget *button, GtkMenu *menu)
    +{
    + if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(button))) {
    + gtk_widget_show_all(GTK_WIDGET(menu));
    + gtk_menu_popup_at_widget(menu, button, GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, NULL);
    + }
    +}
    +
    +#else /* GTK+ 3.22.0 */
    +
    /* This comes from gtkmenutoolbutton.c from gtk+
    * Copyright (C) 2003 Ricardo Fernandez Pascual
    * Copyright (C) 2004 Paolo Borelli
    @@ -1223,6 +1236,8 @@
    }
    }
    +#endif /* GTK+ 3.22.0 */
    +
    static void
    pidgin_menu_deactivate(GtkWidget *menu, GtkToggleButton *button)
    {
    @@ -1245,7 +1260,7 @@
    GtkWidget *item;
    gboolean wide;
    - if (event->button != 3)
    + if (!gdk_event_triggers_context_menu((GdkEvent *)event))
    return FALSE;
    wide = gtk_widget_get_visible(priv->wide_view);
    @@ -1256,8 +1271,7 @@
    gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
    gtk_widget_show(item);
    - gtk_menu_popup(GTK_MENU(menu), NULL, NULL, pidgin_menu_position_func_helper,
    - widget, event->button, event->time);
    + gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
    return TRUE;
    }
    --- a/pidgin/gtkwhiteboard.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkwhiteboard.c Sun Oct 08 20:44:26 2017 +0300
    @@ -423,7 +423,7 @@
    brush_state = PIDGIN_WHITEBOARD_BRUSH_DOWN;
    - if(event->button == 1 && gtkwb->priv->cr != NULL)
    + if(event->button == GDK_BUTTON_PRIMARY && gtkwb->priv->cr != NULL)
    {
    /* Check if draw_list has contents; if so, clear it */
    if(draw_list)
    @@ -561,7 +561,7 @@
    }
    brush_state = PIDGIN_WHITEBOARD_BRUSH_UP;
    - if(event->button == 1 && gtkwb->priv->cr != NULL)
    + if(event->button == GDK_BUTTON_PRIMARY && gtkwb->priv->cr != NULL)
    {
    /* If the brush was never moved, express two sets of two deltas That's a
    * 'point,' but not for Yahoo!
    --- a/pidgin/gtkxfer.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/gtkxfer.c Sun Oct 08 20:44:26 2017 +0300
    @@ -84,7 +84,7 @@
    typedef struct
    {
    GtkTreeIter iter;
    - time_t last_updated_time;
    + gint64 last_updated_time;
    gboolean in_list;
    char *name;
    @@ -578,7 +578,6 @@
    /* Create the treeview */
    dialog->tree = tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
    - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree), TRUE);
    selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
    /* gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); */
    @@ -1009,7 +1008,7 @@
    {
    PidginXferUiData *data;
    char *size_str, *remaining_str;
    - time_t current_time;
    + gint64 current_time;
    GtkTreeIter iter;
    gboolean valid;
    @@ -1022,8 +1021,8 @@
    if (data->in_list == FALSE)
    return;
    - current_time = time(NULL);
    - if (((current_time - data->last_updated_time) == 0) &&
    + current_time = g_get_monotonic_time();
    + if (((current_time - data->last_updated_time) < G_USEC_PER_SEC) &&
    (!purple_xfer_is_completed(xfer)))
    {
    /* Don't update the window more than once per second */
    --- a/pidgin/libpidgin.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/libpidgin.c Sun Oct 08 20:44:26 2017 +0300
    @@ -71,8 +71,6 @@
    #include <signal.h>
    #endif
    -#include <getopt.h>
    -
    #ifndef _WIN32
    /*
    @@ -246,8 +244,8 @@
    static void
    debug_init(void)
    {
    - purple_debug_set_ui_ops(pidgin_debug_get_ui_ops());
    - pidgin_debug_init();
    + PidginDebugUi *ui = pidgin_debug_ui_new();
    + purple_debug_set_ui(PURPLE_DEBUG_UI(ui));
    }
    static void
    @@ -264,9 +262,7 @@
    purple_sound_set_ui_ops(pidgin_sound_get_ui_ops());
    purple_connections_set_ui_ops(pidgin_connections_get_ui_ops());
    purple_whiteboard_set_ui_ops(pidgin_whiteboard_get_ui_ops());
    -#if defined(USE_SCREENSAVER) || defined(HAVE_IOKIT)
    purple_idle_set_ui_ops(pidgin_idle_get_ui_ops());
    -#endif
    pidgin_accounts_init();
    pidgin_connection_init();
    @@ -292,6 +288,8 @@
    pidgin_quit(void)
    {
    /* Uninit */
    + PurpleDebugUi *ui;
    +
    pidgin_utils_uninit();
    pidgin_notify_uninit();
    _pidgin_smiley_theme_uninit();
    @@ -303,7 +301,9 @@
    pidgin_connection_uninit();
    pidgin_accounts_uninit();
    pidgin_xfers_uninit();
    - pidgin_debug_uninit();
    + ui = purple_debug_get_ui();
    + purple_debug_set_ui(NULL);
    + g_object_unref(ui);
    if(NULL != ui_info)
    g_hash_table_destroy(ui_info);
    @@ -375,61 +375,44 @@
    purple_blist_set_visible(TRUE);
    }
    -static void
    -show_usage(const char *name, gboolean terse)
    -{
    - char *text;
    +static gboolean debug_colored = FALSE;
    +static gboolean debug_enabled = FALSE;
    +static gboolean opt_login = FALSE;
    +static gchar *opt_login_arg = NULL;
    - if (terse) {
    - text = g_strdup_printf(_("%s %s. Try `%s -h' for more information.\n"), PIDGIN_NAME, DISPLAY_VERSION, name);
    - } else {
    - GString *str = g_string_new(NULL);
    - g_string_append_printf(str, "%s %s\n", PIDGIN_NAME, DISPLAY_VERSION);
    - g_string_append_printf(str, _("Usage: %s [OPTION]...\n\n"), name);
    - g_string_append_printf(str, " -c, --config=%s %s\n",
    - _("DIR"), _("use DIR for config files"));
    - g_string_append_printf(str, " -d, --debug[=colored] %s\n",
    - _("print debugging messages to stdout"));
    - g_string_append_printf(str, " -f, --force-online %s\n",
    - _("force online, regardless of network status"));
    - g_string_append_printf(str, " -h, --help %s\n",
    - _("display this help and exit"));
    - g_string_append_printf(str, " -m, --multiple %s\n",
    - _("allow multiple instances"));
    - g_string_append_printf(str, " -n, --nologin %s\n",
    - _("don't automatically login"));
    - g_string_append_printf(str, " -l, --login[=%s] %s\n",
    - _("NAME"),
    - _("enable specified account(s) (optional argument NAME\n"
    - " "
    - "specifies account(s) to use, separated by commas.\n"
    - " "
    - "Without this only the first account will be enabled)."));
    -#ifndef WIN32
    - g_string_append_printf(str, " --display=DISPLAY %s\n",
    - _("X display to use"));
    -#endif /* !WIN32 */
    - g_string_append_printf(str, " -v, --version %s\n",
    - _("display the current version and exit"));
    - text = g_string_free(str, FALSE);
    +static gboolean
    +debug_opt_arg_func(const gchar *option_name, const gchar *value,
    + gpointer data, GError **error)
    +{
    + debug_enabled = TRUE;
    +
    + if (purple_strequal(value, "colored")) {
    + debug_colored = TRUE;
    }
    - purple_print_utf8_to_console(stdout, text);
    - g_free(text);
    + return TRUE;
    +}
    +
    +static gboolean
    +login_opt_arg_func(const gchar *option_name, const gchar *value,
    + gpointer data, GError **error)
    +{
    + opt_login = TRUE;
    +
    + g_free(opt_login_arg);
    + opt_login_arg = g_strdup(value);
    +
    + return TRUE;
    }
    int pidgin_start(int argc, char *argv[])
    {
    GApplication *app;
    gboolean opt_force_online = FALSE;
    - gboolean opt_help = FALSE;
    - gboolean opt_login = FALSE;
    gboolean opt_nologin = FALSE;
    gboolean opt_version = FALSE;
    gboolean opt_si = TRUE; /* Check for single instance? */
    char *opt_config_dir_arg = NULL;
    - char *opt_login_arg = NULL;
    - char *opt_session_arg = NULL;
    char *search_path;
    GtkCssProvider *provider;
    GdkScreen *screen;
    @@ -445,27 +428,44 @@
    char *segfault_message_tmp;
    #endif /* DEBUG */
    #endif /* !_WIN32 */
    - int opt;
    + GOptionContext *context;
    + gchar *summary;
    + gchar **args;
    gboolean gui_check;
    - gboolean debug_enabled, debug_colored;
    GList *active_accounts;
    GStatBuf st;
    - GError *error;
    + GError *error = NULL;
    int ret;
    - struct option long_options[] = {
    - {"config", required_argument, NULL, 'c'},
    - {"debug", optional_argument, NULL, 'd'},
    - {"force-online", no_argument, NULL, 'f'},
    - {"help", no_argument, NULL, 'h'},
    - {"login", optional_argument, NULL, 'l'},
    - {"multiple", no_argument, NULL, 'm'},
    - {"nologin", no_argument, NULL, 'n'},
    - {"session", required_argument, NULL, 's'},
    - {"version", no_argument, NULL, 'v'},
    - {"display", required_argument, NULL, 'D'},
    - {"sync", no_argument, NULL, 'S'},
    - {0, 0, 0, 0}
    + GOptionEntry option_entries[] = {
    + {"config", 'c', 0,
    + G_OPTION_ARG_FILENAME, &opt_config_dir_arg,
    + _("use DIR for config files"), _("DIR")},
    + {"debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
    + G_OPTION_ARG_CALLBACK, &debug_opt_arg_func,
    + _("print debugging messages to stdout"),
    + _("[colored]")},
    + {"force-online", 'f', 0,
    + G_OPTION_ARG_NONE, &opt_force_online,
    + _("force online, regardless of network status"), NULL},
    + {"login", 'l', G_OPTION_FLAG_OPTIONAL_ARG,
    + G_OPTION_ARG_CALLBACK, &login_opt_arg_func,
    + _("enable specified account(s) (optional argument NAME\n"
    + " "
    + "specifies account(s) to use, separated by commas.\n"
    + " "
    + "Without this only the first account will be enabled)"),
    + _("[NAME]")},
    + {"multiple", 'm', G_OPTION_FLAG_REVERSE,
    + G_OPTION_ARG_NONE, &opt_si,
    + _("allow multiple instances"), NULL},
    + {"nologin", 'n', 0,
    + G_OPTION_ARG_NONE, &opt_nologin,
    + _("don't automatically login"), NULL},
    + {"version", 'v', 0,
    + G_OPTION_ARG_NONE, &opt_version,
    + _("display the current version and exit"), NULL},
    + {NULL}
    };
    debug_colored = FALSE;
    @@ -505,7 +505,6 @@
    /* we have to convert the message (UTF-8 to console
    charset) early because after a segmentation fault
    it's not a good practice to allocate memory */
    - error = NULL;
    segfault_message = g_locale_from_utf8(segfault_message_tmp,
    -1, NULL, NULL, &error);
    if (segfault_message != NULL) {
    @@ -514,7 +513,7 @@
    else {
    /* use 'segfault_message_tmp' (UTF-8) as a fallback */
    g_warning("%s\n", error->message);
    - g_error_free(error);
    + g_clear_error(&error);
    segfault_message = segfault_message_tmp;
    }
    #else
    @@ -543,11 +542,11 @@
    * Set the channel encoding to raw binary instead of the default of
    * UTF-8, because we'll be sending integers across instead of strings.
    */
    - error = NULL;
    signal_status = g_io_channel_set_encoding(signal_channel, NULL, &error);
    if (signal_status != G_IO_STATUS_NORMAL) {
    fprintf(stderr, "Failed to set the signal channel to raw "
    "binary: %s", error->message);
    + g_clear_error(&error);
    exit(1);
    }
    signal_channel_watcher = g_io_add_watch(signal_channel, G_IO_IN, mainloop_sighandler, NULL);
    @@ -588,73 +587,36 @@
    }
    #endif /* !_WIN32 */
    - /* scan command-line options */
    - opterr = 1;
    - while ((opt = getopt_long(argc, argv,
    -#ifndef _WIN32
    - "c:dfhmnl::s:v",
    + context = g_option_context_new(NULL);
    +
    + summary = g_strdup_printf("%s %s", PIDGIN_NAME, DISPLAY_VERSION);
    + g_option_context_set_summary(context, summary);
    + g_free(summary);
    +
    + g_option_context_add_main_entries(context, option_entries, PACKAGE);
    + g_option_context_add_group(context, gtk_get_option_group(TRUE));
    +
    +#ifdef G_OS_WIN32
    + /* Handle Unicode filenames on Windows. See GOptionContext docs. */
    + args = g_win32_get_command_line();
    #else
    - "c:dfhmnl::v",
    + args = g_strdupv(argv);
    #endif
    - long_options, NULL)) != -1) {
    - switch (opt) {
    - case 'c': /* config dir */
    - g_free(opt_config_dir_arg);
    - opt_config_dir_arg = g_strdup(optarg);
    - break;
    - case 'd': /* debug */
    - debug_enabled = TRUE;
    - if (g_strcmp0(optarg, "colored") == 0)
    - debug_colored = TRUE;
    - break;
    - case 'f': /* force-online */
    - opt_force_online = TRUE;
    - break;
    - case 'h': /* help */
    - opt_help = TRUE;
    - break;
    - case 'n': /* no autologin */
    - opt_nologin = TRUE;
    - break;
    - case 'l': /* login, option username */
    - opt_login = TRUE;
    - g_free(opt_login_arg);
    - if (optarg != NULL)
    - opt_login_arg = g_strdup(optarg);
    - break;
    - case 's': /* use existing session ID */
    - g_free(opt_session_arg);
    - opt_session_arg = g_strdup(optarg);
    - break;
    - case 'v': /* version */
    - opt_version = TRUE;
    - break;
    - case 'm': /* do not ensure single instance. */
    - opt_si = FALSE;
    - break;
    - case 'D': /* --display */
    - case 'S': /* --sync */
    - /* handled by gtk_init_check below */
    - break;
    - case '?': /* show terse help */
    - default:
    - show_usage(argv[0], TRUE);
    -#ifndef _WIN32
    - g_free(segfault_message);
    -#endif
    - return 0;
    - break;
    - }
    - }
    - /* show help message */
    - if (opt_help) {
    - show_usage(argv[0], FALSE);
    + if (!g_option_context_parse_strv(context, &args, &error)) {
    + g_strfreev(args);
    + g_printerr(_("%s %s: %s\nTry `%s -h' for more information.\n"),
    + PIDGIN_NAME, DISPLAY_VERSION, error->message,
    + argv[0]);
    + g_clear_error(&error);
    #ifndef _WIN32
    g_free(segfault_message);
    #endif
    - return 0;
    + return 1;
    }
    +
    + g_strfreev(args);
    +
    /* show version message */
    if (opt_version) {
    printf("%s %s (libpurple %s)\n", PIDGIN_NAME, DISPLAY_VERSION,
    @@ -689,23 +651,6 @@
    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());
    -
    - printf("%s %s\n", PIDGIN_NAME, DISPLAY_VERSION);
    -
    - g_warning("cannot open display: %s", display ? display : "unset");
    -#ifndef _WIN32
    - g_free(segfault_message);
    -#endif
    -
    - return 1;
    - }
    -
    app = G_APPLICATION(gtk_application_new("im.pidgin.Pidgin",
    G_APPLICATION_NON_UNIQUE));
    @@ -728,7 +673,6 @@
    search_path = g_build_filename(purple_user_dir(), "gtk-3.0.css", NULL);
    - error = NULL;
    provider = gtk_css_provider_new();
    gui_check = gtk_css_provider_load_from_path(provider, search_path, &error);
    @@ -740,6 +684,7 @@
    } else {
    purple_debug_error("gtk", "Unable to load custom gtk-3.0.css: %s\n",
    error ? error->message : "(unknown error)");
    + g_clear_error(&error);
    }
    g_free(search_path);
    @@ -793,8 +738,6 @@
    ui_main();
    - g_free(opt_session_arg);
    - opt_session_arg = NULL;
    g_free(opt_config_dir_arg);
    opt_config_dir_arg = NULL;
    Binary file pidgin/logo.png has changed
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,235 @@
    +libpidgin_SOURCES = [
    + 'pidginstock.c',
    + 'gtkaccount.c',
    + 'gtkblist.c',
    + 'gtkblist-theme.c',
    + 'gtkblist-theme-loader.c',
    + 'gtkcellrendererexpander.c',
    + 'gtkcertmgr.c',
    + 'gtkconn.c',
    + 'gtkconv.c',
    + 'gtkconv-theme.c',
    + 'gtkconv-theme-loader.c',
    + 'gtkdebug.c',
    + 'gtkdialogs.c',
    + 'gtkdnd-hints.c',
    + 'gtkdocklet.c',
    + 'gtkicon-theme.c',
    + 'gtkicon-theme-loader.c',
    + 'gtkidle.c',
    + 'gtklog.c',
    + 'gtkmedia.c',
    + 'gtkmenutray.c',
    + 'gtknotify.c',
    + 'gtkplugin.c',
    + 'gtkpluginpref.c',
    + 'gtkpounce.c',
    + 'gtkprefs.c',
    + 'gtkprivacy.c',
    + 'gtkrequest.c',
    + 'gtkroomlist.c',
    + 'gtksavedstatuses.c',
    + 'gtkscrollbook.c',
    + 'gtksmiley-manager.c',
    + 'gtksmiley-theme.c',
    + 'gtksound.c',
    + 'gtkstatus-icon-theme.c',
    + 'gtkstatusbox.c',
    + 'gtkutils.c',
    + 'gtkwebview.c',
    + 'gtkwebviewtoolbar.c',
    + 'gtkwhiteboard.c',
    + 'gtkxfer.c',
    + 'libpidgin.c',
    + 'minidialog.c',
    + 'pidginabout.c',
    + 'pidgintooltip.c',
    +]
    +
    +libpidgin_headers = [
    + 'gtkaccount.h',
    + 'gtkblist.h',
    + 'gtkblist-theme.h',
    + 'gtkblist-theme-loader.h',
    + 'gtkcellrendererexpander.h',
    + 'gtkcertmgr.h',
    + 'gtkconn.h',
    + 'gtkconv.h',
    + 'gtkconvwin.h',
    + 'gtkconv-theme.h',
    + 'gtkconv-theme-loader.h',
    + 'gtkdebug.h',
    + 'gtkdialogs.h',
    + 'gtkdnd-hints.h',
    + 'gtkdocklet.h',
    + 'gtkicon-theme.h',
    + 'gtkicon-theme-loader.h',
    + 'gtkidle.h',
    + 'gtklog.h',
    + 'gtkmedia.h',
    + 'gtkmenutray.h',
    + 'gtknickcolors.h',
    + 'gtknotify.h',
    + 'gtkplugin.h',
    + 'gtkpluginpref.h',
    + 'gtkprefs.h',
    + 'gtkprivacy.h',
    + 'gtkpounce.h',
    + 'gtkrequest.h',
    + 'gtkroomlist.h',
    + 'gtksavedstatuses.h',
    + 'gtkscrollbook.h',
    + 'gtksmiley-manager.h',
    + 'gtksmiley-theme.h',
    + 'gtksound.h',
    + 'gtkstatus-icon-theme.h',
    + 'gtkstatusbox.h',
    + 'pidginstock.h',
    + 'gtkutils.h',
    + 'gtkwebview.h',
    + 'gtkwebviewtoolbar.h',
    + 'gtkwhiteboard.h',
    + 'gtkxfer.h',
    + 'minidialog.h',
    + 'pidginabout.h',
    + 'pidgintooltip.h',
    + 'pidgin.h',
    +]
    +
    +pidgin_SOURCES = [
    + 'pidgin.c'
    +]
    +
    +pidgin_resource = gnome.compile_resources('pidginresources', 'pidgin.gresource.xml',
    + c_name : 'pidgin')
    +libpidgin_SOURCES += pidgin_resource
    +
    +if IS_WIN32
    + libpidgin_SOURCES += [
    + 'win32/gtkwin32dep.c',
    + 'win32/untar.c'
    + ]
    +
    + # Files that looks like obsolete (were used in Pidgin2):
    + # win32/gtkdocklet-win32.c
    + # win32/MinimizeToTray.c
    + # win32/MinimizeToTray.h
    +
    + pidgin_exe_rc = configure_file(
    + input : 'win32/pidgin_exe_rc.rc.in',
    + output : 'pidgin_exe_rc.rc',
    + configuration : version_conf)
    + pidgin_SOURCES += [
    + 'win32/winpidgin.c',
    + windows.compile_resources(pidgin_exe_rc,
    + include_directories : include_directories('win32')
    + )
    + ]
    +
    + libpidgin_headers += [
    + 'win32/gtkwin32dep.h',
    + 'win32/resource.h',
    + 'win32/untar.h'
    + ]
    +endif
    +
    +if ENABLE_GTK
    + if IS_WIN32
    + pidgin_dll_rc = configure_file(
    + input : 'win32/pidgin_dll_rc.rc.in',
    + output : 'pidgin_dll_rc.rc',
    + configuration : version_conf)
    + libpidgin_SOURCES += windows.compile_resources(pidgin_dll_rc,
    + include_directories : include_directories('win32')
    + )
    + endif
    +
    + install_headers(libpidgin_headers, subdir : 'pidgin')
    +
    + libpidgin_inc = include_directories('.')
    + libpidgin = shared_library('pidgin',
    + libpidgin_SOURCES,
    + include_directories : [toplevel_inc],
    + version : PURPLE_LIB_VERSION,
    + dependencies : [
    + dbus,
    + enchant,
    + GCR,
    + glib,
    + gstreamer_video,
    + gtk,
    + IOKIT,
    + json,
    + math,
    + webkit,
    + x11,
    + libpurple_dep,
    + ],
    + install : true)
    + libpidgin_dep = declare_dependency(
    + include_directories : [toplevel_inc, libpidgin_inc],
    + link_with : libpidgin,
    + dependencies : [webkit, gtk, glib, math])
    +
    + pidgin = executable('pidgin',
    + pidgin_SOURCES,
    + link_args : '-export-dynamic',
    + dependencies : [libpurple_dep, libpidgin_dep],
    + gui_app : true,
    + install : true)
    +
    + if IS_WIN32
    +# libpidgin_la_LIBADD += -lwinmm
    +# pidgin_LDFLAGS += -mwindows
    + endif
    +
    + configure_file(input : 'data/pidgin-3.pc.in',
    + output : 'pidgin-3.pc',
    + configuration : pkg_conf,
    + install : true,
    + install_dir : get_option('libdir') + '/pkgconfig')
    +
    + if INSTALL_I18N
    + DESKTOP_FILE = 'im.pidgin.Pidgin.desktop'
    + desktop_file_in = configure_file(
    + input : 'data/' + DESKTOP_FILE + '.in.in',
    + output : DESKTOP_FILE + '.in',
    + configuration : conf)
    + desktop_file = custom_target(DESKTOP_FILE,
    + input : desktop_file_in,
    + output : DESKTOP_FILE,
    + command : [intltool_merge, '--desktop-style', '-u',
    + '-c', '@BUILD_DIR@/po/.intltool-merge-cache',
    + meson.source_root() + '/po', '@INPUT@', '@OUTPUT@'],
    + install : true,
    + install_dir : get_option('datadir') + '/applications')
    +
    + appdata = custom_target('im.pidgin.Pidgin.appdata.xml',
    + input : 'data/im.pidgin.Pidgin.appdata.xml.in',
    + output : 'im.pidgin.Pidgin.appdata.xml',
    + command : [intltool_merge, '--xml-style', '-u',
    + '-c', '@BUILD_DIR@/po/.intltool-merge-cache',
    + meson.source_root() + '/po', '@INPUT@', '@OUTPUT@'],
    + install : true,
    + install_dir : get_option('datadir') + '/metainfo')
    + endif # INSTALL_I18N
    +
    + if enable_introspection
    + introspection_sources = libpidgin_headers
    +
    + gnome.generate_gir(libpidgin,
    + sources : introspection_sources,
    + includes : ['GObject-2.0', 'Gtk-3.0', libpurple_gir[0]],
    + namespace : 'Pidgin',
    + symbol_prefix : 'pidgin',
    + identifier_prefix : 'Pidgin',
    + export_packages : 'pidgin-@0@'.format(purple_major_version),
    + nsversion : '@0@.@1@'.format(purple_major_version,
    + purple_minor_version),
    + install : true)
    + endif
    +
    + subdir('pixmaps')
    + subdir('plugins')
    + subdir('themes')
    +endif # ENABLE_GTK
    --- a/pidgin/pidgin.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/pidgin.c Sun Oct 08 20:44:26 2017 +0300
    @@ -40,7 +40,9 @@
    /* This is for UI testing purposes only, don't use it! */
    test_prgname = g_getenv("PIDGIN_TEST_PRGNAME");
    - g_set_prgname(test_prgname ? test_prgname : "Pidgin");
    + if (test_prgname != NULL)
    + g_set_prgname(test_prgname);
    +
    g_set_application_name(PIDGIN_NAME);
    #ifdef _WIN32
    --- a/pidgin/pidgin.gresource.xml Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/pidgin.gresource.xml Sun Oct 08 20:44:26 2017 +0300
    @@ -1,6 +1,14 @@
    <?xml version="1.0" encoding="UTF-8"?>
    <gresources>
    - <gresource prefix="/im/pidgin/Pidgin">
    + <gresource prefix="/im/pidgin/Pidgin/">
    + <file>logo.png</file>
    + </gresource>
    + <gresource prefix="/im/pidgin/Pidgin/Debug">
    <file compressed="true">gtkdebug.html</file>
    </gresource>
    + <gresource prefix="/im/pidgin/Pidgin/About">
    + <file compressed="true">about.ui</file>
    + <file compressed="true">about.html</file>
    + <file compressed="true">credits.json</file>
    + </gresource>
    </gresources>
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/pidginabout.c Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,488 @@
    +/* 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 <gdk-pixbuf/gdk-pixbuf.h>
    +#include <json-glib/json-glib.h>
    +
    +#include "package_revision.h"
    +#include "pidginabout.h"
    +#include "pidginresources.h"
    +#include "internal.h"
    +#include "gtkutils.h"
    +#include "gtkwebview.h"
    +
    +#include <stdio.h>
    +
    +#ifdef HAVE_MESON_CONFIG
    +#include "meson-config.h"
    +#endif
    +
    +struct _PidginAboutDialog {
    + GtkDialog parent;
    +
    + /*< private >*/
    + PidginAboutDialogPrivate *priv;
    +};
    +
    +struct _PidginAboutDialogClass {
    + GtkDialogClass parent;
    +
    + void (*_pidgin_reserved1)(void);
    + void (*_pidgin_reserved2)(void);
    + void (*_pidgin_reserved3)(void);
    + void (*_pidgin_reserved4)(void);
    +};
    +
    +struct _PidginAboutDialogPrivate {
    + GtkWidget *close_button;
    + GtkWidget *application_name;
    + GtkWidget *stack;
    +
    + GtkWidget *main_scrolled_window;
    +
    + GtkWidget *developers_page;
    + GtkWidget *developers_treeview;
    + GtkTreeStore *developers_store;
    +
    + GtkWidget *translators_page;
    + GtkWidget *translators_treeview;
    + GtkTreeStore *translators_store;
    +
    + GtkWidget *build_info_page;
    + GtkWidget *build_info_treeview;
    + GtkTreeStore *build_info_store;
    +};
    +
    +/******************************************************************************
    + * Helpers
    + *****************************************************************************/
    +static void
    +_pidgin_about_dialog_load_application_name(PidginAboutDialog *about) {
    + gchar *label = g_strdup_printf(
    + "%s %s",
    + PIDGIN_NAME,
    + VERSION
    + );
    +
    + gtk_label_set_text(GTK_LABEL(about->priv->application_name), label);
    +
    + g_free(label);
    +}
    +
    +static void
    +_pidgin_about_dialog_load_main_page(PidginAboutDialog *about) {
    + GtkWidget *webview = NULL;
    + GInputStream *istream = NULL;
    + GString *str = NULL;
    + gchar buffer[8192];
    + gssize read = 0;
    +
    + /* create our webview */
    + webview = pidgin_webview_new(FALSE);
    + pidgin_setup_webview(webview);
    + pidgin_webview_set_format_functions(PIDGIN_WEBVIEW(webview), PIDGIN_WEBVIEW_ALL ^ PIDGIN_WEBVIEW_SMILEY);
    +
    + gtk_container_add(GTK_CONTAINER(about->priv->main_scrolled_window), webview);
    +
    + /* now load the html */
    + istream = g_resource_open_stream(
    + pidgin_get_resource(),
    + "/im/pidgin/Pidgin/About/about.html",
    + G_RESOURCE_LOOKUP_FLAGS_NONE,
    + NULL
    + );
    +
    + str = g_string_new("");
    +
    + while((read = g_input_stream_read(istream, buffer, sizeof(buffer), NULL, NULL)) > 0) {
    + g_string_append_len(str, (gchar *)buffer, read);
    + }
    +
    + pidgin_webview_append_html(PIDGIN_WEBVIEW(webview), str->str);
    +
    + g_string_free(str, TRUE);
    +
    + g_input_stream_close(istream, NULL, NULL);
    +}
    +
    +static void
    +_pidgin_about_dialog_load_json(GtkTreeStore *store, const gchar *json_section) {
    + GInputStream *istream = NULL;
    + GList *l = NULL, *sections = NULL;
    + GError *error = NULL;
    + JsonParser *parser = NULL;
    + JsonNode *root_node = NULL;
    + JsonObject *root_object = NULL;
    + JsonArray *sections_array = NULL;
    +
    + /* get a stream to the credits resource */
    + istream = g_resource_open_stream(
    + pidgin_get_resource(),
    + "/im/pidgin/Pidgin/About/credits.json",
    + G_RESOURCE_LOOKUP_FLAGS_NONE,
    + NULL
    + );
    +
    + /* create our parser */
    + parser = json_parser_new();
    +
    + if(!json_parser_load_from_stream(parser, istream, NULL, &error)) {
    + g_critical("%s", error->message);
    + }
    +
    + root_node = json_parser_get_root(parser);
    + root_object = json_node_get_object(root_node);
    +
    + sections_array = json_object_get_array_member(root_object, json_section);
    + sections = json_array_get_elements(sections_array);
    +
    + for(l = sections; l; l = l->next) {
    + GtkTreeIter section_iter;
    + JsonObject *section = json_node_get_object(l->data);
    + JsonArray *people = NULL;
    + gchar *markup = NULL;
    + guint idx = 0, n_people = 0;
    +
    + markup = g_strdup_printf(
    + "<span font_weight=\"bold\" font_size=\"large\">%s</span>",
    + json_object_get_string_member(section, "title")
    + );
    +
    + gtk_tree_store_append(store, &section_iter, NULL);
    + gtk_tree_store_set(
    + store,
    + &section_iter,
    + 0, markup,
    + 1, 0.5f,
    + -1
    + );
    +
    + g_free(markup);
    +
    + people = json_object_get_array_member(section, "people");
    + n_people = json_array_get_length(people);
    +
    + for(idx = 0; idx < n_people; idx++) {
    + GtkTreeIter person_iter;
    +
    + gtk_tree_store_append(store, &person_iter, &section_iter);
    + gtk_tree_store_set(
    + store,
    + &person_iter,
    + 0, json_array_get_string_element(people, idx),
    + 1, 0.5f,
    + -1
    + );
    + }
    + }
    +
    + g_list_free(sections);
    +
    + /* clean up */
    + g_object_unref(G_OBJECT(parser));
    +
    + g_input_stream_close(istream, NULL, NULL);
    +}
    +
    +static void
    +_pidgin_about_dialog_load_developers(PidginAboutDialog *about) {
    + _pidgin_about_dialog_load_json(about->priv->developers_store, "developers");
    +}
    +
    +static void
    +_pidgin_about_dialog_load_translators(PidginAboutDialog *about) {
    + _pidgin_about_dialog_load_json(about->priv->translators_store, "languages");
    +}
    +
    +static void
    +_pidgin_about_dialog_add_build_args(
    + PidginAboutDialog *about,
    + const gchar *title,
    + const gchar *build_args
    +) {
    + GtkTreeIter section, value;
    + gchar **splits = NULL;
    + gchar *markup = NULL;
    + gint idx = 0;
    +
    + markup = g_strdup_printf("<span font-weight=\"bold\">%s</span>", title);
    + gtk_tree_store_append(about->priv->build_info_store, &section, NULL);
    + gtk_tree_store_set(
    + about->priv->build_info_store,
    + &section,
    + 0, markup,
    + -1
    + );
    + g_free(markup);
    +
    + /* now walk through the arguments and add them */
    + splits = g_strsplit(build_args, " ", -1);
    + for(idx = 0; splits[idx]; idx++) {
    + gchar **value_split = g_strsplit(splits[idx], "=", 2);
    +
    + if(value_split[0] == NULL || value_split[0][0] == '\0') {
    + continue;
    + }
    +
    + gtk_tree_store_append(about->priv->build_info_store, &value, &section);
    + gtk_tree_store_set(
    + about->priv->build_info_store,
    + &value,
    + 0, value_split[0] ? value_split[0] : "",
    + 1, value_split[1] ? value_split[1] : "",
    + -1
    + );
    +
    + g_strfreev(value_split);
    + }
    +
    + g_strfreev(splits);
    +}
    +
    +static void
    +_pidgin_about_dialog_build_info_add_version(
    + GtkTreeStore *store,
    + GtkTreeIter *section,
    + const gchar *title,
    + guint major,
    + guint minor,
    + guint micro
    +) {
    + GtkTreeIter item;
    + gchar *version = g_strdup_printf("%u.%u.%u", major, minor, micro);
    +
    + gtk_tree_store_append(store, &item, section);
    + gtk_tree_store_set(
    + store, &item,
    + 0, title,
    + 1, version,
    + -1
    + );
    + g_free(version);
    +}
    +
    +static void
    +_pidgin_about_dialog_load_build_info(PidginAboutDialog *about) {
    + GtkTreeIter section, item;
    + gchar *markup = NULL;
    +
    + /* create the section */
    + markup = g_strdup_printf(
    + "<span font-weight=\"bold\">%s</span>",
    + _("Build Information")
    + );
    + gtk_tree_store_append(about->priv->build_info_store, &section, NULL);
    + gtk_tree_store_set(
    + about->priv->build_info_store,
    + &section,
    + 0, markup,
    + -1
    + );
    + g_free(markup);
    +
    + /* add the commit hash */
    + gtk_tree_store_append(about->priv->build_info_store, &item, &section);
    + gtk_tree_store_set(
    + about->priv->build_info_store,
    + &item,
    + 0, "Commit Hash",
    + 1, REVISION,
    + -1
    + );
    +
    + /* add the purple version */
    + _pidgin_about_dialog_build_info_add_version(
    + about->priv->build_info_store,
    + &section,
    + _("Purple Version"),
    + PURPLE_MAJOR_VERSION,
    + PURPLE_MINOR_VERSION,
    + PURPLE_MICRO_VERSION
    + );
    +
    + /* add the glib version */
    + _pidgin_about_dialog_build_info_add_version(
    + about->priv->build_info_store,
    + &section,
    + _("GLib Version"),
    + GLIB_MAJOR_VERSION,
    + GLIB_MINOR_VERSION,
    + GLIB_MICRO_VERSION
    + );
    +
    + /* add the gtk version */
    + _pidgin_about_dialog_build_info_add_version(
    + about->priv->build_info_store,
    + &section,
    + _("GTK+ Version"),
    + GTK_MAJOR_VERSION,
    + GTK_MINOR_VERSION,
    + GTK_MICRO_VERSION
    + );
    +}
    +
    +static void
    +_pidgin_about_dialog_load_runtime_info(PidginAboutDialog *about) {
    + GtkTreeIter section;
    + gchar *markup = NULL;
    +
    + /* create the section */
    + markup = g_strdup_printf(
    + "<span font-weight=\"bold\">%s</span>",
    + _("Runtime Information")
    + );
    + gtk_tree_store_append(about->priv->build_info_store, &section, NULL);
    + gtk_tree_store_set(
    + about->priv->build_info_store,
    + &section,
    + 0, markup,
    + -1
    + );
    + g_free(markup);
    +
    + /* add the purple version */
    + _pidgin_about_dialog_build_info_add_version(
    + about->priv->build_info_store,
    + &section,
    + _("Purple Version"),
    + purple_major_version,
    + purple_minor_version,
    + purple_micro_version
    + );
    +
    + /* add the glib version */
    + _pidgin_about_dialog_build_info_add_version(
    + about->priv->build_info_store,
    + &section,
    + _("GLib Version"),
    + glib_major_version,
    + glib_minor_version,
    + glib_micro_version
    + );
    +
    + /* add the gtk version */
    + _pidgin_about_dialog_build_info_add_version(
    + about->priv->build_info_store,
    + &section,
    + _("GTK+ Version"),
    + gtk_major_version,
    + gtk_minor_version,
    + gtk_micro_version
    + );
    +}
    +
    +static void
    +_pidgin_about_dialog_load_build_configuration(PidginAboutDialog *about) {
    +#ifdef MESON_ARGS
    + _pidgin_about_dialog_add_build_args(about, "Meson Arguments", MESON_ARGS);
    +#endif /* MESON_ARGS */
    +#ifdef CONFIG_ARGS
    + _pidgin_about_dialog_add_build_args(about, "Configure Arguments", CONFIG_ARGS);
    +#endif /* CONFIG_ARGS */
    +
    + _pidgin_about_dialog_load_build_info(about);
    + _pidgin_about_dialog_load_runtime_info(about);
    +}
    +
    +/******************************************************************************
    + * Callbacks
    + *****************************************************************************/
    +static void
    +_pidgin_about_dialog_close(GtkWidget *b, gpointer data) {
    + gtk_widget_destroy(GTK_WIDGET(data));
    +}
    +
    +/******************************************************************************
    + * GObject Stuff
    + *****************************************************************************/
    +G_DEFINE_TYPE_WITH_PRIVATE(PidginAboutDialog, pidgin_about_dialog, GTK_TYPE_DIALOG);
    +
    +static void
    +pidgin_about_dialog_class_init(PidginAboutDialogClass *klass) {
    + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
    +
    + gtk_widget_class_set_template_from_resource(
    + widget_class,
    + "/im/pidgin/Pidgin/About/about.ui"
    + );
    +
    + gtk_widget_class_bind_template_child_private(widget_class, PidginAboutDialog, close_button);
    + gtk_widget_class_bind_template_child_private(widget_class, PidginAboutDialog, application_name);
    + gtk_widget_class_bind_template_child_private(widget_class, PidginAboutDialog, stack);
    +
    + gtk_widget_class_bind_template_child_private(widget_class, PidginAboutDialog, main_scrolled_window);
    +
    + gtk_widget_class_bind_template_child_private(widget_class, PidginAboutDialog, developers_page);
    + gtk_widget_class_bind_template_child_private(widget_class, PidginAboutDialog, developers_store);
    + gtk_widget_class_bind_template_child_private(widget_class, PidginAboutDialog, developers_treeview);
    +
    + gtk_widget_class_bind_template_child_private(widget_class, PidginAboutDialog, translators_page);
    + gtk_widget_class_bind_template_child_private(widget_class, PidginAboutDialog, translators_store);
    + gtk_widget_class_bind_template_child_private(widget_class, PidginAboutDialog, translators_treeview);
    +
    + gtk_widget_class_bind_template_child_private(widget_class, PidginAboutDialog, build_info_page);
    + gtk_widget_class_bind_template_child_private(widget_class, PidginAboutDialog, build_info_store);
    + gtk_widget_class_bind_template_child_private(widget_class, PidginAboutDialog, build_info_treeview);
    +}
    +
    +static void
    +pidgin_about_dialog_init(PidginAboutDialog *about) {
    + about->priv = pidgin_about_dialog_get_instance_private(about);
    +
    + gtk_widget_init_template(GTK_WIDGET(about));
    +
    + /* wire up the close button */
    + g_signal_connect(
    + about->priv->close_button,
    + "clicked",
    + G_CALLBACK(_pidgin_about_dialog_close),
    + about
    + );
    +
    + /* setup the application name label */
    + _pidgin_about_dialog_load_application_name(about);
    +
    + /* setup the main page */
    + _pidgin_about_dialog_load_main_page(about);
    +
    + /* setup the developers stuff */
    + _pidgin_about_dialog_load_developers(about);
    + gtk_tree_view_expand_all(GTK_TREE_VIEW(about->priv->developers_treeview));
    +
    + /* setup the translators stuff */
    + _pidgin_about_dialog_load_translators(about);
    + gtk_tree_view_expand_all(GTK_TREE_VIEW(about->priv->translators_treeview));
    +
    + /* setup the build info page */
    + _pidgin_about_dialog_load_build_configuration(about);
    + gtk_tree_view_expand_all(GTK_TREE_VIEW(about->priv->build_info_treeview));
    +}
    +
    +GtkWidget *
    +pidgin_about_dialog_new(void) {
    + GtkWidget *about = NULL;
    +
    + about = g_object_new(
    + PIDGIN_TYPE_ABOUT_DIALOG,
    + "title", "About Pidgin",
    + NULL
    + );
    +
    + return about;
    +}
    +
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/pidginabout.h Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,25 @@
    +#ifndef PIDGIN_ABOUT_H
    +#define PIDGIN_ABOUT_H
    +
    +#include <gtk/gtk.h>
    +
    +#define PIDGIN_TYPE_ABOUT_DIALOG (pidgin_about_dialog_get_type())
    +#define PIDGIN_ABOUT_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PIDGIN_TYPE_ABOUT_DIALOG, PidginAboutDialog))
    +#define PIDGIN_ABOUT_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PIDGIN_TYPE_ABOUT_DIALOG, PidginAboutDialogClass))
    +#define PIDGIN_IS_ABOUT_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PIDGIN_TYPE_ABOUT_DIALOG))
    +#define PIDGIN_IS_ABOUT_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PIDGIN_TYPE_ABOUT_DIALOG))
    +#define PIDGIN_ABOUT_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PIDGIN_TYPE_ABOUT_DIALOG, PidginAboutDialogClass))
    +
    +typedef struct _PidginAboutDialog PidginAboutDialog;
    +typedef struct _PidginAboutDialogClass PidginAboutDialogClass;
    +typedef struct _PidginAboutDialogPrivate PidginAboutDialogPrivate;
    +
    +G_BEGIN_DECLS
    +
    +GType pidgin_about_dialog_get_type(void);
    +GtkWidget *pidgin_about_dialog_new(void);
    +
    +G_END_DECLS
    +
    +#endif /* PIDGIN_ABOUT_H */
    +
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/pixmaps/dialogs/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,32 @@
    +DIALOGS = [
    + 'auth',
    + 'cool',
    + 'dialog',
    + 'error',
    + 'info',
    + 'mail',
    + 'question',
    + 'warning',
    +]
    +
    +DIALOGS_16_ONLY = [
    + 'auth',
    + 'error',
    + 'info',
    + 'mail',
    + 'question',
    +]
    +
    +foreach dialog : DIALOGS
    + foreach size : ['16', '64', 'scalable']
    + if size == 'scalable'
    + filename = '@0@.svg'.format(dialog)
    + else
    + filename = '@0@.png'.format(dialog)
    + endif
    + if size != '16' or DIALOGS_16_ONLY.contains(dialog)
    + install_data(join_paths(size, filename),
    + install_dir : join_paths(pidginpixmapdir, 'dialogs', size))
    + endif
    + endforeach
    +endforeach
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/pixmaps/emotes/default/24/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,204 @@
    +SMILEYS = [
    + 'act-up.png',
    + 'airplane.png',
    + 'alien.png',
    + 'amorous.png',
    + 'angel.png',
    + 'angry.png',
    + 'arrogant.png',
    + 'at-wits-end.png',
    + 'bad.png',
    + 'bashful.png',
    + 'beat-up.png',
    + 'beauty.png',
    + 'beer.png',
    + 'blowkiss.png',
    + 'bomb.png',
    + 'bored.png',
    + 'bowl.png',
    + 'boy.png',
    + 'brb.png',
    + 'bunny.png',
    + 'bye.png',
    + 'cake.png',
    + 'call-me.png',
    + 'camera.png',
    + 'can.png',
    + 'car.png',
    + 'cat.png',
    + 'chicken.png',
    + 'chilli.png',
    + 'cigarette.png',
    + 'clap.png',
    + 'clock.png',
    + 'cloudy.png',
    + 'clover.png',
    + 'clown.png',
    + 'coffee.png',
    + 'coins.png',
    + 'cold.png',
    + 'computer.png',
    + 'confused.png',
    + 'console.png',
    + 'cowboy.png',
    + 'cow.png',
    + 'crying.png',
    + 'curl-lip.png',
    + 'curse.png',
    + 'cute.png',
    + 'cyclops.png',
    + 'dance.png',
    + 'dazed.png',
    + 'desire.png',
    + 'devil.png',
    + 'disappointed.png',
    + 'disdain.png',
    + 'doctor.png',
    + 'dog.png',
    + 'doh.png',
    + 'dont-know.png',
    + 'drink.png',
    + 'drool.png',
    + 'hungry.png',
    + 'embarrassed.png',
    + 'excited.png',
    + 'excruciating.png',
    + 'eyeroll.png',
    + 'female-fighter.png',
    + 'film.png',
    + 'fingers-crossed.png',
    + 'flag.png',
    + 'foot-in-mouth.png',
    + 'ghost.png',
    + 'giggle.png',
    + 'girl.png',
    + 'glasses-cool.png',
    + 'glasses-nerdy.png',
    + 'goat.png',
    + 'go-away.png',
    + 'good.png',
    + 'hammer.png',
    + 'handcuffs.png',
    + 'handshake.png',
    + 'highfive.png',
    + 'hug-left.png',
    + 'hug-right.png',
    + 'hypnotized.png',
    + 'in_love.png',
    + 'island.png',
    + 'jump.png',
    + 'kissed.png',
    + 'kissing.png',
    + 'kiss.png',
    + 'knife.png',
    + 'lamp.png',
    + 'lashes.png',
    + 'laugh.png',
    + 'liquor.png',
    + 'loser.png',
    + 'love-over.png',
    + 'lying.png',
    + 'mad-tongue.png',
    + 'mail.png',
    + 'male-fighter1.png',
    + 'male-fighter2.png',
    + 'mean.png',
    + 'meeting.png',
    + 'mobile.png',
    + 'moneymouth.png',
    + 'monkey.png',
    + 'moon.png',
    + 'mrgreen.png',
    + 'musical-note.png',
    + 'music.png',
    + 'nervous.png',
    + 'neutral.png',
    + 'on-the-phone.png',
    + 'party.png',
    + 'peace.png',
    + 'phone.png',
    + 'pig.png',
    + 'pill.png',
    + 'pirate.png',
    + 'pissed-off.png',
    + 'pizza.png',
    + 'plate.png',
    + 'poop.png',
    + 'pray.png',
    + 'present.png',
    + 'pumpkin.png',
    + 'question.png',
    + 'quiet.png',
    + 'rainbow.png',
    + 'rain.png',
    + 'rose-dead.png',
    + 'rose.png',
    + 'rotfl.png',
    + 'sad.png',
    + 'sarcastic.png',
    + 'search.png',
    + 'secret.png',
    + 'shame.png',
    + 'sheep.png',
    + 'shocked.png',
    + 'shout.png',
    + 'shut-mouth.png',
    + 'sick.png',
    + 'silly.png',
    + 'skeleton.png',
    + 'skywalker.png',
    + 'sleeping.png',
    + 'sleepy.png',
    + 'happy.png',
    + 'snail.png',
    + 'snicker.png',
    + 'snowman.png',
    + 'soccerball.png',
    + 'soldier.png',
    + 'star.png',
    + 'starving.png',
    + 'stop.png',
    + 'stressed.png',
    + 'struggle.png',
    + 'sun.png',
    + 'hot.png',
    + 'talktohand.png',
    + 'teeth.png',
    + 'terror.png',
    + 'thinking.png',
    + 'thunder.png',
    + 'time-out.png',
    + 'tongue.png',
    + 'afraid.png',
    + 'turtle.png',
    + 'tv.png',
    + 'umbrella.png',
    + 'vampire.png',
    + 'victory.png',
    + 'waiting.png',
    + 'watermelon.png',
    + 'waving.png',
    + 'weep.png',
    + 'wilt.png',
    + 'wink.png',
    + 'worship.png',
    + 'yin-yang.png'
    +]
    +
    +if INSTALL_PIXMAPS
    + pidginsmileypixdir = pidginpixmapdir + '/emotes/default'
    +
    + custom_target('default-theme',
    + input : 'default.theme.in',
    + output : 'theme',
    + capture : true,
    + command : [sedpath,
    + '-e', 's/^_Name=/Name=/',
    + '-e', 's/^_Description=/Description=/',
    + '-e', 's/^_Author=/Author=/',
    + '@INPUT@'],
    + install : true,
    + install_dir : pidginsmileypixdir)
    +
    + install_data(SMILEYS, install_dir : pidginsmileypixdir)
    +endif
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/pixmaps/emotes/small/16/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,104 @@
    +# These are mood images that are NOT also used in the smiley theme.
    +MOODS = [
    + 'afraid.png',
    + 'bathing.png',
    + 'cinema.png',
    + 'disappointed.png',
    + 'embarrassed.png',
    + 'grumpy.png',
    + 'hot.png',
    + 'internet.png',
    + 'invincible.png',
    + 'music.png',
    + 'restroom.png',
    + 'search.png',
    + 'shopping.png',
    + 'studying.png',
    + 'suit.png',
    + 'surfing.png',
    + 'typing.png',
    + 'working.png',
    + 'writing.png'
    +]
    +
    +SMILEYS = [
    + 'amorous.png',
    + 'angel.png',
    + 'angry.png',
    + 'beer.png',
    + 'bored.png',
    + 'boy.png',
    + 'camera.png',
    + 'chilli.png',
    + 'cigarette.png',
    + 'coffee.png',
    + 'confused.png',
    + 'console.png',
    + 'cold.png',
    + 'cross.png',
    + 'crying.png',
    + 'devil.png',
    + 'dont-know.png',
    + 'drool.png',
    + 'excited.png',
    + 'excruciating.png',
    + 'eyeroll.png',
    + 'girl.png',
    + 'glasses-cool.png',
    + 'happy.png',
    + 'hug-left.png',
    + 'hug-right.png',
    + 'hungry.png',
    + 'in_love.png',
    + 'kiss.png',
    + 'lamp.png',
    + 'lying.png',
    + 'meeting.png',
    + 'mobile.png',
    + 'mrgreen.png',
    + 'musical-note.png',
    + 'nerdy.png',
    + 'neutral.png',
    + 'party.png',
    + 'phone.png',
    + 'pirate.png',
    + 'pissed-off.png',
    + 'plate.png',
    + 'question.png',
    + 'rose.png',
    + 'sad.png',
    + 'sarcastic.png',
    + 'shame.png',
    + 'shocked.png',
    + 'shut-mouth.png',
    + 'sick.png',
    + 'silent.png',
    + 'sleeping.png',
    + 'sleepy.png',
    + 'star.png',
    + 'stressed.png',
    + 'thinking.png',
    + 'thunder.png',
    + 'tongue.png',
    + 'tv.png',
    + 'uhm-yeah.png',
    + 'wink.png'
    +]
    +
    +if INSTALL_PIXMAPS
    + pidginsmileypixdir = pidginpixmapdir + '/emotes/small'
    +
    + custom_target('small-theme',
    + input : 'small.theme.in',
    + output : 'theme',
    + capture : true,
    + command : [sedpath,
    + '-e', 's/^_Name=/Name=/',
    + '-e', 's/^_Description=/Description=/',
    + '-e', 's/^_Author=/Author=/',
    + '@INPUT@'],
    + install : true,
    + install_dir : pidginsmileypixdir)
    +
    + install_data(MOODS + SMILEYS, install_dir : pidginsmileypixdir)
    +endif
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/pixmaps/icons/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,14 @@
    +ICONS = [
    + 'pidgin'
    +]
    +
    +foreach icon : ICONS
    + foreach size : [16, 22, 24, 32, 48]
    + path = 'hicolor/@0@x@0@/apps'.format(size)
    + install_data(join_paths(path, '@0@.png'.format(icon)),
    + install_dir : join_paths(get_option('datadir'), 'icons', path))
    + endforeach
    + path = 'hicolor/scalable/apps'
    + install_data(join_paths(path, '@0@.svg'.format(icon)),
    + install_dir : join_paths(get_option('datadir'), 'icons', path))
    +endforeach
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/pixmaps/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,28 @@
    +pidginpixmapdir = get_option('datadir') + '/pixmaps/pidgin'
    +
    +subdir('emotes/default/24')
    +subdir('emotes/small/16')
    +
    +if INSTALL_PIXMAPS
    + install_data('logo.png', 'arrow-down.xpm', 'arrow-left.xpm', 'arrow-right.xpm', 'arrow-up.xpm',
    + install_dir : pidginpixmapdir)
    +
    + # Some of these don't use install_subdir because it deletes the target,
    + # and some target directories probably have something in them, for those
    + # installing somewhere with existing stuff. Additionally, we have
    + # extra stuff in our directories we don't want to install.
    + install_subdir('animations',
    + install_dir : pidginpixmapdir)
    + install_data('edit.png', 'info.png', 'pause.png',
    + install_dir : join_paths(pidginpixmapdir, 'buttons'))
    + subdir('dialogs')
    + install_subdir('e2ee',
    + install_dir : pidginpixmapdir)
    + install_subdir('emblems',
    + install_dir : pidginpixmapdir)
    + subdir('icons')
    + subdir('protocols')
    + subdir('status')
    + subdir('toolbar')
    + subdir('tray')
    +endif
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/pixmaps/protocols/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,10 @@
    +foreach dir : ['16', '22', '48', 'scalable']
    + if dir == 'scalable'
    + install_subdir(dir,
    + install_dir : join_paths(pidginpixmapdir, 'protocols'))
    + else
    + install_subdir(dir,
    + exclude_directories : 'scalable',
    + install_dir : join_paths(pidginpixmapdir, 'protocols'))
    + endif
    +endforeach
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/pixmaps/status/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,4 @@
    +foreach dir : ['11', '16', '22', '32', '48']
    + install_subdir(dir,
    + install_dir: join_paths(pidginpixmapdir, 'status'))
    +endforeach
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/pixmaps/toolbar/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,5 @@
    +foreach dir : ['11', '16', '22', '32', '48']
    + install_subdir(dir,
    + exclude_directories : 'scalable',
    + install_dir: join_paths(pidginpixmapdir, 'toolbar'))
    +endforeach
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/pixmaps/tray/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,33 @@
    +TRAY = [
    + 'pidgin-tray-available',
    + 'pidgin-tray-away',
    + 'pidgin-tray-busy',
    + 'pidgin-tray-connect',
    + 'pidgin-tray-email',
    + 'pidgin-tray-invisible',
    + 'pidgin-tray-offline',
    + 'pidgin-tray-pending',
    + 'pidgin-tray-xa',
    +]
    +
    +install_subdir('16',
    + install_dir : pidginpixmapdir + '/tray')
    +
    +install_data('hicolor/index.theme',
    + install_dir : pidginpixmapdir + '/tray/hicolor')
    +if ENABLE_TRAYCOMPAT
    + # Install in a location compatible with hicolor-icon-theme 0.9
    + subdir = 'actions'
    +else
    + # Install in the "correct" locations
    + subdir = 'status'
    +endif
    +foreach tray : TRAY
    + filename = '@0@.png'.format(tray)
    + foreach size : [16, 22, 32, 48]
    + size = '@0@x@0@'.format(size)
    + inpath = join_paths('hicolor', size, 'status', filename)
    + outpath = join_paths(pidginpixmapdir, 'tray', 'hicolor', size, subdir)
    + install_data(inpath, install_dir : outpath)
    + endforeach
    +endforeach
    --- a/pidgin/plugins/cap/cap.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/plugins/cap/cap.c Sun Oct 08 20:44:26 2017 +0300
    @@ -130,7 +130,7 @@
    /* g_free(stats->hourly_usage); */
    /* g_free(stats->daily_usage); */
    if (stats->timeout_source_id != 0)
    - purple_timeout_remove(stats->timeout_source_id);
    + g_source_remove(stats->timeout_source_id);
    g_free(stats);
    }
    @@ -359,9 +359,9 @@
    stats->last_message = time(NULL);
    stats->last_message_status_id = purple_status_get_id(get_status_for(buddy));
    if(stats->timeout_source_id != 0)
    - purple_timeout_remove(stats->timeout_source_id);
    + g_source_remove(stats->timeout_source_id);
    - stats->timeout_source_id = purple_timeout_add_seconds(interval, max_message_difference_cb, stats);
    + stats->timeout_source_id = g_timeout_add_seconds(interval, max_message_difference_cb, stats);
    }
    /* received-im-msg */
    @@ -387,7 +387,7 @@
    * then cancel the timeout callback. */
    if(stats->timeout_source_id != 0) {
    purple_debug_info("cap", "Cancelling timeout callback\n");
    - purple_timeout_remove(stats->timeout_source_id);
    + g_source_remove(stats->timeout_source_id);
    stats->timeout_source_id = 0;
    }
    @@ -678,7 +678,7 @@
    static void cancel_conversation_timeouts(gpointer key, gpointer value, gpointer user_data) {
    CapStatistics *stats = value;
    if(stats->timeout_source_id != 0) {
    - purple_timeout_remove(stats->timeout_source_id);
    + g_source_remove(stats->timeout_source_id);
    stats->timeout_source_id = 0;
    }
    }
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/plugins/cap/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,6 @@
    +if PLUGINS
    + cap = library('cap', 'cap.c', 'cap.h', 'cap_statistics.h',
    + dependencies : [SQLITE3, libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    +endif
    --- a/pidgin/plugins/disco/gtkdisco.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/plugins/disco/gtkdisco.c Sun Oct 08 20:44:26 2017 +0300
    @@ -282,7 +282,7 @@
    GtkTreeIter iter;
    GValue val;
    - if (event->button != 3 || event->type != GDK_BUTTON_PRESS)
    + if (!gdk_event_triggers_context_menu((GdkEvent *)event))
    return FALSE;
    pdl = user_data;
    @@ -315,8 +315,7 @@
    }
    gtk_widget_show_all(menu);
    - gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button,
    - event->time);
    + gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
    return FALSE;
    }
    @@ -535,7 +534,6 @@
    );
    pdl->tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pdl->model));
    - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(pdl->tree), TRUE);
    selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pdl->tree));
    g_signal_connect(G_OBJECT(selection), "changed",
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/plugins/disco/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,13 @@
    +xmppdisco_SOURCES = [
    + 'gtkdisco.c',
    + 'gtkdisco.h',
    + 'xmppdisco.c',
    + 'xmppdisco.h'
    +]
    +
    +if PLUGINS
    + xmppdisco = library('xmppdisco', xmppdisco_SOURCES,
    + dependencies : [libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    +endif
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/plugins/gestures/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,14 @@
    +gestures_SOURCES = [
    + 'gestures.c',
    + 'gstroke.h',
    + 'gstroke-internal.h',
    + 'stroke.c',
    + 'stroke-draw.c'
    +]
    +
    +if PLUGINS
    + gestures = library('gestures', gestures_SOURCES,
    + dependencies : [x11, libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    +endif
    --- a/pidgin/plugins/gevolution/add_buddy_dialog.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/plugins/gevolution/add_buddy_dialog.c Sun Oct 08 20:44:26 2017 +0300
    @@ -508,7 +508,6 @@
    /* Now for the treeview */
    dialog->treeview =
    gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model));
    - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(dialog->treeview), TRUE);
    gtk_box_pack_start(GTK_BOX(vbox),
    pidgin_make_scrollable(dialog->treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1),
    TRUE, TRUE, 0);
    --- a/pidgin/plugins/gevolution/assoc-buddy.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/plugins/gevolution/assoc-buddy.c Sun Oct 08 20:44:26 2017 +0300
    @@ -396,7 +396,6 @@
    /* Now for the treeview */
    dialog->treeview = gtk_tree_view_new_with_model(
    GTK_TREE_MODEL(dialog->model));
    - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(dialog->treeview), TRUE);
    gtk_box_pack_start(GTK_BOX(vbox),
    pidgin_make_scrollable(dialog->treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1),
    TRUE, TRUE, 0);
    --- a/pidgin/plugins/gevolution/gevolution.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/plugins/gevolution/gevolution.c Sun Oct 08 20:44:26 2017 +0300
    @@ -393,7 +393,6 @@
    /* Setup the treeview */
    treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
    - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
    gtk_box_pack_start(GTK_BOX(vbox),
    pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC,
    GTK_POLICY_ALWAYS, GTK_SHADOW_IN, 300, 300), TRUE, TRUE, 0);
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/plugins/gevolution/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,16 @@
    +gevolution_SOURCES = [
    + 'add_buddy_dialog.c',
    + 'assoc-buddy.c',
    + 'gevolution.c',
    + 'gevolution.h',
    + 'gevo-util.c',
    + 'new_person_dialog.c',
    + 'eds-utils.c'
    +]
    +
    +if PLUGINS
    + gevolution = library('gevolution', gevolution_SOURCES,
    + dependencies : EVOLUTION_ADDRESSBOOK + [libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    +endif
    --- a/pidgin/plugins/history.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/plugins/history.c Sun Oct 08 20:44:26 2017 +0300
    @@ -48,7 +48,8 @@
    char *protocol;
    #endif
    char *escaped_alias;
    - const char *header_date;
    + GDateTime *dt;
    + gchar *header_date;
    gtkconv = PIDGIN_CONVERSATION(c);
    g_return_if_fail(gtkconv != NULL);
    @@ -141,13 +142,13 @@
    escaped_alias = g_markup_escape_text(alias, -1);
    - if (((PurpleLog *)logs->data)->tm)
    - header_date = purple_date_format_full(((PurpleLog *)logs->data)->tm);
    - else
    - header_date = purple_date_format_full(localtime(&((PurpleLog *)logs->data)->time));
    + dt = g_date_time_to_local(((PurpleLog *)logs->data)->time);
    + header_date = g_date_time_format(dt, "%c");
    + g_date_time_unref(dt);
    header = g_strdup_printf(_("<b>Conversation with %s on %s:</b><br>"), escaped_alias, header_date);
    pidgin_webview_append_html(PIDGIN_WEBVIEW(gtkconv->webview), header);
    + g_free(header_date);
    g_free(header);
    g_free(escaped_alias);
    --- a/pidgin/plugins/mailchk.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/plugins/mailchk.c Sun Oct 08 20:44:26 2017 +0300
    @@ -94,7 +94,7 @@
    PurpleBuddyList *list = purple_blist_get_buddy_list();
    if (list && !timer) {
    check_timeout(NULL); /* we want the box to be drawn immediately */
    - timer = purple_timeout_add_seconds(2, check_timeout, NULL);
    + timer = g_timeout_add_seconds(2, check_timeout, NULL);
    }
    }
    @@ -103,7 +103,7 @@
    {
    PurpleBuddyList *list = purple_blist_get_buddy_list();
    if ((!list || !PIDGIN_BLIST(list)->vbox) && timer) {
    - purple_timeout_remove(timer);
    + g_source_remove(timer);
    timer = 0;
    }
    }
    @@ -148,7 +148,7 @@
    }
    if (list && PIDGIN_BLIST(list)->vbox)
    - timer = purple_timeout_add_seconds(2, check_timeout, NULL);
    + timer = g_timeout_add_seconds(2, check_timeout, NULL);
    purple_signal_connect(conn_handle, "signed-on",
    plugin, PURPLE_CALLBACK(signon_cb), NULL);
    @@ -162,7 +162,7 @@
    plugin_unload(PurplePlugin *plugin, GError **error)
    {
    if (timer)
    - purple_timeout_remove(timer);
    + g_source_remove(timer);
    timer = 0;
    if (mail)
    gtk_widget_destroy(mail);
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/plugins/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,105 @@
    +if enable_gevolution
    + subdir('gevolution')
    +endif
    +
    +if enable_dbus
    + subdir('musicmessaging')
    +endif
    +
    +if enable_cap
    + subdir('cap')
    +endif
    +
    +if enable_gestures
    + subdir('gestures')
    +endif
    +
    +subdir('disco')
    +subdir('ticker')
    +
    +if IS_WIN32
    + subdir('win32/winprefs')
    + subdir('win32/transparency')
    +endif
    +
    +if PLUGINS
    + contact_priority = library('contact_priority', 'contact_priority.c',
    + dependencies : [libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '')
    +
    + extplacement = library('extplacement', 'extplacement.c',
    + dependencies : [libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    +
    + gtkbuddynote = library('gtkbuddynote', 'gtkbuddynote.c',
    + dependencies : [libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    +
    + gtk_signals_test = library('gtk_signals_test', 'gtk-signals-test.c',
    + dependencies : [libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '')
    +
    + history = library('history', 'history.c',
    + dependencies : [libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    +
    + iconaway = library('iconaway', 'iconaway.c',
    + dependencies : [libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    +
    + imgupload = library('imgupload', 'imgupload.c',
    + dependencies : [json, libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    +
    + markerline = library('markerline', 'markerline.c',
    + dependencies : [webkit, libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    +
    + notify = library('notify', 'notify.c',
    + dependencies : [libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    +
    + relnot = library('relnot', 'relnot.c',
    + dependencies : [libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    +
    + screencap = library('screencap', 'screencap.c',
    + dependencies : [libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    +
    + sendbutton = library('sendbutton', 'sendbutton.c',
    + dependencies : [libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    +
    + spellchk = library('spellchk', 'spellchk.c',
    + dependencies : [libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    +
    + webkit_plugin = library('webkit', 'webkit.c',
    + dependencies : [webkit, libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    +
    + xmppconsole = library('xmppconsole', 'xmppconsole.c',
    + dependencies : [libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    +
    + if enable_unity
    + unity = library('unity', 'unity.c',
    + dependencies : [UNITY, libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    + endif
    +endif # PLUGINS
    --- a/pidgin/plugins/musicmessaging/Makefile.am Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/plugins/musicmessaging/Makefile.am Sun Oct 08 20:44:26 2017 +0300
    @@ -18,18 +18,18 @@
    musicmessaging_la_LIBADD = @PIDGIN_LIBS@ $(DBUS_LIBS)
    -CLEANFILES = music-messaging-bindings.c
    +CLEANFILES = music-messaging-bindings.ch
    .PHONY: always
    $(top_builddir)/libpurple/dbus-types.h: always
    $(AM_V_GEN)cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F)
    -music-messaging-bindings.c: $(top_srcdir)/libpurple/dbus-analyze-functions.py $(musicmessaging_la_SOURCES)
    +music-messaging-bindings.ch: $(top_srcdir)/libpurple/dbus-analyze-functions.py $(musicmessaging_la_SOURCES)
    $(AM_V_GEN)cat $(srcdir)/$(musicmessaging_la_SOURCES) | \
    $(PYTHON) $(top_srcdir)/libpurple/dbus-analyze-functions.py --export-only > $@
    -$(musicmessaging_la_OBJECTS) musicmessaging.so: music-messaging-bindings.c $(top_builddir)/libpurple/dbus-types.h
    +$(musicmessaging_la_OBJECTS) musicmessaging.so: music-messaging-bindings.ch $(top_builddir)/libpurple/dbus-types.h
    endif
    endif
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/plugins/musicmessaging/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,14 @@
    +if PLUGINS and enable_dbus
    + install_data('music.png',
    + install_dir : get_option('datadir') + '/pixmaps/pidgin/buttons')
    +
    + music_messaging_bindings = custom_target('music_messaging_bindings.c',
    + command : [python, dbus_analyze_functions, '--export-only', '-o', '@OUTPUT@', '@INPUT@'],
    + input : 'musicmessaging.c',
    + output : 'music-messaging-bindings.ch')
    +
    + musicmessaging = library('musicmessaging', 'musicmessaging.c', music_messaging_bindings,
    + dependencies : [dbus, libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    +endif
    --- a/pidgin/plugins/musicmessaging/musicmessaging.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/plugins/musicmessaging/musicmessaging.c Sun Oct 08 20:44:26 2017 +0300
    @@ -103,7 +103,7 @@
    /* This file has been generated by the #dbus-analize-functions.py
    script. It contains dbus wrappers for the four functions declared
    above. */
    -#include "music-messaging-bindings.c"
    +#include "music-messaging-bindings.ch"
    /* Exported functions */
    DBUS_EXPORT void
    --- a/pidgin/plugins/screencap.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/plugins/screencap.c Sun Oct 08 20:44:26 2017 +0300
    @@ -666,7 +666,7 @@
    return;
    is_shooting = TRUE;
    - shooting_timeout = purple_timeout_add(SCRNCAP_SHOOTING_TIMEOUT,
    + shooting_timeout = g_timeout_add(SCRNCAP_SHOOTING_TIMEOUT,
    scrncap_do_screenshot_cb, webview);
    }
    @@ -979,7 +979,7 @@
    GList *it;
    if (shooting_timeout > 0)
    - purple_timeout_remove(shooting_timeout);
    + g_source_remove(shooting_timeout);
    if (current_window != NULL)
    gtk_widget_destroy(GTK_WIDGET(current_window));
    --- a/pidgin/plugins/spellchk.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/plugins/spellchk.c Sun Oct 08 20:44:26 2017 +0300
    @@ -2136,7 +2136,6 @@
    gtk_widget_show(vbox);
    tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
    - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree), TRUE);
    gtk_widget_set_size_request(tree, -1, 200);
    renderer = gtk_cell_renderer_text_new();
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/plugins/ticker/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,12 @@
    +ticker_SOURCES = [
    + 'gtkticker.c',
    + 'gtkticker.h',
    + 'ticker.c'
    +]
    +
    +if PLUGINS
    + ticker = library('ticker', ticker_SOURCES,
    + dependencies : [libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    +endif
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/plugins/win32/transparency/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,4 @@
    +win2ktrans = library('win2ktrans', 'win2ktrans.c',
    + dependencies : [libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/plugins/win32/winprefs/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,10 @@
    +winprefs_SOURCES = [
    + 'gtkappbar.c',
    + 'gtkappbar.h',
    + 'winprefs.c'
    +]
    +
    +winprefs = library('winprefs', winprefs_SOURCES,
    + dependencies : [libpurple_dep, libpidgin_dep, glib],
    + name_prefix : '',
    + install : true, install_dir : PIDGIN_PLUGINDIR)
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/pidgin/themes/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,6 @@
    +themetemplatedir = get_option('datadir') + '/pidgin/theme'
    +
    +install_data('Template.html',
    + install_dir : themetemplatedir)
    +install_subdir('Contents',
    + install_dir : themetemplatedir)
    --- a/pidgin/win32/gtkdocklet-win32.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/win32/gtkdocklet-win32.c Sun Oct 08 20:44:26 2017 +0300
    @@ -85,11 +85,11 @@
    /* We'll use Double Click - Single click over on linux */
    if(lparam == WM_LBUTTONDBLCLK)
    - type = 1;
    + type = GDK_BUTTOM_PRIMARY;
    else if(lparam == WM_MBUTTONUP)
    - type = 2;
    + type = GDK_BUTTON_MIDDLE;
    else if(lparam == WM_RBUTTONUP)
    - type = 3;
    + type = GDK_BUTTON_SECONDARY;
    else
    break;
    --- a/pidgin/win32/gtkwin32dep.c Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/win32/gtkwin32dep.c Sun Oct 08 20:44:26 2017 +0300
    @@ -1,7 +1,4 @@
    -/**
    - * @file gtkwin32dep.c UI Win32 Specific Functionality
    - * @ingroup win32
    - *
    +/*
    * 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.
    @@ -39,7 +36,6 @@
    #include "network.h"
    #include "resource.h"
    -#include "zlib.h"
    #include "untar.h"
    #include "gtkwin32dep.h"
    @@ -76,36 +72,59 @@
    }
    int winpidgin_gz_decompress(const char* in, const char* out) {
    - gzFile fin;
    - FILE *fout;
    - char buf[1024];
    - int ret;
    + GFile *fin;
    + GFile *fout;
    + GInputStream *input;
    + GOutputStream *output;
    + GOutputStream *conv_out;
    + GZlibDecompressor *decompressor;
    + gssize size;
    + GError *error = NULL;
    - if((fin = gzopen(in, "rb"))) {
    - if(!(fout = g_fopen(out, "wb"))) {
    - purple_debug_error("winpidgin_gz_decompress", "Error opening file: %s\n", out);
    - gzclose(fin);
    - return 0;
    - }
    - }
    - else {
    - purple_debug_error("winpidgin_gz_decompress", "gzopen failed to open: %s\n", in);
    + fin = g_file_new_for_path(in);
    + input = G_INPUT_STREAM(g_file_read(fin, NULL, &error));
    + g_object_unref(fin);
    +
    + if (input == NULL) {
    + purple_debug_error("winpidgin_gz_decompress",
    + "Failed to open: %s: %s\n",
    + in, error->message);
    + g_clear_error(&error);
    return 0;
    }
    - while((ret = gzread(fin, buf, 1024))) {
    - if ((int)fwrite(buf, 1, ret, fout) < ret) {
    - purple_debug_error("wpurple_gz_decompress", "Error writing %d bytes to file\n", ret);
    - gzclose(fin);
    - fclose(fout);
    - return 0;
    - }
    + fout = g_file_new_for_path(out);
    + output = G_OUTPUT_STREAM(g_file_replace(fout, NULL, FALSE,
    + G_FILE_CREATE_NONE, NULL, &error));
    + g_object_unref(fout);
    +
    + if (output == NULL) {
    + purple_debug_error("winpidgin_gz_decompress",
    + "Error opening file: %s: %s\n",
    + out, error->message);
    + g_clear_error(&error);
    + g_object_unref(input);
    + return 0;
    }
    - fclose(fout);
    - gzclose(fin);
    +
    + decompressor = g_zlib_decompressor_new(G_ZLIB_COMPRESSOR_FORMAT_GZIP);
    + conv_out = g_converter_output_stream_new(output,
    + G_CONVERTER(decompressor));
    + g_object_unref(decompressor);
    + g_object_unref(output);
    - if(ret < 0) {
    - purple_debug_error("winpidgin_gz_decompress", "gzread failed while reading: %s\n", in);
    + size = g_output_stream_splice(conv_out, input,
    + G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
    + G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, NULL, &error);
    +
    + g_object_unref(input);
    + g_object_unref(conv_out);
    +
    + if (size < 0) {
    + purple_debug_error("wpurple_gz_decompress",
    + "Error writing to file: %s\n",
    + error->message);
    + g_clear_error(&error);
    return 0;
    }
    @@ -247,7 +266,7 @@
    } else if (wparam == PBT_APMRESUMESUSPEND) {
    purple_debug_info("winpidgin", "Resuming from system standby.\n");
    /* TODO: It seems like it'd be wise to use the NLA message, if possible, instead of this. */
    - purple_timeout_add_seconds(1, winpidgin_pwm_reconnect, NULL);
    + g_timeout_add_seconds(1, winpidgin_pwm_reconnect, NULL);
    return TRUE;
    }
    }
    --- a/pidgin/win32/gtkwin32dep.h Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/win32/gtkwin32dep.h Sun Oct 08 20:44:26 2017 +0300
    @@ -1,7 +1,4 @@
    -/**
    - * @file gtkwin32dep.h UI Win32 Specific Functionality
    - * @ingroup win32
    - *
    +/*
    * 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
    @@ -22,6 +19,12 @@
    */
    #ifndef _GTKWIN32DEP_H_
    #define _GTKWIN32DEP_H_
    +/**
    + * SECTION:gtkwin32dep
    + * @section_id: pidgin-gtkwin32dep
    + * @short_description: <filename>gtkwin32dep.h</filename>
    + * @title: UI Win32 Specific Functionality
    + */
    #include <config.h>
    --- a/pidgin/win32/pidgin_dll_rc.rc.in Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/win32/pidgin_dll_rc.rc.in Sun Oct 08 20:44:26 2017 +0300
    @@ -30,11 +30,11 @@
    END
    END
    -PIDGIN_TRAY_AVAILABLE_4BIT ICON "pixmaps/tray/16/available_4bit.ico"
    -PIDGIN_TRAY_AWAY_4BIT ICON "pixmaps/tray/16/away_4bit.ico"
    -PIDGIN_TRAY_BUSY_4BIT ICON "pixmaps/tray/16/busy_4bit.ico"
    -PIDGIN_TRAY_XA_4BIT ICON "pixmaps/tray/16/extended-away_4bit.ico"
    -PIDGIN_TRAY_OFFLINE_4BIT ICON "pixmaps/tray/16/offline_4bit.ico"
    -PIDGIN_TRAY_CONNECTING_4BIT ICON "pixmaps/tray/16/connecting_4bit.ico"
    -PIDGIN_TRAY_PENDING_4BIT ICON "pixmaps/tray/16/message_4bit.ico"
    -PIDGIN_TRAY_INVISIBLE_4BIT ICON "pixmaps/tray/16/invisible_4bit.ico"
    +PIDGIN_TRAY_AVAILABLE_4BIT ICON "../pixmaps/tray/16/available_4bit.ico"
    +PIDGIN_TRAY_AWAY_4BIT ICON "../pixmaps/tray/16/away_4bit.ico"
    +PIDGIN_TRAY_BUSY_4BIT ICON "../pixmaps/tray/16/busy_4bit.ico"
    +PIDGIN_TRAY_XA_4BIT ICON "../pixmaps/tray/16/extended-away_4bit.ico"
    +PIDGIN_TRAY_OFFLINE_4BIT ICON "../pixmaps/tray/16/offline_4bit.ico"
    +PIDGIN_TRAY_CONNECTING_4BIT ICON "../pixmaps/tray/16/connecting_4bit.ico"
    +PIDGIN_TRAY_PENDING_4BIT ICON "../pixmaps/tray/16/message_4bit.ico"
    +PIDGIN_TRAY_INVISIBLE_4BIT ICON "../pixmaps/tray/16/invisible_4bit.ico"
    --- a/pidgin/win32/pidgin_exe_rc.rc.in Fri Jul 07 11:50:28 2017 +0300
    +++ b/pidgin/win32/pidgin_exe_rc.rc.in Sun Oct 08 20:44:26 2017 +0300
    @@ -30,4 +30,4 @@
    END
    END
    -PIDGIN_ICON ICON "pixmaps/pidgin.ico"
    +PIDGIN_ICON ICON "../pixmaps/pidgin.ico"
    --- a/po/POTFILES.in Fri Jul 07 11:50:28 2017 +0300
    +++ b/po/POTFILES.in Sun Oct 08 20:44:26 2017 +0300
    @@ -45,7 +45,7 @@
    libpurple/connection.c
    libpurple/conversation.c
    libpurple/conversationtypes.c
    -libpurple/data/purple-url-handler.desktop.in
    +libpurple/data/purple-url-handler.desktop.in.in
    libpurple/dbus-server.c
    libpurple/dbus-server.h
    libpurple/http.c
    @@ -168,8 +168,10 @@
    libpurple/win32/libc_interface.c
    libpurple/xfer.c
    libpurple/xmlnode.c
    -pidgin/data/pidgin.appdata.xml.in
    -pidgin/data/pidgin.desktop.in
    +[type: gettext/glade]pidgin/about.ui
    +pidgin/credits.json
    +pidgin/data/im.pidgin.Pidgin.appdata.xml.in
    +pidgin/data/im.pidgin.Pidgin.desktop.in.in
    pidgin/gtkaccount.c
    pidgin/gtkblist-theme.c
    pidgin/gtkblist.c
    @@ -199,6 +201,7 @@
    pidgin/gtkxfer.c
    pidgin/libpidgin.c
    pidgin/pidgin.h
    +pidgin/pidginabout.c
    pidgin/pidginstock.c
    pidgin/pidgintooltip.c
    pidgin/pixmaps/emotes/default/24/default.theme.in
    --- a/po/POTFILES.skip Fri Jul 07 11:50:28 2017 +0300
    +++ b/po/POTFILES.skip Sun Oct 08 20:44:26 2017 +0300
    @@ -1,6 +1,6 @@
    -libpurple/data/purple-url-handler.desktop.in.in
    +libpurple/data/purple-url-handler.desktop.in
    libpurple/protocols/null/nullprpl.c
    -pidgin/data/pidgin.desktop.in.in
    +pidgin/data/im.pidgin.Pidgin.desktop.in
    sub/libpurple/data/purple-url-handler.desktop.in
    sub/libpurple/protocols/null/nullprpl.c
    -sub/pidgin/data/pidgin.desktop.in
    +sub/pidgin/data/im.pidgin.Pidgin.desktop.in
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/po/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,5 @@
    +i18n = import('i18n')
    +
    +ALL_LINGUAS='af am ar as ast az be@latin bg bn_IN bn br brx bs ca ca@valencia cs da de dz el en_AU en_CA en_GB eo es_AR es et eu fa fi fr ga gl gu he hi hr hu id it ja ka kk km kn ko ks ku_IQ ku lt lv mai mhr mk ml mn mr ms_MY my_MM nb ne nl nn oc or pa pl ps pt_BR pt ro ru sd si sk sl sq sr@latin sr sv sw ta te th tr tt uk ur uz vi xh zh_CN zh_HK zh_TW'.split()
    +
    +i18n.gettext('pidgin', languages : ALL_LINGUAS)
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/share/ca-certs/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,18 @@
    +CERTIFICATES = [
    + 'CAcert_Root.pem',
    + 'CAcert_Class3.pem',
    + 'mozilla.pem'
    +]
    +
    +EXTRA_CERTS = [
    +# 'filename.pem'
    +]
    +
    +if INSTALL_SSL_CERTIFICATES
    + cacerts_DATA = CERTIFICATES + EXTRA_CERTS
    +else
    + cacerts_DATA = EXTRA_CERTS
    +endif
    +
    +install_data(sources : cacerts_DATA,
    + install_dir : get_option('datadir') + '/purple/ca-certs')
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/share/sounds/meson.build Sun Oct 08 20:44:26 2017 +0300
    @@ -0,0 +1,10 @@
    +sounds_DATA = [
    + 'alert.wav',
    + 'login.wav',
    + 'logout.wav',
    + 'receive.wav',
    + 'send.wav'
    +]
    +
    +install_data(sources : sounds_DATA,
    + install_dir : get_option('datadir') + '/sounds/purple')