gnunet_chat_handle_intern.c (31212B)
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 (!file) 877 break; 878 879 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 880 context->handle->files, &(file->hash), file, 881 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 882 file_destroy(file); 883 break; 884 } 885 case GNUNET_MESSENGER_KIND_TAG: 886 { 887 struct GNUNET_CHAT_InternalTagging *tagging = GNUNET_CONTAINER_multihashmap_get( 888 context->taggings, &(message->msg->body.tag.hash)); 889 890 if (!tagging) 891 { 892 tagging = internal_tagging_create(); 893 894 if (!tagging) 895 break; 896 897 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 898 context->taggings, &(message->msg->body.tag.hash), tagging, 899 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 900 { 901 internal_tagging_destroy(tagging); 902 break; 903 } 904 } 905 906 internal_tagging_add(tagging, message); 907 break; 908 } 909 default: 910 break; 911 } 912 913 skip_msg_handing: 914 sender = GNUNET_MESSENGER_get_sender(context->room, &(message->hash)); 915 916 if (!sender) 917 goto clear_dependencies; 918 919 struct GNUNET_ShortHashCode shorthash; 920 util_shorthash_from_member(sender, &shorthash); 921 922 struct GNUNET_CHAT_Contact *contact = GNUNET_CONTAINER_multishortmap_get( 923 handle->contacts, &shorthash 924 ); 925 926 if (!contact) 927 goto clear_dependencies; 928 929 if (GNUNET_MESSENGER_FLAG_DELETE & message->flags) 930 goto skip_sender_handing; 931 932 switch (message->msg->header.kind) 933 { 934 case GNUNET_MESSENGER_KIND_JOIN: 935 { 936 contact_update_join(contact, context, 937 &(message->hash), message->flags); 938 939 GNUNET_CONTAINER_multihashmap_get_multiple( 940 handle->invitations, 941 GNUNET_MESSENGER_room_get_key(context->room), 942 it_invitation_update, handle); 943 944 if ((GNUNET_MESSENGER_FLAG_SENT & message->flags) && 945 (GNUNET_MESSENGER_FLAG_RECENT & message->flags)) 946 handle_send_room_name(handle, context->room); 947 948 break; 949 } 950 case GNUNET_MESSENGER_KIND_LEAVE: 951 { 952 GNUNET_CONTAINER_multihashmap_get_multiple( 953 handle->invitations, 954 GNUNET_MESSENGER_room_get_key(context->room), 955 it_invitation_update, handle); 956 957 break; 958 } 959 case GNUNET_MESSENGER_KIND_KEY: 960 { 961 contact_update_key(contact); 962 break; 963 } 964 case GNUNET_MESSENGER_KIND_TICKET: 965 { 966 struct GNUNET_CHAT_InternalTickets *tickets = contact->tickets_head; 967 while (tickets) 968 { 969 if (0 == strncmp(tickets->ticket->ticket.gns_name, 970 message->msg->body.ticket.identifier, 971 sizeof(tickets->ticket->ticket.gns_name))) 972 break; 973 974 tickets = tickets->next; 975 } 976 977 if (tickets) 978 break; 979 980 tickets = GNUNET_new( 981 struct GNUNET_CHAT_InternalTickets 982 ); 983 984 if (!tickets) 985 break; 986 987 tickets->ticket = ticket_create_from_message( 988 handle, contact, &(message->msg->body.ticket) 989 ); 990 991 if (!tickets->ticket) 992 { 993 GNUNET_free(tickets); 994 break; 995 } 996 997 GNUNET_CONTAINER_DLL_insert_tail( 998 contact->tickets_head, 999 contact->tickets_tail, 1000 tickets 1001 ); 1002 break; 1003 } 1004 case GNUNET_MESSENGER_KIND_SUBSCRIBTION: 1005 { 1006 const struct GNUNET_ShortHashCode *sid = &(message->msg->body.subscription.discourse); 1007 struct GNUNET_CHAT_Discourse *discourse = GNUNET_CONTAINER_multishortmap_get( 1008 context->discourses, sid 1009 ); 1010 1011 if (! discourse) 1012 { 1013 struct GNUNET_CHAT_DiscourseId id; 1014 util_discourse_id_from_shorthash(sid, &id); 1015 1016 discourse = discourse_create(context, &id); 1017 1018 if (GNUNET_OK != GNUNET_CONTAINER_multishortmap_put(context->discourses, 1019 sid, discourse, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 1020 { 1021 discourse_destroy(discourse); 1022 break; 1023 } 1024 } 1025 1026 enum GNUNET_GenericReturnValue subscription_update = GNUNET_NO; 1027 1028 if (GNUNET_MESSENGER_FLAG_SUBSCRIPTION_UNSUBSCRIBE & message->msg->body.subscription.flags) 1029 discourse_unsubscribe( 1030 discourse, 1031 contact, 1032 GNUNET_TIME_absolute_ntoh(message->msg->header.timestamp), 1033 GNUNET_TIME_relative_ntoh(message->msg->body.subscription.time) 1034 ); 1035 else 1036 subscription_update = discourse_subscribe( 1037 discourse, 1038 contact, 1039 GNUNET_TIME_absolute_ntoh(message->msg->header.timestamp), 1040 GNUNET_TIME_relative_ntoh(message->msg->body.subscription.time) 1041 ); 1042 1043 if (GNUNET_YES == subscription_update) 1044 message->flags |= GNUNET_MESSENGER_FLAG_UPDATE; 1045 1046 break; 1047 } 1048 default: 1049 break; 1050 } 1051 1052 skip_sender_handing: 1053 if (!(handle->msg_cb)) 1054 goto clear_dependencies; 1055 1056 handle->msg_cb(handle->msg_cls, context, message); 1057 1058 clear_dependencies: 1059 GNUNET_CONTAINER_multihashmap_get_multiple(context->dependencies, 1060 &(message->hash), 1061 it_context_iterate_dependencies, 1062 NULL); 1063 GNUNET_CONTAINER_multihashmap_remove_all(context->dependencies, 1064 &(message->hash)); 1065 } 1066 1067 void 1068 on_handle_message (void *cls, 1069 struct GNUNET_MESSENGER_Room *room, 1070 const struct GNUNET_MESSENGER_Contact *sender, 1071 const struct GNUNET_MESSENGER_Contact *recipient, 1072 const struct GNUNET_MESSENGER_Message *msg, 1073 const struct GNUNET_HashCode *hash, 1074 enum GNUNET_MESSENGER_MessageFlags flags) 1075 { 1076 struct GNUNET_CHAT_Handle *handle = cls; 1077 1078 GNUNET_assert( 1079 (handle) && 1080 (room) && 1081 (msg) && 1082 (hash) 1083 ); 1084 1085 if ((handle->destruction) || 1086 (GNUNET_OK != handle_request_context_by_room(handle, room))) 1087 return; 1088 1089 struct GNUNET_CHAT_Context *context = GNUNET_CONTAINER_multihashmap_get( 1090 handle->contexts, GNUNET_MESSENGER_room_get_key(room) 1091 ); 1092 1093 if (GNUNET_MESSENGER_KIND_MERGE == msg->header.kind) 1094 context_request_message(context, &(msg->body.merge.previous)); 1095 1096 context_request_message(context, &(msg->header.previous)); 1097 1098 if ((GNUNET_CHAT_KIND_UNKNOWN == util_message_kind_from_kind(msg->header.kind)) || 1099 (GNUNET_OK != intern_provide_contact_for_member(handle, sender, NULL))) 1100 return; 1101 1102 const struct GNUNET_TIME_Absolute timestamp = GNUNET_TIME_absolute_ntoh( 1103 msg->header.timestamp 1104 ); 1105 1106 struct GNUNET_ShortHashCode shorthash; 1107 util_shorthash_from_member(sender, &shorthash); 1108 1109 struct GNUNET_CHAT_Contact *contact = GNUNET_CONTAINER_multishortmap_get( 1110 handle->contacts, &shorthash 1111 ); 1112 1113 if (flags & GNUNET_MESSENGER_FLAG_SENT) 1114 contact->owned = GNUNET_YES; 1115 1116 struct GNUNET_TIME_Absolute *time = GNUNET_CONTAINER_multishortmap_get( 1117 context->timestamps, &shorthash 1118 ); 1119 1120 if (!time) 1121 { 1122 time = GNUNET_new(struct GNUNET_TIME_Absolute); 1123 *time = timestamp; 1124 1125 if (GNUNET_OK != GNUNET_CONTAINER_multishortmap_put( 1126 context->timestamps, &shorthash, time, 1127 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 1128 GNUNET_free(time); 1129 } 1130 else 1131 { 1132 const struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference( 1133 timestamp, *time 1134 ); 1135 1136 if (GNUNET_TIME_relative_is_zero(delta)) 1137 *time = timestamp; 1138 } 1139 1140 const struct GNUNET_HashCode *dependency = NULL; 1141 1142 struct GNUNET_CHAT_Message *message = GNUNET_CONTAINER_multihashmap_get( 1143 context->messages, hash 1144 ); 1145 1146 if (message) 1147 { 1148 if (message->flags & GNUNET_MESSENGER_FLAG_DELETE) 1149 return; 1150 1151 message_update_msg (message, flags, msg); 1152 1153 if (0 == (message->flags & GNUNET_MESSENGER_FLAG_UPDATE)) 1154 return; 1155 1156 goto handle_callback; 1157 } 1158 1159 message = message_create_from_msg(context, hash, flags, msg); 1160 1161 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 1162 context->messages, hash, message, 1163 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 1164 { 1165 message_destroy(message); 1166 return; 1167 } 1168 1169 handle_callback: 1170 switch (msg->header.kind) 1171 { 1172 case GNUNET_MESSENGER_KIND_DELETION: 1173 { 1174 dependency = &(msg->body.deletion.hash); 1175 break; 1176 } 1177 case GNUNET_MESSENGER_KIND_TRANSCRIPT: 1178 { 1179 dependency = &(msg->body.transcript.hash); 1180 break; 1181 } 1182 case GNUNET_MESSENGER_KIND_TAG: 1183 { 1184 dependency = &(msg->body.tag.hash); 1185 break; 1186 } 1187 default: 1188 break; 1189 } 1190 1191 if ((dependency) && 1192 (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains(context->messages, dependency))) 1193 { 1194 GNUNET_CONTAINER_multihashmap_put( 1195 context->dependencies, 1196 dependency, 1197 message, 1198 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE 1199 ); 1200 1201 GNUNET_MESSENGER_get_message(room, dependency); 1202 return; 1203 } 1204 1205 on_handle_message_callback(message); 1206 } 1207 1208 int 1209 it_destroy_handle_groups (GNUNET_UNUSED void *cls, 1210 GNUNET_UNUSED const struct GNUNET_HashCode *key, 1211 void *value) 1212 { 1213 GNUNET_assert(value); 1214 1215 struct GNUNET_CHAT_Group *group = value; 1216 group_destroy(group); 1217 return GNUNET_YES; 1218 } 1219 1220 int 1221 it_destroy_handle_contacts (GNUNET_UNUSED void *cls, 1222 GNUNET_UNUSED const struct GNUNET_ShortHashCode *key, 1223 void *value) 1224 { 1225 GNUNET_assert(value); 1226 1227 struct GNUNET_CHAT_Contact *contact = value; 1228 contact_destroy(contact); 1229 return GNUNET_YES; 1230 } 1231 1232 int 1233 it_destroy_handle_contexts (GNUNET_UNUSED void *cls, 1234 GNUNET_UNUSED const struct GNUNET_HashCode *key, 1235 void *value) 1236 { 1237 GNUNET_assert(value); 1238 1239 struct GNUNET_CHAT_Context *context = value; 1240 context_destroy(context); 1241 return GNUNET_YES; 1242 } 1243 1244 int 1245 it_destroy_handle_files (GNUNET_UNUSED void *cls, 1246 GNUNET_UNUSED const struct GNUNET_HashCode *key, 1247 void *value) 1248 { 1249 GNUNET_assert(value); 1250 1251 struct GNUNET_CHAT_File *file = value; 1252 file_destroy(file); 1253 return GNUNET_YES; 1254 }