gnunet_chat_handle_intern.c (31186B)
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_handle_intern.c 23 */ 24 25 #include "gnunet_chat_contact.h" 26 #include "gnunet_chat_context.h" 27 #include "gnunet_chat_discourse.h" 28 #include "gnunet_chat_file.h" 29 #include "gnunet_chat_group.h" 30 #include "gnunet_chat_handle.h" 31 #include "gnunet_chat_invitation.h" 32 #include "gnunet_chat_lobby.h" 33 #include "gnunet_chat_message.h" 34 #include "gnunet_chat_ticket.h" 35 #include "gnunet_chat_util.h" 36 37 #include "internal/gnunet_chat_accounts.h" 38 #include "internal/gnunet_chat_tagging.h" 39 40 #include <gnunet/gnunet_arm_service.h> 41 #include <gnunet/gnunet_common.h> 42 #include <gnunet/gnunet_hello_uri_lib.h> 43 #include <gnunet/gnunet_identity_service.h> 44 #include <gnunet/gnunet_messenger_service.h> 45 #include <gnunet/gnunet_reclaim_service.h> 46 #include <gnunet/gnunet_scheduler_lib.h> 47 #include <gnunet/gnunet_time_lib.h> 48 #include <gnunet/gnunet_util_lib.h> 49 50 #include <stdio.h> 51 #include <string.h> 52 53 #define GNUNET_UNUSED __attribute__ ((unused)) 54 55 static const char gnunet_service_name_arm [] = "arm"; 56 static const char gnunet_service_name_fs [] = "fs"; 57 static const char gnunet_service_name_gns [] = "gns"; 58 static const char gnunet_service_name_identity [] = "identity"; 59 static const char gnunet_service_name_messenger [] = "messenger"; 60 static const char gnunet_service_name_namestore [] = "namestore"; 61 static const char gnunet_service_name_pils [] = "pils"; 62 static const char gnunet_service_name_reclaim [] = "reclaim"; 63 64 void 65 on_handle_shutdown(void *cls) 66 { 67 struct GNUNET_CHAT_Handle *chat = cls; 68 69 GNUNET_assert((chat) && (chat->shutdown_hook)); 70 chat->shutdown_hook = NULL; 71 72 handle_destroy(chat); 73 } 74 75 void 76 on_handle_service_request(void *cls, 77 enum GNUNET_ARM_RequestStatus status, 78 enum GNUNET_ARM_Result result) 79 { 80 GNUNET_assert(cls); 81 82 struct GNUNET_CHAT_InternalServices *services = cls; 83 services->op = NULL; 84 85 if (status != GNUNET_ARM_REQUEST_SENT_OK) 86 return; 87 88 struct GNUNET_CHAT_Handle *chat = services->chat; 89 90 GNUNET_CONTAINER_DLL_remove( 91 chat->services_head, 92 chat->services_tail, 93 services 94 ); 95 96 GNUNET_free(services); 97 } 98 99 static void 100 _request_service_via_arm(struct GNUNET_CHAT_Handle *chat, 101 const char *service_name) 102 { 103 GNUNET_assert((chat) && (chat->arm) && (service_name)); 104 105 struct GNUNET_CHAT_InternalServices *services = GNUNET_new( 106 struct GNUNET_CHAT_InternalServices 107 ); 108 109 if (! services) 110 return; 111 112 services->chat = chat; 113 services->op = GNUNET_ARM_request_service_start( 114 chat->arm, 115 service_name, 116 GNUNET_OS_INHERIT_STD_NONE, 117 on_handle_service_request, 118 services 119 ); 120 121 GNUNET_CONTAINER_DLL_insert( 122 chat->services_head, 123 chat->services_tail, 124 services 125 ); 126 } 127 128 void 129 on_handle_arm_connection(void *cls, 130 int connected) 131 { 132 struct GNUNET_CHAT_Handle *chat = cls; 133 134 GNUNET_assert((chat) && (chat->arm)); 135 136 if (GNUNET_YES == connected) 137 { 138 _request_service_via_arm(chat, gnunet_service_name_identity); 139 _request_service_via_arm(chat, gnunet_service_name_messenger); 140 _request_service_via_arm(chat, gnunet_service_name_fs); 141 _request_service_via_arm(chat, gnunet_service_name_gns); 142 _request_service_via_arm(chat, gnunet_service_name_namestore); 143 _request_service_via_arm(chat, gnunet_service_name_pils); 144 _request_service_via_arm(chat, gnunet_service_name_reclaim); 145 } 146 else 147 { 148 _request_service_via_arm(chat, gnunet_service_name_arm); 149 } 150 } 151 152 void* 153 notify_handle_fs_progress(void* cls, 154 const struct GNUNET_FS_ProgressInfo* info) 155 { 156 struct GNUNET_CHAT_Handle *chat = cls; 157 158 GNUNET_assert(info); 159 160 if (!chat) 161 return NULL; 162 163 switch (info->status) { 164 case GNUNET_FS_STATUS_PUBLISH_START: { 165 struct GNUNET_CHAT_File *file = info->value.publish.cctx; 166 167 file_update_upload( 168 file, 169 0, 170 info->value.publish.size 171 ); 172 173 return file; 174 } case GNUNET_FS_STATUS_PUBLISH_PROGRESS: { 175 struct GNUNET_CHAT_File *file = info->value.publish.cctx; 176 177 file_update_upload( 178 file, 179 info->value.publish.completed, 180 info->value.publish.size 181 ); 182 183 return file; 184 } case GNUNET_FS_STATUS_PUBLISH_COMPLETED: { 185 struct GNUNET_CHAT_File *file = info->value.publish.cctx; 186 187 file->uri = GNUNET_FS_uri_dup( 188 info->value.publish.specifics.completed.chk_uri 189 ); 190 191 file_update_upload( 192 file, 193 info->value.publish.size, 194 info->value.publish.size 195 ); 196 197 file->publish = NULL; 198 break; 199 } case GNUNET_FS_STATUS_PUBLISH_ERROR: { 200 break; 201 } case GNUNET_FS_STATUS_DOWNLOAD_START: { 202 struct GNUNET_CHAT_File *file = info->value.download.cctx; 203 204 file_update_download( 205 file, 206 0, 207 info->value.download.size 208 ); 209 210 return file; 211 } case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: { 212 return info->value.download.cctx; 213 } case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: { 214 return info->value.download.cctx; 215 } case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: { 216 struct GNUNET_CHAT_File *file = info->value.download.cctx; 217 218 file_update_download( 219 file, 220 info->value.download.completed, 221 info->value.download.size 222 ); 223 224 return file; 225 } case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: { 226 struct GNUNET_CHAT_File *file = info->value.download.cctx; 227 228 file_update_download( 229 file, 230 info->value.download.size, 231 info->value.download.size 232 ); 233 234 file->download = NULL; 235 break; 236 } case GNUNET_FS_STATUS_DOWNLOAD_ERROR: { 237 break; 238 } case GNUNET_FS_STATUS_UNINDEX_START: { 239 struct GNUNET_CHAT_File *file = info->value.unindex.cctx; 240 241 file_update_unindex( 242 file, 243 0, 244 info->value.unindex.size 245 ); 246 247 return file; 248 } case GNUNET_FS_STATUS_UNINDEX_PROGRESS: { 249 struct GNUNET_CHAT_File *file = info->value.unindex.cctx; 250 251 file_update_unindex( 252 file, 253 info->value.unindex.completed, 254 info->value.unindex.size 255 ); 256 257 return file; 258 } case GNUNET_FS_STATUS_UNINDEX_COMPLETED: { 259 struct GNUNET_CHAT_File *file = info->value.unindex.cctx; 260 261 file_update_unindex( 262 file, 263 info->value.unindex.size, 264 info->value.unindex.size 265 ); 266 267 file->unindex = NULL; 268 char *filename = handle_create_file_path( 269 chat, &(file->hash) 270 ); 271 272 if (!filename) 273 break; 274 275 if (GNUNET_YES == GNUNET_DISK_file_test_read(filename)) 276 remove(filename); 277 278 GNUNET_free(filename); 279 break; 280 } default: { 281 break; 282 } 283 } 284 285 return NULL; 286 } 287 288 static void 289 on_handle_refresh (void *cls) 290 { 291 GNUNET_assert(cls); 292 293 struct GNUNET_CHAT_Handle* handle = cls; 294 295 handle->refresh = NULL; 296 297 handle_send_internal_message( 298 handle, 299 NULL, 300 NULL, 301 GNUNET_CHAT_FLAG_REFRESH, 302 NULL, 303 GNUNET_YES 304 ); 305 } 306 307 void 308 on_handle_gnunet_identity (void *cls, 309 struct GNUNET_IDENTITY_Ego *ego, 310 void **ctx, 311 const char *name) 312 { 313 GNUNET_assert(cls); 314 315 if ((name) && (GNUNET_YES == util_is_lobby_name(name))) 316 return; 317 318 struct GNUNET_CHAT_Handle* handle = cls; 319 320 if ((!ctx) || (!ego)) 321 { 322 handle->refreshing = GNUNET_YES; 323 goto send_refresh; 324 } 325 326 struct GNUNET_CHAT_InternalAccounts *accounts = handle->accounts_head; 327 328 while (accounts) 329 { 330 if (!(accounts->account)) 331 goto skip_account; 332 333 if (ego != accounts->account->ego) 334 goto check_matching_name; 335 336 if ((name) && ((!(accounts->account->name)) || 337 (0 != strcmp(accounts->account->name, name)))) 338 { 339 const char *old_name = account_get_name(accounts->account); 340 char *name_buffer = old_name? GNUNET_strdup(old_name) : NULL; 341 342 util_set_name_field(name, &(accounts->account->name)); 343 344 handle_send_internal_message( 345 handle, 346 accounts->account, 347 NULL, 348 GNUNET_CHAT_FLAG_UPDATE_ACCOUNT, 349 name_buffer, 350 GNUNET_YES 351 ); 352 353 if (name_buffer) 354 GNUNET_free(name_buffer); 355 } 356 else if ((!name) && (!(accounts->op))) 357 { 358 if (handle->current == accounts->account) 359 handle_disconnect(handle); 360 361 account_destroy(accounts->account); 362 internal_accounts_destroy(accounts); 363 } 364 else if (!name) 365 account_update_ego(accounts->account, handle, NULL); 366 367 goto send_refresh; 368 369 check_matching_name: 370 if ((name) && (accounts->account->name) && (ego) && 371 (0 == strcmp(accounts->account->name, name))) 372 { 373 account_update_ego(accounts->account, handle, ego); 374 goto send_refresh; 375 } 376 377 skip_account: 378 accounts = accounts->next; 379 } 380 381 if (!name) 382 return; 383 384 accounts = internal_accounts_create( 385 handle, 386 account_create_from_ego(handle, ego, name) 387 ); 388 389 send_refresh: 390 if ((GNUNET_YES != handle->refreshing) || 391 (handle->refresh)) 392 return; 393 394 handle->refresh = GNUNET_SCHEDULER_add_with_priority( 395 GNUNET_SCHEDULER_PRIORITY_IDLE, 396 on_handle_refresh, 397 handle 398 ); 399 } 400 401 void 402 cb_account_creation (void *cls, 403 const struct GNUNET_CRYPTO_BlindablePrivateKey *key, 404 enum GNUNET_ErrorCode ec) 405 { 406 GNUNET_assert(cls); 407 408 struct GNUNET_CHAT_InternalAccounts *accounts = ( 409 (struct GNUNET_CHAT_InternalAccounts*) cls 410 ); 411 412 accounts->op = NULL; 413 414 if ((!(accounts->account)) && (accounts->identifier)) 415 accounts->account = account_create( 416 accounts->handle, accounts->identifier 417 ); 418 419 internal_accounts_stop_method(accounts); 420 421 if (GNUNET_EC_NONE == ec) 422 return; 423 424 handle_send_internal_message( 425 accounts->handle, 426 accounts->account, 427 NULL, 428 GNUNET_CHAT_FLAG_WARNING, 429 GNUNET_ErrorCode_get_hint(ec), 430 GNUNET_YES 431 ); 432 } 433 434 void 435 cb_account_deletion (void *cls, 436 enum GNUNET_ErrorCode ec) 437 { 438 GNUNET_assert(cls); 439 440 struct GNUNET_CHAT_InternalAccounts *accounts = ( 441 (struct GNUNET_CHAT_InternalAccounts*) cls 442 ); 443 444 accounts->op = NULL; 445 446 internal_accounts_stop_method(accounts); 447 448 if (accounts->handle->current == accounts->account) 449 handle_disconnect(accounts->handle); 450 451 if (GNUNET_EC_NONE != ec) 452 handle_send_internal_message( 453 accounts->handle, 454 accounts->account, 455 NULL, 456 GNUNET_CHAT_FLAG_WARNING, 457 GNUNET_ErrorCode_get_hint(ec), 458 GNUNET_YES 459 ); 460 else 461 { 462 handle_send_internal_message( 463 accounts->handle, 464 accounts->account, 465 NULL, 466 GNUNET_CHAT_FLAG_DELETE_ACCOUNT, 467 NULL, 468 GNUNET_YES 469 ); 470 471 account_delete(accounts->account); 472 } 473 474 account_destroy(accounts->account); 475 internal_accounts_destroy(accounts); 476 } 477 478 void 479 cb_account_rename (void *cls, 480 enum GNUNET_ErrorCode ec) 481 { 482 GNUNET_assert(cls); 483 484 struct GNUNET_CHAT_InternalAccounts *accounts = ( 485 (struct GNUNET_CHAT_InternalAccounts*) cls 486 ); 487 488 accounts->op = NULL; 489 490 internal_accounts_stop_method(accounts); 491 492 if (GNUNET_EC_NONE == ec) 493 return; 494 495 handle_send_internal_message( 496 accounts->handle, 497 accounts->account, 498 NULL, 499 GNUNET_CHAT_FLAG_WARNING, 500 GNUNET_ErrorCode_get_hint(ec), 501 GNUNET_YES 502 ); 503 } 504 505 void 506 cb_lobby_deletion (void *cls, 507 enum GNUNET_ErrorCode ec) 508 { 509 GNUNET_assert(cls); 510 511 struct GNUNET_CHAT_InternalAccounts *accounts = ( 512 (struct GNUNET_CHAT_InternalAccounts*) cls 513 ); 514 515 accounts->op = NULL; 516 517 internal_accounts_stop_method(accounts); 518 519 if (GNUNET_EC_NONE != ec) 520 handle_send_internal_message( 521 accounts->handle, 522 accounts->account, 523 NULL, 524 GNUNET_CHAT_FLAG_WARNING, 525 GNUNET_ErrorCode_get_hint(ec), 526 GNUNET_YES 527 ); 528 529 internal_accounts_destroy(accounts); 530 } 531 532 static void 533 cb_account_update_completion (void *cls, 534 const struct GNUNET_CRYPTO_BlindablePrivateKey *key, 535 enum GNUNET_ErrorCode ec) 536 { 537 GNUNET_assert(cls); 538 539 struct GNUNET_CHAT_InternalAccounts *accounts = ( 540 (struct GNUNET_CHAT_InternalAccounts*) cls 541 ); 542 543 accounts->op = NULL; 544 545 cb_account_creation(cls, key, ec); 546 } 547 548 void 549 cb_account_update (void *cls, 550 enum GNUNET_ErrorCode ec) 551 { 552 GNUNET_assert(cls); 553 554 struct GNUNET_CHAT_InternalAccounts *accounts = ( 555 (struct GNUNET_CHAT_InternalAccounts*) cls 556 ); 557 558 if ((GNUNET_EC_NONE != ec) || (!(accounts->identifier))) 559 { 560 cb_account_deletion(cls, ec); 561 return; 562 } 563 564 accounts->op = GNUNET_IDENTITY_create( 565 accounts->handle->identity, 566 accounts->identifier, 567 NULL, 568 GNUNET_PUBLIC_KEY_TYPE_ECDSA, 569 cb_account_update_completion, 570 accounts 571 ); 572 } 573 574 int 575 intern_provide_contact_for_member(struct GNUNET_CHAT_Handle *handle, 576 const struct GNUNET_MESSENGER_Contact *member, 577 struct GNUNET_CHAT_Context *context) 578 { 579 GNUNET_assert((handle) && (handle->contacts)); 580 581 if (!member) 582 return GNUNET_SYSERR; 583 584 struct GNUNET_ShortHashCode shorthash; 585 util_shorthash_from_member(member, &shorthash); 586 587 struct GNUNET_CHAT_Contact *contact = GNUNET_CONTAINER_multishortmap_get( 588 handle->contacts, &shorthash 589 ); 590 591 if (contact) 592 { 593 if ((context) && (NULL == contact->context)) 594 { 595 contact->context = context; 596 context->contact = member; 597 } 598 599 return GNUNET_OK; 600 } 601 602 contact = contact_create_from_member( 603 handle, member 604 ); 605 606 if (context) 607 { 608 contact->context = context; 609 context->contact = member; 610 } 611 612 if (GNUNET_OK == GNUNET_CONTAINER_multishortmap_put( 613 handle->contacts, &shorthash, contact, 614 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 615 return GNUNET_OK; 616 617 if (context) 618 context->contact = NULL; 619 620 contact_destroy(contact); 621 return GNUNET_SYSERR; 622 } 623 624 struct GNUNET_CHAT_CheckHandleRoomMembers 625 { 626 const struct GNUNET_CRYPTO_BlindablePublicKey *ignore_key; 627 const struct GNUNET_MESSENGER_Contact *contact; 628 }; 629 630 int 631 check_handle_room_members (void* cls, 632 GNUNET_UNUSED struct GNUNET_MESSENGER_Room *room, 633 const struct GNUNET_MESSENGER_Contact *member) 634 { 635 struct GNUNET_CHAT_CheckHandleRoomMembers *check = cls; 636 637 GNUNET_assert((check) && (member)); 638 639 const struct GNUNET_CRYPTO_BlindablePublicKey *member_key = ( 640 GNUNET_MESSENGER_contact_get_key(member) 641 ); 642 643 if ((member_key) && (check->ignore_key) && 644 (0 == GNUNET_memcmp(member_key, check->ignore_key))) 645 return GNUNET_YES; 646 647 if (check->contact) 648 { 649 check->contact = NULL; 650 return GNUNET_NO; 651 } 652 653 check->contact = member; 654 return GNUNET_YES; 655 } 656 657 int 658 scan_handle_room_members (void* cls, 659 GNUNET_UNUSED struct GNUNET_MESSENGER_Room *room, 660 const struct GNUNET_MESSENGER_Contact *member) 661 { 662 struct GNUNET_CHAT_Handle *handle = cls; 663 664 GNUNET_assert((handle) && (member)); 665 666 if (GNUNET_OK == intern_provide_contact_for_member(handle, member, NULL)) 667 return GNUNET_YES; 668 else 669 return GNUNET_NO; 670 } 671 672 void 673 on_monitor_namestore_record(void *cls, 674 GNUNET_UNUSED const 675 struct GNUNET_CRYPTO_BlindablePrivateKey *zone, 676 const char *label, 677 unsigned int count, 678 const struct GNUNET_GNSRECORD_Data *data) 679 { 680 struct GNUNET_CHAT_Handle *handle = cls; 681 682 GNUNET_assert((handle) && (label) && (data)); 683 684 if (handle->destruction) 685 { 686 GNUNET_NAMESTORE_zone_monitor_stop(handle->monitor); 687 handle->monitor = NULL; 688 return; 689 } 690 691 handle_process_records(handle, label, count, data); 692 693 if (handle->monitor) 694 GNUNET_NAMESTORE_zone_monitor_next(handle->monitor, 1); 695 } 696 697 void 698 on_pils_identity_changed(void *cls, 699 const struct GNUNET_HELLO_Parser *parser, 700 GNUNET_UNUSED const struct GNUNET_HashCode *hash) 701 { 702 struct GNUNET_CHAT_Handle *handle = cls; 703 704 GNUNET_assert((handle) && (parser)); 705 706 const struct GNUNET_PeerIdentity *id = GNUNET_HELLO_parser_get_id(parser); 707 708 if (!id) 709 return; 710 711 if (!handle->pid) 712 handle->pid = GNUNET_new(struct GNUNET_PeerIdentity); 713 714 GNUNET_memcpy(handle->pid, id, sizeof(struct GNUNET_PeerIdentity)); 715 } 716 717 void 718 on_handle_message_callback(void *cls); 719 720 static enum GNUNET_GenericReturnValue 721 it_context_iterate_dependencies(void *cls, 722 const struct GNUNET_HashCode *key, 723 void *value) 724 { 725 struct GNUNET_CHAT_Message *message = (struct GNUNET_CHAT_Message*) value; 726 727 if ((message) && (!message->task)) 728 message->task = GNUNET_SCHEDULER_add_now( 729 on_handle_message_callback, message 730 ); 731 732 return GNUNET_YES; 733 } 734 735 void 736 on_handle_internal_message_callback(void *cls) 737 { 738 struct GNUNET_CHAT_InternalMessages *internal = cls; 739 740 GNUNET_assert( 741 (internal) && 742 (internal->chat) && 743 (internal->msg) && 744 (internal->task) 745 ); 746 747 internal->task = NULL; 748 749 struct GNUNET_CHAT_Handle *handle = internal->chat; 750 struct GNUNET_CHAT_Context *context = internal->msg->context; 751 752 if (!(handle->msg_cb)) 753 return; 754 755 handle->msg_cb(handle->msg_cls, context, internal->msg); 756 } 757 758 static enum GNUNET_GenericReturnValue 759 it_invitation_update (GNUNET_UNUSED void *cls, 760 GNUNET_UNUSED const struct GNUNET_HashCode *key, 761 void *value) 762 { 763 struct GNUNET_CHAT_Invitation *invitation = (struct GNUNET_CHAT_Invitation*) value; 764 765 if (invitation) 766 invitation_update(invitation); 767 768 return GNUNET_YES; 769 } 770 771 void 772 on_handle_message_callback(void *cls) 773 { 774 struct GNUNET_CHAT_Message *message = (struct GNUNET_CHAT_Message*) cls; 775 776 GNUNET_assert( 777 (message) && 778 (message->context) && 779 (message->context->handle) 780 ); 781 782 message->task = NULL; 783 784 if (GNUNET_YES != message_has_msg(message)) 785 return; 786 787 const struct GNUNET_TIME_Absolute timestamp = GNUNET_TIME_absolute_ntoh( 788 message->msg->header.timestamp 789 ); 790 791 struct GNUNET_TIME_Relative task_delay; 792 switch (message->msg->header.kind) 793 { 794 case GNUNET_MESSENGER_KIND_DELETION: 795 { 796 const struct GNUNET_TIME_Relative delay = GNUNET_TIME_relative_ntoh( 797 message->msg->body.deletion.delay 798 ); 799 800 task_delay = GNUNET_TIME_absolute_get_difference( 801 GNUNET_TIME_absolute_get(), 802 GNUNET_TIME_absolute_add(timestamp, delay) 803 ); 804 805 break; 806 } 807 default: 808 { 809 task_delay = GNUNET_TIME_relative_get_zero_(); 810 break; 811 } 812 } 813 814 if (! GNUNET_TIME_relative_is_zero(task_delay)) 815 { 816 message->task = GNUNET_SCHEDULER_add_delayed( 817 task_delay, 818 on_handle_message_callback, 819 message 820 ); 821 822 return; 823 } 824 825 struct GNUNET_CHAT_Context *context = message->context; 826 struct GNUNET_CHAT_Handle *handle = context->handle; 827 const struct GNUNET_MESSENGER_Contact *sender; 828 829 if (GNUNET_MESSENGER_FLAG_DELETE & message->flags) 830 goto skip_msg_handing; 831 832 switch (message->msg->header.kind) 833 { 834 case GNUNET_MESSENGER_KIND_INVITE: 835 { 836 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(context->invites, 837 &(message->hash))) 838 break; 839 840 struct GNUNET_CHAT_Invitation *invitation = invitation_create_from_message( 841 context, &(message->hash), &(message->msg->body.invite) 842 ); 843 844 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 845 context->invites, &(message->hash), invitation, 846 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 847 invitation_destroy(invitation); 848 else 849 GNUNET_CONTAINER_multihashmap_put( 850 handle->invitations, &(invitation->key.hash), invitation, 851 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); 852 break; 853 } 854 case GNUNET_MESSENGER_KIND_FILE: 855 { 856 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(context->files, 857 &(message->hash))) 858 break; 859 860 GNUNET_CONTAINER_multihashmap_put( 861 context->files, &(message->hash), NULL, 862 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST 863 ); 864 865 struct GNUNET_CHAT_File *file = GNUNET_CONTAINER_multihashmap_get( 866 context->handle->files, &(message->msg->body.file.hash) 867 ); 868 869 if (file) 870 break; 871 872 file = file_create_from_message( 873 context->handle, &(message->msg->body.file) 874 ); 875 876 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 877 context->handle->files, &(file->hash), file, 878 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 879 file_destroy(file); 880 break; 881 } 882 case GNUNET_MESSENGER_KIND_TAG: 883 { 884 struct GNUNET_CHAT_InternalTagging *tagging = GNUNET_CONTAINER_multihashmap_get( 885 context->taggings, &(message->msg->body.tag.hash)); 886 887 if (!tagging) 888 { 889 tagging = internal_tagging_create(); 890 891 if (!tagging) 892 break; 893 894 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 895 context->taggings, &(message->msg->body.tag.hash), tagging, 896 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 897 { 898 internal_tagging_destroy(tagging); 899 break; 900 } 901 } 902 903 internal_tagging_add(tagging, message); 904 break; 905 } 906 default: 907 break; 908 } 909 910 skip_msg_handing: 911 sender = GNUNET_MESSENGER_get_sender(context->room, &(message->hash)); 912 913 if (!sender) 914 goto clear_dependencies; 915 916 struct GNUNET_ShortHashCode shorthash; 917 util_shorthash_from_member(sender, &shorthash); 918 919 struct GNUNET_CHAT_Contact *contact = GNUNET_CONTAINER_multishortmap_get( 920 handle->contacts, &shorthash 921 ); 922 923 if (!contact) 924 goto clear_dependencies; 925 926 if (GNUNET_MESSENGER_FLAG_DELETE & message->flags) 927 goto skip_sender_handing; 928 929 switch (message->msg->header.kind) 930 { 931 case GNUNET_MESSENGER_KIND_JOIN: 932 { 933 contact_update_join(contact, context, 934 &(message->hash), message->flags); 935 936 GNUNET_CONTAINER_multihashmap_get_multiple( 937 handle->invitations, 938 GNUNET_MESSENGER_room_get_key(context->room), 939 it_invitation_update, handle); 940 941 if ((GNUNET_MESSENGER_FLAG_SENT & message->flags) && 942 (GNUNET_MESSENGER_FLAG_RECENT & message->flags)) 943 handle_send_room_name(handle, context->room); 944 945 break; 946 } 947 case GNUNET_MESSENGER_KIND_LEAVE: 948 { 949 GNUNET_CONTAINER_multihashmap_get_multiple( 950 handle->invitations, 951 GNUNET_MESSENGER_room_get_key(context->room), 952 it_invitation_update, handle); 953 954 break; 955 } 956 case GNUNET_MESSENGER_KIND_KEY: 957 { 958 contact_update_key(contact); 959 break; 960 } 961 case GNUNET_MESSENGER_KIND_TICKET: 962 { 963 struct GNUNET_CHAT_InternalTickets *tickets = contact->tickets_head; 964 while (tickets) 965 { 966 if (0 == strncmp(tickets->ticket->ticket.gns_name, 967 message->msg->body.ticket.identifier, 968 sizeof(tickets->ticket->ticket.gns_name))) 969 break; 970 971 tickets = tickets->next; 972 } 973 974 if (tickets) 975 break; 976 977 tickets = GNUNET_new( 978 struct GNUNET_CHAT_InternalTickets 979 ); 980 981 if (!tickets) 982 break; 983 984 tickets->ticket = ticket_create_from_message( 985 handle, contact, &(message->msg->body.ticket) 986 ); 987 988 if (!tickets->ticket) 989 { 990 GNUNET_free(tickets); 991 break; 992 } 993 994 GNUNET_CONTAINER_DLL_insert_tail( 995 contact->tickets_head, 996 contact->tickets_tail, 997 tickets 998 ); 999 break; 1000 } 1001 case GNUNET_MESSENGER_KIND_SUBSCRIBTION: 1002 { 1003 const struct GNUNET_ShortHashCode *sid = &(message->msg->body.subscription.discourse); 1004 struct GNUNET_CHAT_Discourse *discourse = GNUNET_CONTAINER_multishortmap_get( 1005 context->discourses, sid 1006 ); 1007 1008 if (! discourse) 1009 { 1010 struct GNUNET_CHAT_DiscourseId id; 1011 util_discourse_id_from_shorthash(sid, &id); 1012 1013 discourse = discourse_create(context, &id); 1014 1015 if (GNUNET_OK != GNUNET_CONTAINER_multishortmap_put(context->discourses, 1016 sid, discourse, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 1017 { 1018 discourse_destroy(discourse); 1019 break; 1020 } 1021 } 1022 1023 enum GNUNET_GenericReturnValue subscription_update = GNUNET_NO; 1024 1025 if (GNUNET_MESSENGER_FLAG_SUBSCRIPTION_UNSUBSCRIBE & message->msg->body.subscription.flags) 1026 discourse_unsubscribe( 1027 discourse, 1028 contact, 1029 GNUNET_TIME_absolute_ntoh(message->msg->header.timestamp), 1030 GNUNET_TIME_relative_ntoh(message->msg->body.subscription.time) 1031 ); 1032 else 1033 subscription_update = discourse_subscribe( 1034 discourse, 1035 contact, 1036 GNUNET_TIME_absolute_ntoh(message->msg->header.timestamp), 1037 GNUNET_TIME_relative_ntoh(message->msg->body.subscription.time) 1038 ); 1039 1040 if (GNUNET_YES == subscription_update) 1041 message->flags |= GNUNET_MESSENGER_FLAG_UPDATE; 1042 1043 break; 1044 } 1045 default: 1046 break; 1047 } 1048 1049 skip_sender_handing: 1050 if (!(handle->msg_cb)) 1051 goto clear_dependencies; 1052 1053 handle->msg_cb(handle->msg_cls, context, message); 1054 1055 clear_dependencies: 1056 GNUNET_CONTAINER_multihashmap_get_multiple(context->dependencies, 1057 &(message->hash), 1058 it_context_iterate_dependencies, 1059 NULL); 1060 GNUNET_CONTAINER_multihashmap_remove_all(context->dependencies, 1061 &(message->hash)); 1062 } 1063 1064 void 1065 on_handle_message (void *cls, 1066 struct GNUNET_MESSENGER_Room *room, 1067 const struct GNUNET_MESSENGER_Contact *sender, 1068 const struct GNUNET_MESSENGER_Contact *recipient, 1069 const struct GNUNET_MESSENGER_Message *msg, 1070 const struct GNUNET_HashCode *hash, 1071 enum GNUNET_MESSENGER_MessageFlags flags) 1072 { 1073 struct GNUNET_CHAT_Handle *handle = cls; 1074 1075 GNUNET_assert( 1076 (handle) && 1077 (room) && 1078 (msg) && 1079 (hash) 1080 ); 1081 1082 if ((handle->destruction) || 1083 (GNUNET_OK != handle_request_context_by_room(handle, room))) 1084 return; 1085 1086 struct GNUNET_CHAT_Context *context = GNUNET_CONTAINER_multihashmap_get( 1087 handle->contexts, GNUNET_MESSENGER_room_get_key(room) 1088 ); 1089 1090 if (GNUNET_MESSENGER_KIND_MERGE == msg->header.kind) 1091 context_request_message(context, &(msg->body.merge.previous)); 1092 1093 context_request_message(context, &(msg->header.previous)); 1094 1095 if ((GNUNET_CHAT_KIND_UNKNOWN == util_message_kind_from_kind(msg->header.kind)) || 1096 (GNUNET_OK != intern_provide_contact_for_member(handle, sender, NULL))) 1097 return; 1098 1099 const struct GNUNET_TIME_Absolute timestamp = GNUNET_TIME_absolute_ntoh( 1100 msg->header.timestamp 1101 ); 1102 1103 struct GNUNET_ShortHashCode shorthash; 1104 util_shorthash_from_member(sender, &shorthash); 1105 1106 struct GNUNET_CHAT_Contact *contact = GNUNET_CONTAINER_multishortmap_get( 1107 handle->contacts, &shorthash 1108 ); 1109 1110 if (flags & GNUNET_MESSENGER_FLAG_SENT) 1111 contact->owned = GNUNET_YES; 1112 1113 struct GNUNET_TIME_Absolute *time = GNUNET_CONTAINER_multishortmap_get( 1114 context->timestamps, &shorthash 1115 ); 1116 1117 if (!time) 1118 { 1119 time = GNUNET_new(struct GNUNET_TIME_Absolute); 1120 *time = timestamp; 1121 1122 if (GNUNET_OK != GNUNET_CONTAINER_multishortmap_put( 1123 context->timestamps, &shorthash, time, 1124 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 1125 GNUNET_free(time); 1126 } 1127 else 1128 { 1129 const struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference( 1130 timestamp, *time 1131 ); 1132 1133 if (GNUNET_TIME_relative_is_zero(delta)) 1134 *time = timestamp; 1135 } 1136 1137 const struct GNUNET_HashCode *dependency = NULL; 1138 1139 struct GNUNET_CHAT_Message *message = GNUNET_CONTAINER_multihashmap_get( 1140 context->messages, hash 1141 ); 1142 1143 if (message) 1144 { 1145 if (message->flags & GNUNET_MESSENGER_FLAG_DELETE) 1146 return; 1147 1148 message_update_msg (message, flags, msg); 1149 1150 if (0 == (message->flags & GNUNET_MESSENGER_FLAG_UPDATE)) 1151 return; 1152 1153 goto handle_callback; 1154 } 1155 1156 message = message_create_from_msg(context, hash, flags, msg); 1157 1158 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 1159 context->messages, hash, message, 1160 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 1161 { 1162 message_destroy(message); 1163 return; 1164 } 1165 1166 handle_callback: 1167 switch (msg->header.kind) 1168 { 1169 case GNUNET_MESSENGER_KIND_DELETION: 1170 { 1171 dependency = &(msg->body.deletion.hash); 1172 break; 1173 } 1174 case GNUNET_MESSENGER_KIND_TRANSCRIPT: 1175 { 1176 dependency = &(msg->body.transcript.hash); 1177 break; 1178 } 1179 case GNUNET_MESSENGER_KIND_TAG: 1180 { 1181 dependency = &(msg->body.tag.hash); 1182 break; 1183 } 1184 default: 1185 break; 1186 } 1187 1188 if ((dependency) && 1189 (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains(context->messages, dependency))) 1190 { 1191 GNUNET_CONTAINER_multihashmap_put( 1192 context->dependencies, 1193 dependency, 1194 message, 1195 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE 1196 ); 1197 1198 GNUNET_MESSENGER_get_message(room, dependency); 1199 return; 1200 } 1201 1202 on_handle_message_callback(message); 1203 } 1204 1205 int 1206 it_destroy_handle_groups (GNUNET_UNUSED void *cls, 1207 GNUNET_UNUSED const struct GNUNET_HashCode *key, 1208 void *value) 1209 { 1210 GNUNET_assert(value); 1211 1212 struct GNUNET_CHAT_Group *group = value; 1213 group_destroy(group); 1214 return GNUNET_YES; 1215 } 1216 1217 int 1218 it_destroy_handle_contacts (GNUNET_UNUSED void *cls, 1219 GNUNET_UNUSED const struct GNUNET_ShortHashCode *key, 1220 void *value) 1221 { 1222 GNUNET_assert(value); 1223 1224 struct GNUNET_CHAT_Contact *contact = value; 1225 contact_destroy(contact); 1226 return GNUNET_YES; 1227 } 1228 1229 int 1230 it_destroy_handle_contexts (GNUNET_UNUSED void *cls, 1231 GNUNET_UNUSED const struct GNUNET_HashCode *key, 1232 void *value) 1233 { 1234 GNUNET_assert(value); 1235 1236 struct GNUNET_CHAT_Context *context = value; 1237 context_destroy(context); 1238 return GNUNET_YES; 1239 } 1240 1241 int 1242 it_destroy_handle_files (GNUNET_UNUSED void *cls, 1243 GNUNET_UNUSED const struct GNUNET_HashCode *key, 1244 void *value) 1245 { 1246 GNUNET_assert(value); 1247 1248 struct GNUNET_CHAT_File *file = value; 1249 file_destroy(file); 1250 return GNUNET_YES; 1251 }