]> andersk Git - libfaim.git/blobdiff - aim_rxhandlers.c
- Wed Nov 8 02:23:25 UTC 2000
[libfaim.git] / aim_rxhandlers.c
index d6bdc98f6c85ddd540556e4b871d61630390583d..4f5cf74c8b78899a22a17618b7d0d9abd72679b2 100644 (file)
  * Bleck functions get called when there's no non-bleck functions
  * around to cleanup the mess...
  */
-int bleck(struct aim_session_t *sess,struct command_rx_struct *workingPtr, ...)
+faim_internal int bleck(struct aim_session_t *sess,struct command_rx_struct *workingPtr, ...)
 {
   u_short family;
   u_short subtype;
-  family = (workingPtr->data[0] << 8) + workingPtr->data[1];
-  subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
-  printf("bleck: null handler for %04x/%04x\n", family, 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))
+    printf("bleck: null handler for %04x/%04x (%s)\n", family, subtype, literals[family][subtype+1]);
+  else
+    printf("bleck: null handler for %04x/%04x (no literal)\n",family,subtype);
+
   return 1;
 }
 
-int aim_conn_addhandler(struct aim_session_t *sess,
+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 *new,*cur;
+  struct aim_rxcblist_t *newcb;
 
   if (!conn)
     return -1;
 
-#if debug > 0
-  printf("aim_conn_addhandler: adding for %04x/%04x\n", family, type);
-#endif
+  faimdprintf(1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
 
-  new = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t));
-  new->family = family;
-  new->type = type;
-  new->flags = flags;
+  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)
-    new->handler = &bleck;
+    newcb->handler = &bleck;
   else
-    new->handler = newhandler;
-  new->next = NULL;
+    newcb->handler = newhandler;
+  newcb->next = NULL;
   
-  cur = conn->handlerlist;
-  if (!cur)
-    conn->handlerlist = new;
-  else 
-    {
-      while (cur->next)
-       cur = cur->next;
-      cur->next = new;
-    }
+  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;
 }
 
-int aim_clearhandlers(struct aim_conn_t *conn)
+faim_export int aim_clearhandlers(struct aim_conn_t *conn)
 {
- struct aim_rxcblist_t *cur,*tmp;
+ struct aim_rxcblist_t *cur;
+
  if (!conn)
    return -1;
 
  cur = conn->handlerlist;
- while(cur)
-   {
-     tmp = cur->next;
-     free(cur);
-     cur = tmp;
-   }
+ while(cur) {
+   struct aim_rxcblist_t *tmp;
+
+   tmp = cur->next;
+   free(cur);
+   cur = tmp;
+ }
+
  return 0;
 }
 
-rxcallback_t aim_callhandler(struct aim_conn_t *conn,
-                   u_short family,
-                   u_short type)
+faim_internal rxcallback_t aim_callhandler(struct aim_conn_t *conn,
+                                        u_short family,
+                                        u_short type)
 {
   struct aim_rxcblist_t *cur;
 
   if (!conn)
     return NULL;
 
-#if debug > 0
-  printf("aim_callhandler: calling for %04x/%04x\n", family, type);
-#endif
+  faimdprintf(1, "aim_callhandler: calling for %04x/%04x\n", family, type);
   
   cur = conn->handlerlist;
   while(cur)
@@ -101,20 +261,21 @@ rxcallback_t aim_callhandler(struct aim_conn_t *conn,
 
   if (type==0xffff)
     return NULL;
+
   return aim_callhandler(conn, family, 0xffff);
 }
 
-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 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)
 {
   rxcallback_t userfunc = NULL;
   userfunc = aim_callhandler(conn, family, type);
   if (userfunc)
     return userfunc(sess, ptr);
-  return 0;
+  return 1; /* XXX */
 }
 
 /*
@@ -140,427 +301,561 @@ int aim_callhandler_noparam(struct aim_session_t *sess,
   TODO: Allow for NULL handlers.
   
  */
