changeset 4804:9810ce8e7a96

[gaim-migrate @ 5124] Here ya go, Rob. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Mon, 17 Mar 2003 04:02:30 +0000
parents 6f04901ef729
children a7e99eb2c0f2
files src/protocols/oscar/Makefile.am src/protocols/oscar/Makefile.mingw src/protocols/oscar/aim.h src/protocols/oscar/aim_cbtypes.h src/protocols/oscar/aim_internal.h src/protocols/oscar/conn.c src/protocols/oscar/email.c src/protocols/oscar/info.c src/protocols/oscar/oscar.c
diffstat 9 files changed, 227 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/protocols/oscar/Makefile.am	Mon Mar 17 01:57:37 2003 +0000
+++ b/src/protocols/oscar/Makefile.am	Mon Mar 17 04:02:30 2003 +0000
@@ -18,6 +18,7 @@
 	email.c        \
 	faimconfig.h   \
 	ft.c           \
+	icon.c         \
 	icq.c          \
 	im.c           \
 	info.c         \
--- a/src/protocols/oscar/Makefile.mingw	Mon Mar 17 01:57:37 2003 +0000
+++ b/src/protocols/oscar/Makefile.mingw	Mon Mar 17 04:02:30 2003 +0000
@@ -78,6 +78,7 @@
 			conn.c		\
 			email.c		\
 			ft.c		\
+			icon.c		\
 			icq.c		\
 			im.c		\
 			info.c		\
--- a/src/protocols/oscar/aim.h	Mon Mar 17 01:57:37 2003 +0000
+++ b/src/protocols/oscar/aim.h	Mon Mar 17 04:02:30 2003 +0000
@@ -258,6 +258,7 @@
 #define AIM_CONN_TYPE_CHATNAV		0x000d
 #define AIM_CONN_TYPE_CHAT		0x000e
 #define AIM_CONN_TYPE_SEARCH		0x000f
+#define AIM_CONN_TYPE_ICON		0x0010
 #define AIM_CONN_TYPE_EMAIL		0x0018
 
 /* they start getting arbitrary for rendezvous stuff =) */
@@ -476,6 +477,8 @@
 		fu8_t crap[0x25]; /* until we figure it out... */
 	} icqinfo;
 	fu32_t present;
+	fu16_t iconstrlen;
+	fu8_t iconstr[30];
 } aim_userinfo_t;
 
 #define AIM_USERINFO_PRESENT_FLAGS        0x00000001
@@ -1118,6 +1121,12 @@
 faim_export int aim_usersearch_interest(aim_session_t *, const char *, const char *);
 
 
+
+/* icon.c */
+faim_export int aim_icon_requesticon(aim_session_t *sess, const char *sn, const fu8_t *iconstr, fu16_t iconstrlen);
+
+
+
 /* These apply to exchanges as well. */
 #define AIM_CHATROOM_FLAG_EVILABLE 0x0001
 #define AIM_CHATROOM_FLAG_NAV_ONLY 0x0002
