Browse Source

Store messages in files

main
M66B 5 years ago
parent
commit
d884c9c7ec
12 changed files with 185 additions and 107 deletions
  1. +8
    -14
      app/schemas/eu.faircode.email.DB/1.json
  2. +3
    -1
      app/src/main/java/eu/faircode/email/ActivityView.java
  3. +39
    -43
      app/src/main/java/eu/faircode/email/AdapterAttachment.java
  4. +1
    -1
      app/src/main/java/eu/faircode/email/DB.java
  5. +3
    -2
      app/src/main/java/eu/faircode/email/EntityAttachment.java
  6. +55
    -2
      app/src/main/java/eu/faircode/email/EntityMessage.java
  7. +12
    -4
      app/src/main/java/eu/faircode/email/FragmentAbout.java
  8. +33
    -11
      app/src/main/java/eu/faircode/email/FragmentCompose.java
  9. +18
    -3
      app/src/main/java/eu/faircode/email/FragmentMessage.java
  10. +6
    -9
      app/src/main/java/eu/faircode/email/MessageHelper.java
  11. +5
    -6
      app/src/main/java/eu/faircode/email/ServiceSynchronize.java
  12. +2
    -11
      app/src/main/res/layout/item_attachment.xml

+ 8
- 14
app/schemas/eu.faircode.email.DB/1.json View File

@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "23016f9b3ae09175ada077c837687ab6",
"identityHash": "cd3cf378d6f71c13ba8beb38a8bf58cf",
"entities": [
{
"tableName": "identity",
@ -313,7 +313,7 @@
},
{
"tableName": "message",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `account` INTEGER, `folder` INTEGER NOT NULL, `identity` INTEGER, `replying` INTEGER, `uid` INTEGER, `msgid` TEXT, `references` TEXT, `inreplyto` TEXT, `thread` TEXT, `from` TEXT, `to` TEXT, `cc` TEXT, `bcc` TEXT, `reply` TEXT, `subject` TEXT, `body` TEXT, `sent` INTEGER, `received` INTEGER NOT NULL, `stored` INTEGER NOT NULL, `seen` INTEGER NOT NULL, `ui_seen` INTEGER NOT NULL, `ui_hide` INTEGER NOT NULL, `error` TEXT, FOREIGN KEY(`account`) REFERENCES `account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`folder`) REFERENCES `folder`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`identity`) REFERENCES `identity`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`replying`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `account` INTEGER, `folder` INTEGER NOT NULL, `identity` INTEGER, `replying` INTEGER, `uid` INTEGER, `msgid` TEXT, `references` TEXT, `inreplyto` TEXT, `thread` TEXT, `from` TEXT, `to` TEXT, `cc` TEXT, `bcc` TEXT, `reply` TEXT, `subject` TEXT, `sent` INTEGER, `received` INTEGER NOT NULL, `stored` INTEGER NOT NULL, `seen` INTEGER NOT NULL, `ui_seen` INTEGER NOT NULL, `ui_hide` INTEGER NOT NULL, `error` TEXT, FOREIGN KEY(`account`) REFERENCES `account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`folder`) REFERENCES `folder`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`identity`) REFERENCES `identity`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`replying`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
@ -411,12 +411,6 @@
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "body",
"columnName": "body",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "sent",
"columnName": "sent",
@ -599,7 +593,7 @@
},
{
"tableName": "attachment",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `message` INTEGER NOT NULL, `sequence` INTEGER NOT NULL, `name` TEXT, `type` TEXT NOT NULL, `size` INTEGER, `progress` INTEGER, `filename` TEXT, FOREIGN KEY(`message`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `message` INTEGER NOT NULL, `sequence` INTEGER NOT NULL, `name` TEXT, `type` TEXT NOT NULL, `size` INTEGER, `progress` INTEGER, `available` INTEGER NOT NULL, FOREIGN KEY(`message`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
@ -644,10 +638,10 @@
"notNull": false
},
{
"fieldPath": "filename",
"columnName": "filename",
"affinity": "TEXT",
"notNull": false
"fieldPath": "available",
"columnName": "available",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
@ -782,7 +776,7 @@
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"23016f9b3ae09175ada077c837687ab6\")"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"cd3cf378d6f71c13ba8beb38a8bf58cf\")"
]
}
}