-int aim_rxdispatch(struct aim_session_t *sess)
+faim_export int aim_rxdispatch(struct aim_session_t *sess)
 {
   int i = 0;
   struct command_rx_struct *workingPtr = NULL;
   
-  if (sess->queue_incoming == NULL)
-    /* this shouldn't really happen, unless the main loop's select is broke  */
-    printf("parse_generic: incoming packet queue empty.\n");
-  else
-    {
-      workingPtr = sess->queue_incoming;
-      for (i = 0; workingPtr != NULL; i++)
-       {
-         switch(workingPtr->conn->type)
-           {
-           case AIM_CONN_TYPE_AUTH:
-             {
-               u_long head;
-
-               head = aimutil_get32(workingPtr->data);
-               if (head == 0x00000001)
-                 {
-#if debug > 0
-                   printf("got connection ack on auth line\n");
+  if (sess->queue_incoming == NULL) {
+    faimdprintf(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))) {
+       printf("faim: 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: {
+       u_long head;
+       
+       head = aimutil_get32(workingPtr->data);
+       if (head == 0x00000001) {
+         faimdprintf(1, "got connection ack on auth line\n");
+         workingPtr->handled = 1;
+       } else if (workingPtr->hdr.oscar.type == 0x0004) {
+         workingPtr->handled = aim_authparse(sess, workingPtr);
+        } else {
+         u_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 0x0007:
+           if (subtype == 0x0005)
+             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY, 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;
+           } /* others fall through */
+         default:
+#if 0
+           /* Old login protocol */
+           /* any user callbacks will be called from here */
+           workingPtr->handled = aim_authparse(sess, workingPtr);
 #endif
-                   workingPtr->handled = 1;
-                 }
-               else
-                 {
-                   /* any user callbacks will be called from here */
-                   workingPtr->handled = aim_authparse(sess, workingPtr);
-                 }
-             }
-             break;
-           case AIM_CONN_TYPE_BOS:
-             {
-               u_short family;
-               u_short subtype;
-
-               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, 0x0000, 0x0001, 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_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, 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_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000a, workingPtr);
-                       break;
-                     case 0x000f:
-                       workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr);
-                       break;
-                     case 0x0013:
-                       workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0013, workingPtr);
-                       break;
-                     default:
-                       workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
-                     }
-                   break;
-                 case 0x0002: /* Family: Location */
-                   switch (subtype)
-                     {
-                     case 0x0001:
-                       workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0001, 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;
-                 case 0x0003: /* Family: Buddy List */
-                   switch (subtype)
-                     {
-                     case 0x0001:
-                       workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
-                       break;
-                     case 0x0003:
-                       workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0003, 0x0003, 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: Messeging */
-                   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 0x0007:
-                       workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr);
-                       break;
-                     case 0x000a:
-                       workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x000a, 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_callhandler_noparam(sess, workingPtr->conn, 0x0009, 0x0003, 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_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0001, workingPtr);
-                       break;
-                     case 0x0003:
-                       workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0003, 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;
-                 default:
-                   workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
-                   break;
-                 }
-             }
-             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 == 0x0002) && (subtype == 0x0006))
-                 {
-                   workingPtr->handled = 1;
-                   aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
-                 }
-               else
-                 {
-                   workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
-                 }
-             }
-             break;
-           case AIM_CONN_TYPE_CHAT:
-             printf("\nAHH! Dont know what to do with CHAT stuff yet!\n");
-             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
-             break;
-           default:
-             printf("\nAHHHHH! UNKNOWN CONNECTION TYPE! (0x%02x)\n\n", workingPtr->conn->type);
-             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
-             break;
-           }
-         /* move to next command */
-         workingPtr = workingPtr->next;
+           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;
        }
-    }
 
-  sess->queue_incoming = aim_purge_rxqueue(sess->queue_incoming);
+       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, 0x0000, 0x0001, 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_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, 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;
+         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: Messeging */
+         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_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0001, workingPtr);
+           break;
+         case 0x0003:
+           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0003, 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 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_CHATNAV: {
+       u_short family;
+       u_short subtype;
+       family = aimutil_get16(workingPtr->data);
+       subtype= aimutil_get16(workingPtr->data+2);
+       
+       if ((family == 0x0002) && (subtype == 0x0006)) {
+         workingPtr->handled = 1;
+         aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
+       } 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, 0x0000, 0x0001, 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_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
+         else if (subtype == 0x0007)
+           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, 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  
+           printf("Chat: unknown snac %04x/%04x\n", family, subtype); 
+       } else {
+         printf("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) {
+         printf("faim: internal error: non-OFT frames on OFT connection\n");
+         workingPtr->handled = 1; /* get rid of it */
+         break;
+       }
+       
+       /* XXX: implement this */
+       printf("faim: OFT frame!\n");
+       
+       break;
+      }
+      case AIM_CONN_TYPE_RENDEZVOUS_OUT: {
+       /* not possible */
+       break;
+      }
+      default:
+       printf("\ninternal 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;
 }
 
