Merged default branch soc.2013.gobjectification

Fri, 25 Oct 2013 00:31:39 +0530

author
Ankit Vani <a@nevitus.org>
date
Fri, 25 Oct 2013 00:31:39 +0530
branch
soc.2013.gobjectification
changeset 35047
cf8ca70094ff
parent 35046
01aafc96f36e (current diff)
parent 34500
e322f9c8f3e9 (diff)
child 35048
d374b5aef355
child 36930
c1b0e75051e3

Merged default branch

libpurple/Makefile.am file | annotate | diff | comparison | revisions
libpurple/conversation.c file | annotate | diff | comparison | revisions
libpurple/conversation.h file | annotate | diff | comparison | revisions
libpurple/imgstore.h file | annotate | diff | comparison | revisions
libpurple/protocols/mxit/actions.c file | annotate | diff | comparison | revisions
libpurple/protocols/mxit/login.c file | annotate | diff | comparison | revisions
libpurple/request.h file | annotate | diff | comparison | revisions
libpurple/util.c file | annotate | diff | comparison | revisions
libpurple/util.h file | annotate | diff | comparison | revisions
pidgin/gtkconv.c file | annotate | diff | comparison | revisions
pidgin/gtkconvwin.h file | annotate | diff | comparison | revisions
pidgin/gtkrequest.c file | annotate | diff | comparison | revisions
pidgin/gtkutils.c file | annotate | diff | comparison | revisions
pidgin/gtkwebview.c file | annotate | diff | comparison | revisions
--- a/libpurple/Makefile.am	Thu Oct 24 20:24:29 2013 +0530
+++ b/libpurple/Makefile.am	Fri Oct 25 00:31:39 2013 +0530
@@ -74,6 +74,7 @@
 	core.c \
 	debug.c \
 	desktopitem.c \
+	e2ee.c \
 	eventloop.c \
 	http.c \
 	idle.c \
@@ -149,6 +150,7 @@
 	dbus-maybe.h \
 	debug.h \
 	desktopitem.h \
+	e2ee.h \
 	eventloop.h \
 	http.h \
 	idle.h \
--- a/libpurple/conversation.c	Thu Oct 24 20:24:29 2013 +0530
+++ b/libpurple/conversation.c	Fri Oct 25 00:31:39 2013 +0530
@@ -57,6 +57,8 @@
 	PurpleConnectionFlags features;   /**< The supported features            */
 	GList *message_history;           /**< Message history, as a GList of
 	                                       PurpleConversationMessage's       */
+
+	PurpleE2eeState *e2ee_state;      /**< End-to-end encryption state.      */
 };
 
 /**
@@ -440,6 +442,55 @@
 }
 
 void
+purple_conversation_set_e2ee_state(PurpleConversation *conv,
+	PurpleE2eeState *state)
+{
+	PurpleConversationPrivate *priv = PURPLE_CONVERSATION_GET_PRIVATE(conv);
+
+	g_return_if_fail(priv != NULL);
+
+	if (state != NULL && purple_e2ee_state_get_provider(state) !=
+		purple_e2ee_provider_get_main())
+	{
+		purple_debug_error("conversation",
+			"This is not the main e2ee provider");
+
+		return;
+	}
+
+	if (state)
+		purple_e2ee_state_ref(state);
+	purple_e2ee_state_unref(priv->e2ee_state);
+	priv->e2ee_state = state;
+
+	purple_conversation_update(conv, PURPLE_CONVERSATION_UPDATE_E2EE);
+}
+
+PurpleE2eeState *
+purple_conversation_get_e2ee_state(PurpleConversation *conv)
+{
+	PurpleConversationPrivate *priv = PURPLE_CONVERSATION_GET_PRIVATE(conv);
+	PurpleE2eeProvider *provider;
+
+	g_return_val_if_fail(priv != NULL, NULL);
+
+	if (priv->e2ee_state == NULL)
+		return NULL;
+
+	provider = purple_e2ee_provider_get_main();
+	if (provider == NULL)
+		return NULL;
+
+	if (purple_e2ee_state_get_provider(priv->e2ee_state) != provider) {
+		purple_debug_warning("conversation",
+			"e2ee state has invalid provider set");
+		return NULL;
+	}
+
+	return priv->e2ee_state;
+}
+
+void
 purple_conversation_set_logging(PurpleConversation *conv, gboolean log)
 {
 	PurpleConversationPrivate *priv = PURPLE_CONVERSATION_GET_PRIVATE(conv);
@@ -1025,6 +1076,9 @@
 
 	purple_request_close_with_handle(conv);
 
+	purple_e2ee_state_unref(priv->e2ee_state);
+	priv->e2ee_state = NULL;
+
 	/* remove from conversations and im/chats lists prior to emit */
 	purple_conversations_remove(conv);
 
--- a/libpurple/conversation.h	Thu Oct 24 20:24:29 2013 +0530
+++ b/libpurple/conversation.h	Fri Oct 25 00:31:39 2013 +0530
@@ -64,6 +64,8 @@
 	PURPLE_CONVERSATION_UPDATE_LOGGING, /**< Logging for this conversation was
 	                                         enabled or disabled. */
 	PURPLE_CONVERSATION_UPDATE_TOPIC,   /**< The topic for a chat was updated. */
+	PURPLE_CONVERSATION_UPDATE_E2EE,    /**< The End-to-end encryption state was
+	                                         updated. */
 	/*
 	 * XXX These need to go when we implement a more generic core/UI event
 	 * system.
@@ -155,6 +157,7 @@
 
 #include "account.h"
 #include "buddyicon.h"
+#include "e2ee.h"
 #include "log.h"
 
 /**************************************************************************/
