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:
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)