changeset 3141:bcdbffc2c3e6

[gaim-migrate @ 3156] the kingant ate sean's picnic, too committer: Tailor Script <tailor@pidgin.im>
author Rob Flynn <gaim@robflynn.com>
date Fri, 12 Apr 2002 02:43:50 +0000
parents aa18e79365b7
children 71eb7edf0e13
files ChangeLog src/protocols/oscar/aim.h src/protocols/oscar/im.c src/protocols/oscar/oscar.c
diffstat 4 files changed, 265 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Fri Apr 12 02:40:41 2002 +0000
+++ b/ChangeLog	Fri Apr 12 02:43:50 2002 +0000
@@ -12,6 +12,7 @@
  	* Fixed broken signal handling in gdm-started GNOME sessions 
  	  (Thanks Jim Seymour, Vann, Robert McQueen)
 	* Oscar group syncronization (Thanks, Mark Doliner)
+	* ICQ Authorization via Oscar (Thanks, Mark Doliner)
 	
 version 0.55 (03/29/2002):
 	* Jabber improvements (Thanks Jim Seymour)
--- a/src/protocols/oscar/aim.h	Fri Apr 12 02:40:41 2002 +0000
+++ b/src/protocols/oscar/aim.h	Fri Apr 12 02:43:50 2002 +0000
@@ -832,6 +832,17 @@
 	void *destructor; /* used internally only */
 };
 
+/* Valid values for channel 4 args->type */
+#define AIM_ICQMSG_AUTHREQUEST 0x0006
+#define AIM_ICQMSG_AUTHDENIED 0x0007
+#define AIM_ICQMSG_AUTHGRANTED 0x0008
+
+struct aim_incomingim_ch4_args {
+	fu32_t uin; /* Of the sender of the ICBM */
+	fu16_t type;
+	char *msg; /* Reason for auth request, deny, or accept */
+};
+
 faim_export int aim_send_rtfmsg(aim_session_t *sess, struct aim_sendrtfmsg_args *args);
 faim_export int aim_send_im_ext(aim_session_t *sess, struct aim_sendimext_args *args);
 faim_export int aim_send_im(aim_session_t *, const char *destsn, unsigned short flags, const char *msg);
@@ -844,6 +855,7 @@
 faim_export aim_conn_t *aim_directim_connect(aim_session_t *, const char *sn, const char *addr, const fu8_t *cookie);
 
 faim_export aim_conn_t *aim_sendfile_initiate(aim_session_t *, const char *destsn, const char *filename, fu16_t numfiles, fu32_t totsize);
+faim_export int aim_send_im_ch4(aim_session_t *sess, char *sn, fu16_t type, fu8_t *message);
 
 faim_export aim_conn_t *aim_getfile_initiate(aim_session_t *sess, aim_conn_t *conn, const char *destsn);
 faim_export int aim_oft_getfile_request(aim_session_t *sess, aim_conn_t *conn, const char *name, int size);
--- a/src/protocols/oscar/im.c	Fri Apr 12 02:40:41 2002 +0000
+++ b/src/protocols/oscar/im.c	Fri Apr 12 02:43:50 2002 +0000
@@ -732,6 +732,84 @@
 	return 0;
 }
 
