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