]> andersk Git - libfaim.git/blobdiff - aim_tlv.c
- Thu Feb 8 20:12:39 UTC 2001
[libfaim.git] / aim_tlv.c
index d03f2f92cfdb41d40ea49c8c389e9e31ec10d3af..8b8a52664f303e84b677d986bf2012963a3832f8 100644 (file)
--- a/aim_tlv.c
+++ b/aim_tlv.c
@@ -1,6 +1,19 @@
+
+#define FAIM_INTERNAL
 #include <faim/aim.h>
 
-struct aim_tlvlist_t *aim_readtlvchain(u_char *buf, int maxlen)
+/**
+ * aim_readtlvchain - Read a TLV chain from a buffer.
+ * @buf: Input buffer
+ * @maxlen: Length of input buffer
+ *
+ * Reads and parses a series of TLV patterns from a data buffer; the
+ * returned structure is manipulatable with the rest of the TLV
+ * routines.  When done with a TLV chain, aim_freetlvchain() should
+ * be called to free the dynamic substructures.
+ *
+ */
+faim_export struct aim_tlvlist_t *aim_readtlvchain(u_char *buf, int maxlen)
 {
   int pos;
   struct aim_tlvlist_t *list;
@@ -28,18 +41,32 @@ struct aim_tlvlist_t *aim_readtlvchain(u_char *buf, int maxlen)
          
          if ((pos+length) <= maxlen)
            {
-             cur = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
-             memset(cur, 0x00, sizeof(struct aim_tlvlist_t));
-
-             cur->tlv = aim_createtlv();       
-             cur->tlv->type = type;
-             cur->tlv->length = length;
-             cur->tlv->value = (u_char *)malloc(length*sizeof(u_char));
-             memcpy(cur->tlv->value, buf+pos, length);
-             
-             cur->next = list;
-             list = cur;
-             
+             /*
+              * Okay, so now AOL has decided that any TLV of
+              * type 0x0013 can only be two bytes, despite
+              * what the actual given length is.  So here 
+              * we dump any invalid TLVs of that sort.  Hopefully
+              * theres no special cases to this special case.
+              *   - mid (30jun2000)
+              */
+             if ((type == 0x0013) && (length != 0x0002)) {
+               printf("faim: skipping TLV t(0013) with invalid length (0x%04x)\n", length);
+               length = 0x0002;
+             } else {
+               cur = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
+               memset(cur, 0x00, sizeof(struct aim_tlvlist_t));
+
+               cur->tlv = aim_createtlv();     
+               cur->tlv->type = type;
+               cur->tlv->length = length; 
+               if (length) {
+                 cur->tlv->value = (unsigned char *)malloc(length);
+                 memcpy(cur->tlv->value, buf+pos, length);
+               } 
+
+               cur->next = list;
+               list = cur;
+             }
              pos += length;
            }
        }
@@ -48,7 +75,16 @@ struct aim_tlvlist_t *aim_readtlvchain(u_char *buf, int maxlen)
   return list;
 }
 
-void aim_freetlvchain(struct aim_tlvlist_t **list)
+/**
+ * aim_freetlvchain - Free a TLV chain structure
+ * @list: Chain to be freed
+ *
+ * Walks the list of TLVs in the passed TLV chain and
+ * frees each one. Note that any references to this data
+ * should be removed before calling this.
+ *
+ */
+faim_export void aim_freetlvchain(struct aim_tlvlist_t **list)
 {
   struct aim_tlvlist_t *cur, *cur2;
 
@@ -67,10 +103,316 @@ void aim_freetlvchain(struct aim_tlvlist_t **list)
   return;
 }
 
