aboutsummaryrefslogtreecommitdiffstats
path: root/protocols/oscar/tlv.c
blob: af08b6d21fb95ffade33806d7bc691eb8b5bf316 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
Frequently Asked Questions about BitlBee
========================================

Well, maybe not exactly "Frequently", but definitely "Asked" ... mostly by
the developers :-)

Q: WTH were you guys on when you thought of that _weird_ name?
A: Though we live in The Netherlands and one of us even lives in Amsterdam,
   we're not on drugs ... most of the time.

Q: Okay, so the cops are so evil there, you can't even admit the truth, but
   WTH does BitlBee mean then?
A: There are a few explanations. But the most symbolical goes like: the two
   colors of the bee symbolize the two worlds betwee which the Bee flies. On
   the one hand there's the IM-networks, on the other is IRC.
   
   Truth be told, it's absolute nonsense. The biggest nutcase in the
   development team just played around with words for half an hour or so.
   BitlBee was the result. We liked it, we kept it. We lovingly shorten it
   to "the Bee" or even "het Bijtje" (Dutch for "the little Bee") sometimes.

Q: What is 'root' doing in my control channel? I didn't start the Bee as
   root.
A: 'root' is just the name for the most powerful user in BitlBee. Just like
   in the system, it is root who is the ... eh ... root of the
   functionality. Luckily, in BitlBee, root follows your orders (mostly), so
   no BOFHs there.
   
   We get some complaints from time to time that 'root' is a confusing name.
   Because of that name, some package maintainers have renamed root to, for
   example, BitlBee. We recognize that some people see that need. If the
   package maintainer hasn't renamed root, you can do this yourself with the
   'rename' command.
   
   The name root is not likely to change in the 'official' releases, though.
   We find the metaphor of root correct and feel that there is no important
   (security threatening) reason to change this non-creative piece of
   artistic creativity.

Q: When is $random_feature going to be implemented?
A: It depends on the feature. We keep a list of all wishlist "bugs" in our
   Bug Tracking system at http://bugs.bitlbee.org/

Q: The messages I send and/or receive look weird. I see weird characters and
   annoying HTML codes. Or, BitlBee does evil things when I send messages with
   non-ASCII characters!
A: You probably have to change some settings. To get rid of HTML in messages,
   see "help set strip_html". If you seem to have problems with your charset,
   see "help set charset".
   
   Although actually most of these problems should be gone by now. So if you
   can't get things to work well, you might have found a bug.

Q: Is BitlBee forked from Gaim?
A: BitlBee 0.7 was, sort-of. It contained a lot of code from Gaim 0.58
   (mainly the IM-code), although heavily modified, to make it work better
   with BitlBee. We were planning to keep BitlBee up-to-date with later Gaim
   versions, but this turned out to be very time-consuming because the API
   changed a lot, and we don't have the time to keep up with those changes
   all the time.
   
   These days, we replaced the Yahoo! code with libyahoo2 (which is a
   separate Yahoo! module. It's derived from Gaim, but separately
   maintained) and wrote our own MSN module. More modules are probably going
   to be changed, so in the near future, the API might be the only thing
   left from Gaim.

Q: What's that Gaim doing in BitlBee error messages and my Jabber resource?
A: Ah, well, as you probably know we use some of Gaim's IM-modules, and we
   don't think it's worth our time to do a search-and-replace over the whole
   source to get rid of every reference to Gaim. In fact, we don't want to,
   since we don't want to pretend we wrote all that code.
   
   About Jabber: If you want a different resource string, you can set it
   when logging in by appending it to your Jabber ID, like:
   lintux@jabber.com/BitlBee
ref='#n355'>355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
#include <aim.h>

static void freetlv(aim_tlv_t **oldtlv)
{
	if (!oldtlv || !*oldtlv) {
		return;
	}

	g_free((*oldtlv)->value);
	g_free(*oldtlv);
	*oldtlv = NULL;
}

