changeset 1245:2ac6ccb94229

[gaim-migrate @ 1255] libfaim stuff committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Tue, 12 Dec 2000 23:58:58 +0000
parents eaa0e2f5ace4
children 42ca87108cd1
files libfaim/CHANGES libfaim/aim_ft.c libfaim/aim_login.c libfaim/aim_tlv.c libfaim/faim/aim.h src/oscar.c
diffstat 6 files changed, 317 insertions(+), 191 deletions(-) [+]
line wrap: on
line diff
--- a/libfaim/CHANGES	Tue Dec 12 23:09:07 2000 +0000
+++ b/libfaim/CHANGES	Tue Dec 12 23:58:58 2000 +0000
@@ -1,6 +1,17 @@
 
 No release numbers
 ------------------
+ - Tue Dec 12 23:02:41 UTC 2000
+  - Got pissed off at sess->logininfo.  Got rid of it.
+    - Now pass all that stuff in as varargs, like it should be.
+    - *** Look at the changes to faimtest. You'll also need to
+          change anything in your code that references sess->logininfo
+          to reference sess->sn instead.  The rest of the other info
+          is now unavailable (it was before, too, it just didnt look like it).
+  - A few other minor cleanups.
+  - Added aim_gettlv8/16/32, aim_puttlv_8, and aim_addtlvtochain_noval.
+  - Added that short 0x004a TLV to the auth request, like WinAIM 4.3.
+
  - Mon Dec  4 23:46:35 UTC 2000
   - Add exchange to the create response callback (doh!)
 
--- a/libfaim/aim_ft.c	Tue Dec 12 23:09:07 2000 +0000
+++ b/libfaim/aim_ft.c	Tue Dec 12 23:58:58 2000 +0000
@@ -26,7 +26,7 @@
   int acceptfd = 0;
   rxcallback_t userfunc;
   struct sockaddr cliaddr;
-  unsigned int clilen = sizeof(cliaddr);
+  socklen_t clilen = sizeof(cliaddr);
   int ret = 0;
 
   /*
@@ -151,7 +151,7 @@
   i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x0000);
   i += aimutil_put16(newpacket2->hdr.oft.hdr2+i, 0x0000);
 
-  i += aimutil_putstr(newpacket2->hdr.oft.hdr2+i, sess->logininfo.screen_name, strlen(sess->logininfo.screen_name));
+  i += aimutil_putstr(newpacket2->hdr.oft.hdr2+i, sess->sn, strlen(sess->sn));
   
   i = 52; /* 0x34 */
   i += aimutil_put8(newpacket2->hdr.oft.hdr2+i, 0x00); /* 53 */
@@ -205,7 +205,7 @@
   i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
   i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
 
-  i += aimutil_putstr(newpacket->hdr.oft.hdr2+i, sess->logininfo.screen_name, strlen(sess->logininfo.screen_name));
+  i += aimutil_putstr(newpacket->hdr.oft.hdr2+i, sess->sn, strlen(sess->sn));
   
   i = 52; /* 0x34 */
   i += aimutil_put8(newpacket->hdr.oft.hdr2+i, 0x00); /* 53 */
