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