libgnunetchat

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

commit d1a6ac474d731b74ea1b191a76471b698687a278
parent b880617514f9e64e991cb8d6fcff74ce3f292e36
Author: TheJackiMonster <thejackimonster@gmail.com>
Date:   Mon, 12 Jul 2021 00:21:25 +0200

Most of the file handling and necessary disk io calls

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

Diffstat:
Minclude/gnunet_chat_lib.h | 45++++++++++++++++++++++++++++++---------------
Msrc/gnunet_chat_context.c | 10++++++++++
Asrc/gnunet_chat_context_intern.c | 48++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/gnunet_chat_file.c | 37+++++++++++++++++++++++++++++++++++++
Msrc/gnunet_chat_file.h | 11+++++++++++
Msrc/gnunet_chat_handle.c | 30++++++++++++++++++++++++++++--
Msrc/gnunet_chat_handle.h | 5++++-
Msrc/gnunet_chat_handle_intern.c | 157++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/gnunet_chat_lib.c | 213++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Msrc/gnunet_chat_util.c | 148+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/gnunet_chat_util.h | 21+++++++++++++++++++--
11 files changed, 612 insertions(+), 113 deletions(-)

diff --git a/include/gnunet_chat_lib.h b/include/gnunet_chat_lib.h @@ -194,6 +194,7 @@ typedef int * TODO * * @param cfg + * @param directory * @param name * @param warn_cb * @param warn_cls @@ -201,6 +202,7 @@ typedef int */ struct GNUNET_CHAT_Handle* GNUNET_CHAT_start (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *directory, const char *name, GNUNET_CHAT_WarningCallback warn_cb, void *warn_cls, GNUNET_CHAT_ContextMessageCallback msg_cb, void *msg_cls); @@ -398,8 +400,9 @@ GNUNET_CHAT_group_get_context (struct GNUNET_CHAT_Group *group); * * @param context * @param text + * @return */ -void +int GNUNET_CHAT_context_send_text (struct GNUNET_CHAT_Context *context, const char *text); @@ -408,8 +411,9 @@ GNUNET_CHAT_context_send_text (struct GNUNET_CHAT_Context *context, * * @param context * @param path + * @return */ -void +int GNUNET_CHAT_context_send_file (struct GNUNET_CHAT_Context *context, const char *path); @@ -418,8 +422,9 @@ GNUNET_CHAT_context_send_file (struct GNUNET_CHAT_Context *context, * * @param context * @param uri + * @return */ -void +int GNUNET_CHAT_context_send_uri (struct GNUNET_CHAT_Context *context, const char *uri); @@ -428,8 +433,9 @@ GNUNET_CHAT_context_send_uri (struct GNUNET_CHAT_Context *context, * * @param context * @param file + * @return */ -void +int GNUNET_CHAT_context_share_file (struct GNUNET_CHAT_Context *context, const struct GNUNET_CHAT_File *file); @@ -437,17 +443,6 @@ GNUNET_CHAT_context_share_file (struct GNUNET_CHAT_Context *context, * TODO * * @param context - * @param hash - * @param delay - */ -void -GNUNET_CHAT_context_delete_message (const struct GNUNET_CHAT_Message *message, - struct GNUNET_TIME_Relative delay); - -/** - * TODO - * - * @param context * @param callback * @param cls * @return @@ -528,6 +523,17 @@ GNUNET_CHAT_message_get_invitation (const struct GNUNET_CHAT_Message *message); /** * TODO * + * @param message + * @param delay + * @return + */ +int +GNUNET_CHAT_message_delete (const struct GNUNET_CHAT_Message *message, + struct GNUNET_TIME_Relative delay); + +/** + * TODO + * * @param file * @return */ @@ -593,6 +599,15 @@ GNUNET_CHAT_file_stop_download (struct GNUNET_CHAT_File *file); /** * TODO * + * @param file + * @return + */ +int +GNUNET_CHAT_file_unindex (struct GNUNET_CHAT_File *file); + +/** + * TODO + * * @param invitation */ void diff --git a/src/gnunet_chat_context.c b/src/gnunet_chat_context.c @@ -24,6 +24,8 @@ #include "gnunet_chat_context.h" +#include "gnunet_chat_context_intern.c" + struct GNUNET_CHAT_Context* context_create_from_room (struct GNUNET_CHAT_Handle *handle, struct GNUNET_MESSENGER_Room *room) @@ -47,6 +49,14 @@ context_create_from_room (struct GNUNET_CHAT_Handle *handle, void context_destroy (struct GNUNET_CHAT_Context* context) { + GNUNET_CONTAINER_multihashmap_iterate( + context->messages, it_destroy_context_messages, NULL + ); + + GNUNET_CONTAINER_multihashmap_iterate( + context->messages, it_destroy_context_invites, NULL + ); + GNUNET_CONTAINER_multihashmap_destroy(context->messages); GNUNET_CONTAINER_multihashmap_destroy(context->invites); GNUNET_CONTAINER_multihashmap_destroy(context->files); diff --git a/src/gnunet_chat_context_intern.c b/src/gnunet_chat_context_intern.c @@ -0,0 +1,48 @@ +/* + This file is part of GNUnet. + Copyright (C) 2021 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_context_intern.c + */ + +#include "gnunet_chat_invitation.h" +#include "gnunet_chat_message.h" + +#define GNUNET_UNUSED __attribute__ ((unused)) + +int +it_destroy_context_messages (GNUNET_UNUSED void *cls, + GNUNET_UNUSED const struct GNUNET_HashCode *key, + void *value) +{ + struct GNUNET_CHAT_Message *message = value; + message_destroy(message); + return GNUNET_YES; +} + +int +it_destroy_context_invites (GNUNET_UNUSED void *cls, + GNUNET_UNUSED const struct GNUNET_HashCode *key, + void *value) +{ + struct GNUNET_CHAT_Invitation *invitation = value; + invitation_destroy(invitation); + return GNUNET_YES; +} diff --git a/src/gnunet_chat_file.c b/src/gnunet_chat_file.c @@ -39,6 +39,12 @@ file_create_from_message (struct GNUNET_CHAT_Handle *handle, GNUNET_memcpy(&(file->key), &(message->key), sizeof(file->key)); GNUNET_memcpy(&(file->hash), &(message->hash), sizeof(file->hash)); + file->published = 0; + file->downloaded = 0; + file->unindexed = 0; + + file->meta = GNUNET_CONTAINER_meta_data_create(); + file->uri = GNUNET_FS_uri_parse(message->uri, NULL); file->download = NULL; file->publish = NULL; @@ -47,12 +53,43 @@ file_create_from_message (struct GNUNET_CHAT_Handle *handle, return file; } +struct GNUNET_CHAT_File* +file_create_from_disk (struct GNUNET_CHAT_Handle *handle, + const char *name, const struct GNUNET_HashCode *hash, + const struct GNUNET_CRYPTO_SymmetricSessionKey *key) +{ + struct GNUNET_CHAT_File* file = GNUNET_new(struct GNUNET_CHAT_File); + + file->handle = handle; + + file->name = GNUNET_strndup(name, NAME_MAX); + + GNUNET_memcpy(&(file->key), key, sizeof(file->key)); + GNUNET_memcpy(&(file->hash), hash, sizeof(file->hash)); + + file->published = 0; + file->downloaded = 0; + file->unindexed = 0; + + file->meta = GNUNET_CONTAINER_meta_data_create(); + + file->uri = NULL; + file->download = NULL; + file->publish = NULL; + file->unindex = NULL; + + return file; +} + void file_destroy (struct GNUNET_CHAT_File* file) { if (file->uri) GNUNET_FS_uri_destroy(file->uri); + if (file->meta) + GNUNET_CONTAINER_meta_data_destroy(file->meta); + if (file->name) GNUNET_free(file->name); diff --git a/src/gnunet_chat_file.h b/src/gnunet_chat_file.h @@ -43,6 +43,12 @@ struct GNUNET_CHAT_File struct GNUNET_HashCode hash; struct GNUNET_CRYPTO_SymmetricSessionKey key; + uint64_t published; + uint64_t downloaded; + uint64_t unindexed; + + struct GNUNET_CONTAINER_MetaData *meta; + struct GNUNET_FS_Uri* uri; struct GNUNET_FS_DownloadContext* download; struct GNUNET_FS_PublishContext* publish; @@ -53,6 +59,11 @@ struct GNUNET_CHAT_File* file_create_from_message (struct GNUNET_CHAT_Handle *handle, const struct GNUNET_MESSENGER_MessageFile* message); +struct GNUNET_CHAT_File* +file_create_from_disk (struct GNUNET_CHAT_Handle *handle, + const char *name, const struct GNUNET_HashCode *hash, + const struct GNUNET_CRYPTO_SymmetricSessionKey *key); + void file_destroy (struct GNUNET_CHAT_File* file); diff --git a/src/gnunet_chat_handle.c b/src/gnunet_chat_handle.c @@ -28,7 +28,8 @@ struct GNUNET_CHAT_Handle* handle_create_from_config (const struct GNUNET_CONFIGURATION_Handle* cfg, - const char* name, + const char *directory, + const char *name, GNUNET_CHAT_ContextMessageCallback msg_cb, void *msg_cls, GNUNET_CHAT_WarningCallback warn_cb, @@ -38,6 +39,12 @@ handle_create_from_config (const struct GNUNET_CONFIGURATION_Handle* cfg, handle->cfg = cfg; + if ((directory) && + (GNUNET_YES == GNUNET_DISK_directory_test(directory, GNUNET_YES))) + handle->directory = GNUNET_strdup(directory); + else + handle->directory = NULL; + handle->msg_cb = msg_cb; handle->msg_cls = msg_cls; @@ -58,7 +65,7 @@ handle_create_from_config (const struct GNUNET_CONFIGURATION_Handle* cfg, on_handle_arm_connection(handle, GNUNET_NO); handle->fs = GNUNET_FS_start( - handle->cfg, name, // TODO: raw name? + handle->cfg, name, // TODO: raw name? (NULL?) notify_handle_fs_progress, handle, GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END @@ -85,10 +92,29 @@ handle_destroy (struct GNUNET_CHAT_Handle* handle) if (handle->arm) GNUNET_ARM_disconnect(handle->arm); + GNUNET_CONTAINER_multihashmap_iterate( + handle->groups, it_destroy_handle_groups, NULL + ); + + GNUNET_CONTAINER_multishortmap_iterate( + handle->contacts, it_destroy_handle_contacts, NULL + ); + + GNUNET_CONTAINER_multihashmap_iterate( + handle->contexts, it_destroy_handle_contexts, NULL + ); + + GNUNET_CONTAINER_multihashmap_iterate( + handle->files, it_destroy_handle_files, NULL + ); + GNUNET_CONTAINER_multihashmap_destroy(handle->groups); GNUNET_CONTAINER_multishortmap_destroy(handle->contacts); GNUNET_CONTAINER_multihashmap_destroy(handle->contexts); GNUNET_CONTAINER_multihashmap_destroy(handle->files); + if (handle->directory) + GNUNET_free(handle->directory); + GNUNET_free(handle); } diff --git a/src/gnunet_chat_handle.h b/src/gnunet_chat_handle.h @@ -40,6 +40,8 @@ struct GNUNET_CHAT_Handle { const struct GNUNET_CONFIGURATION_Handle* cfg; + char *directory; + GNUNET_CHAT_ContextMessageCallback msg_cb; void *msg_cls; @@ -58,7 +60,8 @@ struct GNUNET_CHAT_Handle struct GNUNET_CHAT_Handle* handle_create_from_config (const struct GNUNET_CONFIGURATION_Handle* cfg, - const char* name, + const char *directory, + const char *name, GNUNET_CHAT_ContextMessageCallback msg_cb, void *msg_cls, GNUNET_CHAT_WarningCallback warn_cb, diff --git a/src/gnunet_chat_handle_intern.c b/src/gnunet_chat_handle_intern.c @@ -24,8 +24,10 @@ #include "gnunet_chat_contact.h" #include "gnunet_chat_context.h" +#include "gnunet_chat_file.h" #include "gnunet_chat_group.h" #include "gnunet_chat_handle.h" +#include "gnunet_chat_invitation.h" #include "gnunet_chat_message.h" #include "gnunet_chat_util.h" @@ -67,79 +69,70 @@ notify_handle_fs_progress(void* cls, const struct GNUNET_FS_ProgressInfo* info) switch (info->status) { case GNUNET_FS_STATUS_PUBLISH_START: { - /*publication_t* publication = (publication_t*) info->value.publish.cctx; - publication->progress = 0.0f; + struct GNUNET_CHAT_File *file = info->value.publish.cctx; - GNUNET_SCHEDULER_add_now(&CGTK_publication_progress, publication); + file->published = 0; - return publication;*/ - break; + return file; } case GNUNET_FS_STATUS_PUBLISH_PROGRESS: { - /*publication_t* publication = (publication_t*) info->value.publish.cctx; - publication->progress = 1.0f * info->value.publish.completed / info->value.publish.size; + struct GNUNET_CHAT_File *file = info->value.publish.cctx; - GNUNET_SCHEDULER_add_now(&CGTK_publication_progress, publication); + file->published = info->value.publish.completed; - return publication;*/ - break; + return file; } case GNUNET_FS_STATUS_PUBLISH_COMPLETED: { - /*publication_t* publication = (publication_t*) info->value.publish.cctx; - publication->uri = GNUNET_FS_uri_dup(info->value.publish.specifics.completed.chk_uri); - publication->progress = 1.0f; + struct GNUNET_CHAT_File *file = info->value.publish.cctx; + + file->uri = GNUNET_FS_uri_dup( + info->value.publish.specifics.completed.chk_uri + ); - GNUNET_SCHEDULER_add_now(&CGTK_publication_finish, publication);*/ + file->published = info->value.publish.size; + file->publish = NULL; break; } case GNUNET_FS_STATUS_PUBLISH_ERROR: { - /*publication_t* publication = (publication_t*) info->value.publish.cctx; - - GNUNET_SCHEDULER_add_now(&CGTK_publication_error, publication);*/ break; } case GNUNET_FS_STATUS_DOWNLOAD_START: { - /*request_t* request = (request_t*) info->value.download.cctx; - request->progress = 0.0f; + struct GNUNET_CHAT_File *file = info->value.download.cctx; - return request;*/ - break; + file->downloaded = 0; + + return file; } case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: { return info->value.download.cctx; } case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: { return info->value.download.cctx; } case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: { - /*request_t* request = (request_t*) info->value.download.cctx; - request->progress = 1.0f * info->value.download.completed / info->value.download.size; + struct GNUNET_CHAT_File *file = info->value.download.cctx; - GNUNET_SCHEDULER_add_now(&CGTK_request_progress, request); + file->downloaded = info->value.download.completed; - return request;*/ - break; + return file; } case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: { - /*request_t* request = (request_t*) info->value.download.cctx; - request->progress = 1.0f; + struct GNUNET_CHAT_File *file = info->value.download.cctx; - GNUNET_SCHEDULER_add_now(&CGTK_request_finish, request);*/ + file->downloaded = info->value.download.size; + file->download = NULL; break; } case GNUNET_FS_STATUS_DOWNLOAD_ERROR: { - /*request_t *request = (request_t *) info->value.download.cctx; - - GNUNET_SCHEDULER_add_now(&CGTK_request_error, request);*/ break; } case GNUNET_FS_STATUS_UNINDEX_START: { - /*publication_t* publication = (publication_t*) info->value.unindex.cctx; - publication->progress = 0.0f; + struct GNUNET_CHAT_File *file = info->value.unindex.cctx; - return publication;*/ - break; + file->unindexed = 0; + + return file; } case GNUNET_FS_STATUS_UNINDEX_PROGRESS: { - /*publication_t* publication = (publication_t*) info->value.unindex.cctx; - publication->progress = 1.0f * info->value.unindex.completed / info->value.unindex.size; + struct GNUNET_CHAT_File *file = info->value.unindex.cctx; - return publication;*/ - break; + file->unindexed = info->value.unindex.completed; + + return file; } case GNUNET_FS_STATUS_UNINDEX_COMPLETED: { - /*publication_t* publication = (publication_t*) info->value.unindex.cctx; - publication->progress = 1.0f; + struct GNUNET_CHAT_File *file = info->value.unindex.cctx; - GNUNET_SCHEDULER_add_now(&CGTK_publication_unindex_finish, publication);*/ + file->unindexed = info->value.unindex.size; + file->unindex = NULL; break; } default: { break; @@ -290,10 +283,45 @@ on_handle_message (void *cls, ); if (message) - goto process_callback; + return; message = message_create_from_msg(context, hash, msg); + switch (msg->header.kind) + { + case GNUNET_MESSENGER_KIND_INVITE: + { + struct GNUNET_CHAT_Invitation *invitation = invitation_create_from_message( + context, &(msg->body.invite) + ); + + if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( + context->invites, hash, invitation, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) + invitation_destroy(invitation); + break; + } + case GNUNET_MESSENGER_KIND_FILE: + { + GNUNET_CONTAINER_multihashmap_put( + context->files, hash, NULL, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST + ); + + struct GNUNET_CHAT_File *file = file_create_from_message( + context->handle, &(msg->body.file) + ); + + if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( + context->handle->files, &(file->hash), file, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) + file_destroy(file); + break; + } + default: + break; + } + if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( context->messages, hash, message, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) @@ -302,7 +330,46 @@ on_handle_message (void *cls, return; } -process_callback: if (handle->msg_cb) handle->msg_cb(handle->msg_cls, context, message); } + +int +it_destroy_handle_groups (GNUNET_UNUSED void *cls, + GNUNET_UNUSED const struct GNUNET_HashCode *key, + void *value) +{ + struct GNUNET_CHAT_Group *group = value; + group_destroy(group); + return GNUNET_YES; +} + +int +it_destroy_handle_contacts (GNUNET_UNUSED void *cls, + GNUNET_UNUSED const struct GNUNET_ShortHashCode *key, + void *value) +{ + struct GNUNET_CHAT_Contact *contact = value; + contact_destroy(contact); + return GNUNET_YES; +} + +int +it_destroy_handle_contexts (GNUNET_UNUSED void *cls, + GNUNET_UNUSED const struct GNUNET_HashCode *key, + void *value) +{ + struct GNUNET_CHAT_Context *context = value; + context_destroy(context); + return GNUNET_YES; +} + +int +it_destroy_handle_files (GNUNET_UNUSED void *cls, + GNUNET_UNUSED const struct GNUNET_HashCode *key, + void *value) +{ + struct GNUNET_CHAT_File *file = value; + file_destroy(file); + return GNUNET_YES; +} diff --git a/src/gnunet_chat_lib.c b/src/gnunet_chat_lib.c @@ -40,6 +40,7 @@ struct GNUNET_CHAT_Handle* GNUNET_CHAT_start (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *directory, const char *name, GNUNET_CHAT_WarningCallback warn_cb, void *warn_cls, GNUNET_CHAT_ContextMessageCallback msg_cb, void *msg_cls) @@ -47,11 +48,10 @@ GNUNET_CHAT_start (const struct GNUNET_CONFIGURATION_Handle *cfg, if (!cfg) return NULL; - if (!name) - return NULL; - return handle_create_from_config( - cfg, name, msg_cb, msg_cls, warn_cb, warn_cls + cfg, directory, name, + msg_cb, msg_cls, + warn_cb, warn_cls ); } @@ -332,6 +332,7 @@ GNUNET_CHAT_group_invite_contact (struct GNUNET_CHAT_Group *group, GNUNET_MESSENGER_send_message(contact->context->room, &msg, contact->member); } + int GNUNET_CHAT_group_iterate_contacts (struct GNUNET_CHAT_Group *group, GNUNET_CHAT_GroupContactCallback callback, @@ -360,12 +361,13 @@ GNUNET_CHAT_group_get_context (struct GNUNET_CHAT_Group *group) return group->context; } -void + +int GNUNET_CHAT_context_send_text (struct GNUNET_CHAT_Context *context, const char *text) { if ((!context) || (!text)) - return; + return GNUNET_SYSERR; struct GNUNET_MESSENGER_Message msg; msg.header.kind = GNUNET_MESSENGER_KIND_TEXT; @@ -374,42 +376,109 @@ GNUNET_CHAT_context_send_text (struct GNUNET_CHAT_Context *context, GNUNET_MESSENGER_send_message(context->room, &msg, NULL); GNUNET_free(msg.body.text.text); + return GNUNET_OK; } -void +int GNUNET_CHAT_context_send_file (struct GNUNET_CHAT_Context *context, const char *path) { if ((!context) || (!path)) - return; + return GNUNET_SYSERR; + + if (!(context->handle->directory)) + return GNUNET_SYSERR; + + struct GNUNET_HashCode hash; + if (GNUNET_OK != util_hash_file(path, &hash)) + return GNUNET_SYSERR; + + char *filename; + util_get_filename (context->handle->directory, &hash, &filename); + + if ((GNUNET_OK != GNUNET_DISK_directory_create_for_file(filename)) || + (GNUNET_OK != GNUNET_DISK_file_copy(path, filename))) + { + GNUNET_free(filename); + return GNUNET_SYSERR; + } + + struct GNUNET_CRYPTO_SymmetricSessionKey key; + GNUNET_CRYPTO_symmetric_create_session_key(&key); + + if (GNUNET_OK != util_encrypt_file(filename, &key)) + { + GNUNET_free(filename); + return GNUNET_SYSERR; + } + + char* p = GNUNET_strdup(path); - // TODO: encrypt file, publish file, share file + struct GNUNET_CHAT_File *file = file_create_from_disk( + context->handle, basename(p), &hash, &key + ); + + GNUNET_free(p); + + struct GNUNET_FS_BlockOptions bo; + + bo.anonymity_level = 1; + bo.content_priority = 100; + bo.replication_level = 1; + + bo.expiration_time = GNUNET_TIME_absolute_add( + GNUNET_TIME_absolute_get(), GNUNET_TIME_relative_get_hour_() + ); + + struct GNUNET_FS_FileInformation* fi = GNUNET_FS_file_information_create_from_file( + context->handle->fs, + file, + filename, + NULL, + file->meta, + GNUNET_YES, + &bo + ); + + file->publish = GNUNET_FS_publish_start( + context->handle->fs, fi, + NULL, NULL, NULL, + GNUNET_FS_PUBLISH_OPTION_NONE + ); + + GNUNET_free(filename); + + // TODO: share file + + return GNUNET_OK; } -void +int GNUNET_CHAT_context_send_uri (struct GNUNET_CHAT_Context *context, const char *uri) { if ((!context) || (!uri)) - return; + return GNUNET_SYSERR; struct GNUNET_FS_Uri *furi = GNUNET_FS_uri_parse(uri, NULL); if (!furi) - return; + return GNUNET_SYSERR; // TODO: download file, hash file, share file + + return GNUNET_SYSERR; } -void +int GNUNET_CHAT_context_share_file (struct GNUNET_CHAT_Context *context, const struct GNUNET_CHAT_File *file) { if ((!context) || (!file) || (strlen(file->name) > NAME_MAX)) - return; + return GNUNET_SYSERR; struct GNUNET_MESSENGER_Message msg; msg.header.kind = GNUNET_MESSENGER_KIND_FILE; @@ -421,26 +490,10 @@ GNUNET_CHAT_context_share_file (struct GNUNET_CHAT_Context *context, GNUNET_MESSENGER_send_message(context->room, &msg, NULL); GNUNET_free(msg.body.file.uri); + return GNUNET_OK; } -void -GNUNET_CHAT_context_delete_message (const struct GNUNET_CHAT_Message *message, - struct GNUNET_TIME_Relative delay) -{ - if (!message) - return; - - struct GNUNET_MESSENGER_Message msg; - msg.header.kind = GNUNET_MESSENGER_KIND_DELETE; - GNUNET_memcpy(&(msg.body.delete.hash), &(message->hash), sizeof(message->hash)); - msg.body.delete.delay = GNUNET_TIME_relative_hton(delay); - - GNUNET_MESSENGER_send_message(message->context->room, &msg, NULL); -} - - - int GNUNET_CHAT_context_iterate_messages (struct GNUNET_CHAT_Context *context, GNUNET_CHAT_ContextMessageCallback callback, @@ -571,6 +624,23 @@ GNUNET_CHAT_message_get_invitation (const struct GNUNET_CHAT_Message *message) } +int +GNUNET_CHAT_message_delete (const struct GNUNET_CHAT_Message *message, + struct GNUNET_TIME_Relative delay) +{ + if (!message) + return GNUNET_SYSERR; + + struct GNUNET_MESSENGER_Message msg; + msg.header.kind = GNUNET_MESSENGER_KIND_DELETE; + GNUNET_memcpy(&(msg.body.delete.hash), &(message->hash), sizeof(message->hash)); + msg.body.delete.delay = GNUNET_TIME_relative_hton(delay); + + GNUNET_MESSENGER_send_message(message->context->room, &msg, NULL); + return GNUNET_OK; +} + + const struct GNUNET_HashCode* GNUNET_CHAT_file_get_hash (const struct GNUNET_CHAT_File *file) { @@ -590,11 +660,15 @@ GNUNET_CHAT_file_get_size (const struct GNUNET_CHAT_File *file) if (file->uri) return GNUNET_FS_uri_chk_get_file_size(file->uri); - const char *path = ""; // TODO: path = download_directory + file->name + char *filename; + util_get_filename (file->handle->directory, &(file->hash), &filename); - // TODO: check size through info or check locally? + uint64_t size; + if (GNUNET_OK != GNUNET_DISK_file_size(filename, &size, GNUNET_NO, GNUNET_YES)) + size = 0; - return 0; + GNUNET_free(filename); + return size; } @@ -604,11 +678,13 @@ GNUNET_CHAT_file_is_local (const struct GNUNET_CHAT_File *file) if (!file) return GNUNET_SYSERR; - const char *path = ""; // TODO: path = download_directory + file->name + char *filename; + util_get_filename (file->handle->directory, &(file->hash), &filename); - // TODO: check locally? + int result = GNUNET_DISK_file_test(filename); - return GNUNET_SYSERR; + GNUNET_free(filename); + return result; } @@ -617,27 +693,44 @@ GNUNET_CHAT_file_start_download (struct GNUNET_CHAT_File *file, GNUNET_CHAT_MessageFileDownloadCallback callback, void *cls) { - if (!file) + if ((!file) || (!(file->uri))) return GNUNET_SYSERR; - // TODO: check if downloading? + if (file->download) + { + GNUNET_FS_download_resume(file->download); + return GNUNET_OK; + } + + const uint64_t size = GNUNET_FS_uri_chk_get_file_size(file->uri); - const char *path = ""; // TODO: path = download_directory + file->name + char *filename; + util_get_filename (file->handle->directory, &(file->hash), &filename); + + uint64_t offset; + if (GNUNET_OK != GNUNET_DISK_file_size(filename, &offset, GNUNET_NO, GNUNET_YES)) + offset = 0; + + if (offset >= size) + return GNUNET_OK; + + const uint64_t remaining = (size - offset); file->download = GNUNET_FS_download_start( file->handle->fs, file->uri, + file->meta, + filename, NULL, - path, - NULL, - 0, - 0, - 0, + offset, + remaining, + 1, GNUNET_FS_DOWNLOAD_OPTION_NONE, - NULL, + file, NULL ); + GNUNET_free(filename); return GNUNET_OK; } @@ -676,6 +769,34 @@ GNUNET_CHAT_file_stop_download (struct GNUNET_CHAT_File *file) } +int +GNUNET_CHAT_file_unindex (struct GNUNET_CHAT_File *file) +{ + if (!file) + return GNUNET_SYSERR; + + if (file->publish) + { + GNUNET_FS_publish_stop(file->publish); + file->publish = NULL; + return GNUNET_OK; + } + + if (file->unindex) + return GNUNET_OK; + + char *filename; + util_get_filename (file->handle->directory, &(file->hash), &filename); + + file->unindex = GNUNET_FS_unindex_start( + file->handle->fs, filename, file + ); + + GNUNET_free(filename); + return GNUNET_OK; +} + + void GNUNET_CHAT_invitation_accept (struct GNUNET_CHAT_Invitation *invitation) { diff --git a/src/gnunet_chat_util.c b/src/gnunet_chat_util.c @@ -26,14 +26,14 @@ void util_shorthash_from_member (const struct GNUNET_MESSENGER_Contact *member, - struct GNUNET_ShortHashCode* shorthash) + struct GNUNET_ShortHashCode *shorthash) { memset(shorthash, 0, sizeof(*shorthash)); GNUNET_memcpy(shorthash, &member, sizeof(member)); } void -util_set_name_field (const char *name, char** field) +util_set_name_field (const char *name, char **field) { if (*field) GNUNET_free(*field); @@ -43,3 +43,147 @@ util_set_name_field (const char *name, char** field) else *field = NULL; } + +int +util_hash_file (const char *filename, struct GNUNET_HashCode *hash) +{ + uint64_t size; + + if (GNUNET_OK != GNUNET_DISK_file_size(filename, &size, GNUNET_NO, GNUNET_YES)) + return GNUNET_SYSERR; + + struct GNUNET_DISK_FileHandle *file = GNUNET_DISK_file_open( + filename, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_USER_READ + ); + + if (!file) + return GNUNET_SYSERR; + + struct GNUNET_DISK_MapHandle *mapping; + const void* data = GNUNET_DISK_file_map( + file, &mapping, GNUNET_DISK_MAP_TYPE_READ, size + ); + + if (!data) + { + GNUNET_DISK_file_close(file); + return GNUNET_SYSERR; + } + + GNUNET_CRYPTO_hash(data, size, hash); + + GNUNET_DISK_file_unmap(mapping); + GNUNET_DISK_file_close(file); + + return GNUNET_OK; +} + +int +util_encrypt_file (const char *filename, + const struct GNUNET_CRYPTO_SymmetricSessionKey *key) +{ + uint64_t size; + + if (GNUNET_OK != GNUNET_DISK_file_size(filename, &size, GNUNET_NO, GNUNET_YES)) + return GNUNET_SYSERR; + + struct GNUNET_DISK_FileHandle *file = GNUNET_DISK_file_open( + filename, GNUNET_DISK_OPEN_READWRITE, + GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE + ); + + if (!file) + return GNUNET_SYSERR; + + struct GNUNET_DISK_MapHandle *mapping; + void* data = GNUNET_DISK_file_map( + file, &mapping, GNUNET_DISK_MAP_TYPE_READWRITE, size + ); + + if (!data) + { + GNUNET_DISK_file_close(file); + return GNUNET_SYSERR; + } + + struct GNUNET_CRYPTO_SymmetricInitializationVector iv; + memset(&iv, 0, sizeof(iv)); + + ssize_t result = GNUNET_CRYPTO_symmetric_encrypt(data, size, key, &iv, data); + + if (GNUNET_OK != GNUNET_DISK_file_unmap(mapping)) + result = -1; + + if (GNUNET_OK != GNUNET_DISK_file_sync(file)) + result = -1; + + if (GNUNET_OK != GNUNET_DISK_file_close(file)) + result = -1; + + if (result < 0) + return GNUNET_SYSERR; + + return GNUNET_OK; +} + +int +util_decrypt_file (const char *filename, + const struct GNUNET_CRYPTO_SymmetricSessionKey *key) +{ + uint64_t size; + + if (GNUNET_OK != GNUNET_DISK_file_size(filename, &size, GNUNET_NO, GNUNET_YES)) + return GNUNET_SYSERR; + + struct GNUNET_DISK_FileHandle *file = GNUNET_DISK_file_open( + filename, GNUNET_DISK_OPEN_READWRITE, + GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE + ); + + if (!file) + return GNUNET_SYSERR; + + struct GNUNET_DISK_MapHandle *mapping; + void* data = GNUNET_DISK_file_map( + file, &mapping, GNUNET_DISK_MAP_TYPE_READWRITE, size + ); + + if (!data) + { + GNUNET_DISK_file_close(file); + return GNUNET_SYSERR; + } + + struct GNUNET_CRYPTO_SymmetricInitializationVector iv; + memset(&iv, 0, sizeof(iv)); + + ssize_t result = GNUNET_CRYPTO_symmetric_decrypt(data, size, key, &iv, data); + + if (GNUNET_OK != GNUNET_DISK_file_unmap(mapping)) + result = -1; + + if (GNUNET_OK != GNUNET_DISK_file_sync(file)) + result = -1; + + if (GNUNET_OK != GNUNET_DISK_file_close(file)) + result = -1; + + if (result < 0) + return GNUNET_SYSERR; + + return GNUNET_OK; +} + +int +util_get_filename (const char *directory, const struct GNUNET_HashCode *hash, + char **filename) +{ + return GNUNET_asprintf ( + filename, + "%s%s%c%s", + directory, + "files", + DIR_SEPARATOR, + GNUNET_h2s_full(hash) + ); +} diff --git a/src/gnunet_chat_util.h b/src/gnunet_chat_util.h @@ -27,14 +27,31 @@ #include <gnunet/platform.h> #include <gnunet/gnunet_common.h> +#include <gnunet/gnunet_crypto_lib.h> +#include <gnunet/gnunet_disk_lib.h> #include <gnunet/gnunet_messenger_service.h> #include <gnunet/gnunet_util_lib.h> void util_shorthash_from_member (const struct GNUNET_MESSENGER_Contact *member, - struct GNUNET_ShortHashCode* shorthash); + struct GNUNET_ShortHashCode *shorthash); void -util_set_name_field (const char *name, char** field); +util_set_name_field (const char *name, char **field); + +int +util_hash_file (const char *filename, struct GNUNET_HashCode *hash); + +int +util_encrypt_file (const char *filename, + const struct GNUNET_CRYPTO_SymmetricSessionKey *key); + +int +util_decrypt_file (const char *filename, + const struct GNUNET_CRYPTO_SymmetricSessionKey *key); + +int +util_get_filename (const char *directory, const struct GNUNET_HashCode *hash, + char **filename); #endif /* GNUNET_CHAT_UTIL_H_ */