gnunet_chat_lib.c (74424B)
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.c 23 */ 24 25 #include "gnunet_chat_lib.h" 26 27 #include <gnunet/gnunet_common.h> 28 #include <gnunet/gnunet_fs_service.h> 29 #include <gnunet/gnunet_messenger_service.h> 30 #include <gnunet/gnunet_reclaim_lib.h> 31 #include <gnunet/gnunet_reclaim_service.h> 32 #include <gnunet/gnunet_scheduler_lib.h> 33 #include <gnunet/gnunet_time_lib.h> 34 #include <gnunet/gnunet_util_lib.h> 35 36 #include <libgen.h> 37 #include <stdint.h> 38 #include <string.h> 39 #include <strings.h> 40 #include <unistd.h> 41 42 #define _(String) ((const char*) String) 43 44 #include "gnunet_chat_contact.h" 45 #include "gnunet_chat_context.h" 46 #include "gnunet_chat_discourse.h" 47 #include "gnunet_chat_file.h" 48 #include "gnunet_chat_group.h" 49 #include "gnunet_chat_handle.h" 50 #include "gnunet_chat_invitation.h" 51 #include "gnunet_chat_lobby.h" 52 #include "gnunet_chat_message.h" 53 #include "gnunet_chat_ticket.h" 54 #include "gnunet_chat_util.h" 55 56 #include "internal/gnunet_chat_tagging.h" 57 58 #include "gnunet_chat_lib_intern.c" 59 60 #define GNUNET_CHAT_VERSION_ASSERT() {\ 61 GNUNET_assert(\ 62 (GNUNET_MESSENGER_VERSION == ((GNUNET_CHAT_VERSION >> 16L) & 0xFFFFFFFFL))\ 63 );\ 64 } 65 66 static const uint32_t block_anonymity_level = 1; 67 static const uint32_t block_content_priority = 100; 68 static const uint32_t block_replication_level = 1; 69 70 struct GNUNET_CHAT_Handle* 71 GNUNET_CHAT_start (const struct GNUNET_CONFIGURATION_Handle *cfg, 72 GNUNET_CHAT_ContextMessageCallback msg_cb, void *msg_cls) 73 { 74 GNUNET_CHAT_VERSION_ASSERT(); 75 76 if (!cfg) 77 return NULL; 78 79 return handle_create_from_config( 80 cfg, 81 msg_cb, 82 msg_cls 83 ); 84 } 85 86 87 void 88 GNUNET_CHAT_stop (struct GNUNET_CHAT_Handle *handle) 89 { 90 GNUNET_CHAT_VERSION_ASSERT(); 91 92 if ((!handle) || (handle->destruction)) 93 return; 94 95 handle->destruction = GNUNET_SCHEDULER_add_with_priority( 96 GNUNET_SCHEDULER_PRIORITY_URGENT, 97 task_handle_destruction, 98 handle 99 ); 100 } 101 102 103 enum GNUNET_GenericReturnValue 104 GNUNET_CHAT_account_create (struct GNUNET_CHAT_Handle *handle, 105 const char* name) 106 { 107 GNUNET_CHAT_VERSION_ASSERT(); 108 109 if ((!handle) || (handle->destruction) || (!name)) 110 return GNUNET_SYSERR; 111 112 char *low = util_get_lower(name); 113 114 enum GNUNET_GenericReturnValue result; 115 result = handle_create_account(handle, low); 116 117 GNUNET_free(low); 118 return result; 119 } 120 121 122 enum GNUNET_GenericReturnValue 123 GNUNET_CHAT_account_delete(struct GNUNET_CHAT_Handle *handle, 124 const char *name) 125 { 126 GNUNET_CHAT_VERSION_ASSERT(); 127 128 if ((!handle) || (handle->destruction) || (!name)) 129 return GNUNET_SYSERR; 130 131 const struct GNUNET_CHAT_Account *account; 132 account = handle_get_account_by_name(handle, name, GNUNET_NO); 133 134 if (!account) 135 return GNUNET_SYSERR; 136 137 return handle_delete_account(handle, account); 138 } 139 140 141 int 142 GNUNET_CHAT_iterate_accounts (struct GNUNET_CHAT_Handle *handle, 143 GNUNET_CHAT_AccountCallback callback, 144 void *cls) 145 { 146 GNUNET_CHAT_VERSION_ASSERT(); 147 148 if ((!handle) || (handle->destruction)) 149 return GNUNET_SYSERR; 150 151 int iterations = 0; 152 153 struct GNUNET_CHAT_InternalAccounts *accounts = handle->accounts_head; 154 while (accounts) 155 { 156 if ((!(accounts->account)) || (accounts->op)) 157 goto skip_account; 158 159 iterations++; 160 161 if ((callback) && (GNUNET_YES != callback(cls, handle, accounts->account))) 162 break; 163 164 skip_account: 165 accounts = accounts->next; 166 } 167 168 return iterations; 169 } 170 171 172 struct GNUNET_CHAT_Account* 173 GNUNET_CHAT_find_account (const struct GNUNET_CHAT_Handle *handle, 174 const char *name) 175 { 176 GNUNET_CHAT_VERSION_ASSERT(); 177 178 if ((!handle) || (handle->destruction)) 179 return NULL; 180 181 return handle_get_account_by_name(handle, name, GNUNET_YES); 182 } 183 184 185 void 186 GNUNET_CHAT_connect (struct GNUNET_CHAT_Handle *handle, 187 struct GNUNET_CHAT_Account *account, 188 const char *secret, 189 uint32_t secret_len) 190 { 191 GNUNET_CHAT_VERSION_ASSERT(); 192 193 if ((!handle) || (handle->destruction)) 194 return; 195 196 if (handle->connection) 197 GNUNET_SCHEDULER_cancel(handle->connection); 198 199 if (handle->current == account) 200 { 201 handle->next = NULL; 202 handle->connection = NULL; 203 return; 204 } 205 206 handle->next = account; 207 208 if (handle->next_secret) 209 { 210 GNUNET_CRYPTO_zero_keys( 211 handle->next_secret, 212 sizeof(*(handle->next_secret)) 213 ); 214 215 GNUNET_free(handle->next_secret); 216 } 217 218 if ((secret) && (secret_len > 0)) 219 { 220 handle->next_secret = GNUNET_new(struct GNUNET_HashCode); 221 222 if (handle->next_secret) 223 GNUNET_CRYPTO_hash(secret, secret_len, handle->next_secret); 224 } 225 else 226 handle->next_secret = NULL; 227 228 if (handle->current) 229 { 230 handle->connection = NULL; 231 GNUNET_CHAT_disconnect(handle); 232 return; 233 } 234 235 handle->connection = GNUNET_SCHEDULER_add_now( 236 task_handle_connection, 237 handle 238 ); 239 } 240 241 242 void 243 GNUNET_CHAT_disconnect (struct GNUNET_CHAT_Handle *handle) 244 { 245 GNUNET_CHAT_VERSION_ASSERT(); 246 247 if ((!handle) || (handle->destruction)) 248 return; 249 250 if (handle->connection) 251 GNUNET_SCHEDULER_cancel(handle->connection); 252 253 if (!(handle->current)) 254 { 255 handle->next = NULL; 256 handle->connection = NULL; 257 return; 258 } 259 260 handle->connection = GNUNET_SCHEDULER_add_now( 261 task_handle_disconnection, 262 handle 263 ); 264 } 265 266 267 struct GNUNET_CHAT_Account* 268 GNUNET_CHAT_get_connected (const struct GNUNET_CHAT_Handle *handle) 269 { 270 GNUNET_CHAT_VERSION_ASSERT(); 271 272 if ((!handle) || (handle->destruction)) 273 return NULL; 274 275 return handle->current; 276 } 277 278 279 enum GNUNET_GenericReturnValue 280 GNUNET_CHAT_update (struct GNUNET_CHAT_Handle *handle) 281 { 282 GNUNET_CHAT_VERSION_ASSERT(); 283 284 if ((!handle) || (handle->destruction)) 285 return GNUNET_SYSERR; 286 287 return handle_update(handle); 288 } 289 290 291 enum GNUNET_GenericReturnValue 292 GNUNET_CHAT_set_name (struct GNUNET_CHAT_Handle *handle, 293 const char *name) 294 { 295 GNUNET_CHAT_VERSION_ASSERT(); 296 297 if ((!handle) || (handle->destruction)) 298 return GNUNET_SYSERR; 299 300 if (!name) 301 return GNUNET_NO; 302 303 char *low = util_get_lower(name); 304 enum GNUNET_GenericReturnValue result; 305 306 if (handle->current) 307 result = handle_rename_account(handle, handle->current, low); 308 else 309 result = GNUNET_OK; 310 311 if (GNUNET_OK != result) 312 return result; 313 314 result = GNUNET_MESSENGER_set_name(handle->messenger, low); 315 316 GNUNET_free(low); 317 return result; 318 } 319 320 321 const char* 322 GNUNET_CHAT_get_name (const struct GNUNET_CHAT_Handle *handle) 323 { 324 GNUNET_CHAT_VERSION_ASSERT(); 325 326 if ((!handle) || (handle->destruction)) 327 return NULL; 328 329 return GNUNET_MESSENGER_get_name(handle->messenger); 330 } 331 332 333 const char* 334 GNUNET_CHAT_get_key (const struct GNUNET_CHAT_Handle *handle) 335 { 336 GNUNET_CHAT_VERSION_ASSERT(); 337 338 if ((!handle) || (handle->destruction)) 339 return NULL; 340 341 return handle->public_key; 342 } 343 344 345 void 346 GNUNET_CHAT_set_attribute (struct GNUNET_CHAT_Handle *handle, 347 const char *name, 348 const char *value) 349 { 350 GNUNET_CHAT_VERSION_ASSERT(); 351 352 if ((!handle) || (handle->destruction)) 353 return; 354 355 const struct GNUNET_CRYPTO_BlindablePrivateKey *key = handle_get_key( 356 handle 357 ); 358 359 if ((!key) || (!name)) 360 return; 361 362 struct GNUNET_TIME_Relative rel; 363 rel = GNUNET_TIME_relative_get_forever_(); 364 365 struct GNUNET_CHAT_AttributeProcess *attributes; 366 attributes = internal_attributes_create_store(handle, name, rel); 367 368 if (!attributes) 369 return; 370 371 if (value) 372 { 373 enum GNUNET_GenericReturnValue result; 374 result = GNUNET_RECLAIM_attribute_string_to_value( 375 GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING, 376 value, 377 &(attributes->data), 378 &(attributes->attribute->data_size) 379 ); 380 381 if (GNUNET_OK != result) 382 { 383 internal_attributes_destroy(attributes); 384 return; 385 } 386 387 attributes->attribute->type = GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING; 388 attributes->attribute->data = attributes->data; 389 } 390 391 attributes->iter = GNUNET_RECLAIM_get_attributes_start( 392 handle->reclaim, 393 key, 394 cb_task_error_iterate_attribute, 395 attributes, 396 cb_store_attribute, 397 attributes, 398 cb_task_finish_iterate_attribute, 399 attributes 400 ); 401 } 402 403 404 void 405 GNUNET_CHAT_delete_attribute (struct GNUNET_CHAT_Handle *handle, 406 const char *name) 407 { 408 GNUNET_CHAT_VERSION_ASSERT(); 409 410 if ((!handle) || (handle->destruction)) 411 return; 412 413 const struct GNUNET_CRYPTO_BlindablePrivateKey *key = handle_get_key( 414 handle 415 ); 416 417 if ((!key) || (!name)) 418 return; 419 420 struct GNUNET_CHAT_AttributeProcess *attributes; 421 attributes = internal_attributes_create(handle, name); 422 423 if (!attributes) 424 return; 425 426 attributes->iter = GNUNET_RECLAIM_get_attributes_start( 427 handle->reclaim, 428 key, 429 cb_task_error_iterate_attribute, 430 attributes, 431 cb_delete_attribute, 432 attributes, 433 cb_task_finish_iterate_attribute, 434 attributes 435 ); 436 } 437 438 439 void 440 GNUNET_CHAT_get_attributes (struct GNUNET_CHAT_Handle *handle, 441 GNUNET_CHAT_AttributeCallback callback, 442 void *cls) 443 { 444 GNUNET_CHAT_VERSION_ASSERT(); 445 446 if ((!handle) || (handle->destruction)) 447 return; 448 449 const struct GNUNET_CRYPTO_BlindablePrivateKey *key = handle_get_key( 450 handle 451 ); 452 453 if (!key) 454 return; 455 456 struct GNUNET_CHAT_AttributeProcess *attributes; 457 attributes = internal_attributes_create(handle, NULL); 458 459 if (!attributes) 460 return; 461 462 attributes->callback = callback; 463 attributes->closure = cls; 464 465 attributes->iter = GNUNET_RECLAIM_get_attributes_start( 466 handle->reclaim, 467 key, 468 cb_task_error_iterate_attribute, 469 attributes, 470 cb_iterate_attribute, 471 attributes, 472 cb_task_finish_iterate_attribute, 473 attributes 474 ); 475 } 476 477 478 void 479 GNUNET_CHAT_share_attribute_with (struct GNUNET_CHAT_Handle *handle, 480 struct GNUNET_CHAT_Contact *contact, 481 const char *name) 482 { 483 GNUNET_CHAT_VERSION_ASSERT(); 484 485 if ((!handle) || (handle->destruction) || (!contact)) 486 return; 487 488 const struct GNUNET_CRYPTO_BlindablePrivateKey *key = handle_get_key( 489 handle 490 ); 491 492 const struct GNUNET_CRYPTO_BlindablePublicKey *pubkey = contact_get_key( 493 contact 494 ); 495 496 if ((!key) || (!pubkey) || (!name)) 497 return; 498 499 struct GNUNET_CHAT_AttributeProcess *attributes; 500 attributes = internal_attributes_create_share(handle, contact, name); 501 502 if (!attributes) 503 return; 504 505 attributes->iter = GNUNET_RECLAIM_get_attributes_start( 506 handle->reclaim, 507 key, 508 cb_task_error_iterate_attribute, 509 attributes, 510 cb_share_attribute, 511 attributes, 512 cb_task_finish_iterate_attribute, 513 attributes 514 ); 515 } 516 517 518 void 519 GNUNET_CHAT_unshare_attribute_from (struct GNUNET_CHAT_Handle *handle, 520 struct GNUNET_CHAT_Contact *contact, 521 const char *name) 522 { 523 GNUNET_CHAT_VERSION_ASSERT(); 524 525 if ((!handle) || (handle->destruction) || (!contact)) 526 return; 527 528 const struct GNUNET_CRYPTO_BlindablePrivateKey *key = handle_get_key( 529 handle 530 ); 531 532 if ((!key) || (!name)) 533 return; 534 535 struct GNUNET_CHAT_TicketProcess *tickets; 536 tickets = internal_tickets_create(handle, contact, name); 537 538 if (!tickets) 539 return; 540 541 tickets->iter = GNUNET_RECLAIM_ticket_iteration_start( 542 handle->reclaim, 543 key, 544 cb_task_error_iterate_ticket, 545 tickets, 546 cb_iterate_ticket_check, 547 tickets, 548 cb_task_finish_iterate_ticket, 549 tickets 550 ); 551 } 552 553 554 void 555 GNUNET_CHAT_get_shared_attributes (struct GNUNET_CHAT_Handle *handle, 556 struct GNUNET_CHAT_Contact *contact, 557 GNUNET_CHAT_ContactAttributeCallback callback, 558 void *cls) 559 { 560 GNUNET_CHAT_VERSION_ASSERT(); 561 562 if ((!handle) || (handle->destruction) || (!contact)) 563 return; 564 565 const struct GNUNET_CRYPTO_BlindablePrivateKey *key = handle_get_key( 566 handle 567 ); 568 569 if (!key) 570 return; 571 572 struct GNUNET_CHAT_TicketProcess *tickets; 573 tickets = internal_tickets_create(handle, contact, NULL); 574 575 if (!tickets) 576 return; 577 578 tickets->callback = callback; 579 tickets->closure = cls; 580 581 tickets->iter = GNUNET_RECLAIM_ticket_iteration_start( 582 handle->reclaim, 583 key, 584 cb_task_error_iterate_ticket, 585 tickets, 586 cb_iterate_ticket, 587 tickets, 588 cb_task_finish_iterate_ticket, 589 tickets 590 ); 591 } 592 593 594 struct GNUNET_CHAT_Uri* 595 GNUNET_CHAT_uri_parse (const char *uri, 596 char **emsg) 597 { 598 GNUNET_CHAT_VERSION_ASSERT(); 599 600 if (!uri) 601 return NULL; 602 603 return uri_parse_from_string(uri, emsg); 604 } 605 606 607 char* 608 GNUNET_CHAT_uri_to_string (const struct GNUNET_CHAT_Uri *uri) 609 { 610 GNUNET_CHAT_VERSION_ASSERT(); 611 612 if (!uri) 613 return NULL; 614 615 return uri_to_string(uri); 616 } 617 618 619 enum GNUNET_CHAT_UriType 620 GNUNET_CHAT_uri_get_type (const struct GNUNET_CHAT_Uri *uri) 621 { 622 GNUNET_CHAT_VERSION_ASSERT(); 623 624 if (!uri) 625 return GNUNET_CHAT_URI_TYPE_UNKNOWN; 626 627 return uri->type; 628 } 629 630 631 void 632 GNUNET_CHAT_uri_destroy (struct GNUNET_CHAT_Uri *uri) 633 { 634 GNUNET_CHAT_VERSION_ASSERT(); 635 636 if (!uri) 637 return; 638 639 uri_destroy(uri); 640 } 641 642 643 struct GNUNET_CHAT_Lobby* 644 GNUNET_CHAT_lobby_open (struct GNUNET_CHAT_Handle *handle, 645 unsigned int delay, 646 GNUNET_CHAT_LobbyCallback callback, 647 void *cls) 648 { 649 GNUNET_CHAT_VERSION_ASSERT(); 650 651 if ((!handle) || (handle->destruction)) 652 return NULL; 653 654 struct GNUNET_TIME_Relative rel = GNUNET_TIME_relative_multiply( 655 GNUNET_TIME_relative_get_second_(), delay 656 ); 657 658 struct GNUNET_CHAT_InternalLobbies *lobbies = GNUNET_new( 659 struct GNUNET_CHAT_InternalLobbies 660 ); 661 662 lobbies->lobby = lobby_create(handle); 663 664 GNUNET_CONTAINER_DLL_insert( 665 handle->lobbies_head, 666 handle->lobbies_tail, 667 lobbies 668 ); 669 670 lobby_open(lobbies->lobby, rel, callback, cls); 671 672 return lobbies->lobby; 673 } 674 675 676 void 677 GNUNET_CHAT_lobby_close (struct GNUNET_CHAT_Lobby *lobby) 678 { 679 GNUNET_CHAT_VERSION_ASSERT(); 680 681 if ((!lobby) || (lobby->destruction)) 682 return; 683 684 lobby->destruction = GNUNET_SCHEDULER_add_now( 685 task_lobby_destruction, 686 lobby 687 ); 688 } 689 690 691 void 692 GNUNET_CHAT_lobby_join (struct GNUNET_CHAT_Handle *handle, 693 const struct GNUNET_CHAT_Uri *uri) 694 { 695 GNUNET_CHAT_VERSION_ASSERT(); 696 697 if ((!handle) || (handle->destruction) || (!(handle->gns)) || 698 (!uri) || (GNUNET_CHAT_URI_TYPE_CHAT != uri->type)) 699 return; 700 701 struct GNUNET_CHAT_UriLookups *lookups = GNUNET_new( 702 struct GNUNET_CHAT_UriLookups 703 ); 704 705 lookups->handle = handle; 706 lookups->uri = uri_create_chat( 707 &(uri->chat.zone), 708 uri->chat.label 709 ); 710 711 lookups->request = GNUNET_GNS_lookup( 712 handle->gns, 713 lookups->uri->chat.label, 714 &(uri->chat.zone), 715 GNUNET_GNSRECORD_TYPE_MESSENGER_ROOM_ENTRY, 716 GNUNET_GNS_LO_DEFAULT, 717 cb_lobby_lookup, 718 lookups 719 ); 720 721 GNUNET_CONTAINER_DLL_insert( 722 handle->lookups_head, 723 handle->lookups_tail, 724 lookups 725 ); 726 } 727 728 729 struct GNUNET_CHAT_File* 730 GNUNET_CHAT_request_file (struct GNUNET_CHAT_Handle *handle, 731 const struct GNUNET_CHAT_Uri *uri) 732 { 733 GNUNET_CHAT_VERSION_ASSERT(); 734 735 if ((!handle) || (handle->destruction) || 736 (!uri) || (GNUNET_CHAT_URI_TYPE_FS != uri->type)) 737 return NULL; 738 739 if (!GNUNET_FS_uri_test_chk(uri->fs.uri)) 740 return NULL; 741 742 const struct GNUNET_HashCode *hash = GNUNET_FS_uri_chk_get_file_hash( 743 uri->fs.uri 744 ); 745 746 if (!hash) 747 return NULL; 748 749 struct GNUNET_CHAT_File *file = GNUNET_CONTAINER_multihashmap_get( 750 handle->files, 751 hash 752 ); 753 754 if (file) 755 return file; 756 757 file = file_create_from_chk_uri(handle, uri->fs.uri); 758 759 if (!file) 760 return NULL; 761 762 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put(handle->files, hash, file, 763 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 764 { 765 file_destroy(file); 766 file = NULL; 767 } 768 769 return file; 770 } 771 772 773 struct GNUNET_CHAT_File* 774 GNUNET_CHAT_upload_file (struct GNUNET_CHAT_Handle *handle, 775 const char *path, 776 GNUNET_CHAT_FileUploadCallback callback, 777 void *cls) 778 { 779 GNUNET_CHAT_VERSION_ASSERT(); 780 781 if ((!handle) || (handle->destruction) || 782 (!path)) 783 return NULL; 784 785 struct GNUNET_HashCode hash; 786 if (GNUNET_OK != util_hash_file(path, &hash)) 787 return NULL; 788 789 char *filename = handle_create_file_path( 790 handle, &hash 791 ); 792 793 if (!filename) 794 return NULL; 795 796 struct GNUNET_CHAT_File *file = GNUNET_CONTAINER_multihashmap_get( 797 handle->files, 798 &hash 799 ); 800 801 if (file) 802 goto file_binding; 803 804 if ((GNUNET_YES == GNUNET_DISK_file_test(filename)) || 805 (GNUNET_OK != GNUNET_DISK_directory_create_for_file(filename)) || 806 (GNUNET_OK != GNUNET_DISK_file_copy(path, filename))) 807 { 808 GNUNET_free(filename); 809 return NULL; 810 } 811 812 char* p = GNUNET_strdup(path); 813 814 file = file_create_from_disk( 815 handle, 816 basename(p), 817 &hash, 818 NULL 819 ); 820 821 GNUNET_free(p); 822 823 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 824 handle->files, &hash, file, 825 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 826 { 827 file_destroy(file); 828 GNUNET_free(filename); 829 return NULL; 830 } 831 832 struct GNUNET_FS_BlockOptions bo; 833 834 bo.anonymity_level = block_anonymity_level; 835 bo.content_priority = block_content_priority; 836 bo.replication_level = block_replication_level; 837 bo.expiration_time = GNUNET_TIME_absolute_get_forever_(); 838 839 struct GNUNET_FS_FileInformation* fi = GNUNET_FS_file_information_create_from_file( 840 handle->fs, 841 file, 842 filename, 843 NULL, 844 file->meta, 845 GNUNET_YES, 846 &bo 847 ); 848 849 file->publish = GNUNET_FS_publish_start( 850 handle->fs, fi, 851 NULL, NULL, NULL, 852 GNUNET_FS_PUBLISH_OPTION_NONE 853 ); 854 855 if (file->publish) 856 file->status |= GNUNET_CHAT_FILE_STATUS_PUBLISH; 857 858 GNUNET_free(filename); 859 860 file_binding: 861 file_bind_upload(file, NULL, callback, cls); 862 return file; 863 } 864 865 866 int 867 GNUNET_CHAT_iterate_files (struct GNUNET_CHAT_Handle *handle, 868 GNUNET_CHAT_FileCallback callback, 869 void *cls) 870 { 871 GNUNET_CHAT_VERSION_ASSERT(); 872 873 if ((!handle) || (handle->destruction)) 874 return GNUNET_SYSERR; 875 876 struct GNUNET_CHAT_IterateFiles it; 877 it.handle = handle; 878 it.cb = callback; 879 it.cls = cls; 880 881 return GNUNET_CONTAINER_multihashmap_iterate( 882 handle->files, 883 it_iterate_files, 884 &it 885 ); 886 } 887 888 889 int 890 GNUNET_CHAT_context_iterate_discourses (struct GNUNET_CHAT_Context *context, 891 GNUNET_CHAT_DiscourseCallback callback, 892 void *cls) 893 { 894 GNUNET_CHAT_VERSION_ASSERT(); 895 896 if ((!context) || (!(context->discourses))) 897 return GNUNET_SYSERR; 898 899 struct GNUNET_CHAT_ContextIterateDiscourses it; 900 it.context = context; 901 it.cb = callback; 902 it.cls = cls; 903 904 return GNUNET_CONTAINER_multishortmap_iterate( 905 context->discourses, 906 it_context_iterate_discourses, 907 &it 908 ); 909 } 910 911 912 void 913 GNUNET_CHAT_set_user_pointer (struct GNUNET_CHAT_Handle *handle, 914 void *user_pointer) 915 { 916 GNUNET_CHAT_VERSION_ASSERT(); 917 918 if ((!handle) || (handle->destruction)) 919 return; 920 921 handle->user_pointer = user_pointer; 922 } 923 924 925 void* 926 GNUNET_CHAT_get_user_pointer (const struct GNUNET_CHAT_Handle *handle) 927 { 928 GNUNET_CHAT_VERSION_ASSERT(); 929 930 if ((!handle) || (handle->destruction)) 931 return NULL; 932 933 return handle->user_pointer; 934 } 935 936 937 int 938 GNUNET_CHAT_iterate_contacts (struct GNUNET_CHAT_Handle *handle, 939 GNUNET_CHAT_ContactCallback callback, 940 void *cls) 941 { 942 GNUNET_CHAT_VERSION_ASSERT(); 943 944 if ((!handle) || (handle->destruction) || (!(handle->contacts))) 945 return GNUNET_SYSERR; 946 947 struct GNUNET_CHAT_HandleIterateContacts it; 948 it.handle = handle; 949 it.cb = callback; 950 it.cls = cls; 951 952 return GNUNET_CONTAINER_multishortmap_iterate( 953 handle->contacts, it_handle_iterate_contacts, &it 954 ); 955 } 956 957 958 struct GNUNET_CHAT_Contact* 959 GNUNET_CHAT_get_own_contact (struct GNUNET_CHAT_Handle *handle) 960 { 961 GNUNET_CHAT_VERSION_ASSERT(); 962 963 if (!(handle->own_contact)) 964 GNUNET_CHAT_iterate_contacts (handle, it_handle_find_own_contact, NULL); 965 966 return handle->own_contact; 967 } 968 969 970 const char* 971 GNUNET_CHAT_account_get_name (const struct GNUNET_CHAT_Account *account) 972 { 973 GNUNET_CHAT_VERSION_ASSERT(); 974 975 if (!account) 976 return NULL; 977 978 return account_get_name(account); 979 } 980 981 982 void 983 GNUNET_CHAT_account_get_attributes (struct GNUNET_CHAT_Handle *handle, 984 struct GNUNET_CHAT_Account *account, 985 GNUNET_CHAT_AccountAttributeCallback callback, 986 void *cls) 987 { 988 GNUNET_CHAT_VERSION_ASSERT(); 989 990 if ((!handle) || (handle->destruction) || (!account)) 991 return; 992 993 const struct GNUNET_CRYPTO_BlindablePrivateKey *key = account_get_key( 994 account 995 ); 996 997 if (!key) 998 return; 999 1000 struct GNUNET_CHAT_AttributeProcess *attributes; 1001 attributes = internal_attributes_create_request(handle, account); 1002 1003 if (!attributes) 1004 return; 1005 1006 attributes->account_callback = callback; 1007 attributes->closure = cls; 1008 1009 attributes->iter = GNUNET_RECLAIM_get_attributes_start( 1010 handle->reclaim, 1011 key, 1012 cb_task_error_iterate_attribute, 1013 attributes, 1014 cb_iterate_attribute, 1015 attributes, 1016 cb_task_finish_iterate_attribute, 1017 attributes 1018 ); 1019 } 1020 1021 1022 void 1023 GNUNET_CHAT_account_set_user_pointer (struct GNUNET_CHAT_Account *account, 1024 void *user_pointer) 1025 { 1026 GNUNET_CHAT_VERSION_ASSERT(); 1027 1028 if (!account) 1029 return; 1030 1031 account->user_pointer = user_pointer; 1032 } 1033 1034 1035 void* 1036 GNUNET_CHAT_account_get_user_pointer (const struct GNUNET_CHAT_Account *account) 1037 { 1038 GNUNET_CHAT_VERSION_ASSERT(); 1039 1040 if (!account) 1041 return NULL; 1042 1043 return account->user_pointer; 1044 } 1045 1046 1047 struct GNUNET_CHAT_Group * 1048 GNUNET_CHAT_group_create (struct GNUNET_CHAT_Handle *handle, 1049 const char* topic) 1050 { 1051 GNUNET_CHAT_VERSION_ASSERT(); 1052 1053 if ((!handle) || (handle->destruction) || 1054 (!(handle->groups)) || (!(handle->contexts))) 1055 return NULL; 1056 1057 union GNUNET_MESSENGER_RoomKey key; 1058 GNUNET_MESSENGER_create_room_key( 1059 &key, 1060 topic, 1061 topic? GNUNET_YES : GNUNET_NO, 1062 GNUNET_YES, 1063 GNUNET_NO 1064 ); 1065 1066 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->contexts, &(key.hash))) 1067 return NULL; 1068 1069 struct GNUNET_MESSENGER_Room *room = GNUNET_MESSENGER_open_room( 1070 handle->messenger, &key 1071 ); 1072 1073 if (!room) 1074 return NULL; 1075 1076 struct GNUNET_CHAT_Context *context = context_create_from_room(handle, room); 1077 context->type = GNUNET_CHAT_CONTEXT_TYPE_GROUP; 1078 1079 util_set_name_field(topic, &(context->topic)); 1080 1081 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 1082 handle->contexts, &(key.hash), context, 1083 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 1084 goto destroy_context; 1085 1086 struct GNUNET_CHAT_Group *group = group_create_from_context(handle, context); 1087 1088 if (context->topic) 1089 group_publish(group); 1090 1091 if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put( 1092 handle->groups, &(key.hash), group, 1093 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 1094 { 1095 context_write_records(context); 1096 return group; 1097 } 1098 1099 group_destroy(group); 1100 1101 GNUNET_CONTAINER_multihashmap_remove(handle->contexts, &(key.hash), context); 1102 1103 destroy_context: 1104 context_destroy(context); 1105 return NULL; 1106 } 1107 1108 1109 int 1110 GNUNET_CHAT_iterate_groups (struct GNUNET_CHAT_Handle *handle, 1111 GNUNET_CHAT_GroupCallback callback, 1112 void *cls) 1113 { 1114 GNUNET_CHAT_VERSION_ASSERT(); 1115 1116 if ((!handle) || (handle->destruction) || (!(handle->groups))) 1117 return GNUNET_SYSERR; 1118 1119 struct GNUNET_CHAT_HandleIterateGroups it; 1120 it.handle = handle; 1121 it.cb = callback; 1122 it.cls = cls; 1123 1124 return GNUNET_CONTAINER_multihashmap_iterate( 1125 handle->groups, it_handle_iterate_groups, &it 1126 ); 1127 } 1128 1129 1130 void 1131 GNUNET_CHAT_contact_delete (struct GNUNET_CHAT_Contact *contact) 1132 { 1133 GNUNET_CHAT_VERSION_ASSERT(); 1134 1135 if ((!contact) || (contact->destruction)) 1136 return; 1137 1138 if (contact->context) 1139 contact->context->deleted = GNUNET_YES; 1140 1141 contact->destruction = GNUNET_SCHEDULER_add_now( 1142 task_contact_destruction, 1143 contact 1144 ); 1145 } 1146 1147 1148 void 1149 GNUNET_CHAT_contact_set_name (struct GNUNET_CHAT_Contact *contact, 1150 const char *name) 1151 { 1152 GNUNET_CHAT_VERSION_ASSERT(); 1153 1154 if ((!contact) || (!(contact->context)) || 1155 (contact->context->topic)) 1156 return; 1157 1158 context_update_nick(contact->context, name); 1159 1160 if (contact->context->room) 1161 context_write_records(contact->context); 1162 } 1163 1164 1165 const char* 1166 GNUNET_CHAT_contact_get_name (const struct GNUNET_CHAT_Contact *contact) 1167 { 1168 GNUNET_CHAT_VERSION_ASSERT(); 1169 1170 if (!contact) 1171 return NULL; 1172 1173 if ((contact->context) && (! contact->context->topic) && 1174 (contact->context->nick)) 1175 return contact->context->nick; 1176 1177 return GNUNET_MESSENGER_contact_get_name(contact->member); 1178 } 1179 1180 1181 const char* 1182 GNUNET_CHAT_contact_get_key (const struct GNUNET_CHAT_Contact *contact) 1183 { 1184 GNUNET_CHAT_VERSION_ASSERT(); 1185 1186 if (!contact) 1187 return NULL; 1188 1189 return contact->public_key; 1190 } 1191 1192 1193 struct GNUNET_CHAT_Context* 1194 GNUNET_CHAT_contact_get_context (struct GNUNET_CHAT_Contact *contact) 1195 { 1196 GNUNET_CHAT_VERSION_ASSERT(); 1197 1198 if (!contact) 1199 return NULL; 1200 1201 if (contact->context) 1202 return contact->context; 1203 1204 struct GNUNET_CHAT_Context *context = contact_find_context( 1205 contact, 1206 GNUNET_NO 1207 ); 1208 1209 if ((context) && (GNUNET_CHAT_CONTEXT_TYPE_CONTACT == context->type)) 1210 goto attach_return; 1211 1212 context = context_create_from_contact(contact->handle, contact->member); 1213 1214 attach_return: 1215 if (context) 1216 contact->context = context; 1217 1218 return context; 1219 } 1220 1221 1222 void 1223 GNUNET_CHAT_contact_set_user_pointer (struct GNUNET_CHAT_Contact *contact, 1224 void *user_pointer) 1225 { 1226 GNUNET_CHAT_VERSION_ASSERT(); 1227 1228 if (!contact) 1229 return; 1230 1231 contact->user_pointer = user_pointer; 1232 } 1233 1234 1235 void* 1236 GNUNET_CHAT_contact_get_user_pointer (const struct GNUNET_CHAT_Contact *contact) 1237 { 1238 GNUNET_CHAT_VERSION_ASSERT(); 1239 1240 if (!contact) 1241 return NULL; 1242 1243 return contact->user_pointer; 1244 } 1245 1246 1247 enum GNUNET_GenericReturnValue 1248 GNUNET_CHAT_contact_is_owned (const struct GNUNET_CHAT_Contact *contact) 1249 { 1250 GNUNET_CHAT_VERSION_ASSERT(); 1251 1252 if (!contact) 1253 return GNUNET_SYSERR; 1254 1255 return contact->owned; 1256 } 1257 1258 1259 void 1260 GNUNET_CHAT_contact_set_blocked (struct GNUNET_CHAT_Contact *contact, 1261 enum GNUNET_GenericReturnValue blocked) 1262 { 1263 GNUNET_CHAT_VERSION_ASSERT(); 1264 1265 if (!contact) 1266 return; 1267 1268 struct GNUNET_CHAT_ContactIterateContexts it; 1269 it.contact = contact; 1270 it.tag = NULL; 1271 1272 if (GNUNET_NO == blocked) 1273 it.cb = contact_untag; 1274 else if (GNUNET_YES == blocked) 1275 it.cb = contact_tag; 1276 else 1277 return; 1278 1279 GNUNET_CONTAINER_multihashmap_iterate( 1280 contact->joined, 1281 it_contact_iterate_contexts, 1282 &it 1283 ); 1284 } 1285 1286 1287 enum GNUNET_GenericReturnValue 1288 GNUNET_CHAT_contact_is_blocked (const struct GNUNET_CHAT_Contact *contact) 1289 { 1290 GNUNET_CHAT_VERSION_ASSERT(); 1291 1292 if (!contact) 1293 return GNUNET_SYSERR; 1294 1295 return contact_is_tagged(contact, NULL, NULL); 1296 } 1297 1298 1299 void 1300 GNUNET_CHAT_contact_tag (struct GNUNET_CHAT_Contact *contact, 1301 const char *tag) 1302 { 1303 GNUNET_CHAT_VERSION_ASSERT(); 1304 1305 if ((!contact) || (!tag) || (!tag[0])) 1306 return; 1307 1308 struct GNUNET_CHAT_ContactIterateContexts it; 1309 it.contact = contact; 1310 it.tag = tag; 1311 it.cb = contact_tag; 1312 1313 GNUNET_CONTAINER_multihashmap_iterate( 1314 contact->joined, 1315 it_contact_iterate_contexts, 1316 &it 1317 ); 1318 } 1319 1320 1321 void 1322 GNUNET_CHAT_contact_untag (struct GNUNET_CHAT_Contact *contact, 1323 const char *tag) 1324 { 1325 GNUNET_CHAT_VERSION_ASSERT(); 1326 1327 if ((!contact) || (!tag) || (!tag[0])) 1328 return; 1329 1330 struct GNUNET_CHAT_ContactIterateContexts it; 1331 it.contact = contact; 1332 it.tag = tag; 1333 it.cb = contact_untag; 1334 1335 GNUNET_CONTAINER_multihashmap_iterate( 1336 contact->joined, 1337 it_contact_iterate_contexts, 1338 &it 1339 ); 1340 } 1341 1342 1343 enum GNUNET_GenericReturnValue 1344 GNUNET_CHAT_contact_is_tagged (const struct GNUNET_CHAT_Contact *contact, 1345 const char *tag) 1346 { 1347 GNUNET_CHAT_VERSION_ASSERT(); 1348 1349 if ((!contact) || (!tag) || (!tag[0])) 1350 return GNUNET_SYSERR; 1351 1352 return contact_is_tagged(contact, NULL, tag); 1353 } 1354 1355 1356 int 1357 GNUNET_CHAT_contact_iterate_tags (struct GNUNET_CHAT_Contact *contact, 1358 GNUNET_CHAT_ContactTagCallback callback, 1359 void *cls) 1360 { 1361 GNUNET_CHAT_VERSION_ASSERT(); 1362 1363 if (!contact) 1364 return GNUNET_SYSERR; 1365 1366 return contact_iterate_tags( 1367 contact, 1368 NULL, 1369 callback, 1370 cls 1371 ); 1372 } 1373 1374 1375 void 1376 GNUNET_CHAT_contact_get_attributes (struct GNUNET_CHAT_Contact *contact, 1377 GNUNET_CHAT_ContactAttributeCallback callback, 1378 void *cls) 1379 { 1380 GNUNET_CHAT_VERSION_ASSERT(); 1381 1382 if (!contact) 1383 return; 1384 1385 struct GNUNET_CHAT_InternalTickets *tickets; 1386 tickets = contact->tickets_head; 1387 1388 while (tickets) 1389 { 1390 ticket_consume( 1391 tickets->ticket, 1392 callback, 1393 cls 1394 ); 1395 1396 tickets = tickets->next; 1397 } 1398 } 1399 1400 1401 enum GNUNET_GenericReturnValue 1402 GNUNET_CHAT_group_leave (struct GNUNET_CHAT_Group *group) 1403 { 1404 GNUNET_CHAT_VERSION_ASSERT(); 1405 1406 if ((!group) || (group->destruction)) 1407 return GNUNET_SYSERR; 1408 1409 group->context->deleted = GNUNET_YES; 1410 group->destruction = GNUNET_SCHEDULER_add_now( 1411 task_group_destruction, 1412 group 1413 ); 1414 1415 return GNUNET_OK; 1416 } 1417 1418 1419 void 1420 GNUNET_CHAT_group_set_name (struct GNUNET_CHAT_Group *group, 1421 const char *name) 1422 { 1423 GNUNET_CHAT_VERSION_ASSERT(); 1424 1425 if ((!group) || (!(group->context))) 1426 return; 1427 1428 context_update_nick(group->context, name); 1429 1430 if (group->context->room) 1431 context_write_records(group->context); 1432 } 1433 1434 1435 const char* 1436 GNUNET_CHAT_group_get_name (const struct GNUNET_CHAT_Group *group) 1437 { 1438 GNUNET_CHAT_VERSION_ASSERT(); 1439 1440 if ((!group) || (!(group->context))) 1441 return NULL; 1442 1443 if (group->context->nick) 1444 return group->context->nick; 1445 1446 return group->context->topic; 1447 } 1448 1449 1450 void 1451 GNUNET_CHAT_group_set_user_pointer (struct GNUNET_CHAT_Group *group, 1452 void *user_pointer) 1453 { 1454 GNUNET_CHAT_VERSION_ASSERT(); 1455 1456 if (!group) 1457 return; 1458 1459 group->user_pointer = user_pointer; 1460 } 1461 1462 1463 void* 1464 GNUNET_CHAT_group_get_user_pointer (const struct GNUNET_CHAT_Group *group) 1465 { 1466 GNUNET_CHAT_VERSION_ASSERT(); 1467 1468 if (!group) 1469 return NULL; 1470 1471 return group->user_pointer; 1472 } 1473 1474 1475 enum GNUNET_GenericReturnValue 1476 GNUNET_CHAT_group_invite_contact (struct GNUNET_CHAT_Group *group, 1477 struct GNUNET_CHAT_Contact *contact) 1478 { 1479 GNUNET_CHAT_VERSION_ASSERT(); 1480 1481 if ((!group) || (!contact) || (!contact->member)) 1482 return GNUNET_SYSERR; 1483 1484 struct GNUNET_CHAT_Context *context = contact_find_context( 1485 contact, 1486 GNUNET_YES 1487 ); 1488 1489 if (!context) 1490 return GNUNET_SYSERR; 1491 1492 union GNUNET_MESSENGER_RoomKey key; 1493 GNUNET_memcpy( 1494 &(key.hash), 1495 GNUNET_MESSENGER_room_get_key(group->context->room), 1496 sizeof(key.hash) 1497 ); 1498 1499 handle_send_room_name(group->handle, GNUNET_MESSENGER_open_room( 1500 group->handle->messenger, &key 1501 )); 1502 1503 struct GNUNET_MESSENGER_Message msg; 1504 memset(&msg, 0, sizeof(msg)); 1505 1506 msg.header.kind = GNUNET_MESSENGER_KIND_INVITE; 1507 GNUNET_CRYPTO_get_peer_identity(group->handle->cfg, &(msg.body.invite.door)); 1508 GNUNET_memcpy(&(msg.body.invite.key), &key, sizeof(msg.body.invite.key)); 1509 1510 GNUNET_MESSENGER_send_message(context->room, &msg, contact->member); 1511 return GNUNET_OK; 1512 } 1513 1514 1515 int 1516 GNUNET_CHAT_group_iterate_contacts (struct GNUNET_CHAT_Group *group, 1517 GNUNET_CHAT_GroupContactCallback callback, 1518 void *cls) 1519 { 1520 GNUNET_CHAT_VERSION_ASSERT(); 1521 1522 if (!group) 1523 return GNUNET_SYSERR; 1524 1525 struct GNUNET_CHAT_GroupIterateContacts it; 1526 it.group = group; 1527 it.cb = callback; 1528 it.cls = cls; 1529 1530 return GNUNET_MESSENGER_iterate_members( 1531 group->context->room, it_group_iterate_contacts, &it 1532 ); 1533 } 1534 1535 1536 void 1537 GNUNET_CHAT_member_set_user_pointer (struct GNUNET_CHAT_Group *group, 1538 const struct GNUNET_CHAT_Contact *member, 1539 void *user_pointer) 1540 { 1541 GNUNET_CHAT_VERSION_ASSERT(); 1542 1543 if ((!group) || (!(group->context)) || (!member)) 1544 return; 1545 1546 struct GNUNET_ShortHashCode hash; 1547 util_shorthash_from_member(member->member, &hash); 1548 1549 GNUNET_CONTAINER_multishortmap_put( 1550 group->context->member_pointers, 1551 &hash, 1552 user_pointer, 1553 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE 1554 ); 1555 } 1556 1557 1558 void* 1559 GNUNET_CHAT_member_get_user_pointer (const struct GNUNET_CHAT_Group *group, 1560 const struct GNUNET_CHAT_Contact *member) 1561 { 1562 GNUNET_CHAT_VERSION_ASSERT(); 1563 1564 if ((!group) || (!(group->context)) || (!member)) 1565 return NULL; 1566 1567 struct GNUNET_ShortHashCode hash; 1568 util_shorthash_from_member(member->member, &hash); 1569 1570 return GNUNET_CONTAINER_multishortmap_get( 1571 group->context->member_pointers, 1572 &hash 1573 ); 1574 } 1575 1576 1577 struct GNUNET_CHAT_Context* 1578 GNUNET_CHAT_group_get_context (struct GNUNET_CHAT_Group *group) 1579 { 1580 GNUNET_CHAT_VERSION_ASSERT(); 1581 1582 if (!group) 1583 return NULL; 1584 1585 return group->context; 1586 } 1587 1588 1589 enum GNUNET_GenericReturnValue 1590 GNUNET_CHAT_context_get_status (struct GNUNET_CHAT_Context *context) 1591 { 1592 GNUNET_CHAT_VERSION_ASSERT(); 1593 1594 if ((!context) || (!(context->room))) 1595 return GNUNET_SYSERR; 1596 1597 switch (context->type) { 1598 case GNUNET_CHAT_CONTEXT_TYPE_CONTACT: 1599 { 1600 const struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_context_get_contact( 1601 context 1602 ); 1603 1604 return contact? GNUNET_OK : GNUNET_NO; 1605 } 1606 case GNUNET_CHAT_CONTEXT_TYPE_GROUP: 1607 return GNUNET_OK; 1608 default: 1609 return GNUNET_NO; 1610 } 1611 } 1612 1613 1614 enum GNUNET_GenericReturnValue 1615 GNUNET_CHAT_context_request (struct GNUNET_CHAT_Context *context) 1616 { 1617 GNUNET_CHAT_VERSION_ASSERT(); 1618 1619 if (!context) 1620 return GNUNET_SYSERR; 1621 else if (context->room) 1622 return GNUNET_OK; 1623 1624 struct GNUNET_CHAT_Handle *handle = context->handle; 1625 1626 if ((!handle) || (!(context->contact))) 1627 return GNUNET_SYSERR; 1628 1629 struct GNUNET_CHAT_Contact *contact = handle_get_contact_from_messenger( 1630 handle, context->contact 1631 ); 1632 1633 if (!contact) 1634 return GNUNET_SYSERR; 1635 1636 enum GNUNET_GenericReturnValue owned = GNUNET_CHAT_contact_is_owned( 1637 contact 1638 ); 1639 1640 context->type = GNUNET_CHAT_CONTEXT_TYPE_CONTACT; 1641 1642 struct GNUNET_CHAT_Context *other = contact_find_context( 1643 contact, GNUNET_YES 1644 ); 1645 1646 if (!other) 1647 return GNUNET_SYSERR; 1648 1649 union GNUNET_MESSENGER_RoomKey key; 1650 GNUNET_MESSENGER_create_room_key( 1651 &key, 1652 NULL, 1653 GNUNET_YES == owned? GNUNET_YES : GNUNET_NO, 1654 GNUNET_NO, 1655 GNUNET_YES == owned? GNUNET_YES : GNUNET_NO 1656 ); 1657 1658 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains( 1659 handle->contexts, &(key.hash))) 1660 return GNUNET_SYSERR; 1661 1662 struct GNUNET_MESSENGER_Room *room; 1663 if (GNUNET_YES == owned) 1664 { 1665 struct GNUNET_PeerIdentity door; 1666 if (GNUNET_OK == GNUNET_CRYPTO_get_peer_identity( 1667 handle->cfg, &door)) 1668 room = GNUNET_MESSENGER_enter_room( 1669 handle->messenger, 1670 &door, 1671 &key 1672 ); 1673 else 1674 room = NULL; 1675 } 1676 else 1677 room = GNUNET_MESSENGER_open_room( 1678 handle->messenger, &key 1679 ); 1680 1681 if (!room) 1682 return GNUNET_SYSERR; 1683 1684 context_update_room(context, room, GNUNET_YES); 1685 1686 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 1687 handle->contexts, &(key.hash), context, 1688 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 1689 { 1690 context_update_room(context, NULL, GNUNET_YES); 1691 return GNUNET_SYSERR; 1692 } 1693 1694 if (GNUNET_YES != owned) 1695 { 1696 struct GNUNET_MESSENGER_Message msg; 1697 memset(&msg, 0, sizeof(msg)); 1698 1699 msg.header.kind = GNUNET_MESSENGER_KIND_INVITE; 1700 GNUNET_CRYPTO_get_peer_identity(handle->cfg, &(msg.body.invite.door)); 1701 GNUNET_memcpy(&(msg.body.invite.key), &key, sizeof(msg.body.invite.key)); 1702 1703 GNUNET_MESSENGER_send_message(other->room, &msg, context->contact); 1704 } 1705 1706 return GNUNET_OK; 1707 } 1708 1709 1710 struct GNUNET_CHAT_Contact* 1711 GNUNET_CHAT_context_get_contact (struct GNUNET_CHAT_Context *context) 1712 { 1713 GNUNET_CHAT_VERSION_ASSERT(); 1714 1715 if ((!context) || (GNUNET_CHAT_CONTEXT_TYPE_CONTACT != context->type)) 1716 return NULL; 1717 1718 if (context->contact) 1719 return handle_get_contact_from_messenger(context->handle, context->contact); 1720 1721 struct GNUNET_MESSENGER_Room *room = context->room; 1722 struct GNUNET_CHAT_RoomFindContact find; 1723 union GNUNET_MESSENGER_RoomKey key; 1724 1725 GNUNET_memcpy(&(key.hash), GNUNET_MESSENGER_room_get_key(room), sizeof(key.hash)); 1726 1727 if (key.code.group_bit) 1728 return NULL; 1729 1730 if (! key.code.feed_bit) 1731 find.ignore_key = GNUNET_MESSENGER_get_key(context->handle->messenger); 1732 else 1733 find.ignore_key = NULL; 1734 1735 find.contact = NULL; 1736 1737 int member_count = GNUNET_MESSENGER_iterate_members( 1738 room, 1739 it_room_find_contact, 1740 &find 1741 ); 1742 1743 if ((!find.contact) || (member_count > 2)) 1744 return NULL; 1745 1746 return handle_get_contact_from_messenger(context->handle, find.contact); 1747 } 1748 1749 1750 struct GNUNET_CHAT_Group* 1751 GNUNET_CHAT_context_get_group (struct GNUNET_CHAT_Context *context) 1752 { 1753 GNUNET_CHAT_VERSION_ASSERT(); 1754 1755 if ((!context) || (GNUNET_CHAT_CONTEXT_TYPE_GROUP != context->type)) 1756 return NULL; 1757 1758 if (!(context->room)) 1759 return NULL; 1760 1761 return handle_get_group_from_messenger(context->handle, context->room); 1762 } 1763 1764 1765 void 1766 GNUNET_CHAT_context_set_user_pointer (struct GNUNET_CHAT_Context *context, 1767 void *user_pointer) 1768 { 1769 GNUNET_CHAT_VERSION_ASSERT(); 1770 1771 if (!context) 1772 return; 1773 1774 context->user_pointer = user_pointer; 1775 } 1776 1777 1778 void* 1779 GNUNET_CHAT_context_get_user_pointer (const struct GNUNET_CHAT_Context *context) 1780 { 1781 GNUNET_CHAT_VERSION_ASSERT(); 1782 1783 if (!context) 1784 return NULL; 1785 1786 return context->user_pointer; 1787 } 1788 1789 1790 enum GNUNET_GenericReturnValue 1791 GNUNET_CHAT_context_send_text (struct GNUNET_CHAT_Context *context, 1792 const char *text) 1793 { 1794 GNUNET_CHAT_VERSION_ASSERT(); 1795 1796 if ((!context) || (!text) || (!(context->room))) 1797 return GNUNET_SYSERR; 1798 1799 struct GNUNET_MESSENGER_Message msg; 1800 memset(&msg, 0, sizeof(msg)); 1801 1802 msg.header.kind = GNUNET_MESSENGER_KIND_TEXT; 1803 msg.body.text.text = GNUNET_strdup(text); 1804 1805 GNUNET_MESSENGER_send_message(context->room, &msg, NULL); 1806 1807 GNUNET_free(msg.body.text.text); 1808 return GNUNET_OK; 1809 } 1810 1811 1812 enum GNUNET_GenericReturnValue 1813 GNUNET_CHAT_context_send_read_receipt (struct GNUNET_CHAT_Context *context, 1814 struct GNUNET_CHAT_Message *message) 1815 { 1816 GNUNET_CHAT_VERSION_ASSERT(); 1817 1818 if ((!context) || (!(context->room))) 1819 return GNUNET_SYSERR; 1820 1821 char zero = '\0'; 1822 struct GNUNET_MESSENGER_Message msg; 1823 memset(&msg, 0, sizeof(msg)); 1824 1825 msg.header.kind = GNUNET_MESSENGER_KIND_TEXT; 1826 msg.body.text.text = &zero; 1827 1828 const struct GNUNET_MESSENGER_Contact *receiver = NULL; 1829 1830 if (!message) 1831 goto skip_filter; 1832 1833 if (GNUNET_CHAT_FLAG_NONE != message->flag) 1834 return GNUNET_SYSERR; 1835 1836 if (message->flags & GNUNET_MESSENGER_FLAG_SENT) 1837 return GNUNET_OK; 1838 1839 if (message->flags & GNUNET_MESSENGER_FLAG_PRIVATE) 1840 { 1841 receiver = GNUNET_MESSENGER_get_sender(context->room, &(message->hash)); 1842 1843 if (!receiver) 1844 return GNUNET_SYSERR; 1845 } 1846 1847 if ((GNUNET_YES != message_has_msg(message)) || 1848 (GNUNET_MESSENGER_KIND_TEXT != message->msg->header.kind)) 1849 goto skip_filter; 1850 1851 if ((!(message->msg->body.text.text)) || 1852 (!(message->msg->body.text.text[0]))) 1853 return GNUNET_SYSERR; 1854 1855 skip_filter: 1856 GNUNET_MESSENGER_send_message(context->room, &msg, receiver); 1857 return GNUNET_OK; 1858 } 1859 1860 1861 struct GNUNET_CHAT_File* 1862 GNUNET_CHAT_context_send_file (struct GNUNET_CHAT_Context *context, 1863 const char *path, 1864 GNUNET_CHAT_FileUploadCallback callback, 1865 void *cls) 1866 { 1867 GNUNET_CHAT_VERSION_ASSERT(); 1868 1869 if ((!context) || (!path) || (!(context->room))) 1870 return NULL; 1871 1872 struct GNUNET_HashCode hash; 1873 if (GNUNET_OK != util_hash_file(path, &hash)) 1874 return NULL; 1875 1876 char *filename = handle_create_file_path( 1877 context->handle, &hash 1878 ); 1879 1880 if (!filename) 1881 return NULL; 1882 1883 struct GNUNET_CHAT_File *file = GNUNET_CONTAINER_multihashmap_get( 1884 context->handle->files, 1885 &hash 1886 ); 1887 1888 if (file) 1889 goto file_binding; 1890 1891 if ((GNUNET_YES == GNUNET_DISK_file_test(filename)) || 1892 (GNUNET_OK != GNUNET_DISK_directory_create_for_file(filename)) || 1893 (GNUNET_OK != GNUNET_DISK_file_copy(path, filename))) 1894 { 1895 GNUNET_free(filename); 1896 return NULL; 1897 } 1898 1899 struct GNUNET_CRYPTO_SymmetricSessionKey key; 1900 GNUNET_CRYPTO_symmetric_create_session_key(&key); 1901 1902 if (GNUNET_OK != util_encrypt_file(filename, &hash, &key)) 1903 { 1904 GNUNET_free(filename); 1905 return NULL; 1906 } 1907 1908 char* p = GNUNET_strdup(path); 1909 1910 file = file_create_from_disk( 1911 context->handle, 1912 basename(p), 1913 &hash, 1914 &key 1915 ); 1916 1917 GNUNET_free(p); 1918 1919 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 1920 context->handle->files, &hash, file, 1921 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 1922 { 1923 file_destroy(file); 1924 GNUNET_free(filename); 1925 return NULL; 1926 } 1927 1928 struct GNUNET_FS_BlockOptions bo; 1929 1930 bo.anonymity_level = block_anonymity_level; 1931 bo.content_priority = block_content_priority; 1932 bo.replication_level = block_replication_level; 1933 bo.expiration_time = GNUNET_TIME_absolute_get_forever_(); 1934 1935 struct GNUNET_FS_FileInformation* fi = GNUNET_FS_file_information_create_from_file( 1936 context->handle->fs, 1937 file, 1938 filename, 1939 NULL, 1940 file->meta, 1941 GNUNET_YES, 1942 &bo 1943 ); 1944 1945 file->publish = GNUNET_FS_publish_start( 1946 context->handle->fs, fi, 1947 NULL, NULL, NULL, 1948 GNUNET_FS_PUBLISH_OPTION_NONE 1949 ); 1950 1951 if (file->publish) 1952 file->status |= GNUNET_CHAT_FILE_STATUS_PUBLISH; 1953 1954 GNUNET_free(filename); 1955 1956 file_binding: 1957 file_bind_upload(file, context, callback, cls); 1958 return file; 1959 } 1960 1961 1962 enum GNUNET_GenericReturnValue 1963 GNUNET_CHAT_context_share_file (struct GNUNET_CHAT_Context *context, 1964 struct GNUNET_CHAT_File *file) 1965 { 1966 GNUNET_CHAT_VERSION_ASSERT(); 1967 1968 if ((!context) || (!file) || 1969 (!(file->name)) || (strlen(file->name) > NAME_MAX) || 1970 (!(file->uri)) || (!(context->room))) 1971 return GNUNET_SYSERR; 1972 1973 struct GNUNET_MESSENGER_Message msg; 1974 memset(&msg, 0, sizeof(msg)); 1975 1976 msg.header.kind = GNUNET_MESSENGER_KIND_FILE; 1977 1978 if (file->key) 1979 GNUNET_memcpy(&(msg.body.file.key), file->key, 1980 sizeof(struct GNUNET_CRYPTO_SymmetricSessionKey)); 1981 else 1982 memset(&(msg.body.file.key), 0, sizeof(msg.body.file.key)); 1983 1984 GNUNET_memcpy(&(msg.body.file.hash), &(file->hash), sizeof(file->hash)); 1985 GNUNET_strlcpy(msg.body.file.name, file->name, NAME_MAX); 1986 msg.body.file.uri = GNUNET_FS_uri_to_string(file->uri); 1987 1988 GNUNET_MESSENGER_send_message(context->room, &msg, NULL); 1989 1990 GNUNET_free(msg.body.file.uri); 1991 return GNUNET_OK; 1992 } 1993 1994 1995 enum GNUNET_GenericReturnValue 1996 GNUNET_CHAT_context_send_tag (struct GNUNET_CHAT_Context *context, 1997 struct GNUNET_CHAT_Message *message, 1998 const char *tag) 1999 { 2000 GNUNET_CHAT_VERSION_ASSERT(); 2001 2002 if ((!context) || (!message) || (!tag) || (!(context->room))) 2003 return GNUNET_SYSERR; 2004 2005 char *tag_value = GNUNET_strdup(tag); 2006 2007 struct GNUNET_MESSENGER_Message msg; 2008 memset(&msg, 0, sizeof(msg)); 2009 2010 msg.header.kind = GNUNET_MESSENGER_KIND_TAG; 2011 GNUNET_memcpy(&(msg.body.tag.hash), &(message->hash), 2012 sizeof(struct GNUNET_HashCode)); 2013 msg.body.tag.tag = tag_value; 2014 2015 GNUNET_MESSENGER_send_message( 2016 context->room, 2017 &msg, 2018 NULL 2019 ); 2020 2021 GNUNET_free(tag_value); 2022 return GNUNET_OK; 2023 } 2024 2025 2026 struct GNUNET_CHAT_Discourse* 2027 GNUNET_CHAT_context_open_discourse (struct GNUNET_CHAT_Context *context, 2028 const struct GNUNET_CHAT_DiscourseId *id) 2029 { 2030 GNUNET_CHAT_VERSION_ASSERT(); 2031 2032 if ((!context) || (!(context->discourses)) || (!(context->room)) || (!id)) 2033 return NULL; 2034 2035 struct GNUNET_ShortHashCode sid; 2036 util_shorthash_from_discourse_id(id, &sid); 2037 2038 struct GNUNET_CHAT_Discourse *discourse = GNUNET_CONTAINER_multishortmap_get( 2039 context->discourses, &sid 2040 ); 2041 2042 if (!discourse) 2043 { 2044 discourse = discourse_create(context, id); 2045 2046 if (GNUNET_OK != GNUNET_CONTAINER_multishortmap_put(context->discourses, 2047 &sid, discourse, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 2048 { 2049 discourse_destroy(discourse); 2050 return NULL; 2051 } 2052 } 2053 2054 struct GNUNET_MESSENGER_Message msg; 2055 memset(&msg, 0, sizeof(msg)); 2056 2057 msg.header.kind = GNUNET_MESSENGER_KIND_SUBSCRIBTION; 2058 GNUNET_memcpy( 2059 &(msg.body.subscription.discourse), 2060 &sid, 2061 sizeof(struct GNUNET_ShortHashCode) 2062 ); 2063 2064 const struct GNUNET_TIME_Relative subscription_time = GNUNET_TIME_relative_multiply( 2065 GNUNET_TIME_relative_get_second_(), 10 2066 ); 2067 2068 msg.body.subscription.time = GNUNET_TIME_relative_hton(subscription_time); 2069 msg.body.subscription.flags = GNUNET_MESSENGER_FLAG_SUBSCRIPTION_KEEP_ALIVE; 2070 2071 GNUNET_MESSENGER_send_message( 2072 context->room, 2073 &msg, 2074 NULL 2075 ); 2076 2077 return discourse; 2078 } 2079 2080 2081 int 2082 GNUNET_CHAT_context_iterate_messages (struct GNUNET_CHAT_Context *context, 2083 GNUNET_CHAT_ContextMessageCallback callback, 2084 void *cls) 2085 { 2086 GNUNET_CHAT_VERSION_ASSERT(); 2087 2088 if (!context) 2089 return GNUNET_SYSERR; 2090 2091 struct GNUNET_CHAT_ContextIterateMessages it; 2092 it.context = context; 2093 it.cb = callback; 2094 it.cls = cls; 2095 2096 return GNUNET_CONTAINER_multihashmap_iterate( 2097 context->messages, it_context_iterate_messages, &it 2098 ); 2099 } 2100 2101 2102 int 2103 GNUNET_CHAT_context_iterate_files (struct GNUNET_CHAT_Context *context, 2104 GNUNET_CHAT_ContextFileCallback callback, 2105 void *cls) 2106 { 2107 GNUNET_CHAT_VERSION_ASSERT(); 2108 2109 if (!context) 2110 return GNUNET_SYSERR; 2111 2112 struct GNUNET_CHAT_ContextIterateFiles it; 2113 it.context = context; 2114 it.cb = callback; 2115 it.cls = cls; 2116 2117 return GNUNET_CONTAINER_multihashmap_iterate( 2118 context->files, it_context_iterate_files, &it 2119 ); 2120 } 2121 2122 2123 enum GNUNET_CHAT_MessageKind 2124 GNUNET_CHAT_message_get_kind (const struct GNUNET_CHAT_Message *message) 2125 { 2126 GNUNET_CHAT_VERSION_ASSERT(); 2127 2128 if (!message) 2129 return GNUNET_CHAT_KIND_UNKNOWN; 2130 2131 switch (message->flag) 2132 { 2133 case GNUNET_CHAT_FLAG_WARNING: 2134 return GNUNET_CHAT_KIND_WARNING; 2135 case GNUNET_CHAT_FLAG_REFRESH: 2136 return GNUNET_CHAT_KIND_REFRESH; 2137 case GNUNET_CHAT_FLAG_LOGIN: 2138 return GNUNET_CHAT_KIND_LOGIN; 2139 case GNUNET_CHAT_FLAG_LOGOUT: 2140 return GNUNET_CHAT_KIND_LOGOUT; 2141 case GNUNET_CHAT_FLAG_CREATE_ACCOUNT: 2142 return GNUNET_CHAT_KIND_CREATED_ACCOUNT; 2143 case GNUNET_CHAT_FLAG_DELETE_ACCOUNT: 2144 return GNUNET_CHAT_KIND_DELETED_ACCOUNT; 2145 case GNUNET_CHAT_FLAG_UPDATE_ACCOUNT: 2146 return GNUNET_CHAT_KIND_UPDATE_ACCOUNT; 2147 case GNUNET_CHAT_FLAG_UPDATE_CONTEXT: 2148 return GNUNET_CHAT_KIND_UPDATE_CONTEXT; 2149 case GNUNET_CHAT_FLAG_ATTRIBUTES: 2150 return GNUNET_CHAT_KIND_ATTRIBUTES; 2151 case GNUNET_CHAT_FLAG_SHARE_ATTRIBUTES: 2152 return GNUNET_CHAT_KIND_SHARED_ATTRIBUTES; 2153 default: 2154 break; 2155 } 2156 2157 if (GNUNET_YES != message_has_msg(message)) 2158 return GNUNET_CHAT_KIND_UNKNOWN; 2159 2160 return util_message_kind_from_kind(message->msg->header.kind); 2161 } 2162 2163 2164 time_t 2165 GNUNET_CHAT_message_get_timestamp (const struct GNUNET_CHAT_Message *message) 2166 { 2167 GNUNET_CHAT_VERSION_ASSERT(); 2168 2169 if ((!message) || (GNUNET_YES != message_has_msg(message))) 2170 return ((time_t) -1); 2171 2172 struct GNUNET_TIME_Absolute abs = GNUNET_TIME_absolute_ntoh( 2173 message->msg->header.timestamp 2174 ); 2175 2176 struct GNUNET_TIME_Timestamp ts = GNUNET_TIME_absolute_to_timestamp( 2177 abs 2178 ); 2179 2180 return (time_t) GNUNET_TIME_timestamp_to_s(ts); 2181 } 2182 2183 2184 struct GNUNET_CHAT_Contact* 2185 GNUNET_CHAT_message_get_sender (const struct GNUNET_CHAT_Message *message) 2186 { 2187 GNUNET_CHAT_VERSION_ASSERT(); 2188 2189 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2190 (!(message->context)) || (!(message->context->room))) 2191 return NULL; 2192 2193 const struct GNUNET_MESSENGER_Contact *sender = GNUNET_MESSENGER_get_sender( 2194 message->context->room, &(message->hash) 2195 ); 2196 2197 if (!sender) 2198 return NULL; 2199 2200 return handle_get_contact_from_messenger(message->context->handle, sender); 2201 } 2202 2203 2204 struct GNUNET_CHAT_Contact* 2205 GNUNET_CHAT_message_get_recipient (const struct GNUNET_CHAT_Message *message) 2206 { 2207 GNUNET_CHAT_VERSION_ASSERT(); 2208 2209 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2210 (!(message->context)) || (!(message->context->room))) 2211 return NULL; 2212 2213 const struct GNUNET_MESSENGER_Contact *recipient = GNUNET_MESSENGER_get_recipient( 2214 message->context->room, &(message->hash) 2215 ); 2216 2217 if (!recipient) 2218 return NULL; 2219 2220 return handle_get_contact_from_messenger(message->context->handle, recipient); 2221 } 2222 2223 2224 enum GNUNET_GenericReturnValue 2225 GNUNET_CHAT_message_is_sent (const struct GNUNET_CHAT_Message *message) 2226 { 2227 GNUNET_CHAT_VERSION_ASSERT(); 2228 2229 if (!message) 2230 return GNUNET_SYSERR; 2231 2232 if (message->flags & GNUNET_MESSENGER_FLAG_SENT) 2233 return GNUNET_YES; 2234 else 2235 return GNUNET_NO; 2236 } 2237 2238 2239 enum GNUNET_GenericReturnValue 2240 GNUNET_CHAT_message_is_private (const struct GNUNET_CHAT_Message *message) 2241 { 2242 GNUNET_CHAT_VERSION_ASSERT(); 2243 2244 if (!message) 2245 return GNUNET_SYSERR; 2246 2247 if (message->flags & GNUNET_MESSENGER_FLAG_PRIVATE) 2248 return GNUNET_YES; 2249 else 2250 return GNUNET_NO; 2251 } 2252 2253 2254 enum GNUNET_GenericReturnValue 2255 GNUNET_CHAT_message_is_recent (const struct GNUNET_CHAT_Message *message) 2256 { 2257 GNUNET_CHAT_VERSION_ASSERT(); 2258 2259 if (!message) 2260 return GNUNET_SYSERR; 2261 2262 if (message->flags & GNUNET_MESSENGER_FLAG_RECENT) 2263 return GNUNET_YES; 2264 else 2265 return GNUNET_NO; 2266 } 2267 2268 2269 enum GNUNET_GenericReturnValue 2270 GNUNET_CHAT_message_is_update (const struct GNUNET_CHAT_Message *message) 2271 { 2272 GNUNET_CHAT_VERSION_ASSERT(); 2273 2274 if (!message) 2275 return GNUNET_SYSERR; 2276 2277 if (message->flags & GNUNET_MESSENGER_FLAG_UPDATE) 2278 return GNUNET_YES; 2279 else 2280 return GNUNET_NO; 2281 } 2282 2283 2284 enum GNUNET_GenericReturnValue 2285 GNUNET_CHAT_message_is_deleted (const struct GNUNET_CHAT_Message *message) 2286 { 2287 GNUNET_CHAT_VERSION_ASSERT(); 2288 2289 if (!message) 2290 return GNUNET_SYSERR; 2291 2292 if ((GNUNET_CHAT_FLAG_NONE == message->flag) && 2293 ((message->flags & GNUNET_MESSENGER_FLAG_DELETE) || 2294 (!message->msg))) 2295 return GNUNET_YES; 2296 else 2297 return GNUNET_NO; 2298 } 2299 2300 2301 enum GNUNET_GenericReturnValue 2302 GNUNET_CHAT_message_is_tagged (const struct GNUNET_CHAT_Message *message, 2303 const char *tag) 2304 { 2305 GNUNET_CHAT_VERSION_ASSERT(); 2306 2307 if ((!message) || (!(message->context))) 2308 return GNUNET_SYSERR; 2309 2310 const struct GNUNET_CHAT_InternalTagging *tagging = GNUNET_CONTAINER_multihashmap_get( 2311 message->context->taggings, &(message->hash)); 2312 2313 if (!tagging) 2314 return GNUNET_NO; 2315 2316 if (internal_tagging_iterate(tagging, GNUNET_NO, tag, NULL, NULL) > 0) 2317 return GNUNET_YES; 2318 else 2319 return GNUNET_NO; 2320 } 2321 2322 2323 int 2324 GNUNET_CHAT_message_get_read_receipt (struct GNUNET_CHAT_Message *message, 2325 GNUNET_CHAT_MessageReadReceiptCallback callback, 2326 void *cls) 2327 { 2328 GNUNET_CHAT_VERSION_ASSERT(); 2329 2330 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2331 (!(message->context))) 2332 return GNUNET_SYSERR; 2333 2334 struct GNUNET_CHAT_MessageIterateReadReceipts it; 2335 it.message = message; 2336 it.cb = callback; 2337 it.cls = cls; 2338 2339 return GNUNET_MESSENGER_iterate_members( 2340 message->context->room, it_message_iterate_read_receipts, &it 2341 ); 2342 } 2343 2344 2345 const char* 2346 GNUNET_CHAT_message_get_text (const struct GNUNET_CHAT_Message *message) 2347 { 2348 GNUNET_CHAT_VERSION_ASSERT(); 2349 2350 if (!message) 2351 return NULL; 2352 2353 if (GNUNET_CHAT_FLAG_WARNING == message->flag) 2354 return message->warning; 2355 else if (GNUNET_CHAT_FLAG_UPDATE_ACCOUNT == message->flag) 2356 return message->warning; 2357 else if (GNUNET_CHAT_FLAG_ATTRIBUTES == message->flag) 2358 return message->attr; 2359 2360 if (GNUNET_YES != message_has_msg(message)) 2361 return NULL; 2362 2363 if (GNUNET_MESSENGER_KIND_TEXT == message->msg->header.kind) 2364 return message->msg->body.text.text; 2365 else if (GNUNET_MESSENGER_KIND_FILE == message->msg->header.kind) 2366 return message->msg->body.file.name; 2367 else if (GNUNET_MESSENGER_KIND_TAG == message->msg->header.kind) 2368 return message->msg->body.tag.tag; 2369 else 2370 return NULL; 2371 } 2372 2373 2374 void 2375 GNUNET_CHAT_message_set_user_pointer (struct GNUNET_CHAT_Message *message, 2376 void *user_pointer) 2377 { 2378 GNUNET_CHAT_VERSION_ASSERT(); 2379 2380 if (!message) 2381 return; 2382 2383 message->user_pointer = user_pointer; 2384 } 2385 2386 2387 void* 2388 GNUNET_CHAT_message_get_user_pointer (const struct GNUNET_CHAT_Message *message) 2389 { 2390 GNUNET_CHAT_VERSION_ASSERT(); 2391 2392 if (!message) 2393 return NULL; 2394 2395 return message->user_pointer; 2396 } 2397 2398 2399 struct GNUNET_CHAT_Account* 2400 GNUNET_CHAT_message_get_account (const struct GNUNET_CHAT_Message *message) 2401 { 2402 GNUNET_CHAT_VERSION_ASSERT(); 2403 2404 if (!message) 2405 return NULL; 2406 2407 if ((message->context) && (message->context->handle)) 2408 return message->context->handle->current; 2409 else 2410 return message->account; 2411 } 2412 2413 2414 struct GNUNET_CHAT_File* 2415 GNUNET_CHAT_message_get_file (const struct GNUNET_CHAT_Message *message) 2416 { 2417 GNUNET_CHAT_VERSION_ASSERT(); 2418 2419 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2420 (!(message->context))) 2421 return NULL; 2422 2423 if (GNUNET_MESSENGER_KIND_FILE != message->msg->header.kind) 2424 return NULL; 2425 2426 return GNUNET_CONTAINER_multihashmap_get( 2427 message->context->handle->files, 2428 &(message->msg->body.file.hash) 2429 ); 2430 } 2431 2432 2433 struct GNUNET_CHAT_Invitation* 2434 GNUNET_CHAT_message_get_invitation (const struct GNUNET_CHAT_Message *message) 2435 { 2436 GNUNET_CHAT_VERSION_ASSERT(); 2437 2438 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2439 (!(message->context))) 2440 return NULL; 2441 2442 if (GNUNET_MESSENGER_KIND_INVITE != message->msg->header.kind) 2443 return NULL; 2444 2445 return GNUNET_CONTAINER_multihashmap_get( 2446 message->context->invites, 2447 &(message->hash) 2448 ); 2449 } 2450 2451 2452 struct GNUNET_CHAT_Discourse* 2453 GNUNET_CHAT_message_get_discourse (const struct GNUNET_CHAT_Message *message) 2454 { 2455 GNUNET_CHAT_VERSION_ASSERT(); 2456 2457 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2458 (!(message->context)) || (!(message->context->discourses))) 2459 return NULL; 2460 2461 struct GNUNET_CHAT_Discourse *discourse; 2462 2463 if (GNUNET_MESSENGER_KIND_SUBSCRIBTION == message->msg->header.kind) 2464 discourse = GNUNET_CONTAINER_multishortmap_get( 2465 message->context->discourses, 2466 &(message->msg->body.subscription.discourse)); 2467 else if (GNUNET_MESSENGER_KIND_TALK == message->msg->header.kind) 2468 discourse = GNUNET_CONTAINER_multishortmap_get( 2469 message->context->discourses, 2470 &(message->msg->body.talk.discourse)); 2471 else 2472 discourse = NULL; 2473 2474 return discourse; 2475 } 2476 2477 2478 struct GNUNET_CHAT_Message* 2479 GNUNET_CHAT_message_get_target (const struct GNUNET_CHAT_Message *message) 2480 { 2481 GNUNET_CHAT_VERSION_ASSERT(); 2482 2483 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2484 (!(message->context))) 2485 return NULL; 2486 2487 struct GNUNET_CHAT_Message *target; 2488 2489 if (GNUNET_MESSENGER_KIND_DELETION == message->msg->header.kind) 2490 target = GNUNET_CONTAINER_multihashmap_get( 2491 message->context->messages, &(message->msg->body.deletion.hash)); 2492 else if (GNUNET_MESSENGER_KIND_TAG == message->msg->header.kind) 2493 target = GNUNET_CONTAINER_multihashmap_get( 2494 message->context->messages, &(message->msg->body.tag.hash)); 2495 else 2496 target = NULL; 2497 2498 return target; 2499 } 2500 2501 2502 enum GNUNET_GenericReturnValue 2503 GNUNET_CHAT_message_delete (struct GNUNET_CHAT_Message *message, 2504 unsigned int delay) 2505 { 2506 GNUNET_CHAT_VERSION_ASSERT(); 2507 2508 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2509 (!(message->context))) 2510 return GNUNET_SYSERR; 2511 2512 struct GNUNET_TIME_Relative rel = GNUNET_TIME_relative_multiply( 2513 GNUNET_TIME_relative_get_second_(), delay 2514 ); 2515 2516 GNUNET_MESSENGER_delete_message( 2517 message->context->room, 2518 &(message->hash), 2519 rel 2520 ); 2521 2522 return GNUNET_OK; 2523 } 2524 2525 2526 int 2527 GNUNET_CHAT_message_iterate_tags (struct GNUNET_CHAT_Message *message, 2528 GNUNET_CHAT_MessageCallback callback, 2529 void *cls) 2530 { 2531 GNUNET_CHAT_VERSION_ASSERT(); 2532 2533 if ((!message) || (!(message->context))) 2534 return GNUNET_SYSERR; 2535 2536 const struct GNUNET_CHAT_InternalTagging *tagging = GNUNET_CONTAINER_multihashmap_get( 2537 message->context->taggings, &(message->hash)); 2538 2539 if (!tagging) 2540 return 0; 2541 2542 return internal_tagging_iterate(tagging, GNUNET_YES, NULL, callback, cls); 2543 } 2544 2545 2546 uint64_t 2547 GNUNET_CHAT_message_available (const struct GNUNET_CHAT_Message *message) 2548 { 2549 GNUNET_CHAT_VERSION_ASSERT(); 2550 2551 if ((!message) || (GNUNET_YES != message_has_msg(message))) 2552 return 0; 2553 2554 if (GNUNET_MESSENGER_KIND_TALK == message->msg->header.kind) 2555 return message->msg->body.talk.length; 2556 else 2557 return 0; 2558 } 2559 2560 2561 enum GNUNET_GenericReturnValue 2562 GNUNET_CHAT_message_read (const struct GNUNET_CHAT_Message *message, 2563 char *data, 2564 uint64_t size) 2565 { 2566 GNUNET_CHAT_VERSION_ASSERT(); 2567 2568 if ((!message) || (GNUNET_YES != message_has_msg(message))) 2569 return GNUNET_SYSERR; 2570 2571 if (GNUNET_MESSENGER_KIND_TALK != message->msg->header.kind) 2572 return GNUNET_SYSERR; 2573 2574 const uint64_t available = message->msg->body.talk.length; 2575 2576 if (available < size) 2577 return GNUNET_NO; 2578 2579 GNUNET_memcpy( 2580 data, 2581 message->msg->body.talk.data, 2582 size 2583 ); 2584 2585 return GNUNET_OK; 2586 } 2587 2588 2589 enum GNUNET_GenericReturnValue 2590 GNUNET_CHAT_message_feed (const struct GNUNET_CHAT_Message *message, 2591 int fd) 2592 { 2593 GNUNET_CHAT_VERSION_ASSERT(); 2594 2595 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2596 (fd == -1)) 2597 return GNUNET_SYSERR; 2598 2599 if (GNUNET_MESSENGER_KIND_TALK != message->msg->header.kind) 2600 return GNUNET_SYSERR; 2601 2602 if (!(message->msg->body.talk.length)) 2603 return GNUNET_NO; 2604 2605 const ssize_t written = write( 2606 fd, 2607 message->msg->body.talk.data, 2608 message->msg->body.talk.length 2609 ); 2610 2611 if (-1 == written) 2612 return GNUNET_SYSERR; 2613 else if (written != message->msg->body.talk.length) 2614 return GNUNET_NO; 2615 else 2616 return GNUNET_OK; 2617 } 2618 2619 2620 const char* 2621 GNUNET_CHAT_file_get_name (const struct GNUNET_CHAT_File *file) 2622 { 2623 GNUNET_CHAT_VERSION_ASSERT(); 2624 2625 if (!file) 2626 return NULL; 2627 2628 return file->name; 2629 } 2630 2631 2632 const char* 2633 GNUNET_CHAT_file_get_hash (const struct GNUNET_CHAT_File *file) 2634 { 2635 GNUNET_CHAT_VERSION_ASSERT(); 2636 2637 if (!file) 2638 return NULL; 2639 2640 return GNUNET_h2s_full(&(file->hash)); 2641 } 2642 2643 2644 uint64_t 2645 GNUNET_CHAT_file_get_size (const struct GNUNET_CHAT_File *file) 2646 { 2647 GNUNET_CHAT_VERSION_ASSERT(); 2648 2649 if ((!file) || (!(file->uri))) 2650 return 0; 2651 2652 return GNUNET_FS_uri_chk_get_file_size(file->uri); 2653 } 2654 2655 2656 uint64_t 2657 GNUNET_CHAT_file_get_local_size (const struct GNUNET_CHAT_File *file) 2658 { 2659 GNUNET_CHAT_VERSION_ASSERT(); 2660 2661 if (!file) 2662 return 0; 2663 2664 char *filename = handle_create_file_path( 2665 file->handle, &(file->hash) 2666 ); 2667 2668 if (!filename) 2669 return 0; 2670 2671 uint64_t size; 2672 if (GNUNET_OK != GNUNET_DISK_file_size(filename, &size, GNUNET_NO, GNUNET_YES)) 2673 size = 0; 2674 2675 GNUNET_free(filename); 2676 return size; 2677 } 2678 2679 2680 struct GNUNET_CHAT_Uri* 2681 GNUNET_CHAT_file_get_uri (const struct GNUNET_CHAT_File *file) 2682 { 2683 GNUNET_CHAT_VERSION_ASSERT(); 2684 2685 if ((!file) || (!(file->uri))) 2686 return NULL; 2687 2688 return uri_create_file(file->uri); 2689 } 2690 2691 2692 enum GNUNET_GenericReturnValue 2693 GNUNET_CHAT_file_is_uploading (const struct GNUNET_CHAT_File *file) 2694 { 2695 GNUNET_CHAT_VERSION_ASSERT(); 2696 2697 if ((!file) || (0 == (file->status & GNUNET_CHAT_FILE_STATUS_PUBLISH))) 2698 return GNUNET_NO; 2699 else 2700 return GNUNET_YES; 2701 } 2702 2703 2704 enum GNUNET_GenericReturnValue 2705 GNUNET_CHAT_file_is_ready (const struct GNUNET_CHAT_File *file) 2706 { 2707 GNUNET_CHAT_VERSION_ASSERT(); 2708 2709 if ((!file) || (file->status & GNUNET_CHAT_FILE_STATUS_MASK)) 2710 return GNUNET_NO; 2711 2712 const uint64_t size = GNUNET_CHAT_file_get_size(file); 2713 const uint64_t local_size = GNUNET_CHAT_file_get_local_size(file); 2714 2715 if (size != local_size) 2716 return GNUNET_NO; 2717 else 2718 return GNUNET_YES; 2719 } 2720 2721 2722 const char* 2723 GNUNET_CHAT_file_open_preview (struct GNUNET_CHAT_File *file) 2724 { 2725 GNUNET_CHAT_VERSION_ASSERT(); 2726 2727 if (!file) 2728 return NULL; 2729 2730 if (file->preview) 2731 return file->preview; 2732 2733 char *filename = handle_create_file_path( 2734 file->handle, &(file->hash) 2735 ); 2736 2737 if (!filename) 2738 return NULL; 2739 2740 if (GNUNET_YES != GNUNET_DISK_file_test(filename)) 2741 goto free_filename; 2742 2743 if (!(file->key)) 2744 { 2745 file->preview = filename; 2746 return file->preview; 2747 } 2748 2749 file->preview = GNUNET_DISK_mktemp( 2750 file->name? file->name : "" 2751 ); 2752 2753 if (!(file->preview)) 2754 goto free_filename; 2755 2756 remove(file->preview); 2757 2758 if ((GNUNET_OK != GNUNET_DISK_file_copy(filename, file->preview)) || 2759 (GNUNET_OK != util_decrypt_file(file->preview, 2760 &(file->hash), file->key))) 2761 { 2762 GNUNET_free(file->preview); 2763 file->preview = NULL; 2764 } 2765 2766 free_filename: 2767 GNUNET_free(filename); 2768 return file->preview; 2769 } 2770 2771 2772 void 2773 GNUNET_CHAT_file_close_preview (struct GNUNET_CHAT_File *file) 2774 { 2775 GNUNET_CHAT_VERSION_ASSERT(); 2776 2777 if ((!file) || (!(file->preview))) 2778 return; 2779 2780 if (!(file->key)) 2781 goto skip_filename; 2782 2783 char *filename = handle_create_file_path( 2784 file->handle, &(file->hash) 2785 ); 2786 2787 if (!filename) 2788 goto skip_filename; 2789 2790 if (0 != strcmp(filename, file->preview)) 2791 remove(file->preview); 2792 2793 GNUNET_free(filename); 2794 2795 skip_filename: 2796 GNUNET_free(file->preview); 2797 file->preview = NULL; 2798 } 2799 2800 2801 void 2802 GNUNET_CHAT_file_set_user_pointer (struct GNUNET_CHAT_File *file, 2803 void *user_pointer) 2804 { 2805 GNUNET_CHAT_VERSION_ASSERT(); 2806 2807 if (!file) 2808 return; 2809 2810 file->user_pointer = user_pointer; 2811 } 2812 2813 2814 void* 2815 GNUNET_CHAT_file_get_user_pointer (const struct GNUNET_CHAT_File *file) 2816 { 2817 GNUNET_CHAT_VERSION_ASSERT(); 2818 2819 if (!file) 2820 return NULL; 2821 2822 return file->user_pointer; 2823 } 2824 2825 2826 enum GNUNET_GenericReturnValue 2827 GNUNET_CHAT_file_is_downloading (const struct GNUNET_CHAT_File *file) 2828 { 2829 GNUNET_CHAT_VERSION_ASSERT(); 2830 2831 if ((!file) || (0 == (file->status & GNUNET_CHAT_FILE_STATUS_DOWNLOAD))) 2832 return GNUNET_NO; 2833 else 2834 return GNUNET_YES; 2835 } 2836 2837 2838 enum GNUNET_GenericReturnValue 2839 GNUNET_CHAT_file_start_download (struct GNUNET_CHAT_File *file, 2840 GNUNET_CHAT_FileDownloadCallback callback, 2841 void *cls) 2842 { 2843 GNUNET_CHAT_VERSION_ASSERT(); 2844 2845 if ((!file) || (!(file->uri))) 2846 return GNUNET_SYSERR; 2847 2848 if (file->download) 2849 { 2850 file_bind_downlaod(file, callback, cls); 2851 2852 GNUNET_FS_download_resume(file->download); 2853 return GNUNET_OK; 2854 } 2855 2856 char *filename = handle_create_file_path( 2857 file->handle, &(file->hash) 2858 ); 2859 2860 if (!filename) 2861 return GNUNET_SYSERR; 2862 2863 const uint64_t size = GNUNET_FS_uri_chk_get_file_size(file->uri); 2864 2865 uint64_t offset; 2866 if (GNUNET_OK != GNUNET_DISK_file_size(filename, &offset, 2867 GNUNET_NO, GNUNET_YES)) 2868 offset = 0; 2869 2870 if (offset >= size) 2871 { 2872 if (callback) 2873 callback(cls, file, size, size); 2874 2875 goto free_filename; 2876 } 2877 2878 file_bind_downlaod(file, callback, cls); 2879 2880 const uint64_t remaining = (size - offset); 2881 2882 file->download = GNUNET_FS_download_start( 2883 file->handle->fs, 2884 file->uri, 2885 file->meta, 2886 filename, 2887 NULL, 2888 offset, 2889 remaining, 2890 1, 2891 GNUNET_FS_DOWNLOAD_OPTION_NONE, 2892 file, 2893 NULL 2894 ); 2895 2896 if (file->download) 2897 file->status |= GNUNET_CHAT_FILE_STATUS_DOWNLOAD; 2898 2899 free_filename: 2900 GNUNET_free(filename); 2901 return GNUNET_OK; 2902 } 2903 2904 2905 enum GNUNET_GenericReturnValue 2906 GNUNET_CHAT_file_pause_download (struct GNUNET_CHAT_File *file) 2907 { 2908 GNUNET_CHAT_VERSION_ASSERT(); 2909 2910 if (!file) 2911 return GNUNET_SYSERR; 2912 2913 GNUNET_FS_download_suspend(file->download); 2914 return GNUNET_OK; 2915 } 2916 2917 2918 enum GNUNET_GenericReturnValue 2919 GNUNET_CHAT_file_resume_download (struct GNUNET_CHAT_File *file) 2920 { 2921 GNUNET_CHAT_VERSION_ASSERT(); 2922 2923 if (!file) 2924 return GNUNET_SYSERR; 2925 2926 GNUNET_FS_download_resume(file->download); 2927 return GNUNET_OK; 2928 } 2929 2930 2931 enum GNUNET_GenericReturnValue 2932 GNUNET_CHAT_file_stop_download (struct GNUNET_CHAT_File *file) 2933 { 2934 GNUNET_CHAT_VERSION_ASSERT(); 2935 2936 if (!file) 2937 return GNUNET_SYSERR; 2938 2939 GNUNET_FS_download_stop(file->download, GNUNET_YES); 2940 file->download = NULL; 2941 return GNUNET_OK; 2942 } 2943 2944 2945 enum GNUNET_GenericReturnValue 2946 GNUNET_CHAT_file_is_unindexing (const struct GNUNET_CHAT_File *file) 2947 { 2948 GNUNET_CHAT_VERSION_ASSERT(); 2949 2950 if ((!file) || (0 == (file->status & GNUNET_CHAT_FILE_STATUS_UNINDEX))) 2951 return GNUNET_NO; 2952 else 2953 return GNUNET_YES; 2954 } 2955 2956 2957 enum GNUNET_GenericReturnValue 2958 GNUNET_CHAT_file_unindex (struct GNUNET_CHAT_File *file, 2959 GNUNET_CHAT_FileUnindexCallback callback, 2960 void *cls) 2961 { 2962 GNUNET_CHAT_VERSION_ASSERT(); 2963 2964 if (!file) 2965 return GNUNET_SYSERR; 2966 2967 if (file->publish) 2968 { 2969 GNUNET_FS_publish_stop(file->publish); 2970 file->publish = NULL; 2971 return GNUNET_OK; 2972 } 2973 2974 file_bind_unindex(file, callback, cls); 2975 2976 if (file->unindex) 2977 return GNUNET_OK; 2978 2979 char *filename = handle_create_file_path( 2980 file->handle, &(file->hash) 2981 ); 2982 2983 if (!filename) 2984 return GNUNET_SYSERR; 2985 2986 file->unindex = GNUNET_FS_unindex_start( 2987 file->handle->fs, filename, file 2988 ); 2989 2990 if (file->unindex) 2991 file->status |= GNUNET_CHAT_FILE_STATUS_UNINDEX; 2992 2993 GNUNET_free(filename); 2994 return GNUNET_OK; 2995 } 2996 2997 2998 void 2999 GNUNET_CHAT_invitation_accept (struct GNUNET_CHAT_Invitation *invitation) 3000 { 3001 GNUNET_CHAT_VERSION_ASSERT(); 3002 3003 if (!invitation) 3004 return; 3005 3006 struct GNUNET_CHAT_Handle *handle; 3007 handle = invitation->context->handle; 3008 3009 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains( 3010 handle->contexts, &(invitation->key.hash))) 3011 return; 3012 3013 struct GNUNET_PeerIdentity door; 3014 GNUNET_PEER_resolve(invitation->door, &door); 3015 3016 struct GNUNET_MESSENGER_Room *room; 3017 room = GNUNET_MESSENGER_enter_room( 3018 invitation->context->handle->messenger, 3019 &door, &(invitation->key) 3020 ); 3021 3022 if (!room) 3023 return; 3024 3025 struct GNUNET_CHAT_Context *context; 3026 context = context_create_from_room(handle, room); 3027 3028 if (!context) 3029 return; 3030 3031 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 3032 handle->contexts, &(invitation->key.hash), context, 3033 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 3034 goto destroy_context; 3035 3036 if (GNUNET_CHAT_CONTEXT_TYPE_GROUP != context->type) 3037 { 3038 context_write_records(context); 3039 return; 3040 } 3041 3042 struct GNUNET_CHAT_Group *group; 3043 group = group_create_from_context(handle, context); 3044 3045 if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put( 3046 handle->groups, &(invitation->key.hash), group, 3047 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 3048 { 3049 context_write_records(context); 3050 return; 3051 } 3052 3053 group_destroy(group); 3054 3055 GNUNET_CONTAINER_multihashmap_remove( 3056 handle->contexts, &(invitation->key.hash), context); 3057 3058 destroy_context: 3059 context_destroy(context); 3060 } 3061 3062 3063 void 3064 GNUNET_CHAT_invitation_reject (struct GNUNET_CHAT_Invitation *invitation) 3065 { 3066 GNUNET_CHAT_VERSION_ASSERT(); 3067 3068 if (!invitation) 3069 return; 3070 3071 const struct GNUNET_MESSENGER_Contact *sender = GNUNET_MESSENGER_get_sender( 3072 invitation->context->room, &(invitation->hash) 3073 ); 3074 3075 if (!sender) 3076 return; 3077 3078 struct GNUNET_MESSENGER_Message msg; 3079 memset(&msg, 0, sizeof(msg)); 3080 3081 msg.header.kind = GNUNET_MESSENGER_KIND_TAG; 3082 GNUNET_memcpy(&(msg.body.tag.hash), &(invitation->hash), 3083 sizeof(struct GNUNET_HashCode)); 3084 msg.body.tag.tag = NULL; 3085 3086 GNUNET_MESSENGER_send_message(invitation->context->room, &msg, sender); 3087 } 3088 3089 3090 enum GNUNET_GenericReturnValue 3091 GNUNET_CHAT_invitation_is_accepted (const struct GNUNET_CHAT_Invitation *invitation) 3092 { 3093 GNUNET_CHAT_VERSION_ASSERT(); 3094 3095 if (!invitation) 3096 return GNUNET_NO; 3097 3098 return GNUNET_CONTAINER_multihashmap_contains( 3099 invitation->context->handle->contexts, 3100 &(invitation->key.hash) 3101 ); 3102 } 3103 3104 3105 enum GNUNET_GenericReturnValue 3106 GNUNET_CHAT_invitation_is_rejected (const struct GNUNET_CHAT_Invitation *invitation) 3107 { 3108 GNUNET_CHAT_VERSION_ASSERT(); 3109 3110 if (!invitation) 3111 return GNUNET_NO; 3112 3113 const struct GNUNET_CHAT_InternalTagging *tagging = GNUNET_CONTAINER_multihashmap_get( 3114 invitation->context->taggings, &(invitation->hash)); 3115 3116 if (!tagging) 3117 return GNUNET_NO; 3118 3119 if (internal_tagging_iterate(tagging, GNUNET_NO, NULL, NULL, NULL) > 0) 3120 return GNUNET_YES; 3121 else 3122 return GNUNET_NO; 3123 } 3124 3125 3126 enum GNUNET_GenericReturnValue 3127 GNUNET_CHAT_invitation_is_direct (const struct GNUNET_CHAT_Invitation *invitation) 3128 { 3129 GNUNET_CHAT_VERSION_ASSERT(); 3130 3131 if ((invitation->key.code.public_bit) || 3132 (invitation->key.code.group_bit) || 3133 (invitation->key.code.feed_bit)) 3134 return GNUNET_NO; 3135 else 3136 return GNUNET_YES; 3137 } 3138 3139 3140 const struct GNUNET_CHAT_DiscourseId* 3141 GNUNET_CHAT_discourse_get_id (const struct GNUNET_CHAT_Discourse *discourse) 3142 { 3143 GNUNET_CHAT_VERSION_ASSERT(); 3144 3145 if (!discourse) 3146 return NULL; 3147 3148 return &(discourse->id); 3149 } 3150 3151 3152 enum GNUNET_GenericReturnValue 3153 GNUNET_CHAT_discourse_is_open (const struct GNUNET_CHAT_Discourse *discourse) 3154 { 3155 GNUNET_CHAT_VERSION_ASSERT(); 3156 3157 if (!discourse) 3158 return GNUNET_SYSERR; 3159 3160 struct GNUNET_CHAT_DiscourseSubscription *sub; 3161 for (sub = discourse->head; sub; sub = sub->next) 3162 { 3163 if (GNUNET_TIME_absolute_cmp(sub->end, <, GNUNET_TIME_absolute_get())) 3164 continue; 3165 3166 if (GNUNET_YES == sub->contact->owned) 3167 return GNUNET_YES; 3168 } 3169 3170 return GNUNET_NO; 3171 } 3172 3173 3174 void 3175 GNUNET_CHAT_discourse_set_user_pointer (struct GNUNET_CHAT_Discourse *discourse, 3176 void *user_pointer) 3177 { 3178 GNUNET_CHAT_VERSION_ASSERT(); 3179 3180 if (!discourse) 3181 return; 3182 3183 discourse->user_pointer = user_pointer; 3184 } 3185 3186 3187 void* 3188 GNUNET_CHAT_discourse_get_user_pointer (const struct GNUNET_CHAT_Discourse *discourse) 3189 { 3190 GNUNET_CHAT_VERSION_ASSERT(); 3191 3192 if (!discourse) 3193 return NULL; 3194 3195 return discourse->user_pointer; 3196 } 3197 3198 3199 void 3200 GNUNET_CHAT_discourse_close (struct GNUNET_CHAT_Discourse *discourse) 3201 { 3202 GNUNET_CHAT_VERSION_ASSERT(); 3203 3204 if ((!discourse) || (!(discourse->context)) || (!(discourse->context->room))) 3205 return; 3206 3207 struct GNUNET_MESSENGER_Message msg; 3208 memset(&msg, 0, sizeof(msg)); 3209 3210 msg.header.kind = GNUNET_MESSENGER_KIND_SUBSCRIBTION; 3211 3212 util_shorthash_from_discourse_id( 3213 &(discourse->id), 3214 &(msg.body.subscription.discourse) 3215 ); 3216 3217 msg.body.subscription.time = GNUNET_TIME_relative_hton(GNUNET_TIME_relative_get_zero_()); 3218 msg.body.subscription.flags = GNUNET_MESSENGER_FLAG_SUBSCRIPTION_UNSUBSCRIBE; 3219 3220 GNUNET_MESSENGER_send_message( 3221 discourse->context->room, 3222 &msg, 3223 NULL 3224 ); 3225 } 3226 3227 3228 enum GNUNET_GenericReturnValue 3229 GNUNET_CHAT_discourse_write (struct GNUNET_CHAT_Discourse *discourse, 3230 const char *data, 3231 uint64_t size) 3232 { 3233 GNUNET_CHAT_VERSION_ASSERT(); 3234 3235 if ((!discourse) || (!data) || (!(discourse->context)) || 3236 (!(discourse->context->room))) 3237 return GNUNET_SYSERR; 3238 3239 static const uint64_t max_size = (uint16_t) ( 3240 GNUNET_MAX_MESSAGE_SIZE - GNUNET_MIN_MESSAGE_SIZE - 3241 sizeof (struct GNUNET_MESSENGER_Message) 3242 ); 3243 3244 struct GNUNET_MESSENGER_Message msg; 3245 memset(&msg, 0, sizeof(msg)); 3246 3247 msg.header.kind = GNUNET_MESSENGER_KIND_TALK; 3248 msg.body.talk.data = GNUNET_malloc(size > max_size? max_size : size); 3249 3250 util_shorthash_from_discourse_id( 3251 &(discourse->id), 3252 &(msg.body.talk.discourse) 3253 ); 3254 3255 while (size > 0) 3256 { 3257 msg.body.talk.length = (uint16_t) (size > max_size? max_size : size); 3258 3259 GNUNET_memcpy( 3260 msg.body.talk.data, 3261 data, 3262 msg.body.talk.length 3263 ); 3264 3265 size -= msg.body.talk.length; 3266 data += msg.body.talk.length; 3267 3268 GNUNET_MESSENGER_send_message(discourse->context->room, &msg, NULL); 3269 } 3270 3271 GNUNET_free(msg.body.talk.data); 3272 return GNUNET_OK; 3273 } 3274 3275 3276 int 3277 GNUNET_CHAT_discourse_get_fd (const struct GNUNET_CHAT_Discourse *discourse) 3278 { 3279 GNUNET_CHAT_VERSION_ASSERT(); 3280 3281 if (! discourse) 3282 return GNUNET_SYSERR; 3283 3284 return discourse->pipe[1]; 3285 } 3286 3287 3288 int 3289 GNUNET_CHAT_discourse_iterate_contacts (struct GNUNET_CHAT_Discourse *discourse, 3290 GNUNET_CHAT_DiscourseContactCallback callback, 3291 void *cls) 3292 { 3293 GNUNET_CHAT_VERSION_ASSERT(); 3294 3295 if (! discourse) 3296 return GNUNET_SYSERR; 3297 3298 int iterations = 0; 3299 3300 struct GNUNET_CHAT_DiscourseSubscription *sub; 3301 for (sub = discourse->head; sub; sub = sub->next) 3302 { 3303 if (GNUNET_TIME_absolute_cmp(sub->end, <, GNUNET_TIME_absolute_get())) 3304 continue; 3305 3306 if (callback) 3307 callback(cls, discourse, sub->contact); 3308 3309 iterations++; 3310 } 3311 3312 return iterations; 3313 } 3314 3315 enum GNUNET_GenericReturnValue 3316 GNUNET_CHAT_generate_secret (char *secret, 3317 uint32_t secret_len) 3318 { 3319 GNUNET_CHAT_VERSION_ASSERT(); 3320 3321 if (secret_len <= 0) 3322 return GNUNET_SYSERR; 3323 3324 const uint32_t requested = secret_len * 5 / 8 + 1; 3325 const uint32_t size = ((requested*8) + (((requested*8) % 5) > 0 ? 5 - ((requested*8) % 5) : 0)) / 5; 3326 3327 char *raw_secret = GNUNET_malloc(requested); 3328 char *buf; 3329 3330 if (!raw_secret) 3331 return GNUNET_SYSERR; 3332 3333 if (size > secret_len) 3334 { 3335 buf = GNUNET_malloc(size); 3336 3337 if (!buf) 3338 { 3339 GNUNET_free(raw_secret); 3340 return GNUNET_SYSERR; 3341 } 3342 } 3343 else 3344 buf = secret; 3345 3346 GNUNET_CRYPTO_random_block( 3347 GNUNET_CRYPTO_QUALITY_STRONG, 3348 raw_secret, 3349 requested 3350 ); 3351 3352 enum GNUNET_GenericReturnValue result; 3353 result = GNUNET_STRINGS_data_to_string( 3354 raw_secret, 3355 requested, 3356 buf, 3357 size 3358 ) == NULL? GNUNET_SYSERR : GNUNET_OK; 3359 3360 GNUNET_CRYPTO_zero_keys(raw_secret, requested); 3361 GNUNET_free(raw_secret); 3362 3363 if (buf != secret) 3364 { 3365 GNUNET_memcpy(secret, buf, secret_len); 3366 GNUNET_CRYPTO_zero_keys(buf, size); 3367 GNUNET_free(buf); 3368 } 3369 3370 return result; 3371 }