changeset 4624:a964972cb361

[gaim-migrate @ 4915] Thanks to CmdrChalumpa for a lot of this code. Vincas: I think I've improved on your methods a bit, too. I employed some Kiaras-Furo shading, and-- Strongbad: I'll improve on your methods! I replied to your patch with a lil more detail. Thanks! committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Fri, 28 Feb 2003 04:26:37 +0000
parents a44382e8e6be
children 819ba05f5b1b
files ChangeLog src/protocols/oscar/aim.h src/protocols/oscar/aim_cbtypes.h src/protocols/oscar/bstream.c src/protocols/oscar/conn.c src/protocols/oscar/icq.c src/protocols/oscar/oscar.c src/protocols/oscar/rxhandlers.c
diffstat 8 files changed, 236 insertions(+), 155 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Feb 27 23:34:18 2003 +0000
+++ b/ChangeLog	Fri Feb 28 04:26:37 2003 +0000
@@ -37,15 +37,16 @@
 	* Fortune profile added to source.
 
 	AIM/ICQ:
+	* TOC no longer compiles statically by default--use OSCAR.
+	* ICQ plugin no longer gets built--use OSCAR.
 	* Server-stored buddy lists for ICQ with full support for 
 	  authorization (Thanks, Mark Doliner)
-	* TOC no longer compiles statically by default--use OSCAR.
-	* ICQ plugin no longer gets built--use OSCAR.
 	* File send/receive support for Aim over Oscar (Thanks, William T. 
 	  Mahan and Mark Doliner)
 	* Non-direct connect typing notification for AIM over OSCAR.
 	  (Thanks, Mark Doliner)
 	* Allow only people in buddy list privacy option added for AIM.
+	* Full ICQ info reading support. (Thanks, Vincas Ciziunas)
 	* Support for synchronizing group renames on server.  Group
 	  rename server synchronization for AIM.  Server-side
 	  synchronization for moving individual AIM buddy to new
--- a/src/protocols/oscar/aim.h	Thu Feb 27 23:34:18 2003 +0000
+++ b/src/protocols/oscar/aim.h	Fri Feb 28 04:26:37 2003 +0000
@@ -430,6 +430,7 @@
 	void (*debugcb)(struct aim_session_s *sess, int level, const char *format, va_list va); /* same as faim_debugging_callback_t */
 
 	aim_msgcookie_t *msgcookies;
+	struct aim_icq_info *icq_info;
 
 	void *modlistv;
 } aim_session_t;
@@ -1219,6 +1220,17 @@
 
 
 /* icq.c */
+#define AIM_ICQ_INFO_SIMPLE	0x001
+#define AIM_ICQ_INFO_SUMMARY	0x002
+#define AIM_ICQ_INFO_EMAIL	0x004
+#define AIM_ICQ_INFO_PERSONAL	0x008
+#define AIM_ICQ_INFO_ADDITIONAL	0x010
+#define AIM_ICQ_INFO_WORK	0x020
+#define AIM_ICQ_INFO_INTERESTS	0x040
+#define AIM_ICQ_INFO_ORGS	0x080
+#define AIM_ICQ_INFO_UNKNOWN	0x100
+#define AIM_ICQ_INFO_HAVEALL	0x1ff
+
 struct aim_icq_offlinemsg {
 	fu32_t sender;
 	fu16_t year;
@@ -1230,20 +1242,44 @@
 };
 
 struct aim_icq_info {
+	fu16_t reqid;
+
+	/* simple */
 	fu32_t uin;
+
+	/* general and "home" information (0x00c8) */
 	char *nick;
 	char *first;
 	char *last;
 	char *email;
-	char *personalwebpage;
-	char *info;
 	char *homecity;
 	char *homestate;
+	char *homephone;
+	char *homefax;
 	char *homeaddr;
+	char *mobile;
 	char *homezip;
 	fu16_t homecountry;
+/*	fu8_t timezone;
+	fu8_t hideemail; */
+
+	/* personal (0x00dc) */
+	fu8_t age;
+	fu8_t unknown;
+	fu8_t gender;
+	char *personalwebpage;
+	fu16_t birthyear;
+	fu8_t birthmonth;
+	fu8_t birthday;
+	fu8_t language1;
+	fu8_t language2;
+	fu8_t language3;
+
+	/* work (0x00d2) */
 	char *workcity;
 	char *workstate;
+	char *workphone;
+	char *workfax;
 	char *workaddr;
 	char *workzip;
 	fu16_t workcountry;
@@ -1251,6 +1287,16 @@
 	char *workdivision;
 	char *workposition;
 	char *workwebpage;
+
+	/* additional personal information (0x00e6) */
+	char *info;
+
+	/* email (0x00eb) */
+	fu16_t numaddresses;
+	char *email2;
+
+	/* we keep track of these in a linked list because we're 1337 */
+	struct aim_icq_info *next;
 };
 
 faim_export int aim_icq_reqofflinemsgs(aim_session_t *sess);
