changeset 1302:4c5c2fcb83cd

[gaim-migrate @ 1312] libfaim stuff committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Tue, 19 Dec 2000 03:08:06 +0000
parents e973ef7a8a87
children 9c34f99af79e
files libfaim/CHANGES libfaim/README libfaim/README.gaim libfaim/aim_info.c libfaim/aim_login.c libfaim/aim_misc.c libfaim/aim_rxhandlers.c libfaim/faim/aim.h libfaim/faim/aim_cbtypes.h plugins/yay/yay.c src/oscar.c
diffstat 11 files changed, 225 insertions(+), 112 deletions(-) [+]
line wrap: on
line diff
--- a/libfaim/CHANGES	Tue Dec 19 01:29:13 2000 +0000
+++ b/libfaim/CHANGES	Tue Dec 19 03:08:06 2000 +0000
@@ -1,6 +1,30 @@
 
 No release numbers
 ------------------
+ - Sun Dec 17 07:19:04 UTC 2000
+  - Update the capability block list
+
+ - Sat Dec 16 01:34:19 UTC 2000
+  - Rename paramid to rateclass
+  - Add a long comment about the rate system
+  - Add a few other comments
+  - Clean up aim_bos_clientready().
+
+ - Fri Dec 15 23:35:01 UTC 2000
+  - Add genericerr callback/middle. 
+   - This is for catching the errors that come back, for instance, from
+     sending a SNAC that isn't supported by the host (such as the
+     Watcher Request SNAC).
+
+ - Fri Dec 15 21:51:32 UTC 2000
+  - Add more info to evilnotify callback
+  - Add a few values to aim_cbtypes.h
+
+ - Fri Dec 15 20:41:15 UTC 2000
+  - Revise README
+  - Make aimdebugd compile
+  - Typos
+
  - Fri Dec 15 02:04:12 UTC 2000
   - Parse rate changes *properly*
   - Add sample code to faimtest demonstrating my approximations
--- a/libfaim/README	Tue Dec 19 01:29:13 2000 +0000
+++ b/libfaim/README	Tue Dec 19 03:08:06 2000 +0000
@@ -4,7 +4,7 @@
 
 This is libfaim, the purpose of which is to implement as much as the
 AOL AIM/OSCAR protocol as possible (which should be all of it).  After