-/*
- * TODO: check and cure memory leakage in this function.
- * TODO: update to use new tlvlist routines
- */
-int aim_authparse(struct aim_session_t *sess, 
-                 struct command_rx_struct *command)
+faim_internal int aim_parse_msgack_middle(struct aim_session_t *sess, struct command_rx_struct *command)
 {
   rxcallback_t userfunc = NULL;
-  int iserror = 0;
-  struct aim_tlv_t *tlv = NULL;
-  char *errorurl = NULL;
-  short errorcode = 0x00;
-  u_int z = 0;
-  u_short family,subtype;
-
-  family = aimutil_get16(command->data);
-  subtype= aimutil_get16(command->data+2);
+  char sn[MAXSNLEN];
+  unsigned short type;
+  int i = 10+8; /* skip SNAC and cookie */
+  int ret = 1;
+  unsigned char snlen;
+
+  type = aimutil_get16(command->data+i);
+  i += 2;
+
+  snlen = aimutil_get8(command->data+i);
+  i++;
+
+  memset(sn, 0, sizeof(sn));
+  strncpy(sn, (char *)command->data+i, snlen);
+
+  if ((userfunc = aim_callhandler(command->conn, 0x0004, 0x000c)))
+    ret =  userfunc(sess, command, type, sn);
+
+  return ret;
+}
+
+faim_internal int aim_parse_ratechange_middle(struct aim_session_t *sess, struct command_rx_struct *command)
+{
+  rxcallback_t userfunc = NULL;
+  int ret = 1;
+  unsigned long newrate;
+
+  if (command->commandlen != 0x2f) {
+    printf("faim: unknown rate change length 0x%04x\n", command->commandlen);
+    return 1;
+  }
   
-  if ( (family == 0x0001) && 
-       (subtype== 0x0003) )
-    {
-      /* "server ready"  -- can be ignored */
-      userfunc = aim_callhandler(command->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY);
-    }
-  else if ( (family == 0x0007) &&
-           (subtype== 0x0005) )
-    {
-      /* "information change reply" */
-      userfunc = aim_callhandler(command->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY);
-    }
-  else
-    {
-      /* anything else -- usually used for login; just parse as pure TLVs */
+  newrate = aimutil_get32(command->data+34);
 
-      /*
-       * Free up the loginstruct first.
-       */
-      sess->logininfo.screen_name[0] = '\0';
-      if (sess->logininfo.BOSIP)
-       {
-         free(sess->logininfo.BOSIP);
-         sess->logininfo.BOSIP = NULL;
-       }
-      if (sess->logininfo.email)
-       {
-         free(sess->logininfo.email);
-         sess->logininfo.email = NULL;
-       }
-      sess->logininfo.regstatus = 0;
-
-      /* all this block does is figure out if it's an
-        error or a success, nothing more */
-      while (z < command->commandlen)
-       {
-         tlv = aim_grabtlvstr(&(command->data[z]));
-         switch(tlv->type) 
-           {
-           case 0x0001: /* screen name */
-             if (tlv->length >= MAXSNLEN)
-               {
-                 /* SN too large... truncate */
-                 printf("faim: login: screen name from OSCAR too long! (%d)\n", tlv->length);
-                 strncpy(sess->logininfo.screen_name, tlv->value, MAXSNLEN);
-               }
-             else
-               strncpy(sess->logininfo.screen_name, tlv->value, tlv->length);
-             z += 2 + 2 + tlv->length;
-             free(tlv);
-             tlv = NULL;
-             break;
-           case 0x0004: /* error URL */
-             errorurl = tlv->value;
-             z += 2 + 2 + tlv->length;
-             free(tlv);
-             tlv = NULL;
-             break;
-           case 0x0005: /* BOS IP */
-             sess->logininfo.BOSIP = tlv->value;
-             z += 2 + 2 + tlv->length;
-             free(tlv);
-             tlv = NULL;
-             break;
-           case 0x0006: /* auth cookie */
-             memcpy(sess->logininfo.cookie, tlv->value, AIM_COOKIELEN);
-             z += 2 + 2 + tlv->length;
-             free(tlv);
-             tlv=NULL;
-             break;
-           case 0x0011: /* email addy */
-             sess->logininfo.email = tlv->value;
-             z += 2 + 2 + tlv->length;
-             free(tlv);
-             tlv = NULL;
-             break;
-           case 0x0013: /* registration status */
-             sess->logininfo.regstatus = *(tlv->value);
-             z += 2 + 2 + tlv->length;
-             aim_freetlv(&tlv);
-             break;
-           case 0x0008: /* error code */
-             errorcode = *(tlv->value);
-             z += 2 + 2 + tlv->length;
-             aim_freetlv(&tlv);
-             iserror = 1;
-             break;
-           default:
-         z += 2 + 2 + tlv->length;
-         aim_freetlv(&tlv);
-         /* dunno */
-           }
-       }
+  if ((userfunc = aim_callhandler(command->conn, 0x0001, 0x000a)))
+    ret =  userfunc(sess, command, newrate);
 
-      if (iserror && 
-         errorurl)
-       {
-         userfunc = aim_callhandler(command->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_ERROR);
-         if (userfunc)
-           return userfunc(sess, command, errorurl, errorcode);
-         return 0;
-       }
-      else if (sess->logininfo.screen_name[0] && 
-              sess->logininfo.cookie[0] && sess->logininfo.BOSIP)
-       {
-         userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHSUCCESS);
-         if (userfunc)
-           return userfunc(sess, command);
-         return 0;
-       }
-      else
-       userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHOTHER);
-    }
+  return ret;
+}
+
+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;
+
+  if ((pos = aimutil_get8(command->data+ 12)) > MAXSNLEN)
+    return 1;
+
+  if(!(sn = (char *)calloc(1, pos+1)))
+    return 1;
+
+  memcpy(sn, command->data+13, pos);
 