+/*
+ * This can be used to send an ICQ authorization reply (deny or grant).  It is the "old way."  
+ * The new way is to use SSI.  I like the new way a lot better.  This seems like such a hack, 
+ * mostly because it's in network byte order.  Figuring this stuff out sometimes takes a while, 
+ * but thats ok, because it gives me time to try to figure out what kind of drugs the AOL people 
+ * were taking when they merged the two protocols.
+ *
+ * sn is the destination screen name
+ * type is the type of message.  0x0007 for authorization denied.  0x0008 for authorization granted
+ * message is the message you want to send, it should be null terminated
+ */
+faim_export int aim_send_im_ch4(aim_session_t *sess, char *sn, fu16_t type, fu8_t *message)
+{
+	aim_conn_t *conn;
+	aim_frame_t *fr;
+	aim_snacid_t snacid;
+	int i;
+
+	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0002)))
+		return -EINVAL;
+
+	if (!sn || !type || !message)
+		return -EINVAL;
+
+	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+3+strlen(sn)+12+strlen(message)+1+4)))
+		return -ENOMEM;
+
+	snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, NULL, 0);
+	aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);
+
+	/*
+	 * Cookie
+	 */
+	for (i=0; i<8; i++)
+		aimbs_put8(&fr->data, (fu8_t)rand());
+
+	/*
+	 * Channel (4)
+	 */
+	aimbs_put16(&fr->data, 0x0004);
+
+	/*
+	 * Dest sn
+	 */
+	aimbs_put8(&fr->data, strlen(sn));
+	aimbs_putraw(&fr->data, sn, strlen(sn));
+
+	/*
+	 * TLV t(0005)
+	 *
+	 * ICQ data (the UIN and the message).
+	 */
+	aimbs_put16(&fr->data, 0x0005);
+	aimbs_put16(&fr->data, 4 + 2+2+strlen(message)+1);
+
+	/*
+	 * Your UIN
+	 */
+	aimbs_putle32(&fr->data, atoi(sess->sn));
+
+	/*
+	 * TLV t(type) l(strlen(message)+1) v(message+NULL)
+	 */
+	aimbs_putle16(&fr->data, type);
+	aimbs_putle16(&fr->data, strlen(message)+1);
+	aimbs_putraw(&fr->data, message, strlen(message)+1);
+
+	/*
+	 * TLV t(0006) l(0000) v()
+	 */
+	aimbs_put16(&fr->data, 0x0006);
+	aimbs_put16(&fr->data, 0x0000);
+
+	aim_tx_enqueue(sess, fr);
+
+	return 0;
+}
+
 static int outgoingim(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
 {
 	int i, ret = 0;
@@ -1519,6 +1597,33 @@
 	return ret;
 }
 
+static int incomingim_ch4(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, fu16_t channel, aim_userinfo_t *userinfo, aim_tlvlist_t *tlvlist, fu8_t *cookie)
+{
+	aim_bstream_t meat;
+	aim_rxcallback_t userfunc;
+	aim_tlv_t *block;
+	struct aim_incomingim_ch4_args args;
+	int ret;
+
+	/*
+	 * Make a bstream for the meaty part.  Yum.  Meat.
+	 */
+	if (!(block = aim_gettlv(tlvlist, 0x0005, 1)))
+		return -1;
+	aim_bstream_init(&meat, block->value, block->length);
+
+	args.uin = aimbs_getle32(&meat);
+	args.type = aimbs_getle16(&meat);
+	args.msg = aimbs_getraw(&meat, aimbs_getle16(&meat));
+
+	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
+		ret = userfunc(sess, rx, channel, userinfo, &args);
+
+	free(args.msg);
+
+	return ret;
+}
+
 /*
  * It can easily be said that parsing ICBMs is THE single
  * most difficult thing to do in the in AIM protocol.  In
@@ -1556,7 +1661,10 @@
 	 * Channel 0x0002 is the Rendevous channel, which
 	 * is where Chat Invitiations and various client-client
 	 * connection negotiations come from.
-	 * 
+	 *
+	 * Channel 0x0004 is used for ICQ authorization, or 
+	 * possibly any system notice.
+	 *
 	 */
 	channel = aimbs_get16(bs);
 
@@ -1602,6 +1710,13 @@
 
 		aim_freetlvchain(&tlvlist);
 
+	} else if (channel == 4) {
+		aim_tlvlist_t *tlvlist;
+
+		tlvlist = aim_readtlvchain(bs);
+		ret = incomingim_ch4(sess, mod, rx, snac, channel, &userinfo, tlvlist, cookie);
+		aim_freetlvchain(&tlvlist);
+
 	} else {
 
 		faimdprintf(sess, 0, "icbm: ICBM received on an unsupported channel.  Ignoring.\n (chan = %04x)", channel);
--- a/src/protocols/oscar/oscar.c	Fri Apr 12 02:40:41 2002 +0000
+++ b/src/protocols/oscar/oscar.c	Fri Apr 12 02:43:50 2002 +0000
@@ -161,6 +161,11 @@
 	gboolean request;
 };
 
+struct icq_auth {
+	struct gaim_connection *gc;
+	fu32_t uin;
+};
+
 static struct direct_im *find_direct_im(struct oscar_data *od, const char *who) {
 	GSList *d = od->direct_ims;
 	char *n = g_strdup(normalize(who));
@@ -1440,6 +1445,77 @@
 	return 1;
 }
 
+static void gaim_icq_authgrant(gpointer w, struct icq_auth *data) {
+	char *uin, message;
+	struct oscar_data *od = (struct oscar_data *)data->gc->proto_data;
+	uin = g_strdup_printf("%d", data->uin);
+	message = 0;
+	aim_send_im_ch4(od->sess, uin, AIM_ICQMSG_AUTHGRANTED, &message);
+	show_got_added(data->gc, NULL, uin, NULL, NULL);
+	g_free(uin);
+	data->uin = 0;
+}
+
+static void gaim_icq_authdeny(gpointer w, struct icq_auth *data) {
+	if (data->uin) {
+		char *uin, *message;
+		struct oscar_data *od = (struct oscar_data *)data->gc->proto_data;
+		uin = g_strdup_printf("%d", data->uin);
+		message = g_strdup_printf("No reason given.");
+		aim_send_im_ch4(od->sess, uin, AIM_ICQMSG_AUTHDENIED, message);
+		g_free(uin);
+		g_free(message);
+	}
+	g_free(data);
+}
+
+/*
+ * For when other people ask you for authorization
+ */
+static void gaim_icq_authask(struct gaim_connection *gc, fu32_t uin, char *msg) {
+	struct icq_auth *data = g_new(struct icq_auth, 1);
+	/* The first 6 chars of the message are some type of alien gibberish, so skip them */
+	char *dialog_msg = g_strdup_printf("The user %d wants to add you to their buddy list for the following reason:\n\n%s", uin, (msg && strlen(msg)>6) ? msg+6 : "No reason given.");
+	debug_printf("Received an authorization request from UIN %ld\n", uin);
+	data->gc = gc;
+	data->uin = uin;
+	do_ask_dialog(dialog_msg, data, gaim_icq_authgrant, gaim_icq_authdeny);
+	g_free(dialog_msg);
+}
+
+static int incomingim_chan4(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch4_args *args) {
+	struct gaim_connection *gc = sess->aux_data;
+
+	switch (args->type) {
+		case 0x0006: { /* Someone requested authorization */
+			gaim_icq_authask(gc, args->uin, args->msg);
+		} break;
+
+		case 0x0007: { /* Someone has denied you authorization */
+			char *dialog_msg;
+			dialog_msg = g_strdup_printf(_("The user %d has denied your request to add them to your contact list for the following reason:\n\n"), args->uin, args->msg ? args->msg : _("No reason given."));
+			do_error_dialog(dialog_msg, _("Gaim - ICQ Authorization Denied"));
+			g_free(dialog_msg);
+		} break;
+
+		case 0x0008: { /* Someone has granted you authorization */
+			char *dialog_msg;
+			dialog_msg = g_strdup_printf(_("The user %d has granted your request to add them to your contact list."), args->uin);
+			do_error_dialog(dialog_msg, _("Gaim - ICQ Authorization Granted"));
+			g_free(dialog_msg);
+		} break;
+
+		case 0x0012: {
+			/* Ack for authorizing/denying someone.  Or possibly an ack for sending any system notice */
+		} break;
+
+		default: {
+			debug_printf("Received a channel 4 message of unknown type (type 0x%04d).\n", args->type);
+		} break;
+	}
+
+	return 1;
+}
 
 static int gaim_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...) {
 	int channel, ret = 0;
@@ -1450,24 +1526,28 @@
 	channel = va_arg(ap, int);
 	userinfo = va_arg(ap, aim_userinfo_t *);
 
-	/* channel 1: standard message */
-	if (channel == 1) {
-		struct aim_incomingim_ch1_args *args;
-
-		args = va_arg(ap, struct aim_incomingim_ch1_args *);
-
-		ret = incomingim_chan1(sess, fr->conn, userinfo, args);
-
-	} else if (channel == 2) {
-		struct aim_incomingim_ch2_args *args;
-
-		args = va_arg(ap, struct aim_incomingim_ch2_args *);
-
-		ret = incomingim_chan2(sess, fr->conn, userinfo, args);
-	} else if (channel == 3) {
-		printf("Chan 3\n");
-	} else if (channel == 4) {
-		printf("Chan 4\n");
+	switch (channel) {
+		case 1: { /* standard message */
+			struct aim_incomingim_ch1_args *args;
+			args = va_arg(ap, struct aim_incomingim_ch1_args *);
+			ret = incomingim_chan1(sess, fr->conn, userinfo, args);
+		} break;
+
+		case 2: { /* rendevous */
+			struct aim_incomingim_ch2_args *args;
+			args = va_arg(ap, struct aim_incomingim_ch2_args *);
+			ret = incomingim_chan2(sess, fr->conn, userinfo, args);
+		} break;
+
+		case 4: { /* ICQ */
+			struct aim_incomingim_ch4_args *args;
+			args = va_arg(ap, struct aim_incomingim_ch4_args *);
+			ret = incomingim_chan4(sess, fr->conn, userinfo, args);
+		} break;
+
+		default: {
+			debug_printf("ICBM received on unsupported channel (channel 0x%04d).", channel);
+		} break;
 	}
 
 	va_end(ap);
@@ -2269,16 +2349,44 @@
 	msg = va_arg(ap, struct aim_icq_offlinemsg *);
 	va_end(ap);
 
-	if (msg->type == 0x0001) {
-		char sender[32];
-		char *tmp = g_strdup(msg->msg);
-		time_t t = get_time(msg->year, msg->month, msg->day, msg->hour, msg->minute, 0);
-		g_snprintf(sender, sizeof(sender), "%lu", msg->sender);
-		strip_linefeed(tmp);
-		serv_got_im(gc, sender, tmp, 0, t, -1);
-		g_free(tmp);
-	} else {
-		debug_printf("unknown offline message type 0x%04x\n", msg->type);
+	debug_printf("Received offline message of type 0x%04x\n", msg->type);
+
+	switch (msg->type) {
+		case 0x0001: { /* Basic offline message */
+			char sender[32];
+			char *dialog_msg = g_strdup(msg->msg);
+			time_t t = get_time(msg->year, msg->month, msg->day, msg->hour, msg->minute, 0);
+			g_snprintf(sender, sizeof(sender), "%lu", msg->sender);
+			strip_linefeed(dialog_msg);
+			serv_got_im(gc, sender, dialog_msg, 0, t, -1);
+			g_free(dialog_msg);
+		} break;
+
+		case 0x0006: { /* Authorization request */
+			gaim_icq_authask(gc, msg->sender, msg->msg);
+		} break;
+
+		case 0x0007: { /* Someone has denied you authorization */
+			char *dialog_msg;
+			dialog_msg = g_strdup_printf(_("The user %d has denied your request to add them to your contact list for the following reason:\n\n"), msg->sender, msg->msg ? msg->msg : _("No reason given."));
+			do_error_dialog(dialog_msg, _("Gaim - ICQ Authorization Denied"));
+			g_free(dialog_msg);
+		} break;
+
+		case 0x0008: { /* Someone has granted you authorization */
+			char *dialog_msg;
+			dialog_msg = g_strdup_printf(_("The user %d has granted your request to add them to your contact list."), msg->sender);
+			do_error_dialog(dialog_msg, _("Gaim - ICQ Authorization Granted"));
+			g_free(dialog_msg);
+		} break;
+
+		case 0x0012: {
+			/* Ack for authorizing/denying someone.  Or possibly an ack for sending any system notice */
+		} break;
+
+		default: {
+			debug_printf("unknown offline message type 0x%04x\n", msg->type);
+		}
 	}
 
 	return 1;