source: libfaim/tlv.c @ c7041b3

barnowl_perlaimdebianowlrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since c7041b3 was e374dee, checked in by James M. Kretchmar <kretch@mit.edu>, 21 years ago
*** empty log message ***
  • Property mode set to 100644
File size: 18.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 with this.
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_readtlvchain_len - Read a TLV chain from a buffer.
180 * @param bs Input bstream
181 * @param len The max length in bytes that will be read.
182 *        There are a number of places where you want to read in a tlvchain,
183 *        but the chain is not at the end of the SNAC, and the chain is
184 *        preceeded by the length of the TLVs.  So you can limit that with this.
185 *
186 * Reads and parses a series of TLV patterns from a data buffer; the
187 * returned structure is manipulatable with the rest of the TLV
188 * routines.  When done with a TLV chain, aim_freetlvchain() should
189 * be called to free the dynamic substructures.
190 *
191 * XXX There should be a flag setable here to have the tlvlist contain
192 * bstream references, so that at least the ->value portion of each
193 * element doesn't need to be malloc/memcpy'd.  This could prove to be
194 * just as effecient as the in-place TLV parsing used in a couple places
195 * in libfaim.
196 *
197 */
198faim_internal aim_tlvlist_t *aim_readtlvchain_len(aim_bstream_t *bs, fu16_t len)
199{
200        aim_tlvlist_t *list = NULL, *cur;
201
202        while ((aim_bstream_empty(bs) > 0) && (len > 0)) {
203                fu16_t type, length;
204
205                type = aimbs_get16(bs);
206                length = aimbs_get16(bs);
207
208                if (length > aim_bstream_empty(bs)) {
209                        aim_freetlvchain(&list);
210                        return NULL;
211                }
212
213                cur = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t));
214                if (!cur) {
215                        aim_freetlvchain(&list);
216                        return NULL;
217                }
218
219                memset(cur, 0, sizeof(aim_tlvlist_t));
220
221                cur->tlv = createtlv();
222                if (!cur->tlv) {
223                        free(cur);
224                        aim_freetlvchain(&list);
225                        return NULL;
226                }
227                cur->tlv->type = type;
228                if ((cur->tlv->length = length)) {
229                       cur->tlv->value = aimbs_getraw(bs, length);
230                       if (!cur->tlv->value) {
231                               freetlv(&cur->tlv);
232                               free(cur);
233                               aim_freetlvchain(&list);
234                               return NULL;
235                       }
236                }
237
238                len -= aim_sizetlvchain(&cur);
239                cur->next = list;
240                list = cur;
241        }
242
243        return list;
244}
245
246/**
247 * aim_tlvlist_copy - Duplicate a TLV chain.
248 * @param orig
249 *
250 * This is pretty pelf exslanatory.
251 *
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_addtlvtochain_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_sizetlvchain(&one) != aim_sizetlvchain(&two))
278                return 1;
279
280        aim_bstream_init(&bs1, ((fu8_t *)malloc(aim_sizetlvchain(&one)*sizeof(fu8_t))), aim_sizetlvchain(&one));
281        aim_bstream_init(&bs2, ((fu8_t *)malloc(aim_sizetlvchain(&two)*sizeof(fu8_t))), aim_sizetlvchain(&two));
282
283        aim_writetlvchain(&bs1, &one);
284        aim_writetlvchain(&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 * aim_freetlvchain - 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_freetlvchain(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 * aim_counttlvchain - Count the number of TLVs in a chain
331 * @list: Chain to be counted
332 *
333 * Returns the number of TLVs stored in the passed chain.
334 *
335 */
336faim_internal int aim_counttlvchain(aim_tlvlist_t **list)
337{
338        aim_tlvlist_t *cur;
339        int count;
340
341        if (!list || !*list)
342                return 0;
343
344        for (cur = *list, count = 0; cur; cur = cur->next)
345                count++;
346
347        return count;
348}
349
350/**
351 * aim_sizetlvchain - Count the number of bytes in a TLV chain
352 * @list: Chain to be sized
353 *
354 * Returns the number of bytes that would be needed to
355 * write the passed TLV chain to a data buffer.
356 *
357 */
358faim_internal int aim_sizetlvchain(aim_tlvlist_t **list)
359{
360        aim_tlvlist_t *cur;
361        int size;
362
363        if (!list || !*list)
364                return 0;
365
366        for (cur = *list, size = 0; cur; cur = cur->next)
367                size += (4 + cur->tlv->length);
368
369        return size;
370}
371
372/**
373 * aim_addtlvtochain_raw - Add a string to a TLV chain
374 * @list: Desination chain (%NULL pointer if empty)
375 * @t: TLV type
376 * @l: Length of string to add (not including %NULL)
377 * @v: String to add
378 *
379 * Adds the passed string as a TLV element of the passed type
380 * to the TLV chain.
381 *
382 */
383faim_internal int aim_addtlvtochain_raw(aim_tlvlist_t **list, const fu16_t t, const fu16_t l, const fu8_t *v)
384{
385        aim_tlvlist_t *newtlv, *cur;
386
387        if (!list)
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())) {
395                free(newtlv);
396                return 0;
397        }
398        newtlv->tlv->type = t;
399        if ((newtlv->tlv->length = l)) {
400                newtlv->tlv->value = (fu8_t *)malloc(newtlv->tlv->length);
401                memcpy(newtlv->tlv->value, v, newtlv->tlv->length);
402        }
403
404        if (!*list)
405                *list = newtlv;
406        else {
407                for(cur = *list; cur->next; cur = cur->next)
408                        ;
409                cur->next = newtlv;
410        }
411
412        return newtlv->tlv->length;
413}
414
415/**
416 * aim_addtlvtochain8 - Add a 8bit integer to a TLV chain
417 * @list: Destination chain
418 * @type: TLV type to add
419 * @val: Value to add
420 *
421 * Adds a one-byte unsigned integer to a TLV chain.
422 *
423 */
424faim_internal int aim_addtlvtochain8(aim_tlvlist_t **list, const fu16_t t, const fu8_t v)
425{
426        fu8_t v8[1];
427
428        aimutil_put8(v8, v);
429
430        return aim_addtlvtochain_raw(list, t, 1, v8);
431}
432
433/**
434 * aim_addtlvtochain16 - Add a 16bit integer to a TLV chain
435 * @list: Destination chain
436 * @t: TLV type to add
437 * @v: Value to add
438 *
439 * Adds a two-byte unsigned integer to a TLV chain.
440 *
441 */
442faim_internal int aim_addtlvtochain16(aim_tlvlist_t **list, const fu16_t t, const fu16_t v)
443{
444        fu8_t v16[2];
445
446        aimutil_put16(v16, v);
447
448        return aim_addtlvtochain_raw(list, t, 2, v16);
449}
450
451/**
452 * aim_addtlvtochain32 - Add a 32bit integer to a TLV chain
453 * @list: Destination chain
454 * @type: TLV type to add
455 * @val: Value to add
456 *
457 * Adds a four-byte unsigned integer to a TLV chain.
458 *
459 */
460faim_internal int aim_addtlvtochain32(aim_tlvlist_t **list, const fu16_t t, const fu32_t v)
461{
462        fu8_t v32[4];
463
464        aimutil_put32(v32, v);
465
466        return aim_addtlvtochain_raw(list, t, 4, v32);
467}
468
469/**
470 * aim_addtlvtochain_caps - Add a capability block to a TLV chain
471 * @list: Destination chain
472 * @type: TLV type to add
473 * @caps: Bitfield of capability flags to send
474 *
475 * Adds a block of capability blocks to a TLV chain. The bitfield
476 * passed in should be a bitwise %OR of any of the %AIM_CAPS constants:
477 *
478 *      %AIM_CAPS_BUDDYICON   Supports Buddy Icons
479 *
480 *      %AIM_CAPS_VOICE       Supports Voice Chat
481 *
482 *      %AIM_CAPS_IMIMAGE     Supports DirectIM/IMImage
483 *
484 *      %AIM_CAPS_CHAT        Supports Chat
485 *
486 *      %AIM_CAPS_GETFILE     Supports Get File functions
487 *
488 *      %AIM_CAPS_SENDFILE    Supports Send File functions
489 *
490 */
491faim_internal int aim_addtlvtochain_caps(aim_tlvlist_t **list, const fu16_t t, const fu32_t caps)
492{
493        fu8_t buf[16*16]; /* XXX icky fixed length buffer */
494        aim_bstream_t bs;
495
496        if (!caps)
497                return 0; /* nothing there anyway */
498
499        aim_bstream_init(&bs, buf, sizeof(buf));
500
501        aim_putcap(&bs, caps);
502
503        return aim_addtlvtochain_raw(list, t, aim_bstream_curpos(&bs), buf);
504}
505
506faim_internal int aim_addtlvtochain_userinfo(aim_tlvlist_t **list, fu16_t type, aim_userinfo_t *ui)
507{
508        fu8_t buf[1024]; /* bleh */
509        aim_bstream_t bs;
510
511        aim_bstream_init(&bs, buf, sizeof(buf));
512
513        aim_putuserinfo(&bs, ui);
514
515        return aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf);
516}
517
518/**
519 * aim_addtlvtochain_noval - Add a blank TLV to a TLV chain
520 * @list: Destination chain
521 * @type: TLV type to add
522 *
523 * Adds a TLV with a zero length to a TLV chain.
524 *
525 */
526faim_internal int aim_addtlvtochain_noval(aim_tlvlist_t **list, const fu16_t t)
527{
528        return aim_addtlvtochain_raw(list, t, 0, NULL);
529}
530
531/*
532 * Note that the inner TLV chain will not be modifiable as a tlvchain once
533 * it is written using this.  Or rather, it can be, but updates won't be
534 * made to this.
535 *
536 * XXX should probably support sublists for real.
537 *
538 * This is so neat.
539 *
540 */
541faim_internal int aim_addtlvtochain_frozentlvlist(aim_tlvlist_t **list, fu16_t type, aim_tlvlist_t **tl)
542{
543        fu8_t *buf;
544        int buflen;
545        aim_bstream_t bs;
546
547        buflen = aim_sizetlvchain(tl);
548
549        if (buflen <= 0)
550                return 0;
551
552        if (!(buf = malloc(buflen)))
553                return 0;
554
555        aim_bstream_init(&bs, buf, buflen);
556
557        aim_writetlvchain(&bs, tl);
558
559        aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf);
560
561        free(buf);
562
563        return buflen;
564}
565
566/**
567 * aim_writetlvchain - Write a TLV chain into a data buffer.
568 * @buf: Destination buffer
569 * @buflen: Maximum number of bytes that will be written to buffer
570 * @list: Source TLV chain
571 *
572 * Copies a TLV chain into a raw data buffer, writing only the number
573 * of bytes specified. This operation does not free the chain;
574 * aim_freetlvchain() must still be called to free up the memory used
575 * by the chain structures.
576 *
577 * XXX clean this up, make better use of bstreams
578 */
579faim_internal int aim_writetlvchain(aim_bstream_t *bs, aim_tlvlist_t **list)
580{
581        int goodbuflen;
582        aim_tlvlist_t *cur;
583
584        /* do an initial run to test total length */
585        goodbuflen = aim_sizetlvchain(list);
586
587        if (goodbuflen > aim_bstream_empty(bs))
588                return 0; /* not enough buffer */
589
590        /* do the real write-out */
591        for (cur = *list; cur; cur = cur->next) {
592                aimbs_put16(bs, cur->tlv->type);
593                aimbs_put16(bs, cur->tlv->length);
594                if (cur->tlv->length)
595                        aimbs_putraw(bs, cur->tlv->value, cur->tlv->length);
596        }
597
598        return 1; /* XXX this is a nonsensical return */
599}
600
601
602/**
603 * aim_gettlv - Grab the Nth TLV of type type in the TLV list list.
604 * @list: Source chain
605 * @type: Requested TLV type
606 * @nth: Index of TLV of type to get
607 *
608 * Returns a pointer to an aim_tlv_t of the specified type;
609 * %NULL on error.  The @nth parameter is specified starting at %1.
610 * In most cases, there will be no more than one TLV of any type
611 * in a chain.
612 *
613 */
614faim_internal aim_tlv_t *aim_gettlv(aim_tlvlist_t *list, const fu16_t t, const int n)
615{
616        aim_tlvlist_t *cur;
617        int i;
618
619        for (cur = list, i = 0; cur; cur = cur->next) {
620                if (cur && cur->tlv) {
621                        if (cur->tlv->type == t)
622                                i++;
623                        if (i >= n)
624                                return cur->tlv;
625                }
626        }
627
628        return NULL;
629}
630
631/**
632 * aim_gettlv_str - Retrieve the Nth TLV in chain as a string.
633 * @list: Source TLV chain
634 * @type: TLV type to search for
635 * @nth: Index of TLV to return
636 *
637 * Same as aim_gettlv(), except that the return value is a %NULL-
638 * terminated string instead of an aim_tlv_t.  This is a
639 * dynamic buffer and must be freed by the caller.
640 *
641 */
642faim_internal char *aim_gettlv_str(aim_tlvlist_t *list, const fu16_t t, const int n)
643{
644        aim_tlv_t *tlv;
645        char *newstr;
646
647        if (!(tlv = aim_gettlv(list, t, n)))
648                return NULL;
649
650        newstr = (char *) malloc(tlv->length + 1);
651        memcpy(newstr, tlv->value, tlv->length);
652        *(newstr + tlv->length) = '\0';
653
654        return newstr;
655}
656
657/**
658 * aim_gettlv8 - Retrieve the Nth TLV in chain as a 8bit integer.
659 * @list: Source TLV chain
660 * @type: TLV type to search for
661 * @nth: Index of TLV to return
662 *
663 * Same as aim_gettlv(), except that the return value is a
664 * 8bit integer instead of an aim_tlv_t.
665 *
666 */
667faim_internal fu8_t aim_gettlv8(aim_tlvlist_t *list, const fu16_t t, const int n)
668{
669        aim_tlv_t *tlv;
670
671        if (!(tlv = aim_gettlv(list, t, n)))
672                return 0; /* erm */
673        return aimutil_get8(tlv->value);
674}
675
676/**
677 * aim_gettlv16 - Retrieve the Nth TLV in chain as a 16bit integer.
678 * @list: Source TLV chain
679 * @type: TLV type to search for
680 * @nth: Index of TLV to return
681 *
682 * Same as aim_gettlv(), except that the return value is a
683 * 16bit integer instead of an aim_tlv_t.
684 *
685 */
686faim_internal fu16_t aim_gettlv16(aim_tlvlist_t *list, const fu16_t t, const int n)
687{
688        aim_tlv_t *tlv;
689
690        if (!(tlv = aim_gettlv(list, t, n)))
691                return 0; /* erm */
692        return aimutil_get16(tlv->value);
693}
694
695/**
696 * aim_gettlv32 - Retrieve the Nth TLV in chain as a 32bit integer.
697 * @list: Source TLV chain
698 * @type: TLV type to search for
699 * @nth: Index of TLV to return
700 *
701 * Same as aim_gettlv(), except that the return value is a
702 * 32bit integer instead of an aim_tlv_t.
703 *
704 */
705faim_internal fu32_t aim_gettlv32(aim_tlvlist_t *list, const fu16_t t, const int n)
706{
707        aim_tlv_t *tlv;
708
709        if (!(tlv = aim_gettlv(list, t, n)))
710                return 0; /* erm */
711        return aimutil_get32(tlv->value);
712}
713
714#if 0
715/**
716 * aim_puttlv_8 - Write a one-byte TLV.
717 * @buf: Destination buffer
718 * @t: TLV type
719 * @v: Value
720 *
721 * Writes a TLV with a one-byte integer value portion.
722 *
723 */
724faim_export int aim_puttlv_8(fu8_t *buf, const fu16_t t, const fu8_t v)
725{
726        fu8_t v8[1];
727
728        aimutil_put8(v8, v);
729
730        return aim_puttlv_raw(buf, t, 1, v8);
731}
732
733/**
734 * aim_puttlv_16 - Write a two-byte TLV.
735 * @buf: Destination buffer
736 * @t: TLV type
737 * @v: Value
738 *
739 * Writes a TLV with a two-byte integer value portion.
740 *
741 */
742faim_export int aim_puttlv_16(fu8_t *buf, const fu16_t t, const fu16_t v)
743{
744        fu8_t v16[2];
745
746        aimutil_put16(v16, v);
747
748        return aim_puttlv_raw(buf, t, 2, v16);
749}
750
751
752/**
753 * aim_puttlv_32 - Write a four-byte TLV.
754 * @buf: Destination buffer
755 * @t: TLV type
756 * @v: Value
757 *
758 * Writes a TLV with a four-byte integer value portion.
759 *
760 */
761faim_export int aim_puttlv_32(fu8_t *buf, const fu16_t t, const fu32_t v)
762{
763        fu8_t v32[4];
764
765        aimutil_put32(v32, v);
766
767        return aim_puttlv_raw(buf, t, 4, v32);
768}
769
770/**
771 * aim_puttlv_raw - Write a raw TLV.
772 * @buf: Destination buffer
773 * @t: TLV type
774 * @l: Length of string
775 * @v: String to write
776 *
777 * Writes a TLV with a raw value portion.  (Only the first @l
778 * bytes of the passed buffer will be written, which should not
779 * include a terminating NULL.)
780 *
781 */
782faim_export int aim_puttlv_raw(fu8_t *buf, const fu16_t t, const fu16_t l, const fu8_t *v)
783{
784        int i;
785
786        i = aimutil_put16(buf, t);
787        i += aimutil_put16(buf+i, l);
788        if (l)
789                memcpy(buf+i, v, l);
790        i += l;
791
792        return i;
793}
794#endif
Note: See TracBrowser for help on using the repository browser.