2011-06-10 19:17:35 -07:00
|
|
|
/* Copyright 2011 Yorba Foundation
|
|
|
|
|
*
|
|
|
|
|
* This software is licensed under the GNU Lesser General Public License
|
|
|
|
|
* (version 2.1 or later). See the COPYING file in this distribution.
|
|
|
|
|
*/
|
|
|
|
|
|
2011-06-23 19:07:04 -07:00
|
|
|
// TODO: This class currently deals with generic email storage as well as IMAP-specific issues; in
|
|
|
|
|
// the future, to support other email services, will need to break this up.
|
|
|
|
|
|
2011-07-18 11:48:42 -07:00
|
|
|
public class Geary.Sqlite.Folder : Geary.AbstractFolder, Geary.LocalFolder, Geary.Imap.FolderExtensions,
|
|
|
|
|
Geary.ReferenceSemantics {
|
|
|
|
|
protected int manual_ref_count { get; protected set; }
|
|
|
|
|
|
2011-06-16 16:27:08 -07:00
|
|
|
private MailDatabase db;
|
|
|
|
|
private FolderRow folder_row;
|
2011-07-15 13:39:02 -07:00
|
|
|
private Geary.Imap.FolderProperties? properties;
|
2011-06-16 16:27:08 -07:00
|
|
|
private MessageTable message_table;
|
|
|
|
|
private MessageLocationTable location_table;
|
2011-07-08 12:45:22 -07:00
|
|
|
private ImapMessagePropertiesTable imap_message_properties_table;
|
2011-07-01 15:40:20 -07:00
|
|
|
private Geary.FolderPath path;
|
2011-06-23 19:07:04 -07:00
|
|
|
private bool opened = false;
|
2011-06-10 19:17:35 -07:00
|
|
|
|
2011-07-18 11:48:42 -07:00
|
|
|
internal Folder(ImapDatabase db, FolderRow folder_row, Geary.Imap.FolderProperties? properties,
|
2011-07-08 12:45:22 -07:00
|
|
|
Geary.FolderPath path) throws Error {
|
2011-06-16 16:27:08 -07:00
|
|
|
this.db = db;
|
|
|
|
|
this.folder_row = folder_row;
|
2011-07-18 11:48:42 -07:00
|
|
|
this.properties = properties;
|
2011-07-01 15:40:20 -07:00
|
|
|
this.path = path;
|
2011-06-16 16:27:08 -07:00
|
|
|
|
|
|
|
|
message_table = db.get_message_table();
|
|
|
|
|
location_table = db.get_message_location_table();
|
2011-07-08 12:45:22 -07:00
|
|
|
imap_message_properties_table = db.get_imap_message_properties_table();
|
2011-06-13 15:16:57 -07:00
|
|
|
}
|
|
|
|
|
|
2011-06-23 19:07:04 -07:00
|
|
|
private void check_open() throws Error {
|
|
|
|
|
if (!opened)
|
|
|
|
|
throw new EngineError.OPEN_REQUIRED("%s not open", to_string());
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-01 15:40:20 -07:00
|
|
|
public override Geary.FolderPath get_path() {
|
|
|
|
|
return path;
|
2011-06-13 15:16:57 -07:00
|
|
|
}
|
|
|
|
|
|
2011-06-28 16:33:27 -07:00
|
|
|
public override Geary.FolderProperties? get_properties() {
|
2011-07-18 11:48:42 -07:00
|
|
|
// TODO: TBD: alteration/updated signals for folders
|
2011-07-08 12:45:22 -07:00
|
|
|
return properties;
|
2011-06-10 19:17:35 -07:00
|
|
|
}
|
|
|
|
|
|
2011-07-18 11:48:42 -07:00
|
|
|
internal void update_properties(Geary.Imap.FolderProperties? properties) {
|
|
|
|
|
this.properties = properties;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-28 16:33:27 -07:00
|
|
|
public override async void open_async(bool readonly, Cancellable? cancellable = null) throws Error {
|
2011-06-23 19:07:04 -07:00
|
|
|
if (opened)
|
|
|
|
|
throw new EngineError.ALREADY_OPEN("%s already open", to_string());
|
|
|
|
|
|
|
|
|
|
opened = true;
|
2011-07-08 12:45:22 -07:00
|
|
|
|
|
|
|
|
notify_opened(Geary.Folder.OpenState.LOCAL);
|
2011-06-10 19:17:35 -07:00
|
|
|
}
|
|
|
|
|
|
2011-06-28 16:33:27 -07:00
|
|
|
public override async void close_async(Cancellable? cancellable = null) throws Error {
|
2011-06-23 19:07:04 -07:00
|
|
|
if (!opened)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
opened = false;
|
2011-07-08 12:45:22 -07:00
|
|
|
|
2011-06-23 19:07:04 -07:00
|
|
|
notify_closed(CloseReason.FOLDER_CLOSED);
|
2011-06-10 19:17:35 -07:00
|
|
|
}
|
|
|
|
|
|
2011-07-26 15:29:08 -07:00
|
|
|
public override async int get_email_count_async(Cancellable? cancellable = null) throws Error {
|
2011-06-23 19:07:04 -07:00
|
|
|
check_open();
|
|
|
|
|
|
2011-07-15 13:39:02 -07:00
|
|
|
// TODO: This can be cached and updated when changes occur
|
|
|
|
|
return yield location_table.fetch_count_for_folder_async(folder_row.id, cancellable);
|
2011-06-10 19:17:35 -07:00
|
|
|
}
|
|
|
|
|
|
2011-06-28 16:33:27 -07:00
|
|
|
public override async void create_email_async(Geary.Email email, Cancellable? cancellable = null)
|
|
|
|
|
throws Error {
|
2011-06-23 19:07:04 -07:00
|
|
|
check_open();
|
2011-06-16 16:27:08 -07:00
|
|
|
|
2011-07-19 15:55:56 -07:00
|
|
|
Geary.Imap.EmailIdentifier id = (Geary.Imap.EmailIdentifier) email.id;
|
2011-06-21 17:48:40 -07:00
|
|
|
|
2011-06-23 19:07:04 -07:00
|
|
|
// See if it already exists; first by UID (which is only guaranteed to be unique in a folder,
|
|
|
|
|
// not account-wide)
|
|
|
|
|
int64 message_id;
|
2011-07-19 15:55:56 -07:00
|
|
|
if (yield location_table.does_ordering_exist_async(folder_row.id, email.location.ordering,
|
2011-07-15 13:39:02 -07:00
|
|
|
out message_id, cancellable)) {
|
2011-06-23 19:07:04 -07:00
|
|
|
throw new EngineError.ALREADY_EXISTS("Email with UID %s already exists in %s",
|
2011-07-19 15:55:56 -07:00
|
|
|
id.uid.to_string(), to_string());
|
2011-06-23 19:07:04 -07:00
|
|
|
}
|
|
|
|
|
|
2011-07-06 15:46:24 -07:00
|
|
|
// TODO: The following steps should be atomic
|
2011-06-23 19:07:04 -07:00
|
|
|
message_id = yield message_table.create_async(
|
|
|
|
|
new MessageRow.from_email(message_table, email),
|
|
|
|
|
cancellable);
|
|
|
|
|
|
2011-07-15 13:39:02 -07:00
|
|
|
// create the message location in the location lookup table using its UID for the ordering
|
|
|
|
|
// (which fulfills the requirements for the ordering column)
|
2011-06-16 16:27:08 -07:00
|
|
|
MessageLocationRow location_row = new MessageLocationRow(location_table, Row.INVALID_ID,
|
2011-07-19 15:55:56 -07:00
|
|
|
message_id, folder_row.id, email.location.ordering, email.location.position);
|
2011-07-15 13:39:02 -07:00
|
|
|
yield location_table.create_async(location_row, cancellable);
|
2011-07-08 12:45:22 -07:00
|
|
|
|
|
|
|
|
// only write out the IMAP email properties if they're supplied and there's something to
|
|
|
|
|
// write out -- no need to create an empty row
|
|
|
|
|
Geary.Imap.EmailProperties? properties = (Geary.Imap.EmailProperties?) email.properties;
|
2011-07-15 13:39:02 -07:00
|
|
|
if (email.fields.fulfills(Geary.Email.Field.PROPERTIES) && properties != null) {
|
2011-07-08 12:45:22 -07:00
|
|
|
ImapMessagePropertiesRow properties_row = new ImapMessagePropertiesRow.from_imap_properties(
|
|
|
|
|
imap_message_properties_table, message_id, properties);
|
|
|
|
|
yield imap_message_properties_table.create_async(properties_row, cancellable);
|
|
|
|
|
}
|
2011-07-26 15:29:08 -07:00
|
|
|
|
|
|
|
|
notify_list_appended(yield get_email_count_async(cancellable));
|
2011-06-10 19:17:35 -07:00
|
|
|
}
|
|
|
|
|
|
2011-06-28 16:33:27 -07:00
|
|
|
public override async Gee.List<Geary.Email>? list_email_async(int low, int count,
|
2011-06-23 19:07:04 -07:00
|
|
|
Geary.Email.Field required_fields, Cancellable? cancellable) throws Error {
|
|
|
|
|
check_open();
|
|
|
|
|
|
2011-07-26 15:29:08 -07:00
|
|
|
normalize_span_specifiers(ref low, ref count, yield get_email_count_async(cancellable));
|
2011-07-15 13:39:02 -07:00
|
|
|
|
2011-07-08 12:45:22 -07:00
|
|
|
if (count == 0)
|
|
|
|
|
return null;
|
|
|
|
|
|
2011-06-21 17:48:40 -07:00
|
|
|
Gee.List<MessageLocationRow>? list = yield location_table.list_async(folder_row.id, low,
|
2011-06-16 16:27:08 -07:00
|
|
|
count, cancellable);
|
2011-06-21 17:48:40 -07:00
|
|
|
|
2011-06-23 19:07:04 -07:00
|
|
|
return yield list_email(list, required_fields, cancellable);
|
2011-06-21 17:48:40 -07:00
|
|
|
}
|
|
|
|
|
|
2011-06-28 16:33:27 -07:00
|
|
|
public override async Gee.List<Geary.Email>? list_email_sparse_async(int[] by_position,
|
2011-06-23 19:07:04 -07:00
|
|
|
Geary.Email.Field required_fields, Cancellable? cancellable = null) throws Error {
|
|
|
|
|
check_open();
|
|
|
|
|
|
2011-06-21 17:48:40 -07:00
|
|
|
Gee.List<MessageLocationRow>? list = yield location_table.list_sparse_async(folder_row.id,
|
|
|
|
|
by_position, cancellable);
|
|
|
|
|
|
2011-06-23 19:07:04 -07:00
|
|
|
return yield list_email(list, required_fields, cancellable);
|
2011-06-21 17:48:40 -07:00
|
|
|
}
|
|
|
|
|
|
2011-07-15 13:39:02 -07:00
|
|
|
public async Gee.List<Geary.Email>? list_email_uid_async(Geary.Imap.UID? low, Geary.Imap.UID? high,
|
|
|
|
|
Geary.Email.Field required_fields, Cancellable? cancellable = null) throws Error {
|
|
|
|
|
check_open();
|
|
|
|
|
|
|
|
|
|
Gee.List<MessageLocationRow>? list = yield location_table.list_ordering_async(folder_row.id,
|
|
|
|
|
(low != null) ? low.value : 1, (high != null) ? high.value : -1, cancellable);
|
|
|
|
|
|
|
|
|
|
return yield list_email(list, required_fields, cancellable);
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-21 17:48:40 -07:00
|
|
|
private async Gee.List<Geary.Email>? list_email(Gee.List<MessageLocationRow>? list,
|
2011-06-23 19:07:04 -07:00
|
|
|
Geary.Email.Field required_fields, Cancellable? cancellable) throws Error {
|
|
|
|
|
check_open();
|
|
|
|
|
|
2011-06-16 16:27:08 -07:00
|
|
|
if (list == null || list.size == 0)
|
2011-06-21 17:48:40 -07:00
|
|
|
return null;
|
2011-06-16 16:27:08 -07:00
|
|
|
|
2011-06-23 19:07:04 -07:00
|
|
|
// TODO: As this loop involves multiple database operations to form an email, might make
|
|
|
|
|
// sense in the future to launch each async method separately, putting the final results
|
|
|
|
|
// together when all the information is fetched
|
2011-06-16 16:27:08 -07:00
|
|
|
Gee.List<Geary.Email> emails = new Gee.ArrayList<Geary.Email>();
|
|
|
|
|
foreach (MessageLocationRow location_row in list) {
|
2011-06-23 19:07:04 -07:00
|
|
|
// fetch the message itself
|
2011-06-16 16:27:08 -07:00
|
|
|
MessageRow? message_row = yield message_table.fetch_async(location_row.message_id,
|
2011-06-23 19:07:04 -07:00
|
|
|
required_fields, cancellable);
|
2011-06-16 16:27:08 -07:00
|
|
|
assert(message_row != null);
|
2011-07-08 12:45:22 -07:00
|
|
|
|
2011-07-15 13:39:02 -07:00
|
|
|
// only add to the list if the email contains all the required fields (because
|
|
|
|
|
// properties comes out of a separate table, skip this if properties are requested)
|
|
|
|
|
if (!message_row.fields.fulfills(required_fields.clear(Geary.Email.Field.PROPERTIES)))
|
2011-06-23 19:07:04 -07:00
|
|
|
continue;
|
2011-06-16 16:27:08 -07:00
|
|
|
|
2011-07-08 12:45:22 -07:00
|
|
|
ImapMessagePropertiesRow? properties = null;
|
2011-07-18 15:57:55 -07:00
|
|
|
if (required_fields.require(Geary.Email.Field.PROPERTIES)) {
|
2011-07-08 12:45:22 -07:00
|
|
|
properties = yield imap_message_properties_table.fetch_async(location_row.message_id,
|
|
|
|
|
cancellable);
|
2011-07-18 15:57:55 -07:00
|
|
|
if (properties == null)
|
|
|
|
|
continue;
|
2011-07-08 12:45:22 -07:00
|
|
|
}
|
|
|
|
|
|
2011-07-19 15:55:56 -07:00
|
|
|
Geary.Imap.UID uid = new Geary.Imap.UID(location_row.ordering);
|
|
|
|
|
|
|
|
|
|
Geary.Email email = message_row.to_email(
|
|
|
|
|
new Geary.Imap.EmailLocation(location_row.position, uid),
|
|
|
|
|
new Geary.Imap.EmailIdentifier(uid));
|
2011-07-08 12:45:22 -07:00
|
|
|
if (properties != null)
|
|
|
|
|
email.set_email_properties(properties.get_imap_email_properties());
|
|
|
|
|
|
|
|
|
|
emails.add(email);
|
2011-06-16 16:27:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (emails.size > 0) ? emails : null;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-19 15:55:56 -07:00
|
|
|
public override async Geary.Email fetch_email_async(Geary.EmailIdentifier id,
|
|
|
|
|
Geary.Email.Field required_fields, Cancellable? cancellable = null) throws Error {
|
2011-06-23 19:07:04 -07:00
|
|
|
check_open();
|
|
|
|
|
|
2011-07-19 15:55:56 -07:00
|
|
|
Geary.Imap.UID uid = ((Imap.EmailIdentifier) id).uid;
|
|
|
|
|
|
|
|
|
|
MessageLocationRow? location_row = yield location_table.fetch_by_ordering_async(folder_row.id,
|
|
|
|
|
uid.value, cancellable);
|
2011-07-01 15:40:20 -07:00
|
|
|
if (location_row == null) {
|
2011-07-19 15:55:56 -07:00
|
|
|
throw new EngineError.NOT_FOUND("No message with ID %s in folder %s", id.to_string(),
|
2011-07-01 15:40:20 -07:00
|
|
|
to_string());
|
|
|
|
|
}
|
2011-06-21 17:48:40 -07:00
|
|
|
|
2011-06-23 19:07:04 -07:00
|
|
|
MessageRow? message_row = yield message_table.fetch_async(location_row.message_id,
|
|
|
|
|
required_fields, cancellable);
|
2011-07-01 15:40:20 -07:00
|
|
|
if (message_row == null) {
|
2011-07-19 15:55:56 -07:00
|
|
|
throw new EngineError.NOT_FOUND("No message with ID %s in folder %s", id.to_string(),
|
2011-07-01 15:40:20 -07:00
|
|
|
to_string());
|
|
|
|
|
}
|
2011-06-16 16:27:08 -07:00
|
|
|
|
2011-07-15 14:29:33 -07:00
|
|
|
// see if the message row fulfills everything but properties, which are held in
|
|
|
|
|
// separate table
|
|
|
|
|
if (!message_row.fields.fulfills(required_fields.clear(Geary.Email.Field.PROPERTIES))) {
|
2011-06-23 19:07:04 -07:00
|
|
|
throw new EngineError.INCOMPLETE_MESSAGE(
|
2011-07-19 15:55:56 -07:00
|
|
|
"Message %s in folder %s only fulfills %Xh fields", id.to_string(), to_string(),
|
2011-06-23 19:07:04 -07:00
|
|
|
message_row.fields);
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-08 12:45:22 -07:00
|
|
|
ImapMessagePropertiesRow? properties = null;
|
2011-07-15 14:29:33 -07:00
|
|
|
if (required_fields.require(Geary.Email.Field.PROPERTIES)) {
|
2011-07-08 12:45:22 -07:00
|
|
|
properties = yield imap_message_properties_table.fetch_async(location_row.message_id,
|
|
|
|
|
cancellable);
|
2011-07-19 15:55:56 -07:00
|
|
|
if (properties == null) {
|
|
|
|
|
throw new EngineError.INCOMPLETE_MESSAGE(
|
|
|
|
|
"Message %s in folder %s does not have PROPERTIES field", id.to_string(),
|
|
|
|
|
to_string());
|
|
|
|
|
}
|
2011-07-08 12:45:22 -07:00
|
|
|
}
|
|
|
|
|
|
2011-07-19 15:55:56 -07:00
|
|
|
// TODO: Would be helpful if proper position was known
|
|
|
|
|
Geary.Email email = message_row.to_email(
|
|
|
|
|
new Geary.Imap.EmailLocation(location_row.position, uid), id);
|
2011-07-08 12:45:22 -07:00
|
|
|
if (properties != null)
|
|
|
|
|
email.set_email_properties(properties.get_imap_email_properties());
|
|
|
|
|
|
|
|
|
|
return email;
|
2011-06-10 19:17:35 -07:00
|
|
|
}
|
2011-06-23 19:07:04 -07:00
|
|
|
|
2011-07-15 13:39:02 -07:00
|
|
|
public async Geary.Imap.UID? get_earliest_uid_async(Cancellable? cancellable = null) throws Error {
|
|
|
|
|
check_open();
|
|
|
|
|
|
|
|
|
|
int64 ordering = yield location_table.get_earliest_ordering_async(folder_row.id, cancellable);
|
|
|
|
|
|
|
|
|
|
return (ordering >= 1) ? new Geary.Imap.UID(ordering) : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override async void remove_email_async(Geary.Email email, Cancellable? cancellable = null)
|
|
|
|
|
throws Error {
|
|
|
|
|
check_open();
|
|
|
|
|
|
|
|
|
|
// TODO: Right now, deleting an email is merely detaching its association with a folder
|
|
|
|
|
// (since it may be located in multiple folders). This means at some point in the future
|
|
|
|
|
// a vacuum will be required to remove emails that are completely unassociated with the
|
|
|
|
|
// account
|
2011-07-19 15:55:56 -07:00
|
|
|
Geary.Imap.UID? uid = ((Geary.Imap.EmailIdentifier) email.id).uid;
|
2011-07-15 13:39:02 -07:00
|
|
|
if (uid == null)
|
|
|
|
|
throw new EngineError.NOT_FOUND("UID required to delete local email");
|
|
|
|
|
|
|
|
|
|
yield location_table.remove_by_ordering_async(folder_row.id, uid.value, cancellable);
|
2011-07-26 15:29:08 -07:00
|
|
|
|
|
|
|
|
// TODO: Notify of changes
|
2011-07-15 13:39:02 -07:00
|
|
|
}
|
|
|
|
|
|
2011-07-19 15:55:56 -07:00
|
|
|
public async bool is_email_present(Geary.EmailIdentifier id, out Geary.Email.Field available_fields,
|
2011-06-23 19:07:04 -07:00
|
|
|
Cancellable? cancellable = null) throws Error {
|
|
|
|
|
check_open();
|
|
|
|
|
|
2011-07-19 15:55:56 -07:00
|
|
|
Geary.Imap.UID uid = ((Imap.EmailIdentifier) id).uid;
|
|
|
|
|
|
2011-06-23 19:07:04 -07:00
|
|
|
available_fields = Geary.Email.Field.NONE;
|
|
|
|
|
|
2011-07-19 15:55:56 -07:00
|
|
|
MessageLocationRow? location_row = yield location_table.fetch_by_ordering_async(folder_row.id,
|
|
|
|
|
uid.value, cancellable);
|
2011-06-23 19:07:04 -07:00
|
|
|
if (location_row == null)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return yield message_table.fetch_fields_async(location_row.message_id, out available_fields,
|
|
|
|
|
cancellable);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async bool is_email_associated_async(Geary.Email email, Cancellable? cancellable = null)
|
|
|
|
|
throws Error {
|
|
|
|
|
check_open();
|
|
|
|
|
|
|
|
|
|
int64 message_id;
|
2011-07-15 13:39:02 -07:00
|
|
|
return yield location_table.does_ordering_exist_async(folder_row.id,
|
2011-07-19 15:55:56 -07:00
|
|
|
((Geary.Imap.EmailIdentifier) email.id).uid.value, out message_id, cancellable);
|
2011-06-23 19:07:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async void update_email_async(Geary.Email email, bool duplicate_okay,
|
|
|
|
|
Cancellable? cancellable = null) throws Error {
|
|
|
|
|
check_open();
|
|
|
|
|
|
|
|
|
|
Geary.Imap.EmailLocation location = (Geary.Imap.EmailLocation) email.location;
|
2011-07-19 15:55:56 -07:00
|
|
|
Geary.Imap.EmailIdentifier id = (Geary.Imap.EmailIdentifier) email.id;
|
2011-06-23 19:07:04 -07:00
|
|
|
|
|
|
|
|
// See if the message can be identified in the folder (which both reveals association and
|
|
|
|
|
// a message_id that can be used for a merge; note that this works without a Message-ID)
|
|
|
|
|
int64 message_id;
|
2011-07-15 13:39:02 -07:00
|
|
|
bool associated = yield location_table.does_ordering_exist_async(folder_row.id,
|
2011-07-19 15:55:56 -07:00
|
|
|
id.uid.value, out message_id, cancellable);
|
2011-06-23 19:07:04 -07:00
|
|
|
|
|
|
|
|
// If working around the lack of a Message-ID and not associated with this folder, treat
|
|
|
|
|
// this operation as a create; otherwise, since a folder-association is determined, do
|
|
|
|
|
// a merge
|
|
|
|
|
if (email.message_id == null) {
|
|
|
|
|
if (!associated) {
|
|
|
|
|
if (!duplicate_okay)
|
|
|
|
|
throw new EngineError.INCOMPLETE_MESSAGE("No Message-ID");
|
|
|
|
|
|
|
|
|
|
yield create_email_async(email, cancellable);
|
|
|
|
|
} else {
|
|
|
|
|
yield merge_email_async(message_id, email, cancellable);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If not associated, find message with matching Message-ID
|
|
|
|
|
if (!associated) {
|
|
|
|
|
Gee.List<int64?>? list = yield message_table.search_message_id_async(email.message_id,
|
|
|
|
|
cancellable);
|
|
|
|
|
|
|
|
|
|
// If none found, this operation is a create
|
|
|
|
|
if (list == null || list.size == 0) {
|
|
|
|
|
yield create_email_async(email, cancellable);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Too many found turns this operation into a create
|
|
|
|
|
if (list.size != 1) {
|
|
|
|
|
yield create_email_async(email, cancellable);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
message_id = list[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Found a message. If not associated with this folder, associate now.
|
|
|
|
|
// TODO: Need to lock the database during this operation, as these steps should be atomic.
|
|
|
|
|
if (!associated) {
|
|
|
|
|
// see if an email exists at this position
|
|
|
|
|
MessageLocationRow? location_row = yield location_table.fetch_async(folder_row.id,
|
|
|
|
|
location.position);
|
|
|
|
|
if (location_row != null) {
|
|
|
|
|
throw new EngineError.ALREADY_EXISTS("Email already exists at position %d in %s",
|
|
|
|
|
email.location.position, to_string());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// insert email at supplied position
|
|
|
|
|
location_row = new MessageLocationRow(location_table, Row.INVALID_ID, message_id,
|
2011-07-19 15:55:56 -07:00
|
|
|
folder_row.id, id.uid.value, location.position);
|
2011-07-15 13:39:02 -07:00
|
|
|
yield location_table.create_async(location_row, cancellable);
|
2011-06-23 19:07:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Merge any new information with the existing message in the local store
|
|
|
|
|
yield merge_email_async(message_id, email, cancellable);
|
|
|
|
|
|
|
|
|
|
// Done.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: The database should be locked around this method, as it should be atomic.
|
|
|
|
|
private async void merge_email_async(int64 message_id, Geary.Email email,
|
|
|
|
|
Cancellable? cancellable = null) throws Error {
|
|
|
|
|
assert(message_id != Row.INVALID_ID);
|
|
|
|
|
|
|
|
|
|
// if nothing to merge, nothing to do
|
|
|
|
|
if (email.fields == Geary.Email.Field.NONE)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
MessageRow? message_row = yield message_table.fetch_async(message_id, email.fields,
|
|
|
|
|
cancellable);
|
|
|
|
|
assert(message_row != null);
|
|
|
|
|
|
|
|
|
|
message_row.merge_from_network(email);
|
|
|
|
|
|
|
|
|
|
// possible nothing has changed or been added
|
|
|
|
|
if (message_row.fields != Geary.Email.Field.NONE)
|
|
|
|
|
yield message_table.merge_async(message_row, cancellable);
|
2011-07-08 12:45:22 -07:00
|
|
|
|
|
|
|
|
// update IMAP properties
|
|
|
|
|
if (email.fields.fulfills(Geary.Email.Field.PROPERTIES)) {
|
2011-07-15 13:39:02 -07:00
|
|
|
Geary.Imap.EmailProperties properties = (Geary.Imap.EmailProperties) email.properties;
|
|
|
|
|
string? internaldate =
|
|
|
|
|
(properties.internaldate != null) ? properties.internaldate.original : null;
|
|
|
|
|
long rfc822_size =
|
|
|
|
|
(properties.rfc822_size != null) ? properties.rfc822_size.value : -1;
|
|
|
|
|
|
|
|
|
|
yield imap_message_properties_table.update_async(message_id, properties.flags.serialize(),
|
|
|
|
|
internaldate, rfc822_size, cancellable);
|
2011-07-08 12:45:22 -07:00
|
|
|
}
|
2011-06-23 19:07:04 -07:00
|
|
|
}
|
2011-06-10 19:17:35 -07:00
|
|
|
}
|
|
|
|
|
|