soc.2010.icq-tlc: f765bcbd: Added an error handler for family_icq.c....

ivan.komarov at soc.pidgin.im ivan.komarov at soc.pidgin.im
Sun May 30 15:25:46 EDT 2010


-----------------------------------------------------------------
Revision: f765bcbdce8ccdb1171321a31fb598f93841133f
Ancestor: 839fbffec07b17dcc9e9f1a79544242b08d3ff0e
Author: ivan.komarov at soc.pidgin.im
Date: 2010-05-30T19:01:30
Branch: im.pidgin.soc.2010.icq-tlc
URL: http://d.pidgin.im/viewmtn/revision/info/f765bcbdce8ccdb1171321a31fb598f93841133f

Modified files:
        libpurple/protocols/oscar/family_icbm.c
        libpurple/protocols/oscar/family_icq.c
        libpurple/protocols/oscar/oscar.h
        libpurple/protocols/oscar/userinfo.c

ChangeLog: 

Added an error handler for family_icq.c. So far it works for
icq fullinfo and alias requests.

This was originally motivated by me getting "Server rate limit exceeded" 
while testing authorization requests. This error completely prevented
the authorization request dialog from showing up.

-------------- next part --------------
============================================================
--- libpurple/protocols/oscar/family_icbm.c	52688bc864209fd4471193bfce81c4547ba8ae51
+++ libpurple/protocols/oscar/family_icbm.c	13c16ef6a0d7bc939530a112798509aceae3ac39
@@ -2495,181 +2495,6 @@ int aim_im_denytransfer(OscarData *od, c
 	return 0;
 }
 
