changeset 17079:79f6b097a0a6

merge of '2263648adbe7bbf44fd9bf0230c9054be1d4c72b' and '8acb1ca32888c20351b7ed15c87ae347440d802a'
author Richard Laager <rlaager@wiktel.com>
date Mon, 14 May 2007 23:17:42 +0000
parents 4453f59c2035 (diff) 74f1f5bbd858 (current diff)
children 4b65a67d23b8 9fae99335d35
files COPYRIGHT ChangeLog pidgin/gtkconv.c
diffstat 26 files changed, 326 insertions(+), 148 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Mon May 14 19:57:03 2007 +0000
+++ b/COPYRIGHT	Mon May 14 23:17:42 2007 +0000
@@ -303,6 +303,7 @@
 David Schmitt
 Mark Schneider
 Evan Schoenberg
+Gabriel Schulof
 Federico Schwindt
 Torrey Searle
 Peter Seebach
@@ -360,6 +361,7 @@
 James Vega
 David Vermeille
 Sid Vicious
+Jorge VillaseƱor (Masca)
 Bjoern Voigt
 Wan Hing Wah
 Philip Walford
--- a/ChangeLog	Mon May 14 19:57:03 2007 +0000
+++ b/ChangeLog	Mon May 14 23:17:42 2007 +0000
@@ -24,7 +24,10 @@
 	* Identify the account when warning about plaintext auth over an
 	  unencrypted channel
 	* Fix XMPP SASL authentication error when using Cyrus and a connect server
-	* Fix changing tab locations to update properly
+	* Fix changing tab locations to update properly	
+	* Turning off "Show formatting on incoming messages" now ignores
+	  formatting in <span> tags too
+	* File transfer progress for transfers on MSN is now correctly displayed
 
 	Finch:
 	* Userlist in chat windows, which can be turned on or off using
@@ -33,6 +36,10 @@
 	* Improved tab completion support
 	* Ctrl+c prompts with a dialog before exiting
 	* Filter string in the debug window
+	* Notify when you leave a chat
+	* Work around an ncurses bug which appears when half of a multi-cell
+	  character is covered by an upper-level window
+	* New plugins are shown in bold text in the plugin dialog
 
 version 2.0.0 (5/3/2007):
 	* The project has new names - libpurple for the core, Pidgin for the
--- a/finch/finch.c	Mon May 14 19:57:03 2007 +0000
+++ b/finch/finch.c	Mon May 14 23:17:42 2007 +0000
@@ -214,11 +214,6 @@
 		{0, 0, 0, 0}
 	};
 
-#ifdef PURPLE_FATAL_ASSERTS
-	/* Make g_return_... functions fatal. */
-	g_log_set_always_fatal(G_LOG_LEVEL_CRITICAL);
-#endif
-
 #ifdef ENABLE_NLS
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	bind_textdomain_codeset(PACKAGE, "UTF-8");
--- a/finch/gntconv.c	Mon May 14 19:57:03 2007 +0000
+++ b/finch/gntconv.c	Mon May 14 23:17:42 2007 +0000
@@ -493,7 +493,8 @@
 		FinchConvChat *fc = ggc->u.chat = g_new0(FinchConvChat, 1);
 		hbox = gnt_hbox_new(FALSE);
 		gnt_box_set_pad(GNT_BOX(hbox), 0);
-		tree = fc->userlist = gnt_tree_new();
+		tree = fc->userlist = gnt_tree_new_with_columns(2);
+		gnt_tree_set_col_width(GNT_TREE(tree), 0, 1);   /* The flag column */
 		gnt_tree_set_compare_func(GNT_TREE(tree), (GCompareFunc)g_utf8_collate);
 		gnt_tree_set_hash_fns(GNT_TREE(tree), g_str_hash, g_str_equal, g_free);
 		GNT_WIDGET_SET_FLAGS(tree, GNT_WIDGET_NO_BORDER);
@@ -675,6 +676,20 @@
 	finch_write_common(conv, name, message, flags, mtime);
 }
 
+static const char *
+chat_flag_text(PurpleConvChatBuddyFlags flags)
+{
+	if (flags & PURPLE_CBFLAGS_FOUNDER)
+		return "~";
+	if (flags & PURPLE_CBFLAGS_OP)
+		return "@";
+	if (flags & PURPLE_CBFLAGS_HALFOP)
+		return "%";
+	if (flags & PURPLE_CBFLAGS_VOICE)
+		return "+";
+	return " ";
+}
+
 static void
 finch_chat_add_users(PurpleConversation *conv, GList *users, gboolean new_arrivals)
 {
@@ -709,7 +724,7 @@
 		gnt_entry_add_suggest(entry, cbuddy->name);
 		gnt_entry_add_suggest(entry, cbuddy->alias);
 		gnt_tree_add_row_after(tree, g_strdup(cbuddy->name),
-				gnt_tree_create_row(tree, cbuddy->alias), NULL, NULL);
+				gnt_tree_create_row(tree, chat_flag_text(cbuddy->flags), cbuddy->alias), NULL, NULL);
 	}
 }
 
@@ -720,12 +735,15 @@
 	FinchConv *ggc = conv->ui_data;
 	GntEntry *entry = GNT_ENTRY(ggc->entry);
 	GntTree *tree = GNT_TREE(ggc->u.chat->userlist);
+	PurpleConvChatBuddy *cb = purple_conv_chat_cb_find(PURPLE_CONV_CHAT(conv), new_n);
+
 	gnt_entry_remove_suggest(entry, old);
+	gnt_tree_remove(tree, (gpointer)old);
+
 	gnt_entry_add_suggest(entry, new_n);
 	gnt_entry_add_suggest(entry, new_a);
