libgnunetchat

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

commit 42f54e73aa1e8dbc05a12657f97b3dfecb67ba8f
parent a11f869069254bc8573964f2004d1f5cbbcf1c08
Author: TheJackiMonster <thejackimonster@gmail.com>
Date:   Mon, 13 Nov 2023 20:35:49 +0100

Adjust tests and reimplement functionality from previous service

Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>

Diffstat:
Msrc/gnunet_chat_handle.c | 237++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/gnunet_chat_handle.h | 18+++++++++++++++++-
Msrc/gnunet_chat_handle_intern.c | 137+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Msrc/gnunet_chat_lib.c | 7+++++--
Mtests/test_gnunet_chat_handle.c | 6+++++-
5 files changed, 289 insertions(+), 116 deletions(-)

diff --git a/src/gnunet_chat_handle.c b/src/gnunet_chat_handle.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2021--2022 GNUnet e.V. + Copyright (C) 2021--2023 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 @@ -185,6 +185,9 @@ handle_destroy (struct GNUNET_CHAT_Handle *handle) accounts ); + if (accounts->identifier) + GNUNET_free(accounts->identifier); + GNUNET_free(accounts); } @@ -217,6 +220,48 @@ handle_destroy (struct GNUNET_CHAT_Handle *handle) GNUNET_free(handle); } +static void +handle_update_identity(struct GNUNET_CHAT_Handle *handle) +{ + GNUNET_assert((handle) && + (handle->contexts) && + (handle->groups) && + (handle->contacts)); + + handle_update_key(handle); + + if ((0 < GNUNET_CONTAINER_multihashmap_size(handle->contexts)) || + (0 < GNUNET_CONTAINER_multihashmap_size(handle->groups)) || + (0 < GNUNET_CONTAINER_multishortmap_size(handle->contacts))) + return; + + GNUNET_assert(handle->messenger); + + handle_send_internal_message( + handle, + NULL, + GNUNET_CHAT_FLAG_LOGIN, + NULL + ); + + const struct GNUNET_IDENTITY_PrivateKey *zone = handle_get_key(handle); + + if ((!zone) || (handle->monitor)) + return; + + handle->monitor = GNUNET_NAMESTORE_zone_monitor_start( + handle->cfg, + zone, + GNUNET_YES, + NULL, + NULL, + on_monitor_namestore_record, + handle, + NULL, + NULL + ); +} + void handle_connect (struct GNUNET_CHAT_Handle *handle, const struct GNUNET_CHAT_Account *account) @@ -270,9 +315,7 @@ handle_connect (struct GNUNET_CHAT_Handle *handle, ); handle->current = account; - handle_update_key(handle); - - on_handle_identity(handle, handle->messenger); + handle_update_identity(handle); } void @@ -385,8 +428,8 @@ handle_disconnect (struct GNUNET_CHAT_Handle *handle) handle_update_key(handle); } -int -handle_create_account (struct GNUNET_CHAT_Handle *handle, +static struct GNUNET_CHAT_InternalAccounts* +find_accounts_by_name (struct GNUNET_CHAT_Handle *handle, const char *name) { GNUNET_assert((handle) && (name)); @@ -399,15 +442,74 @@ handle_create_account (struct GNUNET_CHAT_Handle *handle, if ((accounts->account->name) && (0 == strcmp(accounts->account->name, name))) - return GNUNET_NO; + break; skip_account: accounts = accounts->next; } - accounts = GNUNET_new(struct GNUNET_CHAT_InternalAccounts); - accounts->account = NULL; - accounts->handle = handle; + return accounts; +} + +static int +update_accounts_operation (struct GNUNET_CHAT_InternalAccounts **out_accounts, + struct GNUNET_CHAT_Handle *handle, + const char *name, + int wait_for_completion) +{ + GNUNET_assert(handle); + + struct GNUNET_CHAT_InternalAccounts *accounts = *out_accounts; + + if (!accounts) + { + accounts = GNUNET_new(struct GNUNET_CHAT_InternalAccounts); + + if (!accounts) + return GNUNET_SYSERR; + + accounts->account = NULL; + accounts->handle = handle; + + GNUNET_CONTAINER_DLL_insert_tail( + handle->accounts_head, + handle->accounts_tail, + accounts + ); + } + else + { + if (accounts->identifier) + GNUNET_free(accounts->identifier); + + if (accounts->op) + GNUNET_IDENTITY_cancel(accounts->op); + } + + accounts->identifier = name ? GNUNET_strdup(name) : NULL; + accounts->wait_for_completion = wait_for_completion; + + *out_accounts = accounts; + + return GNUNET_OK; +} + +int +handle_create_account (struct GNUNET_CHAT_Handle *handle, + const char *name) +{ + GNUNET_assert((handle) && (name)); + + struct GNUNET_CHAT_InternalAccounts *accounts; + accounts = find_accounts_by_name(handle, name); + + if (accounts) + return GNUNET_NO; + + int result = update_accounts_operation(&accounts, handle, NULL, GNUNET_NO); + + if (GNUNET_OK != result) + return result; accounts->op = GNUNET_IDENTITY_create( handle->identity, @@ -418,21 +520,10 @@ handle_create_account (struct GNUNET_CHAT_Handle *handle, accounts ); - if (!(accounts->op)) - { - GNUNET_free(accounts); + if (!accounts->op) return GNUNET_SYSERR; - } - - accounts->wait_for_completion = GNUNET_NO; - GNUNET_CONTAINER_DLL_insert_tail( - handle->accounts_head, - handle->accounts_tail, - accounts - ); - - return GNUNET_OK; + return result; } int @@ -441,63 +532,54 @@ handle_delete_account (struct GNUNET_CHAT_Handle *handle, { GNUNET_assert((handle) && (name)); - struct GNUNET_CHAT_InternalAccounts *accounts = handle->accounts_head; - while (accounts) - { - if (!(accounts->account)) - goto skip_account; + struct GNUNET_CHAT_InternalAccounts *accounts; + accounts = find_accounts_by_name(handle, name); - if ((accounts->account->name) && - (0 == strcmp(accounts->account->name, name))) - break; + int result = update_accounts_operation(&accounts, handle, NULL, GNUNET_YES); - skip_account: - accounts = accounts->next; - } + if (GNUNET_OK != result) + return result; - if (!accounts) - { - accounts = GNUNET_new(struct GNUNET_CHAT_InternalAccounts); - accounts->account = NULL; - accounts->handle = handle; + accounts->op = GNUNET_IDENTITY_delete( + handle->identity, + name, + cb_account_deletion, + accounts + ); - accounts->op = GNUNET_IDENTITY_delete( - handle->identity, - name, - cb_account_deletion, - accounts - ); + if (!accounts->op) + return GNUNET_SYSERR; - if (!(accounts->op)) - { - GNUNET_free(accounts); - return GNUNET_SYSERR; - } + return result; +} - accounts->wait_for_completion = GNUNET_YES; +int +handle_rename_account (struct GNUNET_CHAT_Handle *handle, + const char *old_name, + const char *new_name) +{ + GNUNET_assert((handle) && (old_name) && (new_name)); - GNUNET_CONTAINER_DLL_insert_tail( - handle->accounts_head, - handle->accounts_tail, - accounts - ); + struct GNUNET_CHAT_InternalAccounts *accounts; + accounts = find_accounts_by_name(handle, old_name); - return GNUNET_OK; - } + int result = update_accounts_operation(&accounts, handle, NULL, GNUNET_YES); - if (accounts->op) - GNUNET_IDENTITY_cancel(accounts->op); + if (GNUNET_OK != result) + return result; - accounts->op = GNUNET_IDENTITY_delete( + accounts->op = GNUNET_IDENTITY_rename( handle->identity, - name, - cb_account_deletion, + old_name, + new_name, + cb_account_rename, accounts ); - accounts->wait_for_completion = GNUNET_YES; + if (!accounts->op) + return GNUNET_SYSERR; - return (accounts->op? GNUNET_OK : GNUNET_SYSERR); + return result; } const char* @@ -519,9 +601,30 @@ handle_update (struct GNUNET_CHAT_Handle *handle) { GNUNET_assert((handle) && (handle->current)); - // TODO: Implement update function + const char *name = handle->current->name; - return GNUNET_SYSERR; + if (!name) + return GNUNET_SYSERR; + + struct GNUNET_CHAT_InternalAccounts *accounts; + accounts = find_accounts_by_name(handle, name); + + int result = update_accounts_operation(&accounts, handle, name, GNUNET_YES); + + if (GNUNET_OK != result) + return result; + + accounts->op = GNUNET_IDENTITY_delete( + handle->identity, + name, + cb_account_update, + accounts + ); + + if (!accounts->op) + return GNUNET_SYSERR; + + return result; } const struct GNUNET_IDENTITY_PrivateKey* diff --git a/src/gnunet_chat_handle.h b/src/gnunet_chat_handle.h @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2021--2022 GNUnet e.V. + Copyright (C) 2021--2023 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 @@ -51,6 +51,7 @@ struct GNUNET_CHAT_InternalMessages struct GNUNET_CHAT_InternalAccounts { struct GNUNET_CHAT_Account *account; + char *identifier; struct GNUNET_CHAT_Handle *handle; struct GNUNET_IDENTITY_Operation *op; @@ -198,6 +199,21 @@ handle_delete_account (struct GNUNET_CHAT_Handle *handle, const char *name); /** + * Renames a chat account with a specific <i>old_name</i> + * as identifier for a given chat <i>handle</i> to another + * specific <i>new_name</i>. + * + * @param[in,out] handle Chat handle + * @param[in] old_name Old chat account name + * @param[in] new_name New chat account name + * @return #GNUNET_OK on success, otherwise #GNUNET_SYSERR + */ +int +handle_rename_account (struct GNUNET_CHAT_Handle *handle, + const char *old_name, + const char *new_name); + +/** * Returns the main directory path to store information * of a given chat <i>handle</i>. * diff --git a/src/gnunet_chat_handle_intern.c b/src/gnunet_chat_handle_intern.c @@ -287,6 +287,9 @@ on_handle_gnunet_identity(void *cls, accounts ); + if (accounts->identifier) + GNUNET_free(accounts->identifier); + GNUNET_free(accounts); } @@ -347,6 +350,9 @@ cb_account_creation (void *cls, accounts ); + if (accounts->identifier) + GNUNET_free(accounts->identifier); + GNUNET_free(accounts); if (GNUNET_EC_NONE != ec) @@ -382,6 +388,9 @@ cb_account_deletion (void *cls, accounts ); + if (accounts->identifier) + GNUNET_free(accounts->identifier); + GNUNET_free(accounts); if (GNUNET_EC_NONE != ec) @@ -397,6 +406,89 @@ cb_account_deletion (void *cls, } } +void +cb_account_rename (void *cls, + enum GNUNET_ErrorCode ec) +{ + GNUNET_assert(cls); + + struct GNUNET_CHAT_InternalAccounts *accounts = ( + (struct GNUNET_CHAT_InternalAccounts*) cls + ); + + struct GNUNET_CHAT_Handle *handle = accounts->handle; + + GNUNET_CONTAINER_DLL_remove( + handle->accounts_head, + handle->accounts_tail, + accounts + ); + + if (accounts->identifier) + GNUNET_free(accounts->identifier); + + GNUNET_free(accounts); + + if (GNUNET_EC_NONE != ec) + { + handle_send_internal_message( + handle, + NULL, + GNUNET_CHAT_FLAG_WARNING, + GNUNET_ErrorCode_get_hint(ec) + ); + + return; + } +} + +static void +cb_account_update_completion (void *cls, + const struct GNUNET_IDENTITY_PrivateKey *key, + enum GNUNET_ErrorCode ec) +{ + GNUNET_assert(cls); + + struct GNUNET_CHAT_InternalAccounts *accounts = ( + (struct GNUNET_CHAT_InternalAccounts*) cls + ); + + struct GNUNET_CHAT_Handle *handle = accounts->handle; + + if ((GNUNET_EC_NONE == ec) && (key)) + GNUNET_MESSENGER_set_key(handle->messenger, key); + + cb_account_creation(cls, key, ec); +} + +void +cb_account_update (void *cls, + enum GNUNET_ErrorCode ec) +{ + GNUNET_assert(cls); + + struct GNUNET_CHAT_InternalAccounts *accounts = ( + (struct GNUNET_CHAT_InternalAccounts*) cls + ); + + struct GNUNET_CHAT_Handle *handle = accounts->handle; + + if ((GNUNET_EC_NONE != ec) || (!accounts->identifier)) + { + cb_account_deletion(cls, ec); + return; + } + + accounts->op = GNUNET_IDENTITY_create( + handle->identity, + accounts->identifier, + NULL, + GNUNET_IDENTITY_TYPE_ECDSA, + cb_account_update_completion, + accounts + ); +} + int intern_provide_contact_for_member(struct GNUNET_CHAT_Handle *handle, const struct GNUNET_MESSENGER_Contact *member, @@ -517,51 +609,6 @@ on_monitor_namestore_record(void *cls, } void -on_handle_identity(void *cls, - GNUNET_UNUSED struct GNUNET_MESSENGER_Handle *messenger) -{ - struct GNUNET_CHAT_Handle *handle = cls; - - GNUNET_assert((handle) && - (handle->contexts) && - (handle->groups) && - (handle->contacts)); - - handle_update_key(handle); - - if ((0 < GNUNET_CONTAINER_multihashmap_size(handle->contexts)) || - (0 < GNUNET_CONTAINER_multihashmap_size(handle->groups)) || - (0 < GNUNET_CONTAINER_multishortmap_size(handle->contacts))) - return; - - GNUNET_assert(handle->messenger); - - handle_send_internal_message( - handle, - NULL, - GNUNET_CHAT_FLAG_LOGIN, - NULL - ); - - const struct GNUNET_IDENTITY_PrivateKey *zone = handle_get_key(handle); - - if ((!zone) || (handle->monitor)) - return; - - handle->monitor = GNUNET_NAMESTORE_zone_monitor_start( - handle->cfg, - zone, - GNUNET_YES, - NULL, - NULL, - on_monitor_namestore_record, - handle, - NULL, - NULL - ); -} - -void on_handle_message_callback(void *cls) { struct GNUNET_CHAT_Message *message = (struct GNUNET_CHAT_Message*) cls; diff --git a/src/gnunet_chat_lib.c b/src/gnunet_chat_lib.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2021--2022 GNUnet e.V. + Copyright (C) 2021--2023 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 @@ -217,7 +217,10 @@ GNUNET_CHAT_set_name (struct GNUNET_CHAT_Handle *handle, char *low = util_get_lower(name); - int result = GNUNET_MESSENGER_set_name(handle->messenger, name); + if (handle->current) + handle_rename_account(handle, handle->current->name, low); + + int result = GNUNET_MESSENGER_set_name(handle->messenger, low); GNUNET_free(low); return result; diff --git a/tests/test_gnunet_chat_handle.c b/tests/test_gnunet_chat_handle.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2021--2022 GNUnet e.V. + Copyright (C) 2021--2023 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 @@ -146,12 +146,16 @@ on_gnunet_chat_handle_connection_msg(void *cls, ck_assert_ptr_eq(context, NULL); ck_assert_ptr_ne(message, NULL); + if (GNUNET_CHAT_KIND_LOGIN == GNUNET_CHAT_message_get_kind(message)) + goto skip_iteration; + GNUNET_CHAT_iterate_accounts( handle, on_gnunet_chat_handle_connection_it, handle ); +skip_iteration: if (!GNUNET_CHAT_get_connected(handle)) return GNUNET_YES;