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