-over a year of development, its still nowhere close.  
+over two years of development, its still nowhere close.  
 
 This is not a full client and never will be.  libfaim only implements
 the routines to implement a client (ie, there's no user interface).  
@@ -16,7 +16,11 @@
 beta-quality and I know it leaks memory quite badly.  It seems fairly
 stable, however.  YMMV, YAYOR, etc.  I suppose I should say regardless of
 that warning, that several clients use it and people use those clients
-on a daily basis (in particular, me).
+on a daily basis (in particular, me).  Also, you're probably reading this 
+from a CVS version, since I haven't made a release in a very long time.  
+The CVS version changes fairly rapidly when I'm in the mood, so a version
+you checked out an hour ago may be better or worse than a version you 
+check out now.  
 
 
 Building
--- a/libfaim/README.gaim	Tue Dec 19 01:29:13 2000 +0000
+++ b/libfaim/README.gaim	Tue Dec 19 03:08:06 2000 +0000
@@ -67,7 +67,8 @@
 KNOWN ISSUES
 ============
 - Oscar doesn't do whispering in chat rooms any more (and hasn't for quite a
-while, evidently). So if you want to "whisper" to someone, just IM them.
+while, evidently). So if you want to "whisper" to someone, just IM them. (TOC
+doesn't either?)
 
 - Gaim/TOC can do some RVOUS actions, and Gaim/Faim can do others. This is not
 because there is any difference in the protocols as far as the actual transfer
@@ -77,12 +78,8 @@
 - What *is* protocol-dependent about the RVOUS stuff is that only Oscar can
 request RVOUS actions, though both can receive them.
 
-- Temporarily removed Direct IM pending a UI change
-
 - Getting Dir Info is not in libfaim yet, and so is not in Gaim/Faim yet.
 
-- Warnings are there now. Yes, I know it says the wrong value.
-
 - There are also FIXME's scattered about gaim. Grep around for those, figure
 out what needs to be fixed, do that sort of thing. :) (Fixing the things listed
 in KNOWN ISSUES above, or any other bugs you happen to find, is a very good use
--- a/libfaim/aim_info.c	Tue Dec 19 01:29:13 2000 +0000
+++ b/libfaim/aim_info.c	Tue Dec 19 03:08:06 2000 +0000
@@ -94,7 +94,7 @@
 /*
  * Capability blocks.  
  */
-u_char aim_caps[6][16] = {
+u_char aim_caps[8][16] = {
   
   /* Buddy icon */
   {0x09, 0x46, 0x13, 0x46, 0x4c, 0x7f, 0x11, 0xd1, 
@@ -118,7 +118,15 @@
   
   /* Send file */
   {0x09, 0x46, 0x13, 0x43, 0x4c, 0x7f, 0x11, 0xd1, 
-   0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}
+   0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00},
+
+  /* Saves stock portfolios */
+  {0x09, 0x46, 0x13, 0x47, 0x4c, 0x7f, 0x11, 0xd1,
+   0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00},
+
+  /* Games */
+  {0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1,
+   0x22, 0x82, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00},
 };
 
 faim_internal unsigned short aim_getcap(unsigned char *capblock, int buflen)
@@ -126,21 +134,29 @@
   u_short ret = 0;
   int y;
   int offset = 0;
+  int identified;
 
   while (offset < buflen) {
+    identified = 0;
     for(y=0; y < (sizeof(aim_caps)/0x10); y++) {
       if (memcmp(&aim_caps[y], capblock+offset, 0x10) == 0) {
 	switch(y) {
-	case 0: ret |= AIM_CAPS_BUDDYICON; break;
-	case 1: ret |= AIM_CAPS_VOICE; break;
-	case 2: ret |= AIM_CAPS_IMIMAGE; break;
-	case 3: ret |= AIM_CAPS_CHAT; break;
-	case 4: ret |= AIM_CAPS_GETFILE; break;
-	case 5: ret |= AIM_CAPS_SENDFILE; break;
-	default: ret |= 0xff00; break;
+	case 0: ret |= AIM_CAPS_BUDDYICON; identified++; break;
+	case 1: ret |= AIM_CAPS_VOICE; identified++; break;
+	case 2: ret |= AIM_CAPS_IMIMAGE; identified++; break;
+	case 3: ret |= AIM_CAPS_CHAT; identified++; break;
+	case 4: ret |= AIM_CAPS_GETFILE; identified++; break;
+	case 5: ret |= AIM_CAPS_SENDFILE; identified++; break;
+	case 6: ret |= AIM_CAPS_GAMES; identified++; break;
+	case 7: ret |= AIM_CAPS_SAVESTOCKS; identified++; break;
 	}
       }
     }
+    if (!identified) {
+      printf("faim: unknown capability!\n");
+      ret |= 0xff00;
+    }
+
     offset += 0x10;
   } 
   return ret;
@@ -177,6 +193,14 @@
     memcpy(capblock+offset, aim_caps[5], sizeof(aim_caps[5]));
     offset += sizeof(aim_caps[5]);
   }
+  if ((caps & AIM_CAPS_GAMES) && (offset < buflen)) {
+    memcpy(capblock+offset, aim_caps[6], sizeof(aim_caps[6]));
+    offset += sizeof(aim_caps[6]);
+  }
+  if ((caps & AIM_CAPS_SAVESTOCKS) && (offset < buflen)) {
+    memcpy(capblock+offset, aim_caps[7], sizeof(aim_caps[7]));
+    offset += sizeof(aim_caps[7]);
+  }
 
   return offset;
 }
--- a/libfaim/aim_login.c	Tue Dec 19 01:29:13 2000 +0000
+++ b/libfaim/aim_login.c	Tue Dec 19 03:08:06 2000 +0000
@@ -361,6 +361,14 @@
   /*
    * The registration status.  (Not real sure what it means.)
    *   Not available for ICQ logins.
+   *
+   *   1 = No disclosure
+   *   2 = Limited disclosure
+   *   3 = Full disclosure
+   *
+   * This has to do with whether your email address is available
+   * to other users or not.  AFAIK, this feature is no longer used.
+   *
    */
   if (aim_gettlv(tlvlist, 0x0013, 1))
     regstatus = aim_gettlv16(tlvlist, 0x0013, 1);
