# HG changeset patch # User Mark Doliner # Date 1300652452 0 # Node ID 8d6630912021f0e299827c89bffce20b67fea585 # Parent 36011b558d3ed7a61a6afc8d3bde1f16f2121e60 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. diff -r 36011b558d3e -r 8d6630912021 ChangeLog --- a/ChangeLog Sat Mar 19 19:38:55 2011 +0000 +++ b/ChangeLog Sun Mar 20 20:20:52 2011 +0000 @@ -1,5 +1,9 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul +version 3.0.0 (??/??/????): + AIM and ICQ: + * Make buddy list management code more efficient. (Oliver) (#4816) + version 2.8.0 (??/??/????): General: * Implement simple silence suppression for voice calls, preventing wasted diff -r 36011b558d3e -r 8d6630912021 libpurple/protocols/oscar/authorization.c --- a/libpurple/protocols/oscar/authorization.c Sat Mar 19 19:38:55 2011 +0000 +++ b/libpurple/protocols/oscar/authorization.c Sun Mar 20 20:20:52 2011 +0000 @@ -51,7 +51,7 @@ purple_debug_info("oscar", "ssi: adding buddy %s to group %s\n", bname, gname); aim_ssi_sendauthrequest(od, data->name, msg ? msg : _("Please authorize me so I can add you to my buddy list.")); - if (!aim_ssi_itemlist_finditem(od->ssi.local, gname, bname, AIM_SSI_TYPE_BUDDY)) + if (!aim_ssi_itemlist_finditem(&od->ssi.local, gname, bname, AIM_SSI_TYPE_BUDDY)) { aim_ssi_addbuddy(od, bname, gname, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, TRUE); @@ -150,4 +150,4 @@ purple_account_request_authorization(account, data->name, NULL, data->nick, reason, purple_find_buddy(account, data->name) != NULL, oscar_auth_grant, oscar_auth_dontgrant_msgprompt, data); -} \ No newline at end of file +} diff -r 36011b558d3e -r 8d6630912021 libpurple/protocols/oscar/family_feedbag.c --- a/libpurple/protocols/oscar/family_feedbag.c Sat Mar 19 19:38:55 2011 +0000 +++ b/libpurple/protocols/oscar/family_feedbag.c Sun Mar 20 20:20:52 2011 +0000 @@ -21,9 +21,9 @@ /* * Family 0x0013 - Server-Side/Stored Information. * - * Relatively new facility that allows certain types of information, such as - * a user's buddy list, permit/deny list, and permit/deny preferences, to be - * stored on the server, so that they can be accessed from any client. + * Deals with storing certain types of information, such as a user's buddy + * list, permit/deny list, and permit/deny preferences, on the server, so + * that they can be accessed from any client. * * We keep 2 copies of SSI data: * 1) An exact copy of what is stored on the AIM servers. @@ -40,14 +40,41 @@ * * This is entirely too complicated. * You don't know the half of it. - * */ #include "oscar.h" +#include "oscarcommon.h" #include "debug.h" static int aim_ssi_addmoddel(OscarData *od); +static void aim_ssi_item_free(struct aim_ssi_item *item) +{ + g_free(item->name); + aim_tlvlist_free(item->data); + g_free(item); +} + +static void aim_ssi_item_set_name(struct aim_ssi_itemlist *list, struct aim_ssi_item *item, const char *name) +{ + gchar key[3000]; + + if (item->name) { + /* Remove old name from hash table */ + snprintf(key, sizeof(key), "%hx%s", item->type, oscar_normalize(NULL, item->name)); + g_hash_table_remove(list->idx_all_named_items, key); + } + + g_free(item->name); + item->name = g_strdup(name); + + if (name) { + /* Add new name to hash table */ + snprintf(key, sizeof(key), "%hx%s", item->type, oscar_normalize(NULL, item->name)); + g_hash_table_insert(list->idx_all_named_items, g_strdup(key), item); + } +} + /** * List types based on http://dev.aol.com/aim/oscar/#FEEDBAG (archive.org) * and http://iserverd.khstu.ru/oscar/ssi_item.html @@ -112,7 +139,7 @@ * @return Return a pointer to the modified item. */ static void -aim_ssi_itemlist_rebuildgroup(struct aim_ssi_item *list, const char *name) +aim_ssi_itemlist_rebuildgroup(struct aim_ssi_itemlist *list, const char *name) { int newlen; struct aim_ssi_item *cur, *group; @@ -124,11 +151,11 @@ /* Find the length for the new additional data */ newlen = 0; if (group->gid == 0x0000) { - for (cur=list; cur; cur=cur->next) + for (cur=list->data; cur; cur=cur->next) if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid != 0x0000)) newlen += 2; } else { - for (cur=list; cur; cur=cur->next) + for (cur=list->data; cur; cur=cur->next) if ((cur->gid == group->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) newlen += 2; } @@ -137,14 +164,14 @@ if (newlen > 0) { guint8 *newdata; - newdata = (guint8 *)g_malloc((newlen)*sizeof(guint8)); + newdata = g_new(guint8, newlen); newlen = 0; if (group->gid == 0x0000) { - for (cur=list; cur; cur=cur->next) + for (cur=list->data; cur; cur=cur->next) if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid != 0x0000)) newlen += aimutil_put16(newdata+newlen, cur->gid); } else { - for (cur=list; cur; cur=cur->next) + for (cur=list->data; cur; cur=cur->next) if ((cur->gid == group->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) newlen += aimutil_put16(newdata+newlen, cur->bid); } @@ -166,15 +193,12 @@ * @param data The additional data for the new item. * @return A pointer to the newly created item. */ -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) +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) { gboolean exists; struct aim_ssi_item *cur, *new; - new = g_new(struct aim_ssi_item, 1); - - /* Set the name */ - new->name = g_strdup(name); + new = g_new0(struct aim_ssi_item, 1); /* Set the group ID# and buddy ID# */ new->gid = gid; @@ -184,7 +208,7 @@ do { new->gid += 0x0001; exists = FALSE; - for (cur = *list; cur != NULL; cur = cur->next) + for (cur = list->data; cur != NULL; cur = cur->next) if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid == new->gid)) { exists = TRUE; break; @@ -201,7 +225,7 @@ do { new->bid += 0x0001; exists = FALSE; - for (cur = *list; cur != NULL; cur = cur->next) + for (cur = list->data; cur != NULL; cur = cur->next) if (cur->bid == new->bid || cur->gid == new->bid) { exists = TRUE; break; @@ -213,7 +237,7 @@ do { new->bid += 0x0001; exists = FALSE; - for (cur = *list; cur != NULL; cur = cur->next) + for (cur = list->data; cur != NULL; cur = cur->next) if (cur->bid == new->bid && cur->gid == new->gid) { exists = TRUE; break; @@ -225,23 +249,29 @@ /* Set the type */ new->type = type; + /* Add it to the gid+bid hashtable */ + g_hash_table_insert(list->idx_gid_bid, GINT_TO_POINTER((new->gid << 16) + new->bid), new); + + /* Set the name - do this *AFTER* setting the type because type is used for the key */ + aim_ssi_item_set_name(list, new, name); + /* Set the TLV list */ new->data = aim_tlvlist_copy(data); /* Add the item to the list in the correct numerical position. Fancy, eh? */ - if (*list) { - if ((new->gid < (*list)->gid) || ((new->gid == (*list)->gid) && (new->bid < (*list)->bid))) { - new->next = *list; - *list = new; + if (list->data) { + if ((new->gid < list->data->gid) || ((new->gid == list->data->gid) && (new->bid < list->data->bid))) { + new->next = list->data; + list->data = new; } else { struct aim_ssi_item *prev; - for ((prev=*list, cur=(*list)->next); (cur && ((new->gid > cur->gid) || ((new->gid == cur->gid) && (new->bid > cur->bid)))); prev=cur, cur=cur->next); + 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); new->next = prev->next; prev->next = new; } } else { - new->next = *list; - *list = new; + new->next = list->data; + list->data = new; } return new; @@ -254,25 +284,31 @@ * @param del A pointer to the item you want to remove from the list. * @return Return 0 if no errors, otherwise return the error number. */ -static int aim_ssi_itemlist_del(struct aim_ssi_item **list, struct aim_ssi_item *del) +static int aim_ssi_itemlist_del(struct aim_ssi_itemlist *list, struct aim_ssi_item *del) { - if (!(*list) || !del) + gchar key[3000]; + + if (!(list->data) || !del) return -EINVAL; /* Remove the item from the list */ - if (*list == del) { - *list = (*list)->next; + if (list->data == del) { + list->data = list->data->next; } else { struct aim_ssi_item *cur; - for (cur=*list; (cur->next && (cur->next!=del)); cur=cur->next); + for (cur=list->data; (cur->next && (cur->next!=del)); cur=cur->next); if (cur->next) cur->next = del->next; } + /* Remove from the hashtables */ + g_hash_table_remove(list->idx_gid_bid, GINT_TO_POINTER((del->gid << 16) + del->bid)); + + snprintf(key, sizeof(key), "%hx%s", del->type, oscar_normalize(NULL, del->name)); + g_hash_table_remove(list->idx_all_named_items, key); + /* Free the removed item */ - g_free(del->name); - aim_tlvlist_free(del->data); - g_free(del); + aim_ssi_item_free(del); return 0; } @@ -319,10 +355,10 @@ return 0; } -static gboolean aim_ssi_itemlist_valid(struct aim_ssi_item *list, struct aim_ssi_item *item) +static gboolean aim_ssi_itemlist_valid(struct aim_ssi_itemlist *list, struct aim_ssi_item *item) { struct aim_ssi_item *cur; - for (cur=list; cur; cur=cur->next) + for (cur=list->data; cur; cur=cur->next) if (cur == item) return TRUE; return FALSE; @@ -336,13 +372,10 @@ * @param bid The buddy ID# of the desired item. * @return Return a pointer to the item if found, else return NULL; */ -struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, guint16 gid, guint16 bid) +struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_itemlist *list, guint16 gid, guint16 bid) { - struct aim_ssi_item *cur; - for (cur=list; cur; cur=cur->next) - if ((cur->gid == gid) && (cur->bid == bid)) - return cur; - return NULL; + guint32 id_key = (gid << 16) + bid; + return g_hash_table_lookup(list->idx_gid_bid, GINT_TO_POINTER(id_key)); } /** @@ -355,37 +388,30 @@ * @param type The type of the desired item. * @return Return a pointer to the item if found, else return NULL. */ -struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *bn, guint16 type) +struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_itemlist *list, const char *gn, const char *bn, guint16 type) { struct aim_ssi_item *cur; - if (!list) + gchar key[3000]; + + if (!list->data) return NULL; if (gn && bn) { /* For finding buddies in groups */ - for (cur=list; cur; cur=cur->next) + g_return_val_if_fail(type == AIM_SSI_TYPE_BUDDY, NULL); + for (cur=list->data; cur; cur=cur->next) if ((cur->type == type) && (cur->name) && !(oscar_util_name_compare(cur->name, bn))) { struct aim_ssi_item *curg; - for (curg=list; curg; curg=curg->next) + for (curg=list->data; curg; curg=curg->next) if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid) && (curg->name) && !(oscar_util_name_compare(curg->name, gn))) return cur; } - } else if (gn) { /* For finding groups */ - for (cur=list; cur; cur=cur->next) { - if ((cur->type == type) && (cur->bid == 0x0000) && (cur->name) && !(oscar_util_name_compare(cur->name, gn))) { - return cur; - } - } - - } else if (bn) { /* For finding permits, denies, and ignores */ - for (cur=list; cur; cur=cur->next) { - if ((cur->type == type) && (cur->name) && !(oscar_util_name_compare(cur->name, bn))) { - return cur; - } - } + } else if (gn || bn) { /* For finding groups, permits, denies and ignores */ + snprintf(key, sizeof(key), "%hx%s", type, oscar_normalize(NULL, gn ? gn : bn)); + return g_hash_table_lookup(list->idx_all_named_items, key); /* For stuff without names--permit deny setting, visibility mask, etc. */ - } else for (cur=list; cur; cur=cur->next) { + } else for (cur=list->data; cur; cur=cur->next) { if ((cur->type == type) && (!cur->name)) return cur; } @@ -400,7 +426,7 @@ * @param bn The group name of the desired item. * @return Return a pointer to the name of the item if found, else return NULL; */ -struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_item *list, const char *bn) +struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_itemlist *list, const char *bn) { if (!bn) return NULL; @@ -414,10 +440,10 @@ * @param bn The buddy name of the desired item. * @return Return a pointer to the name of the item if found, else return NULL; */ -char *aim_ssi_itemlist_findparentname(struct aim_ssi_item *list, const char *bn) +char *aim_ssi_itemlist_findparentname(struct aim_ssi_itemlist *list, const char *bn) { struct aim_ssi_item *cur, *curg; - if (!list || !bn) + if (!list->data || !bn) return NULL; if (!(cur = aim_ssi_itemlist_exists(list, bn))) return NULL; @@ -432,7 +458,7 @@ * @param list A pointer to the current list of items. * @return Return the current SSI permit deny setting, or 0 if no setting was found. */ -int aim_ssi_getpermdeny(struct aim_ssi_item *list) +int aim_ssi_getpermdeny(struct aim_ssi_itemlist *list) { struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PDINFO); if (cur) { @@ -450,7 +476,7 @@ * @param list A pointer to the current list of items. * @return Return the current set of preferences. */ -guint32 aim_ssi_getpresence(struct aim_ssi_item *list) +guint32 aim_ssi_getpresence(struct aim_ssi_itemlist *list) { struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS); if (cur) { @@ -471,17 +497,23 @@ * alias, or NULL if the buddy has no alias. You should free * this returned value! */ -char *aim_ssi_getalias(struct aim_ssi_item *list, const char *gn, const char *bn) +char *aim_ssi_getalias(struct aim_ssi_itemlist *list, const char *gn, const char *bn) { - struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, bn, AIM_SSI_TYPE_BUDDY); - if (cur) { - aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x0131, 1); - if (tlv && tlv->length) - return g_strndup((const gchar *)tlv->value, tlv->length); + struct aim_ssi_item *item = aim_ssi_itemlist_finditem(list, gn, bn, AIM_SSI_TYPE_BUDDY); + if (item) { + return aim_ssi_getalias_from_item(item); } return NULL; } +char *aim_ssi_getalias_from_item(struct aim_ssi_item *item) +{ + aim_tlv_t *tlv = aim_tlv_gettlv(item->data, 0x0131, 1); + if (tlv && tlv->length) + return g_strndup((const gchar *)tlv->value, tlv->length); + return NULL; +} + /** * Locally find the comment of the given buddy. * @@ -492,7 +524,7 @@ * comment, or NULL if the buddy has no comment. You should free * this returned value! */ -char *aim_ssi_getcomment(struct aim_ssi_item *list, const char *gn, const char *bn) +char *aim_ssi_getcomment(struct aim_ssi_itemlist *list, const char *gn, const char *bn) { struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, bn, AIM_SSI_TYPE_BUDDY); if (cur) { @@ -512,7 +544,7 @@ * @param bn The name of the buddy. * @return 1 if you are waiting for authorization; 0 if you are not */ -gboolean aim_ssi_waitingforauth(struct aim_ssi_item *list, const char *gn, const char *bn) +gboolean aim_ssi_waitingforauth(struct aim_ssi_itemlist *list, const char *gn, const char *bn) { struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, bn, AIM_SSI_TYPE_BUDDY); if (cur) { @@ -560,8 +592,8 @@ /* Deletions */ if (!od->ssi.pending) { - for (cur1=od->ssi.official; cur1 && (n < 15); cur1=cur1->next) { - if (!aim_ssi_itemlist_find(od->ssi.local, cur1->gid, cur1->bid)) { + for (cur1=od->ssi.official.data; cur1 && (n < 15); cur1=cur1->next) { + if (!aim_ssi_itemlist_find(&od->ssi.local, cur1->gid, cur1->bid)) { n++; new = g_new(struct aim_ssi_tmp, 1); new->action = SNAC_SUBTYPE_FEEDBAG_DEL; @@ -574,15 +606,15 @@ cur->next = new; } else od->ssi.pending = new; - aim_ssi_item_debug_append(debugstr, "Deleting item ", cur1); + aim_ssi_item_debug_append(debugstr, "Deleting item ", cur1); } } } /* Additions */ if (!od->ssi.pending) { - for (cur1=od->ssi.local; cur1 && (n < 15); cur1=cur1->next) { - if (!aim_ssi_itemlist_find(od->ssi.official, cur1->gid, cur1->bid)) { + for (cur1=od->ssi.local.data; cur1 && (n < 15); cur1=cur1->next) { + if (!aim_ssi_itemlist_find(&od->ssi.official, cur1->gid, cur1->bid)) { n++; new = g_new(struct aim_ssi_tmp, 1); new->action = SNAC_SUBTYPE_FEEDBAG_ADD; @@ -595,15 +627,15 @@ cur->next = new; } else od->ssi.pending = new; - aim_ssi_item_debug_append(debugstr, "Adding item ", cur1); + aim_ssi_item_debug_append(debugstr, "Adding item ", cur1); } } } /* Modifications */ if (!od->ssi.pending) { - for (cur1=od->ssi.local; cur1 && (n < 15); cur1=cur1->next) { - cur2 = aim_ssi_itemlist_find(od->ssi.official, cur1->gid, cur1->bid); + for (cur1=od->ssi.local.data; cur1 && (n < 15); cur1=cur1->next) { + cur2 = aim_ssi_itemlist_find(&od->ssi.official, cur1->gid, cur1->bid); if (cur2 && (aim_ssi_itemlist_cmp(cur1, cur2))) { n++; new = g_new(struct aim_ssi_tmp, 1); @@ -617,15 +649,15 @@ cur->next = new; } else od->ssi.pending = new; - aim_ssi_item_debug_append(debugstr, "Modifying item ", cur1); + aim_ssi_item_debug_append(debugstr, "Modifying item ", cur1); } } } if (debugstr->len > 0) { purple_debug_info("oscar", "%s", debugstr->str); if (purple_debug_is_verbose()) { - g_string_truncate(debugstr, 0); - for (cur1 = od->ssi.local; cur1; cur1 = cur1->next) + g_string_truncate(debugstr, 0); + for (cur1 = od->ssi.local.data; cur1; cur1 = cur1->next) aim_ssi_item_debug_append(debugstr, "\t", cur1); purple_debug_misc("oscar", "Dumping item list of account %s:\n%s", purple_connection_get_account(od->gc)->username, debugstr->str); @@ -672,22 +704,18 @@ struct aim_ssi_item *cur, *del; struct aim_ssi_tmp *curtmp, *deltmp; - cur = od->ssi.official; + cur = od->ssi.official.data; while (cur) { del = cur; cur = cur->next; - g_free(del->name); - aim_tlvlist_free(del->data); - g_free(del); + aim_ssi_item_free(del); } - cur = od->ssi.local; + cur = od->ssi.local.data; while (cur) { del = cur; cur = cur->next; - g_free(del->name); - aim_tlvlist_free(del->data); - g_free(del); + aim_ssi_item_free(del); } curtmp = od->ssi.pending; @@ -698,8 +726,8 @@ } od->ssi.numitems = 0; - od->ssi.official = NULL; - od->ssi.local = NULL; + od->ssi.official.data = NULL; + od->ssi.local.data = NULL; od->ssi.pending = NULL; od->ssi.timestamp = (time_t)0; } @@ -725,7 +753,7 @@ /* DESTROY any buddies that are directly in the master group. */ /* Do the same for buddies that are in a non-existant group. */ /* This will kind of mess up if you hit the item limit, but this function isn't too critical */ - cur = od->ssi.local; + cur = od->ssi.local.data; while (cur) { next = cur->next; if (!cur->name) { @@ -733,8 +761,8 @@ aim_ssi_delbuddy(od, NULL, NULL); else if (cur->type == AIM_SSI_TYPE_PERMIT || cur->type == AIM_SSI_TYPE_DENY || cur->type == AIM_SSI_TYPE_ICQDENY) aim_ssi_del_from_private_list(od, NULL, cur->type); - } else if ((cur->type == AIM_SSI_TYPE_BUDDY) && ((cur->gid == 0x0000) || (!aim_ssi_itemlist_find(od->ssi.local, cur->gid, 0x0000)))) { - char *alias = aim_ssi_getalias(od->ssi.local, NULL, cur->name); + } else if ((cur->type == AIM_SSI_TYPE_BUDDY) && ((cur->gid == 0x0000) || (!aim_ssi_itemlist_find(&od->ssi.local, cur->gid, 0x0000)))) { + char *alias = aim_ssi_getalias(&od->ssi.local, NULL, cur->name); aim_ssi_addbuddy(od, cur->name, "orphans", NULL, alias, NULL, NULL, FALSE); aim_ssi_delbuddy(od, cur->name, NULL); g_free(alias); @@ -743,7 +771,7 @@ } /* Make sure there aren't any duplicate buddies in a group, or duplicate permits or denies */ - cur = od->ssi.local; + cur = od->ssi.local.data; while (cur) { if ((cur->type == AIM_SSI_TYPE_BUDDY) || (cur->type == AIM_SSI_TYPE_PERMIT) || (cur->type == AIM_SSI_TYPE_DENY)) { @@ -784,16 +812,16 @@ return -EINVAL; /* Find the parent */ - if (!(parent = aim_ssi_itemlist_finditem(od->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP))) { + if (!(parent = aim_ssi_itemlist_finditem(&od->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP))) { /* Find the parent's parent (the master group) */ - if (aim_ssi_itemlist_find(od->ssi.local, 0x0000, 0x0000) == NULL) + if (aim_ssi_itemlist_find(&od->ssi.local, 0x0000, 0x0000) == NULL) aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL); /* Add the parent */ parent = aim_ssi_itemlist_add(&od->ssi.local, group, 0xFFFF, 0x0000, AIM_SSI_TYPE_GROUP, NULL); /* Modify the parent's parent (the master group) */ - aim_ssi_itemlist_rebuildgroup(od->ssi.local, NULL); + aim_ssi_itemlist_rebuildgroup(&od->ssi.local, NULL); } /* Create a TLV list for the new buddy */ @@ -811,7 +839,7 @@ aim_tlvlist_free(data); /* Modify the parent group */ - aim_ssi_itemlist_rebuildgroup(od->ssi.local, group); + aim_ssi_itemlist_rebuildgroup(&od->ssi.local, group); /* Sync our local list with the server list */ return aim_ssi_sync(od); @@ -823,7 +851,7 @@ if (!od || !name || !od->ssi.received_data) return -EINVAL; - if (aim_ssi_itemlist_find(od->ssi.local, 0x0000, 0x0000) == NULL) + if (aim_ssi_itemlist_find(&od->ssi.local, 0x0000, 0x0000) == NULL) aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL); aim_ssi_itemlist_add(&od->ssi.local, name, 0x0000, 0xFFFF, list_type, NULL); @@ -838,7 +866,7 @@ if (!od) return -EINVAL; - if (!(del = aim_ssi_itemlist_finditem(od->ssi.local, NULL, name, list_type))) + if (!(del = aim_ssi_itemlist_finditem(&od->ssi.local, NULL, name, list_type))) return -EINVAL; aim_ssi_itemlist_del(&od->ssi.local, del); @@ -861,14 +889,14 @@ return -EINVAL; /* Find the buddy */ - if (!(del = aim_ssi_itemlist_finditem(od->ssi.local, group, name, AIM_SSI_TYPE_BUDDY))) + if (!(del = aim_ssi_itemlist_finditem(&od->ssi.local, group, name, AIM_SSI_TYPE_BUDDY))) return -EINVAL; /* Remove the item from the list */ aim_ssi_itemlist_del(&od->ssi.local, del); /* Modify the parent group */ - aim_ssi_itemlist_rebuildgroup(od->ssi.local, group); + aim_ssi_itemlist_rebuildgroup(&od->ssi.local, group); /* Sync our local list with the server list */ return aim_ssi_sync(od); @@ -890,7 +918,7 @@ return -EINVAL; /* Find the group */ - if (!(del = aim_ssi_itemlist_finditem(od->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP))) + if (!(del = aim_ssi_itemlist_finditem(&od->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP))) return -EINVAL; /* Don't delete the group if it's not empty */ @@ -902,7 +930,7 @@ aim_ssi_itemlist_del(&od->ssi.local, del); /* Modify the parent group */ - aim_ssi_itemlist_rebuildgroup(od->ssi.local, group); + aim_ssi_itemlist_rebuildgroup(&od->ssi.local, group); /* Sync our local list with the server list */ return aim_ssi_sync(od); @@ -924,7 +952,7 @@ GSList *data; /* Find the buddy */ - buddy = aim_ssi_itemlist_finditem(od->ssi.local, oldgn, bn, AIM_SSI_TYPE_BUDDY); + buddy = aim_ssi_itemlist_finditem(&od->ssi.local, oldgn, bn, AIM_SSI_TYPE_BUDDY); if (buddy == NULL) return -EINVAL; @@ -957,7 +985,7 @@ if (!od || !gn || !bn) return -EINVAL; - if (!(tmp = aim_ssi_itemlist_finditem(od->ssi.local, gn, bn, AIM_SSI_TYPE_BUDDY))) + if (!(tmp = aim_ssi_itemlist_finditem(&od->ssi.local, gn, bn, AIM_SSI_TYPE_BUDDY))) return -EINVAL; /* Either add or remove the 0x0131 TLV from the TLV chain */ @@ -987,7 +1015,7 @@ if (!od || !gn || !bn) return -EINVAL; - if (!(tmp = aim_ssi_itemlist_finditem(od->ssi.local, gn, bn, AIM_SSI_TYPE_BUDDY))) + if (!(tmp = aim_ssi_itemlist_finditem(&od->ssi.local, gn, bn, AIM_SSI_TYPE_BUDDY))) return -EINVAL; /* Either add or remove the 0x0131 TLV from the TLV chain */ @@ -1015,11 +1043,10 @@ if (!od || !oldgn || !newgn) return -EINVAL; - if (!(group = aim_ssi_itemlist_finditem(od->ssi.local, oldgn, NULL, AIM_SSI_TYPE_GROUP))) + if (!(group = aim_ssi_itemlist_finditem(&od->ssi.local, oldgn, NULL, AIM_SSI_TYPE_GROUP))) return -EINVAL; - g_free(group->name); - group->name = g_strdup(newgn); + aim_ssi_item_set_name(&od->ssi.local, group, newgn); /* Sync our local list with the server list */ return aim_ssi_sync(od); @@ -1046,9 +1073,9 @@ return -EINVAL; /* Find the PDINFO item, or add it if it does not exist */ - if (!(tmp = aim_ssi_itemlist_finditem(od->ssi.local, NULL, NULL, AIM_SSI_TYPE_PDINFO))) { + if (!(tmp = aim_ssi_itemlist_finditem(&od->ssi.local, NULL, NULL, AIM_SSI_TYPE_PDINFO))) { /* Make sure the master group exists */ - if (aim_ssi_itemlist_find(od->ssi.local, 0x0000, 0x0000) == NULL) + if (aim_ssi_itemlist_find(&od->ssi.local, 0x0000, 0x0000) == NULL) aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL); tmp = aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PDINFO, NULL); @@ -1078,9 +1105,9 @@ return -EINVAL; /* Find the ICONINFO item, or add it if it does not exist */ - if (!(tmp = aim_ssi_itemlist_finditem(od->ssi.local, NULL, "1", AIM_SSI_TYPE_ICONINFO))) { + if (!(tmp = aim_ssi_itemlist_finditem(&od->ssi.local, NULL, "1", AIM_SSI_TYPE_ICONINFO))) { /* Make sure the master group exists */ - if (aim_ssi_itemlist_find(od->ssi.local, 0x0000, 0x0000) == NULL) + if (aim_ssi_itemlist_find(&od->ssi.local, 0x0000, 0x0000) == NULL) aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL); tmp = aim_ssi_itemlist_add(&od->ssi.local, "1", 0x0000, 0xFFFF, AIM_SSI_TYPE_ICONINFO, NULL); @@ -1138,9 +1165,9 @@ return -EINVAL; /* Find the PRESENCEPREFS item, or add it if it does not exist */ - if (!(tmp = aim_ssi_itemlist_finditem(od->ssi.local, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS))) { + if (!(tmp = aim_ssi_itemlist_finditem(&od->ssi.local, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS))) { /* Make sure the master group exists */ - if (aim_ssi_itemlist_find(od->ssi.local, 0x0000, 0x0000) == NULL) + if (aim_ssi_itemlist_find(&od->ssi.local, 0x0000, 0x0000) == NULL) aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL); tmp = aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PRESENCEPREFS, NULL); @@ -1265,7 +1292,7 @@ if (!(snac->flags & 0x0001)) { /* Make a copy of the list */ struct aim_ssi_item *cur; - for (cur=od->ssi.official; cur; cur=cur->next) + for (cur=od->ssi.official.data; cur; cur=cur->next) aim_ssi_itemlist_add(&od->ssi.local, cur->name, cur->gid, cur->bid, cur->type, cur->data); od->ssi.received_data = TRUE; @@ -1415,18 +1442,16 @@ data = NULL; /* Replace the 2 local items with the given one */ - if ((item = aim_ssi_itemlist_find(od->ssi.local, gid, bid))) { + if ((item = aim_ssi_itemlist_find(&od->ssi.local, gid, bid))) { item->type = type; - g_free(item->name); - item->name = g_strdup(name); + aim_ssi_item_set_name(&od->ssi.local, item, name); aim_tlvlist_free(item->data); item->data = aim_tlvlist_copy(data); } - if ((item = aim_ssi_itemlist_find(od->ssi.official, gid, bid))) { + if ((item = aim_ssi_itemlist_find(&od->ssi.official, gid, bid))) { item->type = type; - g_free(item->name); - item->name = g_strdup(name); + aim_ssi_item_set_name(&od->ssi.official, item, name); aim_tlvlist_free(item->data); item->data = aim_tlvlist_copy(data); } @@ -1460,9 +1485,9 @@ byte_stream_get16(bs); byte_stream_advance(bs, byte_stream_get16(bs)); - if ((del = aim_ssi_itemlist_find(od->ssi.local, gid, bid))) + if ((del = aim_ssi_itemlist_find(&od->ssi.local, gid, bid))) aim_ssi_itemlist_del(&od->ssi.local, del); - if ((del = aim_ssi_itemlist_find(od->ssi.official, gid, bid))) + if ((del = aim_ssi_itemlist_find(&od->ssi.official, gid, bid))) aim_ssi_itemlist_del(&od->ssi.official, del); if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) @@ -1503,7 +1528,8 @@ if (cur->action == SNAC_SUBTYPE_FEEDBAG_ADD) { /* Remove the item from the local list */ /* Make sure cur->item is still valid memory */ - if (aim_ssi_itemlist_valid(od->ssi.local, cur->item)) { + /* TODO: "Still valid memory"? That's bad form. */ + if (aim_ssi_itemlist_valid(&od->ssi.local, cur->item)) { cur->name = g_strdup(cur->item->name); aim_ssi_itemlist_del(&od->ssi.local, cur->item); } @@ -1511,11 +1537,10 @@ } else if (cur->action == SNAC_SUBTYPE_FEEDBAG_MOD) { /* Replace the local item with the item from the official list */ - if (aim_ssi_itemlist_valid(od->ssi.local, cur->item)) { + if (aim_ssi_itemlist_valid(&od->ssi.local, cur->item)) { struct aim_ssi_item *cur1; - if ((cur1 = aim_ssi_itemlist_find(od->ssi.official, cur->item->gid, cur->item->bid))) { - g_free(cur->item->name); - cur->item->name = g_strdup(cur1->name); + if ((cur1 = aim_ssi_itemlist_find(&od->ssi.official, cur->item->gid, cur->item->bid))) { + aim_ssi_item_set_name(&od->ssi.official, cur->item, cur1->name); aim_tlvlist_free(cur->item->data); cur->item->data = aim_tlvlist_copy(cur1->data); } @@ -1524,7 +1549,7 @@ } else if (cur->action == SNAC_SUBTYPE_FEEDBAG_DEL) { /* Add the item back into the local list */ - if (aim_ssi_itemlist_valid(od->ssi.official, cur->item)) { + if (aim_ssi_itemlist_valid(&od->ssi.official, cur->item)) { aim_ssi_itemlist_add(&od->ssi.local, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data); } else cur->item = NULL; @@ -1534,18 +1559,17 @@ /* Do the exact opposite */ if (cur->action == SNAC_SUBTYPE_FEEDBAG_ADD) { /* Add the local item to the official list */ - if (aim_ssi_itemlist_valid(od->ssi.local, cur->item)) { + if (aim_ssi_itemlist_valid(&od->ssi.local, cur->item)) { aim_ssi_itemlist_add(&od->ssi.official, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data); } else cur->item = NULL; } else if (cur->action == SNAC_SUBTYPE_FEEDBAG_MOD) { /* Replace the official item with the item from the local list */ - if (aim_ssi_itemlist_valid(od->ssi.local, cur->item)) { + if (aim_ssi_itemlist_valid(&od->ssi.local, cur->item)) { struct aim_ssi_item *cur1; - if ((cur1 = aim_ssi_itemlist_find(od->ssi.official, cur->item->gid, cur->item->bid))) { - g_free(cur1->name); - cur1->name = g_strdup(cur->item->name); + if ((cur1 = aim_ssi_itemlist_find(&od->ssi.official, cur->item->gid, cur->item->bid))) { + aim_ssi_item_set_name(&od->ssi.official, cur1, cur->item->name); aim_tlvlist_free(cur1->data); cur1->data = aim_tlvlist_copy(cur->item->data); } @@ -1554,7 +1578,7 @@ } else if (cur->action == SNAC_SUBTYPE_FEEDBAG_DEL) { /* Remove the item from the official list */ - if (aim_ssi_itemlist_valid(od->ssi.official, cur->item)) + if (aim_ssi_itemlist_valid(&od->ssi.official, cur->item)) aim_ssi_itemlist_del(&od->ssi.official, cur->item); cur->item = NULL; } diff -r 36011b558d3e -r 8d6630912021 libpurple/protocols/oscar/oscar.c --- a/libpurple/protocols/oscar/oscar.c Sat Mar 19 19:38:55 2011 +0000 +++ b/libpurple/protocols/oscar/oscar.c Sun Mar 20 20:20:52 2011 +0000 @@ -578,7 +578,7 @@ gc = data; od = purple_connection_get_protocol_data(gc); report_idle = strcmp((const char *)value, "none") != 0; - presence = aim_ssi_getpresence(od->ssi.local); + presence = aim_ssi_getpresence(&od->ssi.local); if (report_idle) aim_ssi_setpresence(od, presence | AIM_SSI_PRESENCE_FLAG_SHOWIDLE); @@ -600,7 +600,7 @@ gc = data; od = purple_connection_get_protocol_data(gc); - presence = aim_ssi_getpresence(od->ssi.local); + presence = aim_ssi_getpresence(&od->ssi.local); if (value) aim_ssi_setpresence(od, presence & ~AIM_SSI_PRESENCE_FLAG_NORECENTBUDDIES); @@ -3709,7 +3709,7 @@ } if (od->ssi.received_data) { - if (!aim_ssi_itemlist_finditem(od->ssi.local, gname, bname, AIM_SSI_TYPE_BUDDY)) { + if (!aim_ssi_itemlist_finditem(&od->ssi.local, gname, bname, AIM_SSI_TYPE_BUDDY)) { purple_debug_info("oscar", "ssi: adding buddy %s to group %s\n", bname, gname); aim_ssi_addbuddy(od, bname, gname, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, 0); @@ -3721,8 +3721,8 @@ purple_prpl_got_user_status(account, bname, OSCAR_STATUS_ID_MOBILE, NULL); } - } else if (aim_ssi_waitingforauth(od->ssi.local, - aim_ssi_itemlist_findparentname(od->ssi.local, bname), + } else if (aim_ssi_waitingforauth(&od->ssi.local, + aim_ssi_itemlist_findparentname(&od->ssi.local, bname), bname)) { /* Not authorized -- Re-request authorization */ oscar_auth_sendrequest(gc, bname); @@ -3760,7 +3760,7 @@ OscarData *od = purple_connection_get_protocol_data(gc); if (od->ssi.received_data) { - char *gname = aim_ssi_itemlist_findparentname(od->ssi.local, name); + char *gname = aim_ssi_itemlist_findparentname(&od->ssi.local, name); if (gname) { purple_debug_info("oscar", "ssi: changing the alias for buddy %s to %s\n", name, alias ? alias : "(none)"); @@ -3777,7 +3777,7 @@ if (od->ssi.received_data) { const char *gname = purple_group_get_name(group); - if (aim_ssi_itemlist_finditem(od->ssi.local, gname, NULL, AIM_SSI_TYPE_GROUP)) { + if (aim_ssi_itemlist_finditem(&od->ssi.local, gname, NULL, AIM_SSI_TYPE_GROUP)) { GList *cur, *groups = NULL; PurpleAccount *account = purple_connection_get_account(gc); @@ -3928,7 +3928,7 @@ gname = purple_group_get_name(g); bname = purple_buddy_get_name(b); - if (aim_ssi_itemlist_exists(od->ssi.local, bname)) { + if (aim_ssi_itemlist_exists(&od->ssi.local, bname)) { /* If the buddy is an ICQ user then load his nickname */ const char *servernick = purple_blist_node_get_string((PurpleBlistNode*)b, "servernick"); char *alias; @@ -3937,7 +3937,7 @@ serv_got_alias(gc, bname, servernick); /* Store local alias on server */ - alias = aim_ssi_getalias(od->ssi.local, gname, bname); + alias = aim_ssi_getalias(&od->ssi.local, gname, bname); balias = purple_buddy_get_local_buddy_alias(b); if (!alias && balias && *balias) aim_ssi_aliasbuddy(od, gname, bname, balias); @@ -3960,7 +3960,7 @@ while (next != NULL) { cur = next; next = next->next; - if (!aim_ssi_itemlist_finditem(od->ssi.local, NULL, cur->data, AIM_SSI_TYPE_PERMIT)) { + if (!aim_ssi_itemlist_finditem(&od->ssi.local, NULL, cur->data, AIM_SSI_TYPE_PERMIT)) { purple_debug_info("oscar", "ssi: removing permit %s from local list\n", (const char *)cur->data); purple_privacy_permit_remove(account, cur->data, TRUE); @@ -3973,7 +3973,7 @@ while (next != NULL) { cur = next; next = next->next; - if (!aim_ssi_itemlist_finditem(od->ssi.local, NULL, cur->data, deny_entry_type)) { + if (!aim_ssi_itemlist_finditem(&od->ssi.local, NULL, cur->data, deny_entry_type)) { purple_debug_info("oscar", "ssi: removing deny %s from local list\n", (const char *)cur->data); purple_privacy_deny_remove(account, cur->data, TRUE); @@ -3981,7 +3981,7 @@ } /* Presence settings (idle time visibility) */ - tmp = aim_ssi_getpresence(od->ssi.local); + tmp = aim_ssi_getpresence(&od->ssi.local); if (tmp != 0xFFFFFFFF) { const char *idle_reporting_pref; gboolean report_idle; @@ -3999,7 +3999,7 @@ /*** Begin code for adding from server list to local list ***/ - for (curitem=od->ssi.local; curitem; curitem=curitem->next) { + for (curitem=od->ssi.local.data; curitem; curitem=curitem->next) { if (curitem->name && !g_utf8_validate(curitem->name, -1, NULL)) { /* Got node with invalid UTF-8 in the name. Skip it. */ purple_debug_warning("oscar", "ssi: server list contains item of " @@ -4013,7 +4013,7 @@ struct aim_ssi_item *groupitem; char *gname, *gname_utf8, *alias, *alias_utf8; - groupitem = aim_ssi_itemlist_find(od->ssi.local, curitem->gid, 0x0000); + groupitem = aim_ssi_itemlist_find(&od->ssi.local, curitem->gid, 0x0000); gname = groupitem ? groupitem->name : NULL; gname_utf8 = oscar_utf8_try_convert(account, od, gname); @@ -4023,7 +4023,7 @@ purple_blist_add_group(g, NULL); } - alias = aim_ssi_getalias(od->ssi.local, gname, curitem->name); + alias = aim_ssi_getalias_from_item(curitem); alias_utf8 = oscar_utf8_try_convert(account, od, alias); b = purple_find_buddy_in_group(account, curitem->name, g); @@ -4091,7 +4091,7 @@ * a part of your status and not really related to blocking. */ if (!od->icq && curitem->data) { - guint8 perm_deny = aim_ssi_getpermdeny(od->ssi.local); + guint8 perm_deny = aim_ssi_getpermdeny(&od->ssi.local); if (perm_deny != 0 && perm_deny != account->perm_deny) { purple_debug_info("oscar", @@ -4220,10 +4220,10 @@ if ((type != 0x0000) || (name == NULL)) return 1; - gname = aim_ssi_itemlist_findparentname(od->ssi.local, name); + gname = aim_ssi_itemlist_findparentname(&od->ssi.local, name); gname_utf8 = gname ? oscar_utf8_try_convert(account, od, gname) : NULL; - alias = aim_ssi_getalias(od->ssi.local, gname, name); + alias = aim_ssi_getalias(&od->ssi.local, gname, name); alias_utf8 = oscar_utf8_try_convert(account, od, alias); g_free(alias); @@ -4261,7 +4261,7 @@ } - ssi_item = aim_ssi_itemlist_finditem(od->ssi.local, + ssi_item = aim_ssi_itemlist_finditem(&od->ssi.local, gname, name, AIM_SSI_TYPE_BUDDY); if (ssi_item == NULL) { @@ -4634,8 +4634,8 @@ if (purple_presence_is_online(presence) == FALSE) { char *gname; if ((name) && (od) && (od->ssi.received_data) && - (gname = aim_ssi_itemlist_findparentname(od->ssi.local, name)) && - (aim_ssi_waitingforauth(od->ssi.local, gname, name))) { + (gname = aim_ssi_itemlist_findparentname(&od->ssi.local, name)) && + (aim_ssi_waitingforauth(&od->ssi.local, gname, name))) { return "not-authorized"; } } @@ -4702,8 +4702,8 @@ if ((od != NULL) && !purple_presence_is_online(presence)) { const char *name = purple_buddy_get_name(b); - char *gname = aim_ssi_itemlist_findparentname(od->ssi.local, name); - if (aim_ssi_waitingforauth(od->ssi.local, gname, name)) + char *gname = aim_ssi_itemlist_findparentname(&od->ssi.local, name); + if (aim_ssi_waitingforauth(&od->ssi.local, gname, name)) ret = g_strdup(_("Not Authorized")); else ret = g_strdup(_("Offline")); @@ -4946,7 +4946,7 @@ data = g_new(struct name_data, 1); - comment = aim_ssi_getcomment(od->ssi.local, purple_group_get_name(g), name); + comment = aim_ssi_getcomment(&od->ssi.local, purple_group_get_name(g), name); comment_utf8 = comment ? oscar_utf8_try_convert(account, od, comment) : NULL; data->gc = gc; @@ -5161,8 +5161,8 @@ * waiting for authorization. */ char *gname; - gname = aim_ssi_itemlist_findparentname(od->ssi.local, bname); - if (gname && aim_ssi_waitingforauth(od->ssi.local, gname, bname)) + gname = aim_ssi_itemlist_findparentname(&od->ssi.local, bname); + if (gname && aim_ssi_waitingforauth(&od->ssi.local, gname, bname)) { act = purple_menu_action_new(_("Re-request Authorization"), PURPLE_CALLBACK(oscar_auth_sendrequest_menu), @@ -5313,7 +5313,7 @@ buddy = cur->data; bname = purple_buddy_get_name(buddy); gname = purple_group_get_name(purple_buddy_get_group(buddy)); - if (aim_ssi_waitingforauth(od->ssi.local, gname, bname)) { + if (aim_ssi_waitingforauth(&od->ssi.local, gname, bname)) { filtered_buddies = g_slist_prepend(filtered_buddies, buddy); } } diff -r 36011b558d3e -r 8d6630912021 libpurple/protocols/oscar/oscar.h --- a/libpurple/protocols/oscar/oscar.h Sat Mar 19 19:38:55 2011 +0000 +++ b/libpurple/protocols/oscar/oscar.h Sun Mar 20 20:20:52 2011 +0000 @@ -308,9 +308,14 @@ #include "peer.h" -/* - * AIM Session: The main client-data interface. - * +struct aim_ssi_itemlist { + struct aim_ssi_item *data; + GHashTable *idx_gid_bid; + GHashTable *idx_all_named_items; +}; + +/** + * The main client-data interface. */ struct _OscarData { @@ -387,8 +392,8 @@ struct { gboolean received_data; guint16 numitems; - struct aim_ssi_item *official; - struct aim_ssi_item *local; + struct aim_ssi_itemlist official; + struct aim_ssi_itemlist local; struct aim_ssi_tmp *pending; time_t timestamp; gboolean waiting_for_ack; @@ -916,15 +921,16 @@ /* 0x001a */ int aim_ssi_sendauthreply(OscarData *od, char *bn, guint8 reply, const char *msg); /* Client functions for retrieving SSI data */ -struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, guint16 gid, guint16 bid); -struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *bn, guint16 type); -struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_item *list, const char *bn); -char *aim_ssi_itemlist_findparentname(struct aim_ssi_item *list, const char *bn); -int aim_ssi_getpermdeny(struct aim_ssi_item *list); -guint32 aim_ssi_getpresence(struct aim_ssi_item *list); -char *aim_ssi_getalias(struct aim_ssi_item *list, const char *gn, const char *bn); -char *aim_ssi_getcomment(struct aim_ssi_item *list, const char *gn, const char *bn); -gboolean aim_ssi_waitingforauth(struct aim_ssi_item *list, const char *gn, const char *bn); +struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_itemlist *list, guint16 gid, guint16 bid); +struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_itemlist *list, const char *gn, const char *bn, guint16 type); +struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_itemlist *list, const char *bn); +char *aim_ssi_itemlist_findparentname(struct aim_ssi_itemlist *list, const char *bn); +int aim_ssi_getpermdeny(struct aim_ssi_itemlist *list); +guint32 aim_ssi_getpresence(struct aim_ssi_itemlist *list); +char *aim_ssi_getalias(struct aim_ssi_itemlist *list, const char *gn, const char *bn); +char *aim_ssi_getalias_from_item(struct aim_ssi_item *item); +char *aim_ssi_getcomment(struct aim_ssi_itemlist *list, const char *gn, const char *bn); +gboolean aim_ssi_waitingforauth(struct aim_ssi_itemlist *list, const char *gn, const char *bn); /* Client functions for changing SSI data */ int aim_ssi_addbuddy(OscarData *od, const char *name, const char *group, GSList *tlvlist, const char *alias, const char *comment, const char *smsnum, gboolean needauth); diff -r 36011b558d3e -r 8d6630912021 libpurple/protocols/oscar/oscar_data.c --- a/libpurple/protocols/oscar/oscar_data.c Sat Mar 19 19:38:55 2011 +0000 +++ b/libpurple/protocols/oscar/oscar_data.c Sun Mar 20 20:20:52 2011 +0000 @@ -47,6 +47,12 @@ od->buddyinfo = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); od->handlerlist = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); + od->ssi.local.idx_gid_bid = g_hash_table_new(g_direct_hash, g_direct_equal); + od->ssi.local.idx_all_named_items = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + + od->ssi.official.idx_gid_bid = g_hash_table_new(g_direct_hash, g_direct_equal); + od->ssi.official.idx_all_named_items = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + /* * Register all the modules for this session... */ @@ -126,6 +132,12 @@ g_hash_table_destroy(od->buddyinfo); g_hash_table_destroy(od->handlerlist); + g_hash_table_destroy(od->ssi.local.idx_gid_bid); + g_hash_table_destroy(od->ssi.local.idx_all_named_items); + + g_hash_table_destroy(od->ssi.official.idx_gid_bid); + g_hash_table_destroy(od->ssi.official.idx_all_named_items); + g_free(od); } diff -r 36011b558d3e -r 8d6630912021 libpurple/protocols/oscar/userinfo.c --- a/libpurple/protocols/oscar/userinfo.c Sat Mar 19 19:38:55 2011 +0000 +++ b/libpurple/protocols/oscar/userinfo.c Sun Mar 20 20:20:52 2011 +0000 @@ -263,8 +263,8 @@ message = tmp; } - } else if (aim_ssi_waitingforauth(od->ssi.local, - aim_ssi_itemlist_findparentname(od->ssi.local, purple_buddy_get_name(b)), + } else if (aim_ssi_waitingforauth(&od->ssi.local, + aim_ssi_itemlist_findparentname(&od->ssi.local, purple_buddy_get_name(b)), purple_buddy_get_name(b))) { /* Note if an offline buddy is not authorized */ @@ -356,7 +356,7 @@ } if ((b != NULL) && (bname != NULL) && (g != NULL) && (gname != NULL)) { - tmp = aim_ssi_getcomment(od->ssi.local, gname, bname); + tmp = aim_ssi_getcomment(&od->ssi.local, gname, bname); if (tmp != NULL) { char *tmp2 = g_markup_escape_text(tmp, strlen(tmp)); g_free(tmp); @@ -543,4 +543,4 @@ purple_notify_userinfo(gc, userinfo->bn, user_info, NULL, NULL); purple_notify_user_info_destroy(user_info); -} \ No newline at end of file +} diff -r 36011b558d3e -r 8d6630912021 libpurple/protocols/oscar/visibility.c --- a/libpurple/protocols/oscar/visibility.c Sat Mar 19 19:38:55 2011 +0000 +++ b/libpurple/protocols/oscar/visibility.c Sun Mar 20 20:20:52 2011 +0000 @@ -51,7 +51,7 @@ static gboolean is_buddy_on_list(OscarData *od, const char *bname) { - return aim_ssi_itemlist_finditem(od->ssi.local, NULL, bname, get_buddy_list_type(od)) != NULL; + return aim_ssi_itemlist_finditem(&od->ssi.local, NULL, bname, get_buddy_list_type(od)) != NULL; } static void @@ -102,7 +102,7 @@ buddy = cur->data; bname = purple_buddy_get_name(buddy); - if (aim_ssi_itemlist_finditem(od->ssi.local, NULL, bname, list_type)) { + if (aim_ssi_itemlist_finditem(&od->ssi.local, NULL, bname, list_type)) { filtered_buddies = g_slist_prepend(filtered_buddies, buddy); } }