-	gnt_tree_remove(tree, (gpointer)old);
 	gnt_tree_add_row_after(tree, g_strdup(new_n),
-			gnt_tree_create_row(tree, new_a), NULL, NULL);
+			gnt_tree_create_row(tree, chat_flag_text(cb->flags), new_a), NULL, NULL);
 }
 
 static void
@@ -744,6 +762,9 @@
 static void
 finch_chat_update_user(PurpleConversation *conv, const char *user)
 {
+	PurpleConvChatBuddy *cb = purple_conv_chat_cb_find(PURPLE_CONV_CHAT(conv), user);
+	FinchConv *ggc = conv->ui_data;
+	gnt_tree_change_text(GNT_TREE(ggc->u.chat->userlist), (gpointer)user, 0, chat_flag_text(cb->flags));
 }
 
 static PurpleConversationUiOps conv_ui_ops = 
--- a/finch/libgnt/gntmain.c	Mon May 14 19:57:03 2007 +0000
+++ b/finch/libgnt/gntmain.c	Mon May 14 23:17:42 2007 +0000
@@ -144,8 +144,8 @@
 		event = GNT_MOUSE_UP;
 	} else
 		return FALSE;
-	
-	if (gnt_wm_process_click(wm, event, x, y, widget))
+
+	if (widget && gnt_wm_process_click(wm, event, x, y, widget))
 		return TRUE;
 	
 	if (event == GNT_LEFT_MOUSE_DOWN && widget && widget != wm->_list.window &&
@@ -177,7 +177,8 @@
 		offset = 0;
 	}
 
-	gnt_widget_clicked(widget, event, x, y);
+	if (widget)
+		gnt_widget_clicked(widget, event, x, y);
 	return TRUE;
 }
 
@@ -348,6 +349,10 @@
 	gnt_wm_raise_window(wm, win);
 }
 
+#ifdef SIGWINCH
+static void (*org_winch_handler)(int);
+#endif
+
 static void
 sighandler(int sig)
 {
@@ -357,6 +362,7 @@
 		werase(stdscr);
 		wrefresh(stdscr);
 		g_idle_add(refresh_screen, NULL);
+		org_winch_handler(sig);
 		signal(SIGWINCH, sighandler);
 		break;
 #endif
@@ -434,7 +440,7 @@
 	wrefresh(stdscr);
 
 #ifdef SIGWINCH
-	signal(SIGWINCH, sighandler);
+	org_winch_handler = signal(SIGWINCH, sighandler);
 #endif
 	signal(SIGCHLD, sighandler);
 	signal(SIGINT, sighandler);
--- a/finch/libgnt/gntwm.c	Mon May 14 19:57:03 2007 +0000
+++ b/finch/libgnt/gntwm.c	Mon May 14 23:17:42 2007 +0000
@@ -48,6 +48,10 @@
 static void update_window_in_list(GntWM *wm, GntWidget *wid);
 static void shift_window(GntWM *wm, GntWidget *widget, int dir);
 
+#ifndef NO_WIDECHAR
+static int widestringwidth(wchar_t *wide);
+#endif
+
 static gboolean write_already(gpointer data);
 static int write_timeout;
 static time_t last_active_time;
@@ -136,6 +140,65 @@
 	copywin(src, dst, node->scroll, 0, 0, 0, getmaxy(dst) - 1, getmaxx(dst) - 1, 0);
 }
 
+/**
+ * The following is a workaround for a bug in most versions of ncursesw.
+ * Read about it in: http://article.gmane.org/gmane.comp.lib.ncurses.bugs/2751
+ * 
+ * In short, if a panel hides one cell of a multi-cell character, then the rest
+ * of the characters in that line get screwed. The workaround here is to erase
+ * any such character preemptively.
+ *
+ * Caveat: If a wide character is erased, and the panel above it is moved enough
+ * to expose the entire character, it is not always redrawn.
+ */
+static void
+work_around_for_ncurses_bug()
+{
+#ifndef NO_WIDECHAR
+	PANEL *panel = NULL;
+	while ((panel = panel_below(panel)) != NULL) {
+		int sx, ex, sy, ey, w, y;
+		cchar_t ch;
+		PANEL *below = panel;
+
+		sx = panel->win->_begx;
+		ex = panel->win->_maxx + sx;
+		sy = panel->win->_begy;
+		ey = panel->win->_maxy + sy;
+
+		while ((below = panel_below(below)) != NULL) {
+			if (sy > below->win->_begy + below->win->_maxy ||
+					ey < below->win->_begy)
+				continue;
+			if (sx > below->win->_begx + below->win->_maxx ||
+					ex < below->win->_begx)
+				continue;
+			for (y = MAX(sy, below->win->_begy); y <= MIN(ey, below->win->_begy + below->win->_maxy); y++) {
+				if (mvwin_wch(below->win, y - below->win->_begy, sx - 1 - below->win->_begx, &ch) != OK)
+					goto right;
+				w = widestringwidth(ch.chars);
+				if (w > 1 && (ch.attr & 1)) {
+					ch.chars[0] = ' ';
+					ch.attr &= ~ A_CHARTEXT;
+					mvwadd_wch(below->win, y - below->win->_begy, sx - 1 - below->win->_begx, &ch);
+					touchline(below->win, y - below->win->_begy, 1);
+				}
+right:
+				if (mvwin_wch(below->win, y - below->win->_begy, ex + 1 - below->win->_begx, &ch) != OK)
+					continue;
+				w = widestringwidth(ch.chars);
+				if (w > 1 && !(ch.attr & 1)) {
+					ch.chars[0] = ' ';
+					ch.attr &= ~ A_CHARTEXT;
+					mvwadd_wch(below->win, y - below->win->_begy, ex + 1 - below->win->_begx, &ch);
+					touchline(below->win, y - below->win->_begy, 1);
+				}
+			}
+		}
+	}
+#endif
+}
+
 static gboolean
 update_screen(GntWM *wm)
 {
@@ -148,6 +211,7 @@
 			top = top->submenu;
 		}
 	}
+	work_around_for_ncurses_bug();
 	update_panels();
 	doupdate();
 	return TRUE;
--- a/libpurple/Makefile.am	Mon May 14 19:57:03 2007 +0000
+++ b/libpurple/Makefile.am	Mon May 14 23:17:42 2007 +0000
@@ -151,7 +151,7 @@
 dbus_headers  = dbus-bindings.h dbus-purple.h dbus-server.h dbus-useful.h dbus-define-api.h
 
 dbus_exported = dbus-useful.h dbus-define-api.h account.h blist.h buddyicon.h \
-                connection.h conversation.h core.h log.h prefs.h roomlist.h \
+                connection.h conversation.h core.h log.h notify.h prefs.h roomlist.h \
                 savedstatuses.h status.h server.h util.h xmlnode.h
 
 purple_build_coreheaders = $(addprefix $(srcdir)/, $(purple_coreheaders))
--- a/libpurple/conversation.c	Mon May 14 19:57:03 2007 +0000
+++ b/libpurple/conversation.c	Mon May 14 23:17:42 2007 +0000
@@ -970,20 +970,20 @@
 	{
 		im->typing_state = state;
 
-		if (state == PURPLE_TYPING)
-		{
-			purple_signal_emit(purple_conversations_get_handle(),
-							 "buddy-typing", im->conv->account, im->conv->name);
-		}
-		else if (state == PURPLE_TYPED)
+		switch (state)
 		{
-			purple_signal_emit(purple_conversations_get_handle(),
-							 "buddy-typed", im->conv->account, im->conv->name);
-		}
-		else if (state == PURPLE_NOT_TYPING)
-		{
-			purple_signal_emit(purple_conversations_get_handle(),
-							 "buddy-typing-stopped", im->conv->account, im->conv->name);
+			case PURPLE_TYPING:
+				purple_signal_emit(purple_conversations_get_handle(),
+								   "buddy-typing", im->conv->account, im->conv->name);
+				break;
+			case PURPLE_TYPED:
+				purple_signal_emit(purple_conversations_get_handle(),
+								   "buddy-typed", im->conv->account, im->conv->name);
+				break;
+			case PURPLE_NOT_TYPING:
+				purple_signal_emit(purple_conversations_get_handle(),
+								   "buddy-typing-stopped", im->conv->account, im->conv->name);
+				break;
 		}
 	}
 }
--- a/libpurple/dbus-analyze-functions.py	Mon May 14 19:57:03 2007 +0000
+++ b/libpurple/dbus-analyze-functions.py	Mon May 14 23:17:42 2007 +0000
@@ -96,7 +96,7 @@
 
         if len(type) == 1:
             # simple types (int, gboolean, etc.) and enums
-            if (type[0] in simpletypes) or (type[0].startswith("Purple")):
+            if (type[0] in simpletypes) or ((type[0].startswith("Purple") and not type[0].endswith("Callback"))):
                 return self.inputsimple(type, name)
 
         # pointers ... 
@@ -118,7 +118,6 @@
             # unknown pointers are always replaced with NULL
             else:
                 return self.inputpointer(type, name)
-                return
 
         raise myexception
 
--- a/libpurple/ft.c	Mon May 14 19:57:03 2007 +0000
+++ b/libpurple/ft.c	Mon May 14 23:17:42 2007 +0000
@@ -972,7 +972,8 @@
 
 	fseek(xfer->dest_fp, xfer->bytes_sent, SEEK_SET);
 
-	xfer->watcher = purple_input_add(xfer->fd, cond, transfer_cb, xfer);
+	if (xfer->fd)
+		xfer->watcher = purple_input_add(xfer->fd, cond, transfer_cb, xfer);
 
 	xfer->start_time = time(NULL);
 
--- a/libpurple/idle.c	Mon May 14 19:57:03 2007 +0000
+++ b/libpurple/idle.c	Mon May 14 23:17:42 2007 +0000
@@ -31,7 +31,6 @@
 #include "signals.h"
 
 #define IDLEMARK 600 /* 10 minutes! */
-#define IDLE_CHECK_INTERVAL 5 /* 5 seconds */
 
 typedef enum
 {
@@ -92,6 +91,8 @@
 	purple_presence_set_idle(presence, FALSE, 0);
 }
 
+
+static gint time_until_next_idle_event;
 /*
  * This function should be called when you think your idle state
  * may have changed.  Maybe you're over the 10-minute mark and
@@ -110,14 +111,17 @@
  * 2. Set or unset your auto-away message.
  * 3. Report your current idle time to the IM server.
  */
-static gint
-check_idleness()
+
+static void
+check_idleness(void)
 {
 	time_t time_idle;
 	gboolean auto_away;
 	const gchar *idle_reporting;
 	gboolean report_idle;
 	GList *l;
+	gint away_seconds = 0;
+	static int no_away = 0;
 
 	purple_signal_emit(purple_blist_get_handle(), "update-idle");
 
@@ -153,14 +157,24 @@
 			time_idle = time(NULL) - last_active_time;
 	}
 
-	if (auto_away &&
-		(time_idle > (60 * purple_prefs_get_int("/purple/away/mins_before_away"))))
+	time_until_next_idle_event = IDLEMARK - time_idle; /* reasonable start upperbound */
+
+	if (auto_away || !no_away)
+		away_seconds = 60 * purple_prefs_get_int("/purple/away/mins_before_away");
+
+	if (auto_away && time_idle > away_seconds)
 	{
 		purple_savedstatus_set_idleaway(TRUE);
+		no_away = 0;
+		if (time_idle < away_seconds && (away_seconds - time_idle) < time_until_next_idle_event)
+			time_until_next_idle_event = away_seconds - time_idle;
 	}
