libgnunetchat

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

commit 6fb953df955b223cccd8feb3a322f61a377e44da
parent f599dd4efae4601e18954027caf2e5e5d527b338
Author: Jacki <jacki@thejackimonster.de>
Date:   Sun, 22 Sep 2024 21:20:54 +0200

Implement tag iteration of tags by a contact

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

Diffstat:
Minclude/gnunet/gnunet_chat_lib.h | 27+++++++++++++++++++++++++++
Msrc/gnunet_chat_contact.c | 86++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/gnunet_chat_contact.h | 16++++++++++++++++
Msrc/gnunet_chat_contact_intern.c | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/gnunet_chat_lib.c | 19+++++++++++++++++++
5 files changed, 210 insertions(+), 1 deletion(-)

diff --git a/include/gnunet/gnunet_chat_lib.h b/include/gnunet/gnunet_chat_lib.h @@ -327,6 +327,19 @@ typedef enum GNUNET_GenericReturnValue struct GNUNET_CHAT_Contact *contact); /** + * Iterator over tags of a specific chat contact. + * + * @param[in,out] cls Closure + * @param[in,out] contact Chat contact + * @param[in] tag Tag + * @return #GNUNET_YES if we should continue to iterate, #GNUNET_NO otherwise. + */ +typedef enum GNUNET_GenericReturnValue +(*GNUNET_CHAT_ContactTagCallback) (void *cls, + struct GNUNET_CHAT_Contact *contact, + const char *tag); + +/** * Iterator over accessible attributes of a specific chat contact. * * @param[in,out] cls Closure @@ -1070,6 +1083,7 @@ GNUNET_CHAT_contact_untag (struct GNUNET_CHAT_Contact *contact, * a specific <i>tag</i>. * * @param[in] contact Contact + * @param[in] tag Tag * @return #GNUNET_YES if the contact is tagged, #GNUNET_SYSERR on failure and * #GNUNET_NO otherwise */ @@ -1078,6 +1092,19 @@ GNUNET_CHAT_contact_is_tagged (const struct GNUNET_CHAT_Contact *contact, const char *tag); /** + * Calls an optional <i>callback</i> for each tag of a given chat + * <i>contact</i>. + * + * @param[in,out] contact Chat contact + * @param[in] callback Callback for tag iteration (optional) + * @param[in,out] cls Closure for tag iteration (optional) + */ +void +GNUNET_CHAT_contact_get_tags (struct GNUNET_CHAT_Contact *contact, + GNUNET_CHAT_ContactTagCallback callback, + void *cls); + +/** * Calls an optional <i>callback</i> for each attribute of a given chat * <i>contact</i>. * diff --git a/src/gnunet_chat_contact.c b/src/gnunet_chat_contact.c @@ -33,6 +33,7 @@ #include <gnunet/gnunet_common.h> #include <gnunet/gnunet_messenger_service.h> #include <gnunet/gnunet_time_lib.h> +#include <gnunet/gnunet_util_lib.h> static const unsigned int initial_map_size_of_contact = 8; @@ -219,7 +220,7 @@ contact_is_tagged (const struct GNUNET_CHAT_Contact *contact, struct GNUNET_CONTAINER_MultiHashMapIterator *iter; iter = GNUNET_CONTAINER_multihashmap_iterator_create( - contact->handle->contexts + contact->joined ); if (iter) @@ -388,6 +389,89 @@ skip_tag_search: } void +contact_iterate_tags (struct GNUNET_CHAT_Contact *contact, + struct GNUNET_CHAT_Context *context, + GNUNET_CHAT_ContactTagCallback callback, + void *cls) +{ + GNUNET_assert((contact) && (contact->joined)); + + if (! context) + { + struct GNUNET_CHAT_ContactIterateUniqueTag it; + it.tags = GNUNET_CONTAINER_multihashmap_create( + initial_map_size_of_contact, GNUNET_NO); + it.callback = callback; + it.cls = cls; + + if (! (it.tags)) + return; + + struct GNUNET_CONTAINER_MultiHashMapIterator *iter; + iter = GNUNET_CONTAINER_multihashmap_iterator_create( + contact->joined + ); + + if (! iter) + goto free_tags_iteration; + + struct GNUNET_HashCode key; + const void *value; + + while (! context) + { + if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_iterator_next( + iter, &key, &value)) + break; + + context = GNUNET_CONTAINER_multihashmap_get( + contact->handle->contexts, &key); + + if (context) + contact_iterate_tags( + contact, + context, + it_contact_iterate_unique_tag, + &it + ); + } + + GNUNET_CONTAINER_multihashmap_iterator_destroy(iter); + +free_tags_iteration: + GNUNET_CONTAINER_multihashmap_destroy(it.tags); + return; + } + + const struct GNUNET_HashCode *hash = get_contact_join_hash( + contact, context); + + if (! hash) + return; + + const struct GNUNET_CHAT_InternalTagging *tagging = GNUNET_CONTAINER_multihashmap_get( + context->taggings, + hash + ); + + if (! tagging) + return; + + struct GNUNET_CHAT_ContactIterateTag it; + it.contact = contact; + it.callback = callback; + it.cls = cls; + + internal_tagging_iterate( + tagging, + GNUNET_YES, + NULL, + it_contact_iterate_tag, + &it + ); +} + +void contact_destroy (struct GNUNET_CHAT_Contact* contact) { GNUNET_assert(contact); diff --git a/src/gnunet_chat_contact.h b/src/gnunet_chat_contact.h @@ -159,6 +159,22 @@ contact_tag (struct GNUNET_CHAT_Contact *contact, const char *tag); /** + * Iterate through all tags of a given chat <i>contact</i> + * in a specific chat <i>context</i> (or all of them) using + * an optional <i>callback</i> with its closure. + * + * @param[in,out] contact Chat contact + * @param[in,out] context Chat context or NULL + * @param[in] callback Callback for tag iteration or NULL + * @param[in,out] cls Closure for tag iteration or NULL + */ +void +contact_iterate_tags (struct GNUNET_CHAT_Contact *contact, + struct GNUNET_CHAT_Context *context, + GNUNET_CHAT_ContactTagCallback callback, + void *cls); + +/** * 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 @@ -27,6 +27,7 @@ #include <gnunet/gnunet_common.h> #include <gnunet/gnunet_messenger_service.h> +#include <gnunet/gnunet_util_lib.h> #include <stdlib.h> #define GNUNET_UNUSED __attribute__ ((unused)) @@ -84,6 +85,68 @@ it_contact_find_tag (void *cls, return GNUNET_YES; } +struct GNUNET_CHAT_ContactIterateUniqueTag +{ + struct GNUNET_CONTAINER_MultiHashMap *tags; + GNUNET_CHAT_ContactTagCallback callback; + void *cls; +}; + +enum GNUNET_GenericReturnValue +it_contact_iterate_unique_tag (void *cls, + struct GNUNET_CHAT_Contact *contact, + const char *tag) +{ + GNUNET_assert((cls) && (contact) && (tag)); + + struct GNUNET_CHAT_ContactIterateUniqueTag *it = cls; + + struct GNUNET_HashCode hash; + GNUNET_CRYPTO_hash_from_string(tag, &hash); + + if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(it->tags, &hash)) + return GNUNET_YES; + + if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put(it->tags, + &hash, NULL, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) + return GNUNET_YES; + + if (it->callback) + return it->callback(it->cls, contact, tag); + else + return GNUNET_YES; +} + +struct GNUNET_CHAT_ContactIterateTag +{ + struct GNUNET_CHAT_Contact *contact; + GNUNET_CHAT_ContactTagCallback callback; + void *cls; +}; + +enum GNUNET_GenericReturnValue +it_contact_iterate_tag (void *cls, + const struct GNUNET_CHAT_Message *message) +{ + GNUNET_assert((cls) && (message)); + + struct GNUNET_CHAT_ContactIterateTag *it = cls; + + if ((GNUNET_YES != message_has_msg(message)) || + (message->flags & GNUNET_MESSENGER_FLAG_DELETE)) + return GNUNET_YES; + + if ((message->flags & GNUNET_MESSENGER_FLAG_SENT) && + (it->callback)) + return it->callback( + it->cls, + it->contact, + message->msg->body.tag.tag + ); + else + return GNUNET_YES; +} + enum GNUNET_GenericReturnValue it_free_join_hashes (void *cls, const struct GNUNET_HashCode *key, diff --git a/src/gnunet_chat_lib.c b/src/gnunet_chat_lib.c @@ -1321,6 +1321,25 @@ GNUNET_CHAT_contact_is_tagged (const struct GNUNET_CHAT_Contact *contact, void +GNUNET_CHAT_contact_get_tags (struct GNUNET_CHAT_Contact *contact, + GNUNET_CHAT_ContactTagCallback callback, + void *cls) +{ + GNUNET_CHAT_VERSION_ASSERT(); + + if (!contact) + return; + + contact_iterate_tags( + contact, + NULL, + callback, + cls + ); +} + + +void GNUNET_CHAT_contact_get_attributes (struct GNUNET_CHAT_Contact *contact, GNUNET_CHAT_ContactAttributeCallback callback, void *cls)