diff src/protocols/oscar/rxhandlers.c @ 2246:933346315b9b

[gaim-migrate @ 2256] heh. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Sun, 09 Sep 2001 10:07:14 +0000
parents 424a40f12a6c
children c41030cfed76
line wrap: on
line diff
--- a/src/protocols/oscar/rxhandlers.c	Sun Sep 09 06:33:54 2001 +0000
+++ b/src/protocols/oscar/rxhandlers.c	Sun Sep 09 10:07:14 2001 +0000
@@ -10,561 +10,564 @@
 #define FAIM_INTERNAL
 #include <aim.h>
 
-static aim_module_t *findmodule(struct aim_session_t *sess, const char *name)
-{
-  aim_module_t *cur;
+struct aim_rxcblist_s {
+	fu16_t family;
+	fu16_t type;
+	aim_rxcallback_t handler;
+	u_short flags;
+	struct aim_rxcblist_s *next;
+};
 
-  for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
-    if (strcmp(name, cur->name) == 0)
-      return cur;
-  }
+static aim_module_t *findmodule(aim_session_t *sess, const char *name)
+{
+	aim_module_t *cur;
 
-  return NULL;
+	for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
+		if (strcmp(name, cur->name) == 0)
+			return cur;
+	}
+
+	return NULL;
 }
 
-faim_internal int aim__registermodule(struct aim_session_t *sess, int (*modfirst)(struct aim_session_t *, aim_module_t *))
+faim_internal int aim__registermodule(aim_session_t *sess, int (*modfirst)(aim_session_t *, aim_module_t *))
 {
-  aim_module_t *mod;
+	aim_module_t *mod;
+
+	if (!sess || !modfirst)
+		return -1;
+
+	if (!(mod = malloc(sizeof(aim_module_t))))
+		return -1;
+	memset(mod, 0, sizeof(aim_module_t));
 
-  if (!sess || !modfirst)
-    return -1;
+	if (modfirst(sess, mod) == -1) {
+		free(mod);
+		return -1;
+	}
 
-  if (!(mod = malloc(sizeof(aim_module_t))))
-    return -1;
-  memset(mod, 0, sizeof(aim_module_t));
+	if (findmodule(sess, mod->name)) {
+		if (mod->shutdown)
+			mod->shutdown(sess, mod);
+		free(mod);
+		return -1;
+	}
+
+	mod->next = (aim_module_t *)sess->modlistv;
+	(aim_module_t *)sess->modlistv = mod;
 
-  if (modfirst(sess, mod) == -1) {
-    free(mod);
-    return -1;
-  }
+	faimdprintf(sess, 1, "registered module %s (family 0x%04x)\n", mod->name, mod->family);
+
+	return 0;
+}
+
+faim_internal void aim__shutdownmodules(aim_session_t *sess)
+{
+	aim_module_t *cur;
+
+	for (cur = (aim_module_t *)sess->modlistv; cur; ) {
+		aim_module_t *tmp;
 
-  if (findmodule(sess, mod->name)) {
-    if (mod->shutdown)
-      mod->shutdown(sess, mod);
-    free(mod);
-    return -1;
-  }
+		tmp = cur->next;
+
+		if (cur->shutdown)
+			cur->shutdown(sess, cur);
+
+		free(cur);
 
-  mod->next = (aim_module_t *)sess->modlistv;
-  (aim_module_t *)sess->modlistv = mod;
+		cur = tmp;
+	}
 
-  faimdprintf(sess, 1, "registered module %s (family 0x%04x)\n", mod->name, mod->family);
+	sess->modlistv = NULL;
 
-  return 0;
+	return;
 }
 
-faim_internal void aim__shutdownmodules(struct aim_session_t *sess)
+static int consumesnac(aim_session_t *sess, aim_frame_t *rx)
 {
-  aim_module_t *cur;
+	aim_module_t *cur;
+	aim_modsnac_t snac;
 
-  for (cur = (aim_module_t *)sess->modlistv; cur; ) {
-    aim_module_t *tmp;
+	if (aim_bstream_empty(&rx->data) < 10)
+		return 0;
 
-    tmp = cur->next;
+	snac.family = aimbs_get16(&rx->data);
+	snac.subtype = aimbs_get16(&rx->data);
+	snac.flags = aimbs_get16(&rx->data);
+	snac.id = aimbs_get32(&rx->data);
 
-    if (cur->shutdown)
-      cur->shutdown(sess, cur);
+	for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
 
-    free(cur);
+		if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) && 
+				(cur->family != snac.family))
+			continue;
 