-/*
- * Grab the Nth TLV of type type in the TLV list list.
+/**
+ * aim_counttlvchain - Count the number of TLVs in a chain
+ * @list: Chain to be counted
+ *
+ * Returns the number of TLVs stored in the passed chain.
+ *
+ */
+faim_export int aim_counttlvchain(struct aim_tlvlist_t **list)
+{
+  struct aim_tlvlist_t *cur;
+  int count = 0;
+
+  if (!list || !(*list))
+    return 0;
+
+  for (cur = *list; cur; cur = cur->next)
+    count++;
+  return count;
+}
+
+/**
+ * aim_sizetlvchain - Count the number of bytes in a TLV chain
+ * @list: Chain to be sized
+ *
+ * Returns the number of bytes that would be needed to 
+ * write the passed TLV chain to a data buffer.
+ *
+ */
+faim_export int aim_sizetlvchain(struct aim_tlvlist_t **list)
+{
+  struct aim_tlvlist_t *cur;
+  int size = 0;
+
+  if (!list || !(*list))
+    return 0;
+
+  for (cur = *list; cur; cur = cur->next)
+    size += (4 + cur->tlv->length);
+  return size;
+}
+
+/**
+ * aim_addtlvtochain_str - Add a string to a TLV chain
+ * @list: Desination chain (%NULL pointer if empty)
+ * @type: TLV type
+ * @str: String to add
+ * @len: Length of string to add (not including %NULL)
+ *
+ * Adds the passed string as a TLV element of the passed type
+ * to the TLV chain.
+ *
+ */
+faim_export int aim_addtlvtochain_str(struct aim_tlvlist_t **list, unsigned short type, char *str, int len)
+{
+  struct aim_tlvlist_t *newtlv;
+  struct aim_tlvlist_t *cur;
+
+  if (!list)
+    return 0;
+
+  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 = len;
+  newtlv->tlv->value = (unsigned char *)malloc(newtlv->tlv->length*sizeof(unsigned char));
+  memcpy(newtlv->tlv->value, str, newtlv->tlv->length);
+
+  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_addtlvtochain16 - Add a 16bit integer to a TLV chain
+ * @list: Destination chain
+ * @type: TLV type to add
+ * @val: Value to add
+ *
+ * Adds a two-byte unsigned integer to a TLV chain.
+ *
+ */
+faim_export int aim_addtlvtochain16(struct aim_tlvlist_t **list, unsigned short type, unsigned short val)
+{
+  struct aim_tlvlist_t *newtl;
+  struct aim_tlvlist_t *cur;
+
+  if (!list)
+    return 0;
+
+  newtl = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
+  memset(newtl, 0x00, sizeof(struct aim_tlvlist_t));
+
+  newtl->tlv = aim_createtlv();        
+  newtl->tlv->type = type;
+  newtl->tlv->length = 2;
+  newtl->tlv->value = (unsigned char *)malloc(newtl->tlv->length*sizeof(unsigned char));
+  aimutil_put16(newtl->tlv->value, val);
+
+  newtl->next = NULL;
+
+  if (*list == NULL) {
+    *list = newtl;
+  } else if ((*list)->next == NULL) {
+    (*list)->next = newtl;
+  } else {
+    for(cur = *list; cur->next; cur = cur->next)
+      ;
+    cur->next = newtl;
+  }
+  return 2;
+}
+
+/**
+ * aim_addtlvtochain32 - Add a 32bit integer to a TLV chain
+ * @list: Destination chain
+ * @type: TLV type to add
+ * @val: Value to add
+ *
+ * Adds a four-byte unsigned integer to a TLV chain.
+ *
+ */
+faim_export int aim_addtlvtochain32(struct aim_tlvlist_t **list, unsigned short type, unsigned long val)
+{
+  struct aim_tlvlist_t *newtl;
+  struct aim_tlvlist_t *cur;
+
+  if (!list)
+    return 0;
+
+  newtl = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
+  memset(newtl, 0x00, sizeof(struct aim_tlvlist_t));
+
+  newtl->tlv = aim_createtlv();        
+  newtl->tlv->type = type;
+  newtl->tlv->length = 4;
+  newtl->tlv->value = (unsigned char *)malloc(newtl->tlv->length*sizeof(unsigned char));
+  aimutil_put32(newtl->tlv->value, val);
+
+  newtl->next = NULL;
+
+  if (*list == NULL) {
+    *list = newtl;
+  } else if ((*list)->next == NULL) {
+    (*list)->next = newtl;
+  } else {
+    for(cur = *list; cur->next; cur = cur->next)
+      ;
+    cur->next = newtl;
+  }
+  return 4;
+}
+
+/**
+ * aim_addtlvtochain_caps - Add a capability block to a TLV chain
+ * @list: Destination chain
+ * @type: TLV type to add
+ * @caps: Bitfield of capability flags to send
+ *
+ * Adds a block of capability blocks to a TLV chain. The bitfield
+ * passed in should be a bitwise %OR of any of the %AIM_CAPS constants:
+ *
+ *      %AIM_CAPS_BUDDYICON   Supports Buddy Icons
+ *
+ *      %AIM_CAPS_VOICE       Supports Voice Chat
+ *
+ *      %AIM_CAPS_IMIMAGE     Supports DirectIM/IMImage
+ *
+ *      %AIM_CAPS_CHAT        Supports Chat
+ *
+ *      %AIM_CAPS_GETFILE     Supports Get File functions
+ *
+ *      %AIM_CAPS_SENDFILE    Supports Send File functions
+ *
+ */
+faim_export int aim_addtlvtochain_caps(struct aim_tlvlist_t **list, unsigned short type, unsigned short caps)
+{
+  unsigned char buf[128]; /* icky fixed length buffer */
+  struct aim_tlvlist_t *newtl;
+  struct aim_tlvlist_t *cur;
+
+  if(!list)
+    return 0;
+
+  newtl = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
+  memset(newtl, 0x00, sizeof(struct aim_tlvlist_t));
+
+  newtl->tlv = aim_createtlv();        
+  newtl->tlv->type = type;
+
+  newtl->tlv->length = aim_putcap(buf, sizeof(buf), caps);
+  newtl->tlv->value = (unsigned char *)calloc(1, newtl->tlv->length);
+  memcpy(newtl->tlv->value, buf, newtl->tlv->length);
+
+  newtl->next = NULL;
+
+  if (*list == NULL) {
+    *list = newtl;
+  } else if ((*list)->next == NULL) {
+    (*list)->next = newtl;
+  } else {
+    for(cur = *list; cur->next; cur = cur->next)
+      ;
+    cur->next = newtl;
+  }
+  return newtl->tlv->length;
+}
+
+/**
+ * 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.
+ *
  */
-struct aim_tlv_t *aim_gettlv(struct aim_tlvlist_t *list, u_short type, int nth)
+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
+ * @list: Source TLV chain
+ *
+ * Copies a TLV chain into a raw data buffer, writing only the number
+ * of bytes specified. This operation does not free the chain; 
+ * aim_freetlvchain() must still be called to free up the memory used
+ * by the chain structures.
+ *
+ */
+faim_export int aim_writetlvchain(u_char *buf, int buflen, struct aim_tlvlist_t **list)
+{
+  int goodbuflen = 0;
+  int i = 0;
+  struct aim_tlvlist_t *cur;
+
+  if (!list || !buf || !buflen)
+    return 0;
+
+  /* do an initial run to test total length */
+  for (cur = *list; cur; cur = cur->next) {
+    goodbuflen += 2 + 2; /* type + len */
+    goodbuflen += cur->tlv->length;
+  }
+
+  if (goodbuflen > buflen)
+    return 0; /* not enough buffer */
+
+  /* do the real write-out */
+  for (cur = *list; cur; cur = cur->next) {
+    i += aimutil_put16(buf+i, cur->tlv->type);
+    i += aimutil_put16(buf+i, cur->tlv->length);
+    memcpy(buf+i, cur->tlv->value, cur->tlv->length);
+    i += cur->tlv->length;
+  }
+
+  return i;
+}
+
+
+/**
+ * aim_gettlv - Grab the Nth TLV of type type in the TLV list list.
+ * @list: Source chain
+ * @type: Requested TLV type
+ * @nth: Index of TLV of type to get
+ *
+ * Returns a pointer to an aim_tlv_t of the specified type; 
+ * %NULL on error.  The @nth parameter is specified starting at %1.
+ * In most cases, there will be no more than one TLV of any type
+ * in a chain.
+ *
+ */
+faim_export struct aim_tlv_t *aim_gettlv(struct aim_tlvlist_t *list, u_short type, int nth)
 {
   int i;
   struct aim_tlvlist_t *cur;
@@ -89,7 +431,18 @@ struct aim_tlv_t *aim_gettlv(struct aim_tlvlist_t *list, u_short type, int nth)
   return NULL;
 }
 
-char *aim_gettlv_str(struct aim_tlvlist_t *list, u_short type, int nth)
+/**
+ * aim_gettlv_str - Retrieve the Nth TLV in chain as a string.
+ * @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 %NULL-
+ * terminated string instead of an aim_tlv_t.  This is a 
+ * dynamic buffer and must be freed by the caller.
+ *
+ */
+faim_export char *aim_gettlv_str(struct aim_tlvlist_t *list, u_short type, int nth)
 {
   struct aim_tlv_t *tlv;
   char *newstr;
@@ -104,7 +457,76 @@ char *aim_gettlv_str(struct aim_tlvlist_t *list, u_short type, int nth)
   return newstr;
 }
 
-struct aim_tlv_t *aim_grabtlv(u_char *src)
+/**
+ * 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)
+ *
+ * Creates a TLV structure aim_tlv_t and returns it
+ * filled with values from a buffer, possibly including a 
+ * dynamically allocated buffer for the value portion.
+ *
+ * Both the aim_tlv_t and the tlv->value pointer
+ * must be freed by the caller if non-%NULL.
+ *
+ */
+faim_export struct aim_tlv_t *aim_grabtlv(u_char *src)
 {
   struct aim_tlv_t *dest = NULL;
 
@@ -124,7 +546,20 @@ struct aim_tlv_t *aim_grabtlv(u_char *src)
   return dest;
 }
 
-struct aim_tlv_t *aim_grabtlvstr(u_char *src)
+/**
+ * aim_grabtlvstr - Grab a single TLV from a data buffer as string
+ * @src: Source data buffer (must be at least 4 bytes long)
+ *
+ * Creates a TLV structure aim_tlv_t and returns it
+ * filled with values from a buffer, possibly including a 
+ * dynamically allocated buffer for the value portion, which 
+ * is %NULL-terminated as a string.
+ *
+ * Both the aim_tlv_t and the tlv->value pointer
+ * must be freed by the caller if non-%NULL.
+ *
+ */
+faim_export struct aim_tlv_t *aim_grabtlvstr(u_char *src)
 {
   struct aim_tlv_t *dest = NULL;
 
@@ -145,7 +580,19 @@ struct aim_tlv_t *aim_grabtlvstr(u_char *src)
   return dest;
 }
 
-int aim_puttlv (u_char *dest, struct aim_tlv_t *newtlv)
+/**
+ * aim_puttlv - Write a aim_tlv_t into a data buffer
+ * @dest: Destination data buffer
+ * @newtlv: Source TLV structure
+ *
+ * Writes out the passed TLV structure into the buffer. No bounds
+ * checking is done on the output buffer.
+ *
+ * The passed aim_tlv_t is not freed. aim_freetlv() should
+ * still be called by the caller to free the structure.
+ *
+ */
+faim_export int aim_puttlv(u_char *dest, struct aim_tlv_t *newtlv)
 {
   int i=0;
 
@@ -158,15 +605,31 @@ int aim_puttlv (u_char *dest, struct aim_tlv_t *newtlv)
   return i;
 }
 
-struct aim_tlv_t *aim_createtlv(void)
+/**
+ * aim_createtlv - Generate an aim_tlv_t structure.
+ * 
+ * Allocates an empty TLV structure and returns a pointer
+ * to it; %NULL on error.
+ *
+ */
+faim_export struct aim_tlv_t *aim_createtlv(void)
 {
-  struct aim_tlv_t *newtlv = NULL;
-  newtlv = (struct aim_tlv_t *)malloc(sizeof(struct aim_tlv_t));
+  struct aim_tlv_t *newtlv;
+
+  if (!(newtlv = (struct aim_tlv_t *)malloc(sizeof(struct aim_tlv_t))))
+    return NULL;
   memset(newtlv, 0, sizeof(struct aim_tlv_t));
   return newtlv;
 }
 
-int aim_freetlv(struct aim_tlv_t **oldtlv)
+/**
+ * aim_freetlv - Free a aim_tlv_t structure
+ * @oldtlv: TLV to be destroyed
+ *
+ * Frees both the TLV structure and the value portion.
+ *
+ */
+faim_export int aim_freetlv(struct aim_tlv_t **oldtlv)
 {
   if (!oldtlv)
     return -1;
@@ -180,7 +643,36 @@ int aim_freetlv(struct aim_tlv_t **oldtlv)
   return 0;
 }
 
-int aim_puttlv_16(u_char *buf, u_short t, u_short v)
+/**
+ * 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
+ * @v: Value
+ *
+ * Writes a TLV with a two-byte integer value portion.
+ *
+ */
+faim_export int aim_puttlv_16(u_char *buf, u_short t, u_short v)
 {
   int curbyte=0;
   curbyte += aimutil_put16(buf+curbyte, (u_short)(t&0xffff));
@@ -189,7 +681,16 @@ int aim_puttlv_16(u_char *buf, u_short t, u_short v)
   return curbyte;
 }
 
-int aim_puttlv_32(u_char *buf, u_short t, u_long v)
+/**
+ * aim_puttlv_32 - Write a four-byte TLV.
+ * @buf: Destination buffer
+ * @t: TLV type
+ * @v: Value
+ *
+ * Writes a TLV with a four-byte integer value portion.
+ *
+ */
+faim_export int aim_puttlv_32(u_char *buf, u_short t, u_long v)
 {
   int curbyte=0;
   curbyte += aimutil_put16(buf+curbyte, (u_short)(t&0xffff));
@@ -198,7 +699,19 @@ int aim_puttlv_32(u_char *buf, u_short t, u_long v)
   return curbyte;
 }
 
-int aim_puttlv_str(u_char *buf, u_short t, u_short l, u_char *v)
+/**
+ * aim_puttlv_str - Write a string TLV.
+ * @buf: Destination buffer
+ * @t: TLV type
+ * @l: Length of string
+ * @v: String to write
+ *
+ * Writes a TLV with a string value portion.  (Only the first @l
+ * bytes of the passed string will be written, which should not
+ * include the terminating NULL.)
+ *
+ */
+faim_export int aim_puttlv_str(u_char *buf, u_short t, int l, char *v)
 {
   int curbyte;
   
@@ -206,7 +719,7 @@ int aim_puttlv_str(u_char *buf, u_short t, u_short l, u_char *v)
   curbyte += aimutil_put16(buf+curbyte, (u_short)(t&0xffff));
   curbyte += aimutil_put16(buf+curbyte, (u_short)(l&0xffff));
   if (v)
-    memcpy(buf+curbyte, v, l);
+    memcpy(buf+curbyte, (unsigned char *)v, l);
   curbyte += l;
   return curbyte;
 }
This page took 0.058347 seconds and 4 git commands to generate.