comparison libpurple/protocols/oscar/tlv.c @ 17369:f80f7e1047be

Cleanup and simplification of some tlvlist stuff in the oscar protocol. No functionality change.
author Mark Doliner <mark@kingant.net>
date Tue, 29 May 2007 09:51:51 +0000
parents 1927f4ead3ca
children e333072d8680
comparison
equal deleted inserted replaced
17368:b31f53796f3b 17369:f80f7e1047be
16 * You should have received a copy of the GNU Lesser General Public 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 17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21
22 #include "oscar.h" 21 #include "oscar.h"
23 22
24 static aim_tlv_t * 23 static aim_tlv_t *
25 createtlv(guint16 type, guint16 length, guint8 *value) 24 createtlv(guint16 type, guint16 length, guint8 *value)
26 { 25 {
33 32
34 return ret; 33 return ret;
35 } 34 }
36 35
37 static void 36 static void
38 freetlv(aim_tlv_t **oldtlv) 37 freetlv(aim_tlv_t *oldtlv)
39 { 38 {
40 39 g_free(oldtlv->value);
41 if (!oldtlv || !*oldtlv) 40 g_free(oldtlv);
42 return; 41 }
43 42
44 g_free((*oldtlv)->value); 43 static GSList *
45 g_free(*oldtlv); 44 aim_tlv_read(GSList *list, ByteStream *bs)
46 *oldtlv = NULL; 45 {
47 46 guint16 type, length;
48 return; 47 aim_tlv_t *tlv;
48
49 type = byte_stream_get16(bs);
50 length = byte_stream_get16(bs);
51
52 #if 0
53 /*
54 * This code hasn't been needed in years. It's been commented
55 * out since 2003, at the latest. It seems likely that it was
56 * just a bug in their server code that has since been fixed.
57 * In any case, here's the orignal comment, kept for historical
58 * purposes:
59 *
60 * Okay, so now AOL has decided that any TLV of
61 * type 0x0013 can only be two bytes, despite
62 * what the actual given length is. So here
63 * we dump any invalid TLVs of that sort. Hopefully
64 * there's no special cases to this special case.
65 * - mid (30jun2000)
66 */
67 if ((type == 0x0013) && (length != 0x0002)) {
68 length = 0x0002;
69 return list;
70 }
71 #endif
72 if (length > byte_stream_empty(bs)) {
73 aim_tlvlist_free(list);
74 return NULL;
75 }
76
77 tlv = createtlv(type, length, NULL);
78 if (tlv->length > 0) {
79 tlv->value = byte_stream_getraw(bs, length);
80 if (!tlv->value) {
81 freetlv(tlv);
82 aim_tlvlist_free(list);
83 return NULL;
84 }
85 }
86
87 return g_slist_prepend(list, tlv);
49 } 88 }
50 89
51 /** 90 /**
52 * Read a TLV chain from a buffer. 91 * Read a TLV chain from a buffer.
53 * 92 *
54 * Reads and parses a series of TLV patterns from a data buffer; the 93 * Reads and parses a series of TLV patterns from a data buffer; the
55 * returned structure is manipulatable with the rest of the TLV 94 * returned structure is manipulatable with the rest of the TLV
56 * routines. When done with a TLV chain, aim_tlvlist_free() should 95 * routines. When done with a TLV chain, aim_tlvlist_free() should
57 * be called to free the dynamic substructures. 96 * be called to free the dynamic substructures.
58 * 97 *
59 * XXX There should be a flag setable here to have the tlvlist contain 98 * TODO: There should be a flag setable here to have the tlvlist contain
60 * bstream references, so that at least the ->value portion of each 99 * bstream references, so that at least the ->value portion of each
61 * element doesn't need to be malloc/memcpy'd. This could prove to be 100 * element doesn't need to be malloc/memcpy'd. This could prove to be
62 * just as efficient as the in-place TLV parsing used in a couple places 101 * just as efficient as the in-place TLV parsing used in a couple places
63 * in libfaim. 102 * in libfaim.
64 * 103 *
65 * @param bs Input bstream 104 * @param bs Input bstream
66 * @return Return the TLV chain read 105 * @return Return the TLV chain read
67 */ 106 */
68 aim_tlvlist_t *aim_tlvlist_read(ByteStream *bs) 107 GSList *aim_tlvlist_read(ByteStream *bs)
69 { 108 {
70 aim_tlvlist_t *list = NULL, *cur; 109 GSList *list = NULL;
71 110
72 while (byte_stream_empty(bs) > 0) { 111 while (byte_stream_empty(bs) > 0) {
73 guint16 type, length; 112 list = aim_tlv_read(list, bs);
74 113 if (list == NULL)
75 type = byte_stream_get16(bs); 114 return NULL;
76 length = byte_stream_get16(bs); 115 }
77 116
78 #if 0 /* temporarily disabled until I know if they're still doing it or not */ 117 return g_slist_reverse(list);
79 /*
80 * Okay, so now AOL has decided that any TLV of
81 * type 0x0013 can only be two bytes, despite
82 * what the actual given length is. So here
83 * we dump any invalid TLVs of that sort. Hopefully
84 * there's no special cases to this special case.
85 * - mid (30jun2000)
86 */
87 if ((type == 0x0013) && (length != 0x0002))
88 length = 0x0002;
89 #else
90 if (0)
91 ;
92 #endif
93 else {
94
95 if (length > byte_stream_empty(bs)) {
96 aim_tlvlist_free(&list);
97 return NULL;
98 }
99
100 cur = g_new0(aim_tlvlist_t, 1);
101 cur->tlv = createtlv(type, length, NULL);
102 if (cur->tlv->length > 0) {
103 cur->tlv->value = byte_stream_getraw(bs, length);
104 if (!cur->tlv->value) {
105 freetlv(&cur->tlv);
106 g_free(cur);
107 aim_tlvlist_free(&list);
108 return NULL;
109 }
110 }
111
112 cur->next = list;
113 list = cur;
114 }
115 }
116
117 return list;
118 } 118 }
119 119
120 /** 120 /**
121 * Read a TLV chain from a buffer. 121 * Read a TLV chain from a buffer.
122 * 122 *
123 * Reads and parses a series of TLV patterns from a data buffer; the 123 * Reads and parses a series of TLV patterns from a data buffer; the
124 * returned structure is manipulatable with the rest of the TLV 124 * returned structure is manipulatable with the rest of the TLV
125 * routines. When done with a TLV chain, aim_tlvlist_free() should 125 * routines. When done with a TLV chain, aim_tlvlist_free() should
126 * be called to free the dynamic substructures. 126 * be called to free the dynamic substructures.
127 * 127 *
128 * XXX There should be a flag setable here to have the tlvlist contain 128 * TODO: There should be a flag setable here to have the tlvlist contain
129 * bstream references, so that at least the ->value portion of each 129 * bstream references, so that at least the ->value portion of each
130 * element doesn't need to be malloc/memcpy'd. This could prove to be 130 * element doesn't need to be malloc/memcpy'd. This could prove to be
131 * just as efficient as the in-place TLV parsing used in a couple places 131 * just as efficient as the in-place TLV parsing used in a couple places
132 * in libfaim. 132 * in libfaim.
133 * 133 *
136 * There are a number of places where you want to read in a tlvchain, 136 * There are a number of places where you want to read in a tlvchain,
137 * but the chain is not at the end of the SNAC, and the chain is 137 * but the chain is not at the end of the SNAC, and the chain is
138 * preceded by the number of TLVs. So you can limit that with this. 138 * preceded by the number of TLVs. So you can limit that with this.
139 * @return Return the TLV chain read 139 * @return Return the TLV chain read
140 */ 140 */
141 aim_tlvlist_t *aim_tlvlist_readnum(ByteStream *bs, guint16 num) 141 GSList *aim_tlvlist_readnum(ByteStream *bs, guint16 num)
142 { 142 {
143 aim_tlvlist_t *list = NULL, *cur; 143 GSList *list = NULL;
144 144
145 while ((byte_stream_empty(bs) > 0) && (num != 0)) { 145 while ((byte_stream_empty(bs) > 0) && (num != 0)) {
146 guint16 type, length; 146 list = aim_tlv_read(list, bs);
147 147 if (list == NULL)
148 type = byte_stream_get16(bs);
149 length = byte_stream_get16(bs);
150
151 if (length > byte_stream_empty(bs)) {
152 aim_tlvlist_free(&list);
153 return NULL; 148 return NULL;
154 } 149 num--;
155 150 }
156 cur = g_new0(aim_tlvlist_t, 1); 151
157 cur->tlv = createtlv(type, length, NULL); 152 return g_slist_reverse(list);
158 if (cur->tlv->length > 0) {
159 cur->tlv->value = byte_stream_getraw(bs, length);
160 if (!cur->tlv->value) {
161 freetlv(&cur->tlv);
162 g_free(cur);
163 aim_tlvlist_free(&list);
164 return NULL;
165 }
166 }
167
168 if (num > 0)
169 num--;
170 cur->next = list;
171 list = cur;
172 }
173
174 return list;
175 } 153 }
176 154
177 /** 155 /**
178 * Read a TLV chain from a buffer. 156 * Read a TLV chain from a buffer.
179 * 157 *
180 * Reads and parses a series of TLV patterns from a data buffer; the 158 * Reads and parses a series of TLV patterns from a data buffer; the
181 * returned structure is manipulatable with the rest of the TLV 159 * returned structure is manipulatable with the rest of the TLV
182 * routines. When done with a TLV chain, aim_tlvlist_free() should 160 * routines. When done with a TLV chain, aim_tlvlist_free() should
183 * be called to free the dynamic substructures. 161 * be called to free the dynamic substructures.
184 * 162 *
185 * XXX There should be a flag setable here to have the tlvlist contain 163 * TODO: There should be a flag setable here to have the tlvlist contain
186 * bstream references, so that at least the ->value portion of each 164 * bstream references, so that at least the ->value portion of each
187 * element doesn't need to be malloc/memcpy'd. This could prove to be 165 * element doesn't need to be malloc/memcpy'd. This could prove to be
188 * just as efficient as the in-place TLV parsing used in a couple places 166 * just as efficient as the in-place TLV parsing used in a couple places
189 * in libfaim. 167 * in libfaim.
190 * 168 *
193 * There are a number of places where you want to read in a tlvchain, 171 * There are a number of places where you want to read in a tlvchain,
194 * but the chain is not at the end of the SNAC, and the chain is 172 * but the chain is not at the end of the SNAC, and the chain is
195 * preceded by the length of the TLVs. So you can limit that with this. 173 * preceded by the length of the TLVs. So you can limit that with this.
196 * @return Return the TLV chain read 174 * @return Return the TLV chain read
197 */ 175 */
198 aim_tlvlist_t *aim_tlvlist_readlen(ByteStream *bs, guint16 len) 176 GSList *aim_tlvlist_readlen(ByteStream *bs, guint16 len)
199 { 177 {
200 aim_tlvlist_t *list = NULL, *cur; 178 GSList *list = NULL;
201 179
202 while ((byte_stream_empty(bs) > 0) && (len > 0)) { 180 while ((byte_stream_empty(bs) > 0) && (len > 0)) {
203 guint16 type, length; 181 list = aim_tlv_read(list, bs);
204 182 if (list == NULL)
205 type = byte_stream_get16(bs);
206 length = byte_stream_get16(bs);
207
208 if (length > byte_stream_empty(bs)) {
209 aim_tlvlist_free(&list);
210 return NULL; 183 return NULL;
211 } 184
212 185 len -= 2 + 2 + ((aim_tlv_t *)list->data)->length;
213 cur = g_new0(aim_tlvlist_t, 1); 186 }
214 cur->tlv = createtlv(type, length, NULL); 187
215 if (cur->tlv->length > 0) { 188 return g_slist_reverse(list);
216 cur->tlv->value = byte_stream_getraw(bs, length);
217 if (!cur->tlv->value) {
218 freetlv(&cur->tlv);
219 g_free(cur);
220 aim_tlvlist_free(&list);
221 return NULL;
222 }
223 }
224
225 len -= aim_tlvlist_size(&cur);
226 cur->next = list;
227 list = cur;
228 }
229
230 return list;
231 } 189 }
232 190
233 /** 191 /**
234 * Duplicate a TLV chain. 192 * Duplicate a TLV chain.
235 * This is pretty self explanatory. 193 * This is pretty self explanatory.
236 * 194 *
237 * @param orig The TLV chain you want to make a copy of. 195 * @param orig The TLV chain you want to make a copy of.
238 * @return A newly allocated TLV chain. 196 * @return A newly allocated TLV chain.
239 */ 197 */
240 aim_tlvlist_t *aim_tlvlist_copy(aim_tlvlist_t *orig) 198 GSList *aim_tlvlist_copy(GSList *orig)
241 { 199 {
242 aim_tlvlist_t *new = NULL; 200 GSList *new = NULL;
243 201 aim_tlv_t *tlv;
244 while (orig) { 202
245 aim_tlvlist_add_raw(&new, orig->tlv->type, orig->tlv->length, orig->tlv->value); 203 while (orig != NULL) {
204 tlv = orig->data;
205 aim_tlvlist_add_raw(&new, tlv->type, tlv->length, tlv->value);
246 orig = orig->next; 206 orig = orig->next;
247 } 207 }
248 208
249 return new; 209 return new;
250 } 210 }
255 * 215 *
256 * @param one One of the TLV chains to compare. 216 * @param one One of the TLV chains to compare.
257 * @param two The other TLV chain to compare. 217 * @param two The other TLV chain to compare.
258 * @return Return 0 if the lists are the same, return 1 if they are different. 218 * @return Return 0 if the lists are the same, return 1 if they are different.
259 */ 219 */
260 int aim_tlvlist_cmp(aim_tlvlist_t *one, aim_tlvlist_t *two) 220 int aim_tlvlist_cmp(GSList *one, GSList *two)
261 { 221 {
262 ByteStream bs1, bs2; 222 ByteStream bs1, bs2;
263 223
264 if (aim_tlvlist_size(&one) != aim_tlvlist_size(&two)) 224 if (aim_tlvlist_size(one) != aim_tlvlist_size(two))
265 return 1; 225 return 1;
266 226
267 byte_stream_new(&bs1, aim_tlvlist_size(&one)); 227 byte_stream_new(&bs1, aim_tlvlist_size(one));
268 byte_stream_new(&bs2, aim_tlvlist_size(&two)); 228 byte_stream_new(&bs2, aim_tlvlist_size(two));
269 229
270 aim_tlvlist_write(&bs1, &one); 230 aim_tlvlist_write(&bs1, &one);
271 aim_tlvlist_write(&bs2, &two); 231 aim_tlvlist_write(&bs2, &two);
272 232
273 if (memcmp(bs1.data, bs2.data, bs1.len)) { 233 if (memcmp(bs1.data, bs2.data, bs1.len)) {
289 * frees each one. Note that any references to this data 249 * frees each one. Note that any references to this data
290 * should be removed before calling this. 250 * should be removed before calling this.
291 * 251 *
292 * @param list Chain to be freed 252 * @param list Chain to be freed
293 */ 253 */
294 void aim_tlvlist_free(aim_tlvlist_t **list) 254 void aim_tlvlist_free(GSList *list)
295 { 255 {
296 aim_tlvlist_t *cur; 256 while (list != NULL)
297 257 {
298 if (!list || !*list) 258 freetlv(list->data);
299 return; 259 list = g_slist_delete_link(list, list);
300 260 }
301 for (cur = *list; cur; ) {
302 aim_tlvlist_t *tmp;
303
304 freetlv(&cur->tlv);
305
306 tmp = cur->next;
307 g_free(cur);
308 cur = tmp;
309 }
310
311 list = NULL;
312
313 return;
314 } 261 }
315 262
316 /** 263 /**
317 * Count the number of TLVs in a chain. 264 * Count the number of TLVs in a chain.
318 * 265 *
319 * @param list Chain to be counted. 266 * @param list Chain to be counted.
320 * @return The number of TLVs stored in the passed chain. 267 * @return The number of TLVs stored in the passed chain.
321 */ 268 */
322 int aim_tlvlist_count(aim_tlvlist_t **list) 269 int aim_tlvlist_count(GSList *list)
323 { 270 {
324 aim_tlvlist_t *cur; 271 GSList *cur;
325 int count; 272 int count;
326 273
327 if (!list || !*list) 274 if (list == NULL)
328 return 0; 275 return 0;
329 276
330 for (cur = *list, count = 0; cur; cur = cur->next) 277 for (cur = list, count = 0; cur; cur = cur->next)
331 count++; 278 count++;
332 279
333 return count; 280 return count;
334 } 281 }
335 282
338 * 285 *
339 * @param list Chain to be sized 286 * @param list Chain to be sized
340 * @return The number of bytes that would be needed to 287 * @return The number of bytes that would be needed to
341 * write the passed TLV chain to a data buffer. 288 * write the passed TLV chain to a data buffer.
342 */ 289 */
343 int aim_tlvlist_size(aim_tlvlist_t **list) 290 int aim_tlvlist_size(GSList *list)
344 { 291 {
345 aim_tlvlist_t *cur; 292 GSList *cur;
346 int size; 293 int size;
347 294
348 if (!list || !*list) 295 if (list == NULL)
349 return 0; 296 return 0;
350 297
351 for (cur = *list, size = 0; cur; cur = cur->next) 298 for (cur = list, size = 0; cur; cur = cur->next)
352 size += (4 + cur->tlv->length); 299 size += (4 + ((aim_tlv_t *)cur->data)->length);
353 300
354 return size; 301 return size;
355 } 302 }
356 303
357 /** 304 /**
362 * @param type TLV type. 309 * @param type TLV type.
363 * @param length Length of string to add (not including %NULL). 310 * @param length Length of string to add (not including %NULL).
364 * @param value String to add. 311 * @param value String to add.
365 * @return The size of the value added. 312 * @return The size of the value added.
366 */ 313 */
367 int aim_tlvlist_add_raw(aim_tlvlist_t **list, const guint16 type, const guint16 length, const guint8 *value) 314 int aim_tlvlist_add_raw(GSList **list, const guint16 type, const guint16 length, const guint8 *value)
368 { 315 {
369 aim_tlvlist_t *newtlv, *cur; 316 aim_tlv_t *tlv;
370 317
371 if (list == NULL) 318 if (list == NULL)
372 return 0; 319 return 0;
373 320
374 newtlv = g_new0(aim_tlvlist_t, 1); 321 tlv = createtlv(type, length, NULL);
375 newtlv->tlv = createtlv(type, length, NULL); 322 if (tlv->length > 0)
376 if (newtlv->tlv->length > 0) 323 tlv->value = g_memdup(value, length);
377 newtlv->tlv->value = g_memdup(value, length); 324
378 325 *list = g_slist_append(*list, tlv);
379 if (!*list) 326
380 *list = newtlv; 327 return tlv->length;
381 else {
382 for(cur = *list; cur->next; cur = cur->next)
383 ;
384 cur->next = newtlv;
385 }
386
387 return newtlv->tlv->length;
388 } 328 }
389 329
390 /** 330 /**
391 * Add a one byte integer to a TLV chain. 331 * Add a one byte integer to a TLV chain.
392 * 332 *
393 * @param list Destination chain. 333 * @param list Destination chain.
394 * @param type TLV type to add. 334 * @param type TLV type to add.
395 * @param value Value to add. 335 * @param value Value to add.
396 * @return The size of the value added. 336 * @return The size of the value added.
397 */ 337 */
398 int aim_tlvlist_add_8(aim_tlvlist_t **list, const guint16 type, const guint8 value) 338 int aim_tlvlist_add_8(GSList **list, const guint16 type, const guint8 value)
399 { 339 {
400 guint8 v8[1]; 340 guint8 v8[1];
401 341
402 aimutil_put8(v8, value); 342 aimutil_put8(v8, value);
403 343
410 * @param list Destination chain. 350 * @param list Destination chain.
411 * @param type TLV type to add. 351 * @param type TLV type to add.
412 * @param value Value to add. 352 * @param value Value to add.
413 * @return The size of the value added. 353 * @return The size of the value added.
414 */ 354 */
415 int aim_tlvlist_add_16(aim_tlvlist_t **list, const guint16 type, const guint16 value) 355 int aim_tlvlist_add_16(GSList **list, const guint16 type, const guint16 value)
416 { 356 {
417 guint8 v16[2]; 357 guint8 v16[2];
418 358
419 aimutil_put16(v16, value); 359 aimutil_put16(v16, value);
420 360
427 * @param list Destination chain. 367 * @param list Destination chain.
428 * @param type TLV type to add. 368 * @param type TLV type to add.
429 * @param value Value to add. 369 * @param value Value to add.
430 * @return The size of the value added. 370 * @return The size of the value added.
431 */ 371 */
432 int aim_tlvlist_add_32(aim_tlvlist_t **list, const guint16 type, const guint32 value) 372 int aim_tlvlist_add_32(GSList **list, const guint16 type, const guint32 value)
433 { 373 {
434 guint8 v32[4]; 374 guint8 v32[4];
435 375
436 aimutil_put32(v32, value); 376 aimutil_put32(v32, value);
437 377
444 * @param list Destination chain. 384 * @param list Destination chain.
445 * @param type TLV type to add. 385 * @param type TLV type to add.
446 * @param value Value to add. 386 * @param value Value to add.
447 * @return The size of the value added. 387 * @return The size of the value added.
448 */ 388 */
449 int aim_tlvlist_add_str(aim_tlvlist_t **list, const guint16 type, const char *value) 389 int aim_tlvlist_add_str(GSList **list, const guint16 type, const char *value)
450 { 390 {
451 return aim_tlvlist_add_raw(list, type, strlen(value), (guint8 *)value); 391 return aim_tlvlist_add_raw(list, type, strlen(value), (guint8 *)value);
452 } 392 }
453 393
454 /** 394 /**
465 * @param list Destination chain 405 * @param list Destination chain
466 * @param type TLV type to add 406 * @param type TLV type to add
467 * @param caps Bitfield of capability flags to send 407 * @param caps Bitfield of capability flags to send
468 * @return The size of the value added. 408 * @return The size of the value added.
469 */ 409 */
470 int aim_tlvlist_add_caps(aim_tlvlist_t **list, const guint16 type, const guint32 caps) 410 int aim_tlvlist_add_caps(GSList **list, const guint16 type, const guint32 caps)
471 { 411 {
472 guint8 buf[16*16]; /* XXX icky fixed length buffer */ 412 guint8 buf[256]; /* TODO: Don't use a fixed length buffer */
473 ByteStream bs; 413 ByteStream bs;
474 414
475 if (!caps) 415 if (caps == 0)
476 return 0; /* nothing there anyway */ 416 return 0; /* nothing there anyway */
477 417
478 byte_stream_init(&bs, buf, sizeof(buf)); 418 byte_stream_init(&bs, buf, sizeof(buf));
479 419
480 byte_stream_putcaps(&bs, caps); 420 byte_stream_putcaps(&bs, caps);
487 * 427 *
488 * @param list Destination chain. 428 * @param list Destination chain.
489 * @param type TLV type to add. 429 * @param type TLV type to add.
490 * @return The size of the value added. 430 * @return The size of the value added.
491 */ 431 */
492 int aim_tlvlist_add_userinfo(aim_tlvlist_t **list, guint16 type, aim_userinfo_t *userinfo) 432 int aim_tlvlist_add_userinfo(GSList **list, guint16 type, aim_userinfo_t *userinfo)
493 { 433 {
494 guint8 buf[1024]; /* bleh */ 434 guint8 buf[1024]; /* TODO: Don't use a fixed length buffer */
495 ByteStream bs; 435 ByteStream bs;
496 436
497 byte_stream_init(&bs, buf, sizeof(buf)); 437 byte_stream_init(&bs, buf, sizeof(buf));
498 438
499 aim_putuserinfo(&bs, userinfo); 439 aim_putuserinfo(&bs, userinfo);
508 * @param type TLV type to add. 448 * @param type TLV type to add.
509 * @param roomname The name of the chat. 449 * @param roomname The name of the chat.
510 * @param instance The instance. 450 * @param instance The instance.
511 * @return The size of the value added. 451 * @return The size of the value added.
512 */ 452 */
513 int aim_tlvlist_add_chatroom(aim_tlvlist_t **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance) 453 int aim_tlvlist_add_chatroom(GSList **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance)
514 { 454 {
515 int len; 455 int len;
516 ByteStream bs; 456 ByteStream bs;
517 457
518 byte_stream_new(&bs, 2 + 1 + strlen(roomname) + 2); 458 byte_stream_new(&bs, 2 + 1 + strlen(roomname) + 2);
534 * 474 *
535 * @param list Destination chain. 475 * @param list Destination chain.
536 * @param type TLV type to add. 476 * @param type TLV type to add.
537 * @return The size of the value added. 477 * @return The size of the value added.
538 */ 478 */
539 int aim_tlvlist_add_noval(aim_tlvlist_t **list, const guint16 type) 479 int aim_tlvlist_add_noval(GSList **list, const guint16 type)
540 { 480 {
541 return aim_tlvlist_add_raw(list, type, 0, NULL); 481 return aim_tlvlist_add_raw(list, type, 0, NULL);
542 } 482 }
543 483
544 /* 484 /*
545 * Note that the inner TLV chain will not be modifiable as a tlvchain once 485 * Note that the inner TLV chain will not be modifiable as a tlvchain once
546 * it is written using this. Or rather, it can be, but updates won't be 486 * it is written using this. Or rather, it can be, but updates won't be
547 * made to this. 487 * made to this.
548 * 488 *
549 * XXX should probably support sublists for real. 489 * TODO: Should probably support sublists for real.
550 * 490 *
551 * This is so neat. 491 * This is so neat.
552 * 492 *
553 * @param list Destination chain. 493 * @param list Destination chain.
554 * @param type TLV type to add. 494 * @param type TLV type to add.
555 * @param t1 The TLV chain you want to write. 495 * @param t1 The TLV chain you want to write.
556 * @return The number of bytes written to the destination TLV chain. 496 * @return The number of bytes written to the destination TLV chain.
557 * 0 is returned if there was an error or if the destination 497 * 0 is returned if there was an error or if the destination
558 * TLV chain has length 0. 498 * TLV chain has length 0.
559 */ 499 */
560 int aim_tlvlist_add_frozentlvlist(aim_tlvlist_t **list, guint16 type, aim_tlvlist_t **tl) 500 int aim_tlvlist_add_frozentlvlist(GSList **list, guint16 type, GSList **tlvlist)
561 { 501 {
562 int buflen; 502 int buflen;
563 ByteStream bs; 503 ByteStream bs;
564 504
565 buflen = aim_tlvlist_size(tl); 505 buflen = aim_tlvlist_size(*tlvlist);
566 506
567 if (buflen <= 0) 507 if (buflen <= 0)
568 return 0; 508 return 0;
569 509
570 byte_stream_new(&bs, buflen); 510 byte_stream_new(&bs, buflen);
571 511
572 aim_tlvlist_write(&bs, tl); 512 aim_tlvlist_write(&bs, tlvlist);
573 513
574 aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), bs.data); 514 aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), bs.data);
575 515
576 g_free(bs.data); 516 g_free(bs.data);
577 517
587 * @param type TLV type. 527 * @param type TLV type.
588 * @param length Length of string to add (not including %NULL). 528 * @param length Length of string to add (not including %NULL).
589 * @param value String to add. 529 * @param value String to add.
590 * @return The length of the TLV. 530 * @return The length of the TLV.
591 */ 531 */
592 int aim_tlvlist_replace_raw(aim_tlvlist_t **list, const guint16 type, const guint16 length, const guint8 *value) 532 int aim_tlvlist_replace_raw(GSList **list, const guint16 type, const guint16 length, const guint8 *value)
593 { 533 {
594 aim_tlvlist_t *cur; 534 GSList *cur;
535 aim_tlv_t *tlv;
595 536
596 if (list == NULL) 537 if (list == NULL)
597 return 0; 538 return 0;
598 539
599 for (cur = *list; ((cur != NULL) && (cur->tlv->type != type)); cur = cur->next); 540 for (cur = *list; cur != NULL; cur = cur->next)
541 {
542 tlv = cur->data;
543 if (tlv->type == type)
544 break;
545 }
546
600 if (cur == NULL) 547 if (cur == NULL)
548 /* TLV does not exist, so add a new one */
601 return aim_tlvlist_add_raw(list, type, length, value); 549 return aim_tlvlist_add_raw(list, type, length, value);
602 550
603 g_free(cur->tlv->value); 551 g_free(tlv->value);
604 cur->tlv->length = length; 552 tlv->length = length;
605 if (cur->tlv->length > 0) { 553 if (tlv->length > 0) {
606 cur->tlv->value = g_memdup(value, length); 554 tlv->value = g_memdup(value, length);
607 } else 555 } else
608 cur->tlv->value = NULL; 556 tlv->value = NULL;
609 557
610 return cur->tlv->length; 558 return tlv->length;
611 } 559 }
612 560
613 /** 561 /**
614 * Substitute a TLV of a given type with a new TLV of the same type. If 562 * Substitute a TLV of a given type with a new TLV of the same type. If
615 * you attempt to replace a TLV that does not exist, this function will 563 * you attempt to replace a TLV that does not exist, this function will
618 * @param list Desination chain (%NULL pointer if empty). 566 * @param list Desination chain (%NULL pointer if empty).
619 * @param type TLV type. 567 * @param type TLV type.
620 * @param str String to add. 568 * @param str String to add.
621 * @return The length of the TLV. 569 * @return The length of the TLV.
622 */ 570 */
623 int aim_tlvlist_replace_str(aim_tlvlist_t **list, const guint16 type, const char *str) 571 int aim_tlvlist_replace_str(GSList **list, const guint16 type, const char *str)
624 { 572 {
625 return aim_tlvlist_replace_raw(list, type, strlen(str), (const guchar *)str); 573 return aim_tlvlist_replace_raw(list, type, strlen(str), (const guchar *)str);
626 } 574 }
627 575
628 /** 576 /**
632 * 580 *
633 * @param list Desination chain (%NULL pointer if empty). 581 * @param list Desination chain (%NULL pointer if empty).
634 * @param type TLV type. 582 * @param type TLV type.
635 * @return The length of the TLV. 583 * @return The length of the TLV.
636 */ 584 */
637 int aim_tlvlist_replace_noval(aim_tlvlist_t **list, const guint16 type) 585 int aim_tlvlist_replace_noval(GSList **list, const guint16 type)
638 { 586 {
639 return aim_tlvlist_replace_raw(list, type, 0, NULL); 587 return aim_tlvlist_replace_raw(list, type, 0, NULL);
640 } 588 }
641 589
642 /** 590 /**
647 * @param list Desination chain (%NULL pointer if empty). 595 * @param list Desination chain (%NULL pointer if empty).
648 * @param type TLV type. 596 * @param type TLV type.
649 * @param value 8 bit value to add. 597 * @param value 8 bit value to add.
650 * @return The length of the TLV. 598 * @return The length of the TLV.
651 */ 599 */
652 int aim_tlvlist_replace_8(aim_tlvlist_t **list, const guint16 type, const guint8 value) 600 int aim_tlvlist_replace_8(GSList **list, const guint16 type, const guint8 value)
653 { 601 {
654 guint8 v8[1]; 602 guint8 v8[1];
655 603
656 aimutil_put8(v8, value); 604 aimutil_put8(v8, value);
657 605
666 * @param list Desination chain (%NULL pointer if empty). 614 * @param list Desination chain (%NULL pointer if empty).
667 * @param type TLV type. 615 * @param type TLV type.
668 * @param value 32 bit value to add. 616 * @param value 32 bit value to add.
669 * @return The length of the TLV. 617 * @return The length of the TLV.
670 */ 618 */
671 int aim_tlvlist_replace_32(aim_tlvlist_t **list, const guint16 type, const guint32 value) 619 int aim_tlvlist_replace_32(GSList **list, const guint16 type, const guint32 value)
672 { 620 {
673 guint8 v32[4]; 621 guint8 v32[4];
674 622
675 aimutil_put32(v32, value); 623 aimutil_put32(v32, value);
676 624
677 return aim_tlvlist_replace_raw(list, type, 4, v32); 625 return aim_tlvlist_replace_raw(list, type, 4, v32);
678 } 626 }
679 627
680 /** 628 /**
681 * Remove a TLV of a given type. If you attempt to remove a TLV that 629 * Remove all TLVs of a given type. If you attempt to remove a TLV
682 * does not exist, nothing happens. 630 * that does not exist, nothing happens.
683 * 631 *
684 * @param list Desination chain (%NULL pointer if empty). 632 * @param list Desination chain (%NULL pointer if empty).
685 * @param type TLV type. 633 * @param type TLV type.
686 */ 634 */
687 void aim_tlvlist_remove(aim_tlvlist_t **list, const guint16 type) 635 void aim_tlvlist_remove(GSList **list, const guint16 type)
688 { 636 {
689 aim_tlvlist_t *del; 637 GSList *cur, *next;
690 638 aim_tlv_t *tlv;
691 if (!list || !(*list)) 639
640 if (list == NULL || *list == NULL)
692 return; 641 return;
693 642
694 /* Remove the item from the list */ 643 cur = *list;
695 if ((*list)->tlv->type == type) { 644 while (cur != NULL)
696 del = *list; 645 {
697 *list = (*list)->next; 646 tlv = cur->data;
698 } else { 647 next = cur->next;
699 aim_tlvlist_t *cur; 648
700 for (cur=*list; (cur->next && (cur->next->tlv->type!=type)); cur=cur->next); 649 if (tlv->type == type)
701 if (!cur->next) 650 {
702 return; 651 /* Delete this TLV */
703 del = cur->next; 652 *list = g_slist_delete_link(*list, cur);
704 cur->next = del->next; 653 g_free(tlv->value);
705 } 654 g_free(tlv);
706 655 }
707 /* Free the removed item */ 656
708 g_free(del->tlv->value); 657 cur = next;
709 g_free(del->tlv); 658 }
710 g_free(del);
711 } 659 }
712 660
713 /** 661 /**
714 * Write a TLV chain into a data buffer. 662 * Write a TLV chain into a data buffer.
715 * 663 *
716 * Copies a TLV chain into a raw data buffer, writing only the number 664 * Copies a TLV chain into a raw data buffer, writing only the number
717 * of bytes specified. This operation does not free the chain; 665 * of bytes specified. This operation does not free the chain;
718 * aim_tlvlist_free() must still be called to free up the memory used 666 * aim_tlvlist_free() must still be called to free up the memory used
719 * by the chain structures. 667 * by the chain structures.
720 * 668 *
721 * XXX clean this up, make better use of bstreams 669 * TODO: Clean this up, make better use of bstreams
722 * 670 *
723 * @param bs Input bstream 671 * @param bs Input bstream
724 * @param list Source TLV chain 672 * @param list Source TLV chain
725 * @return Return 0 if the destination bstream is too small. 673 * @return Return 0 if the destination bstream is too small.
726 */ 674 */
727 int aim_tlvlist_write(ByteStream *bs, aim_tlvlist_t **list) 675 int aim_tlvlist_write(ByteStream *bs, GSList **list)
728 { 676 {
729 int goodbuflen; 677 int goodbuflen;
730 aim_tlvlist_t *cur; 678 GSList *cur;
679 aim_tlv_t *tlv;
731 680
732 /* do an initial run to test total length */ 681 /* do an initial run to test total length */
733 goodbuflen = aim_tlvlist_size(list); 682 goodbuflen = aim_tlvlist_size(*list);
734 683
735 if (goodbuflen > byte_stream_empty(bs)) 684 if (goodbuflen > byte_stream_empty(bs))
736 return 0; /* not enough buffer */ 685 return 0; /* not enough buffer */
737 686
738 /* do the real write-out */ 687 /* do the real write-out */
739 for (cur = *list; cur; cur = cur->next) { 688 for (cur = *list; cur; cur = cur->next) {
740 byte_stream_put16(bs, cur->tlv->type); 689 tlv = cur->data;
741 byte_stream_put16(bs, cur->tlv->length); 690 byte_stream_put16(bs, tlv->type);
742 if (cur->tlv->length) 691 byte_stream_put16(bs, tlv->length);
743 byte_stream_putraw(bs, cur->tlv->value, cur->tlv->length); 692 if (tlv->length > 0)
744 } 693 byte_stream_putraw(bs, tlv->value, tlv->length);
745 694 }
746 return 1; /* XXX this is a nonsensical return */ 695
696 return 1; /* TODO: This is a nonsensical return */
747 } 697 }
748 698
749 699
750 /** 700 /**
751 * Grab the Nth TLV of type type in the TLV list list. 701 * Grab the Nth TLV of type type in the TLV list list.
758 * @param list Source chain. 708 * @param list Source chain.
759 * @param type Requested TLV type. 709 * @param type Requested TLV type.
760 * @param nth Index of TLV of type to get. 710 * @param nth Index of TLV of type to get.
761 * @return The TLV you were looking for, or NULL if one could not be found. 711 * @return The TLV you were looking for, or NULL if one could not be found.
762 */ 712 */
763 aim_tlv_t *aim_tlv_gettlv(aim_tlvlist_t *list, const guint16 type, const int nth) 713 aim_tlv_t *aim_tlv_gettlv(GSList *list, const guint16 type, const int nth)
764 { 714 {
765 aim_tlvlist_t *cur; 715 GSList *cur;
716 aim_tlv_t *tlv;
766 int i; 717 int i;
767 718
768 for (cur = list, i = 0; cur; cur = cur->next) { 719 for (cur = list, i = 0; cur != NULL; cur = cur->next) {
769 if (cur && cur->tlv) { 720 tlv = cur->data;
770 if (cur->tlv->type == type) 721 if (tlv != NULL) { /* TODO: This NULL check shouldn't be needed */
722 if (tlv->type == type)
771 i++; 723 i++;
772 if (i >= nth) 724 if (i >= nth)
773 return cur->tlv; 725 return tlv;
774 } 726 }
775 } 727 }
776 728
777 return NULL; 729 return NULL;
778 } 730 }
784 * @param type Requested TLV type. 736 * @param type Requested TLV type.
785 * @param nth Index of TLV of type to get. 737 * @param nth Index of TLV of type to get.
786 * @return The length of the data in this TLV, or -1 if the TLV could not be 738 * @return The length of the data in this TLV, or -1 if the TLV could not be
787 * found. Unless -1 is returned, this value will be 2 bytes. 739 * found. Unless -1 is returned, this value will be 2 bytes.
788 */ 740 */
789 int aim_tlv_getlength(aim_tlvlist_t *list, const guint16 type, const int nth) 741 int aim_tlv_getlength(GSList *list, const guint16 type, const int nth)
790 { 742 {
791 aim_tlvlist_t *cur; 743 aim_tlv_t *tlv;
792 int i; 744
793 745 tlv = aim_tlv_gettlv(list, type, nth);
794 for (cur = list, i = 0; cur; cur = cur->next) { 746 if (tlv == NULL)
795 if (cur && cur->tlv) { 747 return -1;
796 if (cur->tlv->type == type) 748
797 i++; 749 return tlv->length;
798 if (i >= nth)
799 return cur->tlv->length;
800 }
801 }
802
803 return -1;
804 } 750 }
805 751
806 char * 752 char *
807 aim_tlv_getvalue_as_string(aim_tlv_t *tlv) 753 aim_tlv_getvalue_as_string(aim_tlv_t *tlv)
808 { 754 {
823 * @param nth Index of TLV to return. 769 * @param nth Index of TLV to return.
824 * @return The value of the TLV you were looking for, or NULL if one could 770 * @return The value of the TLV you were looking for, or NULL if one could
825 * not be found. This is a dynamic buffer and must be freed by the 771 * not be found. This is a dynamic buffer and must be freed by the
826 * caller. 772 * caller.
827 */ 773 */
828 char *aim_tlv_getstr(aim_tlvlist_t *list, const guint16 type, const int nth) 774 char *aim_tlv_getstr(GSList *list, const guint16 type, const int nth)
829 { 775 {
830 aim_tlv_t *tlv; 776 aim_tlv_t *tlv;
831 777
832 if (!(tlv = aim_tlv_gettlv(list, type, nth))) 778 tlv = aim_tlv_gettlv(list, type, nth);
779 if (tlv == NULL)
833 return NULL; 780 return NULL;
834 781
835 return aim_tlv_getvalue_as_string(tlv); 782 return aim_tlv_getvalue_as_string(tlv);
836 } 783 }
837 784
843 * @param type TLV type to search for. 790 * @param type TLV type to search for.
844 * @param nth Index of TLV to return. 791 * @param nth Index of TLV to return.
845 * @return The value the TLV you were looking for, or 0 if one could 792 * @return The value the TLV you were looking for, or 0 if one could
846 * not be found. 793 * not be found.
847 */ 794 */
848 guint8 aim_tlv_get8(aim_tlvlist_t *list, const guint16 type, const int nth) 795 guint8 aim_tlv_get8(GSList *list, const guint16 type, const int nth)
849 { 796 {
850 aim_tlv_t *tlv; 797 aim_tlv_t *tlv;
851 798
852 if (!(tlv = aim_tlv_gettlv(list, type, nth))) 799 tlv = aim_tlv_gettlv(list, type, nth);
800 if (tlv == NULL)
853 return 0; /* erm */ 801 return 0; /* erm */
802
854 return aimutil_get8(tlv->value); 803 return aimutil_get8(tlv->value);
855 } 804 }
856 805
857 /** 806 /**
858 * Retrieve the data from the nth TLV in the given TLV chain as a 16bit 807 * Retrieve the data from the nth TLV in the given TLV chain as a 16bit
862 * @param type TLV type to search for. 811 * @param type TLV type to search for.
863 * @param nth Index of TLV to return. 812 * @param nth Index of TLV to return.
864 * @return The value the TLV you were looking for, or 0 if one could 813 * @return The value the TLV you were looking for, or 0 if one could
865 * not be found. 814 * not be found.
866 */ 815 */
867 guint16 aim_tlv_get16(aim_tlvlist_t *list, const guint16 type, const int nth) 816 guint16 aim_tlv_get16(GSList *list, const guint16 type, const int nth)
868 { 817 {
869 aim_tlv_t *tlv; 818 aim_tlv_t *tlv;
870 819
871 if (!(tlv = aim_tlv_gettlv(list, type, nth))) 820 tlv = aim_tlv_gettlv(list, type, nth);
821 if (tlv == NULL)
872 return 0; /* erm */ 822 return 0; /* erm */
823
873 return aimutil_get16(tlv->value); 824 return aimutil_get16(tlv->value);
874 } 825 }
875 826
876 /** 827 /**
877 * Retrieve the data from the nth TLV in the given TLV chain as a 32bit 828 * Retrieve the data from the nth TLV in the given TLV chain as a 32bit
881 * @param type TLV type to search for. 832 * @param type TLV type to search for.
882 * @param nth Index of TLV to return. 833 * @param nth Index of TLV to return.
883 * @return The value the TLV you were looking for, or 0 if one could 834 * @return The value the TLV you were looking for, or 0 if one could
884 * not be found. 835 * not be found.
885 */ 836 */
886 guint32 aim_tlv_get32(aim_tlvlist_t *list, const guint16 type, const int nth) 837 guint32 aim_tlv_get32(GSList *list, const guint16 type, const int nth)
887 { 838 {
888 aim_tlv_t *tlv; 839 aim_tlv_t *tlv;
889 840
890 if (!(tlv = aim_tlv_gettlv(list, type, nth))) 841 tlv = aim_tlv_gettlv(list, type, nth);
842 if (tlv == NULL)
891 return 0; /* erm */ 843 return 0; /* erm */
844
892 return aimutil_get32(tlv->value); 845 return aimutil_get32(tlv->value);
893 } 846 }