diff --git a/Makefile b/Makefile index cac493b7..45792bef 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ ENGINE_SRC := \ src/engine/api/Account.vala \ src/engine/api/Email.vala \ src/engine/api/EmailProperties.vala \ - src/engine/api/EmailOrdering.vala \ + src/engine/api/EmailLocation.vala \ src/engine/api/Folder.vala \ src/engine/api/FolderProperties.vala \ src/engine/api/Credentials.vala \ @@ -30,6 +30,8 @@ ENGINE_SRC := \ src/engine/sqlite/MessageTable.vala \ src/engine/sqlite/MessageLocationRow.vala \ src/engine/sqlite/MessageLocationTable.vala \ + src/engine/sqlite/ImapMessageLocationPropertiesTable.vala \ + src/engine/sqlite/ImapMessageLocationPropertiesRow.vala \ src/engine/sqlite/api/Account.vala \ src/engine/sqlite/api/Folder.vala \ src/engine/state/Machine.vala \ @@ -70,10 +72,12 @@ ENGINE_SRC := \ src/engine/imap/decoders/SelectExamineResults.vala \ src/engine/imap/decoders/StatusResults.vala \ src/engine/imap/api/Account.vala \ + src/engine/imap/api/EmailLocation.vala \ src/engine/imap/api/EmailProperties.vala \ src/engine/imap/api/Folder.vala \ src/engine/imap/api/FolderProperties.vala \ src/engine/rfc822/MailboxAddress.vala \ + src/engine/rfc822/MailboxAddresses.vala \ src/engine/rfc822/MessageData.vala \ src/engine/util/Memory.vala \ src/engine/util/ReferenceSemantics.vala \ diff --git a/sql/Create.sql b/sql/Create.sql index 69910eca..94aadcd5 100644 --- a/sql/Create.sql +++ b/sql/Create.sql @@ -50,7 +50,7 @@ CREATE TABLE MessageLocationTable ( id INTEGER PRIMARY KEY, message_id INTEGER REFERENCES MessageTable ON DELETE CASCADE, folder_id INTEGER REFERENCES FolderTable ON DELETE CASCADE, - ordering INTEGER + position INTEGER ); CREATE INDEX MessageLocationTableMessageIDIndex ON MessageLocationTable(message_id); @@ -92,3 +92,15 @@ CREATE TABLE ImapMessagePropertiesTable ( CREATE INDEX ImapMessagePropertiesTableMessageIDIndex ON ImapMessagePropertiesTable(message_id); +-- +-- ImapMessageLocationPropertiesTable +-- + +CREATE TABLE ImapMessageLocationPropertiesTable ( + id INTEGER PRIMARY KEY, + location_id INTEGER UNIQUE REFERENCES MessageLocationTable ON DELETE CASCADE, + uid INTEGER +); + +CREATE INDEX ImapMessageLocationPropertiesTableLocationIDIndex ON ImapMessageLocationPropertiesTable(location_id); + diff --git a/src/client/ui/MainWindow.vala b/src/client/ui/MainWindow.vala index d8ea7c57..7ca04086 100644 --- a/src/client/ui/MainWindow.vala +++ b/src/client/ui/MainWindow.vala @@ -68,14 +68,6 @@ public class MainWindow : Gtk.Window { do_start.begin(); } - private void on_folders_added_removed(Gee.Collection? added, - Gee.Collection? removed) { - if (added != null) { - folder_list_store.add_folders(added); - debug("%d folders added", added.size); - } - } - private async void do_start() { try { // pull down the root-level folders @@ -196,10 +188,13 @@ public class MainWindow : Gtk.Window { private async void do_select_folder(Geary.Folder folder) throws Error { message_list_store.clear(); - if (current_folder != null) + if (current_folder != null) { + current_folder.email_added_removed.disconnect(on_email_added_removed); yield current_folder.close_async(); + } current_folder = folder; + current_folder.email_added_removed.connect(on_email_added_removed); yield current_folder.open_async(true); @@ -207,7 +202,7 @@ public class MainWindow : Gtk.Window { Geary.Email.Field.ENVELOPE); if (email != null && email.size > 0) { foreach (Geary.Email envelope in email) - message_list_store.append_header(envelope); + message_list_store.append_envelope(envelope); } } @@ -236,7 +231,8 @@ public class MainWindow : Gtk.Window { return; } - Geary.Email text = yield current_folder.fetch_email_async(email.msg_num, Geary.Email.Field.BODY); + Geary.Email text = yield current_folder.fetch_email_async(email.location.position, + Geary.Email.Field.BODY); message_buffer.set_text(text.body.buffer.to_ascii_string()); } @@ -247,5 +243,20 @@ public class MainWindow : Gtk.Window { debug("Unable to select message: %s", err.message); } } + + private void on_folders_added_removed(Gee.Collection? added, + Gee.Collection? removed) { + if (added != null) { + folder_list_store.add_folders(added); + debug("%d folders added", added.size); + } + } + + private void on_email_added_removed(Gee.List? added, Gee.List? removed) { + if (added != null) { + foreach (Geary.Email email in added) + message_list_store.append_envelope(email); + } + } } diff --git a/src/client/ui/MessageListStore.vala b/src/client/ui/MessageListStore.vala index d498f388..ef7d13e7 100644 --- a/src/client/ui/MessageListStore.vala +++ b/src/client/ui/MessageListStore.vala @@ -54,7 +54,8 @@ public class MessageListStore : Gtk.TreeStore { set_column_types(Column.get_types()); } - public void append_header(Geary.Email envelope) { + // The Email should've been fetched with Geary.Email.Field.ENVELOPE, at least. + public void append_envelope(Geary.Email envelope) { Gtk.TreeIter iter; append(out iter, null); diff --git a/src/engine/EngineFolder.vala b/src/engine/EngineFolder.vala index 6306721d..00702224 100644 --- a/src/engine/EngineFolder.vala +++ b/src/engine/EngineFolder.vala @@ -30,7 +30,7 @@ private class Geary.EngineFolder : Object, Geary.Folder { return null; } - public async void create_email_async(Geary.Email email, Geary.EmailOrdering ordering, + public async void create_email_async(Geary.Email email, Geary.Email.Field fields, Cancellable? cancellable) throws Error { throw new EngineError.READONLY("Engine currently read-only"); } @@ -57,9 +57,111 @@ private class Geary.EngineFolder : Object, Geary.Folder { return 0; } - public async Gee.List list_email_async(int low, int count, Geary.Email.Field fields, + public async Gee.List? list_email_async(int low, int count, Geary.Email.Field fields, Cancellable? cancellable = null) throws Error { - return yield net_folder.list_email_async(low, count, fields, cancellable); + assert(low >= 1); + assert(count >= 0); + + if (count == 0) + return null; + + Gee.List? local_list = yield local_folder.list_email_async(low, count, fields, + cancellable); + int local_list_size = (local_list != null) ? local_list.size : 0; + debug("local list found %d", local_list_size); + + if (net_folder != null && local_list_size != count) { + // go through the positions from (low) to (low + count) and see if they're not already + // present in local_list; whatever isn't present needs to be fetched + int[] needed_by_position = new int[0]; + int position = low; + for (int index = 0; (index < count) && (position <= (low + count - 1)); position++) { + while ((index < local_list_size) && (local_list[index].location.position < position)) + index++; + + if (index >= local_list_size || local_list[index].location.position != position) + needed_by_position += position; + } + + if (needed_by_position.length != 0) + background_update_email_list.begin(needed_by_position, fields, cancellable); + } + + return local_list; + } + + public async Gee.List? list_email_sparse_async(int[] by_position, + Geary.Email.Field fields, Cancellable? cancellable = null) throws Error { + if (by_position.length == 0) + return null; + + Gee.List? local_list = yield local_folder.list_email_sparse_async(by_position, + fields, cancellable); + int local_list_size = (local_list != null) ? local_list.size : 0; + + if (net_folder != null && local_list_size != by_position.length) { + // go through the list looking for anything not already in the sparse by_position list + // to fetch from the server; since by_position is not guaranteed to be sorted, the local + // list needs to be searched each iteration. + // + // TODO: Optimize this, especially if large lists/sparse sets are supplied + int[] needed_by_position = new int[0]; + foreach (int position in by_position) { + bool found = false; + if (local_list != null) { + foreach (Geary.Email email in local_list) { + if (email.location.position == position) { + found = true; + + break; + } + } + } + + if (!found) + needed_by_position += position; + } + + if (needed_by_position.length != 0) + background_update_email_list.begin(needed_by_position, fields, cancellable); + } + + return local_list; + } + + private async void background_update_email_list(int[] needed_by_position, Geary.Email.Field fields, + Cancellable? cancellable) { + debug("Background fetching %d emails for %s", needed_by_position.length, get_name()); + + Gee.List? net_list = null; + try { + net_list = yield net_folder.list_email_sparse_async(needed_by_position, fields, + cancellable); + } catch (Error net_err) { + message("Unable to fetch emails from server: %s", net_err.message); + + if (net_err is IOError.CANCELLED) + return; + } + + if (net_list != null && net_list.size == 0) + net_list = null; + + if (net_list != null) + notify_email_added_removed(net_list, null); + + if (net_list != null) { + foreach (Geary.Email email in net_list) { + try { + yield local_folder.create_email_async(email, fields, cancellable); + } catch (Error local_err) { + message("Unable to create email in local store: %s", local_err.message); + + if (local_err is IOError.CANCELLED) + return; + } + } + } } public async Geary.Email fetch_email_async(int num, Geary.Email.Field fields, diff --git a/src/engine/api/Email.vala b/src/engine/api/Email.vala index c0250449..320f2324 100644 --- a/src/engine/api/Email.vala +++ b/src/engine/api/Email.vala @@ -33,7 +33,7 @@ public class Geary.Email : Object { } } - public int msg_num { get; private set; } + public Geary.EmailLocation location { get; private set; } // DATE public Geary.RFC822.Date? date = null; @@ -64,8 +64,8 @@ public class Geary.Email : Object { // PROPERTIES public Geary.EmailProperties? properties = null; - public Email(int msg_num) { - this.msg_num = msg_num; + public Email(Geary.EmailLocation location) { + this.location = location; } public string to_string() { diff --git a/src/engine/api/EmailOrdering.vala b/src/engine/api/EmailLocation.vala similarity index 55% rename from src/engine/api/EmailOrdering.vala rename to src/engine/api/EmailLocation.vala index c9e7fd54..07f45bd7 100644 --- a/src/engine/api/EmailOrdering.vala +++ b/src/engine/api/EmailLocation.vala @@ -4,11 +4,11 @@ * (version 2.1 or later). See the COPYING file in this distribution. */ -public class Geary.EmailOrdering { - public int64 ordinal { get; private set; } +public class Geary.EmailLocation : Object { + public int position { get; private set; } - public EmailOrdering(int64 ordinal) { - this.ordinal = ordinal; + public EmailLocation(int position) { + this.position = position; } } diff --git a/src/engine/api/Folder.vala b/src/engine/api/Folder.vala index 7451676f..7e199bdb 100644 --- a/src/engine/api/Folder.vala +++ b/src/engine/api/Folder.vala @@ -15,6 +15,9 @@ public interface Geary.Folder : Object { public signal void closed(CloseReason reason); + public signal void email_added_removed(Gee.List? added, + Gee.List? removed); + public signal void updated(); public virtual void notify_opened() { @@ -25,6 +28,11 @@ public interface Geary.Folder : Object { closed(reason); } + public virtual void notify_email_added_removed(Gee.List? added, + Gee.List? removed) { + email_added_removed(added, removed); + } + public virtual void notify_updated() { updated(); } @@ -39,16 +47,25 @@ public interface Geary.Folder : Object { public abstract int get_message_count() throws Error; - public abstract async void create_email_async(Geary.Email email, Geary.EmailOrdering ordering, - Cancellable? cancellable = null) throws Error; + public abstract async void create_email_async(Geary.Email email, + Geary.Email.Field fields, Cancellable? cancellable = null) throws Error; /** * low is one-based. */ - public abstract async Gee.List list_email_async(int low, int count, + public abstract async Gee.List? list_email_async(int low, int count, Geary.Email.Field fields, Cancellable? cancellable = null) throws Error; - public abstract async Geary.Email fetch_email_async(int msg_num, Geary.Email.Field fields, + /** + * All positions are one-based. + */ + public abstract async Gee.List? list_email_sparse_async(int[] by_position, + Geary.Email.Field fields, Cancellable? cancellable = null) throws Error; + + /** + * position is one-based. + */ + public abstract async Geary.Email fetch_email_async(int position, Geary.Email.Field fields, Cancellable? cancellable = null) throws Error; } diff --git a/src/engine/imap/Mailbox.vala b/src/engine/imap/Mailbox.vala index 2676a0c6..450cc20f 100644 --- a/src/engine/imap/Mailbox.vala +++ b/src/engine/imap/Mailbox.vala @@ -30,7 +30,7 @@ public class Geary.Imap.Mailbox : Geary.SmartReference { uid_validity = context.uid_validity; } - public async Gee.List? list_async(int low, int count, Geary.Email.Field fields, + public async Gee.List? list_set_async(MessageSet msg_set, Geary.Email.Field fields, Cancellable? cancellable = null) throws Error { if (context.is_closed()) throw new ImapError.NOT_SELECTED("Mailbox %s closed", name); @@ -39,7 +39,7 @@ public class Geary.Imap.Mailbox : Geary.SmartReference { throw new EngineError.BAD_PARAMETERS("No email fields specify for list"); CommandResponse resp = yield context.session.send_command_async( - new FetchCommand(context.session.generate_tag(), new MessageSet.range(low, count), + new FetchCommand(context.session.generate_tag(), msg_set, fields_to_fetch_data_types(fields)), cancellable); if (resp.status_response.status != Status.OK) @@ -49,12 +49,13 @@ public class Geary.Imap.Mailbox : Geary.SmartReference { FetchResults[] results = FetchResults.decode(resp); foreach (FetchResults res in results) { - Geary.Email email = new Geary.Email(res.msg_num); + // TODO: Add UID + Geary.Email email = new Geary.Email(new Geary.Imap.EmailLocation(res.msg_num, 0)); fetch_results_to_email(res, fields, email); msgs.add(email); } - return msgs; + return (msgs != null && msgs.size > 0) ? msgs : null; } public async Geary.Email fetch_async(int msg_num, Geary.Email.Field fields, @@ -78,7 +79,8 @@ public class Geary.Imap.Mailbox : Geary.SmartReference { results[0].msg_num, msg_num); } - Geary.Email email = new Geary.Email(msg_num); + // TODO: Add UID + Geary.Email email = new Geary.Email(new Geary.Imap.EmailLocation(results[0].msg_num, 0)); fetch_results_to_email(results[0], fields, email); return email; diff --git a/src/engine/imap/MessageSet.vala b/src/engine/imap/MessageSet.vala index 22b05fd6..000094f1 100644 --- a/src/engine/imap/MessageSet.vala +++ b/src/engine/imap/MessageSet.vala @@ -28,12 +28,12 @@ public class Geary.Imap.MessageSet { value = "%d:*".printf(low_msg_num); } - public MessageSet.scattered(int[] msg_nums) { - value = build_scattered_range(msg_nums); + public MessageSet.sparse(int[] msg_nums) { + value = build_sparse_range(msg_nums); } - public MessageSet.scattered_to_highest(int[] msg_nums) { - value = "%s:*".printf(build_scattered_range(msg_nums)); + public MessageSet.sparse_to_highest(int[] msg_nums) { + value = "%s:*".printf(build_sparse_range(msg_nums)); } public MessageSet.multirange(MessageSet[] msg_sets) { @@ -50,7 +50,7 @@ public class Geary.Imap.MessageSet { value = builder.str; } - public MessageSet.multiscattered(MessageSet[] msg_sets) { + public MessageSet.multisparse(MessageSet[] msg_sets) { StringBuilder builder = new StringBuilder(); for (int ctr = 0; ctr < msg_sets.length; ctr++) { unowned MessageSet msg_set = msg_sets[ctr]; @@ -68,7 +68,9 @@ public class Geary.Imap.MessageSet { value = custom; } - private static string build_scattered_range(int[] msg_nums) { + // TODO: It would be more efficient to look for runs in the numbers and form the set specifier + // with them. + private static string build_sparse_range(int[] msg_nums) { assert(msg_nums.length > 0); StringBuilder builder = new StringBuilder(); diff --git a/src/engine/imap/api/EmailLocation.vala b/src/engine/imap/api/EmailLocation.vala new file mode 100644 index 00000000..35026078 --- /dev/null +++ b/src/engine/imap/api/EmailLocation.vala @@ -0,0 +1,16 @@ +/* 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. + */ + +private class Geary.Imap.EmailLocation : Geary.EmailLocation { + public int64 uid { get; private set; } + + public EmailLocation(int position, int64 uid) { + base (position); + + this.uid = uid; + } +} + diff --git a/src/engine/imap/api/Folder.vala b/src/engine/imap/api/Folder.vala index 2518897e..b5ec4d98 100644 --- a/src/engine/imap/api/Folder.vala +++ b/src/engine/imap/api/Folder.vala @@ -57,25 +57,33 @@ public class Geary.Imap.Folder : Object, Geary.Folder { return mailbox.count; } - public async void create_email_async(Geary.Email email, Geary.EmailOrdering ordring, + public async void create_email_async(Geary.Email email, Geary.Email.Field fields, Cancellable? cancellable = null) throws Error { throw new EngineError.READONLY("IMAP currently read-only"); } - public async Gee.List list_email_async(int low, int count, Geary.Email.Field fields, + public async Gee.List? list_email_async(int low, int count, Geary.Email.Field fields, Cancellable? cancellable = null) throws Error { if (mailbox == null) throw new EngineError.OPEN_REQUIRED("%s not opened", to_string()); - return yield mailbox.list_async(low, count, fields, cancellable); + return yield mailbox.list_set_async(new MessageSet.range(low, count), fields, cancellable); } - public async Geary.Email fetch_email_async(int msg_num, Geary.Email.Field fields, + public async Gee.List? list_email_sparse_async(int[] by_position, + Geary.Email.Field fields, Cancellable? cancellable = null) throws Error { + if (mailbox == null) + throw new EngineError.OPEN_REQUIRED("%s not opened", to_string()); + + return yield mailbox.list_set_async(new MessageSet.sparse(by_position), fields, cancellable); + } + + public async Geary.Email fetch_email_async(int position, Geary.Email.Field fields, Cancellable? cancellable = null) throws Error { if (mailbox == null) throw new EngineError.OPEN_REQUIRED("%s not opened", to_string()); - return yield mailbox.fetch_async(msg_num, fields, cancellable); + return yield mailbox.fetch_async(position, fields, cancellable); } public string to_string() { diff --git a/src/engine/imap/decoders/FetchDataDecoder.vala b/src/engine/imap/decoders/FetchDataDecoder.vala index 38b47351..43d93a78 100644 --- a/src/engine/imap/decoders/FetchDataDecoder.vala +++ b/src/engine/imap/decoders/FetchDataDecoder.vala @@ -138,7 +138,7 @@ public class Geary.Imap.EnvelopeDecoder : Geary.Imap.FetchDataDecoder { StringParameter mailbox = fields.get_as_string(2); StringParameter domain = fields.get_as_string(3); - Geary.RFC822.MailboxAddress addr = new Geary.RFC822.MailboxAddress( + Geary.RFC822.MailboxAddress addr = new Geary.RFC822.MailboxAddress.imap( (name != null) ? name.nullable_value : null, (source_route != null) ? source_route.nullable_value : null, mailbox.value, diff --git a/src/engine/rfc822/MailboxAddress.vala b/src/engine/rfc822/MailboxAddress.vala index 07af5d98..e14218bb 100644 --- a/src/engine/rfc822/MailboxAddress.vala +++ b/src/engine/rfc822/MailboxAddress.vala @@ -11,7 +11,20 @@ public class Geary.RFC822.MailboxAddress { public string domain { get; private set; } public string address { get; private set; } - public MailboxAddress(string? name, string? source_route, string mailbox, string domain) { + public MailboxAddress(string? name, string address) { + this.name = name; + this.address = address; + + source_route = null; + + int atsign = address.index_of_char('@'); + if (atsign > 0) { + mailbox = address.slice(0, atsign); + domain = address.slice(atsign + 1, address.length); + } + } + + public MailboxAddress.imap(string? name, string? source_route, string mailbox, string domain) { this.name = name; this.source_route = source_route; this.mailbox = mailbox; @@ -36,6 +49,10 @@ public class Geary.RFC822.MailboxAddress { return name ?? mailbox; } + public string to_rfc822_string() { + return get_full_address(); + } + public string to_string() { return get_full_address(); } diff --git a/src/engine/rfc822/MailboxAddresses.vala b/src/engine/rfc822/MailboxAddresses.vala new file mode 100644 index 00000000..ee41b319 --- /dev/null +++ b/src/engine/rfc822/MailboxAddresses.vala @@ -0,0 +1,85 @@ +/* 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. + */ + +public class Geary.RFC822.MailboxAddresses : Geary.Common.MessageData, Geary.RFC822.MessageData { + public int size { get { return addrs.size; } } + + private Gee.List addrs = new Gee.ArrayList(); + + public MailboxAddresses(Gee.Collection addrs) { + this.addrs.add_all(addrs); + } + + public MailboxAddresses.from_rfc822_string(string rfc822) { + InternetAddressList addrlist = InternetAddressList.parse_string(rfc822); + int length = addrlist.length(); + for (int ctr = 0; ctr < length; ctr++) { + InternetAddress? addr = addrlist.get_address(ctr); + + // TODO: Handle group lists + InternetAddressMailbox? mbox_addr = addr as InternetAddressMailbox; + if (mbox_addr == null) + continue; + + addrs.add(new MailboxAddress(mbox_addr.get_name(), mbox_addr.get_addr())); + } + } + + public MailboxAddress? get(int index) { + return addrs.get(index); + } + + public Gee.Iterator iterator() { + return addrs.iterator(); + } + + public Gee.List get_all() { + return addrs.read_only_view; + } + + public string to_rfc822_string() { + switch (addrs.size) { + case 0: + return ""; + + case 1: + return addrs[0].to_rfc822_string(); + + default: + StringBuilder builder = new StringBuilder(); + foreach (MailboxAddress addr in addrs) { + if (!String.is_empty(builder.str)) + builder.append(", "); + + builder.append(addr.to_rfc822_string()); + } + + return builder.str; + } + } + + public override string to_string() { + switch (addrs.size) { + case 0: + return "(no addresses)"; + + case 1: + return addrs[0].to_string(); + + default: + StringBuilder builder = new StringBuilder(); + foreach (MailboxAddress addr in addrs) { + if (!String.is_empty(builder.str)) + builder.append(", "); + + builder.append(addr.to_string()); + } + + return builder.str; + } + } +} + diff --git a/src/engine/rfc822/MessageData.vala b/src/engine/rfc822/MessageData.vala index d4fae919..56ffac34 100644 --- a/src/engine/rfc822/MessageData.vala +++ b/src/engine/rfc822/MessageData.vala @@ -50,49 +50,6 @@ public class Geary.RFC822.Subject : Geary.Common.StringMessageData, Geary.RFC822 } } -public class Geary.RFC822.MailboxAddresses : Geary.Common.MessageData, Geary.RFC822.MessageData { - public int size { get { return addrs.size; } } - - private Gee.List addrs = new Gee.ArrayList(); - - public MailboxAddresses(Gee.Collection addrs) { - this.addrs.add_all(addrs); - } - - public MailboxAddress? get(int index) { - return addrs.get(index); - } - - public Gee.Iterator iterator() { - return addrs.iterator(); - } - - public Gee.List get_all() { - return addrs.read_only_view; - } - - public override string to_string() { - switch (addrs.size) { - case 0: - return "(no addresses)"; - - case 1: - return addrs[0].to_string(); - - default: - StringBuilder builder = new StringBuilder(); - foreach (MailboxAddress addr in addrs) { - if (!String.is_empty(builder.str)) - builder.append(", "); - - builder.append(addr.to_string()); - } - - return builder.str; - } - } -} - public class Geary.RFC822.Header : Geary.Common.BlockMessageData, Geary.RFC822.MessageData { public Header(Geary.Memory.AbstractBuffer buffer) { base ("RFC822.Header", buffer); diff --git a/src/engine/sqlite/ImapMessageLocationPropertiesRow.vala b/src/engine/sqlite/ImapMessageLocationPropertiesRow.vala new file mode 100644 index 00000000..39c22bf2 --- /dev/null +++ b/src/engine/sqlite/ImapMessageLocationPropertiesRow.vala @@ -0,0 +1,21 @@ +/* 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. + */ + +public class Geary.Sqlite.ImapMessageLocationPropertiesRow : Geary.Sqlite.Row { + public int64 id { get; private set; } + public int64 location_id { get; private set; } + public int64 uid { get; private set; } + + public ImapMessageLocationPropertiesRow(ImapMessageLocationPropertiesTable table, int64 id, + int64 location_id, int64 uid) { + base (table); + + this.id = id; + this.location_id = location_id; + this.uid = uid; + } +} + diff --git a/src/engine/sqlite/ImapMessageLocationPropertiesTable.vala b/src/engine/sqlite/ImapMessageLocationPropertiesTable.vala new file mode 100644 index 00000000..1cf2477f --- /dev/null +++ b/src/engine/sqlite/ImapMessageLocationPropertiesTable.vala @@ -0,0 +1,43 @@ +/* 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. + */ + +public class Geary.Sqlite.ImapMessageLocationPropertiesTable : Geary.Sqlite.Table { + // This *must* be in the same order as the schema. + public enum Column { + ID, + LOCATION_ID, + UID + } + + public ImapMessageLocationPropertiesTable(Geary.Sqlite.Database gdb, SQLHeavy.Table table) { + base (gdb, table); + } + + public async int64 create_async(ImapMessageLocationPropertiesRow row, + Cancellable? cancellable = null) throws Error { + SQLHeavy.Query query = db.prepare( + "INSERT INTO ImapMessageLocationPropertiesTable (location_id, uid) VALUES (?, ?)"); + query.bind_int64(0, row.location_id); + query.bind_int64(1, row.uid); + + return yield query.execute_insert_async(cancellable); + } + + public async ImapMessageLocationPropertiesRow? fetch_async(int64 location_id, + Cancellable? cancellable = null) throws Error { + SQLHeavy.Query query = db.prepare( + "SELECT id, uid FROM ImapMessageLocationPropertiesTable WHERE location_id = ?"); + query.bind_int64(0, location_id); + + SQLHeavy.QueryResult result = yield query.execute_async(cancellable); + if (result.finished) + return null; + + return new ImapMessageLocationPropertiesRow(this, result.fetch_int64(0), location_id, + result.fetch_int64(1)); + } +} + diff --git a/src/engine/sqlite/MailDatabase.vala b/src/engine/sqlite/MailDatabase.vala index 028c3f64..cae638eb 100644 --- a/src/engine/sqlite/MailDatabase.vala +++ b/src/engine/sqlite/MailDatabase.vala @@ -39,5 +39,15 @@ public class Geary.Sqlite.MailDatabase : Geary.Sqlite.Database { ? location_table : (MessageLocationTable) add_table(new MessageLocationTable(this, heavy_table)); } + + public Geary.Sqlite.ImapMessageLocationPropertiesTable get_imap_message_location_table() { + SQLHeavy.Table heavy_table; + ImapMessageLocationPropertiesTable? imap_location_table = get_table( + "ImapMessageLocationPropertiesTable", out heavy_table) as ImapMessageLocationPropertiesTable; + + return (imap_location_table != null) + ? imap_location_table + : (ImapMessageLocationPropertiesTable) add_table(new ImapMessageLocationPropertiesTable(this, heavy_table)); + } } diff --git a/src/engine/sqlite/MessageLocationRow.vala b/src/engine/sqlite/MessageLocationRow.vala index a6bda62f..7815aafc 100644 --- a/src/engine/sqlite/MessageLocationRow.vala +++ b/src/engine/sqlite/MessageLocationRow.vala @@ -8,16 +8,16 @@ public class Geary.Sqlite.MessageLocationRow : Geary.Sqlite.Row { public int64 id { get; private set; } public int64 message_id { get; private set; } public int64 folder_id { get; private set; } - public int64 ordering { get; private set; } + public int position { get; private set; } public MessageLocationRow(MessageLocationTable table, int64 id, int64 message_id, int64 folder_id, - int64 ordering) { + int position) { base (table); this.id = id; this.message_id = message_id; this.folder_id = folder_id; - this.ordering = ordering; + this.position = position; } public MessageLocationRow.from_query_result(MessageLocationTable table, @@ -27,7 +27,7 @@ public class Geary.Sqlite.MessageLocationRow : Geary.Sqlite.Row { id = fetch_int64_for(result, MessageLocationTable.Column.ID); message_id = fetch_int64_for(result, MessageLocationTable.Column.MESSAGE_ID); folder_id = fetch_int64_for(result, MessageLocationTable.Column.FOLDER_ID); - ordering = fetch_int64_for(result, MessageLocationTable.Column.ORDERING); + position = fetch_int_for(result, MessageLocationTable.Column.POSITION); } } diff --git a/src/engine/sqlite/MessageLocationTable.vala b/src/engine/sqlite/MessageLocationTable.vala index bdc09d99..dbb7259c 100644 --- a/src/engine/sqlite/MessageLocationTable.vala +++ b/src/engine/sqlite/MessageLocationTable.vala @@ -10,7 +10,7 @@ public class Geary.Sqlite.MessageLocationTable : Geary.Sqlite.Table { ID, MESSAGE_ID, FOLDER_ID, - ORDERING + POSITION } public MessageLocationTable(Geary.Sqlite.Database db, SQLHeavy.Table table) { @@ -20,27 +20,27 @@ public class Geary.Sqlite.MessageLocationTable : Geary.Sqlite.Table { public async int64 create_async(MessageLocationRow row, Cancellable? cancellable = null) throws Error { SQLHeavy.Query query = db.prepare( - "INSERT INTO MessageLocationTable (message_id, folder_id, ordering) VALUES (?, ?, ?)"); + "INSERT INTO MessageLocationTable (message_id, folder_id, position) VALUES (?, ?, ?)"); query.bind_int64(0, row.message_id); query.bind_int64(1, row.folder_id); - query.bind_int64(2, row.ordering); + query.bind_int(2, row.position); return yield query.execute_insert_async(cancellable); } /** - * low is zero-based. + * low is one-based. */ public async Gee.List? list_async(int64 folder_id, int low, int count, Cancellable? cancellable = null) throws Error { - assert(low >= 0); + assert(low >= 1); SQLHeavy.Query query = db.prepare( - "SELECT id, message_id, ordering FROM MessageLocationTable WHERE folder_id = ? " - + "LIMIT ? OFFSET ? ORDER BY ordering"); + "SELECT id, message_id, position FROM MessageLocationTable WHERE folder_id = ? " + + "ORDER BY position LIMIT ? OFFSET ?"); query.bind_int64(0, folder_id); query.bind_int(1, count); - query.bind_int(2, low); + query.bind_int(2, low - 1); SQLHeavy.QueryResult results = yield query.execute_async(cancellable); if (results.finished) @@ -49,7 +49,7 @@ public class Geary.Sqlite.MessageLocationTable : Geary.Sqlite.Table { Gee.List list = new Gee.ArrayList(); do { list.add(new MessageLocationRow(this, results.fetch_int64(0), results.fetch_int64(1), - folder_id, results.fetch_int64(2))); + folder_id, results.fetch_int(2))); yield results.next_async(cancellable); } while (!results.finished); @@ -57,24 +57,60 @@ public class Geary.Sqlite.MessageLocationTable : Geary.Sqlite.Table { } /** - * num is zero-based. + * All positions are one-based. */ - public async MessageLocationRow? fetch_async(int64 folder_id, int num, + public async Gee.List? list_sparse_async(int64 folder_id, int[] by_position, Cancellable? cancellable = null) throws Error { - assert(num >= 0); + // build a vector for the IN expression + StringBuilder vector = new StringBuilder("("); + for (int ctr = 0; ctr < by_position.length; ctr++) { + assert(by_position[ctr] >= 1); + + if (ctr < (by_position.length - 1)) + vector.append_printf("%d, ", by_position[ctr]); + else + vector.append_printf("%d", by_position[ctr]); + } + vector.append(")"); SQLHeavy.Query query = db.prepare( - "SELECT id, message_id, ordering FROM MessageLocationTable WHERE folder_id = ? " - + "LIMIT 1 OFFSET ? ORDER BY ordering"); + "SELECT id, message_id, position FROM MessageLocationTable WHERE folder_id = ? AND position IN ?"); query.bind_int64(0, folder_id); - query.bind_int64(1, num); + query.bind_string(1, vector.str); + + SQLHeavy.QueryResult results = yield query.execute_async(cancellable); + if (results.finished) + return null; + + Gee.List list = new Gee.ArrayList(); + do { + list.add(new MessageLocationRow(this, results.fetch_int64(0), results.fetch_int64(1), + folder_id, results.fetch_int(2))); + yield results.next_async(cancellable); + } while (!results.finished); + + return list; + } + + /** + * position is one-based. + */ + public async MessageLocationRow? fetch_async(int64 folder_id, int position, + Cancellable? cancellable = null) throws Error { + assert(position >= 1); + + SQLHeavy.Query query = db.prepare( + "SELECT id, message_id, position FROM MessageLocationTable WHERE folder_id = ? " + + "AND position = ?"); + query.bind_int64(0, folder_id); + query.bind_int64(1, position); SQLHeavy.QueryResult results = yield query.execute_async(cancellable); if (results.finished) return null; return new MessageLocationRow(this, results.fetch_int64(0), results.fetch_int64(1), folder_id, - results.fetch_int64(2)); + results.fetch_int(2)); } } diff --git a/src/engine/sqlite/MessageRow.vala b/src/engine/sqlite/MessageRow.vala index 17d9c967..660db35c 100644 --- a/src/engine/sqlite/MessageRow.vala +++ b/src/engine/sqlite/MessageRow.vala @@ -93,8 +93,8 @@ public class Geary.Sqlite.MessageRow : Geary.Sqlite.Row { body = fetch_string_for(result, MessageTable.Column.BODY); } - public Geary.Email to_email(int msg_num) throws Error { - Geary.Email email = new Geary.Email(msg_num); + public Geary.Email to_email(Geary.EmailLocation location) throws Error { + Geary.Email email = new Geary.Email(location); email.date = (date != null) ? new RFC822.Date(date) : null; @@ -145,10 +145,7 @@ public class Geary.Sqlite.MessageRow : Geary.Sqlite.Row { } public RFC822.MailboxAddresses? unflatten_addresses(string? str) { - if (str == null) - return null; - - return null; + return String.is_empty(str) ? null : new RFC822.MailboxAddresses.from_rfc822_string(str); } } diff --git a/src/engine/sqlite/MessageTable.vala b/src/engine/sqlite/MessageTable.vala index 49a771b9..f561e954 100644 --- a/src/engine/sqlite/MessageTable.vala +++ b/src/engine/sqlite/MessageTable.vala @@ -82,7 +82,7 @@ public class Geary.Sqlite.MessageTable : Geary.Sqlite.Table { assert(fields != Geary.Email.Field.NONE); SQLHeavy.Query query = db.prepare( - "SELECT %s FROM MessageTable WHERE id = ?".printf(fields_to_columns(fields))); + "SELECT id, %s FROM MessageTable WHERE id = ?".printf(fields_to_columns(fields))); query.bind_int64(0, id); SQLHeavy.QueryResult results = yield query.execute_async(cancellable); @@ -90,7 +90,6 @@ public class Geary.Sqlite.MessageTable : Geary.Sqlite.Table { return null; MessageRow row = new MessageRow.from_query_result(this, fields, results); - row.id = id; return row; } @@ -99,34 +98,36 @@ public class Geary.Sqlite.MessageTable : Geary.Sqlite.Table { StringBuilder builder = new StringBuilder(); foreach (Geary.Email.Field field in Geary.Email.Field.all()) { string? append = null; - switch (field) { - case Geary.Email.Field.DATE: - append = "date_field, date_time_t"; - break; - - case Geary.Email.Field.ORIGINATORS: - append = "from_field, sender, reply_to"; - break; - - case Geary.Email.Field.RECEIVERS: - append = "to_field, cc, bcc"; - break; - - case Geary.Email.Field.REFERENCES: - append = "message_id, in_reply_to"; - break; - - case Geary.Email.Field.SUBJECT: - append = "subject"; - break; - - case Geary.Email.Field.HEADER: - append = "header"; - break; - - case Geary.Email.Field.BODY: - append = "body"; - break; + if ((fields & field) != 0) { + switch (field) { + case Geary.Email.Field.DATE: + append = "date_field, date_time_t"; + break; + + case Geary.Email.Field.ORIGINATORS: + append = "from_field, sender, reply_to"; + break; + + case Geary.Email.Field.RECEIVERS: + append = "to_field, cc, bcc"; + break; + + case Geary.Email.Field.REFERENCES: + append = "message_id, in_reply_to"; + break; + + case Geary.Email.Field.SUBJECT: + append = "subject"; + break; + + case Geary.Email.Field.HEADER: + append = "header"; + break; + + case Geary.Email.Field.BODY: + append = "body"; + break; + } } if (append != null) { diff --git a/src/engine/sqlite/api/Folder.vala b/src/engine/sqlite/api/Folder.vala index 5f607251..38d9eda8 100644 --- a/src/engine/sqlite/api/Folder.vala +++ b/src/engine/sqlite/api/Folder.vala @@ -9,6 +9,7 @@ public class Geary.Sqlite.Folder : Object, Geary.Folder { private FolderRow folder_row; private MessageTable message_table; private MessageLocationTable location_table; + private ImapMessageLocationPropertiesTable imap_location_table; private string name; internal Folder(MailDatabase db, FolderRow folder_row) throws Error { @@ -19,6 +20,7 @@ public class Geary.Sqlite.Folder : Object, Geary.Folder { message_table = db.get_message_table(); location_table = db.get_message_location_table(); + imap_location_table = db.get_imap_message_location_table(); } public string get_name() { @@ -39,57 +41,93 @@ public class Geary.Sqlite.Folder : Object, Geary.Folder { return 0; } - public async void create_email_async(Geary.Email email, Geary.EmailOrdering ordering, + public async void create_email_async(Geary.Email email, Geary.Email.Field fields, Cancellable? cancellable = null) throws Error { int64 message_id = yield message_table.create_async( new MessageRow.from_email(message_table, email), cancellable); + Geary.Imap.EmailLocation location = (Geary.Imap.EmailLocation) email.location; + MessageLocationRow location_row = new MessageLocationRow(location_table, Row.INVALID_ID, - message_id, folder_row.id, ordering.ordinal); - yield location_table.create_async(location_row, cancellable); + message_id, folder_row.id, location.position); + int64 location_id = yield location_table.create_async(location_row, cancellable); + + ImapMessageLocationPropertiesRow imap_location_row = new ImapMessageLocationPropertiesRow( + imap_location_table, Row.INVALID_ID, location_id, location.uid); + yield imap_location_table.create_async(imap_location_row, cancellable); } - public async Gee.List list_email_async(int low, int count, Geary.Email.Field fields, + public async Gee.List? list_email_async(int low, int count, Geary.Email.Field fields, Cancellable? cancellable) throws Error { assert(low >= 1); assert(count >= 1); // low is zero-based in the database. - Gee.List? list = yield location_table.list_async(folder_row.id, low - 1, + Gee.List? list = yield location_table.list_async(folder_row.id, low, count, cancellable); + + return yield list_email(list, fields, cancellable); + } + + public async Gee.List? list_email_sparse_async(int[] by_position, + Geary.Email.Field fields, Cancellable? cancellable = null) throws Error { + Gee.List? list = yield location_table.list_sparse_async(folder_row.id, + by_position, cancellable); + + return yield list_email(list, fields, cancellable); + } + + private async Gee.List? list_email(Gee.List? list, + Geary.Email.Field fields, Cancellable? cancellable) throws Error { if (list == null || list.size == 0) - throw new EngineError.NOT_FOUND("No messages found at position %d in %s", low, name); + return null; Gee.List emails = new Gee.ArrayList(); - int msg_num = 1; foreach (MessageLocationRow location_row in list) { + ImapMessageLocationPropertiesRow? imap_location_row = yield imap_location_table.fetch_async( + location_row.id, cancellable); + assert(imap_location_row != null); + MessageRow? message_row = yield message_table.fetch_async(location_row.message_id, fields, cancellable); assert(message_row != null); - emails.add(message_row.to_email(msg_num++)); + emails.add(message_row.to_email(new Geary.Imap.EmailLocation(location_row.position, + imap_location_row.uid))); } return (emails.size > 0) ? emails : null; } - public async Geary.Email fetch_email_async(int num, Geary.Email.Field fields, + public async Geary.Email fetch_email_async(int position, Geary.Email.Field fields, Cancellable? cancellable = null) throws Error { - assert(num >= 0); + assert(position >= 1); // num is zero-based in the database. - MessageLocationRow? location_row = yield location_table.fetch_async(folder_row.id, num - 1, + MessageLocationRow? location_row = yield location_table.fetch_async(folder_row.id, position, cancellable); if (location_row == null) - throw new EngineError.NOT_FOUND("No message number %s in folder %s", num, name); + throw new EngineError.NOT_FOUND("No message at position %d in folder %s", position, name); + + assert(location_row.position == position); + + ImapMessageLocationPropertiesRow? imap_location_row = yield imap_location_table.fetch_async( + location_row.id, cancellable); + if (imap_location_row == null) { + throw new EngineError.NOT_FOUND("No IMAP location properties at position %d in %s", + position, name); + } + + assert(imap_location_row.location_id == location_row.id); MessageRow? message_row = yield message_table.fetch_async(location_row.message_id, fields, cancellable); if (message_row == null) - throw new EngineError.NOT_FOUND("No message number %s in folde %s", num, name); + throw new EngineError.NOT_FOUND("No message at position %d in folder %s", position, name); - return message_row.to_email(num); + return message_row.to_email(new Geary.Imap.EmailLocation(location_row.position, + imap_location_row.uid)); } } diff --git a/vapi/gmime-2.4.vapi b/vapi/gmime-2.4.vapi index 8f951bd2..12c71a34 100644 --- a/vapi/gmime-2.4.vapi +++ b/vapi/gmime-2.4.vapi @@ -299,80 +299,12 @@ namespace GMime { public ssize_t write_to_stream (GMime.Stream stream); } [CCode (cheader_filename = "gmime/gmime.h")] - public class InternetAddress : GLib.Object { - public weak string name; - [CCode (has_construct_function = false)] - protected InternetAddress (); - [CCode (cname = "internet_address_get_name")] - public unowned string get_name (); - [CCode (cname = "internet_address_set_name")] - public void set_name (string name); - [CCode (cname = "internet_address_to_string")] - public virtual string to_string (bool encoded); - } - [CCode (cheader_filename = "gmime/gmime.h")] - public class InternetAddressGroup : GMime.InternetAddress { - public weak GMime.InternetAddressList members; - [CCode (cname = "internet_address_group_new")] - public InternetAddressGroup (string name); - [CCode (cname = "internet_address_group_add_member")] - public int add_member (GMime.InternetAddress member); - [CCode (cname = "internet_address_group_get_members")] - public GMime.InternetAddressList get_members (); - [CCode (cname = "internet_address_group_set_members")] - public void set_members (GMime.InternetAddressList members); - } - [CCode (cheader_filename = "gmime/gmime.h")] - public class InternetAddressList : GLib.Object { - public weak GLib.GenericArray array; - [CCode (cname = "internet_address_list_new")] - public InternetAddressList (); - [CCode (cname = "internet_address_list_add")] - public int add (GMime.InternetAddress addr); - [CCode (cname = "internet_address_list_append")] - public void append (GMime.InternetAddressList append); - [CCode (cname = "internet_address_list_clear")] - public void clear (); - [CCode (cname = "internet_address_list_contains")] - public bool contains (GMime.InternetAddress addr); - [CCode (cname = "internet_address_list_get_address")] - public GMime.InternetAddress get_address (int index); - [CCode (cname = "internet_address_list_index_of")] - public int index_of (GMime.InternetAddress addr); - [CCode (cname = "internet_address_list_insert")] - public void insert (int index, GMime.InternetAddress addr); - [CCode (cname = "internet_address_list_length")] - public int length (); - [CCode (cname = "internet_address_list_parse_string")] - public static GMime.InternetAddressList parse_string (string str); - [CCode (cname = "internet_address_list_prepend")] - public void prepend (GMime.InternetAddressList prepend); - [CCode (cname = "internet_address_list_remove")] - public bool remove (GMime.InternetAddress addr); - [CCode (cname = "internet_address_list_remove_at")] - public bool remove_at (int index); - [CCode (cname = "internet_address_list_set_address")] - public void set_address (int index, GMime.InternetAddress addr); - [CCode (cname = "internet_address_list_to_string")] - public string to_string (bool encode); - } - [CCode (cheader_filename = "gmime/gmime.h")] - public class InternetAddressMailbox : GMime.InternetAddress { - public weak string addr; - [CCode (cname = "internet_address_mailbox_new")] - public InternetAddressMailbox (string name, string addr); - [CCode (cname = "internet_address_mailbox_get_addr")] - public string get_addr (); - [CCode (cname = "internet_address_mailbox_set_addr")] - public void set_addr (string addr); - } - [CCode (cheader_filename = "gmime/gmime.h")] public class Message : GMime.Object { public ulong date; public weak string from; public weak string message_id; public weak GMime.Object mime_part; - public weak GMime.InternetAddressList recipients; + public weak InternetAddressList recipients; public weak string reply_to; public weak string subject; public int tz_offset; @@ -380,12 +312,12 @@ namespace GMime { public Message (bool pretty_headers); public void add_recipient (GMime.RecipientType type, string name, string addr); public void @foreach (GMime.ObjectForeachFunc callback); - public unowned GMime.InternetAddressList get_all_recipients (); + public unowned InternetAddressList get_all_recipients (); public void get_date (out ulong date, out int tz_offset); public unowned string get_date_as_string (); public unowned string get_message_id (); public unowned GMime.Object get_mime_part (); - public unowned GMime.InternetAddressList get_recipients (GMime.RecipientType type); + public unowned InternetAddressList get_recipients (GMime.RecipientType type); public unowned string get_reply_to (); public unowned string get_sender (); public unowned string get_subject (); @@ -1010,3 +942,40 @@ namespace GMime { [CCode (cheader_filename = "gmime/gmime.h")] public static size_t yencode_step (uint inbuf, size_t inlen, uint outbuf, int state, uint32 pcrc, uint32 crc); } +[CCode (type_check_function = "IS_INTERNET_ADDRESS", type_id = "INTERNET_ADDRESS", cheader_filename = "gmime/gmime.h")] +public class InternetAddress : GLib.Object { + public unowned string? get_name (); + public void set_name (string? name); + public virtual string to_string (bool encoded); +} +[CCode (type_check_function = "INTERNET_ADDRESS_IS_GROUP", type_id = "INTERNET_ADDRESS_GROUP", cheader_filename = "gmime/gmime.h")] +public class InternetAddressGroup : InternetAddress { + public InternetAddressGroup (string name); + public int add_member (InternetAddress member); + public InternetAddressList get_members (); + public void set_members (InternetAddressList members); +} +[CCode (type_check_function = "INTERNET_ADDRESS_IS_MAILBOX", type_id = "INTERNET_ADDRESS_MAILBOX", cheader_filename = "gmime/gmime.h")] +public class InternetAddressMailbox : InternetAddress { + public InternetAddressMailbox (string? name, string addr); + public unowned string get_addr (); + public void set_addr (string addr); +} +[CCode (type_check_function = "IS_INTERNET_ADDRESS_LIST", type_id = "INTERNET_ADDRESS_LIST", cheader_filename = "gmime/gmime.h")] +public class InternetAddressList : GLib.Object { + public InternetAddressList (); + public int add (InternetAddress addr); + public void append (InternetAddressList append); + public void clear (); + public bool contains (InternetAddress addr); + public unowned InternetAddress get_address (int index); + public int index_of (InternetAddress addr); + public void insert (int index, InternetAddress addr); + public int length (); + public static InternetAddressList? parse_string (string str); + public void prepend (InternetAddressList prepend); + public bool remove (InternetAddress addr); + public bool remove_at (int index); + public void set_address (int index, InternetAddress addr); + public string? to_string (bool encode); +} diff --git a/vapi/gmime-2.4/gmime-2.4-custom.vala b/vapi/gmime-2.4/gmime-2.4-custom.vala index 27a2a897..322cfd2b 100644 --- a/vapi/gmime-2.4/gmime-2.4-custom.vala +++ b/vapi/gmime-2.4/gmime-2.4-custom.vala @@ -4,67 +4,69 @@ * (version 2.1 or later). See the COPYING file in this distribution. */ -namespace GMime { - public class InternetAddress { - [CCode (cname="internet_address_get_name")] - public unowned string get_name(); - [CCode (cname="internet_address_set_name")] - public void set_name(string name); - [CCode (cname="internet_address_to_string")] - public virtual string to_string(bool encoded); - } - - public class InternetAddressGroup { - [CCode (cname="internet_address_group_new")] - public InternetAddressGroup(string name); - [CCode (cname="internet_address_group_get_members")] - public InternetAddressList get_members(); - [CCode (cname="internet_address_group_set_members")] - public void set_members(InternetAddressList members); - [CCode (cname="internet_address_group_add_member")] - public int add_member(InternetAddress member); - } - - public class InternetAddressMailbox { - [CCode (cname="internet_address_mailbox_new")] - public InternetAddressMailbox(string name, string addr); - [CCode (cname="internet_address_mailbox_get_addr")] - public string get_addr(); - [CCode (cname="internet_address_mailbox_set_addr")] - public void set_addr(string addr); - } - - public class InternetAddressList { - [CCode (cname="internet_address_list_new")] - public InternetAddressList(); - [CCode (cname="internet_address_list_length")] - public int length(); - [CCode (cname="internet_address_list_clear")] - public void clear(); - [CCode (cname="internet_address_list_add")] - public int add(InternetAddress addr); - [CCode (cname="internet_address_list_insert")] - public void insert(int index, InternetAddress addr); - [CCode (cname="internet_address_list_remove")] - public bool remove(InternetAddress addr); - [CCode (cname="internet_address_list_remove_at")] - public bool remove_at(int index); - [CCode (cname="internet_address_list_contains")] - public bool contains(InternetAddress addr); - [CCode (cname="internet_address_list_index_of")] - public int index_of(InternetAddress addr); - [CCode (cname="internet_address_list_get_address")] - public InternetAddress get_address(int index); - [CCode (cname="internet_address_list_set_address")] - public void set_address(int index, InternetAddress addr); - [CCode (cname="internet_address_list_prepend")] - public void prepend(InternetAddressList prepend); - [CCode (cname="internet_address_list_append")] - public void append(InternetAddressList append); - [CCode (cname="internet_address_list_to_string")] - public string to_string(bool encode); - [CCode (cname="internet_address_list_parse_string")] - public static InternetAddressList parse_string(string str); - } +[CCode (cname="InternetAddress", cheader_filename="gmime/gmime.h", type_id="INTERNET_ADDRESS", type_check_function="IS_INTERNET_ADDRESS")] +public class InternetAddress : GLib.Object { + [CCode (cname="internet_address_get_name")] + public unowned string? get_name(); + [CCode (cname="internet_address_set_name")] + public void set_name(string? name); + [CCode (cname="internet_address_to_string")] + public virtual string to_string(bool encoded); +} + +[CCode (cname="InternetAddressGroup", cheader_filename="gmime/gmime.h", type_id="INTERNET_ADDRESS_GROUP", type_check_function="INTERNET_ADDRESS_IS_GROUP")] +public class InternetAddressGroup : InternetAddress { + [CCode (cname="internet_address_group_new")] + public InternetAddressGroup(string name); + [CCode (cname="internet_address_group_get_members")] + public InternetAddressList get_members(); + [CCode (cname="internet_address_group_set_members")] + public void set_members(InternetAddressList members); + [CCode (cname="internet_address_group_add_member")] + public int add_member(InternetAddress member); +} + +[CCode (cname="InternetAddressMailbox", cheader_filename="gmime/gmime.h", type_id="INTERNET_ADDRESS_MAILBOX", type_check_function="INTERNET_ADDRESS_IS_MAILBOX")] +public class InternetAddressMailbox : InternetAddress { + [CCode (cname="internet_address_mailbox_new")] + public InternetAddressMailbox(string? name, string addr); + [CCode (cname="internet_address_mailbox_get_addr")] + public unowned string get_addr(); + [CCode (cname="internet_address_mailbox_set_addr")] + public void set_addr(string addr); +} + +[CCode (cname="InternetAddressList", cheader_filename="gmime/gmime.h", type_id="INTERNET_ADDRESS_LIST", type_check_function="IS_INTERNET_ADDRESS_LIST")] +public class InternetAddressList : GLib.Object { + [CCode (cname="internet_address_list_new")] + public InternetAddressList(); + [CCode (cname="internet_address_list_length")] + public int length(); + [CCode (cname="internet_address_list_clear")] + public void clear(); + [CCode (cname="internet_address_list_add")] + public int add(InternetAddress addr); + [CCode (cname="internet_address_list_insert")] + public void insert(int index, InternetAddress addr); + [CCode (cname="internet_address_list_remove")] + public bool remove(InternetAddress addr); + [CCode (cname="internet_address_list_remove_at")] + public bool remove_at(int index); + [CCode (cname="internet_address_list_contains")] + public bool contains(InternetAddress addr); + [CCode (cname="internet_address_list_index_of")] + public int index_of(InternetAddress addr); + [CCode (cname="internet_address_list_get_address")] + public unowned InternetAddress get_address(int index); + [CCode (cname="internet_address_list_set_address")] + public void set_address(int index, InternetAddress addr); + [CCode (cname="internet_address_list_prepend")] + public void prepend(InternetAddressList prepend); + [CCode (cname="internet_address_list_append")] + public void append(InternetAddressList append); + [CCode (cname="internet_address_list_to_string")] + public string? to_string(bool encode); + [CCode (cname="internet_address_list_parse_string")] + public static InternetAddressList? parse_string(string str); } diff --git a/vapi/gmime-2.4/gmime-2.4.metadata b/vapi/gmime-2.4/gmime-2.4.metadata index a206a44e..2ae264c3 100644 --- a/vapi/gmime-2.4/gmime-2.4.metadata +++ b/vapi/gmime-2.4/gmime-2.4.metadata @@ -8,19 +8,19 @@ g_mime_signer_next name="get_next" g_mime_utils_header_decode_date type_name="time_t" g_mime_utils_header_decode_date.tz_offset is_out="1" nullable="1" -GMime.InternetAddress hidden="1" +InternetAddress hidden="1" internet_address_* hidden="1" -GMime.InternetAddress.name hidden="1" +InternetAddress.name hidden="1" -GMime.InternetAddressGroup hidden="1" +InternetAddressGroup hidden="1" internet_address_group_* hidden="1" -GMime.InternetAddressGroup.members hidden="1" +InternetAddressGroup.members hidden="1" -GMime.InternetAddressList hidden="1" +InternetAddressList hidden="1" internet_address_list_* hidden="1" -GMime.InternetAddressList.array hidden="1" +InternetAddressList.array hidden="1" -GMime.InternetAddressMailbox hidden="1" +InternetAddressMailbox hidden="1" internet_address_mailbox_* hidden="1" -GMime.InternetAddressMailbox.addr hidden="1" +InternetAddressMailbox.addr hidden="1"