view libfaim/aim_tlv.c @ 312:3069be4c291e

[gaim-migrate @ 322] I don't know why I did this. I have homework due in 15 hours that I haven't started yet, and it's in a language I don't know and it's a project I don't understand. If my teacher knew about this, he would be pissed. He looks pissed all the time, even when he's not. When he smiles he looks devilish. Maybe I only think that because literally half the class flunked the midterm. I am not joking about that. More people got F's than A, B, and C combined. It's 2 am and the homework's due at 5 tomorrow so what do I do? Get chat to work. Wow. That's going to look good on my resume. "Why did you flunk this class?" "Because I was getting chat in Instant Messenger to work." Not that that's not something to be proud of, but I wonder which is more important to employers. The big battle, experience versus education. Just because you got good grades in college doesn't mean you're smarter than someone who flunked, it just means you put in the effort necessary to get a better grade and the other person didn't. Maybe the person who flunked was working on real honest-to-god actually *used* software, as opposed to some stupid tree that only gets used for a fringe branch of computer science that doesn't offer much more than a normal heap or binary search tree offers. Maybe the person was out there reverse-engineering protocols and allowing cross- platform communication to occur, creating interoperability and causing a greater demand not only for the product, but for the platform it runs on! Given the choices, who would you pick? Someone who was told how to code a tree and managed to get it to work, or someone who increases your userbase and marketability? Enough of my rant for a while. I've had waaaaay too much sugar (gummy candy is deadly). committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Fri, 02 Jun 2000 09:11:48 +0000
parents 0f14e6d8a51b
children 6d78b988b479
line wrap: on
line source

#include <faim/aim.h>

struct aim_tlvlist_t *aim_readtlvchain(u_char *buf, int maxlen)
{
  int pos;
  struct aim_tlvlist_t *list;
  struct aim_tlvlist_t *cur;
  
  u_short type;
  u_short length;

  if (!buf)
    return NULL;

  list = NULL;
  
  pos = 0;

  while (pos < maxlen)
    {
      type = aimutil_get16(buf+pos);
      pos += 2;

      if (pos < maxlen)
	{
	  length = aimutil_get16(buf+pos);
	  pos += 2;
	  
	  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;
	      
	      pos += length;
	    }
	}
    }

  return list;
}

void aim_freetlvchain(struct aim_tlvlist_t **list)
{
  struct aim_tlvlist_t *cur, *cur2;

  if (!list || !(*list))
    return;

  cur = *list;
  while (cur)
    {
      aim_freetlv(&cur->tlv);
      cur2 = cur->next;
      free(cur);
      cur = cur2;
    }
  list = NULL;
  return;
}

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;
}

int aim_addtlvtochain_str(struct aim_tlvlist_t **list, unsigned short type, char *str, int len)
{
  struct aim_tlvlist_t *new;
  struct aim_tlvlist_t *cur;

  if (!list)
    return 0;

  new = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
  memset(new, 0x00, sizeof(struct aim_tlvlist_t));

  new->tlv = aim_createtlv();	
  new->tlv->type = type;
  new->tlv->length = len;
  new->tlv->value = (u_char *)malloc(new->tlv->length*sizeof(u_char));
  memcpy(new->tlv->value, str, new->tlv->length);

  new->next = NULL;

  if (*list == NULL) {
    *list = new;
  } else if ((*list)->next == NULL) {
    (*list)->next = new;
  } else {
    for(cur = *list; cur->next; cur = cur->next)
      ;
    cur->next = new;
  }
  return new->tlv->length;
}

int aim_addtlvtochain16(struct aim_tlvlist_t **list, unsigned short type, unsigned short val)
{
  struct aim_tlvlist_t *new;
  struct aim_tlvlist_t *cur;

  if (!list)
    return 0;

  new = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
  memset(new, 0x00, sizeof(struct aim_tlvlist_t));

  new->tlv = aim_createtlv();	
  new->tlv->type = type;
  new->tlv->length = 2;
  new->tlv->value = (u_char *)malloc(new->tlv->length*sizeof(u_char));
  aimutil_put16(new->tlv->value, val);

  new->next = NULL;

  if (*list == NULL) {
    *list = new;
  } else if ((*list)->next == NULL) {
    (*list)->next = new;
  } else {
    for(cur = *list; cur->next; cur = cur->next)
      ;
    cur->next = new;
  }
  return 2;
}

