libgnunetchat

library for GNUnet Messenger
Log | Files | Refs | README | LICENSE

commit e366e189791025f7fad5572bc786f4883152812e
parent 5200796f0fe43ba498eaa7ea5c81e46cdc2d8116
Author: TheJackiMonster <thejackimonster@gmail.com>
Date:   Sun,  4 Jul 2021 23:21:39 +0200

Additions to restructure generalized the messenger API for the purpose of chatting

Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>

Diffstat:
MMakefile | 4+++-
Minclude/gnunet_chat_lib.h | 123++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Asrc/gnunet_chat_config.c | 27+++++++++++++++++++++++++++
Asrc/gnunet_chat_config.h | 30++++++++++++++++++++++++++++++
Msrc/gnunet_chat_contact.c | 4++++
Msrc/gnunet_chat_context.c | 10++++++----
Msrc/gnunet_chat_file.c | 43++++++++++++++++++++++++++++++++++---------
Msrc/gnunet_chat_file.h | 2++
Msrc/gnunet_chat_group.c | 12++++++++++--
Msrc/gnunet_chat_group.h | 7+++++++
Msrc/gnunet_chat_handle.c | 482+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Msrc/gnunet_chat_handle.h | 72++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Asrc/gnunet_chat_invitation.c | 37+++++++++++++++++++++++++++++++++++++
Asrc/gnunet_chat_invitation.h | 35+++++++++++++++++++++++++++++++++++
Msrc/gnunet_chat_message.c | 8++++++++
Msrc/gnunet_chat_message.h | 2+-
16 files changed, 810 insertions(+), 88 deletions(-)

