changeset 14049:8294485b79db

[gaim-migrate @ 16662] Enhanced protocol testing tools, primarily by designing a more useful interface for sending customized packets. committer: Tailor Script <tailor@pidgin.im>
author Mark Huetsch <markhuetsch>
date Mon, 07 Aug 2006 06:17:13 +0000
parents 9c4bec886220
children 6342ffdeb3ac
files src/protocols/qq/qq.c src/protocols/qq/recv_core.c src/protocols/qq/send_core.h src/protocols/qq/utils.c src/protocols/qq/utils.h
diffstat 5 files changed, 167 insertions(+), 55 deletions(-) [+]
line wrap: on
line diff
--- a/src/protocols/qq/qq.c	Mon Aug 07 03:24:39 2006 +0000
+++ b/src/protocols/qq/qq.c	Mon Aug 07 06:17:13 2006 +0000
@@ -28,6 +28,7 @@
 
 #include "accountopt.h"
 #include "debug.h"
+#include "gtkroomlist.h"
 #include "notify.h"
 #include "prefs.h"
 #include "prpl.h"
@@ -586,12 +587,10 @@
 }
 */
 
-/*
 static void _qq_menu_search_or_add_permanent_group(GaimPluginAction * action)
 {
 	gaim_gtk_roomlist_dialog_show();
 }
-*/
 
 /*
 static void _qq_menu_create_permanent_group(GaimPluginAction * action)
@@ -659,57 +658,160 @@
 //	}
 }
 */
-/*
-static void _qq_send_custom_packet(GaimConnection *gc, const gchar *packet)
+
+static gboolean _qq_parse_custom_packet_field(GaimRequestFields *fields,
+		const gchar *id, guint8 **value)
 {
-	guint16 cmd;
-	guint8 *buffer;
-	gint len;
+	GaimRequestField *field;
+	const gchar *str;
+	gint len, i;
+	gboolean success;
+
+	success = FALSE;
+	field = gaim_request_fields_get_field(fields, id);
+	str = gaim_request_field_string_get_value(field);
+	if (str) {
+		success = TRUE;
+		if (strcmp(id, "uid") != 0) {
+			*value = hex_str_to_bytes(str, &len);
+			if (!*value || len != 2)
+				success = FALSE;
+		} else {
+			for (i = 0; i < strlen(str); i++) {
+				if (!g_ascii_isdigit(str[i])) {
+					success = FALSE;
+					break;
+				}
+			}
+			if (success) {
+				*(guint32 *) value = strtoul(str, NULL, 10);
+				if (errno == ERANGE)
+					success = FALSE;
+			}
+		}
+	}
+	if (!success)
+		gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Invalid entry: %s\n", id);
+	return success;
+}
 
-	if (!packet) {
-		gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Null packet inputted!\n");
-		return;
+static gboolean _qq_parse_custom_packet_fields(GaimRequestFields *fields,
+		guint8 **client, guint8 **cmd, guint8 **seq, guint32 *uid, 
+		guint8 **body, gint *body_len)
+{
+	GaimRequestField *field;
+	gboolean success;
+
+	success = TRUE;
+	*client = *cmd = *seq = *body = NULL;
+	*uid = 0;
+	success = _qq_parse_custom_packet_field(fields, "client", client);
+	if (success)
+		success = _qq_parse_custom_packet_field(fields, "cmd", cmd);
+	if (success)
+		success = _qq_parse_custom_packet_field(fields, "uid", (guint8 **) uid);
+	if (success)
+		success = _qq_parse_custom_packet_field(fields, "seq", seq);
+	if (success) {
+		field = gaim_request_fields_get_field(fields, "body");
+		*body = hex_str_to_bytes(gaim_request_field_string_get_value(field), 
+				body_len);
+	} else {
+		if (*client)
+			g_free(*client);
+		if (*cmd)
+			g_free(*cmd);
+		if (*seq)
+			g_free(*seq);
 	}
-	if (strlen(packet) > MAX_PACKET_SIZE * 2) {
-		gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Packet inputted is too large!\n");
-		return;
-	}
-	if (strlen(packet) < 4) {
-		gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Packet is impossibly short!\n");
+	return success;
+}
+
+static void _qq_send_custom_packet_cb(GaimConnection *gc, GaimRequestFields *fields)
+{
+	guint32 uid;
+	guint8 *buf, *client, *cmd, *seq, *body, *cursor;
+	gint bytes, len;
+	qq_data *qd;
+	gboolean success;
+
+	qd = (qq_data *) gc->proto_data;
+
+	success = _qq_parse_custom_packet_fields(fields, &client, &cmd, 
+			&seq, &uid, &body, &len);
+	if (!success) {
+		gaim_notify_error(gc, _("Error"), _("Invalid packet entry"), NULL);
 		return;
 	}
 
-	buffer = hex_str_to_bytes(packet);
-	if (!buffer) {
-		gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Invalid packet inputted!\n");
-		return;
-	}
-	// big endian
-	cmd = 256 * buffer[0] + buffer[1];
-	gaim_debug(GAIM_DEBUG_INFO, "QQ", "Inputted CMD: %d\n", cmd);
+	if (body)
+		g_return_if_fail(len+12 <= MAX_PACKET_SIZE);
 
-	len = strlen(buffer) - 2;
-	packet = buffer + 2;
+	bytes = 0;
+	buf = g_newa(guint8, MAX_PACKET_SIZE);
+	cursor = buf;
+        /* QQ TCP packet has two bytes in the beginning to define packet length
+	 * so I leave room here for size */
+	if (qd->use_tcp)
+		bytes += create_packet_w(buf, &cursor, 0x0000);
+	bytes += create_packet_b(buf, &cursor, QQ_PACKET_TAG);
+	bytes += create_packet_w(buf, &cursor, *(guint16 *) client);
+	bytes += create_packet_w(buf, &cursor, *(guint16 *) cmd);
+	bytes += create_packet_w(buf, &cursor, *(guint16 *) seq);
+	bytes += create_packet_dw(buf, &cursor, uid);
+	if (body) {
+		bytes += create_packet_data(buf, &cursor, body, len);
+		g_free(body);
+	}
+	bytes += create_packet_b(buf, &cursor, QQ_PACKET_TAIL);
 
