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