changeset 18046:58e28ccf08e6

merge of '9d95292d55daedb7f74c7df323ad2c69d347d384' and 'fc5f9423f83f31e42ce80066eec30cdbbae7be01'
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Tue, 05 Jun 2007 01:38:09 +0000
parents 6b7b13adb9b1 (current diff) 25819c54a963 (diff)
children 82d68fedbd77
files COPYRIGHT ChangeLog ChangeLog.API finch/gntaccount.c libpurple/util.c pidgin/gtkaccount.c pidgin/gtkblist.c pidgin/gtkimhtml.c
diffstat 15 files changed, 290 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Mon Jun 04 23:48:54 2007 +0000
+++ b/COPYRIGHT	Tue Jun 05 01:38:09 2007 +0000
@@ -146,6 +146,7 @@
 Charlie Gordon
 Ryan C. Gordon
 Miah Gregory
+David Grohmann
 Christian Hammond
 Erick Hamness
 Fred Hampton
--- a/ChangeLog	Mon Jun 04 23:48:54 2007 +0000
+++ b/ChangeLog	Tue Jun 05 01:38:09 2007 +0000
@@ -9,6 +9,8 @@
 	  (Arjan van de Ven with Intel Corporation)
 	* No longer linkifies screennames containing @ signs in join/part
 	  notifications in chats
+	* With the HTML logger, images in conversations are now saved.
+	  NOTE: Saved images are not yet displayed when loading logs.
 
 	Pidgin:
 	* Ensure only one copy of Pidgin is running with a given configuration
--- a/ChangeLog.API	Mon Jun 04 23:48:54 2007 +0000
+++ b/ChangeLog.API	Tue Jun 05 01:38:09 2007 +0000
@@ -15,6 +15,10 @@
 	* purple_core_ensure_single_instance()
 	    This is for UIs to use to ensure only one copy is running.
 	* purple_dbus_is_owner()
+	* purple_image_data_calculate_filename()
+	* purple_timeout_add_seconds()
+	    Callers should prefer this to purple_timeout_add() for timers
+	    longer than 1 second away.  Be aware of the rounding, though.
 	* purple_timeout_add_seconds()
 	    Callers should prefer this to purple_timeout_add() for timers
 	    longer than 1 second away.  Be aware of the rounding, though.
--- a/finch/gntaccount.c	Mon Jun 04 23:48:54 2007 +0000
+++ b/finch/gntaccount.c	Tue Jun 05 01:38:09 2007 +0000
@@ -282,7 +282,11 @@
 
 		if (dialog->account)
 		{
-			s = strrchr(username, purple_account_user_split_get_separator(split));
+			if(purple_account_user_split_get_reverse(split))
+				s = strrchr(username, purple_account_user_split_get_separator(split));
+			else
+				s = strchr(username, purple_account_user_split_get_separator(split));
+
 			if (s != NULL)
 			{
 				*s = '\0';
--- a/libpurple/accountopt.c	Mon Jun 04 23:48:54 2007 +0000
+++ b/libpurple/accountopt.c	Tue Jun 05 01:38:09 2007 +0000
@@ -308,6 +308,7 @@
 	split->text = g_strdup(text);
 	split->field_sep = sep;
 	split->default_value = g_strdup(default_value);
+	split->reverse = TRUE;
 
 	return split;
 }
@@ -345,3 +346,19 @@
 
 	return split->field_sep;
 }
+
+gboolean
+purple_account_user_split_get_reverse(const PurpleAccountUserSplit *split)
+{
+	g_return_val_if_fail(split != NULL, FALSE);
+
+	return split->reverse;
+}
+
+void
+purple_account_user_split_set_reverse(PurpleAccountUserSplit *split, gboolean reverse)
+{
+	g_return_if_fail(split != NULL);
+
+	split->reverse = reverse;
+}
--- a/libpurple/accountopt.h	Mon Jun 04 23:48:54 2007 +0000
+++ b/libpurple/accountopt.h	Tue Jun 05 01:38:09 2007 +0000
@@ -64,6 +64,9 @@
 	char *text;             /**< The text that will appear to the user. */
 	char *default_value;    /**< The default value.                     */
 	char  field_sep;        /**< The field separator.                   */
+	gboolean reverse;       /**< TRUE if the separator should be found
+							  starting a the end of the string, FALSE
+							  otherwise                                 */
 
 } PurpleAccountUserSplit;
 