@@ -1572,6 +1572,86 @@
 }
 
 /*
+ * int aim_getfile_send_chunk(struct aim_conn_t *conn, FILE *tosend, struct aim_fileheader_t *fh, int pos, int bufsize)
+ * conn is the OFT connection to shove the data down,
+ * tosend is the FILE * for the file to send
+ * fh is the filled-in fh value
+ * pos is the position to start at (at beginning should be 0, after 5
+ *  bytes are sent should be 5); -1 for "don't seek"
+ * bufsize is the size of the chunk to send
+ *
+ * returns -1 on error, new pos on success.
+ *
+ * 
+ * Notes on usage: 
+ * You don't really have to keep track of pos if you don't want
+ *  to. just always call with -1 for pos, and it'll use the one
+ *  contained within the FILE *.
+ *
+ * if (pos + chunksize > fh->size), we only send as much data as we
+ *  can get (ie: up to fh->size.  
+ */
+
+faim_export int aim_getfile_send_chunk(struct aim_conn_t *conn, FILE *tosend, struct aim_fileheader_t *fh, int pos, int bufsize)
+{
+  int bufpos; 
+  char *buf;
+
+  /* sanity checks */
+  if(conn->type != AIM_CONN_TYPE_RENDEZVOUS || conn->type != AIM_CONN_SUBTYPE_OFT_GETFILE) {
+    faimdprintf(1, "faim: getfile_send_chunk: conn->type(0x%04x) != RENDEZVOUS or conn->subtype(0x%04x) != GETFILE\n", conn->type, conn->subtype);
+    return -1;
+  }
+  
+  if(!tosend) {
+    faimdprintf(1, "faim: getfile_send_chunk: file pointer isn't valid\n");
+    return -1;
+  }
+
+  if(!fh) {
+    faimdprintf(1, "faim: getfile_send_chunk: fh isn't valid\n");
+    return -1;
+  }
+
+  /* real code */
+
+  if(!(buf = (char *)calloc(1, bufsize))) {
+    perror("faim: getfile_send_chunk: calloc:");
+    faimdprintf(2, "faim: getfile_send_chunk calloc error\n");
+    return -1;
+  }
+  
+  if(pos != -1) {
+    if( fseek(tosend, pos, SEEK_SET) == -1) {
+      perror("faim: getfile_send_chunk:  fseek:");
+      faimdprintf(2, "faim: getfile_send_chunk fseek error\n");
+    }  
+  }
+
+  faimdprintf(2, "faim: getfile_send_chunk: using %i byte blocks\n", bufsize);
+
+  for(bufpos = 0; pos < fh->size; bufpos++, pos++) {
+    if( (buf[bufpos] = fgetc(tosend)) == EOF) {
+      if(pos != fh->size) {
+	faimdprintf(1, "faim: getfile_send_chunk: hrm... apparent early EOF at pos 0x%x of 0x%x\n", pos, fh->size);
+	free(buf);   
+	return -1;
+      }
+    }      
+  }
+
+  if( write(conn->fd, buf, bufpos+1) != (bufpos+1)) {
+    faimdprintf(1, "faim: getfile_send_chunk cleanup: whoopsy, didn't write it all...\n");
+    free(buf);   
+    return -1;
+  }
+
+  free(buf);   
+  
+  return (pos + bufpos);
+}
+
+/*
  * aim_tx_destroy:
  * free's tx_command_t's. if command is locked, doesn't free.
  * returns -1 on error (locked struct); 0 on success.
@@ -1802,92 +1882,3 @@
 }
 
 #endif
-
-/*
- * int aim_getfile_send_chunk(struct aim_conn_t *conn, FILE *tosend, struct aim_fileheader_t *fh, int pos, int bufsize)
- * conn is the OFT connection to shove the data down,
- * tosend is the FILE * for the file to send
- * fh is the filled-in fh value
- * pos is the position to start at (at beginning should be 0, after 5
- *  bytes are sent should be 5); -1 for "don't seek"
- * bufsize is the size of the chunk to send
- *
- * returns -1 on error, new pos on success. 0 on EOF
- *
- * 
- * Notes on usage: 
- * You don't really have to keep track of pos if you don't want
- *  to. just always call with -1 for pos, and it'll use the one
- *  contained within the FILE *.
- *
- * if (pos + chunksize > fh->size), we only send as much data as we
- *  can get (ie: up to fh->size.  
- */
-
-faim_export int aim_getfile_send_chunk(struct aim_conn_t *conn, FILE *tosend, struct aim_fileheader_t *fh, int pos, int bufsize)
-{
-  int bufpos; 
-  int curpos;
-  char *buf;
-
-  /* sanity checks */
-  if(conn->type != AIM_CONN_TYPE_RENDEZVOUS || conn->subtype != AIM_CONN_SUBTYPE_OFT_GETFILE) {
-    faimdprintf(1, "faim: getfile_send_chunk: conn->type(0x%04x) != RENDEZVOUS or conn->subtype(0x%04x) != GETFILE\n", conn->type, conn->subtype);
-    return -1;
-  }
-  
-  if(!tosend) {
-    faimdprintf(1, "faim: getfile_send_chunk: file pointer isn't valid\n");
-    return -1;
-  }
-
-  if(!fh) {
-    faimdprintf(1, "faim: getfile_send_chunk: fh isn't valid\n");
-    return -1;
-  }
-
-  /* real code */
-
-  if(!(buf = (char *)calloc(1, bufsize))) {
-    perror("faim: getfile_send_chunk: calloc:");
-    faimdprintf(2, "faim: getfile_send_chunk calloc error\n");
-    return -1;
-  }
-  
-  if(pos != -1) {
-    if( fseek(tosend, pos, SEEK_SET) == -1) {
-      perror("faim: getfile_send_chunk:  fseek:");
-      faimdprintf(2, "faim: getfile_send_chunk fseek error\n");
-    }  
-    curpos = pos;
-  } else 
-    pos = ftell(tosend);
-	
-
-  faimdprintf(2, "faim: getfile_send_chunk: using %i byte blocks\n", bufsize);
-
-  for(bufpos = 0; (bufpos < bufsize) && (pos < fh->size); bufpos++, pos++) {
-    if( (buf[bufpos] = fgetc(tosend)) == EOF) {
-#if 0 /* fuck checking */
-      if(pos != fh->size) {
-	fprintf(stderr, "faim: getfile_send_chunk: hrm... apparent early EOF at pos 0x%x of 0x%x\n", pos, fh->size);
-	perror("getfile_send_chunk: fgetc: ");
-	free(buf);   
-	return -1;
-      }
-#endif
-      return 0;
-    }      
-  }
-
-  if( write(conn->fd, buf, bufpos+1) != (bufpos+1)) {
-    faimdprintf(1, "faim: getfile_send_chunk cleanup: whoopsy, didn't write it all...\n");
-    perror("getfile_send_chunk: write: ");
-    free(buf);   
-    return -1;
-  }
-
-  free(buf);   
-  
-  return (pos+1);
-}
--- a/libfaim/aim_login.c	Tue Dec 12 23:09:07 2000 +0000
+++ b/libfaim/aim_login.c	Tue Dec 12 23:58:58 2000 +0000
@@ -132,6 +132,17 @@
  * encode_password().  See that function for their
  * stupid method of doing it.
  *
