source: protocols/oscar/tlv.c @ cfbb3a6

Last change on this file since cfbb3a6 was b8ef1b1, checked in by Nelson Elhage <nelhage@…>, at 2005-12-04T19:32:14Z

Merging the Hanji groupchat patch

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