Match attachments by properties

pull/156/head
M66B 5 years ago
parent 61f7a2f692
commit 4cf330dfb6

File diff suppressed because it is too large Load Diff

@ -1390,7 +1390,7 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB
a.sequence = ++sequence; a.sequence = ++sequence;
a.id = db.attachment().insertAttachment(a); a.id = db.attachment().insertAttachment(a);
try { try {
parts.downloadAttachment(context, index, a.id); parts.downloadAttachment(context, a);
} catch (Throwable ex) { } catch (Throwable ex) {
Log.e(ex); Log.e(ex);
} }

@ -248,7 +248,7 @@ public class AdapterAttachment extends RecyclerView.Adapter<AdapterAttachment.Vi
db.attachment().setProgress(id, 0); db.attachment().setProgress(id, 0);
EntityOperation.queue(context, db, message, EntityOperation.ATTACHMENT, sequence); EntityOperation.queue(context, db, message, EntityOperation.ATTACHMENT, id);
db.setTransactionSuccessful(); db.setTransactionSuccessful();
} finally { } finally {

@ -150,7 +150,7 @@ public class AdapterImage extends RecyclerView.Adapter<AdapterImage.ViewHolder>
db.attachment().setProgress(id, 0); db.attachment().setProgress(id, 0);
EntityMessage msg = db.message().getMessage(message); EntityMessage msg = db.message().getMessage(message);
EntityOperation.queue(context, db, msg, EntityOperation.ATTACHMENT, sequence); EntityOperation.queue(context, db, msg, EntityOperation.ATTACHMENT, id);
db.setTransactionSuccessful(); db.setTransactionSuccessful();
} finally { } finally {

@ -1343,7 +1343,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
for (EntityAttachment attachment : db.attachment().getAttachments(message.id)) for (EntityAttachment attachment : db.attachment().getAttachments(message.id))
if (attachment.progress == null && !attachment.available) { if (attachment.progress == null && !attachment.available) {
db.attachment().setProgress(attachment.id, 0); db.attachment().setProgress(attachment.id, 0);
EntityOperation.queue(context, db, msg, EntityOperation.ATTACHMENT, attachment.sequence); EntityOperation.queue(context, db, msg, EntityOperation.ATTACHMENT, attachment.id);
} }
db.setTransactionSuccessful(); db.setTransactionSuccessful();
@ -1691,7 +1691,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
List<EntityAttachment> attachments = db.attachment().getAttachments(message.id); List<EntityAttachment> attachments = db.attachment().getAttachments(message.id);
for (EntityAttachment attachment : attachments) for (EntityAttachment attachment : attachments)
if (!attachment.available && !TextUtils.isEmpty(attachment.cid)) if (!attachment.available && !TextUtils.isEmpty(attachment.cid))
EntityOperation.queue(context, db, message, EntityOperation.ATTACHMENT, attachment.sequence); EntityOperation.queue(context, db, message, EntityOperation.ATTACHMENT, attachment.id);
db.setTransactionSuccessful(); db.setTransactionSuccessful();
} finally { } finally {

@ -691,10 +691,14 @@ class Core {
// Download attachment // Download attachment
DB db = DB.getInstance(context); DB db = DB.getInstance(context);
int sequence = jargs.getInt(0); long id = jargs.getLong(0);
// Get attachment // Get attachment
EntityAttachment attachment = db.attachment().getAttachment(op.message, sequence); EntityAttachment attachment = db.attachment().getAttachment(id);
if (attachment == null)
attachment = db.attachment().getAttachment(message.id, (int) id); // legacy
if (attachment == null)
throw new IllegalArgumentException("Attachment not found");
if (attachment.available) if (attachment.available)
return; return;
@ -703,10 +707,28 @@ class Core {
if (imessage == null) if (imessage == null)
throw new MessageRemovedException(); throw new MessageRemovedException();
// Match attachment by attributes
// Some servers order attachments randomly
boolean found = false;
List<EntityAttachment> attachments = db.attachment().getAttachments(message.id);
for (EntityAttachment a : attachments) {
if (Objects.equals(a.name, attachment.name) &&
Objects.equals(a.type, attachment.type) &&
Objects.equals(a.disposition, attachment.disposition) &&
Objects.equals(a.cid, attachment.cid) &&
Objects.equals(a.encryption, attachment.encryption) &&
Objects.equals(a.size, attachment.size)) {
found = true;
// Download attachment // Download attachment
MessageHelper helper = new MessageHelper((MimeMessage) imessage); MessageHelper helper = new MessageHelper((MimeMessage) imessage);
MessageHelper.MessageParts parts = helper.getMessageParts(); MessageHelper.MessageParts parts = helper.getMessageParts();
parts.downloadAttachment(context, sequence - 1, attachment.id); parts.downloadAttachment(context, a);
}
}
if (!found && !EntityFolder.DRAFTS.equals(folder.type))
throw new IllegalArgumentException("Attachment not found");
updateMessageSize(context, message.id); updateMessageSize(context, message.id);
} }
@ -1566,7 +1588,7 @@ class Core {
if (!attachment.available) if (!attachment.available)
if (state.getNetworkState().isUnmetered() || (attachment.size != null && attachment.size < maxSize)) if (state.getNetworkState().isUnmetered() || (attachment.size != null && attachment.size < maxSize))
try { try {
parts.downloadAttachment(context, attachment.sequence - 1, attachment.id); parts.downloadAttachment(context, attachment);
} catch (Throwable ex) { } catch (Throwable ex) {
Log.e(ex); Log.e(ex);
} }

@ -51,7 +51,7 @@ import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory;
// https://developer.android.com/topic/libraries/architecture/room.html // https://developer.android.com/topic/libraries/architecture/room.html
@Database( @Database(
version = 79, version = 80,
entities = { entities = {
EntityIdentity.class, EntityIdentity.class,
EntityAccount.class, EntityAccount.class,
@ -801,6 +801,14 @@ public abstract class DB extends RoomDatabase {
db.execSQL("ALTER TABLE `message` ADD COLUMN `plain_only` INTEGER"); db.execSQL("ALTER TABLE `message` ADD COLUMN `plain_only` INTEGER");
} }
}) })
.addMigrations(new Migration(79, 80) {
@Override
public void migrate(SupportSQLiteDatabase db) {
Log.i("DB migration from version " + startVersion + " to " + endVersion);
db.execSQL("DROP INDEX index_attachment_message_cid");
db.execSQL("CREATE INDEX `index_attachment_message_cid` ON `attachment` (`message`, `cid`)");
}
})
.build(); .build();
} }

