changeset 1746:bacb77b0eb06

[gaim-migrate @ 1756] this won't help. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Wed, 25 Apr 2001 01:53:56 +0000
parents c39cc2b44226
children 0763e0d4addd
files libfaim/CHANGES libfaim/aim.h libfaim/bos.c libfaim/chat.c libfaim/im.c libfaim/login.c src/oscar.c
diffstat 7 files changed, 379 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/libfaim/CHANGES	Tue Apr 24 23:23:40 2001 +0000
+++ b/libfaim/CHANGES	Wed Apr 25 01:53:56 2001 +0000
@@ -1,6 +1,33 @@
 
 No release numbers
 ------------------
+ - Tue Apr 24 17:36:03 PDT 2001
+  - Let Eric generate the hash if he wants.
+
+ - Mon Apr 23 15:58:11 PDT 2001
+  - On a clear day, you can see forever.
+
+ - Thu Mar 29 13:05:50 PST 2001
+  - Less leaks.
+
+ - Thu Mar 29 14:45:22 CST 2001 (jbm)
+  - Add module capability to the 0001/001f stuff (jbm)
+
+ - Wed Mar 28 21:20:08 PST 2001
+  - Add flags arg to aim_chat_send_im()
+  - Add msglen arg to aim_send_im and aim_chat_send_im
+     - This will make more sense when I make the UNICODE commit (tomorrow?)
+
+ - Wed Mar 28 16:51:25 PST 2001
+  - I decided it was a good day while I was figuring out that it was a bad day.
+  - See faimtest and login.c::memrequest().
+  - Hopefully I'm done for a while.
+
+ - Tue Mar 27 19:15:10 PST 2001
+  - I haven't decided yet whether today is a good day or a bad day.
+  - Probably both.
+  - More later.
+
  -  Mon Mar 26 16:08:45 PST 2001
   - Why didn't anyone tell me buddy-offgoing wasn't working?
     - *** REQUIRES CLIENT CHANGES... buddy-offgoing now passes a userinfo
--- a/libfaim/aim.h	Tue Apr 24 23:23:40 2001 +0000
+++ b/libfaim/aim.h	Wed Apr 25 01:53:56 2001 +0000
@@ -169,7 +169,7 @@
   long unknown;
 };
 
-#define AIM_CLIENTINFO_KNOWNGOOD { \
+#define AIM_CLIENTINFO_KNOWNGOOD_3_5_1670 { \
   "AOL Instant Messenger (SM), version 3.5.1670/WIN32", \
   0x0003, \
   0x0005, \
@@ -181,6 +181,28 @@
   0x0000002a, \
 }
 
+#define AIM_CLIENTINFO_KNOWNGOOD_4_1_2010 { \
+  "AOL Instant Messenger (SM), version 4.1.2010/WIN32", \
+  0x0004, \
+  0x0001, \
+  0x07da, \
+  "us", \
+  "en", \
+  0x0004, \
+  0x0000, \
+  0x0000004b, \
+}
+
+/*
+ * I would make 4.1.2010 the default, but they seem to have found
+ * an alternate way of breaking that one. 
+ *
+ * 3.5.1670 should work fine, however, you will be subjected to the
+ * memory test, which may require you to have a WinAIM binary laying 
+ * around. (see login.c::memrequest())
+ */
+#define AIM_CLIENTINFO_KNOWNGOOD AIM_CLIENTINFO_KNOWNGOOD_3_5_1670
+
 #ifndef TRUE
 #define TRUE 1
 #define FALSE 0
@@ -615,7 +637,7 @@
 #define AIM_IMFLAGS_AWAY 0x01 /* mark as an autoreply */
 #define AIM_IMFLAGS_ACK  0x02 /* request a receipt notice */
 
-faim_export unsigned long aim_send_im(struct aim_session_t *, struct aim_conn_t *, char *, u_int, char *);
+faim_export unsigned long aim_send_im(struct aim_session_t *, struct aim_conn_t *, const char *destsn, unsigned short flags, const char *msg, int msglen);
 faim_export int aim_send_im_direct(struct aim_session_t *, struct aim_conn_t *, char *);
 faim_export struct aim_conn_t * aim_directim_initiate(struct aim_session_t *, struct aim_conn_t *, struct aim_directim_priv *, char *destsn);
 faim_export struct aim_conn_t *aim_directim_connect(struct aim_session_t *, struct aim_conn_t *, struct aim_directim_priv *);