-	qq_send_cmd(gc, cmd, TRUE, 0, TRUE, packet, len);
-
-	g_free(buffer);
+	gaim_debug(GAIM_DEBUG_INFO, "QQ", "Custom packet of length %i\n", bytes);
+	_qq_show_packet("Outgoing custom packet", buf, bytes);
+	
+	_qq_send_packet(gc, buf, bytes, *(guint16 *) cmd);
+	g_free(client);
+	g_free(cmd);
+	g_free(seq);
 }
-*/
 
 /* send a custom packet to the server - for protocol testing */
-/*
 static void _qq_menu_send_custom_packet(GaimPluginAction *action)
 {
-	GaimConnection *gc = (GaimConnection *) action->context;
-	g_return_if_fail(gc != NULL);
-	gaim_request_input(gc, _("Send Custom Packet"),
-			   _("Enter the packet in hex here"),
-			   _("Include the command and everything following"),
-			   NULL, FALSE, FALSE, NULL,
-			   _("Send"), G_CALLBACK(_qq_send_custom_packet), _("Cancel"), NULL, gc);
+	GaimConnection *gc;
+	GaimRequestFields *fields;
+	GaimRequestFieldGroup *group;
+	GaimRequestField *field;
+	gchar *tmp;
+	qq_data *qd;
+       
+	gc = (GaimConnection *) action->context;
+	qd = (qq_data *) gc->proto_data;
+	g_return_if_fail(gc != NULL && qd != NULL);
+
+	fields = gaim_request_fields_new();
+	group = gaim_request_field_group_new(_("Packet Elements"));
+	gaim_request_fields_add_group(fields, group);
+	tmp = g_strdup_printf("%04X", QQ_CLIENT);
+	field = gaim_request_field_string_new("client", _("Client (hex)"), tmp, FALSE);
+	g_free(tmp);
+	gaim_request_field_group_add_field(group, field);
+	field = gaim_request_field_string_new("cmd", _("Command (hex)"), "0000", FALSE);
+	gaim_request_field_group_add_field(group, field);
+	field = gaim_request_field_string_new("seq", _("Sequence (hex)"), "0000", FALSE);
+	gaim_request_field_group_add_field(group, field);
+	tmp = g_strdup_printf("%u", qd->uid);
+	field = gaim_request_field_string_new("uid", _("QQ Number (decimal)"), tmp, FALSE);
+	g_free(tmp);
+	gaim_request_field_group_add_field(group, field);
+	field = gaim_request_field_string_new("body", _("Body (hex)"), NULL, FALSE);
+	gaim_request_field_group_add_field(group, field);
+
+	gaim_request_fields(gc, _("Send a custom packet"),
+			_("Send a custom packet"), NULL, fields,
+			_("Send"), G_CALLBACK(_qq_send_custom_packet_cb),
+			_("Cancel"), NULL,
+			gc);
 }
-*/
 
 /* protocol related menus */
 static GList *_qq_actions(GaimPlugin *plugin, gpointer context)
@@ -727,7 +829,7 @@
 	act = gaim_plugin_action_new(_("Show Login Information"), _qq_menu_show_login_info);
 	m = g_list_append(m, act);
 
-	/* 
+	/*
 	act = gaim_plugin_action_new(_("Send Custom Packet"), _qq_menu_send_custom_packet);
 	m = g_list_append(m, act);
 	*/
@@ -737,7 +839,7 @@
 	m = g_list_append(m, act);
 	*/
 
