pidgin/pidgin

Manual merge. Only 1 conflict, in ChangeLog
release-2.x.y
2014-01-09, Mark Doliner
829e8731d60c
Manual merge. Only 1 conflict, in ChangeLog
--- a/.hgignore Thu Jan 09 20:19:29 2014 -0800
+++ b/.hgignore Thu Jan 09 21:12:37 2014 -0800
@@ -87,6 +87,7 @@
pidgin-.*.tar.gz
pidgin.apspec$
pidgin.desktop$
+pidgin.desktop.in$
pidgin.spec$
pidgin/pidgin$
pidgin/pixmaps/emotes/default/24/theme
@@ -112,4 +113,5 @@
po/pidgin.pot
po/stamp-it
stamp-h1
+test-driver
win32-install-dir(\.release)?
--- a/ChangeLog Thu Jan 09 20:19:29 2014 -0800
+++ b/ChangeLog Thu Jan 09 21:12:37 2014 -0800
@@ -1,12 +1,18 @@
Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
version 2.10.8:
+ Stock market:
+ * Ludicrous increases on mediocre worldwide economic data.
+
libpurple:
* Impose maximum download size for all HTTP fetches.
General:
* Add support for Python3 in build scripts. (Ashish Gupta) (#15624)
+ Pidgin:
+ * Add Unity integration plugin.
+
AIM and ICQ:
* Fix a possible crash when receiving a malformed message in a Direct IM
session.
@@ -17,7 +23,7 @@
Windows-Specific Changes:
* Updates to dependencies:
- * NSS 3.15.2 and NSPR 4.10.1
+ * NSS 3.15.3 and NSPR 4.10.2
version 2.10.7 (02/13/2013):
Alien hatchery:
--- a/configure.ac Thu Jan 09 20:19:29 2014 -0800
+++ b/configure.ac Thu Jan 09 21:12:37 2014 -0800
@@ -1391,6 +1391,26 @@
fi
dnl #######################################################################
+dnl # Check for Unity and Messaging Menu
+dnl #######################################################################
+AC_ARG_ENABLE(unity, [AC_HELP_STRING([--enable-unity],
+ [compile with support for unity integration plugin])], enable_unity="$enableval", enable_unity="no")
+if test "$enable_unity" = yes; then
+ PKG_CHECK_MODULES(UNITY, [unity >= 6.8 messaging-menu >= 12.10], , [
+ AC_MSG_RESULT(no)
+ AC_MSG_ERROR([
+You must have libunity9 >= 6.8 and libmessaging-menu >= 12.10 to build the unity integration plugin.
+ ])])
+ USES_MM_CHAT_SECTION="X-MessagingMenu-UsesChatSection=true"
+ AC_SUBST(UNITY_CFLAGS)
+ AC_SUBST(UNITY_LIBS)
+ AC_SUBST(USES_MM_CHAT_SECTION)
+else
+ enable_unity=no
+fi
+AM_CONDITIONAL(ENABLE_UNITY, [test "x$enable_unity" = "xyes"])
+
+dnl #######################################################################
dnl # Check for Python
dnl #######################################################################
@@ -2604,6 +2624,7 @@
finch/libgnt/wms/Makefile
finch/plugins/Makefile
po/Makefile.in
+ pidgin.desktop.in
pidgin.spec
])
AC_OUTPUT
@@ -2645,6 +2666,7 @@
echo Use X Session Management...... : $enable_sm
echo Use startup notification...... : $enable_startup_notification
echo Build with GtkSpell support... : $enable_gtkspell
+echo Build Unity integration plugin.: $enable_unity
echo
echo Build with plugin support..... : $enable_plugins
echo Build with Mono support....... : $enable_mono
--- a/libpurple/ciphers/Makefile.am Thu Jan 09 20:19:29 2014 -0800
+++ b/libpurple/ciphers/Makefile.am Thu Jan 09 21:12:37 2014 -0800
@@ -10,8 +10,7 @@
sha1.c \
sha256.c
-INCLUDES = -I$(top_srcdir)/libpurple
-
AM_CPPFLAGS = \
+ -I$(top_srcdir)/libpurple \
$(GLIB_CFLAGS)
--- a/libpurple/plugins/ssl/ssl-nss.c Thu Jan 09 20:19:29 2014 -0800
+++ b/libpurple/plugins/ssl/ssl-nss.c Thu Jan 09 21:12:37 2014 -0800
@@ -155,74 +155,24 @@
}
static SECStatus
-ssl_auth_cert(void *arg, PRFileDesc *socket, PRBool checksig,
- PRBool is_server)
-{
- return SECSuccess;
-
-#if 0
- CERTCertificate *cert;
- void *pinArg;
- SECStatus status;
-
- cert = SSL_PeerCertificate(socket);
- pinArg = SSL_RevealPinArg(socket);
-
- status = CERT_VerifyCertNow((CERTCertDBHandle *)arg, cert, checksig,
- certUsageSSLClient, pinArg);
-
- if (status != SECSuccess) {
- purple_debug_error("nss", "CERT_VerifyCertNow failed\n");
- CERT_DestroyCertificate(cert);
- return status;
- }
-
- CERT_DestroyCertificate(cert);
- return SECSuccess;
-#endif
-}
-
-#if 0
-static SECStatus
-ssl_bad_cert(void *arg, PRFileDesc *socket)
+ssl_auth_cert(void *arg, PRFileDesc *socket, PRBool checksig, PRBool is_server)
{
- SECStatus status = SECFailure;
- PRErrorCode err;
-
- if (arg == NULL)
- return status;
-
- *(PRErrorCode *)arg = err = PORT_GetError();
-
- switch (err)
- {
- case SEC_ERROR_INVALID_AVA:
- case SEC_ERROR_INVALID_TIME:
- case SEC_ERROR_BAD_SIGNATURE:
- case SEC_ERROR_EXPIRED_CERTIFICATE:
- case SEC_ERROR_UNKNOWN_ISSUER:
- case SEC_ERROR_UNTRUSTED_CERT:
- case SEC_ERROR_CERT_VALID:
- case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
- case SEC_ERROR_CRL_EXPIRED:
- case SEC_ERROR_CRL_BAD_SIGNATURE:
- case SEC_ERROR_EXTENSION_VALUE_INVALID:
- case SEC_ERROR_CA_CERT_INVALID:
- case SEC_ERROR_CERT_USAGES_INVALID:
- case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION:
- status = SECSuccess;
- break;
-
- default:
- status = SECFailure;
- break;
- }
-
- purple_debug_error("nss", "Bad certificate: %d\n", err);
-
- return status;
+ /* We just skip cert verification here, and will verify the whole chain
+ * in ssl_nss_handshake_cb, after the handshake is complete.
+ *
+ * The problem is, purple_certificate_verify is asynchronous and
+ * ssl_auth_cert should return the result synchronously (it may ask the
+ * user, if an unknown certificate should be trusted or not).
+ *
+ * Ideally, SSL_AuthCertificateHook/ssl_auth_cert should decide
+ * immediately, if the certificate chain is already trusted and possibly
+ * SSL_BadCertHook to deal with unknown certificates.
+ *
+ * Current implementation may not be ideal, but is no less secure in
+ * terms of MITM attack.
+ */
+ return SECSuccess;
}
-#endif
static gboolean
ssl_nss_init(void)
@@ -362,7 +312,10 @@
purple_certificate_destroy_list(peers);
} else {
/* Otherwise, just call the "connection complete"
- callback */
+ * callback. The verification was already done with
+ * SSL_AuthCertificate, the default verifier
+ * (SSL_AuthCertificateHook was not called in ssl_nss_connect).
+ */
gsc->connect_cb(gsc->connect_cb_data, gsc, cond);
}
}
@@ -427,13 +380,10 @@
SSL_OptionSet(nss_data->in, SSL_SECURITY, PR_TRUE);
SSL_OptionSet(nss_data->in, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE);
- SSL_AuthCertificateHook(nss_data->in,
- (SSLAuthCertificate)ssl_auth_cert,
- (void *)CERT_GetDefaultCertDB());
-#if 0
- /* No point in hooking BadCert, since ssl_auth_cert always succeeds */
- SSL_BadCertHook(nss_data->in, (SSLBadCertHandler)ssl_bad_cert, NULL);
-#endif
+ /* If we have our internal verifier set up, use it. Otherwise,
+ * use default. */
+ if (gsc->verifier != NULL)
+ SSL_AuthCertificateHook(nss_data->in, ssl_auth_cert, NULL);
if(gsc->host)
SSL_SetURL(nss_data->in, gsc->host);
--- a/libpurple/protocols/jabber/oob.c Thu Jan 09 20:19:29 2014 -0800
+++ b/libpurple/protocols/jabber/oob.c Thu Jan 09 21:12:37 2014 -0800
@@ -137,8 +137,8 @@
*tmp = '\0';
lenstr = strstr(jox->headers->str, "Content-Length: ");
if(lenstr) {
- int size;
- if (sscanf(lenstr, "Content-Length: %d", &size) == 1)
+ gsize size;
+ if (sscanf(lenstr, "Content-Length: %" G_GSIZE_FORMAT, &size) == 1)
purple_xfer_set_size(xfer, size);
else {
purple_debug_error("jabber", "Unable to parse Content-Length!\n");
--- a/libpurple/win32/global.mak Thu Jan 09 20:19:29 2014 -0800
+++ b/libpurple/win32/global.mak Thu Jan 09 21:12:37 2014 -0800
@@ -17,7 +17,7 @@
BONJOUR_TOP ?= $(WIN32_DEV_TOP)/Bonjour_SDK
LIBXML2_TOP ?= $(WIN32_DEV_TOP)/libxml2-2.9.0
MEANWHILE_TOP ?= $(WIN32_DEV_TOP)/meanwhile-1.0.2_daa3
-NSS_TOP ?= $(WIN32_DEV_TOP)/nss-3.15.2-nspr-4.10.1
+NSS_TOP ?= $(WIN32_DEV_TOP)/nss-3.15.3-nspr-4.10.2
PERL_LIB_TOP ?= $(WIN32_DEV_TOP)/perl-5.10.0
SILC_TOOLKIT ?= $(WIN32_DEV_TOP)/silc-toolkit-1.1.10
TCL_LIB_TOP ?= $(WIN32_DEV_TOP)/tcl-8.4.5
--- a/pidgin.desktop.in Thu Jan 09 20:19:29 2014 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-[Desktop Entry]
-_Name=Pidgin Internet Messenger
-_GenericName=Internet Messenger
-_Comment=Chat over IM. Supports AIM, Google Talk, Jabber/XMPP, MSN, Yahoo and more
-Exec=pidgin
-Icon=pidgin
-StartupNotify=true
-Terminal=false
-Type=Application
-Categories=Network;InstantMessaging;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin.desktop.in.in Thu Jan 09 21:12:37 2014 -0800
@@ -0,0 +1,11 @@
+[Desktop Entry]
+_Name=Pidgin Internet Messenger
+_GenericName=Internet Messenger
+_Comment=Chat over IM. Supports AIM, Google Talk, Jabber/XMPP, MSN, Yahoo and more
+Exec=pidgin
+Icon=pidgin
+StartupNotify=true
+Terminal=false
+Type=Application
+Categories=Network;InstantMessaging;
+@USES_MM_CHAT_SECTION@
--- a/pidgin/gtkdialogs.c Thu Jan 09 20:19:29 2014 -0800
+++ b/pidgin/gtkdialogs.c Thu Jan 09 21:12:37 2014 -0800
@@ -74,13 +74,10 @@
static const struct developer developers[] = {
{"Daniel 'datallah' Atallah", NULL, NULL},
{"Paul 'darkrain42' Aurich", NULL, NULL},
- {"John 'rekkanoryo' Bailey", NULL, NULL},
{"Ethan 'Paco-Paco' Blanton", NULL, NULL},
{"Hylke Bons", N_("artist"), "hylkebons@gmail.com"},
{"Sadrul Habib Chowdhury", NULL, NULL},
{"Mark 'KingAnt' Doliner", NULL, "mark@kingant.net"},
- {"Casey Harkins", NULL, NULL},
- {"Ivan Komarov", NULL, "ivan.komarov@pidgin.im"},
{"Gary 'grim' Kramlich", NULL, "grim@pidgin.im"},
{"Richard 'rlaager' Laager", NULL, "rlaager@pidgin.im"},
{"Marcus 'malu' Lundblad", NULL, NULL},
@@ -95,6 +92,7 @@
{"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}
};
@@ -103,23 +101,24 @@
{"Jakub 'haakon' Adam", NULL, NULL},
{"Krzysztof Klinikowski", NULL, NULL},
{"Eion Robb", NULL, NULL},
- {"Peter 'Fmoo' Ruibal", NULL, NULL},
- {"Gabriel 'Nix' Schulhof", NULL, NULL},
- {"Tomasz Wasilczyk", 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},
- /* feel free to not translate this */
- {N_("Ka-Hing Cheung"), NULL, NULL},
+ /* Translators: This is a person's name. For most languages we recommend
+ not translating it. */
+ {N_("Ka-Hing Cheung"), NULL, NULL},
{"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"},
@@ -137,10 +136,12 @@
static const struct developer retired_patch_writers[] = {
{"Felipe 'shx' Contreras", NULL, NULL},
{"Decklin Foster", NULL, NULL},
- {"Dennis 'EvilDennisR' Ristuccia", N_("Senior Contributor/QA"), 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}
};
@@ -152,7 +153,7 @@
{N_("Assamese"), "as", "Amitakhya Phukan", "aphukan@fedoraproject.org"},
{N_("Belarusian Latin"), "be@latin", "Ihar Hrachyshka", "ihar.hrachyshka@gmail.com"},
{N_("Bulgarian"), "bg", "Vladimira Girginova", "missing@here.is"},
- {N_("Bulgarian"), "bg", "Vladimir (Kaladan) Petkov", "vpetkov@i-space.org"},
+ {N_("Bulgarian"), "bg", "Vladimir (Kaladan) Petkov", "kaladan@gmail.com"},
{N_("Bengali"), "bn", "Jamil Ahmed", "jamil@bengalinux.org"},
{N_("Bengali"), "bn", "Israt Jahan", "israt@ankur.org.bd"},
{N_("Bengali"), "bn", "Samia Nimatullah", "mailsamia2001@yahoo.com"},
@@ -218,14 +219,13 @@
{N_("Malay"), "ms_MY", "Muhammad Najmi bin Ahmad Zabidi", "najmi.zabidi@gmail.com"},
{N_("Burmese"), "my_MM", "Thura Hlaing", "trhura@gmail.com"},
{N_("Bokmål Norwegian"), "nb", "Hans Fredrik Nordhaug", "hans@nordhaug.priv.no"},
- {N_("Nepali"), "ne", "Shyam Krishna Bal", "shyamkrishna_bal@yahoo.com"},
+ {N_("Nepali"), "ne", "Shyam Krishna Bal", NULL},
{N_("Dutch, Flemish"), "nl", "Gideon van Melle", "translations@gvmelle.com"},
{N_("Norwegian Nynorsk"), "nn", "Yngve Spjeld Landro", "l10n@landro.net"},
{N_("Occitan"), "oc", "Yannig Marchegay", "yannig@marchegay.org"},
{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_("Polish"), "pl", "Piotr Makowski", "pmakowski@aviary.pl"},
{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"},
@@ -237,7 +237,7 @@
{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"), "sr@Latn", "Miloš Popović", "gpopac@gmail.com"},
+ {N_("Serbian Latin"), "sr@latin", "Miloš Popović", "gpopac@gmail.com"},
{N_("Sinhala"), "si", "Yajith Ajantha Dayarathna", "yajith@gmail.com"},
{N_("Sinhala"), "si", "Danishka Navin", "snavin@redhat.com"},
{N_("Swedish"), "sv", "Peter Hjalmarsson", "xake@telia.com"},
@@ -246,7 +246,6 @@
{N_("Tamil"), "ta", "Viveka Nathan K", "vivekanathan@users.sourceforge.net"},
{N_("Telugu"), "te", "Krishnababu Krottapalli", "krottapalli@ymail.com"},
{N_("Thai"), "th", "Isriya Paireepairit", "markpeak@gmail.com"},
- {N_("Turkish"), "tr", "Serdar Soytetir", "tulliana@gmail.com"},
{N_("Ukranian"), "uk", "Oleksandr Kovalenko", "alx.kovalenko@gmail.com"},
{N_("Urdu"), "ur", "RKVS Raman", "rkvsraman@gmail.com"},
{N_("Vietnamese"), "vi", "Nguyễn Vũ Hưng", "vuhung16plus@gmail.com"},
@@ -307,6 +306,7 @@
{N_("Dutch, Flemish"), "nl", "Vincent van Adrighem", "V.vanAdrighem@dirck.mine.nu"},
{N_("Polish"), "pl", "Krzysztof Foltman", "krzysztof@foltman.com"},
{N_("Polish"), "pl", "Paweł Godlewski", "pawel@bajk.pl"},
+ {N_("Polish"), "pl", "Piotr Makowski", NULL},
{N_("Polish"), "pl", "Emil Nowak", "emil5@go2.pl"},
{N_("Polish"), "pl", "Przemysław Sułek", NULL},
{N_("Portuguese"), "pt", "Duarte Henriques", NULL},
@@ -324,6 +324,7 @@
{N_("Swedish"), "sv", "Tore Lundqvist", NULL},
{N_("Swedish"), "sv", "Christian Rose", NULL},
{N_("Telugu"), "te", "Mr. Subbaramaih", "info.gist@cdac.in"},
+ {N_("Turkish"), "tr", "Serdar Soytetir", "tulliana@gmail.com"},
{N_("Turkish"), "tr", "Ahmet Alp Balkan", NULL},
{N_("Vietnamese"), "vi", N_("T.M.Thanh and the Gnome-Vi Team"), "gnomevi-list@lists.sf.net"},
{N_("Simplified Chinese"), "zh_CN", "Hashao, Rocky S. Lee", NULL},
@@ -337,7 +338,11 @@
{
for (; list->name != NULL; list++) {
if (list->email != NULL) {
- g_string_append_printf(str, " <a href=\"mailto:%s\">%s</a>%s%s%s<br/>",
+ const gchar *proto = "mailto:";
+ if (strchr(list->email, ':') != NULL)
+ proto = "";
+ g_string_append_printf(str, " <a href=\"%s%s\">%s</a>%s%s%s<br/>",
+ proto,
list->email, _(list->name),
list->role ? " (" : "",
list->role ? _(list->role) : "",
--- a/pidgin/plugins/Makefile.am Thu Jan 09 20:19:29 2014 -0800
+++ b/pidgin/plugins/Makefile.am Thu Jan 09 21:12:37 2014 -0800
@@ -47,6 +47,7 @@
themeedit_la_LDFLAGS = -module -avoid-version
timestamp_la_LDFLAGS = -module -avoid-version
timestamp_format_la_LDFLAGS = -module -avoid-version
+unity_la_LDFLAGS = -module -avoid-version
vvconfig_la_LDFLAGS = -module -avoid-version
xmppconsole_la_LDFLAGS = -module -avoid-version
@@ -73,6 +74,10 @@
plugin_LTLIBRARIES += vvconfig.la
endif
+if ENABLE_UNITY
+plugin_LTLIBRARIES += unity.la
+endif
+
noinst_LTLIBRARIES = \
contact_priority.la \
gtk_signals_test.la
@@ -93,6 +98,7 @@
themeedit_la_SOURCES = themeedit.c themeedit-icon.c themeedit-icon.h
timestamp_la_SOURCES = timestamp.c
timestamp_format_la_SOURCES = timestamp_format.c
+unity_la_SOURCES = unity.c
vvconfig_la_SOURCES = vvconfig.c
xmppconsole_la_SOURCES = xmppconsole.c
@@ -112,6 +118,7 @@
themeedit_la_LIBADD = $(GTK_LIBS)
timestamp_la_LIBADD = $(GTK_LIBS)
timestamp_format_la_LIBADD = $(GTK_LIBS)
+unity_la_LIBADD = $(GTK_LIBS) $(UNITY_LIBS)
vvconfig_la_LIBADD = $(GTK_LIBS) $(GSTREAMER_LIBS)
xmppconsole_la_LIBADD = $(GTK_LIBS)
@@ -136,6 +143,7 @@
-I$(top_srcdir)/pidgin \
$(DEBUG_CFLAGS) \
$(GTK_CFLAGS) \
+ $(UNITY_CFLAGS) \
$(GSTREAMER_CFLAGS) \
$(PLUGIN_CFLAGS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/plugins/unity.c Thu Jan 09 21:12:37 2014 -0800
@@ -0,0 +1,635 @@
+/*
+ * Integration with Unity's messaging menu and launcher
+ * Copyright (C) 2013 Ankit Vani <a@nevitus.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+#include "internal.h"
+#include "version.h"
+#include "account.h"
+#include "savedstatuses.h"
+
+#include "gtkplugin.h"
+#include "gtkconv.h"
+#include "gtkutils.h"
+
+#include <unity.h>
+#include <messaging-menu.h>
+
+#define UNITY_PLUGIN_ID "gtk-unity-integration"
+
+static MessagingMenuApp *mmapp = NULL;
+static UnityLauncherEntry *launcher = NULL;
+static guint n_sources = 0;
+static gint launcher_count;
+static gint messaging_menu_text;
+static gboolean alert_chat_nick = TRUE;
+
+enum {
+ LAUNCHER_COUNT_DISABLE,
+ LAUNCHER_COUNT_MESSAGES,
+ LAUNCHER_COUNT_SOURCES,
+};
+
+enum {
+ MESSAGING_MENU_COUNT,
+ MESSAGING_MENU_TIME,
+};
+
+static int attach_signals(PurpleConversation *conv);
+static void detach_signals(PurpleConversation *conv);
+
+static void
+update_launcher()
+{
+ guint count = 0;
+ GList *convs = NULL;
+ g_return_if_fail(launcher != NULL);
+ if (launcher_count == LAUNCHER_COUNT_DISABLE)
+ return;
+
+ if (launcher_count == LAUNCHER_COUNT_MESSAGES) {
+ for (convs = purple_get_conversations(); convs != NULL; convs = convs->next) {
+ PurpleConversation *conv = convs->data;
+ count += GPOINTER_TO_INT(purple_conversation_get_data(conv,
+ "unity-message-count"));
+ }
+ } else {
+ count = n_sources;
+ }
+
+ if (launcher != NULL) {
+ if (count > 0)
+ unity_launcher_entry_set_count_visible(launcher, TRUE);
+ else
+ unity_launcher_entry_set_count_visible(launcher, FALSE);
+ unity_launcher_entry_set_count(launcher, count);
+ }
+}
+
+static gchar *
+conversation_id(PurpleConversation *conv)
+{
+ PurpleConversationType conv_type = purple_conversation_get_type(conv);
+ PurpleAccount *account = purple_conversation_get_account(conv);
+ char type[2] = "0";
+ type[0] += conv_type;
+
+ return g_strconcat(type, ":",
+ purple_conversation_get_name(conv), ":",
+ purple_account_get_username(account), ":",
+ purple_account_get_protocol_id(account), NULL);
+}
+
+static void
+messaging_menu_add_conversation(PurpleConversation *conv, gint count)
+{
+ gchar *id;
+ g_return_if_fail(count > 0);
+ id = conversation_id(conv);
+
+ /* GBytesIcon may be useful for messaging menu source icons using buddy
+ icon data for IMs */
+ if (!messaging_menu_app_has_source(mmapp, id))
+ messaging_menu_app_append_source(mmapp, id, NULL,
+ purple_conversation_get_title(conv));
+
+ if (messaging_menu_text == MESSAGING_MENU_TIME)
+ messaging_menu_app_set_source_time(mmapp, id, g_get_real_time());
+ else if (messaging_menu_text == MESSAGING_MENU_COUNT)
+ messaging_menu_app_set_source_count(mmapp, id, count);
+ messaging_menu_app_draw_attention(mmapp, id);
+
+ g_free(id);
+}
+
+static void
+messaging_menu_remove_conversation(PurpleConversation *conv)
+{
+ gchar *id = conversation_id(conv);
+ if (messaging_menu_app_has_source(mmapp, id))
+ messaging_menu_app_remove_source(mmapp, id);
+ g_free(id);
+}
+
+static void
+refill_messaging_menu()
+{
+ GList *convs;
+
+ for (convs = purple_get_conversations(); convs != NULL; convs = convs->next) {
+ PurpleConversation *conv = convs->data;
+ messaging_menu_add_conversation(conv,
+ GPOINTER_TO_INT(purple_conversation_get_data(conv, "unity-message-count")));
+ }
+}
+
+static int
+alert(PurpleConversation *conv)
+{
+ gint count;
+ PidginWindow *purplewin = NULL;
+ if (conv == NULL || PIDGIN_CONVERSATION(conv) == NULL)
+ return 0;
+
+ purplewin = PIDGIN_CONVERSATION(conv)->win;
+
+ if (!pidgin_conv_window_has_focus(purplewin) ||
+ !pidgin_conv_window_is_active_conversation(conv))
+ {
+ count = GPOINTER_TO_INT(purple_conversation_get_data(conv,
+ "unity-message-count"));
+ if (!count++)
+ ++n_sources;
+
+ purple_conversation_set_data(conv, "unity-message-count",
+ GINT_TO_POINTER(count));
+ messaging_menu_add_conversation(conv, count);
+ update_launcher();
+ }
+
+ return 0;
+}
+
+static void
+unalert(PurpleConversation *conv)
+{
+ if (GPOINTER_TO_INT(purple_conversation_get_data(conv, "unity-message-count")) > 0)
+ --n_sources;
+ purple_conversation_set_data(conv, "unity-message-count",
+ GINT_TO_POINTER(0));
+ messaging_menu_remove_conversation(conv);
+ update_launcher();
+}
+
+static int
+unalert_cb(GtkWidget *widget, gpointer data, PurpleConversation *conv)
+{
+ unalert(conv);
+ return 0;
+}
+
+static gboolean
+message_displayed_cb(PurpleAccount *account, const char *who, char *message,
+ PurpleConversation *conv, PurpleMessageFlags flags)
+{
+ if ((purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT &&
+ alert_chat_nick && !(flags & PURPLE_MESSAGE_NICK)))
+ return FALSE;
+
+ if ((flags & PURPLE_MESSAGE_RECV) && !(flags & PURPLE_MESSAGE_DELAYED))
+ alert(conv);
+
+ return FALSE;
+}
+
+static void
+im_sent_im(PurpleAccount *account, const char *receiver, const char *message)
+{
+ PurpleConversation *conv = NULL;
+ conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, receiver,
+ account);
+ unalert(conv);
+}
+
+static void
+chat_sent_im(PurpleAccount *account, const char *message, int id)
+{
+ PurpleConversation *conv = NULL;
+ conv = purple_find_chat(purple_account_get_connection(account), id);
+ unalert(conv);
+}
+
+static void
+conv_created(PurpleConversation *conv)
+{
+ purple_conversation_set_data(conv, "unity-message-count",
+ GINT_TO_POINTER(0));
+ attach_signals(conv);
+}
+
+static void
+deleting_conv(PurpleConversation *conv)
+{
+ detach_signals(conv);
+ unalert(conv);
+}
+
+static void
+message_source_activated(MessagingMenuApp *app, const gchar *id,
+ gpointer user_data)
+{
+ gchar **sections = g_strsplit(id, ":", 0);
+ PurpleConversation *conv = NULL;
+ PurpleAccount *account;
+ PidginWindow *purplewin = NULL;
+ PurpleConversationType conv_type;
+
+ char *type = sections[0];
+ char *cname = sections[1];
+ char *aname = sections[2];
+ char *protocol = sections[3];
+
+ conv_type = type[0] - '0';
+ account = purple_accounts_find(aname, protocol);
+ conv = purple_find_conversation_with_account(conv_type, cname, account);
+
+ if (conv) {
+ unalert(conv);
+ purplewin = PIDGIN_CONVERSATION(conv)->win;
+ pidgin_conv_window_switch_gtkconv(purplewin, PIDGIN_CONVERSATION(conv));
+ gdk_window_focus(gtk_widget_get_window(purplewin->window), time(NULL));
+ }
+ g_strfreev (sections);
+}
+
+static PurpleSavedStatus *
+create_transient_status(PurpleStatusPrimitive primitive, PurpleStatusType *status_type)
+{
+ PurpleSavedStatus *saved_status = purple_savedstatus_new(NULL, primitive);
+
+ if(status_type != NULL) {
+ GList *tmp, *active_accts = purple_accounts_get_all_active();
+ for (tmp = active_accts; tmp != NULL; tmp = tmp->next) {
+ purple_savedstatus_set_substatus(saved_status,
+ (PurpleAccount*) tmp->data, status_type, NULL);
+ }
+ g_list_free(active_accts);
+ }
+
+ return saved_status;
+}
+
+static void
+status_changed_cb(PurpleSavedStatus *saved_status)
+{
+ MessagingMenuStatus status = MESSAGING_MENU_STATUS_AVAILABLE;
+
+ switch (purple_savedstatus_get_type(saved_status)) {
+ case PURPLE_STATUS_AVAILABLE:
+ case PURPLE_STATUS_MOOD:
+ case PURPLE_STATUS_TUNE:
+ case PURPLE_STATUS_UNSET:
+ status = MESSAGING_MENU_STATUS_AVAILABLE;
+ break;
+
+ case PURPLE_STATUS_AWAY:
+ case PURPLE_STATUS_EXTENDED_AWAY:
+ status = MESSAGING_MENU_STATUS_AWAY;
+ break;
+
+ case PURPLE_STATUS_INVISIBLE:
+ status = MESSAGING_MENU_STATUS_INVISIBLE;
+ break;
+
+ case PURPLE_STATUS_MOBILE:
+ case PURPLE_STATUS_OFFLINE:
+ status = MESSAGING_MENU_STATUS_OFFLINE;
+ break;
+
+ case PURPLE_STATUS_UNAVAILABLE:
+ status = MESSAGING_MENU_STATUS_BUSY;
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+ messaging_menu_app_set_status(mmapp, status);
+}
+
+static void
+messaging_menu_status_changed(MessagingMenuApp *mmapp,
+ MessagingMenuStatus mm_status, gpointer user_data)
+{
+ PurpleSavedStatus *saved_status;
+ PurpleStatusPrimitive primitive = PURPLE_STATUS_UNSET;
+
+ switch (mm_status) {
+ case MESSAGING_MENU_STATUS_AVAILABLE:
+ primitive = PURPLE_STATUS_AVAILABLE;
+ break;
+
+ case MESSAGING_MENU_STATUS_AWAY:
+ primitive = PURPLE_STATUS_AWAY;
+ break;
+
+ case MESSAGING_MENU_STATUS_BUSY:
+ primitive = PURPLE_STATUS_UNAVAILABLE;
+ break;
+
+ case MESSAGING_MENU_STATUS_INVISIBLE:
+ primitive = PURPLE_STATUS_INVISIBLE;
+ break;
+
+ case MESSAGING_MENU_STATUS_OFFLINE:
+ primitive = PURPLE_STATUS_OFFLINE;
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+
+ saved_status = purple_savedstatus_find_transient_by_type_and_message(primitive, NULL);
+ if (saved_status == NULL)
+ saved_status = create_transient_status(primitive, NULL);
+ purple_savedstatus_activate(saved_status);
+}
+
+static void
+alert_config_cb(GtkWidget *widget, gpointer data)
+{
+ gboolean on = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+ purple_prefs_set_bool("/plugins/gtk/unity/alert_chat_nick", on);
+ alert_chat_nick = on;
+}
+
+static void
+launcher_config_cb(GtkWidget *widget, gpointer data)
+{
+ gint option = GPOINTER_TO_INT(data);
+ if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
+ return;
+
+ purple_prefs_set_int("/plugins/gtk/unity/launcher_count", option);
+ launcher_count = option;
+ if (option == LAUNCHER_COUNT_DISABLE)
+ unity_launcher_entry_set_count_visible(launcher, FALSE);
+ else
+ update_launcher();
+}
+
+static void
+messaging_menu_config_cb(GtkWidget *widget, gpointer data)
+{
+ gint option = GPOINTER_TO_INT(data);
+ if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
+ return;
+
+ purple_prefs_set_int("/plugins/gtk/unity/messaging_menu_text", option);
+ messaging_menu_text = option;
+ refill_messaging_menu();
+}
+
+static int
+attach_signals(PurpleConversation *conv)
+{
+ PidginConversation *gtkconv = NULL;
+ guint id;
+
+ gtkconv = PIDGIN_CONVERSATION(conv);
+ if (!gtkconv)
+ return 0;
+
+ id = g_signal_connect(G_OBJECT(gtkconv->entry), "focus-in-event",
+ G_CALLBACK(unalert_cb), conv);
+ purple_conversation_set_data(conv, "unity-entry-signal", GUINT_TO_POINTER(id));
+
+ id = g_signal_connect(G_OBJECT(gtkconv->imhtml), "focus-in-event",
+ G_CALLBACK(unalert_cb), conv);
+ purple_conversation_set_data(conv, "unity-imhtml-signal", GUINT_TO_POINTER(id));
+
+ return 0;
+}
+
+static void
+detach_signals(PurpleConversation *conv)
+{
+ PidginConversation *gtkconv = NULL;
+ guint id;
+ gtkconv = PIDGIN_CONVERSATION(conv);
+ if (!gtkconv)
+ return;
+
+ id = GPOINTER_TO_INT(purple_conversation_get_data(conv, "unity-imhtml-signal"));
+ g_signal_handler_disconnect(gtkconv->imhtml, id);
+
+ id = GPOINTER_TO_INT(purple_conversation_get_data(conv, "unity-entry-signal"));
+ g_signal_handler_disconnect(gtkconv->entry, id);
+
+ purple_conversation_set_data(conv, "unity-message-count",
+ GINT_TO_POINTER(0));
+}
+
+static GtkWidget *
+get_config_frame(PurplePlugin *plugin)
+{
+ GtkWidget *ret = NULL, *frame = NULL;
+ GtkWidget *vbox = NULL, *toggle = NULL;
+
+ ret = gtk_vbox_new(FALSE, 18);
+ gtk_container_set_border_width(GTK_CONTAINER (ret), 12);
+
+ /* Alerts */
+
+ frame = pidgin_make_frame(ret, _("Chatroom alerts"));
+ vbox = gtk_vbox_new(FALSE, 5);
+ gtk_container_add(GTK_CONTAINER(frame), vbox);
+
+ toggle = gtk_check_button_new_with_mnemonic(_("Chatroom message alerts _only where someone says your username"));
+ gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle),
+ purple_prefs_get_bool("/plugins/gtk/unity/alert_chat_nick"));
+ g_signal_connect(G_OBJECT(toggle), "toggled",
+ G_CALLBACK(alert_config_cb), NULL);
+
+ /* Launcher integration */
+
+ frame = pidgin_make_frame(ret, _("Launcher Icon"));
+ vbox = gtk_vbox_new(FALSE, 5);
+ gtk_container_add(GTK_CONTAINER(frame), vbox);
+
+ toggle = gtk_radio_button_new_with_mnemonic(NULL, _("_Disable launcher integration"));
+ gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle),
+ purple_prefs_get_int("/plugins/gtk/unity/launcher_count") == LAUNCHER_COUNT_DISABLE);
+ g_signal_connect(G_OBJECT(toggle), "toggled",
+ G_CALLBACK(launcher_config_cb), GUINT_TO_POINTER(LAUNCHER_COUNT_DISABLE));
+
+ toggle = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(toggle),
+ _("Show number of unread _messages on launcher icon"));
+ gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle),
+ purple_prefs_get_int("/plugins/gtk/unity/launcher_count") == LAUNCHER_COUNT_MESSAGES);
+ g_signal_connect(G_OBJECT(toggle), "toggled",
+ G_CALLBACK(launcher_config_cb), GUINT_TO_POINTER(LAUNCHER_COUNT_MESSAGES));
+
+ toggle = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(toggle),
+ _("Show number of unread _conversations on launcher icon"));
+ gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle),
+ purple_prefs_get_int("/plugins/gtk/unity/launcher_count") == LAUNCHER_COUNT_SOURCES);
+ g_signal_connect(G_OBJECT(toggle), "toggled",
+ G_CALLBACK(launcher_config_cb), GUINT_TO_POINTER(LAUNCHER_COUNT_SOURCES));
+
+ /* Messaging menu integration */
+
+ frame = pidgin_make_frame(ret, _("Messaging Menu"));
+ vbox = gtk_vbox_new(FALSE, 5);
+ gtk_container_add(GTK_CONTAINER(frame), vbox);
+
+ toggle = gtk_radio_button_new_with_mnemonic(NULL,
+ _("Show number of _unread messages for conversations in messaging menu"));
+ gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle),
+ purple_prefs_get_int("/plugins/gtk/unity/messaging_menu_text") == MESSAGING_MENU_COUNT);
+ g_signal_connect(G_OBJECT(toggle), "toggled",
+ G_CALLBACK(messaging_menu_config_cb), GUINT_TO_POINTER(MESSAGING_MENU_COUNT));
+
+ toggle = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(toggle),
+ _("Show _elapsed time for unread conversations in messaging menu"));
+ gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle),
+ purple_prefs_get_int("/plugins/gtk/unity/messaging_menu_text") == MESSAGING_MENU_TIME);
+ g_signal_connect(G_OBJECT(toggle), "toggled",
+ G_CALLBACK(messaging_menu_config_cb), GUINT_TO_POINTER(MESSAGING_MENU_TIME));
+
+ gtk_widget_show_all(ret);
+ return ret;
+}
+
+static gboolean
+plugin_load(PurplePlugin *plugin)
+{
+ GList *convs = purple_get_conversations();
+ PurpleSavedStatus *saved_status;
+ void *conv_handle = purple_conversations_get_handle();
+ void *gtk_conv_handle = pidgin_conversations_get_handle();
+ void *savedstat_handle = purple_savedstatuses_get_handle();
+
+ alert_chat_nick = purple_prefs_get_bool("/plugins/gtk/unity/alert_chat_nick");
+
+ mmapp = messaging_menu_app_new("pidgin.desktop");
+ g_object_ref(mmapp);
+ messaging_menu_app_register(mmapp);
+ messaging_menu_text = purple_prefs_get_int("/plugins/gtk/unity/messaging_menu_text");
+
+ g_signal_connect(mmapp, "activate-source",
+ G_CALLBACK(message_source_activated), NULL);
+ g_signal_connect(mmapp, "status-changed",
+ G_CALLBACK(messaging_menu_status_changed), NULL);
+
+ saved_status = purple_savedstatus_get_current();
+ status_changed_cb(saved_status);
+
+ purple_signal_connect(savedstat_handle, "savedstatus-changed", plugin,
+ PURPLE_CALLBACK(status_changed_cb), NULL);
+
+ launcher = unity_launcher_entry_get_for_desktop_id("pidgin.desktop");
+ g_object_ref(launcher);
+ launcher_count = purple_prefs_get_int("/plugins/gtk/unity/launcher_count");
+
+ purple_signal_connect(gtk_conv_handle, "displayed-im-msg", plugin,
+ PURPLE_CALLBACK(message_displayed_cb), NULL);
+ purple_signal_connect(gtk_conv_handle, "displayed-chat-msg", plugin,
+ PURPLE_CALLBACK(message_displayed_cb), NULL);
+ purple_signal_connect(conv_handle, "sent-im-msg", plugin,
+ PURPLE_CALLBACK(im_sent_im), NULL);
+ purple_signal_connect(conv_handle, "sent-chat-msg", plugin,
+ PURPLE_CALLBACK(chat_sent_im), NULL);
+ purple_signal_connect(conv_handle, "conversation-created", plugin,
+ PURPLE_CALLBACK(conv_created), NULL);
+ purple_signal_connect(conv_handle, "deleting-conversation", plugin,
+ PURPLE_CALLBACK(deleting_conv), NULL);
+
+ while (convs) {
+ PurpleConversation *conv = (PurpleConversation *)convs->data;
+ attach_signals(conv);
+ convs = convs->next;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+plugin_unload(PurplePlugin *plugin)
+{
+ GList *convs = purple_get_conversations();
+ while (convs) {
+ PurpleConversation *conv = (PurpleConversation *)convs->data;
+ unalert(conv);
+ detach_signals(conv);
+ convs = convs->next;
+ }
+
+ unity_launcher_entry_set_count_visible(launcher, FALSE);
+ messaging_menu_app_unregister(mmapp);
+
+ g_object_unref(launcher);
+ g_object_unref(mmapp);
+ return TRUE;
+}
+
+static PidginPluginUiInfo ui_info =
+{
+ get_config_frame,
+ 0, /* page_num (Reserved) */
+
+ /* padding */
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+static PurplePluginInfo info =
+{
+ PURPLE_PLUGIN_MAGIC,
+ PURPLE_MAJOR_VERSION,
+ PURPLE_MINOR_VERSION,
+ PURPLE_PLUGIN_STANDARD, /**< type */
+ PIDGIN_PLUGIN_TYPE, /**< ui_requirement */
+ 0, /**< flags */
+ NULL, /**< dependencies */
+ PURPLE_PRIORITY_DEFAULT, /**< priority */
+
+ UNITY_PLUGIN_ID, /**< id */
+ N_("Unity Integration"), /**< name */
+ DISPLAY_VERSION, /**< version */
+ /** summary */
+ N_("Provides integration with Unity."),
+ /** description */
+ N_("Provides integration with Unity's messaging "
+ "menu and launcher."),
+ /**< author */
+ "Ankit Vani <a@nevitus.org>",
+ PURPLE_WEBSITE, /**< homepage */
+
+ plugin_load, /**< load */
+ plugin_unload, /**< unload */
+ NULL, /**< destroy */
+
+ &ui_info, /**< ui_info */
+ NULL, /**< extra_info */
+ NULL,
+ NULL,
+
+ /* padding */
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+static void
+init_plugin(PurplePlugin *plugin)
+{
+ purple_prefs_add_none("/plugins/gtk");
+ purple_prefs_add_none("/plugins/gtk/unity");
+ purple_prefs_add_int("/plugins/gtk/unity/launcher_count", LAUNCHER_COUNT_SOURCES);
+ purple_prefs_add_int("/plugins/gtk/unity/messaging_menu_text", MESSAGING_MENU_COUNT);
+ purple_prefs_add_bool("/plugins/gtk/unity/alert_chat_nick", TRUE);
+}
+
+PURPLE_INIT_PLUGIN(unity, init_plugin, info)