/*
This file is part of GNUnet.
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
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 .
SPDX-License-Identifier: AGPL3.0-or-later
*/
/*
* @author Tobias Frisch
* @file gnunet_chat_lib.c
*/
#include "gnunet_chat_lib.h"
#include
#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"
#include "gnunet_chat_lib_intern.c"
struct GNUNET_CHAT_Handle*
GNUNET_CHAT_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
const char *directory,
const char *name,
GNUNET_CHAT_ContextMessageCallback msg_cb, void *msg_cls)
{
if (!cfg)
return NULL;
return handle_create_from_config(
cfg, directory, name,
msg_cb, msg_cls
);
}
void
GNUNET_CHAT_stop (struct GNUNET_CHAT_Handle *handle)
{
if (!handle)
return;
handle_destroy(handle);
}
int
GNUNET_CHAT_update (struct GNUNET_CHAT_Handle *handle)
{
if (!handle)
return GNUNET_SYSERR;
return GNUNET_MESSENGER_update(handle->messenger);
}
int
GNUNET_CHAT_set_name (struct GNUNET_CHAT_Handle *handle,
const char *name)
{
if (!handle)
return GNUNET_SYSERR;
if (!name)
return GNUNET_NO;
return GNUNET_MESSENGER_set_name(handle->messenger, name);
}
const char*
GNUNET_CHAT_get_name (const struct GNUNET_CHAT_Handle *handle)
{
if (!handle)
return NULL;
return GNUNET_MESSENGER_get_name(handle->messenger);
}
const char*
GNUNET_CHAT_get_key (const struct GNUNET_CHAT_Handle *handle)
{
if (!handle)
return NULL;
return handle->public_key;
}
void
GNUNET_CHAT_set_user_pointer (struct GNUNET_CHAT_Handle *handle,
void *user_pointer)
{
if (!handle)
return;
handle->user_pointer = user_pointer;
}
void*
GNUNET_CHAT_get_user_pointer (const struct GNUNET_CHAT_Handle *handle)
{
if (!handle)
return NULL;
return handle->user_pointer;
}
int
GNUNET_CHAT_iterate_contacts (struct GNUNET_CHAT_Handle *handle,
GNUNET_CHAT_ContactCallback callback,
void *cls)
{
if (!handle)
return GNUNET_SYSERR;
struct GNUNET_CHAT_HandleIterateContacts it;
it.handle = handle;
it.cb = callback;
it.cls = cls;
return GNUNET_CONTAINER_multishortmap_iterate(
handle->contacts, it_handle_iterate_contacts, &it
);
}
struct GNUNET_CHAT_Group *
GNUNET_CHAT_group_create (struct GNUNET_CHAT_Handle *handle,
const char* topic)
{
if (!handle)
return NULL;
struct GNUNET_HashCode key;
if (topic)
GNUNET_CRYPTO_hash(topic, strlen(topic), &key);
else
GNUNET_CRYPTO_random_block(GNUNET_CRYPTO_QUALITY_WEAK, &key, sizeof(key));
if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(
handle->contexts, &key))
return NULL;
struct GNUNET_MESSENGER_Room *room = GNUNET_MESSENGER_open_room(
handle->messenger, &key
);
if (!room)
return NULL;
struct GNUNET_CHAT_Context *context = context_create_from_room(handle, room);
handle_send_room_name(handle, room);
context->type = GNUNET_CHAT_CONTEXT_TYPE_GROUP;
if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put(
handle->contexts, &key, context,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
goto destroy_context;
struct GNUNET_CHAT_Group *group = group_create_from_context(handle, context);
util_set_name_field(topic, &(group->topic));
if (group->topic)
group_publish(group);
if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(
handle->groups, &key, group,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
return group;
group_destroy(group);
GNUNET_CONTAINER_multihashmap_remove(handle->contexts, &key, context);
destroy_context:
context_destroy(context);
return NULL;
}
int
GNUNET_CHAT_iterate_groups (struct GNUNET_CHAT_Handle *handle,
GNUNET_CHAT_GroupCallback callback,
void *cls)
{
if (!handle)
return GNUNET_SYSERR;
struct GNUNET_CHAT_HandleIterateGroups it;
it.handle = handle;
it.cb = callback;
it.cls = cls;
return GNUNET_CONTAINER_multihashmap_iterate(
handle->groups, it_handle_iterate_groups, &it
);
}
int
GNUNET_CHAT_contact_delete (struct GNUNET_CHAT_Contact *contact)
{
if (!contact)
return GNUNET_SYSERR;
struct GNUNET_ShortHashCode shorthash;
util_shorthash_from_member(contact->member, &shorthash);
GNUNET_CONTAINER_multishortmap_remove(
contact->handle->contacts, &shorthash, contact
);
const struct GNUNET_HashCode *key = GNUNET_MESSENGER_room_get_key(
contact->context->room
);
GNUNET_CONTAINER_multihashmap_remove(
contact->handle->contexts, key, contact->context
);
GNUNET_MESSENGER_close_room(contact->context->room);
context_destroy(contact->context);
contact_destroy(contact);
return GNUNET_OK;
}
void
GNUNET_CHAT_contact_set_name (struct GNUNET_CHAT_Contact *contact,
const char *name)
{
if ((!contact) || (!(contact->context)))
return;
context_update_nick(contact->context, name);
}
const char*
GNUNET_CHAT_contact_get_name (const struct GNUNET_CHAT_Contact *contact)
{
if (!contact)
return NULL;
if ((contact->context) && (contact->context->nick))
return contact->context->nick;
return GNUNET_MESSENGER_contact_get_name(contact->member);
}
const char*
GNUNET_CHAT_contact_get_key (const struct GNUNET_CHAT_Contact *contact)
{
if (!contact)
return NULL;
return contact->public_key;
}
struct GNUNET_CHAT_Context*
GNUNET_CHAT_contact_get_context (struct GNUNET_CHAT_Contact *contact)
{
if (!contact)
return NULL;
if (contact->context)
return contact->context;
struct GNUNET_CHAT_Context *context = contact_find_context(contact);
if ((context) && (GNUNET_CHAT_CONTEXT_TYPE_CONTACT == context->type))
return context;
context = context_create_from_contact(contact->handle, contact->member);
if (context)
contact->context = context;
return context;
}
void
GNUNET_CHAT_contact_set_user_pointer (struct GNUNET_CHAT_Contact *contact,
void *user_pointer)
{
if (!contact)
return;
contact->user_pointer = user_pointer;
}
void*
GNUNET_CHAT_contact_get_user_pointer (const struct GNUNET_CHAT_Contact *contact)
{
if (!contact)
return NULL;
return contact->user_pointer;
}
int
GNUNET_CHAT_contact_is_owned (const struct GNUNET_CHAT_Contact *contact)
{
if (!contact)
return GNUNET_SYSERR;
return contact->is_owned;
}
int
GNUNET_CHAT_group_leave (struct GNUNET_CHAT_Group *group)
{
if (!group)
return GNUNET_SYSERR;
const struct GNUNET_HashCode *key = GNUNET_MESSENGER_room_get_key(
group->context->room
);
GNUNET_CONTAINER_multihashmap_remove(
group->handle->groups, key, group
);
GNUNET_CONTAINER_multihashmap_remove(
group->handle->contexts, key, group->context
);
GNUNET_MESSENGER_close_room(group->context->room);
context_destroy(group->context);
group_destroy(group);
return GNUNET_OK;
}
void
GNUNET_CHAT_group_set_name (struct GNUNET_CHAT_Group *group,
const char *name)
{
if (!group)
return;
util_set_name_field(name, &(group->context->nick));
}
const char*
GNUNET_CHAT_group_get_name (const struct GNUNET_CHAT_Group *group)
{
if (!group)
return NULL;
return group->context->nick;
}
void
GNUNET_CHAT_group_set_user_pointer (struct GNUNET_CHAT_Group *group,
void *user_pointer)
{
if (!group)
return;
group->user_pointer = user_pointer;
}
void*
GNUNET_CHAT_group_get_user_pointer (const struct GNUNET_CHAT_Group *group)
{
if (!group)
return NULL;
return group->user_pointer;
}
void
GNUNET_CHAT_group_invite_contact (const struct GNUNET_CHAT_Group *group,
struct GNUNET_CHAT_Contact *contact)
{
if ((!group) || (!contact))
return;
struct GNUNET_CHAT_Context *context = contact_find_context(contact);
if (!context)
return;
const struct GNUNET_HashCode *key = GNUNET_MESSENGER_room_get_key(
group->context->room
);
handle_send_room_name(group->handle, GNUNET_MESSENGER_open_room(
group->handle->messenger, key
));
struct GNUNET_MESSENGER_Message msg;
msg.header.kind = GNUNET_MESSENGER_KIND_INVITE;
GNUNET_CRYPTO_get_peer_identity(group->handle->cfg, &(msg.body.invite.door));
GNUNET_memcpy(&(msg.body.invite.key), key, sizeof(msg.body.invite.key));
GNUNET_MESSENGER_send_message(context->room, &msg, contact->member);
}
int
GNUNET_CHAT_group_iterate_contacts (const struct GNUNET_CHAT_Group *group,
GNUNET_CHAT_GroupContactCallback callback,
void *cls)
{
if (!group)
return GNUNET_SYSERR;
struct GNUNET_CHAT_GroupIterateContacts it;
it.group = group;
it.cb = callback;
it.cls = cls;
return GNUNET_MESSENGER_iterate_members(
group->context->room, it_group_iterate_contacts, &it
);
}
struct GNUNET_CHAT_Context*
GNUNET_CHAT_group_get_context (struct GNUNET_CHAT_Group *group)
{
if (!group)
return NULL;
return group->context;
}
int
GNUNET_CHAT_context_get_status (const struct GNUNET_CHAT_Context *context)
{
if ((!context) || (!(context->room)))
return GNUNET_SYSERR;
if (1 >= GNUNET_MESSENGER_iterate_members(context->room, NULL, NULL))
return GNUNET_NO;
return GNUNET_OK;
}
void
GNUNET_CHAT_context_request (struct GNUNET_CHAT_Context *context)
{
if ((!context) || (context->room))
return;
struct GNUNET_CHAT_Handle *handle = context->handle;
if ((!handle) || (!(context->contact)))
return;
struct GNUNET_CHAT_Contact *contact = contact_create_from_member(
handle, context->contact
);
if (!contact)
return;
context->type = GNUNET_CHAT_CONTEXT_TYPE_CONTACT;
struct GNUNET_CHAT_Context *other = contact_find_context(contact);
if ((!other) || (!(other->room)))
return;
struct GNUNET_HashCode key;
GNUNET_CRYPTO_random_block(GNUNET_CRYPTO_QUALITY_WEAK, &key, sizeof(key));
if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(
handle->contexts, &key))
return;
struct GNUNET_MESSENGER_Room *room = GNUNET_MESSENGER_open_room(
handle->messenger, &key
);
if (!room)
return;
context_update_room(context, room);
handle_send_room_name(handle, room);
struct GNUNET_MESSENGER_Message msg;
msg.header.kind = GNUNET_MESSENGER_KIND_INVITE;
GNUNET_CRYPTO_get_peer_identity(handle->cfg, &(msg.body.invite.door));
GNUNET_memcpy(&(msg.body.invite.key), &key, sizeof(msg.body.invite.key));
GNUNET_MESSENGER_send_message(other->room, &msg, context->contact);
}
const struct GNUNET_CHAT_Contact*
GNUNET_CHAT_context_get_contact (const struct GNUNET_CHAT_Context *context)
{
if ((!context) || (GNUNET_CHAT_CONTEXT_TYPE_CONTACT != context->type))
return NULL;
if (context->contact)
return handle_get_contact_from_messenger(context->handle, context->contact);
struct GNUNET_MESSENGER_Room *room = context->room;
struct GNUNET_CHAT_RoomFindContact find;
find.ignore_key = GNUNET_MESSENGER_get_key(context->handle->messenger);
find.contact = NULL;
int member_count = GNUNET_MESSENGER_iterate_members(
room,
it_room_find_contact,
&find
);
if ((!find.contact) || (member_count > 2))
return NULL;
return handle_get_contact_from_messenger(context->handle, find.contact);
}
const struct GNUNET_CHAT_Group*
GNUNET_CHAT_context_get_group (const struct GNUNET_CHAT_Context *context)
{
if ((!context) || (GNUNET_CHAT_CONTEXT_TYPE_GROUP != context->type))
return NULL;
if (!(context->room))
return NULL;
return handle_get_group_from_messenger(context->handle, context->room);
}
void
GNUNET_CHAT_context_set_user_pointer (struct GNUNET_CHAT_Context *context,
void *user_pointer)
{
if (!context)
return;
context->user_pointer = user_pointer;
}
void*
GNUNET_CHAT_context_get_user_pointer (const struct GNUNET_CHAT_Context *context)
{
if (!context)
return NULL;
return context->user_pointer;
}
int
GNUNET_CHAT_context_send_text (struct GNUNET_CHAT_Context *context,
const char *text)
{
if ((!context) || (!text) || (!(context->room)))
return GNUNET_SYSERR;
struct GNUNET_MESSENGER_Message msg;
msg.header.kind = GNUNET_MESSENGER_KIND_TEXT;
msg.body.text.text = GNUNET_strdup(text);
GNUNET_MESSENGER_send_message(context->room, &msg, NULL);
GNUNET_free(msg.body.text.text);
return GNUNET_OK;
}
struct GNUNET_CHAT_File*
GNUNET_CHAT_context_send_file (struct GNUNET_CHAT_Context *context,
const char *path,
GNUNET_CHAT_FileUploadCallback callback,
void *cls)
{
if ((!context) || (!path) || (!(context->room)))
return NULL;
if (!(context->handle->directory))
return NULL;
struct GNUNET_HashCode hash;
if (GNUNET_OK != util_hash_file(path, &hash))
return NULL;
struct GNUNET_CHAT_File *file = GNUNET_CONTAINER_multihashmap_get(
context->handle->files,
&hash
);
char *filename;
util_get_filename (
context->handle->directory, "files", &hash, &filename
);
if (file)
goto file_upload;
if ((GNUNET_YES == GNUNET_DISK_file_test(filename)) ||
(GNUNET_OK != GNUNET_DISK_directory_create_for_file(filename)) ||
(GNUNET_OK != GNUNET_DISK_file_copy(path, filename)))
{
GNUNET_free(filename);
return NULL;
}
struct GNUNET_CRYPTO_SymmetricSessionKey key;
GNUNET_CRYPTO_symmetric_create_session_key(&key);
if (GNUNET_OK != util_encrypt_file(filename, &key))
{
GNUNET_free(filename);
return NULL;
}
char* p = GNUNET_strdup(path);
file = file_create_from_disk(
context->handle,
basename(p),
&hash,
&key
);
GNUNET_free(p);
if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put(
context->handle->files, &hash, file,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
{
file_destroy(file);
GNUNET_free(filename);
return NULL;
}
file_upload:
file_bind_upload(file, context, callback, cls);
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);
return file;
}
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) ||
(!(context->room)))
return GNUNET_SYSERR;
struct GNUNET_MESSENGER_Message msg;
msg.header.kind = GNUNET_MESSENGER_KIND_FILE;
GNUNET_memcpy(&(msg.body.file.key), &(file->key), sizeof(file->key));
GNUNET_memcpy(&(msg.body.file.hash), &(file->hash), sizeof(file->hash));
GNUNET_strlcpy(msg.body.file.name, file->name, NAME_MAX);
msg.body.file.uri = GNUNET_FS_uri_to_string(file->uri);
GNUNET_MESSENGER_send_message(context->room, &msg, NULL);
GNUNET_free(msg.body.file.uri);
return GNUNET_OK;
}
int
GNUNET_CHAT_context_iterate_messages (struct GNUNET_CHAT_Context *context,
GNUNET_CHAT_ContextMessageCallback callback,
void *cls)
{
if (!context)
return GNUNET_SYSERR;
struct GNUNET_CHAT_ContextIterateMessages it;
it.context = context;
it.cb = callback;
it.cls = cls;
return GNUNET_CONTAINER_multihashmap_iterate(
context->messages, it_context_iterate_messages, &it
);
}
int
GNUNET_CHAT_context_iterate_files (struct GNUNET_CHAT_Context *context,
GNUNET_CHAT_ContextFileCallback callback,
void *cls)
{
if (!context)
return GNUNET_SYSERR;
struct GNUNET_CHAT_ContextIterateFiles it;
it.context = context;
it.cb = callback;
it.cls = cls;
return GNUNET_CONTAINER_multihashmap_iterate(
context->files, it_context_iterate_files, &it
);
}
enum GNUNET_CHAT_MessageKind
GNUNET_CHAT_message_get_kind (const struct GNUNET_CHAT_Message *message)
{
if (!message)
return GNUNET_CHAT_KIND_UNKNOWN;
switch (message->flag)
{
case GNUNET_CHAT_FLAG_WARNING:
return GNUNET_CHAT_KIND_WARNING;
case GNUNET_CHAT_FLAG_LOGIN:
return GNUNET_CHAT_KIND_LOGIN;
case GNUNET_CHAT_FLAG_UPDATE:
return GNUNET_CHAT_KIND_UPDATE;
default:
break;
}
if (!(message->msg))
return GNUNET_CHAT_KIND_UNKNOWN;
switch (message->msg->header.kind)
{
case GNUNET_MESSENGER_KIND_JOIN:
return GNUNET_CHAT_KIND_JOIN;
case GNUNET_MESSENGER_KIND_LEAVE:
return GNUNET_CHAT_KIND_LEAVE;
case GNUNET_MESSENGER_KIND_NAME:
case GNUNET_MESSENGER_KIND_KEY:
case GNUNET_MESSENGER_KIND_ID:
return GNUNET_CHAT_KIND_CONTACT;
case GNUNET_MESSENGER_KIND_INVITE:
return GNUNET_CHAT_KIND_INVITATION;
case GNUNET_MESSENGER_KIND_TEXT:
return GNUNET_CHAT_KIND_TEXT;
case GNUNET_MESSENGER_KIND_FILE:
return GNUNET_CHAT_KIND_FILE;
case GNUNET_MESSENGER_KIND_DELETE:
return GNUNET_CHAT_KIND_DELETION;
default:
return GNUNET_CHAT_KIND_UNKNOWN;
}
}
struct GNUNET_TIME_Absolute
GNUNET_CHAT_message_get_timestamp (const struct GNUNET_CHAT_Message *message)
{
if ((!message) || (!(message->msg)))
return GNUNET_TIME_absolute_get_zero_();
return GNUNET_TIME_absolute_ntoh(message->msg->header.timestamp);
}
struct GNUNET_CHAT_Contact*
GNUNET_CHAT_message_get_sender (const struct GNUNET_CHAT_Message *message)
{
if ((!message) || (GNUNET_CHAT_FLAG_NONE != message->flag) ||
(!(message->context)) || (!(message->context->room)))
return NULL;
const struct GNUNET_MESSENGER_Contact *sender = GNUNET_MESSENGER_get_sender(
message->context->room, &(message->hash)
);
if (!sender)
return NULL;
return handle_get_contact_from_messenger(message->context->handle, sender);
}
int
GNUNET_CHAT_message_is_sent (const struct GNUNET_CHAT_Message *message)
{
if (!message)
return GNUNET_SYSERR;
if (message->flags & GNUNET_MESSENGER_FLAG_SENT)
return GNUNET_YES;
else
return GNUNET_NO;
}
int
GNUNET_CHAT_message_is_private (const struct GNUNET_CHAT_Message *message)
{
if (!message)
return GNUNET_SYSERR;
if (message->flags & GNUNET_MESSENGER_FLAG_PRIVATE)
return GNUNET_YES;
else
return GNUNET_NO;
}
int
GNUNET_CHAT_message_get_read_receipt (const struct GNUNET_CHAT_Message *message,
GNUNET_CHAT_MessageReadReceiptCallback callback,
void *cls)
{
if ((!message) || (!(message->msg)) || (!(message->context)))
return GNUNET_SYSERR;
struct GNUNET_CHAT_MessageIterateReadReceipts it;
it.message = message;
it.cb = callback;
it.cls = cls;
return GNUNET_MESSENGER_iterate_members(
message->context->room, it_message_iterate_read_receipts, &it
);
}
const char*
GNUNET_CHAT_message_get_text (const struct GNUNET_CHAT_Message *message)
{
if ((!message) || (!(message->msg)))
return NULL;
if (GNUNET_CHAT_FLAG_WARNING == message->flag)
return message->warning;
if (GNUNET_MESSENGER_KIND_TEXT != message->msg->header.kind)
return NULL;
return message->msg->body.text.text;
}
struct GNUNET_CHAT_File*
GNUNET_CHAT_message_get_file (const struct GNUNET_CHAT_Message *message)
{
if ((!message) || (!(message->msg)) || (!(message->context)))
return NULL;
if (GNUNET_MESSENGER_KIND_FILE != message->msg->header.kind)
return NULL;
return GNUNET_CONTAINER_multihashmap_get(
message->context->handle->files,
&(message->msg->body.file.hash)
);
}
struct GNUNET_CHAT_Invitation*
GNUNET_CHAT_message_get_invitation (const struct GNUNET_CHAT_Message *message)
{
if ((!message) || (!(message->msg)) || (!(message->context)))
return NULL;
if (GNUNET_MESSENGER_KIND_INVITE != message->msg->header.kind)
return NULL;
return GNUNET_CONTAINER_multihashmap_get(
message->context->invites,
&(message->hash)
);
}
int
GNUNET_CHAT_message_delete (const struct GNUNET_CHAT_Message *message,
struct GNUNET_TIME_Relative delay)
{
if ((!message) || (!(message->msg)) || (!(message->context)))
return GNUNET_SYSERR;
struct GNUNET_MESSENGER_Message msg;
msg.header.kind = GNUNET_MESSENGER_KIND_DELETE;
GNUNET_memcpy(&(msg.body.deletion.hash), &(message->hash), sizeof(message->hash));
msg.body.deletion.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)
{
if (!file)
return NULL;
return &(file->hash);
}
uint64_t
GNUNET_CHAT_file_get_size (const struct GNUNET_CHAT_File *file)
{
if (!file)
return 0;
if (file->uri)
return GNUNET_FS_uri_chk_get_file_size(file->uri);
char *filename;
util_get_filename (
file->handle->directory, "files", &(file->hash), &filename
);
uint64_t size;
if (GNUNET_OK != GNUNET_DISK_file_size(filename, &size, GNUNET_NO, GNUNET_YES))
size = 0;
GNUNET_free(filename);
return size;
}
int
GNUNET_CHAT_file_is_local (const struct GNUNET_CHAT_File *file)
{
if (!file)
return GNUNET_SYSERR;
char *filename;
util_get_filename (
file->handle->directory, "files", &(file->hash), &filename
);
int result = GNUNET_DISK_file_test(filename);
GNUNET_free(filename);
return result;
}
void
GNUNET_CHAT_file_set_user_pointer (struct GNUNET_CHAT_File *file,
void *user_pointer)
{
if (!file)
return;
file->user_pointer = user_pointer;
}
void*
GNUNET_CHAT_file_get_user_pointer (const struct GNUNET_CHAT_File *file)
{
if (!file)
return NULL;
return file->user_pointer;
}
int
GNUNET_CHAT_file_start_download (struct GNUNET_CHAT_File *file,
GNUNET_CHAT_FileDownloadCallback callback,
void *cls)
{
if ((!file) || (!(file->uri)))
return GNUNET_SYSERR;
if (file->download)
{
file_bind_downlaod(file, callback, cls);
GNUNET_FS_download_resume(file->download);
return GNUNET_OK;
}
const uint64_t size = GNUNET_FS_uri_chk_get_file_size(file->uri);
char *filename;
util_get_filename (
file->handle->directory, "files", &(file->hash), &filename
);
uint64_t offset;
if (GNUNET_OK != GNUNET_DISK_file_size(filename, &offset, GNUNET_NO, GNUNET_YES))
offset = 0;
if (offset >= size)
{
if (callback)
callback(cls, file, size, size);
return GNUNET_OK;
}
file_bind_downlaod(file, callback, cls);
const uint64_t remaining = (size - offset);
file->download = GNUNET_FS_download_start(
file->handle->fs,
file->uri,
file->meta,
filename,
NULL,
offset,
remaining,
1,
GNUNET_FS_DOWNLOAD_OPTION_NONE,
file,
NULL
);
GNUNET_free(filename);
return GNUNET_OK;
}
int
GNUNET_CHAT_file_pause_download (struct GNUNET_CHAT_File *file)
{
if (!file)
return GNUNET_SYSERR;
GNUNET_FS_download_suspend(file->download);
return GNUNET_OK;
}
int
GNUNET_CHAT_file_resume_download (struct GNUNET_CHAT_File *file)
{
if (!file)
return GNUNET_SYSERR;
GNUNET_FS_download_resume(file->download);
return GNUNET_OK;
}
int
GNUNET_CHAT_file_stop_download (struct GNUNET_CHAT_File *file)
{
if (!file)
return GNUNET_SYSERR;
GNUNET_FS_download_stop(file->download, GNUNET_YES);
file->download = NULL;
return GNUNET_OK;
}
int
GNUNET_CHAT_file_unindex (struct GNUNET_CHAT_File *file,
GNUNET_CHAT_FileUnindexCallback callback,
void *cls)
{
if (!file)
return GNUNET_SYSERR;
if (file->publish)
{
GNUNET_FS_publish_stop(file->publish);
file->publish = NULL;
return GNUNET_OK;
}
file_bind_unindex(file, callback, cls);
if (file->unindex)
return GNUNET_OK;
char *filename;
util_get_filename (
file->handle->directory, "files", &(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)
{
if (!invitation)
return;
struct GNUNET_PeerIdentity door;
GNUNET_PEER_resolve(invitation->door, &door);
GNUNET_MESSENGER_enter_room(
invitation->context->handle->messenger,
&door, &(invitation->key)
);
}