Added importing provider profiles

pull/207/head
M66B 3 years ago
parent 443a5b12e7
commit e8b391a862

@ -142,6 +142,7 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
static final int REQUEST_OAUTH = 7;
static final int REQUEST_STILL = 8;
static final int REQUEST_DELETE_ACCOUNT = 9;
static final int REQUEST_IMPORT_PROVIDERS = 10;
static final int PI_MISC = 1;
@ -462,6 +463,10 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
if (resultCode == RESULT_OK && data != null)
handleImportCertificate(data);
break;
case REQUEST_IMPORT_PROVIDERS:
if (resultCode == RESULT_OK && data != null)
handleImportProviders(data);
break;
}
} catch (Throwable ex) {
Log.e(ex);
@ -1543,6 +1548,34 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
}
}
private void handleImportProviders(Intent data) {
Bundle args = new Bundle();
args.putParcelable("uri", data.getData());
new SimpleTask<Void>() {
@Override
protected Void onExecute(Context context, Bundle args) throws Throwable {
Uri uri = args.getParcelable("uri");
Log.i("Reading URI=" + uri);
ContentResolver resolver = context.getContentResolver();
EmailProvider.importProfiles(resolver.openInputStream(uri), context);
return null;
}
@Override
protected void onExecuted(Bundle args, Void data) {
ToastEx.makeText(ActivitySetup.this, R.string.title_completed, Toast.LENGTH_LONG).show();
}
@Override
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getSupportFragmentManager(), ex);
}
}.execute(this, args, "import:providers");
}
private void onGmail(Intent intent) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.content_frame, new FragmentGmail()).addToBackStack("quick");

@ -214,6 +214,7 @@ public class ApplicationEx extends Application
Log.e(ex);
}
EmailProvider.init(this);
EncryptionHelper.init(this);
MessageHelper.setSystemProperties(this);

