summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElliott Sales de Andrade <qulogic@pidgin.im>2010-12-17 09:01:26 +0000
committerElliott Sales de Andrade <qulogic@pidgin.im>2010-12-17 09:01:26 +0000
commit6bf51c6e8a0c6a8a90a37633c3337dd5cde6c43e (patch)
treecd72829a14c714e768e22c756acf9634417f9bb4
parent0797547596674ea385fb670e2faf74f9b38d7549 (diff)
downloadpidgin-6bf51c6e8a0c6a8a90a37633c3337dd5cde6c43e.tar.gz
Nick some TLV functions from AIM. I don't know if I need all of these,
but I guess we'll see. Too bad they don't use the same sizes for the fields.
-rw-r--r--libpurple/protocols/msn/Makefile.am2
-rw-r--r--libpurple/protocols/msn/tlv.c420
-rw-r--r--libpurple/protocols/msn/tlv.h75
3 files changed, 497 insertions, 0 deletions
diff --git a/libpurple/protocols/msn/Makefile.am b/libpurple/protocols/msn/Makefile.am
index dcde2f0a80..f2edc6454e 100644
--- a/libpurple/protocols/msn/Makefile.am
+++ b/libpurple/protocols/msn/Makefile.am
@@ -62,6 +62,8 @@ MSNSOURCES = \
switchboard.h \
table.c \
table.h \
+ tlv.c \
+ tlv.h \
transaction.c \
transaction.h \
user.c \
diff --git a/libpurple/protocols/msn/tlv.c b/libpurple/protocols/msn/tlv.c
new file mode 100644
index 0000000000..e31bf58476
--- /dev/null
+++ b/libpurple/protocols/msn/tlv.c
@@ -0,0 +1,420 @@
+/**
+ * @file tlv.c MSN TLV functions
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include "tlv.h"
+#include "msnutils.h"
+
+static msn_tlv_t *
+createtlv(guint8 type, guint8 length, guint8 *value)
+{
+ msn_tlv_t *ret;
+
+ ret = g_new(msn_tlv_t, 1);
+ ret->type = type;
+ ret->length = length;
+ ret->value = value;
+
+ return ret;
+}
+
+static void
+freetlv(msn_tlv_t *oldtlv)
+{
+ g_free(oldtlv->value);
+ g_free(oldtlv);
+}
+
+static GSList *
+msn_tlv_read(GSList *list, char *bs, size_t *bs_len)
+{
+ guint8 type, length;
+ msn_tlv_t *tlv;
+
+ type = msn_read8(bs);
+ length = msn_read8(bs);
+ *bs_len -= 2;
+
+ if (length > *bs_len) {
+ msn_tlvlist_free(list);
+ return NULL;
+ }
+
+ tlv = createtlv(type, length, NULL);
+ if (length > 0) {
+ tlv->value = g_memdup(bs, length);
+ if (!tlv->value) {
+ freetlv(tlv);
+ msn_tlvlist_free(list);
+ return NULL;
+ }
+ }
+
+ *bs_len -= length;
+
+ return g_slist_prepend(list, tlv);
+}
+
+GSList *
+msn_tlvlist_read(char *bs, size_t bs_len)
+{
+ GSList *list = NULL;
+
+ while (bs_len > 0) {
+ list = msn_tlv_read(list, bs, &bs_len);
+ if (list == NULL)
+ return NULL;
+ }
+
+ return g_slist_reverse(list);
+}
+
+GSList *msn_tlvlist_copy(GSList *orig)
+{
+ GSList *new = NULL;
+ msn_tlv_t *tlv;
+
+ while (orig != NULL) {
+ tlv = orig->data;
+ msn_tlvlist_add_raw(&new, tlv->type, tlv->length, (const char *)tlv->value);
+ orig = orig->next;
+ }
+
+ return new;
+}
+
+gboolean
+msn_tlvlist_equal(GSList *one, GSList *two)
+{
+ while (one && two) {
+ msn_tlv_t *a = one->data;
+ msn_tlv_t *b = two->data;
+
+ if (a->type != b->type)
+ return FALSE;
+ else if (a->length != b->length)
+ return FALSE;
+ else if (!a->value && b->value)
+ return FALSE;
+ else if (a->value && !b->value)
+ return FALSE;
+ else if (a->value && b->value && memcmp(a->value, b->value, a->length) != 0)
+ return FALSE;
+
+ one = one->next;
+ two = two->next;
+ }
+
+ return one == two;
+}
+
+void
+msn_tlvlist_free(GSList *list)
+{
+ while (list != NULL) {
+ freetlv(list->data);
+ list = g_slist_delete_link(list, list);
+ }
+}
+
+int
+msn_tlvlist_count(GSList *list)
+{
+ return g_slist_length(list);
+}
+
+size_t
+msn_tlvlist_size(GSList *list)
+{
+ int size;
+
+ if (list == NULL)
+ return 0;
+
+ for (size = 0; list; list = list->next)
+ size += (2 + ((msn_tlv_t *)list->data)->length);
+
+ return size;
+}
+
+int
+msn_tlvlist_add_raw(GSList **list, const guint16 type, const guint16 length, const char *value)
+{
+ msn_tlv_t *tlv;
+
+ if (list == NULL)
+ return 0;
+
+ tlv = createtlv(type, length, NULL);
+ if (length > 0)
+ tlv->value = g_memdup(value, length);
+
+ *list = g_slist_append(*list, tlv);
+
+ return tlv->length;
+}
+
+int
+msn_tlvlist_add_8(GSList **list, const guint16 type, const guint8 value)
+{
+ char v8[1];
+
+ msn_write8(v8, value);
+
+ return msn_tlvlist_add_raw(list, type, 1, v8);
+}
+
+int
+msn_tlvlist_add_16(GSList **list, const guint16 type, const guint16 value)
+{
+ char v16[2];
+
+ msn_write16be(v16, value);
+
+ return msn_tlvlist_add_raw(list, type, 2, v16);
+}
+
+int
+msn_tlvlist_add_32(GSList **list, const guint16 type, const guint32 value)
+{
+ char v32[4];
+
+ msn_write32be(v32, value);
+
+ return msn_tlvlist_add_raw(list, type, 4, v32);
+}
+
+int
+msn_tlvlist_add_str(GSList **list, const guint16 type, const char *value)
+{
+ return msn_tlvlist_add_raw(list, type, strlen(value), value);
+}
+
+int
+msn_tlvlist_add_empty(GSList **list, const guint16 type)
+{
+ return msn_tlvlist_add_raw(list, type, 0, NULL);
+}
+
+int
+msn_tlvlist_replace_raw(GSList **list, const guint16 type, const guint16 length, const char *value)
+{
+ GSList *cur;
+ msn_tlv_t *tlv;
+
+ if (list == NULL)
+ return 0;
+
+ for (cur = *list; cur != NULL; cur = cur->next) {
+ tlv = cur->data;
+ if (tlv->type == type)
+ break;
+ }
+
+ if (cur == NULL)
+ /* TLV does not exist, so add a new one */
+ return msn_tlvlist_add_raw(list, type, length, value);
+
+ g_free(tlv->value);
+ tlv->length = length;
+ if (length > 0) {
+ tlv->value = g_memdup(value, length);
+ } else
+ tlv->value = NULL;
+
+ return length;
+}
+
+int
+msn_tlvlist_replace_str(GSList **list, const guint16 type, const char *str)
+{
+ return msn_tlvlist_replace_raw(list, type, strlen(str), str);
+}
+
+int
+msn_tlvlist_replace_empty(GSList **list, const guint16 type)
+{
+ return msn_tlvlist_replace_raw(list, type, 0, NULL);
+}
+
+int
+msn_tlvlist_replace_8(GSList **list, const guint16 type, const guint8 value)
+{
+ char v8[1];
+
+ msn_write8(v8, value);
+
+ return msn_tlvlist_replace_raw(list, type, 1, v8);
+}
+
+int
+msn_tlvlist_replace_32(GSList **list, const guint16 type, const guint32 value)
+{
+ char v32[4];
+
+ msn_write32be(v32, value);
+
+ return msn_tlvlist_replace_raw(list, type, 4, v32);
+}
+
+void
+msn_tlvlist_remove(GSList **list, const guint16 type)
+{
+ GSList *cur, *next;
+ msn_tlv_t *tlv;
+
+ if (list == NULL || *list == NULL)
+ return;
+
+ cur = *list;
+ while (cur != NULL) {
+ tlv = cur->data;
+ next = cur->next;
+
+ if (tlv->type == type) {
+ /* Delete this TLV */
+ *list = g_slist_delete_link(*list, cur);
+ g_free(tlv->value);
+ g_free(tlv);
+ }
+
+ cur = next;
+ }
+}
+
+#if 0
+int
+msn_tlvlist_write(ByteStream *bs, GSList **list)
+{
+ int goodbuflen;
+ GSList *cur;
+ msn_tlv_t *tlv;
+
+ /* do an initial run to test total length */
+ goodbuflen = msn_tlvlist_size(*list);
+
+ if (goodbuflen > byte_stream_bytes_left(bs))
+ return 0; /* not enough buffer */
+
+ /* do the real write-out */
+ for (cur = *list; cur; cur = cur->next) {
+ tlv = cur->data;
+ byte_stream_put16(bs, tlv->type);
+ byte_stream_put16(bs, tlv->length);
+ if (tlv->length > 0)
+ byte_stream_putraw(bs, tlv->value, tlv->length);
+ }
+
+ return 1; /* TODO: This is a nonsensical return */
+}
+#endif
+
+msn_tlv_t *
+msn_tlv_gettlv(GSList *list, const guint16 type, const int nth)
+{
+ msn_tlv_t *tlv;
+ int i;
+
+ for (i = 0; list != NULL; list = list->next) {
+ tlv = list->data;
+ if (tlv->type == type)
+ i++;
+ if (i >= nth)
+ return tlv;
+ }
+
+ return NULL;
+}
+
+int
+msn_tlv_getlength(GSList *list, const guint16 type, const int nth)
+{
+ msn_tlv_t *tlv;
+
+ tlv = msn_tlv_gettlv(list, type, nth);
+ if (tlv == NULL)
+ return -1;
+
+ return tlv->length;
+}
+
+char *
+msn_tlv_getvalue_as_string(msn_tlv_t *tlv)
+{
+ char *ret;
+
+ ret = g_malloc(tlv->length + 1);
+ memcpy(ret, tlv->value, tlv->length);
+ ret[tlv->length] = '\0';
+
+ return ret;
+}
+
+char *
+msn_tlv_getstr(GSList *list, const guint16 type, const int nth)
+{
+ msn_tlv_t *tlv;
+
+ tlv = msn_tlv_gettlv(list, type, nth);
+ if (tlv == NULL)
+ return NULL;
+
+ return msn_tlv_getvalue_as_string(tlv);
+}
+
+guint8
+msn_tlv_get8(GSList *list, const guint16 type, const int nth)
+{
+ msn_tlv_t *tlv;
+
+ tlv = msn_tlv_gettlv(list, type, nth);
+ if (tlv == NULL)
+ return 0; /* erm */
+
+ return msn_read8((const char *)tlv->value);
+}
+
+guint16
+msn_tlv_get16(GSList *list, const guint16 type, const int nth)
+{
+ msn_tlv_t *tlv;
+
+ tlv = msn_tlv_gettlv(list, type, nth);
+ if (tlv == NULL)
+ return 0; /* erm */
+
+ return msn_read16be((const char *)tlv->value);
+}
+
+guint32
+msn_tlv_get32(GSList *list, const guint16 type, const int nth)
+{
+ msn_tlv_t *tlv;
+
+ tlv = msn_tlv_gettlv(list, type, nth);
+ if (tlv == NULL)
+ return 0; /* erm */
+
+ return msn_read32be((const char *)tlv->value);
+}
+
diff --git a/libpurple/protocols/msn/tlv.h b/libpurple/protocols/msn/tlv.h
new file mode 100644
index 0000000000..fc088a96cd
--- /dev/null
+++ b/libpurple/protocols/msn/tlv.h
@@ -0,0 +1,75 @@
+/**
+ * @file tlv.h MSN TLV functions
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#ifndef MSN_TLV_H
+#define MSN_TLV_H
+
+#include "msn.h"
+
+/* TLV structure */
+typedef struct msn_tlv_s
+{
+ guint8 type;
+ guint8 length;
+ guint8 *value;
+} msn_tlv_t;
+
+/* TLV handling functions */
+char *msn_tlv_getvalue_as_string(msn_tlv_t *tlv);
+
+msn_tlv_t *msn_tlv_gettlv(GSList *list, const guint16 type, const int nth);
+int msn_tlv_getlength(GSList *list, const guint16 type, const int nth);
+char *msn_tlv_getstr(GSList *list, const guint16 type, const int nth);
+guint8 msn_tlv_get8(GSList *list, const guint16 type, const int nth);
+guint16 msn_tlv_get16(GSList *list, const guint16 type, const int nth);
+guint32 msn_tlv_get32(GSList *list, const guint16 type, const int nth);
+
+/* TLV list handling functions */
+GSList *msn_tlvlist_read(char *bs, size_t bs_len);
+GSList *msn_tlvlist_copy(GSList *orig);
+
+int msn_tlvlist_count(GSList *list);
+size_t msn_tlvlist_size(GSList *list);
+gboolean msn_tlvlist_equal(GSList *one, GSList *two);
+int msn_tlvlist_write(char *bs, size_t bs_len, GSList **list);
+void msn_tlvlist_free(GSList *list);
+
+int msn_tlvlist_add_raw(GSList **list, const guint16 type, const guint16 length, const char *value);
+int msn_tlvlist_add_empty(GSList **list, const guint16 type);
+int msn_tlvlist_add_8(GSList **list, const guint16 type, const guint8 value);
+int msn_tlvlist_add_16(GSList **list, const guint16 type, const guint16 value);
+int msn_tlvlist_add_32(GSList **list, const guint16 type, const guint32 value);
+int msn_tlvlist_add_str(GSList **list, const guint16 type, const char *value);
+
+int msn_tlvlist_replace_raw(GSList **list, const guint16 type, const guint16 lenth, const char *value);
+int msn_tlvlist_replace_str(GSList **list, const guint16 type, const char *str);
+int msn_tlvlist_replace_empty(GSList **list, const guint16 type);
+int msn_tlvlist_replace_8(GSList **list, const guint16 type, const guint8 value);
+int msn_tlvlist_replace_16(GSList **list, const guint16 type, const guint16 value);
+int msn_tlvlist_replace_32(GSList **list, const guint16 type, const guint32 value);
+
+void msn_tlvlist_remove(GSList **list, const guint16 type);
+
+#endif /* MSN_TLV_H */
+