]> andersk Git - libfaim.git/commitdiff
- The week prior to Fri Jun 16 19:37:09 UTC 2000
authormid <mid>
Fri, 16 Jun 2000 20:47:56 +0000 (20:47 +0000)
committermid <mid>
Fri, 16 Jun 2000 20:47:56 +0000 (20:47 +0000)
   - Rethought the rendezvous stuff.  DEFINIT WORK IN PROGRESS
     - Do not bother trying to use this.  This will probably break
         your clients.  You may or may not want to fix them, since
         I may change it again soon.
     - I REPEAT: This really is a developer-only version.  It barely
         compiles.  I'm just committing it so I don't have so many
         trees floating around.
   - Added stuff to support OFT as well as OSCAR protocols
   - Added aim_send_im_direct() for directim ("IM Image")
   - Added caps getting/putting routines
   - Added more aim_login fixes to avoid more AOL stupidity
     - This is the same as went to libfaim-devel yesterday, so don't upgrade
       just to get these changes.
   - Removed aimicq_encode_password -- now use the same table
       for both ICQ and AIM
   - Added AUTHORS

16 files changed:
AUTHORS [new file with mode: 0644]
CHANGES
aim_auth.c
aim_buddylist.c
aim_chat.c
aim_chatnav.c
aim_im.c
aim_info.c
aim_login.c
aim_misc.c
aim_rxhandlers.c
aim_rxqueue.c
aim_search.c
aim_txqueue.c
faim/aim.h
utils/faimtest/faimtest.c

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..988b852
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,31 @@
+
+Anyone else want to be in here?
+
+---
+
+N: Adam Fritzler
+H: mid
+E: mid@auk.cx
+W: http://www.auk.cx/~mid,http://www.auk.cx/faim
+D: Wrote most of the wap of crap that you see before you.
+
+N: Josh Myer
+E: josh@joshisanerd.com
+D: [I'm sure he did something -mid]
+
+N: Daniel Reed
+H: n, linuxkitty
+E: n@ml.org
+W: http://users.n.ml.org/n/
+D: Fixed aim_snac.c
+
+N: Eric Warmenhoven
+E: warmenhoven@linux.com
+D: Some OFT info, author of the faim interface for gaim
+
+N: Brock Wilcox
+H: awwaiid
+E: awwaiid@auk.cx
+D: Figured out original password roasting
+
+
diff --git a/CHANGES b/CHANGES
index 268afdb969d42432002b35bdcd5f0147bc133357..62ae094605727f8a5256f342ebbfc1fd1a1e165b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,24 @@
 
 No release numbers
 ------------------
+ - The week prior to Fri Jun 16 19:37:09 UTC 2000
+   - Rethought the rendezvous stuff.  DEFINIT WORK IN PROGRESS
+     - Do not bother trying to use this.  This will probably break
+         your clients.  You may or may not want to fix them, since 
+         I may change it again soon.  
+     - I REPEAT: This really is a developer-only version.  It barely
+         compiles.  I'm just committing it so I don't have so many
+         trees floating around.
+   - Added stuff to support OFT as well as OSCAR protocols
+   - Added aim_send_im_direct() for directim ("IM Image")
+   - Added caps getting/putting routines 
+   - Added more aim_login fixes to avoid more AOL stupidity
+     - This is the same as went to libfaim-devel yesterday, so don't upgrade
+       just to get these changes.
+   - Removed aimicq_encode_password -- now use the same table
+       for both ICQ and AIM
+   - Added AUTHORS
+
  - Tue Jun  6 01:36:48 UTC 2000
    - Inverted gethostbyname2() check.  Not sure how that ended up 
        in that state.
index 491e2e08628302c76d503b7f3b9054b3b1b26ddc..64c47ed4c42b6b409723b310c99616ab1d9f2da6 100644 (file)
@@ -15,7 +15,7 @@ int aim_auth_sendcookie(struct aim_session_t *sess,
   struct command_tx_struct *newpacket;
   int curbyte=0;
   
-  if (!(newpacket = aim_tx_new(0x0001, conn, 4+2+2+AIM_COOKIELEN)))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0001, conn, 4+2+2+AIM_COOKIELEN)))
     return -1;
 
   newpacket->lock = 1;
@@ -35,7 +35,7 @@ u_long aim_auth_clientready(struct aim_session_t *sess,
   struct command_tx_struct *newpacket;
   int curbyte = 0;
 
-  if (!(newpacket = aim_tx_new(0x0002, conn, 26)))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 26)))
     return -1;
 
   newpacket->lock = 1;
@@ -75,7 +75,7 @@ u_long aim_auth_changepasswd(struct aim_session_t *sess,
   struct command_tx_struct *newpacket;
   int i;
 
-  if (!(newpacket = aim_tx_new(0x0002, conn, 10+4+strlen(current)+4+strlen(new))))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+4+strlen(current)+4+strlen(new))))
     return -1;
 
   newpacket->lock = 1;
index 04572b3356945c6ef8e9b858a03f7dad7e0741f2..affdb3ca5beb6979e41af9f365345a20492e56f7 100644 (file)
@@ -17,7 +17,7 @@ u_long aim_add_buddy(struct aim_session_t *sess,
    if(!sn)
      return -1;
 
-   if (!(newpacket = aim_tx_new(0x0002, conn, 10+1+strlen(sn))))
+   if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+1+strlen(sn))))
      return -1;
 
    newpacket->lock = 1;
@@ -55,7 +55,7 @@ u_long aim_remove_buddy(struct aim_session_t *sess,
    if(!sn)
      return -1;
 
-   if (!(newpacket = aim_tx_new(0x0002, conn, 10+1+strlen(sn))))
+   if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+1+strlen(sn))))
      return -1;
 
    newpacket->lock = 1;
index 0543ade2b06f0c56359fc020cbb1eccd2f72032b..ab49d1205dc869d25641ad2c5f47bbd411891da9 100644 (file)
@@ -55,7 +55,7 @@ u_long aim_chat_send_im(struct aim_session_t *sess,
   if (!sess || !conn || !msg)
     return 0;
   
-  if (!(newpacket = aim_tx_new(0x0002, conn, 1152)))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152)))
     return -1;
 
   newpacket->lock = 1; /* lock struct */
@@ -130,7 +130,7 @@ u_long aim_chat_join(struct aim_session_t *sess,
   if (!sess || !conn || !roomname)
     return 0;
   
-  if (!(newpacket = aim_tx_new(0x0002, conn, 10+9+strlen(roomname)+2)))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+9+strlen(roomname)+2)))
     return -1;
 
   newpacket->lock = 1;
@@ -513,7 +513,7 @@ u_long aim_chat_clientready(struct aim_session_t *sess,
   struct command_tx_struct *newpacket;
   int i;
 
-  if (!(newpacket = aim_tx_new(0x0002, conn, 0x20)))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 0x20)))
     return -1;
 
   newpacket->lock = 1;
@@ -567,7 +567,7 @@ u_long aim_chat_invite(struct aim_session_t *sess,
   if (!sess || !conn || !sn || !msg || !roomname)
     return 0;
 
-  if (!(newpacket = aim_tx_new(0x0002, conn, 1152+strlen(sn)+strlen(roomname)+strlen(msg))))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152+strlen(sn)+strlen(roomname)+strlen(msg))))
     return -1;
 
   newpacket->lock = 1;
index fd5be6d048b32bcbefb2311e03e62e5836456237..1bc8c33fa2067d693c9c5e6de38e658894fd155e 100644 (file)
@@ -34,7 +34,7 @@ u_long aim_chatnav_clientready(struct aim_session_t *sess,
   struct command_tx_struct *newpacket; 
   int i;
 
-  if (!(newpacket = aim_tx_new(0x0002, conn, 0x20)))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 0x20)))
     return -1;
 
   newpacket->lock = 1;
@@ -283,7 +283,7 @@ u_long aim_chatnav_createroom(struct aim_session_t *sess,
   int i;
   struct aim_snac_t snac;
 
-  if (!(newpacket = aim_tx_new(0x0002, conn, 10+12+strlen("invite")+strlen(name))))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+12+strlen("invite")+strlen(name))))
     return -1;
 
   newpacket->lock = 1;
index 3be7e40b4960e63deb6d1a3506034126b60900f1..219ba1ed5c53e065d519899e43e9d1a5df31be43 100644 (file)
--- a/aim_im.c
+++ b/aim_im.c
@@ -28,7 +28,7 @@ u_long aim_send_im(struct aim_session_t *sess,
   if (strlen(msg) >= MAXMSGLEN)
     return -1;
 
-  if (!(newpacket = aim_tx_new(0x0002, conn, strlen(msg)+256)))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, strlen(msg)+256)))
     return -1;
 
   newpacket->lock = 1; /* lock struct */
@@ -132,6 +132,88 @@ u_long aim_send_im(struct aim_session_t *sess,
   return (sess->snac_nextid++);
 }
 
