comparison libpurple/protocols/oscar/family_feedbag.c @ 32295:dc120ca9f523

propagate from branch 'im.pidgin.pidgin' (head bfb757dfe6b2549ab37a9b19f78f5f1f2f9df0cd) to branch 'im.pidgin.pidgin.next.major' (head fc195a83f896d038c367b1e92cc1bebd7e8246ab)
author Mark Doliner <mark@kingant.net>
date Mon, 21 Mar 2011 05:45:22 +0000
parents 0cf50b0f7af4 8d6630912021
children 142429bcb4c8
comparison
equal deleted inserted replaced
31855:62dc884f2dec 32295:dc120ca9f523
19 */ 19 */
20 20
21 /* 21 /*
22 * Family 0x0013 - Server-Side/Stored Information. 22 * Family 0x0013 - Server-Side/Stored Information.
23 * 23 *
24 * Relatively new facility that allows certain types of information, such as 24 * Deals with storing certain types of information, such as a user's buddy
25 * a user's buddy list, permit/deny list, and permit/deny preferences, to be 25 * list, permit/deny list, and permit/deny preferences, on the server, so
26 * stored on the server, so that they can be accessed from any client. 26 * that they can be accessed from any client.
27 * 27 *
28 * We keep 2 copies of SSI data: 28 * We keep 2 copies of SSI data:
29 * 1) An exact copy of what is stored on the AIM servers. 29 * 1) An exact copy of what is stored on the AIM servers.
30 * 2) A local copy that we make changes to, and then send diffs 30 * 2) A local copy that we make changes to, and then send diffs
31 * between this and the exact copy to keep them in sync. 31 * between this and the exact copy to keep them in sync.
38 * starting with the request rights function (subtype 0x0002), then parse 38 * starting with the request rights function (subtype 0x0002), then parse
39 * rights (subtype 0x0003), then--well, you get the idea. 39 * rights (subtype 0x0003), then--well, you get the idea.
40 * 40 *
41 * This is entirely too complicated. 41 * This is entirely too complicated.
42 * You don't know the half of it. 42 * You don't know the half of it.
43 *
44 */ 43 */
45 44
46 #include "oscar.h" 45 #include "oscar.h"
46 #include "oscarcommon.h"
47 #include "debug.h" 47 #include "debug.h"
48 48
49 static int aim_ssi_addmoddel(OscarData *od); 49 static int aim_ssi_addmoddel(OscarData *od);
50
51 static void aim_ssi_item_free(struct aim_ssi_item *item)
52 {
53 g_free(item->name);
54 aim_tlvlist_free(item->data);
55 g_free(item);
56 }
57
58 static void aim_ssi_item_set_name(struct aim_ssi_itemlist *list, struct aim_ssi_item *item, const char *name)
59 {
60 gchar key[3000];
61
62 if (item->name) {
63 /* Remove old name from hash table */
64 snprintf(key, sizeof(key), "%hx%s", item->type, oscar_normalize(NULL, item->name));
65 g_hash_table_remove(list->idx_all_named_items, key);
66 }
67
68 g_free(item->name);
69 item->name = g_strdup(name);
70
71 if (name) {
72 /* Add new name to hash table */
73 snprintf(key, sizeof(key), "%hx%s", item->type, oscar_normalize(NULL, item->name));
74 g_hash_table_insert(list->idx_all_named_items, g_strdup(key), item);
75 }
76 }
50 77
51 /** 78 /**
52 * List types based on http://dev.aol.com/aim/oscar/#FEEDBAG (archive.org) 79 * List types based on http://dev.aol.com/aim/oscar/#FEEDBAG (archive.org)
53 * and http://iserverd.khstu.ru/oscar/ssi_item.html 80 * and http://iserverd.khstu.ru/oscar/ssi_item.html
54 * 81 *
110 * @param name A null terminated string containing the group name, or NULL 137 * @param name A null terminated string containing the group name, or NULL
111 * if you want to modify the master group. 138 * if you want to modify the master group.
112 * @return Return a pointer to the modified item. 139 * @return Return a pointer to the modified item.
113 */ 140 */
114 static void 141 static void
115 aim_ssi_itemlist_rebuildgroup(struct aim_ssi_item *list, const char *name) 142 aim_ssi_itemlist_rebuildgroup(struct aim_ssi_itemlist *list, const char *name)
116 { 143 {
117 int newlen; 144 int newlen;
118 struct aim_ssi_item *cur, *group; 145 struct aim_ssi_item *cur, *group;
119 146
120 /* Find the group */ 147 /* Find the group */
122 return; 149 return;
123 150
124 /* Find the length for the new additional data */ 151 /* Find the length for the new additional data */
125 newlen = 0; 152 newlen = 0;
126 if (group->gid == 0x0000) { 153 if (group->gid == 0x0000) {
127 for (cur=list; cur; cur=cur->next) 154 for (cur=list->data; cur; cur=cur->next)
128 if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid != 0x0000)) 155 if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid != 0x0000))
129 newlen += 2; 156 newlen += 2;
130 } else { 157 } else {
131 for (cur=list; cur; cur=cur->next) 158 for (cur=list->data; cur; cur=cur->next)
132 if ((cur->gid == group->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) 159 if ((cur->gid == group->gid) && (cur->type == AIM_SSI_TYPE_BUDDY))
133 newlen += 2; 160 newlen += 2;
134 } 161 }
135 162
136 /* Build the new TLV list */ 163 /* Build the new TLV list */
137 if (newlen > 0) { 164 if (newlen > 0) {
138 guint8 *newdata; 165 guint8 *newdata;
139 166
140 newdata = (guint8 *)g_malloc((newlen)*sizeof(guint8)); 167 newdata = g_new(guint8, newlen);
141 newlen = 0; 168 newlen = 0;
142 if (group->gid == 0x0000) { 169 if (group->gid == 0x0000) {
143 for (cur=list; cur; cur=cur->next) 170 for (cur=list->data; cur; cur=cur->next)
144 if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid != 0x0000)) 171 if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid != 0x0000))
145 newlen += aimutil_put16(newdata+newlen, cur->gid); 172 newlen += aimutil_put16(newdata+newlen, cur->gid);
146 } else { 173 } else {
147 for (cur=list; cur; cur=cur->next) 174 for (cur=list->data; cur; cur=cur->next)
148 if ((cur->gid == group->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) 175 if ((cur->gid == group->gid) && (cur->type == AIM_SSI_TYPE_BUDDY))
149 newlen += aimutil_put16(newdata+newlen, cur->bid); 176 newlen += aimutil_put16(newdata+newlen, cur->bid);
150 } 177 }
151 aim_tlvlist_replace_raw(&group->data, 0x00c8, newlen, newdata); 178 aim_tlvlist_replace_raw(&group->data, 0x00c8, newlen, newdata);
152 179
164 * @param bid The buddy ID# you want the new item to have, or 0xFFFF if we should pick something. 191 * @param bid The buddy ID# you want the new item to have, or 0xFFFF if we should pick something.
165 * @param type The type of the item, 0x0000 for a contact, 0x0001 for a group, etc. 192 * @param type The type of the item, 0x0000 for a contact, 0x0001 for a group, etc.
166 * @param data The additional data for the new item. 193 * @param data The additional data for the new item.
167 * @return A pointer to the newly created item. 194 * @return A pointer to the newly created item.
168 */ 195 */
169 static struct aim_ssi_item *aim_ssi_itemlist_add(struct aim_ssi_item **list, const char *name, guint16 gid, guint16 bid, guint16 type, GSList *data) 196 static struct aim_ssi_item *aim_ssi_itemlist_add(struct aim_ssi_itemlist *list, const char *name, guint16 gid, guint16 bid, guint16 type, GSList *data)
170 { 197 {
171 gboolean exists; 198 gboolean exists;
172 struct aim_ssi_item *cur, *new; 199 struct aim_ssi_item *cur, *new;
173 200
174 new = g_new(struct aim_ssi_item, 1); 201 new = g_new0(struct aim_ssi_item, 1);
175
176 /* Set the name */
177 new->name = g_strdup(name);
178 202
179 /* Set the group ID# and buddy ID# */ 203 /* Set the group ID# and buddy ID# */
180 new->gid = gid; 204 new->gid = gid;
181 new->bid = bid; 205 new->bid = bid;
182 if (type == AIM_SSI_TYPE_GROUP) { 206 if (type == AIM_SSI_TYPE_GROUP) {
183 if ((new->gid == 0xFFFF) && name) { 207 if ((new->gid == 0xFFFF) && name) {
184 do { 208 do {
185 new->gid += 0x0001; 209 new->gid += 0x0001;
186 exists = FALSE; 210 exists = FALSE;
187 for (cur = *list; cur != NULL; cur = cur->next) 211 for (cur = list->data; cur != NULL; cur = cur->next)
188 if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid == new->gid)) { 212 if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid == new->gid)) {
189 exists = TRUE; 213 exists = TRUE;
190 break; 214 break;
191 } 215 }
192 } while (exists); 216 } while (exists);
199 */ 223 */
200 if (new->bid == 0xFFFF) { 224 if (new->bid == 0xFFFF) {
201 do { 225 do {
202 new->bid += 0x0001; 226 new->bid += 0x0001;
203 exists = FALSE; 227 exists = FALSE;
204 for (cur = *list; cur != NULL; cur = cur->next) 228 for (cur = list->data; cur != NULL; cur = cur->next)
205 if (cur->bid == new->bid || cur->gid == new->bid) { 229 if (cur->bid == new->bid || cur->gid == new->bid) {
206 exists = TRUE; 230 exists = TRUE;
207 break; 231 break;
208 } 232 }
209 } while (exists); 233 } while (exists);
211 } else { 235 } else {
212 if (new->bid == 0xFFFF) { 236 if (new->bid == 0xFFFF) {
213 do { 237 do {
214 new->bid += 0x0001; 238 new->bid += 0x0001;
215 exists = FALSE; 239 exists = FALSE;
216 for (cur = *list; cur != NULL; cur = cur->next) 240 for (cur = list->data; cur != NULL; cur = cur->next)
217 if (cur->bid == new->bid && cur->gid == new->gid) { 241 if (cur->bid == new->bid && cur->gid == new->gid) {
218 exists = TRUE; 242 exists = TRUE;
219 break; 243 break;
220 } 244 }
221 } while (exists); 245 } while (exists);
223 } 247 }
224 248
225 /* Set the type */ 249 /* Set the type */
226 new->type = type; 250 new->type = type;
227 251
252 /* Add it to the gid+bid hashtable */
253 g_hash_table_insert(list->idx_gid_bid, GINT_TO_POINTER((new->gid << 16) + new->bid), new);
254
255 /* Set the name - do this *AFTER* setting the type because type is used for the key */
256 aim_ssi_item_set_name(list, new, name);
257
228 /* Set the TLV list */ 258 /* Set the TLV list */
229 new->data = aim_tlvlist_copy(data); 259 new->data = aim_tlvlist_copy(data);
230 260
231 /* Add the item to the list in the correct numerical position. Fancy, eh? */ 261 /* Add the item to the list in the correct numerical position. Fancy, eh? */
232 if (*list) { 262 if (list->data) {
233 if ((new->gid < (*list)->gid) || ((new->gid == (*list)->gid) && (new->bid < (*list)->bid))) { 263 if ((new->gid < list->data->gid) || ((new->gid == list->data->gid) && (new->bid < list->data->bid))) {
234 new->next = *list; 264 new->next = list->data;
235 *list = new; 265 list->data = new;
236 } else { 266 } else {
237 struct aim_ssi_item *prev; 267 struct aim_ssi_item *prev;
238 for ((prev=*list, cur=(*list)->next); (cur && ((new->gid > cur->gid) || ((new->gid == cur->gid) && (new->bid > cur->bid)))); prev=cur, cur=cur->next); 268 for ((prev=list->data, cur=list->data->next); (cur && ((new->gid > cur->gid) || ((new->gid == cur->gid) && (new->bid > cur->bid)))); prev=cur, cur=cur->next);
239 new->next = prev->next; 269 new->next = prev->next;
240 prev->next = new; 270 prev->next = new;
241 } 271 }
242 } else { 272 } else {
243 new->next = *list; 273 new->next = list->data;
244 *list = new; 274 list->data = new;
245 } 275 }
246 276
247 return new; 277 return new;
248 } 278 }
249 279
252 * 282 *
253 * @param list A pointer to a pointer to the current list of items. 283 * @param list A pointer to a pointer to the current list of items.
254 * @param del A pointer to the item you want to remove from the list. 284 * @param del A pointer to the item you want to remove from the list.
255 * @return Return 0 if no errors, otherwise return the error number. 285 * @return Return 0 if no errors, otherwise return the error number.
256 */ 286 */
257 static int aim_ssi_itemlist_del(struct aim_ssi_item **list, struct aim_ssi_item *del) 287 static int aim_ssi_itemlist_del(struct aim_ssi_itemlist *list, struct aim_ssi_item *del)
258 { 288 {
259 if (!(*list) || !del) 289 gchar key[3000];
290
291 if (!(list->data) || !del)
260 return -EINVAL; 292 return -EINVAL;
261 293
262 /* Remove the item from the list */ 294 /* Remove the item from the list */
263 if (*list == del) { 295 if (list->data == del) {
264 *list = (*list)->next; 296 list->data = list->data->next;
265 } else { 297 } else {
266 struct aim_ssi_item *cur; 298 struct aim_ssi_item *cur;
267 for (cur=*list; (cur->next && (cur->next!=del)); cur=cur->next); 299 for (cur=list->data; (cur->next && (cur->next!=del)); cur=cur->next);
268 if (cur->next) 300 if (cur->next)
269 cur->next = del->next; 301 cur->next = del->next;
270 } 302 }
271 303
304 /* Remove from the hashtables */
305 g_hash_table_remove(list->idx_gid_bid, GINT_TO_POINTER((del->gid << 16) + del->bid));
306
307 snprintf(key, sizeof(key), "%hx%s", del->type, oscar_normalize(NULL, del->name));
308 g_hash_table_remove(list->idx_all_named_items, key);
309
272 /* Free the removed item */ 310 /* Free the removed item */
273 g_free(del->name); 311 aim_ssi_item_free(del);
274 aim_tlvlist_free(del->data);
275 g_free(del);
276 312
277 return 0; 313 return 0;
278 } 314 }
279 315
280 /** 316 /**
317 return 10; 353 return 10;
318 354
319 return 0; 355 return 0;
320 } 356 }
321 357
322 static gboolean aim_ssi_itemlist_valid(struct aim_ssi_item *list, struct aim_ssi_item *item) 358 static gboolean aim_ssi_itemlist_valid(struct aim_ssi_itemlist *list, struct aim_ssi_item *item)
323 { 359 {
324 struct aim_ssi_item *cur; 360 struct aim_ssi_item *cur;
325 for (cur=list; cur; cur=cur->next) 361 for (cur=list->data; cur; cur=cur->next)
326 if (cur == item) 362 if (cur == item)
327 return TRUE; 363 return TRUE;
328 return FALSE; 364 return FALSE;
329 } 365 }
330 366
334 * @param list A pointer to the current list of items. 370 * @param list A pointer to the current list of items.
335 * @param gid The group ID# of the desired item. 371 * @param gid The group ID# of the desired item.
336 * @param bid The buddy ID# of the desired item. 372 * @param bid The buddy ID# of the desired item.
337 * @return Return a pointer to the item if found, else return NULL; 373 * @return Return a pointer to the item if found, else return NULL;
338 */ 374 */
339 struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, guint16 gid, guint16 bid) 375 struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_itemlist *list, guint16 gid, guint16 bid)
340 { 376 {
341 struct aim_ssi_item *cur; 377 guint32 id_key = (gid << 16) + bid;
342 for (cur=list; cur; cur=cur->next) 378 return g_hash_table_lookup(list->idx_gid_bid, GINT_TO_POINTER(id_key));
343 if ((cur->gid == gid) && (cur->bid == bid))
344 return cur;
345 return NULL;
346 } 379 }
347 380
348 /** 381 /**
349 * Locally find an item given a group name, buddy name, and type. If group name 382 * Locally find an item given a group name, buddy name, and type. If group name
350 * and buddy name are null, then just return the first item of the given type. 383 * and buddy name are null, then just return the first item of the given type.
353 * @param gn The group name of the desired item. 386 * @param gn The group name of the desired item.
354 * @param bn The buddy name of the desired item. 387 * @param bn The buddy name of the desired item.
355 * @param type The type of the desired item. 388 * @param type The type of the desired item.
356 * @return Return a pointer to the item if found, else return NULL. 389 * @return Return a pointer to the item if found, else return NULL.
357 */ 390 */
358 struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *bn, guint16 type) 391 struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_itemlist *list, const char *gn, const char *bn, guint16 type)
359 { 392 {
360 struct aim_ssi_item *cur; 393 struct aim_ssi_item *cur;
361 if (!list) 394 gchar key[3000];
395
396 if (!list->data)
362 return NULL; 397 return NULL;
363 398
364 if (gn && bn) { /* For finding buddies in groups */ 399 if (gn && bn) { /* For finding buddies in groups */
365 for (cur=list; cur; cur=cur->next) 400 g_return_val_if_fail(type == AIM_SSI_TYPE_BUDDY, NULL);
401 for (cur=list->data; cur; cur=cur->next)
366 if ((cur->type == type) && (cur->name) && !(oscar_util_name_compare(cur->name, bn))) { 402 if ((cur->type == type) && (cur->name) && !(oscar_util_name_compare(cur->name, bn))) {
367 struct aim_ssi_item *curg; 403 struct aim_ssi_item *curg;
368 for (curg=list; curg; curg=curg->next) 404 for (curg=list->data; curg; curg=curg->next)
369 if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid) && (curg->name) && !(oscar_util_name_compare(curg->name, gn))) 405 if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid) && (curg->name) && !(oscar_util_name_compare(curg->name, gn)))
370 return cur; 406 return cur;
371 } 407 }
372 408
373 } else if (gn) { /* For finding groups */ 409 } else if (gn || bn) { /* For finding groups, permits, denies and ignores */
374 for (cur=list; cur; cur=cur->next) { 410 snprintf(key, sizeof(key), "%hx%s", type, oscar_normalize(NULL, gn ? gn : bn));
375 if ((cur->type == type) && (cur->bid == 0x0000) && (cur->name) && !(oscar_util_name_compare(cur->name, gn))) { 411 return g_hash_table_lookup(list->idx_all_named_items, key);
376 return cur;
377 }
378 }
379
380 } else if (bn) { /* For finding permits, denies, and ignores */
381 for (cur=list; cur; cur=cur->next) {
382 if ((cur->type == type) && (cur->name) && !(oscar_util_name_compare(cur->name, bn))) {
383 return cur;
384 }
385 }
386 412
387 /* For stuff without names--permit deny setting, visibility mask, etc. */ 413 /* For stuff without names--permit deny setting, visibility mask, etc. */
388 } else for (cur=list; cur; cur=cur->next) { 414 } else for (cur=list->data; cur; cur=cur->next) {
389 if ((cur->type == type) && (!cur->name)) 415 if ((cur->type == type) && (!cur->name))
390 return cur; 416 return cur;
391 } 417 }
392 418
393 return NULL; 419 return NULL;
398 * 424 *
399 * @param list A pointer to the current list of items. 425 * @param list A pointer to the current list of items.
400 * @param bn The group name of the desired item. 426 * @param bn The group name of the desired item.
401 * @return Return a pointer to the name of the item if found, else return NULL; 427 * @return Return a pointer to the name of the item if found, else return NULL;
402 */ 428 */
403 struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_item *list, const char *bn) 429 struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_itemlist *list, const char *bn)
404 { 430 {
405 if (!bn) 431 if (!bn)
406 return NULL; 432 return NULL;
407 return aim_ssi_itemlist_finditem(list, NULL, bn, AIM_SSI_TYPE_BUDDY); 433 return aim_ssi_itemlist_finditem(list, NULL, bn, AIM_SSI_TYPE_BUDDY);
408 } 434 }
412 * 438 *
413 * @param list A pointer to the current list of items. 439 * @param list A pointer to the current list of items.
414 * @param bn The buddy name of the desired item. 440 * @param bn The buddy name of the desired item.
415 * @return Return a pointer to the name of the item if found, else return NULL; 441 * @return Return a pointer to the name of the item if found, else return NULL;
416 */ 442 */
417 char *aim_ssi_itemlist_findparentname(struct aim_ssi_item *list, const char *bn) 443 char *aim_ssi_itemlist_findparentname(struct aim_ssi_itemlist *list, const char *bn)
418 { 444 {
419 struct aim_ssi_item *cur, *curg; 445 struct aim_ssi_item *cur, *curg;
420 if (!list || !bn) 446 if (!list->data || !bn)
421 return NULL; 447 return NULL;
422 if (!(cur = aim_ssi_itemlist_exists(list, bn))) 448 if (!(cur = aim_ssi_itemlist_exists(list, bn)))
423 return NULL; 449 return NULL;
424 if (!(curg = aim_ssi_itemlist_find(list, cur->gid, 0x0000))) 450 if (!(curg = aim_ssi_itemlist_find(list, cur->gid, 0x0000)))
425 return NULL; 451 return NULL;
430 * Locally find the permit/deny setting item, and return the setting. 456 * Locally find the permit/deny setting item, and return the setting.
431 * 457 *
432 * @param list A pointer to the current list of items. 458 * @param list A pointer to the current list of items.
433 * @return Return the current SSI permit deny setting, or 0 if no setting was found. 459 * @return Return the current SSI permit deny setting, or 0 if no setting was found.
434 */ 460 */
435 int aim_ssi_getpermdeny(struct aim_ssi_item *list) 461 int aim_ssi_getpermdeny(struct aim_ssi_itemlist *list)
436 { 462 {
437 struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PDINFO); 463 struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PDINFO);
438 if (cur) { 464 if (cur) {
439 aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x00ca, 1); 465 aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x00ca, 1);
440 if (tlv && tlv->value) 466 if (tlv && tlv->value)
448 * bitmask of the preferences. See the AIM_SSI_PRESENCE_FLAG_* #defines in oscar.h. 474 * bitmask of the preferences. See the AIM_SSI_PRESENCE_FLAG_* #defines in oscar.h.
449 * 475 *
450 * @param list A pointer to the current list of items. 476 * @param list A pointer to the current list of items.
451 * @return Return the current set of preferences. 477 * @return Return the current set of preferences.
452 */ 478 */
453 guint32 aim_ssi_getpresence(struct aim_ssi_item *list) 479 guint32 aim_ssi_getpresence(struct aim_ssi_itemlist *list)
454 { 480 {
455 struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS); 481 struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS);
456 if (cur) { 482 if (cur) {
457 aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x00c9, 1); 483 aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x00c9, 1);
458 if (tlv && tlv->length) 484 if (tlv && tlv->length)
469 * @param bn The name of the buddy. 495 * @param bn The name of the buddy.
470 * @return A pointer to a NULL terminated string that is the buddy's 496 * @return A pointer to a NULL terminated string that is the buddy's
471 * alias, or NULL if the buddy has no alias. You should free 497 * alias, or NULL if the buddy has no alias. You should free
472 * this returned value! 498 * this returned value!
473 */ 499 */
474 char *aim_ssi_getalias(struct aim_ssi_item *list, const char *gn, const char *bn) 500 char *aim_ssi_getalias(struct aim_ssi_itemlist *list, const char *gn, const char *bn)
475 { 501 {
476 struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, bn, AIM_SSI_TYPE_BUDDY); 502 struct aim_ssi_item *item = aim_ssi_itemlist_finditem(list, gn, bn, AIM_SSI_TYPE_BUDDY);
477 if (cur) { 503 if (item) {
478 aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x0131, 1); 504 return aim_ssi_getalias_from_item(item);
479 if (tlv && tlv->length) 505 }
480 return g_strndup((const gchar *)tlv->value, tlv->length); 506 return NULL;
481 } 507 }
508
509 char *aim_ssi_getalias_from_item(struct aim_ssi_item *item)
510 {
511 aim_tlv_t *tlv = aim_tlv_gettlv(item->data, 0x0131, 1);
512 if (tlv && tlv->length)
513 return g_strndup((const gchar *)tlv->value, tlv->length);
482 return NULL; 514 return NULL;
483 } 515 }
484 516
485 /** 517 /**
486 * Locally find the comment of the given buddy. 518 * Locally find the comment of the given buddy.
490 * @param bn The name of the buddy. 522 * @param bn The name of the buddy.
491 * @return A pointer to a NULL terminated string that is the buddy's 523 * @return A pointer to a NULL terminated string that is the buddy's
492 * comment, or NULL if the buddy has no comment. You should free 524 * comment, or NULL if the buddy has no comment. You should free
493 * this returned value! 525 * this returned value!
494 */ 526 */
495 char *aim_ssi_getcomment(struct aim_ssi_item *list, const char *gn, const char *bn) 527 char *aim_ssi_getcomment(struct aim_ssi_itemlist *list, const char *gn, const char *bn)
496 { 528 {
497 struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, bn, AIM_SSI_TYPE_BUDDY); 529 struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, bn, AIM_SSI_TYPE_BUDDY);
498 if (cur) { 530 if (cur) {
499 aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x013c, 1); 531 aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x013c, 1);
500 if (tlv && tlv->length) { 532 if (tlv && tlv->length) {
510 * @param list A pointer to the current list of items. 542 * @param list A pointer to the current list of items.
511 * @param gn The group of the buddy. 543 * @param gn The group of the buddy.
512 * @param bn The name of the buddy. 544 * @param bn The name of the buddy.
513 * @return 1 if you are waiting for authorization; 0 if you are not 545 * @return 1 if you are waiting for authorization; 0 if you are not
514 */ 546 */
515 gboolean aim_ssi_waitingforauth(struct aim_ssi_item *list, const char *gn, const char *bn) 547 gboolean aim_ssi_waitingforauth(struct aim_ssi_itemlist *list, const char *gn, const char *bn)
516 { 548 {
517 struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, bn, AIM_SSI_TYPE_BUDDY); 549 struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, bn, AIM_SSI_TYPE_BUDDY);
518 if (cur) { 550 if (cur) {
519 if (aim_tlv_gettlv(cur->data, 0x0066, 1)) 551 if (aim_tlv_gettlv(cur->data, 0x0066, 1))
520 return TRUE; 552 return TRUE;
558 * buddy ID#s, which makes things more efficient. I think. 590 * buddy ID#s, which makes things more efficient. I think.
559 */ 591 */
560 592
561 /* Deletions */ 593 /* Deletions */
562 if (!od->ssi.pending) { 594 if (!od->ssi.pending) {
563 for (cur1=od->ssi.official; cur1 && (n < 15); cur1=cur1->next) { 595 for (cur1=od->ssi.official.data; cur1 && (n < 15); cur1=cur1->next) {
564 if (!aim_ssi_itemlist_find(od->ssi.local, cur1->gid, cur1->bid)) { 596 if (!aim_ssi_itemlist_find(&od->ssi.local, cur1->gid, cur1->bid)) {
565 n++; 597 n++;
566 new = g_new(struct aim_ssi_tmp, 1); 598 new = g_new(struct aim_ssi_tmp, 1);
567 new->action = SNAC_SUBTYPE_FEEDBAG_DEL; 599 new->action = SNAC_SUBTYPE_FEEDBAG_DEL;
568 new->ack = 0xffff; 600 new->ack = 0xffff;
569 new->name = NULL; 601 new->name = NULL;
572 if (od->ssi.pending) { 604 if (od->ssi.pending) {
573 for (cur=od->ssi.pending; cur->next; cur=cur->next); 605 for (cur=od->ssi.pending; cur->next; cur=cur->next);
574 cur->next = new; 606 cur->next = new;
575 } else 607 } else
576 od->ssi.pending = new; 608 od->ssi.pending = new;
577 aim_ssi_item_debug_append(debugstr, "Deleting item ", cur1); 609 aim_ssi_item_debug_append(debugstr, "Deleting item ", cur1);
578 } 610 }
579 } 611 }
580 } 612 }
581 613
582 /* Additions */ 614 /* Additions */
583 if (!od->ssi.pending) { 615 if (!od->ssi.pending) {
584 for (cur1=od->ssi.local; cur1 && (n < 15); cur1=cur1->next) { 616 for (cur1=od->ssi.local.data; cur1 && (n < 15); cur1=cur1->next) {
585 if (!aim_ssi_itemlist_find(od->ssi.official, cur1->gid, cur1->bid)) { 617 if (!aim_ssi_itemlist_find(&od->ssi.official, cur1->gid, cur1->bid)) {
586 n++; 618 n++;
587 new = g_new(struct aim_ssi_tmp, 1); 619 new = g_new(struct aim_ssi_tmp, 1);
588 new->action = SNAC_SUBTYPE_FEEDBAG_ADD; 620 new->action = SNAC_SUBTYPE_FEEDBAG_ADD;
589 new->ack = 0xffff; 621 new->ack = 0xffff;
590 new->name = NULL; 622 new->name = NULL;
593 if (od->ssi.pending) { 625 if (od->ssi.pending) {
594 for (cur=od->ssi.pending; cur->next; cur=cur->next); 626 for (cur=od->ssi.pending; cur->next; cur=cur->next);
595 cur->next = new; 627 cur->next = new;
596 } else 628 } else
597 od->ssi.pending = new; 629 od->ssi.pending = new;
598 aim_ssi_item_debug_append(debugstr, "Adding item ", cur1); 630 aim_ssi_item_debug_append(debugstr, "Adding item ", cur1);
599 } 631 }
600 } 632 }
601 } 633 }
602 634
603 /* Modifications */ 635 /* Modifications */
604 if (!od->ssi.pending) { 636 if (!od->ssi.pending) {
605 for (cur1=od->ssi.local; cur1 && (n < 15); cur1=cur1->next) { 637 for (cur1=od->ssi.local.data; cur1 && (n < 15); cur1=cur1->next) {
606 cur2 = aim_ssi_itemlist_find(od->ssi.official, cur1->gid, cur1->bid); 638 cur2 = aim_ssi_itemlist_find(&od->ssi.official, cur1->gid, cur1->bid);
607 if (cur2 && (aim_ssi_itemlist_cmp(cur1, cur2))) { 639 if (cur2 && (aim_ssi_itemlist_cmp(cur1, cur2))) {
608 n++; 640 n++;
609 new = g_new(struct aim_ssi_tmp, 1); 641 new = g_new(struct aim_ssi_tmp, 1);
610 new->action = SNAC_SUBTYPE_FEEDBAG_MOD; 642 new->action = SNAC_SUBTYPE_FEEDBAG_MOD;
611 new->ack = 0xffff; 643 new->ack = 0xffff;
615 if (od->ssi.pending) { 647 if (od->ssi.pending) {
616 for (cur=od->ssi.pending; cur->next; cur=cur->next); 648 for (cur=od->ssi.pending; cur->next; cur=cur->next);
617 cur->next = new; 649 cur->next = new;
618 } else 650 } else
619 od->ssi.pending = new; 651 od->ssi.pending = new;
620 aim_ssi_item_debug_append(debugstr, "Modifying item ", cur1); 652 aim_ssi_item_debug_append(debugstr, "Modifying item ", cur1);
621 } 653 }
622 } 654 }
623 } 655 }
624 if (debugstr->len > 0) { 656 if (debugstr->len > 0) {
625 purple_debug_info("oscar", "%s", debugstr->str); 657 purple_debug_info("oscar", "%s", debugstr->str);
626 if (purple_debug_is_verbose()) { 658 if (purple_debug_is_verbose()) {
627 g_string_truncate(debugstr, 0); 659 g_string_truncate(debugstr, 0);
628 for (cur1 = od->ssi.local; cur1; cur1 = cur1->next) 660 for (cur1 = od->ssi.local.data; cur1; cur1 = cur1->next)
629 aim_ssi_item_debug_append(debugstr, "\t", cur1); 661 aim_ssi_item_debug_append(debugstr, "\t", cur1);
630 purple_debug_misc("oscar", "Dumping item list of account %s:\n%s", 662 purple_debug_misc("oscar", "Dumping item list of account %s:\n%s",
631 purple_connection_get_account(od->gc)->username, debugstr->str); 663 purple_connection_get_account(od->gc)->username, debugstr->str);
632 } 664 }
633 } 665 }
670 aim_ssi_freelist(OscarData *od) 702 aim_ssi_freelist(OscarData *od)
671 { 703 {
672 struct aim_ssi_item *cur, *del; 704 struct aim_ssi_item *cur, *del;
673 struct aim_ssi_tmp *curtmp, *deltmp; 705 struct aim_ssi_tmp *curtmp, *deltmp;
674 706
675 cur = od->ssi.official; 707 cur = od->ssi.official.data;
676 while (cur) { 708 while (cur) {
677 del = cur; 709 del = cur;
678 cur = cur->next; 710 cur = cur->next;
679 g_free(del->name); 711 aim_ssi_item_free(del);
680 aim_tlvlist_free(del->data); 712 }
681 g_free(del); 713
682 } 714 cur = od->ssi.local.data;
683
684 cur = od->ssi.local;
685 while (cur) { 715 while (cur) {
686 del = cur; 716 del = cur;
687 cur = cur->next; 717 cur = cur->next;
688 g_free(del->name); 718 aim_ssi_item_free(del);
689 aim_tlvlist_free(del->data);
690 g_free(del);
691 } 719 }
692 720
693 curtmp = od->ssi.pending; 721 curtmp = od->ssi.pending;
694 while (curtmp) { 722 while (curtmp) {
695 deltmp = curtmp; 723 deltmp = curtmp;
696 curtmp = curtmp->next; 724 curtmp = curtmp->next;
697 g_free(deltmp); 725 g_free(deltmp);
698 } 726 }
699 727
700 od->ssi.numitems = 0; 728 od->ssi.numitems = 0;
701 od->ssi.official = NULL; 729 od->ssi.official.data = NULL;
702 od->ssi.local = NULL; 730 od->ssi.local.data = NULL;
703 od->ssi.pending = NULL; 731 od->ssi.pending = NULL;
704 od->ssi.timestamp = (time_t)0; 732 od->ssi.timestamp = (time_t)0;
705 } 733 }
706 734
707 /** 735 /**
723 /* Delete any buddies, permits, or denies with empty names. */ 751 /* Delete any buddies, permits, or denies with empty names. */
724 /* If there are any buddies directly in the master group, add them to a real group. */ 752 /* If there are any buddies directly in the master group, add them to a real group. */
725 /* DESTROY any buddies that are directly in the master group. */ 753 /* DESTROY any buddies that are directly in the master group. */
726 /* Do the same for buddies that are in a non-existant group. */ 754 /* Do the same for buddies that are in a non-existant group. */
727 /* This will kind of mess up if you hit the item limit, but this function isn't too critical */ 755 /* This will kind of mess up if you hit the item limit, but this function isn't too critical */
728 cur = od->ssi.local; 756 cur = od->ssi.local.data;
729 while (cur) { 757 while (cur) {
730 next = cur->next; 758 next = cur->next;
731 if (!cur->name) { 759 if (!cur->name) {
732 if (cur->type == AIM_SSI_TYPE_BUDDY) 760 if (cur->type == AIM_SSI_TYPE_BUDDY)
733 aim_ssi_delbuddy(od, NULL, NULL); 761 aim_ssi_delbuddy(od, NULL, NULL);
734 else if (cur->type == AIM_SSI_TYPE_PERMIT || cur->type == AIM_SSI_TYPE_DENY || cur->type == AIM_SSI_TYPE_ICQDENY) 762 else if (cur->type == AIM_SSI_TYPE_PERMIT || cur->type == AIM_SSI_TYPE_DENY || cur->type == AIM_SSI_TYPE_ICQDENY)
735 aim_ssi_del_from_private_list(od, NULL, cur->type); 763 aim_ssi_del_from_private_list(od, NULL, cur->type);
736 } else if ((cur->type == AIM_SSI_TYPE_BUDDY) && ((cur->gid == 0x0000) || (!aim_ssi_itemlist_find(od->ssi.local, cur->gid, 0x0000)))) { 764 } else if ((cur->type == AIM_SSI_TYPE_BUDDY) && ((cur->gid == 0x0000) || (!aim_ssi_itemlist_find(&od->ssi.local, cur->gid, 0x0000)))) {
737 char *alias = aim_ssi_getalias(od->ssi.local, NULL, cur->name); 765 char *alias = aim_ssi_getalias(&od->ssi.local, NULL, cur->name);
738 aim_ssi_addbuddy(od, cur->name, "orphans", NULL, alias, NULL, NULL, FALSE); 766 aim_ssi_addbuddy(od, cur->name, "orphans", NULL, alias, NULL, NULL, FALSE);
739 aim_ssi_delbuddy(od, cur->name, NULL); 767 aim_ssi_delbuddy(od, cur->name, NULL);
740 g_free(alias); 768 g_free(alias);
741 } 769 }
742 cur = next; 770 cur = next;
743 } 771 }
744 772
745 /* Make sure there aren't any duplicate buddies in a group, or duplicate permits or denies */ 773 /* Make sure there aren't any duplicate buddies in a group, or duplicate permits or denies */
746 cur = od->ssi.local; 774 cur = od->ssi.local.data;
747 while (cur) { 775 while (cur) {
748 if ((cur->type == AIM_SSI_TYPE_BUDDY) || (cur->type == AIM_SSI_TYPE_PERMIT) || (cur->type == AIM_SSI_TYPE_DENY)) 776 if ((cur->type == AIM_SSI_TYPE_BUDDY) || (cur->type == AIM_SSI_TYPE_PERMIT) || (cur->type == AIM_SSI_TYPE_DENY))
749 { 777 {
750 struct aim_ssi_item *cur2, *next2; 778 struct aim_ssi_item *cur2, *next2;
751 cur2 = cur->next; 779 cur2 = cur->next;
782 810
783 if (!od || !name || !group) 811 if (!od || !name || !group)
784 return -EINVAL; 812 return -EINVAL;
785 813
786 /* Find the parent */ 814 /* Find the parent */
787 if (!(parent = aim_ssi_itemlist_finditem(od->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP))) { 815 if (!(parent = aim_ssi_itemlist_finditem(&od->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP))) {
788 /* Find the parent's parent (the master group) */ 816 /* Find the parent's parent (the master group) */
789 if (aim_ssi_itemlist_find(od->ssi.local, 0x0000, 0x0000) == NULL) 817 if (aim_ssi_itemlist_find(&od->ssi.local, 0x0000, 0x0000) == NULL)
790 aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL); 818 aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL);
791 819
792 /* Add the parent */ 820 /* Add the parent */
793 parent = aim_ssi_itemlist_add(&od->ssi.local, group, 0xFFFF, 0x0000, AIM_SSI_TYPE_GROUP, NULL); 821 parent = aim_ssi_itemlist_add(&od->ssi.local, group, 0xFFFF, 0x0000, AIM_SSI_TYPE_GROUP, NULL);
794 822
795 /* Modify the parent's parent (the master group) */ 823 /* Modify the parent's parent (the master group) */
796 aim_ssi_itemlist_rebuildgroup(od->ssi.local, NULL); 824 aim_ssi_itemlist_rebuildgroup(&od->ssi.local, NULL);
797 } 825 }
798 826
799 /* Create a TLV list for the new buddy */ 827 /* Create a TLV list for the new buddy */
800 if (needauth) 828 if (needauth)
801 aim_tlvlist_add_noval(&data, 0x0066); 829 aim_tlvlist_add_noval(&data, 0x0066);
809 /* Add that bad boy */ 837 /* Add that bad boy */
810 aim_ssi_itemlist_add(&od->ssi.local, name, parent->gid, 0xFFFF, AIM_SSI_TYPE_BUDDY, data); 838 aim_ssi_itemlist_add(&od->ssi.local, name, parent->gid, 0xFFFF, AIM_SSI_TYPE_BUDDY, data);
811 aim_tlvlist_free(data); 839 aim_tlvlist_free(data);
812 840
813 /* Modify the parent group */ 841 /* Modify the parent group */
814 aim_ssi_itemlist_rebuildgroup(od->ssi.local, group); 842 aim_ssi_itemlist_rebuildgroup(&od->ssi.local, group);
815 843
816 /* Sync our local list with the server list */ 844 /* Sync our local list with the server list */
817 return aim_ssi_sync(od); 845 return aim_ssi_sync(od);
818 } 846 }
819 847
821 aim_ssi_add_to_private_list(OscarData *od, const char* name, guint16 list_type) 849 aim_ssi_add_to_private_list(OscarData *od, const char* name, guint16 list_type)
822 { 850 {
823 if (!od || !name || !od->ssi.received_data) 851 if (!od || !name || !od->ssi.received_data)
824 return -EINVAL; 852 return -EINVAL;
825 853
826 if (aim_ssi_itemlist_find(od->ssi.local, 0x0000, 0x0000) == NULL) 854 if (aim_ssi_itemlist_find(&od->ssi.local, 0x0000, 0x0000) == NULL)
827 aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL); 855 aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL);
828 856
829 aim_ssi_itemlist_add(&od->ssi.local, name, 0x0000, 0xFFFF, list_type, NULL); 857 aim_ssi_itemlist_add(&od->ssi.local, name, 0x0000, 0xFFFF, list_type, NULL);
830 return aim_ssi_sync(od); 858 return aim_ssi_sync(od);
831 } 859 }
836 struct aim_ssi_item *del; 864 struct aim_ssi_item *del;
837 865
838 if (!od) 866 if (!od)
839 return -EINVAL; 867 return -EINVAL;
840 868
841 if (!(del = aim_ssi_itemlist_finditem(od->ssi.local, NULL, name, list_type))) 869 if (!(del = aim_ssi_itemlist_finditem(&od->ssi.local, NULL, name, list_type)))
842 return -EINVAL; 870 return -EINVAL;
843 871
844 aim_ssi_itemlist_del(&od->ssi.local, del); 872 aim_ssi_itemlist_del(&od->ssi.local, del);
845 return aim_ssi_sync(od); 873 return aim_ssi_sync(od);
846 } 874 }
859 887
860 if (!od) 888 if (!od)
861 return -EINVAL; 889 return -EINVAL;
862 890
863 /* Find the buddy */ 891 /* Find the buddy */
864 if (!(del = aim_ssi_itemlist_finditem(od->ssi.local, group, name, AIM_SSI_TYPE_BUDDY))) 892 if (!(del = aim_ssi_itemlist_finditem(&od->ssi.local, group, name, AIM_SSI_TYPE_BUDDY)))
865 return -EINVAL; 893 return -EINVAL;
866 894
867 /* Remove the item from the list */ 895 /* Remove the item from the list */
868 aim_ssi_itemlist_del(&od->ssi.local, del); 896 aim_ssi_itemlist_del(&od->ssi.local, del);
869 897
870 /* Modify the parent group */ 898 /* Modify the parent group */
871 aim_ssi_itemlist_rebuildgroup(od->ssi.local, group); 899 aim_ssi_itemlist_rebuildgroup(&od->ssi.local, group);
872 900
873 /* Sync our local list with the server list */ 901 /* Sync our local list with the server list */
874 return aim_ssi_sync(od); 902 return aim_ssi_sync(od);
875 } 903 }
876 904
888 916
889 if (!od) 917 if (!od)
890 return -EINVAL; 918 return -EINVAL;
891 919
892 /* Find the group */ 920 /* Find the group */
893 if (!(del = aim_ssi_itemlist_finditem(od->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP))) 921 if (!(del = aim_ssi_itemlist_finditem(&od->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP)))
894 return -EINVAL; 922 return -EINVAL;
895 923
896 /* Don't delete the group if it's not empty */ 924 /* Don't delete the group if it's not empty */
897 tlv = aim_tlv_gettlv(del->data, 0x00c8, 1); 925 tlv = aim_tlv_gettlv(del->data, 0x00c8, 1);
898 if (tlv && tlv->length > 0) 926 if (tlv && tlv->length > 0)
900 928
901 /* Remove the item from the list */ 929 /* Remove the item from the list */
902 aim_ssi_itemlist_del(&od->ssi.local, del); 930 aim_ssi_itemlist_del(&od->ssi.local, del);
903 931
904 /* Modify the parent group */ 932 /* Modify the parent group */
905 aim_ssi_itemlist_rebuildgroup(od->ssi.local, group); 933 aim_ssi_itemlist_rebuildgroup(&od->ssi.local, group);
906 934
907 /* Sync our local list with the server list */ 935 /* Sync our local list with the server list */
908 return aim_ssi_sync(od); 936 return aim_ssi_sync(od);
909 } 937 }
910 938
922 { 950 {
923 struct aim_ssi_item *buddy; 951 struct aim_ssi_item *buddy;
924 GSList *data; 952 GSList *data;
925 953
926 /* Find the buddy */ 954 /* Find the buddy */
927 buddy = aim_ssi_itemlist_finditem(od->ssi.local, oldgn, bn, AIM_SSI_TYPE_BUDDY); 955 buddy = aim_ssi_itemlist_finditem(&od->ssi.local, oldgn, bn, AIM_SSI_TYPE_BUDDY);
928 if (buddy == NULL) 956 if (buddy == NULL)
929 return -EINVAL; 957 return -EINVAL;
930 958
931 /* Make a copy of the buddy's TLV list */ 959 /* Make a copy of the buddy's TLV list */
932 data = aim_tlvlist_copy(buddy->data); 960 data = aim_tlvlist_copy(buddy->data);
955 struct aim_ssi_item *tmp; 983 struct aim_ssi_item *tmp;
956 984
957 if (!od || !gn || !bn) 985 if (!od || !gn || !bn)
958 return -EINVAL; 986 return -EINVAL;
959 987
960 if (!(tmp = aim_ssi_itemlist_finditem(od->ssi.local, gn, bn, AIM_SSI_TYPE_BUDDY))) 988 if (!(tmp = aim_ssi_itemlist_finditem(&od->ssi.local, gn, bn, AIM_SSI_TYPE_BUDDY)))
961 return -EINVAL; 989 return -EINVAL;
962 990
963 /* Either add or remove the 0x0131 TLV from the TLV chain */ 991 /* Either add or remove the 0x0131 TLV from the TLV chain */
964 if ((alias != NULL) && (strlen(alias) > 0)) 992 if ((alias != NULL) && (strlen(alias) > 0))
965 aim_tlvlist_replace_str(&tmp->data, 0x0131, alias); 993 aim_tlvlist_replace_str(&tmp->data, 0x0131, alias);
985 struct aim_ssi_item *tmp; 1013 struct aim_ssi_item *tmp;
986 1014
987 if (!od || !gn || !bn) 1015 if (!od || !gn || !bn)
988 return -EINVAL; 1016 return -EINVAL;
989 1017
990 if (!(tmp = aim_ssi_itemlist_finditem(od->ssi.local, gn, bn, AIM_SSI_TYPE_BUDDY))) 1018 if (!(tmp = aim_ssi_itemlist_finditem(&od->ssi.local, gn, bn, AIM_SSI_TYPE_BUDDY)))
991 return -EINVAL; 1019 return -EINVAL;
992 1020
993 /* Either add or remove the 0x0131 TLV from the TLV chain */ 1021 /* Either add or remove the 0x0131 TLV from the TLV chain */
994 if ((comment != NULL) && (strlen(comment) > 0)) 1022 if ((comment != NULL) && (strlen(comment) > 0))
995 aim_tlvlist_replace_str(&tmp->data, 0x013c, comment); 1023 aim_tlvlist_replace_str(&tmp->data, 0x013c, comment);
1013 struct aim_ssi_item *group; 1041 struct aim_ssi_item *group;
1014 1042
1015 if (!od || !oldgn || !newgn) 1043 if (!od || !oldgn || !newgn)
1016 return -EINVAL; 1044 return -EINVAL;
1017 1045
1018 if (!(group = aim_ssi_itemlist_finditem(od->ssi.local, oldgn, NULL, AIM_SSI_TYPE_GROUP))) 1046 if (!(group = aim_ssi_itemlist_finditem(&od->ssi.local, oldgn, NULL, AIM_SSI_TYPE_GROUP)))
1019 return -EINVAL; 1047 return -EINVAL;
1020 1048
1021 g_free(group->name); 1049 aim_ssi_item_set_name(&od->ssi.local, group, newgn);
1022 group->name = g_strdup(newgn);
1023 1050
1024 /* Sync our local list with the server list */ 1051 /* Sync our local list with the server list */
1025 return aim_ssi_sync(od); 1052 return aim_ssi_sync(od);
1026 } 1053 }
1027 1054
1044 1071
1045 if (!od || !od->ssi.received_data) 1072 if (!od || !od->ssi.received_data)
1046 return -EINVAL; 1073 return -EINVAL;
1047 1074
1048 /* Find the PDINFO item, or add it if it does not exist */ 1075 /* Find the PDINFO item, or add it if it does not exist */
1049 if (!(tmp = aim_ssi_itemlist_finditem(od->ssi.local, NULL, NULL, AIM_SSI_TYPE_PDINFO))) { 1076 if (!(tmp = aim_ssi_itemlist_finditem(&od->ssi.local, NULL, NULL, AIM_SSI_TYPE_PDINFO))) {
1050 /* Make sure the master group exists */ 1077 /* Make sure the master group exists */
1051 if (aim_ssi_itemlist_find(od->ssi.local, 0x0000, 0x0000) == NULL) 1078 if (aim_ssi_itemlist_find(&od->ssi.local, 0x0000, 0x0000) == NULL)
1052 aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL); 1079 aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL);
1053 1080
1054 tmp = aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PDINFO, NULL); 1081 tmp = aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PDINFO, NULL);
1055 } 1082 }
1056 1083
1076 1103
1077 if (!od || !iconsum || !iconsumlen || !od->ssi.received_data) 1104 if (!od || !iconsum || !iconsumlen || !od->ssi.received_data)
1078 return -EINVAL; 1105 return -EINVAL;
1079 1106
1080 /* Find the ICONINFO item, or add it if it does not exist */ 1107 /* Find the ICONINFO item, or add it if it does not exist */
1081 if (!(tmp = aim_ssi_itemlist_finditem(od->ssi.local, NULL, "1", AIM_SSI_TYPE_ICONINFO))) { 1108 if (!(tmp = aim_ssi_itemlist_finditem(&od->ssi.local, NULL, "1", AIM_SSI_TYPE_ICONINFO))) {
1082 /* Make sure the master group exists */ 1109 /* Make sure the master group exists */
1083 if (aim_ssi_itemlist_find(od->ssi.local, 0x0000, 0x0000) == NULL) 1110 if (aim_ssi_itemlist_find(&od->ssi.local, 0x0000, 0x0000) == NULL)
1084 aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL); 1111 aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL);
1085 1112
1086 tmp = aim_ssi_itemlist_add(&od->ssi.local, "1", 0x0000, 0xFFFF, AIM_SSI_TYPE_ICONINFO, NULL); 1113 tmp = aim_ssi_itemlist_add(&od->ssi.local, "1", 0x0000, 0xFFFF, AIM_SSI_TYPE_ICONINFO, NULL);
1087 } 1114 }
1088 1115
1136 1163
1137 if (!od || !od->ssi.received_data) 1164 if (!od || !od->ssi.received_data)
1138 return -EINVAL; 1165 return -EINVAL;
1139 1166
1140 /* Find the PRESENCEPREFS item, or add it if it does not exist */ 1167 /* Find the PRESENCEPREFS item, or add it if it does not exist */
1141 if (!(tmp = aim_ssi_itemlist_finditem(od->ssi.local, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS))) { 1168 if (!(tmp = aim_ssi_itemlist_finditem(&od->ssi.local, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS))) {
1142 /* Make sure the master group exists */ 1169 /* Make sure the master group exists */
1143 if (aim_ssi_itemlist_find(od->ssi.local, 0x0000, 0x0000) == NULL) 1170 if (aim_ssi_itemlist_find(&od->ssi.local, 0x0000, 0x0000) == NULL)
1144 aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL); 1171 aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL);
1145 1172
1146 tmp = aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PRESENCEPREFS, NULL); 1173 tmp = aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PRESENCEPREFS, NULL);
1147 } 1174 }
1148 1175
1263 od->ssi.timestamp = byte_stream_get32(bs); 1290 od->ssi.timestamp = byte_stream_get32(bs);
1264 1291
1265 if (!(snac->flags & 0x0001)) { 1292 if (!(snac->flags & 0x0001)) {
1266 /* Make a copy of the list */ 1293 /* Make a copy of the list */
1267 struct aim_ssi_item *cur; 1294 struct aim_ssi_item *cur;
1268 for (cur=od->ssi.official; cur; cur=cur->next) 1295 for (cur=od->ssi.official.data; cur; cur=cur->next)
1269 aim_ssi_itemlist_add(&od->ssi.local, cur->name, cur->gid, cur->bid, cur->type, cur->data); 1296 aim_ssi_itemlist_add(&od->ssi.local, cur->name, cur->gid, cur->bid, cur->type, cur->data);
1270 1297
1271 od->ssi.received_data = TRUE; 1298 od->ssi.received_data = TRUE;
1272 1299
1273 if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) 1300 if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
1413 data = aim_tlvlist_readlen(bs, len); 1440 data = aim_tlvlist_readlen(bs, len);
1414 else 1441 else
1415 data = NULL; 1442 data = NULL;
1416 1443
1417 /* Replace the 2 local items with the given one */ 1444 /* Replace the 2 local items with the given one */
1418 if ((item = aim_ssi_itemlist_find(od->ssi.local, gid, bid))) { 1445 if ((item = aim_ssi_itemlist_find(&od->ssi.local, gid, bid))) {
1419 item->type = type; 1446 item->type = type;
1420 g_free(item->name); 1447 aim_ssi_item_set_name(&od->ssi.local, item, name);
1421 item->name = g_strdup(name);
1422 aim_tlvlist_free(item->data); 1448 aim_tlvlist_free(item->data);
1423 item->data = aim_tlvlist_copy(data); 1449 item->data = aim_tlvlist_copy(data);
1424 } 1450 }
1425 1451
1426 if ((item = aim_ssi_itemlist_find(od->ssi.official, gid, bid))) { 1452 if ((item = aim_ssi_itemlist_find(&od->ssi.official, gid, bid))) {
1427 item->type = type; 1453 item->type = type;
1428 g_free(item->name); 1454 aim_ssi_item_set_name(&od->ssi.official, item, name);
1429 item->name = g_strdup(name);
1430 aim_tlvlist_free(item->data); 1455 aim_tlvlist_free(item->data);
1431 item->data = aim_tlvlist_copy(data); 1456 item->data = aim_tlvlist_copy(data);
1432 } 1457 }
1433 1458
1434 if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) 1459 if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
1458 gid = byte_stream_get16(bs); 1483 gid = byte_stream_get16(bs);
1459 bid = byte_stream_get16(bs); 1484 bid = byte_stream_get16(bs);
1460 byte_stream_get16(bs); 1485 byte_stream_get16(bs);
1461 byte_stream_advance(bs, byte_stream_get16(bs)); 1486 byte_stream_advance(bs, byte_stream_get16(bs));
1462 1487
1463 if ((del = aim_ssi_itemlist_find(od->ssi.local, gid, bid))) 1488 if ((del = aim_ssi_itemlist_find(&od->ssi.local, gid, bid)))
1464 aim_ssi_itemlist_del(&od->ssi.local, del); 1489 aim_ssi_itemlist_del(&od->ssi.local, del);
1465 if ((del = aim_ssi_itemlist_find(od->ssi.official, gid, bid))) 1490 if ((del = aim_ssi_itemlist_find(&od->ssi.official, gid, bid)))
1466 aim_ssi_itemlist_del(&od->ssi.official, del); 1491 aim_ssi_itemlist_del(&od->ssi.official, del);
1467 1492
1468 if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) 1493 if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
1469 ret = userfunc(od, conn, frame); 1494 ret = userfunc(od, conn, frame);
1470 } 1495 }
1501 if (cur->ack) { 1526 if (cur->ack) {
1502 /* Our action was unsuccessful, so change the local list back to how it was */ 1527 /* Our action was unsuccessful, so change the local list back to how it was */
1503 if (cur->action == SNAC_SUBTYPE_FEEDBAG_ADD) { 1528 if (cur->action == SNAC_SUBTYPE_FEEDBAG_ADD) {
1504 /* Remove the item from the local list */ 1529 /* Remove the item from the local list */
1505 /* Make sure cur->item is still valid memory */ 1530 /* Make sure cur->item is still valid memory */
1506 if (aim_ssi_itemlist_valid(od->ssi.local, cur->item)) { 1531 /* TODO: "Still valid memory"? That's bad form. */
1532 if (aim_ssi_itemlist_valid(&od->ssi.local, cur->item)) {
1507 cur->name = g_strdup(cur->item->name); 1533 cur->name = g_strdup(cur->item->name);
1508 aim_ssi_itemlist_del(&od->ssi.local, cur->item); 1534 aim_ssi_itemlist_del(&od->ssi.local, cur->item);
1509 } 1535 }
1510 cur->item = NULL; 1536 cur->item = NULL;
1511 1537
1512 } else if (cur->action == SNAC_SUBTYPE_FEEDBAG_MOD) { 1538 } else if (cur->action == SNAC_SUBTYPE_FEEDBAG_MOD) {
1513 /* Replace the local item with the item from the official list */ 1539 /* Replace the local item with the item from the official list */
1514 if (aim_ssi_itemlist_valid(od->ssi.local, cur->item)) { 1540 if (aim_ssi_itemlist_valid(&od->ssi.local, cur->item)) {
1515 struct aim_ssi_item *cur1; 1541 struct aim_ssi_item *cur1;
1516 if ((cur1 = aim_ssi_itemlist_find(od->ssi.official, cur->item->gid, cur->item->bid))) { 1542 if ((cur1 = aim_ssi_itemlist_find(&od->ssi.official, cur->item->gid, cur->item->bid))) {
1517 g_free(cur->item->name); 1543 aim_ssi_item_set_name(&od->ssi.official, cur->item, cur1->name);
1518 cur->item->name = g_strdup(cur1->name);
1519 aim_tlvlist_free(cur->item->data); 1544 aim_tlvlist_free(cur->item->data);
1520 cur->item->data = aim_tlvlist_copy(cur1->data); 1545 cur->item->data = aim_tlvlist_copy(cur1->data);
1521 } 1546 }
1522 } else 1547 } else
1523 cur->item = NULL; 1548 cur->item = NULL;
1524 1549
1525 } else if (cur->action == SNAC_SUBTYPE_FEEDBAG_DEL) { 1550 } else if (cur->action == SNAC_SUBTYPE_FEEDBAG_DEL) {
1526 /* Add the item back into the local list */ 1551 /* Add the item back into the local list */
1527 if (aim_ssi_itemlist_valid(od->ssi.official, cur->item)) { 1552 if (aim_ssi_itemlist_valid(&od->ssi.official, cur->item)) {
1528 aim_ssi_itemlist_add(&od->ssi.local, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data); 1553 aim_ssi_itemlist_add(&od->ssi.local, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data);
1529 } else 1554 } else
1530 cur->item = NULL; 1555 cur->item = NULL;
1531 } 1556 }
1532 1557
1533 } else { 1558 } else {
1534 /* Do the exact opposite */ 1559 /* Do the exact opposite */
1535 if (cur->action == SNAC_SUBTYPE_FEEDBAG_ADD) { 1560 if (cur->action == SNAC_SUBTYPE_FEEDBAG_ADD) {
1536 /* Add the local item to the official list */ 1561 /* Add the local item to the official list */
1537 if (aim_ssi_itemlist_valid(od->ssi.local, cur->item)) { 1562 if (aim_ssi_itemlist_valid(&od->ssi.local, cur->item)) {
1538 aim_ssi_itemlist_add(&od->ssi.official, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data); 1563 aim_ssi_itemlist_add(&od->ssi.official, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data);
1539 } else 1564 } else
1540 cur->item = NULL; 1565 cur->item = NULL;
1541 1566
1542 } else if (cur->action == SNAC_SUBTYPE_FEEDBAG_MOD) { 1567 } else if (cur->action == SNAC_SUBTYPE_FEEDBAG_MOD) {
1543 /* Replace the official item with the item from the local list */ 1568 /* Replace the official item with the item from the local list */
1544 if (aim_ssi_itemlist_valid(od->ssi.local, cur->item)) { 1569 if (aim_ssi_itemlist_valid(&od->ssi.local, cur->item)) {
1545 struct aim_ssi_item *cur1; 1570 struct aim_ssi_item *cur1;
1546 if ((cur1 = aim_ssi_itemlist_find(od->ssi.official, cur->item->gid, cur->item->bid))) { 1571 if ((cur1 = aim_ssi_itemlist_find(&od->ssi.official, cur->item->gid, cur->item->bid))) {
1547 g_free(cur1->name); 1572 aim_ssi_item_set_name(&od->ssi.official, cur1, cur->item->name);
1548 cur1->name = g_strdup(cur->item->name);
1549 aim_tlvlist_free(cur1->data); 1573 aim_tlvlist_free(cur1->data);
1550 cur1->data = aim_tlvlist_copy(cur->item->data); 1574 cur1->data = aim_tlvlist_copy(cur->item->data);
1551 } 1575 }
1552 } else 1576 } else
1553 cur->item = NULL; 1577 cur->item = NULL;
1554 1578
1555 } else if (cur->action == SNAC_SUBTYPE_FEEDBAG_DEL) { 1579 } else if (cur->action == SNAC_SUBTYPE_FEEDBAG_DEL) {
1556 /* Remove the item from the official list */ 1580 /* Remove the item from the official list */
1557 if (aim_ssi_itemlist_valid(od->ssi.official, cur->item)) 1581 if (aim_ssi_itemlist_valid(&od->ssi.official, cur->item))
1558 aim_ssi_itemlist_del(&od->ssi.official, cur->item); 1582 aim_ssi_itemlist_del(&od->ssi.official, cur->item);
1559 cur->item = NULL; 1583 cur->item = NULL;
1560 } 1584 }
1561 1585
1562 } 1586 }