+ * Latest WinAIM:
+ *   clientstring = "AOL Instant Messenger (SM), version 4.3.2188/WIN32"
+ *   major2 = 0x0109
+ *   major = 0x0400
+ *   minor = 0x0003
+ *   minor2 = 0x0000
+ *   build = 0x088c
+ *   unknown = 0x00000086
+ *   lang = "en"
+ *   country = "us"
+ *   unknown4a = 0x01
  */
 faim_export int aim_send_login (struct aim_session_t *sess,
 				struct aim_conn_t *conn, 
@@ -188,7 +199,9 @@
   
     curbyte += aim_puttlv_32(newpacket->data+curbyte, 0x0014, clientinfo->unknown);
     curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0009, 0x0015);
+    curbyte += aim_puttlv_8(newpacket->data+curbyte, 0x004a, 0x01);
   } else {
+    /* Use very specific version numbers, to further indicate the hack. */
     curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0016, 0x010a);
     curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0017, 0x0004);
     curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0018, 0x003c);
@@ -272,7 +285,7 @@
  * It can be either an error or a success, depending on the
  * precense of certain TLVs.  
  *
- * The client should check the value of logininfo->errorcode. If
+ * The client should check the value passed as errorcode. If
  * its nonzero, there was an error.
  *
  */