@@ -637,7 +659,11 @@
 #define AIM_CAPS_SAVESTOCKS 0x80
 
 faim_export int aim_0002_000b(struct aim_session_t *sess, struct aim_conn_t *conn, const char *sn);
-faim_export int aim_0001_0020(struct aim_session_t *sess, struct aim_conn_t *conn);
+
+#define AIM_SENDMEMBLOCK_FLAG_ISREQUEST  0
+#define AIM_SENDMEMBLOCK_FLAG_ISHASH     1
+
+faim_export int aim_sendmemblock(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned long offset, unsigned long len, const unsigned char *buf, unsigned char flag);
 
 #define AIM_GETINFO_GENERALINFO 0x00001
 #define AIM_GETINFO_AWAYMESSAGE 0x00003
@@ -714,7 +740,9 @@
   char *lang2;
 };
 
-faim_export unsigned long aim_chat_send_im(struct aim_session_t *sess, struct aim_conn_t *conn, char *msg);
+#define AIM_CHATFLAGS_NOREFLECT 0x0001
+#define AIM_CHATFLAGS_AWAY      0x0002
+faim_export unsigned long aim_chat_send_im(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned short flags, const char *msg, int msglen);
 faim_export unsigned long aim_chat_join(struct aim_session_t *sess, struct aim_conn_t *conn, u_short exchange, const char *roomname);
 faim_export unsigned long aim_chat_clientready(struct aim_session_t *sess, struct aim_conn_t *conn);
 faim_export int aim_chat_attachname(struct aim_conn_t *conn, char *roomname);
--- a/libfaim/bos.c	Tue Apr 24 23:23:40 2001 +0000
+++ b/libfaim/bos.c	Wed Apr 25 01:53:56 2001 +0000
@@ -19,34 +19,6 @@
   return aim_genericreq_l(sess, conn, 0x0009, 0x0004, &mask);
 }
 
-faim_export int aim_0001_0020(struct aim_session_t *sess, struct aim_conn_t *conn)
-{
-    struct command_tx_struct *tx;
-  int i = 0;
-
-  if (!sess || !conn)
-    return 0;
-
-  if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+2+16)))
-    return -1;
-
-  tx->lock = 1;
-
-  /* Hummm.... */
-  i = aim_putsnac(tx->data, 0x0001, 0x0020, 0x0000, sess->snac_nextid++);
-  i += aimutil_put16(tx->data+i, 0x0010);
-  i += aimutil_put32(tx->data+i, 0xd41d8cd9);
-  i += aimutil_put32(tx->data+i, 0x8f00b204);
-  i += aimutil_put32(tx->data+i, 0xe9800998);
-  i += aimutil_put32(tx->data+i, 0xecf8427e);
-  
-  tx->commandlen = i;
-  tx->lock = 0;
-  aim_tx_enqueue(sess, tx);
-
-  return 0;
-}
-
 static int rights(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen)
 {
   rxcallback_t userfunc;
--- a/libfaim/chat.c	Tue Apr 24 23:23:40 2001 +0000
+++ b/libfaim/chat.c	Wed Apr 25 01:53:56 2001 +0000
@@ -51,17 +51,30 @@
   return 0;
 }
 
-/* XXX convert this to use tlvchains */
+/*
+ * Send a Chat Message.
+ *
+ * Possible flags:
+ *   AIM_CHATFLAGS_NOREFLECT   --  Unset the flag that requests messages
+ *                                 should be sent to their sender.
+ *   AIM_CHATFLAGS_AWAY        --  Mark the message as an autoresponse
+ *                                 (Note that WinAIM does not honor this,
+ *                                 and displays the message as normal.)
+ *
+ * XXX convert this to use tlvchains 
+ */
 faim_export unsigned long aim_chat_send_im(struct aim_session_t *sess,
 					   struct aim_conn_t *conn, 
-					   char *msg)
+					   unsigned short flags,
+					   const char *msg,
+					   int msglen)
 {   
 
   int curbyte,i;
   struct command_tx_struct *newpacket;
   struct aim_msgcookie_t *cookie;
 
-  if (!sess || !conn || !msg)
+  if (!sess || !conn || !msg || (msglen <= 0))
     return 0;
   
   if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152)))
