Changeset e374dee for libfaim/ssi.c
- Timestamp:
- Oct 10, 2003, 5:12:30 PM (20 years ago)
- Branches:
- master, barnowl_perlaim, debian, owl, release-1.10, release-1.4, release-1.5, release-1.6, release-1.7, release-1.8, release-1.9
- Children:
- fe6f1d3
- Parents:
- f4d0975
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
libfaim/ssi.c
r862371b re374dee 1 1 /* 2 * Server-Side/Stored Information. 3 * 4 * Relatively new facility that allows storing of certain types of information, 5 * such as a users buddy list, permit/deny list, and permit/deny preferences, 6 * to be stored on the server, so that they can be accessed from any client. 7 * 8 * We keep a copy of the ssi data in sess->ssi, because the data needs to be 9 * accessed for various reasons. So all the "aim_ssi_itemlist_bleh" functions 10 * near the top just manage the local data. 2 * Family 0x0013 - Server-Side/Stored Information. 3 * 4 * Relatively new facility that allows certain types of information, such as 5 * a user's buddy list, permit/deny list, and permit/deny preferences, to be 6 * stored on the server, so that they can be accessed from any client. 7 * 8 * We keep 2 copies of SSI data: 9 * 1) An exact copy of what is stored on the AIM servers. 10 * 2) A local copy that we make changes to, and then send diffs 11 * between this and the exact copy to keep them in sync. 12 * 13 * All the "aim_ssi_itemlist_bleh" functions near the top just modify the list 14 * that is given to them (i.e. they don't send SNACs). 11 15 * 12 16 * The SNAC sending and receiving functions are lower down in the file, and … … 18 22 * You don't know the half of it. 19 23 * 20 * XXX - Test for memory leaks 21 * XXX - Better parsing of rights, and use the rights info to limit adds 24 * XXX - Preserve unknown data in TLV lists 22 25 * 23 26 */ … … 27 30 28 31 /** 32 * Locally rebuild the 0x00c8 TLV in the additional data of the given group. 33 * 34 * @param list A pointer to a pointer to the current list of items. 35 * @param name A null terminated string containing the group name, or NULL 36 * if you want to modify the master group. 37 * @return Return a pointer to the modified item. 38 */ 39 static struct aim_ssi_item *aim_ssi_itemlist_rebuildgroup(struct aim_ssi_item *list, const char *name) 40 { 41 int newlen; 42 struct aim_ssi_item *cur, *group; 43 44 if (!list) 45 return NULL; 46 47 /* Find the group */ 48 if (!(group = aim_ssi_itemlist_finditem(list, name, NULL, AIM_SSI_TYPE_GROUP))) 49 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 67 /* Build the new TLV list */ 68 if (newlen > 0) { 69 fu8_t *newdata; 70 71 if (!(newdata = (fu8_t *)malloc((newlen)*sizeof(fu8_t)))) 72 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 return group; 89 } 90 91 /** 29 92 * Locally add a new item to the given item list. 30 93 * 31 94 * @param list A pointer to a pointer to the current list of items. 32 * @param parent A pointer to the parent group, or NULL if the item should have no33 * parent group (ie. the group ID# should be 0).34 95 * @param name A null terminated string of the name of the new item, or NULL if the 35 96 * item should have no name. 36 * @param type The type of the item, 0x0001 for a contact, 0x0002 for a group, etc. 37 * @return The newly created item. 38 */ 39 static struct aim_ssi_item *aim_ssi_itemlist_add(struct aim_ssi_item **list, struct aim_ssi_item *parent, const char *name, fu16_t type) 97 * @param gid The group ID# you want the new item to have, or 0xFFFF if we should pick something. 98 * @param bid The buddy ID# you want the new item to have, or 0xFFFF if we should pick something. 99 * @param type The type of the item, 0x0000 for a contact, 0x0001 for a group, etc. 100 * @param data The additional data for the new item. 101 * @return A pointer to the newly created item. 102 */ 103 static struct aim_ssi_item *aim_ssi_itemlist_add(struct aim_ssi_item **list, const char *name, fu16_t gid, fu16_t bid, fu16_t type, aim_tlvlist_t *data) 40 104 { 41 105 int i; 42 struct aim_ssi_item *cur, *newitem; 43 44 if (!(newitem = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item)))) 106 struct aim_ssi_item *cur, *new; 107 108 if (!list) 109 return NULL; 110 111 if (!(new = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item)))) 45 112 return NULL; 46 113 47 114 /* Set the name */ 48 115 if (name) { 49 if (!(newitem->name = (char *)malloc((strlen(name)+1)*sizeof(char)))) { 50 free(newitem); 51 return NULL; 52 } 53 strcpy(newitem->name, name); 116 new->name = (char *)malloc((strlen(name)+1)*sizeof(char)); 117 strcpy(new->name, name); 54 118 } else 55 new item->name = NULL;56 57 /* Set the group ID# and thebuddy ID# */58 new item->gid = 0x0000;59 new item->bid = 0x0000;119 new->name = NULL; 120 121 /* Set the group ID# and buddy ID# */ 122 new->gid = gid; 123 new->bid = bid; 60 124 if (type == AIM_SSI_TYPE_GROUP) { 61 if ( name)125 if ((new->gid == 0xFFFF) && name) { 62 126 do { 63 new item->gid += 0x0001;127 new->gid += 0x0001; 64 128 for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next) 65 if ((cur-> gid == newitem->gid) && (cur->gid == newitem->gid))129 if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid == new->gid)) 66 130 i=1; 67 131 } while (i); 132 } 68 133 } else { 69 if (parent) 70 newitem->gid = parent->gid; 71 do { 72 newitem->bid += 0x0001; 73 for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next) 74 if ((cur->bid == newitem->bid) && (cur->gid == newitem->gid)) 75 i=1; 76 } while (i); 77 } 78 79 /* Set the rest */ 80 newitem->type = type; 81 newitem->data = NULL; 82 newitem->next = *list; 83 *list = newitem; 84 85 return newitem; 86 } 87 88 /** 89 * Locally rebuild the 0x00c8 TLV in the additional data of the given group. 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; 167 } 168 169 /** 170 * Locally delete an item from the given item list. 90 171 * 91 172 * @param list A pointer to a pointer to the current list of items. 92 * @param parentgroup A pointer to the group who's additional data you want to rebuild.173 * @param del A pointer to the item you want to remove from the list. 93 174 * @return Return 0 if no errors, otherwise return the error number. 94 175 */ 95 static int aim_ssi_itemlist_rebuildgroup(struct aim_ssi_item **list, struct aim_ssi_item *parentgroup) 96 { 97 int newlen; 176 static int aim_ssi_itemlist_del(struct aim_ssi_item **list, struct aim_ssi_item *del) 177 { 178 if (!list || !(*list) || !del) 179 return -EINVAL; 180 181 /* Remove the item from the list */ 182 if (*list == del) { 183 *list = (*list)->next; 184 } else { 185 struct aim_ssi_item *cur; 186 for (cur=*list; (cur->next && (cur->next!=del)); cur=cur->next); 187 if (cur->next) 188 cur->next = cur->next->next; 189 } 190 191 /* Free the deleted item */ 192 free(del->name); 193 aim_freetlvchain(&del->data); 194 free(del); 195 196 return 0; 197 } 198 199 /** 200 * Compare two items to see if they have the same data. 201 * 202 * @param cur1 A pointer to a pointer to the first item. 203 * @param cur2 A pointer to a pointer to the second item. 204 * @return Return 0 if no differences, or a number if there are differences. 205 */ 206 static int aim_ssi_itemlist_cmp(struct aim_ssi_item *cur1, struct aim_ssi_item *cur2) 207 { 208 if (!cur1 || !cur2) 209 return 1; 210 211 if (cur1->data && !cur2->data) 212 return 2; 213 214 if (!cur1->data && cur2->data) 215 return 3; 216 217 if ((cur1->data && cur2->data) && (aim_tlvlist_cmp(cur1->data, cur2->data))) 218 return 4; 219 220 if (cur1->name && !cur2->name) 221 return 5; 222 223 if (!cur1->name && cur2->name) 224 return 6; 225 226 if (cur1->name && cur2->name && aim_sncmp(cur1->name, cur2->name)) 227 return 7; 228 229 if (cur1->gid != cur2->gid) 230 return 8; 231 232 if (cur1->bid != cur2->bid) 233 return 9; 234 235 if (cur1->type != cur2->type) 236 return 10; 237 238 return 0; 239 } 240 241 faim_export int aim_ssi_itemlist_valid(struct aim_ssi_item *list, struct aim_ssi_item *item) 242 { 98 243 struct aim_ssi_item *cur; 99 100 /* Free the old additional data */ 101 if (parentgroup->data) { 102 aim_freetlvchain((aim_tlvlist_t **)&parentgroup->data); 103 parentgroup->data = NULL; 104 } 105 106 /* Find the length for the new additional data */ 107 newlen = 0; 108 if (parentgroup->gid == 0x0000) { 109 for (cur=*list; cur; cur=cur->next) 110 if ((cur->gid != 0x0000) && (cur->type == AIM_SSI_TYPE_GROUP)) 111 newlen += 2; 112 } else { 113 for (cur=*list; cur; cur=cur->next) 114 if ((cur->gid == parentgroup->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) 115 newlen += 2; 116 } 117 118 /* Rebuild the additional data */ 119 if (newlen>0) { 120 fu8_t *newdata; 121 122 if (!(newdata = (fu8_t *)malloc((newlen)*sizeof(fu8_t)))) 123 return -ENOMEM; 124 newlen = 0; 125 if (parentgroup->gid == 0x0000) { 126 for (cur=*list; cur; cur=cur->next) 127 if ((cur->gid != 0x0000) && (cur->type == AIM_SSI_TYPE_GROUP)) 128 newlen += aimutil_put16(newdata+newlen, cur->gid); 129 } else { 130 for (cur=*list; cur; cur=cur->next) 131 if ((cur->gid == parentgroup->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) 132 newlen += aimutil_put16(newdata+newlen, cur->bid); 133 } 134 aim_addtlvtochain_raw((aim_tlvlist_t **)&(parentgroup->data), 0x00c8, newlen, newdata); 135 136 free(newdata); 137 } 138 139 return 0; 140 } 141 142 /** 143 * Locally free all of the stored buddy list information. 144 * 145 * @param sess The oscar session. 146 * @return Return 0 if no errors, otherwise return the error number. 147 */ 148 static int aim_ssi_freelist(aim_session_t *sess) 149 { 150 struct aim_ssi_item *cur, *delitem; 151 152 cur = sess->ssi.items; 153 while (cur) { 154 if (cur->name) free(cur->name); 155 if (cur->data) aim_freetlvchain((aim_tlvlist_t **)&cur->data); 156 delitem = cur; 157 cur = cur->next; 158 free(delitem); 159 } 160 161 sess->ssi.items = NULL; 162 sess->ssi.revision = 0; 163 sess->ssi.timestamp = (time_t)0; 164 244 for (cur=list; cur; cur=cur->next) 245 if (cur == item) 246 return 1; 165 247 return 0; 166 248 } … … 208 290 } 209 291 210 } else if ( sn) { /* For finding groups, permits, denies, and ignores */211 for (cur=list; cur; cur=cur->next) 212 if ((cur->type == type) && (cur-> name) && !(aim_sncmp(cur->name, sn)))292 } else if (gn) { /* For finding groups */ 293 for (cur=list; cur; cur=cur->next) { 294 if ((cur->type == type) && (cur->bid == 0x0000) && (cur->name) && !(aim_sncmp(cur->name, gn))) { 213 295 return cur; 296 } 297 } 298 299 } else if (sn) { /* For finding permits, denies, and ignores */ 300 for (cur=list; cur; cur=cur->next) { 301 if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, sn))) { 302 return cur; 303 } 304 } 214 305 215 306 /* For stuff without names--permit deny setting, visibility mask, etc. */ 216 307 } else for (cur=list; cur; cur=cur->next) { 217 if ( cur->type == type)308 if ((cur->type == type) && (!cur->name)) 218 309 return cur; 219 310 } 220 311 312 return NULL; 313 } 314 315 /** 316 * Check if the given buddy exists in any group in the buddy list. 317 * 318 * @param list A pointer to the current list of items. 319 * @param sn The group name of the desired item. 320 * @return Return a pointer to the name of the item if found, else return NULL; 321 */ 322 faim_export struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_item *list, const char *sn) 323 { 324 struct aim_ssi_item *cur; 325 if (!list || !sn) 326 return NULL; 327 for (cur=list; cur; cur=cur->next) 328 if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->name) && (!aim_sncmp(cur->name, sn))) 329 return cur; 221 330 return NULL; 222 331 } … … 227 336 * @param list A pointer to the current list of items. 228 337 * @param bn The buddy name of the desired item. 229 * @return Return a pointer to the item if found, else return NULL;230 */ 231 faim_export struct aim_ssi_item *aim_ssi_itemlist_findparent(struct aim_ssi_item *list,char *sn)338 * @return Return a pointer to the name of the item if found, else return NULL; 339 */ 340 faim_export char *aim_ssi_itemlist_findparentname(struct aim_ssi_item *list, const char *sn) 232 341 { 233 342 struct aim_ssi_item *cur, *curg; 234 343 if (!list || !sn) 235 344 return NULL; 236 if (!(cur = aim_ssi_itemlist_ finditem(list, NULL, sn, AIM_SSI_TYPE_BUDDY)))345 if (!(cur = aim_ssi_itemlist_exists(list, sn))) 237 346 return NULL; 238 for (curg=list; curg; curg=curg->next) 239 if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid)) 240 return curg; 241 return NULL; 347 if (!(curg = aim_ssi_itemlist_find(list, cur->gid, 0x0000))) 348 return NULL; 349 return curg->name; 242 350 } 243 351 … … 285 393 286 394 /** 287 * Add the given packet to the holding queue. We totally need to send SSI SNACs one at 288 * a time, so we have a local queue where packets get put before they are sent, and 289 * then we send stuff one at a time, nice and orderly-like. 395 * Locally find the alias of the given buddy. 396 * 397 * @param list A pointer to the current list of items. 398 * @param gn The group of the buddy. 399 * @param sn The name of the buddy. 400 * @return A pointer to a NULL terminated string that is the buddies 401 * alias, or NULL if the buddy has no alias. You should free 402 * this returned value! 403 */ 404 faim_export char *aim_ssi_getalias(struct aim_ssi_item *list, const char *gn, const char *sn) 405 { 406 struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY); 407 if (cur) { 408 aim_tlvlist_t *tlvlist = cur->data; 409 if (tlvlist) { 410 aim_tlv_t *tlv = aim_gettlv(tlvlist, 0x0131, 1); 411 if (tlv && tlv->length) { 412 char *alias = (char *)malloc((tlv->length+1)*sizeof(char)); 413 strncpy(alias, tlv->value, tlv->length); 414 alias[tlv->length] = 0; 415 return alias; 416 } 417 } 418 } 419 return NULL; 420 } 421 422 /** 423 * Locally find if you are waiting for authorization for a buddy. 424 * 425 * @param list A pointer to the current list of items. 426 * @param gn The group of the buddy. 427 * @param sn The name of the buddy. 428 * @return A pointer to a NULL terminated string that is the buddies 429 * alias, or NULL if the buddy has no alias. You should free 430 * this returned value! 431 */ 432 faim_export int aim_ssi_waitingforauth(struct aim_ssi_item *list, const char *gn, const char *sn) 433 { 434 struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY); 435 if (cur) { 436 aim_tlvlist_t *tlvlist = cur->data; 437 if (tlvlist) 438 if (aim_gettlv(tlvlist, 0x0066, 1)) 439 return 1; 440 } 441 return 0; 442 } 443 444 /** 445 * If there are changes, then create temporary items and 446 * call addmoddel. 290 447 * 291 448 * @param sess The oscar session. 292 * @param conn The bos connection for this session.293 * @param fr The newly created SNAC that you want to send.294 449 * @return Return 0 if no errors, otherwise return the error number. 295 450 */ 296 static int aim_ssi_enqueue(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *fr) 297 { 298 aim_frame_t *cur; 299 300 if (!sess || !conn || !fr) 301 return -EINVAL; 302 303 fr->next = NULL; 304 if (sess->ssi.holding_queue == NULL) { 305 sess->ssi.holding_queue = fr; 306 if (!sess->ssi.waiting_for_ack) 307 aim_ssi_modbegin(sess, conn); 308 } else { 309 for (cur = sess->ssi.holding_queue; cur->next; cur = cur->next) ; 310 cur->next = fr; 311 } 312 313 return 0; 314 } 315 316 /** 317 * Send the next SNAC from the holding queue. This is called 318 * automatically when an ack from an add, mod, or del is received. 319 * If the queue is empty, it sends the modend SNAC. 451 static int aim_ssi_sync(aim_session_t *sess) 452 { 453 struct aim_ssi_item *cur1, *cur2; 454 struct aim_ssi_tmp *cur, *new; 455 456 if (!sess) 457 return -EINVAL; 458 459 /* If we're waiting for an ack, we shouldn't do anything else */ 460 if (sess->ssi.waiting_for_ack) 461 return 0; 462 463 /* 464 * Compare the 2 lists and create an aim_ssi_tmp for each difference. 465 * We should only send either additions, modifications, or deletions 466 * before waiting for an acknowledgement. So first do deletions, then 467 * additions, then modifications. Also, both the official and the local 468 * list should be in ascending numerical order for the group ID#s and the 469 * buddy ID#s, which makes things more efficient. I think. 470 */ 471 472 /* Additions */ 473 if (!sess->ssi.pending) { 474 for (cur1=sess->ssi.local; cur1; cur1=cur1->next) { 475 if (!aim_ssi_itemlist_find(sess->ssi.official, cur1->gid, cur1->bid)) { 476 new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp)); 477 new->action = AIM_CB_SSI_ADD; 478 new->ack = 0xffff; 479 new->name = NULL; 480 new->item = cur1; 481 new->next = NULL; 482 if (sess->ssi.pending) { 483 for (cur=sess->ssi.pending; cur->next; cur=cur->next); 484 cur->next = new; 485 } else 486 sess->ssi.pending = new; 487 } 488 } 489 } 490 491 /* Deletions */ 492 if (!sess->ssi.pending) { 493 for (cur1=sess->ssi.official; cur1; cur1=cur1->next) { 494 if (!aim_ssi_itemlist_find(sess->ssi.local, cur1->gid, cur1->bid)) { 495 new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp)); 496 new->action = AIM_CB_SSI_DEL; 497 new->ack = 0xffff; 498 new->name = NULL; 499 new->item = cur1; 500 new->next = NULL; 501 if (sess->ssi.pending) { 502 for (cur=sess->ssi.pending; cur->next; cur=cur->next); 503 cur->next = new; 504 } else 505 sess->ssi.pending = new; 506 } 507 } 508 } 509 510 /* Modifications */ 511 if (!sess->ssi.pending) { 512 for (cur1=sess->ssi.local; cur1; cur1=cur1->next) { 513 cur2 = aim_ssi_itemlist_find(sess->ssi.official, cur1->gid, cur1->bid); 514 if (cur2 && (aim_ssi_itemlist_cmp(cur1, cur2))) { 515 new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp)); 516 new->action = AIM_CB_SSI_MOD; 517 new->ack = 0xffff; 518 new->name = NULL; 519 new->item = cur1; 520 new->next = NULL; 521 if (sess->ssi.pending) { 522 for (cur=sess->ssi.pending; cur->next; cur=cur->next); 523 cur->next = new; 524 } else 525 sess->ssi.pending = new; 526 } 527 } 528 } 529 530 /* We're out of stuff to do, so tell the AIM servers we're done and exit */ 531 if (!sess->ssi.pending) { 532 aim_ssi_modend(sess); 533 return 0; 534 } 535 536 /* Make sure we don't send anything else between now 537 * and when we receive the ack for the following operation */ 538 sess->ssi.waiting_for_ack = 1; 539 540 /* Now go mail off our data and wait 4 to 6 weeks */ 541 aim_ssi_addmoddel(sess); 542 543 return 0; 544 } 545 546 /** 547 * Free all SSI data. 548 * 549 * This doesn't remove it from the server, that's different. 320 550 * 321 551 * @param sess The oscar session. 322 * @param conn The bos connection for this session.323 552 * @return Return 0 if no errors, otherwise return the error number. 324 553 */ 325 static int aim_ssi_dispatch(aim_session_t *sess, aim_conn_t *conn) 326 { 327 aim_frame_t *cur; 328 329 if (!sess || !conn) 330 return -EINVAL; 331 332 if (!sess->ssi.waiting_for_ack) { 333 if (sess->ssi.holding_queue) { 334 sess->ssi.waiting_for_ack = 1; 335 cur = sess->ssi.holding_queue->next; 336 sess->ssi.holding_queue->next = NULL; 337 aim_tx_enqueue(sess, sess->ssi.holding_queue); 338 sess->ssi.holding_queue = cur; 339 } else 340 aim_ssi_modend(sess, conn); 341 } 342 343 return 0; 344 } 345 346 /** 347 * Send SNACs necessary to remove all SSI data from the server list, 348 * and then free the local copy as well. 554 static int aim_ssi_freelist(aim_session_t *sess) 555 { 556 struct aim_ssi_item *cur, *del; 557 struct aim_ssi_tmp *curtmp, *deltmp; 558 559 cur = sess->ssi.official; 560 while (cur) { 561 del = cur; 562 cur = cur->next; 563 free(del->name); 564 aim_freetlvchain(&del->data); 565 free(del); 566 } 567 568 cur = sess->ssi.local; 569 while (cur) { 570 del = cur; 571 cur = cur->next; 572 free(del->name); 573 aim_freetlvchain(&del->data); 574 free(del); 575 } 576 577 curtmp = sess->ssi.pending; 578 while (curtmp) { 579 deltmp = curtmp; 580 curtmp = curtmp->next; 581 free(deltmp); 582 } 583 584 sess->ssi.numitems = 0; 585 sess->ssi.official = NULL; 586 sess->ssi.local = NULL; 587 sess->ssi.pending = NULL; 588 sess->ssi.timestamp = (time_t)0; 589 590 return 0; 591 } 592 593 /** 594 * Delete all SSI data. 349 595 * 350 596 * @param sess The oscar session. 351 * @param conn The bos connection for this session.352 597 * @return Return 0 if no errors, otherwise return the error number. 353 598 */ 354 faim_export int aim_ssi_deletelist(aim_session_t *sess, aim_conn_t *conn) 355 { 356 int num; 357 struct aim_ssi_item *cur, **items; 358 359 for (cur=sess->ssi.items, num=0; cur; cur=cur->next) 360 num++; 361 362 if (!(items = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)))) 363 return -ENOMEM; 364 memset(items, 0, num*sizeof(struct aim_ssi_item *)); 365 for (cur=sess->ssi.items, num=0; cur; cur=cur->next) { 366 items[num] = cur; 367 num++; 368 } 369 370 aim_ssi_addmoddel(sess, conn, items, num, AIM_CB_SSI_DEL); 371 free(items); 372 aim_ssi_dispatch(sess, conn); 373 aim_ssi_freelist(sess); 374 375 return 0; 376 } 377 378 /** 379 * This "cleans" the ssi list. It does a few things, with the intent of making 380 * sure there ain't nothin' wrong with your SSI. 381 * -Make sure all buddies are in a group, and all groups have the correct 382 * additional data. 383 * -Make sure there are no empty groups in the list. While there is nothing 384 * wrong empty groups in the SSI, it's wiser to not have them. 599 faim_export int aim_ssi_deletelist(aim_session_t *sess) 600 { 601 struct aim_ssi_item *cur, *del; 602 603 if (!sess) 604 return -EINVAL; 605 606 /* Free the local list */ 607 cur = sess->ssi.local; 608 while (cur) { 609 del = cur; 610 cur = cur->next; 611 free(del->name); 612 aim_freetlvchain(&del->data); 613 free(del); 614 } 615 sess->ssi.local = NULL; 616 617 /* Sync our local list with the server list */ 618 aim_ssi_sync(sess); 619 620 return 0; 621 } 622 623 /** 624 * This "cleans" the ssi list. It does the following: 625 * 1) Makes sure all buddies, permits, and denies have names. 626 * 2) Makes sure that all buddies are in a group that exist. 627 * 3) Deletes any empty groups 385 628 * 386 629 * @param sess The oscar session. 387 * @param conn The bos connection for this session.388 630 * @return Return 0 if no errors, otherwise return the error number. 389 631 */ 390 faim_export int aim_ssi_cleanlist(aim_session_t *sess, aim_conn_t *conn) 391 { 392 unsigned int i; 393 struct aim_ssi_item *cur, *parentgroup; 394 395 /* Make sure we actually need to clean out the list */ 396 for (cur=sess->ssi.items, i=0; cur && !i; cur=cur->next) 397 /* Any buddies directly in the master group */ 398 if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->gid == 0x0000)) 399 i++; 400 if (!i) 401 return 0; 402 403 /* Remove all the additional data from all groups */ 404 for (cur=sess->ssi.items; cur; cur=cur->next) 405 if ((cur->data) && (cur->type == AIM_SSI_TYPE_GROUP)) { 406 aim_freetlvchain((aim_tlvlist_t **)&cur->data); 407 cur->data = NULL; 632 faim_export int aim_ssi_cleanlist(aim_session_t *sess) 633 { 634 struct aim_ssi_item *cur, *next; 635 636 if (!sess) 637 return -EINVAL; 638 639 /* Delete any buddies, permits, or denies with empty names. */ 640 /* If there are any buddies directly in the master group, add them to a real group. */ 641 /* DESTROY any buddies that are directly in the master group. */ 642 /* Do the same for buddies that are in a non-existant group. */ 643 /* This will kind of mess up if you hit the item limit, but this function isn't too critical */ 644 cur = sess->ssi.local; 645 while (cur) { 646 next = cur->next; 647 if (!cur->name) { 648 if (cur->type == AIM_SSI_TYPE_BUDDY) 649 aim_ssi_delbuddy(sess, NULL, NULL); 650 else if (cur->type == AIM_SSI_TYPE_PERMIT) 651 aim_ssi_delpermit(sess, NULL); 652 else if (cur->type == AIM_SSI_TYPE_DENY) 653 aim_ssi_deldeny(sess, NULL); 654 } else if ((cur->type == AIM_SSI_TYPE_BUDDY) && ((cur->gid == 0x0000) || (!aim_ssi_itemlist_find(sess->ssi.local, cur->gid, 0x0000)))) { 655 aim_ssi_addbuddy(sess, cur->name, "orphans", NULL, NULL, NULL, 0); 656 aim_ssi_delbuddy(sess, cur->name, NULL); 408 657 } 409 410 /* If there are buddies directly in the master group, make sure */411 /* there is a group to put them in. Any group, any group at all. */ 412 for (cur=sess->ssi.items; ((cur) && ((cur->type != AIM_SSI_TYPE_BUDDY) || (cur->gid != 0x0000))); cur=cur->next);413 if (!cur) {414 for (parentgroup=sess->ssi.items; ((parentgroup) && (parentgroup->type!=AIM_SSI_TYPE_GROUP) && (parentgroup->gid==0x0000)); parentgroup=parentgroup->next);415 if (!parentgroup) {416 char *newgroup;417 newgroup = (char*)malloc(strlen("Unknown")*sizeof(char));418 strcpy(newgroup, "Unknown");419 aim_ssi_addgroups(sess, conn, (const char**)&newgroup, 1);658 cur = next; 659 } 660 661 /* Check if there are empty groups and delete them */ 662 cur = sess->ssi.local; 663 while (cur) { 664 next = cur->next; 665 if (cur->type == AIM_SSI_TYPE_GROUP) { 666 aim_tlv_t *tlv = aim_gettlv(cur->data, 0x00c8, 1); 667 if (!tlv || !tlv->length) 668 aim_ssi_itemlist_del(&sess->ssi.local, cur); 420 669 } 421 } 422 423 /* Set parentgroup equal to any arbitray group */ 424 for (parentgroup=sess->ssi.items; parentgroup->gid==0x0000 || parentgroup->type!=AIM_SSI_TYPE_GROUP; parentgroup=parentgroup->next); 425 426 /* If there are any buddies directly in the master group, put them in a real group */ 427 for (cur=sess->ssi.items; cur; cur=cur->next) 428 if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->gid == 0x0000)) { 429 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_DEL); 430 cur->gid = parentgroup->gid; 431 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_ADD); 670 cur = next; 671 } 672 673 /* Check if the master group is empty */ 674 if ((cur = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000)) && (!cur->data)) 675 aim_ssi_itemlist_del(&sess->ssi.local, cur); 676 677 return 0; 678 } 679 680 /** 681 * Add a buddy to the list. 682 * 683 * @param sess The oscar session. 684 * @param name The name of the item. 685 * @param group The group of the item. 686 * @param alias The alias/nickname of the item, or NULL. 687 * @param comment The buddy comment for the item, or NULL. 688 * @param smsnum The locally assigned SMS number, or NULL. 689 * @return Return 0 if no errors, otherwise return the error number. 690 */ 691 faim_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) 692 { 693 struct aim_ssi_item *parent; 694 aim_tlvlist_t *data = NULL; 695 696 if (!sess || !name || !group) 697 return -EINVAL; 698 699 /* Find the parent */ 700 if (!(parent = aim_ssi_itemlist_finditem(sess->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP))) { 701 /* Find the parent's parent (the master group) */ 702 if (!(parent = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000))) 703 if (!(parent = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL))) 704 return -ENOMEM; 705 /* Add the parent */ 706 if (!(parent = aim_ssi_itemlist_add(&sess->ssi.local, group, 0xFFFF, 0x0000, AIM_SSI_TYPE_GROUP, NULL))) 707 return -ENOMEM; 708 709 /* Modify the parent's parent (the master group) */ 710 aim_ssi_itemlist_rebuildgroup(sess->ssi.local, NULL); 711 } 712 713 /* Create a TLV list for the new buddy */ 714 if (needauth) 715 aim_addtlvtochain_noval(&data, 0x0066); 716 if (alias) 717 aim_addtlvtochain_raw(&data, 0x0131, strlen(alias), alias); 718 if (smsnum) 719 aim_addtlvtochain_raw(&data, 0x013a, strlen(smsnum), smsnum); 720 if (comment) 721 aim_addtlvtochain_raw(&data, 0x013c, strlen(comment), comment); 722 723 /* Add that bad boy */ 724 aim_ssi_itemlist_add(&sess->ssi.local, name, parent->gid, 0xFFFF, AIM_SSI_TYPE_BUDDY, data); 725 aim_freetlvchain(&data); 726 727 /* Modify the parent group */ 728 aim_ssi_itemlist_rebuildgroup(sess->ssi.local, group); 729 730 /* Sync our local list with the server list */ 731 aim_ssi_sync(sess); 732 733 return 0; 734 } 735 736 /** 737 * Add a permit buddy to the list. 738 * 739 * @param sess The oscar session. 740 * @param name The name of the item.. 741 * @return Return 0 if no errors, otherwise return the error number. 742 */ 743 faim_export int aim_ssi_addpermit(aim_session_t *sess, const char *name) 744 { 745 746 if (!sess || !name) 747 return -EINVAL; 748 749 /* Add that bad boy */ 750 aim_ssi_itemlist_add(&sess->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_PERMIT, NULL); 751 752 /* Sync our local list with the server list */ 753 aim_ssi_sync(sess); 754 755 return 0; 756 } 757 758 /** 759 * Add a deny buddy to the list. 760 * 761 * @param sess The oscar session. 762 * @param name The name of the item.. 763 * @return Return 0 if no errors, otherwise return the error number. 764 */ 765 faim_export int aim_ssi_adddeny(aim_session_t *sess, const char *name) 766 { 767 768 if (!sess || !name) 769 return -EINVAL; 770 771 /* Add that bad boy */ 772 aim_ssi_itemlist_add(&sess->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_DENY, NULL); 773 774 /* Sync our local list with the server list */ 775 aim_ssi_sync(sess); 776 777 return 0; 778 } 779 780 /** 781 * Deletes a buddy from the list. 782 * 783 * @param sess The oscar session. 784 * @param name The name of the item, or NULL. 785 * @param group The group of the item, or NULL. 786 * @return Return 0 if no errors, otherwise return the error number. 787 */ 788 faim_export int aim_ssi_delbuddy(aim_session_t *sess, const char *name, const char *group) 789 { 790 struct aim_ssi_item *del; 791 792 if (!sess) 793 return -EINVAL; 794 795 /* Find the buddy */ 796 if (!(del = aim_ssi_itemlist_finditem(sess->ssi.local, group, name, AIM_SSI_TYPE_BUDDY))) 797 return -EINVAL; 798 799 /* Remove the item from the list */ 800 aim_ssi_itemlist_del(&sess->ssi.local, del); 801 802 /* Modify the parent group */ 803 aim_ssi_itemlist_rebuildgroup(sess->ssi.local, group); 804 805 /* Check if we should delete the parent group */ 806 if ((del = aim_ssi_itemlist_finditem(sess->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP)) && (!del->data)) { 807 aim_ssi_itemlist_del(&sess->ssi.local, del); 808 809 /* Modify the parent group */ 810 aim_ssi_itemlist_rebuildgroup(sess->ssi.local, NULL); 811 812 /* Check if we should delete the parent's parent (the master group) */ 813 if ((del = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000)) && (!del->data)) { 814 aim_ssi_itemlist_del(&sess->ssi.local, del); 432 815 } 433 434 /* Rebuild additional data for all groups */ 435 for (parentgroup=sess->ssi.items; parentgroup; parentgroup=parentgroup->next) 436 if (parentgroup->type == AIM_SSI_TYPE_GROUP) 437 aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup); 438 439 /* Send a mod snac for all groups */ 440 i = 0; 441 for (cur=sess->ssi.items; cur; cur=cur->next) 442 if (cur->type == AIM_SSI_TYPE_GROUP) 443 i++; 444 if (i > 0) { 445 /* Allocate an array of pointers to each of the groups */ 446 struct aim_ssi_item **groups; 447 if (!(groups = (struct aim_ssi_item **)malloc(i*sizeof(struct aim_ssi_item *)))) 448 return -ENOMEM; 449 450 for (cur=sess->ssi.items, i=0; cur; cur=cur->next) 451 if (cur->type == AIM_SSI_TYPE_GROUP) 452 groups[i] = cur; 453 454 aim_ssi_addmoddel(sess, conn, groups, i, AIM_CB_SSI_MOD); 455 free(groups); 456 } 457 458 /* Send a del snac for any empty groups */ 459 i = 0; 460 for (cur=sess->ssi.items; cur; cur=cur->next) 461 if ((cur->type == AIM_SSI_TYPE_GROUP) && !(cur->data)) 462 i++; 463 if (i > 0) { 464 /* Allocate an array of pointers to each of the groups */ 465 struct aim_ssi_item **groups; 466 if (!(groups = (struct aim_ssi_item **)malloc(i*sizeof(struct aim_ssi_item *)))) 467 return -ENOMEM; 468 469 for (cur=sess->ssi.items, i=0; cur; cur=cur->next) 470 if ((cur->type == AIM_SSI_TYPE_GROUP) && !(cur->data)) 471 groups[i] = cur; 472 473 aim_ssi_addmoddel(sess, conn, groups, i, AIM_CB_SSI_DEL); 474 free(groups); 475 } 476 477 /* Begin sending SSI SNACs */ 478 aim_ssi_dispatch(sess, conn); 479 480 return 0; 481 } 482 483 /** 484 * Add an array of screen names to the given group. 816 } 817 818 /* Sync our local list with the server list */ 819 aim_ssi_sync(sess); 820 821 return 0; 822 } 823 824 /** 825 * Deletes a permit buddy from the list. 485 826 * 486 827 * @param sess The oscar session. 487 * @param conn The bos connection for this session. 488 * @param gn The name of the group to which you want to add these names. 489 * @param sn An array of null terminated strings of the names you want to add. 490 * @param num The number of screen names you are adding (size of the sn array). 828 * @param name The name of the item, or NULL. 491 829 * @return Return 0 if no errors, otherwise return the error number. 492 830 */ 493 faim_export int aim_ssi_addbuddies(aim_session_t *sess, aim_conn_t *conn, const char *gn, const char **sn, unsigned int num) 494 { 495 struct aim_ssi_item *parentgroup, **newitems; 496 fu16_t i; 497 498 if (!sess || !conn || !gn || !sn || !num) 499 return -EINVAL; 500 501 /* Look up the parent group */ 502 if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn, AIM_SSI_TYPE_GROUP))) { 503 aim_ssi_addgroups(sess, conn, (const char **)&gn, 1); 504 if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn, AIM_SSI_TYPE_GROUP))) 505 return -ENOMEM; 506 } 507 508 /* Allocate an array of pointers to each of the new items */ 509 if (!(newitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)))) 510 return -ENOMEM; 511 512 /* Add items to the local list, and index them in the array */ 513 for (i=0; i<num; i++) 514 if (!(newitems[i] = aim_ssi_itemlist_add(&sess->ssi.items, parentgroup, sn[i], AIM_SSI_TYPE_BUDDY))) { 515 free(newitems); 516 return -ENOMEM; 517 } 518 519 /* Send the add item SNAC */ 520 if ((i = aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD))) { 521 free(newitems); 522 return -i; 523 } 524 525 /* Free the array of pointers to each of the new items */ 526 free(newitems); 527 528 /* Rebuild the additional data in the parent group */ 529 if ((i = aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup))) 530 return i; 531 532 /* Send the mod item SNAC */ 533 if ((i = aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD))) 534 return i; 535 536 /* Begin sending SSI SNACs */ 537 if (!(i = aim_ssi_dispatch(sess, conn))) 538 return i; 539 540 return 0; 541 } 542 543 /** 544 * Add the master group (the group containing all groups). This is called by 545 * aim_ssi_addgroups, if necessary. 831 faim_export int aim_ssi_delpermit(aim_session_t *sess, const char *name) 832 { 833 struct aim_ssi_item *del; 834 835 if (!sess) 836 return -EINVAL; 837 838 /* Find the item */ 839 if (!(del = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, name, AIM_SSI_TYPE_PERMIT))) 840 return -EINVAL; 841 842 /* Remove the item from the list */ 843 aim_ssi_itemlist_del(&sess->ssi.local, del); 844 845 /* Sync our local list with the server list */ 846 aim_ssi_sync(sess); 847 848 return 0; 849 } 850 851 /** 852 * Deletes a deny buddy from the list. 546 853 * 547 854 * @param sess The oscar session. 548 * @param conn The bos connection for this session.855 * @param name The name of the item, or NULL. 549 856 * @return Return 0 if no errors, otherwise return the error number. 550 857 */ 551 faim_export int aim_ssi_addmastergroup(aim_session_t *sess, aim_conn_t *conn) 552 { 553 struct aim_ssi_item *newitem; 554 555 if (!sess || !conn) 556 return -EINVAL; 557 558 /* Add the item to the local list, and keep a pointer to it */ 559 if (!(newitem = aim_ssi_itemlist_add(&sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_GROUP))) 560 return -ENOMEM; 561 562 /* If there are any existing groups (technically there shouldn't be, but */ 563 /* just in case) then add their group ID#'s to the additional data */ 564 aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, newitem); 565 566 /* Send the add item SNAC */ 567 aim_ssi_addmoddel(sess, conn, &newitem, 1, AIM_CB_SSI_ADD); 568 569 /* Begin sending SSI SNACs */ 570 aim_ssi_dispatch(sess, conn); 571 572 return 0; 573 } 574 575 /** 576 * Add an array of groups to the list. 577 * 578 * @param sess The oscar session. 579 * @param conn The bos connection for this session. 580 * @param gn An array of null terminated strings of the names you want to add. 581 * @param num The number of groups names you are adding (size of the sn array). 582 * @return Return 0 if no errors, otherwise return the error number. 583 */ 584 faim_export int aim_ssi_addgroups(aim_session_t *sess, aim_conn_t *conn, const char **gn, unsigned int num) 585 { 586 struct aim_ssi_item *parentgroup, **newitems; 587 fu16_t i; 588 589 if (!sess || !conn || !gn || !num) 590 return -EINVAL; 591 592 /* Look up the parent group */ 593 if (!(parentgroup = aim_ssi_itemlist_find(sess->ssi.items, 0, 0))) { 594 aim_ssi_addmastergroup(sess, conn); 595 if (!(parentgroup = aim_ssi_itemlist_find(sess->ssi.items, 0, 0))) 596 return -ENOMEM; 597 } 598 599 /* Allocate an array of pointers to each of the new items */ 600 if (!(newitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)))) 601 return -ENOMEM; 602 603 /* Add items to the local list, and index them in the array */ 604 for (i=0; i<num; i++) 605 if (!(newitems[i] = aim_ssi_itemlist_add(&sess->ssi.items, parentgroup, gn[i], AIM_SSI_TYPE_GROUP))) { 606 free(newitems); 607 return -ENOMEM; 608 } 609 610 /* Send the add item SNAC */ 611 if ((i = aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD))) { 612 free(newitems); 613 return -i; 614 } 615 616 /* Free the array of pointers to each of the new items */ 617 free(newitems); 618 619 /* Rebuild the additional data in the parent group */ 620 if ((i = aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup))) 621 return i; 622 623 /* Send the mod item SNAC */ 624 if ((i = aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD))) 625 return i; 626 627 /* Begin sending SSI SNACs */ 628 if (!(i = aim_ssi_dispatch(sess, conn))) 629 return i; 630 631 return 0; 632 } 633 634 /** 635 * Add an array of a certain type of item to the list. This can be used for 636 * permit buddies, deny buddies, ICQ's ignore buddies, and probably other 637 * types, also. 638 * 639 * @param sess The oscar session. 640 * @param conn The bos connection for this session. 641 * @param sn An array of null terminated strings of the names you want to add. 642 * @param num The number of groups names you are adding (size of the sn array). 643 * @param type The type of item you want to add. See the AIM_SSI_TYPE_BLEH 644 * #defines in aim.h. 645 * @return Return 0 if no errors, otherwise return the error number. 646 */ 647 faim_export int aim_ssi_addpord(aim_session_t *sess, aim_conn_t *conn, const char **sn, unsigned int num, fu16_t type) 648 { 649 struct aim_ssi_item **newitems; 650 fu16_t i; 651 652 if (!sess || !conn || !sn || !num) 653 return -EINVAL; 654 655 /* Allocate an array of pointers to each of the new items */ 656 if (!(newitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)))) 657 return -ENOMEM; 658 659 /* Add items to the local list, and index them in the array */ 660 for (i=0; i<num; i++) 661 if (!(newitems[i] = aim_ssi_itemlist_add(&sess->ssi.items, NULL, sn[i], type))) { 662 free(newitems); 663 return -ENOMEM; 664 } 665 666 /* Send the add item SNAC */ 667 if ((i = aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD))) { 668 free(newitems); 669 return -i; 670 } 671 672 /* Free the array of pointers to each of the new items */ 673 free(newitems); 674 675 /* Begin sending SSI SNACs */ 676 if (!(i = aim_ssi_dispatch(sess, conn))) 677 return i; 858 faim_export int aim_ssi_deldeny(aim_session_t *sess, const char *name) 859 { 860 struct aim_ssi_item *del; 861 862 if (!sess) 863 return -EINVAL; 864 865 /* Find the item */ 866 if (!(del = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, name, AIM_SSI_TYPE_DENY))) 867 return -EINVAL; 868 869 /* Remove the item from the list */ 870 aim_ssi_itemlist_del(&sess->ssi.local, del); 871 872 /* Sync our local list with the server list */ 873 aim_ssi_sync(sess); 678 874 679 875 return 0; … … 685 881 * 686 882 * @param sess The oscar session. 687 * @param conn The bos connection for this session.688 883 * @param oldgn The group that the buddy is currently in. 689 884 * @param newgn The group that the buddy should be moved in to. … … 691 886 * @return Return 0 if no errors, otherwise return the error number. 692 887 */ 693 faim_export int aim_ssi_movebuddy(aim_session_t *sess, aim_conn_t *conn, const char *oldgn, const char *newgn, const char *sn) 694 { 695 struct aim_ssi_item **groups, *buddy, *cur; 696 fu16_t i; 697 698 if (!sess || !conn || !oldgn || !newgn || !sn) 699 return -EINVAL; 700 701 /* Look up the buddy */ 702 if (!(buddy = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, sn, AIM_SSI_TYPE_BUDDY))) 703 return -ENOMEM; 704 705 /* Allocate an array of pointers to the two groups */ 706 if (!(groups = (struct aim_ssi_item **)malloc(2*sizeof(struct aim_ssi_item *)))) 707 return -ENOMEM; 708 709 /* Look up the old parent group */ 710 if (!(groups[0] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, oldgn, AIM_SSI_TYPE_GROUP))) { 711 free(groups); 712 return -ENOMEM; 713 } 714 715 /* Look up the new parent group */ 716 if (!(groups[1] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, newgn, AIM_SSI_TYPE_GROUP))) { 717 aim_ssi_addgroups(sess, conn, (const char**)&newgn, 1); 718 if (!(groups[1] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, newgn, AIM_SSI_TYPE_GROUP))) { 719 free(groups); 720 return -ENOMEM; 721 } 722 } 723 724 /* Send the delete item SNAC */ 725 aim_ssi_addmoddel(sess, conn, &buddy, 1, AIM_CB_SSI_DEL); 726 727 /* Put the buddy in the new group */ 728 buddy->gid = groups[1]->gid; 729 730 /* Assign a new buddy ID#, because the new group might already have a buddy with this ID# */ 731 buddy->bid = 0; 732 do { 733 buddy->bid += 0x0001; 734 for (cur=sess->ssi.items, i=0; ((cur) && (!i)); cur=cur->next) 735 if ((cur->bid == buddy->bid) && (cur->gid == buddy->gid) && (cur->type == AIM_SSI_TYPE_BUDDY) && (cur->name) && aim_sncmp(cur->name, buddy->name)) 736 i=1; 737 } while (i); 738 739 /* Rebuild the additional data in the two parent groups */ 740 aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, groups[0]); 741 aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, groups[1]); 742 743 /* Send the add item SNAC */ 744 aim_ssi_addmoddel(sess, conn, &buddy, 1, AIM_CB_SSI_ADD); 745 746 /* Send the mod item SNAC */ 747 aim_ssi_addmoddel(sess, conn, groups, 2, AIM_CB_SSI_MOD); 748 749 /* Free the temporary array */ 750 free(groups); 751 752 /* Begin sending SSI SNACs */ 753 aim_ssi_dispatch(sess, conn); 754 755 return 0; 756 } 757 758 /** 759 * Rename a group. I really like how this is done. It turns me on. 760 * 761 * Did I say that out loud?... 888 faim_export int aim_ssi_movebuddy(aim_session_t *sess, const char *oldgn, const char *newgn, const char *sn) 889 { 890 aim_ssi_addbuddy(sess, sn, newgn, aim_ssi_getalias(sess->ssi.local, oldgn, sn), NULL, NULL, aim_ssi_waitingforauth(sess->ssi.local, oldgn, sn)); 891 aim_ssi_delbuddy(sess, sn, oldgn); 892 return 0; 893 } 894 895 /** 896 * Change the alias stored on the server for a given buddy. 762 897 * 763 898 * @param sess The oscar session. 764 * @param conn The bos connection for this session. 899 * @param gn The group that the buddy is currently in. 900 * @param sn The screen name of the buddy. 901 * @param alias The new alias for the buddy. 902 * @return Return 0 if no errors, otherwise return the error number. 903 */ 904 faim_export int aim_ssi_aliasbuddy(aim_session_t *sess, const char *gn, const char *sn, const char *alias) 905 { 906 struct aim_ssi_item *tmp; 907 aim_tlvlist_t *data = NULL; 908 909 if (!sess || !gn || !sn) 910 return -EINVAL; 911 912 if (!(tmp = aim_ssi_itemlist_finditem(sess->ssi.local, gn, sn, AIM_SSI_TYPE_BUDDY))) 913 return -EINVAL; 914 915 if (alias && !strlen(alias)) 916 alias = NULL; 917 918 /* Need to add the x0131 TLV to the TLV chain */ 919 if (alias) 920 aim_addtlvtochain_raw(&data, 0x0131, strlen(alias), alias); 921 922 aim_freetlvchain(&tmp->data); 923 tmp->data = data; 924 925 /* Sync our local list with the server list */ 926 aim_ssi_sync(sess); 927 928 return 0; 929 } 930 931 /** 932 * Rename a group. 933 * 934 * @param sess The oscar session. 765 935 * @param oldgn The old group name. 766 936 * @param newgn The new group name. 767 937 * @return Return 0 if no errors, otherwise return the error number. 768 938 */ 769 faim_export int aim_ssi_rename_group(aim_session_t *sess, aim_conn_t *conn,const char *oldgn, const char *newgn)939 faim_export int aim_ssi_rename_group(aim_session_t *sess, const char *oldgn, const char *newgn) 770 940 { 771 941 struct aim_ssi_item *group; 772 942 773 if (!sess || !conn || !oldgn || !newgn) 774 return -EINVAL; 775 776 /* Look up the group */ 777 if (!(group = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, oldgn, AIM_SSI_TYPE_GROUP))) 778 return -ENOMEM; 779 780 /* Free the old group name and copy the new one in its place. */ 781 if (group->name) 782 free(group->name); 783 if (!(group->name = (char *)malloc((strlen(newgn)+1)*sizeof(char)))) { 784 group->name = NULL; 785 return -ENOMEM; 786 } 943 if (!sess || !oldgn || !newgn) 944 return -EINVAL; 945 946 if (!(group = aim_ssi_itemlist_finditem(sess->ssi.local, oldgn, NULL, AIM_SSI_TYPE_GROUP))) 947 return -EINVAL; 948 949 free(group->name); 950 group->name = (char *)malloc((strlen(newgn)+1)*sizeof(char)); 787 951 strcpy(group->name, newgn); 788 952 789 /* Send the mod item SNAC */ 790 aim_ssi_addmoddel(sess, conn, &group, 1, AIM_CB_SSI_MOD); 791 792 /* Begin sending SSI SNACs */ 793 aim_ssi_dispatch(sess, conn); 794 795 return 0; 796 } 797 798 /** 799 * Delete an array of screen names from the given group. 953 /* Sync our local list with the server list */ 954 aim_ssi_sync(sess); 955 956 return 0; 957 } 958 959 /** 960 * Stores your permit/deny setting on the server, and starts using it. 800 961 * 801 962 * @param sess The oscar session. 802 * @param conn The bos connection for this session.803 * @param gn The name of the group from which you want to delete these names.804 * @param sn An array of null terminated strings of the names you want to delete.805 * @param num The number of screen names you are deleting (size of the sn array).806 * @return Return 0 if no errors, otherwise return the error number.807 */808 faim_export int aim_ssi_delbuddies(aim_session_t *sess, aim_conn_t *conn, const char *gn, char **sn, unsigned int num)809 {810 struct aim_ssi_item *cur, *parentgroup, **delitems;811 int i;812 813 if (!sess || !conn || !gn || !sn || !num)814 return -EINVAL;815 816 /* Look up the parent group */817 if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn, AIM_SSI_TYPE_GROUP)))818 return -EINVAL;819 820 /* Allocate an array of pointers to each of the items to be deleted */821 delitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *));822 memset(delitems, 0, num*sizeof(struct aim_ssi_item *));823 824 /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */825 for (i=0; i<num; i++) {826 if (!(delitems[i] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, sn[i], AIM_SSI_TYPE_BUDDY))) {827 free(delitems);828 return -EINVAL;829 }830 831 /* Remove the delitems from the item list */832 if (sess->ssi.items == delitems[i]) {833 sess->ssi.items = sess->ssi.items->next;834 } else {835 for (cur=sess->ssi.items; (cur->next && (cur->next!=delitems[i])); cur=cur->next);836 if (cur->next)837 cur->next = cur->next->next;838 }839 }840 841 /* Send the del item SNAC */842 aim_ssi_addmoddel(sess, conn, delitems, num, AIM_CB_SSI_DEL);843 844 /* Free the items */845 for (i=0; i<num; i++) {846 if (delitems[i]->name)847 free(delitems[i]->name);848 if (delitems[i]->data)849 aim_freetlvchain((aim_tlvlist_t **)&delitems[i]->data);850 free(delitems[i]);851 }852 free(delitems);853 854 /* Rebuild the additional data in the parent group */855 aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup);856 857 /* Send the mod item SNAC */858 aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD);859 860 /* Delete the group, but only if it's empty */861 if (!parentgroup->data)862 aim_ssi_delgroups(sess, conn, &parentgroup->name, 1);863 864 /* Begin sending SSI SNACs */865 aim_ssi_dispatch(sess, conn);866 867 return 0;868 }869 870 /**871 * Delete the master group from the item list. There can be only one.872 * Er, so just find the one master group and delete it.873 *874 * @param sess The oscar session.875 * @param conn The bos connection for this session.876 * @return Return 0 if no errors, otherwise return the error number.877 */878 faim_export int aim_ssi_delmastergroup(aim_session_t *sess, aim_conn_t *conn)879 {880 struct aim_ssi_item *cur, *delitem;881 882 if (!sess || !conn)883 return -EINVAL;884 885 /* Make delitem a pointer to the aim_ssi_item to be deleted */886 if (!(delitem = aim_ssi_itemlist_find(sess->ssi.items, 0, 0)))887 return -EINVAL;888 889 /* Remove delitem from the item list */890 if (sess->ssi.items == delitem) {891 sess->ssi.items = sess->ssi.items->next;892 } else {893 for (cur=sess->ssi.items; (cur->next && (cur->next!=delitem)); cur=cur->next);894 if (cur->next)895 cur->next = cur->next->next;896 }897 898 /* Send the del item SNAC */899 aim_ssi_addmoddel(sess, conn, &delitem, 1, AIM_CB_SSI_DEL);900 901 /* Free the item */902 if (delitem->name)903 free(delitem->name);904 if (delitem->data)905 aim_freetlvchain((aim_tlvlist_t **)&delitem->data);906 free(delitem);907 908 /* Begin sending SSI SNACs */909 aim_ssi_dispatch(sess, conn);910 911 return 0;912 }913 914 /**915 * Delete an array of groups.916 *917 * @param sess The oscar session.918 * @param conn The bos connection for this session.919 * @param gn An array of null terminated strings of the groups you want to delete.920 * @param num The number of groups you are deleting (size of the gn array).921 * @return Return 0 if no errors, otherwise return the error number.922 */923 faim_export int aim_ssi_delgroups(aim_session_t *sess, aim_conn_t *conn, char **gn, unsigned int num) {924 struct aim_ssi_item *cur, *parentgroup, **delitems;925 int i;926 927 if (!sess || !conn || !gn || !num)928 return -EINVAL;929 930 /* Look up the parent group */931 if (!(parentgroup = aim_ssi_itemlist_find(sess->ssi.items, 0, 0)))932 return -EINVAL;933 934 /* Allocate an array of pointers to each of the items to be deleted */935 delitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *));936 memset(delitems, 0, num*sizeof(struct aim_ssi_item *));937 938 /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */939 for (i=0; i<num; i++) {940 if (!(delitems[i] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn[i], AIM_SSI_TYPE_GROUP))) {941 free(delitems);942 return -EINVAL;943 }944 945 /* Remove the delitems from the item list */946 if (sess->ssi.items == delitems[i]) {947 sess->ssi.items = sess->ssi.items->next;948 } else {949 for (cur=sess->ssi.items; (cur->next && (cur->next!=delitems[i])); cur=cur->next);950 if (cur->next)951 cur->next = cur->next->next;952 }953 }954 955 /* Send the del item SNAC */956 aim_ssi_addmoddel(sess, conn, delitems, num, AIM_CB_SSI_DEL);957 958 /* Free the items */959 for (i=0; i<num; i++) {960 if (delitems[i]->name)961 free(delitems[i]->name);962 if (delitems[i]->data)963 aim_freetlvchain((aim_tlvlist_t **)&delitems[i]->data);964 free(delitems[i]);965 }966 free(delitems);967 968 /* Rebuild the additional data in the parent group */969 aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup);970 971 /* Send the mod item SNAC */972 aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD);973 974 /* Delete the group, but only if it's empty */975 if (!parentgroup->data)976 aim_ssi_delmastergroup(sess, conn);977 978 /* Begin sending SSI SNACs */979 aim_ssi_dispatch(sess, conn);980 981 return 0;982 }983 984 /**985 * Delete an array of a certain type of item from the list. This can be986 * used for permit buddies, deny buddies, ICQ's ignore buddies, and987 * probably other types, also.988 *989 * @param sess The oscar session.990 * @param conn The bos connection for this session.991 * @param sn An array of null terminated strings of the items you want to delete.992 * @param num The number of items you are deleting (size of the sn array).993 * @return Return 0 if no errors, otherwise return the error number.994 */995 faim_export int aim_ssi_delpord(aim_session_t *sess, aim_conn_t *conn, const char **sn, unsigned int num, fu16_t type) {996 struct aim_ssi_item *cur, **delitems;997 int i;998 999 if (!sess || !conn || !sn || !num || (type!=AIM_SSI_TYPE_PERMIT && type!=AIM_SSI_TYPE_DENY))1000 return -EINVAL;1001 1002 /* Allocate an array of pointers to each of the items to be deleted */1003 delitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *));1004 memset(delitems, 0, num*sizeof(struct aim_ssi_item *));1005 1006 /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */1007 for (i=0; i<num; i++) {1008 if (!(delitems[i] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, sn[i], type))) {1009 free(delitems);1010 return -EINVAL;1011 }1012 1013 /* Remove the delitems from the item list */1014 if (sess->ssi.items == delitems[i]) {1015 sess->ssi.items = sess->ssi.items->next;1016 } else {1017 for (cur=sess->ssi.items; (cur->next && (cur->next!=delitems[i])); cur=cur->next);1018 if (cur->next)1019 cur->next = cur->next->next;1020 }1021 }1022 1023 /* Send the del item SNAC */1024 aim_ssi_addmoddel(sess, conn, delitems, num, AIM_CB_SSI_DEL);1025 1026 /* Free the items */1027 for (i=0; i<num; i++) {1028 if (delitems[i]->name)1029 free(delitems[i]->name);1030 if (delitems[i]->data)1031 aim_freetlvchain((aim_tlvlist_t **)&delitems[i]->data);1032 free(delitems[i]);1033 }1034 free(delitems);1035 1036 /* Begin sending SSI SNACs */1037 aim_ssi_dispatch(sess, conn);1038 1039 return 0;1040 }1041 1042 /**1043 * Stores your permit/deny setting on the server, and starts using it.1044 *1045 * @param sess The oscar session.1046 * @param conn The bos connection for this session.1047 963 * @param permdeny Your permit/deny setting. Can be one of the following: 1048 964 * 1 - Allow all users … … 1055 971 * @return Return 0 if no errors, otherwise return the error number. 1056 972 */ 1057 faim_export int aim_ssi_setpermdeny(aim_session_t *sess, aim_conn_t *conn, fu8_t permdeny, fu32_t vismask) { 1058 struct aim_ssi_item *cur; 1059 aim_tlv_t *tlv; 1060 1061 if (!sess || !conn) 1062 return -EINVAL; 1063 1064 /* Look up the permit/deny settings item */ 1065 cur = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_PDINFO); 1066 1067 if (cur) { 1068 /* The permit/deny item exists */ 1069 if (cur->data && (tlv = aim_gettlv(cur->data, 0x00ca, 1))) { 1070 /* Just change the value of the x00ca TLV */ 1071 if (tlv->length != 1) { 1072 tlv->length = 1; 1073 free(tlv->value); 1074 tlv->value = (fu8_t *)malloc(sizeof(fu8_t)); 1075 } 1076 tlv->value[0] = permdeny; 1077 } else { 1078 /* Need to add the x00ca TLV to the TLV chain */ 1079 aim_addtlvtochain8((aim_tlvlist_t**)&cur->data, 0x00ca, permdeny); 973 faim_export int aim_ssi_setpermdeny(aim_session_t *sess, fu8_t permdeny, fu32_t vismask) 974 { 975 struct aim_ssi_item *tmp; 976 aim_tlvlist_t *data = NULL; 977 978 if (!sess) 979 return -EINVAL; 980 981 /* Need to add the x00ca TLV to the TLV chain */ 982 aim_addtlvtochain8(&data, 0x00ca, permdeny); 983 984 /* Need to add the x00cb TLV to the TLV chain */ 985 aim_addtlvtochain32(&data, 0x00cb, vismask); 986 987 if ((tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, NULL, AIM_SSI_TYPE_PDINFO))) { 988 aim_freetlvchain(&tmp->data); 989 tmp->data = data; 990 } else { 991 tmp = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PDINFO, data); 992 aim_freetlvchain(&data); 993 } 994 995 /* Sync our local list with the server list */ 996 aim_ssi_sync(sess); 997 998 return 0; 999 } 1000 1001 /** 1002 * Set buddy icon information 1003 * 1004 * @param sess The oscar session. 1005 * @param iconcsum The MD5 checksum of the icon you are using. 1006 * @param iconcsumlen Length of the MD5 checksum given above. Should be 0x10 bytes. 1007 * @return Return 0 if no errors, otherwise return the error number. 1008 */ 1009 faim_export int aim_ssi_seticon(aim_session_t *sess, fu8_t *iconsum, fu16_t iconsumlen) 1010 { 1011 struct aim_ssi_item *tmp; 1012 aim_tlvlist_t *data = NULL; 1013 fu8_t *csumdata; 1014 1015 if (!sess || !iconsum || !iconsumlen) 1016 return -EINVAL; 1017 1018 if (!(csumdata = (fu8_t *)malloc((iconsumlen+2)*sizeof(fu8_t)))) 1019 return -ENOMEM; 1020 csumdata[0] = 0x00; 1021 csumdata[1] = 0x10; 1022 memcpy(&csumdata[2], iconsum, iconsumlen); 1023 1024 /* Need to add the x00d5 TLV to the TLV chain */ 1025 aim_addtlvtochain_raw(&data, 0x00d5, (iconsumlen+2) * sizeof(fu8_t), csumdata); 1026 1027 /* This TLV is added to cache the icon. */ 1028 aim_addtlvtochain_noval(&data, 0x0131); 1029 1030 if ((tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, "1", AIM_SSI_TYPE_ICONINFO))) { 1031 /* If the new tlvchain and oldtlvchain are the same, then do nothing */ 1032 if (!aim_tlvlist_cmp(tmp->data, data)) { 1033 /* The new tlvlist is the identical to the old one */ 1034 aim_freetlvchain(&data); 1035 free(csumdata); 1036 return 0; 1080 1037 } 1081 1082 if (cur->data && (tlv = aim_gettlv(cur->data, 0x00cb, 1))) { 1083 /* Just change the value of the x00cb TLV */ 1084 if (tlv->length != 4) { 1085 tlv->length = 4; 1086 free(tlv->value); 1087 tlv->value = (fu8_t *)malloc(4*sizeof(fu8_t)); 1088 } 1089 aimutil_put32(tlv->value, vismask); 1090 } else { 1091 /* Need to add the x00cb TLV to the TLV chain */ 1092 aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00cb, vismask); 1093 } 1094 1095 /* Send the mod item SNAC */ 1096 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_MOD); 1038 aim_freetlvchain(&tmp->data); 1039 tmp->data = data; 1097 1040 } else { 1098 /* Need to add the permit/deny item */ 1099 if (!(cur = aim_ssi_itemlist_add(&sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_PDINFO))) 1100 return -ENOMEM; 1101 aim_addtlvtochain8((aim_tlvlist_t**)&cur->data, 0x00ca, permdeny); 1102 aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00cb, vismask); 1103 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_ADD); 1104 } 1105 1106 /* Begin sending SSI SNACs */ 1107 aim_ssi_dispatch(sess, conn); 1108 1041 tmp = aim_ssi_itemlist_add(&sess->ssi.local, "1", 0x0000, 0x51F4, AIM_SSI_TYPE_ICONINFO, data); 1042 aim_freetlvchain(&data); 1043 } 1044 1045 /* Sync our local list with the server list */ 1046 aim_ssi_sync(sess); 1047 free(csumdata); 1109 1048 return 0; 1110 1049 } … … 1114 1053 * 1115 1054 * @param sess The oscar session. 1116 * @param conn The bos connection for this session.1117 1055 * @param presence I think it's a bitmask, but I only know what one of the bits is: 1118 1056 * 0x00000400 - Allow others to see your idle time 1119 1057 * @return Return 0 if no errors, otherwise return the error number. 1120 1058 */ 1121 faim_export int aim_ssi_setpresence(aim_session_t *sess, aim_conn_t *conn, fu32_t presence) { 1122 struct aim_ssi_item *cur; 1059 faim_export int aim_ssi_setpresence(aim_session_t *sess, fu32_t presence) { 1060 struct aim_ssi_item *tmp; 1061 aim_tlvlist_t *data = NULL; 1062 1063 if (!sess) 1064 return -EINVAL; 1065 1066 /* Need to add the x00c9 TLV to the TLV chain */ 1067 aim_addtlvtochain32(&data, 0x00c9, presence); 1068 1069 if ((tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS))) { 1070 aim_freetlvchain(&tmp->data); 1071 tmp->data = data; 1072 } else { 1073 tmp = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PRESENCEPREFS, data); 1074 aim_freetlvchain(&data); 1075 } 1076 1077 /* Sync our local list with the server list */ 1078 aim_ssi_sync(sess); 1079 1080 return 0; 1081 } 1082 1083 /* 1084 * Subtype 0x0002 - Request SSI Rights. 1085 */ 1086 faim_export int aim_ssi_reqrights(aim_session_t *sess) 1087 { 1088 aim_conn_t *conn; 1089 1090 if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI))) 1091 return -EINVAL; 1092 1093 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_REQRIGHTS); 1094 } 1095 1096 /* 1097 * Subtype 0x0003 - SSI Rights Information. 1098 */ 1099 static int parserights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1100 { 1101 int ret = 0, i; 1102 aim_rxcallback_t userfunc; 1103 aim_tlvlist_t *tlvlist; 1123 1104 aim_tlv_t *tlv; 1124 1125 if (!sess || !conn) 1126 return -EINVAL; 1127 1128 /* Look up the item */ 1129 cur = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS); 1130 1131 if (cur) { 1132 /* The item exists */ 1133 if (cur->data && (tlv = aim_gettlv(cur->data, 0x00c9, 1))) { 1134 /* Just change the value of the x00c9 TLV */ 1135 if (tlv->length != 4) { 1136 tlv->length = 4; 1137 free(tlv->value); 1138 tlv->value = (fu8_t *)malloc(4*sizeof(fu8_t)); 1139 } 1140 aimutil_put32(tlv->value, presence); 1141 } else { 1142 /* Need to add the x00c9 TLV to the TLV chain */ 1143 aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00c9, presence); 1144 } 1145 1146 /* Send the mod item SNAC */ 1147 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_MOD); 1148 } else { 1149 /* Need to add the item */ 1150 if (!(cur = aim_ssi_itemlist_add(&sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS))) 1151 return -ENOMEM; 1152 aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00c9, presence); 1153 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_ADD); 1154 } 1155 1156 /* Begin sending SSI SNACs */ 1157 aim_ssi_dispatch(sess, conn); 1158 1159 return 0; 1160 } 1161 1162 /* 1163 * Request SSI Rights. 1164 */ 1165 faim_export int aim_ssi_reqrights(aim_session_t *sess, aim_conn_t *conn) 1166 { 1167 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_REQRIGHTS); 1168 } 1169 1170 /* 1171 * SSI Rights Information. 1172 */ 1173 static int parserights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1174 { 1175 int ret = 0; 1176 aim_rxcallback_t userfunc; 1105 aim_bstream_t bstream; 1106 fu16_t *maxitems; 1107 1108 /* This SNAC is made up of a bunch of TLVs */ 1109 tlvlist = aim_readtlvchain(bs); 1110 1111 /* TLV 0x0004 contains the maximum number of each item */ 1112 if (!(tlv = aim_gettlv(tlvlist, 0x0004, 1))) { 1113 aim_freetlvchain(&tlvlist); 1114 return 0; 1115 } 1116 1117 aim_bstream_init(&bstream, tlv->value, tlv->length); 1118 1119 if (!(maxitems = (fu16_t *)malloc((tlv->length/2)*sizeof(fu16_t)))) { 1120 aim_freetlvchain(&tlvlist); 1121 return 0; 1122 } 1123 1124 for (i=0; i<(tlv->length/2); i++) 1125 maxitems[i] = aimbs_get16(&bstream); 1177 1126 1178 1127 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1179 ret = userfunc(sess, rx); 1128 ret = userfunc(sess, rx, tlv->length/2, maxitems); 1129 1130 aim_freetlvchain(&tlvlist); 1131 free(maxitems); 1180 1132 1181 1133 return ret; … … 1183 1135 1184 1136 /* 1185 * Request SSI Data. 1137 * Subtype 0x0004 - Request SSI Data when you don't have a timestamp and 1138 * revision number. 1139 * 1140 */ 1141 faim_export int aim_ssi_reqdata(aim_session_t *sess) 1142 { 1143 aim_conn_t *conn; 1144 1145 if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI))) 1146 return -EINVAL; 1147 1148 /* Free any current data, just in case */ 1149 aim_ssi_freelist(sess); 1150 1151 return aim_genericreq_n_snacid(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_REQDATA); 1152 } 1153 1154 /* 1155 * Subtype 0x0005 - Request SSI Data when you have a timestamp and revision 1156 * number. 1186 1157 * 1187 1158 * The data will only be sent if it is newer than the posted local … … 1191 1162 * 1192 1163 */ 1193 faim_export int aim_ssi_reqdata(aim_session_t *sess, aim_conn_t *conn, time_t localstamp, fu16_t localrev) 1194 { 1164 faim_export int aim_ssi_reqifchanged(aim_session_t *sess, time_t timestamp, fu16_t numitems) 1165 { 1166 aim_conn_t *conn; 1195 1167 aim_frame_t *fr; 1196 1168 aim_snacid_t snacid; 1197 1169 1198 if (!sess || ! conn)1170 if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI))) 1199 1171 return -EINVAL; 1200 1172 … … 1202 1174 return -ENOMEM; 1203 1175 1204 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_REQ LIST, 0x0000, NULL, 0);1205 1206 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_REQ LIST, 0x0000, snacid);1207 aimbs_put32(&fr->data, localstamp);1208 aimbs_put16(&fr->data, localrev);1176 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_REQIFCHANGED, 0x0000, NULL, 0); 1177 1178 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_REQIFCHANGED, 0x0000, snacid); 1179 aimbs_put32(&fr->data, timestamp); 1180 aimbs_put16(&fr->data, numitems); 1209 1181 1210 1182 aim_tx_enqueue(sess, fr); 1211 1183 1212 return 0; 1213 } 1214 1215 /* 1216 * SSI Data. 1184 /* Free any current data, just in case */ 1185 aim_ssi_freelist(sess); 1186 1187 return 0; 1188 } 1189 1190 /* 1191 * Subtype 0x0006 - SSI Data. 1217 1192 */ 1218 1193 static int parsedata(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) … … 1220 1195 int ret = 0; 1221 1196 aim_rxcallback_t userfunc; 1222 struct aim_ssi_item *cur = NULL;1223 1197 fu8_t fmtver; /* guess */ 1224 fu16_t revision; 1225 fu32_t timestamp; 1226 1227 /* When you set the version for the SSI family to 2-4, the beginning of this changes. 1228 * Instead of the version and then the revision, there is "0x0006" and then a type 1229 * 0x0001 TLV containing the 2 byte SSI family version that you sent earlier. Also, 1230 * the SNAC flags go from 0x0000 to 0x8000. I guess the 0x0006 is the length of the 1231 * TLV(s) that follow. The rights SNAC does the same thing, with the differing flag 1232 * and everything. 1233 */ 1198 fu16_t namelen, gid, bid, type; 1199 char *name; 1200 aim_tlvlist_t *data; 1234 1201 1235 1202 fmtver = aimbs_get8(bs); /* Version of ssi data. Should be 0x00 */ 1236 revision = aimbs_get16(bs); /* # of times ssi data has been modified */ 1237 if (revision != 0) 1238 sess->ssi.revision = revision; 1239 1240 for (cur = sess->ssi.items; cur && cur->next; cur=cur->next) ; 1241 1242 while (aim_bstream_empty(bs) > 4) { /* last four bytes are stamp */ 1243 fu16_t namelen, tbslen; 1244 1245 if (!sess->ssi.items) { 1246 if (!(sess->ssi.items = malloc(sizeof(struct aim_ssi_item)))) 1247 return -ENOMEM; 1248 cur = sess->ssi.items; 1249 } else { 1250 if (!(cur->next = malloc(sizeof(struct aim_ssi_item)))) 1251 return -ENOMEM; 1252 cur = cur->next; 1253 } 1254 memset(cur, 0, sizeof(struct aim_ssi_item)); 1255 1203 sess->ssi.numitems += aimbs_get16(bs); /* # of items in this SSI SNAC */ 1204 1205 /* Read in the list */ 1206 while (aim_bstream_empty(bs) > 4) { /* last four bytes are timestamp */ 1256 1207 if ((namelen = aimbs_get16(bs))) 1257 cur->name = aimbs_getstr(bs, namelen); 1258 cur->gid = aimbs_get16(bs); 1259 cur->bid = aimbs_get16(bs); 1260 cur->type = aimbs_get16(bs); 1261 1262 if ((tbslen = aimbs_get16(bs))) { 1263 aim_bstream_t tbs; 1264 1265 aim_bstream_init(&tbs, bs->data + bs->offset /* XXX */, tbslen); 1266 cur->data = (void *)aim_readtlvchain(&tbs); 1267 aim_bstream_advance(bs, tbslen); 1268 } 1269 } 1270 1271 timestamp = aimbs_get32(bs); 1272 if (timestamp != 0) 1273 sess->ssi.timestamp = timestamp; 1274 sess->ssi.received_data = 1; 1275 1276 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1277 ret = userfunc(sess, rx, fmtver, sess->ssi.revision, sess->ssi.timestamp, sess->ssi.items); 1208 name = aimbs_getstr(bs, namelen); 1209 else 1210 name = NULL; 1211 gid = aimbs_get16(bs); 1212 bid = aimbs_get16(bs); 1213 type = aimbs_get16(bs); 1214 data = aim_readtlvchain_len(bs, aimbs_get16(bs)); 1215 aim_ssi_itemlist_add(&sess->ssi.official, name, gid, bid, type, data); 1216 free(name); 1217 aim_freetlvchain(&data); 1218 } 1219 1220 /* Read in the timestamp */ 1221 sess->ssi.timestamp = aimbs_get32(bs); 1222 1223 if (!(snac->flags & 0x0001)) { 1224 /* Make a copy of the list */ 1225 struct aim_ssi_item *cur; 1226 for (cur=sess->ssi.official; cur; cur=cur->next) 1227 aim_ssi_itemlist_add(&sess->ssi.local, cur->name, cur->gid, cur->bid, cur->type, cur->data); 1228 1229 sess->ssi.received_data = 1; 1230 1231 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1232 ret = userfunc(sess, rx, fmtver, sess->ssi.numitems, sess->ssi.official, sess->ssi.timestamp); 1233 } 1278 1234 1279 1235 return ret; … … 1281 1237 1282 1238 /* 1283 * S SI Data Enable Presence.1239 * Subtype 0x0007 - SSI Activate Data. 1284 1240 * 1285 1241 * Should be sent after receiving 13/6 or 13/f to tell the server you … … 1289 1245 * 1290 1246 */ 1291 faim_export int aim_ssi_enable(aim_session_t *sess, aim_conn_t *conn) 1292 { 1247 faim_export int aim_ssi_enable(aim_session_t *sess) 1248 { 1249 aim_conn_t *conn; 1250 1251 if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI))) 1252 return -EINVAL; 1253 1293 1254 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, 0x0007); 1294 1255 } 1295 1256 1296 1257 /* 1297 * S SI Add/Mod/Del Item(s).1258 * Subtype 0x0008/0x0009/0x000a - SSI Add/Mod/Del Item(s). 1298 1259 * 1299 1260 * Sends the SNAC to add, modify, or delete an item from the server-stored … … 1302 1263 * 1303 1264 */ 1304 faim_export int aim_ssi_addmoddel(aim_session_t *sess, aim_conn_t *conn, struct aim_ssi_item **items, unsigned int num, fu16_t subtype) 1305 { 1265 faim_export int aim_ssi_addmoddel(aim_session_t *sess) 1266 { 1267 aim_conn_t *conn; 1306 1268 aim_frame_t *fr; 1307 1269 aim_snacid_t snacid; 1308 int i, snaclen; 1309 1310 if (!sess || !conn || !items || !num) 1311 return -EINVAL; 1312 1270 int snaclen; 1271 struct aim_ssi_tmp *cur; 1272 1273 if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)) || !sess->ssi.pending || !sess->ssi.pending->item) 1274 return -EINVAL; 1275 1276 /* Calculate total SNAC size */ 1313 1277 snaclen = 10; /* For family, subtype, flags, and SNAC ID */ 1314 for ( i=0; i<num; i++) {1278 for (cur=sess->ssi.pending; cur; cur=cur->next) { 1315 1279 snaclen += 10; /* For length, GID, BID, type, and length */ 1316 if ( items[i]->name)1317 snaclen += strlen( items[i]->name);1318 if ( items[i]->data)1319 snaclen += aim_sizetlvchain( (aim_tlvlist_t **)&items[i]->data);1280 if (cur->item->name) 1281 snaclen += strlen(cur->item->name); 1282 if (cur->item->data) 1283 snaclen += aim_sizetlvchain(&cur->item->data); 1320 1284 } 1321 1285 … … 1323 1287 return -ENOMEM; 1324 1288 1325 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, subtype, 0x0000, NULL, 0); 1326 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, subtype, 0x0000, snacid); 1327 1328 for (i=0; i<num; i++) { 1329 aimbs_put16(&fr->data, items[i]->name ? strlen(items[i]->name) : 0); 1330 if (items[i]->name) 1331 aimbs_putraw(&fr->data, items[i]->name, strlen(items[i]->name)); 1332 aimbs_put16(&fr->data, items[i]->gid); 1333 aimbs_put16(&fr->data, items[i]->bid); 1334 aimbs_put16(&fr->data, items[i]->type); 1335 aimbs_put16(&fr->data, items[i]->data ? aim_sizetlvchain((aim_tlvlist_t **)&items[i]->data) : 0); 1336 if (items[i]->data) 1337 aim_writetlvchain(&fr->data, (aim_tlvlist_t **)&items[i]->data); 1338 } 1339 1340 aim_ssi_enqueue(sess, conn, fr); 1341 1342 return 0; 1343 } 1344 1345 /* 1346 * SSI Add/Mod/Del Ack. 1347 * 1348 * Response to add, modify, or delete SNAC (sent with aim_ssi_addmoddel). 1349 * 1350 */ 1351 static int parseack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1289 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, sess->ssi.pending->action, 0x0000, NULL, 0); 1290 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, sess->ssi.pending->action, 0x0000, snacid); 1291 1292 for (cur=sess->ssi.pending; cur; cur=cur->next) { 1293 aimbs_put16(&fr->data, cur->item->name ? strlen(cur->item->name) : 0); 1294 if (cur->item->name) 1295 aimbs_putraw(&fr->data, cur->item->name, strlen(cur->item->name)); 1296 aimbs_put16(&fr->data, cur->item->gid); 1297 aimbs_put16(&fr->data, cur->item->bid); 1298 aimbs_put16(&fr->data, cur->item->type); 1299 aimbs_put16(&fr->data, cur->item->data ? aim_sizetlvchain(&cur->item->data) : 0); 1300 if (cur->item->data) 1301 aim_writetlvchain(&fr->data, &cur->item->data); 1302 } 1303 1304 aim_tx_enqueue(sess, fr); 1305 1306 return 0; 1307 } 1308 1309 /* 1310 * Subtype 0x0008 - Incoming SSI add. 1311 * 1312 * XXX - It would probably be good for the client to actually do something when it gets this. 1313 */ 1314 static int parseadd(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1352 1315 { 1353 1316 int ret = 0; 1354 1317 aim_rxcallback_t userfunc; 1355 1356 sess->ssi.waiting_for_ack = 0; 1357 aim_ssi_dispatch(sess, rx->conn); 1318 char *name; 1319 fu16_t len, gid, bid, type; 1320 aim_tlvlist_t *data; 1321 1322 while (aim_bstream_empty(bs)) { 1323 if ((len = aimbs_get16(bs))) 1324 name = aimbs_getstr(bs, len); 1325 else 1326 name = NULL; 1327 gid = aimbs_get16(bs); 1328 bid = aimbs_get16(bs); 1329 type = aimbs_get16(bs); 1330 if ((len = aimbs_get16(bs))) 1331 data = aim_readtlvchain_len(bs, len); 1332 else 1333 data = NULL; 1334 1335 aim_ssi_itemlist_add(&sess->ssi.local, name, gid, bid, type, data); 1336 aim_ssi_itemlist_add(&sess->ssi.official, name, gid, bid, type, data); 1337 free(name); 1338 aim_freetlvchain(&data); 1339 1340 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1341 ret = userfunc(sess, rx); 1342 1343 free(name); 1344 } 1345 1346 return ret; 1347 } 1348 1349 /* 1350 * Subtype 0x0009 - Incoming SSI mod. 1351 * 1352 * XXX - It would probably be good for the client to actually do something when it gets this. 1353 */ 1354 static int parsemod(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1355 { 1356 int ret = 0; 1357 aim_rxcallback_t userfunc; 1358 char *name; 1359 fu16_t len, gid, bid, type; 1360 aim_tlvlist_t *data; 1361 struct aim_ssi_item *item; 1362 1363 while (aim_bstream_empty(bs)) { 1364 if ((len = aimbs_get16(bs))) 1365 name = aimbs_getstr(bs, len); 1366 else 1367 name = NULL; 1368 gid = aimbs_get16(bs); 1369 bid = aimbs_get16(bs); 1370 type = aimbs_get16(bs); 1371 if ((len = aimbs_get16(bs))) 1372 data = aim_readtlvchain_len(bs, len); 1373 else 1374 data = NULL; 1375 1376 /* Replace the 2 local items with the given one */ 1377 if ((item = aim_ssi_itemlist_find(sess->ssi.local, gid, bid))) { 1378 item->type = type; 1379 free(item->name); 1380 if (name) { 1381 item->name = (char *)malloc((strlen(name)+1)*sizeof(char)); 1382 strcpy(item->name, name); 1383 } else 1384 item->name = NULL; 1385 aim_freetlvchain(&item->data); 1386 item->data = aim_tlvlist_copy(data); 1387 } 1388 1389 if ((item = aim_ssi_itemlist_find(sess->ssi.official, gid, bid))) { 1390 item->type = type; 1391 free(item->name); 1392 if (name) { 1393 item->name = (char *)malloc((strlen(name)+1)*sizeof(char)); 1394 strcpy(item->name, name); 1395 } else 1396 item->name = NULL; 1397 aim_freetlvchain(&item->data); 1398 item->data = aim_tlvlist_copy(data); 1399 } 1400 1401 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1402 ret = userfunc(sess, rx); 1403 1404 free(name); 1405 aim_freetlvchain(&data); 1406 } 1407 1408 return ret; 1409 } 1410 1411 /* 1412 * Subtype 0x000a - Incoming SSI del. 1413 * 1414 * XXX - It would probably be good for the client to actually do something when it gets this. 1415 */ 1416 static int parsedel(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1417 { 1418 int ret = 0; 1419 aim_rxcallback_t userfunc; 1420 fu16_t gid, bid; 1421 struct aim_ssi_item *del; 1422 1423 while (aim_bstream_empty(bs)) { 1424 aim_bstream_advance(bs, aimbs_get16(bs)); 1425 gid = aimbs_get16(bs); 1426 bid = aimbs_get16(bs); 1427 aimbs_get16(bs); 1428 aim_bstream_advance(bs, aimbs_get16(bs)); 1429 1430 if ((del = aim_ssi_itemlist_find(sess->ssi.local, gid, bid))) 1431 aim_ssi_itemlist_del(&sess->ssi.local, del); 1432 if ((del = aim_ssi_itemlist_find(sess->ssi.official, gid, bid))) 1433 aim_ssi_itemlist_del(&sess->ssi.official, del); 1434 1435 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1436 ret = userfunc(sess, rx); 1437 } 1438 1439 return ret; 1440 } 1441 1442 /* 1443 * Subtype 0x000e - SSI Add/Mod/Del Ack. 1444 * 1445 * Response to add, modify, or delete SNAC (sent with aim_ssi_addmoddel). 1446 * 1447 */ 1448 static int parseack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1449 { 1450 int ret = 0; 1451 aim_rxcallback_t userfunc; 1452 struct aim_ssi_tmp *cur, *del; 1453 1454 /* Read in the success/failure flags from the ack SNAC */ 1455 cur = sess->ssi.pending; 1456 while (cur && (aim_bstream_empty(bs)>0)) { 1457 cur->ack = aimbs_get16(bs); 1458 cur = cur->next; 1459 } 1460 1461 /* 1462 * If outcome is 0, then add the item to the item list, or replace the other item, 1463 * or remove the old item. If outcome is non-zero, then remove the item from the 1464 * local list, or unmodify it, or add it. 1465 */ 1466 for (cur=sess->ssi.pending; (cur && (cur->ack != 0xffff)); cur=cur->next) { 1467 if (cur->item) { 1468 if (cur->ack) { 1469 /* Our action was unsuccessful, so change the local list back to how it was */ 1470 if (cur->action == AIM_CB_SSI_ADD) { 1471 /* Remove the item from the local list */ 1472 /* Make sure cur->item is still valid memory */ 1473 if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) { 1474 if (cur->item->name) { 1475 cur->name = (char *)malloc((strlen(cur->item->name)+1)*sizeof(char)); 1476 strcpy(cur->name, cur->item->name); 1477 } 1478 aim_ssi_itemlist_del(&sess->ssi.local, cur->item); 1479 } 1480 cur->item = NULL; 1481 1482 } else if (cur->action == AIM_CB_SSI_MOD) { 1483 /* Replace the local item with the item from the official list */ 1484 if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) { 1485 struct aim_ssi_item *cur1; 1486 if ((cur1 = aim_ssi_itemlist_find(sess->ssi.official, cur->item->gid, cur->item->bid))) { 1487 free(cur->item->name); 1488 if (cur1->name) { 1489 cur->item->name = (char *)malloc((strlen(cur1->name)+1)*sizeof(char)); 1490 strcpy(cur->item->name, cur1->name); 1491 } else 1492 cur->item->name = NULL; 1493 aim_freetlvchain(&cur->item->data); 1494 cur->item->data = aim_tlvlist_copy(cur1->data); 1495 } 1496 } else 1497 cur->item = NULL; 1498 1499 } else if (cur->action == AIM_CB_SSI_DEL) { 1500 /* Add the item back into the local list */ 1501 if (aim_ssi_itemlist_valid(sess->ssi.official, cur->item)) { 1502 aim_ssi_itemlist_add(&sess->ssi.local, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data); 1503 } else 1504 cur->item = NULL; 1505 } 1506 1507 } else { 1508 /* Do the exact opposite */ 1509 if (cur->action == AIM_CB_SSI_ADD) { 1510 /* Add the local item to the official list */ 1511 if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) { 1512 aim_ssi_itemlist_add(&sess->ssi.official, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, cur->item->data); 1513 } else 1514 cur->item = NULL; 1515 1516 } else if (cur->action == AIM_CB_SSI_MOD) { 1517 /* Replace the official item with the item from the local list */ 1518 if (aim_ssi_itemlist_valid(sess->ssi.local, cur->item)) { 1519 struct aim_ssi_item *cur1; 1520 if ((cur1 = aim_ssi_itemlist_find(sess->ssi.official, cur->item->gid, cur->item->bid))) { 1521 free(cur1->name); 1522 if (cur->item->name) { 1523 cur1->name = (char *)malloc((strlen(cur->item->name)+1)*sizeof(char)); 1524 strcpy(cur1->name, cur->item->name); 1525 } else 1526 cur1->name = NULL; 1527 aim_freetlvchain(&cur1->data); 1528 cur1->data = aim_tlvlist_copy(cur->item->data); 1529 } 1530 } else 1531 cur->item = NULL; 1532 1533 } else if (cur->action == AIM_CB_SSI_DEL) { 1534 /* Remove the item from the official list */ 1535 if (aim_ssi_itemlist_valid(sess->ssi.official, cur->item)) 1536 aim_ssi_itemlist_del(&sess->ssi.official, cur->item); 1537 cur->item = NULL; 1538 } 1539 1540 } 1541 } /* End if (cur->item) */ 1542 } /* End for loop */ 1543 1544 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1545 ret = userfunc(sess, rx, sess->ssi.pending); 1546 1547 /* Free all aim_ssi_tmp's with an outcome */ 1548 cur = sess->ssi.pending; 1549 while (cur && (cur->ack != 0xffff)) { 1550 del = cur; 1551 cur = cur->next; 1552 free(del->name); 1553 free(del); 1554 } 1555 sess->ssi.pending = cur; 1556 1557 /* If we're not waiting for any more acks, then send more SNACs */ 1558 if (!sess->ssi.pending) { 1559 sess->ssi.pending = NULL; 1560 sess->ssi.waiting_for_ack = 0; 1561 aim_ssi_sync(sess); 1562 } 1563 1564 return ret; 1565 } 1566 1567 /* 1568 * Subtype 0x000f - SSI Data Unchanged. 1569 * 1570 * Response to aim_ssi_reqifchanged() if the server-side data is not newer than 1571 * posted local stamp/revision. 1572 * 1573 */ 1574 static int parsedataunchanged(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1575 { 1576 int ret = 0; 1577 aim_rxcallback_t userfunc; 1578 1579 sess->ssi.received_data = 1; 1358 1580 1359 1581 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) … … 1364 1586 1365 1587 /* 1366 * S SI Begin Data Modification.1588 * Subtype 0x0011 - SSI Begin Data Modification. 1367 1589 * 1368 1590 * Tells the server you're going to start modifying data. 1369 1591 * 1370 1592 */ 1371 faim_export int aim_ssi_modbegin(aim_session_t *sess, aim_conn_t *conn) 1372 { 1593 faim_export int aim_ssi_modbegin(aim_session_t *sess) 1594 { 1595 aim_conn_t *conn; 1596 1597 if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI))) 1598 return -EINVAL; 1599 1373 1600 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTART); 1374 1601 } 1375 1602 1376 1603 /* 1377 * SSI End Data Modification. 1378 * 1379 * Tells the server you're done modifying data. 1380 * 1381 */ 1382 faim_export int aim_ssi_modend(aim_session_t *sess, aim_conn_t *conn) 1383 { 1604 * Subtype 0x0012 - SSI End Data Modification. 1605 * 1606 * Tells the server you're finished modifying data. 1607 * 1608 */ 1609 faim_export int aim_ssi_modend(aim_session_t *sess) 1610 { 1611 aim_conn_t *conn; 1612 1613 if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI))) 1614 return -EINVAL; 1615 1384 1616 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTOP); 1385 1617 } 1386 1618 1387 1619 /* 1388 * SSI Data Unchanged. 1389 * 1390 * Response to aim_ssi_reqdata() if the server-side data is not newer than 1391 * posted local stamp/revision. 1392 * 1393 */ 1394 static int parsedataunchanged(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1620 * Subtype 0x0014 - Grant authorization 1621 * 1622 * Authorizes a contact so they can add you to their contact list. 1623 * 1624 */ 1625 faim_export int aim_ssi_sendauth(aim_session_t *sess, char *sn, char *msg) 1626 { 1627 aim_conn_t *conn; 1628 aim_frame_t *fr; 1629 aim_snacid_t snacid; 1630 1631 if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)) || !sn) 1632 return -EINVAL; 1633 1634 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)+2+(msg ? strlen(msg)+1 : 0)+2))) 1635 return -ENOMEM; 1636 1637 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTH, 0x0000, NULL, 0); 1638 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTH, 0x0000, snacid); 1639 1640 /* Screen name */ 1641 aimbs_put8(&fr->data, strlen(sn)); 1642 aimbs_putraw(&fr->data, sn, strlen(sn)); 1643 1644 /* Message (null terminated) */ 1645 aimbs_put16(&fr->data, msg ? strlen(msg) : 0); 1646 if (msg) { 1647 aimbs_putraw(&fr->data, msg, strlen(msg)); 1648 aimbs_put8(&fr->data, 0x00); 1649 } 1650 1651 /* Unknown */ 1652 aimbs_put16(&fr->data, 0x0000); 1653 1654 aim_tx_enqueue(sess, fr); 1655 1656 return 0; 1657 } 1658 1659 /* 1660 * Subtype 0x0015 - Receive an authorization grant 1661 */ 1662 static int receiveauthgrant(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1395 1663 { 1396 1664 int ret = 0; 1397 1665 aim_rxcallback_t userfunc; 1398 1399 sess->ssi.received_data = 1; 1666 fu16_t tmp; 1667 char *sn, *msg; 1668 1669 /* Read screen name */ 1670 if ((tmp = aimbs_get8(bs))) 1671 sn = aimbs_getstr(bs, tmp); 1672 else 1673 sn = NULL; 1674 1675 /* Read message (null terminated) */ 1676 if ((tmp = aimbs_get16(bs))) 1677 msg = aimbs_getstr(bs, tmp); 1678 else 1679 msg = NULL; 1680 1681 /* Unknown */ 1682 tmp = aimbs_get16(bs); 1400 1683 1401 1684 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1402 ret = userfunc(sess, rx); 1685 ret = userfunc(sess, rx, sn, msg); 1686 1687 free(sn); 1688 free(msg); 1689 1690 return ret; 1691 } 1692 1693 /* 1694 * Subtype 0x0018 - Send authorization request 1695 * 1696 * Sends a request for authorization to the given contact. The request will either be 1697 * granted, denied, or dropped. 1698 * 1699 */ 1700 faim_export int aim_ssi_sendauthrequest(aim_session_t *sess, char *sn, char *msg) 1701 { 1702 aim_conn_t *conn; 1703 aim_frame_t *fr; 1704 aim_snacid_t snacid; 1705 1706 if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)) || !sn) 1707 return -EINVAL; 1708 1709 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)+2+(msg ? strlen(msg)+1 : 0)+2))) 1710 return -ENOMEM; 1711 1712 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREQ, 0x0000, NULL, 0); 1713 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREQ, 0x0000, snacid); 1714 1715 /* Screen name */ 1716 aimbs_put8(&fr->data, strlen(sn)); 1717 aimbs_putraw(&fr->data, sn, strlen(sn)); 1718 1719 /* Message (null terminated) */ 1720 aimbs_put16(&fr->data, msg ? strlen(msg) : 0); 1721 if (msg) { 1722 aimbs_putraw(&fr->data, msg, strlen(msg)); 1723 aimbs_put8(&fr->data, 0x00); 1724 } 1725 1726 /* Unknown */ 1727 aimbs_put16(&fr->data, 0x0000); 1728 1729 aim_tx_enqueue(sess, fr); 1730 1731 return 0; 1732 } 1733 1734 /* 1735 * Subtype 0x0019 - Receive an authorization request 1736 */ 1737 static int receiveauthrequest(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1738 { 1739 int ret = 0; 1740 aim_rxcallback_t userfunc; 1741 fu16_t tmp; 1742 char *sn, *msg; 1743 1744 /* Read screen name */ 1745 if ((tmp = aimbs_get8(bs))) 1746 sn = aimbs_getstr(bs, tmp); 1747 else 1748 sn = NULL; 1749 1750 /* Read message (null terminated) */ 1751 if ((tmp = aimbs_get16(bs))) 1752 msg = aimbs_getstr(bs, tmp); 1753 else 1754 msg = NULL; 1755 1756 /* Unknown */ 1757 tmp = aimbs_get16(bs); 1758 1759 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1760 ret = userfunc(sess, rx, sn, msg); 1761 1762 free(sn); 1763 free(msg); 1764 1765 return ret; 1766 } 1767 1768 /* 1769 * Subtype 0x001a - Send authorization reply 1770 * 1771 * Sends a reply to a request for authorization. The reply can either 1772 * grant authorization or deny authorization. 1773 * 1774 * if reply=0x00 then deny 1775 * if reply=0x01 then grant 1776 * 1777 */ 1778 faim_export int aim_ssi_sendauthreply(aim_session_t *sess, char *sn, fu8_t reply, char *msg) 1779 { 1780 aim_conn_t *conn; 1781 aim_frame_t *fr; 1782 aim_snacid_t snacid; 1783 1784 if (!sess || !(conn = aim_conn_findbygroup(sess, AIM_CB_FAM_SSI)) || !sn) 1785 return -EINVAL; 1786 1787 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 1+strlen(sn) + 1 + 2+(msg ? strlen(msg)+1 : 0) + 2))) 1788 return -ENOMEM; 1789 1790 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREP, 0x0000, NULL, 0); 1791 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREP, 0x0000, snacid); 1792 1793 /* Screen name */ 1794 aimbs_put8(&fr->data, strlen(sn)); 1795 aimbs_putraw(&fr->data, sn, strlen(sn)); 1796 1797 /* Grant or deny */ 1798 aimbs_put8(&fr->data, reply); 1799 1800 /* Message (null terminated) */ 1801 aimbs_put16(&fr->data, msg ? (strlen(msg)+1) : 0); 1802 if (msg) { 1803 aimbs_putraw(&fr->data, msg, strlen(msg)); 1804 aimbs_put8(&fr->data, 0x00); 1805 } 1806 1807 /* Unknown */ 1808 aimbs_put16(&fr->data, 0x0000); 1809 1810 aim_tx_enqueue(sess, fr); 1811 1812 return 0; 1813 } 1814 1815 /* 1816 * Subtype 0x001b - Receive an authorization reply 1817 * You get this bad boy when other people respond to the authorization 1818 * request that you have previously sent them. 1819 */ 1820 static int receiveauthreply(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1821 { 1822 int ret = 0; 1823 aim_rxcallback_t userfunc; 1824 fu16_t tmp; 1825 fu8_t reply; 1826 char *sn, *msg; 1827 1828 /* Read screen name */ 1829 if ((tmp = aimbs_get8(bs))) 1830 sn = aimbs_getstr(bs, tmp); 1831 else 1832 sn = NULL; 1833 1834 /* Read reply */ 1835 reply = aimbs_get8(bs); 1836 1837 /* Read message (null terminated) */ 1838 if ((tmp = aimbs_get16(bs))) 1839 msg = aimbs_getstr(bs, tmp); 1840 else 1841 msg = NULL; 1842 1843 /* Unknown */ 1844 tmp = aimbs_get16(bs); 1845 1846 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1847 ret = userfunc(sess, rx, sn, reply, msg); 1848 1849 free(sn); 1850 free(msg); 1851 1852 return ret; 1853 } 1854 1855 /* 1856 * Subtype 0x001c - Receive a message telling you someone added you to their list. 1857 */ 1858 static int receiveadded(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) 1859 { 1860 int ret = 0; 1861 aim_rxcallback_t userfunc; 1862 fu16_t tmp; 1863 char *sn; 1864 1865 /* Read screen name */ 1866 if ((tmp = aimbs_get8(bs))) 1867 sn = aimbs_getstr(bs, tmp); 1868 else 1869 sn = NULL; 1870 1871 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1872 ret = userfunc(sess, rx, sn); 1873 1874 free(sn); 1403 1875 1404 1876 return ret; … … 1412 1884 else if (snac->subtype == AIM_CB_SSI_LIST) 1413 1885 return parsedata(sess, mod, rx, snac, bs); 1886 else if (snac->subtype == AIM_CB_SSI_ADD) 1887 return parseadd(sess, mod, rx, snac, bs); 1888 else if (snac->subtype == AIM_CB_SSI_MOD) 1889 return parsemod(sess, mod, rx, snac, bs); 1890 else if (snac->subtype == AIM_CB_SSI_DEL) 1891 return parsedel(sess, mod, rx, snac, bs); 1414 1892 else if (snac->subtype == AIM_CB_SSI_SRVACK) 1415 1893 return parseack(sess, mod, rx, snac, bs); 1416 1894 else if (snac->subtype == AIM_CB_SSI_NOLIST) 1417 1895 return parsedataunchanged(sess, mod, rx, snac, bs); 1896 else if (snac->subtype == AIM_CB_SSI_RECVAUTH) 1897 return receiveauthgrant(sess, mod, rx, snac, bs); 1898 else if (snac->subtype == AIM_CB_SSI_RECVAUTHREQ) 1899 return receiveauthrequest(sess, mod, rx, snac, bs); 1900 else if (snac->subtype == AIM_CB_SSI_RECVAUTHREP) 1901 return receiveauthreply(sess, mod, rx, snac, bs); 1902 else if (snac->subtype == AIM_CB_SSI_ADDED) 1903 return receiveadded(sess, mod, rx, snac, bs); 1418 1904 1419 1905 return 0; … … 1431 1917 1432 1918 mod->family = AIM_CB_FAM_SSI; 1433 mod->version = 0x000 1;1919 mod->version = 0x0004; 1434 1920 mod->toolid = 0x0110; 1435 mod->toolversion = 0x0 47b;1921 mod->toolversion = 0x0629; 1436 1922 mod->flags = 0; 1437 1923 strncpy(mod->name, "ssi", sizeof(mod->name));
Note: See TracChangeset
for help on using the changeset viewer.