@ -59,7 +59,8 @@ public interface DaoAttachment {
@Query("SELECT * FROM attachment" + @Query("SELECT * FROM attachment" +
" WHERE message = :message" + " WHERE message = :message" +
" AND cid = :cid") " AND cid = :cid" +
" LIMIT 1")
EntityAttachment getAttachment(long message, String cid); EntityAttachment getAttachment(long message, String cid);
@Query("UPDATE attachment" + @Query("UPDATE attachment" +
@ -67,11 +68,6 @@ public interface DaoAttachment {
" WHERE id = :id") " WHERE id = :id")
void setMessage(long id, long message); void setMessage(long id, long message);
@Query("UPDATE attachment" +
" SET name = :name, type = :type, disposition = :disposition, cid = :cid, encryption = :encryption" +
" WHERE id = :id")
void setInfo(long id, String name, String type, String disposition, String cid, Integer encryption);
@Query("UPDATE attachment" + @Query("UPDATE attachment" +
" SET error = NULL, progress = :progress, available = 0" + " SET error = NULL, progress = :progress, available = 0" +
" WHERE id = :id") " WHERE id = :id")

@ -45,7 +45,7 @@ import static androidx.room.ForeignKey.CASCADE;
indices = { indices = {
@Index(value = {"message"}), @Index(value = {"message"}),
@Index(value = {"message", "sequence"}, unique = true), @Index(value = {"message", "sequence"}, unique = true),
@Index(value = {"message", "cid"}, unique = true) @Index(value = {"message", "cid"})
} }
) )
public class EntityAttachment { public class EntityAttachment {

@ -2182,7 +2182,7 @@ public class FragmentCompose extends FragmentBase {
List<EntityAttachment> attachments = db.attachment().getAttachments(draft.id); List<EntityAttachment> attachments = db.attachment().getAttachments(draft.id);
for (EntityAttachment attachment : attachments) for (EntityAttachment attachment : attachments)
if (!attachment.available) if (!attachment.available)
EntityOperation.queue(context, db, draft, EntityOperation.ATTACHMENT, attachment.sequence); EntityOperation.queue(context, db, draft, EntityOperation.ATTACHMENT, attachment.id);
} }
db.setTransactionSuccessful(); db.setTransactionSuccessful();

@ -826,34 +826,17 @@ public class MessageHelper {
return result; return result;
} }
void downloadAttachment(Context context, int index, long id) throws MessagingException, IOException { void downloadAttachment(Context context, EntityAttachment attachment) throws MessagingException, IOException {
Log.i("downloading attchment id=" + id + " seq=" + index); Log.i("downloading attachment id=" + attachment.id);
// Attachments of drafts might not have been uploaded yet
if (index >= attachments.size()) {
Log.w("Attachment unavailable sequence=" + index + " size=" + attachments.size());
return;
}
DB db = DB.getInstance(context); DB db = DB.getInstance(context);
// Get data // Get data
AttachmentPart apart = attachments.get(index); AttachmentPart apart = attachments.get(attachment.sequence - 1);
EntityAttachment attachment = db.attachment().getAttachment(id);
if (attachment == null)
return;
// Set info again in case ordering changed
db.attachment().setInfo(id,
apart.attachment.name,
apart.attachment.type,
apart.attachment.disposition,
apart.attachment.cid,
apart.attachment.encryption);
// Download attachment // Download attachment
File file = attachment.getFile(context); File file = attachment.getFile(context);
db.attachment().setProgress(id, null); db.attachment().setProgress(attachment.id, null);
try (InputStream is = apart.part.getInputStream()) { try (InputStream is = apart.part.getInputStream()) {
long size = 0; long size = 0;
long total = apart.part.getSize(); long total = apart.part.getSize();
@ -866,19 +849,19 @@ public class MessageHelper {
// Update progress // Update progress
if (total > 0) if (total > 0)
db.attachment().setProgress(id, (int) (size * 100 / total)); db.attachment().setProgress(attachment.id, (int) (size * 100 / total));
} }
} }
// Store attachment data // Store attachment data
db.attachment().setDownloaded(id, size); db.attachment().setDownloaded(attachment.id, size);
Log.i("Downloaded attachment size=" + size); Log.i("Downloaded attachment size=" + size);
} catch (FolderClosedIOException ex) { } catch (FolderClosedIOException ex) {
throw new FolderClosedException(ex.getFolder(), "downloadAttachment", ex); throw new FolderClosedException(ex.getFolder(), "downloadAttachment", ex);
} catch (Throwable ex) { } catch (Throwable ex) {
// Reset progress on failure // Reset progress on failure
db.attachment().setError(id, Helper.formatThrowable(ex)); db.attachment().setError(attachment.id, Helper.formatThrowable(ex));
throw ex; throw ex;
} }
} }
@ -922,18 +905,6 @@ public class MessageHelper {
getMessageParts(cmessage, parts, false); getMessageParts(cmessage, parts, false);
// Fix duplicate CIDs
List<EntityAttachment> attachments = parts.getAttachments();
for (int i = 0; i < attachments.size(); i++) {
String cid = attachments.get(i).cid;
if (cid != null)
for (int j = i + 1; j < attachments.size(); j++) {
EntityAttachment a = attachments.get(j);
if (cid.equals(a.cid))
a.cid = null;
}
}
return parts; return parts;
} }

Loading…
Cancel
Save