Changeset 862371b for libfaim/ssi.c
- Timestamp:
- Jun 29, 2003, 1:47:04 PM (21 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:
- e016fc2
- Parents:
- 03ad7b2
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
libfaim/ssi.c
r5e53c4a r862371b 6 6 * to be stored on the server, so that they can be accessed from any client. 7 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. 11 * 12 * The SNAC sending and receiving functions are lower down in the file, and 13 * they're simpler. They are in the order of the subtypes they deal with, 14 * starting with the request rights function (subtype 0x0002), then parse 15 * rights (subtype 0x0003), then--well, you get the idea. 16 * 8 17 * This is entirely too complicated. 18 * You don't know the half of it. 19 * 20 * XXX - Test for memory leaks 21 * XXX - Better parsing of rights, and use the rights info to limit adds 9 22 * 10 23 */ … … 13 26 #include <aim.h> 14 27 28 /** 29 * Locally add a new item to the given item list. 30 * 31 * @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 no 33 * parent group (ie. the group ID# should be 0). 34 * @param name A null terminated string of the name of the new item, or NULL if the 35 * 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) 40 { 41 int i; 42 struct aim_ssi_item *cur, *newitem; 43 44 if (!(newitem = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item)))) 45 return NULL; 46 47 /* Set the name */ 48 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); 54 } else 55 newitem->name = NULL; 56 57 /* Set the group ID# and the buddy ID# */ 58 newitem->gid = 0x0000; 59 newitem->bid = 0x0000; 60 if (type == AIM_SSI_TYPE_GROUP) { 61 if (name) 62 do { 63 newitem->gid += 0x0001; 64 for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next) 65 if ((cur->gid == newitem->gid) && (cur->gid == newitem->gid)) 66 i=1; 67 } while (i); 68 } 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. 90 * 91 * @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. 93 * @return Return 0 if no errors, otherwise return the error number. 94 */ 95 static int aim_ssi_itemlist_rebuildgroup(struct aim_ssi_item **list, struct aim_ssi_item *parentgroup) 96 { 97 int newlen; 98 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 165 return 0; 166 } 167 168 /** 169 * Locally find an item given a group ID# and a buddy ID#. 170 * 171 * @param list A pointer to the current list of items. 172 * @param gid The group ID# of the desired item. 173 * @param bid The buddy ID# of the desired item. 174 * @return Return a pointer to the item if found, else return NULL; 175 */ 176 faim_export struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, fu16_t gid, fu16_t bid) 177 { 178 struct aim_ssi_item *cur; 179 for (cur=list; cur; cur=cur->next) 180 if ((cur->gid == gid) && (cur->bid == bid)) 181 return cur; 182 return NULL; 183 } 184 185 /** 186 * Locally find an item given a group name, screen name, and type. If group name 187 * and screen name are null, then just return the first item of the given type. 188 * 189 * @param list A pointer to the current list of items. 190 * @param gn The group name of the desired item. 191 * @param bn The buddy name of the desired item. 192 * @param type The type of the desired item. 193 * @return Return a pointer to the item if found, else return NULL; 194 */ 195 faim_export struct aim_ssi_item *aim_ssi_itemlist_finditem(struct aim_ssi_item *list, const char *gn, const char *sn, fu16_t type) 196 { 197 struct aim_ssi_item *cur; 198 if (!list) 199 return NULL; 200 201 if (gn && sn) { /* For finding buddies in groups */ 202 for (cur=list; cur; cur=cur->next) 203 if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, sn))) { 204 struct aim_ssi_item *curg; 205 for (curg=list; curg; curg=curg->next) 206 if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid) && (curg->name) && !(aim_sncmp(curg->name, gn))) 207 return cur; 208 } 209 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))) 213 return cur; 214 215 /* For stuff without names--permit deny setting, visibility mask, etc. */ 216 } else for (cur=list; cur; cur=cur->next) { 217 if (cur->type == type) 218 return cur; 219 } 220 221 return NULL; 222 } 223 224 /** 225 * Locally find the parent item of the given buddy name. 226 * 227 * @param list A pointer to the current list of items. 228 * @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) 232 { 233 struct aim_ssi_item *cur, *curg; 234 if (!list || !sn) 235 return NULL; 236 if (!(cur = aim_ssi_itemlist_finditem(list, NULL, sn, AIM_SSI_TYPE_BUDDY))) 237 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; 242 } 243 244 /** 245 * Locally find the permit/deny setting item, and return the setting. 246 * 247 * @param list A pointer to the current list of items. 248 * @return Return the current SSI permit deny setting, or 0 if no setting was found. 249 */ 250 faim_export int aim_ssi_getpermdeny(struct aim_ssi_item *list) 251 { 252 struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PDINFO); 253 if (cur) { 254 aim_tlvlist_t *tlvlist = cur->data; 255 if (tlvlist) { 256 aim_tlv_t *tlv = aim_gettlv(tlvlist, 0x00ca, 1); 257 if (tlv && tlv->value) 258 return aimutil_get8(tlv->value); 259 } 260 } 261 return 0; 262 } 263 264 /** 265 * Locally find the presence flag item, and return the setting. The returned setting is a 266 * bitmask of the user flags that you are visible to. See the AIM_FLAG_* #defines 267 * in aim.h 268 * 269 * @param list A pointer to the current list of items. 270 * @return Return the current visibility mask. 271 */ 272 faim_export fu32_t aim_ssi_getpresence(struct aim_ssi_item *list) 273 { 274 struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS); 275 if (cur) { 276 aim_tlvlist_t *tlvlist = cur->data; 277 if (tlvlist) { 278 aim_tlv_t *tlv = aim_gettlv(tlvlist, 0x00c9, 1); 279 if (tlv && tlv->length) 280 return aimutil_get32(tlv->value); 281 } 282 } 283 return 0xFFFFFFFF; 284 } 285 286 /** 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. 290 * 291 * @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 * @return Return 0 if no errors, otherwise return the error number. 295 */ 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. 320 * 321 * @param sess The oscar session. 322 * @param conn The bos connection for this session. 323 * @return Return 0 if no errors, otherwise return the error number. 324 */ 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. 349 * 350 * @param sess The oscar session. 351 * @param conn The bos connection for this session. 352 * @return Return 0 if no errors, otherwise return the error number. 353 */ 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. 385 * 386 * @param sess The oscar session. 387 * @param conn The bos connection for this session. 388 * @return Return 0 if no errors, otherwise return the error number. 389 */ 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; 408 } 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); 420 } 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); 432 } 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. 485 * 486 * @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). 491 * @return Return 0 if no errors, otherwise return the error number. 492 */ 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. 546 * 547 * @param sess The oscar session. 548 * @param conn The bos connection for this session. 549 * @return Return 0 if no errors, otherwise return the error number. 550 */ 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; 678 679 return 0; 680 } 681 682 /** 683 * Move a buddy from one group to another group. This basically just deletes the 684 * buddy and re-adds it. 685 * 686 * @param sess The oscar session. 687 * @param conn The bos connection for this session. 688 * @param oldgn The group that the buddy is currently in. 689 * @param newgn The group that the buddy should be moved in to. 690 * @param sn The name of the buddy to be moved. 691 * @return Return 0 if no errors, otherwise return the error number. 692 */ 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?... 762 * 763 * @param sess The oscar session. 764 * @param conn The bos connection for this session. 765 * @param oldgn The old group name. 766 * @param newgn The new group name. 767 * @return Return 0 if no errors, otherwise return the error number. 768 */ 769 faim_export int aim_ssi_rename_group(aim_session_t *sess, aim_conn_t *conn, const char *oldgn, const char *newgn) 770 { 771 struct aim_ssi_item *group; 772 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 } 787 strcpy(group->name, newgn); 788 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. 800 * 801 * @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 be 986 * used for permit buddies, deny buddies, ICQ's ignore buddies, and 987 * 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 * @param permdeny Your permit/deny setting. Can be one of the following: 1048 * 1 - Allow all users 1049 * 2 - Block all users 1050 * 3 - Allow only the users below 1051 * 4 - Block only the users below 1052 * 5 - Allow only users on my buddy list 1053 * @param vismask A bitmask of the class of users to whom you want to be 1054 * visible. See the AIM_FLAG_BLEH #defines in aim.h 1055 * @return Return 0 if no errors, otherwise return the error number. 1056 */ 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); 1080 } 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); 1097 } 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 1109 return 0; 1110 } 1111 1112 /** 1113 * Stores your setting for whether you should show up as idle or not. 1114 * 1115 * @param sess The oscar session. 1116 * @param conn The bos connection for this session. 1117 * @param presence I think it's a bitmask, but I only know what one of the bits is: 1118 * 0x00000400 - Allow others to see your idle time 1119 * @return Return 0 if no errors, otherwise return the error number. 1120 */ 1121 faim_export int aim_ssi_setpresence(aim_session_t *sess, aim_conn_t *conn, fu32_t presence) { 1122 struct aim_ssi_item *cur; 1123 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 15 1162 /* 16 1163 * Request SSI Rights. … … 18 1165 faim_export int aim_ssi_reqrights(aim_session_t *sess, aim_conn_t *conn) 19 1166 { 20 return aim_genericreq_n(sess, conn, 0x0013, 0x0002);1167 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_REQRIGHTS); 21 1168 } 22 1169 … … 55 1202 return -ENOMEM; 56 1203 57 snacid = aim_cachesnac(sess, 0x0013, 0x0005, 0x0000, NULL, 0);58 59 aim_putsnac(&fr->data, 0x0013, 0x0005, 0x0000, snacid);1204 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_REQLIST, 0x0000, NULL, 0); 1205 1206 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_REQLIST, 0x0000, snacid); 60 1207 aimbs_put32(&fr->data, localstamp); 61 1208 aimbs_put16(&fr->data, localrev); … … 73 1220 int ret = 0; 74 1221 aim_rxcallback_t userfunc; 75 struct aim_ssi_item * list= NULL;1222 struct aim_ssi_item *cur = NULL; 76 1223 fu8_t fmtver; /* guess */ 77 fu16_t itemcount; 78 fu32_t stamp; 79 80 fmtver = aimbs_get8(bs); 81 itemcount = aimbs_get16(bs); 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 */ 1234 1235 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) ; 82 1241 83 1242 while (aim_bstream_empty(bs) > 4) { /* last four bytes are stamp */ 84 1243 fu16_t namelen, tbslen; 85 struct aim_ssi_item *nl, *el; 86 87 if (!(nl = malloc(sizeof(struct aim_ssi_item)))) 88 break; 89 memset(nl, 0, sizeof(struct aim_ssi_item)); 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)); 90 1255 91 1256 if ((namelen = aimbs_get16(bs))) 92 nl->name = aimbs_getstr(bs, namelen);93 nl->gid = aimbs_get16(bs);94 nl->bid = aimbs_get16(bs);95 nl->type = 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); 96 1261 97 1262 if ((tbslen = aimbs_get16(bs))) { … … 99 1264 100 1265 aim_bstream_init(&tbs, bs->data + bs->offset /* XXX */, tbslen); 101 nl->data = (void *)aim_readtlvchain(&tbs);1266 cur->data = (void *)aim_readtlvchain(&tbs); 102 1267 aim_bstream_advance(bs, tbslen); 103 1268 } 104 105 for (el = list; el && el->next; el = el->next) 106 ; 107 if (el) 108 el->next = nl; 109 else 110 list = nl; 111 } 112 113 stamp = aimbs_get32(bs); 1269 } 1270 1271 timestamp = aimbs_get32(bs); 1272 if (timestamp != 0) 1273 sess->ssi.timestamp = timestamp; 1274 sess->ssi.received_data = 1; 114 1275 115 1276 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 116 ret = userfunc(sess, rx, fmtver, itemcount, stamp, list); 117 118 while (list) { 119 struct aim_ssi_item *tmp; 120 121 tmp = list->next; 122 aim_freetlvchain((aim_tlvlist_t **)&list->data); 123 free(list); 124 list = tmp; 125 } 1277 ret = userfunc(sess, rx, fmtver, sess->ssi.revision, sess->ssi.timestamp, sess->ssi.items); 126 1278 127 1279 return ret; … … 139 1291 faim_export int aim_ssi_enable(aim_session_t *sess, aim_conn_t *conn) 140 1292 { 141 return aim_genericreq_n(sess, conn, 0x0013, 0x0007); 1293 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, 0x0007); 1294 } 1295 1296 /* 1297 * SSI Add/Mod/Del Item(s). 1298 * 1299 * Sends the SNAC to add, modify, or delete an item from the server-stored 1300 * information. These 3 SNACs all have an identical structure. The only 1301 * difference is the subtype that is set for the SNAC. 1302 * 1303 */ 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 { 1306 aim_frame_t *fr; 1307 aim_snacid_t snacid; 1308 int i, snaclen; 1309 1310 if (!sess || !conn || !items || !num) 1311 return -EINVAL; 1312 1313 snaclen = 10; /* For family, subtype, flags, and SNAC ID */ 1314 for (i=0; i<num; i++) { 1315 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); 1320 } 1321 1322 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, snaclen))) 1323 return -ENOMEM; 1324 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) 1352 { 1353 int ret = 0; 1354 aim_rxcallback_t userfunc; 1355 1356 sess->ssi.waiting_for_ack = 0; 1357 aim_ssi_dispatch(sess, rx->conn); 1358 1359 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 1360 ret = userfunc(sess, rx); 1361 1362 return ret; 142 1363 } 143 1364 … … 150 1371 faim_export int aim_ssi_modbegin(aim_session_t *sess, aim_conn_t *conn) 151 1372 { 152 return aim_genericreq_n(sess, conn, 0x0013, 0x0011);1373 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTART); 153 1374 } 154 1375 … … 161 1382 faim_export int aim_ssi_modend(aim_session_t *sess, aim_conn_t *conn) 162 1383 { 163 return aim_genericreq_n(sess, conn, 0x0013, 0x0012);1384 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTOP); 164 1385 } 165 1386 … … 176 1397 aim_rxcallback_t userfunc; 177 1398 1399 sess->ssi.received_data = 1; 1400 178 1401 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) 179 1402 ret = userfunc(sess, rx); … … 185 1408 { 186 1409 187 if (snac->subtype == 0x0003)1410 if (snac->subtype == AIM_CB_SSI_RIGHTSINFO) 188 1411 return parserights(sess, mod, rx, snac, bs); 189 else if (snac->subtype == 0x006)1412 else if (snac->subtype == AIM_CB_SSI_LIST) 190 1413 return parsedata(sess, mod, rx, snac, bs); 191 else if (snac->subtype == 0x00f) 1414 else if (snac->subtype == AIM_CB_SSI_SRVACK) 1415 return parseack(sess, mod, rx, snac, bs); 1416 else if (snac->subtype == AIM_CB_SSI_NOLIST) 192 1417 return parsedataunchanged(sess, mod, rx, snac, bs); 193 1418 … … 195 1420 } 196 1421 1422 static void ssi_shutdown(aim_session_t *sess, aim_module_t *mod) 1423 { 1424 aim_ssi_freelist(sess); 1425 1426 return; 1427 } 1428 197 1429 faim_internal int ssi_modfirst(aim_session_t *sess, aim_module_t *mod) 198 1430 { 199 1431 200 mod->family = 0x0013;1432 mod->family = AIM_CB_FAM_SSI; 201 1433 mod->version = 0x0001; 202 1434 mod->toolid = 0x0110; … … 205 1437 strncpy(mod->name, "ssi", sizeof(mod->name)); 206 1438 mod->snachandler = snachandler; 207 208 return 0; 209 } 210 211 1439 mod->shutdown = ssi_shutdown; 1440 1441 return 0; 1442 }
Note: See TracChangeset
for help on using the changeset viewer.