@@ -379,6 +382,26 @@
 const char *purple_conversation_get_name(const PurpleConversation *conv);
 
 /**
+ * Sets current E2EE state for the conversation.
+ *
+ * @param conv  The conversation.
+ * @param state The E2EE state.
+ */
+void
+purple_conversation_set_e2ee_state(PurpleConversation *conv,
+	PurpleE2eeState *state);
+
+/**
+ * Gets current conversation's E2EE state.
+ *
+ * @param conv The conversation.
+ *
+ * @return Current E2EE state for conversation.
+ */
+PurpleE2eeState *
+purple_conversation_get_e2ee_state(PurpleConversation *conv);
+
+/**
  * Enables or disables logging for this conversation.
  *
  * @param conv The conversation.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/e2ee.c	Fri Oct 25 00:31:39 2013 +0530
@@ -0,0 +1,225 @@
+/**
+ * @file e2ee.c End-to-end encryption API
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include "e2ee.h"
+
+#include "debug.h"
+
+struct _PurpleE2eeState
+{
+	PurpleE2eeProvider *provider;
+
+	gchar *name;
+	gchar *stock_icon;
+
+	guint ref_count;
+};
+
+struct _PurpleE2eeProvider
+{
+	gchar *name;
+	PurpleE2eeConvMenuCallback conv_menu_cb;
+};
+
+static PurpleE2eeProvider *main_provider = NULL;
+
+/*** Encryption states for conversations. *************************************/
+
+PurpleE2eeState *
+purple_e2ee_state_new(PurpleE2eeProvider *provider)
+{
+	PurpleE2eeState *state;
+
+	g_return_val_if_fail(provider != NULL, NULL);
+
+	state = g_new0(PurpleE2eeState, 1);
+	state->provider = provider;
+	state->ref_count = 1;
+
+	return state;
+}
+
+void
+purple_e2ee_state_ref(PurpleE2eeState *state)
+{
+	g_return_if_fail(state != NULL);
+
+	state->ref_count++;
+}
+
+PurpleE2eeState *
+purple_e2ee_state_unref(PurpleE2eeState *state)
+{
+	if (state == NULL)
+		return NULL;
+
+	state->ref_count--;
+	if (state->ref_count > 0)
+		return state;
+
+	g_free(state->name);
+	g_free(state->stock_icon);
+	g_free(state);
+
+	return NULL;
+}
+
+PurpleE2eeProvider *
+purple_e2ee_state_get_provider(PurpleE2eeState *state)
+{
+	g_return_val_if_fail(state != NULL, NULL);
+
+	return state->provider;
+}
+
+void
+purple_e2ee_state_set_name(PurpleE2eeState *state, const gchar *name)
+{
+	g_return_if_fail(state != NULL);
+	g_return_if_fail(name != NULL);
+
+	g_free(state->name);
+	state->name = g_strdup(name);
+}
+
+const gchar *
+purple_e2ee_state_get_name(PurpleE2eeState *state)
+{
+	g_return_val_if_fail(state != NULL, NULL);
+
+	return state->name;
+}
+
+void
+purple_e2ee_state_set_stock_icon(PurpleE2eeState *state,
+	const gchar *stock_icon)
+{
+	g_return_if_fail(state != NULL);
+	g_return_if_fail(stock_icon != NULL);
+
+	g_free(state->stock_icon);
+	state->stock_icon = g_strdup(stock_icon);
+}
+
+const gchar *
+purple_e2ee_state_get_stock_icon(PurpleE2eeState *state)
+{
+	g_return_val_if_fail(state, NULL);
+
+	return state->stock_icon;
+}
+
+/*** Encryption providers API. ************************************************/
+
+PurpleE2eeProvider *
+purple_e2ee_provider_new(void)
+{
+	PurpleE2eeProvider *provider;
+
+	provider = g_new0(PurpleE2eeProvider, 1);
+
+	return provider;
+}
+
+void
+purple_e2ee_provider_free(PurpleE2eeProvider *provider)
+{
+	g_return_if_fail(provider != NULL);
+
+	if (provider == main_provider) {
+		purple_debug_error("e2ee", "This provider is still registered");
+		return;
+	}
+
+	g_free(provider->name);
+	g_free(provider);
+}
+
+gboolean
+purple_e2ee_provider_register(PurpleE2eeProvider *provider)
+{
+	g_return_val_if_fail(provider != NULL, FALSE);
+
+	if (main_provider != NULL)
+		return FALSE;
+
+	main_provider = provider;
+	return TRUE;
+}
+
+void
+purple_e2ee_provider_unregister(PurpleE2eeProvider *provider)
+{
+	g_return_if_fail(provider != NULL);
+
+	if (main_provider != provider) {
+		purple_debug_warning("e2ee", "This provider is not registered");
+		return;
+	}
+
+	main_provider = NULL;
+}
+
+PurpleE2eeProvider *
+purple_e2ee_provider_get_main(void)
+{
+	return main_provider;
+}
+
+void
+purple_e2ee_provider_set_name(PurpleE2eeProvider *provider, const gchar *name)
+{
+	g_return_if_fail(provider != NULL);
+	g_return_if_fail(name != NULL);
+
+	g_free(provider->name);
+	provider->name = g_strdup(name);
+}
+
+const gchar *
+purple_e2ee_provider_get_name(PurpleE2eeProvider *provider)
+{
+	g_return_val_if_fail(provider != NULL, NULL);
+
+	return provider->name;
+}
+
+void
+purple_e2ee_provider_set_conv_menu_cb(PurpleE2eeProvider *provider,
+	PurpleE2eeConvMenuCallback conv_menu_cb)
+{
+	g_return_if_fail(provider != NULL);
+
+	provider->conv_menu_cb = conv_menu_cb;
+}
+
+PurpleE2eeConvMenuCallback
+purple_e2ee_provider_get_conv_menu_cb(PurpleE2eeProvider *provider)
+{
+	g_return_val_if_fail(provider != NULL, NULL);
+
+	return provider->conv_menu_cb;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/e2ee.h	Fri Oct 25 00:31:39 2013 +0530
@@ -0,0 +1,231 @@
+/**
+ * @file e2ee.h End-to-end encryption API
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#ifndef _PURPLE_E2EE_H_
+#define _PURPLE_E2EE_H_
+
+typedef struct _PurpleE2eeState PurpleE2eeState;
+
+typedef struct _PurpleE2eeProvider PurpleE2eeProvider;
+
+#include <glib.h>
+#include "conversation.h"
+
+typedef GList * (*PurpleE2eeConvMenuCallback)(PurpleConversation *conv);
+
+G_BEGIN_DECLS
+
+/**************************************************************************/
+/** @name Encryption states for conversations.                            */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Creates new E2EE state.
+ *
+ * State objects are global (shared between multiple conversations).
+ *
+ * @param provider The E2EE provider that created this state.
+ *
+ * @return New E2EE state.
+ */
+PurpleE2eeState *
+purple_e2ee_state_new(PurpleE2eeProvider *provider);
+
+/**
+ * Increment the reference count.
+ *
+ * @param state The E2EE state.
+ */
+void
+purple_e2ee_state_ref(PurpleE2eeState *state);
+
+/**
+ * Decrement the reference count.
+ *
+ * If the reference count reaches zero, the state will be freed.
+ *
+ * @param state The E2EE state.
+ *
+ * @return @a state or @c NULL if the reference count reached zero.
+ */
+PurpleE2eeState *
+purple_e2ee_state_unref(PurpleE2eeState *state);
+
+/**
+ * Gets the provider of specified E2EE state.
+ *
+ * @param state The E2EE state.
+ *
+ * @return The provider for this state.
+ */
+PurpleE2eeProvider *
+purple_e2ee_state_get_provider(PurpleE2eeState *state);
+
+/**
+ * Sets the name for the E2EE state.
+ *
+ * @param state The E2EE state.
+ * @param name  The localized name.
+ */
+void
+purple_e2ee_state_set_name(PurpleE2eeState *state, const gchar *name);
+
+/**
+ * Gets the name of the E2EE state.
+ *
+ * @param state The E2EE state.
+ *
+ * @return The localized name.
+ */
+const gchar *
+purple_e2ee_state_get_name(PurpleE2eeState *state);
+
+/**
+ * Sets the icon for the E2EE state.
+ *
+ * @param state      The E2EE state.
+ * @param stock_icon The stock icon identifier.
+ */
+void
+purple_e2ee_state_set_stock_icon(PurpleE2eeState *state,
+	const gchar *stock_icon);
+
+/**
+ * Gets the icon of the E2EE state.
+ *
+ * @param state The E2EE state.
+ *
+ * @return The stock icon identifier.
+ */
+const gchar *
+purple_e2ee_state_get_stock_icon(PurpleE2eeState *state);
+
+/*@}*/
+
+
+/**************************************************************************/
+/** @name Encryption providers API.                                       */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Creates new E2EE provider.
+ *
+ * @return New E2EE provider.
+ */
+PurpleE2eeProvider *
+purple_e2ee_provider_new(void);
+
+/**
+ * Destroys the E2EE provider.
+ *
+ * The provider have to be unregistered prior.
+ *
+ * @param provider The provider.
+ */
+void
+purple_e2ee_provider_free(PurpleE2eeProvider *provider);
+
+/**
+ * Registers the E2EE provider.
+ *
+ * Currently, there is no support for multiple E2EE providers - only the first
+ * one is registered.
+ *
+ * @param provider The E2EE provider.
+ *
+ * @return @c TRUE, if the provider was successfully registered,
+ *         @c FALSE otherwise.
+ */
+gboolean
+purple_e2ee_provider_register(PurpleE2eeProvider *provider);
+
+/**
+ * Unregisters the E2EE provider.
+ *
+ * @param provider The E2EE provider.
+ */
+void
+purple_e2ee_provider_unregister(PurpleE2eeProvider *provider);
+
+/**
+ * Gets main E2EE provider.
+ *
+ * @return The main E2EE provider.
+ */
+PurpleE2eeProvider *
+purple_e2ee_provider_get_main(void);
+
+/**
+ * Sets the name for the E2EE provider.
+ *
+ * @param provider The E2EE provider.
+ * @param name     The localized name.
+ */
+void
+purple_e2ee_provider_set_name(PurpleE2eeProvider *provider, const gchar *name);
+
+/**
+ * Gets the name of the E2EE provider.
+ *
+ * @param provider The E2EE provider.
+ *
+ * @return The localized name of specified E2EE provider.
+ */
+const gchar *
+purple_e2ee_provider_get_name(PurpleE2eeProvider *provider);
+
+/**
+ * Sets the conversation menu callback for the E2EE provider.
+ *
+ * The function is called, when user extends the E2EE menu for the conversation
+ * specified in its parameter.
+ *
+ * Function should return the GList of PurpleMenuAction objects.
+ *
+ * @param provider     The E2EE provider.
+ * @param conv_menu_cb The callback.
+ */
+void
+purple_e2ee_provider_set_conv_menu_cb(PurpleE2eeProvider *provider,
+	PurpleE2eeConvMenuCallback conv_menu_cb);
+
+/**
+ * Gets the conversation menu callback of the E2EE provider.
+ *
+ * @param provider The E2EE provider.
+ *
+ * @return The callback.
+ */
+PurpleE2eeConvMenuCallback
+purple_e2ee_provider_get_conv_menu_cb(PurpleE2eeProvider *provider);
+
+/*@}*/
+
+G_END_DECLS
+
+#endif /* _PURPLE_E2EE_H_ */
--- a/libpurple/imgstore.h	Thu Oct 24 20:24:29 2013 +0530
+++ b/libpurple/imgstore.h	Fri Oct 25 00:31:39 2013 +0530
@@ -31,6 +31,7 @@
 #include <glib.h>
 
 #define PURPLE_STORED_IMAGE_PROTOCOL "purple-image:"
+#define PURPLE_STOCK_IMAGE_PROTOCOL "purple-stock-image:"
 
 /** A reference-counted immutable wrapper around an image's data and its
  *  filename.
--- a/libpurple/plugins/perl/common/Request.xs	Thu Oct 24 20:24:29 2013 +0530
+++ b/libpurple/plugins/perl/common/Request.xs	Fri Oct 25 00:31:39 2013 +0530
@@ -487,10 +487,6 @@
 	Purple::Request::Field field
 
 gboolean
-purple_request_field_string_is_editable(field)
-	Purple::Request::Field field
-
-gboolean
 purple_request_field_string_is_masked(field)
 	Purple::Request::Field field
 
@@ -504,11 +500,6 @@
 	const char *default_value
 
 void
-purple_request_field_string_set_editable(field, editable)
-	Purple::Request::Field field
-	gboolean editable
-
-void
 purple_request_field_string_set_masked(field, masked)
 	Purple::Request::Field field
 	gboolean masked
--- a/libpurple/protocols/mxit/actions.c	Thu Oct 24 20:24:29 2013 +0530
+++ b/libpurple/protocols/mxit/actions.c	Fri Oct 25 00:31:39 2013 +0530
@@ -239,7 +239,7 @@
 		field = purple_request_field_string_new( "bday", _( "Birthday" ), profile->birthday, FALSE );
 		purple_request_field_group_add_field( public_group, field );
 		if ( profile->flags & CP_PROF_DOBLOCKED )
-			purple_request_field_string_set_editable( field, FALSE );
+			purple_request_field_set_sensitive( field, FALSE );
 
 		/* gender */
 		field = purple_request_field_choice_new( "male", _( "Gender" ), GINT_TO_POINTER(profile->male ? 1 : 0));
--- a/libpurple/protocols/mxit/login.c	Thu Oct 24 20:24:29 2013 +0530
+++ b/libpurple/protocols/mxit/login.c	Fri Oct 25 00:31:39 2013 +0530
@@ -338,7 +338,7 @@
 
 	/* mxit login name */
 	field = purple_request_field_string_new( "loginname", _( "MXit ID" ), purple_account_get_username( session->acc ), FALSE );
-	purple_request_field_string_set_editable( field, FALSE );
+	purple_request_field_set_sensitive( field, FALSE );
 	purple_request_field_group_add_field( group, field );
 
 	/* nick name (required) */
--- a/libpurple/request.c	Thu Oct 24 20:24:29 2013 +0530
+++ b/libpurple/request.c	Fri Oct 25 00:31:39 2013 +0530
@@ -59,6 +59,8 @@
 
 	gboolean visible;
 	gboolean required;
+	gboolean sensitive;
+	PurpleRequestFieldSensitivityCb sensitivity_cb;
 
 	union
 	{
@@ -66,7 +68,6 @@
 		{
 			gboolean multiline;
 			gboolean masked;
-			gboolean editable;
 			char *default_value;
 			char *value;
 
@@ -150,6 +151,8 @@
 
 	GList *validated_fields;
 
+	GList *autosensitive_fields;
+
 	void *ui_data;
 };
 
@@ -185,6 +188,9 @@
 	gpointer parent_from;
 };
 
+static void
+purple_request_fields_check_others_sensitivity(PurpleRequestField *field);
+
 PurpleRequestCommonParameters *
 purple_request_cpar_new(void)
 {
@@ -492,6 +498,7 @@
 	g_list_free(fields->groups);
 	g_list_free(fields->required_fields);
 	g_list_free(fields->validated_fields);
+	g_list_free(fields->autosensitive_fields);
 	g_hash_table_destroy(fields->fields);
 	g_free(fields);
 }
@@ -529,6 +536,10 @@
 				g_list_append(fields->validated_fields, field);
 		}
 