-	else if (time_idle < 60 * purple_prefs_get_int("/purple/away/mins_before_away"))
+	else if (!no_away && time_idle < away_seconds)
 	{
 		purple_savedstatus_set_idleaway(FALSE);
+		no_away = 1;
+		if (time_idle < away_seconds && (away_seconds - time_idle) < time_until_next_idle_event)
+			time_until_next_idle_event = away_seconds - time_idle;
 	}
 
 	/* Idle reporting stuff */
@@ -177,8 +191,21 @@
 		while (idled_accts != NULL)
 			set_account_unidle(idled_accts->data);
 	}
+	
+	if (time_until_next_idle_event < 0)
+		time_until_next_idle_event = IDLEMARK;
+}
 
-	return TRUE;
+
+/*
+ * Check idle and set the timer to fire at the next idle-worth event 
+ */
+static gint
+check_idleness_timer()
+{
+	check_idleness();
+	idle_timer = purple_timeout_add(1000 * (time_until_next_idle_event + 1), check_idleness_timer, NULL);
+	return FALSE;
 }
 
 static void
@@ -241,7 +268,7 @@
 purple_idle_init()
 {
 	/* Add the timer to check if we're idle */
-	idle_timer = purple_timeout_add(IDLE_CHECK_INTERVAL * 1000, check_idleness, NULL);
+	idle_timer = purple_timeout_add(1000 * (IDLEMARK + 1), check_idleness_timer, NULL);
 
 	purple_signal_connect(purple_conversations_get_handle(), "sent-im-msg",
 						purple_idle_get_handle(),
--- a/libpurple/notify.c	Mon May 14 19:57:03 2007 +0000
+++ b/libpurple/notify.c	Mon May 14 23:17:42 2007 +0000
@@ -22,6 +22,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+#include "internal.h"
+#include "dbus-maybe.h"
 #include "notify.h"
 
 static PurpleNotifyUiOps *notify_ui_ops = NULL;
@@ -481,6 +483,7 @@
 	PurpleNotifyUserInfoEntry *user_info_entry;
 	
 	user_info_entry = g_new0(PurpleNotifyUserInfoEntry, 1);
+	PURPLE_DBUS_REGISTER_POINTER(user_info_entry, PurpleNotifyUserInfoEntry);
 	user_info_entry->label = g_strdup(label);
 	user_info_entry->value = g_strdup(value);
 	user_info_entry->type = PURPLE_NOTIFY_USER_INFO_ENTRY_PAIR;
@@ -495,6 +498,7 @@
 	
 	g_free(user_info_entry->label);
 	g_free(user_info_entry->value);	
+	PURPLE_DBUS_UNREGISTER_POINTER(user_info_entry);
 	g_free(user_info_entry);
 }
 
@@ -504,6 +508,7 @@
 	PurpleNotifyUserInfo *user_info;
 	
 	user_info = g_new0(PurpleNotifyUserInfo, 1);
+	PURPLE_DBUS_REGISTER_POINTER(user_info, PurpleNotifyUserInfo);
 	user_info->user_info_entries = NULL;
 	
 	return user_info;
@@ -521,6 +526,7 @@
 	}
 	
 	g_list_free(user_info->user_info_entries);
+	PURPLE_DBUS_UNREGISTER_POINTER(user_info);
 	g_free(user_info);
 }
 
--- a/libpurple/protocols/irc/parse.c	Mon May 14 19:57:03 2007 +0000
+++ b/libpurple/protocols/irc/parse.c	Mon May 14 23:17:42 2007 +0000
@@ -227,7 +227,7 @@
 	enclist = purple_account_get_string(irc->account, "encoding", IRC_DEFAULT_CHARSET);
 	encodings = g_strsplit(enclist, ",", 2);
 
-	if (encodings[0] == NULL || !strcasecmp("UTF-8", encodings[0])) {
+	if (encodings[0] == NULL || !g_ascii_strcasecmp("UTF-8", encodings[0])) {
 		g_strfreev(encodings);
 		return g_strdup(string);
 	}
--- a/libpurple/protocols/msn/msn.c	Mon May 14 19:57:03 2007 +0000
+++ b/libpurple/protocols/msn/msn.c	Mon May 14 23:17:42 2007 +0000
@@ -73,6 +73,15 @@
 
 } MsnGetInfoStepTwoData;
 
+typedef struct
+{
+	PurpleConnection *gc;
+	const char *who;
+	char *msg;
+	PurpleMessageFlags flags;
+	time_t when;
+} MsnIMData;
+
 static const char *
 msn_normalize(const PurpleAccount *account, const char *str)
 {
@@ -409,33 +418,7 @@
 static void
 t_msn_xfer_init(PurpleXfer *xfer)
 {
-	MsnSlpLink *slplink;
-	const char *filename;
-	FILE *fp;
-
-	filename = purple_xfer_get_local_filename(xfer);
-
-	slplink = xfer->data;
-
-	if ((fp = g_fopen(filename, "rb")) == NULL)
-	{
-		PurpleAccount *account;
-		const char *who;
-		char *msg;
-
-		account = slplink->session->account;
-		who = slplink->remote_user;
-
-		msg = g_strdup_printf(_("Error reading %s: \n%s.\n"),
-							  filename, strerror(errno));
-		purple_xfer_error(purple_xfer_get_type(xfer), account, xfer->who, msg);
-		purple_xfer_cancel_local(xfer);
-		g_free(msg);
-
-		return;
-	}
-	fclose(fp);
-
+	MsnSlpLink *slplink = xfer->data;
 	msn_slplink_request_ft(slplink, xfer);
 }
 
@@ -753,6 +736,16 @@
 	gc->proto_data = NULL;
 }
 
+static gboolean
+msn_send_me_im(gpointer data)
+{
+	MsnIMData *imdata = data;
+	serv_got_im(imdata->gc, imdata->who, imdata->msg, imdata->flags, imdata->when);
+	g_free(imdata->msg);
+	g_free(imdata);
+	return FALSE;
+}
+
 static int
 msn_send_im(PurpleConnection *gc, const char *who, const char *message,
 			PurpleMessageFlags flags)
