Added support for client certificates (untested)

pull/174/head
M66B 6 years ago
parent c298eb824a
commit 58e49368e3

File diff suppressed because it is too large Load Diff

@ -60,7 +60,7 @@ import io.requery.android.database.sqlite.SQLiteDatabase;
// https://developer.android.com/topic/libraries/architecture/room.html // https://developer.android.com/topic/libraries/architecture/room.html
@Database( @Database(
version = 140, version = 141,
entities = { entities = {
EntityIdentity.class, EntityIdentity.class,
EntityAccount.class, EntityAccount.class,
@ -1356,6 +1356,14 @@ public abstract class DB extends RoomDatabase {
Log.i("DB migration from version " + startVersion + " to " + endVersion); Log.i("DB migration from version " + startVersion + " to " + endVersion);
db.execSQL("UPDATE `message` SET fts = 0"); db.execSQL("UPDATE `message` SET fts = 0");
} }
})
.addMigrations(new Migration(140, 141) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
Log.i("DB migration from version " + startVersion + " to " + endVersion);
db.execSQL("ALTER TABLE `account` ADD COLUMN `certificate` INTEGER NOT NULL DEFAULT 0");
db.execSQL("ALTER TABLE `identity` ADD COLUMN `certificate` INTEGER NOT NULL DEFAULT 0");
}
}); });
} }

