changeset 2191:657dbe515608

[gaim-migrate @ 2201] genericize buddy icon stuff committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Wed, 29 Aug 2001 23:41:43 +0000
parents 24d947eff811
children f2a93c8f1be3
files src/buddy.c src/conversation.c src/gaim.h src/protocols/oscar/oscar.c src/prpl.c src/prpl.h
diffstat 6 files changed, 290 insertions(+), 324 deletions(-) [+]
line wrap: on
line diff
--- a/src/buddy.c	Wed Aug 29 23:38:38 2001 +0000
+++ b/src/buddy.c	Wed Aug 29 23:41:43 2001 +0000
@@ -486,6 +486,7 @@
 	system_log(log_signoff, gc, NULL, OPT_LOG_BUDDY_SIGNON | OPT_LOG_MY_SIGNON);
 	update_keepalive(gc, FALSE);
 	convo_menu_remove(gc);
+	remove_icon_data(gc);
 	serv_close(gc);
 	redo_buddy_list();
 	build_edit_tree();
--- a/src/conversation.c	Wed Aug 29 23:38:38 2001 +0000
+++ b/src/conversation.c	Wed Aug 29 23:41:43 2001 +0000
@@ -75,6 +75,9 @@
 void check_everything(GtkWidget *entry);
 gboolean keypress_callback(GtkWidget *entry, GdkEventKey * event, struct conversation *c);
 
+static void update_icon(struct conversation *);
+static void remove_icon(struct conversation *);
+
 /*------------------------------------------------------------------------*/
 /*  Helpers                                                               */
 /*------------------------------------------------------------------------*/
@@ -156,6 +159,7 @@
 	show_conv(c);
 	if (c->gc && c->gc->prpl && c->gc->prpl->insert_convo)
 		(*c->gc->prpl->insert_convo)(c->gc, c);
+	update_icon(c);
 	plugin_event(event_new_conversation, name, 0, 0, 0);
 	return c;
 }
@@ -411,6 +415,7 @@
 	if (!c->is_chat) {
 		if (c->gc && c->gc->prpl && c->gc->prpl->remove_convo)
 			(*c->gc->prpl->remove_convo)(c->gc, c);
+		remove_icon(c);
 		if (display_options & OPT_DISP_ONE_WINDOW) {
 			if (g_list_length(conversations) > 1) {
 				gtk_notebook_remove_page(GTK_NOTEBOOK(convo_notebook),
@@ -1785,6 +1790,7 @@
 
 	if (cnv->gc && cnv->gc->prpl && cnv->gc->prpl->insert_convo)
 		(*cnv->gc->prpl->insert_convo)(cnv->gc, cnv);
+	update_icon(cnv);
 }
 
 void update_convo_add_button(struct conversation *c)
@@ -1892,6 +1898,7 @@
 
 		if (C->gc && C->gc->prpl && C->gc->prpl->remove_convo)
 			(*C->gc->prpl->remove_convo)(C->gc, C);
+		remove_icon(C);
 	}
 }
 
@@ -1912,6 +1919,7 @@
 
 	if (c->gc && c->gc->prpl && c->gc->prpl->insert_convo)
 		(*c->gc->prpl->insert_convo)(c->gc, c);
+	update_icon(c);
 }
 
 void update_buttons_by_protocol(struct conversation *c)
@@ -2336,6 +2344,7 @@
 			win = c->window;
 			if (c->gc && c->gc->prpl->remove_convo)
 				(*c->gc->prpl->remove_convo)(c->gc, c);
+			remove_icon(c);
 			show_conv(c);
 			gtk_widget_destroy(c->text);
 			gtk_widget_reparent(imhtml, c->sw);
@@ -2343,6 +2352,7 @@
 			gtk_widget_destroy(win);
 			if (c->gc && c->gc->prpl->insert_convo)
 				(*c->gc->prpl->insert_convo)(c->gc, c);
+			update_icon(c);
 
 			x = x->next;
 		}
@@ -2357,12 +2367,14 @@
 			imhtml = c->text;
 			if (c->gc && c->gc->prpl->remove_convo)
 				(*c->gc->prpl->remove_convo)(c->gc, c);