-    cur = tmp;
-  }
+		if (cur->snachandler(sess, cur, rx, &snac, &rx->data))
+			return 1;
 
-  sess->modlistv = NULL;
+	}
 
-  return;
+	return 0;
 }
 
-static int consumesnac(struct aim_session_t *sess, struct command_rx_struct *rx)
+static int consumenonsnac(aim_session_t *sess, aim_frame_t *rx, fu16_t family, fu16_t subtype)
 {
-  aim_module_t *cur;
-  aim_modsnac_t snac;
+	aim_module_t *cur;
+	aim_modsnac_t snac;
 
-  snac.family = aimutil_get16(rx->data+0);
-  snac.subtype = aimutil_get16(rx->data+2);
-  snac.flags = aimutil_get16(rx->data+4);
-  snac.id = aimutil_get32(rx->data+6);
+	snac.family = family;
+	snac.subtype = subtype;
+	snac.flags = snac.id = 0;
+
+	for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
 
-  for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
-
-    if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) && 
-	(cur->family != snac.family))
-      continue;
+		if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) && 
+				(cur->family != snac.family))
+			continue;
 
-    if (cur->snachandler(sess, cur, rx, &snac, rx->data+10, rx->commandlen-10))
-      return 1;
+		if (cur->snachandler(sess, cur, rx, &snac, &rx->data))
+			return 1;
 
-  }
+	}
 
-  return 0;
+	return 0;
 }
 
-static int consumenonsnac(struct aim_session_t *sess, struct command_rx_struct *rx, unsigned short family, unsigned short subtype)
+static int negchan_middle(aim_session_t *sess, aim_frame_t *fr)
 {
-  aim_module_t *cur;
-  aim_modsnac_t snac;
+	aim_tlvlist_t *tlvlist;
+	char *msg = NULL;
+	fu16_t code = 0;
+	aim_rxcallback_t userfunc;
+	int ret = 1;
 
-  snac.family = family;
-  snac.subtype = subtype;
-  snac.flags = snac.id = 0;
-
-  for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
+	if (aim_bstream_empty(&fr->data) == 0) {
+		/* XXX should do something with this */
+		return 1;
+	}
 
-    if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) && 
-	(cur->family != snac.family))
-      continue;
+	/* Used only by the older login protocol */
+	/* XXX remove this special case? */
+	if (fr->conn->type == AIM_CONN_TYPE_AUTH)
+		return consumenonsnac(sess, fr, 0x0017, 0x0003);
+
+	tlvlist = aim_readtlvchain(&fr->data);
+
+	if (aim_gettlv(tlvlist, 0x0009, 1))
+		code = aim_gettlv16(tlvlist, 0x0009, 1);
 
-    if (cur->snachandler(sess, cur, rx, &snac, rx->data, rx->commandlen))
-      return 1;
+	if (aim_gettlv(tlvlist, 0x000b, 1))
+		msg = aim_gettlv_str(tlvlist, 0x000b, 1);
+
+	if ((userfunc = aim_callhandler(sess, fr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR))) 
+		ret = userfunc(sess, fr, code, msg);
 
-  }
+	aim_freetlvchain(&tlvlist);
 
-  return 0;
+	free(msg);
+
+	return ret;
 }
 
 /*
  * Bleck functions get called when there's no non-bleck functions
  * around to cleanup the mess...
  */
