📄 ssi.c
字号:
/* * 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. * * We keep 2 copies of SSI data: * 1) An exact copy of what is stored on the AIM servers. * 2) A local copy that we make changes to, and then send diffs * between this and the exact copy to keep them in sync. * * All the "aim_ssi_itemlist_bleh" functions near the top just modify the list * that is given to them (i.e. they don't send SNACs). * * 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. * */#define FAIM_INTERNAL#include <aim.h>/** * 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 name A null terminated string containing the group name, or NULL * if you want to modify the master group. * @return Return a pointer to the modified item. */static struct aim_ssi_item *aim_ssi_itemlist_rebuildgroup(struct aim_ssi_item *list, const char *name){ int newlen; struct aim_ssi_item *cur, *group; if (!list) return NULL; /* Find the group */ if (!(group = aim_ssi_itemlist_finditem(list, name, NULL, AIM_SSI_TYPE_GROUP))) return NULL; /* Find the length for the new additional data */ newlen = 0; if (group->gid == 0x0000) { for (cur=list; cur; cur=cur->next) if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid != 0x0000)) newlen += 2; } else { for (cur=list; cur; cur=cur->next) if ((cur->gid == group->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) newlen += 2; } /* Build the new TLV list */ if (newlen > 0) { fu8_t *newdata; if (!(newdata = (fu8_t *)malloc((newlen)*sizeof(fu8_t)))) return NULL; newlen = 0; if (group->gid == 0x0000) { for (cur=list; 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) if ((cur->gid == group->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) newlen += aimutil_put16(newdata+newlen, cur->bid); } aim_tlvlist_replace_raw(&group->data, 0x00c8, newlen, newdata); free(newdata); } return group;}/** * Locally add a new item to the given item list. * * @param list A pointer to a pointer to the current list of items. * @param name A null terminated string of the name of the new item, or NULL if the * item should have no name. * @param gid The group ID# you want the new item to have, or 0xFFFF if we should pick something. * @param bid The buddy ID# you want the new item to have, or 0xFFFF if we should pick something. * @param type The type of the item, 0x0000 for a contact, 0x0001 for a group, etc. * @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, fu16_t gid, fu16_t bid, fu16_t type, aim_tlvlist_t *data){ int i; struct aim_ssi_item *cur, *new; if (!list) return NULL; if (!(new = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item)))) return NULL; /* Set the name */ if (name) { new->name = (char *)malloc((strlen(name)+1)*sizeof(char)); strcpy(new->name, name); } else new->name = NULL; /* Set the group ID# and buddy ID# */ new->gid = gid; new->bid = bid; if (type == AIM_SSI_TYPE_GROUP) { if ((new->gid == 0xFFFF) && name) { do { new->gid += 0x0001; for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next) if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid == new->gid)) i=1; } while (i); } } else { if (new->bid == 0xFFFF) { do { new->bid += 0x0001; for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next) if ((cur->bid == new->bid) && (cur->gid == new->gid)) i=1; } while (i); } } /* Set the type */ new->type = type; /* 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; } 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); new->next = prev->next; prev->next = new; } } else { new->next = *list; *list = new; } return new;}/** * Locally delete an item from the given item list. * * @param list A pointer to a pointer to the current list of items. * @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){ if (!list || !(*list) || !del) return -EINVAL; /* Remove the item from the list */ if (*list == del) { *list = (*list)->next; } else { struct aim_ssi_item *cur; for (cur=*list; (cur->next && (cur->next!=del)); cur=cur->next); if (cur->next) cur->next = del->next; } /* Free the removed item */ free(del->name); aim_tlvlist_free(&del->data); free(del); return 0;}/** * Compare two items to see if they have the same data. * * @param cur1 A pointer to a pointer to the first item. * @param cur2 A pointer to a pointer to the second item. * @return Return 0 if no differences, or a number if there are differences. */static int aim_ssi_itemlist_cmp(struct aim_ssi_item *cur1, struct aim_ssi_item *cur2){ if (!cur1 || !cur2) return 1; if (cur1->data && !cur2->data) return 2; if (!cur1->data && cur2->data) return 3; if ((cur1->data && cur2->data) && (aim_tlvlist_cmp(cur1->data, cur2->data))) return 4; if (cur1->name && !cur2->name) return 5; if (!cur1->name && cur2->name) return 6; if (cur1->name && cur2->name && aim_sncmp(cur1->name, cur2->name)) return 7; if (cur1->gid != cur2->gid) return 8; if (cur1->bid != cur2->bid) return 9; if (cur1->type != cur2->type) return 10; return 0;}faim_export int aim_ssi_itemlist_valid(struct aim_ssi_item *list, struct aim_ssi_item *item){ struct aim_ssi_item *cur; for (cur=list; cur; cur=cur->next) if (cur == item) return 1; return 0;}/** * 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; */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; for (cur=list; cur; cur=cur->next) if ((cur->gid == gid) && (cur->bid == bid)) return cur; return NULL;}/** * 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 struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *sn, fu16_t type){ 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 (gn) { /* For finding groups */ for (cur=list; cur; cur=cur->next) { if ((cur->type == type) && (cur->bid == 0x0000) && (cur->name) && !(aim_sncmp(cur->name, gn))) { return cur; } } } else if (sn) { /* For finding 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) && (!cur->name)) return cur; } return NULL;}/** * Check if the given buddy exists in any group in the buddy list. * * @param list A pointer to the current list of items. * @param sn The group name of the desired item. * @return Return a pointer to the name of the item if found, else return NULL; */faim_export struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_item *list, const char *sn){ struct aim_ssi_item *cur; if (!list || !sn) return NULL; for (cur=list; cur; cur=cur->next) if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->name) && (!aim_sncmp(cur->name, sn))) 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 name of the item if found, else return NULL; */faim_export char *aim_ssi_itemlist_findparentname(struct aim_ssi_item *list, const char *sn){ struct aim_ssi_item *cur, *curg; if (!list || !sn) return NULL; if (!(cur = aim_ssi_itemlist_exists(list, sn))) return NULL; if (!(curg = aim_ssi_itemlist_find(list, cur->gid, 0x0000))) return NULL; return curg->name;}/** * 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_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x00ca, 1); if (tlv && tlv->value) return aimutil_get8(tlv->value); } return 0;}/** * 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(struct aim_ssi_item *list){ struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS); if (cur) { aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x00c9, 1); if (tlv && tlv->length) return aimutil_get32(tlv->value); } return 0xFFFFFFFF;}/** * Locally find the alias of the given buddy. * * @param list A pointer to the current list of items. * @param gn The group of the buddy. * @param sn The name of the buddy. * @return A pointer to a NULL terminated string that is the buddy's * alias, or NULL if the buddy has no alias. You should free * this returned value! */faim_export char *aim_ssi_getalias(struct aim_ssi_item *list, const char *gn, const char *sn){ struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY); if (cur) { aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x0131, 1); if (tlv && tlv->length) { char *alias = (char *)malloc((tlv->length+1)*sizeof(char)); strncpy(alias, tlv->value, tlv->length); alias[tlv->length] = 0; return alias; } } return NULL;}/** * Locally find the comment of the given buddy. * * @param list A pointer to the current list of items. * @param gn The group of the buddy. * @param sn The name of the buddy. * @return A pointer to a NULL terminated string that is the buddy's * comment, or NULL if the buddy has no comment. You should free * this returned value! */faim_export char *aim_ssi_getcomment(struct aim_ssi_item *list, const char *gn, const char *sn){ struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY); if (cur) { aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x013c, 1); if (tlv && tlv->length) { char *alias = (char *)malloc((tlv->length+1)*sizeof(char)); strncpy(alias, tlv->value, tlv->length); alias[tlv->length] = 0; return alias; } } return NULL;}/** * Locally find if you are waiting for authorization for a buddy. * * @param list A pointer to the current list of items. * @param gn The group of the buddy. * @param sn The name of the buddy. * @return A pointer to a NULL terminated string that is the buddies * alias, or NULL if the buddy has no alias. You should free * this returned value! */faim_export int aim_ssi_waitingforauth(struct aim_ssi_item *list, const char *gn, const char *sn){ struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY); if (cur) { if (aim_tlv_gettlv(cur->data, 0x0066, 1)) return 1; } return 0;}/** * If there are changes, then create temporary items and * call addmoddel. * * @param sess The oscar session. * @return Return 0 if no errors, otherwise return the error number. */static int aim_ssi_sync(aim_session_t *sess){ struct aim_ssi_item *cur1, *cur2; struct aim_ssi_tmp *cur, *new; if (!sess) return -EINVAL; /* If we're waiting for an ack, we shouldn't do anything else */ if (sess->ssi.waiting_for_ack) return 0; /* * Compare the 2 lists and create an aim_ssi_tmp for each difference. * We should only send either additions, modifications, or deletions * before waiting for an acknowledgement. So first do deletions, then * additions, then modifications. Also, both the official and the local * list should be in ascending numerical order for the group ID#s and the * buddy ID#s, which makes things more efficient. I think. */ /* Additions */ if (!sess->ssi.pending) { for (cur1=sess->ssi.local; cur1; cur1=cur1->next) { if (!aim_ssi_itemlist_find(sess->ssi.official, cur1->gid, cur1->bid)) { new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp)); new->action = AIM_CB_SSI_ADD; new->ack = 0xffff; new->name = NULL; new->item = cur1; new->next = NULL; if (sess->ssi.pending) { for (cur=sess->ssi.pending; cur->next; cur=cur->next); cur->next = new;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -