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