source: protocols/oscar/tlv.c @ 831c955

Last change on this file since 831c955 was fbc7844, checked in by Jelmer Vernooij <jelmer@…>, at 2005-11-15T14:29:47Z

Remove some unused code in oscar

  • Property mode set to 100644
File size: 12.4 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
342/**
343 * aim_writetlvchain - Write a TLV chain into a data buffer.
344 * @buf: Destination buffer
345 * @buflen: Maximum number of bytes that will be written to buffer
346 * @list: Source TLV chain
347 *
348 * Copies a TLV chain into a raw data buffer, writing only the number
349 * of bytes specified. This operation does not free the chain;
350 * aim_freetlvchain() must still be called to free up the memory used
351 * by the chain structures.
352 *
353 * XXX clean this up, make better use of bstreams
354 */
355int aim_writetlvchain(aim_bstream_t *bs, aim_tlvlist_t **list)
356{
357        int goodbuflen;
358        aim_tlvlist_t *cur;
359
360        /* do an initial run to test total length */
361        for (cur = *list, goodbuflen = 0; cur; cur = cur->next) {
362                goodbuflen += 2 + 2; /* type + len */
363                goodbuflen += cur->tlv->length;
364        }
365
366        if (goodbuflen > aim_bstream_empty(bs))
367                return 0; /* not enough buffer */
368
369        /* do the real write-out */
370        for (cur = *list; cur; cur = cur->next) {
371                aimbs_put16(bs, cur->tlv->type);
372                aimbs_put16(bs, cur->tlv->length);
373                if (cur->tlv->length)
374                        aimbs_putraw(bs, cur->tlv->value, cur->tlv->length);
375        }
376
377        return 1; /* XXX this is a nonsensical return */
378}
379
380
381/**
382 * aim_gettlv - Grab the Nth TLV of type type in the TLV list list.
383 * @list: Source chain
384 * @type: Requested TLV type
385 * @nth: Index of TLV of type to get
386 *
387 * Returns a pointer to an aim_tlv_t of the specified type;
388 * %NULL on error.  The @nth parameter is specified starting at %1.
389 * In most cases, there will be no more than one TLV of any type
390 * in a chain.
391 *
392 */
393aim_tlv_t *aim_gettlv(aim_tlvlist_t *list, const guint16 t, const int n)
394{
395        aim_tlvlist_t *cur;
396        int i;
397
398        for (cur = list, i = 0; cur; cur = cur->next) {
399                if (cur && cur->tlv) {
400                        if (cur->tlv->type == t)
401                                i++;
402                        if (i >= n)
403                                return cur->tlv;
404                }
405        }
406
407        return NULL;
408}
409
410/**
411 * aim_gettlv_str - Retrieve the Nth TLV in chain as a string.
412 * @list: Source TLV chain
413 * @type: TLV type to search for
414 * @nth: Index of TLV to return
415 *
416 * Same as aim_gettlv(), except that the return value is a %NULL-
417 * terminated string instead of an aim_tlv_t.  This is a
418 * dynamic buffer and must be freed by the caller.
419 *
420 */
421char *aim_gettlv_str(aim_tlvlist_t *list, const guint16 t, const int n)
422{
423        aim_tlv_t *tlv;
424        char *newstr;
425
426        if (!(tlv = aim_gettlv(list, t, n)))
427                return NULL;
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        return aimutil_get8(tlv->value);
453}
454
455/**
456 * aim_gettlv16 - Retrieve the Nth TLV in chain as a 16bit integer.
457 * @list: Source TLV chain
458 * @type: TLV type to search for
459 * @nth: Index of TLV to return
460 *
461 * Same as aim_gettlv(), except that the return value is a
462 * 16bit integer instead of an aim_tlv_t.
463 *
464 */
465guint16 aim_gettlv16(aim_tlvlist_t *list, const guint16 t, const int n)
466{
467        aim_tlv_t *tlv;
468
469        if (!(tlv = aim_gettlv(list, t, n)))
470                return 0; /* erm */
471        return aimutil_get16(tlv->value);
472}
473
474/**
475 * aim_gettlv32 - Retrieve the Nth TLV in chain as a 32bit integer.
476 * @list: Source TLV chain
477 * @type: TLV type to search for
478 * @nth: Index of TLV to return
479 *
480 * Same as aim_gettlv(), except that the return value is a
481 * 32bit integer instead of an aim_tlv_t.
482 *
483 */
484guint32 aim_gettlv32(aim_tlvlist_t *list, const guint16 t, const int n)
485{
486        aim_tlv_t *tlv;
487
488        if (!(tlv = aim_gettlv(list, t, n)))
489                return 0; /* erm */
490        return aimutil_get32(tlv->value);
491}
492
493#if 0
494/**
495 * aim_puttlv_8 - Write a one-byte TLV.
496 * @buf: Destination buffer
497 * @t: TLV type
498 * @v: Value
499 *
500 * Writes a TLV with a one-byte integer value portion.
501 *
502 */
503int aim_puttlv_8(guint8 *buf, const guint16 t, const guint8 v)
504{
505        guint8 v8[1];
506
507        aimutil_put8(v8, v);
508
509        return aim_puttlv_raw(buf, t, 1, v8);
510}
511
512/**
513 * aim_puttlv_16 - Write a two-byte TLV.
514 * @buf: Destination buffer
515 * @t: TLV type
516 * @v: Value
517 *
518 * Writes a TLV with a two-byte integer value portion.
519 *
520 */
521int aim_puttlv_16(guint8 *buf, const guint16 t, const guint16 v)
522{
523        guint8 v16[2];
524
525        aimutil_put16(v16, v);
526
527        return aim_puttlv_raw(buf, t, 2, v16);
528}
529
530
531/**
532 * aim_puttlv_32 - Write a four-byte TLV.
533 * @buf: Destination buffer
534 * @t: TLV type
535 * @v: Value
536 *
537 * Writes a TLV with a four-byte integer value portion.
538 *
539 */
540int aim_puttlv_32(guint8 *buf, const guint16 t, const guint32 v)
541{
542        guint8 v32[4];
543
544        aimutil_put32(v32, v);
545
546        return aim_puttlv_raw(buf, t, 4, v32);
547}
548
549/**
550 * aim_puttlv_raw - Write a raw TLV.
551 * @buf: Destination buffer
552 * @t: TLV type
553 * @l: Length of string
554 * @v: String to write
555 *
556 * Writes a TLV with a raw value portion.  (Only the first @l
557 * bytes of the passed buffer will be written, which should not
558 * include a terminating NULL.)
559 *
560 */
561int aim_puttlv_raw(guint8 *buf, const guint16 t, const guint16 l, const guint8 *v)
562{
563        int i;
564
565        i = aimutil_put16(buf, t);
566        i += aimutil_put16(buf+i, l);
567        if (l)
568                memcpy(buf+i, v, l);
569        i += l;
570
571        return i;
572}
573#endif
574
Note: See TracBrowser for help on using the repository browser.