diff --git a/sflphone-client-gnome/src/accountlist.h b/sflphone-client-gnome/src/accountlist.h index 260eec094e48065e2a1168a1a5267432ab2e6586..a810ac0f7d797546cec10c71cb262f5cb50b7981 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; + GArray * 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 d8903ad6fd4a8e46e896fa70331ebbeb1f3a9d88..5fa8327978d3480b9ba1daa25c045683d38645b9 100644 --- a/sflphone-client-gnome/src/actions.c +++ b/sflphone-client-gnome/src/actions.c @@ -147,6 +147,11 @@ sflphone_hung_up( callable_obj_t * c) #endif } +static hashtable_free(gpointer key, gpointer value, gpointer user_data) +{ + g_free(value); +} + /** Internal to actions: Fill account list */ void sflphone_fill_account_list(gboolean toolbarInitialized) @@ -165,6 +170,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 +183,32 @@ 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. + */ + int credential_index; + if(a->credential_information != NULL) { + for(credential_index = 0; credential_index < a->credential_information->len; credential_index++) { + GHashTable * element = g_array_index(a->credential_information, GHashTable*, credential_index); + g_hash_table_foreach(element, hashtable_free, NULL); + g_hash_table_destroy(element); + g_free(element); + } + + g_array_free(a->credential_information, TRUE); + a->credential_information = NULL; + } + + /* Fill the actual array of credentials */ + a->credential_information = g_array_new (FALSE, TRUE, sizeof(GHashTable*)); + int number_of_credential = dbus_get_number_of_credential(a->accountID); + + for(credential_index = 0; credential_index < number_of_credential; credential_index++) { + GHashTable * credential_information = dbus_get_credential(a->accountID, credential_index); + g_array_append_val(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 44548d79ca4a4a60bb6d55c8174abf634b4509cf..bbb9a9039ac6f894737820d0f8d268b1e6384e34 100644 --- a/sflphone-client-gnome/src/config/accountwindow.c +++ b/sflphone-client-gnome/src/config/accountwindow.c @@ -48,6 +48,18 @@ GtkWidget * entryPassword; GtkWidget * entryMailbox; GtkWidget * entryResolveNameOnlyOnce; GtkWidget * entryExpire; +GtkListStore * credentialStore; +GtkWidget * deleteCredButton; +GArray * credential_information; + +// Credentials +enum { + COLUMN_CREDENTIAL_REALM, + COLUMN_CREDENTIAL_USERNAME, + COLUMN_CREDENTIAL_PASSWORD, + COLUMN_CREDENTIAL_DATA, + COLUMN_CREDENTIAL_COUNT +}; /* Signal to entryProtocol 'changed' */ void @@ -66,6 +78,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 +201,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 +214,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 +234,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 +252,177 @@ 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 */ + 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); + + 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_array_index(account->credential_information, GHashTable*, 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); + + /* We are building a temporary hash table that is either + * copied into the account_t structure or just discarded depending + * on whether the user pressed "apply" or "close" + */ + GHashTable * temporary; + temporary = g_hash_table_new(NULL, g_str_equal); + g_hash_table_insert(temporary, ACCOUNT_REALM, g_hash_table_lookup(element, ACCOUNT_REALM)); + g_hash_table_insert(temporary, ACCOUNT_USERNAME, g_hash_table_lookup(element, ACCOUNT_USERNAME)); + g_hash_table_insert(temporary, ACCOUNT_PASSWORD, g_hash_table_lookup(element, ACCOUNT_PASSWORD)); + g_array_append_val(credential_information, temporary); + } +} + +static select_credential_cb(GtkTreeSelection *selection, GtkTreeModel *model) +{ + DEBUG("Select credential"); + 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) +{ + DEBUG("add credential"); + GtkTreeIter iter; + GtkTreeModel *model = (GtkTreeModel *)data; + + 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); + + GHashTable * new_credential; + new_credential = g_hash_table_new(NULL, g_str_equal); + g_hash_table_insert(new_credential, COLUMN_CREDENTIAL_REALM, "*"); + g_hash_table_insert(new_credential, COLUMN_CREDENTIAL_USERNAME, _("Authentication")); + g_hash_table_insert(new_credential, COLUMN_CREDENTIAL_PASSWORD, _("Secret")); + g_array_append_val(credential_information, new_credential); +} + +static void delete_credential_cb(GtkWidget *button, gpointer data) +{ + DEBUG("delete credential"); + GtkTreeIter iter; + GtkTreeView *treeview = (GtkTreeView *)data; + GtkTreeModel *model = gtk_tree_view_get_model (treeview); + GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview); + + 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); + + gint credential_index = gtk_tree_path_get_indices (path)[0]; + GHashTable * element = g_array_index(credential_information, GHashTable*, credential_index); + g_hash_table_foreach(element, hashtable_free, NULL); + g_hash_table_destroy(element); + g_free(element); + + gtk_tree_path_free (path); + } +} + +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")); + gtk_tree_model_get_iter (model, &iter, path); + + gtk_list_store_set (GTK_LIST_STORE (model), &iter, column, text, -1); + gint credential_index = gtk_tree_path_get_indices (path)[0]; + + GHashTable * element = g_array_index(credential_information, GHashTable*, credential_index); + switch(column) { + case COLUMN_CREDENTIAL_REALM: + g_hash_table_replace(element, ACCOUNT_REALM, g_strdup(text)); + break; + case COLUMN_CREDENTIAL_USERNAME: + g_hash_table_replace(element, ACCOUNT_USERNAME, g_strdup(text)); + break; + case COLUMN_CREDENTIAL_PASSWORD: + g_hash_table_replace(element, ACCOUNT_PASSWORD, g_strdup(text)); + break; + } + + gtk_tree_path_free (path); + + 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); + } + } +} + +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 * scrolledWindow; + GtkWidget * treeView; + 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 +430,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 +447,88 @@ 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 */ + credential_information = g_array_new(FALSE, FALSE, sizeof(GHashTable*)); + + 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); + + scrolledWindow = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledWindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledWindow), GTK_SHADOW_IN); + gtk_table_attach (GTK_TABLE(table), scrolledWindow, 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 + ); + + treeView = gtk_tree_view_new_with_model(GTK_TREE_MODEL(credentialStore)); + treeSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW (treeView)); + 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(treeView), 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(treeView), 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(treeView), treeViewColumn); + + gtk_container_add(GTK_CONTAINER(scrolledWindow), treeView); + + fill_treeview_with_credential(credentialStore, *a); + + /* Dynamically resize the window to fit the scrolled window */ + gtk_widget_size_request(GTK_WIDGET(treeView), &requisitionTreeView); + gtk_widget_set_size_request(GTK_WIDGET(scrolledWindow), requisitionTable.width, requisitionTreeView.height + 10); + + /* 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), treeView); + gtk_box_pack_start(GTK_BOX(hbox), deleteCredButton, FALSE, FALSE, 0); + + gtk_widget_show_all(ret); + return ret; } void diff --git a/sflphone-client-gnome/src/config/configwindow.c b/sflphone-client-gnome/src/config/configwindow.c index 1d436d118c8b7d43a099a59a774887fb4abd259c..2a09df877dd56b5993fd4427257763174d41a062 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 7e3888c2338960ea9c20d4d0d7e0fed94c09a4cf..d5935a39a220b88c8b6fef050a231a95acd483f3 100644 --- a/sflphone-client-gnome/src/dbus/configurationmanager-introspec.xml +++ b/sflphone-client-gnome/src/dbus/configurationmanager-introspec.xml @@ -15,6 +15,23 @@ <arg type="a{ss}" name="details" direction="in"/> </method> + <method name="setCredential"> + <arg type="s" name="accountID" direction="in"/> + <arg type="i" name="index" direction="in"/> + <arg type="a{ss}" name="credentialInformation" direction="in"/> + </method> + + <method name="getCredential"> + <arg type="s" name="accountID" direction="in"/> + <arg type="i" name="index" direction="in"/> + <arg type="a{ss}" name="credentialInformation" direction="out"/> + </method> + + <method name="getNumberOfCredential"> + <arg type="s" name="accountID" direction="in"/> + <arg type="i" name="numberOfCredential" direction="out"/> + </method> + <method name="addAccount"> <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="MapStringString"/> <arg type="a{ss}" name="details" direction="in"/> diff --git a/sflphone-client-gnome/src/dbus/dbus.c b/sflphone-client-gnome/src/dbus/dbus.c index b4ad2226dfcaa819ac46eda8f8d09b4ef3d15952..a7cb70713ed39ddda36cf9025582ce288409a588 100644 --- a/sflphone-client-gnome/src/dbus/dbus.c +++ b/sflphone-client-gnome/src/dbus/dbus.c @@ -559,6 +559,64 @@ GHashTable* dbus_account_details(gchar * accountID) } } + void +dbus_set_credential(account_t *a, int index) +{ + GError *error = NULL; + org_sflphone_SFLphone_ConfigurationManager_set_credential ( + configurationManagerProxy, + a->accountID, + index, + g_array_index(a->credential_information, GHashTable*, index), + &error); + if (error) { + ERROR ("Failed to call set_account_details() 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 0c46d263da68011555309b6e774fa8de6377b6d8..d6b03f7e43b3e345f7c8e2344831db837dff3a54 100644 --- a/sflphone-client-gnome/src/dbus/dbus.h +++ b/sflphone-client-gnome/src/dbus/dbus.h @@ -106,6 +106,37 @@ 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 - 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 3f0d9f97eb5200c111f2e8130bab602589cbae42..b3c5e121aa69e663c18af8327702dea646ecf2d2 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_AUTH_USERNAME "authenticationUsername" +#define ACCOUNT_REALM "realm" /** * Global logger diff --git a/sflphone-common/src/account.h b/sflphone-common/src/account.h index 72eee8cda7c126ef5f1d16adc653d2bdc1582257..d6c89e3eb14777c5a6b52cfc0faf86caf442bbd9 100644 --- a/sflphone-common/src/account.h +++ b/sflphone-common/src/account.h @@ -60,10 +60,12 @@ 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 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 7e3888c2338960ea9c20d4d0d7e0fed94c09a4cf..e4c304791803679f691a0409bb5f88bedb5ae012 100644 --- a/sflphone-common/src/dbus/configurationmanager-introspec.xml +++ b/sflphone-common/src/dbus/configurationmanager-introspec.xml @@ -15,6 +15,23 @@ <arg type="a{ss}" name="details" direction="in"/> </method> + <method name="setCredential"> + <arg type="s" name="accountID" direction="in"/> + <arg type="i" name="index" direction="in"/> + <arg type="a{ss}" name="credentialInformation" direction="in"/> + </method> + + <method name="getCredential"> + <arg type="s" name="accountID" direction="in"/> + <arg type="i" name="index" direction="in"/> + <arg type="a{ss}" name="credentialInformation" direction="out"/> + </method> + + <method name="getNumberOfCredential"> + <arg type="s" name="accountID" direction="in"/> + <arg type="i" name="numberOfCredential" direction="out"/> + </method> + <method name="addAccount"> <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="MapStringString"/> <arg type="a{ss}" name="details" direction="in"/> diff --git a/sflphone-common/src/dbus/configurationmanager.cpp b/sflphone-common/src/dbus/configurationmanager.cpp index 7afc9cb250eacae12e0490b5145f1eeae9aec89e..167dafda633513990aa872c7d16c3958f66ede0b 100644 --- a/sflphone-common/src/dbus/configurationmanager.cpp +++ b/sflphone-common/src/dbus/configurationmanager.cpp @@ -41,6 +41,76 @@ 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<std::string, std::string> 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<std::string, std::string> (USERNAME, username)); + credentialInformation.insert(std::pair<std::string, std::string> (PASSWORD, password)); + credentialInformation.insert(std::pair<std::string, std::string> (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::setCredential (const std::string& accountID, const int32_t& index, + const std::map< std::string, std::string >& details) +{ + _debug ("ConfigurationManager::setCredential received\n"); + + std::map<std::string, std::string>::iterator it; + std::map<std::string, std::string> credentialInformation = details; + + std::string credentialIndex; + std::stringstream streamOut; + streamOut << index; + credentialIndex = streamOut.str(); + + std::string section = "Credential" + std::string(":") + accountID + std::string(":") + credentialIndex; + + it = credentialInformation.find(USERNAME); + if(it == credentialInformation.end()) { + Manager::instance().setConfig (section, USERNAME, EMPTY_FIELD); + } else { + Manager::instance().setConfig (section, USERNAME, it->second); + } + + it = credentialInformation.find(PASSWORD); + if(it == credentialInformation.end()) { + Manager::instance().setConfig (section, PASSWORD, EMPTY_FIELD); + } else { + Manager::instance().setConfig (section, PASSWORD, it->second); + } + + it = credentialInformation.find(REALM); + if(it == credentialInformation.end()) { + Manager::instance().setConfig (section, REALM, EMPTY_FIELD); + } else { + Manager::instance().setConfig (section, REALM, it->second); + } + +} + 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 128f80e9605ba0a2baf1b48ad127e696290f24f8..2a7d51586d42fa121b175883555b0b7a9a501f15 100644 --- a/sflphone-common/src/dbus/configurationmanager.h +++ b/sflphone-common/src/dbus/configurationmanager.h @@ -46,6 +46,10 @@ public: 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); + 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 3fc1494d63ace7153b3f107087d4fd52c6207a7b..ce3d6597d5bb4d142eeaa0bfce0d8e69924836c7 100644 --- a/sflphone-common/src/managerimpl.cpp +++ b/sflphone-common/src/managerimpl.cpp @@ -2477,6 +2477,7 @@ std::map< std::string, std::string > ManagerImpl::getAccountDetails (const Accou a.insert (std::pair<std::string, std::string> (USERNAME, getConfigString (accountID, USERNAME))); a.insert (std::pair<std::string, std::string> (PASSWORD, getConfigString (accountID, PASSWORD))); a.insert (std::pair<std::string, std::string> (HOSTNAME, getConfigString (accountID, HOSTNAME))); + a.insert (std::pair<std::string, std::string> (REALM, getConfigString (accountID, REALM))); a.insert (std::pair<std::string, std::string> (CONFIG_ACCOUNT_MAILBOX, getConfigString (accountID, CONFIG_ACCOUNT_MAILBOX))); if (getConfigString (accountID, CONFIG_ACCOUNT_REGISTRATION_EXPIRE).empty()) { @@ -2523,6 +2524,9 @@ 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); @@ -2730,7 +2734,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; } @@ -2771,7 +2775,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/sipaccount.h b/sflphone-common/src/sipaccount.h index d7d06f9ebc8a73935cda543ccf2a34dd2152a659..ede4dba36f7e2dd68887d8e8649fc71269d9e896 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); @@ -83,11 +90,8 @@ class SIPAccount : public Account /* 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 +109,16 @@ class SIPAccount : public Account */ bool _bRegister; + bool _resolveOnce; + /* * SIP address */ std::string _contact; - bool _resolveOnce; - std::string _registrationExpire; + + std::string _authenticationUserName; }; #endif