changeset 15655:c8eac129daf0

merge of '3b293c5fd1cd7d68449469b92376535eb45e90c9' and 'd9c0ecf7b9a07149efdfe2351743ebfa2951b079'
author Evan Schoenberg <evan.s@dreskin.net>
date Sun, 18 Feb 2007 18:28:47 +0000
parents 552be3958d6a (current diff) 836d7c247d22 (diff)
children ca1c878be941
files
diffstat 7 files changed, 452 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/console/gntrequest.c	Sun Feb 18 18:26:55 2007 +0000
+++ b/console/gntrequest.c	Sun Feb 18 18:28:47 2007 +0000
@@ -34,6 +34,14 @@
 
 #include "gntgaim.h"
 #include "gntrequest.h"
+#include "util.c"
+
+typedef struct
+{
+	void *user_data;
+	GntWidget *entry, *dialog;
+	GCallback *cbs;
+} GaimGntFileRequest;
 
 static GntWidget *
 setup_request_window(const char *title, const char *primary,
@@ -510,6 +518,81 @@
 	return window;
 }
 
+static void
+file_cancel_cb(GntWidget *wid, gpointer fq)
+{
+	GaimGntFileRequest *data = fq;
+	if (data->cbs[1] != NULL)
+		((GaimRequestFileCb)data->cbs[1])(data->user_data, NULL);
+
+	gaim_request_close(GAIM_REQUEST_FILE, data->dialog);
+}
+
+static void
+file_ok_cb(GntWidget *wid, gpointer fq)
+{
+	GaimGntFileRequest *data = fq;
+	if (data->cbs[0] != NULL)
+		((GaimRequestFileCb)data->cbs[0])(data->user_data, gnt_entry_get_text(GNT_ENTRY(data->entry)));
+
+	gaim_request_close(GAIM_REQUEST_FILE, data->dialog);
+}
+
+static void
+file_request_destroy(GaimGntFileRequest *data)
+{
+	g_free(data->cbs);
+	g_free(data);
+}
+
+static void *
+gg_request_file(const char *title, const char *filename,
+				gboolean savedialog,
+				GCallback ok_cb, GCallback cancel_cb,
+				void *user_data)
+{
+	GntWidget *window = gnt_vbox_new(FALSE);
+	GntWidget *entry, *hbox, *button;
+	GaimGntFileRequest *data = g_new0(GaimGntFileRequest, 1);
+
+	data->user_data = user_data;
+	data->cbs = g_new0(GCallback, 2);
+	data->cbs[0] = ok_cb;
+	data->cbs[1] = cancel_cb;
+	data->dialog = window;
+	data->entry = entry = gnt_entry_new(g_strconcat(gaim_home_dir(), G_DIR_SEPARATOR_S, filename, NULL));
+	gnt_widget_set_size(entry, 30, 1);
+	gnt_box_set_toplevel(GNT_BOX(window), TRUE);
+	gnt_box_set_title(GNT_BOX(window), title ? title : (savedialog ? _("Save File...") : _("Open File...")));
+#if 0
+	/* After the string freeze */
+	gnt_box_add_widget(GNT_BOX(window), gnt_label_new(_("Please enter a full path for a file")));
+#endif
+	gnt_box_add_widget(GNT_BOX(window), entry);
+
+	hbox = gnt_hbox_new(TRUE);
+	gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID);
+
+	button = gnt_button_new(_("Cancel"));
+	g_signal_connect(G_OBJECT(button), "activate",
+		G_CALLBACK(file_cancel_cb), data);
+	gnt_box_add_widget(GNT_BOX(hbox), button);
+
+	button = gnt_button_new(_("OK"));
+	g_signal_connect(G_OBJECT(button), "activate",
+		G_CALLBACK(file_ok_cb), data);
+	gnt_box_add_widget(GNT_BOX(hbox), button);
+
+	gnt_box_add_widget(GNT_BOX(window), hbox);
+
+	g_signal_connect_swapped(G_OBJECT(window), "destroy",
+			G_CALLBACK(file_request_destroy), data);
+
+	gnt_widget_show(window);
+
+	return window;
+}
+
 static GaimRequestUiOps uiops =
 {
 	.request_input = gg_request_input,
@@ -517,8 +600,8 @@
 	.request_choice = gg_request_choice,
 	.request_action = gg_request_action,
 	.request_fields = gg_request_fields,
-	.request_file = NULL,                  /* No plans for these */
-	.request_folder = NULL
+	.request_file = gg_request_file,
+	.request_folder = NULL                        /* No plans for this */
 };
 
 GaimRequestUiOps *gg_request_get_ui_ops()
