diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsBackup.java b/app/src/main/java/eu/faircode/email/FragmentOptionsBackup.java index df92af47b6..24ee8e8984 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsBackup.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsBackup.java @@ -21,6 +21,7 @@ package eu.faircode.email; import static android.app.Activity.RESULT_OK; import static eu.faircode.email.ServiceAuthenticator.AUTH_TYPE_GMAIL; +import static eu.faircode.email.ServiceAuthenticator.AUTH_TYPE_PASSWORD; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; @@ -60,6 +61,7 @@ import androidx.cardview.widget.CardView; import androidx.constraintlayout.widget.Group; import androidx.documentfile.provider.DocumentFile; import androidx.lifecycle.ViewModelProvider; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.preference.PreferenceManager; import com.google.android.material.textfield.TextInputLayout; @@ -655,6 +657,9 @@ public class FragmentOptionsBackup extends FragmentBase implements SharedPrefere if ("k9s".equals(ext)) { handleK9Import(uri); return; + } else if ("mobileconfig".equals(ext)) { + handleAppleImport(uri); + return; } } } catch (Throwable ex) { @@ -1514,6 +1519,183 @@ public class FragmentOptionsBackup extends FragmentBase implements SharedPrefere }.execute(this, args, "setup:k9"); } + private void handleAppleImport(Uri uri) { + Bundle args = new Bundle(); + args.putParcelable("uri", uri); + + ViewModelExport vme = new ViewModelProvider(getActivity()).get(ViewModelExport.class); + args.putString("password", vme.getPassword()); + + new SimpleTask() { + @Override + protected EntityAccount onExecute(Context context, Bundle args) throws Throwable { + Uri uri = args.getParcelable("uri"); + String password = args.getString("password"); + + EntityAccount account = new EntityAccount(); + EntityIdentity identity = new EntityIdentity(); + + ContentResolver resolver = context.getContentResolver(); + InputStream is = resolver.openInputStream(uri); + if (is == null) + throw new FileNotFoundException(uri.toString()); + try (InputStream bis = new BufferedInputStream(is)) { + XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); + XmlPullParser xml = factory.newPullParser(); + xml.setInput(new InputStreamReader(bis)); + + account.auth_type = AUTH_TYPE_PASSWORD; + account.password = password; + account.encryption = EmailService.ENCRYPTION_STARTTLS; + account.synchronize = false; + account.primary = false; + + identity.auth_type = AUTH_TYPE_PASSWORD; + identity.password = password; + identity.encryption = EmailService.ENCRYPTION_STARTTLS; + identity.synchronize = false; + identity.primary = true; + + // https://developer.apple.com/documentation/devicemanagement/mail + String key = null; + int eventType = xml.getEventType(); + while (eventType != XmlPullParser.END_DOCUMENT) { + if (eventType == XmlPullParser.START_TAG) { + String name = xml.getName(); + if ("key".equals(name)) { + eventType = xml.next(); + key = (eventType == XmlPullParser.TEXT ? xml.getText() : null); + } else if (key != null && + ("string".equals(name) || "integer".equals(name))) { + eventType = xml.next(); + if (eventType == XmlPullParser.TEXT) { + String value = xml.getText(); + eventType = xml.next(); + if (eventType == XmlPullParser.END_TAG) { + Log.i("mobileconfig " + key + "=" + value); + switch (key) { + case "allowMailDrop": + break; + case "disableMailRecentsSyncing": + break; + + case "EmailAccountDescription": + account.name = value; + break; + case "EmailAccountName": + identity.name = value; + break; + case "EmailAccountType": // required + if ("EmailTypeIMAP".equals(value)) + account.protocol = EntityAccount.TYPE_IMAP; + else if ("EmailTypePOP".equals(value)) + account.protocol = EntityAccount.TYPE_POP; + break; + case "EmailAddress": + String[] email = value.split(","); + if (email.length > 0) + identity.email = email[0]; + break; + + case "IncomingMailServerAuthentication": // required + // EmailAuthNone, EmailAuthPassword, EmailAuthCRAMMD5, EmailAuthNTLM, EmailAuthHTTPMD5 + break; + case "IncomingMailServerHostName": // required + account.host = value; + break; + case "IncomingMailServerIMAPPathPrefix": + break; + case "IncomingMailServerPortNumber": + account.port = Integer.parseInt(value); + break; + case "IncomingMailServerUsername": + account.user = value; + break; + case "IncomingMailServerUseSSL": + account.encryption = EmailService.ENCRYPTION_SSL; + break; + case "IncomingPassword": + account.password = value; + break; + + case "OutgoingMailServerAuthentication": // required + // EmailAuthNone, EmailAuthPassword, EmailAuthCRAMMD5, EmailAuthNTLM, EmailAuthHTTPMD5 + break; + case "OutgoingMailServerHostName": // required + identity.host = value; + break; + case "OutgoingMailServerPortNumber": + identity.port = Integer.parseInt(value); + break; + case "OutgoingMailServerUsername": + identity.user = value; + break; + case "OutgoingMailServerUseSSL": + identity.encryption = EmailService.ENCRYPTION_SSL; + break; + case "OutgoingPassword": + identity.password = value; + break; + case "OutgoingPasswordSameAsIncomingPassword": + identity.password = account.password; + break; + } + } + } else + key = null; + } else if (key != null && "true".equals(name)) { + Log.i("mobileconfig " + key + "=" + name); + } else + key = null; + } + eventType = xml.next(); + } + + if (account.port == null) + account.port = 993; + if (account.password == null) + account.password = ""; + if (identity.port == null) + identity.port = 587; + if (identity.password == null) + identity.password = ""; + } + + DB db = DB.getInstance(context); + try { + db.beginTransaction(); + + account.id = db.account().insertAccount(account); + identity.account = account.id; + identity.id = db.identity().insertIdentity(identity); + + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + + return account; + } + + @Override + protected void onExecuted(Bundle args, EntityAccount account) { + if (account == null) + return; + + LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext()); + lbm.sendBroadcast( + new Intent(ActivitySetup.ACTION_EDIT_ACCOUNT) + .putExtra("id", account.id) + .putExtra("protocol", account.protocol)); + } + + @Override + protected void onException(Bundle args, Throwable ex) { + Log.unexpectedError(getParentFragmentManager(), ex); + } + }.execute(this, args, "setup:apple"); + } + private void askPassword(final boolean export) { final Context context = getContext(); Intent intent = (export ? getIntentExport(context) : getIntentImport(context));