@@ -90,16 +103,26 @@
   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
 
   /*
-   * Type 1: Unknown.  Blank.
+   * Type 1: Flag meaning this message is destined to the room.
    */
   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001);
   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
   
   /*
-   * Type 6: Unknown.  Blank.
+   * Type 6: Reflect
    */
-  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0006);
-  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
+  if (!(flags & AIM_CHATFLAGS_NOREFLECT)) {
+    curbyte += aimutil_put16(newpacket->data+curbyte, 0x0006);
+    curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
+  }
+
+  /*
+   * Type 7: Autoresponse
+   */
+  if (flags & AIM_CHATFLAGS_AWAY) {
+    curbyte += aimutil_put16(newpacket->data+curbyte, 0x0007);
+    curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
+  }
 
   /*
    * Type 5: Message block.  Contains more TLVs.
--- a/libfaim/im.c	Tue Apr 24 23:23:40 2001 +0000
+++ b/libfaim/im.c	Wed Apr 25 01:53:56 2001 +0000
@@ -75,18 +75,18 @@
  *                        when the message is received (of type 0x0004/0x000c)
  *
  */
-faim_export unsigned long aim_send_im(struct aim_session_t *sess,
-				      struct aim_conn_t *conn, 
-				      char *destsn, u_int flags, char *msg)
-{   
-
+faim_export unsigned long aim_send_im(struct aim_session_t *sess, struct aim_conn_t *conn, const char *destsn, unsigned short flags, const char *msg, int msglen)
+{
   int curbyte,i;
   struct command_tx_struct *newpacket;
-  
-  if (strlen(msg) >= MAXMSGLEN)
+
+  if (!msg || (msglen <= 0))
     return -1;
 
-  if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, strlen(msg)+256)))
+  if (msglen >= MAXMSGLEN)
+    return -1;
+
+  if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, msglen+256)))
     return -1;
 
   newpacket->lock = 1; /* lock struct */
@@ -122,7 +122,7 @@
    * metaTLV start.
    */
   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
-  curbyte += aimutil_put16(newpacket->data+curbyte, strlen(msg) + 0x10);
+  curbyte += aimutil_put16(newpacket->data+curbyte, msglen + 0x10);
 
   /*
    * Flag data / ICBM Parameters?
@@ -145,7 +145,7 @@
   /* 
    * Message block length.
    */
-  curbyte += aimutil_put16(newpacket->data+curbyte, strlen(msg) + 0x04);
+  curbyte += aimutil_put16(newpacket->data+curbyte, msglen + 0x04);
 
   /*
    * Character set data? 
@@ -156,7 +156,7 @@
   /*
    * Message.  Not terminated.
    */
-  curbyte += aimutil_putstr(newpacket->data+curbyte,msg, strlen(msg));
+  curbyte += aimutil_putstr(newpacket->data+curbyte,msg, msglen);
 
   /*
    * Set the Request Acknowledge flag.  
--- a/libfaim/login.c	Tue Apr 24 23:23:40 2001 +0000
+++ b/libfaim/login.c	Wed Apr 25 01:53:56 2001 +0000
@@ -121,9 +121,9 @@
  *  
  * This is the initial login request packet.
  *
- * The password is encoded before transmition, as per
- * encode_password().  See that function for their
- * stupid method of doing it.
+ * NOTE!! If you want/need to make use of the aim_sendmemblock() function,
+ * then the client information you send here must exactly match the
+ * executable that you're pulling the data from.
  *
  * Latest WinAIM:
  *   clientstring = "AOL Instant Messenger (SM), version 4.3.2188/WIN32"
@@ -138,6 +138,15 @@
  *   unknown4a = 0x01
  *
  * Latest WinAIM that libfaim can emulate without server-side buddylists:
+ *   clientstring = "AOL Instant Messenger (SM), version 4.1.2010/WIN32"
+ *   major2 = 0x0004
+ *   major  = 0x0004
+ *   minor  = 0x0001
+ *   minor2 = 0x0000
+ *   build  = 0x07da
+ *   unknown= 0x0000004b
+ *
+ * WinAIM 3.5.1670:
  *   clientstring = "AOL Instant Messenger (SM), version 3.5.1670/WIN32"
  *   major2 = 0x0004
  *   major =  0x0003
@@ -146,6 +155,25 @@
  *   build =  0x0686
  *   unknown =0x0000002a
  *
+ * Java AIM 1.1.19:
+ *   clientstring = "AOL Instant Messenger (TM) version 1.1.19 for Java built 03/24/98, freeMem 215871 totalMem 1048567, i686, Linus, #2 SMP Sun Feb 11 03:41:17 UTC 2001 2.4.1-ac9, IBM Corporation, 1.1.8, 45.3, Tue Mar 27 12:09:17 PST 2001"
+ *   major2 = 0x0001
+ *   major  = 0x0001
+ *   minor  = 0x0001
+ *   minor2 = (not sent)
+ *   build  = 0x0013
+ *   unknown= (not sent)
+ *   
+ * AIM for Linux 1.1.112:
+ *   clientstring = "AOL Instant Messenger (SM)"
+ *   major2 = 0x1d09
+ *   major  = 0x0001
+ *   minor  = 0x0001
+ *   minor2 = 0x0001
+ *   build  = 0x0070
+ *   unknown= 0x0000008b
+ *   serverstore = 0x01
+ *
  */
 faim_export int aim_send_login (struct aim_session_t *sess,
 				struct aim_conn_t *conn, 
@@ -646,6 +674,164 @@
   return 0;
 }
 