+		if (field->sensitivity_cb != NULL) {
+			fields->autosensitive_fields =
+				g_list_append(fields->autosensitive_fields, field);
+		}
 	}
 }
 
@@ -565,6 +576,14 @@
 	return fields->validated_fields;
 }
 
+const GList *
+purple_request_fields_get_autosensitive(const PurpleRequestFields *fields)
+{
+	g_return_val_if_fail(fields != NULL, NULL);
+
+	return fields->autosensitive_fields;
+}
+
 gboolean
 purple_request_fields_is_field_required(const PurpleRequestFields *fields,
 									  const char *id)
@@ -633,6 +652,37 @@
 	return TRUE;
 }
 
+static void
+purple_request_fields_check_sensitivity(PurpleRequestFields *fields)
+{
+	GList *it;
+
+	g_return_if_fail(fields != NULL);
+
+	for (it = fields->autosensitive_fields; it; it = g_list_next(it)) {
+		PurpleRequestField *field = it->data;
+
+		if (field->sensitivity_cb == NULL) {
+			g_warn_if_reached();
+			continue;
+		}
+
+		purple_request_field_set_sensitive(field,
+			field->sensitivity_cb(field));
+	}
+}
+
+static void
+purple_request_fields_check_others_sensitivity(PurpleRequestField *field)
+{
+	g_return_if_fail(field != NULL);
+
+	if (field->group == NULL || field->group->fields_list == NULL)
+		return;
+
+	purple_request_fields_check_sensitivity(field->group->fields_list);
+}
+
 PurpleRequestField *
 purple_request_fields_get_field(const PurpleRequestFields *fields, const char *id)
 {
@@ -779,12 +829,18 @@
 			group->fields_list->required_fields =
 				g_list_append(group->fields_list->required_fields, field);
 		}