diff --git a/Makefile b/Makefile @@ -7,9 +7,11 @@ LIBRARY = libgnunetchat.so SOURCES = gnunet_chat_handle.c\ gnunet_chat_contact.c\ gnunet_chat_file.c\ + gnunet_chat_invitation.c\ gnunet_chat_group.c\ gnunet_chat_context.c\ - gnunet_chat_message.c + gnunet_chat_message.c\ + gnunet_chat_config.c HEADERS = gnunet_chat_lib.h LIBRARIES = gnunetarm\ diff --git a/include/gnunet_chat_lib.h b/include/gnunet_chat_lib.h @@ -29,6 +29,8 @@ #ifndef GNUNET_CHAT_LIB_H_ #define GNUNET_CHAT_LIB_H_ +#define GNUNET_UNUSED __attribute__ ((unused)) + #include <gnunet/platform.h> #include <gnunet/gnunet_util_lib.h> @@ -40,17 +42,22 @@ enum GNUNET_CHAT_MessageKind /** * TODO */ - GNUNET_CHAT_KIND_TEXT = 1, /**< GNUNET_CHAT_KIND_TEXT */ + GNUNET_CHAT_KIND_TEXT = 1, /**< GNUNET_CHAT_KIND_TEXT */ + + /** + * TODO + */ + GNUNET_CHAT_KIND_FILE = 2, /**< GNUNET_CHAT_KIND_FILE */ /** * TODO */ - GNUNET_CHAT_KIND_FILE = 2, /**< GNUNET_CHAT_KIND_FILE */ + GNUNET_CHAT_KIND_INVITATION = 3, /**< GNUNET_CHAT_KIND_INVITATION */ /** * TODO */ - GNUNET_CHAT_KIND_UNKNOWN = 0/**< GNUNET_CHAT_KIND_UNKNOWN */ + GNUNET_CHAT_KIND_UNKNOWN = 0 /**< GNUNET_CHAT_KIND_UNKNOWN */ }; /** @@ -85,6 +92,11 @@ struct GNUNET_CHAT_File; /** * TODO + */ +struct GNUNET_CHAT_Invitation; + +/** + * TODO * * @param cls * @param handle @@ -157,8 +169,27 @@ typedef int struct GNUNET_CHAT_Contact *contact, int read_receipt); -typedef void -(*GNUNET_CHAT_MessageFileDownloadCallback) (void *cls, struct GNUNET_CHAT_File *file); +/** + * TODO + * + * @param cls + * @param file + * @param completed + */ +typedef int +(*GNUNET_CHAT_MessageFileUploadCallback) (void *cls, const struct GNUNET_CHAT_File *file, + uint64_t completed); + +/** + * TODO + * + * @param cls + * @param file + * @param completed + */ +typedef int +(*GNUNET_CHAT_MessageFileDownloadCallback) (void *cls, struct GNUNET_CHAT_File *file, + uint64_t completed); /** * TODO @@ -172,7 +203,8 @@ typedef void struct GNUNET_CHAT_Handle* GNUNET_CHAT_start (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *name, - GNUNET_CHAT_WarningCallback warn_cb, void *warn_cls); + GNUNET_CHAT_WarningCallback warn_cb, void *warn_cls, + GNUNET_CHAT_ContextMessageCallback msg_cb, void *msg_cls); /** * TODO @@ -306,8 +338,9 @@ GNUNET_CHAT_contact_get_context (struct GNUNET_CHAT_Contact *contact); * TODO * * @param group + * @return */ -void +int GNUNET_CHAT_group_leave (struct GNUNET_CHAT_Group *group); /** @@ -418,11 +451,15 @@ GNUNET_CHAT_context_delete_message (struct GNUNET_CHAT_Context *context, * * @param context * @param hash + * @param callback + * @param cls * @return */ -const struct GNUNET_CHAT_Message* +int GNUNET_CHAT_context_get_message (struct GNUNET_CHAT_Context *context, - const struct GNUNET_HashCode *hash); + const struct GNUNET_HashCode *hash, + GNUNET_CHAT_ContextMessageCallback callback, + void *cls); /** * TODO @@ -499,33 +536,91 @@ GNUNET_CHAT_message_get_file (const struct GNUNET_CHAT_Message *message); /** * TODO * + * @param message + * @return + */ +struct GNUNET_CHAT_Invitation* +GNUNET_CHAT_message_get_invitation (const struct GNUNET_CHAT_Message *message); + +/** + * TODO + * * @param file + * @return */ -void -GNUNET_CHAT_file_start_download (struct GNUNET_CHAT_File *file); +const struct GNUNET_HashCode* +GNUNET_CHAT_file_get_hash (const struct GNUNET_CHAT_File *file); /** * TODO * * @param file + * @return */ -void +uint64_t +GNUNET_CHAT_file_get_size (const struct GNUNET_CHAT_File *file); + +/** + * TODO + * + * @param file + * @return + */ +int +GNUNET_CHAT_file_is_local (const struct GNUNET_CHAT_File *file); + +/** + * TODO + * + * @param file + * @return + */ +int +GNUNET_CHAT_file_start_download (struct GNUNET_CHAT_File *file, + GNUNET_CHAT_MessageFileDownloadCallback callback, + void *cls); + +/** + * TODO + * + * @param file + * @return + */ +int GNUNET_CHAT_file_pause_download (struct GNUNET_CHAT_File *file); /** * TODO * * @param file + * @return */ -void +int GNUNET_CHAT_file_resume_download (struct GNUNET_CHAT_File *file); /** * TODO * * @param file + * @return */ -void +int GNUNET_CHAT_file_stop_download (struct GNUNET_CHAT_File *file); +/** + * TODO + * + * @param invitation + */ +void +GNUNET_CHAT_invitation_accept (struct GNUNET_CHAT_Invitation *invitation); + +/** + * TODO + * + * @param invitation + */ +void +GNUNET_CHAT_invitation_decline (struct GNUNET_CHAT_Invitation *invitation); + #endif /* GNUNET_CHAT_LIB_H_ */ diff --git a/src/gnunet_chat_config.c b/src/gnunet_chat_config.c @@ -0,0 +1,27 @@ +/* + This file is part of GNUnet. + Copyright (C) 2021 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file gnunet_chat_config.c + */ + +#include "gnunet_chat_config.h" + + diff --git a/src/gnunet_chat_config.h b/src/gnunet_chat_config.h @@ -0,0 +1,30 @@ +/* + This file is part of GNUnet. + Copyright (C) 2021 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file gnunet_chat_config.h + */ + +#ifndef GNUNET_CHAT_CONFIG_H_ +#define GNUNET_CHAT_CONFIG_H_ + + + +#endif /* GNUNET_CHAT_CONFIG_H_ */ diff --git a/src/gnunet_chat_contact.c b/src/gnunet_chat_contact.c @@ -140,6 +140,10 @@ GNUNET_CHAT_contact_delete (struct GNUNET_CHAT_Contact *contact) if (!contact) return GNUNET_SYSERR; + if (GNUNET_YES != handle_update_chat_contact(contact->handle, + contact, GNUNET_YES)) + return GNUNET_SYSERR; + if (contact->context) GNUNET_MESSENGER_close_room(contact->context->room); diff --git a/src/gnunet_chat_context.c b/src/gnunet_chat_context.c @@ -165,12 +165,14 @@ GNUNET_CHAT_context_delete_message (struct GNUNET_CHAT_Context *context, GNUNET_MESSENGER_send_message(context->room, &message, NULL); } -const struct GNUNET_CHAT_Message* +int GNUNET_CHAT_context_get_message (struct GNUNET_CHAT_Context *context, - const struct GNUNET_HashCode *hash) + const struct GNUNET_HashCode *hash, + GNUNET_CHAT_ContextMessageCallback callback, + void *cls) { if (!context) - return NULL; + return GNUNET_SYSERR; struct GNUNET_MESSENGER_Message *message = GNUNET_MESSENGER_get_message( context->room, hash @@ -178,7 +180,7 @@ GNUNET_CHAT_context_get_message (struct GNUNET_CHAT_Context *context, //TODO: convert messenger-message to chat-message - return NULL; + return GNUNET_OK; } int diff --git a/src/gnunet_chat_file.c b/src/gnunet_chat_file.c @@ -25,11 +25,31 @@ #include "gnunet_chat_lib.h" #include "gnunet_chat_file.h" -void -GNUNET_CHAT_file_start_download (struct GNUNET_CHAT_File *file) +const struct GNUNET_HashCode* +GNUNET_CHAT_file_get_hash (const struct GNUNET_CHAT_File *file) +{ + return &(file->hash); +} + +uint64_t +GNUNET_CHAT_file_get_size (const struct GNUNET_CHAT_File *file) +{ + return 0; +} + +int +GNUNET_CHAT_file_is_local (const struct GNUNET_CHAT_File *file) +{ + return GNUNET_NO; +} + +int +GNUNET_CHAT_file_start_download (struct GNUNET_CHAT_File *file, + GNUNET_CHAT_MessageFileDownloadCallback callback, + void *cls) { if (!file) - return; + return GNUNET_SYSERR; struct GNUNET_FS_Handle *handle; const char *path = ""; // TODO: path = download_directory + filename @@ -47,31 +67,36 @@ GNUNET_CHAT_file_start_download (struct GNUNET_CHAT_File *file) NULL, NULL ); + + return GNUNET_OK; } -void +int GNUNET_CHAT_file_pause_download (struct GNUNET_CHAT_File *file) { if (!file) - return; + return GNUNET_SYSERR; GNUNET_FS_download_suspend(file->context); + return GNUNET_OK; } -void +int GNUNET_CHAT_file_resume_download (struct GNUNET_CHAT_File *file) { if (!file) - return; + return GNUNET_SYSERR; GNUNET_FS_download_resume(file->context); + return GNUNET_OK; } -void +int GNUNET_CHAT_file_stop_download (struct GNUNET_CHAT_File *file) { if (!file) - return; + return GNUNET_SYSERR; GNUNET_FS_download_stop(file->context, GNUNET_YES); + return GNUNET_OK; } diff --git a/src/gnunet_chat_file.h b/src/gnunet_chat_file.h @@ -27,10 +27,12 @@ #include <gnunet/platform.h> #include <gnunet/gnunet_fs_service.h> +#include <gnunet/gnunet_messenger_service.h> #include <gnunet/gnunet_util_lib.h> struct GNUNET_CHAT_File { + struct GNUNET_HashCode hash; struct GNUNET_FS_Uri* uri; struct GNUNET_FS_DownloadContext* context; }; diff --git a/src/gnunet_chat_group.c b/src/gnunet_chat_group.c @@ -46,6 +46,10 @@ group_create(struct GNUNET_CHAT_Handle *handle, topic? &topic_key : NULL ); + group->is_public = topic? GNUNET_YES : GNUNET_NO; + group->announcement = NULL; + group->search = NULL; + if (!group->context) { group_destroy (group); @@ -90,16 +94,20 @@ skip_context: GNUNET_free(group); } -void +int GNUNET_CHAT_group_leave (struct GNUNET_CHAT_Group *group) { if (!group) - return; + return GNUNET_SYSERR; + + if (GNUNET_YES != handle_update_chat_group(group->handle, group, GNUNET_YES)) + return GNUNET_SYSERR; if (group->context) GNUNET_MESSENGER_close_room(group->context->room); group_destroy(group); + return GNUNET_OK; } void diff --git a/src/gnunet_chat_group.h b/src/gnunet_chat_group.h @@ -25,12 +25,19 @@ #ifndef GNUNET_CHAT_GROUP_H_ #define GNUNET_CHAT_GROUP_H_ +#include <gnunet/gnunet_regex_service.h> + #include "gnunet_chat_context.h" struct GNUNET_CHAT_Group { struct GNUNET_CHAT_Handle *handle; struct GNUNET_CHAT_Context *context; + + int is_public; + + struct GNUNET_REGEX_Announcement *announcement; + struct GNUNET_REGEX_Search *search; }; struct GNUNET_CHAT_Group* diff --git a/src/gnunet_chat_handle.c b/src/gnunet_chat_handle.c @@ -25,57 +25,285 @@ #include "gnunet_chat_lib.h" #include "gnunet_chat_handle.h" #include "gnunet_chat_group.h" +#include "gnunet_chat_contact.h" +#include "gnunet_chat_message.h" +#include "gnunet_chat_file.h" -static void handle_arm_connection(void* cls, int connected) { - struct GNUNET_CHAT_Handle *handle = cls; +static void* +handle_fs_progress(void* cls, const struct GNUNET_FS_ProgressInfo* info) +{ + struct GNUNET_CHAT_Handle *chat = cls; + + if (!chat) + return NULL; + + switch (info->status) { + case GNUNET_FS_STATUS_PUBLISH_START: { + /*publication_t* publication = (publication_t*) info->value.publish.cctx; + publication->progress = 0.0f; + + GNUNET_SCHEDULER_add_now(&CGTK_publication_progress, publication); + + return publication;*/ + } case GNUNET_FS_STATUS_PUBLISH_PROGRESS: { + /*publication_t* publication = (publication_t*) info->value.publish.cctx; + publication->progress = 1.0f * info->value.publish.completed / info->value.publish.size; + + GNUNET_SCHEDULER_add_now(&CGTK_publication_progress, publication); + + return publication;*/ + } case GNUNET_FS_STATUS_PUBLISH_COMPLETED: { + /*publication_t* publication = (publication_t*) info->value.publish.cctx; + publication->uri = GNUNET_FS_uri_dup(info->value.publish.specifics.completed.chk_uri); + publication->progress = 1.0f; + + GNUNET_SCHEDULER_add_now(&CGTK_publication_finish, publication);*/ + break; + } case GNUNET_FS_STATUS_PUBLISH_ERROR: { + /*publication_t* publication = (publication_t*) info->value.publish.cctx; + + GNUNET_SCHEDULER_add_now(&CGTK_publication_error, publication);*/ + break; + } case GNUNET_FS_STATUS_DOWNLOAD_START: { + /*request_t* request = (request_t*) info->value.download.cctx; + request->progress = 0.0f; + + return request;*/ + } case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: { + return info->value.download.cctx; + } case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: { + return info->value.download.cctx; + } case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: { + /*request_t* request = (request_t*) info->value.download.cctx; + request->progress = 1.0f * info->value.download.completed / info->value.download.size; + + GNUNET_SCHEDULER_add_now(&CGTK_request_progress, request); + + return request;*/ + } case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: { + /*request_t* request = (request_t*) info->value.download.cctx; + request->progress = 1.0f; + + GNUNET_SCHEDULER_add_now(&CGTK_request_finish, request);*/ + break; + } case GNUNET_FS_STATUS_DOWNLOAD_ERROR: { + /*request_t *request = (request_t *) info->value.download.cctx; + + GNUNET_SCHEDULER_add_now(&CGTK_request_error, request);*/ + break; + } case GNUNET_FS_STATUS_UNINDEX_START: { + /*publication_t* publication = (publication_t*) info->value.unindex.cctx; + publication->progress = 0.0f; + + return publication;*/ + } case GNUNET_FS_STATUS_UNINDEX_PROGRESS: { + /*publication_t* publication = (publication_t*) info->value.unindex.cctx; + publication->progress = 1.0f * info->value.unindex.completed / info->value.unindex.size; + + return publication;*/ + } case GNUNET_FS_STATUS_UNINDEX_COMPLETED: { + /*publication_t* publication = (publication_t*) info->value.unindex.cctx; + publication->progress = 1.0f; + + GNUNET_SCHEDULER_add_now(&CGTK_publication_unindex_finish, publication);*/ + break; + } default: { + break; + } + } + + return NULL; +} + +static void +handle_on_message (void *cls, + GNUNET_UNUSED struct GNUNET_MESSENGER_Room *room, + GNUNET_UNUSED const struct GNUNET_MESSENGER_Contact *sender, + const struct GNUNET_MESSENGER_Message *message, + const struct GNUNET_HashCode *hash, + GNUNET_UNUSED enum GNUNET_MESSENGER_MessageFlags flags) +{ + struct GNUNET_CHAT_Handle *chat = cls; + + //TODO + + struct GNUNET_CHAT_Message msg; + GNUNET_memcpy(&(msg.hash), hash, sizeof(msg.hash)); + msg.message = message; + + if ((GNUNET_CHAT_KIND_UNKNOWN == GNUNET_CHAT_message_get_kind(&msg)) || + (!chat->msg_cb)) + return; + + chat->msg_cb(chat->msg_cls, NULL /* TODO */, &msg); +} + +struct GNUNET_CHAT_CheckRoomMembers +{ + const struct GNUNET_IDENTITY_PublicKey *ignore_key; + const struct GNUNET_MESSENGER_Contact *contact; +}; + +static int +handle_check_room_members (void* cls, + GNUNET_UNUSED struct GNUNET_MESSENGER_Room *room, + const struct GNUNET_MESSENGER_Contact *contact) +{ + struct GNUNET_CHAT_CheckRoomMembers *check = cls; + const struct GNUNET_IDENTITY_PublicKey *contact_key = ( + GNUNET_MESSENGER_contact_get_key(contact) + ); + + if (0 == GNUNET_memcmp(contact_key, check->ignore_key)) + return GNUNET_YES; + + if (check->contact) + return GNUNET_NO; + + check->contact = contact; + return GNUNET_YES; +} + +static int +handle_initialize_context (void *cls, struct GNUNET_MESSENGER_Room *room, + GNUNET_UNUSED const struct GNUNET_MESSENGER_Contact *contact) +{ + struct GNUNET_CHAT_Handle *chat = cls; + + struct GNUNET_CHAT_CheckRoomMembers check; + check.ignore_key = GNUNET_CHAT_get_key(chat); + check.contact = NULL; + + const int amount = GNUNET_MESSENGER_iterate_members( + room, handle_check_room_members, &check + ); + + if (amount <= 1) + return GNUNET_YES; + + const struct GNUNET_HashCode *key = GNUNET_MESSENGER_room_get_key(room); + struct GNUNET_CHAT_Context *context = handle_get_chat_context(chat, key); + enum GNUNET_CHAT_ContextType type = GNUNET_CHAT_CONTEXT_TYPE_UNKNOWN; + + if (check.contact) + type = GNUNET_CHAT_CONTEXT_TYPE_CONTACT; + else + type = GNUNET_CHAT_CONTEXT_TYPE_GROUP; + + if (!context) + context = context_create(chat, type, key); + else + context->type = type; + + if (GNUNET_YES != handle_update_chat_context(chat, context, GNUNET_NO)) + context_destroy(context); + + return GNUNET_YES; +} + +static void +handle_on_identity(void *cls, struct GNUNET_MESSENGER_Handle *handle) +{ + struct GNUNET_CHAT_Handle *chat = cls; + + //TODO + + GNUNET_MESSENGER_find_rooms( + chat->handles.messenger, NULL, handle_initialize_context, handle + ); +} + +static void +handle_arm_connection(void *cls, int connected) +{ + struct GNUNET_CHAT_Handle *chat = cls; if (GNUNET_YES == connected) { - GNUNET_ARM_request_service_start(handle->handles.arm, "messenger", GNUNET_OS_INHERIT_STD_NONE, NULL, NULL); - GNUNET_ARM_request_service_start(handle->handles.arm, "fs", GNUNET_OS_INHERIT_STD_NONE, NULL, NULL); + GNUNET_ARM_request_service_start(chat->handles.arm, "messenger", + GNUNET_OS_INHERIT_STD_NONE, NULL, NULL); + GNUNET_ARM_request_service_start(chat->handles.arm, "fs", + GNUNET_OS_INHERIT_STD_NONE, NULL, NULL); } else { - GNUNET_ARM_request_service_start(handle->handles.arm, "arm", GNUNET_OS_INHERIT_STD_NONE, NULL, NULL); + GNUNET_ARM_request_service_start(chat->handles.arm, "arm", + GNUNET_OS_INHERIT_STD_NONE, NULL, NULL); } } struct GNUNET_CHAT_Handle* GNUNET_CHAT_start (const struct GNUNET_CONFIGURATION_Handle* cfg, - const char *name, - GNUNET_CHAT_WarningCallback warn_cb, - void *warn_cls) { + const char *name, + GNUNET_CHAT_WarningCallback warn_cb, + void *warn_cls, + GNUNET_CHAT_ContextMessageCallback msg_cb, + void *msg_cls) +{ if (!cfg) return NULL; - struct GNUNET_CHAT_Handle *handle = GNUNET_new(struct GNUNET_CHAT_Handle); - memset(handle, 0, sizeof(*handle)); - handle->cfg = cfg; + struct GNUNET_CHAT_Handle *chat = GNUNET_new(struct GNUNET_CHAT_Handle); + memset(chat, 0, sizeof(*chat)); + chat->cfg = cfg; - handle->handles.arm = GNUNET_ARM_connect(cfg, &handle_arm_connection, handle); + chat->warn_cb = warn_cb; + chat->warn_cls = warn_cls; - if (handle->handles.arm) - handle_arm_connection(handle, GNUNET_NO); + chat->handles.arm = GNUNET_ARM_connect(cfg, &handle_arm_connection, chat); + + if (chat->handles.arm) + handle_arm_connection(chat, GNUNET_NO); - handle->handles.messenger = GNUNET_MESSENGER_connect( - cfg, name, NULL, NULL, NULL, NULL //TODO + chat->handles.messenger = GNUNET_MESSENGER_connect( + cfg, name, + handle_on_identity, chat, + handle_on_message, chat ); - if (!handle->handles.messenger) + if (!chat->handles.messenger) { - GNUNET_CHAT_stop(handle); + GNUNET_CHAT_stop(chat); return NULL; } - handle->handles.fs = GNUNET_FS_start( + chat->handles.fs = GNUNET_FS_start( cfg, - NULL, //TODO - NULL, + name, + handle_fs_progress, + chat, GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END ); - handle->contacts = GNUNET_CONTAINER_multihashmap_create(8, GNUNET_NO); - handle->groups = GNUNET_CONTAINER_multihashmap_create(8, GNUNET_NO); + chat->contacts.short_map = GNUNET_CONTAINER_multishortmap_create(8, GNUNET_NO); + chat->contacts.hash_map = GNUNET_CONTAINER_multihashmap_create(8, GNUNET_NO); + + chat->groups = GNUNET_CONTAINER_multihashmap_create(8, GNUNET_NO); + chat->contexts = GNUNET_CONTAINER_multihashmap_create(8, GNUNET_NO); + chat->files = GNUNET_CONTAINER_multihashmap_create(8, GNUNET_NO); + + chat->msg_cb = msg_cb; + chat->msg_cls = msg_cls; + + return chat; +} + +static int +handle_iterate_destroy_contacts (GNUNET_UNUSED void *cls, + GNUNET_UNUSED const struct GNUNET_HashCode *key, + void *value) +{ + struct GNUNET_CHAT_Contact *contact = value; + contact_destroy(contact); + return GNUNET_YES; +} - return handle; +static int +handle_iterate_destroy_groups (GNUNET_UNUSED void *cls, + GNUNET_UNUSED const struct GNUNET_HashCode *key, + void *value) +{ + struct GNUNET_CHAT_Group *group = value; + group_destroy(group); + return GNUNET_YES; } void @@ -102,18 +330,28 @@ GNUNET_CHAT_stop (struct GNUNET_CHAT_Handle *handle) if (handle->groups) { - // TODO: destroy each + GNUNET_CONTAINER_multihashmap_iterate( + handle->groups, handle_iterate_destroy_groups, NULL + ); GNUNET_CONTAINER_multihashmap_destroy(handle->groups); handle->groups = NULL; } - if (handle->contacts) + if (handle->contacts.hash_map) { - // TODO: destroy each + GNUNET_CONTAINER_multihashmap_iterate( + handle->contacts.hash_map, handle_iterate_destroy_contacts, NULL + ); - GNUNET_CONTAINER_multihashmap_destroy(handle->contacts); - handle->contacts = NULL; + GNUNET_CONTAINER_multihashmap_destroy(handle->contacts.hash_map); + handle->contacts.hash_map = NULL; + } + + if (handle->contacts.short_map) + { + GNUNET_CONTAINER_multishortmap_destroy(handle->contacts.short_map); + handle->contacts.short_map = NULL; } if (handle->handles.arm) @@ -172,7 +410,8 @@ struct GNUNET_CHAT_IterateContacts }; static int -handle_iterate_contacts(void *cls, const struct GNUNET_HashCode *key, +handle_iterate_contacts(void *cls, + GNUNET_UNUSED const struct GNUNET_HashCode *key, void *value) { struct GNUNET_CHAT_IterateContacts *iterate = cls; @@ -197,7 +436,7 @@ GNUNET_CHAT_iterate_contacts (struct GNUNET_CHAT_Handle *handle, iterate.callback = callback; iterate.cls = cls; - return GNUNET_CONTAINER_multihashmap_iterate(handle->contacts, + return GNUNET_CONTAINER_multihashmap_iterate(handle->contacts.hash_map, handle_iterate_contacts, &iterate); } @@ -209,7 +448,18 @@ GNUNET_CHAT_group_create (struct GNUNET_CHAT_Handle *handle, if (!handle) return NULL; - return group_create(handle, topic); + struct GNUNET_CHAT_Group *group = group_create(handle, topic); + + if (!group) + return NULL; + + if (GNUNET_YES != handle_update_chat_group(handle, group, GNUNET_NO)) + { + group_destroy(group); + return NULL; + } + + return group; } struct GNUNET_CHAT_IterateGroups @@ -220,8 +470,9 @@ struct GNUNET_CHAT_IterateGroups }; static int -handle_iterate_groups(void *cls, const struct GNUNET_HashCode *key, - void *value) +handle_iterate_groups(void *cls, + GNUNET_UNUSED const struct GNUNET_HashCode *key, + void *value) { struct GNUNET_CHAT_IterateGroups *iterate = cls; struct GNUNET_CHAT_Group *group = value; @@ -246,6 +497,167 @@ GNUNET_CHAT_iterate_groups (struct GNUNET_CHAT_Handle *handle, iterate.cls = cls; return GNUNET_CONTAINER_multihashmap_iterate(handle->groups, - handle_iterate_contacts, + handle_iterate_groups, &iterate); } + +int +handle_update_chat_contact (struct GNUNET_CHAT_Handle *handle, + struct GNUNET_CHAT_Contact *chatContact, + int removeContact) +{ + const struct GNUNET_HashCode *key = context_get_key(chatContact->context); + + if (GNUNET_YES == removeContact) + { + const int result = GNUNET_CONTAINER_multihashmap_remove( + handle->contacts.hash_map, key, chatContact + ); + + if (GNUNET_YES == result) + return handle_update_chat_context(handle, chatContact->context, + GNUNET_YES); + else + return GNUNET_NO; + } + else + { + const int result = GNUNET_CONTAINER_multihashmap_put( + handle->contacts.hash_map, key, chatContact, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY + ); + + if (GNUNET_OK != result) + return GNUNET_NO; + else + return handle_update_chat_context(handle, chatContact->context, + GNUNET_NO); + } +} + +int +handle_update_chat_group (struct GNUNET_CHAT_Handle *handle, + struct GNUNET_CHAT_Group *chatGroup, + int removeGroup) +{ + const struct GNUNET_HashCode *key = context_get_key(chatGroup->context); + + if (GNUNET_YES == removeGroup) + { + const int result = GNUNET_CONTAINER_multihashmap_remove( + handle->groups, key, chatGroup + ); + + if (GNUNET_YES == result) + return handle_update_chat_context(handle, chatGroup->context, + GNUNET_YES); + else + return GNUNET_NO; + } + else + { + const int result = GNUNET_CONTAINER_multihashmap_put( + handle->groups, key, chatGroup, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY + ); + + if (GNUNET_OK != result) + return GNUNET_NO; + else + return handle_update_chat_context(handle, chatGroup->context, + GNUNET_NO); + } +} + +int +handle_update_chat_context (struct GNUNET_CHAT_Handle *handle, + struct GNUNET_CHAT_Context *context, + int removeContext) +{ + const struct GNUNET_HashCode *key = context_get_key(context); + + if (GNUNET_YES == removeContext) + return GNUNET_CONTAINER_multihashmap_remove( + handle->contexts, key, context + ); + else + { + const int result = GNUNET_CONTAINER_multihashmap_put( + handle->contexts, key, context, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY + ); + + if (GNUNET_OK != result) + return GNUNET_NO; + else + return GNUNET_YES; + } +} + +int +handle_update_chat_file (struct GNUNET_CHAT_Handle *handle, + struct GNUNET_CHAT_File *file, + int removeFile) +{ + const struct GNUNET_HashCode *hash = GNUNET_CHAT_file_get_hash(file); + + if (GNUNET_YES == removeFile) + return GNUNET_CONTAINER_multihashmap_remove( + handle->files, hash, file + ); + else + { + const int result = GNUNET_CONTAINER_multihashmap_put( + handle->files, hash, file, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY + ); + + if (GNUNET_OK != result) + return GNUNET_NO; + else + return GNUNET_YES; + } +} + +static void +handle_get_short_of_contact(struct GNUNET_ShortHashCode *shortHash, + const struct GNUNET_MESSENGER_Contact *contact) +{ + memset(shortHash, 0, sizeof(*shortHash)); + GNUNET_memcpy(shortHash, &contact, sizeof(contact)); +} + +struct GNUNET_CHAT_Contact* +handle_get_chat_contact (struct GNUNET_CHAT_Handle *handle, + const struct GNUNET_MESSENGER_Contact *contact) +{ + struct GNUNET_ShortHashCode shortHash; + handle_get_short_of_contact (&shortHash, contact); + + struct GNUNET_CHAT_Contact* chatContact = GNUNET_CONTAINER_multishortmap_get( + handle->contacts.short_map, &shortHash + ); + + return chatContact; +} + +void +handle_set_chat_contact (struct GNUNET_CHAT_Handle *handle, + const struct GNUNET_MESSENGER_Contact *contact, + struct GNUNET_CHAT_Contact *chatContact) +{ + struct GNUNET_ShortHashCode shortHash; + handle_get_short_of_contact (&shortHash, contact); + + if (chatContact) + { + GNUNET_CONTAINER_multishortmap_remove_all(handle->contacts.short_map, + &shortHash); + return; + } + + GNUNET_CONTAINER_multishortmap_put( + handle->contacts.short_map, &shortHash, chatContact, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE + ); +} diff --git a/src/gnunet_chat_handle.h b/src/gnunet_chat_handle.h @@ -30,10 +30,7 @@ #include <gnunet/gnunet_container_lib.h> #include <gnunet/gnunet_arm_service.h> #include <gnunet/gnunet_fs_service.h> -#include <gnunet/gnunet_gns_service.h> -#include <gnunet/gnunet_identity_service.h> #include <gnunet/gnunet_messenger_service.h> -#include <gnunet/gnunet_reclaim_service.h> #include <gnunet/gnunet_regex_service.h> #include <gnunet/gnunet_util_lib.h> @@ -53,31 +50,62 @@ struct GNUNET_CHAT_Handle struct GNUNET_FS_Handle *fs; /* - * required: (names can be resolved as well as zones and members) - */ - struct GNUNET_GNS_Handle *gns; - - /* - * optional: (if not anonymous to receive private key) - * (has to be reset as soon as the private key changes) - */ - struct GNUNET_IDENTITY_Handle *identity; - - /* * required! */ struct GNUNET_MESSENGER_Handle *messenger; - - /* - * feature/optional: (maybe add new reclaim message kind?) - * (the message would automatically issue the ticket) - * (send the ticket and consume it) - */ - struct GNUNET_RECLAIM_Handle *reclaim; } handles; - struct GNUNET_CONTAINER_MultiHashMap *contacts; + struct { + struct GNUNET_CONTAINER_MultiShortmap *short_map; + struct GNUNET_CONTAINER_MultiHashMap *hash_map; + } contacts; + struct GNUNET_CONTAINER_MultiHashMap *groups; + struct GNUNET_CONTAINER_MultiHashMap *contexts; + struct GNUNET_CONTAINER_MultiHashMap *files; + + GNUNET_CHAT_ContextMessageCallback msg_cb; + void *msg_cls; + + GNUNET_CHAT_WarningCallback warn_cb; + void *warn_cls; }; +int +handle_update_chat_contact (struct GNUNET_CHAT_Handle *handle, + struct GNUNET_CHAT_Contact *chatContact, + int removeContact); + +int +handle_update_chat_group (struct GNUNET_CHAT_Handle *handle, + struct GNUNET_CHAT_Group *chatGroup, + int removeGroup); + +int +handle_update_chat_context (struct GNUNET_CHAT_Handle *handle, + struct GNUNET_CHAT_Context *context, + int removeContext); + +int +handle_update_chat_file (struct GNUNET_CHAT_Handle *handle, + struct GNUNET_CHAT_File *file, + int removeFile); + +struct GNUNET_CHAT_Contact* +handle_get_chat_contact (struct GNUNET_CHAT_Handle *handle, + const struct GNUNET_MESSENGER_Contact *contact); + +void +handle_set_chat_contact (struct GNUNET_CHAT_Handle *handle, + const struct GNUNET_MESSENGER_Contact *contact, + struct GNUNET_CHAT_Contact *chatContact); + +struct GNUNET_CHAT_Context* +handle_get_chat_context (struct GNUNET_CHAT_Handle *handle, + const struct GNUNET_HashCode *key); + +struct GNUNET_CHAT_File* +handle_get_chat_file (struct GNUNET_CHAT_Handle *handle, + const struct GNUNET_HashCode *hash); + #endif /* GNUNET_CHAT_HANDLE_H_ */ diff --git a/src/gnunet_chat_invitation.c b/src/gnunet_chat_invitation.c @@ -0,0 +1,37 @@ +/* + This file is part of GNUnet. + Copyright (C) 2021 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file gnunet_chat_invitation.c + */ + +#include "gnunet_chat_invitation.h" + +void +GNUNET_CHAT_invitation_accept (struct GNUNET_CHAT_Invitation *invitation) +{ + //TODO +} + +void +GNUNET_CHAT_invitation_decline (struct GNUNET_CHAT_Invitation *invitation) +{ + //TODO +} diff --git a/src/gnunet_chat_invitation.h b/src/gnunet_chat_invitation.h @@ -0,0 +1,35 @@ +/* + This file is part of GNUnet. + Copyright (C) 2021 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file gnunet_chat_invitation.h + */ + +#ifndef GNUNET_CHAT_INVITATION_H_ +#define GNUNET_CHAT_INVITATION_H_ + +#include "gnunet_chat_lib.h" + +struct GNUNET_CHAT_Invitation +{ + +}; + +#endif /* GNUNET_CHAT_INVITATION_H_ */ diff --git a/src/gnunet_chat_message.c b/src/gnunet_chat_message.c @@ -32,6 +32,8 @@ GNUNET_CHAT_message_get_kind (const struct GNUNET_CHAT_Message *message) return GNUNET_CHAT_KIND_UNKNOWN; switch (message->message->header.kind) { + case GNUNET_MESSENGER_KIND_INVITE: + return GNUNET_CHAT_KIND_INVITATION; case GNUNET_MESSENGER_KIND_TEXT: return GNUNET_CHAT_KIND_TEXT; case GNUNET_MESSENGER_KIND_FILE: @@ -64,6 +66,12 @@ GNUNET_CHAT_message_get_read_receipt (const struct GNUNET_CHAT_Message *message, return GNUNET_SYSERR; } +struct GNUNET_CHAT_Invitation* +GNUNET_CHAT_message_get_invitation (const struct GNUNET_CHAT_Message *message) +{ + return NULL; //TODO +} + const char* GNUNET_CHAT_message_get_text (const struct GNUNET_CHAT_Message *message) { diff --git a/src/gnunet_chat_message.h b/src/gnunet_chat_message.h @@ -32,7 +32,7 @@ struct GNUNET_CHAT_Message { struct GNUNET_HashCode hash; - struct GNUNET_MESSENGER_Message *message; + const struct GNUNET_MESSENGER_Message *message; }; #endif /* GNUNET_CHAT_MESSAGE_H_ */