Index: protocols/oscar/im.c
===================================================================
--- protocols/oscar/im.c	(revision bb556db516af064649588a771048b004852e4f49)
+++ protocols/oscar/im.c	(revision 94281efa4280bd3ef1cecb7cd22deca03ecb5935)
@@ -1996,4 +1996,88 @@
 }
 
+/*
+ * Subtype 0x0014 - Send a mini typing notification (mtn) packet.
+ *
+ * This is supported by winaim5 and newer, MacAIM bleh and newer, iChat bleh and newer, 
+ * and Gaim 0.60 and newer.
+ *
+ */
+int aim_im_sendmtn(aim_session_t *sess, guint16 type1, const char *sn, guint16 type2)
+{
+	aim_conn_t *conn;
+	aim_frame_t *fr;
+	aim_snacid_t snacid;
+
+	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0002)))
+		return -EINVAL;
+
+	if (!sn)
+		return -EINVAL;
+
+	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+11+strlen(sn)+2)))
+		return -ENOMEM;
+
+	snacid = aim_cachesnac(sess, 0x0004, 0x0014, 0x0000, NULL, 0);
+	aim_putsnac(&fr->data, 0x0004, 0x0014, 0x0000, snacid);
+
+	/*
+	 * 8 days of light
+	 * Er, that is to say, 8 bytes of 0's
+	 */
+	aimbs_put16(&fr->data, 0x0000);
+	aimbs_put16(&fr->data, 0x0000);
+	aimbs_put16(&fr->data, 0x0000);
+	aimbs_put16(&fr->data, 0x0000);
+
+	/*
+	 * Type 1 (should be 0x0001 for mtn)
+	 */
+	aimbs_put16(&fr->data, type1);
+
+	/*
+	 * Dest sn
+	 */
+	aimbs_put8(&fr->data, strlen(sn));
+	aimbs_putraw(&fr->data, sn, strlen(sn));
+
+	/*
+	 * Type 2 (should be 0x0000, 0x0001, or 0x0002 for mtn)
+	 */
+	aimbs_put16(&fr->data, type2);
+
+	aim_tx_enqueue(sess, fr);
+
+	return 0;
+}
+
+/*
+ * Subtype 0x0014 - Receive a mini typing notification (mtn) packet.
+ *
+ * This is supported by winaim5 and newer, MacAIM bleh and newer, iChat bleh and newer, 
+ * and Gaim 0.60 and newer.
+ *
+ */
+static int mtn_receive(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
+{
+	int ret = 0;
+	aim_rxcallback_t userfunc;
+	char *sn;
+	guint8 snlen;
+	guint16 type1, type2;
+
+	aim_bstream_advance(bs, 8); /* Unknown - All 0's */
+	type1 = aimbs_get16(bs);
+	snlen = aimbs_get8(bs);
+	sn = aimbs_getstr(bs, snlen);
+	type2 = aimbs_get16(bs);
+
+	if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
+		ret = userfunc(sess, rx, type1, sn, type2);
+
+	g_free(sn);
+
+	return ret;
+}
+
 static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
 {
@@ -2011,4 +2095,6 @@
 	else if (snac->subtype == 0x000c)
 		return msgack(sess, mod, rx, snac, bs);
+	else if (snac->subtype == 0x0014)
+		return mtn_receive(sess, mod, rx, snac, bs);
 
 	return 0;
Index: protocols/oscar/im.h
===================================================================
--- protocols/oscar/im.h	(revision bb556db516af064649588a771048b004852e4f49)
+++ protocols/oscar/im.h	(revision 94281efa4280bd3ef1cecb7cd22deca03ecb5935)
@@ -14,4 +14,5 @@
 #define AIM_CB_MSG_CLIENTAUTORESP 0x000b
 #define AIM_CB_MSG_ACK 0x000c
+#define AIM_CB_MSG_MTN 0x0014
 #define AIM_CB_MSG_DEFAULT 0xffff
 
@@ -194,4 +195,5 @@
 
 int aim_send_im_ch2_geticqmessage(aim_session_t *sess, const char *sn, int type);
+int aim_im_sendmtn(aim_session_t *sess, guint16 type1, const char *sn, guint16 type2);
 int aim_send_im_ch2_statusmessage(aim_session_t *sess, const char *sender, const guint8 *cookie, const char *message, const guint8 state, const guint16 dc);
 
Index: protocols/oscar/oscar.c
===================================================================
--- protocols/oscar/oscar.c	(revision bb556db516af064649588a771048b004852e4f49)
+++ protocols/oscar/oscar.c	(revision 94281efa4280bd3ef1cecb7cd22deca03ecb5935)
@@ -221,5 +221,5 @@
 static int gaim_ssi_parselist    (aim_session_t *, aim_frame_t *, ...);
 static int gaim_ssi_parseack     (aim_session_t *, aim_frame_t *, ...);
-
+static int gaim_parsemtn         (aim_session_t *, aim_frame_t *, ...);
 static int gaim_icqinfo          (aim_session_t *, aim_frame_t *, ...);
 static int gaim_parseaiminfo     (aim_session_t *, aim_frame_t *, ...);
@@ -558,4 +558,5 @@
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_SRVACK, gaim_ssi_parseack, 0);
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, gaim_parseaiminfo, 0);
+	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MTN, gaim_parsemtn, 0);
 
 	((struct oscar_data *)gc->proto_data)->conn = bosconn;
@@ -1678,4 +1679,5 @@
 
 	/* Maybe senderwarn and recverwarn should be user preferences... */
+	params->flags = 0x0000000b;
 	params->maxmsglen = 8000;
 	params->minmsginterval = 0;
@@ -2435,4 +2437,23 @@
 }
 
+int gaim_parsemtn(aim_session_t *sess, aim_frame_t *fr, ...)
+{
+	struct gaim_connection * gc = sess->aux_data;
+	va_list ap;
+	guint16 type1, type2;
+	char * sn;
+
+	va_start(ap, fr);
+	type1 = va_arg(ap, int);
+	sn = va_arg(ap, char*);
+	type2 = va_arg(ap, int);
+	va_end(ap);
+
+	if(type2 == 0x0001 || type2 == 0x0002)
+		serv_got_typing(gc, sn, 0);
+
+	return 1;
+}
+
 static char *oscar_get_status_string( struct gaim_connection *gc, int number )
 {
@@ -2461,4 +2482,10 @@
 		return( "Away" );
 	}
+}
+
+int oscar_send_typing(struct gaim_connection *gc, char * who, int typing)
+{
+	struct oscar_data *od = gc->proto_data;
+	return( aim_im_sendmtn(od->sess, 1, who, typing ? 0x0002 : 0x0000) );
 }
 
@@ -2485,4 +2512,6 @@
 	ret->get_status_string = oscar_get_status_string;
 
+	ret->send_typing = oscar_send_typing;
+
 	my_protocol = ret;
 }
