diff --git a/app/schemas/eu.faircode.email.DB/7.json b/app/schemas/eu.faircode.email.DB/1.json similarity index 95% rename from app/schemas/eu.faircode.email.DB/7.json rename to app/schemas/eu.faircode.email.DB/1.json index 00802c1cbe..eb54211ba3 100644 --- a/app/schemas/eu.faircode.email.DB/7.json +++ b/app/schemas/eu.faircode.email.DB/1.json @@ -1,8 +1,8 @@ { "formatVersion": 1, "database": { - "version": 7, - "identityHash": "74b765c4ee277861c68851c33a596610", + "version": 1, + "identityHash": "ff81778e939ac6480ab8ec93435db96a", "entities": [ { "tableName": "identity", @@ -634,7 +634,7 @@ }, { "tableName": "operation", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `message` INTEGER NOT NULL, `name` TEXT NOT NULL, `args` 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, `folder` INTEGER NOT NULL, `message` INTEGER NOT NULL, `name` TEXT NOT NULL, `args` TEXT, FOREIGN KEY(`folder`) REFERENCES `folder`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`message`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", "fields": [ { "fieldPath": "id", @@ -642,6 +642,12 @@ "affinity": "INTEGER", "notNull": false }, + { + "fieldPath": "folder", + "columnName": "folder", + "affinity": "INTEGER", + "notNull": true + }, { "fieldPath": "message", "columnName": "message", @@ -678,6 +684,17 @@ } ], "foreignKeys": [ + { + "table": "folder", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "folder" + ], + "referencedColumns": [ + "id" + ] + }, { "table": "message", "onDelete": "CASCADE", @@ -694,7 +711,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, \"74b765c4ee277861c68851c33a596610\")" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"ff81778e939ac6480ab8ec93435db96a\")" ] } } \ No newline at end of file diff --git a/app/schemas/eu.faircode.email.DB/2.json b/app/schemas/eu.faircode.email.DB/2.json deleted file mode 100644 index b7df5c6cb1..0000000000 --- a/app/schemas/eu.faircode.email.DB/2.json +++ /dev/null @@ -1,639 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 2, - "identityHash": "28de77abd152c62bbdcca05efc2a6f59", - "entities": [ - { - "tableName": "identity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT NOT NULL, `email` TEXT NOT NULL, `replyto` TEXT, `host` TEXT NOT NULL, `port` INTEGER NOT NULL, `starttls` INTEGER NOT NULL, `user` TEXT NOT NULL, `password` TEXT NOT NULL, `primary` INTEGER NOT NULL, `synchronize` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "replyto", - "columnName": "replyto", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "host", - "columnName": "host", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "port", - "columnName": "port", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "starttls", - "columnName": "starttls", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "user", - "columnName": "user", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "password", - "columnName": "password", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "primary", - "columnName": "primary", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "synchronize", - "columnName": "synchronize", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "account", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `host` TEXT NOT NULL, `port` INTEGER NOT NULL, `user` TEXT NOT NULL, `password` TEXT NOT NULL, `primary` INTEGER NOT NULL, `synchronize` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "host", - "columnName": "host", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "port", - "columnName": "port", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "user", - "columnName": "user", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "password", - "columnName": "password", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "primary", - "columnName": "primary", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "synchronize", - "columnName": "synchronize", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "folder", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `account` INTEGER, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `synchronize` INTEGER NOT NULL, `after` INTEGER NOT NULL, FOREIGN KEY(`account`) REFERENCES `account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "account", - "columnName": "account", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "synchronize", - "columnName": "synchronize", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "after", - "columnName": "after", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [ - { - "name": "index_folder_account_name", - "unique": true, - "columnNames": [ - "account", - "name" - ], - "createSql": "CREATE UNIQUE INDEX `index_folder_account_name` ON `${TABLE_NAME}` (`account`, `name`)" - }, - { - "name": "index_folder_account", - "unique": false, - "columnNames": [ - "account" - ], - "createSql": "CREATE INDEX `index_folder_account` ON `${TABLE_NAME}` (`account`)" - }, - { - "name": "index_folder_name", - "unique": false, - "columnNames": [ - "name" - ], - "createSql": "CREATE INDEX `index_folder_name` ON `${TABLE_NAME}` (`name`)" - }, - { - "name": "index_folder_type", - "unique": false, - "columnNames": [ - "type" - ], - "createSql": "CREATE INDEX `index_folder_type` ON `${TABLE_NAME}` (`type`)" - } - ], - "foreignKeys": [ - { - "table": "account", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "account" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "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, `seen` INTEGER NOT NULL, `ui_seen` INTEGER NOT NULL, `ui_hide` INTEGER NOT NULL, 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", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "account", - "columnName": "account", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "folder", - "columnName": "folder", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "identity", - "columnName": "identity", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "replying", - "columnName": "replying", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "uid", - "columnName": "uid", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "msgid", - "columnName": "msgid", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "references", - "columnName": "references", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "inreplyto", - "columnName": "inreplyto", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "thread", - "columnName": "thread", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "from", - "columnName": "from", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "to", - "columnName": "to", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "cc", - "columnName": "cc", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "bcc", - "columnName": "bcc", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "reply", - "columnName": "reply", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "subject", - "columnName": "subject", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "body", - "columnName": "body", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "sent", - "columnName": "sent", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "received", - "columnName": "received", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "seen", - "columnName": "seen", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "ui_seen", - "columnName": "ui_seen", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "ui_hide", - "columnName": "ui_hide", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [ - { - "name": "index_message_account", - "unique": false, - "columnNames": [ - "account" - ], - "createSql": "CREATE INDEX `index_message_account` ON `${TABLE_NAME}` (`account`)" - }, - { - "name": "index_message_folder", - "unique": false, - "columnNames": [ - "folder" - ], - "createSql": "CREATE INDEX `index_message_folder` ON `${TABLE_NAME}` (`folder`)" - }, - { - "name": "index_message_identity", - "unique": false, - "columnNames": [ - "identity" - ], - "createSql": "CREATE INDEX `index_message_identity` ON `${TABLE_NAME}` (`identity`)" - }, - { - "name": "index_message_replying", - "unique": false, - "columnNames": [ - "replying" - ], - "createSql": "CREATE INDEX `index_message_replying` ON `${TABLE_NAME}` (`replying`)" - }, - { - "name": "index_message_folder_uid", - "unique": true, - "columnNames": [ - "folder", - "uid" - ], - "createSql": "CREATE UNIQUE INDEX `index_message_folder_uid` ON `${TABLE_NAME}` (`folder`, `uid`)" - }, - { - "name": "index_message_thread", - "unique": false, - "columnNames": [ - "thread" - ], - "createSql": "CREATE INDEX `index_message_thread` ON `${TABLE_NAME}` (`thread`)" - }, - { - "name": "index_message_received", - "unique": false, - "columnNames": [ - "received" - ], - "createSql": "CREATE INDEX `index_message_received` ON `${TABLE_NAME}` (`received`)" - } - ], - "foreignKeys": [ - { - "table": "account", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "account" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "folder", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "folder" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "identity", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "identity" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "message", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "replying" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "attachment", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `message` INTEGER NOT NULL, `sequence` INTEGER NOT NULL, `type` TEXT NOT NULL, `name` TEXT, `content` BLOB, FOREIGN KEY(`message`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "message", - "columnName": "message", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "sequence", - "columnName": "sequence", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "content", - "columnName": "content", - "affinity": "BLOB", - "notNull": false - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [ - { - "name": "index_attachment_message", - "unique": false, - "columnNames": [ - "message" - ], - "createSql": "CREATE INDEX `index_attachment_message` ON `${TABLE_NAME}` (`message`)" - }, - { - "name": "index_attachment_message_sequence", - "unique": true, - "columnNames": [ - "message", - "sequence" - ], - "createSql": "CREATE UNIQUE INDEX `index_attachment_message_sequence` ON `${TABLE_NAME}` (`message`, `sequence`)" - } - ], - "foreignKeys": [ - { - "table": "message", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "message" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "operation", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `message` INTEGER NOT NULL, `name` TEXT NOT NULL, `args` TEXT, FOREIGN KEY(`message`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "message", - "columnName": "message", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "args", - "columnName": "args", - "affinity": "TEXT", - "notNull": false - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [ - { - "name": "index_operation_message", - "unique": false, - "columnNames": [ - "message" - ], - "createSql": "CREATE INDEX `index_operation_message` ON `${TABLE_NAME}` (`message`)" - } - ], - "foreignKeys": [ - { - "table": "message", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "message" - ], - "referencedColumns": [ - "id" - ] - } - ] - } - ], - "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, \"28de77abd152c62bbdcca05efc2a6f59\")" - ] - } -} \ No newline at end of file diff --git a/app/schemas/eu.faircode.email.DB/3.json b/app/schemas/eu.faircode.email.DB/3.json deleted file mode 100644 index 87c96eb961..0000000000 --- a/app/schemas/eu.faircode.email.DB/3.json +++ /dev/null @@ -1,651 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 3, - "identityHash": "40fd6ebf37a522fd68104290c7f30208", - "entities": [ - { - "tableName": "identity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT NOT NULL, `email` TEXT NOT NULL, `replyto` TEXT, `host` TEXT NOT NULL, `port` INTEGER NOT NULL, `starttls` INTEGER NOT NULL, `user` TEXT NOT NULL, `password` TEXT NOT NULL, `primary` INTEGER NOT NULL, `synchronize` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "replyto", - "columnName": "replyto", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "host", - "columnName": "host", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "port", - "columnName": "port", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "starttls", - "columnName": "starttls", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "user", - "columnName": "user", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "password", - "columnName": "password", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "primary", - "columnName": "primary", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "synchronize", - "columnName": "synchronize", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "account", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `host` TEXT NOT NULL, `port` INTEGER NOT NULL, `user` TEXT NOT NULL, `password` TEXT NOT NULL, `primary` INTEGER NOT NULL, `synchronize` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "host", - "columnName": "host", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "port", - "columnName": "port", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "user", - "columnName": "user", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "password", - "columnName": "password", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "primary", - "columnName": "primary", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "synchronize", - "columnName": "synchronize", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "folder", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `account` INTEGER, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `synchronize` INTEGER NOT NULL, `after` INTEGER NOT NULL, FOREIGN KEY(`account`) REFERENCES `account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "account", - "columnName": "account", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "synchronize", - "columnName": "synchronize", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "after", - "columnName": "after", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [ - { - "name": "index_folder_account_name", - "unique": true, - "columnNames": [ - "account", - "name" - ], - "createSql": "CREATE UNIQUE INDEX `index_folder_account_name` ON `${TABLE_NAME}` (`account`, `name`)" - }, - { - "name": "index_folder_account", - "unique": false, - "columnNames": [ - "account" - ], - "createSql": "CREATE INDEX `index_folder_account` ON `${TABLE_NAME}` (`account`)" - }, - { - "name": "index_folder_name", - "unique": false, - "columnNames": [ - "name" - ], - "createSql": "CREATE INDEX `index_folder_name` ON `${TABLE_NAME}` (`name`)" - }, - { - "name": "index_folder_type", - "unique": false, - "columnNames": [ - "type" - ], - "createSql": "CREATE INDEX `index_folder_type` ON `${TABLE_NAME}` (`type`)" - } - ], - "foreignKeys": [ - { - "table": "account", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "account" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "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, `seen` INTEGER NOT NULL, `ui_seen` INTEGER NOT NULL, `ui_hide` INTEGER NOT NULL, 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", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "account", - "columnName": "account", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "folder", - "columnName": "folder", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "identity", - "columnName": "identity", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "replying", - "columnName": "replying", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "uid", - "columnName": "uid", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "msgid", - "columnName": "msgid", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "references", - "columnName": "references", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "inreplyto", - "columnName": "inreplyto", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "thread", - "columnName": "thread", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "from", - "columnName": "from", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "to", - "columnName": "to", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "cc", - "columnName": "cc", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "bcc", - "columnName": "bcc", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "reply", - "columnName": "reply", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "subject", - "columnName": "subject", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "body", - "columnName": "body", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "sent", - "columnName": "sent", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "received", - "columnName": "received", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "seen", - "columnName": "seen", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "ui_seen", - "columnName": "ui_seen", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "ui_hide", - "columnName": "ui_hide", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [ - { - "name": "index_message_account", - "unique": false, - "columnNames": [ - "account" - ], - "createSql": "CREATE INDEX `index_message_account` ON `${TABLE_NAME}` (`account`)" - }, - { - "name": "index_message_folder", - "unique": false, - "columnNames": [ - "folder" - ], - "createSql": "CREATE INDEX `index_message_folder` ON `${TABLE_NAME}` (`folder`)" - }, - { - "name": "index_message_identity", - "unique": false, - "columnNames": [ - "identity" - ], - "createSql": "CREATE INDEX `index_message_identity` ON `${TABLE_NAME}` (`identity`)" - }, - { - "name": "index_message_replying", - "unique": false, - "columnNames": [ - "replying" - ], - "createSql": "CREATE INDEX `index_message_replying` ON `${TABLE_NAME}` (`replying`)" - }, - { - "name": "index_message_folder_uid", - "unique": true, - "columnNames": [ - "folder", - "uid" - ], - "createSql": "CREATE UNIQUE INDEX `index_message_folder_uid` ON `${TABLE_NAME}` (`folder`, `uid`)" - }, - { - "name": "index_message_thread", - "unique": false, - "columnNames": [ - "thread" - ], - "createSql": "CREATE INDEX `index_message_thread` ON `${TABLE_NAME}` (`thread`)" - }, - { - "name": "index_message_received", - "unique": false, - "columnNames": [ - "received" - ], - "createSql": "CREATE INDEX `index_message_received` ON `${TABLE_NAME}` (`received`)" - } - ], - "foreignKeys": [ - { - "table": "account", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "account" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "folder", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "folder" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "identity", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "identity" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "message", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "replying" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "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, `content` BLOB, FOREIGN KEY(`message`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "message", - "columnName": "message", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "sequence", - "columnName": "sequence", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "size", - "columnName": "size", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "progress", - "columnName": "progress", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "content", - "columnName": "content", - "affinity": "BLOB", - "notNull": false - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [ - { - "name": "index_attachment_message", - "unique": false, - "columnNames": [ - "message" - ], - "createSql": "CREATE INDEX `index_attachment_message` ON `${TABLE_NAME}` (`message`)" - }, - { - "name": "index_attachment_message_sequence", - "unique": true, - "columnNames": [ - "message", - "sequence" - ], - "createSql": "CREATE UNIQUE INDEX `index_attachment_message_sequence` ON `${TABLE_NAME}` (`message`, `sequence`)" - } - ], - "foreignKeys": [ - { - "table": "message", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "message" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "operation", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `message` INTEGER NOT NULL, `name` TEXT NOT NULL, `args` TEXT, FOREIGN KEY(`message`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "message", - "columnName": "message", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "args", - "columnName": "args", - "affinity": "TEXT", - "notNull": false - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [ - { - "name": "index_operation_message", - "unique": false, - "columnNames": [ - "message" - ], - "createSql": "CREATE INDEX `index_operation_message` ON `${TABLE_NAME}` (`message`)" - } - ], - "foreignKeys": [ - { - "table": "message", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "message" - ], - "referencedColumns": [ - "id" - ] - } - ] - } - ], - "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, \"40fd6ebf37a522fd68104290c7f30208\")" - ] - } -} \ No newline at end of file diff --git a/app/schemas/eu.faircode.email.DB/4.json b/app/schemas/eu.faircode.email.DB/4.json deleted file mode 100644 index a1df6281c5..0000000000 --- a/app/schemas/eu.faircode.email.DB/4.json +++ /dev/null @@ -1,659 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 4, - "identityHash": "ed5cc04cd8d171bff391cd8435cc29fe", - "entities": [ - { - "tableName": "identity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT NOT NULL, `email` TEXT NOT NULL, `replyto` TEXT, `host` TEXT NOT NULL, `port` INTEGER NOT NULL, `starttls` INTEGER NOT NULL, `user` TEXT NOT NULL, `password` TEXT NOT NULL, `primary` INTEGER NOT NULL, `synchronize` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "replyto", - "columnName": "replyto", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "host", - "columnName": "host", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "port", - "columnName": "port", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "starttls", - "columnName": "starttls", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "user", - "columnName": "user", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "password", - "columnName": "password", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "primary", - "columnName": "primary", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "synchronize", - "columnName": "synchronize", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "account", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `host` TEXT NOT NULL, `port` INTEGER NOT NULL, `user` TEXT NOT NULL, `password` TEXT NOT NULL, `primary` INTEGER NOT NULL, `synchronize` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "host", - "columnName": "host", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "port", - "columnName": "port", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "user", - "columnName": "user", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "password", - "columnName": "password", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "primary", - "columnName": "primary", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "synchronize", - "columnName": "synchronize", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "folder", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `account` INTEGER, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `synchronize` INTEGER NOT NULL, `after` INTEGER NOT NULL, FOREIGN KEY(`account`) REFERENCES `account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "account", - "columnName": "account", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "synchronize", - "columnName": "synchronize", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "after", - "columnName": "after", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [ - { - "name": "index_folder_account_name", - "unique": true, - "columnNames": [ - "account", - "name" - ], - "createSql": "CREATE UNIQUE INDEX `index_folder_account_name` ON `${TABLE_NAME}` (`account`, `name`)" - }, - { - "name": "index_folder_account", - "unique": false, - "columnNames": [ - "account" - ], - "createSql": "CREATE INDEX `index_folder_account` ON `${TABLE_NAME}` (`account`)" - }, - { - "name": "index_folder_name", - "unique": false, - "columnNames": [ - "name" - ], - "createSql": "CREATE INDEX `index_folder_name` ON `${TABLE_NAME}` (`name`)" - }, - { - "name": "index_folder_type", - "unique": false, - "columnNames": [ - "type" - ], - "createSql": "CREATE INDEX `index_folder_type` ON `${TABLE_NAME}` (`type`)" - } - ], - "foreignKeys": [ - { - "table": "account", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "account" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "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, `seen` INTEGER NOT NULL, `ui_seen` INTEGER NOT NULL, `ui_hide` INTEGER NOT NULL, 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", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "account", - "columnName": "account", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "folder", - "columnName": "folder", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "identity", - "columnName": "identity", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "replying", - "columnName": "replying", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "uid", - "columnName": "uid", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "msgid", - "columnName": "msgid", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "references", - "columnName": "references", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "inreplyto", - "columnName": "inreplyto", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "thread", - "columnName": "thread", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "from", - "columnName": "from", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "to", - "columnName": "to", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "cc", - "columnName": "cc", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "bcc", - "columnName": "bcc", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "reply", - "columnName": "reply", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "subject", - "columnName": "subject", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "body", - "columnName": "body", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "sent", - "columnName": "sent", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "received", - "columnName": "received", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "seen", - "columnName": "seen", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "ui_seen", - "columnName": "ui_seen", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "ui_hide", - "columnName": "ui_hide", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [ - { - "name": "index_message_account", - "unique": false, - "columnNames": [ - "account" - ], - "createSql": "CREATE INDEX `index_message_account` ON `${TABLE_NAME}` (`account`)" - }, - { - "name": "index_message_folder", - "unique": false, - "columnNames": [ - "folder" - ], - "createSql": "CREATE INDEX `index_message_folder` ON `${TABLE_NAME}` (`folder`)" - }, - { - "name": "index_message_identity", - "unique": false, - "columnNames": [ - "identity" - ], - "createSql": "CREATE INDEX `index_message_identity` ON `${TABLE_NAME}` (`identity`)" - }, - { - "name": "index_message_replying", - "unique": false, - "columnNames": [ - "replying" - ], - "createSql": "CREATE INDEX `index_message_replying` ON `${TABLE_NAME}` (`replying`)" - }, - { - "name": "index_message_folder_uid", - "unique": true, - "columnNames": [ - "folder", - "uid" - ], - "createSql": "CREATE UNIQUE INDEX `index_message_folder_uid` ON `${TABLE_NAME}` (`folder`, `uid`)" - }, - { - "name": "index_message_thread", - "unique": false, - "columnNames": [ - "thread" - ], - "createSql": "CREATE INDEX `index_message_thread` ON `${TABLE_NAME}` (`thread`)" - }, - { - "name": "index_message_received", - "unique": false, - "columnNames": [ - "received" - ], - "createSql": "CREATE INDEX `index_message_received` ON `${TABLE_NAME}` (`received`)" - }, - { - "name": "index_message_ui_seen", - "unique": false, - "columnNames": [ - "ui_seen" - ], - "createSql": "CREATE INDEX `index_message_ui_seen` ON `${TABLE_NAME}` (`ui_seen`)" - } - ], - "foreignKeys": [ - { - "table": "account", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "account" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "folder", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "folder" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "identity", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "identity" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "message", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "replying" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "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, `content` BLOB, FOREIGN KEY(`message`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "message", - "columnName": "message", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "sequence", - "columnName": "sequence", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "size", - "columnName": "size", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "progress", - "columnName": "progress", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "content", - "columnName": "content", - "affinity": "BLOB", - "notNull": false - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [ - { - "name": "index_attachment_message", - "unique": false, - "columnNames": [ - "message" - ], - "createSql": "CREATE INDEX `index_attachment_message` ON `${TABLE_NAME}` (`message`)" - }, - { - "name": "index_attachment_message_sequence", - "unique": true, - "columnNames": [ - "message", - "sequence" - ], - "createSql": "CREATE UNIQUE INDEX `index_attachment_message_sequence` ON `${TABLE_NAME}` (`message`, `sequence`)" - } - ], - "foreignKeys": [ - { - "table": "message", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "message" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "operation", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `message` INTEGER NOT NULL, `name` TEXT NOT NULL, `args` TEXT, FOREIGN KEY(`message`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "message", - "columnName": "message", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "args", - "columnName": "args", - "affinity": "TEXT", - "notNull": false - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [ - { - "name": "index_operation_message", - "unique": false, - "columnNames": [ - "message" - ], - "createSql": "CREATE INDEX `index_operation_message` ON `${TABLE_NAME}` (`message`)" - } - ], - "foreignKeys": [ - { - "table": "message", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "message" - ], - "referencedColumns": [ - "id" - ] - } - ] - } - ], - "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, \"ed5cc04cd8d171bff391cd8435cc29fe\")" - ] - } -} \ No newline at end of file diff --git a/app/schemas/eu.faircode.email.DB/5.json b/app/schemas/eu.faircode.email.DB/5.json deleted file mode 100644 index 149077d68e..0000000000 --- a/app/schemas/eu.faircode.email.DB/5.json +++ /dev/null @@ -1,667 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 5, - "identityHash": "b14a2bd7371400904e10cb3dd32a5d98", - "entities": [ - { - "tableName": "identity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT NOT NULL, `email` TEXT NOT NULL, `replyto` TEXT, `host` TEXT NOT NULL, `port` INTEGER NOT NULL, `starttls` INTEGER NOT NULL, `user` TEXT NOT NULL, `password` TEXT NOT NULL, `primary` INTEGER NOT NULL, `synchronize` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "replyto", - "columnName": "replyto", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "host", - "columnName": "host", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "port", - "columnName": "port", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "starttls", - "columnName": "starttls", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "user", - "columnName": "user", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "password", - "columnName": "password", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "primary", - "columnName": "primary", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "synchronize", - "columnName": "synchronize", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "account", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `host` TEXT NOT NULL, `port` INTEGER NOT NULL, `user` TEXT NOT NULL, `password` TEXT NOT NULL, `primary` INTEGER NOT NULL, `synchronize` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "host", - "columnName": "host", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "port", - "columnName": "port", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "user", - "columnName": "user", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "password", - "columnName": "password", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "primary", - "columnName": "primary", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "synchronize", - "columnName": "synchronize", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "folder", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `account` INTEGER, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `synchronize` INTEGER NOT NULL, `after` INTEGER NOT NULL, FOREIGN KEY(`account`) REFERENCES `account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "account", - "columnName": "account", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "synchronize", - "columnName": "synchronize", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "after", - "columnName": "after", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [ - { - "name": "index_folder_account_name", - "unique": true, - "columnNames": [ - "account", - "name" - ], - "createSql": "CREATE UNIQUE INDEX `index_folder_account_name` ON `${TABLE_NAME}` (`account`, `name`)" - }, - { - "name": "index_folder_account", - "unique": false, - "columnNames": [ - "account" - ], - "createSql": "CREATE INDEX `index_folder_account` ON `${TABLE_NAME}` (`account`)" - }, - { - "name": "index_folder_name", - "unique": false, - "columnNames": [ - "name" - ], - "createSql": "CREATE INDEX `index_folder_name` ON `${TABLE_NAME}` (`name`)" - }, - { - "name": "index_folder_type", - "unique": false, - "columnNames": [ - "type" - ], - "createSql": "CREATE INDEX `index_folder_type` ON `${TABLE_NAME}` (`type`)" - } - ], - "foreignKeys": [ - { - "table": "account", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "account" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "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, `seen` INTEGER NOT NULL, `ui_seen` INTEGER NOT NULL, `ui_hide` INTEGER NOT NULL, 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", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "account", - "columnName": "account", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "folder", - "columnName": "folder", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "identity", - "columnName": "identity", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "replying", - "columnName": "replying", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "uid", - "columnName": "uid", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "msgid", - "columnName": "msgid", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "references", - "columnName": "references", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "inreplyto", - "columnName": "inreplyto", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "thread", - "columnName": "thread", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "from", - "columnName": "from", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "to", - "columnName": "to", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "cc", - "columnName": "cc", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "bcc", - "columnName": "bcc", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "reply", - "columnName": "reply", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "subject", - "columnName": "subject", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "body", - "columnName": "body", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "sent", - "columnName": "sent", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "received", - "columnName": "received", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "seen", - "columnName": "seen", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "ui_seen", - "columnName": "ui_seen", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "ui_hide", - "columnName": "ui_hide", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [ - { - "name": "index_message_account", - "unique": false, - "columnNames": [ - "account" - ], - "createSql": "CREATE INDEX `index_message_account` ON `${TABLE_NAME}` (`account`)" - }, - { - "name": "index_message_folder", - "unique": false, - "columnNames": [ - "folder" - ], - "createSql": "CREATE INDEX `index_message_folder` ON `${TABLE_NAME}` (`folder`)" - }, - { - "name": "index_message_identity", - "unique": false, - "columnNames": [ - "identity" - ], - "createSql": "CREATE INDEX `index_message_identity` ON `${TABLE_NAME}` (`identity`)" - }, - { - "name": "index_message_replying", - "unique": false, - "columnNames": [ - "replying" - ], - "createSql": "CREATE INDEX `index_message_replying` ON `${TABLE_NAME}` (`replying`)" - }, - { - "name": "index_message_folder_uid", - "unique": true, - "columnNames": [ - "folder", - "uid" - ], - "createSql": "CREATE UNIQUE INDEX `index_message_folder_uid` ON `${TABLE_NAME}` (`folder`, `uid`)" - }, - { - "name": "index_message_thread", - "unique": false, - "columnNames": [ - "thread" - ], - "createSql": "CREATE INDEX `index_message_thread` ON `${TABLE_NAME}` (`thread`)" - }, - { - "name": "index_message_received", - "unique": false, - "columnNames": [ - "received" - ], - "createSql": "CREATE INDEX `index_message_received` ON `${TABLE_NAME}` (`received`)" - }, - { - "name": "index_message_ui_seen", - "unique": false, - "columnNames": [ - "ui_seen" - ], - "createSql": "CREATE INDEX `index_message_ui_seen` ON `${TABLE_NAME}` (`ui_seen`)" - }, - { - "name": "index_message_ui_hide", - "unique": false, - "columnNames": [ - "ui_hide" - ], - "createSql": "CREATE INDEX `index_message_ui_hide` ON `${TABLE_NAME}` (`ui_hide`)" - } - ], - "foreignKeys": [ - { - "table": "account", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "account" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "folder", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "folder" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "identity", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "identity" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "message", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "replying" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "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, `content` BLOB, FOREIGN KEY(`message`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "message", - "columnName": "message", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "sequence", - "columnName": "sequence", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "size", - "columnName": "size", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "progress", - "columnName": "progress", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "content", - "columnName": "content", - "affinity": "BLOB", - "notNull": false - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [ - { - "name": "index_attachment_message", - "unique": false, - "columnNames": [ - "message" - ], - "createSql": "CREATE INDEX `index_attachment_message` ON `${TABLE_NAME}` (`message`)" - }, - { - "name": "index_attachment_message_sequence", - "unique": true, - "columnNames": [ - "message", - "sequence" - ], - "createSql": "CREATE UNIQUE INDEX `index_attachment_message_sequence` ON `${TABLE_NAME}` (`message`, `sequence`)" - } - ], - "foreignKeys": [ - { - "table": "message", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "message" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "operation", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `message` INTEGER NOT NULL, `name` TEXT NOT NULL, `args` TEXT, FOREIGN KEY(`message`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "message", - "columnName": "message", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "args", - "columnName": "args", - "affinity": "TEXT", - "notNull": false - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [ - { - "name": "index_operation_message", - "unique": false, - "columnNames": [ - "message" - ], - "createSql": "CREATE INDEX `index_operation_message` ON `${TABLE_NAME}` (`message`)" - } - ], - "foreignKeys": [ - { - "table": "message", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "message" - ], - "referencedColumns": [ - "id" - ] - } - ] - } - ], - "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, \"b14a2bd7371400904e10cb3dd32a5d98\")" - ] - } -} \ No newline at end of file diff --git a/app/schemas/eu.faircode.email.DB/6.json b/app/schemas/eu.faircode.email.DB/6.json deleted file mode 100644 index 1eed7e426b..0000000000 --- a/app/schemas/eu.faircode.email.DB/6.json +++ /dev/null @@ -1,673 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 6, - "identityHash": "5b850d93ed77b9df16fbe138b3fb2475", - "entities": [ - { - "tableName": "identity", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT NOT NULL, `email` TEXT NOT NULL, `replyto` TEXT, `host` TEXT NOT NULL, `port` INTEGER NOT NULL, `starttls` INTEGER NOT NULL, `user` TEXT NOT NULL, `password` TEXT NOT NULL, `primary` INTEGER NOT NULL, `synchronize` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "email", - "columnName": "email", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "replyto", - "columnName": "replyto", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "host", - "columnName": "host", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "port", - "columnName": "port", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "starttls", - "columnName": "starttls", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "user", - "columnName": "user", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "password", - "columnName": "password", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "primary", - "columnName": "primary", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "synchronize", - "columnName": "synchronize", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "account", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `host` TEXT NOT NULL, `port` INTEGER NOT NULL, `user` TEXT NOT NULL, `password` TEXT NOT NULL, `primary` INTEGER NOT NULL, `synchronize` INTEGER NOT NULL, `seen_until` INTEGER)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "host", - "columnName": "host", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "port", - "columnName": "port", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "user", - "columnName": "user", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "password", - "columnName": "password", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "primary", - "columnName": "primary", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "synchronize", - "columnName": "synchronize", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "seen_until", - "columnName": "seen_until", - "affinity": "INTEGER", - "notNull": false - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "folder", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `account` INTEGER, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `synchronize` INTEGER NOT NULL, `after` INTEGER NOT NULL, FOREIGN KEY(`account`) REFERENCES `account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "account", - "columnName": "account", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "synchronize", - "columnName": "synchronize", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "after", - "columnName": "after", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [ - { - "name": "index_folder_account_name", - "unique": true, - "columnNames": [ - "account", - "name" - ], - "createSql": "CREATE UNIQUE INDEX `index_folder_account_name` ON `${TABLE_NAME}` (`account`, `name`)" - }, - { - "name": "index_folder_account", - "unique": false, - "columnNames": [ - "account" - ], - "createSql": "CREATE INDEX `index_folder_account` ON `${TABLE_NAME}` (`account`)" - }, - { - "name": "index_folder_name", - "unique": false, - "columnNames": [ - "name" - ], - "createSql": "CREATE INDEX `index_folder_name` ON `${TABLE_NAME}` (`name`)" - }, - { - "name": "index_folder_type", - "unique": false, - "columnNames": [ - "type" - ], - "createSql": "CREATE INDEX `index_folder_type` ON `${TABLE_NAME}` (`type`)" - } - ], - "foreignKeys": [ - { - "table": "account", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "account" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "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, `seen` INTEGER NOT NULL, `ui_seen` INTEGER NOT NULL, `ui_hide` INTEGER NOT NULL, 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", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "account", - "columnName": "account", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "folder", - "columnName": "folder", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "identity", - "columnName": "identity", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "replying", - "columnName": "replying", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "uid", - "columnName": "uid", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "msgid", - "columnName": "msgid", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "references", - "columnName": "references", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "inreplyto", - "columnName": "inreplyto", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "thread", - "columnName": "thread", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "from", - "columnName": "from", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "to", - "columnName": "to", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "cc", - "columnName": "cc", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "bcc", - "columnName": "bcc", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "reply", - "columnName": "reply", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "subject", - "columnName": "subject", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "body", - "columnName": "body", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "sent", - "columnName": "sent", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "received", - "columnName": "received", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "seen", - "columnName": "seen", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "ui_seen", - "columnName": "ui_seen", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "ui_hide", - "columnName": "ui_hide", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [ - { - "name": "index_message_account", - "unique": false, - "columnNames": [ - "account" - ], - "createSql": "CREATE INDEX `index_message_account` ON `${TABLE_NAME}` (`account`)" - }, - { - "name": "index_message_folder", - "unique": false, - "columnNames": [ - "folder" - ], - "createSql": "CREATE INDEX `index_message_folder` ON `${TABLE_NAME}` (`folder`)" - }, - { - "name": "index_message_identity", - "unique": false, - "columnNames": [ - "identity" - ], - "createSql": "CREATE INDEX `index_message_identity` ON `${TABLE_NAME}` (`identity`)" - }, - { - "name": "index_message_replying", - "unique": false, - "columnNames": [ - "replying" - ], - "createSql": "CREATE INDEX `index_message_replying` ON `${TABLE_NAME}` (`replying`)" - }, - { - "name": "index_message_folder_uid", - "unique": true, - "columnNames": [ - "folder", - "uid" - ], - "createSql": "CREATE UNIQUE INDEX `index_message_folder_uid` ON `${TABLE_NAME}` (`folder`, `uid`)" - }, - { - "name": "index_message_thread", - "unique": false, - "columnNames": [ - "thread" - ], - "createSql": "CREATE INDEX `index_message_thread` ON `${TABLE_NAME}` (`thread`)" - }, - { - "name": "index_message_received", - "unique": false, - "columnNames": [ - "received" - ], - "createSql": "CREATE INDEX `index_message_received` ON `${TABLE_NAME}` (`received`)" - }, - { - "name": "index_message_ui_seen", - "unique": false, - "columnNames": [ - "ui_seen" - ], - "createSql": "CREATE INDEX `index_message_ui_seen` ON `${TABLE_NAME}` (`ui_seen`)" - }, - { - "name": "index_message_ui_hide", - "unique": false, - "columnNames": [ - "ui_hide" - ], - "createSql": "CREATE INDEX `index_message_ui_hide` ON `${TABLE_NAME}` (`ui_hide`)" - } - ], - "foreignKeys": [ - { - "table": "account", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "account" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "folder", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "folder" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "identity", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "identity" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "message", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "replying" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "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, `content` BLOB, FOREIGN KEY(`message`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "message", - "columnName": "message", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "sequence", - "columnName": "sequence", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "size", - "columnName": "size", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "progress", - "columnName": "progress", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "content", - "columnName": "content", - "affinity": "BLOB", - "notNull": false - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [ - { - "name": "index_attachment_message", - "unique": false, - "columnNames": [ - "message" - ], - "createSql": "CREATE INDEX `index_attachment_message` ON `${TABLE_NAME}` (`message`)" - }, - { - "name": "index_attachment_message_sequence", - "unique": true, - "columnNames": [ - "message", - "sequence" - ], - "createSql": "CREATE UNIQUE INDEX `index_attachment_message_sequence` ON `${TABLE_NAME}` (`message`, `sequence`)" - } - ], - "foreignKeys": [ - { - "table": "message", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "message" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "operation", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `message` INTEGER NOT NULL, `name` TEXT NOT NULL, `args` TEXT, FOREIGN KEY(`message`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "message", - "columnName": "message", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "args", - "columnName": "args", - "affinity": "TEXT", - "notNull": false - } - ], - "primaryKey": { - "columnNames": [ - "id" - ], - "autoGenerate": true - }, - "indices": [ - { - "name": "index_operation_message", - "unique": false, - "columnNames": [ - "message" - ], - "createSql": "CREATE INDEX `index_operation_message` ON `${TABLE_NAME}` (`message`)" - } - ], - "foreignKeys": [ - { - "table": "message", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "message" - ], - "referencedColumns": [ - "id" - ] - } - ] - } - ], - "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, \"5b850d93ed77b9df16fbe138b3fb2475\")" - ] - } -} \ No newline at end of file diff --git a/app/src/main/java/eu/faircode/email/ActivityView.java b/app/src/main/java/eu/faircode/email/ActivityView.java index c191fcb058..bd10b63350 100644 --- a/app/src/main/java/eu/faircode/email/ActivityView.java +++ b/app/src/main/java/eu/faircode/email/ActivityView.java @@ -38,6 +38,7 @@ import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; +import android.widget.Toast; import java.text.Collator; import java.util.Collections; @@ -45,8 +46,6 @@ import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Locale; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -62,13 +61,17 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack private DrawerLayout drawerLayout; private ListView drawerList; private ActionBarDrawerToggle drawerToggle; - private ExecutorService executor = Executors.newSingleThreadExecutor(); static final int LOADER_ACCOUNT_PUT = 1; static final int LOADER_IDENTITY_PUT = 2; static final int LOADER_FOLDER_PUT = 3; - static final int LOADER_MESSAGES_INIT = 4; - static final int LOADER_MESSAGE_MOVE = 5; + static final int LOADER_MESSAGE_SEEN = 4; + static final int LOADER_MESSAGE_EDIT = 5; + static final int LOADER_MESSAGE_SPAM = 6; + static final int LOADER_MESSAGE_TRASH = 7; + static final int LOADER_MESSAGE_MOVE = 8; + static final int LOADER_MESSAGE_ARCHIVE = 9; + static final int LOADER_SEEN_UNTIL = 10; static final int REQUEST_VIEW = 1; static final int REQUEST_UNSEEN = 2; @@ -271,19 +274,27 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack setIntent(intent); if ("unseen".equals(action)) { - final long now = new Date().getTime(); + Bundle args = new Bundle(); + args.putLong("time", new Date().getTime()); - executor.submit(new Runnable() { + new SimpleLoader() { @Override - public void run() { + public Object onLoad(Bundle args) { + long time = args.getLong("time"); DaoAccount dao = DB.getInstance(ActivityView.this).account(); for (EntityAccount account : dao.getAccounts(true)) { - account.seen_until = now; + account.seen_until = time; dao.updateAccount(account); } - Log.i(Helper.TAG, "Updated seen until"); + return null; } - }); + + @Override + public void onLoaded(Bundle args, Result result) { + if (result.ex != null) + Toast.makeText(ActivityView.this, result.ex.toString(), Toast.LENGTH_LONG).show(); + } + }.load(this, LOADER_SEEN_UNTIL, args); } } @@ -420,11 +431,50 @@ public class ActivityView extends ActivityBase implements FragmentManager.OnBack fragmentTransaction.replace(R.id.content_frame, fragment).addToBackStack("messages"); fragmentTransaction.commit(); } else if (ACTION_VIEW_MESSAGE.equals(intent.getAction())) { - FragmentMessage fragment = new FragmentMessage(); - fragment.setArguments(intent.getExtras()); - FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); - fragmentTransaction.replace(R.id.content_frame, fragment).addToBackStack("message"); - fragmentTransaction.commit(); + + new SimpleLoader() { + @Override + public Object onLoad(Bundle args) { + long id = args.getLong("id"); + DB db = DB.getInstance(ActivityView.this); + EntityMessage message = db.message().getMessage(id); + EntityFolder folder = db.folder().getFolder(message.folder); + if (!EntityFolder.OUTBOX.equals(folder.type)) { + if (!message.seen && !message.ui_seen) { + try { + db.beginTransaction(); + + message.ui_seen = !message.ui_seen; + db.message().updateMessage(message); + + if (message.uid != null) + EntityOperation.queue(db, message, EntityOperation.SEEN, message.ui_seen); + + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + + EntityOperation.process(ActivityView.this); + } + } + + return null; + } + + @Override + public void onLoaded(Bundle args, Result result) { + if (result.ex == null) { + FragmentMessage fragment = new FragmentMessage(); + fragment.setArguments(args); + FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); + fragmentTransaction.replace(R.id.content_frame, fragment).addToBackStack("message"); + fragmentTransaction.commit(); + } else + Toast.makeText(ActivityView.this, result.ex.toString(), Toast.LENGTH_LONG).show(); + } + }.load(ActivityView.this, 0000, intent.getExtras()); + } else if (ACTION_EDIT_FOLDER.equals(intent.getAction())) { FragmentFolder fragment = new FragmentFolder(); fragment.setArguments(intent.getExtras()); diff --git a/app/src/main/java/eu/faircode/email/AdapterAttachment.java b/app/src/main/java/eu/faircode/email/AdapterAttachment.java index 0b3202afb7..fd52321927 100644 --- a/app/src/main/java/eu/faircode/email/AdapterAttachment.java +++ b/app/src/main/java/eu/faircode/email/AdapterAttachment.java @@ -177,10 +177,12 @@ public class AdapterAttachment extends RecyclerView.Adapter getOperations(long folder); - - @Query("SELECT COUNT(operation.id) FROM operation" + - " JOIN message ON message.id = operation.message" + - " WHERE folder = :folder") + @Query("SELECT * FROM operation WHERE folder = :folder ORDER BY id") + List getOperations(long folder); + + @Query("SELECT COUNT(id) FROM operation WHERE folder = :folder") int getOperationCount(long folder); @Query("DELETE FROM operation WHERE id = :id") diff --git a/app/src/main/java/eu/faircode/email/EntityOperation.java b/app/src/main/java/eu/faircode/email/EntityOperation.java index c59b83d635..f4afa1e2d9 100644 --- a/app/src/main/java/eu/faircode/email/EntityOperation.java +++ b/app/src/main/java/eu/faircode/email/EntityOperation.java @@ -40,6 +40,7 @@ import static androidx.room.ForeignKey.CASCADE; @Entity( tableName = EntityOperation.TABLE_NAME, foreignKeys = { + @ForeignKey(childColumns = "folder", entity = EntityFolder.class, parentColumns = "id", onDelete = CASCADE), @ForeignKey(childColumns = "message", entity = EntityMessage.class, parentColumns = "id", onDelete = CASCADE) }, indices = { @@ -52,6 +53,8 @@ public class EntityOperation { @PrimaryKey(autoGenerate = true) public Long id; @NonNull + public Long folder; + @NonNull public Long message; @NonNull public String name; @@ -66,25 +69,31 @@ public class EntityOperation { private static List queue = new ArrayList<>(); - static void queue(Context context, EntityMessage message, String name) { + static void queue(DB db, EntityMessage message, String name) { JSONArray jsonArray = new JSONArray(); - queue(context, message, name, jsonArray); + queue(db, message, name, jsonArray); } - static void queue(Context context, EntityMessage message, String name, Object value) { + static void queue(DB db, EntityMessage message, String name, Object value) { JSONArray jsonArray = new JSONArray(); jsonArray.put(value); - queue(context, message, name, jsonArray); + queue(db, message, name, jsonArray); } - private static void queue(Context context, EntityMessage message, String name, JSONArray jsonArray) { - DaoOperation dao = DB.getInstance(context).operation(); + static void queue(DB db, EntityMessage message, String name, Object value1, Object value2) { + JSONArray jsonArray = new JSONArray(); + jsonArray.put(value1); + jsonArray.put(value2); + queue(db, message, name, jsonArray); + } + private static void queue(DB db, EntityMessage message, String name, JSONArray jsonArray) { EntityOperation operation = new EntityOperation(); + operation.folder = message.folder; operation.message = message.id; operation.name = name; operation.args = jsonArray.toString(); - operation.id = dao.insertOperation(operation); + operation.id = db.operation().insertOperation(operation); Intent intent = new Intent(); if (SEND.equals(name)) @@ -99,9 +108,9 @@ public class EntityOperation { queue.add(intent); } - Log.i(Helper.TAG, "Queued op=" + operation.id + "/" + name + - " args=" + operation.args + - " msg=" + message.folder + "/" + message.id + " uid=" + message.uid); + Log.i(Helper.TAG, "Queued op=" + operation.id + "/" + operation.name + + " msg=" + message.folder + "/" + operation.message + + " args=" + operation.args); } public static void process(Context context) { diff --git a/app/src/main/java/eu/faircode/email/FragmentAbout.java b/app/src/main/java/eu/faircode/email/FragmentAbout.java index 2d2e74963d..cb9eb73a5c 100644 --- a/app/src/main/java/eu/faircode/email/FragmentAbout.java +++ b/app/src/main/java/eu/faircode/email/FragmentAbout.java @@ -80,9 +80,6 @@ public class FragmentAbout extends FragmentEx { draft.ui_hide = false; draft.id = db.message().insertMessage(draft); - EntityOperation.queue(getContext(), draft, EntityOperation.ADD); - EntityOperation.process(getContext()); - startActivity(new Intent(getContext(), ActivityCompose.class) .putExtra("id", draft.id)); } diff --git a/app/src/main/java/eu/faircode/email/FragmentCompose.java b/app/src/main/java/eu/faircode/email/FragmentCompose.java index 1259f33ee2..ef9bd4b2b3 100644 --- a/app/src/main/java/eu/faircode/email/FragmentCompose.java +++ b/app/src/main/java/eu/faircode/email/FragmentCompose.java @@ -329,10 +329,10 @@ public class FragmentCompose extends FragmentEx { try { String action = args.getString("action"); long id = args.getLong("id", -1); - EntityMessage msg = DB.getInstance(getContext()).message().getMessage(id); result.putString("action", action); + EntityMessage msg = DB.getInstance(getContext()).message().getMessage(id); if (msg != null) { if (msg.identity != null) result.putLong("iid", msg.identity); @@ -550,47 +550,72 @@ public class FragmentCompose extends FragmentEx { draft.received = new Date().getTime(); draft.seen = false; draft.ui_seen = false; - draft.ui_hide = !"save".equals(action); + draft.ui_hide = false; // Store draft - if (update) - message.updateMessage(draft); - else + if (!update) draft.id = message.insertMessage(draft); // Check data try { db.beginTransaction(); - if ("send".equals(action)) { - if (draft.to == null && draft.cc == null && draft.bcc == null) - throw new IllegalArgumentException(getContext().getString(R.string.title_to_missing)); - EntityOperation.queue(getContext(), draft, EntityOperation.DELETE); + if ("save".equals(action)) { + // Delete previous draft + if (draft.uid == null) + db.message().deleteMessage(draft.id); + else { + draft.ui_hide = true; + db.message().updateMessage(draft); + EntityOperation.queue(db, draft, EntityOperation.DELETE); + } + // Create new draft draft.id = null; - draft.folder = folder.getOutbox().id; + draft.uid = null; draft.ui_hide = false; draft.id = db.message().insertMessage(draft); + EntityOperation.queue(db, draft, EntityOperation.ADD); - EntityOperation.queue(getContext(), draft, EntityOperation.SEND); + } else if ("trash".equals(action)) { + EntityFolder trash = db.folder().getFolderByType(ident.account, EntityFolder.TRASH); - } else if ("save".equals(action)) - EntityOperation.queue(getContext(), draft, EntityOperation.ADD); + boolean move = (draft.uid != null); + if (move) + EntityOperation.queue(db, draft, EntityOperation.MOVE, trash.id, draft.uid); - else if ("trash".equals(action)) { - EntityOperation.queue(getContext(), draft, EntityOperation.DELETE); + draft.folder = trash.id; + draft.uid = null; + db.message().updateMessage(draft); - EntityFolder trash = db.folder().getFolderByType(ident.account, EntityFolder.TRASH); - if (trash != null) { - draft.id = null; - draft.folder = trash.id; - draft.id = db.message().insertMessage(draft); + if (!move) + EntityOperation.queue(db, draft, EntityOperation.ADD); + + } else if ("send".equals(action)) { + if (draft.to == null && draft.cc == null && draft.bcc == null) + throw new IllegalArgumentException(getContext().getString(R.string.title_to_missing)); - EntityOperation.queue(getContext(), draft, EntityOperation.ADD); + // Delete draft (cannot move to outbox) + if (draft.uid == null) + db.message().deleteMessage(draft.id); + else { + draft.ui_hide = true; + db.message().updateMessage(draft); + EntityOperation.queue(db, draft, EntityOperation.DELETE); } + + // Copy message to outbox + draft.id = null; + draft.folder = folder.getOutbox().id; + draft.uid = null; + draft.ui_hide = false; + draft.id = db.message().insertMessage(draft); + + EntityOperation.queue(db, draft, EntityOperation.SEND); } + db.setTransactionSuccessful(); } finally { db.endTransaction(); @@ -625,17 +650,20 @@ public class FragmentCompose extends FragmentEx { String action = args.getString("action"); Log.i(Helper.TAG, "Put finished action=" + action + " ex=" + ex); + bottom_navigation.getMenu().setGroupEnabled(0, true); + if (ex == null) { - getFragmentManager().popBackStack(); - if ("trash".equals(action)) + if ("trash".equals(action)) { + getFragmentManager().popBackStack(); Toast.makeText(getContext(), R.string.title_draft_trashed, Toast.LENGTH_LONG).show(); - else if ("save".equals(action)) + } else if ("save".equals(action)) Toast.makeText(getContext(), R.string.title_draft_saved, Toast.LENGTH_LONG).show(); - else if ("send".equals(action)) + else if ("send".equals(action)) { + getFragmentManager().popBackStack(); Toast.makeText(getContext(), R.string.title_queued, Toast.LENGTH_LONG).show(); + } } else { Log.w(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); - bottom_navigation.getMenu().setGroupEnabled(0, true); Toast.makeText(getContext(), Helper.formatThrowable(ex), Toast.LENGTH_LONG).show(); } } diff --git a/app/src/main/java/eu/faircode/email/FragmentMessage.java b/app/src/main/java/eu/faircode/email/FragmentMessage.java index 527b868ead..5b49da6943 100644 --- a/app/src/main/java/eu/faircode/email/FragmentMessage.java +++ b/app/src/main/java/eu/faircode/email/FragmentMessage.java @@ -23,6 +23,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Typeface; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.preference.PreferenceManager; @@ -32,7 +33,6 @@ import android.text.Spannable; import android.text.TextUtils; import android.text.method.LinkMovementMethod; import android.text.style.URLSpan; -import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -42,6 +42,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; import android.widget.TextView; +import android.widget.Toast; import com.google.android.material.bottomnavigation.BottomNavigationView; @@ -53,8 +54,6 @@ import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Locale; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -90,7 +89,6 @@ public class FragmentMessage extends FragmentEx { private AdapterAttachment adapter; - private ExecutorService executor = Executors.newCachedThreadPool(); private DateFormat df = SimpleDateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); @Override @@ -257,13 +255,15 @@ public class FragmentMessage extends FragmentEx { } else { setSubtitle(Helper.localizeFolderName(getContext(), message.folderName)); + String extra = (debug ? (message.ui_hide ? "HIDDEN " : "") + message.uid + "/" + message.id + " " : ""); + tvFrom.setText(message.from == null ? null : TextUtils.join(", ", message.from)); tvTo.setText(message.to == null ? null : TextUtils.join(", ", message.to)); tvCc.setText(message.cc == null ? null : TextUtils.join(", ", message.cc)); tvBcc.setText(message.bcc == null ? null : TextUtils.join(", ", message.bcc)); tvTime.setText(message.sent == null ? null : df.format(new Date(message.sent))); tvSubject.setText(message.subject); - tvCount.setText(Integer.toString(message.count)); + tvCount.setText(extra + Integer.toString(message.count)); tvCount.setVisibility(debug || message.count > 1 ? View.VISIBLE : View.GONE); int typeface = (message.ui_seen ? Typeface.NORMAL : Typeface.BOLD); @@ -297,19 +297,17 @@ public class FragmentMessage extends FragmentEx { ? null : Html.fromHtml(HtmlHelper.sanitize(getContext(), message.body, false))); - bottom_navigation.setTag(message.folderType); - db.folder().liveFolders(message.account).removeObservers(getViewLifecycleOwner()); db.folder().liveFolders(message.account).observe(getViewLifecycleOwner(), new Observer>() { @Override public void onChanged(@Nullable final List folders) { - boolean inbox = EntityFolder.INBOX.equals(message.folderType); - boolean outbox = EntityFolder.OUTBOX.equals(message.folderType); - boolean archive = EntityFolder.ARCHIVE.equals(message.folderType); - boolean drafts = EntityFolder.DRAFTS.equals(message.folderType); - boolean trash = EntityFolder.TRASH.equals(message.folderType); - boolean junk = EntityFolder.JUNK.equals(message.folderType); - boolean sent = EntityFolder.SENT.equals(message.folderType); + boolean inInbox = EntityFolder.INBOX.equals(message.folderType); + boolean inOutbox = EntityFolder.OUTBOX.equals(message.folderType); + boolean inArchive = EntityFolder.ARCHIVE.equals(message.folderType); + //boolean inDafts = EntityFolder.DRAFTS.equals(message.folderType); + boolean inTrash = EntityFolder.TRASH.equals(message.folderType); + boolean inJunk = EntityFolder.JUNK.equals(message.folderType); + //boolean inSent = EntityFolder.SENT.equals(message.folderType); boolean hasTrash = false; boolean hasJunk = false; @@ -326,18 +324,20 @@ public class FragmentMessage extends FragmentEx { hasUser = true; } + bottom_navigation.setTag(inTrash || !hasTrash); + top_navigation.getMenu().findItem(R.id.action_thread).setVisible(message.count > 1); - top_navigation.getMenu().findItem(R.id.action_seen).setVisible(!outbox); - top_navigation.getMenu().findItem(R.id.action_edit).setVisible(trash); - top_navigation.getMenu().findItem(R.id.action_forward).setVisible(!outbox); - top_navigation.getMenu().findItem(R.id.action_reply_all).setVisible(!outbox && message.cc != null); + top_navigation.getMenu().findItem(R.id.action_seen).setVisible(!inOutbox); + top_navigation.getMenu().findItem(R.id.action_edit).setVisible(inTrash); + top_navigation.getMenu().findItem(R.id.action_forward).setVisible(!inOutbox); + top_navigation.getMenu().findItem(R.id.action_reply_all).setVisible(!inOutbox && message.cc != null); top_navigation.setVisibility(View.VISIBLE); - bottom_navigation.getMenu().findItem(R.id.action_spam).setVisible(!outbox && !junk && hasJunk); - bottom_navigation.getMenu().findItem(R.id.action_trash).setVisible(!outbox && !trash && hasTrash); - bottom_navigation.getMenu().findItem(R.id.action_move).setVisible(!outbox && (!inbox || hasUser)); - bottom_navigation.getMenu().findItem(R.id.action_archive).setVisible(!outbox && !archive && hasArchive); - bottom_navigation.getMenu().findItem(R.id.action_reply).setVisible(!outbox); + bottom_navigation.getMenu().findItem(R.id.action_spam).setVisible(!inOutbox && !inJunk && hasJunk); + bottom_navigation.getMenu().findItem(R.id.action_trash).setVisible(!inOutbox && hasTrash); + bottom_navigation.getMenu().findItem(R.id.action_move).setVisible(!inOutbox && (!inInbox || hasUser)); + bottom_navigation.getMenu().findItem(R.id.action_archive).setVisible(!inOutbox && !inArchive && hasArchive); + bottom_navigation.getMenu().findItem(R.id.action_reply).setVisible(!inOutbox); bottom_navigation.setVisibility(View.VISIBLE); } }); @@ -383,44 +383,89 @@ public class FragmentMessage extends FragmentEx { fragmentTransaction.commit(); } - private void onActionSeen(final long id) { - executor.submit(new Runnable() { + private void onActionSeen(long id) { + final MenuItem item = top_navigation.getMenu().findItem(R.id.action_seen); + item.setEnabled(false); + + final Drawable icon = item.getIcon(); + item.setIcon(Helper.toDimmed(icon)); + + Bundle args = new Bundle(); + args.putLong("id", id); + + new SimpleLoader() { @Override - public void run() { + public Object onLoad(Bundle args) { + long id = args.getLong("id"); + DB db = DB.getInstance(getContext()); try { - DB db = DB.getInstance(getContext()); + db.beginTransaction(); + EntityMessage message = db.message().getMessage(id); message.ui_seen = !message.ui_seen; db.message().updateMessage(message); - EntityOperation.queue(getContext(), message, EntityOperation.SEEN, message.ui_seen); - EntityOperation.process(getContext()); - } catch (Throwable ex) { - Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); + + if (message.uid != null) + EntityOperation.queue(db, message, EntityOperation.SEEN, message.ui_seen); + + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); } + + EntityOperation.process(getContext()); + + return null; } - }); + + @Override + public void onLoaded(Bundle args, Result result) { + item.setEnabled(true); + item.setIcon(icon); + + if (result.ex != null) + Toast.makeText(getContext(), result.ex.toString(), Toast.LENGTH_LONG).show(); + } + }.load(this, ActivityView.LOADER_MESSAGE_SEEN, args); } - private void onActionEdit(final long id) { - executor.submit(new Runnable() { + private void onActionEdit(long id) { + final MenuItem item = top_navigation.getMenu().findItem(R.id.action_edit); + item.setEnabled(false); + + final Drawable icon = item.getIcon(); + item.setIcon(Helper.toDimmed(icon)); + + Bundle args = new Bundle(); + args.putLong("id", id); + + new SimpleLoader() { @Override - public void run() { - try { - DB db = DB.getInstance(getContext()); - EntityMessage draft = db.message().getMessage(id); - EntityFolder drafts = EntityFolder.getDrafts(getContext(), db, draft.account); - draft.id = null; - draft.folder = drafts.id; - draft.id = db.message().insertMessage(draft); + public Object onLoad(Bundle args) { + long id = args.getLong("id"); + DB db = DB.getInstance(getContext()); + EntityMessage draft = db.message().getMessage(id); + EntityFolder drafts = EntityFolder.getDrafts(getContext(), db, draft.account); + draft.id = null; + draft.folder = drafts.id; + draft.uid = null; + draft.id = db.message().insertMessage(draft); + return id; + } + + @Override + public void onLoaded(Bundle args, Result result) { + item.setEnabled(true); + item.setIcon(icon); + if (result.ex == null) getContext().startActivity( new Intent(getContext(), ActivityCompose.class) - .putExtra("id", draft.id)); - } catch (Throwable ex) { - Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); - } + .putExtra("id", (long) result.data)); + else + Toast.makeText(getContext(), result.ex.toString(), Toast.LENGTH_LONG).show(); } - }); + }.load(this, ActivityView.LOADER_MESSAGE_EDIT, args); } private void onActionForward(long id) { @@ -442,102 +487,231 @@ public class FragmentMessage extends FragmentEx { .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - executor.submit(new Runnable() { + final MenuItem item = bottom_navigation.getMenu().findItem(R.id.action_spam); + item.setEnabled(false); + + final Drawable icon = item.getIcon(); + item.setIcon(Helper.toDimmed(icon)); + + Bundle args = new Bundle(); + args.putLong("id", id); + + new SimpleLoader() { @Override - public void run() { + public Object onLoad(Bundle args) { + long id = args.getLong("id"); + DB db = DB.getInstance(getContext()); try { - DB db = DB.getInstance(getContext()); + db.beginTransaction(); + EntityMessage message = db.message().getMessage(id); - message.ui_hide = true; + EntityFolder spam = db.folder().getFolderByType(message.account, EntityFolder.JUNK); + + boolean move = (message.uid != null); + if (move) + EntityOperation.queue(db, message, EntityOperation.MOVE, spam.id, message.uid); + + message.folder = spam.id; + message.uid = null; db.message().updateMessage(message); - EntityFolder spam = db.folder().getFolderByType(message.account, EntityFolder.JUNK); - EntityOperation.queue(getContext(), message, EntityOperation.MOVE, spam.id); - EntityOperation.process(getContext()); - } catch (Throwable ex) { - Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); + if (!move) + EntityOperation.queue(db, message, EntityOperation.ADD); + + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); } + + EntityOperation.process(getContext()); + + return null; + } + + @Override + public void onLoaded(Bundle args, Result result) { + item.setEnabled(true); + item.setIcon(icon); + + if (result.ex != null) + Toast.makeText(getContext(), result.ex.toString(), Toast.LENGTH_LONG).show(); } - }); + }.load(FragmentMessage.this, ActivityView.LOADER_MESSAGE_SPAM, args); } }) .setNegativeButton(android.R.string.cancel, null).show(); } private void onActionDelete(final long id) { - String folderType = (String) bottom_navigation.getTag(); - if (EntityFolder.TRASH.equals(folderType)) { + boolean delete = (Boolean) bottom_navigation.getTag(); + if (delete) { + // No trash or is trash AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); builder .setMessage(R.string.title_ask_delete) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - executor.submit(new Runnable() { + final MenuItem item = bottom_navigation.getMenu().findItem(R.id.action_trash); + item.setEnabled(false); + + final Drawable icon = item.getIcon(); + item.setIcon(Helper.toDimmed(icon)); + + Bundle args = new Bundle(); + args.putLong("id", id); + + new SimpleLoader() { @Override - public void run() { + public Object onLoad(Bundle args) { + long id = args.getLong("id"); + DB db = DB.getInstance(getContext()); try { - DB db = DB.getInstance(getContext()); - EntityMessage message = db.message().getMessage(id); - message.ui_hide = true; - db.message().updateMessage(message); + db.beginTransaction(); - EntityOperation.queue(getContext(), message, EntityOperation.DELETE); - EntityOperation.process(getContext()); - } catch (Throwable ex) { - Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); + EntityMessage message = db.message().getMessage(id); + if (message.uid == null) + db.message().deleteMessage(id); + else { + message.ui_hide = true; + db.message().updateMessage(message); + EntityOperation.queue(db, message, EntityOperation.DELETE); + } + + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); } + + EntityOperation.process(getContext()); + + return null; } - }); + + @Override + public void onLoaded(Bundle args, Result result) { + item.setEnabled(true); + item.setIcon(icon); + + if (result.ex != null) + Toast.makeText(getContext(), result.ex.toString(), Toast.LENGTH_LONG).show(); + } + }.load(FragmentMessage.this, ActivityView.LOADER_MESSAGE_TRASH, args); } }) .setNegativeButton(android.R.string.cancel, null).show(); } else { - executor.submit(new Runnable() { + final MenuItem item = bottom_navigation.getMenu().findItem(R.id.action_trash); + item.setEnabled(false); + + final Drawable icon = item.getIcon(); + item.setIcon(Helper.toDimmed(icon)); + + Bundle args = new Bundle(); + args.putLong("id", id); + + new SimpleLoader() { @Override - public void run() { + public Object onLoad(Bundle args) { + long id = args.getLong("id"); + DB db = DB.getInstance(getContext()); try { - DB db = DB.getInstance(getContext()); + db.beginTransaction(); + EntityMessage message = db.message().getMessage(id); - message.ui_hide = true; + EntityFolder trash = db.folder().getFolderByType(message.account, EntityFolder.TRASH); + + boolean move = (message.uid != null); + if (move) + EntityOperation.queue(db, message, EntityOperation.MOVE, trash.id, message.uid); + + message.folder = trash.id; + message.uid = null; db.message().updateMessage(message); - EntityFolder trash = db.folder().getFolderByType(message.account, EntityFolder.TRASH); - EntityOperation.queue(getContext(), message, EntityOperation.MOVE, trash.id); - EntityOperation.process(getContext()); - } catch (Throwable ex) { - Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); + if (!move) + EntityOperation.queue(db, message, EntityOperation.ADD); + + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); } + + EntityOperation.process(getContext()); + + return null; } - }); + + @Override + public void onLoaded(Bundle args, Result result) { + item.setEnabled(true); + item.setIcon(icon); + + if (result.ex != null) + Toast.makeText(getContext(), result.ex.toString(), Toast.LENGTH_LONG).show(); + } + }.load(FragmentMessage.this, ActivityView.LOADER_MESSAGE_TRASH, args); } } - private void onActionMove(final long id) { + private void onActionMove(long id) { Bundle args = new Bundle(); args.putLong("id", id); LoaderManager.getInstance(this) .restartLoader(ActivityView.LOADER_MESSAGE_MOVE, args, moveLoaderCallbacks).forceLoad(); } - private void onActionArchive(final long id) { - executor.submit(new Runnable() { + private void onActionArchive(long id) { + final MenuItem item = bottom_navigation.getMenu().findItem(R.id.action_archive); + item.setEnabled(false); + + final Drawable icon = item.getIcon(); + item.setIcon(Helper.toDimmed(icon)); + + Bundle args = new Bundle(); + args.putLong("id", id); + + new SimpleLoader() { @Override - public void run() { + public Object onLoad(Bundle args) { + long id = args.getLong("id"); + DB db = DB.getInstance(getContext()); try { - DB db = DB.getInstance(getContext()); + db.beginTransaction(); + EntityMessage message = db.message().getMessage(id); - message.ui_hide = true; + EntityFolder archive = db.folder().getFolderByType(message.account, EntityFolder.ARCHIVE); + + boolean move = (message.uid != null); + if (move) + EntityOperation.queue(db, message, EntityOperation.MOVE, archive.id, message.uid); + + message.folder = archive.id; + message.uid = null; db.message().updateMessage(message); - EntityFolder archive = db.folder().getFolderByType(message.account, EntityFolder.ARCHIVE); - EntityOperation.queue(getContext(), message, EntityOperation.MOVE, archive.id); - EntityOperation.process(getContext()); - } catch (Throwable ex) { - Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); + if (!move) + EntityOperation.queue(db, message, EntityOperation.ADD); + + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); } + + EntityOperation.process(getContext()); + + return null; } - }); + + @Override + public void onLoaded(Bundle args, Result result) { + item.setEnabled(true); + item.setIcon(icon); + + if (result.ex != null) + Toast.makeText(getContext(), result.ex.toString(), Toast.LENGTH_LONG).show(); + } + }.load(FragmentMessage.this, ActivityView.LOADER_MESSAGE_ARCHIVE, args); } private void onActionReply(long id) { @@ -603,7 +777,7 @@ public class FragmentMessage extends FragmentEx { public void onLoadFinished(@NonNull Loader> loader, List folders) { LoaderManager.getInstance(FragmentMessage.this).destroyLoader(loader.getId()); - View anchor = top_navigation.findViewById(R.id.action_thread); + View anchor = bottom_navigation.findViewById(R.id.action_move); PopupMenu popupMenu = new PopupMenu(getContext(), anchor); int order = 0; for (EntityFolder folder : folders) @@ -612,24 +786,56 @@ public class FragmentMessage extends FragmentEx { popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @Override - public boolean onMenuItemClick(MenuItem item) { - final long folder = item.getItemId(); - executor.submit(new Runnable() { + public boolean onMenuItemClick(final MenuItem target) { + final MenuItem item = bottom_navigation.getMenu().findItem(R.id.action_move); + item.setEnabled(false); + + final Drawable icon = item.getIcon(); + item.setIcon(Helper.toDimmed(icon)); + + args.putLong("target", target.getItemId()); + + new SimpleLoader() { @Override - public void run() { + public Object onLoad(Bundle args) { + long id = args.getLong("id"); + long target = args.getLong("target"); + DB db = DB.getInstance(getContext()); try { - DB db = DB.getInstance(getContext()); - EntityMessage message = db.message().getMessage(args.getLong("id")); - message.ui_hide = true; + db.beginTransaction(); + + EntityMessage message = db.message().getMessage(id); + + boolean move = (message.uid != null); + if (move) + EntityOperation.queue(db, message, EntityOperation.MOVE, target, message.uid); + + message.folder = target; + message.uid = null; db.message().updateMessage(message); - EntityOperation.queue(getContext(), message, EntityOperation.MOVE, folder); - EntityOperation.process(getContext()); - } catch (Throwable ex) { - Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); + if (!move) + EntityOperation.queue(db, message, EntityOperation.ADD); + + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); } + + EntityOperation.process(getContext()); + + return null; } - }); + + @Override + public void onLoaded(Bundle args, Result result) { + item.setEnabled(true); + item.setIcon(icon); + + if (result.ex != null) + Toast.makeText(getContext(), result.ex.toString(), Toast.LENGTH_LONG).show(); + } + }.load(FragmentMessage.this, ActivityView.LOADER_MESSAGE_MOVE, args); return true; } diff --git a/app/src/main/java/eu/faircode/email/Helper.java b/app/src/main/java/eu/faircode/email/Helper.java index b3ad4854f1..6e79969db9 100644 --- a/app/src/main/java/eu/faircode/email/Helper.java +++ b/app/src/main/java/eu/faircode/email/Helper.java @@ -21,6 +21,9 @@ package eu.faircode.email; import android.content.Context; import android.content.res.TypedArray; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.drawable.Drawable; import android.os.Build; import android.text.TextUtils; import android.util.Log; @@ -29,6 +32,8 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; +import androidx.annotation.NonNull; + public class Helper { static final String TAG = BuildConfig.APPLICATION_ID; @@ -40,6 +45,16 @@ public class Helper { return color; } + static Drawable toDimmed(@NonNull Drawable drawable) { + ColorMatrix matrix = new ColorMatrix(); + matrix.setSaturation(0); + ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix); + Drawable mutated = drawable.mutate(); + mutated.setColorFilter(filter); + mutated.setAlpha(128); + return mutated; + } + static String localizeFolderName(Context context, String name) { if ("INBOX".equals(name)) return context.getString(R.string.title_folder_inbox); diff --git a/app/src/main/java/eu/faircode/email/MimeMessageEx.java b/app/src/main/java/eu/faircode/email/MimeMessageEx.java index 7e6bf8e7b5..28c198a227 100644 --- a/app/src/main/java/eu/faircode/email/MimeMessageEx.java +++ b/app/src/main/java/eu/faircode/email/MimeMessageEx.java @@ -31,7 +31,7 @@ public class MimeMessageEx extends MimeMessage { .append('>'); setHeader("Message-ID", sb.toString()); - Log.i(Helper.TAG, "Override Message-ID=" + sb.toString()); + Log.v(Helper.TAG, "Override Message-ID=" + sb.toString()); } catch (Throwable ex) { Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); super.updateMessageID(); @@ -54,7 +54,7 @@ public class MimeMessageEx extends MimeMessage { return -1; long id = Long.parseLong(part.substring(1)); - Log.i(Helper.TAG, "Parsed Message-ID=" + msgid + " id=" + id); + Log.v(Helper.TAG, "Parsed Message-ID=" + msgid + " id=" + id); return id; } catch (Throwable ex) { Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); diff --git a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java index b10ec9bc7e..3852b9f6a9 100644 --- a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java +++ b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java @@ -596,8 +596,8 @@ public class ServiceSynchronize extends LifecycleService { Log.i(Helper.TAG, folder.name + " messages removed"); for (Message imessage : e.getMessages()) try { - long uid = ifolder.getUID(imessage); DB db = DB.getInstance(ServiceSynchronize.this); + long uid = ifolder.getUID(imessage); int count = db.message().deleteMessage(folder.id, uid); Log.i(Helper.TAG, "Deleted uid=" + uid + " count=" + count); } catch (MessageRemovedException ex) { @@ -694,215 +694,56 @@ public class ServiceSynchronize extends LifecycleService { Log.i(Helper.TAG, folder.name + " start process"); DB db = DB.getInstance(this); - DaoOperation operation = db.operation(); - DaoMessage message = db.message(); - for (TupleOperationEx op : operation.getOperations(folder.id)) + for (EntityOperation op : db.operation().getOperations(folder.id)) try { Log.i(Helper.TAG, folder.name + " start op=" + op.id + "/" + op.name + - " args=" + op.args + - " msg=" + op.message); + " msg=" + op.message + + " args=" + op.args); JSONArray jargs = new JSONArray(op.args); + EntityMessage message = db.message().getMessage(op.message); try { - if (EntityOperation.SEEN.equals(op.name)) { - // Mark message (un)seen - Message imessage = ifolder.getMessageByUID(op.uid); - if (imessage == null) - throw new MessageRemovedException(); - imessage.setFlag(Flags.Flag.SEEN, jargs.getBoolean(0)); - - } else if (EntityOperation.ADD.equals(op.name)) { - // Append message - EntityMessage msg = message.getMessage(op.message); - if (msg == null) - return; - - // Disconnect from remote to prevent deletion - Long uid = msg.uid; - if (msg.uid != null) { - msg.uid = null; - message.updateMessage(msg); - } - - // Execute append - Properties props = MessageHelper.getSessionProperties(); - Session isession = Session.getInstance(props, null); - MimeMessage imessage = MessageHelper.from(msg, isession); - ifolder.appendMessages(new Message[]{imessage}); - - // Drafts can be appended multiple times - if (uid != null) { - Message previously = ifolder.getMessageByUID(uid); - if (previously == null) - throw new MessageRemovedException(); - - previously.setFlag(Flags.Flag.DELETED, true); - ifolder.expunge(); - } - - } else if (EntityOperation.MOVE.equals(op.name)) { - EntityFolder target = db.folder().getFolder(jargs.getLong(0)); - if (target == null) - throw new FolderNotFoundException(); - - // Move message - Message imessage = ifolder.getMessageByUID(op.uid); - if (imessage == null) - throw new MessageRemovedException(); - - Folder itarget = istore.getFolder(target.name); - if (istore.hasCapability("MOVE")) - ifolder.moveMessages(new Message[]{imessage}, itarget); - else { - Log.i(Helper.TAG, "MOVE by APPEND/DELETE"); - EntityMessage msg = message.getMessage(op.message); - - // Execute append - Properties props = MessageHelper.getSessionProperties(); - Session isession = Session.getInstance(props, null); - MimeMessage icopy = MessageHelper.from(msg, isession); - itarget.appendMessages(new Message[]{icopy}); - - // Execute delete - imessage.setFlag(Flags.Flag.DELETED, true); - ifolder.expunge(); - } - - message.deleteMessage(op.message); - - } else if (EntityOperation.DELETE.equals(op.name)) { - // Delete message - if (op.uid != null) { - Message imessage = ifolder.getMessageByUID(op.uid); - if (imessage == null) - throw new MessageRemovedException(); - imessage.setFlag(Flags.Flag.DELETED, true); - ifolder.expunge(); - } - - message.deleteMessage(op.message); + if (EntityOperation.SEEN.equals(op.name)) + doSeen(ifolder, jargs, message); - } else if (EntityOperation.SEND.equals(op.name)) { - // Send message - EntityMessage msg = message.getMessage(op.message); - if (msg == null) - return; + else if (EntityOperation.ADD.equals(op.name)) + doAdd(ifolder, message); - EntityMessage reply = (msg.replying == null ? null : message.getMessage(msg.replying)); - EntityIdentity ident = db.identity().getIdentity(msg.identity); + else if (EntityOperation.MOVE.equals(op.name)) + doMove(folder, istore, ifolder, db, jargs, message); - if (ident == null || !ident.synchronize) { - // Message will remain in outbox - return; - } - - // Create session - Properties props = MessageHelper.getSessionProperties(); - Session isession = Session.getInstance(props, null); - - // Create message - MimeMessage imessage; - if (reply == null) - imessage = MessageHelper.from(msg, isession); - else - imessage = MessageHelper.from(msg, reply, isession); - if (ident.replyto != null) - imessage.setReplyTo(new Address[]{new InternetAddress(ident.replyto)}); - - // Create transport - Transport itransport = isession.getTransport(ident.starttls ? "smtp" : "smtps"); - try { - // Connect transport - itransport.connect(ident.host, ident.port, ident.user, ident.password); - - // Send message - Address[] to = imessage.getAllRecipients(); - itransport.sendMessage(imessage, to); - Log.i(Helper.TAG, "Sent via " + ident.host + "/" + ident.user + - " to " + TextUtils.join(", ", to)); - - msg.sent = new Date().getTime(); - msg.seen = true; - msg.ui_seen = true; - - EntityFolder sent = db.folder().getFolderByType(ident.account, EntityFolder.SENT); - if (sent != null) { - Log.i(Helper.TAG, "Moving to sent folder=" + sent.id); - msg.folder = sent.id; - } + else if (EntityOperation.DELETE.equals(op.name)) + doDelete(folder, ifolder, db, message); - message.updateMessage(msg); + else if (EntityOperation.SEND.equals(op.name)) + doSend(db, message); - } finally { - itransport.close(); - } - // TODO: cache transport? - - } else if (EntityOperation.ATTACHMENT.equals(op.name)) { - int sequence = jargs.getInt(0); - EntityAttachment attachment = db.attachment().getAttachment(op.message, sequence); - if (attachment == null) - return; - - try { - // Get message - Message imessage = ifolder.getMessageByUID(op.uid); - if (imessage == null) - throw new MessageRemovedException(); - - // Get attachment - MessageHelper helper = new MessageHelper((MimeMessage) imessage); - EntityAttachment a = helper.getAttachments().get(sequence - 1); - - // Download attachment - InputStream is = a.part.getInputStream(); - ByteArrayOutputStream os = new ByteArrayOutputStream(); - byte[] buffer = new byte[DOWNLOAD_BUFFER_SIZE]; - for (int len = is.read(buffer); len != -1; len = is.read(buffer)) { - os.write(buffer, 0, len); - - // Update progress - if (attachment.size != null) { - attachment.progress = os.size() * 100 / attachment.size; - db.attachment().updateAttachment(attachment); - Log.i(Helper.TAG, "Progress %=" + attachment.progress); - } - } + else if (EntityOperation.ATTACHMENT.equals(op.name)) + doAttachment(ifolder, db, op, jargs, message); - // Store attachment data - attachment.progress = null; - attachment.content = os.toByteArray(); - db.attachment().updateAttachment(attachment); - Log.i(Helper.TAG, "Downloaded bytes=" + attachment.content.length); - } catch (Throwable ex) { - // Reset progress on failure - attachment.progress = null; - db.attachment().updateAttachment(attachment); - throw ex; - } - } else + else throw new MessagingException("Unknown operation name=" + op.name); // Operation succeeded - operation.deleteOperation(op.id); + db.operation().deleteOperation(op.id); } catch (MessageRemovedException ex) { Log.w(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); // There is no use in repeating - operation.deleteOperation(op.id); + db.operation().deleteOperation(op.id); } catch (FolderNotFoundException ex) { Log.w(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); // There is no use in repeating - operation.deleteOperation(op.id); + db.operation().deleteOperation(op.id); } catch (SMTPSendFailedException ex) { // TODO: response codes: https://www.ietf.org/rfc/rfc821.txt Log.w(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); // There is probably no use in repeating - operation.deleteOperation(op.id); + db.operation().deleteOperation(op.id); throw ex; } catch (MessagingException ex) { // Socket timeout is a recoverable condition (send message) @@ -921,6 +762,207 @@ public class ServiceSynchronize extends LifecycleService { } } + private void doSeen(IMAPFolder ifolder, JSONArray jargs, EntityMessage message) throws MessagingException, JSONException { + if (message.uid == null) + return; + + // Mark message (un)seen + Message imessage = ifolder.getMessageByUID(message.uid); + if (imessage == null) + throw new MessageRemovedException(); + + imessage.setFlag(Flags.Flag.SEEN, jargs.getBoolean(0)); + } + + private void doAdd(IMAPFolder ifolder, EntityMessage message) throws MessagingException { + // Append message + Properties props = MessageHelper.getSessionProperties(); + Session isession = Session.getInstance(props, null); + MimeMessage imessage = MessageHelper.from(message, isession); + ifolder.appendMessages(new Message[]{imessage}); + } + + private void doMove(EntityFolder source, IMAPStore istore, IMAPFolder ifolder, DB db, JSONArray jargs, EntityMessage message) throws JSONException, MessagingException { + long id = jargs.getLong(0); + long uid = jargs.getLong(1); + EntityFolder target = db.folder().getFolder(id); + if (target == null) + throw new FolderNotFoundException(); + + // Get message + Message imessage = ifolder.getMessageByUID(uid); + if (imessage == null) + throw new MessageRemovedException(); + + // Get folder + Folder itarget = istore.getFolder(target.name); + + // Append/delete because message ID header needs to be added and not all providers support MOVE + long oid = message.id; + try { + db.beginTransaction(); + + // Hide original (to be deleted) + message.ui_hide = true; + db.message().updateMessage(message); + + // Copy message (to be appended) + if (!EntityFolder.ARCHIVE.equals(target.type)) { + message.id = null; + message.ui_hide = false; + message.id = db.message().insertMessage(message); + + // New archived message will be created + EntityMessage archived = db.message().getArchivedMessage(message.thread); + if (archived != null) + db.message().deleteMessage(archived.id); + } + + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + + // Append copy + if (!EntityFolder.ARCHIVE.equals(target.type)) { + Properties props = MessageHelper.getSessionProperties(); + Session isession = Session.getInstance(props, null); + MimeMessage icopy = MessageHelper.from(message, isession); + itarget.appendMessages(new Message[]{icopy}); + icopy.setFlag(Flags.Flag.SEEN, message.seen); + } + + // Delete original + imessage.setFlag(Flags.Flag.DELETED, true); + ifolder.expunge(); + + db.message().deleteMessage(oid); + } + + private void doDelete(EntityFolder folder, IMAPFolder ifolder, DB db, EntityMessage message) throws MessagingException { + // Delete message + Message imessage = ifolder.getMessageByUID(message.uid); + if (imessage == null) + throw new MessageRemovedException(); + + imessage.setFlag(Flags.Flag.DELETED, true); + ifolder.expunge(); + + db.message().deleteMessage(message.id); + } + + private void doSend(DB db, EntityMessage message) throws MessagingException { + // Send message + EntityMessage reply = (message.replying == null ? null : db.message().getMessage(message.replying)); + EntityIdentity ident = db.identity().getIdentity(message.identity); + + if (!ident.synchronize) { + // Message will remain in outbox + return; + } + + try { + db.beginTransaction(); + + // Move message to sent + EntityFolder sent = db.folder().getFolderByType(ident.account, EntityFolder.SENT); + if (sent == null) + ; // Leave message in outbox + else { + message.folder = sent.id; + message.uid = null; + } + + // Create session + Properties props = MessageHelper.getSessionProperties(); + Session isession = Session.getInstance(props, null); + + // Create message + MimeMessage imessage; + if (reply == null) + imessage = MessageHelper.from(message, isession); + else + imessage = MessageHelper.from(message, reply, isession); + if (ident.replyto != null) + imessage.setReplyTo(new Address[]{new InternetAddress(ident.replyto)}); + + // Create transport + // TODO: cache transport? + Transport itransport = isession.getTransport(ident.starttls ? "smtp" : "smtps"); + try { + // Connect transport + itransport.connect(ident.host, ident.port, ident.user, ident.password); + + // Send message + Address[] to = imessage.getAllRecipients(); + itransport.sendMessage(imessage, to); + Log.i(Helper.TAG, "Sent via " + ident.host + "/" + ident.user + + " to " + TextUtils.join(", ", to)); + + // Update state + message.sent = new Date().getTime(); + message.seen = true; + message.ui_seen = true; + db.message().updateMessage(message); + + if (sent != null) + EntityOperation.queue(db, message, EntityOperation.ADD); // Could already exist + + } finally { + itransport.close(); + } + + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + } + + private void doAttachment(IMAPFolder ifolder, DB db, EntityOperation op, JSONArray jargs, EntityMessage message) throws JSONException, MessagingException, IOException { + int sequence = jargs.getInt(0); + + EntityAttachment attachment = db.attachment().getAttachment(op.message, sequence); + if (attachment == null) + return; + + try { + // Get message + Message imessage = ifolder.getMessageByUID(message.uid); + if (imessage == null) + throw new MessageRemovedException(); + + // Get attachment + MessageHelper helper = new MessageHelper((MimeMessage) imessage); + EntityAttachment a = helper.getAttachments().get(sequence - 1); + + // Download attachment + InputStream is = a.part.getInputStream(); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + byte[] buffer = new byte[DOWNLOAD_BUFFER_SIZE]; + for (int len = is.read(buffer); len != -1; len = is.read(buffer)) { + os.write(buffer, 0, len); + + // Update progress + if (attachment.size != null) { + attachment.progress = os.size() * 100 / attachment.size; + db.attachment().updateAttachment(attachment); + Log.i(Helper.TAG, "Progress %=" + attachment.progress); + } + } + + // Store attachment data + attachment.progress = null; + attachment.content = os.toByteArray(); + db.attachment().updateAttachment(attachment); + Log.i(Helper.TAG, "Downloaded bytes=" + attachment.content.length); + } catch (Throwable ex) { + // Reset progress on failure + attachment.progress = null; + db.attachment().updateAttachment(attachment); + throw ex; + } + } + private void synchronizeFolders(EntityAccount account, IMAPStore istore) throws MessagingException { try { Log.i(Helper.TAG, "Start sync folders"); @@ -1029,6 +1071,9 @@ public class ServiceSynchronize extends LifecycleService { } // Add/update local messages + int added = 0; + int updated = 0; + int unchanged = 0; Log.i(Helper.TAG, folder.name + " add=" + imessages.length); for (int batch = 0; batch < imessages.length; batch += FETCH_BATCH_SIZE) { Log.i(Helper.TAG, folder.name + " fetch @" + batch); @@ -1036,7 +1081,13 @@ public class ServiceSynchronize extends LifecycleService { db.beginTransaction(); for (int i = 0; i < FETCH_BATCH_SIZE && batch + i < imessages.length; i++) try { - synchronizeMessage(folder, ifolder, (IMAPMessage) imessages[batch + i]); + int status = synchronizeMessage(folder, ifolder, (IMAPMessage) imessages[batch + i]); + if (status > 0) + added++; + else if (status < 0) + updated++; + else + unchanged++; } catch (MessageRemovedException ex) { Log.w(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex)); } @@ -1045,12 +1096,13 @@ public class ServiceSynchronize extends LifecycleService { db.endTransaction(); } } + Log.i(Helper.TAG, folder.name + " added=" + added + " updated=" + updated + " unchanged=" + unchanged); } finally { Log.i(Helper.TAG, folder.name + " end sync"); } } - private void synchronizeMessage(EntityFolder folder, IMAPFolder ifolder, IMAPMessage imessage) throws MessagingException, JSONException, IOException { + private int synchronizeMessage(EntityFolder folder, IMAPFolder ifolder, IMAPMessage imessage) throws MessagingException, JSONException, IOException { long uid = -1; try { FetchProfile fp = new FetchProfile(); @@ -1063,18 +1115,36 @@ public class ServiceSynchronize extends LifecycleService { if (imessage.isExpunged()) { Log.i(Helper.TAG, folder.name + " expunged uid=" + uid); - return; + return 0; } if (imessage.isSet(Flags.Flag.DELETED)) { Log.i(Helper.TAG, folder.name + " deleted uid=" + uid); - return; + return 0; + } + + + DB db = DB.getInstance(this); + + EntityMessage message = null; + long id = MimeMessageEx.getId(imessage); + if (id >= 0) { + message = db.message().getMessage(id); + Log.i(Helper.TAG, "By id=" + id + " uid=" + (message == null ? "n/a" : message.uid)); + } + if (message != null && message.folder != folder.id) { + if (EntityFolder.ARCHIVE.equals(folder.type)) + message = null; + else // Outbox to sent + message.folder = folder.id; + } + if (message == null) { + message = db.message().getMessage(folder.id, uid); + Log.i(Helper.TAG, "By uid=" + uid + " id=" + (message == null ? "n/a" : message.id)); } MessageHelper helper = new MessageHelper(imessage); boolean seen = helper.getSeen(); - DB db = DB.getInstance(this); - EntityMessage message = db.message().getMessage(folder.id, uid); if (message == null) { FetchProfile fp1 = new FetchProfile(); fp1.add(FetchProfile.Item.ENVELOPE); @@ -1083,18 +1153,7 @@ public class ServiceSynchronize extends LifecycleService { fp1.add(IMAPFolder.FetchProfileItem.MESSAGE); ifolder.fetch(new Message[]{imessage}, fp1); - long id = MimeMessageEx.getId(imessage); - message = db.message().getMessage(id); - if (message != null && message.folder != folder.id) { - if (EntityFolder.ARCHIVE.equals(folder.type)) - message = null; - else // Outbox to sent - message.folder = folder.id; - } - boolean update = (message != null); - if (message == null) - message = new EntityMessage(); - + message = new EntityMessage(); message.account = folder.account; message.folder = folder.id; message.uid = uid; @@ -1115,13 +1174,8 @@ public class ServiceSynchronize extends LifecycleService { message.ui_seen = seen; message.ui_hide = false; - if (update) { - db.message().updateMessage(message); - Log.i(Helper.TAG, folder.name + " updated id=" + message.id + " uid=" + message.uid); - } else { - message.id = db.message().insertMessage(message); - Log.i(Helper.TAG, folder.name + " added id=" + message.id + " uid=" + message.uid); - } + message.id = db.message().insertMessage(message); + Log.i(Helper.TAG, folder.name + " added id=" + message.id + " uid=" + message.uid); int sequence = 0; for (EntityAttachment attachment : helper.getAttachments()) { @@ -1132,14 +1186,26 @@ public class ServiceSynchronize extends LifecycleService { attachment.sequence = sequence; attachment.id = db.attachment().insertAttachment(attachment); } + + return 1; } else if (message.seen != seen) { + //if (message.uid == null) + message.uid = uid; // Complete move message.seen = seen; message.ui_seen = seen; - // TODO: synchronize all data? db.message().updateMessage(message); Log.i(Helper.TAG, folder.name + " updated id=" + message.id + " uid=" + message.uid); + return -1; } else { - Log.v(Helper.TAG, folder.name + " unchanged id=" + message.id + " uid=" + message.uid); + if (message.uid == null) { + message.uid = uid; + db.message().updateMessage(message); + Log.i(Helper.TAG, folder.name + " updated id=" + message.id + " set uid=" + message.uid); + return -1; + } else { + Log.v(Helper.TAG, folder.name + " unchanged id=" + message.id + " uid=" + message.uid); + return 0; + } } } finally { diff --git a/app/src/main/java/eu/faircode/email/SimpleLoader.java b/app/src/main/java/eu/faircode/email/SimpleLoader.java new file mode 100644 index 0000000000..2a0632f11f --- /dev/null +++ b/app/src/main/java/eu/faircode/email/SimpleLoader.java @@ -0,0 +1,92 @@ +package eu.faircode.email; + +import android.content.Context; +import android.os.Bundle; +import android.util.Log; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.Fragment; +import androidx.loader.app.LoaderManager; +import androidx.loader.content.AsyncTaskLoader; +import androidx.loader.content.Loader; + +public abstract class SimpleLoader { + private Context context; + private LoaderManager manager; + + public void load(AppCompatActivity activity, int id, Bundle args) { + this.context = activity; + this.manager = LoaderManager.getInstance(activity); + manager.restartLoader(id, args, callbacks).forceLoad(); + } + + public void load(Fragment fragment, int id, Bundle args) { + this.context = fragment.getContext(); + this.manager = LoaderManager.getInstance(fragment); + manager.restartLoader(id, args, callbacks).forceLoad(); + } + + public Object onLoad(Bundle args) { + return null; + } + + public void onLoaded(Bundle args, Result result) { + } + + private static class CommonLoader extends AsyncTaskLoader { + Bundle args; + SimpleLoader loader; + + CommonLoader(Context context) { + super(context); + } + + void setArgs(Bundle args, SimpleLoader x) { + this.args = args; + this.loader = x; + } + + @Override + public Result loadInBackground() { + Result result = new Result(); + try { + result.data = loader.onLoad(args); + } catch (Throwable ex) { + Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); + result.ex = ex; + } + return result; + } + } + + private LoaderManager.LoaderCallbacks callbacks = new LoaderManager.LoaderCallbacks() { + @Override + public Loader onCreateLoader(int id, Bundle args) { + CommonLoader loader = new CommonLoader(context); + loader.setArgs(args, SimpleLoader.this); + return loader; + } + + @Override + public void onLoadFinished(Loader loader, Result data) { + manager.destroyLoader(loader.getId()); + + CommonLoader common = (CommonLoader) loader; + onLoaded(common.args, data); + + common.args = null; + common.loader = null; + + manager = null; + } + + @Override + public void onLoaderReset(Loader loader) { + } + }; + + public static class Result { + Throwable ex; + Object data; + } +} diff --git a/app/src/main/java/eu/faircode/email/TupleOperationEx.java b/app/src/main/java/eu/faircode/email/TupleOperationEx.java deleted file mode 100644 index 610d2b424f..0000000000 --- a/app/src/main/java/eu/faircode/email/TupleOperationEx.java +++ /dev/null @@ -1,24 +0,0 @@ -package eu.faircode.email; - -/* - This file is part of Safe email. - - Safe email is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - NetGuard is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with NetGuard. If not, see . - - Copyright 2018 by Marcel Bokhorst (M66B) -*/ - -public class TupleOperationEx extends EntityOperation { - public Long uid; -}