libgnunetchat

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

commit 43485ce71b4eb227d934c5726bc234195e0cbafa
parent 7d43dc0a81ff20c11ae497fece2b414fd241a00c
Author: Jacki <jacki@thejackimonster.de>
Date:   Sat, 10 Feb 2024 23:34:12 +0100

Implement blocking and unblocking via rejection tags

Signed-off-by: Jacki <jacki@thejackimonster.de>

Diffstat:
Msrc/gnunet_chat_contact.c | 183++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/gnunet_chat_contact.h | 51++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/gnunet_chat_contact_intern.c | 37++++++++++++++++++++++++++++++++++++-
Msrc/gnunet_chat_context.c | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/gnunet_chat_context.h | 12++++++++++++
Msrc/gnunet_chat_handle_intern.c | 15+++++++++++----
Msrc/gnunet_chat_lib.c | 31++++++++++++++++++++++++++-----
Msrc/gnunet_chat_lib_intern.c | 50+++++++++++++++++++++++++++++++++++++++++++-------
Msrc/gnunet_chat_message.c | 5+++++
9 files changed, 426 insertions(+), 19 deletions(-)

diff --git a/src/gnunet_chat_contact.c b/src/gnunet_chat_contact.c @@ -28,6 +28,11 @@ #include "gnunet_chat_ticket.h" #include "gnunet_chat_contact_intern.c" +#include <gnunet/gnunet_common.h> +#include <gnunet/gnunet_messenger_service.h> +#include <gnunet/gnunet_time_lib.h> + +static const unsigned int initial_map_size_of_contact = 8; struct GNUNET_CHAT_Contact* contact_create_from_member (struct GNUNET_CHAT_Handle *handle, @@ -41,18 +46,63 @@ contact_create_from_member (struct GNUNET_CHAT_Handle *handle, contact->context = NULL; contact->member = member; + contact->joined = GNUNET_CONTAINER_multihashmap_create( + initial_map_size_of_contact, GNUNET_NO); + + contact->tickets_head = NULL; + contact->tickets_tail = NULL; contact->public_key = NULL; contact->user_pointer = NULL; contact->owned = GNUNET_NO; - contact->blocked = GNUNET_NO; contact_update_key (contact); return contact; } void +contact_update_join (struct GNUNET_CHAT_Contact *contact, + struct GNUNET_CHAT_Context *context, + const struct GNUNET_HashCode *hash, + enum GNUNET_MESSENGER_MessageFlags flags) +{ + GNUNET_assert( + (contact) && + (contact->joined) && + (context) && + (context->room) && + (hash) + ); + + const struct GNUNET_HashCode *key = GNUNET_MESSENGER_room_get_key( + context->room + ); + + struct GNUNET_HashCode *current = GNUNET_CONTAINER_multihashmap_get( + contact->joined, + key + ); + + if (! current) + { + current = GNUNET_new(struct GNUNET_HashCode); + + if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( + contact->joined, key, current, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) + { + GNUNET_free(current); + return; + } + } + else if (0 == (flags & GNUNET_MESSENGER_FLAG_RECENT)) + return; + + GNUNET_memcpy(current, hash, + sizeof(struct GNUNET_HashCode)); +} + +void contact_update_key (struct GNUNET_CHAT_Contact *contact) { GNUNET_assert(contact); @@ -100,6 +150,134 @@ contact_find_context (const struct GNUNET_CHAT_Contact *contact) ); } +enum GNUNET_GenericReturnValue +contact_is_blocked (const struct GNUNET_CHAT_Contact *contact, + const struct GNUNET_CHAT_Context *context) +{ + GNUNET_assert( + (contact) && + (contact->joined) && + (context) + ); + + if (!(context->room)) + return GNUNET_NO; + + const struct GNUNET_HashCode *hash; + hash = GNUNET_CONTAINER_multihashmap_get( + contact->joined, + GNUNET_MESSENGER_room_get_key(context->room) + ); + + if (! hash) + return GNUNET_YES; + + struct GNUNET_CHAT_ContactFindJoin find; + find.hash = NULL; + + GNUNET_CONTAINER_multihashmap_get_multiple( + context->rejections, + hash, + it_contact_find_rejection, + &find + ); + + if (find.hash) + return GNUNET_YES; + else + return GNUNET_NO; +} + +void +contact_unblock (struct GNUNET_CHAT_Contact *contact, + struct GNUNET_CHAT_Context *context) +{ + GNUNET_assert( + (contact) && + (contact->joined) && + (context) + ); + + if (!(context->room)) + return; + + const struct GNUNET_HashCode *hash; + hash = GNUNET_CONTAINER_multihashmap_get( + contact->joined, + GNUNET_MESSENGER_room_get_key(context->room) + ); + + if (! hash) + return; + + struct GNUNET_CHAT_ContactFindJoin find; + find.hash = NULL; + + GNUNET_CONTAINER_multihashmap_get_multiple( + context->rejections, + hash, + it_contact_find_rejection, + &find + ); + + if ((! find.hash) || (! context->room)) + return; + + GNUNET_MESSENGER_delete_message( + context->room, + find.hash, + GNUNET_TIME_relative_get_zero_() + ); +} + +void +contact_block (struct GNUNET_CHAT_Contact *contact, + struct GNUNET_CHAT_Context *context) +{ + GNUNET_assert( + (contact) && + (contact->joined) && + (context) + ); + + if (!(context->room)) + return; + + const struct GNUNET_HashCode *hash; + hash = GNUNET_CONTAINER_multihashmap_get( + contact->joined, + GNUNET_MESSENGER_room_get_key(context->room) + ); + + if (! hash) + return; + + struct GNUNET_CHAT_ContactFindJoin find; + find.hash = NULL; + + GNUNET_CONTAINER_multihashmap_get_multiple( + context->rejections, + hash, + it_contact_find_rejection, + &find + ); + + if ((find.hash) || (! context->room)) + return; + + struct GNUNET_MESSENGER_Message msg; + msg.header.kind = GNUNET_MESSENGER_KIND_TAG; + GNUNET_memcpy(&(msg.body.tag.hash), hash, + sizeof(struct GNUNET_HashCode)); + msg.body.tag.tag = NULL; + + GNUNET_MESSENGER_send_message( + context->room, + &msg, + contact->member + ); +} + void contact_destroy (struct GNUNET_CHAT_Contact* contact) { @@ -124,6 +302,9 @@ contact_destroy (struct GNUNET_CHAT_Contact* contact) if (contact->public_key) GNUNET_free(contact->public_key); + if (contact->joined) + GNUNET_CONTAINER_multihashmap_destroy(contact->joined); + if ((contact->context) && (!contact->context->room)) context_destroy(contact->context); diff --git a/src/gnunet_chat_contact.h b/src/gnunet_chat_contact.h @@ -46,6 +46,7 @@ struct GNUNET_CHAT_Contact struct GNUNET_CHAT_Context *context; const struct GNUNET_MESSENGER_Contact *member; + struct GNUNET_CONTAINER_MultiHashMap *joined; struct GNUNET_CHAT_InternalTickets *tickets_head; struct GNUNET_CHAT_InternalTickets *tickets_tail; @@ -54,7 +55,6 @@ struct GNUNET_CHAT_Contact void *user_pointer; enum GNUNET_GenericReturnValue owned; - enum GNUNET_GenericReturnValue blocked; }; /** @@ -70,6 +70,21 @@ contact_create_from_member (struct GNUNET_CHAT_Handle *handle, const struct GNUNET_MESSENGER_Contact *member); /** + * Updates the latest <i>hash</i> of a join message from a given + * chat <i>contact</i> in a current chat <i>context</i>. + * + * @param[in,out] contact Chat contact + * @param[in,out] context Chat context + * @param[in] hash Join message hash + * @param[in] flags Join message flags + */ +void +contact_update_join (struct GNUNET_CHAT_Contact *contact, + struct GNUNET_CHAT_Context *context, + const struct GNUNET_HashCode *hash, + enum GNUNET_MESSENGER_MessageFlags flags); + +/** * Updates the string representation of the public key from * a given chat <i>contact</i>. * @@ -89,6 +104,40 @@ struct GNUNET_CHAT_Context* contact_find_context (const struct GNUNET_CHAT_Contact *contact); /** + * Returns whether a chat <i>contact</i> is blocked in + * a given chat <i>context</i>. + * + * @param[in] contact Chat contact + * @param[in] context Chat context + * @return #GNUNET_YES if blocked, otherwise #GNUNET_NO + */ +enum GNUNET_GenericReturnValue +contact_is_blocked (const struct GNUNET_CHAT_Contact *contact, + const struct GNUNET_CHAT_Context *context); + +/** + * Unblocks a given chat <i>contact</i> in + * a given chat <i>context</i>. + * + * @param[in,out] contact Chat contact + * @param[in,out] context Chat context + */ +void +contact_unblock (struct GNUNET_CHAT_Contact *contact, + struct GNUNET_CHAT_Context *context); + +/** + * Blocks a given chat <i>contact</i> in + * a given chat <i>context</i>. + * + * @param[in,out] contact Chat contact + * @param[in,out] context Chat context + */ +void +contact_block (struct GNUNET_CHAT_Contact *contact, + struct GNUNET_CHAT_Context *context); + +/** * Destroys a chat <i>contact</i> and frees its memory. * * @param[in,out] contact Chat contact diff --git a/src/gnunet_chat_contact_intern.c b/src/gnunet_chat_contact_intern.c @@ -22,6 +22,11 @@ * @file gnunet_chat_contact_intern.c */ +#include "gnunet_chat_context.h" +#include "gnunet_chat_message.h" + +#include <gnunet/gnunet_common.h> +#include <gnunet/gnunet_messenger_service.h> #include <stdlib.h> #define GNUNET_UNUSED __attribute__ ((unused)) @@ -32,7 +37,7 @@ struct GNUNET_CHAT_ContactFindRoom struct GNUNET_MESSENGER_Room *room; }; -int +enum GNUNET_GenericReturnValue it_contact_find_room (void *cls, struct GNUNET_MESSENGER_Room *room, GNUNET_UNUSED const struct GNUNET_MESSENGER_Contact *member) @@ -52,3 +57,33 @@ it_contact_find_room (void *cls, return GNUNET_YES; } + +struct GNUNET_CHAT_ContactFindJoin +{ + const struct GNUNET_HashCode *hash; +}; + +enum GNUNET_GenericReturnValue +it_contact_find_rejection (void *cls, + const struct GNUNET_HashCode *key, + void *value) +{ + GNUNET_assert((cls) && (key) && (value)); + + struct GNUNET_CHAT_ContactFindJoin *find = cls; + + const struct GNUNET_CHAT_Message *message = value; + + if (GNUNET_YES != message_has_msg(message)) + return GNUNET_YES; + + if (message->flags & GNUNET_MESSENGER_FLAG_SENT) + { + find->hash = &(message->hash); + return GNUNET_NO; + } + + return GNUNET_YES; +} + + diff --git a/src/gnunet_chat_context.c b/src/gnunet_chat_context.c @@ -23,10 +23,13 @@ */ #include "gnunet_chat_context.h" +#include "gnunet_chat_file.h" #include "gnunet_chat_handle.h" +#include "gnunet_chat_message.h" #include "gnunet_chat_util.h" #include "gnunet_chat_context_intern.c" +#include <gnunet/gnunet_messenger_service.h> #include <gnunet/gnunet_namestore_service.h> static const unsigned int initial_map_size_of_room = 8; @@ -274,6 +277,64 @@ context_read_records (struct GNUNET_CHAT_Context *context, } void +context_delete_message (struct GNUNET_CHAT_Context *context, + const struct GNUNET_CHAT_Message *message) +{ + GNUNET_assert((context) && (message)); + + if (GNUNET_YES != message_has_msg(message)) + return; + + switch (message->msg->header.kind) + { + case GNUNET_MESSENGER_KIND_INVITE: + { + struct GNUNET_CHAT_Invitation *invite = GNUNET_CONTAINER_multihashmap_get( + context->invites, &(message->hash) + ); + + if (! invite) + break; + + if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove( + context->invites, &(message->hash), invite)) + invitation_destroy(invite); + + break; + } + case GNUNET_MESSENGER_KIND_FILE: + { + struct GNUNET_CHAT_File *file = GNUNET_CONTAINER_multihashmap_get( + context->files, &(message->hash) + ); + + if (! file) + break; + + if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove( + context->files, &(message->hash), file)) + file_destroy(file); + + break; + } + case GNUNET_MESSENGER_KIND_TAG: + { + if (message->msg->body.tag.tag) + break; + + GNUNET_CONTAINER_multihashmap_remove( + context->rejections, + &(message->msg->body.tag.hash), + message); + + break; + } + default: + break; + } +} + +void context_write_records (struct GNUNET_CHAT_Context *context) { GNUNET_assert((context) && (context->handle) && (context->room)); diff --git a/src/gnunet_chat_context.h b/src/gnunet_chat_context.h @@ -32,6 +32,7 @@ #include "gnunet_chat_util.h" struct GNUNET_CHAT_Handle; +struct GNUNET_CHAT_Message; struct GNUNET_CHAT_Context { @@ -113,6 +114,17 @@ context_update_nick (struct GNUNET_CHAT_Context *context, const char *nick); /** + * Deletes linked content from a given chat <i>context</i> + * of a specific chat <i>message</i>. + * + * @param[in,out] context Chat context + * @param[in] message Chat message + */ +void +context_delete_message (struct GNUNET_CHAT_Context *context, + const struct GNUNET_CHAT_Message *message); + +/** * Reads the <i>data</i> of records under a given <i>label</i> * and updates the chat <i>context</i> with it. * diff --git a/src/gnunet_chat_handle_intern.c b/src/gnunet_chat_handle_intern.c @@ -897,6 +897,13 @@ on_handle_message_callback(void *cls) switch (message->msg->header.kind) { + case GNUNET_MESSENGER_KIND_JOIN: + { + contact_update_join(contact, context, + &(message->hash), message->flags); + + break; + } case GNUNET_MESSENGER_KIND_KEY: { contact_update_key(contact); @@ -932,7 +939,7 @@ on_handle_message_callback(void *cls) break; } - if (GNUNET_YES == contact->blocked) + if (GNUNET_YES == contact_is_blocked(contact, context)) goto clear_dependencies; handle->msg_cb(handle->msg_cls, context, message); @@ -1029,10 +1036,10 @@ on_handle_message (void *cls, { message_update_msg (message, flags, msg); - if (message->flags & GNUNET_MESSENGER_FLAG_UPDATE) - goto handle_callback; - else + if (0 != (message->flags & GNUNET_MESSENGER_FLAG_UPDATE)) return; + + goto handle_callback; } else if (msg->header.kind == GNUNET_MESSENGER_KIND_DELETE) { diff --git a/src/gnunet_chat_lib.c b/src/gnunet_chat_lib.c @@ -830,7 +830,8 @@ GNUNET_CHAT_contact_set_name (struct GNUNET_CHAT_Contact *contact, { GNUNET_CHAT_VERSION_ASSERT(); - if ((!contact) || (!(contact->context))) + if ((!contact) || (!(contact->context)) || + (contact->context->topic)) return; context_update_nick(contact->context, name); @@ -848,7 +849,8 @@ GNUNET_CHAT_contact_get_name (const struct GNUNET_CHAT_Contact *contact) if (!contact) return NULL; - if ((contact->context) && (contact->context->nick[0])) + if ((contact->context) && (! contact->context->topic) && + (contact->context->nick[0])) return contact->context->nick; return GNUNET_MESSENGER_contact_get_name(contact->member); @@ -936,10 +938,24 @@ GNUNET_CHAT_contact_set_blocked (struct GNUNET_CHAT_Contact *contact, { GNUNET_CHAT_VERSION_ASSERT(); - if ((!contact) || ((GNUNET_YES != blocked) && (GNUNET_NO != blocked))) + if (!contact) + return; + + struct GNUNET_CHAT_ContactIterateContexts it; + it.contact = contact; + + if (GNUNET_NO == blocked) + it.cb = contact_unblock; + else if (GNUNET_YES == blocked) + it.cb = contact_block; + else return; - contact->blocked = blocked; + GNUNET_CONTAINER_multihashmap_iterate( + contact->joined, + it_contact_iterate_contexts, + &it + ); } @@ -951,7 +967,12 @@ GNUNET_CHAT_contact_is_blocked (const struct GNUNET_CHAT_Contact *contact) if (!contact) return GNUNET_SYSERR; - return contact->blocked; + struct GNUNET_CHAT_Context *context = contact_find_context(contact); + + if (!context) + return GNUNET_SYSERR; + + return contact_is_blocked(contact, context); } diff --git a/src/gnunet_chat_lib_intern.c b/src/gnunet_chat_lib_intern.c @@ -22,6 +22,9 @@ * @file gnunet_chat_lib_intern.c */ +#include "gnunet_chat_contact.h" +#include "gnunet_chat_handle.h" + #include <gnunet/gnunet_common.h> #include <stdlib.h> @@ -105,7 +108,7 @@ struct GNUNET_CHAT_HandleIterateContacts void *cls; }; -int +enum GNUNET_GenericReturnValue it_handle_iterate_contacts (void *cls, GNUNET_UNUSED const struct GNUNET_ShortHashCode *key, void *value) @@ -129,7 +132,7 @@ struct GNUNET_CHAT_HandleIterateGroups void *cls; }; -int +enum GNUNET_GenericReturnValue it_handle_iterate_groups (void *cls, GNUNET_UNUSED const struct GNUNET_HashCode *key, void *value) @@ -146,13 +149,46 @@ it_handle_iterate_groups (void *cls, return it->cb(it->cls, it->handle, group); } +typedef void +(*GNUNET_CHAT_ContactIterateContextCallback) (struct GNUNET_CHAT_Contact *contact, + struct GNUNET_CHAT_Context *context); + +struct GNUNET_CHAT_ContactIterateContexts +{ + struct GNUNET_CHAT_Contact *contact; + GNUNET_CHAT_ContactIterateContextCallback cb; +}; + +enum GNUNET_GenericReturnValue +it_contact_iterate_contexts (void *cls, + const struct GNUNET_HashCode *key, + GNUNET_UNUSED void *value) +{ + GNUNET_assert((cls) && (key)); + + struct GNUNET_CHAT_ContactIterateContexts *it = cls; + + if (!(it->cb)) + return GNUNET_YES; + + struct GNUNET_CHAT_Handle *handle = it->contact->handle; + struct GNUNET_CHAT_Context *context = GNUNET_CONTAINER_multihashmap_get( + handle->contexts, key); + + if (! context) + return GNUNET_YES; + + it->cb(it->contact, context); + return GNUNET_YES; +} + struct GNUNET_CHAT_RoomFindContact { const struct GNUNET_CRYPTO_PublicKey *ignore_key; const struct GNUNET_MESSENGER_Contact *contact; }; -int +enum GNUNET_GenericReturnValue it_room_find_contact (void *cls, GNUNET_UNUSED struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Contact *member) @@ -180,7 +216,7 @@ struct GNUNET_CHAT_GroupIterateContacts void *cls; }; -int +enum GNUNET_GenericReturnValue it_group_iterate_contacts (void* cls, GNUNET_UNUSED struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Contact *member) @@ -204,7 +240,7 @@ struct GNUNET_CHAT_ContextIterateMessages void *cls; }; -int +enum GNUNET_GenericReturnValue it_context_iterate_messages (void *cls, GNUNET_UNUSED const struct GNUNET_HashCode *key, void *value) @@ -228,7 +264,7 @@ struct GNUNET_CHAT_ContextIterateFiles void *cls; }; -int +enum GNUNET_GenericReturnValue it_context_iterate_files (void *cls, const struct GNUNET_HashCode *key, GNUNET_UNUSED void *value) @@ -264,7 +300,7 @@ struct GNUNET_CHAT_MessageIterateReadReceipts void *cls; }; -int +enum GNUNET_GenericReturnValue it_message_iterate_read_receipts (void *cls, GNUNET_UNUSED struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Contact *member) diff --git a/src/gnunet_chat_message.c b/src/gnunet_chat_message.c @@ -23,6 +23,8 @@ */ #include "gnunet_chat_message.h" +#include "gnunet_chat_context.h" + #include <gnunet/gnunet_messenger_service.h> struct GNUNET_CHAT_Message* @@ -93,7 +95,10 @@ message_update_msg (struct GNUNET_CHAT_Message* message, if (flags & GNUNET_MESSENGER_FLAG_UPDATE) message->msg = msg; else if (flags & GNUNET_MESSENGER_FLAG_DELETE) + { + context_delete_message(message->context, message); message->msg = NULL; + } else return;