+  if ((userfunc = aim_callhandler(command->conn, 0x0001, 0x0010)))
+    ret = userfunc(sess, command, sn);
+  
+  free(sn);
+
+  return ret;
+}
+
+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(command->conn, 0x0001, 0x0013);
   if (userfunc)
-    return userfunc(sess, command);
-  printf("handler not available!\n");
-  return 0;
+    ret =  userfunc(sess, command, id, msg);
+
+  aim_freetlvchain(&tlvlist);
+  free(msg);
+
+  return ret;  
 }
 
-/*
- * TODO: check for and cure any memory leaks here.
- */
-int aim_handleredirect_middle(struct aim_session_t *sess,
+faim_internal int aim_handleredirect_middle(struct aim_session_t *sess,
                              struct command_rx_struct *command, ...)
 {
-  struct aim_tlv_t *tlv = NULL;
-  u_int z = 10;
+  struct aim_tlv_t *tmptlv = NULL;
   int serviceid = 0x00;
-  char *cookie = NULL;
+  unsigned char cookie[AIM_COOKIELEN];
   char *ip = NULL;
   rxcallback_t userfunc = NULL;
+  struct aim_tlvlist_t *tlvlist;
+  int ret = 1;
+  
+  if (!(tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10)))
+    {
+      printf("libfaim: major bug: unable to read tlvchain from redirect\n");
+      return ret;
+    }
+  
+  if (!(tmptlv = aim_gettlv(tlvlist, 0x000d, 1))) 
+    {
+      printf("libfaim: major bug: no service ID in tlvchain from redirect\n");
+      aim_freetlvchain(&tlvlist);
+      return ret;
+    }
+  serviceid = aimutil_get16(tmptlv->value);
 
-  while (z < command->commandlen)
+  if (!(ip = aim_gettlv_str(tlvlist, 0x0005, 1))) 
     {
-      tlv = aim_grabtlvstr(&(command->data[z]));
-      switch(tlv->type)
-       {
-       case 0x000d:  /* service id */
-         aim_freetlv(&tlv);
-         /* regrab as an int */
-         tlv = aim_grabtlv(&(command->data[z]));
-         serviceid = aimutil_get16(tlv->value);
-         z += 2 + 2 + tlv->length;
-         aim_freetlv(&tlv);
-         break;
-       case 0x0005:  /* service server IP */
-         ip = tlv->value;
-         z += 2 + 2 + tlv->length;
-         free(tlv);
-         tlv = NULL;
-         break;
-       case 0x0006: /* auth cookie */
-         cookie = tlv->value;
-         z += 2 + 2 + tlv->length;
-         free(tlv);
-         tlv = NULL;
-         break;
-       default:
-         /* dunno */
-         z += 2 + 2 + tlv->length;
-         aim_freetlv(&tlv);
-       }
+      printf("libfaim: major bug: no IP in tlvchain from redirect (service 0x%02x)\n", serviceid);
+      free(ip);
+      aim_freetlvchain(&tlvlist);
+      return ret;
     }
-  userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
-  if (userfunc)
-    return userfunc(sess, command, serviceid, ip, cookie);
-  return 0;
+  
+  if (!(tmptlv = aim_gettlv(tlvlist, 0x0006, 1)))
+    {
+      printf("libfaim: major bug: no cookie in tlvchain from redirect (service 0x%02x)\n", serviceid);
+      free(ip);
+      aim_freetlvchain(&tlvlist);
+      return ret;
+    }
+  memcpy(cookie, tmptlv->value, AIM_COOKIELEN);
+
+  if (serviceid == AIM_CONN_TYPE_CHAT)
+    {
+      /*
+       * Chat hack.
+       *
+       */
+      userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
+      if (userfunc)
+       ret =  userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin);
+      free(sess->pendingjoin);
+      sess->pendingjoin = NULL;
+    }
+  else
+    {
+      userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
+      if (userfunc)
+       ret =  userfunc(sess, command, serviceid, ip, cookie);
+    }
+
+  free(ip);
+  aim_freetlvchain(&tlvlist);
+
+  return ret;
 }
 