@ -22,11 +22,11 @@ package eu.faircode.email;
import static android.system.OsConstants.ECONNREFUSED;
import android.content.Context;
import android.content.res.XmlResourceParser;
import android.os.Parcel;
import android.os.Parcelable;
import android.system.ErrnoException;
import android.text.TextUtils;
import android.util.Xml;
import androidx.annotation.NonNull;
@ -37,9 +37,14 @@ import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.InetAddress;
@ -92,6 +97,10 @@ public class EmailProvider implements Parcelable {
enum UserType {LOCAL, EMAIL, VALUE}
private static List<EmailProvider> imported;
private static final ExecutorService executor =
Helper.getBackgroundExecutor(0, "provider");
private static final int SCAN_TIMEOUT = 15 * 1000; // milliseconds
private static final int ISPDB_TIMEOUT = 15 * 1000; // milliseconds
@ -105,8 +114,6 @@ public class EmailProvider implements Parcelable {
"keemail.me", // tutanota
"ctemplar.com"
));
private static final ExecutorService executor =
Helper.getBackgroundExecutor(0, "provider");
private EmailProvider() {
}
@ -115,6 +122,33 @@ public class EmailProvider implements Parcelable {
this.name = name;
}
static void init(Context context) {
executor.submit(new Runnable() {
@Override
public void run() {
File file = new File(context.getFilesDir(), "providers.xml");
if (file.exists()) {
try (FileInputStream is = new FileInputStream(file)) {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(is, null);
imported = parseProfiles(parser);
} catch (Throwable ex) {
Log.e(ex);
}
}
}
});
}
static void importProfiles(InputStream is, Context context) throws IOException {
File file = new File(context.getFilesDir(), "providers.xml");
try (OutputStream os = new FileOutputStream(file)) {
Helper.copy(is, os);
}
init(context);
}
private void validate() throws UnknownHostException {
if (TextUtils.isEmpty(this.imap.host) || this.imap.port <= 0 ||
TextUtils.isEmpty(this.smtp.host) || this.smtp.port <= 0)
@ -139,9 +173,38 @@ public class EmailProvider implements Parcelable {
static List<EmailProvider> loadProfiles(Context context) {
List<EmailProvider> result = null;
try {
result = parseProfiles(context.getResources().getXml(R.xml.providers));
} catch (Throwable ex) {
Log.e(ex);
}
if (imported != null)
result.addAll(imported);
final Collator collator = Collator.getInstance(Locale.getDefault());
collator.setStrength(Collator.SECONDARY); // Case insensitive, process accents etc
Collections.sort(result, new Comparator<EmailProvider>() {
@Override
public int compare(EmailProvider p1, EmailProvider p2) {
int o = Integer.compare(p1.order, p2.order);
if (o == 0)
return collator.compare(p1.name, p2.name);
else
return o;
}
});
return result;
}
private static List<EmailProvider> parseProfiles(XmlPullParser xml) {
List<EmailProvider> result = null;
try {
EmailProvider provider = null;
XmlResourceParser xml = context.getResources().getXml(R.xml.providers);
int eventType = xml.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
@ -156,7 +219,7 @@ public class EmailProvider implements Parcelable {
provider.description = xml.getAttributeValue(null, "description");
if (provider.description == null)
provider.description = provider.name;
provider.enabled = xml.getAttributeBooleanValue(null, "enabled", true);
provider.enabled = getAttributeBooleanValue(xml, "enabled", true);
String domain = xml.getAttributeValue(null, "domain");
if (domain != null)
@ -166,11 +229,11 @@ public class EmailProvider implements Parcelable {
if (mx != null)
provider.mx = Arrays.asList(mx.split(","));
provider.order = xml.getAttributeIntValue(null, "order", Integer.MAX_VALUE);
provider.keepalive = xml.getAttributeIntValue(null, "keepalive", 0);
provider.partial = xml.getAttributeBooleanValue(null, "partial", true);
provider.useip = xml.getAttributeBooleanValue(null, "useip", true);
provider.appPassword = xml.getAttributeBooleanValue(null, "appPassword", false);
provider.order = getAttributeIntValue(xml, "order", Integer.MAX_VALUE);
provider.keepalive = getAttributeIntValue(xml, "keepalive", 0);
provider.partial = getAttributeBooleanValue(xml, "partial", true);
provider.useip = getAttributeBooleanValue(xml, "useip", true);
provider.appPassword = getAttributeBooleanValue(xml, "appPassword", false);
provider.link = xml.getAttributeValue(null, "link");
String documentation = xml.getAttributeValue(null, "documentation");
@ -193,20 +256,20 @@ public class EmailProvider implements Parcelable {
} else if ("imap".equals(name)) {
provider.imap.score = 100;
provider.imap.host = xml.getAttributeValue(null, "host");
provider.imap.port = xml.getAttributeIntValue(null, "port", 0);
provider.imap.starttls = xml.getAttributeBooleanValue(null, "starttls", false);
provider.imap.port = getAttributeIntValue(xml, "port", 0);
provider.imap.starttls = getAttributeBooleanValue(xml, "starttls", false);
} else if ("smtp".equals(name)) {
provider.smtp.score = 100;
provider.smtp.host = xml.getAttributeValue(null, "host");
provider.smtp.port = xml.getAttributeIntValue(null, "port", 0);
provider.smtp.starttls = xml.getAttributeBooleanValue(null, "starttls", false);
provider.smtp.port = getAttributeIntValue(xml, "port", 0);
provider.smtp.starttls = getAttributeBooleanValue(xml, "starttls", false);
} else if ("oauth".equals(name)) {
provider.oauth = new OAuth();
provider.oauth.enabled = xml.getAttributeBooleanValue(null, "enabled", false);
provider.oauth.askAccount = xml.getAttributeBooleanValue(null, "askAccount", false);
provider.oauth.enabled = getAttributeBooleanValue(xml, "enabled", false);
provider.oauth.askAccount = getAttributeBooleanValue(xml, "askAccount", false);
provider.oauth.clientId = xml.getAttributeValue(null, "clientId");
provider.oauth.clientSecret = xml.getAttributeValue(null, "clientSecret");
provider.oauth.pcke = xml.getAttributeBooleanValue(null, "pcke", false);
provider.oauth.pcke = getAttributeBooleanValue(xml, "pcke", false);
provider.oauth.scopes = xml.getAttributeValue(null, "scopes").split(",");
provider.oauth.authorizationEndpoint = xml.getAttributeValue(null, "authorizationEndpoint");
provider.oauth.tokenEndpoint = xml.getAttributeValue(null, "tokenEndpoint");
@ -226,23 +289,20 @@ public class EmailProvider implements Parcelable {
} catch (Throwable ex) {
Log.e(ex);
}
final Collator collator = Collator.getInstance(Locale.getDefault());
collator.setStrength(Collator.SECONDARY); // Case insensitive, process accents etc
Collections.sort(result, new Comparator<EmailProvider>() {
@Override
public int compare(EmailProvider p1, EmailProvider p2) {
int o = Integer.compare(p1.order, p2.order);
if (o == 0)
return collator.compare(p1.name, p2.name);
else
return o;
}
});
return result;
}
static boolean getAttributeBooleanValue(XmlPullParser parser, String name, boolean defaultValue) {
String value = parser.getAttributeValue(null, name);
return (value == null ? defaultValue : Boolean.parseBoolean(value));
}
static int getAttributeIntValue(XmlPullParser parser, String name, int defaultValue) {
String value = parser.getAttributeValue(null, name);
return (value == null ? defaultValue : Integer.parseInt(value));
}
static EmailProvider getProvider(Context context, String id) throws FileNotFoundException {
for (EmailProvider provider : loadProfiles(context))
if (id.equals(provider.id))

@ -19,6 +19,7 @@ package eu.faircode.email;
Copyright 2018-2022 by Marcel Bokhorst (M66B)
*/
import android.app.Activity;
import android.app.ActivityManager;
import android.app.NotificationChannel;
import android.app.NotificationManager;
@ -172,6 +173,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
private SwitchCompat swInfra;
private SwitchCompat swDupMsgId;
private SwitchCompat swTestIab;
private Button btnImportProviders;
private TextView tvProcessors;
private TextView tvMemoryClass;
private TextView tvMemoryUsage;
@ -333,6 +335,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
swInfra = view.findViewById(R.id.swInfra);
swDupMsgId = view.findViewById(R.id.swDupMsgId);
swTestIab = view.findViewById(R.id.swTestIab);
btnImportProviders = view.findViewById(R.id.btnImportProviders);
tvProcessors = view.findViewById(R.id.tvProcessors);
tvMemoryClass = view.findViewById(R.id.tvMemoryClass);
tvMemoryUsage = view.findViewById(R.id.tvMemoryUsage);
@ -1144,6 +1147,17 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
}
});
btnImportProviders.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
Intent choose = Helper.getChooser(v.getContext(), intent);
getActivity().startActivityForResult(choose, ActivitySetup.REQUEST_IMPORT_PROVIDERS);
}
});
btnGC.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

@ -1379,6 +1379,16 @@
app:layout_constraintTop_toBottomOf="@id/swDupMsgId"
app:switchPadding="12dp" />
<Button
android:id="@+id/btnImportProviders"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_advanced_import_providers"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swTestIab" />
<eu.faircode.email.FixedTextView
android:id="@+id/tvProcessors"
android:layout_width="0dp"
@ -1388,7 +1398,7 @@
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swTestIab" />
app:layout_constraintTop_toBottomOf="@id/btnImportProviders" />
<eu.faircode.email.FixedTextView
android:id="@+id/tvMemoryClass"

@ -738,6 +738,7 @@
<string name="title_advanced_infra" translatable="false">Show infrastructure</string>
<string name="title_advanced_dup_msgid" translatable="false">Duplicates by message ID</string>
<string name="title_advanced_test_iab" translatable="false">Test IAB</string>
<string name="title_advanced_import_providers" translatable="false">Import providers</string>
<string name="title_advanced_processors" translatable="false">Processors: %1$d</string>
<string name="title_advanced_memory_class" translatable="false">Memory class: %1$s/%2$s Total: %3$s</string>
<string name="title_advanced_memory_usage" translatable="false">Memory usage: %1$s/%2$s Native: %3$s</string>

Loading…
Cancel
Save