diff --git a/sflphone-client-gnome/src/accountlist.h b/sflphone-client-gnome/src/accountlist.h index 260eec094..dd6dbb98a 100644 --- a/sflphone-client-gnome/src/accountlist.h +++ b/sflphone-client-gnome/src/accountlist.h @@ -62,14 +62,15 @@ typedef enum * * To retrieve the Alias for example, use g_hash_table_lookup(a->properties, ACCOUNT_ALIAS). */ + typedef struct { gchar * accountID; account_state_t state; GHashTable * properties; + GPtrArray * credential_information; } account_t; - /** * This function initialize the account list. */ diff --git a/sflphone-client-gnome/src/actions.c b/sflphone-client-gnome/src/actions.c index d8903ad6f..37c5ac1c8 100644 --- a/sflphone-client-gnome/src/actions.c +++ b/sflphone-client-gnome/src/actions.c @@ -147,6 +147,12 @@ sflphone_hung_up( callable_obj_t * c) #endif } +static hashtable_free(gpointer key, gpointer value, gpointer user_data) +{ + g_free(key); + g_free(value); +} + /** Internal to actions: Fill account list */ void sflphone_fill_account_list(gboolean toolbarInitialized) @@ -165,6 +171,7 @@ sflphone_fill_account_list(gboolean toolbarInitialized) { account_t * a = g_new0(account_t,1); a->accountID = g_strdup(*accountID); + a->credential_information = NULL; account_list_add(a); } g_strfreev (array); @@ -177,6 +184,25 @@ sflphone_fill_account_list(gboolean toolbarInitialized) if( details == NULL ) break; a->properties = details; + + /* As this function might be called numberous time, we should free the + * previously allocated space to avoid memory leaks. + */ + + /* Fill the actual array of credentials */ + + int number_of_credential = dbus_get_number_of_credential(a->accountID); + if(number_of_credential) { + a->credential_information = g_ptr_array_new(); + } else { + a->credential_information = NULL; + } + + int credential_index; + for(credential_index = 0; credential_index < number_of_credential; credential_index++) { + GHashTable * credential_information = dbus_get_credential(a->accountID, credential_index); + g_ptr_array_add(a->credential_information, credential_information); + } gchar * status = g_hash_table_lookup(details, "Status"); if(strcmp(status, "REGISTERED") == 0) diff --git a/sflphone-client-gnome/src/config/accountwindow.c b/sflphone-client-gnome/src/config/accountwindow.c index 44548d79c..f3e19db1b 100644 --- a/sflphone-client-gnome/src/config/accountwindow.c +++ b/sflphone-client-gnome/src/config/accountwindow.c @@ -2,6 +2,7 @@ * Copyright (C) 2007-2008 Savoir-Faire Linux inc. * Author: Emmanuel Milou * Author: Pierre-Luc Beaudoin + * Author: Pierre-Luc Bacon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -48,6 +49,19 @@ GtkWidget * entryPassword; GtkWidget * entryMailbox; GtkWidget * entryResolveNameOnlyOnce; GtkWidget * entryExpire; +GtkListStore * credentialStore; +GtkWidget * deleteCredButton; +GtkWidget * treeViewCredential; +GtkWidget * scrolledWindowCredential; + +// Credentials +enum { + COLUMN_CREDENTIAL_REALM, + COLUMN_CREDENTIAL_USERNAME, + COLUMN_CREDENTIAL_PASSWORD, + COLUMN_CREDENTIAL_DATA, + COLUMN_CREDENTIAL_COUNT +}; /* Signal to entryProtocol 'changed' */ void @@ -66,6 +80,14 @@ is_iax_enabled(void) return FALSE; } +static void update_credential_cb(GtkWidget *widget, gpointer data UNUSED) +{ + GtkTreeIter iter; + gtk_tree_model_get_iter_from_string ((GtkTreeModel *) credentialStore, &iter, "0"); + gint column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "column")); + gtk_list_store_set (GTK_LIST_STORE (credentialStore), &iter, column, (gchar *) gtk_entry_get_text(GTK_ENTRY(widget)), -1); +} + static GtkWidget * createAccountTab(account_t **a) { GtkWidget * frame; @@ -181,7 +203,7 @@ static GtkWidget * createAccountTab(account_t **a) gtk_table_attach ( GTK_TABLE( table ), entryHostname, 1, 2, 5, 6, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); label = gtk_label_new_with_mnemonic (_("_User name")); - gtk_table_attach ( GTK_TABLE( table ), label, 0, 1, 6, 7, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_table_attach ( GTK_TABLE( table ), label, 0, 1, 6, 7, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); gtk_misc_set_alignment(GTK_MISC (label), 0, 0.5); #if GTK_CHECK_VERSION(2,16,0) entryUsername = gtk_entry_new(); @@ -194,12 +216,16 @@ static GtkWidget * createAccountTab(account_t **a) gtk_label_set_mnemonic_widget (GTK_LABEL (label), entryUsername); gtk_entry_set_text(GTK_ENTRY(entryUsername), curUsername); gtk_table_attach ( GTK_TABLE( table ), entryUsername, 1, 2, 6, 7, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + g_signal_connect(G_OBJECT (entryUsername), "changed", G_CALLBACK (update_credential_cb), NULL); + g_object_set_data (G_OBJECT (entryUsername), "column", GINT_TO_POINTER (COLUMN_CREDENTIAL_USERNAME)); label = gtk_label_new_with_mnemonic (_("_Password")); gtk_table_attach ( GTK_TABLE( table ), label, 0, 1, 7, 8, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); gtk_misc_set_alignment(GTK_MISC (label), 0, 0.5); #if GTK_CHECK_VERSION(2,16,0) entryPassword = gtk_entry_new(); + GtkSettings *settings = gtk_settings_get_default (); + g_object_set (G_OBJECT (settings), "gtk-entry-password-hint-timeout", 600, NULL); gtk_entry_set_icon_from_stock (GTK_ENTRY (entryPassword), GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_DIALOG_AUTHENTICATION); #else entryPassword = sexy_icon_entry_new(); @@ -210,7 +236,9 @@ static GtkWidget * createAccountTab(account_t **a) gtk_label_set_mnemonic_widget (GTK_LABEL (label), entryPassword); gtk_entry_set_text(GTK_ENTRY(entryPassword), curPassword); gtk_table_attach ( GTK_TABLE( table ), entryPassword, 1, 2, 7, 8, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); - + g_signal_connect(G_OBJECT (entryPassword), "changed", G_CALLBACK (update_credential_cb), NULL); + g_object_set_data (G_OBJECT (entryPassword), "column", GINT_TO_POINTER (COLUMN_CREDENTIAL_PASSWORD)); + label = gtk_label_new_with_mnemonic (_("_Voicemail number")); gtk_table_attach ( GTK_TABLE( table ), label, 0, 1, 8, 9, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); gtk_misc_set_alignment(GTK_MISC (label), 0, 0.5); @@ -226,17 +254,160 @@ static GtkWidget * createAccountTab(account_t **a) return frame; } +static void fill_treeview_with_credential(GtkListStore * credentialStore, account_t * account) +{ + GtkTreeIter iter; + gtk_list_store_clear(credentialStore); + gtk_list_store_append (credentialStore, &iter); + + /* This is the default, undeletable credential */ + if(g_hash_table_lookup(account->properties, ACCOUNT_AUTHENTICATION_USERNAME) == NULL) { + DEBUG("DEFAULT"); + gtk_list_store_set(credentialStore, &iter, + COLUMN_CREDENTIAL_REALM, g_hash_table_lookup(account->properties, ACCOUNT_REALM), + COLUMN_CREDENTIAL_USERNAME, gtk_entry_get_text(GTK_ENTRY(entryUsername)), + COLUMN_CREDENTIAL_PASSWORD, gtk_entry_get_text(GTK_ENTRY(entryPassword)), + COLUMN_CREDENTIAL_DATA, account, + -1); + } else { + gtk_list_store_set(credentialStore, &iter, + COLUMN_CREDENTIAL_REALM, g_hash_table_lookup(account->properties, ACCOUNT_REALM), + COLUMN_CREDENTIAL_USERNAME, g_hash_table_lookup(account->properties, ACCOUNT_AUTHENTICATION_USERNAME), + COLUMN_CREDENTIAL_PASSWORD, gtk_entry_get_text(GTK_ENTRY(entryPassword)), + COLUMN_CREDENTIAL_DATA, account, + -1); + g_signal_handlers_disconnect_by_func (G_OBJECT(entryUsername), G_CALLBACK(update_credential_cb), NULL); + } + + if(account->credential_information == NULL) { + DEBUG("No credential defined"); + return; + } + + unsigned int i; + for(i = 0; i < account->credential_information->len; i++) + { + GHashTable * element = g_ptr_array_index(account->credential_information, i); + gtk_list_store_append (credentialStore, &iter); + gtk_list_store_set(credentialStore, &iter, + COLUMN_CREDENTIAL_REALM, g_hash_table_lookup(element, ACCOUNT_REALM), + COLUMN_CREDENTIAL_USERNAME, g_hash_table_lookup(element, ACCOUNT_USERNAME), + COLUMN_CREDENTIAL_PASSWORD, g_hash_table_lookup(element, ACCOUNT_PASSWORD), + COLUMN_CREDENTIAL_DATA, element, // Pointer + -1); + } +} + +static select_credential_cb(GtkTreeSelection *selection, GtkTreeModel *model) +{ + GtkTreeIter iter; + GtkTreePath *path; + if(gtk_tree_selection_get_selected (selection, NULL, &iter)) { + path = gtk_tree_model_get_path (model, &iter); + if(gtk_tree_path_get_indices (path)[0] == 0) { + gtk_widget_set_sensitive(GTK_WIDGET(deleteCredButton), FALSE); + } else { + gtk_widget_set_sensitive(GTK_WIDGET(deleteCredButton), TRUE); + } + } +} + +static void add_credential_cb (GtkWidget *button, gpointer data) +{ + GtkTreeIter iter; + GtkTreeModel *model = (GtkTreeModel *)data; + GtkRequisition requisitionTreeView; + GtkRequisition oldRequisitionTreeView; + + gtk_widget_size_request(GTK_WIDGET(treeViewCredential), &oldRequisitionTreeView); + + gtk_list_store_append (GTK_LIST_STORE (model), &iter); + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + COLUMN_CREDENTIAL_REALM, "*", + COLUMN_CREDENTIAL_USERNAME, _("Authentication"), + COLUMN_CREDENTIAL_PASSWORD, _("Secret"), + -1); + + gtk_widget_size_request(GTK_WIDGET(treeViewCredential), &requisitionTreeView); + gtk_widget_set_size_request(GTK_WIDGET(scrolledWindowCredential), oldRequisitionTreeView.width, requisitionTreeView.height + 20); +} + +static void delete_credential_cb(GtkWidget *button, gpointer data) +{ + GtkTreeIter iter; + GtkTreeView *treeview = (GtkTreeView *)data; + GtkTreeModel *model = gtk_tree_view_get_model (treeview); + GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview); + GtkRequisition requisitionTreeView; + GtkRequisition oldRequisitionTreeView; + + gtk_widget_size_request(GTK_WIDGET(treeViewCredential), &oldRequisitionTreeView); + + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) + { + GtkTreePath *path; + path = gtk_tree_model_get_path (model, &iter); + gtk_list_store_remove (GTK_LIST_STORE (model), &iter); + + gtk_tree_path_free (path); + } + + gtk_widget_size_request(GTK_WIDGET(treeViewCredential), &requisitionTreeView); + gtk_widget_set_size_request(GTK_WIDGET(scrolledWindowCredential), oldRequisitionTreeView.width, requisitionTreeView.height + 20); + +} + +static void cell_edited_cb(GtkCellRendererText *renderer, gchar *path_desc, gchar *text, gpointer data) +{ + GtkTreeModel *model = (GtkTreeModel *)data; + GtkTreePath *path = gtk_tree_path_new_from_string (path_desc); + GtkTreeIter iter; + + gint column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (renderer), "column")); + + if(g_strcasecmp(path_desc, "0") == 0) { + if(g_strcasecmp(text, gtk_entry_get_text(GTK_ENTRY(entryUsername))) != 0) { + g_signal_handlers_disconnect_by_func (G_OBJECT(entryUsername), G_CALLBACK(update_credential_cb), NULL); + } + } + + gtk_tree_model_get_iter (model, &iter, path); + gtk_list_store_set (GTK_LIST_STORE (model), &iter, column, text, -1); + gtk_tree_path_free (path); + +} + +static void editing_started_cb (GtkCellRenderer *cell, GtkCellEditable * editable, const gchar * path, gpointer data) +{ + DEBUG("Editing started"); + gtk_entry_set_visibility(GTK_ENTRY(editable), FALSE); +} + GtkWidget * createAdvancedTab(account_t **a) { GtkWidget * frame; GtkWidget * table; + GtkWidget * ret; + GtkWidget * hbox; + GtkWidget * editButton; + GtkWidget * addButton; + GtkCellRenderer * renderer; + GtkTreeViewColumn * treeViewColumn; + GtkTreeSelection * treeSelection; + GtkRequisition requisitionTable; + GtkRequisition requisitionTreeView; + + + ret = gtk_vbox_new(FALSE, 10); + gtk_container_set_border_width(GTK_CONTAINER(ret), 10); + account_t * currentAccount; // Default settings gchar * curAccountResolveOnce = "FALSE"; gchar * curAccountExpire = "600"; - currentAccount = *a; + currentAccount = *a; // Load from SIP/IAX/Unknown ? if(currentAccount) { @@ -244,14 +415,8 @@ GtkWidget * createAdvancedTab(account_t **a) curAccountExpire = g_hash_table_lookup(currentAccount->properties, ACCOUNT_REGISTRATION_EXPIRE); } - gnome_main_section_new (_("Advanced Settings"), &frame); - gtk_widget_show(frame); - - table = gtk_table_new (2, 2, FALSE/* homogeneous */); - gtk_table_set_row_spacings( GTK_TABLE(table), 10); - gtk_table_set_col_spacings( GTK_TABLE(table), 10); - gtk_widget_show(table); - gtk_container_add( GTK_CONTAINER( frame) , table ); + gnome_main_section_new_with_table (_("Registration Options"), &frame, &table, 2, 3); + gtk_box_pack_start(GTK_BOX(ret), frame, FALSE, FALSE, 0); label = gtk_label_new_with_mnemonic (_("Registration _expire")); gtk_table_attach ( GTK_TABLE( table ), label, 0, 1, 0, 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); @@ -267,11 +432,137 @@ GtkWidget * createAdvancedTab(account_t **a) gtk_table_attach ( GTK_TABLE( table ), entryResolveNameOnlyOnce, 0, 2, 1, 2, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); gtk_widget_set_sensitive( GTK_WIDGET( entryResolveNameOnlyOnce ) , TRUE ); - gtk_widget_show_all( table ); + gtk_widget_show_all( table ); gtk_container_set_border_width (GTK_CONTAINER(table), 10); - *a = currentAccount; - return frame; + gtk_widget_size_request(GTK_WIDGET(table), &requisitionTable); + + /* Credentials tree view */ + gnome_main_section_new_with_table (_("Credential informations"), &frame, &table, 1, 1); + gtk_container_set_border_width (GTK_CONTAINER(table), 10); + gtk_table_set_row_spacings (GTK_TABLE(table), 10); + gtk_box_pack_start(GTK_BOX(ret), frame, FALSE, FALSE, 0); + + scrolledWindowCredential = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledWindowCredential), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledWindowCredential), GTK_SHADOW_IN); + gtk_table_attach (GTK_TABLE(table), scrolledWindowCredential, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + credentialStore = gtk_list_store_new(COLUMN_CREDENTIAL_COUNT, + G_TYPE_STRING, // Realm + G_TYPE_STRING, // Username + G_TYPE_STRING, // Password + G_TYPE_POINTER // Pointer to the Object + ); + + treeViewCredential = gtk_tree_view_new_with_model(GTK_TREE_MODEL(credentialStore)); + treeSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW (treeViewCredential)); + g_signal_connect(G_OBJECT (treeSelection), "changed", G_CALLBACK (select_credential_cb), credentialStore); + + renderer = gtk_cell_renderer_text_new(); + g_object_set (renderer, "editable", TRUE, "editable-set", TRUE, NULL); + g_signal_connect(G_OBJECT (renderer), "edited", G_CALLBACK(cell_edited_cb), credentialStore); + g_object_set_data (G_OBJECT (renderer), "column", GINT_TO_POINTER (COLUMN_CREDENTIAL_REALM)); + treeViewColumn = gtk_tree_view_column_new_with_attributes ("Realm", + renderer, + "markup", COLUMN_CREDENTIAL_REALM, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW(treeViewCredential), treeViewColumn); + + renderer = gtk_cell_renderer_text_new(); + g_object_set (renderer, "editable", TRUE, "editable-set", TRUE, NULL); + g_signal_connect(G_OBJECT (renderer), "edited", G_CALLBACK(cell_edited_cb), credentialStore); + g_object_set_data (G_OBJECT (renderer), "column", GINT_TO_POINTER (COLUMN_CREDENTIAL_USERNAME)); + treeViewColumn = gtk_tree_view_column_new_with_attributes (_("Authentication name"), + renderer, + "markup", COLUMN_CREDENTIAL_USERNAME, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW(treeViewCredential), treeViewColumn); + + renderer = gtk_cell_renderer_text_new(); + g_object_set (renderer, "editable", TRUE, "editable-set", TRUE, NULL); + g_signal_connect(G_OBJECT (renderer), "edited", G_CALLBACK(cell_edited_cb), credentialStore); + g_signal_connect (renderer, "editing-started", G_CALLBACK (editing_started_cb), NULL); + g_object_set_data (G_OBJECT (renderer), "column", GINT_TO_POINTER (COLUMN_CREDENTIAL_PASSWORD)); + treeViewColumn = gtk_tree_view_column_new_with_attributes (_("Password"), + renderer, + "markup", COLUMN_CREDENTIAL_PASSWORD, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW(treeViewCredential), treeViewColumn); + + gtk_container_add(GTK_CONTAINER(scrolledWindowCredential), treeViewCredential); + + fill_treeview_with_credential(credentialStore, *a); + + /* Dynamically resize the window to fit the scrolled window */ + gtk_widget_size_request(GTK_WIDGET(treeViewCredential), &requisitionTreeView); + gtk_widget_set_size_request(GTK_WIDGET(scrolledWindowCredential), requisitionTable.width, requisitionTreeView.height + 20); + + /* Credential Buttons */ + hbox = gtk_hbox_new(FALSE, 10); + gtk_table_attach (GTK_TABLE(table), hbox, 0, 2, 1, 2, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + addButton = gtk_button_new_from_stock (GTK_STOCK_ADD); + g_signal_connect (addButton, "clicked", G_CALLBACK (add_credential_cb), credentialStore); + gtk_box_pack_start(GTK_BOX(hbox), addButton, FALSE, FALSE, 0); + + deleteCredButton = gtk_button_new_from_stock (GTK_STOCK_REMOVE); + g_signal_connect (deleteCredButton, "clicked", G_CALLBACK (delete_credential_cb), treeViewCredential); + gtk_box_pack_start(GTK_BOX(hbox), deleteCredButton, FALSE, FALSE, 0); + + gtk_widget_show_all(ret); + return ret; +} + +static GPtrArray * getNewCredential(account_t * account) +{ + GtkTreeIter iter; + gboolean valid; + gint row_count = 0; + + valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL(credentialStore), &iter); + + GPtrArray * credential_array = g_ptr_array_new (); + + gchar *username; + gchar *realm; + gchar *password; + GHashTable * new_table; + + gtk_tree_model_get (GTK_TREE_MODEL(credentialStore), &iter, + COLUMN_CREDENTIAL_REALM, &realm, + COLUMN_CREDENTIAL_USERNAME, &username, + COLUMN_CREDENTIAL_PASSWORD, &password, + -1); + + g_hash_table_insert(account->properties, g_strdup(ACCOUNT_REALM), realm); + g_hash_table_insert(account->properties, g_strdup(ACCOUNT_AUTHENTICATION_USERNAME), username); + g_hash_table_insert(account->properties, g_strdup(ACCOUNT_PASSWORD), password); + + valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(credentialStore), &iter); + + while (valid) { + gtk_tree_model_get (GTK_TREE_MODEL(credentialStore), &iter, + COLUMN_CREDENTIAL_REALM, &realm, + COLUMN_CREDENTIAL_USERNAME, &username, + COLUMN_CREDENTIAL_PASSWORD, &password, + -1); + + DEBUG ("Row %d: %s %s %s", row_count, username, password, realm); + + new_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + g_hash_table_insert(new_table, g_strdup(ACCOUNT_REALM), realm); + g_hash_table_insert(new_table, g_strdup(ACCOUNT_USERNAME), username); + g_hash_table_insert(new_table, g_strdup(ACCOUNT_PASSWORD), password); + + g_ptr_array_add (credential_array, new_table); + + row_count ++; + + valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(credentialStore), &iter); + } + + return credential_array; } void @@ -346,8 +637,8 @@ show_account_window (account_t * a) g_strdup((gchar *)gtk_entry_get_text(GTK_ENTRY(entryMailbox)))); g_hash_table_replace(currentAccount->properties, g_strdup(ACCOUNT_REGISTRATION_EXPIRE), - g_strdup((gchar *)gtk_entry_get_text(GTK_ENTRY(entryExpire)))); - + g_strdup((gchar *)gtk_entry_get_text(GTK_ENTRY(entryExpire)))); + if (strcmp(proto, "SIP") == 0) { guint i, size; account_t * account; @@ -376,13 +667,33 @@ show_account_window (account_t * a) if(!flag) { g_hash_table_replace(currentAccount->properties, g_strdup(ACCOUNT_SIP_STUN_SERVER), (gchar*)""); - g_hash_table_replace(currentAccount->properties, g_strdup(ACCOUNT_SIP_STUN_ENABLED), - "FALSE"); + g_hash_table_replace(currentAccount->properties, g_strdup(ACCOUNT_SIP_STUN_ENABLED), "FALSE"); } config_window_set_stun_visible(); } + /* Set new credentials if any */ + + DEBUG("Setting credentials"); + + /* This hack is necessary because of the way the + * configuration file is made (.ini at that time). + * and deleting account per account is too much + * of a trouble. + */ + dbus_delete_all_credential(currentAccount); + + GPtrArray * credential = getNewCredential(a); + currentAccount->credential_information = credential; + if(currentAccount->credential_information != NULL) { + int i; + for(i = 0; i < currentAccount->credential_information->len; i++) { + dbus_set_credential(currentAccount, i); + } + dbus_set_number_of_credential(currentAccount, currentAccount->credential_information->len); + } + /** @todo Verify if it's the best condition to check */ if (currentAccount->accountID == NULL) { dbus_add_account(currentAccount); @@ -390,7 +701,10 @@ show_account_window (account_t * a) else { dbus_set_account_details(currentAccount); } - } + + + } + gtk_widget_destroy (GTK_WIDGET(dialog)); } diff --git a/sflphone-client-gnome/src/config/configwindow.c b/sflphone-client-gnome/src/config/configwindow.c index 1d436d118..2a09df877 100644 --- a/sflphone-client-gnome/src/config/configwindow.c +++ b/sflphone-client-gnome/src/config/configwindow.c @@ -236,7 +236,7 @@ select_account(GtkTreeSelection *selection, GtkTreeModel *model) gtk_widget_set_sensitive(GTK_WIDGET(accountMoveUpButton), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(accountMoveDownButton), TRUE); } - DEBUG("select"); + DEBUG("Selecting account in account window"); } static void diff --git a/sflphone-client-gnome/src/dbus/configurationmanager-introspec.xml b/sflphone-client-gnome/src/dbus/configurationmanager-introspec.xml index 7e3888c23..bf535c9d6 100644 --- a/sflphone-client-gnome/src/dbus/configurationmanager-introspec.xml +++ b/sflphone-client-gnome/src/dbus/configurationmanager-introspec.xml @@ -14,6 +14,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sflphone-client-gnome/src/dbus/dbus.c b/sflphone-client-gnome/src/dbus/dbus.c index b4ad2226d..08904b82f 100644 --- a/sflphone-client-gnome/src/dbus/dbus.c +++ b/sflphone-client-gnome/src/dbus/dbus.c @@ -559,6 +559,100 @@ GHashTable* dbus_account_details(gchar * accountID) } } + void +dbus_set_credential(account_t *a, int index) +{ + DEBUG("Sending credential %d to server", index); + GError *error = NULL; + GHashTable * credential = g_ptr_array_index(a->credential_information, index); + + if(credential == NULL) { + DEBUG("Credential %d was deleted", index); + } else { + org_sflphone_SFLphone_ConfigurationManager_set_credential ( + configurationManagerProxy, + a->accountID, + index, + credential, + &error); + } + + if (error) { + ERROR ("Failed to call set_account_details() on ConfigurationManager: %s", + error->message); + g_error_free (error); + } +} + void +dbus_set_number_of_credential(account_t *a, int number) +{ + DEBUG("Sending number of credential %d to server", number); + GError *error = NULL; + + org_sflphone_SFLphone_ConfigurationManager_set_number_of_credential( configurationManagerProxy, a->accountID, number, &error); + + if (error) { + ERROR ("Failed to call set_account_details() on ConfigurationManager: %s", + error->message); + g_error_free (error); + } +} + void +dbus_delete_all_credential(account_t *a) +{ + DEBUG("Deleting all credentials\n"); + GError *error = NULL; + + org_sflphone_SFLphone_ConfigurationManager_delete_all_credential(configurationManagerProxy, a->accountID, &error); + + if (error) { + ERROR ("Failed to call deleteAllCredential on ConfigurationManager: %s", + error->message); + g_error_free (error); + } +} + + int +dbus_get_number_of_credential(gchar * accountID) +{ + GError *error = NULL; + int number = 0; + + DEBUG("Getting number of credential for account %s", accountID); + + if(!org_sflphone_SFLphone_ConfigurationManager_get_number_of_credential( configurationManagerProxy, accountID, &number, &error)) { + if(error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION) { + ERROR ("Caught remote method (get_account_details) exception %s: %s", dbus_g_error_get_name(error), error->message); + } + else { + ERROR("Error while calling get_account_details: %s", error->message); + } + g_error_free (error); + return 0; + } else { + DEBUG("%d credential(s) found for account %s", number, accountID); + return number; + } +} + +GHashTable* dbus_get_credential(gchar * accountID, int index) +{ + GError *error = NULL; + GHashTable * details; + + if(!org_sflphone_SFLphone_ConfigurationManager_get_credential( configurationManagerProxy, accountID, index, &details, &error)) { + if(error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION) { + ERROR ("Caught remote method (get_account_details) exception %s: %s", dbus_g_error_get_name(error), error->message); + } else { + ERROR("Error while calling get_account_details: %s", error->message); + } + g_error_free (error); + return NULL; + } else { + return details; + } +} + void dbus_send_register ( gchar* accountID , const guint expire) { diff --git a/sflphone-client-gnome/src/dbus/dbus.h b/sflphone-client-gnome/src/dbus/dbus.h index 0c46d263d..f0bf2a9a9 100644 --- a/sflphone-client-gnome/src/dbus/dbus.h +++ b/sflphone-client-gnome/src/dbus/dbus.h @@ -106,6 +106,51 @@ GHashTable * dbus_account_details(gchar * accountID); */ void dbus_set_account_details(account_t *a); +/** + * ConfigurationManager - Set the additional credential information + * of a specific account, for a specific credential index. + * This function will add the new section on the server side + * if it cannot be found. + * @param a The account to update + * @param index The index for the credential to update + */ +void dbus_set_credential(account_t *a, int index); + +/** + * ConfigurationManager - Set the additional credential information + * of a specific account, for a specific credential index. + * This function will add the new section on the server side + * if it cannot be found. + * @param a The account to update + * @return int The number of credentials specified + */ +int dbus_get_number_of_credential(gchar * accountID); + +/** + * ConfigurationManager - Delete all credentials defined for + * a given account. + * @param a The account id + */ +void dbus_delete_all_credential(account_t *a); + +/** + * ConfigurationManager - Set the number of credential that + * is being used. + * @param a The account id + */ +void dbus_set_number_of_credential(account_t *a, int number); + +/** + * ConfigurationManager - Set the additional credential information + * of a specific account, for a specific credential index. + * This function will add the new section on the server side + * if it cannot be found. + * @param a The account to update + * @param index The credential index + * @return GHashTable* The credential at index "index" for the given account + */ +GHashTable* dbus_get_credential(gchar * accountID, int index); + /** * ConfigurationManager - Send registration request * @param accountID The account to register/unregister diff --git a/sflphone-client-gnome/src/sflphone_const.h b/sflphone-client-gnome/src/sflphone_const.h index 3f0d9f97e..e0208b8fd 100644 --- a/sflphone-client-gnome/src/sflphone_const.h +++ b/sflphone-client-gnome/src/sflphone_const.h @@ -56,6 +56,8 @@ #define ACCOUNT_HOSTNAME "hostname" #define ACCOUNT_USERNAME "username" #define ACCOUNT_PASSWORD "password" +#define ACCOUNT_AUTHENTICATION_USERNAME "authenticationUsername" +#define ACCOUNT_REALM "realm" /** * Global logger diff --git a/sflphone-common/src/account.h b/sflphone-common/src/account.h index 72eee8cda..23c098a84 100644 --- a/sflphone-common/src/account.h +++ b/sflphone-common/src/account.h @@ -60,10 +60,13 @@ typedef enum RegistrationState { #define CONFIG_ACCOUNT_ENABLE "Account.enable" #define CONFIG_ACCOUNT_RESOLVE_ONCE "Account.resolveOnce" #define CONFIG_ACCOUNT_REGISTRATION_EXPIRE "Account.expire" +#define CONFIG_CREDENTIAL_NUMBER "Credential.count" #define HOSTNAME "hostname" #define USERNAME "username" +#define AUTHENTICATION_USERNAME "authenticationUsername" #define PASSWORD "password" +#define REALM "realm" // SIP specific parameters #define SIP_PROXY "SIP.proxy" diff --git a/sflphone-common/src/dbus/configurationmanager-introspec.xml b/sflphone-common/src/dbus/configurationmanager-introspec.xml index 7e3888c23..2371fb931 100644 --- a/sflphone-common/src/dbus/configurationmanager-introspec.xml +++ b/sflphone-common/src/dbus/configurationmanager-introspec.xml @@ -15,6 +15,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sflphone-common/src/dbus/configurationmanager.cpp b/sflphone-common/src/dbus/configurationmanager.cpp index 7afc9cb25..d12825631 100644 --- a/sflphone-common/src/dbus/configurationmanager.cpp +++ b/sflphone-common/src/dbus/configurationmanager.cpp @@ -41,6 +41,97 @@ ConfigurationManager::getAccountDetails (const std::string& accountID) return Manager::instance().getAccountDetails (accountID); } +std::map< std::string, std::string > +ConfigurationManager::getCredential (const std::string& accountID, const int32_t& index) +{ + _debug ("ConfigurationManager::getCredential number %i for accountID %s\n", index, accountID.c_str()); + + std::string credentialIndex; + std::stringstream streamOut; + streamOut << index; + credentialIndex = streamOut.str(); + + std::string section = std::string("Credential") + std::string(":") + accountID + std::string(":") + credentialIndex; + + std::map credentialInformation; + std::string username = Manager::instance().getConfigString(section, USERNAME); + std::string password = Manager::instance().getConfigString(section, PASSWORD); + std::string realm = Manager::instance().getConfigString(section, REALM); + + credentialInformation.insert(std::pair (USERNAME, username)); + credentialInformation.insert(std::pair (PASSWORD, password)); + credentialInformation.insert(std::pair (REALM, realm)); + + return credentialInformation; +} + +int32_t +ConfigurationManager::getNumberOfCredential (const std::string& accountID) +{ + _debug ("ConfigurationManager::getNumberOfCredential\n"); + return Manager::instance().getConfigInt (accountID, CONFIG_CREDENTIAL_NUMBER); +} + +void +ConfigurationManager::setNumberOfCredential (const std::string& accountID, const int32_t& number) +{ + Manager::instance().setConfig (accountID, CONFIG_CREDENTIAL_NUMBER, number); +} + +void +ConfigurationManager::setCredential (const std::string& accountID, const int32_t& index, + const std::map< std::string, std::string >& details) +{ + _debug ("ConfigurationManager::setCredential received\n"); + + std::map::iterator it; + std::map credentialInformation = details; + + std::string credentialIndex; + std::stringstream streamOut; + streamOut << index; + credentialIndex = streamOut.str(); + + std::string section = "Credential" + std::string(":") + accountID + std::string(":") + credentialIndex; + + _debug("Setting credential in section %s\n", section.c_str()); + + it = credentialInformation.find(USERNAME); + if(it == credentialInformation.end()) { + Manager::instance().setConfig (section, USERNAME, EMPTY_FIELD); + } else { + Manager::instance().setConfig (section, USERNAME, it->second); + } + + _debug("Username: %s\n", it->second.c_str()); + + it = credentialInformation.find(PASSWORD); + if(it == credentialInformation.end()) { + Manager::instance().setConfig (section, PASSWORD, EMPTY_FIELD); + } else { + Manager::instance().setConfig (section, PASSWORD, it->second); + } + + _debug("Password: %s\n", it->second.c_str()); + + it = credentialInformation.find(REALM); + if(it == credentialInformation.end()) { + Manager::instance().setConfig (section, REALM, EMPTY_FIELD); + } else { + Manager::instance().setConfig (section, REALM, it->second); + } + + _debug("Realm: %s\n", it->second.c_str()); + +} + +void +ConfigurationManager::deleteAllCredential (const std::string& accountID) +{ + _debug ("ConfigurationManager::deleteAllCredential received\n"); + Manager::instance().deleteAllCredential (accountID); +} + void ConfigurationManager::setAccountDetails (const std::string& accountID, const std::map< std::string, std::string >& details) diff --git a/sflphone-common/src/dbus/configurationmanager.h b/sflphone-common/src/dbus/configurationmanager.h index 128f80e96..2a74fe448 100644 --- a/sflphone-common/src/dbus/configurationmanager.h +++ b/sflphone-common/src/dbus/configurationmanager.h @@ -43,9 +43,15 @@ public: void setAccountDetails( const std::string& accountID, const std::map< std::string, std::string >& details ); std::string addAccount( const std::map< std::string, std::string >& details ); void removeAccount( const std::string& accoundID ); + void deleteAllCredential (const std::string& accountID); std::vector< std::string > getAccountList( ); void sendRegister( const std::string& accoundID , const int32_t& expire ); + std::map< std::string, std::string > getCredential (const std::string& accountID, const int32_t& index); + int32_t getNumberOfCredential (const std::string& accountID); + void setCredential (const std::string& accountID, const int32_t& index, const std::map< std::string, std::string >& details); + void setNumberOfCredential (const std::string& accountID, const int32_t& number); + std::vector< std::string > getCodecList( ); std::vector< std::string > getCodecDetails( const int32_t& payload ); std::vector< std::string > getActiveCodecList( ); diff --git a/sflphone-common/src/managerimpl.cpp b/sflphone-common/src/managerimpl.cpp index ad14f21a1..a4e0de2c5 100644 --- a/sflphone-common/src/managerimpl.cpp +++ b/sflphone-common/src/managerimpl.cpp @@ -2492,6 +2492,8 @@ std::map< std::string, std::string > ManagerImpl::getAccountDetails (const Accou a.insert (std::pair (USERNAME, getConfigString (accountID, USERNAME))); a.insert (std::pair (PASSWORD, getConfigString (accountID, PASSWORD))); a.insert (std::pair (HOSTNAME, getConfigString (accountID, HOSTNAME))); + a.insert (std::pair (REALM, getConfigString (accountID, REALM))); + a.insert (std::pair (AUTHENTICATION_USERNAME, getConfigString (accountID, AUTHENTICATION_USERNAME))); a.insert (std::pair (CONFIG_ACCOUNT_MAILBOX, getConfigString (accountID, CONFIG_ACCOUNT_MAILBOX))); if (getConfigString (accountID, CONFIG_ACCOUNT_REGISTRATION_EXPIRE).empty()) { @@ -2538,13 +2540,18 @@ void ManagerImpl::setAccountDetails (const std::string& accountID, const std::ma ( (iter = map_cpy.find (HOSTNAME)) == map_cpy.end ()) ? setConfig (accountID, HOSTNAME, EMPTY_FIELD) : setConfig (accountID, HOSTNAME, iter->second); + + ( (iter = map_cpy.find (REALM)) == map_cpy.end ()) ? setConfig (accountID, REALM, std::string("*")) + : setConfig (accountID, REALM, iter->second); ( (iter = map_cpy.find (CONFIG_ACCOUNT_MAILBOX)) == map_cpy.end ()) ? setConfig (accountID, CONFIG_ACCOUNT_MAILBOX, EMPTY_FIELD) : setConfig (accountID, CONFIG_ACCOUNT_MAILBOX, iter->second); ( (iter = map_cpy.find (CONFIG_ACCOUNT_REGISTRATION_EXPIRE)) == map_cpy.end ()) ? setConfig (accountID, CONFIG_ACCOUNT_REGISTRATION_EXPIRE, DFT_EXPIRE_VALUE) : setConfig (accountID, CONFIG_ACCOUNT_REGISTRATION_EXPIRE, iter->second); - + + ( (iter = map_cpy.find (AUTHENTICATION_USERNAME)) == map_cpy.end ()) ? setConfig (accountID, AUTHENTICATION_USERNAME, EMPTY_FIELD) + : setConfig (accountID, AUTHENTICATION_USERNAME, iter->second); saveConfig(); acc = getAccount (accountID); @@ -2638,6 +2645,25 @@ ManagerImpl::addAccount (const std::map< std::string, std::string >& details) return newAccountID; } +void +ManagerImpl::deleteAllCredential(const AccountID& accountID) +{ + int numberOfCredential = getConfigInt (accountID, CONFIG_CREDENTIAL_NUMBER); + + int i; + for(i = 0; i < numberOfCredential; i++) { + std::string credentialIndex; + std::stringstream streamOut; + streamOut << i; + credentialIndex = streamOut.str(); + std::string section = "Credential" + std::string(":") + accountID + std::string(":") + credentialIndex; + + _config.removeSection (section); + } + + setConfig (accountID, CONFIG_CREDENTIAL_NUMBER, 0); +} + void ManagerImpl::removeAccount (const AccountID& accountID) { @@ -2745,7 +2771,7 @@ ManagerImpl::loadAccountMap() while (iter != sections.end()) { // Check if it starts with "Account:" (SIP and IAX pour le moment) - if ( (int) (iter->find ("Account:")) == -1) { + if ( (int) (iter->find ("Account:")) != 0) { iter++; continue; } @@ -2786,7 +2812,7 @@ ManagerImpl::unloadAccountMap() while (iter != _accountMap.end()) { - _debug ("-> Deleting account %s\n", iter->first.c_str()); + _debug ("-> Unloading account %s\n", iter->first.c_str()); delete iter->second; iter->second = 0; diff --git a/sflphone-common/src/managerimpl.h b/sflphone-common/src/managerimpl.h index eef8c251f..47a825c62 100644 --- a/sflphone-common/src/managerimpl.h +++ b/sflphone-common/src/managerimpl.h @@ -342,6 +342,13 @@ class ManagerImpl { */ void removeAccount(const AccountID& accountID); + + /** + * Deletes all credentials defined for an account + * @param accountID The account unique ID + */ + void deleteAllCredential(const AccountID& accountID); + /** * Get the list of codecs we supports, not ordered * @return The list of the codecs @@ -897,7 +904,7 @@ class ManagerImpl { * Initialize audiodriver */ bool initAudioDriver(void); - + private: /** diff --git a/sflphone-common/src/sipaccount.cpp b/sflphone-common/src/sipaccount.cpp index ce4bc9707..38f3e8ce8 100644 --- a/sflphone-common/src/sipaccount.cpp +++ b/sflphone-common/src/sipaccount.cpp @@ -47,7 +47,7 @@ SIPAccount::~SIPAccount() dynamic_cast (_link)->decrementClients(); /* Delete accounts-related information */ _regc = NULL; - delete _cred; + free(_cred); _cred = NULL; } @@ -61,11 +61,59 @@ int SIPAccount::registerVoIPLink() if (Manager::instance().getConfigString (_accountID, HOSTNAME).length() >= PJ_MAX_HOSTNAME) { return !SUCCESS; } - + setHostname (Manager::instance().getConfigString (_accountID, HOSTNAME)); - setUsername (Manager::instance().getConfigString (_accountID, USERNAME)); setPassword (Manager::instance().getConfigString (_accountID, PASSWORD)); + _authenticationUsername = Manager::instance().getConfigString (_accountID, AUTHENTICATION_USERNAME); + _realm = Manager::instance().getConfigString (_accountID, REALM); + + int credentialCount = 0; + credentialCount = Manager::instance().getConfigInt (_accountID, CONFIG_CREDENTIAL_NUMBER); + credentialCount += 1; + + pjsip_cred_info * cred_info = (pjsip_cred_info *) malloc(sizeof(pjsip_cred_info)*(credentialCount)); + if (cred_info == NULL) { + _debug("Failed to set cred_info for account %s\n", _accountID.c_str()); + return !SUCCESS; + } + pj_bzero (cred_info, sizeof(pjsip_cred_info)*credentialCount); + + if (!_authenticationUsername.empty()) { + cred_info[0].username = pj_str(strdup(_authenticationUsername.c_str())); + } else { + cred_info[0].username = pj_str(strdup(_username.c_str())); + } + cred_info[0].data = pj_str(strdup(_password.c_str())); + cred_info[0].realm = pj_str(strdup(_realm.c_str())); + cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; + cred_info[0].scheme = pj_str("digest"); + + int i; + for (i = 1; i < credentialCount; i++) { + std::string credentialIndex; + std::stringstream streamOut; + streamOut << i - 1; + credentialIndex = streamOut.str(); + + std::string section = std::string("Credential") + std::string(":") + _accountID + std::string(":") + credentialIndex; + + std::string username = Manager::instance().getConfigString(section, USERNAME); + std::string password = Manager::instance().getConfigString(section, PASSWORD); + std::string realm = Manager::instance().getConfigString(section, REALM); + + cred_info[i].username = pj_str(strdup(username.c_str())); + cred_info[i].data = pj_str(strdup(password.c_str())); + cred_info[i].realm = pj_str(strdup(realm.c_str())); + cred_info[i].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; + cred_info[i].scheme = pj_str("digest"); + + _debug("Setting credential %d realm = %s passwd = %s username = %s data_type = %d\n", i, realm.c_str(), password.c_str(), username.c_str(), cred_info[i].data_type); + } + + _credentialCount = credentialCount; + _cred = cred_info; + _resolveOnce = Manager::instance().getConfigString (_accountID, CONFIG_ACCOUNT_RESOLVE_ONCE) == "1" ? true : false; if (Manager::instance().getConfigString (_accountID, CONFIG_ACCOUNT_REGISTRATION_EXPIRE).empty()) { @@ -73,7 +121,7 @@ int SIPAccount::registerVoIPLink() } else { _registrationExpire = Manager::instance().getConfigString (_accountID, CONFIG_ACCOUNT_REGISTRATION_EXPIRE); } - + /* Start registration */ status = _link->sendRegister (_accountID); diff --git a/sflphone-common/src/sipaccount.h b/sflphone-common/src/sipaccount.h index d7d06f9eb..3a4830ed2 100644 --- a/sflphone-common/src/sipaccount.h +++ b/sflphone-common/src/sipaccount.h @@ -70,10 +70,17 @@ class SIPAccount : public Account inline void setCredInfo(pjsip_cred_info *cred) {_cred = cred;} inline pjsip_cred_info *getCredInfo() {return _cred;} - + inline void setContact(const std::string &contact) {_contact = contact;} inline std::string getContact() {return _contact;} - + + inline std::string& getAuthenticationUsername(void) { return _authenticationUsername; } + inline void setAuthenticationUsername(const std::string& username) { _authenticationUsername = username; } + + inline bool isResolveOnce(void) { return _resolveOnce; } + + inline std::string& getRegistrationExpire(void) { return _registrationExpire; } + bool fullMatch(const std::string& username, const std::string& hostname); bool userMatch(const std::string& username); bool hostnameMatch(const std::string& hostname); @@ -81,13 +88,12 @@ class SIPAccount : public Account pjsip_regc* getRegistrationInfo( void ) { return _regc; } void setRegistrationInfo( pjsip_regc *regc ) { _regc = regc; } + inline int getCredentialCount(void) { return _credentialCount; } + /* Registration flag */ bool isRegister() {return _bRegister;} - void setRegister(bool result) {_bRegister = result;} - - inline bool isResolveOnce(void) { return _resolveOnce; } - - inline std::string& getRegistrationExpire(void) { return _registrationExpire; } + void setRegister(bool result) {_bRegister = result;} + private: /** @@ -105,14 +111,20 @@ class SIPAccount : public Account */ bool _bRegister; + bool _resolveOnce; + /* * SIP address */ std::string _contact; - bool _resolveOnce; - std::string _registrationExpire; + + std::string _authenticationUsername; + + std::string _realm; + + int _credentialCount; }; #endif diff --git a/sflphone-common/src/sipvoiplink.cpp b/sflphone-common/src/sipvoiplink.cpp index 926eb0964..4ef449218 100644 --- a/sflphone-common/src/sipvoiplink.cpp +++ b/sflphone-common/src/sipvoiplink.cpp @@ -484,26 +484,10 @@ int SIPVoIPLink::sendRegister (AccountID id) } pjsip_cred_info *cred = account->getCredInfo(); - - if (!cred) - cred = new pjsip_cred_info(); - - pj_bzero (cred, sizeof (pjsip_cred_info)); - - pj_strdup2 (_pool, &cred->username, username.data()); - - cred->data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; - - pj_strdup2 (_pool, &cred->data, password.data()); - - pj_strdup2 (_pool, &cred->realm, "*"); - - pj_strdup2 (_pool, &cred->scheme, "digest"); - - pjsip_regc_set_credentials (regc, 1, cred); - - account->setCredInfo (cred); - + int credential_count = account->getCredentialCount(); + _debug("setting %d credentials\n", credential_count); + pjsip_regc_set_credentials (regc, credential_count, cred); + // Add User-Agent Header pj_list_init (&hdr_list); diff --git a/sflphone-common/src/sipvoiplink.h b/sflphone-common/src/sipvoiplink.h index 8dde01c29..eec72e706 100644 --- a/sflphone-common/src/sipvoiplink.h +++ b/sflphone-common/src/sipvoiplink.h @@ -42,7 +42,7 @@ class AudioRtp; #define RANDOM_SIP_PORT rand() % 64000 + 1024 // To set the verbosity. From 0 (min) to 6 (max) -#define PJ_LOG_LEVEL 0 +#define PJ_LOG_LEVEL 0 /** * @file sipvoiplink.h