Added DNSSEC account/identity option

pull/214/head
M66B 2 years ago
parent fec7e96feb
commit 91ee9b5c60

@ -2,11 +2,11 @@
"formatVersion": 1, "formatVersion": 1,
"database": { "database": {
"version": 288, "version": 288,
"identityHash": "bf7da4c39c5e94bcc21472eba1772d8d", "identityHash": "4cec816a440db77674127f7b1744967a",
"entities": [ "entities": [
{ {
"tableName": "identity", "tableName": "identity",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `uuid` TEXT NOT NULL, `name` TEXT NOT NULL, `email` TEXT NOT NULL, `account` INTEGER NOT NULL, `display` TEXT, `color` INTEGER, `signature` TEXT, `host` TEXT NOT NULL, `starttls` INTEGER NOT NULL, `insecure` INTEGER NOT NULL, `dane` INTEGER NOT NULL, `port` INTEGER NOT NULL, `auth_type` INTEGER NOT NULL, `provider` TEXT, `user` TEXT NOT NULL, `password` TEXT NOT NULL, `certificate` INTEGER NOT NULL, `certificate_alias` TEXT, `realm` TEXT, `fingerprint` TEXT, `use_ip` INTEGER NOT NULL, `ehlo` TEXT, `synchronize` INTEGER NOT NULL, `primary` INTEGER NOT NULL, `self` INTEGER NOT NULL, `sender_extra` INTEGER NOT NULL, `sender_extra_name` INTEGER NOT NULL, `reply_extra_name` INTEGER NOT NULL, `sender_extra_regex` TEXT, `replyto` TEXT, `cc` TEXT, `bcc` TEXT, `internal` TEXT, `uri` TEXT, `unicode` INTEGER NOT NULL, `octetmime` INTEGER NOT NULL, `plain_only` INTEGER NOT NULL, `sign_default` INTEGER NOT NULL, `encrypt_default` INTEGER NOT NULL, `encrypt` INTEGER NOT NULL, `receipt_type` INTEGER, `delivery_receipt` INTEGER NOT NULL, `read_receipt` INTEGER NOT NULL, `sensitivity` INTEGER NOT NULL, `store_sent` INTEGER NOT NULL, `sent_folder` INTEGER, `sign_key` INTEGER, `sign_key_alias` TEXT, `tbd` INTEGER, `state` TEXT, `error` TEXT, `last_connected` INTEGER, `max_size` INTEGER, `last_modified` INTEGER, FOREIGN KEY(`account`) REFERENCES `account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `uuid` TEXT NOT NULL, `name` TEXT NOT NULL, `email` TEXT NOT NULL, `account` INTEGER NOT NULL, `display` TEXT, `color` INTEGER, `signature` TEXT, `host` TEXT NOT NULL, `starttls` INTEGER NOT NULL, `insecure` INTEGER NOT NULL, `dnssec` INTEGER NOT NULL, `dane` INTEGER NOT NULL, `port` INTEGER NOT NULL, `auth_type` INTEGER NOT NULL, `provider` TEXT, `user` TEXT NOT NULL, `password` TEXT NOT NULL, `certificate` INTEGER NOT NULL, `certificate_alias` TEXT, `realm` TEXT, `fingerprint` TEXT, `use_ip` INTEGER NOT NULL, `ehlo` TEXT, `synchronize` INTEGER NOT NULL, `primary` INTEGER NOT NULL, `self` INTEGER NOT NULL, `sender_extra` INTEGER NOT NULL, `sender_extra_name` INTEGER NOT NULL, `reply_extra_name` INTEGER NOT NULL, `sender_extra_regex` TEXT, `replyto` TEXT, `cc` TEXT, `bcc` TEXT, `internal` TEXT, `uri` TEXT, `unicode` INTEGER NOT NULL, `octetmime` INTEGER NOT NULL, `plain_only` INTEGER NOT NULL, `sign_default` INTEGER NOT NULL, `encrypt_default` INTEGER NOT NULL, `encrypt` INTEGER NOT NULL, `receipt_type` INTEGER, `delivery_receipt` INTEGER NOT NULL, `read_receipt` INTEGER NOT NULL, `sensitivity` INTEGER NOT NULL, `store_sent` INTEGER NOT NULL, `sent_folder` INTEGER, `sign_key` INTEGER, `sign_key_alias` TEXT, `tbd` INTEGER, `state` TEXT, `error` TEXT, `last_connected` INTEGER, `max_size` INTEGER, `last_modified` INTEGER, FOREIGN KEY(`account`) REFERENCES `account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [ "fields": [
{ {
"fieldPath": "id", "fieldPath": "id",
@ -74,6 +74,12 @@
"affinity": "INTEGER", "affinity": "INTEGER",
"notNull": true "notNull": true
}, },
{
"fieldPath": "dnssec",
"columnName": "dnssec",
"affinity": "INTEGER",
"notNull": true
},
{ {
"fieldPath": "dane", "fieldPath": "dane",
"columnName": "dane", "columnName": "dane",
@ -382,7 +388,7 @@
}, },
{ {
"tableName": "account", "tableName": "account",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `uuid` TEXT NOT NULL, `pop` INTEGER NOT NULL, `host` TEXT NOT NULL, `starttls` INTEGER NOT NULL, `insecure` INTEGER NOT NULL, `dane` INTEGER NOT NULL, `port` INTEGER NOT NULL, `auth_type` INTEGER NOT NULL, `provider` TEXT, `user` TEXT NOT NULL, `password` TEXT NOT NULL, `certificate` INTEGER NOT NULL, `certificate_alias` TEXT, `realm` TEXT, `fingerprint` TEXT, `name` TEXT, `category` TEXT, `signature` TEXT, `color` INTEGER, `calendar` TEXT, `synchronize` INTEGER NOT NULL, `ondemand` INTEGER NOT NULL, `poll_exempted` INTEGER NOT NULL, `primary` INTEGER NOT NULL, `notify` INTEGER NOT NULL, `summary` INTEGER NOT NULL, `browse` INTEGER NOT NULL, `leave_on_server` INTEGER NOT NULL, `client_delete` INTEGER NOT NULL, `leave_deleted` INTEGER NOT NULL, `leave_on_device` INTEGER NOT NULL, `max_messages` INTEGER, `auto_seen` INTEGER NOT NULL, `separator` INTEGER, `swipe_left` INTEGER, `swipe_right` INTEGER, `move_to` INTEGER, `poll_interval` INTEGER NOT NULL, `keep_alive_noop` INTEGER NOT NULL, `keep_alive_ok` INTEGER NOT NULL, `keep_alive_failed` INTEGER NOT NULL, `keep_alive_succeeded` INTEGER NOT NULL, `partial_fetch` INTEGER NOT NULL, `raw_fetch` INTEGER NOT NULL, `ignore_size` INTEGER NOT NULL, `use_date` INTEGER NOT NULL, `use_received` INTEGER NOT NULL, `prefix` TEXT, `unicode` INTEGER NOT NULL, `conditions` TEXT, `quota_usage` INTEGER, `quota_limit` INTEGER, `created` INTEGER, `tbd` INTEGER, `thread` INTEGER, `state` TEXT, `warning` TEXT, `error` TEXT, `last_connected` INTEGER, `backoff_until` INTEGER, `max_size` INTEGER, `capabilities` TEXT, `capability_idle` INTEGER, `capability_utf8` INTEGER, `capability_uidl` INTEGER, `last_modified` INTEGER, `order` INTEGER)", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `uuid` TEXT NOT NULL, `pop` INTEGER NOT NULL, `host` TEXT NOT NULL, `starttls` INTEGER NOT NULL, `insecure` INTEGER NOT NULL, `dnssec` INTEGER NOT NULL, `dane` INTEGER NOT NULL, `port` INTEGER NOT NULL, `auth_type` INTEGER NOT NULL, `provider` TEXT, `user` TEXT NOT NULL, `password` TEXT NOT NULL, `certificate` INTEGER NOT NULL, `certificate_alias` TEXT, `realm` TEXT, `fingerprint` TEXT, `name` TEXT, `category` TEXT, `signature` TEXT, `color` INTEGER, `calendar` TEXT, `synchronize` INTEGER NOT NULL, `ondemand` INTEGER NOT NULL, `poll_exempted` INTEGER NOT NULL, `primary` INTEGER NOT NULL, `notify` INTEGER NOT NULL, `summary` INTEGER NOT NULL, `browse` INTEGER NOT NULL, `leave_on_server` INTEGER NOT NULL, `client_delete` INTEGER NOT NULL, `leave_deleted` INTEGER NOT NULL, `leave_on_device` INTEGER NOT NULL, `max_messages` INTEGER, `auto_seen` INTEGER NOT NULL, `separator` INTEGER, `swipe_left` INTEGER, `swipe_right` INTEGER, `move_to` INTEGER, `poll_interval` INTEGER NOT NULL, `keep_alive_noop` INTEGER NOT NULL, `keep_alive_ok` INTEGER NOT NULL, `keep_alive_failed` INTEGER NOT NULL, `keep_alive_succeeded` INTEGER NOT NULL, `partial_fetch` INTEGER NOT NULL, `raw_fetch` INTEGER NOT NULL, `ignore_size` INTEGER NOT NULL, `use_date` INTEGER NOT NULL, `use_received` INTEGER NOT NULL, `prefix` TEXT, `unicode` INTEGER NOT NULL, `conditions` TEXT, `quota_usage` INTEGER, `quota_limit` INTEGER, `created` INTEGER, `tbd` INTEGER, `thread` INTEGER, `state` TEXT, `warning` TEXT, `error` TEXT, `last_connected` INTEGER, `backoff_until` INTEGER, `max_size` INTEGER, `capabilities` TEXT, `capability_idle` INTEGER, `capability_utf8` INTEGER, `capability_uidl` INTEGER, `last_modified` INTEGER, `order` INTEGER)",
"fields": [ "fields": [
{ {
"fieldPath": "id", "fieldPath": "id",
@ -420,6 +426,12 @@
"affinity": "INTEGER", "affinity": "INTEGER",
"notNull": true "notNull": true
}, },
{
"fieldPath": "dnssec",
"columnName": "dnssec",
"affinity": "INTEGER",
"notNull": true
},
{ {
"fieldPath": "dane", "fieldPath": "dane",
"columnName": "dane", "columnName": "dane",
@ -2997,7 +3009,7 @@
], ],
"setupQueries": [ "setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'bf7da4c39c5e94bcc21472eba1772d8d')" "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '4cec816a440db77674127f7b1744967a')"
] ]
} }
} }

File diff suppressed because it is too large Load Diff

@ -67,7 +67,7 @@ import javax.mail.internet.InternetAddress;
// https://developer.android.com/topic/libraries/architecture/room.html // https://developer.android.com/topic/libraries/architecture/room.html
@Database( @Database(
version = 288, version = 289,
entities = { entities = {
EntityIdentity.class, EntityIdentity.class,
EntityAccount.class, EntityAccount.class,
@ -2916,6 +2916,13 @@ public abstract class DB extends RoomDatabase {
db.execSQL("ALTER TABLE `account` ADD COLUMN `dane` INTEGER NOT NULL DEFAULT 0"); db.execSQL("ALTER TABLE `account` ADD COLUMN `dane` INTEGER NOT NULL DEFAULT 0");
db.execSQL("ALTER TABLE `identity` ADD COLUMN `dane` INTEGER NOT NULL DEFAULT 0"); db.execSQL("ALTER TABLE `identity` ADD COLUMN `dane` INTEGER NOT NULL DEFAULT 0");
} }
}).addMigrations(new Migration(288, 289) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
logMigration(startVersion, endVersion);
db.execSQL("ALTER TABLE `account` ADD COLUMN `dnssec` INTEGER NOT NULL DEFAULT 0");
db.execSQL("ALTER TABLE `identity` ADD COLUMN `dnssec` INTEGER NOT NULL DEFAULT 0");
}
}).addMigrations(new Migration(998, 999) { }).addMigrations(new Migration(998, 999) {
@Override @Override
public void migrate(@NonNull SupportSQLiteDatabase db) { public void migrate(@NonNull SupportSQLiteDatabase db) {

@ -113,7 +113,7 @@ public class DnsHelper {
} }
@NonNull @NonNull
private static DnsRecord[] _lookup(Context context, String name, String type, int timeout, boolean dns_secure) { private static DnsRecord[] _lookup(Context context, String name, String type, int timeout, boolean dnssec) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean dns_custom = prefs.getBoolean("dns_custom", false); boolean dns_custom = prefs.getBoolean("dns_custom", false);
@ -187,7 +187,7 @@ public class DnsHelper {
data.throwIfErrorResponse(); data.throwIfErrorResponse();
boolean secure = (data.getUnverifiedReasons() != null); boolean secure = (data.getUnverifiedReasons() != null);
if (secure && dns_secure) { if (secure && dnssec) {
DnssecResultNotAuthenticException ex = data.getDnssecResultNotAuthenticException(); DnssecResultNotAuthenticException ex = data.getDnssecResultNotAuthenticException();
if (ex != null) if (ex != null)
throw ex; throw ex;
@ -293,24 +293,24 @@ public class DnsHelper {
return getAllByName(context, host, false); return getAllByName(context, host, false);
} }
static InetAddress getByName(Context context, String host, boolean secure) throws UnknownHostException { static InetAddress getByName(Context context, String host, boolean dnssec) throws UnknownHostException {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean dns_custom = prefs.getBoolean("dns_custom", false); boolean dns_custom = prefs.getBoolean("dns_custom", false);
if (!dns_custom) if (!dns_custom && !dnssec)
return InetAddress.getByName(host); return InetAddress.getByName(host);
if (ConnectionHelper.isNumericAddress(host)) if (ConnectionHelper.isNumericAddress(host))
return InetAddress.getByName(host); return InetAddress.getByName(host);
return getAllByName(context, host, secure)[0]; return getAllByName(context, host, dnssec)[0];
} }
static InetAddress[] getAllByName(Context context, String host, boolean secure) throws UnknownHostException { static InetAddress[] getAllByName(Context context, String host, boolean dnssec) throws UnknownHostException {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean dns_custom = prefs.getBoolean("dns_custom", false); boolean dns_custom = prefs.getBoolean("dns_custom", false);
if (!dns_custom) if (!dns_custom && !dnssec)
return InetAddress.getAllByName(host); return InetAddress.getAllByName(host);
List<InetAddress> result = new ArrayList<>(); List<InetAddress> result = new ArrayList<>();
@ -318,11 +318,11 @@ public class DnsHelper {
boolean[] has46 = ConnectionHelper.has46(context); boolean[] has46 = ConnectionHelper.has46(context);
if (has46[0]) if (has46[0])
for (DnsRecord a : _lookup(context, host, "a", LOOKUP_TIMEOUT, secure)) for (DnsRecord a : _lookup(context, host, "a", LOOKUP_TIMEOUT, dnssec))
result.add(a.address); result.add(a.address);
if (has46[1]) if (has46[1])
for (DnsRecord aaaa : _lookup(context, host, "aaaa", LOOKUP_TIMEOUT, secure)) for (DnsRecord aaaa : _lookup(context, host, "aaaa", LOOKUP_TIMEOUT, dnssec))
result.add(aaaa.address); result.add(aaaa.address);
if (result.size() == 0) if (result.size() == 0)

@ -363,7 +363,7 @@ public class EmailService implements AutoCloseable {
public void connect(EntityAccount account) throws MessagingException { public void connect(EntityAccount account) throws MessagingException {
connect( connect(
account.host, account.port, account.dnssec, account.host, account.port,
account.auth_type, account.provider, account.auth_type, account.provider,
account.user, account.password, account.user, account.password,
new ServiceAuthenticator.IAuthenticated() { new ServiceAuthenticator.IAuthenticated() {
@ -382,7 +382,7 @@ public class EmailService implements AutoCloseable {
public void connect(EntityIdentity identity) throws MessagingException { public void connect(EntityIdentity identity) throws MessagingException {
connect( connect(
identity.host, identity.port, identity.dnssec, identity.host, identity.port,
identity.auth_type, identity.provider, identity.auth_type, identity.provider,
identity.user, identity.password, identity.user, identity.password,
new ServiceAuthenticator.IAuthenticated() { new ServiceAuthenticator.IAuthenticated() {
@ -400,15 +400,15 @@ public class EmailService implements AutoCloseable {
} }
public void connect( public void connect(
String host, int port, boolean dnssec, String host, int port,
int auth, String provider, int auth, String provider,
String user, String password, String user, String password,
String certificate, String fingerprint) throws MessagingException { String certificate, String fingerprint) throws MessagingException {
connect(host, port, auth, provider, user, password, null, certificate, fingerprint); connect(dnssec, host, port, auth, provider, user, password, null, certificate, fingerprint);
} }
private void connect( private void connect(
String host, int port, boolean dnssec, String host, int port,
int auth, String provider, int auth, String provider,
String user, String password, String user, String password,
ServiceAuthenticator.IAuthenticated intf, ServiceAuthenticator.IAuthenticated intf,
@ -493,7 +493,7 @@ public class EmailService implements AutoCloseable {
properties.put("mail." + protocol + ".auth.xoauth2.two.line.authentication.format", "true"); properties.put("mail." + protocol + ".auth.xoauth2.two.line.authentication.format", "true");
Log.i("Connecting to " + host + ":" + port + " auth=" + auth); Log.i("Connecting to " + host + ":" + port + " auth=" + auth);
connect(host, port, auth, user, factory); connect(dnssec, host, port, auth, user, factory);
} catch (AuthenticationFailedException ex) { } catch (AuthenticationFailedException ex) {
//if ("outlook.office365.com".equals(host) && //if ("outlook.office365.com".equals(host) &&
// "AUTHENTICATE failed.".equals(ex.getMessage())) // "AUTHENTICATE failed.".equals(ex.getMessage()))
@ -511,7 +511,7 @@ public class EmailService implements AutoCloseable {
EntityLog.log(context, EntityLog.Type.Debug, EntityLog.log(context, EntityLog.Type.Debug,
ex + "\n" + android.util.Log.getStackTraceString(ex)); ex + "\n" + android.util.Log.getStackTraceString(ex));
authenticator.refreshToken(true); authenticator.refreshToken(true);
connect(host, port, auth, user, factory); connect(dnssec, host, port, auth, user, factory);
} catch (Exception ex1) { } catch (Exception ex1) {
Throwable cause = ex1.getCause(); Throwable cause = ex1.getCause();
if (cause == null) if (cause == null)
@ -602,7 +602,7 @@ public class EmailService implements AutoCloseable {
} }
private void connect( private void connect(
String host, int port, int auth, String user, boolean dnssec, String host, int port, int auth, String user,
SSLSocketFactoryService factory) throws MessagingException { SSLSocketFactoryService factory) throws MessagingException {
Map<String, String> crumb = new HashMap<>(); Map<String, String> crumb = new HashMap<>();
crumb.put("host", host); crumb.put("host", host);
@ -623,7 +623,7 @@ public class EmailService implements AutoCloseable {
String key = "dns." + host; String key = "dns." + host;
try { try {
main = DnsHelper.getByName(context, host); main = DnsHelper.getByName(context, host, dnssec);
EntityLog.log(context, EntityLog.Type.Network, "Main address=" + main); EntityLog.log(context, EntityLog.Type.Network, "Main address=" + main);
prefs.edit().putString(key, main.getHostAddress()).apply(); prefs.edit().putString(key, main.getHostAddress()).apply();
} catch (UnknownHostException ex) { } catch (UnknownHostException ex) {
@ -632,7 +632,7 @@ public class EmailService implements AutoCloseable {
throw ex; throw ex;
else { else {
EntityLog.log(context, EntityLog.Type.Network, "Using " + key + "=" + last); EntityLog.log(context, EntityLog.Type.Network, "Using " + key + "=" + last);
main = DnsHelper.getByName(context, last); main = DnsHelper.getByName(context, last, dnssec);
} }
} }
@ -641,7 +641,7 @@ public class EmailService implements AutoCloseable {
boolean[] has46 = ConnectionHelper.has46(context); boolean[] has46 = ConnectionHelper.has46(context);
if (has46[0]) if (has46[0])
try { try {
for (InetAddress iaddr : DnsHelper.getAllByName(context, host)) for (InetAddress iaddr : DnsHelper.getAllByName(context, host, dnssec))
if (iaddr instanceof Inet4Address) { if (iaddr instanceof Inet4Address) {
main = iaddr; main = iaddr;
EntityLog.log(context, EntityLog.Type.Network, "Preferring=" + main); EntityLog.log(context, EntityLog.Type.Network, "Preferring=" + main);
@ -729,7 +729,7 @@ public class EmailService implements AutoCloseable {
ex + "\n" + android.util.Log.getStackTraceString(ex)); ex + "\n" + android.util.Log.getStackTraceString(ex));
try { try {
// Some devices resolve IPv6 addresses while not having IPv6 connectivity // Some devices resolve IPv6 addresses while not having IPv6 connectivity
InetAddress[] iaddrs = DnsHelper.getAllByName(context, host); InetAddress[] iaddrs = DnsHelper.getAllByName(context, host, dnssec);
int ip4 = (main instanceof Inet4Address ? 1 : 0); int ip4 = (main instanceof Inet4Address ? 1 : 0);
int ip6 = (main instanceof Inet6Address ? 1 : 0); int ip6 = (main instanceof Inet6Address ? 1 : 0);

@ -74,6 +74,8 @@ public class EntityAccount extends EntityOrder implements Serializable {
@ColumnInfo(name = "pop") @ColumnInfo(name = "pop")
public Integer protocol = TYPE_IMAP; public Integer protocol = TYPE_IMAP;
@NonNull @NonNull
public Boolean dnssec = false;
@NonNull
public String host; // POP3/IMAP public String host; // POP3/IMAP
@NonNull @NonNull
@ColumnInfo(name = "starttls") @ColumnInfo(name = "starttls")

@ -68,6 +68,8 @@ public class EntityIdentity {
public Integer color; public Integer color;
public String signature; public String signature;
@NonNull @NonNull
public Boolean dnssec = false;
@NonNull
public String host; // SMTP public String host; // SMTP
@NonNull @NonNull
@ColumnInfo(name = "starttls") @ColumnInfo(name = "starttls")

@ -97,6 +97,7 @@ public class FragmentAccount extends FragmentBase {
private Button btnAutoConfig; private Button btnAutoConfig;
private ContentLoadingProgressBar pbAutoConfig; private ContentLoadingProgressBar pbAutoConfig;
private CheckBox cbDnsSec;
private EditText etHost; private EditText etHost;
private RadioGroup rgEncryption; private RadioGroup rgEncryption;
private CheckBox cbInsecure; private CheckBox cbInsecure;
@ -220,6 +221,7 @@ public class FragmentAccount extends FragmentBase {
btnAutoConfig = view.findViewById(R.id.btnAutoConfig); btnAutoConfig = view.findViewById(R.id.btnAutoConfig);
pbAutoConfig = view.findViewById(R.id.pbAutoConfig); pbAutoConfig = view.findViewById(R.id.pbAutoConfig);
cbDnsSec = view.findViewById(R.id.cbDnsSec);
etHost = view.findViewById(R.id.etHost); etHost = view.findViewById(R.id.etHost);
etPort = view.findViewById(R.id.etPort); etPort = view.findViewById(R.id.etPort);
rgEncryption = view.findViewById(R.id.rgEncryption); rgEncryption = view.findViewById(R.id.rgEncryption);
@ -733,6 +735,7 @@ public class FragmentAccount extends FragmentBase {
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putLong("id", id); args.putLong("id", id);
args.putBoolean("dnssec", cbDnsSec.isChecked());
args.putString("host", etHost.getText().toString().trim().replace(" ", "")); args.putString("host", etHost.getText().toString().trim().replace(" ", ""));
args.putInt("encryption", encryption); args.putInt("encryption", encryption);
args.putBoolean("insecure", cbInsecure.isChecked()); args.putBoolean("insecure", cbInsecure.isChecked());
@ -779,6 +782,7 @@ public class FragmentAccount extends FragmentBase {
@Override @Override
protected CheckResult onExecute(Context context, Bundle args) throws Throwable { protected CheckResult onExecute(Context context, Bundle args) throws Throwable {
long id = args.getLong("id"); long id = args.getLong("id");
boolean dnssec = args.getBoolean("dnssec");
String host = args.getString("host"); String host = args.getString("host");
int encryption = args.getInt("encryption"); int encryption = args.getInt("encryption");
boolean insecure = args.getBoolean("insecure"); boolean insecure = args.getBoolean("insecure");
@ -821,7 +825,7 @@ public class FragmentAccount extends FragmentBase {
protocol, realm, encryption, insecure, dane, unicode, protocol, realm, encryption, insecure, dane, unicode,
EmailService.PURPOSE_CHECK, true)) { EmailService.PURPOSE_CHECK, true)) {
iservice.connect( iservice.connect(
host, Integer.parseInt(port), dnssec, host, Integer.parseInt(port),
auth, provider, auth, provider,
user, password, user, password,
certificate, fingerprint); certificate, fingerprint);
@ -944,6 +948,7 @@ public class FragmentAccount extends FragmentBase {
else else
encryption = EmailService.ENCRYPTION_SSL; encryption = EmailService.ENCRYPTION_SSL;
args.putBoolean("dnssec", cbDnsSec.isChecked());
args.putString("host", etHost.getText().toString().trim().replace(" ", "")); args.putString("host", etHost.getText().toString().trim().replace(" ", ""));
args.putInt("encryption", encryption); args.putInt("encryption", encryption);
args.putBoolean("insecure", cbInsecure.isChecked()); args.putBoolean("insecure", cbInsecure.isChecked());
@ -1022,6 +1027,7 @@ public class FragmentAccount extends FragmentBase {
protected Boolean onExecute(Context context, Bundle args) throws Throwable { protected Boolean onExecute(Context context, Bundle args) throws Throwable {
long id = args.getLong("id"); long id = args.getLong("id");
boolean dnssec = args.getBoolean("dnssec");
String host = args.getString("host"); String host = args.getString("host");
int encryption = args.getInt("encryption"); int encryption = args.getInt("encryption");
boolean insecure = args.getBoolean("insecure"); boolean insecure = args.getBoolean("insecure");
@ -1116,6 +1122,8 @@ public class FragmentAccount extends FragmentBase {
if (account == null) if (account == null)
return !TextUtils.isEmpty(host) && !TextUtils.isEmpty(user); return !TextUtils.isEmpty(host) && !TextUtils.isEmpty(user);
if (!Objects.equals(account.dnssec, dnssec))
return true;
if (!Objects.equals(account.host, host)) if (!Objects.equals(account.host, host))
return true; return true;
if (!Objects.equals(account.encryption, encryption)) if (!Objects.equals(account.encryption, encryption))
@ -1221,6 +1229,7 @@ public class FragmentAccount extends FragmentBase {
boolean check = (synchronize && (account == null || boolean check = (synchronize && (account == null ||
!account.synchronize || !account.synchronize ||
account.error != null || account.error != null ||
!account.dnssec.equals(dnssec) ||
!account.host.equals(host) || !account.host.equals(host) ||
!account.encryption.equals(encryption) || !account.encryption.equals(encryption) ||
!account.insecure.equals(insecure) || !account.insecure.equals(insecure) ||
@ -1246,7 +1255,7 @@ public class FragmentAccount extends FragmentBase {
protocol, realm, encryption, insecure, dane, unicode, protocol, realm, encryption, insecure, dane, unicode,
EmailService.PURPOSE_CHECK, true)) { EmailService.PURPOSE_CHECK, true)) {
iservice.connect( iservice.connect(
host, Integer.parseInt(port), dnssec, host, Integer.parseInt(port),
auth, provider, auth, provider,
user, password, user, password,
certificate, fingerprint); certificate, fingerprint);
@ -1288,6 +1297,7 @@ public class FragmentAccount extends FragmentBase {
if (account == null) if (account == null)
account = new EntityAccount(); account = new EntityAccount();
account.dnssec = dnssec;
account.host = host; account.host = host;
account.encryption = encryption; account.encryption = encryption;
account.insecure = insecure; account.insecure = insecure;
@ -1657,6 +1667,8 @@ public class FragmentAccount extends FragmentBase {
Log.e(ex); Log.e(ex);
} }
cbDnsSec.setChecked(account == null ? false : account.dnssec);
if (account != null) { if (account != null) {
boolean found = false; boolean found = false;
for (int pos = 2; pos < providers.size(); pos++) { for (int pos = 2; pos < providers.size(); pos++) {

@ -483,7 +483,7 @@ public class FragmentGmail extends FragmentBase {
aprotocol, null, aencryption, false, false, false, aprotocol, null, aencryption, false, false, false,
EmailService.PURPOSE_CHECK, true)) { EmailService.PURPOSE_CHECK, true)) {
aservice.connect( aservice.connect(
inbound.host, inbound.port, false, inbound.host, inbound.port,
AUTH_TYPE_GMAIL, null, AUTH_TYPE_GMAIL, null,
user, password, user, password,
null, null); null, null);
@ -501,7 +501,7 @@ public class FragmentGmail extends FragmentBase {
iprotocol, null, iencryption, false, false, false, iprotocol, null, iencryption, false, false, false,
EmailService.PURPOSE_CHECK, true)) { EmailService.PURPOSE_CHECK, true)) {
iservice.connect( iservice.connect(
provider.smtp.host, provider.smtp.port, false, provider.smtp.host, provider.smtp.port,
AUTH_TYPE_GMAIL, null, AUTH_TYPE_GMAIL, null,
user, password, user, password,
null, null); null, null);

@ -98,6 +98,7 @@ public class FragmentIdentity extends FragmentBase {
private EditText etDomain; private EditText etDomain;
private Button btnAutoConfig; private Button btnAutoConfig;
private ContentLoadingProgressBar pbAutoConfig; private ContentLoadingProgressBar pbAutoConfig;
private CheckBox cbDnsSec;
private EditText etHost; private EditText etHost;
private RadioGroup rgEncryption; private RadioGroup rgEncryption;
private CheckBox cbInsecure; private CheckBox cbInsecure;
@ -206,6 +207,7 @@ public class FragmentIdentity extends FragmentBase {
btnAutoConfig = view.findViewById(R.id.btnAutoConfig); btnAutoConfig = view.findViewById(R.id.btnAutoConfig);
pbAutoConfig = view.findViewById(R.id.pbAutoConfig); pbAutoConfig = view.findViewById(R.id.pbAutoConfig);
cbDnsSec = view.findViewById(R.id.cbDnsSec);
etHost = view.findViewById(R.id.etHost); etHost = view.findViewById(R.id.etHost);
rgEncryption = view.findViewById(R.id.rgEncryption); rgEncryption = view.findViewById(R.id.rgEncryption);
cbInsecure = view.findViewById(R.id.cbInsecure); cbInsecure = view.findViewById(R.id.cbInsecure);
@ -776,6 +778,7 @@ public class FragmentIdentity extends FragmentBase {
args.putBoolean("octetmime", cbOctetMime.isChecked()); args.putBoolean("octetmime", cbOctetMime.isChecked());
args.putString("max_size", etMaxSize.getText().toString()); args.putString("max_size", etMaxSize.getText().toString());
args.putLong("account", account == null ? -1 : account.id); args.putLong("account", account == null ? -1 : account.id);
args.putBoolean("dnssec", cbDnsSec.isChecked());
args.putString("host", etHost.getText().toString().trim().replace(" ", "")); args.putString("host", etHost.getText().toString().trim().replace(" ", ""));
args.putInt("encryption", encryption); args.putInt("encryption", encryption);
args.putBoolean("insecure", cbInsecure.isChecked()); args.putBoolean("insecure", cbInsecure.isChecked());
@ -830,6 +833,7 @@ public class FragmentIdentity extends FragmentBase {
Integer color = args.getInt("color"); Integer color = args.getInt("color");
String signature = args.getString("signature"); String signature = args.getString("signature");
boolean dnssec = args.getBoolean("dnssec");
String host = args.getString("host"); String host = args.getString("host");
int encryption = args.getInt("encryption"); int encryption = args.getInt("encryption");
boolean insecure = args.getBoolean("insecure"); boolean insecure = args.getBoolean("insecure");
@ -974,6 +978,8 @@ public class FragmentIdentity extends FragmentBase {
return true; return true;
if (!Objects.equals(identity.signature, signature)) if (!Objects.equals(identity.signature, signature))
return true; return true;
if (!Objects.equals(identity.dnssec, dnssec))
return true;
if (!Objects.equals(identity.host, host)) if (!Objects.equals(identity.host, host))
return true; return true;
if (!Objects.equals(identity.encryption, encryption)) if (!Objects.equals(identity.encryption, encryption))
@ -1048,6 +1054,7 @@ public class FragmentIdentity extends FragmentBase {
boolean check = (synchronize && (identity == null || boolean check = (synchronize && (identity == null ||
!identity.synchronize || identity.error != null || !identity.synchronize || identity.error != null ||
dnssec != identity.dnssec ||
!host.equals(identity.host) || !host.equals(identity.host) ||
encryption != identity.encryption || encryption != identity.encryption ||
insecure != identity.insecure || insecure != identity.insecure ||
@ -1078,7 +1085,7 @@ public class FragmentIdentity extends FragmentBase {
EmailService.PURPOSE_CHECK, true)) { EmailService.PURPOSE_CHECK, true)) {
iservice.setUseIp(use_ip, ehlo); iservice.setUseIp(use_ip, ehlo);
iservice.connect( iservice.connect(
host, Integer.parseInt(port), dnssec, host, Integer.parseInt(port),
auth, provider, auth, provider,
user, password, user, password,
certificate, fingerprint); certificate, fingerprint);
@ -1107,6 +1114,7 @@ public class FragmentIdentity extends FragmentBase {
identity.color = color; identity.color = color;
identity.signature = signature; identity.signature = signature;
identity.dnssec = dnssec;
identity.host = host; identity.host = host;
identity.encryption = encryption; identity.encryption = encryption;
identity.insecure = insecure; identity.insecure = insecure;
@ -1281,6 +1289,7 @@ public class FragmentIdentity extends FragmentBase {
if (signature == null) if (signature == null)
signature = (identity == null ? null : identity.signature); signature = (identity == null ? null : identity.signature);
cbDnsSec.setChecked(identity == null ? false : identity.dnssec);
etHost.setText(identity == null ? null : identity.host); etHost.setText(identity == null ? null : identity.host);
if (identity != null && identity.encryption == EmailService.ENCRYPTION_STARTTLS) if (identity != null && identity.encryption == EmailService.ENCRYPTION_STARTTLS)

@ -821,7 +821,7 @@ public class FragmentOAuth extends FragmentBase {
aprotocol, null, aencryption, false, false, false, aprotocol, null, aencryption, false, false, false,
EmailService.PURPOSE_CHECK, true)) { EmailService.PURPOSE_CHECK, true)) {
aservice.connect( aservice.connect(
inbound.host, inbound.port, false, inbound.host, inbound.port,
AUTH_TYPE_OAUTH, provider.id, AUTH_TYPE_OAUTH, provider.id,
alt, state[0], alt, state[0],
null, null); null, null);
@ -831,7 +831,7 @@ public class FragmentOAuth extends FragmentBase {
iprotocol, null, iencryption, false, false, false, iprotocol, null, iencryption, false, false, false,
EmailService.PURPOSE_CHECK, true)) { EmailService.PURPOSE_CHECK, true)) {
iservice.connect( iservice.connect(
provider.smtp.host, provider.smtp.port, false, provider.smtp.host, provider.smtp.port,
AUTH_TYPE_OAUTH, provider.id, AUTH_TYPE_OAUTH, provider.id,
alt, state[0], alt, state[0],
null, null); null, null);
@ -896,7 +896,7 @@ public class FragmentOAuth extends FragmentBase {
aprotocol, null, aencryption, false, false, false, aprotocol, null, aencryption, false, false, false,
EmailService.PURPOSE_CHECK, true)) { EmailService.PURPOSE_CHECK, true)) {
aservice.connect( aservice.connect(
inbound.host, inbound.port, false, inbound.host, inbound.port,
AUTH_TYPE_OAUTH, provider.id, AUTH_TYPE_OAUTH, provider.id,
sharedname == null ? username : sharedname, state[0], sharedname == null ? username : sharedname, state[0],
null, null); null, null);
@ -915,7 +915,7 @@ public class FragmentOAuth extends FragmentBase {
iprotocol, null, iencryption, false, false, false, iprotocol, null, iencryption, false, false, false,
EmailService.PURPOSE_CHECK, true)) { EmailService.PURPOSE_CHECK, true)) {
iservice.connect( iservice.connect(
provider.smtp.host, provider.smtp.port, false, provider.smtp.host, provider.smtp.port,
AUTH_TYPE_OAUTH, provider.id, AUTH_TYPE_OAUTH, provider.id,
username, state[0], username, state[0],
null, null); null, null);

@ -72,6 +72,7 @@ public class FragmentPop extends FragmentBase {
private ViewGroup view; private ViewGroup view;
private ScrollView scroll; private ScrollView scroll;
private CheckBox cbDnsSec;
private EditText etHost; private EditText etHost;
private RadioGroup rgEncryption; private RadioGroup rgEncryption;
private CheckBox cbInsecure; private CheckBox cbInsecure;
@ -152,6 +153,7 @@ public class FragmentPop extends FragmentBase {
scroll = view.findViewById(R.id.scroll); scroll = view.findViewById(R.id.scroll);
// Get controls // Get controls
cbDnsSec = view.findViewById(R.id.cbDnsSec);
etHost = view.findViewById(R.id.etHost); etHost = view.findViewById(R.id.etHost);
etPort = view.findViewById(R.id.etPort); etPort = view.findViewById(R.id.etPort);
rgEncryption = view.findViewById(R.id.rgEncryption); rgEncryption = view.findViewById(R.id.rgEncryption);
@ -391,6 +393,7 @@ public class FragmentPop extends FragmentBase {
else else
encryption = EmailService.ENCRYPTION_SSL; encryption = EmailService.ENCRYPTION_SSL;
args.putBoolean("dnssec", cbDnsSec.isChecked());
args.putString("host", etHost.getText().toString().trim().replace(" ", "")); args.putString("host", etHost.getText().toString().trim().replace(" ", ""));
args.putInt("encryption", encryption); args.putInt("encryption", encryption);
args.putBoolean("insecure", cbInsecure.isChecked()); args.putBoolean("insecure", cbInsecure.isChecked());
@ -449,6 +452,7 @@ public class FragmentPop extends FragmentBase {
protected Boolean onExecute(Context context, Bundle args) throws Throwable { protected Boolean onExecute(Context context, Bundle args) throws Throwable {
long id = args.getLong("id"); long id = args.getLong("id");
boolean dnssec = args.getBoolean("dnssec");
String host = args.getString("host"); String host = args.getString("host");
int encryption = args.getInt("encryption"); int encryption = args.getInt("encryption");
boolean insecure = args.getBoolean("insecure"); boolean insecure = args.getBoolean("insecure");
@ -532,6 +536,8 @@ public class FragmentPop extends FragmentBase {
if (account == null) if (account == null)
return !TextUtils.isEmpty(host) && !TextUtils.isEmpty(user); return !TextUtils.isEmpty(host) && !TextUtils.isEmpty(user);
if (!Objects.equals(account.dnssec, dnssec))
return true;
if (!Objects.equals(account.host, host)) if (!Objects.equals(account.host, host))
return true; return true;
if (!Objects.equals(account.encryption, encryption)) if (!Objects.equals(account.encryption, encryption))
@ -596,6 +602,7 @@ public class FragmentPop extends FragmentBase {
boolean check = (synchronize && (account == null || boolean check = (synchronize && (account == null ||
!account.synchronize || !account.synchronize ||
account.error != null || account.error != null ||
!account.dnssec.equals(dnssec) ||
!account.host.equals(host) || !account.host.equals(host) ||
!account.encryption.equals(encryption) || !account.encryption.equals(encryption) ||
!account.insecure.equals(insecure) || !account.insecure.equals(insecure) ||
@ -617,7 +624,7 @@ public class FragmentPop extends FragmentBase {
protocol, null, encryption, insecure, dane, false, protocol, null, encryption, insecure, dane, false,
EmailService.PURPOSE_CHECK, true)) { EmailService.PURPOSE_CHECK, true)) {
iservice.connect( iservice.connect(
host, Integer.parseInt(port), dnssec, host, Integer.parseInt(port),
auth, null, auth, null,
user, password, user, password,
null, null); null, null);
@ -641,6 +648,7 @@ public class FragmentPop extends FragmentBase {
account = new EntityAccount(); account = new EntityAccount();
account.protocol = EntityAccount.TYPE_POP; account.protocol = EntityAccount.TYPE_POP;
account.dnssec = dnssec;
account.host = host; account.host = host;
account.encryption = encryption; account.encryption = encryption;
account.insecure = insecure; account.insecure = insecure;
@ -837,6 +845,7 @@ public class FragmentPop extends FragmentBase {
Log.e(ex); Log.e(ex);
} }
cbDnsSec.setChecked(account == null ? false : account.dnssec);
etHost.setText(account == null ? null : account.host); etHost.setText(account == null ? null : account.host);
etPort.setText(account == null ? null : Long.toString(account.port)); etPort.setText(account == null ? null : Long.toString(account.port));

@ -439,7 +439,7 @@ public class FragmentQuickSetup extends FragmentBase {
Log.i("Trying with user=" + user); Log.i("Trying with user=" + user);
try { try {
iservice.connect( iservice.connect(
provider.imap.host, provider.imap.port, false, provider.imap.host, provider.imap.port,
AUTH_TYPE_PASSWORD, null, AUTH_TYPE_PASSWORD, null,
user, password, user, password,
null, null); null, null);
@ -448,7 +448,7 @@ public class FragmentQuickSetup extends FragmentBase {
imap_certificate = ex.getCertificate(); imap_certificate = ex.getCertificate();
imap_fingerprint = EntityCertificate.getKeyFingerprint(imap_certificate); imap_fingerprint = EntityCertificate.getKeyFingerprint(imap_certificate);
iservice.connect( iservice.connect(
provider.imap.host, provider.imap.port, false, provider.imap.host, provider.imap.port,
AUTH_TYPE_PASSWORD, null, AUTH_TYPE_PASSWORD, null,
user, password, user, password,
null, imap_fingerprint); null, imap_fingerprint);
@ -545,7 +545,7 @@ public class FragmentQuickSetup extends FragmentBase {
iservice.setUseIp(provider.useip, null); iservice.setUseIp(provider.useip, null);
try { try {
iservice.connect( iservice.connect(
provider.smtp.host, provider.smtp.port, false, provider.smtp.host, provider.smtp.port,
AUTH_TYPE_PASSWORD, null, AUTH_TYPE_PASSWORD, null,
user, password, user, password,
null, null); null, null);
@ -553,7 +553,7 @@ public class FragmentQuickSetup extends FragmentBase {
smtp_certificate = ex.getCertificate(); smtp_certificate = ex.getCertificate();
smtp_fingerprint = EntityCertificate.getKeyFingerprint(smtp_certificate); smtp_fingerprint = EntityCertificate.getKeyFingerprint(smtp_certificate);
iservice.connect( iservice.connect(
provider.smtp.host, provider.smtp.port, false, provider.smtp.host, provider.smtp.port,
AUTH_TYPE_PASSWORD, null, AUTH_TYPE_PASSWORD, null,
user, password, user, password,
null, smtp_fingerprint); null, smtp_fingerprint);

@ -135,6 +135,15 @@
<!-- host --> <!-- host -->
<CheckBox
android:id="@+id/cbDnsSec"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_dnssec"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvImap" />
<TextView <TextView
android:id="@+id/tvHost" android:id="@+id/tvHost"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -145,7 +154,7 @@
android:textColor="?android:textColorPrimary" android:textColor="?android:textColorPrimary"
android:textStyle="bold" android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvImap" /> app:layout_constraintTop_toBottomOf="@id/cbDnsSec" />
<eu.faircode.email.EditTextPlain <eu.faircode.email.EditTextPlain
android:id="@+id/etHost" android:id="@+id/etHost"

@ -285,6 +285,15 @@
<!-- host --> <!-- host -->
<CheckBox
android:id="@+id/cbDnsSec"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_dnssec"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvSmtp" />
<TextView <TextView
android:id="@+id/tvHost" android:id="@+id/tvHost"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -295,7 +304,7 @@
android:textColor="?android:textColorPrimary" android:textColor="?android:textColorPrimary"
android:textStyle="bold" android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvSmtp" /> app:layout_constraintTop_toBottomOf="@id/cbDnsSec" />
<eu.faircode.email.EditTextPlain <eu.faircode.email.EditTextPlain
android:id="@+id/etHost" android:id="@+id/etHost"

@ -76,6 +76,15 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<CheckBox
android:id="@+id/cbDnsSec"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_dnssec"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvPop" />
<TextView <TextView
android:id="@+id/tvHost" android:id="@+id/tvHost"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -86,7 +95,7 @@
android:textColor="?android:textColorPrimary" android:textColor="?android:textColorPrimary"
android:textStyle="bold" android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvPop" /> app:layout_constraintTop_toBottomOf="@id/cbDnsSec" />
<eu.faircode.email.EditTextPlain <eu.faircode.email.EditTextPlain
android:id="@+id/etHost" android:id="@+id/etHost"

@ -1187,6 +1187,7 @@
<string name="title_aliases">Aliases</string> <string name="title_aliases">Aliases</string>
<string name="title_provider">Provider</string> <string name="title_provider">Provider</string>
<string name="title_custom">Custom</string> <string name="title_custom">Custom</string>
<string name="title_dnssec">Enforce DNSSEC</string>
<string name="title_host">Host name</string> <string name="title_host">Host name</string>
<string name="title_encryption">Encryption</string> <string name="title_encryption">Encryption</string>
<string name="title_encryption_ssl" translatable="false">SSL/TLS</string> <string name="title_encryption_ssl" translatable="false">SSL/TLS</string>

Loading…
Cancel
Save