diff --git a/app/src/main/java/eu/faircode/email/FragmentSetup.java b/app/src/main/java/eu/faircode/email/FragmentSetup.java index 5759ac97ee..f85392af0d 100644 --- a/app/src/main/java/eu/faircode/email/FragmentSetup.java +++ b/app/src/main/java/eu/faircode/email/FragmentSetup.java @@ -38,6 +38,7 @@ import android.os.PowerManager; import android.preference.PreferenceManager; import android.provider.Settings; import android.text.TextUtils; +import android.util.Patterns; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -53,6 +54,9 @@ import android.widget.TextView; import android.widget.ToggleButton; import com.google.android.material.snackbar.Snackbar; +import com.google.android.material.textfield.TextInputLayout; +import com.sun.mail.imap.IMAPFolder; +import com.sun.mail.imap.IMAPStore; import org.json.JSONArray; import org.json.JSONObject; @@ -65,8 +69,10 @@ import java.io.OutputStream; import java.security.SecureRandom; import java.security.spec.KeySpec; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Properties; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; @@ -76,6 +82,9 @@ import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; +import javax.mail.Folder; +import javax.mail.Session; +import javax.mail.Transport; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -91,6 +100,11 @@ public class FragmentSetup extends FragmentEx { private ImageButton ibHelp; + private EditText etName; + private EditText etEmail; + private TextInputLayout tilPassword; + private Button btnQuick; + private Button btnAccount; private TextView tvAccountDone; private TextView tvNoPrimaryDrafts; @@ -135,6 +149,11 @@ public class FragmentSetup extends FragmentEx { // Get controls ibHelp = view.findViewById(R.id.ibHelp); + etName = view.findViewById(R.id.etName); + etEmail = view.findViewById(R.id.etEmail); + tilPassword = view.findViewById(R.id.tilPassword); + btnQuick = view.findViewById(R.id.btnQuick); + btnAccount = view.findViewById(R.id.btnAccount); tvAccountDone = view.findViewById(R.id.tvAccountDone); tvNoPrimaryDrafts = view.findViewById(R.id.tvNoPrimaryDrafts); @@ -165,6 +184,216 @@ public class FragmentSetup extends FragmentEx { } }); + btnQuick.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Bundle args = new Bundle(); + args.putString("name", etName.getText().toString()); + args.putString("email", etEmail.getText().toString()); + args.putString("password", tilPassword.getEditText().getText().toString()); + + new SimpleTask() { + @Override + protected void onInit(Bundle args) { + etName.setEnabled(false); + etEmail.setEnabled(false); + tilPassword.setEnabled(false); + btnQuick.setEnabled(false); + } + + @Override + protected void onCleanup(Bundle args) { + etName.setEnabled(true); + etEmail.setEnabled(true); + tilPassword.setEnabled(true); + btnQuick.setEnabled(true); + } + + @Override + protected Void onLoad(Context context, Bundle args) throws Throwable { + String name = args.getString("name"); + String email = args.getString("email"); + String password = args.getString("password"); + + if (TextUtils.isEmpty(name)) + throw new IllegalArgumentException(context.getString(R.string.title_no_name)); + if (TextUtils.isEmpty(email)) + throw new IllegalArgumentException(context.getString(R.string.title_no_email)); + if (!Patterns.EMAIL_ADDRESS.matcher(email).matches()) + throw new IllegalArgumentException(context.getString(R.string.title_email_invalid)); + + String domain = email.split("@")[1]; + Provider provider = Provider.fromDomain(context, domain); + + String user = email; // TODO + + Character separator; + long now = new Date().getTime(); + + List folders = new ArrayList<>(); + + { + Properties props = MessageHelper.getSessionProperties(Helper.AUTH_TYPE_PASSWORD, false); + Session isession = Session.getInstance(props, null); + isession.setDebug(true); + IMAPStore istore = null; + try { + istore = (IMAPStore) isession.getStore(provider.imap_starttls ? "imap" : "imaps"); + istore.connect(provider.imap_host, provider.imap_port, user, password); + + separator = istore.getDefaultFolder().getSeparator(); + + boolean drafts = false; + for (Folder ifolder : istore.getDefaultFolder().list("*")) { + String type = null; + boolean selectable = true; + String[] attrs = ((IMAPFolder) ifolder).getAttributes(); + Log.i(ifolder.getFullName() + " attrs=" + TextUtils.join(" ", attrs)); + for (String attr : attrs) { + if ("\\Noselect".equals(attr) || "\\NonExistent".equals(attr)) + selectable = false; + if (attr.startsWith("\\")) { + int index = EntityFolder.SYSTEM_FOLDER_ATTR.indexOf(attr.substring(1)); + if (index >= 0) { + type = EntityFolder.SYSTEM_FOLDER_TYPE.get(index); + break; + } + } + } + + if (selectable && type != null) { + EntityFolder folder = new EntityFolder(); + folder.name = ifolder.getFullName(); + folder.type = type; + folder.level = EntityFolder.getLevel(separator, folder.name); + folder.synchronize = EntityFolder.SYSTEM_FOLDER_SYNC.contains(type); + folder.sync_days = EntityFolder.DEFAULT_SYNC; + folder.keep_days = EntityFolder.DEFAULT_KEEP; + folders.add(folder); + + if (EntityFolder.DRAFTS.equals(type)) + drafts = true; + } + } + + if (!drafts) + throw new IllegalArgumentException(context.getString(R.string.title_no_drafts)); + } finally { + if (istore != null) + istore.close(); + } + } + + { + Properties props = MessageHelper.getSessionProperties(Helper.AUTH_TYPE_PASSWORD, false); + Session isession = Session.getInstance(props, null); + isession.setDebug(true); + Transport itransport = isession.getTransport(provider.smtp_starttls ? "smtp" : "smtps"); + try { + itransport.connect(provider.smtp_host, provider.smtp_port, user, password); + } finally { + itransport.close(); + } + } + + DB db = DB.getInstance(context); + try { + db.beginTransaction(); + EntityAccount primary = db.account().getPrimaryAccount(); + + // Create account + EntityAccount account = new EntityAccount(); + + account.auth_type = Helper.AUTH_TYPE_PASSWORD; + account.host = provider.imap_host; + account.starttls = provider.imap_starttls; + account.insecure = false; + account.port = provider.imap_port; + account.user = user; + account.password = password; + + account.name = provider.name; + account.color = null; + + account.synchronize = true; + account.primary = (primary == null); + account.notify = false; + account.browse = true; + account.poll_interval = 19; + account.prefix = provider.prefix; // TODO + + account.created = now; + account.error = null; + account.last_connected = now; + + account.id = db.account().insertAccount(account); + + // Create folders + for (EntityFolder folder : folders) { + folder.account = account.id; + folder.id = db.folder().insertFolder(folder); + } + + // Create identity + EntityIdentity identity = new EntityIdentity(); + identity.name = name; + identity.email = email; + identity.account = account.id; + + identity.display = null; + identity.color = null; + identity.signature = null; + + identity.auth_type = Helper.AUTH_TYPE_PASSWORD; + identity.host = provider.smtp_host; + identity.starttls = provider.smtp_starttls; + identity.insecure = false; + identity.port = provider.smtp_port; + identity.user = user; + identity.password = password; + identity.synchronize = true; + identity.primary = true; + + identity.replyto = null; + identity.bcc = null; + identity.delivery_receipt = false; + identity.read_receipt = false; + identity.store_sent = false; + identity.sent_folder = null; + identity.error = null; + + identity.id = db.identity().insertIdentity(identity); + + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + + ServiceSynchronize.reload(context, "quick setup"); + + return null; + } + + @Override + protected void onLoaded(Bundle args, Void data) { + finish(); + } + + @Override + protected void onException(Bundle args, Throwable ex) { + if (ex instanceof IllegalArgumentException) + Snackbar.make(view, ex.getMessage(), Snackbar.LENGTH_LONG).show(); + else + new DialogBuilderLifecycle(getContext(), getViewLifecycleOwner()) + .setMessage(Helper.formatThrowable(ex)) + .setPositiveButton(android.R.string.cancel, null) + .create() + .show(); + } + }.load(FragmentSetup.this, args); + } + }); + btnAccount.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { diff --git a/app/src/main/res/layout/fragment_setup.xml b/app/src/main/res/layout/fragment_setup.xml index 15b14d9dd3..00688abd41 100644 --- a/app/src/main/res/layout/fragment_setup.xml +++ b/app/src/main/res/layout/fragment_setup.xml @@ -12,7 +12,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - + + + + + + + + + +