Mercurial > pidgin
comparison libpurple/protocols/oscar/family_feedbag.c @ 31836:8d6630912021
Add two hash tables to the oscar code that deals with your server stored
buddy list. One hash table is indexed by a combination of group id and
buddy id. The other hash table is indexed by a combination of item type
and item name. This should reduce the number of times we iterate through
a linked list by A LOT.
This is a modified version of Oliver's patch from #4816.
Fixes #4816.
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Sun, 20 Mar 2011 20:20:52 +0000 |
parents | e5cd15ee3e5d |
children | dc120ca9f523 |
comparison
equal
deleted
inserted
replaced
31835:36011b558d3e | 31836:8d6630912021 |
---|---|
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 } |