Show certificate information / quick setup

pull/203/head
M66B 4 years ago
parent adfcc4b391
commit ce3f3dd387

@ -484,7 +484,7 @@ public class EmailService implements AutoCloseable {
Throwable ce = ex; Throwable ce = ex;
while (ce != null) { while (ce != null) {
if (factory != null && ce instanceof CertificateException) if (factory != null && ce instanceof CertificateException)
throw new UntrustedException(factory.certificate, ex); throw new UntrustedException(ex, factory.certificate);
if (ce instanceof IOException) if (ce instanceof IOException)
ioError = true; ioError = true;
ce = ce.getCause(); ce = ce.getCause();
@ -1037,10 +1037,10 @@ public class EmailService implements AutoCloseable {
} }
} }
class UntrustedException extends MessagingException { static class UntrustedException extends MessagingException {
private X509Certificate certificate; private X509Certificate certificate;
UntrustedException(@NonNull X509Certificate certificate, @NonNull Exception cause) { UntrustedException(@NonNull Exception cause, @NonNull X509Certificate certificate) {
super("Untrusted", cause); super("Untrusted", cause);
this.certificate = certificate; this.certificate = certificate;
} }
@ -1049,23 +1049,10 @@ public class EmailService implements AutoCloseable {
return certificate; return certificate;
} }
String getFingerprint() {
try {
if (certificate == null)
return null;
String keyId = EntityCertificate.getKeyId(certificate);
String fingerPrint = EntityCertificate.getFingerprintSha1(certificate);
return fingerPrint + (keyId == null ? "" : "/" + keyId);
} catch (Throwable ex) {
Log.e(ex);
return null;
}
}
@NonNull @NonNull
@Override @Override
public synchronized String toString() { public synchronized String toString() {
return getCause().toString(); return getCause().toString();
} }
} }
} }

@ -143,6 +143,19 @@ public class EntityCertificate {
} }
} }
static String getKeyFingerprint(X509Certificate certificate) {
if (certificate == null)
return null;
try {
String keyId = getKeyId(certificate);
String fingerPrint = getFingerprintSha1(certificate);
return fingerPrint + (keyId == null ? "" : "/" + keyId);
} catch (Throwable ex) {
Log.e(ex);
return null;
}
}
static String getSubject(X509Certificate certificate) { static String getSubject(X509Certificate certificate) {
return certificate.getSubjectX500Principal().getName(X500Principal.RFC2253); return certificate.getSubjectX500Principal().getName(X500Principal.RFC2253);
} }

