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