-faim_internal int bleck(struct aim_session_t *sess,struct command_rx_struct *workingPtr, ...)
+faim_internal int bleck(aim_session_t *sess, aim_frame_t *frame, ...)
 {
-  u_short family;
-  u_short subtype;
-
-  u_short maxf;
-  u_short maxs;
+	fu16_t family, subtype;
+	fu16_t maxf, maxs;
 
-  /* XXX: this is ugly. and big just for debugging. */
-  char *literals[14][25] = {
-    {"Invalid", 
-     NULL
-    },
-    {"General", 
-     "Invalid",
-     "Error",
-     "Client Ready",
-     "Server Ready",
-     "Service Request",
-     "Redirect",
-     "Rate Information Request",
-     "Rate Information",
-     "Rate Information Ack",
-     NULL,
-     "Rate Information Change",
-     "Server Pause",
-     NULL,
-     "Server Resume",
-     "Request Personal User Information",
-     "Personal User Information",
-     "Evil Notification",
-     NULL,
-     "Migration notice",
-     "Message of the Day",
-     "Set Privacy Flags",
-     "Well Known URL",
-     "NOP"
-    },
-    {"Location", 
-      "Invalid",
-      "Error",
-      "Request Rights",
-      "Rights Information", 
-      "Set user information", 
-      "Request User Information", 
-      "User Information", 
-      "Watcher Sub Request",
-      "Watcher Notification"
-    },
-    {"Buddy List Management", 
-      "Invalid", 
-      "Error", 
-      "Request Rights",
-      "Rights Information",
-      "Add Buddy", 
-      "Remove Buddy", 
-      "Watcher List Query", 
-      "Watcher List Response", 
-      "Watcher SubRequest", 
-      "Watcher Notification", 
-      "Reject Notification", 
-      "Oncoming Buddy", 
-      "Offgoing Buddy"
-    },
-    {"Messeging", 
-      "Invalid",
-      "Error", 
-      "Add ICBM Parameter",
-      "Remove ICBM Parameter", 
-      "Request Parameter Information",
-      "Parameter Information",
-      "Outgoing Message", 
-      "Incoming Message",
-      "Evil Request",
-      "Evil Reply", 
-      "Missed Calls",
-      "Message Error", 
-      "Host Ack"
-    },
-    {"Advertisements", 
-      "Invalid", 
-      "Error", 
-      "Request Ad",
-      "Ad Data (GIFs)"
-    },
-    {"Invitation / Client-to-Client", 
-     "Invalid",
-     "Error",
-     "Invite a Friend",
-     "Invitation Ack"
-    },
-    {"Administrative", 
-      "Invalid",
-      "Error",
-      "Information Request",
-      "Information Reply",
-      "Information Change Request",
-      "Information Chat Reply",
-      "Account Confirm Request",
-      "Account Confirm Reply",
-      "Account Delete Request",
-      "Account Delete Reply"
-    },
-    {"Popups", 
-      "Invalid",
-      "Error",
-      "Display Popup"
-    },
-    {"BOS", 
-      "Invalid",
-      "Error",
-      "Request Rights",
-      "Rights Response",
-      "Set group permission mask",
-      "Add permission list entries",
-      "Delete permission list entries",
-      "Add deny list entries",
-      "Delete deny list entries",
-      "Server Error"
-    },
-    {"User Lookup", 
-      "Invalid",
-      "Error",
-      "Search Request",
-      "Search Response"
-    },
-    {"Stats", 
-      "Invalid",
-      "Error",
-      "Set minimum report interval",
-      "Report Events"
-    },
-    {"Translate", 
-      "Invalid",
-      "Error",
-      "Translate Request",
-      "Translate Reply",
-    },
-    {"Chat Navigation", 
-      "Invalid",
-      "Error",
-      "Request rights",
-      "Request Exchange Information",
-      "Request Room Information",
-      "Request Occupant List",
-      "Search for Room",
-      "Outgoing Message", 
-      "Incoming Message",
-      "Evil Request", 
-      "Evil Reply", 
-      "Chat Error",
-    }
-  };
+	static const char *channels[6] = {
+		"Invalid (0)",
+		"FLAP Version",
+		"SNAC",
+		"Invalid (3)",
+		"Negotiation",
+		"FLAP NOP"
+	};
+	static const int maxchannels = 5;
+	
+	/* XXX: this is ugly. and big just for debugging. */
+	static const char *literals[14][25] = {
+		{"Invalid", 
+		 NULL
+		},
+		{"General", 
+		 "Invalid",
+		 "Error",
+		 "Client Ready",
+		 "Server Ready",
+		 "Service Request",
+		 "Redirect",
+		 "Rate Information Request",
+		 "Rate Information",
+		 "Rate Information Ack",
+		 NULL,
+		 "Rate Information Change",
+		 "Server Pause",
+		 NULL,
+		 "Server Resume",
+		 "Request Personal User Information",
+		 "Personal User Information",
+		 "Evil Notification",
+		 NULL,
+		 "Migration notice",
+		 "Message of the Day",
+		 "Set Privacy Flags",
+		 "Well Known URL",
+		 "NOP"
+		},
+		{"Location", 
+		 "Invalid",
+		 "Error",
+		 "Request Rights",
+		 "Rights Information", 
+		 "Set user information", 
+		 "Request User Information", 
+		 "User Information", 
+		 "Watcher Sub Request",
+		 "Watcher Notification"
+		},
+		{"Buddy List Management", 
+		 "Invalid", 
+		 "Error", 
+		 "Request Rights",
+		 "Rights Information",
+		 "Add Buddy", 
+		 "Remove Buddy", 
+		 "Watcher List Query", 
+		 "Watcher List Response", 
+		 "Watcher SubRequest", 
+		 "Watcher Notification", 
+		 "Reject Notification", 
+		 "Oncoming Buddy", 
+		 "Offgoing Buddy"
+		},
+		{"Messeging", 
+		 "Invalid",
+		 "Error", 
+		 "Add ICBM Parameter",
+		 "Remove ICBM Parameter", 
+		 "Request Parameter Information",
+		 "Parameter Information",
+		 "Outgoing Message", 
+		 "Incoming Message",
+		 "Evil Request",
+		 "Evil Reply", 
+		 "Missed Calls",
+		 "Message Error", 
+		 "Host Ack"
+		},
+		{"Advertisements", 
+		 "Invalid", 
+		 "Error", 
+		 "Request Ad",
+		 "Ad Data (GIFs)"
+		},
+		{"Invitation / Client-to-Client", 
+		 "Invalid",
+		 "Error",
+		 "Invite a Friend",
+		 "Invitation Ack"
+		},
+		{"Administrative", 
+		 "Invalid",
+		 "Error",
+		 "Information Request",
+		 "Information Reply",
+		 "Information Change Request",
+		 "Information Chat Reply",
+		 "Account Confirm Request",
+		 "Account Confirm Reply",
+		 "Account Delete Request",
+		 "Account Delete Reply"
+		},
+		{"Popups", 
+		 "Invalid",
+		 "Error",
+		 "Display Popup"
+		},
+		{"BOS", 
+		 "Invalid",
+		 "Error",
+		 "Request Rights",
+		 "Rights Response",
+		 "Set group permission mask",
+		 "Add permission list entries",
+		 "Delete permission list entries",
+		 "Add deny list entries",
+		 "Delete deny list entries",
+		 "Server Error"
+		},
+		{"User Lookup", 
+		 "Invalid",
+		 "Error",
+		 "Search Request",
+		 "Search Response"
+		},
+		{"Stats", 
+		 "Invalid",
+		 "Error",
+		 "Set minimum report interval",
+		 "Report Events"
+		},
+		{"Translate", 
+		 "Invalid",
+		 "Error",
+		 "Translate Request",
+		 "Translate Reply",
+		},
+		{"Chat Navigation", 
+		 "Invalid",
+		 "Error",
+		 "Request rights",
+		 "Request Exchange Information",
+		 "Request Room Information",
+		 "Request Occupant List",
+		 "Search for Room",
+		 "Outgoing Message", 
+		 "Incoming Message",
+		 "Evil Request", 
+		 "Evil Reply", 
+		 "Chat Error",
+		}
+	};
 
-  maxf = sizeof(literals) / sizeof(literals[0]);
-  maxs = sizeof(literals[0]) / sizeof(literals[0][0]);
+	maxf = sizeof(literals) / sizeof(literals[0]);
+	maxs = sizeof(literals[0]) / sizeof(literals[0][0]);
 
-  family = aimutil_get16(workingPtr->data+0);
-  subtype= aimutil_get16(workingPtr->data+2);
+	if (frame->hdr.flap.type == 0x02) {
 
-  if((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL))
-    faimdprintf(sess, 0, "bleck: null handler for %04x/%04x (%s)\n", family, subtype, literals[family][subtype+1]);
-  else
-    faimdprintf(sess, 0, "bleck: null handler for %04x/%04x (no literal)\n",family,subtype);
+		family = aimbs_get16(&frame->data);
+		subtype = aimbs_get16(&frame->data);
+		
+		if ((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL))
+			faimdprintf(sess, 0, "bleck: channel %s: null handler for %04x/%04x (%s)\n", channels[frame->hdr.flap.type], family, subtype, literals[family][subtype+1]);
+		else
+			faimdprintf(sess, 0, "bleck: channel %s: null handler for %04x/%04x (no literal)\n", channels[frame->hdr.flap.type], family, subtype);
+	} else {
 
-  return 1;
+		if (frame->hdr.flap.type <= maxchannels)
+			faimdprintf(sess, 0, "bleck: channel %s (0x%02x)\n", channels[frame->hdr.flap.type], frame->hdr.flap.type);
+		else
+			faimdprintf(sess, 0, "bleck: unknown channel 0x%02x\n", frame->hdr.flap.type);
+
+	}
+		
+	return 1;
 }
 
