From 8cb78d85a142816b4360dec9fa5e4348cb0ee235 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 15 Oct 2015 18:01:05 +0200 Subject: [PATCH] Multiaccount: handle settings --- Classes/LinphoneCoreSettingsStore.h | 2 + Classes/LinphoneCoreSettingsStore.m | 161 ++++++++++-------- Classes/LinphoneManager.m | 9 +- Classes/SettingsView.m | 71 +++++--- .../IASKAppSettingsViewController.h | 1 + .../IASKAppSettingsViewController.m | 10 +- README.md | 2 +- Resources/assistant_linphone_create.rc | 4 +- Resources/assistant_linphone_existing.rc | 3 +- 9 files changed, 154 insertions(+), 109 deletions(-) diff --git a/Classes/LinphoneCoreSettingsStore.h b/Classes/LinphoneCoreSettingsStore.h index 224b8f679..f95f65f47 100644 --- a/Classes/LinphoneCoreSettingsStore.h +++ b/Classes/LinphoneCoreSettingsStore.h @@ -29,5 +29,7 @@ } - (void)transformLinphoneCoreToKeys; +- (void)transformAccountToKeys:(NSString *)username; +- (void)removeAccount; @end diff --git a/Classes/LinphoneCoreSettingsStore.m b/Classes/LinphoneCoreSettingsStore.m index 55584ead6..89c903af5 100644 --- a/Classes/LinphoneCoreSettingsStore.m +++ b/Classes/LinphoneCoreSettingsStore.m @@ -116,9 +116,73 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); } } +- (void)transformAccountToKeys:(NSString *)username { + LinphoneCore *lc = [LinphoneManager getLc]; + const MSList *proxies = linphone_core_get_proxy_config_list(lc); + while (proxies && + strcmp(username.UTF8String, + linphone_address_get_username(linphone_proxy_config_get_identity_address(proxies->data))) != 0) { + proxies = proxies->next; + } + if (!proxies) { + // we must always find associated proxy config. + LOGF(@"Proxy not found for account with username %@. Please fix application.", username); + } + LinphoneProxyConfig *proxy = proxies->data; + + [self setInteger:ms_list_index(linphone_core_get_proxy_config_list(lc), proxy) + forKey:@"current_proxy_config_preference"]; + + const LinphoneAddress *identity_addr = linphone_proxy_config_get_identity_address(proxy); + if (identity_addr) { + const char *server_addr = linphone_proxy_config_get_server_addr(proxy); + LinphoneAddress *proxy_addr = linphone_address_new(server_addr); + int port = linphone_address_get_port(proxy_addr); + + [self setCString:linphone_address_get_username(identity_addr) forKey:@"username_preference"]; + [self setCString:linphone_address_get_domain(identity_addr) forKey:@"domain_preference"]; + if (strcmp(linphone_address_get_domain(identity_addr), linphone_address_get_domain(proxy_addr)) != 0 || + port > 0) { + char tmp[256] = {0}; + if (port > 0) { + snprintf(tmp, sizeof(tmp) - 1, "%s:%i", linphone_address_get_domain(proxy_addr), port); + } else + snprintf(tmp, sizeof(tmp) - 1, "%s", linphone_address_get_domain(proxy_addr)); + [self setCString:tmp forKey:@"proxy_preference"]; + } + const char *tname = "udp"; + switch (linphone_address_get_transport(proxy_addr)) { + case LinphoneTransportTcp: + tname = "tcp"; + break; + case LinphoneTransportTls: + tname = "tls"; + break; + default: + break; + } + linphone_address_destroy(proxy_addr); + + [self setCString:tname forKey:@"transport_preference"]; + [self setBool:(linphone_proxy_config_get_route(proxy) != NULL) forKey:@"outbound_proxy_preference"]; + [self setBool:linphone_proxy_config_avpf_enabled(proxy) forKey:@"avpf_preference"]; + + const LinphoneAuthInfo *ai = + linphone_core_find_auth_info(lc, NULL, [self stringForKey:@"username_preference"].UTF8String, + [self stringForKey:@"domain_preference"].UTF8String); + if (ai) { + [self setCString:linphone_auth_info_get_userid(ai) forKey:@"userid_preference"]; + [self setCString:linphone_auth_info_get_passwd(ai) forKey:@"password_preference"]; + // hidden but useful if provisioned + [self setCString:linphone_auth_info_get_ha1(ai) forKey:@"ha1_preference"]; + } + } +} + - (void)transformLinphoneCoreToKeys { LinphoneManager *lm = [LinphoneManager instance]; LinphoneCore *lc = [LinphoneManager getLc]; + LinphoneProxyConfig *default_proxy = linphone_core_get_default_proxy_config(lc); // root section { @@ -134,80 +198,11 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); [self setBool:linphone_core_video_enabled(lc) forKey:@"enable_video_preference"]; [self setBool:[LinphoneManager.instance lpConfigBoolForKey:@"auto_answer"] forKey:@"enable_auto_answer_preference"]; + [self setBool:[lm lpConfigBoolForKey:@"advanced_account_preference"] forKey:@"advanced_account_preference"]; } // account section { - // todo - /* - LinphoneProxyConfig *cfg = NULL; - linphone_core_get_default_proxy(lc, &cfg); - if (cfg) { - const char *identity = linphone_proxy_config_get_identity(cfg); - LinphoneAddress *addr = linphone_address_new(identity); - if (addr) { - const char *proxy = linphone_proxy_config_get_addr(cfg); - LinphoneAddress *proxy_addr = linphone_address_new(proxy); - int port = linphone_address_get_port(proxy_addr); - - [self setCString:linphone_address_get_username(addr) forKey:@"username_preference"]; - [self setCString:linphone_address_get_domain(addr) forKey:@"domain_preference"]; - if (strcmp(linphone_address_get_domain(addr), linphone_address_get_domain(proxy_addr)) != 0 || - port > 0) { - char tmp[256] = {0}; - if (port > 0) { - snprintf(tmp, sizeof(tmp) - 1, "%s:%i", linphone_address_get_domain(proxy_addr), port); - } else - snprintf(tmp, sizeof(tmp) - 1, "%s", linphone_address_get_domain(proxy_addr)); - [self setCString:tmp forKey:@"proxy_preference"]; - } - const char *tname = "udp"; - switch (linphone_address_get_transport(proxy_addr)) { - case LinphoneTransportTcp: - tname = "tcp"; - break; - case LinphoneTransportTls: - tname = "tls"; - break; - default: - break; - } - linphone_address_destroy(addr); - linphone_address_destroy(proxy_addr); - - [self setCString:tname forKey:@"transport_preference"]; - [self setBool:(linphone_proxy_config_get_route(cfg) != NULL)forKey:@"outbound_proxy_preference"]; - [self setBool:linphone_proxy_config_avpf_enabled(cfg) forKey:@"avpf_preference"]; - - // actually in Advanced section but proxy config dependent - [self setInteger:linphone_proxy_config_get_expires(cfg) forKey:@"expire_preference"]; - // actually in Call section but proxy config dependent - [self setCString:linphone_proxy_config_get_dial_prefix(cfg) forKey:@"prefix_preference"]; - // actually in Call section but proxy config dependent - [self setBool:linphone_proxy_config_get_dial_escape_plus(cfg) forKey:@"substitute_+_by_00_preference"]; - } - } else { - [self setObject:@"" forKey:@"username_preference"]; - [self setObject:@"" forKey:@"password_preference"]; - [self setObject:@"" forKey:@"domain_preference"]; - [self setObject:@"" forKey:@"proxy_preference"]; - [self setCString:"udp" forKey:@"transport_preference"]; - [self setBool:FALSE forKey:@"outbound_proxy_preference"]; - [self setBool:FALSE forKey:@"avpf_preference"]; - // actually in Advanced section but proxy config dependent - [self setInteger:[lm lpConfigIntForKey:@"reg_expires" forSection:@"default_values" withDefault:600] - forKey:@"expire_preference"]; - } - - LinphoneAuthInfo *ai; - const MSList *elem = linphone_core_get_auth_info_list(lc); - if (elem && (ai = (LinphoneAuthInfo *)elem->data)) { - [self setCString:linphone_auth_info_get_userid(ai) forKey:@"userid_preference"]; - [self setCString:linphone_auth_info_get_passwd(ai) forKey:@"password_preference"]; - // hidden but useful if provisioned - [self setCString:linphone_auth_info_get_ha1(ai) forKey:@"ha1_preference"]; - } - [self setBool:[lm lpConfigBoolForKey:@"advanced_account_preference"] forKey:@"advanced_account_preference"]; - */ + // this is filled by [self transformAccountToKeys] automatically } // audio section @@ -261,6 +256,13 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); [self setBool:[lm lpConfigBoolForKey:@"repeat_call_notification"] forKey:@"repeat_call_notification_preference"]; + + // actually in Call section but proxy config dependent + const char *dial_prefix = default_proxy ? linphone_proxy_config_get_dial_prefix(default_proxy) : NULL; + [self setCString:dial_prefix forKey:@"prefix_preference"]; + // actually in Call section but proxy config dependent + BOOL dial_escape_plus = default_proxy ? linphone_proxy_config_get_dial_escape_plus(default_proxy) : NO; + [self setBool:dial_escape_plus forKey:@"substitute_+_by_00_preference"]; } // network section @@ -350,6 +352,10 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); } linphone_address_destroy(parsed); [self setCString:linphone_core_get_file_transfer_server(lc) forKey:@"file_transfer_server_url_preference"]; + + // actually in Advanced section but proxy config dependent + int expires = default_proxy ? linphone_proxy_config_get_expires(default_proxy) : -1; + [self setInteger:expires forKey:@"expire_preference"]; } changedDict = [[NSMutableDictionary alloc] init]; @@ -368,7 +374,8 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); [alertview show]; } -- (void)synchronizeAccount { +- (void)synchronizeAccounts { + LOGI(@"Account changed, synchronizing."); LinphoneManager *lm = [LinphoneManager instance]; LinphoneCore *lc = [LinphoneManager getLc]; LinphoneProxyConfig *proxyCfg = NULL; @@ -590,7 +597,7 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); [self valueChangedForKey:@"substitute_+_by_00_preference"] || [self valueChangedForKey:@"use_ipv6"] || [self valueChangedForKey:@"avpf_preference"] || [self valueChangedForKey:@"pushnotification_preference"]; if (account_changed) - [self synchronizeAccount]; + [self synchronizeAccounts]; bool enableVideo = [self boolForKey:@"enable_video_preference"]; linphone_core_enable_video(lc, enableVideo, enableVideo); @@ -823,4 +830,12 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); return YES; } +- (void)removeAccount { + LinphoneCore *lc = [LinphoneManager getLc]; + LinphoneProxyConfig *config = ms_list_nth_data(linphone_core_get_proxy_config_list(lc), + [self integerForKey:@"current_proxy_config_preference"]); + linphone_core_remove_proxy_config(lc, config); + linphone_core_clear_all_auth_info(lc); // TODO: only remove the right one + [self transformLinphoneCoreToKeys]; +} @end diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 6ca5f58dc..f1d2363a3 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -876,6 +876,8 @@ static void linphone_iphone_popup_password_request(LinphoneCore *lc, const char [alertView dismissWithClickedButtonIndex:0 animated:NO]; } + __weak UITextField *passwordField = [alertView textFieldAtIndex:0]; + alertView = [[DTAlertView alloc] initWithTitle:NSLocalizedString(@"Authentication needed.", nil) message:[NSString stringWithFormat:NSLocalizedString(@"Registration failed because authentication is " @@ -885,8 +887,11 @@ static void linphone_iphone_popup_password_request(LinphoneCore *lc, const char nil), username, realm]]; alertView.alertViewStyle = UIAlertViewStyleSecureTextInput; - [alertView addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) block:nil]; - __weak UITextField *passwordField = [alertView textFieldAtIndex:0]; + [alertView addCancelButtonWithTitle:NSLocalizedString(@"Go to settings", nil) + block:^{ + SettingsView *view = VIEW(SettingsView); + [PhoneMainView.instance changeCurrentView:view.compositeViewDescription]; + }]; [alertView addButtonWithTitle:NSLocalizedString(@"Continue", nil) block:^{ diff --git a/Classes/SettingsView.m b/Classes/SettingsView.m index d82523d91..2b838926b 100644 --- a/Classes/SettingsView.m +++ b/Classes/SettingsView.m @@ -337,6 +337,7 @@ labelTitleView.text = viewController.title; [labelTitleView sizeToFit]; viewController.navigationItem.titleView = labelTitleView; + [super pushViewController:viewController animated:animated]; } @@ -358,9 +359,6 @@ @implementation SettingsView -@synthesize settingsController; -@synthesize navigationController; - #pragma mark - UICompositeViewDelegate Functions static UICompositeViewDescription *compositeDescription = nil; @@ -388,21 +386,21 @@ static UICompositeViewDescription *compositeDescription = nil; settingsStore = [[LinphoneCoreSettingsStore alloc] init]; - settingsController.showDoneButton = FALSE; - settingsController.delegate = self; - settingsController.showCreditsFooter = FALSE; - settingsController.settingsStore = settingsStore; + _settingsController.showDoneButton = FALSE; + _settingsController.delegate = self; + _settingsController.showCreditsFooter = FALSE; + _settingsController.settingsStore = settingsStore; - [navigationController.view setBackgroundColor:[UIColor clearColor]]; + [_navigationController.view setBackgroundColor:[UIColor clearColor]]; - navigationController.view.frame = self.view.frame; - [navigationController pushViewController:settingsController animated:FALSE]; - [self.view addSubview:navigationController.view]; + _navigationController.view.frame = self.view.frame; + [_navigationController pushViewController:_settingsController animated:FALSE]; + [self.view addSubview:_navigationController.view]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; - [settingsController dismiss:self]; + [_settingsController dismiss:self]; // Set observer [[NSNotificationCenter defaultCenter] removeObserver:self name:kIASKAppSettingChanged object:nil]; } @@ -412,8 +410,8 @@ static UICompositeViewDescription *compositeDescription = nil; // Sync settings with linphone core settings [settingsStore transformLinphoneCoreToKeys]; - settingsController.hiddenKeys = [self findHiddenKeys]; - [settingsController.tableView reloadData]; + _settingsController.hiddenKeys = [self findHiddenKeys]; + [_settingsController.tableView reloadData]; // Set observer [[NSNotificationCenter defaultCenter] addObserver:self @@ -425,7 +423,7 @@ static UICompositeViewDescription *compositeDescription = nil; #pragma mark - Event Functions - (void)appSettingChanged:(NSNotification *)notif { - NSMutableSet *hiddenKeys = [NSMutableSet setWithSet:[settingsController hiddenKeys]]; + NSMutableSet *hiddenKeys = [NSMutableSet setWithSet:[_settingsController hiddenKeys]]; NSMutableArray *keys = [NSMutableArray array]; BOOL removeFromHiddenKeys = TRUE; @@ -468,7 +466,7 @@ static UICompositeViewDescription *compositeDescription = nil; [hiddenKeys addObject:key]; } - [settingsController setHiddenKeys:hiddenKeys animated:TRUE]; + [_settingsController setHiddenKeys:hiddenKeys animated:TRUE]; } #pragma mark - @@ -658,10 +656,27 @@ static UICompositeViewDescription *compositeDescription = nil; - (void)settingsViewControllerDidEnd:(IASKAppSettingsViewController *)sender { } +- (void)settingsViewControllerDidAppear:(IASKAppSettingsViewController *)sender { + // going to account: fill info + if ([sender.file isEqualToString:@"Account"]) { + LOGI(@"Going editting account %@", sender.title); + [settingsStore transformAccountToKeys:sender.title]; + // coming back to default: if we were in account, we must synchronize account now + } else if ([sender.file isEqualToString:@"Root"]) { + [settingsStore synchronize]; + // it's a bit violent... but IASK is not designed to dynamically change subviews' name + [_settingsController.settingsReader indexPathForKey:@"account_1_menu"]; // force refresh username' + [_settingsController.settingsReader indexPathForKey:@"account_2_menu"]; // force refresh username' + [_settingsController.settingsReader indexPathForKey:@"account_3_menu"]; // force refresh username' + [_settingsController.settingsReader indexPathForKey:@"account_4_menu"]; // force refresh username' + [_settingsController.settingsReader indexPathForKey:@"account_5_menu"]; // force refresh username' + [[_settingsController tableView] reloadData]; + } +} + - (void)settingsViewController:(IASKAppSettingsViewController *)sender buttonTappedForSpecifier:(IASKSpecifier *)specifier { NSString *key = [specifier.specifierDict objectForKey:kIASKKey]; - LinphoneCore *lc = [LinphoneManager getLc]; #ifdef DEBUG if ([key isEqual:@"release_button"]) { [UIApplication sharedApplication].keyWindow.rootViewController = nil; @@ -682,10 +697,6 @@ static UICompositeViewDescription *compositeDescription = nil; [PhoneMainView.instance changeCurrentView:AssistantView.compositeViewDescription]; return; } else if ([key isEqual:@"remove_proxy_button"]) { - if (linphone_core_get_default_proxy_config(lc) == NULL) { - return; - } - DTAlertView *alert = [[DTAlertView alloc] initWithTitle:NSLocalizedString(@"Warning", nil) message:NSLocalizedString(@"Are you sure to want to remove your proxy setup?", nil)]; @@ -693,13 +704,21 @@ static UICompositeViewDescription *compositeDescription = nil; [alert addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) block:nil]; [alert addButtonWithTitle:NSLocalizedString(@"Yes", nil) block:^{ - linphone_core_clear_proxy_config(lc); - linphone_core_clear_all_auth_info(lc); - [settingsStore transformLinphoneCoreToKeys]; - [settingsController.tableView reloadData]; + [settingsStore removeAccount]; + _settingsController.hiddenKeys = [self findHiddenKeys]; + [_settingsController.settingsReader + indexPathForKey:@"account_1_menu"]; // force refresh username' + [_settingsController.settingsReader + indexPathForKey:@"account_2_menu"]; // force refresh username' + [_settingsController.settingsReader + indexPathForKey:@"account_3_menu"]; // force refresh username' + [_settingsController.settingsReader + indexPathForKey:@"account_4_menu"]; // force refresh username' + [_settingsController.settingsReader + indexPathForKey:@"account_5_menu"]; // force refresh username' + [_settingsController.navigationController popViewControllerAnimated:NO]; }]; [alert show]; - } else if ([key isEqual:@"about_button"]) { [PhoneMainView.instance changeCurrentView:AboutView.compositeViewDescription push:TRUE]; } else if ([key isEqualToString:@"reset_logs_button"]) { diff --git a/Classes/Utils/InAppSettingsKit/Controllers/IASKAppSettingsViewController.h b/Classes/Utils/InAppSettingsKit/Controllers/IASKAppSettingsViewController.h index 10847d4d8..cc8a87285 100755 --- a/Classes/Utils/InAppSettingsKit/Controllers/IASKAppSettingsViewController.h +++ b/Classes/Utils/InAppSettingsKit/Controllers/IASKAppSettingsViewController.h @@ -26,6 +26,7 @@ @protocol IASKSettingsDelegate - (void)settingsViewControllerDidEnd:(IASKAppSettingsViewController*)sender; +- (void)settingsViewControllerDidAppear:(IASKAppSettingsViewController *)sender; @optional #pragma mark - UITableView header customization diff --git a/Classes/Utils/InAppSettingsKit/Controllers/IASKAppSettingsViewController.m b/Classes/Utils/InAppSettingsKit/Controllers/IASKAppSettingsViewController.m index 8f101232d..78bc62aac 100755 --- a/Classes/Utils/InAppSettingsKit/Controllers/IASKAppSettingsViewController.m +++ b/Classes/Utils/InAppSettingsKit/Controllers/IASKAppSettingsViewController.m @@ -203,6 +203,12 @@ CGRect IASKCGRectSwap(CGRect rect); object:[NSUserDefaults standardUserDefaults]]; [self userDefaultsDidChange]; // force update in case of changes while we were hidden } + + // hack gautier: be notified when changing page + if (self.delegate && [self.delegate conformsToProtocol:@protocol(IASKSettingsDelegate)]) { + [self.delegate settingsViewControllerDidAppear:self]; + } + [super viewWillAppear:animated]; } @@ -720,8 +726,8 @@ CGRect IASKCGRectSwap(CGRect rect); targetViewController.title = specifier.title; targetViewController.showCreditsFooter = NO; [[self navigationController] pushViewController:targetViewController animated:YES]; - } else if ([[specifier type] isEqualToString:kIASKOpenURLSpecifier]) { - [tableView deselectRowAtIndexPath:indexPath animated:YES]; + } else if ([[specifier type] isEqualToString:kIASKOpenURLSpecifier]) { + [tableView deselectRowAtIndexPath:indexPath animated:YES]; [[UIApplication sharedApplication] openURL:[NSURL URLWithString:specifier.file]]; } else if ([[specifier type] isEqualToString:kIASKButtonSpecifier]) { [tableView deselectRowAtIndexPath:indexPath animated:YES]; diff --git a/README.md b/README.md index 4e63b151f..66c708928 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ This SDK can be generated in 2 flavors: * NO GPL third parties means that Linphone will only use non GPL code except for `liblinphone`, `mediastreamer2`, `oRTP` and `belle-sip`. If you choose this flavor, your final application is **still subject to GPL except if you have a [commercial license for the mentioned libraries](http://www.belledonne-communications.com/products.html)**. To generate the liblinphone multi arch SDK without GPL third parties, invoke: - ./prepare.py --disable-gpl-third-parties=no [other options] && make + ./prepare.py --disable-gpl-third-parties [other options] && make ## Customizing features diff --git a/Resources/assistant_linphone_create.rc b/Resources/assistant_linphone_create.rc index 0f85ee58b..0e1eb50b6 100644 --- a/Resources/assistant_linphone_create.rc +++ b/Resources/assistant_linphone_create.rc @@ -2,7 +2,6 @@
- <sip:sip.linphone.org;transport=tls> sip:?@sip.linphone.org 1314000 1 @@ -12,11 +11,10 @@ sip:voip-metrics@sip.linphone.org;transport=tls 1 180 - sip.linphone.org
- ^[a-z0-9-_\\.]*$ + ^[a-z0-9_.\-]*$ sip.linphone.org https://www.linphone.org/assistant.php https://www.linphone.org:444/lft.php diff --git a/Resources/assistant_linphone_existing.rc b/Resources/assistant_linphone_existing.rc index 0f85ee58b..5f9ffbc90 100644 --- a/Resources/assistant_linphone_existing.rc +++ b/Resources/assistant_linphone_existing.rc @@ -2,7 +2,6 @@
- <sip:sip.linphone.org;transport=tls> sip:?@sip.linphone.org 1314000 1 @@ -16,7 +15,7 @@
- ^[a-z0-9-_\\.]*$ + ^[a-z0-9_.\-]*$ sip.linphone.org https://www.linphone.org/assistant.php https://www.linphone.org:444/lft.php