From 3f72d34c498113a00bc052747a74a2b267e123ad Mon Sep 17 00:00:00 2001 From: Evangelos Ribeiro Tzaras Date: Mon, 26 Apr 2021 17:19:21 +0200 Subject: [PATCH] Add CallsCredentials class and use it in CallsSipProvider CallsCredentials is a dumb container to store account credentials. This is done in preparation for the account management in the UI. --- plugins/sip/calls-sip-provider.c | 63 ++--- src/calls-credentials.c | 391 +++++++++++++++++++++++++++++++ src/calls-credentials.h | 42 ++++ src/meson.build | 1 + 4 files changed, 450 insertions(+), 47 deletions(-) create mode 100644 src/calls-credentials.c create mode 100644 src/calls-credentials.h diff --git a/plugins/sip/calls-sip-provider.c b/plugins/sip/calls-sip-provider.c index 10579d1..c4c7b54 100644 --- a/plugins/sip/calls-sip-provider.c +++ b/plugins/sip/calls-sip-provider.c @@ -26,6 +26,7 @@ #define SIP_ACCOUNT_FILE "sip-account.cfg" +#include "calls-credentials.h" #include "calls-message-source.h" #include "calls-provider.h" #include "calls-sip-enums.h" @@ -75,26 +76,6 @@ G_DEFINE_DYNAMIC_TYPE_EXTENDED calls_sip_provider_message_source_interface_init)); -static gboolean -check_required_keys (GKeyFile *key_file, - const gchar *group_name) -{ - gchar *keys[] = { - "User", - "Password", - "Host", - "Protocol", - }; - - for (gsize i = 0; i < G_N_ELEMENTS (keys); i++) { - if (!g_key_file_has_key (key_file, group_name, keys[i], NULL)) - return FALSE; - } - - return TRUE; -} - - static void calls_sip_provider_load_accounts (CallsSipProvider *self) { @@ -112,48 +93,36 @@ calls_sip_provider_load_accounts (CallsSipProvider *self) groups = g_key_file_get_groups (key_file, NULL); for (gsize i = 0; groups[i] != NULL; i++) { + g_autoptr (CallsCredentials) credentials = calls_credentials_new (); g_autofree gchar *user = NULL; g_autofree gchar *password = NULL; g_autofree gchar *host = NULL; g_autofree gchar *protocol = NULL; gint port = 0; gint local_port = 0; + gboolean auto_connect = TRUE; gboolean direct_connection = g_key_file_get_boolean (key_file, groups[i], "Direct", NULL); - gboolean auto_connect = TRUE; - - if (g_key_file_has_key (key_file, groups[i], "AutoConnect", NULL)) - auto_connect = g_key_file_get_boolean (key_file, groups[i], "AutoConnect", NULL); if (direct_connection) { - local_port = 5060; + local_port = g_key_file_get_integer (key_file, groups[i], "LocalPort", NULL); + if (local_port == 0) + local_port = 5060; + protocol = g_strdup ("UDP"); goto skip; } - if (!check_required_keys (key_file, groups[i])) { - g_warning ("Not all required keys found in section %s of file `%s'", - groups[i], self->filename); - continue; - } - - user = g_key_file_get_string (key_file, groups[i], "User", NULL); - password = g_key_file_get_string (key_file, groups[i], "Password", NULL); - host = g_key_file_get_string (key_file, groups[i], "Host", NULL); - protocol = g_key_file_get_string (key_file, groups[i], "Protocol", NULL); - port = g_key_file_get_integer (key_file, groups[i], "Port", NULL); - local_port = g_key_file_get_integer (key_file, groups[i], "LocalPort", NULL); + calls_credentials_update_from_keyfile (credentials, key_file, groups[i]); + g_object_get (G_OBJECT (credentials), + "host", &host, + "user", &user, + "password", &password, + "port", &port, + "protocol", &protocol, + "auto-connect", &auto_connect, + NULL); skip: - if (protocol == NULL) - protocol = g_strdup ("UDP"); - - /* If Protocol is TLS fall back to port 5061, 5060 otherwise */ - if (port == 0) { - if (g_strcmp0 (protocol, "TLS") == 0) - port = 5061; - else - port = 5060; - } g_debug ("Adding origin for SIP account %s", groups[i]); diff --git a/src/calls-credentials.c b/src/calls-credentials.c new file mode 100644 index 0000000..41508df --- /dev/null +++ b/src/calls-credentials.c @@ -0,0 +1,391 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * This file is part of Calls. + * + * Calls is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calls 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calls. If not, see . + * + * Author: Evangelos Ribeiro Tzaras + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#define G_LOG_DOMAIN "CallsCredentials" + +#include "calls-credentials.h" + +/** + * SECTION:Credentials + * @short_description: Credentials for online accounts + * @Title: CallsCredentials + * + * #CallsCredentials represents account credentials f.e. for SIP. + */ + +enum { + PROP_0, + PROP_NAME, + PROP_ACC_HOST, + PROP_ACC_DISPLAY_NAME, + PROP_ACC_USER, + PROP_ACC_PASSWORD, + PROP_ACC_PORT, + PROP_ACC_PROTOCOL, + PROP_ACC_AUTO_CONNECT, + PROP_LAST_PROP, +}; +static GParamSpec *props[PROP_LAST_PROP]; + +enum { + SIGNAL_ACCOUNT_UPDATED, + SIGNAL_LAST_SIGNAL, +}; +static guint signals[SIGNAL_LAST_SIGNAL]; + +struct _CallsCredentials +{ + GObject parent_instance; + + char *name; + + /* Account information */ + char *host; + char *display_name; + char *user; + char *password; + gint port; + char *transport_protocol; + + gboolean auto_connect; +}; + + +G_DEFINE_TYPE (CallsCredentials, calls_credentials, G_TYPE_OBJECT) + +static gboolean +check_required_keys (GKeyFile *key_file, + const gchar *group_name) +{ + gchar *keys[] = { + "User", + "Password", + "Host", + }; + + g_assert (group_name); + g_assert (g_key_file_has_group (key_file, group_name)); + + for (gsize i = 0; i < G_N_ELEMENTS (keys); i++) { + if (!g_key_file_has_key (key_file, group_name, keys[i], NULL)) + return FALSE; + } + + return TRUE; +} + + +static void +calls_credentials_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + CallsCredentials *self = CALLS_CREDENTIALS (object); + + switch (property_id) { + case PROP_NAME: + g_free (self->name); + self->name = g_value_dup_string (value); + break; + + case PROP_ACC_HOST: + g_free (self->host); + self->host = g_value_dup_string (value); + break; + + case PROP_ACC_DISPLAY_NAME: + g_free (self->display_name); + self->display_name = g_value_dup_string (value); + break; + + case PROP_ACC_USER: + g_free (self->user); + self->user = g_value_dup_string (value); + break; + + case PROP_ACC_PASSWORD: + g_free (self->password); + self->password = g_value_dup_string (value); + break; + + case PROP_ACC_PORT: + self->port = g_value_get_int (value); + break; + + case PROP_ACC_PROTOCOL: + g_free (self->transport_protocol); + self->transport_protocol = g_value_dup_string (value); + break; + + case PROP_ACC_AUTO_CONNECT: + self->auto_connect = g_value_get_boolean (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +calls_credentials_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + CallsCredentials *self = CALLS_CREDENTIALS (object); + + switch (property_id) { + case PROP_NAME: + g_value_set_string (value, self->name); + break; + + case PROP_ACC_HOST: + g_value_set_string (value, self->host); + break; + + case PROP_ACC_DISPLAY_NAME: + g_value_set_string (value, self->display_name); + break; + + case PROP_ACC_USER: + g_value_set_string (value, self->user); + break; + + case PROP_ACC_PASSWORD: + g_value_set_string (value, self->password); + break; + + case PROP_ACC_PORT: + g_value_set_int (value, self->port); + break; + + case PROP_ACC_PROTOCOL: + g_value_set_string (value, self->transport_protocol); + break; + + case PROP_ACC_AUTO_CONNECT: + g_value_set_boolean (value, self->auto_connect); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +calls_credentials_finalize (GObject *object) +{ + CallsCredentials *self = CALLS_CREDENTIALS (object); + + g_free (self->name); + g_free (self->host); + g_free (self->display_name); + g_free (self->user); + g_free (self->password); + g_free (self->transport_protocol); + + G_OBJECT_CLASS (calls_credentials_parent_class)->finalize (object); +} + + +static void +calls_credentials_class_init (CallsCredentialsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = calls_credentials_set_property; + object_class->get_property = calls_credentials_get_property; + object_class->finalize = calls_credentials_finalize; + + props[PROP_NAME] = + g_param_spec_string ("name", + "Name", + "The name for this set of credentials", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + props[PROP_ACC_HOST] = + g_param_spec_string ("host", + "Host", + "The host to connect to", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + props[PROP_ACC_DISPLAY_NAME] = + g_param_spec_string ("display-name", + "Display name", + "The display name", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + props[PROP_ACC_USER] = + g_param_spec_string ("user", + "User", + "The username", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + props[PROP_ACC_PASSWORD] = + g_param_spec_string ("password", + "Password", + "The password", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + props[PROP_ACC_PORT] = + g_param_spec_int ("port", + "Port", + "The port to connect to", + 0, 65535, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + props[PROP_ACC_PROTOCOL] = + g_param_spec_string ("protocol", + "Protocol", + "The transport protocol to use for the connection", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + props[PROP_ACC_AUTO_CONNECT] = + g_param_spec_boolean ("auto-connect", + "Auto connect", + "Whether to connect automatically", + TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); + + signals[SIGNAL_ACCOUNT_UPDATED] = + g_signal_new ("account-updated", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, + 0); +} + + +static void +calls_credentials_init (CallsCredentials *self) +{ +} + + +CallsCredentials * +calls_credentials_new () +{ + return g_object_new (CALLS_TYPE_CREDENTIALS, NULL); +} + +/** + * calls_credentials_update_from_keyfile: + * @self: A #CallsCredentials + * @key_file: A #GKeyFile + * @name: The name of the credentials which doubles as the option group + * + * Updates the credentials from a given keyfile. + * + * Returns: %TRUE if credentials were updated, %FALSE otherwise + */ +gboolean +calls_credentials_update_from_keyfile (CallsCredentials *self, + GKeyFile *key_file, + const char *name) +{ + char *user = NULL; + char *password = NULL; + char *host = NULL; + char *protocol = NULL; + char *display_name = NULL; + gint port = 0; + gboolean auto_connect = TRUE; + + g_return_val_if_fail (CALLS_IS_CREDENTIALS (self), FALSE); + g_return_val_if_fail (name, FALSE); + g_return_val_if_fail (g_key_file_has_group (key_file, name), FALSE); + + if (!check_required_keys (key_file, name)) { + g_warning ("Not all required keys found in section %s", name); + return FALSE; + } + + user = g_key_file_get_string (key_file, name, "User", NULL); + password = g_key_file_get_string (key_file, name, "Password", NULL); + host = g_key_file_get_string (key_file, name, "Host", NULL); + protocol = g_key_file_get_string (key_file, name, "Protocol", NULL); + port = g_key_file_get_integer (key_file, name, "Port", NULL); + display_name = g_key_file_get_string (key_file, name, "DisplayName", NULL); + + if (g_key_file_has_key (key_file, name, "AutoConnect", NULL)) + auto_connect = g_key_file_get_boolean (key_file, name, "AutoConnect", NULL); + + if (protocol == NULL) + protocol = g_strdup ("UDP"); + + if (g_strcmp0 (host, "") == 0 || + g_strcmp0 (user, "") == 0 || + g_strcmp0 (password, "") == 0) { + g_warning ("Host, user and password must not be empty"); + + g_free (user); + g_free (password); + g_free (host); + g_free (protocol); + g_free (display_name); + + return FALSE; + } + + g_free (self->name); + self->name = g_strdup (name); + + g_free (self->host); + self->host = host; + + g_free (self->user); + self->user = user; + + g_free (self->password); + self->password = password; + + g_free (self->transport_protocol); + self->transport_protocol = protocol; + + g_free (self->display_name); + self->display_name = display_name; + + self->port = port; + self->auto_connect = auto_connect; + + g_debug ("Updated credentials with name %s", name); + + g_signal_emit (self, signals[SIGNAL_ACCOUNT_UPDATED], 0); + + return TRUE; +} diff --git a/src/calls-credentials.h b/src/calls-credentials.h new file mode 100644 index 0000000..8ff192b --- /dev/null +++ b/src/calls-credentials.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * This file is part of Calls. + * + * Calls is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calls 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calls. If not, see . + * + * Author: Evangelos Ribeiro Tzaras + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define CALLS_TYPE_CREDENTIALS (calls_credentials_get_type ()) + +G_DECLARE_FINAL_TYPE (CallsCredentials, calls_credentials, CALLS, CREDENTIALS, GObject); + + +CallsCredentials *calls_credentials_new (); +gboolean calls_credentials_update_from_keyfile (CallsCredentials *self, + GKeyFile *key_file, + const char *name); + +G_END_DECLS + diff --git a/src/meson.build b/src/meson.build index 6225b17..16120d8 100644 --- a/src/meson.build +++ b/src/meson.build @@ -106,6 +106,7 @@ calls_sources = files(['calls-message-source.c', 'calls-message-source.h', 'calls-notifier.c', 'calls-notifier.h', 'calls-contacts-box.c', 'calls-contacts-box.h', 'calls-contacts-row.c', 'calls-contacts-row.h', + 'calls-credentials.c', 'calls-credentials.h', ]) + wayland_sources + calls_generated_sources calls_config_data = config_data