--- a/libfaim/aim_misc.c	Tue Dec 19 01:29:13 2000 +0000
+++ b/libfaim/aim_misc.c	Tue Dec 19 03:08:06 2000 +0000
@@ -301,79 +301,57 @@
  * 
  * Send Client Ready.  
  *
- * TODO: Dynamisize.
- *
  */
 faim_export unsigned long aim_bos_clientready(struct aim_session_t *sess,
 					      struct aim_conn_t *conn)
 {
-  u_char command_2[] = {
-     /* placeholders for dynamic data */
-     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-     0xff, 0xff, 
-     /* real data */
-     0x00, 0x01,   
-     0x00, 0x03, 
-     0x00, 0x04, 
-     0x06, 0x86, /* the good ones */
-#if 0
-     0x07, 0xda, /* DUPLE OF DEATH! */
-#endif
+#define AIM_TOOL_JAVA   0x0001
+#define AIM_TOOL_MAC    0x0002
+#define AIM_TOOL_WIN16  0x0003
+#define AIM_TOOL_WIN32  0x0004
+#define AIM_TOOL_MAC68K 0x0005
+#define AIM_TOOL_MACPPC 0x0006
+  struct aim_tool_version {
+    unsigned short group;
+    unsigned short version;
+    unsigned short tool;
+    unsigned short toolversion;
+  } tools[] = {
+    {0x0001, 0x0003,    AIM_TOOL_WIN32, 0x0686},
+    {0x0002, 0x0001,    AIM_TOOL_WIN32, 0x0001}, 
+    {0x0003, 0x0001,    AIM_TOOL_WIN32, 0x0001},
+    {0x0004, 0x0001,    AIM_TOOL_WIN32, 0x0001},
+    {0x0006, 0x0001,    AIM_TOOL_WIN32, 0x0001}, 
+    {0x0008, 0x0001,    AIM_TOOL_WIN32, 0x0001},
+    {0x0009, 0x0001,    AIM_TOOL_WIN32, 0x0001}, 
+    {0x000a, 0x0001,    AIM_TOOL_WIN32, 0x0001},
+    {0x000b, 0x0001,    AIM_TOOL_WIN32, 0x0001}
+  };
+  int i,j;
+  struct command_tx_struct *newpacket;
+  int toolcount = sizeof(tools)/sizeof(struct aim_tool_version);
 
-     0x00, 0x02, 
-     0x00, 0x01,  
-     0x00, 0x04, 
-     0x00, 0x01, 
- 
-     0x00, 0x03, 
-     0x00, 0x01,  
-     0x00, 0x04, 
-     0x00, 0x01,
- 
-     0x00, 0x04, 
-     0x00, 0x01, 
-     0x00, 0x04,
-     0x00, 0x01,
- 
-     0x00, 0x06, 
-     0x00, 0x01, 
-     0x00, 0x04,  
-     0x00, 0x01, 
-     0x00, 0x08, 
-     0x00, 0x01, 
-     0x00, 0x04,
-     0x00, 0x01,
- 
-     0x00, 0x09, 
-     0x00, 0x01, 
-     0x00, 0x04,
-     0x00, 0x01, 
-     0x00, 0x0a, 
-     0x00, 0x01, 
-     0x00, 0x04,
-     0x00, 0x01,
- 
-     0x00, 0x0b,
-     0x00, 0x01, 
-     0x00, 0x04,
-     0x00, 0x01
-  };
-  int command_2_len = 0x52;
-  struct command_tx_struct *newpacket;
-  
-  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, command_2_len)))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152)))
     return -1;
 
   newpacket->lock = 1;
 
