Mercurial > pidgin.yaz
changeset 3210:5e90ecb578c5
[gaim-migrate @ 3227]
Among other things, a warning for when your OSCAR buddy list is too long. Thanks KingAnt
committer: Tailor Script <tailor@pidgin.im>
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Sun, 05 May 2002 18:42:11 +0000 |
parents | 265a3c9d0557 |
children | 3ef95e625bbc |
files | src/protocols/oscar/aim.h src/protocols/oscar/oscar.c src/protocols/oscar/ssi.c |
diffstat | 3 files changed, 536 insertions(+), 406 deletions(-) [+] |
line wrap: on
line diff
--- a/src/protocols/oscar/aim.h Sun May 05 01:16:45 2002 +0000 +++ b/src/protocols/oscar/aim.h Sun May 05 18:42:11 2002 +0000 @@ -1037,10 +1037,11 @@ faim_export int aim_ssi_modend(aim_session_t *sess, aim_conn_t *conn); /* These handle the local variables */ -faim_export int aim_ssi_inlist(aim_session_t *sess, aim_conn_t *conn, char *name, fu16_t type); -faim_export char *aim_ssi_getparentgroup(aim_session_t *sess, aim_conn_t *conn, char *name); -faim_export int aim_ssi_getpermdeny(aim_session_t *sess, aim_conn_t *conn); -faim_export fu32_t aim_ssi_getpresence(aim_session_t *sess, aim_conn_t *conn); +faim_export struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, fu16_t gid, fu16_t bid); +faim_export struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, char *gn, char *sn, fu16_t type); +faim_export struct aim_ssi_item *aim_ssi_itemlist_findparent(struct aim_ssi_item *list, char *sn); +faim_export int aim_ssi_getpermdeny(struct aim_ssi_item *list); +faim_export fu32_t aim_ssi_getpresence(struct aim_ssi_item *list); faim_export int aim_ssi_cleanlist(aim_session_t *sess, aim_conn_t *conn); faim_export int aim_ssi_addbuddies(aim_session_t *sess, aim_conn_t *conn, char *gn, char **sn, unsigned int num); faim_export int aim_ssi_addmastergroup(aim_session_t *sess, aim_conn_t *conn); @@ -1052,7 +1053,7 @@ faim_export int aim_ssi_delgroups(aim_session_t *sess, aim_conn_t *conn, char **gn, unsigned int num); faim_export int aim_ssi_deletelist(aim_session_t *sess, aim_conn_t *conn); faim_export int aim_ssi_delpord(aim_session_t *sess, aim_conn_t *conn, char **sn, unsigned int num, fu16_t type); -faim_export int aim_ssi_setpermdeny(aim_session_t *sess, aim_conn_t *conn, int permdeny); +faim_export int aim_ssi_setpermdeny(aim_session_t *sess, aim_conn_t *conn, fu8_t permdeny, fu32_t vismask); faim_export int aim_ssi_setpresence(aim_session_t *sess, aim_conn_t *conn, fu32_t presence); struct aim_icq_offlinemsg {
--- a/src/protocols/oscar/oscar.c Sun May 05 01:16:45 2002 +0000 +++ b/src/protocols/oscar/oscar.c Sun May 05 18:42:11 2002 +0000 @@ -2785,7 +2785,7 @@ if (odata->icq) { aim_add_buddy(odata->sess, odata->conn, name); } else { - if ((odata->sess->ssi.received_data) && !(aim_ssi_inlist(odata->sess, odata->conn, name, 0x0000))) { + if ((odata->sess->ssi.received_data) && !(aim_ssi_itemlist_finditem(odata->sess->ssi.items, NULL, name, 0x0000))) { debug_printf("ssi: adding buddy %s to group %s\n", name, find_group_by_buddy(g, name)->name); aim_ssi_addbuddies(odata->sess, odata->conn, find_group_by_buddy(g, name)->name, &name, 1); } @@ -2813,13 +2813,13 @@ for (curgrp=g->groups; curgrp; curgrp=g_slist_next(curgrp)) { tmp = 0; for (curbud=((struct group*)curgrp->data)->members; curbud; curbud=curbud->next) - if (!aim_ssi_inlist(odata->sess, odata->conn, ((struct buddy*)curbud->data)->name, 0x0000)) + if (!aim_ssi_itemlist_finditem(odata->sess->ssi.items, NULL, ((struct buddy*)curbud->data)->name, 0x0000)) tmp++; if (tmp) { char **sns = (char **)malloc(tmp*sizeof(char*)); tmp = 0; for (curbud=((struct group*)curgrp->data)->members; curbud; curbud=curbud->next) - if (!aim_ssi_inlist(odata->sess, odata->conn, ((struct buddy*)curbud->data)->name, 0x0000)) { + if (!aim_ssi_itemlist_finditem(odata->sess->ssi.items, NULL, ((struct buddy*)curbud->data)->name, 0x0000)) { debug_printf("ssi: adding buddy %s to group %s\n", ((struct buddy*)curbud->data)->name, ((struct group*)curgrp->data)->name); sns[tmp] = (char *)((struct buddy*)curbud->data)->name; tmp++; @@ -2847,8 +2847,8 @@ aim_remove_buddy(odata->sess, odata->conn, name); } else { if (odata->sess->ssi.received_data) { - char *ssigroup; - while (aim_ssi_inlist(odata->sess, odata->conn, name, 0x0000) && (ssigroup = aim_ssi_getparentgroup(odata->sess, odata->conn, name)) && !aim_ssi_delbuddies(odata->sess, odata->conn, ssigroup, &name, 1)) + struct aim_ssi_item *ssigroup; + while (aim_ssi_itemlist_finditem(odata->sess->ssi.items, NULL, name, 0x0000) && (ssigroup = aim_ssi_itemlist_findparent(odata->sess->ssi.items, name)) && !aim_ssi_delbuddies(odata->sess, odata->conn, ssigroup->name, &name, 1)) debug_printf("ssi: deleted buddy %s from group %s\n", name, group); } } @@ -2865,14 +2865,14 @@ GList *cur; int tmp = 0; for (cur=buddies; cur; cur=cur->next) - if (aim_ssi_inlist(odata->sess, odata->conn, cur->data, 0x0000)) + if (aim_ssi_itemlist_finditem(odata->sess->ssi.items, NULL, cur->data, 0x0000)) tmp++; if (tmp) { char **sns; sns = (char **)malloc(tmp*sizeof(char*)); tmp = 0; for (cur=buddies; cur; cur=cur->next) - if (aim_ssi_inlist(odata->sess, odata->conn, cur->data, 0x0000)) { + if (aim_ssi_itemlist_finditem(odata->sess->ssi.items, NULL, cur->data, 0x0000)) { debug_printf("ssi: deleting buddy %s from group %s\n", cur->data, group); sns[tmp] = cur->data; tmp++; @@ -2919,7 +2919,7 @@ aim_ssi_enable(sess, fr->conn); /* Clean the buddy list */ - /* aim_ssi_cleanlist(sess, fr->conn); */ + aim_ssi_cleanlist(sess, fr->conn); /* Add from server list to local list */ tmp = 0; @@ -2972,7 +2972,7 @@ case 0x0004: /* Permit/deny setting */ if (curitem->data) { fu8_t permdeny; - if ((permdeny = aim_ssi_getpermdeny(sess, fr->conn)) && (permdeny != gc->permdeny)) { + if ((permdeny = aim_ssi_getpermdeny(sess->ssi.items)) && (permdeny != gc->permdeny)) { debug_printf("ssi: changing permdeny from %d to %d\n", gc->permdeny, permdeny); gc->permdeny = permdeny; tmp++; @@ -2998,13 +2998,13 @@ GSList *curbud; tmp = 0; for (curbud=((struct group*)cur->data)->members; curbud; curbud=curbud->next) - if (!aim_ssi_inlist(sess, fr->conn, ((struct buddy*)curbud->data)->name, 0x0000)) + if (!aim_ssi_itemlist_finditem(sess->ssi.items, NULL, ((struct buddy*)curbud->data)->name, 0x0000)) tmp++; if (tmp) { sns = (char **)malloc(tmp*sizeof(char*)); tmp = 0; for (curbud=((struct group*)cur->data)->members; curbud; curbud=curbud->next) - if (!aim_ssi_inlist(sess, fr->conn, ((struct buddy*)curbud->data)->name, 0x0000)) { + if (!aim_ssi_itemlist_finditem(sess->ssi.items, NULL, ((struct buddy*)curbud->data)->name, 0x0000)) { debug_printf("ssi: adding buddy %s from local list to server list\n", ((struct buddy*)curbud->data)->name); sns[tmp] = ((char *)((struct buddy*)curbud->data)->name); tmp++; @@ -3019,13 +3019,13 @@ if (gc->permit) { tmp = 0; for (cur=gc->permit; cur; cur=cur->next) - if (!aim_ssi_inlist(sess, fr->conn, cur->data, 0x0002)) + if (!aim_ssi_itemlist_finditem(sess->ssi.items, NULL, cur->data, 0x0002)) tmp++; if (tmp) { sns = (char **)malloc(tmp*sizeof(char*)); tmp = 0; for (cur=gc->permit; cur; cur=cur->next) - if (!aim_ssi_inlist(sess, fr->conn, cur->data, 0x0002)) { + if (!aim_ssi_itemlist_finditem(sess->ssi.items, NULL, cur->data, 0x0002)) { debug_printf("ssi: adding permit %s from local list to server list\n", cur->data); sns[tmp] = cur->data; tmp++; @@ -3039,13 +3039,13 @@ if (gc->deny) { tmp = 0; for (cur=gc->deny; cur; cur=cur->next) - if (!aim_ssi_inlist(sess, fr->conn, cur->data, 0x0003)) + if (!aim_ssi_itemlist_finditem(sess->ssi.items, NULL, cur->data, 0x0003)) tmp++; if (tmp) { sns = (char **)malloc(tmp*sizeof(char*)); tmp = 0; for (cur=gc->deny; cur; cur=cur->next) - if (!aim_ssi_inlist(sess, fr->conn, cur->data, 0x0003)) { + if (!aim_ssi_itemlist_finditem(sess->ssi.items, NULL, cur->data, 0x0003)) { debug_printf("ssi: adding deny %s from local list to server list\n", cur->data); sns[tmp] = cur->data; tmp++; @@ -3056,10 +3056,23 @@ } /* Presence settings (idle time visibility) */ - if ((tmp = aim_ssi_getpresence(sess, fr->conn)) != 0xFFFFFFFF) + if ((tmp = aim_ssi_getpresence(sess->ssi.items)) != 0xFFFFFFFF) if (report_idle && !(tmp & 0x400)) aim_ssi_setpresence(sess, fr->conn, tmp | 0x400); - } + + /* Check for maximum number of buddies */ + for (cur=gc->groups, tmp=0; cur; cur=g_slist_next(cur)) { + tmp = tmp + g_slist_length(cur->data->members); + + if (tmp > odata->rights.maxbuddies) { + char *dialog_msg = g_strdup_printf(_("The maximum number of buddies allowed in your buddy list is %d, and you have %d." + " Until you are below the limit, some buddies will not show up as online."), + odata->rights.maxbuddies, tmp); + do_error_dialog(dialog_msg, _("Gaim - Warning")); + g_free(dialog_msg); + } + + } /* end if (gc) */ return 1; } @@ -3520,7 +3533,7 @@ signoff_blocked(gc); } else { if (od->sess->ssi.received_data) - aim_ssi_setpermdeny(od->sess, od->conn, gc->permdeny); + aim_ssi_setpermdeny(od->sess, od->conn, gc->permdeny, 0xffffffff); } }
--- a/src/protocols/oscar/ssi.c Sun May 05 01:16:45 2002 +0000 +++ b/src/protocols/oscar/ssi.c Sun May 05 18:42:11 2002 +0000 @@ -5,6 +5,15 @@ * such as a users buddy list, permit/deny list, and permit/deny preferences, * to be stored on the server, so that they can be accessed from any client. * + * We keep a copy of the ssi data in sess->ssi, because the data needs to be + * accessed for various reasons. So all the "aim_ssi_itemlist_bleh" functions + * near the top just manage the local data. + * + * The SNAC sending and receiving functions are lower down in the file, and + * they're simpler. They are in the order of the subtypes they deal with, + * starting with the request rights function (subtype 0x0002), then parse + * rights (subtype 0x0003), then--well, you get the idea. + * * This is entirely too complicated. * You don't know the half of it. * @@ -16,63 +25,231 @@ #define FAIM_INTERNAL #include <aim.h> -/* - * Checks if the given screen name is anywhere in our buddy list. +/** + * Locally add a new item to the given item list. + * + * @param list A pointer to a pointer to the current list of items. + * @param parent A pointer to the parent group, or NULL if the item should have no + * parent group (ie. the group ID# should be 0). + * @param name A null terminated string of the name of the new item, or NULL if the + * item should have no name. + * @param type The type of the item, 0x0001 for a contact, 0x0002 for a group, etc. + * @return The newly created item. */ -faim_export int aim_ssi_inlist(aim_session_t *sess, aim_conn_t *conn, char *name, fu16_t type) +static struct aim_ssi_item *aim_ssi_itemlist_add(struct aim_ssi_item **list, struct aim_ssi_item *parent, char *name, fu16_t type) { + int i; + struct aim_ssi_item *cur, *newitem; + + if (!(newitem = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item)))) + return NULL; + + /* Set the name */ + if (name) { + if (!(newitem->name = (char *)malloc((strlen(name)+1)*sizeof(char)))) { + free(newitem); + return NULL; + } + strcpy(newitem->name, name); + } else + newitem->name = NULL; + + /* Set the group ID# and the buddy ID# */ + newitem->gid = 0x0000; + newitem->bid = 0x0000; + if (type == AIM_SSI_TYPE_GROUP) { + if (name) + do { + newitem->gid += 0x0001; + for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next) + if ((cur->gid == newitem->gid) && (cur->gid == newitem->gid)) + i=1; + } while (i); + } else { + if (parent) + newitem->gid = parent->gid; + do { + newitem->bid += 0x0001; + for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next) + if ((cur->bid == newitem->bid) && (cur->gid == newitem->gid)) + i=1; + } while (i); + } + + /* Set the rest */ + newitem->type = type; + newitem->data = NULL; + newitem->next = *list; + *list = newitem; + + return newitem; +} + +/** + * Locally rebuild the 0x00c8 TLV in the additional data of the given group. + * + * @param list A pointer to a pointer to the current list of items. + * @param parentgroup A pointer to the group who's additional data you want to rebuild. + * @return Return 0 if no errors, otherwise return the error number. + */ +static int aim_ssi_itemlist_rebuildgroup(struct aim_ssi_item **list, struct aim_ssi_item *parentgroup) +{ + int newlen, i; struct aim_ssi_item *cur; - if (!sess && !conn && !name) - return -EINVAL; - for (cur=sess->ssi.items; cur; cur=cur->next) - if ((cur->type==type) && (cur->name) && (!aim_sncmp(cur->name, name))) - return 1; + + /* Free the old additional data */ + if (parentgroup->data) { + aim_freetlvchain((aim_tlvlist_t **)&parentgroup->data); + parentgroup->data = NULL; + } + + /* Find the length for the new additional data */ + newlen = 0; + if (parentgroup->gid == 0x0000) { + for (cur=*list; cur; cur=cur->next) + if ((cur->gid != 0x0000) && (cur->type == AIM_SSI_TYPE_GROUP)) + newlen += 2; + } else { + for (cur=*list; cur; cur=cur->next) + if ((cur->gid == parentgroup->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) + newlen += 2; + } + + /* Rebuild the additional data */ + if (newlen>0) { + fu8_t *newdata; + + if (!(newdata = (fu8_t *)malloc((newlen)*sizeof(fu8_t)))) + return -ENOMEM; + newlen = 0; + if (parentgroup->gid == 0x0000) { + for (cur=*list; cur; cur=cur->next) + if ((cur->gid != 0x0000) && (cur->type == AIM_SSI_TYPE_GROUP)) + aimutil_put16(newdata+newlen*2, cur->gid); + } else { + for (cur=*list; cur; cur=cur->next) + if ((cur->gid == parentgroup->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) + aimutil_put16(newdata+newlen*2, cur->bid); + } + aim_addtlvtochain_raw((aim_tlvlist_t **)&(parentgroup->data), 0x00c8, newlen, newdata); + + free(newdata); + } + return 0; } -/* - * Return the parent group of a given buddy. +/** + * Locally free all of the stored buddy list information. + * + * @param sess The oscar session. + * @return Return 0 if no errors, otherwise return the error number. */ -faim_export char *aim_ssi_getparentgroup(aim_session_t *sess, aim_conn_t *conn, char *name) +static int aim_ssi_freelist(aim_session_t *sess) { - fu16_t gid; - struct aim_ssi_item *cur; - if (!sess && !conn && !name) - return NULL; - for (cur=sess->ssi.items; cur && (cur->type!=AIM_SSI_TYPE_BUDDY || !cur->name || aim_sncmp(cur->name, name)); cur=cur->next) - if (!cur) - return NULL; - gid = cur->gid; - for (cur=sess->ssi.items; cur; cur=cur->next) - if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid == gid) && (cur->name)) - return cur->name; + struct aim_ssi_item *cur, *delitem; + + cur = sess->ssi.items; + while (cur) { + if (cur->name) free(cur->name); + if (cur->data) aim_freetlvchain((aim_tlvlist_t **)&cur->data); + delitem = cur; + cur = cur->next; + free(delitem); + } + + sess->ssi.items = NULL; + sess->ssi.revision = 0; + sess->ssi.timestamp = (time_t)0; + return 0; } -/* - * Returns a pointer to an item with the given name and type, or NULL if one does not exist. +/** + * Locally find an item given a group ID# and a buddy ID#. + * + * @param list A pointer to the current list of items. + * @param gid The group ID# of the desired item. + * @param bid The buddy ID# of the desired item. + * @return Return a pointer to the item if found, else return NULL; */ -static struct aim_ssi_item *get_ssi_item(struct aim_ssi_item *items, char *name, fu16_t type) +faim_export struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, fu16_t gid, fu16_t bid) { struct aim_ssi_item *cur; - if (name) { - for (cur=items; cur; cur=cur->next) - if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, name))) - return cur; - } else { /* return the given type with gid 0 */ - for (cur=items; cur; cur=cur->next) - if ((cur->type == type) && (cur->gid == 0x0000)) - return cur; - } + for (cur=list; cur; cur=cur->next) + if ((cur->gid == gid) && (cur->bid == bid)) + return cur; return NULL; } -/* - * Returns the permit/deny byte +/** + * Locally find an item given a group name, screen name, and type. If group name + * and screen name are null, then just return the first item of the given type. + * + * @param list A pointer to the current list of items. + * @param gn The group name of the desired item. + * @param bn The buddy name of the desired item. + * @param type The type of the desired item. + * @return Return a pointer to the item if found, else return NULL; */ -faim_export int aim_ssi_getpermdeny(aim_session_t *sess, aim_conn_t *conn) +faim_export struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, char *gn, char *sn, fu16_t type) { - struct aim_ssi_item *cur = get_ssi_item(sess->ssi.items, NULL, AIM_SSI_TYPE_PDINFO); + struct aim_ssi_item *cur; + if (!list) + return NULL; + + if (gn && sn) { /* For finding buddies in groups */ + for (cur=list; cur; cur=cur->next) + if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, sn))) { + struct aim_ssi_item *curg; + for (curg=list; curg; curg=curg->next) + if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid) && (curg->name) && !(aim_sncmp(curg->name, gn))) + return cur; + } + + } else if (sn) { /* For finding groups, permits, denies, and ignores */ + for (cur=list; cur; cur=cur->next) + if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, sn))) + return cur; + + /* For stuff without names--permit deny setting, visibility mask, etc. */ + } else for (cur=list; cur; cur=cur->next) { + if (cur->type == type) + return cur; + } + + return NULL; +} + +/** + * Locally find the parent item of the given buddy name. + * + * @param list A pointer to the current list of items. + * @param bn The buddy name of the desired item. + * @return Return a pointer to the item if found, else return NULL; + */ +faim_export struct aim_ssi_item *aim_ssi_itemlist_findparent(struct aim_ssi_item *list, char *sn) +{ + struct aim_ssi_item *cur, *curg; + if (!list || !sn) + return NULL; + if (!(cur = aim_ssi_itemlist_finditem(list, NULL, sn, AIM_SSI_TYPE_BUDDY))) + return NULL; + for (curg=list; curg; curg=curg->next) + if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid)) + return curg; + return NULL; +} + +/** + * Locally find the permit/deny setting item, and return the setting. + * + * @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. + */ +faim_export int aim_ssi_getpermdeny(struct aim_ssi_item *list) +{ + struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PDINFO); if (cur) { aim_tlvlist_t *tlvlist = cur->data; if (tlvlist) { @@ -81,18 +258,20 @@ return aimutil_get8(tlv->value); } } - return 0; } -/* - * Returns the presence flag - * I'm pretty sure this is a bitmask, but really have no evidence for that. - * 0x00000400 - Show up as visible to others +/** + * Locally find the presence flag item, and return the setting. The returned setting is a + * bitmask of the user flags that you are visible to. See the AIM_FLAG_* #defines + * in aim.h + * + * @param list A pointer to the current list of items. + * @return Return the current visibility mask. */ -faim_export fu32_t aim_ssi_getpresence(aim_session_t *sess, aim_conn_t *conn) +faim_export fu32_t aim_ssi_getpresence(struct aim_ssi_item *list) { - struct aim_ssi_item *cur = get_ssi_item(sess->ssi.items, NULL, AIM_SSI_TYPE_PRESENCEPREFS); + struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS); if (cur) { aim_tlvlist_t *tlvlist = cur->data; if (tlvlist) { @@ -101,12 +280,18 @@ return aimutil_get32(tlv->value); } } - return 0xFFFFFFFF; } -/* - * Add the given packet to the holding queue. +/** + * Add the given packet to the holding queue. We totally need to send SSI SNACs one at + * a time, so we have a local queue where packets get put before they are sent, and + * then we send stuff one at a time, nice and orderly-like. + * + * @param sess The oscar session. + * @param conn The bos connection for this session. + * @param fr The newly created SNAC that you want to send. + * @return Return 0 if no errors, otherwise return the error number. */ static int aim_ssi_enqueue(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *fr) { @@ -128,8 +313,14 @@ return 0; } -/* - * Send the next SNAC from the holding queue. +/** + * Send the next SNAC from the holding queue. This is called + * automatically when an ack from an add, mod, or del is received. + * If the queue is empty, it sends the modend SNAC. + * + * @param sess The oscar session. + * @param conn The bos connection for this session. + * @return Return 0 if no errors, otherwise return the error number. */ static int aim_ssi_dispatch(aim_session_t *sess, aim_conn_t *conn) { @@ -152,107 +343,13 @@ return 0; } -/* - * Rebuild the additional data for the given group(s). - */ -static int aim_ssi_rebuildgroup(aim_session_t *sess, aim_conn_t *conn, struct aim_ssi_item *parentgroup) -{ - int newlen; - struct aim_ssi_item *cur; - - if (!sess || !conn || !parentgroup) - return -EINVAL; - - /* Free the old additional data */ - if (parentgroup->data) { - aim_freetlvchain((aim_tlvlist_t **)&parentgroup->data); - parentgroup->data = NULL; - } - - /* Find the length for the new additional data */ - newlen = 0; - if (parentgroup->gid == 0x0000) { - for (cur=sess->ssi.items; cur; cur=cur->next) - if ((cur->gid != 0x0000) && (cur->type == AIM_SSI_TYPE_GROUP)) - newlen += 2; - } else { - for (cur=sess->ssi.items; cur; cur=cur->next) - if ((cur->gid == parentgroup->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) - newlen += 2; - } - - /* Rebuild the additional data */ - if (newlen>0) { - aim_bstream_t tbs; - tbs.len = newlen+4; - tbs.offset = 0; - if (!(tbs.data = (fu8_t *)malloc((tbs.len)*sizeof(fu8_t)))) - return -ENOMEM; - aimbs_put16(&tbs, 0x00c8); - aimbs_put16(&tbs, tbs.len-4); - if (parentgroup->gid == 0x0000) { - for (cur=sess->ssi.items; cur; cur=cur->next) - if ((cur->gid != 0x0000) && (cur->type == AIM_SSI_TYPE_GROUP)) - aimbs_put16(&tbs, cur->gid); - } else { - for (cur=sess->ssi.items; cur; cur=cur->next) - if ((cur->gid == parentgroup->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) - aimbs_put16(&tbs, cur->bid); - } - tbs.offset = 0; - parentgroup->data = (void *)aim_readtlvchain(&tbs); - free(tbs.data); - -/* XXX - WHYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY does this crash? - fu8_t *newdata; - if (!(newdata = (fu8_t *)malloc((newlen)*sizeof(fu8_t)))) - return -ENOMEM; - newlen = 0; - if (parentgroup->gid == 0x0000) { - for (cur=sess->ssi.items; cur; cur=cur->next) - if ((cur->gid != 0x0000) && (cur->type == AIM_SSI_TYPE_GROUP)) { - memcpy(&newdata[newlen*2], &cur->gid, 2); - newlen += 2; - } - } else { - for (cur=sess->ssi.items; cur; cur=cur->next) - if ((cur->gid == parentgroup->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) { - memcpy(&newdata[newlen*2], &cur->bid, 2); - newlen += 2; - } - } - aim_addtlvtochain_raw((aim_tlvlist_t **)&parentgroup->data, 0x00c8, newlen, newdata); - free(newdata); */ - } - - return 0; -} - -/* - * Clears all of our locally stored buddy list information. - */ -static int aim_ssi_freelist(aim_session_t *sess) -{ - struct aim_ssi_item *cur, *delitem; - - cur = sess->ssi.items; - while (cur) { - if (cur->name) free(cur->name); - if (cur->data) aim_freetlvchain((aim_tlvlist_t **)&cur->data); - delitem = cur; - cur = cur->next; - free(delitem); - } - - sess->ssi.revision = 0; - sess->ssi.items = NULL; - sess->ssi.timestamp = (time_t)0; - - return 0; -} - -/* - * This removes all ssi data from server and local copy. +/** + * Send SNACs necessary to remove all SSI data from the server list, + * and then free the local copy as well. + * + * @param sess The oscar session. + * @param conn The bos connection for this session. + * @return Return 0 if no errors, otherwise return the error number. */ faim_export int aim_ssi_deletelist(aim_session_t *sess, aim_conn_t *conn) { @@ -278,29 +375,34 @@ return 0; } -/* - * This "cleans" the ssi list. It makes sure all buddies are in a group, and - * all groups have additional data for the buddies that are in them. It does - * this by rebuilding the additional data for every group, sending mod SNACs - * as necessary. +/** + * This "cleans" the ssi list. It does a few things, with the intent of making + * sure there ain't nothin' wrong with your SSI. + * -Make sure all buddies are in a group, and all groups have the correct + * additional data. + * -Make sure there are no empty groups in the list. While there is nothing + * wrong empty groups in the SSI, it's wiser to not have them. + * + * @param sess The oscar session. + * @param conn The bos connection for this session. + * @return Return 0 if no errors, otherwise return the error number. */ faim_export int aim_ssi_cleanlist(aim_session_t *sess, aim_conn_t *conn) { - unsigned int num_to_be_fixed; + unsigned int i; struct aim_ssi_item *cur, *parentgroup; /* Make sure we actually need to clean out the list */ - for (cur=sess->ssi.items, num_to_be_fixed=0; cur; cur=cur->next) { + for (cur=sess->ssi.items, i=0; cur && !i; cur=cur->next) /* Any buddies directly in the master group */ if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->gid == 0x0000)) - num_to_be_fixed++; - } - if (!num_to_be_fixed) + i++; + if (!i) return 0; - /* Remove all the additional data from all groups and buddies */ + /* Remove all the additional data from all groups */ for (cur=sess->ssi.items; cur; cur=cur->next) - if (cur->data && ((cur->type == AIM_SSI_TYPE_BUDDY) || (cur->type == AIM_SSI_TYPE_GROUP))) { + if ((cur->data) && (cur->type == AIM_SSI_TYPE_GROUP)) { aim_freetlvchain((aim_tlvlist_t **)&cur->data); cur->data = NULL; } @@ -309,7 +411,7 @@ /* there is a group to put them in. Any group, any group at all. */ for (cur=sess->ssi.items; ((cur) && ((cur->type != AIM_SSI_TYPE_BUDDY) || (cur->gid != 0x0000))); cur=cur->next); if (!cur) { - for (parentgroup=sess->ssi.items; ((parentgroup) && ((parentgroup->type!=AIM_SSI_TYPE_GROUP) || (parentgroup->gid!=0x0000))); parentgroup=parentgroup->next); + for (parentgroup=sess->ssi.items; ((parentgroup) && (parentgroup->type!=AIM_SSI_TYPE_GROUP) && (parentgroup->gid==0x0000)); parentgroup=parentgroup->next); if (!parentgroup) { char *newgroup; newgroup = (char*)malloc(strlen("Unknown")*sizeof(char)); @@ -332,12 +434,45 @@ /* Rebuild additional data for all groups */ for (parentgroup=sess->ssi.items; parentgroup; parentgroup=parentgroup->next) if (parentgroup->type == AIM_SSI_TYPE_GROUP) - aim_ssi_rebuildgroup(sess, conn, parentgroup); + aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup); /* Send a mod snac for all groups */ + i = 0; for (cur=sess->ssi.items; cur; cur=cur->next) if (cur->type == AIM_SSI_TYPE_GROUP) - aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_MOD); + i++; + if (i > 0) { + /* Allocate an array of pointers to each of the groups */ + struct aim_ssi_item **groups; + if (!(groups = (struct aim_ssi_item **)malloc(i*sizeof(struct aim_ssi_item *)))) + return -ENOMEM; + + for (cur=sess->ssi.items, i=0; cur; cur=cur->next) + if (cur->type == AIM_SSI_TYPE_GROUP) + groups[i] = cur; + + aim_ssi_addmoddel(sess, conn, groups, i, AIM_CB_SSI_MOD); + free(groups); + } + + /* Send a del snac for any empty groups */ + i = 0; + for (cur=sess->ssi.items; cur; cur=cur->next) + if ((cur->type == AIM_SSI_TYPE_GROUP) && !(cur->data)) + i++; + if (i > 0) { + /* Allocate an array of pointers to each of the groups */ + struct aim_ssi_item **groups; + if (!(groups = (struct aim_ssi_item **)malloc(i*sizeof(struct aim_ssi_item *)))) + return -ENOMEM; + + for (cur=sess->ssi.items, i=0; cur; cur=cur->next) + if ((cur->type == AIM_SSI_TYPE_GROUP) && !(cur->data)) + groups[i] = cur; + + aim_ssi_addmoddel(sess, conn, groups, i, AIM_CB_SSI_DEL); + free(groups); + } /* Begin sending SSI SNACs */ aim_ssi_dispatch(sess, conn); @@ -345,117 +480,88 @@ return 0; } -/* - * The next few functions take data as screen names and groups, - * modifies the ssi item list, and calls the functions to - * add, mod, or del an item or items. +/** + * Add an array of screen names to the given group. * - * These are what the client should call. The client should - * also make sure it's not adding a buddy that's already in - * the list (using aim_ssi_inlist). + * @param sess The oscar session. + * @param conn The bos connection for this session. + * @param gn The name of the group to which you want to add these names. + * @param sn An array of null terminated strings of the names you want to add. + * @param num The number of screen names you are adding (size of the sn array). + * @return Return 0 if no errors, otherwise return the error number. */ faim_export int aim_ssi_addbuddies(aim_session_t *sess, aim_conn_t *conn, char *gn, char **sn, unsigned int num) { - struct aim_ssi_item *cur, *parentgroup, **newitems; - fu16_t i, j; + struct aim_ssi_item *parentgroup, **newitems; + fu16_t i; if (!sess || !conn || !gn || !sn || !num) return -EINVAL; /* Look up the parent group */ - if (!(parentgroup = get_ssi_item(sess->ssi.items, gn, AIM_SSI_TYPE_GROUP))) { + if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn, AIM_SSI_TYPE_GROUP))) { aim_ssi_addgroups(sess, conn, &gn, 1); - if (!(parentgroup = get_ssi_item(sess->ssi.items, gn, AIM_SSI_TYPE_GROUP))) + if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn, AIM_SSI_TYPE_GROUP))) return -ENOMEM; } /* Allocate an array of pointers to each of the new items */ if (!(newitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)))) return -ENOMEM; - memset(newitems, 0, num*sizeof(struct aim_ssi_item *)); - /* The following for loop iterates once per item that needs to be added. */ - /* For each i, create an item and tack it onto the newitems array */ - for (i=0; i<num; i++) { - if (!(newitems[i] = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item)))) { - for (j=0; j<(i-1); j++) { - free(newitems[j]->name); - free(newitems[j]); - } + /* Add items to the local list, and index them in the array */ + for (i=0; i<num; i++) + if (!(newitems[i] = aim_ssi_itemlist_add(&sess->ssi.items, parentgroup, sn[i], AIM_SSI_TYPE_BUDDY))) { free(newitems); return -ENOMEM; } - if (!(newitems[i]->name = (char *)malloc((strlen(sn[i])+1)*sizeof(char)))) { - for (j=0; j<(i-1); j++) { - free(newitems[j]->name); - free(newitems[j]); - } - free(newitems[i]); - free(newitems); - return -ENOMEM; - } - strcpy(newitems[i]->name, sn[i]); - newitems[i]->gid = parentgroup->gid; - newitems[i]->bid = i ? newitems[i-1]->bid : 0; - do { - newitems[i]->bid += 0x0001; - for (cur=sess->ssi.items, j=0; ((cur) && (!j)); cur=cur->next) - if ((cur->bid == newitems[i]->bid) && (cur->gid == newitems[i]->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) - j=1; - } while (j); - newitems[i]->type = AIM_SSI_TYPE_BUDDY; - newitems[i]->data = NULL; - newitems[i]->next = i ? newitems[i-1] : NULL; - } - - /* Add the items to our list */ - newitems[0]->next = sess->ssi.items; - sess->ssi.items = newitems[num-1]; /* Send the add item SNAC */ - aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD); + if (i = aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD)) { + free(newitems); + return -i; + } /* Free the array of pointers to each of the new items */ free(newitems); /* Rebuild the additional data in the parent group */ - aim_ssi_rebuildgroup(sess, conn, parentgroup); + if (i = aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup)) + return i; /* Send the mod item SNAC */ - aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD); + if (i = aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD)) + return i; /* Begin sending SSI SNACs */ - aim_ssi_dispatch(sess, conn); + if (!(i = aim_ssi_dispatch(sess, conn))) + return i; return 0; } -/* - * This adds the master group (the group containing all groups) if it doesn't exist. - * It's called by aim_ssi_addgroups, if your list is empty. +/** + * Add the master group (the group containing all groups). This is called by + * aim_ssi_addgroups, if necessary. + * + * @param sess The oscar session. + * @param conn The bos connection for this session. + * @return Return 0 if no errors, otherwise return the error number. */ -faim_export int aim_ssi_addmastergroup(aim_session_t *sess, aim_conn_t *conn) { +faim_export int aim_ssi_addmastergroup(aim_session_t *sess, aim_conn_t *conn) +{ struct aim_ssi_item *newitem; if (!sess || !conn) return -EINVAL; - /* Allocate an array of pointers to each of the new items */ - if (!(newitem = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item)))) + /* Add the item to the local list, and keep a pointer to it */ + if (!(newitem = aim_ssi_itemlist_add(&sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_GROUP))) return -ENOMEM; - memset(newitem, 0, sizeof(struct aim_ssi_item)); - - /* memset to 0 sets most of the vars to what they should be */ - newitem->type = AIM_SSI_TYPE_GROUP; - - /* Add the item to our list */ - newitem->next = sess->ssi.items; - sess->ssi.items = newitem; /* If there are any existing groups (technically there shouldn't be, but */ /* just in case) then add their group ID#'s to the additional data */ - if (sess->ssi.items) - aim_ssi_rebuildgroup(sess, conn, newitem); + aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, newitem); /* Send the add item SNAC */ aim_ssi_addmoddel(sess, conn, &newitem, 1, AIM_CB_SSI_ADD); @@ -466,149 +572,124 @@ return 0; } +/** + * Add an array of groups to the list. + * + * @param sess The oscar session. + * @param conn The bos connection for this session. + * @param gn An array of null terminated strings of the names you want to add. + * @param num The number of groups names you are adding (size of the sn array). + * @return Return 0 if no errors, otherwise return the error number. + */ faim_export int aim_ssi_addgroups(aim_session_t *sess, aim_conn_t *conn, char **gn, unsigned int num) { - struct aim_ssi_item *cur, *parentgroup, **newitems; - fu16_t i, j; + struct aim_ssi_item *parentgroup, **newitems; + fu16_t i; if (!sess || !conn || !gn || !num) return -EINVAL; /* Look up the parent group */ - if (!(parentgroup = get_ssi_item(sess->ssi.items, NULL, AIM_SSI_TYPE_GROUP))) { + if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_GROUP))) { aim_ssi_addmastergroup(sess, conn); - if (!(parentgroup = get_ssi_item(sess->ssi.items, NULL, AIM_SSI_TYPE_GROUP))) + if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_GROUP))) return -ENOMEM; } /* Allocate an array of pointers to each of the new items */ if (!(newitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)))) return -ENOMEM; - memset(newitems, 0, num*sizeof(struct aim_ssi_item *)); - /* The following for loop iterates once per item that needs to be added. */ - /* For each i, create an item and tack it onto the newitems array */ - for (i=0; i<num; i++) { - if (!(newitems[i] = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item)))) { - for (j=0; j<(i-1); j++) { - free(newitems[j]->name); - free(newitems[j]); - } + /* Add items to the local list, and index them in the array */ + for (i=0; i<num; i++) + if (!(newitems[i] = aim_ssi_itemlist_add(&sess->ssi.items, parentgroup, gn[i], AIM_SSI_TYPE_GROUP))) { free(newitems); return -ENOMEM; } - if (!(newitems[i]->name = (char *)malloc((strlen(gn[i])+1)*sizeof(char)))) { - for (j=0; j<(i-1); j++) { - free(newitems[j]->name); - free(newitems[j]); - } - free(newitems[i]); - free(newitems); - return -ENOMEM; - } - strcpy(newitems[i]->name, gn[i]); - newitems[i]->gid = i ? newitems[i-1]->gid : 0; - do { - newitems[i]->gid += 0x0001; - for (cur=sess->ssi.items, j=0; ((cur) && (!j)); cur=cur->next) - if ((cur->gid == newitems[i]->gid) && (cur->type == AIM_SSI_TYPE_GROUP)) - j=1; - } while (j); - newitems[i]->bid = 0x0000; - newitems[i]->type = AIM_SSI_TYPE_GROUP; - newitems[i]->data = NULL; - newitems[i]->next = i ? newitems[i-1] : NULL; - } - - /* Add the items to our list */ - newitems[0]->next = sess->ssi.items; - sess->ssi.items = newitems[num-1]; /* Send the add item SNAC */ - aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD); + if (i = aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD)) { + free(newitems); + return -i; + } /* Free the array of pointers to each of the new items */ free(newitems); /* Rebuild the additional data in the parent group */ - aim_ssi_rebuildgroup(sess, conn, parentgroup); + if (i = aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup)) + return i; /* Send the mod item SNAC */ - aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD); + if (i = aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD)) + return i; /* Begin sending SSI SNACs */ - aim_ssi_dispatch(sess, conn); + if (!(i = aim_ssi_dispatch(sess, conn))) + return i; return 0; } -/* - * Add permit or deny buddies to the permit or deny list. - * The buddies are passed as an array of pointers to char strings. +/** + * Add an array of a certain type of item to the list. This can be used for + * permit buddies, deny buddies, ICQ's ignore buddies, and probably other + * types, also. + * + * @param sess The oscar session. + * @param conn The bos connection for this session. + * @param sn An array of null terminated strings of the names you want to add. + * @param num The number of groups names you are adding (size of the sn array). + * @param type The type of item you want to add. See the AIM_SSI_TYPE_BLEH + * #defines in aim.h. + * @return Return 0 if no errors, otherwise return the error number. */ faim_export int aim_ssi_addpord(aim_session_t *sess, aim_conn_t *conn, char **sn, unsigned int num, fu16_t type) { - struct aim_ssi_item *cur, **newitems; - fu16_t i, j; + struct aim_ssi_item **newitems; + fu16_t i; - if (!sess || !conn || !sn || !num || (type!=AIM_SSI_TYPE_PERMIT && type!=AIM_SSI_TYPE_DENY)) + if (!sess || !conn || !sn || !num) return -EINVAL; /* Allocate an array of pointers to each of the new items */ if (!(newitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)))) return -ENOMEM; - memset(newitems, 0, num*sizeof(struct aim_ssi_item *)); - /* The following for loop iterates once per item that needs to be added. */ - /* For each i, create an item and tack it onto the newitems array */ - for (i=0; i<num; i++) { - if (!(newitems[i] = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item)))) { - for (j=0; j<(i-1); j++) { - free(newitems[j]->name); - free(newitems[j]); - } + /* Add items to the local list, and index them in the array */ + for (i=0; i<num; i++) + if (!(newitems[i] = aim_ssi_itemlist_add(&sess->ssi.items, NULL, sn[i], type))) { free(newitems); return -ENOMEM; } - if (!(newitems[i]->name = (char *)malloc((strlen(sn[i])+1)*sizeof(char)))) { - for (j=0; j<(i-1); j++) { - free(newitems[j]->name); - free(newitems[j]); - } - free(newitems[i]); - free(newitems); - return -ENOMEM; - } - strcpy(newitems[i]->name, sn[i]); - newitems[i]->gid = 0x0000; - newitems[i]->bid = i ? newitems[i-1]->bid : 0x0000; - do { - newitems[i]->bid += 0x0001; - for (cur=sess->ssi.items, j=0; ((cur) && (!j)); cur=cur->next) - if ((cur->bid == newitems[i]->bid) && ((cur->type == AIM_SSI_TYPE_PERMIT) || (cur->type == AIM_SSI_TYPE_DENY))) - j=1; - } while (j); - newitems[i]->type = type; - newitems[i]->data = NULL; - newitems[i]->next = i ? newitems[i-1] : NULL; - } - - /* Add the items to our list */ - newitems[0]->next = sess->ssi.items; - sess->ssi.items = newitems[num-1]; /* Send the add item SNAC */ - aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD); + if (i = aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD)) { + free(newitems); + return -i; + } /* Free the array of pointers to each of the new items */ free(newitems); /* Begin sending SSI SNACs */ - aim_ssi_dispatch(sess, conn); + if (!(i = aim_ssi_dispatch(sess, conn))) + return i; return 0; } +/** + * Move a buddy from one group to another group. This basically just deletes the + * buddy and re-adds it. + * + * @param sess The oscar session. + * @param conn The bos connection for this session. + * @param oldgn The group that the buddy is currently in. + * @param newgn The group that the buddy should be moved in to. + * @param sn The name of the buddy to be moved. + * @return Return 0 if no errors, otherwise return the error number. + */ faim_export int aim_ssi_movebuddy(aim_session_t *sess, aim_conn_t *conn, char *oldgn, char *newgn, char *sn) { struct aim_ssi_item **groups, *buddy, *cur; @@ -618,7 +699,7 @@ return -EINVAL; /* Look up the buddy */ - if (!(buddy = get_ssi_item(sess->ssi.items, sn, AIM_SSI_TYPE_BUDDY))) + if (!(buddy = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, sn, AIM_SSI_TYPE_BUDDY))) return -ENOMEM; /* Allocate an array of pointers to the two groups */ @@ -626,13 +707,13 @@ return -ENOMEM; /* Look up the old parent group */ - if (!(groups[0] = get_ssi_item(sess->ssi.items, oldgn, AIM_SSI_TYPE_GROUP))) { + if (!(groups[0] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, oldgn, AIM_SSI_TYPE_GROUP))) { free(groups); return -ENOMEM; } /* Look up the new parent group */ - if (!(groups[1] = get_ssi_item(sess->ssi.items, newgn, AIM_SSI_TYPE_GROUP))) { + if (!(groups[1] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, newgn, AIM_SSI_TYPE_GROUP))) { free(groups); return -ENOMEM; } @@ -653,8 +734,8 @@ } while (i); /* Rebuild the additional data in the two parent groups */ - aim_ssi_rebuildgroup(sess, conn, groups[0]); - aim_ssi_rebuildgroup(sess, conn, groups[1]); + aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, groups[0]); + aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, groups[1]); /* Send the add item SNAC */ aim_ssi_addmoddel(sess, conn, &buddy, 1, AIM_CB_SSI_ADD); @@ -671,6 +752,16 @@ return 0; } +/** + * Delete an array of screen names from the given group. + * + * @param sess The oscar session. + * @param conn The bos connection for this session. + * @param gn The name of the group from which you want to delete these names. + * @param sn An array of null terminated strings of the names you want to delete. + * @param num The number of screen names you are deleting (size of the sn array). + * @return Return 0 if no errors, otherwise return the error number. + */ faim_export int aim_ssi_delbuddies(aim_session_t *sess, aim_conn_t *conn, char *gn, char **sn, unsigned int num) { struct aim_ssi_item *cur, *parentgroup, **delitems; @@ -680,7 +771,7 @@ return -EINVAL; /* Look up the parent group */ - if (!(parentgroup = get_ssi_item(sess->ssi.items, gn, AIM_SSI_TYPE_GROUP))) + if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn, AIM_SSI_TYPE_GROUP))) return -EINVAL; /* Allocate an array of pointers to each of the items to be deleted */ @@ -689,7 +780,7 @@ /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */ for (i=0; i<num; i++) { - if (!(delitems[i] = get_ssi_item(sess->ssi.items, sn[i], AIM_SSI_TYPE_BUDDY))) { + if (!(delitems[i] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, sn[i], AIM_SSI_TYPE_BUDDY))) { free(delitems); return -EINVAL; } @@ -718,7 +809,7 @@ free(delitems); /* Rebuild the additional data in the parent group */ - aim_ssi_rebuildgroup(sess, conn, parentgroup); + aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup); /* Send the mod item SNAC */ aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD); @@ -733,14 +824,23 @@ return 0; } -faim_export int aim_ssi_delmastergroup(aim_session_t *sess, aim_conn_t *conn) { +/** + * Delete the master group from the item list. There can be only one. + * Er, so just find the one master group and delete it. + * + * @param sess The oscar session. + * @param conn The bos connection for this session. + * @return Return 0 if no errors, otherwise return the error number. + */ +faim_export int aim_ssi_delmastergroup(aim_session_t *sess, aim_conn_t *conn) +{ struct aim_ssi_item *cur, *delitem; if (!sess || !conn) return -EINVAL; /* Make delitem a pointer to the aim_ssi_item to be deleted */ - if (!(delitem = get_ssi_item(sess->ssi.items, NULL, AIM_SSI_TYPE_GROUP))) + if (!(delitem = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_GROUP))) return -EINVAL; /* Remove delitem from the item list */ @@ -768,6 +868,15 @@ return 0; } +/** + * Delete an array of groups. + * + * @param sess The oscar session. + * @param conn The bos connection for this session. + * @param gn An array of null terminated strings of the groups you want to delete. + * @param num The number of groups you are deleting (size of the gn array). + * @return Return 0 if no errors, otherwise return the error number. + */ faim_export int aim_ssi_delgroups(aim_session_t *sess, aim_conn_t *conn, char **gn, unsigned int num) { struct aim_ssi_item *cur, *parentgroup, **delitems; int i; @@ -776,7 +885,7 @@ return -EINVAL; /* Look up the parent group */ - if (!(parentgroup = get_ssi_item(sess->ssi.items, NULL, AIM_SSI_TYPE_GROUP))) + if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_GROUP))) return -EINVAL; /* Allocate an array of pointers to each of the items to be deleted */ @@ -785,7 +894,7 @@ /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */ for (i=0; i<num; i++) { - if (!(delitems[i] = get_ssi_item(sess->ssi.items, gn[i], AIM_SSI_TYPE_GROUP))) { + if (!(delitems[i] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn[i], AIM_SSI_TYPE_GROUP))) { free(delitems); return -EINVAL; } @@ -814,7 +923,7 @@ free(delitems); /* Rebuild the additional data in the parent group */ - aim_ssi_rebuildgroup(sess, conn, parentgroup); + aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup); /* Send the mod item SNAC */ aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD); @@ -829,6 +938,17 @@ return 0; } +/** + * Delete an array of a certain type of item from the list. This can be + * used for permit buddies, deny buddies, ICQ's ignore buddies, and + * probably other types, also. + * + * @param sess The oscar session. + * @param conn The bos connection for this session. + * @param sn An array of null terminated strings of the items you want to delete. + * @param num The number of items you are deleting (size of the sn array). + * @return Return 0 if no errors, otherwise return the error number. + */ faim_export int aim_ssi_delpord(aim_session_t *sess, aim_conn_t *conn, char **sn, unsigned int num, fu16_t type) { struct aim_ssi_item *cur, **delitems; int i; @@ -842,7 +962,7 @@ /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */ for (i=0; i<num; i++) { - if (!(delitems[i] = get_ssi_item(sess->ssi.items, sn[i], type))) { + if (!(delitems[i] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, sn[i], type))) { free(delitems); return -EINVAL; } @@ -876,17 +996,22 @@ return 0; } -/* +/** * Stores your permit/deny setting on the server, and starts using it. - * The permit/deny byte should be: - * 1 - Allow all users - * 2 - Block all users - * 3 - Allow only the users below - * 4 - Block the users below - * 5 - Allow only users on my buddy list - * To block AIM users, change the x00cb tlv from xffff to x0004 + * + * @param sess The oscar session. + * @param conn The bos connection for this session. + * @param permdeny Your permit/deny setting. Can be one of the following: + * 1 - Allow all users + * 2 - Block all users + * 3 - Allow only the users below + * 4 - Block only the users below + * 5 - Allow only users on my buddy list + * @param vismask A bitmask of the class of users to whom you want to be + * visible. See the AIM_FLAG_BLEH #defines in aim.h + * @return Return 0 if no errors, otherwise return the error number. */ -faim_export int aim_ssi_setpermdeny(aim_session_t *sess, aim_conn_t *conn, int permdeny) { +faim_export int aim_ssi_setpermdeny(aim_session_t *sess, aim_conn_t *conn, fu8_t permdeny, fu32_t vismask) { struct aim_ssi_item *cur, *tmp; fu16_t j; aim_tlv_t *tlv; @@ -895,7 +1020,7 @@ return -EINVAL; /* Look up the permit/deny settings item */ - cur = get_ssi_item(sess->ssi.items, NULL, AIM_SSI_TYPE_PDINFO); + cur = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_PDINFO); if (cur) { /* The permit/deny item exists */ @@ -912,31 +1037,27 @@ aim_addtlvtochain8((aim_tlvlist_t**)&cur->data, 0x00ca, permdeny); } + if (cur->data && (tlv = aim_gettlv(cur->data, 0x00cb, 1))) { + /* Just change the value of the x00cb TLV */ + if (tlv->length != 4) { + tlv->length = 4; + free(tlv->value); + tlv->value = (fu8_t *)malloc(4*sizeof(fu8_t)); + } + aimutil_put32(tlv->value, vismask); + } else { + /* Need to add the x00cb TLV to the TLV chain */ + aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00cb, vismask); + } + /* Send the mod item SNAC */ aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_MOD); } else { /* Need to add the permit/deny item */ - if (!(cur = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item)))) + if (!(cur = aim_ssi_itemlist_add(&sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_PDINFO))) return -ENOMEM; - cur->name = NULL; - cur->gid = 0x0000; - cur->bid = 0x007a; /* XXX - Is this number significant? */ - do { - cur->bid += 0x0001; - for (tmp=sess->ssi.items, j=0; ((tmp) && (!j)); tmp=tmp->next) - if (tmp->bid == cur->bid) - j=1; - } while (j); - cur->type = AIM_SSI_TYPE_PDINFO; - cur->data = NULL; aim_addtlvtochain8((aim_tlvlist_t**)&cur->data, 0x00ca, permdeny); - aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00cb, 0xffffffff); - - /* Add the item to our list */ - cur->next = sess->ssi.items; - sess->ssi.items = cur; - - /* Send the add item SNAC */ + aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00cb, vismask); aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_ADD); } @@ -946,10 +1067,14 @@ return 0; } -/* +/** * Stores your setting for whether you should show up as idle or not. - * presence is a bitmask (at least, I think so...) - * 0x00000400 if you want others to see your idle time + * + * @param sess The oscar session. + * @param conn The bos connection for this session. + * @param presence I think it's a bitmask, but I only know what one of the bits is: + * 0x00000400 - Allow others to see your idle time + * @return Return 0 if no errors, otherwise return the error number. */ faim_export int aim_ssi_setpresence(aim_session_t *sess, aim_conn_t *conn, fu32_t presence) { struct aim_ssi_item *cur, *tmp; @@ -960,7 +1085,7 @@ return -EINVAL; /* Look up the item */ - cur = get_ssi_item(sess->ssi.items, NULL, AIM_SSI_TYPE_PRESENCEPREFS); + cur = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS); if (cur) { /* The item exists */ @@ -981,26 +1106,9 @@ aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_MOD); } else { /* Need to add the item */ - if (!(cur = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item)))) + if (!(cur = aim_ssi_itemlist_add(&sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS))) return -ENOMEM; - cur->name = NULL; - cur->gid = 0x0000; - cur->bid = 0x007a; /* XXX - Is this number significant? */ - do { - cur->bid += 0x0001; - for (tmp=sess->ssi.items, j=0; ((tmp) && (!j)); tmp=tmp->next) - if (tmp->bid == cur->bid) - j=1; - } while (j); - cur->type = AIM_SSI_TYPE_PRESENCEPREFS; - cur->data = NULL; aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00c9, presence); - - /* Add the item to our list */ - cur->next = sess->ssi.items; - sess->ssi.items = cur; - - /* Send the add item SNAC */ aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_ADD); } @@ -1075,6 +1183,14 @@ fu16_t revision; fu32_t timestamp; + /* When you set the version for the SSI family to 2-4, the beginning of this changes. + * Instead of the version and then the revision, there is "0x0006" and then a type + * 0x0001 TLV containing the 2 byte SSI family version that you sent earlier. Also, + * the SNAC flags go from 0x0000 to 0x8000. I guess the 0x0006 is the length of the + * TLV(s) that follow. The rights SNAC does the same thing, with the differing flag + * and everything. + */ + fmtver = aimbs_get8(bs); /* Version of ssi data. Should be 0x00 */ revision = aimbs_get16(bs); /* # of times ssi data has been modified */ if (revision != 0)