diff --git a/app/src/main/java/eu/faircode/email/DaoMessage.java b/app/src/main/java/eu/faircode/email/DaoMessage.java index 3d0c8454f0..886f6028fd 100644 --- a/app/src/main/java/eu/faircode/email/DaoMessage.java +++ b/app/src/main/java/eu/faircode/email/DaoMessage.java @@ -456,9 +456,6 @@ public interface DaoMessage { @Query("UPDATE message SET error = :error WHERE id = :id") int setMessageError(long id, String error); - @Query("UPDATE message SET signature = :signature WHERE id = :id") - int setMessageSignature(long id, boolean signature); - @Query("UPDATE message SET revision = :revision WHERE id = :id") int setMessageRevision(long id, Integer revision); diff --git a/app/src/main/java/eu/faircode/email/FragmentCompose.java b/app/src/main/java/eu/faircode/email/FragmentCompose.java index ca550513a8..afc6fdd954 100644 --- a/app/src/main/java/eu/faircode/email/FragmentCompose.java +++ b/app/src/main/java/eu/faircode/email/FragmentCompose.java @@ -412,33 +412,7 @@ public class FragmentCompose extends FragmentBase { cbSignature.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { - Bundle args = new Bundle(); - args.putLong("id", working); - args.putBoolean("signature", checked); - - new SimpleTask() { - @Override - protected Integer onExecute(Context context, Bundle args) { - long id = args.getLong("id"); - boolean signature = args.getBoolean("signature"); - - DB db = DB.getInstance(context); - return db.message().setMessageSignature(id, signature); - } - - @Override - protected void onExecuted(Bundle args, Integer count) { - if (count > 0) { - boolean signature = args.getBoolean("signature"); - tvSignature.setAlpha(signature ? 1.0f : Helper.LOW_LIGHT); - } - } - - @Override - protected void onException(Bundle args, Throwable ex) { - Helper.unexpectedError(getParentFragmentManager(), ex); - } - }.execute(FragmentCompose.this, args, "draft:signature"); + onAction(R.id.action_save); } }); @@ -723,15 +697,12 @@ public class FragmentCompose extends FragmentBase { String text = HtmlHelper.getText(ref.outerHtml()); Element p = document.createElement("p"); p.html(text.replaceAll("\\r?\\n", "
")); - if (document.body() != null) - document.body().appendChild(p); + document.body().appendChild(p); } else { Document d = HtmlHelper.sanitize(context, ref.outerHtml(), true, false); Element b = d.body(); - if (document.body() != null && b != null) { - b.tagName("div"); - document.body().appendChild(b); - } + b.tagName("div"); + document.body().appendChild(b); } return document.html(); @@ -1908,6 +1879,7 @@ public class FragmentCompose extends FragmentBase { args.putString("bcc", etBcc.getText().toString().trim()); args.putString("subject", etSubject.getText().toString().trim()); args.putString("body", HtmlHelper.toHtml(etBody.getText())); + args.putBoolean("signature", cbSignature.isChecked()); args.putBoolean("empty", isEmpty()); args.putBundle("extras", extras); @@ -2144,8 +2116,6 @@ public class FragmentCompose extends FragmentBase { EntityMessage ref = db.message().getMessage(reference); - Document document = JsoupEx.parse(""); - data.draft = new EntityMessage(); data.draft.msgid = EntityMessage.generateMessageId(); @@ -2156,6 +2126,100 @@ public class FragmentCompose extends FragmentBase { if (receipt_default) data.draft.receipt_request = true; + // Select identity matching from address + EntityIdentity selected = null; + long aid = args.getLong("account", -1); + long iid = args.getLong("identity", -1); + + if (aid < 0 && ref != null) + aid = ref.account; + if (iid < 0 && ref != null && ref.identity != null) + iid = ref.identity; + + if (iid >= 0) + for (EntityIdentity identity : data.identities) + if (identity.id.equals(iid)) { + Log.i("Selected requested identity=" + iid); + selected = identity; + break; + } + + if (data.draft.from != null && data.draft.from.length > 0) { + if (selected == null) + for (Address sender : data.draft.from) + for (EntityIdentity identity : data.identities) + if (identity.account.equals(aid) && + identity.sameAddress(sender)) { + selected = identity; + Log.i("Selected same account/identity"); + break; + } + + if (selected == null) + for (Address sender : data.draft.from) + for (EntityIdentity identity : data.identities) + if (identity.account.equals(aid) && + identity.similarAddress(sender)) { + selected = identity; + Log.i("Selected similar account/identity"); + break; + } + + if (selected == null) + for (Address sender : data.draft.from) + for (EntityIdentity identity : data.identities) + if (identity.sameAddress(sender)) { + selected = identity; + Log.i("Selected same */identity"); + break; + } + + if (selected == null) + for (Address sender : data.draft.from) + for (EntityIdentity identity : data.identities) + if (identity.similarAddress(sender)) { + selected = identity; + Log.i("Selected similer */identity"); + break; + } + } + + if (selected == null) + for (EntityIdentity identity : data.identities) + if (identity.account.equals(aid) && identity.primary) { + selected = identity; + Log.i("Selected primary account/identity"); + break; + } + + if (selected == null) + for (EntityIdentity identity : data.identities) + if (identity.account.equals(aid)) { + selected = identity; + Log.i("Selected account/identity"); + break; + } + + if (selected == null) + for (EntityIdentity identity : data.identities) + if (identity.primary) { + Log.i("Selected primary */identity"); + selected = identity; + break; + } + + if (selected == null) + for (EntityIdentity identity : data.identities) { + Log.i("Selected */identity"); + selected = identity; + break; + } + + if (selected == null) + throw new IllegalArgumentException(context.getString(R.string.title_no_identities)); + + Document document = Document.createShell(""); + if (ref == null) { data.draft.thread = data.draft.msgid; @@ -2185,10 +2249,8 @@ public class FragmentCompose extends FragmentBase { if (!TextUtils.isEmpty(b)) { Document d = HtmlHelper.sanitize(context, b, false, false); Element e = d.body(); - if (e != null) { - e.tagName("div"); - document.body().appendChild(e); - } + e.tagName("div"); + document.body().appendChild(e); } if (answer > 0) { @@ -2197,12 +2259,12 @@ public class FragmentCompose extends FragmentBase { data.draft.subject = a.name; Document d = JsoupEx.parse(a.getText(null)); Element e = d.body(); - if (e != null) { - e.tagName("div"); - document.body().appendChild(e); - } + e.tagName("div"); + document.body().appendChild(e); } } + + addSignature(document, data.draft, selected); } else { // Actions: // - reply @@ -2270,10 +2332,8 @@ public class FragmentCompose extends FragmentBase { String html = Helper.readText(ref.getFile(context)); Document d = HtmlHelper.sanitize(context, html, true, false); Element e = d.body(); - if (e != null) { - e.tagName("div"); - document.body().appendChild(e); - } + e.tagName("div"); + document.body().appendChild(e); } } else if ("list".equals(action)) { data.draft.subject = ref.subject; @@ -2306,10 +2366,8 @@ public class FragmentCompose extends FragmentBase { if (a != null) { Document d = JsoupEx.parse(a.getText(data.draft.to)); Element e = d.body(); - if (e != null) { - e.tagName("div"); - document.body().appendChild(e); - } + e.tagName("div"); + document.body().appendChild(e); } } @@ -2381,109 +2439,17 @@ public class FragmentCompose extends FragmentBase { // Quote referenced message body Element e = d.body(); - if (e != null) { - boolean quote_reply = prefs.getBoolean("quote_reply", true); - boolean quote = (quote_reply && ("reply".equals(action) || "reply_all".equals(action))); + boolean quote_reply = prefs.getBoolean("quote_reply", true); + boolean quote = (quote_reply && ("reply".equals(action) || "reply_all".equals(action))); - e.tagName(quote ? "blockquote" : "div"); - div.appendChild(e); - } + e.tagName(quote ? "blockquote" : "div"); + div.appendChild(e); document.body().appendChild(div); - } - } - - // Select identity matching from address - EntityIdentity selected = null; - long aid = args.getLong("account", -1); - long iid = args.getLong("identity", -1); - - if (aid < 0 && ref != null) - aid = ref.account; - if (iid < 0 && ref != null && ref.identity != null) - iid = ref.identity; - - if (iid >= 0) - for (EntityIdentity identity : data.identities) - if (identity.id.equals(iid)) { - Log.i("Selected requested identity=" + iid); - selected = identity; - break; - } - - if (data.draft.from != null && data.draft.from.length > 0) { - if (selected == null) - for (Address sender : data.draft.from) - for (EntityIdentity identity : data.identities) - if (identity.account.equals(aid) && - identity.sameAddress(sender)) { - selected = identity; - Log.i("Selected same account/identity"); - break; - } - - if (selected == null) - for (Address sender : data.draft.from) - for (EntityIdentity identity : data.identities) - if (identity.account.equals(aid) && - identity.similarAddress(sender)) { - selected = identity; - Log.i("Selected similar account/identity"); - break; - } - - if (selected == null) - for (Address sender : data.draft.from) - for (EntityIdentity identity : data.identities) - if (identity.sameAddress(sender)) { - selected = identity; - Log.i("Selected same */identity"); - break; - } - - if (selected == null) - for (Address sender : data.draft.from) - for (EntityIdentity identity : data.identities) - if (identity.similarAddress(sender)) { - selected = identity; - Log.i("Selected similer */identity"); - break; - } - } - - if (selected == null) - for (EntityIdentity identity : data.identities) - if (identity.account.equals(aid) && identity.primary) { - selected = identity; - Log.i("Selected primary account/identity"); - break; - } - - if (selected == null) - for (EntityIdentity identity : data.identities) - if (identity.account.equals(aid)) { - selected = identity; - Log.i("Selected account/identity"); - break; - } - if (selected == null) - for (EntityIdentity identity : data.identities) - if (identity.primary) { - Log.i("Selected primary */identity"); - selected = identity; - break; - } - - if (selected == null) - for (EntityIdentity identity : data.identities) { - Log.i("Selected */identity"); - selected = identity; - break; + addSignature(document, data.draft, selected); } - - if (selected == null) - throw new IllegalArgumentException(context.getString(R.string.title_no_identities)); + } EntityFolder drafts = db.folder().getFolderByType(selected.account, EntityFolder.DRAFTS); if (drafts == null) @@ -2594,6 +2560,7 @@ public class FragmentCompose extends FragmentBase { File file = data.draft.getFile(context); Document doc = JsoupEx.parse(Helper.readText(file)); + doc.select("div[fairemail=signature]").remove(); Elements ref = doc.select("div[fairemail=reference]"); ref.remove(); @@ -2604,8 +2571,14 @@ public class FragmentCompose extends FragmentBase { } Document document = HtmlHelper.sanitize(context, doc.html(), true, false); + + if (data.draft.identity != null) { + EntityIdentity identity = db.identity().getIdentity(data.draft.identity); + addSignature(document, data.draft, identity); + } + for (Element e : ref) - document.appendChild(e); + document.body().appendChild(e); String html = JsoupEx.parse(document.html()).html(); Helper.writeText(file, html); @@ -2808,6 +2781,7 @@ public class FragmentCompose extends FragmentBase { String bcc = args.getString("bcc"); String subject = args.getString("subject"); String body = args.getString("body"); + boolean signature = args.getBoolean("signature"); boolean empty = args.getBoolean("empty"); Bundle extras = args.getBundle("extras"); @@ -2956,6 +2930,7 @@ public class FragmentCompose extends FragmentBase { !MessageHelper.equal(draft.cc, acc) || !MessageHelper.equal(draft.bcc, abcc) || !Objects.equals(draft.subject, subject) || + !draft.signature.equals(signature) || last_available != available); last_available = available; @@ -2969,6 +2944,7 @@ public class FragmentCompose extends FragmentBase { draft.cc = acc; draft.bcc = abcc; draft.subject = subject; + draft.signature = signature; draft.sender = MessageHelper.getSortKey(draft.from); Uri lookupUri = ContactInfo.getLookupUri(context, draft.from); draft.avatar = (lookupUri == null ? null : lookupUri.toString()); @@ -2981,6 +2957,7 @@ public class FragmentCompose extends FragmentBase { (extras != null && extras.containsKey("html"))) { dirty = true; + doc.select("div[fairemail=signature]").remove(); Elements ref = doc.select("div[fairemail=reference]"); ref.remove(); @@ -2989,15 +2966,17 @@ public class FragmentCompose extends FragmentBase { if (extras != null && extras.containsKey("html")) { // Save current revision Document c = JsoupEx.parse(body); - if (c.body() != null && ref.size() > 0) - c.body().appendChild(ref.first()); + addSignature(c, draft, identity); + for (Element e : ref) + c.body().appendChild(e); Helper.writeText(draft.getFile(context, draft.revision), c.html()); d = JsoupEx.parse(extras.getString("html")); } else { d = JsoupEx.parse(body); - if (d.body() != null && ref.size() > 0) - d.body().appendChild(ref.first()); + addSignature(d, draft, identity); + for (Element e : ref) + d.body().appendChild(e); } body = d.html(); @@ -3273,6 +3252,28 @@ public class FragmentCompose extends FragmentBase { return subject; } + private void addSignature(Document document, EntityMessage message, EntityIdentity identity) { + if (!message.signature || + identity == null || TextUtils.isEmpty(identity.signature)) + return; + + Element div = document.createElement("div"); + div.attr("fairemail", "signature"); + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); + boolean usenet = prefs.getBoolean("usenet_signature", false); + if (usenet) { + // https://www.ietf.org/rfc/rfc3676.txt + Element span = document.createElement("span"); + span.text("-- "); + span.appendElement("br"); + div.appendChild(span); + } + + div.append(identity.signature); + document.body().appendChild(div); + } + private void showDraft(final EntityMessage draft) { Bundle args = new Bundle(); args.putLong("id", draft.id); @@ -3314,6 +3315,7 @@ public class FragmentCompose extends FragmentBase { throw new IllegalArgumentException(context.getString(R.string.title_no_body)); Document doc = JsoupEx.parse(Helper.readText(draft.getFile(context))); + doc.select("div[fairemail=signature]").remove(); Elements ref = doc.select("div[fairemail=reference]"); ref.remove(); diff --git a/app/src/main/java/eu/faircode/email/FragmentMessages.java b/app/src/main/java/eu/faircode/email/FragmentMessages.java index de6a045c5d..d7e6a4c7eb 100644 --- a/app/src/main/java/eu/faircode/email/FragmentMessages.java +++ b/app/src/main/java/eu/faircode/email/FragmentMessages.java @@ -4637,63 +4637,60 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. Document document = JsoupEx.parse(html); HtmlHelper.embedInlineImages(context, id, document); - Element body = document.body(); - if (body != null) { - Element p = document.createElement("p"); - - if (message.from != null && message.from.length > 0) { - Element span = document.createElement("span"); - Element strong = document.createElement("strong"); - strong.text(getString(R.string.title_from)); - span.appendChild(strong); - span.appendText(" " + MessageHelper.formatAddresses(message.from)); - span.appendElement("br"); - p.appendChild(span); - } + Element p = document.createElement("p"); + + if (message.from != null && message.from.length > 0) { + Element span = document.createElement("span"); + Element strong = document.createElement("strong"); + strong.text(getString(R.string.title_from)); + span.appendChild(strong); + span.appendText(" " + MessageHelper.formatAddresses(message.from)); + span.appendElement("br"); + p.appendChild(span); + } - if (message.to != null && message.to.length > 0) { - Element span = document.createElement("span"); - Element strong = document.createElement("strong"); - strong.text(getString(R.string.title_to)); - span.appendChild(strong); - span.appendText(" " + MessageHelper.formatAddresses(message.to)); - span.appendElement("br"); - p.appendChild(span); - } + if (message.to != null && message.to.length > 0) { + Element span = document.createElement("span"); + Element strong = document.createElement("strong"); + strong.text(getString(R.string.title_to)); + span.appendChild(strong); + span.appendText(" " + MessageHelper.formatAddresses(message.to)); + span.appendElement("br"); + p.appendChild(span); + } - if (message.cc != null && message.cc.length > 0) { - Element span = document.createElement("span"); - Element strong = document.createElement("strong"); - strong.text(getString(R.string.title_cc)); - span.appendChild(strong); - span.appendText(" " + MessageHelper.formatAddresses(message.cc)); - span.appendElement("br"); - p.appendChild(span); - } + if (message.cc != null && message.cc.length > 0) { + Element span = document.createElement("span"); + Element strong = document.createElement("strong"); + strong.text(getString(R.string.title_cc)); + span.appendChild(strong); + span.appendText(" " + MessageHelper.formatAddresses(message.cc)); + span.appendElement("br"); + p.appendChild(span); + } - { - DateFormat DTF = Helper.getDateTimeInstance(context, SimpleDateFormat.LONG, SimpleDateFormat.LONG); + { + DateFormat DTF = Helper.getDateTimeInstance(context, SimpleDateFormat.LONG, SimpleDateFormat.LONG); - Element span = document.createElement("span"); - Element strong = document.createElement("strong"); - strong.text(getString(R.string.title_received)); - span.appendChild(strong); - span.appendText(" " + DTF.format(message.received)); - span.appendElement("br"); - p.appendChild(span); - } + Element span = document.createElement("span"); + Element strong = document.createElement("strong"); + strong.text(getString(R.string.title_received)); + span.appendChild(strong); + span.appendText(" " + DTF.format(message.received)); + span.appendElement("br"); + p.appendChild(span); + } - if (!TextUtils.isEmpty(message.subject)) { - Element span = document.createElement("span"); - span.appendText(message.subject); - span.appendElement("br"); - p.appendChild(span); - } + if (!TextUtils.isEmpty(message.subject)) { + Element span = document.createElement("span"); + span.appendText(message.subject); + span.appendElement("br"); + p.appendChild(span); + } - p.appendElement("hr").appendElement("br"); + p.appendElement("hr").appendElement("br"); - body.prependChild(p); - } + document.prependChild(p); return new String[]{message.subject, document.html()}; } diff --git a/app/src/main/java/eu/faircode/email/HtmlHelper.java b/app/src/main/java/eu/faircode/email/HtmlHelper.java index a1566a83b1..1071ad498c 100644 --- a/app/src/main/java/eu/faircode/email/HtmlHelper.java +++ b/app/src/main/java/eu/faircode/email/HtmlHelper.java @@ -86,10 +86,10 @@ public class HtmlHelper { } catch (Throwable ex) { // OutOfMemoryError Log.e(ex); - Document document = new Document(""); + Document document = Document.createShell(""); Element strong = document.createElement("strong"); strong.text(Helper.formatThrowable(ex)); - document.appendChild(strong); + document.body().appendChild(strong); return document; } } @@ -476,6 +476,11 @@ public class HtmlHelper { if (!TextUtils.isEmpty(span.attr("color"))) span.tagName("font"); + if (document.body() == null) { + Log.e("Sanitize without body"); + document.normalise(); + } + return document; } diff --git a/app/src/main/java/eu/faircode/email/MessageHelper.java b/app/src/main/java/eu/faircode/email/MessageHelper.java index 446c40d8de..abe1d856ff 100644 --- a/app/src/main/java/eu/faircode/email/MessageHelper.java +++ b/app/src/main/java/eu/faircode/email/MessageHelper.java @@ -20,19 +20,14 @@ package eu.faircode.email; */ import android.content.Context; -import android.content.SharedPreferences; import android.net.MailTo; import android.net.Uri; import android.text.TextUtils; -import androidx.preference.PreferenceManager; - import com.sun.mail.util.FolderClosedIOException; import com.sun.mail.util.MessageRemovedIOException; import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; import java.io.BufferedReader; import java.io.File; @@ -322,28 +317,10 @@ public class MessageHelper { // Build html body Document document = JsoupEx.parse(Helper.readText(message.getFile(context))); - Elements ref = document.select("div[fairemail=reference]"); - ref.remove(); - ref.removeAttr("fairemail"); - - if (document.body() != null) { - // When sending message - if (identity != null && !TextUtils.isEmpty(identity.signature) && message.signature) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - boolean usenet = prefs.getBoolean("usenet_signature", false); - if (usenet) { - // https://www.ietf.org/rfc/rfc3676.txt - Element span = document.createElement("span"); - span.text("-- "); - span.appendElement("br"); - document.body().appendChild(span); - } - document.body().append(identity.signature); - } - if (ref.size() > 0) - document.body().appendChild(ref.first()); - } + // When sending message + if (identity != null) + document.select("div[fairemail=signature],div[fairemail=reference]").removeAttr("fairemail"); // multipart/mixed // multipart/related