mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-17 11:08:06 +00:00
841 lines
34 KiB
Objective-C
841 lines
34 KiB
Objective-C
/* LinphoneCoreSettingsStore.m
|
|
*
|
|
* Copyright (C) 2012 Belledonne Comunications, Grenoble, France
|
|
*
|
|
* 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
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#import "LinphoneCoreSettingsStore.h"
|
|
#import "Utils.h"
|
|
|
|
#include "linphone/lpconfig.h"
|
|
|
|
extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args);
|
|
|
|
@implementation LinphoneCoreSettingsStore
|
|
|
|
- (id)init {
|
|
self = [super init];
|
|
if (self) {
|
|
dict = [[NSMutableDictionary alloc] init];
|
|
changedDict = [[NSMutableDictionary alloc] init];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)setCString:(const char *)value forKey:(NSString *)key {
|
|
id obj = Nil;
|
|
if (value)
|
|
obj = [[NSString alloc] initWithCString:value encoding:[NSString defaultCStringEncoding]];
|
|
[self setObject:obj forKey:key];
|
|
}
|
|
|
|
- (NSString *)stringForKey:(NSString *)key {
|
|
return [self objectForKey:key];
|
|
}
|
|
|
|
- (void)setObject:(id)value forKey:(NSString *)key {
|
|
[dict setValue:value forKey:key];
|
|
[changedDict setValue:[NSNumber numberWithBool:TRUE] forKey:key];
|
|
}
|
|
|
|
- (id)objectForKey:(NSString *)key {
|
|
return [dict valueForKey:key];
|
|
}
|
|
|
|
- (BOOL)valueChangedForKey:(NSString *)key {
|
|
return [[changedDict valueForKey:key] boolValue];
|
|
}
|
|
|
|
+ (int)validPort:(int)port {
|
|
if (port < 0) {
|
|
return 0;
|
|
}
|
|
if (port > 65535) {
|
|
return 65535;
|
|
}
|
|
return port;
|
|
}
|
|
|
|
+ (BOOL)parsePortRange:(NSString *)text minPort:(int *)minPort maxPort:(int *)maxPort {
|
|
NSError *error = nil;
|
|
*minPort = -1;
|
|
*maxPort = -1;
|
|
NSRegularExpression *regex =
|
|
[NSRegularExpression regularExpressionWithPattern:@"([0-9]+)(([^0-9]+)([0-9]+))?" options:0 error:&error];
|
|
if (error != NULL)
|
|
return FALSE;
|
|
NSArray *matches = [regex matchesInString:text options:0 range:NSMakeRange(0, [text length])];
|
|
if ([matches count] == 1) {
|
|
NSTextCheckingResult *match = [matches objectAtIndex:0];
|
|
bool range = [match rangeAtIndex:2].length > 0;
|
|
if (!range) {
|
|
NSRange rangeMinPort = [match rangeAtIndex:1];
|
|
*minPort = [LinphoneCoreSettingsStore validPort:[[text substringWithRange:rangeMinPort] intValue]];
|
|
*maxPort = *minPort;
|
|
return TRUE;
|
|
} else {
|
|
NSRange rangeMinPort = [match rangeAtIndex:1];
|
|
*minPort = [LinphoneCoreSettingsStore validPort:[[text substringWithRange:rangeMinPort] intValue]];
|
|
NSRange rangeMaxPort = [match rangeAtIndex:4];
|
|
*maxPort = [LinphoneCoreSettingsStore validPort:[[text substringWithRange:rangeMaxPort] intValue]];
|
|
if (*minPort > *maxPort) {
|
|
*minPort = *maxPort;
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
- (void)transformCodecsToKeys:(const MSList *)codecs {
|
|
LinphoneCore *lc = [LinphoneManager getLc];
|
|
|
|
const MSList *elem = codecs;
|
|
for (; elem != NULL; elem = elem->next) {
|
|
PayloadType *pt = (PayloadType *)elem->data;
|
|
NSString *pref = [LinphoneManager getPreferenceForCodec:pt->mime_type withRate:pt->clock_rate];
|
|
if (pref) {
|
|
bool_t value = linphone_core_payload_type_enabled(lc, pt);
|
|
[self setBool:value forKey:pref];
|
|
} else {
|
|
LOGW(@"Codec %s/%i supported by core is not shown in iOS app config view.", pt->mime_type, pt->clock_rate);
|
|
}
|
|
}
|
|
}
|
|
|
|
- (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
|
|
{
|
|
const MSList *accounts = linphone_core_get_proxy_config_list([LinphoneManager getLc]);
|
|
int count = ms_list_size(accounts);
|
|
for (int i = 1; i <= count; i++, accounts = accounts->next) {
|
|
NSString *key = [NSString stringWithFormat:@"account_%d_menu", i];
|
|
LinphoneProxyConfig *proxy = (LinphoneProxyConfig *)accounts->data;
|
|
[self setCString:linphone_address_get_username(linphone_proxy_config_get_identity_address(proxy))
|
|
forKey:key];
|
|
}
|
|
|
|
[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
|
|
{
|
|
// this is filled by [self transformAccountToKeys] automatically
|
|
}
|
|
|
|
// audio section
|
|
{
|
|
[self transformCodecsToKeys:linphone_core_get_audio_codecs(lc)];
|
|
[self setFloat:linphone_core_get_playback_gain_db(lc) forKey:@"playback_gain_preference"];
|
|
[self setFloat:linphone_core_get_mic_gain_db(lc) forKey:@"microphone_gain_preference"];
|
|
[self setInteger:[lm lpConfigIntForKey:@"codec_bitrate_limit"
|
|
forSection:@"audio"
|
|
withDefault:kLinphoneAudioVbrCodecDefaultBitrate]
|
|
forKey:@"audio_codec_bitrate_limit_preference"];
|
|
[self setInteger:[lm lpConfigIntForKey:@"voiceproc_preference" withDefault:1] forKey:@"voiceproc_preference"];
|
|
[self setInteger:[lm lpConfigIntForKey:@"eq_active" forSection:@"sound" withDefault:0] forKey:@"eq_active"];
|
|
}
|
|
|
|
// video section
|
|
{
|
|
[self transformCodecsToKeys:linphone_core_get_video_codecs(lc)];
|
|
|
|
const LinphoneVideoPolicy *pol;
|
|
pol = linphone_core_get_video_policy(lc);
|
|
[self setBool:(pol->automatically_initiate)forKey:@"start_video_preference"];
|
|
[self setBool:(pol->automatically_accept)forKey:@"accept_video_preference"];
|
|
[self setBool:linphone_core_self_view_enabled(lc) forKey:@"self_video_preference"];
|
|
BOOL previewEnabled = [lm lpConfigBoolForKey:@"preview_preference" withDefault:YES];
|
|
[self setBool:previewEnabled forKey:@"preview_preference"];
|
|
|
|
const char *preset = linphone_core_get_video_preset(lc);
|
|
[self setCString:preset ? preset : "default" forKey:@"video_preset_preference"];
|
|
MSVideoSize vsize = linphone_core_get_preferred_video_size(lc);
|
|
int index;
|
|
if ((vsize.width == MS_VIDEO_SIZE_720P_W) && (vsize.height == MS_VIDEO_SIZE_720P_H)) {
|
|
index = 0;
|
|
} else if ((vsize.width == MS_VIDEO_SIZE_VGA_W) && (vsize.height == MS_VIDEO_SIZE_VGA_H)) {
|
|
index = 1;
|
|
} else {
|
|
index = 2;
|
|
}
|
|
[self setInteger:index forKey:@"video_preferred_size_preference"];
|
|
[self setInteger:linphone_core_get_preferred_framerate(lc) forKey:@"video_preferred_fps_preference"];
|
|
[self setInteger:linphone_core_get_download_bandwidth(lc) forKey:@"download_bandwidth_preference"];
|
|
}
|
|
|
|
// call section
|
|
{
|
|
[self setBool:linphone_core_get_use_info_for_dtmf(lc) forKey:@"sipinfo_dtmf_preference"];
|
|
[self setBool:linphone_core_get_use_rfc2833_for_dtmf(lc) forKey:@"rfc_dtmf_preference"];
|
|
|
|
[self setInteger:linphone_core_get_inc_timeout(lc) forKey:@"incoming_call_timeout_preference"];
|
|
[self setInteger:linphone_core_get_in_call_timeout(lc) forKey:@"in_call_timeout_preference"];
|
|
|
|
[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
|
|
{
|
|
[self setBool:[lm lpConfigBoolForKey:@"edge_opt_preference" withDefault:NO] forKey:@"edge_opt_preference"];
|
|
[self setBool:[lm lpConfigBoolForKey:@"wifi_only_preference" withDefault:NO] forKey:@"wifi_only_preference"];
|
|
[self setCString:linphone_core_get_stun_server(lc) forKey:@"stun_preference"];
|
|
[self setBool:linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce forKey:@"ice_preference"];
|
|
int random_port_preference = [lm lpConfigIntForKey:@"random_port_preference" withDefault:1];
|
|
[self setInteger:random_port_preference forKey:@"random_port_preference"];
|
|
int port = [lm lpConfigIntForKey:@"port_preference" withDefault:5060];
|
|
[self setInteger:port forKey:@"port_preference"];
|
|
{
|
|
int minPort, maxPort;
|
|
linphone_core_get_audio_port_range(lc, &minPort, &maxPort);
|
|
if (minPort != maxPort)
|
|
[self setObject:[NSString stringWithFormat:@"%d-%d", minPort, maxPort] forKey:@"audio_port_preference"];
|
|
else
|
|
[self setObject:[NSString stringWithFormat:@"%d", minPort] forKey:@"audio_port_preference"];
|
|
}
|
|
{
|
|
int minPort, maxPort;
|
|
linphone_core_get_video_port_range(lc, &minPort, &maxPort);
|
|
if (minPort != maxPort)
|
|
[self setObject:[NSString stringWithFormat:@"%d-%d", minPort, maxPort] forKey:@"video_port_preference"];
|
|
else
|
|
[self setObject:[NSString stringWithFormat:@"%d", minPort] forKey:@"video_port_preference"];
|
|
}
|
|
[self setBool:[lm lpConfigBoolForKey:@"use_ipv6" withDefault:NO] forKey:@"use_ipv6"];
|
|
LinphoneMediaEncryption menc = linphone_core_get_media_encryption(lc);
|
|
const char *val;
|
|
switch (menc) {
|
|
case LinphoneMediaEncryptionSRTP:
|
|
val = "SRTP";
|
|
break;
|
|
case LinphoneMediaEncryptionZRTP:
|
|
val = "ZRTP";
|
|
break;
|
|
case LinphoneMediaEncryptionDTLS:
|
|
val = "DTLS";
|
|
break;
|
|
case LinphoneMediaEncryptionNone:
|
|
val = "None";
|
|
break;
|
|
}
|
|
[self setCString:val forKey:@"media_encryption_preference"];
|
|
[self setBool:[lm lpConfigBoolForKey:@"pushnotification_preference" withDefault:NO]
|
|
forKey:@"pushnotification_preference"];
|
|
[self setInteger:linphone_core_get_upload_bandwidth(lc) forKey:@"upload_bandwidth_preference"];
|
|
[self setInteger:linphone_core_get_download_bandwidth(lc) forKey:@"download_bandwidth_preference"];
|
|
[self setBool:linphone_core_adaptive_rate_control_enabled(lc) forKey:@"adaptive_rate_control_preference"];
|
|
}
|
|
|
|
// tunnel section
|
|
if (linphone_core_tunnel_available()) {
|
|
LinphoneTunnel *tunnel = linphone_core_get_tunnel([LinphoneManager getLc]);
|
|
[self setObject:[lm lpConfigStringForKey:@"tunnel_mode_preference" withDefault:@"off"]
|
|
forKey:@"tunnel_mode_preference"];
|
|
const MSList *configs = linphone_tunnel_get_servers(tunnel);
|
|
if (configs != NULL) {
|
|
LinphoneTunnelConfig *ltc = (LinphoneTunnelConfig *)configs->data;
|
|
[self setCString:linphone_tunnel_config_get_host(ltc) forKey:@"tunnel_address_preference"];
|
|
[self setInteger:linphone_tunnel_config_get_port(ltc) forKey:@"tunnel_port_preference"];
|
|
} else {
|
|
[self setCString:"" forKey:@"tunnel_address_preference"];
|
|
[self setInteger:443 forKey:@"tunnel_port_preference"];
|
|
}
|
|
}
|
|
|
|
// advanced section
|
|
{
|
|
[self setBool:[lm lpConfigBoolForKey:@"debugenable_preference" withDefault:NO]
|
|
forKey:@"debugenable_preference"];
|
|
[self setBool:[lm lpConfigBoolForKey:@"animations_preference" withDefault:NO] forKey:@"animations_preference"];
|
|
[self setBool:[lm lpConfigBoolForKey:@"backgroundmode_preference" withDefault:NO]
|
|
forKey:@"backgroundmode_preference"];
|
|
[self setBool:[lm lpConfigBoolForKey:@"start_at_boot_preference" withDefault:NO]
|
|
forKey:@"start_at_boot_preference"];
|
|
[self setBool:[lm lpConfigBoolForKey:@"autoanswer_notif_preference" withDefault:NO]
|
|
forKey:@"autoanswer_notif_preference"];
|
|
[self setBool:[lm lpConfigBoolForKey:@"enable_first_login_view_preference" withDefault:NO]
|
|
forKey:@"enable_first_login_view_preference"];
|
|
LinphoneAddress *parsed = linphone_core_get_primary_contact_parsed(lc);
|
|
if (parsed != NULL) {
|
|
[self setCString:linphone_address_get_display_name(parsed) forKey:@"primary_displayname_preference"];
|
|
[self setCString:linphone_address_get_username(parsed) forKey:@"primary_username_preference"];
|
|
}
|
|
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];
|
|
|
|
// Post event
|
|
NSDictionary *eventDic = [NSDictionary dictionaryWithObject:self forKey:@"settings"];
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneLogsUpdate object:self userInfo:eventDic];
|
|
}
|
|
|
|
- (void)alertAccountError:(NSString *)error {
|
|
UIAlertView *alertview = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error", nil)
|
|
message:error
|
|
delegate:nil
|
|
cancelButtonTitle:NSLocalizedString(@"OK", nil)
|
|
otherButtonTitles:nil];
|
|
[alertview show];
|
|
}
|
|
|
|
- (void)synchronizeAccounts {
|
|
LOGI(@"Account changed, synchronizing.");
|
|
LinphoneManager *lm = [LinphoneManager instance];
|
|
LinphoneCore *lc = [LinphoneManager getLc];
|
|
LinphoneProxyConfig *proxyCfg = NULL;
|
|
BOOL isEditing = FALSE;
|
|
NSString *error = nil;
|
|
|
|
int port_preference = [self integerForKey:@"port_preference"];
|
|
|
|
BOOL random_port_preference = [self boolForKey:@"random_port_preference"];
|
|
[lm lpConfigSetInt:random_port_preference forKey:@"random_port_preference"];
|
|
if (random_port_preference) {
|
|
port_preference = -1;
|
|
}
|
|
|
|
LCSipTransports transportValue = {port_preference, port_preference, -1, -1};
|
|
|
|
// will also update the sip_*_port section of the config
|
|
if (linphone_core_set_sip_transports(lc, &transportValue)) {
|
|
LOGE(@"cannot set transport");
|
|
}
|
|
|
|
port_preference = linphone_core_get_sip_port(lc);
|
|
[self setInteger:port_preference forKey:@"port_preference"]; // Update back preference
|
|
|
|
BOOL enable_ipv6 = [self boolForKey:@"use_ipv6"];
|
|
[lm lpConfigSetBool:enable_ipv6 forKey:@"use_ipv6" forSection:@"sip"];
|
|
if (linphone_core_ipv6_enabled(lc) != enable_ipv6) {
|
|
LOGD(@"%@ IPV6", enable_ipv6 ? @"ENABLING" : @"DISABLING");
|
|
linphone_core_enable_ipv6(lc, enable_ipv6);
|
|
}
|
|
|
|
// configure sip account
|
|
|
|
// mandatory parameters
|
|
NSString *username = [self stringForKey:@"username_preference"];
|
|
NSString *userID = [self stringForKey:@"userid_preference"];
|
|
NSString *domain = [self stringForKey:@"domain_preference"];
|
|
NSString *transport = [self stringForKey:@"transport_preference"];
|
|
NSString *accountHa1 = [self stringForKey:@"ha1_preference"];
|
|
NSString *accountPassword = [self stringForKey:@"password_preference"];
|
|
bool isOutboundProxy = [self boolForKey:@"outbound_proxy_preference"];
|
|
BOOL use_avpf = [self boolForKey:@"avpf_preference"];
|
|
|
|
if (username && [username length] > 0 && domain && [domain length] > 0) {
|
|
int expire = [self integerForKey:@"expire_preference"];
|
|
BOOL isWifiOnly = [self boolForKey:@"wifi_only_preference"];
|
|
BOOL pushnotification = [self boolForKey:@"pushnotification_preference"];
|
|
NSString *prefix = [self stringForKey:@"prefix_preference"];
|
|
NSString *proxyAddress = [self stringForKey:@"proxy_preference"];
|
|
|
|
LinphoneAuthInfo *info = NULL;
|
|
const char *route = NULL;
|
|
|
|
if (isWifiOnly && [LinphoneManager instance].connectivity == wwan)
|
|
expire = 0;
|
|
|
|
if ((!proxyAddress || [proxyAddress length] < 1) && domain) {
|
|
proxyAddress = domain;
|
|
}
|
|
|
|
if (![proxyAddress hasPrefix:@"sip:"] && ![proxyAddress hasPrefix:@"sips:"]) {
|
|
proxyAddress = [NSString stringWithFormat:@"sip:%@", proxyAddress];
|
|
}
|
|
|
|
char *proxy = ms_strdup([proxyAddress cStringUsingEncoding:[NSString defaultCStringEncoding]]);
|
|
LinphoneAddress *proxy_addr = linphone_address_new(proxy);
|
|
|
|
if (proxy_addr) {
|
|
LinphoneTransportType type = LinphoneTransportUdp;
|
|
if ([transport isEqualToString:@"tcp"])
|
|
type = LinphoneTransportTcp;
|
|
else if ([transport isEqualToString:@"tls"])
|
|
type = LinphoneTransportTls;
|
|
|
|
linphone_address_set_transport(proxy_addr, type);
|
|
ms_free(proxy);
|
|
proxy = linphone_address_as_string_uri_only(proxy_addr);
|
|
}
|
|
|
|
// possible valid config detected, try to modify current proxy or create new one if none existing
|
|
proxyCfg = linphone_core_get_default_proxy_config(lc);
|
|
if (proxyCfg == NULL) {
|
|
proxyCfg = linphone_core_create_proxy_config(lc);
|
|
} else {
|
|
isEditing = TRUE;
|
|
linphone_proxy_config_edit(proxyCfg);
|
|
}
|
|
|
|
char normalizedUserName[256];
|
|
LinphoneAddress *linphoneAddress = linphone_address_new("sip:user@domain.com");
|
|
linphone_proxy_config_normalize_number(proxyCfg,
|
|
[username cStringUsingEncoding:[NSString defaultCStringEncoding]],
|
|
normalizedUserName, sizeof(normalizedUserName));
|
|
linphone_address_set_username(linphoneAddress, normalizedUserName);
|
|
linphone_address_set_domain(linphoneAddress, [domain cStringUsingEncoding:[NSString defaultCStringEncoding]]);
|
|
|
|
const char *identity = linphone_address_as_string_uri_only(linphoneAddress);
|
|
const char *password = [accountPassword cStringUsingEncoding:[NSString defaultCStringEncoding]];
|
|
const char *ha1 = [accountHa1 cStringUsingEncoding:[NSString defaultCStringEncoding]];
|
|
|
|
if (linphone_proxy_config_set_identity(proxyCfg, identity) == -1) {
|
|
error = NSLocalizedString(@"Invalid username or domain", nil);
|
|
goto bad_proxy;
|
|
}
|
|
// use proxy as route if outbound_proxy is enabled
|
|
route = isOutboundProxy ? proxy : NULL;
|
|
if (linphone_proxy_config_set_server_addr(proxyCfg, proxy) == -1) {
|
|
error = NSLocalizedString(@"Invalid proxy address", nil);
|
|
goto bad_proxy;
|
|
}
|
|
if (linphone_proxy_config_set_route(proxyCfg, route) == -1) {
|
|
error = NSLocalizedString(@"Invalid route", nil);
|
|
goto bad_proxy;
|
|
}
|
|
|
|
if ([prefix length] > 0) {
|
|
linphone_proxy_config_set_dial_prefix(proxyCfg,
|
|
[prefix cStringUsingEncoding:[NSString defaultCStringEncoding]]);
|
|
}
|
|
|
|
if ([self objectForKey:@"substitute_+_by_00_preference"]) {
|
|
bool substitute_plus_by_00 = [self boolForKey:@"substitute_+_by_00_preference"];
|
|
linphone_proxy_config_set_dial_escape_plus(proxyCfg, substitute_plus_by_00);
|
|
}
|
|
|
|
[lm lpConfigSetInt:pushnotification forKey:@"pushnotification_preference"];
|
|
[[LinphoneManager instance] configurePushTokenForProxyConfig:proxyCfg];
|
|
|
|
linphone_proxy_config_enable_register(proxyCfg, true);
|
|
linphone_proxy_config_enable_avpf(proxyCfg, use_avpf);
|
|
linphone_proxy_config_set_expires(proxyCfg, expire);
|
|
|
|
// setup auth info
|
|
if (linphone_core_get_auth_info_list(lc)) {
|
|
info = linphone_auth_info_clone(linphone_core_get_auth_info_list(lc)->data);
|
|
linphone_auth_info_set_username(info, username.UTF8String);
|
|
if (password) {
|
|
linphone_auth_info_set_passwd(info, password);
|
|
linphone_auth_info_set_ha1(info, NULL);
|
|
}
|
|
linphone_auth_info_set_domain(info, linphone_proxy_config_get_domain(proxyCfg));
|
|
} else {
|
|
LinphoneAddress *from = linphone_address_new(identity);
|
|
if (from) {
|
|
const char *userid_str = (userID != nil) ? [userID UTF8String] : NULL;
|
|
info = linphone_auth_info_new(
|
|
linphone_address_get_username(from), userid_str, password ? password : NULL, password ? NULL : ha1,
|
|
linphone_proxy_config_get_realm(proxyCfg), linphone_proxy_config_get_domain(proxyCfg));
|
|
linphone_address_destroy(from);
|
|
}
|
|
}
|
|
|
|
// We reached here without hitting the goto: the new settings are correct, so replace the previous ones.
|
|
|
|
// add auth info
|
|
linphone_core_clear_all_auth_info(lc);
|
|
if (info) {
|
|
linphone_core_add_auth_info(lc, info);
|
|
}
|
|
|
|
// setup new proxycfg
|
|
if (isEditing) {
|
|
linphone_proxy_config_done(proxyCfg);
|
|
} else {
|
|
// was a new proxy config, add it
|
|
linphone_core_add_proxy_config(lc, proxyCfg);
|
|
linphone_core_set_default_proxy_config(lc, proxyCfg);
|
|
}
|
|
|
|
bad_proxy:
|
|
if (linphoneAddress)
|
|
linphone_address_destroy(linphoneAddress);
|
|
if (proxy)
|
|
ms_free(proxy);
|
|
if (info)
|
|
linphone_auth_info_destroy(info);
|
|
|
|
// in case of error, show an alert to the user
|
|
if (error != nil) {
|
|
if (isEditing)
|
|
linphone_proxy_config_done(proxyCfg);
|
|
else
|
|
linphone_proxy_config_destroy(proxyCfg);
|
|
|
|
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error", nil)
|
|
message:error
|
|
delegate:nil
|
|
cancelButtonTitle:NSLocalizedString(@"OK", nil)
|
|
otherButtonTitles:nil] show];
|
|
}
|
|
}
|
|
// reload address book to prepend proxy config domain to contacts' phone number
|
|
[[[LinphoneManager instance] fastAddressBook] reload];
|
|
}
|
|
|
|
- (void)synchronizeCodecs:(const MSList *)codecs {
|
|
LinphoneCore *lc = [LinphoneManager getLc];
|
|
PayloadType *pt;
|
|
const MSList *elem;
|
|
|
|
for (elem = codecs; elem != NULL; elem = elem->next) {
|
|
pt = (PayloadType *)elem->data;
|
|
NSString *pref = [LinphoneManager getPreferenceForCodec:pt->mime_type withRate:pt->clock_rate];
|
|
linphone_core_enable_payload_type(lc, pt, [self boolForKey:pref]);
|
|
}
|
|
}
|
|
|
|
- (BOOL)synchronize {
|
|
LinphoneManager *lm = [LinphoneManager instance];
|
|
LinphoneCore *lc = [LinphoneManager getLc];
|
|
// root section
|
|
{
|
|
BOOL account_changed =
|
|
[self valueChangedForKey:@"username_preference"] || [self valueChangedForKey:@"password_preference"] ||
|
|
[self valueChangedForKey:@"domain_preference"] || [self valueChangedForKey:@"expire_preference"] ||
|
|
[self valueChangedForKey:@"proxy_preference"] || [self valueChangedForKey:@"outbound_proxy_preference"] ||
|
|
[self valueChangedForKey:@"transport_preference"] || [self valueChangedForKey:@"port_preference"] ||
|
|
[self valueChangedForKey:@"random_port_preference"] || [self valueChangedForKey:@"prefix_preference"] ||
|
|
[self valueChangedForKey:@"substitute_+_by_00_preference"] || [self valueChangedForKey:@"use_ipv6"] ||
|
|
[self valueChangedForKey:@"avpf_preference"] || [self valueChangedForKey:@"pushnotification_preference"];
|
|
if (account_changed)
|
|
[self synchronizeAccounts];
|
|
|
|
bool enableVideo = [self boolForKey:@"enable_video_preference"];
|
|
linphone_core_enable_video(lc, enableVideo, enableVideo);
|
|
|
|
bool enableAutoAnswer = [self boolForKey:@"enable_auto_answer_preference"];
|
|
[LinphoneManager.instance lpConfigSetBool:enableAutoAnswer forKey:@"auto_answer"];
|
|
}
|
|
|
|
// audio section
|
|
{
|
|
[self synchronizeCodecs:linphone_core_get_audio_codecs(lc)];
|
|
|
|
float playback_gain = [self floatForKey:@"playback_gain_preference"];
|
|
linphone_core_set_playback_gain_db(lc, playback_gain);
|
|
|
|
float mic_gain = [self floatForKey:@"microphone_gain_preference"];
|
|
linphone_core_set_mic_gain_db(lc, mic_gain);
|
|
|
|
[lm lpConfigSetInt:[self integerForKey:@"audio_codec_bitrate_limit_preference"]
|
|
forKey:@"codec_bitrate_limit"
|
|
forSection:@"audio"];
|
|
|
|
BOOL voice_processing = [self boolForKey:@"voiceproc_preference"];
|
|
[lm lpConfigSetInt:voice_processing forKey:@"voiceproc_preference"];
|
|
|
|
BOOL equalizer = [self boolForKey:@"eq_active"];
|
|
[lm lpConfigSetBool:equalizer forKey:@"eq_active" forSection:@"sound"];
|
|
|
|
[[LinphoneManager instance] configureVbrCodecs];
|
|
|
|
NSString *au_device = @"AU: Audio Unit Receiver";
|
|
if (!voice_processing) {
|
|
au_device = @"AU: Audio Unit NoVoiceProc";
|
|
}
|
|
linphone_core_set_capture_device(lc, [au_device UTF8String]);
|
|
linphone_core_set_playback_device(lc, [au_device UTF8String]);
|
|
}
|
|
|
|
// video section
|
|
{
|
|
[self synchronizeCodecs:linphone_core_get_video_codecs(lc)];
|
|
|
|
LinphoneVideoPolicy policy;
|
|
policy.automatically_initiate = [self boolForKey:@"start_video_preference"];
|
|
policy.automatically_accept = [self boolForKey:@"accept_video_preference"];
|
|
linphone_core_set_video_policy(lc, &policy);
|
|
linphone_core_enable_self_view(lc, [self boolForKey:@"self_video_preference"]);
|
|
BOOL preview_preference = [self boolForKey:@"preview_preference"];
|
|
[lm lpConfigSetInt:preview_preference forKey:@"preview_preference"];
|
|
|
|
NSString *videoPreset = [self stringForKey:@"video_preset_preference"];
|
|
linphone_core_set_video_preset(lc, [videoPreset UTF8String]);
|
|
int bw;
|
|
MSVideoSize vsize;
|
|
switch ([self integerForKey:@"video_preferred_size_preference"]) {
|
|
case 0:
|
|
MS_VIDEO_SIZE_ASSIGN(vsize, 720P);
|
|
// 128 = margin for audio, the BW includes both video and audio
|
|
bw = 1024 + 128;
|
|
break;
|
|
case 1:
|
|
MS_VIDEO_SIZE_ASSIGN(vsize, VGA);
|
|
// no margin for VGA or QVGA, because video encoders can encode the
|
|
// target resulution in less than the asked bandwidth
|
|
bw = 660;
|
|
break;
|
|
case 2:
|
|
default:
|
|
MS_VIDEO_SIZE_ASSIGN(vsize, QVGA);
|
|
bw = 380;
|
|
break;
|
|
}
|
|
linphone_core_set_preferred_video_size(lc, vsize);
|
|
if (![videoPreset isEqualToString:@"custom"]) {
|
|
[self setInteger:0 forKey:@"video_preferred_fps_preference"];
|
|
[self setInteger:bw forKey:@"download_bandwidth_preference"];
|
|
}
|
|
linphone_core_set_preferred_framerate(lc, [self integerForKey:@"video_preferred_fps_preference"]);
|
|
linphone_core_set_download_bandwidth(lc, [self integerForKey:@"download_bandwidth_preference"]);
|
|
linphone_core_set_upload_bandwidth(lc, [self integerForKey:@"download_bandwidth_preference"]);
|
|
}
|
|
|
|
// call section
|
|
{
|
|
linphone_core_set_use_rfc2833_for_dtmf(lc, [self boolForKey:@"rfc_dtmf_preference"]);
|
|
linphone_core_set_use_info_for_dtmf(lc, [self boolForKey:@"sipinfo_dtmf_preference"]);
|
|
linphone_core_set_inc_timeout(lc, [self integerForKey:@"incoming_call_timeout_preference"]);
|
|
linphone_core_set_in_call_timeout(lc, [self integerForKey:@"in_call_timeout_preference"]);
|
|
[lm lpConfigSetString:[self stringForKey:@"voice_mail_uri_preference"] forKey:@"voice_mail_uri"];
|
|
[lm lpConfigSetBool:[self boolForKey:@"repeat_call_notification_preference"]
|
|
forKey:@"repeat_call_notification"];
|
|
}
|
|
|
|
// network section
|
|
{
|
|
BOOL edgeOpt = [self boolForKey:@"edge_opt_preference"];
|
|
[lm lpConfigSetInt:edgeOpt forKey:@"edge_opt_preference"];
|
|
|
|
BOOL wifiOnly = [self boolForKey:@"wifi_only_preference"];
|
|
[lm lpConfigSetInt:wifiOnly forKey:@"wifi_only_preference"];
|
|
if ([self valueChangedForKey:@"wifi_only_preference"]) {
|
|
[[LinphoneManager instance] setupNetworkReachabilityCallback];
|
|
}
|
|
|
|
NSString *stun_server = [self stringForKey:@"stun_preference"];
|
|
if ([stun_server length] > 0) {
|
|
linphone_core_set_stun_server(lc, [stun_server UTF8String]);
|
|
BOOL ice_preference = [self boolForKey:@"ice_preference"];
|
|
if (ice_preference) {
|
|
linphone_core_set_firewall_policy(lc, LinphonePolicyUseIce);
|
|
} else {
|
|
linphone_core_set_firewall_policy(lc, LinphonePolicyUseStun);
|
|
}
|
|
} else {
|
|
linphone_core_set_stun_server(lc, NULL);
|
|
linphone_core_set_firewall_policy(lc, LinphonePolicyNoFirewall);
|
|
}
|
|
|
|
{
|
|
NSString *audio_port_preference = [self stringForKey:@"audio_port_preference"];
|
|
int minPort, maxPort;
|
|
[LinphoneCoreSettingsStore parsePortRange:audio_port_preference minPort:&minPort maxPort:&maxPort];
|
|
linphone_core_set_audio_port_range(lc, minPort, maxPort);
|
|
}
|
|
{
|
|
NSString *video_port_preference = [self stringForKey:@"video_port_preference"];
|
|
int minPort, maxPort;
|
|
[LinphoneCoreSettingsStore parsePortRange:video_port_preference minPort:&minPort maxPort:&maxPort];
|
|
linphone_core_set_video_port_range(lc, minPort, maxPort);
|
|
}
|
|
|
|
NSString *menc = [self stringForKey:@"media_encryption_preference"];
|
|
if (menc && [menc compare:@"SRTP"] == NSOrderedSame)
|
|
linphone_core_set_media_encryption(lc, LinphoneMediaEncryptionSRTP);
|
|
else if (menc && [menc compare:@"ZRTP"] == NSOrderedSame)
|
|
linphone_core_set_media_encryption(lc, LinphoneMediaEncryptionZRTP);
|
|
else if (menc && [menc compare:@"DTLS"] == NSOrderedSame)
|
|
linphone_core_set_media_encryption(lc, LinphoneMediaEncryptionDTLS);
|
|
else
|
|
linphone_core_set_media_encryption(lc, LinphoneMediaEncryptionNone);
|
|
|
|
linphone_core_enable_adaptive_rate_control(lc, [self boolForKey:@"adaptive_rate_control_preference"]);
|
|
}
|
|
|
|
// tunnel section
|
|
{
|
|
if (linphone_core_tunnel_available()) {
|
|
NSString *lTunnelPrefMode = [self stringForKey:@"tunnel_mode_preference"];
|
|
NSString *lTunnelPrefAddress = [self stringForKey:@"tunnel_address_preference"];
|
|
int lTunnelPrefPort = [self integerForKey:@"tunnel_port_preference"];
|
|
LinphoneTunnel *tunnel = linphone_core_get_tunnel([LinphoneManager getLc]);
|
|
TunnelMode mode = tunnel_off;
|
|
int lTunnelPort = 443;
|
|
if (lTunnelPrefPort) {
|
|
lTunnelPort = lTunnelPrefPort;
|
|
}
|
|
|
|
linphone_tunnel_clean_servers(tunnel);
|
|
if (lTunnelPrefAddress && [lTunnelPrefAddress length]) {
|
|
LinphoneTunnelConfig *ltc = linphone_tunnel_config_new();
|
|
linphone_tunnel_config_set_host(ltc, [lTunnelPrefAddress UTF8String]);
|
|
linphone_tunnel_config_set_port(ltc, lTunnelPort);
|
|
linphone_tunnel_add_server(tunnel, ltc);
|
|
|
|
if ([lTunnelPrefMode isEqualToString:@"off"]) {
|
|
mode = tunnel_off;
|
|
} else if ([lTunnelPrefMode isEqualToString:@"on"]) {
|
|
mode = tunnel_on;
|
|
} else if ([lTunnelPrefMode isEqualToString:@"wwan"]) {
|
|
mode = tunnel_wwan;
|
|
} else if ([lTunnelPrefMode isEqualToString:@"auto"]) {
|
|
mode = tunnel_auto;
|
|
} else {
|
|
LOGE(@"Unexpected tunnel mode [%s]",
|
|
[lTunnelPrefMode cStringUsingEncoding:[NSString defaultCStringEncoding]]);
|
|
}
|
|
}
|
|
|
|
[lm lpConfigSetString:lTunnelPrefMode forKey:@"tunnel_mode_preference"];
|
|
[[LinphoneManager instance] setTunnelMode:mode];
|
|
}
|
|
}
|
|
|
|
// advanced section
|
|
{
|
|
BOOL debugmode = [self boolForKey:@"debugenable_preference"];
|
|
[lm lpConfigSetInt:debugmode forKey:@"debugenable_preference"];
|
|
[[LinphoneManager instance] setLogsEnabled:debugmode];
|
|
|
|
BOOL animations = [self boolForKey:@"animations_preference"];
|
|
[lm lpConfigSetInt:animations forKey:@"animations_preference"];
|
|
|
|
UIDevice *device = [UIDevice currentDevice];
|
|
bool backgroundSupported =
|
|
[device respondsToSelector:@selector(isMultitaskingSupported)] && [device isMultitaskingSupported];
|
|
BOOL isbackgroundModeEnabled = backgroundSupported && [self boolForKey:@"backgroundmode_preference"];
|
|
[lm lpConfigSetInt:isbackgroundModeEnabled forKey:@"backgroundmode_preference"];
|
|
|
|
[lm lpConfigSetInt:[self integerForKey:@"start_at_boot_preference"] forKey:@"start_at_boot_preference"];
|
|
[lm lpConfigSetInt:[self integerForKey:@"autoanswer_notif_preference"] forKey:@"autoanswer_notif_preference"];
|
|
|
|
BOOL firstloginview = [self boolForKey:@"enable_first_login_view_preference"];
|
|
[lm lpConfigSetInt:firstloginview forKey:@"enable_first_login_view_preference"];
|
|
|
|
NSString *displayname = [self stringForKey:@"primary_displayname_preference"];
|
|
NSString *username = [self stringForKey:@"primary_username_preference"];
|
|
LinphoneAddress *parsed = linphone_core_get_primary_contact_parsed(lc);
|
|
if (parsed != NULL) {
|
|
linphone_address_set_display_name(parsed,
|
|
[displayname cStringUsingEncoding:[NSString defaultCStringEncoding]]);
|
|
linphone_address_set_username(parsed, [username cStringUsingEncoding:[NSString defaultCStringEncoding]]);
|
|
char *contact = linphone_address_as_string(parsed);
|
|
linphone_core_set_primary_contact(lc, contact);
|
|
ms_free(contact);
|
|
linphone_address_destroy(parsed);
|
|
}
|
|
|
|
[lm lpConfigSetInt:[self integerForKey:@"advanced_account_preference"] forKey:@"advanced_account_preference"];
|
|
|
|
linphone_core_set_file_transfer_server(lc,
|
|
[[self stringForKey:@"file_transfer_server_url_preference"] UTF8String]);
|
|
}
|
|
|
|
changedDict = [[NSMutableDictionary alloc] init];
|
|
|
|
// Post event
|
|
NSDictionary *eventDic = [NSDictionary dictionaryWithObject:self forKey:@"settings"];
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneSettingsUpdate object:self userInfo:eventDic];
|
|
|
|
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
|