--- a/src/protocols/oscar/aim_cbtypes.h	Mon Mar 17 01:57:37 2003 +0000
+++ b/src/protocols/oscar/aim_cbtypes.h	Mon Mar 17 04:02:30 2003 +0000
@@ -179,14 +179,19 @@
 
 /*
  * SNAC Family: "New" Search
- *
- * Most of these are actually special.
  */ 
 #define AIM_CB_SCH_ERROR 0x0001
 #define AIM_CB_SCH_SEARCH 0x0002
 #define AIM_CB_SCH_RESULTS 0x0003
 
 /*
+ * SNAC Family: Buddy icons
+ */ 
+#define AIM_CB_ICO_ERROR 0x0001
+#define AIM_CB_ICO_REQUEST 0x0004
+#define AIM_CB_ICO_RESPONSE 0x0005
+
+/*
  * SNAC Family: ICQ
  *
  * Most of these are actually special.
--- a/src/protocols/oscar/aim_internal.h	Mon Mar 17 01:57:37 2003 +0000
+++ b/src/protocols/oscar/aim_internal.h	Mon Mar 17 04:02:30 2003 +0000
@@ -35,8 +35,8 @@
 faim_internal aim_module_t *aim__findmodulebygroup(aim_session_t *sess, fu16_t group);
 faim_internal aim_module_t *aim__findmodule(aim_session_t *sess, const char *name);
 
+faim_internal int admin_modfirst(aim_session_t *sess, aim_module_t *mod);
 faim_internal int buddylist_modfirst(aim_session_t *sess, aim_module_t *mod);
-faim_internal int admin_modfirst(aim_session_t *sess, aim_module_t *mod);
 faim_internal int bos_modfirst(aim_session_t *sess, aim_module_t *mod);
 faim_internal int search_modfirst(aim_session_t *sess, aim_module_t *mod);
 faim_internal int stats_modfirst(aim_session_t *sess, aim_module_t *mod);
@@ -47,14 +47,15 @@
 faim_internal int chat_modfirst(aim_session_t *sess, aim_module_t *mod);
 faim_internal int locate_modfirst(aim_session_t *sess, aim_module_t *mod);
 faim_internal int general_modfirst(aim_session_t *sess, aim_module_t *mod);
-faim_internal int ssi_modfirst(aim_session_t *sess, aim_module_t *mod);
 faim_internal int invite_modfirst(aim_session_t *sess, aim_module_t *mod);
 faim_internal int translate_modfirst(aim_session_t *sess, aim_module_t *mod);
 faim_internal int popups_modfirst(aim_session_t *sess, aim_module_t *mod);
 faim_internal int adverts_modfirst(aim_session_t *sess, aim_module_t *mod);
+faim_internal int newsearch_modfirst(aim_session_t *sess, aim_module_t *mod);
+faim_internal int icon_modfirst(aim_session_t *sess, aim_module_t *mod);
+faim_internal int ssi_modfirst(aim_session_t *sess, aim_module_t *mod);
 faim_internal int icq_modfirst(aim_session_t *sess, aim_module_t *mod);
 faim_internal int email_modfirst(aim_session_t *sess, aim_module_t *mod);
-faim_internal int newsearch_modfirst(aim_session_t *sess, aim_module_t *mod);
 
 faim_internal int aim_genericreq_n(aim_session_t *, aim_conn_t *conn, fu16_t family, fu16_t subtype);
 faim_internal int aim_genericreq_n_snacid(aim_session_t *, aim_conn_t *conn, fu16_t family, fu16_t subtype);
--- a/src/protocols/oscar/conn.c	Mon Mar 17 01:57:37 2003 +0000
+++ b/src/protocols/oscar/conn.c	Mon Mar 17 04:02:30 2003 +0000
@@ -919,7 +919,8 @@
 	aim__registermodule(sess, chatnav_modfirst);
 	aim__registermodule(sess, chat_modfirst);
 	aim__registermodule(sess, newsearch_modfirst);
-	/* missing 0x10 - 0x12 */
+	aim__registermodule(sess, icon_modfirst);
+	/* missing 0x11 - 0x12 */
 	aim__registermodule(sess, ssi_modfirst);
 	/* missing 0x14 */
 	aim__registermodule(sess, icq_modfirst); /* XXX - Make sure this isn't sent for AIM */
--- a/src/protocols/oscar/email.c	Mon Mar 17 01:57:37 2003 +0000
+++ b/src/protocols/oscar/email.c	Mon Mar 17 04:02:30 2003 +0000
@@ -62,6 +62,7 @@
 
 /**
  * Subtype 0x0007 - Receive information about your email account
+ *
  * So I don't even know if you can have multiple 16 byte keys, 
  * but this is coded so it will handle that, and handle it well.
  * This tells you if you have unread mail or not, the URL you 
--- a/src/protocols/oscar/info.c	Mon Mar 17 01:57:37 2003 +0000
+++ b/src/protocols/oscar/info.c	Mon Mar 17 04:02:30 2003 +0000
@@ -618,10 +618,22 @@
 
 		} else if (type == 0x001d) {
 			/*
-			 * Type 29: Unknown.
+			 * Type = 0x001d
 			 *
-			 * Currently very rare. Always 18 bytes of mostly zero.
+			 * Buddy icon information.  This contains the info 
+			 * about the buddy icon that the user has stored on 
+			 * the server.
 			 */
