source: libfaim/tlv.c @ 3baf77f

barnowl_perlaimdebianowlrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 3baf77f was cf02dd6, checked in by James M. Kretchmar <kretch@mit.edu>, 20 years ago
*** empty log message ***
  • Property mode set to 100644
File size: 20.2 KB
Line 
1
2#define FAIM_INTERNAL
3#include <aim.h>
4
5static aim_tlv_t *createtlv(fu16_t type, fu16_t length, fu8_t *value)
6{
7        aim_tlv_t *ret;
8
9        if (!(ret = (aim_tlv_t *)malloc(sizeof(aim_tlv_t))))
10                return NULL;
11        ret->type = type;
12        ret->length = length;
13        ret->value = value;
14
15        return ret;
16}
17
18static void freetlv(aim_tlv_t **oldtlv)
19{
20
21        if (!oldtlv || !*oldtlv)
22                return;
23       
24        free((*oldtlv)->value);
25        free(*oldtlv);
26        *oldtlv = NULL;
27
28        return;
29}
30
31/**
32 * Read a TLV chain from a buffer.
33 *
34 * Reads and parses a series of TLV patterns from a data buffer; the
35 * returned structure is manipulatable with the rest of the TLV
36 * routines.  When done with a TLV chain, aim_tlvlist_free() should
37 * be called to free the dynamic substructures.
38 *
39 * XXX There should be a flag setable here to have the tlvlist contain
40 * bstream references, so that at least the ->value portion of each
41 * element doesn't need to be malloc/memcpy'd.  This could prove to be
42 * just as effecient as the in-place TLV parsing used in a couple places
43 * in libfaim.
44 *
45 * @param bs Input bstream
46 */
47faim_internal aim_tlvlist_t *aim_tlvlist_read(aim_bstream_t *bs)
48{
49        aim_tlvlist_t *list = NULL, *cur;
50       
51        while (aim_bstream_empty(bs) > 0) {
52                fu16_t type, length;
53
54                type = aimbs_get16(bs);
55                length = aimbs_get16(bs);
56
57#if 0 /* temporarily disabled until I know if they're still doing it or not */
58                /*
59                 * Okay, so now AOL has decided that any TLV of
60                 * type 0x0013 can only be two bytes, despite
61                 * what the actual given length is.  So here
62                 * we dump any invalid TLVs of that sort.  Hopefully
63                 * theres no special cases to this special case.
64                 *   - mid (30jun2000)
65                 */
66                if ((type == 0x0013) && (length != 0x0002))
67                        length = 0x0002;
68#else
69                if (0)
70                        ;
71#endif
72                else {
73
74                        if (length > aim_bstream_empty(bs)) {
75                                aim_tlvlist_free(&list);
76                                return NULL;
77                        }
78
79                        cur = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t));
80                        if (!cur) {
81                                aim_tlvlist_free(&list);
82                                return NULL;
83                        }
84
85                        memset(cur, 0, sizeof(aim_tlvlist_t));
86
87                        cur->tlv = createtlv(type, length, NULL);
88                        if (!cur->tlv) {
89                                free(cur);
90                                aim_tlvlist_free(&list);
91                                return NULL;
92                        }
93                        if (cur->tlv->length > 0) {
94                                cur->tlv->value = aimbs_getraw(bs, length);     
95                                if (!cur->tlv->value) {
96                                        freetlv(&cur->tlv);
97                                        free(cur);
98                                        aim_tlvlist_free(&list);
99                                        return NULL;
100                                }
101                        }
102
103                        cur->next = list;
104                        list = cur;
105                }
106        }
107
108        return list;
109}
110
111/**
112 * Read a TLV chain from a buffer.
113 *
114 * Reads and parses a series of TLV patterns from a data buffer; the
115 * returned structure is manipulatable with the rest of the TLV
116 * routines.  When done with a TLV chain, aim_tlvlist_free() should
117 * be called to free the dynamic substructures.
118 *
119 * XXX There should be a flag setable here to have the tlvlist contain
120 * bstream references, so that at least the ->value portion of each
121 * element doesn't need to be malloc/memcpy'd.  This could prove to be
122 * just as effecient as the in-place TLV parsing used in a couple places
123 * in libfaim.
124 *
125 * @param bs Input bstream
126 * @param num The max number of TLVs that will be read, or -1 if unlimited. 
127 *        There are a number of places where you want to read in a tlvchain,
128 *        but the chain is not at the end of the SNAC, and the chain is
129 *        preceeded by the number of TLVs.  So you can limit that with this.
130 */
131faim_internal aim_tlvlist_t *aim_tlvlist_readnum(aim_bstream_t *bs, fu16_t num)
132{
133        aim_tlvlist_t *list = NULL, *cur;
134
135        while ((aim_bstream_empty(bs) > 0) && (num != 0)) {
136                fu16_t type, length;
137
138                type = aimbs_get16(bs);
139                length = aimbs_get16(bs);
140
141                if (length > aim_bstream_empty(bs)) {
142                        aim_tlvlist_free(&list);
143                        return NULL;
144                }
145
146                cur = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t));
147                if (!cur) {
148                        aim_tlvlist_free(&list);
149                        return NULL;
150                }
151
152                memset(cur, 0, sizeof(aim_tlvlist_t));
153
154                cur->tlv = createtlv(type, length, NULL);
155                if (!cur->tlv) {
156                        free(cur);
157                        aim_tlvlist_free(&list);
158                        return NULL;
159                }
160                if (cur->tlv->length > 0) {
161                        cur->tlv->value = aimbs_getraw(bs, length);
162                        if (!cur->tlv->value) {
163                                freetlv(&cur->tlv);
164                                free(cur);
165                                aim_tlvlist_free(&list);
166                                return NULL;
167                        }
168                }
169
170                if (num > 0)
171                        num--;
172                cur->next = list;
173                list = cur;
174        }
175
176        return list;
177}
178
179/**
180 * Read a TLV chain from a buffer.
181 *
182 * Reads and parses a series of TLV patterns from a data buffer; the
183 * returned structure is manipulatable with the rest of the TLV
184 * routines.  When done with a TLV chain, aim_tlvlist_free() should
185 * be called to free the dynamic substructures.
186 *
187 * XXX There should be a flag setable here to have the tlvlist contain
188 * bstream references, so that at least the ->value portion of each
189 * element doesn't need to be malloc/memcpy'd.  This could prove to be
190 * just as effecient as the in-place TLV parsing used in a couple places
191 * in libfaim.
192 *
193 * @param bs Input bstream
194 * @param len The max length in bytes that will be read.
195 *        There are a number of places where you want to read in a tlvchain,
196 *        but the chain is not at the end of the SNAC, and the chain is
197 *        preceeded by the length of the TLVs.  So you can limit that with this.
198 */
199faim_internal aim_tlvlist_t *aim_tlvlist_readlen(aim_bstream_t *bs, fu16_t len)
200{
201        aim_tlvlist_t *list = NULL, *cur;
202
203        while ((aim_bstream_empty(bs) > 0) && (len > 0)) {
204                fu16_t type, length;
205
206                type = aimbs_get16(bs);
207                length = aimbs_get16(bs);
208
209                if (length > aim_bstream_empty(bs)) {
210                        aim_tlvlist_free(&list);
211                        return NULL;
212                }
213
214                cur = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t));
215                if (!cur) {
216                        aim_tlvlist_free(&list);
217                        return NULL;
218                }
219
220                memset(cur, 0, sizeof(aim_tlvlist_t));
221
222                cur->tlv = createtlv(type, length, NULL);
223                if (!cur->tlv) {
224                        free(cur);
225                        aim_tlvlist_free(&list);
226                        return NULL;
227                }
228                if (cur->tlv->length > 0) {
229                        cur->tlv->value = aimbs_getraw(bs, length);
230                        if (!cur->tlv->value) {
231                                freetlv(&cur->tlv);
232                                free(cur);
233                                aim_tlvlist_free(&list);
234                                return NULL;
235                        }
236                }
237
238                len -= aim_tlvlist_size(&cur);
239                cur->next = list;
240                list = cur;
241        }
242
243        return list;
244}
245
246/**
247 * Duplicate a TLV chain.
248 * This is pretty pelf exslanatory.
249 *
250 * @param orig The TLV chain you want to make a copy of.
251 * @return A newly allocated TLV chain.
252 */
253faim_internal aim_tlvlist_t *aim_tlvlist_copy(aim_tlvlist_t *orig)
254{
255        aim_tlvlist_t *new = NULL;
256
257        while (orig) {
258                aim_tlvlist_add_raw(&new, orig->tlv->type, orig->tlv->length, orig->tlv->value);
259                orig = orig->next;
260        }
261
262        return new;
263}
264
265/*
266 * Compare two TLV lists for equality.  This probably is not the most
267 * efficient way to do this.
268 *
269 * @param one One of the TLV chains to compare.
270 * @param two The other TLV chain to compare.
271 * @preturn Retrun 0 if the lists are the same, return 1 if they are different.
272 */
273faim_internal int aim_tlvlist_cmp(aim_tlvlist_t *one, aim_tlvlist_t *two)
274{
275        aim_bstream_t bs1, bs2;
276
277        if (aim_tlvlist_size(&one) != aim_tlvlist_size(&two))
278                return 1;
279
280        aim_bstream_init(&bs1, ((fu8_t *)malloc(aim_tlvlist_size(&one)*sizeof(fu8_t))), aim_tlvlist_size(&one));
281        aim_bstream_init(&bs2, ((fu8_t *)malloc(aim_tlvlist_size(&two)*sizeof(fu8_t))), aim_tlvlist_size(&two));
282
283        aim_tlvlist_write(&bs1, &one);
284        aim_tlvlist_write(&bs2, &two);
285
286        if (memcmp(bs1.data, bs2.data, bs1.len)) {
287                free(bs1.data);
288                free(bs2.data);
289                return 1;
290        }
291
292        free(bs1.data);
293        free(bs2.data);
294
295        return 0;
296}
297
298/**
299 * Free a TLV chain structure
300 * @list: Chain to be freed
301 *
302 * Walks the list of TLVs in the passed TLV chain and
303 * frees each one. Note that any references to this data
304 * should be removed before calling this.
305 *
306 */
307faim_internal void aim_tlvlist_free(aim_tlvlist_t **list)
308{
309        aim_tlvlist_t *cur;
310
311        if (!list || !*list)
312                return;
313
314        for (cur = *list; cur; ) {
315                aim_tlvlist_t *tmp;
316               
317                freetlv(&cur->tlv);
318
319                tmp = cur->next;
320                free(cur);
321                cur = tmp;
322        }
323
324        list = NULL;
325
326        return;
327}
328
329/**
330 * Count the number of TLVs in a chain.
331 *
332 * @param list Chain to be counted.
333 * @return The number of TLVs stored in the passed chain.
334 */
335faim_internal int aim_tlvlist_count(aim_tlvlist_t **list)
336{
337        aim_tlvlist_t *cur;
338        int count;
339
340        if (!list || !*list)
341                return 0;
342
343        for (cur = *list, count = 0; cur; cur = cur->next)
344                count++;
345
346        return count;
347}
348
349/**
350 * Count the number of bytes in a TLV chain.
351 *
352 * @param list Chain to be sized
353 * @return The number of bytes that would be needed to
354 *         write the passed TLV chain to a data buffer.
355 */
356faim_internal int aim_tlvlist_size(aim_tlvlist_t **list)
357{
358        aim_tlvlist_t *cur;
359        int size;
360
361        if (!list || !*list)
362                return 0;
363
364        for (cur = *list, size = 0; cur; cur = cur->next)
365                size += (4 + cur->tlv->length);
366
367        return size;
368}
369
370/**
371 * Adds the passed string as a TLV element of the passed type
372 * to the TLV chain.
373 *
374 * @param list Desination chain (%NULL pointer if empty).
375 * @param type TLV type.
376 * @length Length of string to add (not including %NULL).
377 * @value String to add.
378 * @retun The size of the value added.
379 */
380faim_internal int aim_tlvlist_add_raw(aim_tlvlist_t **list, const fu16_t type, const fu16_t length, const fu8_t *value)
381{
382        aim_tlvlist_t *newtlv, *cur;
383
384        if (list == NULL)
385                return 0;
386
387        if (!(newtlv = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t))))
388                return 0;
389        memset(newtlv, 0x00, sizeof(aim_tlvlist_t));
390
391        if (!(newtlv->tlv = createtlv(type, length, NULL))) {
392                free(newtlv);
393                return 0;
394        }
395        if (newtlv->tlv->length > 0) {
396                newtlv->tlv->value = (fu8_t *)malloc(newtlv->tlv->length);
397                memcpy(newtlv->tlv->value, value, newtlv->tlv->length);
398        }
399
400        if (!*list)
401                *list = newtlv;
402        else {
403                for(cur = *list; cur->next; cur = cur->next)
404                        ;
405                cur->next = newtlv;
406        }
407
408        return newtlv->tlv->length;
409}
410
411/**
412 * Add a one byte integer to a TLV chain.
413 *
414 * @param list Destination chain.
415 * @param type TLV type to add.
416 * @param value Value to add.
417 * @retun The size of the value added.
418 */
419faim_internal int aim_tlvlist_add_8(aim_tlvlist_t **list, const fu16_t type, const fu8_t value)
420{
421        fu8_t v8[1];
422
423        aimutil_put8(v8, value);
424
425        return aim_tlvlist_add_raw(list, type, 1, v8);
426}
427
428/**
429 * Add a two byte integer to a TLV chain.
430 *
431 * @param list Destination chain.
432 * @param type TLV type to add.
433 * @param value Value to add.
434 * @retun The size of the value added.
435 */
436faim_internal int aim_tlvlist_add_16(aim_tlvlist_t **list, const fu16_t type, const fu16_t value)
437{
438        fu8_t v16[2];
439
440        aimutil_put16(v16, value);
441
442        return aim_tlvlist_add_raw(list, type, 2, v16);
443}
444
445/**
446 * Add a four byte integer to a TLV chain.
447 *
448 * @param list Destination chain.
449 * @param type TLV type to add.
450 * @param value Value to add.
451 * @retun The size of the value added.
452 */
453faim_internal int aim_tlvlist_add_32(aim_tlvlist_t **list, const fu16_t type, const fu32_t value)
454{
455        fu8_t v32[4];
456
457        aimutil_put32(v32, value);
458
459        return aim_tlvlist_add_raw(list, type, 4, v32);
460}
461
462/**
463 * Adds a block of capability blocks to a TLV chain. The bitfield
464 * passed in should be a bitwise %OR of any of the %AIM_CAPS constants:
465 *
466 *     %AIM_CAPS_BUDDYICON   Supports Buddy Icons
467 *     %AIM_CAPS_VOICE       Supports Voice Chat
468 *     %AIM_CAPS_IMIMAGE     Supports DirectIM/IMImage
469 *     %AIM_CAPS_CHAT        Supports Chat
470 *     %AIM_CAPS_GETFILE     Supports Get File functions
471 *     %AIM_CAPS_SENDFILE    Supports Send File functions
472 *
473 * @param list Destination chain
474 * @param type TLV type to add
475 * @param caps Bitfield of capability flags to send
476 * @retun The size of the value added.
477 */
478faim_internal int aim_tlvlist_add_caps(aim_tlvlist_t **list, const fu16_t type, const fu32_t caps)
479{
480        fu8_t buf[16*16]; /* XXX icky fixed length buffer */
481        aim_bstream_t bs;
482
483        if (!caps)
484                return 0; /* nothing there anyway */
485
486        aim_bstream_init(&bs, buf, sizeof(buf));
487
488        aim_putcap(&bs, caps);
489
490        return aim_tlvlist_add_raw(list, type, aim_bstream_curpos(&bs), buf);
491}
492
493/**
494 * Adds the given userinfo struct to a TLV chain.
495 *
496 * @param list Destination chain.
497 * @param type TLV type to add.
498 * @retun The size of the value added.
499 */
500faim_internal int aim_tlvlist_add_userinfo(aim_tlvlist_t **list, fu16_t type, aim_userinfo_t *userinfo)
501{
502        fu8_t buf[1024]; /* bleh */
503        aim_bstream_t bs;
504
505        aim_bstream_init(&bs, buf, sizeof(buf));
506
507        aim_putuserinfo(&bs, userinfo);
508
509        return aim_tlvlist_add_raw(list, type, aim_bstream_curpos(&bs), buf);
510}
511
512/**
513 * Adds a TLV with a zero length to a TLV chain.
514 *
515 * @param list Destination chain.
516 * @param type TLV type to add.
517 * @retun The size of the value added.
518 */
519faim_internal int aim_tlvlist_add_noval(aim_tlvlist_t **list, const fu16_t type)
520{
521        return aim_tlvlist_add_raw(list, type, 0, NULL);
522}
523
524/*
525 * Note that the inner TLV chain will not be modifiable as a tlvchain once
526 * it is written using this.  Or rather, it can be, but updates won't be
527 * made to this.
528 *
529 * XXX should probably support sublists for real.
530 *
531 * This is so neat.
532 *
533 */
534faim_internal int aim_tlvlist_add_frozentlvlist(aim_tlvlist_t **list, fu16_t type, aim_tlvlist_t **tl)
535{
536        fu8_t *buf;
537        int buflen;
538        aim_bstream_t bs;
539
540        buflen = aim_tlvlist_size(tl);
541
542        if (buflen <= 0)
543                return 0;
544
545        if (!(buf = malloc(buflen)))
546                return 0;
547
548        aim_bstream_init(&bs, buf, buflen);
549
550        aim_tlvlist_write(&bs, tl);
551
552        aim_tlvlist_add_raw(list, type, aim_bstream_curpos(&bs), buf);
553
554        free(buf);
555
556        return buflen;
557}
558
559/**
560 * Substitute a TLV of a given type with a new TLV of the same type.  If
561 * you attempt to replace a TLV that does not exist, this function will
562 * just add a new TLV as if you called aim_tlvlist_add_raw().
563 *
564 * @param list Desination chain (%NULL pointer if empty).
565 * @param type TLV type.
566 * @param length Length of string to add (not including %NULL).
567 * @param value String to add.
568 * @return The length of the TLV.
569 */
570faim_internal int aim_tlvlist_replace_raw(aim_tlvlist_t **list, const fu16_t type, const fu16_t length, const fu8_t *value)
571{
572        aim_tlvlist_t *cur;
573
574        if (list == NULL)
575                return 0;
576
577        for (cur = *list; ((cur != NULL) && (cur->tlv->type != type)); cur = cur->next);
578        if (cur == NULL)
579                return aim_tlvlist_add_raw(list, type, length, value);
580
581        free(cur->tlv->value);
582        cur->tlv->length = length;
583        if (cur->tlv->length > 0) {
584                cur->tlv->value = (fu8_t *)malloc(cur->tlv->length);
585                memcpy(cur->tlv->value, value, cur->tlv->length);
586        } else
587                cur->tlv->value = NULL;
588
589        return cur->tlv->length;
590}
591
592/**
593 * Substitute a TLV of a given type with a new TLV of the same type.  If
594 * you attempt to replace a TLV that does not exist, this function will
595 * just add a new TLV as if you called aim_tlvlist_add_raw().
596 *
597 * @param list Desination chain (%NULL pointer if empty).
598 * @param type TLV type.
599 * @return The length of the TLV.
600 */
601faim_internal int aim_tlvlist_replace_noval(aim_tlvlist_t **list, const fu16_t type)
602{
603        return aim_tlvlist_replace_raw(list, type, 0, NULL);
604}
605
606/**
607 * Substitute a TLV of a given type with a new TLV of the same type.  If
608 * you attempt to replace a TLV that does not exist, this function will
609 * just add a new TLV as if you called aim_tlvlist_add_raw().
610 *
611 * @param list Desination chain (%NULL pointer if empty).
612 * @param type TLV type.
613 * @param value 8 bit value to add.
614 * @return The length of the TLV.
615 */
616faim_internal int aim_tlvlist_replace_8(aim_tlvlist_t **list, const fu16_t type, const fu8_t value)
617{
618        fu8_t v8[1];
619
620        aimutil_put8(v8, value);
621
622        return aim_tlvlist_replace_raw(list, type, 1, v8);
623}
624
625/**
626 * Substitute a TLV of a given type with a new TLV of the same type.  If
627 * you attempt to replace a TLV that does not exist, this function will
628 * just add a new TLV as if you called aim_tlvlist_add_raw().
629 *
630 * @param list Desination chain (%NULL pointer if empty).
631 * @param type TLV type.
632 * @param value 32 bit value to add.
633 * @return The length of the TLV.
634 */
635faim_internal int aim_tlvlist_replace_32(aim_tlvlist_t **list, const fu16_t type, const fu32_t value)
636{
637        fu8_t v32[4];
638
639        aimutil_put32(v32, value);
640
641        return aim_tlvlist_replace_raw(list, type, 4, v32);
642}
643
644/**
645 * Remove a TLV of a given type.  If you attempt to remove a TLV that
646 * does not exist, nothing happens.
647 *
648 * @param list Desination chain (%NULL pointer if empty).
649 * @param type TLV type.
650 */
651faim_internal void aim_tlvlist_remove(aim_tlvlist_t **list, const fu16_t type)
652{
653        aim_tlvlist_t *del;
654
655        if (!list || !(*list))
656                return;
657
658        /* Remove the item from the list */
659        if ((*list)->tlv->type == type) {
660                del = *list;
661                *list = (*list)->next;
662        } else {
663                aim_tlvlist_t *cur;
664                for (cur=*list; (cur->next && (cur->next->tlv->type!=type)); cur=cur->next);
665                if (!cur->next)
666                        return;
667                del = cur->next;
668                cur->next = del->next;
669        }
670
671        /* Free the removed item */
672        free(del->tlv->value);
673        free(del->tlv);
674        free(del);
675}
676
677/**
678 * aim_tlvlist_write - Write a TLV chain into a data buffer.
679 * @buf: Destination buffer
680 * @buflen: Maximum number of bytes that will be written to buffer
681 * @list: Source TLV chain
682 *
683 * Copies a TLV chain into a raw data buffer, writing only the number
684 * of bytes specified. This operation does not free the chain;
685 * aim_tlvlist_free() must still be called to free up the memory used
686 * by the chain structures.
687 *
688 * XXX clean this up, make better use of bstreams
689 */
690faim_internal int aim_tlvlist_write(aim_bstream_t *bs, aim_tlvlist_t **list)
691{
692        int goodbuflen;
693        aim_tlvlist_t *cur;
694
695        /* do an initial run to test total length */
696        goodbuflen = aim_tlvlist_size(list);
697
698        if (goodbuflen > aim_bstream_empty(bs))
699                return 0; /* not enough buffer */
700
701        /* do the real write-out */
702        for (cur = *list; cur; cur = cur->next) {
703                aimbs_put16(bs, cur->tlv->type);
704                aimbs_put16(bs, cur->tlv->length);
705                if (cur->tlv->length)
706                        aimbs_putraw(bs, cur->tlv->value, cur->tlv->length);
707        }
708
709        return 1; /* XXX this is a nonsensical return */
710}
711
712
713/**
714 * Grab the Nth TLV of type type in the TLV list list.
715 *
716 * Returns a pointer to an aim_tlv_t of the specified type;
717 * %NULL on error.  The @nth parameter is specified starting at %1.
718 * In most cases, there will be no more than one TLV of any type
719 * in a chain.
720 *
721 * @param list Source chain.
722 * @param type Requested TLV type.
723 * @param nth Index of TLV of type to get.
724 * @return The TLV you were looking for, or NULL if one could not be found.
725 */
726faim_internal aim_tlv_t *aim_tlv_gettlv(aim_tlvlist_t *list, const fu16_t type, const int nth)
727{
728        aim_tlvlist_t *cur;
729        int i;
730
731        for (cur = list, i = 0; cur; cur = cur->next) {
732                if (cur && cur->tlv) {
733                        if (cur->tlv->type == type)
734                                i++;
735                        if (i >= nth)
736                                return cur->tlv;
737                }
738        }
739
740        return NULL;
741}
742
743/**
744 * Retrieve the data from the nth TLV in the given TLV chain as a string.
745 *
746 * @param list Source TLV chain.
747 * @param type TLV type to search for.
748 * @param nth Index of TLV to return.
749 * @return The value of the TLV you were looking for, or NULL if one could
750 *         not be found.  This is a dynamic buffer and must be freed by the
751 *         caller.
752 */
753faim_internal char *aim_tlv_getstr(aim_tlvlist_t *list, const fu16_t type, const int nth)
754{
755        aim_tlv_t *tlv;
756        char *newstr;
757
758        if (!(tlv = aim_tlv_gettlv(list, type, nth)))
759                return NULL;
760
761        newstr = (char *) malloc(tlv->length + 1);
762        memcpy(newstr, tlv->value, tlv->length);
763        newstr[tlv->length] = '\0';
764
765        return newstr;
766}
767
768/**
769 * Retrieve the data from the nth TLV in the given TLV chain as an 8bit
770 * integer.
771 *
772 * @param list Source TLV chain.
773 * @param type TLV type to search for.
774 * @param nth Index of TLV to return.
775 * @return The value the TLV you were looking for, or 0 if one could
776 *         not be found.
777 */
778faim_internal fu8_t aim_tlv_get8(aim_tlvlist_t *list, const fu16_t type, const int nth)
779{
780        aim_tlv_t *tlv;
781
782        if (!(tlv = aim_tlv_gettlv(list, type, nth)))
783                return 0; /* erm */
784        return aimutil_get8(tlv->value);
785}
786
787/**
788 * Retrieve the data from the nth TLV in the given TLV chain as a 16bit
789 * integer.
790 *
791 * @param list Source TLV chain.
792 * @param type TLV type to search for.
793 * @param nth Index of TLV to return.
794 * @return The value the TLV you were looking for, or 0 if one could
795 *         not be found.
796 */
797faim_internal fu16_t aim_tlv_get16(aim_tlvlist_t *list, const fu16_t type, const int nth)
798{
799        aim_tlv_t *tlv;
800
801        if (!(tlv = aim_tlv_gettlv(list, type, nth)))
802                return 0; /* erm */
803        return aimutil_get16(tlv->value);
804}
805
806/**
807 * Retrieve the data from the nth TLV in the given TLV chain as a 32bit
808 * integer.
809 *
810 * @param list Source TLV chain.
811 * @param type TLV type to search for.
812 * @param nth Index of TLV to return.
813 * @return The value the TLV you were looking for, or 0 if one could
814 *         not be found.
815 */
816faim_internal fu32_t aim_tlv_get32(aim_tlvlist_t *list, const fu16_t type, const int nth)
817{
818        aim_tlv_t *tlv;
819
820        if (!(tlv = aim_tlv_gettlv(list, type, nth)))
821                return 0; /* erm */
822        return aimutil_get32(tlv->value);
823}
Note: See TracBrowser for help on using the repository browser.