/**
 * aim_readtlvchain - Read a TLV chain from a buffer.
 * @buf: Input buffer
 * @maxlen: Length of input buffer
 *
 * Reads and parses a series of TLV patterns from a data buffer; the
 * returned structure is manipulatable with the rest of the TLV
 * routines.  When done with a TLV chain, aim_freetlvchain() should
 * be called to free the dynamic substructures.
 *
 * XXX There should be a flag setable here to have the tlvlist contain
 * bstream references, so that at least the ->value portion of each
 * element doesn't need to be malloc/memcpy'd.  This could prove to be
 * just as efficient as the in-place TLV parsing used in a couple places
 * in libfaim.
 *
 */
aim_tlvlist_t *aim_readtlvchain(aim_bstream_t *bs)
{
	aim_tlvlist_t *list = NULL, *cur;
	guint16 type, length;

	while (aim_bstream_empty(bs)) {

		type = aimbs_get16(bs);
		length = aimbs_get16(bs);

		cur = g_new0(aim_tlvlist_t, 1);

		cur->tlv = g_new0(aim_tlv_t, 1);
		cur->tlv->type = type;
		if ((cur->tlv->length = length)) {
			cur->tlv->value = aimbs_getraw(bs, length);
		}

		cur->next = list;
		list = cur;
	}

	return list;
}

/**
 * aim_freetlvchain - Free a TLV chain structure
 * @list: Chain to be freed
 *
 * Walks the list of TLVs in the passed TLV chain and
 * frees each one. Note that any references to this data
 * should be removed before calling this.
 *
 */
void aim_freetlvchain(aim_tlvlist_t **list)
{
	aim_tlvlist_t *cur;

	if (!list || !*list) {
		return;
	}

	for (cur = *list; cur; ) {
		aim_tlvlist_t *tmp;

		freetlv(&cur->tlv);

		tmp = cur->next;
		g_free(cur);
		cur = tmp;
	}

	list = NULL;

	return;
}

/**
 * aim_counttlvchain - Count the number of TLVs in a chain
 * @list: Chain to be counted
 *
 * Returns the number of TLVs stored in the passed chain.
 *
 */
int aim_counttlvchain(aim_tlvlist_t **list)
{
	aim_tlvlist_t *cur;
	int count;

	if (!list || !*list) {
		return 0;
	}

	for (cur = *list, count = 0; cur; cur = cur->next) {
		count++;
	}

	return count;
}

/**
 * aim_sizetlvchain - Count the number of bytes in a TLV chain
 * @list: Chain to be sized
 *
 * Returns the number of bytes that would be needed to
 * write the passed TLV chain to a data buffer.
 *
 */
int aim_sizetlvchain(aim_tlvlist_t **list)
{
	aim_tlvlist_t *cur;
	int size;

	if (!list || !*list) {
		return 0;
	}

	for (cur = *list, size = 0; cur; cur = cur->next) {
		size += (4 + cur->tlv->length);
	}

	return size;
}

/**
 * aim_addtlvtochain_str - Add a string to a TLV chain
 * @list: Designation chain (%NULL pointer if empty)
 * @type: TLV type
 * @str: String to add
 * @len: Length of string to add (not including %NULL)
 *
 * Adds the passed string as a TLV element of the passed type
 * to the TLV chain.
 *
 */
int aim_addtlvtochain_raw(aim_tlvlist_t **list, const guint16 t, const guint16 l, const guint8 *v)
{
	aim_tlvlist_t *newtlv, *cur;

	if (!list) {
		return 0;
	}

	if (!(newtlv = g_new0(aim_tlvlist_t, 1))) {
		return 0;
	}

	if (!(newtlv->tlv = g_new0(aim_tlv_t, 1))) {
		g_free(newtlv);
		return 0;
	}
	newtlv->tlv->type = t;
	if ((newtlv->tlv->length = l)) {
		newtlv->tlv->value = (guint8 *) g_malloc(newtlv->tlv->length);
		memcpy(newtlv->tlv->value, v, newtlv->tlv->length);
	}

	if (!*list) {
		*list = newtlv;
	} else {
		for (cur = *list; cur->next; cur = cur->next) {
			;
		}
		cur->next = newtlv;
	}

	return newtlv->tlv->length;
}

