File:  [Coherent Logic Development] / ChivanetAimPidgin / oscarprpl / src / c / tlv.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Mon Jan 27 19:48:25 2025 UTC (6 months ago) by snw
Branches: MAIN, CoherentLogicDevelopment
CVS tags: test-tag, start, HEAD
Pidgin AIM Plugin for ChivaNet

    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>