From 25e42d202a4f9b356a5e8775cd7ef2c741b3d187 Mon Sep 17 00:00:00 2001 From: TheJackiMonster Date: Thu, 1 Feb 2024 20:40:40 +0100 Subject: MESSENGER: Implement client side deletion and update callback for messages Signed-off-by: TheJackiMonster --- src/include/gnunet_messenger_service.h | 10 + src/service/messenger/messenger_api.c | 102 +---- .../messenger/messenger_api_contact_store.c | 5 +- src/service/messenger/messenger_api_message.c | 24 +- src/service/messenger/messenger_api_message.h | 12 +- src/service/messenger/messenger_api_room.c | 437 ++++++++++++++++----- src/service/messenger/messenger_api_room.h | 28 +- 7 files changed, 398 insertions(+), 220 deletions(-) (limited to 'src') diff --git a/src/include/gnunet_messenger_service.h b/src/include/gnunet_messenger_service.h index 8e1cd666d..8c009a0e6 100644 --- a/src/include/gnunet_messenger_service.h +++ b/src/include/gnunet_messenger_service.h @@ -669,6 +669,16 @@ enum GNUNET_MESSENGER_MessageFlags * The recent flag. The flag indicates that the message was recently handled by the service. */ GNUNET_MESSENGER_FLAG_RECENT = 8, + + /** + * The update flag. The flag indicates that the message was updated by the client. + */ + GNUNET_MESSENGER_FLAG_UPDATE = 16, + + /** + * The delete flag. The flag indicates that the message was deleted by the service. + */ + GNUNET_MESSENGER_FLAG_DELETE = 32, }; /** diff --git a/src/service/messenger/messenger_api.c b/src/service/messenger/messenger_api.c index 7623e21c5..dc2e6045a 100644 --- a/src/service/messenger/messenger_api.c +++ b/src/service/messenger/messenger_api.c @@ -24,7 +24,6 @@ */ #include "gnunet_common.h" -#include "gnunet_core_service.h" #include "gnunet_messenger_service.h" #include "gnunet-service-messenger.h" @@ -109,7 +108,7 @@ handle_room_open (void *cls, if (! room) return; - GNUNET_memcpy (&(room->last_message), prev, sizeof(room->last_message)); + update_room_last_message (room, prev); dequeue_messages_from_room (room); } @@ -134,7 +133,7 @@ handle_room_entry (void *cls, if (! room) return; - GNUNET_memcpy (&(room->last_message), prev, sizeof(room->last_message)); + update_room_last_message (room, prev); dequeue_messages_from_room (room); } @@ -152,7 +151,7 @@ handle_room_close (void *cls, struct GNUNET_MESSENGER_Room *room = get_handle_room (handle, key); if (room) - GNUNET_memcpy (&(room->last_message), prev, sizeof(room->last_message)); + update_room_last_message (room, prev); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Closed room: %s\n", GNUNET_h2s (key)); @@ -174,7 +173,7 @@ handle_room_sync (void *cls, if (! room) return; - GNUNET_memcpy (&(room->last_message), prev, sizeof(room->last_message)); + update_room_last_message (room, prev); room->wait_for_sync = GNUNET_NO; @@ -225,12 +224,6 @@ handle_member_id (void *cls, } -static void -delete_message_in_room (struct GNUNET_MESSENGER_Room *room, - const struct GNUNET_HashCode *hash, - const struct GNUNET_TIME_Relative delay); - - static enum GNUNET_GenericReturnValue check_recv_message (void *cls, const struct GNUNET_MESSENGER_RecvMessage *msg) @@ -281,8 +274,7 @@ handle_recv_message (void *cls, const struct GNUNET_HashCode *hash = &(msg->hash); enum GNUNET_MESSENGER_MessageFlags flags = ( - (enum GNUNET_MESSENGER_MessageFlags) (msg->flags) - ); + (enum GNUNET_MESSENGER_MessageFlags) (msg->flags)); const uint16_t length = ntohs (msg->header.size) - sizeof(*msg); const char *buffer = ((const char*) msg) + sizeof(*msg); @@ -290,28 +282,8 @@ handle_recv_message (void *cls, struct GNUNET_MESSENGER_Message message; decode_message (&message, length, buffer, GNUNET_YES, NULL); - struct GNUNET_MESSENGER_Message *private_message = NULL; - const struct GNUNET_MESSENGER_Message *handle_msg = &message; - - if (GNUNET_MESSENGER_KIND_PRIVATE == message.header.kind) - { - private_message = copy_message (&message); - - if (GNUNET_YES != decrypt_message (private_message, get_handle_key ( - handle))) - { - destroy_message (private_message); - private_message = NULL; - } - } - - if (private_message) - flags |= GNUNET_MESSENGER_FLAG_PRIVATE; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving message: %s\n", - GNUNET_MESSENGER_name_of_kind (private_message ? - private_message->header.kind : - message.header.kind)); + GNUNET_MESSENGER_name_of_kind (message.header.kind)); struct GNUNET_MESSENGER_Room *room = get_handle_room (handle, key); @@ -332,66 +304,16 @@ handle_recv_message (void *cls, struct GNUNET_MESSENGER_Contact *contact = get_store_contact_raw ( store, context, sender); - - struct GNUNET_MESSENGER_Contact *recipient = NULL; - - if (!private_message) - goto skip_recipient; - - const struct GNUNET_CRYPTO_PublicKey *recipient_key; - - if (GNUNET_MESSENGER_KIND_TRANSCRIPT == private_message->header.kind) - { - struct GNUNET_MESSENGER_Message *transcript; - recipient_key = &(private_message->body.transcript.key); - transcript = read_transcript_message(private_message); + handle_room_message (room, contact, &message, hash, flags); - if (transcript) - { - destroy_message(private_message); - private_message = transcript; - } - } - else - recipient_key = get_handle_pubkey(handle); + if (flags & GNUNET_MESSENGER_FLAG_RECENT) + update_room_last_message (room, hash); - recipient = get_store_contact(store, context, recipient_key); - -skip_recipient: - if (private_message) - handle_msg = private_message; - - if ((GNUNET_MESSENGER_KIND_DELETE == handle_msg->header.kind) && - (GNUNET_MESSENGER_FLAG_SENT & flags)) - { - struct GNUNET_TIME_Relative delay; - struct GNUNET_TIME_Absolute action; - - delay = GNUNET_TIME_relative_ntoh (handle_msg->body.deletion.delay); - - action = GNUNET_TIME_absolute_ntoh (handle_msg->header.timestamp); - action = GNUNET_TIME_absolute_add (action, delay); - - delay = GNUNET_TIME_absolute_get_difference (GNUNET_TIME_absolute_get (), action); - - link_room_deletion (room, &(handle_msg->body.deletion.hash), delay, delete_message_in_room); - } - - contact = handle_room_message (room, contact, recipient, handle_msg, hash, flags); - - const struct GNUNET_MESSENGER_Message *stored_message = get_room_message ( - room, hash); - - if (handle->msg_callback) - handle->msg_callback (handle->msg_cls, room, contact, recipient, - stored_message, hash, flags); + callback_room_message (room, hash); skip_message: cleanup_message (&message); - - if (private_message) - destroy_message (private_message); } @@ -752,7 +674,7 @@ send_message_to_room (struct GNUNET_MESSENGER_Room *room, hash_message (message, msg_length, msg_buffer, hash); sign_message (message, msg_length, msg_buffer, hash, key); - GNUNET_memcpy (&(room->last_message), hash, sizeof(room->last_message)); + update_room_last_message (room, hash); GNUNET_MQ_send (room->handle->mq, env); @@ -1243,7 +1165,7 @@ GNUNET_MESSENGER_send_message (struct GNUNET_MESSENGER_Room *room, } -static void +void delete_message_in_room (struct GNUNET_MESSENGER_Room *room, const struct GNUNET_HashCode *hash, const struct GNUNET_TIME_Relative delay) diff --git a/src/service/messenger/messenger_api_contact_store.c b/src/service/messenger/messenger_api_contact_store.c index 538e97acc..75069b187 100644 --- a/src/service/messenger/messenger_api_contact_store.c +++ b/src/service/messenger/messenger_api_contact_store.c @@ -113,14 +113,13 @@ get_store_contact (struct GNUNET_MESSENGER_ContactStore *store, const struct GNUNET_HashCode *context, const struct GNUNET_CRYPTO_PublicKey *pubkey) { - GNUNET_assert ((store) && (store->contacts) && (context) && (pubkey)); + GNUNET_assert ((store) && (store->contacts) && (pubkey)); struct GNUNET_HashCode hash; GNUNET_CRYPTO_hash (pubkey, sizeof(*pubkey), &hash); struct GNUNET_CONTAINER_MultiHashMap *map = select_store_contact_map ( - store, context, &hash - ); + store, context, &hash); struct GNUNET_MESSENGER_Contact *contact = GNUNET_CONTAINER_multihashmap_get ( map, &hash); diff --git a/src/service/messenger/messenger_api_message.c b/src/service/messenger/messenger_api_message.c index f6d8c31f7..d98938671 100644 --- a/src/service/messenger/messenger_api_message.c +++ b/src/service/messenger/messenger_api_message.c @@ -29,6 +29,7 @@ #include "gnunet_messenger_service.h" #include "gnunet_signatures.h" #include +#include struct GNUNET_MESSENGER_MessageSignature { @@ -1123,34 +1124,29 @@ transcribe_message (const struct GNUNET_MESSENGER_Message *message, } -struct GNUNET_MESSENGER_Message* -read_transcript_message (const struct GNUNET_MESSENGER_Message *transcript) +enum GNUNET_GenericReturnValue +read_transcript_message (struct GNUNET_MESSENGER_Message *message) { - GNUNET_assert (transcript); + GNUNET_assert (message); - if (GNUNET_MESSENGER_KIND_TRANSCRIPT != transcript->header.kind) - return NULL; + if (GNUNET_MESSENGER_KIND_TRANSCRIPT != message->header.kind) + return GNUNET_NO; - const uint16_t data_length = transcript->body.transcript.length; + const uint16_t data_length = message->body.transcript.length; struct GNUNET_MESSENGER_ShortMessage shortened; if (GNUNET_YES != decode_short_message (&shortened, data_length, - transcript->body.transcript.data)) + message->body.transcript.data)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Decoding decrypted message failed!\n"); - return NULL; + return GNUNET_NO; } - struct GNUNET_MESSENGER_Message *message = create_message(shortened.kind); - - if (!message) - return NULL; - unfold_short_message(&shortened, message); - return message; + return GNUNET_YES; } diff --git a/src/service/messenger/messenger_api_message.h b/src/service/messenger/messenger_api_message.h index a19eb36ba..f5bc62519 100644 --- a/src/service/messenger/messenger_api_message.h +++ b/src/service/messenger/messenger_api_message.h @@ -257,13 +257,15 @@ transcribe_message (const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_CRYPTO_PublicKey *key); /** - * Read the original message from a message transcript. + * Read the original message from a transcript message and replaces its body + * and kind with the inner encrypted message. The function returns #GNUNET_YES if the + * operation succeeded, otherwise #GNUNET_NO. * - * @param[in] transcript Message transcript - * @return Original message + * @param[in,out] transcript Message transcript + * @return #GNUNET_YES on success, otherwise #GNUNET_NO */ -struct GNUNET_MESSENGER_Message* -read_transcript_message (const struct GNUNET_MESSENGER_Message *transcript); +enum GNUNET_GenericReturnValue +read_transcript_message (struct GNUNET_MESSENGER_Message *message); typedef void (*GNUNET_MESSENGER_SignFunction)( const void *cls, diff --git a/src/service/messenger/messenger_api_room.c b/src/service/messenger/messenger_api_room.c index 364a4e674..6b127fca5 100644 --- a/src/service/messenger/messenger_api_room.c +++ b/src/service/messenger/messenger_api_room.c @@ -25,8 +25,12 @@ #include "messenger_api_room.h" +#include "gnunet_common.h" +#include "gnunet_messenger_service.h" +#include "messenger_api_contact_store.h" #include "messenger_api_handle.h" #include "messenger_api_message.h" +#include struct GNUNET_MESSENGER_Room* create_room (struct GNUNET_MESSENGER_Handle *handle, @@ -178,8 +182,11 @@ get_room_message (const struct GNUNET_MESSENGER_Room *room, GNUNET_CONTAINER_multihashmap_get ( room->messages, hash ); + + if (! entry) + return NULL; - return (entry? entry->message : NULL); + return entry->message; } @@ -213,50 +220,85 @@ get_room_recipient (const struct GNUNET_MESSENGER_Room *room, } -static struct GNUNET_MESSENGER_Contact* +void +callback_room_message (struct GNUNET_MESSENGER_Room *room, + const struct GNUNET_HashCode *hash) +{ + GNUNET_assert ((room) && (hash)); + + struct GNUNET_MESSENGER_Handle *handle = room->handle; + + if (! handle) + return; + + struct GNUNET_MESSENGER_RoomMessageEntry *entry; + entry = GNUNET_CONTAINER_multihashmap_get (room->messages, hash); + + if (! entry) + return; + + if (handle->msg_callback) + handle->msg_callback (handle->msg_cls, room, + entry->sender, + entry->recipient, + entry->message, + hash, + entry->flags); + + if (entry->flags & GNUNET_MESSENGER_FLAG_UPDATE) + entry->flags ^= GNUNET_MESSENGER_FLAG_UPDATE; +} + + +static void +handle_message (struct GNUNET_MESSENGER_Room *room, + const struct GNUNET_HashCode *hash, + struct GNUNET_MESSENGER_RoomMessageEntry *entry); + + +void handle_join_message (struct GNUNET_MESSENGER_Room *room, - struct GNUNET_MESSENGER_Contact *sender, - const struct GNUNET_MESSENGER_Message *message, - const struct GNUNET_HashCode *hash) + const struct GNUNET_HashCode *hash, + struct GNUNET_MESSENGER_RoomMessageEntry *entry) { - if (! sender) + GNUNET_assert ((room) && (hash) && (entry)); + + if (! entry->sender) { struct GNUNET_MESSENGER_ContactStore *store = get_handle_contact_store ( room->handle); struct GNUNET_HashCode context; - get_context_from_member (&(room->key), &(message->header.sender_id), + get_context_from_member (&(room->key), &(entry->message->header.sender_id), &context); - sender = get_store_contact (store, &context, &(message->body.join.key)); + entry->sender = get_store_contact (store, &context, &(entry->message->body.join.key)); } if ((GNUNET_YES != GNUNET_CONTAINER_multishortmap_contains_value ( - room->members, &(message->header.sender_id), sender)) && + room->members, &(entry->message->header.sender_id), entry->sender)) && (GNUNET_OK == GNUNET_CONTAINER_multishortmap_put (room->members, - &(message->header. - sender_id), sender, + &(entry->message->header.sender_id), + entry->sender, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE))) - increase_contact_rc (sender); - - return sender; + increase_contact_rc (entry->sender); } static void handle_leave_message (struct GNUNET_MESSENGER_Room *room, - struct GNUNET_MESSENGER_Contact *sender, - const struct GNUNET_MESSENGER_Message *message, - const struct GNUNET_HashCode *hash) + const struct GNUNET_HashCode *hash, + struct GNUNET_MESSENGER_RoomMessageEntry *entry) { - if ((! sender) || + GNUNET_assert ((room) && (hash) && (entry)); + + if ((! entry->sender) || (GNUNET_YES != GNUNET_CONTAINER_multishortmap_remove (room->members, - &(message->header. - sender_id), - sender))) + &(entry->message->header.sender_id), + entry->sender))) return; - if (GNUNET_YES == decrease_contact_rc (sender)) + if (GNUNET_YES == decrease_contact_rc (entry->sender)) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "A contact does not share any room with you anymore!\n"); } @@ -264,12 +306,12 @@ handle_leave_message (struct GNUNET_MESSENGER_Room *room, static void handle_name_message (struct GNUNET_MESSENGER_Room *room, - struct GNUNET_MESSENGER_Contact *sender, - const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash, - enum GNUNET_MESSENGER_MessageFlags flags) + struct GNUNET_MESSENGER_RoomMessageEntry *entry) { - if (GNUNET_MESSENGER_FLAG_SENT & flags) + GNUNET_assert ((room) && (hash) && (entry)); + + if (GNUNET_MESSENGER_FLAG_SENT & entry->flags) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Set rule for using handle name in room: %s\n", @@ -277,176 +319,363 @@ handle_name_message (struct GNUNET_MESSENGER_Room *room, const char *handle_name = get_handle_name (room->handle); - if ((handle_name) && (0 == strcmp (handle_name, message->body.name.name))) + if ((handle_name) && (0 == strcmp (handle_name, entry->message->body.name.name))) room->use_handle_name = GNUNET_YES; } - if (! sender) + if (! entry->sender) return; - set_contact_name (sender, message->body.name.name); + set_contact_name (entry->sender, entry->message->body.name.name); } static void handle_key_message (struct GNUNET_MESSENGER_Room *room, - struct GNUNET_MESSENGER_Contact *sender, - const struct GNUNET_MESSENGER_Message *message, - const struct GNUNET_HashCode *hash) + const struct GNUNET_HashCode *hash, + struct GNUNET_MESSENGER_RoomMessageEntry *entry) { - if (! sender) + GNUNET_assert ((room) && (hash) && (entry)); + + if (! entry->sender) return; struct GNUNET_HashCode context; - get_context_from_member (&(room->key), &(message->header.sender_id), + get_context_from_member (&(room->key), &(entry->message->header.sender_id), &context); struct GNUNET_MESSENGER_ContactStore *store = get_handle_contact_store ( room->handle); - update_store_contact (store, sender, &context, &context, - &(message->body.key.key)); + update_store_contact (store, entry->sender, &context, &context, + &(entry->message->body.key.key)); } static void handle_id_message (struct GNUNET_MESSENGER_Room *room, - struct GNUNET_MESSENGER_Contact *sender, - const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash, - enum GNUNET_MESSENGER_MessageFlags flags) + struct GNUNET_MESSENGER_RoomMessageEntry *entry) { - if (GNUNET_MESSENGER_FLAG_SENT & flags) - set_room_sender_id (room, &(message->body.id.id)); + GNUNET_assert ((room) && (hash) && (entry)); - if ((! sender) || + if (GNUNET_MESSENGER_FLAG_SENT & entry->flags) + set_room_sender_id (room, &(entry->message->body.id.id)); + + if ((! entry->sender) || (GNUNET_YES != GNUNET_CONTAINER_multishortmap_remove (room->members, - &(message->header. - sender_id), - sender)) || + &(entry->message->header.sender_id), + entry->sender)) || (GNUNET_OK != GNUNET_CONTAINER_multishortmap_put (room->members, - &(message->body.id.id), - sender, + &(entry->message->body.id.id), + entry->sender, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE))) return; struct GNUNET_HashCode context, next_context; - get_context_from_member (&(room->key), &(message->header.sender_id), + get_context_from_member (&(room->key), &(entry->message->header.sender_id), &context); - get_context_from_member (&(room->key), &(message->body.id.id), &next_context); + get_context_from_member (&(room->key), &(entry->message->body.id.id), &next_context); struct GNUNET_MESSENGER_ContactStore *store = get_handle_contact_store ( room->handle); - update_store_contact (store, sender, &context, &next_context, - get_contact_key (sender)); + update_store_contact (store, entry->sender, &context, &next_context, + get_contact_key (entry->sender)); } static void handle_miss_message (struct GNUNET_MESSENGER_Room *room, - struct GNUNET_MESSENGER_Contact *sender, - const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash, - enum GNUNET_MESSENGER_MessageFlags flags) + struct GNUNET_MESSENGER_RoomMessageEntry *entry) { - if (GNUNET_MESSENGER_FLAG_SENT & flags) - { - struct GNUNET_MESSENGER_ListTunnel *match = find_list_tunnels ( - &(room->entries), &(message->body.miss.peer), NULL); + GNUNET_assert ((room) && (hash) && (entry)); + + if (0 == (GNUNET_MESSENGER_FLAG_SENT & entry->flags)) + return; + + struct GNUNET_MESSENGER_ListTunnel *match = find_list_tunnels ( + &(room->entries), &(entry->message->body.miss.peer), NULL); + + if (match) + remove_from_list_tunnels (&(room->entries), match); +} + + +static void +handle_private_message (struct GNUNET_MESSENGER_Room *room, + const struct GNUNET_HashCode *hash, + struct GNUNET_MESSENGER_RoomMessageEntry *entry) +{ + GNUNET_assert ((room) && (hash) && (entry)); + + struct GNUNET_MESSENGER_Message *private_message = copy_message (entry->message); - if (match) - remove_from_list_tunnels (&(room->entries), match); + if (! private_message) + return; + + if (GNUNET_YES != decrypt_message (private_message, + get_handle_key (room->handle))) + { + destroy_message (private_message); + private_message = NULL; } + + if (! private_message) + return; + + destroy_message (entry->message); + + entry->recipient = get_handle_contact (room->handle, &(room->key)); + + entry->message = private_message; + entry->flags |= GNUNET_MESSENGER_FLAG_PRIVATE; + + if ((entry->sender) && (entry->recipient)) + handle_message (room, hash, entry); } +extern void +delete_message_in_room (struct GNUNET_MESSENGER_Room *room, + const struct GNUNET_HashCode *hash, + const struct GNUNET_TIME_Relative delay); + + static void handle_delete_message (struct GNUNET_MESSENGER_Room *room, - struct GNUNET_MESSENGER_Contact *sender, - const struct GNUNET_MESSENGER_Message *message, - const struct GNUNET_HashCode *hash) + const struct GNUNET_HashCode *hash, + struct GNUNET_MESSENGER_RoomMessageEntry *entry) { - struct GNUNET_MESSENGER_RoomMessageEntry *entry = - GNUNET_CONTAINER_multihashmap_get ( - room->messages, &(message->body.deletion.hash) - ); + GNUNET_assert ((room) && (hash) && (entry)); - if ((entry) && ((entry->sender == sender) || (get_handle_contact ( - room->handle, &(room->key)) == - sender)) && - (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (room->messages, - &(message->body. - deletion.hash), - entry))) + const struct GNUNET_HashCode *target_hash = &(entry->message->body.deletion.hash); + + if (get_handle_contact (room->handle, &(room->key)) == entry->sender) { - destroy_message (entry->message); - GNUNET_free (entry); + struct GNUNET_TIME_Relative delay; + struct GNUNET_TIME_Absolute action; + + delay = GNUNET_TIME_relative_ntoh (entry->message->body.deletion.delay); + + action = GNUNET_TIME_absolute_ntoh (entry->message->header.timestamp); + action = GNUNET_TIME_absolute_add (action, delay); + + delay = GNUNET_TIME_absolute_get_difference (GNUNET_TIME_absolute_get (), + action); + + link_room_deletion(room, target_hash, delay, delete_message_in_room); + } + + struct GNUNET_MESSENGER_RoomMessageEntry *target = + GNUNET_CONTAINER_multihashmap_get (room->messages, target_hash); + + if (! target) + return; + + if (((target->sender != entry->sender) && + (get_handle_contact (room->handle, &(room->key)) != entry->sender))) + return; + + target->flags |= GNUNET_MESSENGER_FLAG_DELETE; + callback_room_message (room, target_hash); + + if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (room->messages, + target_hash, + target)) + { + destroy_message (target->message); + GNUNET_free (target); } } -struct GNUNET_MESSENGER_Contact* -handle_room_message (struct GNUNET_MESSENGER_Room *room, - struct GNUNET_MESSENGER_Contact *sender, - struct GNUNET_MESSENGER_Contact *recipient, - const struct GNUNET_MESSENGER_Message *message, - const struct GNUNET_HashCode *hash, - enum GNUNET_MESSENGER_MessageFlags flags) +static void +handle_transcript_message (struct GNUNET_MESSENGER_Room *room, + const struct GNUNET_HashCode *hash, + struct GNUNET_MESSENGER_RoomMessageEntry *entry) { - if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains (room->messages, - hash)) - return sender; + GNUNET_assert ((room) && (hash) && (entry)); - switch (message->header.kind) + if (get_handle_contact (room->handle, &(room->key)) != entry->sender) + return; + + const struct GNUNET_HashCode *original_hash = &(entry->message->body.transcript.hash); + struct GNUNET_MESSENGER_ContactStore *store = get_handle_contact_store ( + room->handle); + + struct GNUNET_MESSENGER_RoomMessageEntry *original = + GNUNET_CONTAINER_multihashmap_get (room->messages, original_hash); + struct GNUNET_MESSENGER_Message *original_message; + + if (original) + goto read_transcript; + + original = GNUNET_new (struct GNUNET_MESSENGER_RoomMessageEntry); + + if (! original) + return; + + original->sender = NULL; + original->recipient = NULL; + + original->message = NULL; + original->flags = GNUNET_MESSENGER_FLAG_NONE; + + if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (room->messages, + original_hash, + original, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) + { + GNUNET_free (original); + return; + } + +read_transcript: + original_message = copy_message (entry->message); + + if (! original_message) + return; + + if (GNUNET_YES != read_transcript_message (original_message)) + { + destroy_message (original_message); + return; + } + + original->recipient = get_store_contact (store, + NULL, + &(entry->message->body.transcript.key)); + + if (original->message) + { + enum GNUNET_MESSENGER_MessageKind kind = original_message->header.kind; + memcpy (&(original_message->header), &(original->message->header), + sizeof(struct GNUNET_MESSENGER_MessageHeader)); + original_message->header.kind = kind; + + destroy_message (original->message); + } + + original->message = original_message; + original->flags |= GNUNET_MESSENGER_FLAG_PRIVATE; + + link_room_message(room, hash, original_hash); + link_room_message(room, original_hash, hash); + + if ((original->sender) && (original->recipient)) + { + original->flags |= GNUNET_MESSENGER_FLAG_UPDATE; + handle_message (room, original_hash, original); + } +} + + +static void +handle_message (struct GNUNET_MESSENGER_Room *room, + const struct GNUNET_HashCode *hash, + struct GNUNET_MESSENGER_RoomMessageEntry *entry) +{ + GNUNET_assert ((room) && (hash) && (entry)); + + switch (entry->message->header.kind) { case GNUNET_MESSENGER_KIND_JOIN: - sender = handle_join_message (room, sender, message, hash); + handle_join_message (room, hash, entry); break; case GNUNET_MESSENGER_KIND_LEAVE: - handle_leave_message (room, sender, message, hash); + handle_leave_message (room, hash, entry); break; case GNUNET_MESSENGER_KIND_NAME: - handle_name_message (room, sender, message, hash, flags); + handle_name_message (room, hash, entry); break; case GNUNET_MESSENGER_KIND_KEY: - handle_key_message (room, sender, message, hash); + handle_key_message (room, hash, entry); break; case GNUNET_MESSENGER_KIND_ID: - handle_id_message (room, sender, message, hash, flags); + handle_id_message (room, hash, entry); break; case GNUNET_MESSENGER_KIND_MISS: - handle_miss_message (room, sender, message, hash, flags); + handle_miss_message (room, hash, entry); + break; + case GNUNET_MESSENGER_KIND_PRIVATE: + handle_private_message (room, hash, entry); break; case GNUNET_MESSENGER_KIND_DELETE: - handle_delete_message (room, sender, message, hash); + handle_delete_message (room, hash, entry); + break; + case GNUNET_MESSENGER_KIND_TRANSCRIPT: + handle_transcript_message (room, hash, entry); break; default: break; } - struct GNUNET_MESSENGER_RoomMessageEntry *entry = GNUNET_new (struct - GNUNET_MESSENGER_RoomMessageEntry); + if (entry->flags & GNUNET_MESSENGER_FLAG_UPDATE) + callback_room_message (room, hash); +} + + +void +handle_room_message (struct GNUNET_MESSENGER_Room *room, + struct GNUNET_MESSENGER_Contact *sender, + const struct GNUNET_MESSENGER_Message *message, + const struct GNUNET_HashCode *hash, + enum GNUNET_MESSENGER_MessageFlags flags) +{ + GNUNET_assert ((room) && (message) && (hash)); + + struct GNUNET_MESSENGER_RoomMessageEntry *entry; + entry = GNUNET_CONTAINER_multihashmap_get (room->messages, hash); + + if (entry) + goto update_entry; + + entry = GNUNET_new (struct GNUNET_MESSENGER_RoomMessageEntry); if (! entry) - return sender; + return; - entry->sender = sender; - entry->recipient = recipient; - entry->message = copy_message (message); + entry->sender = NULL; + entry->recipient = NULL; + + entry->message = NULL; + entry->flags = GNUNET_MESSENGER_FLAG_NONE; if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (room->messages, hash, entry, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) { - destroy_message (entry->message); GNUNET_free (entry); + return; + } + +update_entry: + entry->sender = sender; + entry->flags = flags; + + if (entry->message) + { + enum GNUNET_MESSENGER_MessageKind kind = message->header.kind; + memcpy (&(entry->message->header), &(message->header), + sizeof(struct GNUNET_MESSENGER_MessageHeader)); + entry->message->header.kind = kind; } + else + entry->message = copy_message (message); + + handle_message (room, hash, entry); +} - if (flags & GNUNET_MESSENGER_FLAG_RECENT) - GNUNET_memcpy (&(room->last_message), hash, sizeof(room->last_message)); - return sender; +void +update_room_last_message (struct GNUNET_MESSENGER_Room *room, + const struct GNUNET_HashCode *hash) +{ + GNUNET_assert ((room) && (hash)); + + GNUNET_memcpy (&(room->last_message), hash, sizeof(room->last_message)); } diff --git a/src/service/messenger/messenger_api_room.h b/src/service/messenger/messenger_api_room.h index 79571bc2e..7587fb256 100644 --- a/src/service/messenger/messenger_api_room.h +++ b/src/service/messenger/messenger_api_room.h @@ -40,7 +40,9 @@ struct GNUNET_MESSENGER_RoomMessageEntry { struct GNUNET_MESSENGER_Contact *sender; struct GNUNET_MESSENGER_Contact *recipient; + struct GNUNET_MESSENGER_Message *message; + enum GNUNET_MESSENGER_MessageFlags flags; }; struct GNUNET_MESSENGER_Room @@ -152,6 +154,16 @@ struct GNUNET_MESSENGER_Contact* get_room_recipient (const struct GNUNET_MESSENGER_Room *room, const struct GNUNET_HashCode *hash); +/** + * Executes the message callback for a given hash in a room. + * + * @param[in,out] room Room + * @param[in] hash Hash of message + */ +void +callback_room_message (struct GNUNET_MESSENGER_Room *room, + const struct GNUNET_HashCode *hash); + /** * Handles a message with a given hash in a room for the client API to update * members and its information. The function also stores the message in map locally for access afterwards. @@ -161,20 +173,28 @@ get_room_recipient (const struct GNUNET_MESSENGER_Room *room, * * @param[in,out] room Room * @param[in,out] sender Contact of sender - * @param[in,out] recipient Contact of recipient * @param[in] message Message * @param[in] hash Hash of message * @param[in] flags Flags of message - * @return Contact of sender */ -struct GNUNET_MESSENGER_Contact* +void handle_room_message (struct GNUNET_MESSENGER_Room *room, struct GNUNET_MESSENGER_Contact *sender, - struct GNUNET_MESSENGER_Contact *recipient, const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash, enum GNUNET_MESSENGER_MessageFlags flags); +/** + * Updates the last message hash of a room for the client API so that new messages can + * point to the latest message hash while sending. + * + * @param[in,out] room Room + * @param[in] hash Hash of message + */ +void +update_room_last_message (struct GNUNET_MESSENGER_Room *room, + const struct GNUNET_HashCode *hash); + /** * Iterates through all members of a given room to forward each of them to a selected * callback with a custom closure. -- cgit v1.2.3