+struct aim_directim_priv {
+  unsigned char cookie[8];
+  char sn[MAXSNLEN+1];
+};
+
+int aim_send_im_direct(struct aim_session_t *sess, 
+                      struct aim_conn_t *conn,
+                      char *msg)
+{
+  struct command_tx_struct *newpacket;
+  struct aim_directim_priv *priv = NULL;
+  int i;
+
+  if (strlen(msg) >= MAXMSGLEN)
+    return -1;
+
+  if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS) || !conn->priv) {
+    printf("faim: directim: invalid arguments\n");
+    return -1;
+  }
+
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OFT, 0x0001, conn, strlen(msg)))) {
+    printf("faim: directim: tx_new failed\n");
+    return -1;
+  }
+
+  newpacket->lock = 1; /* lock struct */
+
+  priv = (struct aim_directim_priv *)conn->priv;
+
+  newpacket->hdr.oft.hdr2len = 0x44;
+
+  if (!(newpacket->hdr.oft.hdr2 = malloc(newpacket->hdr.oft.hdr2len))) {
+    free(newpacket);
+    return -1;
+  }
+
+  i = 0;
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0006);
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+
+  i += aimutil_putstr(newpacket->hdr.oft.hdr2+i, priv->cookie, 8);
+
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+
+  i += aimutil_put32(newpacket->hdr.oft.hdr2+i, strlen(msg));
+
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+  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 = 52;
+  i += aimutil_put8(newpacket->hdr.oft.hdr2+i, 0x00);
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+  i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+
+  memcpy(newpacket->data, msg, strlen(msg));
+
+  newpacket->lock = 0;
+
+  aim_tx_enqueue(sess, newpacket);
+
+  return 0;
+}
+
 /*
  * It can easily be said that parsing ICBMs is THE single
  * most difficult thing to do in the in AIM protocol.  In
@@ -353,9 +435,8 @@ int aim_parse_incoming_im_middle(struct aim_session_t *sess,
       struct aim_tlv_t *block1;
       struct aim_tlvlist_t *list2;
       struct aim_tlv_t *tmptlv;
-      struct aim_tlv_t *miscinfo;
       unsigned short reqclass = 0;
-      int a;
+      unsigned short status = 0;
       
       /* Class. */
       if ((tmptlv = aim_gettlv(tlvlist, 0x0001, 1)))
@@ -383,32 +464,57 @@ int aim_parse_incoming_im_middle(struct aim_session_t *sess,
        return 1; /* major problem */
       }
 
-      a = 0x1a; /* skip -- not sure what this information is! */
+      /*
+       * First two bytes represent the status of the connection.
+       *
+       * 0 is a request, 2 is an accept
+       */ 
+      status = aimutil_get16(block1->value+0);
+      
+      /*
+       * Next comes the cookie.  Should match the ICBM cookie.
+       */
+      if (memcmp(block1->value+2, cookie, 8) != 0) 
+       printf("faim: rend: warning cookies don't match!\n");
 
       /*
-       * XXX: Ignore if there's no data, only cookie information.
+       * The next 16bytes are a capability block so we can
+       * identify what type of rendezvous this is.
        *
-       * Its probably just an accepted invitation or something.
-       *  
+       * Thanks to Eric Warmenhoven <warmenhoven@linux.com> (of GAIM)
+       * for pointing some of this out to me.  In fact, a lot of 
+       * the client-to-client info comes from the work of the GAIM 
+       * developers. Thanks!
+       *
+       * Read off one capability string and we should have it ID'd.
+       * 
        */