/**
 * aim_addtlvtochain8 - Add a 8bit integer to a TLV chain
 * @list: Destination chain
 * @type: TLV type to add
 * @val: Value to add
 *
 * Adds a one-byte unsigned integer to a TLV chain.
 *
 */
int aim_addtlvtochain8(aim_tlvlist_t **list, const guint16 t, const guint8 v)
{
	guint8 v8[1];

	(void) aimutil_put8(v8, v);

	return aim_addtlvtochain_raw(list, t, 1, v8);
}

/**
 * aim_addtlvtochain16 - Add a 16bit integer to a TLV chain
 * @list: Destination chain
 * @type: TLV type to add
 * @val: Value to add
 *
 * Adds a two-byte unsigned integer to a TLV chain.
 *
 */
int aim_addtlvtochain16(aim_tlvlist_t **list, const guint16 t, const guint16 v)
{
	guint8 v16[2];

	(void) aimutil_put16(v16, v);

	return aim_addtlvtochain_raw(list, t, 2, v16);
}

/**
 * aim_addtlvtochain32 - Add a 32bit integer to a TLV chain
 * @list: Destination chain
 * @type: TLV type to add
 * @val: Value to add
 *
 * Adds a four-byte unsigned integer to a TLV chain.
 *
 */
int aim_addtlvtochain32(aim_tlvlist_t **list, const guint16 t, const guint32 v)
{
	guint8 v32[4];

	(void) aimutil_put32(v32, v);

	return aim_addtlvtochain_raw(list, t, 4, v32);
}

/**
 * aim_addtlvtochain_caps - Add a capability block to a TLV chain
 * @list: Destination chain
 * @type: TLV type to add
 * @caps: Bitfield of capability flags to send
 *
 * Adds a block of capability blocks to a TLV chain. The bitfield
 * passed in should be a bitwise %OR of any of the %AIM_CAPS constants:
 *
 */
int aim_addtlvtochain_caps(aim_tlvlist_t **list, const guint16 t, const guint32 caps)
{
	guint8 buf[16 * 16]; /* XXX icky fixed length buffer */
	aim_bstream_t bs;

	if (!caps) {
		return 0; /* nothing there anyway */

	}
	aim_bstream_init(&bs, buf, sizeof(buf));

	aim_putcap(&bs, caps);

	return aim_addtlvtochain_raw(list, t, aim_bstream_curpos(&bs), buf);
}

/**
 * aim_addtlvtochain_noval - Add a blank TLV to a TLV chain
 * @list: Destination chain
 * @type: TLV type to add
 *
 * Adds a TLV with a zero length to a TLV chain.
 *
 */
int aim_addtlvtochain_noval(aim_tlvlist_t **list, const guint16 t)
{
	return aim_addtlvtochain_raw(list, t, 0, NULL);
}

/*
 * Note that the inner TLV chain will not be modifiable as a tlvchain once
 * it is written using this.  Or rather, it can be, but updates won't be
 * made to this.
 *
 * XXX should probably support sublists for real.
 *
 * This is so neat.
 *
 */
int aim_addtlvtochain_frozentlvlist(aim_tlvlist_t **list, guint16 type, aim_tlvlist_t **tl)
{
	guint8 *buf;
	int buflen;
	aim_bstream_t bs;

	buflen = aim_sizetlvchain(tl);

	if (buflen <= 0) {
		return 0;
	}

	if (!(buf = g_malloc(buflen))) {
		return 0;
	}

	aim_bstream_init(&bs, buf, buflen);

	aim_writetlvchain(&bs, tl);

	aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf);

	g_free(buf);

	return buflen;
}

