[geary/wip/730682-refine-convo-list: 1/11] Add a GVariant API for (de)serialising FolderPath and EmailIdentifier.
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/730682-refine-convo-list: 1/11] Add a GVariant API for (de)serialising FolderPath and EmailIdentifier.
- Date: Fri, 5 Jan 2018 04:20:41 +0000 (UTC)
commit 0f3e1e011cbe82243afc103aa71717349cfe41a9
Author: Michael James Gratton <mike vee net>
Date: Wed Jan 3 15:01:21 2018 +1100
Add a GVariant API for (de)serialising FolderPath and EmailIdentifier.
* src/engine/api/geary-account.vala (Account): Add to_email_identifier
and to_folder_path methods for de-serialising these objects, replacing
new_folder_path. Update subclasses and call sites.
* src/engine/api/geary-email-identifier.vala (EmailIdentifier),
src/engine/api/geary-folder-path.vala (FolderPath): Add to_variant()
and tidy up the class source.
* src/engine/imap-db/imap-db-email-identifier.vala (EmailIdentifier),
src/engine/imap-db/outbox/smtp-outbox-email-identifier.vala
(SmtpOutboxEmailIdentifier): Add from_variant ctor, implement
to_variant. Clean up class source.
* src/engine/imap/api/imap-folder-root.vala (FolderRoot): Implement
from_variant factory method.
* src/client/components/main-window.vala (path_to_variant): Use new
engine API to pass FolderPaths around via action params.
src/client/components/main-window.vala | 42 +++----
src/engine/api/geary-account.vala | 45 +++++--
src/engine/api/geary-email-identifier.vala | 129 +++++++++++---------
src/engine/api/geary-folder-path.vala | 112 ++++++++++-------
src/engine/imap-db/imap-db-email-identifier.vala | 72 ++++++++---
.../outbox/smtp-outbox-email-identifier.vala | 42 ++++++-
.../imap-engine/imap-engine-generic-account.vala | 37 ++++--
src/engine/imap/api/imap-folder-root.vala | 39 +++++--
8 files changed, 336 insertions(+), 182 deletions(-)
---
diff --git a/src/client/components/main-window.vala b/src/client/components/main-window.vala
index 8585b6d..1979b86 100644
--- a/src/client/components/main-window.vala
+++ b/src/client/components/main-window.vala
@@ -661,22 +661,6 @@ public class MainWindow : Gtk.ApplicationWindow {
return (SimpleAction) lookup_action(name);
}
- private Geary.FolderPath? variant_to_path(Variant? strv) {
- Geary.FolderPath? path = null;
- if (this.current_folder != null &&
- strv != null &&
- strv.get_type_string() == "as") {
- path = this.current_folder.account.new_folder_path(
- new Gee.ArrayList<string>.wrap(strv.get_strv())
- );
- }
- return path;
- }
-
- private Variant path_to_variant(Geary.FolderPath path) {
- return new Variant.strv(path.as_list().to_array());
- }
-
private void on_folder_selected(Geary.Folder? folder) {
if (folder != null) {
update_folder(folder);
@@ -871,8 +855,15 @@ public class MainWindow : Gtk.ApplicationWindow {
}
private void on_conversation_copy(Action action, Variant? param) {
- Geary.FolderPath? destination = variant_to_path(param);
- if (path != null) {
+ Geary.FolderPath? destination = null;
+ if (param != null) {
+ try {
+ destination = this.current_folder.account.to_folder_path(param);
+ } catch (Geary.EngineError err) {
+ debug("Failed to deserialise folder path: %s", err.message);
+ }
+ }
+ if (destination != null) {
this.application.controller.copy_conversations.begin(
this.conversation_list.get_highlighted_conversations(),
destination,
@@ -1009,8 +1000,15 @@ public class MainWindow : Gtk.ApplicationWindow {
}
private void on_conversation_move(Action action, Variant? param) {
- Geary.FolderPath? destination = variant_to_path(param);
- if (path != null) {
+ Geary.FolderPath? destination = null;
+ if (param != null) {
+ try {
+ destination = this.current_folder.account.to_folder_path(param);
+ } catch (Geary.EngineError err) {
+ debug("Failed to deserialise folder path: %s", err.message);
+ }
+ }
+ if (destination != null) {
this.application.controller.move_conversations.begin(
this.conversation_list.get_highlighted_conversations(),
destination,
@@ -1055,11 +1053,11 @@ public class MainWindow : Gtk.ApplicationWindow {
}
public void on_copy_folder(Geary.Folder target) {
- get_action(ACTION_COPY).activate(path_to_variant(target.path));
+ get_action(ACTION_COPY).activate(target.path.to_variant());
}
public void on_move_folder(Geary.Folder target) {
- get_action(ACTION_MOVE).activate(path_to_variant(target.path));
+ get_action(ACTION_MOVE).activate(target.path.to_variant());
}
private void on_selection_mode_enabled() {
diff --git a/src/engine/api/geary-account.vala b/src/engine/api/geary-account.vala
index 6773ed9..6daf9b3 100644
--- a/src/engine/api/geary-account.vala
+++ b/src/engine/api/geary-account.vala
@@ -1,4 +1,6 @@
-/* Copyright 2016 Software Freedom Conservancy Inc.
+/*
+ * Copyright 2016 Software Freedom Conservancy Inc.
+ * Copyright 2018 Michael Gratton <mike vee net>.
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
@@ -187,6 +189,35 @@ public abstract class Geary.Account : BaseObject {
throws Error;
/**
+ * Returns the email identifier from its serialised form.
+ *
+ * This is useful for converting a string representation of a
+ * email id back into an actual instance of an id. This does not
+ * guarantee that the email represented by the id will exist.
+ *
+ * @see EmailIdentifier.to_variant
+ * @throws EngineError.BAD_PARAMETERS when the variant is not the
+ * have the correct type.
+ */
+ public abstract EmailIdentifier to_email_identifier(GLib.Variant serialised)
+ throws EngineError;
+
+ /**
+ * Returns the folder path from its serialised form.
+ *
+ * This is useful for converting a string representation of a
+ * folder path back into an actual instance of a path. This does
+ * not guarantee that the folder represented by the path will
+ * exist.
+ *
+ * @see FolderPath.to_variant
+ * @throws EngineError.BAD_PARAMETERS when the variant is not the
+ * have the correct type.
+ */
+ public abstract FolderPath to_folder_path(GLib.Variant serialised)
+ throws EngineError;
+
+ /**
* Lists all the currently-available folders found under the parent path
* unless it's null, in which case it lists all the root folders. If the
* parent path cannot be found, EngineError.NOT_FOUND is thrown. If no
@@ -209,18 +240,6 @@ public abstract class Geary.Account : BaseObject {
public abstract Gee.Collection<Geary.Folder> list_folders() throws Error;
/**
- * Returns a path for a list of folder names.
- *
- * This is useful for converting a string representation of a
- * folder path back into an actual instance of a folder path. This
- * does not guarantee that the folder represented by the path will
- * exist.
- *
- * {@see FolderPath.as_list}
- */
- public abstract FolderPath new_folder_path(Gee.List<string> name_list);
-
- /**
* Gets a perpetually update-to-date collection of autocompletion contacts.
*/
public abstract Geary.ContactStore get_contact_store();
diff --git a/src/engine/api/geary-email-identifier.vala b/src/engine/api/geary-email-identifier.vala
index e044ab1..53488c0 100644
--- a/src/engine/api/geary-email-identifier.vala
+++ b/src/engine/api/geary-email-identifier.vala
@@ -1,4 +1,6 @@
-/* Copyright 2016 Software Freedom Conservancy Inc.
+/*
+ * Copyright 2016 Software Freedom Conservancy Inc.
+ * Copyright 2018 Michael Gratton <mike vee net>.
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
@@ -17,24 +19,87 @@
*/
public abstract class Geary.EmailIdentifier : BaseObject, Gee.Hashable<Geary.EmailIdentifier> {
+
+ /**
+ * Sorts the supplied Collection of {@link EmailIdentifier} by their natural sort order.
+ *
+ * This method uses {@link natural_sort_comparator}, so read its provisions about comparison.
+ * In essence, this method should only be used against EmailIdentifiers that originated from
+ * the same Folder.
+ */
+ public static Gee.SortedSet<Geary.EmailIdentifier> sort(Gee.Collection<Geary.EmailIdentifier> ids) {
+ Gee.SortedSet<Geary.EmailIdentifier> sorted = new Gee.TreeSet<Geary.EmailIdentifier>(
+ (a, b) => {
+ int cmp = a.natural_sort_comparator(b);
+ if (cmp == 0)
+ cmp = a.stable_sort_comparator(b);
+
+ return cmp;
+ });
+ sorted.add_all(ids);
+
+ return sorted;
+ }
+
+ /**
+ * Sorts the supplied Collection of {@link EmailIdentifier} by their natural sort order.
+ *
+ * This method uses {@link natural_sort_comparator}, so read its provisions about comparison.
+ * In essence, this method should only be used against EmailIdentifiers that originated from
+ * the same Folder.
+ */
+ public static Gee.SortedSet<Geary.Email> sort_emails(Gee.Collection<Geary.Email> emails) {
+ Gee.SortedSet<Geary.Email> sorted = new Gee.TreeSet<Geary.Email>(
+ (a, b) => {
+ int cmp = a.id.natural_sort_comparator(b.id);
+ if (cmp == 0)
+ cmp = a.id.stable_sort_comparator(b.id);
+
+ return cmp;
+ });
+ sorted.add_all(emails);
+
+ return sorted;
+ }
+
+
// Warning: only change this if you know what you are doing.
protected string unique;
-
+
protected EmailIdentifier(string unique) {
this.unique = unique;
}
-
+
public virtual uint hash() {
return unique.hash();
}
-
+
+ /**
+ * Returns a representation useful for serialisation.
+ *
+ * This can be used to transmit ids as D-Bus method and GLib
+ * Action parameters, and so on.
+ *
+ * @returns a serialised form of this id, that will match the
+ * GVariantType `(*)`
+ * @see Account.to_email_identifier
+ */
+ public abstract GLib.Variant to_variant();
+
+ /**
+ * Returns a representation useful for debugging.
+ */
+ public virtual string to_string() {
+ return "[%s]".printf(unique.to_string());
+ }
+
public virtual bool equal_to(Geary.EmailIdentifier other) {
if (this == other)
return true;
-
+
return unique == other.unique;
}
-
+
/**
* A comparator for stabilizing sorts.
*
@@ -44,10 +109,10 @@ public abstract class Geary.EmailIdentifier : BaseObject, Gee.Hashable<Geary.Ema
public virtual int stable_sort_comparator(Geary.EmailIdentifier other) {
if (this == other)
return 0;
-
+
return strcmp(unique, other.unique);
}
-
+
/**
* A comparator for finding which {@link EmailIdentifier} is earliest in the "natural"
* sorting of a {@link Folder}'s list.
@@ -68,51 +133,5 @@ public abstract class Geary.EmailIdentifier : BaseObject, Gee.Hashable<Geary.Ema
* @see Folder.list_email_by_id_async
*/
public abstract int natural_sort_comparator(Geary.EmailIdentifier other);
-
- /**
- * Sorts the supplied Collection of {@link EmailIdentifier} by their natural sort order.
- *
- * This method uses {@link natural_sort_comparator}, so read its provisions about comparison.
- * In essence, this method should only be used against EmailIdentifiers that originated from
- * the same Folder.
- */
- public static Gee.SortedSet<Geary.EmailIdentifier> sort(Gee.Collection<Geary.EmailIdentifier> ids) {
- Gee.SortedSet<Geary.EmailIdentifier> sorted = new Gee.TreeSet<Geary.EmailIdentifier>(
- (a, b) => {
- int cmp = a.natural_sort_comparator(b);
- if (cmp == 0)
- cmp = a.stable_sort_comparator(b);
-
- return cmp;
- });
- sorted.add_all(ids);
-
- return sorted;
- }
-
- /**
- * Sorts the supplied Collection of {@link EmailIdentifier} by their natural sort order.
- *
- * This method uses {@link natural_sort_comparator}, so read its provisions about comparison.
- * In essence, this method should only be used against EmailIdentifiers that originated from
- * the same Folder.
- */
- public static Gee.SortedSet<Geary.Email> sort_emails(Gee.Collection<Geary.Email> emails) {
- Gee.SortedSet<Geary.Email> sorted = new Gee.TreeSet<Geary.Email>(
- (a, b) => {
- int cmp = a.id.natural_sort_comparator(b.id);
- if (cmp == 0)
- cmp = a.id.stable_sort_comparator(b.id);
-
- return cmp;
- });
- sorted.add_all(emails);
-
- return sorted;
- }
-
- public virtual string to_string() {
- return "[%s]".printf(unique.to_string());
- }
-}
+}
diff --git a/src/engine/api/geary-folder-path.vala b/src/engine/api/geary-folder-path.vala
index 7f0bf7b..2828a94 100644
--- a/src/engine/api/geary-folder-path.vala
+++ b/src/engine/api/geary-folder-path.vala
@@ -1,4 +1,6 @@
-/* Copyright 2016 Software Freedom Conservancy Inc.
+/*
+ * Copyright 2016 Software Freedom Conservancy Inc.
+ * Copyright 2018 Michael Gratton <mike vee net>.
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
@@ -15,11 +17,16 @@
public class Geary.FolderPath : BaseObject, Gee.Hashable<Geary.FolderPath>,
Gee.Comparable<Geary.FolderPath> {
+
+
+ public const string VARIANT_TYPE = "as";
+
+
/**
* The name of this folder (without any child or parent names or delimiters).
*/
public string basename { get; private set; }
-
+
/**
* Whether this path is lexiographically case-sensitive.
*
@@ -29,22 +36,22 @@ public class Geary.FolderPath : BaseObject, Gee.Hashable<Geary.FolderPath>,
private Gee.List<Geary.FolderPath>? path = null;
private uint stored_hash = uint.MAX;
-
+
protected FolderPath(string basename, bool case_sensitive) {
assert(this is FolderRoot);
-
+
this.basename = basename;
this.case_sensitive = case_sensitive;
}
-
+
private FolderPath.child(Gee.List<Geary.FolderPath> path, string basename, bool case_sensitive) {
assert(path[0] is FolderRoot);
-
+
this.path = path;
this.basename = basename;
this.case_sensitive = case_sensitive;
}
-
+
/**
* Returns true if this {@link FolderPath} is a root folder.
*
@@ -56,14 +63,14 @@ public class Geary.FolderPath : BaseObject, Gee.Hashable<Geary.FolderPath>,
public bool is_root() {
return (path == null || path.size == 0);
}
-
+
/**
* Returns the {@link FolderRoot} of this path.
*/
public Geary.FolderRoot get_root() {
return (FolderRoot) ((path != null && path.size > 0) ? path[0] : this);
}
-
+
/**
* Returns the parent {@link FolderPath} of this folder or null if this is the root.
*
@@ -72,7 +79,7 @@ public class Geary.FolderPath : BaseObject, Gee.Hashable<Geary.FolderPath>,
public Geary.FolderPath? get_parent() {
return (path != null && path.size > 0) ? path.last() : null;
}
-
+
/**
* Returns the number of folders in this path, not including any children of this object.
*/
@@ -80,7 +87,7 @@ public class Geary.FolderPath : BaseObject, Gee.Hashable<Geary.FolderPath>,
// include self, which is not stored in the path list
return (path != null) ? path.size + 1 : 1;
}
-
+
/**
* Returns the {@link FolderPath} object at the index, with this FolderPath object being
* the farthest child.
@@ -98,17 +105,17 @@ public class Geary.FolderPath : BaseObject, Gee.Hashable<Geary.FolderPath>,
// look like "this" is stored at the end of the path list
if (path == null)
return (index == 0) ? this : null;
-
+
int length = path.size;
if (index < length)
return path[index];
-
+
if (index == length)
return this;
-
+
return null;
}
-
+
/**
* Returns the {@link FolderPath} as a List of {@link basename} strings, this FolderPath's
* being the last in the list.
@@ -117,17 +124,17 @@ public class Geary.FolderPath : BaseObject, Gee.Hashable<Geary.FolderPath>,
*/
public Gee.List<string> as_list() {
Gee.List<string> list = new Gee.ArrayList<string>();
-
+
if (path != null) {
foreach (Geary.FolderPath folder in path)
list.add(folder.basename);
}
-
+
list.add(basename);
-
+
return list;
}
-
+
/**
* Creates a {@link FolderPath} object that is a child of this folder.
*
@@ -140,11 +147,11 @@ public class Geary.FolderPath : BaseObject, Gee.Hashable<Geary.FolderPath>,
if (path != null)
child_path.add_all(path);
child_path.add(this);
-
+
return new FolderPath.child(child_path, basename,
child_case_sensitive.to_boolean(get_root().default_case_sensitivity));
}
-
+
/**
* Returns true if the other {@link FolderPath} has the same parent as this one.
*
@@ -154,35 +161,35 @@ public class Geary.FolderPath : BaseObject, Gee.Hashable<Geary.FolderPath>,
public bool has_same_parent(FolderPath other) {
FolderPath? parent = get_parent();
FolderPath? other_parent = other.get_parent();
-
+
if (parent == other_parent)
return true;
-
+
if (parent != null && other_parent != null)
return parent.equal_to(other_parent);
-
+
return false;
}
private uint get_basename_hash() {
return case_sensitive ? str_hash(basename) : str_hash(basename.down());
}
-
+
private int compare_internal(Geary.FolderPath other, bool allow_case_sensitive, bool normalize) {
if (this == other)
return 0;
-
+
// walk elements using as_list() as that includes the basename (whereas path does not),
// avoids the null problem, and makes comparisons straightforward
Gee.List<string> this_list = as_list();
Gee.List<string> other_list = other.as_list();
-
+
// if paths exist, do comparison of each parent in order
int min = int.min(this_list.size, other_list.size);
for (int ctr = 0; ctr < min; ctr++) {
string this_element = this_list[ctr];
string other_element = other_list[ctr];
-
+
if (normalize) {
this_element = this_element.normalize();
other_element = other_element.normalize();
@@ -193,17 +200,17 @@ public class Geary.FolderPath : BaseObject, Gee.Hashable<Geary.FolderPath>,
this_element = this_element.casefold();
other_element = other_element.casefold();
}
-
+
int result = this_element.collate(other_element);
if (result != 0)
return result;
}
-
+
// paths up to the min element count are equal, shortest path is less-than, otherwise
// equal paths
return this_list.size - other_list.size;
}
-
+
/**
* Does a Unicode-normalized, case insensitive match. Useful for getting a rough idea if
* a folder matches a name, but shouldn't be used to determine strict equality.
@@ -211,7 +218,7 @@ public class Geary.FolderPath : BaseObject, Gee.Hashable<Geary.FolderPath>,
public int compare_normalized_ci(Geary.FolderPath other) {
return compare_internal(other, false, true);
}
-
+
/**
* {@inheritDoc}
*
@@ -229,7 +236,7 @@ public class Geary.FolderPath : BaseObject, Gee.Hashable<Geary.FolderPath>,
public int compare_to(Geary.FolderPath other) {
return compare_internal(other, true, false);
}
-
+
/**
* {@inheritDoc}
*
@@ -238,22 +245,22 @@ public class Geary.FolderPath : BaseObject, Gee.Hashable<Geary.FolderPath>,
public uint hash() {
if (stored_hash != uint.MAX)
return stored_hash;
-
+
// always one element in path
stored_hash = get_folder_at(0).get_basename_hash();
-
+
int path_length = get_path_length();
for (int ctr = 1; ctr < path_length; ctr++)
stored_hash ^= get_folder_at(ctr).get_basename_hash();
-
+
return stored_hash;
}
-
+
private bool is_basename_equal(string cmp, bool other_cs) {
// case-sensitive comparison if either is sensitive
return (other_cs || case_sensitive) ? (basename == cmp) : (basename.down() == cmp.down());
}
-
+
/**
* {@inheritDoc}
*/
@@ -261,21 +268,35 @@ public class Geary.FolderPath : BaseObject, Gee.Hashable<Geary.FolderPath>,
int path_length = get_path_length();
if (other.get_path_length() != path_length)
return false;
-
+
for (int ctr = 0; ctr < path_length; ctr++) {
// this should never return null as length is already checked
FolderPath? other_folder = other.get_folder_at(ctr);
assert(other_folder != null);
-
+
if (!get_folder_at(ctr).is_basename_equal(other_folder.basename, other_folder.case_sensitive))
return false;
}
-
+
return true;
}
/**
- * Returns a string version of the path using a default separator.
+ * Returns a representation useful for serialisation.
+ *
+ * This can be used to transmit folder paths as D-Bus method and
+ * GLib Action parameters, and so on.
+ *
+ * @returns a serialised form of this path, that will match the
+ * GVariantType `as`
+ * @see Account.to_folder_path
+ */
+ public Variant to_variant() {
+ return new Variant.strv(as_list().to_array());
+ }
+
+ /**
+ * Returns a representation useful for debugging.
*
* Do not use this for obtaining an IMAP mailbox name to send to a
* server, use {@link Geary.Imap.MailboxSpecifier.from_folder_path}
@@ -292,8 +313,10 @@ public class Geary.FolderPath : BaseObject, Gee.Hashable<Geary.FolderPath>,
builder.append(basename);
return builder.str;
}
+
}
+
/**
* The root of a folder heirarchy.
*
@@ -312,11 +335,10 @@ public abstract class Geary.FolderRoot : Geary.FolderPath {
* @see FolderPath.get_child
*/
public bool default_case_sensitivity { get; private set; }
-
+
protected FolderRoot(string basename, bool case_sensitive, bool default_case_sensitivity) {
base (basename, case_sensitive);
-
+
this.default_case_sensitivity = default_case_sensitivity;
}
}
-
diff --git a/src/engine/imap-db/imap-db-email-identifier.vala
b/src/engine/imap-db/imap-db-email-identifier.vala
index 5f0fb0e..e7b1a44 100644
--- a/src/engine/imap-db/imap-db-email-identifier.vala
+++ b/src/engine/imap-db/imap-db-email-identifier.vala
@@ -1,85 +1,117 @@
-/* Copyright 2016 Software Freedom Conservancy Inc.
+/*
+ * Copyright 2016 Software Freedom Conservancy Inc.
+ * Copyright 2018 Michael Gratton <mike vee net>.
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
*/
private class Geary.ImapDB.EmailIdentifier : Geary.EmailIdentifier {
+
+
+ private const string VARIANT_TYPE = "(yxx)";
+
+
public int64 message_id { get; private set; }
public Imap.UID? uid { get; private set; }
-
+
public EmailIdentifier(int64 message_id, Imap.UID? uid) {
assert(message_id != Db.INVALID_ROWID);
-
+
base (message_id.to_string());
-
+
this.message_id = message_id;
this.uid = uid;
}
-
+
+ public EmailIdentifier.from_variant(Variant serialised) throws EngineError {
+ if (serialised.get_type_string() != VARIANT_TYPE) {
+ throw new EngineError.BAD_PARAMETERS(
+ "Invalid serialised id type: %s", serialised.get_type_string()
+ );
+ }
+ Imap.UID? uid = null;
+ int64 uid_value = serialised.get_child_value(2).get_int64();
+ if (uid_value >= 0) {
+ uid = new Imap.UID(uid_value);
+ }
+ this(serialised.get_child_value(1).get_int64(), uid);
+ }
+
// Used when a new message comes off the wire and doesn't have a rowid associated with it (yet)
// Requires a UID in order to find or create such an association
public EmailIdentifier.no_message_id(Imap.UID uid) {
base (Db.INVALID_ROWID.to_string());
-
+
message_id = Db.INVALID_ROWID;
this.uid = uid;
}
-
+
// Used to promote an id created with no_message_id to one that has a
// message id. Warning: this causes the hash value to change, so if you
// have any EmailIdentifiers in a hashed data structure, this will cause
// you not to be able to find them.
public void promote_with_message_id(int64 message_id) {
assert(this.message_id == Db.INVALID_ROWID);
-
+
unique = message_id.to_string();
this.message_id = message_id;
}
-
+
public bool has_uid() {
return (uid != null) && uid.is_valid();
}
-
+
public override int natural_sort_comparator(Geary.EmailIdentifier o) {
ImapDB.EmailIdentifier? other = o as ImapDB.EmailIdentifier;
if (other == null)
return 1;
-
+
if (uid == null)
return 1;
-
+
if (other.uid == null)
return -1;
-
+
return uid.compare_to(other.uid);
}
-
+
+ public override Variant to_variant() {
+ // Return a tuple to satisfy the API contract, add an 'i' to
+ // inform GenericAccount that it's an IMAP id.
+ int64 uid_value = this.uid != null ? this.uid.value : -1;
+ return new Variant.tuple(new Variant[] {
+ new Variant.byte('i'),
+ new Variant.int64(this.message_id),
+ new Variant.int64(uid_value)
+ });
+ }
+
public override string to_string() {
return "[%s/%s]".printf(message_id.to_string(), (uid == null ? "null" : uid.to_string()));
}
-
+
// Email's with no UID get sorted after emails with
public static int compare_email_uid_ascending(Geary.Email a, Geary.Email b) {
Imap.UID? auid = ((ImapDB.EmailIdentifier) a.id).uid;
Imap.UID? buid = ((ImapDB.EmailIdentifier) b.id).uid;
-
+
if (auid == null)
return (buid != null) ? 1 : 0;
-
+
if (buid == null)
return -1;
-
+
return auid.compare_to(buid);
}
-
+
public static Gee.Set<Imap.UID> to_uids(Gee.Collection<ImapDB.EmailIdentifier> ids) {
Gee.HashSet<Imap.UID> uids = new Gee.HashSet<Imap.UID>();
foreach (ImapDB.EmailIdentifier id in ids) {
if (id.uid != null)
uids.add(id.uid);
}
-
+
return uids;
}
}
diff --git a/src/engine/imap-db/outbox/smtp-outbox-email-identifier.vala
b/src/engine/imap-db/outbox/smtp-outbox-email-identifier.vala
index 2500acc..6acc2cf 100644
--- a/src/engine/imap-db/outbox/smtp-outbox-email-identifier.vala
+++ b/src/engine/imap-db/outbox/smtp-outbox-email-identifier.vala
@@ -1,24 +1,54 @@
-/* Copyright 2016 Software Freedom Conservancy Inc.
+/*
+ * Copyright 2016 Software Freedom Conservancy Inc.
+ * Copyright 2018 Michael Gratton <mike vee net>.
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
*/
private class Geary.SmtpOutboxEmailIdentifier : Geary.EmailIdentifier {
+
+
+ private const string VARIANT_TYPE = "(yxx)";
+
+ public int64 message_id { get; private set; }
public int64 ordering { get; private set; }
-
+
+
public SmtpOutboxEmailIdentifier(int64 message_id, int64 ordering) {
base ("SmtpOutboxEmailIdentifer:%s".printf(message_id.to_string()));
-
+ this.message_id = message_id;
this.ordering = ordering;
}
-
+
+ internal SmtpOutboxEmailIdentifier.from_variant(Variant serialised)
+ throws EngineError {
+ if (serialised.get_type_string() != VARIANT_TYPE) {
+ throw new EngineError.BAD_PARAMETERS(
+ "Invalid serialised id type: %s", serialised.get_type_string()
+ );
+ }
+ Variant mid = serialised.get_child_value(1);
+ Variant uid = serialised.get_child_value(2);
+ this(mid.get_int64(), uid.get_int64());
+ }
+
public override int natural_sort_comparator(Geary.EmailIdentifier o) {
SmtpOutboxEmailIdentifier? other = o as SmtpOutboxEmailIdentifier;
if (other == null)
return 1;
-
+
return (int) (ordering - other.ordering).clamp(-1, 1);
}
-}
+ public override Variant to_variant() {
+ // Return a tuple to satisfy the API contract, add an 's' to
+ // inform GenericAccount that it's an SMTP id.
+ return new Variant.tuple(new Variant[] {
+ new Variant.byte('s'),
+ new Variant.int64(this.message_id),
+ new Variant.int64(this.ordering)
+ });
+ }
+
+}
diff --git a/src/engine/imap-engine/imap-engine-generic-account.vala
b/src/engine/imap-engine/imap-engine-generic-account.vala
index 6872e0a..6e8340b 100644
--- a/src/engine/imap-engine/imap-engine-generic-account.vala
+++ b/src/engine/imap-engine/imap-engine-generic-account.vala
@@ -1,4 +1,6 @@
-/* Copyright 2016 Software Freedom Conservancy Inc.
+/*
+ * Copyright 2016 Software Freedom Conservancy Inc.
+ * Copyright 2018 Michael Gratton <mike vee net>.
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
@@ -18,6 +20,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
private static Geary.FolderPath? outbox_path = null;
private static Geary.FolderPath? search_path = null;
+ private static VariantType email_id_type = new VariantType("(y*)");
private Imap.Account remote;
private ImapDB.Account local;
@@ -304,6 +307,27 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
yield this.remote.open_async();
}
+ public override EmailIdentifier to_email_identifier(GLib.Variant serialised)
+ throws EngineError {
+ if (serialised.is_of_type(GenericAccount.email_id_type)) {
+ throw new EngineError.BAD_PARAMETERS(
+ "Invalid outer serialised type: (y*)"
+ );
+ }
+ char type = (char) serialised.get_child_value(0).get_byte();
+ if (type == 'i')
+ return new ImapDB.EmailIdentifier.from_variant(serialised);
+ if (type == 's')
+ return new SmtpOutboxEmailIdentifier.from_variant(serialised);
+
+ throw new EngineError.BAD_PARAMETERS("Unknown serialised type: %c", type);
+ }
+
+ public override FolderPath to_folder_path(GLib.Variant serialised)
+ throws EngineError {
+ return Imap.FolderRoot.from_variant(serialised);
+ }
+
// Subclasses should implement this to return their flavor of a MinimalFolder with the
// appropriate interfaces attached. The returned folder should have its SpecialFolderType
// set using either the properties from the local folder or its path.
@@ -370,17 +394,6 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
return all_folders;
}
-
- public override FolderPath new_folder_path(Gee.List<string> name_list) {
- Gee.Iterator<string> names = name_list.iterator();
- names.next();
- Geary.FolderPath path = new Imap.FolderRoot(names.get());
- while (names.next()) {
- path = path.get_child(names.get());
- }
- return path;
- }
-
private void reschedule_unseen_update(Geary.Folder folder) {
if (!folder_map.has_key(folder.path))
return;
diff --git a/src/engine/imap/api/imap-folder-root.vala b/src/engine/imap/api/imap-folder-root.vala
index e19a4a1..58ac388 100644
--- a/src/engine/imap/api/imap-folder-root.vala
+++ b/src/engine/imap/api/imap-folder-root.vala
@@ -1,4 +1,6 @@
-/* Copyright 2016 Software Freedom Conservancy Inc.
+/*
+ * Copyright 2016 Software Freedom Conservancy Inc.
+ * Copyright 2018 Michael Gratton <mike vee net>.
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
@@ -13,28 +15,47 @@
*/
private class Geary.Imap.FolderRoot : Geary.FolderRoot {
+
+
+ public static FolderPath from_variant(Variant serialised)
+ throws EngineError {
+ if (serialised.get_type_string() != VARIANT_TYPE) {
+ throw new EngineError.BAD_PARAMETERS(
+ "Invalid serialised id type: %s", serialised.get_type_string()
+ );
+ }
+
+ FolderPath path = new FolderRoot(serialised.get_child_value(0).get_string());
+ for (int i = 1; i < serialised.n_children(); i++) {
+ path = path.get_child(serialised.get_child_value(i).get_string());
+ }
+ return path;
+ }
+
+
public bool is_inbox { get; private set; }
-
+
+
public FolderRoot(string basename) {
bool init_is_inbox;
string normalized_basename = init(basename, out init_is_inbox);
-
+
base (normalized_basename, !init_is_inbox, true);
-
+
is_inbox = init_is_inbox;
}
-
+
// This is the magic that ensures the canonical IMAP Inbox name is used throughout the engine
private static string init(string basename, out bool is_inbox) {
if (MailboxSpecifier.is_inbox_name(basename)) {
is_inbox = true;
-
+
return MailboxSpecifier.CANONICAL_INBOX_NAME;
}
-
+
is_inbox = false;
-
+
return basename;
}
-}
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]