@@ -805,6 +798,7 @@
 	{
 		char *body_str, *body_enc, *pre, *post;
 		const char *format;
+		MsnIMData *imdata = g_new0(MsnIMData, 1);
 		/*
 		 * In MSN, you can't send messages to yourself, so
 		 * we'll fake like we received it ;)
@@ -822,8 +816,12 @@
 		g_free(post);
 
 		serv_got_typing_stopped(gc, who);
-		serv_got_im(gc, who, body_str, flags, time(NULL));
-		g_free(body_str);
+		imdata->gc = gc;
+		imdata->who = who;
+		imdata->msg = body_str;
+		imdata->flags = flags;
+		imdata->when = time(NULL);
+		g_idle_add(msn_send_me_im, imdata);
 	}
 
 	msn_message_destroy(msg);
--- a/libpurple/protocols/msn/slp.c	Mon May 14 19:57:03 2007 +0000
+++ b/libpurple/protocols/msn/slp.c	Mon May 14 23:17:42 2007 +0000
@@ -158,7 +158,9 @@
 msn_xfer_completed_cb(MsnSlpCall *slpcall, const guchar *body,
 					  gsize size)
 {
-	purple_xfer_set_completed(slpcall->xfer, TRUE);
+	PurpleXfer *xfer = slpcall->xfer;
+	purple_xfer_set_completed(xfer, TRUE);
+	purple_xfer_end(xfer);
 }
 
 /**************************************************************************
--- a/libpurple/protocols/msn/slplink.c	Mon May 14 19:57:03 2007 +0000
+++ b/libpurple/protocols/msn/slplink.c	Mon May 14 23:17:42 2007 +0000
@@ -482,6 +482,8 @@
 {
 	MsnSlpCall *slpcall;
 	MsnSlpMessage *slpmsg;
+	struct stat st;
+	PurpleXfer *xfer;
 
 	slpcall = slpsession->slpcall;
 	slpmsg = msn_slpmsg_new(slpcall->slplink);
@@ -491,7 +493,12 @@
 #ifdef MSN_DEBUG_SLP
 	slpmsg->info = "SLP FILE";
 #endif
-	msn_slpmsg_open_file(slpmsg, purple_xfer_get_local_filename(slpcall->xfer));
+	xfer = (PurpleXfer *)slpcall->xfer;
+	purple_xfer_start(slpcall->xfer, 0, NULL, 0);
+	slpmsg->fp = xfer->dest_fp;
+	if (g_stat(purple_xfer_get_local_filename(xfer), &st) == 0)
+		slpmsg->size = st.st_size;
+	xfer->dest_fp = NULL; /* Disable double fclose() */
 
 	msn_slplink_send_slpmsg(slpcall->slplink, slpmsg);
 }
@@ -551,9 +558,10 @@
 
 					if (xfer != NULL)
 					{
-						slpmsg->fp =
-							g_fopen(purple_xfer_get_local_filename(slpmsg->slpcall->xfer),
-								  "wb");
+						purple_xfer_start(slpmsg->slpcall->xfer,
+							0, NULL, 0);
+						slpmsg->fp = ((PurpleXfer *)slpmsg->slpcall->xfer)->dest_fp;
+						xfer->dest_fp = NULL; /* Disable double fclose() */
 					}
 				}
 			}
--- a/libpurple/proxy.c	Mon May 14 19:57:03 2007 +0000
+++ b/libpurple/proxy.c	Mon May 14 23:17:42 2007 +0000
@@ -217,14 +217,14 @@
 		g_free(path);
 
 		/* See whether to use a proxy. */