-faim_export int aim_conn_addhandler(struct aim_session_t *sess,
-				    struct aim_conn_t *conn,
-				    u_short family,
-				    u_short type,
-				    aim_rxcallback_t newhandler,
-				    u_short flags)
+faim_export int aim_conn_addhandler(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type, aim_rxcallback_t newhandler, fu16_t flags)
 {
-  struct aim_rxcblist_t *newcb;
+	struct aim_rxcblist_s *newcb;
+
+	if (!conn)
+		return -1;
 
-  if (!conn)
-    return -1;
+	faimdprintf(sess, 1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
 
-  faimdprintf(sess, 1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
+	if (!(newcb = (struct aim_rxcblist_s *)calloc(1, sizeof(struct aim_rxcblist_s))))
+		return -1;
 
-  if (!(newcb = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t))))
-    return -1;
-  newcb->family = family;
-  newcb->type = type;
-  newcb->flags = flags;
-  if (!newhandler)
-    newcb->handler = &bleck;
-  else
-    newcb->handler = newhandler;
-  newcb->next = NULL;
-  
-  if (!conn->handlerlist)
-    conn->handlerlist = newcb;
-  else {
-    struct aim_rxcblist_t *cur;
+	newcb->family = family;
+	newcb->type = type;
+	newcb->flags = flags;
+	newcb->handler = newhandler ? newhandler : bleck;
+	newcb->next = NULL;
 
-    cur = conn->handlerlist;
+	if (!conn->handlerlist)
+		conn->handlerlist = (void *)newcb;
+	else {
+		struct aim_rxcblist_s *cur;
 
-    while (cur->next)
-      cur = cur->next;
-    cur->next = newcb;
-  }
+		for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur->next; cur = cur->next)
+			;
+		cur->next = newcb;
+	}
 