+			remove_icon(c);
 			show_conv(c);
 			gtk_widget_destroy(c->text);
 			gtk_widget_reparent(imhtml, c->sw);
 			c->text = imhtml;
 			if (c->gc && c->gc->prpl->insert_convo)
 				(*c->gc->prpl->insert_convo)(c->gc, c);
+			update_icon(c);
 
 			x = x->next;
 		}
@@ -2461,3 +2473,181 @@
 		sprintf(b->fontface, "%s", fontface);
 	}
 }
+
+#if USE_PIXBUF
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gdk-pixbuf/gdk-pixbuf-loader.h>
+#define SCALE 48
+
+static gboolean redraw_icon(gpointer data)
+{
+	struct conversation *c = data;
+
+	GList *frames;
+	GdkPixbufFrame *frame;
+	GdkPixbuf *buf;
+	GdkPixbuf *scale;
+	GdkPixmap *src;
+	GdkPixmap *pm;
+	GdkBitmap *bm;
+	GdkGC *gc;
+	gint delay;
+
+	if (!g_list_find(conversations, c)) {
+		debug_printf("I think this is a bug.\n");
+		return FALSE;
+	}
+
+	frames = gdk_pixbuf_animation_get_frames(c->anim);
+	frame = g_list_nth_data(frames, c->frame);
+	switch (gdk_pixbuf_frame_get_action(frame)) {
+	case GDK_PIXBUF_FRAME_RETAIN:
+		buf = gdk_pixbuf_frame_get_pixbuf(frame);
+		scale = gdk_pixbuf_scale_simple(buf,
+				MAX(gdk_pixbuf_get_width(buf) * SCALE /
+					gdk_pixbuf_animation_get_width(c->anim), 1),
+				MAX(gdk_pixbuf_get_height(buf) * SCALE /
+					gdk_pixbuf_animation_get_height(c->anim), 1),
+				GDK_INTERP_NEAREST);
+		gdk_pixbuf_render_pixmap_and_mask(scale, &src, NULL, 0);
+		gdk_pixbuf_unref(scale);
+		gtk_pixmap_get(GTK_PIXMAP(c->icon), &pm, &bm);
+		gc = gdk_gc_new(pm);
+		gdk_draw_pixmap(pm, gc, src, 0, 0,
+				MAX(gdk_pixbuf_frame_get_x_offset(frame) * SCALE /
+					gdk_pixbuf_animation_get_width(c->anim), 1),
+				MAX(gdk_pixbuf_frame_get_y_offset(frame) * SCALE /
+					gdk_pixbuf_animation_get_height(c->anim), 1),
+				-1, -1);
+		gdk_pixmap_unref(src);
+		gtk_widget_queue_draw(c->icon);
+		gdk_gc_unref(gc);
+		break;
+	case GDK_PIXBUF_FRAME_DISPOSE:
+		buf = gdk_pixbuf_frame_get_pixbuf(frame);
+		scale = gdk_pixbuf_scale_simple(buf,
+				MAX(gdk_pixbuf_get_width(buf) * SCALE /
+					gdk_pixbuf_animation_get_width(c->anim), 1),
+				MAX(gdk_pixbuf_get_height(buf) * SCALE /
+					gdk_pixbuf_animation_get_height(c->anim), 1),
+				GDK_INTERP_NEAREST);
+		gdk_pixbuf_render_pixmap_and_mask(scale, &pm, &bm, 0);
+		gdk_pixbuf_unref(scale);
+		gtk_pixmap_set(GTK_PIXMAP(c->icon), pm, bm);
+		gdk_pixmap_unref(pm);
+		if (bm)
+			gdk_bitmap_unref(bm);
+		break;
+	case GDK_PIXBUF_FRAME_REVERT:
+		frame = frames->data;
+		buf = gdk_pixbuf_frame_get_pixbuf(frame);
+		scale = gdk_pixbuf_scale_simple(buf,
+				MAX(gdk_pixbuf_get_width(buf) * SCALE /
+					gdk_pixbuf_animation_get_width(c->anim), 1),
+				MAX(gdk_pixbuf_get_height(buf) * SCALE /
+					gdk_pixbuf_animation_get_height(c->anim), 1),
+				GDK_INTERP_NEAREST);
+		gdk_pixbuf_render_pixmap_and_mask(scale, &pm, &bm, 0);
+		gdk_pixbuf_unref(scale);
+		gtk_pixmap_set(GTK_PIXMAP(c->icon), pm, bm);
+		gdk_pixmap_unref(pm);
+		if (bm)
+			gdk_bitmap_unref(bm);
+		break;
+	}
+
+	c->frame = (c->frame + 1) % g_list_length(frames);
+	delay = MAX(gdk_pixbuf_frame_get_delay_time(frame), 13);
+	c->icon_timer = gtk_timeout_add(delay * 10, redraw_icon, c);
+
+	return FALSE;
+}
+#endif
+
+void remove_icon(struct conversation *c)
+{
+#if USE_PIXBUF
+	if (c->icon)
+		gtk_container_remove(GTK_CONTAINER(c->bbox), c->icon);
+	c->icon = NULL;
+	if (c->anim)
+		gdk_pixbuf_animation_unref(c->anim);
+	c->anim = NULL;
+	if (c->unanim)
+		gdk_pixbuf_unref(c->unanim);
+	c->unanim = NULL;
+	if (c->icon_timer)
+		gtk_timeout_remove(c->icon_timer);
+	c->icon_timer = 0;
+	c->frame = 0;
+#endif
+}
+
+void update_icon(struct conversation *c)
+{
+#if USE_PIXBUF
+	void *data;
+	int len;
+
+	GdkPixbufLoader *load;
+	GdkPixbuf *scale;
+	GdkPixmap *pm;
+	GdkBitmap *bm;
+
+	if (!c)
+		return;
+
+	if (!c->gc)
+		return;
+	data = get_icon_data(c->gc, normalize(c->name), &len);
+	if (!data)
+		return;
+
+	load = gdk_pixbuf_loader_new();
+	gdk_pixbuf_loader_write(load, data, len);
+	c->anim = gdk_pixbuf_loader_get_animation(load);
+
+	if (c->anim) {
+		GList *frames = gdk_pixbuf_animation_get_frames(c->anim);
+		GdkPixbuf *buf = gdk_pixbuf_frame_get_pixbuf(frames->data);
+		scale = gdk_pixbuf_scale_simple(buf,
+				MAX(gdk_pixbuf_get_width(buf) * SCALE /
+					gdk_pixbuf_animation_get_width(c->anim), 1),
+				MAX(gdk_pixbuf_get_height(buf) * SCALE /
+					gdk_pixbuf_animation_get_height(c->anim), 1),
+				GDK_INTERP_NEAREST);
+
+		if (gdk_pixbuf_animation_get_num_frames(c->anim) > 1) {
+			int delay = MAX(gdk_pixbuf_frame_get_delay_time(frames->data), 13);
+			c->frame = 1;
+			c->icon_timer = gtk_timeout_add(delay * 10, redraw_icon, c);
+		}
+	} else {
+		c->unanim = gdk_pixbuf_loader_get_pixbuf(load);
+		if (!c->unanim) {
+			gdk_pixbuf_loader_close(load);
+			return;
+		}
+		scale = gdk_pixbuf_scale_simple(c->unanim, SCALE, SCALE, GDK_INTERP_NEAREST);
+	}
+
+	gdk_pixbuf_render_pixmap_and_mask(scale, &pm, &bm, 0);
+	gdk_pixbuf_unref(scale);
+
+	c->icon = gtk_pixmap_new(pm, bm);
+	gtk_box_pack_start(GTK_BOX(c->bbox), c->icon, FALSE, FALSE, 5);
+	gtk_widget_show(c->icon);
+	gdk_pixmap_unref(pm);
+	if (bm)
+		gdk_bitmap_unref(bm);
+
+	gdk_pixbuf_loader_close(load);
+#endif
+}
+
+void got_new_icon(struct gaim_connection *gc, char *who)
+{
+	struct conversation *c = find_conversation(who);
+	if (c->gc == gc)
+		update_icon(c);
+}
--- a/src/gaim.h	Wed Aug 29 23:38:38 2001 +0000
+++ b/src/gaim.h	Wed Aug 29 23:41:43 2001 +0000
@@ -322,6 +322,10 @@
 	GtkWidget *entry;
 };
 