-	/* XXX the old group gtk code needs to moved to the gaim UI before this can be used
+	/*
 	act = gaim_plugin_action_new(_("Qun: Search a permanent Qun"), _qq_menu_search_or_add_permanent_group);
 	m = g_list_append(m, act);
 
--- a/src/protocols/qq/recv_core.c	Mon Aug 07 03:24:39 2006 +0000
+++ b/src/protocols/qq/recv_core.c	Mon Aug 07 06:17:13 2006 +0000
@@ -90,6 +90,7 @@
 	data = g_newa(guint8, len);
 	msg_utf8 = NULL;
 
+	_qq_show_packet("Processing unknown packet", buf, len);
 	if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) {
 		gaim_debug(GAIM_DEBUG_WARNING, "QQ",
 			   ">>> [%d] %s, %d bytes -> [default] decrypt and dump\n%s",
--- a/src/protocols/qq/send_core.h	Mon Aug 07 03:24:39 2006 +0000
+++ b/src/protocols/qq/send_core.h	Mon Aug 07 06:17:13 2006 +0000
@@ -28,9 +28,10 @@
 
 
 #define	QQ_CLIENT	0x0E1B
+/* #define	QQ_CLIENT	0x0F3F */
 
-gint
-qq_send_cmd(GaimConnection *gc,
-	    guint16 cmd, gboolean is_auto_seq, guint16 seq, gboolean need_ack, guint8 *data, gint len);
+gint qq_send_cmd(GaimConnection *gc, guint16 cmd, gboolean is_auto_seq, guint16 seq, 
+		gboolean need_ack, guint8 *data, gint len);
+gint _qq_send_packet(GaimConnection * gc, guint8 *buf, gint len, guint16 cmd);
 
 #endif
--- a/src/protocols/qq/utils.c	Mon Aug 07 03:24:39 2006 +0000
+++ b/src/protocols/qq/utils.c	Mon Aug 07 06:17:13 2006 +0000
@@ -199,6 +199,8 @@
 	gchar *ret;
 	int i;
 
+	g_return_val_if_fail(buffer != NULL, NULL);
+
         stripped = g_string_new("");
         for (i=0; i<strlen(buffer); i++) {
                 if ((int) buffer[i] != 32) {
@@ -214,12 +216,14 @@
 /* Dumps an ASCII hex string to a string of bytes. The return should be freed later.
  * Returns NULL if a string with an odd number of nibbles is passed in or if buffer 
  * isn't a valid hex string */
-guint8 *hex_str_to_bytes(const gchar *buffer)
+guint8 *hex_str_to_bytes(const gchar *buffer, gint *out_len)
 {
 	gchar *hex_str, *hex_buffer, *cursor, tmp;
 	guint8 *bytes, nibble1, nibble2;
-	gint index, len;
+	gint index;
 
+	g_return_val_if_fail(buffer != NULL, NULL);
+	
 	hex_buffer = strstrip(buffer);
 
 	if (strlen(hex_buffer) % 2 != 0) {
@@ -233,10 +237,11 @@
 	g_free(hex_buffer);
 	index = 0;
 	for (cursor = hex_str; cursor < hex_str + sizeof(gchar) * (strlen(hex_str)) - 1; cursor++) {
-		if (g_ascii_isdigit(*cursor)) {tmp = *cursor; nibble1 = atoi(&tmp); }
-		else if (g_ascii_isalpha(*cursor) && (gint) *cursor - 87 < 16)
+		if (g_ascii_isdigit(*cursor)) {
+			tmp = *cursor; nibble1 = atoi(&tmp);
+		} else if (g_ascii_isalpha(*cursor) && (gint) *cursor - 87 < 16) {
 			nibble1 = (gint) *cursor - 87;
-		else {
+		} else {
 			gaim_debug(GAIM_DEBUG_WARNING, "QQ",
 				"Invalid char found in hex string!\n");
 			g_free(hex_str);
@@ -244,18 +249,21 @@
 		}
 		nibble1 = nibble1 << 4;
 		cursor++;
-		if (g_ascii_isdigit(*cursor)) {tmp = *cursor; nibble2 = atoi(&tmp); }
-		else if (g_ascii_isalpha(*cursor) && (gint) (*cursor - 87) < 16)
+		if (g_ascii_isdigit(*cursor)) {
+			tmp = *cursor; nibble2 = atoi(&tmp);
+		} else if (g_ascii_isalpha(*cursor) && (gint) (*cursor - 87) < 16) {
 			nibble2 = (gint) *cursor - 87;
-		else {
+		} else {
+			gaim_debug(GAIM_DEBUG_WARNING, "QQ",
+				"Invalid char found in hex string!\n");
 			g_free(hex_str);
 			return NULL;
 		}
 		bytes[index++] = nibble1 + nibble2;
 	}
-	len = strlen(hex_str) / 2;
+	*out_len = strlen(hex_str) / 2;
 	g_free(hex_str);
-	return g_memdup(bytes, len);
+	return g_memdup(bytes, *out_len);
 }
 
 /* Dumps a chunk of raw data into an ASCII hex string. The return should be freed later. */
--- a/src/protocols/qq/utils.h	Mon Aug 07 03:24:39 2006 +0000
+++ b/src/protocols/qq/utils.h	Mon Aug 07 06:17:13 2006 +0000
@@ -43,7 +43,7 @@
 
 void try_dump_as_gbk(guint8 *data, gint len);
 
-guint8 *hex_str_to_bytes(const gchar *buf);
+guint8 *hex_str_to_bytes(const gchar *buf, gint *out_len);
 gchar *hex_dump_to_str(const guint8 *buf, gint buf_len);
 
 #endif