source: protocols/oscar/tlv.c @ 59a7dc5

Last change on this file since 59a7dc5 was e88fe7da, checked in by Veres Lajos <vlajos@…>, at 2015-08-07T21:53:25Z

typofix - https://github.com/vlajos/misspell_fixer

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