-  return 0;
+	return 0;
 }
 
-faim_export int aim_clearhandlers(struct aim_conn_t *conn)
+faim_export int aim_clearhandlers(aim_conn_t *conn)
 {
- struct aim_rxcblist_t *cur;
+	struct aim_rxcblist_s *cur;
 
- if (!conn)
-   return -1;
+	if (!conn)
+		return -1;
 
- for (cur = conn->handlerlist; cur; ) {
-   struct aim_rxcblist_t *tmp;
+	for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; ) {
+		struct aim_rxcblist_s *tmp;
 
-   tmp = cur->next;
-   free(cur);
-   cur = tmp;
- }
- conn->handlerlist = NULL;
+		tmp = cur->next;
+		free(cur);
+		cur = tmp;
+	}
+	conn->handlerlist = NULL;
 
- return 0;
+	return 0;
 }
 
-faim_internal aim_rxcallback_t aim_callhandler(struct aim_session_t *sess,
-					       struct aim_conn_t *conn,
-					       unsigned short family,
-					       unsigned short type)
+faim_internal aim_rxcallback_t aim_callhandler(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type)
 {
-  struct aim_rxcblist_t *cur;
+	struct aim_rxcblist_s *cur;
 
-  if (!conn)
-    return NULL;
+	if (!conn)
+		return NULL;
+
+	faimdprintf(sess, 1, "aim_callhandler: calling for %04x/%04x\n", family, type);
 
-  faimdprintf(sess, 1, "aim_callhandler: calling for %04x/%04x\n", family, type);
-  
-  for (cur = conn->handlerlist; cur; cur = cur->next) {
-    if ((cur->family == family) && (cur->type == type))
-      return cur->handler;
-  }
+	for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; cur = cur->next) {
+		if ((cur->family == family) && (cur->type == type))
+			return cur->handler;
+	}
 
