gnunet_chat_lib.c (73892B)
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 ); 819 820 GNUNET_free(p); 821 822 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 823 handle->files, &hash, file, 824 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 825 { 826 file_destroy(file); 827 GNUNET_free(filename); 828 return NULL; 829 } 830 831 struct GNUNET_FS_BlockOptions bo; 832 833 bo.anonymity_level = block_anonymity_level; 834 bo.content_priority = block_content_priority; 835 bo.replication_level = block_replication_level; 836 bo.expiration_time = GNUNET_TIME_absolute_get_forever_(); 837 838 struct GNUNET_FS_FileInformation* fi = GNUNET_FS_file_information_create_from_file( 839 handle->fs, 840 file, 841 filename, 842 NULL, 843 file->meta, 844 GNUNET_YES, 845 &bo 846 ); 847 848 file->publish = GNUNET_FS_publish_start( 849 handle->fs, fi, 850 NULL, NULL, NULL, 851 GNUNET_FS_PUBLISH_OPTION_NONE 852 ); 853 854 if (file->publish) 855 file->status |= GNUNET_CHAT_FILE_STATUS_PUBLISH; 856 857 GNUNET_free(filename); 858 859 file_binding: 860 file_bind_upload(file, NULL, callback, cls); 861 return file; 862 } 863 864 865 int 866 GNUNET_CHAT_iterate_files (struct GNUNET_CHAT_Handle *handle, 867 GNUNET_CHAT_FileCallback callback, 868 void *cls) 869 { 870 GNUNET_CHAT_VERSION_ASSERT(); 871 872 if ((!handle) || (handle->destruction)) 873 return GNUNET_SYSERR; 874 875 struct GNUNET_CHAT_IterateFiles it; 876 it.handle = handle; 877 it.cb = callback; 878 it.cls = cls; 879 880 return GNUNET_CONTAINER_multihashmap_iterate( 881 handle->files, 882 it_iterate_files, 883 &it 884 ); 885 } 886 887 888 int 889 GNUNET_CHAT_context_iterate_discourses (struct GNUNET_CHAT_Context *context, 890 GNUNET_CHAT_DiscourseCallback callback, 891 void *cls) 892 { 893 GNUNET_CHAT_VERSION_ASSERT(); 894 895 if ((!context) || (!(context->discourses))) 896 return GNUNET_SYSERR; 897 898 struct GNUNET_CHAT_ContextIterateDiscourses it; 899 it.context = context; 900 it.cb = callback; 901 it.cls = cls; 902 903 return GNUNET_CONTAINER_multishortmap_iterate( 904 context->discourses, 905 it_context_iterate_discourses, 906 &it 907 ); 908 } 909 910 911 void 912 GNUNET_CHAT_set_user_pointer (struct GNUNET_CHAT_Handle *handle, 913 void *user_pointer) 914 { 915 GNUNET_CHAT_VERSION_ASSERT(); 916 917 if ((!handle) || (handle->destruction)) 918 return; 919 920 handle->user_pointer = user_pointer; 921 } 922 923 924 void* 925 GNUNET_CHAT_get_user_pointer (const struct GNUNET_CHAT_Handle *handle) 926 { 927 GNUNET_CHAT_VERSION_ASSERT(); 928 929 if ((!handle) || (handle->destruction)) 930 return NULL; 931 932 return handle->user_pointer; 933 } 934 935 936 int 937 GNUNET_CHAT_iterate_contacts (struct GNUNET_CHAT_Handle *handle, 938 GNUNET_CHAT_ContactCallback callback, 939 void *cls) 940 { 941 GNUNET_CHAT_VERSION_ASSERT(); 942 943 if ((!handle) || (handle->destruction) || (!(handle->contacts))) 944 return GNUNET_SYSERR; 945 946 struct GNUNET_CHAT_HandleIterateContacts it; 947 it.handle = handle; 948 it.cb = callback; 949 it.cls = cls; 950 951 return GNUNET_CONTAINER_multishortmap_iterate( 952 handle->contacts, it_handle_iterate_contacts, &it 953 ); 954 } 955 956 957 struct GNUNET_CHAT_Contact* 958 GNUNET_CHAT_get_own_contact (struct GNUNET_CHAT_Handle *handle) 959 { 960 GNUNET_CHAT_VERSION_ASSERT(); 961 962 if (!(handle->own_contact)) 963 GNUNET_CHAT_iterate_contacts (handle, it_handle_find_own_contact, NULL); 964 965 return handle->own_contact; 966 } 967 968 969 const char* 970 GNUNET_CHAT_account_get_name (const struct GNUNET_CHAT_Account *account) 971 { 972 GNUNET_CHAT_VERSION_ASSERT(); 973 974 if (!account) 975 return NULL; 976 977 return account_get_name(account); 978 } 979 980 981 void 982 GNUNET_CHAT_account_get_attributes (struct GNUNET_CHAT_Handle *handle, 983 struct GNUNET_CHAT_Account *account, 984 GNUNET_CHAT_AccountAttributeCallback callback, 985 void *cls) 986 { 987 GNUNET_CHAT_VERSION_ASSERT(); 988 989 if ((!handle) || (handle->destruction) || (!account)) 990 return; 991 992 const struct GNUNET_CRYPTO_BlindablePrivateKey *key = account_get_key( 993 account 994 ); 995 996 if (!key) 997 return; 998 999 struct GNUNET_CHAT_AttributeProcess *attributes; 1000 attributes = internal_attributes_create_request(handle, account); 1001 1002 if (!attributes) 1003 return; 1004 1005 attributes->account_callback = callback; 1006 attributes->closure = cls; 1007 1008 attributes->iter = GNUNET_RECLAIM_get_attributes_start( 1009 handle->reclaim, 1010 key, 1011 cb_task_error_iterate_attribute, 1012 attributes, 1013 cb_iterate_attribute, 1014 attributes, 1015 cb_task_finish_iterate_attribute, 1016 attributes 1017 ); 1018 } 1019 1020 1021 void 1022 GNUNET_CHAT_account_set_user_pointer (struct GNUNET_CHAT_Account *account, 1023 void *user_pointer) 1024 { 1025 GNUNET_CHAT_VERSION_ASSERT(); 1026 1027 if (!account) 1028 return; 1029 1030 account->user_pointer = user_pointer; 1031 } 1032 1033 1034 void* 1035 GNUNET_CHAT_account_get_user_pointer (const struct GNUNET_CHAT_Account *account) 1036 { 1037 GNUNET_CHAT_VERSION_ASSERT(); 1038 1039 if (!account) 1040 return NULL; 1041 1042 return account->user_pointer; 1043 } 1044 1045 1046 struct GNUNET_CHAT_Group * 1047 GNUNET_CHAT_group_create (struct GNUNET_CHAT_Handle *handle, 1048 const char* topic) 1049 { 1050 GNUNET_CHAT_VERSION_ASSERT(); 1051 1052 if ((!handle) || (handle->destruction) || 1053 (!(handle->groups)) || (!(handle->contexts))) 1054 return NULL; 1055 1056 union GNUNET_MESSENGER_RoomKey key; 1057 GNUNET_MESSENGER_create_room_key( 1058 &key, 1059 topic, 1060 topic? GNUNET_YES : GNUNET_NO, 1061 GNUNET_YES, 1062 GNUNET_NO 1063 ); 1064 1065 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->contexts, &(key.hash))) 1066 return NULL; 1067 1068 struct GNUNET_MESSENGER_Room *room = GNUNET_MESSENGER_open_room( 1069 handle->messenger, &key 1070 ); 1071 1072 if (!room) 1073 return NULL; 1074 1075 struct GNUNET_CHAT_Context *context = context_create_from_room(handle, room); 1076 context->type = GNUNET_CHAT_CONTEXT_TYPE_GROUP; 1077 1078 util_set_name_field(topic, &(context->topic)); 1079 1080 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 1081 handle->contexts, &(key.hash), context, 1082 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 1083 goto destroy_context; 1084 1085 struct GNUNET_CHAT_Group *group = group_create_from_context(handle, context); 1086 1087 if (context->topic) 1088 group_publish(group); 1089 1090 if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put( 1091 handle->groups, &(key.hash), group, 1092 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 1093 { 1094 context_write_records(context); 1095 return group; 1096 } 1097 1098 group_destroy(group); 1099 1100 GNUNET_CONTAINER_multihashmap_remove(handle->contexts, &(key.hash), context); 1101 1102 destroy_context: 1103 context_destroy(context); 1104 return NULL; 1105 } 1106 1107 1108 int 1109 GNUNET_CHAT_iterate_groups (struct GNUNET_CHAT_Handle *handle, 1110 GNUNET_CHAT_GroupCallback callback, 1111 void *cls) 1112 { 1113 GNUNET_CHAT_VERSION_ASSERT(); 1114 1115 if ((!handle) || (handle->destruction) || (!(handle->groups))) 1116 return GNUNET_SYSERR; 1117 1118 struct GNUNET_CHAT_HandleIterateGroups it; 1119 it.handle = handle; 1120 it.cb = callback; 1121 it.cls = cls; 1122 1123 return GNUNET_CONTAINER_multihashmap_iterate( 1124 handle->groups, it_handle_iterate_groups, &it 1125 ); 1126 } 1127 1128 1129 void 1130 GNUNET_CHAT_contact_delete (struct GNUNET_CHAT_Contact *contact) 1131 { 1132 GNUNET_CHAT_VERSION_ASSERT(); 1133 1134 if ((!contact) || (contact->destruction)) 1135 return; 1136 1137 if (contact->context) 1138 contact->context->deleted = GNUNET_YES; 1139 1140 contact->destruction = GNUNET_SCHEDULER_add_now( 1141 task_contact_destruction, 1142 contact 1143 ); 1144 } 1145 1146 1147 void 1148 GNUNET_CHAT_contact_set_name (struct GNUNET_CHAT_Contact *contact, 1149 const char *name) 1150 { 1151 GNUNET_CHAT_VERSION_ASSERT(); 1152 1153 if ((!contact) || (!(contact->context)) || 1154 (contact->context->topic)) 1155 return; 1156 1157 context_update_nick(contact->context, name); 1158 1159 if (contact->context->room) 1160 context_write_records(contact->context); 1161 } 1162 1163 1164 const char* 1165 GNUNET_CHAT_contact_get_name (const struct GNUNET_CHAT_Contact *contact) 1166 { 1167 GNUNET_CHAT_VERSION_ASSERT(); 1168 1169 if (!contact) 1170 return NULL; 1171 1172 if ((contact->context) && (! contact->context->topic) && 1173 (contact->context->nick)) 1174 return contact->context->nick; 1175 1176 return GNUNET_MESSENGER_contact_get_name(contact->member); 1177 } 1178 1179 1180 const char* 1181 GNUNET_CHAT_contact_get_key (const struct GNUNET_CHAT_Contact *contact) 1182 { 1183 GNUNET_CHAT_VERSION_ASSERT(); 1184 1185 if (!contact) 1186 return NULL; 1187 1188 return contact->public_key; 1189 } 1190 1191 1192 struct GNUNET_CHAT_Context* 1193 GNUNET_CHAT_contact_get_context (struct GNUNET_CHAT_Contact *contact) 1194 { 1195 GNUNET_CHAT_VERSION_ASSERT(); 1196 1197 if (!contact) 1198 return NULL; 1199 1200 if (contact->context) 1201 return contact->context; 1202 1203 struct GNUNET_CHAT_Context *context = contact_find_context( 1204 contact, 1205 GNUNET_NO 1206 ); 1207 1208 if ((context) && (GNUNET_CHAT_CONTEXT_TYPE_CONTACT == context->type)) 1209 goto attach_return; 1210 1211 context = context_create_from_contact(contact->handle, contact->member); 1212 1213 attach_return: 1214 if (context) 1215 contact->context = context; 1216 1217 return context; 1218 } 1219 1220 1221 void 1222 GNUNET_CHAT_contact_set_user_pointer (struct GNUNET_CHAT_Contact *contact, 1223 void *user_pointer) 1224 { 1225 GNUNET_CHAT_VERSION_ASSERT(); 1226 1227 if (!contact) 1228 return; 1229 1230 contact->user_pointer = user_pointer; 1231 } 1232 1233 1234 void* 1235 GNUNET_CHAT_contact_get_user_pointer (const struct GNUNET_CHAT_Contact *contact) 1236 { 1237 GNUNET_CHAT_VERSION_ASSERT(); 1238 1239 if (!contact) 1240 return NULL; 1241 1242 return contact->user_pointer; 1243 } 1244 1245 1246 enum GNUNET_GenericReturnValue 1247 GNUNET_CHAT_contact_is_owned (const struct GNUNET_CHAT_Contact *contact) 1248 { 1249 GNUNET_CHAT_VERSION_ASSERT(); 1250 1251 if (!contact) 1252 return GNUNET_SYSERR; 1253 1254 return contact->owned; 1255 } 1256 1257 1258 void 1259 GNUNET_CHAT_contact_set_blocked (struct GNUNET_CHAT_Contact *contact, 1260 enum GNUNET_GenericReturnValue blocked) 1261 { 1262 GNUNET_CHAT_VERSION_ASSERT(); 1263 1264 if (!contact) 1265 return; 1266 1267 struct GNUNET_CHAT_ContactIterateContexts it; 1268 it.contact = contact; 1269 it.tag = NULL; 1270 1271 if (GNUNET_NO == blocked) 1272 it.cb = contact_untag; 1273 else if (GNUNET_YES == blocked) 1274 it.cb = contact_tag; 1275 else 1276 return; 1277 1278 GNUNET_CONTAINER_multihashmap_iterate( 1279 contact->joined, 1280 it_contact_iterate_contexts, 1281 &it 1282 ); 1283 } 1284 1285 1286 enum GNUNET_GenericReturnValue 1287 GNUNET_CHAT_contact_is_blocked (const struct GNUNET_CHAT_Contact *contact) 1288 { 1289 GNUNET_CHAT_VERSION_ASSERT(); 1290 1291 if (!contact) 1292 return GNUNET_SYSERR; 1293 1294 return contact_is_tagged(contact, NULL, NULL); 1295 } 1296 1297 1298 void 1299 GNUNET_CHAT_contact_tag (struct GNUNET_CHAT_Contact *contact, 1300 const char *tag) 1301 { 1302 GNUNET_CHAT_VERSION_ASSERT(); 1303 1304 if ((!contact) || (!tag) || (!tag[0])) 1305 return; 1306 1307 struct GNUNET_CHAT_ContactIterateContexts it; 1308 it.contact = contact; 1309 it.tag = tag; 1310 it.cb = contact_tag; 1311 1312 GNUNET_CONTAINER_multihashmap_iterate( 1313 contact->joined, 1314 it_contact_iterate_contexts, 1315 &it 1316 ); 1317 } 1318 1319 1320 void 1321 GNUNET_CHAT_contact_untag (struct GNUNET_CHAT_Contact *contact, 1322 const char *tag) 1323 { 1324 GNUNET_CHAT_VERSION_ASSERT(); 1325 1326 if ((!contact) || (!tag) || (!tag[0])) 1327 return; 1328 1329 struct GNUNET_CHAT_ContactIterateContexts it; 1330 it.contact = contact; 1331 it.tag = tag; 1332 it.cb = contact_untag; 1333 1334 GNUNET_CONTAINER_multihashmap_iterate( 1335 contact->joined, 1336 it_contact_iterate_contexts, 1337 &it 1338 ); 1339 } 1340 1341 1342 enum GNUNET_GenericReturnValue 1343 GNUNET_CHAT_contact_is_tagged (const struct GNUNET_CHAT_Contact *contact, 1344 const char *tag) 1345 { 1346 GNUNET_CHAT_VERSION_ASSERT(); 1347 1348 if ((!contact) || (!tag) || (!tag[0])) 1349 return GNUNET_SYSERR; 1350 1351 return contact_is_tagged(contact, NULL, tag); 1352 } 1353 1354 1355 int 1356 GNUNET_CHAT_contact_iterate_tags (struct GNUNET_CHAT_Contact *contact, 1357 GNUNET_CHAT_ContactTagCallback callback, 1358 void *cls) 1359 { 1360 GNUNET_CHAT_VERSION_ASSERT(); 1361 1362 if (!contact) 1363 return GNUNET_SYSERR; 1364 1365 return contact_iterate_tags( 1366 contact, 1367 NULL, 1368 callback, 1369 cls 1370 ); 1371 } 1372 1373 1374 void 1375 GNUNET_CHAT_contact_get_attributes (struct GNUNET_CHAT_Contact *contact, 1376 GNUNET_CHAT_ContactAttributeCallback callback, 1377 void *cls) 1378 { 1379 GNUNET_CHAT_VERSION_ASSERT(); 1380 1381 if (!contact) 1382 return; 1383 1384 struct GNUNET_CHAT_InternalTickets *tickets; 1385 tickets = contact->tickets_head; 1386 1387 while (tickets) 1388 { 1389 ticket_consume( 1390 tickets->ticket, 1391 callback, 1392 cls 1393 ); 1394 1395 tickets = tickets->next; 1396 } 1397 } 1398 1399 1400 enum GNUNET_GenericReturnValue 1401 GNUNET_CHAT_group_leave (struct GNUNET_CHAT_Group *group) 1402 { 1403 GNUNET_CHAT_VERSION_ASSERT(); 1404 1405 if ((!group) || (group->destruction)) 1406 return GNUNET_SYSERR; 1407 1408 group->context->deleted = GNUNET_YES; 1409 group->destruction = GNUNET_SCHEDULER_add_now( 1410 task_group_destruction, 1411 group 1412 ); 1413 1414 return GNUNET_OK; 1415 } 1416 1417 1418 void 1419 GNUNET_CHAT_group_set_name (struct GNUNET_CHAT_Group *group, 1420 const char *name) 1421 { 1422 GNUNET_CHAT_VERSION_ASSERT(); 1423 1424 if ((!group) || (!(group->context))) 1425 return; 1426 1427 context_update_nick(group->context, name); 1428 1429 if (group->context->room) 1430 context_write_records(group->context); 1431 } 1432 1433 1434 const char* 1435 GNUNET_CHAT_group_get_name (const struct GNUNET_CHAT_Group *group) 1436 { 1437 GNUNET_CHAT_VERSION_ASSERT(); 1438 1439 if ((!group) || (!(group->context))) 1440 return NULL; 1441 1442 if (group->context->nick) 1443 return group->context->nick; 1444 1445 return group->context->topic; 1446 } 1447 1448 1449 void 1450 GNUNET_CHAT_group_set_user_pointer (struct GNUNET_CHAT_Group *group, 1451 void *user_pointer) 1452 { 1453 GNUNET_CHAT_VERSION_ASSERT(); 1454 1455 if (!group) 1456 return; 1457 1458 group->user_pointer = user_pointer; 1459 } 1460 1461 1462 void* 1463 GNUNET_CHAT_group_get_user_pointer (const struct GNUNET_CHAT_Group *group) 1464 { 1465 GNUNET_CHAT_VERSION_ASSERT(); 1466 1467 if (!group) 1468 return NULL; 1469 1470 return group->user_pointer; 1471 } 1472 1473 1474 enum GNUNET_GenericReturnValue 1475 GNUNET_CHAT_group_invite_contact (struct GNUNET_CHAT_Group *group, 1476 struct GNUNET_CHAT_Contact *contact) 1477 { 1478 GNUNET_CHAT_VERSION_ASSERT(); 1479 1480 if ((!group) || (!contact) || (!contact->member)) 1481 return GNUNET_SYSERR; 1482 1483 struct GNUNET_CHAT_Context *context = contact_find_context( 1484 contact, 1485 GNUNET_YES 1486 ); 1487 1488 if (!context) 1489 return GNUNET_SYSERR; 1490 1491 const struct GNUNET_PeerIdentity *pid = context->handle->pid; 1492 1493 if (!pid) 1494 return GNUNET_SYSERR; 1495 1496 union GNUNET_MESSENGER_RoomKey key; 1497 GNUNET_memcpy( 1498 &(key.hash), 1499 GNUNET_MESSENGER_room_get_key(group->context->room), 1500 sizeof(key.hash) 1501 ); 1502 1503 handle_send_room_name(group->handle, GNUNET_MESSENGER_open_room( 1504 group->handle->messenger, &key 1505 )); 1506 1507 struct GNUNET_MESSENGER_Message msg; 1508 memset(&msg, 0, sizeof(msg)); 1509 1510 msg.header.kind = GNUNET_MESSENGER_KIND_INVITE; 1511 GNUNET_memcpy(&(msg.body.invite.door), pid, sizeof(msg.body.invite.door)); 1512 GNUNET_memcpy(&(msg.body.invite.key), &key, sizeof(msg.body.invite.key)); 1513 1514 GNUNET_MESSENGER_send_message(context->room, &msg, contact->member); 1515 return GNUNET_OK; 1516 } 1517 1518 1519 int 1520 GNUNET_CHAT_group_iterate_contacts (struct GNUNET_CHAT_Group *group, 1521 GNUNET_CHAT_GroupContactCallback callback, 1522 void *cls) 1523 { 1524 GNUNET_CHAT_VERSION_ASSERT(); 1525 1526 if (!group) 1527 return GNUNET_SYSERR; 1528 1529 struct GNUNET_CHAT_GroupIterateContacts it; 1530 it.group = group; 1531 it.cb = callback; 1532 it.cls = cls; 1533 1534 return GNUNET_MESSENGER_iterate_members( 1535 group->context->room, it_group_iterate_contacts, &it 1536 ); 1537 } 1538 1539 1540 void 1541 GNUNET_CHAT_member_set_user_pointer (struct GNUNET_CHAT_Group *group, 1542 const struct GNUNET_CHAT_Contact *member, 1543 void *user_pointer) 1544 { 1545 GNUNET_CHAT_VERSION_ASSERT(); 1546 1547 if ((!group) || (!(group->context)) || (!member)) 1548 return; 1549 1550 struct GNUNET_ShortHashCode hash; 1551 util_shorthash_from_member(member->member, &hash); 1552 1553 GNUNET_CONTAINER_multishortmap_put( 1554 group->context->member_pointers, 1555 &hash, 1556 user_pointer, 1557 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE 1558 ); 1559 } 1560 1561 1562 void* 1563 GNUNET_CHAT_member_get_user_pointer (const struct GNUNET_CHAT_Group *group, 1564 const struct GNUNET_CHAT_Contact *member) 1565 { 1566 GNUNET_CHAT_VERSION_ASSERT(); 1567 1568 if ((!group) || (!(group->context)) || (!member)) 1569 return NULL; 1570 1571 struct GNUNET_ShortHashCode hash; 1572 util_shorthash_from_member(member->member, &hash); 1573 1574 return GNUNET_CONTAINER_multishortmap_get( 1575 group->context->member_pointers, 1576 &hash 1577 ); 1578 } 1579 1580 1581 struct GNUNET_CHAT_Context* 1582 GNUNET_CHAT_group_get_context (struct GNUNET_CHAT_Group *group) 1583 { 1584 GNUNET_CHAT_VERSION_ASSERT(); 1585 1586 if (!group) 1587 return NULL; 1588 1589 return group->context; 1590 } 1591 1592 1593 enum GNUNET_GenericReturnValue 1594 GNUNET_CHAT_context_get_status (struct GNUNET_CHAT_Context *context) 1595 { 1596 GNUNET_CHAT_VERSION_ASSERT(); 1597 1598 if ((!context) || (!(context->room))) 1599 return GNUNET_SYSERR; 1600 1601 switch (context->type) { 1602 case GNUNET_CHAT_CONTEXT_TYPE_CONTACT: 1603 { 1604 const struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_context_get_contact( 1605 context 1606 ); 1607 1608 return contact? GNUNET_OK : GNUNET_NO; 1609 } 1610 case GNUNET_CHAT_CONTEXT_TYPE_GROUP: 1611 return GNUNET_OK; 1612 default: 1613 return GNUNET_NO; 1614 } 1615 } 1616 1617 1618 enum GNUNET_GenericReturnValue 1619 GNUNET_CHAT_context_request (struct GNUNET_CHAT_Context *context) 1620 { 1621 GNUNET_CHAT_VERSION_ASSERT(); 1622 1623 if (!context) 1624 return GNUNET_SYSERR; 1625 else if (context->room) 1626 return GNUNET_OK; 1627 1628 struct GNUNET_CHAT_Handle *handle = context->handle; 1629 1630 if ((!handle) || (!(context->contact))) 1631 return GNUNET_SYSERR; 1632 1633 struct GNUNET_CHAT_Contact *contact = handle_get_contact_from_messenger( 1634 handle, context->contact 1635 ); 1636 1637 if (!contact) 1638 return GNUNET_SYSERR; 1639 1640 enum GNUNET_GenericReturnValue owned = GNUNET_CHAT_contact_is_owned( 1641 contact 1642 ); 1643 1644 context->type = GNUNET_CHAT_CONTEXT_TYPE_CONTACT; 1645 1646 struct GNUNET_CHAT_Context *other = contact_find_context( 1647 contact, GNUNET_YES 1648 ); 1649 1650 if (!other) 1651 return GNUNET_SYSERR; 1652 1653 union GNUNET_MESSENGER_RoomKey key; 1654 GNUNET_MESSENGER_create_room_key( 1655 &key, 1656 NULL, 1657 GNUNET_YES == owned? GNUNET_YES : GNUNET_NO, 1658 GNUNET_NO, 1659 GNUNET_YES == owned? GNUNET_YES : GNUNET_NO 1660 ); 1661 1662 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains( 1663 handle->contexts, &(key.hash))) 1664 return GNUNET_SYSERR; 1665 1666 const struct GNUNET_PeerIdentity *pid = handle->pid; 1667 1668 if (!pid) 1669 return GNUNET_SYSERR; 1670 1671 struct GNUNET_MESSENGER_Room *room; 1672 if (GNUNET_YES == owned) 1673 { 1674 room = GNUNET_MESSENGER_enter_room( 1675 handle->messenger, 1676 pid, 1677 &key 1678 ); 1679 } 1680 else 1681 room = GNUNET_MESSENGER_open_room( 1682 handle->messenger, &key 1683 ); 1684 1685 if (!room) 1686 return GNUNET_SYSERR; 1687 1688 context_update_room(context, room, GNUNET_YES); 1689 1690 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 1691 handle->contexts, &(key.hash), context, 1692 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 1693 { 1694 context_update_room(context, NULL, GNUNET_YES); 1695 return GNUNET_SYSERR; 1696 } 1697 1698 if (GNUNET_YES != owned) 1699 { 1700 struct GNUNET_MESSENGER_Message msg; 1701 memset(&msg, 0, sizeof(msg)); 1702 1703 msg.header.kind = GNUNET_MESSENGER_KIND_INVITE; 1704 GNUNET_memcpy(&(msg.body.invite.door), pid, sizeof(msg.body.invite.door)); 1705 GNUNET_memcpy(&(msg.body.invite.key), &key, sizeof(msg.body.invite.key)); 1706 1707 GNUNET_MESSENGER_send_message(other->room, &msg, context->contact); 1708 } 1709 1710 return GNUNET_OK; 1711 } 1712 1713 1714 struct GNUNET_CHAT_Contact* 1715 GNUNET_CHAT_context_get_contact (struct GNUNET_CHAT_Context *context) 1716 { 1717 GNUNET_CHAT_VERSION_ASSERT(); 1718 1719 if ((!context) || (GNUNET_CHAT_CONTEXT_TYPE_CONTACT != context->type)) 1720 return NULL; 1721 1722 if (context->contact) 1723 return handle_get_contact_from_messenger(context->handle, context->contact); 1724 1725 struct GNUNET_MESSENGER_Room *room = context->room; 1726 struct GNUNET_CHAT_RoomFindContact find; 1727 union GNUNET_MESSENGER_RoomKey key; 1728 1729 GNUNET_memcpy(&(key.hash), GNUNET_MESSENGER_room_get_key(room), sizeof(key.hash)); 1730 1731 if (key.code.group_bit) 1732 return NULL; 1733 1734 if (! key.code.feed_bit) 1735 find.ignore_key = GNUNET_MESSENGER_get_key(context->handle->messenger); 1736 else 1737 find.ignore_key = NULL; 1738 1739 find.contact = NULL; 1740 1741 int member_count = GNUNET_MESSENGER_iterate_members( 1742 room, 1743 it_room_find_contact, 1744 &find 1745 ); 1746 1747 if ((!find.contact) || (member_count > 2)) 1748 return NULL; 1749 1750 return handle_get_contact_from_messenger(context->handle, find.contact); 1751 } 1752 1753 1754 struct GNUNET_CHAT_Group* 1755 GNUNET_CHAT_context_get_group (struct GNUNET_CHAT_Context *context) 1756 { 1757 GNUNET_CHAT_VERSION_ASSERT(); 1758 1759 if ((!context) || (GNUNET_CHAT_CONTEXT_TYPE_GROUP != context->type)) 1760 return NULL; 1761 1762 if (!(context->room)) 1763 return NULL; 1764 1765 return handle_get_group_from_messenger(context->handle, context->room); 1766 } 1767 1768 1769 void 1770 GNUNET_CHAT_context_set_user_pointer (struct GNUNET_CHAT_Context *context, 1771 void *user_pointer) 1772 { 1773 GNUNET_CHAT_VERSION_ASSERT(); 1774 1775 if (!context) 1776 return; 1777 1778 context->user_pointer = user_pointer; 1779 } 1780 1781 1782 void* 1783 GNUNET_CHAT_context_get_user_pointer (const struct GNUNET_CHAT_Context *context) 1784 { 1785 GNUNET_CHAT_VERSION_ASSERT(); 1786 1787 if (!context) 1788 return NULL; 1789 1790 return context->user_pointer; 1791 } 1792 1793 1794 enum GNUNET_GenericReturnValue 1795 GNUNET_CHAT_context_send_text (struct GNUNET_CHAT_Context *context, 1796 const char *text) 1797 { 1798 GNUNET_CHAT_VERSION_ASSERT(); 1799 1800 if ((!context) || (!text) || (!(context->room))) 1801 return GNUNET_SYSERR; 1802 1803 struct GNUNET_MESSENGER_Message msg; 1804 memset(&msg, 0, sizeof(msg)); 1805 1806 msg.header.kind = GNUNET_MESSENGER_KIND_TEXT; 1807 msg.body.text.text = GNUNET_strdup(text); 1808 1809 GNUNET_MESSENGER_send_message(context->room, &msg, NULL); 1810 1811 GNUNET_free(msg.body.text.text); 1812 return GNUNET_OK; 1813 } 1814 1815 1816 enum GNUNET_GenericReturnValue 1817 GNUNET_CHAT_context_send_read_receipt (struct GNUNET_CHAT_Context *context, 1818 struct GNUNET_CHAT_Message *message) 1819 { 1820 GNUNET_CHAT_VERSION_ASSERT(); 1821 1822 if ((!context) || (!(context->room))) 1823 return GNUNET_SYSERR; 1824 1825 char zero = '\0'; 1826 struct GNUNET_MESSENGER_Message msg; 1827 memset(&msg, 0, sizeof(msg)); 1828 1829 msg.header.kind = GNUNET_MESSENGER_KIND_TEXT; 1830 msg.body.text.text = &zero; 1831 1832 const struct GNUNET_MESSENGER_Contact *receiver = NULL; 1833 1834 if (!message) 1835 goto skip_filter; 1836 1837 if (GNUNET_CHAT_FLAG_NONE != message->flag) 1838 return GNUNET_SYSERR; 1839 1840 if (message->flags & GNUNET_MESSENGER_FLAG_SENT) 1841 return GNUNET_OK; 1842 1843 if (message->flags & GNUNET_MESSENGER_FLAG_PRIVATE) 1844 { 1845 receiver = GNUNET_MESSENGER_get_sender(context->room, &(message->hash)); 1846 1847 if (!receiver) 1848 return GNUNET_SYSERR; 1849 } 1850 1851 if ((GNUNET_YES != message_has_msg(message)) || 1852 (GNUNET_MESSENGER_KIND_TEXT != message->msg->header.kind)) 1853 goto skip_filter; 1854 1855 if ((!(message->msg->body.text.text)) || 1856 (!(message->msg->body.text.text[0]))) 1857 return GNUNET_SYSERR; 1858 1859 skip_filter: 1860 GNUNET_MESSENGER_send_message(context->room, &msg, receiver); 1861 return GNUNET_OK; 1862 } 1863 1864 1865 struct GNUNET_CHAT_File* 1866 GNUNET_CHAT_context_send_file (struct GNUNET_CHAT_Context *context, 1867 const char *path, 1868 GNUNET_CHAT_FileUploadCallback callback, 1869 void *cls) 1870 { 1871 GNUNET_CHAT_VERSION_ASSERT(); 1872 1873 if ((!context) || (!path) || (!(context->room))) 1874 return NULL; 1875 1876 struct GNUNET_HashCode hash; 1877 if (GNUNET_OK != util_hash_file(path, &hash)) 1878 return NULL; 1879 1880 char *filename = handle_create_file_path( 1881 context->handle, &hash 1882 ); 1883 1884 if (!filename) 1885 return NULL; 1886 1887 struct GNUNET_CHAT_File *file = GNUNET_CONTAINER_multihashmap_get( 1888 context->handle->files, 1889 &hash 1890 ); 1891 1892 if (file) 1893 goto file_binding; 1894 1895 if ((GNUNET_YES == GNUNET_DISK_file_test(filename)) || 1896 (GNUNET_OK != GNUNET_DISK_directory_create_for_file(filename)) || 1897 (GNUNET_OK != GNUNET_DISK_file_copy(path, filename))) 1898 { 1899 GNUNET_free(filename); 1900 return NULL; 1901 } 1902 1903 char* p = GNUNET_strdup(path); 1904 1905 file = file_create_from_disk( 1906 context->handle, 1907 basename(p), 1908 &hash 1909 ); 1910 1911 GNUNET_free(p); 1912 1913 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 1914 context->handle->files, &hash, file, 1915 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 1916 { 1917 file_destroy(file); 1918 GNUNET_free(filename); 1919 return NULL; 1920 } 1921 1922 struct GNUNET_FS_BlockOptions bo; 1923 1924 bo.anonymity_level = block_anonymity_level; 1925 bo.content_priority = block_content_priority; 1926 bo.replication_level = block_replication_level; 1927 bo.expiration_time = GNUNET_TIME_absolute_get_forever_(); 1928 1929 struct GNUNET_FS_FileInformation* fi = GNUNET_FS_file_information_create_from_file( 1930 context->handle->fs, 1931 file, 1932 filename, 1933 NULL, 1934 file->meta, 1935 GNUNET_YES, 1936 &bo 1937 ); 1938 1939 file->publish = GNUNET_FS_publish_start( 1940 context->handle->fs, fi, 1941 NULL, NULL, NULL, 1942 GNUNET_FS_PUBLISH_OPTION_NONE 1943 ); 1944 1945 if (file->publish) 1946 file->status |= GNUNET_CHAT_FILE_STATUS_PUBLISH; 1947 1948 GNUNET_free(filename); 1949 1950 file_binding: 1951 file_bind_upload(file, context, callback, cls); 1952 return file; 1953 } 1954 1955 1956 enum GNUNET_GenericReturnValue 1957 GNUNET_CHAT_context_share_file (struct GNUNET_CHAT_Context *context, 1958 struct GNUNET_CHAT_File *file) 1959 { 1960 GNUNET_CHAT_VERSION_ASSERT(); 1961 1962 if ((!context) || (!file) || 1963 (!(file->name)) || (strlen(file->name) > NAME_MAX) || 1964 (!(file->uri)) || (!(context->room))) 1965 return GNUNET_SYSERR; 1966 1967 struct GNUNET_MESSENGER_Message msg; 1968 memset(&msg, 0, sizeof(msg)); 1969 1970 msg.header.kind = GNUNET_MESSENGER_KIND_FILE; 1971 1972 GNUNET_memcpy(&(msg.body.file.hash), &(file->hash), sizeof(file->hash)); 1973 GNUNET_strlcpy(msg.body.file.name, file->name, NAME_MAX); 1974 msg.body.file.uri = GNUNET_FS_uri_to_string(file->uri); 1975 1976 GNUNET_MESSENGER_send_message(context->room, &msg, NULL); 1977 1978 GNUNET_free(msg.body.file.uri); 1979 return GNUNET_OK; 1980 } 1981 1982 1983 enum GNUNET_GenericReturnValue 1984 GNUNET_CHAT_context_send_tag (struct GNUNET_CHAT_Context *context, 1985 struct GNUNET_CHAT_Message *message, 1986 const char *tag) 1987 { 1988 GNUNET_CHAT_VERSION_ASSERT(); 1989 1990 if ((!context) || (!message) || (!tag) || (!(context->room))) 1991 return GNUNET_SYSERR; 1992 1993 char *tag_value = GNUNET_strdup(tag); 1994 1995 struct GNUNET_MESSENGER_Message msg; 1996 memset(&msg, 0, sizeof(msg)); 1997 1998 msg.header.kind = GNUNET_MESSENGER_KIND_TAG; 1999 GNUNET_memcpy(&(msg.body.tag.hash), &(message->hash), 2000 sizeof(struct GNUNET_HashCode)); 2001 msg.body.tag.tag = tag_value; 2002 2003 GNUNET_MESSENGER_send_message( 2004 context->room, 2005 &msg, 2006 NULL 2007 ); 2008 2009 GNUNET_free(tag_value); 2010 return GNUNET_OK; 2011 } 2012 2013 2014 struct GNUNET_CHAT_Discourse* 2015 GNUNET_CHAT_context_open_discourse (struct GNUNET_CHAT_Context *context, 2016 const struct GNUNET_CHAT_DiscourseId *id) 2017 { 2018 GNUNET_CHAT_VERSION_ASSERT(); 2019 2020 if ((!context) || (!(context->discourses)) || (!(context->room)) || (!id)) 2021 return NULL; 2022 2023 struct GNUNET_ShortHashCode sid; 2024 util_shorthash_from_discourse_id(id, &sid); 2025 2026 struct GNUNET_CHAT_Discourse *discourse = GNUNET_CONTAINER_multishortmap_get( 2027 context->discourses, &sid 2028 ); 2029 2030 if (!discourse) 2031 { 2032 discourse = discourse_create(context, id); 2033 2034 if (GNUNET_OK != GNUNET_CONTAINER_multishortmap_put(context->discourses, 2035 &sid, discourse, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 2036 { 2037 discourse_destroy(discourse); 2038 return NULL; 2039 } 2040 } 2041 2042 struct GNUNET_MESSENGER_Message msg; 2043 memset(&msg, 0, sizeof(msg)); 2044 2045 msg.header.kind = GNUNET_MESSENGER_KIND_SUBSCRIBTION; 2046 GNUNET_memcpy( 2047 &(msg.body.subscription.discourse), 2048 &sid, 2049 sizeof(struct GNUNET_ShortHashCode) 2050 ); 2051 2052 const struct GNUNET_TIME_Relative subscription_time = GNUNET_TIME_relative_multiply( 2053 GNUNET_TIME_relative_get_second_(), 10 2054 ); 2055 2056 msg.body.subscription.time = GNUNET_TIME_relative_hton(subscription_time); 2057 msg.body.subscription.flags = GNUNET_MESSENGER_FLAG_SUBSCRIPTION_KEEP_ALIVE; 2058 2059 GNUNET_MESSENGER_send_message( 2060 context->room, 2061 &msg, 2062 NULL 2063 ); 2064 2065 return discourse; 2066 } 2067 2068 2069 int 2070 GNUNET_CHAT_context_iterate_messages (struct GNUNET_CHAT_Context *context, 2071 GNUNET_CHAT_ContextMessageCallback callback, 2072 void *cls) 2073 { 2074 GNUNET_CHAT_VERSION_ASSERT(); 2075 2076 if (!context) 2077 return GNUNET_SYSERR; 2078 2079 struct GNUNET_CHAT_ContextIterateMessages it; 2080 it.context = context; 2081 it.cb = callback; 2082 it.cls = cls; 2083 2084 return GNUNET_CONTAINER_multihashmap_iterate( 2085 context->messages, it_context_iterate_messages, &it 2086 ); 2087 } 2088 2089 2090 int 2091 GNUNET_CHAT_context_iterate_files (struct GNUNET_CHAT_Context *context, 2092 GNUNET_CHAT_ContextFileCallback callback, 2093 void *cls) 2094 { 2095 GNUNET_CHAT_VERSION_ASSERT(); 2096 2097 if (!context) 2098 return GNUNET_SYSERR; 2099 2100 struct GNUNET_CHAT_ContextIterateFiles it; 2101 it.context = context; 2102 it.cb = callback; 2103 it.cls = cls; 2104 2105 return GNUNET_CONTAINER_multihashmap_iterate( 2106 context->files, it_context_iterate_files, &it 2107 ); 2108 } 2109 2110 2111 enum GNUNET_CHAT_MessageKind 2112 GNUNET_CHAT_message_get_kind (const struct GNUNET_CHAT_Message *message) 2113 { 2114 GNUNET_CHAT_VERSION_ASSERT(); 2115 2116 if (!message) 2117 return GNUNET_CHAT_KIND_UNKNOWN; 2118 2119 switch (message->flag) 2120 { 2121 case GNUNET_CHAT_FLAG_WARNING: 2122 return GNUNET_CHAT_KIND_WARNING; 2123 case GNUNET_CHAT_FLAG_REFRESH: 2124 return GNUNET_CHAT_KIND_REFRESH; 2125 case GNUNET_CHAT_FLAG_LOGIN: 2126 return GNUNET_CHAT_KIND_LOGIN; 2127 case GNUNET_CHAT_FLAG_LOGOUT: 2128 return GNUNET_CHAT_KIND_LOGOUT; 2129 case GNUNET_CHAT_FLAG_CREATE_ACCOUNT: 2130 return GNUNET_CHAT_KIND_CREATED_ACCOUNT; 2131 case GNUNET_CHAT_FLAG_DELETE_ACCOUNT: 2132 return GNUNET_CHAT_KIND_DELETED_ACCOUNT; 2133 case GNUNET_CHAT_FLAG_UPDATE_ACCOUNT: 2134 return GNUNET_CHAT_KIND_UPDATE_ACCOUNT; 2135 case GNUNET_CHAT_FLAG_UPDATE_CONTEXT: 2136 return GNUNET_CHAT_KIND_UPDATE_CONTEXT; 2137 case GNUNET_CHAT_FLAG_ATTRIBUTES: 2138 return GNUNET_CHAT_KIND_ATTRIBUTES; 2139 case GNUNET_CHAT_FLAG_SHARE_ATTRIBUTES: 2140 return GNUNET_CHAT_KIND_SHARED_ATTRIBUTES; 2141 default: 2142 break; 2143 } 2144 2145 if (GNUNET_YES != message_has_msg(message)) 2146 return GNUNET_CHAT_KIND_UNKNOWN; 2147 2148 return util_message_kind_from_kind(message->msg->header.kind); 2149 } 2150 2151 2152 time_t 2153 GNUNET_CHAT_message_get_timestamp (const struct GNUNET_CHAT_Message *message) 2154 { 2155 GNUNET_CHAT_VERSION_ASSERT(); 2156 2157 if ((!message) || (GNUNET_YES != message_has_msg(message))) 2158 return ((time_t) -1); 2159 2160 struct GNUNET_TIME_Absolute abs = GNUNET_TIME_absolute_ntoh( 2161 message->msg->header.timestamp 2162 ); 2163 2164 struct GNUNET_TIME_Timestamp ts = GNUNET_TIME_absolute_to_timestamp( 2165 abs 2166 ); 2167 2168 return (time_t) GNUNET_TIME_timestamp_to_s(ts); 2169 } 2170 2171 2172 struct GNUNET_CHAT_Contact* 2173 GNUNET_CHAT_message_get_sender (const struct GNUNET_CHAT_Message *message) 2174 { 2175 GNUNET_CHAT_VERSION_ASSERT(); 2176 2177 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2178 (!(message->context)) || (!(message->context->room))) 2179 return NULL; 2180 2181 const struct GNUNET_MESSENGER_Contact *sender = GNUNET_MESSENGER_get_sender( 2182 message->context->room, &(message->hash) 2183 ); 2184 2185 if (!sender) 2186 return NULL; 2187 2188 return handle_get_contact_from_messenger(message->context->handle, sender); 2189 } 2190 2191 2192 struct GNUNET_CHAT_Contact* 2193 GNUNET_CHAT_message_get_recipient (const struct GNUNET_CHAT_Message *message) 2194 { 2195 GNUNET_CHAT_VERSION_ASSERT(); 2196 2197 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2198 (!(message->context)) || (!(message->context->room))) 2199 return NULL; 2200 2201 const struct GNUNET_MESSENGER_Contact *recipient = GNUNET_MESSENGER_get_recipient( 2202 message->context->room, &(message->hash) 2203 ); 2204 2205 if (!recipient) 2206 return NULL; 2207 2208 return handle_get_contact_from_messenger(message->context->handle, recipient); 2209 } 2210 2211 2212 enum GNUNET_GenericReturnValue 2213 GNUNET_CHAT_message_is_sent (const struct GNUNET_CHAT_Message *message) 2214 { 2215 GNUNET_CHAT_VERSION_ASSERT(); 2216 2217 if (!message) 2218 return GNUNET_SYSERR; 2219 2220 if (message->flags & GNUNET_MESSENGER_FLAG_SENT) 2221 return GNUNET_YES; 2222 else 2223 return GNUNET_NO; 2224 } 2225 2226 2227 enum GNUNET_GenericReturnValue 2228 GNUNET_CHAT_message_is_private (const struct GNUNET_CHAT_Message *message) 2229 { 2230 GNUNET_CHAT_VERSION_ASSERT(); 2231 2232 if (!message) 2233 return GNUNET_SYSERR; 2234 2235 if (message->flags & GNUNET_MESSENGER_FLAG_PRIVATE) 2236 return GNUNET_YES; 2237 else 2238 return GNUNET_NO; 2239 } 2240 2241 2242 enum GNUNET_GenericReturnValue 2243 GNUNET_CHAT_message_is_recent (const struct GNUNET_CHAT_Message *message) 2244 { 2245 GNUNET_CHAT_VERSION_ASSERT(); 2246 2247 if (!message) 2248 return GNUNET_SYSERR; 2249 2250 if (message->flags & GNUNET_MESSENGER_FLAG_RECENT) 2251 return GNUNET_YES; 2252 else 2253 return GNUNET_NO; 2254 } 2255 2256 2257 enum GNUNET_GenericReturnValue 2258 GNUNET_CHAT_message_is_update (const struct GNUNET_CHAT_Message *message) 2259 { 2260 GNUNET_CHAT_VERSION_ASSERT(); 2261 2262 if (!message) 2263 return GNUNET_SYSERR; 2264 2265 if (message->flags & GNUNET_MESSENGER_FLAG_UPDATE) 2266 return GNUNET_YES; 2267 else 2268 return GNUNET_NO; 2269 } 2270 2271 2272 enum GNUNET_GenericReturnValue 2273 GNUNET_CHAT_message_is_deleted (const struct GNUNET_CHAT_Message *message) 2274 { 2275 GNUNET_CHAT_VERSION_ASSERT(); 2276 2277 if (!message) 2278 return GNUNET_SYSERR; 2279 2280 if ((GNUNET_CHAT_FLAG_NONE == message->flag) && 2281 ((message->flags & GNUNET_MESSENGER_FLAG_DELETE) || 2282 (!message->msg))) 2283 return GNUNET_YES; 2284 else 2285 return GNUNET_NO; 2286 } 2287 2288 2289 enum GNUNET_GenericReturnValue 2290 GNUNET_CHAT_message_is_tagged (const struct GNUNET_CHAT_Message *message, 2291 const char *tag) 2292 { 2293 GNUNET_CHAT_VERSION_ASSERT(); 2294 2295 if ((!message) || (!(message->context))) 2296 return GNUNET_SYSERR; 2297 2298 const struct GNUNET_CHAT_InternalTagging *tagging = GNUNET_CONTAINER_multihashmap_get( 2299 message->context->taggings, &(message->hash)); 2300 2301 if (!tagging) 2302 return GNUNET_NO; 2303 2304 if (internal_tagging_iterate(tagging, GNUNET_NO, tag, NULL, NULL) > 0) 2305 return GNUNET_YES; 2306 else 2307 return GNUNET_NO; 2308 } 2309 2310 2311 int 2312 GNUNET_CHAT_message_get_read_receipt (struct GNUNET_CHAT_Message *message, 2313 GNUNET_CHAT_MessageReadReceiptCallback callback, 2314 void *cls) 2315 { 2316 GNUNET_CHAT_VERSION_ASSERT(); 2317 2318 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2319 (!(message->context))) 2320 return GNUNET_SYSERR; 2321 2322 struct GNUNET_CHAT_MessageIterateReadReceipts it; 2323 it.message = message; 2324 it.cb = callback; 2325 it.cls = cls; 2326 2327 return GNUNET_MESSENGER_iterate_members( 2328 message->context->room, it_message_iterate_read_receipts, &it 2329 ); 2330 } 2331 2332 2333 const char* 2334 GNUNET_CHAT_message_get_text (const struct GNUNET_CHAT_Message *message) 2335 { 2336 GNUNET_CHAT_VERSION_ASSERT(); 2337 2338 if (!message) 2339 return NULL; 2340 2341 if (GNUNET_CHAT_FLAG_WARNING == message->flag) 2342 return message->warning; 2343 else if (GNUNET_CHAT_FLAG_UPDATE_ACCOUNT == message->flag) 2344 return message->warning; 2345 else if (GNUNET_CHAT_FLAG_ATTRIBUTES == message->flag) 2346 return message->attr; 2347 2348 if (GNUNET_YES != message_has_msg(message)) 2349 return NULL; 2350 2351 if (GNUNET_MESSENGER_KIND_TEXT == message->msg->header.kind) 2352 return message->msg->body.text.text; 2353 else if (GNUNET_MESSENGER_KIND_FILE == message->msg->header.kind) 2354 return message->msg->body.file.name; 2355 else if (GNUNET_MESSENGER_KIND_TAG == message->msg->header.kind) 2356 return message->msg->body.tag.tag; 2357 else 2358 return NULL; 2359 } 2360 2361 2362 void 2363 GNUNET_CHAT_message_set_user_pointer (struct GNUNET_CHAT_Message *message, 2364 void *user_pointer) 2365 { 2366 GNUNET_CHAT_VERSION_ASSERT(); 2367 2368 if (!message) 2369 return; 2370 2371 message->user_pointer = user_pointer; 2372 } 2373 2374 2375 void* 2376 GNUNET_CHAT_message_get_user_pointer (const struct GNUNET_CHAT_Message *message) 2377 { 2378 GNUNET_CHAT_VERSION_ASSERT(); 2379 2380 if (!message) 2381 return NULL; 2382 2383 return message->user_pointer; 2384 } 2385 2386 2387 struct GNUNET_CHAT_Account* 2388 GNUNET_CHAT_message_get_account (const struct GNUNET_CHAT_Message *message) 2389 { 2390 GNUNET_CHAT_VERSION_ASSERT(); 2391 2392 if (!message) 2393 return NULL; 2394 2395 if ((message->context) && (message->context->handle)) 2396 return message->context->handle->current; 2397 else 2398 return message->account; 2399 } 2400 2401 2402 struct GNUNET_CHAT_File* 2403 GNUNET_CHAT_message_get_file (const struct GNUNET_CHAT_Message *message) 2404 { 2405 GNUNET_CHAT_VERSION_ASSERT(); 2406 2407 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2408 (!(message->context))) 2409 return NULL; 2410 2411 if (GNUNET_MESSENGER_KIND_FILE != message->msg->header.kind) 2412 return NULL; 2413 2414 return GNUNET_CONTAINER_multihashmap_get( 2415 message->context->handle->files, 2416 &(message->msg->body.file.hash) 2417 ); 2418 } 2419 2420 2421 struct GNUNET_CHAT_Invitation* 2422 GNUNET_CHAT_message_get_invitation (const struct GNUNET_CHAT_Message *message) 2423 { 2424 GNUNET_CHAT_VERSION_ASSERT(); 2425 2426 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2427 (!(message->context))) 2428 return NULL; 2429 2430 if (GNUNET_MESSENGER_KIND_INVITE != message->msg->header.kind) 2431 return NULL; 2432 2433 return GNUNET_CONTAINER_multihashmap_get( 2434 message->context->invites, 2435 &(message->hash) 2436 ); 2437 } 2438 2439 2440 struct GNUNET_CHAT_Discourse* 2441 GNUNET_CHAT_message_get_discourse (const struct GNUNET_CHAT_Message *message) 2442 { 2443 GNUNET_CHAT_VERSION_ASSERT(); 2444 2445 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2446 (!(message->context)) || (!(message->context->discourses))) 2447 return NULL; 2448 2449 struct GNUNET_CHAT_Discourse *discourse; 2450 2451 if (GNUNET_MESSENGER_KIND_SUBSCRIBTION == message->msg->header.kind) 2452 discourse = GNUNET_CONTAINER_multishortmap_get( 2453 message->context->discourses, 2454 &(message->msg->body.subscription.discourse)); 2455 else if (GNUNET_MESSENGER_KIND_TALK == message->msg->header.kind) 2456 discourse = GNUNET_CONTAINER_multishortmap_get( 2457 message->context->discourses, 2458 &(message->msg->body.talk.discourse)); 2459 else 2460 discourse = NULL; 2461 2462 return discourse; 2463 } 2464 2465 2466 struct GNUNET_CHAT_Message* 2467 GNUNET_CHAT_message_get_target (const struct GNUNET_CHAT_Message *message) 2468 { 2469 GNUNET_CHAT_VERSION_ASSERT(); 2470 2471 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2472 (!(message->context))) 2473 return NULL; 2474 2475 struct GNUNET_CHAT_Message *target; 2476 2477 if (GNUNET_MESSENGER_KIND_DELETION == message->msg->header.kind) 2478 target = GNUNET_CONTAINER_multihashmap_get( 2479 message->context->messages, &(message->msg->body.deletion.hash)); 2480 else if (GNUNET_MESSENGER_KIND_TAG == message->msg->header.kind) 2481 target = GNUNET_CONTAINER_multihashmap_get( 2482 message->context->messages, &(message->msg->body.tag.hash)); 2483 else 2484 target = NULL; 2485 2486 return target; 2487 } 2488 2489 2490 enum GNUNET_GenericReturnValue 2491 GNUNET_CHAT_message_delete (struct GNUNET_CHAT_Message *message, 2492 unsigned int delay) 2493 { 2494 GNUNET_CHAT_VERSION_ASSERT(); 2495 2496 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2497 (!(message->context))) 2498 return GNUNET_SYSERR; 2499 2500 struct GNUNET_TIME_Relative rel = GNUNET_TIME_relative_multiply( 2501 GNUNET_TIME_relative_get_second_(), delay 2502 ); 2503 2504 GNUNET_MESSENGER_delete_message( 2505 message->context->room, 2506 &(message->hash), 2507 rel 2508 ); 2509 2510 return GNUNET_OK; 2511 } 2512 2513 2514 int 2515 GNUNET_CHAT_message_iterate_tags (struct GNUNET_CHAT_Message *message, 2516 GNUNET_CHAT_MessageCallback callback, 2517 void *cls) 2518 { 2519 GNUNET_CHAT_VERSION_ASSERT(); 2520 2521 if ((!message) || (!(message->context))) 2522 return GNUNET_SYSERR; 2523 2524 const struct GNUNET_CHAT_InternalTagging *tagging = GNUNET_CONTAINER_multihashmap_get( 2525 message->context->taggings, &(message->hash)); 2526 2527 if (!tagging) 2528 return 0; 2529 2530 return internal_tagging_iterate(tagging, GNUNET_YES, NULL, callback, cls); 2531 } 2532 2533 2534 uint64_t 2535 GNUNET_CHAT_message_available (const struct GNUNET_CHAT_Message *message) 2536 { 2537 GNUNET_CHAT_VERSION_ASSERT(); 2538 2539 if ((!message) || (GNUNET_YES != message_has_msg(message))) 2540 return 0; 2541 2542 if (GNUNET_MESSENGER_KIND_TALK == message->msg->header.kind) 2543 return message->msg->body.talk.length; 2544 else 2545 return 0; 2546 } 2547 2548 2549 enum GNUNET_GenericReturnValue 2550 GNUNET_CHAT_message_read (const struct GNUNET_CHAT_Message *message, 2551 char *data, 2552 uint64_t size) 2553 { 2554 GNUNET_CHAT_VERSION_ASSERT(); 2555 2556 if ((!message) || (GNUNET_YES != message_has_msg(message))) 2557 return GNUNET_SYSERR; 2558 2559 if (GNUNET_MESSENGER_KIND_TALK != message->msg->header.kind) 2560 return GNUNET_SYSERR; 2561 2562 const uint64_t available = message->msg->body.talk.length; 2563 2564 if (available < size) 2565 return GNUNET_NO; 2566 2567 GNUNET_memcpy( 2568 data, 2569 message->msg->body.talk.data, 2570 size 2571 ); 2572 2573 return GNUNET_OK; 2574 } 2575 2576 2577 enum GNUNET_GenericReturnValue 2578 GNUNET_CHAT_message_feed (const struct GNUNET_CHAT_Message *message, 2579 int fd) 2580 { 2581 GNUNET_CHAT_VERSION_ASSERT(); 2582 2583 if ((!message) || (GNUNET_YES != message_has_msg(message)) || 2584 (fd == -1)) 2585 return GNUNET_SYSERR; 2586 2587 if (GNUNET_MESSENGER_KIND_TALK != message->msg->header.kind) 2588 return GNUNET_SYSERR; 2589 2590 if (!(message->msg->body.talk.length)) 2591 return GNUNET_NO; 2592 2593 const ssize_t written = write( 2594 fd, 2595 message->msg->body.talk.data, 2596 message->msg->body.talk.length 2597 ); 2598 2599 if (-1 == written) 2600 return GNUNET_SYSERR; 2601 else if (written != message->msg->body.talk.length) 2602 return GNUNET_NO; 2603 else 2604 return GNUNET_OK; 2605 } 2606 2607 2608 const char* 2609 GNUNET_CHAT_file_get_name (const struct GNUNET_CHAT_File *file) 2610 { 2611 GNUNET_CHAT_VERSION_ASSERT(); 2612 2613 if (!file) 2614 return NULL; 2615 2616 return file->name; 2617 } 2618 2619 2620 const char* 2621 GNUNET_CHAT_file_get_hash (const struct GNUNET_CHAT_File *file) 2622 { 2623 GNUNET_CHAT_VERSION_ASSERT(); 2624 2625 if (!file) 2626 return NULL; 2627 2628 return GNUNET_h2s_full(&(file->hash)); 2629 } 2630 2631 2632 uint64_t 2633 GNUNET_CHAT_file_get_size (const struct GNUNET_CHAT_File *file) 2634 { 2635 GNUNET_CHAT_VERSION_ASSERT(); 2636 2637 if ((!file) || (!(file->uri))) 2638 return 0; 2639 2640 return GNUNET_FS_uri_chk_get_file_size(file->uri); 2641 } 2642 2643 2644 uint64_t 2645 GNUNET_CHAT_file_get_local_size (const struct GNUNET_CHAT_File *file) 2646 { 2647 GNUNET_CHAT_VERSION_ASSERT(); 2648 2649 if (!file) 2650 return 0; 2651 2652 char *filename = handle_create_file_path( 2653 file->handle, &(file->hash) 2654 ); 2655 2656 if (!filename) 2657 return 0; 2658 2659 uint64_t size; 2660 if (GNUNET_OK != GNUNET_DISK_file_size(filename, &size, GNUNET_NO, GNUNET_YES)) 2661 size = 0; 2662 2663 GNUNET_free(filename); 2664 return size; 2665 } 2666 2667 2668 struct GNUNET_CHAT_Uri* 2669 GNUNET_CHAT_file_get_uri (const struct GNUNET_CHAT_File *file) 2670 { 2671 GNUNET_CHAT_VERSION_ASSERT(); 2672 2673 if ((!file) || (!(file->uri))) 2674 return NULL; 2675 2676 return uri_create_file(file->uri); 2677 } 2678 2679 2680 enum GNUNET_GenericReturnValue 2681 GNUNET_CHAT_file_is_uploading (const struct GNUNET_CHAT_File *file) 2682 { 2683 GNUNET_CHAT_VERSION_ASSERT(); 2684 2685 if ((!file) || (0 == (file->status & GNUNET_CHAT_FILE_STATUS_PUBLISH))) 2686 return GNUNET_NO; 2687 else 2688 return GNUNET_YES; 2689 } 2690 2691 2692 enum GNUNET_GenericReturnValue 2693 GNUNET_CHAT_file_is_ready (const struct GNUNET_CHAT_File *file) 2694 { 2695 GNUNET_CHAT_VERSION_ASSERT(); 2696 2697 if ((!file) || (file->status & GNUNET_CHAT_FILE_STATUS_MASK)) 2698 return GNUNET_NO; 2699 2700 const uint64_t size = GNUNET_CHAT_file_get_size(file); 2701 const uint64_t local_size = GNUNET_CHAT_file_get_local_size(file); 2702 2703 if (size != local_size) 2704 return GNUNET_NO; 2705 else 2706 return GNUNET_YES; 2707 } 2708 2709 2710 enum GNUNET_GenericReturnValue 2711 GNUNET_CHAT_file_is_valid (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_SYSERR; 2717 2718 char *filename = handle_create_file_path( 2719 file->handle, &(file->hash) 2720 ); 2721 2722 if (!filename) 2723 return GNUNET_SYSERR; 2724 2725 struct GNUNET_HashCode hash; 2726 enum GNUNET_GenericReturnValue result; 2727 2728 if (GNUNET_OK == util_hash_file(filename, &hash)) 2729 { 2730 if (0 == GNUNET_CRYPTO_hash_cmp(&hash, &(file->hash))) 2731 result = GNUNET_YES; 2732 else 2733 result = GNUNET_NO; 2734 } 2735 else 2736 result = GNUNET_SYSERR; 2737 2738 GNUNET_free(filename); 2739 return result; 2740 } 2741 2742 2743 const char* 2744 GNUNET_CHAT_file_open_preview (struct GNUNET_CHAT_File *file) 2745 { 2746 GNUNET_CHAT_VERSION_ASSERT(); 2747 2748 if (!file) 2749 return NULL; 2750 2751 if (file->preview) 2752 return file->preview; 2753 2754 char *filename = handle_create_file_path( 2755 file->handle, &(file->hash) 2756 ); 2757 2758 if (!filename) 2759 return NULL; 2760 2761 if (GNUNET_YES != GNUNET_DISK_file_test(filename)) 2762 { 2763 GNUNET_free(filename); 2764 filename = NULL; 2765 } 2766 2767 file->preview = filename; 2768 return file->preview; 2769 } 2770 2771 2772 void 2773 GNUNET_CHAT_file_close_preview (struct GNUNET_CHAT_File *file) 2774 { 2775 GNUNET_CHAT_VERSION_ASSERT(); 2776 2777 if ((!file) || (!(file->preview))) 2778 return; 2779 2780 GNUNET_free(file->preview); 2781 file->preview = NULL; 2782 } 2783 2784 2785 void 2786 GNUNET_CHAT_file_set_user_pointer (struct GNUNET_CHAT_File *file, 2787 void *user_pointer) 2788 { 2789 GNUNET_CHAT_VERSION_ASSERT(); 2790 2791 if (!file) 2792 return; 2793 2794 file->user_pointer = user_pointer; 2795 } 2796 2797 2798 void* 2799 GNUNET_CHAT_file_get_user_pointer (const struct GNUNET_CHAT_File *file) 2800 { 2801 GNUNET_CHAT_VERSION_ASSERT(); 2802 2803 if (!file) 2804 return NULL; 2805 2806 return file->user_pointer; 2807 } 2808 2809 2810 enum GNUNET_GenericReturnValue 2811 GNUNET_CHAT_file_is_downloading (const struct GNUNET_CHAT_File *file) 2812 { 2813 GNUNET_CHAT_VERSION_ASSERT(); 2814 2815 if ((!file) || (0 == (file->status & GNUNET_CHAT_FILE_STATUS_DOWNLOAD))) 2816 return GNUNET_NO; 2817 else 2818 return GNUNET_YES; 2819 } 2820 2821 2822 enum GNUNET_GenericReturnValue 2823 GNUNET_CHAT_file_start_download (struct GNUNET_CHAT_File *file, 2824 GNUNET_CHAT_FileDownloadCallback callback, 2825 void *cls) 2826 { 2827 GNUNET_CHAT_VERSION_ASSERT(); 2828 2829 if ((!file) || (!(file->uri))) 2830 return GNUNET_SYSERR; 2831 2832 if (file->download) 2833 { 2834 file_bind_downlaod(file, callback, cls); 2835 2836 GNUNET_FS_download_resume(file->download); 2837 return GNUNET_OK; 2838 } 2839 2840 char *filename = handle_create_file_path( 2841 file->handle, &(file->hash) 2842 ); 2843 2844 if (!filename) 2845 return GNUNET_SYSERR; 2846 2847 const uint64_t size = GNUNET_FS_uri_chk_get_file_size(file->uri); 2848 2849 uint64_t offset; 2850 if (GNUNET_OK != GNUNET_DISK_file_size(filename, &offset, 2851 GNUNET_NO, GNUNET_YES)) 2852 offset = 0; 2853 2854 if (offset >= size) 2855 { 2856 if (callback) 2857 callback(cls, file, size, size); 2858 2859 goto free_filename; 2860 } 2861 2862 file_bind_downlaod(file, callback, cls); 2863 2864 const uint64_t remaining = (size - offset); 2865 2866 file->download = GNUNET_FS_download_start( 2867 file->handle->fs, 2868 file->uri, 2869 file->meta, 2870 filename, 2871 NULL, 2872 offset, 2873 remaining, 2874 1, 2875 GNUNET_FS_DOWNLOAD_OPTION_NONE, 2876 file, 2877 NULL 2878 ); 2879 2880 if (file->download) 2881 file->status |= GNUNET_CHAT_FILE_STATUS_DOWNLOAD; 2882 2883 free_filename: 2884 GNUNET_free(filename); 2885 return GNUNET_OK; 2886 } 2887 2888 2889 enum GNUNET_GenericReturnValue 2890 GNUNET_CHAT_file_pause_download (struct GNUNET_CHAT_File *file) 2891 { 2892 GNUNET_CHAT_VERSION_ASSERT(); 2893 2894 if (!file) 2895 return GNUNET_SYSERR; 2896 2897 GNUNET_FS_download_suspend(file->download); 2898 return GNUNET_OK; 2899 } 2900 2901 2902 enum GNUNET_GenericReturnValue 2903 GNUNET_CHAT_file_resume_download (struct GNUNET_CHAT_File *file) 2904 { 2905 GNUNET_CHAT_VERSION_ASSERT(); 2906 2907 if (!file) 2908 return GNUNET_SYSERR; 2909 2910 GNUNET_FS_download_resume(file->download); 2911 return GNUNET_OK; 2912 } 2913 2914 2915 enum GNUNET_GenericReturnValue 2916 GNUNET_CHAT_file_stop_download (struct GNUNET_CHAT_File *file) 2917 { 2918 GNUNET_CHAT_VERSION_ASSERT(); 2919 2920 if (!file) 2921 return GNUNET_SYSERR; 2922 2923 GNUNET_FS_download_stop(file->download, GNUNET_YES); 2924 file->download = NULL; 2925 return GNUNET_OK; 2926 } 2927 2928 2929 enum GNUNET_GenericReturnValue 2930 GNUNET_CHAT_file_is_unindexing (const struct GNUNET_CHAT_File *file) 2931 { 2932 GNUNET_CHAT_VERSION_ASSERT(); 2933 2934 if ((!file) || (0 == (file->status & GNUNET_CHAT_FILE_STATUS_UNINDEX))) 2935 return GNUNET_NO; 2936 else 2937 return GNUNET_YES; 2938 } 2939 2940 2941 enum GNUNET_GenericReturnValue 2942 GNUNET_CHAT_file_unindex (struct GNUNET_CHAT_File *file, 2943 GNUNET_CHAT_FileUnindexCallback callback, 2944 void *cls) 2945 { 2946 GNUNET_CHAT_VERSION_ASSERT(); 2947 2948 if (!file) 2949 return GNUNET_SYSERR; 2950 2951 if (file->publish) 2952 { 2953 GNUNET_FS_publish_stop(file->publish); 2954 file->publish = NULL; 2955 return GNUNET_OK; 2956 } 2957 2958 file_bind_unindex(file, callback, cls); 2959 2960 if (file->unindex) 2961 return GNUNET_OK; 2962 2963 char *filename = handle_create_file_path( 2964 file->handle, &(file->hash) 2965 ); 2966 2967 if (!filename) 2968 return GNUNET_SYSERR; 2969 2970 file->unindex = GNUNET_FS_unindex_start( 2971 file->handle->fs, filename, file 2972 ); 2973 2974 if (file->unindex) 2975 file->status |= GNUNET_CHAT_FILE_STATUS_UNINDEX; 2976 2977 GNUNET_free(filename); 2978 return GNUNET_OK; 2979 } 2980 2981 2982 void 2983 GNUNET_CHAT_invitation_accept (struct GNUNET_CHAT_Invitation *invitation) 2984 { 2985 GNUNET_CHAT_VERSION_ASSERT(); 2986 2987 if (!invitation) 2988 return; 2989 2990 struct GNUNET_CHAT_Handle *handle; 2991 handle = invitation->context->handle; 2992 2993 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains( 2994 handle->contexts, &(invitation->key.hash))) 2995 return; 2996 2997 struct GNUNET_PeerIdentity door; 2998 GNUNET_PEER_resolve(invitation->door, &door); 2999 3000 struct GNUNET_MESSENGER_Room *room; 3001 room = GNUNET_MESSENGER_enter_room( 3002 invitation->context->handle->messenger, 3003 &door, &(invitation->key) 3004 ); 3005 3006 if (!room) 3007 return; 3008 3009 struct GNUNET_CHAT_Context *context; 3010 context = context_create_from_room(handle, room); 3011 3012 if (!context) 3013 return; 3014 3015 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( 3016 handle->contexts, &(invitation->key.hash), context, 3017 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 3018 goto destroy_context; 3019 3020 if (GNUNET_CHAT_CONTEXT_TYPE_GROUP != context->type) 3021 { 3022 context_write_records(context); 3023 return; 3024 } 3025 3026 struct GNUNET_CHAT_Group *group; 3027 group = group_create_from_context(handle, context); 3028 3029 if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put( 3030 handle->groups, &(invitation->key.hash), group, 3031 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) 3032 { 3033 context_write_records(context); 3034 return; 3035 } 3036 3037 group_destroy(group); 3038 3039 GNUNET_CONTAINER_multihashmap_remove( 3040 handle->contexts, &(invitation->key.hash), context); 3041 3042 destroy_context: 3043 context_destroy(context); 3044 } 3045 3046 3047 void 3048 GNUNET_CHAT_invitation_reject (struct GNUNET_CHAT_Invitation *invitation) 3049 { 3050 GNUNET_CHAT_VERSION_ASSERT(); 3051 3052 if (!invitation) 3053 return; 3054 3055 const struct GNUNET_MESSENGER_Contact *sender = GNUNET_MESSENGER_get_sender( 3056 invitation->context->room, &(invitation->hash) 3057 ); 3058 3059 if (!sender) 3060 return; 3061 3062 struct GNUNET_MESSENGER_Message msg; 3063 memset(&msg, 0, sizeof(msg)); 3064 3065 msg.header.kind = GNUNET_MESSENGER_KIND_TAG; 3066 GNUNET_memcpy(&(msg.body.tag.hash), &(invitation->hash), 3067 sizeof(struct GNUNET_HashCode)); 3068 msg.body.tag.tag = NULL; 3069 3070 GNUNET_MESSENGER_send_message(invitation->context->room, &msg, sender); 3071 } 3072 3073 3074 enum GNUNET_GenericReturnValue 3075 GNUNET_CHAT_invitation_is_accepted (const struct GNUNET_CHAT_Invitation *invitation) 3076 { 3077 GNUNET_CHAT_VERSION_ASSERT(); 3078 3079 if (!invitation) 3080 return GNUNET_NO; 3081 3082 return GNUNET_CONTAINER_multihashmap_contains( 3083 invitation->context->handle->contexts, 3084 &(invitation->key.hash) 3085 ); 3086 } 3087 3088 3089 enum GNUNET_GenericReturnValue 3090 GNUNET_CHAT_invitation_is_rejected (const struct GNUNET_CHAT_Invitation *invitation) 3091 { 3092 GNUNET_CHAT_VERSION_ASSERT(); 3093 3094 if (!invitation) 3095 return GNUNET_NO; 3096 3097 const struct GNUNET_CHAT_InternalTagging *tagging = GNUNET_CONTAINER_multihashmap_get( 3098 invitation->context->taggings, &(invitation->hash)); 3099 3100 if (!tagging) 3101 return GNUNET_NO; 3102 3103 if (internal_tagging_iterate(tagging, GNUNET_NO, NULL, NULL, NULL) > 0) 3104 return GNUNET_YES; 3105 else 3106 return GNUNET_NO; 3107 } 3108 3109 3110 enum GNUNET_GenericReturnValue 3111 GNUNET_CHAT_invitation_is_direct (const struct GNUNET_CHAT_Invitation *invitation) 3112 { 3113 GNUNET_CHAT_VERSION_ASSERT(); 3114 3115 if ((invitation->key.code.public_bit) || 3116 (invitation->key.code.group_bit) || 3117 (invitation->key.code.feed_bit)) 3118 return GNUNET_NO; 3119 else 3120 return GNUNET_YES; 3121 } 3122 3123 3124 const struct GNUNET_CHAT_DiscourseId* 3125 GNUNET_CHAT_discourse_get_id (const struct GNUNET_CHAT_Discourse *discourse) 3126 { 3127 GNUNET_CHAT_VERSION_ASSERT(); 3128 3129 if (!discourse) 3130 return NULL; 3131 3132 return &(discourse->id); 3133 } 3134 3135 3136 enum GNUNET_GenericReturnValue 3137 GNUNET_CHAT_discourse_is_open (const struct GNUNET_CHAT_Discourse *discourse) 3138 { 3139 GNUNET_CHAT_VERSION_ASSERT(); 3140 3141 if (!discourse) 3142 return GNUNET_SYSERR; 3143 3144 struct GNUNET_CHAT_DiscourseSubscription *sub; 3145 for (sub = discourse->head; sub; sub = sub->next) 3146 { 3147 if (GNUNET_TIME_absolute_cmp(sub->end, <, GNUNET_TIME_absolute_get())) 3148 continue; 3149 3150 if (GNUNET_YES == sub->contact->owned) 3151 return GNUNET_YES; 3152 } 3153 3154 return GNUNET_NO; 3155 } 3156 3157 3158 void 3159 GNUNET_CHAT_discourse_set_user_pointer (struct GNUNET_CHAT_Discourse *discourse, 3160 void *user_pointer) 3161 { 3162 GNUNET_CHAT_VERSION_ASSERT(); 3163 3164 if (!discourse) 3165 return; 3166 3167 discourse->user_pointer = user_pointer; 3168 } 3169 3170 3171 void* 3172 GNUNET_CHAT_discourse_get_user_pointer (const struct GNUNET_CHAT_Discourse *discourse) 3173 { 3174 GNUNET_CHAT_VERSION_ASSERT(); 3175 3176 if (!discourse) 3177 return NULL; 3178 3179 return discourse->user_pointer; 3180 } 3181 3182 3183 void 3184 GNUNET_CHAT_discourse_close (struct GNUNET_CHAT_Discourse *discourse) 3185 { 3186 GNUNET_CHAT_VERSION_ASSERT(); 3187 3188 if ((!discourse) || (!(discourse->context)) || (!(discourse->context->room))) 3189 return; 3190 3191 struct GNUNET_MESSENGER_Message msg; 3192 memset(&msg, 0, sizeof(msg)); 3193 3194 msg.header.kind = GNUNET_MESSENGER_KIND_SUBSCRIBTION; 3195 3196 util_shorthash_from_discourse_id( 3197 &(discourse->id), 3198 &(msg.body.subscription.discourse) 3199 ); 3200 3201 msg.body.subscription.time = GNUNET_TIME_relative_hton(GNUNET_TIME_relative_get_zero_()); 3202 msg.body.subscription.flags = GNUNET_MESSENGER_FLAG_SUBSCRIPTION_UNSUBSCRIBE; 3203 3204 GNUNET_MESSENGER_send_message( 3205 discourse->context->room, 3206 &msg, 3207 NULL 3208 ); 3209 } 3210 3211 3212 enum GNUNET_GenericReturnValue 3213 GNUNET_CHAT_discourse_write (struct GNUNET_CHAT_Discourse *discourse, 3214 const char *data, 3215 uint64_t size) 3216 { 3217 GNUNET_CHAT_VERSION_ASSERT(); 3218 3219 if ((!discourse) || (!data) || (!(discourse->context)) || 3220 (!(discourse->context->room))) 3221 return GNUNET_SYSERR; 3222 3223 static const uint64_t max_size = (uint16_t) ( 3224 GNUNET_MAX_MESSAGE_SIZE - GNUNET_MIN_MESSAGE_SIZE - 3225 sizeof (struct GNUNET_MESSENGER_Message) 3226 ); 3227 3228 struct GNUNET_MESSENGER_Message msg; 3229 memset(&msg, 0, sizeof(msg)); 3230 3231 msg.header.kind = GNUNET_MESSENGER_KIND_TALK; 3232 msg.body.talk.data = GNUNET_malloc(size > max_size? max_size : size); 3233 3234 util_shorthash_from_discourse_id( 3235 &(discourse->id), 3236 &(msg.body.talk.discourse) 3237 ); 3238 3239 while (size > 0) 3240 { 3241 msg.body.talk.length = (uint16_t) (size > max_size? max_size : size); 3242 3243 GNUNET_memcpy( 3244 msg.body.talk.data, 3245 data, 3246 msg.body.talk.length 3247 ); 3248 3249 size -= msg.body.talk.length; 3250 data += msg.body.talk.length; 3251 3252 GNUNET_MESSENGER_send_message(discourse->context->room, &msg, NULL); 3253 } 3254 3255 GNUNET_free(msg.body.talk.data); 3256 return GNUNET_OK; 3257 } 3258 3259 3260 int 3261 GNUNET_CHAT_discourse_get_fd (const struct GNUNET_CHAT_Discourse *discourse) 3262 { 3263 GNUNET_CHAT_VERSION_ASSERT(); 3264 3265 if (! discourse) 3266 return GNUNET_SYSERR; 3267 3268 return discourse->pipe[1]; 3269 } 3270 3271 3272 int 3273 GNUNET_CHAT_discourse_iterate_contacts (struct GNUNET_CHAT_Discourse *discourse, 3274 GNUNET_CHAT_DiscourseContactCallback callback, 3275 void *cls) 3276 { 3277 GNUNET_CHAT_VERSION_ASSERT(); 3278 3279 if (! discourse) 3280 return GNUNET_SYSERR; 3281 3282 int iterations = 0; 3283 3284 struct GNUNET_CHAT_DiscourseSubscription *sub; 3285 for (sub = discourse->head; sub; sub = sub->next) 3286 { 3287 if (GNUNET_TIME_absolute_cmp(sub->end, <, GNUNET_TIME_absolute_get())) 3288 continue; 3289 3290 if (callback) 3291 callback(cls, discourse, sub->contact); 3292 3293 iterations++; 3294 } 3295 3296 return iterations; 3297 } 3298 3299 enum GNUNET_GenericReturnValue 3300 GNUNET_CHAT_generate_secret (char *secret, 3301 uint32_t secret_len) 3302 { 3303 GNUNET_CHAT_VERSION_ASSERT(); 3304 3305 if (secret_len <= 0) 3306 return GNUNET_SYSERR; 3307 3308 const uint32_t requested = secret_len * 5 / 8 + 1; 3309 const uint32_t size = ((requested*8) + (((requested*8) % 5) > 0 ? 5 - ((requested*8) % 5) : 0)) / 5; 3310 3311 char *raw_secret = GNUNET_malloc(requested); 3312 char *buf; 3313 3314 if (!raw_secret) 3315 return GNUNET_SYSERR; 3316 3317 if (size > secret_len) 3318 { 3319 buf = GNUNET_malloc(size); 3320 3321 if (!buf) 3322 { 3323 GNUNET_free(raw_secret); 3324 return GNUNET_SYSERR; 3325 } 3326 } 3327 else 3328 buf = secret; 3329 3330 GNUNET_CRYPTO_random_block( 3331 raw_secret, 3332 requested 3333 ); 3334 3335 enum GNUNET_GenericReturnValue result; 3336 result = GNUNET_STRINGS_data_to_string( 3337 raw_secret, 3338 requested, 3339 buf, 3340 size 3341 ) == NULL? GNUNET_SYSERR : GNUNET_OK; 3342 3343 GNUNET_CRYPTO_zero_keys(raw_secret, requested); 3344 GNUNET_free(raw_secret); 3345 3346 if (buf != secret) 3347 { 3348 GNUNET_memcpy(secret, buf, secret_len); 3349 GNUNET_CRYPTO_zero_keys(buf, size); 3350 GNUNET_free(buf); 3351 } 3352 3353 return result; 3354 }