6 * aim_readtlvchain - Read a TLV chain from a buffer.
8 * @maxlen: Length of input buffer
10 * Reads and parses a series of TLV patterns from a data buffer; the
11 * returned structure is manipulatable with the rest of the TLV
12 * routines. When done with a TLV chain, aim_freetlvchain() should
13 * be called to free the dynamic substructures.
16 faim_export struct aim_tlvlist_t *aim_readtlvchain(const unsigned char *buf, const int maxlen)
19 struct aim_tlvlist_t *list;
20 struct aim_tlvlist_t *cur;
22 unsigned short type, length;
33 type = aimutil_get16(buf+pos);
38 length = aimutil_get16(buf+pos);
41 if ((pos+length) <= maxlen)
44 * Okay, so now AOL has decided that any TLV of
45 * type 0x0013 can only be two bytes, despite
46 * what the actual given length is. So here
47 * we dump any invalid TLVs of that sort. Hopefully
48 * theres no special cases to this special case.
51 if ((type == 0x0013) && (length != 0x0002))
54 cur = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
55 memset(cur, 0x00, sizeof(struct aim_tlvlist_t));
57 cur->tlv = aim_createtlv();
58 cur->tlv->type = type;
59 cur->tlv->length = length;
61 cur->tlv->value = (unsigned char *)malloc(length);
62 memcpy(cur->tlv->value, buf+pos, length);
77 * aim_freetlvchain - Free a TLV chain structure
78 * @list: Chain to be freed
80 * Walks the list of TLVs in the passed TLV chain and
81 * frees each one. Note that any references to this data
82 * should be removed before calling this.
85 faim_export void aim_freetlvchain(struct aim_tlvlist_t **list)
87 struct aim_tlvlist_t *cur, *cur2;
89 if (!list || !(*list))
95 aim_freetlv(&cur->tlv);
105 * aim_counttlvchain - Count the number of TLVs in a chain
106 * @list: Chain to be counted
108 * Returns the number of TLVs stored in the passed chain.
111 faim_export int aim_counttlvchain(struct aim_tlvlist_t **list)
113 struct aim_tlvlist_t *cur;
116 if (!list || !(*list))
119 for (cur = *list; cur; cur = cur->next)
126 * aim_sizetlvchain - Count the number of bytes in a TLV chain
127 * @list: Chain to be sized
129 * Returns the number of bytes that would be needed to
130 * write the passed TLV chain to a data buffer.
133 faim_export int aim_sizetlvchain(struct aim_tlvlist_t **list)
135 struct aim_tlvlist_t *cur;
138 if (!list || !(*list))
141 for (cur = *list; cur; cur = cur->next)
142 size += (4 + cur->tlv->length);
148 * aim_addtlvtochain_str - Add a string to a TLV chain
149 * @list: Desination chain (%NULL pointer if empty)
151 * @str: String to add
152 * @len: Length of string to add (not including %NULL)
154 * Adds the passed string as a TLV element of the passed type
158 faim_export int aim_addtlvtochain_str(struct aim_tlvlist_t **list, const unsigned short type, const char *str, const int len)
160 struct aim_tlvlist_t *newtlv;
161 struct aim_tlvlist_t *cur;
166 newtlv = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
167 memset(newtlv, 0x00, sizeof(struct aim_tlvlist_t));
169 newtlv->tlv = aim_createtlv();
170 newtlv->tlv->type = type;
171 newtlv->tlv->length = len;
172 newtlv->tlv->value = (unsigned char *)malloc(newtlv->tlv->length*sizeof(unsigned char));
173 memcpy(newtlv->tlv->value, str, newtlv->tlv->length);
179 } else if ((*list)->next == NULL) {
180 (*list)->next = newtlv;
182 for(cur = *list; cur->next; cur = cur->next)
186 return newtlv->tlv->length;
190 * aim_addtlvtochain16 - Add a 16bit integer to a TLV chain
191 * @list: Destination chain
192 * @type: TLV type to add
195 * Adds a two-byte unsigned integer to a TLV chain.
198 faim_export int aim_addtlvtochain16(struct aim_tlvlist_t **list, const unsigned short type, const unsigned short val)
200 struct aim_tlvlist_t *newtl;
201 struct aim_tlvlist_t *cur;
206 newtl = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
207 memset(newtl, 0x00, sizeof(struct aim_tlvlist_t));
209 newtl->tlv = aim_createtlv();
210 newtl->tlv->type = type;
211 newtl->tlv->length = 2;
212 newtl->tlv->value = (unsigned char *)malloc(newtl->tlv->length*sizeof(unsigned char));
213 aimutil_put16(newtl->tlv->value, val);
219 } else if ((*list)->next == NULL) {
220 (*list)->next = newtl;
222 for(cur = *list; cur->next; cur = cur->next)
230 * aim_addtlvtochain32 - Add a 32bit integer to a TLV chain
231 * @list: Destination chain
232 * @type: TLV type to add
235 * Adds a four-byte unsigned integer to a TLV chain.
238 faim_export int aim_addtlvtochain32(struct aim_tlvlist_t **list, const unsigned short type, const unsigned long val)
240 struct aim_tlvlist_t *newtl;
241 struct aim_tlvlist_t *cur;
246 newtl = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
247 memset(newtl, 0x00, sizeof(struct aim_tlvlist_t));
249 newtl->tlv = aim_createtlv();
250 newtl->tlv->type = type;
251 newtl->tlv->length = 4;
252 newtl->tlv->value = (unsigned char *)malloc(newtl->tlv->length*sizeof(unsigned char));
253 aimutil_put32(newtl->tlv->value, val);
259 } else if ((*list)->next == NULL) {
260 (*list)->next = newtl;
262 for(cur = *list; cur->next; cur = cur->next)
270 * aim_addtlvtochain_caps - Add a capability block to a TLV chain
271 * @list: Destination chain
272 * @type: TLV type to add
273 * @caps: Bitfield of capability flags to send
275 * Adds a block of capability blocks to a TLV chain. The bitfield
276 * passed in should be a bitwise %OR of any of the %AIM_CAPS constants:
278 * %AIM_CAPS_BUDDYICON Supports Buddy Icons
280 * %AIM_CAPS_VOICE Supports Voice Chat
282 * %AIM_CAPS_IMIMAGE Supports DirectIM/IMImage
284 * %AIM_CAPS_CHAT Supports Chat
286 * %AIM_CAPS_GETFILE Supports Get File functions
288 * %AIM_CAPS_SENDFILE Supports Send File functions
291 faim_export int aim_addtlvtochain_caps(struct aim_tlvlist_t **list, const unsigned short type, const unsigned short caps)
293 unsigned char buf[128]; /* icky fixed length buffer */
294 struct aim_tlvlist_t *newtl;
295 struct aim_tlvlist_t *cur;
300 newtl = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
301 memset(newtl, 0x00, sizeof(struct aim_tlvlist_t));
303 newtl->tlv = aim_createtlv();
304 newtl->tlv->type = type;
306 newtl->tlv->length = aim_putcap(buf, sizeof(buf), caps);
307 newtl->tlv->value = (unsigned char *)calloc(1, newtl->tlv->length);
308 memcpy(newtl->tlv->value, buf, newtl->tlv->length);
314 } else if ((*list)->next == NULL) {
315 (*list)->next = newtl;
317 for(cur = *list; cur->next; cur = cur->next)
321 return newtl->tlv->length;
325 * aim_addtlvtochain_noval - Add a blank TLV to a TLV chain
326 * @list: Destination chain
327 * @type: TLV type to add
329 * Adds a TLV with a zero length to a TLV chain.
332 faim_internal int aim_addtlvtochain_noval(struct aim_tlvlist_t **list, const unsigned short type)
334 struct aim_tlvlist_t *newtlv;
335 struct aim_tlvlist_t *cur;
337 newtlv = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
338 memset(newtlv, 0x00, sizeof(struct aim_tlvlist_t));
340 newtlv->tlv = aim_createtlv();
341 newtlv->tlv->type = type;
342 newtlv->tlv->length = 0;
343 newtlv->tlv->value = NULL;
349 } else if ((*list)->next == NULL) {
350 (*list)->next = newtlv;
352 for(cur = *list; cur->next; cur = cur->next)
356 return newtlv->tlv->length;
360 * aim_writetlvchain - Write a TLV chain into a data buffer.
361 * @buf: Destination buffer
362 * @buflen: Maximum number of bytes that will be written to buffer
363 * @list: Source TLV chain
365 * Copies a TLV chain into a raw data buffer, writing only the number
366 * of bytes specified. This operation does not free the chain;
367 * aim_freetlvchain() must still be called to free up the memory used
368 * by the chain structures.
371 faim_export int aim_writetlvchain(unsigned char *buf, int buflen, struct aim_tlvlist_t **list)
375 struct aim_tlvlist_t *cur;
377 if (!list || !buf || !buflen)
380 /* do an initial run to test total length */
381 for (cur = *list; cur; cur = cur->next) {
382 goodbuflen += 2 + 2; /* type + len */
383 goodbuflen += cur->tlv->length;
386 if (goodbuflen > buflen)
387 return 0; /* not enough buffer */
389 /* do the real write-out */
390 for (cur = *list; cur; cur = cur->next) {
391 i += aimutil_put16(buf+i, cur->tlv->type);
392 i += aimutil_put16(buf+i, cur->tlv->length);
393 memcpy(buf+i, cur->tlv->value, cur->tlv->length);
394 i += cur->tlv->length;
402 * aim_gettlv - Grab the Nth TLV of type type in the TLV list list.
403 * @list: Source chain
404 * @type: Requested TLV type
405 * @nth: Index of TLV of type to get
407 * Returns a pointer to an aim_tlv_t of the specified type;
408 * %NULL on error. The @nth parameter is specified starting at %1.
409 * In most cases, there will be no more than one TLV of any type
413 faim_export struct aim_tlv_t *aim_gettlv(struct aim_tlvlist_t *list, const unsigned short type, const int nth)
416 struct aim_tlvlist_t *cur;
419 for (cur = list; cur != NULL; cur = cur->next)
423 if (cur->tlv->type == type)
433 * aim_gettlv_str - Retrieve the Nth TLV in chain as a string.
434 * @list: Source TLV chain
435 * @type: TLV type to search for
436 * @nth: Index of TLV to return
438 * Same as aim_gettlv(), except that the return value is a %NULL-
439 * terminated string instead of an aim_tlv_t. This is a
440 * dynamic buffer and must be freed by the caller.
443 faim_export char *aim_gettlv_str(struct aim_tlvlist_t *list, const unsigned short type, const int nth)
445 struct aim_tlv_t *tlv;
448 if (!(tlv = aim_gettlv(list, type, nth)))
451 newstr = (char *) malloc(tlv->length + 1);
452 memcpy(newstr, tlv->value, tlv->length);
453 *(newstr + tlv->length) = '\0';
459 * aim_gettlv8 - Retrieve the Nth TLV in chain as a 8bit integer.
460 * @list: Source TLV chain
461 * @type: TLV type to search for
462 * @nth: Index of TLV to return
464 * Same as aim_gettlv(), except that the return value is a
465 * 8bit integer instead of an aim_tlv_t.
468 faim_internal unsigned char aim_gettlv8(struct aim_tlvlist_t *list, const unsigned short type, const int num)
470 struct aim_tlv_t *tlv;
472 if (!(tlv = aim_gettlv(list, type, num)) || !tlv->value)
474 return aimutil_get8(tlv->value);
478 * aim_gettlv16 - Retrieve the Nth TLV in chain as a 16bit integer.
479 * @list: Source TLV chain
480 * @type: TLV type to search for
481 * @nth: Index of TLV to return
483 * Same as aim_gettlv(), except that the return value is a
484 * 16bit integer instead of an aim_tlv_t.
487 faim_internal unsigned short aim_gettlv16(struct aim_tlvlist_t *list, const unsigned short type, const int num)
489 struct aim_tlv_t *tlv;
491 if (!(tlv = aim_gettlv(list, type, num)) || !tlv->value)
493 return aimutil_get16(tlv->value);
497 * aim_gettlv32 - Retrieve the Nth TLV in chain as a 32bit integer.
498 * @list: Source TLV chain
499 * @type: TLV type to search for
500 * @nth: Index of TLV to return
502 * Same as aim_gettlv(), except that the return value is a
503 * 32bit integer instead of an aim_tlv_t.
506 faim_internal unsigned long aim_gettlv32(struct aim_tlvlist_t *list, const unsigned short type, const int num)
508 struct aim_tlv_t *tlv;
510 if (!(tlv = aim_gettlv(list, type, num)) || !tlv->value)
512 return aimutil_get32(tlv->value);
516 * aim_grabtlv - Grab a single TLV from a data buffer
517 * @src: Source data buffer (must be at least 4 bytes long)
519 * Creates a TLV structure aim_tlv_t and returns it
520 * filled with values from a buffer, possibly including a
521 * dynamically allocated buffer for the value portion.
523 * Both the aim_tlv_t and the tlv->value pointer
524 * must be freed by the caller if non-%NULL.
527 faim_export struct aim_tlv_t *aim_grabtlv(const unsigned char *src)
529 struct aim_tlv_t *dest = NULL;
531 dest = aim_createtlv();
533 dest->type = src[0] << 8;
534 dest->type += src[1];
536 dest->length = src[2] << 8;
537 dest->length += src[3];
539 dest->value = (unsigned char *) malloc(dest->length);
540 memset(dest->value, 0, dest->length);
542 memcpy(dest->value, &(src[4]), dest->length);
548 * aim_grabtlvstr - Grab a single TLV from a data buffer as string
549 * @src: Source data buffer (must be at least 4 bytes long)
551 * Creates a TLV structure aim_tlv_t and returns it
552 * filled with values from a buffer, possibly including a
553 * dynamically allocated buffer for the value portion, which
554 * is %NULL-terminated as a string.
556 * Both the aim_tlv_t and the tlv->value pointer
557 * must be freed by the caller if non-%NULL.
560 faim_export struct aim_tlv_t *aim_grabtlvstr(const unsigned char *src)
562 struct aim_tlv_t *dest = NULL;
564 dest = aim_createtlv();
566 dest->type = src[0] << 8;
567 dest->type += src[1];
569 dest->length = src[2] << 8;
570 dest->length += src[3];
572 dest->value = (unsigned char *) malloc(dest->length+1);
573 memset(dest->value, 0, dest->length+1);
575 memcpy(dest->value, src+4, dest->length);
576 dest->value[dest->length] = '\0';
582 * aim_puttlv - Write a aim_tlv_t into a data buffer
583 * @dest: Destination data buffer
584 * @newtlv: Source TLV structure
586 * Writes out the passed TLV structure into the buffer. No bounds
587 * checking is done on the output buffer.
589 * The passed aim_tlv_t is not freed. aim_freetlv() should
590 * still be called by the caller to free the structure.
593 faim_export int aim_puttlv(unsigned char *dest, struct aim_tlv_t *newtlv)
597 dest[i++] = newtlv->type >> 8;
598 dest[i++] = newtlv->type & 0x00FF;
599 dest[i++] = newtlv->length >> 8;
600 dest[i++] = newtlv->length & 0x00FF;
601 memcpy(&(dest[i]), newtlv->value, newtlv->length);
607 * aim_createtlv - Generate an aim_tlv_t structure.
609 * Allocates an empty TLV structure and returns a pointer
610 * to it; %NULL on error.
613 faim_export struct aim_tlv_t *aim_createtlv(void)
615 struct aim_tlv_t *newtlv;
617 if (!(newtlv = (struct aim_tlv_t *)malloc(sizeof(struct aim_tlv_t))))
619 memset(newtlv, 0, sizeof(struct aim_tlv_t));
624 * aim_freetlv - Free a aim_tlv_t structure
625 * @oldtlv: TLV to be destroyed
627 * Frees both the TLV structure and the value portion.
630 faim_export int aim_freetlv(struct aim_tlv_t **oldtlv)
636 if ((*oldtlv)->value)
637 free((*oldtlv)->value);
645 * aim_puttlv_8 - Write a one-byte TLV.
646 * @buf: Destination buffer
650 * Writes a TLV with a one-byte integer value portion.
653 faim_export int aim_puttlv_8(unsigned char *buf, const unsigned short t, const unsigned char v)
657 curbyte += aimutil_put16(buf+curbyte, (unsigned short)(t&0xffff));
658 curbyte += aimutil_put16(buf+curbyte, (unsigned short)0x0001);
659 curbyte += aimutil_put8(buf+curbyte, (unsigned char)(v&0xff));
665 * aim_puttlv_16 - Write a two-byte TLV.
666 * @buf: Destination buffer
670 * Writes a TLV with a two-byte integer value portion.
673 faim_export int aim_puttlv_16(unsigned char *buf, const unsigned short t, const unsigned short v)
676 curbyte += aimutil_put16(buf+curbyte, (unsigned short)(t&0xffff));
677 curbyte += aimutil_put16(buf+curbyte, (unsigned short)0x0002);
678 curbyte += aimutil_put16(buf+curbyte, (unsigned short)(v&0xffff));
683 * aim_puttlv_32 - Write a four-byte TLV.
684 * @buf: Destination buffer
688 * Writes a TLV with a four-byte integer value portion.
691 faim_export int aim_puttlv_32(unsigned char *buf, const unsigned short t, const unsigned long v)
694 curbyte += aimutil_put16(buf+curbyte, (unsigned short)(t&0xffff));
695 curbyte += aimutil_put16(buf+curbyte, (unsigned short)0x0004);
696 curbyte += aimutil_put32(buf+curbyte, (unsigned long)(v&0xffffffff));
701 * aim_puttlv_str - Write a string TLV.
702 * @buf: Destination buffer
704 * @l: Length of string
705 * @v: String to write
707 * Writes a TLV with a string value portion. (Only the first @l
708 * bytes of the passed string will be written, which should not
709 * include the terminating NULL.)
712 faim_export int aim_puttlv_str(unsigned char *buf, const unsigned short t, const int l, const char *v)
717 curbyte += aimutil_put16(buf+curbyte, (unsigned short)(t&0xffff));
718 curbyte += aimutil_put16(buf+curbyte, (unsigned short)(l&0xffff));
720 memcpy(buf+curbyte, (unsigned char *)v, l);