-      if (block1->length <= 0x1a) {
+      reqclass = aim_getcap(block1->value+2+8, 0x10);
+      if (reqclass == 0x0000) {
+       printf("faim: rend: no ID block\n");
        aim_freetlvchain(&tlvlist);
        return 1;
       }
 
-      list2 = aim_readtlvchain(block1->value+a, block1->length-a);
-
-      if (!(miscinfo = aim_gettlv(list2, 0x2711, 1))) {
+      /* 
+       * What follows may be TLVs or nothing, depending on the
+       * purpose of the message.
+       *
+       * Ack packets for instance have nothing more to them.
+       */
+      list2 = aim_readtlvchain(block1->value+2+8+16, block1->length-2-8-16);
+      
+      if (!list2 || ((reqclass != AIM_CAPS_IMIMAGE) && !(aim_gettlv(list2, 0x2711, 1)))) {
        struct aim_msgcookie_t *cook;
 
        if ((cook = aim_uncachecookie(sess, cookie)) == NULL) {
-         printf("faim: no 0x2711 info TLV in rendezvous and its not in cache!\n");
+         printf("faim: non-data rendezvous thats not in cache!\n");
          aim_freetlvchain(&list2);
          aim_freetlvchain(&tlvlist);
          return 1;
        }
 
-       if (cook->type == 1) {
+       if (cook->type == AIM_CAPS_SENDFILE) {
          struct aim_filetransfer_t *ft;
 
          if (cook->data) {
@@ -420,40 +526,43 @@ int aim_parse_incoming_im_middle(struct aim_session_t *sess,
            if ((errortlv = aim_gettlv(list2, 0x000b, 1))) {
              errorcode = aimutil_get16(errortlv->value);
            }
-           printf("faim: transfer from %s (%s) for %s cancelled (error code %d)\n", ft->sender, ft->ip, ft->filename, errorcode);
+           if (errorcode) {
+             printf("faim: transfer from %s (%s) for %s cancelled (error code %d)\n", ft->sender, ft->ip, ft->filename, errorcode);
+           } else if (status == 0x0002) { /* connection accepted */
+             printf("faim: transfer from %s (%s) for %s accepted\n", ft->sender, ft->ip, ft->filename);
+           }
            free(cook->data);
          } else {
            printf("faim: not data attached to file transfer\n");
          }
-
+       } else if (cook->type == AIM_CAPS_VOICE) {
+         printf("faim: voice request cancelled\n");
        } else {
          printf("faim: unknown cookie cache type %d\n", cook->type);
        }
 
        free(cook);
+       if (list2)
+         aim_freetlvchain(&list2);
+       aim_freetlvchain(&tlvlist);
        return 1;
       }
 
-
       /*
-       * Parse the first two bytes of the 0x2711 TLV.  
-       *
-       * This can be interpretted in a couple ways.  
-       *
-       * It could be said that its a service type or some such and
-       * that voice is 0, file transfer is 1, and chat is 4 (and 5).
-       *
-       * Or it could be said that its an exchange value.  Exchanges
-       * four and five are for chat, voice is on exchange zero and
-       * file transfer is done on exchange 1.  
-       *
-       * It should work out the same no how its thought of.
-       *
+       * The rest of the handling depends on what type it is.
        */
-      reqclass = aimutil_get16(miscinfo->value+0);
-   
-      switch (reqclass) {      
-      case AIM_RENDEZVOUS_VOICE: {
+      if (reqclass & AIM_CAPS_BUDDYICON) {
+       printf("faim: rend: buddy icon!\n");
+      } else if (reqclass & AIM_CAPS_VOICE) {
+       struct aim_msgcookie_t cachedcook;
+
+       printf("faim: rend: voice!\n");
+
+       memcpy(cachedcook.cookie, cookie, 8);
+       cachedcook.type = AIM_CAPS_VOICE;
+       cachedcook.data = NULL;
+       if (aim_cachecookie(sess, &cachedcook) != 0)
+         printf("faim: ERROR caching message cookie\n");
 
        /* XXX: implement all this */
 
@@ -468,13 +577,9 @@ int aim_parse_incoming_im_middle(struct aim_session_t *sess,
                       reqclass,
                       &userinfo);
        }
-       break;
-      }
-      case AIM_RENDEZVOUS_FILETRANSFER: {
+      } else if (reqclass & AIM_CAPS_IMIMAGE) {
        char ip[30];
-       char *desc = NULL;
        struct aim_msgcookie_t cachedcook;
-       struct aim_filetransfer_t *ft;
 
        memset(ip, 0, sizeof(ip));
        
@@ -489,51 +594,52 @@ int aim_parse_incoming_im_middle(struct aim_session_t *sess,
                  aimutil_get8(iptlv->value+1),
                  aimutil_get8(iptlv->value+2),
                  aimutil_get8(iptlv->value+3),
-                 aimutil_get16(porttlv->value));
+                 4443 /*aimutil_get16(porttlv->value)*/);
        }
 
-       if (aim_gettlv(list2, 0x000c, 1)) {
-         desc = aim_gettlv_str(list2, 0x000c, 1);
-       }
-
-       printf("faim: rend: file transfer request from %s for %s: %s (%s)\n",
+       printf("faim: rend: directIM request from %s (%s)\n",
               userinfo.sn,
-              miscinfo->value+8,
-              desc, 
               ip);
+
+       {
+         struct aim_conn_t *newconn;
+         
+         newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, ip);
+         if (!newconn || (newconn->fd == -1)) { 
+           printf("could not connect to %s\n", ip);
+           perror("aim_newconn");
+           aim_conn_kill(sess, &newconn);
+         } else {
+           struct aim_directim_priv *priv;
+           priv = (struct aim_directim_priv *)malloc(sizeof(struct aim_directim_priv));
+           memcpy(priv->cookie, cookie, 8);
+           strncpy(priv->sn, userinfo.sn, MAXSNLEN);
+           newconn->priv = priv;
+           printf("faim: connected to peer (fd = %d)\n", newconn->fd);
+         }
+       }
        
+#if 0
        memcpy(cachedcook.cookie, cookie, 8);
-       memcpy(cachedcook.extended, block1->value+10, 16);
        
        ft = malloc(sizeof(struct aim_filetransfer_t));
        strncpy(ft->sender, userinfo.sn, sizeof(ft->sender));
        strncpy(ft->ip, ip, sizeof(ft->ip));
        ft->filename = strdup(miscinfo->value+8);
-       cachedcook.type = 1
+       cachedcook.type = AIM_CAPS_SENDFILE
        cachedcook.data = ft;
 
        if (aim_cachecookie(sess, &cachedcook) != 0)
          printf("faim: ERROR caching message cookie\n");
-       
-       
-       aim_denytransfer(sess, command->conn, ft->sender, cookie, 0);
+#endif 
 
-       free(desc);
-       
-       i = 1;
-       break;
-      }
-      case AIM_RENDEZVOUS_FILETRANSFER_GET: {
-       printf("faim: file get request (unsupported)\n");
-       i = 1;
-       break;
-      }
-      case AIM_RENDEZVOUS_CHAT_EX3:
-      case AIM_RENDEZVOUS_CHAT_EX4:
-      case AIM_RENDEZVOUS_CHAT_EX5: {
+
+      } else if (reqclass & AIM_CAPS_CHAT) {
+       struct aim_tlv_t *miscinfo;
        struct aim_chat_roominfo roominfo;
        char *msg=NULL,*encoding=NULL,*lang=NULL;
 
+       miscinfo = aim_gettlv(list2, 0x2711, 1);
        aim_chat_readroominfo(miscinfo->value, &roominfo);
                  
        if (aim_gettlv(list2, 0x000c, 1))
@@ -563,14 +669,64 @@ int aim_parse_incoming_im_middle(struct aim_session_t *sess,
          free(msg);
          free(encoding);
          free(lang);
-         break;
-      }
-      default: {
-       printf("faim: rendezvous: unknown rend class 0x%04x\n", reqclass);
+      } else if (reqclass & AIM_CAPS_GETFILE) {
+       printf("faim: rend: getfile!\n");
+      } else if (reqclass & AIM_CAPS_SENDFILE) {
+       char ip[30];
+       char *desc = NULL;
+       struct aim_msgcookie_t cachedcook;
+       struct aim_filetransfer_t *ft;
+       struct aim_tlv_t *miscinfo;
+
+       memset(ip, 0, sizeof(ip));
+       
+       miscinfo = aim_gettlv(list2, 0x2711, 1);
+
+       if (aim_gettlv(list2, 0x0003, 1) && aim_gettlv(list2, 0x0003, 1)) {
+         struct aim_tlv_t *iptlv, *porttlv;
+         
+         iptlv = aim_gettlv(list2, 0x0003, 1);
+         porttlv = aim_gettlv(list2, 0x0005, 1);
+
+         snprintf(ip, sizeof(ip)-1, "%d.%d.%d.%d:%d", 
+                 aimutil_get8(iptlv->value+0),
+                 aimutil_get8(iptlv->value+1),
+                 aimutil_get8(iptlv->value+2),
+                 aimutil_get8(iptlv->value+3),
+                 aimutil_get16(porttlv->value));
+       }
+
+       if (aim_gettlv(list2, 0x000c, 1)) {
+         desc = aim_gettlv_str(list2, 0x000c, 1);
+       }
+
+       printf("faim: rend: file transfer request from %s for %s: %s (%s)\n",
+              userinfo.sn,
+              miscinfo->value+8,
+              desc, 
+              ip);
+       
+       memcpy(cachedcook.cookie, cookie, 8);
+       
+       ft = malloc(sizeof(struct aim_filetransfer_t));
+       strncpy(ft->sender, userinfo.sn, sizeof(ft->sender));
+       strncpy(ft->ip, ip, sizeof(ft->ip));
+       ft->filename = strdup(miscinfo->value+8);
+       cachedcook.type = AIM_CAPS_SENDFILE; 
+       cachedcook.data = ft;
+
+       if (aim_cachecookie(sess, &cachedcook) != 0)
+         printf("faim: ERROR caching message cookie\n");
+       
+       
+       aim_accepttransfer(sess, command->conn, ft->sender, cookie, AIM_CAPS_SENDFILE);
+
+       free(desc);
+       
        i = 1;
-       break;
+      } else {
+       printf("faim: rend: unknown rendezvous 0x%04x\n", reqclass);
       }
-      } /* switch */
 
       aim_freetlvchain(&list2);
     }
@@ -584,6 +740,39 @@ int aim_parse_incoming_im_middle(struct aim_session_t *sess,
   return i;
 }
 
+u_long aim_accepttransfer(struct aim_session_t *sess,
+                         struct aim_conn_t *conn, 
+                         char *sender,
+                         char *cookie,
+                         unsigned short rendid)
+{
+  struct command_tx_struct *newpacket;
+  int curbyte, i;
+
+  if(!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+8+2+1+strlen(sender)+4+2+8+16)))
+    return -1;
+
+  newpacket->lock = 1;
+
+  curbyte = aim_putsnac(newpacket->data, 0x0004, 0x0006, 0x0000, sess->snac_nextid);
+  for (i = 0; i < 8; i++)
+    curbyte += aimutil_put8(newpacket->data+curbyte, cookie[i]);
+  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
+  curbyte += aimutil_put8(newpacket->data+curbyte, strlen(sender));
+  curbyte += aimutil_putstr(newpacket->data+curbyte, sender, strlen(sender));
+  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
+  curbyte += aimutil_put16(newpacket->data+curbyte, 0x001a);
+  curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002 /* accept */);
+  for (i = 0; i < 8; i++)
+    curbyte += aimutil_put8(newpacket->data+curbyte, cookie[i]);
+  curbyte += aim_putcap(newpacket->data+curbyte, 0x10, rendid);
+
+  newpacket->lock = 0;
+  aim_tx_enqueue(sess, newpacket);
+
+  return (sess->snac_nextid++);
+}
+
 /*
  * Possible codes:
  *    AIM_TRANSFER_DENY_NOTSUPPORTED -- "client does not support"
@@ -600,7 +789,7 @@ u_long aim_denytransfer(struct aim_session_t *sess,
   struct command_tx_struct *newpacket;
   int curbyte, i;
 
-  if(!(newpacket = aim_tx_new(0x0002, conn, 10+8+2+1+strlen(sender)+6)))
+  if(!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+8+2+1+strlen(sender)+6)))
     return -1;
 
   newpacket->lock = 1;
@@ -632,7 +821,7 @@ u_long aim_seticbmparam(struct aim_session_t *sess,
   struct command_tx_struct *newpacket;
   int curbyte;
 
-  if(!(newpacket = aim_tx_new(0x0002, conn, 10+16)))
+  if(!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+16)))
     return -1;
 
   newpacket->lock = 1;
index 13ac60e0d75ca288ea3f0683e73c1f1d38b8ce52..88f07fce626843887ee6978f32ea09d66d4aad8e 100644 (file)
@@ -25,7 +25,7 @@ u_long aim_getinfo(struct aim_session_t *sess,
   if (!sess || !conn || !sn)
     return 0;
 
-  if (!(newpacket = aim_tx_new(0x0002, conn, 12+1+strlen(sn))))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 12+1+strlen(sn))))
     return -1;
 
   newpacket->lock = 1;
@@ -88,6 +88,66 @@ u_char aim_caps[6][16] = {
    0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}
 };
 
+u_short aim_getcap(unsigned char *capblock, int buflen)
+{
+  u_short ret = 0;
+  int y;
+  int offset = 0;
+
+  while (offset < buflen) {
+    for(y=0; y < (sizeof(aim_caps)/0x10); y++) {
+      if (memcmp(&aim_caps[y], capblock+offset, 0x10) == 0) {
+       switch(y) {
+       case 0: ret |= AIM_CAPS_BUDDYICON; break;
+       case 1: ret |= AIM_CAPS_VOICE; break;
+       case 2: ret |= AIM_CAPS_IMIMAGE; break;
+       case 3: ret |= AIM_CAPS_CHAT; break;
+       case 4: ret |= AIM_CAPS_GETFILE; break;
+       case 5: ret |= AIM_CAPS_SENDFILE; break;
+       default: ret |= 0xff00; break;
+       }
+      }
+    }
+    offset += 0x10;
+  } 
+  return ret;
+}
+
+int aim_putcap(unsigned char *capblock, int buflen, u_short caps)
+{
+  int offset = 0;
+
+  if (!capblock)
+    return -1;
+
+  if ((caps & AIM_CAPS_BUDDYICON) && (offset < buflen)) {
+    memcpy(capblock+offset, aim_caps[0], sizeof(aim_caps[0]));
+    offset += sizeof(aim_caps[1]);
+  }
+  if ((caps & AIM_CAPS_VOICE) && (offset < buflen)) {
+    memcpy(capblock+offset, aim_caps[1], sizeof(aim_caps[1]));
+    offset += sizeof(aim_caps[1]);
+  }
+  if ((caps & AIM_CAPS_IMIMAGE) && (offset < buflen)) {
+    memcpy(capblock+offset, aim_caps[2], sizeof(aim_caps[2]));
+    offset += sizeof(aim_caps[2]);
+  }
+  if ((caps & AIM_CAPS_CHAT) && (offset < buflen)) {
+    memcpy(capblock+offset, aim_caps[3], sizeof(aim_caps[3]));
+    offset += sizeof(aim_caps[3]);
+  }
+  if ((caps & AIM_CAPS_GETFILE) && (offset < buflen)) {
+    memcpy(capblock+offset, aim_caps[4], sizeof(aim_caps[4]));
+    offset += sizeof(aim_caps[4]);
+  }
+  if ((caps & AIM_CAPS_SENDFILE) && (offset < buflen)) {
+    memcpy(capblock+offset, aim_caps[5], sizeof(aim_caps[5]));
+    offset += sizeof(aim_caps[5]);
+  }
+
+  return offset;
+}
+
 /*
  * AIM is fairly regular about providing user info.  This
  * is a generic routine to extract it in its standard form.
@@ -198,32 +258,15 @@ int aim_extractuserinfo(u_char *buf, struct aim_userinfo_s *outinfo)
           * actual decoding.  See comment on aim_bos_setprofile()
           * in aim_misc.c about the capability block, its the same.
           *
-          * Ignore.
-          *
           */
        case 0x000d:
          {
-           int z,y; 
            int len;
            len = aimutil_get16(buf+i+2);
            if (!len)
              break;
-
-           for (z = 0; z < len; z+=0x10) {
-             for(y=0; y < 6; y++) {
-               if (memcmp(&aim_caps[y], buf+i+4+z, 0x10) == 0) {
-                 switch(y) {
-                 case 0: outinfo->capabilities |= AIM_CAPS_BUDDYICON; break;
-                 case 1: outinfo->capabilities |= AIM_CAPS_VOICE; break;
-                 case 2: outinfo->capabilities |= AIM_CAPS_IMIMAGE; break;
-                 case 3: outinfo->capabilities |= AIM_CAPS_CHAT; break;
-                 case 4: outinfo->capabilities |= AIM_CAPS_GETFILE; break;
-                 case 5: outinfo->capabilities |= AIM_CAPS_SENDFILE; break;
-                 default: outinfo->capabilities |= 0xff00; break;
-                 }
-               }
-             }
-           }
+           
+           outinfo->capabilities = aim_getcap(buf+i+4, len);
          }
          break;
 