-		
+
 		if (purple_request_field_is_validatable(field))
 		{
 			group->fields_list->validated_fields =
 				g_list_append(group->fields_list->validated_fields, field);
 		}
+
+		if (field->sensitivity_cb != NULL)
+		{
+			group->fields_list->autosensitive_fields =
+				g_list_append(group->fields_list->autosensitive_fields, field);
+		}
 	}
 
 	field->group = group;
@@ -831,6 +887,7 @@
 
 	purple_request_field_set_label(field, text);
 	purple_request_field_set_visible(field, TRUE);
+	purple_request_field_set_sensitive(field, TRUE);
 
 	return field;
 }
@@ -1082,6 +1139,45 @@
 	return valid;
 }
 
+void
+purple_request_field_set_sensitive(PurpleRequestField *field,
+	gboolean sensitive)
+{
+	g_return_if_fail(field != NULL);
+
+	field->sensitive = sensitive;
+}
+
+gboolean
+purple_request_field_is_sensitive(PurpleRequestField *field)
+{
+	g_return_val_if_fail(field != NULL, FALSE);
+
+	return field->sensitive;
+}
+
+void
+purple_request_field_set_sensitivity_cb(PurpleRequestField *field,
+	PurpleRequestFieldSensitivityCb cb)
+{
+	PurpleRequestFields *flist;
+
+	g_return_if_fail(field != NULL);
+
+	field->sensitivity_cb = cb;
+
+	if (!field->group || !field->group->fields_list)
+		return;
+	flist = field->group->fields_list;
+	flist->autosensitive_fields = g_list_remove(flist->autosensitive_fields,
+		field);
+	if (cb != NULL)
+	{
+		flist->autosensitive_fields = g_list_append(
+			flist->autosensitive_fields, field);
+	}
+}
+
 PurpleRequestField *
 purple_request_field_string_new(const char *id, const char *text,
 							  const char *default_value, gboolean multiline)
@@ -1094,7 +1190,6 @@
 	field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_STRING);
 
 	field->u.string.multiline = multiline;
-	field->u.string.editable  = TRUE;
 
 	purple_request_field_string_set_default_value(field, default_value);
 	purple_request_field_string_set_value(field, default_value);
@@ -1121,6 +1216,8 @@
 
 	g_free(field->u.string.value);
 	field->u.string.value = g_strdup(value);
+
+	purple_request_fields_check_others_sensitivity(field);
 }
 
 void
@@ -1132,16 +1229,6 @@
 	field->u.string.masked = masked;
 }
 
-void
-purple_request_field_string_set_editable(PurpleRequestField *field,
-									   gboolean editable)
-{
-	g_return_if_fail(field != NULL);
-	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_STRING);
-
-	field->u.string.editable = editable;
-}
-
 const char *
 purple_request_field_string_get_default_value(const PurpleRequestField *field)
 {
@@ -1178,15 +1265,6 @@
 	return field->u.string.masked;
 }
 
-gboolean
-purple_request_field_string_is_editable(const PurpleRequestField *field)
-{
-	g_return_val_if_fail(field != NULL, FALSE);
-	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_STRING, FALSE);
-
-	return field->u.string.editable;
-}
-
 PurpleRequestField *
 purple_request_field_int_new(const char *id, const char *text,
 	int default_value, int lower_bound, int upper_bound)
@@ -1249,6 +1327,8 @@
 	}
 
 	field->u.integer.value = value;
+
+	purple_request_fields_check_others_sensitivity(field);
 }
 
 int
@@ -1321,6 +1401,8 @@
 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_BOOLEAN);
 
 	field->u.boolean.value = value;
+
+	purple_request_fields_check_others_sensitivity(field);
 }
 
 gboolean
@@ -1389,6 +1471,8 @@
 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_CHOICE);
 
 	field->u.choice.value = value;
+
+	purple_request_fields_check_others_sensitivity(field);
 }
 
 gpointer
@@ -1741,6 +1825,8 @@
 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_ACCOUNT);
 
 	field->u.account.account = value;
+
+	purple_request_fields_check_others_sensitivity(field);
 }
 
 void
