Annotation of ChivanetAimPidgin/oscarprpl/src/c/tlv.c, revision 1.1.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>