source: libfaim/tlv.c @ 5d9c664

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