Changeset cf02dd6 for libfaim/ssi.c


Ignore:
Timestamp:
Dec 10, 2003, 3:20:45 PM (17 years ago)
Author:
James M. Kretchmar <kretch@mit.edu>
Branches:
master, barnowl_perlaim, debian, owl, release-1.4, release-1.5, release-1.6, release-1.7, release-1.8, release-1.9
Children:
b1fe407
Parents:
8c46404
Message:
*** empty log message ***
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libfaim/ssi.c

    ra0a5179 rcf02dd6  
    2222 * You don't know the half of it.
    2323 *
    24  * XXX - Preserve unknown data in TLV lists
    25  *
    2624 */
    2725
     
    3937static struct aim_ssi_item *aim_ssi_itemlist_rebuildgroup(struct aim_ssi_item *list, const char *name)
    4038{
    41   int newlen;
    42   struct aim_ssi_item *cur, *group;
    43 
    44   owl_function_debugmsg("aim_ssi_itemlist_rebuildgroup: in for group %s", name?name:"NULL");
    45  
    46   if (!list) return(NULL);
    47  
    48   /* Find the group */
    49   if (!(group = aim_ssi_itemlist_finditem(list, name, NULL, AIM_SSI_TYPE_GROUP))) return(NULL);
    50  
    51   /* Free the old data */
    52   aim_freetlvchain(&group->data);
    53   group->data = NULL;
    54  
    55   /* Find the length for the new additional data */
    56   newlen = 0;
    57   if (group->gid == 0x0000) {
    58     for (cur=list; cur; cur=cur->next)
    59       if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid != 0x0000))
    60         newlen += 2;
    61   } else {
    62     for (cur=list; cur; cur=cur->next)
    63       if ((cur->gid == group->gid) && (cur->type == AIM_SSI_TYPE_BUDDY))
    64         newlen += 2;
    65   }
    66   owl_function_debugmsg("aim_ssi_itemlist_rebuildgroup: newlen is %i", newlen);
    67  
    68   /* Build the new TLV list */
    69   if (newlen > 0) {
    70     fu8_t *newdata;
    71    
    72     if (!(newdata = (fu8_t *)malloc((newlen)*sizeof(fu8_t)))) return NULL;
    73     newlen = 0;
    74     if (group->gid == 0x0000) {
    75       for (cur=list; cur; cur=cur->next)
    76         if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid != 0x0000))
    77           newlen += aimutil_put16(newdata+newlen, cur->gid);
    78     } else {
    79       for (cur=list; cur; cur=cur->next)
    80         if ((cur->gid == group->gid) && (cur->type == AIM_SSI_TYPE_BUDDY))
    81           newlen += aimutil_put16(newdata+newlen, cur->bid);
    82     }
    83     aim_addtlvtochain_raw(&group->data, 0x00c8, newlen, newdata);
    84    
    85     free(newdata);
    86   }
    87 
    88   owl_function_debugmsg("aim_ssi_itemlist_rebuildgroup: exiting");
    89   return group;
     39        int newlen;
     40        struct aim_ssi_item *cur, *group;
     41
     42        if (!list)
     43                return NULL;
     44
     45        /* Find the group */
     46        if (!(group = aim_ssi_itemlist_finditem(list, name, NULL, AIM_SSI_TYPE_GROUP)))
     47                return NULL;
     48
     49        /* Find the length for the new additional data */
     50        newlen = 0;
     51        if (group->gid == 0x0000) {
     52                for (cur=list; cur; cur=cur->next)
     53                        if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid != 0x0000))
     54                                newlen += 2;
     55        } else {
     56                for (cur=list; cur; cur=cur->next)
     57                        if ((cur->gid == group->gid) && (cur->type == AIM_SSI_TYPE_BUDDY))
     58                                newlen += 2;
     59        }
     60
     61        /* Build the new TLV list */
     62        if (newlen > 0) {
     63                fu8_t *newdata;
     64
     65                if (!(newdata = (fu8_t *)malloc((newlen)*sizeof(fu8_t))))
     66                        return NULL;
     67                newlen = 0;
     68                if (group->gid == 0x0000) {
     69                        for (cur=list; cur; cur=cur->next)
     70                                if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid != 0x0000))
     71                                                newlen += aimutil_put16(newdata+newlen, cur->gid);
     72                } else {
     73                        for (cur=list; cur; cur=cur->next)
     74                                if ((cur->gid == group->gid) && (cur->type == AIM_SSI_TYPE_BUDDY))
     75                                                newlen += aimutil_put16(newdata+newlen, cur->bid);
     76                }
     77                aim_tlvlist_replace_raw(&group->data, 0x00c8, newlen, newdata);
     78
     79                free(newdata);
     80        }
     81
     82        return group;
    9083}
    9184
     
    10497static 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)
    10598{
    106   int i;
    107   struct aim_ssi_item *cur, *new;
    108  
    109   if (!list) return(NULL);
    110  
    111   if (!(new = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item)))) return(NULL);
    112  
    113   /* Set the name */
    114   if (name) {
    115     new->name = (char *)malloc((strlen(name)+1)*sizeof(char));
    116     strcpy(new->name, name);
    117   } else {
    118     new->name = NULL;
    119   }
    120  
    121   /* Set the group ID# and buddy ID# */
    122   new->gid = gid;
    123   new->bid = bid;
    124   if (type == AIM_SSI_TYPE_GROUP) {
    125     if ((new->gid == 0xFFFF) && name) {
    126       do {
    127         new->gid += 0x0001;
    128         for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next)
    129           if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid == new->gid))
    130             i=1;
    131       } while (i);
    132     }
    133   } else {
    134     if (new->bid == 0xFFFF) {
    135       do {
    136         new->bid += 0x0001;
    137         for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next)
    138           if ((cur->bid == new->bid) && (cur->gid == new->gid))
    139             i=1;
    140       } while (i);
    141     }
    142   }
    143  
    144   /* Set the type */
    145   new->type = type;
    146  
    147   /* Set the TLV list */
    148   new->data = aim_tlvlist_copy(data);
    149  
    150   /* Add the item to the list in the correct numerical position.  Fancy, eh? */
    151   if (*list) {
    152     if ((new->gid < (*list)->gid) || ((new->gid == (*list)->gid) && (new->bid < (*list)->bid))) {
    153       new->next = *list;
    154       *list = new;
    155     } else {
    156       struct aim_ssi_item *prev;
    157       for ((prev=*list, cur=(*list)->next); (cur && ((new->gid > cur->gid) || ((new->gid == cur->gid) && (new->bid > cur->bid)))); prev=cur, cur=cur->next);
    158       new->next = prev->next;
    159       prev->next = new;
    160     }
    161   } else {
    162     new->next = *list;
    163     *list = new;
    164   }
    165 
    166   return(new);
     99        int i;
     100        struct aim_ssi_item *cur, *new;
     101
     102        if (!list)
     103                return NULL;
     104
     105        if (!(new = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item))))
     106                return NULL;
     107
     108        /* Set the name */
     109        if (name) {
     110                new->name = (char *)malloc((strlen(name)+1)*sizeof(char));
     111                strcpy(new->name, name);
     112        } else
     113                new->name = NULL;
     114
     115        /* Set the group ID# and buddy ID# */
     116        new->gid = gid;
     117        new->bid = bid;
     118        if (type == AIM_SSI_TYPE_GROUP) {
     119                if ((new->gid == 0xFFFF) && name) {
     120                        do {
     121                                new->gid += 0x0001;
     122                                for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next)
     123                                        if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid == new->gid))
     124                                                i=1;
     125                        } while (i);
     126                }
     127        } else {
     128                if (new->bid == 0xFFFF) {
     129                        do {
     130                                new->bid += 0x0001;
     131                                for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next)
     132                                        if ((cur->bid == new->bid) && (cur->gid == new->gid))
     133                                                i=1;
     134                        } while (i);
     135                }
     136        }
     137
     138        /* Set the type */
     139        new->type = type;
     140
     141        /* Set the TLV list */
     142        new->data = aim_tlvlist_copy(data);
     143
     144        /* Add the item to the list in the correct numerical position.  Fancy, eh? */
     145        if (*list) {
     146                if ((new->gid < (*list)->gid) || ((new->gid == (*list)->gid) && (new->bid < (*list)->bid))) {
     147                        new->next = *list;
     148                        *list = new;
     149                } else {
     150                        struct aim_ssi_item *prev;
     151                        for ((prev=*list, cur=(*list)->next); (cur && ((new->gid > cur->gid) || ((new->gid == cur->gid) && (new->bid > cur->bid)))); prev=cur, cur=cur->next);
     152                        new->next = prev->next;
     153                        prev->next = new;
     154                }
     155        } else {
     156                new->next = *list;
     157                *list = new;
     158        }
     159
     160        return new;
    167161}
    168162
     
    176170static int aim_ssi_itemlist_del(struct aim_ssi_item **list, struct aim_ssi_item *del)
    177171{
    178   if (!list || !(*list) || !del) return -EINVAL;
    179 
    180   owl_function_debugmsg("aim_ssi_itemlist_del: in");
    181   /* Remove the item from the list */
    182   if (*list == del) {
    183     *list = (*list)->next;
    184     owl_function_debugmsg("aim_ssi_itemlist_del: deleted %s from beginning of list", del->name);
    185   } else {
    186     struct aim_ssi_item *cur;
    187     for (cur=*list; (cur->next && (cur->next!=del)); cur=cur->next);
    188     if (cur->next) cur->next=cur->next->next;
    189     owl_function_debugmsg("aim_ssi_itemlist_del: deleted %s from middle of list", del->name);
    190   }
    191 
    192   /* Free the deleted item */
    193   owl_function_debugmsg("aim_ssi_itemlist_del: freeing");
    194   free(del->name);
    195   aim_freetlvchain(&del->data);
    196   free(del);
    197 
    198   return(0);
     172        if (!list || !(*list) || !del)
     173                return -EINVAL;
     174
     175        /* Remove the item from the list */
     176        if (*list == del) {
     177                *list = (*list)->next;
     178        } else {
     179                struct aim_ssi_item *cur;
     180                for (cur=*list; (cur->next && (cur->next!=del)); cur=cur->next);
     181                if (cur->next)
     182                        cur->next = del->next;
     183        }
     184
     185        /* Free the removed item */
     186        free(del->name);
     187        aim_tlvlist_free(&del->data);
     188        free(del);
     189
     190        return 0;
    199191}
    200192
     
    208200static int aim_ssi_itemlist_cmp(struct aim_ssi_item *cur1, struct aim_ssi_item *cur2)
    209201{
    210   if (!cur1 || !cur2)
    211     return 1;
    212  
    213   if (cur1->data && !cur2->data)
    214     return 2;
    215  
    216   if (!cur1->data && cur2->data)
    217     return 3;
    218  
    219   if ((cur1->data && cur2->data) && (aim_tlvlist_cmp(cur1->data, cur2->data)))
    220     return 4;
    221  
    222   if (cur1->name && !cur2->name)
    223     return 5;
    224  
    225   if (!cur1->name && cur2->name)
    226     return 6;
    227  
    228   if (cur1->name && cur2->name && aim_sncmp(cur1->name, cur2->name))
    229     return 7;
    230  
    231   if (cur1->gid != cur2->gid)
    232     return 8;
    233  
    234   if (cur1->bid != cur2->bid)
    235     return 9;
    236  
    237   if (cur1->type != cur2->type)
    238     return 10;
    239  
    240   return 0;
     202        if (!cur1 || !cur2)
     203                return 1;
     204
     205        if (cur1->data && !cur2->data)
     206                return 2;
     207
     208        if (!cur1->data && cur2->data)
     209                return 3;
     210
     211        if ((cur1->data && cur2->data) && (aim_tlvlist_cmp(cur1->data, cur2->data)))
     212                        return 4;
     213
     214        if (cur1->name && !cur2->name)
     215                return 5;
     216
     217        if (!cur1->name && cur2->name)
     218                return 6;
     219
     220        if (cur1->name && cur2->name && aim_sncmp(cur1->name, cur2->name))
     221                return 7;
     222
     223        if (cur1->gid != cur2->gid)
     224                return 8;
     225
     226        if (cur1->bid != cur2->bid)
     227                return 9;
     228
     229        if (cur1->type != cur2->type)
     230                return 10;
     231
     232        return 0;
    241233}
    242234
    243235faim_export int aim_ssi_itemlist_valid(struct aim_ssi_item *list, struct aim_ssi_item *item)
    244236{
    245   struct aim_ssi_item *cur;
    246   for (cur=list; cur; cur=cur->next)
    247     if (cur == item)
    248       return 1;
    249   return 0;
     237        struct aim_ssi_item *cur;
     238        for (cur=list; cur; cur=cur->next)
     239                if (cur == item)
     240                        return 1;
     241        return 0;
    250242}
    251243
     
    260252faim_export struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, fu16_t gid, fu16_t bid)
    261253{
    262   struct aim_ssi_item *cur;
    263   for (cur=list; cur; cur=cur->next)
    264     if ((cur->gid == gid) && (cur->bid == bid))
    265       return cur;
    266   return NULL;
     254        struct aim_ssi_item *cur;
     255        for (cur=list; cur; cur=cur->next)
     256                if ((cur->gid == gid) && (cur->bid == bid))
     257                        return cur;
     258        return NULL;
    267259}
    268260
     
    279271faim_export struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *sn, fu16_t type)
    280272{
    281   struct aim_ssi_item *cur;
    282   if (!list)
    283     return NULL;
    284  
    285   if (gn && sn) { /* For finding buddies in groups */
    286     for (cur=list; cur; cur=cur->next)
    287       if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, sn))) {
    288         struct aim_ssi_item *curg;
    289         for (curg=list; curg; curg=curg->next)
    290           if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid) && (curg->name) && !(aim_sncmp(curg->name, gn)))
    291             return cur;
    292       }
    293    
    294   } else if (gn) { /* For finding groups */
    295     for (cur=list; cur; cur=cur->next) {
    296       if ((cur->type == type) && (cur->bid == 0x0000) && (cur->name) && !(aim_sncmp(cur->name, gn))) {
    297         return cur;
    298       }
    299     }
    300    
    301   } else if (sn) { /* For finding permits, denies, and ignores */
    302     for (cur=list; cur; cur=cur->next) {
    303       if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, sn))) {
    304         return cur;
    305       }
    306     }
    307    
    308     /* For stuff without names--permit deny setting, visibility mask, etc. */
    309   } else for (cur=list; cur; cur=cur->next) {
    310     if ((cur->type == type) && (!cur->name))
    311       return cur;
    312   }
    313  
    314   return NULL;
     273        struct aim_ssi_item *cur;
     274        if (!list)
     275                return NULL;
     276
     277        if (gn && sn) { /* For finding buddies in groups */
     278                for (cur=list; cur; cur=cur->next)
     279                        if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, sn))) {
     280                                struct aim_ssi_item *curg;
     281                                for (curg=list; curg; curg=curg->next)
     282                                        if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid) && (curg->name) && !(aim_sncmp(curg->name, gn)))
     283                                                return cur;
     284                        }
     285
     286        } else if (gn) { /* For finding groups */
     287                for (cur=list; cur; cur=cur->next) {
     288                        if ((cur->type == type) && (cur->bid == 0x0000) && (cur->name) && !(aim_sncmp(cur->name, gn))) {
     289                                return cur;
     290                        }
     291                }
     292
     293        } else if (sn) { /* For finding permits, denies, and ignores */
     294                for (cur=list; cur; cur=cur->next) {
     295                        if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, sn))) {
     296                                return cur;
     297                        }
     298                }
     299
     300        /* For stuff without names--permit deny setting, visibility mask, etc. */
     301        } else for (cur=list; cur; cur=cur->next) {
     302                if ((cur->type == type) && (!cur->name))
     303                        return cur;
     304        }
     305
     306        return NULL;
    315307}
    316308
     
    324316faim_export struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_item *list, const char *sn)
    325317{
    326   struct aim_ssi_item *cur;
    327   if (!list || !sn)
    328     return NULL;
    329   for (cur=list; cur; cur=cur->next)
    330     if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->name) && (!aim_sncmp(cur->name, sn)))
    331       return cur;
    332   return NULL;
     318        struct aim_ssi_item *cur;
     319        if (!list || !sn)
     320                return NULL;
     321        for (cur=list; cur; cur=cur->next)
     322                if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->name) && (!aim_sncmp(cur->name, sn)))
     323                        return cur;
     324        return NULL;
    333325}
    334326
     
    342334faim_export char *aim_ssi_itemlist_findparentname(struct aim_ssi_item *list, const char *sn)
    343335{
    344   struct aim_ssi_item *cur, *curg;
    345   if (!list || !sn)
    346     return NULL;
    347   if (!(cur = aim_ssi_itemlist_exists(list, sn)))
    348     return NULL;
    349   if (!(curg = aim_ssi_itemlist_find(list, cur->gid, 0x0000)))
    350     return NULL;
    351   return curg->name;
     336        struct aim_ssi_item *cur, *curg;
     337        if (!list || !sn)
     338                return NULL;
     339        if (!(cur = aim_ssi_itemlist_exists(list, sn)))
     340                return NULL;
     341        if (!(curg = aim_ssi_itemlist_find(list, cur->gid, 0x0000)))
     342                return NULL;
     343        return curg->name;
    352344}
    353345
     
    360352faim_export int aim_ssi_getpermdeny(struct aim_ssi_item *list)
    361353{
    362   struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PDINFO);
    363   if (cur) {
    364     aim_tlvlist_t *tlvlist = cur->data;
    365     if (tlvlist) {
    366       aim_tlv_t *tlv = aim_gettlv(tlvlist, 0x00ca, 1);
    367       if (tlv && tlv->value)
    368         return aimutil_get8(tlv->value);
    369     }
    370   }
    371   return 0;
     354        struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PDINFO);
     355        if (cur) {
     356                aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x00ca, 1);
     357                if (tlv && tlv->value)
     358                        return aimutil_get8(tlv->value);
     359        }
     360        return 0;
    372361}
    373362
     
    382371faim_export fu32_t aim_ssi_getpresence(struct aim_ssi_item *list)
    383372{
    384   struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS);
    385   if (cur) {
    386     aim_tlvlist_t *tlvlist = cur->data;
    387     if (tlvlist) {
    388       aim_tlv_t *tlv = aim_gettlv(tlvlist, 0x00c9, 1);
    389       if (tlv && tlv->length)
    390         return aimutil_get32(tlv->value);
    391     }
    392   }
    393   return 0xFFFFFFFF;
     373        struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS);
     374        if (cur) {
     375                aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x00c9, 1);
     376                if (tlv && tlv->length)
     377                        return aimutil_get32(tlv->value);
     378        }
     379        return 0xFFFFFFFF;
    394380}
    395381
    396382/**
    397383 * Locally find the alias of the given buddy.
     384 *
     385 * @param list A pointer to the current list of items.
     386 * @param gn The group of the buddy.
     387 * @param sn The name of the buddy.
     388 * @return A pointer to a NULL terminated string that is the buddy's
     389 *         alias, or NULL if the buddy has no alias.  You should free
     390 *         this returned value!
     391 */
     392faim_export char *aim_ssi_getalias(struct aim_ssi_item *list, const char *gn, const char *sn)
     393{
     394        struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY);
     395        if (cur) {
     396                aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x0131, 1);
     397                if (tlv && tlv->length) {
     398                        char *alias = (char *)malloc((tlv->length+1)*sizeof(char));
     399                        strncpy(alias, tlv->value, tlv->length);
     400                        alias[tlv->length] = 0;
     401                        return alias;
     402                }
     403        }
     404        return NULL;
     405}
     406
     407/**
     408 * Locally find the comment of the given buddy.
     409 *
     410 * @param list A pointer to the current list of items.
     411 * @param gn The group of the buddy.
     412 * @param sn The name of the buddy.
     413 * @return A pointer to a NULL terminated string that is the buddy's
     414 *         comment, or NULL if the buddy has no comment.  You should free
     415 *         this returned value!
     416 */
     417faim_export char *aim_ssi_getcomment(struct aim_ssi_item *list, const char *gn, const char *sn)
     418{
     419        struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY);
     420        if (cur) {
     421                aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x013c, 1);
     422                if (tlv && tlv->length) {
     423                        char *alias = (char *)malloc((tlv->length+1)*sizeof(char));
     424                        strncpy(alias, tlv->value, tlv->length);
     425                        alias[tlv->length] = 0;
     426                        return alias;
     427                }
     428        }
     429        return NULL;
     430}
     431
     432/**
     433 * Locally find if you are waiting for authorization for a buddy.
    398434 *
    399435 * @param list A pointer to the current list of items.
     
    404440 *         this returned value!
    405441 */
    406 faim_export char *aim_ssi_getalias(struct aim_ssi_item *list, const char *gn, const char *sn)
    407 {
    408   struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY);
    409   if (cur) {
    410     aim_tlvlist_t *tlvlist = cur->data;
    411     if (tlvlist) {
    412       aim_tlv_t *tlv = aim_gettlv(tlvlist, 0x0131, 1);
    413       if (tlv && tlv->length) {
    414         char *alias = (char *)malloc((tlv->length+1)*sizeof(char));
    415         strncpy(alias, tlv->value, tlv->length);
    416         alias[tlv->length] = 0;
    417         return alias;
    418       }
    419     }
    420   }
    421   return NULL;
    422 }
    423 
    424 /**
    425  * Locally find if you are waiting for authorization for a buddy.
    426  *
    427  * @param list A pointer to the current list of items.
    428  * @param gn The group of the buddy.
    429  * @param sn The name of the buddy.
    430  * @return A pointer to a NULL terminated string that is the buddies
    431  *         alias, or NULL if the buddy has no alias.  You should free
    432  *         this returned value!
    433  */
    434442faim_export int aim_ssi_waitingforauth(struct aim_ssi_item *list, const char *gn, const char *sn)
    435443{
    436   struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY);
    437   if (cur) {
    438     aim_tlvlist_t *tlvlist = cur->data;
    439     if (tlvlist)
    440       if (aim_gettlv(tlvlist, 0x0066, 1))
    441         return 1;
    442   }
    443   return 0;
     444        struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY);
     445        if (cur) {
     446                if (aim_tlv_gettlv(cur->data, 0x0066, 1))
     447                        return 1;
     448        }
     449        return 0;
    444450}
    445451
     
    453459static int aim_ssi_sync(aim_session_t *sess)
    454460{
    455   struct aim_ssi_item *cur1, *cur2;
    456   struct aim_ssi_tmp *cur, *new;
    457 
    458   owl_function_debugmsg("aim_ssi_sync: beginning");
    459  
    460   if (!sess) return (-EINVAL);
    461 
    462   /* If we're waiting for an ack, we shouldn't do anything else */
    463   if (sess->ssi.waiting_for_ack) {
    464     owl_function_debugmsg("Aborting aim_ssi_sync, waiting for ack");
    465     return 0;
    466   }
    467  
    468   /*
    469    * Compare the 2 lists and create an aim_ssi_tmp for each difference. 
    470    * We should only send either additions, modifications, or deletions
    471    * before waiting for an acknowledgement.  So first do deletions, then
    472    * additions, then modifications.  Also, both the official and the local
    473    * list should be in ascending numerical order for the group ID#s and the
    474    * buddy ID#s, which makes things more efficient.  I think.
    475    */
    476 
    477   /* Additions */
    478   if (!sess->ssi.pending) {
    479     for (cur1=sess->ssi.local; cur1; cur1=cur1->next) {
    480       if (!aim_ssi_itemlist_find(sess->ssi.official, cur1->gid, cur1->bid)) {
    481         owl_function_debugmsg("aim_ssi_sync: doing addition");
    482         new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp));
    483         new->action = AIM_CB_SSI_ADD;
    484         new->ack = 0xffff;
    485         new->name = NULL;
    486         new->item = cur1;
    487         new->next = NULL;
    488         if (sess->ssi.pending) {
    489           for (cur=sess->ssi.pending; cur->next; cur=cur->next);
    490           cur->next = new;
    491         } else
    492           sess->ssi.pending = new;
    493       }
    494     }
    495   }
    496  
    497   /* Deletions */
    498   if (!sess->ssi.pending) {
    499     for (cur1=sess->ssi.official; cur1; cur1=cur1->next) {
    500       if (!aim_ssi_itemlist_find(sess->ssi.local, cur1->gid, cur1->bid)) {
    501         owl_function_debugmsg("aim_ssi_sync: doing deletion");
    502         new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp));
    503         new->action = AIM_CB_SSI_DEL;
    504         new->ack = 0xffff;
    505         new->name = NULL;
    506         new->item = cur1;
    507         new->next = NULL;
    508         if (sess->ssi.pending) {
    509           for (cur=sess->ssi.pending; cur->next; cur=cur->next);
    510           cur->next = new;
    511         } else
    512           sess->ssi.pending = new;
    513       }
    514     }
    515   }
    516  
    517   /* Modifications */
    518   if (!sess->ssi.pending) {
    519     for (cur1=sess->ssi.local; cur1; cur1=cur1->next) {
    520       cur2 = aim_ssi_itemlist_find(sess->ssi.official, cur1->gid, cur1->bid);
    521       if (cur2 && (aim_ssi_itemlist_cmp(cur1, cur2))) {
    522         owl_function_debugmsg("aim_ssi_sync: doing modification");
    523         new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp));
    524         new->action = AIM_CB_SSI_MOD;
    525         new->ack = 0xffff;
    526         new->name = NULL;
    527         new->item = cur1;
    528         new->next = NULL;
    529         if (sess->ssi.pending) {
    530           for (cur=sess->ssi.pending; cur->next; cur=cur->next);
    531           cur->next = new;
    532         } else
    533           sess->ssi.pending = new;
    534       }
    535     }
    536   }
    537  
    538   /* We're out of stuff to do, so tell the AIM servers we're done and exit */
    539   if (!sess->ssi.pending) {
    540     owl_function_debugmsg("aim_ssi_sync: telling server we're done modifying SSI data.");
    541     aim_ssi_modend(sess);
    542     return 0;
    543   }
    544  
    545   /* Make sure we don't send anything else between now
    546    * and when we receive the ack for the following operation */
    547   owl_function_debugmsg("aim_ssi_sync: setting SSI waiting_for_ack");
    548   sess->ssi.waiting_for_ack = 1;
    549  
    550   /* Now go mail off our data and wait 4 to 6 weeks */
    551   owl_function_debugmsg("aim_ssi_sync: about to call addmoddel to send SNACs to server");
    552   aim_ssi_addmoddel(sess);
    553  
    554   return 0;
     461        struct aim_ssi_item *cur1, *cur2;
     462        struct aim_ssi_tmp *cur, *new;
     463
     464        if (!sess)
     465                return -EINVAL;
     466
     467        /* If we're waiting for an ack, we shouldn't do anything else */
     468        if (sess->ssi.waiting_for_ack)
     469                return 0;
     470
     471        /*
     472         * Compare the 2 lists and create an aim_ssi_tmp for each difference. 
     473         * We should only send either additions, modifications, or deletions
     474         * before waiting for an acknowledgement.  So first do deletions, then
     475         * additions, then modifications.  Also, both the official and the local
     476         * list should be in ascending numerical order for the group ID#s and the
     477         * buddy ID#s, which makes things more efficient.  I think.
     478         */
     479
     480        /* Additions */
     481        if (!sess->ssi.pending) {
     482                for (cur1=sess->ssi.local; cur1; cur1=cur1->next) {
     483                        if (!aim_ssi_itemlist_find(sess->ssi.official, cur1->gid, cur1->bid)) {
     484                                new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp));
     485                                new->action = AIM_CB_SSI_ADD;
     486                                new->ack = 0xffff;
     487                                new->name = NULL;
     488                                new->item = cur1;
     489                                new->next = NULL;
     490                                if (sess->ssi.pending) {
     491                                        for (cur=sess->ssi.pending; cur->next; cur=cur->next);
     492                                        cur->next = new;
     493                                } else
     494                                        sess->ssi.pending = new;
     495                        }
     496                }
     497        }
     498
     499        /* Deletions */
     500        if (!sess->ssi.pending) {
     501                for (cur1=sess->ssi.official; cur1; cur1=cur1->next) {
     502                        if (!aim_ssi_itemlist_find(sess->ssi.local, cur1->gid, cur1->bid)) {
     503                                new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp));
     504                                new->action = AIM_CB_SSI_DEL;
     505                                new->ack = 0xffff;
     506                                new->name = NULL;
     507                                new->item = cur1;
     508                                new->next = NULL;
     509                                if (sess->ssi.pending) {
     510                                        for (cur=sess->ssi.pending; cur->next; cur=cur->next);
     511                                        cur->next = new;
     512                                } else
     513                                        sess->ssi.pending = new;
     514                        }
     515                }
     516        }
     517
     518        /* Modifications */
     519        if (!sess->ssi.pending) {
     520                for (cur1=sess->ssi.local; cur1; cur1=cur1->next) {
     521                        cur2 = aim_ssi_itemlist_find(sess->ssi.official, cur1->gid, cur1->bid);
     522                        if (cur2 && (aim_ssi_itemlist_cmp(cur1, cur2))) {
     523                                new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp));
     524                                new->action = AIM_CB_SSI_MOD;
     525                                new->ack = 0xffff;
     526                                new->name = NULL;
     527                                new->item = cur1;
     528                                new->next = NULL;
     529                                if (sess->ssi.pending) {
     530                                        for (cur=sess->ssi.pending; cur->next; cur=cur->next);
     531                                        cur->next = new;
     532                                } else
     533                                        sess->ssi.pending = new;
     534                        }
     535                }
     536        }
     537
     538        /* We're out of stuff to do, so tell the AIM servers we're done and exit */
     539        if (!sess->ssi.pending) {
     540                aim_ssi_modend(sess);
     541                return 0;
     542        }
     543
     544        /* Make sure we don't send anything else between now
     545         * and when we receive the ack for the following operation */
     546        sess->ssi.waiting_for_ack = 1;
     547
     548        /* Now go mail off our data and wait 4 to 6 weeks */
     549        aim_ssi_addmoddel(sess);
     550
     551        return 0;
    555552}
    556553
     
    565562static int aim_ssi_freelist(aim_session_t *sess)
    566563{
    567   struct aim_ssi_item *cur, *del;
    568   struct aim_ssi_tmp *curtmp, *deltmp;
    569  
    570   cur = sess->ssi.official;
    571   while (cur) {
    572     del = cur;
    573     cur = cur->next;
    574     free(del->name);
    575     aim_freetlvchain(&del->data);
    576     free(del);
    577   }
    578  
    579   cur = sess->ssi.local;
    580   while (cur) {
    581     del = cur;
    582     cur = cur->next;
    583     free(del->name);
    584     aim_freetlvchain(&del->data);
    585     free(del);
    586   }
    587  
    588   curtmp = sess->ssi.pending;
    589   while (curtmp) {
    590     deltmp = curtmp;
    591     curtmp = curtmp->next;
    592     free(deltmp);
    593   }
    594  
    595   sess->ssi.numitems = 0;
    596   sess->ssi.official = NULL;
    597   sess->ssi.local = NULL;
    598   sess->ssi.pending = NULL;
    599   sess->ssi.timestamp = (time_t)0;
    600  
    601   return 0;
     564        struct aim_ssi_item *cur, *del;
     565        struct aim_ssi_tmp *curtmp, *deltmp;
     566
     567        cur = sess->ssi.official;
     568        while (cur) {
     569                del = cur;
     570                cur = cur->next;
     571                free(del->name);
     572                aim_tlvlist_free(&del->data);
     573                free(del);
     574        }
     575
     576        cur = sess->ssi.local;
     577        while (cur) {
     578                del = cur;
     579                cur = cur->next;
     580                free(del->name);
     581                aim_tlvlist_free(&del->data);
     582                free(del);
     583        }
     584
     585        curtmp = sess->ssi.pending;
     586        while (curtmp) {
     587                deltmp = curtmp;
     588                curtmp = curtmp->next;
     589                free(deltmp);
     590        }
     591
     592        sess->ssi.numitems = 0;
     593        sess->ssi.official = NULL;
     594        sess->ssi.local = NULL;
     595        sess->ssi.pending = NULL;
     596        sess->ssi.timestamp = (time_t)0;
     597
     598        return 0;
    602599}
    603600
     
    610607faim_export int aim_ssi_deletelist(aim_session_t *sess)
    611608{
    612   struct aim_ssi_item *cur, *del;
    613  
    614   if (!sess) return (-EINVAL);
    615  
    616   /* Free the local list */
    617   cur = sess->ssi.local;
    618   while (cur) {
    619     del = cur;
    620     cur = cur->next;
    621     free(del->name);
    622     aim_freetlvchain(&del->data);
    623     free(del);
    624   }
    625   sess->ssi.local = NULL;
    626  
    627   /* Sync our local list with the server list */
    628   aim_ssi_sync(sess);
    629  
    630   return 0;
     609        struct aim_ssi_item *cur, *del;
     610
     611        if (!sess)
     612                return -EINVAL;
     613
     614        /* Free the local list */
     615        cur = sess->ssi.local;
     616        while (cur) {
     617                del = cur;
     618                cur = cur->next;
     619                free(del->name);
     620                aim_tlvlist_free(&del->data);
     621                free(del);
     622        }
     623        sess->ssi.local = NULL;
     624
     625        /* Sync our local list with the server list */
     626        aim_ssi_sync(sess);
     627
     628        return 0;
    631629}
    632630
     
    642640faim_export int aim_ssi_cleanlist(aim_session_t *sess)
    643641{
    644   struct aim_ssi_item *cur, *next;
    645  
    646   if (!sess) return -EINVAL;
    647 
    648   /* Delete any buddies, permits, or denies with empty names. */
    649   /* If there are any buddies directly in the master group, add them to a real group. */
    650   /* DESTROY any buddies that are directly in the master group. */
    651   /* Do the same for buddies that are in a non-existant group. */
    652   /* This will kind of mess up if you hit the item limit, but this function isn't too critical */
    653   cur = sess->ssi.local;
    654   while (cur) {
    655     next = cur->next;
    656     if (!cur->name) {
    657       if (cur->type == AIM_SSI_TYPE_BUDDY)
    658         aim_ssi_delbuddy(sess, NULL, NULL);
    659       else if (cur->type == AIM_SSI_TYPE_PERMIT)
    660         aim_ssi_delpermit(sess, NULL);
    661       else if (cur->type == AIM_SSI_TYPE_DENY)
    662         aim_ssi_deldeny(sess, NULL);
    663     } else if ((cur->type == AIM_SSI_TYPE_BUDDY) && ((cur->gid == 0x0000) || (!aim_ssi_itemlist_find(sess->ssi.local, cur->gid, 0x0000)))) {
    664       aim_ssi_addbuddy(sess, cur->name, "orphans", NULL, NULL, NULL, 0);
    665       aim_ssi_delbuddy(sess, cur->name, NULL);
    666     }
    667     cur = next;
    668   }
    669  
    670   /* Check if there are empty groups and delete them */
    671   cur = sess->ssi.local;
    672   while (cur) {
    673     next = cur->next;
    674     if (cur->type == AIM_SSI_TYPE_GROUP) {
    675       aim_tlv_t *tlv = aim_gettlv(cur->data, 0x00c8, 1);
    676       if (!tlv || !tlv->length)
    677         aim_ssi_itemlist_del(&sess->ssi.local, cur);
    678     }
    679     cur = next;
    680   }
    681  
    682   /* Check if the master group is empty */
    683   if ((cur = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000)) && (!cur->data))
    684     aim_ssi_itemlist_del(&sess->ssi.local, cur);
    685  
    686   return 0;
     642        struct aim_ssi_item *cur, *next;
     643
     644        if (!sess)
     645                return -EINVAL;
     646
     647        /* Delete any buddies, permits, or denies with empty names. */
     648        /* If there are any buddies directly in the master group, add them to a real group. */
     649        /* DESTROY any buddies that are directly in the master group. */
     650        /* Do the same for buddies that are in a non-existant group. */
     651        /* This will kind of mess up if you hit the item limit, but this function isn't too critical */
     652        cur = sess->ssi.local;
     653        while (cur) {
     654                next = cur->next;
     655                if (!cur->name) {
     656                        if (cur->type == AIM_SSI_TYPE_BUDDY)
     657                                aim_ssi_delbuddy(sess, NULL, NULL);
     658                        else if (cur->type == AIM_SSI_TYPE_PERMIT)
     659                                aim_ssi_delpermit(sess, NULL);
     660                        else if (cur->type == AIM_SSI_TYPE_DENY)
     661                                aim_ssi_deldeny(sess, NULL);
     662                } else if ((cur->type == AIM_SSI_TYPE_BUDDY) && ((cur->gid == 0x0000) || (!aim_ssi_itemlist_find(sess->ssi.local, cur->gid, 0x0000)))) {
     663                        aim_ssi_addbuddy(sess, cur->name, "orphans", NULL, NULL, NULL, 0);
     664                        aim_ssi_delbuddy(sess, cur->name, NULL);
     665                }
     666                cur = next;
     667        }
     668
     669        /* Check if there are empty groups and delete them */
     670        cur = sess->ssi.local;
     671        while (cur) {
     672                next = cur->next;
     673                if (cur->type == AIM_SSI_TYPE_GROUP) {
     674                        aim_tlv_t *tlv = aim_tlv_gettlv(cur->data, 0x00c8, 1);
     675                        if (!tlv || !tlv->length)
     676                                aim_ssi_itemlist_del(&sess->ssi.local, cur);
     677                }
     678                cur = next;
     679        }
     680
     681        /* Check if the master group is empty */
     682        if ((cur = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000)) && (!cur->data))
     683                aim_ssi_itemlist_del(&sess->ssi.local, cur);
     684
     685        return 0;
    687686}
    688687
     
    700699faim_export int aim_ssi_addbuddy(aim_session_t *sess, const char *name, const char *group, const char *alias, const char *comment, const char *smsnum, int needauth)
    701700{
    702   struct aim_ssi_item *parent;
    703   aim_tlvlist_t *data = NULL;
    704  
    705   if (!sess || !name || !group) return (-EINVAL);
    706 
    707   /* Find the parent */
    708   if (!(parent = aim_ssi_itemlist_finditem(sess->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP))) {
    709     /* Find the parent's parent (the master group) */
    710     if (!(parent = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000))) {
    711       if (!(parent = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL))) {
    712         return -ENOMEM;
    713       }
    714     }
    715     /* Add the parent */
    716     if (!(parent = aim_ssi_itemlist_add(&sess->ssi.local, group, 0xFFFF, 0x0000, AIM_SSI_TYPE_GROUP, NULL))) {
    717       return -ENOMEM;
    718     }
    719    
    720     /* Modify the parent's parent (the master group) */
    721     aim_ssi_itemlist_rebuildgroup(sess->ssi.local, NULL);
    722   }
    723  
    724   /* Create a TLV list for the new buddy */
    725   if (needauth) aim_addtlvtochain_noval(&data, 0x0066);
    726   if (alias) aim_addtlvtochain_raw(&data, 0x0131, strlen(alias), alias);
    727   if (smsnum) aim_addtlvtochain_raw(&data, 0x013a, strlen(smsnum), smsnum);
    728   if (comment) aim_addtlvtochain_raw(&data, 0x013c, strlen(comment), comment);
    729  
    730   /* Add that bad boy */
    731   aim_ssi_itemlist_add(&sess->ssi.local, name, parent->gid, 0xFFFF, AIM_SSI_TYPE_BUDDY, data);
    732   aim_freetlvchain(&data);
    733  
    734   /* Modify the parent group */
    735   aim_ssi_itemlist_rebuildgroup(sess->ssi.local, group);
    736  
    737   /* Sync our local list with the server list */
    738   aim_ssi_sync(sess);
    739  
    740   return(0);
     701        struct aim_ssi_item *parent;
     702        aim_tlvlist_t *data = NULL;
     703
     704        if (!sess || !name || !group)
     705                return -EINVAL;
     706
     707        /* Find the parent */
     708        if (!(parent = aim_ssi_itemlist_finditem(sess->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP))) {
     709                /* Find the parent's parent (the master group) */
     710                if (!(parent = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000)))
     711                        if (!(parent = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL)))
     712                                return -ENOMEM;
     713                /* Add the parent */
     714                if (!(parent = aim_ssi_itemlist_add(&sess->ssi.local, group, 0xFFFF, 0x0000, AIM_SSI_TYPE_GROUP, NULL)))
     715                        return -ENOMEM;
     716
     717                /* Modify the parent's parent (the master group) */
     718                aim_ssi_itemlist_rebuildgroup(sess->ssi.local, NULL);
     719        }
     720
     721        /* Create a TLV list for the new buddy */
     722        if (needauth)
     723                aim_tlvlist_add_noval(&data, 0x0066);
     724        if (alias)
     725                aim_tlvlist_add_raw(&data, 0x0131, strlen(alias), alias);
     726        if (smsnum)
     727                aim_tlvlist_add_raw(&data, 0x013a, strlen(smsnum), smsnum);
     728        if (comment)
     729                aim_tlvlist_add_raw(&data, 0x013c, strlen(comment), comment);
     730
     731        /* Add that bad boy */
     732        aim_ssi_itemlist_add(&sess->ssi.local, name, parent->gid, 0xFFFF, AIM_SSI_TYPE_BUDDY, data);
     733        aim_tlvlist_free(&data);
     734
     735        /* Modify the parent group */
     736        aim_ssi_itemlist_rebuildgroup(sess->ssi.local, group);
     737
     738        /* Sync our local list with the server list */
     739        aim_ssi_sync(sess);
     740
     741        return 0;
    741742}
    742743
     
    751752{
    752753
    753   if (!sess || !name) return -EINVAL;
    754 
    755   /* Add that bad boy */
    756   aim_ssi_itemlist_add(&sess->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_PERMIT, NULL);
    757 
    758   /* Sync our local list with the server list */
    759   aim_ssi_sync(sess);
    760 
    761   return(0);
     754        if (!sess || !name)
     755                return -EINVAL;
     756
     757        /* Add that bad boy */
     758        aim_ssi_itemlist_add(&sess->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_PERMIT, NULL);
     759
     760        /* Sync our local list with the server list */
     761        aim_ssi_sync(sess);
     762
     763        return 0;
    762764}
    763765
     
    772774{
    773775
    774   if (!sess || !name) return (-EINVAL);
    775 
    776   /* Add that bad boy */
    777   aim_ssi_itemlist_add(&sess->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_DENY, NULL);
    778  
    779   /* Sync our local list with the server list */
    780   aim_ssi_sync(sess);
    781  
    782   return(0);
     776        if (!sess || !name)
     777                return -EINVAL;
     778
     779        /* Add that bad boy */
     780        aim_ssi_itemlist_add(&sess->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_DENY, NULL);
     781
     782        /* Sync our local list with the server list */
     783        aim_ssi_sync(sess);
     784
     785        return 0;
    783786}
    784787
     
    793796faim_export int aim_ssi_delbuddy(aim_session_t *sess, const char *name, const char *group)
    794797{
    795   struct aim_ssi_item *del;
    796 
    797   if (!sess) return -EINVAL;
    798  
    799   /* Find the buddy */
    800   del=aim_ssi_itemlist_finditem(sess->ssi.local, group, name, AIM_SSI_TYPE_BUDDY);
    801   if (!del) return(-EINVAL);
    802  
    803   /* Remove the item from the list */
    804   aim_ssi_itemlist_del(&sess->ssi.local, del);
    805 
    806   /* Modify the parent group */
    807   aim_ssi_itemlist_rebuildgroup(sess->ssi.local, group);
    808  
    809   /* Check if we should delete the parent group */
    810   if ((del = aim_ssi_itemlist_finditem(sess->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP)) && (!del->data)) {
    811     aim_ssi_itemlist_del(&sess->ssi.local, del);
    812    
    813     /* Modify the parent group */
    814     aim_ssi_itemlist_rebuildgroup(sess->ssi.local, NULL);
    815    
    816     /* Check if we should delete the parent's parent (the master group) */
    817     if ((del = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000)) && (!del->data)) {
    818       aim_ssi_itemlist_del(&sess->ssi.local, del);
    819     }
    820   }
    821  
    822   /* Sync our local list with the server list */
    823   owl_function_debugmsg("aim_ssi_delbuddy: about to sync");
    824   aim_ssi_sync(sess);
    825  
    826   return(0);
     798        struct aim_ssi_item *del;
     799
     800        if (!sess)
     801                return -EINVAL;
     802
     803        /* Find the buddy */
     804        if (!(del = aim_ssi_itemlist_finditem(sess->ssi.local, group, name, AIM_SSI_TYPE_BUDDY)))
     805                return -EINVAL;
     806
     807        /* Remove the item from the list */
     808        aim_ssi_itemlist_del(&sess->ssi.local, del);
     809
     810        /* Modify the parent group */
     811        aim_ssi_itemlist_rebuildgroup(sess->ssi.local, group);
     812
     813        /* Check if we should delete the parent group */
     814        if ((del = aim_ssi_itemlist_finditem(sess->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP)) && (!del->data)) {
     815                aim_ssi_itemlist_del(&sess->ssi.local, del);
     816
     817                /* Modify the parent group */
     818                aim_ssi_itemlist_rebuildgroup(sess->ssi.local, NULL);
     819
     820                /* Check if we should delete the parent's parent (the master group) */
     821                if ((del = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000)) && (!del->data)) {
     822                        aim_ssi_itemlist_del(&sess->ssi.local, del);
     823                }
     824        }
     825
     826        /* Sync our local list with the server list */
     827        aim_ssi_sync(sess);
     828
     829        return 0;
    827830}
    828831
     
    836839faim_export int aim_ssi_delpermit(aim_session_t *sess, const char *name)
    837840{
    838   struct aim_ssi_item *del;
    839  
    840   if (!sess)
    841     return -EINVAL;
    842  
    843   /* Find the item */
    844   if (!(del = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, name, AIM_SSI_TYPE_PERMIT)))
    845     return -EINVAL;
    846  
    847   /* Remove the item from the list */
    848   aim_ssi_itemlist_del(&sess->ssi.local, del);
    849  
    850   /* Sync our local list with the server list */
    851   aim_ssi_sync(sess);
    852  
    853   return 0;
     841        struct aim_ssi_item *del;
     842
     843        if (!sess)
     844                return -EINVAL;
     845
     846        /* Find the item */
     847        if (!(del = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, name, AIM_SSI_TYPE_PERMIT)))
     848                return -EINVAL;
     849
     850        /* Remove the item from the list */
     851        aim_ssi_itemlist_del(&sess->ssi.local, del);
     852
     853        /* Sync our local list with the server list */
     854        aim_ssi_sync(sess);
     855
     856        return 0;
    854857}
    855858
     
    863866faim_export int aim_ssi_deldeny(aim_session_t *sess, const char *name)
    864867{
    865   struct aim_ssi_item *del;
    866  
    867   if (!sess)
    868     return -EINVAL;
    869  
    870   /* Find the item */
    871   if (!(del = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, name, AIM_SSI_TYPE_DENY)))
    872     return -EINVAL;
    873  
    874   /* Remove the item from the list */
    875   aim_ssi_itemlist_del(&sess->ssi.local, del);
    876  
    877   /* Sync our local list with the server list */
    878   aim_ssi_sync(sess);
    879  
    880   return 0;
     868        struct aim_ssi_item *del;
     869
     870        if (!sess)
     871                return -EINVAL;
     872
     873        /* Find the item */
     874        if (!(del = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, name, AIM_SSI_TYPE_DENY)))
     875                return -EINVAL;
     876
     877        /* Remove the item from the list */
     878        aim_ssi_itemlist_del(&sess->ssi.local, del);
     879
     880        /* Sync our local list with the server list */
     881        aim_ssi_sync(sess);
     882
     883        return 0;
    881884}
    882885
     
    893896faim_export int aim_ssi_movebuddy(aim_session_t *sess, const char *oldgn, const char *newgn, const char *sn)
    894897{
    895   aim_ssi_addbuddy(sess, sn, newgn, aim_ssi_getalias(sess->ssi.local, oldgn, sn), NULL, NULL, aim_ssi_waitingforauth(sess->ssi.local, oldgn, sn));
    896   aim_ssi_delbuddy(sess, sn, oldgn);
    897   return 0;
     898        aim_ssi_addbuddy(sess, sn, newgn, aim_ssi_getalias(sess->ssi.local, oldgn, sn), NULL, NULL, aim_ssi_waitingforauth(sess->ssi.local, oldgn, sn));
     899        aim_ssi_delbuddy(sess, sn, oldgn);
     900        return 0;
    898901}
    899902
     
    904907 * @param gn The group that the buddy is currently in.
    905908 * @param sn The screen name of the buddy.
    906  * @param alias The new alias for the buddy.
     909 * @param alias The new alias for the buddy, or NULL if you want to remove
     910 *        a buddy's comment.
    907911 * @return Return 0 if no errors, otherwise return the error number.
    908912 */
    909913faim_export int aim_ssi_aliasbuddy(aim_session_t *sess, const char *gn, const char *sn, const char *alias)
    910914{
    911   struct aim_ssi_item *tmp;
    912   aim_tlvlist_t *data = NULL;
    913  
    914   if (!sess || !gn || !sn)
    915     return -EINVAL;
    916  
    917   if (!(tmp = aim_ssi_itemlist_finditem(sess->ssi.local, gn, sn, AIM_SSI_TYPE_BUDDY)))
    918     return -EINVAL;
    919  
    920   if (alias && !strlen(alias))
    921     alias = NULL;
    922  
    923   /* Need to add the x0131 TLV to the TLV chain */
    924   if (alias)
    925     aim_addtlvtochain_raw(&data, 0x0131, strlen(alias), alias);
    926  
    927   aim_freetlvchain(&tmp->data);
    928   tmp->data = data;
    929  
    930   /* Sync our local list with the server list */
    931   aim_ssi_sync(sess);
    932  
    933   return 0;
     915        struct aim_ssi_item *tmp;
     916
     917        if (!sess || !gn || !sn)
     918                return -EINVAL;
     919
     920        if (!(tmp = aim_ssi_itemlist_finditem(sess->ssi.local, gn, sn, AIM_SSI_TYPE_BUDDY)))
     921                return -EINVAL;
     922
     923        /* Either add or remove the 0x0131 TLV from the TLV chain */
     924        if ((alias != NULL) && (strlen(alias) > 0))
     925                aim_tlvlist_replace_raw(&tmp->data, 0x0131, strlen(alias), alias);
     926        else
     927                aim_tlvlist_remove(&tmp->data, 0x0131);
     928
     929        /* Sync our local list with the server list */
     930        aim_ssi_sync(sess);
     931
     932        return 0;
     933}
     934
     935/**
     936 * Change the comment stored on the server for a given buddy.
     937 *
     938 * @param sess The oscar session.
     939 * @param gn The group that the buddy is currently in.
     940 * @param sn The screen name of the buddy.
     941 * @param alias The new comment for the buddy, or NULL if you want to remove
     942 *        a buddy's comment.
     943 * @return Return 0 if no errors, otherwise return the error number.
     944 */
     945faim_export int aim_ssi_editcomment(aim_session_t *sess, const char *gn, const char *sn, const char *comment)
     946{
     947        struct aim_ssi_item *tmp;
     948
     949        if (!sess || !gn || !sn)
     950                return -EINVAL;
     951
     952        if (!(tmp = aim_ssi_itemlist_finditem(sess->ssi.local, gn, sn, AIM_SSI_TYPE_BUDDY)))
     953                return -EINVAL;
     954
     955        /* Either add or remove the 0x0131 TLV from the TLV chain */
     956        if ((comment != NULL) && (strlen(comment) > 0))
     957                aim_tlvlist_replace_raw(&tmp->data, 0x013c, strlen(comment), comment);
     958        else
     959                aim_tlvlist_remove(&tmp->data, 0x013c);
     960
     961        /* Sync our local list with the server list */
     962        aim_ssi_sync(sess);
     963
     964        return 0;
    934965}
    935966
     
    944975faim_export int aim_ssi_rename_group(aim_session_t *sess, const char *oldgn, const char *newgn)
    945976{
    946   struct aim_ssi_item *group;
    947  
    948   if (!sess || !oldgn || !newgn)
    949     return -EINVAL;
    950  
    951   if (!(group = aim_ssi_itemlist_finditem(sess->ssi.local, oldgn, NULL, AIM_SSI_TYPE_GROUP)))
    952     return -EINVAL;
    953  
    954   free(group->name);
    955   group->name = (char *)malloc((strlen(newgn)+1)*sizeof(char));
    956   strcpy(group->name, newgn);
    957  
    958   /* Sync our local list with the server list */
    959   aim_ssi_sync(sess);
    960  
    961   return 0;
     977        struct aim_ssi_item *group;
     978
     979        if (!sess || !oldgn || !newgn)
     980                return -EINVAL;
     981
     982        if (!(group = aim_ssi_itemlist_finditem(sess->ssi.local, oldgn, NULL, AIM_SSI_TYPE_GROUP)))
     983                return -EINVAL;
     984
     985        free(group->name);
     986        group->name = (char *)malloc((strlen(newgn)+1)*sizeof(char));
     987        strcpy(group->name, newgn);
     988
     989        /* Sync our local list with the server list */
     990        aim_ssi_sync(sess);
     991
     992        return 0;
    962993}
    963994
     
    9781009faim_export int aim_ssi_setpermdeny(aim_session_t *sess, fu8_t permdeny, fu32_t vismask)
    9791010{
    980   struct aim_ssi_item *tmp;
    981   aim_tlvlist_t *data = NULL;
    982  
    983   if (!sess)
    984     return -EINVAL;
    985  
    986   /* Need to add the x00ca TLV to the TLV chain */
    987   aim_addtlvtochain8(&data, 0x00ca, permdeny);
    988  
    989   /* Need to add the x00cb TLV to the TLV chain */
    990   aim_addtlvtochain32(&data, 0x00cb, vismask);
    991  
    992   if ((tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, NULL, AIM_SSI_TYPE_PDINFO))) {
    993     aim_freetlvchain(&tmp->data);
    994     tmp->data = data;
    995   } else {
    996     tmp = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PDINFO, data);
    997     aim_freetlvchain(&data);
    998   }
    999  
    1000   /* Sync our local list with the server list */
    1001   aim_ssi_sync(sess);
    1002  
    1003   return 0;
     1011        struct aim_ssi_item *tmp;
     1012
     1013        if (!sess)
     1014                return -EINVAL;
     1015
     1016        /* Find the PDINFO item, or add it if it does not exist */
     1017        if (!(tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, NULL, AIM_SSI_TYPE_PDINFO)))
     1018                tmp = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PDINFO, NULL);
     1019
     1020        /* Need to add the 0x00ca TLV to the TLV chain */
     1021        aim_tlvlist_replace_8(&tmp->data, 0x00ca, permdeny);
     1022
     1023        /* Need to add the 0x00cb TLV to the TLV chain */
     1024        aim_tlvlist_replace_32(&tmp->data, 0x00cb, vismask);
     1025
     1026        /* Sync our local list with the server list */
     1027        aim_ssi_sync(sess);
     1028
     1029        return 0;
    10041030}
    10051031
     
    10141040faim_export int aim_ssi_seticon(aim_session_t *sess, fu8_t *iconsum, fu16_t iconsumlen)
    10151041{
    1016   struct aim_ssi_item *tmp;
    1017   aim_tlvlist_t *data = NULL;
    1018   fu8_t *csumdata;
    1019  
    1020   if (!sess || !iconsum || !iconsumlen)
    1021     return -EINVAL;
    1022  
    1023   if (!(csumdata = (fu8_t *)malloc((iconsumlen+2)*sizeof(fu8_t))))
    1024     return -ENOMEM;
    1025   csumdata[0] = 0x00;
    1026   csumdata[1] = 0x10;
    1027   memcpy(&csumdata[2], iconsum, iconsumlen);
    1028  
    1029   /* Need to add the x00d5 TLV to the TLV chain */
    1030   aim_addtlvtochain_raw(&data, 0x00d5, (iconsumlen+2) * sizeof(fu8_t), csumdata);
    1031  
    1032   /* This TLV is added to cache the icon. */
    1033   aim_addtlvtochain_noval(&data, 0x0131);
    1034  
    1035   if ((tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, "1", AIM_SSI_TYPE_ICONINFO))) {
    1036     /* If the new tlvchain and oldtlvchain are the same, then do nothing */
    1037     if (!aim_tlvlist_cmp(tmp->data, data)) {
    1038       /* The new tlvlist is the identical to the old one */
    1039       aim_freetlvchain(&data);
    1040       free(csumdata);
    1041       return 0;
    1042     }
    1043     aim_freetlvchain(&tmp->data);
    1044     tmp->data = data;
    1045   } else {
    1046     tmp = aim_ssi_itemlist_add(&sess->ssi.local, "1", 0x0000, 0x51F4, AIM_SSI_TYPE_ICONINFO, data);
    1047     aim_freetlvchain(&data);
    1048   }
    1049  
    1050   /* Sync our local list with the server list */
    1051   aim_ssi_sync(sess);
    1052   free(csumdata);
    1053   return 0;
     1042        struct aim_ssi_item *tmp;
     1043        fu8_t *csumdata;
     1044
     1045        if (!sess || !iconsum || !iconsumlen)
     1046                return -EINVAL;
     1047
     1048        /* Find the ICONINFO item, or add it if it does not exist */
     1049        if (!(tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, "1", AIM_SSI_TYPE_ICONINFO))) {
     1050                tmp = aim_ssi_itemlist_add(&sess->ssi.local, "1", 0x0000, 0x51F4, AIM_SSI_TYPE_ICONINFO, NULL);
     1051        }
     1052
     1053        /* Need to add the 0x00d5 TLV to the TLV chain */
     1054        if (!(csumdata = (fu8_t *)malloc((iconsumlen+2)*sizeof(fu8_t))))
     1055                return -ENOMEM;
     1056        csumdata[0] = 0x00;
     1057        csumdata[1] = 0x10;
     1058        memcpy(&csumdata[2], iconsum, iconsumlen);
     1059        aim_tlvlist_replace_raw(&tmp->data, 0x00d5, (iconsumlen+2) * sizeof(fu8_t), csumdata);
     1060        free(csumdata);
     1061
     1062        /* Need to add the 0x0131 TLV to the TLV chain, used to cache the icon */
     1063        aim_tlvlist_replace_noval(&tmp->data, 0x0131);
     1064
     1065        /* Sync our local list with the server list */
     1066        aim_ssi_sync(sess);
     1067        return 0;
     1068}
     1069
     1070/**
     1071 * Remove a reference to a server stored buddy icon.  This will make your
     1072 * icon stop showing up to other people.
     1073 *
     1074 * @param sess The oscar session.
     1075 * @return Return 0 if no errors, otherwise return the error number.
     1076 */
     1077faim_export int aim_ssi_delicon(aim_session_t *sess)
     1078{
     1079        struct aim_ssi_item *tmp;
     1080
     1081        if (!sess)
     1082                return -EINVAL;
     1083
     1084        /* Find the ICONINFO item and delete it if it exists*/
     1085        if ((tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, "1", AIM_SSI_TYPE_ICONINFO)))
     1086                aim_ssi_itemlist_del(&sess->ssi.local, tmp);
     1087
     1088        /* Sync our local list with the server list */
     1089        aim_ssi_sync(sess);
     1090        return 0;
    10541091}
    10551092
     
    10591096 * @param sess The oscar session.
    10601097 * @param presence I think it's a bitmask, but I only know what one of the bits is:
     1098 *        0x00000002 - Hide wireless?
    10611099 *        0x00000400 - Allow others to see your idle time
    10621100 * @return Return 0 if no errors, otherwise return the error number.
    10631101 */
    10641102faim_export int aim_ssi_setpresence(aim_session_t *sess, fu32_t presence) {
    1065   struct aim_ssi_item *tmp;
    1066   aim_tlvlist_t *data = NULL;
    1067  
    1068   if (!sess)
    1069     return -EINVAL;
    1070  
    1071   /* Need to add the x00c9 TLV to the TLV chain */
    1072   aim_addtlvtochain32(&data, 0x00c9, presence);
    1073  
    1074   if ((tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS))) {
    1075     aim_freetlvchain(&tmp->data);
    1076     tmp->data = data;
    1077   } else {
    1078     tmp = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PRESENCEPREFS, data);
    1079     aim_freetlvchain(&data);
    1080   }
    1081  
    1082   /* Sync our local list with the server list */
    1083   aim_ssi_sync(sess);
    1084  
    1085   return 0;
     1103        struct aim_ssi_item *tmp;
     1104
     1105        if (!sess)
     1106                return -EINVAL;
     1107
     1108        /* Find the PRESENCEPREFS item, or add it if it does not exist */
     1109        if (!(tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS)))
     1110                tmp = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PRESENCEPREFS, NULL);
     1111
     1112        /* Need to add the x00c9 TLV to the TLV chain */
     1113        aim_tlvlist_replace_32(&tmp->data, 0x00c9, presence);
     1114
     1115        /* Sync our local list with the server list */
     1116        aim_ssi_sync(sess);
     1117
     1118        return 0;
    10861119}
    10871120
     
    10911124faim_export int aim_ssi_reqrights(aim_session_t *sess)
    10921125{
    1093   aim_conn_t *conn;
    1094  
    1095   if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)))
    1096     return -EINVAL;
    1097  
    1098   return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_REQRIGHTS);
     1126        aim_conn_t *conn;
     1127
     1128        if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)))
     1129                return -EINVAL;
     1130
     1131        return aim_genericreq_n_snacid(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_REQRIGHTS);
    10991132}
    11001133
     
    11041137static int parserights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    11051138{
    1106   int ret = 0, i;
    1107   aim_rxcallback_t userfunc;
    1108   aim_tlvlist_t *tlvlist;
    1109   aim_tlv_t *tlv;
    1110   aim_bstream_t bstream;
    1111   fu16_t *maxitems;
    1112  
    1113   /* This SNAC is made up of a bunch of TLVs */
    1114   tlvlist = aim_readtlvchain(bs);
    1115  
    1116   /* TLV 0x0004 contains the maximum number of each item */
    1117   if (!(tlv = aim_gettlv(tlvlist, 0x0004, 1))) {
    1118     aim_freetlvchain(&tlvlist);
    1119     return 0;
    1120   }
    1121  
    1122   aim_bstream_init(&bstream, tlv->value, tlv->length);
    1123  
    1124   if (!(maxitems = (fu16_t *)malloc((tlv->length/2)*sizeof(fu16_t)))) {
    1125     aim_freetlvchain(&tlvlist);
    1126     return 0;
    1127   }
    1128  
    1129   for (i=0; i<(tlv->length/2); i++)
    1130     maxitems[i] = aimbs_get16(&bstream);
    1131  
    1132   if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    1133     ret = userfunc(sess, rx, tlv->length/2, maxitems);
    1134  
    1135   aim_freetlvchain(&tlvlist);
    1136   free(maxitems);
    1137  
    1138   return ret;
     1139        int ret = 0, i;
     1140        aim_rxcallback_t userfunc;
     1141        aim_tlvlist_t *tlvlist;
     1142        aim_tlv_t *tlv;
     1143        aim_bstream_t bstream;
     1144        fu16_t *maxitems;
     1145
     1146        /* This SNAC is made up of a bunch of TLVs */
     1147        tlvlist = aim_tlvlist_read(bs);
     1148
     1149        /* TLV 0x0004 contains the maximum number of each item */
     1150        if (!(tlv = aim_tlv_gettlv(tlvlist, 0x0004, 1))) {
     1151                aim_tlvlist_free(&tlvlist);
     1152                return 0;
     1153        }
     1154
     1155        aim_bstream_init(&bstream, tlv->value, tlv->length);
     1156
     1157        if (!(maxitems = (fu16_t *)malloc((tlv->length/2)*sizeof(fu16_t)))) {
     1158                aim_tlvlist_free(&tlvlist);
     1159                return 0;
     1160        }
     1161
     1162        for (i=0; i<(tlv->length/2); i++)
     1163                maxitems[i] = aimbs_get16(&bstream);
     1164
     1165        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1166                ret = userfunc(sess, rx, tlv->length/2, maxitems);
     1167
     1168        aim_tlvlist_free(&tlvlist);
     1169        free(maxitems);
     1170
     1171        return ret;
    11391172}
    11401173
     
    11461179faim_export int aim_ssi_reqdata(aim_session_t *sess)
    11471180{
    1148   aim_conn_t *conn;
    1149  
    1150   if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)))
    1151     return -EINVAL;
    1152  
    1153   /* Free any current data, just in case */
    1154   aim_ssi_freelist(sess);
    1155  
    1156   return aim_genericreq_n_snacid(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_REQDATA);
     1181        aim_conn_t *conn;
     1182
     1183        if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)))
     1184                return -EINVAL;
     1185
     1186        /* Free any current data, just in case */
     1187        aim_ssi_freelist(sess);
     1188
     1189        return aim_genericreq_n_snacid(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_REQDATA);
    11571190}
    11581191
     
    11691202faim_export int aim_ssi_reqifchanged(aim_session_t *sess, time_t timestamp, fu16_t numitems)
    11701203{
    1171   aim_conn_t *conn;
    1172   aim_frame_t *fr;
    1173   aim_snacid_t snacid;
    1174  
    1175   if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)))
    1176     return -EINVAL;
    1177  
    1178   if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+4+2)))
    1179     return -ENOMEM;
    1180  
    1181   snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_REQIFCHANGED, 0x0000, NULL, 0);
    1182  
    1183   aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_REQIFCHANGED, 0x0000, snacid);
    1184   aimbs_put32(&fr->data, timestamp);
    1185   aimbs_put16(&fr->data, numitems);
    1186  
    1187   aim_tx_enqueue(sess, fr);
    1188  
    1189   /* Free any current data, just in case */
    1190   aim_ssi_freelist(sess);
    1191  
    1192   return 0;
     1204        aim_conn_t *conn;
     1205        aim_frame_t *fr;
     1206        aim_snacid_t snacid;
     1207
     1208        if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)))
     1209                return -EINVAL;
     1210
     1211        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+4+2)))
     1212                return -ENOMEM;
     1213
     1214        snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_REQIFCHANGED, 0x0000, NULL, 0);
     1215
     1216        aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_REQIFCHANGED, 0x0000, snacid);
     1217        aimbs_put32(&fr->data, timestamp);
     1218        aimbs_put16(&fr->data, numitems);
     1219
     1220        aim_tx_enqueue(sess, fr);
     1221
     1222        /* Free any current data, just in case */
     1223        aim_ssi_freelist(sess);
     1224
     1225        return 0;
    11931226}
    11941227
     
    11981231static int parsedata(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    11991232{
    1200   int ret = 0;
    1201   aim_rxcallback_t userfunc;
    1202   fu8_t fmtver; /* guess */
    1203   fu16_t namelen, gid, bid, type;
    1204   char *name;
    1205   aim_tlvlist_t *data;
    1206  
    1207   fmtver = aimbs_get8(bs); /* Version of ssi data.  Should be 0x00 */
    1208   sess->ssi.numitems += aimbs_get16(bs); /* # of items in this SSI SNAC */
    1209  
    1210   /* Read in the list */
    1211   while (aim_bstream_empty(bs) > 4) { /* last four bytes are timestamp */
    1212     if ((namelen = aimbs_get16(bs)))
    1213       name = aimbs_getstr(bs, namelen);
    1214     else
    1215       name = NULL;
    1216     gid = aimbs_get16(bs);
    1217     bid = aimbs_get16(bs);
    1218     type = aimbs_get16(bs);
    1219     data = aim_readtlvchain_len(bs, aimbs_get16(bs));
    1220     aim_ssi_itemlist_add(&sess->ssi.official, name, gid, bid, type, data);
    1221     free(name);
    1222     aim_freetlvchain(&data);
    1223   }
    1224  
    1225   /* Read in the timestamp */
    1226   sess->ssi.timestamp = aimbs_get32(bs);
    1227  
    1228   if (!(snac->flags & 0x0001)) {
    1229     /* Make a copy of the list */
    1230     struct aim_ssi_item *cur;
    1231     for (cur=sess->ssi.official; cur; cur=cur->next)
    1232       aim_ssi_itemlist_add(&sess->ssi.local, cur->name, cur->gid, cur->bid, cur->type, cur->data);
    1233    
    1234     sess->ssi.received_data = 1;
    1235    
    1236     if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    1237       ret = userfunc(sess, rx, fmtver, sess->ssi.numitems, sess->ssi.official, sess->ssi.timestamp);
    1238   }
    1239  
    1240   return ret;
     1233        int ret = 0;
     1234        aim_rxcallback_t userfunc;
     1235        fu8_t fmtver; /* guess */
     1236        fu16_t namelen, gid, bid, type;
     1237        char *name;
     1238        aim_tlvlist_t *data;
     1239
     1240        fmtver = aimbs_get8(bs); /* Version of ssi data.  Should be 0x00 */
     1241        sess->ssi.numitems += aimbs_get16(bs); /* # of items in this SSI SNAC */
     1242
     1243        /* Read in the list */
     1244        while (aim_bstream_empty(bs) > 4) { /* last four bytes are timestamp */
     1245                if ((namelen = aimbs_get16(bs)))
     1246                        name = aimbs_getstr(bs, namelen);
     1247                else
     1248                        name = NULL;
     1249                gid = aimbs_get16(bs);
     1250                bid = aimbs_get16(bs);
     1251                type = aimbs_get16(bs);
     1252                data = aim_tlvlist_readlen(bs, aimbs_get16(bs));
     1253                aim_ssi_itemlist_add(&sess->ssi.official, name, gid, bid, type, data);
     1254                free(name);
     1255                aim_tlvlist_free(&data);
     1256        }
     1257
     1258        /* Read in the timestamp */
     1259        sess->ssi.timestamp = aimbs_get32(bs);
     1260
     1261        if (!(snac->flags & 0x0001)) {
     1262                /* Make a copy of the list */
     1263                struct aim_ssi_item *cur;
     1264                for (cur=sess->ssi.official; cur; cur=cur->next)
     1265                        aim_ssi_itemlist_add(&sess->ssi.local, cur->name, cur->gid, cur->bid, cur->type, cur->data);
     1266
     1267                sess->ssi.received_data = 1;
     1268
     1269                if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1270                        ret = userfunc(sess, rx, fmtver, sess->ssi.numitems, sess->ssi.official, sess->ssi.timestamp);
     1271        }
     1272
     1273        return ret;
    12411274}
    12421275
     
    12521285faim_export int aim_ssi_enable(aim_session_t *sess)
    12531286{
    1254   aim_conn_t *conn;
    1255  
    1256   if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)))
    1257     return -EINVAL;
    1258  
    1259   return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, 0x0007);
     1287        aim_conn_t *conn;
     1288
     1289        if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)))
     1290                return -EINVAL;
     1291
     1292        return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, 0x0007);
    12601293}
    12611294
     
    12701303faim_export int aim_ssi_addmoddel(aim_session_t *sess)
    12711304{
    1272   aim_conn_t *conn;
    1273   aim_frame_t *fr;
    1274   aim_snacid_t snacid;
    1275   int snaclen;
    1276   struct aim_ssi_tmp *cur;
    1277  
    1278   if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)) || !sess->ssi.pending || !sess->ssi.pending->item) {
    1279     owl_function_debugmsg("aim_ssi_addmoddel: aborting early");
    1280     return -EINVAL;
    1281   }
    1282  
    1283   /* Calculate total SNAC size */
    1284   snaclen = 10; /* For family, subtype, flags, and SNAC ID */
    1285   for (cur=sess->ssi.pending; cur; cur=cur->next) {
    1286     snaclen += 10; /* For length, GID, BID, type, and length */
    1287     if (cur->item->name) snaclen += strlen(cur->item->name);
    1288     if (cur->item->data) snaclen += aim_sizetlvchain(&cur->item->data);
    1289   }
    1290  
    1291   if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, snaclen))) return (-ENOMEM);
    1292  
    1293   snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, sess->ssi.pending->action, 0x0000, NULL, 0);
    1294   aim_putsnac(&fr->data, AIM_CB_FAM_SSI, sess->ssi.pending->action, 0x0000, snacid);
    1295  
    1296   for (cur=sess->ssi.pending; cur; cur=cur->next) {
    1297     aimbs_put16(&fr->data, cur->item->name ? strlen(cur->item->name) : 0);
    1298     if (cur->item->name) aimbs_putraw(&fr->data, cur->item->name, strlen(cur->item->name));
    1299     aimbs_put16(&fr->data, cur->item->gid);
    1300     aimbs_put16(&fr->data, cur->item->bid);
    1301     aimbs_put16(&fr->data, cur->item->type);
    1302     aimbs_put16(&fr->data, cur->item->data ? aim_sizetlvchain(&cur->item->data) : 0);
    1303     if (cur->item->data) aim_writetlvchain(&fr->data, &cur->item->data);
    1304   }
    1305  
    1306   aim_tx_enqueue(sess, fr);
    1307 
    1308   owl_function_debugmsg("aim_ssi_addmoddel: exiting normally");
    1309   return 0;
     1305        aim_conn_t *conn;
     1306        aim_frame_t *fr;
     1307        aim_snacid_t snacid;
     1308        int snaclen;
     1309        struct aim_ssi_tmp *cur;
     1310
     1311        if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)) || !sess->ssi.pending || !sess->ssi.pending->item)
     1312                return -EINVAL;
     1313
     1314        /* Calculate total SNAC size */
     1315        snaclen = 10; /* For family, subtype, flags, and SNAC ID */
     1316        for (cur=sess->ssi.pending; cur; cur=cur->next) {
     1317                snaclen += 10; /* For length, GID, BID, type, and length */
     1318                if (cur->item->name)
     1319                        snaclen += strlen(cur->item->name);
     1320                if (cur->item->data)
     1321                        snaclen += aim_tlvlist_size(&cur->item->data);
     1322        }
     1323
     1324        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, snaclen)))
     1325                return -ENOMEM;
     1326
     1327        snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, sess->ssi.pending->action, 0x0000, NULL, 0);
     1328        aim_putsnac(&fr->data, AIM_CB_FAM_SSI, sess->ssi.pending->action, 0x0000, snacid);
     1329
     1330        for (cur=sess->ssi.pending; cur; cur=cur->next) {
     1331                aimbs_put16(&fr->data, cur->item->name ? strlen(cur->item->name) : 0);
     1332                if (cur->item->name)
     1333                        aimbs_putraw(&fr->data, cur->item->name, strlen(cur->item->name));
     1334                aimbs_put16(&fr->data, cur->item->gid);
     1335                aimbs_put16(&fr->data, cur->item->bid);
     1336                aimbs_put16(&fr->data, cur->item->type);
     1337                aimbs_put16(&fr->data, cur->item->data ? aim_tlvlist_size(&cur->item->data) : 0);
     1338                if (cur->item->data)
     1339                        aim_tlvlist_write(&fr->data, &cur->item->data);
     1340        }
     1341
     1342        aim_tx_enqueue(sess, fr);
     1343
     1344        return 0;
    13101345}
    13111346
     
    13171352static int parseadd(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    13181353{
    1319   int ret = 0;
    1320   aim_rxcallback_t userfunc;
    1321   char *name;
    1322   fu16_t len, gid, bid, type;
    1323   aim_tlvlist_t *data;
    1324  
    1325   while (aim_bstream_empty(bs)) {
    1326     if ((len = aimbs_get16(bs)))
    1327       name = aimbs_getstr(bs, len);
    1328     else
    1329       name = NULL;
    1330     gid = aimbs_get16(bs);
    1331     bid = aimbs_get16(bs);
    1332     type = aimbs_get16(bs);
    1333     if ((len = aimbs_get16(bs)))
    1334       data = aim_readtlvchain_len(bs, len);
    1335     else
    1336       data = NULL;
    1337    
    1338     aim_ssi_itemlist_add(&sess->ssi.local, name, gid, bid, type, data);
    1339     aim_ssi_itemlist_add(&sess->ssi.official, name, gid, bid, type, data);
    1340     free(name);
    1341     aim_freetlvchain(&data);
    1342    
    1343     if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    1344       ret = userfunc(sess, rx);
    1345    
    1346     free(name);
    1347   }
    1348  
    1349   return ret;
     1354        int ret = 0;
     1355        aim_rxcallback_t userfunc;
     1356        char *name;
     1357        fu16_t len, gid, bid, type;
     1358        aim_tlvlist_t *data;
     1359
     1360        while (aim_bstream_empty(bs)) {
     1361                if ((len = aimbs_get16(bs)))
     1362                        name = aimbs_getstr(bs, len);
     1363                else
     1364                        name = NULL;
     1365                gid = aimbs_get16(bs);
     1366                bid = aimbs_get16(bs);
     1367                type = aimbs_get16(bs);
     1368                if ((len = aimbs_get16(bs)))
     1369                        data = aim_tlvlist_readlen(bs, len);
     1370                else
     1371                        data = NULL;
     1372
     1373                aim_ssi_itemlist_add(&sess->ssi.local, name, gid, bid, type, data);
     1374                aim_ssi_itemlist_add(&sess->ssi.official, name, gid, bid, type, data);
     1375                free(name);
     1376                aim_tlvlist_free(&data);
     1377
     1378                if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1379                        ret = userfunc(sess, rx);
     1380
     1381                free(name);
     1382        }
     1383
     1384        return ret;
    13501385}
    13511386
     
    13571392static int parsemod(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    13581393{
    1359   int ret = 0;
    1360   aim_rxcallback_t userfunc;
    1361   char *name;
    1362   fu16_t len, gid, bid, type;
    1363   aim_tlvlist_t *data;
    1364   struct aim_ssi_item *item;
    1365  
    1366   while (aim_bstream_empty(bs)) {
    1367     if ((len = aimbs_get16(bs)))
    1368       name = aimbs_getstr(bs, len);
    1369     else
    1370       name = NULL;
    1371     gid = aimbs_get16(bs);
    1372     bid = aimbs_get16(bs);
    1373     type = aimbs_get16(bs);
    1374     if ((len = aimbs_get16(bs)))
    1375       data = aim_readtlvchain_len(bs, len);
    1376     else
    1377       data = NULL;
    1378    
    1379     /* Replace the 2 local items with the given one */
    1380     if ((item = aim_ssi_itemlist_find(sess->ssi.local, gid, bid))) {
    1381       item->type = type;
    1382       free(item->name);
    1383       if (name) {
    1384         item->name = (char *)malloc((strlen(name)+1)*sizeof(char));
    1385         strcpy(item->name, name);
    1386       } else
    1387         item->name = NULL;
    1388       aim_freetlvchain(&item->data);
    1389       item->data = aim_tlvlist_copy(data);
    1390     }
    1391    
    1392     if ((item = aim_ssi_itemlist_find(sess->ssi.official, gid, bid))) {
    1393       item->type = type;
    1394       free(item->name);
    1395       if (name) {
    1396         item->name = (char *)malloc((strlen(name)+1)*sizeof(char));
    1397         strcpy(item->name, name);
    1398       } else
    1399         item->name = NULL;
    1400       aim_freetlvchain(&item->data);
    1401       item->data = aim_tlvlist_copy(data);
    1402     }
    1403    
    1404     if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    1405       ret = userfunc(sess, rx);
    1406    
    1407     free(name);
    1408     aim_freetlvchain(&data);
    1409   }
    1410  
    1411   return ret;
     1394        int ret = 0;
     1395        aim_rxcallback_t userfunc;
     1396        char *name;
     1397        fu16_t len, gid, bid, type;
     1398        aim_tlvlist_t *data;
     1399        struct aim_ssi_item *item;
     1400
     1401        while (aim_bstream_empty(bs)) {
     1402                if ((len = aimbs_get16(bs)))
     1403                        name = aimbs_getstr(bs, len);
     1404                else
     1405                        name = NULL;
     1406                gid = aimbs_get16(bs);
     1407                bid = aimbs_get16(bs);
     1408                type = aimbs_get16(bs);
     1409                if ((len = aimbs_get16(bs)))
     1410                        data = aim_tlvlist_readlen(bs, len);
     1411                else
     1412                        data = NULL;
     1413
     1414                /* Replace the 2 local items with the given one */
     1415                if ((item = aim_ssi_itemlist_find(sess->ssi.local, gid, bid))) {
     1416                        item->type = type;
     1417                        free(item->name);
     1418                        if (name) {
     1419                                item->name = (char *)malloc((strlen(name)+1)*sizeof(char));
     1420                                strcpy(item->name, name);
     1421                        } else
     1422                                item->name = NULL;
     1423                        aim_tlvlist_free(&item->data);
     1424                        item->data = aim_tlvlist_copy(data);
     1425                }
     1426
     1427                if ((item = aim_ssi_itemlist_find(sess->ssi.official, gid, bid))) {
     1428                        item->type = type;
     1429                        free(item->name);
     1430                        if (name) {
     1431                                item->name = (char *)malloc((strlen(name)+1)*sizeof(char));
     1432                                strcpy(item->name, name);
     1433                        } else
     1434                                item->name = NULL;
     1435                        aim_tlvlist_free(&item->data);
     1436                        item->data = aim_tlvlist_copy(data);
     1437                }
     1438
     1439                if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1440                        ret = userfunc(sess, rx);
     1441
     1442                free(name);
     1443                aim_tlvlist_free(&data);
     1444        }
     1445
     1446        return ret;
    14121447}
    14131448
     
    14191454static int parsedel(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    14201455{
    1421   int ret = 0;
    1422   aim_rxcallback_t userfunc;
    1423   fu16_t gid, bid;
    1424   struct aim_ssi_item *del;
    1425  
    1426   while (aim_bstream_empty(bs)) {
    1427     aim_bstream_advance(bs, aimbs_get16(bs));
    1428     gid = aimbs_get16(bs);
    1429     bid = aimbs_get16(bs);
    1430     aimbs_get16(bs);
    1431     aim_bstream_advance(bs, aimbs_get16(bs));
    1432    
    1433     if ((del = aim_ssi_itemlist_find(sess->ssi.local, gid, bid)))
    1434       aim_ssi_itemlist_del(&sess->ssi.local, del);
    1435     if ((del = aim_ssi_itemlist_find(sess->ssi.official, gid, bid)))
    1436       aim_ssi_itemlist_del(&sess->ssi.official, del);
    1437    
    1438     if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    1439       ret = userfunc(sess, rx);
    1440   }
    1441  
    1442   return ret;
     1456        int ret = 0;
     1457        aim_rxcallback_t userfunc;
     1458        fu16_t gid, bid;
     1459        struct aim_ssi_item *del;
     1460
     1461        while (aim_bstream_empty(bs)) {
     1462                aim_bstream_advance(bs, aimbs_get16(bs));
     1463                gid = aimbs_get16(bs);
     1464                bid = aimbs_get16(bs);
     1465                aimbs_get16(bs);
     1466                aim_bstream_advance(bs, aimbs_get16(bs));
     1467
     1468                if ((del = aim_ssi_itemlist_find(sess->ssi.local, gid, bid)))
     1469                        aim_ssi_itemlist_del(&sess->ssi.local, del);
     1470                if ((del = aim_ssi_itemlist_find(sess->ssi.official, gid, bid)))
     1471                        aim_ssi_itemlist_del(&sess->ssi.official, del);
     1472
     1473                if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1474                        ret = userfunc(sess, rx);
     1475        }
     1476
     1477        return ret;
    14431478}
    14441479
     
    14511486static int parseack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    14521487{
    1453   int ret = 0;
    1454   aim_rxcallback_t userfunc;
    1455   struct aim_ssi_tmp *cur, *del;
    1456 
    1457   owl_function_debugmsg("Handling SNAC SSI ACK");
    1458  
    1459   /* Read in the success/failure flags from the ack SNAC */
    1460   cur = sess->ssi.pending;
    1461   while (cur && (aim_bstream_empty(bs)>0)) {
    1462     cur->ack = aimbs_get16(bs);
    1463     cur = cur->next;
    1464   }
    1465  
    1466   /*
    1467    * If outcome is 0, then add the item to the item list, or replace the other item,
    1468    * or remove the old item.  If outcome is non-zero, then remove the item from the
    1469    * local list, or unmodify it, or add it.
    1470    */
    1471   for (cur=sess->ssi.pending; (cur && (cur->ack != 0xffff)); cur=cur->next) {
    1472     owl_function_debugmsg("parseack: processing a change");
    1473     if (cur->item) {
    1474       if (cur->ack) {
    1475         /* Our action was unsuccessful, so change the local list back to how it was */
    1476         if (cur->action == AIM_CB_SSI_ADD) {
    1477           owl_function_debugmsg("parseack: unsuccesful add, reverting");
    1478           /* Remove the item from the local list */
    1479           /* Make sure cur->item is still valid memory */
    1480           if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) {
    1481             if (cur->item->name) {
    1482               cur->name = (char *)malloc((strlen(cur->item->name)+1)*sizeof(char));
    1483               strcpy(cur->name, cur->item->name);
    1484             }
    1485             aim_ssi_itemlist_del(&sess->ssi.local, cur->item);
    1486           }
    1487           cur->item = NULL;
    1488          
    1489         } else if (cur->action == AIM_CB_SSI_MOD) {
    1490           /* Replace the local item with the item from the official list */
    1491           owl_function_debugmsg("parseack: unsuccesful modify, reverting");
    1492           if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) {
    1493             struct aim_ssi_item *cur1;
    1494             if ((cur1 = aim_ssi_itemlist_find(sess->ssi.official, cur->item->gid, cur->item->bid))) {
    1495               free(cur->item->name);
    1496               if (cur1->name) {
    1497                 cur->item->name = (char *)malloc((strlen(cur1->name)+1)*sizeof(char));
    1498                 strcpy(cur->item->name, cur1->name);
    1499               } else
    1500                 cur->item->name = NULL;
    1501               aim_freetlvchain(&cur->item->data);
    1502               cur->item->data = aim_tlvlist_copy(cur1->data);
    1503             }
    1504           } else
    1505             cur->item = NULL;
    1506          
    1507         } else if (cur->action == AIM_CB_SSI_DEL) {
    1508           /* Add the item back into the local list */
    1509           owl_function_debugmsg("parseack: unsuccesful delete, reverting");
    1510           if (aim_ssi_itemlist_valid(sess->ssi.official, cur->item)) {
    1511             aim_ssi_itemlist_add(&sess->ssi.local, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data);
    1512           } else
    1513             cur->item = NULL;
    1514         }
    1515        
    1516       } else {
    1517         /* Do the exact opposite */
    1518         if (cur->action == AIM_CB_SSI_ADD) {
    1519           /* Add the local item to the official list */
    1520           owl_function_debugmsg("parseack: succesful add");
    1521           if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) {
    1522             aim_ssi_itemlist_add(&sess->ssi.official, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data);
    1523           } else
    1524             cur->item = NULL;
    1525          
    1526         } else if (cur->action == AIM_CB_SSI_MOD) {
    1527           /* Replace the official item with the item from the local list */
    1528           owl_function_debugmsg("parseack: succesful modify");
    1529           if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) {
    1530             struct aim_ssi_item *cur1;
    1531             if ((cur1 = aim_ssi_itemlist_find(sess->ssi.official, cur->item->gid, cur->item->bid))) {
    1532               free(cur1->name);
    1533               if (cur->item->name) {
    1534                 cur1->name = (char *)malloc((strlen(cur->item->name)+1)*sizeof(char));
    1535                 strcpy(cur1->name, cur->item->name);
    1536               } else
    1537                 cur1->name = NULL;
    1538               aim_freetlvchain(&cur1->data);
    1539               cur1->data = aim_tlvlist_copy(cur->item->data);
    1540             }
    1541           } else
    1542             cur->item = NULL;
    1543          
    1544         } else if (cur->action == AIM_CB_SSI_DEL) {
    1545           /* Remove the item from the official list */
    1546           owl_function_debugmsg("parseack: succesful delete");
    1547           if (aim_ssi_itemlist_valid(sess->ssi.official, cur->item))
    1548             aim_ssi_itemlist_del(&sess->ssi.official, cur->item);
    1549           cur->item = NULL;
    1550         }
    1551        
    1552       }
    1553     } /* End if (cur->item) */
    1554   } /* End for loop */
    1555  
    1556   if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    1557     ret = userfunc(sess, rx, sess->ssi.pending);
    1558  
    1559   /* Free all aim_ssi_tmp's with an outcome */
    1560   cur = sess->ssi.pending;
    1561   while (cur && (cur->ack != 0xffff)) {
    1562     del = cur;
    1563     cur = cur->next;
    1564     free(del->name);
    1565     free(del);
    1566   }
    1567   sess->ssi.pending = cur;
    1568  
    1569   /* If we're not waiting for any more acks, then send more SNACs */
    1570 
    1571   if (!sess->ssi.pending) {
    1572     sess->ssi.pending = NULL;
    1573     sess->ssi.waiting_for_ack = 0;
    1574     owl_function_debugmsg("parseack: Clearing SSI waiting_for_ack");
    1575     aim_ssi_sync(sess);
    1576   }
    1577 
    1578   owl_function_debugmsg("parseack: returning with %i", ret);
    1579  
    1580   return ret;
     1488        int ret = 0;
     1489        aim_rxcallback_t userfunc;
     1490        struct aim_ssi_tmp *cur, *del;
     1491
     1492        /* Read in the success/failure flags from the ack SNAC */
     1493        cur = sess->ssi.pending;
     1494        while (cur && (aim_bstream_empty(bs)>0)) {
     1495                cur->ack = aimbs_get16(bs);
     1496                cur = cur->next;
     1497        }
     1498
     1499        /*
     1500         * If outcome is 0, then add the item to the item list, or replace the other item,
     1501         * or remove the old item.  If outcome is non-zero, then remove the item from the
     1502         * local list, or unmodify it, or add it.
     1503         */
     1504        for (cur=sess->ssi.pending; (cur && (cur->ack != 0xffff)); cur=cur->next) {
     1505        if (cur->item) {
     1506                if (cur->ack) {
     1507                        /* Our action was unsuccessful, so change the local list back to how it was */
     1508                        if (cur->action == AIM_CB_SSI_ADD) {
     1509                                /* Remove the item from the local list */
     1510                                /* Make sure cur->item is still valid memory */
     1511                                if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) {
     1512                                        if (cur->item->name) {
     1513                                                cur->name = (char *)malloc((strlen(cur->item->name)+1)*sizeof(char));
     1514                                                strcpy(cur->name, cur->item->name);
     1515                                        }
     1516                                        aim_ssi_itemlist_del(&sess->ssi.local, cur->item);
     1517                                }
     1518                                cur->item = NULL;
     1519
     1520                        } else if (cur->action == AIM_CB_SSI_MOD) {
     1521                                /* Replace the local item with the item from the official list */
     1522                                if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) {
     1523                                        struct aim_ssi_item *cur1;
     1524                                        if ((cur1 = aim_ssi_itemlist_find(sess->ssi.official, cur->item->gid, cur->item->bid))) {
     1525                                                free(cur->item->name);
     1526                                                if (cur1->name) {
     1527                                                        cur->item->name = (char *)malloc((strlen(cur1->name)+1)*sizeof(char));
     1528                                                        strcpy(cur->item->name, cur1->name);
     1529                                                } else
     1530                                                        cur->item->name = NULL;
     1531                                                aim_tlvlist_free(&cur->item->data);
     1532                                                cur->item->data = aim_tlvlist_copy(cur1->data);
     1533                                        }
     1534                                } else
     1535                                        cur->item = NULL;
     1536
     1537                        } else if (cur->action == AIM_CB_SSI_DEL) {
     1538                                /* Add the item back into the local list */
     1539                                if (aim_ssi_itemlist_valid(sess->ssi.official, cur->item)) {
     1540                                        aim_ssi_itemlist_add(&sess->ssi.local, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data);
     1541                                } else
     1542                                        cur->item = NULL;
     1543                        }
     1544
     1545                } else {
     1546                        /* Do the exact opposite */
     1547                        if (cur->action == AIM_CB_SSI_ADD) {
     1548                        /* Add the local item to the official list */
     1549                                if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) {
     1550                                        aim_ssi_itemlist_add(&sess->ssi.official, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data);
     1551                                } else
     1552                                        cur->item = NULL;
     1553
     1554                        } else if (cur->action == AIM_CB_SSI_MOD) {
     1555                                /* Replace the official item with the item from the local list */
     1556                                if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) {
     1557                                        struct aim_ssi_item *cur1;
     1558                                        if ((cur1 = aim_ssi_itemlist_find(sess->ssi.official, cur->item->gid, cur->item->bid))) {
     1559                                                free(cur1->name);
     1560                                                if (cur->item->name) {
     1561                                                        cur1->name = (char *)malloc((strlen(cur->item->name)+1)*sizeof(char));
     1562                                                        strcpy(cur1->name, cur->item->name);
     1563                                                } else
     1564                                                        cur1->name = NULL;
     1565                                                aim_tlvlist_free(&cur1->data);
     1566                                                cur1->data = aim_tlvlist_copy(cur->item->data);
     1567                                        }
     1568                                } else
     1569                                        cur->item = NULL;
     1570
     1571                        } else if (cur->action == AIM_CB_SSI_DEL) {
     1572                                /* Remove the item from the official list */
     1573                                if (aim_ssi_itemlist_valid(sess->ssi.official, cur->item))
     1574                                        aim_ssi_itemlist_del(&sess->ssi.official, cur->item);
     1575                                cur->item = NULL;
     1576                        }
     1577
     1578                }
     1579        } /* End if (cur->item) */
     1580        } /* End for loop */
     1581
     1582        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1583                ret = userfunc(sess, rx, sess->ssi.pending);
     1584
     1585        /* Free all aim_ssi_tmp's with an outcome */
     1586        cur = sess->ssi.pending;
     1587        while (cur && (cur->ack != 0xffff)) {
     1588                del = cur;
     1589                cur = cur->next;
     1590                free(del->name);
     1591                free(del);
     1592        }
     1593        sess->ssi.pending = cur;
     1594
     1595        /* If we're not waiting for any more acks, then send more SNACs */
     1596        if (!sess->ssi.pending) {
     1597                sess->ssi.pending = NULL;
     1598                sess->ssi.waiting_for_ack = 0;
     1599                aim_ssi_sync(sess);
     1600        }
     1601
     1602        return ret;
    15811603}
    15821604
     
    15901612static int parsedataunchanged(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    15911613{
    1592   int ret = 0;
    1593   aim_rxcallback_t userfunc;
    1594  
    1595   sess->ssi.received_data = 1;
    1596  
    1597   if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    1598     ret = userfunc(sess, rx);
    1599  
    1600   return ret;
     1614        int ret = 0;
     1615        aim_rxcallback_t userfunc;
     1616
     1617        sess->ssi.received_data = 1;
     1618
     1619        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1620                ret = userfunc(sess, rx);
     1621
     1622        return ret;
    16011623}
    16021624
     
    16091631faim_export int aim_ssi_modbegin(aim_session_t *sess)
    16101632{
    1611   aim_conn_t *conn;
    1612  
    1613   if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)))
    1614     return -EINVAL;
    1615  
    1616   return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTART);
     1633        aim_conn_t *conn;
     1634
     1635        if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)))
     1636                return -EINVAL;
     1637
     1638        return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTART);
    16171639}
    16181640
     
    16251647faim_export int aim_ssi_modend(aim_session_t *sess)
    16261648{
    1627   aim_conn_t *conn;
    1628  
    1629   if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI))) return -EINVAL;
    1630  
    1631   return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTOP);
     1649        aim_conn_t *conn;
     1650
     1651        if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)))
     1652                return -EINVAL;
     1653
     1654        return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTOP);
    16321655}
    16331656
     
    16401663faim_export int aim_ssi_sendauth(aim_session_t *sess, char *sn, char *msg)
    16411664{
    1642   aim_conn_t *conn;
    1643   aim_frame_t *fr;
    1644   aim_snacid_t snacid;
    1645  
    1646   if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)) || !sn)
    1647     return -EINVAL;
    1648  
    1649   if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)+2+(msg ? strlen(msg)+1 : 0)+2)))
    1650     return -ENOMEM;
    1651  
    1652   snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTH, 0x0000, NULL, 0);
    1653   aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTH, 0x0000, snacid);
    1654  
    1655   /* Screen name */
    1656   aimbs_put8(&fr->data, strlen(sn));
    1657   aimbs_putraw(&fr->data, sn, strlen(sn));
    1658  
    1659   /* Message (null terminated) */
    1660   aimbs_put16(&fr->data, msg ? strlen(msg) : 0);
    1661   if (msg) {
    1662     aimbs_putraw(&fr->data, msg, strlen(msg));
    1663     aimbs_put8(&fr->data, 0x00);
    1664   }
    1665  
    1666   /* Unknown */
    1667   aimbs_put16(&fr->data, 0x0000);
    1668  
    1669   aim_tx_enqueue(sess, fr);
    1670  
    1671   return 0;
     1665        aim_conn_t *conn;
     1666        aim_frame_t *fr;
     1667        aim_snacid_t snacid;
     1668
     1669        if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)) || !sn)
     1670                return -EINVAL;
     1671
     1672        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)+2+(msg ? strlen(msg)+1 : 0)+2)))
     1673                return -ENOMEM;
     1674
     1675        snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTH, 0x0000, NULL, 0);
     1676        aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTH, 0x0000, snacid);
     1677
     1678        /* Screen name */
     1679        aimbs_put8(&fr->data, strlen(sn));
     1680        aimbs_putraw(&fr->data, sn, strlen(sn));
     1681
     1682        /* Message (null terminated) */
     1683        aimbs_put16(&fr->data, msg ? strlen(msg) : 0);
     1684        if (msg) {
     1685                aimbs_putraw(&fr->data, msg, strlen(msg));
     1686                aimbs_put8(&fr->data, 0x00);
     1687        }
     1688
     1689        /* Unknown */
     1690        aimbs_put16(&fr->data, 0x0000);
     1691
     1692        aim_tx_enqueue(sess, fr);
     1693
     1694        return 0;
    16721695}
    16731696
     
    16771700static int receiveauthgrant(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    16781701{
    1679   int ret = 0;
    1680   aim_rxcallback_t userfunc;
    1681   fu16_t tmp;
    1682   char *sn, *msg;
    1683  
    1684   /* Read screen name */
    1685   if ((tmp = aimbs_get8(bs)))
    1686     sn = aimbs_getstr(bs, tmp);
    1687   else
    1688     sn = NULL;
    1689  
    1690   /* Read message (null terminated) */
    1691   if ((tmp = aimbs_get16(bs)))
    1692     msg = aimbs_getstr(bs, tmp);
    1693   else
    1694     msg = NULL;
    1695  
    1696   /* Unknown */
    1697   tmp = aimbs_get16(bs);
    1698  
    1699   if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    1700     ret = userfunc(sess, rx, sn, msg);
    1701  
    1702   free(sn);
    1703   free(msg);
    1704  
    1705   return ret;
     1702        int ret = 0;
     1703        aim_rxcallback_t userfunc;
     1704        fu16_t tmp;
     1705        char *sn, *msg;
     1706
     1707        /* Read screen name */
     1708        if ((tmp = aimbs_get8(bs)))
     1709                sn = aimbs_getstr(bs, tmp);
     1710        else
     1711                sn = NULL;
     1712
     1713        /* Read message (null terminated) */
     1714        if ((tmp = aimbs_get16(bs)))
     1715                msg = aimbs_getstr(bs, tmp);
     1716        else
     1717                msg = NULL;
     1718
     1719        /* Unknown */
     1720        tmp = aimbs_get16(bs);
     1721
     1722        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1723                ret = userfunc(sess, rx, sn, msg);
     1724
     1725        free(sn);
     1726        free(msg);
     1727
     1728        return ret;
    17061729}
    17071730
     
    17151738faim_export int aim_ssi_sendauthrequest(aim_session_t *sess, char *sn, char *msg)
    17161739{
    1717   aim_conn_t *conn;
    1718   aim_frame_t *fr;
    1719   aim_snacid_t snacid;
    1720  
    1721   if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)) || !sn)
    1722     return -EINVAL;
    1723  
    1724   if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)+2+(msg ? strlen(msg)+1 : 0)+2)))
    1725     return -ENOMEM;
    1726  
    1727   snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREQ, 0x0000, NULL, 0);
    1728   aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREQ, 0x0000, snacid);
    1729  
    1730   /* Screen name */
    1731   aimbs_put8(&fr->data, strlen(sn));
    1732   aimbs_putraw(&fr->data, sn, strlen(sn));
    1733  
    1734   /* Message (null terminated) */
    1735   aimbs_put16(&fr->data, msg ? strlen(msg) : 0);
    1736   if (msg) {
    1737     aimbs_putraw(&fr->data, msg, strlen(msg));
    1738     aimbs_put8(&fr->data, 0x00);
    1739   }
    1740  
    1741   /* Unknown */
    1742   aimbs_put16(&fr->data, 0x0000);
    1743  
    1744   aim_tx_enqueue(sess, fr);
    1745  
    1746   return 0;
     1740        aim_conn_t *conn;
     1741        aim_frame_t *fr;
     1742        aim_snacid_t snacid;
     1743
     1744        if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)) || !sn)
     1745                return -EINVAL;
     1746
     1747        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)+2+(msg ? strlen(msg)+1 : 0)+2)))
     1748                return -ENOMEM;
     1749
     1750        snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREQ, 0x0000, NULL, 0);
     1751        aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREQ, 0x0000, snacid);
     1752
     1753        /* Screen name */
     1754        aimbs_put8(&fr->data, strlen(sn));
     1755        aimbs_putraw(&fr->data, sn, strlen(sn));
     1756
     1757        /* Message (null terminated) */
     1758        aimbs_put16(&fr->data, msg ? strlen(msg) : 0);
     1759        if (msg) {
     1760                aimbs_putraw(&fr->data, msg, strlen(msg));
     1761                aimbs_put8(&fr->data, 0x00);
     1762        }
     1763
     1764        /* Unknown */
     1765        aimbs_put16(&fr->data, 0x0000);
     1766
     1767        aim_tx_enqueue(sess, fr);
     1768
     1769        return 0;
    17471770}
    17481771
     
    17521775static int receiveauthrequest(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    17531776{
    1754   int ret = 0;
    1755   aim_rxcallback_t userfunc;
    1756   fu16_t tmp;
    1757   char *sn, *msg;
    1758  
    1759   /* Read screen name */
    1760   if ((tmp = aimbs_get8(bs)))
    1761     sn = aimbs_getstr(bs, tmp);
    1762   else
    1763     sn = NULL;
    1764  
    1765   /* Read message (null terminated) */
    1766   if ((tmp = aimbs_get16(bs)))
    1767     msg = aimbs_getstr(bs, tmp);
    1768   else
    1769     msg = NULL;
    1770  
    1771   /* Unknown */
    1772   tmp = aimbs_get16(bs);
    1773  
    1774   if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    1775     ret = userfunc(sess, rx, sn, msg);
    1776  
    1777   free(sn);
    1778   free(msg);
    1779  
    1780   return ret;
     1777        int ret = 0;
     1778        aim_rxcallback_t userfunc;
     1779        fu16_t tmp;
     1780        char *sn, *msg;
     1781
     1782        /* Read screen name */
     1783        if ((tmp = aimbs_get8(bs)))
     1784                sn = aimbs_getstr(bs, tmp);
     1785        else
     1786                sn = NULL;
     1787
     1788        /* Read message (null terminated) */
     1789        if ((tmp = aimbs_get16(bs)))
     1790                msg = aimbs_getstr(bs, tmp);
     1791        else
     1792                msg = NULL;
     1793
     1794        /* Unknown */
     1795        tmp = aimbs_get16(bs);
     1796
     1797        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1798                ret = userfunc(sess, rx, sn, msg);
     1799
     1800        free(sn);
     1801        free(msg);
     1802
     1803        return ret;
    17811804}
    17821805
     
    17931816faim_export int aim_ssi_sendauthreply(aim_session_t *sess, char *sn, fu8_t reply, char *msg)
    17941817{
    1795   aim_conn_t *conn;
    1796   aim_frame_t *fr;
    1797   aim_snacid_t snacid;
    1798  
    1799   if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)) || !sn)
    1800     return -EINVAL;
    1801  
    1802   if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 1+strlen(sn) + 1 + 2+(msg ? strlen(msg)+1 : 0) + 2)))
    1803     return -ENOMEM;
    1804  
    1805   snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREP, 0x0000, NULL, 0);
    1806   aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREP, 0x0000, snacid);
    1807  
    1808   /* Screen name */
    1809   aimbs_put8(&fr->data, strlen(sn));
    1810   aimbs_putraw(&fr->data, sn, strlen(sn));
    1811  
    1812   /* Grant or deny */
    1813   aimbs_put8(&fr->data, reply);
    1814  
    1815   /* Message (null terminated) */
    1816   aimbs_put16(&fr->data, msg ? (strlen(msg)+1) : 0);
    1817   if (msg) {
    1818     aimbs_putraw(&fr->data, msg, strlen(msg));
    1819     aimbs_put8(&fr->data, 0x00);
    1820   }
    1821  
    1822   /* Unknown */
    1823   aimbs_put16(&fr->data, 0x0000);
    1824  
    1825   aim_tx_enqueue(sess, fr);
    1826  
    1827   return 0;
     1818        aim_conn_t *conn;
     1819        aim_frame_t *fr;
     1820        aim_snacid_t snacid;
     1821
     1822        if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)) || !sn)
     1823                return -EINVAL;
     1824
     1825        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 1+strlen(sn) + 1 + 2+(msg ? strlen(msg)+1 : 0) + 2)))
     1826                return -ENOMEM;
     1827
     1828        snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREP, 0x0000, NULL, 0);
     1829        aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREP, 0x0000, snacid);
     1830
     1831        /* Screen name */
     1832        aimbs_put8(&fr->data, strlen(sn));
     1833        aimbs_putraw(&fr->data, sn, strlen(sn));
     1834
     1835        /* Grant or deny */
     1836        aimbs_put8(&fr->data, reply);
     1837
     1838        /* Message (null terminated) */
     1839        aimbs_put16(&fr->data, msg ? (strlen(msg)+1) : 0);
     1840        if (msg) {
     1841                aimbs_putraw(&fr->data, msg, strlen(msg));
     1842                aimbs_put8(&fr->data, 0x00);
     1843        }
     1844
     1845        /* Unknown */
     1846        aimbs_put16(&fr->data, 0x0000);
     1847
     1848        aim_tx_enqueue(sess, fr);
     1849
     1850        return 0;
    18281851}
    18291852
     
    18351858static int receiveauthreply(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    18361859{
    1837   int ret = 0;
    1838   aim_rxcallback_t userfunc;
    1839   fu16_t tmp;
    1840   fu8_t reply;
    1841   char *sn, *msg;
    1842  
    1843   /* Read screen name */
    1844   if ((tmp = aimbs_get8(bs)))
    1845     sn = aimbs_getstr(bs, tmp);
    1846   else
    1847     sn = NULL;
    1848  
    1849   /* Read reply */
    1850   reply = aimbs_get8(bs);
    1851  
    1852   /* Read message (null terminated) */
    1853   if ((tmp = aimbs_get16(bs)))
    1854     msg = aimbs_getstr(bs, tmp);
    1855   else
    1856     msg = NULL;
    1857  
    1858   /* Unknown */
    1859   tmp = aimbs_get16(bs);
    1860  
    1861   if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
    1862     ret = userfunc(sess, rx, sn, reply, msg);
    1863  
    1864   free(sn);
    1865   free(msg);
    1866  
    1867   return ret;
     1860        int ret = 0;
     1861        aim_rxcallback_t userfunc;
     1862        fu16_t tmp;
     1863        fu8_t reply;
     1864        char *sn, *msg;
     1865
     1866        /* Read screen name */
     1867        if ((tmp = aimbs_get8(bs)))
     1868                sn = aimbs_getstr(bs, tmp);
     1869        else
     1870                sn = NULL;
     1871
     1872        /* Read reply */
     1873        reply = aimbs_get8(bs);
     1874
     1875        /* Read message (null terminated) */
     1876        if ((tmp = aimbs_get16(bs)))
     1877                msg = aimbs_getstr(bs, tmp);
     1878        else
     1879                msg = NULL;
     1880
     1881        /* Unknown */
     1882        tmp = aimbs_get16(bs);
     1883
     1884        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1885                ret = userfunc(sess, rx, sn, reply, msg);
     1886
     1887        free(sn);
     1888        free(msg);
     1889
     1890        return ret;
    18681891}
    18691892
     
    18731896static int receiveadded(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    18741897{
    1875   int ret = 0;
    1876   aim_rxcallback_t userfunc;
    1877   fu16_t tmp;
    1878   char *sn;
    1879  
    1880   /* Read screen name */
    1881   if ((tmp = aimbs_get8(bs))) {
    1882     sn = aimbs_getstr(bs, tmp);
    1883   } else {
    1884     sn = NULL;
    1885   }
    1886  
    1887   if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) {
    1888     ret = userfunc(sess, rx, sn);
    1889   }
    1890  
    1891   free(sn);
    1892   return(ret);
     1898        int ret = 0;
     1899        aim_rxcallback_t userfunc;
     1900        fu16_t tmp;
     1901        char *sn;
     1902
     1903        /* Read screen name */
     1904        if ((tmp = aimbs_get8(bs)))
     1905                sn = aimbs_getstr(bs, tmp);
     1906        else
     1907                sn = NULL;
     1908
     1909        if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
     1910                ret = userfunc(sess, rx, sn);
     1911
     1912        free(sn);
     1913
     1914        return ret;
    18931915}
    18941916
    18951917static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
    18961918{
    1897   if (snac->subtype == AIM_CB_SSI_RIGHTSINFO) {
    1898     return parserights(sess, mod, rx, snac, bs);
    1899   } else if (snac->subtype == AIM_CB_SSI_LIST) {
    1900     return parsedata(sess, mod, rx, snac, bs);
    1901   } else if (snac->subtype == AIM_CB_SSI_ADD) {
    1902     return parseadd(sess, mod, rx, snac, bs);
    1903   } else if (snac->subtype == AIM_CB_SSI_MOD) {
    1904     return parsemod(sess, mod, rx, snac, bs);
    1905   } else if (snac->subtype == AIM_CB_SSI_DEL) {
    1906     return parsedel(sess, mod, rx, snac, bs);
    1907   } else if (snac->subtype == AIM_CB_SSI_SRVACK) {
    1908     return parseack(sess, mod, rx, snac, bs);
    1909   } else if (snac->subtype == AIM_CB_SSI_NOLIST) {
    1910     return parsedataunchanged(sess, mod, rx, snac, bs);
    1911   } else if (snac->subtype == AIM_CB_SSI_RECVAUTH) {
    1912     return receiveauthgrant(sess, mod, rx, snac, bs);
    1913   } else if (snac->subtype == AIM_CB_SSI_RECVAUTHREQ) {
    1914     return receiveauthrequest(sess, mod, rx, snac, bs);
    1915   } else if (snac->subtype == AIM_CB_SSI_RECVAUTHREP) {
    1916     return receiveauthreply(sess, mod, rx, snac, bs);
    1917   } else if (snac->subtype == AIM_CB_SSI_ADDED) {
    1918     return receiveadded(sess, mod, rx, snac, bs);
    1919   }
    1920   return(0);
     1919
     1920        if (snac->subtype == AIM_CB_SSI_RIGHTSINFO)
     1921                return parserights(sess, mod, rx, snac, bs);
     1922        else if (snac->subtype == AIM_CB_SSI_LIST)
     1923                return parsedata(sess, mod, rx, snac, bs);
     1924        else if (snac->subtype == AIM_CB_SSI_ADD)
     1925                return parseadd(sess, mod, rx, snac, bs);
     1926        else if (snac->subtype == AIM_CB_SSI_MOD)
     1927                return parsemod(sess, mod, rx, snac, bs);
     1928        else if (snac->subtype == AIM_CB_SSI_DEL)
     1929                return parsedel(sess, mod, rx, snac, bs);
     1930        else if (snac->subtype == AIM_CB_SSI_SRVACK)
     1931                return parseack(sess, mod, rx, snac, bs);
     1932        else if (snac->subtype == AIM_CB_SSI_NOLIST)
     1933                return parsedataunchanged(sess, mod, rx, snac, bs);
     1934        else if (snac->subtype == AIM_CB_SSI_RECVAUTH)
     1935                return receiveauthgrant(sess, mod, rx, snac, bs);
     1936        else if (snac->subtype == AIM_CB_SSI_RECVAUTHREQ)
     1937                return receiveauthrequest(sess, mod, rx, snac, bs);
     1938        else if (snac->subtype == AIM_CB_SSI_RECVAUTHREP)
     1939                return receiveauthreply(sess, mod, rx, snac, bs);
     1940        else if (snac->subtype == AIM_CB_SSI_ADDED)
     1941                return receiveadded(sess, mod, rx, snac, bs);
     1942
     1943        return 0;
    19211944}
    19221945
    19231946static void ssi_shutdown(aim_session_t *sess, aim_module_t *mod)
    19241947{
    1925   aim_ssi_freelist(sess);
    1926   return;
     1948        aim_ssi_freelist(sess);
    19271949}
    19281950
    19291951faim_internal int ssi_modfirst(aim_session_t *sess, aim_module_t *mod)
    19301952{
    1931  
    1932   mod->family = AIM_CB_FAM_SSI;
    1933   mod->version = 0x0004;
    1934   mod->toolid = 0x0110;
    1935   mod->toolversion = 0x0629;
    1936   mod->flags = 0;
    1937   strncpy(mod->name, "ssi", sizeof(mod->name));
    1938   mod->snachandler = snachandler;
    1939   mod->shutdown = ssi_shutdown;
    1940  
    1941   return 0;
    1942 }
     1953
     1954        mod->family = AIM_CB_FAM_SSI;
     1955        mod->version = 0x0004;
     1956        mod->toolid = 0x0110;
     1957        mod->toolversion = 0x0629;
     1958        mod->flags = 0;
     1959        strncpy(mod->name, "ssi", sizeof(mod->name));
     1960        mod->snachandler = snachandler;
     1961        mod->shutdown = ssi_shutdown;
     1962
     1963        return 0;
     1964}
Note: See TracChangeset for help on using the changeset viewer.