src/protocols/oscar/tlv.c

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

mercurial