-		if (!g_spawn_command_line_sync("gconftool-2 -g /system/http_proxy/use_http_proxy", &tmp,
+		if (!g_spawn_command_line_sync("gconftool-2 -g /system/proxy/mode", &tmp,
 					       NULL, NULL, NULL))
 			return purple_global_proxy_get_info();
-		if (!strcmp(tmp, "false\n")) {
+		if (!strcmp(tmp, "none\n")) {
 			info.type = PURPLE_PROXY_NONE;
 			g_free(tmp);
 			return &info;
-		} else if (strcmp(tmp, "true\n")) {
+		} else if (strcmp(tmp, "manual\n")) {
 			g_free(tmp);
 			return purple_global_proxy_get_info();
 		}
--- a/libpurple/server.c	Mon May 14 19:57:03 2007 +0000
+++ b/libpurple/server.c	Mon May 14 23:17:42 2007 +0000
@@ -576,15 +576,20 @@
 		purple_conv_im_set_typing_state(im, state);
 		purple_conv_im_update_typing(im);
 	} else {
-		if (state == PURPLE_TYPING)
+		switch (state)
 		{
-			purple_signal_emit(purple_conversations_get_handle(),
-							 "buddy-typing", gc->account, name);
-		}
-		else
-		{
-			purple_signal_emit(purple_conversations_get_handle(),
-							 "buddy-typed", gc->account, name);
+			case PURPLE_TYPING:
+				purple_signal_emit(purple_conversations_get_handle(),
+								   "buddy-typing", gc->account, name);
+				break;
+			case PURPLE_TYPED:
+				purple_signal_emit(purple_conversations_get_handle(),
+								   "buddy-typed", gc->account, name);
+				break;
+			case PURPLE_NOT_TYPING:
+				purple_signal_emit(purple_conversations_get_handle(),
+								   "buddy-typing-stopped", gc->account, name);
+				break;
 		}
 	}
 
--- a/pidgin.spec.in	Mon May 14 19:57:03 2007 +0000
+++ b/pidgin.spec.in	Mon May 14 23:17:42 2007 +0000
@@ -70,6 +70,10 @@
 # For some reason perl isn't always automatically detected as a requirement :(
 Requires: perl
 
+Requires(pre): GConf2
+Requires(post): GConf2
+Requires(preun): GConf2
+
 Obsoletes: gaim
 Provides: gaim
 
@@ -296,7 +300,7 @@
     if [ -f %{_sysconfdir}/gconf/schemas/purple.schemas ]; then
         gconftool-2 --makefile-uninstall-rule \
             %{_sysconfdir}/gconf/schemas/purple.schemas >/dev/null || :
-        killall -HUP gconfd-2 || :
+        killall -HUP gconfd-2 &> /dev/null || :
     fi
 fi
 
@@ -305,7 +309,7 @@
     export GCONF_CONFIG_SOURCE=`gconftool-2 --get-default-source`
     gconftool-2 --makefile-install-rule \
         %{_sysconfdir}/gconf/schemas/purple.schemas > /dev/null || :
-    killall -HUP gconfd-2 || :
+    killall -HUP gconfd-2 &> /dev/null || :
 fi
 touch --no-create %{_datadir}/icons/hicolor || :
 %{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor || :
@@ -319,7 +323,7 @@
     export GCONF_CONFIG_SOURCE=`gconftool-2 --get-default-source`
     gconftool-2 --makefile-uninstall-rule \
       %{_sysconfdir}/gconf/schemas/purple.schemas > /dev/null || :
-    killall -HUP gconfd-2 || :
+    killall -HUP gconfd-2 &> /dev/null || :
 fi
 
 %postun
@@ -443,6 +447,10 @@
 %endif
 
 %changelog
+* Thu May 10 2007 Stu Tomlinson <stu@nosnilmot.com>
+- Add scriptlet Requires for GConf2 to fix schema installation
+- Silence harmless errors when gconfd-2 is not running at install time
+
 * Thu May 3 2007 Stu Tomlinson <stu@nosnilmot.com>
 - Add missing BuildRequires: startup-notification-devel, if you really
   need to build on a distro without it use --without startupnotification
--- a/pidgin/gtkconv.c	Mon May 14 19:57:03 2007 +0000
+++ b/pidgin/gtkconv.c	Mon May 14 23:17:42 2007 +0000
@@ -4128,6 +4128,7 @@
 	GtkTreeViewColumn *col;
 	void *blist_handle = purple_blist_get_handle();
 	GList *focus_chain = NULL;
+	int ul_width;
 
 	gtkchat = gtkconv->u.chat;
 	gc      = purple_conversation_get_gc(conv);
@@ -4228,8 +4229,13 @@
 												   "pixbuf", CHAT_USERS_ICON_COLUMN, NULL);
 	gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
 	gtk_tree_view_append_column(GTK_TREE_VIEW(list), col);
-	gtk_widget_set_size_request(lbox,
-	                            purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/chat/userlist_width"), -1);
+	ul_width = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/chat/userlist_width");
+	gtk_widget_set_size_request(lbox, ul_width, -1);
+
+	/* Hack to prevent completely collapsed userlist coming back with a 1 pixel width.
+	 * I would have liked to use the GtkPaned "max-position", but for some reason that didn't work */
+	if (ul_width == 0)
+		gtk_paned_set_position(GTK_PANED(hpaned), 999999);
 
 	g_signal_connect(G_OBJECT(list), "button_press_event",
 					 G_CALLBACK(right_click_chat_cb), gtkconv);
@@ -5551,9 +5557,9 @@
 
 	flags = purple_conv_chat_user_get_flags(chat, user);
 
-	cbuddy = purple_conv_chat_cb_new(user, alias, flags);
-
-	add_chat_buddy_common(conv, cbuddy, NULL);
+	cbuddy = purple_conv_chat_cb_find(chat, user);
+	if (cbuddy)
+		add_chat_buddy_common(conv, cbuddy, NULL);
 	g_free(alias);
 }
 
--- a/pidgin/gtkidle.c	Mon May 14 19:57:03 2007 +0000
+++ b/pidgin/gtkidle.c	Mon May 14 23:17:42 2007 +0000
@@ -103,14 +103,21 @@
 
 	/* Query xscreensaver */
 	static XScreenSaverInfo *mit_info = NULL;
+	static int has_extension = -1;
 	int event_base, error_base;
-	if (XScreenSaverQueryExtension(GDK_DISPLAY(), &event_base, &error_base)) {
-		if (mit_info == NULL) {
+
+	if (has_extension == -1)
+		has_extension = XScreenSaverQueryExtension(GDK_DISPLAY(), &event_base, &error_base);
+
+	if (has_extension)
+	{
+		if (mit_info == NULL)
 			mit_info = XScreenSaverAllocInfo();
-		}
+
 		XScreenSaverQueryInfo(GDK_DISPLAY(), GDK_ROOT_WINDOW(), mit_info);
 		return (mit_info->idle) / 1000;
-	} else
+	}
+	else
 		return 0;
 #  endif /* !_WIN32 */
 # endif /* !HAVE_IOKIT */
--- a/pidgin/gtkimhtml.c	Mon May 14 19:57:03 2007 +0000
+++ b/pidgin/gtkimhtml.c	Mon May 14 23:17:42 2007 +0000
@@ -2761,7 +2761,8 @@
 						}
 						if (textdec && font->underline != 1
 							&& g_ascii_strcasecmp(textdec, "underline") == 0
-							&& (imhtml->format_functions & GTK_IMHTML_UNDERLINE))
+							&& (imhtml->format_functions & GTK_IMHTML_UNDERLINE)
+							&& !(options & GTK_IMHTML_NO_FORMATTING))
 						{
 						    gtk_imhtml_toggle_underline(imhtml);
 						    font->underline = 1;
@@ -2790,7 +2791,7 @@
 								else
 									font->bold = 0;
 							}