--- a/console/libgnt/gntwm.c	Sun Feb 18 18:26:55 2007 +0000
+++ b/console/libgnt/gntwm.c	Sun Feb 18 18:28:47 2007 +0000
@@ -41,6 +41,7 @@
 static void gnt_wm_win_moved(GntWM *wm, GntNode *node);
 static void gnt_wm_give_focus(GntWM *wm, GntWidget *widget);
 static void update_window_in_list(GntWM *wm, GntWidget *wid);
+static void shift_window(GntWM *wm, GntWidget *widget, int dir);
 
 static gboolean write_already(gpointer data);
 static int write_timeout;
@@ -373,12 +374,50 @@
 	gnt_wm_raise_window(wm, widget);
 }
 
+static void
+populate_window_list(GntWM *wm)
+{
+	GList *iter;
+	GntTree *tree = GNT_TREE(wm->windows->tree);
+	for (iter = wm->list; iter; iter = iter->next) {
+		GntBox *box = GNT_BOX(iter->data);
+
+		gnt_tree_add_row_last(tree, box,
+				gnt_tree_create_row(tree, box->title), NULL);
+		update_window_in_list(wm, GNT_WIDGET(box));
+	}
+}
+
+static gboolean
+window_list_key_pressed(GntWidget *widget, const char *text, GntWM *wm)
+{
+	if (text[1] == 0 && wm->ordered) {
+		GntWidget *sel = gnt_tree_get_selection_data(GNT_TREE(widget));
+		switch (text[0]) {
+			case '-':
+			case '<':
+				shift_window(wm, sel, -1);
+				break;
+			case '+':
+			case '>':
+				shift_window(wm, sel, 1);
+				break;
+			default:
+				return FALSE;
+		}
+		gnt_tree_remove_all(GNT_TREE(widget));
+		populate_window_list(wm);
+		gnt_tree_set_selected(GNT_TREE(widget), sel);
+		return TRUE;
+	}
+	return FALSE;
+}
+
 static gboolean
 window_list(GntBindable *bindable, GList *null)
 {
 	GntWM *wm = GNT_WM(bindable);
 	GntWidget *tree, *win;
-	GList *iter;
 
 	if (wm->_list.window || wm->menu)
 		return TRUE;
@@ -393,17 +432,12 @@
 	tree = wm->windows->tree;
 
 	gnt_box_set_title(GNT_BOX(win), "Window List");
-
-	for (iter = wm->list; iter; iter = iter->next) {
-		GntBox *box = GNT_BOX(iter->data);
-
-		gnt_tree_add_row_last(GNT_TREE(tree), box,
-				gnt_tree_create_row(GNT_TREE(tree), box->title), NULL);
-		update_window_in_list(wm, GNT_WIDGET(box));
-	}
+	
+	populate_window_list(wm);
 
 	gnt_tree_set_selected(GNT_TREE(tree), wm->ordered->data);
 	g_signal_connect(G_OBJECT(tree), "activate", G_CALLBACK(window_list_activate), wm);
+	g_signal_connect(G_OBJECT(tree), "key_pressed", G_CALLBACK(window_list_key_pressed), wm);
 
 	gnt_tree_set_col_width(GNT_TREE(tree), 0, getmaxx(stdscr) / 3);
 	gnt_widget_set_size(tree, 0, getmaxy(stdscr) / 2);
--- a/libpurple/gaim-compat.h	Sun Feb 18 18:26:55 2007 +0000
+++ b/libpurple/gaim-compat.h	Sun Feb 18 18:28:47 2007 +0000
@@ -1984,4 +1984,294 @@
 #define gaim_status_init        purple_status_init
 #define gaim_status_uninit      purple_status_uninit
 
+/* from stringref.h */
+
+#define GaimStringref  PurpleStringref
+
+#define gaim_stringref_new        purple_stringref_new
+#define gaim_stringref_new_noref  purple_stringref_new_noref
+#define gaim_stringref_printf     purple_stringref_printf
+#define gaim_stringref_ref        purple_stringref_ref
+#define gaim_stringref_unref      purple_stringref_unref
+#define gaim_stringref_value      purple_stringref_value
+#define gaim_stringref_cmp        purple_stringref_cmp
+#define gaim_stringref_len        purple_stringref_len
+
+/* from stun.h */
+
+#define GaimStunNatDiscovery  PurpleStunNatDiscovery
+
+#define GAIM_STUN_STATUS_UNDISCOVERED  PURPLE_STUN_STATUS_UNDISCOVERED
+#define GAIM_STUN_STATUS_UNKNOWN       PURPLE_STUN_STATUS_UNKNOWN
+#define GAIM_STUN_STATUS_DISCOVERING   PURPLE_STUN_STATUS_DISCOVERING
+#define GAIM_STUN_STATUS_DISCOVERED    PURPLE_STUN_STATUS_DISCOVERED
+#define GaimStunStatus  PurpleStunStatus
+
+#define GAIM_STUN_NAT_TYPE_PUBLIC_IP             PURPLE_STUN_NAT_TYPE_PUBLIC_IP
+#define GAIM_STUN_NAT_TYPE_UNKNOWN_NAT           PURPLE_STUN_NAT_TYPE_UNKNOWN_NAT
+#define GAIM_STUN_NAT_TYPE_FULL_CONE             PURPLE_STUN_NAT_TYPE_FULL_CONE
+#define GAIM_STUN_NAT_TYPE_RESTRICTED_CONE       PURPLE_STUN_NAT_TYPE_RESTRICTED_CONE
+#define GAIM_STUN_NAT_TYPE_PORT_RESTRICTED_CONE  PURPLE_STUN_NAT_TYPE_PORT_RESTRICTED_CONE
+#define GAIM_STUN_NAT_TYPE_SYMMETRIC             PURPLE_STUN_NAT_TYPE_SYMMETRIC
+#define GaimStunNatType  PurpleStunNatType
+
+/* why didn't this have a Gaim prefix before? */
+#define StunCallback  PurpleStunCallback
+
+#define gaim_stun_discover  purple_stun_discover
+#define gaim_stun_init      purple_stun_init
+
+/* from upnp.h */
+
+/* suggested rename: PurpleUPnpMappingHandle */
+#define UPnPMappingAddRemove  PurpleUPnPMappingAddRemove
+
+#define GaimUPnPCallback  PurpleUPnPCallback
+
+#define gaim_upnp_discover             purple_upnp_discover
+#define gaim_upnp_get_public_ip        purple_upnp_get_public_ip
+#define gaim_upnp_cancel_port_mapping  purple_upnp_cancel_port_mapping
+#define gaim_upnp_set_port_mapping     purple_upnp_set_port_mapping
+
+#define gaim_upnp_remove_port_mapping  purple_upnp_remove_port_mapping
+
+/* from util.h */
+
+#define GaimUtilFetchUrlData  PurpleUtilFetchUrlData
+#define GaimMenuAction        PurpleMenuAction
+
+#define GaimInfoFieldFormatCallback  PurpleIntoFieldFormatCallback
+
+#define GaimKeyValuePair  PurpleKeyValuePair
+
+#define gaim_menu_action_new   purple_menu_action_new
+#define gaim_menu_action_free  purple_menu_action_free
+
+#define gaim_base16_encode   purple_base16_encode
+#define gaim_base16_decode   purple_base16_decode
+#define gaim_base64_encode   purple_base64_encode
+#define gaim_base64_decode   purple_base64_decode
+#define gaim_quotedp_decode  purple_quotedp_decode
+
+#define gaim_mime_decode_field  purple_mime_deco_field
+
+#define gaim_utf8_strftime      purple_utf8_strftime
+#define gaim_date_format_short  purple_date_format_short
+#define gaim_date_format_long   purple_date_format_long
+#define gaim_date_format_full   purple_date_format_full
+#define gaim_time_format        purple_time_format
+#define gaim_time_build         purple_time_build
+
+#define GAIM_NO_TZ_OFF  PURPLE_NO_TZ_OFF
+
+#define gaim_str_to_time  purple_str_to_time
+
+#define gaim_markup_find_tag            purple_markup_find_tag
+#define gaim_markup_extract_info_field  purple_markup_extract_info_field
+#define gaim_markup_html_to_xhtml       purple_markup_html_to_xhtml
+#define gaim_markup_strip_html          purple_markup_strip_html
+#define gaim_markup_linkify             purple_markup_linkify
+#define gaim_markup_slice               purple_markup_slice
+#define gaim_markup_get_tag_name        purple_markup_get_tag_name
+#define gaim_unescape_html              purple_unescape_html
+
+#define gaim_home_dir  purple_home_dir
+#define gaim_user_dir  purple_user_dir
+
+#define gaim_util_set_user_dir  purple_util_set_user_dir
+
+#define gaim_build_dir  purple_build_dir
+
+#define gaim_util_write_data_to_file  purple_util_write_data_to_file
+
+#define gaim_util_read_xml_from_file  purple_util_read_xml_from_file
+
+#define gaim_mkstemp  purple_mkstemp
+
+#define gaim_program_is_valid  purple_program_is_valid
+
+#define gaim_running_gnome  purple_running_gnome
+#define gaim_running_kde    purple_running_kde
+#define gaim_running_osx    purple_running_osx
+
+#define gaim_fd_get_ip  purple_fd_get_ip
+
+#define gaim_normalize         purple_normalize
+#define gaim_normalize_nocase  purple_normalize_nocase
+
+#define gaim_strdup_withhtml  purple_strdup_withhtml
+
+#define gaim_str_has_prefix  purple_str_has_prefix
+#define gaim_str_has_suffix  purple_str_has_suffix
+#define gaim_str_add_cr      purple_str_add_cr
+#define gaim_str_strip_char  purple_str_strip_char
+
+#define gaim_util_chrreplace  purple_util_chrreplace
+
+#define gaim_strreplace  purple_strreplace
+
+#define gaim_utf8_ncr_encode  purple_utf8_ncr_encode
+#define gaim_utf8_ncr_decode  purple_utf8_ncr_decode
+
+#define gaim_strcasereplace  purple_strcasereplace
+#define gaim_strcasestr      purple_strcasestr
+
+#define gaim_str_size_to_units      purple_str_size_to_units
+#define gaim_str_seconds_to_string  purple_str_seconds_to_string
+#define gaim_str_binary_to_ascii    purple_str_binary_to_ascii
+
+
+#define gaim_got_protocol_handler_uri  purple_got_protocol_handler_uri
+
+#define gaim_url_parse  purple_url_parse
+
+#define GaimUtilFetchUrlCallback  PurpleUtilFetchUrlCallback
+#define gaim_util_fetch_url          purple_util_fetch_url
+#define gaim_util_fetch_url_request  purple_util_fetch_url_request
+#define gaim_util_fetch_url_cancel   purple_util_fetch_url_cancel
+
+#define gaim_url_decode  purple_url_decode
+#define gaim_url_encode  purple_url_encode
+
+#define gaim_email_is_valid  purple_email_is_valid
+
+#define gaim_uri_list_extract_uris       purple_uri_list_extract_uris
+#define gaim_uri_list_extract_filenames  purple_uri_list_extract_filenames
+
+#define gaim_utf8_try_convert  purple_utf8_try_convert
+#define gaim_utf8_salvage      purple_utf8_salvage
+#define gaim_utf8_strcasecmp   purple_utf8_strcasecmp
+#define gaim_utf8_has_word     purple_utf8_has_word
+
+#define gaim_print_utf8_to_console  purple_print_utf8_to_console
+
+#define gaim_message_meify  purple_message_meify
+
+#define gaim_text_strip_mnemonic  purple_text_strip_mnemonic
+
+#define gaim_unescape_filename  purple_unescape_filename
+#define gaim_escape_filename    purple_escape_filename
+
+/* from value.h */
+
+#define GAIM_TYPE_UNKNOWN  PURPLE_TYPE_UNKNOWN
+#define GAIM_TYPE_SUBTYPE  PURPLE_TYPE_SUBTYPE
+#define GAIM_TYPE_CHAR     PURPLE_TYPE_CHAR
+#define GAIM_TYPE_UCHAR    PURPLE_TYPE_UCHAR
+#define GAIM_TYPE_BOOLEAN  PURPLE_TYPE_BOOLEAN
+#define GAIM_TYPE_SHORT    PURPLE_TYPE_SHORT
+#define GAIM_TYPE_USHORT   PURPLE_TYPE_USHORT
+#define GAIM_TYPE_INT      PURPLE_TYPE_INT
+#define GAIM_TYPE_UINT     PURPLE_TYPE_UINT
+#define GAIM_TYPE_LONG     PURPLE_TYPE_LONG
+#define GAIM_TYPE_ULONG    PURPLE_TYPE_ULONG
+#define GAIM_TYPE_INT64    PURPLE_TYPE_INT64
+#define GAIM_TYPE_UINT64   PURPLE_TYPE_UINT64
+#define GAIM_TYPE_STRING   PURPLE_TYPE_STRING
+#define GAIM_TYPE_OBJECT   PURPLE_TYPE_OBJECT
+#define GAIM_TYPE_POINTER  PURPLE_TYPE_POINTER
+#define GAIM_TYPE_ENUM     PURPLE_TYPE_ENUM
+#define GAIM_TYPE_BOXED    PURPLE_TYPE_BOXED
+#define GaimType  PurpleType
+
+
+#define GAIM_SUBTYPE_UNKNOWN       PURPLE_SUBTYPE_UNKNOWN
+#define GAIM_SUBTYPE_ACCOUNT       PURPLE_SUBTYPE_ACCOUNT
+#define GAIM_SUBTYPE_BLIST         PURPLE_SUBTYPE_BLIST
+#define GAIM_SUBTYPE_BLIST_BUDDY   PURPLE_SUBTYPE_BLIST_BUDDY
+#define GAIM_SUBTYPE_BLIST_GROUP   PURPLE_SUBTYPE_BLIST_GROUP
+#define GAIM_SUBTYPE_BLIST_CHAT    PURPLE_SUBTYPE_BLIST_CHAT
+#define GAIM_SUBTYPE_BUDDY_ICON    PURPLE_SUBTYPE_BUDDY_ICON
+#define GAIM_SUBTYPE_CONNECTION    PURPLE_SUBTYPE_CONNECTION
+#define GAIM_SUBTYPE_CONVERSATION  PURPLE_SUBTYPE_CONVERSATION
+#define GAIM_SUBTYPE_PLUGIN        PURPLE_SUBTYPE_PLUGIN
+#define GAIM_SUBTYPE_BLIST_NODE    PURPLE_SUBTYPE_BLIST_NODE
+#define GAIM_SUBTYPE_CIPHER        PURPLE_SUBTYPE_CIPHER
+#define GAIM_SUBTYPE_STATUS        PURPLE_SUBTYPE_STATUS
+#define GAIM_SUBTYPE_LOG           PURPLE_SUBTYPE_LOG
+#define GAIM_SUBTYPE_XFER          PURPLE_SUBTYPE_XFER
+#define GAIM_SUBTYPE_SAVEDSTATUS   PURPLE_SUBTYPE_SAVEDSTATUS
+#define GAIM_SUBTYPE_XMLNODE       PURPLE_SUBTYPE_XMLNODE
+#define GAIM_SUBTYPE_USERINFO      PURPLE_SUBTYPE_USERINFO
+#define GaimSubType  PurpleSubType
+
+#define GaimValue  PurpleValue
+
+#define gaim_value_new                purple_value_new
+#define gaim_value_new_outgoing       purple_value_new_outgoing
+#define gaim_value_destroy            purple_value_destroy
+#define gaim_value_dup                purple_value_dup
+#define gaim_value_get_type           purple_value_get_type
+#define gaim_value_get_subtype        purple_value_get_subtype
+#define gaim_value_get_specific_type  purple_value_get_specific_type
+#define gaim_value_is_outgoing        purple_value_is_outgoing
+#define gaim_value_set_char           purple_value_set_char
+#define gaim_value_set_uchar          purple_value_set_uchar
+#define gaim_value_set_boolean        purple_value_set_boolean
+#define gaim_value_set_short          purple_value_set_short
+#define gaim_value_set_ushort         purple_value_set_ushort
+#define gaim_value_set_int            purple_value_set_int
+#define gaim_value_set_uint           purple_value_set_uint
+#define gaim_value_set_long           purple_value_set_long
+#define gaim_value_set_ulong          purple_value_set_ulong
+#define gaim_value_set_int64          purple_value_set_int64
+#define gaim_value_set_uint64         purple_value_set_uint64
+#define gaim_value_set_string         purple_value_set_string
+#define gaim_value_set_object         purple_value_set_object
+#define gaim_value_set_pointer        purple_value_set_pointer
+#define gaim_value_set_enum           purple_value_set_enum
+#define gaim_value_set_boxed          purple_value_set_boxed
+#define gaim_value_get_char           purple_value_get_char
+#define gaim_value_get_uchar          purple_value_get_uchar
+#define gaim_value_get_boolean        purple_value_get_boolean
+#define gaim_value_get_short          purple_value_get_short
+#define gaim_value_get_ushort         purple_value_get_ushort
+#define gaim_value_get_int            purple_value_get_int
+#define gaim_value_get_uint           purple_value_get_uint
+#define gaim_value_get_long           purple_value_get_long
+#define gaim_value_get_ulong          purple_value_get_ulong
+#define gaim_value_get_int64          purple_value_get_int64
+#define gaim_value_get_uint64         purple_value_get_uint64
+#define gaim_value_get_string         purple_value_get_string
+#define gaim_value_get_object         purple_value_get_object
+#define gaim_value_get_pointer        purple_value_get_pointer
+#define gaim_value_get_enum           purple_value_get_enum
+#define gaim_value_get_boxed          purple_value_get_boxed
+
+/* from version.h */
+
+#define GAIM_MAJOR_VERSION  PURPLE_MAJOR_VERSION
+#define GAIM_MINOR_VERSION  PURPLE_MINOR_VERSION
+#define GAIM_MICRO_VERSION  PURPLE_MICRO_VERSION
+
+#define GAIM_VERSION_CHECK  PURPLE_VERSION_CHECK
+
+/* from whiteboard.h */
+
+#ifndef _GAIM_WHITEBOARD_H_
+#define _GAIM_WHITEBOARD_H_
+
+#define GaimWhiteboardPrplOps  PurpleWhiteboardPrplOps
+#define GaimWhiteboard         PurpleWhiteboard
+#define GaimWhiteboardUiOps    PurpleWhiteboardUiOps
+
+#define gaim_whiteboard_set_ui_ops    purple_whiteboard_set_ui_ops
+#define gaim_whiteboard_set_prpl_ops  purple_whiteboard_set_prpl_ops
+
+#define gaim_whiteboard_create             purple_whiteboard_create
+#define gaim_whiteboard_destroy            purple_whiteboard_destroy
+#define gaim_whiteboard_start              purple_whiteboard_start
+#define gaim_whiteboard_get_session        purple_whiteboard_get_session
+#define gaim_whiteboard_draw_list_destroy  purple_whiteboard_draw_list_destroy
+#define gaim_whiteboard_get_dimensions     purple_whiteboard_get_dimensions
+#define gaim_whiteboard_set_dimensions     purple_whiteboard_set_dimensions
+#define gaim_whiteboard_draw_point         purple_whiteboard_draw_point
+#define gaim_whiteboard_send_draw_list     purple_whiteboard_send_draw_list
+#define gaim_whiteboard_draw_line          purple_whiteboard_draw_line
+#define gaim_whiteboard_clear              purple_whiteboard_clear
+#define gaim_whiteboard_send_clear         purple_whiteboard_send_clear
+#define gaim_whiteboard_send_brush         purple_whiteboard_send_brush
+#define gaim_whiteboard_get_brush          purple_whiteboard_get_brush
+#define gaim_whiteboard_set_brush          purple_whiteboard_set_brush
+
 #endif /* _GAIM_COMPAT_H_ */
--- a/libpurple/protocols/jabber/jabber.c	Sun Feb 18 18:26:55 2007 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Sun Feb 18 18:28:47 2007 +0000
@@ -1431,6 +1431,8 @@
 			g_free(jbr->thread_id);
 			jbr->thread_id = NULL;
 		}
