commit e19d4dedf548d6b16f95a97f6b67fd2a09a18643
parent e068078b3ae07d67e9d4b75574075773a88c4a3d
Author: TheJackiMonster <thejackimonster@gmail.com>
Date: Sun, 25 Jul 2021 17:09:02 +0200
Implemented read receipts and deletion
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
Diffstat:
10 files changed, 128 insertions(+), 161 deletions(-)
diff --git a/include/gnunet_chat_lib.h b/include/gnunet_chat_lib.h
@@ -31,6 +31,7 @@
#include <gnunet/platform.h>
#include <gnunet/gnunet_common.h>
+#include <gnunet/gnunet_time_lib.h>
#include <gnunet/gnunet_util_lib.h>
/**
@@ -184,8 +185,8 @@ typedef int
* @return
*/
typedef int
-(*GNUNET_CHAT_MessageReadReceiptCallback) (void *cls, struct GNUNET_CHAT_Message *message,
- struct GNUNET_CHAT_Contact *contact,
+(*GNUNET_CHAT_MessageReadReceiptCallback) (void *cls, const struct GNUNET_CHAT_Message *message,
+ const struct GNUNET_CHAT_Contact *contact,
int read_receipt);
/**
@@ -373,7 +374,7 @@ GNUNET_CHAT_contact_set_user_pointer (struct GNUNET_CHAT_Contact *contact,
* @return
*/
void*
-GNUNET_CHAT_contact_get_user_pointer (struct GNUNET_CHAT_Contact *contact);
+GNUNET_CHAT_contact_get_user_pointer (const struct GNUNET_CHAT_Contact *contact);
/**
* TODO
diff --git a/src/gnunet_chat_context.c b/src/gnunet_chat_context.c
@@ -39,6 +39,7 @@ context_create_from_room (struct GNUNET_CHAT_Handle *handle,
context->type = GNUNET_CHAT_CONTEXT_TYPE_UNKNOWN;
context->nick = NULL;
+ context->timestamps = GNUNET_CONTAINER_multishortmap_create(8, GNUNET_NO);
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);
@@ -53,14 +54,19 @@ context_create_from_room (struct GNUNET_CHAT_Handle *handle,
void
context_destroy (struct GNUNET_CHAT_Context* context)
{
+ GNUNET_CONTAINER_multishortmap_iterate(
+ context->timestamps, it_destroy_context_timestamps, NULL
+ );
+
GNUNET_CONTAINER_multihashmap_iterate(
context->messages, it_destroy_context_messages, NULL
);
GNUNET_CONTAINER_multihashmap_iterate(
- context->messages, it_destroy_context_invites, NULL
+ context->invites, it_destroy_context_invites, NULL
);
+ GNUNET_CONTAINER_multishortmap_destroy(context->timestamps);
GNUNET_CONTAINER_multihashmap_destroy(context->messages);
GNUNET_CONTAINER_multihashmap_destroy(context->invites);
GNUNET_CONTAINER_multihashmap_destroy(context->files);
diff --git a/src/gnunet_chat_context.h b/src/gnunet_chat_context.h
@@ -48,6 +48,7 @@ struct GNUNET_CHAT_Context
enum GNUNET_CHAT_ContextType type;
char *nick;
+ struct GNUNET_CONTAINER_MultiShortmap *timestamps;
struct GNUNET_CONTAINER_MultiHashMap *messages;
struct GNUNET_CONTAINER_MultiHashMap *invites;
struct GNUNET_CONTAINER_MultiHashMap *files;
diff --git a/src/gnunet_chat_context_intern.c b/src/gnunet_chat_context_intern.c
@@ -28,6 +28,16 @@
#define GNUNET_UNUSED __attribute__ ((unused))
int
+it_destroy_context_timestamps (GNUNET_UNUSED void *cls,
+ GNUNET_UNUSED const struct GNUNET_ShortHashCode *key,
+ void *value)
+{
+ struct GNUNET_TIME_Absolute *time = value;
+ GNUNET_free(time);
+ return GNUNET_YES;
+}
+
+int
it_destroy_context_messages (GNUNET_UNUSED void *cls,
GNUNET_UNUSED const struct GNUNET_HashCode *key,
void *value)
diff --git a/src/gnunet_chat_handle_intern.c b/src/gnunet_chat_handle_intern.c
@@ -279,6 +279,37 @@ on_handle_message (void *cls,
if (!context)
return;
+ const struct GNUNET_TIME_Absolute timestamp = GNUNET_TIME_absolute_ntoh(
+ msg->header.timestamp
+ );
+
+ struct GNUNET_ShortHashCode shorthash;
+ util_shorthash_from_member(sender, &shorthash);
+
+ struct GNUNET_TIME_Absolute *time = GNUNET_CONTAINER_multishortmap_get(
+ context->timestamps, &shorthash
+ );
+
+ if (time)
+ {
+ time = GNUNET_new(struct GNUNET_TIME_Absolute);
+ *time = timestamp;
+
+ if (GNUNET_OK != GNUNET_CONTAINER_multishortmap_put(
+ context->timestamps, &shorthash, time,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ GNUNET_free(time);
+ }
+ else
+ {
+ struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference(
+ timestamp, *time
+ );
+
+ if (GNUNET_TIME_relative_get_zero_().rel_value_us == delta.rel_value_us)
+ *time = timestamp;
+ }
+
struct GNUNET_CHAT_Message *message = GNUNET_CONTAINER_multihashmap_get(
context->messages, hash
);
@@ -319,6 +350,16 @@ on_handle_message (void *cls,
file_destroy(file);
break;
}
+ case GNUNET_MESSENGER_KIND_DELETE:
+ {
+ struct GNUNET_CHAT_Message *target = GNUNET_CONTAINER_multihashmap_get(
+ context->messages, &(msg->body.deletion.hash)
+ );
+
+ if (target)
+ target->msg = NULL;
+ break;
+ }
default:
break;
}
diff --git a/src/gnunet_chat_lib.c b/src/gnunet_chat_lib.c
@@ -306,7 +306,7 @@ GNUNET_CHAT_contact_set_user_pointer (struct GNUNET_CHAT_Contact *contact,
void*
-GNUNET_CHAT_contact_get_user_pointer (struct GNUNET_CHAT_Contact *contact)
+GNUNET_CHAT_contact_get_user_pointer (const struct GNUNET_CHAT_Contact *contact)
{
if (!contact)
return NULL;
@@ -611,7 +611,7 @@ GNUNET_CHAT_context_iterate_messages (struct GNUNET_CHAT_Context *context,
enum GNUNET_CHAT_MessageKind
GNUNET_CHAT_message_get_kind (const struct GNUNET_CHAT_Message *message)
{
- if (!message)
+ if ((!message) || (!(message->msg)))
return GNUNET_CHAT_KIND_UNKNOWN;
switch (message->msg->header.kind)
@@ -641,7 +641,7 @@ GNUNET_CHAT_message_get_kind (const struct GNUNET_CHAT_Message *message)
struct GNUNET_TIME_Absolute
GNUNET_CHAT_message_get_timestamp (const struct GNUNET_CHAT_Message *message)
{
- if (!message)
+ if ((!message) || (!(message->msg)))
return GNUNET_TIME_absolute_get_zero_();
return GNUNET_TIME_absolute_ntoh(message->msg->header.timestamp);
@@ -701,19 +701,29 @@ GNUNET_CHAT_message_get_read_receipt (const struct GNUNET_CHAT_Message *message,
GNUNET_CHAT_MessageReadReceiptCallback callback,
void *cls)
{
- if (!message)
+ if ((!message) || (!(message->msg)))
return GNUNET_SYSERR;
- // TODO: request read receipt? / check if newer message was received of sender?
+ struct GNUNET_CHAT_Context *context = message->context;
- return GNUNET_SYSERR;
+ if (!context)
+ return GNUNET_SYSERR;
+
+ struct GNUNET_CHAT_MessageIterateReadReceipts it;
+ it.message = message;
+ it.cb = callback;
+ it.cls = cls;
+
+ return GNUNET_MESSENGER_iterate_members(
+ context->room, it_message_iterate_read_receipts, &it
+ );
}
const char*
GNUNET_CHAT_message_get_text (const struct GNUNET_CHAT_Message *message)
{
- if (!message)
+ if ((!message) || (!(message->msg)))
return NULL;
if (GNUNET_MESSENGER_KIND_TEXT != message->msg->header.kind)
@@ -726,7 +736,7 @@ GNUNET_CHAT_message_get_text (const struct GNUNET_CHAT_Message *message)
struct GNUNET_CHAT_File*
GNUNET_CHAT_message_get_file (const struct GNUNET_CHAT_Message *message)
{
- if (!message)
+ if ((!message) || (!(message->msg)))
return NULL;
if (GNUNET_MESSENGER_KIND_FILE != message->msg->header.kind)
@@ -742,7 +752,7 @@ GNUNET_CHAT_message_get_file (const struct GNUNET_CHAT_Message *message)
struct GNUNET_CHAT_Invitation*
GNUNET_CHAT_message_get_invitation (const struct GNUNET_CHAT_Message *message)
{
- if (!message)
+ if ((!message) || (!(message->msg)))
return NULL;
if (GNUNET_MESSENGER_KIND_INVITE != message->msg->header.kind)
@@ -759,7 +769,7 @@ int
GNUNET_CHAT_message_delete (const struct GNUNET_CHAT_Message *message,
struct GNUNET_TIME_Relative delay)
{
- if (!message)
+ if ((!message) || (!(message->msg)))
return GNUNET_SYSERR;
struct GNUNET_MESSENGER_Message msg;
diff --git a/src/gnunet_chat_lib_intern.c b/src/gnunet_chat_lib_intern.c
@@ -117,8 +117,53 @@ it_context_iterate_messages (void *cls,
return it->cb(it->cls, it->context, message);
}
+struct GNUNET_CHAT_MessageIterateReadReceipts
+{
+ const struct GNUNET_CHAT_Message *message;
+ GNUNET_CHAT_MessageReadReceiptCallback cb;
+ void *cls;
+};
+
+int
+it_message_iterate_read_receipts (void *cls,
+ GNUNET_UNUSED struct GNUNET_MESSENGER_Room *room,
+ const struct GNUNET_MESSENGER_Contact *member)
+{
+ struct GNUNET_CHAT_MessageIterateReadReceipts *it = cls;
+ struct GNUNET_CHAT_Handle *handle = it->message->context->handle;
+
+ if (!handle)
+ return GNUNET_NO;
+
+ struct GNUNET_ShortHashCode shorthash;
+ util_shorthash_from_member(member, &shorthash);
+ struct GNUNET_CHAT_Contact *contact = GNUNET_CONTAINER_multishortmap_get(
+ handle->contacts, &shorthash
+ );
+
+ if (!contact)
+ return GNUNET_YES;
+
+ struct GNUNET_TIME_Absolute *timestamp = GNUNET_CONTAINER_multishortmap_get(
+ it->message->context->timestamps, &shorthash
+ );
+ if (!timestamp)
+ return GNUNET_YES;
+ struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference(
+ *timestamp, GNUNET_CHAT_message_get_timestamp(it->message)
+ );
+ int read_receipt;
+ if (GNUNET_TIME_relative_get_zero_().rel_value_us == delta.rel_value_us)
+ read_receipt = GNUNET_YES;
+ else
+ read_receipt = GNUNET_NO;
+ if (it->cb)
+ it->cb(it->cls, it->message, contact, read_receipt);
+
+ return GNUNET_YES;
+}
diff --git a/src/gnunet_chat_message.c b/src/gnunet_chat_message.c
@@ -24,8 +24,6 @@
#include "gnunet_chat_message.h"
-#include "gnunet_chat_message_intern.c"
-
struct GNUNET_CHAT_Message*
message_create_from_msg (struct GNUNET_CHAT_Context *context,
const struct GNUNET_HashCode *hash,
@@ -39,20 +37,13 @@ message_create_from_msg (struct GNUNET_CHAT_Context *context,
GNUNET_memcpy(&(message->hash), hash, sizeof(message->hash));
message->flags = flags;
- message->head = NULL;
- message->tail = NULL;
-
message->msg = msg;
- link_message_parent(message);
-
return message;
}
void
message_destroy (struct GNUNET_CHAT_Message* message)
{
- unlink_message_parent(message);
- clear_message_children(message);
GNUNET_free(message);
}
diff --git a/src/gnunet_chat_message.h b/src/gnunet_chat_message.h
@@ -48,9 +48,6 @@ struct GNUNET_CHAT_Message
struct GNUNET_HashCode hash;
enum GNUNET_MESSENGER_MessageFlags flags;
- struct GNUNET_CHAT_MessageList *head;
- struct GNUNET_CHAT_MessageList *tail;
-
const struct GNUNET_MESSENGER_Message *msg;
};
diff --git a/src/gnunet_chat_message_intern.c b/src/gnunet_chat_message_intern.c
@@ -1,135 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2021 GNUnet e.V.
-
- GNUnet is free software: you can redistribute it and/or modify it
- under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License,
- or (at your option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
- SPDX-License-Identifier: AGPL3.0-or-later
- */
-/*
- * @author Tobias Frisch
- * @file gnunet_chat_message_intern.c
- */
-
-#include <gnunet/gnunet_container_lib.h>
-
-#include "gnunet_chat_context.h"
-
-void
-link_message_parent (struct GNUNET_CHAT_Message *message)
-{
- struct GNUNET_CHAT_Context *context = message->context;
-
- struct GNUNET_CHAT_Message *prev = GNUNET_CONTAINER_multihashmap_get(
- context->messages, &(message->msg->header.previous)
- );
-
- if (prev)
- {
- struct GNUNET_CHAT_MessageList *list = GNUNET_new(
- struct GNUNET_CHAT_MessageList
- );
-
- list->message = message;
-
- GNUNET_CONTAINER_DLL_insert(prev->head, prev->tail, list);
- }
-
- if (GNUNET_MESSENGER_KIND_MERGE != message->msg->header.kind)
- return;
-
- prev = GNUNET_CONTAINER_multihashmap_get(
- context->messages, &(message->msg->body.merge.previous)
- );
-
- if (prev)
- {
- struct GNUNET_CHAT_MessageList *list = GNUNET_new(
- struct GNUNET_CHAT_MessageList
- );
-
- list->message = message;
-
- GNUNET_CONTAINER_DLL_insert(prev->head, prev->tail, list);
- }
-}
-
-void
-unlink_message_parent (struct GNUNET_CHAT_Message *message)
-{
- struct GNUNET_CHAT_Context *context = message->context;
-
- struct GNUNET_CHAT_Message *prev = GNUNET_CONTAINER_multihashmap_get(
- context->messages, &(message->msg->header.previous)
- );
-
- if (prev)
- {
- struct GNUNET_CHAT_MessageList *list = prev->head;
-
- while (list)
- {
- if (list->message == message)
- break;
-
- list = list->next;
- }
-
- if (list)
- {
- GNUNET_CONTAINER_DLL_remove(prev->head, prev->tail, list);
- GNUNET_free(list);
- }
- }
-
- if (GNUNET_MESSENGER_KIND_MERGE != message->msg->header.kind)
- return;
-
- prev = GNUNET_CONTAINER_multihashmap_get(
- context->messages, &(message->msg->body.merge.previous)
- );
-
- if (prev)
- {
- struct GNUNET_CHAT_MessageList *list = prev->head;
-
- while (list)
- {
- if (list->message == message)
- break;
-
- list = list->next;
- }
-
- if (list)
- {
- GNUNET_CONTAINER_DLL_remove(prev->head, prev->tail, list);
- GNUNET_free(list);
- }
- }
-}
-
-void
-clear_message_children (struct GNUNET_CHAT_Message *message)
-{
- struct GNUNET_CHAT_MessageList *list = message->tail;
-
- while (list)
- {
- GNUNET_CONTAINER_DLL_remove(message->head, message->tail, list);
- GNUNET_free(list);
-
- list = message->tail;
- }
-}