gnunet_chat_lib.c (74410B)
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 enum GNUNET_CHAT_LobbyType type, 646 unsigned int delay, 647 GNUNET_CHAT_LobbyCallback callback, 648 void *cls) 649 { 650 GNUNET_CHAT_VERSION_ASSERT(); 651 652 if ((!handle) || (handle->destruction)) 653 return NULL; 654 655 struct GNUNET_TIME_Relative rel = GNUNET_TIME_relative_multiply( 656 GNUNET_TIME_relative_get_second_(), delay 657 ); 658 659 struct GNUNET_CHAT_InternalLobbies *lobbies = GNUNET_new( 660 struct GNUNET_CHAT_InternalLobbies 661 ); 662 663 lobbies->lobby = lobby_create(handle); 664 665 GNUNET_CONTAINER_DLL_insert( 666 handle->lobbies_head, 667 handle->lobbies_tail, 668 lobbies 669 ); 670 671 lobby_open(lobbies->lobby, type, rel, callback, cls); 672 673 return lobbies->lobby; 674 } 675 676 677 void 678 GNUNET_CHAT_lobby_close (struct GNUNET_CHAT_Lobby *lobby) 679 { 680 GNUNET_CHAT_VERSION_ASSERT(); 681 682 if ((!lobby) || (lobby->destruction)) 683 return; 684 685 lobby->destruction = GNUNET_SCHEDULER_add_now( 686 task_lobby_destruction, 687 lobby 688 ); 689 } 690 691 692 void 693 GNUNET_CHAT_lobby_join (struct GNUNET_CHAT_Handle *handle, 694 const struct GNUNET_CHAT_Uri *uri) 695 { 696 GNUNET_CHAT_VERSION_ASSERT(); 697 698 if ((!handle) || (handle->destruction) || (!(handle->gns)) || 699 (!uri) || (GNUNET_CHAT_URI_TYPE_CHAT != uri->type)) 700 return; 701 702 struct GNUNET_CHAT_UriLookups *lookups = GNUNET_new( 703 struct GNUNET_CHAT_UriLookups 704 ); 705 706 lookups->handle = handle; 707 lookups->uri = uri_create_chat( 708 &(uri->chat.zone), 709 uri->chat.label 710 ); 711 712 lookups->request = GNUNET_GNS_lookup( 713 handle->gns, 714 lookups->uri->chat.label, 715 &(uri->chat.zone), 716 GNUNET_GNSRECORD_TYPE_MESSENGER_ROOM_ENTRY, 717 GNUNET_GNS_LO_DEFAULT, 718 cb_lobby_lookup, 719 lookups 720 ); 721 722 GNUNET_CONTAINER_DLL_insert( 723 handle->lookups_head, 724 handle->lookups_tail, 725 lookups 726 ); 727 } 728 729 730 struct GNUNET_CHAT_File* 731 GNUNET_CHAT_request_file (struct GNUNET_CHAT_Handle *handle, 732 const struct GNUNET_CHAT_Uri *uri) 733 { 734 GNUNET_CHAT_VERSION_ASSERT(); 735 736 if ((!handle) || (handle->destruction) || 737 (!uri) || (GNUNET_CHAT_URI_TYPE_FS != uri->type)) 738 return NULL; 739 740 if (!GNUNET_FS_uri_test_chk(uri->fs.uri)) 741 return NULL; 742 743 const struct GNUNET_HashCode *hash = GNUNET_FS_uri_chk_get_file_hash( 744 uri->fs.uri 745 ); 746 747 if (!hash) 748 return NULL; 749 750 struct GNUNET_CHAT_File *file = GNUNET_CONTAINER_multihashmap_get( 751 handle->files, 752 hash 753 ); 754 755 if (file) 756 return file; 757 758 file = file_create_from_chk_uri(handle, uri->fs.uri); 759 760 if (!file) 761 return NULL; 762 763 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put(handle->files, hash, file, 764 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 765 { 766 file_destroy(file); 767 file = NULL; 768 } 769 770 return file; 771 } 772 773 774 struct GNUNET_CHAT_File* 775 GNUNET_CHAT_upload_file (struct GNUNET_CHAT_Handle *handle, 776 const char *path, 777 GNUNET_CHAT_FileUploadCallback callback, 778 void *cls) 779 { 780 GNUNET_CHAT_VERSION_ASSERT(); 781 782 if ((!handle) || (handle->destruction) || 783 (!path)) 784 return NULL; 785 786 struct GNUNET_HashCode hash; 787 if (GNUNET_OK != util_hash_file(path, &hash)) 788 return NULL; 789 790 char *filename = handle_create_file_path( 791 handle, &hash 792 ); 793 794 if (!filename) 795 return NULL; 796 797 struct GNUNET_CHAT_File *file = GNUNET_CONTAINER_multihashmap_get( 798 handle->files, 799 &hash 800 ); 801 802 if (file) 803 goto file_binding; 804 805 if ((GNUNET_YES == GNUNET_DISK_file_test(filename)) || 806 (GNUNET_OK != GNUNET_DISK_directory_create_for_file(filename)) || 807 (GNUNET_OK != GNUNET_DISK_file_copy(path, filename))) 808 { 809 GNUNET_free(filename); 810 return NULL; 811 } 812 813 char* p = GNUNET_strdup(path); 814 815 file = file_create_from_disk( 816 handle, 817 basename(p), 818 &hash 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 char* p = GNUNET_strdup(path); 1905 1906 file = file_create_from_disk( 1907 context->handle, 1908 basename(p), 1909 &hash 1910 ); 1911 1912 GNUNET_free(p); 1913 1914 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 1915 context->handle->files, &hash, file, 1916 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 1917 { 1918 file_destroy(file); 1919 GNUNET_free(filename); 1920 return NULL; 1921 } 1922 1923 struct GNUNET_FS_BlockOptions bo; 1924 1925 bo.anonymity_level = block_anonymity_level; 1926 bo.content_priority = block_content_priority; 1927 bo.replication_level = block_replication_level; 1928 bo.expiration_time = GNUNET_TIME_absolute_get_forever_(); 1929 1930 struct GNUNET_FS_FileInformation* fi = GNUNET_FS_file_information_create_from_file( 1931 context->handle->fs, 1932 file, 1933 filename, 1934 NULL, 1935 file->meta, 1936 GNUNET_YES, 1937 &bo 1938 ); 1939 1940 file->publish = GNUNET_FS_publish_start( 1941 context->handle->fs, fi, 1942 NULL, NULL, NULL, 1943 GNUNET_FS_PUBLISH_OPTION_NONE 1944 ); 1945 1946 if (file->publish) 1947 file->status |= GNUNET_CHAT_FILE_STATUS_PUBLISH; 1948 1949 GNUNET_free(filename); 1950 1951 file_binding: 1952 file_bind_upload(file, context, callback, cls); 1953 return file; 1954 } 1955 1956 1957 enum GNUNET_GenericReturnValue 1958 GNUNET_CHAT_context_share_file (struct GNUNET_CHAT_Context *context, 1959 struct GNUNET_CHAT_File *file) 1960 { 1961 GNUNET_CHAT_VERSION_ASSERT(); 1962 1963 if ((!context) || (!file) || 1964 (!(file->name)) || (strlen(file->name) > NAME_MAX) || 1965 (!(file->uri)) || (!(context->room))) 1966 return GNUNET_SYSERR; 1967 1968 struct GNUNET_MESSENGER_Message msg; 1969 memset(&msg, 0, sizeof(msg)); 1970 1971 msg.header.kind = GNUNET_MESSENGER_KIND_FILE; 1972 1973 GNUNET_memcpy(&(msg.body.file.hash), &(file->hash), sizeof(file->hash)); 1974 GNUNET_strlcpy(msg.body.file.name, file->name, NAME_MAX); 1975 msg.body.file.uri = GNUNET_FS_uri_to_string(file->uri); 1976 1977 GNUNET_MESSENGER_send_message(context->room, &msg, NULL); 1978 1979 GNUNET_free(msg.body.file.uri); 1980 return GNUNET_OK; 1981 } 1982 1983 1984 enum GNUNET_GenericReturnValue 1985 GNUNET_CHAT_context_send_tag (struct GNUNET_CHAT_Context *context, 1986 struct GNUNET_CHAT_Message *message, 1987 const char *tag) 1988 { 1989 GNUNET_CHAT_VERSION_ASSERT(); 1990 1991 if ((!context) || (!message) || (!tag) || (!(context->room))) 1992 return GNUNET_SYSERR; 1993 1994 char *tag_value = GNUNET_strdup(tag); 1995 1996 struct GNUNET_MESSENGER_Message msg; 1997 memset(&msg, 0, sizeof(msg)); 1998 1999 msg.header.kind = GNUNET_MESSENGER_KIND_TAG; 2000 GNUNET_memcpy(&(msg.body.tag.hash), &(message->hash), 2001 sizeof(struct GNUNET_HashCode)); 2002 msg.body.tag.tag = tag_value; 2003 2004 GNUNET_MESSENGER_send_message( 2005 context->room, 2006 &msg, 2007 NULL 2008 ); 2009 2010 GNUNET_free(tag_value); 2011 return GNUNET_OK; 2012 } 2013 2014 2015 struct GNUNET_CHAT_Discourse* 2016 GNUNET_CHAT_context_open_discourse (struct GNUNET_CHAT_Context *context, 2017 const struct GNUNET_CHAT_DiscourseId *id) 2018 { 2019 GNUNET_CHAT_VERSION_ASSERT(); 2020 2021 if ((!context) || (!(context->discourses)) || (!(context->room)) || (!id)) 2022 return NULL; 2023 2024 struct GNUNET_ShortHashCode sid; 2025 util_shorthash_from_discourse_id(id, &sid); 2026 2027 struct GNUNET_CHAT_Discourse *discourse = GNUNET_CONTAINER_multishortmap_get( 2028 context->discourses, &sid 2029 ); 2030 2031 if (!discourse) 2032 { 2033 discourse = discourse_create(context, id); 2034 2035 if (GNUNET_OK != GNUNET_CONTAINER_multishortmap_put(context->discourses, 2036 &sid, discourse, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 2037 { 2038 discourse_destroy(discourse); 2039 return NULL; 2040 } 2041 } 2042 2043 struct GNUNET_MESSENGER_Message msg; 2044 memset(&msg, 0, sizeof(msg)); 2045 2046 msg.header.kind = GNUNET_MESSENGER_KIND_SUBSCRIBTION; 2047 GNUNET_memcpy( 2048 &(msg.body.subscription.discourse), 2049 &sid, 2050 sizeof(struct GNUNET_ShortHashCode) 2051 ); 2052 2053 const struct GNUNET_TIME_Relative subscription_time = GNUNET_TIME_relative_multiply( 2054 GNUNET_TIME_relative_get_second_(), 10 2055 ); 2056 2057 msg.body.subscription.time = GNUNET_TIME_relative_hton(subscription_time); 2058 msg.body.subscription.flags = GNUNET_MESSENGER_FLAG_SUBSCRIPTION_KEEP_ALIVE; 2059 2060 GNUNET_MESSENGER_send_message( 2061 context->room, 2062 &msg, 2063 NULL 2064 ); 2065 2066 return discourse; 2067 } 2068 2069 2070 int 2071 GNUNET_CHAT_context_iterate_messages (struct GNUNET_CHAT_Context *context, 2072 GNUNET_CHAT_ContextMessageCallback callback, 2073 void *cls) 2074 { 2075 GNUNET_CHAT_VERSION_ASSERT(); 2076 2077 if (!context) 2078 return GNUNET_SYSERR; 2079 2080 struct GNUNET_CHAT_ContextIterateMessages it; 2081 it.context = context; 2082 it.cb = callback; 2083 it.cls = cls; 2084 2085 return GNUNET_CONTAINER_multihashmap_iterate( 2086 context->messages, it_context_iterate_messages, &it 2087 ); 2088 } 2089 2090 2091 int 2092 GNUNET_CHAT_context_iterate_files (struct GNUNET_CHAT_Context *context, 2093 GNUNET_CHAT_ContextFileCallback callback, 2094 void *cls) 2095 { 2096 GNUNET_CHAT_VERSION_ASSERT(); 2097 2098 if (!context) 2099 return GNUNET_SYSERR; 2100 2101 struct GNUNET_CHAT_ContextIterateFiles it; 2102 it.context = context; 2103 it.cb = callback; 2104 it.cls = cls; 2105 2106 return GNUNET_CONTAINER_multihashmap_iterate( 2107 context->files, it_context_iterate_files, &it 2108 ); 2109 } 2110 2111 2112 enum GNUNET_CHAT_MessageKind 2113 GNUNET_CHAT_message_get_kind (const struct GNUNET_CHAT_Message *message) 2114 { 2115 GNUNET_CHAT_VERSION_ASSERT(); 2116 2117 if (!message) 2118 return GNUNET_CHAT_KIND_UNKNOWN; 2119 2120 switch (message->flag) 2121 { 2122 case GNUNET_CHAT_FLAG_WARNING: 2123 return GNUNET_CHAT_KIND_WARNING; 2124 case GNUNET_CHAT_FLAG_REFRESH: 2125 return GNUNET_CHAT_KIND_REFRESH; 2126 case GNUNET_CHAT_FLAG_LOGIN: 2127 return GNUNET_CHAT_KIND_LOGIN; 2128 case GNUNET_CHAT_FLAG_LOGOUT: 2129 return GNUNET_CHAT_KIND_LOGOUT; 2130 case GNUNET_CHAT_FLAG_CREATE_ACCOUNT: 2131 return GNUNET_CHAT_KIND_CREATED_ACCOUNT; 2132 case GNUNET_CHAT_FLAG_DELETE_ACCOUNT: 2133 return GNUNET_CHAT_KIND_DELETED_ACCOUNT; 2134 case GNUNET_CHAT_FLAG_UPDATE_ACCOUNT: 2135 return GNUNET_CHAT_KIND_UPDATE_ACCOUNT; 2136 case GNUNET_CHAT_FLAG_UPDATE_CONTEXT: 2137 return GNUNET_CHAT_KIND_UPDATE_CONTEXT; 2138 case GNUNET_CHAT_FLAG_ATTRIBUTES: 2139 return GNUNET_CHAT_KIND_ATTRIBUTES; 2140 case GNUNET_CHAT_FLAG_SHARE_ATTRIBUTES: 2141 return GNUNET_CHAT_KIND_SHARED_ATTRIBUTES; 2142 default: 2143 break; 2144 } 2145 2146 if (GNUNET_YES != message_has_msg(message)) 2147 return GNUNET_CHAT_KIND_UNKNOWN; 2148 2149 return util_message_kind_from_kind(message->msg->header.kind); 2150 } 2151 2152 2153 time_t 2154 GNUNET_CHAT_message_get_timestamp (const struct GNUNET_CHAT_Message *message) 2155 { 2156 GNUNET_CHAT_VERSION_ASSERT(); 2157 2158 if ((!message) || (GNUNET_YES != message_has_msg(message))) 2159 return ((time_t) -1); 2160 2161 struct GNUNET_TIME_Absolute abs = GNUNET_TIME_absolute_ntoh( 2162 message->msg->header.timestamp 2163 ); 2164 2165 struct GNUNET_TIME_Timestamp ts = GNUNET_TIME_absolute_to_timestamp( 2166 abs 2167 ); 2168 2169 return (time_t) GNUNET_TIME_timestamp_to_s(ts); 2170 } 2171 2172 2173 struct GNUNET_CHAT_Contact* 2174 GNUNET_CHAT_message_get_sender (const struct GNUNET_CHAT_Message *message) 2175 { 2176 GNUNET_CHAT_VERSION_ASSERT(); 2177 2178 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2179 (!(message->context)) || (!(message->context->room))) 2180 return NULL; 2181 2182 const struct GNUNET_MESSENGER_Contact *sender = GNUNET_MESSENGER_get_sender( 2183 message->context->room, &(message->hash) 2184 ); 2185 2186 if (!sender) 2187 return NULL; 2188 2189 return handle_get_contact_from_messenger(message->context->handle, sender); 2190 } 2191 2192 2193 struct GNUNET_CHAT_Contact* 2194 GNUNET_CHAT_message_get_recipient (const struct GNUNET_CHAT_Message *message) 2195 { 2196 GNUNET_CHAT_VERSION_ASSERT(); 2197 2198 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2199 (!(message->context)) || (!(message->context->room))) 2200 return NULL; 2201 2202 const struct GNUNET_MESSENGER_Contact *recipient = GNUNET_MESSENGER_get_recipient( 2203 message->context->room, &(message->hash) 2204 ); 2205 2206 if (!recipient) 2207 return NULL; 2208 2209 return handle_get_contact_from_messenger(message->context->handle, recipient); 2210 } 2211 2212 2213 enum GNUNET_GenericReturnValue 2214 GNUNET_CHAT_message_is_sent (const struct GNUNET_CHAT_Message *message) 2215 { 2216 GNUNET_CHAT_VERSION_ASSERT(); 2217 2218 if (!message) 2219 return GNUNET_SYSERR; 2220 2221 if (message->flags & GNUNET_MESSENGER_FLAG_SENT) 2222 return GNUNET_YES; 2223 else 2224 return GNUNET_NO; 2225 } 2226 2227 2228 enum GNUNET_GenericReturnValue 2229 GNUNET_CHAT_message_is_private (const struct GNUNET_CHAT_Message *message) 2230 { 2231 GNUNET_CHAT_VERSION_ASSERT(); 2232 2233 if (!message) 2234 return GNUNET_SYSERR; 2235 2236 if (message->flags & GNUNET_MESSENGER_FLAG_PRIVATE) 2237 return GNUNET_YES; 2238 else 2239 return GNUNET_NO; 2240 } 2241 2242 2243 enum GNUNET_GenericReturnValue 2244 GNUNET_CHAT_message_is_recent (const struct GNUNET_CHAT_Message *message) 2245 { 2246 GNUNET_CHAT_VERSION_ASSERT(); 2247 2248 if (!message) 2249 return GNUNET_SYSERR; 2250 2251 if (message->flags & GNUNET_MESSENGER_FLAG_RECENT) 2252 return GNUNET_YES; 2253 else 2254 return GNUNET_NO; 2255 } 2256 2257 2258 enum GNUNET_GenericReturnValue 2259 GNUNET_CHAT_message_is_update (const struct GNUNET_CHAT_Message *message) 2260 { 2261 GNUNET_CHAT_VERSION_ASSERT(); 2262 2263 if (!message) 2264 return GNUNET_SYSERR; 2265 2266 if (message->flags & GNUNET_MESSENGER_FLAG_UPDATE) 2267 return GNUNET_YES; 2268 else 2269 return GNUNET_NO; 2270 } 2271 2272 2273 enum GNUNET_GenericReturnValue 2274 GNUNET_CHAT_message_is_deleted (const struct GNUNET_CHAT_Message *message) 2275 { 2276 GNUNET_CHAT_VERSION_ASSERT(); 2277 2278 if (!message) 2279 return GNUNET_SYSERR; 2280 2281 if ((GNUNET_CHAT_FLAG_NONE == message->flag) && 2282 ((message->flags & GNUNET_MESSENGER_FLAG_DELETE) || 2283 (!message->msg))) 2284 return GNUNET_YES; 2285 else 2286 return GNUNET_NO; 2287 } 2288 2289 2290 enum GNUNET_GenericReturnValue 2291 GNUNET_CHAT_message_is_tagged (const struct GNUNET_CHAT_Message *message, 2292 const char *tag) 2293 { 2294 GNUNET_CHAT_VERSION_ASSERT(); 2295 2296 if ((!message) || (!(message->context))) 2297 return GNUNET_SYSERR; 2298 2299 const struct GNUNET_CHAT_InternalTagging *tagging = GNUNET_CONTAINER_multihashmap_get( 2300 message->context->taggings, &(message->hash)); 2301 2302 if (!tagging) 2303 return GNUNET_NO; 2304 2305 if (internal_tagging_iterate(tagging, GNUNET_NO, tag, NULL, NULL) > 0) 2306 return GNUNET_YES; 2307 else 2308 return GNUNET_NO; 2309 } 2310 2311 2312 int 2313 GNUNET_CHAT_message_get_read_receipt (struct GNUNET_CHAT_Message *message, 2314 GNUNET_CHAT_MessageReadReceiptCallback callback, 2315 void *cls) 2316 { 2317 GNUNET_CHAT_VERSION_ASSERT(); 2318 2319 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2320 (!(message->context))) 2321 return GNUNET_SYSERR; 2322 2323 struct GNUNET_CHAT_MessageIterateReadReceipts it; 2324 it.message = message; 2325 it.cb = callback; 2326 it.cls = cls; 2327 2328 return GNUNET_MESSENGER_iterate_members( 2329 message->context->room, it_message_iterate_read_receipts, &it 2330 ); 2331 } 2332 2333 2334 const char* 2335 GNUNET_CHAT_message_get_text (const struct GNUNET_CHAT_Message *message) 2336 { 2337 GNUNET_CHAT_VERSION_ASSERT(); 2338 2339 if (!message) 2340 return NULL; 2341 2342 if (GNUNET_CHAT_FLAG_WARNING == message->flag) 2343 return message->warning; 2344 else if (GNUNET_CHAT_FLAG_UPDATE_ACCOUNT == message->flag) 2345 return message->warning; 2346 else if (GNUNET_CHAT_FLAG_ATTRIBUTES == message->flag) 2347 return message->attr; 2348 2349 if (GNUNET_YES != message_has_msg(message)) 2350 return NULL; 2351 2352 if (GNUNET_MESSENGER_KIND_TEXT == message->msg->header.kind) 2353 return message->msg->body.text.text; 2354 else if (GNUNET_MESSENGER_KIND_FILE == message->msg->header.kind) 2355 return message->msg->body.file.name; 2356 else if (GNUNET_MESSENGER_KIND_TAG == message->msg->header.kind) 2357 return message->msg->body.tag.tag; 2358 else 2359 return NULL; 2360 } 2361 2362 2363 void 2364 GNUNET_CHAT_message_set_user_pointer (struct GNUNET_CHAT_Message *message, 2365 void *user_pointer) 2366 { 2367 GNUNET_CHAT_VERSION_ASSERT(); 2368 2369 if (!message) 2370 return; 2371 2372 message->user_pointer = user_pointer; 2373 } 2374 2375 2376 void* 2377 GNUNET_CHAT_message_get_user_pointer (const struct GNUNET_CHAT_Message *message) 2378 { 2379 GNUNET_CHAT_VERSION_ASSERT(); 2380 2381 if (!message) 2382 return NULL; 2383 2384 return message->user_pointer; 2385 } 2386 2387 2388 struct GNUNET_CHAT_Account* 2389 GNUNET_CHAT_message_get_account (const struct GNUNET_CHAT_Message *message) 2390 { 2391 GNUNET_CHAT_VERSION_ASSERT(); 2392 2393 if (!message) 2394 return NULL; 2395 2396 if ((message->context) && (message->context->handle)) 2397 return message->context->handle->current; 2398 else 2399 return message->account; 2400 } 2401 2402 2403 struct GNUNET_CHAT_File* 2404 GNUNET_CHAT_message_get_file (const struct GNUNET_CHAT_Message *message) 2405 { 2406 GNUNET_CHAT_VERSION_ASSERT(); 2407 2408 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2409 (!(message->context))) 2410 return NULL; 2411 2412 if (GNUNET_MESSENGER_KIND_FILE != message->msg->header.kind) 2413 return NULL; 2414 2415 return GNUNET_CONTAINER_multihashmap_get( 2416 message->context->handle->files, 2417 &(message->msg->body.file.hash) 2418 ); 2419 } 2420 2421 2422 struct GNUNET_CHAT_Invitation* 2423 GNUNET_CHAT_message_get_invitation (const struct GNUNET_CHAT_Message *message) 2424 { 2425 GNUNET_CHAT_VERSION_ASSERT(); 2426 2427 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2428 (!(message->context))) 2429 return NULL; 2430 2431 if (GNUNET_MESSENGER_KIND_INVITE != message->msg->header.kind) 2432 return NULL; 2433 2434 return GNUNET_CONTAINER_multihashmap_get( 2435 message->context->invites, 2436 &(message->hash) 2437 ); 2438 } 2439 2440 2441 struct GNUNET_CHAT_Discourse* 2442 GNUNET_CHAT_message_get_discourse (const struct GNUNET_CHAT_Message *message) 2443 { 2444 GNUNET_CHAT_VERSION_ASSERT(); 2445 2446 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2447 (!(message->context)) || (!(message->context->discourses))) 2448 return NULL; 2449 2450 struct GNUNET_CHAT_Discourse *discourse; 2451 2452 if (GNUNET_MESSENGER_KIND_SUBSCRIBTION == message->msg->header.kind) 2453 discourse = GNUNET_CONTAINER_multishortmap_get( 2454 message->context->discourses, 2455 &(message->msg->body.subscription.discourse)); 2456 else if (GNUNET_MESSENGER_KIND_TALK == message->msg->header.kind) 2457 discourse = GNUNET_CONTAINER_multishortmap_get( 2458 message->context->discourses, 2459 &(message->msg->body.talk.discourse)); 2460 else 2461 discourse = NULL; 2462 2463 return discourse; 2464 } 2465 2466 2467 struct GNUNET_CHAT_Message* 2468 GNUNET_CHAT_message_get_target (const struct GNUNET_CHAT_Message *message) 2469 { 2470 GNUNET_CHAT_VERSION_ASSERT(); 2471 2472 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2473 (!(message->context))) 2474 return NULL; 2475 2476 struct GNUNET_CHAT_Message *target; 2477 2478 if (GNUNET_MESSENGER_KIND_DELETION == message->msg->header.kind) 2479 target = GNUNET_CONTAINER_multihashmap_get( 2480 message->context->messages, &(message->msg->body.deletion.hash)); 2481 else if (GNUNET_MESSENGER_KIND_TAG == message->msg->header.kind) 2482 target = GNUNET_CONTAINER_multihashmap_get( 2483 message->context->messages, &(message->msg->body.tag.hash)); 2484 else 2485 target = NULL; 2486 2487 return target; 2488 } 2489 2490 2491 enum GNUNET_GenericReturnValue 2492 GNUNET_CHAT_message_delete (struct GNUNET_CHAT_Message *message, 2493 unsigned int delay) 2494 { 2495 GNUNET_CHAT_VERSION_ASSERT(); 2496 2497 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2498 (!(message->context))) 2499 return GNUNET_SYSERR; 2500 2501 struct GNUNET_TIME_Relative rel = GNUNET_TIME_relative_multiply( 2502 GNUNET_TIME_relative_get_second_(), delay 2503 ); 2504 2505 GNUNET_MESSENGER_delete_message( 2506 message->context->room, 2507 &(message->hash), 2508 rel 2509 ); 2510 2511 return GNUNET_OK; 2512 } 2513 2514 2515 int 2516 GNUNET_CHAT_message_iterate_tags (struct GNUNET_CHAT_Message *message, 2517 GNUNET_CHAT_MessageCallback callback, 2518 void *cls) 2519 { 2520 GNUNET_CHAT_VERSION_ASSERT(); 2521 2522 if ((!message) || (!(message->context))) 2523 return GNUNET_SYSERR; 2524 2525 const struct GNUNET_CHAT_InternalTagging *tagging = GNUNET_CONTAINER_multihashmap_get( 2526 message->context->taggings, &(message->hash)); 2527 2528 if (!tagging) 2529 return 0; 2530 2531 return internal_tagging_iterate(tagging, GNUNET_YES, NULL, callback, cls); 2532 } 2533 2534 2535 uint64_t 2536 GNUNET_CHAT_message_available (const struct GNUNET_CHAT_Message *message) 2537 { 2538 GNUNET_CHAT_VERSION_ASSERT(); 2539 2540 if ((!message) || (GNUNET_YES != message_has_msg(message))) 2541 return 0; 2542 2543 if (GNUNET_MESSENGER_KIND_TALK == message->msg->header.kind) 2544 return message->msg->body.talk.length; 2545 else 2546 return 0; 2547 } 2548 2549 2550 enum GNUNET_GenericReturnValue 2551 GNUNET_CHAT_message_read (const struct GNUNET_CHAT_Message *message, 2552 char *data, 2553 uint64_t size) 2554 { 2555 GNUNET_CHAT_VERSION_ASSERT(); 2556 2557 if ((!message) || (GNUNET_YES != message_has_msg(message))) 2558 return GNUNET_SYSERR; 2559 2560 if (GNUNET_MESSENGER_KIND_TALK != message->msg->header.kind) 2561 return GNUNET_SYSERR; 2562 2563 const uint64_t available = message->msg->body.talk.length; 2564 2565 if (available < size) 2566 return GNUNET_NO; 2567 2568 GNUNET_memcpy( 2569 data, 2570 message->msg->body.talk.data, 2571 size 2572 ); 2573 2574 return GNUNET_OK; 2575 } 2576 2577 2578 enum GNUNET_GenericReturnValue 2579 GNUNET_CHAT_message_feed (const struct GNUNET_CHAT_Message *message, 2580 int fd) 2581 { 2582 GNUNET_CHAT_VERSION_ASSERT(); 2583 2584 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2585 (fd == -1)) 2586 return GNUNET_SYSERR; 2587 2588 if (GNUNET_MESSENGER_KIND_TALK != message->msg->header.kind) 2589 return GNUNET_SYSERR; 2590 2591 if (!(message->msg->body.talk.length)) 2592 return GNUNET_NO; 2593 2594 const ssize_t written = write( 2595 fd, 2596 message->msg->body.talk.data, 2597 message->msg->body.talk.length 2598 ); 2599 2600 if (-1 == written) 2601 return GNUNET_SYSERR; 2602 else if (written != message->msg->body.talk.length) 2603 return GNUNET_NO; 2604 else 2605 return GNUNET_OK; 2606 } 2607 2608 2609 const char* 2610 GNUNET_CHAT_file_get_name (const struct GNUNET_CHAT_File *file) 2611 { 2612 GNUNET_CHAT_VERSION_ASSERT(); 2613 2614 if (!file) 2615 return NULL; 2616 2617 return file->name; 2618 } 2619 2620 2621 const char* 2622 GNUNET_CHAT_file_get_hash (const struct GNUNET_CHAT_File *file) 2623 { 2624 GNUNET_CHAT_VERSION_ASSERT(); 2625 2626 if (!file) 2627 return NULL; 2628 2629 return GNUNET_h2s_full(&(file->hash)); 2630 } 2631 2632 2633 uint64_t 2634 GNUNET_CHAT_file_get_size (const struct GNUNET_CHAT_File *file) 2635 { 2636 GNUNET_CHAT_VERSION_ASSERT(); 2637 2638 if ((!file) || (!(file->uri))) 2639 return 0; 2640 2641 return GNUNET_FS_uri_chk_get_file_size(file->uri); 2642 } 2643 2644 2645 uint64_t 2646 GNUNET_CHAT_file_get_local_size (const struct GNUNET_CHAT_File *file) 2647 { 2648 GNUNET_CHAT_VERSION_ASSERT(); 2649 2650 if (!file) 2651 return 0; 2652 2653 char *filename = handle_create_file_path( 2654 file->handle, &(file->hash) 2655 ); 2656 2657 if (!filename) 2658 return 0; 2659 2660 uint64_t size; 2661 if (GNUNET_OK != GNUNET_DISK_file_size(filename, &size, GNUNET_NO, GNUNET_YES)) 2662 size = 0; 2663 2664 GNUNET_free(filename); 2665 return size; 2666 } 2667 2668 2669 struct GNUNET_CHAT_Uri* 2670 GNUNET_CHAT_file_get_uri (const struct GNUNET_CHAT_File *file) 2671 { 2672 GNUNET_CHAT_VERSION_ASSERT(); 2673 2674 if ((!file) || (!(file->uri))) 2675 return NULL; 2676 2677 return uri_create_file(file->uri); 2678 } 2679 2680 2681 enum GNUNET_GenericReturnValue 2682 GNUNET_CHAT_file_is_uploading (const struct GNUNET_CHAT_File *file) 2683 { 2684 GNUNET_CHAT_VERSION_ASSERT(); 2685 2686 if ((!file) || (0 == (file->status & GNUNET_CHAT_FILE_STATUS_PUBLISH))) 2687 return GNUNET_NO; 2688 else 2689 return GNUNET_YES; 2690 } 2691 2692 2693 enum GNUNET_GenericReturnValue 2694 GNUNET_CHAT_file_stop_upload (struct GNUNET_CHAT_File *file) 2695 { 2696 GNUNET_CHAT_VERSION_ASSERT(); 2697 2698 if (!file) 2699 return GNUNET_SYSERR; 2700 2701 if (!file->publish) 2702 return GNUNET_SYSERR; 2703 2704 GNUNET_FS_publish_stop(file->publish); 2705 file->publish = NULL; 2706 return GNUNET_OK; 2707 } 2708 2709 2710 enum GNUNET_GenericReturnValue 2711 GNUNET_CHAT_file_is_ready (const struct GNUNET_CHAT_File *file) 2712 { 2713 GNUNET_CHAT_VERSION_ASSERT(); 2714 2715 if ((!file) || (file->status & GNUNET_CHAT_FILE_STATUS_MASK)) 2716 return GNUNET_NO; 2717 2718 const uint64_t size = GNUNET_CHAT_file_get_size(file); 2719 const uint64_t local_size = GNUNET_CHAT_file_get_local_size(file); 2720 2721 if (size != local_size) 2722 return GNUNET_NO; 2723 else 2724 return GNUNET_YES; 2725 } 2726 2727 2728 enum GNUNET_GenericReturnValue 2729 GNUNET_CHAT_file_is_valid (const struct GNUNET_CHAT_File *file) 2730 { 2731 GNUNET_CHAT_VERSION_ASSERT(); 2732 2733 if ((!file) || (file->status & GNUNET_CHAT_FILE_STATUS_MASK)) 2734 return GNUNET_SYSERR; 2735 2736 char *filename = handle_create_file_path( 2737 file->handle, &(file->hash) 2738 ); 2739 2740 if (!filename) 2741 return GNUNET_SYSERR; 2742 2743 struct GNUNET_HashCode hash; 2744 enum GNUNET_GenericReturnValue result; 2745 2746 if (GNUNET_OK == util_hash_file(filename, &hash)) 2747 { 2748 if (0 == GNUNET_CRYPTO_hash_cmp(&hash, &(file->hash))) 2749 result = GNUNET_YES; 2750 else 2751 result = GNUNET_NO; 2752 } 2753 else 2754 result = GNUNET_SYSERR; 2755 2756 GNUNET_free(filename); 2757 return result; 2758 } 2759 2760 2761 const char* 2762 GNUNET_CHAT_file_open_preview (struct GNUNET_CHAT_File *file) 2763 { 2764 GNUNET_CHAT_VERSION_ASSERT(); 2765 2766 if (!file) 2767 return NULL; 2768 2769 if (file->preview) 2770 return file->preview; 2771 2772 char *filename = handle_create_file_path( 2773 file->handle, &(file->hash) 2774 ); 2775 2776 if (!filename) 2777 return NULL; 2778 2779 if (GNUNET_YES != GNUNET_DISK_file_test(filename)) 2780 { 2781 GNUNET_free(filename); 2782 filename = NULL; 2783 } 2784 2785 file->preview = filename; 2786 return file->preview; 2787 } 2788 2789 2790 void 2791 GNUNET_CHAT_file_close_preview (struct GNUNET_CHAT_File *file) 2792 { 2793 GNUNET_CHAT_VERSION_ASSERT(); 2794 2795 if ((!file) || (!(file->preview))) 2796 return; 2797 2798 GNUNET_free(file->preview); 2799 file->preview = NULL; 2800 } 2801 2802 2803 void 2804 GNUNET_CHAT_file_set_user_pointer (struct GNUNET_CHAT_File *file, 2805 void *user_pointer) 2806 { 2807 GNUNET_CHAT_VERSION_ASSERT(); 2808 2809 if (!file) 2810 return; 2811 2812 file->user_pointer = user_pointer; 2813 } 2814 2815 2816 void* 2817 GNUNET_CHAT_file_get_user_pointer (const struct GNUNET_CHAT_File *file) 2818 { 2819 GNUNET_CHAT_VERSION_ASSERT(); 2820 2821 if (!file) 2822 return NULL; 2823 2824 return file->user_pointer; 2825 } 2826 2827 2828 enum GNUNET_GenericReturnValue 2829 GNUNET_CHAT_file_is_downloading (const struct GNUNET_CHAT_File *file) 2830 { 2831 GNUNET_CHAT_VERSION_ASSERT(); 2832 2833 if ((!file) || (0 == (file->status & GNUNET_CHAT_FILE_STATUS_DOWNLOAD))) 2834 return GNUNET_NO; 2835 else 2836 return GNUNET_YES; 2837 } 2838 2839 2840 enum GNUNET_GenericReturnValue 2841 GNUNET_CHAT_file_start_download (struct GNUNET_CHAT_File *file, 2842 GNUNET_CHAT_FileDownloadCallback callback, 2843 void *cls) 2844 { 2845 GNUNET_CHAT_VERSION_ASSERT(); 2846 2847 if ((!file) || (!(file->uri))) 2848 return GNUNET_SYSERR; 2849 2850 if (file->download) 2851 { 2852 file_bind_downlaod(file, callback, cls); 2853 2854 GNUNET_FS_download_resume(file->download); 2855 return GNUNET_OK; 2856 } 2857 2858 char *filename = handle_create_file_path( 2859 file->handle, &(file->hash) 2860 ); 2861 2862 if (!filename) 2863 return GNUNET_SYSERR; 2864 2865 const uint64_t size = GNUNET_FS_uri_chk_get_file_size(file->uri); 2866 2867 uint64_t offset; 2868 if (GNUNET_OK != GNUNET_DISK_file_size(filename, &offset, 2869 GNUNET_NO, GNUNET_YES)) 2870 offset = 0; 2871 2872 if (offset >= size) 2873 { 2874 if (callback) 2875 callback(cls, file, size, size); 2876 2877 goto free_filename; 2878 } 2879 2880 file_bind_downlaod(file, callback, cls); 2881 2882 const uint64_t remaining = (size - offset); 2883 2884 file->download = GNUNET_FS_download_start( 2885 file->handle->fs, 2886 file->uri, 2887 file->meta, 2888 filename, 2889 NULL, 2890 offset, 2891 remaining, 2892 1, 2893 GNUNET_FS_DOWNLOAD_OPTION_NONE, 2894 file, 2895 NULL 2896 ); 2897 2898 if (file->download) 2899 file->status |= GNUNET_CHAT_FILE_STATUS_DOWNLOAD; 2900 2901 free_filename: 2902 GNUNET_free(filename); 2903 return GNUNET_OK; 2904 } 2905 2906 2907 enum GNUNET_GenericReturnValue 2908 GNUNET_CHAT_file_pause_download (struct GNUNET_CHAT_File *file) 2909 { 2910 GNUNET_CHAT_VERSION_ASSERT(); 2911 2912 if (!file) 2913 return GNUNET_SYSERR; 2914 2915 if (!file->download) 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 if (!file->download) 2932 return GNUNET_SYSERR; 2933 2934 GNUNET_FS_download_resume(file->download); 2935 return GNUNET_OK; 2936 } 2937 2938 2939 enum GNUNET_GenericReturnValue 2940 GNUNET_CHAT_file_stop_download (struct GNUNET_CHAT_File *file) 2941 { 2942 GNUNET_CHAT_VERSION_ASSERT(); 2943 2944 if (!file) 2945 return GNUNET_SYSERR; 2946 2947 if (!file->download) 2948 return GNUNET_SYSERR; 2949 2950 GNUNET_FS_download_stop(file->download, GNUNET_YES); 2951 file->download = NULL; 2952 return GNUNET_OK; 2953 } 2954 2955 2956 enum GNUNET_GenericReturnValue 2957 GNUNET_CHAT_file_is_unindexing (const struct GNUNET_CHAT_File *file) 2958 { 2959 GNUNET_CHAT_VERSION_ASSERT(); 2960 2961 if ((!file) || (0 == (file->status & GNUNET_CHAT_FILE_STATUS_UNINDEX))) 2962 return GNUNET_NO; 2963 else 2964 return GNUNET_YES; 2965 } 2966 2967 2968 enum GNUNET_GenericReturnValue 2969 GNUNET_CHAT_file_unindex (struct GNUNET_CHAT_File *file, 2970 GNUNET_CHAT_FileUnindexCallback callback, 2971 void *cls) 2972 { 2973 GNUNET_CHAT_VERSION_ASSERT(); 2974 2975 if (!file) 2976 return GNUNET_SYSERR; 2977 2978 if (file->publish) 2979 { 2980 GNUNET_FS_publish_stop(file->publish); 2981 file->publish = NULL; 2982 return GNUNET_OK; 2983 } 2984 2985 file_bind_unindex(file, callback, cls); 2986 2987 if (file->unindex) 2988 return GNUNET_OK; 2989 2990 char *filename = handle_create_file_path( 2991 file->handle, &(file->hash) 2992 ); 2993 2994 if (!filename) 2995 return GNUNET_SYSERR; 2996 2997 file->unindex = GNUNET_FS_unindex_start( 2998 file->handle->fs, filename, file 2999 ); 3000 3001 if (file->unindex) 3002 file->status |= GNUNET_CHAT_FILE_STATUS_UNINDEX; 3003 3004 GNUNET_free(filename); 3005 return GNUNET_OK; 3006 } 3007 3008 3009 void 3010 GNUNET_CHAT_invitation_accept (struct GNUNET_CHAT_Invitation *invitation) 3011 { 3012 GNUNET_CHAT_VERSION_ASSERT(); 3013 3014 if (!invitation) 3015 return; 3016 3017 struct GNUNET_CHAT_Handle *handle; 3018 handle = invitation->context->handle; 3019 3020 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains( 3021 handle->contexts, &(invitation->key.hash))) 3022 return; 3023 3024 struct GNUNET_PeerIdentity door; 3025 GNUNET_PEER_resolve(invitation->door, &door); 3026 3027 struct GNUNET_MESSENGER_Room *room; 3028 room = GNUNET_MESSENGER_enter_room( 3029 invitation->context->handle->messenger, 3030 &door, &(invitation->key) 3031 ); 3032 3033 if (!room) 3034 return; 3035 3036 struct GNUNET_CHAT_Context *context; 3037 context = context_create_from_room(handle, room); 3038 3039 if (!context) 3040 return; 3041 3042 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 3043 handle->contexts, &(invitation->key.hash), context, 3044 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 3045 goto destroy_context; 3046 3047 if (GNUNET_CHAT_CONTEXT_TYPE_GROUP != context->type) 3048 { 3049 context_write_records(context); 3050 return; 3051 } 3052 3053 struct GNUNET_CHAT_Group *group; 3054 group = group_create_from_context(handle, context); 3055 3056 if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put( 3057 handle->groups, &(invitation->key.hash), group, 3058 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 3059 { 3060 context_write_records(context); 3061 return; 3062 } 3063 3064 group_destroy(group); 3065 3066 GNUNET_CONTAINER_multihashmap_remove( 3067 handle->contexts, &(invitation->key.hash), context); 3068 3069 destroy_context: 3070 context_destroy(context); 3071 } 3072 3073 3074 void 3075 GNUNET_CHAT_invitation_reject (struct GNUNET_CHAT_Invitation *invitation) 3076 { 3077 GNUNET_CHAT_VERSION_ASSERT(); 3078 3079 if (!invitation) 3080 return; 3081 3082 const struct GNUNET_MESSENGER_Contact *sender = GNUNET_MESSENGER_get_sender( 3083 invitation->context->room, &(invitation->hash) 3084 ); 3085 3086 if (!sender) 3087 return; 3088 3089 struct GNUNET_MESSENGER_Message msg; 3090 memset(&msg, 0, sizeof(msg)); 3091 3092 msg.header.kind = GNUNET_MESSENGER_KIND_TAG; 3093 GNUNET_memcpy(&(msg.body.tag.hash), &(invitation->hash), 3094 sizeof(struct GNUNET_HashCode)); 3095 msg.body.tag.tag = NULL; 3096 3097 GNUNET_MESSENGER_send_message(invitation->context->room, &msg, sender); 3098 } 3099 3100 3101 enum GNUNET_GenericReturnValue 3102 GNUNET_CHAT_invitation_is_accepted (const struct GNUNET_CHAT_Invitation *invitation) 3103 { 3104 GNUNET_CHAT_VERSION_ASSERT(); 3105 3106 if (!invitation) 3107 return GNUNET_NO; 3108 3109 return GNUNET_CONTAINER_multihashmap_contains( 3110 invitation->context->handle->contexts, 3111 &(invitation->key.hash) 3112 ); 3113 } 3114 3115 3116 enum GNUNET_GenericReturnValue 3117 GNUNET_CHAT_invitation_is_rejected (const struct GNUNET_CHAT_Invitation *invitation) 3118 { 3119 GNUNET_CHAT_VERSION_ASSERT(); 3120 3121 if (!invitation) 3122 return GNUNET_NO; 3123 3124 const struct GNUNET_CHAT_InternalTagging *tagging = GNUNET_CONTAINER_multihashmap_get( 3125 invitation->context->taggings, &(invitation->hash)); 3126 3127 if (!tagging) 3128 return GNUNET_NO; 3129 3130 if (internal_tagging_iterate(tagging, GNUNET_NO, NULL, NULL, NULL) > 0) 3131 return GNUNET_YES; 3132 else 3133 return GNUNET_NO; 3134 } 3135 3136 3137 enum GNUNET_GenericReturnValue 3138 GNUNET_CHAT_invitation_is_direct (const struct GNUNET_CHAT_Invitation *invitation) 3139 { 3140 GNUNET_CHAT_VERSION_ASSERT(); 3141 3142 if ((invitation->key.code.public_bit) || 3143 (invitation->key.code.group_bit) || 3144 (invitation->key.code.feed_bit)) 3145 return GNUNET_NO; 3146 else 3147 return GNUNET_YES; 3148 } 3149 3150 3151 const struct GNUNET_CHAT_DiscourseId* 3152 GNUNET_CHAT_discourse_get_id (const struct GNUNET_CHAT_Discourse *discourse) 3153 { 3154 GNUNET_CHAT_VERSION_ASSERT(); 3155 3156 if (!discourse) 3157 return NULL; 3158 3159 return &(discourse->id); 3160 } 3161 3162 3163 enum GNUNET_GenericReturnValue 3164 GNUNET_CHAT_discourse_is_open (const struct GNUNET_CHAT_Discourse *discourse) 3165 { 3166 GNUNET_CHAT_VERSION_ASSERT(); 3167 3168 if (!discourse) 3169 return GNUNET_SYSERR; 3170 3171 struct GNUNET_CHAT_DiscourseSubscription *sub; 3172 for (sub = discourse->head; sub; sub = sub->next) 3173 { 3174 if (GNUNET_TIME_absolute_cmp(sub->end, <, GNUNET_TIME_absolute_get())) 3175 continue; 3176 3177 if (GNUNET_YES == sub->contact->owned) 3178 return GNUNET_YES; 3179 } 3180 3181 return GNUNET_NO; 3182 } 3183 3184 3185 void 3186 GNUNET_CHAT_discourse_set_user_pointer (struct GNUNET_CHAT_Discourse *discourse, 3187 void *user_pointer) 3188 { 3189 GNUNET_CHAT_VERSION_ASSERT(); 3190 3191 if (!discourse) 3192 return; 3193 3194 discourse->user_pointer = user_pointer; 3195 } 3196 3197 3198 void* 3199 GNUNET_CHAT_discourse_get_user_pointer (const struct GNUNET_CHAT_Discourse *discourse) 3200 { 3201 GNUNET_CHAT_VERSION_ASSERT(); 3202 3203 if (!discourse) 3204 return NULL; 3205 3206 return discourse->user_pointer; 3207 } 3208 3209 3210 void 3211 GNUNET_CHAT_discourse_close (struct GNUNET_CHAT_Discourse *discourse) 3212 { 3213 GNUNET_CHAT_VERSION_ASSERT(); 3214 3215 if ((!discourse) || (!(discourse->context)) || (!(discourse->context->room))) 3216 return; 3217 3218 struct GNUNET_MESSENGER_Message msg; 3219 memset(&msg, 0, sizeof(msg)); 3220 3221 msg.header.kind = GNUNET_MESSENGER_KIND_SUBSCRIBTION; 3222 3223 util_shorthash_from_discourse_id( 3224 &(discourse->id), 3225 &(msg.body.subscription.discourse) 3226 ); 3227 3228 msg.body.subscription.time = GNUNET_TIME_relative_hton(GNUNET_TIME_relative_get_zero_()); 3229 msg.body.subscription.flags = GNUNET_MESSENGER_FLAG_SUBSCRIPTION_UNSUBSCRIBE; 3230 3231 GNUNET_MESSENGER_send_message( 3232 discourse->context->room, 3233 &msg, 3234 NULL 3235 ); 3236 } 3237 3238 3239 enum GNUNET_GenericReturnValue 3240 GNUNET_CHAT_discourse_write (struct GNUNET_CHAT_Discourse *discourse, 3241 const char *data, 3242 uint64_t size) 3243 { 3244 GNUNET_CHAT_VERSION_ASSERT(); 3245 3246 if ((!discourse) || (!data) || (!(discourse->context)) || 3247 (!(discourse->context->room))) 3248 return GNUNET_SYSERR; 3249 3250 static const uint64_t max_size = (uint16_t) ( 3251 GNUNET_MAX_MESSAGE_SIZE - GNUNET_MIN_MESSAGE_SIZE - 3252 sizeof (struct GNUNET_MESSENGER_Message) 3253 ); 3254 3255 struct GNUNET_MESSENGER_Message msg; 3256 memset(&msg, 0, sizeof(msg)); 3257 3258 msg.header.kind = GNUNET_MESSENGER_KIND_TALK; 3259 msg.body.talk.data = GNUNET_malloc(size > max_size? max_size : size); 3260 3261 util_shorthash_from_discourse_id( 3262 &(discourse->id), 3263 &(msg.body.talk.discourse) 3264 ); 3265 3266 while (size > 0) 3267 { 3268 msg.body.talk.length = (uint16_t) (size > max_size? max_size : size); 3269 3270 GNUNET_memcpy( 3271 msg.body.talk.data, 3272 data, 3273 msg.body.talk.length 3274 ); 3275 3276 size -= msg.body.talk.length; 3277 data += msg.body.talk.length; 3278 3279 GNUNET_MESSENGER_send_message(discourse->context->room, &msg, NULL); 3280 } 3281 3282 GNUNET_free(msg.body.talk.data); 3283 return GNUNET_OK; 3284 } 3285 3286 3287 int 3288 GNUNET_CHAT_discourse_get_fd (const struct GNUNET_CHAT_Discourse *discourse) 3289 { 3290 GNUNET_CHAT_VERSION_ASSERT(); 3291 3292 if (! discourse) 3293 return GNUNET_SYSERR; 3294 3295 return discourse->pipe[1]; 3296 } 3297 3298 3299 int 3300 GNUNET_CHAT_discourse_iterate_contacts (struct GNUNET_CHAT_Discourse *discourse, 3301 GNUNET_CHAT_DiscourseContactCallback callback, 3302 void *cls) 3303 { 3304 GNUNET_CHAT_VERSION_ASSERT(); 3305 3306 if (! discourse) 3307 return GNUNET_SYSERR; 3308 3309 int iterations = 0; 3310 3311 struct GNUNET_CHAT_DiscourseSubscription *sub; 3312 for (sub = discourse->head; sub; sub = sub->next) 3313 { 3314 if (GNUNET_TIME_absolute_cmp(sub->end, <, GNUNET_TIME_absolute_get())) 3315 continue; 3316 3317 if (callback) 3318 callback(cls, discourse, sub->contact); 3319 3320 iterations++; 3321 } 3322 3323 return iterations; 3324 } 3325 3326 enum GNUNET_GenericReturnValue 3327 GNUNET_CHAT_generate_secret (char *secret, 3328 uint32_t secret_len) 3329 { 3330 GNUNET_CHAT_VERSION_ASSERT(); 3331 3332 if (secret_len <= 0) 3333 return GNUNET_SYSERR; 3334 3335 const uint32_t requested = secret_len * 5 / 8 + 1; 3336 const uint32_t size = ((requested*8) + (((requested*8) % 5) > 0 ? 5 - ((requested*8) % 5) : 0)) / 5; 3337 3338 char *raw_secret = GNUNET_malloc(requested); 3339 char *buf; 3340 3341 if (!raw_secret) 3342 return GNUNET_SYSERR; 3343 3344 if (size > secret_len) 3345 { 3346 buf = GNUNET_malloc(size); 3347 3348 if (!buf) 3349 { 3350 GNUNET_free(raw_secret); 3351 return GNUNET_SYSERR; 3352 } 3353 } 3354 else 3355 buf = secret; 3356 3357 GNUNET_CRYPTO_random_block( 3358 raw_secret, 3359 requested 3360 ); 3361 3362 enum GNUNET_GenericReturnValue result; 3363 result = GNUNET_STRINGS_data_to_string( 3364 raw_secret, 3365 requested, 3366 buf, 3367 size 3368 ) == NULL? GNUNET_SYSERR : GNUNET_OK; 3369 3370 GNUNET_CRYPTO_zero_keys(raw_secret, requested); 3371 GNUNET_free(raw_secret); 3372 3373 if (buf != secret) 3374 { 3375 GNUNET_memcpy(secret, buf, secret_len); 3376 GNUNET_CRYPTO_zero_keys(buf, size); 3377 GNUNET_free(buf); 3378 } 3379 3380 return result; 3381 }