-							if ((font->bold && oldfont && !oldfont->bold) || (oldfont && oldfont->bold && !font->bold) || (font->bold && !oldfont))
+							if (((font->bold && oldfont && !oldfont->bold) || (oldfont && oldfont->bold && !font->bold) || (font->bold && !oldfont)) && !(options & GTK_IMHTML_NO_FORMATTING))
 							{
 								gtk_imhtml_toggle_bold(imhtml);
 							}
@@ -2816,33 +2817,36 @@
 
 						if (!oldfont) {
 							gtk_imhtml_font_set_size(imhtml, 3);
-							if (font->underline)
+							if (font->underline && !(options & GTK_IMHTML_NO_FORMATTING))
 							    gtk_imhtml_toggle_underline(imhtml);
-							if (font->bold)
+							if (font->bold && !(options & GTK_IMHTML_NO_FORMATTING))
 								gtk_imhtml_toggle_bold(imhtml);
-							gtk_imhtml_toggle_fontface(imhtml, NULL);
-							gtk_imhtml_toggle_forecolor(imhtml, NULL);
-							gtk_imhtml_toggle_backcolor(imhtml, NULL);
+							if (!(options & GTK_IMHTML_NO_FONTS))
+								gtk_imhtml_toggle_fontface(imhtml, NULL);
+							if (!(options & GTK_IMHTML_NO_COLOURS))
+								gtk_imhtml_toggle_forecolor(imhtml, NULL);
+							if (!(options & GTK_IMHTML_NO_COLOURS))
+								gtk_imhtml_toggle_backcolor(imhtml, NULL);
 						}
 						else
 						{
 
-						    if (font->size != oldfont->size)
+						    if ((font->size != oldfont->size) && !(options & GTK_IMHTML_NO_SIZES))
 							    gtk_imhtml_font_set_size(imhtml, oldfont->size);
 
-							if (font->underline != oldfont->underline)
+							if ((font->underline != oldfont->underline) && !(options & GTK_IMHTML_NO_FORMATTING))
 							    gtk_imhtml_toggle_underline(imhtml);
 
-							if ((font->bold && !oldfont->bold) || (oldfont->bold && !font->bold))
+							if (((font->bold && !oldfont->bold) || (oldfont->bold && !font->bold)) && !(options & GTK_IMHTML_NO_FORMATTING))
 								gtk_imhtml_toggle_bold(imhtml);
 
-							if (font->face && (!oldfont->face || strcmp(font->face, oldfont->face) != 0))
+							if (font->face && (!oldfont->face || strcmp(font->face, oldfont->face) != 0) && !(options & GTK_IMHTML_NO_FONTS))
 							    gtk_imhtml_toggle_fontface(imhtml, oldfont->face);
 
-							if (font->fore && (!oldfont->fore || strcmp(font->fore, oldfont->fore) != 0))
+							if (font->fore && (!oldfont->fore || strcmp(font->fore, oldfont->fore) != 0) && !(options & GTK_IMHTML_NO_COLOURS))
 							    gtk_imhtml_toggle_forecolor(imhtml, oldfont->fore);
 
-							if (font->back && (!oldfont->back || strcmp(font->back, oldfont->back) != 0))
+							if (font->back && (!oldfont->back || strcmp(font->back, oldfont->back) != 0) && !(options & GTK_IMHTML_NO_COLOURS))
 						      gtk_imhtml_toggle_backcolor(imhtml, oldfont->back);
 						}
 
@@ -3384,7 +3388,7 @@
 		return FALSE;
 
 	pix = gdk_pixbuf_animation_get_static_image(anim);
-	image = gtk_imhtml_image_new(pix, NULL, 0);
+	image = gtk_imhtml_image_new(pix, smiley->smile, 0);
 	ret = gtk_imhtml_image_clicked(w, event, (GtkIMHtmlImage*)image);
 	g_object_set_data_full(G_OBJECT(w), "image-data", image, (GDestroyNotify)gtk_imhtml_image_free);
 	g_object_unref(G_OBJECT(pix));
--- a/pidgin/gtkmain.c	Mon May 14 19:57:03 2007 +0000
+++ b/pidgin/gtkmain.c	Mon May 14 23:17:42 2007 +0000
@@ -473,9 +473,6 @@
 #else
 	debug_enabled = FALSE;
 #endif
-
-	/* This is the first Glib function call. Make sure to initialize GThread bfeore then */
-	g_thread_init(NULL);
 	
 #ifdef ENABLE_NLS
 	bindtextdomain(PACKAGE, LOCALEDIR);
--- a/pidgin/gtkutils.c	Mon May 14 19:57:03 2007 +0000
+++ b/pidgin/gtkutils.c	Mon May 14 23:17:42 2007 +0000
@@ -510,6 +510,10 @@
 	const char *proto_name;
 	char buf[256];
 	int i, selected_index = -1;
+	const char *gtalk_name = NULL;
+
+	if (purple_find_prpl("prpl-jabber"))
+		gtalk_name = _("Google Talk");
 
 	optmenu = gtk_option_menu_new();
 	gtk_widget_show(optmenu);
@@ -528,6 +532,28 @@
 		plugin = (PurplePlugin *)p->data;
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin);
 
+		if (gtalk_name && strcmp(gtalk_name, plugin->info->name) < 0)
+		{
+			GtkWidget *gtalk_item;
+
+			filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols",
+			                            "16", "google-talk.png", NULL);
+			pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
+			g_free(filename);
+
+
+			if (pixbuf)
+				image = gtk_image_new_from_pixbuf(pixbuf);
+			else
+				image = gtk_image_new();
+
+			gtalk_item = pidgin_protocol_option_menu_item(menu, sg, image, gtalk_name, "prpl-fake");
+			g_object_set_data(G_OBJECT(gtalk_item), "real_protocol", "prpl-jabber");
+			i++;
+
+			gtalk_name = NULL;
+		}
+
 		/* Load the image. */
 		proto_name = prpl_info->list_icon(NULL, NULL);
 		g_snprintf(buf, sizeof(buf), "%s.png", proto_name);
