Always move sent messages to the sent folder (if any)

This commit is contained in:
M66B 2019-01-19 14:35:17 +00:00
parent bd1c741f2e
commit fc87b37b20
7 changed files with 71 additions and 161 deletions

10
FAQ.md
View File

@ -68,7 +68,7 @@ FairEmail follows all the best practices for an email client as decribed in [thi
* [(4) How can I use an invalid security certificate / IMAP STARTTLS / an empty password?](#user-content-faq4)
* [(5) How can I customize the message view?](#user-content-faq5)
* [(6) How can I login to Gmail / G suite?](#user-content-faq6)
* [(7) Why are messages in the outbox not moved to the sent folder?](#user-content-faq7)
* [~~(7) Why are messages in the outbox not moved to the sent folder?~~](#user-content-faq7)
* [(8) Can I use a Microsoft Exchange account?](#user-content-faq8)
* [(9) What are identities?](#user-content-faq9)
* [(11) Why is POP not supported?](#user-content-faq11)
@ -246,13 +246,13 @@ If this doesn't work, see here for more solutions: [https://support.google.com/m
<br />
<a name="faq7"></a>
**(7) Why are messages in the outbox not moved to the sent folder?**
**~~(7) Why are messages in the outbox not moved to the sent folder?~~**
Messages in the outbox are moved to the sent folder as soon as your provider adds the message to the sent folder.
~~Messages in the outbox are moved to the sent folder as soon as your provider adds the message to the sent folder.
Note that this requires a sent folder to be selected and to be set to synchronizing.
If this doesn't happen, your provider might not keep track of sent messages or you might be using an SMTP server not related to the provider.
In these cases you can use the advanced identity setting *Store a copy of sent messages in* and select the sent folder.
There is a menu to move sent messages in the outbox to the sent folder.
There is a menu to move sent messages in the outbox to the sent folder.~~
<br />
@ -983,6 +983,8 @@ Messages shown dimmed are locally moved messages for which the move is not confi
This can happen when there is no connection with the server or when the messages are too old to be synchronized.
Eventually, these messages will be synchronized when the connection to the server is restored or will be deleted if they are too old to be synchronized.
Some providers don't store sent messages, in this case messages in the sent folder might never be synchronized.
You can view these messages, but you cannot move these messages again until the previous move has been confirmed by the server.
<br />

View File

@ -296,6 +296,9 @@ public interface DaoMessage {
@Query("UPDATE message SET ui_ignored = :ui_ignored WHERE id = :id")
int setMessageUiIgnored(long id, boolean ui_ignored);
@Query("UPDATE message SET sent = :sent WHERE id = :id")
int setMessageSent(long id, Long sent);
@Query("UPDATE message SET warning = :warning WHERE id = :id")
int setMessageWarning(long id, String warning);

View File

@ -81,7 +81,7 @@ public class EntityIdentity {
public Boolean read_receipt;
@NonNull
public Boolean store_sent = false; // obsolete
public Long sent_folder;
public Long sent_folder; // obsolete
public Boolean tbd;
public String state;
public String error;
@ -109,9 +109,6 @@ public class EntityIdentity {
json.put("bcc", bcc);
json.put("delivery_receipt", delivery_receipt);
json.put("read_receipt", read_receipt);
json.put("store_sent", store_sent);
if (sent_folder != null)
json.put("sent_folder", sent_folder);
// not state
// not error
return json;
@ -157,12 +154,6 @@ public class EntityIdentity {
else
identity.read_receipt = false;
if (json.has("store_sent"))
identity.store_sent = json.getBoolean("store_sent");
if (json.has("sent_folder"))
identity.sent_folder = json.getLong("sent_folder");
return identity;
}
@ -187,7 +178,6 @@ public class EntityIdentity {
(this.replyto == null ? other.replyto == null : this.replyto.equals(other.replyto)) &&
this.delivery_receipt.equals(other.delivery_receipt) &&
this.read_receipt.equals(other.read_receipt) &&
(this.sent_folder == null ? other.sent_folder == null : this.sent_folder.equals(other.sent_folder)) &&
(this.tbd == null ? other.tbd == null : this.tbd.equals(other.tbd)) &&
(this.state == null ? other.state == null : this.state.equals(other.state)) &&
(this.error == null ? other.error == null : this.error.equals(other.error)));

View File

@ -110,7 +110,6 @@ public class FragmentIdentity extends FragmentBase {
private EditText etBcc;
private CheckBox cbDeliveryReceipt;
private CheckBox cbReadReceipt;
private Spinner spSent;
private Button btnSave;
private ContentLoadingProgressBar pbSave;
@ -123,7 +122,6 @@ public class FragmentIdentity extends FragmentBase {
private long id = -1;
private int color = Color.TRANSPARENT;
private ArrayAdapter<EntityFolder> adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
@ -175,7 +173,6 @@ public class FragmentIdentity extends FragmentBase {
etBcc = view.findViewById(R.id.etBcc);
cbDeliveryReceipt = view.findViewById(R.id.cbDeliveryReceipt);
cbReadReceipt = view.findViewById(R.id.cbReadReceipt);
spSent = view.findViewById(R.id.spSent);
btnSave = view.findViewById(R.id.btnSave);
pbSave = view.findViewById(R.id.pbSave);
@ -233,13 +230,10 @@ public class FragmentIdentity extends FragmentBase {
etUser.setText(account.user);
tilPassword.getEditText().setText(account.password);
etRealm.setText(account.realm);
setFolders(account.id);
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
adapter.clear();
}
});
@ -407,10 +401,6 @@ public class FragmentIdentity extends FragmentBase {
}
});
adapter = new ArrayAdapter<>(getContext(), R.layout.spinner_item1, android.R.id.text1, new ArrayList<EntityFolder>());
adapter.setDropDownViewResource(R.layout.spinner_item1_dropdown);
spSent.setAdapter(adapter);
// Initialize
Helper.setViewsEnabled(view, false);
btnAutoConfig.setEnabled(false);
@ -502,7 +492,6 @@ public class FragmentIdentity extends FragmentBase {
args.putString("signature", Html.toHtml(etSignature.getText()));
args.putBoolean("synchronize", cbSynchronize.isChecked());
args.putBoolean("primary", cbPrimary.isChecked());
args.putSerializable("sent", (EntityFolder) spSent.getSelectedItem());
new SimpleTask<Void>() {
@Override
@ -546,7 +535,6 @@ public class FragmentIdentity extends FragmentBase {
String bcc = args.getString("bcc");
boolean delivery_receipt = args.getBoolean("delivery_receipt");
boolean read_receipt = args.getBoolean("read_receipt");
EntityFolder sent = (EntityFolder) args.getSerializable("sent");
if (TextUtils.isEmpty(name))
throw new IllegalArgumentException(context.getString(R.string.title_no_name));
@ -646,7 +634,7 @@ public class FragmentIdentity extends FragmentBase {
identity.delivery_receipt = delivery_receipt;
identity.read_receipt = read_receipt;
identity.store_sent = false;
identity.sent_folder = (sent == null ? null : sent.id);
identity.sent_folder = null;
identity.error = null;
if (identity.primary)
@ -838,7 +826,6 @@ public class FragmentIdentity extends FragmentBase {
// OAuth token could be updated
if (pos > 0 && accounts.get(pos).auth_type != Helper.AUTH_TYPE_PASSWORD)
tilPassword.getEditText().setText(accounts.get(pos).password);
setFolders(account.id);
break;
}
}
@ -941,64 +928,6 @@ public class FragmentIdentity extends FragmentBase {
vwColor.setBackground(border);
}
private void setFolders(long account) {
Bundle args = new Bundle();
args.putLong("account", account);
args.putLong("identity", id);
new SimpleTask<IdentityFolders>() {
@Override
protected IdentityFolders onExecute(Context context, Bundle args) {
long aid = args.getLong("account");
long iid = args.getLong("identity");
DB db = DB.getInstance(context);
IdentityFolders result = new IdentityFolders();
result.identity = db.identity().getIdentity(iid);
result.folders = db.folder().getFolders(aid);
if (result.folders != null) {
for (EntityFolder folder : result.folders)
folder.display = folder.getDisplayName(context);
EntityFolder.sort(context, result.folders);
}
return result;
}
@Override
protected void onExecuted(Bundle args, IdentityFolders result) {
EntityFolder none = new EntityFolder();
none.name = "-";
result.folders.add(0, none);
adapter.clear();
adapter.addAll(result.folders);
if (result.identity != null)
for (int pos = 0; pos < result.folders.size(); pos++) {
EntityFolder folder = result.folders.get(pos);
if (result.identity.store_sent) {
if (EntityFolder.SENT.equals(folder.type)) {
spSent.setSelection(pos);
break;
}
} else if (result.identity.sent_folder != null) {
if (result.identity.sent_folder.equals(folder.id)) {
spSent.setSelection(pos);
break;
}
}
}
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex);
}
}.execute(this, args, "identity:folders:get");
}
class IdentityFolders {
EntityIdentity identity;
List<EntityFolder> folders;

View File

@ -1790,51 +1790,62 @@ public class ServiceSynchronize extends LifecycleService {
db.identity().setIdentityState(ident.id, "connected");
// Send message
Address[] to = imessage.getAllRecipients();
itransport.sendMessage(imessage, to);
EntityLog.log(this, "Sent via " + ident.host + "/" + ident.user +
" to " + TextUtils.join(", ", to));
db.identity().setIdentityError(ident.id, null);
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.cancel("send", message.identity.intValue());
// Append replied/forwarded text
if (message.replying != null || message.forwarding != null) {
String html = message.read(this);
html += HtmlHelper.getQuote(this,
message.replying == null ? message.forwarding : message.replying, false);
message.write(this, html);
}
Long sid = null;
try {
db.beginTransaction();
// Append replied/forwarded text
String body = message.read(this);
if (message.replying != null || message.forwarding != null)
body += HtmlHelper.getQuote(this,
message.replying == null ? message.forwarding : message.replying, false);
// Message could be moved
message = db.message().getMessage(message.id);
EntityFolder sent = db.folder().getFolderByType(ident.account, EntityFolder.SENT);
if (sent != null) {
long id = message.id;
long folder = message.folder;
// Mark message as sent
// - will be moved to sent folder by synchronize message later
message.sent = imessage.getSentDate().getTime();
message.seen = true;
message.ui_seen = true;
message.error = null;
db.message().updateMessage(message);
message.id = null;
message.folder = sent.id;
message.seen = true;
message.ui_seen = true;
message.ui_hide = true;
message.ui_browsed = true; // prevent deleting on sync
message.error = null;
message.id = db.message().insertMessage(message);
message.write(this, body);
if (ident.store_sent || ident.sent_folder != null) {
EntityFolder sent;
if (ident.store_sent)
sent = db.folder().getFolderByType(ident.account, EntityFolder.SENT);
else
sent = db.folder().getFolder(ident.sent_folder);
if (sent != null) {
message.folder = sent.id;
message.uid = null;
db.message().updateMessage(message);
Log.i("Appending sent msgid=" + message.msgid);
EntityOperation.queue(this, db, message, EntityOperation.ADD); // Could already exist
sid = message.id;
message.id = id;
message.folder = folder;
message.seen = false;
message.ui_seen = false;
message.ui_browsed = false;
message.ui_hide = false;
}
Address[] to = imessage.getAllRecipients();
itransport.sendMessage(imessage, to);
EntityLog.log(this, "Sent via " + ident.host + "/" + ident.user +
" to " + TextUtils.join(", ", to));
try {
db.beginTransaction();
if (sid == null) {
db.message().setMessageSent(message.id, imessage.getSentDate().getTime());
db.message().setMessageSeen(message.id, true);
db.message().setMessageUiSeen(message.id, true);
db.message().setMessageError(message.id, null);
message.write(this, body);
} else {
db.message().setMessageSent(sid, imessage.getSentDate().getTime());
db.message().setMessageUiHide(sid, false);
db.message().deleteMessage(message.id);
//EntityOperation.queue(this, db, message, EntityOperation.ADD);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
if (message.replying != null) {
@ -1842,9 +1853,14 @@ public class ServiceSynchronize extends LifecycleService {
EntityOperation.queue(this, db, replying, EntityOperation.ANSWERED, true);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
db.identity().setIdentityError(ident.id, null);
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.cancel("send", message.identity.intValue());
} catch (Throwable ex) {
if (sid != null)
db.message().deleteMessage(sid);
throw ex;
}
} catch (MessagingException ex) {
if (ex instanceof SendFailedException) {

View File

@ -484,34 +484,6 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbReadReceipt" />
<TextView
android:id="@+id/tvSent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_store_copy"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvReceipt" />
<Spinner
android:id="@+id/spSent"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvSent" />
<TextView
android:id="@+id/tvSentHint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/title_identity_sent_hint"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="italic"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/spSent" />
<Button
android:id="@+id/btnSave"
android:layout_width="wrap_content"
@ -519,7 +491,7 @@
android:layout_marginTop="12dp"
android:text="@string/title_save"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvSentHint" />
app:layout_constraintTop_toBottomOf="@id/tvReceipt" />
<eu.faircode.email.ContentLoadingProgressBar
android:id="@+id/pbSave"

View File

@ -194,7 +194,6 @@
<string name="title_authorize">Select account</string>
<string name="title_authorizing">Authorizing account &#8230;</string>
<string name="title_setup_advanced">Advanced</string>
<string name="title_store_copy">Store a copy of sent messages in:</string>
<string name="title_synchronize_account">Synchronize (receive messages)</string>
<string name="title_synchronize_identity">Synchronize (send messages)</string>
<string name="title_primary_account">Primary (default account)</string>
@ -214,7 +213,6 @@
<string name="title_account_delete">Delete this account permanently?</string>
<string name="title_identity_delete">Delete this identity permanently?</string>
<string name="title_pop">POP is not supported</string>
<string name="title_identity_sent_hint">Sent messages will automatically be stored in the sent folder already in most cases</string>
<string name="title_edit_html">Edit as HTML</string>
<string name="title_unseen_count" translatable="false">%1$s (%2$d)</string>