+#if USE_PIXBUF
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#endif
+
 /* struct buddy_chat went away and got merged with this. */
 struct conversation {
 	struct gaim_connection *gc;
@@ -375,6 +379,15 @@
 	GtkWidget *menu;
 	gboolean unseen;
 
+#if USE_PIXBUF
+	/* buddy icon stuff. sigh. */
+	GtkWidget *icon;
+	GdkPixbuf *unanim;
+	GdkPixbufAnimation *anim;
+	guint32 icon_timer;
+	int frame;
+#endif
+
 	/* stuff used just for chat */
         GList *in_room;
         GList *ignored;
@@ -721,6 +734,8 @@
 extern void set_font_face(char *, struct conversation *);
 extern void redo_convo_menus();
 extern void convo_menu_remove(struct gaim_connection *);
+extern void remove_icon_data(struct gaim_connection *);
+extern void got_new_icon(struct gaim_connection *, char *);
 extern void toggle_spellchk();
 extern void set_convo_gc(struct conversation *, struct gaim_connection *);
 extern void update_buttons_by_protocol(struct conversation *);
--- a/src/protocols/oscar/oscar.c	Wed Aug 29 23:38:38 2001 +0000
+++ b/src/protocols/oscar/oscar.c	Wed Aug 29 23:41:43 2001 +0000
@@ -26,7 +26,6 @@
 
 
 #include <netdb.h>
-#include <gtk/gtk.h>
 #include <unistd.h>
 #include <errno.h>
 #include <netinet/in.h>
@@ -43,12 +42,6 @@
 #include "aim.h"
 #include "proxy.h"
 
-#if USE_PIXBUF
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <gdk-pixbuf/gdk-pixbuf-loader.h>
-#define SCALE 48
-#endif
-
 /*#include "pixmaps/cancel.xpm"*/
 #include "pixmaps/admin_icon.xpm"
 #include "pixmaps/aol_icon.xpm"
@@ -122,21 +115,12 @@
 	struct aim_directim_priv *priv;
 };
 