+			char *iconstr;
+			outinfo->iconstrlen = length-4;
+			outinfo->iconstrlen -= aim_bstream_advance(bs, aimbs_get16(bs));
+			outinfo->iconstrlen -= aim_bstream_advance(bs, aimbs_get16(bs));
+			if (aim_bstream_empty(bs) >= outinfo->iconstrlen) {
+				iconstr = aimbs_getraw(bs, outinfo->iconstrlen);
+				memcpy(outinfo->iconstr, iconstr, outinfo->iconstrlen);
+			} else
+				outinfo->iconstrlen = 0;
+			free(iconstr);
 
 		} else if (type == 0x001e) {
 			/*
--- a/src/protocols/oscar/oscar.c	Mon Mar 17 01:57:37 2003 +0000
+++ b/src/protocols/oscar/oscar.c	Mon Mar 17 04:02:30 2003 +0000
@@ -87,6 +87,7 @@
 	guint cnpa;
 	guint paspa;
 	guint emlpa;
+	guint icopa;
 
 	GSList *create_rooms;
 
@@ -104,10 +105,12 @@
 	GSList *direct_ims;
 	GSList *file_transfers;
 	GHashTable *buddyinfo;
+	GSList *requesticon;
 
 	gboolean killme;
 	gboolean icq;
 	GSList *evilhack;
+	guint icontimer;
 
 	struct {
 		guint maxwatchers; /* max users who can watch you */
@@ -182,6 +185,9 @@
 	unsigned long ico_me_csum;
 	time_t ico_me_time;
 	gboolean ico_informed;
+
+	fu16_t iconstrlen;
+	fu8_t iconstr[30];
 };
 
 struct name_data {
@@ -289,6 +295,8 @@
 static int gaim_chat_info_update (aim_session_t *, aim_frame_t *, ...);
 static int gaim_chat_incoming_msg(aim_session_t *, aim_frame_t *, ...);
 static int gaim_email_parseupdate(aim_session_t *, aim_frame_t *, ...);
+static int gaim_icon_error       (aim_session_t *, aim_frame_t *, ...);
+static int gaim_icon_parseicon   (aim_session_t *, aim_frame_t *, ...);
 static int gaim_parse_msgack     (aim_session_t *, aim_frame_t *, ...);
 static int gaim_parse_ratechange (aim_session_t *, aim_frame_t *, ...);
 static int gaim_parse_evilnotify (aim_session_t *, aim_frame_t *, ...);
@@ -301,6 +309,7 @@
 static int conninitdone_chatnav  (aim_session_t *, aim_frame_t *, ...);
 static int conninitdone_chat     (aim_session_t *, aim_frame_t *, ...);
 static int conninitdone_email    (aim_session_t *, aim_frame_t *, ...);
+static int conninitdone_icon     (aim_session_t *, aim_frame_t *, ...);
 static int gaim_parse_msgerr     (aim_session_t *, aim_frame_t *, ...);
 static int gaim_parse_mtn        (aim_session_t *, aim_frame_t *, ...);
 static int gaim_parse_locaterights(aim_session_t *, aim_frame_t *, ...);
@@ -338,6 +347,9 @@
 static int oscar_sendfile_ack    (aim_session_t *, aim_frame_t *, ...);
 static int oscar_sendfile_done   (aim_session_t *, aim_frame_t *, ...);
 
+/* for icons */
+static gboolean gaim_icon_timerfunc(gpointer data);
+
 static fu32_t check_encoding(const char *utf8);
 static fu32_t parse_encoding(const char *enc);
 
@@ -479,6 +491,12 @@
 					od->emlpa = 0;
 					debug_printf("removing email input watcher\n");
 					aim_conn_kill(od->sess, &conn);
+				} else if (conn->type == AIM_CONN_TYPE_ICON) {
+					if (od->icopa > 0)
+						gaim_input_remove(od->icopa);
+					od->icopa = 0;
+					debug_printf("removing icon input watcher\n");
+					aim_conn_kill(od->sess, &conn);
 				} else if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) {
 					if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM)
 						gaim_odc_disconnect(od->sess, conn);
@@ -611,14 +629,17 @@
 		od->direct_ims = g_slist_remove(od->direct_ims, n);
 		g_free(n);
 	}