int aim_addtlvtochain32(struct aim_tlvlist_t **list, unsigned short type, unsigned long val)
{
  struct aim_tlvlist_t *new;
  struct aim_tlvlist_t *cur;

  if (!list)
    return 0;

  new = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
  memset(new, 0x00, sizeof(struct aim_tlvlist_t));

  new->tlv = aim_createtlv();	
  new->tlv->type = type;
  new->tlv->length = 4;
  new->tlv->value = (u_char *)malloc(new->tlv->length*sizeof(u_char));
  aimutil_put32(new->tlv->value, val);

  new->next = NULL;

  if (*list == NULL) {
    *list = new;
  } else if ((*list)->next == NULL) {
    (*list)->next = new;
  } else {
    for(cur = *list; cur->next; cur = cur->next)
      ;
    cur->next = new;
  }
  return 4;
}

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;
}


/*
 * Grab the Nth TLV of type type in the TLV list list.
 */
struct aim_tlv_t *aim_gettlv(struct aim_tlvlist_t *list, u_short type, int nth)
{
  int i;
  struct aim_tlvlist_t *cur;
  
  i = 0;
  for (cur = list; cur != NULL; cur = cur->next)
    {
      if (cur && cur->tlv)
	{
	  if (cur->tlv->type == type)
	    i++;
	  if (i >= nth)
	    return cur->tlv;
	}
    }
  return NULL;
}

char *aim_gettlv_str(struct aim_tlvlist_t *list, u_short type, int nth)
{
  struct aim_tlv_t *tlv;
  char *newstr;

  if (!(tlv = aim_gettlv(list, type, nth)))
    return NULL;
  
  newstr = (char *) malloc(tlv->length + 1);
  memcpy(newstr, tlv->value, tlv->length);
  *(newstr + tlv->length) = '\0';

  return newstr;
}

struct aim_tlv_t *aim_grabtlv(u_char *src)
{
  struct aim_tlv_t *dest = NULL;

  dest = aim_createtlv();

  dest->type = src[0] << 8;
  dest->type += src[1];

  dest->length = src[2] << 8;
  dest->length += src[3];

  dest->value = (u_char *) malloc(dest->length*sizeof(u_char));
  memset(dest->value, 0, dest->length*sizeof(u_char));

  memcpy(dest->value, &(src[4]), dest->length*sizeof(u_char));
  
  return dest;
}

struct aim_tlv_t *aim_grabtlvstr(u_char *src)
{
  struct aim_tlv_t *dest = NULL;

  dest = aim_createtlv();

  dest->type = src[0] << 8;
  dest->type += src[1];

  dest->length = src[2] << 8;
  dest->length += src[3];

  dest->value = (u_char *) malloc((dest->length+1)*sizeof(u_char));
  memset(dest->value, 0, (dest->length+1)*sizeof(u_char));

  memcpy(dest->value, &(src[4]), dest->length*sizeof(u_char));
  dest->value[dest->length] = '\0';

  return dest;
}

int aim_puttlv (u_char *dest, struct aim_tlv_t *newtlv)
{
  int i=0;

  dest[i++] = newtlv->type >> 8;
  dest[i++] = newtlv->type & 0x00FF;
  dest[i++] = newtlv->length >> 8;
  dest[i++] = newtlv->length & 0x00FF;
  memcpy(&(dest[i]), newtlv->value, newtlv->length);
  i+=newtlv->length;
  return i;
}

struct aim_tlv_t *aim_createtlv(void)
{
  struct aim_tlv_t *newtlv = NULL;
  newtlv = (struct aim_tlv_t *)malloc(sizeof(struct aim_tlv_t));
  memset(newtlv, 0, sizeof(struct aim_tlv_t));
  return newtlv;
}

int aim_freetlv(struct aim_tlv_t **oldtlv)
{
  if (!oldtlv)
    return -1;
  if (!*oldtlv)
    return -1;
  if ((*oldtlv)->value)
    free((*oldtlv)->value);
  free(*(oldtlv));
  (*oldtlv) = NULL;

  return 0;
}

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));
  curbyte += aimutil_put16(buf+curbyte, (u_short)0x0002);
  curbyte += aimutil_put16(buf+curbyte, (u_short)(v&0xffff));
  return curbyte;
}

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));
  curbyte += aimutil_put16(buf+curbyte, (u_short)0x0004);
  curbyte += aimutil_put32(buf+curbyte, (u_long)(v&0xffffffff));
  return curbyte;
}

int aim_puttlv_str(u_char *buf, u_short t, u_short l, u_char *v)
{
  int curbyte;
  
  curbyte  = 0;
  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);
  curbyte += l;
  return curbyte;
}