-int aim_parse_unknown(struct aim_session_t *sess,
-                     struct command_rx_struct *command, ...)
+faim_internal int aim_parse_unknown(struct aim_session_t *sess,
+                                         struct command_rx_struct *command, ...)
 {
   u_int i = 0;
 
-  printf("\nRecieved unknown packet:");
+  faimdprintf(1, "\nRecieved unknown packet:");
 
   for (i = 0; i < command->commandlen; i++)
     {
       if ((i % 8) == 0)
-       printf("\n\t");
+       faimdprintf(1, "\n\t");
 
-      printf("0x%2x ", command->data[i]);
+      faimdprintf(1, "0x%2x ", command->data[i]);
     }
   
-  printf("\n\n");
+  faimdprintf(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;
+  struct aim_tlv_t *tmptlv;
+  rxcallback_t userfunc = NULL;
+  int ret = 1;
+
+  tlvlist = aim_readtlvchain(command->data, command->commandlen);
+
+  if ((tmptlv = aim_gettlv(tlvlist, 0x0009, 1)))
+    code = aimutil_get16(tmptlv->value);
+
+  if ((tmptlv = aim_gettlv(tlvlist, 0x000b, 1)))
+    msg = aim_gettlv_str(tlvlist, 0x000b, 1);
+
+  userfunc = aim_callhandler(command->conn, 
+                            AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR);
+  if (userfunc)
+    ret =  userfunc(sess, command, code, msg);
+
+  aim_freetlvchain(&tlvlist);
+  free(msg);
+
+  return ret;
+}
+
 /*
  * aim_parse_generalerrs()
  *
  * Middle handler for 0x0001 snac of each family.
  *
  */
-int aim_parse_generalerrs(struct aim_session_t *sess,
-                         struct command_rx_struct *command, ...)
+faim_internal int aim_parse_generalerrs(struct aim_session_t *sess,
+                                       struct command_rx_struct *command, ...)
 {
   u_short family;
   u_short subtype;
This page took 0.17364 seconds and 4 git commands to generate.