+/*
+ * Starting this past week (26 Mar 2001, say), AOL has started sending
+ * this nice little extra SNAC.  AFAIK, it has never been used until now.
+ *
+ * The request contains eight bytes.  The first four are an offset, the
+ * second four are a length.
+ *
+ * The offset is an offset into aim.exe when it is mapped during execution
+ * on Win32.  So far, AOL has only been requesting bytes in static regions
+ * of memory.  (I won't put it past them to start requesting data in
+ * less static regions -- regions that are initialized at run time, but still
+ * before the client recieves this request.)
+ *
+ * When the client recieves the request, it adds it to the current ds
+ * (0x00400000) and dereferences it, copying the data into a buffer which
+ * it then runs directly through the MD5 hasher.  The 16 byte output of
+ * the hash is then sent back to the server.
+ *
+ * If the client does not send any data back, or the data does not match
+ * the data that the specific client should have, the client will get the
+ * following message from "AOL Instant Messenger":
+ *    "You have been disconnected from the AOL Instant Message Service (SM) 
+ *     for accessing the AOL network using unauthorized software.  You can
+ *     download a FREE, fully featured, and authorized client, here 
+ *     http://www.aol.com/aim/download2.html"
+ * The connection is then closed, recieving disconnect code 1, URL
+ * http://www.aim.aol.com/errors/USER_LOGGED_OFF_NEW_LOGIN.html.  
+ *
+ * Note, however, that numerous inconsistencies can cause the above error, 
+ * not just sending back a bad hash.  Do not immediatly suspect this code
+ * if you get disconnected.  AOL and the open/free software community have
+ * played this game for a couple years now, generating the above message
+ * on numerous ocassions.
+ *
+ * Anyway, neener.  We win again.
+ *
+ */
+static int memrequest(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen)
+{
+  rxcallback_t userfunc;
+  unsigned long offset, len;
+  int i = 0;
+  struct aim_tlvlist_t *list;
+  char *modname = NULL;
+
+  offset = aimutil_get32(data);
+  i += 4;
+
+  len = aimutil_get32(data+4);
+  i += 4;
+
+  list = aim_readtlvchain(data+i, datalen-i);
+
+  if (aim_gettlv(list, 0x0001, 1))
+    modname = aim_gettlv_str(list, 0x0001, 1);
+
+  faimdprintf(sess, 1, "data at 0x%08lx (%d bytes) of requested\n", offset, len, modname?modname:"aim.exe");
+
+  if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
+    return userfunc(sess, rx, offset, len, modname);
+
+  free(modname);
+  aim_freetlvchain(&list);
+
+  return 0;
+}
+
+static void dumpbox(struct aim_session_t *sess, unsigned char *buf, int len)
+{
+  int i = 0;
+
+  if (!sess || !buf || !len)
+    return;
+
+  faimdprintf(sess, 1, "\nDump of %d bytes at %p:", len, buf);
+
+  for (i = 0; i < len; i++)
+    {
+      if ((i % 8) == 0)
+	faimdprintf(sess, 1, "\n\t");
+
+      faimdprintf(sess, 1, "0x%2x ", buf[i]);
+    }
+  
+  faimdprintf(sess, 1, "\n\n");
+
+  return;
+}
+
+faim_export int aim_sendmemblock(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned long offset, unsigned long len, const unsigned char *buf, unsigned char flag)
+{
+  struct command_tx_struct *tx;
+  int i = 0;
+
+  if (!sess || !conn || ((offset == 0) && !buf))
+    return 0;
+
+  if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+2+16)))
+    return -1;
+
+  tx->lock = 1;
+
+  i = aim_putsnac(tx->data, 0x0001, 0x0020, 0x0000, sess->snac_nextid++);
+  i += aimutil_put16(tx->data+i, 0x0010); /* md5 is always 16 bytes */
+
+  if ((flag == AIM_SENDMEMBLOCK_FLAG_ISHASH) &&
+      buf && (len == 0x10)) { /* we're getting a hash */
+
+    memcpy(tx->data+i, buf, 0x10);
+    i += 0x10;
+
+  } else if (buf && (len > 0)) { /* use input buffer */
+    md5_state_t state;
+
+    md5_init(&state);	
+    md5_append(&state, (const md5_byte_t *)buf, len);
+    md5_finish(&state, (md5_byte_t *)(tx->data+i));
+    i += 0x10;
+
+  } else if (len == 0) { /* no length, just hash NULL (buf is optional) */
+    md5_state_t state;
+    unsigned char nil = '\0';
+
+    /*
+     * These MD5 routines are stupid in that you have to have
+     * at least one append.  So thats why this doesn't look 
+     * real logical.
+     */
+    md5_init(&state);
+    md5_append(&state, (const md5_byte_t *)&nil, 0);
+    md5_finish(&state, (md5_byte_t *)(tx->data+i));
+    i += 0x10;
+
+  } else {
+
+    if ((offset != 0x00001004) || (len != 0x00000004))
+      faimdprintf(sess, 0, "sendmemblock: WARNING: sending bad hash... you will be disconnected soon...\n");
+
+    /* 
+     * This data is correct for AIM 3.5.1670, offset 0x1004, length 4 
+     *
+     * Using this block is as close to "legal" as you can get without
+     * using an AIM binary.
+     */
+    i += aimutil_put32(tx->data+i, 0x92bd6757);
+    i += aimutil_put32(tx->data+i, 0x3722cbd3);
+    i += aimutil_put32(tx->data+i, 0x2b048ab9);
+    i += aimutil_put32(tx->data+i, 0xd0b1e4ab);
+
+  }
+
+  tx->commandlen = i;
+  tx->lock = 0;
+  aim_tx_enqueue(sess, tx);
+
+  return 0;
+}
+
 static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen)
 {
 
@@ -665,6 +851,8 @@
     return motd(sess, mod, rx, snac, data, datalen);
   else if (snac->subtype == 0x0018)
     return hostversions(sess, mod, rx, snac, data, datalen);
+  else if (snac->subtype == 0x001f)
+    return memrequest(sess, mod, rx, snac, data, datalen);
 
   return 0;
 }
