gnunet_chat_lib_intern.c (28809B)
1 /* 2 This file is part of GNUnet. 3 Copyright (C) 2021--2026 GNUnet e.V. 4 5 GNUnet is free software: you can redistribute it and/or modify it 6 under the terms of the GNU Affero General Public License as published 7 by the Free Software Foundation, either version 3 of the License, 8 or (at your option) any later version. 9 10 GNUnet is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Affero General Public License for more details. 14 15 You should have received a copy of the GNU Affero General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 SPDX-License-Identifier: AGPL3.0-or-later 19 */ 20 /* 21 * @author Tobias Frisch 22 * @file gnunet_chat_lib_intern.c 23 */ 24 25 #include "gnunet_chat_account.h" 26 #include "gnunet_chat_contact.h" 27 #include "gnunet_chat_context.h" 28 #include "gnunet_chat_group.h" 29 #include "gnunet_chat_handle.h" 30 #include "gnunet_chat_lib.h" 31 32 #include <gnunet/gnunet_common.h> 33 #include <gnunet/gnunet_messenger_service.h> 34 #include <gnunet/gnunet_reclaim_lib.h> 35 #include <gnunet/gnunet_reclaim_service.h> 36 #include <gnunet/gnunet_time_lib.h> 37 #include <stdint.h> 38 #include <string.h> 39 40 #define GNUNET_UNUSED __attribute__ ((unused)) 41 42 void 43 task_handle_destruction (void *cls) 44 { 45 GNUNET_assert(cls); 46 47 struct GNUNET_CHAT_Handle *handle = (struct GNUNET_CHAT_Handle*) cls; 48 49 struct GNUNET_CHAT_InternalAccounts *accounts = handle->accounts_head; 50 while (accounts) 51 { 52 if ((accounts->op) && (GNUNET_CHAT_ACCOUNT_NONE != accounts->method)) 53 break; 54 55 accounts = accounts->next; 56 } 57 58 if (accounts) 59 { 60 handle->destruction = GNUNET_SCHEDULER_add_delayed_with_priority( 61 GNUNET_TIME_relative_get_millisecond_(), 62 GNUNET_SCHEDULER_PRIORITY_BACKGROUND, 63 task_handle_destruction, 64 handle 65 ); 66 67 return; 68 } 69 70 handle->destruction = NULL; 71 handle_destroy(handle); 72 } 73 74 void 75 task_handle_connection (void *cls) 76 { 77 GNUNET_assert(cls); 78 79 struct GNUNET_CHAT_Handle *handle = (struct GNUNET_CHAT_Handle*) cls; 80 81 handle->connection = NULL; 82 83 if (! handle->next) 84 return; 85 86 struct GNUNET_CHAT_Account *account = handle->next; 87 struct GNUNET_HashCode local_secret; 88 const struct GNUNET_HashCode *secret; 89 90 if (handle->next_secret) 91 { 92 GNUNET_memcpy( 93 &local_secret, 94 handle->next_secret, 95 sizeof(local_secret) 96 ); 97 98 secret = &local_secret; 99 100 GNUNET_CRYPTO_zero_keys( 101 handle->next_secret, 102 sizeof(*(handle->next_secret)) 103 ); 104 105 GNUNET_free(handle->next_secret); 106 handle->next_secret = NULL; 107 } 108 else 109 secret = NULL; 110 111 handle->next = NULL; 112 handle_connect(handle, account, secret); 113 114 GNUNET_CRYPTO_zero_keys( 115 &local_secret, 116 sizeof(local_secret) 117 ); 118 } 119 120 void 121 task_handle_disconnection (void *cls) 122 { 123 GNUNET_assert(cls); 124 125 struct GNUNET_CHAT_Handle *handle = (struct GNUNET_CHAT_Handle*) cls; 126 127 handle->connection = NULL; 128 handle_disconnect(handle); 129 130 if (! handle->next) 131 return; 132 133 task_handle_connection(cls); 134 } 135 136 void 137 cb_lobby_lookup (void *cls, 138 uint32_t count, 139 const struct GNUNET_GNSRECORD_Data *data) 140 { 141 GNUNET_assert(cls); 142 143 struct GNUNET_CHAT_UriLookups *lookups = (struct GNUNET_CHAT_UriLookups*) cls; 144 145 if ((!(lookups->handle)) || (!(lookups->uri)) || 146 (GNUNET_CHAT_URI_TYPE_CHAT != lookups->uri->type)) 147 goto drop_lookup; 148 149 struct GNUNET_CHAT_Context *context = handle_process_records( 150 lookups->handle, 151 lookups->uri->chat.label, 152 count, 153 data 154 ); 155 156 if (context) 157 context_write_records(context); 158 159 drop_lookup: 160 if (lookups->uri) 161 uri_destroy(lookups->uri); 162 163 if (lookups->handle) 164 GNUNET_CONTAINER_DLL_remove( 165 lookups->handle->lookups_head, 166 lookups->handle->lookups_tail, 167 lookups 168 ); 169 170 GNUNET_free(lookups); 171 } 172 173 struct GNUNET_CHAT_IterateFiles 174 { 175 struct GNUNET_CHAT_Handle *handle; 176 GNUNET_CHAT_FileCallback cb; 177 void *cls; 178 }; 179 180 enum GNUNET_GenericReturnValue 181 it_iterate_files (void *cls, 182 GNUNET_UNUSED const struct GNUNET_HashCode *key, 183 void *value) 184 { 185 GNUNET_assert((cls) && (key)); 186 187 struct GNUNET_CHAT_IterateFiles *it = cls; 188 189 if (!(it->cb)) 190 return GNUNET_YES; 191 192 struct GNUNET_CHAT_File *file = (struct GNUNET_CHAT_File*) value; 193 194 if (!file) 195 return GNUNET_YES; 196 197 return it->cb(it->cls, it->handle, file); 198 } 199 200 struct GNUNET_CHAT_HandleIterateContacts 201 { 202 struct GNUNET_CHAT_Handle *handle; 203 GNUNET_CHAT_ContactCallback cb; 204 void *cls; 205 }; 206 207 enum GNUNET_GenericReturnValue 208 it_handle_iterate_contacts (void *cls, 209 GNUNET_UNUSED const struct GNUNET_ShortHashCode *key, 210 void *value) 211 { 212 GNUNET_assert((cls) && (value)); 213 214 struct GNUNET_CHAT_HandleIterateContacts *it = cls; 215 216 if (!(it->cb)) 217 return GNUNET_YES; 218 219 struct GNUNET_CHAT_Contact *contact = value; 220 221 return it->cb(it->cls, it->handle, contact); 222 } 223 224 enum GNUNET_GenericReturnValue 225 it_handle_find_own_contact (GNUNET_UNUSED void *cls, 226 struct GNUNET_CHAT_Handle *handle, 227 struct GNUNET_CHAT_Contact *contact) 228 { 229 GNUNET_assert((handle) && (contact)); 230 231 if (GNUNET_YES != GNUNET_CHAT_contact_is_owned(contact)) 232 return GNUNET_YES; 233 234 const char *contact_key = GNUNET_CHAT_contact_get_key(contact); 235 const char *handle_key = GNUNET_CHAT_get_key(handle); 236 237 if ((!contact_key) || (!handle_key) || 238 (0 != strcmp(contact_key, handle_key))) 239 return GNUNET_YES; 240 241 handle->own_contact = contact; 242 return GNUNET_NO; 243 } 244 245 struct GNUNET_CHAT_HandleIterateGroups 246 { 247 struct GNUNET_CHAT_Handle *handle; 248 GNUNET_CHAT_GroupCallback cb; 249 void *cls; 250 }; 251 252 enum GNUNET_GenericReturnValue 253 it_handle_iterate_groups (void *cls, 254 GNUNET_UNUSED const struct GNUNET_HashCode *key, 255 void *value) 256 { 257 GNUNET_assert((cls) && (value)); 258 259 struct GNUNET_CHAT_HandleIterateGroups *it = cls; 260 261 if (!(it->cb)) 262 return GNUNET_YES; 263 264 struct GNUNET_CHAT_Group *group = value; 265 266 return it->cb(it->cls, it->handle, group); 267 } 268 269 typedef void 270 (*GNUNET_CHAT_ContactIterateContextCallback) (struct GNUNET_CHAT_Contact *contact, 271 struct GNUNET_CHAT_Context *context, 272 const char *tag); 273 274 struct GNUNET_CHAT_ContactIterateContexts 275 { 276 struct GNUNET_CHAT_Contact *contact; 277 const char *tag; 278 279 GNUNET_CHAT_ContactIterateContextCallback cb; 280 }; 281 282 enum GNUNET_GenericReturnValue 283 it_contact_iterate_contexts (void *cls, 284 const struct GNUNET_HashCode *key, 285 GNUNET_UNUSED void *value) 286 { 287 GNUNET_assert((cls) && (key)); 288 289 struct GNUNET_CHAT_ContactIterateContexts *it = cls; 290 291 if (!(it->cb)) 292 return GNUNET_YES; 293 294 struct GNUNET_CHAT_Handle *handle = it->contact->handle; 295 struct GNUNET_CHAT_Context *context = GNUNET_CONTAINER_multihashmap_get( 296 handle->contexts, key); 297 298 if (! context) 299 return GNUNET_YES; 300 301 it->cb(it->contact, context, it->tag); 302 return GNUNET_YES; 303 } 304 305 struct GNUNET_CHAT_RoomFindContact 306 { 307 const struct GNUNET_CRYPTO_BlindablePublicKey *ignore_key; 308 const struct GNUNET_MESSENGER_Contact *contact; 309 }; 310 311 enum GNUNET_GenericReturnValue 312 it_room_find_contact (void *cls, 313 GNUNET_UNUSED struct GNUNET_MESSENGER_Room *room, 314 const struct GNUNET_MESSENGER_Contact *member) 315 { 316 GNUNET_assert((cls) && (member)); 317 318 const struct GNUNET_CRYPTO_BlindablePublicKey *key = GNUNET_MESSENGER_contact_get_key( 319 member 320 ); 321 322 struct GNUNET_CHAT_RoomFindContact *find = cls; 323 324 if ((find->ignore_key) && (key) && 325 (0 == GNUNET_memcmp(find->ignore_key, key))) 326 return GNUNET_YES; 327 328 find->contact = member; 329 return GNUNET_NO; 330 } 331 332 void 333 task_lobby_destruction (void *cls) 334 { 335 GNUNET_assert(cls); 336 337 struct GNUNET_CHAT_Lobby *lobby = (struct GNUNET_CHAT_Lobby*) cls; 338 struct GNUNET_CHAT_InternalLobbies *lobbies = lobby->handle->lobbies_head; 339 340 while (lobbies) 341 { 342 if (lobbies->lobby == lobby) 343 { 344 GNUNET_CONTAINER_DLL_remove( 345 lobby->handle->lobbies_head, 346 lobby->handle->lobbies_tail, 347 lobbies 348 ); 349 350 GNUNET_free(lobbies); 351 break; 352 } 353 354 lobbies = lobbies->next; 355 } 356 357 struct GNUNET_CHAT_Context *context = lobby->context; 358 359 lobby->destruction = NULL; 360 lobby_destroy(lobby); 361 362 if ((! context) || 363 (GNUNET_OK == GNUNET_CHAT_context_get_status(context))) 364 return; 365 366 context_delete(context, GNUNET_YES); 367 } 368 369 void 370 task_contact_destruction (void *cls) 371 { 372 GNUNET_assert(cls); 373 374 struct GNUNET_CHAT_Contact *contact = (struct GNUNET_CHAT_Contact*) cls; 375 struct GNUNET_ShortHashCode shorthash; 376 377 util_shorthash_from_member(contact->member, &shorthash); 378 379 contact_leave (contact, contact->context); 380 381 const uint32_t other_contexts = GNUNET_CONTAINER_multihashmap_size( 382 contact->joined 383 ); 384 385 if (0 >= other_contexts) 386 GNUNET_CONTAINER_multishortmap_remove( 387 contact->handle->contacts, &shorthash, contact 388 ); 389 390 context_delete(contact->context, GNUNET_YES); 391 392 contact->destruction = NULL; 393 394 if (0 >= other_contexts) 395 contact_destroy(contact); 396 } 397 398 void 399 task_group_destruction (void *cls) 400 { 401 GNUNET_assert(cls); 402 403 struct GNUNET_CHAT_Group *group = (struct GNUNET_CHAT_Group*) cls; 404 struct GNUNET_HashCode key; 405 406 GNUNET_memcpy(&key, GNUNET_MESSENGER_room_get_key( 407 group->context->room 408 ), sizeof(key)); 409 410 GNUNET_CONTAINER_multihashmap_remove( 411 group->handle->groups, &key, group 412 ); 413 414 context_delete(group->context, GNUNET_YES); 415 416 group->destruction = NULL; 417 418 group_destroy(group); 419 } 420 421 struct GNUNET_CHAT_GroupIterateContacts 422 { 423 struct GNUNET_CHAT_Group *group; 424 GNUNET_CHAT_GroupContactCallback cb; 425 void *cls; 426 }; 427 428 enum GNUNET_GenericReturnValue 429 it_group_iterate_contacts (void* cls, 430 GNUNET_UNUSED struct GNUNET_MESSENGER_Room *room, 431 const struct GNUNET_MESSENGER_Contact *member) 432 { 433 GNUNET_assert((cls) && (member)); 434 435 struct GNUNET_CHAT_GroupIterateContacts *it = cls; 436 437 if (!(it->cb)) 438 return GNUNET_YES; 439 440 return it->cb(it->cls, it->group, handle_get_contact_from_messenger( 441 it->group->handle, member 442 )); 443 } 444 445 struct GNUNET_CHAT_ContextIterateMessages 446 { 447 struct GNUNET_CHAT_Context *context; 448 GNUNET_CHAT_ContextMessageCallback cb; 449 void *cls; 450 }; 451 452 enum GNUNET_GenericReturnValue 453 it_context_iterate_messages (void *cls, 454 GNUNET_UNUSED const struct GNUNET_HashCode *key, 455 void *value) 456 { 457 GNUNET_assert((cls) && (value)); 458 459 struct GNUNET_CHAT_ContextIterateMessages *it = cls; 460 461 if (!(it->cb)) 462 return GNUNET_YES; 463 464 struct GNUNET_CHAT_Message *message = value; 465 466 return it->cb(it->cls, it->context, message); 467 } 468 469 struct GNUNET_CHAT_ContextIterateFiles 470 { 471 struct GNUNET_CHAT_Context *context; 472 GNUNET_CHAT_ContextFileCallback cb; 473 void *cls; 474 }; 475 476 enum GNUNET_GenericReturnValue 477 it_context_iterate_files (void *cls, 478 const struct GNUNET_HashCode *key, 479 GNUNET_UNUSED void *value) 480 { 481 GNUNET_assert((cls) && (key)); 482 483 struct GNUNET_CHAT_ContextIterateFiles *it = cls; 484 485 if (!(it->cb)) 486 return GNUNET_YES; 487 488 struct GNUNET_CHAT_Message *message = GNUNET_CONTAINER_multihashmap_get( 489 it->context->messages, key 490 ); 491 492 if ((!message) || (! message->msg)) 493 return GNUNET_YES; 494 495 struct GNUNET_CHAT_File *file = GNUNET_CONTAINER_multihashmap_get( 496 it->context->handle->files, &(message->msg->body.file.hash) 497 ); 498 499 if (!file) 500 return GNUNET_YES; 501 502 return it->cb(it->cls, it->context, file); 503 } 504 505 struct GNUNET_CHAT_ContextIterateDiscourses 506 { 507 struct GNUNET_CHAT_Context *context; 508 GNUNET_CHAT_DiscourseCallback cb; 509 void *cls; 510 }; 511 512 enum GNUNET_GenericReturnValue 513 it_context_iterate_discourses (void *cls, 514 GNUNET_UNUSED const struct GNUNET_ShortHashCode *key, 515 void *value) 516 { 517 GNUNET_assert((cls) && (value)); 518 519 struct GNUNET_CHAT_ContextIterateDiscourses *it = cls; 520 struct GNUNET_CHAT_Discourse *discourse = value; 521 522 if (!(it->cb)) 523 return GNUNET_YES; 524 525 return it->cb(it->cls, it->context, discourse); 526 } 527 528 struct GNUNET_CHAT_MessageIterateReadReceipts 529 { 530 struct GNUNET_CHAT_Message *message; 531 GNUNET_CHAT_MessageReadReceiptCallback cb; 532 void *cls; 533 }; 534 535 enum GNUNET_GenericReturnValue 536 it_message_iterate_read_receipts (void *cls, 537 GNUNET_UNUSED struct GNUNET_MESSENGER_Room *room, 538 const struct GNUNET_MESSENGER_Contact *member) 539 { 540 GNUNET_assert((cls) && (member)); 541 542 struct GNUNET_CHAT_MessageIterateReadReceipts *it = cls; 543 struct GNUNET_CHAT_Handle *handle = it->message->context->handle; 544 545 if (!handle) 546 return GNUNET_NO; 547 548 struct GNUNET_ShortHashCode shorthash; 549 util_shorthash_from_member(member, &shorthash); 550 551 struct GNUNET_CHAT_Contact *contact = GNUNET_CONTAINER_multishortmap_get( 552 handle->contacts, &shorthash 553 ); 554 555 if (!contact) 556 return GNUNET_YES; 557 558 struct GNUNET_TIME_Absolute *timestamp = GNUNET_CONTAINER_multishortmap_get( 559 it->message->context->timestamps, &shorthash 560 ); 561 562 if (!timestamp) 563 return GNUNET_YES; 564 565 struct GNUNET_TIME_Absolute abs = GNUNET_TIME_absolute_ntoh( 566 it->message->msg->header.timestamp 567 ); 568 569 struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference( 570 *timestamp, abs 571 ); 572 573 int read_receipt; 574 if (GNUNET_TIME_relative_get_zero_().rel_value_us == delta.rel_value_us) 575 read_receipt = GNUNET_YES; 576 else 577 read_receipt = GNUNET_NO; 578 579 if (it->cb) 580 it->cb(it->cls, it->message, contact, read_receipt); 581 582 return GNUNET_YES; 583 } 584 585 void 586 cont_update_attribute_with_status (void *cls, 587 int32_t success, 588 const char *emsg) 589 { 590 GNUNET_assert(cls); 591 592 struct GNUNET_CHAT_AttributeProcess *attributes = ( 593 (struct GNUNET_CHAT_AttributeProcess*) cls 594 ); 595 596 attributes->op = NULL; 597 598 struct GNUNET_CHAT_Account *account = attributes->account; 599 struct GNUNET_CHAT_Handle *handle = attributes->handle; 600 601 const char *attribute_name = NULL; 602 603 if (attributes->attribute) 604 attribute_name = attributes->attribute->name; 605 606 if (GNUNET_SYSERR == success) 607 handle_send_internal_message( 608 handle, 609 account, 610 NULL, 611 GNUNET_CHAT_FLAG_WARNING, 612 emsg, 613 GNUNET_YES 614 ); 615 else 616 handle_send_internal_message( 617 handle, 618 account, 619 NULL, 620 GNUNET_CHAT_FLAG_ATTRIBUTES, 621 attribute_name, 622 GNUNET_YES 623 ); 624 625 internal_attributes_destroy(attributes); 626 } 627 628 void 629 cb_task_finish_iterate_attribute (void *cls) 630 { 631 GNUNET_assert(cls); 632 633 struct GNUNET_CHAT_AttributeProcess *attributes = ( 634 (struct GNUNET_CHAT_AttributeProcess*) cls 635 ); 636 637 attributes->iter = NULL; 638 639 struct GNUNET_CHAT_Handle *handle = attributes->handle; 640 641 const struct GNUNET_CRYPTO_BlindablePrivateKey *key; 642 643 if (attributes->account) 644 key = account_get_key(attributes->account); 645 else 646 key = handle_get_key(handle); 647 648 if (attributes->name) 649 GNUNET_free(attributes->name); 650 651 attributes->name = NULL; 652 653 if ((! attributes->op) && (key) && 654 (attributes->attribute)) 655 attributes->op = GNUNET_RECLAIM_attribute_store( 656 handle->reclaim, 657 key, 658 attributes->attribute, 659 &(attributes->expires), 660 cont_update_attribute_with_status, 661 attributes 662 ); 663 664 if (attributes->data) 665 GNUNET_free(attributes->data); 666 667 attributes->data = NULL; 668 669 if (attributes->op) 670 return; 671 672 internal_attributes_destroy(attributes); 673 } 674 675 void 676 cb_task_error_iterate_attribute (void *cls) 677 { 678 GNUNET_assert(cls); 679 680 struct GNUNET_CHAT_AttributeProcess *attributes = ( 681 (struct GNUNET_CHAT_AttributeProcess*) cls 682 ); 683 684 handle_send_internal_message( 685 attributes->handle, 686 attributes->account, 687 NULL, 688 GNUNET_CHAT_FLAG_WARNING, 689 "Attribute iteration failed!", 690 GNUNET_YES 691 ); 692 693 cb_task_finish_iterate_attribute(cls); 694 } 695 696 void 697 cb_store_attribute (void *cls, 698 const struct GNUNET_CRYPTO_BlindablePublicKey *identity, 699 const struct GNUNET_RECLAIM_Attribute *attribute) 700 { 701 GNUNET_assert(cls); 702 703 struct GNUNET_CHAT_AttributeProcess *attributes = ( 704 (struct GNUNET_CHAT_AttributeProcess*) cls 705 ); 706 707 struct GNUNET_CHAT_Handle *handle = attributes->handle; 708 709 const struct GNUNET_CRYPTO_BlindablePrivateKey *key = handle_get_key( 710 handle 711 ); 712 713 if (! attributes->name) 714 { 715 internal_attributes_stop_iter(attributes); 716 return; 717 } 718 719 if (0 == strcmp(attribute->name, attributes->name)) 720 { 721 internal_attributes_stop_iter(attributes); 722 723 if (attributes->attribute) 724 { 725 attributes->attribute->credential = attribute->credential; 726 attributes->attribute->flag = attribute->flag; 727 attributes->attribute->id = attribute->id; 728 } 729 730 attributes->op = GNUNET_RECLAIM_attribute_store( 731 handle->reclaim, 732 key, 733 attributes->attribute, 734 &(attributes->expires), 735 cont_update_attribute_with_status, 736 attributes 737 ); 738 739 if (attributes->data) 740 GNUNET_free(attributes->data); 741 742 attributes->data = NULL; 743 744 GNUNET_free(attributes->name); 745 attributes->name = NULL; 746 return; 747 } 748 749 internal_attributes_next_iter(attributes); 750 } 751 752 void 753 cb_delete_attribute (void *cls, 754 const struct GNUNET_CRYPTO_BlindablePublicKey *identity, 755 const struct GNUNET_RECLAIM_Attribute *attribute) 756 { 757 GNUNET_assert(cls); 758 759 struct GNUNET_CHAT_AttributeProcess *attributes = ( 760 (struct GNUNET_CHAT_AttributeProcess*) cls 761 ); 762 763 if (! attributes->name) 764 { 765 internal_attributes_stop_iter(attributes); 766 return; 767 } 768 769 struct GNUNET_CHAT_Handle *handle = attributes->handle; 770 771 const struct GNUNET_CRYPTO_BlindablePrivateKey *key = handle_get_key( 772 handle 773 ); 774 775 if (0 == strcmp(attribute->name, attributes->name)) 776 { 777 internal_attributes_stop_iter(attributes); 778 779 attributes->op = GNUNET_RECLAIM_attribute_delete( 780 handle->reclaim, 781 key, 782 attribute, 783 cont_update_attribute_with_status, 784 attributes 785 ); 786 787 GNUNET_free(attributes->name); 788 attributes->name = NULL; 789 return; 790 } 791 792 internal_attributes_next_iter(attributes); 793 } 794 795 void 796 cb_iterate_attribute (void *cls, 797 const struct GNUNET_CRYPTO_BlindablePublicKey *identity, 798 const struct GNUNET_RECLAIM_Attribute *attribute) 799 { 800 GNUNET_assert(cls); 801 802 struct GNUNET_CHAT_AttributeProcess *attributes = ( 803 (struct GNUNET_CHAT_AttributeProcess*) cls 804 ); 805 806 struct GNUNET_CHAT_Handle *handle = attributes->handle; 807 enum GNUNET_GenericReturnValue result = GNUNET_YES; 808 809 char *value = GNUNET_RECLAIM_attribute_value_to_string( 810 attribute->type, 811 attribute->data, 812 attribute->data_size 813 ); 814 815 if (attributes->callback) 816 result = attributes->callback(attributes->closure, handle, attribute->name, value); 817 else if (attributes->account_callback) 818 result = attributes->account_callback( 819 attributes->closure, 820 attributes->account, 821 attribute->name, 822 value 823 ); 824 825 if (value) 826 GNUNET_free (value); 827 828 if (GNUNET_YES != result) 829 internal_attributes_stop_iter(attributes); 830 else 831 internal_attributes_next_iter(attributes); 832 } 833 834 void 835 cb_issue_ticket (void *cls, 836 const struct GNUNET_RECLAIM_Ticket *ticket, 837 const struct GNUNET_RECLAIM_PresentationList *presentations) 838 { 839 GNUNET_assert(cls); 840 841 struct GNUNET_CHAT_AttributeProcess *attributes = ( 842 (struct GNUNET_CHAT_AttributeProcess*) cls 843 ); 844 845 attributes->op = NULL; 846 847 if ((!(attributes->contact)) || (!(attributes->contact->member))) 848 goto skip_sending; 849 850 struct GNUNET_CHAT_Context *context = contact_find_context( 851 attributes->contact, 852 GNUNET_YES 853 ); 854 855 if ((!context) || (!ticket)) 856 goto skip_sending; 857 858 char *identifier = GNUNET_strdup(ticket->gns_name); 859 860 if (!identifier) 861 goto skip_sending; 862 863 struct GNUNET_MESSENGER_Message message; 864 memset(&message, 0, sizeof(message)); 865 866 message.header.kind = GNUNET_MESSENGER_KIND_TICKET; 867 message.body.ticket.identifier = identifier; 868 869 GNUNET_MESSENGER_send_message( 870 context->room, 871 &message, 872 attributes->contact->member 873 ); 874 875 GNUNET_free(identifier); 876 877 skip_sending: 878 internal_attributes_destroy(attributes); 879 } 880 881 static struct GNUNET_RECLAIM_AttributeList* 882 attribute_list_from_attribute (const struct GNUNET_RECLAIM_Attribute *attribute) 883 { 884 struct GNUNET_RECLAIM_AttributeList *attrs; 885 struct GNUNET_RECLAIM_AttributeListEntry *le; 886 887 attrs = GNUNET_new (struct GNUNET_RECLAIM_AttributeList); 888 889 if (!attrs) 890 return NULL; 891 892 le = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry); 893 894 if (!le) 895 { 896 GNUNET_free (attrs); 897 return NULL; 898 } 899 900 le->attribute = GNUNET_RECLAIM_attribute_new ( 901 attribute->name, 902 &(attribute->credential), 903 attribute->type, 904 attribute->data, 905 attribute->data_size 906 ); 907 908 le->attribute->flag = attribute->flag; 909 le->attribute->id = attribute->id; 910 911 GNUNET_CONTAINER_DLL_insert ( 912 attrs->list_head, 913 attrs->list_tail, 914 le 915 ); 916 917 return attrs; 918 } 919 920 void 921 cb_share_attribute (void *cls, 922 const struct GNUNET_CRYPTO_BlindablePublicKey *identity, 923 const struct GNUNET_RECLAIM_Attribute *attribute) 924 { 925 GNUNET_assert(cls); 926 927 struct GNUNET_CHAT_AttributeProcess *attributes = ( 928 (struct GNUNET_CHAT_AttributeProcess*) cls 929 ); 930 931 if (! attributes->name) 932 { 933 internal_attributes_stop_iter(attributes); 934 return; 935 } 936 937 struct GNUNET_CHAT_Handle *handle = attributes->handle; 938 939 if (0 != strcmp(attribute->name, attributes->name)) 940 { 941 internal_attributes_next_iter(attributes); 942 return; 943 } 944 945 internal_attributes_stop_iter(attributes); 946 947 GNUNET_free(attributes->name); 948 attributes->name = NULL; 949 950 const struct GNUNET_CRYPTO_BlindablePrivateKey *key = handle_get_key( 951 handle 952 ); 953 954 if (!key) 955 return; 956 957 const struct GNUNET_CRYPTO_BlindablePublicKey *pubkey = contact_get_key( 958 attributes->contact 959 ); 960 961 if (!pubkey) 962 return; 963 964 char *rp_uri = GNUNET_CRYPTO_blindable_public_key_to_string(pubkey); 965 966 struct GNUNET_RECLAIM_AttributeList *attrs; 967 attrs = attribute_list_from_attribute(attribute); 968 969 if (!attrs) 970 goto cleanup; 971 972 attributes->op = GNUNET_RECLAIM_ticket_issue( 973 handle->reclaim, 974 key, 975 rp_uri, 976 attrs, 977 cb_issue_ticket, 978 attributes 979 ); 980 981 GNUNET_RECLAIM_attribute_list_destroy(attrs); 982 983 cleanup: 984 GNUNET_free(rp_uri); 985 } 986 987 void 988 cb_task_finish_iterate_ticket (void *cls) 989 { 990 GNUNET_assert(cls); 991 992 struct GNUNET_CHAT_TicketProcess *tickets = ( 993 (struct GNUNET_CHAT_TicketProcess*) cls 994 ); 995 996 tickets->iter = NULL; 997 998 internal_tickets_destroy(tickets); 999 } 1000 1001 void 1002 cb_task_error_iterate_ticket (void *cls) 1003 { 1004 GNUNET_assert(cls); 1005 1006 struct GNUNET_CHAT_TicketProcess *tickets = ( 1007 (struct GNUNET_CHAT_TicketProcess*) cls 1008 ); 1009 1010 handle_send_internal_message( 1011 tickets->handle, 1012 NULL, 1013 NULL, 1014 GNUNET_CHAT_FLAG_WARNING, 1015 "Ticket iteration failed!", 1016 GNUNET_YES 1017 ); 1018 1019 cb_task_finish_iterate_ticket(cls); 1020 } 1021 1022 void 1023 cont_revoke_ticket (void *cls, 1024 int32_t success, 1025 const char *emsg) 1026 { 1027 GNUNET_assert(cls); 1028 1029 struct GNUNET_CHAT_TicketProcess *tickets = ( 1030 (struct GNUNET_CHAT_TicketProcess*) cls 1031 ); 1032 1033 tickets->op = NULL; 1034 1035 struct GNUNET_CHAT_Handle *handle = tickets->handle; 1036 1037 if (success == GNUNET_SYSERR) 1038 handle_send_internal_message( 1039 handle, 1040 NULL, 1041 NULL, 1042 GNUNET_CHAT_FLAG_WARNING, 1043 emsg, 1044 GNUNET_YES 1045 ); 1046 else 1047 handle_send_internal_message( 1048 handle, 1049 NULL, 1050 NULL, 1051 GNUNET_CHAT_FLAG_SHARE_ATTRIBUTES, 1052 NULL, 1053 GNUNET_NO 1054 ); 1055 1056 internal_tickets_destroy(tickets); 1057 } 1058 1059 void 1060 cb_consume_ticket_check (void *cls, 1061 const struct GNUNET_CRYPTO_BlindablePublicKey *identity, 1062 const struct GNUNET_RECLAIM_Attribute *attribute, 1063 const struct GNUNET_RECLAIM_Presentation *presentation) 1064 { 1065 GNUNET_assert(cls); 1066 1067 struct GNUNET_CHAT_TicketProcess *tickets = ( 1068 (struct GNUNET_CHAT_TicketProcess*) cls 1069 ); 1070 1071 if ((!identity) && (!attribute) && (!presentation)) 1072 { 1073 tickets->op = NULL; 1074 1075 struct GNUNET_CHAT_Handle *handle = tickets->handle; 1076 1077 const struct GNUNET_CRYPTO_BlindablePrivateKey *key = handle_get_key( 1078 handle 1079 ); 1080 1081 if (tickets->name) 1082 { 1083 GNUNET_free(tickets->name); 1084 tickets->name = NULL; 1085 } 1086 else if (key) 1087 tickets->op = GNUNET_RECLAIM_ticket_revoke( 1088 handle->reclaim, 1089 key, 1090 tickets->ticket, 1091 cont_revoke_ticket, 1092 tickets 1093 ); 1094 1095 if (tickets->ticket) 1096 { 1097 GNUNET_free(tickets->ticket); 1098 tickets->ticket = NULL; 1099 } 1100 1101 if (tickets->op) 1102 return; 1103 1104 internal_tickets_destroy(tickets); 1105 return; 1106 } 1107 1108 if ((!attribute) || (! tickets->name) || 1109 (0 != strcmp(tickets->name, attribute->name))) 1110 return; 1111 1112 if (tickets->name) 1113 { 1114 GNUNET_free(tickets->name); 1115 tickets->name = NULL; 1116 } 1117 } 1118 1119 static enum GNUNET_GenericReturnValue 1120 is_contact_ticket_audience (const struct GNUNET_CHAT_Contact *contact, 1121 const char *rp_uri) 1122 { 1123 GNUNET_assert((contact) && (rp_uri)); 1124 1125 const struct GNUNET_CRYPTO_BlindablePublicKey *pubkey; 1126 pubkey = contact_get_key(contact); 1127 1128 if (!pubkey) 1129 return GNUNET_NO; 1130 1131 struct GNUNET_CRYPTO_BlindablePublicKey audience; 1132 enum GNUNET_GenericReturnValue parsing; 1133 1134 parsing = GNUNET_CRYPTO_blindable_public_key_from_string(rp_uri, &audience); 1135 1136 if ((GNUNET_OK != parsing) || (0 != GNUNET_memcmp(pubkey, &audience))) 1137 return GNUNET_NO; 1138 1139 return GNUNET_YES; 1140 } 1141 1142 void 1143 cb_iterate_ticket_check (void *cls, 1144 const struct GNUNET_RECLAIM_Ticket *ticket, 1145 const char *rp_uri) 1146 { 1147 GNUNET_assert(cls); 1148 1149 struct GNUNET_CHAT_TicketProcess *tickets = ( 1150 (struct GNUNET_CHAT_TicketProcess*) cls 1151 ); 1152 1153 struct GNUNET_CHAT_Handle *handle = tickets->handle; 1154 1155 if ((!rp_uri) || (!(tickets->contact)) || 1156 (GNUNET_YES != is_contact_ticket_audience(tickets->contact, rp_uri))) 1157 { 1158 internal_tickets_next_iter(tickets); 1159 return; 1160 } 1161 1162 const struct GNUNET_CRYPTO_BlindablePrivateKey *key = handle_get_key( 1163 handle 1164 ); 1165 1166 if (!key) 1167 { 1168 internal_tickets_stop_iter(tickets); 1169 return; 1170 } 1171 1172 struct GNUNET_CHAT_TicketProcess *new_tickets; 1173 new_tickets = internal_tickets_copy(tickets, ticket); 1174 1175 if (!new_tickets) 1176 { 1177 internal_tickets_stop_iter(tickets); 1178 return; 1179 } 1180 1181 new_tickets->op = GNUNET_RECLAIM_ticket_consume( 1182 handle->reclaim, 1183 ticket, 1184 rp_uri, 1185 cb_consume_ticket_check, 1186 new_tickets 1187 ); 1188 1189 internal_tickets_next_iter(tickets); 1190 } 1191 1192 void 1193 cb_consume_ticket (void *cls, 1194 const struct GNUNET_CRYPTO_BlindablePublicKey *identity, 1195 const struct GNUNET_RECLAIM_Attribute *attribute, 1196 const struct GNUNET_RECLAIM_Presentation *presentation) 1197 { 1198 GNUNET_assert(cls); 1199 1200 struct GNUNET_CHAT_TicketProcess *tickets = ( 1201 (struct GNUNET_CHAT_TicketProcess*) cls 1202 ); 1203 1204 if ((!identity) && (!attribute) && (!presentation)) 1205 { 1206 tickets->op = NULL; 1207 1208 internal_tickets_destroy(tickets); 1209 return; 1210 } 1211 1212 if (!attribute) 1213 return; 1214 1215 char *value = GNUNET_RECLAIM_attribute_value_to_string( 1216 attribute->type, 1217 attribute->data, 1218 attribute->data_size 1219 ); 1220 1221 if (tickets->callback) 1222 tickets->callback(tickets->closure, tickets->contact, attribute->name, value); 1223 1224 if (value) 1225 GNUNET_free (value); 1226 } 1227 1228 void 1229 cb_iterate_ticket (void *cls, 1230 const struct GNUNET_RECLAIM_Ticket *ticket, 1231 const char *rp_uri) 1232 { 1233 GNUNET_assert(cls); 1234 1235 struct GNUNET_CHAT_TicketProcess *tickets = ( 1236 (struct GNUNET_CHAT_TicketProcess*) cls 1237 ); 1238 1239 struct GNUNET_CHAT_Handle *handle = tickets->handle; 1240 1241 if ((!rp_uri) || (!(tickets->contact)) || 1242 (GNUNET_YES != is_contact_ticket_audience(tickets->contact, rp_uri))) 1243 { 1244 internal_tickets_next_iter(tickets); 1245 return; 1246 } 1247 1248 const struct GNUNET_CRYPTO_BlindablePrivateKey *key = handle_get_key( 1249 handle 1250 ); 1251 1252 if (!key) 1253 { 1254 internal_tickets_stop_iter(tickets); 1255 return; 1256 } 1257 1258 struct GNUNET_CHAT_TicketProcess *new_tickets; 1259 new_tickets = internal_tickets_copy(tickets, NULL); 1260 1261 if (!new_tickets) 1262 { 1263 internal_tickets_stop_iter(tickets); 1264 return; 1265 } 1266 1267 new_tickets->op = GNUNET_RECLAIM_ticket_consume( 1268 handle->reclaim, 1269 ticket, 1270 rp_uri, 1271 cb_consume_ticket, 1272 new_tickets 1273 ); 1274 1275 internal_tickets_next_iter(tickets); 1276 }