-  if (type == AIM_CB_SPECIAL_DEFAULT) {
-    faimdprintf(sess, 1, "aim_callhandler: no default handler for family 0x%04x\n", family);
-    return NULL; /* prevent infinite recursion */
-  }
+	if (type == AIM_CB_SPECIAL_DEFAULT) {
+		faimdprintf(sess, 1, "aim_callhandler: no default handler for family 0x%04x\n", family);
+		return NULL; /* prevent infinite recursion */
+	}
 
-  faimdprintf(sess, 1, "aim_callhandler: no handler for  0x%04x/0x%04x\n", family, type);
+	faimdprintf(sess, 1, "aim_callhandler: no handler for  0x%04x/0x%04x\n", family, type);
 
-  return aim_callhandler(sess, conn, family, AIM_CB_SPECIAL_DEFAULT);
+	return aim_callhandler(sess, conn, family, AIM_CB_SPECIAL_DEFAULT);
 }
 
-faim_internal int aim_callhandler_noparam(struct aim_session_t *sess,
-					  struct aim_conn_t *conn,
-					  u_short family,
-					  u_short type,
-					  struct command_rx_struct *ptr)
+faim_internal void aim_clonehandlers(aim_session_t *sess, aim_conn_t *dest, aim_conn_t *src)
 {
-  aim_rxcallback_t userfunc = NULL;
-  userfunc = aim_callhandler(sess, conn, family, type);
-  if (userfunc)
-    return userfunc(sess, ptr);
-  return 1; /* XXX */
+	struct aim_rxcblist_s *cur;
+
+	for (cur = (struct aim_rxcblist_s *)src->handlerlist; cur; cur = cur->next) {
+		aim_conn_addhandler(sess, dest, cur->family, cur->type, 
+						cur->handler, cur->flags);
+	}
+
+	return;
+}
+
+faim_internal int aim_callhandler_noparam(aim_session_t *sess, aim_conn_t *conn,fu16_t family, fu16_t type, aim_frame_t *ptr)
+{
+	aim_rxcallback_t userfunc;
+
+	if ((userfunc = aim_callhandler(sess, conn, family, type)))
+		return userfunc(sess, ptr);
+
+	return 1; /* XXX */
 }
 
 /*
-  aim_rxdispatch()
-
-  Basically, heres what this should do:
-    1) Determine correct packet handler for this packet
-    2) Mark the packet handled (so it can be dequeued in purge_queue())
-    3) Send the packet to the packet handler
-    4) Go to next packet in the queue and start over
-    5) When done, run purge_queue() to purge handled commands
-
-  Note that any unhandlable packets should probably be left in the
-  queue.  This is the best way to prevent data loss.  This means
-  that a single packet may get looked at by this function multiple
-  times.  This is more good than bad!  This behavior may change.
-
-  Aren't queue's fun? 
-
-  TODO: Get rid of all the ugly if's.
-  TODO: Clean up.
-  TODO: More support for mid-level handlers.
-  TODO: Allow for NULL handlers.
-  
+ * aim_rxdispatch()
+ *
+ * Basically, heres what this should do:
+ *   1) Determine correct packet handler for this packet
+ *   2) Mark the packet handled (so it can be dequeued in purge_queue())
+ *   3) Send the packet to the packet handler
+ *   4) Go to next packet in the queue and start over
+ *   5) When done, run purge_queue() to purge handled commands
+ *
+ * TODO: Clean up.
+ * TODO: More support for mid-level handlers.
+ * TODO: Allow for NULL handlers.
+ *
  */
