diff libfaim/aim_rxhandlers.c @ 2:68b230f8da5f

[gaim-migrate @ 11] A few more commits :) committer: Tailor Script <tailor@pidgin.im>
author Rob Flynn <gaim@robflynn.com>
date Thu, 23 Mar 2000 03:16:06 +0000
parents
children 6ced2f1c8b24
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libfaim/aim_rxhandlers.c	Thu Mar 23 03:16:06 2000 +0000
@@ -0,0 +1,485 @@
+
+/*
+  aim_rxhandlers.c
+
+  This file contains most all of the incoming packet handlers, along
+  with aim_rxdispatch(), the Rx dispatcher.  Queue/list management is
+  actually done in aim_rxqueue.c.
+  
+ */
+
+
+#include "aim.h" /* for most everything */
+
+int bleck(struct command_rx_struct *param, ...)
+{
+  return 1;
+}
+
+/*
+ * The callbacks.  Used to pass data up from the wire into the client.
+ *
+ * TODO: MASSIVE OVERHAUL.  This method of doing it (array of function 
+ *       pointers) is ugly.  Overhaul may mean including chained callbacks
+ *       for having client features such as run-time loadable modules.
+ *
+ */
+rxcallback_t aim_callbacks[] = {
+  bleck, /* incoming IM */
+  bleck, /* oncoming buddy */
+  bleck, /* offgoing buddy */
+  bleck, /* messaging error */
+  bleck, /* server missed call */
+  bleck, /* login phase 4 packet C command 1*/
+  bleck, /* login phase 4 packet C command 2 */
+  bleck, /* login phase 2, first resp */
+  bleck, /* login phase 2, second resp -- **REQUIRED** */
+  bleck, /* login phase 3 packet B */
+  bleck, /* login phase 3D packet A */
+  bleck, /* login phase 3D packet B */
+  bleck, /* login phase 3D packet C */
+  bleck, /* login phase 3D packet D */
+  bleck, /* login phase 3D packet E */
+  bleck, /* redirect -- **REQUIRED** */
+  bleck, /* server rate change */
+  bleck, /* user location error */
+  aim_parse_unknown, /* completely unknown command */
+  bleck, /* User Info Response */
+  bleck, /* User Search by Address response */
+  bleck, /* User Search by Name response */
+  bleck, /* user search fail */
+  bleck, /* auth error */
+  bleck, /* auth success */
+  bleck, /* auth server ready */
+  bleck, /* auth other */
+  bleck, /* info change reply */
+  bleck, /* ChatNAV: server ready */
+  0x00
+};
+
+
+int aim_register_callbacks(rxcallback_t *newcallbacks)
+{
+  int i = 0;
+  
+  for (i = 0; aim_callbacks[i] != 0x00; i++)
+    {
+      if ( (newcallbacks[i] != NULL) &&
+	   (newcallbacks[i] != 0x00) )
+	{
+#if debug > 3
+	  printf("aim_register_callbacks: changed handler %d\n", i);
+#endif
+	  aim_callbacks[i] = newcallbacks[i];
+	}
+    }
+  
+  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.
+  
+ */
+int aim_rxdispatch(void)
+{
+  int i = 0;
+  struct command_rx_struct *workingPtr = NULL;
+  
+  if (aim_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 = aim_queue_incoming;
+      for (i = 0; workingPtr != NULL; i++)
+	{
+	  switch(workingPtr->conn->type)
+	    {
+	    case AIM_CONN_TYPE_AUTH:
+	      if ( (workingPtr->data[0] == 0x00) && 
+		   (workingPtr->data[1] == 0x00) &&
+		   (workingPtr->data[2] == 0x00) &&
+		   (workingPtr->data[3] == 0x01) )
+		{
+#if debug > 0
+		  fprintf(stderr, "got connection ack on auth line\n");
+#endif
+		  workingPtr->handled = 1;
+		}
+	      else
+		{
+		  /* any user callbacks will be called from here */
+		  workingPtr->handled = aim_authparse(workingPtr);
+		}
+	      break;
+	    case AIM_CONN_TYPE_BOS:
+	      {
+		u_short family;
+		u_short subtype;
+		family = (workingPtr->data[0] << 8) + workingPtr->data[1];
+		subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
+		switch (family)
+		  {
+		  case 0x0000: /* not really a family, but it works */
+		    if (subtype == 0x0001)
+		      workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P2_1])(workingPtr);
+		    else
+		      workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
+		    break;
+		  case 0x0001: /* Family: General */
+		    switch (subtype)
+		      {
+		      case 0x0001:
+			workingPtr->handled = aim_parse_generalerrs(workingPtr);
+			break;
+		      case 0x0003:
+			workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P2_2])(workingPtr);
+			break;
+		      case 0x0005:
+			workingPtr->handled = aim_handleredirect_middle(workingPtr);
+			break;
+		      case 0x0007:
+			workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3_B])(workingPtr);
+			break;
+		      case 0x000a:
+			workingPtr->handled = (aim_callbacks[AIM_CB_RATECHANGE])(workingPtr);
+			break;
+		      case 0x000f:
+			workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_A])(workingPtr);
+			break;
+		      case 0x0013:
+			workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P4_C2])(workingPtr);
+			break;
+		      default:
+			workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
+		      }
+		    break;
+		  case 0x0002: /* Family: Location */
+		    switch (subtype)
+		      {
+		      case 0x0001:
+			workingPtr->handled = (aim_callbacks[AIM_CB_MISSED_IM])(workingPtr);
+			break;
+		      case 0x0003:
+			workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_D])(workingPtr);
+			break;
+		      case 0x0006:
+			workingPtr->handled = aim_parse_userinfo_middle(workingPtr);
+			break;
+		      default:
+			workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
+		      }
+		    break;
+		  case 0x0003: /* Family: Buddy List */
+		    switch (subtype)
+		      {
+		      case 0x0001:
+			workingPtr->handled = aim_parse_generalerrs(workingPtr);
+			break;
+		      case 0x0003:
+			workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_C])(workingPtr);
+			break;
+		      case 0x000b:
+			workingPtr->handled = (aim_callbacks[AIM_CB_ONCOMING_BUDDY])(workingPtr);
+			break;
+		      case 0x000c:
+			workingPtr->handled = (aim_callbacks[AIM_CB_OFFGOING_BUDDY])(workingPtr);
+			break;
+		      default:
+			workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
+		      }
+		    break;
+		  case 0x0004: /* Family: Messeging */
+		    switch (subtype)
+		      {
+		      case 0x0001:
+			workingPtr->handled = (aim_callbacks[AIM_CB_USERERROR])(workingPtr);
+			break;
+		      case 0x0005:
+			workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_E])(workingPtr);
+			break;
+		      case 0x0007:
+			workingPtr->handled = aim_parse_incoming_im_middle(workingPtr);
+			break;
+		      case 0x000a:
+			workingPtr->handled = (aim_callbacks[AIM_CB_MISSED_CALL])(workingPtr);
+			break;
+		      default:
+			workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
+		      }
+		    break;
+		  case 0x0009:
+		    if (subtype == 0x0001)
+		      workingPtr->handled = aim_parse_generalerrs(workingPtr);
+		    else if (subtype == 0x0003)
+		      workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_B])(workingPtr);
+		    else
+		      workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
+		    break;
+		  case 0x000a:  /* Family: User lookup */
+		    switch (subtype)
+		      {
+		      case 0x0001:
+			workingPtr->handled = (aim_callbacks[AIM_CB_SEARCH_FAIL])(workingPtr);
+			break;
+		      case 0x0003:
+			workingPtr->handled = (aim_callbacks[AIM_CB_SEARCH_ADDRESS])(workingPtr);
+			break;
+		      default:
+			workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
+		      }
+		    break;
+		  case 0x000b:
+		    if (subtype == 0x0001)
+		      workingPtr->handled = aim_parse_generalerrs(workingPtr);
+		    else if (subtype == 0x0002)
+		      workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P4_C1])(workingPtr);
+		    else
+		      workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
+		    break;
+		  default:
+		    workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
+		    break;
+		  }
+	      }
+	      break;
+	    case AIM_CONN_TYPE_CHATNAV:
+	      if ( (workingPtr->data[0] == 0x00) &&
+		   (workingPtr->data[1] == 0x02) &&
+		   (workingPtr->data[2] == 0x00) &&
+		   (workingPtr->data[3] == 0x06) )
+		{
+		  workingPtr->handled = 1;
+		  aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
+		}
+	      else
+		workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
+	      break;
+	    case AIM_CONN_TYPE_CHAT:
+	      fprintf(stderr, "\nAHH! Dont know what to do with CHAT stuff yet!\n");
+	      workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
+	      break;
+	    default:
+	      fprintf(stderr, "\nAHHHHH! UNKNOWN CONNECTION TYPE!\n\n");
+	      workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
+	      break;
+	    }
+	      /* move to next command */
+	  workingPtr = workingPtr->next;
+	}
+    }
+
+  aim_queue_incoming = aim_purge_rxqueue(aim_queue_incoming);
+  
+  return 0;
+}
+
+/*
+ * TODO: check and cure memory leakage in this function.
+ */
+int aim_authparse(struct command_rx_struct *command)
+{
+  int iserror = 0;
+  struct aim_tlv_t *tlv = NULL;
+  char *errorurl = NULL;
+  short errorcode;
+  int z = 0;
+
+  if ( (command->data[0] == 0x00) &&
+       (command->data[1] == 0x01) &&
+       (command->data[2] == 0x00) &&
+       (command->data[3] == 0x03) )
+    {
+      /* "server ready"  -- can be ignored */
+      return (aim_callbacks[AIM_CB_AUTH_SVRREADY])(command);
+    }
+  else if ( (command->data[0] == 0x00) &&
+	    (command->data[1] == 0x07) &&
+	    (command->data[2] == 0x00) &&
+	    (command->data[3] == 0x05) )
+    {
+      /* "information change reply" */
+      return (aim_callbacks[AIM_CB_AUTH_INFOCHNG_REPLY])(command);
+    }
+  else
+    {
+      /* anything else -- usually used for login; just parse as pure TLVs */
+
+
+      /* 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 */
+	      aim_logininfo.screen_name = tlv->value;
+	      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 */
+	      aim_logininfo.BOSIP = tlv->value;
+	      z += 2 + 2 + tlv->length;
+	      free(tlv);
+	      tlv = NULL;
+	      break;
+	    case 0x0006: /* auth cookie */
+	      aim_logininfo.cookie = tlv->value;
+	      z += 2 + 2 + tlv->length;
+	      free(tlv);
+	      tlv=NULL;
+	      break;
+	    case 0x0011: /* email addy */
+	      aim_logininfo.email = tlv->value;
+	      z += 2 + 2 + tlv->length;
+	      free(tlv);
+	      tlv = NULL;
+	      break;
+	    case 0x0013: /* registration status */
+	      aim_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 (iserror && 
+	  errorurl && 
+	  errorcode)
+	return (aim_callbacks[AIM_CB_AUTH_ERROR])(command, &aim_logininfo, errorurl, errorcode);
+      else if (aim_logininfo.screen_name && 
+	       aim_logininfo.cookie && aim_logininfo.BOSIP)
+	return (aim_callbacks[AIM_CB_AUTH_SUCCESS])(command, &aim_logininfo);
+      else
+	return (aim_callbacks[AIM_CB_AUTH_OTHER])(command);
+    }
+}
+
+/*
+ * TODO: check for and cure any memory leaks here.
+ */
+int aim_handleredirect_middle(struct command_rx_struct *command, ...)
+{
+  struct aim_tlv_t *tlv = NULL;
+  int z = 10;
+  int serviceid;
+  char *cookie;
+  char *ip;
+
+  while (z < command->commandlen)
+    {
+      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 = (tlv->value[0] << 8) + tlv->value[1]; /* hehe */
+	  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);
+	}
+    }
+  return (aim_callbacks[AIM_CB_LOGIN_P3D_F])(command, serviceid, ip, cookie);
+}
+
+int aim_parse_unknown(struct command_rx_struct *command, ...)
+{
+  int i = 0;
+
+  printf("\nRecieved unknown packet:");
+
+  for (i = 0; i < command->commandlen; i++)
+    {
+      if ((i % 8) == 0)
+	printf("\n\t");
+
+      printf("0x%2x ", command->data[i]);
+    }
+  
+  printf("\n\n");
+
+  return 1;
+}
+
+
+/*
+ * aim_parse_generalerrs()
+ *
+ * Middle handler for 0x0001 snac of each family.
+ *
+ */
+int aim_parse_generalerrs(struct command_rx_struct *command, ...)
+{
+  u_short family;
+  u_short subtype;
+  family = (command->data[0] << 8) + command->data[1];
+  subtype = (command->data[2] << 8) + command->data[3];
+  
+  switch(family)
+    {
+    default:
+      /* Unknown family */
+      return (aim_callbacks[AIM_CB_UNKNOWN])(command);
+    }
+
+  return 1;
+}
+
+
+