int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, guint16 type, guint16 exchange, const char *roomname,
                               guint16 instance)
{
	guint8 *buf;
	int buflen;
	aim_bstream_t bs;

	buflen = 2 + 1 + strlen(roomname) + 2;

	if (!(buf = g_malloc(buflen))) {
		return 0;
	}

	aim_bstream_init(&bs, buf, buflen);

	aimbs_put16(&bs, exchange);
	aimbs_put8(&bs, strlen(roomname));
	aimbs_putraw(&bs, (guint8 *) roomname, strlen(roomname));
	aimbs_put16(&bs, instance);

	aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf);

	g_free(buf);

	return 0;
}

/**
 * aim_writetlvchain - Write a TLV chain into a data buffer.
 * @buf: Destination buffer
 * @buflen: Maximum number of bytes that will be written to buffer
 * @list: Source TLV chain
 *
 * Copies a TLV chain into a raw data buffer, writing only the number
 * of bytes specified. This operation does not free the chain;
 * aim_freetlvchain() must still be called to free up the memory used
 * by the chain structures.
 *
 * XXX clean this up, make better use of bstreams
 */
int aim_writetlvchain(aim_bstream_t *bs, aim_tlvlist_t **list)
{
	int goodbuflen;
	aim_tlvlist_t *cur;

	/* do an initial run to test total length */
	for (cur = *list, goodbuflen = 0; cur; cur = cur->next) {
		goodbuflen += 2 + 2; /* type + len */
		goodbuflen += cur->tlv->length;
	}

	if (goodbuflen > aim_bstream_empty(bs)) {
		return 0; /* not enough buffer */

	}
	/* do the real write-out */
	for (cur = *list; cur; cur = cur->next) {
		aimbs_put16(bs, cur->tlv->type);
		aimbs_put16(bs, cur->tlv->length);
		if (cur->tlv->length) {
			aimbs_putraw(bs, cur->tlv->value, cur->tlv->length);
		}
	}

	return 1; /* XXX this is a nonsensical return */
}


/**
 * aim_gettlv - Grab the Nth TLV of type type in the TLV list list.
 * @list: Source chain
 * @type: Requested TLV type
 * @nth: Index of TLV of type to get
 *
 * Returns a pointer to an aim_tlv_t of the specified type;
 * %NULL on error.  The @nth parameter is specified starting at %1.
 * In most cases, there will be no more than one TLV of any type
 * in a chain.
 *
 */
aim_tlv_t *aim_gettlv(aim_tlvlist_t *list, const guint16 t, const int n)
{
	aim_tlvlist_t *cur;
	int i;

	for (cur = list, i = 0; cur; cur = cur->next) {
		if (cur && cur->tlv) {
			if (cur->tlv->type == t) {
				i++;
			}
			if (i >= n) {
				return cur->tlv;
			}
		}
	}

	return NULL;
}

/**
 * aim_gettlv_str - Retrieve the Nth TLV in chain as a string.
 * @list: Source TLV chain
 * @type: TLV type to search for
 * @nth: Index of TLV to return
 *
 * Same as aim_gettlv(), except that the return value is a %NULL-
 * terminated string instead of an aim_tlv_t.  This is a
 * dynamic buffer and must be freed by the caller.
 *
 */
char *aim_gettlv_str(aim_tlvlist_t *list, const guint16 t, const int n)
{
	aim_tlv_t *tlv;
	char *newstr;

	if (!(tlv = aim_gettlv(list, t, n))) {
		return NULL;
	}

	newstr = (char *) g_malloc(tlv->length + 1);
	memcpy(newstr, tlv->value, tlv->length);
	*(newstr + tlv->length) = '\0';

	return newstr;
}