@@ -2231,6 +2317,8 @@
 		purple_request_fields_strip_html(fields);
 	}
 
+	purple_request_fields_check_sensitivity(fields);
+
 	if (ops != NULL && ops->request_fields != NULL) {
 		PurpleRequestInfo *info;
 		gchar **tmp;
--- a/libpurple/request.h	Thu Oct 24 20:24:29 2013 +0530
+++ b/libpurple/request.h	Fri Oct 25 00:31:39 2013 +0530
@@ -179,6 +179,8 @@
 typedef gboolean (*PurpleRequestFieldValidator)(PurpleRequestField *field,
 	gchar **errmsg, gpointer user_data);
 
+typedef gboolean (*PurpleRequestFieldSensitivityCb)(PurpleRequestField *field);
+
 /** The type of callbacks passed to purple_request_action().  The first
  *  argument is the @a user_data parameter; the second is the index in the list
  *  of actions of the one chosen.
@@ -516,6 +518,16 @@
 	const PurpleRequestFields *fields);
 
 /**
+ * Returns a list of all fields with sensitivity callback added.
+ *
+ * @param fields The fields list.
+ *
+ * @constreturn The list of fields with automatic sensitivity callback.
+ */
+const GList *
+purple_request_fields_get_autosensitive(const PurpleRequestFields *fields);
+
+/**
  * Returns whether or not a field with the specified ID is required.
  *
  * @param fields The fields list.
@@ -886,6 +898,33 @@
 gboolean purple_request_field_is_valid(PurpleRequestField *field, gchar **errmsg);
 
 /**
+ * Sets field editable.
+ *
+ * @param field     The field.
+ * @param sensitive TRUE if the field should be sensitive for user input.
+ */
+void purple_request_field_set_sensitive(PurpleRequestField *field,
+	gboolean sensitive);
+
+/**
+ * Checks, if field is editable.
+ *
+ * @param field The field.
+ *
+ * @return TRUE, if the field is sensitive for user input.
+ */
+gboolean purple_request_field_is_sensitive(PurpleRequestField *field);
+
+/**
+ * Sets the callback, used to determine if the field should be editable.
+ *
+ * @param field The field.
+ * @param cb    The callback.
+ */
+void purple_request_field_set_sensitivity_cb(PurpleRequestField *field,
+	PurpleRequestFieldSensitivityCb cb);
+
+/**
  * Returns the ui_data for a field.
  *
  * @param field The field.
@@ -956,15 +995,6 @@
 										  gboolean masked);
 
 /**
- * Sets whether or not a string field is editable.
- *
- * @param field    The field.
- * @param editable The editable value.
- */
-void purple_request_field_string_set_editable(PurpleRequestField *field,
-											gboolean editable);
-
-/**
  * Returns the default value in a string field.
  *
  * @param field The field.
@@ -1001,15 +1031,6 @@
  */
 gboolean purple_request_field_string_is_masked(const PurpleRequestField *field);
 
-/**
- * Returns whether or not a string field is editable.
- *
- * @param field The field.
- *
- * @return @c TRUE if the field is editable, or @c FALSE otherwise.
- */
-gboolean purple_request_field_string_is_editable(const PurpleRequestField *field);
-
 /*@}*/
 
 /**************************************************************************/
--- a/libpurple/util.c	Thu Oct 24 20:24:29 2013 +0530
+++ b/libpurple/util.c	Fri Oct 25 00:31:39 2013 +0530
@@ -40,6 +40,7 @@
 	PurpleCallback callback;
 	gpointer data;
 	GList *children;
+	gchar *stock_icon;
 };
 
 static char *custom_user_dir = NULL;
@@ -65,6 +66,7 @@
 {
 	g_return_if_fail(act != NULL);
 
+	g_free(act->stock_icon);
 	g_free(act->label);
 	g_free(act);
 }
@@ -125,6 +127,21 @@
 	act->children = children;
 }
 
+void purple_menu_action_set_stock_icon(PurpleMenuAction *act,
+	const gchar *stock)
+{
+	g_return_if_fail(act != NULL);
+
+	g_free(act->stock_icon);
+	act->stock_icon = g_strdup(stock);
+}
+
+const gchar *
+purple_menu_action_get_stock_icon(PurpleMenuAction *act)
+{
+	return act->stock_icon;
+}
+
 void
 purple_util_init(void)
 {
--- a/libpurple/util.h	Thu Oct 24 20:24:29 2013 +0530
+++ b/libpurple/util.h	Fri Oct 25 00:31:39 2013 +0530
@@ -154,6 +154,25 @@
 void purple_menu_action_set_children(PurpleMenuAction *act, GList *children);
 
 /**
+ * Sets the icon for the PurpleMenuAction.
+ *
+ * @param act    The menu action.
+ * @param strock The stock icon identifier.
+ */
+void purple_menu_action_set_stock_icon(PurpleMenuAction *act,
+	const gchar *stock);
+
+/**
+ * Gets the stock icon of the PurpleMenuAction.
+ *
+ * @param act The menu action.
+ *
+ * @return The stock icon identifier.
+ */
+const gchar *
+purple_menu_action_get_stock_icon(PurpleMenuAction *act);
+
+/**
  * Set the appropriate presence values for the currently playing song.
  *
  * @param title     The title of the song, @c NULL to unset the value.
--- a/pidgin/gtkconv.c	Thu Oct 24 20:24:29 2013 +0530
+++ b/pidgin/gtkconv.c	Fri Oct 25 00:31:39 2013 +0530
@@ -50,6 +50,7 @@
 #include "util.h"
 #include "version.h"
 
+#include "gtkinternal.h"
 #include "gtkdnd-hints.h"
 #include "gtkblist.h"
 #include "gtkconv.h"
@@ -119,7 +120,8 @@
 	PIDGIN_CONV_TAB_ICON			= 1 << 3,
 	PIDGIN_CONV_TOPIC			= 1 << 4,
 	PIDGIN_CONV_SMILEY_THEME		= 1 << 5,
-	PIDGIN_CONV_COLORIZE_TITLE		= 1 << 6
+	PIDGIN_CONV_COLORIZE_TITLE		= 1 << 6,
+	PIDGIN_CONV_E2EE			= 1 << 7
 }PidginConvFields;
 
 enum {
@@ -187,6 +189,7 @@
 static GList *xa_list = NULL;
 static GList *offline_list = NULL;
 static GHashTable *prpl_lists = NULL;
+static GHashTable *e2ee_stock = NULL;
 
 static PurpleTheme *default_conv_theme = NULL;
 
@@ -3916,12 +3919,28 @@
 	return FALSE;
 }
 
-static void
-create_sendto_item(GtkWidget *menu, GtkSizeGroup *sg, GSList **group, PurpleBuddy *buddy, PurpleAccount *account, const char *name)
+static GtkWidget *
+e2ee_state_to_gtkimage(PurpleE2eeState *state)
+{
+	PurpleStoredImage *img;
+
+	img = _pidgin_e2ee_stock_icon_get(
+		purple_e2ee_state_get_stock_icon(state));
+	if (!img)
+		return NULL;
+
+	return gtk_image_new_from_pixbuf(pidgin_pixbuf_from_imgstore(img));
+}
+
+static void
+create_sendto_item(GtkWidget *menu, GtkSizeGroup *sg, GSList **group,
+	PurpleBuddy *buddy, PurpleAccount *account, const char *name,
+	gboolean e2ee_enabled)
 {
 	GtkWidget *box;
 	GtkWidget *label;
 	GtkWidget *image;
+	GtkWidget *e2ee_image = NULL;
 	GtkWidget *menuitem;
 	GdkPixbuf *pixbuf;
 	gchar *text;
@@ -3938,6 +3957,20 @@
 		g_object_unref(G_OBJECT(pixbuf));
 	}
 
+	if (e2ee_enabled) {
+		PurpleIMConversation *im;
+		PurpleE2eeState *state = NULL;
+
+		im = purple_conversations_find_im_with_account(
+			purple_buddy_get_name(buddy), purple_buddy_get_account(buddy));
+		if (im)
+			state = purple_conversation_get_e2ee_state(PURPLE_CONVERSATION(im));
+		if (state)
+			e2ee_image = e2ee_state_to_gtkimage(state);
+		else
+			e2ee_image = gtk_image_new();
+	}
+
 	gtk_size_group_add_widget(sg, image);
 
 	/* Make our menu item */
@@ -3954,7 +3987,10 @@
 	gtk_container_remove(GTK_CONTAINER(menuitem), label);
 
 	gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 0);