@@ -478,7 +521,7 @@ int aim_sendbuddyoncoming(struct aim_session_t *sess, struct aim_conn_t *conn, s
   if (!sess || !conn || !info)
     return 0;
 
-  if (!(tx = aim_tx_new(0x0002, conn, 1152)))
+  if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152)))
     return -1;
 
   tx->lock = 1;
@@ -506,7 +549,7 @@ int aim_sendbuddyoffgoing(struct aim_session_t *sess, struct aim_conn_t *conn, c
   if (!sess || !conn || !sn)
     return 0;
 
-  if (!(tx = aim_tx_new(0x0002, conn, 10+1+strlen(sn))))
+  if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+1+strlen(sn))))
     return -1;
 
   tx->lock = 1;
index 52716ac7d3827fb4209708c3007a3100df3a986f..8b3b925b7f47f3297ab501139f35c9034a6fc114 100644 (file)
@@ -22,7 +22,7 @@ int aim_sendconnack(struct aim_session_t *sess,
   
   struct command_tx_struct *newpacket;
 
-  if (!(newpacket = aim_tx_new(0x0001, conn, 4)))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0001, conn, 4)))
     return -1;
 
   newpacket->lock = 1;
@@ -51,7 +51,7 @@ int aim_request_login(struct aim_session_t *sess,
   
   struct command_tx_struct *newpacket;
 
-  if (!(newpacket = aim_tx_new(0x0002, conn, 10+2+2+strlen(sn))))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+2+2+strlen(sn))))
     return -1;
 
   newpacket->lock = 1;
@@ -87,7 +87,7 @@ int aim_send_login (struct aim_session_t *sess,
   if (!clientinfo || !sn || !password)
     return -1;
 
-  if (!(newpacket = aim_tx_new(0x0002, conn, 1152)))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152)))
     return -1;
 
   /*
@@ -150,7 +150,7 @@ int aim_send_login (struct aim_session_t *sess,
   }
 
   newpacket->lock = 1;
-  newpacket->type = 0x01;
+  newpacket->hdr.oscar.type = 0x01;
 
   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001);
@@ -161,20 +161,16 @@ int aim_send_login (struct aim_session_t *sess,
   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
   curbyte += aimutil_put16(newpacket->data+curbyte, strlen(password));
   password_encoded = (char *) malloc(strlen(password));
-  if (icqmode)
-    aimicq_encode_password(password, password_encoded);
-  else
-    aim_encode_password(password, password_encoded);
+  aim_encode_password(password, password_encoded);
   curbyte += aimutil_putstr(newpacket->data+curbyte, password_encoded, strlen(password));
   free(password_encoded);
   
-  curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0016, 0x010a /*0x0004*/);
-  
   if (strlen(clientinfo->clientstring)) {
     curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
     curbyte += aimutil_put16(newpacket->data+curbyte, strlen(clientinfo->clientstring));
     curbyte += aimutil_putstr(newpacket->data+curbyte, clientinfo->clientstring, strlen(clientinfo->clientstring));
   }
+  curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0016, /*0x010a*/ 0x0004);
   curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0017, clientinfo->major /*0x0001*/);
   curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0018, clientinfo->minor /*0x0001*/);
   curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0019, 0x0001);
