diff -uNr -x .bzr -x debian devel/protocols/oscar/oscar.c branches/aim-icons/protocols/oscar/oscar.c
--- devel/protocols/oscar/oscar.c	2006-06-21 18:32:30.000000000 +0200
+++ branches/aim-icons/protocols/oscar/oscar.c	2006-06-24 21:43:47.000000000 +0200
@@ -1,6 +1,7 @@
 /*
  * gaim
  *
+ * Buddy icon hooks Copyright (C) 2006, Kozoru <http://www.kozoru.com/>
  * Some code copyright (C) 2002-2006, Jelmer Vernooij <jelmer@samba.org>
  *                                    and the BitlBee team.
  * Some code copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
@@ -29,6 +30,7 @@
 #include <stdio.h>
 #include <time.h>
 #include <sys/stat.h>
+#include <fcntl.h>
 #include <glib.h>
 #include "nogaim.h"
 #include "bitlbee.h"
@@ -45,9 +47,7 @@
 #include "chat.h"
 #include "chatnav.h"
 
-/* constants to identify proto_opts */
-#define USEROPT_AUTH      0
-#define USEROPT_AUTHPORT  1
+#include "http_client.h"
 
 #define UC_AOL		0x02
 #define UC_ADMIN	0x04
@@ -60,10 +60,13 @@
 
 #define OSCAR_GROUP "Friends"
 
+#define OSCAR_MAX_ICON_SIZE 7168
+
 /* Don't know if support for UTF8 is really working. For now it's UTF16 here.
    static int gaim_caps = AIM_CAPS_UTF8; */
 