+
 	gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 4);
+	if (e2ee_image)
+		gtk_box_pack_start(GTK_BOX(box), e2ee_image, FALSE, FALSE, 0);
 
 	if (buddy != NULL &&
 	    !purple_presence_is_online(purple_buddy_get_presence(buddy)))
@@ -3977,6 +4013,8 @@
 
 	gtk_widget_show(label);
 	gtk_widget_show(image);
+	if (e2ee_image)
+		gtk_widget_show(e2ee_image);
 	gtk_widget_show(box);
 
 	/* Set our data and callbacks. */
@@ -4042,6 +4080,7 @@
 		}
 		else
 		{
+			gboolean e2ee_enabled = FALSE;
 			GList *list = NULL, *iter;
 			for (l = buds; l != NULL; l = l->next)
 			{
@@ -4053,10 +4092,15 @@
 				{
 					PurpleBuddy *buddy = (PurpleBuddy *)node;
 					PurpleAccount *account;
+					PurpleIMConversation *im;
 
 					if (!PURPLE_IS_BUDDY(node))
 						continue;
 
+					im = purple_conversations_find_im_with_account(purple_buddy_get_name(buddy), purple_buddy_get_account(buddy));
+					if (im && purple_conversation_get_e2ee_state(PURPLE_CONVERSATION(im)) != NULL)
+						e2ee_enabled = TRUE;
+
 					account = purple_buddy_get_account(buddy);
 					/* TODO WEBKIT: (I'm not actually sure if this is webkit-related --Mark Doliner) */
 					if (purple_account_is_connected(account) /*|| account == purple_conversation_get_account(gtkconv->active_conv)*/)
@@ -4077,7 +4121,7 @@
 					PurplePresence *pre = iter->data;
 					PurpleBuddy *buddy = purple_buddy_presence_get_buddy(PURPLE_BUDDY_PRESENCE(pre));
 					create_sendto_item(menu, sg, &group, buddy,
-							purple_buddy_get_account(buddy), purple_buddy_get_name(buddy));
+							purple_buddy_get_account(buddy), purple_buddy_get_name(buddy), e2ee_enabled);
 				}
 			}
 			g_list_free(list);
@@ -4094,6 +4138,92 @@
 	update_send_to_selection(win);
 }
 
+PurpleStoredImage *
+_pidgin_e2ee_stock_icon_get(const gchar *stock_name)
+{
+	gchar filename[100], *path;
+	PurpleStoredImage *image;
+
+	/* core is quitting */
+	if (e2ee_stock == NULL)
+		return NULL;
+
+	if (g_hash_table_lookup_extended(e2ee_stock, stock_name, NULL, (gpointer*)&image))
+		return image;
+
+	g_snprintf(filename, sizeof(filename), "%s.png", stock_name);
+	path = g_build_filename(DATADIR, "pixmaps", "pidgin", "e2ee", "16",
+		filename, NULL);
+	image = purple_imgstore_new_from_file(path);
+	g_free(path);
+
+	g_hash_table_insert(e2ee_stock, g_strdup(stock_name), image);
+	return image;
+}
+
+static void
+generate_e2ee_controls(PidginWindow *win)
+{
+	PidginConversation *gtkconv;
+	PurpleConversation *conv;
+	PurpleE2eeState *state;
+	PurpleE2eeProvider *provider;
+	GtkWidget *menu;
+	PurpleE2eeConvMenuCallback menu_cb;
+	GList *menu_actions = NULL, *it;
+	GtkWidget *e2ee_image;
+
+	gtkconv = pidgin_conv_window_get_active_gtkconv(win);
+	g_return_if_fail(gtkconv != NULL);
+
+	conv = gtkconv->active_conv;
+	g_return_if_fail(conv != NULL);
+
+	if (win->menu->e2ee != NULL) {
+		gtk_widget_destroy(win->menu->e2ee);
+		win->menu->e2ee = NULL;
+	}
+
+	provider = purple_e2ee_provider_get_main();
+	state = purple_conversation_get_e2ee_state(conv);
+	if (state == NULL || provider == NULL)
+		return;
+	if (purple_e2ee_state_get_provider(state) != provider)
+		return;
+
+	win->menu->e2ee = gtk_image_menu_item_new_with_label(
+		purple_e2ee_provider_get_name(provider));
+
+	menu = gtk_menu_new();
+	gtk_menu_shell_insert(GTK_MENU_SHELL(win->menu->menubar),
+		win->menu->e2ee, 3);
+	gtk_menu_item_set_submenu(GTK_MENU_ITEM(win->menu->e2ee), menu);
+
+	e2ee_image = e2ee_state_to_gtkimage(state);
+	if (e2ee_image) {
+		gtk_image_menu_item_set_image(
+			GTK_IMAGE_MENU_ITEM(win->menu->e2ee), e2ee_image);
+	}
+
+	gtk_widget_set_tooltip_text(win->menu->e2ee,
+		purple_e2ee_state_get_name(state));
+
+	menu_cb = purple_e2ee_provider_get_conv_menu_cb(provider);
+	if (menu_cb)
+		menu_actions = menu_cb(conv);
+
+	for (it = g_list_first(menu_actions); it; it = g_list_next(it)) {
+		PurpleMenuAction *action = it->data;
+
+		gtk_widget_show_all(
+			pidgin_append_menu_action(menu, action, conv));
+	}
+	g_list_free(menu_actions);
+
+	gtk_widget_show(win->menu->e2ee);
+	gtk_widget_show(menu);
+}
+
 static const char *
 get_chat_user_status_icon(PurpleChatConversation *chat, const char *name, PurpleChatUserFlags flags)
 {
@@ -7364,6 +7494,9 @@
 		regenerate_plugins_items(win);
 	}
 
