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