-static void parse_status_note_text(OscarData *od, guchar *cookie, char *bn, ByteStream *bs)
-{
-	struct aim_icq_info *info;
-	struct aim_icq_info *prev_info;
-	char *response;
-	char *encoding;
-	char *stripped_encoding;
-	char *status_note_title;
-	char *status_note_text;
-	char *stripped_status_note_text;
-	char *status_note;
-	guint32 length;
-	guint16 version;
-	guint32 capability;
-	guint8 message_type;
-	guint16 status_code;
-	guint16 text_length;
-	guint32 request_length;
-	guint32 response_length;
-	guint32 encoding_length;
-	PurpleAccount *account;
-	PurpleBuddy *buddy;
-	PurplePresence *presence;
-	PurpleStatus *status;
-
-	for (prev_info = NULL, info = od->icq_info; info != NULL; prev_info = info, info = info->next)
-	{
-		if (memcmp(&info->icbm_cookie, cookie, 8) == 0)
-		{
-			if (prev_info == NULL)
-				od->icq_info = info->next;
-			else
-				prev_info->next = info->next;
-
-			break;
-		}
-	}
-
-	if (info == NULL)
-		return;
-
-	status_note_title = info->status_note_title;
-	g_free(info);
-
-	length = byte_stream_getle16(bs);
-	if (length != 27) {
-		purple_debug_misc("oscar", "clientautoresp: incorrect header "
-				"size; expected 27, received %u.\n", length);
-		g_free(status_note_title);
-		return;
-	}
-
-	version = byte_stream_getle16(bs);
-	if (version != 9) {
-		purple_debug_misc("oscar", "clientautoresp: incorrect version; "
-				"expected 9, received %u.\n", version);
-		g_free(status_note_title);
-		return;
-	}
-
-	capability = aim_locate_getcaps(od, bs, 0x10);
-	if (capability != OSCAR_CAPABILITY_EMPTY) {
-		purple_debug_misc("oscar", "clientautoresp: plugin ID is not null.\n");
-		g_free(status_note_title);
-		return;
-	}
-
-	byte_stream_advance(bs, 2); /* unknown */
-	byte_stream_advance(bs, 4); /* client capabilities flags */
-	byte_stream_advance(bs, 1); /* unknown */
-	byte_stream_advance(bs, 2); /* downcouner? */
-
-	length = byte_stream_getle16(bs);
-	if (length != 14) {
-		purple_debug_misc("oscar", "clientautoresp: incorrect header "
-				"size; expected 14, received %u.\n", length);
-		g_free(status_note_title);
-		return;
-	}
-
-	byte_stream_advance(bs, 2); /* downcounter? */
-	byte_stream_advance(bs, 12); /* unknown */
-
-	message_type = byte_stream_get8(bs);
-	if (message_type != 0x1a) {
-		purple_debug_misc("oscar", "clientautoresp: incorrect message "
-				"type; expected 0x1a, received 0x%x.\n", message_type);
-		g_free(status_note_title);
-		return;
-	}
-
-	byte_stream_advance(bs, 1); /* message flags */
-
-	status_code = byte_stream_getle16(bs);
-	if (status_code != 0) {
-		purple_debug_misc("oscar", "clientautoresp: incorrect status "
-				"code; expected 0, received %u.\n", status_code);
-		g_free(status_note_title);
-		return;
-	}
-
-	byte_stream_advance(bs, 2); /* priority code */
-
-	text_length = byte_stream_getle16(bs);
-	byte_stream_advance(bs, text_length); /* text */
-
-	length = byte_stream_getle16(bs);
-	byte_stream_advance(bs, 18); /* unknown */
-
-	request_length = byte_stream_getle32(bs);
-	if (length != 18 + 4 + request_length + 17) {
-		purple_debug_misc("oscar", "clientautoresp: incorrect block; "
-				"expected length is %u, got %u.\n",
-				18 + 4 + request_length + 17, length);
-		g_free(status_note_title);
-		return;
-	}
-
-	byte_stream_advance(bs, request_length); /* x request */
-	byte_stream_advance(bs, 17); /* unknown */
-
-	length = byte_stream_getle32(bs);
-	response_length = byte_stream_getle32(bs);
-	response = byte_stream_getstr(bs, response_length);
-	encoding_length = byte_stream_getle32(bs);
-	if (length != 4 + response_length + 4 + encoding_length) {
-		purple_debug_misc("oscar", "clientautoresp: incorrect block; "
-				"expected length is %u, got %u.\n",
-				4 + response_length + 4 + encoding_length, length);
-		g_free(status_note_title);
-		g_free(response);
-		return;
-	}
-
-	encoding = byte_stream_getstr(bs, encoding_length);
-
-	account = purple_connection_get_account(od->gc);
-
-	stripped_encoding = oscar_encoding_extract(encoding);
-	status_note_text = oscar_encoding_to_utf8(account, stripped_encoding, response, response_length);
-	stripped_status_note_text = purple_markup_strip_html(status_note_text);
-
-	if (stripped_status_note_text != NULL && stripped_status_note_text[0] != 0)
-		status_note = g_strdup_printf("%s: %s", status_note_title, stripped_status_note_text);
-	else
-		status_note = g_strdup(status_note_title);
-
-	g_free(status_note_title);
-	g_free(response);
-	g_free(encoding);
-	g_free(stripped_encoding);
-	g_free(status_note_text);
-	g_free(stripped_status_note_text);
-
-	buddy = purple_find_buddy(account, bn);
-	if (buddy == NULL)
-	{
-		purple_debug_misc("oscar", "clientautoresp: buddy %s was not found.\n", bn);
-		g_free(status_note);
-		return;
-	}
-
-	purple_debug_misc("oscar", "clientautoresp: setting status "
-			"message to \"%s\".\n", status_note);
-
-	presence = purple_buddy_get_presence(buddy);
-	status = purple_presence_get_active_status(presence);
-
-	purple_prpl_got_user_status(account, bn,
-			purple_status_get_id(status),
-			"message", status_note, NULL);
-
-	g_free(status_note);
-}
-
 /*
  * Subtype 0x000b - Receive the response from an ICQ status message
  * request (in which case this contains the ICQ status message) or
============================================================
--- libpurple/protocols/oscar/family_icq.c	ece5b121584a17967caea4c0b6225c7360b0040a
+++ libpurple/protocols/oscar/family_icq.c	ec08a415f11a10242dde9e3dcd6b4681267a39b0
@@ -25,6 +25,102 @@
 
 #include "oscar.h"
 
+#define AIM_ICQ_INFO_REQUEST 0x04b2
+#define AIM_ICQ_ALIAS_REQUEST 0x04ba
+
+static
+int compare_icq_infos(gconstpointer a, gconstpointer b)
+{
+	const struct aim_icq_info* aa = a;
+	const guint16* bb = b;
+	return aa->reqid - *bb;
+}
+
+static void aim_icq_freeinfo(struct aim_icq_info *info) {
+	int i;
+
+	if (!info)
+		return;
+	g_free(info->nick);
+	g_free(info->first);
+	g_free(info->last);
+	g_free(info->email);
+	g_free(info->homecity);
+	g_free(info->homestate);
+	g_free(info->homephone);
+	g_free(info->homefax);
+	g_free(info->homeaddr);
+	g_free(info->mobile);
+	g_free(info->homezip);
+	g_free(info->personalwebpage);
+	if (info->email2)
+		for (i = 0; i < info->numaddresses; i++)
+			g_free(info->email2[i]);
+	g_free(info->email2);
+	g_free(info->workcity);
+	g_free(info->workstate);
+	g_free(info->workphone);
+	g_free(info->workfax);
+	g_free(info->workaddr);
+	g_free(info->workzip);
+	g_free(info->workcompany);
+	g_free(info->workdivision);
+	g_free(info->workposition);
+	g_free(info->workwebpage);
+	g_free(info->info);
+	g_free(info->status_note_title);
+	g_free(info->auth_request_reason);
+}
+
+static
+int error(OscarData *od, aim_modsnac_t *error_snac, ByteStream *bs)
+{
+	aim_snac_t *original_snac = aim_remsnac(od, error_snac->id);
+	guint16 *request_type;
+	GSList *original_info_ptr;
+	struct aim_icq_info *original_info;
+	guint16 reason;
+	gchar *uin;
+
+	if (!original_snac || (original_snac->family != SNAC_FAMILY_ICQ) || !original_snac->data) {
+		purple_debug_misc("oscar", "icq: the original snac for the error packet was not found");
+		g_free(original_snac);
+		return 0;
+	}
+	
+	request_type = original_snac->data;
+	original_info_ptr = g_slist_find_custom(od->icq_info, &original_snac->id, compare_icq_infos);
+	original_info = original_info_ptr->data;
+	
+	if (!original_info_ptr) {
+		purple_debug_misc("oscar", "icq: the request info for the error packet was not found");
+		g_free(original_snac);
+		return 0;
+	}
+	
+	reason = byte_stream_get16(bs);
+	uin = g_strdup_printf("%u", original_info->uin);
+	switch (*request_type) {
+		case AIM_ICQ_INFO_REQUEST:
+			oscar_user_info_display_error(od, reason, uin);
+			break;
+		case AIM_ICQ_ALIAS_REQUEST:
+			/* Couldn't retrieve an alias for the buddy requesting authorization; have to make do with UIN only. */
+			if (original_info->for_auth_request)
+				oscar_auth_recvrequest(od->gc, uin, NULL, original_info->auth_request_reason);
+			break;
+		default:
+			purple_debug_misc("oscar", "icq: got an error packet with unknown request type %u", *request_type);
+			break;
+	}
+
+	aim_icq_freeinfo(original_info);
+	od->icq_info = g_slist_remove(od->icq_info, original_info_ptr);
+	g_free(original_snac->data);
+	g_free(original_snac);
+	return 1;
+}
+
 int
 aim_icq_setsecurity(OscarData *od, gboolean auth_required, gboolean webaware)
 {
@@ -124,6 +220,7 @@ int aim_icq_getallinfo(OscarData *od, co
 	aim_snacid_t snacid;
 	int bslen;
 	struct aim_icq_info *info;
+	guint16 request_type = AIM_ICQ_INFO_REQUEST;
 
 	if (!uin || uin[0] < '0' || uin[0] > '9')
 		return -EINVAL;
@@ -135,7 +232,7 @@ int aim_icq_getallinfo(OscarData *od, co
 
 	byte_stream_new(&bs, 4 + bslen);
 
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
+	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, &request_type, sizeof(request_type));
 
 	/* For simplicity, don't bother using a tlvlist */
 	byte_stream_put16(&bs, 0x0001);
@@ -145,7 +242,7 @@ int aim_icq_getallinfo(OscarData *od, co
 	byte_stream_putuid(&bs, od);
 	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
 	byte_stream_putle16(&bs, snacid); /* eh. */
-	byte_stream_putle16(&bs, 0x04b2); /* shrug. */
+	byte_stream_putle16(&bs, request_type); /* shrug. */
 	byte_stream_putle32(&bs, atoi(uin));
 
 	flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs, FALSE);
@@ -156,8 +253,7 @@ int aim_icq_getallinfo(OscarData *od, co
 	info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
 	info->reqid = snacid;
 	info->uin = atoi(uin);
-	info->next = od->icq_info;
-	od->icq_info = info;
+	od->icq_info = g_slist_prepend(od->icq_info, info);
 
 	return 0;
 }
@@ -169,6 +265,7 @@ int aim_icq_getalias(OscarData *od, cons
 	aim_snacid_t snacid;
 	int bslen;
 	struct aim_icq_info *info;
+	guint16 request_type = AIM_ICQ_ALIAS_REQUEST;
 
 	if (!uin || uin[0] < '0' || uin[0] > '9')
 		return -EINVAL;
@@ -182,7 +279,7 @@ int aim_icq_getalias(OscarData *od, cons
 
 	byte_stream_new(&bs, 4 + bslen);
 
-	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
+	snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, &request_type, sizeof(request_type));
 
 	/* For simplicity, don't bother using a tlvlist */
 	byte_stream_put16(&bs, 0x0001);
@@ -192,7 +289,7 @@ int aim_icq_getalias(OscarData *od, cons
 	byte_stream_putuid(&bs, od);
 	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
 	byte_stream_putle16(&bs, snacid); /* eh. */
-	byte_stream_putle16(&bs, 0x04ba); /* shrug. */
+	byte_stream_putle16(&bs, request_type); /* shrug. */
 	byte_stream_putle32(&bs, atoi(uin));
 
 	flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs, FALSE);
@@ -203,10 +300,9 @@ int aim_icq_getalias(OscarData *od, cons
 	info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
 	info->reqid = snacid;
 	info->uin = atoi(uin);
-	info->next = od->icq_info;
 	info->for_auth_request = for_auth_request;
 	info->auth_request_reason = g_strdup(auth_request_reason);
-	od->icq_info = info;
+	od->icq_info = g_slist_prepend(od->icq_info, info);
 
 	return 0;
 }
@@ -331,54 +427,15 @@ gotalias(OscarData *od, struct aim_icq_i
 			g_free(utf8);
 		}
 	}
-
-	g_free(info->auth_request_reason);
 	return 1;
 }
 
-static void aim_icq_freeinfo(struct aim_icq_info *info) {
-	int i;
-
-	if (!info)
-		return;
-	g_free(info->nick);
-	g_free(info->first);
-	g_free(info->last);
-	g_free(info->email);
-	g_free(info->homecity);
-	g_free(info->homestate);
-	g_free(info->homephone);
-	g_free(info->homefax);
-	g_free(info->homeaddr);
-	g_free(info->mobile);
-	g_free(info->homezip);
-	g_free(info->personalwebpage);
-	if (info->email2)
-		for (i = 0; i < info->numaddresses; i++)
-			g_free(info->email2[i]);
-	g_free(info->email2);
-	g_free(info->workcity);
-	g_free(info->workstate);
-	g_free(info->workphone);
-	g_free(info->workfax);
-	g_free(info->workaddr);
-	g_free(info->workzip);
-	g_free(info->workcompany);
-	g_free(info->workdivision);
-	g_free(info->workposition);
-	g_free(info->workwebpage);
-	g_free(info->info);
-	g_free(info->status_note_title);
-	g_free(info);
-}
-
 /**
  * Subtype 0x0003 - Response to SNAC_FAMILY_ICQ/0x002, contains an ICQesque packet.
  */
 static int
-icqresponse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
+icqresponse(OscarData *od, aim_modsnac_t *snac, ByteStream *bs)
 {
-	int ret = 0;
 	GSList *tlvlist;
 	aim_tlv_t *datatlv;
 	ByteStream qbs;
@@ -402,20 +459,21 @@ icqresponse(OscarData *od, FlapConnectio
 
 	if (cmd == 0x07da) { /* information */
 		guint16 subtype;
+		GSList *info_ptr;
 		struct aim_icq_info *info;
 
 		subtype = byte_stream_getle16(&qbs);
 		byte_stream_advance(&qbs, 1); /* 0x0a */
 
 		/* find other data from the same request */
-		for (info = od->icq_info; info && (info->reqid != reqid); info = info->next);
-		if (!info) {
-			info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
-			info->reqid = reqid;
-			info->next = od->icq_info;
-			od->icq_info = info;
+		info_ptr = g_slist_find_custom(od->icq_info, &reqid, compare_icq_infos);
+		if (!info_ptr) {
+			struct aim_icq_info *new_info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
+			new_info->reqid = reqid;
+			info_ptr = od->icq_info = g_slist_prepend(od->icq_info, new_info);
 		}
 
+		info = info_ptr->data;
 		switch (subtype) {
 		case 0x00a0: { /* hide ip status */
 			/* nothing */
@@ -667,8 +725,7 @@ icqresponse(OscarData *od, FlapConnectio
 
 				memcpy(&info->icbm_cookie, cookie, 8);
 
-				info->next = od->icq_info;
-				od->icq_info = info;
+				od->icq_info = g_slist_prepend(od->icq_info, info);
 
 				flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs, FALSE);
 
@@ -688,28 +745,23 @@ icqresponse(OscarData *od, FlapConnectio
 			if (info->uin && info->nick)
 				gotalias(od, info);
 
-			if (od->icq_info == info) {
-				od->icq_info = info->next;
-			} else {
-				struct aim_icq_info *cur;
-				for (cur=od->icq_info; (cur->next && (cur->next!=info)); cur=cur->next);
-				if (cur->next)
-					cur->next = cur->next->next;
-			}
 			aim_icq_freeinfo(info);
+			od->icq_info = g_slist_remove(od->icq_info, info);
 		}
 	}
 
 	aim_tlvlist_free(tlvlist);
 
-	return ret;
+	return 1;
 }
 
 static int
 snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-	if (snac->subtype == 0x0003)
-		return icqresponse(od, conn, mod, frame, snac, bs);
+	if (snac->subtype == 0x0001)
+		return error(od, snac, bs);
+	else if (snac->subtype == 0x0003)
+		return icqresponse(od, snac, bs);
 
 	return 0;
 }
@@ -717,15 +769,10 @@ icq_shutdown(OscarData *od, aim_module_t
 static void
 icq_shutdown(OscarData *od, aim_module_t *mod)
 {
-	struct aim_icq_info *del;
-
-	while (od->icq_info) {
-		del = od->icq_info;
-		od->icq_info = od->icq_info->next;
-		aim_icq_freeinfo(del);
-	}
-
-	return;
+	GSList *cur;
+	for (cur = od->icq_info; cur; cur = cur->next)
+		aim_icq_freeinfo(cur->data);
+	g_slist_free(od->icq_info);
 }
 
 int
============================================================
--- libpurple/protocols/oscar/oscar.h	7c82d9253f035326f3daf134047c6c48fa592dc2
+++ libpurple/protocols/oscar/oscar.h	a502d7c04c7fd459230be88158165a2add4c534f
@@ -542,7 +542,7 @@ struct _OscarData
 	 */
 
 	IcbmCookie *msgcookies;
-	struct aim_icq_info *icq_info;
+	GSList *icq_info;
 
 	/** Only used when connecting with the old-style BUCP login. */
 	struct aim_authresp_info *authinfo;
@@ -1414,9 +1414,6 @@ struct aim_icq_info
 	guint16 numaddresses;
 	char **email2;
 
-	/* we keep track of these in a linked list because we're 1337 */
-	struct aim_icq_info *next;
-
 	/* status note info */
 	guint8 icbm_cookie[8];
 	char *status_note_title;
============================================================
--- libpurple/protocols/oscar/userinfo.c	c31483630ec1ef8caf1405745d361a01835ec000
+++ libpurple/protocols/oscar/userinfo.c	3ce41413aa9f461cb05e512a3cb856d569ab1b99
@@ -369,7 +369,7 @@ void
 }
 
 void
-oscar_user_info_display_error(OscarData *od, guint16 error_reason, char *buddy)
+oscar_user_info_display_error(OscarData *od, guint16 error_reason, gchar *buddy)
 {
 	PurpleNotifyUserInfo *user_info = purple_notify_user_info_new();
 	gchar *buf = g_strdup_printf(_("User information not available: %s"), oscar_get_msgerr_reason(error_reason));
@@ -395,7 +395,7 @@ oscar_user_info_display_icq(OscarData *o
 
 	if (!info->uin)
 		return;
-	
+
 	user_info = purple_notify_user_info_new();
 
 	g_snprintf(who, sizeof(who), "%u", info->uin);


More information about the Commits mailing list