core/protocols/oscar/tlv.c

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

mercurial