| 1 |
|
| 2 #define FAIM_INTERNAL |
|
| 3 #include <aim.h> |
|
| 4 |
|
| 5 static aim_tlv_t *createtlv(fu16_t type, fu16_t length, fu8_t *value) |
|
| 6 { |
|
| 7 aim_tlv_t *ret; |
|
| 8 |
|
| 9 if (!(ret = (aim_tlv_t *)malloc(sizeof(aim_tlv_t)))) |
|
| 10 return NULL; |
|
| 11 ret->type = type; |
|
| 12 ret->length = length; |
|
| 13 ret->value = value; |
|
| 14 |
|
| 15 return ret; |
|
| 16 } |
|
| 17 |
|
| 18 static void freetlv(aim_tlv_t **oldtlv) |
|
| 19 { |
|
| 20 |
|
| 21 if (!oldtlv || !*oldtlv) |
|
| 22 return; |
|
| 23 |
|
| 24 free((*oldtlv)->value); |
|
| 25 free(*oldtlv); |
|
| 26 *oldtlv = NULL; |
|
| 27 |
|
| 28 return; |
|
| 29 } |
|
| 30 |
|
| 31 /** |
|
| 32 * Read a TLV chain from a 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_tlvlist_free() should |
|
| 37 * be called to free the dynamic substructures. |
|
| 38 * |
|
| 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 efficient as the in-place TLV parsing used in a couple places |
|
| 43 * in libfaim. |
|
| 44 * |
|
| 45 * @param bs Input bstream |
|
| 46 * @return Return the TLV chain read |
|
| 47 */ |
|
| 48 faim_internal aim_tlvlist_t *aim_tlvlist_read(aim_bstream_t *bs) |
|
| 49 { |
|
| 50 aim_tlvlist_t *list = NULL, *cur; |
|
| 51 |
|
| 52 while (aim_bstream_empty(bs) > 0) { |
|
| 53 fu16_t type, length; |
|
| 54 |
|
| 55 type = aimbs_get16(bs); |
|
| 56 length = aimbs_get16(bs); |
|
| 57 |
|
| 58 #if 0 /* temporarily disabled until I know if they're still doing it or not */ |
|
| 59 /* |
|
| 60 * Okay, so now AOL has decided that any TLV of |
|
| 61 * type 0x0013 can only be two bytes, despite |
|
| 62 * what the actual given length is. So here |
|
| 63 * we dump any invalid TLVs of that sort. Hopefully |
|
| 64 * there's no special cases to this special case. |
|
| 65 * - mid (30jun2000) |
|
| 66 */ |
|
| 67 if ((type == 0x0013) && (length != 0x0002)) |
|
| 68 length = 0x0002; |
|
| 69 #else |
|
| 70 if (0) |
|
| 71 ; |
|
| 72 #endif |
|
| 73 else { |
|
| 74 |
|
| 75 if (length > aim_bstream_empty(bs)) { |
|
| 76 aim_tlvlist_free(&list); |
|
| 77 return NULL; |
|
| 78 } |
|
| 79 |
|
| 80 cur = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t)); |
|
| 81 if (!cur) { |
|
| 82 aim_tlvlist_free(&list); |
|
| 83 return NULL; |
|
| 84 } |
|
| 85 |
|
| 86 memset(cur, 0, sizeof(aim_tlvlist_t)); |
|
| 87 |
|
| 88 cur->tlv = createtlv(type, length, NULL); |
|
| 89 if (!cur->tlv) { |
|
| 90 free(cur); |
|
| 91 aim_tlvlist_free(&list); |
|
| 92 return NULL; |
|
| 93 } |
|
| 94 if (cur->tlv->length > 0) { |
|
| 95 cur->tlv->value = aimbs_getraw(bs, length); |
|
| 96 if (!cur->tlv->value) { |
|
| 97 freetlv(&cur->tlv); |
|
| 98 free(cur); |
|
| 99 aim_tlvlist_free(&list); |
|
| 100 return NULL; |
|
| 101 } |
|
| 102 } |
|
| 103 |
|
| 104 cur->next = list; |
|
| 105 list = cur; |
|
| 106 } |
|
| 107 } |
|
| 108 |
|
| 109 return list; |
|
| 110 } |
|
| 111 |
|
| 112 /** |
|
| 113 * Read a TLV chain from a buffer. |
|
| 114 * |
|
| 115 * Reads and parses a series of TLV patterns from a data buffer; the |
|
| 116 * returned structure is manipulatable with the rest of the TLV |
|
| 117 * routines. When done with a TLV chain, aim_tlvlist_free() should |
|
| 118 * be called to free the dynamic substructures. |
|
| 119 * |
|
| 120 * XXX There should be a flag setable here to have the tlvlist contain |
|
| 121 * bstream references, so that at least the ->value portion of each |
|
| 122 * element doesn't need to be malloc/memcpy'd. This could prove to be |
|
| 123 * just as efficient as the in-place TLV parsing used in a couple places |
|
| 124 * in libfaim. |
|
| 125 * |
|
| 126 * @param bs Input bstream |
|
| 127 * @param num The max number of TLVs that will be read, or -1 if unlimited. |
|
| 128 * There are a number of places where you want to read in a tlvchain, |
|
| 129 * but the chain is not at the end of the SNAC, and the chain is |
|
| 130 * preceded by the number of TLVs. So you can limit that with this. |
|
| 131 * @return Return the TLV chain read |
|
| 132 */ |
|
| 133 faim_internal aim_tlvlist_t *aim_tlvlist_readnum(aim_bstream_t *bs, fu16_t num) |
|
| 134 { |
|
| 135 aim_tlvlist_t *list = NULL, *cur; |
|
| 136 |
|
| 137 while ((aim_bstream_empty(bs) > 0) && (num != 0)) { |
|
| 138 fu16_t type, length; |
|
| 139 |
|
| 140 type = aimbs_get16(bs); |
|
| 141 length = aimbs_get16(bs); |
|
| 142 |
|
| 143 if (length > aim_bstream_empty(bs)) { |
|
| 144 aim_tlvlist_free(&list); |
|
| 145 return NULL; |
|
| 146 } |
|
| 147 |
|
| 148 cur = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t)); |
|
| 149 if (!cur) { |
|
| 150 aim_tlvlist_free(&list); |
|
| 151 return NULL; |
|
| 152 } |
|
| 153 |
|
| 154 memset(cur, 0, sizeof(aim_tlvlist_t)); |
|
| 155 |
|
| 156 cur->tlv = createtlv(type, length, NULL); |
|
| 157 if (!cur->tlv) { |
|
| 158 free(cur); |
|
| 159 aim_tlvlist_free(&list); |
|
| 160 return NULL; |
|
| 161 } |
|
| 162 if (cur->tlv->length > 0) { |
|
| 163 cur->tlv->value = aimbs_getraw(bs, length); |
|
| 164 if (!cur->tlv->value) { |
|
| 165 freetlv(&cur->tlv); |
|
| 166 free(cur); |
|
| 167 aim_tlvlist_free(&list); |
|
| 168 return NULL; |
|
| 169 } |
|
| 170 } |
|
| 171 |
|
| 172 if (num > 0) |
|
| 173 num--; |
|
| 174 cur->next = list; |
|
| 175 list = cur; |
|
| 176 } |
|
| 177 |
|
| 178 return list; |
|
| 179 } |
|
| 180 |
|
| 181 /** |
|
| 182 * Read a TLV chain from a buffer. |
|
| 183 * |
|
| 184 * Reads and parses a series of TLV patterns from a data buffer; the |
|
| 185 * returned structure is manipulatable with the rest of the TLV |
|
| 186 * routines. When done with a TLV chain, aim_tlvlist_free() should |
|
| 187 * be called to free the dynamic substructures. |
|
| 188 * |
|
| 189 * XXX There should be a flag setable here to have the tlvlist contain |
|
| 190 * bstream references, so that at least the ->value portion of each |
|
| 191 * element doesn't need to be malloc/memcpy'd. This could prove to be |
|
| 192 * just as efficient as the in-place TLV parsing used in a couple places |
|
| 193 * in libfaim. |
|
| 194 * |
|
| 195 * @param bs Input bstream |
|
| 196 * @param len The max length in bytes that will be read. |
|
| 197 * There are a number of places where you want to read in a tlvchain, |
|
| 198 * but the chain is not at the end of the SNAC, and the chain is |
|
| 199 * preceded by the length of the TLVs. So you can limit that with this. |
|
| 200 * @return Return the TLV chain read |
|
| 201 */ |
|
| 202 faim_internal aim_tlvlist_t *aim_tlvlist_readlen(aim_bstream_t *bs, fu16_t len) |
|
| 203 { |
|
| 204 aim_tlvlist_t *list = NULL, *cur; |
|
| 205 |
|
| 206 while ((aim_bstream_empty(bs) > 0) && (len > 0)) { |
|
| 207 fu16_t type, length; |
|
| 208 |
|
| 209 type = aimbs_get16(bs); |
|
| 210 length = aimbs_get16(bs); |
|
| 211 |
|
| 212 if (length > aim_bstream_empty(bs)) { |
|
| 213 aim_tlvlist_free(&list); |
|
| 214 return NULL; |
|
| 215 } |
|
| 216 |
|
| 217 cur = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t)); |
|
| 218 if (!cur) { |
|
| 219 aim_tlvlist_free(&list); |
|
| 220 return NULL; |
|
| 221 } |
|
| 222 |
|
| 223 memset(cur, 0, sizeof(aim_tlvlist_t)); |
|
| 224 |
|
| 225 cur->tlv = createtlv(type, length, NULL); |
|
| 226 if (!cur->tlv) { |
|
| 227 free(cur); |
|
| 228 aim_tlvlist_free(&list); |
|
| 229 return NULL; |
|
| 230 } |
|
| 231 if (cur->tlv->length > 0) { |
|
| 232 cur->tlv->value = aimbs_getraw(bs, length); |
|
| 233 if (!cur->tlv->value) { |
|
| 234 freetlv(&cur->tlv); |
|
| 235 free(cur); |
|
| 236 aim_tlvlist_free(&list); |
|
| 237 return NULL; |
|
| 238 } |
|
| 239 } |
|
| 240 |
|
| 241 len -= aim_tlvlist_size(&cur); |
|
| 242 cur->next = list; |
|
| 243 list = cur; |
|
| 244 } |
|
| 245 |
|
| 246 return list; |
|
| 247 } |
|
| 248 |
|
| 249 /** |
|
| 250 * Duplicate a TLV chain. |
|
| 251 * This is pretty self explanatory. |
|
| 252 * |
|
| 253 * @param orig The TLV chain you want to make a copy of. |
|
| 254 * @return A newly allocated TLV chain. |
|
| 255 */ |
|
| 256 faim_internal aim_tlvlist_t *aim_tlvlist_copy(aim_tlvlist_t *orig) |
|
| 257 { |
|
| 258 aim_tlvlist_t *new = NULL; |
|
| 259 |
|
| 260 while (orig) { |
|
| 261 aim_tlvlist_add_raw(&new, orig->tlv->type, orig->tlv->length, orig->tlv->value); |
|
| 262 orig = orig->next; |
|
| 263 } |
|
| 264 |
|
| 265 return new; |
|
| 266 } |
|
| 267 |
|
| 268 /* |
|
| 269 * Compare two TLV lists for equality. This probably is not the most |
|
| 270 * efficient way to do this. |
|
| 271 * |
|
| 272 * @param one One of the TLV chains to compare. |
|
| 273 * @param two The other TLV chain to compare. |
|
| 274 * @return Return 0 if the lists are the same, return 1 if they are different. |
|
| 275 */ |
|
| 276 faim_internal int aim_tlvlist_cmp(aim_tlvlist_t *one, aim_tlvlist_t *two) |
|
| 277 { |
|
| 278 aim_bstream_t bs1, bs2; |
|
| 279 |
|
| 280 if (aim_tlvlist_size(&one) != aim_tlvlist_size(&two)) |
|
| 281 return 1; |
|
| 282 |
|
| 283 aim_bstream_init(&bs1, ((fu8_t *)malloc(aim_tlvlist_size(&one)*sizeof(fu8_t))), aim_tlvlist_size(&one)); |
|
| 284 aim_bstream_init(&bs2, ((fu8_t *)malloc(aim_tlvlist_size(&two)*sizeof(fu8_t))), aim_tlvlist_size(&two)); |
|
| 285 |
|
| 286 aim_tlvlist_write(&bs1, &one); |
|
| 287 aim_tlvlist_write(&bs2, &two); |
|
| 288 |
|
| 289 if (memcmp(bs1.data, bs2.data, bs1.len)) { |
|
| 290 free(bs1.data); |
|
| 291 free(bs2.data); |
|
| 292 return 1; |
|
| 293 } |
|
| 294 |
|
| 295 free(bs1.data); |
|
| 296 free(bs2.data); |
|
| 297 |
|
| 298 return 0; |
|
| 299 } |
|
| 300 |
|
| 301 /** |
|
| 302 * Free a TLV chain structure |
|
| 303 * |
|
| 304 * Walks the list of TLVs in the passed TLV chain and |
|
| 305 * frees each one. Note that any references to this data |
|
| 306 * should be removed before calling this. |
|
| 307 * |
|
| 308 * @param list Chain to be freed |
|
| 309 */ |
|
| 310 faim_internal void aim_tlvlist_free(aim_tlvlist_t **list) |
|
| 311 { |
|
| 312 aim_tlvlist_t *cur; |
|
| 313 |
|
| 314 if (!list || !*list) |
|
| 315 return; |
|
| 316 |
|
| 317 for (cur = *list; cur; ) { |
|
| 318 aim_tlvlist_t *tmp; |
|
| 319 |
|
| 320 freetlv(&cur->tlv); |
|
| 321 |
|
| 322 tmp = cur->next; |
|
| 323 free(cur); |
|
| 324 cur = tmp; |
|
| 325 } |
|
| 326 |
|
| 327 list = NULL; |
|
| 328 |
|
| 329 return; |
|
| 330 } |
|
| 331 |
|
| 332 /** |
|
| 333 * Count the number of TLVs in a chain. |
|
| 334 * |
|
| 335 * @param list Chain to be counted. |
|
| 336 * @return The number of TLVs stored in the passed chain. |
|
| 337 */ |
|
| 338 faim_internal int aim_tlvlist_count(aim_tlvlist_t **list) |
|
| 339 { |
|
| 340 aim_tlvlist_t *cur; |
|
| 341 int count; |
|
| 342 |
|
| 343 if (!list || !*list) |
|
| 344 return 0; |
|
| 345 |
|
| 346 for (cur = *list, count = 0; cur; cur = cur->next) |
|
| 347 count++; |
|
| 348 |
|
| 349 return count; |
|
| 350 } |
|
| 351 |
|
| 352 /** |
|
| 353 * Count the number of bytes in a TLV chain. |
|
| 354 * |
|
| 355 * @param list Chain to be sized |
|
| 356 * @return The number of bytes that would be needed to |
|
| 357 * write the passed TLV chain to a data buffer. |
|
| 358 */ |
|
| 359 faim_internal int aim_tlvlist_size(aim_tlvlist_t **list) |
|
| 360 { |
|
| 361 aim_tlvlist_t *cur; |
|
| 362 int size; |
|
| 363 |
|
| 364 if (!list || !*list) |
|
| 365 return 0; |
|
| 366 |
|
| 367 for (cur = *list, size = 0; cur; cur = cur->next) |
|
| 368 size += (4 + cur->tlv->length); |
|
| 369 |
|
| 370 return size; |
|
| 371 } |
|
| 372 |
|
| 373 /** |
|
| 374 * Adds the passed string as a TLV element of the passed type |
|
| 375 * to the TLV chain. |
|
| 376 * |
|
| 377 * @param list Desination chain (%NULL pointer if empty). |
|
| 378 * @param type TLV type. |
|
| 379 * @param length Length of string to add (not including %NULL). |
|
| 380 * @param value String to add. |
|
| 381 * @return The size of the value added. |
|
| 382 */ |
|
| 383 faim_internal int aim_tlvlist_add_raw(aim_tlvlist_t **list, const fu16_t type, const fu16_t length, const fu8_t *value) |
|
| 384 { |
|
| 385 aim_tlvlist_t *newtlv, *cur; |
|
| 386 |
|
| 387 if (list == NULL) |
|
| 388 return 0; |
|
| 389 |
|
| 390 if (!(newtlv = (aim_tlvlist_t *)malloc(sizeof(aim_tlvlist_t)))) |
|
| 391 return 0; |
|
| 392 memset(newtlv, 0x00, sizeof(aim_tlvlist_t)); |
|
| 393 |
|
| 394 if (!(newtlv->tlv = createtlv(type, length, NULL))) { |
|
| 395 free(newtlv); |
|
| 396 return 0; |
|
| 397 } |
|
| 398 if (newtlv->tlv->length > 0) { |
|
| 399 newtlv->tlv->value = (fu8_t *)malloc(newtlv->tlv->length); |
|
| 400 memcpy(newtlv->tlv->value, value, newtlv->tlv->length); |
|
| 401 } |
|
| 402 |
|
| 403 if (!*list) |
|
| 404 *list = newtlv; |
|
| 405 else { |
|
| 406 for(cur = *list; cur->next; cur = cur->next) |
|
| 407 ; |
|
| 408 cur->next = newtlv; |
|
| 409 } |
|
| 410 |
|
| 411 return newtlv->tlv->length; |
|
| 412 } |
|
| 413 |
|
| 414 /** |
|
| 415 * Add a one byte integer to a TLV chain. |
|
| 416 * |
|
| 417 * @param list Destination chain. |
|
| 418 * @param type TLV type to add. |
|
| 419 * @param value Value to add. |
|
| 420 * @return The size of the value added. |
|
| 421 */ |
|
| 422 faim_internal int aim_tlvlist_add_8(aim_tlvlist_t **list, const fu16_t type, const fu8_t value) |
|
| 423 { |
|
| 424 fu8_t v8[1]; |
|
| 425 |
|
| 426 aimutil_put8(v8, value); |
|
| 427 |
|
| 428 return aim_tlvlist_add_raw(list, type, 1, v8); |
|
| 429 } |
|
| 430 |
|
| 431 /** |
|
| 432 * Add a two byte integer to a TLV chain. |
|
| 433 * |
|
| 434 * @param list Destination chain. |
|
| 435 * @param type TLV type to add. |
|
| 436 * @param value Value to add. |
|
| 437 * @return The size of the value added. |
|
| 438 */ |
|
| 439 faim_internal int aim_tlvlist_add_16(aim_tlvlist_t **list, const fu16_t type, const fu16_t value) |
|
| 440 { |
|
| 441 fu8_t v16[2]; |
|
| 442 |
|
| 443 aimutil_put16(v16, value); |
|
| 444 |
|
| 445 return aim_tlvlist_add_raw(list, type, 2, v16); |
|
| 446 } |
|
| 447 |
|
| 448 /** |
|
| 449 * Add a four byte integer to a TLV chain. |
|
| 450 * |
|
| 451 * @param list Destination chain. |
|
| 452 * @param type TLV type to add. |
|
| 453 * @param value Value to add. |
|
| 454 * @return The size of the value added. |
|
| 455 */ |
|
| 456 faim_internal int aim_tlvlist_add_32(aim_tlvlist_t **list, const fu16_t type, const fu32_t value) |
|
| 457 { |
|
| 458 fu8_t v32[4]; |
|
| 459 |
|
| 460 aimutil_put32(v32, value); |
|
| 461 |
|
| 462 return aim_tlvlist_add_raw(list, type, 4, v32); |
|
| 463 } |
|
| 464 |
|
| 465 /** |
|
| 466 * Add a string to a TLV chain. |
|
| 467 * |
|
| 468 * @param list Destination chain. |
|
| 469 * @param type TLV type to add. |
|
| 470 * @param value Value to add. |
|
| 471 * @return The size of the value added. |
|
| 472 */ |
|
| 473 faim_internal int aim_tlvlist_add_str(aim_tlvlist_t **list, const fu16_t type, const char *value) |
|
| 474 { |
|
| 475 return aim_tlvlist_add_raw(list, type, strlen(value), (fu8_t *)value); |
|
| 476 } |
|
| 477 |
|
| 478 /** |
|
| 479 * Adds a block of capability blocks to a TLV chain. The bitfield |
|
| 480 * passed in should be a bitwise %OR of any of the %AIM_CAPS constants: |
|
| 481 * |
|
| 482 * %AIM_CAPS_BUDDYICON Supports Buddy Icons |
|
| 483 * %AIM_CAPS_TALK Supports Voice Chat |
|
| 484 * %AIM_CAPS_IMIMAGE Supports DirectIM/IMImage |
|
| 485 * %AIM_CAPS_CHAT Supports Chat |
|
| 486 * %AIM_CAPS_GETFILE Supports Get File functions |
|
| 487 * %AIM_CAPS_SENDFILE Supports Send File functions |
|
| 488 * |
|
| 489 * @param list Destination chain |
|
| 490 * @param type TLV type to add |
|
| 491 * @param caps Bitfield of capability flags to send |
|
| 492 * @return The size of the value added. |
|
| 493 */ |
|
| 494 faim_internal int aim_tlvlist_add_caps(aim_tlvlist_t **list, const fu16_t type, const fu32_t caps) |
|
| 495 { |
|
| 496 fu8_t buf[16*16]; /* XXX icky fixed length buffer */ |
|
| 497 aim_bstream_t bs; |
|
| 498 |
|
| 499 if (!caps) |
|
| 500 return 0; /* nothing there anyway */ |
|
| 501 |
|
| 502 aim_bstream_init(&bs, buf, sizeof(buf)); |
|
| 503 |
|
| 504 aimbs_putcaps(&bs, caps); |
|
| 505 |
|
| 506 return aim_tlvlist_add_raw(list, type, aim_bstream_curpos(&bs), buf); |
|
| 507 } |
|
| 508 |
|
| 509 /** |
|
| 510 * Adds the given userinfo struct to a TLV chain. |
|
| 511 * |
|
| 512 * @param list Destination chain. |
|
| 513 * @param type TLV type to add. |
|
| 514 * @return The size of the value added. |
|
| 515 */ |
|
| 516 faim_internal int aim_tlvlist_add_userinfo(aim_tlvlist_t **list, fu16_t type, aim_userinfo_t *userinfo) |
|
| 517 { |
|
| 518 fu8_t buf[1024]; /* bleh */ |
|
| 519 aim_bstream_t bs; |
|
| 520 |
|
| 521 aim_bstream_init(&bs, buf, sizeof(buf)); |
|
| 522 |
|
| 523 aim_putuserinfo(&bs, userinfo); |
|
| 524 |
|
| 525 return aim_tlvlist_add_raw(list, type, aim_bstream_curpos(&bs), buf); |
|
| 526 } |
|
| 527 |
|
| 528 /** |
|
| 529 * Adds the given chatroom info to a TLV chain. |
|
| 530 * |
|
| 531 * @param list Destination chain. |
|
| 532 * @param type TLV type to add. |
|
| 533 * @param roomname The name of the chat. |
|
| 534 * @param instance The instance. |
|
| 535 * @return The size of the value added. |
|
| 536 */ |
|
| 537 faim_internal int aim_tlvlist_add_chatroom(aim_tlvlist_t **list, fu16_t type, fu16_t exchange, const char *roomname, fu16_t instance) |
|
| 538 { |
|
| 539 fu8_t *buf; |
|
| 540 int len; |
|
| 541 aim_bstream_t bs; |
|
| 542 |
|
| 543 len = 2 + 1 + strlen(roomname) + 2; |
|
| 544 |
|
| 545 if (!(buf = malloc(len))) |
|
| 546 return 0; |
|
| 547 |
|
| 548 aim_bstream_init(&bs, buf, len); |
|
| 549 |
|
| 550 aimbs_put16(&bs, exchange); |
|
| 551 aimbs_put8(&bs, strlen(roomname)); |
|
| 552 aimbs_putstr(&bs, roomname); |
|
| 553 aimbs_put16(&bs, instance); |
|
| 554 |
|
| 555 len = aim_tlvlist_add_raw(list, type, aim_bstream_curpos(&bs), buf); |
|
| 556 |
|
| 557 free(buf); |
|
| 558 |
|
| 559 return len; |
|
| 560 } |
|
| 561 |
|
| 562 /** |
|
| 563 * Adds a TLV with a zero length to a TLV chain. |
|
| 564 * |
|
| 565 * @param list Destination chain. |
|
| 566 * @param type TLV type to add. |
|
| 567 * @return The size of the value added. |
|
| 568 */ |
|
| 569 faim_internal int aim_tlvlist_add_noval(aim_tlvlist_t **list, const fu16_t type) |
|
| 570 { |
|
| 571 return aim_tlvlist_add_raw(list, type, 0, NULL); |
|
| 572 } |
|
| 573 |
|
| 574 /* |
|
| 575 * Note that the inner TLV chain will not be modifiable as a tlvchain once |
|
| 576 * it is written using this. Or rather, it can be, but updates won't be |
|
| 577 * made to this. |
|
| 578 * |
|
| 579 * XXX should probably support sublists for real. |
|
| 580 * |
|
| 581 * This is so neat. |
|
| 582 * |
|
| 583 * @param list Destination chain. |
|
| 584 * @param type TLV type to add. |
|
| 585 * @param t1 The TLV chain you want to write. |
|
| 586 * @return The number of bytes written to the destination TLV chain. |
|
| 587 * 0 is returned if there was an error or if the destination |
|
| 588 * TLV chain has length 0. |
|
| 589 */ |
|
| 590 faim_internal int aim_tlvlist_add_frozentlvlist(aim_tlvlist_t **list, fu16_t type, aim_tlvlist_t **tl) |
|
| 591 { |
|
| 592 fu8_t *buf; |
|
| 593 int buflen; |
|
| 594 aim_bstream_t bs; |
|
| 595 |
|
| 596 buflen = aim_tlvlist_size(tl); |
|
| 597 |
|
| 598 if (buflen <= 0) |
|
| 599 return 0; |
|
| 600 |
|
| 601 if (!(buf = malloc(buflen))) |
|
| 602 return 0; |
|
| 603 |
|
| 604 aim_bstream_init(&bs, buf, buflen); |
|
| 605 |
|
| 606 aim_tlvlist_write(&bs, tl); |
|
| 607 |
|
| 608 aim_tlvlist_add_raw(list, type, aim_bstream_curpos(&bs), buf); |
|
| 609 |
|
| 610 free(buf); |
|
| 611 |
|
| 612 return buflen; |
|
| 613 } |
|
| 614 |
|
| 615 /** |
|
| 616 * Substitute a TLV of a given type with a new TLV of the same type. If |
|
| 617 * you attempt to replace a TLV that does not exist, this function will |
|
| 618 * just add a new TLV as if you called aim_tlvlist_add_raw(). |
|
| 619 * |
|
| 620 * @param list Desination chain (%NULL pointer if empty). |
|
| 621 * @param type TLV type. |
|
| 622 * @param length Length of string to add (not including %NULL). |
|
| 623 * @param value String to add. |
|
| 624 * @return The length of the TLV. |
|
| 625 */ |
|
| 626 faim_internal int aim_tlvlist_replace_raw(aim_tlvlist_t **list, const fu16_t type, const fu16_t length, const fu8_t *value) |
|
| 627 { |
|
| 628 aim_tlvlist_t *cur; |
|
| 629 |
|
| 630 if (list == NULL) |
|
| 631 return 0; |
|
| 632 |
|
| 633 for (cur = *list; ((cur != NULL) && (cur->tlv->type != type)); cur = cur->next); |
|
| 634 if (cur == NULL) |
|
| 635 return aim_tlvlist_add_raw(list, type, length, value); |
|
| 636 |
|
| 637 free(cur->tlv->value); |
|
| 638 cur->tlv->length = length; |
|
| 639 if (cur->tlv->length > 0) { |
|
| 640 cur->tlv->value = (fu8_t *)malloc(cur->tlv->length); |
|
| 641 memcpy(cur->tlv->value, value, cur->tlv->length); |
|
| 642 } else |
|
| 643 cur->tlv->value = NULL; |
|
| 644 |
|
| 645 return cur->tlv->length; |
|
| 646 } |
|
| 647 |
|
| 648 /** |
|
| 649 * Substitute a TLV of a given type with a new TLV of the same type. If |
|
| 650 * you attempt to replace a TLV that does not exist, this function will |
|
| 651 * just add a new TLV as if you called aim_tlvlist_add_str(). |
|
| 652 * |
|
| 653 * @param list Desination chain (%NULL pointer if empty). |
|
| 654 * @param type TLV type. |
|
| 655 * @param str String to add. |
|
| 656 * @return The length of the TLV. |
|
| 657 */ |
|
| 658 faim_internal int aim_tlvlist_replace_str(aim_tlvlist_t **list, const fu16_t type, const char *str) |
|
| 659 { |
|
| 660 return aim_tlvlist_replace_raw(list, type, strlen(str), (const guchar *)str); |
|
| 661 } |
|
| 662 |
|
| 663 /** |
|
| 664 * Substitute a TLV of a given type with a new TLV of the same type. If |
|
| 665 * you attempt to replace a TLV that does not exist, this function will |
|
| 666 * just add a new TLV as if you called aim_tlvlist_add_raw(). |
|
| 667 * |
|
| 668 * @param list Desination chain (%NULL pointer if empty). |
|
| 669 * @param type TLV type. |
|
| 670 * @return The length of the TLV. |
|
| 671 */ |
|
| 672 faim_internal int aim_tlvlist_replace_noval(aim_tlvlist_t **list, const fu16_t type) |
|
| 673 { |
|
| 674 return aim_tlvlist_replace_raw(list, type, 0, NULL); |
|
| 675 } |
|
| 676 |
|
| 677 /** |
|
| 678 * Substitute a TLV of a given type with a new TLV of the same type. If |
|
| 679 * you attempt to replace a TLV that does not exist, this function will |
|
| 680 * just add a new TLV as if you called aim_tlvlist_add_raw(). |
|
| 681 * |
|
| 682 * @param list Desination chain (%NULL pointer if empty). |
|
| 683 * @param type TLV type. |
|
| 684 * @param value 8 bit value to add. |
|
| 685 * @return The length of the TLV. |
|
| 686 */ |
|
| 687 faim_internal int aim_tlvlist_replace_8(aim_tlvlist_t **list, const fu16_t type, const fu8_t value) |
|
| 688 { |
|
| 689 fu8_t v8[1]; |
|
| 690 |
|
| 691 aimutil_put8(v8, value); |
|
| 692 |
|
| 693 return aim_tlvlist_replace_raw(list, type, 1, v8); |
|
| 694 } |
|
| 695 |
|
| 696 /** |
|
| 697 * Substitute a TLV of a given type with a new TLV of the same type. If |
|
| 698 * you attempt to replace a TLV that does not exist, this function will |
|
| 699 * just add a new TLV as if you called aim_tlvlist_add_raw(). |
|
| 700 * |
|
| 701 * @param list Desination chain (%NULL pointer if empty). |
|
| 702 * @param type TLV type. |
|
| 703 * @param value 32 bit value to add. |
|
| 704 * @return The length of the TLV. |
|
| 705 */ |
|
| 706 faim_internal int aim_tlvlist_replace_32(aim_tlvlist_t **list, const fu16_t type, const fu32_t value) |
|
| 707 { |
|
| 708 fu8_t v32[4]; |
|
| 709 |
|
| 710 aimutil_put32(v32, value); |
|
| 711 |
|
| 712 return aim_tlvlist_replace_raw(list, type, 4, v32); |
|
| 713 } |
|
| 714 |
|
| 715 /** |
|
| 716 * Remove a TLV of a given type. If you attempt to remove a TLV that |
|
| 717 * does not exist, nothing happens. |
|
| 718 * |
|
| 719 * @param list Desination chain (%NULL pointer if empty). |
|
| 720 * @param type TLV type. |
|
| 721 */ |
|
| 722 faim_internal void aim_tlvlist_remove(aim_tlvlist_t **list, const fu16_t type) |
|
| 723 { |
|
| 724 aim_tlvlist_t *del; |
|
| 725 |
|
| 726 if (!list || !(*list)) |
|
| 727 return; |
|
| 728 |
|
| 729 /* Remove the item from the list */ |
|
| 730 if ((*list)->tlv->type == type) { |
|
| 731 del = *list; |
|
| 732 *list = (*list)->next; |
|
| 733 } else { |
|
| 734 aim_tlvlist_t *cur; |
|
| 735 for (cur=*list; (cur->next && (cur->next->tlv->type!=type)); cur=cur->next); |
|
| 736 if (!cur->next) |
|
| 737 return; |
|
| 738 del = cur->next; |
|
| 739 cur->next = del->next; |
|
| 740 } |
|
| 741 |
|
| 742 /* Free the removed item */ |
|
| 743 free(del->tlv->value); |
|
| 744 free(del->tlv); |
|
| 745 free(del); |
|
| 746 } |
|
| 747 |
|
| 748 /** |
|
| 749 * Write a TLV chain into a data buffer. |
|
| 750 * |
|
| 751 * Copies a TLV chain into a raw data buffer, writing only the number |
|
| 752 * of bytes specified. This operation does not free the chain; |
|
| 753 * aim_tlvlist_free() must still be called to free up the memory used |
|
| 754 * by the chain structures. |
|
| 755 * |
|
| 756 * XXX clean this up, make better use of bstreams |
|
| 757 * |
|
| 758 * @param bs Input bstream |
|
| 759 * @param list Source TLV chain |
|
| 760 * @return Return 0 if the destination bstream is too small. |
|
| 761 */ |
|
| 762 faim_internal int aim_tlvlist_write(aim_bstream_t *bs, aim_tlvlist_t **list) |
|
| 763 { |
|
| 764 int goodbuflen; |
|
| 765 aim_tlvlist_t *cur; |
|
| 766 |
|
| 767 /* do an initial run to test total length */ |
|
| 768 goodbuflen = aim_tlvlist_size(list); |
|
| 769 |
|
| 770 if (goodbuflen > aim_bstream_empty(bs)) |
|
| 771 return 0; /* not enough buffer */ |
|
| 772 |
|
| 773 /* do the real write-out */ |
|
| 774 for (cur = *list; cur; cur = cur->next) { |
|
| 775 aimbs_put16(bs, cur->tlv->type); |
|
| 776 aimbs_put16(bs, cur->tlv->length); |
|
| 777 if (cur->tlv->length) |
|
| 778 aimbs_putraw(bs, cur->tlv->value, cur->tlv->length); |
|
| 779 } |
|
| 780 |
|
| 781 return 1; /* XXX this is a nonsensical return */ |
|
| 782 } |
|
| 783 |
|
| 784 |
|
| 785 /** |
|
| 786 * Grab the Nth TLV of type type in the TLV list list. |
|
| 787 * |
|
| 788 * Returns a pointer to an aim_tlv_t of the specified type; |
|
| 789 * %NULL on error. The @nth parameter is specified starting at %1. |
|
| 790 * In most cases, there will be no more than one TLV of any type |
|
| 791 * in a chain. |
|
| 792 * |
|
| 793 * @param list Source chain. |
|
| 794 * @param type Requested TLV type. |
|
| 795 * @param nth Index of TLV of type to get. |
|
| 796 * @return The TLV you were looking for, or NULL if one could not be found. |
|
| 797 */ |
|
| 798 faim_internal aim_tlv_t *aim_tlv_gettlv(aim_tlvlist_t *list, const fu16_t type, const int nth) |
|
| 799 { |
|
| 800 aim_tlvlist_t *cur; |
|
| 801 int i; |
|
| 802 |
|
| 803 for (cur = list, i = 0; cur; cur = cur->next) { |
|
| 804 if (cur && cur->tlv) { |
|
| 805 if (cur->tlv->type == type) |
|
| 806 i++; |
|
| 807 if (i >= nth) |
|
| 808 return cur->tlv; |
|
| 809 } |
|
| 810 } |
|
| 811 |
|
| 812 return NULL; |
|
| 813 } |
|
| 814 |
|
| 815 /** |
|
| 816 * Get the length of the data of the nth TLV in the given TLV chain. |
|
| 817 * |
|
| 818 * @param list Source chain. |
|
| 819 * @param type Requested TLV type. |
|
| 820 * @param nth Index of TLV of type to get. |
|
| 821 * @return The length of the data in this TLV, or -1 if the TLV could not be |
|
| 822 * found. Unless -1 is returned, this value will be 2 bytes. |
|
| 823 */ |
|
| 824 faim_internal int aim_tlv_getlength(aim_tlvlist_t *list, const fu16_t type, const int nth) |
|
| 825 { |
|
| 826 aim_tlvlist_t *cur; |
|
| 827 int i; |
|
| 828 |
|
| 829 for (cur = list, i = 0; cur; cur = cur->next) { |
|
| 830 if (cur && cur->tlv) { |
|
| 831 if (cur->tlv->type == type) |
|
| 832 i++; |
|
| 833 if (i >= nth) |
|
| 834 return cur->tlv->length; |
|
| 835 } |
|
| 836 } |
|
| 837 |
|
| 838 return -1; |
|
| 839 } |
|
| 840 |
|
| 841 /** |
|
| 842 * Retrieve the data from the nth TLV in the given TLV chain as a string. |
|
| 843 * |
|
| 844 * @param list Source TLV chain. |
|
| 845 * @param type TLV type to search for. |
|
| 846 * @param nth Index of TLV to return. |
|
| 847 * @return The value of the TLV you were looking for, or NULL if one could |
|
| 848 * not be found. This is a dynamic buffer and must be freed by the |
|
| 849 * caller. |
|
| 850 */ |
|
| 851 faim_internal char *aim_tlv_getstr(aim_tlvlist_t *list, const fu16_t type, const int nth) |
|
| 852 { |
|
| 853 aim_tlv_t *tlv; |
|
| 854 char *newstr; |
|
| 855 |
|
| 856 if (!(tlv = aim_tlv_gettlv(list, type, nth))) |
|
| 857 return NULL; |
|
| 858 |
|
| 859 newstr = (char *) malloc(tlv->length + 1); |
|
| 860 memcpy(newstr, tlv->value, tlv->length); |
|
| 861 newstr[tlv->length] = '\0'; |
|
| 862 |
|
| 863 return newstr; |
|
| 864 } |
|
| 865 |
|
| 866 /** |
|
| 867 * Retrieve the data from the nth TLV in the given TLV chain as an 8bit |
|
| 868 * integer. |
|
| 869 * |
|
| 870 * @param list Source TLV chain. |
|
| 871 * @param type TLV type to search for. |
|
| 872 * @param nth Index of TLV to return. |
|
| 873 * @return The value the TLV you were looking for, or 0 if one could |
|
| 874 * not be found. |
|
| 875 */ |
|
| 876 faim_internal fu8_t aim_tlv_get8(aim_tlvlist_t *list, const fu16_t type, const int nth) |
|
| 877 { |
|
| 878 aim_tlv_t *tlv; |
|
| 879 |
|
| 880 if (!(tlv = aim_tlv_gettlv(list, type, nth))) |
|
| 881 return 0; /* erm */ |
|
| 882 return aimutil_get8(tlv->value); |
|
| 883 } |
|
| 884 |
|
| 885 /** |
|
| 886 * Retrieve the data from the nth TLV in the given TLV chain as a 16bit |
|
| 887 * integer. |
|
| 888 * |
|
| 889 * @param list Source TLV chain. |
|
| 890 * @param type TLV type to search for. |
|
| 891 * @param nth Index of TLV to return. |
|
| 892 * @return The value the TLV you were looking for, or 0 if one could |
|
| 893 * not be found. |
|
| 894 */ |
|
| 895 faim_internal fu16_t aim_tlv_get16(aim_tlvlist_t *list, const fu16_t type, const int nth) |
|
| 896 { |
|
| 897 aim_tlv_t *tlv; |
|
| 898 |
|
| 899 if (!(tlv = aim_tlv_gettlv(list, type, nth))) |
|
| 900 return 0; /* erm */ |
|
| 901 return aimutil_get16(tlv->value); |
|
| 902 } |
|
| 903 |
|
| 904 /** |
|
| 905 * Retrieve the data from the nth TLV in the given TLV chain as a 32bit |
|
| 906 * integer. |
|
| 907 * |
|
| 908 * @param list Source TLV chain. |
|
| 909 * @param type TLV type to search for. |
|
| 910 * @param nth Index of TLV to return. |
|
| 911 * @return The value the TLV you were looking for, or 0 if one could |
|
| 912 * not be found. |
|
| 913 */ |
|
| 914 faim_internal fu32_t aim_tlv_get32(aim_tlvlist_t *list, const fu16_t type, const int nth) |
|
| 915 { |
|
| 916 aim_tlv_t *tlv; |
|
| 917 |
|
| 918 if (!(tlv = aim_tlv_gettlv(list, type, nth))) |
|
| 919 return 0; /* erm */ |
|
| 920 return aimutil_get32(tlv->value); |
|
| 921 } |
|