@ -62,6 +62,8 @@ import javax.mail.Service;
import javax.mail.Session; import javax.mail.Session;
import javax.mail.Store; import javax.mail.Store;
import javax.mail.event.StoreListener; import javax.mail.event.StoreListener;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.SSLSocketFactory;
@ -232,7 +234,11 @@ public class EmailService implements AutoCloseable {
} }
public void connect(EntityAccount account) throws MessagingException { public void connect(EntityAccount account) throws MessagingException {
String password = connect(account.host, account.port, account.auth_type, account.provider, account.user, account.password, account.fingerprint); String password = connect(
account.host, account.port,
account.auth_type, account.provider,
account.user, account.password,
account.certificate, account.fingerprint);
if (password != null) { if (password != null) {
DB db = DB.getInstance(context); DB db = DB.getInstance(context);
int count = db.account().setAccountPassword(account.id, account.password); int count = db.account().setAccountPassword(account.id, account.password);
@ -241,7 +247,11 @@ public class EmailService implements AutoCloseable {
} }
public void connect(EntityIdentity identity) throws MessagingException { public void connect(EntityIdentity identity) throws MessagingException {
String password = connect(identity.host, identity.port, identity.auth_type, identity.provider, identity.user, identity.password, identity.fingerprint); String password = connect(
identity.host, identity.port,
identity.auth_type, identity.provider,
identity.user, identity.password,
identity.certificate, identity.fingerprint);
if (password != null) { if (password != null) {
DB db = DB.getInstance(context); DB db = DB.getInstance(context);
int count = db.identity().setIdentityPassword(identity.id, identity.password); int count = db.identity().setIdentityPassword(identity.id, identity.password);
@ -252,10 +262,10 @@ public class EmailService implements AutoCloseable {
public String connect( public String connect(
String host, int port, String host, int port,
int auth, String provider, String user, String password, int auth, String provider, String user, String password,
String fingerprint) throws MessagingException { boolean certificate, String fingerprint) throws MessagingException {
SSLSocketFactoryService factory = null; SSLSocketFactoryService factory = null;
try { try {
factory = new SSLSocketFactoryService(host, insecure, harden, fingerprint); factory = new SSLSocketFactoryService(host, insecure, harden, certificate, fingerprint);
properties.put("mail." + protocol + ".ssl.socketFactory", factory); properties.put("mail." + protocol + ".ssl.socketFactory", factory);
properties.put("mail." + protocol + ".socketFactory.fallback", "false"); properties.put("mail." + protocol + ".socketFactory.fallback", "false");
properties.put("mail." + protocol + ".ssl.checkserveridentity", "false"); properties.put("mail." + protocol + ".ssl.checkserveridentity", "false");
@ -564,7 +574,7 @@ public class EmailService implements AutoCloseable {
private SSLSocketFactory factory; private SSLSocketFactory factory;
private X509Certificate certificate; private X509Certificate certificate;
SSLSocketFactoryService(String host, boolean insecure, boolean harden, String fingerprint) throws GeneralSecurityException { SSLSocketFactoryService(String host, boolean insecure, boolean harden, boolean use_certificate, String fingerprint) throws GeneralSecurityException {
this.server = host; this.server = host;
this.secure = !insecure; this.secure = !insecure;
this.harden = harden; this.harden = harden;
@ -633,7 +643,19 @@ public class EmailService implements AutoCloseable {
} }
}; };
sslContext.init(null, new TrustManager[]{tm}, null); KeyManager[] km = null;
if (use_certificate)
try {
KeyStore ks = KeyStore.getInstance("AndroidCAStore");
ks.load(null, null);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
kmf.init(ks, null);
km = kmf.getKeyManagers();
} catch (Throwable ex) {
Log.e(ex);
}
sslContext.init(km, new TrustManager[]{tm}, null);
} }
factory = sslContext.getSocketFactory(); factory = sslContext.getSocketFactory();

@ -77,6 +77,8 @@ public class EntityAccount extends EntityOrder implements Serializable {
public String user; public String user;
@NonNull @NonNull
public String password; public String password;
@NonNull
public Boolean certificate;
public String realm; public String realm;
public String fingerprint; public String fingerprint;
@ -195,6 +197,7 @@ public class EntityAccount extends EntityOrder implements Serializable {
json.put("provider", provider); json.put("provider", provider);
json.put("user", user); json.put("user", user);
json.put("password", password); json.put("password", password);
json.put("certificate", certificate);
json.put("realm", realm); json.put("realm", realm);
json.put("fingerprint", fingerprint); json.put("fingerprint", fingerprint);
@ -253,6 +256,7 @@ public class EntityAccount extends EntityOrder implements Serializable {
account.provider = json.getString("provider"); account.provider = json.getString("provider");
account.user = json.getString("user"); account.user = json.getString("user");
account.password = json.getString("password"); account.password = json.getString("password");
account.certificate = json.optBoolean("certificate");
if (json.has("realm")) if (json.has("realm"))
account.realm = json.getString("realm"); account.realm = json.getString("realm");
if (json.has("fingerprint")) if (json.has("fingerprint"))

@ -77,6 +77,8 @@ public class EntityIdentity {
public String user; public String user;
@NonNull @NonNull
public String password; public String password;
@NonNull
public boolean certificate;
public String realm; public String realm;
public String fingerprint; public String fingerprint;
@NonNull @NonNull
@ -173,6 +175,7 @@ public class EntityIdentity {
json.put("provider", provider); json.put("provider", provider);
json.put("user", user); json.put("user", user);
json.put("password", password); json.put("password", password);
json.put("certificate", certificate);
json.put("realm", realm); json.put("realm", realm);
json.put("fingerprint", fingerprint); json.put("fingerprint", fingerprint);
json.put("use_ip", use_ip); json.put("use_ip", use_ip);
@ -218,6 +221,7 @@ public class EntityIdentity {
identity.provider = json.getString("provider"); identity.provider = json.getString("provider");
identity.user = json.getString("user"); identity.user = json.getString("user");
identity.password = json.getString("password"); identity.password = json.getString("password");
identity.certificate = json.optBoolean("certificate");
if (json.has("realm") && !json.isNull("realm")) if (json.has("realm") && !json.isNull("realm"))
identity.realm = json.getString("realm"); identity.realm = json.getString("realm");
if (json.has("fingerprint")) if (json.has("fingerprint"))

@ -91,6 +91,7 @@ public class FragmentAccount extends FragmentBase {
private EditText etUser; private EditText etUser;
private TextInputLayout tilPassword; private TextInputLayout tilPassword;
private TextView tvCharacters; private TextView tvCharacters;
private CheckBox cbCertificate;
private Button btnOAuth; private Button btnOAuth;
private TextView tvOAuthSupport; private TextView tvOAuthSupport;
private EditText etRealm; private EditText etRealm;
@ -199,6 +200,7 @@ public class FragmentAccount extends FragmentBase {
etUser = view.findViewById(R.id.etUser); etUser = view.findViewById(R.id.etUser);
tilPassword = view.findViewById(R.id.tilPassword); tilPassword = view.findViewById(R.id.tilPassword);
tvCharacters = view.findViewById(R.id.tvCharacters); tvCharacters = view.findViewById(R.id.tvCharacters);
cbCertificate = view.findViewById(R.id.cbCertificate);
btnOAuth = view.findViewById(R.id.btnOAuth); btnOAuth = view.findViewById(R.id.btnOAuth);
tvOAuthSupport = view.findViewById(R.id.tvOAuthSupport); tvOAuthSupport = view.findViewById(R.id.tvOAuthSupport);
etRealm = view.findViewById(R.id.etRealm); etRealm = view.findViewById(R.id.etRealm);
@ -282,6 +284,7 @@ public class FragmentAccount extends FragmentBase {
etUser.setTag(null); etUser.setTag(null);
etUser.setText(null); etUser.setText(null);
tilPassword.getEditText().setText(null); tilPassword.getEditText().setText(null);
cbCertificate.setChecked(false);
btnOAuth.setEnabled(false); btnOAuth.setEnabled(false);
etRealm.setText(null); etRealm.setText(null);
cbTrust.setChecked(false); cbTrust.setChecked(false);
@ -549,6 +552,7 @@ public class FragmentAccount extends FragmentBase {
args.putString("provider", provider); args.putString("provider", provider);
args.putString("user", etUser.getText().toString().trim()); args.putString("user", etUser.getText().toString().trim());
args.putString("password", tilPassword.getEditText().getText().toString()); args.putString("password", tilPassword.getEditText().getText().toString());
args.putBoolean("certificate", cbCertificate.isChecked());
args.putString("realm", etRealm.getText().toString()); args.putString("realm", etRealm.getText().toString());
args.putString("fingerprint", cbTrust.isChecked() ? (String) cbTrust.getTag() : null); args.putString("fingerprint", cbTrust.isChecked() ? (String) cbTrust.getTag() : null);
@ -587,6 +591,7 @@ public class FragmentAccount extends FragmentBase {
String provider = args.getString("provider"); String provider = args.getString("provider");
String user = args.getString("user"); String user = args.getString("user");
String password = args.getString("password"); String password = args.getString("password");
boolean certificate = args.getBoolean("certificate'");
String realm = args.getString("realm"); String realm = args.getString("realm");
String fingerprint = args.getString("fingerprint"); String fingerprint = args.getString("fingerprint");
@ -601,7 +606,7 @@ public class FragmentAccount extends FragmentBase {
port = (starttls ? "143" : "993"); port = (starttls ? "143" : "993");
if (TextUtils.isEmpty(user)) if (TextUtils.isEmpty(user))
throw new IllegalArgumentException(context.getString(R.string.title_no_user)); throw new IllegalArgumentException(context.getString(R.string.title_no_user));
if (TextUtils.isEmpty(password) && !insecure) if (TextUtils.isEmpty(password) && !insecure && !certificate)
throw new IllegalArgumentException(context.getString(R.string.title_no_password)); throw new IllegalArgumentException(context.getString(R.string.title_no_password));
if (TextUtils.isEmpty(realm)) if (TextUtils.isEmpty(realm))
@ -620,7 +625,8 @@ public class FragmentAccount extends FragmentBase {
iservice.connect( iservice.connect(
host, Integer.parseInt(port), host, Integer.parseInt(port),
auth, provider, auth, provider,
user, password, fingerprint); user, password,
certificate, fingerprint);
result.idle = iservice.hasCapability("IDLE"); result.idle = iservice.hasCapability("IDLE");
@ -763,6 +769,7 @@ public class FragmentAccount extends FragmentBase {
args.putString("provider", provider); args.putString("provider", provider);
args.putString("user", etUser.getText().toString().trim()); args.putString("user", etUser.getText().toString().trim());
args.putString("password", tilPassword.getEditText().getText().toString()); args.putString("password", tilPassword.getEditText().getText().toString());
args.putBoolean("certificate", cbCertificate.isChecked());
args.putString("realm", etRealm.getText().toString()); args.putString("realm", etRealm.getText().toString());
args.putString("fingerprint", cbTrust.isChecked() ? (String) cbTrust.getTag() : null); args.putString("fingerprint", cbTrust.isChecked() ? (String) cbTrust.getTag() : null);
@ -824,6 +831,7 @@ public class FragmentAccount extends FragmentBase {
String provider = args.getString("provider"); String provider = args.getString("provider");
String user = args.getString("user").trim(); String user = args.getString("user").trim();
String password = args.getString("password"); String password = args.getString("password");
boolean certificate = args.getBoolean("certificate");
String realm = args.getString("realm"); String realm = args.getString("realm");
String fingerprint = args.getString("fingerprint"); String fingerprint = args.getString("fingerprint");
@ -864,7 +872,7 @@ public class FragmentAccount extends FragmentBase {
port = (starttls ? "143" : "993"); port = (starttls ? "143" : "993");
if (TextUtils.isEmpty(user) && !should) if (TextUtils.isEmpty(user) && !should)
throw new IllegalArgumentException(context.getString(R.string.title_no_user)); throw new IllegalArgumentException(context.getString(R.string.title_no_user));
if (synchronize && TextUtils.isEmpty(password) && !insecure && !should) if (synchronize && TextUtils.isEmpty(password) && !insecure && !certificate && !should)
throw new IllegalArgumentException(context.getString(R.string.title_no_password)); throw new IllegalArgumentException(context.getString(R.string.title_no_password));
if (TextUtils.isEmpty(interval)) if (TextUtils.isEmpty(interval))
interval = Integer.toString(EntityAccount.DEFAULT_KEEP_ALIVE_INTERVAL); interval = Integer.toString(EntityAccount.DEFAULT_KEEP_ALIVE_INTERVAL);
@ -901,6 +909,8 @@ public class FragmentAccount extends FragmentBase {
return true; return true;
if (!Objects.equals(account.password, password)) if (!Objects.equals(account.password, password))
return true; return true;
if (!Objects.equals(account.certificate, certificate))
return true;
if (!Objects.equals(account.realm, realm)) if (!Objects.equals(account.realm, realm))
return true; return true;
if (!Objects.equals(account.fingerprint, fingerprint)) if (!Objects.equals(account.fingerprint, fingerprint))
@ -972,6 +982,7 @@ public class FragmentAccount extends FragmentBase {
!account.port.equals(Integer.parseInt(port)) || !account.port.equals(Integer.parseInt(port)) ||
!account.user.equals(user) || !account.user.equals(user) ||
!account.password.equals(password) || !account.password.equals(password) ||
!account.certificate.equals(certificate) ||
!Objects.equals(realm, accountRealm) || !Objects.equals(realm, accountRealm) ||
!Objects.equals(account.fingerprint, fingerprint))); !Objects.equals(account.fingerprint, fingerprint)));
Log.i("Account check=" + check); Log.i("Account check=" + check);
@ -989,7 +1000,8 @@ public class FragmentAccount extends FragmentBase {
iservice.connect( iservice.connect(
host, Integer.parseInt(port), host, Integer.parseInt(port),
auth, provider, auth, provider,
user, password, fingerprint); user, password,
certificate, fingerprint);
for (Folder ifolder : iservice.getStore().getDefaultFolder().list("*")) { for (Folder ifolder : iservice.getStore().getDefaultFolder().list("*")) {
// Check folder attributes // Check folder attributes
@ -1033,6 +1045,7 @@ public class FragmentAccount extends FragmentBase {
account.auth_type = auth; account.auth_type = auth;
account.user = user; account.user = user;
account.password = password; account.password = password;
account.certificate = certificate;
account.provider = provider; account.provider = provider;
account.realm = realm; account.realm = realm;
account.fingerprint = fingerprint; account.fingerprint = fingerprint;
@ -1369,6 +1382,7 @@ public class FragmentAccount extends FragmentBase {
etUser.setText(account == null ? null : account.user); etUser.setText(account == null ? null : account.user);
tilPassword.getEditText().setText(account == null ? null : account.password); tilPassword.getEditText().setText(account == null ? null : account.password);
cbCertificate.setChecked(account == null ? false : account.certificate);
etRealm.setText(account == null ? null : account.realm); etRealm.setText(account == null ? null : account.realm);
if (account == null || account.fingerprint == null) { if (account == null || account.fingerprint == null) {
@ -1433,6 +1447,7 @@ public class FragmentAccount extends FragmentBase {
if (auth != EmailService.AUTH_TYPE_PASSWORD) { if (auth != EmailService.AUTH_TYPE_PASSWORD) {
etUser.setEnabled(false); etUser.setEnabled(false);
tilPassword.setEnabled(false); tilPassword.setEnabled(false);
cbCertificate.setEnabled(false);
} }
if (account == null || account.auth_type != EmailService.AUTH_TYPE_GMAIL) if (account == null || account.auth_type != EmailService.AUTH_TYPE_GMAIL)

@ -315,7 +315,8 @@ public class FragmentGmail extends FragmentBase {
iservice.connect( iservice.connect(
provider.imap.host, provider.imap.port, provider.imap.host, provider.imap.port,
EmailService.AUTH_TYPE_GMAIL, null, EmailService.AUTH_TYPE_GMAIL, null,
user, password, null); user, password,
false, null);
folders = iservice.getFolders(); folders = iservice.getFolders();
@ -329,7 +330,8 @@ public class FragmentGmail extends FragmentBase {
iservice.connect( iservice.connect(
provider.smtp.host, provider.smtp.port, provider.smtp.host, provider.smtp.port,
EmailService.AUTH_TYPE_GMAIL, null, EmailService.AUTH_TYPE_GMAIL, null,
user, password, null); user, password,
false, null);
} }
DB db = DB.getInstance(context); DB db = DB.getInstance(context);

@ -100,6 +100,7 @@ public class FragmentIdentity extends FragmentBase {
private EditText etUser; private EditText etUser;
private TextInputLayout tilPassword; private TextInputLayout tilPassword;
private TextView tvCharacters; private TextView tvCharacters;
private CheckBox cbCertificate;
private Button btnOAuth; private Button btnOAuth;
private EditText etRealm; private EditText etRealm;
private CheckBox cbUseIp; private CheckBox cbUseIp;
@ -185,6 +186,7 @@ public class FragmentIdentity extends FragmentBase {
etUser = view.findViewById(R.id.etUser); etUser = view.findViewById(R.id.etUser);
tilPassword = view.findViewById(R.id.tilPassword); tilPassword = view.findViewById(R.id.tilPassword);
tvCharacters = view.findViewById(R.id.tvCharacters); tvCharacters = view.findViewById(R.id.tvCharacters);
cbCertificate = view.findViewById(R.id.cbCertificate);
btnOAuth = view.findViewById(R.id.btnOAuth); btnOAuth = view.findViewById(R.id.btnOAuth);
etRealm = view.findViewById(R.id.etRealm); etRealm = view.findViewById(R.id.etRealm);
cbUseIp = view.findViewById(R.id.cbUseIp); cbUseIp = view.findViewById(R.id.cbUseIp);
@ -266,10 +268,12 @@ public class FragmentIdentity extends FragmentBase {
etEmail.setText(account.user); etEmail.setText(account.user);
etUser.setText(account.user); etUser.setText(account.user);
tilPassword.getEditText().setText(account.password); tilPassword.getEditText().setText(account.password);
cbCertificate.setChecked(account.certificate);
etRealm.setText(account.realm); etRealm.setText(account.realm);
etUser.setEnabled(auth == EmailService.AUTH_TYPE_PASSWORD); etUser.setEnabled(auth == EmailService.AUTH_TYPE_PASSWORD);
tilPassword.setEnabled(auth == EmailService.AUTH_TYPE_PASSWORD); tilPassword.setEnabled(auth == EmailService.AUTH_TYPE_PASSWORD);
cbCertificate.setEnabled(auth == EmailService.AUTH_TYPE_PASSWORD);
cbTrust.setChecked(false); cbTrust.setChecked(false);
} }
@ -402,6 +406,7 @@ public class FragmentIdentity extends FragmentBase {
etUser.setEnabled(auth == EmailService.AUTH_TYPE_PASSWORD); etUser.setEnabled(auth == EmailService.AUTH_TYPE_PASSWORD);
tilPassword.setEnabled(auth == EmailService.AUTH_TYPE_PASSWORD); tilPassword.setEnabled(auth == EmailService.AUTH_TYPE_PASSWORD);
cbCertificate.setEnabled(auth == EmailService.AUTH_TYPE_PASSWORD);
} }
@Override @Override
@ -581,6 +586,7 @@ public class FragmentIdentity extends FragmentBase {
args.putString("provider", provider); args.putString("provider", provider);
args.putString("user", etUser.getText().toString().trim()); args.putString("user", etUser.getText().toString().trim());
args.putString("password", tilPassword.getEditText().getText().toString()); args.putString("password", tilPassword.getEditText().getText().toString());
args.putBoolean("certificate", cbCertificate.isChecked());
args.putString("realm", etRealm.getText().toString()); args.putString("realm", etRealm.getText().toString());
args.putString("fingerprint", cbTrust.isChecked() ? (String) cbTrust.getTag() : null); args.putString("fingerprint", cbTrust.isChecked() ? (String) cbTrust.getTag() : null);
args.putBoolean("use_ip", cbUseIp.isChecked()); args.putBoolean("use_ip", cbUseIp.isChecked());
@ -630,6 +636,7 @@ public class FragmentIdentity extends FragmentBase {
String provider = args.getString("provider"); String provider = args.getString("provider");
String user = args.getString("user").trim(); String user = args.getString("user").trim();
String password = args.getString("password"); String password = args.getString("password");
boolean certificate = args.getBoolean("certificate");
String realm = args.getString("realm"); String realm = args.getString("realm");
String fingerprint = args.getString("fingerprint"); String fingerprint = args.getString("fingerprint");
boolean use_ip = args.getBoolean("use_ip"); boolean use_ip = args.getBoolean("use_ip");
@ -660,7 +667,7 @@ public class FragmentIdentity extends FragmentBase {
port = (starttls ? "587" : "465"); port = (starttls ? "587" : "465");
if (TextUtils.isEmpty(user) && !should) if (TextUtils.isEmpty(user) && !should)
throw new IllegalArgumentException(context.getString(R.string.title_no_user)); throw new IllegalArgumentException(context.getString(R.string.title_no_user));
if (synchronize && TextUtils.isEmpty(password) && !insecure && !should) if (synchronize && TextUtils.isEmpty(password) && !insecure && !certificate && !should)
throw new IllegalArgumentException(context.getString(R.string.title_no_password)); throw new IllegalArgumentException(context.getString(R.string.title_no_password));
if (!TextUtils.isEmpty(replyto) && !should) { if (!TextUtils.isEmpty(replyto) && !should) {
@ -732,6 +739,8 @@ public class FragmentIdentity extends FragmentBase {
return true; return true;
if (!Objects.equals(identity.password, password)) if (!Objects.equals(identity.password, password))
return true; return true;
if (!Objects.equals(identity.certificate, certificate))
return true;
if (!Objects.equals(identity.realm, realm)) if (!Objects.equals(identity.realm, realm))
return true; return true;
if (!Objects.equals(identity.fingerprint, fingerprint)) if (!Objects.equals(identity.fingerprint, fingerprint))
@ -761,6 +770,7 @@ public class FragmentIdentity extends FragmentBase {
!identity.insecure.equals(insecure) || !identity.insecure.equals(insecure) ||
!host.equals(identity.host) || Integer.parseInt(port) != identity.port || !host.equals(identity.host) || Integer.parseInt(port) != identity.port ||
!user.equals(identity.user) || !password.equals(identity.password) || !user.equals(identity.user) || !password.equals(identity.password) ||
!Objects.equals(identity.certificate, certificate) ||
!Objects.equals(realm, identityRealm) || !Objects.equals(realm, identityRealm) ||
!Objects.equals(identity.fingerprint, fingerprint) || !Objects.equals(identity.fingerprint, fingerprint) ||
use_ip != identity.use_ip)); use_ip != identity.use_ip));
@ -777,7 +787,11 @@ public class FragmentIdentity extends FragmentBase {
try (EmailService iservice = new EmailService( try (EmailService iservice = new EmailService(
context, protocol, realm, insecure, EmailService.PURPOSE_CHECK, true)) { context, protocol, realm, insecure, EmailService.PURPOSE_CHECK, true)) {
iservice.setUseIp(use_ip); iservice.setUseIp(use_ip);
iservice.connect(host, Integer.parseInt(port), auth, provider, user, password, fingerprint); iservice.connect(
host, Integer.parseInt(port),
auth, provider,
user, password,
certificate, fingerprint);
} }
} }
@ -809,6 +823,7 @@ public class FragmentIdentity extends FragmentBase {
identity.auth_type = auth; identity.auth_type = auth;
identity.user = user; identity.user = user;
identity.password = password; identity.password = password;
identity.certificate = certificate;
identity.provider = provider; identity.provider = provider;
identity.realm = realm; identity.realm = realm;
identity.fingerprint = fingerprint; identity.fingerprint = fingerprint;
@ -1004,6 +1019,7 @@ public class FragmentIdentity extends FragmentBase {
etPort.setText(identity == null ? null : Long.toString(identity.port)); etPort.setText(identity == null ? null : Long.toString(identity.port));
etUser.setText(identity == null ? null : identity.user); etUser.setText(identity == null ? null : identity.user);
tilPassword.getEditText().setText(identity == null ? null : identity.password); tilPassword.getEditText().setText(identity == null ? null : identity.password);
cbCertificate.setChecked(identity != null && identity.certificate);
etRealm.setText(identity == null ? null : identity.realm); etRealm.setText(identity == null ? null : identity.realm);
if (identity == null || identity.fingerprint == null) { if (identity == null || identity.fingerprint == null) {
@ -1059,6 +1075,7 @@ public class FragmentIdentity extends FragmentBase {
if (auth != EmailService.AUTH_TYPE_PASSWORD) { if (auth != EmailService.AUTH_TYPE_PASSWORD) {
etUser.setEnabled(false); etUser.setEnabled(false);
tilPassword.setEnabled(false); tilPassword.setEnabled(false);
cbCertificate.setEnabled(false);
} }
if (identity == null || identity.auth_type != EmailService.AUTH_TYPE_GMAIL) if (identity == null || identity.auth_type != EmailService.AUTH_TYPE_GMAIL)

@ -468,13 +468,14 @@ public class FragmentOAuth extends FragmentBase {
List<EntityFolder> folders; List<EntityFolder> folders;
Log.i("OAuth checking IMAP provider=" + provider.id); Log.i("OAuth checking IMAP provider=" + provider.id);
String aprotocol = provider.imap.starttls ? "imap" : "imaps"; String aprotocol = (provider.imap.starttls ? "imap" : "imaps");
try (EmailService iservice = new EmailService( try (EmailService iservice = new EmailService(
context, aprotocol, null, false, EmailService.PURPOSE_CHECK, true)) { context, aprotocol, null, false, EmailService.PURPOSE_CHECK, true)) {
iservice.connect( iservice.connect(
provider.imap.host, provider.imap.port, provider.imap.host, provider.imap.port,
EmailService.AUTH_TYPE_OAUTH, provider.id, EmailService.AUTH_TYPE_OAUTH, provider.id,
primaryEmail, state, null); primaryEmail, state,
false, null);
folders = iservice.getFolders(); folders = iservice.getFolders();
@ -483,13 +484,14 @@ public class FragmentOAuth extends FragmentBase {
} }
Log.i("OAuth checking SMTP provider=" + provider.id); Log.i("OAuth checking SMTP provider=" + provider.id);
String iprotocol = provider.smtp.starttls ? "smtp" : "smtps"; String iprotocol = (provider.smtp.starttls ? "smtp" : "smtps");
try (EmailService iservice = new EmailService( try (EmailService iservice = new EmailService(
context, iprotocol, null, false, EmailService.PURPOSE_CHECK, true)) { context, iprotocol, null, false, EmailService.PURPOSE_CHECK, true)) {
iservice.connect( iservice.connect(
provider.smtp.host, provider.smtp.port, provider.smtp.host, provider.smtp.port,
EmailService.AUTH_TYPE_OAUTH, provider.id, EmailService.AUTH_TYPE_OAUTH, provider.id,
primaryEmail, state, null); primaryEmail, state,
false, null);
} }
Log.i("OAuth passed provider=" + provider.id); Log.i("OAuth passed provider=" + provider.id);

@ -328,7 +328,8 @@ public class FragmentPop extends FragmentBase {
iservice.connect( iservice.connect(
host, Integer.parseInt(port), host, Integer.parseInt(port),
EmailService.AUTH_TYPE_PASSWORD, null, EmailService.AUTH_TYPE_PASSWORD, null,
user, password, null); user, password,
false, null);
} }
} }

@ -284,13 +284,18 @@ public class FragmentQuickSetup extends FragmentBase {
iservice.connect( iservice.connect(
provider.imap.host, provider.imap.port, provider.imap.host, provider.imap.port,
EmailService.AUTH_TYPE_PASSWORD, null, EmailService.AUTH_TYPE_PASSWORD, null,
user, password, null); user, password,
false, null);
} catch (AuthenticationFailedException ex) { } catch (AuthenticationFailedException ex) {
if (!user.equals(username)) { if (!user.equals(username)) {
Log.w(ex); Log.w(ex);
user = username; user = username;
Log.i("Retry with user=" + user); Log.i("Retry with user=" + user);
iservice.connect(provider.imap.host, provider.imap.port, EmailService.AUTH_TYPE_PASSWORD, null, user, password, null); iservice.connect(
provider.imap.host, provider.imap.port,
EmailService.AUTH_TYPE_PASSWORD, null,
user, password,
false, null);
} else } else
throw ex; throw ex;
} }
@ -308,7 +313,8 @@ public class FragmentQuickSetup extends FragmentBase {
iservice.connect( iservice.connect(
provider.smtp.host, provider.smtp.port, provider.smtp.host, provider.smtp.port,
EmailService.AUTH_TYPE_PASSWORD, null, EmailService.AUTH_TYPE_PASSWORD, null,
user, password, null); user, password,
false, null);
} }
if (check) if (check)

@ -255,6 +255,15 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tilPassword" /> app:layout_constraintTop_toBottomOf="@id/tilPassword" />
<CheckBox
android:id="@+id/cbCertificate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_use_certificate"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvCharacters" />
<Button <Button
android:id="@+id/btnOAuth" android:id="@+id/btnOAuth"
style="@style/buttonStyleSmall" style="@style/buttonStyleSmall"
@ -266,7 +275,7 @@
android:tag="disable" android:tag="disable"
android:text="@string/title_setup_authentication" android:text="@string/title_setup_authentication"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvCharacters" /> app:layout_constraintTop_toBottomOf="@id/cbCertificate" />
<TextView <TextView
android:id="@+id/tvOAuthSupport" android:id="@+id/tvOAuthSupport"
@ -906,7 +915,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
app:constraint_referenced_ids=" app:constraint_referenced_ids="
tvUser,etUser,tvPassword,tilPassword,btnOAuth,tvOAuthSupport,tvRealm,etRealm, tvUser,etUser,tvPassword,tilPassword,cbCertificate,btnOAuth,tvOAuthSupport,tvRealm,etRealm,
tvName,tvNameRemark,etName, tvName,tvNameRemark,etName,
tvColor,btnColor,tvColorHint,tvColorPro" /> tvColor,btnColor,tvColorHint,tvColorPro" />

@ -442,6 +442,15 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tilPassword" /> app:layout_constraintTop_toBottomOf="@id/tilPassword" />
<CheckBox
android:id="@+id/cbCertificate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_use_certificate"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvCharacters" />
<Button <Button
android:id="@+id/btnOAuth" android:id="@+id/btnOAuth"
style="@style/buttonStyleSmall" style="@style/buttonStyleSmall"
@ -453,7 +462,7 @@
android:tag="disable" android:tag="disable"
android:text="@string/title_setup_authentication" android:text="@string/title_setup_authentication"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvCharacters" /> app:layout_constraintTop_toBottomOf="@id/cbCertificate" />
<TextView <TextView
android:id="@+id/tvRealm" android:id="@+id/tvRealm"
@ -714,7 +723,7 @@
tvProvider,spProvider, tvProvider,spProvider,
tvDomain,tvDomainHint,etDomain,btnAutoConfig, tvDomain,tvDomainHint,etDomain,btnAutoConfig,
tvSmtp,tvHost,etHost,rgEncryption,cbInsecure,tvInsecureRemark,tvPort,etPort, tvSmtp,tvHost,etHost,rgEncryption,cbInsecure,tvInsecureRemark,tvPort,etPort,
tvUser,etUser,tvPassword,tilPassword,btnOAuth, tvUser,etUser,tvPassword,tilPassword,cbCertificate,btnOAuth,
tvRealm,etRealm, tvRealm,etRealm,
cbUseIp,tvUseIpHint, cbUseIp,tvUseIpHint,
cbSynchronize,cbPrimary, cbSynchronize,cbPrimary,

@ -517,6 +517,7 @@
<string name="title_port">Port number</string> <string name="title_port">Port number</string>
<string name="title_user">User name</string> <string name="title_user">User name</string>
<string name="title_password">Password</string> <string name="title_password">Password</string>
<string name="title_use_certificate">Use client certificate</string>
<string name="title_realm">Realm</string> <string name="title_realm">Realm</string>
<string name="title_use_ip">Use local IP address instead of host name</string> <string name="title_use_ip">Use local IP address instead of host name</string>
<string name="title_primary_account">Primary (default account)</string> <string name="title_primary_account">Primary (default account)</string>

Loading…
Cancel
Save