-
 /* BBB */
 	while (od->file_transfers) {
 		struct gaim_xfer *xfer;
 		xfer = (struct gaim_xfer *)od->file_transfers->data;
 		gaim_xfer_destroy(xfer);
 	}
-
+	while (od->requesticon) {
+		char *sn = od->requesticon->data;
+		od->requesticon = g_slist_remove(od->requesticon, sn);
+		free(sn);
+	}
 	g_hash_table_destroy(od->buddyinfo);
 	while (od->evilhack) {
 		g_free(od->evilhack->data);
@@ -644,6 +665,8 @@
 		gaim_input_remove(od->paspa);
 	if (od->emlpa > 0)
 		gaim_input_remove(od->emlpa);
+	if (od->icopa > 0)
+		gaim_input_remove(od->icopa);
 	aim_session_kill(od->sess);
 	g_free(od->sess);
 	od->sess = NULL;
@@ -1347,6 +1370,23 @@
 	return 1;
 }
 
+static int conninitdone_icon(aim_session_t *sess, aim_frame_t *fr, ...) {
+	struct gaim_connection *gc = sess->aux_data;
+	struct oscar_data *od = gc->proto_data;
+
+	aim_conn_addhandler(sess, fr->conn, 0x0018, 0x0001, gaim_parse_genericerr, 0);
+	aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_ICO, AIM_CB_ICO_ERROR, gaim_icon_error, 0);
+	aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_ICO, AIM_CB_ICO_RESPONSE, gaim_icon_parseicon, 0);
+
+	aim_clientready(sess, fr->conn);
+
+	if (od->icontimer)
+		g_source_remove(od->icontimer);
+	od->icontimer = g_timeout_add(100, gaim_icon_timerfunc, gc);
+
+	return 1;
+}
+
 static void oscar_chatnav_connect(gpointer data, gint source, GaimInputCondition cond) {
 	struct gaim_connection *gc = data;
 	struct oscar_data *od;
@@ -1463,6 +1503,33 @@
 	debug_printf("email: connected\n");
 }
 
+static void oscar_icon_connect(gpointer data, gint source, GaimInputCondition cond) {
+	struct gaim_connection *gc = data;
+	struct oscar_data *od;
+	aim_session_t *sess;
+	aim_conn_t *tstconn;
+
+	if (!g_slist_find(connections, gc)) {
+		close(source);
+		return;
+	}
+
+	od = gc->proto_data;
+	sess = od->sess;
+	tstconn = aim_getconn_type_all(sess, AIM_CONN_TYPE_ICON);
+	tstconn->fd = source;
+
+	if (source < 0) {
+		aim_conn_kill(sess, &tstconn);
+		debug_printf("unable to connect to icon server\n");
+		return;
+	}
+
+	aim_conn_completeconnect(sess, tstconn);
+	od->icopa = gaim_input_add(tstconn->fd, GAIM_INPUT_READ, oscar_callback, tstconn);
+	debug_printf("icon: connected\n");
+}
+
 /* Hrmph. I don't know how to make this look better. --mid */
 static int gaim_handle_redirect(aim_session_t *sess, aim_frame_t *fr, ...) {
 	va_list ap;
@@ -1570,6 +1637,25 @@
 		debug_printf("Connected to chat room %s exchange %hu\n", ccon->name, ccon->exchange);
 	} break;
 