/**
 * aim_gettlv8 - Retrieve the Nth TLV in chain as a 8bit integer.
 * @list: Source TLV chain
 * @type: TLV type to search for
 * @nth: Index of TLV to return
 *
 * Same as aim_gettlv(), except that the return value is a
 * 8bit integer instead of an aim_tlv_t.
 *
 */
guint8 aim_gettlv8(aim_tlvlist_t *list, const guint16 t, const int n)
{
	aim_tlv_t *tlv;

	if (!(tlv = aim_gettlv(list, t, n))) {
		return 0; /* erm */
	}
	return aimutil_get8(tlv->value);
}

/**
 * aim_gettlv16 - Retrieve the Nth TLV in chain as a 16bit integer.
 * @list: Source TLV chain
 * @type: TLV type to search for
 * @nth: Index of TLV to return
 *
 * Same as aim_gettlv(), except that the return value is a
 * 16bit integer instead of an aim_tlv_t.
 *
 */
guint16 aim_gettlv16(aim_tlvlist_t *list, const guint16 t, const int n)
{
	aim_tlv_t *tlv;

	if (!(tlv = aim_gettlv(list, t, n))) {
		return 0; /* erm */
	}
	return aimutil_get16(tlv->value);
}

/**
 * aim_gettlv32 - Retrieve the Nth TLV in chain as a 32bit integer.
 * @list: Source TLV chain
 * @type: TLV type to search for
 * @nth: Index of TLV to return
 *
 * Same as aim_gettlv(), except that the return value is a
 * 32bit integer instead of an aim_tlv_t.
 *
 */
guint32 aim_gettlv32(aim_tlvlist_t *list, const guint16 t, const int n)
{
	aim_tlv_t *tlv;

	if (!(tlv = aim_gettlv(list, t, n))) {
		return 0; /* erm */
	}
	return aimutil_get32(tlv->value);
}

#if 0
/**
 * aim_puttlv_8 - Write a one-byte TLV.
 * @buf: Destination buffer
 * @t: TLV type
 * @v: Value
 *
 * Writes a TLV with a one-byte integer value portion.
 *
 */
int aim_puttlv_8(guint8 *buf, const guint16 t, const guint8 v)
{
	guint8 v8[1];

	aimutil_put8(v8, v);

	return aim_puttlv_raw(buf, t, 1, v8);
}

/**
 * aim_puttlv_16 - Write a two-byte TLV.
 * @buf: Destination buffer
 * @t: TLV type
 * @v: Value
 *
 * Writes a TLV with a two-byte integer value portion.
 *
 */
int aim_puttlv_16(guint8 *buf, const guint16 t, const guint16 v)
{
	guint8 v16[2];

	aimutil_put16(v16, v);

	return aim_puttlv_raw(buf, t, 2, v16);
}


/**
 * aim_puttlv_32 - Write a four-byte TLV.
 * @buf: Destination buffer
 * @t: TLV type
 * @v: Value
 *
 * Writes a TLV with a four-byte integer value portion.
 *
 */
int aim_puttlv_32(guint8 *buf, const guint16 t, const guint32 v)
{
	guint8 v32[4];

	aimutil_put32(v32, v);

	return aim_puttlv_raw(buf, t, 4, v32);
}

/**
 * aim_puttlv_raw - Write a raw TLV.
 * @buf: Destination buffer
 * @t: TLV type
 * @l: Length of string
 * @v: String to write
 *
 * Writes a TLV with a raw value portion.  (Only the first @l
 * bytes of the passed buffer will be written, which should not
 * include a terminating NULL.)
 *
 */
int aim_puttlv_raw(guint8 *buf, const guint16 t, const guint16 l, const guint8 *v)
{
	int i;

	i = aimutil_put16(buf, t);
	i += aimutil_put16(buf + i, l);
	if (l) {
		memcpy(buf + i, v, l);
	}
	i += l;

	return i;
}
#endif