-  memcpy(newpacket->data, command_2, command_2_len);
-  
-  /* This write over the dynamic parts of the byte block */
-  aim_putsnac(newpacket->data, 0x0001, 0x0002, 0x0000, sess->snac_nextid);
+  i = aim_putsnac(newpacket->data, 0x0001, 0x0002, 0x0000, sess->snac_nextid);
+  aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0);
+
+  for (j = 0; j < toolcount; j++) {
+    i += aimutil_put16(newpacket->data+i, tools[j].group);
+    i += aimutil_put16(newpacket->data+i, tools[j].version);
+    i += aimutil_put16(newpacket->data+i, tools[j].tool);
+    i += aimutil_put16(newpacket->data+i, tools[j].toolversion);
+  }
+
+  newpacket->commandlen = i;
+  newpacket->lock = 0;
 
   aim_tx_enqueue(sess, newpacket);
 
-  return (sess->snac_nextid++);
+  return sess->snac_nextid;
 }
 
 /* 
--- a/libfaim/aim_rxhandlers.c	Tue Dec 19 01:29:13 2000 +0000
+++ b/libfaim/aim_rxhandlers.c	Tue Dec 19 03:08:06 2000 +0000
@@ -480,7 +480,7 @@
 	    workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
 	  }
 	  break;
-	case 0x0004: /* Family: Messeging */
+	case 0x0004: /* Family: Messaging */
 	  switch (subtype) {
 	  case 0x0001:
 	    workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr);
@@ -533,6 +533,10 @@
 	    workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
 	  break;
 	}
+	case 0x0013: {
+	  printf("lalala: 0x%04x/0x%04x\n", family, subtype);
+	  break;
+	}
 	case AIM_CB_FAM_SPECIAL: 
 	  workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
 	  break;
@@ -655,13 +659,62 @@
   return ret;
 }
 
+/*
+ * The Rate Limiting System, An Abridged Guide to Nonsense.
+ *
+ * OSCAR defines several 'rate classes'.  Each class has seperate
+ * rate limiting properties (limit level, alert level, disconnect
+ * level, etc), and a set of SNAC family/type pairs associated with
+ * it.  The rate classes, their limiting properties, and the definitions
+ * of which SNACs are belong to which class, are defined in the
+ * Rate Response packet at login to each host.  
+ *
+ * Logically, all rate offenses within one class count against further
+ * offenses for other SNACs in the same class (ie, sending messages
+ * too fast will limit the number of user info requests you can send,
+ * since those two SNACs are in the same rate class).
+ *
+ * Since the rate classes are defined dynamically at login, the values
+ * below may change. But they seem to be fairly constant.
+ *
+ * Currently, BOS defines five rate classes, with the commonly used
+ * members as follows...
+ *
+ *  Rate class 0x0001:
+ *  	- Everything thats not in any of the other classes
+ *
+ *  Rate class 0x0002:
+ * 	- Buddy list add/remove
+ *	- Permit list add/remove
+ *	- Deny list add/remove
+ *
+ *  Rate class 0x0003:
+ *	- User information requests
+ *	- Outgoing ICBMs
+ *
+ *  Rate class 0x0004:
+ *	- A few unknowns: 2/9, 2/b, and f/2
+ *
+ *  Rate class 0x0005:
+ *	- Chat room create
+ *	- Outgoing chat ICBMs
+ *
+ * The only other thing of note is that class 5 (chat) has slightly looser
+ * limiting properties than class 3 (normal messages).  But thats just a 
+ * small bit of trivia for you.
+ *
+ * The last thing that needs to be learned about the rate limiting
+ * system is how the actual numbers relate to the passing of time.  This
+ * seems to be a big mystery.
+ * 
+ */
 faim_internal int aim_parse_ratechange_middle(struct aim_session_t *sess, struct command_rx_struct *command)
 {
   rxcallback_t userfunc = NULL;
   int ret = 1;
   int i;
   int code;
-  unsigned long parmid, windowsize, clear, alert, limit, disconnect;
+  unsigned long rateclass, windowsize, clear, alert, limit, disconnect;
   unsigned long currentavg, maxavg;
 
   i = 10;
@@ -669,7 +722,7 @@
   code = aimutil_get16(command->data+i);
   i += 2;
 
-  parmid = aimutil_get16(command->data+i);
+  rateclass = aimutil_get16(command->data+i);
   i += 2;
 
   windowsize = aimutil_get32(command->data+i);
@@ -688,7 +741,7 @@
   i += 4;
 
   if ((userfunc = aim_callhandler(command->conn, 0x0001, 0x000a)))
-    ret =  userfunc(sess, command, code, parmid, windowsize, clear, alert, limit, disconnect, currentavg, maxavg);
+    ret =  userfunc(sess, command, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg);
 
   return ret;
 }
