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