+		if(jbr->chat_states == JABBER_CHAT_STATES_SUPPORTED)
+			jabber_message_conv_closed(js, who);
 	}
 
 	jabber_id_free(jid);
--- a/libpurple/protocols/jabber/message.c	Sun Feb 18 18:26:55 2007 +0000
+++ b/libpurple/protocols/jabber/message.c	Sun Feb 18 18:28:47 2007 +0000
@@ -78,12 +78,26 @@
 	}
 
 	if(!jm->xhtml && !jm->body) {
-		if(JM_STATE_COMPOSING == jm->chat_state)
+		if(JM_STATE_COMPOSING == jm->chat_state) {
 			serv_got_typing(jm->js->gc, from, 0, GAIM_TYPING);
-		else if(JM_STATE_PAUSED == jm->chat_state)
+		} else if(JM_STATE_PAUSED == jm->chat_state) {
 			serv_got_typing(jm->js->gc, from, 0, GAIM_TYPED);
-		else
+		} else if(JM_STATE_GONE == jm->chat_state) {
+			GaimConversation *conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM,
+					from, jm->js->gc->account);
+			if (conv) {
+#if 0  /* String freeze */
+				gaim_conversation_write(conv, "",
+						  "So and so has left the conversation.",
+						  GAIM_MESSAGE_INFO, time(NULL));
+#endif
+				
+			}
 			serv_got_typing_stopped(jm->js->gc, from);
+			
+		} else {
+			serv_got_typing_stopped(jm->js->gc, from);
+		}
 	} else {
 		if(jbr) {
 			if(JM_TS_JEP_0085 == (jm->typing_style & JM_TS_JEP_0085)) {
@@ -635,3 +649,15 @@
 	return 0;
 }
 
+void jabber_message_conv_closed(JabberStream *js, const char *who)
+{
+	JabberMessage *jm = g_new0(JabberMessage, 1);
+	jm->js = js;
+	jm->type = JABBER_MESSAGE_CHAT;
+	jm->to = g_strdup(who);
+	jm->id = jabber_get_next_id(jm->js);
+	jm->typing_style = JM_TS_JEP_0085;
+	jm->chat_state = JM_STATE_GONE;
+	jabber_message_send(jm);
+	jabber_message_free(jm);
+}
--- a/libpurple/protocols/jabber/message.h	Sun Feb 18 18:26:55 2007 +0000
+++ b/libpurple/protocols/jabber/message.h	Sun Feb 18 18:28:47 2007 +0000
@@ -22,6 +22,7 @@
 #ifndef _GAIM_JABBER_MESSAGE_H_
 #define _GAIM_JABBER_MESSAGE_H_
 
+#include "buddy.h"
 #include "jabber.h"
 #include "xmlnode.h"
 
@@ -72,6 +73,6 @@
 int jabber_message_send_chat(GaimConnection *gc, int id, const char *message, GaimMessageFlags flags);
 
 unsigned int jabber_send_typing(GaimConnection *gc, const char *who, GaimTypingState state);
-
+void jabber_message_conv_closed(JabberStream *js, const char *who);
 
 #endif /* _GAIM_JABBER_MESSAGE_H_ */
--- a/pidgin/plugins/perl/common/GtkConv.xs	Sun Feb 18 18:26:55 2007 +0000
+++ b/pidgin/plugins/perl/common/GtkConv.xs	Sun Feb 18 18:28:47 2007 +0000
@@ -37,7 +37,7 @@
 pidgin_conv_get_gtkconv(conv)
 	Gaim::Conversation conv
 PPCODE:
-	if (conv != NULL && GAIM_IS_GTK_CONVERSATION(conv))
+	if (conv != NULL && PIDGIN_IS_PIDGIN_CONVERSATION(conv))
 		XPUSHs(sv_2mortal(gaim_perl_bless_object(
 				PIDGIN_CONVERSATION(conv),
 				"Pidgin::Conversation")));