]> andersk Git - libfaim.git/blame - aim_tlv.c
- Sat Dec 2 02:14:45 UTC 2000
[libfaim.git] / aim_tlv.c
CommitLineData
a25832e6 1#include <faim/aim.h>
9de3ca7e 2
be67fdd0 3/**
4 * aim_readtlvchain - Read a TLV chain from a buffer.
5 * @buf: Input buffer
6 * @maxlen: Length of input buffer
7 *
8 * Reads and parses a series of TLV patterns from a data buffer; the
9 * returned structure is manipulatable with the rest of the TLV
10 * routines. When done with a TLV chain, aim_freetlvchain() should
11 * be called to free the dynamic substructures.
12 *
13 */
14faim_export struct aim_tlvlist_t *aim_readtlvchain(u_char *buf, int maxlen)
49c8a2fa 15{
16 int pos;
17 struct aim_tlvlist_t *list;
18 struct aim_tlvlist_t *cur;
19
20 u_short type;
21 u_short length;
22
23 if (!buf)
24 return NULL;
25
26 list = NULL;
27
28 pos = 0;
29
30 while (pos < maxlen)
31 {
32 type = aimutil_get16(buf+pos);
33 pos += 2;
34
35 if (pos < maxlen)
36 {
37 length = aimutil_get16(buf+pos);
38 pos += 2;
39
40 if ((pos+length) <= maxlen)
41 {
13ebc4c4 42 /*
43 * Okay, so now AOL has decided that any TLV of
44 * type 0x0013 can only be two bytes, despite
45 * what the actual given length is. So here
46 * we dump any invalid TLVs of that sort. Hopefully
47 * theres no special cases to this special case.
48 * - mid (30jun2000)
49 */
50 if ((type == 0x0013) && (length != 0x0002)) {
51 printf("faim: skipping TLV t(0013) with invalid length (0x%04x)\n", length);
52 length = 0x0002;
53 } else {
54 cur = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
55 memset(cur, 0x00, sizeof(struct aim_tlvlist_t));
49c8a2fa 56
13ebc4c4 57 cur->tlv = aim_createtlv();
58 cur->tlv->type = type;
8515d6a5 59 cur->tlv->length = length;
60 if (length) {
61 cur->tlv->value = (unsigned char *)malloc(length);
62 memcpy(cur->tlv->value, buf+pos, length);
63 }
98c88242 64
13ebc4c4 65 cur->next = list;
66 list = cur;
67 }
49c8a2fa 68 pos += length;
69 }
70 }
71 }
72
73 return list;
74}
75
be67fdd0 76/**
77 * aim_freetlvchain - Free a TLV chain structure
78 * @list: Chain to be freed
79 *
80 * Walks the list of TLVs in the passed TLV chain and
81 * frees each one. Note that any references to this data
82 * should be removed before calling this.
83 *
84 */
85faim_export void aim_freetlvchain(struct aim_tlvlist_t **list)
49c8a2fa 86{
87 struct aim_tlvlist_t *cur, *cur2;
88
89 if (!list || !(*list))
90 return;
91
92 cur = *list;
93 while (cur)
94 {
95 aim_freetlv(&cur->tlv);
96 cur2 = cur->next;
97 free(cur);
98 cur = cur2;
99 }
100 list = NULL;
101 return;
102}
103
be67fdd0 104/**
105 * aim_counttlvchain - Count the number of TLVs in a chain
106 * @list: Chain to be counted
107 *
108 * Returns the number of TLVs stored in the passed chain.
109 *
110 */
111faim_export int aim_counttlvchain(struct aim_tlvlist_t **list)
e6b05d80 112{
113 struct aim_tlvlist_t *cur;
114 int count = 0;
115
116 if (!list || !(*list))
117 return 0;
118
119 for (cur = *list; cur; cur = cur->next)
120 count++;
121
122 return count;
123}
124
be67fdd0 125/**
126 * aim_sizetlvchain - Count the number of bytes in a TLV chain
127 * @list: Chain to be sized
128 *
129 * Returns the number of bytes that would be needed to
130 * write the passed TLV chain to a data buffer.
131 *
132 */
3b101546 133faim_export int aim_sizetlvchain(struct aim_tlvlist_t **list)
134{
135 struct aim_tlvlist_t *cur;
136 int size = 0;
137
138 if (!list || !(*list))
139 return 0;
140
141 for (cur = *list; cur; cur = cur->next)
142 size += (4 + cur->tlv->length);
143
144 return size;
145}
146
be67fdd0 147/**
148 * aim_addtlvtochain_str - Add a string to a TLV chain
149 * @list: Desination chain (%NULL pointer if empty)
150 * @type: TLV type
151 * @str: String to add
152 * @len: Length of string to add (not including %NULL)
153 *
154 * Adds the passed string as a TLV element of the passed type
155 * to the TLV chain.
156 *
157 */
158faim_export int aim_addtlvtochain_str(struct aim_tlvlist_t **list, unsigned short type, char *str, int len)
0e2be272 159{
a15d82b1 160 struct aim_tlvlist_t *newtlv;
0e2be272 161 struct aim_tlvlist_t *cur;
162
163 if (!list)
164 return 0;
165
a15d82b1 166 newtlv = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
167 memset(newtlv, 0x00, sizeof(struct aim_tlvlist_t));
0e2be272 168
a15d82b1 169 newtlv->tlv = aim_createtlv();
170 newtlv->tlv->type = type;
171 newtlv->tlv->length = len;
172 newtlv->tlv->value = (unsigned char *)malloc(newtlv->tlv->length*sizeof(unsigned char));
173 memcpy(newtlv->tlv->value, str, newtlv->tlv->length);
0e2be272 174
a15d82b1 175 newtlv->next = NULL;
0e2be272 176
177 if (*list == NULL) {
a15d82b1 178 *list = newtlv;
0e2be272 179 } else if ((*list)->next == NULL) {
a15d82b1 180 (*list)->next = newtlv;
0e2be272 181 } else {
182 for(cur = *list; cur->next; cur = cur->next)
183 ;
a15d82b1 184 cur->next = newtlv;
0e2be272 185 }
a15d82b1 186 return newtlv->tlv->length;
0e2be272 187}
188
be67fdd0 189/**
190 * aim_addtlvtochain16 - Add a 16bit integer to a TLV chain
191 * @list: Destination chain
192 * @type: TLV type to add
193 * @val: Value to add
194 *
195 * Adds a two-byte unsigned integer to a TLV chain.
196 *
197 */
198faim_export int aim_addtlvtochain16(struct aim_tlvlist_t **list, unsigned short type, unsigned short val)
0e2be272 199{
a15d82b1 200 struct aim_tlvlist_t *newtl;
0e2be272 201 struct aim_tlvlist_t *cur;
202
203 if (!list)
204 return 0;
205
a15d82b1 206 newtl = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
207 memset(newtl, 0x00, sizeof(struct aim_tlvlist_t));
0e2be272 208
a15d82b1 209 newtl->tlv = aim_createtlv();
210 newtl->tlv->type = type;
211 newtl->tlv->length = 2;
212 newtl->tlv->value = (unsigned char *)malloc(newtl->tlv->length*sizeof(unsigned char));
213 aimutil_put16(newtl->tlv->value, val);
0e2be272 214
a15d82b1 215 newtl->next = NULL;
0e2be272 216
217 if (*list == NULL) {
a15d82b1 218 *list = newtl;
0e2be272 219 } else if ((*list)->next == NULL) {
a15d82b1 220 (*list)->next = newtl;
0e2be272 221 } else {
222 for(cur = *list; cur->next; cur = cur->next)
223 ;
a15d82b1 224 cur->next = newtl;
0e2be272 225 }
226 return 2;
227}
228
be67fdd0 229/**
230 * aim_addtlvtochain32 - Add a 32bit integer to a TLV chain
231 * @list: Destination chain
232 * @type: TLV type to add
233 * @val: Value to add
234 *
235 * Adds a four-byte unsigned integer to a TLV chain.
236 *
237 */
238faim_export int aim_addtlvtochain32(struct aim_tlvlist_t **list, unsigned short type, unsigned long val)
0e2be272 239{
a15d82b1 240 struct aim_tlvlist_t *newtl;
0e2be272 241 struct aim_tlvlist_t *cur;
242
243 if (!list)
244 return 0;
245
a15d82b1 246 newtl = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
247 memset(newtl, 0x00, sizeof(struct aim_tlvlist_t));
0e2be272 248
a15d82b1 249 newtl->tlv = aim_createtlv();
250 newtl->tlv->type = type;
251 newtl->tlv->length = 4;
252 newtl->tlv->value = (unsigned char *)malloc(newtl->tlv->length*sizeof(unsigned char));
253 aimutil_put32(newtl->tlv->value, val);
0e2be272 254
a15d82b1 255 newtl->next = NULL;
0e2be272 256
257 if (*list == NULL) {
a15d82b1 258 *list = newtl;
0e2be272 259 } else if ((*list)->next == NULL) {
a15d82b1 260 (*list)->next = newtl;
0e2be272 261 } else {
262 for(cur = *list; cur->next; cur = cur->next)
263 ;
a15d82b1 264 cur->next = newtl;
0e2be272 265 }
266 return 4;
267}
268
be67fdd0 269/**
270 * aim_addtlvtochain_caps - Add a capability block to a TLV chain
271 * @list: Destination chain
272 * @type: TLV type to add
273 * @caps: Bitfield of capability flags to send
274 *
275 * Adds a block of capability blocks to a TLV chain. The bitfield
276 * passed in should be a bitwise %OR of any of the %AIM_CAPS constants:
277 *
278 * %AIM_CAPS_BUDDYICON Supports Buddy Icons
279 *
280 * %AIM_CAPS_VOICE Supports Voice Chat
281 *
282 * %AIM_CAPS_IMIMAGE Supports DirectIM/IMImage
283 *
284 * %AIM_CAPS_CHAT Supports Chat
285 *
286 * %AIM_CAPS_GETFILE Supports Get File functions
287 *
288 * %AIM_CAPS_SENDFILE Supports Send File functions
289 *
290 */
291faim_export int aim_addtlvtochain_caps(struct aim_tlvlist_t **list, unsigned short type, unsigned short caps)
3b101546 292{
293 unsigned char buf[128]; /* icky fixed length buffer */
294 struct aim_tlvlist_t *newtl;
295 struct aim_tlvlist_t *cur;
296
297 if(!list)
298 return 0;
299
9c38f1a7 300 newtl = (struct aim_tlvlist_t *)malloc(sizeof(struct aim_tlvlist_t));
301 memset(newtl, 0x00, sizeof(struct aim_tlvlist_t));
302
3b101546 303 newtl->tlv = aim_createtlv();
304 newtl->tlv->type = type;
305
9c38f1a7 306 newtl->tlv->length = aim_putcap(buf, sizeof(buf), caps);
3b101546 307 newtl->tlv->value = (unsigned char *)calloc(1, newtl->tlv->length);
9c38f1a7 308 memcpy(newtl->tlv->value, buf, newtl->tlv->length);
3b101546 309
310 newtl->next = NULL;
311
312 if (*list == NULL) {
313 *list = newtl;
314 } else if ((*list)->next == NULL) {
315 (*list)->next = newtl;
316 } else {
317 for(cur = *list; cur->next; cur = cur->next)
318 ;
319 cur->next = newtl;
320 }
321 return newtl->tlv->length;
322}
323
be67fdd0 324/**
325 * aim_writetlvchain - Write a TLV chain into a data buffer.
326 * @buf: Destination buffer
327 * @buflen: Maximum number of bytes that will be written to buffer
328 * @list: Source TLV chain
329 *
330 * Copies a TLV chain into a raw data buffer, writing only the number
331 * of bytes specified. This operation does not free the chain;
332 * aim_freetlvchain() must still be called to free up the memory used
333 * by the chain structures.
334 *
335 */
336faim_export int aim_writetlvchain(u_char *buf, int buflen, struct aim_tlvlist_t **list)
0e2be272 337{
338 int goodbuflen = 0;
339 int i = 0;
340 struct aim_tlvlist_t *cur;
341
342 if (!list || !buf || !buflen)
343 return 0;
344
345 /* do an initial run to test total length */
346 for (cur = *list; cur; cur = cur->next) {
347 goodbuflen += 2 + 2; /* type + len */
348 goodbuflen += cur->tlv->length;
349 }
350
351 if (goodbuflen > buflen)
352 return 0; /* not enough buffer */
353
354 /* do the real write-out */
355 for (cur = *list; cur; cur = cur->next) {
356 i += aimutil_put16(buf+i, cur->tlv->type);
357 i += aimutil_put16(buf+i, cur->tlv->length);
358 memcpy(buf+i, cur->tlv->value, cur->tlv->length);
359 i += cur->tlv->length;
360 }
361
362 return i;
363}
364
365
be67fdd0 366/**
367 * aim_gettlv - Grab the Nth TLV of type type in the TLV list list.
368 * @list: Source chain
369 * @type: Requested TLV type
370 * @nth: Index of TLV of type to get
371 *
372 * Returns a pointer to an aim_tlv_t of the specified type;
373 * %NULL on error. The @nth parameter is specified starting at %1.
374 * In most cases, there will be no more than one TLV of any type
375 * in a chain.
376 *
49c8a2fa 377 */
be67fdd0 378faim_export struct aim_tlv_t *aim_gettlv(struct aim_tlvlist_t *list, u_short type, int nth)
49c8a2fa 379{
380 int i;
381 struct aim_tlvlist_t *cur;
382
383 i = 0;
384 for (cur = list; cur != NULL; cur = cur->next)
385 {
386 if (cur && cur->tlv)
387 {
388 if (cur->tlv->type == type)
389 i++;
390 if (i >= nth)
391 return cur->tlv;
392 }
393 }
394 return NULL;
395}
396
be67fdd0 397/**
398 * aim_gettlv_str - Retrieve the Nth TLV in chain as a string.
399 * @list: Source TLV chain
400 * @type: TLV type to search for
401 * @nth: Index of TLV to return
402 *
403 * Same as aim_gettlv(), except that the return value is a %NULL-
404 * terminated string instead of an aim_tlv_t. This is a
405 * dynamic buffer and must be freed by the caller.
406 *
407 */
408faim_export char *aim_gettlv_str(struct aim_tlvlist_t *list, u_short type, int nth)
49c8a2fa 409{
410 struct aim_tlv_t *tlv;
411 char *newstr;
412
413 if (!(tlv = aim_gettlv(list, type, nth)))
414 return NULL;
415
416 newstr = (char *) malloc(tlv->length + 1);
417 memcpy(newstr, tlv->value, tlv->length);
418 *(newstr + tlv->length) = '\0';
419
420 return newstr;
421}
422
be67fdd0 423/**
424 * aim_grabtlv - Grab a single TLV from a data buffer
425 * @src: Source data buffer (must be at least 4 bytes long)
426 *
427 * Creates a TLV structure aim_tlv_t and returns it
428 * filled with values from a buffer, possibly including a
429 * dynamically allocated buffer for the value portion.
430 *
431 * Both the aim_tlv_t and the tlv->value pointer
432 * must be freed by the caller if non-%NULL.
433 *
434 */
435faim_export struct aim_tlv_t *aim_grabtlv(u_char *src)
9de3ca7e 436{
437 struct aim_tlv_t *dest = NULL;
438
439 dest = aim_createtlv();
440
441 dest->type = src[0] << 8;
442 dest->type += src[1];
443
444 dest->length = src[2] << 8;
445 dest->length += src[3];
446
447 dest->value = (u_char *) malloc(dest->length*sizeof(u_char));
448 memset(dest->value, 0, dest->length*sizeof(u_char));
449
450 memcpy(dest->value, &(src[4]), dest->length*sizeof(u_char));
451
452 return dest;
453}
454
be67fdd0 455/**
456 * aim_grabtlvstr - Grab a single TLV from a data buffer as string
457 * @src: Source data buffer (must be at least 4 bytes long)
458 *
459 * Creates a TLV structure aim_tlv_t and returns it
460 * filled with values from a buffer, possibly including a
461 * dynamically allocated buffer for the value portion, which
462 * is %NULL-terminated as a string.
463 *
464 * Both the aim_tlv_t and the tlv->value pointer
465 * must be freed by the caller if non-%NULL.
466 *
467 */
468faim_export struct aim_tlv_t *aim_grabtlvstr(u_char *src)
9de3ca7e 469{
470 struct aim_tlv_t *dest = NULL;
471
472 dest = aim_createtlv();
473
474 dest->type = src[0] << 8;
475 dest->type += src[1];
476
477 dest->length = src[2] << 8;
478 dest->length += src[3];
479
480 dest->value = (u_char *) malloc((dest->length+1)*sizeof(u_char));
481 memset(dest->value, 0, (dest->length+1)*sizeof(u_char));
482
483 memcpy(dest->value, &(src[4]), dest->length*sizeof(u_char));
484 dest->value[dest->length] = '\0';
485
486 return dest;
487}
488
be67fdd0 489/**
490 * aim_puttlv - Write a aim_tlv_t into a data buffer
491 * @dest: Destination data buffer
492 * @newtlv: Source TLV structure
493 *
494 * Writes out the passed TLV structure into the buffer. No bounds
495 * checking is done on the output buffer.
496 *
497 * The passed aim_tlv_t is not freed. aim_freetlv() should
498 * still be called by the caller to free the structure.
499 *
500 */
501faim_export int aim_puttlv(u_char *dest, struct aim_tlv_t *newtlv)
9de3ca7e 502{
503 int i=0;
504
505 dest[i++] = newtlv->type >> 8;
506 dest[i++] = newtlv->type & 0x00FF;
507 dest[i++] = newtlv->length >> 8;
508 dest[i++] = newtlv->length & 0x00FF;
509 memcpy(&(dest[i]), newtlv->value, newtlv->length);
510 i+=newtlv->length;
511 return i;
512}
513
be67fdd0 514/**
515 * aim_createtlv - Generate an aim_tlv_t structure.
516 *
517 * Allocates an empty TLV structure and returns a pointer
518 * to it; %NULL on error.
519 *
520 */
521faim_export struct aim_tlv_t *aim_createtlv(void)
9de3ca7e 522{
be67fdd0 523 struct aim_tlv_t *newtlv;
524
525 if (!(newtlv = (struct aim_tlv_t *)malloc(sizeof(struct aim_tlv_t))))
526 return NULL;
9de3ca7e 527 memset(newtlv, 0, sizeof(struct aim_tlv_t));
528 return newtlv;
529}
530
be67fdd0 531/**
532 * aim_freetlv - Free a aim_tlv_t structure
533 * @oldtlv: TLV to be destroyed
534 *
535 * Frees both the TLV structure and the value portion.
536 *
537 */
538faim_export int aim_freetlv(struct aim_tlv_t **oldtlv)
9de3ca7e 539{
540 if (!oldtlv)
541 return -1;
542 if (!*oldtlv)
543 return -1;
544 if ((*oldtlv)->value)
545 free((*oldtlv)->value);
546 free(*(oldtlv));
547 (*oldtlv) = NULL;
548
549 return 0;
550}
551
be67fdd0 552/**
553 * aim_puttlv_16 - Write a two-byte TLV.
554 * @buf: Destination buffer
555 * @t: TLV type
556 * @v: Value
557 *
558 * Writes a TLV with a two-byte integer value portion.
559 *
560 */
561faim_export int aim_puttlv_16(u_char *buf, u_short t, u_short v)
9de3ca7e 562{
563 int curbyte=0;
564 curbyte += aimutil_put16(buf+curbyte, (u_short)(t&0xffff));
565 curbyte += aimutil_put16(buf+curbyte, (u_short)0x0002);
566 curbyte += aimutil_put16(buf+curbyte, (u_short)(v&0xffff));
567 return curbyte;
568}
01b59e1e 569
be67fdd0 570/**
571 * aim_puttlv_32 - Write a four-byte TLV.
572 * @buf: Destination buffer
573 * @t: TLV type
574 * @v: Value
575 *
576 * Writes a TLV with a four-byte integer value portion.
577 *
578 */
579faim_export int aim_puttlv_32(u_char *buf, u_short t, u_long v)
01b59e1e 580{
581 int curbyte=0;
582 curbyte += aimutil_put16(buf+curbyte, (u_short)(t&0xffff));
583 curbyte += aimutil_put16(buf+curbyte, (u_short)0x0004);
584 curbyte += aimutil_put32(buf+curbyte, (u_long)(v&0xffffffff));
585 return curbyte;
586}
587
be67fdd0 588/**
589 * aim_puttlv_str - Write a string TLV.
590 * @buf: Destination buffer
591 * @t: TLV type
592 * @l: Length of string
593 * @v: String to write
594 *
595 * Writes a TLV with a string value portion. (Only the first @l
596 * bytes of the passed string will be written, which should not
597 * include the terminating NULL.)
598 *
599 */
600faim_export int aim_puttlv_str(u_char *buf, u_short t, int l, char *v)
01b59e1e 601{
602 int curbyte;
01b59e1e 603
604 curbyte = 0;
605 curbyte += aimutil_put16(buf+curbyte, (u_short)(t&0xffff));
606 curbyte += aimutil_put16(buf+curbyte, (u_short)(l&0xffff));
0c20631f 607 if (v)
78b3fb13 608 memcpy(buf+curbyte, (unsigned char *)v, l);
01b59e1e 609 curbyte += l;
610 return curbyte;
611}
This page took 0.242656 seconds and 5 git commands to generate.