@@ -353,6 +356,23 @@
  */
 char purple_account_user_split_get_separator(const PurpleAccountUserSplit *split);
 
+/**
+ * Returns the 'reverse' value for an account split.
+ *
+ * @param split The account username split.
+ *
+ * @return The 'reverse' value.
+ */
+gboolean purple_account_user_split_get_reverse(const PurpleAccountUserSplit *split);
+
+/**
+ * Sets the 'reverse' value for an account split.
+ *
+ * @param split   The account username split.
+ * @param reverse The 'reverse' value
+ */
+void purple_account_user_split_set_reverse(PurpleAccountUserSplit *split, gboolean reverse);
+
 /*@}*/
 
 #ifdef __cplusplus
--- a/libpurple/buddyicon.c	Mon Jun 04 23:48:54 2007 +0000
+++ b/libpurple/buddyicon.c	Tue Jun 05 01:38:09 2007 +0000
@@ -24,7 +24,6 @@
  */
 #include "internal.h"
 #include "buddyicon.h"
-#include "cipher.h"
 #include "conversation.h"
 #include "dbus-maybe.h"
 #include "debug.h"
@@ -93,33 +92,6 @@
 	}
 }
 
-static char *
-purple_buddy_icon_data_calculate_filename(guchar *icon_data, size_t icon_len)
-{
-	PurpleCipherContext *context;
-	gchar digest[41];
-
-	context = purple_cipher_context_new_by_name("sha1", NULL);
-	if (context == NULL)
-	{
-		purple_debug_error("buddyicon", "Could not find sha1 cipher\n");
-		g_return_val_if_reached(NULL);
-	}
-
-	/* Hash the icon data */
-	purple_cipher_context_append(context, icon_data, icon_len);
-	if (!purple_cipher_context_digest_to_str(context, sizeof(digest), digest, NULL))
-	{
-		purple_debug_error("buddyicon", "Failed to get SHA-1 digest.\n");
-		g_return_val_if_reached(NULL);
-	}
-	purple_cipher_context_destroy(context);
-
-	/* Return the filename */
-	return g_strdup_printf("%s.%s", digest,
-	                       purple_util_get_image_extension(icon_data, icon_len));
-}
-
 static void
 purple_buddy_icon_data_cache(PurpleStoredImage *img)
 {
@@ -238,7 +210,7 @@
 
 	if (filename == NULL)
 	{
-		file = purple_buddy_icon_data_calculate_filename(icon_data, icon_len);
+		file = purple_util_get_image_filename(icon_data, icon_len);
 		if (file == NULL)
 		{
 			g_free(icon_data);
@@ -966,7 +938,7 @@
 
 		g_free(path);
 
-		new_filename = purple_buddy_icon_data_calculate_filename(icon_data, icon_len);
+		new_filename = purple_util_get_image_filename(icon_data, icon_len);
 		if (new_filename == NULL)
 		{
 			purple_debug_error("buddyicon",
--- a/libpurple/buddyicon.h	Mon Jun 04 23:48:54 2007 +0000
+++ b/libpurple/buddyicon.h	Tue Jun 05 01:38:09 2007 +0000
@@ -31,6 +31,7 @@
 #include "blist.h"
 #include "imgstore.h"
 #include "prpl.h"
+#include "util.h"
 
 #ifdef __cplusplus
 extern "C" {
--- a/libpurple/log.c	Mon Jun 04 23:48:54 2007 +0000
+++ b/libpurple/log.c	Tue Jun 05 01:38:09 2007 +0000
@@ -32,6 +32,7 @@
 #include "prefs.h"
 #include "util.h"
 #include "stringref.h"
+#include "imgstore.h"
 
 static GSList *loggers = NULL;
 
@@ -690,6 +691,109 @@
 		return g_strdup(purple_time_format(&tm));
 }
 
+/* NOTE: This can return msg (which you may or may not want to g_free())
+ * NOTE: or a newly allocated string which you MUST g_free(). */
+static char *
+convert_image_tags(const PurpleLog *log, const char *msg)
+{
+	const char *tmp;
+	const char *start;
+	const char *end;
+	GData *attributes;
+	GString *newmsg = NULL;
+
+	tmp = msg;
+
+	newmsg = g_string_new("");
+
+	while (purple_markup_find_tag("img", tmp, &start, &end, &attributes)) {
+		int imgid = 0;
+		char *idstr = NULL;
+
+		if (newmsg == NULL)
+			newmsg = g_string_new("");
+
+		/* copy any text before the img tag */
+		if (tmp < start)
+			g_string_append_len(newmsg, tmp, start - tmp);
+
+		idstr = g_datalist_get_data(&attributes, "id");
+
+		imgid = atoi(idstr);
+		if (imgid != 0)
+		{
+			FILE *image_file;
+			char *dir;
+			PurpleStoredImage *image;
+			gconstpointer image_data;
+			char *new_filename = NULL;
+			char *path = NULL;
+			size_t image_byte_count;
+
+			image = purple_imgstore_find_by_id(imgid);
+			if (image == NULL)
+			{
+				/* This should never happen. */
+				g_string_free(newmsg, TRUE);
+				g_return_val_if_reached((char *)msg);
+			}
+
+			image_data       = purple_imgstore_get_data(image);
+			image_byte_count = purple_imgstore_get_size(image);
+			dir              = purple_log_get_log_dir(log->type, log->name, log->account);
+			new_filename     = purple_util_get_image_filename(image_data, image_byte_count);
+
+			path = g_build_filename(dir, new_filename, NULL);
+
+			/* Only save unique files. */
+			if (!g_file_test(path, G_FILE_TEST_EXISTS))
+			{
+				if ((image_file = g_fopen(path, "wb")) != NULL)
+				{
+					if (!fwrite(image_data, image_byte_count, 1, image_file))
+					{
+						purple_debug_error("log", "Error writing %s: %s\n",
+						                   path, strerror(errno));
+						fclose(image_file);
+
+						/* Attempt to not leave half-written files around. */
+						unlink(path);
+					}
+					else
+					{
+						purple_debug_info("log", "Wrote image file: %s\n", path);
+						fclose(image_file);
+					}
+				}
+				else
+				{
+					purple_debug_error("log", "Unable to create file %s: %s\n",
+					                   path, strerror(errno));
+				}
+			}
+
+			/* Write the new image tag */
+			g_string_append_printf(newmsg, "<IMG SRC=\"%s\">", new_filename);
+			g_free(new_filename);
+			g_free(path);
+		}
+
+		/* Continue from the end of the tag */
+		tmp = end + 1;
+	}
+
+	if (newmsg == NULL)
+	{
+		/* No images were found to change. */
+		return (char *)msg;
+	}
+
+	/* Append any remaining message data */
+	g_string_append(newmsg, tmp);
+
+	return g_string_free(newmsg, FALSE);
+}
+
 void purple_log_common_writer(PurpleLog *log, const char *ext)
 {
 	PurpleLogCommonLoggerData *data = log->logger_data;
@@ -1191,6 +1295,7 @@
 							  const char *from, time_t time, const char *message)
 {
 	char *msg_fixed;
+	char *image_corrected_msg;
 	char *date;
 	char *header;
 	PurplePlugin *plugin = purple_find_prpl(purple_account_get_protocol_id(log->account));
@@ -1231,7 +1336,14 @@
 	if(!data->file)
 		return 0;
 
-	purple_markup_html_to_xhtml(message, &msg_fixed, NULL);
+	image_corrected_msg = convert_image_tags(log, message);
+	purple_markup_html_to_xhtml(image_corrected_msg, &msg_fixed, NULL);
+
+	/* Yes, this breaks encapsulation.  But it's a static function and
+	 * this saves a needless strdup(). */
+	if (image_corrected_msg != message)
+		g_free(image_corrected_msg);
+
 	date = log_get_timestamp(log, time);
 
 	if(log->type == PURPLE_LOG_SYSTEM){
--- a/libpurple/protocols/jabber/libxmpp.c	Mon Jun 04 23:48:54 2007 +0000
+++ b/libpurple/protocols/jabber/libxmpp.c	Tue Jun 05 01:38:09 2007 +0000
@@ -195,9 +195,11 @@
 
 	/* Translators: 'domain' is used here in the context of Internet domains, e.g. pidgin.im */
         split = purple_account_user_split_new(_("Domain"), NULL, '@');
+		purple_account_user_split_set_reverse(split, FALSE);
         prpl_info.user_splits = g_list_append(prpl_info.user_splits, split);
 
         split = purple_account_user_split_new(_("Resource"), "Home", '/');
+		purple_account_user_split_set_reverse(split, FALSE);
         prpl_info.user_splits = g_list_append(prpl_info.user_splits, split);
 
         option = purple_account_option_bool_new(_("Force old (port 5223) SSL"), "old_ssl", FALSE);
--- a/libpurple/util.c	Mon Jun 04 23:48:54 2007 +0000
+++ b/libpurple/util.c	Tue Jun 05 01:38:09 2007 +0000
@@ -22,6 +22,7 @@
  */
 #include "internal.h"
 
+#include "cipher.h"
 #include "conversation.h"
 #include "core.h"
 #include "debug.h"
@@ -1422,6 +1423,40 @@
 						plain = g_string_append_c(plain, '\n');
 					continue;
 				}
+				if(!g_ascii_strncasecmp(c, "<img", 4) && (*(c+4) == '>' || *(c+4) == ' ')) {
+					const char *p = c;
+					GString *src = NULL;
+					struct purple_parse_tag *pt;
+					while(*p && *p != '>') {
+						if(!g_ascii_strncasecmp(p, "src=", strlen("src="))) {
+							const char *q = p + strlen("src=");
+							src = g_string_new("");
+							if(*q == '\'' || *q == '\"')
+								q++;
+							while(*q && *q != '\"' && *q != '\'' && *q != ' ') {
+								src = g_string_append_c(src, *q);
+								q++;
+							}
+							p = q;
+						}
+						p++;
+					}
+					if ((c = strchr(c, '>')) != NULL)
+						c++;
+					else
+						c = p;
+					pt = g_new0(struct purple_parse_tag, 1);
+					pt->src_tag = "img";
+					pt->dest_tag = "img";
+					tags = g_list_prepend(tags, pt);
+					if(xhtml && src && src->len)
+						g_string_append_printf(xhtml, "<img src='%s' alt=''>", g_strstrip(src->str));
+					else
+						pt->ignore = TRUE;
+					if (src)
+						g_string_free(src, TRUE);
+					continue;
+				}
 				if(!g_ascii_strncasecmp(c, "<b>", 3) || !g_ascii_strncasecmp(c, "<bold>", strlen("<bold>"))) {
 					struct purple_parse_tag *pt = g_new0(struct purple_parse_tag, 1);
 					pt->src_tag = *(c+2) == '>' ? "b" : "bold";
@@ -1563,10 +1598,7 @@
 					pt->dest_tag = "span";
 					tags = g_list_prepend(tags, pt);
 					if(style->len)
-					{
-						if(xhtml)
-							g_string_append_printf(xhtml, "<span style='%s'>", g_strstrip(style->str));
-					}
+						g_string_append_printf(xhtml, "<span style='%s'>", g_strstrip(style->str));
 					else
 						pt->ignore = TRUE;
 					g_string_free(style, TRUE);
@@ -2692,6 +2724,33 @@
 	return "icon";
 }
 
+char *
+purple_util_get_image_filename(gconstpointer image_data, size_t image_len)
+{
+	PurpleCipherContext *context;
+	gchar digest[41];
+
+	context = purple_cipher_context_new_by_name("sha1", NULL);
+	if (context == NULL)
+	{
+		purple_debug_error("util", "Could not find sha1 cipher\n");
+		g_return_val_if_reached(NULL);
+	}
+
+	/* Hash the image data */
+	purple_cipher_context_append(context, image_data, image_len);
+	if (!purple_cipher_context_digest_to_str(context, sizeof(digest), digest, NULL))
+	{
+		purple_debug_error("util", "Failed to get SHA-1 digest.\n");
+		g_return_val_if_reached(NULL);
+	}
+	purple_cipher_context_destroy(context);
+
+	/* Return the filename */
+	return g_strdup_printf("%s.%s", digest,
+	                       purple_util_get_image_extension(image_data, image_len));
+}
+
 gboolean
 purple_program_is_valid(const char *program)
 {
--- a/libpurple/util.h	Mon Jun 04 23:48:54 2007 +0000
+++ b/libpurple/util.h	Tue Jun 05 01:38:09 2007 +0000
@@ -32,6 +32,7 @@
 
 #include "account.h"
 #include "xmlnode.h"
+#include "notify.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -623,6 +624,12 @@
 const char *
 purple_util_get_image_extension(gconstpointer data, size_t len);
 
+/**
+ * Returns a SHA-1 hash string of the data passed in with the correct file
+ * extention appended.
+ */
+char *purple_util_get_image_filename(gconstpointer image_data, size_t image_len);
+
 /*@}*/
 
 
--- a/pidgin/Makefile.mingw	Mon Jun 04 23:48:54 2007 +0000
+++ b/pidgin/Makefile.mingw	Tue Jun 05 01:38:09 2007 +0000
@@ -85,6 +85,7 @@
 			gtkscrollbook.c \
 			gtksound.c \
 			gtksourceiter.c \
+			gtksourceundomanager.c \
 			gtkstatusbox.c \
 			gtkthemes.c \
 			gtkutils.c \
--- a/pidgin/gtkaccount.c	Mon Jun 04 23:48:54 2007 +0000
+++ b/pidgin/gtkaccount.c	Tue Jun 05 01:38:09 2007 +0000
@@ -484,7 +484,11 @@
 		char *c;
 
 		if (dialog->account != NULL) {
-			c = strrchr(username,
+			if(purple_account_user_split_get_reverse(split))
+				c = strrchr(username,
+						purple_account_user_split_get_separator(split));
+			else
+				c = strchr(username,
 						purple_account_user_split_get_separator(split));
 
 			if (c != NULL) {
@@ -830,7 +834,7 @@
 				item = gtk_menu_get_active(GTK_MENU(menu));
 				if (str_value == NULL && g_object_get_data(G_OBJECT(item), "fake") &&
 					!strcmp(_("Connect server"),  purple_account_option_get_text(option)))
-					str_value = "talk.google.com";	
+					str_value = "talk.google.com";
 		
 				if (str_value != NULL)
 					gtk_entry_set_text(GTK_ENTRY(entry), str_value);
--- a/pidgin/gtkimhtml.c	Mon Jun 04 23:48:54 2007 +0000
+++ b/pidgin/gtkimhtml.c	Tue Jun 05 01:38:09 2007 +0000
@@ -144,6 +144,10 @@
 };
 static guint signals [LAST_SIGNAL] = { 0 };
 
+static char *html_clipboard = NULL;
+static char *text_clipboard = NULL;
+GtkClipboard *clipboard_selection = NULL;
+
 static GtkTargetEntry selection_targets[] = {
 #ifndef _WIN32
 	{ "text/html", 0, TARGET_HTML },
@@ -875,14 +879,17 @@
 
 static void gtk_imhtml_clipboard_get(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, GtkIMHtml *imhtml) {
 	char *text = NULL;
-	gboolean primary;
+	gboolean primary = (clipboard != clipboard_selection);
 	GtkTextIter start, end;
-	GtkTextMark *sel = gtk_text_buffer_get_selection_bound(imhtml->text_buffer);
-	GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
-
-	gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, sel);
-	gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &end, ins);
-	primary = gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY) == clipboard;
+	GtkTextMark *sel = NULL;
+	GtkTextMark *ins = NULL; 
+
+	if (primary) { 
+		ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
+		sel = gtk_text_buffer_get_selection_bound(imhtml->text_buffer);
+		gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, sel);
+		gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &end, ins);
+	}
 
 	if (info == TARGET_HTML) {
 		char *selection;
@@ -892,7 +899,7 @@
 		if (primary) {
 			text = gtk_imhtml_get_markup_range(imhtml, &start, &end);
 		} else
-			text = imhtml->clipboard_html_string;
+			text = html_clipboard;
 
 		/* Mozilla asks that we start our text/html with the Unicode byte order mark */
 		str = g_string_append_unichar(str, 0xfeff);
@@ -910,7 +917,7 @@
 		if (primary) {
 			text = gtk_imhtml_get_text(imhtml, &start, &end);
 		} else
-			text = imhtml->clipboard_text_string;
+			text = text_clipboard;
 		gtk_selection_data_set_text(selection_data, text, strlen(text));
 	}
 	if (primary) /* This was allocated here */
@@ -933,20 +940,32 @@
 					   &insert);
 }
 
+static void gtk_imhtml_clipboard_clear (GtkClipboard *clipboard, GtkSelectionData *sel_data,
+				 guint info, gpointer user_data_or_owner)
+{
+	clipboard_selection = NULL;
+}
+
 static void copy_clipboard_cb(GtkIMHtml *imhtml, gpointer unused)
 {
 	GtkTextIter start, end;
 	if (gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) {
-		gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD),
+		if (!clipboard_selection)
+			clipboard_selection = gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD);
+		gtk_clipboard_set_with_owner(clipboard_selection,
 						 selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry),
 						 (GtkClipboardGetFunc)gtk_imhtml_clipboard_get,
-						 (GtkClipboardClearFunc)NULL, G_OBJECT(imhtml));
+						 (GtkClipboardClearFunc)gtk_imhtml_clipboard_clear, G_OBJECT(imhtml));
 
 		g_free(imhtml->clipboard_html_string);
 		g_free(imhtml->clipboard_text_string);
 
 		imhtml->clipboard_html_string = gtk_imhtml_get_markup_range(imhtml, &start, &end);
 		imhtml->clipboard_text_string = gtk_imhtml_get_text(imhtml, &start, &end);
+
+		text_clipboard = imhtml->clipboard_text_string;
+		html_clipboard = imhtml->clipboard_html_string;
+	
 	}
 
 	g_signal_stop_emission_by_name(imhtml, "copy-clipboard");
@@ -956,10 +975,12 @@
 {
 	GtkTextIter start, end;
 	if (gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) {
-		gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD),
+		if (!clipboard_selection)
+			clipboard_selection = gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD);
+		gtk_clipboard_set_with_owner(clipboard_selection,
 						 selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry),
 						 (GtkClipboardGetFunc)gtk_imhtml_clipboard_get,
-						 (GtkClipboardClearFunc)NULL, G_OBJECT(imhtml));
+						 (GtkClipboardClearFunc)gtk_imhtml_clipboard_clear, G_OBJECT(imhtml));
 
 		g_free(imhtml->clipboard_html_string);
 		g_free(imhtml->clipboard_text_string);