+ 3
- 1
app/src/main/java/eu/faircode/email/ActivityView.java View File

@ -225,6 +225,8 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack
file.delete();
String body = "<pre>" + sb.toString().replaceAll("\\r?\\n", "<br />") + "</pre>";
EntityMessage draft = null;
DB db = DB.getInstance(context);
@ -239,12 +241,12 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack
draft.msgid = EntityMessage.generateMessageId();
draft.to = new Address[]{Helper.myAddress()};
draft.subject = context.getString(R.string.app_name) + " crash log";
draft.body = "<pre>" + sb.toString().replaceAll("\\r?\\n", "<br />") + "</pre>";
draft.received = new Date().getTime();
draft.seen = false;
draft.ui_seen = false;
draft.ui_hide = false;
draft.id = db.message().insertMessage(draft);
draft.write(context, body);
}
EntityOperation.queue(db, draft, EntityOperation.ADD);


+ 39
- 43
app/src/main/java/eu/faircode/email/AdapterAttachment.java View File

@ -64,7 +64,6 @@ public class AdapterAttachment extends RecyclerView.Adapter<AdapterAttachment.Vi
TextView tvSize;
ImageView ivStatus;
TextView tvType;
TextView tvFile;
ProgressBar progressbar;
ViewHolder(View itemView) {
@ -76,7 +75,6 @@ public class AdapterAttachment extends RecyclerView.Adapter<AdapterAttachment.Vi
tvSize = itemView.findViewById(R.id.tvSize);
ivStatus = itemView.findViewById(R.id.ivStatus);
tvType = itemView.findViewById(R.id.tvType);
tvFile = itemView.findViewById(R.id.tvFile);
progressbar = itemView.findViewById(R.id.progressbar);
}
@ -97,15 +95,15 @@ public class AdapterAttachment extends RecyclerView.Adapter<AdapterAttachment.Vi
tvSize.setText(Helper.humanReadableByteCount(attachment.size, false));
tvSize.setVisibility(attachment.size == null ? View.GONE : View.VISIBLE);
if (attachment.filename == null) {
if (attachment.available) {
ivStatus.setImageResource(R.drawable.baseline_visibility_24);
ivStatus.setVisibility(View.VISIBLE);
} else {
if (attachment.progress == null) {
ivStatus.setImageResource(R.drawable.baseline_get_app_24);
ivStatus.setVisibility(View.VISIBLE);
} else
ivStatus.setVisibility(View.GONE);
} else {
ivStatus.setImageResource(R.drawable.baseline_visibility_24);
ivStatus.setVisibility(View.VISIBLE);
}
ivDelete.setVisibility(readonly ? View.GONE : View.VISIBLE);
@ -113,12 +111,10 @@ public class AdapterAttachment extends RecyclerView.Adapter<AdapterAttachment.Vi
if (attachment.progress != null)
progressbar.setProgress(attachment.progress);
progressbar.setVisibility(
attachment.progress == null || attachment.filename != null ? View.GONE : View.VISIBLE);
attachment.progress == null || attachment.available ? View.GONE : View.VISIBLE);
tvType.setText(attachment.type);
tvFile.setText(attachment.filename);
tvType.setVisibility(debug ? View.VISIBLE : View.GONE);
tvFile.setVisibility(debug ? View.VISIBLE : View.GONE);
}
@Override
@ -137,7 +133,7 @@ public class AdapterAttachment extends RecyclerView.Adapter<AdapterAttachment.Vi
protected Void onLoad(Context context, Bundle args) {
DB.getInstance(context).attachment().deleteAttachment(attachment.id);
File dir = new File(context.getFilesDir(), "attachments");
File file = new File(dir, attachment.filename);
File file = new File(dir, attachment.id.toString());
file.delete();
return null;
@ -145,7 +141,39 @@ public class AdapterAttachment extends RecyclerView.Adapter<AdapterAttachment.Vi
}.load(context, owner, args);
} else {
if (attachment.filename == null) {
if (attachment.available) {
// Build file name
File dir = new File(context.getFilesDir(), "attachments");
File file = new File(dir, attachment.id.toString());
// https://developer.android.com/reference/android/support/v4/content/FileProvider
Uri uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID, file);
Log.i(Helper.TAG, "uri=" + uri);
// Build intent
final Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, attachment.type);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Log.i(Helper.TAG, "Sharing " + file + " type=" + attachment.type);
Log.i(Helper.TAG, "Intent=" + intent);
//context.startActivity(Intent.createChooser(intent, attachment.name));
// Set permissions
List<ResolveInfo> targets = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : targets) {
Log.i(Helper.TAG, "Target=" + resolveInfo);
context.grantUriPermission(resolveInfo.activityInfo.packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
// Check if viewer available
if (targets.size() == 0) {
Toast.makeText(context, R.string.title_no_viewer, Toast.LENGTH_LONG).show();
return;
}
context.startActivity(intent);
} else {
if (attachment.progress == null) {
Bundle args = new Bundle();
args.putLong("id", attachment.id);
@ -179,38 +207,6 @@ public class AdapterAttachment extends RecyclerView.Adapter<AdapterAttachment.Vi
}
}.load(context, owner, args);
}
} else {
// Build file name
File dir = new File(context.getFilesDir(), "attachments");
File file = new File(dir, attachment.filename);
// https://developer.android.com/reference/android/support/v4/content/FileProvider
Uri uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID, file);
Log.i(Helper.TAG, "uri=" + uri);
// Build intent
final Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, attachment.type);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Log.i(Helper.TAG, "Sharing " + file + " type=" + attachment.type);
Log.i(Helper.TAG, "Intent=" + intent);
//context.startActivity(Intent.createChooser(intent, attachment.name));
// Set permissions
List<ResolveInfo> targets = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : targets) {
Log.i(Helper.TAG, "Target=" + resolveInfo);
context.grantUriPermission(resolveInfo.activityInfo.packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
// Check if viewer available
if (targets.size() == 0) {
Toast.makeText(context, R.string.title_no_viewer, Toast.LENGTH_LONG).show();
return;
}
context.startActivity(intent);
}
}
}