@@ -281,10 +294,10 @@
 {
   struct aim_tlvlist_t *tlvlist;
   int ret = 1;
-  char *sn;
   rxcallback_t userfunc = NULL;
-
-  memset(&sess->logininfo, 0x00, sizeof(sess->logininfo));
+  char *sn = NULL, *bosip = NULL, *errurl = NULL, *email = NULL;
+  unsigned char *cookie = NULL;
+  int errorcode = 0, regstatus = 0;
 
   /*
    * Read block of TLVs.  All further data is derived
@@ -301,74 +314,69 @@
   /*
    * No matter what, we should have a screen name.
    */
-  sn = aim_gettlv_str(tlvlist, 0x0001, 1);
-  strncpy(sess->logininfo.screen_name, sn, strlen(sn));
-  free(sn);
+  memset(sess->sn, 0, sizeof(sess->sn));
+  if (aim_gettlv(tlvlist, 0x0001, 1)) {
+    sn = aim_gettlv_str(tlvlist, 0x0001, 1);
+    strncpy(sess->sn, sn, sizeof(sess->sn));
+  }
 
   /*
    * Check for an error code.  If so, we should also
    * have an error url.
    */
-  if (aim_gettlv(tlvlist, 0x0008, 1)) {
-    struct aim_tlv_t *errtlv;
-    errtlv = aim_gettlv(tlvlist, 0x0008, 1);
-    sess->logininfo.errorcode = aimutil_get16(errtlv->value);
-    sess->logininfo.errorurl = aim_gettlv_str(tlvlist, 0x0004, 1);
-  }
-  /* 
-   * If we have both an IP number (0x0005) and a cookie (0x0006),
-   * then the login was successful.
+  if (aim_gettlv(tlvlist, 0x0008, 1)) 
+    errorcode = aim_gettlv16(tlvlist, 0x0008, 1);
+  if (aim_gettlv(tlvlist, 0x0004, 1))
+    errurl = aim_gettlv_str(tlvlist, 0x0004, 1);
+
+  /*
+   * BOS server address.
    */
-  else if (aim_gettlv(tlvlist, 0x0005, 1) && aim_gettlv(tlvlist, 0x0006, 1) 
-	   /*aim_gettlv(tlvlist, 0x0006, 1)->length*/) {
+  if (aim_gettlv(tlvlist, 0x0005, 1))
+    bosip = aim_gettlv_str(tlvlist, 0x0005, 1);
+
+  /*
+   * Authorization cookie.
+   */
+  if (aim_gettlv(tlvlist, 0x0006, 1)) {
     struct aim_tlv_t *tmptlv;
 
-    /*
-     * IP address of BOS server.
-     */
-    sess->logininfo.BOSIP = aim_gettlv_str(tlvlist, 0x0005, 1);
-    
-    /*
-     * Authorization Cookie
-     */
     tmptlv = aim_gettlv(tlvlist, 0x0006, 1);
-    memcpy(sess->logininfo.cookie, tmptlv->value, AIM_COOKIELEN);
-    
-    /*
-     * The email address attached to this account
-     *   Not available for ICQ logins.
-     */
-    if (aim_gettlv(tlvlist, 0x0011, 1))
-      sess->logininfo.email = aim_gettlv_str(tlvlist, 0x0011, 1);
-    
-    /*
-     * The registration status.  (Not real sure what it means.)
-     *   Not available for ICQ logins.
-     */
-    if ((tmptlv = aim_gettlv(tlvlist, 0x0013, 1)))
-      sess->logininfo.regstatus = aimutil_get16(tmptlv->value);
-      
+
+    if ((cookie = malloc(tmptlv->length)))
+      memcpy(cookie, tmptlv->value, tmptlv->length);
   }
 
-  userfunc = aim_callhandler(command->conn, 0x0017, 0x0003);
+  /*
+   * The email address attached to this account
+   *   Not available for ICQ logins.
+   */
+  if (aim_gettlv(tlvlist, 0x0011, 1))
+    email = aim_gettlv_str(tlvlist, 0x0011, 1);
 
-  if (userfunc)
-    ret = userfunc(sess, command);
+  /*
+   * The registration status.  (Not real sure what it means.)
+   *   Not available for ICQ logins.
+   */
+  if (aim_gettlv(tlvlist, 0x0013, 1))
+    regstatus = aim_gettlv16(tlvlist, 0x0013, 1);
 
-  aim_freetlvchain(&tlvlist);
 
-  if (sess->logininfo.BOSIP) {
-    free(sess->logininfo.BOSIP);
-    sess->logininfo.BOSIP = NULL;
-  }
-  if (sess->logininfo.email) {
-    free(sess->logininfo.email);
-    sess->logininfo.email = NULL;
-  }
-  if (sess->logininfo.errorurl) {
-    free(sess->logininfo.errorurl);
-    sess->logininfo.errorurl = NULL;
-  }
+  if ((userfunc = aim_callhandler(command->conn, 0x0017, 0x0003)))
+    ret = userfunc(sess, command, sn, errorcode, errurl, regstatus, email, bosip, cookie);
+
+
+  if (sn)
+    free(sn);
+  if (bosip)
+    free(bosip);
+  if (errurl)
+    free(errurl);
+  if (email)
+    free(email);
+  if (cookie)
+    free(cookie);
+  aim_freetlvchain(&tlvlist);
 
   return ret;
 }
@@ -409,7 +417,8 @@
  */
 faim_export unsigned long aim_sendauthresp(struct aim_session_t *sess, 
 					   struct aim_conn_t *conn, 
-					   char *sn, char *bosip, 
+					   char *sn, int errorcode,
+					   char *errorurl, char *bosip, 
 					   char *cookie, char *email, 
 					   int regstatus)
 {	
@@ -424,11 +433,11 @@
   if (sn)
     aim_addtlvtochain_str(&tlvlist, 0x0001, sn, strlen(sn));
   else
-    aim_addtlvtochain_str(&tlvlist, 0x0001, sess->logininfo.screen_name, strlen(sess->logininfo.screen_name));
+    aim_addtlvtochain_str(&tlvlist, 0x0001, sess->sn, strlen(sess->sn));
 
-  if (sess->logininfo.errorcode) {
-    aim_addtlvtochain16(&tlvlist, 0x0008, sess->logininfo.errorcode);
-    aim_addtlvtochain_str(&tlvlist, 0x0004, sess->logininfo.errorurl, strlen(sess->logininfo.errorurl));
+  if (errorcode) {
+    aim_addtlvtochain16(&tlvlist, 0x0008, errorcode);
+    aim_addtlvtochain_str(&tlvlist, 0x0004, errorurl, strlen(errorurl));
   } else {
     aim_addtlvtochain_str(&tlvlist, 0x0005, bosip, strlen(bosip));
     aim_addtlvtochain_str(&tlvlist, 0x0006, cookie, AIM_COOKIELEN);
@@ -438,6 +447,7 @@
 
   tx->commandlen = aim_writetlvchain(tx->data, tx->commandlen, &tlvlist);
   tx->lock = 0;
+
   return aim_tx_enqueue(sess, tx);
 }
 
--- a/libfaim/aim_tlv.c	Tue Dec 12 23:09:07 2000 +0000
+++ b/libfaim/aim_tlv.c	Tue Dec 12 23:58:58 2000 +0000
@@ -322,6 +322,41 @@
 }
 
 /**
+ * aim_addtlvtochain_noval - Add a blank TLV to a TLV chain
+ * @list: Destination chain
+ * @type: TLV type to add
+ *
+ * Adds a TLV with a zero length to a TLV chain.
+ *
+ */
+faim_internal int aim_addtlvtochain_noval(struct aim_tlvlist_t **list, unsigned short type)
+{
+  struct aim_tlvlist_t *newtlv;
+  struct aim_tlvlist_t *cur;
+
+  newtlv = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
+  memset(newtlv, 0x00, sizeof(struct aim_tlvlist_t));
+
+  newtlv->tlv = aim_createtlv();	
+  newtlv->tlv->type = type;
+  newtlv->tlv->length = 0;
+  newtlv->tlv->value = NULL;
+
+  newtlv->next = NULL;
+
+  if (*list == NULL) {
+    *list = newtlv;
+  } else if ((*list)->next == NULL) {
+    (*list)->next = newtlv;
+  } else {
+    for(cur = *list; cur->next; cur = cur->next)
+      ;
+    cur->next = newtlv;
+  }
+  return newtlv->tlv->length;
+}
+
+/**
  * aim_writetlvchain - Write a TLV chain into a data buffer.
  * @buf: Destination buffer
  * @buflen: Maximum number of bytes that will be written to buffer
@@ -421,6 +456,63 @@
 }
 
 /**
+ * aim_gettlv8 - Retrieve the Nth TLV in chain as a 8bit integer.
+ * @list: Source TLV chain
+ * @type: TLV type to search for
+ * @nth: Index of TLV to return
+ *
+ * Same as aim_gettlv(), except that the return value is a 
+ * 8bit integer instead of an aim_tlv_t. 
+ *
+ */
+faim_internal unsigned char aim_gettlv8(struct aim_tlvlist_t *list, unsigned short type, int num)
+{
+  struct aim_tlv_t *tlv;
+
+  if (!(tlv = aim_gettlv(list, type, num)) || !tlv->value)
+    return 0; /* erm */
+  return aimutil_get8(tlv->value);
+}
+
+/**
+ * aim_gettlv16 - Retrieve the Nth TLV in chain as a 16bit integer.
+ * @list: Source TLV chain
+ * @type: TLV type to search for
+ * @nth: Index of TLV to return
+ *
+ * Same as aim_gettlv(), except that the return value is a 
+ * 16bit integer instead of an aim_tlv_t. 
+ *
+ */
+faim_internal unsigned short aim_gettlv16(struct aim_tlvlist_t *list, unsigned short type, int num)
+{
+  struct aim_tlv_t *tlv;
+
+  if (!(tlv = aim_gettlv(list, type, num)) || !tlv->value)
+    return 0; /* erm */
+  return aimutil_get16(tlv->value);
+}
+
+/**
+ * aim_gettlv32 - Retrieve the Nth TLV in chain as a 32bit integer.
+ * @list: Source TLV chain
+ * @type: TLV type to search for
+ * @nth: Index of TLV to return
+ *
+ * Same as aim_gettlv(), except that the return value is a 
+ * 32bit integer instead of an aim_tlv_t. 
+ *
+ */
+faim_internal unsigned long aim_gettlv32(struct aim_tlvlist_t *list, unsigned short type, int num)
+{
+  struct aim_tlv_t *tlv;
+
+  if (!(tlv = aim_gettlv(list, type, num)) || !tlv->value)
+    return 0; /* erm */
+  return aimutil_get32(tlv->value);
+}
+
+/**
  * aim_grabtlv - Grab a single TLV from a data buffer
  * @src: Source data buffer (must be at least 4 bytes long)
  *
@@ -550,6 +642,26 @@
 }
 
 /**
+ * aim_puttlv_8 - Write a one-byte TLV.
+ * @buf: Destination buffer
+ * @t: TLV type
+ * @v: Value
+ *
+ * Writes a TLV with a one-byte integer value portion.
+ *
+ */
+faim_export int aim_puttlv_8(unsigned char *buf, unsigned short t, unsigned char  v)
+{
+  int curbyte=0;
+
+  curbyte += aimutil_put16(buf+curbyte, (unsigned short)(t&0xffff));
+  curbyte += aimutil_put16(buf+curbyte, (unsigned short)0x0001);
+  curbyte += aimutil_put8(buf+curbyte, (unsigned char)(v&0xff));
+
+  return curbyte;
+}
+
+/**
  * aim_puttlv_16 - Write a two-byte TLV.
  * @buf: Destination buffer
  * @t: TLV type
--- a/libfaim/faim/aim.h	Tue Dec 12 23:09:07 2000 +0000
+++ b/libfaim/faim/aim.h	Tue Dec 12 23:58:58 2000 +0000
@@ -143,22 +143,6 @@
 #define AIM_MD5_STRING "AOL Instant Messenger (SM)"
 
 /*
- * Login info.  Passes information from the Authorization
- * stage of login to the service (BOS, etc) connection
- * phase.
- *
- */
-struct aim_login_struct {
-  char screen_name[MAXSNLEN+1];
-  char *BOSIP;
-  unsigned char cookie[AIM_COOKIELEN];
-  char *email;
-  u_short regstatus;
-  char *errorurl;
-  u_short errorcode;
-};
-
-/*
  * Client info.  Filled in by the client and passed
  * in to aim_login().  The information ends up
  * getting passed to OSCAR through the initial
@@ -297,21 +281,24 @@
 
   /* ---- Client Accessible ------------------------ */
   /* 
-   * Login information.  See definition above.
+   * Our screen name.
    *
    */
-  struct aim_login_struct logininfo;
+  char sn[MAXSNLEN+1];
   
   /*
    * Pointer to anything the client wants to 
    * explicitly associate with this session.
+   *
+   * This is for use in the callbacks mainly. In any
+   * callback, you can access this with sess->aux_data.
+   *
    */
   void *aux_data;
 
   /* 
    * OFT Data 
    */
-
   struct aim_oft_session_t oft;
 
   /* ---- Internal Use Only ------------------------ */
@@ -419,9 +406,13 @@
 faim_internal struct aim_tlv_t *aim_grabtlvstr(u_char *src);
 faim_internal struct aim_tlv_t *aim_gettlv(struct aim_tlvlist_t *, u_short, int);
 faim_internal char *aim_gettlv_str(struct aim_tlvlist_t *, u_short, int);
+faim_internal unsigned char aim_gettlv8(struct aim_tlvlist_t *list, unsigned short type, int num);
+faim_internal unsigned short aim_gettlv16(struct aim_tlvlist_t *list, unsigned short type, int num);
+faim_internal unsigned long aim_gettlv32(struct aim_tlvlist_t *list, unsigned short type, int num);
 faim_internal int aim_puttlv (u_char *dest, struct aim_tlv_t *newtlv);
 faim_internal struct aim_tlv_t *aim_createtlv(void);
 faim_internal int aim_freetlv(struct aim_tlv_t **oldtlv);
+faim_export int aim_puttlv_8(unsigned char *buf, unsigned short t, unsigned char  v);
 faim_internal int aim_puttlv_16(u_char *, u_short, u_short);
 faim_internal int aim_puttlv_32(u_char *, u_short, u_long);
 faim_internal int aim_puttlv_str(u_char *buf, u_short t, int l, char *v);
@@ -430,6 +421,7 @@
 faim_internal int aim_addtlvtochain32(struct aim_tlvlist_t **list, unsigned short type, unsigned long val);
 faim_internal int aim_addtlvtochain_str(struct aim_tlvlist_t **list, unsigned short type, char *str, int len);
 faim_internal int aim_addtlvtochain_caps(struct aim_tlvlist_t **list, unsigned short type, unsigned short caps);
+faim_internal int aim_addtlvtochain_noval(struct aim_tlvlist_t **list, unsigned short type);
 faim_internal int aim_counttlvchain(struct aim_tlvlist_t **list);
 
 /*
@@ -460,7 +452,7 @@
 faim_export int aim_sendconnack(struct aim_session_t *sess, struct aim_conn_t *conn);
 faim_export int aim_request_login (struct aim_session_t *sess, struct aim_conn_t *conn, char *sn);
 faim_export int aim_send_login (struct aim_session_t *, struct aim_conn_t *, char *, char *, struct client_info_s *, char *key);
-faim_export unsigned long aim_sendauthresp(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn, char *bosip, char *cookie, char *email, int regstatus);
+faim_export unsigned long aim_sendauthresp(struct aim_session_t *sess, struct aim_conn_t *conn, char *sn, int errorcode, char *errorurl, char *bosip, char *cookie, char *email, int regstatus);
 faim_export int aim_gencookie(unsigned char *buf);
 faim_export int aim_sendserverready(struct aim_session_t *sess, struct aim_conn_t *conn);
 faim_internal int aim_authkeyparse(struct aim_session_t *sess, struct command_rx_struct *command);
--- a/src/oscar.c	Tue Dec 12 23:09:07 2000 +0000
+++ b/src/oscar.c	Tue Dec 12 23:58:58 2000 +0000
@@ -453,14 +453,29 @@
 
 int gaim_parse_auth_resp(struct aim_session_t *sess,
 			 struct command_rx_struct *command, ...) {
+	va_list ap;
 	struct aim_conn_t *bosconn = NULL;
+	char *sn = NULL, *bosip = NULL, *errurl = NULL, *email = NULL;
+	unsigned char *cookie = NULL;
+	int errorcode = 0, regstatus = 0;
+
 	struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess);
-	sprintf(debug_buff, "inside auth_resp (Screen name: %s)\n",
-			sess->logininfo.screen_name);
+
+	va_start(ap, command);
+	sn = va_arg(ap, char *);
+	errorcode = va_arg(ap, int);
+	errurl = va_arg(ap, char *);
+	regstatus = va_arg(ap, int);
+	email = va_arg(ap, char *);
+	bosip = va_arg(ap, char *);
+	cookie = va_arg(ap, unsigned char *);
+	va_end(ap);
+
+	sprintf(debug_buff, "inside auth_resp (Screen name: %s)\n", sn);
 	debug_print(debug_buff);
 
-	if (sess->logininfo.errorcode) {
-		switch (sess->logininfo.errorcode) {
+	if (errorcode || !bosip || !cookie) {
+		switch (errorcode) {
 		case 0x18:
 			/* connecting too frequently */
 			hide_login_progress(gc, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer."));
@@ -480,12 +495,8 @@
 			hide_login_progress(gc, _("Authentication Failed"));
 			break;
 		}
-		sprintf(debug_buff, "Login Error Code 0x%04x\n",
-				sess->logininfo.errorcode);
-		debug_print(debug_buff);
-		sprintf(debug_buff, "Error URL: %s\n",
-				sess->logininfo.errorurl);
-		debug_print(debug_buff);
+		debug_printf("Login Error Code 0x%04x\n", errorcode);
+		debug_printf("Error URL: %s\n", errurl);
 #ifdef USE_APPLET
 		set_user_state(offline);
 #endif
@@ -494,18 +505,17 @@
 	}
 
 
-	if (sess->logininfo.email) {
-		sprintf(debug_buff, "Email: %s\n", sess->logininfo.email);
-		debug_print(debug_buff);
+	if (email) {
+		debug_printf("Email: %s\n", email);
 	} else {
-		debug_print("Email is NULL\n");
+		debug_printf("Email is NULL\n");
 	}
 	sprintf(debug_buff, "Closing auth connection...\n");
 	debug_print(debug_buff);
 	gdk_input_remove(gc->inpa);
 	aim_conn_kill(sess, &command->conn);
 
-	bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, sess->logininfo.BOSIP);
+	bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, bosip);
 	if (bosconn == NULL) {
 #ifdef USE_APPLET
 		set_user_state(offline);
@@ -544,7 +554,7 @@
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEFAULT, aim_parse_unknown, 0);
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, gaim_parse_motd, 0);
 
-	aim_auth_sendcookie(sess, bosconn, sess->logininfo.cookie);
+	aim_auth_sendcookie(sess, bosconn, cookie);
 	((struct oscar_data *)gc->proto_data)->conn = bosconn;
 	gc->inpa = gdk_input_add(bosconn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
 			oscar_callback, bosconn);