--- a/src/protocols/oscar/aim_cbtypes.h	Thu Feb 27 23:34:18 2003 +0000
+++ b/src/protocols/oscar/aim_cbtypes.h	Fri Feb 28 04:26:37 2003 +0000
@@ -194,8 +194,7 @@
 #define AIM_CB_ICQ_ERROR 0x0001
 #define AIM_CB_ICQ_OFFLINEMSG 0x00f0
 #define AIM_CB_ICQ_OFFLINEMSGCOMPLETE 0x00f1
-#define AIM_CB_ICQ_SIMPLEINFO 0x00f2
-#define AIM_CB_ICQ_ALLINFO 0x00f3
+#define AIM_CB_ICQ_INFO 0x00f2
 #define AIM_CB_ICQ_DEFAULT 0xffff
 
 /*
--- a/src/protocols/oscar/bstream.c	Thu Feb 27 23:34:18 2003 +0000
+++ b/src/protocols/oscar/bstream.c	Fri Feb 28 04:26:37 2003 +0000
@@ -230,6 +230,11 @@
 		free(ob);
 		return NULL;
 	}
+
+	if (ob[0] == '\0') {
+		free(ob);
+		return NULL;
+	}
 	
 	ob[len] = '\0';
 
--- a/src/protocols/oscar/conn.c	Thu Feb 27 23:34:18 2003 +0000
+++ b/src/protocols/oscar/conn.c	Fri Feb 28 04:26:37 2003 +0000
@@ -866,6 +866,7 @@
 	sess->queue_incoming = NULL;
 	aim_initsnachash(sess);
 	sess->msgcookies = NULL;
+	sess->icq_info = NULL;
 	sess->snacid_next = 0x00000001;
 
 	sess->flags = 0;
--- a/src/protocols/oscar/icq.c	Thu Feb 27 23:34:18 2003 +0000
+++ b/src/protocols/oscar/icq.c	Fri Feb 28 04:26:37 2003 +0000
@@ -115,6 +115,7 @@
 	aim_frame_t *fr;
 	aim_snacid_t snacid;
 	int bslen;
+	struct aim_icq_info *info;
 
 	if (!uin || uin[0] < '0' || uin[0] > '9')
 		return -EINVAL;
@@ -143,6 +144,13 @@
 
 	aim_tx_enqueue(sess, fr);
 
+	/* Keep track of this request and the ICQ number and request ID */
+	info = (struct aim_icq_info *)calloc(1, sizeof(struct aim_icq_info));
+	info->reqid = snacid;
+	info->uin = atoi(sess->sn);
+	info->next = sess->icq_info;
+	sess->icq_info = info;
+
 	return 0;
 }
 
@@ -221,6 +229,36 @@
 	return 0;
 }
 
+static void aim_icq_freeinfo(struct aim_icq_info *info) {
+	if (!info)
+		return;
+	free(info->nick);
+	free(info->first);
+	free(info->last);
+	free(info->email);
+	free(info->homecity);
+	free(info->homestate);
+	free(info->homephone);
+	free(info->homefax);
+	free(info->homeaddr);
+	free(info->mobile);
+	free(info->homezip);
+	free(info->personalwebpage);
+	free(info->email2);
+	free(info->workcity);
+	free(info->workstate);
+	free(info->workphone);
+	free(info->workfax);
+	free(info->workaddr);
+	free(info->workzip);
+	free(info->workcompany);
+	free(info->workdivision);
+	free(info->workposition);
+	free(info->workwebpage);
+	free(info->info);
+	free(info);
+}
+
 /**
  * Subtype 0x0003 - Response to 0x0015/0x002, contains an ICQesque packet.
  */