@ -69,6 +69,7 @@ import com.sun.mail.imap.IMAPFolder;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.security.cert.X509Certificate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
@ -1331,9 +1332,10 @@ public class FragmentAccount extends FragmentBase {
grpError.setVisibility(View.VISIBLE); grpError.setVisibility(View.VISIBLE);
if (ex instanceof EmailService.UntrustedException) { if (ex instanceof EmailService.UntrustedException) {
EmailService.UntrustedException e = (EmailService.UntrustedException) ex; X509Certificate certificate = ((EmailService.UntrustedException) ex).getCertificate();
cbTrust.setTag(e.getFingerprint()); String fingerprint = EntityCertificate.getKeyFingerprint(certificate);
cbTrust.setText(getString(R.string.title_trust, e.getFingerprint())); cbTrust.setTag(fingerprint);
cbTrust.setText(getString(R.string.title_trust, fingerprint));
cbTrust.setVisibility(View.VISIBLE); cbTrust.setVisibility(View.VISIBLE);
} }

@ -66,6 +66,7 @@ import com.google.android.material.textfield.TextInputLayout;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.security.cert.X509Certificate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -1044,9 +1045,10 @@ public class FragmentIdentity extends FragmentBase {
grpError.setVisibility(View.VISIBLE); grpError.setVisibility(View.VISIBLE);
if (ex instanceof EmailService.UntrustedException) { if (ex instanceof EmailService.UntrustedException) {
EmailService.UntrustedException e = (EmailService.UntrustedException) ex; X509Certificate certificate = ((EmailService.UntrustedException) ex).getCertificate();
cbTrust.setTag(e.getFingerprint()); String fingerprint = EntityCertificate.getKeyFingerprint(certificate);
cbTrust.setText(getString(R.string.title_trust, e.getFingerprint())); cbTrust.setTag(fingerprint);
cbTrust.setText(getString(R.string.title_trust, fingerprint));
cbTrust.setVisibility(View.VISIBLE); cbTrust.setVisibility(View.VISIBLE);
} }

@ -50,6 +50,8 @@ import androidx.fragment.app.FragmentActivity;
import com.google.android.material.textfield.TextInputLayout; import com.google.android.material.textfield.TextInputLayout;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -77,13 +79,18 @@ public class FragmentQuickSetup extends FragmentBase {
private Button btnSupport; private Button btnSupport;
private TextView tvImap; private TextView tvImap;
private TextView tvImapFingerprint;
private TextView tvSmtp; private TextView tvSmtp;
private TextView tvImapFingerprint;
private TextView tvImapDnsNames;
private TextView tvSmtpFingerprint; private TextView tvSmtpFingerprint;
private TextView tvSmtpDnsNames;
private Button btnSave; private Button btnSave;
private ContentLoadingProgressBar pbSave; private ContentLoadingProgressBar pbSave;
private Group grpSetup; private Group grpSetup;
private Group grpCertificate;
private Group grpError; private Group grpError;
private static final String PRIVACY_URI = "https://www.mozilla.org/privacy/"; private static final String PRIVACY_URI = "https://www.mozilla.org/privacy/";
@ -114,13 +121,18 @@ public class FragmentQuickSetup extends FragmentBase {
btnSupport = view.findViewById(R.id.btnSupport); btnSupport = view.findViewById(R.id.btnSupport);
tvImap = view.findViewById(R.id.tvImap); tvImap = view.findViewById(R.id.tvImap);
tvImapFingerprint = view.findViewById(R.id.tvImapFingerprint);
tvSmtp = view.findViewById(R.id.tvSmtp); tvSmtp = view.findViewById(R.id.tvSmtp);
tvImapFingerprint = view.findViewById(R.id.tvImapFingerprint);
tvImapDnsNames = view.findViewById(R.id.tvImapDnsNames);
tvSmtpFingerprint = view.findViewById(R.id.tvSmtpFingerprint); tvSmtpFingerprint = view.findViewById(R.id.tvSmtpFingerprint);
tvSmtpDnsNames = view.findViewById(R.id.tvSmtpDnsNames);
btnSave = view.findViewById(R.id.btnSave); btnSave = view.findViewById(R.id.btnSave);
pbSave = view.findViewById(R.id.pbSave); pbSave = view.findViewById(R.id.pbSave);
grpSetup = view.findViewById(R.id.grpSetup); grpSetup = view.findViewById(R.id.grpSetup);
grpCertificate = view.findViewById(R.id.grpCertificate);
grpError = view.findViewById(R.id.grpError); grpError = view.findViewById(R.id.grpError);
// Wire controls // Wire controls
@ -209,6 +221,7 @@ public class FragmentQuickSetup extends FragmentBase {
btnHelp.setVisibility(View.GONE); btnHelp.setVisibility(View.GONE);
btnSave.setVisibility(View.GONE); btnSave.setVisibility(View.GONE);
grpSetup.setVisibility(View.GONE); grpSetup.setVisibility(View.GONE);
grpCertificate.setVisibility(View.GONE);
grpError.setVisibility(View.GONE); grpError.setVisibility(View.GONE);
return view; return view;
@ -219,8 +232,6 @@ public class FragmentQuickSetup extends FragmentBase {
args.putString("name", etName.getText().toString().trim()); args.putString("name", etName.getText().toString().trim());
args.putString("email", etEmail.getText().toString().trim()); args.putString("email", etEmail.getText().toString().trim());
args.putString("password", tilPassword.getEditText().getText().toString()); args.putString("password", tilPassword.getEditText().getText().toString());
args.putString("imap_fingerprint", tvImapFingerprint.getText().toString());
args.putString("smtp_fingerprint", tvSmtpFingerprint.getText().toString());
args.putBoolean("check", check); args.putBoolean("check", check);
new SimpleTask<EmailProvider>() { new SimpleTask<EmailProvider>() {
@ -237,6 +248,8 @@ public class FragmentQuickSetup extends FragmentBase {
btnHelp.setVisibility(View.GONE); btnHelp.setVisibility(View.GONE);
btnSave.setVisibility(check ? View.GONE : View.VISIBLE); btnSave.setVisibility(check ? View.GONE : View.VISIBLE);
grpSetup.setVisibility(check ? View.GONE : View.VISIBLE); grpSetup.setVisibility(check ? View.GONE : View.VISIBLE);
if (check)
grpCertificate.setVisibility(View.GONE);
} }
@Override @Override
@ -253,8 +266,6 @@ public class FragmentQuickSetup extends FragmentBase {
String email = args.getString("email"); String email = args.getString("email");
String password = args.getString("password"); String password = args.getString("password");
boolean check = args.getBoolean("check"); boolean check = args.getBoolean("check");
String imap_fingerprint = args.getString("imap_fingerprint");
String smtp_fingerprint = args.getString("smtp_fingerprint");
if (TextUtils.isEmpty(name)) if (TextUtils.isEmpty(name))
throw new IllegalArgumentException(context.getString(R.string.title_no_name)); throw new IllegalArgumentException(context.getString(R.string.title_no_name));
@ -264,10 +275,6 @@ public class FragmentQuickSetup extends FragmentBase {
throw new IllegalArgumentException(context.getString(R.string.title_email_invalid, email)); throw new IllegalArgumentException(context.getString(R.string.title_email_invalid, email));
if (TextUtils.isEmpty(password)) if (TextUtils.isEmpty(password))
throw new IllegalArgumentException(context.getString(R.string.title_no_password)); throw new IllegalArgumentException(context.getString(R.string.title_no_password));
if (TextUtils.isEmpty(imap_fingerprint))
imap_fingerprint = null;
if (TextUtils.isEmpty(smtp_fingerprint))
smtp_fingerprint = null;
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ani = (cm == null ? null : cm.getActiveNetworkInfo()); NetworkInfo ani = (cm == null ? null : cm.getActiveNetworkInfo());
@ -284,6 +291,10 @@ public class FragmentQuickSetup extends FragmentBase {
Log.i("User type=" + provider.user + " name=" + user); Log.i("User type=" + provider.user + " name=" + user);
List<EntityFolder> folders; List<EntityFolder> folders;
String imap_fingerprint = null;
String smtp_fingerprint = null;
X509Certificate imap_certificate = null;
X509Certificate smtp_certificate = null;
String aprotocol = (provider.imap.starttls ? "imap" : "imaps"); String aprotocol = (provider.imap.starttls ? "imap" : "imaps");
int aencryption = (provider.imap.starttls ? EmailService.ENCRYPTION_STARTTLS : EmailService.ENCRYPTION_SSL); int aencryption = (provider.imap.starttls ? EmailService.ENCRYPTION_STARTTLS : EmailService.ENCRYPTION_SSL);
@ -294,17 +305,15 @@ public class FragmentQuickSetup extends FragmentBase {
provider.imap.host, provider.imap.port, provider.imap.host, provider.imap.port,
AUTH_TYPE_PASSWORD, null, AUTH_TYPE_PASSWORD, null,
user, password, user, password,
null, imap_fingerprint); null, null);
} catch (EmailService.UntrustedException ex) { } catch (EmailService.UntrustedException ex) {
if (check) { imap_certificate = ex.getCertificate();
imap_fingerprint = ex.getFingerprint(); imap_fingerprint = EntityCertificate.getKeyFingerprint(imap_certificate);
iservice.connect( iservice.connect(
provider.imap.host, provider.imap.port, provider.imap.host, provider.imap.port,
AUTH_TYPE_PASSWORD, null, AUTH_TYPE_PASSWORD, null,
user, password, user, password,
null, imap_fingerprint); null, imap_fingerprint);
} else
throw ex;
} catch (Throwable ex) { } catch (Throwable ex) {
Log.w(ex); Log.w(ex);
// Why not AuthenticationFailedException? // Why not AuthenticationFailedException?
@ -348,29 +357,35 @@ public class FragmentQuickSetup extends FragmentBase {
} }
} }
Long max_size = null; Long max_size;
String iprotocol = (provider.smtp.starttls ? "smtp" : "smtps"); String iprotocol = (provider.smtp.starttls ? "smtp" : "smtps");
int iencryption = (provider.smtp.starttls ? EmailService.ENCRYPTION_STARTTLS : EmailService.ENCRYPTION_SSL); int iencryption = (provider.smtp.starttls ? EmailService.ENCRYPTION_STARTTLS : EmailService.ENCRYPTION_SSL);
try (EmailService iservice = new EmailService( try (EmailService iservice = new EmailService(
context, iprotocol, null, iencryption, false, context, iprotocol, null, iencryption, false,
EmailService.PURPOSE_CHECK, true)) { EmailService.PURPOSE_CHECK, true)) {
iservice.setUseIp(provider.useip, null); iservice.setUseIp(provider.useip, null);
iservice.connect( try {
provider.smtp.host, provider.smtp.port, iservice.connect(
AUTH_TYPE_PASSWORD, null, provider.smtp.host, provider.smtp.port,
user, password, AUTH_TYPE_PASSWORD, null,
null, smtp_fingerprint); user, password,
null, null);
} catch (EmailService.UntrustedException ex) {
smtp_certificate = ex.getCertificate();
smtp_fingerprint = EntityCertificate.getKeyFingerprint(smtp_certificate);
iservice.connect(
provider.smtp.host, provider.smtp.port,
AUTH_TYPE_PASSWORD, null,
user, password,
null, smtp_fingerprint);
}
max_size = iservice.getMaxSize(); max_size = iservice.getMaxSize();
} catch (EmailService.UntrustedException ex) {
if (check)
smtp_fingerprint = ex.getFingerprint();
else
throw ex;
} }
if (check) { if (check) {
args.putString("imap_fingerprint", imap_fingerprint); args.putSerializable("imap_certificate", imap_certificate);
args.putString("smtp_fingerprint", smtp_fingerprint); args.putSerializable("smtp_certificate", smtp_certificate);
return provider; return provider;
} }
@ -468,11 +483,38 @@ public class FragmentQuickSetup extends FragmentBase {
boolean check = args.getBoolean("check"); boolean check = args.getBoolean("check");
if (check) { if (check) {
tvImap.setText(result == null ? null : result.imap.toString()); tvImap.setText(result == null ? null : result.imap.toString());
tvImapFingerprint.setText(args.getString("imap_fingerprint"));
tvSmtp.setText(result == null ? null : result.smtp.toString()); tvSmtp.setText(result == null ? null : result.smtp.toString());
tvSmtpFingerprint.setText(args.getString("smtp_fingerprint"));
btnSave.setVisibility(result == null ? View.GONE : View.VISIBLE);
grpSetup.setVisibility(result == null ? View.GONE : View.VISIBLE); grpSetup.setVisibility(result == null ? View.GONE : View.VISIBLE);
X509Certificate imap_certificate =
(X509Certificate) args.getSerializable("imap_certificate");
X509Certificate smtp_certificate =
(X509Certificate) args.getSerializable("smtp_certificate");
List<String> imapNames = new ArrayList<>();
if (imap_certificate != null)
try {
imapNames = EntityCertificate.getDnsNames(imap_certificate);
} catch (Throwable ignored) {
}
List<String> smtpNames = new ArrayList<>();
if (smtp_certificate != null)
try {
smtpNames = EntityCertificate.getDnsNames(smtp_certificate);
} catch (Throwable ignored) {
}
tvImapFingerprint.setText(EntityCertificate.getKeyFingerprint(imap_certificate));
tvImapDnsNames.setText(TextUtils.join(", ", imapNames));
tvSmtpFingerprint.setText(EntityCertificate.getKeyFingerprint(smtp_certificate));
tvSmtpDnsNames.setText(TextUtils.join(", ", smtpNames));
grpCertificate.setVisibility(
imap_certificate == null && smtp_certificate == null
? View.GONE : View.VISIBLE);
btnSave.setVisibility(result == null ? View.GONE : View.VISIBLE);
} else { } else {
FragmentDialogAccount fragment = new FragmentDialogAccount(); FragmentDialogAccount fragment = new FragmentDialogAccount();
fragment.setArguments(args); fragment.setArguments(args);
@ -527,10 +569,9 @@ public class FragmentQuickSetup extends FragmentBase {
if (provider != null && if (provider != null &&
provider.imap != null && provider.smtp != null) { provider.imap != null && provider.smtp != null) {
tvImap.setText(provider.imap.toString()); tvImap.setText(provider.imap.toString());
tvImapFingerprint.setText(null);
tvSmtp.setText(provider.smtp.toString()); tvSmtp.setText(provider.smtp.toString());
tvSmtpFingerprint.setText(null);
grpSetup.setVisibility(View.VISIBLE); grpSetup.setVisibility(View.VISIBLE);
grpCertificate.setVisibility(View.GONE);
} }
getMainHandler().post(new Runnable() { getMainHandler().post(new Runnable() {

@ -253,6 +253,37 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvImapTitle" /> app:layout_constraintTop_toBottomOf="@id/tvImapTitle" />
<eu.faircode.email.FixedTextView
android:id="@+id/tvSmtpTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_setup_quick_smtp"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvImap" />
<eu.faircode.email.FixedTextView
android:id="@+id/tvSmtp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="smtp.domain.tld:993"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="?android:attr/textColorPrimary"
android:textIsSelectable="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvSmtpTitle" />
<eu.faircode.email.FixedTextView
android:id="@+id/tvCertificateInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_setup_quick_certificates"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvSmtp" />
<eu.faircode.email.FixedTextView <eu.faircode.email.FixedTextView
android:id="@+id/tvImapFingerprint" android:id="@+id/tvImapFingerprint"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -262,39 +293,43 @@
android:textColor="?attr/colorWarning" android:textColor="?attr/colorWarning"
android:textIsSelectable="true" android:textIsSelectable="true"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvImap" /> app:layout_constraintTop_toBottomOf="@id/tvCertificateInfo" />
<eu.faircode.email.FixedTextView <eu.faircode.email.FixedTextView
android:id="@+id/tvSmtpTitle" android:id="@+id/tvImapDnsNames"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="12dp" android:text="names"
android:text="@string/title_setup_quick_smtp"
android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textColor="?attr/colorWarning"
android:textIsSelectable="true"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvImapFingerprint" /> app:layout_constraintTop_toBottomOf="@id/tvImapFingerprint" />
<eu.faircode.email.FixedTextView <eu.faircode.email.FixedTextView
android:id="@+id/tvSmtp" android:id="@+id/tvSmtpFingerprint"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="smtp.domain.tld:993" android:layout_marginTop="12dp"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" android:text="fingerprint"
android:textColor="?android:attr/textColorPrimary" android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textColor="?attr/colorWarning"
android:textIsSelectable="true" android:textIsSelectable="true"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvSmtpTitle" /> app:layout_constraintTop_toBottomOf="@id/tvImapDnsNames" />
<eu.faircode.email.FixedTextView <eu.faircode.email.FixedTextView
android:id="@+id/tvSmtpFingerprint" android:id="@+id/tvSmtpDnsNames"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="fingerprint" android:text="names"
android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textColor="?attr/colorWarning" android:textColor="?attr/colorWarning"
android:textIsSelectable="true" android:textIsSelectable="true"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvSmtp" /> app:layout_constraintTop_toBottomOf="@id/tvSmtpFingerprint" />
<Button <Button
android:id="@+id/btnSave" android:id="@+id/btnSave"
@ -306,7 +341,7 @@
android:tag="disable" android:tag="disable"
android:text="@string/title_save" android:text="@string/title_save"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvSmtpFingerprint" /> app:layout_constraintTop_toBottomOf="@id/tvSmtpDnsNames" />
<eu.faircode.email.ContentLoadingProgressBar <eu.faircode.email.ContentLoadingProgressBar
android:id="@+id/pbSave" android:id="@+id/pbSave"
@ -324,8 +359,16 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
app:constraint_referenced_ids=" app:constraint_referenced_ids="
tvImapTitle,tvImap,tvImapFingerprint,tvSmtpTitle, tvImapTitle,tvImap,
tvSmtp,tvSmtpFingerprint" /> tvSmtpTitle,tvSmtp" />
<androidx.constraintlayout.widget.Group
android:id="@+id/grpCertificate"
android:layout_width="0dp"
android:layout_height="0dp"
app:constraint_referenced_ids="tvCertificateInfo,
tvImapFingerprint,tvImapDnsNames,
tvSmtpFingerprint,tvSmtpDnsNames" />
<androidx.constraintlayout.widget.Group <androidx.constraintlayout.widget.Group
android:id="@+id/grpError" android:id="@+id/grpError"

@ -165,8 +165,9 @@
<string name="title_setup_quick_support">Some providers make it difficult to add an account. Please do not blame FairEmail for this, but ask for support instead.</string> <string name="title_setup_quick_support">Some providers make it difficult to add an account. Please do not blame FairEmail for this, but ask for support instead.</string>
<string name="title_setup_quick_hint">The quick setup will fetch configuration information from autoconfig.thunderbird.net</string> <string name="title_setup_quick_hint">The quick setup will fetch configuration information from autoconfig.thunderbird.net</string>
<string name="title_setup_quick_patience">Please be patient &#8230;</string> <string name="title_setup_quick_patience">Please be patient &#8230;</string>
<string name="title_setup_quick_imap">IMAP server to receive messages</string>0 <string name="title_setup_quick_imap">IMAP server to receive messages</string>
<string name="title_setup_quick_smtp">SMTP server to send messages</string>0 <string name="title_setup_quick_smtp">SMTP server to send messages</string>
<string name="title_setup_quick_certificates">Server certificates</string>
<string name="title_setup_wizard">Wizard</string> <string name="title_setup_wizard">Wizard</string>
<string name="title_setup_wizard_multiple">The wizard can be used multiple times to set up multiple accounts</string> <string name="title_setup_wizard_multiple">The wizard can be used multiple times to set up multiple accounts</string>
<string name="title_setup_wizard_new">I need a new email address</string> <string name="title_setup_wizard_new">I need a new email address</string>

Loading…
Cancel
Save