@@ -696,25 +749,22 @@
 faim_internal int aim_parse_evilnotify_middle(struct aim_session_t *sess, struct command_rx_struct *command)
 {
   rxcallback_t userfunc = NULL;
-  int ret = 1, pos;
-  char *sn = NULL;
-
-  if(command->commandlen < 12) /* a warning level dec sends this */
-    return 1;
+  int ret = 1;
+  int i;
+  unsigned short newevil;
+  struct aim_userinfo_s userinfo;
 
-  if ((pos = aimutil_get8(command->data+ 12)) > MAXSNLEN)
-    return 1;
+  i = 10;
+  newevil = aimutil_get16(command->data+10);
+  i += 2;
 
-  if(!(sn = (char *)calloc(1, pos+1)))
-    return 1;
-
-  memcpy(sn, command->data+13, pos);
+  memset(&userinfo, 0, sizeof(struct aim_userinfo_s));
+  if (command->commandlen-i)
+    i += aim_extractuserinfo(command->data+i, &userinfo);
 
   if ((userfunc = aim_callhandler(command->conn, 0x0001, 0x0010)))
-    ret = userfunc(sess, command, sn);
+    ret = userfunc(sess, command, newevil, &userinfo);
   
-  free(sn);
-
   return ret;
 }
 
@@ -906,20 +956,22 @@
 faim_internal int aim_parse_generalerrs(struct aim_session_t *sess,
 					struct command_rx_struct *command, ...)
 {
-  u_short family;
-  u_short subtype;
+  unsigned short family;
+  unsigned short subtype;
+  int ret = 1;
+  int error = 0;
+  rxcallback_t userfunc = NULL;
   
   family = aimutil_get16(command->data+0);
   subtype= aimutil_get16(command->data+2);
   
-  switch(family)
-    {
-    default:
-      /* Unknown family */
-      return aim_callhandler_noparam(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command);
-    }
+  if (command->commandlen > 10)
+    error = aimutil_get16(command->data+10);
 
-  return 1;
+  if ((userfunc = aim_callhandler(command->conn, family, subtype))) 
+    ret = userfunc(sess, command, error);
+
+  return ret;
 }
 
 
--- a/libfaim/faim/aim.h	Tue Dec 19 01:29:13 2000 +0000
+++ b/libfaim/faim/aim.h	Tue Dec 19 03:08:06 2000 +0000
@@ -620,8 +620,10 @@
 #define AIM_CAPS_CHAT 0x08
 #define AIM_CAPS_GETFILE 0x10
 #define AIM_CAPS_SENDFILE 0x20
+#define AIM_CAPS_GAMES 0x40
+#define AIM_CAPS_SAVESTOCKS 0x80
 
-extern u_char aim_caps[6][16];
+extern u_char aim_caps[8][16];
 faim_internal unsigned short aim_getcap(unsigned char *capblock, int buflen);
 faim_internal int aim_putcap(unsigned char *capblock, int buflen, u_short caps);
 
--- a/libfaim/faim/aim_cbtypes.h	Tue Dec 19 01:29:13 2000 +0000
+++ b/libfaim/faim/aim_cbtypes.h	Tue Dec 19 03:08:06 2000 +0000
@@ -128,6 +128,8 @@
  * SNAC Family: Misc BOS Services.
  */ 
 #define AIM_CB_BOS_ERROR 0x0001
