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