commit ba528dd455716f73fbfb3191401b8978e9900453
parent afd5d7cb5fdb8d2cf20f50d3942f553be78ca0ca
Author: TheJackiMonster <thejackimonster@gmail.com>
Date: Sat, 12 Mar 2022 14:38:12 +0100
Implemented lobby functionality and uri solving to add contacts
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
Diffstat:
16 files changed, 857 insertions(+), 112 deletions(-)
diff --git a/Makefile b/Makefile
@@ -14,7 +14,9 @@ SOURCES = gnunet_chat_lib.c\
gnunet_chat_group.c\
gnunet_chat_handle.c\
gnunet_chat_invitation.c\
+ gnunet_chat_lobby.c\
gnunet_chat_message.c\
+ gnunet_chat_uri.c\
gnunet_chat_util.c
HEADERS = gnunet_chat_lib.h
@@ -24,6 +26,7 @@ TESTS = test_gnunet_chat_handle.c
LIBRARIES = gnunetarm\
gnunetfs\
gnunetidentity\
+ gnunetgns\
gnunetmessenger\
gnunetnamestore\
gnunetregex\
diff --git a/include/gnunet_chat_lib.h b/include/gnunet_chat_lib.h
@@ -39,6 +39,8 @@
#include <gnunet/gnunet_time_lib.h>
#include <gnunet/gnunet_util_lib.h>
+#define GNUNET_CHAT_URI_PREFIX "gnunet://chat/"
+
/**
* Enum for the different kinds of messages.
*/
@@ -172,7 +174,7 @@ typedef int
* Method called when a lobby is opened to share with others via a chat URI.
*
* @param[in,out] cls Closure from #GNUNET_CHAT_lobby_open
- * @param[in] uri Chat URI of the lobby
+ * @param[in] uri Chat URI of the lobby or NULL on error
*/
typedef void
(*GNUNET_CHAT_LobbyCallback) (void *cls,
diff --git a/src/gnunet_chat_context.c b/src/gnunet_chat_context.c
@@ -329,27 +329,8 @@ context_write_records (struct GNUNET_CHAT_Context *context)
count++;
}
- const char *type_string = "chat";
-
- switch (context->type)
- {
- case GNUNET_CHAT_CONTEXT_TYPE_CONTACT:
- type_string = "contact";
- break;
- case GNUNET_CHAT_CONTEXT_TYPE_GROUP:
- type_string = "group";
- break;
- default:
- break;
- }
-
char *label;
- GNUNET_asprintf (
- &label,
- "%s_%s",
- type_string,
- GNUNET_h2s(hash)
- );
+ util_get_context_label(context->type, hash, &label);
printf("WRITE: %s -> %u (%s, %s)\n", label, count, nick, topic);
diff --git a/src/gnunet_chat_context.h b/src/gnunet_chat_context.h
@@ -33,12 +33,7 @@
#include <gnunet/gnunet_messenger_service.h>
#include <gnunet/gnunet_util_lib.h>
-enum GNUNET_CHAT_ContextType
-{
- GNUNET_CHAT_CONTEXT_TYPE_CONTACT = 1,
- GNUNET_CHAT_CONTEXT_TYPE_GROUP = 2,
- GNUNET_CHAT_CONTEXT_TYPE_UNKNOWN = 0
-};
+#include "gnunet_chat_util.h"
struct GNUNET_CHAT_Handle;
diff --git a/src/gnunet_chat_handle.c b/src/gnunet_chat_handle.c
@@ -60,6 +60,12 @@ handle_create_from_config (const struct GNUNET_CONFIGURATION_Handle* cfg,
handle->creation_op = NULL;
handle->monitor = NULL;
+ handle->lobbies_head = NULL;
+ handle->lobbies_tail = NULL;
+
+ handle->lobbies_head = NULL;
+ handle->lobbies_tail = NULL;
+
handle->files = NULL;
handle->contexts = NULL;
handle->contacts = NULL;
@@ -84,6 +90,7 @@ handle_create_from_config (const struct GNUNET_CONFIGURATION_Handle* cfg,
);
handle->fs = NULL;
+ handle->gns = NULL;
handle->messenger = NULL;
handle->public_key = NULL;
@@ -218,6 +225,8 @@ handle_connect (struct GNUNET_CHAT_Handle *handle,
GNUNET_free(fs_client_name);
+ handle->gns = GNUNET_GNS_connect(handle->cfg);
+
handle->messenger = GNUNET_MESSENGER_connect(
handle->cfg, name,
on_handle_identity, handle,
@@ -250,18 +259,76 @@ handle_disconnect (struct GNUNET_CHAT_Handle *handle)
handle->contexts, it_destroy_handle_contexts, NULL
);
+ struct GNUNET_CHAT_InternalMessages *internal;
+ while (handle->internal_head)
+ {
+ internal = handle->internal_head;
+
+ if ((internal->msg) && (internal->msg->context))
+ message_destroy(internal->msg);
+
+ GNUNET_CONTAINER_DLL_remove(
+ handle->internal_head,
+ handle->internal_tail,
+ internal
+ );
+
+ GNUNET_free(internal);
+ }
+
if (handle->messenger)
GNUNET_MESSENGER_disconnect(handle->messenger);
+ if (handle->gns)
+ GNUNET_GNS_disconnect(handle->gns);
+
if (handle->fs)
GNUNET_FS_stop(handle->fs);
+ handle->fs = NULL;
+ handle->gns = NULL;
+ handle->messenger = NULL;
+
GNUNET_CONTAINER_multihashmap_iterate(
handle->files, it_destroy_handle_files, NULL
);
- handle->fs = NULL;
- handle->messenger = NULL;
+ struct GNUNET_CHAT_InternalLobbies *lobbies;
+ while (handle->lobbies_head)
+ {
+ lobbies = handle->lobbies_head;
+
+ if (lobbies->lobby)
+ lobby_destroy(lobbies->lobby);
+
+ GNUNET_CONTAINER_DLL_remove(
+ handle->lobbies_head,
+ handle->lobbies_tail,
+ lobbies
+ );
+
+ GNUNET_free(lobbies);
+ }
+
+ struct GNUNET_CHAT_UriLookups *lookups;
+ while (handle->lookups_head)
+ {
+ lookups = handle->lookups_head;
+
+ if (lookups->request)
+ GNUNET_GNS_lookup_cancel(lookups->request);
+
+ if (lookups->uri)
+ uri_destroy(lookups->uri);
+
+ GNUNET_CONTAINER_DLL_remove(
+ handle->lookups_head,
+ handle->lookups_tail,
+ lookups
+ );
+
+ GNUNET_free(lookups);
+ }
GNUNET_CONTAINER_multihashmap_destroy(handle->groups);
GNUNET_CONTAINER_multishortmap_destroy(handle->contacts);
@@ -493,3 +560,87 @@ handle_get_group_from_messenger (const struct GNUNET_CHAT_Handle *handle,
handle->groups, key
);
}
+
+struct GNUNET_CHAT_Context*
+handle_process_records (struct GNUNET_CHAT_Handle *handle,
+ const char *label,
+ unsigned int count,
+ const struct GNUNET_GNSRECORD_Data *data)
+{
+ GNUNET_assert((handle) && (data));
+
+ if (count <= 0)
+ return NULL;
+
+ const struct GNUNET_MESSENGER_RoomEntryRecord *record = NULL;
+
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (GNUNET_YES == GNUNET_GNSRECORD_is_expired(data + i))
+ continue;
+
+ if ((GNUNET_GNSRECORD_TYPE_MESSENGER_ROOM_ENTRY == data[i].record_type) &&
+ (!(GNUNET_GNSRECORD_RF_SUPPLEMENTAL & data[i].flags)))
+ {
+ record = data[i].data;
+ break;
+ }
+ }
+
+ if (!record)
+ return NULL;
+
+ struct GNUNET_CHAT_Context *context = GNUNET_CONTAINER_multihashmap_get(
+ handle->contexts,
+ &(record->key)
+ );
+
+ if (context)
+ {
+ context_read_records(context, label, count, data);
+
+ printf("PATCH: %s %u %d %s\n", label, count, (int) context->type, context->topic);
+
+ return NULL;
+ }
+
+ struct GNUNET_MESSENGER_Room *room = GNUNET_MESSENGER_enter_room(
+ handle->messenger,
+ &(record->door),
+ &(record->key)
+ );
+
+ if (!room)
+ return NULL;
+
+ context = context_create_from_room(handle, room);
+ context_read_records(context, label, count, data);
+
+ printf("READ: %s %u %d %s\n", label, count, (int) context->type, context->topic);
+
+ handle_send_room_name(handle, room);
+
+ if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put(
+ handle->contexts, &(record->key), context,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ {
+ context_destroy(context);
+ GNUNET_MESSENGER_close_room(room);
+ return NULL;
+ }
+
+ if (GNUNET_CHAT_CONTEXT_TYPE_GROUP != context->type)
+ return context;
+
+ struct GNUNET_CHAT_Group *group = group_create_from_context(handle, context);
+
+ if (context->topic)
+ group_publish(group);
+
+ if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put(
+ handle->groups, &(record->key), group,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ group_destroy(group);
+
+ return context;
+}
diff --git a/src/gnunet_chat_handle.h b/src/gnunet_chat_handle.h
@@ -31,6 +31,7 @@
#include <gnunet/gnunet_container_lib.h>
#include <gnunet/gnunet_arm_service.h>
#include <gnunet/gnunet_fs_service.h>
+#include <gnunet/gnunet_gns_service.h>
#include <gnunet/gnunet_identity_service.h>
#include <gnunet/gnunet_messenger_service.h>
#include <gnunet/gnunet_namestore_service.h>
@@ -39,7 +40,11 @@
#include "gnunet_chat_lib.h"
#include "gnunet_chat_account.h"
+#include "gnunet_chat_lobby.h"
#include "gnunet_chat_message.h"
+#include "gnunet_chat_uri.h"
+
+struct GNUNET_CHAT_Handle;
struct GNUNET_CHAT_InternalMessages
{
@@ -55,6 +60,24 @@ struct GNUNET_CHAT_InternalAccounts
struct GNUNET_CHAT_InternalAccounts *prev;
};
+struct GNUNET_CHAT_InternalLobbies
+{
+ struct GNUNET_CHAT_Lobby *lobby;
+ struct GNUNET_CHAT_InternalLobbies *next;
+ struct GNUNET_CHAT_InternalLobbies *prev;
+};
+
+struct GNUNET_CHAT_UriLookups
+{
+ struct GNUNET_CHAT_Handle *handle;
+
+ struct GNUNET_GNS_LookupRequest *request;
+ struct GNUNET_CHAT_Uri *uri;
+
+ struct GNUNET_CHAT_UriLookups *next;
+ struct GNUNET_CHAT_UriLookups *prev;
+};
+
struct GNUNET_CHAT_Handle
{
const struct GNUNET_CONFIGURATION_Handle* cfg;
@@ -75,6 +98,12 @@ struct GNUNET_CHAT_Handle
struct GNUNET_IDENTITY_Operation *creation_op;
struct GNUNET_NAMESTORE_ZoneMonitor *monitor;
+ struct GNUNET_CHAT_InternalLobbies *lobbies_head;
+ struct GNUNET_CHAT_InternalLobbies *lobbies_tail;
+
+ struct GNUNET_CHAT_UriLookups *lookups_head;
+ struct GNUNET_CHAT_UriLookups *lookups_tail;
+
struct GNUNET_CONTAINER_MultiHashMap *files;
struct GNUNET_CONTAINER_MultiHashMap *contexts;
struct GNUNET_CONTAINER_MultiShortmap *contacts;
@@ -82,6 +111,7 @@ struct GNUNET_CHAT_Handle
struct GNUNET_ARM_Handle *arm;
struct GNUNET_FS_Handle *fs;
+ struct GNUNET_GNS_Handle *gns;
struct GNUNET_IDENTITY_Handle *identity;
struct GNUNET_MESSENGER_Handle *messenger;
struct GNUNET_NAMESTORE_Handle *namestore;
@@ -137,4 +167,10 @@ struct GNUNET_CHAT_Group*
handle_get_group_from_messenger (const struct GNUNET_CHAT_Handle *handle,
const struct GNUNET_MESSENGER_Room *room);
+struct GNUNET_CHAT_Context*
+handle_process_records (struct GNUNET_CHAT_Handle *handle,
+ const char *label,
+ unsigned int count,
+ const struct GNUNET_GNSRECORD_Data *data);
+
#endif /* GNUNET_CHAT_HANDLE_H_ */
diff --git a/src/gnunet_chat_handle_intern.c b/src/gnunet_chat_handle_intern.c
@@ -374,79 +374,8 @@ on_monitor_namestore_record(void *cls,
{
struct GNUNET_CHAT_Handle *chat = cls;
- if (count <= 0)
- goto skip_records;
+ handle_process_records(chat, label, count, data);
- const struct GNUNET_MESSENGER_RoomEntryRecord *record = NULL;
-
- for (unsigned int i = 0; i < count; i++)
- {
- if (GNUNET_YES == GNUNET_GNSRECORD_is_expired(data + i))
- continue;
-
- if ((GNUNET_GNSRECORD_TYPE_MESSENGER_ROOM_ENTRY == data[i].record_type) &&
- (!(GNUNET_GNSRECORD_RF_SUPPLEMENTAL & data[i].flags)))
- {
- record = data[i].data;
- break;
- }
- }
-
- if (!record)
- goto skip_records;
-
- struct GNUNET_CHAT_Context *context = GNUNET_CONTAINER_multihashmap_get(
- chat->contexts,
- &(record->key)
- );
-
- if (context)
- {
- context_read_records(context, label, count, data);
-
- printf("PATCH: %s %u %d %s\n", label, count, (int) context->type, context->topic);
-
- goto skip_records;
- }
-
- struct GNUNET_MESSENGER_Room *room = GNUNET_MESSENGER_enter_room(
- chat->messenger,
- &(record->door),
- &(record->key)
- );
-
- if (!room)
- goto skip_records;
-
- context = context_create_from_room(chat, room);
- context_read_records(context, label, count, data);
-
- printf("READ: %s %u %d %s\n", label, count, (int) context->type, context->topic);
-
- handle_send_room_name(chat, room);
-
- if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put(
- chat->contexts, &(record->key), context,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
- {
- context_destroy(context);
- goto skip_records;
- }
-
- if (GNUNET_CHAT_CONTEXT_TYPE_GROUP != context->type)
- goto skip_records;
-
- struct GNUNET_CHAT_Group *group = group_create_from_context(chat, context);
-
- if (context->topic)
- group_publish(group);
-
- if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put(
- chat->groups, &(record->key), group,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
- group_destroy(group);
-
-skip_records:
if (chat->monitor)
GNUNET_NAMESTORE_zone_monitor_next(chat->monitor, 1);
}
@@ -471,8 +400,6 @@ on_handle_identity(void *cls,
GNUNET_assert(handle->messenger);
- printf("HURRAY!\n");
-
handle_send_internal_message(
handle,
NULL,
diff --git a/src/gnunet_chat_lib.c b/src/gnunet_chat_lib.c
@@ -32,7 +32,9 @@
#include "gnunet_chat_group.h"
#include "gnunet_chat_handle.h"
#include "gnunet_chat_invitation.h"
+#include "gnunet_chat_lobby.h"
#include "gnunet_chat_message.h"
+
#include "gnunet_chat_util.h"
#include "gnunet_chat_lib_intern.c"
@@ -215,9 +217,44 @@ GNUNET_CHAT_uri_parse (const char *uri,
if (!uri)
return NULL;
- // TODO
+ const size_t prefix_len = strlen(GNUNET_CHAT_URI_PREFIX);
- return NULL;
+ if (0 != strncmp(GNUNET_CHAT_URI_PREFIX, uri, prefix_len))
+ {
+ if (emsg)
+ *emsg = GNUNET_strdup (_ ("CHAT URI malformed (invalid prefix)"));
+
+ return NULL;
+ }
+
+ struct GNUNET_IDENTITY_PublicKey zone;
+
+ const char *data = uri + prefix_len;
+ char *end = strchr(data, '.');
+
+ if (!end)
+ {
+ if (emsg)
+ *emsg = GNUNET_strdup (_ ("CHAT URI malformed (zone key missing)"));
+
+ return NULL;
+ }
+
+ char *zone_data = GNUNET_strndup(data, (size_t) (end - data));
+
+ if (GNUNET_OK != GNUNET_IDENTITY_public_key_from_string(zone_data, &zone))
+ {
+ GNUNET_free(zone_data);
+
+ if (emsg)
+ *emsg = GNUNET_strdup (_ ("CHAT URI malformed (zone key invalid)"));
+
+ return NULL;
+ }
+
+ GNUNET_free(zone_data);
+
+ return uri_create(&zone, end + 1);
}
@@ -227,9 +264,18 @@ GNUNET_CHAT_uri_to_string (const struct GNUNET_CHAT_Uri *uri)
if (!uri)
return NULL;
- // TODO
+ char *key_string = GNUNET_IDENTITY_public_key_to_string(&(uri->zone));
- return NULL;
+ char *string;
+ GNUNET_asprintf(
+ &string,
+ "gnunet://chat/%s.%s",
+ key_string,
+ uri->label
+ );
+
+ GNUNET_free(key_string);
+ return string;
}
@@ -239,7 +285,7 @@ GNUNET_CHAT_uri_destroy (struct GNUNET_CHAT_Uri *uri)
if (!uri)
return;
- GNUNET_free(uri);
+ uri_destroy(uri);
}
@@ -249,16 +295,53 @@ GNUNET_CHAT_lobby_open (struct GNUNET_CHAT_Handle *handle,
GNUNET_CHAT_LobbyCallback callback,
void *cls)
{
- // TODO
+ if (!handle)
+ return NULL;
- return NULL;
+ struct GNUNET_CHAT_InternalLobbies *lobbies = GNUNET_new(
+ struct GNUNET_CHAT_InternalLobbies
+ );
+
+ lobbies->lobby = lobby_create(handle);
+
+ GNUNET_CONTAINER_DLL_insert(
+ handle->lobbies_head,
+ handle->lobbies_tail,
+ lobbies
+ );
+
+ lobby_open(lobbies->lobby, delay, callback, cls);
+
+ return lobbies->lobby;
}
void
GNUNET_CHAT_lobby_close (struct GNUNET_CHAT_Lobby *lobby)
{
- // TODO
+ if (!lobby)
+ return;
+
+ struct GNUNET_CHAT_InternalLobbies *lobbies = lobby->handle->lobbies_head;
+
+ while (lobbies)
+ {
+ if (lobbies->lobby == lobby)
+ {
+ GNUNET_CONTAINER_DLL_remove(
+ lobby->handle->lobbies_head,
+ lobby->handle->lobbies_tail,
+ lobbies
+ );
+
+ GNUNET_free(lobbies);
+ break;
+ }
+
+ lobbies = lobbies->next;
+ }
+
+ lobby_destroy(lobby);
}
@@ -266,7 +349,31 @@ void
GNUNET_CHAT_lobby_join (struct GNUNET_CHAT_Handle *handle,
const struct GNUNET_CHAT_Uri *uri)
{
- // TODO
+ if ((!handle) || (!uri) || (!(handle->gns)))
+ return;
+
+ struct GNUNET_CHAT_UriLookups *lookups = GNUNET_new(
+ struct GNUNET_CHAT_UriLookups
+ );
+
+ lookups->handle = handle;
+ lookups->uri = uri_create(&(uri->zone), uri->label);
+
+ lookups->request = GNUNET_GNS_lookup(
+ handle->gns,
+ lookups->uri->label,
+ &(uri->zone),
+ GNUNET_GNSRECORD_TYPE_MESSENGER_ROOM_ENTRY,
+ GNUNET_GNS_LO_DEFAULT,
+ cb_lobby_lookup,
+ lookups
+ );
+
+ GNUNET_CONTAINER_DLL_insert(
+ handle->lookups_head,
+ handle->lookups_tail,
+ lookups
+ );
}
diff --git a/src/gnunet_chat_lib_intern.c b/src/gnunet_chat_lib_intern.c
@@ -41,6 +41,45 @@ cb_account_creation (void *cls,
handle_send_internal_message(handle, NULL, GNUNET_CHAT_FLAG_REFRESH, NULL);
}
+void
+cb_lobby_lookup (void *cls,
+ uint32_t count,
+ const struct GNUNET_GNSRECORD_Data *data)
+{
+ GNUNET_assert(cls);
+
+ struct GNUNET_CHAT_UriLookups *lookups = (struct GNUNET_CHAT_UriLookups*) cls;
+
+ if ((!(lookups->handle)) || (!(lookups->uri)))
+ goto drop_lookup;
+
+ struct GNUNET_CHAT_Context *context = handle_process_records(
+ lookups->handle,
+ lookups->uri->label,
+ count,
+ data
+ );
+
+ if (context)
+ context_write_records(context);
+
+drop_lookup:
+ if (lookups->request)
+ GNUNET_GNS_lookup_cancel(lookups->request);
+
+ if (lookups->uri)
+ uri_destroy(lookups->uri);
+
+ if (lookups->handle)
+ GNUNET_CONTAINER_DLL_remove(
+ lookups->handle->lookups_head,
+ lookups->handle->lookups_tail,
+ lookups
+ );
+
+ GNUNET_free(lookups);
+}
+
struct GNUNET_CHAT_HandleIterateContacts
{
struct GNUNET_CHAT_Handle *handle;
diff --git a/src/gnunet_chat_lobby.c b/src/gnunet_chat_lobby.c
@@ -0,0 +1,130 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2022 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_lobby.c
+ */
+
+#include "gnunet_chat_lobby.h"
+
+#include "gnunet_chat_handle.h"
+#include "gnunet_chat_lobby_intern.c"
+
+struct GNUNET_CHAT_Lobby*
+lobby_create (struct GNUNET_CHAT_Handle *handle)
+{
+ GNUNET_assert(handle);
+
+ struct GNUNET_CHAT_Lobby *lobby = GNUNET_new(struct GNUNET_CHAT_Lobby);
+
+ lobby->handle = handle;
+ lobby->context = NULL;
+ lobby->uri = NULL;
+
+ lobby->op_create = NULL;
+ lobby->op_delete = NULL;
+
+ lobby->expiration = GNUNET_TIME_absolute_get_forever_();
+ lobby->callback = NULL;
+ lobby->cls = NULL;
+
+ return lobby;
+}
+
+void
+lobby_destroy (struct GNUNET_CHAT_Lobby *lobby)
+{
+ GNUNET_assert(lobby);
+
+ if (lobby->op_create)
+ GNUNET_IDENTITY_cancel(lobby->op_create);
+
+ if (lobby->op_delete)
+ GNUNET_IDENTITY_cancel(lobby->op_delete);
+
+ if (lobby->uri)
+ uri_destroy(lobby->uri);
+
+ if (lobby->context)
+ context_destroy(lobby->context);
+
+ GNUNET_free(lobby);
+}
+
+void
+lobby_open (struct GNUNET_CHAT_Lobby *lobby,
+ struct GNUNET_TIME_Relative delay,
+ GNUNET_CHAT_LobbyCallback callback,
+ void *cls)
+{
+ GNUNET_assert(lobby);
+
+ char *name;
+
+ lobby->expiration = GNUNET_TIME_relative_to_absolute(delay);
+ lobby->callback = callback;
+ lobby->cls = cls;
+
+ if (lobby->op_create)
+ {
+ GNUNET_IDENTITY_cancel(lobby->op_create);
+ goto open_zone;
+ }
+
+ struct GNUNET_HashCode key;
+ GNUNET_CRYPTO_random_block(GNUNET_CRYPTO_QUALITY_WEAK, &key, sizeof(key));
+
+ struct GNUNET_MESSENGER_Room *room = GNUNET_MESSENGER_open_room(
+ lobby->handle->messenger,
+ &key
+ );
+
+ if (!room)
+ return;
+
+ lobby->context = context_create_from_room(lobby->handle, room);
+
+ handle_send_room_name(lobby->handle, room);
+
+ if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put(
+ lobby->handle->contexts, &key, lobby->context,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ {
+ context_destroy(lobby->context);
+ lobby->context = NULL;
+
+ GNUNET_MESSENGER_close_room(room);
+ return;
+ }
+
+open_zone:
+ util_lobby_name(&key, &name);
+
+ lobby->op_create = GNUNET_IDENTITY_create(
+ lobby->handle->identity,
+ name,
+ NULL,
+ GNUNET_IDENTITY_TYPE_EDDSA,
+ cont_lobby_identity_create,
+ lobby
+ );
+
+ GNUNET_free(name);
+}
diff --git a/src/gnunet_chat_lobby.h b/src/gnunet_chat_lobby.h
@@ -0,0 +1,66 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2022 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_lobby.h
+ */
+
+#ifndef GNUNET_CHAT_LOBBY_H_
+#define GNUNET_CHAT_LOBBY_H_
+
+#include <gnunet/platform.h>
+#include <gnunet/gnunet_common.h>
+#include <gnunet/gnunet_identity_service.h>
+#include <gnunet/gnunet_util_lib.h>
+
+#include "gnunet_chat_lib.h"
+
+struct GNUNET_CHAT_Handle;
+struct GNUNET_CHAT_Context;
+struct GNUNET_CHAT_Uri;
+
+struct GNUNET_CHAT_Lobby
+{
+ struct GNUNET_CHAT_Handle *handle;
+
+ struct GNUNET_CHAT_Context *context;
+ struct GNUNET_CHAT_Uri *uri;
+
+ struct GNUNET_IDENTITY_Operation *op_create;
+ struct GNUNET_IDENTITY_Operation *op_delete;
+
+ struct GNUNET_TIME_Absolute expiration;
+ GNUNET_CHAT_LobbyCallback callback;
+ void *cls;
+};
+
+struct GNUNET_CHAT_Lobby*
+lobby_create (struct GNUNET_CHAT_Handle *handle);
+
+void
+lobby_destroy (struct GNUNET_CHAT_Lobby *lobby);
+
+void
+lobby_open (struct GNUNET_CHAT_Lobby *lobby,
+ struct GNUNET_TIME_Relative delay,
+ GNUNET_CHAT_LobbyCallback callback,
+ void *cls);
+
+#endif /* GNUNET_CHAT_LOBBY_H_ */
diff --git a/src/gnunet_chat_lobby_intern.c b/src/gnunet_chat_lobby_intern.c
@@ -0,0 +1,157 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2022 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_lobby_intern.c
+ */
+
+#include "gnunet_chat_context.h"
+
+void
+cont_lobby_write_records (void *cls,
+ GNUNET_UNUSED int32_t success,
+ const char *emsg)
+{
+ struct GNUNET_CHAT_Lobby *lobby = cls;
+
+ if (!emsg)
+ goto call_cb;
+
+ handle_send_internal_message(
+ lobby->handle,
+ lobby->context,
+ GNUNET_CHAT_FLAG_WARNING,
+ emsg
+ );
+
+ if (lobby->uri)
+ uri_destroy(lobby->uri);
+
+ lobby->uri = NULL;
+
+call_cb:
+ if (lobby->callback)
+ lobby->callback(lobby->cls, lobby->uri);
+}
+
+void
+cont_lobby_identity_delete (void *cls,
+ const char *emsg)
+{
+ struct GNUNET_CHAT_Lobby *lobby = cls;
+
+ if (!emsg)
+ return;
+
+ handle_send_internal_message(
+ lobby->handle,
+ lobby->context,
+ GNUNET_CHAT_FLAG_WARNING,
+ emsg
+ );
+}
+
+void
+cont_lobby_identity_create (void *cls,
+ const struct GNUNET_IDENTITY_PrivateKey *zone,
+ const char *emsg)
+{
+ struct GNUNET_CHAT_Lobby *lobby = cls;
+
+ char *name;
+
+ if (emsg)
+ {
+ handle_send_internal_message(
+ lobby->handle,
+ NULL,
+ GNUNET_CHAT_FLAG_WARNING,
+ emsg
+ );
+
+ return;
+ }
+
+ struct GNUNET_MESSENGER_Room *room = GNUNET_MESSENGER_open_room(
+ lobby->handle->messenger,
+ NULL
+ );
+
+ if (!room)
+ goto destroy_identity;
+
+ const struct GNUNET_HashCode *key = GNUNET_MESSENGER_room_get_key(room);
+
+ lobby->context = context_create_from_room(lobby->handle, room);
+
+ handle_send_room_name(lobby->handle, room);
+
+ if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put(
+ lobby->handle->contexts, key, lobby->context,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ {
+ context_destroy(lobby->context);
+ lobby->context = NULL;
+ goto destroy_identity;
+ }
+
+ struct GNUNET_GNSRECORD_Data data [3];
+ data[0].record_type = GNUNET_GNSRECORD_TYPE_MESSENGER_ROOM_ENTRY;
+ data[0].data = &room;
+ data[0].data_size = sizeof(room);
+ data[0].expiration_time = lobby->expiration.abs_value_us;
+ data[0].flags = GNUNET_GNSRECORD_RF_NONE;
+
+ if (lobby->uri)
+ uri_destroy(lobby->uri);
+
+ struct GNUNET_IDENTITY_PublicKey public_zone;
+ GNUNET_IDENTITY_key_get_public(zone, &public_zone);
+
+ char *label;
+ util_get_context_label(lobby->context->type, key, &label);
+
+ lobby->uri = uri_create(&public_zone, label);
+ GNUNET_free(label);
+
+ GNUNET_NAMESTORE_records_store(
+ lobby->handle->namestore,
+ zone,
+ lobby->uri->label,
+ 1,
+ data,
+ cont_lobby_write_records,
+ lobby
+ );
+
+ context_write_records(lobby->context);
+
+destroy_identity:
+ util_lobby_name(key, &name);
+
+ lobby->op_delete = GNUNET_IDENTITY_delete(
+ lobby->handle->identity,
+ name,
+ cont_lobby_identity_delete,
+ lobby
+ );
+
+ GNUNET_free(name);
+}
diff --git a/src/gnunet_chat_uri.c b/src/gnunet_chat_uri.c
@@ -0,0 +1,51 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2022 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_uri.c
+ */
+
+#include "gnunet_chat_uri.h"
+
+struct GNUNET_CHAT_Uri*
+uri_create (const struct GNUNET_IDENTITY_PublicKey *zone,
+ const char *label)
+{
+ GNUNET_assert((zone) && (label));
+
+ struct GNUNET_CHAT_Uri *uri = GNUNET_new(struct GNUNET_CHAT_Uri);
+
+ GNUNET_memcpy(&(uri->zone), zone, sizeof(uri->zone));
+
+ uri->label = GNUNET_strdup(label);
+
+ return uri;
+}
+
+void
+uri_destroy (struct GNUNET_CHAT_Uri *uri)
+{
+ GNUNET_assert(uri);
+
+ if (uri->label)
+ GNUNET_free(uri->label);
+
+ GNUNET_free(uri);
+}
diff --git a/src/gnunet_chat_uri.h b/src/gnunet_chat_uri.h
@@ -0,0 +1,48 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2022 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_uri.h
+ */
+
+#ifndef GNUNET_CHAT_URI_H_
+#define GNUNET_CHAT_URI_H_
+
+#include <gnunet/platform.h>
+#include <gnunet/gnunet_common.h>
+#include <gnunet/gnunet_identity_service.h>
+#include <gnunet/gnunet_util_lib.h>
+
+#include "gnunet_chat_util.h"
+
+struct GNUNET_CHAT_Uri
+{
+ struct GNUNET_IDENTITY_PublicKey zone;
+ char *label;
+};
+
+struct GNUNET_CHAT_Uri*
+uri_create (const struct GNUNET_IDENTITY_PublicKey *zone,
+ const char *label);
+
+void
+uri_destroy (struct GNUNET_CHAT_Uri *uri);
+
+#endif /* GNUNET_CHAT_URI_H_ */
diff --git a/src/gnunet_chat_util.c b/src/gnunet_chat_util.c
@@ -286,3 +286,40 @@ util_get_filename (const char *directory,
GNUNET_free(dirname);
return result;
}
+
+int
+util_get_context_label (enum GNUNET_CHAT_ContextType type,
+ const struct GNUNET_HashCode *hash,
+ char **label)
+{
+ const char *type_string = "chat";
+
+ switch (type)
+ {
+ case GNUNET_CHAT_CONTEXT_TYPE_CONTACT:
+ type_string = "contact";
+ break;
+ case GNUNET_CHAT_CONTEXT_TYPE_GROUP:
+ type_string = "group";
+ break;
+ default:
+ break;
+ }
+
+ return GNUNET_asprintf (
+ label,
+ "%s_%s",
+ type_string,
+ GNUNET_h2s(hash)
+ );
+}
+
+int util_lobby_name (const struct GNUNET_HashCode *hash,
+ char **name)
+{
+ return GNUNET_asprintf (
+ name,
+ "chat_lobby_%s",
+ GNUNET_h2s(hash)
+ );
+}
diff --git a/src/gnunet_chat_util.h b/src/gnunet_chat_util.h
@@ -32,6 +32,13 @@
#include <gnunet/gnunet_messenger_service.h>
#include <gnunet/gnunet_util_lib.h>
+enum GNUNET_CHAT_ContextType
+{
+ GNUNET_CHAT_CONTEXT_TYPE_CONTACT = 1,
+ GNUNET_CHAT_CONTEXT_TYPE_GROUP = 2,
+ GNUNET_CHAT_CONTEXT_TYPE_UNKNOWN = 0
+};
+
void
util_shorthash_from_member (const struct GNUNET_MESSENGER_Contact *member,
struct GNUNET_ShortHashCode *shorthash);
@@ -63,4 +70,12 @@ util_get_filename (const char *directory,
const struct GNUNET_HashCode *hash,
char **filename);
+int
+util_get_context_label (enum GNUNET_CHAT_ContextType type,
+ const struct GNUNET_HashCode *hash,
+ char **label);
+
+int util_lobby_name (const struct GNUNET_HashCode *hash,
+ char **name);
+
#endif /* GNUNET_CHAT_UTIL_H_ */