--- a/src/oscar.c	Tue Apr 24 23:23:40 2001 +0000
+++ b/src/oscar.c	Wed Apr 25 01:53:56 2001 +0000
@@ -243,6 +243,7 @@
 static int gaim_parse_buddyrights(struct aim_session_t *, struct command_rx_struct *, ...);
 static int gaim_parse_locerr     (struct aim_session_t *, struct command_rx_struct *, ...);
 static int gaim_parse_genericerr (struct aim_session_t *, struct command_rx_struct *, ...);
+static int gaim_memrequest       (struct aim_session_t *, struct command_rx_struct *, ...);
 
 static int gaim_directim_initiate  (struct aim_session_t *, struct command_rx_struct *, ...);
 static int gaim_directim_incoming  (struct aim_session_t *, struct command_rx_struct *, ...);
@@ -593,6 +594,7 @@
 	aim_conn_addhandler(sess, bosconn, 0x0001, 0x0001, gaim_parse_genericerr, 0);
 	aim_conn_addhandler(sess, bosconn, 0x0003, 0x0001, gaim_parse_genericerr, 0);
 	aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, gaim_parse_genericerr, 0);
+	aim_conn_addhandler(sess, bosconn, 0x0001, 0x001f, gaim_memrequest, 0);
 
 	aim_auth_sendcookie(sess, bosconn, cookie);
 	((struct oscar_data *)gc->proto_data)->conn = bosconn;
