Mercurial > pidgin
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 |