source: libfaim/tlv.c @ 6bf73ce

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