@@ -555,26 +581,6 @@
 			g_object_set_data(G_OBJECT(optmenu), "last_protocol", plugin->info->id);
 		}
 
-		if (!strcmp(plugin->info->id, "prpl-jabber"))
-		{
-			GtkWidget *gtalk_item;
-
-			filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols",
-			                            "16", "google-talk.png", NULL);
-			pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
-			g_free(filename);
-
-
-			if (pixbuf)
-				image = gtk_image_new_from_pixbuf(pixbuf);
-			else
-				image = gtk_image_new();
-
-			gtalk_item = pidgin_protocol_option_menu_item(menu, sg, image, _("Google Talk"), "prpl-fake");
-			g_object_set_data(G_OBJECT(gtalk_item), "real_protocol", plugin->info->id);
-			i++;
-		}
-
 		if (pixbuf)
 			g_object_unref(G_OBJECT(pixbuf));
 	}
--- a/pidgin/plugins/pidginrc.c	Mon May 14 19:57:03 2007 +0000
+++ b/pidgin/plugins/pidginrc.c	Mon May 14 23:17:42 2007 +0000
@@ -61,16 +61,16 @@
 static const char *font_prefs[] = {
 	"/plugins/gtk/purplerc/font/*pidgin_conv_entry",
 	"/plugins/gtk/purplerc/font/*pidgin_conv_imhtml",
-	"/plugins/gtk/purplerc/font/*pidginlog_imhtml",
-	"/plugins/gtk/purplerc/font/*pidginrequest_imhtml",
-	"/plugins/gtk/purplerc/font/*pidginnotify_imhtml",
+	"/plugins/gtk/purplerc/font/*pidgin_log_imhtml",
+	"/plugins/gtk/purplerc/font/*pidgin_request_imhtml",
+	"/plugins/gtk/purplerc/font/*pidgin_notify_imhtml",
 };
 static const char *font_prefs_set[] = {
 	"/plugins/gtk/purplerc/set/font/*pidgin_conv_entry",
 	"/plugins/gtk/purplerc/set/font/*pidgin_conv_imhtml",
-	"/plugins/gtk/purplerc/set/font/*pidginlog_imhtml",
-	"/plugins/gtk/purplerc/set/font/*pidginrequest_imhtml",
-	"/plugins/gtk/purplerc/set/font/*pidginnotify_imhtml",
+	"/plugins/gtk/purplerc/set/font/*pidgin_log_imhtml",
+	"/plugins/gtk/purplerc/set/font/*pidgin_request_imhtml",
+	"/plugins/gtk/purplerc/set/font/*pidgin_notify_imhtml",
 };
 static const char *font_names[] = {
 	N_("Conversation Entry"),
@@ -167,7 +167,7 @@
 				g_string_append_printf(style_string,
 				                       "style \"%s_style\"\n"
 				                       "{font_name = \"%s\"}\n"
-				                       "widget \"%s\""
+				                       "widget \"%s\" "
 				                       "style \"%s_style\"\n",
 				                       prefbase, pref,
 				                       prefbase, prefbase);
@@ -260,7 +260,7 @@
 				g_string_append_printf(style_string,
 				                       "style \"%s_style\"\n"
 				                       "{font_name = \"%s\"}\n"
-				                       "widget \"%s\""
+				                       "widget \"%s\" "
 				                       "style \"%s_style\"\n",
 				                       prefbase, pref,
 				                       prefbase, prefbase);
--- a/pidgin/win32/gtkwin32dep.c	Mon May 14 19:57:03 2007 +0000
+++ b/pidgin/win32/gtkwin32dep.c	Mon May 14 23:17:42 2007 +0000
@@ -251,7 +251,13 @@
 
 static gboolean stop_flashing(GtkWidget *widget, GdkEventFocus *event, gpointer data) {
 	GtkWindow *window = data;
+	gpointer handler_id;
+
 	winpidgin_window_flash(window, FALSE);
+
+	if ((handler_id = g_object_get_data(G_OBJECT(window), "flash_stop_handler_id")))
+		g_signal_handler_disconnect(G_OBJECT(window), (gulong) GPOINTER_TO_UINT(handler_id));
+
 	return FALSE;
 }
 
@@ -275,12 +281,12 @@
 		memset(&info, 0, sizeof(FLASHWINFO));
 		info.cbSize = sizeof(FLASHWINFO);
 		info.hwnd = GDK_WINDOW_HWND(gdkwin);
-		if (flash)
-			info.dwFlags = FLASHW_ALL | FLASHW_TIMERNOFG;
-		else
+		if (flash) {
+			info.uCount = 3;
+			info.dwFlags = FLASHW_ALL | FLASHW_TIMER;
+		} else
 			info.dwFlags = FLASHW_STOP;
 		info.dwTimeout = 0;
-		info.dwTimeout = 0;
 
 		MyFlashWindowEx(&info);
 	} else
@@ -314,8 +320,11 @@
 
 	winpidgin_window_flash(window, TRUE);
 	/* Stop flashing when window receives focus */
-	g_signal_connect(G_OBJECT(window), "focus-in-event",
-					 G_CALLBACK(stop_flashing), window);
+	if (g_object_get_data(G_OBJECT(window), "flash_stop_handler_id") == NULL) {
+		gulong handler_id = g_signal_connect(G_OBJECT(window), "focus-in-event",
+						     G_CALLBACK(stop_flashing), window);
+		g_object_set_data(G_OBJECT(window), "flash_stop_handler_id", GUINT_TO_POINTER(handler_id));
+	}
 }
 
 static gboolean