@@ -602,6 +604,87 @@
 	return 1;
 }
 
+struct pieceofcrap {
+	struct gaim_connection *gc;
+	unsigned long offset;
+	unsigned long len;
+	char *modname;
+	struct aim_conn_t *conn;
+	struct aim_conn_t *mainconn;
+	unsigned int inpa;
+};
+
+void damn_you(gpointer data, gint source, GdkInputCondition c)
+{
+	struct pieceofcrap *pos = data;
+	struct oscar_data *od = pos->gc->proto_data;
+	char in;
+	int x = 0;
+	char m[17];
+	if (c == GDK_INPUT_WRITE) {
+		char buf[BUF_LONG];
+		aim_conn_completeconnect(od->sess, pos->conn);
+		g_snprintf(buf, sizeof(buf), "GET http://gaim.sourceforge.net/aim_data.php3?"
+				"offset=%d&len=%d&modname=%s HTTP/1.0\n\n",
+				pos->offset, pos->len, pos->modname ? pos->modname : "");
+		write(pos->conn->fd, buf, strlen(buf));
+		if (pos->modname)
+			g_free(pos->modname);
+		gdk_input_remove(pos->inpa);
+		pos->inpa = gdk_input_add(pos->conn->fd, GDK_INPUT_READ, damn_you, pos);
+		return;
+	}
+
+	while (read(pos->conn->fd, &in, 1) == 1) {
+		if (in == '\n')
+			x++;
+		else if (in != '\r')
+			x = 0;
+		if (x == 2)
+			break;
+	}
+	read(pos->conn->fd, m, 16);
+	m[16] = '\0';
+	gdk_input_remove(pos->inpa);
+	close(pos->conn->fd);
+	aim_conn_kill(od->sess, &pos->conn);
+	aim_sendmemblock(od->sess, pos->mainconn, 0, 16, m, AIM_SENDMEMBLOCK_FLAG_ISHASH);
+	g_free(pos);
+}
+
+int gaim_memrequest(struct aim_session_t *sess,
+		    struct command_rx_struct *command, ...) {
+	va_list ap;
+	struct pieceofcrap *pos;
+	unsigned long offset, len;
+	char *modname;
+
+	va_start(ap, command);
+	offset = va_arg(ap, unsigned long);
+	len = va_arg(ap, unsigned long);
+	modname = va_arg(ap, char *);
+	va_end(ap);
+
+	if (len == 0) {
+		aim_sendmemblock(sess, command->conn, offset, len, NULL,
+				AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
+		return;
+	}
+
+	pos = g_new0(struct pieceofcrap, 1);
+	pos->gc = sess->aux_data;
+	pos->mainconn = command->conn;
+
+	pos->offset = offset;
+	pos->len = len;
+	pos->modname = modname ? g_strdup(modname) : NULL;
+
+	pos->conn = aim_newconn(sess, 0, "gaim.sourceforge.net:80");
+	pos->inpa = gdk_input_add(pos->conn->fd, GDK_INPUT_WRITE, damn_you, pos);
+
+	return 1;
+}
+
 void some_name(char *buf)
 {
 	int x[4];
@@ -1448,8 +1531,6 @@
 		do_error_dialog(_("Your connection may be lost."),
 				_("AOL error"));
 
-	aim_0001_0020(sess, command->conn);
-
 	return 1;
 }
 
@@ -1893,9 +1974,11 @@
 		aim_send_im_direct(odata->sess, dim->conn, message);
 	} else {
 		if (away)
-			aim_send_im(odata->sess, odata->conn, name, AIM_IMFLAGS_AWAY, message);
+			aim_send_im(odata->sess, odata->conn, name, AIM_IMFLAGS_AWAY, message,
+					strlen(message));
 		else
-			aim_send_im(odata->sess, odata->conn, name, AIM_IMFLAGS_ACK, message);
+			aim_send_im(odata->sess, odata->conn, name, AIM_IMFLAGS_ACK, message,
+					strlen(message));
 	}
 }
 
@@ -2069,7 +2152,7 @@
 		return;
 
 	cn = aim_chat_getconn(odata->sess, b->name);
-	aim_chat_send_im(odata->sess, cn, message);
+	aim_chat_send_im(odata->sess, cn, 0, message, strlen(message));
 }
 
 static char **oscar_list_icon(int uc) {