/* 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 chat/messenger.c */ #include "messenger.h" #include "../contact.h" #include "../event.h" int _chat_messenger_destroy_contacts(UNUSED void *cls, UNUSED struct GNUNET_CHAT_Handle *handle, struct GNUNET_CHAT_Contact *contact) { if (contact) contact_destroy_info(contact); return GNUNET_YES; } static void _chat_messenger_quit(void *cls) { MESSENGER_Application *app = (MESSENGER_Application*) cls; if (app->chat.messenger.idle) GNUNET_SCHEDULER_cancel(app->chat.messenger.idle); MESSENGER_ApplicationSignal signal; int received = read(app->chat.pipe[0], &signal, sizeof(signal)); if (received < 0) signal = MESSENGER_FAIL; // Free contact infos GNUNET_CHAT_iterate_contacts( app->chat.messenger.handle, _chat_messenger_destroy_contacts, NULL ); GNUNET_CHAT_stop(app->chat.messenger.handle); app->chat.messenger.handle = NULL; GNUNET_SCHEDULER_shutdown(); } static void _chat_messenger_idle(void *cls) { MESSENGER_Application *app = (MESSENGER_Application*) cls; // Idling until the application shuts down // (required to get events immediately). app->chat.messenger.idle = GNUNET_SCHEDULER_add_delayed_with_priority( GNUNET_TIME_relative_get_second_(), GNUNET_SCHEDULER_PRIORITY_IDLE, &_chat_messenger_idle, app ); } static int _chat_messenger_message(void *cls, struct GNUNET_CHAT_Context *context, const struct GNUNET_CHAT_Message *message) { MESSENGER_Application *app = (MESSENGER_Application*) cls; // Locking the mutex for synchronization pthread_mutex_lock(&(app->chat.mutex)); // Handle each kind of message as proper event regarding context switch (GNUNET_CHAT_message_get_kind(message)) { case GNUNET_CHAT_KIND_WARNING: application_call_message_event( app, event_handle_warning, context, message ); break; case GNUNET_CHAT_KIND_REFRESH: { application_call_event(app, event_refresh_accounts); break; } case GNUNET_CHAT_KIND_LOGIN: { application_call_event(app, event_update_profile); break; } case GNUNET_CHAT_KIND_UPDATE: { application_call_message_event( app, event_update_chats, context, message ); break; } case GNUNET_CHAT_KIND_JOIN: case GNUNET_CHAT_KIND_LEAVE: { application_call_message_event( app, (GNUNET_YES == GNUNET_CHAT_message_is_sent(message)? event_update_chats : event_presence_contact ), context, message ); break; } case GNUNET_CHAT_KIND_CONTACT: { application_call_message_event( app, event_update_contacts, context, message ); break; } case GNUNET_CHAT_KIND_INVITATION: { application_call_message_event( app, event_invitation, context, message ); break; } case GNUNET_CHAT_KIND_TEXT: case GNUNET_CHAT_KIND_FILE: case GNUNET_CHAT_KIND_WHISPER: { application_call_message_event( app, event_receive_message, context, message ); break; } case GNUNET_CHAT_KIND_DELETION: { application_call_message_event( app, event_delete_message, context, message ); break; } default: break; } pthread_mutex_unlock(&(app->chat.mutex)); return GNUNET_YES; } void chat_messenger_run(void *cls, UNUSED char *const *args, UNUSED const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { MESSENGER_Application *app = (MESSENGER_Application*) cls; // Start libgnunetchat handle app->chat.messenger.handle = GNUNET_CHAT_start( cfg, &_chat_messenger_message, app ); // Setup pipe to handle closing the application from the other thread struct GNUNET_NETWORK_FDSet *fd = GNUNET_NETWORK_fdset_create (); GNUNET_NETWORK_fdset_set_native(fd, app->chat.pipe[0]); app->chat.messenger.quit = GNUNET_SCHEDULER_add_select( GNUNET_SCHEDULER_PRIORITY_URGENT, GNUNET_TIME_relative_get_forever_(), fd, NULL, &_chat_messenger_quit, app ); // The idle callback seems to be necessary to not wait too long for // other events app->chat.messenger.idle = GNUNET_SCHEDULER_add_now( &_chat_messenger_idle, app ); GNUNET_NETWORK_fdset_destroy(fd); }