@@ -282,45 +320,58 @@
 		aim_rxcallback_t userfunc;
 
 		subtype = aimbs_getle16(&qbs);
-		info = (struct aim_icq_info *)malloc(sizeof(struct aim_icq_info));
-		memset(info, 0, sizeof(struct aim_icq_info));
 		aim_bstream_advance(&qbs, 1); /* 0x0a */
 
+		/* find other data from the same request */
+		for (info = sess->icq_info; info && (info->reqid != reqid); info = info->next);
+		if (!info) {
+			info = (struct aim_icq_info *)calloc(1, sizeof(struct aim_icq_info));
+			info->reqid = reqid;
+			info->next = sess->icq_info;
+			sess->icq_info = info;
+		}
+
 		switch (subtype) {
 		case 0x00aa: { /* password change status */
 			aimbs_getle8(&qbs); /* 0x000a for success */
 		} break;
 
-		case 0x00c8: { /* info summary (useful stuff) */
+		case 0x00c8: { /* general and "home" information */
 			info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
 			info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
 			info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			aim_bstream_advance(&qbs, aimbs_getle16(&qbs));
+			info->email = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
 			info->homecity = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
 			info->homestate = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			aim_bstream_advance(&qbs, aimbs_getle16(&qbs));
-			aim_bstream_advance(&qbs, aimbs_getle16(&qbs));
+			info->homephone = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
+			info->homefax = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
 			info->homeaddr = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			aim_bstream_advance(&qbs, aimbs_getle16(&qbs));
+			info->mobile = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
 			info->homezip = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
 			info->homecountry = aimbs_getle16(&qbs);
+			/* 1 byte timezone */
+			/* 1 byte hide email flag */
 		} break;
 
-		case 0x00dc: { /* personal web page */
-			aim_bstream_advance(&qbs, 3);
+		case 0x00dc: { /* personal information */
+			info->age = aimbs_getle8(&qbs);
+			info->unknown = aimbs_getle8(&qbs);
+			info->gender = aimbs_getle8(&qbs);
 			info->personalwebpage = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
+			info->birthyear = aimbs_getle16(&qbs);
+			info->birthmonth = aimbs_getle8(&qbs);
+			info->birthday = aimbs_getle8(&qbs);
+			info->language1 = aimbs_getle8(&qbs);
+			info->language2 = aimbs_getle8(&qbs);
+			info->language3 = aimbs_getle8(&qbs);
 		} break;
 
-		case 0x00eb: { /* email address(es) */
-			aim_bstream_advance(&qbs, 2); /* Number of email addresses? */
-			info->email = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-		} break;
-
+		/* XXX - Look into the webpage thing for this, too */
 		case 0x00d2: { /* work information */
 			info->workcity = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
 			info->workstate = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
-			aim_bstream_advance(&qbs, aimbs_getle16(&qbs));
-			aim_bstream_advance(&qbs, aimbs_getle16(&qbs));
+			info->workphone = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
+			info->workfax = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
 			info->workaddr = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
 			info->workzip = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
 			info->workcountry = aimbs_getle16(&qbs);
@@ -332,7 +383,13 @@
 		} break;
 
 		case 0x00e6: { /* additional personal information */
-			info->info = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
+			info->info = aimbs_getstr(&qbs, aimbs_getle16(&qbs)-1);
+		} break;
+
+		/* XXX - Find out the structure of this.  Probably make a 2d array of strings */
+		case 0x00eb: { /* email address(es) */
+			info->numaddresses = aimbs_getle16(&qbs);
+			info->email2 = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
 		} break;
 
 		case 0x00f0: { /* personal interests */
@@ -355,33 +412,20 @@
 		} break;
 		} /* End switch statement */
 
-		if (subtype == 0x019a) {
-			if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_SIMPLEINFO)))
+		if (!(snac->flags & 0x0001)) {
+			if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_INFO)))
 				ret = userfunc(sess, rx, info);