-#if USE_PIXBUF
 struct icon_req {
 	char *user;
 	time_t timestamp;
-	unsigned long length;
-	gpointer data;
+	unsigned long checksum;
 	gboolean request;
-	GdkPixbufAnimation *anim;
-	GdkPixbuf *unanim;
-	struct conversation *cnv;
-	GtkWidget *pix;
-	int curframe;
-	int timer;
 };
-#endif
 
 static struct direct_im *find_direct_im(struct oscar_data *od, char *who) {
 	GSList *d = od->direct_ims;
@@ -477,17 +461,7 @@
 #if USE_PIXBUF
 	while (odata->hasicons) {
 		struct icon_req *n = odata->hasicons->data;
-		if (n->anim)
-			gdk_pixbuf_animation_unref(n->anim);
-		if (n->unanim)
-			gdk_pixbuf_unref(n->unanim);
-		if (n->timer)
-			g_source_remove(n->timer);
-		if (n->cnv && n->pix)
-			gtk_container_remove(GTK_CONTAINER(n->cnv->bbox), n->pix);
 		g_free(n->user);
-		if (n->data)
-			g_free(n->data);
 		odata->hasicons = g_slist_remove(odata->hasicons, n);
 		g_free(n);
 	}
@@ -1266,88 +1240,6 @@
 	return TRUE;
 }
 
