Merge branch 'master' into feature/drafts
This commit is contained in:
commit
8059f0f31e
6 changed files with 110 additions and 28 deletions
1
THANKS
1
THANKS
|
|
@ -16,6 +16,7 @@ Jens Georg <mail@jensge.org>
|
|||
Michael George <mdgeorge@cs.cornell.edu>
|
||||
Sven Hagemann <sven@rednose.nl>
|
||||
Mathias Hasselmann <mathias@openismus.com>
|
||||
Brendan Long <self@brendanlong.com>
|
||||
Timo Kluck <tkluck@infty.nl>
|
||||
Avi Levy <avi.w.levy@gmail.com>
|
||||
Kai Mast <mail@kai-mast.de>
|
||||
|
|
|
|||
|
|
@ -10,8 +10,14 @@ public abstract class Geary.BaseObject : Object {
|
|||
|
||||
protected BaseObject() {
|
||||
lock (refmap) {
|
||||
if (refmap == null)
|
||||
refmap = new Gee.HashMap<unowned string, int>(direct_hash, direct_equal);
|
||||
if (refmap == null) {
|
||||
// because strings are unowned and guaranteed to be
|
||||
// unique by GType, use direct comparison functions,
|
||||
// more efficient then string hash/equal
|
||||
refmap = new Gee.HashMap<unowned string, int>(
|
||||
Gee.Functions.get_hash_func_for(typeof(void*)),
|
||||
Gee.Functions.get_equal_func_for(typeof(void*)));
|
||||
}
|
||||
|
||||
unowned string classname = get_classname();
|
||||
refmap.set(classname, refmap.get(classname) + 1);
|
||||
|
|
@ -42,7 +48,7 @@ public abstract class Geary.BaseObject : Object {
|
|||
|
||||
Gee.ArrayList<unowned string> list = new Gee.ArrayList<unowned string>();
|
||||
list.add_all(refmap.keys);
|
||||
list.sort(strcmp);
|
||||
list.sort();
|
||||
foreach (unowned string classname in list)
|
||||
outs.printf("%9d %s\n", refmap.get(classname), classname);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -369,6 +369,17 @@ private class Geary.ImapEngine.AccountSynchronizer : Geary.BaseObject {
|
|||
} else if (epoch_id != null) {
|
||||
oldest_local_id = epoch_id;
|
||||
}
|
||||
|
||||
// look for complete synchronization of UIDs (i.e. complete vector normalization)
|
||||
// no need to keep searching once this happens
|
||||
int local_count = yield folder.local_folder.get_email_count_async(ImapDB.Folder.ListFlags.NONE,
|
||||
bg_cancellable);
|
||||
if (local_count >= folder.properties.email_total) {
|
||||
debug("Total vector normalization for %s: %d/%d emails", folder.to_string(), local_count,
|
||||
folder.properties.email_total);
|
||||
|
||||
break;
|
||||
}
|
||||
} while (current_epoch.compare(epoch) > 0);
|
||||
} else {
|
||||
debug("No expansion necessary for %s, oldest local (%s) is before epoch (%s)",
|
||||
|
|
|
|||
|
|
@ -1028,7 +1028,11 @@ private class Geary.ImapEngine.GenericFolder : Geary.AbstractFolder, Geary.Folde
|
|||
check_open("expunge_email_async");
|
||||
check_ids("expunge_email_async", email_ids);
|
||||
|
||||
replay_queue.schedule(new ExpungeEmail(this, email_ids, cancellable));
|
||||
ExpungeEmail expunge = new ExpungeEmail(this, (Gee.List<ImapDB.EmailIdentifier>) email_ids,
|
||||
cancellable);
|
||||
replay_queue.schedule(expunge);
|
||||
|
||||
yield expunge.wait_for_ready_async(cancellable);
|
||||
}
|
||||
|
||||
private void check_open(string method) throws EngineError {
|
||||
|
|
@ -1058,22 +1062,29 @@ private class Geary.ImapEngine.GenericFolder : Geary.AbstractFolder, Geary.Folde
|
|||
Cancellable? cancellable = null) throws Error {
|
||||
check_open("mark_email_async");
|
||||
|
||||
replay_queue.schedule(new MarkEmail(this, to_mark, flags_to_add, flags_to_remove,
|
||||
cancellable));
|
||||
MarkEmail mark = new MarkEmail(this, to_mark, flags_to_add, flags_to_remove, cancellable);
|
||||
replay_queue.schedule(mark);
|
||||
yield mark.wait_for_ready_async(cancellable);
|
||||
}
|
||||
|
||||
public virtual async void copy_email_async(Gee.List<Geary.EmailIdentifier> to_copy,
|
||||
Geary.FolderPath destination, Cancellable? cancellable = null) throws Error {
|
||||
check_open("copy_email_async");
|
||||
check_ids("copy_email_async", to_copy);
|
||||
|
||||
replay_queue.schedule(new CopyEmail(this, to_copy, destination));
|
||||
CopyEmail copy = new CopyEmail(this, (Gee.List<ImapDB.EmailIdentifier>) to_copy, destination);
|
||||
replay_queue.schedule(copy);
|
||||
yield copy.wait_for_ready_async(cancellable);
|
||||
}
|
||||
|
||||
public virtual async void move_email_async(Gee.List<Geary.EmailIdentifier> to_move,
|
||||
Geary.FolderPath destination, Cancellable? cancellable = null) throws Error {
|
||||
check_open("move_email_async");
|
||||
check_ids("move_email_async", to_move);
|
||||
|
||||
replay_queue.schedule(new MoveEmail(this, to_move, destination));
|
||||
MoveEmail move = new MoveEmail(this, (Gee.List<ImapDB.EmailIdentifier>) to_move, destination);
|
||||
replay_queue.schedule(move);
|
||||
yield move.wait_for_ready_async(cancellable);
|
||||
}
|
||||
|
||||
private void on_email_flags_changed(Gee.Map<Geary.EmailIdentifier, Geary.EmailFlags> changed) {
|
||||
|
|
@ -1113,7 +1124,7 @@ private class Geary.ImapEngine.GenericFolder : Geary.AbstractFolder, Geary.Folde
|
|||
// class. Magically generating EmailIdentifiers is a bad idea. (That's why this uses
|
||||
// list_email_by_id_async() and not fetch_email_async(), and why OLDEST_TO_NEWEST is set.)
|
||||
Gee.List<Geary.Email>? list = yield list_email_by_id_async(found_id, 1, Geary.Email.Field.NONE,
|
||||
ListFlags.OLDEST_TO_NEWEST, cancellable);
|
||||
ListFlags.OLDEST_TO_NEWEST | ListFlags.INCLUDING_ID, cancellable);
|
||||
if (list == null || list.size == 0)
|
||||
return null;
|
||||
|
||||
|
|
|
|||
|
|
@ -45,26 +45,64 @@ public class Geary.RFC822.MessageIDList : Geary.MessageData.AbstractMessageData,
|
|||
public MessageIDList.from_rfc822_string(string value) {
|
||||
this ();
|
||||
|
||||
string[] ids = value.split_set(" \n\r\t");
|
||||
// Have seen some mailers use commas between Message-IDs, meaning that the standard
|
||||
// whitespace tokenizer is not sufficient; however, can't add the comma (or every other
|
||||
// delimiter that mailers dream up) because it may be used within a Message-ID. The
|
||||
// only guarantee made of a Message-ID is that it's surrounded by angle brackets, so
|
||||
// mark anything not an angle bracket as a space and strip
|
||||
//
|
||||
// NOTE: Seen at least one spamfilter mailer that imaginatively uses parens instead of
|
||||
// angle brackets for its Message-IDs; accounting for that as well here.
|
||||
StringBuilder canonicalized = new StringBuilder();
|
||||
int index = 0;
|
||||
unichar ch;
|
||||
bool in_message_id = false;
|
||||
while (value.get_next_char(ref index, out ch)) {
|
||||
switch (ch) {
|
||||
case '<':
|
||||
in_message_id = true;
|
||||
break;
|
||||
|
||||
case '(':
|
||||
if (!in_message_id) {
|
||||
ch = '<';
|
||||
in_message_id = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case '>':
|
||||
in_message_id = false;
|
||||
break;
|
||||
|
||||
case ')':
|
||||
if (in_message_id) {
|
||||
ch = '>';
|
||||
in_message_id = false;
|
||||
}
|
||||
break;
|
||||
|
||||
// anything not inside the message-id brackets is turned into spaces
|
||||
default:
|
||||
if (!in_message_id)
|
||||
ch = ' ';
|
||||
break;
|
||||
}
|
||||
|
||||
canonicalized.append_unichar(ch);
|
||||
}
|
||||
|
||||
if (value != canonicalized.str)
|
||||
debug("Message-ID list corrected: \"%s\" -> \"%s\"", value, canonicalized.str);
|
||||
|
||||
// there's some additional paranoia here with getting the Message-ID sliced out of the
|
||||
// strings, but it's worth it to get a valid Message-ID or none at all vs. a bogus one
|
||||
string[] ids = canonicalized.str.split(" ");
|
||||
foreach (string id in ids) {
|
||||
if (String.is_empty(id))
|
||||
continue;
|
||||
|
||||
// Have seen some mailers use commas between Message-IDs, meaning that the standard
|
||||
// whitespace tokenizer is not sufficient; however, can't add the comma (or every other
|
||||
// delimiter that mailers dream up) because it may be used within a Message-ID. The
|
||||
// only guarantee made of a Message-ID is that it's surrounded by angle brackets, so
|
||||
// mark anything not an angle bracket as a space and strip
|
||||
//
|
||||
// NOTE: Seen at least one spamfilter mailer that imaginatively uses parens instead of
|
||||
// angle brackets for its Message-IDs; accounting for that as well here.
|
||||
int start = id.index_of_char('<');
|
||||
if (start < 0)
|
||||
start = id.index_of_char('(');
|
||||
|
||||
int end = id.last_index_of_char('>');
|
||||
if (end < 0)
|
||||
end = id.last_index_of_char(')');
|
||||
|
||||
// if either end not found or the end comes before the beginning, invalid Message-ID
|
||||
if (start < 0 || end < 0 || (start >= end)) {
|
||||
|
|
|
|||
|
|
@ -3,23 +3,38 @@
|
|||
<!-- interface-requires gtk+ 3.0 -->
|
||||
<object class="GtkActionGroup" id="compose actions">
|
||||
<child>
|
||||
<object class="GtkAction" id="undo"/>
|
||||
<object class="GtkAction" id="undo">
|
||||
<property name="label" translatable="yes">Undo</property>
|
||||
<property name="icon-name">undo</property>
|
||||
</object>
|
||||
<accelerator key="z" modifiers="GDK_CONTROL_MASK"/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAction" id="redo"/>
|
||||
<object class="GtkAction" id="redo">
|
||||
<property name="label" translatable="yes">Redo</property>
|
||||
<property name="icon-name">redo</property>
|
||||
</object>
|
||||
<accelerator key="z" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK"/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAction" id="cut"/>
|
||||
<object class="GtkAction" id="cut">
|
||||
<property name="label" translatable="yes">Cut</property>
|
||||
<property name="icon-name">edit-cut</property>
|
||||
</object>
|
||||
<accelerator key="x" modifiers="GDK_CONTROL_MASK"/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAction" id="copy"/>
|
||||
<object class="GtkAction" id="copy">
|
||||
<property name="label" translatable="yes">Copy</property>
|
||||
<property name="icon-name">edit-copy</property>
|
||||
</object>
|
||||
<accelerator key="c" modifiers="GDK_CONTROL_MASK"/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAction" id="paste"/>
|
||||
<object class="GtkAction" id="paste">
|
||||
<property name="label" translatable="yes">Paste</property>
|
||||
<property name="icon-name">edit-paste</property>
|
||||
</object>
|
||||
<accelerator key="v" modifiers="GDK_CONTROL_MASK"/>
|
||||
</child>
|
||||
<child>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue