changeset 21787:f595326da191

merge of '38cb8ea7055d8c059d560031c45e5a2eedd4b4b5' and 'e01f47781596a32f43650b309f62df34c4825aed'
author Stu Tomlinson <stu@nosnilmot.com>
date Wed, 05 Dec 2007 20:45:38 +0000
parents 770c384b1803 (diff) e9f94dd202c8 (current diff)
children 29a4b8e5f4f6
files
diffstat 27 files changed, 188 insertions(+), 117 deletions(-) [+]
line wrap: on
line diff
--- a/doc/account-signals.dox	Wed Dec 05 20:44:34 2007 +0000
+++ b/doc/account-signals.dox	Wed Dec 05 20:45:38 2007 +0000
@@ -9,6 +9,7 @@
   @signal account-setting-info
   @signal account-set-info
   @signal account-status-changed
+  @signal account-alias-changed
   @signal account-authorization-requested
   @signal account-authorization-denied
   @signal account-authorization-granted
--- a/doc/blist-signals.dox	Wed Dec 05 20:44:34 2007 +0000
+++ b/doc/blist-signals.dox	Wed Dec 05 20:45:38 2007 +0000
@@ -82,6 +82,14 @@
    Emitted when a new buddy is added to the buddy list.
   @endsignaldef
 
+ @signaldef buddy-removed
+  @signalproto
+void (*buddy_removed)(PurpleBuddy *buddy)
+  @endsignalproto
+  @signaldesc
+   Emitted when a buddy is removed from the buddy list.
+  @endsignaldef
+
  @signaldef buddy-icon-changed
   @signalproto
 void (*buddy_icon_changed)(PurpleBuddy *buddy)
@@ -90,14 +98,6 @@
    Emitted when a buddy's icon is set.
   @endsignaldef
 
- @signaldef buddy-removed
-  @signalproto
-void (*buddy_removed)(PurpleBuddy *buddy)
-  @endsignalproto
-  @signaldesc
-   Emitted when a buddy is removed from the buddy list.
-  @endsignaldef
-
  @signaldef blist-node-aliased
   @signalproto
 void (*blist_node_aliased)(PurpleBlistNode *node, const char *old_alias)
--- a/doc/gtkconv-signals.dox	Wed Dec 05 20:44:34 2007 +0000
+++ b/doc/gtkconv-signals.dox	Wed Dec 05 20:45:38 2007 +0000
@@ -28,12 +28,14 @@
 
  @signaldef conversation-timestamp
   @signalproto
-char *(*conversation_timestamp)(PurpleConversation *conv, time_t when);
+char *(*conversation_timestamp)(PurpleConversation *conv, time_t when,
+                                gboolean show_date);
   @endsignalproto
   @signaldesc
    Emitted to allow plugins to customize the timestamp on a message.
-  @param conv The conversation the message belongs to.
-  @param when The time to be converted to a string.
+  @param conv      The conversation the message belongs to.
+  @param when      The time to be converted to a string.
+  @param show_date Whether the date should be displayed.
   @return A textual representation of the time, or @c NULL to use a
           default format.
  @endsignaldef
--- a/doc/log-signals.dox	Wed Dec 05 20:44:34 2007 +0000
+++ b/doc/log-signals.dox	Wed Dec 05 20:45:38 2007 +0000
@@ -10,13 +10,14 @@
 
  @signaldef log-timestamp
   @signalproto
-char *(*log_timestamp)(PurpleLog *log, time_t when);
+char *(*log_timestamp)(PurpleLog *log, time_t when, gboolean show_date);
   @endsignalproto
   @signaldesc
    Emitted to allow plugins to customize the timestamp on a message
    being logged.
-  @param log The log the message belongs to.
-  @param when The time to be converted to a string.
+  @param log       The log the message belongs to.
+  @param when      The time to be converted to a string.
+  @param show_date Whether the date should be displayed.
   @return A textual representation of the time, or @c NULL to use a
           default format.
   @note Plugins must be careful of logs with a type of PURPLE_LOG_SYSTEM.
--- a/finch/libgnt/gntstyle.c	Wed Dec 05 20:44:34 2007 +0000
+++ b/finch/libgnt/gntstyle.c	Wed Dec 05 20:45:38 2007 +0000
@@ -66,13 +66,15 @@
 	int fg = 0, bg = 0;
 	gsize n;
 	char **vals;
+	int ret = 0;
 	vals = gnt_style_get_string_list(group, key, &n);
 	if (vals && n == 2) {
 		fg = gnt_colors_get_color(vals[0]);
 		bg = gnt_colors_get_color(vals[1]);
-		return gnt_color_add_pair(fg, bg);
+		ret = gnt_color_add_pair(fg, bg);
 	}
-	return 0;
+	g_strfreev(vals);
+	return ret;
 #else
 	return 0;
 #endif
--- a/libpurple/ft.c	Wed Dec 05 20:44:34 2007 +0000
+++ b/libpurple/ft.c	Wed Dec 05 20:45:38 2007 +0000
@@ -1306,8 +1306,12 @@
 }
 
 void
-purple_xfers_uninit(void) {
-	purple_signals_disconnect_by_handle(purple_xfers_get_handle());
+purple_xfers_uninit(void)
+{
+	void *handle = purple_xfers_get_handle();
+
+	purple_signals_disconnect_by_handle(handle);
+	purple_signals_unregister_by_instance(handle);
 }
 
 void
--- a/libpurple/network.c	Wed Dec 05 20:44:34 2007 +0000
+++ b/libpurple/network.c	Wed Dec 05 20:45:38 2007 +0000
@@ -710,4 +710,7 @@
 	if(nm_context)
 		libnm_glib_shutdown(nm_context);
 #endif
+
+	purple_signal_unregister(purple_network_get_handle(),
+	                         "network-configuration-changed");
 }