@@ -218,39 +214,21 @@ int aim_send_login (struct aim_session_t *sess,
 int aim_encode_password(const char *password, u_char *encoded)
 {
   u_char encoding_table[] = {
+#if 0 /* old v1 table */
     0xf3, 0xb3, 0x6c, 0x99,
     0x95, 0x3f, 0xac, 0xb6,
     0xc5, 0xfa, 0x6b, 0x63,
     0x69, 0x6c, 0xc3, 0x9f
-  };
-
-  int i;
-  
-  for (i = 0; i < strlen(password); i++)
-      encoded[i] = (password[i] ^ encoding_table[i]);
-
-  return 0;
-}
-
-/*
- * They changed the hash slightly for ICQ. 
- *   This new hash may work for AIM too (though
- *   the max password length for ICQ is only 
- *   eight characters, where its 16 with AIM).
- *
- */
-int aimicq_encode_password(const char *password, u_char *encoded)
-{
-  u_char encoding_table[] = {
+#else /* v2.1 table, also works for ICQ */
     0xf3, 0x26, 0x81, 0xc4,
-    0x39, 0x86, 0xdb, 0x92
+    0x39, 0x86, 0xdb, 0x92,
+    0x71, 0xa3, 0xb9, 0xe6,
+    0x53, 0x7a, 0x95, 0x7c
+#endif
   };
 
   int i;
-
-  if (strlen(password) > 8)
-    return -1;
-
+  
   for (i = 0; i < strlen(password); i++)
       encoded[i] = (password[i] ^ encoding_table[i]);
 
@@ -306,7 +284,8 @@ int aim_authparse(struct aim_session_t *sess,
    * If we have both an IP number (0x0005) and a cookie (0x0006),
    * then the login was successful.
    */
-  else if (aim_gettlv(tlvlist, 0x0005, 1) && aim_gettlv(tlvlist, 0x0006, 1)) {
+  else if (aim_gettlv(tlvlist, 0x0005, 1) && aim_gettlv(tlvlist, 0x0006, 1) 
+          /*aim_gettlv(tlvlist, 0x0006, 1)->length*/) {
     struct aim_tlv_t *tmptlv;
 
     /*
@@ -369,7 +348,7 @@ unsigned long aim_sendauthresp(struct aim_session_t *sess,
   struct command_tx_struct *tx;
   struct aim_tlvlist_t *tlvlist = NULL;
 
-  if (!(tx = aim_tx_new(0x0004, conn, 1152)))
+  if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0004, conn, 1152)))
     return -1;
   
   tx->lock = 1;
@@ -417,7 +396,7 @@ int aim_sendserverready(struct aim_session_t *sess, struct aim_conn_t *conn)
   struct command_tx_struct *tx;
   int i = 0;
 
-  if (!(tx = aim_tx_new(0x0002, conn, 10+0x22)))
+  if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+0x22)))
     return -1;
 
   tx->lock = 1;
@@ -456,7 +435,7 @@ unsigned long aim_sendredirect(struct aim_session_t *sess,
   struct aim_tlvlist_t *tlvlist = NULL;
   int i = 0;
 
-  if (!(tx = aim_tx_new(0x0002, conn, 1152)))
+  if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152)))
     return -1;
 
   tx->lock = 1;
index 9a0d1f3342c2218384255071d8893c317c34bfe3..c6244eec5c692feeae8b24aaf4801b1bf0d31175 100644 (file)
@@ -79,7 +79,7 @@ u_long aim_bos_changevisibility(struct aim_session_t *sess,
   listcount = aimutil_itemcnt(localcpy, '&');
   packlen = aimutil_tokslen(localcpy, 99, '&') + listcount + 9;
 
-  if (!(newpacket = aim_tx_new(0x0002, conn, packlen)))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, packlen)))
     return -1;
 
   newpacket->lock = 1;
@@ -173,7 +173,7 @@ u_long aim_bos_setbuddylist(struct aim_session_t *sess,
 #endif
   free(localcpy);
 
-  if (!(newpacket = aim_tx_new(0x0002, conn, packet_login_phase3c_hi_b_len - 6)))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, packet_login_phase3c_hi_b_len - 6)))
     return -1;
 
   newpacket->lock = 1;
@@ -209,20 +209,6 @@ u_long aim_bos_setbuddylist(struct aim_session_t *sess,
  * Gives BOS your profile.
  *
  * 
- * The large data chunk given here is of unknown decoding.
- * What I do know is that each 0x20 byte repetition 
- * represents a capability.  People with only the 
- * first two reptitions can support normal messaging
- * and chat (client version 2.0 or 3.0).  People with 
- * the third as well can also support voice chat (client
- * version 3.5 or higher).  IOW, if we don't send this,
- * we won't get chat invitations (get "software doesn't
- * support chat" error).
- *
- * This data is broadcast along with your oncoming
- * buddy command to everyone who has you on their
- * buddy list, as a type 0x0002 TLV.
- * 
  */
 u_long aim_bos_setprofile(struct aim_session_t *sess,
                          struct aim_conn_t *conn, 
@@ -231,9 +217,9 @@ u_long aim_bos_setprofile(struct aim_session_t *sess,
                          unsigned int caps)
 {
   struct command_tx_struct *newpacket;
-  int i = 0;
+  int i = 0, tmp, caplen;
 
-  if (!(newpacket = aim_tx_new(0x0002, conn, 1152+strlen(profile)+1+(awaymsg?strlen(awaymsg):0))))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152+strlen(profile)+1+(awaymsg?strlen(awaymsg):0))))
     return -1;
 
   i += aim_putsnac(newpacket->data, 0x0002, 0x004, 0x0000, sess->snac_nextid);
@@ -249,25 +235,12 @@ u_long aim_bos_setprofile(struct aim_session_t *sess,
     i += aim_puttlv_str(newpacket->data+i, 0x0004, 0x0000, NULL);
 
   /* Capability information. */
-  {
-    int isave;
-    i += aimutil_put16(newpacket->data+i, 0x0005);
-    isave = i;
-    i += aimutil_put16(newpacket->data+i, 0);
-    if (caps & AIM_CAPS_BUDDYICON)
-      i += aimutil_putstr(newpacket->data+i, aim_caps[0], 0x10);
-    if (caps & AIM_CAPS_VOICE)
-      i += aimutil_putstr(newpacket->data+i, aim_caps[1], 0x10);
-    if (caps & AIM_CAPS_IMIMAGE)
-      i += aimutil_putstr(newpacket->data+i, aim_caps[2], 0x10);
-    if (caps & AIM_CAPS_CHAT)
-      i += aimutil_putstr(newpacket->data+i, aim_caps[3], 0x10);
-    if (caps & AIM_CAPS_GETFILE)
-      i += aimutil_putstr(newpacket->data+i, aim_caps[4], 0x10);
-    if (caps & AIM_CAPS_SENDFILE)
-      i += aimutil_putstr(newpacket->data+i, aim_caps[5], 0x10);
-    aimutil_put16(newpacket->data+isave, i-isave-2);
-  }
+  tmp = (i += aimutil_put16(newpacket->data+i, 0x0005));
+  i += aimutil_put16(newpacket->data+i, 0x0000); /* rewritten later */
+  i += (caplen = aim_putcap(newpacket->data+i, 512, caps));
+  aimutil_put16(newpacket->data+tmp, caplen); /* rewrite TLV size */
+
   newpacket->commandlen = i;
   aim_tx_enqueue(sess, newpacket);
   
@@ -347,7 +320,7 @@ u_long aim_bos_clientready(struct aim_session_t *sess,
   int command_2_len = 0x52;
   struct command_tx_struct *newpacket;
   
-  if (!(newpacket = aim_tx_new(0x0002, conn, command_2_len)))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, command_2_len)))
     return -1;
 
   newpacket->lock = 1;
@@ -391,7 +364,7 @@ u_long aim_bos_ackrateresp(struct aim_session_t *sess,
   if (conn->type != AIM_CONN_TYPE_BOS)
     packlen += 2;
 
-  if(!(newpacket = aim_tx_new(0x0002, conn, packlen)));
+  if(!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, packlen)));
   
   newpacket->lock = 1;
 
@@ -438,7 +411,7 @@ u_long aim_bos_reqpersonalinfo(struct aim_session_t *sess,
 {
   struct command_tx_struct *newpacket;
   
-  if (!(newpacket = aim_tx_new(0x0002, conn, 12)))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 12)))
     return -1;
 
   newpacket->lock = 1;
@@ -460,7 +433,7 @@ u_long aim_setversions(struct aim_session_t *sess,
   struct command_tx_struct *newpacket;
   int i;
 
-  if (!(newpacket = aim_tx_new(0x0002, conn, 10 + (4*11))))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10 + (4*11))))
     return -1;
 
   newpacket->lock = 1;
@@ -568,7 +541,7 @@ u_long aim_genericreq_n(struct aim_session_t *sess,
 {
   struct command_tx_struct *newpacket;
 
-  if (!(newpacket = aim_tx_new(0x0002, conn, 10)))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10)))
     return 0;
 
   newpacket->lock = 1;
@@ -594,7 +567,7 @@ u_long aim_genericreq_l(struct aim_session_t *sess,
   if (!longdata)
     return aim_genericreq_n(sess, conn, family, subtype);
 
-  if (!(newpacket = aim_tx_new(0x0002, conn, 10+sizeof(u_long))))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+sizeof(u_long))))
     return -1;
 
   newpacket->lock = 1;
@@ -620,7 +593,7 @@ u_long aim_genericreq_s(struct aim_session_t *sess,
   if (!shortdata)
     return aim_genericreq_n(sess, conn, family, subtype);
 
-  if (!(newpacket = aim_tx_new(0x0002, conn, 10+sizeof(u_short))))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+sizeof(u_short))))
     return -1;
 
   newpacket->lock = 1;
index 7e4fc75de35d20e44fd7a29e4baae58ae0205301..81d3cffadcb5ba6efd031d3f6d52b7d07f6b3d98 100644 (file)
@@ -311,6 +311,19 @@ int aim_rxdispatch(struct aim_session_t *sess)
       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:
        /*
@@ -373,7 +386,7 @@ int aim_rxdispatch(struct aim_session_t *sess)
        u_short family;
        u_short subtype;
 
-       if (workingPtr->type == 0x04) {
+       if (workingPtr->hdr.oscar.type == 0x04) {
          workingPtr->handled = aim_negchan_middle(sess, workingPtr);
          break;
        }
@@ -550,8 +563,21 @@ int aim_rxdispatch(struct aim_session_t *sess)
        }
        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;
+      }
       default:
-       printf("\ninternal error: unknown connection type (very bad.) (type = %d, fd = %d, channel = %02x, commandlen = %02x)\n\n", workingPtr->conn->type, workingPtr->conn->fd, workingPtr->type, workingPtr->commandlen);
+       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;
       }        
index 481e49b07c713e82d9ba68f2e28e165b2826ef97..003c1a20fc8413f81c588636c367c6f3897dd801 100644 (file)
@@ -14,7 +14,7 @@
  */
 int aim_get_command(struct aim_session_t *sess, struct aim_conn_t *conn)
 {
-  u_char generic[6]; 
+  unsigned char generic[6]; 
   struct command_rx_struct *newrx = NULL;
 
   if (!sess || !conn)
@@ -27,8 +27,8 @@ int aim_get_command(struct aim_session_t *sess, struct aim_conn_t *conn)
    * Rendezvous (client-client) connections do not speak
    * FLAP, so this function will break on them.
    */
-  if (conn->type > 0x01000)
-    return 0;
+  if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) 
+    return aim_get_command_rendezvous(sess, conn);
 
   /*
    * Read FLAP header.  Six bytes:
@@ -44,7 +44,6 @@ int aim_get_command(struct aim_session_t *sess, struct aim_conn_t *conn)
     faim_mutex_unlock(&conn->active);
     return -1;
   }
-  faim_mutex_unlock(&conn->active);
 
   /*
    * This shouldn't happen unless the socket breaks, the server breaks,
@@ -52,22 +51,27 @@ int aim_get_command(struct aim_session_t *sess, struct aim_conn_t *conn)
    */
   if (generic[0] != 0x2a) {
     faimdprintf(1, "Bad incoming data!");
+    faim_mutex_unlock(&conn->active);
     return -1;
   }    
 
   /* allocate a new struct */
-  newrx = (struct command_rx_struct *)malloc(sizeof(struct command_rx_struct));
-  if (!newrx)
+  if (!(newrx = (struct command_rx_struct *)malloc(sizeof(struct command_rx_struct)))) {
+    faim_mutex_unlock(&conn->active);
     return -1;
+  }
   memset(newrx, 0x00, sizeof(struct command_rx_struct));
 
   newrx->lock = 1;  /* lock the struct */
 
