libgnunetchat

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

commit fba50c0338fb76feec7fee5a12e27fc57df1972b
parent 807dec8e802737fb46d015c48a7859a6ec504f74
Author: TheJackiMonster <thejackimonster@gmail.com>
Date:   Thu, 10 Mar 2022 02:18:22 +0100

Replace local files with namestore usage

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

Diffstat:
MMakefile | 1+
Minclude/gnunet_chat_lib.h | 25+++++++++++++++++++++++++
Msrc/gnunet_chat_context.c | 303+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/gnunet_chat_context.h | 15+++++++++++----
Msrc/gnunet_chat_context_intern.c | 16++++++++++++++++
Msrc/gnunet_chat_group.c | 89+++----------------------------------------------------------------------------
Msrc/gnunet_chat_group.h | 8--------
Msrc/gnunet_chat_handle.c | 41+++++++++++++++++++++++++++++++++++++----
Msrc/gnunet_chat_handle.h | 6++++++
Msrc/gnunet_chat_handle_intern.c | 115++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/gnunet_chat_lib.c | 53++++++++++++++++++++++++++++++++++++++++++++++++-----
11 files changed, 454 insertions(+), 218 deletions(-)

diff --git a/Makefile b/Makefile @@ -25,6 +25,7 @@ LIBRARIES = gnunetarm\ gnunetfs\ gnunetidentity\ gnunetmessenger\ + gnunetnamestore\ gnunetregex\ gnunetutil diff --git a/include/gnunet_chat_lib.h b/include/gnunet_chat_lib.h @@ -781,6 +781,31 @@ GNUNET_CHAT_context_iterate_files (struct GNUNET_CHAT_Context *context, void *cls); /** + * Sets a custom <i>user pointer</i> to a given <i>member</i> relative to a + * <i>context</i> so it can be accessed in member related callbacks. + * + * @param[in,out] context Chat context + * @param[in] member Contact + * @param[in] user_pointer Custom user pointer + */ +void +GNUNET_CHAT_member_set_user_pointer (struct GNUNET_CHAT_Context *context, + const struct GNUNET_CHAT_Contact *member, + void *user_pointer); + +/** + * Returns the custom user pointer of a given <i>contact</i> or NULL if it was + * not set any. + * + * @param[in] context Chat context + * @param[in] member Contact + * @return Custom user pointer or NULL + */ +void* +GNUNET_CHAT_member_get_user_pointer (const struct GNUNET_CHAT_Context *context, + const struct GNUNET_CHAT_Contact *member); + +/** * Returns the kind of a given <i>message</i> to determine its content and * related usage. * diff --git a/src/gnunet_chat_context.c b/src/gnunet_chat_context.c @@ -23,6 +23,7 @@ */ #include "gnunet_chat_context.h" +#include "gnunet_chat_group.h" #include "gnunet_chat_handle.h" #include "gnunet_chat_util.h" @@ -40,6 +41,7 @@ context_create_from_room (struct GNUNET_CHAT_Handle *handle, context->type = GNUNET_CHAT_CONTEXT_TYPE_UNKNOWN; context->nick = NULL; + context->topic = NULL; context->timestamps = GNUNET_CONTAINER_multishortmap_create(8, GNUNET_NO); context->messages = GNUNET_CONTAINER_multihashmap_create(8, GNUNET_NO); @@ -51,6 +53,10 @@ context_create_from_room (struct GNUNET_CHAT_Handle *handle, context->user_pointer = NULL; + context->member_pointers = GNUNET_CONTAINER_multishortmap_create( + 8, GNUNET_NO + ); + return context; } @@ -66,6 +72,7 @@ context_create_from_contact (struct GNUNET_CHAT_Handle *handle, context->type = GNUNET_CHAT_CONTEXT_TYPE_CONTACT; context->nick = NULL; + context->topic = NULL; context->timestamps = GNUNET_CONTAINER_multishortmap_create(4, GNUNET_NO); context->messages = GNUNET_CONTAINER_multihashmap_create(4, GNUNET_NO); @@ -77,6 +84,10 @@ context_create_from_contact (struct GNUNET_CHAT_Handle *handle, context->user_pointer = NULL; + context->member_pointers = GNUNET_CONTAINER_multishortmap_create( + 8, GNUNET_NO + ); + return context; } @@ -101,11 +112,16 @@ context_destroy (struct GNUNET_CHAT_Context *context) context->invites, it_destroy_context_invites, NULL ); + GNUNET_CONTAINER_multishortmap_destroy(context->member_pointers); + GNUNET_CONTAINER_multishortmap_destroy(context->timestamps); GNUNET_CONTAINER_multihashmap_destroy(context->messages); GNUNET_CONTAINER_multihashmap_destroy(context->invites); GNUNET_CONTAINER_multihashmap_destroy(context->files); + if (context->topic) + GNUNET_free(context->topic); + if (context->nick) GNUNET_free(context->nick); @@ -141,6 +157,11 @@ context_update_room (struct GNUNET_CHAT_Context *context, GNUNET_CONTAINER_multihashmap_clear(context->files); context->room = room; + + if (!(context->room)) + return; + + context_write_records(context); } void @@ -163,169 +184,235 @@ context_update_nick (struct GNUNET_CHAT_Context *context, } void -context_load_config (struct GNUNET_CHAT_Context *context) +context_read_records (struct GNUNET_CHAT_Context *context, + const char *label, + unsigned int count, + const struct GNUNET_GNSRECORD_Data *data) { GNUNET_assert((context) && - (context->handle) && - (context->room)); - - const char *directory = handle_get_directory(context->handle); + (context->room)); - if (!directory) - return; + char *nick = NULL; + char *topic = NULL; - const struct GNUNET_HashCode *hash = GNUNET_MESSENGER_room_get_key( - context->room - ); + for (unsigned int i = 0; i < count; i++) + { + if (!(GNUNET_GNSRECORD_RF_SUPPLEMENTAL & data[i].flags)) + continue; - char* filename; - util_get_filename(directory, "chats", hash, &filename); + if (GNUNET_GNSRECORD_TYPE_NICK == data[i].record_type) + { + if (nick) + continue; - if (GNUNET_YES != GNUNET_DISK_file_test(filename)) - goto free_filename; + nick = GNUNET_strndup(data[i].data, data[i].data_size); + } - struct GNUNET_CONFIGURATION_Handle *config = GNUNET_CONFIGURATION_create(); + if (GNUNET_DNSPARSER_TYPE_TXT == data[i].record_type) + { + if (topic) + continue; - if (GNUNET_OK != GNUNET_CONFIGURATION_load(config, filename)) - goto destroy_config; + topic = GNUNET_strndup(data[i].data, data[i].data_size); + } + } - char* name = NULL; + context_update_nick(context, nick); - if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string( - config, "chat", "name", &name)) - context_update_nick(context, name); + if (nick) + GNUNET_free(nick); - if (name) - GNUNET_free(name); + if (topic) + { + struct GNUNET_HashCode topic_hash; + GNUNET_CRYPTO_hash(topic, strlen(topic), &topic_hash); - unsigned long long type_number; + const struct GNUNET_HashCode *hash = GNUNET_MESSENGER_room_get_key( + context->room + ); - if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number( - config, "chat", "type", &type_number)) - switch (type_number) { - case GNUNET_CHAT_CONTEXT_TYPE_CONTACT: - context->type = GNUNET_CHAT_CONTEXT_TYPE_CONTACT; - break; - case GNUNET_CHAT_CONTEXT_TYPE_GROUP: - context->type = GNUNET_CHAT_CONTEXT_TYPE_GROUP; - break; - default: - context->type = GNUNET_CHAT_CONTEXT_TYPE_UNKNOWN; - break; + if (0 != GNUNET_CRYPTO_hash_cmp(&topic_hash, hash)) + { + GNUNET_free(topic); + topic = NULL; } + } -destroy_config: - GNUNET_CONFIGURATION_destroy(config); + util_set_name_field(topic, &(context->topic)); -free_filename: - GNUNET_free(filename); + if (topic) + GNUNET_free(topic); + + if (0 == strncmp(label, "group_", 6)) + context->type = GNUNET_CHAT_CONTEXT_TYPE_GROUP; + else if (0 == strncmp(label, "contact_", 8)) + context->type = GNUNET_CHAT_CONTEXT_TYPE_CONTACT; + else + context->type = GNUNET_CHAT_CONTEXT_TYPE_UNKNOWN; } void -context_save_config (const struct GNUNET_CHAT_Context *context) +context_write_records (struct GNUNET_CHAT_Context *context) { GNUNET_assert((context) && - (context->handle) && - (context->room)); + (context->handle) && + (context->room)); - const char *directory = handle_get_directory(context->handle); + const struct GNUNET_IDENTITY_PrivateKey *zone = handle_get_key( + context->handle + ); - if (!directory) + if (!zone) return; - const struct GNUNET_HashCode *key = GNUNET_MESSENGER_room_get_key( + const struct GNUNET_HashCode *hash = GNUNET_MESSENGER_room_get_key( context->room ); - struct GNUNET_CONFIGURATION_Handle *config = GNUNET_CONFIGURATION_create(); + struct GNUNET_TIME_Absolute expiration = GNUNET_TIME_absolute_get_forever_(); - if (context->room) - GNUNET_CONFIGURATION_set_value_string( - config, "chat", "key", GNUNET_h2s_full(key) - ); - - if (context->nick) - GNUNET_CONFIGURATION_set_value_string( - config, "chat", "name", context->nick - ); + struct GNUNET_MESSENGER_RoomEntryRecord room; + GNUNET_CRYPTO_get_peer_identity(context->handle->cfg, &(room.door)); - if (GNUNET_CHAT_CONTEXT_TYPE_UNKNOWN != context->type) - GNUNET_CONFIGURATION_set_value_number( - config, "chat", "type", context->type - ); + GNUNET_memcpy( + &(room.key), + hash, + sizeof(room.key) + ); - char* filename; - util_get_filename(directory, "chats", key, &filename); + const char *nick = context->nick; + const char *topic = context->topic; - if (GNUNET_OK == GNUNET_DISK_directory_create_for_file(filename)) - GNUNET_CONFIGURATION_write(config, filename); + if (topic) + { + struct GNUNET_HashCode topic_hash; + GNUNET_CRYPTO_hash(topic, strlen(topic), &topic_hash); - GNUNET_CONFIGURATION_destroy(config); + if (0 != GNUNET_CRYPTO_hash_cmp(&topic_hash, hash)) + topic = NULL; + } - GNUNET_free(filename); -} + unsigned int count = 1; -enum GNUNET_GenericReturnValue -callback_scan_for_configs (void *cls, - const char *filename) -{ - struct GNUNET_CHAT_Handle *handle = (struct GNUNET_CHAT_Handle*) cls; - struct GNUNET_PeerIdentity door; - struct GNUNET_HashCode key; + 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 = expiration.abs_value_us; + data[0].flags = GNUNET_GNSRECORD_RF_PRIVATE; - memset(&door, 0, sizeof(door)); - memset(&key, 0, sizeof(key)); + if (nick) + { + data[count].record_type = GNUNET_GNSRECORD_TYPE_NICK; + data[count].data = nick; + data[count].data_size = strlen(nick); + data[count].expiration_time = expiration.abs_value_us; + data[count].flags = ( + GNUNET_GNSRECORD_RF_PRIVATE | + GNUNET_GNSRECORD_RF_SUPPLEMENTAL + ); - if ((!filename) || - (GNUNET_OK != GNUNET_CRYPTO_get_peer_identity(handle->cfg, &door))) - return GNUNET_YES; + count++; + } - struct GNUNET_CONFIGURATION_Handle *config = GNUNET_CONFIGURATION_create(); + if (topic) + { + data[count].record_type = GNUNET_DNSPARSER_TYPE_TXT; + data[count].data = topic; + data[count].data_size = strlen(topic); + data[count].expiration_time = expiration.abs_value_us; + data[count].flags = ( + GNUNET_GNSRECORD_RF_PRIVATE | + GNUNET_GNSRECORD_RF_SUPPLEMENTAL + ); - if (GNUNET_OK != GNUNET_CONFIGURATION_load(config, filename)) - goto destroy_config; + count++; + } - char* key_value = NULL; + const char *type_string = "chat"; - if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_string( - config, "chat", "key", &key_value)) && - (GNUNET_OK == GNUNET_CRYPTO_hash_from_string(key_value, &key))) + switch (context->type) { - handle_send_room_name(handle, GNUNET_MESSENGER_enter_room( - handle->messenger, &door, &key - )); + case GNUNET_CHAT_CONTEXT_TYPE_CONTACT: + type_string = "contact"; + break; + case GNUNET_CHAT_CONTEXT_TYPE_GROUP: + type_string = "group"; + break; + default: + break; } - if (key_value) - GNUNET_free(key_value); + char *label; + GNUNET_asprintf ( + &label, + "%s_%s", + type_string, + GNUNET_h2s(hash) + ); + + GNUNET_NAMESTORE_records_store( + context->handle->namestore, + zone, + label, + count, + data, + cont_context_write_records, + context + ); -destroy_config: - GNUNET_CONFIGURATION_destroy(config); - return GNUNET_YES; + GNUNET_free(label); } void -context_scan_configs (struct GNUNET_CHAT_Handle *handle) +context_delete_records (struct GNUNET_CHAT_Context *context) { - GNUNET_assert((handle) && (handle->messenger)); + GNUNET_assert((context) && + (context->handle) && + (context->room)); - const char *directory = handle_get_directory(handle); + const struct GNUNET_IDENTITY_PrivateKey *zone = handle_get_key( + context->handle + ); - if (!directory) + if (!zone) return; - char* dirname; - util_get_dirname(directory, "chats", &dirname); + const struct GNUNET_HashCode *hash = GNUNET_MESSENGER_room_get_key( + context->room + ); - if (GNUNET_YES != GNUNET_DISK_directory_test(dirname, GNUNET_YES)) - goto free_dirname; + 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) + ); - GNUNET_DISK_directory_scan( - dirname, - callback_scan_for_configs, - handle + GNUNET_NAMESTORE_records_store( + context->handle->namestore, + zone, + label, + 0, + NULL, + cont_context_write_records, + context ); -free_dirname: - GNUNET_free(dirname); + GNUNET_free(label); } diff --git a/src/gnunet_chat_context.h b/src/gnunet_chat_context.h @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2021 GNUnet e.V. + Copyright (C) 2021--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 @@ -29,6 +29,7 @@ #include <gnunet/gnunet_common.h> #include <gnunet/gnunet_configuration_lib.h> #include <gnunet/gnunet_container_lib.h> +#include <gnunet/gnunet_gnsrecord_lib.h> #include <gnunet/gnunet_messenger_service.h> #include <gnunet/gnunet_util_lib.h> @@ -47,6 +48,7 @@ struct GNUNET_CHAT_Context enum GNUNET_CHAT_ContextType type; char *nick; + char *topic; struct GNUNET_CONTAINER_MultiShortmap *timestamps; struct GNUNET_CONTAINER_MultiHashMap *messages; @@ -57,6 +59,8 @@ struct GNUNET_CHAT_Context const struct GNUNET_MESSENGER_Contact *contact; void *user_pointer; + + struct GNUNET_CONTAINER_MultiShortmap *member_pointers; }; struct GNUNET_CHAT_Context* @@ -79,12 +83,15 @@ context_update_nick (struct GNUNET_CHAT_Context *context, const char *nick); void -context_load_config (struct GNUNET_CHAT_Context *context); +context_read_records (struct GNUNET_CHAT_Context *context, + const char *label, + unsigned int count, + const struct GNUNET_GNSRECORD_Data *data); void -context_save_config (const struct GNUNET_CHAT_Context *context); +context_write_records (struct GNUNET_CHAT_Context *context); void -context_scan_configs (struct GNUNET_CHAT_Handle *handle); +context_delete_records (struct GNUNET_CHAT_Context *context); #endif /* GNUNET_CHAT_CONTEXT_H_ */ diff --git a/src/gnunet_chat_context_intern.c b/src/gnunet_chat_context_intern.c @@ -62,3 +62,19 @@ it_destroy_context_invites (GNUNET_UNUSED void *cls, invitation_destroy(invitation); return GNUNET_YES; } + +void +cont_context_write_records (void *cls, + GNUNET_UNUSED int32_t success, + const char *emsg) +{ + struct GNUNET_CHAT_Context *context = cls; + + if (emsg) + handle_send_internal_message( + context->handle, + context, + GNUNET_CHAT_FLAG_WARNING, + emsg + ); +} diff --git a/src/gnunet_chat_group.c b/src/gnunet_chat_group.c @@ -38,8 +38,6 @@ group_create_from_context (struct GNUNET_CHAT_Handle *handle, group->handle = handle; group->context = context; - group->topic = NULL; - group->announcement = NULL; group->search = NULL; @@ -64,9 +62,6 @@ group_destroy (struct GNUNET_CHAT_Group* group) if (group->announcement) GNUNET_REGEX_announce_cancel(group->announcement); - if (group->topic) - GNUNET_free(group->topic); - GNUNET_free(group); } @@ -74,7 +69,8 @@ void group_publish (struct GNUNET_CHAT_Group* group) { GNUNET_assert((group) && - (group->topic) && + (group->context) && + (group->context->topic) && (group->handle) && (group->handle->cfg)); @@ -82,7 +78,7 @@ group_publish (struct GNUNET_CHAT_Group* group) GNUNET_asprintf ( &topic, "GNUNET_CHAT_%s", - group->topic + group->context->topic ); group->announcement = GNUNET_REGEX_announce( @@ -98,82 +94,3 @@ group_publish (struct GNUNET_CHAT_Group* group) GNUNET_free(topic); } - -void -group_load_config (struct GNUNET_CHAT_Group *group) -{ - GNUNET_assert((group) && (group->handle)); - - const char *directory = handle_get_directory(group->handle); - - if ((!directory) || (!(group->context))) - return; - - const struct GNUNET_HashCode *key = GNUNET_MESSENGER_room_get_key( - group->context->room - ); - - char* filename; - util_get_filename(directory, "groups", key, &filename); - - if (GNUNET_YES != GNUNET_DISK_file_test(filename)) - goto free_filename; - - struct GNUNET_CONFIGURATION_Handle *config = GNUNET_CONFIGURATION_create(); - - if (GNUNET_OK != GNUNET_CONFIGURATION_load(config, filename)) - goto destroy_config; - - char* name = NULL; - - if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string( - config, "group", "topic", &name)) - util_set_name_field(name, &(group->topic)); - - if (name) - GNUNET_free(name); - -destroy_config: - GNUNET_CONFIGURATION_destroy(config); - -free_filename: - GNUNET_free(filename); -} - -void -group_save_config (const struct GNUNET_CHAT_Group *group) -{ - GNUNET_assert((group) && (group->handle)); - - const char *directory = handle_get_directory(group->handle); - - if ((!directory) || (!(group->context))) - return; - - const struct GNUNET_HashCode *key = GNUNET_MESSENGER_room_get_key( - group->context->room - ); - - struct GNUNET_CONFIGURATION_Handle *config = GNUNET_CONFIGURATION_create(); - - if (group->topic) - { - struct GNUNET_HashCode topic_hash; - GNUNET_CRYPTO_hash(group->topic, strlen(group->topic), &topic_hash); - - if (0 == GNUNET_memcmp(key, &topic_hash)) - GNUNET_CONFIGURATION_set_value_string( - config, "group", "topic", group->topic - ); - } - - char* filename; - util_get_filename(directory, "groups", key, &filename); - - if (GNUNET_OK == GNUNET_DISK_directory_create_for_file(filename)) - GNUNET_CONFIGURATION_write(config, filename); - - GNUNET_CONFIGURATION_destroy(config); - - GNUNET_free(filename); -} diff --git a/src/gnunet_chat_group.h b/src/gnunet_chat_group.h @@ -39,8 +39,6 @@ struct GNUNET_CHAT_Group struct GNUNET_CHAT_Handle *handle; struct GNUNET_CHAT_Context *context; - char *topic; - struct GNUNET_REGEX_Announcement *announcement; struct GNUNET_REGEX_Search *search; @@ -59,10 +57,4 @@ group_destroy (struct GNUNET_CHAT_Group* group); void group_publish (struct GNUNET_CHAT_Group* group); -void -group_load_config (struct GNUNET_CHAT_Group *group); - -void -group_save_config (const struct GNUNET_CHAT_Group *group); - #endif /* GNUNET_CHAT_GROUP_H_ */ diff --git a/src/gnunet_chat_handle.c b/src/gnunet_chat_handle.c @@ -58,6 +58,7 @@ handle_create_from_config (const struct GNUNET_CONFIGURATION_Handle* cfg, handle->current = NULL; handle->creation_op = NULL; + handle->monitor = NULL; handle->files = NULL; handle->contexts = NULL; @@ -78,6 +79,10 @@ handle_create_from_config (const struct GNUNET_CONFIGURATION_Handle* cfg, handle ); + handle->namestore = GNUNET_NAMESTORE_connect( + handle->cfg + ); + handle->fs = NULL; handle->messenger = NULL; @@ -114,12 +119,18 @@ handle_destroy (struct GNUNET_CHAT_Handle *handle) if (handle->shutdown_hook) GNUNET_SCHEDULER_cancel(handle->shutdown_hook); + if (handle->monitor) + GNUNET_NAMESTORE_zone_monitor_stop(handle->monitor); + if (handle->creation_op) GNUNET_IDENTITY_cancel(handle->creation_op); if (handle->current) handle_disconnect(handle); + if (handle->namestore) + GNUNET_NAMESTORE_disconnect(handle->namestore); + if (handle->identity) GNUNET_IDENTITY_disconnect(handle->identity); @@ -177,6 +188,12 @@ handle_connect (struct GNUNET_CHAT_Handle *handle, (!(handle->contexts)) && (!(handle->files))); + if (handle->monitor) + { + GNUNET_NAMESTORE_zone_monitor_stop(handle->monitor); + handle->monitor = NULL; + } + handle->files = GNUNET_CONTAINER_multihashmap_create(8, GNUNET_NO); handle->contexts = GNUNET_CONTAINER_multihashmap_create(8, GNUNET_NO); handle->contacts = GNUNET_CONTAINER_multishortmap_create(8, GNUNET_NO); @@ -274,6 +291,19 @@ handle_get_directory (const struct GNUNET_CHAT_Handle *handle) return handle->current->directory; } +const struct GNUNET_IDENTITY_PrivateKey* +handle_get_key (const struct GNUNET_CHAT_Handle *handle) +{ + GNUNET_assert(handle); + + if ((!(handle->current)) || (!(handle->current->ego))) + return NULL; + + return GNUNET_IDENTITY_ego_get_private_key( + handle->current->ego + ); +} + void handle_send_internal_message (struct GNUNET_CHAT_Handle *handle, struct GNUNET_CHAT_Context *context, @@ -351,7 +381,6 @@ handle_request_context_by_room (struct GNUNET_CHAT_Handle *handle, return GNUNET_OK; context = context_create_from_room(handle, room); - context_load_config(context); if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( handle->contexts, key, context, @@ -376,9 +405,14 @@ check_type: (GNUNET_OK == intern_provide_contact_for_member(handle, check.contact, context))) + { + context_delete_records(context); context->type = GNUNET_CHAT_CONTEXT_TYPE_CONTACT; + context_write_records(context); + } else if (checks >= 2) { + context_delete_records(context); context->type = GNUNET_CHAT_CONTEXT_TYPE_GROUP; if (context->contact) @@ -405,9 +439,7 @@ setup_group: handle, context ); - group_load_config(group); - - if (group->topic) + if (context->topic) group_publish(group); if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put( @@ -421,6 +453,7 @@ setup_group: NULL ); + context_write_records(context); return GNUNET_OK; } diff --git a/src/gnunet_chat_handle.h b/src/gnunet_chat_handle.h @@ -33,6 +33,7 @@ #include <gnunet/gnunet_fs_service.h> #include <gnunet/gnunet_identity_service.h> #include <gnunet/gnunet_messenger_service.h> +#include <gnunet/gnunet_namestore_service.h> #include <gnunet/gnunet_scheduler_lib.h> #include <gnunet/gnunet_util_lib.h> @@ -72,6 +73,7 @@ struct GNUNET_CHAT_Handle const struct GNUNET_CHAT_Account *current; struct GNUNET_IDENTITY_Operation *creation_op; + struct GNUNET_NAMESTORE_ZoneMonitor *monitor; struct GNUNET_CONTAINER_MultiHashMap *files; struct GNUNET_CONTAINER_MultiHashMap *contexts; @@ -82,6 +84,7 @@ struct GNUNET_CHAT_Handle struct GNUNET_FS_Handle *fs; struct GNUNET_IDENTITY_Handle *identity; struct GNUNET_MESSENGER_Handle *messenger; + struct GNUNET_NAMESTORE_Handle *namestore; char *public_key; void *user_pointer; @@ -109,6 +112,9 @@ handle_disconnect (struct GNUNET_CHAT_Handle *handle); const char* handle_get_directory (const struct GNUNET_CHAT_Handle *handle); +const struct GNUNET_IDENTITY_PrivateKey* +handle_get_key (const struct GNUNET_CHAT_Handle *handle); + void handle_send_internal_message (struct GNUNET_CHAT_Handle *handle, struct GNUNET_CHAT_Context *context, diff --git a/src/gnunet_chat_handle_intern.c b/src/gnunet_chat_handle_intern.c @@ -64,6 +64,12 @@ on_handle_arm_connection(void *cls, GNUNET_OS_INHERIT_STD_NONE, NULL, NULL ); + + GNUNET_ARM_request_service_start( + chat->arm, "namestore", + GNUNET_OS_INHERIT_STD_NONE, + NULL, NULL + ); } else { GNUNET_ARM_request_service_start( chat->arm, "arm", @@ -359,6 +365,93 @@ scan_handle_room_members (void* cls, } void +on_monitor_namestore_record(void *cls, + GNUNET_UNUSED const + struct GNUNET_IDENTITY_PrivateKey *zone, + const char *label, + unsigned int count, + const struct GNUNET_GNSRECORD_Data *data) +{ + struct GNUNET_CHAT_Handle *chat = cls; + + if (count <= 0) + goto skip_records; + + 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); +} + +void on_handle_identity(void *cls, GNUNET_UNUSED struct GNUNET_MESSENGER_Handle *messenger) { @@ -377,7 +470,8 @@ on_handle_identity(void *cls, return; GNUNET_assert(handle->messenger); - context_scan_configs(handle); + + printf("HURRAY!\n"); handle_send_internal_message( handle, @@ -385,6 +479,23 @@ on_handle_identity(void *cls, 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 @@ -583,7 +694,6 @@ it_destroy_handle_groups (GNUNET_UNUSED void *cls, GNUNET_assert(value); struct GNUNET_CHAT_Group *group = value; - group_save_config(group); group_destroy(group); return GNUNET_YES; } @@ -608,7 +718,6 @@ it_destroy_handle_contexts (GNUNET_UNUSED void *cls, GNUNET_assert(value); struct GNUNET_CHAT_Context *context = value; - context_save_config(context); context_destroy(context); return GNUNET_YES; } diff --git a/src/gnunet_chat_lib.c b/src/gnunet_chat_lib.c @@ -310,6 +310,8 @@ GNUNET_CHAT_group_create (struct GNUNET_CHAT_Handle *handle, context->type = GNUNET_CHAT_CONTEXT_TYPE_GROUP; + util_set_name_field(topic, &(context->topic)); + if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( handle->contexts, &key, context, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) @@ -317,15 +319,16 @@ GNUNET_CHAT_group_create (struct GNUNET_CHAT_Handle *handle, struct GNUNET_CHAT_Group *group = group_create_from_context(handle, context); - util_set_name_field(topic, &(group->topic)); - - if (group->topic) + if (context->topic) group_publish(group); if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put( handle->groups, &key, group, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) + { + context_write_records(context); return group; + } group_destroy(group); @@ -513,10 +516,13 @@ GNUNET_CHAT_group_set_name (struct GNUNET_CHAT_Group *group, const char* GNUNET_CHAT_group_get_name (const struct GNUNET_CHAT_Group *group) { - if (!group) + if ((!group) || (!(group->context))) return NULL; - return group->context->nick; + if (group->context->nick) + return group->context->nick; + + return group->context->topic; } @@ -911,6 +917,43 @@ GNUNET_CHAT_context_iterate_files (struct GNUNET_CHAT_Context *context, } +void +GNUNET_CHAT_member_set_user_pointer (struct GNUNET_CHAT_Context *context, + const struct GNUNET_CHAT_Contact *member, + void *user_pointer) +{ + if ((!context) || (!member)) + return; + + struct GNUNET_ShortHashCode hash; + util_shorthash_from_member(member->member, &hash); + + GNUNET_CONTAINER_multishortmap_put( + context->member_pointers, + &hash, + user_pointer, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE + ); +} + + +void* +GNUNET_CHAT_member_get_user_pointer (const struct GNUNET_CHAT_Context *context, + const struct GNUNET_CHAT_Contact *member) +{ + if ((!context) || (!member)) + return NULL; + + struct GNUNET_ShortHashCode hash; + util_shorthash_from_member(member->member, &hash); + + return GNUNET_CONTAINER_multishortmap_get( + context->member_pointers, + &hash + ); +} + + enum GNUNET_CHAT_MessageKind GNUNET_CHAT_message_get_kind (const struct GNUNET_CHAT_Message *message) {