[geary/wip/714922-multiple-addresses-2: 2/5] Rebase against master from mar-v-in
- From: Jim Nelson <jnelson src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/714922-multiple-addresses-2: 2/5] Rebase against master from mar-v-in
- Date: Tue, 10 Feb 2015 22:08:11 +0000 (UTC)
commit a0bdbc2b69eb0fac8cba634aec7beb113bb98b29
Author: Jim Nelson <jim yorba org>
Date: Fri Feb 6 12:30:25 2015 -0800
Rebase against master from mar-v-in
src/client/composer/composer-widget.vala | 147 ++++++++++++++------
.../conversation-list/conversation-list-store.vala | 4 +-
.../formatted-conversation-data.vala | 30 ++--
src/engine/api/geary-account-information.vala | 28 ++++-
src/engine/imap-db/outbox/smtp-outbox-folder.vala | 2 +-
src/engine/rfc822/rfc822-utils.vala | 33 +++--
6 files changed, 172 insertions(+), 72 deletions(-)
---
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
index 9626b2f..541e30a 100644
--- a/src/client/composer/composer-widget.vala
+++ b/src/client/composer/composer-widget.vala
@@ -26,6 +26,15 @@ public class ComposerWidget : Gtk.EventBox {
INLINE,
INLINE_COMPACT
}
+
+ private class FromAddressMap {
+ public Geary.Account account;
+ public string email;
+ public FromAddressMap(Geary.Account a, string e) {
+ account = a;
+ email = e;
+ }
+ }
public const string ACTION_UNDO = "undo";
public const string ACTION_REDO = "redo";
@@ -205,6 +214,7 @@ public class ComposerWidget : Gtk.EventBox {
private Gtk.Label from_label;
private Gtk.Label from_single;
private Gtk.ComboBoxText from_multiple = new Gtk.ComboBoxText();
+ private Gee.ArrayList<FromAddressMap> from_list = new Gee.ArrayList<FromAddressMap>();
private EmailEntry to_entry;
private EmailEntry cc_entry;
private Gtk.Label bcc_label;
@@ -236,6 +246,7 @@ public class ComposerWidget : Gtk.EventBox {
private bool action_flag = false;
private bool is_attachment_overlay_visible = false;
private Gee.List<Geary.Attachment>? pending_attachments = null;
+ private string? preferred_from_address = null;
private Geary.RFC822.MailboxAddresses reply_to_addresses;
private Geary.RFC822.MailboxAddresses reply_cc_addresses;
private string reply_subject = "";
@@ -427,7 +438,7 @@ public class ComposerWidget : Gtk.EventBox {
add_extra_accelerators();
- from = account.information.get_from().to_rfc822_string();
+ from = account.information.get_primary_from().to_rfc822_string();
update_from_field();
from_multiple.changed.connect(on_from_changed);
@@ -571,7 +582,7 @@ public class ComposerWidget : Gtk.EventBox {
chain.append(attachments_box);
box.set_focus_chain(chain);
- // If there's only one account, open the drafts manager. If there's more than one account,
+ // If there's only one From option, open the drafts manager. If there's more than one,
// the drafts manager will be opened by on_from_changed().
if (!from_multiple.visible)
open_draft_manager_async.begin(null);
@@ -702,6 +713,32 @@ public class ComposerWidget : Gtk.EventBox {
}
}
+ private bool check_preferred_from_address(Gee.List<string> account_addresses,
+ Geary.RFC822.MailboxAddresses? referred_addresses) {
+ if (referred_addresses != null) {
+ foreach (string address in account_addresses) {
+ if (referred_addresses.contains(address)) {
+ preferred_from_address = address;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private void set_preferred_from_address(Geary.Email referred, ComposeType compose_type) {
+ if (compose_type == ComposeType.NEW_MESSAGE) {
+ if (referred.from != null)
+ preferred_from_address = referred.from.to_rfc822_string();
+ } else {
+ Gee.List<string> account_addresses = account.information.get_all_email_addresses();
+ if (!check_preferred_from_address(account_addresses, referred.to)) {
+ if (!check_preferred_from_address(account_addresses, referred.cc))
+ check_preferred_from_address(account_addresses, referred.bcc);
+ }
+ }
+ }
+
private void on_load_finished(WebKit.WebFrame frame) {
if (get_realized())
on_load_finished_and_realized();
@@ -943,15 +980,16 @@ public class ComposerWidget : Gtk.EventBox {
private void add_recipients_and_ids(ComposeType type, Geary.Email referred,
bool modify_headers = true) {
- string? sender_address = account.information.get_mailbox_address().address;
+ Gee.List<string> sender_addresses = account.information.get_all_email_addresses();
Geary.RFC822.MailboxAddresses to_addresses =
- Geary.RFC822.Utils.create_to_addresses_for_reply(referred, sender_address);
+ Geary.RFC822.Utils.create_to_addresses_for_reply(referred, sender_addresses);
Geary.RFC822.MailboxAddresses cc_addresses =
- Geary.RFC822.Utils.create_cc_addresses_for_reply_all(referred, sender_address);
+ Geary.RFC822.Utils.create_cc_addresses_for_reply_all(referred, sender_addresses);
reply_to_addresses = Geary.RFC822.Utils.merge_addresses(reply_to_addresses, to_addresses);
reply_cc_addresses = Geary.RFC822.Utils.remove_addresses(
Geary.RFC822.Utils.merge_addresses(reply_cc_addresses, cc_addresses),
reply_to_addresses);
+ set_preferred_from_address(referred, type);
if (!modify_headers)
return;
@@ -2218,6 +2256,36 @@ public class ComposerWidget : Gtk.EventBox {
action_flag = false;
}
}
+
+ private void add_account_emails_to_from_list(Geary.Account account) {
+ from_multiple.append_text(account.information.get_primary_mailbox_address().to_rfc822_string());
+ from_list.add(new FromAddressMap(account, account.information.email));
+
+ bool set_active = false;
+ int index = 1; // We already inserted the main address.
+ if (account.information.alternate_emails != null) {
+ foreach (string alternate_email in account.information.alternate_emails) {
+ string rfc822_address = new Geary.RFC822.MailboxAddress(
+ account.information.real_name, alternate_email).to_rfc822_string();
+ // Displayed in the From dropdown to indicate an "alternate email address"
+ // for an account. The first printf argument will be the alternate email
+ // address, and the second will be the account's primary email address.
+ string display = _("%1$s via %2$s").printf(rfc822_address, account.information.email);
+ from_multiple.append_text(display);
+ from_list.add(new FromAddressMap(account, alternate_email));
+
+ if (!set_active && preferred_from_address == alternate_email) {
+ from_multiple.set_active(index);
+ set_active = true;
+ }
+
+ index++;
+ }
+ }
+
+ if (!set_active)
+ from_multiple.set_active(0);
+ }
private void update_from_field() {
from_single.visible = from_multiple.visible = from_label.visible = false;
@@ -2237,44 +2305,39 @@ public class ComposerWidget : Gtk.EventBox {
return;
// If there's only one account, show nothing. (From fields are hidden above.)
- if (accounts.size <= 1)
+ if (accounts.size < 1 || (accounts.size == 1 && Geary.traverse<Geary.AccountInformation>(
+ accounts.values).first().alternate_emails == null))
return;
from_label.visible = true;
+
+ from_label.set_use_underline(true);
+ from_label.set_mnemonic_widget(from_multiple);
+ // Composer label (with mnemonic underscore) for the account selector
+ // when choosing what address to send a message from.
+ from_label.set_text_with_mnemonic(_("_From:"));
+
+ from_multiple.visible = true;
+ from_multiple.remove_all();
+ from_list = new Gee.ArrayList<FromAddressMap>();
if (compose_type == ComposeType.NEW_MESSAGE) {
- // For new messages, show the account combo-box.
- from_label.set_use_underline(true);
- from_label.set_mnemonic_widget(from_multiple);
- // Composer label (with mnemonic underscore) for the account selector
- // when choosing what address to send a message from.
- from_label.set_text_with_mnemonic(_("_From:"));
-
- from_multiple.visible = true;
- from_multiple.remove_all();
- foreach (Geary.AccountInformation a in accounts.values)
- from_multiple.append(a.email, a.get_mailbox_address().get_full_address());
-
- // Set the active account to the currently selected account, or failing that, set it
- // to the first account in the list.
- if (!from_multiple.set_active_id(account.information.email))
- from_multiple.set_active(0);
+ add_account_emails_to_from_list(account);
+ foreach (Geary.AccountInformation info in accounts.values) {
+ try {
+ Geary.Account a = Geary.Engine.instance.get_account_instance(info);
+ if (a != account)
+ add_account_emails_to_from_list(a);
+ } catch (Error e) {
+ debug("Error getting account in composer: %s", e.message);
+ }
+ }
} else {
- // For other types of messages, just show the from account.
- from_label.set_use_underline(false);
- // Composer label (without mnemonic underscore) for the account selector
- // when choosing what address to send a message from.
- from_label.set_text(_("From:"));
-
- from_single.label = account.information.get_mailbox_address().get_full_address();
- from_single.visible = true;
+ add_account_emails_to_from_list(account);
}
}
private void on_from_changed() {
- if (compose_type != ComposeType.NEW_MESSAGE)
- return;
-
bool changed = false;
try {
changed = update_from_account();
@@ -2293,24 +2356,20 @@ public class ComposerWidget : Gtk.EventBox {
}
private bool update_from_account() throws Error {
- // Since we've set the combo box ID to the email addresses, we can
- // fetch that and use it to grab the account from the engine.
- string? id = from_multiple.get_active_id();
- if (id == null)
+ int index = from_multiple.get_active();
+ if (index < 0)
return false;
- // it's possible for changed signals to fire even though nothing has changed; catch that
- // here when possible to avoid a lot of extra work
- Geary.AccountInformation? new_account_info = Geary.Engine.instance.get_accounts().get(id);
- if (new_account_info == null)
- return false;
+ assert(from_list.size > index);
- Geary.Account new_account = Geary.Engine.instance.get_account_instance(new_account_info);
+ Geary.Account new_account = from_list.get(index).account;
+ // TODO: Allow using other real name (not only mail address)
+ from = new Geary.RFC822.MailboxAddresses.single(new Geary.RFC822.MailboxAddress(
+ new_account.information.real_name, from_list.get(index).email)).to_rfc822_string();
if (new_account == account)
return false;
account = new_account;
- from = new_account_info.get_from().to_rfc822_string();
set_entry_completions();
return true;
diff --git a/src/client/conversation-list/conversation-list-store.vala
b/src/client/conversation-list/conversation-list-store.vala
index 12859cd..f359af1 100644
--- a/src/client/conversation-list/conversation-list-store.vala
+++ b/src/client/conversation-list/conversation-list-store.vala
@@ -72,6 +72,7 @@ public class ConversationListStore : Gtk.ListStore {
}
}
+ public Gee.List<string>? account_owner_emails { get; set; default = null; }
public Geary.ProgressMonitor preview_monitor { get; private set; default =
new Geary.SimpleProgressMonitor(Geary.ProgressType.ACTIVITY); }
public bool is_clearing { get; private set; default = false; }
@@ -289,7 +290,8 @@ public class ConversationListStore : Gtk.ListStore {
private void set_row(Gtk.TreeIter iter, Geary.App.Conversation conversation, Geary.Email preview) {
FormattedConversationData conversation_data = new FormattedConversationData(conversation,
- preview, conversation_monitor.folder, conversation_monitor.folder.account.information.email);
+ preview, conversation_monitor.folder,
+ conversation_monitor.folder.account.information.get_all_email_addresses());
Gtk.TreePath? path = get_path(iter);
assert(path != null);
diff --git a/src/client/conversation-list/formatted-conversation-data.vala
b/src/client/conversation-list/formatted-conversation-data.vala
index 211361a..be0d05c 100644
--- a/src/client/conversation-list/formatted-conversation-data.vala
+++ b/src/client/conversation-list/formatted-conversation-data.vala
@@ -30,12 +30,12 @@ public class FormattedConversationData : Geary.BaseObject {
this.is_unread = is_unread;
}
- public string get_full_markup(string normalized_account_key) {
- return get_as_markup((key == normalized_account_key) ? ME : address.get_short_address());
+ public string get_full_markup(Gee.List<string> normalized_account_emails) {
+ return get_as_markup((key in normalized_account_emails) ? ME : address.get_short_address());
}
- public string get_short_markup(string normalized_account_key) {
- if (key == normalized_account_key)
+ public string get_short_markup(Gee.List<string> normalized_account_emails) {
+ if (key in normalized_account_emails)
return get_as_markup(ME);
string short_address = address.get_short_address().strip();
@@ -45,17 +45,17 @@ public class FormattedConversationData : Geary.BaseObject {
string[] tokens = short_address.split(", ", 2);
short_address = tokens[1].strip();
if (Geary.String.is_empty(short_address))
- return get_full_markup(normalized_account_key);
+ return get_full_markup(normalized_account_emails);
}
// use first name as delimited by a space
string[] tokens = short_address.split(" ", 2);
if (tokens.length < 1)
- return get_full_markup(normalized_account_key);
+ return get_full_markup(normalized_account_emails);
string first_name = tokens[0].strip();
if (Geary.String.is_empty_or_whitespace(first_name))
- return get_full_markup(normalized_account_key);
+ return get_full_markup(normalized_account_emails);
return get_as_markup(first_name);
}
@@ -89,17 +89,17 @@ public class FormattedConversationData : Geary.BaseObject {
public Geary.Email? preview { get; private set; default = null; }
private Geary.App.Conversation? conversation = null;
- private string? account_owner_email = null;
+ private Gee.List<string>? account_owner_emails = null;
private bool use_to = true;
private CountBadge count_badge = new CountBadge(2);
// Creates a formatted message data from an e-mail.
public FormattedConversationData(Geary.App.Conversation conversation, Geary.Email preview,
- Geary.Folder folder, string account_owner_email) {
+ Geary.Folder folder, Gee.List<string> account_owner_emails) {
assert(preview.fields.fulfills(ConversationListStore.REQUIRED_FIELDS));
this.conversation = conversation;
- this.account_owner_email = account_owner_email;
+ this.account_owner_emails = account_owner_emails;
use_to = (folder != null) && folder.special_folder_type.is_outgoing();
// Load preview-related data.
@@ -173,10 +173,12 @@ public class FormattedConversationData : Geary.BaseObject {
}
private string get_participants_markup(Gtk.Widget widget, bool selected) {
- if (conversation == null || account_owner_email == null)
+ if (conversation == null || account_owner_emails == null || account_owner_emails.size == 0)
return "";
- string normalized_account_owner_email = account_owner_email.normalize().casefold();
+ Gee.ArrayList<string> normalized_account_owner_emails = Geary.traverse<string>(account_owner_emails)
+ .map<string>(e => e.normalize().casefold())
+ .to_array_list();
// Build chronological list of AuthorDisplay records, setting to unread if any message by
// that author is unread
@@ -210,14 +212,14 @@ public class FormattedConversationData : Geary.BaseObject {
rgba_to_markup(get_foreground_rgba(widget, selected))));
if (list.size == 1) {
// if only one participant, use full name
- builder.append(list[0].get_full_markup(normalized_account_owner_email));
+ builder.append(list[0].get_full_markup(normalized_account_owner_emails));
} else {
bool first = true;
foreach (ParticipantDisplay participant in list) {
if (!first)
builder.append(", ");
- builder.append(participant.get_short_markup(normalized_account_owner_email));
+ builder.append(participant.get_short_markup(normalized_account_owner_emails));
first = false;
}
}
diff --git a/src/engine/api/geary-account-information.vala b/src/engine/api/geary-account-information.vala
index 926dc27..af25735 100644
--- a/src/engine/api/geary-account-information.vala
+++ b/src/engine/api/geary-account-information.vala
@@ -10,6 +10,7 @@ public class Geary.AccountInformation : BaseObject {
private const string GROUP = "AccountInformation";
private const string REAL_NAME_KEY = "real_name";
private const string NICKNAME_KEY = "nickname";
+ private const string ALTERNATE_EMAILS_KEY = "alternate_emails";
private const string SERVICE_PROVIDER_KEY = "service_provider";
private const string ORDINAL_KEY = "ordinal";
private const string PREFETCH_PERIOD_DAYS_KEY = "prefetch_period_days";
@@ -60,6 +61,7 @@ public class Geary.AccountInformation : BaseObject {
public string real_name { get; set; }
public string nickname { get; set; }
public string email { get; set; }
+ public Gee.List<string>? alternate_emails { get; set; }
public Geary.ServiceProvider service_provider { get; set; }
public int prefetch_period_days { get; set; }
@@ -143,6 +145,9 @@ public class Geary.AccountInformation : BaseObject {
} finally {
real_name = get_string_value(key_file, GROUP, REAL_NAME_KEY);
nickname = get_string_value(key_file, GROUP, NICKNAME_KEY);
+ alternate_emails = get_string_list_value(key_file, GROUP, ALTERNATE_EMAILS_KEY);
+ if (alternate_emails.size == 0)
+ alternate_emails = null;
imap_credentials.user = get_string_value(key_file, GROUP, IMAP_USERNAME_KEY, email);
imap_remember_password = get_bool_value(key_file, GROUP, IMAP_REMEMBER_PASSWORD_KEY, true);
smtp_credentials.user = get_string_value(key_file, GROUP, SMTP_USERNAME_KEY, email);
@@ -226,6 +231,12 @@ public class Geary.AccountInformation : BaseObject {
real_name = from.real_name;
nickname = from.nickname;
email = from.email;
+ alternate_emails = null;
+ if (from.alternate_emails != null) {
+ alternate_emails = new Gee.ArrayList<string>();
+ foreach (string alternate_email in from.alternate_emails)
+ alternate_emails.add(alternate_email);
+ }
service_provider = from.service_provider;
prefetch_period_days = from.prefetch_period_days;
save_sent_mail = from.save_sent_mail;
@@ -254,6 +265,17 @@ public class Geary.AccountInformation : BaseObject {
}
/**
+ * Return a list of the primary and all alternate email addresses.
+ */
+ public Gee.List<string> get_all_email_addresses() {
+ Gee.ArrayList<string> all = new Gee.ArrayList<string>();
+ all.add(email);
+ if (alternate_emails != null)
+ all.add_all(alternate_emails);
+ return all;
+ }
+
+ /**
* Return whether this account allows setting the save_sent_mail option.
* If not, save_sent_mail will always be true and setting it will be
* ignored.
@@ -792,15 +814,15 @@ public class Geary.AccountInformation : BaseObject {
/**
* Returns a MailboxAddress object for this account.
*/
- public RFC822.MailboxAddress get_mailbox_address() {
+ public RFC822.MailboxAddress get_primary_mailbox_address() {
return new RFC822.MailboxAddress(real_name, email);
}
/**
* Returns a MailboxAddresses object with this mailbox address.
*/
- public RFC822.MailboxAddresses get_from() {
- return new RFC822.MailboxAddresses.single(get_mailbox_address());
+ public RFC822.MailboxAddresses get_primary_from() {
+ return new RFC822.MailboxAddresses.single(get_primary_mailbox_address());
}
public static int compare_ascending(AccountInformation a, AccountInformation b) {
diff --git a/src/engine/imap-db/outbox/smtp-outbox-folder.vala
b/src/engine/imap-db/outbox/smtp-outbox-folder.vala
index 745967b..a09c6bc 100644
--- a/src/engine/imap-db/outbox/smtp-outbox-folder.vala
+++ b/src/engine/imap-db/outbox/smtp-outbox-folder.vala
@@ -634,7 +634,7 @@ private class Geary.SmtpOutboxFolder : Geary.AbstractLocalFolder, Geary.FolderSu
if (smtp_err == null) {
try {
- yield smtp.send_email_async(_account.information.get_mailbox_address(),
+ yield smtp.send_email_async(_account.information.get_primary_mailbox_address(),
rfc822, cancellable);
} catch (Error send_err) {
debug("SMTP send mail error: %s", send_err.message);
diff --git a/src/engine/rfc822/rfc822-utils.vala b/src/engine/rfc822/rfc822-utils.vala
index a76373b..e9a8da9 100644
--- a/src/engine/rfc822/rfc822-utils.vala
+++ b/src/engine/rfc822/rfc822-utils.vala
@@ -69,14 +69,22 @@ private void remove_address(Gee.List<Geary.RFC822.MailboxAddress> addresses,
}
}
+private bool email_is_from_sender(Geary.Email email, Gee.List<string>? sender_addresses) {
+ if (sender_addresses == null)
+ return false;
+
+ return Geary.traverse<string>(sender_addresses).any(a =>
+ !String.is_empty(a) && email.from.contains(a));
+}
+
public Geary.RFC822.MailboxAddresses create_to_addresses_for_reply(Geary.Email email,
- string? sender_address = null) {
+ Gee.List<string>? sender_addresses = null) {
Gee.List<Geary.RFC822.MailboxAddress> new_to =
new Gee.ArrayList<Geary.RFC822.MailboxAddress>();
// If we're replying to something we sent, send it to the same people we originally did.
// Otherwise, we'll send to the reply-to address or the from address.
- if (email.to != null && !String.is_empty(sender_address) && email.from.contains(sender_address))
+ if (email.to != null && email_is_from_sender(email, sender_addresses))
new_to.add_all(email.to.get_all());
else if (email.reply_to != null)
new_to.add_all(email.reply_to.get_all());
@@ -84,29 +92,36 @@ public Geary.RFC822.MailboxAddresses create_to_addresses_for_reply(Geary.Email e
new_to.add_all(email.from.get_all());
// Exclude the current sender. No need to receive the mail they're sending.
- if (!String.is_empty(sender_address))
- remove_address(new_to, sender_address);
+ if (sender_addresses != null) {
+ foreach (string address in sender_addresses) {
+ if (!String.is_empty(address))
+ remove_address(new_to, address);
+ }
+ }
return new Geary.RFC822.MailboxAddresses(new_to);
}
public Geary.RFC822.MailboxAddresses create_cc_addresses_for_reply_all(Geary.Email email,
- string? sender_address = null) {
+ Gee.List<string>? sender_addresses = null) {
Gee.List<Geary.RFC822.MailboxAddress> new_cc = new Gee.ArrayList<Geary.RFC822.MailboxAddress>();
// If we're replying to something we received, also add other recipients. Don't do this for
// emails we sent, since everyone we sent it to is already covered in
// create_to_addresses_for_reply().
- if (email.to != null && (String.is_empty(sender_address) ||
- !email.from.contains(sender_address)))
+ if (email.to != null && !email_is_from_sender(email, sender_addresses))
new_cc.add_all(email.to.get_all());
if (email.cc != null)
new_cc.add_all(email.cc.get_all());
// Again, exclude the current sender.
- if (!String.is_empty(sender_address))
- remove_address(new_cc, sender_address, true);
+ if (sender_addresses != null) {
+ foreach (string address in sender_addresses) {
+ if (!String.is_empty(address))
+ remove_address(new_cc, address, true);
+ }
+ }
return new Geary.RFC822.MailboxAddresses(new_cc);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]