+	if (fields & PIDGIN_CONV_E2EE)
+		generate_e2ee_controls(win);
+
 	if (fields & PIDGIN_CONV_TAB_ICON)
 	{
 		update_tab_icon(conv);
@@ -7560,6 +7693,10 @@
 	{
 		flags = PIDGIN_CONV_MENU;
 	}
+	else if (type == PURPLE_CONVERSATION_UPDATE_E2EE)
+	{
+		flags = PIDGIN_CONV_E2EE | PIDGIN_CONV_MENU;
+	}
 
 	pidgin_conv_update_fields(conv, flags);
 }
@@ -8299,8 +8436,9 @@
 static void
 update_conversation_switched(PurpleConversation *conv)
 {
-	pidgin_conv_update_fields(conv, PIDGIN_CONV_TAB_ICON | PIDGIN_CONV_SET_TITLE |
-					PIDGIN_CONV_MENU | PIDGIN_CONV_BUDDY_ICON);
+	pidgin_conv_update_fields(conv, PIDGIN_CONV_TAB_ICON |
+		PIDGIN_CONV_SET_TITLE | PIDGIN_CONV_MENU |
+		PIDGIN_CONV_BUDDY_ICON | PIDGIN_CONV_E2EE );
 }
 
 static void
@@ -8505,6 +8643,17 @@
 	return &handle;
 }
 
+static void
+e2ee_stock_delete_value(gpointer value)
+{
+	PurpleStoredImage *img = value;
+
+	purple_imgstore_unref(img);
+}
+
+static void
+pidgin_conversations_pre_uninit(void);
+
 void
 pidgin_conversations_init(void)
 {
@@ -8512,6 +8661,9 @@
 	void *blist_handle = purple_blist_get_handle();
 	char *theme_dir;
 
+	e2ee_stock = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+		e2ee_stock_delete_value);
+
 	/* Conversations */
 	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/conversations");
 	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/conversations/themes");
@@ -8602,8 +8754,6 @@
 	purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/conversations/im/hide_new",
 								hide_new_pref_cb, NULL);
 
-
-
 	/**********************************************************************
 	 * Register signals
 	 **********************************************************************/
@@ -8725,6 +8875,9 @@
 	purple_signal_connect(purple_accounts_get_handle(), "account-status-changed",
 						handle, PURPLE_CALLBACK(account_status_changed_cb), NULL);
 
+	purple_signal_connect_priority(purple_get_core(), "quitting", handle,
+		PURPLE_CALLBACK(pidgin_conversations_pre_uninit), NULL, PURPLE_SIGNAL_PRIORITY_HIGHEST);
+
 	/* Callbacks to update a conversation */
 	purple_signal_connect(blist_handle, "blist-node-added", handle,
 						G_CALLBACK(buddy_update_cb), NULL);
@@ -8810,6 +8963,13 @@
 #endif
 }
 
+static void
+pidgin_conversations_pre_uninit(void)
+{
+	g_hash_table_destroy(e2ee_stock);
+	e2ee_stock = NULL;
+}
+
 void
 pidgin_conversations_uninit(void)
 {
@@ -9814,6 +9974,7 @@
 	                             purple_conversation_is_logging(conv));
 
 	generate_send_to_items(win);
+	generate_e2ee_controls(win);
 	regenerate_options_items(win);
 	regenerate_plugins_items(win);
 
--- a/pidgin/gtkconvwin.h	Thu Oct 24 20:24:29 2013 +0530
+++ b/pidgin/gtkconvwin.h	Fri Oct 25 00:31:39 2013 +0530
@@ -66,6 +66,7 @@
 	GtkAction *show_formatting_toolbar;
 
 	GtkWidget *send_to;
+	GtkWidget *e2ee;
 
 	GtkWidget *tray;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtkinternal.h	Fri Oct 25 00:31:39 2013 +0530
@@ -0,0 +1,36 @@
+/**
+ * @file gtkinternal.h Internal definitions and includes for Pidgin
+ * @ingroup pidgin
+ */
+
+/* pidgin
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+#ifndef _PIDGIN_INTERNAL_H_
+#define _PIDGIN_INTERNAL_H_
+
+G_BEGIN_DECLS
+
+PurpleStoredImage *
+_pidgin_e2ee_stock_icon_get(const gchar *stock_name);
+
+G_END_DECLS
+
+#endif /* _PIDGIN_INTERNAL_H_ */
--- a/pidgin/gtkrequest.c	Thu Oct 24 20:24:29 2013 +0530
+++ b/pidgin/gtkrequest.c	Fri Oct 25 00:31:39 2013 +0530
@@ -1073,6 +1073,7 @@
 	PurpleRequestFieldGroup *group;
 	PurpleRequestFields *fields;
 	PidginRequestData *req_data;
+	const GList *it;
 
 	group = purple_request_field_get_group(field);
 	fields = purple_request_field_group_get_fields_list(group);
@@ -1081,6 +1082,20 @@
 	gtk_widget_set_sensitive(req_data->ok_button,
 		purple_request_fields_all_required_filled(fields) &&
 		purple_request_fields_all_valid(fields));
+
+	it = purple_request_fields_get_autosensitive(fields);
+	for (; it != NULL; it = g_list_next(it)) {
+		PurpleRequestField *field = it->data;
+		GtkWidget *widget = purple_request_field_get_ui_data(field);
+		gboolean sensitive;
+
+		sensitive = purple_request_field_is_sensitive(field);
+		gtk_widget_set_sensitive(widget, sensitive);
+
+		/* XXX: and what about multiline? */
+		if (GTK_IS_EDITABLE(widget))
+			gtk_editable_set_editable(GTK_EDITABLE(widget), sensitive);
+	}
 }
 
 static void
@@ -1138,7 +1153,7 @@
 	gboolean is_editable;
 
 	value = purple_request_field_string_get_default_value(field);
