diff --git a/plugins/sip/calls-sip-origin.c b/plugins/sip/calls-sip-origin.c index fd4e8c1..bfc44fd 100644 --- a/plugins/sip/calls-sip-origin.c +++ b/plugins/sip/calls-sip-origin.c @@ -36,6 +36,14 @@ struct _CallsSipOrigin { GObject parent_instance; GString *name; + + /* Account information */ + gchar *user; + gchar *password; + gchar *host; + gchar *protocol; + gboolean use_direct_connection; + GList *calls; }; @@ -51,11 +59,22 @@ G_DEFINE_TYPE_WITH_CODE (CallsSipOrigin, calls_sip_origin, G_TYPE_OBJECT, enum { PROP_0, PROP_NAME, + PROP_ACC_USER, + PROP_ACC_PASSWORD, + PROP_ACC_HOST, + PROP_ACC_PROTOCOL, + PROP_ACC_DIRECT, PROP_CALLS, PROP_LAST_PROP, }; static GParamSpec *props[PROP_LAST_PROP]; +static gboolean +protocol_is_valid (const gchar *protocol) +{ + return g_strcmp0 (protocol, "UDP") == 0 || + g_strcmp0 (protocol, "TLS") == 0; +} static void remove_call (CallsSipOrigin *self, @@ -165,6 +184,37 @@ calls_sip_origin_set_property (GObject *object, switch (property_id) { + 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_HOST: + g_free (self->host); + self->host = g_value_dup_string (value); + break; + + case PROP_ACC_PROTOCOL: + if (!protocol_is_valid (g_value_get_string (value))) { + g_warning ("Tried setting invalid protocol: '%s'\n" + "Continue using old protocol: '%s'", + g_value_get_string (value), self->protocol); + return; + } + + g_free (self->protocol); + self->protocol = g_value_dup_string (value); + break; + + case PROP_ACC_DIRECT: + self->use_direct_connection = g_value_get_boolean (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -189,6 +239,18 @@ calls_sip_origin_get_property (GObject *object, g_value_set_pointer (value, g_list_copy (self->calls)); break; + case PROP_ACC_USER: + g_value_set_string (value, self->user); + break; + + case PROP_ACC_HOST: + g_value_set_string (value, self->host); + break; + + case PROP_ACC_PROTOCOL: + g_value_set_string (value, self->protocol); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -213,6 +275,10 @@ calls_sip_origin_finalize (GObject *object) CallsSipOrigin *self = CALLS_SIP_ORIGIN (object); g_string_free (self->name, TRUE); + g_free (self->user); + g_free (self->password); + g_free (self->host); + g_free (self->protocol); G_OBJECT_CLASS (calls_sip_origin_parent_class)->finalize (object); } @@ -228,6 +294,46 @@ calls_sip_origin_class_init (CallsSipOriginClass *klass) object_class->get_property = calls_sip_origin_get_property; object_class->set_property = calls_sip_origin_set_property; + props[PROP_ACC_USER] = + g_param_spec_string ("user", + "User", + "The username for authentication", + "", + G_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_ACC_USER, props[PROP_ACC_USER]); + + props[PROP_ACC_PASSWORD] = + g_param_spec_string ("password", + "Password", + "The password for authentication", + "", + G_PARAM_WRITABLE); + g_object_class_install_property (object_class, PROP_ACC_PASSWORD, props[PROP_ACC_PASSWORD]); + + props[PROP_ACC_HOST] = + g_param_spec_string ("host", + "Host", + "The fqdn of the SIP server", + "", + G_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_ACC_HOST, props[PROP_ACC_HOST]); + + props[PROP_ACC_PROTOCOL] = + g_param_spec_string ("protocol", + "Protocol", + "The protocol used to connect to the SIP server", + "UDP", + G_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_ACC_PROTOCOL, props[PROP_ACC_PROTOCOL]); + + props[PROP_ACC_DIRECT] = + g_param_spec_boolean ("direct-connection", + "Direct connection", + "Whether to use a direct connection (no SIP server)", + FALSE, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, PROP_ACC_DIRECT, props[PROP_ACC_DIRECT]); + #define IMPLEMENTS(ID, NAME) \ g_object_class_override_property (object_class, ID, NAME); \ props[ID] = g_object_class_find_property(object_class, NAME); @@ -271,10 +377,21 @@ calls_sip_origin_create_inbound (CallsSipOrigin *self, CallsSipOrigin * -calls_sip_origin_new (const gchar *name) +calls_sip_origin_new (const gchar *name, + const gchar *user, + const gchar *password, + const gchar *host, + const gchar *protocol, + gboolean direct_connection) + { CallsSipOrigin *origin = g_object_new (CALLS_TYPE_SIP_ORIGIN, + "user", user, + "password", password, + "host", host, + "protocol", protocol, + "direct-connection", direct_connection, NULL); g_string_assign (origin->name, name); diff --git a/plugins/sip/calls-sip-origin.h b/plugins/sip/calls-sip-origin.h index 0e0bccc..0a630d1 100644 --- a/plugins/sip/calls-sip-origin.h +++ b/plugins/sip/calls-sip-origin.h @@ -32,8 +32,13 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE (CallsSipOrigin, calls_sip_origin, CALLS, SIP_ORIGIN, GObject); -CallsSipOrigin *calls_sip_origin_new (const gchar *name); +CallsSipOrigin *calls_sip_origin_new (const gchar *name, + const gchar *user, + const gchar *password, + const gchar *host, + const gchar *protocol, + gboolean direct_connection); void calls_sip_origin_create_inbound (CallsSipOrigin *self, - const gchar *number); + const gchar *number); G_END_DECLS diff --git a/plugins/sip/calls-sip-provider.c b/plugins/sip/calls-sip-provider.c index d717b18..c1fd950 100644 --- a/plugins/sip/calls-sip-provider.c +++ b/plugins/sip/calls-sip-provider.c @@ -31,11 +31,16 @@ #include +#define SIP_ACCOUNT_FILE "sip-account.cfg" + struct _CallsSipProvider { CallsProvider parent_instance; GListStore *origins; + /* SIP */ + + gchar *filename; }; static void calls_sip_provider_message_source_interface_init (CallsMessageSourceInterface *iface); @@ -46,6 +51,74 @@ G_DEFINE_DYNAMIC_TYPE_EXTENDED G_IMPLEMENT_INTERFACE_DYNAMIC (CALLS_TYPE_MESSAGE_SOURCE, 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) +{ + g_autoptr (GError) error = NULL; + g_autoptr (GKeyFile) key_file = g_key_file_new (); + gchar **groups = NULL; + + g_assert (CALLS_IS_SIP_PROVIDER (self)); + + if (!g_key_file_load_from_file (key_file, self->filename, G_KEY_FILE_NONE, &error)) { + g_warning ("Error loading key file: %s", error->message); + return; + } + + groups = g_key_file_get_groups (key_file, NULL); + + for (gsize i = 0; groups[i] != NULL; i++) { + g_autofree gchar *user = NULL; + g_autofree gchar *password = NULL; + g_autofree gchar *host = NULL; + g_autofree gchar *protocol = NULL; + gboolean direct_connection = + g_key_file_get_boolean (key_file, groups[i], "Direct", NULL); + + if (direct_connection) + 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); + + skip: + if (protocol == NULL) + protocol = g_strdup ("UDP"); + + g_debug ("Adding origin for SIP account %s", groups[i]); + + calls_sip_provider_add_origin (self, groups[i], user, password, host, protocol, direct_connection); + } + + g_strfreev (groups); +} static const char * calls_sip_provider_get_name (CallsProvider *provider) @@ -72,7 +145,7 @@ calls_sip_provider_constructed (GObject *object) { CallsSipProvider *self = CALLS_SIP_PROVIDER (object); - calls_sip_provider_add_origin (self, "Sip origin"); + calls_sip_provider_load_accounts (self); G_OBJECT_CLASS (calls_sip_provider_parent_class)->constructed (object); } @@ -86,6 +159,9 @@ calls_sip_provider_dispose (GObject *object) g_list_store_remove_all (self->origins); g_clear_object (&self->origins); + g_free (self->filename); + self->filename = NULL; + G_OBJECT_CLASS (calls_sip_provider_parent_class)->dispose (object); } @@ -120,9 +196,21 @@ calls_sip_provider_init (CallsSipProvider *self) void calls_sip_provider_add_origin (CallsSipProvider *self, - const gchar *name) + const gchar *name, + const gchar *user, + const gchar *password, + const gchar *host, + const gchar *protocol, + gboolean direct_connection) { - g_autoptr (CallsSipOrigin) origin = calls_sip_origin_new (name); + g_autoptr (CallsSipOrigin) origin = + calls_sip_origin_new (name, + user, + password, + host, + protocol, + direct_connection); + g_list_store_append (self->origins, origin); } diff --git a/plugins/sip/calls-sip-provider.h b/plugins/sip/calls-sip-provider.h index d48c395..bee2a22 100644 --- a/plugins/sip/calls-sip-provider.h +++ b/plugins/sip/calls-sip-provider.h @@ -36,6 +36,11 @@ G_DECLARE_FINAL_TYPE (CallsSipProvider, calls_sip_provider, CALLS, SIP_PROVIDER, CallsSipProvider *calls_sip_provider_new (); void calls_sip_provider_add_origin (CallsSipProvider *self, - const gchar *name); + const gchar *name, + const gchar *user, + const gchar *password, + const gchar *host, + const gchar *protocol, + gboolean direct_connection); G_END_DECLS