-		 } else {
-			if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_ALLINFO)))
-				ret = userfunc(sess, rx, info);
-		}
 
-		free(info->nick);
-		free(info->first);
-		free(info->last);
-		free(info->email);
-		free(info->personalwebpage);
-		free(info->info);
-		free(info->homecity);
-		free(info->homestate);
-		free(info->homeaddr);
-		free(info->homezip);
-		free(info->workcity);
-		free(info->workstate);
-		free(info->workaddr);
-		free(info->workzip);
-		free(info->workcompany);
-		free(info->workdivision);
-		free(info->workposition);
-		free(info->workwebpage);
-		free(info);
+			if (sess->icq_info == info) {
+				sess->icq_info = info->next;
+			} else {
+				struct aim_icq_info *cur;
+				for (cur=sess->icq_info; (cur->next && (cur->next!=info)); cur=cur->next);
+				if (cur->next)
+					cur->next = cur->next->next;
+			}
+			aim_icq_freeinfo(info);
+		}
 	}
 
 	aim_freetlvchain(&tl);
--- a/src/protocols/oscar/oscar.c	Thu Feb 27 23:34:18 2003 +0000
+++ b/src/protocols/oscar/oscar.c	Fri Feb 28 04:26:37 2003 +0000
@@ -593,8 +593,7 @@
 static int gaim_selfinfo         (aim_session_t *, aim_frame_t *, ...);
 static int gaim_offlinemsg       (aim_session_t *, aim_frame_t *, ...);
 static int gaim_offlinemsgdone   (aim_session_t *, aim_frame_t *, ...);
-static int gaim_icqsimpleinfo    (aim_session_t *, aim_frame_t *, ...);
-static int gaim_icqallinfo       (aim_session_t *, aim_frame_t *, ...);
+static int gaim_icqinfo          (aim_session_t *, aim_frame_t *, ...);
 static int gaim_popup            (aim_session_t *, aim_frame_t *, ...);
 #ifndef NOSSI
 static int gaim_ssi_parserights  (aim_session_t *, aim_frame_t *, ...);
@@ -1102,8 +1101,7 @@
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG, gaim_offlinemsg, 0);
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE, gaim_offlinemsgdone, 0);
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_POP, 0x0002, gaim_popup, 0);
-	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_SIMPLEINFO, gaim_icqsimpleinfo, 0);
-	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_ALLINFO, gaim_icqallinfo, 0);
+	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_INFO, gaim_icqinfo, 0);
 #ifndef NOSSI
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_RIGHTSINFO, gaim_ssi_parserights, 0);
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_LIST, gaim_ssi_parselist, 0);
@@ -2053,7 +2051,7 @@
 	if (args->icbmflags & AIM_IMFLAGS_TYPINGNOT) {
 		char *who = normalize(userinfo->sn);
 		if (!g_hash_table_lookup(od->supports_tn, who))
-			g_hash_table_insert(od->supports_tn, who, who);
+			g_hash_table_insert(od->supports_tn, who, (gpointer)1);
 	}
 
 	/* strip_linefeed(tmp); */
@@ -2747,8 +2745,6 @@
 	type2 = (fu16_t) va_arg(ap, unsigned int);
 	va_end(ap);
 
-	debug_printf("Received an mtn from %s.  Type1 is 0x%04hx and type2 is 0x%04hx.\n", sn, type1, type2);
-
 	switch (type2) {
 		case 0x0000: { /* Text has been cleared */
 			serv_got_typing_stopped(gc, sn);
@@ -2763,7 +2759,7 @@
 		} break;
 
 		default: {
-			printf("Received unknown typing notification type.\n");
+			printf("Received unknown typing notification message from %s.  Type1 is 0x%04x and type2 is 0x%04hx.\n", sn, type1, type2);
 		} break;
 	}
 
@@ -3510,126 +3506,103 @@
 	return 1;
 }
 
