#define FAIM_INTERNAL
#include <aim.h>
-/*
- * 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, ...)
+struct aim_rxcblist_s {
+ fu16_t family;
+ fu16_t type;
+ aim_rxcallback_t handler;
+ u_short flags;
+ struct aim_rxcblist_s *next;
+};
+
+static aim_module_t *findmodule(aim_session_t *sess, const char *name)
{
- u_short family;
- u_short subtype;
-
- u_short maxf;
- u_short 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",
- }
- };
-
- 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((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);
-
- return 1;
-}
+ aim_module_t *cur;
-faim_export int aim_conn_addhandler(struct aim_session_t *sess,
- struct aim_conn_t *conn,
- u_short family,
- u_short type,
- rxcallback_t newhandler,
- u_short flags)
-{
- struct aim_rxcblist_t *newcb;
-
- if (!conn)
- return -1;
-
- faimdprintf(sess, 1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
-
- 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;
-
- cur = conn->handlerlist;
-
- while (cur->next)
- cur = cur->next;
- cur->next = newcb;
- }
-
- return 0;
+ for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
+ if (strcmp(name, cur->name) == 0)
+ return cur;
+ }
+
+ return NULL;
}
-faim_export int aim_clearhandlers(struct aim_conn_t *conn)
+faim_internal int aim__registermodule(aim_session_t *sess, int (*modfirst)(aim_session_t *, aim_module_t *))
{
- struct aim_rxcblist_t *cur;
+ aim_module_t *mod;
+
+ if (!sess || !modfirst)
+ return -1;
- if (!conn)
- return -1;
+ if (!(mod = malloc(sizeof(aim_module_t))))
+ return -1;
+ memset(mod, 0, sizeof(aim_module_t));
- for (cur = conn->handlerlist; cur; ) {
- struct aim_rxcblist_t *tmp;
+ if (modfirst(sess, mod) == -1) {
+ free(mod);
+ return -1;
+ }
- tmp = cur->next;
- free(cur);
- cur = tmp;
- }
- conn->handlerlist = NULL;
+ if (findmodule(sess, mod->name)) {
+ if (mod->shutdown)
+ mod->shutdown(sess, mod);
+ free(mod);
+ return -1;
+ }
- return 0;
+ mod->next = (aim_module_t *)sess->modlistv;
+ (aim_module_t *)sess->modlistv = mod;
+
+ faimdprintf(sess, 1, "registered module %s (family 0x%04x)\n", mod->name, mod->family);
+
+ return 0;
}
-faim_internal rxcallback_t aim_callhandler(struct aim_session_t *sess,
- struct aim_conn_t *conn,
- unsigned short family,
- unsigned short type)
+faim_internal void aim__shutdownmodules(aim_session_t *sess)
{
- struct aim_rxcblist_t *cur;
+ aim_module_t *cur;
- if (!conn)
- return NULL;
+ for (cur = (aim_module_t *)sess->modlistv; cur; ) {
+ aim_module_t *tmp;
- 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;
- }
+ tmp = cur->next;
- 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 (cur->shutdown)
+ cur->shutdown(sess, cur);
- faimdprintf(sess, 1, "aim_callhandler: no handler for 0x%04x/0x%04x\n", family, type);
+ free(cur);
- return aim_callhandler(sess, conn, family, AIM_CB_SPECIAL_DEFAULT);
+ cur = tmp;
+ }
+
+ sess->modlistv = NULL;
+
+ return;
}
-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)
+static int consumesnac(aim_session_t *sess, aim_frame_t *rx)
{
- rxcallback_t userfunc = NULL;
- userfunc = aim_callhandler(sess, conn, family, type);
- if (userfunc)
- return userfunc(sess, ptr);
- return 1; /* XXX */
+ aim_module_t *cur;
+ aim_modsnac_t snac;
+
+ if (aim_bstream_empty(&rx->data) < 10)
+ return 0;
+
+ snac.family = aimbs_get16(&rx->data);
+ snac.subtype = aimbs_get16(&rx->data);
+ snac.flags = aimbs_get16(&rx->data);
+ snac.id = aimbs_get32(&rx->data);
+
+ for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
+
+ if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
+ (cur->family != snac.family))
+ continue;
+
+ if (cur->snachandler(sess, cur, rx, &snac, &rx->data))
+ return 1;
+
+ }
+
+ return 0;
}
-/*
- 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.
-
- */
-faim_export int aim_rxdispatch(struct aim_session_t *sess)
+static int consumenonsnac(aim_session_t *sess, aim_frame_t *rx, fu16_t family, fu16_t subtype)
{
- int i = 0;
- struct command_rx_struct *workingPtr = NULL;
-
- if (sess->queue_incoming == NULL) {
- faimdprintf(sess, 1, "parse_generic: incoming packet queue empty.\n");
- return 0;
- } else {
- workingPtr = sess->queue_incoming;
- for (i = 0; workingPtr != NULL; workingPtr = workingPtr->next, i++) {
- /*
- * 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 (((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;
- }
-
- switch(workingPtr->conn->type) {
- case -1:
- /*
- * This can happen if we have a queued command
- * that was recieved after a connection has
- * been terminated. In which case, the handler
- * list has been cleared, and there's nothing we
- * can do for it. We can only cancel it.
- */
- workingPtr->handled = 1;
- break;
- case AIM_CONN_TYPE_AUTH: {
- unsigned long head;
-
- head = aimutil_get32(workingPtr->data);
- if ((head == 0x00000001) && (workingPtr->commandlen == 4)) {
- faimdprintf(sess, 1, "got connection ack on auth line\n");
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
- } else if (workingPtr->hdr.oscar.type == 0x04) {
- /* Used only by the older login protocol */
- workingPtr->handled = aim_authparse(sess, workingPtr);
- } else {
- unsigned short family,subtype;
-
- family = aimutil_get16(workingPtr->data);
- subtype = aimutil_get16(workingPtr->data+2);
-
- switch (family) {
- /* New login protocol */
- case 0x0017:
- if (subtype == 0x0001)
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr);
- else if (subtype == 0x0003)
- workingPtr->handled = aim_authparse(sess, workingPtr);
- else if (subtype == 0x0007)
- workingPtr->handled = aim_authkeyparse(sess, workingPtr);
- else
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
- break;
-
- case 0x0001:
- if (subtype == 0x0003)
- workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
- else if (subtype == 0x0007)
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
- else if (subtype == 0x0018)
- workingPtr->handled = aim_parse_hostversions(sess, workingPtr);
- else
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0xffff, workingPtr);
- break;
-
- case 0x0007:
- if (subtype == 0x0003)
- workingPtr->handled = aim_parse_infochange(sess, workingPtr);
- else if (subtype == 0x0005)
- workingPtr->handled = aim_parse_infochange(sess, workingPtr);
- else if (subtype == 0x0007)
- workingPtr->handled = aim_parse_accountconfirm(sess, workingPtr);
- break;
-
- case AIM_CB_FAM_SPECIAL:
- if (subtype == AIM_CB_SPECIAL_DEBUGCONN_CONNECT) {
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
- break;
- } else
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
- break;
-
- default:
- break;
- }
- }
- break;
- }
- case AIM_CONN_TYPE_BOS: {
- u_short family;
- u_short subtype;
-
- if (workingPtr->hdr.oscar.type == 0x04) {
- workingPtr->handled = aim_negchan_middle(sess, workingPtr);
- break;
- }
+ aim_module_t *cur;
+ aim_modsnac_t snac;
+
+ snac.family = family;
+ snac.subtype = subtype;
+ snac.flags = snac.id = 0;
+
+ for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
+
+ if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
+ (cur->family != snac.family))
+ continue;
+
+ if (cur->snachandler(sess, cur, rx, &snac, &rx->data))
+ return 1;
- family = aimutil_get16(workingPtr->data);
- subtype = aimutil_get16(workingPtr->data+2);
-
- switch (family) {
- case 0x0000: /* not really a family, but it works */
- if (subtype == 0x0001)
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
- else
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
- break;
- case 0x0001: /* Family: General */
- switch (subtype) {
- case 0x0001:
- workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
- break;
- case 0x0003:
- workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
- break;
- case 0x0005:
- workingPtr->handled = aim_handleredirect_middle(sess, workingPtr);
- break;
- case 0x0007:
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
- break;
- case 0x000a:
- workingPtr->handled = aim_parse_ratechange_middle(sess, workingPtr);
- break;
- case 0x000f:
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr);
- break;
- case 0x0010:
- workingPtr->handled = aim_parse_evilnotify_middle(sess, workingPtr);
- break;
- case 0x0013:
- workingPtr->handled = aim_parsemotd_middle(sess, workingPtr);
- break;
- case 0x0018:
- workingPtr->handled = aim_parse_hostversions(sess, workingPtr);
- break;
- default:
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
- break;
- }
- break;
- case 0x0002: /* Family: Location */
- switch (subtype) {
- case 0x0001:
- workingPtr->handled = aim_parse_locateerr(sess, workingPtr);
- break;
- case 0x0003:
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr);
- break;
- case 0x0006:
- workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr);
- break;
- default:
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
- break;
- }
- break;
- case 0x0003: /* Family: Buddy List */
- switch (subtype) {
- case 0x0001:
- workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
- break;
- case 0x0003:
- workingPtr->handled = aim_parse_buddyrights(sess, workingPtr);
- break;
- case 0x000b: /* oncoming buddy */
- workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr);
- break;
- case 0x000c: /* offgoing buddy */
- workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr);
- break;
- default:
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
- }
- break;
- case 0x0004: /* Family: Messaging */
- switch (subtype) {
- case 0x0001:
- workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr);
- break;
- case 0x0005:
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr);
- break;
- case 0x0006:
- workingPtr->handled = aim_parse_outgoing_im_middle(sess, workingPtr);
- break;
- case 0x0007:
- workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr);
- break;
- case 0x000a:
- workingPtr->handled = aim_parse_missedcall(sess, workingPtr);
- break;
- case 0x000c:
- workingPtr->handled = aim_parse_msgack_middle(sess, workingPtr);
- break;
- default:
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
- }
- break;
- case 0x0009:
- if (subtype == 0x0001)
- workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
- else if (subtype == 0x0003)
- workingPtr->handled = aim_parse_bosrights(sess, workingPtr);
- else
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
- break;
- case 0x000a: /* Family: User lookup */
- switch (subtype) {
- case 0x0001:
- workingPtr->handled = aim_parse_searcherror(sess, workingPtr);
- break;
- case 0x0003:
- workingPtr->handled = aim_parse_searchreply(sess, workingPtr);
- break;
- default:
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
- }
- break;
- case 0x000b: {
- if (subtype == 0x0001)
- workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
- else if (subtype == 0x0002)
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000b, 0x0002, workingPtr);
- else
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
- break;
- }
- case 0x0013: {
- faimdprintf(sess, 0, "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;
- default:
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
- break;
- } /* switch(family) */
- break;
- } /* AIM_CONN_TYPE_BOS */
- case AIM_CONN_TYPE_ADS: {
- unsigned short family;
- unsigned short subtype;
-
- family = aimutil_get16(workingPtr->data);
- subtype= aimutil_get16(workingPtr->data+2);
-
- if ((family == 0x0000) && (subtype == 0x00001)) {
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
- } else if ((family == 0x0001) && (subtype == 0x0003)) {
- workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
- } else {
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
- }
- break;
- }
- case AIM_CONN_TYPE_CHATNAV: {
- u_short family;
- u_short subtype;
- family = aimutil_get16(workingPtr->data);
- subtype= aimutil_get16(workingPtr->data+2);
-
- if ((family == 0x0000) && (subtype == 0x00001)) {
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
- } else if ((family == 0x0001) && (subtype == 0x0003)) {
- workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
- } else if ((family == 0x000d) && (subtype == 0x0009)) {
- workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr);
- } else {
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
- }
- break;
- }
- case AIM_CONN_TYPE_CHAT: {
- u_short family, subtype;
-
- family = aimutil_get16(workingPtr->data);
- subtype= aimutil_get16(workingPtr->data+2);
-
- if ((family == 0x0000) && (subtype == 0x00001)) {
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, workingPtr);
- } else if (family == 0x0001) {
- if (subtype == 0x0001)
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0001, workingPtr);
- else if (subtype == 0x0003)
- workingPtr->handled = aim_parse_hostonline(sess, workingPtr);
- else if (subtype == 0x0007)
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
- else if (subtype == 0x000a)
- workingPtr->handled = aim_parse_ratechange_middle(sess, workingPtr);
- else
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
- } else if (family == 0x000e) {
- if (subtype == 0x0002)
- workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr);
- else if (subtype == 0x0003)
- workingPtr->handled = aim_chat_parse_joined(sess, workingPtr);
- else if (subtype == 0x0004)
- workingPtr->handled = aim_chat_parse_leave(sess, workingPtr);
- else if (subtype == 0x0006)
- workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr);
- else
- faimdprintf(sess, 0, "Chat: unknown snac %04x/%04x\n", family, subtype);
- } else {
- faimdprintf(sess, 0, "Chat: unknown snac %04x/%04x\n", family, subtype);
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
- }
- break;
- }
- case 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 */
- break;
}
-
- /* XXX: implement this */
- faimdprintf(sess, 0, "faim: OFT frame!\n");
-
- break;
- }
- case AIM_CONN_TYPE_RENDEZVOUS_OUT: {
- /* not possible */
- break;
- }
- default:
- faimdprintf(sess, 0, "internal error: unknown connection type (very bad.) (type = %d, fd = %d, commandlen = %02x)\n\n", workingPtr->conn->type, workingPtr->conn->fd, workingPtr->commandlen);
- workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
- break;
- }
- }
- }
-
- /*
- * 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);
-
- return 0;
+
+ return 0;
}
-faim_internal int aim_parse_msgack_middle(struct aim_session_t *sess, struct command_rx_struct *command)
+static int negchan_middle(aim_session_t *sess, aim_frame_t *fr)
{
- rxcallback_t userfunc = NULL;
- char sn[MAXSNLEN];
- unsigned short type;
- int i = 10+8; /* skip SNAC and cookie */
- int ret = 1;
- unsigned char snlen;
+ aim_tlvlist_t *tlvlist;
+ char *msg = NULL;
+ fu16_t code = 0;
+ aim_rxcallback_t userfunc;
+ int ret = 1;
+
+ if (aim_bstream_empty(&fr->data) == 0) {
+ /* XXX should do something with this */
+ return 1;
+ }
+
+ /* 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);
- type = aimutil_get16(command->data+i);
- i += 2;
+ tlvlist = aim_readtlvchain(&fr->data);
- snlen = aimutil_get8(command->data+i);
- i++;
+ if (aim_gettlv(tlvlist, 0x0009, 1))
+ code = aim_gettlv16(tlvlist, 0x0009, 1);
- memset(sn, 0, sizeof(sn));
- strncpy(sn, (char *)command->data+i, snlen);
+ if (aim_gettlv(tlvlist, 0x000b, 1))
+ msg = aim_gettlv_str(tlvlist, 0x000b, 1);
- if ((userfunc = aim_callhandler(sess, command->conn, 0x0004, 0x000c)))
- ret = userfunc(sess, command, type, sn);
+ if ((userfunc = aim_callhandler(sess, fr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR)))
+ ret = userfunc(sess, fr, code, msg);
- return ret;
+ aim_freetlvchain(&tlvlist);
+
+ free(msg);
+
+ 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.
- *
+ * Bleck functions get called when there's no non-bleck functions
+ * around to cleanup the mess...
*/
-faim_internal int aim_parse_ratechange_middle(struct aim_session_t *sess, struct command_rx_struct *command)
+faim_internal int bleck(aim_session_t *sess, aim_frame_t *frame, ...)
{
- rxcallback_t userfunc = NULL;
- int ret = 1;
- int i;
- int code;
- unsigned long rateclass, windowsize, clear, alert, limit, disconnect;
- unsigned long currentavg, maxavg;
-
- i = 10;
-
- code = aimutil_get16(command->data+i);
- i += 2;
-
- rateclass = aimutil_get16(command->data+i);
- i += 2;
-
- windowsize = aimutil_get32(command->data+i);
- i += 4;
- clear = aimutil_get32(command->data+i);
- i += 4;
- alert = aimutil_get32(command->data+i);
- i += 4;
- limit = aimutil_get32(command->data+i);
- i += 4;
- disconnect = aimutil_get32(command->data+i);
- i += 4;
- currentavg = aimutil_get32(command->data+i);
- i += 4;
- maxavg = aimutil_get32(command->data+i);
- i += 4;
-
- if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x000a)))
- ret = userfunc(sess, command, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg);
-
- return ret;
-}
+ fu16_t family, subtype;
+ fu16_t maxf, maxs;
+
+ 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]);
+
+ if (frame->hdr.flap.type == 0x02) {
+
+ 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 {
-faim_internal int aim_parse_evilnotify_middle(struct aim_session_t *sess, struct command_rx_struct *command)
-{
- rxcallback_t userfunc = NULL;
- int ret = 1;
- int i;
- unsigned short newevil;
- struct aim_userinfo_s userinfo;
-
- i = 10;
- newevil = aimutil_get16(command->data+10);
- i += 2;
-
- memset(&userinfo, 0, sizeof(struct aim_userinfo_s));
- if (command->commandlen-i)
- i += aim_extractuserinfo(sess, command->data+i, &userinfo);
-
- if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0010)))
- ret = userfunc(sess, command, newevil, &userinfo);
-
- return ret;
-}
+ 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);
-faim_internal int aim_parsemotd_middle(struct aim_session_t *sess,
- struct command_rx_struct *command, ...)
-{
- rxcallback_t userfunc = NULL;
- char *msg;
- int ret=1;
- struct aim_tlvlist_t *tlvlist;
- u_short id;
-
- /*
- * Code.
- *
- * Valid values:
- * 1 Mandatory upgrade
- * 2 Advisory upgrade
- * 3 System bulletin
- * 4 Nothing's wrong ("top o the world" -- normal)
- *
- */
- id = aimutil_get16(command->data+10);
-
- /*
- * TLVs follow
- */
- if (!(tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12)))
- return ret;
-
- if (!(msg = aim_gettlv_str(tlvlist, 0x000b, 1))) {
- aim_freetlvchain(&tlvlist);
- return ret;
- }
-
- userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0013);
- if (userfunc)
- ret = userfunc(sess, command, id, msg);
-
- aim_freetlvchain(&tlvlist);
- free(msg);
-
- return ret;
+ }
+
+ return 1;
}
-faim_internal int aim_parse_hostonline(struct aim_session_t *sess,
- struct command_rx_struct *command, ...)
+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)
{
- rxcallback_t userfunc = NULL;
- int ret = 1;
- unsigned short *families = NULL;
- int famcount = 0, i;
+ struct aim_rxcblist_s *newcb;
- famcount = (command->commandlen-10)/2;
- if (!(families = malloc(command->commandlen-10)))
- return ret;
+ if (!conn)
+ return -1;
- for (i = 0; i < famcount; i++)
- families[i] = aimutil_get16(command->data+((i*2)+10));
+ faimdprintf(sess, 1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
- if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0003)))
- ret = userfunc(sess, command, famcount, families);
+ if (!(newcb = (struct aim_rxcblist_s *)calloc(1, sizeof(struct aim_rxcblist_s))))
+ return -1;
- free(families);
+ newcb->family = family;
+ newcb->type = type;
+ newcb->flags = flags;
+ newcb->handler = newhandler ? newhandler : bleck;
+ newcb->next = NULL;
- return ret;
-}
+ if (!conn->handlerlist)
+ conn->handlerlist = (void *)newcb;
+ else {
+ struct aim_rxcblist_s *cur;
-faim_internal int aim_parse_accountconfirm(struct aim_session_t *sess,
- struct command_rx_struct *command)
-{
- rxcallback_t userfunc = NULL;
- int ret = 1;
- int status = -1;
-
- status = aimutil_get16(command->data+10);
-
- if ((userfunc = aim_callhandler(sess, command->conn, 0x0007, 0x0007)))
- ret = userfunc(sess, command, status);
+ for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur->next; cur = cur->next)
+ ;
+ cur->next = newcb;
+ }
- return ret;
+ return 0;
}
-faim_internal int aim_parse_infochange(struct aim_session_t *sess,
- struct command_rx_struct *command)
+faim_export int aim_clearhandlers(aim_conn_t *conn)
{
- unsigned short subtype; /* called for both reply and change-reply */
- int i;
-
- subtype = aimutil_get16(command->data+2);
-
- /*
- * struct {
- * unsigned short perms;
- * unsigned short tlvcount;
- * aim_tlv_t tlvs[tlvcount];
- * } admin_info[n];
- */
- for (i = 10; i < command->commandlen; ) {
- int perms, tlvcount;
-
- perms = aimutil_get16(command->data+i);
- i += 2;
-
- tlvcount = aimutil_get16(command->data+i);
- i += 2;
-
- while (tlvcount) {
- rxcallback_t userfunc;
- struct aim_tlv_t *tlv;
- int str = 0;
-
- if ((aimutil_get16(command->data+i) == 0x0011) ||
- (aimutil_get16(command->data+i) == 0x0004))
- str = 1;
-
- if (str)
- tlv = aim_grabtlvstr(command->data+i);
- else
- tlv = aim_grabtlv(command->data+i);
-
- /* XXX fix so its only called once for the entire packet */
- if ((userfunc = aim_callhandler(sess, command->conn, 0x0007, subtype)))
- userfunc(sess, command, perms, tlv->type, tlv->length, tlv->value, str);
-
- if (tlv)
- i += 2+2+tlv->length;
-
- if (tlv && tlv->value)
- free(tlv->value);
- if (tlv)
- free(tlv);
-
- tlvcount--;
- }
- }
-
- return 1;
-}
+ struct aim_rxcblist_s *cur;
-faim_internal int aim_parse_hostversions(struct aim_session_t *sess,
- struct command_rx_struct *command, ...)
-{
- rxcallback_t userfunc = NULL;
- int ret = 1;
- int vercount;
+ if (!conn)
+ return -1;
- vercount = (command->commandlen-10)/4;
-
- if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0018)))
- ret = userfunc(sess, command, vercount, command->data+10);
+ for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; ) {
+ struct aim_rxcblist_s *tmp;
- return ret;
-}
+ tmp = cur->next;
+ free(cur);
+ cur = tmp;
+ }
+ conn->handlerlist = NULL;
-faim_internal int aim_handleredirect_middle(struct aim_session_t *sess,
- struct command_rx_struct *command, ...)
-{
- int serviceid = 0;
- unsigned char *cookie = NULL;
- char *ip = NULL;
- rxcallback_t userfunc = NULL;
- struct aim_tlvlist_t *tlvlist;
- int ret = 1;
-
- tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10);
-
- if (aim_gettlv(tlvlist, 0x000d, 1))
- serviceid = aim_gettlv16(tlvlist, 0x000d, 1);
- if (aim_gettlv(tlvlist, 0x0005, 1))
- ip = aim_gettlv_str(tlvlist, 0x0005, 1);
- if (aim_gettlv(tlvlist, 0x0006, 1))
- cookie = aim_gettlv_str(tlvlist, 0x0006, 1);
-
- if ((serviceid == AIM_CONN_TYPE_CHAT) && sess->pendingjoin) {
-
- /*
- * Chat hack.
- *
- */
- if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0005)))
- ret = userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin, (int)sess->pendingjoinexchange);
- free(sess->pendingjoin);
- sess->pendingjoin = NULL;
- sess->pendingjoinexchange = 0;
- } else if (!serviceid || !ip || !cookie) { /* yeep! */
- ret = 1;
- } else {
- if ((userfunc = aim_callhandler(sess, command->conn, 0x0001, 0x0005)))
- ret = userfunc(sess, command, serviceid, ip, cookie);
- }
-
- if (ip)
- free(ip);
- if (cookie)
- free(cookie);
-
- aim_freetlvchain(&tlvlist);
-
- return ret;
+ return 0;
}
-faim_internal int aim_parse_unknown(struct aim_session_t *sess,
- struct command_rx_struct *command, ...)
+faim_internal aim_rxcallback_t aim_callhandler(aim_session_t *sess, aim_conn_t *conn, fu16_t family, fu16_t type)
{
- u_int i = 0;
+ struct aim_rxcblist_s *cur;
- if (!sess || !command)
- return 1;
+ if (!conn)
+ return NULL;
- faimdprintf(sess, 1, "\nRecieved unknown packet:");
+ faimdprintf(sess, 1, "aim_callhandler: calling for %04x/%04x\n", family, type);
- for (i = 0; i < command->commandlen; i++)
- {
- if ((i % 8) == 0)
- faimdprintf(sess, 1, "\n\t");
+ for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; cur = cur->next) {
+ if ((cur->family == family) && (cur->type == type))
+ return cur->handler;
+ }
- faimdprintf(sess, 1, "0x%2x ", command->data[i]);
- }
-
- faimdprintf(sess, 1, "\n\n");
+ 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 */
+ }
- return 1;
-}
+ 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);
+}
-faim_internal int aim_negchan_middle(struct aim_session_t *sess,
- struct command_rx_struct *command)
+faim_internal void aim_clonehandlers(aim_session_t *sess, aim_conn_t *dest, aim_conn_t *src)
{
- struct aim_tlvlist_t *tlvlist;
- char *msg = NULL;
- unsigned short code = 0;
- rxcallback_t userfunc = NULL;
- int ret = 1;
+ struct aim_rxcblist_s *cur;
- 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);
+ 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);
+ }
- if ((userfunc = aim_callhandler(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR)))
- ret = userfunc(sess, command, code, msg);
+ return;
+}
- aim_freetlvchain(&tlvlist);
+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 (msg)
- free(msg);
+ if ((userfunc = aim_callhandler(sess, conn, family, type)))
+ return userfunc(sess, ptr);
- return ret;
+ return 1; /* XXX */
}
/*
- * aim_parse_generalerrs()
+ * 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
*
- * Middle handler for 0x0001 snac of each family.
+ * TODO: Clean up.
+ * TODO: More support for mid-level handlers.
+ * TODO: Allow for NULL handlers.
*
*/
-faim_internal int aim_parse_generalerrs(struct aim_session_t *sess,
- struct command_rx_struct *command, ...)
+faim_export void aim_rxdispatch(aim_session_t *sess)
{
- 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);
-
- if (command->commandlen > 10)
- error = aimutil_get16(command->data+10);
-
- if ((userfunc = aim_callhandler(sess, command->conn, family, subtype)))
- ret = userfunc(sess, command, error);
-
- return ret;
+ int i;
+ aim_frame_t *cur;
+
+ for (cur = sess->queue_incoming, i = 0; cur; cur = cur->next, i++) {
+
+ /*
+ * XXX: This is still fairly ugly.
+ */
+
+ if (cur->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;
+ }
+
+ 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 (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 (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 ((cur->handled = consumesnac(sess, cur)))
+ continue;
+
+ } else if (cur->hdr.flap.type == 0x04) {
+
+ cur->handled = negchan_middle(sess, cur);
+ continue;
+
+ } 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);
+
+ return;
+}
+
+faim_internal int aim_parse_unknown(aim_session_t *sess, aim_frame_t *frame, ...)
+{
+ int i;
+
+ faimdprintf(sess, 1, "\nRecieved unknown packet:");
+
+ for (i = 0; aim_bstream_empty(&frame->data); i++) {
+ if ((i % 8) == 0)
+ faimdprintf(sess, 1, "\n\t");
+
+ faimdprintf(sess, 1, "0x%2x ", aimbs_get8(&frame->data));
+ }
+
+ faimdprintf(sess, 1, "\n\n");
+
+ return 1;
}