]>
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 | */ |
603fdcaa | 46 | faim_internal 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 | */ | |
603fdcaa | 98 | faim_internal 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 | */ | |
603fdcaa | 127 | faim_internal 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 | */ | |
603fdcaa | 149 | faim_internal 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 | */ | |
603fdcaa | 174 | faim_internal 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 | */ | |
603fdcaa | 215 | faim_internal 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 | */ | |
603fdcaa | 233 | faim_internal 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 | */ | |
603fdcaa | 264 | faim_internal 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 | ||
603fdcaa | 276 | faim_internal int aim_addtlvtochain_userinfo(aim_tlvlist_t **list, fu16_t type, struct aim_userinfo_s *ui) |
277 | { | |
278 | fu8_t buf[1024]; /* bleh */ | |
279 | aim_bstream_t bs; | |
280 | ||
281 | aim_bstream_init(&bs, buf, sizeof(buf)); | |
282 | ||
283 | aim_putuserinfo(&bs, ui); | |
284 | ||
285 | return aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf); | |
286 | } | |
287 | ||
355982c5 | 288 | /** |
289 | * aim_addtlvtochain_noval - Add a blank TLV to a TLV chain | |
290 | * @list: Destination chain | |
291 | * @type: TLV type to add | |
292 | * | |
293 | * Adds a TLV with a zero length to a TLV chain. | |
294 | * | |
295 | */ | |
d410cf58 | 296 | faim_internal int aim_addtlvtochain_noval(aim_tlvlist_t **list, const fu16_t t) |
355982c5 | 297 | { |
d410cf58 | 298 | return aim_addtlvtochain_raw(list, t, 0, NULL); |
299 | } | |
300 | ||
301 | /* | |
302 | * Note that the inner TLV chain will not be modifiable as a tlvchain once | |
303 | * it is written using this. Or rather, it can be, but updates won't be | |
304 | * made to this. | |
305 | * | |
306 | * XXX should probably support sublists for real. | |
307 | * | |
308 | * This is so neat. | |
309 | * | |
310 | */ | |
311 | faim_internal int aim_addtlvtochain_frozentlvlist(aim_tlvlist_t **list, fu16_t type, aim_tlvlist_t **tl) | |
312 | { | |
313 | fu8_t *buf; | |
314 | int buflen; | |
315 | aim_bstream_t bs; | |
316 | ||
317 | buflen = aim_sizetlvchain(tl); | |
318 | ||
319 | if (buflen <= 0) | |
320 | return 0; | |
321 | ||
322 | if (!(buf = malloc(buflen))) | |
323 | return 0; | |
324 | ||
325 | aim_bstream_init(&bs, buf, buflen); | |
326 | ||
327 | aim_writetlvchain(&bs, tl); | |
328 | ||
329 | aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf); | |
330 | ||
331 | free(buf); | |
332 | ||
333 | return buflen; | |
355982c5 | 334 | } |
335 | ||
be67fdd0 | 336 | /** |
337 | * aim_writetlvchain - Write a TLV chain into a data buffer. | |
338 | * @buf: Destination buffer | |
339 | * @buflen: Maximum number of bytes that will be written to buffer | |
340 | * @list: Source TLV chain | |
341 | * | |
342 | * Copies a TLV chain into a raw data buffer, writing only the number | |
343 | * of bytes specified. This operation does not free the chain; | |
344 | * aim_freetlvchain() must still be called to free up the memory used | |
345 | * by the chain structures. | |
346 | * | |
d410cf58 | 347 | * XXX clean this up, make better use of bstreams |
be67fdd0 | 348 | */ |
603fdcaa | 349 | faim_internal int aim_writetlvchain(aim_bstream_t *bs, aim_tlvlist_t **list) |
0e2be272 | 350 | { |
d410cf58 | 351 | int goodbuflen; |
352 | aim_tlvlist_t *cur; | |
353 | ||
354 | /* do an initial run to test total length */ | |
355 | for (cur = *list, goodbuflen = 0; cur; cur = cur->next) { | |
356 | goodbuflen += 2 + 2; /* type + len */ | |
357 | goodbuflen += cur->tlv->length; | |
358 | } | |
359 | ||
360 | if (goodbuflen > aim_bstream_empty(bs)) | |
361 | return 0; /* not enough buffer */ | |
362 | ||
363 | /* do the real write-out */ | |
364 | for (cur = *list; cur; cur = cur->next) { | |
365 | aimbs_put16(bs, cur->tlv->type); | |
366 | aimbs_put16(bs, cur->tlv->length); | |
367 | if (cur->tlv->length) | |
368 | aimbs_putraw(bs, cur->tlv->value, cur->tlv->length); | |
369 | } | |
370 | ||
371 | return 1; /* XXX this is a nonsensical return */ | |
0e2be272 | 372 | } |
373 | ||
374 | ||
be67fdd0 | 375 | /** |
376 | * aim_gettlv - Grab the Nth TLV of type type in the TLV list list. | |
377 | * @list: Source chain | |
378 | * @type: Requested TLV type | |
379 | * @nth: Index of TLV of type to get | |
380 | * | |
381 | * Returns a pointer to an aim_tlv_t of the specified type; | |
382 | * %NULL on error. The @nth parameter is specified starting at %1. | |
383 | * In most cases, there will be no more than one TLV of any type | |
384 | * in a chain. | |
385 | * | |
49c8a2fa | 386 | */ |
603fdcaa | 387 | faim_internal aim_tlv_t *aim_gettlv(aim_tlvlist_t *list, const fu16_t t, const int n) |
49c8a2fa | 388 | { |
d410cf58 | 389 | aim_tlvlist_t *cur; |
390 | int i; | |
391 | ||
392 | for (cur = list, i = 0; cur; cur = cur->next) { | |
393 | if (cur && cur->tlv) { | |
394 | if (cur->tlv->type == t) | |
395 | i++; | |
396 | if (i >= n) | |
397 | return cur->tlv; | |
398 | } | |
49c8a2fa | 399 | } |
d410cf58 | 400 | |
401 | return NULL; | |
49c8a2fa | 402 | } |
403 | ||
be67fdd0 | 404 | /** |
405 | * aim_gettlv_str - Retrieve the Nth TLV in chain as a string. | |
406 | * @list: Source TLV chain | |
407 | * @type: TLV type to search for | |
408 | * @nth: Index of TLV to return | |
409 | * | |
410 | * Same as aim_gettlv(), except that the return value is a %NULL- | |
411 | * terminated string instead of an aim_tlv_t. This is a | |
412 | * dynamic buffer and must be freed by the caller. | |
413 | * | |
414 | */ | |
603fdcaa | 415 | faim_internal char *aim_gettlv_str(aim_tlvlist_t *list, const fu16_t t, const int n) |
49c8a2fa | 416 | { |
d410cf58 | 417 | aim_tlv_t *tlv; |
418 | char *newstr; | |
419 | ||
420 | if (!(tlv = aim_gettlv(list, t, n))) | |
421 | return NULL; | |
49c8a2fa | 422 | |
d410cf58 | 423 | newstr = (char *) malloc(tlv->length + 1); |
424 | memcpy(newstr, tlv->value, tlv->length); | |
425 | *(newstr + tlv->length) = '\0'; | |
49c8a2fa | 426 | |
d410cf58 | 427 | return newstr; |
49c8a2fa | 428 | } |
429 | ||
355982c5 | 430 | /** |
431 | * aim_gettlv8 - Retrieve the Nth TLV in chain as a 8bit integer. | |
432 | * @list: Source TLV chain | |
433 | * @type: TLV type to search for | |
434 | * @nth: Index of TLV to return | |
435 | * | |
436 | * Same as aim_gettlv(), except that the return value is a | |
437 | * 8bit integer instead of an aim_tlv_t. | |
438 | * | |
439 | */ | |
d410cf58 | 440 | faim_internal fu8_t aim_gettlv8(aim_tlvlist_t *list, const fu16_t t, const int n) |
355982c5 | 441 | { |
d410cf58 | 442 | aim_tlv_t *tlv; |
355982c5 | 443 | |
d410cf58 | 444 | if (!(tlv = aim_gettlv(list, t, n))) |
445 | return 0; /* erm */ | |
446 | return aimutil_get8(tlv->value); | |
355982c5 | 447 | } |
448 | ||
449 | /** | |
450 | * aim_gettlv16 - Retrieve the Nth TLV in chain as a 16bit integer. | |
451 | * @list: Source TLV chain | |
452 | * @type: TLV type to search for | |
453 | * @nth: Index of TLV to return | |
454 | * | |
455 | * Same as aim_gettlv(), except that the return value is a | |
456 | * 16bit integer instead of an aim_tlv_t. | |
457 | * | |
458 | */ | |
d410cf58 | 459 | faim_internal fu16_t aim_gettlv16(aim_tlvlist_t *list, const fu16_t t, const int n) |
355982c5 | 460 | { |
d410cf58 | 461 | aim_tlv_t *tlv; |
355982c5 | 462 | |
d410cf58 | 463 | if (!(tlv = aim_gettlv(list, t, n))) |
464 | return 0; /* erm */ | |
465 | return aimutil_get16(tlv->value); | |
355982c5 | 466 | } |
467 | ||
468 | /** | |
469 | * aim_gettlv32 - Retrieve the Nth TLV in chain as a 32bit integer. | |
470 | * @list: Source TLV chain | |
471 | * @type: TLV type to search for | |
472 | * @nth: Index of TLV to return | |
473 | * | |
474 | * Same as aim_gettlv(), except that the return value is a | |
475 | * 32bit integer instead of an aim_tlv_t. | |
476 | * | |
477 | */ | |
d410cf58 | 478 | faim_internal fu32_t aim_gettlv32(aim_tlvlist_t *list, const fu16_t t, const int n) |
355982c5 | 479 | { |
d410cf58 | 480 | aim_tlv_t *tlv; |
355982c5 | 481 | |
d410cf58 | 482 | if (!(tlv = aim_gettlv(list, t, n))) |
483 | return 0; /* erm */ | |
484 | return aimutil_get32(tlv->value); | |
9de3ca7e | 485 | } |
486 | ||
d410cf58 | 487 | #if 0 |
355982c5 | 488 | /** |
489 | * aim_puttlv_8 - Write a one-byte TLV. | |
490 | * @buf: Destination buffer | |
491 | * @t: TLV type | |
492 | * @v: Value | |
493 | * | |
494 | * Writes a TLV with a one-byte integer value portion. | |
495 | * | |
496 | */ | |
d410cf58 | 497 | faim_export int aim_puttlv_8(fu8_t *buf, const fu16_t t, const fu8_t v) |
355982c5 | 498 | { |
d410cf58 | 499 | fu8_t v8[1]; |
355982c5 | 500 | |
d410cf58 | 501 | aimutil_put8(v8, v); |
355982c5 | 502 | |
d410cf58 | 503 | return aim_puttlv_raw(buf, t, 1, v8); |
355982c5 | 504 | } |
505 | ||
be67fdd0 | 506 | /** |
507 | * aim_puttlv_16 - Write a two-byte TLV. | |
508 | * @buf: Destination buffer | |
509 | * @t: TLV type | |
510 | * @v: Value | |
511 | * | |
512 | * Writes a TLV with a two-byte integer value portion. | |
513 | * | |
514 | */ | |
d410cf58 | 515 | faim_export int aim_puttlv_16(fu8_t *buf, const fu16_t t, const fu16_t v) |
9de3ca7e | 516 | { |
d410cf58 | 517 | fu8_t v16[2]; |
518 | ||
519 | aimutil_put16(v16, v); | |
520 | ||
521 | return aim_puttlv_raw(buf, t, 2, v16); | |
9de3ca7e | 522 | } |
01b59e1e | 523 | |
d410cf58 | 524 | |
be67fdd0 | 525 | /** |
526 | * aim_puttlv_32 - Write a four-byte TLV. | |
527 | * @buf: Destination buffer | |
528 | * @t: TLV type | |
529 | * @v: Value | |
530 | * | |
531 | * Writes a TLV with a four-byte integer value portion. | |
532 | * | |
533 | */ | |
d410cf58 | 534 | faim_export int aim_puttlv_32(fu8_t *buf, const fu16_t t, const fu32_t v) |
01b59e1e | 535 | { |
d410cf58 | 536 | fu8_t v32[4]; |
537 | ||
538 | aimutil_put32(v32, v); | |
539 | ||
540 | return aim_puttlv_raw(buf, t, 4, v32); | |
01b59e1e | 541 | } |
542 | ||
be67fdd0 | 543 | /** |
d410cf58 | 544 | * aim_puttlv_raw - Write a raw TLV. |
be67fdd0 | 545 | * @buf: Destination buffer |
546 | * @t: TLV type | |
547 | * @l: Length of string | |
548 | * @v: String to write | |
549 | * | |
d410cf58 | 550 | * Writes a TLV with a raw value portion. (Only the first @l |
551 | * bytes of the passed buffer will be written, which should not | |
552 | * include a terminating NULL.) | |
be67fdd0 | 553 | * |
554 | */ | |
d410cf58 | 555 | faim_export int aim_puttlv_raw(fu8_t *buf, const fu16_t t, const fu16_t l, const fu8_t *v) |
01b59e1e | 556 | { |
d410cf58 | 557 | int i; |
558 | ||
559 | i = aimutil_put16(buf, t); | |
560 | i += aimutil_put16(buf+i, l); | |
561 | if (l) | |
562 | memcpy(buf+i, v, l); | |
563 | i += l; | |
564 | ||
565 | return i; | |
01b59e1e | 566 | } |
d410cf58 | 567 | #endif |
568 |