-	is_editable = purple_request_field_string_is_editable(field);
+	is_editable = purple_request_field_is_sensitive(field);
 
 	if (purple_request_field_string_is_multiline(field))
 	{
@@ -1167,7 +1182,6 @@
 		gtk_widget_set_tooltip_text(textview, purple_request_field_get_tooltip(field));
 
 		gtk_text_view_set_editable(GTK_TEXT_VIEW(textview), is_editable);
-		gtk_widget_set_sensitive(textview, is_editable);
 
 		g_signal_connect(G_OBJECT(textview), "focus-out-event",
 						 G_CALLBACK(field_string_focus_out_cb), field);
@@ -1198,7 +1212,6 @@
 		}
 
 		gtk_editable_set_editable(GTK_EDITABLE(widget), is_editable);
-		gtk_widget_set_sensitive(widget, is_editable);
 
 		g_signal_connect(G_OBJECT(widget), "focus-out-event",
 						 G_CALLBACK(field_string_focus_out_cb), field);
@@ -1876,6 +1889,9 @@
 						continue;
 				}
 
+				gtk_widget_set_sensitive(widget,
+					purple_request_field_is_sensitive(field));
+
 				if (label)
 					gtk_label_set_mnemonic_widget(GTK_LABEL(label), widget);
 
--- a/pidgin/gtkutils.c	Thu Oct 24 20:24:29 2013 +0530
+++ b/pidgin/gtkutils.c	Fri Oct 25 00:31:39 2013 +0530
@@ -1724,13 +1724,31 @@
 {
 	GtkWidget *menuitem;
 	GList *list;
+	const gchar *stock_id;
+	GtkWidget *icon_image = NULL;
 
 	if (act == NULL) {
 		return pidgin_separator(menu);
 	}
 
+	stock_id = purple_menu_action_get_stock_icon(act);
+	if (stock_id) {
+		icon_image = gtk_image_new_from_stock(stock_id,
+			gtk_icon_size_from_name(
+				PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL));
+	}
+
+	if (icon_image) {
+		menuitem = gtk_image_menu_item_new_with_mnemonic(
+			purple_menu_action_get_label(act));
+		gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem),
+			icon_image);
+	} else {
+		menuitem = gtk_menu_item_new_with_mnemonic(
+			purple_menu_action_get_label(act));
+	}
+
 	list = purple_menu_action_get_children(act);
-	menuitem = gtk_menu_item_new_with_mnemonic(purple_menu_action_get_label(act));
 
 	if (list == NULL) {
 		PurpleCallback callback;
--- a/pidgin/gtkwebview.c	Thu Oct 24 20:24:29 2013 +0530
+++ b/pidgin/gtkwebview.c	Fri Oct 25 00:31:39 2013 +0530
@@ -34,6 +34,7 @@
 #include "gtkwebview.h"
 #include "gtkwebviewtoolbar.h"
 
+#include "gtkinternal.h"
 #include "gtk3compat.h"
 
 #define MAX_FONT_SIZE 7
@@ -687,12 +688,12 @@
                          gpointer user_data)
 {
 	const gchar *uri;
+	PurpleStoredImage *img = NULL;
+	const char *filename;
 
 	uri = webkit_network_request_get_uri(request);
 	if (purple_str_has_prefix(uri, PURPLE_STORED_IMAGE_PROTOCOL)) {
 		int id;
-		PurpleStoredImage *img;
-		const char *filename;
 
 		uri += sizeof(PURPLE_STORED_IMAGE_PROTOCOL) - 1;
 		id = strtoul(uri, NULL, 10);
@@ -700,17 +701,52 @@
 		img = purple_imgstore_find_by_id(id);
 		if (!img)
 			return;
-
+	} else if (purple_str_has_prefix(uri, PURPLE_STOCK_IMAGE_PROTOCOL)) {
+		gchar *p_uri, *found;
+		const gchar *domain, *stock_name;
+
+		uri += sizeof(PURPLE_STOCK_IMAGE_PROTOCOL) - 1;
+
+		p_uri = g_strdup(uri);
+		found = strchr(p_uri, '/');
+		if (!found) {
+			purple_debug_warning("webview", "Invalid purple stock "
+				"image uri: %s", uri);
+			return;
+		}
+
+		found[0] = '\0';
+		domain = p_uri;
+		stock_name = found + 1;
+
+		if (g_strcmp0(domain, "e2ee") == 0) {
+			img = _pidgin_e2ee_stock_icon_get(stock_name);
+			if (!img)
+				return;
+		} else {
+			purple_debug_warning("webview", "Invalid purple stock "
+				"image domain: %s", domain);
+			return;
+		}
+	} else
+		return;
+
+	if (img != NULL) {
 		filename = purple_imgstore_get_filename(img);
 		if (filename && g_path_is_absolute(filename)) {
-			char *tmp = g_strdup_printf("file://%s", filename);
+			gchar *tmp = g_strdup_printf("file://%s", filename);
 			webkit_network_request_set_uri(request, tmp);
 			g_free(tmp);
 		} else {
-			char *b64 = purple_base64_encode(purple_imgstore_get_data(img),
-			                                 purple_imgstore_get_size(img));
-			const char *type = purple_imgstore_get_extension(img);
-			char *tmp = g_strdup_printf("data:image/%s;base64,%s", type, b64);
+			gchar *b64, *tmp;
+			const gchar *type;
+
+			b64 = purple_base64_encode(
+				purple_imgstore_get_data(img),
+				purple_imgstore_get_size(img));
+			type = purple_imgstore_get_extension(img);
+			tmp = g_strdup_printf("data:image/%s;base64,%s",
+				type, b64);
 			webkit_network_request_set_uri(request, tmp);
 			g_free(b64);
 			g_free(tmp);
--- a/pidgin/pixmaps/Makefile.am	Thu Oct 24 20:24:29 2013 +0530
+++ b/pidgin/pixmaps/Makefile.am	Fri Oct 25 00:31:39 2013 +0530
@@ -88,6 +88,12 @@
 		dialogs/scalable/question.svg \
 		dialogs/scalable/warning.svg
 
+E2EE_STATES_16 = \
+		e2ee/16/finished.png \
+		e2ee/16/not-private.png \
+		e2ee/16/private.png \
+		e2ee/16/unverified.png
+
 EMBLEMS_16 = \
 		emblems/16/aol-client.png \
 		emblems/16/birthday.png \
@@ -561,6 +567,7 @@
 		$(DIALOGS_16) \
 		$(DIALOGS_64) \
 		$(DIALOGS_SCALABLE)	\
+		$(E2EE_STATES_16) \
 		$(EMBLEMS_16) \
 		$(EMBLEMS_SCALABLE)	\
 		$(PROTOCOLS_16) \
Binary file pidgin/pixmaps/e2ee/16/finished.png has changed
Binary file pidgin/pixmaps/e2ee/16/not-private.png has changed
Binary file pidgin/pixmaps/e2ee/16/private.png has changed
Binary file pidgin/pixmaps/e2ee/16/unverified.png has changed

mercurial