-static int gaim_icqsimpleinfo(aim_session_t *sess, aim_frame_t *fr, ...)
+static int gaim_icqinfo(aim_session_t *sess, aim_frame_t *fr, ...)
 {
 	struct gaim_connection *gc = sess->aux_data;
-	struct buddy *budlight;
+	gchar *buf, *tmp;
+	gchar who[16];
 	va_list ap;
 	struct aim_icq_info *info;
-	gchar *buf, *tmp;
-	gchar who[16];
 
 	va_start(ap, fr);
 	info = va_arg(ap, struct aim_icq_info *);
 	va_end(ap);
 
-	if (!info || !info->uin)
-		return 1;
-
 	g_snprintf(who, sizeof(who), "%lu", info->uin);
-	buf = g_strdup_printf("<b>UIN:</b> %s<br>", who);
+	buf = g_strdup_printf("<b>UIN:</b> %s", who);
 	if (info->nick) {
-		tmp = buf;
-		buf = g_strconcat(tmp, "<b>Nick:</b> ", info->nick, "<br>\n", NULL);
-		g_free(tmp);
+		tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>Nick:</b> ", info->nick, NULL);  g_free(tmp);
 		serv_got_alias(gc, who, info->nick);
 	}
 	if (info->first) {
-		tmp = buf;
-		buf = g_strconcat(tmp, "<b>First Name:</b> ", info->first, "<br>\n", NULL);
-		g_free(tmp);
+		tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>First Name:</b> ", info->first, NULL);  g_free(tmp);
 	}
 	if (info->last) {
-		tmp = buf;
-		buf = g_strconcat(tmp, "<b>Last Name:</b> ", info->last, "<br>\n", NULL);
-		g_free(tmp);
+		tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>Last Name:</b> ", info->last, NULL);  g_free(tmp);
 	}
 	if (info->email) {
-		tmp = buf;
-		buf = g_strconcat(tmp, "<b>Email Address:</b> ", info->email, "<br>\n", NULL);
-		g_free(tmp);
+		tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>Email Address:</b> ", info->email, NULL);  g_free(tmp);
+	}
+	if (info->mobile) {
+		tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>Mobile:</b> ", info->mobile, NULL);  g_free(tmp);
 	}
-
-	/* If the contact is away, then we also want to get their status message
-	 * and show it in the same window as info.  g_show_info_text gets the status 
-	 * message if the third arg is 0 (this seems really gross to me).  The 
-	 * parse-icq-status-message function knows if it is putting it's message in 
-	 * an info window because the name will _not_ be in od->evilhack.  For getting 
-	 * only the away message the contact's UIN is put in od->evilhack. */
-	if ((budlight = find_buddy(gc->account, who))) {
-		if ((budlight->uc >> 16) & (AIM_ICQ_STATE_AWAY || AIM_ICQ_STATE_DND || AIM_ICQ_STATE_OUT || AIM_ICQ_STATE_BUSY || AIM_ICQ_STATE_CHAT)) {
-			if (budlight->caps & AIM_CAPS_ICQSERVERRELAY)
-				g_show_info_text(gc, who, 0, buf, NULL);
-			else {
-				char *state_msg = gaim_icq_status((budlight->uc & 0xffff0000) >> 16);
-				g_show_info_text(gc, who, 2, buf, "<B>Status:</B> ", state_msg, "<HR>\n<I>Remote client does not support sending status messages.</I><BR>\n", NULL);
-				free(state_msg);
-			}
-		} else {
-			char *state_msg = gaim_icq_status((budlight->uc & 0xffff0000) >> 16);
-			g_show_info_text(gc, who, 2, buf, "<B>Status:</B> ", state_msg, NULL);
-			free(state_msg);
-		}
-	} else
-		g_show_info_text(gc, who, 2, buf, NULL);
-
-	g_free(buf);
-
-	return 1;
-}
-
-static int gaim_icqallinfo(aim_session_t *sess, aim_frame_t *fr, ...)
-{
-	struct gaim_connection *gc = sess->aux_data;
-	va_list ap;
-	struct aim_icq_info *info;
-	gchar *buf, *tmp;
-	gchar who[16];
-
-	va_start(ap, fr);
-	info = va_arg(ap, struct aim_icq_info *);
-	va_end(ap);
-
-	if (!info || !info->uin)
-		return 1;
-
-	g_snprintf(who, sizeof(who), "%lu", info->uin);
-	buf = g_strdup_printf("<b>UIN:</b> %s<br>", who);
-	if (info->nick) {
-		tmp = buf;
-		buf = g_strconcat(tmp, "<b>Nick:</b> ", info->nick, "<br>\n", NULL);
-		g_free(tmp);
-		serv_got_alias(gc, who, info->nick);
+	if (info->birthyear || info->birthmonth || info->birthday) {
+		char date[15];
+		snprintf(date, sizeof(date), "%hhd/%hhd/%hd", info->birthday, info->birthmonth, info->birthyear);
+		tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>Birthday:</b> ", date, NULL);  g_free(tmp);
 	}
-	if (info->first) {
-		tmp = buf;
-		buf = g_strconcat(tmp, "<b>First Name:</b> ", info->first, "<br>\n", NULL);
-		g_free(tmp);
+	if (info->age) {
+		char age[5];
+		snprintf(age, sizeof(age), "%hhd", info->age);
+		tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>Age:</b> ", age, NULL);  g_free(tmp);
 	}
-	if (info->last) {
-		tmp = buf;
-		buf = g_strconcat(tmp, "<b>Last Name:</b> ", info->last, "<br>\n", NULL);
-		g_free(tmp);
-	}
-	if (info->email) {
-		tmp = buf;
-		buf = g_strconcat(tmp, "<b>Email Address:</b> ", info->email, "<br>\n", NULL);
-		g_free(tmp);
+	if (info->gender) {
+		tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>Age:</b> ", info->gender ? "Male" : "Female", NULL);  g_free(tmp);
 	}
 	if (info->personalwebpage) {
-		tmp = buf;
-		buf = g_strconcat(tmp, "<b>Personal Webpage:</b> ", info->personalwebpage, "<br>\n", NULL);
-		g_free(tmp);
+		tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>Personal Web Page:</b> <a href=\"", info->personalwebpage, "\">", info->personalwebpage, "</a>", NULL);  g_free(tmp);
 	}
 	if (info->info) {
-		tmp = buf;
-		buf = g_strconcat(tmp, "<br><b>Additional Information:</b><br>", info->info, "<hr>\n", NULL);
-		g_free(tmp);
+		tmp = buf;  buf = g_strconcat(tmp, "<hr><b>Additional Information:</b><br>", info->info, NULL);  g_free(tmp);
+	}
+	tmp = buf;  buf = g_strconcat(tmp, "<hr>\n", NULL);  g_free(tmp);
+	if (info->homeaddr || info->homecity || info->homestate || info->homezip) {
+		tmp = buf;  buf = g_strconcat(tmp, "<b>Home Address:</b>", NULL);  g_free(tmp);
+		if (info->homeaddr) {
+			tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>Address:</b> ", info->homeaddr, NULL);  g_free(tmp);
+		}
+		if (info->homecity) {
+			tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>City:</b> ", info->homecity,  NULL);  g_free(tmp);
+		}
+		if (info->homestate) {
+			tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>State:</b> ", info->homestate, NULL);  g_free(tmp);
+		}
+		if (info->homezip) {
+			tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>Zip Code:</b> ", info->homezip, NULL);  g_free(tmp);
+		}
+		tmp = buf; buf = g_strconcat(tmp, "\n<hr>\n", NULL); g_free(tmp);
 	}
-	if (info->homecity && info->homestate && info->homeaddr && info->homezip) {
-		tmp = buf;
-		buf = g_strconcat(tmp, "<br><b>Home Address:</b><br>\n", info->homeaddr, "<br>\n", info->homecity, ", ", info->homestate, " ", info->homezip, "<hr>\n", NULL);
-		g_free(tmp);
+	if (info->workaddr || info->workcity || info->workstate || info->workzip) {
+		tmp = buf;  buf = g_strconcat(tmp, "<b>Work Address:</b>", NULL);  g_free(tmp);
+		if (info->workaddr) {
+			tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>Address:</b> ", info->workaddr, NULL);  g_free(tmp);
+		}
+		if (info->workcity) {
+			tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>City:</b> ", info->workcity, NULL);  g_free(tmp);
+		}
+		if (info->workstate) {
+			tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>State:</b> ", info->workstate, NULL);  g_free(tmp);
+		}
+		if (info->workzip) {
+			tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>Zip Code:</b> ", info->workzip, NULL);  g_free(tmp);
+		}
+		tmp = buf; buf = g_strconcat(tmp, "\n<hr>\n", NULL); g_free(tmp);
+	}
+	if (info->workcompany || info->workdivision || info->workposition || info->workwebpage) {
+		tmp = buf;  buf = g_strconcat(tmp, "<b>Work Information:</b>", NULL);  g_free(tmp);
+		if (info->workcompany) {
+			tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>Company:</b> ", info->workcompany, NULL);  g_free(tmp);
+		}
+		if (info->workdivision) {
+			tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>Division:</b> ", info->workdivision, NULL);  g_free(tmp);
+		}
+		if (info->workposition) {
+			tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>Position:</b> ", info->workposition, NULL);  g_free(tmp);
+		}
+		if (info->workwebpage) {
+			tmp = buf;  buf = g_strconcat(tmp, "\n<br><b>Web Page:</b> <a href=\"", info->workwebpage, "\">", info->workwebpage, "</a>", NULL);  g_free(tmp);
+		}
+		tmp = buf; buf = g_strconcat(tmp, "\n<hr>\n", NULL); g_free(tmp);
 	}
 
 	g_show_info_text(gc, who, 2, buf, NULL);
@@ -3915,7 +3888,7 @@
 static void oscar_get_info(struct gaim_connection *g, char *name) {
 	struct oscar_data *od = (struct oscar_data *)g->proto_data;
 	if (od->icq)
-		aim_icq_getsimpleinfo(od->sess, name);
+		aim_icq_getallinfo(od->sess, name);
 	else
 		/* people want the away message on the top, so we get the away message
 		 * first and then get the regular info, since it's too difficult to
@@ -5130,11 +5103,13 @@
 	m = g_list_append(m, pbm);
 
 	if (od->icq) {
+#if 0
 		pbm = g_new0(struct proto_buddy_menu, 1);
 		pbm->label = _("Get Status Msg");
 		pbm->callback = oscar_get_away_msg;
 		pbm->gc = gc;
 		m = g_list_append(m, pbm);
+#endif
 	} else {
 		struct buddy *b = find_buddy(gc->account, who);
 
--- a/src/protocols/oscar/rxhandlers.c	Thu Feb 27 23:34:18 2003 +0000
+++ b/src/protocols/oscar/rxhandlers.c	Fri Feb 28 04:26:37 2003 +0000
@@ -109,13 +109,23 @@
 	snac.id = aimbs_get32(&rx->data);
 
 	/* SNAC flags are apparently uniform across all SNACs, so we handle them here */
+	if (snac.flags & 0x0001) {
+		/*
+		 * This means the SNAC will be followed by another SNAC with 
+		 * related information.  We don't need to do anything about 
+		 * this here.
+		 */
+	}
 	if (snac.flags & 0x8000) {
-		/* This contains the version of the family that this SNAC is in.  
-		 * You get this when your SSI module is version 2 or higher.  
+		/*
+		 * This packet contains the version of the family that this SNAC is 
+		 * in.  You get this when your SSI module is version 2 or higher.  
 		 * For now we have no need for this, but you could always save 
 		 * it as a part of aim_modnsac_t, or something.  The format is...
-		 * 2 byte length of total mini-header, then TLV of  type 0x0001, 
-		 * length 0x0002, value is the 2 byte version number */
+		 * 2 byte length of total mini-header (which is 6 bytes), then TLV 
+		 * of  type 0x0001, length 0x0002, value is the 2 byte version 
+		 * number
+		 */
 		aim_bstream_advance(&rx->data, aimbs_get16(&rx->data));
 	}