-static int gaim_caps = AIM_CAPS_INTEROP | AIM_CAPS_ICHAT | AIM_CAPS_ICQSERVERRELAY | AIM_CAPS_CHAT;
+static int gaim_caps = AIM_CAPS_INTEROP | AIM_CAPS_ICHAT | AIM_CAPS_ICQSERVERRELAY |
+                       AIM_CAPS_CHAT | AIM_CAPS_BUDDYICON;
 static guint8 gaim_features[] = {0x01, 0x01, 0x01, 0x02};
 
 struct oscar_data {
@@ -90,6 +93,11 @@
 	gboolean killme;
 	gboolean icq;
 	GSList *evilhack;
+	
+	char *icon;
+	guint icon_size;
+	time_t icon_time;
+	guint16 icon_sum;
 
 	struct {
 		guint maxbuddies; /* max users you can watch */
@@ -355,10 +363,12 @@
 	return FALSE;
 }
 
+static void oscar_got_http_icon(struct http_request *req);
+
 static void oscar_login(struct aim_user *user) {
 	aim_session_t *sess;
 	aim_conn_t *conn;
-	char buf[256];
+	char buf[256], *server;
 	struct gaim_connection *gc = new_gaim_conn(user);
 	struct oscar_data *odata = gc->proto_data = g_new0(struct oscar_data, 1);
 
@@ -389,9 +399,15 @@
 		return;
 	}
 	
-	if (g_strcasecmp(user->proto_opt[USEROPT_AUTH], "login.icq.com") != 0 &&
-	    g_strcasecmp(user->proto_opt[USEROPT_AUTH], "login.oscar.aol.com") != 0) {
-		serv_got_crap(gc, "Warning: Unknown OSCAR server: `%s'. Please review your configuration if the connection fails.",user->proto_opt[USEROPT_AUTH]);
+	server = g_strdup(user->proto_opt[0]);
+	if ((odata->icon = strchr(server, ':'))) {
+		*odata->icon = 0;
+		odata->icon = g_strdup(odata->icon + 1);
+	}
+	
+	if (g_strcasecmp(server, "login.icq.com") != 0 &&
+	    g_strcasecmp(server, "login.oscar.aol.com") != 0) {
+		serv_got_crap(gc, "Warning: Unknown OSCAR server: `%s'. Please review your configuration if the connection fails.", server);
 	}
 	
 	g_snprintf(buf, sizeof(buf), _("Signon: %s"), gc->username);
@@ -401,17 +417,100 @@
 	aim_conn_addhandler(sess, conn, 0x0017, 0x0003, gaim_parse_auth_resp, 0);
 
 	conn->status |= AIM_CONN_STATUS_INPROGRESS;
-	conn->fd = proxy_connect(user->proto_opt[USEROPT_AUTH][0] ?
-					user->proto_opt[USEROPT_AUTH] : AIM_DEFAULT_LOGIN_SERVER,
-				 user->proto_opt[USEROPT_AUTHPORT][0] ?
-					atoi(user->proto_opt[USEROPT_AUTHPORT]) : AIM_LOGIN_PORT,
-				 oscar_login_connect, gc);
+	conn->fd = proxy_connect(server, AIM_LOGIN_PORT, oscar_login_connect, gc);
+	g_free(server);
 	if (conn->fd < 0) {
 		hide_login_progress(gc, _("Couldn't connect to host"));
 		signoff(gc);
 		return;
 	}
 	aim_request_login(sess, conn, gc->username);
+	
+	if (odata->icon) {
+		int fd = -1;
+		
+		if (odata->icon[0] == '/') {
+			struct stat sb;
+			
+			fd = open(odata->icon, O_RDONLY);
+			if (fd == -1)
+				goto icon_error;
+			
+			if (fstat(fd, &sb) == -1)
+				goto icon_error;
+			
+			if (sb.st_size > OSCAR_MAX_ICON_SIZE) {
+				serv_got_crap(gc, "Couldn't load usericon (%s)", "It's too big");
+				goto icon_error_silent;
+			}
+			
+			g_free(odata->icon);
+			odata->icon_time = sb.st_mtime;
+			odata->icon_size = sb.st_size;
+			odata->icon = g_malloc(odata->icon_size);
+			
+			if (read(fd, odata->icon, odata->icon_size) != odata->icon_size)
+				goto icon_error;
+			
+			odata->icon_sum = aim_iconsum((guint8*)odata->icon, odata->icon_size);
+			
+			serv_got_crap(gc, "Successfully loaded usericon (%d bytes)", odata->icon_size);
+			
+			close(fd);
+		} else {
+			if (!http_dorequest_url(odata->icon, oscar_got_http_icon, odata))
+				goto icon_error;
+		}
+		
+		return;
+		
+icon_error:
+		serv_got_crap(gc, "Couldn't load usericon (%s)", strerror(errno));
+icon_error_silent:
+		g_free(odata->icon);
+		odata->icon = NULL;
+		odata->icon_size = 0;
+		
+		if (fd != -1)
+			close(fd);
+	}
+	
+	/* DON'T PUT ANY CODE HERE! EVIL CONSTRUCTION INSIDE [tm] ;-) */
+}
+
+static void oscar_got_http_icon(struct http_request *req) {
+	struct oscar_data *od = req->data;
+	struct gaim_connection *gc;
+	GSList *l;
+	
+	for (l = get_connections(); l; l = l->next)
+		if (((struct gaim_connection*)l->data)->proto_data == od)
+			break;
+	
+	if (!l)
+		return;
+	
+	gc = l->data;
+	
+	if (req->status_code != 200) {
+		serv_got_crap(gc, "Couldn't load usericon (HTTP error %d)", req->status_code);
+		return;
+	}
+	
+	if (req->body_size > OSCAR_MAX_ICON_SIZE) {
+		serv_got_crap(gc, "Couldn't load usericon (%s)", "It's too big");
+		return;
+	}
+	
+	g_free(od->icon);
+	od->icon_time = time(NULL);
+	od->icon_size = req->body_size;
+	od->icon = g_malloc(od->icon_size);
+	memcpy(od->icon, req->reply_body, od->icon_size);
+	
+	od->icon_sum = aim_iconsum((guint8*)od->icon, od->icon_size);
+	
+	serv_got_crap(gc, "Successfully loaded usericon (%d bytes)", od->icon_size);
 }
 
 static void oscar_close(struct gaim_connection *gc) {
@@ -444,6 +543,7 @@
 		b_event_remove(odata->cnpa);
 	if (odata->paspa > 0)
 		b_event_remove(odata->paspa);
+	g_free(odata->icon);
 	aim_session_kill(odata->sess);
 	g_free(odata->sess);
 	odata->sess = NULL;
@@ -490,8 +590,7 @@
 	struct gaim_connection *gc = sess->aux_data;
         struct oscar_data *od = gc->proto_data;
 	user = gc->user;
-	port = user->proto_opt[USEROPT_AUTHPORT][0] ?
-		atoi(user->proto_opt[USEROPT_AUTHPORT]) : AIM_LOGIN_PORT,
+	port = AIM_LOGIN_PORT;
 
 	va_start(ap, fr);
 	info = va_arg(ap, struct aim_authresp_info *);
@@ -870,14 +969,12 @@
 	va_list ap;
 	struct aim_redirect_data *redir;
 	struct gaim_connection *gc = sess->aux_data;
-	struct aim_user *user = gc->user;
 	aim_conn_t *tstconn;
 	int i;
 	char *host;
 	int port;
 
-	port = user->proto_opt[USEROPT_AUTHPORT][0] ?
-		atoi(user->proto_opt[USEROPT_AUTHPORT]) : AIM_LOGIN_PORT,
+	port = AIM_LOGIN_PORT;
 
 	va_start(ap, fr);
 	redir = va_arg(ap, struct aim_redirect_data *);
@@ -1051,8 +1148,14 @@
 static int incomingim_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch1_args *args) {
 	char *tmp = g_malloc(BUF_LONG + 1);
 	struct gaim_connection *gc = sess->aux_data;
+	struct oscar_data *od = gc->proto_data;
 	int flags = 0;
 	
+	/* W000t, they want to see our icon! \o/ */
+	if (args->icbmflags & AIM_IMFLAGS_BUDDYREQ && od->icon_size > 0)
+		aim_send_icon(sess, userinfo->sn, (guint8*) od->icon, od->icon_size,
+		              od->icon_time, od->icon_sum);
+	
 	if (args->icbmflags & AIM_IMFLAGS_AWAY)
 		flags |= IM_FLAG_AWAY;
 	
@@ -1887,6 +1990,17 @@
 		args.msg    = s;
 		args.msglen = len;
 		
+		if (odata->icon_size > 0) {
+			/* Set this flag and give more information about the
+			   icon, the client can decide if it wants to see
+			   the icon or not. */
+			args.flags |= AIM_IMFLAGS_HASICON;
+			
+			args.iconlen = odata->icon_size;
+			args.iconsum = odata->icon_sum;
+			args.iconstamp = odata->icon_time;
+		}
+		
 		ret = aim_send_im_ext(odata->sess, &args);
 		
 		if (s != message) {
