From b880617514f9e64e991cb8d6fcff74ce3f292e36 Mon Sep 17 00:00:00 2001 From: TheJackiMonster Date: Sun, 11 Jul 2021 02:33:00 +0200 Subject: Code reorganized and refactored, most features implemented Signed-off-by: TheJackiMonster --- Makefile | 13 +- include/gnunet_chat_lib.h | 29 +- src/gnunet_chat_contact.c | 155 +-------- src/gnunet_chat_contact.h | 22 +- src/gnunet_chat_context.c | 160 +--------- src/gnunet_chat_context.h | 28 +- src/gnunet_chat_file.c | 84 ++--- src/gnunet_chat_file.h | 21 +- src/gnunet_chat_group.c | 201 ++---------- src/gnunet_chat_group.h | 17 +- src/gnunet_chat_group_intern.c | 51 +++ src/gnunet_chat_handle.c | 653 +++---------------------------------- src/gnunet_chat_handle.h | 79 ++--- src/gnunet_chat_handle_intern.c | 308 ++++++++++++++++++ src/gnunet_chat_invitation.c | 20 +- src/gnunet_chat_invitation.h | 19 +- src/gnunet_chat_lib.c | 693 ++++++++++++++++++++++++++++++++++++++++ src/gnunet_chat_lib_intern.c | 124 +++++++ src/gnunet_chat_message.c | 68 +--- src/gnunet_chat_message.h | 16 +- src/gnunet_chat_util.c | 45 +++ src/gnunet_chat_util.h | 40 +++ 22 files changed, 1508 insertions(+), 1338 deletions(-) create mode 100644 src/gnunet_chat_group_intern.c create mode 100644 src/gnunet_chat_handle_intern.c create mode 100644 src/gnunet_chat_lib.c create mode 100644 src/gnunet_chat_lib_intern.c create mode 100644 src/gnunet_chat_util.c create mode 100644 src/gnunet_chat_util.h diff --git a/Makefile b/Makefile index 39d00d3..c92dd87 100644 --- a/Makefile +++ b/Makefile @@ -4,14 +4,17 @@ INCLUDE_DIR = include/ INSTALL_DIR = /usr/local/ LIBRARY = libgnunetchat.so -SOURCES = gnunet_chat_handle.c\ - gnunet_chat_contact.c\ +SOURCES = gnunet_chat_lib.c\ + gnunet_chat_config.c\ + gnunet_chat_contact.c\ + gnunet_chat_context.c\ gnunet_chat_file.c\ - gnunet_chat_invitation.c\ gnunet_chat_group.c\ - gnunet_chat_context.c\ + gnunet_chat_handle.c\ + gnunet_chat_invitation.c\ gnunet_chat_message.c\ - gnunet_chat_config.c + gnunet_chat_util.c + HEADERS = gnunet_chat_lib.h LIBRARIES = gnunetarm\ diff --git a/include/gnunet_chat_lib.h b/include/gnunet_chat_lib.h index f2605b9..4c15df5 100644 --- a/include/gnunet_chat_lib.h +++ b/include/gnunet_chat_lib.h @@ -29,9 +29,8 @@ #ifndef GNUNET_CHAT_LIB_H_ #define GNUNET_CHAT_LIB_H_ -#define GNUNET_UNUSED __attribute__ ((unused)) - #include +#include #include /** @@ -442,25 +441,9 @@ GNUNET_CHAT_context_share_file (struct GNUNET_CHAT_Context *context, * @param delay */ void -GNUNET_CHAT_context_delete_message (struct GNUNET_CHAT_Context *context, - const struct GNUNET_HashCode *hash, +GNUNET_CHAT_context_delete_message (const struct GNUNET_CHAT_Message *message, struct GNUNET_TIME_Relative delay); -/** - * TODO - * - * @param context - * @param hash - * @param callback - * @param cls - * @return - */ -int -GNUNET_CHAT_context_get_message (struct GNUNET_CHAT_Context *context, - const struct GNUNET_HashCode *hash, - GNUNET_CHAT_ContextMessageCallback callback, - void *cls); - /** * TODO * @@ -615,12 +598,4 @@ GNUNET_CHAT_file_stop_download (struct GNUNET_CHAT_File *file); 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_contact.c b/src/gnunet_chat_contact.c index d1d92ff..a172c8e 100644 --- a/src/gnunet_chat_contact.c +++ b/src/gnunet_chat_contact.c @@ -22,169 +22,26 @@ * @file gnunet_chat_contact.c */ -#include "gnunet_chat_lib.h" #include "gnunet_chat_contact.h" -#include "gnunet_chat_handle.h" struct GNUNET_CHAT_Contact* -contact_create (struct GNUNET_CHAT_Handle *handle, - const struct GNUNET_MESSENGER_Contact *msg_contact) +contact_create_from_member (struct GNUNET_CHAT_Handle *handle, + const struct GNUNET_MESSENGER_Contact *member) { struct GNUNET_CHAT_Contact* contact = GNUNET_new(struct GNUNET_CHAT_Contact); contact->handle = handle; - contact->context = context_create( - handle, - GNUNET_CHAT_CONTEXT_TYPE_CONTACT, - NULL - ); // TODO: check for existing context? + contact->context = NULL; - contact->contact = msg_contact; + // TODO: search for private context? create private context? - if (!contact->context) - { - contact_destroy (contact); - return NULL; - } - - const struct GNUNET_HashCode *key = context_get_key(contact->context); - - const int result = GNUNET_CONTAINER_multihashmap_put( - handle->contacts, - key, - contact, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST - ); - - if (GNUNET_OK != result) { - contact_destroy (contact); - return NULL; - } + contact->member = member; return contact; } void -contact_destroy (struct GNUNET_CHAT_Contact *contact) +contact_destroy (struct GNUNET_CHAT_Contact* contact) { - if (!contact->context) - goto skip_context; - - struct GNUNET_CHAT_Handle *handle = contact->handle; - const struct GNUNET_HashCode *key = context_get_key(contact->context); - - GNUNET_CONTAINER_multihashmap_remove( - handle->contacts, - key, - contact - ); - - context_destroy(contact->context); - -skip_context: GNUNET_free(contact); } - -struct GNUNET_CHAT_SearchContact -{ - struct GNUNET_MESSENGER_Contact *contact; - const struct GNUNET_MESSENGER_Contact *msg_contact; -}; - -static int -contact_search (void *cls, const struct GNUNET_HashCode *key, void *value) -{ - struct GNUNET_CHAT_Contact *contact = value; - struct GNUNET_CHAT_SearchContact *search = cls; - - if (contact->contact == search->msg_contact) - { - search->contact = contact; - return GNUNET_NO; - } - - return GNUNET_YES; -} - -int -contact_call (struct GNUNET_CHAT_Handle *handle, - const struct GNUNET_MESSENGER_Contact *msg_contact, - GNUNET_CHAT_ContactCallback callback, - void *cls) -{ - struct GNUNET_CHAT_SearchContact search; - search.contact = NULL; - search.msg_contact = msg_contact; - - GNUNET_CONTAINER_multihashmap_iterate( - handle->contacts, - contact_search, - &search - ); - - if (search.contact) - return callback(cls, handle, search.contact); - - search.contact = contact_create(handle, msg_contact); - int result = callback(cls, handle, search.contact); - - // TODO: check if contact has private chat - - contact_destroy(search.contact); - return result; -} - -int -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); - - contact_destroy(contact); - return GNUNET_OK; -} - -void -GNUNET_CHAT_contact_set_name (struct GNUNET_CHAT_Contact *contact, - const char *name) -{ - if (!contact) - return; - - if (contact->context) - context_set_nick(contact->context, name); -} - -const char* -GNUNET_CHAT_contact_get_name (const struct GNUNET_CHAT_Contact *contact) -{ - if (!contact) - return NULL; - - if (!contact->context) - goto skip_context; - - const char *nick = context_get_nick(contact->context); - - if (nick) - return nick; - -skip_context: - return GNUNET_MESSENGER_contact_get_name(contact->contact); -} - -struct GNUNET_CHAT_Context* -GNUNET_CHAT_contact_get_context (struct GNUNET_CHAT_Contact *contact) -{ - if (!contact) - return NULL; - - return contact->context; -} diff --git a/src/gnunet_chat_contact.h b/src/gnunet_chat_contact.h index e215c5f..1cf5618 100644 --- a/src/gnunet_chat_contact.h +++ b/src/gnunet_chat_contact.h @@ -25,27 +25,27 @@ #ifndef GNUNET_CHAT_CONTACT_H_ #define GNUNET_CHAT_CONTACT_H_ -#include "gnunet_chat_context.h" +#include +#include +#include +#include + +struct GNUNET_CHAT_Handle; +struct GNUNET_CHAT_Context; struct GNUNET_CHAT_Contact { struct GNUNET_CHAT_Handle *handle; struct GNUNET_CHAT_Context *context; - const struct GNUNET_MESSENGER_Contact *contact; + const struct GNUNET_MESSENGER_Contact *member; }; struct GNUNET_CHAT_Contact* -contact_create (struct GNUNET_CHAT_Handle *handle, - const struct GNUNET_MESSENGER_Contact *msg_contact); +contact_create_from_member (struct GNUNET_CHAT_Handle *handle, + const struct GNUNET_MESSENGER_Contact *member); void -contact_destroy (struct GNUNET_CHAT_Contact *contact); - -int -contact_call (struct GNUNET_CHAT_Handle *handle, - const struct GNUNET_MESSENGER_Contact *msg_contact, - GNUNET_CHAT_ContactCallback callback, - void *cls); +contact_destroy (struct GNUNET_CHAT_Contact* contact); #endif /* GNUNET_CHAT_CONTACT_H_ */ diff --git a/src/gnunet_chat_context.c b/src/gnunet_chat_context.c index 27e8f35..54c63f7 100644 --- a/src/gnunet_chat_context.c +++ b/src/gnunet_chat_context.c @@ -22,171 +22,37 @@ * @file gnunet_chat_context.c */ -#include "gnunet_chat_lib.h" #include "gnunet_chat_context.h" -#include "gnunet_chat_handle.h" struct GNUNET_CHAT_Context* -context_create (struct GNUNET_CHAT_Handle *handle, - enum GNUNET_CHAT_ContextType type, - const struct GNUNET_HashCode *key) +context_create_from_room (struct GNUNET_CHAT_Handle *handle, + struct GNUNET_MESSENGER_Room *room) { - struct GNUNET_MESSENGER_Handle *messenger = handle->handles.messenger; - - struct GNUNET_HashCode _room_key; - const struct GNUNET_HashCode *room_key; - - if (key) - room_key = key; - else - { - GNUNET_CRYPTO_random_block( - GNUNET_CRYPTO_QUALITY_WEAK, - &_room_key, - sizeof(_room_key) - ); - - room_key = &_room_key; - } - - struct GNUNET_MESSENGER_Room *room = GNUNET_MESSENGER_open_room( - messenger, room_key - ); - - if (!room) - return NULL; - struct GNUNET_CHAT_Context* context = GNUNET_new(struct GNUNET_CHAT_Context); context->handle = handle; - context->room = room; - context->type = type; - GNUNET_memcpy(&(context->key), room_key, sizeof(_room_key)); + context->type = GNUNET_CHAT_CONTEXT_TYPE_UNKNOWN; context->nick = NULL; + context->messages = GNUNET_CONTAINER_multihashmap_create(8, GNUNET_NO); + context->invites = GNUNET_CONTAINER_multihashmap_create(8, GNUNET_NO); + context->files = GNUNET_CONTAINER_multihashmap_create(8, GNUNET_NO); + + context->room = room; + return context; } void context_destroy (struct GNUNET_CHAT_Context* context) { - GNUNET_free(context); -} - -enum GNUNET_CHAT_ContextType -context_get_type (struct GNUNET_CHAT_Context* context) -{ - return context->type; -} + GNUNET_CONTAINER_multihashmap_destroy(context->messages); + GNUNET_CONTAINER_multihashmap_destroy(context->invites); + GNUNET_CONTAINER_multihashmap_destroy(context->files); -const struct GNUNET_HashCode* -context_get_key (struct GNUNET_CHAT_Context* context) -{ - return &(context->key); -} - -const char* -context_get_nick (struct GNUNET_CHAT_Context* context) -{ - return context->nick; -} - -void -context_set_nick (struct GNUNET_CHAT_Context* context, - const char *nick) -{ if (context->nick) GNUNET_free(context->nick); - context->nick = nick? GNUNET_strdup(nick) : NULL; -} - -void -GNUNET_CHAT_context_send_text (struct GNUNET_CHAT_Context *context, - const char *text) -{ - if (!context) - return; - - struct GNUNET_MESSENGER_Message message; - message.header.kind = GNUNET_MESSENGER_KIND_TEXT; - message.body.text.text = text; - - GNUNET_MESSENGER_send_message(context->room, &message, NULL); -} - -void -GNUNET_CHAT_context_send_file (struct GNUNET_CHAT_Context *context, - const char *path) -{ - //TODO: generate key, hash file, encrypt file, upload file, share uri & info -} - -void -GNUNET_CHAT_context_send_uri (struct GNUNET_CHAT_Context *context, - const char *uri) -{ - if (!context) - return; - - struct GNUNET_MESSENGER_Message message; - message.header.kind = GNUNET_MESSENGER_KIND_FILE; - - memset(&(message.body.file.key), 0, sizeof(message.body.file.key)); - - message.body.file.hash; // TODO: download & hash - GNUNET_memcpy(message.body.file.name, "", 1); // TODO: cut from uri or get from download? - message.body.file.uri = uri; - - GNUNET_MESSENGER_send_message(context->room, &message, NULL); -} - -void -GNUNET_CHAT_context_share_file (struct GNUNET_CHAT_Context *context, - const struct GNUNET_CHAT_File *file) -{ - //TODO: send copied message basically -} - -void -GNUNET_CHAT_context_delete_message (struct GNUNET_CHAT_Context *context, - const struct GNUNET_HashCode *hash, - struct GNUNET_TIME_Relative delay) -{ - if (!context) - return; - - struct GNUNET_MESSENGER_Message message; - message.header.kind = GNUNET_MESSENGER_KIND_TEXT; - GNUNET_memcpy(&(message.body.delete.hash), hash, sizeof(*hash)); - message.body.delete.delay = GNUNET_TIME_relative_hton(delay); - - GNUNET_MESSENGER_send_message(context->room, &message, NULL); -} - -int -GNUNET_CHAT_context_get_message (struct GNUNET_CHAT_Context *context, - const struct GNUNET_HashCode *hash, - GNUNET_CHAT_ContextMessageCallback callback, - void *cls) -{ - if (!context) - return GNUNET_SYSERR; - - struct GNUNET_MESSENGER_Message *message = GNUNET_MESSENGER_get_message( - context->room, hash - ); - - //TODO: convert messenger-message to chat-message - - return GNUNET_OK; -} - -int -GNUNET_CHAT_context_iterate_messages (struct GNUNET_CHAT_Context *context, - GNUNET_CHAT_ContextMessageCallback callback, - void *cls) -{ - return GNUNET_SYSERR; + GNUNET_free(context); } diff --git a/src/gnunet_chat_context.h b/src/gnunet_chat_context.h index 87f7dfd..e975312 100644 --- a/src/gnunet_chat_context.h +++ b/src/gnunet_chat_context.h @@ -26,6 +26,8 @@ #define GNUNET_CHAT_CONTEXT_H_ #include +#include +#include #include #include @@ -41,32 +43,22 @@ struct GNUNET_CHAT_Handle; struct GNUNET_CHAT_Context { struct GNUNET_CHAT_Handle *handle; - struct GNUNET_MESSENGER_Room *room; enum GNUNET_CHAT_ContextType type; - struct GNUNET_HashCode key; char *nick; + + struct GNUNET_CONTAINER_MultiHashMap *messages; + struct GNUNET_CONTAINER_MultiHashMap *invites; + struct GNUNET_CONTAINER_MultiHashMap *files; + + struct GNUNET_MESSENGER_Room *room; }; struct GNUNET_CHAT_Context* -context_create (struct GNUNET_CHAT_Handle *handle, - enum GNUNET_CHAT_ContextType type, - const struct GNUNET_HashCode *key); +context_create_from_room (struct GNUNET_CHAT_Handle *handle, + struct GNUNET_MESSENGER_Room *room); void context_destroy (struct GNUNET_CHAT_Context* context); -enum GNUNET_CHAT_ContextType -context_get_type (struct GNUNET_CHAT_Context* context); - -const struct GNUNET_HashCode* -context_get_key (struct GNUNET_CHAT_Context* context); - -const char* -context_get_nick (struct GNUNET_CHAT_Context* context); - -void -context_set_nick (struct GNUNET_CHAT_Context* context, - const char *nick); - #endif /* GNUNET_CHAT_CONTEXT_H_ */ diff --git a/src/gnunet_chat_file.c b/src/gnunet_chat_file.c index b5f480c..d472551 100644 --- a/src/gnunet_chat_file.c +++ b/src/gnunet_chat_file.c @@ -22,81 +22,39 @@ * @file gnunet_chat_file.c */ -#include "gnunet_chat_lib.h" #include "gnunet_chat_file.h" -const struct GNUNET_HashCode* -GNUNET_CHAT_file_get_hash (const struct GNUNET_CHAT_File *file) -{ - return &(file->hash); -} +#include -uint64_t -GNUNET_CHAT_file_get_size (const struct GNUNET_CHAT_File *file) +struct GNUNET_CHAT_File* +file_create_from_message (struct GNUNET_CHAT_Handle *handle, + const struct GNUNET_MESSENGER_MessageFile* message) { - return 0; -} + struct GNUNET_CHAT_File* file = GNUNET_new(struct GNUNET_CHAT_File); -int -GNUNET_CHAT_file_is_local (const struct GNUNET_CHAT_File *file) -{ - return GNUNET_NO; -} + file->handle = handle; -int -GNUNET_CHAT_file_start_download (struct GNUNET_CHAT_File *file, - GNUNET_CHAT_MessageFileDownloadCallback callback, - void *cls) -{ - if (!file) - return GNUNET_SYSERR; + file->name = GNUNET_strndup(message->name, NAME_MAX); - struct GNUNET_FS_Handle *handle; - const char *path = ""; // TODO: path = download_directory + filename + GNUNET_memcpy(&(file->key), &(message->key), sizeof(file->key)); + GNUNET_memcpy(&(file->hash), &(message->hash), sizeof(file->hash)); - GNUNET_FS_download_start( - handle, - file->uri, - NULL, - path, - NULL, - 0, - 0, - 0, - GNUNET_FS_DOWNLOAD_OPTION_NONE, - NULL, - NULL - ); + file->uri = GNUNET_FS_uri_parse(message->uri, NULL); + file->download = NULL; + file->publish = NULL; + file->unindex = NULL; - return GNUNET_OK; + return file; } -int -GNUNET_CHAT_file_pause_download (struct GNUNET_CHAT_File *file) +void +file_destroy (struct GNUNET_CHAT_File* file) { - if (!file) - return GNUNET_SYSERR; + if (file->uri) + GNUNET_FS_uri_destroy(file->uri); - GNUNET_FS_download_suspend(file->context); - return GNUNET_OK; -} - -int -GNUNET_CHAT_file_resume_download (struct GNUNET_CHAT_File *file) -{ - if (!file) - return GNUNET_SYSERR; - - GNUNET_FS_download_resume(file->context); - return GNUNET_OK; -} - -int -GNUNET_CHAT_file_stop_download (struct GNUNET_CHAT_File *file) -{ - if (!file) - return GNUNET_SYSERR; + if (file->name) + GNUNET_free(file->name); - GNUNET_FS_download_stop(file->context, GNUNET_YES); - return GNUNET_OK; + GNUNET_free(file); } diff --git a/src/gnunet_chat_file.h b/src/gnunet_chat_file.h index ae45def..9669bf2 100644 --- a/src/gnunet_chat_file.h +++ b/src/gnunet_chat_file.h @@ -26,15 +26,34 @@ #define GNUNET_CHAT_FILE_H_ #include +#include +#include #include #include #include +struct GNUNET_CHAT_Handle; + struct GNUNET_CHAT_File { + struct GNUNET_CHAT_Handle *handle; + + char *name; + struct GNUNET_HashCode hash; + struct GNUNET_CRYPTO_SymmetricSessionKey key; + struct GNUNET_FS_Uri* uri; - struct GNUNET_FS_DownloadContext* context; + struct GNUNET_FS_DownloadContext* download; + struct GNUNET_FS_PublishContext* publish; + struct GNUNET_FS_UnindexContext* unindex; }; +struct GNUNET_CHAT_File* +file_create_from_message (struct GNUNET_CHAT_Handle *handle, + const struct GNUNET_MESSENGER_MessageFile* message); + +void +file_destroy (struct GNUNET_CHAT_File* file); + #endif /* GNUNET_CHAT_FILE_H_ */ diff --git a/src/gnunet_chat_group.c b/src/gnunet_chat_group.c index e027b19..0c998ec 100644 --- a/src/gnunet_chat_group.c +++ b/src/gnunet_chat_group.c @@ -22,208 +22,53 @@ * @file gnunet_chat_group.c */ -#include "gnunet_chat_lib.h" #include "gnunet_chat_group.h" -#include "gnunet_chat_handle.h" -#include "gnunet_chat_contact.h" + +#include "gnunet_chat_group_intern.c" struct GNUNET_CHAT_Group* -group_create(struct GNUNET_CHAT_Handle *handle, - const char *topic) +group_create_from_context (struct GNUNET_CHAT_Handle *handle, + struct GNUNET_CHAT_Context *context) { - struct GNUNET_HashCode topic_key; - - if (topic) { - GNUNET_CRYPTO_hash(topic, strlen(topic), &topic_key); - } - - struct GNUNET_CHAT_Group *group = GNUNET_new(struct GNUNET_CHAT_Group); + struct GNUNET_CHAT_Group* group = GNUNET_new(struct GNUNET_CHAT_Group); group->handle = handle; - group->context = context_create( - handle, - GNUNET_CHAT_CONTEXT_TYPE_GROUP, - topic? &topic_key : NULL - ); + group->context = context; + + group->topic = NULL; - group->is_public = topic? GNUNET_YES : GNUNET_NO; group->announcement = NULL; group->search = NULL; - if (!group->context) - { - group_destroy (group); - return NULL; - } - - const struct GNUNET_HashCode *key = context_get_key(group->context); - - const int result = GNUNET_CONTAINER_multihashmap_put( - handle->groups, - key, - group, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST - ); - - if (GNUNET_OK != result) { - group_destroy(group); - return NULL; - } - return group; } void -group_destroy(struct GNUNET_CHAT_Group* group) +group_destroy (struct GNUNET_CHAT_Group* group) { - if (!group->context) - goto skip_context; + if (group->search) + GNUNET_REGEX_search_cancel(group->search); - struct GNUNET_CHAT_Handle *handle = group->handle; - const struct GNUNET_HashCode *key = context_get_key(group->context); + if (group->announcement) + GNUNET_REGEX_announce_cancel(group->announcement); - GNUNET_CONTAINER_multihashmap_remove( - handle->groups, - key, - group - ); + if (group->topic) + GNUNET_free(group->topic); - context_destroy(group->context); - -skip_context: GNUNET_free(group); } -int -GNUNET_CHAT_group_leave (struct GNUNET_CHAT_Group *group) -{ - if (!group) - 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 -GNUNET_CHAT_group_set_name (struct GNUNET_CHAT_Group *group, - const char *name) -{ - if (!group) - return; - - if (group->context) - context_set_nick(group->context, name); -} - -const char* -GNUNET_CHAT_group_get_name (const struct GNUNET_CHAT_Group *group) -{ - if (!group) - return NULL; - - if (!group->context) - return NULL; - - return context_get_nick(group->context); -} - void -GNUNET_CHAT_group_invite_contact (struct GNUNET_CHAT_Group *group, - struct GNUNET_CHAT_Contact *contact) +group_publish (struct GNUNET_CHAT_Group* group) { - if ((!group) || (!contact)) - return; - - struct GNUNET_CHAT_Context *context = GNUNET_CHAT_contact_get_context(contact); - - if (!context) - return; - - struct GNUNET_MESSENGER_Handle *messenger = group->handle->handles.messenger; - GNUNET_MESSENGER_open_room(messenger, context_get_key(group->context)); - - struct GNUNET_MESSENGER_Message message; - message.header.kind = GNUNET_MESSENGER_KIND_INVITE; - - int result = GNUNET_CRYPTO_get_peer_identity( - group->handle->cfg, - &(message.body.invite.door) - ); - - if (GNUNET_OK != result) - return; - - GNUNET_memcpy( - &(message.body.invite.key), - context_get_key(group->context), - sizeof(message.body.invite.key) - ); - - GNUNET_MESSENGER_send_message(context->room, &message, NULL); -} - -struct GNUNET_CHAT_GroupIterateContacts -{ - struct GNUNET_CHAT_Group *group; - GNUNET_CHAT_GroupContactCallback callback; - void *cls; -}; - -static int -group_call_member (void* cls, struct GNUNET_CHAT_Handle *handle, - struct GNUNET_CHAT_Contact *contact) -{ - struct GNUNET_CHAT_GroupIterateContacts *iterate = cls; - - return iterate->callback(iterate->cls, iterate->group, contact); -} - -static int -group_iterate_members (void* cls, struct GNUNET_MESSENGER_Room *room, - const struct GNUNET_MESSENGER_Contact *contact) -{ - struct GNUNET_CHAT_GroupIterateContacts *iterate = cls; - - return contact_call( - iterate->group->handle, - contact, - group_call_member, - iterate + group->announcement = GNUNET_REGEX_announce( + group->handle->cfg, group->topic, // TODO: raw topic? + GNUNET_TIME_relative_get_minute_(), // TODO: configure delay? + 1 // TODO: no compression? ); -} - -int -GNUNET_CHAT_group_iterate_contacts (struct GNUNET_CHAT_Group *group, - GNUNET_CHAT_GroupContactCallback callback, - void *cls) -{ - if (!group) - return GNUNET_SYSERR; - - if (!callback) - return GNUNET_MESSENGER_iterate_members(group->context->room, NULL, cls); - struct GNUNET_CHAT_GroupIterateContacts iterate; - iterate.group = group; - iterate.callback = callback; - iterate.cls = cls; - - return GNUNET_MESSENGER_iterate_members( - group->context->room, group_iterate_members, &iterate + group->search = GNUNET_REGEX_search( + group->handle->cfg, group->topic, // TODO: raw topic? + search_group_by_topic, group ); } - -struct GNUNET_CHAT_Context* -GNUNET_CHAT_group_get_context (struct GNUNET_CHAT_Group *group) -{ - if (!group) - return NULL; - - return group->context; -} diff --git a/src/gnunet_chat_group.h b/src/gnunet_chat_group.h index c0127bc..0130481 100644 --- a/src/gnunet_chat_group.h +++ b/src/gnunet_chat_group.h @@ -25,26 +25,33 @@ #ifndef GNUNET_CHAT_GROUP_H_ #define GNUNET_CHAT_GROUP_H_ +#include +#include #include +#include -#include "gnunet_chat_context.h" +struct GNUNET_CHAT_Handle; +struct GNUNET_CHAT_Context; struct GNUNET_CHAT_Group { struct GNUNET_CHAT_Handle *handle; struct GNUNET_CHAT_Context *context; - int is_public; + char *topic; struct GNUNET_REGEX_Announcement *announcement; struct GNUNET_REGEX_Search *search; }; struct GNUNET_CHAT_Group* -group_create(struct GNUNET_CHAT_Handle *handle, - const char *topic); +group_create_from_context (struct GNUNET_CHAT_Handle *handle, + struct GNUNET_CHAT_Context *context); void -group_destroy(struct GNUNET_CHAT_Group* group); +group_destroy (struct GNUNET_CHAT_Group* group); + +void +group_publish (struct GNUNET_CHAT_Group* group); #endif /* GNUNET_CHAT_GROUP_H_ */ diff --git a/src/gnunet_chat_group_intern.c b/src/gnunet_chat_group_intern.c new file mode 100644 index 0000000..b70b901 --- /dev/null +++ b/src/gnunet_chat_group_intern.c @@ -0,0 +1,51 @@ +/* + 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 . + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file gnunet_chat_group_intern.c + */ + +#include "gnunet_chat_context.h" +#include "gnunet_chat_handle.h" + +#define GNUNET_UNUSED __attribute__ ((unused)) + +void +search_group_by_topic(void *cls, + const struct GNUNET_PeerIdentity *door, + GNUNET_UNUSED const struct GNUNET_PeerIdentity *get_path, + GNUNET_UNUSED unsigned int get_path_length, + GNUNET_UNUSED const struct GNUNET_PeerIdentity *put_path, + GNUNET_UNUSED unsigned int put_path_length) +{ + struct GNUNET_CHAT_Group *group = cls; + + struct GNUNET_PeerIdentity peer; + GNUNET_CRYPTO_get_peer_identity(group->handle->cfg, &peer); + + if (0 == GNUNET_memcmp(&peer, door)) + return; + + const struct GNUNET_HashCode *key = GNUNET_MESSENGER_room_get_key( + group->context->room + ); + + GNUNET_MESSENGER_enter_room(group->handle->messenger, door, key); +} diff --git a/src/gnunet_chat_handle.c b/src/gnunet_chat_handle.c index 84539c5..11b57ac 100644 --- a/src/gnunet_chat_handle.c +++ b/src/gnunet_chat_handle.c @@ -22,642 +22,73 @@ * @file gnunet_chat_handle.c */ -#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_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(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(chat->handles.arm, "arm", - GNUNET_OS_INHERIT_STD_NONE, NULL, NULL); - } -} +#include "gnunet_chat_handle_intern.c" 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_ContextMessageCallback msg_cb, - void *msg_cls) +handle_create_from_config (const struct GNUNET_CONFIGURATION_Handle* cfg, + const char* name, + GNUNET_CHAT_ContextMessageCallback msg_cb, + void *msg_cls, + GNUNET_CHAT_WarningCallback warn_cb, + void *warn_cls) { - if (!cfg) - return NULL; + struct GNUNET_CHAT_Handle* handle = GNUNET_new(struct GNUNET_CHAT_Handle); - struct GNUNET_CHAT_Handle *chat = GNUNET_new(struct GNUNET_CHAT_Handle); - memset(chat, 0, sizeof(*chat)); - chat->cfg = cfg; + handle->cfg = cfg; - chat->warn_cb = warn_cb; - chat->warn_cls = warn_cls; + handle->msg_cb = msg_cb; + handle->msg_cls = msg_cls; - chat->handles.arm = GNUNET_ARM_connect(cfg, &handle_arm_connection, chat); + handle->warn_cb = warn_cb; + handle->warn_cls = warn_cls; - if (chat->handles.arm) - handle_arm_connection(chat, GNUNET_NO); + handle->files = GNUNET_CONTAINER_multihashmap_create(8, GNUNET_NO); + handle->contexts = GNUNET_CONTAINER_multihashmap_create(8, GNUNET_NO); + handle->contacts = GNUNET_CONTAINER_multishortmap_create(8, GNUNET_NO); + handle->groups = GNUNET_CONTAINER_multihashmap_create(8, GNUNET_NO); - chat->handles.messenger = GNUNET_MESSENGER_connect( - cfg, name, - handle_on_identity, chat, - handle_on_message, chat + handle->arm = GNUNET_ARM_connect( + handle->cfg, + on_handle_arm_connection, handle ); - if (!chat->handles.messenger) - { - GNUNET_CHAT_stop(chat); - return NULL; - } + if (handle->arm) + on_handle_arm_connection(handle, GNUNET_NO); - chat->handles.fs = GNUNET_FS_start( - cfg, - name, - handle_fs_progress, - chat, + handle->fs = GNUNET_FS_start( + handle->cfg, name, // TODO: raw name? + notify_handle_fs_progress, handle, GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END ); - 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; -} + handle->messenger = GNUNET_MESSENGER_connect( + handle->cfg, name, + on_handle_identity, handle, + on_handle_message, 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; + return handle; } void -GNUNET_CHAT_stop (struct GNUNET_CHAT_Handle *handle) +handle_destroy (struct GNUNET_CHAT_Handle* handle) { - if (!handle) - return; - - if (handle->handles.fs) - { - // TODO: stop each action - - GNUNET_FS_stop(handle->handles.fs); - handle->handles.fs = NULL; - } - - if (handle->handles.messenger) - { - // TODO: stop everything related - - GNUNET_MESSENGER_disconnect(handle->handles.messenger); - handle->handles.messenger = NULL; - } + if (handle->messenger) + GNUNET_MESSENGER_disconnect(handle->messenger); - if (handle->groups) - { - GNUNET_CONTAINER_multihashmap_iterate( - handle->groups, handle_iterate_destroy_groups, NULL - ); + if (handle->files) + GNUNET_FS_stop(handle->fs); - GNUNET_CONTAINER_multihashmap_destroy(handle->groups); - handle->groups = NULL; - } + if (handle->arm) + GNUNET_ARM_disconnect(handle->arm); - if (handle->contacts.hash_map) - { - GNUNET_CONTAINER_multihashmap_iterate( - handle->contacts.hash_map, handle_iterate_destroy_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) - { - //TODO: stop started services? - - GNUNET_ARM_disconnect(handle->handles.arm); - handle->handles.arm = NULL; - } + GNUNET_CONTAINER_multihashmap_destroy(handle->groups); + GNUNET_CONTAINER_multishortmap_destroy(handle->contacts); + GNUNET_CONTAINER_multihashmap_destroy(handle->contexts); + GNUNET_CONTAINER_multihashmap_destroy(handle->files); GNUNET_free(handle); } - -int -GNUNET_CHAT_update (struct GNUNET_CHAT_Handle *handle) -{ - if (!handle) - return GNUNET_SYSERR; - - return GNUNET_MESSENGER_update(handle->handles.messenger); -} - -int -GNUNET_CHAT_set_name (struct GNUNET_CHAT_Handle *handle, - const char *name) -{ - if (!handle) - return GNUNET_SYSERR; - - return GNUNET_MESSENGER_set_name(handle->handles.messenger, name); -} - -const char* -GNUNET_CHAT_get_name (const struct GNUNET_CHAT_Handle *handle) -{ - if (!handle) - return NULL; - - return GNUNET_MESSENGER_get_name(handle->handles.messenger); -} - -const struct GNUNET_IDENTITY_PublicKey* -GNUNET_CHAT_get_key (const struct GNUNET_CHAT_Handle *handle) -{ - if (!handle) - return NULL; - - return GNUNET_MESSENGER_get_key(handle->handles.messenger); -} - -struct GNUNET_CHAT_IterateContacts -{ - struct GNUNET_CHAT_Handle *handle; - GNUNET_CHAT_ContactCallback callback; - void *cls; -}; - -static int -handle_iterate_contacts(void *cls, - GNUNET_UNUSED const struct GNUNET_HashCode *key, - void *value) -{ - struct GNUNET_CHAT_IterateContacts *iterate = cls; - struct GNUNET_CHAT_Contact *contact = value; - - if (!iterate->callback) - return GNUNET_YES; - - return iterate->callback(iterate->cls, iterate->handle, contact); -} - -int -GNUNET_CHAT_iterate_contacts (struct GNUNET_CHAT_Handle *handle, - GNUNET_CHAT_ContactCallback callback, - void *cls) -{ - if (!handle) - return GNUNET_SYSERR; - - struct GNUNET_CHAT_IterateContacts iterate; - iterate.handle = handle; - iterate.callback = callback; - iterate.cls = cls; - - return GNUNET_CONTAINER_multihashmap_iterate(handle->contacts.hash_map, - handle_iterate_contacts, - &iterate); -} - -struct GNUNET_CHAT_Group* -GNUNET_CHAT_group_create (struct GNUNET_CHAT_Handle *handle, - const char *topic) -{ - if (!handle) - return NULL; - - 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 -{ - struct GNUNET_CHAT_Handle *handle; - GNUNET_CHAT_GroupCallback callback; - void *cls; -}; - -static int -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; - - if (!iterate->callback) - return GNUNET_YES; - - return iterate->callback(iterate->cls, iterate->handle, group); -} - -int -GNUNET_CHAT_iterate_groups (struct GNUNET_CHAT_Handle *handle, - GNUNET_CHAT_GroupCallback callback, - void *cls) -{ - if (!handle) - return GNUNET_SYSERR; - - struct GNUNET_CHAT_IterateGroups iterate; - iterate.handle = handle; - iterate.callback = callback; - iterate.cls = cls; - - return GNUNET_CONTAINER_multihashmap_iterate(handle->groups, - 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 index b287336..a0f44e0 100644 --- a/src/gnunet_chat_handle.h +++ b/src/gnunet_chat_handle.h @@ -26,86 +26,45 @@ #define GNUNET_CHAT_HANDLE_H_ #include +#include #include #include #include #include #include -#include #include +#include "gnunet_chat_lib.h" + struct GNUNET_CHAT_Handle { const struct GNUNET_CONFIGURATION_Handle* cfg; - struct { - /* - * feature: (automatically start required services) - */ - struct GNUNET_ARM_Handle *arm; - - /* - * required: (files can be uploaded/downloaded) - */ - struct GNUNET_FS_Handle *fs; - - /* - * required! - */ - struct GNUNET_MESSENGER_Handle *messenger; - } handles; - - 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); + struct GNUNET_CONTAINER_MultiHashMap *files; + struct GNUNET_CONTAINER_MultiHashMap *contexts; + struct GNUNET_CONTAINER_MultiShortmap *contacts; + struct GNUNET_CONTAINER_MultiHashMap *groups; -int -handle_update_chat_file (struct GNUNET_CHAT_Handle *handle, - struct GNUNET_CHAT_File *file, - int removeFile); + struct GNUNET_ARM_Handle *arm; + struct GNUNET_FS_Handle *fs; + struct GNUNET_MESSENGER_Handle *messenger; +}; -struct GNUNET_CHAT_Contact* -handle_get_chat_contact (struct GNUNET_CHAT_Handle *handle, - const struct GNUNET_MESSENGER_Contact *contact); +struct GNUNET_CHAT_Handle* +handle_create_from_config (const struct GNUNET_CONFIGURATION_Handle* cfg, + const char* name, + GNUNET_CHAT_ContextMessageCallback msg_cb, + void *msg_cls, + GNUNET_CHAT_WarningCallback warn_cb, + void *warn_cls); 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); +handle_destroy (struct GNUNET_CHAT_Handle* handle); #endif /* GNUNET_CHAT_HANDLE_H_ */ diff --git a/src/gnunet_chat_handle_intern.c b/src/gnunet_chat_handle_intern.c new file mode 100644 index 0000000..282492c --- /dev/null +++ b/src/gnunet_chat_handle_intern.c @@ -0,0 +1,308 @@ +/* + 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 . + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file gnunet_chat_handle_intern.c + */ + +#include "gnunet_chat_contact.h" +#include "gnunet_chat_context.h" +#include "gnunet_chat_group.h" +#include "gnunet_chat_handle.h" +#include "gnunet_chat_message.h" +#include "gnunet_chat_util.h" + +#define GNUNET_UNUSED __attribute__ ((unused)) + +void +on_handle_arm_connection(void *cls, int connected) +{ + struct GNUNET_CHAT_Handle *chat = cls; + + if (GNUNET_YES == connected) { + GNUNET_ARM_request_service_start( + chat->arm, "messenger", + GNUNET_OS_INHERIT_STD_NONE, + NULL, NULL + ); + + GNUNET_ARM_request_service_start( + chat->arm, "fs", + GNUNET_OS_INHERIT_STD_NONE, + NULL, NULL + ); + } else { + GNUNET_ARM_request_service_start( + chat->arm, "arm", + GNUNET_OS_INHERIT_STD_NONE, + NULL, NULL + ); + } +} + +void* +notify_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;*/ + break; + } 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;*/ + break; + } 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;*/ + break; + } 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;*/ + break; + } 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;*/ + break; + } 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;*/ + break; + } 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; +} + +struct GNUNET_CHAT_CheckHandleRoomMembers +{ + const struct GNUNET_IDENTITY_PublicKey *ignore_key; + const struct GNUNET_MESSENGER_Contact *contact; +}; + +int +check_handle_room_members (void* cls, + GNUNET_UNUSED struct GNUNET_MESSENGER_Room *room, + const struct GNUNET_MESSENGER_Contact *contact) +{ + struct GNUNET_CHAT_CheckHandleRoomMembers *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; +} + +struct GNUNET_CHAT_Context* +request_handle_context_by_room (struct GNUNET_CHAT_Handle *handle, + struct GNUNET_MESSENGER_Room *room) +{ + const struct GNUNET_HashCode *key = GNUNET_MESSENGER_room_get_key(room); + + struct GNUNET_CHAT_Context *context = GNUNET_CONTAINER_multihashmap_get( + handle->contexts, key + ); + + if (context) + return context; + + context = context_create_from_room(handle, room); + + if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( + handle->contexts, key, context, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) + { + context_destroy(context); + return NULL; + } + + struct GNUNET_CHAT_CheckHandleRoomMembers check; + check.ignore_key = GNUNET_MESSENGER_get_key(handle->messenger); + check.contact = NULL; + + GNUNET_MESSENGER_iterate_members(room, check_handle_room_members, &check); + + if (check.contact) + { + context->type = GNUNET_CHAT_CONTEXT_TYPE_CONTACT; + + struct GNUNET_CHAT_Contact *contact = contact_create_from_member( + handle, check.contact + ); + + struct GNUNET_ShortHashCode shorthash; + util_shorthash_from_member(check.contact, &shorthash); + + if (GNUNET_OK == GNUNET_CONTAINER_multishortmap_put( + handle->contacts, &shorthash, contact, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) + return context; + + contact_destroy(contact); + } + else + { + context->type = GNUNET_CHAT_CONTEXT_TYPE_GROUP; + + struct GNUNET_CHAT_Group *group = group_create_from_context( + handle, context + ); + + if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put( + handle->groups, key, group, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) + return context; + + group_destroy(group); + } + + GNUNET_CONTAINER_multihashmap_remove(handle->contexts, key, context); + context_destroy(context); + return NULL; +} + +int +find_handle_rooms (void *cls, struct GNUNET_MESSENGER_Room *room, + GNUNET_UNUSED const struct GNUNET_MESSENGER_Contact *member) +{ + struct GNUNET_CHAT_Handle *handle = cls; + + request_handle_context_by_room( + handle, room + ); + + return GNUNET_YES; +} + +void +on_handle_identity(void *cls, + GNUNET_UNUSED struct GNUNET_MESSENGER_Handle *messenger) +{ + struct GNUNET_CHAT_Handle *handle = cls; + + GNUNET_MESSENGER_find_rooms( + handle->messenger, NULL, find_handle_rooms, handle + ); +} + +void +on_handle_message (void *cls, + struct GNUNET_MESSENGER_Room *room, + GNUNET_UNUSED const struct GNUNET_MESSENGER_Contact *sender, + const struct GNUNET_MESSENGER_Message *msg, + const struct GNUNET_HashCode *hash, + GNUNET_UNUSED enum GNUNET_MESSENGER_MessageFlags flags) +{ + struct GNUNET_CHAT_Handle *handle = cls; + + struct GNUNET_CHAT_Context *context = request_handle_context_by_room( + handle, room + ); + + if (!context) + return; + + struct GNUNET_CHAT_Message *message = GNUNET_CONTAINER_multihashmap_get( + context->messages, hash + ); + + if (message) + goto process_callback; + + message = message_create_from_msg(context, hash, msg); + + if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( + context->messages, hash, message, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) + { + message_destroy(message); + return; + } + +process_callback: + if (handle->msg_cb) + handle->msg_cb(handle->msg_cls, context, message); +} diff --git a/src/gnunet_chat_invitation.c b/src/gnunet_chat_invitation.c index 44f7787..9562daa 100644 --- a/src/gnunet_chat_invitation.c +++ b/src/gnunet_chat_invitation.c @@ -24,14 +24,24 @@ #include "gnunet_chat_invitation.h" -void -GNUNET_CHAT_invitation_accept (struct GNUNET_CHAT_Invitation *invitation) +struct GNUNET_CHAT_Invitation* +invitation_create_from_message (struct GNUNET_CHAT_Context *context, + const struct GNUNET_MESSENGER_MessageInvite *message) { - //TODO + struct GNUNET_CHAT_Invitation *invitation = GNUNET_new(struct GNUNET_CHAT_Invitation); + + invitation->context = context; + + GNUNET_memcpy(&(invitation->key), &(message->key), sizeof(invitation->key)); + invitation->door = GNUNET_PEER_intern(&(message->door)); + + return invitation; } void -GNUNET_CHAT_invitation_decline (struct GNUNET_CHAT_Invitation *invitation) +invitation_destroy (struct GNUNET_CHAT_Invitation *invitation) { - //TODO + GNUNET_PEER_decrement_rcs(&(invitation->door), 1); + + GNUNET_free(invitation); } diff --git a/src/gnunet_chat_invitation.h b/src/gnunet_chat_invitation.h index dd2b8e8..433131e 100644 --- a/src/gnunet_chat_invitation.h +++ b/src/gnunet_chat_invitation.h @@ -25,11 +25,28 @@ #ifndef GNUNET_CHAT_INVITATION_H_ #define GNUNET_CHAT_INVITATION_H_ -#include "gnunet_chat_lib.h" +#include +#include +#include +#include +#include +#include + +struct GNUNET_CHAT_Context; struct GNUNET_CHAT_Invitation { + struct GNUNET_CHAT_Context *context; + struct GNUNET_HashCode key; + GNUNET_PEER_Id door; }; +struct GNUNET_CHAT_Invitation* +invitation_create_from_message (struct GNUNET_CHAT_Context *context, + const struct GNUNET_MESSENGER_MessageInvite *message); + +void +invitation_destroy (struct GNUNET_CHAT_Invitation *invitation); + #endif /* GNUNET_CHAT_INVITATION_H_ */ diff --git a/src/gnunet_chat_lib.c b/src/gnunet_chat_lib.c new file mode 100644 index 0000000..23c541d --- /dev/null +++ b/src/gnunet_chat_lib.c @@ -0,0 +1,693 @@ +/* + 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 . + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file gnunet_chat_lib.c + */ + +#include "gnunet_chat_lib.h" + +#include + +#include "gnunet_chat_config.h" +#include "gnunet_chat_contact.h" +#include "gnunet_chat_context.h" +#include "gnunet_chat_file.h" +#include "gnunet_chat_group.h" +#include "gnunet_chat_handle.h" +#include "gnunet_chat_invitation.h" +#include "gnunet_chat_message.h" +#include "gnunet_chat_util.h" + +#include "gnunet_chat_lib_intern.c" + +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_ContextMessageCallback msg_cb, void *msg_cls) +{ + if (!cfg) + return NULL; + + if (!name) + return NULL; + + return handle_create_from_config( + cfg, name, msg_cb, msg_cls, warn_cb, warn_cls + ); +} + +void +GNUNET_CHAT_stop (struct GNUNET_CHAT_Handle *handle) +{ + if (!handle) + return; + + handle_destroy(handle); +} + +int +GNUNET_CHAT_update (struct GNUNET_CHAT_Handle *handle) +{ + if (!handle) + return GNUNET_SYSERR; + + return GNUNET_MESSENGER_update(handle->messenger); +} + +int +GNUNET_CHAT_set_name (struct GNUNET_CHAT_Handle *handle, + const char *name) +{ + if (!handle) + return GNUNET_SYSERR; + + if (!name) + return GNUNET_NO; + + return GNUNET_MESSENGER_set_name(handle->messenger, name); +} + +const char* +GNUNET_CHAT_get_name (const struct GNUNET_CHAT_Handle *handle) +{ + if (!handle) + return NULL; + + return GNUNET_MESSENGER_get_name(handle->messenger); +} + +const struct GNUNET_IDENTITY_PublicKey* +GNUNET_CHAT_get_key (const struct GNUNET_CHAT_Handle *handle) +{ + if (!handle) + return NULL; + + return GNUNET_MESSENGER_get_key(handle->messenger); +} + +int +GNUNET_CHAT_iterate_contacts (struct GNUNET_CHAT_Handle *handle, + GNUNET_CHAT_ContactCallback callback, + void *cls) +{ + if (!handle) + return GNUNET_SYSERR; + + struct GNUNET_CHAT_HandleIterateContacts it; + it.handle = handle; + it.cb = callback; + it.cls = cls; + + return GNUNET_CONTAINER_multishortmap_iterate( + handle->contacts, it_handle_iterate_contacts, &it + ); +} + +struct GNUNET_CHAT_Group * +GNUNET_CHAT_group_create (struct GNUNET_CHAT_Handle *handle, + const char* topic) +{ + if (!handle) + return NULL; + + struct GNUNET_HashCode key; + + if (topic) + GNUNET_CRYPTO_hash(topic, strlen(topic), &key); + else + GNUNET_CRYPTO_random_block(GNUNET_CRYPTO_QUALITY_WEAK, &key, sizeof(key)); + + if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains( + handle->contexts, &key)) + return NULL; + + struct GNUNET_MESSENGER_Room *room = GNUNET_MESSENGER_open_room( + handle->messenger, &key + ); + + struct GNUNET_CHAT_Context *context = context_create_from_room(handle, room); + + context->type = GNUNET_CHAT_CONTEXT_TYPE_GROUP; + + if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( + handle->contexts, &key, context, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) + goto destroy_context; + + struct GNUNET_CHAT_Group *group = group_create_from_context(handle, context); + + util_set_name_field(topic, &(group->topic)); + + if (group->topic) + group_publish(group); + + if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put( + handle->groups, &key, group, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) + return group; + + group_destroy(group); + + GNUNET_CONTAINER_multihashmap_remove(handle->contexts, &key, context); + +destroy_context: + context_destroy(context); + return NULL; +} + +int +GNUNET_CHAT_iterate_groups (struct GNUNET_CHAT_Handle *handle, + GNUNET_CHAT_GroupCallback callback, + void *cls) +{ + if (!handle) + return GNUNET_SYSERR; + + struct GNUNET_CHAT_HandleIterateGroups it; + it.handle = handle; + it.cb = callback; + it.cls = cls; + + return GNUNET_CONTAINER_multihashmap_iterate( + handle->groups, it_handle_iterate_groups, &it + ); +} + +int +GNUNET_CHAT_contact_delete (struct GNUNET_CHAT_Contact *contact) +{ + if (!contact) + return GNUNET_SYSERR; + + struct GNUNET_ShortHashCode shorthash; + util_shorthash_from_member(contact->member, &shorthash); + + GNUNET_CONTAINER_multishortmap_remove( + contact->handle->contacts, &shorthash, contact + ); + + const struct GNUNET_HashCode *key = GNUNET_MESSENGER_room_get_key( + contact->context->room + ); + + GNUNET_CONTAINER_multihashmap_remove( + contact->handle->contexts, key, contact->context + ); + + GNUNET_MESSENGER_close_room(contact->context->room); + + context_destroy(contact->context); + contact_destroy(contact); + return GNUNET_OK; +} + +void +GNUNET_CHAT_contact_set_name (struct GNUNET_CHAT_Contact *contact, + const char *name) +{ + if (!contact) + return; + + util_set_name_field(name, &(contact->context->nick)); +} + + +const char* +GNUNET_CHAT_contact_get_name (const struct GNUNET_CHAT_Contact *contact) +{ + if (!contact) + return NULL; + + if (contact->context->nick) + return contact->context->nick; + + return GNUNET_MESSENGER_contact_get_name(contact->member); +} + + +const struct GNUNET_IDENTITY_PublicKey* +GNUNET_CHAT_contact_get_key (const struct GNUNET_CHAT_Contact *contact) +{ + if (!contact) + return NULL; + + return GNUNET_MESSENGER_contact_get_key(contact->member); +} + + +struct GNUNET_CHAT_Context* +GNUNET_CHAT_contact_get_context (struct GNUNET_CHAT_Contact *contact) +{ + if (!contact) + return NULL; + + return contact->context; +} + + +int +GNUNET_CHAT_group_leave (struct GNUNET_CHAT_Group *group) +{ + if (!group) + return GNUNET_SYSERR; + + const struct GNUNET_HashCode *key = GNUNET_MESSENGER_room_get_key( + group->context->room + ); + + GNUNET_CONTAINER_multihashmap_remove( + group->handle->groups, key, group + ); + + GNUNET_CONTAINER_multihashmap_remove( + group->handle->contexts, key, group->context + ); + + GNUNET_MESSENGER_close_room(group->context->room); + + context_destroy(group->context); + group_destroy(group); + return GNUNET_OK; +} + + +void +GNUNET_CHAT_group_set_name (struct GNUNET_CHAT_Group *group, + const char *name) +{ + if (!group) + return; + + util_set_name_field(name, &(group->context->nick)); +} + + +const char* +GNUNET_CHAT_group_get_name (const struct GNUNET_CHAT_Group *group) +{ + if (!group) + return NULL; + + return group->context->nick; +} + + +void +GNUNET_CHAT_group_invite_contact (struct GNUNET_CHAT_Group *group, + struct GNUNET_CHAT_Contact *contact) +{ + if ((!group) || (!contact)) + return; + + const struct GNUNET_HashCode *key = GNUNET_MESSENGER_room_get_key( + group->context->room + ); + + GNUNET_MESSENGER_open_room(group->handle->messenger, key); + + struct GNUNET_MESSENGER_Message msg; + msg.header.kind = GNUNET_MESSENGER_KIND_INVITE; + GNUNET_CRYPTO_get_peer_identity(group->handle->cfg, &(msg.body.invite.door)); + GNUNET_memcpy(&(msg.body.invite.key), key, sizeof(msg.body.invite.key)); + + GNUNET_MESSENGER_send_message(contact->context->room, &msg, contact->member); +} + +int +GNUNET_CHAT_group_iterate_contacts (struct GNUNET_CHAT_Group *group, + GNUNET_CHAT_GroupContactCallback callback, + void *cls) +{ + if (!group) + return GNUNET_SYSERR; + + struct GNUNET_CHAT_GroupIterateContacts it; + it.group = group; + it.cb = callback; + it.cls = cls; + + return GNUNET_MESSENGER_iterate_members( + group->context->room, it_group_iterate_contacts, &it + ); +} + + +struct GNUNET_CHAT_Context* +GNUNET_CHAT_group_get_context (struct GNUNET_CHAT_Group *group) +{ + if (!group) + return NULL; + + return group->context; +} + +void +GNUNET_CHAT_context_send_text (struct GNUNET_CHAT_Context *context, + const char *text) +{ + if ((!context) || (!text)) + return; + + struct GNUNET_MESSENGER_Message msg; + msg.header.kind = GNUNET_MESSENGER_KIND_TEXT; + msg.body.text.text = GNUNET_strdup(text); + + GNUNET_MESSENGER_send_message(context->room, &msg, NULL); + + GNUNET_free(msg.body.text.text); +} + + +void +GNUNET_CHAT_context_send_file (struct GNUNET_CHAT_Context *context, + const char *path) +{ + if ((!context) || (!path)) + return; + + // TODO: encrypt file, publish file, share file +} + + +void +GNUNET_CHAT_context_send_uri (struct GNUNET_CHAT_Context *context, + const char *uri) +{ + if ((!context) || (!uri)) + return; + + struct GNUNET_FS_Uri *furi = GNUNET_FS_uri_parse(uri, NULL); + + if (!furi) + return; + + // TODO: download file, hash file, share file +} + + +void +GNUNET_CHAT_context_share_file (struct GNUNET_CHAT_Context *context, + const struct GNUNET_CHAT_File *file) +{ + if ((!context) || (!file) || (strlen(file->name) > NAME_MAX)) + return; + + struct GNUNET_MESSENGER_Message msg; + msg.header.kind = GNUNET_MESSENGER_KIND_FILE; + GNUNET_memcpy(&(msg.body.file.key), &(file->key), sizeof(file->key)); + GNUNET_memcpy(&(msg.body.file.hash), &(file->hash), sizeof(file->hash)); + GNUNET_strlcpy(msg.body.file.name, file->name, NAME_MAX); + msg.body.file.uri = GNUNET_FS_uri_to_string(file->uri); + + GNUNET_MESSENGER_send_message(context->room, &msg, NULL); + + GNUNET_free(msg.body.file.uri); +} + + +void +GNUNET_CHAT_context_delete_message (const struct GNUNET_CHAT_Message *message, + struct GNUNET_TIME_Relative delay) +{ + if (!message) + return; + + struct GNUNET_MESSENGER_Message msg; + msg.header.kind = GNUNET_MESSENGER_KIND_DELETE; + GNUNET_memcpy(&(msg.body.delete.hash), &(message->hash), sizeof(message->hash)); + msg.body.delete.delay = GNUNET_TIME_relative_hton(delay); + + GNUNET_MESSENGER_send_message(message->context->room, &msg, NULL); +} + + + +int +GNUNET_CHAT_context_iterate_messages (struct GNUNET_CHAT_Context *context, + GNUNET_CHAT_ContextMessageCallback callback, + void *cls) +{ + if (!context) + return GNUNET_SYSERR; + + struct GNUNET_CHAT_ContextIterateMessages it; + it.context = context; + it.cb = callback; + it.cls = cls; + + return GNUNET_CONTAINER_multihashmap_iterate( + context->messages, it_context_iterate_messages, &it + ); +} + + +enum GNUNET_CHAT_MessageKind +GNUNET_CHAT_message_get_kind (const struct GNUNET_CHAT_Message *message) +{ + if (!message) + return GNUNET_CHAT_KIND_UNKNOWN; + + switch (message->msg->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: + return GNUNET_CHAT_KIND_FILE; + default: + return GNUNET_CHAT_KIND_UNKNOWN; + } +} + + +struct GNUNET_TIME_Absolute +GNUNET_CHAT_message_get_timestamp (const struct GNUNET_CHAT_Message *message) +{ + if (!message) + return GNUNET_TIME_absolute_get_zero_(); + + return GNUNET_TIME_absolute_ntoh(message->msg->header.timestamp); +} + + +const struct GNUNET_CHAT_Contact* +GNUNET_CHAT_message_get_sender (const struct GNUNET_CHAT_Message *message) +{ + if (!message) + return NULL; + + const struct GNUNET_MESSENGER_Contact *sender = GNUNET_MESSENGER_get_sender( + message->context->room, &(message->hash) + ); + + if (!sender) + return NULL; + + struct GNUNET_ShortHashCode shorthash; + util_shorthash_from_member(sender, &shorthash); + + return GNUNET_CONTAINER_multishortmap_get( + message->context->handle->contacts, &shorthash + ); +} + + +int +GNUNET_CHAT_message_get_read_receipt (const struct GNUNET_CHAT_Message *message, + GNUNET_CHAT_MessageReadReceiptCallback callback, + void *cls) +{ + if (!message) + return GNUNET_SYSERR; + + // TODO: request read receipt? / check if newer message was received of sender? + + return GNUNET_SYSERR; +} + + +const char* +GNUNET_CHAT_message_get_text (const struct GNUNET_CHAT_Message *message) +{ + if (!message) + return NULL; + + if (GNUNET_MESSENGER_KIND_TEXT != message->msg->header.kind) + return NULL; + + return message->msg->body.text.text; +} + + +struct GNUNET_CHAT_File* +GNUNET_CHAT_message_get_file (const struct GNUNET_CHAT_Message *message) +{ + if (!message) + return NULL; + + if (GNUNET_MESSENGER_KIND_FILE != message->msg->header.kind) + return NULL; + + return GNUNET_CONTAINER_multihashmap_get( + message->context->handle->files, + &(message->msg->body.file.hash) + ); +} + + +struct GNUNET_CHAT_Invitation* +GNUNET_CHAT_message_get_invitation (const struct GNUNET_CHAT_Message *message) +{ + if (!message) + return NULL; + + if (GNUNET_MESSENGER_KIND_INVITE != message->msg->header.kind) + return NULL; + + return GNUNET_CONTAINER_multihashmap_get( + message->context->invites, + &(message->hash) + ); +} + + +const struct GNUNET_HashCode* +GNUNET_CHAT_file_get_hash (const struct GNUNET_CHAT_File *file) +{ + if (!file) + return NULL; + + return &(file->hash); +} + + +uint64_t +GNUNET_CHAT_file_get_size (const struct GNUNET_CHAT_File *file) +{ + if (!file) + return 0; + + if (file->uri) + return GNUNET_FS_uri_chk_get_file_size(file->uri); + + const char *path = ""; // TODO: path = download_directory + file->name + + // TODO: check size through info or check locally? + + return 0; +} + + +int +GNUNET_CHAT_file_is_local (const struct GNUNET_CHAT_File *file) +{ + if (!file) + return GNUNET_SYSERR; + + const char *path = ""; // TODO: path = download_directory + file->name + + // TODO: check locally? + + return GNUNET_SYSERR; +} + + +int +GNUNET_CHAT_file_start_download (struct GNUNET_CHAT_File *file, + GNUNET_CHAT_MessageFileDownloadCallback callback, + void *cls) +{ + if (!file) + return GNUNET_SYSERR; + + // TODO: check if downloading? + + const char *path = ""; // TODO: path = download_directory + file->name + + file->download = GNUNET_FS_download_start( + file->handle->fs, + file->uri, + NULL, + path, + NULL, + 0, + 0, + 0, + GNUNET_FS_DOWNLOAD_OPTION_NONE, + NULL, + NULL + ); + + return GNUNET_OK; +} + + +int +GNUNET_CHAT_file_pause_download (struct GNUNET_CHAT_File *file) +{ + if (!file) + return GNUNET_SYSERR; + + GNUNET_FS_download_suspend(file->download); + return GNUNET_OK; +} + + +int +GNUNET_CHAT_file_resume_download (struct GNUNET_CHAT_File *file) +{ + if (!file) + return GNUNET_SYSERR; + + GNUNET_FS_download_resume(file->download); + return GNUNET_OK; +} + + +int +GNUNET_CHAT_file_stop_download (struct GNUNET_CHAT_File *file) +{ + if (!file) + return GNUNET_SYSERR; + + GNUNET_FS_download_stop(file->download, GNUNET_YES); + file->download = NULL; + return GNUNET_OK; +} + + +void +GNUNET_CHAT_invitation_accept (struct GNUNET_CHAT_Invitation *invitation) +{ + if (!invitation) + return; + + struct GNUNET_PeerIdentity door; + GNUNET_PEER_resolve(invitation->door, &door); + + GNUNET_MESSENGER_enter_room( + invitation->context->handle->messenger, + &door, &(invitation->key) + ); +} + diff --git a/src/gnunet_chat_lib_intern.c b/src/gnunet_chat_lib_intern.c new file mode 100644 index 0000000..8ccfce5 --- /dev/null +++ b/src/gnunet_chat_lib_intern.c @@ -0,0 +1,124 @@ +/* + 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 . + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file gnunet_chat_lib_intern.c + */ + +#define GNUNET_UNUSED __attribute__ ((unused)) + +struct GNUNET_CHAT_HandleIterateContacts +{ + struct GNUNET_CHAT_Handle *handle; + GNUNET_CHAT_ContactCallback cb; + void *cls; +}; + +int +it_handle_iterate_contacts (void *cls, + GNUNET_UNUSED const struct GNUNET_ShortHashCode *key, + void *value) +{ + struct GNUNET_CHAT_HandleIterateContacts *it = cls; + + if (!(it->cb)) + return GNUNET_YES; + + struct GNUNET_CHAT_Contact *contact = value; + + return it->cb(it->cls, it->handle, contact); +} + +struct GNUNET_CHAT_HandleIterateGroups +{ + struct GNUNET_CHAT_Handle *handle; + GNUNET_CHAT_GroupCallback cb; + void *cls; +}; + +int +it_handle_iterate_groups (void *cls, + GNUNET_UNUSED const struct GNUNET_HashCode *key, + void *value) +{ + struct GNUNET_CHAT_HandleIterateGroups *it = cls; + + if (!(it->cb)) + return GNUNET_YES; + + struct GNUNET_CHAT_Group *group = value; + + return it->cb(it->cls, it->handle, group); +} + +struct GNUNET_CHAT_GroupIterateContacts +{ + struct GNUNET_CHAT_Group *group; + GNUNET_CHAT_GroupContactCallback cb; + void *cls; +}; + +int +it_group_iterate_contacts (void* cls, + GNUNET_UNUSED struct GNUNET_MESSENGER_Room *room, + const struct GNUNET_MESSENGER_Contact *member) +{ + struct GNUNET_CHAT_GroupIterateContacts *it = cls; + + if (!(it->cb)) + return GNUNET_YES; + + struct GNUNET_ShortHashCode shorthash; + util_shorthash_from_member(member, &shorthash); + + struct GNUNET_CHAT_Contact *contact = GNUNET_CONTAINER_multishortmap_get( + it->group->handle->contacts, &shorthash + ); + + return it->cb(it->cls, it->group, contact); +} + +struct GNUNET_CHAT_ContextIterateMessages +{ + struct GNUNET_CHAT_Context *context; + GNUNET_CHAT_ContextMessageCallback cb; + void *cls; +}; + +int +it_context_iterate_messages (void *cls, + GNUNET_UNUSED const struct GNUNET_HashCode *key, + void *value) +{ + struct GNUNET_CHAT_ContextIterateMessages *it = cls; + + if (!(it->cb)) + return GNUNET_YES; + + struct GNUNET_CHAT_Message *message = value; + + return it->cb(it->cls, it->context, message); +} + + + + + + diff --git a/src/gnunet_chat_message.c b/src/gnunet_chat_message.c index 805453e..bff8a52 100644 --- a/src/gnunet_chat_message.c +++ b/src/gnunet_chat_message.c @@ -22,70 +22,26 @@ * @file gnunet_chat_message.c */ -#include "gnunet_chat_lib.h" #include "gnunet_chat_message.h" -enum GNUNET_CHAT_MessageKind -GNUNET_CHAT_message_get_kind (const struct GNUNET_CHAT_Message *message) +struct GNUNET_CHAT_Message* +message_create_from_msg (struct GNUNET_CHAT_Context *context, + const struct GNUNET_HashCode *hash, + const struct GNUNET_MESSENGER_Message *msg) { - if (!message) - return GNUNET_CHAT_KIND_UNKNOWN; + struct GNUNET_CHAT_Message *message = GNUNET_new(struct GNUNET_CHAT_Message); - 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: - return GNUNET_CHAT_KIND_FILE; - default: - return GNUNET_CHAT_KIND_UNKNOWN; - } -} - -struct GNUNET_TIME_Absolute -GNUNET_CHAT_message_get_timestamp (const struct GNUNET_CHAT_Message *message) -{ - if (!message) - return GNUNET_TIME_absolute_get_zero_(); - - return GNUNET_TIME_absolute_ntoh(message->message->header.timestamp); -} - -const struct GNUNET_CHAT_Contact* -GNUNET_CHAT_message_get_sender (const struct GNUNET_CHAT_Message *message) -{ - return NULL; -} + message->context = context; -int -GNUNET_CHAT_message_get_read_receipt (const struct GNUNET_CHAT_Message *message, - GNUNET_CHAT_MessageReadReceiptCallback callback, - void *cls) -{ - 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) -{ - if (!message) - return NULL; + GNUNET_memcpy(&(message->hash), hash, sizeof(message->hash)); - if (GNUNET_MESSENGER_KIND_TEXT != message->message->header.kind) - return NULL; + message->msg = msg; - return message->message->body.text.text; + return message; } -struct GNUNET_CHAT_File* -GNUNET_CHAT_message_get_file (const struct GNUNET_CHAT_Message *message) +void +message_destroy (struct GNUNET_CHAT_Message* message) { - return NULL; + GNUNET_free(message); } diff --git a/src/gnunet_chat_message.h b/src/gnunet_chat_message.h index 6de7fae..7b3051c 100644 --- a/src/gnunet_chat_message.h +++ b/src/gnunet_chat_message.h @@ -26,13 +26,27 @@ #define GNUNET_CHAT_MESSAGE_H_ #include +#include #include #include +struct GNUNET_CHAT_Context; + struct GNUNET_CHAT_Message { + struct GNUNET_CHAT_Context *context; + struct GNUNET_HashCode hash; - const struct GNUNET_MESSENGER_Message *message; + + const struct GNUNET_MESSENGER_Message *msg; }; +struct GNUNET_CHAT_Message* +message_create_from_msg (struct GNUNET_CHAT_Context *context, + const struct GNUNET_HashCode *hash, + const struct GNUNET_MESSENGER_Message *msg); + +void +message_destroy (struct GNUNET_CHAT_Message* message); + #endif /* GNUNET_CHAT_MESSAGE_H_ */ diff --git a/src/gnunet_chat_util.c b/src/gnunet_chat_util.c new file mode 100644 index 0000000..1a75ba9 --- /dev/null +++ b/src/gnunet_chat_util.c @@ -0,0 +1,45 @@ +/* + 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 . + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file gnunet_chat_util.c + */ + +#include "gnunet_chat_util.h" + +void +util_shorthash_from_member (const struct GNUNET_MESSENGER_Contact *member, + struct GNUNET_ShortHashCode* shorthash) +{ + memset(shorthash, 0, sizeof(*shorthash)); + GNUNET_memcpy(shorthash, &member, sizeof(member)); +} + +void +util_set_name_field (const char *name, char** field) +{ + if (*field) + GNUNET_free(*field); + + if (name) + *field = GNUNET_strdup(name); + else + *field = NULL; +} diff --git a/src/gnunet_chat_util.h b/src/gnunet_chat_util.h new file mode 100644 index 0000000..d9ff947 --- /dev/null +++ b/src/gnunet_chat_util.h @@ -0,0 +1,40 @@ +/* + 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 . + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file gnunet_chat_util.h + */ + +#ifndef GNUNET_CHAT_UTIL_H_ +#define GNUNET_CHAT_UTIL_H_ + +#include +#include +#include +#include + +void +util_shorthash_from_member (const struct GNUNET_MESSENGER_Contact *member, + struct GNUNET_ShortHashCode* shorthash); + +void +util_set_name_field (const char *name, char** field); + +#endif /* GNUNET_CHAT_UTIL_H_ */ -- cgit v1.2.3