📄 family_feedbag.c
字号:
/* * Purple's oscar protocol plugin * This file is the legal property of its developers. * Please see the AUTHORS file distributed alongside this file. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*//* * 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. * */#include "oscar.h"static int aim_ssi_addmoddel(OscarData *od);/** * 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 voidaim_ssi_itemlist_rebuildgroup(struct aim_ssi_item *list, const char *name){ int newlen; struct aim_ssi_item *cur, *group; /* Find the group */ if (!(group = aim_ssi_itemlist_finditem(list, name, NULL, AIM_SSI_TYPE_GROUP))) return; /* 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) { guint8 *newdata; newdata = (guint8 *)g_malloc((newlen)*sizeof(guint8)); 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); g_free(newdata); }}/** * 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, guint16 gid, guint16 bid, guint16 type, GSList *data){ gboolean exists; struct aim_ssi_item *cur, *new; new = (struct aim_ssi_item *)g_malloc(sizeof(struct aim_ssi_item)); /* Set the name */ if (name) { new->name = (char *)g_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; exists = FALSE; for (cur = *list; cur != NULL; cur = cur->next) if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid == new->gid)) { exists = TRUE; break; } } while (exists); } } else if (type == AIM_SSI_TYPE_ICONINFO) { if (new->bid == 0xFFFF) { do { new->bid += 0x0001; exists = FALSE; for (cur = *list; cur != NULL; cur = cur->next) if ((cur->bid >= new->bid) || (cur->gid >= new->bid)) { exists = TRUE; break; } } while (exists); } } else { if (new->bid == 0xFFFF) { do { new->bid += 0x0001; exists = FALSE; for (cur = *list; cur != NULL; cur = cur->next) if ((cur->bid == new->bid) && (cur->gid == new->gid)) { exists = TRUE; break; } } while (exists); } } /* 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) || !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 */ g_free(del->name); aim_tlvlist_free(del->data); g_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;}static gboolean 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 TRUE; return FALSE;}/** * 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; */struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *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;}/** * 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. */struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *sn, guint16 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; */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; */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. */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 oscar.h * * @param list A pointer to the current list of items. * @return Return the current visibility mask. */guint32 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! */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) return g_strndup((const gchar *)tlv->value, tlv->length); } 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! */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) { return g_strndup((const gchar *)tlv->value, tlv->length); } } 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 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 *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 TRUE; } return FALSE;}/** * If there are changes, then create temporary items and * call addmoddel. * * @param od The oscar session. * @return Return 0 if no errors, otherwise return the error number. */static int aim_ssi_sync(OscarData *od){ struct aim_ssi_item *cur1, *cur2; struct aim_ssi_tmp *cur, *new; int n = 0; /* * The variable "n" is used to limit the number of addmoddel's that * are performed in a single SNAC. It will hopefully keep the size * of the SNAC below the maximum SNAC size. */ if (!od) return -EINVAL; /* If we're waiting for an ack, we shouldn't do anything else */ if (od->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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -