From e98d2623e65e67c85512a3995dd03cbd02ad3587 Mon Sep 17 00:00:00 2001 From: M66B Date: Wed, 16 Sep 2026 22:30:56 +0200 Subject: [PATCH] Added demo accounts --- app/src/main/java/eu/faircode/email/Core.java | 5 + .../java/eu/faircode/email/EmailService.java | 98 ++++++++++--------- .../java/eu/faircode/email/EntityAccount.java | 62 ++++++++++++ .../eu/faircode/email/EntityIdentity.java | 46 +++++++++ .../eu/faircode/email/FragmentAccount.java | 10 ++ .../eu/faircode/email/FragmentIdentity.java | 10 ++ .../java/eu/faircode/email/FragmentOAuth.java | 10 ++ .../java/eu/faircode/email/FragmentPop.java | 10 ++ .../java/eu/faircode/email/ServiceSend.java | 5 + app/src/main/res/xml/providers.xml | 2 +- 10 files changed, 210 insertions(+), 48 deletions(-) diff --git a/app/src/main/java/eu/faircode/email/Core.java b/app/src/main/java/eu/faircode/email/Core.java index 98187dc9dc..9c466a0569 100644 --- a/app/src/main/java/eu/faircode/email/Core.java +++ b/app/src/main/java/eu/faircode/email/Core.java @@ -167,6 +167,11 @@ class Core { State state, long serial) throws JSONException, FolderClosedException { try { + if (EntityAccount.isTestAccount(account.user)) { + ops.clear(); + return; + } + Log.i(folder.name + " start process"); Store istore = iservice.getStore(); diff --git a/app/src/main/java/eu/faircode/email/EmailService.java b/app/src/main/java/eu/faircode/email/EmailService.java index cc0f45d127..b76995b8f3 100644 --- a/app/src/main/java/eu/faircode/email/EmailService.java +++ b/app/src/main/java/eu/faircode/email/EmailService.java @@ -908,46 +908,49 @@ public class EmailService implements AutoCloseable { if ("pop3".equals(protocol) || "pop3s".equals(protocol)) { iservice = isession.getStore(protocol); - iservice.connect(address.getHostAddress(), port, user, null); + if (!EntityAccount.isTestAccount(user)) + iservice.connect(address.getHostAddress(), port, user, null); } else if ("imap".equals(protocol) || "imaps".equals(protocol) || "gimaps".equals(protocol)) { iservice = isession.getStore(protocol); if (listener != null) ((IMAPStore) iservice).addStoreListener(listener); - iservice.connect(address.getHostAddress(), port, user, null); + if (!EntityAccount.isTestAccount(user)) { + iservice.connect(address.getHostAddress(), port, user, null); - // https://www.ietf.org/rfc/rfc2971.txt - IMAPStore istore = (IMAPStore) getStore(); - if (istore.hasCapability("ID")) - try { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - boolean client_id = prefs.getBoolean("client_id", true); - Map sid = istore.id(client_id ? getId(context) : null); - if (sid != null) { - Map crumb = new HashMap<>(); - for (String key : sid.keySet()) { - crumb.put(key, sid.get(key)); - EntityLog.log(context, EntityLog.Type.Protocol, "Server " + key + "=" + sid.get(key)); + // https://www.ietf.org/rfc/rfc2971.txt + IMAPStore istore = (IMAPStore) getStore(); + if (istore.hasCapability("ID")) + try { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + boolean client_id = prefs.getBoolean("client_id", true); + Map sid = istore.id(client_id ? getId(context) : null); + if (sid != null) { + Map crumb = new HashMap<>(); + for (String key : sid.keySet()) { + crumb.put(key, sid.get(key)); + EntityLog.log(context, EntityLog.Type.Protocol, "Server " + key + "=" + sid.get(key)); + } + Log.breadcrumb("server", crumb); } - Log.breadcrumb("server", crumb); + } catch (MessagingException ex) { + Log.w(ex); + // Check for 'User is authenticated but not connected' + if (require_id) + throw ex; } - } catch (MessagingException ex) { - Log.w(ex); - // Check for 'User is authenticated but not connected' - if (require_id) - throw ex; - } - // Verizon - // https://senders.yahooinc.com/developer/documentation/#imap-modes-limited - // https://www.ietf.org/archive/id/draft-melnikov-imap-uidonly-00.html - // https://answers.microsoft.com/en-us/outlook_com/forum/all/why-is-an-imap-inbox-only-displaying-10000-items/6d15de5f-9047-4b41-9b58-1d8345bbd002 - if (false && istore.hasCapability("X-UIDONLY") && istore.hasCapability("ENABLE")) - try { - istore.enable("X-UIDONLY"); - } catch (ProtocolException ex) { - Log.e(ex); - } + // Verizon + // https://senders.yahooinc.com/developer/documentation/#imap-modes-limited + // https://www.ietf.org/archive/id/draft-melnikov-imap-uidonly-00.html + // https://answers.microsoft.com/en-us/outlook_com/forum/all/why-is-an-imap-inbox-only-displaying-10000-items/6d15de5f-9047-4b41-9b58-1d8345bbd002 + if (false && istore.hasCapability("X-UIDONLY") && istore.hasCapability("ENABLE")) + try { + istore.enable("X-UIDONLY"); + } catch (ProtocolException ex) { + Log.e(ex); + } + } } else if ("smtp".equals(protocol) || "smtps".equals(protocol)) { // https://tools.ietf.org/html/rfc5321#section-4.1.3 @@ -959,22 +962,23 @@ public class EmailService implements AutoCloseable { Log.i("Using localhost=" + properties.getProperty("mail." + protocol + ".localhost")); iservice = isession.getTransport(protocol); - try { - iservice.connect(address.getHostAddress(), port, user, null); - } catch (MessagingException ex) { - if (ehlo == null && ConnectionHelper.isSyntacticallyInvalid(ex)) { - properties.put("mail." + protocol + ".localhost", useip ? hdomain : haddr); - Log.i("Fallback localhost=" + properties.getProperty("mail." + protocol + ".localhost")); - try { - iservice.connect(address.getHostAddress(), port, user, null); - } catch (MessagingException ex1) { - if (ConnectionHelper.isSyntacticallyInvalid(ex1)) - Log.e("Used localhost=" + haddr + "/" + hdomain); - throw ex1; - } - } else - throw ex; - } + if (!EntityAccount.isTestAccount(user)) + try { + iservice.connect(address.getHostAddress(), port, user, null); + } catch (MessagingException ex) { + if (ehlo == null && ConnectionHelper.isSyntacticallyInvalid(ex)) { + properties.put("mail." + protocol + ".localhost", useip ? hdomain : haddr); + Log.i("Fallback localhost=" + properties.getProperty("mail." + protocol + ".localhost")); + try { + iservice.connect(address.getHostAddress(), port, user, null); + } catch (MessagingException ex1) { + if (ConnectionHelper.isSyntacticallyInvalid(ex1)) + Log.e("Used localhost=" + haddr + "/" + hdomain); + throw ex1; + } + } else + throw ex; + } } else throw new NoSuchProviderException(protocol); } diff --git a/app/src/main/java/eu/faircode/email/EntityAccount.java b/app/src/main/java/eu/faircode/email/EntityAccount.java index 35eb3382ef..f66621c4b3 100644 --- a/app/src/main/java/eu/faircode/email/EntityAccount.java +++ b/app/src/main/java/eu/faircode/email/EntityAccount.java @@ -26,9 +26,11 @@ import android.app.NotificationManager; import android.content.Context; import android.content.SharedPreferences; import android.os.Build; +import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; +import androidx.fragment.app.Fragment; import androidx.preference.PreferenceManager; import androidx.room.ColumnInfo; import androidx.room.Entity; @@ -563,6 +565,66 @@ public class EntityAccount extends EntityOrder implements Serializable { }; } + static boolean isTestAccount(String user) { + return (user != null && user.endsWith("@demo.faircode.eu")); + } + + static EntityAccount getTestAccount(String user) { + EntityAccount account = new EntityAccount(); + account.name = "Test account"; + account.host = ""; + account.port = 0; + account.encryption = 0; + account.auth_type = ServiceAuthenticator.AUTH_TYPE_PASSWORD; + account.user = user; + account.password = ""; + account.synchronize = false; + account.primary = false; + return account; + } + + static void createTestUser(Fragment fragment, String user, Runnable ready) { + Bundle args = new Bundle(); + args.putString("user", user); + + new SimpleTask() { + @Override + protected Void onExecute(Context context, Bundle args) { + String user = args.getString("user"); + boolean sync = "test2".equals(UriHelper.getEmailUser(user)); + DB db = DB.getInstance(context); + EntityAccount account = EntityAccount.getTestAccount(user); + account.synchronize = sync; + account.id = db.account().insertAccount(account); + if (sync) { + EntityFolder folder = new EntityFolder(); + folder.account = account.id; + folder.name = "Inbox"; + folder.type = EntityFolder.INBOX; + folder.synchronize = false; + folder.sync_days = EntityFolder.DEFAULT_SYNC; + folder.keep_days = EntityFolder.DEFAULT_KEEP; + db.folder().insertFolder(folder); + + folder.name = context.getString(R.string.title_folder_local_drafts); + folder.type = EntityFolder.DRAFTS; + folder.local = true; + db.folder().insertFolder(folder); + } + return null; + } + + @Override + protected void onExecuted(Bundle args, Void data) { + ready.run(); + } + + @Override + protected void onException(Bundle args, Throwable ex) { + } + }.execute(fragment, args, "dummy"); + } + @NonNull @Override public String toString() { diff --git a/app/src/main/java/eu/faircode/email/EntityIdentity.java b/app/src/main/java/eu/faircode/email/EntityIdentity.java index 04669fd161..732d42b14e 100644 --- a/app/src/main/java/eu/faircode/email/EntityIdentity.java +++ b/app/src/main/java/eu/faircode/email/EntityIdentity.java @@ -21,9 +21,12 @@ package eu.faircode.email; import static androidx.room.ForeignKey.CASCADE; +import android.content.Context; +import android.os.Bundle; import android.text.TextUtils; import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; import androidx.room.ColumnInfo; import androidx.room.Entity; import androidx.room.ForeignKey; @@ -455,6 +458,49 @@ public class EntityIdentity { return (display == null ? name : display); } + static EntityIdentity getTestAccount(Long account, String user) { + EntityIdentity identity = new EntityIdentity(); + identity.account = account; + identity.name = "Test identity"; + identity.email = user; + identity.host = ""; + identity.port = 0; + identity.encryption = 0; + identity.auth_type = ServiceAuthenticator.AUTH_TYPE_PASSWORD; + identity.user = user; + identity.password = ""; + identity.synchronize = true; + identity.primary = false; + return identity; + } + + static void createTestUser(Fragment fragment, long account, String user, Runnable ready) { + Bundle args = new Bundle(); + args.putLong("account", account); + args.putString("user", user); + + new SimpleTask() { + @Override + protected Void onExecute(Context context, Bundle args) { + long account = args.getLong("account"); + String user = args.getString("user"); + DB db = DB.getInstance(context); + EntityIdentity identity = EntityIdentity.getTestAccount(account, user); + identity.id = db.identity().insertIdentity(identity); + return null; + } + + @Override + protected void onExecuted(Bundle args, Void data) { + ready.run(); + } + + @Override + protected void onException(Bundle args, Throwable ex) { + } + }.execute(fragment, args, "dummy"); + } + @NonNull @Override public String toString() { diff --git a/app/src/main/java/eu/faircode/email/FragmentAccount.java b/app/src/main/java/eu/faircode/email/FragmentAccount.java index 18bb6a9e7c..9c9fbf0566 100644 --- a/app/src/main/java/eu/faircode/email/FragmentAccount.java +++ b/app/src/main/java/eu/faircode/email/FragmentAccount.java @@ -792,6 +792,16 @@ public class FragmentAccount extends FragmentBase { } private void onCheck() { + if (EntityAccount.isTestAccount(etUser.getText().toString())) { + EntityAccount.createTestUser(this, etUser.getText().toString(), new Runnable() { + @Override + public void run() { + finish(); + } + }); + return; + } + int encryption; if (rgEncryption.getCheckedRadioButtonId() == R.id.radio_starttls) encryption = EmailService.ENCRYPTION_STARTTLS; diff --git a/app/src/main/java/eu/faircode/email/FragmentIdentity.java b/app/src/main/java/eu/faircode/email/FragmentIdentity.java index dba22f4fe3..102c2558dd 100644 --- a/app/src/main/java/eu/faircode/email/FragmentIdentity.java +++ b/app/src/main/java/eu/faircode/email/FragmentIdentity.java @@ -785,6 +785,16 @@ public class FragmentIdentity extends FragmentBase { private void onSave(boolean should) { EntityAccount account = (EntityAccount) spAccount.getSelectedItem(); + if (account != null && EntityAccount.isTestAccount(etUser.getText().toString())) { + EntityIdentity.createTestUser(this, account.id, etUser.getText().toString(), new Runnable() { + @Override + public void run() { + finish(); + } + }); + return; + } + String name = etName.getText().toString(); if (TextUtils.isEmpty(name)) { CharSequence hint = etName.getHint(); diff --git a/app/src/main/java/eu/faircode/email/FragmentOAuth.java b/app/src/main/java/eu/faircode/email/FragmentOAuth.java index 3a150b6573..afe6bc6ff1 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOAuth.java +++ b/app/src/main/java/eu/faircode/email/FragmentOAuth.java @@ -379,6 +379,16 @@ public class FragmentOAuth extends FragmentBase { String name = etName.getText().toString().trim(); String email = etEmail.getText().toString().trim(); + if (EntityAccount.isTestAccount(email)) { + EntityAccount.createTestUser(this, email, new Runnable() { + @Override + public void run() { + finish(); + } + }); + return; + } + if (TextUtils.isEmpty(name)) throw new IllegalArgumentException(getString(R.string.title_no_name)); diff --git a/app/src/main/java/eu/faircode/email/FragmentPop.java b/app/src/main/java/eu/faircode/email/FragmentPop.java index 1dddcf308a..260873efbc 100644 --- a/app/src/main/java/eu/faircode/email/FragmentPop.java +++ b/app/src/main/java/eu/faircode/email/FragmentPop.java @@ -473,6 +473,16 @@ public class FragmentPop extends FragmentBase { } private void onSave(boolean should) { + if (EntityAccount.isTestAccount(etUser.getText().toString())) { + EntityAccount.createTestUser(this, etUser.getText().toString(), new Runnable() { + @Override + public void run() { + finish(); + } + }); + return; + } + Bundle args = new Bundle(); args.putLong("id", id); diff --git a/app/src/main/java/eu/faircode/email/ServiceSend.java b/app/src/main/java/eu/faircode/email/ServiceSend.java index 4dd71d721a..9ca6acf267 100644 --- a/app/src/main/java/eu/faircode/email/ServiceSend.java +++ b/app/src/main/java/eu/faircode/email/ServiceSend.java @@ -672,6 +672,11 @@ public class ServiceSend extends ServiceBase implements SharedPreferences.OnShar throw new IllegalArgumentException("Message body missing"); EntityAccount account = db.account().getAccount(message.account); + if (EntityAccount.isTestAccount(account.user)){ + db.operation().deleteOperation(operation.id); + db.message().deleteMessage(message.id); + return; + } EntityIdentity ident = db.identity().getIdentity(message.identity); if (ident == null) diff --git a/app/src/main/res/xml/providers.xml b/app/src/main/res/xml/providers.xml index be9a15e086..c608dc1a50 100644 --- a/app/src/main/res/xml/providers.xml +++ b/app/src/main/res/xml/providers.xml @@ -864,7 +864,7 @@ starttls="false" /-->