-faim_export int aim_rxdispatch(struct aim_session_t *sess)
+faim_export void aim_rxdispatch(aim_session_t *sess)
 {
-  int i = 0;
-  struct command_rx_struct *workingPtr = NULL;
-  static int critical = 0;
-  
-  if (critical)
-    return 0; /* don't call recursively! */
+	int i;
+	aim_frame_t *cur;
 
-  critical = 1;
+	for (cur = sess->queue_incoming, i = 0; cur; cur = cur->next, i++) {
+
+		/*
+		 * XXX: This is still fairly ugly.
+		 */
 
-  if (sess->queue_incoming == NULL) {
-    faimdprintf(sess, 1, "parse_generic: incoming packet queue empty.\n");
-  } else {
-    workingPtr = sess->queue_incoming;
-    for (i = 0; workingPtr != NULL; workingPtr = workingPtr->next, i++) {
-      unsigned short family,subtype;
+		if (cur->handled)
+			continue;
 
-      /*
-       * XXX: This is still fairly ugly.
-       */
-      if (workingPtr->handled)
-	continue;
+		/*
+		 * This is a debugging/sanity check only and probably 
+		 * could/should be removed for stable code.
+		 */
+		if (((cur->hdrtype == AIM_FRAMETYPE_OFT) && 
+		   (cur->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) || 
+		  ((cur->hdrtype == AIM_FRAMETYPE_FLAP) && 
+		   (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS))) {
+			faimdprintf(sess, 0, "rxhandlers: incompatible frame type %d on connection type 0x%04x\n", cur->hdrtype, cur->conn->type);
+			cur->handled = 1;
+			continue;
+		}
 
-      /*
-       * This is a debugging/sanity check only and probably could/should be removed
-       * for stable code.
-       */
-      if (((workingPtr->hdrtype == AIM_FRAMETYPE_OFT) && 
-	   (workingPtr->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) || 
-	  ((workingPtr->hdrtype == AIM_FRAMETYPE_OSCAR) && 
-	   (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS))) {
-	faimdprintf(sess, 0, "rxhandlers: incompatible frame type %d on connection type 0x%04x\n", workingPtr->hdrtype, workingPtr->conn->type);
-	workingPtr->handled = 1;
-	continue;
-      }
+		if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS) {
+			if (cur->hdrtype != AIM_FRAMETYPE_OFT) {
+				faimdprintf(sess, 0, "internal error: non-OFT frames on OFT connection\n");
+				cur->handled = 1; /* get rid of it */
+			} else {
+				/* XXX: implement this */
+				faimdprintf(sess, 0, "faim: OFT frame!\n");
+				cur->handled = 1; /* get rid of it */
+			}
+			continue;
+		}
 
-      if (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS) {
-	/* make sure that we only get OFT frames on these connections */
-	if (workingPtr->hdrtype != AIM_FRAMETYPE_OFT) {
-	  faimdprintf(sess, 0, "internal error: non-OFT frames on OFT connection\n");
-	  workingPtr->handled = 1; /* get rid of it */
-	} else {
-	  /* XXX: implement this */
-	  faimdprintf(sess, 0, "faim: OFT frame!\n");
-	  workingPtr->handled = 1; /* get rid of it */
-	}
-	continue;
-      }
+		if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
+			/* not possible */
+			faimdprintf(sess, 0, "rxdispatch called on RENDEZVOUS_OUT connection!\n");
+			cur->handled = 1;
+			continue;
+		}
 
-      if (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
-	/* not possible */
-	faimdprintf(sess, 0, "rxdispatch called on RENDEZVOUS_OUT connection!\n");
-	workingPtr->handled = 1;
-	continue;
-      }
+		if (cur->hdr.flap.type == 0x01) {
+			
+			cur->handled = aim_callhandler_noparam(sess, cur->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, cur); /* XXX use consumenonsnac */
+			
+			continue;
+			
+		} else if (cur->hdr.flap.type == 0x02) {
 
-      if ((workingPtr->commandlen == 4) && 
-	  (aimutil_get32(workingPtr->data) == 0x00000001)) {
-	workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
-	continue;
-      } 
+			if ((cur->handled = consumesnac(sess, cur)))
+				continue;
 
-      if (workingPtr->hdr.oscar.type == 0x04) {
-	workingPtr->handled = aim_negchan_middle(sess, workingPtr);
-	continue;
-      }
+		} else if (cur->hdr.flap.type == 0x04) {
 
-      if ((workingPtr->handled = consumesnac(sess, workingPtr)))
-	continue;
-	  
-      if (!workingPtr->handled) {
-	family = aimutil_get16(workingPtr->data);
-	subtype = aimutil_get16(workingPtr->data+2);
+			cur->handled = negchan_middle(sess, cur);
+			continue;
 
-	faimdprintf(sess, 1, "warning: unhandled packet %04x/%04x\n", family, subtype);
-	consumenonsnac(sess, workingPtr, 0xffff, 0xffff); /* last chance! */
-	workingPtr->handled = 1;
-      }
-    }
-  }
+		} else if (cur->hdr.flap.type == 0x05)
+			;
+		
+		if (!cur->handled) {
+			consumenonsnac(sess, cur, 0xffff, 0xffff); /* last chance! */
+			cur->handled = 1;
+		}
+	}
 
-  /* 
-   * This doesn't have to be called here.  It could easily be done
-   * by a seperate thread or something. It's an administrative operation,
-   * and can take a while. Though the less you call it the less memory
-   * you'll have :)
-   */
-  aim_purge_rxqueue(sess);
+	/* 
+	 * This doesn't have to be called here.  It could easily be done
+	 * by a seperate thread or something. It's an administrative operation,
+	 * and can take a while. Though the less you call it the less memory
+	 * you'll have :)
+	 */
+	aim_purge_rxqueue(sess);
 
-  critical = 0;
-  
-  return 0;
+	return;
 }
 