+	case 0x0010: { /* icon */
+		if (!(tstconn = aim_newconn(sess, AIM_CONN_TYPE_ICON, NULL))) {
+			debug_printf("unable to connect to icon server\n");
+			g_free(host);
+			return 1;
+		}
+		aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, gaim_connerr, 0);
+		aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_icon, 0);
+
+		tstconn->status |= AIM_CONN_STATUS_INPROGRESS;
+		if (proxy_connect(account, host, port, oscar_icon_connect, gc) != 0) {
+			aim_conn_kill(sess, &tstconn);
+			debug_printf("unable to connect to icon server\n");
+			g_free(host);
+			return 1;
+		}
+		aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
+	} break;
+
 	case 0x0018: { /* email */
 		if (!(tstconn = aim_newconn(sess, AIM_CONN_TYPE_EMAIL, NULL))) {
 			debug_printf("unable to connect to email server\n");
@@ -1663,6 +1749,16 @@
 	bi->typingnot = FALSE;
 	bi->ico_informed = FALSE;
 
+	/* Server stored icon stuff */
+	if (info->iconstrlen) {
+		od->requesticon = g_slist_append(od->requesticon, strdup(normalize(info->sn)));
+		if (od->icontimer)
+			g_source_remove(od->icontimer);
+		od->icontimer = g_timeout_add(500, gaim_icon_timerfunc, gc);
+	}
+	bi->iconstrlen = info->iconstrlen;
+	memcpy(bi->iconstr, info->iconstr, info->iconstrlen);
+
 	serv_got_update(gc, info->sn, 1, info->warnlevel/10, signon,
 			time_idle, type);
 
@@ -3226,6 +3322,96 @@
 	return 1;
 }
 
+static int gaim_icon_error(aim_session_t *sess, aim_frame_t *fr, ...) {
+	struct gaim_connection *gc = sess->aux_data;
+	struct oscar_data *od = gc->proto_data;
+	char *sn;
+
+	sn = od->requesticon->data;
+	debug_printf("removing %s from hash table\n", sn);
+	od->requesticon = g_slist_remove(od->requesticon, sn);
+	free(sn);
+
+	if (od->icontimer)
+		g_source_remove(od->icontimer);
+	od->icontimer = g_timeout_add(500, gaim_icon_timerfunc, gc);
+
+	return 1;
+}
+
+static int gaim_icon_parseicon(aim_session_t *sess, aim_frame_t *fr, ...) {
+	struct gaim_connection *gc = sess->aux_data;
+	struct oscar_data *od = gc->proto_data;
+	GSList *cur;
+	va_list ap;
+	char *sn;
+	fu8_t *iconstr, *icon;
+	fu16_t iconstrlen, iconlen;
+
+	va_start(ap, fr);
+	sn = va_arg(ap, char *);
+	iconstr = va_arg(ap, fu8_t *);
+	iconstrlen = va_arg(ap, int);
+	icon = va_arg(ap, fu8_t *);
+	iconlen = va_arg(ap, int);
+	va_end(ap);
+
+	if (iconlen > 0)
+		set_icon_data(gc, sn, icon, iconlen);
+
+	cur = od->requesticon;
+	while (cur) {
+		char *cursn = cur->data;
+		if (!aim_sncmp(cursn, sn)) {
+			od->requesticon = g_slist_remove(od->requesticon, cursn);
+			free(cursn);
+			cur = od->requesticon;
+		} else
+			cur = cur->next;
+	}
+
+	if (od->icontimer)
+		g_source_remove(od->icontimer);
+	od->icontimer = g_timeout_add(250, gaim_icon_timerfunc, gc);
+
+	return 1;
+}
+
+static gboolean gaim_icon_timerfunc(gpointer data) {
+	struct gaim_connection *gc = data;
+	struct oscar_data *od = gc->proto_data;
+	struct buddy *b;
+	struct buddyinfo *bi;
+	aim_conn_t *conn;
+	char *buddy_icon;
+
+	if (!od->requesticon) {
+		debug_printf("no more icons to request\n");
+		return FALSE;
+	}
+
+	conn = aim_getconn_type(od->sess, AIM_CONN_TYPE_ICON);
+	if (!conn) {
+		aim_reqservice(od->sess, od->conn, AIM_CONN_TYPE_ICON);
+		return FALSE;
+	}
+
+	bi = g_hash_table_lookup(od->buddyinfo, (char *)od->requesticon->data);
+	b = gaim_find_buddy(gc->account, (char *)od->requesticon->data);
+	buddy_icon = gaim_buddy_get_setting(b, "buddy_icon");
+	if (bi && (bi->iconstrlen > 0) && !buddy_icon) {
+		aim_icon_requesticon(od->sess, od->requesticon->data, bi->iconstr, bi->iconstrlen);
+		return FALSE;
+	} else {
+		char *sn = od->requesticon->data;
+		od->requesticon = g_slist_remove(od->requesticon, sn);
+		free(sn);
+	}
+	free(buddy_icon);
+
+	return TRUE;
+}
+
 /*
  * Recieved in response to an IM sent with the AIM_IMFLAGS_ACK option.
  */