gnunet_chat_lib.c (74464B)
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 const struct GNUNET_PeerIdentity *pid = context->handle->pid; 1493 1494 if (!pid) 1495 return GNUNET_SYSERR; 1496 1497 union GNUNET_MESSENGER_RoomKey key; 1498 GNUNET_memcpy( 1499 &(key.hash), 1500 GNUNET_MESSENGER_room_get_key(group->context->room), 1501 sizeof(key.hash) 1502 ); 1503 1504 handle_send_room_name(group->handle, GNUNET_MESSENGER_open_room( 1505 group->handle->messenger, &key 1506 )); 1507 1508 struct GNUNET_MESSENGER_Message msg; 1509 memset(&msg, 0, sizeof(msg)); 1510 1511 msg.header.kind = GNUNET_MESSENGER_KIND_INVITE; 1512 GNUNET_memcpy(&(msg.body.invite.door), pid, sizeof(msg.body.invite.door)); 1513 GNUNET_memcpy(&(msg.body.invite.key), &key, sizeof(msg.body.invite.key)); 1514 1515 GNUNET_MESSENGER_send_message(context->room, &msg, contact->member); 1516 return GNUNET_OK; 1517 } 1518 1519 1520 int 1521 GNUNET_CHAT_group_iterate_contacts (struct GNUNET_CHAT_Group *group, 1522 GNUNET_CHAT_GroupContactCallback callback, 1523 void *cls) 1524 { 1525 GNUNET_CHAT_VERSION_ASSERT(); 1526 1527 if (!group) 1528 return GNUNET_SYSERR; 1529 1530 struct GNUNET_CHAT_GroupIterateContacts it; 1531 it.group = group; 1532 it.cb = callback; 1533 it.cls = cls; 1534 1535 return GNUNET_MESSENGER_iterate_members( 1536 group->context->room, it_group_iterate_contacts, &it 1537 ); 1538 } 1539 1540 1541 void 1542 GNUNET_CHAT_member_set_user_pointer (struct GNUNET_CHAT_Group *group, 1543 const struct GNUNET_CHAT_Contact *member, 1544 void *user_pointer) 1545 { 1546 GNUNET_CHAT_VERSION_ASSERT(); 1547 1548 if ((!group) || (!(group->context)) || (!member)) 1549 return; 1550 1551 struct GNUNET_ShortHashCode hash; 1552 util_shorthash_from_member(member->member, &hash); 1553 1554 GNUNET_CONTAINER_multishortmap_put( 1555 group->context->member_pointers, 1556 &hash, 1557 user_pointer, 1558 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE 1559 ); 1560 } 1561 1562 1563 void* 1564 GNUNET_CHAT_member_get_user_pointer (const struct GNUNET_CHAT_Group *group, 1565 const struct GNUNET_CHAT_Contact *member) 1566 { 1567 GNUNET_CHAT_VERSION_ASSERT(); 1568 1569 if ((!group) || (!(group->context)) || (!member)) 1570 return NULL; 1571 1572 struct GNUNET_ShortHashCode hash; 1573 util_shorthash_from_member(member->member, &hash); 1574 1575 return GNUNET_CONTAINER_multishortmap_get( 1576 group->context->member_pointers, 1577 &hash 1578 ); 1579 } 1580 1581 1582 struct GNUNET_CHAT_Context* 1583 GNUNET_CHAT_group_get_context (struct GNUNET_CHAT_Group *group) 1584 { 1585 GNUNET_CHAT_VERSION_ASSERT(); 1586 1587 if (!group) 1588 return NULL; 1589 1590 return group->context; 1591 } 1592 1593 1594 enum GNUNET_GenericReturnValue 1595 GNUNET_CHAT_context_get_status (struct GNUNET_CHAT_Context *context) 1596 { 1597 GNUNET_CHAT_VERSION_ASSERT(); 1598 1599 if ((!context) || (!(context->room))) 1600 return GNUNET_SYSERR; 1601 1602 switch (context->type) { 1603 case GNUNET_CHAT_CONTEXT_TYPE_CONTACT: 1604 { 1605 const struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_context_get_contact( 1606 context 1607 ); 1608 1609 return contact? GNUNET_OK : GNUNET_NO; 1610 } 1611 case GNUNET_CHAT_CONTEXT_TYPE_GROUP: 1612 return GNUNET_OK; 1613 default: 1614 return GNUNET_NO; 1615 } 1616 } 1617 1618 1619 enum GNUNET_GenericReturnValue 1620 GNUNET_CHAT_context_request (struct GNUNET_CHAT_Context *context) 1621 { 1622 GNUNET_CHAT_VERSION_ASSERT(); 1623 1624 if (!context) 1625 return GNUNET_SYSERR; 1626 else if (context->room) 1627 return GNUNET_OK; 1628 1629 struct GNUNET_CHAT_Handle *handle = context->handle; 1630 1631 if ((!handle) || (!(context->contact))) 1632 return GNUNET_SYSERR; 1633 1634 struct GNUNET_CHAT_Contact *contact = handle_get_contact_from_messenger( 1635 handle, context->contact 1636 ); 1637 1638 if (!contact) 1639 return GNUNET_SYSERR; 1640 1641 enum GNUNET_GenericReturnValue owned = GNUNET_CHAT_contact_is_owned( 1642 contact 1643 ); 1644 1645 context->type = GNUNET_CHAT_CONTEXT_TYPE_CONTACT; 1646 1647 struct GNUNET_CHAT_Context *other = contact_find_context( 1648 contact, GNUNET_YES 1649 ); 1650 1651 if (!other) 1652 return GNUNET_SYSERR; 1653 1654 union GNUNET_MESSENGER_RoomKey key; 1655 GNUNET_MESSENGER_create_room_key( 1656 &key, 1657 NULL, 1658 GNUNET_YES == owned? GNUNET_YES : GNUNET_NO, 1659 GNUNET_NO, 1660 GNUNET_YES == owned? GNUNET_YES : GNUNET_NO 1661 ); 1662 1663 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains( 1664 handle->contexts, &(key.hash))) 1665 return GNUNET_SYSERR; 1666 1667 const struct GNUNET_PeerIdentity *pid = handle->pid; 1668 1669 if (!pid) 1670 return GNUNET_SYSERR; 1671 1672 struct GNUNET_MESSENGER_Room *room; 1673 if (GNUNET_YES == owned) 1674 { 1675 room = GNUNET_MESSENGER_enter_room( 1676 handle->messenger, 1677 pid, 1678 &key 1679 ); 1680 } 1681 else 1682 room = GNUNET_MESSENGER_open_room( 1683 handle->messenger, &key 1684 ); 1685 1686 if (!room) 1687 return GNUNET_SYSERR; 1688 1689 context_update_room(context, room, GNUNET_YES); 1690 1691 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 1692 handle->contexts, &(key.hash), context, 1693 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 1694 { 1695 context_update_room(context, NULL, GNUNET_YES); 1696 return GNUNET_SYSERR; 1697 } 1698 1699 if (GNUNET_YES != owned) 1700 { 1701 struct GNUNET_MESSENGER_Message msg; 1702 memset(&msg, 0, sizeof(msg)); 1703 1704 msg.header.kind = GNUNET_MESSENGER_KIND_INVITE; 1705 GNUNET_memcpy(&(msg.body.invite.door), pid, sizeof(msg.body.invite.door)); 1706 GNUNET_memcpy(&(msg.body.invite.key), &key, sizeof(msg.body.invite.key)); 1707 1708 GNUNET_MESSENGER_send_message(other->room, &msg, context->contact); 1709 } 1710 1711 return GNUNET_OK; 1712 } 1713 1714 1715 struct GNUNET_CHAT_Contact* 1716 GNUNET_CHAT_context_get_contact (struct GNUNET_CHAT_Context *context) 1717 { 1718 GNUNET_CHAT_VERSION_ASSERT(); 1719 1720 if ((!context) || (GNUNET_CHAT_CONTEXT_TYPE_CONTACT != context->type)) 1721 return NULL; 1722 1723 if (context->contact) 1724 return handle_get_contact_from_messenger(context->handle, context->contact); 1725 1726 struct GNUNET_MESSENGER_Room *room = context->room; 1727 struct GNUNET_CHAT_RoomFindContact find; 1728 union GNUNET_MESSENGER_RoomKey key; 1729 1730 GNUNET_memcpy(&(key.hash), GNUNET_MESSENGER_room_get_key(room), sizeof(key.hash)); 1731 1732 if (key.code.group_bit) 1733 return NULL; 1734 1735 if (! key.code.feed_bit) 1736 find.ignore_key = GNUNET_MESSENGER_get_key(context->handle->messenger); 1737 else 1738 find.ignore_key = NULL; 1739 1740 find.contact = NULL; 1741 1742 int member_count = GNUNET_MESSENGER_iterate_members( 1743 room, 1744 it_room_find_contact, 1745 &find 1746 ); 1747 1748 if ((!find.contact) || (member_count > 2)) 1749 return NULL; 1750 1751 return handle_get_contact_from_messenger(context->handle, find.contact); 1752 } 1753 1754 1755 struct GNUNET_CHAT_Group* 1756 GNUNET_CHAT_context_get_group (struct GNUNET_CHAT_Context *context) 1757 { 1758 GNUNET_CHAT_VERSION_ASSERT(); 1759 1760 if ((!context) || (GNUNET_CHAT_CONTEXT_TYPE_GROUP != context->type)) 1761 return NULL; 1762 1763 if (!(context->room)) 1764 return NULL; 1765 1766 return handle_get_group_from_messenger(context->handle, context->room); 1767 } 1768 1769 1770 void 1771 GNUNET_CHAT_context_set_user_pointer (struct GNUNET_CHAT_Context *context, 1772 void *user_pointer) 1773 { 1774 GNUNET_CHAT_VERSION_ASSERT(); 1775 1776 if (!context) 1777 return; 1778 1779 context->user_pointer = user_pointer; 1780 } 1781 1782 1783 void* 1784 GNUNET_CHAT_context_get_user_pointer (const struct GNUNET_CHAT_Context *context) 1785 { 1786 GNUNET_CHAT_VERSION_ASSERT(); 1787 1788 if (!context) 1789 return NULL; 1790 1791 return context->user_pointer; 1792 } 1793 1794 1795 enum GNUNET_GenericReturnValue 1796 GNUNET_CHAT_context_send_text (struct GNUNET_CHAT_Context *context, 1797 const char *text) 1798 { 1799 GNUNET_CHAT_VERSION_ASSERT(); 1800 1801 if ((!context) || (!text) || (!(context->room))) 1802 return GNUNET_SYSERR; 1803 1804 struct GNUNET_MESSENGER_Message msg; 1805 memset(&msg, 0, sizeof(msg)); 1806 1807 msg.header.kind = GNUNET_MESSENGER_KIND_TEXT; 1808 msg.body.text.text = GNUNET_strdup(text); 1809 1810 GNUNET_MESSENGER_send_message(context->room, &msg, NULL); 1811 1812 GNUNET_free(msg.body.text.text); 1813 return GNUNET_OK; 1814 } 1815 1816 1817 enum GNUNET_GenericReturnValue 1818 GNUNET_CHAT_context_send_read_receipt (struct GNUNET_CHAT_Context *context, 1819 struct GNUNET_CHAT_Message *message) 1820 { 1821 GNUNET_CHAT_VERSION_ASSERT(); 1822 1823 if ((!context) || (!(context->room))) 1824 return GNUNET_SYSERR; 1825 1826 char zero = '\0'; 1827 struct GNUNET_MESSENGER_Message msg; 1828 memset(&msg, 0, sizeof(msg)); 1829 1830 msg.header.kind = GNUNET_MESSENGER_KIND_TEXT; 1831 msg.body.text.text = &zero; 1832 1833 const struct GNUNET_MESSENGER_Contact *receiver = NULL; 1834 1835 if (!message) 1836 goto skip_filter; 1837 1838 if (GNUNET_CHAT_FLAG_NONE != message->flag) 1839 return GNUNET_SYSERR; 1840 1841 if (message->flags & GNUNET_MESSENGER_FLAG_SENT) 1842 return GNUNET_OK; 1843 1844 if (message->flags & GNUNET_MESSENGER_FLAG_PRIVATE) 1845 { 1846 receiver = GNUNET_MESSENGER_get_sender(context->room, &(message->hash)); 1847 1848 if (!receiver) 1849 return GNUNET_SYSERR; 1850 } 1851 1852 if ((GNUNET_YES != message_has_msg(message)) || 1853 (GNUNET_MESSENGER_KIND_TEXT != message->msg->header.kind)) 1854 goto skip_filter; 1855 1856 if ((!(message->msg->body.text.text)) || 1857 (!(message->msg->body.text.text[0]))) 1858 return GNUNET_SYSERR; 1859 1860 skip_filter: 1861 GNUNET_MESSENGER_send_message(context->room, &msg, receiver); 1862 return GNUNET_OK; 1863 } 1864 1865 1866 struct GNUNET_CHAT_File* 1867 GNUNET_CHAT_context_send_file (struct GNUNET_CHAT_Context *context, 1868 const char *path, 1869 GNUNET_CHAT_FileUploadCallback callback, 1870 void *cls) 1871 { 1872 GNUNET_CHAT_VERSION_ASSERT(); 1873 1874 if ((!context) || (!path) || (!(context->room))) 1875 return NULL; 1876 1877 struct GNUNET_HashCode hash; 1878 if (GNUNET_OK != util_hash_file(path, &hash)) 1879 return NULL; 1880 1881 char *filename = handle_create_file_path( 1882 context->handle, &hash 1883 ); 1884 1885 if (!filename) 1886 return NULL; 1887 1888 struct GNUNET_CHAT_File *file = GNUNET_CONTAINER_multihashmap_get( 1889 context->handle->files, 1890 &hash 1891 ); 1892 1893 if (file) 1894 goto file_binding; 1895 1896 if ((GNUNET_YES == GNUNET_DISK_file_test(filename)) || 1897 (GNUNET_OK != GNUNET_DISK_directory_create_for_file(filename)) || 1898 (GNUNET_OK != GNUNET_DISK_file_copy(path, filename))) 1899 { 1900 GNUNET_free(filename); 1901 return NULL; 1902 } 1903 1904 struct GNUNET_CRYPTO_SymmetricSessionKey key; 1905 GNUNET_CRYPTO_symmetric_create_session_key(&key); 1906 1907 if (GNUNET_OK != util_encrypt_file(filename, &hash, &key)) 1908 { 1909 GNUNET_free(filename); 1910 return NULL; 1911 } 1912 1913 char* p = GNUNET_strdup(path); 1914 1915 file = file_create_from_disk( 1916 context->handle, 1917 basename(p), 1918 &hash, 1919 &key 1920 ); 1921 1922 GNUNET_free(p); 1923 1924 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 1925 context->handle->files, &hash, file, 1926 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 1927 { 1928 file_destroy(file); 1929 GNUNET_free(filename); 1930 return NULL; 1931 } 1932 1933 struct GNUNET_FS_BlockOptions bo; 1934 1935 bo.anonymity_level = block_anonymity_level; 1936 bo.content_priority = block_content_priority; 1937 bo.replication_level = block_replication_level; 1938 bo.expiration_time = GNUNET_TIME_absolute_get_forever_(); 1939 1940 struct GNUNET_FS_FileInformation* fi = GNUNET_FS_file_information_create_from_file( 1941 context->handle->fs, 1942 file, 1943 filename, 1944 NULL, 1945 file->meta, 1946 GNUNET_YES, 1947 &bo 1948 ); 1949 1950 file->publish = GNUNET_FS_publish_start( 1951 context->handle->fs, fi, 1952 NULL, NULL, NULL, 1953 GNUNET_FS_PUBLISH_OPTION_NONE 1954 ); 1955 1956 if (file->publish) 1957 file->status |= GNUNET_CHAT_FILE_STATUS_PUBLISH; 1958 1959 GNUNET_free(filename); 1960 1961 file_binding: 1962 file_bind_upload(file, context, callback, cls); 1963 return file; 1964 } 1965 1966 1967 enum GNUNET_GenericReturnValue 1968 GNUNET_CHAT_context_share_file (struct GNUNET_CHAT_Context *context, 1969 struct GNUNET_CHAT_File *file) 1970 { 1971 GNUNET_CHAT_VERSION_ASSERT(); 1972 1973 if ((!context) || (!file) || 1974 (!(file->name)) || (strlen(file->name) > NAME_MAX) || 1975 (!(file->uri)) || (!(context->room))) 1976 return GNUNET_SYSERR; 1977 1978 struct GNUNET_MESSENGER_Message msg; 1979 memset(&msg, 0, sizeof(msg)); 1980 1981 msg.header.kind = GNUNET_MESSENGER_KIND_FILE; 1982 1983 if (file->key) 1984 GNUNET_memcpy(&(msg.body.file.key), file->key, 1985 sizeof(struct GNUNET_CRYPTO_SymmetricSessionKey)); 1986 else 1987 memset(&(msg.body.file.key), 0, sizeof(msg.body.file.key)); 1988 1989 GNUNET_memcpy(&(msg.body.file.hash), &(file->hash), sizeof(file->hash)); 1990 GNUNET_strlcpy(msg.body.file.name, file->name, NAME_MAX); 1991 msg.body.file.uri = GNUNET_FS_uri_to_string(file->uri); 1992 1993 GNUNET_MESSENGER_send_message(context->room, &msg, NULL); 1994 1995 GNUNET_free(msg.body.file.uri); 1996 return GNUNET_OK; 1997 } 1998 1999 2000 enum GNUNET_GenericReturnValue 2001 GNUNET_CHAT_context_send_tag (struct GNUNET_CHAT_Context *context, 2002 struct GNUNET_CHAT_Message *message, 2003 const char *tag) 2004 { 2005 GNUNET_CHAT_VERSION_ASSERT(); 2006 2007 if ((!context) || (!message) || (!tag) || (!(context->room))) 2008 return GNUNET_SYSERR; 2009 2010 char *tag_value = GNUNET_strdup(tag); 2011 2012 struct GNUNET_MESSENGER_Message msg; 2013 memset(&msg, 0, sizeof(msg)); 2014 2015 msg.header.kind = GNUNET_MESSENGER_KIND_TAG; 2016 GNUNET_memcpy(&(msg.body.tag.hash), &(message->hash), 2017 sizeof(struct GNUNET_HashCode)); 2018 msg.body.tag.tag = tag_value; 2019 2020 GNUNET_MESSENGER_send_message( 2021 context->room, 2022 &msg, 2023 NULL 2024 ); 2025 2026 GNUNET_free(tag_value); 2027 return GNUNET_OK; 2028 } 2029 2030 2031 struct GNUNET_CHAT_Discourse* 2032 GNUNET_CHAT_context_open_discourse (struct GNUNET_CHAT_Context *context, 2033 const struct GNUNET_CHAT_DiscourseId *id) 2034 { 2035 GNUNET_CHAT_VERSION_ASSERT(); 2036 2037 if ((!context) || (!(context->discourses)) || (!(context->room)) || (!id)) 2038 return NULL; 2039 2040 struct GNUNET_ShortHashCode sid; 2041 util_shorthash_from_discourse_id(id, &sid); 2042 2043 struct GNUNET_CHAT_Discourse *discourse = GNUNET_CONTAINER_multishortmap_get( 2044 context->discourses, &sid 2045 ); 2046 2047 if (!discourse) 2048 { 2049 discourse = discourse_create(context, id); 2050 2051 if (GNUNET_OK != GNUNET_CONTAINER_multishortmap_put(context->discourses, 2052 &sid, discourse, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 2053 { 2054 discourse_destroy(discourse); 2055 return NULL; 2056 } 2057 } 2058 2059 struct GNUNET_MESSENGER_Message msg; 2060 memset(&msg, 0, sizeof(msg)); 2061 2062 msg.header.kind = GNUNET_MESSENGER_KIND_SUBSCRIBTION; 2063 GNUNET_memcpy( 2064 &(msg.body.subscription.discourse), 2065 &sid, 2066 sizeof(struct GNUNET_ShortHashCode) 2067 ); 2068 2069 const struct GNUNET_TIME_Relative subscription_time = GNUNET_TIME_relative_multiply( 2070 GNUNET_TIME_relative_get_second_(), 10 2071 ); 2072 2073 msg.body.subscription.time = GNUNET_TIME_relative_hton(subscription_time); 2074 msg.body.subscription.flags = GNUNET_MESSENGER_FLAG_SUBSCRIPTION_KEEP_ALIVE; 2075 2076 GNUNET_MESSENGER_send_message( 2077 context->room, 2078 &msg, 2079 NULL 2080 ); 2081 2082 return discourse; 2083 } 2084 2085 2086 int 2087 GNUNET_CHAT_context_iterate_messages (struct GNUNET_CHAT_Context *context, 2088 GNUNET_CHAT_ContextMessageCallback callback, 2089 void *cls) 2090 { 2091 GNUNET_CHAT_VERSION_ASSERT(); 2092 2093 if (!context) 2094 return GNUNET_SYSERR; 2095 2096 struct GNUNET_CHAT_ContextIterateMessages it; 2097 it.context = context; 2098 it.cb = callback; 2099 it.cls = cls; 2100 2101 return GNUNET_CONTAINER_multihashmap_iterate( 2102 context->messages, it_context_iterate_messages, &it 2103 ); 2104 } 2105 2106 2107 int 2108 GNUNET_CHAT_context_iterate_files (struct GNUNET_CHAT_Context *context, 2109 GNUNET_CHAT_ContextFileCallback callback, 2110 void *cls) 2111 { 2112 GNUNET_CHAT_VERSION_ASSERT(); 2113 2114 if (!context) 2115 return GNUNET_SYSERR; 2116 2117 struct GNUNET_CHAT_ContextIterateFiles it; 2118 it.context = context; 2119 it.cb = callback; 2120 it.cls = cls; 2121 2122 return GNUNET_CONTAINER_multihashmap_iterate( 2123 context->files, it_context_iterate_files, &it 2124 ); 2125 } 2126 2127 2128 enum GNUNET_CHAT_MessageKind 2129 GNUNET_CHAT_message_get_kind (const struct GNUNET_CHAT_Message *message) 2130 { 2131 GNUNET_CHAT_VERSION_ASSERT(); 2132 2133 if (!message) 2134 return GNUNET_CHAT_KIND_UNKNOWN; 2135 2136 switch (message->flag) 2137 { 2138 case GNUNET_CHAT_FLAG_WARNING: 2139 return GNUNET_CHAT_KIND_WARNING; 2140 case GNUNET_CHAT_FLAG_REFRESH: 2141 return GNUNET_CHAT_KIND_REFRESH; 2142 case GNUNET_CHAT_FLAG_LOGIN: 2143 return GNUNET_CHAT_KIND_LOGIN; 2144 case GNUNET_CHAT_FLAG_LOGOUT: 2145 return GNUNET_CHAT_KIND_LOGOUT; 2146 case GNUNET_CHAT_FLAG_CREATE_ACCOUNT: 2147 return GNUNET_CHAT_KIND_CREATED_ACCOUNT; 2148 case GNUNET_CHAT_FLAG_DELETE_ACCOUNT: 2149 return GNUNET_CHAT_KIND_DELETED_ACCOUNT; 2150 case GNUNET_CHAT_FLAG_UPDATE_ACCOUNT: 2151 return GNUNET_CHAT_KIND_UPDATE_ACCOUNT; 2152 case GNUNET_CHAT_FLAG_UPDATE_CONTEXT: 2153 return GNUNET_CHAT_KIND_UPDATE_CONTEXT; 2154 case GNUNET_CHAT_FLAG_ATTRIBUTES: 2155 return GNUNET_CHAT_KIND_ATTRIBUTES; 2156 case GNUNET_CHAT_FLAG_SHARE_ATTRIBUTES: 2157 return GNUNET_CHAT_KIND_SHARED_ATTRIBUTES; 2158 default: 2159 break; 2160 } 2161 2162 if (GNUNET_YES != message_has_msg(message)) 2163 return GNUNET_CHAT_KIND_UNKNOWN; 2164 2165 return util_message_kind_from_kind(message->msg->header.kind); 2166 } 2167 2168 2169 time_t 2170 GNUNET_CHAT_message_get_timestamp (const struct GNUNET_CHAT_Message *message) 2171 { 2172 GNUNET_CHAT_VERSION_ASSERT(); 2173 2174 if ((!message) || (GNUNET_YES != message_has_msg(message))) 2175 return ((time_t) -1); 2176 2177 struct GNUNET_TIME_Absolute abs = GNUNET_TIME_absolute_ntoh( 2178 message->msg->header.timestamp 2179 ); 2180 2181 struct GNUNET_TIME_Timestamp ts = GNUNET_TIME_absolute_to_timestamp( 2182 abs 2183 ); 2184 2185 return (time_t) GNUNET_TIME_timestamp_to_s(ts); 2186 } 2187 2188 2189 struct GNUNET_CHAT_Contact* 2190 GNUNET_CHAT_message_get_sender (const struct GNUNET_CHAT_Message *message) 2191 { 2192 GNUNET_CHAT_VERSION_ASSERT(); 2193 2194 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2195 (!(message->context)) || (!(message->context->room))) 2196 return NULL; 2197 2198 const struct GNUNET_MESSENGER_Contact *sender = GNUNET_MESSENGER_get_sender( 2199 message->context->room, &(message->hash) 2200 ); 2201 2202 if (!sender) 2203 return NULL; 2204 2205 return handle_get_contact_from_messenger(message->context->handle, sender); 2206 } 2207 2208 2209 struct GNUNET_CHAT_Contact* 2210 GNUNET_CHAT_message_get_recipient (const struct GNUNET_CHAT_Message *message) 2211 { 2212 GNUNET_CHAT_VERSION_ASSERT(); 2213 2214 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2215 (!(message->context)) || (!(message->context->room))) 2216 return NULL; 2217 2218 const struct GNUNET_MESSENGER_Contact *recipient = GNUNET_MESSENGER_get_recipient( 2219 message->context->room, &(message->hash) 2220 ); 2221 2222 if (!recipient) 2223 return NULL; 2224 2225 return handle_get_contact_from_messenger(message->context->handle, recipient); 2226 } 2227 2228 2229 enum GNUNET_GenericReturnValue 2230 GNUNET_CHAT_message_is_sent (const struct GNUNET_CHAT_Message *message) 2231 { 2232 GNUNET_CHAT_VERSION_ASSERT(); 2233 2234 if (!message) 2235 return GNUNET_SYSERR; 2236 2237 if (message->flags & GNUNET_MESSENGER_FLAG_SENT) 2238 return GNUNET_YES; 2239 else 2240 return GNUNET_NO; 2241 } 2242 2243 2244 enum GNUNET_GenericReturnValue 2245 GNUNET_CHAT_message_is_private (const struct GNUNET_CHAT_Message *message) 2246 { 2247 GNUNET_CHAT_VERSION_ASSERT(); 2248 2249 if (!message) 2250 return GNUNET_SYSERR; 2251 2252 if (message->flags & GNUNET_MESSENGER_FLAG_PRIVATE) 2253 return GNUNET_YES; 2254 else 2255 return GNUNET_NO; 2256 } 2257 2258 2259 enum GNUNET_GenericReturnValue 2260 GNUNET_CHAT_message_is_recent (const struct GNUNET_CHAT_Message *message) 2261 { 2262 GNUNET_CHAT_VERSION_ASSERT(); 2263 2264 if (!message) 2265 return GNUNET_SYSERR; 2266 2267 if (message->flags & GNUNET_MESSENGER_FLAG_RECENT) 2268 return GNUNET_YES; 2269 else 2270 return GNUNET_NO; 2271 } 2272 2273 2274 enum GNUNET_GenericReturnValue 2275 GNUNET_CHAT_message_is_update (const struct GNUNET_CHAT_Message *message) 2276 { 2277 GNUNET_CHAT_VERSION_ASSERT(); 2278 2279 if (!message) 2280 return GNUNET_SYSERR; 2281 2282 if (message->flags & GNUNET_MESSENGER_FLAG_UPDATE) 2283 return GNUNET_YES; 2284 else 2285 return GNUNET_NO; 2286 } 2287 2288 2289 enum GNUNET_GenericReturnValue 2290 GNUNET_CHAT_message_is_deleted (const struct GNUNET_CHAT_Message *message) 2291 { 2292 GNUNET_CHAT_VERSION_ASSERT(); 2293 2294 if (!message) 2295 return GNUNET_SYSERR; 2296 2297 if ((GNUNET_CHAT_FLAG_NONE == message->flag) && 2298 ((message->flags & GNUNET_MESSENGER_FLAG_DELETE) || 2299 (!message->msg))) 2300 return GNUNET_YES; 2301 else 2302 return GNUNET_NO; 2303 } 2304 2305 2306 enum GNUNET_GenericReturnValue 2307 GNUNET_CHAT_message_is_tagged (const struct GNUNET_CHAT_Message *message, 2308 const char *tag) 2309 { 2310 GNUNET_CHAT_VERSION_ASSERT(); 2311 2312 if ((!message) || (!(message->context))) 2313 return GNUNET_SYSERR; 2314 2315 const struct GNUNET_CHAT_InternalTagging *tagging = GNUNET_CONTAINER_multihashmap_get( 2316 message->context->taggings, &(message->hash)); 2317 2318 if (!tagging) 2319 return GNUNET_NO; 2320 2321 if (internal_tagging_iterate(tagging, GNUNET_NO, tag, NULL, NULL) > 0) 2322 return GNUNET_YES; 2323 else 2324 return GNUNET_NO; 2325 } 2326 2327 2328 int 2329 GNUNET_CHAT_message_get_read_receipt (struct GNUNET_CHAT_Message *message, 2330 GNUNET_CHAT_MessageReadReceiptCallback callback, 2331 void *cls) 2332 { 2333 GNUNET_CHAT_VERSION_ASSERT(); 2334 2335 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2336 (!(message->context))) 2337 return GNUNET_SYSERR; 2338 2339 struct GNUNET_CHAT_MessageIterateReadReceipts it; 2340 it.message = message; 2341 it.cb = callback; 2342 it.cls = cls; 2343 2344 return GNUNET_MESSENGER_iterate_members( 2345 message->context->room, it_message_iterate_read_receipts, &it 2346 ); 2347 } 2348 2349 2350 const char* 2351 GNUNET_CHAT_message_get_text (const struct GNUNET_CHAT_Message *message) 2352 { 2353 GNUNET_CHAT_VERSION_ASSERT(); 2354 2355 if (!message) 2356 return NULL; 2357 2358 if (GNUNET_CHAT_FLAG_WARNING == message->flag) 2359 return message->warning; 2360 else if (GNUNET_CHAT_FLAG_UPDATE_ACCOUNT == message->flag) 2361 return message->warning; 2362 else if (GNUNET_CHAT_FLAG_ATTRIBUTES == message->flag) 2363 return message->attr; 2364 2365 if (GNUNET_YES != message_has_msg(message)) 2366 return NULL; 2367 2368 if (GNUNET_MESSENGER_KIND_TEXT == message->msg->header.kind) 2369 return message->msg->body.text.text; 2370 else if (GNUNET_MESSENGER_KIND_FILE == message->msg->header.kind) 2371 return message->msg->body.file.name; 2372 else if (GNUNET_MESSENGER_KIND_TAG == message->msg->header.kind) 2373 return message->msg->body.tag.tag; 2374 else 2375 return NULL; 2376 } 2377 2378 2379 void 2380 GNUNET_CHAT_message_set_user_pointer (struct GNUNET_CHAT_Message *message, 2381 void *user_pointer) 2382 { 2383 GNUNET_CHAT_VERSION_ASSERT(); 2384 2385 if (!message) 2386 return; 2387 2388 message->user_pointer = user_pointer; 2389 } 2390 2391 2392 void* 2393 GNUNET_CHAT_message_get_user_pointer (const struct GNUNET_CHAT_Message *message) 2394 { 2395 GNUNET_CHAT_VERSION_ASSERT(); 2396 2397 if (!message) 2398 return NULL; 2399 2400 return message->user_pointer; 2401 } 2402 2403 2404 struct GNUNET_CHAT_Account* 2405 GNUNET_CHAT_message_get_account (const struct GNUNET_CHAT_Message *message) 2406 { 2407 GNUNET_CHAT_VERSION_ASSERT(); 2408 2409 if (!message) 2410 return NULL; 2411 2412 if ((message->context) && (message->context->handle)) 2413 return message->context->handle->current; 2414 else 2415 return message->account; 2416 } 2417 2418 2419 struct GNUNET_CHAT_File* 2420 GNUNET_CHAT_message_get_file (const struct GNUNET_CHAT_Message *message) 2421 { 2422 GNUNET_CHAT_VERSION_ASSERT(); 2423 2424 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2425 (!(message->context))) 2426 return NULL; 2427 2428 if (GNUNET_MESSENGER_KIND_FILE != message->msg->header.kind) 2429 return NULL; 2430 2431 return GNUNET_CONTAINER_multihashmap_get( 2432 message->context->handle->files, 2433 &(message->msg->body.file.hash) 2434 ); 2435 } 2436 2437 2438 struct GNUNET_CHAT_Invitation* 2439 GNUNET_CHAT_message_get_invitation (const struct GNUNET_CHAT_Message *message) 2440 { 2441 GNUNET_CHAT_VERSION_ASSERT(); 2442 2443 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2444 (!(message->context))) 2445 return NULL; 2446 2447 if (GNUNET_MESSENGER_KIND_INVITE != message->msg->header.kind) 2448 return NULL; 2449 2450 return GNUNET_CONTAINER_multihashmap_get( 2451 message->context->invites, 2452 &(message->hash) 2453 ); 2454 } 2455 2456 2457 struct GNUNET_CHAT_Discourse* 2458 GNUNET_CHAT_message_get_discourse (const struct GNUNET_CHAT_Message *message) 2459 { 2460 GNUNET_CHAT_VERSION_ASSERT(); 2461 2462 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2463 (!(message->context)) || (!(message->context->discourses))) 2464 return NULL; 2465 2466 struct GNUNET_CHAT_Discourse *discourse; 2467 2468 if (GNUNET_MESSENGER_KIND_SUBSCRIBTION == message->msg->header.kind) 2469 discourse = GNUNET_CONTAINER_multishortmap_get( 2470 message->context->discourses, 2471 &(message->msg->body.subscription.discourse)); 2472 else if (GNUNET_MESSENGER_KIND_TALK == message->msg->header.kind) 2473 discourse = GNUNET_CONTAINER_multishortmap_get( 2474 message->context->discourses, 2475 &(message->msg->body.talk.discourse)); 2476 else 2477 discourse = NULL; 2478 2479 return discourse; 2480 } 2481 2482 2483 struct GNUNET_CHAT_Message* 2484 GNUNET_CHAT_message_get_target (const struct GNUNET_CHAT_Message *message) 2485 { 2486 GNUNET_CHAT_VERSION_ASSERT(); 2487 2488 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2489 (!(message->context))) 2490 return NULL; 2491 2492 struct GNUNET_CHAT_Message *target; 2493 2494 if (GNUNET_MESSENGER_KIND_DELETION == message->msg->header.kind) 2495 target = GNUNET_CONTAINER_multihashmap_get( 2496 message->context->messages, &(message->msg->body.deletion.hash)); 2497 else if (GNUNET_MESSENGER_KIND_TAG == message->msg->header.kind) 2498 target = GNUNET_CONTAINER_multihashmap_get( 2499 message->context->messages, &(message->msg->body.tag.hash)); 2500 else 2501 target = NULL; 2502 2503 return target; 2504 } 2505 2506 2507 enum GNUNET_GenericReturnValue 2508 GNUNET_CHAT_message_delete (struct GNUNET_CHAT_Message *message, 2509 unsigned int delay) 2510 { 2511 GNUNET_CHAT_VERSION_ASSERT(); 2512 2513 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2514 (!(message->context))) 2515 return GNUNET_SYSERR; 2516 2517 struct GNUNET_TIME_Relative rel = GNUNET_TIME_relative_multiply( 2518 GNUNET_TIME_relative_get_second_(), delay 2519 ); 2520 2521 GNUNET_MESSENGER_delete_message( 2522 message->context->room, 2523 &(message->hash), 2524 rel 2525 ); 2526 2527 return GNUNET_OK; 2528 } 2529 2530 2531 int 2532 GNUNET_CHAT_message_iterate_tags (struct GNUNET_CHAT_Message *message, 2533 GNUNET_CHAT_MessageCallback callback, 2534 void *cls) 2535 { 2536 GNUNET_CHAT_VERSION_ASSERT(); 2537 2538 if ((!message) || (!(message->context))) 2539 return GNUNET_SYSERR; 2540 2541 const struct GNUNET_CHAT_InternalTagging *tagging = GNUNET_CONTAINER_multihashmap_get( 2542 message->context->taggings, &(message->hash)); 2543 2544 if (!tagging) 2545 return 0; 2546 2547 return internal_tagging_iterate(tagging, GNUNET_YES, NULL, callback, cls); 2548 } 2549 2550 2551 uint64_t 2552 GNUNET_CHAT_message_available (const struct GNUNET_CHAT_Message *message) 2553 { 2554 GNUNET_CHAT_VERSION_ASSERT(); 2555 2556 if ((!message) || (GNUNET_YES != message_has_msg(message))) 2557 return 0; 2558 2559 if (GNUNET_MESSENGER_KIND_TALK == message->msg->header.kind) 2560 return message->msg->body.talk.length; 2561 else 2562 return 0; 2563 } 2564 2565 2566 enum GNUNET_GenericReturnValue 2567 GNUNET_CHAT_message_read (const struct GNUNET_CHAT_Message *message, 2568 char *data, 2569 uint64_t size) 2570 { 2571 GNUNET_CHAT_VERSION_ASSERT(); 2572 2573 if ((!message) || (GNUNET_YES != message_has_msg(message))) 2574 return GNUNET_SYSERR; 2575 2576 if (GNUNET_MESSENGER_KIND_TALK != message->msg->header.kind) 2577 return GNUNET_SYSERR; 2578 2579 const uint64_t available = message->msg->body.talk.length; 2580 2581 if (available < size) 2582 return GNUNET_NO; 2583 2584 GNUNET_memcpy( 2585 data, 2586 message->msg->body.talk.data, 2587 size 2588 ); 2589 2590 return GNUNET_OK; 2591 } 2592 2593 2594 enum GNUNET_GenericReturnValue 2595 GNUNET_CHAT_message_feed (const struct GNUNET_CHAT_Message *message, 2596 int fd) 2597 { 2598 GNUNET_CHAT_VERSION_ASSERT(); 2599 2600 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2601 (fd == -1)) 2602 return GNUNET_SYSERR; 2603 2604 if (GNUNET_MESSENGER_KIND_TALK != message->msg->header.kind) 2605 return GNUNET_SYSERR; 2606 2607 if (!(message->msg->body.talk.length)) 2608 return GNUNET_NO; 2609 2610 const ssize_t written = write( 2611 fd, 2612 message->msg->body.talk.data, 2613 message->msg->body.talk.length 2614 ); 2615 2616 if (-1 == written) 2617 return GNUNET_SYSERR; 2618 else if (written != message->msg->body.talk.length) 2619 return GNUNET_NO; 2620 else 2621 return GNUNET_OK; 2622 } 2623 2624 2625 const char* 2626 GNUNET_CHAT_file_get_name (const struct GNUNET_CHAT_File *file) 2627 { 2628 GNUNET_CHAT_VERSION_ASSERT(); 2629 2630 if (!file) 2631 return NULL; 2632 2633 return file->name; 2634 } 2635 2636 2637 const char* 2638 GNUNET_CHAT_file_get_hash (const struct GNUNET_CHAT_File *file) 2639 { 2640 GNUNET_CHAT_VERSION_ASSERT(); 2641 2642 if (!file) 2643 return NULL; 2644 2645 return GNUNET_h2s_full(&(file->hash)); 2646 } 2647 2648 2649 uint64_t 2650 GNUNET_CHAT_file_get_size (const struct GNUNET_CHAT_File *file) 2651 { 2652 GNUNET_CHAT_VERSION_ASSERT(); 2653 2654 if ((!file) || (!(file->uri))) 2655 return 0; 2656 2657 return GNUNET_FS_uri_chk_get_file_size(file->uri); 2658 } 2659 2660 2661 uint64_t 2662 GNUNET_CHAT_file_get_local_size (const struct GNUNET_CHAT_File *file) 2663 { 2664 GNUNET_CHAT_VERSION_ASSERT(); 2665 2666 if (!file) 2667 return 0; 2668 2669 char *filename = handle_create_file_path( 2670 file->handle, &(file->hash) 2671 ); 2672 2673 if (!filename) 2674 return 0; 2675 2676 uint64_t size; 2677 if (GNUNET_OK != GNUNET_DISK_file_size(filename, &size, GNUNET_NO, GNUNET_YES)) 2678 size = 0; 2679 2680 GNUNET_free(filename); 2681 return size; 2682 } 2683 2684 2685 struct GNUNET_CHAT_Uri* 2686 GNUNET_CHAT_file_get_uri (const struct GNUNET_CHAT_File *file) 2687 { 2688 GNUNET_CHAT_VERSION_ASSERT(); 2689 2690 if ((!file) || (!(file->uri))) 2691 return NULL; 2692 2693 return uri_create_file(file->uri); 2694 } 2695 2696 2697 enum GNUNET_GenericReturnValue 2698 GNUNET_CHAT_file_is_uploading (const struct GNUNET_CHAT_File *file) 2699 { 2700 GNUNET_CHAT_VERSION_ASSERT(); 2701 2702 if ((!file) || (0 == (file->status & GNUNET_CHAT_FILE_STATUS_PUBLISH))) 2703 return GNUNET_NO; 2704 else 2705 return GNUNET_YES; 2706 } 2707 2708 2709 enum GNUNET_GenericReturnValue 2710 GNUNET_CHAT_file_is_ready (const struct GNUNET_CHAT_File *file) 2711 { 2712 GNUNET_CHAT_VERSION_ASSERT(); 2713 2714 if ((!file) || (file->status & GNUNET_CHAT_FILE_STATUS_MASK)) 2715 return GNUNET_NO; 2716 2717 const uint64_t size = GNUNET_CHAT_file_get_size(file); 2718 const uint64_t local_size = GNUNET_CHAT_file_get_local_size(file); 2719 2720 if (size != local_size) 2721 return GNUNET_NO; 2722 else 2723 return GNUNET_YES; 2724 } 2725 2726 2727 const char* 2728 GNUNET_CHAT_file_open_preview (struct GNUNET_CHAT_File *file) 2729 { 2730 GNUNET_CHAT_VERSION_ASSERT(); 2731 2732 if (!file) 2733 return NULL; 2734 2735 if (file->preview) 2736 return file->preview; 2737 2738 char *filename = handle_create_file_path( 2739 file->handle, &(file->hash) 2740 ); 2741 2742 if (!filename) 2743 return NULL; 2744 2745 if (GNUNET_YES != GNUNET_DISK_file_test(filename)) 2746 goto free_filename; 2747 2748 if (!(file->key)) 2749 { 2750 file->preview = filename; 2751 return file->preview; 2752 } 2753 2754 file->preview = GNUNET_DISK_mktemp( 2755 file->name? file->name : "" 2756 ); 2757 2758 if (!(file->preview)) 2759 goto free_filename; 2760 2761 remove(file->preview); 2762 2763 if ((GNUNET_OK != GNUNET_DISK_file_copy(filename, file->preview)) || 2764 (GNUNET_OK != util_decrypt_file(file->preview, 2765 &(file->hash), file->key))) 2766 { 2767 GNUNET_free(file->preview); 2768 file->preview = NULL; 2769 } 2770 2771 free_filename: 2772 GNUNET_free(filename); 2773 return file->preview; 2774 } 2775 2776 2777 void 2778 GNUNET_CHAT_file_close_preview (struct GNUNET_CHAT_File *file) 2779 { 2780 GNUNET_CHAT_VERSION_ASSERT(); 2781 2782 if ((!file) || (!(file->preview))) 2783 return; 2784 2785 if (!(file->key)) 2786 goto skip_filename; 2787 2788 char *filename = handle_create_file_path( 2789 file->handle, &(file->hash) 2790 ); 2791 2792 if (!filename) 2793 goto skip_filename; 2794 2795 if (0 != strcmp(filename, file->preview)) 2796 remove(file->preview); 2797 2798 GNUNET_free(filename); 2799 2800 skip_filename: 2801 GNUNET_free(file->preview); 2802 file->preview = NULL; 2803 } 2804 2805 2806 void 2807 GNUNET_CHAT_file_set_user_pointer (struct GNUNET_CHAT_File *file, 2808 void *user_pointer) 2809 { 2810 GNUNET_CHAT_VERSION_ASSERT(); 2811 2812 if (!file) 2813 return; 2814 2815 file->user_pointer = user_pointer; 2816 } 2817 2818 2819 void* 2820 GNUNET_CHAT_file_get_user_pointer (const struct GNUNET_CHAT_File *file) 2821 { 2822 GNUNET_CHAT_VERSION_ASSERT(); 2823 2824 if (!file) 2825 return NULL; 2826 2827 return file->user_pointer; 2828 } 2829 2830 2831 enum GNUNET_GenericReturnValue 2832 GNUNET_CHAT_file_is_downloading (const struct GNUNET_CHAT_File *file) 2833 { 2834 GNUNET_CHAT_VERSION_ASSERT(); 2835 2836 if ((!file) || (0 == (file->status & GNUNET_CHAT_FILE_STATUS_DOWNLOAD))) 2837 return GNUNET_NO; 2838 else 2839 return GNUNET_YES; 2840 } 2841 2842 2843 enum GNUNET_GenericReturnValue 2844 GNUNET_CHAT_file_start_download (struct GNUNET_CHAT_File *file, 2845 GNUNET_CHAT_FileDownloadCallback callback, 2846 void *cls) 2847 { 2848 GNUNET_CHAT_VERSION_ASSERT(); 2849 2850 if ((!file) || (!(file->uri))) 2851 return GNUNET_SYSERR; 2852 2853 if (file->download) 2854 { 2855 file_bind_downlaod(file, callback, cls); 2856 2857 GNUNET_FS_download_resume(file->download); 2858 return GNUNET_OK; 2859 } 2860 2861 char *filename = handle_create_file_path( 2862 file->handle, &(file->hash) 2863 ); 2864 2865 if (!filename) 2866 return GNUNET_SYSERR; 2867 2868 const uint64_t size = GNUNET_FS_uri_chk_get_file_size(file->uri); 2869 2870 uint64_t offset; 2871 if (GNUNET_OK != GNUNET_DISK_file_size(filename, &offset, 2872 GNUNET_NO, GNUNET_YES)) 2873 offset = 0; 2874 2875 if (offset >= size) 2876 { 2877 if (callback) 2878 callback(cls, file, size, size); 2879 2880 goto free_filename; 2881 } 2882 2883 file_bind_downlaod(file, callback, cls); 2884 2885 const uint64_t remaining = (size - offset); 2886 2887 file->download = GNUNET_FS_download_start( 2888 file->handle->fs, 2889 file->uri, 2890 file->meta, 2891 filename, 2892 NULL, 2893 offset, 2894 remaining, 2895 1, 2896 GNUNET_FS_DOWNLOAD_OPTION_NONE, 2897 file, 2898 NULL 2899 ); 2900 2901 if (file->download) 2902 file->status |= GNUNET_CHAT_FILE_STATUS_DOWNLOAD; 2903 2904 free_filename: 2905 GNUNET_free(filename); 2906 return GNUNET_OK; 2907 } 2908 2909 2910 enum GNUNET_GenericReturnValue 2911 GNUNET_CHAT_file_pause_download (struct GNUNET_CHAT_File *file) 2912 { 2913 GNUNET_CHAT_VERSION_ASSERT(); 2914 2915 if (!file) 2916 return GNUNET_SYSERR; 2917 2918 GNUNET_FS_download_suspend(file->download); 2919 return GNUNET_OK; 2920 } 2921 2922 2923 enum GNUNET_GenericReturnValue 2924 GNUNET_CHAT_file_resume_download (struct GNUNET_CHAT_File *file) 2925 { 2926 GNUNET_CHAT_VERSION_ASSERT(); 2927 2928 if (!file) 2929 return GNUNET_SYSERR; 2930 2931 GNUNET_FS_download_resume(file->download); 2932 return GNUNET_OK; 2933 } 2934 2935 2936 enum GNUNET_GenericReturnValue 2937 GNUNET_CHAT_file_stop_download (struct GNUNET_CHAT_File *file) 2938 { 2939 GNUNET_CHAT_VERSION_ASSERT(); 2940 2941 if (!file) 2942 return GNUNET_SYSERR; 2943 2944 GNUNET_FS_download_stop(file->download, GNUNET_YES); 2945 file->download = NULL; 2946 return GNUNET_OK; 2947 } 2948 2949 2950 enum GNUNET_GenericReturnValue 2951 GNUNET_CHAT_file_is_unindexing (const struct GNUNET_CHAT_File *file) 2952 { 2953 GNUNET_CHAT_VERSION_ASSERT(); 2954 2955 if ((!file) || (0 == (file->status & GNUNET_CHAT_FILE_STATUS_UNINDEX))) 2956 return GNUNET_NO; 2957 else 2958 return GNUNET_YES; 2959 } 2960 2961 2962 enum GNUNET_GenericReturnValue 2963 GNUNET_CHAT_file_unindex (struct GNUNET_CHAT_File *file, 2964 GNUNET_CHAT_FileUnindexCallback callback, 2965 void *cls) 2966 { 2967 GNUNET_CHAT_VERSION_ASSERT(); 2968 2969 if (!file) 2970 return GNUNET_SYSERR; 2971 2972 if (file->publish) 2973 { 2974 GNUNET_FS_publish_stop(file->publish); 2975 file->publish = NULL; 2976 return GNUNET_OK; 2977 } 2978 2979 file_bind_unindex(file, callback, cls); 2980 2981 if (file->unindex) 2982 return GNUNET_OK; 2983 2984 char *filename = handle_create_file_path( 2985 file->handle, &(file->hash) 2986 ); 2987 2988 if (!filename) 2989 return GNUNET_SYSERR; 2990 2991 file->unindex = GNUNET_FS_unindex_start( 2992 file->handle->fs, filename, file 2993 ); 2994 2995 if (file->unindex) 2996 file->status |= GNUNET_CHAT_FILE_STATUS_UNINDEX; 2997 2998 GNUNET_free(filename); 2999 return GNUNET_OK; 3000 } 3001 3002 3003 void 3004 GNUNET_CHAT_invitation_accept (struct GNUNET_CHAT_Invitation *invitation) 3005 { 3006 GNUNET_CHAT_VERSION_ASSERT(); 3007 3008 if (!invitation) 3009 return; 3010 3011 struct GNUNET_CHAT_Handle *handle; 3012 handle = invitation->context->handle; 3013 3014 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains( 3015 handle->contexts, &(invitation->key.hash))) 3016 return; 3017 3018 struct GNUNET_PeerIdentity door; 3019 GNUNET_PEER_resolve(invitation->door, &door); 3020 3021 struct GNUNET_MESSENGER_Room *room; 3022 room = GNUNET_MESSENGER_enter_room( 3023 invitation->context->handle->messenger, 3024 &door, &(invitation->key) 3025 ); 3026 3027 if (!room) 3028 return; 3029 3030 struct GNUNET_CHAT_Context *context; 3031 context = context_create_from_room(handle, room); 3032 3033 if (!context) 3034 return; 3035 3036 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 3037 handle->contexts, &(invitation->key.hash), context, 3038 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 3039 goto destroy_context; 3040 3041 if (GNUNET_CHAT_CONTEXT_TYPE_GROUP != context->type) 3042 { 3043 context_write_records(context); 3044 return; 3045 } 3046 3047 struct GNUNET_CHAT_Group *group; 3048 group = group_create_from_context(handle, context); 3049 3050 if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put( 3051 handle->groups, &(invitation->key.hash), group, 3052 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 3053 { 3054 context_write_records(context); 3055 return; 3056 } 3057 3058 group_destroy(group); 3059 3060 GNUNET_CONTAINER_multihashmap_remove( 3061 handle->contexts, &(invitation->key.hash), context); 3062 3063 destroy_context: 3064 context_destroy(context); 3065 } 3066 3067 3068 void 3069 GNUNET_CHAT_invitation_reject (struct GNUNET_CHAT_Invitation *invitation) 3070 { 3071 GNUNET_CHAT_VERSION_ASSERT(); 3072 3073 if (!invitation) 3074 return; 3075 3076 const struct GNUNET_MESSENGER_Contact *sender = GNUNET_MESSENGER_get_sender( 3077 invitation->context->room, &(invitation->hash) 3078 ); 3079 3080 if (!sender) 3081 return; 3082 3083 struct GNUNET_MESSENGER_Message msg; 3084 memset(&msg, 0, sizeof(msg)); 3085 3086 msg.header.kind = GNUNET_MESSENGER_KIND_TAG; 3087 GNUNET_memcpy(&(msg.body.tag.hash), &(invitation->hash), 3088 sizeof(struct GNUNET_HashCode)); 3089 msg.body.tag.tag = NULL; 3090 3091 GNUNET_MESSENGER_send_message(invitation->context->room, &msg, sender); 3092 } 3093 3094 3095 enum GNUNET_GenericReturnValue 3096 GNUNET_CHAT_invitation_is_accepted (const struct GNUNET_CHAT_Invitation *invitation) 3097 { 3098 GNUNET_CHAT_VERSION_ASSERT(); 3099 3100 if (!invitation) 3101 return GNUNET_NO; 3102 3103 return GNUNET_CONTAINER_multihashmap_contains( 3104 invitation->context->handle->contexts, 3105 &(invitation->key.hash) 3106 ); 3107 } 3108 3109 3110 enum GNUNET_GenericReturnValue 3111 GNUNET_CHAT_invitation_is_rejected (const struct GNUNET_CHAT_Invitation *invitation) 3112 { 3113 GNUNET_CHAT_VERSION_ASSERT(); 3114 3115 if (!invitation) 3116 return GNUNET_NO; 3117 3118 const struct GNUNET_CHAT_InternalTagging *tagging = GNUNET_CONTAINER_multihashmap_get( 3119 invitation->context->taggings, &(invitation->hash)); 3120 3121 if (!tagging) 3122 return GNUNET_NO; 3123 3124 if (internal_tagging_iterate(tagging, GNUNET_NO, NULL, NULL, NULL) > 0) 3125 return GNUNET_YES; 3126 else 3127 return GNUNET_NO; 3128 } 3129 3130 3131 enum GNUNET_GenericReturnValue 3132 GNUNET_CHAT_invitation_is_direct (const struct GNUNET_CHAT_Invitation *invitation) 3133 { 3134 GNUNET_CHAT_VERSION_ASSERT(); 3135 3136 if ((invitation->key.code.public_bit) || 3137 (invitation->key.code.group_bit) || 3138 (invitation->key.code.feed_bit)) 3139 return GNUNET_NO; 3140 else 3141 return GNUNET_YES; 3142 } 3143 3144 3145 const struct GNUNET_CHAT_DiscourseId* 3146 GNUNET_CHAT_discourse_get_id (const struct GNUNET_CHAT_Discourse *discourse) 3147 { 3148 GNUNET_CHAT_VERSION_ASSERT(); 3149 3150 if (!discourse) 3151 return NULL; 3152 3153 return &(discourse->id); 3154 } 3155 3156 3157 enum GNUNET_GenericReturnValue 3158 GNUNET_CHAT_discourse_is_open (const struct GNUNET_CHAT_Discourse *discourse) 3159 { 3160 GNUNET_CHAT_VERSION_ASSERT(); 3161 3162 if (!discourse) 3163 return GNUNET_SYSERR; 3164 3165 struct GNUNET_CHAT_DiscourseSubscription *sub; 3166 for (sub = discourse->head; sub; sub = sub->next) 3167 { 3168 if (GNUNET_TIME_absolute_cmp(sub->end, <, GNUNET_TIME_absolute_get())) 3169 continue; 3170 3171 if (GNUNET_YES == sub->contact->owned) 3172 return GNUNET_YES; 3173 } 3174 3175 return GNUNET_NO; 3176 } 3177 3178 3179 void 3180 GNUNET_CHAT_discourse_set_user_pointer (struct GNUNET_CHAT_Discourse *discourse, 3181 void *user_pointer) 3182 { 3183 GNUNET_CHAT_VERSION_ASSERT(); 3184 3185 if (!discourse) 3186 return; 3187 3188 discourse->user_pointer = user_pointer; 3189 } 3190 3191 3192 void* 3193 GNUNET_CHAT_discourse_get_user_pointer (const struct GNUNET_CHAT_Discourse *discourse) 3194 { 3195 GNUNET_CHAT_VERSION_ASSERT(); 3196 3197 if (!discourse) 3198 return NULL; 3199 3200 return discourse->user_pointer; 3201 } 3202 3203 3204 void 3205 GNUNET_CHAT_discourse_close (struct GNUNET_CHAT_Discourse *discourse) 3206 { 3207 GNUNET_CHAT_VERSION_ASSERT(); 3208 3209 if ((!discourse) || (!(discourse->context)) || (!(discourse->context->room))) 3210 return; 3211 3212 struct GNUNET_MESSENGER_Message msg; 3213 memset(&msg, 0, sizeof(msg)); 3214 3215 msg.header.kind = GNUNET_MESSENGER_KIND_SUBSCRIBTION; 3216 3217 util_shorthash_from_discourse_id( 3218 &(discourse->id), 3219 &(msg.body.subscription.discourse) 3220 ); 3221 3222 msg.body.subscription.time = GNUNET_TIME_relative_hton(GNUNET_TIME_relative_get_zero_()); 3223 msg.body.subscription.flags = GNUNET_MESSENGER_FLAG_SUBSCRIPTION_UNSUBSCRIBE; 3224 3225 GNUNET_MESSENGER_send_message( 3226 discourse->context->room, 3227 &msg, 3228 NULL 3229 ); 3230 } 3231 3232 3233 enum GNUNET_GenericReturnValue 3234 GNUNET_CHAT_discourse_write (struct GNUNET_CHAT_Discourse *discourse, 3235 const char *data, 3236 uint64_t size) 3237 { 3238 GNUNET_CHAT_VERSION_ASSERT(); 3239 3240 if ((!discourse) || (!data) || (!(discourse->context)) || 3241 (!(discourse->context->room))) 3242 return GNUNET_SYSERR; 3243 3244 static const uint64_t max_size = (uint16_t) ( 3245 GNUNET_MAX_MESSAGE_SIZE - GNUNET_MIN_MESSAGE_SIZE - 3246 sizeof (struct GNUNET_MESSENGER_Message) 3247 ); 3248 3249 struct GNUNET_MESSENGER_Message msg; 3250 memset(&msg, 0, sizeof(msg)); 3251 3252 msg.header.kind = GNUNET_MESSENGER_KIND_TALK; 3253 msg.body.talk.data = GNUNET_malloc(size > max_size? max_size : size); 3254 3255 util_shorthash_from_discourse_id( 3256 &(discourse->id), 3257 &(msg.body.talk.discourse) 3258 ); 3259 3260 while (size > 0) 3261 { 3262 msg.body.talk.length = (uint16_t) (size > max_size? max_size : size); 3263 3264 GNUNET_memcpy( 3265 msg.body.talk.data, 3266 data, 3267 msg.body.talk.length 3268 ); 3269 3270 size -= msg.body.talk.length; 3271 data += msg.body.talk.length; 3272 3273 GNUNET_MESSENGER_send_message(discourse->context->room, &msg, NULL); 3274 } 3275 3276 GNUNET_free(msg.body.talk.data); 3277 return GNUNET_OK; 3278 } 3279 3280 3281 int 3282 GNUNET_CHAT_discourse_get_fd (const struct GNUNET_CHAT_Discourse *discourse) 3283 { 3284 GNUNET_CHAT_VERSION_ASSERT(); 3285 3286 if (! discourse) 3287 return GNUNET_SYSERR; 3288 3289 return discourse->pipe[1]; 3290 } 3291 3292 3293 int 3294 GNUNET_CHAT_discourse_iterate_contacts (struct GNUNET_CHAT_Discourse *discourse, 3295 GNUNET_CHAT_DiscourseContactCallback callback, 3296 void *cls) 3297 { 3298 GNUNET_CHAT_VERSION_ASSERT(); 3299 3300 if (! discourse) 3301 return GNUNET_SYSERR; 3302 3303 int iterations = 0; 3304 3305 struct GNUNET_CHAT_DiscourseSubscription *sub; 3306 for (sub = discourse->head; sub; sub = sub->next) 3307 { 3308 if (GNUNET_TIME_absolute_cmp(sub->end, <, GNUNET_TIME_absolute_get())) 3309 continue; 3310 3311 if (callback) 3312 callback(cls, discourse, sub->contact); 3313 3314 iterations++; 3315 } 3316 3317 return iterations; 3318 } 3319 3320 enum GNUNET_GenericReturnValue 3321 GNUNET_CHAT_generate_secret (char *secret, 3322 uint32_t secret_len) 3323 { 3324 GNUNET_CHAT_VERSION_ASSERT(); 3325 3326 if (secret_len <= 0) 3327 return GNUNET_SYSERR; 3328 3329 const uint32_t requested = secret_len * 5 / 8 + 1; 3330 const uint32_t size = ((requested*8) + (((requested*8) % 5) > 0 ? 5 - ((requested*8) % 5) : 0)) / 5; 3331 3332 char *raw_secret = GNUNET_malloc(requested); 3333 char *buf; 3334 3335 if (!raw_secret) 3336 return GNUNET_SYSERR; 3337 3338 if (size > secret_len) 3339 { 3340 buf = GNUNET_malloc(size); 3341 3342 if (!buf) 3343 { 3344 GNUNET_free(raw_secret); 3345 return GNUNET_SYSERR; 3346 } 3347 } 3348 else 3349 buf = secret; 3350 3351 GNUNET_CRYPTO_random_block( 3352 GNUNET_CRYPTO_QUALITY_STRONG, 3353 raw_secret, 3354 requested 3355 ); 3356 3357 enum GNUNET_GenericReturnValue result; 3358 result = GNUNET_STRINGS_data_to_string( 3359 raw_secret, 3360 requested, 3361 buf, 3362 size 3363 ) == NULL? GNUNET_SYSERR : GNUNET_OK; 3364 3365 GNUNET_CRYPTO_zero_keys(raw_secret, requested); 3366 GNUNET_free(raw_secret); 3367 3368 if (buf != secret) 3369 { 3370 GNUNET_memcpy(secret, buf, secret_len); 3371 GNUNET_CRYPTO_zero_keys(buf, size); 3372 GNUNET_free(buf); 3373 } 3374 3375 return result; 3376 }