-faim_internal int aim_parse_unknown(struct aim_session_t *sess,
-					  struct command_rx_struct *command, ...)
+faim_internal int aim_parse_unknown(aim_session_t *sess, aim_frame_t *frame, ...)
 {
-  u_int i = 0;
+	int i;
 
-  if (!sess || !command)
-    return 1;
-
-  faimdprintf(sess, 1, "\nRecieved unknown packet:");
+	faimdprintf(sess, 1, "\nRecieved unknown packet:");
 
-  for (i = 0; i < command->commandlen; i++)
-    {
-      if ((i % 8) == 0)
-	faimdprintf(sess, 1, "\n\t");
+	for (i = 0; aim_bstream_empty(&frame->data); i++) {
+		if ((i % 8) == 0)
+			faimdprintf(sess, 1, "\n\t");
 
-      faimdprintf(sess, 1, "0x%2x ", command->data[i]);
-    }
-  
-  faimdprintf(sess, 1, "\n\n");
+		faimdprintf(sess, 1, "0x%2x ", aimbs_get8(&frame->data));
+	}
 
-  return 1;
+	faimdprintf(sess, 1, "\n\n");
+
+	return 1;
 }
 
 
-faim_internal int aim_negchan_middle(struct aim_session_t *sess,
-				     struct command_rx_struct *command)
-{
-  struct aim_tlvlist_t *tlvlist;
-  char *msg = NULL;
-  unsigned short code = 0;
-  aim_rxcallback_t userfunc = NULL;
-  int ret = 1;
 
-  /* Used only by the older login protocol */
-  /* XXX remove this special case? */
-  if (command->conn->type == AIM_CONN_TYPE_AUTH)
-    return consumenonsnac(sess, command, 0x0017, 0x0003);
-
-  tlvlist = aim_readtlvchain(command->data, command->commandlen);
-
-  if (aim_gettlv(tlvlist, 0x0009, 1))
-    code = aim_gettlv16(tlvlist, 0x0009, 1);
-
-  if (aim_gettlv(tlvlist, 0x000b, 1))
-    msg = aim_gettlv_str(tlvlist, 0x000b, 1);
-
-  if ((userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR))) 
-    ret = userfunc(sess, command, code, msg);
-
-  aim_freetlvchain(&tlvlist);
-
-  if (msg)
-    free(msg);
-
-  return ret;
-}
-