comparison libpurple/protocols/msn/tlv.c @ 31047:a6d2d7de8a08

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.
author Elliott Sales de Andrade <qulogic@pidgin.im>
date Fri, 17 Dec 2010 09:01:26 +0000
parents
children a8cc50c2279f
comparison
equal deleted inserted replaced
31046:b4064198e017 31047:a6d2d7de8a08
1 /**
2 * @file tlv.c MSN TLV functions
3 *
4 * purple
5 *
6 * Purple is the legal property of its developers, whose names are too numerous
7 * to list here. Please refer to the COPYRIGHT file distributed with this
8 * source distribution.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
23 */
24
25 #include "tlv.h"
26 #include "msnutils.h"
27
28 static msn_tlv_t *
29 createtlv(guint8 type, guint8 length, guint8 *value)
30 {
31 msn_tlv_t *ret;
32
33 ret = g_new(msn_tlv_t, 1);
34 ret->type = type;
35 ret->length = length;
36 ret->value = value;
37
38 return ret;
39 }
40
41 static void
42 freetlv(msn_tlv_t *oldtlv)
43 {
44 g_free(oldtlv->value);
45 g_free(oldtlv);
46 }
47
48 static GSList *
49 msn_tlv_read(GSList *list, char *bs, size_t *bs_len)
50 {
51 guint8 type, length;
52 msn_tlv_t *tlv;
53
54 type = msn_read8(bs);
55 length = msn_read8(bs);
56 *bs_len -= 2;
57
58 if (length > *bs_len) {
59 msn_tlvlist_free(list);
60 return NULL;
61 }
62
63 tlv = createtlv(type, length, NULL);
64 if (length > 0) {
65 tlv->value = g_memdup(bs, length);
66 if (!tlv->value) {
67 freetlv(tlv);
68 msn_tlvlist_free(list);
69 return NULL;
70 }
71 }
72
73 *bs_len -= length;
74
75 return g_slist_prepend(list, tlv);
76 }
77
78 GSList *
79 msn_tlvlist_read(char *bs, size_t bs_len)
80 {
81 GSList *list = NULL;
82
83 while (bs_len > 0) {
84 list = msn_tlv_read(list, bs, &bs_len);
85 if (list == NULL)
86 return NULL;
87 }
88
89 return g_slist_reverse(list);
90 }
91
92 GSList *msn_tlvlist_copy(GSList *orig)
93 {
94 GSList *new = NULL;
95 msn_tlv_t *tlv;
96
97 while (orig != NULL) {
98 tlv = orig->data;
99 msn_tlvlist_add_raw(&new, tlv->type, tlv->length, (const char *)tlv->value);
100 orig = orig->next;
101 }
102
103 return new;
104 }
105
106 gboolean
107 msn_tlvlist_equal(GSList *one, GSList *two)
108 {
109 while (one && two) {
110 msn_tlv_t *a = one->data;
111 msn_tlv_t *b = two->data;
112
113 if (a->type != b->type)
114 return FALSE;
115 else if (a->length != b->length)
116 return FALSE;
117 else if (!a->value && b->value)
118 return FALSE;
119 else if (a->value && !b->value)
120 return FALSE;
121 else if (a->value && b->value && memcmp(a->value, b->value, a->length) != 0)
122 return FALSE;
123
124 one = one->next;
125 two = two->next;
126 }
127
128 return one == two;
129 }
130
131 void
132 msn_tlvlist_free(GSList *list)
133 {
134 while (list != NULL) {
135 freetlv(list->data);
136 list = g_slist_delete_link(list, list);
137 }
138 }
139
140 int
141 msn_tlvlist_count(GSList *list)
142 {
143 return g_slist_length(list);
144 }
145
146 size_t
147 msn_tlvlist_size(GSList *list)
148 {
149 int size;
150
151 if (list == NULL)
152 return 0;
153
154 for (size = 0; list; list = list->next)
155 size += (2 + ((msn_tlv_t *)list->data)->length);
156
157 return size;
158 }
159
160 int
161 msn_tlvlist_add_raw(GSList **list, const guint16 type, const guint16 length, const char *value)
162 {
163 msn_tlv_t *tlv;
164
165 if (list == NULL)
166 return 0;
167
168 tlv = createtlv(type, length, NULL);
169 if (length > 0)
170 tlv->value = g_memdup(value, length);
171
172 *list = g_slist_append(*list, tlv);
173
174 return tlv->length;
175 }
176
177 int
178 msn_tlvlist_add_8(GSList **list, const guint16 type, const guint8 value)
179 {
180 char v8[1];
181
182 msn_write8(v8, value);
183
184 return msn_tlvlist_add_raw(list, type, 1, v8);
185 }
186
187 int
188 msn_tlvlist_add_16(GSList **list, const guint16 type, const guint16 value)
189 {
190 char v16[2];
191
192 msn_write16be(v16, value);
193
194 return msn_tlvlist_add_raw(list, type, 2, v16);
195 }
196
197 int
198 msn_tlvlist_add_32(GSList **list, const guint16 type, const guint32 value)
199 {
200 char v32[4];
201
202 msn_write32be(v32, value);
203
204 return msn_tlvlist_add_raw(list, type, 4, v32);
205 }
206
207 int
208 msn_tlvlist_add_str(GSList **list, const guint16 type, const char *value)
209 {
210 return msn_tlvlist_add_raw(list, type, strlen(value), value);
211 }
212
213 int
214 msn_tlvlist_add_empty(GSList **list, const guint16 type)
215 {
216 return msn_tlvlist_add_raw(list, type, 0, NULL);
217 }
218
219 int
220 msn_tlvlist_replace_raw(GSList **list, const guint16 type, const guint16 length, const char *value)
221 {
222 GSList *cur;
223 msn_tlv_t *tlv;
224
225 if (list == NULL)
226 return 0;
227
228 for (cur = *list; cur != NULL; cur = cur->next) {
229 tlv = cur->data;
230 if (tlv->type == type)
231 break;
232 }
233
234 if (cur == NULL)
235 /* TLV does not exist, so add a new one */
236 return msn_tlvlist_add_raw(list, type, length, value);
237
238 g_free(tlv->value);
239 tlv->length = length;
240 if (length > 0) {
241 tlv->value = g_memdup(value, length);
242 } else
243 tlv->value = NULL;
244
245 return length;
246 }
247
248 int
249 msn_tlvlist_replace_str(GSList **list, const guint16 type, const char *str)
250 {
251 return msn_tlvlist_replace_raw(list, type, strlen(str), str);
252 }
253
254 int
255 msn_tlvlist_replace_empty(GSList **list, const guint16 type)
256 {
257 return msn_tlvlist_replace_raw(list, type, 0, NULL);
258 }
259
260 int
261 msn_tlvlist_replace_8(GSList **list, const guint16 type, const guint8 value)
262 {
263 char v8[1];
264
265 msn_write8(v8, value);
266
267 return msn_tlvlist_replace_raw(list, type, 1, v8);
268 }
269
270 int
271 msn_tlvlist_replace_32(GSList **list, const guint16 type, const guint32 value)
272 {
273 char v32[4];
274
275 msn_write32be(v32, value);
276
277 return msn_tlvlist_replace_raw(list, type, 4, v32);
278 }
279
280 void
281 msn_tlvlist_remove(GSList **list, const guint16 type)
282 {
283 GSList *cur, *next;
284 msn_tlv_t *tlv;
285
286 if (list == NULL || *list == NULL)
287 return;
288
289 cur = *list;
290 while (cur != NULL) {
291 tlv = cur->data;
292 next = cur->next;
293
294 if (tlv->type == type) {
295 /* Delete this TLV */
296 *list = g_slist_delete_link(*list, cur);
297 g_free(tlv->value);
298 g_free(tlv);
299 }
300
301 cur = next;
302 }
303 }
304
305 #if 0
306 int
307 msn_tlvlist_write(ByteStream *bs, GSList **list)
308 {
309 int goodbuflen;
310 GSList *cur;
311 msn_tlv_t *tlv;
312
313 /* do an initial run to test total length */
314 goodbuflen = msn_tlvlist_size(*list);
315
316 if (goodbuflen > byte_stream_bytes_left(bs))
317 return 0; /* not enough buffer */
318
319 /* do the real write-out */
320 for (cur = *list; cur; cur = cur->next) {
321 tlv = cur->data;
322 byte_stream_put16(bs, tlv->type);
323 byte_stream_put16(bs, tlv->length);
324 if (tlv->length > 0)
325 byte_stream_putraw(bs, tlv->value, tlv->length);
326 }
327
328 return 1; /* TODO: This is a nonsensical return */
329 }
330 #endif
331
332 msn_tlv_t *
333 msn_tlv_gettlv(GSList *list, const guint16 type, const int nth)
334 {
335 msn_tlv_t *tlv;
336 int i;
337
338 for (i = 0; list != NULL; list = list->next) {
339 tlv = list->data;
340 if (tlv->type == type)
341 i++;
342 if (i >= nth)
343 return tlv;
344 }
345
346 return NULL;
347 }
348
349 int
350 msn_tlv_getlength(GSList *list, const guint16 type, const int nth)
351 {
352 msn_tlv_t *tlv;
353
354 tlv = msn_tlv_gettlv(list, type, nth);
355 if (tlv == NULL)
356 return -1;
357
358 return tlv->length;
359 }
360
361 char *
362 msn_tlv_getvalue_as_string(msn_tlv_t *tlv)
363 {
364 char *ret;
365
366 ret = g_malloc(tlv->length + 1);
367 memcpy(ret, tlv->value, tlv->length);
368 ret[tlv->length] = '\0';
369
370 return ret;
371 }
372
373 char *
374 msn_tlv_getstr(GSList *list, const guint16 type, const int nth)
375 {
376 msn_tlv_t *tlv;
377
378 tlv = msn_tlv_gettlv(list, type, nth);
379 if (tlv == NULL)
380 return NULL;
381
382 return msn_tlv_getvalue_as_string(tlv);
383 }
384
385 guint8
386 msn_tlv_get8(GSList *list, const guint16 type, const int nth)
387 {
388 msn_tlv_t *tlv;
389
390 tlv = msn_tlv_gettlv(list, type, nth);
391 if (tlv == NULL)
392 return 0; /* erm */
393
394 return msn_read8((const char *)tlv->value);
395 }
396
397 guint16
398 msn_tlv_get16(GSList *list, const guint16 type, const int nth)
399 {
400 msn_tlv_t *tlv;
401
402 tlv = msn_tlv_gettlv(list, type, nth);
403 if (tlv == NULL)
404 return 0; /* erm */
405
406 return msn_read16be((const char *)tlv->value);
407 }
408
409 guint32
410 msn_tlv_get32(GSList *list, const guint16 type, const int nth)
411 {
412 msn_tlv_t *tlv;
413
414 tlv = msn_tlv_gettlv(list, type, nth);
415 if (tlv == NULL)
416 return 0; /* erm */
417
418 return msn_read32be((const char *)tlv->value);
419 }
420