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