+#define AIM_CB_BOS_RIGHTSQUERY 0x0002
+#define AIM_CB_BOS_RIGHTS 0x0003
 #define AIM_CB_BOS_DEFAULT 0xffff
 
 /*
--- a/plugins/yay/yay.c	Tue Dec 19 01:29:13 2000 +0000
+++ b/plugins/yay/yay.c	Tue Dec 19 03:08:06 2000 +0000
@@ -401,6 +401,7 @@
 	ret->name = yahoo_name;
 	ret->list_icon = yahoo_list_icon;
 	ret->action_menu = yahoo_action_menu;
+	ret->user_opts = NULL;
 	ret->login = yahoo_login;
 	ret->close = yahoo_close;
 	ret->send_im = yahoo_send_im;
--- a/src/oscar.c	Tue Dec 19 01:29:13 2000 +0000
+++ b/src/oscar.c	Tue Dec 19 03:08:06 2000 +0000
@@ -56,7 +56,8 @@
 #define USEROPT_SOCKSPORT 3
 
 int gaim_caps = AIM_CAPS_CHAT | AIM_CAPS_SENDFILE | AIM_CAPS_GETFILE |
-		AIM_CAPS_VOICE | AIM_CAPS_IMIMAGE | AIM_CAPS_BUDDYICON;
+		AIM_CAPS_VOICE | AIM_CAPS_IMIMAGE | AIM_CAPS_BUDDYICON |
+		AIM_CAPS_GAMES | AIM_CAPS_SAVESTOCKS;
 
 struct oscar_data {
 	struct aim_session_t *sess;
@@ -248,6 +249,7 @@
 static int gaim_parse_msgerr     (struct aim_session_t *, struct command_rx_struct *, ...);
 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_directim_initiate  (struct aim_session_t *, struct command_rx_struct *, ...);
 static int gaim_directim_incoming  (struct aim_session_t *, struct command_rx_struct *, ...);
@@ -561,6 +563,9 @@
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_CTN, AIM_CB_CTN_DEFAULT, aim_parse_unknown, 0);
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEFAULT, aim_parse_unknown, 0);
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, gaim_parse_motd, 0);
+	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_auth_sendcookie(sess, bosconn, cookie);
 	((struct oscar_data *)gc->proto_data)->conn = bosconn;
@@ -1224,6 +1229,20 @@
 	return 1;
 }
 
+int gaim_parse_genericerr(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
+	va_list ap;
+	unsigned short reason;
+
+	va_start(ap, command);
+	reason = va_arg(ap, int);
+	va_end(ap);
+
+	debug_printf("snac threw error (reason 0x%04x: %s\n", reason,
+			(reason < msgerrreasonlen) ? msgerrreason[reason] : "unknown");
+
+	return 1;
+}
+
 int gaim_parse_msgerr(struct aim_session_t *sess,
 		      struct command_rx_struct *command, ...) {
 	va_list ap;
@@ -1519,12 +1538,12 @@
 				 "limit cleared"};
 	va_list ap;
 	int code;
-	unsigned long parmid, windowsize, clear, alert, limit, disconnect;
+	unsigned long rateclass, windowsize, clear, alert, limit, disconnect;
 	unsigned long currentavg, maxavg;
 
 	va_start(ap, command); 
 	code = va_arg(ap, int);
-	parmid = va_arg(ap, int);
+	rateclass= va_arg(ap, int);
 	windowsize = va_arg(ap, unsigned long);
 	clear = va_arg(ap, unsigned long);
 	alert = va_arg(ap, unsigned long);
@@ -1537,7 +1556,7 @@
 	debug_printf("rate %s (paramid 0x%04lx): curavg = %ld, maxavg = %ld, alert at %ld, "
 		     "clear warning at %ld, limit at %ld, disconnect at %ld (window size = %ld)\n",
 		     (code < 5) ? codes[code] : codes[0],
-		     parmid,
+		     rateclass,
 		     currentavg, maxavg,
 		     alert, clear,
 		     limit, disconnect,
@@ -1559,14 +1578,16 @@
 
 int gaim_parse_evilnotify(struct aim_session_t *sess, struct command_rx_struct *command, ...) {
 	va_list ap;
-	char *sn;
+	int newevil;
+	struct aim_userinfo_s *userinfo;
 	struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess);
 
 	va_start(ap, command);
-	sn = va_arg(ap, char *);
+	newevil = va_arg(ap, int);
+	userinfo = va_arg(ap, struct aim_userinfo_s *);
 	va_end(ap);
 
-	serv_got_eviled(gc, sn, 0);
+	serv_got_eviled(gc, (userinfo && userinfo->sn[0]) ? userinfo->sn : NULL, newevil / 10);
 
 	return 1;
 }