@@ -967,6 +988,9 @@
 		imhtml->clipboard_html_string = gtk_imhtml_get_markup_range(imhtml, &start, &end);
 		imhtml->clipboard_text_string = gtk_imhtml_get_text(imhtml, &start, &end);
 
+		text_clipboard = imhtml->clipboard_text_string;
+		html_clipboard = imhtml->clipboard_html_string;
+
 		if (imhtml->editable)
 			gtk_text_buffer_delete_selection(imhtml->text_buffer, FALSE, FALSE);
 	}
@@ -1220,11 +1244,6 @@
 		g_free(img_data);
 	}
 
-	if (imhtml->clipboard_text_string) {
-		g_free(imhtml->clipboard_text_string);
-		g_free(imhtml->clipboard_html_string);
-	}
-
 	g_list_free(imhtml->scalables);
 	g_slist_free(imhtml->im_images);
 	g_queue_free(imhtml->animations);
@@ -1232,6 +1251,12 @@
 	g_free(imhtml->search_string);
 	g_object_unref(imhtml->undo_manager);
 	G_OBJECT_CLASS(parent_class)->finalize (object);
+	if (clipboard_selection)
+		gtk_clipboard_set_with_owner(clipboard_selection,
+        	                             selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry),
+                	                     (GtkClipboardGetFunc)gtk_imhtml_clipboard_get,
+                        	             (GtkClipboardClearFunc)NULL, G_OBJECT(imhtml));
+
 }
 
 /* Boring GTK+ stuff */
@@ -1344,9 +1369,9 @@
 	gtk_binding_entry_add_signal (binding_set, GDK_r, GDK_CONTROL_MASK, "format_function_clear", 0);
 	gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "message_send", 0);
 	gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "message_send", 0);
-	gtk_binding_entry_add_signal (binding_set, GDK_z, GDK_CONTROL_MASK, "undo", 0);
-	gtk_binding_entry_add_signal (binding_set, GDK_z, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "redo", 0);
-	gtk_binding_entry_add_signal (binding_set, GDK_F14, 0, "undo", 0);
+        gtk_binding_entry_add_signal (binding_set, GDK_z, GDK_CONTROL_MASK, "undo", 0);
+        gtk_binding_entry_add_signal (binding_set, GDK_z, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "redo", 0);
+        gtk_binding_entry_add_signal (binding_set, GDK_F14, 0, "undo", 0);
 
 }