+  /* we're doing OSCAR if we're here */
+  newrx->hdrtype = AIM_FRAMETYPE_OSCAR;
+
   /* store channel -- byte 2 */
-  newrx->type = (char) generic[1];
+  newrx->hdr.oscar.type = (char) generic[1];
 
   /* store seqnum -- bytes 3 and 4 */
-  newrx->seqnum = aimutil_get16(generic+2);
+  newrx->hdr.oscar.seqnum = aimutil_get16(generic+2);
 
   /* store commandlen -- bytes 5 and 6 */
   newrx->commandlen = aimutil_get16(generic+4);
@@ -75,14 +79,13 @@ int aim_get_command(struct aim_session_t *sess, struct aim_conn_t *conn)
   newrx->nofree = 0; /* free by default */
 
   /* malloc for data portion */
-  newrx->data = (u_char *) malloc(newrx->commandlen);
-  if (!newrx->data) {
+  if (!(newrx->data = (u_char *) malloc(newrx->commandlen))) {
     free(newrx);
+    faim_mutex_unlock(&conn->active);
     return -1;
   }
 
   /* read the data portion of the packet */
-  faim_mutex_lock(&conn->active);
   if (read(conn->fd, newrx->data, newrx->commandlen) < newrx->commandlen){
     free(newrx->data);
     free(newrx);
@@ -119,6 +122,82 @@ int aim_get_command(struct aim_session_t *sess, struct aim_conn_t *conn)
   return 0;  
 }
 
+int aim_get_command_rendezvous(struct aim_session_t *sess, struct aim_conn_t *conn)
+{
+  unsigned char hdrbuf1[6];
+  unsigned char *hdr = NULL;
+  int hdrlen, hdrtype;
+  int payloadlength = 0;
+  int flags = 0;
+  char *snptr = NULL;
+
+  if (read(conn->fd, hdrbuf1, 6) < 6) {
+    perror("read");
+    printf("faim: rend: read error\n");
+    aim_conn_kill(sess, &conn);
+    return -1;
+  }
+
+  hdrlen = aimutil_get16(hdrbuf1+4);
+
+  hdrlen -= 6;
+  hdr = malloc(hdrlen);
+
+  faim_mutex_lock(&conn->active);
+  if (read(conn->fd, hdr, hdrlen) < hdrlen) {
+    perror("read");
+    printf("faim: rend: read2 error\n");
+    free(hdr);
+    faim_mutex_unlock(&conn->active);
+    aim_conn_kill(sess, &conn);
+    return -1;
+  }
+  
+  hdrtype = aimutil_get16(hdr);  
+
+  switch (hdrtype) {
+  case 0x0001: {
+    payloadlength = aimutil_get32(hdr+22);
+    flags = aimutil_get16(hdr+32);
+    snptr = hdr+38;
+
+    printf("OFT frame: %04x / %04x / %04x / %s\n", hdrtype, payloadlength, flags, snptr);
+
+    if (flags == 0x000e) {
+      printf("directim: %s has started typing\n", snptr);
+    } else if ((flags == 0x0000) && payloadlength) {
+      unsigned char *buf;
+      buf = malloc(payloadlength+1);
+
+      /* XXX theres got to be a better way */
+      faim_mutex_lock(&conn->active);
+      if (recv(conn->fd, buf, payloadlength, MSG_WAITALL) < payloadlength) {
+       perror("read");
+       printf("faim: rend: read3 error\n");
+       free(buf);
+       faim_mutex_unlock(&conn->active);
+       aim_conn_kill(sess, &conn);
+       return -1;
+      }
+      faim_mutex_unlock(&conn->active);
+      buf[payloadlength] = '\0';
+      printf("directim: %s/%04x/%04x/%s\n", snptr, payloadlength, flags, buf);
+      aim_send_im_direct(sess, conn, buf);
+      free(buf);
+    }
+    break;
+  }
+  default:
+    printf("OFT frame: type %04x\n", hdrtype);  
+    /* data connection may be unreliable here */
+    break;
+  } /* switch */
+
+  free(hdr);
+  
+  return 0;
+}
+
 /*
  * Purge recieve queue of all handled commands (->handled==1).  Also
  * allows for selective freeing using ->nofree so that the client can
@@ -144,6 +223,8 @@ void aim_purge_rxqueue(struct aim_session_t *sess)
       sess->queue_incoming = NULL;
 
       if (!tmp->nofree) {
+       if (tmp->hdrtype == AIM_FRAMETYPE_OFT)
+         free(tmp->hdr.oft.hdr2);
        free(tmp->data);
        free(tmp);
       } else
@@ -157,6 +238,8 @@ void aim_purge_rxqueue(struct aim_session_t *sess)
       tmp = cur->next;
       cur->next = tmp->next;
       if (!tmp->nofree) {
+       if (tmp->hdrtype == AIM_FRAMETYPE_OFT)
+         free(tmp->hdr.oft.hdr2);
        free(tmp->data);
        free(tmp);
       } else
index 0f18faf73ec7c12eadb11e26f14c53e2f506f3e3..d67d772af723d90419d82310716dd17b2eb6bf96 100644 (file)
@@ -17,7 +17,7 @@ u_long aim_usersearch_address(struct aim_session_t *sess,
   if (!address)
     return -1;
 
-  if (!(newpacket = aim_tx_new(0x0002, conn, 10+strlen(address))))
+  if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+strlen(address))))
     return -1;
 
   newpacket->lock = 1;
index bdc3b14bf6b0845630271fc99d62fc774245da0c..619137d7b5b3c046be1e8d63ceff4a1600e08a6e 100644 (file)
  *
  * Right now, that is.  If/when we implement a pool of transmit
  * frames, this will become the request-an-unused-frame part.
+ *
+ * framing = AIM_FRAMETYPE_OFT/OSCAR
+ * chan = channel for OSCAR, hdrtype for OFT
+ *
  */
-struct command_tx_struct *aim_tx_new(int chan, struct aim_conn_t *conn, int datalen)
+struct command_tx_struct *aim_tx_new(unsigned short framing, int chan, struct aim_conn_t *conn, int datalen)
 {
   struct command_tx_struct *new;
 
@@ -30,11 +34,21 @@ struct command_tx_struct *aim_tx_new(int chan, struct aim_conn_t *conn, int data
   memset(new, 0, sizeof(struct command_tx_struct));
 
   new->conn = conn; 
-  new->type = chan;
 
   if(datalen) {
     new->data = (u_char *)malloc(datalen);
     new->commandlen = datalen;
+  } else
+    new->data = NULL;
+
+  new->hdrtype = framing;
+  if (new->hdrtype == AIM_FRAMETYPE_OSCAR) {
+    new->hdr.oscar.type = chan;
+  } else if (new->hdrtype == AIM_FRAMETYPE_OFT) {
+    new->hdr.oft.type = chan;
+    new->hdr.oft.hdr2len = 0; /* this will get setup by caller */
+  } else { 
+    printf("tx_new: unknown framing\n");
   }
 
   return new;
@@ -66,8 +80,10 @@ int aim_tx_enqueue__queuebased(struct aim_session_t *sess,
       newpacket->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS);
   }
  
-  /* assign seqnum */
-  newpacket->seqnum = aim_get_next_txseqnum(newpacket->conn);
+  if (newpacket->hdrtype == AIM_FRAMETYPE_OSCAR) {
+    /* assign seqnum */
+    newpacket->hdr.oscar.seqnum = aim_get_next_txseqnum(newpacket->conn);
+  }
   /* set some more fields */
   newpacket->lock = 1; /* lock */
   newpacket->sent = 0; /* not sent yet */
@@ -116,7 +132,8 @@ int aim_tx_enqueue__immediate(struct aim_session_t *sess, struct command_tx_stru
     return -1;
   }
 
-  newpacket->seqnum = aim_get_next_txseqnum(newpacket->conn);
+  if (newpacket->hdrtype == AIM_FRAMETYPE_OSCAR)
+    newpacket->hdr.oscar.seqnum = aim_get_next_txseqnum(newpacket->conn);
 
   newpacket->lock = 1; /* lock */
   newpacket->sent = 0; /* not sent yet */
@@ -169,8 +186,10 @@ int aim_tx_printqueue(struct aim_session_t *sess)
     faimdprintf(2, "aim_tx_flushqueue(): queue empty");
   else {
       for (cur = sess->queue_outgoing; cur; cur = cur->next) {
-         faimdprintf(2, "\t  %2x   %4x %4x   %1d    %1d\n", 
-                     cur->type, cur->seqnum, 
+         faimdprintf(2, "\t  %2x  %2x   %4x %4x   %1d    %1d\n", 
+                     cur->hdrtype,
+                     (cur->hdrtype==AIM_FRAMETYPE_OFT)?cur->hdr.oft.type:cur->hdr.oscar.type, 
+                     (cur->hdrtype==AIM_FRAMETYPE_OSCAR)?cur->seqnum:0, 
                      cur->commandlen, cur->lock, 
                      cur->sent);
       }
@@ -208,44 +227,84 @@ int aim_tx_printqueue(struct aim_session_t *sess)
  */
 int aim_tx_sendframe(struct command_tx_struct *cur)
 {
-  u_char *curPacket;
+  int buflen = 0;
+  unsigned char *curPacket;
 
   if (!cur)
     return -1; /* fatal */
 
   cur->lock = 1; /* lock the struct */
 
+  if (cur->hdrtype == AIM_FRAMETYPE_OSCAR)
+    buflen = cur->commandlen + 6;
+  else if (cur->hdrtype == AIM_FRAMETYPE_OFT)
+    buflen = cur->hdr.oft.hdr2len + 8;
+  else {
+    cur->lock = 0;
+    return -1;
+  }
+
   /* allocate full-packet buffer */
-  curPacket = (char *) malloc(cur->commandlen + 6);
+  if (!(curPacket = (unsigned char *) malloc(buflen))) {
+    cur->lock = 0;
+    return -1;
+  }
       
-  /* command byte */
-  curPacket[0] = 0x2a;
+  if (cur->hdrtype == AIM_FRAMETYPE_OSCAR) {
+    /* command byte */
+    curPacket[0] = 0x2a;
       
-  /* type/family byte */
-  curPacket[1] = cur->type;
+    /* type/family byte */
+    curPacket[1] = cur->hdr.oscar.type;
       
-  /* bytes 3+4: word: FLAP sequence number */
-  aimutil_put16(curPacket+2, cur->seqnum);
+    /* bytes 3+4: word: FLAP sequence number */
+    aimutil_put16(curPacket+2, cur->hdr.oscar.seqnum);
 
-  /* bytes 5+6: word: SNAC len */
-  aimutil_put16(curPacket+4, cur->commandlen);
+    /* bytes 5+6: word: SNAC len */
+    aimutil_put16(curPacket+4, cur->commandlen);
       
-  /* bytes 7 and on: raw: SNAC data */  /* XXX: ye gods! get rid of this! */
-  memcpy(&(curPacket[6]), cur->data, cur->commandlen);
-      
-  /* full image of raw packet data now in curPacket */
+    /* bytes 7 and on: raw: SNAC data */  /* XXX: ye gods! get rid of this! */
+    memcpy(&(curPacket[6]), cur->data, cur->commandlen);
+
+  } else if (cur->hdrtype == AIM_FRAMETYPE_OFT) {
+    int z = 0;
+
+    z += aimutil_put8(curPacket+z, 0x4f);
+    z += aimutil_put8(curPacket+z, 0x44);
+    z += aimutil_put8(curPacket+z, 0x43);
+    z += aimutil_put8(curPacket+z, 0x32);
+
+    z += aimutil_put16(curPacket+z, cur->hdr.oft.hdr2len + 8);
+    z += aimutil_put16(curPacket+z, cur->hdr.oft.type);
+
+    memcpy(curPacket+z, cur->hdr.oft.hdr2, cur->hdr.oft.hdr2len);
+  }
+
+  /* 
+   * For OSCAR, a full image of the raw packet data now in curPacket.
+   * For OFT, an image of just the bloated header is in curPacket, 
+   * since OFT allows us to do the data in a different write (yay!).
+   */
   faim_mutex_lock(&cur->conn->active);
-  if ( (u_int)write(cur->conn->fd, curPacket, (cur->commandlen + 6)) != (cur->commandlen + 6)) {
+  if ( (u_int)write(cur->conn->fd, curPacket, buflen) != buflen) {
     faim_mutex_unlock(&cur->conn->active);
-    printf("\nWARNING: Error in sending packet 0x%4x -- will try again next time\n\n", cur->seqnum);
+    printf("\nWARNING: Error in sending packet -- will try again next time\n\n");
     cur->sent = 0; /* mark it unsent */
     return 0; /* bail out -- continuable error */
-  } else {
-    faimdprintf(2, "\nSENT 0x%4x\n\n", cur->seqnum);
-    
-    cur->sent = 1; /* mark the struct as sent */
-    cur->conn->lastactivity = time(NULL);
   }
+
+  if ((cur->hdrtype == AIM_FRAMETYPE_OFT) && cur->commandlen) {
+    if (write(cur->conn->fd, cur->data, cur->commandlen) != cur->commandlen) {
+      /* 
+       * Theres nothing we can do about this since we've already sent the 
+       * header!  The connection is unstable.
+       */
+    }
+  }
+
+  cur->sent = 1; /* mark the struct as sent */
+  cur->conn->lastactivity = time(NULL);
+
   faim_mutex_unlock(&cur->conn->active);
 
 #if debug > 2
@@ -324,6 +383,8 @@ void aim_tx_purgequeue(struct aim_session_t *sess)
     if (!sess->queue_outgoing->lock && sess->queue_outgoing->sent) {
       tmp = sess->queue_outgoing;
       sess->queue_outgoing = NULL;
+      if (tmp->hdrtype == AIM_FRAMETYPE_OFT)
+       free(tmp->hdr.oft.hdr2);
       free(tmp->data);
       free(tmp);
     }
@@ -334,6 +395,8 @@ void aim_tx_purgequeue(struct aim_session_t *sess)
     if (!cur->next->lock && cur->next->sent) {
       tmp = cur->next;
       cur->next = tmp->next;
+      if (tmp->hdrtype == AIM_FRAMETYPE_OFT)
+       free(tmp->hdr.oft.hdr2);
       free(tmp->data);
       free(tmp);
     }  
index d0d2da4d49e0266b5914d5dbfb1ce349895e1c06..ec3592e9bc8ce0441341ee2dc2a57c5a79e30a15 100644 (file)
@@ -74,7 +74,7 @@
  * with utterly oversized instant messages!
  * 
  */
-#define MAXMSGLEN 7988
+#define MAXMSGLEN 7987
 
 /*
  * Current Maximum Length for Chat Room Messages
@@ -154,6 +154,9 @@ struct client_info_s {
 #define AIM_CONN_STATUS_RESOLVERR   0x0080
 #define AIM_CONN_STATUS_CONNERR     0x0040
 
+#define AIM_FRAMETYPE_OSCAR 0x0000
+#define AIM_FRAMETYPE_OFT 0x0001
+
 struct aim_conn_t {
   int fd;
   int type;
@@ -170,25 +173,43 @@ struct aim_conn_t {
 
 /* struct for incoming commands */
 struct command_rx_struct {
-                            /* byte 1 assumed to always be 0x2a */
-  char type;                /* type code (byte 2) */
-  u_int seqnum;             /* sequence number (bytes 3 and 4) */
-  u_int commandlen;         /* total packet len - 6 (bytes 5 and 6) */
-  u_char *data;             /* packet data (from 7 byte on) */
-  u_int lock;               /* 0 = open, !0 = locked */
-  u_int handled;            /* 0 = new, !0 = been handled */
-  u_int nofree;                    /* 0 = free data on purge, 1 = only unlink */
+  unsigned char hdrtype; /* defines which piece of the union to use */
+  union {
+    struct { 
+      char type;        
+      unsigned short seqnum;     
+    } oscar;
+    struct {
+      unsigned short type;
+      unsigned short hdr2len;
+      unsigned char *hdr2; /* rest of bloated header */
+    } oft;
+  } hdr;
+  unsigned short commandlen;         /* total payload length */
+  unsigned char *data;             /* packet data (from 7 byte on) */
+  unsigned char lock;               /* 0 = open, !0 = locked */
+  unsigned char handled;            /* 0 = new, !0 = been handled */
+  unsigned char nofree;                    /* 0 = free data on purge, 1 = only unlink */
   struct aim_conn_t *conn;  /* the connection it came in on... */
   struct command_rx_struct *next; /* ptr to next struct in list */
 };
 
 /* struct for outgoing commands */
 struct command_tx_struct {
-                            /* byte 1 assumed to be 0x2a */
-  char type;                /* type/family code */
-  u_int seqnum;             /* seqnum dynamically assigned on tx */
-  u_int commandlen;         /* SNAC length */
-  u_char *data;             /* packet data */
+  unsigned char hdrtype; /* defines which piece of the union to use */
+  union {
+    struct {
+      unsigned char type;
+      unsigned short seqnum;
+    } oscar;
+    struct {
+      unsigned short type;
+      unsigned short hdr2len;
+      unsigned char *hdr2;
+    } oft;
+  } hdr;
+  u_int commandlen;         
+  u_char *data;      
   u_int lock;               /* 0 = open, !0 = locked */
   u_int sent;               /* 0 = pending, !0 = has been sent */
   struct aim_conn_t *conn; 
@@ -355,7 +376,8 @@ int aim_parse_unknown(struct aim_session_t *, struct command_rx_struct *command,
 int aim_parse_missed_im(struct aim_session_t *, struct command_rx_struct *, ...);
 int aim_parse_last_bad(struct aim_session_t *, struct command_rx_struct *, ...);
 
-struct command_tx_struct *aim_tx_new(int, struct aim_conn_t *, int);
+
+struct command_tx_struct *aim_tx_new(unsigned short framing, int chan, struct aim_conn_t *conn, int datalen);
 int aim_tx_enqueue__queuebased(struct aim_session_t *, struct command_tx_struct *);
 int aim_tx_enqueue__immediate(struct aim_session_t *, struct command_tx_struct *);
 #define aim_tx_enqueue(x, y) ((*(x->tx_enqueue))(x, y))
@@ -458,21 +480,16 @@ int aim_negchan_middle(struct aim_session_t *sess, struct command_rx_struct *com
 #define AIM_CAPS_CHAT 0x08
 #define AIM_CAPS_GETFILE 0x10
 #define AIM_CAPS_SENDFILE 0x20
+
 extern u_char aim_caps[6][16];
+u_short aim_getcap(unsigned char *capblock, int buflen);
+int aim_putcap(unsigned char *capblock, int buflen, u_short caps);
 
 #define AIM_GETINFO_GENERALINFO 0x00001
 #define AIM_GETINFO_AWAYMESSAGE 0x00003
 
-#define AIM_RENDEZVOUS_VOICE 0x0000
-#define AIM_RENDEZVOUS_FILETRANSFER 0x0001
-#define AIM_RENDEZVOUS_CHAT_EX3 0x0003
-#define AIM_RENDEZVOUS_CHAT_EX4 0x0004
-#define AIM_RENDEZVOUS_CHAT_EX5 0x0005
-#define AIM_RENDEZVOUS_FILETRANSFER_GET 0x0012
-
 struct aim_msgcookie_t {
   unsigned char cookie[8];
-  unsigned char extended[16];
   int type;
   void *data;
   time_t addtime;
@@ -492,6 +509,7 @@ int aim_purgecookies(struct aim_session_t *sess);
 #define AIM_TRANSFER_DENY_DECLINE 0x0001
 #define AIM_TRANSFER_DENY_NOTACCEPTING 0x0002
 u_long aim_denytransfer(struct aim_session_t *sess, struct aim_conn_t *conn, char *sender, char *cookie, unsigned short code);
+u_long aim_accepttransfer(struct aim_session_t *sess, struct aim_conn_t *conn, char *sender, char *cookie, unsigned short rendid);
 
 u_long aim_getinfo(struct aim_session_t *, struct aim_conn_t *, const char *, unsigned short);
 int aim_extractuserinfo(u_char *, struct aim_userinfo_s *);
index 1bf7414fda115b0b24704bfa08213b4cc5629a2a..6dcde74bf7967510a5b49198b7ce2fc8708b7327 100644 (file)
@@ -74,9 +74,9 @@ int main(void)
   struct aim_conn_t *authconn = NULL, *waitingconn = NULL;
   int keepgoing = 1, stayconnected = 1;
 
-#if 0
+#if 1
   /* Use something like this for AIM */
-  struct client_info_s info = {"FAIMtest (Hi guys!)", 3, 5, 1670, "us", "en"};
+  struct client_info_s info = {"Boo", 2, 1, 0, "us", "en"};
 #else
   /* or something exactly like this for ICQ and AIM */
   struct client_info_s info = {"Random String (libfaim)", 4, 30, 3141, "us", "en"};
@@ -163,7 +163,7 @@ int main(void)
       printf("\nTrying to reconnect in 2 seconds...\n");
       sleep(2);
       goto enter;
-    }
+   }
 
   /* Get out */
   exit(0);
@@ -266,7 +266,7 @@ int faimtest_handleredirect(struct aim_session_t *sess, struct command_rx_struct
 
       /* send the buddy list and profile (required, even if empty) */
       aim_bos_setbuddylist(sess, command->conn, buddies);
-      aim_bos_setprofile(sess, command->conn, profile, NULL, AIM_CAPS_CHAT);
+      aim_bos_setprofile(sess, command->conn, profile, NULL, AIM_CAPS_BUDDYICON | AIM_CAPS_CHAT | AIM_CAPS_VOICE | AIM_CAPS_GETFILE | AIM_CAPS_SENDFILE | AIM_CAPS_IMIMAGE);
 
       /* send final login command (required) */
       aim_bos_clientready(sess, command->conn); /* tell BOS we're ready to go live */
@@ -511,6 +511,7 @@ int faimtest_parse_incoming_im(struct aim_session_t *sess, struct command_rx_str
     printf("faimtest: icbm: membersince = %lu\n", userinfo->membersince);
     printf("faimtest: icbm: onlinesince = %lu\n", userinfo->onlinesince);
     printf("faimtest: icbm: idletime = 0x%04x\n", userinfo->idletime);
+    printf("faimtest: icbm: capabilities = 0x%04x\n", userinfo->capabilities);
     
     printf("faimtest: icbm: icbmflags = ");
     if (icbmflags & AIM_IMFLAGS_AWAY)
@@ -524,11 +525,18 @@ int faimtest_parse_incoming_im(struct aim_session_t *sess, struct command_rx_str
     printf("faimtest: icbm: message: %s\n", msg);
     
     if (msg) {
-      tmpstr = index(msg, '>');
-      if (tmpstr != NULL)
-       tmpstr+=1;
-      else
-       tmpstr = msg;
+      int i = 0;
+
+      while (msg[i] == '<') {
+       if (msg[i] == '<') {
+         while (msg[i] != '>')
+           i++;
+         i++;
+       }
+      }
+      tmpstr = msg+i;
+
+      printf("tmpstr = %s\n", tmpstr);
       
       if ( (strlen(tmpstr) >= 10) &&
           (!strncmp(tmpstr, "disconnect", 10)) ) {
@@ -553,8 +561,24 @@ int faimtest_parse_incoming_im(struct aim_session_t *sess, struct command_rx_str
       else if (!strncmp(tmpstr, "getinfo", 7)) {
        aim_getinfo(sess, command->conn, "75784102", AIM_GETINFO_GENERALINFO);
        aim_getinfo(sess, command->conn, "15853637", AIM_GETINFO_AWAYMESSAGE);
+      } else if (!strncmp(tmpstr, "sendmsg", 7)) {
+       int i;
+       i = atoi(tmpstr+8);
+       if (i < 10000) {
+         char *newbuf;
+         int z;
+
+         newbuf = malloc(i+1);
+         for (z = 0; z < i; z++) {
+           newbuf[z] = (z % 10)+0x30;
+         }
+         newbuf[i] = '\0';
+         aim_send_im(sess, command->conn, userinfo->sn, 0, newbuf);
+         free(newbuf);
+       }
       } else {
        printf("unknown command.\n");
+       aim_add_buddy(sess, command->conn, userinfo->sn);
       }
       
     }
@@ -568,7 +592,7 @@ int faimtest_parse_incoming_im(struct aim_session_t *sess, struct command_rx_str
     
     reqclass = va_arg(ap, unsigned short);
     switch (reqclass) {
-    case AIM_RENDEZVOUS_VOICE: {
+    case AIM_CAPS_VOICE: {
       userinfo = va_arg(ap, struct aim_userinfo_s *);
       va_end(ap);
       
@@ -588,13 +612,15 @@ int faimtest_parse_incoming_im(struct aim_session_t *sess, struct command_rx_str
       
       break;
     }
-    case AIM_RENDEZVOUS_FILETRANSFER: {
-      printf("faimtset: file transfer!\n");
+    case AIM_CAPS_GETFILE: {
+      printf("faimtset: get file!\n");
       break;
     }
-    case AIM_RENDEZVOUS_CHAT_EX3:
-    case AIM_RENDEZVOUS_CHAT_EX4:
-    case AIM_RENDEZVOUS_CHAT_EX5: {
+    case AIM_CAPS_SENDFILE: {
+      printf("faimtest: send file!\n");
+      break;
+    }
+    case AIM_CAPS_CHAT: {
       char *msg,*encoding,*lang;
       struct aim_chat_roominfo *roominfo;
       
@@ -677,7 +703,8 @@ int faimtest_parse_oncoming(struct aim_session_t *sess, struct command_rx_struct
   userinfo = va_arg(ap, struct aim_userinfo_s *);
   va_end(ap);
 
-  printf("\n%s is now online (class: %04x = %s%s%s%s%s%s%s%s)\n", userinfo->sn, userinfo->class,
+  printf("\n%s is now online (class: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
+        userinfo->sn, userinfo->class,
         (userinfo->class&AIM_CLASS_TRIAL)?" TRIAL":"",
         (userinfo->class&AIM_CLASS_UNKNOWN2)?" UNKNOWN2":"",
         (userinfo->class&AIM_CLASS_AOL)?" AOL":"",
@@ -685,8 +712,8 @@ int faimtest_parse_oncoming(struct aim_session_t *sess, struct command_rx_struct
         (userinfo->class&AIM_CLASS_FREE)?" FREE":"",
         (userinfo->class&AIM_CLASS_AWAY)?" AWAY":"",
         (userinfo->class&AIM_CLASS_UNKNOWN40)?" UNKNOWN40":"",
-        (userinfo->class&AIM_CLASS_UNKNOWN80)?" UNKNOWN80":"");
-
+        (userinfo->class&AIM_CLASS_UNKNOWN80)?" UNKNOWN80":"",
+        userinfo->capabilities);
   return 1;
 }
 
This page took 0.121043 seconds and 5 git commands to generate.