Bring back polling

This commit is contained in:
M66B 2018-09-21 17:19:02 +00:00
parent 5cca576e28
commit 9cafc1223d
7 changed files with 83 additions and 55 deletions

12
FAQ.md
View File

@ -49,13 +49,13 @@ See also [this FAQ](#FAQ16).
Valid security certificates are officially signed (not self signed) and have matching a host name.
<a name="FAQ5"></a>
**(5) What does 'no IDLE support' mean?**
~~**(5) What does 'no IDLE support' mean?**~~
Without [IMAP IDLE](https://en.wikipedia.org/wiki/IMAP_IDLE) emails need to be periodically fetched,
which is a waste of battery power and internet bandwidth and will delay notification of new emails.
Since the goal of FairEmail is to offer safe and fast email, providers without IMAP IDLE are not supported.
You should consider this a problem of the provider, not of the app.
Almost all email providers offer IMAP IDLE, with as notable exception Yahoo!
~~Without [IMAP IDLE](https://en.wikipedia.org/wiki/IMAP_IDLE) emails need to be periodically fetched,~~
~~which is a waste of battery power and internet bandwidth and will delay notification of new emails.~~
~~Since the goal of FairEmail is to offer safe and fast email, providers without IMAP IDLE are not supported.~~
~~You should consider this a problem of the provider, not of the app.~~
~~Almost all email providers offer IMAP IDLE, with as notable exception Yahoo!~~
<a name="FAQ6"></a>
**(6) How can I login to Gmail / G suite?**

View File

@ -7,11 +7,6 @@ You'll need to add at least one account to receive email and at least one identi
An internet connection is required to add accounts and identities.
Your email provider should support IMAP with the IDLE and UIDPLUS extensions.
All up-to-date email providers do, with as notable exception Yahoo!
IMAP IDLE is required to limit battery usage,
see [this FAQ](https://github.com/M66B/open-source-email/blob/master/FAQ.md#FAQ5) for more details.
Your email provider should support secure connections.
If your provider doesn't support secure connections and you care at least a little about your privacy,
you are strongly advised to switch to another provider.

View File

@ -110,6 +110,7 @@ public class FragmentAccount extends FragmentEx {
private ImageButton ibPro;
private CheckBox cbSynchronize;
private CheckBox cbPrimary;
private EditText etInterval;
private Button btnCheck;
private ProgressBar pbCheck;
@ -173,6 +174,7 @@ public class FragmentAccount extends FragmentEx {
cbSynchronize = view.findViewById(R.id.cbSynchronize);
cbPrimary = view.findViewById(R.id.cbPrimary);
etInterval = view.findViewById(R.id.etInterval);
btnCheck = view.findViewById(R.id.btnCheck);
pbCheck = view.findViewById(R.id.pbCheck);
@ -429,9 +431,6 @@ public class FragmentAccount extends FragmentEx {
throw ex;
}
if (!istore.hasCapability("IDLE"))
throw new MessagingException(getContext().getString(R.string.title_no_idle));
if (!istore.hasCapability("UIDPLUS"))
throw new MessagingException(getContext().getString(R.string.title_no_uidplus));
@ -567,6 +566,7 @@ public class FragmentAccount extends FragmentEx {
args.putInt("color", color);
args.putString("signature", Html.toHtml(etSignature.getText()));
args.putBoolean("primary", cbPrimary.isChecked());
args.putString("interval", etInterval.getText().toString());
args.putParcelable("drafts", drafts);
args.putParcelable("sent", sent);
@ -588,6 +588,7 @@ public class FragmentAccount extends FragmentEx {
String signature = args.getString("signature");
boolean synchronize = args.getBoolean("synchronize");
boolean primary = args.getBoolean("primary");
String interval = args.getString("interval");
EntityFolder drafts = args.getParcelable("drafts");
EntityFolder sent = args.getParcelable("sent");
@ -603,6 +604,8 @@ public class FragmentAccount extends FragmentEx {
throw new Throwable(getContext().getString(R.string.title_no_user));
if (TextUtils.isEmpty(password))
throw new Throwable(getContext().getString(R.string.title_no_password));
if (TextUtils.isEmpty(interval))
interval = "9";
if (synchronize && drafts == null)
throw new Throwable(getContext().getString(R.string.title_no_drafts));
@ -653,7 +656,7 @@ public class FragmentAccount extends FragmentEx {
account.synchronize = synchronize;
account.primary = (account.synchronize && primary);
account.store_sent = false;
account.poll_interval = 9;
account.poll_interval = Integer.parseInt(interval);
if (!synchronize)
account.error = null;
@ -874,6 +877,7 @@ public class FragmentAccount extends FragmentEx {
cbSynchronize.setChecked(account == null ? true : account.synchronize);
cbPrimary.setChecked(account == null ? true : account.primary);
etInterval.setText(Long.toString(account == null ? 9 : account.poll_interval));
color = (account == null || account.color == null ? Color.TRANSPARENT : account.color);

View File

@ -642,6 +642,8 @@ public class ServiceSynchronize extends LifecycleService {
db.folder().setFolderState(folder.id, null);
db.account().setAccountState(account.id, "connecting");
Helper.connect(this, istore, account);
final boolean capIdle = istore.hasCapability("IDLE");
Log.i(Helper.TAG, account.name + " idle=" + capIdle);
db.account().setAccountState(account.id, "connected");
db.account().setAccountError(account.id, null);
@ -813,15 +815,18 @@ public class ServiceSynchronize extends LifecycleService {
try {
Thread.sleep(account.poll_interval * 60 * 1000L);
Log.i(Helper.TAG, folder.name + " request NOOP");
ifolder.doCommand(new IMAPFolder.ProtocolCommand() {
public Object doCommand(IMAPProtocol p) throws ProtocolException {
Log.i(Helper.TAG, ifolder.getName() + " start NOOP");
p.simpleCommand("NOOP", null);
Log.i(Helper.TAG, ifolder.getName() + " end NOOP");
return null;
}
});
if (capIdle) {
Log.i(Helper.TAG, folder.name + " request NOOP");
ifolder.doCommand(new IMAPFolder.ProtocolCommand() {
public Object doCommand(IMAPProtocol p) throws ProtocolException {
Log.i(Helper.TAG, ifolder.getName() + " start NOOP");
p.simpleCommand("NOOP", null);
Log.i(Helper.TAG, ifolder.getName() + " end NOOP");
return null;
}
});
} else
synchronizeMessages(account, folder, ifolder, state);
} catch (InterruptedException ex) {
Log.w(Helper.TAG, folder.name + " noop " + ex.toString());
@ -845,32 +850,34 @@ public class ServiceSynchronize extends LifecycleService {
noops.add(noop);
// Receive folder events
Thread idle = new Thread(new Runnable() {
@Override
public void run() {
try {
Log.i(Helper.TAG, folder.name + " start idle");
while (state.running && ifolder.isOpen()) {
//Log.i(Helper.TAG, folder.name + " do idle");
ifolder.idle(false);
//Log.i(Helper.TAG, folder.name + " done idle");
}
} catch (Throwable ex) {
Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
reportError(account.name, folder.name, ex);
if (capIdle) {
Thread idle = new Thread(new Runnable() {
@Override
public void run() {
try {
Log.i(Helper.TAG, folder.name + " start idle");
while (state.running && ifolder.isOpen()) {
Log.i(Helper.TAG, folder.name + " do idle");
ifolder.idle(false);
//Log.i(Helper.TAG, folder.name + " done idle");
}
} catch (Throwable ex) {
Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
reportError(account.name, folder.name, ex);
db.folder().setFolderError(folder.id, Helper.formatThrowable(ex));
db.folder().setFolderError(folder.id, Helper.formatThrowable(ex));
synchronized (state) {
state.notifyAll();
synchronized (state) {
state.notifyAll();
}
} finally {
Log.i(Helper.TAG, folder.name + " end idle");
}
} finally {
Log.i(Helper.TAG, folder.name + " end idle");
}
}
}, "sync.idle." + folder.id);
idle.start();
idlers.add(idle);
}, "sync.idle." + folder.id);
idle.start();
idlers.add(idle);
}
}
backoff = CONNECT_BACKOFF_START;

View File

@ -173,7 +173,6 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvUser" />
<!-- password -->
<TextView
@ -318,6 +317,29 @@
android:text="@string/title_primary_account"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbSynchronize" />
<!-- port -->
<TextView
android:id="@+id/tvInterval"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_poll_interval"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbPrimary" />
<EditText
android:id="@+id/etInterval"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="9"
android:inputType="number"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvInterval" />
<!-- check -->
<Button
@ -327,7 +349,7 @@
android:layout_marginTop="12dp"
android:text="@string/title_check"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbPrimary" />
app:layout_constraintTop_toBottomOf="@id/etInterval" />
<ProgressBar
android:id="@+id/pbCheck"
@ -347,7 +369,7 @@
android:layout_marginTop="12dp"
android:src="@drawable/baseline_delete_24"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbPrimary" />
app:layout_constraintTop_toBottomOf="@id/etInterval" />
<TextView
android:id="@+id/tvDrafts"
@ -498,7 +520,7 @@
android:id="@+id/grpAdvanced"
android:layout_width="0dp"
android:layout_height="0dp"
app:constraint_referenced_ids="tvName,etName,btnColor,vwColor,ibColorDefault,tvSignature,etSignature,ibPro,cbSynchronize,cbPrimary" />
app:constraint_referenced_ids="tvName,etName,btnColor,vwColor,ibColorDefault,tvSignature,etSignature,ibPro,cbSynchronize,cbPrimary,tvInterval,etInterval" />
<androidx.constraintlayout.widget.Group
android:id="@+id/grpFolders"

View File

@ -110,6 +110,7 @@
<string name="title_synchronize_identity">Synchronize (send messages)</string>
<string name="title_primary_account">Primary (default account)</string>
<string name="title_primary_identity">Primary (default identity)</string>
<string name="title_poll_interval">Poll interval (minutes)</string>
<string name="title_check">Check</string>
<string name="title_no_name">Name missing</string>
<string name="title_no_email">Email address missing</string>
@ -119,7 +120,6 @@
<string name="title_no_user">User name missing</string>
<string name="title_no_password">Password missing</string>
<string name="title_no_drafts">Drafts folder missing</string>
<string name="title_no_idle">IMAP IDLE not supported, see the FAQ</string>
<string name="title_no_uidplus">IMAP UIDPLUS not supported, see the FAQ</string>
<string name="title_account_delete">Delete this account permanently?</string>
<string name="title_identity_delete">Delete this identity permanently?</string>

View File

@ -36,7 +36,7 @@
starttls="false" />
</provider>
<!-- no IMAP IDLE -->
<!--provider
<provider
name="Yahoo!"
link="https://help.yahoo.com/kb/SLN4075.html">
<imap
@ -46,7 +46,7 @@
host="smtp.mail.yahoo.com"
port="465"
starttls="false" />
</provider-->
</provider>
<provider
name="Posteo.de"
link="https://posteo.de/en/help/how-do-i-set-up-posteo-in-an-email-client-pop3-imap-and-smtp">
@ -81,7 +81,7 @@
starttls="false" />
</provider>
<!-- no IMAP IDLE -->
<!--provider
<provider
name="SFR.fr"
link="https://assistance.sfr.fr/service-et-accessoire/sfr-mail/serveurs-messagerie-sfr.html">
<imap
@ -91,7 +91,7 @@
host="smtp.sfr.fr"
port="465"
starttls="false" />
</provider-->
</provider>
<provider
name="infomaniak"
link="https://www.infomaniak.com/fr/support/faq/1075/configurer-une-adresse-email-configuration-logiciel-de-messagerie-parametres-courrier">