+ 1
- 1
app/src/main/java/eu/faircode/email/DB.java View File

@ -71,7 +71,7 @@ public abstract class DB extends RoomDatabase {
private static DB sInstance;
private static final String DB_NAME = "fairemail";
private static final String DB_NAME = "email";
public static synchronized DB getInstance(Context context) {
if (sInstance == null)


+ 3
- 2
app/src/main/java/eu/faircode/email/EntityAttachment.java View File

@ -54,7 +54,8 @@ public class EntityAttachment {
public String type;
public Integer size;
public Integer progress;
public String filename;
@NonNull
public Boolean available = false;
@Ignore
BodyPart part;
@ -69,7 +70,7 @@ public class EntityAttachment {
this.type.equals(other.type) &&
(this.size == null ? other.size == null : this.size.equals(other.size)) &&
(this.progress == null ? other.progress == null : this.progress.equals(other.progress)) &&
(this.filename == null ? other.filename == null : this.filename.equals(other.filename)));
this.available.equals(other.available));
} else
return false;
}


+ 55
- 2
app/src/main/java/eu/faircode/email/EntityMessage.java View File

@ -19,6 +19,15 @@ package eu.faircode.email;
Copyright 2018 by Marcel Bokhorst (M66B)
*/
import android.content.Context;
import android.util.Log;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;
import java.util.Random;
@ -76,7 +85,6 @@ public class EntityMessage {
public Address[] bcc;
public Address[] reply;
public String subject;
public String body;
public Long sent; // compose = null
@NonNull
public Long received; // compose = stored
@ -100,6 +108,52 @@ public class EntityMessage {
return sb.toString();
}
void write(Context context, String body) throws IOException {
File dir = new File(context.getFilesDir(), "messages");
dir.mkdir();
File file = new File(dir, id.toString());
BufferedWriter out = null;
try {
out = new BufferedWriter(new FileWriter(file));
out.write(body);
} finally {
if (out != null)
try {
out.close();
} catch (IOException e) {
Log.e(Helper.TAG, e + "\n" + Log.getStackTraceString(e));
}
}
}
String read(Context context) throws IOException {
return read(context, this.id);
}
static String read(Context context, Long id) throws IOException {
File dir = new File(context.getFilesDir(), "messages");
File file = new File(dir, id.toString());
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader(file));
StringBuilder body = new StringBuilder();
String line;
while ((line = in.readLine()) != null) {
body.append(line);
body.append('\n');
}
return body.toString();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ex) {
Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex));
}
}
}
}
@Override
public boolean equals(Object obj) {
if (obj instanceof EntityMessage) {
@ -119,7 +173,6 @@ public class EntityMessage {
equal(this.bcc, other.bcc) &&
equal(this.reply, other.reply) &&
(this.subject == null ? other.subject == null : this.subject.equals(other.subject)) &&
(this.body == null ? other.body == null : this.body.equals(other.body)) &&
(this.sent == null ? other.sent == null : this.sent.equals(other.sent)) &&
this.received.equals(other.received) &&
this.seen.equals(other.seen) &&


+ 12
- 4
app/src/main/java/eu/faircode/email/FragmentAbout.java View File

@ -23,6 +23,7 @@ import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -30,6 +31,7 @@ import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Date;
@ -80,6 +82,8 @@ public class FragmentAbout extends FragmentEx {
sb.append(Helper.getLogcat());
String body = "<pre>" + sb.toString().replaceAll("\\r?\\n", "<br />") + "</pre>";
EntityMessage draft;
DB db = DB.getInstance(context);
@ -96,16 +100,19 @@ public class FragmentAbout extends FragmentEx {
draft.msgid = EntityMessage.generateMessageId();
draft.to = new Address[]{Helper.myAddress()};
draft.subject = context.getString(R.string.app_name) + " debug info";
draft.body = "<pre>" + sb.toString().replaceAll("\\r?\\n", "<br />") + "</pre>";
draft.received = new Date().getTime();
draft.seen = false;
draft.ui_seen = false;
draft.ui_hide = false;
draft.id = db.message().insertMessage(draft);
draft.write(context, body);
EntityOperation.queue(db, draft, EntityOperation.ADD);
db.setTransactionSuccessful();
} catch (IOException ex) {
Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex));
return null;
} finally {
db.endTransaction();
}
@ -118,9 +125,10 @@ public class FragmentAbout extends FragmentEx {
@Override
protected void onLoaded(Bundle args, Long id) {
btnDebugInfo.setEnabled(true);
startActivity(new Intent(getContext(), ActivityCompose.class)
.putExtra("action", "edit")
.putExtra("id", id));
if (id != null)
startActivity(new Intent(getContext(), ActivityCompose.class)
.putExtra("action", "edit")
.putExtra("id", id));
}
@Override


+ 33
- 11
app/src/main/java/eu/faircode/email/FragmentCompose.java View File

@ -30,6 +30,7 @@ import android.os.Handler;
import android.provider.ContactsContract;
import android.provider.OpenableColumns;
import android.text.Html;
import android.text.Spanned;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
@ -516,7 +517,7 @@ public class FragmentCompose extends FragmentEx {
attachment.size = size;
attachment.progress = null;
attachment.filename = file.getName();
attachment.available = true;
db.attachment().updateAttachment(attachment);
} finally {
try {
@ -530,7 +531,6 @@ public class FragmentCompose extends FragmentEx {
} catch (Throwable ex) {
// Reset progress on failure
attachment.progress = null;
attachment.filename = null;
db.attachment().updateAttachment(attachment);
throw ex;
}
@ -571,7 +571,7 @@ public class FragmentCompose extends FragmentEx {
private SimpleTask<EntityMessage> draftLoader = new SimpleTask<EntityMessage>() {
@Override
protected EntityMessage onLoad(Context context, Bundle args) {
protected EntityMessage onLoad(Context context, Bundle args) throws IOException {
String action = args.getString("action");
long id = args.getLong("id", -1);
long account = args.getLong("account", -1);
@ -618,6 +618,8 @@ public class FragmentCompose extends FragmentEx {
if (drafts == null)
throw new IllegalArgumentException("no drafts folder");
String body = "";
draft = new EntityMessage();
draft.account = account;
draft.folder = drafts.id;
@ -640,21 +642,21 @@ public class FragmentCompose extends FragmentEx {
if ("reply".equals(action) || "reply_all".equals(action)) {
draft.subject = context.getString(R.string.title_subject_reply, ref.subject);
draft.body = String.format("<br><br>%s %s:<br><br>%s",
body = String.format("<br><br>%s %s:<br><br>%s",
Html.escapeHtml(new Date().toString()),
Html.escapeHtml(TextUtils.join(", ", draft.to)),
HtmlHelper.sanitize(context, ref.body, true));
HtmlHelper.sanitize(context, ref.read(context), true));
} else if ("forward".equals(action)) {
draft.subject = context.getString(R.string.title_subject_forward, ref.subject);
draft.body = String.format("<br><br>%s %s:<br><br>%s",
body = String.format("<br><br>%s %s:<br><br>%s",
Html.escapeHtml(new Date().toString()),
Html.escapeHtml(TextUtils.join(", ", ref.from)),
HtmlHelper.sanitize(context, ref.body, true));
HtmlHelper.sanitize(context, ref.read(context), true));
}
}
if ("new".equals(action))
draft.body = "";
body = "";
draft.received = new Date().getTime();
draft.seen = false;
@ -662,6 +664,7 @@ public class FragmentCompose extends FragmentEx {
draft.ui_hide = false;
draft.id = db.message().insertMessage(draft);
draft.write(context, body);
EntityOperation.queue(db, draft, EntityOperation.ADD);
@ -687,7 +690,22 @@ public class FragmentCompose extends FragmentEx {
etBcc.setText(draft.bcc == null ? null : TextUtils.join(", ", draft.bcc));
etSubject.setText(draft.subject);
etBody.setText(TextUtils.isEmpty(draft.body) ? null : Html.fromHtml(draft.body));
etBody.setText(null);
Bundle a = new Bundle();
a.putLong("id", draft.id);
new SimpleTask<Spanned>() {
@Override
protected Spanned onLoad(Context context, Bundle args) throws Throwable {
return Html.fromHtml(EntityMessage.read(context, args.getLong("id")));
}
@Override
protected void onLoaded(Bundle args, Spanned body) {
etBody.setText(body);
}
}.load(FragmentCompose.this, a);
getActivity().invalidateOptionsMenu();
Helper.setViewsEnabled(view, true);
@ -836,14 +854,16 @@ public class FragmentCompose extends FragmentEx {
draft.cc = acc;
draft.bcc = abcc;
draft.subject = subject;
draft.body = "<pre>" + body.replaceAll("\\r?\\n", "<br />") + "</pre>";
draft.received = new Date().getTime();
body = "<pre>" + body.replaceAll("\\r?\\n", "<br />") + "</pre>";
// Execute action
if (action == R.id.action_trash) {
draft.ui_seen = true;
draft.ui_hide = true;
db.message().updateMessage(draft);
draft.write(context, body);
EntityOperation.queue(db, draft, EntityOperation.SEEN, true);
@ -857,11 +877,13 @@ public class FragmentCompose extends FragmentEx {
return null;
db.message().updateMessage(draft);
draft.write(context, body);
EntityOperation.queue(db, draft, EntityOperation.ADD);
} else if (action == R.id.action_send) {
db.message().updateMessage(draft);
draft.write(context, body);
// Check data
if (draft.identity == null)
@ -876,7 +898,7 @@ public class FragmentCompose extends FragmentEx {
// Save attachments
List<EntityAttachment> attachments = db.attachment().getAttachments(draft.id);
for (EntityAttachment attachment : attachments)
if (attachment.filename == null)
if (!attachment.available)
throw new IllegalArgumentException(context.getString(R.string.title_attachments_missing));
// Delete draft (cannot move to outbox)


+ 18
- 3
app/src/main/java/eu/faircode/email/FragmentMessage.java View File

@ -29,6 +29,7 @@ import android.preference.PreferenceManager;
import android.text.Html;
import android.text.Layout;
import android.text.Spannable;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.URLSpan;
import android.view.LayoutInflater;
@ -339,9 +340,23 @@ public class FragmentMessage extends FragmentEx {
: R.drawable.baseline_visibility_24);
actionSeen.setTitle(message.ui_seen ? R.string.title_unseen : R.string.title_seen);
tvBody.setText(message.body == null
? null
: Html.fromHtml(HtmlHelper.sanitize(getContext(), message.body, false)));
tvBody.setText(null);
Bundle args = new Bundle();
args.putLong("id", message.id);
new SimpleTask<Spanned>() {
@Override
protected Spanned onLoad(Context context, Bundle args) throws Throwable {
String body = EntityMessage.read(context, args.getLong("id"));
return Html.fromHtml(HtmlHelper.sanitize(getContext(), body, false));
}
@Override
protected void onLoaded(Bundle args, Spanned body) {
tvBody.setText(body);
}
}.load(FragmentMessage.this, args);
db.folder().liveFolders(message.account).removeObservers(getViewLifecycleOwner());
db.folder().liveFolders(message.account).observe(getViewLifecycleOwner(), new Observer<List<TupleFolderEx>>() {


+ 6
- 9
app/src/main/java/eu/faircode/email/MessageHelper.java View File

@ -93,7 +93,7 @@ public class MessageHelper {
return props;
}
static MimeMessageEx from(Context context, EntityMessage message, List<EntityAttachment> attachments, Session isession) throws MessagingException {
static MimeMessageEx from(Context context, EntityMessage message, List<EntityAttachment> attachments, Session isession) throws MessagingException, IOException {
MimeMessageEx imessage = new MimeMessageEx(isession, message.msgid);
imessage.setFlag(Flags.Flag.SEEN, message.seen);
@ -115,25 +115,22 @@ public class MessageHelper {
// TODO: plain message?
if (message.body == null)
throw new IllegalArgumentException("null message");
if (attachments.size() == 0)
imessage.setText(message.body, Charset.defaultCharset().name(), "html");
imessage.setText(message.read(context), Charset.defaultCharset().name(), "html");
else {
Multipart multipart = new MimeMultipart();
BodyPart bpMessage = new MimeBodyPart();
bpMessage.setContent(message.body, "text/html; charset=" + Charset.defaultCharset().name());
bpMessage.setContent(message.read(context), "text/html; charset=" + Charset.defaultCharset().name());
multipart.addBodyPart(bpMessage);
for (final EntityAttachment attachment : attachments)
if (attachment.filename != null) {
if (attachment.available) {
BodyPart bpAttachment = new MimeBodyPart();
bpAttachment.setFileName(attachment.name);
File dir = new File(context.getFilesDir(), "attachments");
File file = new File(dir, attachment.filename);
File file = new File(dir, attachment.id.toString());
FileDataSource dataSource = new FileDataSource(file);
dataSource.setFileTypeMap(new FileTypeMap() {
@Override
@ -159,7 +156,7 @@ public class MessageHelper {
return imessage;
}
static MimeMessageEx from(Context context, EntityMessage message, EntityMessage reply, List<EntityAttachment> attachments, Session isession) throws MessagingException {
static MimeMessageEx from(Context context, EntityMessage message, EntityMessage reply, List<EntityAttachment> attachments, Session isession) throws MessagingException, IOException {
MimeMessageEx imessage = from(context, message, attachments, isession);
imessage.addHeader("In-Reply-To", reply.msgid);
imessage.addHeader("References", (reply.references == null ? "" : reply.references + " ") + reply.msgid);


+ 5
- 6
app/src/main/java/eu/faircode/email/ServiceSynchronize.java View File

@ -851,7 +851,7 @@ public class ServiceSynchronize extends LifecycleService {
db.message().setMessageSeen(message.id, seen);
}
private void doAdd(EntityFolder folder, Session isession, IMAPFolder ifolder, EntityMessage message, JSONArray jargs, DB db) throws MessagingException, JSONException {
private void doAdd(EntityFolder folder, Session isession, IMAPFolder ifolder, EntityMessage message, JSONArray jargs, DB db) throws MessagingException, JSONException, IOException {
// Append message
List<EntityAttachment> attachments = db.attachment().getAttachments(message.id);
@ -871,7 +871,7 @@ public class ServiceSynchronize extends LifecycleService {
Log.i(Helper.TAG, "Appended uid=" + message.uid);
}
private void doMove(EntityFolder folder, Session isession, IMAPStore istore, IMAPFolder ifolder, EntityMessage message, JSONArray jargs, DB db) throws JSONException, MessagingException {
private void doMove(EntityFolder folder, Session isession, IMAPStore istore, IMAPFolder ifolder, EntityMessage message, JSONArray jargs, DB db) throws JSONException, MessagingException, IOException {
// Move message
long id = jargs.getLong(0);
EntityFolder target = db.folder().getFolder(id);
@ -914,7 +914,7 @@ public class ServiceSynchronize extends LifecycleService {
db.message().deleteMessage(message.id);
}
private void doSend(Session isession, EntityMessage message, DB db) throws MessagingException {
private void doSend(Session isession, EntityMessage message, DB db) throws MessagingException, IOException {
// Send message
EntityIdentity ident = db.identity().getIdentity(message.identity);
EntityMessage reply = (message.replying == null ? null : db.message().getMessage(message.replying));
@ -1033,7 +1033,7 @@ public class ServiceSynchronize extends LifecycleService {
// Store attachment data
attachment.size = size;
attachment.progress = null;
attachment.filename = file.getName();
attachment.available = true;
db.attachment().updateAttachment(attachment);
} finally {
try {
@ -1048,7 +1048,6 @@ public class ServiceSynchronize extends LifecycleService {
} catch (Throwable ex) {
// Reset progress on failure
attachment.progress = null;
attachment.filename = null;
db.attachment().updateAttachment(attachment);
throw ex;
}
@ -1296,7 +1295,6 @@ public class ServiceSynchronize extends LifecycleService {
message.bcc = helper.getBcc();
message.reply = helper.getReply();
message.subject = imessage.getSubject();
message.body = helper.getHtml();
message.received = imessage.getReceivedDate().getTime();
message.sent = (imessage.getSentDate() == null ? null : imessage.getSentDate().getTime());
message.seen = seen;
@ -1304,6 +1302,7 @@ public class ServiceSynchronize extends LifecycleService {
message.ui_hide = false;
message.id = db.message().insertMessage(message);
message.write(this, helper.getHtml());
Log.i(Helper.TAG, folder.name + " added id=" + message.id + " uid=" + message.uid);
int sequence = 0;


+ 2
- 11
app/src/main/res/layout/item_attachment.xml View File

@ -61,24 +61,15 @@
<TextView
android:id="@+id/tvType"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:text="text/plain"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintEnd_toEndOf="@id/ivStatus"
app:layout_constraintStart_toEndOf="@id/ivAttachments"
app:layout_constraintTop_toBottomOf="@id/ivAttachments" />
<TextView
android:id="@+id/tvFile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:text="filename"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/ivAttachments" />
<ProgressBar
android:id="@+id/progressbar"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"


Loading…
Cancel
Save