diff --git a/Classes/LinphoneCoreSettingsStore.h b/Classes/LinphoneCoreSettingsStore.h
index 49180e690..b3e656704 100644
--- a/Classes/LinphoneCoreSettingsStore.h
+++ b/Classes/LinphoneCoreSettingsStore.h
@@ -30,6 +30,8 @@
- (void)transformLinphoneCoreToKeys;
- (void)transformAccountToKeys:(NSString *)username;
+- (void)transformLdapToKeys:(NSString *)ldap_server;
- (void)removeAccount;
+- (void)removeLdap;
@end
diff --git a/Classes/LinphoneCoreSettingsStore.m b/Classes/LinphoneCoreSettingsStore.m
index 1203c80a2..b08f62311 100644
--- a/Classes/LinphoneCoreSettingsStore.m
+++ b/Classes/LinphoneCoreSettingsStore.m
@@ -257,6 +257,87 @@
}
}
+
+- (void)transformLdapToKeys:(NSString *)ldap_server {
+ const MSList *ldaps = linphone_core_get_ldap_list(LC);
+ while (ldap_server && ldaps &&
+ strcmp(ldap_server.UTF8String,
+ linphone_ldap_params_get_server(linphone_ldap_get_params(ldaps->data))) != 0) {
+ ldaps = ldaps->next;
+ }
+ LinphoneLdap *ldap = NULL;
+
+ // default values
+ {
+ [self setBool:YES forKey:@"ldap_enabled"];
+ [self setObject:@"" forKey:@"ldap_server"];
+ [self setObject:@"" forKey:@"ldap_bind_dn"];
+ [self setObject:@"" forKey:@"ldap_password"];
+ [self setObject:@"simple" forKey:@"ldap_auth_method"];
+ [self setBool:YES forKey:@"ldap_tls_enabled"];
+ [self setObject:@"default" forKey:@"ldap_certificates_verification_mode"];
+ [self setObject:@"" forKey:@"ldap_filter"];
+ [self setInteger:50 forKey:@"ldap_max_results"];
+ [self setInteger:5 forKey:@"ldap_timeout"];
+ [self setInteger:500 forKey:@"ldap_delay"];
+ [self setInteger:3 forKey:@"ldap_min_chars"];
+ [self setObject:@"" forKey:@"ldap_name_attribute"];
+ [self setObject:@"" forKey:@"ldap_sip_attribute"];
+ [self setObject:@"" forKey:@"ldap_sip_domain"];
+ [self setBool:NO forKey:@"ldap_logs_enabled"];
+ }
+
+ if (ldaps) {
+ ldap = ldaps->data;
+ LinphoneLdapParams const *ldapParams = linphone_ldap_get_params(ldap);
+
+ int idx = (int)bctbx_list_index(linphone_core_get_ldap_list(LC), ldap);
+ [self setInteger:idx forKey:@"current_ldap_index"];
+
+ [self setBool:linphone_ldap_params_get_enabled(ldapParams) forKey:@"ldap_enabled"];
+ [self setCString:linphone_ldap_params_get_server(ldapParams) forKey:@"ldap_server"];
+ [self setCString:linphone_ldap_params_get_bind_dn(ldapParams) forKey:@"ldap_bind_dn"];
+ [self setCString:linphone_ldap_params_get_password(ldapParams) forKey:@"ldap_password"];
+ [self setBool:linphone_ldap_params_tls_enabled(ldapParams) forKey:@"ldap_tls_enabled"];
+
+ switch (linphone_ldap_params_get_auth_method(ldapParams)) {
+ case LinphoneLdapAuthMethodSimple:
+ [self setObject:@"simple" forKey:@"ldap_auth_method"];
+ break;
+ case LinphoneLdapAuthMethodAnonymous:
+ [self setObject:@"anonymous" forKey:@"ldap_auth_method"];
+ break;
+ }
+
+ switch (linphone_ldap_params_get_server_certificates_verification_mode(ldapParams)) {
+ case LinphoneLdapCertVerificationDefault:
+ [self setObject:@"default" forKey:@"ldap_certificates_verification_mode"];
+ break;
+ case LinphoneLdapCertVerificationEnabled:
+ [self setObject:@"enabled" forKey:@"ldap_certificates_verification_mode"];
+ break;
+ case LinphoneLdapCertVerificationDisabled:
+ [self setObject:@"disabled" forKey:@"ldap_certificates_verification_mode"];
+ break;
+ }
+
+ [self setCString:linphone_ldap_params_get_base_object(ldapParams) forKey:@"ldap_base_object"];
+ [self setCString:linphone_ldap_params_get_filter(ldapParams) forKey:@"ldap_filter"];
+ [self setInteger:linphone_ldap_params_get_max_results(ldapParams) forKey:@"ldap_max_results"];
+ [self setInteger:linphone_ldap_params_get_timeout(ldapParams) forKey:@"ldap_timeout"];
+ [self setInteger:linphone_ldap_params_get_delay(ldapParams) forKey:@"ldap_delay"];
+ [self setInteger:linphone_ldap_params_get_min_chars(ldapParams) forKey:@"ldap_min_chars"];
+
+
+ [self setCString:linphone_ldap_params_get_name_attribute(ldapParams) forKey:@"ldap_name_attribute"];
+ [self setCString:linphone_ldap_params_get_sip_attribute(ldapParams) forKey:@"ldap_sip_attribute"];
+ [self setCString:linphone_ldap_params_get_sip_domain(ldapParams) forKey:@"ldap_sip_domain"];
+
+ bool ldapLogsEnabled = linphone_ldap_params_get_debug_level(ldapParams) == LinphoneLdapDebugLevelVerbose;
+ [self setBool:ldapLogsEnabled forKey:@"ldap_logs_enabled"];
+ }
+}
+
- (void)transformLinphoneCoreToKeys {
LinphoneManager *lm = LinphoneManager.instance;
@@ -424,6 +505,11 @@
[self setInteger:443 forKey:@"tunnel_port_preference"];
}
}
+
+ // contacts section
+ if (linphone_core_ldap_available(LC)) {
+ [self transformLdapToKeys:nil];
+ }
// advanced section
{
@@ -687,6 +773,71 @@
}
}
+- (void)synchronizeLdap {
+ LOGI(@"LDAP config changed, synchronizing.");
+
+ LinphoneLdap*ldap = bctbx_list_nth_data(linphone_core_get_ldap_list(LC), [self integerForKey:@"current_ldap_index"]);
+ if (!ldap) {
+ return;
+ }
+
+ if ([self stringForKey:@"ldap_base_object"].length == 0) {
+ UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Error", nil)
+ message:@"LDAPResearch base must not be empty"
+ preferredStyle:UIAlertControllerStyleAlert];
+
+ UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction * action) {}];
+
+ [errView addAction:defaultAction];
+ [PhoneMainView.instance presentViewController:errView animated:YES completion:nil];
+ return;
+ }
+
+ LinphoneLdapParams *newLdapParams = linphone_ldap_params_clone(linphone_ldap_get_params(ldap));
+
+ // Connexion parameters
+ linphone_ldap_params_set_enabled(newLdapParams, [self boolForKey:@"ldap_enabled"]);
+ linphone_ldap_params_set_server(newLdapParams, [self stringForKey:@"ldap_server"].UTF8String);
+ linphone_ldap_params_set_bind_dn(newLdapParams, [self stringForKey:@"ldap_bind_dn"].UTF8String);
+ linphone_ldap_params_set_password(newLdapParams, [self stringForKey:@"ldap_password"].UTF8String);
+
+ LinphoneLdapAuthMethod authMethod = [[self stringForKey:@"ldap_verification_method"] isEqualToString:@"simple"] ? LinphoneLdapAuthMethodSimple : LinphoneLdapAuthMethodAnonymous;
+ linphone_ldap_params_set_auth_method(newLdapParams, authMethod);
+ linphone_ldap_params_enable_tls(newLdapParams, [self boolForKey:@"ldap_tls_enabled"]);
+
+
+ LinphoneLdapCertVerificationMode certVerifMode = LinphoneLdapCertVerificationDefault;
+ NSString *certVerifModeStr = [self stringForKey:@"ldap_certificates_verification_mode"];
+ if ([certVerifModeStr isEqualToString:@"enabled"])
+ certVerifMode = LinphoneLdapCertVerificationEnabled;
+ else if ([certVerifModeStr isEqualToString:@"disabled"])
+ certVerifMode = LinphoneLdapCertVerificationEnabled;
+ linphone_ldap_params_set_server_certificates_verification_mode(newLdapParams, certVerifMode);
+
+ // Research parameters
+ linphone_ldap_params_set_base_object(newLdapParams, [self stringForKey:@"ldap_base_object"].UTF8String);
+ linphone_ldap_params_set_filter(newLdapParams, [self stringForKey:@"ldap_filter"].UTF8String);
+ linphone_ldap_params_set_max_results(newLdapParams, [self integerForKey:@"ldap_max_results"]);
+ linphone_ldap_params_set_timeout(newLdapParams, [self integerForKey:@"ldap_timeout"]);
+ linphone_ldap_params_set_delay(newLdapParams, [self integerForKey:@"ldap_delay"]);
+ linphone_ldap_params_set_min_chars(newLdapParams, [self integerForKey:@"ldap_min_chars"]);
+
+
+
+ // Analysis parameters
+ linphone_ldap_params_set_name_attribute(newLdapParams, [self stringForKey:@"ldap_name_attributes"].UTF8String);
+ linphone_ldap_params_set_sip_attribute(newLdapParams, [self stringForKey:@"ldap_sip_attributes"].UTF8String);
+ linphone_ldap_params_set_sip_domain(newLdapParams, [self stringForKey:@"ldap_sip_domain"].UTF8String);
+
+ // Miscellaneous parameters
+ LinphoneLdapDebugLevel debugLevel = [self boolForKey:@"ldap_logs_enabled"] ? LinphoneLdapDebugLevelVerbose : LinphoneLdapDebugLevelOff;
+ linphone_ldap_params_set_debug_level(newLdapParams, debugLevel);
+
+ linphone_ldap_set_params(ldap, newLdapParams);
+}
+
- (BOOL)synchronize {
@try {
LinphoneManager *lm = LinphoneManager.instance;
@@ -705,7 +856,7 @@
if (account_changed)
[self synchronizeAccounts];
-
+
bool enableVideo = [self boolForKey:@"enable_video_preference"];
linphone_core_enable_video_capture(LC, enableVideo);
linphone_core_enable_video_display(LC, enableVideo);
@@ -911,6 +1062,19 @@
linphone_tunnel_set_mode(tunnel, mode);
}
+ // contacts section
+
+
+ BOOL ldap_changed = NO;
+ for (NSString *key in self->changedDict) {
+ if ([key hasPrefix:@"ldap_"] && [self valueChangedForKey:key]) {
+ ldap_changed = YES;
+ break;
+ }
+ }
+ if (ldap_changed)
+ [self synchronizeLdap];
+
// advanced section
BOOL animations = [self boolForKey:@"animations_preference"];
[lm lpConfigSetInt:animations forKey:@"animations_preference"];
@@ -1012,4 +1176,11 @@
}
[self transformLinphoneCoreToKeys];
}
+
+- (void)removeLdap {
+ LinphoneLdap *ldap = bctbx_list_nth_data(linphone_core_get_ldap_list(LC),
+ [self integerForKey:@"current_ldap_index"]);
+ linphone_core_remove_ldap(LC, ldap);
+ [self transformLinphoneCoreToKeys];
+}
@end
diff --git a/Classes/SettingsView.m b/Classes/SettingsView.m
index 4064de1fb..86954998b 100644
--- a/Classes/SettingsView.m
+++ b/Classes/SettingsView.m
@@ -592,7 +592,33 @@ void update_hash_cbs(LinphoneAccountCreator *creator, LinphoneAccountCreatorStat
[specifier.specifierDict setValue:name forKey:kIASKTitle];
}
}
-
+
+ if ([specifier.key hasPrefix:@"ldap_"]) {
+ if (linphone_core_ldap_available(LC)) {
+ const bctbx_list_t *ldaps = linphone_core_get_ldap_list(LC);
+ int index = [specifier.key substringFromIndex:@"ldap_".length].intValue - 1;
+ if (index < bctbx_list_size(ldaps)) {
+ const LinphoneLdapParams *ldapParams = linphone_ldap_get_params(bctbx_list_nth_data(ldaps, index));
+
+ NSString *name = [NSString
+ stringWithUTF8String:linphone_ldap_params_get_server(ldapParams)];
+ [specifier.specifierDict setValue:name forKey:kIASKTitle];
+ }
+ }
+ }
+
+
+ if ([[specifier key] isEqualToString:@"ldap_auth_method"]) {
+ NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[specifier specifierDict]];
+ NSMutableArray *titles = [NSMutableArray arrayWithArray:[dict objectForKey:@"Titles"]];
+ [titles removeObject:@"TLS"];
+ [dict setObject:titles forKey:@"Titles"];
+ NSMutableArray *values = [NSMutableArray arrayWithArray:[dict objectForKey:@"Values"]];
+ [values removeObject:@"tls"];
+ [dict setObject:values forKey:@"Values"];
+ return [[IASKSpecifier alloc] initWithSpecifier:dict];
+ }
+
return specifier;
}
@@ -605,10 +631,17 @@ void update_hash_cbs(LinphoneAccountCreator *creator, LinphoneAccountCreatorStat
[hiddenKeys addObject:[NSString stringWithFormat:@"menu_account_%lu", i]];
}
+ const MSList *ldaps = linphone_core_get_ldap_list(LC);
+ for (size_t i = bctbx_list_size(ldaps) + 1; i <= 5; i++) {
+ [hiddenKeys addObject:[NSString stringWithFormat:@"ldap_%lu", i]];
+ }
if (!linphone_core_sip_transport_supported(LC, LinphoneTransportTls)) {
[hiddenKeys addObject:@"media_encryption_preference"];
}
+ if (!linphone_core_ldap_available(LC)) {
+ [hiddenKeys addObject:@"contacts_menu"];
+ }
#ifndef DEBUG
[hiddenKeys addObject:@"debug_actions_group"];
[hiddenKeys addObject:@"release_button"];
@@ -743,6 +776,17 @@ void update_hash_cbs(LinphoneAccountCreator *creator, LinphoneAccountCreatorStat
[[_settingsController tableView] reloadData];
}
+-(void)recomputeLdapLabelsAndSync {
+ // it's a bit violent... but IASK is not designed to dynamically change subviews' name
+ _settingsController.hiddenKeys = [self findHiddenKeys];
+ [_settingsController.settingsReader indexPathForKey:@"ldap_1"]; // force refresh ldap server name display
+ [_settingsController.settingsReader indexPathForKey:@"ldap_2"]; // force refresh ldap server name display
+ [_settingsController.settingsReader indexPathForKey:@"ldap_3"]; // force refresh ldap server name display
+ [_settingsController.settingsReader indexPathForKey:@"ldap_4"]; // force refresh ldap server name display
+ [_settingsController.settingsReader indexPathForKey:@"ldap_5"]; // force refresh ldap server name display
+ [[_settingsController tableView] reloadData];
+}
+
#pragma mark - IASKSettingsDelegate Functions
- (void)settingsViewControllerDidEnd:(IASKAppSettingsViewController *)sender {
@@ -754,10 +798,15 @@ void update_hash_cbs(LinphoneAccountCreator *creator, LinphoneAccountCreatorStat
// going to account: fill account specific info
if ([sender.file isEqualToString:@"Account"]) {
- LOGI(@"Going editting account %@", sender.title);
+ LOGI(@"Going editing 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"]) {
+ } else if ([sender.file isEqualToString:@"Contacts"]) {
+ [settingsStore synchronize];
+ [self recomputeLdapLabelsAndSync];
+ } else if ([sender.file isEqualToString:@"LDAP"]) {
+ LOGI(@"Going editing LDAP config %@", sender.title);
+ [settingsStore transformLdapToKeys:sender.title];
+ } else if ([sender.file isEqualToString:@"Root"]) { // coming back to default: if we were in account, we must synchronize account now
[settingsStore synchronize];
[self recomputeAccountLabelsAndSync];
}
@@ -987,6 +1036,32 @@ void update_hash_cbs(LinphoneAccountCreator *creator, LinphoneAccountCreatorStat
[self presentViewController:errView animated:YES completion:nil];
} else if ([key isEqual:@"send_db_button"]) {
[self sendEmailWithPrivacyAttachments];
+ } else if ([key isEqual:@"new_ldap_button"]) {
+ if (bctbx_list_size(linphone_core_get_ldap_list(LC)) < 5 ) {
+ linphone_core_add_ldap(LC, linphone_core_create_ldap(LC));
+ [self recomputeLdapLabelsAndSync];
+ }
+ } else if ([key isEqual:@"ldap_remove_button"]) {
+ UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Warning", nil)
+ message:NSLocalizedString(@"Are you sure to want to remove your LDAP config?", nil)
+ preferredStyle:UIAlertControllerStyleAlert];
+
+ UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction * action) {}];
+
+ UIAlertAction* continueAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Yes", nil)
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction * action) {
+ [settingsStore removeLdap];
+ [self recomputeLdapLabelsAndSync];
+ [_settingsController.navigationController popViewControllerAnimated:NO];
+ }];
+
+
+ [errView addAction:defaultAction];
+ [errView addAction:continueAction];
+ [self presentViewController:errView animated:YES completion:nil];
}
}
diff --git a/Settings/InAppSettings.bundle/Contacts.plist b/Settings/InAppSettings.bundle/Contacts.plist
new file mode 100644
index 000000000..4bba4dfc3
--- /dev/null
+++ b/Settings/InAppSettings.bundle/Contacts.plist
@@ -0,0 +1,73 @@
+
+
+
+
+ PreferenceSpecifiers
+
+
+ Title
+ LDAP configs
+ Type
+ PSGroupSpecifier
+
+
+ Key
+ new_ldap_button
+ Title
+ Add new LDAP config (5 max)
+ Type
+ IASKButtonSpecifier
+
+
+ Key
+ ldap_1
+ File
+ LDAP
+ Title
+ LDAP 1
+ Type
+ PSChildPaneSpecifier
+
+
+ Key
+ ldap_2
+ File
+ LDAP
+ Title
+ LDAP 2
+ Type
+ PSChildPaneSpecifier
+
+
+ Key
+ ldap_3
+ File
+ LDAP
+ Title
+ LDAP 3
+ Type
+ PSChildPaneSpecifier
+
+
+ Key
+ ldap_4
+ File
+ LDAP
+ Title
+ LDAP 4
+ Type
+ PSChildPaneSpecifier
+
+
+ Key
+ ldap_5
+ File
+ LDAP
+ Title
+ LDAP 5
+ Type
+ PSChildPaneSpecifier
+
+
+
+
diff --git a/Settings/InAppSettings.bundle/LDAP.plist b/Settings/InAppSettings.bundle/LDAP.plist
new file mode 100644
index 000000000..f1658bd04
--- /dev/null
+++ b/Settings/InAppSettings.bundle/LDAP.plist
@@ -0,0 +1,318 @@
+
+
+
+
+ PreferenceSpecifiers
+
+
+ Type
+ PSToggleSwitchSpecifier
+ Title
+ Enabled
+ Key
+ ldap_enabled
+ DefaultValue
+
+
+
+ Key
+ ldap_remove_button
+ Title
+ Delete this LDAP config
+ Type
+ IASKButtonSpecifier
+
+
+ Title
+ Connexion
+ Type
+ PSGroupSpecifier
+
+
+ Key
+ ldap_server
+ Title
+ Server URL
+ Type
+ PSTextFieldSpecifier
+ AutocapitalizationType
+ None
+ AutocorrectionType
+ No
+ DefaultValue
+
+ IASKTextAlignment
+ IASKUITextAlignmentRight
+
+
+ Key
+ ldap_bind_dn
+ Title
+ Bind DN
+ Type
+ PSTextFieldSpecifier
+ AutocapitalizationType
+ None
+ AutocorrectionType
+ No
+ DefaultValue
+
+ IASKTextAlignment
+ IASKUITextAlignmentRight
+
+
+ IASKTextAlignment
+ IASKUITextAlignmentRight
+ AutocapitalizationType
+ None
+ AutocorrectionType
+ No
+ DefaultValue
+
+ IsSecure
+
+ Key
+ lda^p
+ KeyboardType
+ Alphabet
+ Title
+ Password
+ Type
+ PSTextFieldSpecifier
+
+
+ DefaultValue
+ simple
+ Key
+ ldap_auth_method
+ Title
+ Authentication Method
+ Titles
+
+ Simple
+ Anonymous
+
+ Type
+ PSMultiValueSpecifier
+ Values
+
+ simple
+ anonymous
+
+
+
+ Type
+ PSToggleSwitchSpecifier
+ Title
+ Use TLS
+ Key
+ ldap_tls_enabled
+ DefaultValue
+
+
+
+ DefaultValue
+ simple
+ Key
+ ldap_certificates_verification_mode
+ Title
+ Certificate Verification
+ Titles
+
+ Auto
+ Enabled
+ Disabled
+
+ Type
+ PSMultiValueSpecifier
+ Values
+
+ default
+ enabled
+ disabled
+
+
+
+ Title
+ Research
+ Type
+ PSGroupSpecifier
+
+
+ Key
+ ldap_base_object
+ Title
+ Research Base
+ Type
+ PSTextFieldSpecifier
+ AutocapitalizationType
+ None
+ AutocorrectionType
+ No
+ DefaultValue
+
+ IASKTextAlignment
+ IASKUITextAlignmentRight
+
+
+ Key
+ ldap_filter
+ Title
+ Filter
+ Type
+ PSTextFieldSpecifier
+ AutocapitalizationType
+ None
+ AutocorrectionType
+ No
+ DefaultValue
+
+ IASKTextAlignment
+ IASKUITextAlignmentRight
+
+
+ Key
+ ldap_max_results
+ Title
+ Max results
+ Type
+ PSTextFieldSpecifier
+ AutocapitalizationType
+ None
+ AutocorrectionType
+ No
+ KeyboardType
+ NumberPad
+ DefaultValue
+ 50
+ IASKTextAlignment
+ IASKUITextAlignmentRight
+
+
+ Key
+ ldap_timeout
+ Title
+ Timeout (seconds)
+ Type
+ PSTextFieldSpecifier
+ AutocapitalizationType
+ None
+ AutocorrectionType
+ No
+ KeyboardType
+ NumberPad
+ DefaultValue
+ 5
+ IASKTextAlignment
+ IASKUITextAlignmentRight
+
+
+ Key
+ ldap_delay
+ Title
+ Delay (milliseconds)
+ Type
+ PSTextFieldSpecifier
+ AutocapitalizationType
+ None
+ AutocorrectionType
+ No
+ KeyboardType
+ NumberPad
+ DefaultValue
+ 500
+ IASKTextAlignment
+ IASKUITextAlignmentRight
+
+
+ Key
+ ldap_min_chars
+ Title
+ Min chars
+ Type
+ PSTextFieldSpecifier
+ AutocapitalizationType
+ None
+ AutocorrectionType
+ No
+ KeyboardType
+ NumberPad
+ DefaultValue
+ 3
+ IASKTextAlignment
+ IASKUITextAlignmentRight
+
+
+
+ Title
+ Analysis
+ Type
+ PSGroupSpecifier
+
+
+ Key
+ ldap_name_attribute
+ Title
+ Name Attributes
+ Type
+ PSTextFieldSpecifier
+ AutocapitalizationType
+ None
+ AutocorrectionType
+ No
+ DefaultValue
+
+ IASKTextAlignment
+ IASKUITextAlignmentRight
+
+
+ Key
+ ldap_sip_attribute
+ Title
+ SIP Attributes
+ Type
+ PSTextFieldSpecifier
+ AutocapitalizationType
+ None
+ AutocorrectionType
+ No
+ DefaultValue
+
+ IASKTextAlignment
+ IASKUITextAlignmentRight
+
+
+ Key
+ ldap_sip_domain
+ Title
+ Domain
+ Type
+ PSTextFieldSpecifier
+ AutocapitalizationType
+ None
+ AutocorrectionType
+ No
+ DefaultValue
+
+ IASKTextAlignment
+ IASKUITextAlignmentRight
+
+
+ Title
+ Miscellaneous
+ Type
+ PSGroupSpecifier
+
+
+ Type
+ PSToggleSwitchSpecifier
+ Title
+ Enabled
+ Key
+ ldap_logs_enabled
+ DefaultValue
+
+
+
+
+
diff --git a/Settings/InAppSettings.bundle/Root.plist b/Settings/InAppSettings.bundle/Root.plist
index 2fbc0eab4..b4c5a2cec 100644
--- a/Settings/InAppSettings.bundle/Root.plist
+++ b/Settings/InAppSettings.bundle/Root.plist
@@ -144,6 +144,16 @@
Type
PSChildPaneSpecifier
+
+ Key
+ contacts_menu
+ File
+ Contacts
+ Title
+ Contacts
+ Type
+ PSChildPaneSpecifier
+
File
Advanced