-#if USE_PIXBUF
-static gboolean redraw_anim(gpointer data)
-{
-	int delay;
-	struct icon_req *ir = data;
-	GList *frames;
-	GdkPixbufFrame *frame;
-	GdkPixbuf *buf;
-	GdkPixbuf *scale;
-	GdkPixmap *pm; GdkBitmap *bm;
-	GdkPixmap *src;
-	GdkGC *gc;
-
-	if (!ir->cnv || !g_list_find(conversations, ir->cnv)) {
-		debug_printf("I think this is a bug.\n");
-		return FALSE;
-	}
-
-	frames = gdk_pixbuf_animation_get_frames(ir->anim);
-	frame = g_list_nth_data(frames, ir->curframe);
-	switch (gdk_pixbuf_frame_get_action(frame)) {
-		case GDK_PIXBUF_FRAME_RETAIN:
-			buf = gdk_pixbuf_frame_get_pixbuf(frame);
-			scale = gdk_pixbuf_scale_simple(buf,
-					MAX(gdk_pixbuf_get_width(buf) * SCALE /
-						gdk_pixbuf_animation_get_width(ir->anim), 1),
-					MAX(gdk_pixbuf_get_height(buf) * SCALE /
-						gdk_pixbuf_animation_get_height(ir->anim), 1),
-					GDK_INTERP_NEAREST);
-			gdk_pixbuf_render_pixmap_and_mask(scale, &src, NULL, 0);
-			gdk_pixbuf_unref(scale);
-			gtk_pixmap_get(GTK_PIXMAP(ir->pix), &pm, &bm);
-			gc = gdk_gc_new(pm);
-			gdk_draw_pixmap(pm, gc, src, 0, 0,
-					MAX(gdk_pixbuf_frame_get_x_offset(frame) * SCALE /
-						gdk_pixbuf_animation_get_width(ir->anim), 1),
-					MAX(gdk_pixbuf_frame_get_y_offset(frame) * SCALE /
-						gdk_pixbuf_animation_get_height(ir->anim), 1),
-					-1, -1);
-			gdk_pixmap_unref(src);
-			gtk_widget_queue_draw(ir->pix);
-			gdk_gc_unref(gc);
-			break;
-		case GDK_PIXBUF_FRAME_DISPOSE:
-			buf = gdk_pixbuf_frame_get_pixbuf(frame);
-			scale = gdk_pixbuf_scale_simple(buf,
-					MAX(gdk_pixbuf_get_width(buf) * SCALE /
-						gdk_pixbuf_animation_get_width(ir->anim), 1),
-					MAX(gdk_pixbuf_get_height(buf) * SCALE /
-						gdk_pixbuf_animation_get_height(ir->anim), 1),
-					GDK_INTERP_NEAREST);
-			gdk_pixbuf_render_pixmap_and_mask(scale, &pm, &bm, 0);
-			gdk_pixbuf_unref(scale);
-			gtk_pixmap_set(GTK_PIXMAP(ir->pix), pm, bm);
-			gdk_pixmap_unref(pm);
-			if (bm)
-				gdk_bitmap_unref(bm);
-			break;
-		case GDK_PIXBUF_FRAME_REVERT:
-			frame = frames->data;
-			buf = gdk_pixbuf_frame_get_pixbuf(frame);
-			scale = gdk_pixbuf_scale_simple(buf,
-					MAX(gdk_pixbuf_get_width(buf) * SCALE /
-						gdk_pixbuf_animation_get_width(ir->anim), 1),
-					MAX(gdk_pixbuf_get_height(buf) * SCALE /
-						gdk_pixbuf_animation_get_height(ir->anim), 1),
-					GDK_INTERP_NEAREST);
-			gdk_pixbuf_render_pixmap_and_mask(scale, &pm, &bm, 0);
-			gdk_pixbuf_unref(scale);
-			gtk_pixmap_set(GTK_PIXMAP(ir->pix), pm, bm);
-			gdk_pixmap_unref(pm);
-			if (bm)
-				gdk_bitmap_unref(bm);
-			break;
-	}
-	ir->curframe = (ir->curframe + 1) % g_list_length(frames);
-	delay = MAX(gdk_pixbuf_frame_get_delay_time(frame), 13);
-	ir->timer = g_timeout_add(delay * 10, redraw_anim, ir);
-	return FALSE;
-}
-#endif
-
 int gaim_parse_incoming_im(struct aim_session_t *sess,
 			   struct command_rx_struct *command, ...) {
 	int channel;
@@ -1367,7 +1259,6 @@
 		args = va_arg(ap, struct aim_incomingim_ch1_args *);
 		va_end(ap);
 
-#if USE_PIXBUF
 		if (args->icbmflags & AIM_IMFLAGS_HASICON) {
 			struct oscar_data *od = gc->proto_data;
 			struct icon_req *ir = NULL;
@@ -1389,7 +1280,6 @@
 				ir->request = TRUE;
 			ir->timestamp = args->iconstamp;
 		}
-#endif
 
 		/*
 		 * Quickly convert it to eight bit format, replacing 
@@ -1434,105 +1324,8 @@
 		} else if (args->reqclass & AIM_CAPS_GETFILE) {
 		} else if (args->reqclass & AIM_CAPS_VOICE) {
 		} else if (args->reqclass & AIM_CAPS_BUDDYICON) {
-#if USE_PIXBUF
-			struct oscar_data *od = gc->proto_data;
-			GSList *h = od->hasicons;
-			struct icon_req *ir = NULL;
-			char *who;
-			struct conversation *c;
-
-			GdkPixbufLoader *load;
-			GList *frames;
-			GdkPixbuf *buf;
-			GdkPixbuf *scale;
-			GdkPixmap *pm;
-			GdkBitmap *bm;
-
-			who = normalize(userinfo->sn);
-
-			while (h) {
-				ir = h->data;
-				if (!strcmp(who, ir->user))
-					break;
-				h = h->next;
-
-			}
-
-			if (!h || ((c = find_conversation(userinfo->sn)) == NULL) || (c->gc != gc)) {
-				debug_printf("got buddy icon for %s but didn't want it\n", userinfo->sn);
-				return 1;
-			}
-
-			if (ir->pix && ir->cnv)
-				gtk_container_remove(GTK_CONTAINER(ir->cnv->bbox), ir->pix);
-			ir->pix = NULL;
-			ir->cnv = NULL;
-			if (ir->data)
-				g_free(ir->data);
-			if (ir->anim)
-				gdk_pixbuf_animation_unref(ir->anim);
-			ir->anim = NULL;
-			if (ir->unanim)
-				gdk_pixbuf_unref(ir->unanim);
-			ir->unanim = NULL;
-			if (ir->timer)
-				g_source_remove(ir->timer);
-			ir->timer = 0;
-
-			ir->length = args->info.icon.length;
-
-			if (!ir->length)
-				return 1;
-
-			ir->data = g_memdup(args->info.icon.icon, args->info.icon.length);
-
-			load = gdk_pixbuf_loader_new();
-			gdk_pixbuf_loader_write(load, ir->data, ir->length);
-			ir->anim = gdk_pixbuf_loader_get_animation(load);
-
-			if (ir->anim) {
-				frames = gdk_pixbuf_animation_get_frames(ir->anim);
-				buf = gdk_pixbuf_frame_get_pixbuf(frames->data);
-				scale = gdk_pixbuf_scale_simple(buf,
-						MAX(gdk_pixbuf_get_width(buf) * SCALE /
-							gdk_pixbuf_animation_get_width(ir->anim), 1),
-						MAX(gdk_pixbuf_get_height(buf) * SCALE /
-							gdk_pixbuf_animation_get_height(ir->anim), 1),
-						GDK_INTERP_NEAREST);
-				gdk_pixbuf_render_pixmap_and_mask(scale, &pm, &bm, 0);
-				gdk_pixbuf_unref(scale);
-
-				if (gdk_pixbuf_animation_get_num_frames(ir->anim) > 1) {
-					int delay =
-						MAX(gdk_pixbuf_frame_get_delay_time(frames->data), 13);
-					ir->curframe = 1;
-					ir->timer = g_timeout_add(delay * 10, redraw_anim, ir);
-				}
-			} else {
-				ir->unanim = gdk_pixbuf_loader_get_pixbuf(load);
-				if (!ir->unanim) {
-					gdk_pixbuf_loader_close(load);
-					return 1;
-				}
-				scale = gdk_pixbuf_scale_simple(ir->unanim, SCALE, SCALE,
-						GDK_INTERP_NEAREST);
-				gdk_pixbuf_render_pixmap_and_mask(scale, &pm, &bm, 0);
-				gdk_pixbuf_unref(scale);
-			}
-
-			ir->cnv = c;
-			ir->pix = gtk_pixmap_new(pm, bm);
-			gtk_box_pack_start(GTK_BOX(c->bbox), ir->pix, FALSE, FALSE, 5);
-			if (ir->anim && (gdk_pixbuf_animation_get_num_frames(ir->anim) > 1))
-				gtk_widget_set_usize(ir->pix, SCALE, SCALE);
-			gtk_widget_show(ir->pix);
-			gdk_pixmap_unref(pm);
-			if (bm)
-				gdk_bitmap_unref(bm);
-
-			gdk_pixbuf_loader_close(load);
-
-#endif
+			set_icon_data(gc, normalize(userinfo->sn), args->info.icon.icon,
+					args->info.icon.length);
 		} else if (args->reqclass & AIM_CAPS_IMIMAGE) {
 			struct ask_direct *d = g_new0(struct ask_direct, 1);
 			char buf[256];
@@ -2885,118 +2678,6 @@
 	}
 }
 
-static void oscar_insert_convo(struct gaim_connection *gc, struct conversation *c)
-{
-#if USE_PIXBUF
-	struct oscar_data *od = gc->proto_data;
-	GSList *h = od->hasicons;
-	struct icon_req *ir = NULL;
-	char *who = normalize(c->name);
-
-	GdkPixbufLoader *load;
-	GList *frames;
-	GdkPixbuf *buf;
-	GdkPixbuf *scale;
-	GdkPixmap *pm;
-	GdkBitmap *bm;
-
-	while (h) {
-		ir = h->data;
-		if (!strcmp(who, ir->user))
-			break;
-		h = h->next;
-	}
-	if (!h || !ir->data)
-		return;
-
-	ir->cnv = c;
-
-	load = gdk_pixbuf_loader_new();
-	gdk_pixbuf_loader_write(load, ir->data, ir->length);
-	ir->anim = gdk_pixbuf_loader_get_animation(load);
-
-	if (ir->anim) {
-		frames = gdk_pixbuf_animation_get_frames(ir->anim);
-		buf = gdk_pixbuf_frame_get_pixbuf(frames->data);
-		scale = gdk_pixbuf_scale_simple(buf,
-				MAX(gdk_pixbuf_get_width(buf) * SCALE /
-					gdk_pixbuf_animation_get_width(ir->anim), 1),
-				MAX(gdk_pixbuf_get_height(buf) * SCALE /
-					gdk_pixbuf_animation_get_height(ir->anim), 1),
-				GDK_INTERP_NEAREST);
-		gdk_pixbuf_render_pixmap_and_mask(scale, &pm, &bm, 0);
-		gdk_pixbuf_unref(scale);
-
-		if (gdk_pixbuf_animation_get_num_frames(ir->anim) > 1) {
-			int delay = MAX(gdk_pixbuf_frame_get_delay_time(frames->data), 13);
-			ir->curframe = 1;
-			ir->timer = g_timeout_add(delay * 10, redraw_anim, ir);
-		}
-	} else {
-		ir->unanim = gdk_pixbuf_loader_get_pixbuf(load);
-		if (!ir->unanim) {
-			gdk_pixbuf_loader_close(load);
-			return;
-		}
-		scale = gdk_pixbuf_scale_simple(ir->unanim, SCALE, SCALE,
-				GDK_INTERP_NEAREST);
-		gdk_pixbuf_render_pixmap_and_mask(scale, &pm, &bm, 0);
-		gdk_pixbuf_unref(scale);
-	}
-
-	ir->pix = gtk_pixmap_new(pm, bm);
-	gtk_box_pack_start(GTK_BOX(c->bbox), ir->pix, FALSE, FALSE, 5);
-	if (ir->anim && (gdk_pixbuf_animation_get_num_frames(ir->anim) > 1))
-		gtk_widget_set_usize(ir->pix, gdk_pixbuf_animation_get_width(ir->anim),
-					gdk_pixbuf_animation_get_height(ir->anim));
-	gtk_widget_show(ir->pix);
-	gdk_pixmap_unref(pm);
-	if (bm)
-		gdk_bitmap_unref(bm);
-
-	gdk_pixbuf_loader_close(load);
-#endif
-}
-
-static void oscar_remove_convo(struct gaim_connection *gc, struct conversation *c)
-{
-#if USE_PIXBUF
-	struct oscar_data *od = gc->proto_data;
-	GSList *h = od->hasicons;
-	struct icon_req *ir = NULL;
-	char *who = normalize(c->name);
-	
-	while (h) {
-		ir = h->data;
-		if (!strcmp(who, ir->user))
-			break;
-		h = h->next;
-	}
-	if (!h || !ir->data)
-		return;
-	
-	if (ir->cnv && ir->pix) {
-		gtk_container_remove(GTK_CONTAINER(ir->cnv->bbox), ir->pix);
-		ir->pix = NULL;
-		ir->cnv = NULL;
-	}
-	
-	if (ir->anim) {
-		gdk_pixbuf_animation_unref(ir->anim);
-		ir->anim = NULL;
-	} else if (ir->unanim) {
-		gdk_pixbuf_unref(ir->unanim);
-		ir->unanim = NULL;
-	}
-	
-	ir->curframe = 0;
-	
-	if (ir->timer)
-		g_source_remove(ir->timer);
-	ir->timer = 0;
-#endif
-}
-
 static struct prpl *my_protocol = NULL;
 
 void oscar_init(struct prpl *ret) {
@@ -3011,8 +2692,6 @@
 	ret->user_opts = oscar_user_opts;
 	ret->draw_new_user = oscar_draw_new_user;
 	ret->do_new_user = oscar_do_new_user;
-	ret->insert_convo = oscar_insert_convo;
-	ret->remove_convo = oscar_remove_convo;
 	ret->login = oscar_login;
 	ret->close = oscar_close;
 	ret->send_im = oscar_send_im;
--- a/src/prpl.c	Wed Aug 29 23:38:38 2001 +0000
+++ b/src/prpl.c	Wed Aug 29 23:41:43 2001 +0000
@@ -549,3 +549,81 @@
 	} else if (gc->email_win)
 		gtk_widget_destroy(gc->email_win);
 }
+
+struct icon_data {
+	struct gaim_connection *gc;
+	char *who;
+	void *data;
+	int len;
+};
+
+static GList *icons = NULL;
+
+static gint find_icon_data(gconstpointer a, gconstpointer b)
+{
+	const struct icon_data *x = a;
+	const struct icon_data *y = b;
+
+	return ((x->gc != y->gc) || g_strcasecmp(x->who, y->who));
+}
+
+void set_icon_data(struct gaim_connection *gc, char *who, void *data, int len)
+{
+	struct icon_data tmp = { gc, who, NULL, 0 };
+	GList *l = g_list_find_custom(icons, &tmp, find_icon_data);
+	struct icon_data *id = l ? l->data : NULL;
+
+	if (id) {
+		g_free(id->data);
+		if (!data) {
+			icons = g_list_remove(icons, id);
+			g_free(id->who);
+			g_free(id);
+			return;
+		}
+	} else if (data) {
+		id = g_new0(struct icon_data, 1);
+		icons = g_list_append(icons, id);
+		id->gc = gc;
+		id->who = g_strdup(who);
+	} else {
+		return;
+	}
+
+	id->data = g_memdup(data, len);
+	id->len = len;
+
+	got_new_icon(gc, who);
+}
+
+void remove_icon_data(struct gaim_connection *gc)
+{
+	GList *list = icons;
+	struct icon_data *id;
+
+	while (list) {
+		id = list->data;
+		if (id->gc == gc) {
+			g_free(id->data);
+			g_free(id->who);
+			list = icons = g_list_remove(icons, id);
+			g_free(id);
+		} else
+			list = list->next;
+	}
+}
+
+void *get_icon_data(struct gaim_connection *gc, char *who, int *len)
+{
+	struct icon_data tmp = { gc, who, NULL, 0 };
+	GList *l = g_list_find_custom(icons, &tmp, find_icon_data);
+	struct icon_data *id = l ? l->data : NULL;
+
+	if (id) {
+		*len = id->len;
+		return id->data;
+	}
+
+	*len = 0;
+	return NULL;
+}
--- a/src/prpl.h	Wed Aug 29 23:38:38 2001 +0000
+++ b/src/prpl.h	Wed Aug 29 23:41:43 2001 +0000
@@ -162,4 +162,7 @@
 
 extern void connection_has_mail(struct gaim_connection *, int, const char *, const char *);
 
+extern void set_icon_data(struct gaim_connection *, char *, void *, int);
+extern void *get_icon_data(struct gaim_connection *, char *, int *);
+
 #endif