2016-05-06 08:33:37 -04:00
|
|
|
/* Copyright 2016 Software Freedom Conservancy Inc.
|
2011-06-16 16:27:08 -07:00
|
|
|
*
|
|
|
|
|
* This software is licensed under the GNU Lesser General Public License
|
2013-04-12 12:31:58 -07:00
|
|
|
* (version 2.1 or later). See the COPYING file in this distribution.
|
2011-06-16 16:27:08 -07:00
|
|
|
*/
|
|
|
|
|
|
2015-01-09 17:50:19 -08:00
|
|
|
private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
|
2016-06-05 18:36:16 +10:00
|
|
|
|
2014-03-03 15:05:41 -08:00
|
|
|
private const int REFRESH_FOLDER_LIST_SEC = 2 * 60;
|
|
|
|
|
private const int REFRESH_UNSEEN_SEC = 1;
|
2016-06-05 18:36:16 +10:00
|
|
|
private const Geary.SpecialFolderType[] SUPPORTED_SPECIAL_FOLDERS = {
|
|
|
|
|
Geary.SpecialFolderType.DRAFTS,
|
|
|
|
|
Geary.SpecialFolderType.SENT,
|
|
|
|
|
Geary.SpecialFolderType.SPAM,
|
|
|
|
|
Geary.SpecialFolderType.TRASH,
|
|
|
|
|
Geary.SpecialFolderType.ARCHIVE,
|
|
|
|
|
};
|
|
|
|
|
|
2012-06-22 14:42:51 -07:00
|
|
|
private static Geary.FolderPath? outbox_path = null;
|
2013-05-14 11:52:02 -07:00
|
|
|
private static Geary.FolderPath? search_path = null;
|
2016-06-05 18:36:16 +10:00
|
|
|
|
|
|
|
|
protected virtual Geary.SpecialFolderType[] supported_special_folders {
|
|
|
|
|
get { return SUPPORTED_SPECIAL_FOLDERS; }
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-14 11:05:32 -07:00
|
|
|
private Imap.Account remote;
|
Remove SQLHeavy: Closes #5034
It is done.
Initial implementation of the new database subsystem
These pieces represent the foundation for ticket #5034
Expanded transactions, added VersionedDatabase
Further expansions of the async code.
Moved async pool logic into Database, where it realistically
belongs.
Further improvements. Introduced geary-db-test.
Added SQL create and update files for Geary.Db
version-001 to version-003 are exact copies of the SQLHeavy scripts
to ensure no slight changes when migrating. version-004 upgrades
the database to remove the ImapFolderPropertiesTable and
ImapMessagePropertiesTable, now that the database code is pure
IMAP.
When we support other messaging systems (such as POP3), those
subsystems will need to code their own database layers OR rely on
the IMAP schema and simply ignore the IMAP-specific fields.
ImapDB.Account fleshed out
ImapDB.Folder is commented out, however. Need to port next.
ImapDB.Folder fleshed out
MessageTable, MessageLocationTable, and AttachementTable are now
handled inside ImapDB.Folder.
chmod -x imap-db-database.vala
OutboxEmailIdentifier/Properties -> SmtpOutboxEmailIdentifier/Properties
Moved SmtpOutboxFolderRoot into its own source file
SmtpOutboxFolder ported to new database code
Move Engine implementations to ImapDB.
Integration and cleanup of new database code with main source
This commit performs the final integration steps to move Geary
completely over to the new database model. This also cleans out
the old SQLHeavy-based code and fixes a handful of small bugs that
were detected during basic test runs.
Moved Outbox to ImapDB
As the Outbox is tied to the database that ImapDB runs, move the
Outbox code into that folder.
Outbox fixes and better parameter checking
Bumped Database thread pool count and made them exclusive
My reasoning is that there may be a need for a lot of threads at
once (when a big batch of commands comes in, especially at
startup). If performance looks ok, we might consider relaxing
this later.
2012-06-14 14:47:53 -07:00
|
|
|
private ImapDB.Account local;
|
|
|
|
|
private bool open = false;
|
2014-02-11 15:24:01 -08:00
|
|
|
private Gee.HashMap<FolderPath, MinimalFolder> folder_map = new Gee.HashMap<
|
|
|
|
|
FolderPath, MinimalFolder>();
|
2013-04-24 12:22:32 -07:00
|
|
|
private Gee.HashMap<FolderPath, Folder> local_only = new Gee.HashMap<FolderPath, Folder>();
|
2014-03-03 15:05:41 -08:00
|
|
|
private Gee.HashMap<FolderPath, uint> refresh_unseen_timeout_ids
|
|
|
|
|
= new Gee.HashMap<FolderPath, uint>();
|
|
|
|
|
private Gee.HashSet<Geary.Folder> in_refresh_unseen = new Gee.HashSet<Geary.Folder>();
|
2013-02-25 20:18:37 -08:00
|
|
|
private uint refresh_folder_timeout_id = 0;
|
|
|
|
|
private bool in_refresh_enumerate = false;
|
|
|
|
|
private Cancellable refresh_cancellable = new Cancellable();
|
2013-09-23 18:27:56 -07:00
|
|
|
private bool awaiting_credentials = false;
|
2016-06-15 18:24:50 -04:00
|
|
|
|
|
|
|
|
private Gee.Map<Geary.SpecialFolderType, Gee.List<string>> special_search_names =
|
|
|
|
|
new Gee.HashMap<Geary.SpecialFolderType, Gee.List<string>>();
|
|
|
|
|
|
2016-06-02 10:35:43 +10:00
|
|
|
public GenericAccount(string name, Geary.AccountInformation information,
|
2014-01-07 15:04:49 -08:00
|
|
|
Imap.Account remote, ImapDB.Account local) {
|
2016-06-02 10:35:43 +10:00
|
|
|
base (name, information);
|
2011-07-01 15:40:20 -07:00
|
|
|
|
2011-06-23 19:07:04 -07:00
|
|
|
this.remote = remote;
|
2011-06-16 16:27:08 -07:00
|
|
|
this.local = local;
|
2011-07-01 19:33:35 -07:00
|
|
|
|
2012-03-14 11:05:32 -07:00
|
|
|
this.remote.login_failed.connect(on_login_failed);
|
2013-09-17 16:55:03 -07:00
|
|
|
this.local.email_sent.connect(on_email_sent);
|
2012-06-22 14:42:51 -07:00
|
|
|
|
2013-06-03 17:39:42 -07:00
|
|
|
search_upgrade_monitor = local.search_index_monitor;
|
2013-07-08 14:22:23 -07:00
|
|
|
db_upgrade_monitor = local.upgrade_monitor;
|
2014-12-18 17:00:47 -08:00
|
|
|
db_vacuum_monitor = local.vacuum_monitor;
|
2014-06-12 13:01:47 -07:00
|
|
|
opening_monitor = new Geary.ReentrantProgressMonitor(Geary.ProgressType.ACTIVITY);
|
2013-09-17 16:55:03 -07:00
|
|
|
sending_monitor = local.sending_monitor;
|
2013-06-03 17:39:42 -07:00
|
|
|
|
2012-06-22 14:42:51 -07:00
|
|
|
if (outbox_path == null) {
|
|
|
|
|
outbox_path = new SmtpOutboxFolderRoot();
|
|
|
|
|
}
|
2013-05-14 11:52:02 -07:00
|
|
|
|
|
|
|
|
if (search_path == null) {
|
2015-03-02 17:34:17 -08:00
|
|
|
search_path = new ImapDB.SearchFolderRoot();
|
2013-05-14 11:52:02 -07:00
|
|
|
}
|
2016-06-15 18:24:50 -04:00
|
|
|
|
|
|
|
|
compile_special_search_names();
|
2011-06-16 16:27:08 -07:00
|
|
|
}
|
2016-06-15 18:24:50 -04:00
|
|
|
|
2013-07-09 13:48:47 -07:00
|
|
|
protected override void notify_folders_available_unavailable(Gee.List<Geary.Folder>? available,
|
|
|
|
|
Gee.List<Geary.Folder>? unavailable) {
|
|
|
|
|
base.notify_folders_available_unavailable(available, unavailable);
|
|
|
|
|
if (available != null) {
|
|
|
|
|
foreach (Geary.Folder folder in available) {
|
2013-09-05 18:46:38 -07:00
|
|
|
folder.email_appended.connect(notify_email_appended);
|
|
|
|
|
folder.email_inserted.connect(notify_email_inserted);
|
|
|
|
|
folder.email_removed.connect(notify_email_removed);
|
|
|
|
|
folder.email_locally_complete.connect(notify_email_locally_complete);
|
|
|
|
|
folder.email_flags_changed.connect(notify_email_flags_changed);
|
2013-07-09 13:48:47 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (unavailable != null) {
|
|
|
|
|
foreach (Geary.Folder folder in unavailable) {
|
2013-09-05 18:46:38 -07:00
|
|
|
folder.email_appended.disconnect(notify_email_appended);
|
|
|
|
|
folder.email_inserted.disconnect(notify_email_inserted);
|
|
|
|
|
folder.email_removed.disconnect(notify_email_removed);
|
|
|
|
|
folder.email_locally_complete.disconnect(notify_email_locally_complete);
|
|
|
|
|
folder.email_flags_changed.disconnect(notify_email_flags_changed);
|
2013-07-09 13:48:47 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-03 15:05:41 -08:00
|
|
|
protected override void notify_email_appended(Geary.Folder folder, Gee.Collection<Geary.EmailIdentifier> ids) {
|
|
|
|
|
base.notify_email_appended(folder, ids);
|
|
|
|
|
reschedule_unseen_update(folder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void notify_email_inserted(Geary.Folder folder, Gee.Collection<Geary.EmailIdentifier> ids) {
|
|
|
|
|
base.notify_email_inserted(folder, ids);
|
|
|
|
|
reschedule_unseen_update(folder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void notify_email_removed(Geary.Folder folder, Gee.Collection<Geary.EmailIdentifier> ids) {
|
|
|
|
|
base.notify_email_removed(folder, ids);
|
|
|
|
|
reschedule_unseen_update(folder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void notify_email_flags_changed(Geary.Folder folder,
|
|
|
|
|
Gee.Map<Geary.EmailIdentifier, Geary.EmailFlags> flag_map) {
|
|
|
|
|
base.notify_email_flags_changed(folder, flag_map);
|
|
|
|
|
reschedule_unseen_update(folder);
|
|
|
|
|
}
|
|
|
|
|
|
Remove SQLHeavy: Closes #5034
It is done.
Initial implementation of the new database subsystem
These pieces represent the foundation for ticket #5034
Expanded transactions, added VersionedDatabase
Further expansions of the async code.
Moved async pool logic into Database, where it realistically
belongs.
Further improvements. Introduced geary-db-test.
Added SQL create and update files for Geary.Db
version-001 to version-003 are exact copies of the SQLHeavy scripts
to ensure no slight changes when migrating. version-004 upgrades
the database to remove the ImapFolderPropertiesTable and
ImapMessagePropertiesTable, now that the database code is pure
IMAP.
When we support other messaging systems (such as POP3), those
subsystems will need to code their own database layers OR rely on
the IMAP schema and simply ignore the IMAP-specific fields.
ImapDB.Account fleshed out
ImapDB.Folder is commented out, however. Need to port next.
ImapDB.Folder fleshed out
MessageTable, MessageLocationTable, and AttachementTable are now
handled inside ImapDB.Folder.
chmod -x imap-db-database.vala
OutboxEmailIdentifier/Properties -> SmtpOutboxEmailIdentifier/Properties
Moved SmtpOutboxFolderRoot into its own source file
SmtpOutboxFolder ported to new database code
Move Engine implementations to ImapDB.
Integration and cleanup of new database code with main source
This commit performs the final integration steps to move Geary
completely over to the new database model. This also cleans out
the old SQLHeavy-based code and fixes a handful of small bugs that
were detected during basic test runs.
Moved Outbox to ImapDB
As the Outbox is tied to the database that ImapDB runs, move the
Outbox code into that folder.
Outbox fixes and better parameter checking
Bumped Database thread pool count and made them exclusive
My reasoning is that there may be a need for a lot of threads at
once (when a big batch of commands comes in, especially at
startup). If performance looks ok, we might consider relaxing
this later.
2012-06-14 14:47:53 -07:00
|
|
|
private void check_open() throws EngineError {
|
|
|
|
|
if (!open)
|
|
|
|
|
throw new EngineError.OPEN_REQUIRED("Account %s not opened", to_string());
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-11 12:03:57 -07:00
|
|
|
public override async void open_async(Cancellable? cancellable = null) throws Error {
|
Remove SQLHeavy: Closes #5034
It is done.
Initial implementation of the new database subsystem
These pieces represent the foundation for ticket #5034
Expanded transactions, added VersionedDatabase
Further expansions of the async code.
Moved async pool logic into Database, where it realistically
belongs.
Further improvements. Introduced geary-db-test.
Added SQL create and update files for Geary.Db
version-001 to version-003 are exact copies of the SQLHeavy scripts
to ensure no slight changes when migrating. version-004 upgrades
the database to remove the ImapFolderPropertiesTable and
ImapMessagePropertiesTable, now that the database code is pure
IMAP.
When we support other messaging systems (such as POP3), those
subsystems will need to code their own database layers OR rely on
the IMAP schema and simply ignore the IMAP-specific fields.
ImapDB.Account fleshed out
ImapDB.Folder is commented out, however. Need to port next.
ImapDB.Folder fleshed out
MessageTable, MessageLocationTable, and AttachementTable are now
handled inside ImapDB.Folder.
chmod -x imap-db-database.vala
OutboxEmailIdentifier/Properties -> SmtpOutboxEmailIdentifier/Properties
Moved SmtpOutboxFolderRoot into its own source file
SmtpOutboxFolder ported to new database code
Move Engine implementations to ImapDB.
Integration and cleanup of new database code with main source
This commit performs the final integration steps to move Geary
completely over to the new database model. This also cleans out
the old SQLHeavy-based code and fixes a handful of small bugs that
were detected during basic test runs.
Moved Outbox to ImapDB
As the Outbox is tied to the database that ImapDB runs, move the
Outbox code into that folder.
Outbox fixes and better parameter checking
Bumped Database thread pool count and made them exclusive
My reasoning is that there may be a need for a lot of threads at
once (when a big batch of commands comes in, especially at
startup). If performance looks ok, we might consider relaxing
this later.
2012-06-14 14:47:53 -07:00
|
|
|
if (open)
|
|
|
|
|
throw new EngineError.ALREADY_OPEN("Account %s already opened", to_string());
|
|
|
|
|
|
2014-06-12 13:01:47 -07:00
|
|
|
opening_monitor.notify_start();
|
|
|
|
|
|
|
|
|
|
Error? throw_err = null;
|
|
|
|
|
try {
|
|
|
|
|
yield internal_open_async(cancellable);
|
|
|
|
|
} catch (Error err) {
|
|
|
|
|
throw_err = err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
opening_monitor.notify_finish();
|
|
|
|
|
|
|
|
|
|
if (throw_err != null)
|
|
|
|
|
throw throw_err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async void internal_open_async(Cancellable? cancellable) throws Error {
|
2013-09-09 14:44:36 -07:00
|
|
|
try {
|
2016-07-04 23:02:28 +02:00
|
|
|
yield local.open_async(information.data_dir, Engine.instance.resource_dir.get_child("sql"),
|
2013-09-09 14:44:36 -07:00
|
|
|
cancellable);
|
|
|
|
|
} catch (Error err) {
|
|
|
|
|
// convert database-open errors
|
|
|
|
|
if (err is DatabaseError.CORRUPT)
|
|
|
|
|
throw new EngineError.CORRUPT("%s", err.message);
|
|
|
|
|
else if (err is DatabaseError.ACCESS)
|
|
|
|
|
throw new EngineError.PERMISSIONS("%s", err.message);
|
2013-09-09 15:41:31 -07:00
|
|
|
else if (err is DatabaseError.SCHEMA_VERSION)
|
|
|
|
|
throw new EngineError.VERSION("%s", err.message);
|
2013-09-09 14:44:36 -07:00
|
|
|
else
|
|
|
|
|
throw err;
|
|
|
|
|
}
|
2012-08-27 12:08:58 -07:00
|
|
|
|
|
|
|
|
// outbox is now available
|
|
|
|
|
local.outbox.report_problem.connect(notify_report_problem);
|
2013-01-17 12:50:30 -08:00
|
|
|
local_only.set(outbox_path, local.outbox);
|
2012-06-11 12:03:57 -07:00
|
|
|
|
2013-05-14 11:52:02 -07:00
|
|
|
// Search folder.
|
|
|
|
|
local_only.set(search_path, local.search_folder);
|
|
|
|
|
|
2014-10-28 16:31:31 -07:00
|
|
|
// To prevent spurious connection failures, we make sure we have the
|
|
|
|
|
// IMAP password before attempting a connection. This might have to be
|
|
|
|
|
// reworked when we allow passwordless logins.
|
|
|
|
|
if (!information.imap_credentials.is_complete())
|
|
|
|
|
yield information.fetch_passwords_async(ServiceFlag.IMAP);
|
|
|
|
|
|
2012-06-11 12:03:57 -07:00
|
|
|
// need to back out local.open_async() if remote fails
|
|
|
|
|
try {
|
|
|
|
|
yield remote.open_async(cancellable);
|
|
|
|
|
} catch (Error err) {
|
|
|
|
|
// back out
|
|
|
|
|
try {
|
|
|
|
|
yield local.close_async(cancellable);
|
|
|
|
|
} catch (Error close_err) {
|
|
|
|
|
// ignored
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw err;
|
|
|
|
|
}
|
|
|
|
|
|
Remove SQLHeavy: Closes #5034
It is done.
Initial implementation of the new database subsystem
These pieces represent the foundation for ticket #5034
Expanded transactions, added VersionedDatabase
Further expansions of the async code.
Moved async pool logic into Database, where it realistically
belongs.
Further improvements. Introduced geary-db-test.
Added SQL create and update files for Geary.Db
version-001 to version-003 are exact copies of the SQLHeavy scripts
to ensure no slight changes when migrating. version-004 upgrades
the database to remove the ImapFolderPropertiesTable and
ImapMessagePropertiesTable, now that the database code is pure
IMAP.
When we support other messaging systems (such as POP3), those
subsystems will need to code their own database layers OR rely on
the IMAP schema and simply ignore the IMAP-specific fields.
ImapDB.Account fleshed out
ImapDB.Folder is commented out, however. Need to port next.
ImapDB.Folder fleshed out
MessageTable, MessageLocationTable, and AttachementTable are now
handled inside ImapDB.Folder.
chmod -x imap-db-database.vala
OutboxEmailIdentifier/Properties -> SmtpOutboxEmailIdentifier/Properties
Moved SmtpOutboxFolderRoot into its own source file
SmtpOutboxFolder ported to new database code
Move Engine implementations to ImapDB.
Integration and cleanup of new database code with main source
This commit performs the final integration steps to move Geary
completely over to the new database model. This also cleans out
the old SQLHeavy-based code and fixes a handful of small bugs that
were detected during basic test runs.
Moved Outbox to ImapDB
As the Outbox is tied to the database that ImapDB runs, move the
Outbox code into that folder.
Outbox fixes and better parameter checking
Bumped Database thread pool count and made them exclusive
My reasoning is that there may be a need for a lot of threads at
once (when a big batch of commands comes in, especially at
startup). If performance looks ok, we might consider relaxing
this later.
2012-06-14 14:47:53 -07:00
|
|
|
open = true;
|
2012-06-11 12:03:57 -07:00
|
|
|
|
|
|
|
|
notify_opened();
|
2013-01-17 12:50:30 -08:00
|
|
|
|
2013-06-11 19:57:43 -07:00
|
|
|
notify_folders_available_unavailable(sort_by_path(local_only.values), null);
|
2013-02-25 20:18:37 -08:00
|
|
|
|
|
|
|
|
// schedule an immediate sweep of the folders; once this is finished, folders will be
|
|
|
|
|
// regularly enumerated
|
|
|
|
|
reschedule_folder_refresh(true);
|
2012-06-11 12:03:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override async void close_async(Cancellable? cancellable = null) throws Error {
|
Remove SQLHeavy: Closes #5034
It is done.
Initial implementation of the new database subsystem
These pieces represent the foundation for ticket #5034
Expanded transactions, added VersionedDatabase
Further expansions of the async code.
Moved async pool logic into Database, where it realistically
belongs.
Further improvements. Introduced geary-db-test.
Added SQL create and update files for Geary.Db
version-001 to version-003 are exact copies of the SQLHeavy scripts
to ensure no slight changes when migrating. version-004 upgrades
the database to remove the ImapFolderPropertiesTable and
ImapMessagePropertiesTable, now that the database code is pure
IMAP.
When we support other messaging systems (such as POP3), those
subsystems will need to code their own database layers OR rely on
the IMAP schema and simply ignore the IMAP-specific fields.
ImapDB.Account fleshed out
ImapDB.Folder is commented out, however. Need to port next.
ImapDB.Folder fleshed out
MessageTable, MessageLocationTable, and AttachementTable are now
handled inside ImapDB.Folder.
chmod -x imap-db-database.vala
OutboxEmailIdentifier/Properties -> SmtpOutboxEmailIdentifier/Properties
Moved SmtpOutboxFolderRoot into its own source file
SmtpOutboxFolder ported to new database code
Move Engine implementations to ImapDB.
Integration and cleanup of new database code with main source
This commit performs the final integration steps to move Geary
completely over to the new database model. This also cleans out
the old SQLHeavy-based code and fixes a handful of small bugs that
were detected during basic test runs.
Moved Outbox to ImapDB
As the Outbox is tied to the database that ImapDB runs, move the
Outbox code into that folder.
Outbox fixes and better parameter checking
Bumped Database thread pool count and made them exclusive
My reasoning is that there may be a need for a lot of threads at
once (when a big batch of commands comes in, especially at
startup). If performance looks ok, we might consider relaxing
this later.
2012-06-14 14:47:53 -07:00
|
|
|
if (!open)
|
|
|
|
|
return;
|
2013-01-17 12:50:30 -08:00
|
|
|
|
2013-06-11 19:57:43 -07:00
|
|
|
notify_folders_available_unavailable(null, sort_by_path(local_only.values));
|
|
|
|
|
notify_folders_available_unavailable(null, sort_by_path(folder_map.values));
|
Remove SQLHeavy: Closes #5034
It is done.
Initial implementation of the new database subsystem
These pieces represent the foundation for ticket #5034
Expanded transactions, added VersionedDatabase
Further expansions of the async code.
Moved async pool logic into Database, where it realistically
belongs.
Further improvements. Introduced geary-db-test.
Added SQL create and update files for Geary.Db
version-001 to version-003 are exact copies of the SQLHeavy scripts
to ensure no slight changes when migrating. version-004 upgrades
the database to remove the ImapFolderPropertiesTable and
ImapMessagePropertiesTable, now that the database code is pure
IMAP.
When we support other messaging systems (such as POP3), those
subsystems will need to code their own database layers OR rely on
the IMAP schema and simply ignore the IMAP-specific fields.
ImapDB.Account fleshed out
ImapDB.Folder is commented out, however. Need to port next.
ImapDB.Folder fleshed out
MessageTable, MessageLocationTable, and AttachementTable are now
handled inside ImapDB.Folder.
chmod -x imap-db-database.vala
OutboxEmailIdentifier/Properties -> SmtpOutboxEmailIdentifier/Properties
Moved SmtpOutboxFolderRoot into its own source file
SmtpOutboxFolder ported to new database code
Move Engine implementations to ImapDB.
Integration and cleanup of new database code with main source
This commit performs the final integration steps to move Geary
completely over to the new database model. This also cleans out
the old SQLHeavy-based code and fixes a handful of small bugs that
were detected during basic test runs.
Moved Outbox to ImapDB
As the Outbox is tied to the database that ImapDB runs, move the
Outbox code into that folder.
Outbox fixes and better parameter checking
Bumped Database thread pool count and made them exclusive
My reasoning is that there may be a need for a lot of threads at
once (when a big batch of commands comes in, especially at
startup). If performance looks ok, we might consider relaxing
this later.
2012-06-14 14:47:53 -07:00
|
|
|
|
2012-08-27 12:08:58 -07:00
|
|
|
local.outbox.report_problem.disconnect(notify_report_problem);
|
|
|
|
|
|
2012-06-11 12:03:57 -07:00
|
|
|
// attempt to close both regardless of errors
|
|
|
|
|
Error? local_err = null;
|
|
|
|
|
try {
|
|
|
|
|
yield local.close_async(cancellable);
|
|
|
|
|
} catch (Error lclose_err) {
|
|
|
|
|
local_err = lclose_err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Error? remote_err = null;
|
|
|
|
|
try {
|
|
|
|
|
yield remote.close_async(cancellable);
|
|
|
|
|
} catch (Error rclose_err) {
|
|
|
|
|
remote_err = rclose_err;
|
|
|
|
|
}
|
2013-05-31 17:56:48 -07:00
|
|
|
|
|
|
|
|
folder_map.clear();
|
2013-01-17 12:50:30 -08:00
|
|
|
local_only.clear();
|
2013-02-04 19:26:48 -08:00
|
|
|
open = false;
|
2012-06-11 12:03:57 -07:00
|
|
|
|
|
|
|
|
if (local_err != null)
|
|
|
|
|
throw local_err;
|
|
|
|
|
|
|
|
|
|
if (remote_err != null)
|
|
|
|
|
throw remote_err;
|
2011-06-23 19:07:04 -07:00
|
|
|
}
|
|
|
|
|
|
2013-02-04 19:26:48 -08:00
|
|
|
public override bool is_open() {
|
|
|
|
|
return open;
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-09 14:44:36 -07:00
|
|
|
public override async void rebuild_async(Cancellable? cancellable = null) throws Error {
|
|
|
|
|
if (open)
|
|
|
|
|
throw new EngineError.ALREADY_OPEN("Account cannot be open during rebuild");
|
|
|
|
|
|
|
|
|
|
message("%s: Rebuilding account local data", to_string());
|
|
|
|
|
|
|
|
|
|
// get all the storage locations associated with this Account
|
|
|
|
|
File db_file;
|
|
|
|
|
File attachments_dir;
|
2016-07-04 23:02:28 +02:00
|
|
|
ImapDB.Account.get_imap_db_storage_locations(information.data_dir, out db_file,
|
2013-09-09 14:44:36 -07:00
|
|
|
out attachments_dir);
|
|
|
|
|
|
|
|
|
|
if (yield Files.query_exists_async(db_file, cancellable)) {
|
|
|
|
|
message("%s: Deleting database file %s...", to_string(), db_file.get_path());
|
|
|
|
|
yield db_file.delete_async(Priority.DEFAULT, cancellable);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (yield Files.query_exists_async(attachments_dir, cancellable)) {
|
|
|
|
|
message("%s: Deleting attachments directory %s...", to_string(), attachments_dir.get_path());
|
|
|
|
|
yield Files.recursive_delete_async(attachments_dir, cancellable);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
message("%s: Rebuild complete", to_string());
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-11 15:24:01 -08:00
|
|
|
// Subclasses should implement this to return their flavor of a MinimalFolder with the
|
2012-06-27 18:25:45 -07:00
|
|
|
// appropriate interfaces attached. The returned folder should have its SpecialFolderType
|
|
|
|
|
// set using either the properties from the local folder or its path.
|
2012-06-22 14:42:51 -07:00
|
|
|
//
|
2013-05-14 11:52:02 -07:00
|
|
|
// This won't be called to build the Outbox or search folder, but for all others (including Inbox) it will.
|
2014-02-11 15:24:01 -08:00
|
|
|
protected abstract MinimalFolder new_folder(Geary.FolderPath path, Imap.Account remote_account,
|
Remove SQLHeavy: Closes #5034
It is done.
Initial implementation of the new database subsystem
These pieces represent the foundation for ticket #5034
Expanded transactions, added VersionedDatabase
Further expansions of the async code.
Moved async pool logic into Database, where it realistically
belongs.
Further improvements. Introduced geary-db-test.
Added SQL create and update files for Geary.Db
version-001 to version-003 are exact copies of the SQLHeavy scripts
to ensure no slight changes when migrating. version-004 upgrades
the database to remove the ImapFolderPropertiesTable and
ImapMessagePropertiesTable, now that the database code is pure
IMAP.
When we support other messaging systems (such as POP3), those
subsystems will need to code their own database layers OR rely on
the IMAP schema and simply ignore the IMAP-specific fields.
ImapDB.Account fleshed out
ImapDB.Folder is commented out, however. Need to port next.
ImapDB.Folder fleshed out
MessageTable, MessageLocationTable, and AttachementTable are now
handled inside ImapDB.Folder.
chmod -x imap-db-database.vala
OutboxEmailIdentifier/Properties -> SmtpOutboxEmailIdentifier/Properties
Moved SmtpOutboxFolderRoot into its own source file
SmtpOutboxFolder ported to new database code
Move Engine implementations to ImapDB.
Integration and cleanup of new database code with main source
This commit performs the final integration steps to move Geary
completely over to the new database model. This also cleans out
the old SQLHeavy-based code and fixes a handful of small bugs that
were detected during basic test runs.
Moved Outbox to ImapDB
As the Outbox is tied to the database that ImapDB runs, move the
Outbox code into that folder.
Outbox fixes and better parameter checking
Bumped Database thread pool count and made them exclusive
My reasoning is that there may be a need for a lot of threads at
once (when a big batch of commands comes in, especially at
startup). If performance looks ok, we might consider relaxing
this later.
2012-06-14 14:47:53 -07:00
|
|
|
ImapDB.Account local_account, ImapDB.Folder local_folder);
|
2012-06-22 14:42:51 -07:00
|
|
|
|
2013-08-19 16:39:53 -07:00
|
|
|
// Subclasses with specific SearchFolder implementations should override
|
|
|
|
|
// this to return the correct subclass.
|
|
|
|
|
internal virtual SearchFolder new_search_folder() {
|
2015-03-02 17:34:17 -08:00
|
|
|
return new ImapDB.SearchFolder(this);
|
2013-08-19 16:39:53 -07:00
|
|
|
}
|
|
|
|
|
|
2014-02-11 15:24:01 -08:00
|
|
|
private MinimalFolder build_folder(ImapDB.Folder local_folder) {
|
2014-01-29 18:32:53 -08:00
|
|
|
return Geary.Collection.get_first(build_folders(
|
|
|
|
|
Geary.iterate<ImapDB.Folder>(local_folder).to_array_list()));
|
2013-01-17 12:50:30 -08:00
|
|
|
}
|
|
|
|
|
|
2014-02-11 15:24:01 -08:00
|
|
|
private Gee.Collection<MinimalFolder> build_folders(Gee.Collection<ImapDB.Folder> local_folders) {
|
2013-01-17 12:50:30 -08:00
|
|
|
Gee.ArrayList<ImapDB.Folder> folders_to_build = new Gee.ArrayList<ImapDB.Folder>();
|
2014-02-11 15:24:01 -08:00
|
|
|
Gee.ArrayList<MinimalFolder> built_folders = new Gee.ArrayList<MinimalFolder>();
|
|
|
|
|
Gee.ArrayList<MinimalFolder> return_folders = new Gee.ArrayList<MinimalFolder>();
|
2013-05-31 17:56:48 -07:00
|
|
|
|
2013-01-17 12:50:30 -08:00
|
|
|
foreach(ImapDB.Folder local_folder in local_folders) {
|
2013-05-31 17:56:48 -07:00
|
|
|
if (folder_map.has_key(local_folder.get_path()))
|
|
|
|
|
return_folders.add(folder_map.get(local_folder.get_path()));
|
2013-01-17 12:50:30 -08:00
|
|
|
else
|
|
|
|
|
folders_to_build.add(local_folder);
|
|
|
|
|
}
|
2013-05-31 17:56:48 -07:00
|
|
|
|
2013-01-17 12:50:30 -08:00
|
|
|
foreach(ImapDB.Folder folder_to_build in folders_to_build) {
|
2014-02-11 15:24:01 -08:00
|
|
|
MinimalFolder folder = new_folder(folder_to_build.get_path(), remote, local, folder_to_build);
|
2013-06-26 15:02:33 -07:00
|
|
|
folder_map.set(folder.path, folder);
|
2013-01-17 12:50:30 -08:00
|
|
|
built_folders.add(folder);
|
|
|
|
|
return_folders.add(folder);
|
|
|
|
|
}
|
2013-05-31 17:56:48 -07:00
|
|
|
|
2013-01-17 12:50:30 -08:00
|
|
|
if (built_folders.size > 0)
|
2013-06-11 19:57:43 -07:00
|
|
|
notify_folders_available_unavailable(sort_by_path(built_folders), null);
|
2013-02-25 20:18:37 -08:00
|
|
|
|
2013-01-17 12:50:30 -08:00
|
|
|
return return_folders;
|
2012-06-14 16:47:54 -07:00
|
|
|
}
|
|
|
|
|
|
2013-06-10 20:07:12 -07:00
|
|
|
public override Gee.Collection<Geary.Folder> list_matching_folders(Geary.FolderPath? parent)
|
|
|
|
|
throws Error {
|
2013-01-31 15:17:44 -08:00
|
|
|
check_open();
|
|
|
|
|
|
2013-12-12 12:42:02 -08:00
|
|
|
return Geary.traverse<FolderPath>(folder_map.keys)
|
|
|
|
|
.filter(p => {
|
|
|
|
|
FolderPath? path_parent = p.get_parent();
|
|
|
|
|
return ((parent == null && path_parent == null) ||
|
|
|
|
|
(parent != null && path_parent != null && path_parent.equal_to(parent)));
|
|
|
|
|
})
|
|
|
|
|
.map<Geary.Folder>(p => folder_map.get(p))
|
|
|
|
|
.to_array_list();
|
2013-01-17 12:50:30 -08:00
|
|
|
}
|
|
|
|
|
|
2013-01-31 15:17:44 -08:00
|
|
|
public override Gee.Collection<Geary.Folder> list_folders() throws Error {
|
|
|
|
|
check_open();
|
2013-05-14 11:52:02 -07:00
|
|
|
Gee.HashSet<Geary.Folder> all_folders = new Gee.HashSet<Geary.Folder>();
|
2013-06-14 16:34:06 -07:00
|
|
|
all_folders.add_all(folder_map.values);
|
2013-05-14 11:52:02 -07:00
|
|
|
all_folders.add_all(local_only.values);
|
2013-02-25 20:18:37 -08:00
|
|
|
|
2013-05-14 11:52:02 -07:00
|
|
|
return all_folders;
|
2013-01-31 15:17:44 -08:00
|
|
|
}
|
|
|
|
|
|
2014-03-03 15:05:41 -08:00
|
|
|
private void reschedule_unseen_update(Geary.Folder folder) {
|
|
|
|
|
if (!folder_map.has_key(folder.path))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (refresh_unseen_timeout_ids.get(folder.path) != 0)
|
|
|
|
|
Source.remove(refresh_unseen_timeout_ids.get(folder.path));
|
|
|
|
|
|
|
|
|
|
refresh_unseen_timeout_ids.set(folder.path,
|
|
|
|
|
Timeout.add_seconds(REFRESH_UNSEEN_SEC, () => on_refresh_unseen(folder)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool on_refresh_unseen(Geary.Folder folder) {
|
|
|
|
|
// If we're in the process already, reschedule for later.
|
|
|
|
|
if (in_refresh_unseen.contains(folder))
|
|
|
|
|
return true;
|
|
|
|
|
|
2015-02-05 17:57:27 -08:00
|
|
|
// add here, remove in completed callback
|
|
|
|
|
in_refresh_unseen.add(folder);
|
|
|
|
|
|
2014-03-03 15:05:41 -08:00
|
|
|
refresh_unseen_async.begin(folder, null, on_refresh_unseen_completed);
|
|
|
|
|
|
|
|
|
|
refresh_unseen_timeout_ids.unset(folder.path);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void on_refresh_unseen_completed(Object? source, AsyncResult result) {
|
|
|
|
|
try {
|
|
|
|
|
refresh_unseen_async.end(result);
|
|
|
|
|
} catch (Error e) {
|
|
|
|
|
debug("Error refreshing unseen counts: %s", e.message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async void refresh_unseen_async(Geary.Folder folder, Cancellable? cancellable) throws Error {
|
|
|
|
|
debug("Refreshing unseen counts for %s", folder.to_string());
|
|
|
|
|
|
2015-02-05 17:57:27 -08:00
|
|
|
try {
|
|
|
|
|
bool folder_created;
|
|
|
|
|
Imap.Folder remote_folder = yield remote.fetch_folder_async(folder.path,
|
|
|
|
|
out folder_created, null, cancellable);
|
|
|
|
|
|
|
|
|
|
// if created, don't need to fetch count because it was fetched when it was created
|
|
|
|
|
int unseen, total;
|
|
|
|
|
if (!folder_created) {
|
|
|
|
|
yield remote.fetch_counts_async(folder.path, out unseen, out total, cancellable);
|
|
|
|
|
remote_folder.properties.set_status_unseen(unseen);
|
|
|
|
|
remote_folder.properties.set_status_message_count(total, false);
|
|
|
|
|
} else {
|
|
|
|
|
unseen = remote_folder.properties.unseen;
|
|
|
|
|
total = remote_folder.properties.email_total;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield local.update_folder_status_async(remote_folder, false, true, cancellable);
|
|
|
|
|
} finally {
|
|
|
|
|
// added when call scheduled (above)
|
|
|
|
|
in_refresh_unseen.remove(folder);
|
2014-03-03 15:05:41 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-25 20:18:37 -08:00
|
|
|
private void reschedule_folder_refresh(bool immediate) {
|
|
|
|
|
if (in_refresh_enumerate)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
cancel_folder_refresh();
|
|
|
|
|
|
|
|
|
|
refresh_folder_timeout_id = immediate
|
|
|
|
|
? Idle.add(on_refresh_folders)
|
|
|
|
|
: Timeout.add_seconds(REFRESH_FOLDER_LIST_SEC, on_refresh_folders);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void cancel_folder_refresh() {
|
|
|
|
|
if (refresh_folder_timeout_id != 0) {
|
|
|
|
|
Source.remove(refresh_folder_timeout_id);
|
|
|
|
|
refresh_folder_timeout_id = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool on_refresh_folders() {
|
|
|
|
|
in_refresh_enumerate = true;
|
2013-05-31 17:56:48 -07:00
|
|
|
enumerate_folders_async.begin(refresh_cancellable, on_refresh_completed);
|
2013-02-25 20:18:37 -08:00
|
|
|
|
|
|
|
|
refresh_folder_timeout_id = 0;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void on_refresh_completed(Object? source, AsyncResult result) {
|
|
|
|
|
try {
|
|
|
|
|
enumerate_folders_async.end(result);
|
|
|
|
|
} catch (Error err) {
|
|
|
|
|
if (!(err is IOError.CANCELLED))
|
|
|
|
|
debug("Refresh of account %s folders did not complete: %s", to_string(), err.message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
in_refresh_enumerate = false;
|
|
|
|
|
reschedule_folder_refresh(false);
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-31 17:56:48 -07:00
|
|
|
private async void enumerate_folders_async(Cancellable? cancellable) throws Error {
|
Remove SQLHeavy: Closes #5034
It is done.
Initial implementation of the new database subsystem
These pieces represent the foundation for ticket #5034
Expanded transactions, added VersionedDatabase
Further expansions of the async code.
Moved async pool logic into Database, where it realistically
belongs.
Further improvements. Introduced geary-db-test.
Added SQL create and update files for Geary.Db
version-001 to version-003 are exact copies of the SQLHeavy scripts
to ensure no slight changes when migrating. version-004 upgrades
the database to remove the ImapFolderPropertiesTable and
ImapMessagePropertiesTable, now that the database code is pure
IMAP.
When we support other messaging systems (such as POP3), those
subsystems will need to code their own database layers OR rely on
the IMAP schema and simply ignore the IMAP-specific fields.
ImapDB.Account fleshed out
ImapDB.Folder is commented out, however. Need to port next.
ImapDB.Folder fleshed out
MessageTable, MessageLocationTable, and AttachementTable are now
handled inside ImapDB.Folder.
chmod -x imap-db-database.vala
OutboxEmailIdentifier/Properties -> SmtpOutboxEmailIdentifier/Properties
Moved SmtpOutboxFolderRoot into its own source file
SmtpOutboxFolder ported to new database code
Move Engine implementations to ImapDB.
Integration and cleanup of new database code with main source
This commit performs the final integration steps to move Geary
completely over to the new database model. This also cleans out
the old SQLHeavy-based code and fixes a handful of small bugs that
were detected during basic test runs.
Moved Outbox to ImapDB
As the Outbox is tied to the database that ImapDB runs, move the
Outbox code into that folder.
Outbox fixes and better parameter checking
Bumped Database thread pool count and made them exclusive
My reasoning is that there may be a need for a lot of threads at
once (when a big batch of commands comes in, especially at
startup). If performance looks ok, we might consider relaxing
this later.
2012-06-14 14:47:53 -07:00
|
|
|
check_open();
|
|
|
|
|
|
2014-01-17 16:34:19 -08:00
|
|
|
// enumerate local folders first
|
|
|
|
|
Gee.HashMap<FolderPath, ImapDB.Folder> local_folders = yield enumerate_local_folders_async(
|
|
|
|
|
null, cancellable);
|
2013-05-31 17:56:48 -07:00
|
|
|
|
|
|
|
|
// convert to a list of Geary.Folder ... build_folder() also reports new folders, so this
|
2014-01-17 16:34:19 -08:00
|
|
|
// gets the word out quickly (local_only folders have already been reported)
|
2013-05-31 17:56:48 -07:00
|
|
|
Gee.Collection<Geary.Folder> existing_list = new Gee.ArrayList<Geary.Folder>();
|
2014-01-17 16:34:19 -08:00
|
|
|
existing_list.add_all(build_folders(local_folders.values));
|
2013-05-31 17:56:48 -07:00
|
|
|
existing_list.add_all(local_only.values);
|
|
|
|
|
|
2014-01-17 16:34:19 -08:00
|
|
|
// build a map of all existing folders
|
2013-12-12 12:42:02 -08:00
|
|
|
Gee.HashMap<FolderPath, Geary.Folder> existing_folders
|
|
|
|
|
= Geary.traverse<Geary.Folder>(existing_list).to_hash_map<FolderPath>(f => f.path);
|
2013-05-31 17:56:48 -07:00
|
|
|
|
2014-01-17 16:34:19 -08:00
|
|
|
// now that all local have been enumerated and reported (this is important to assist
|
|
|
|
|
// startup of the UI), enumerate the remote folders
|
2014-03-11 12:12:37 -07:00
|
|
|
bool remote_folders_suspect;
|
2014-01-17 16:34:19 -08:00
|
|
|
Gee.HashMap<FolderPath, Imap.Folder>? remote_folders = yield enumerate_remote_folders_async(
|
2014-03-11 12:12:37 -07:00
|
|
|
null, out remote_folders_suspect, cancellable);
|
2013-05-31 17:56:48 -07:00
|
|
|
|
2014-01-17 16:34:19 -08:00
|
|
|
// pair the local and remote folders and make sure everything is up-to-date
|
2014-03-11 12:12:37 -07:00
|
|
|
yield update_folders_async(existing_folders, remote_folders, remote_folders_suspect, cancellable);
|
2013-05-31 17:56:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Gee.HashMap<FolderPath, ImapDB.Folder> enumerate_local_folders_async(
|
|
|
|
|
Geary.FolderPath? parent, Cancellable? cancellable) throws Error {
|
|
|
|
|
check_open();
|
|
|
|
|
|
|
|
|
|
Gee.Collection<ImapDB.Folder>? local_children = null;
|
2011-07-01 15:40:20 -07:00
|
|
|
try {
|
2013-05-31 17:56:48 -07:00
|
|
|
local_children = yield local.list_folders_async(parent, cancellable);
|
2011-07-01 15:40:20 -07:00
|
|
|
} catch (EngineError err) {
|
|
|
|
|
// don't pass on NOT_FOUND's, that means we need to go to the server for more info
|
|
|
|
|
if (!(err is EngineError.NOT_FOUND))
|
|
|
|
|
throw err;
|
|
|
|
|
}
|
2011-06-16 16:27:08 -07:00
|
|
|
|
2013-05-31 17:56:48 -07:00
|
|
|
Gee.HashMap<FolderPath, ImapDB.Folder> result = new Gee.HashMap<FolderPath, ImapDB.Folder>();
|
|
|
|
|
if (local_children != null) {
|
|
|
|
|
foreach (ImapDB.Folder local_child in local_children) {
|
|
|
|
|
result.set(local_child.get_path(), local_child);
|
|
|
|
|
Collection.map_set_all<FolderPath, ImapDB.Folder>(result,
|
|
|
|
|
yield enumerate_local_folders_async(local_child.get_path(), cancellable));
|
|
|
|
|
}
|
2011-07-01 15:40:20 -07:00
|
|
|
}
|
2011-06-16 16:27:08 -07:00
|
|
|
|
2013-05-31 17:56:48 -07:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Gee.HashMap<FolderPath, Imap.Folder> enumerate_remote_folders_async(
|
2014-03-11 12:12:37 -07:00
|
|
|
Geary.FolderPath? parent, out bool results_suspect, Cancellable? cancellable) throws Error {
|
|
|
|
|
results_suspect = false;
|
2013-05-31 17:56:48 -07:00
|
|
|
check_open();
|
|
|
|
|
|
|
|
|
|
Gee.List<Imap.Folder>? remote_children = null;
|
|
|
|
|
try {
|
|
|
|
|
remote_children = yield remote.list_child_folders_async(parent, cancellable);
|
|
|
|
|
} catch (Error err) {
|
2014-01-29 11:06:32 -08:00
|
|
|
// ignore everything but I/O and IMAP errors (cancellation is an IOError)
|
|
|
|
|
if (err is IOError || err is ImapError)
|
2013-05-31 17:56:48 -07:00
|
|
|
throw err;
|
2014-03-11 12:12:37 -07:00
|
|
|
debug("Ignoring error listing child folders of %s: %s",
|
|
|
|
|
(parent != null ? parent.to_string() : "root"), err.message);
|
|
|
|
|
results_suspect = true;
|
2011-07-01 15:40:20 -07:00
|
|
|
}
|
2012-06-22 14:42:51 -07:00
|
|
|
|
2013-05-31 17:56:48 -07:00
|
|
|
Gee.HashMap<FolderPath, Imap.Folder> result = new Gee.HashMap<FolderPath, Imap.Folder>();
|
|
|
|
|
if (remote_children != null) {
|
|
|
|
|
foreach (Imap.Folder remote_child in remote_children) {
|
|
|
|
|
result.set(remote_child.path, remote_child);
|
2013-06-05 18:24:42 -07:00
|
|
|
if (remote_child.properties.has_children.is_possible()) {
|
2014-03-11 12:12:37 -07:00
|
|
|
bool recursive_results_suspect;
|
2013-06-05 18:24:42 -07:00
|
|
|
Collection.map_set_all<FolderPath, Imap.Folder>(result,
|
2014-03-11 12:12:37 -07:00
|
|
|
yield enumerate_remote_folders_async(
|
|
|
|
|
remote_child.path, out recursive_results_suspect, cancellable));
|
|
|
|
|
if (recursive_results_suspect)
|
|
|
|
|
results_suspect = true;
|
2013-06-05 18:24:42 -07:00
|
|
|
}
|
2013-05-31 17:56:48 -07:00
|
|
|
}
|
|
|
|
|
}
|
2012-06-22 14:42:51 -07:00
|
|
|
|
2013-05-31 17:56:48 -07:00
|
|
|
return result;
|
2011-06-16 16:27:08 -07:00
|
|
|
}
|
|
|
|
|
|
2012-07-20 17:51:28 -07:00
|
|
|
public override Geary.ContactStore get_contact_store() {
|
|
|
|
|
return local.contact_store;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-04 13:54:00 -07:00
|
|
|
public override async bool folder_exists_async(Geary.FolderPath path,
|
|
|
|
|
Cancellable? cancellable = null) throws Error {
|
Remove SQLHeavy: Closes #5034
It is done.
Initial implementation of the new database subsystem
These pieces represent the foundation for ticket #5034
Expanded transactions, added VersionedDatabase
Further expansions of the async code.
Moved async pool logic into Database, where it realistically
belongs.
Further improvements. Introduced geary-db-test.
Added SQL create and update files for Geary.Db
version-001 to version-003 are exact copies of the SQLHeavy scripts
to ensure no slight changes when migrating. version-004 upgrades
the database to remove the ImapFolderPropertiesTable and
ImapMessagePropertiesTable, now that the database code is pure
IMAP.
When we support other messaging systems (such as POP3), those
subsystems will need to code their own database layers OR rely on
the IMAP schema and simply ignore the IMAP-specific fields.
ImapDB.Account fleshed out
ImapDB.Folder is commented out, however. Need to port next.
ImapDB.Folder fleshed out
MessageTable, MessageLocationTable, and AttachementTable are now
handled inside ImapDB.Folder.
chmod -x imap-db-database.vala
OutboxEmailIdentifier/Properties -> SmtpOutboxEmailIdentifier/Properties
Moved SmtpOutboxFolderRoot into its own source file
SmtpOutboxFolder ported to new database code
Move Engine implementations to ImapDB.
Integration and cleanup of new database code with main source
This commit performs the final integration steps to move Geary
completely over to the new database model. This also cleans out
the old SQLHeavy-based code and fixes a handful of small bugs that
were detected during basic test runs.
Moved Outbox to ImapDB
As the Outbox is tied to the database that ImapDB runs, move the
Outbox code into that folder.
Outbox fixes and better parameter checking
Bumped Database thread pool count and made them exclusive
My reasoning is that there may be a need for a lot of threads at
once (when a big batch of commands comes in, especially at
startup). If performance looks ok, we might consider relaxing
this later.
2012-06-14 14:47:53 -07:00
|
|
|
check_open();
|
|
|
|
|
|
2011-07-04 13:54:00 -07:00
|
|
|
if (yield local.folder_exists_async(path, cancellable))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return yield remote.folder_exists_async(path, cancellable);
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-21 19:17:05 -07:00
|
|
|
// TODO: This needs to be made into a single transaction
|
2011-07-01 15:40:20 -07:00
|
|
|
public override async Geary.Folder fetch_folder_async(Geary.FolderPath path,
|
2011-06-16 16:27:08 -07:00
|
|
|
Cancellable? cancellable = null) throws Error {
|
Remove SQLHeavy: Closes #5034
It is done.
Initial implementation of the new database subsystem
These pieces represent the foundation for ticket #5034
Expanded transactions, added VersionedDatabase
Further expansions of the async code.
Moved async pool logic into Database, where it realistically
belongs.
Further improvements. Introduced geary-db-test.
Added SQL create and update files for Geary.Db
version-001 to version-003 are exact copies of the SQLHeavy scripts
to ensure no slight changes when migrating. version-004 upgrades
the database to remove the ImapFolderPropertiesTable and
ImapMessagePropertiesTable, now that the database code is pure
IMAP.
When we support other messaging systems (such as POP3), those
subsystems will need to code their own database layers OR rely on
the IMAP schema and simply ignore the IMAP-specific fields.
ImapDB.Account fleshed out
ImapDB.Folder is commented out, however. Need to port next.
ImapDB.Folder fleshed out
MessageTable, MessageLocationTable, and AttachementTable are now
handled inside ImapDB.Folder.
chmod -x imap-db-database.vala
OutboxEmailIdentifier/Properties -> SmtpOutboxEmailIdentifier/Properties
Moved SmtpOutboxFolderRoot into its own source file
SmtpOutboxFolder ported to new database code
Move Engine implementations to ImapDB.
Integration and cleanup of new database code with main source
This commit performs the final integration steps to move Geary
completely over to the new database model. This also cleans out
the old SQLHeavy-based code and fixes a handful of small bugs that
were detected during basic test runs.
Moved Outbox to ImapDB
As the Outbox is tied to the database that ImapDB runs, move the
Outbox code into that folder.
Outbox fixes and better parameter checking
Bumped Database thread pool count and made them exclusive
My reasoning is that there may be a need for a lot of threads at
once (when a big batch of commands comes in, especially at
startup). If performance looks ok, we might consider relaxing
this later.
2012-06-14 14:47:53 -07:00
|
|
|
check_open();
|
2012-06-11 12:03:57 -07:00
|
|
|
|
2013-01-17 12:50:30 -08:00
|
|
|
if (local_only.has_key(path))
|
|
|
|
|
return local_only.get(path);
|
2012-06-11 12:03:57 -07:00
|
|
|
|
2011-07-04 13:54:00 -07:00
|
|
|
try {
|
Remove SQLHeavy: Closes #5034
It is done.
Initial implementation of the new database subsystem
These pieces represent the foundation for ticket #5034
Expanded transactions, added VersionedDatabase
Further expansions of the async code.
Moved async pool logic into Database, where it realistically
belongs.
Further improvements. Introduced geary-db-test.
Added SQL create and update files for Geary.Db
version-001 to version-003 are exact copies of the SQLHeavy scripts
to ensure no slight changes when migrating. version-004 upgrades
the database to remove the ImapFolderPropertiesTable and
ImapMessagePropertiesTable, now that the database code is pure
IMAP.
When we support other messaging systems (such as POP3), those
subsystems will need to code their own database layers OR rely on
the IMAP schema and simply ignore the IMAP-specific fields.
ImapDB.Account fleshed out
ImapDB.Folder is commented out, however. Need to port next.
ImapDB.Folder fleshed out
MessageTable, MessageLocationTable, and AttachementTable are now
handled inside ImapDB.Folder.
chmod -x imap-db-database.vala
OutboxEmailIdentifier/Properties -> SmtpOutboxEmailIdentifier/Properties
Moved SmtpOutboxFolderRoot into its own source file
SmtpOutboxFolder ported to new database code
Move Engine implementations to ImapDB.
Integration and cleanup of new database code with main source
This commit performs the final integration steps to move Geary
completely over to the new database model. This also cleans out
the old SQLHeavy-based code and fixes a handful of small bugs that
were detected during basic test runs.
Moved Outbox to ImapDB
As the Outbox is tied to the database that ImapDB runs, move the
Outbox code into that folder.
Outbox fixes and better parameter checking
Bumped Database thread pool count and made them exclusive
My reasoning is that there may be a need for a lot of threads at
once (when a big batch of commands comes in, especially at
startup). If performance looks ok, we might consider relaxing
this later.
2012-06-14 14:47:53 -07:00
|
|
|
return build_folder((ImapDB.Folder) yield local.fetch_folder_async(path, cancellable));
|
2011-07-04 13:54:00 -07:00
|
|
|
} catch (EngineError err) {
|
|
|
|
|
// don't thrown NOT_FOUND's, that means we need to fall through and clone from the
|
|
|
|
|
// server
|
|
|
|
|
if (!(err is EngineError.NOT_FOUND))
|
|
|
|
|
throw err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// clone the entire path
|
|
|
|
|
int length = path.get_path_length();
|
|
|
|
|
for (int ctr = 0; ctr < length; ctr++) {
|
|
|
|
|
Geary.FolderPath folder = path.get_folder_at(ctr);
|
|
|
|
|
|
|
|
|
|
if (yield local.folder_exists_async(folder))
|
|
|
|
|
continue;
|
|
|
|
|
|
2012-03-14 11:05:32 -07:00
|
|
|
Imap.Folder remote_folder = (Imap.Folder) yield remote.fetch_folder_async(folder,
|
2015-01-22 17:11:01 -08:00
|
|
|
null, null, cancellable);
|
2011-07-04 13:54:00 -07:00
|
|
|
|
|
|
|
|
yield local.clone_folder_async(remote_folder, cancellable);
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-11 15:24:01 -08:00
|
|
|
// Fetch the local account's version of the folder for the MinimalFolder
|
Remove SQLHeavy: Closes #5034
It is done.
Initial implementation of the new database subsystem
These pieces represent the foundation for ticket #5034
Expanded transactions, added VersionedDatabase
Further expansions of the async code.
Moved async pool logic into Database, where it realistically
belongs.
Further improvements. Introduced geary-db-test.
Added SQL create and update files for Geary.Db
version-001 to version-003 are exact copies of the SQLHeavy scripts
to ensure no slight changes when migrating. version-004 upgrades
the database to remove the ImapFolderPropertiesTable and
ImapMessagePropertiesTable, now that the database code is pure
IMAP.
When we support other messaging systems (such as POP3), those
subsystems will need to code their own database layers OR rely on
the IMAP schema and simply ignore the IMAP-specific fields.
ImapDB.Account fleshed out
ImapDB.Folder is commented out, however. Need to port next.
ImapDB.Folder fleshed out
MessageTable, MessageLocationTable, and AttachementTable are now
handled inside ImapDB.Folder.
chmod -x imap-db-database.vala
OutboxEmailIdentifier/Properties -> SmtpOutboxEmailIdentifier/Properties
Moved SmtpOutboxFolderRoot into its own source file
SmtpOutboxFolder ported to new database code
Move Engine implementations to ImapDB.
Integration and cleanup of new database code with main source
This commit performs the final integration steps to move Geary
completely over to the new database model. This also cleans out
the old SQLHeavy-based code and fixes a handful of small bugs that
were detected during basic test runs.
Moved Outbox to ImapDB
As the Outbox is tied to the database that ImapDB runs, move the
Outbox code into that folder.
Outbox fixes and better parameter checking
Bumped Database thread pool count and made them exclusive
My reasoning is that there may be a need for a lot of threads at
once (when a big batch of commands comes in, especially at
startup). If performance looks ok, we might consider relaxing
this later.
2012-06-14 14:47:53 -07:00
|
|
|
return build_folder((ImapDB.Folder) yield local.fetch_folder_async(path, cancellable));
|
2011-06-16 16:27:08 -07:00
|
|
|
}
|
|
|
|
|
|
2015-01-09 15:09:53 -08:00
|
|
|
/**
|
|
|
|
|
* Returns an Imap.Folder that is not connected (is detached) to a MinimalFolder or any other
|
|
|
|
|
* ImapEngine container.
|
|
|
|
|
*
|
|
|
|
|
* This is useful for one-shot operations that need to bypass the heavyweight synchronization
|
|
|
|
|
* routines inside MinimalFolder. This also means that operations performed on this Folder will
|
|
|
|
|
* not be reflected in the local database unless there's a separate connection to the server
|
|
|
|
|
* that is notified or detects these changes.
|
|
|
|
|
*
|
2015-02-05 17:57:27 -08:00
|
|
|
* The returned Folder must be opened prior to use and closed once completed. ''Leaving a
|
|
|
|
|
* Folder open will cause a connection leak.''
|
|
|
|
|
*
|
2015-01-09 15:09:53 -08:00
|
|
|
* It is not recommended this object be held open long-term, or that its status or notifications
|
|
|
|
|
* be directly written to the database unless you know exactly what you're doing. ''Caveat
|
|
|
|
|
* implementor.''
|
|
|
|
|
*/
|
|
|
|
|
public async Imap.Folder fetch_detached_folder_async(Geary.FolderPath path, Cancellable? cancellable)
|
|
|
|
|
throws Error {
|
|
|
|
|
check_open();
|
|
|
|
|
|
|
|
|
|
if (local_only.has_key(path)) {
|
|
|
|
|
throw new EngineError.NOT_FOUND("%s: path %s points to local-only folder, not IMAP",
|
|
|
|
|
to_string(), path.to_string());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return yield remote.fetch_unrecycled_folder_async(path, cancellable);
|
|
|
|
|
}
|
2016-06-15 18:24:50 -04:00
|
|
|
|
|
|
|
|
private void compile_special_search_names() {
|
|
|
|
|
/*
|
|
|
|
|
* Compiles the list of names used to search for special
|
|
|
|
|
* folders when they aren't known in advance and the server
|
|
|
|
|
* supports neither SPECIAL-USE not XLIST.
|
|
|
|
|
*
|
|
|
|
|
* Uses both translated and untranslated names in case the
|
|
|
|
|
* server has not localised the folders that match the login
|
|
|
|
|
* session's language. Also checks for lower-case versions of
|
|
|
|
|
* each.
|
|
|
|
|
*/
|
|
|
|
|
foreach (Geary.SpecialFolderType type in this.supported_special_folders) {
|
|
|
|
|
Gee.List<string> compiled = new Gee.ArrayList<string>();
|
|
|
|
|
foreach (string names in get_special_search_names(type)) {
|
|
|
|
|
foreach (string name in names.split("|")) {
|
|
|
|
|
name = name.strip();
|
|
|
|
|
if (name.length != 0) {
|
|
|
|
|
if (!(name in compiled)) {
|
|
|
|
|
compiled.add(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
name = name.down();
|
|
|
|
|
if (!(name in compiled)) {
|
|
|
|
|
compiled.add(name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
special_search_names.set(type, compiled);
|
2014-02-11 15:24:01 -08:00
|
|
|
}
|
|
|
|
|
}
|
2016-06-15 18:24:50 -04:00
|
|
|
|
|
|
|
|
private Gee.List<string> get_special_search_names(Geary.SpecialFolderType type) {
|
|
|
|
|
Gee.List<string> loc_names = new Gee.ArrayList<string>();
|
|
|
|
|
Gee.List<string> unloc_names = new Gee.ArrayList<string>();
|
|
|
|
|
switch (type) {
|
|
|
|
|
case Geary.SpecialFolderType.DRAFTS:
|
|
|
|
|
// List of general possible folder names to match for the
|
|
|
|
|
// Draft mailbox. Separate names using a vertical bar and
|
|
|
|
|
// put the most common localized name to the front for the
|
|
|
|
|
// default. English names do not need to be included.
|
|
|
|
|
loc_names.add(_("Drafts | Draft"));
|
|
|
|
|
unloc_names.add("Drafts | Draft");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Geary.SpecialFolderType.SENT:
|
|
|
|
|
// List of general possible folder names to match for the
|
|
|
|
|
// Sent mailbox. Separate names using a vertical bar and
|
|
|
|
|
// put the most common localized name to the front for the
|
|
|
|
|
// default. English names do not need to be included.
|
|
|
|
|
loc_names.add(_("Sent | Sent Mail | Sent Email | Sent E-Mail"));
|
|
|
|
|
unloc_names.add("Sent | Sent Mail | Sent Email | Sent E-Mail");
|
|
|
|
|
|
|
|
|
|
// The localised name(s) of the Sent folder name as used
|
|
|
|
|
// by MS Outlook/Exchange.
|
|
|
|
|
loc_names.add(NC_("Outlook localised name", "Sent Items"));
|
|
|
|
|
unloc_names.add("Sent Items");
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Geary.SpecialFolderType.SPAM:
|
|
|
|
|
// List of general possible folder names to match for the
|
|
|
|
|
// Spam mailbox. Separate names using a vertical bar and
|
|
|
|
|
// put the most common localized name to the front for the
|
|
|
|
|
// default. English names do not need to be included.
|
|
|
|
|
loc_names.add(_("Junk | Spam | Junk Mail | Junk Email | Junk E-Mail | Bulk Mail | Bulk Email | Bulk E-Mail"));
|
|
|
|
|
unloc_names.add("Junk | Spam | Junk Mail | Junk Email | Junk E-Mail | Bulk Mail | Bulk Email | Bulk E-Mail");
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Geary.SpecialFolderType.TRASH:
|
|
|
|
|
// List of general possible folder names to match for the
|
|
|
|
|
// Trash mailbox. Separate names using a vertical bar and
|
|
|
|
|
// put the most common localized name to the front for the
|
|
|
|
|
// default. English names do not need to be included.
|
|
|
|
|
loc_names.add(_("Trash | Rubbish | Rubbish Bin"));
|
|
|
|
|
unloc_names.add("Trash | Rubbish | Rubbish Bin");
|
|
|
|
|
|
|
|
|
|
// The localised name(s) of the Trash folder name as used
|
|
|
|
|
// by MS Outlook/Exchange.
|
|
|
|
|
loc_names.add(NC_("Outlook localised name", "Deleted Items"));
|
|
|
|
|
unloc_names.add("Deleted Items");
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Geary.SpecialFolderType.ARCHIVE:
|
|
|
|
|
// List of general possible folder names to match for the
|
|
|
|
|
// Archive mailbox. Separate names using a vertical bar
|
|
|
|
|
// and put the most common localized name to the front for
|
|
|
|
|
// the default. English names do not need to be included.
|
|
|
|
|
loc_names.add(_("Archive | Archives"));
|
|
|
|
|
unloc_names.add("Archive | Archives");
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
loc_names.add_all(unloc_names);
|
|
|
|
|
return loc_names;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-11 15:24:01 -08:00
|
|
|
private async Geary.Folder ensure_special_folder_async(Geary.SpecialFolderType special,
|
|
|
|
|
Cancellable? cancellable) throws Error {
|
|
|
|
|
Geary.Folder? folder = get_special_folder(special);
|
|
|
|
|
if (folder != null)
|
|
|
|
|
return folder;
|
2016-06-15 18:24:50 -04:00
|
|
|
|
2014-02-11 15:24:01 -08:00
|
|
|
MinimalFolder? minimal_folder = null;
|
|
|
|
|
Geary.FolderPath? path = information.get_special_folder_path(special);
|
|
|
|
|
if (path != null) {
|
|
|
|
|
debug("Previously used %s for special folder %s", path.to_string(), special.to_string());
|
|
|
|
|
} else {
|
|
|
|
|
// This is the first time we're turning a non-special folder into a special one.
|
|
|
|
|
// After we do this, we'll record which one we picked in the account info.
|
2016-06-15 18:24:50 -04:00
|
|
|
|
|
|
|
|
Gee.List<string> search_names = special_search_names.get(special);
|
2014-02-11 15:24:01 -08:00
|
|
|
foreach (string search_name in search_names) {
|
2015-10-27 12:34:39 +11:00
|
|
|
Geary.FolderPath search_path = new Imap.FolderRoot(search_name);
|
2014-02-11 15:24:01 -08:00
|
|
|
foreach (Geary.FolderPath test_path in folder_map.keys) {
|
|
|
|
|
if (test_path.compare_normalized_ci(search_path) == 0) {
|
|
|
|
|
path = search_path;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (path != null)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (path == null) {
|
|
|
|
|
foreach (string search_name in search_names) {
|
|
|
|
|
Geary.FolderPath search_path = new Imap.FolderRoot(
|
2015-10-27 12:34:39 +11:00
|
|
|
Imap.MailboxSpecifier.CANONICAL_INBOX_NAME).get_child(search_name);
|
2014-02-11 15:24:01 -08:00
|
|
|
foreach (Geary.FolderPath test_path in folder_map.keys) {
|
|
|
|
|
if (test_path.compare_normalized_ci(search_path) == 0) {
|
|
|
|
|
path = search_path;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (path != null)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (path == null)
|
2015-10-27 12:34:39 +11:00
|
|
|
path = new Imap.FolderRoot(search_names[0]);
|
2014-02-11 15:24:01 -08:00
|
|
|
|
|
|
|
|
information.set_special_folder_path(special, path);
|
|
|
|
|
yield information.store_async(cancellable);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (path in folder_map.keys) {
|
|
|
|
|
debug("Promoting %s to special folder %s", path.to_string(), special.to_string());
|
|
|
|
|
|
|
|
|
|
minimal_folder = folder_map.get(path);
|
|
|
|
|
} else {
|
|
|
|
|
debug("Creating %s to use as special folder %s", path.to_string(), special.to_string());
|
|
|
|
|
|
|
|
|
|
// TODO: ignore error due to already existing.
|
|
|
|
|
yield remote.create_folder_async(path, cancellable);
|
|
|
|
|
minimal_folder = (MinimalFolder) yield fetch_folder_async(path, cancellable);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
minimal_folder.set_special_folder_type(special);
|
|
|
|
|
return minimal_folder;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override async Geary.Folder get_required_special_folder_async(Geary.SpecialFolderType special,
|
|
|
|
|
Cancellable? cancellable) throws Error {
|
2016-06-05 18:36:16 +10:00
|
|
|
if (!(special in this.supported_special_folders)) {
|
|
|
|
|
throw new EngineError.BAD_PARAMETERS(
|
|
|
|
|
"Invalid special folder type %s passed to get_required_special_folder_async",
|
|
|
|
|
special.to_string());
|
2014-02-11 15:24:01 -08:00
|
|
|
}
|
|
|
|
|
check_open();
|
2016-06-05 18:36:16 +10:00
|
|
|
|
2014-02-11 15:24:01 -08:00
|
|
|
return yield ensure_special_folder_async(special, cancellable);
|
|
|
|
|
}
|
2016-06-05 18:36:16 +10:00
|
|
|
|
2014-02-11 15:24:01 -08:00
|
|
|
private async void ensure_special_folders_async(Cancellable? cancellable) throws Error {
|
2016-06-05 18:36:16 +10:00
|
|
|
foreach (Geary.SpecialFolderType special in this.supported_special_folders)
|
2014-02-11 15:24:01 -08:00
|
|
|
yield ensure_special_folder_async(special, cancellable);
|
|
|
|
|
}
|
2016-06-05 18:36:16 +10:00
|
|
|
|
2013-05-31 17:56:48 -07:00
|
|
|
private async void update_folders_async(Gee.Map<FolderPath, Geary.Folder> existing_folders,
|
2014-03-11 12:12:37 -07:00
|
|
|
Gee.Map<FolderPath, Imap.Folder> remote_folders, bool remote_folders_suspect, Cancellable? cancellable) {
|
2012-06-22 14:42:51 -07:00
|
|
|
// update all remote folders properties in the local store and active in the system
|
2013-04-24 12:22:32 -07:00
|
|
|
Gee.HashSet<Geary.FolderPath> altered_paths = new Gee.HashSet<Geary.FolderPath>();
|
2013-05-31 17:56:48 -07:00
|
|
|
foreach (Imap.Folder remote_folder in remote_folders.values) {
|
2014-02-11 15:24:01 -08:00
|
|
|
MinimalFolder? minimal_folder = existing_folders.get(remote_folder.path)
|
|
|
|
|
as MinimalFolder;
|
|
|
|
|
if (minimal_folder == null)
|
2013-05-31 17:56:48 -07:00
|
|
|
continue;
|
|
|
|
|
|
2013-02-25 20:18:37 -08:00
|
|
|
// only worry about alterations if the remote is openable
|
2013-04-25 14:47:20 -07:00
|
|
|
if (remote_folder.properties.is_openable.is_possible()) {
|
2014-02-11 15:24:01 -08:00
|
|
|
ImapDB.Folder local_folder = minimal_folder.local_folder;
|
2013-08-09 15:17:06 -07:00
|
|
|
|
|
|
|
|
if (remote_folder.properties.have_contents_changed(local_folder.get_properties(),
|
2014-02-11 15:24:01 -08:00
|
|
|
minimal_folder.to_string())) {
|
2013-05-31 17:56:48 -07:00
|
|
|
altered_paths.add(remote_folder.path);
|
2013-08-09 15:17:06 -07:00
|
|
|
}
|
2013-02-25 20:18:37 -08:00
|
|
|
}
|
|
|
|
|
|
2013-09-03 15:09:39 -07:00
|
|
|
// always update, openable or not; have the folder update the UID info the next time
|
|
|
|
|
// it's opened
|
2012-06-22 14:42:51 -07:00
|
|
|
try {
|
2015-02-05 17:57:27 -08:00
|
|
|
yield local.update_folder_status_async(remote_folder, false, false, cancellable);
|
2012-06-22 14:42:51 -07:00
|
|
|
} catch (Error update_error) {
|
|
|
|
|
debug("Unable to update local folder %s with remote properties: %s",
|
|
|
|
|
remote_folder.to_string(), update_error.message);
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-31 17:56:48 -07:00
|
|
|
// set the engine folder's special type
|
2012-07-19 17:40:07 -07:00
|
|
|
// (but only promote, not demote, since getting the special folder type via its
|
|
|
|
|
// properties relies on the optional XLIST extension)
|
2013-05-31 17:56:48 -07:00
|
|
|
// use this iteration to add discovered properties to map
|
2014-02-11 15:24:01 -08:00
|
|
|
if (minimal_folder.special_folder_type == SpecialFolderType.NONE)
|
|
|
|
|
minimal_folder.set_special_folder_type(remote_folder.properties.attrs.get_special_folder_type());
|
2012-05-10 20:28:42 -07:00
|
|
|
}
|
2011-06-16 16:27:08 -07:00
|
|
|
|
2012-06-22 14:42:51 -07:00
|
|
|
// If path in remote but not local, need to add it
|
2013-12-12 12:42:02 -08:00
|
|
|
Gee.ArrayList<Imap.Folder> to_add = Geary.traverse<Imap.Folder>(remote_folders.values)
|
|
|
|
|
.filter(f => !existing_folders.has_key(f.path))
|
|
|
|
|
.to_array_list();
|
2012-03-14 11:05:32 -07:00
|
|
|
|
2013-05-31 17:56:48 -07:00
|
|
|
// If path in local but not remote (and isn't local-only, i.e. the Outbox), need to remove it
|
2013-12-12 12:42:02 -08:00
|
|
|
Gee.ArrayList<Geary.Folder> to_remove
|
|
|
|
|
= Geary.traverse<Gee.Map.Entry<FolderPath, Imap.Folder>>(existing_folders)
|
|
|
|
|
.filter(e => !remote_folders.has_key(e.key) && !local_only.has_key(e.key))
|
|
|
|
|
.map<Geary.Folder>(e => (Geary.Folder) e.value)
|
|
|
|
|
.to_array_list();
|
2011-06-16 16:27:08 -07:00
|
|
|
|
2012-06-22 14:42:51 -07:00
|
|
|
// For folders to add, clone them and their properties locally
|
2013-05-31 17:56:48 -07:00
|
|
|
foreach (Geary.Imap.Folder remote_folder in to_add) {
|
|
|
|
|
try {
|
|
|
|
|
yield local.clone_folder_async(remote_folder, cancellable);
|
|
|
|
|
} catch (Error err) {
|
|
|
|
|
debug("Unable to add/remove folder %s to local store: %s", remote_folder.path.to_string(),
|
|
|
|
|
err.message);
|
2011-07-08 12:45:22 -07:00
|
|
|
}
|
2011-06-16 16:27:08 -07:00
|
|
|
}
|
|
|
|
|
|
2012-06-22 14:42:51 -07:00
|
|
|
// Create Geary.Folder objects for all added folders
|
2013-05-31 17:56:48 -07:00
|
|
|
Gee.ArrayList<ImapDB.Folder> folders_to_build = new Gee.ArrayList<ImapDB.Folder>();
|
|
|
|
|
foreach (Geary.Imap.Folder remote_folder in to_add) {
|
|
|
|
|
try {
|
|
|
|
|
folders_to_build.add(yield local.fetch_folder_async(remote_folder.path, cancellable));
|
|
|
|
|
} catch (Error convert_err) {
|
|
|
|
|
// This isn't fatal, but irksome ... in the future, when local folders are
|
|
|
|
|
// removed, it's possible for one to disappear between cloning it and fetching
|
|
|
|
|
// it
|
|
|
|
|
debug("Unable to fetch local folder after cloning: %s", convert_err.message);
|
2011-06-16 16:27:08 -07:00
|
|
|
}
|
|
|
|
|
}
|
2014-02-11 15:24:01 -08:00
|
|
|
Gee.Collection<MinimalFolder> engine_added = new Gee.ArrayList<Geary.Folder>();
|
2013-05-31 17:56:48 -07:00
|
|
|
engine_added.add_all(build_folders(folders_to_build));
|
2011-06-16 16:27:08 -07:00
|
|
|
|
2014-02-14 16:03:19 -08:00
|
|
|
Gee.ArrayList<Geary.Folder> engine_removed = new Gee.ArrayList<Geary.Folder>();
|
2014-03-11 12:12:37 -07:00
|
|
|
if (remote_folders_suspect) {
|
|
|
|
|
debug("Skipping removing folders due to prior errors");
|
|
|
|
|
} else {
|
|
|
|
|
notify_folders_available_unavailable(null, to_remove);
|
|
|
|
|
|
|
|
|
|
// Sort by path length descending, so we always remove children first.
|
|
|
|
|
to_remove.sort((a, b) => b.path.get_path_length() - a.path.get_path_length());
|
|
|
|
|
foreach (Geary.Folder folder in to_remove) {
|
|
|
|
|
try {
|
|
|
|
|
debug("Locally deleting removed folder %s", folder.to_string());
|
|
|
|
|
|
|
|
|
|
yield local.delete_folder_async(folder, cancellable);
|
|
|
|
|
engine_removed.add(folder);
|
|
|
|
|
} catch (Error e) {
|
|
|
|
|
debug("Unable to locally delete removed folder %s: %s", folder.to_string(), e.message);
|
|
|
|
|
}
|
2014-02-14 16:03:19 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (engine_added.size > 0 || engine_removed.size > 0)
|
|
|
|
|
notify_folders_added_removed(sort_by_path(engine_added), sort_by_path(engine_removed));
|
2013-02-25 20:18:37 -08:00
|
|
|
|
2014-03-04 17:30:11 -08:00
|
|
|
remote.folders_removed(Geary.traverse<Geary.Folder>(engine_removed)
|
|
|
|
|
.map<FolderPath>(f => f.path).to_array_list());
|
|
|
|
|
|
2013-02-25 20:18:37 -08:00
|
|
|
// report all altered folders
|
|
|
|
|
if (altered_paths.size > 0) {
|
|
|
|
|
Gee.ArrayList<Geary.Folder> altered = new Gee.ArrayList<Geary.Folder>();
|
2013-05-31 17:56:48 -07:00
|
|
|
foreach (Geary.FolderPath altered_path in altered_paths) {
|
|
|
|
|
if (existing_folders.has_key(altered_path))
|
|
|
|
|
altered.add(existing_folders.get(altered_path));
|
2013-02-25 20:18:37 -08:00
|
|
|
else
|
2013-05-31 17:56:48 -07:00
|
|
|
debug("Unable to report %s altered: no local representation", altered_path.to_string());
|
2013-02-25 20:18:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (altered.size > 0)
|
|
|
|
|
notify_folders_contents_altered(altered);
|
|
|
|
|
}
|
2014-02-11 15:24:01 -08:00
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
yield ensure_special_folders_async(cancellable);
|
|
|
|
|
} catch (Error e) {
|
|
|
|
|
warning("Unable to ensure special folders: %s", e.message);
|
|
|
|
|
}
|
2011-06-16 16:27:08 -07:00
|
|
|
}
|
2011-07-01 19:33:35 -07:00
|
|
|
|
2012-06-11 12:03:57 -07:00
|
|
|
public override async void send_email_async(Geary.ComposedEmail composed,
|
|
|
|
|
Cancellable? cancellable = null) throws Error {
|
Remove SQLHeavy: Closes #5034
It is done.
Initial implementation of the new database subsystem
These pieces represent the foundation for ticket #5034
Expanded transactions, added VersionedDatabase
Further expansions of the async code.
Moved async pool logic into Database, where it realistically
belongs.
Further improvements. Introduced geary-db-test.
Added SQL create and update files for Geary.Db
version-001 to version-003 are exact copies of the SQLHeavy scripts
to ensure no slight changes when migrating. version-004 upgrades
the database to remove the ImapFolderPropertiesTable and
ImapMessagePropertiesTable, now that the database code is pure
IMAP.
When we support other messaging systems (such as POP3), those
subsystems will need to code their own database layers OR rely on
the IMAP schema and simply ignore the IMAP-specific fields.
ImapDB.Account fleshed out
ImapDB.Folder is commented out, however. Need to port next.
ImapDB.Folder fleshed out
MessageTable, MessageLocationTable, and AttachementTable are now
handled inside ImapDB.Folder.
chmod -x imap-db-database.vala
OutboxEmailIdentifier/Properties -> SmtpOutboxEmailIdentifier/Properties
Moved SmtpOutboxFolderRoot into its own source file
SmtpOutboxFolder ported to new database code
Move Engine implementations to ImapDB.
Integration and cleanup of new database code with main source
This commit performs the final integration steps to move Geary
completely over to the new database model. This also cleans out
the old SQLHeavy-based code and fixes a handful of small bugs that
were detected during basic test runs.
Moved Outbox to ImapDB
As the Outbox is tied to the database that ImapDB runs, move the
Outbox code into that folder.
Outbox fixes and better parameter checking
Bumped Database thread pool count and made them exclusive
My reasoning is that there may be a need for a lot of threads at
once (when a big batch of commands comes in, especially at
startup). If performance looks ok, we might consider relaxing
this later.
2012-06-14 14:47:53 -07:00
|
|
|
check_open();
|
|
|
|
|
|
2014-01-29 18:18:31 -08:00
|
|
|
// TODO: we should probably not use someone else's FQDN in something
|
|
|
|
|
// that's supposed to be globally unique...
|
|
|
|
|
Geary.RFC822.Message rfc822 = new Geary.RFC822.Message.from_composed_email(
|
2014-03-24 16:29:26 -07:00
|
|
|
composed, GMime.utils_generate_message_id(information.get_smtp_endpoint().remote_address.hostname));
|
Remove SQLHeavy: Closes #5034
It is done.
Initial implementation of the new database subsystem
These pieces represent the foundation for ticket #5034
Expanded transactions, added VersionedDatabase
Further expansions of the async code.
Moved async pool logic into Database, where it realistically
belongs.
Further improvements. Introduced geary-db-test.
Added SQL create and update files for Geary.Db
version-001 to version-003 are exact copies of the SQLHeavy scripts
to ensure no slight changes when migrating. version-004 upgrades
the database to remove the ImapFolderPropertiesTable and
ImapMessagePropertiesTable, now that the database code is pure
IMAP.
When we support other messaging systems (such as POP3), those
subsystems will need to code their own database layers OR rely on
the IMAP schema and simply ignore the IMAP-specific fields.
ImapDB.Account fleshed out
ImapDB.Folder is commented out, however. Need to port next.
ImapDB.Folder fleshed out
MessageTable, MessageLocationTable, and AttachementTable are now
handled inside ImapDB.Folder.
chmod -x imap-db-database.vala
OutboxEmailIdentifier/Properties -> SmtpOutboxEmailIdentifier/Properties
Moved SmtpOutboxFolderRoot into its own source file
SmtpOutboxFolder ported to new database code
Move Engine implementations to ImapDB.
Integration and cleanup of new database code with main source
This commit performs the final integration steps to move Geary
completely over to the new database model. This also cleans out
the old SQLHeavy-based code and fixes a handful of small bugs that
were detected during basic test runs.
Moved Outbox to ImapDB
As the Outbox is tied to the database that ImapDB runs, move the
Outbox code into that folder.
Outbox fixes and better parameter checking
Bumped Database thread pool count and made them exclusive
My reasoning is that there may be a need for a lot of threads at
once (when a big batch of commands comes in, especially at
startup). If performance looks ok, we might consider relaxing
this later.
2012-06-14 14:47:53 -07:00
|
|
|
|
|
|
|
|
// don't use create_email_async() as that requires the folder be open to use
|
|
|
|
|
yield local.outbox.enqueue_email_async(rfc822, cancellable);
|
2011-09-30 17:29:03 -07:00
|
|
|
}
|
2012-06-25 16:30:23 -07:00
|
|
|
|
|
|
|
|
private void on_email_sent(Geary.RFC822.Message rfc822) {
|
|
|
|
|
notify_email_sent(rfc822);
|
|
|
|
|
}
|
2011-12-22 12:31:06 -08:00
|
|
|
|
2013-08-19 16:39:53 -07:00
|
|
|
private ImapDB.EmailIdentifier check_id(Geary.EmailIdentifier id) throws EngineError {
|
|
|
|
|
ImapDB.EmailIdentifier? imapdb_id = id as ImapDB.EmailIdentifier;
|
|
|
|
|
if (imapdb_id == null)
|
|
|
|
|
throw new EngineError.BAD_PARAMETERS("EmailIdentifier %s not from ImapDB folder", id.to_string());
|
|
|
|
|
|
|
|
|
|
return imapdb_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Gee.Collection<ImapDB.EmailIdentifier> check_ids(Gee.Collection<Geary.EmailIdentifier> ids)
|
|
|
|
|
throws EngineError {
|
|
|
|
|
foreach (Geary.EmailIdentifier id in ids) {
|
|
|
|
|
if (!(id is ImapDB.EmailIdentifier))
|
|
|
|
|
throw new EngineError.BAD_PARAMETERS("EmailIdentifier %s not from ImapDB folder", id.to_string());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (Gee.Collection<ImapDB.EmailIdentifier>) ids;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-26 11:09:02 -08:00
|
|
|
public override async Gee.MultiMap<Geary.Email, Geary.FolderPath?>? local_search_message_id_async(
|
|
|
|
|
Geary.RFC822.MessageID message_id, Geary.Email.Field requested_fields, bool partial_ok,
|
2013-09-10 19:16:53 -07:00
|
|
|
Gee.Collection<Geary.FolderPath?>? folder_blacklist, Geary.EmailFlags? flag_blacklist,
|
|
|
|
|
Cancellable? cancellable = null) throws Error {
|
2013-02-26 11:09:02 -08:00
|
|
|
return yield local.search_message_id_async(
|
2013-09-10 19:16:53 -07:00
|
|
|
message_id, requested_fields, partial_ok, folder_blacklist, flag_blacklist, cancellable);
|
2013-02-26 11:09:02 -08:00
|
|
|
}
|
|
|
|
|
|
2013-03-08 17:41:33 -08:00
|
|
|
public override async Geary.Email local_fetch_email_async(Geary.EmailIdentifier email_id,
|
|
|
|
|
Geary.Email.Field required_fields, Cancellable? cancellable = null) throws Error {
|
2013-08-19 16:39:53 -07:00
|
|
|
return yield local.fetch_email_async(check_id(email_id), required_fields, cancellable);
|
2013-07-09 13:48:47 -07:00
|
|
|
}
|
|
|
|
|
|
2014-12-16 12:21:09 -08:00
|
|
|
public override Geary.SearchQuery open_search(string query, SearchQuery.Strategy strategy) {
|
|
|
|
|
return new ImapDB.SearchQuery(local, query, strategy);
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-17 11:40:29 -08:00
|
|
|
public override async Gee.Collection<Geary.EmailIdentifier>? local_search_async(Geary.SearchQuery query,
|
2013-06-21 17:19:39 -07:00
|
|
|
int limit = 100, int offset = 0, Gee.Collection<Geary.FolderPath?>? folder_blacklist = null,
|
2013-05-14 11:52:02 -07:00
|
|
|
Gee.Collection<Geary.EmailIdentifier>? search_ids = null, Cancellable? cancellable = null) throws Error {
|
2013-06-10 12:21:28 -07:00
|
|
|
if (offset < 0)
|
|
|
|
|
throw new EngineError.BAD_PARAMETERS("Offset must not be negative");
|
|
|
|
|
|
2013-12-17 11:40:29 -08:00
|
|
|
return yield local.search_async(query, limit, offset, folder_blacklist, search_ids, cancellable);
|
2013-05-14 11:52:02 -07:00
|
|
|
}
|
|
|
|
|
|
2014-12-16 12:21:09 -08:00
|
|
|
public override async Gee.Set<string>? get_search_matches_async(Geary.SearchQuery query,
|
2013-06-18 11:26:44 -07:00
|
|
|
Gee.Collection<Geary.EmailIdentifier> ids, Cancellable? cancellable = null) throws Error {
|
2013-12-17 11:40:29 -08:00
|
|
|
return yield local.get_search_matches_async(query, check_ids(ids), cancellable);
|
2013-08-19 16:39:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override async Gee.MultiMap<Geary.EmailIdentifier, Geary.FolderPath>? get_containing_folders_async(
|
|
|
|
|
Gee.Collection<Geary.EmailIdentifier> ids, Cancellable? cancellable) throws Error {
|
2013-09-11 12:03:52 -07:00
|
|
|
return yield local.get_containing_folders_async(ids, cancellable);
|
2013-06-18 11:26:44 -07:00
|
|
|
}
|
|
|
|
|
|
2012-03-14 11:05:32 -07:00
|
|
|
private void on_login_failed(Geary.Credentials? credentials) {
|
2013-09-23 18:27:56 -07:00
|
|
|
if (awaiting_credentials)
|
|
|
|
|
return; // We're already asking for the password.
|
|
|
|
|
|
|
|
|
|
awaiting_credentials = true;
|
|
|
|
|
do_login_failed_async.begin(credentials, () => { awaiting_credentials = false; });
|
2013-01-31 15:17:44 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async void do_login_failed_async(Geary.Credentials? credentials) {
|
|
|
|
|
try {
|
2014-08-28 17:27:50 -07:00
|
|
|
if (yield information.fetch_passwords_async(ServiceFlag.IMAP, true))
|
2013-01-31 15:17:44 -08:00
|
|
|
return;
|
|
|
|
|
} catch (Error e) {
|
|
|
|
|
debug("Error prompting for IMAP password: %s", e.message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
notify_report_problem(Geary.Account.Problem.RECV_EMAIL_LOGIN_FAILED, null);
|
2011-12-22 12:31:06 -08:00
|
|
|
}
|
2011-06-16 16:27:08 -07:00
|
|
|
}
|
|
|
|
|
|