--- a/libpurple/plugin.c	Wed Dec 05 20:44:34 2007 +0000
+++ b/libpurple/plugin.c	Wed Dec 05 20:45:38 2007 +0000
@@ -1175,7 +1175,7 @@
 purple_plugins_init(void) {
 	void *handle = purple_plugins_get_handle();
 
-        purple_plugins_add_search_path(LIBDIR);
+	purple_plugins_add_search_path(LIBDIR);
 
 	purple_signal_register(handle, "plugin-load",
 						 purple_marshal_VOID__POINTER,
@@ -1190,8 +1190,12 @@
 }
 
 void
-purple_plugins_uninit(void) {
-	purple_signals_disconnect_by_handle(purple_plugins_get_handle());
+purple_plugins_uninit(void)
+{
+	void *handle = purple_plugins_get_handle();
+
+	purple_signals_disconnect_by_handle(handle);
+	purple_signals_unregister_by_instance(handle);
 }
 
 /**************************************************************************
--- a/libpurple/plugins/autoaccept.c	Wed Dec 05 20:44:34 2007 +0000
+++ b/libpurple/plugins/autoaccept.c	Wed Dec 05 20:45:38 2007 +0000
@@ -114,22 +114,33 @@
 		case FT_ACCEPT:
 			if (ensure_path_exists(pref))
 			{
-				dirname = g_build_filename(pref, xfer->who, NULL);
+				int count = 1;
+				const char *escape;
+				dirname = g_build_filename(pref, purple_normalize(account, xfer->who), NULL);
 
 				if (!ensure_path_exists(dirname))
 				{
 					g_free(dirname);
 					break;
 				}
-				
-				filename = g_build_filename(dirname, xfer->filename, NULL);
+
+				escape = purple_escape_filename(xfer->filename);
+				filename = g_build_filename(dirname, escape, NULL);
+
+				/* Make sure the file doesn't exist. Do we want some better checking than this? */
+				while (g_file_test(filename, G_FILE_TEST_EXISTS)) {
+					char *file = g_strdup_printf("%s-%d", escape, count++);
+					g_free(filename);
+					filename = g_build_filename(dirname, file, NULL);
+					g_free(file);
+				}
 
 				purple_xfer_request_accepted(xfer, filename);
 
 				g_free(dirname);
 				g_free(filename);
 			}
-			
+
 			purple_signal_connect(purple_xfers_get_handle(), "file-recv-complete", handle,
 								PURPLE_CALLBACK(auto_accept_complete_cb), xfer);
 			break;
--- a/libpurple/plugins/perl/common/BuddyList.xs	Wed Dec 05 20:44:34 2007 +0000
+++ b/libpurple/plugins/perl/common/BuddyList.xs	Wed Dec 05 20:45:38 2007 +0000
@@ -44,11 +44,13 @@
 	Purple::Account account
 	const char * name
 PREINIT:
-	GSList *l;
+	GSList *l, *ll;
 PPCODE:
-	for (l = purple_find_buddies(account, name); l != NULL; l = l->next) {
+	ll = purple_find_buddies(account, name);
+	for (l = ll; l != NULL; l = l->next) {
 		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::BuddyList::Buddy")));
 	}
+	g_slist_free(ll);
 
 Purple::BuddyList::Group
 purple_find_group(name)
@@ -101,11 +103,13 @@
 purple_group_get_accounts(group)
 	Purple::BuddyList::Group  group
 PREINIT:
-	GSList *l;
+	GSList *l, *ll;
 PPCODE:
-	for (l = purple_group_get_accounts(group); l != NULL; l = l->next) {
+	ll = purple_group_get_accounts(group);
+	for (l = ll; l != NULL; l = l->next) {
 		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Account")));
 	}
+	g_slist_free(ll);
 
 gboolean
 purple_group_on_account(group, account)
@@ -268,11 +272,15 @@
 purple_blist_node_get_extended_menu(node)
 	Purple::BuddyList::Node node
 PREINIT:
-	GList *l;
+	GList *l, *ll;
 PPCODE:
-	for (l = purple_blist_node_get_extended_menu(node); l != NULL; l = g_list_delete_link(l, l)) {
+	ll = purple_blist_node_get_extended_menu(node);
+	for (l = ll; l != NULL; l = l->next) {
 		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Menu::Action")));
 	}
+	/* We can free the list here but the script needs to free the
+	 * Purple::Menu::Action 'objects' itself. */
+	g_list_free(ll);
 
 void
 purple_blist_node_set_bool(node, key, value)
--- a/libpurple/plugins/perl/common/Cmds.xs	Wed Dec 05 20:44:34 2007 +0000
+++ b/libpurple/plugins/perl/common/Cmds.xs	Wed Dec 05 20:45:38 2007 +0000
@@ -66,21 +66,23 @@
 	Purple::Conversation conv
 	const gchar *command
 PREINIT:
-	GList *l;
+	GList *l, *ll;
 PPCODE:
-	for (l = purple_cmd_help(conv, command); l != NULL; l = l->next) {
+	for (l = ll = purple_cmd_help(conv, command); l != NULL; l = l->next) {
 		XPUSHs(sv_2mortal(newSVpv(l->data, 0)));
 	}
+	g_list_free(ll);
 
 void
 purple_cmd_list(conv)
 	Purple::Conversation conv
 PREINIT:
-	GList *l;
+	GList *l, *ll;
 PPCODE:
-	for (l = purple_cmd_list(conv); l != NULL; l = l->next) {
+	for (l = ll = purple_cmd_list(conv); l != NULL; l = l->next) {
 		XPUSHs(sv_2mortal(newSVpv(l->data, 0)));
 	}
+	g_list_free(ll);
 
 Purple::Cmd::Id
 purple_cmd_register(plugin, command, args, priority, flag, prpl_id, func, helpstr, data = 0)
--- a/libpurple/plugins/perl/common/Conversation.xs	Wed Dec 05 20:44:34 2007 +0000
+++ b/libpurple/plugins/perl/common/Conversation.xs	Wed Dec 05 20:45:38 2007 +0000
@@ -464,6 +464,10 @@
 
 	purple_conv_chat_add_users(chat, t_GL_users, t_GL_extra_msgs, t_GL_flags, new_arrivals);
 
+	g_list_free(t_GL_users);
+	g_list_free(t_GL_extra_msgs);
+	g_list_free(t_GL_flags);
+
 gboolean
 purple_conv_chat_find_user(chat, user)
 	Purple::Conversation::Chat chat
--- a/libpurple/plugins/perl/common/Log.xs	Wed Dec 05 20:44:34 2007 +0000
+++ b/libpurple/plugins/perl/common/Log.xs	Wed Dec 05 20:45:38 2007 +0000
@@ -65,11 +65,15 @@
 	const char *name
 	Purple::Account account
 PREINIT:
-	GList *l;
+	GList *l, *ll;
 PPCODE:
-	for (l = purple_log_get_logs(type, name, account); l != NULL; l = l->next) {
-		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::ListEntry")));
+	ll = purple_log_get_logs(type, name, account);
+	for (l = ll; l != NULL; l = l->next) {
+		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Log")));
 	}
+	/* We can free the list here but the script needs to free the
+	 * Purple::Log 'objects' itself. */
+	g_list_free(ll);
 
 int
 purple_log_get_size(log)
@@ -79,11 +83,15 @@
 purple_log_get_system_logs(account)
 	Purple::Account account
 PREINIT:
-	GList *l;
+	GList *l, *ll;
 PPCODE:
-	for (l = purple_log_get_system_logs(account); l != NULL; l = l->next) {
-		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::ListEntry")));
+	ll = purple_log_get_system_logs(account);
+	for (l = ll; l != NULL; l = l->next) {
+		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Log")));
 	}
+	/* We can free the list here but the script needs to free the
+	 * Purple::Log 'objects' itself. */
+	g_list_free(ll);
 
 int
 purple_log_get_total_size(type, name, account)
@@ -101,11 +109,14 @@
 void
 purple_log_logger_get_options()
 PREINIT:
-	GList *l;
+	GList *l, *ll;
 PPCODE:
-	for (l = purple_log_logger_get_options(); l != NULL; l = l->next) {
-		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::ListEntry")));
+	/* This might want to be massaged to a hash, since that's essentially
+	 * what the key/value list is emulating. */
+	for (l = ll = purple_log_logger_get_options(); l != NULL; l = l->next) {
+		XPUSHs(sv_2mortal(newSVpv(l->data, 0)));
 	}
+	g_list_free(ll);
 
 gchar_own *
 purple_log_read(log, flags)
--- a/libpurple/plugins/perl/common/Pounce.xs	Wed Dec 05 20:44:34 2007 +0000
+++ b/libpurple/plugins/perl/common/Pounce.xs	Wed Dec 05 20:45:38 2007 +0000
@@ -106,6 +106,18 @@
 		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Pounce")));
 	}
 
+void
+purple_pounces_get_all_for_ui(ui)
+	const char *ui
+PREINIT:
+	GList *l, *ll;
+PPCODE:
+	ll = purple_pounces_get_all_for_ui(ui);
+	for (l = ll; l != NULL; l = l->next) {
+		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Pounce")));
+	}
+	g_list_free(ll);
+
 Purple::Handle
 purple_pounces_get_handle()
 
--- a/libpurple/plugins/perl/common/Prefs.xs	Wed Dec 05 20:44:34 2007 +0000
+++ b/libpurple/plugins/perl/common/Prefs.xs	Wed Dec 05 20:45:38 2007 +0000
@@ -57,6 +57,7 @@
 		t_GL = g_list_append(t_GL, SvPV(*av_fetch((AV *)SvRV(value), i, 0), t_sl));
 	}
 	purple_prefs_add_string_list(name, t_GL);
+	g_list_free(t_GL);
 
 void
 purple_prefs_destroy()
@@ -159,6 +160,7 @@
 		t_GL = g_list_append(t_GL, SvPV(*av_fetch((AV *)SvRV(value), i, 0), t_sl));
 	}
 	purple_prefs_set_string_list(name, t_GL);
+	g_list_free(t_GL);
 
 void
 purple_prefs_trigger_callback(name)
--- a/libpurple/plugins/perl/common/Prpl.xs	Wed Dec 05 20:44:34 2007 +0000
+++ b/libpurple/plugins/perl/common/Prpl.xs	Wed Dec 05 20:45:38 2007 +0000
@@ -21,13 +21,15 @@
 	Purple::Account account
 	Purple::Presence presence
 PREINIT:
-	GList *l;
+	GList *l, *ll;
 PPCODE:
-	for (l = purple_prpl_get_statuses(account,presence); l != NULL; l = l->next) {
-		/* XXX Someone please test and make sure this is the right
-		 * type for these things. */
+	ll = purple_prpl_get_statuses(account,presence);
+	for (l = ll; l != NULL; l = l->next) {
 		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Status")));
 	}
+	/* We can free the list here but the script needs to free the
+	 * Purple::Status 'objects' itself. */
+	g_list_free(ll);
 
 void
 purple_prpl_got_account_idle(account, idle, idle_time)
--- a/libpurple/plugins/perl/common/SavedStatuses.xs	Wed Dec 05 20:44:34 2007 +0000
+++ b/libpurple/plugins/perl/common/SavedStatuses.xs	Wed Dec 05 20:45:38 2007 +0000
@@ -140,11 +140,13 @@
 purple_savedstatuses_get_popular(how_many)
 	unsigned int how_many
 PREINIT:
-	GList *l;
+	GList *l, *ll;
 PPCODE:
-	for (l = purple_savedstatuses_get_popular(how_many); l != NULL; l = l->next) {
+	ll = purple_savedstatuses_get_popular(how_many);
+	for (l = ll; l != NULL; l = l->next) {
 		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::SavedStatus")));
 	}
+	g_list_free(ll);
 
 Purple::Handle
 purple_savedstatuses_get_handle()
--- a/libpurple/plugins/perl/common/Status.xs	Wed Dec 05 20:44:34 2007 +0000
+++ b/libpurple/plugins/perl/common/Status.xs	Wed Dec 05 20:45:38 2007 +0000
@@ -90,6 +90,7 @@
 		t_GL = g_list_append(t_GL, SvPV(*av_fetch((AV *)SvRV(source_list), i, 0), t_sl));
 	}
 	purple_presence_add_list(presence, t_GL);
+	g_list_free(t_GL);
 
 void
 purple_presence_add_status(presence, status)
@@ -361,28 +362,6 @@
 purple_status_type_destroy(status_type)
 	Purple::StatusType status_type
 
-Purple::StatusType
-purple_status_type_find_with_id(status_types, id)
-	SV *status_types
-	const char *id
-PREINIT:
-/* XXX Check that this function actually works, I think it might need a */
-/* status_type as it's first argument to work as $status_type->find_with_id */
-/* properly. */
-	GList *t_GL;
-	int i, t_len;
-CODE:
-	t_GL = NULL;
-	t_len = av_len((AV *)SvRV(status_types));
-
-	for (i = 0; i < t_len; i++) {
-		STRLEN t_sl;
-		t_GL = g_list_append(t_GL, SvPV(*av_fetch((AV *)SvRV(status_types), i, 0), t_sl));
-	}
-	RETVAL = (PurpleStatusType *)purple_status_type_find_with_id(t_GL, id);
-OUTPUT:
-	RETVAL
-
 Purple::StatusAttr
 purple_status_type_get_attr(status_type, id)
 	Purple::StatusType status_type
@@ -398,6 +377,26 @@
 		XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::StatusAttr")));
 	}
 
+Purple::StatusType
+purple_status_type_find_with_id(status_types, id)
+	SV *status_types
+	const char *id
+PREINIT:
+	GList *t_GL;
+	int i, t_len;
+CODE:
+	t_GL = NULL;
+	t_len = av_len((AV *)SvRV(status_types));
+
+	for (i = 0; i < t_len; i++) {
+		STRLEN t_sl;
+		t_GL = g_list_append(t_GL, SvPV(*av_fetch((AV *)SvRV(status_types), i, 0), t_sl));
+	}
+	RETVAL = (PurpleStatusType *)purple_status_type_find_with_id(t_GL, id);
+	g_list_free(t_GL);
+OUTPUT:
+	RETVAL
+
 const char *
 purple_status_type_get_id(status_type)
 	Purple::StatusType status_type
--- a/libpurple/protocols/irc/irc.c	Wed Dec 05 20:44:34 2007 +0000
+++ b/libpurple/protocols/irc/irc.c	Wed Dec 05 20:45:38 2007 +0000
@@ -184,9 +184,14 @@
 /* XXX I don't like messing directly with these buddies */
 gboolean irc_blist_timeout(struct irc_conn *irc)
 {
-	GString *string = g_string_sized_new(512);
+	GString *string;
 	char *list, *buf;
 
+	if (irc->ison_outstanding)
+		return TRUE;
+
+	string = g_string_sized_new(512);
+
 	g_hash_table_foreach(irc->buddies, (GHFunc)irc_buddy_append, (gpointer)string);
 
 	list = g_string_free(string, FALSE);
@@ -200,6 +205,8 @@
 	irc_send(irc, buf);
 	g_free(buf);
 
+	irc->ison_outstanding = TRUE;
+
 	return TRUE;
 }
 
--- a/libpurple/protocols/irc/irc.h	Wed Dec 05 20:44:34 2007 +0000
+++ b/libpurple/protocols/irc/irc.h	Wed Dec 05 20:45:38 2007 +0000
@@ -56,6 +56,8 @@
 	guint timer;
 	GHashTable *buddies;
 
+	gboolean ison_outstanding;
+
 	char *inbuf;
 	int inbuflen;
 	int inbufused;
--- a/libpurple/protocols/irc/msgs.c	Wed Dec 05 20:44:34 2007 +0000
+++ b/libpurple/protocols/irc/msgs.c	Wed Dec 05 20:45:38 2007 +0000
@@ -707,6 +707,7 @@
 	g_strfreev(nicks);
 
 	g_hash_table_foreach(irc->buddies, (GHFunc)irc_buddy_status, (gpointer)irc);
+	irc->ison_outstanding = FALSE;
 }
 
 static void irc_buddy_status(char *name, struct irc_buddy *ib, struct irc_conn *irc)
--- a/libpurple/protocols/msn/notification.c	Wed Dec 05 20:44:34 2007 +0000
+++ b/libpurple/protocols/msn/notification.c	Wed Dec 05 20:45:38 2007 +0000
@@ -1777,7 +1777,7 @@
 			passport = msn_user_get_passport(session->user);
 			url = session->passport_info.file;
 
-			purple_notify_emails(gc, atoi(unread), FALSE, NULL, NULL,
+			purple_notify_emails(gc, count, FALSE, NULL, NULL,
 							   &passport, &url, NULL, NULL);
 		}
 	}
@@ -1850,7 +1850,7 @@
 			passport = msn_user_get_passport(session->user);
 			url = session->passport_info.file;
 
-			purple_notify_emails(gc, atoi(unread), FALSE, NULL, NULL,
+			purple_notify_emails(gc, count, FALSE, NULL, NULL,
 							   &passport, &url, NULL, NULL);
 		}
 	}
--- a/libpurple/protocols/msn/oim.c	Wed Dec 05 20:44:34 2007 +0000
+++ b/libpurple/protocols/msn/oim.c	Wed Dec 05 20:45:38 2007 +0000
@@ -488,10 +488,12 @@
 		char *unread = xmlnode_get_data(iu_node);
 		const char *passport = msn_user_get_passport(session->user);
 		const char *url = session->passport_info.file;
+		int count = atoi(unread);
 
 		/* XXX/khc: pretty sure this is wrong */
-		purple_notify_emails(session->account->gc, atoi(unread), FALSE, NULL,
-			NULL, &passport, &url, NULL, NULL);
+		if (count > 0)
+			purple_notify_emails(session->account->gc, count, FALSE, NULL,
+				NULL, &passport, &url, NULL, NULL);
 		g_free(unread);
 	}
 
--- a/pidgin/gtkblist.c	Wed Dec 05 20:44:34 2007 +0000
+++ b/pidgin/gtkblist.c	Wed Dec 05 20:45:38 2007 +0000
@@ -3170,6 +3170,7 @@
 		GList *cur;
 		struct proto_chat_entry *pce;
 		char *name, *value;
+		PidginBlistNode *bnode = node->ui_data;
 
 		chat = (PurpleChat *)node;
 		prpl = purple_find_prpl(purple_account_get_protocol_id(chat->account));
@@ -3182,6 +3183,13 @@
 			g_free(tmp);
 		}
 
+		if (bnode && bnode->conv.conv &&
+				prpl_info && (prpl_info->options & OPT_PROTO_CHAT_TOPIC) &&
+				!purple_conv_chat_has_left(PURPLE_CONV_CHAT(bnode->conv.conv))) {
+			const char *topic = purple_conv_chat_get_topic(PURPLE_CONV_CHAT(bnode->conv.conv));
+			g_string_append_printf(str, _("\n<b>Topic:</b> %s"), topic ? topic : _("(no topic set)"));
+		}
+
 		if (prpl_info->chat_info != NULL)
 			cur = prpl_info->chat_info(chat->account->gc);
 		else
@@ -3251,7 +3259,7 @@
 		/* Alias */
 		/* If there's not a contact alias, the node is being displayed with
 		 * this alias, so there's no point in showing it in the tooltip. */
-		if (full && b->alias != NULL && b->alias[0] != '\0' &&
+		if (full && c && b->alias != NULL && b->alias[0] != '\0' &&
 		    (c->alias != NULL && c->alias[0] != '\0') &&
 		    strcmp(c->alias, b->alias) != 0)
 		{
@@ -3302,13 +3310,13 @@
 		}
 
 		/* Last Seen */
-		if (full && !PURPLE_BUDDY_IS_ONLINE(b))
+		if (full && c && !PURPLE_BUDDY_IS_ONLINE(b))
 		{
 			struct _pidgin_blist_node *gtknode = ((PurpleBlistNode *)c)->ui_data;
 			PurpleBlistNode *bnode;
 			int lastseen = 0;
 
-			if (!gtknode->contact_expanded || PURPLE_BLIST_NODE_IS_CONTACT(node))
+			if (gtknode && (!gtknode->contact_expanded || PURPLE_BLIST_NODE_IS_CONTACT(node)))
 			{
 				/* We're either looking at a buddy for a collapsed contact or
 				 * an expanded contact itself so we show the most recent
@@ -4091,7 +4099,7 @@
 		PurpleConversation *conv, PurpleMessageFlags flag, PurpleBlistNode *node)
 {
 	PidginBlistNode *ui = node->ui_data;
-	if (ui->conv.conv != conv || PIDGIN_CONVERSATION(conv) ||
+	if (ui->conv.conv != conv || !pidgin_conv_is_hidden(PIDGIN_CONVERSATION(conv)) ||
 			!(flag & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV)))
 		return;
 	ui->conv.flags |= PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE;
@@ -4100,11 +4108,10 @@
 }
 
 static void
-displayed_msg_update_ui_cb(PurpleAccount *account, const char *who, const char *message,
-		PurpleConversation *conv, PurpleMessageFlags flag, PurpleBlistNode *node)
+displayed_msg_update_ui_cb(PidginConversation *gtkconv, PurpleBlistNode *node)
 {
 	PidginBlistNode *ui = node->ui_data;
-	if (ui->conv.conv != conv)
+	if (ui->conv.conv != gtkconv->active_conv)
 		return;
 	ui->conv.flags &= ~PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE;
 	pidgin_blist_update(purple_get_blist(), node);
@@ -4130,10 +4137,11 @@
 							ui, PURPLE_CALLBACK(conversation_deleted_update_ui_cb), ui);
 					purple_signal_connect(purple_conversations_get_handle(), "wrote-im-msg",
 							ui, PURPLE_CALLBACK(written_msg_update_ui_cb), buddy);
-					purple_signal_connect(pidgin_conversations_get_handle(), "displayed-im-msg",
+					purple_signal_connect(pidgin_conversations_get_handle(), "conversation-displayed",
 							ui, PURPLE_CALLBACK(displayed_msg_update_ui_cb), buddy);
 				}
 			}
+			break;
 		case PURPLE_CONV_TYPE_CHAT:
 			{
 				PurpleChat *chat = purple_blist_find_chat(conv->account, conv->name);
@@ -4150,9 +4158,10 @@
 						ui, PURPLE_CALLBACK(conversation_deleted_update_ui_cb), ui);
 				purple_signal_connect(purple_conversations_get_handle(), "wrote-chat-msg",
 						ui, PURPLE_CALLBACK(written_msg_update_ui_cb), chat);
-				purple_signal_connect(pidgin_conversations_get_handle(), "displayed-chat-msg",
+				purple_signal_connect(pidgin_conversations_get_handle(), "conversation-displayed",
 						ui, PURPLE_CALLBACK(displayed_msg_update_ui_cb), chat);
 			}
+			break;
 		default:
 			break;
 	}
@@ -5961,7 +5970,8 @@
 
 		ui = node->ui_data;
 		conv = ui->conv.conv;
-		hidden = (conv && (ui->conv.flags & PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE));
+		hidden = (conv && (ui->conv.flags & PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE) &&
+				pidgin_conv_is_hidden(PIDGIN_CONVERSATION(conv)));
 
 		status = pidgin_blist_get_status_icon(node,
 				 biglist ? PIDGIN_STATUS_ICON_LARGE : PIDGIN_STATUS_ICON_SMALL);
--- a/pidgin/gtkconv.c	Wed Dec 05 20:44:34 2007 +0000
+++ b/pidgin/gtkconv.c	Wed Dec 05 20:45:38 2007 +0000
@@ -5093,7 +5093,7 @@
 	    !purple_status_is_available(purple_account_get_active_status(account)))
 		hide = TRUE;
 
-	if (PIDGIN_IS_PIDGIN_CONVERSATION(conv) && !hide) {
+	if (conv && PIDGIN_IS_PIDGIN_CONVERSATION(conv) && !hide) {
 		PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
 		if (gtkconv->win == hidden_convwin) {
 			pidgin_conv_window_remove_gtkconv(gtkconv->win, gtkconv);
@@ -6638,7 +6638,6 @@
 			unseen = PIDGIN_UNSEEN_TEXT;
 
 		conv_set_unseen(conv, unseen);
-		purple_conversation_update(conv, PURPLE_CONV_UPDATE_UNSEEN);
 	}
 }
 
@@ -7495,6 +7494,8 @@
 			return FALSE;
 		pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv);
 		pidgin_conv_placement_place(gtkconv);
+		purple_signal_emit(pidgin_conversations_get_handle(),
+				"conversation-displayed", gtkconv);
 		return TRUE;
 	}
 
@@ -7714,17 +7715,17 @@
 						 purple_value_new(PURPLE_TYPE_INT));
 
 	purple_signal_register(handle, "conversation-switched",
-						 purple_marshal_VOID__POINTER_POINTER, NULL, 1,
+						 purple_marshal_VOID__POINTER, NULL, 1,
 						 purple_value_new(PURPLE_TYPE_SUBTYPE,
 										PURPLE_SUBTYPE_CONVERSATION));
 
 	purple_signal_register(handle, "conversation-hiding",
-						 purple_marshal_VOID__POINTER_POINTER, NULL, 1,
+						 purple_marshal_VOID__POINTER, NULL, 1,
 						 purple_value_new(PURPLE_TYPE_BOXED,
 										"PidginConversation *"));
 
 	purple_signal_register(handle, "conversation-displayed",
-						 purple_marshal_VOID__POINTER_POINTER, NULL, 1,
+						 purple_marshal_VOID__POINTER, NULL, 1,
 						 purple_value_new(PURPLE_TYPE_BOXED,
 										"PidginConversation *"));
 
@@ -9029,8 +9030,6 @@
 	if (win->dialogs.search)
 		gtk_widget_destroy(win->dialogs.search);
 
-	gtk_widget_hide_all(win->window);
-
 	if (win->gtkconvs) {
 		while (win->gtkconvs) {
 			gboolean last = (win->gtkconvs->next == NULL);
--- a/pidgin/gtkimhtml.c	Wed Dec 05 20:44:34 2007 +0000
+++ b/pidgin/gtkimhtml.c	Wed Dec 05 20:45:38 2007 +0000
@@ -838,28 +838,6 @@
 	gtk_menu_shell_insert(GTK_MENU_SHELL(menu), menuitem, 5);
 
 	g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(clear_formatting_cb), imhtml);
-	
-	mi = gtk_menu_item_new();
-	gtk_widget_show(mi);
-	gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi);
-
-	img = gtk_image_new_from_stock(PIDGIN_STOCK_TOOLBAR_SMILEY, GTK_ICON_SIZE_MENU);
-	mi = gtk_image_menu_item_new_with_mnemonic(_("S_mile!"));
-	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img);
-	gtk_widget_show(mi);
-	gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi);
-
-	img = gtk_image_new_from_stock(PIDGIN_STOCK_TOOLBAR_INSERT, GTK_ICON_SIZE_MENU);
-	mi = gtk_image_menu_item_new_with_mnemonic(_("_Insert"));
-	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img);
-	gtk_widget_show(mi);
-	gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi);
-
-	img = gtk_image_new_from_stock(GTK_STOCK_BOLD, GTK_ICON_SIZE_MENU);
-	mi = gtk_image_menu_item_new_with_mnemonic(_("_Font"));
-	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img);
-	gtk_widget_show(mi);
-	gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi);
 }
 
 static char *
--- a/pidgin/gtkimhtmltoolbar.c	Wed Dec 05 20:44:34 2007 +0000
+++ b/pidgin/gtkimhtmltoolbar.c	Wed Dec 05 20:45:38 2007 +0000
@@ -1315,7 +1315,9 @@
 
 	purple_prefs_connect_callback(toolbar, PIDGIN_PREFS_ROOT "/conversations/toolbar/wide",
 			imhtmltoolbar_view_pref_changed, toolbar);
-	purple_prefs_trigger_callback(PIDGIN_PREFS_ROOT "/conversations/toolbar/wide");
+	g_signal_connect_data(G_OBJECT(toolbar), "realize",
+			G_CALLBACK(purple_prefs_trigger_callback), PIDGIN_PREFS_ROOT "/conversations/toolbar/wide",
+			NULL, G_CONNECT_AFTER | G_CONNECT_SWAPPED);
 
 #if GTK_CHECK_VERSION(2,4,0)
 	gtk_event_box_set_visible_window(GTK_EVENT_BOX(event), FALSE);