This rather large patch allows separate IMAP and SMTP credentials and separates the user's credential username from their email address. Additional work in this patch includes fixing some minor protocol bugs in the SMTP stack to work with Postfix, refactoring the Geary.Engine interface to stop issuing plain strings for account names, and removing the Geary.EngineAccount abstract class which was growing unnecessary with each passing day.
This commit is contained in:
parent
7f741b0a2c
commit
126378d85c
35 changed files with 1434 additions and 615 deletions
|
|
@ -31,7 +31,6 @@ engine/api/geary-email-identifier.vala
|
|||
engine/api/geary-email-properties.vala
|
||||
engine/api/geary-email.vala
|
||||
engine/api/geary-endpoint.vala
|
||||
engine/api/geary-engine-account.vala
|
||||
engine/api/geary-engine-error.vala
|
||||
engine/api/geary-engine.vala
|
||||
engine/api/geary-folder.vala
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
private static GearyApplication _instance = null;
|
||||
|
||||
private GearyController? controller = null;
|
||||
private Geary.EngineAccount? account = null;
|
||||
private Geary.Account? account = null;
|
||||
|
||||
private File exec_dir;
|
||||
|
||||
|
|
@ -177,7 +177,7 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
return;
|
||||
}
|
||||
|
||||
private void set_account(Geary.EngineAccount? account) {
|
||||
private void set_account(Geary.Account? account) {
|
||||
if (this.account == account)
|
||||
return;
|
||||
|
||||
|
|
@ -193,19 +193,22 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
}
|
||||
|
||||
private void initialize_account() {
|
||||
string? username = get_username();
|
||||
if (username == null)
|
||||
create_account(username);
|
||||
Geary.AccountInformation? account_information = get_account();
|
||||
if (account_information == null)
|
||||
create_account(null);
|
||||
else
|
||||
open_account(username);
|
||||
open_account(account_information.email, null, null, PasswordTypeFlag.IMAP | PasswordTypeFlag.SMTP, null);
|
||||
}
|
||||
|
||||
private void create_account(string? username) {
|
||||
private void create_account(string? email) {
|
||||
Geary.AccountInformation? old_account_information = null;
|
||||
if (username != null) {
|
||||
Geary.Credentials credentials = new Geary.Credentials(username, null);
|
||||
old_account_information = new Geary.AccountInformation(credentials);
|
||||
old_account_information.load_info_from_file();
|
||||
if (email != null) {
|
||||
try {
|
||||
old_account_information = Geary.Engine.get_account_for_email(email);
|
||||
} catch (Error err) {
|
||||
debug("Unable to open account information for %s, creating instead: %s", email,
|
||||
err.message);
|
||||
}
|
||||
}
|
||||
|
||||
Geary.AccountInformation account_information =
|
||||
|
|
@ -262,23 +265,31 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
return new_account_information;
|
||||
}
|
||||
|
||||
private void open_account(string username, string? old_password = null, Cancellable? cancellable = null) {
|
||||
Geary.Credentials credentials = new Geary.Credentials(username, null);
|
||||
Geary.AccountInformation account_information = new Geary.AccountInformation(credentials);
|
||||
account_information.load_info_from_file();
|
||||
private void open_account(string email, string? old_imap_password, string? old_smtp_password,
|
||||
PasswordTypeFlag password_flags, Cancellable? cancellable) {
|
||||
Geary.AccountInformation account_information;
|
||||
try {
|
||||
account_information = Geary.Engine.get_account_for_email(email);
|
||||
} catch (Error err) {
|
||||
error("Unable to open account information for label %s: %s", email, err.message);
|
||||
}
|
||||
|
||||
bool remember_password = account_information.remember_password;
|
||||
string? password = get_password(account_information.credentials.user, old_password, ref remember_password);
|
||||
// If there was no saved password and the user refused to enter a password.
|
||||
if (password == null) {
|
||||
bool imap_remember_password = account_information.imap_remember_password;
|
||||
bool smtp_remember_password = account_information.smtp_remember_password;
|
||||
string? imap_password, smtp_password;
|
||||
get_passwords(account_information, password_flags, ref imap_remember_password,
|
||||
ref smtp_remember_password, out imap_password, out smtp_password);
|
||||
if (imap_password == null || smtp_password == null) {
|
||||
set_account(null);
|
||||
return;
|
||||
}
|
||||
|
||||
account_information.remember_password = remember_password;
|
||||
account_information.imap_remember_password = imap_remember_password;
|
||||
account_information.smtp_remember_password = smtp_remember_password;
|
||||
account_information.store_async.begin(cancellable);
|
||||
|
||||
account_information.credentials.pass = password;
|
||||
account_information.imap_credentials.pass = imap_password;
|
||||
account_information.smtp_credentials.pass = smtp_password;
|
||||
|
||||
try {
|
||||
set_account(account_information.get_account());
|
||||
|
|
@ -290,29 +301,34 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
}
|
||||
}
|
||||
|
||||
private string? get_username() {
|
||||
private Geary.AccountInformation? get_account() {
|
||||
try {
|
||||
Gee.List<string> usernames = Geary.Engine.get_usernames();
|
||||
if (usernames.size > 0) {
|
||||
string username = usernames.get(0);
|
||||
return Geary.String.is_empty(username) ? null : username;
|
||||
}
|
||||
Gee.List<Geary.AccountInformation> accounts = Geary.Engine.get_accounts();
|
||||
if (accounts.size > 0)
|
||||
return accounts[0];
|
||||
} catch (Error e) {
|
||||
debug("Unable to fetch accounts. Error: %s", e.message);
|
||||
debug("Unable to fetch account labels: %s", e.message);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string? get_password(string username, string? old_password, ref bool remember_password) {
|
||||
string? password = null;
|
||||
if (old_password == null && remember_password)
|
||||
password = keyring_get_password(username);
|
||||
private void get_passwords(Geary.AccountInformation old_account_information,
|
||||
PasswordTypeFlag password_flags, ref bool imap_remember_password,
|
||||
ref bool smtp_remember_password, out string? imap_password, out string? smtp_password) {
|
||||
imap_password = null;
|
||||
if (!old_account_information.imap_credentials.is_complete() && imap_remember_password)
|
||||
imap_password = keyring_get_password(old_account_information.imap_credentials.user, PasswordType.IMAP);
|
||||
|
||||
if (Geary.String.is_null_or_whitespace(password))
|
||||
password = request_password(username, old_password, out remember_password);
|
||||
smtp_password = null;
|
||||
if (!old_account_information.smtp_credentials.is_complete() && smtp_remember_password)
|
||||
smtp_password = keyring_get_password(old_account_information.smtp_credentials.user, PasswordType.SMTP);
|
||||
|
||||
return password;
|
||||
if (Geary.String.is_empty_or_whitespace(imap_password) ||
|
||||
Geary.String.is_empty_or_whitespace(smtp_password)) {
|
||||
request_passwords(old_account_information, password_flags, out imap_password,
|
||||
out smtp_password, out imap_remember_password, out smtp_remember_password);
|
||||
}
|
||||
}
|
||||
|
||||
private string get_default_real_name() {
|
||||
|
|
@ -320,30 +336,53 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
return real_name == "Unknown" ? "" : real_name;
|
||||
}
|
||||
|
||||
private string? request_password(string username, string? old_password, out bool remember_password) {
|
||||
Geary.Credentials credentials = new Geary.Credentials(username, old_password);
|
||||
private void request_passwords(Geary.AccountInformation old_account_information,
|
||||
PasswordTypeFlag password_flags, out string? imap_password, out string? smtp_password,
|
||||
out bool imap_remember_password, out bool smtp_remember_password) {
|
||||
Geary.AccountInformation temp_account_information;
|
||||
try {
|
||||
temp_account_information = Geary.Engine.get_account_for_email(old_account_information.email);
|
||||
} catch (Error err) {
|
||||
error("Unable to open account information for %s: %s", old_account_information.email,
|
||||
err.message);
|
||||
}
|
||||
|
||||
Geary.AccountInformation old_account_information = new Geary.AccountInformation(credentials);
|
||||
old_account_information.load_info_from_file();
|
||||
temp_account_information.imap_credentials = old_account_information.imap_credentials.copy();
|
||||
temp_account_information.smtp_credentials = old_account_information.smtp_credentials.copy();
|
||||
|
||||
PasswordDialog password_dialog = new PasswordDialog(old_account_information, old_password == null);
|
||||
bool first_try = !temp_account_information.imap_credentials.is_complete() ||
|
||||
!temp_account_information.smtp_credentials.is_complete();
|
||||
PasswordDialog password_dialog = new PasswordDialog(temp_account_information, first_try,
|
||||
password_flags);
|
||||
if (!password_dialog.run()) {
|
||||
exit(1);
|
||||
remember_password = false;
|
||||
return null;
|
||||
imap_password = null;
|
||||
smtp_password = null;
|
||||
imap_remember_password = false;
|
||||
smtp_remember_password = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// password_dialog.password should never be null at this point. It will only be null when
|
||||
// password_dialog.run() returns false, in which case we have already exited/returned.
|
||||
string? password = password_dialog.password;
|
||||
remember_password = password_dialog.remember_password;
|
||||
imap_password = password_dialog.imap_password;
|
||||
smtp_password = password_dialog.smtp_password;
|
||||
imap_remember_password = password_dialog.imap_remember_password;
|
||||
smtp_remember_password = password_dialog.smtp_remember_password;
|
||||
|
||||
if (remember_password)
|
||||
keyring_save_password(new Geary.Credentials(username, password));
|
||||
else
|
||||
keyring_delete_password(username);
|
||||
if (imap_remember_password) {
|
||||
keyring_save_password(new Geary.Credentials(temp_account_information.imap_credentials.user,
|
||||
imap_password), PasswordType.IMAP);
|
||||
} else {
|
||||
keyring_delete_password(temp_account_information.imap_credentials.user, PasswordType.IMAP);
|
||||
}
|
||||
|
||||
return password;
|
||||
if (smtp_remember_password) {
|
||||
keyring_save_password(new Geary.Credentials(temp_account_information.smtp_credentials.user,
|
||||
smtp_password), PasswordType.SMTP);
|
||||
} else {
|
||||
keyring_delete_password(temp_account_information.smtp_credentials.user, PasswordType.SMTP);
|
||||
}
|
||||
}
|
||||
|
||||
// Prompt the user for a service, real name, username, and password, and try to start Geary.
|
||||
|
|
@ -359,15 +398,26 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
return null;
|
||||
}
|
||||
|
||||
if (login_dialog.account_information.remember_password)
|
||||
keyring_save_password(login_dialog.account_information.credentials);
|
||||
else
|
||||
keyring_delete_password(login_dialog.account_information.credentials.user);
|
||||
|
||||
if (login_dialog.account_information.imap_remember_password) {
|
||||
keyring_save_password(login_dialog.account_information.imap_credentials,
|
||||
PasswordType.IMAP);
|
||||
} else {
|
||||
keyring_delete_password(login_dialog.account_information.imap_credentials.user,
|
||||
PasswordType.IMAP);
|
||||
}
|
||||
|
||||
if (login_dialog.account_information.smtp_remember_password) {
|
||||
keyring_save_password(login_dialog.account_information.smtp_credentials,
|
||||
PasswordType.SMTP);
|
||||
} else {
|
||||
keyring_delete_password(login_dialog.account_information.smtp_credentials.user,
|
||||
PasswordType.SMTP);
|
||||
}
|
||||
|
||||
return login_dialog.account_information;
|
||||
}
|
||||
|
||||
private void on_report_problem(Geary.Account.Problem problem, Geary.Credentials? credentials,
|
||||
private void on_report_problem(Geary.Account.Problem problem, Geary.AccountSettings settings,
|
||||
Error? err) {
|
||||
debug("Reported problem: %s Error: %s", problem.to_string(), err != null ? err.message : "(N/A)");
|
||||
switch (problem) {
|
||||
|
|
@ -377,11 +427,18 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
// TODO
|
||||
break;
|
||||
|
||||
case Geary.Account.Problem.LOGIN_FAILED:
|
||||
debug("Login failed.");
|
||||
Geary.Credentials old_credentials = account.settings.credentials;
|
||||
// TODO: Different password dialog prompt for SMTP or IMAP login.
|
||||
case Geary.Account.Problem.RECV_EMAIL_LOGIN_FAILED:
|
||||
account.report_problem.disconnect(on_report_problem);
|
||||
open_account(old_credentials.user, old_credentials.pass);
|
||||
open_account(account.settings.email.address, account.settings.imap_credentials.pass,
|
||||
account.settings.smtp_credentials.pass, PasswordTypeFlag.IMAP, null);
|
||||
break;
|
||||
|
||||
// TODO: Different password dialog prompt for SMTP or IMAP login.
|
||||
case Geary.Account.Problem.SEND_EMAIL_LOGIN_FAILED:
|
||||
account.report_problem.disconnect(on_report_problem);
|
||||
open_account(account.settings.email.address, account.settings.imap_credentials.pass,
|
||||
account.settings.smtp_credentials.pass, PasswordTypeFlag.SMTP, null);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ public class GearyController {
|
|||
|
||||
public MainWindow main_window { get; private set; }
|
||||
|
||||
private Geary.EngineAccount? account = null;
|
||||
private Geary.Account? account = null;
|
||||
private Cancellable cancellable_folder = new Cancellable();
|
||||
private Cancellable cancellable_inbox = new Cancellable();
|
||||
private Cancellable cancellable_message = new Cancellable();
|
||||
|
|
@ -246,7 +246,7 @@ public class GearyController {
|
|||
return entries;
|
||||
}
|
||||
|
||||
public async void connect_account_async(Geary.EngineAccount? new_account, Cancellable? cancellable) {
|
||||
public async void connect_account_async(Geary.Account? new_account, Cancellable? cancellable) {
|
||||
if (account == new_account)
|
||||
return;
|
||||
|
||||
|
|
@ -297,8 +297,7 @@ public class GearyController {
|
|||
|
||||
if (account.settings.service_provider == Geary.ServiceProvider.YAHOO)
|
||||
main_window.title = GearyApplication.NAME + "!";
|
||||
// TODO: Change this when Geary no longer assumes username is email addresss.
|
||||
main_window.message_list_store.account_owner_email = account.settings.credentials.user;
|
||||
main_window.message_list_store.account_owner_email = account.settings.email.address;
|
||||
|
||||
main_window.folder_list.set_user_folders_root_name(_("Labels"));
|
||||
load_folders.begin(cancellable_folder);
|
||||
|
|
@ -538,7 +537,7 @@ public class GearyController {
|
|||
|
||||
// Clear view before we yield, to make sure it happens
|
||||
if (clear_view) {
|
||||
main_window.message_viewer.clear(current_folder);
|
||||
main_window.message_viewer.clear(current_folder, account.settings);
|
||||
main_window.message_viewer.scroll_reset();
|
||||
main_window.message_viewer.external_images_info_bar.hide();
|
||||
}
|
||||
|
|
@ -1139,17 +1138,9 @@ public class GearyController {
|
|||
}
|
||||
|
||||
private Geary.RFC822.MailboxAddress get_sender() {
|
||||
string username;
|
||||
try {
|
||||
// TODO: Multiple accounts.
|
||||
username = Geary.Engine.get_usernames().get(0);
|
||||
} catch (Error e) {
|
||||
error("Unable to get username. Error: %s", e.message);
|
||||
}
|
||||
|
||||
return new Geary.RFC822.MailboxAddress(account.settings.real_name, username);
|
||||
return account.settings.email;
|
||||
}
|
||||
|
||||
|
||||
private Geary.RFC822.MailboxAddresses get_from() {
|
||||
return new Geary.RFC822.MailboxAddresses.single(get_sender());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ public class ContactEntryCompletion : Gtk.EntryCompletion {
|
|||
Gee.List<string> addresses = get_addresses(sender, out current_address_index, null,
|
||||
out current_address_remainder);
|
||||
addresses[current_address_index] = full_address;
|
||||
if (!Geary.String.is_null_or_whitespace(current_address_remainder))
|
||||
if (!Geary.String.is_empty_or_whitespace(current_address_remainder))
|
||||
addresses.insert(current_address_index + 1, current_address_remainder);
|
||||
string delimiter = ", ";
|
||||
entry.text = concat_strings(addresses, delimiter);
|
||||
|
|
|
|||
|
|
@ -7,23 +7,35 @@
|
|||
// Displays a dialog for collecting the user's login data.
|
||||
public class LoginDialog {
|
||||
private Gtk.Dialog dialog;
|
||||
private Gtk.Entry entry_username;
|
||||
private Gtk.Entry entry_email;
|
||||
private Gtk.Label label_password;
|
||||
private Gtk.Entry entry_password;
|
||||
private Gtk.Entry entry_real_name;
|
||||
private Gtk.ComboBoxText combo_service;
|
||||
private Gtk.CheckButton check_remember_password;
|
||||
|
||||
private Gtk.Alignment other_info;
|
||||
|
||||
// IMAP info widgets
|
||||
private Gtk.Entry entry_imap_host;
|
||||
private Gtk.Entry entry_imap_port;
|
||||
private Gtk.Entry entry_imap_username;
|
||||
private Gtk.Entry entry_imap_password;
|
||||
private Gtk.CheckButton check_imap_remember_password;
|
||||
private Gtk.RadioButton radio_imap_none;
|
||||
private Gtk.RadioButton radio_imap_ssl;
|
||||
private Gtk.RadioButton radio_imap_starttls;
|
||||
|
||||
// SMTP info widgets
|
||||
private Gtk.Entry entry_smtp_host;
|
||||
private Gtk.Entry entry_smtp_port;
|
||||
private Gtk.Entry entry_smtp_username;
|
||||
private Gtk.Entry entry_smtp_password;
|
||||
private Gtk.CheckButton check_smtp_remember_password;
|
||||
private Gtk.RadioButton radio_smtp_none;
|
||||
private Gtk.RadioButton radio_smtp_ssl;
|
||||
private Gtk.RadioButton radio_smtp_starttls;
|
||||
|
||||
private Gtk.Button ok_button;
|
||||
|
||||
private bool edited_imap_port = false;
|
||||
|
|
@ -31,49 +43,80 @@ public class LoginDialog {
|
|||
|
||||
public Geary.AccountInformation account_information { get; private set; }
|
||||
|
||||
// TODO: Update the login dialog to use email, imap_credentials, smtp_credentials,
|
||||
// imap_remember_password, and smtp_remember_password.
|
||||
public LoginDialog.from_account_information(Geary.AccountInformation initial_account_information) {
|
||||
this(initial_account_information.real_name, initial_account_information.credentials.user,
|
||||
initial_account_information.credentials.pass, initial_account_information.remember_password,
|
||||
initial_account_information.service_provider, initial_account_information.default_imap_server_host,
|
||||
initial_account_information.default_imap_server_port, initial_account_information.default_imap_server_ssl,
|
||||
initial_account_information.default_imap_server_starttls, initial_account_information.default_smtp_server_host,
|
||||
initial_account_information.default_smtp_server_port, initial_account_information.default_smtp_server_ssl,
|
||||
this(initial_account_information.real_name,
|
||||
initial_account_information.email,
|
||||
initial_account_information.imap_credentials.user,
|
||||
initial_account_information.imap_credentials.pass,
|
||||
initial_account_information.imap_remember_password,
|
||||
initial_account_information.smtp_credentials.user,
|
||||
initial_account_information.smtp_credentials.pass,
|
||||
initial_account_information.smtp_remember_password,
|
||||
initial_account_information.service_provider,
|
||||
initial_account_information.default_imap_server_host,
|
||||
initial_account_information.default_imap_server_port,
|
||||
initial_account_information.default_imap_server_ssl,
|
||||
initial_account_information.default_imap_server_starttls,
|
||||
initial_account_information.default_smtp_server_host,
|
||||
initial_account_information.default_smtp_server_port,
|
||||
initial_account_information.default_smtp_server_ssl,
|
||||
initial_account_information.default_smtp_server_starttls);
|
||||
}
|
||||
|
||||
public LoginDialog(string? initial_real_name = null, string? initial_username = null,
|
||||
string? initial_password = null, bool initial_remember_password = true,
|
||||
int initial_service_provider = -1, string? initial_default_imap_host = null,
|
||||
public LoginDialog(
|
||||
string? initial_real_name = null,
|
||||
string? initial_email = null,
|
||||
string? initial_imap_username = null,
|
||||
string? initial_imap_password = null,
|
||||
bool initial_imap_remember_password = true,
|
||||
string? initial_smtp_username = null,
|
||||
string? initial_smtp_password = null,
|
||||
bool initial_smtp_remember_password = true,
|
||||
int initial_service_provider = -1,
|
||||
string? initial_default_imap_host = null,
|
||||
uint16 initial_default_imap_port = Geary.Imap.ClientConnection.DEFAULT_PORT_SSL,
|
||||
bool initial_default_imap_ssl = true, bool initial_default_imap_starttls = false,
|
||||
bool initial_default_imap_ssl = true,
|
||||
bool initial_default_imap_starttls = false,
|
||||
string? initial_default_smtp_host = null,
|
||||
uint16 initial_default_smtp_port = Geary.Smtp.ClientConnection.DEFAULT_PORT_SSL,
|
||||
bool initial_default_smtp_ssl = true, bool initial_default_smtp_starttls = false) {
|
||||
bool initial_default_smtp_ssl = true,
|
||||
bool initial_default_smtp_starttls = false) {
|
||||
Gtk.Builder builder = GearyApplication.instance.create_builder("login.glade");
|
||||
|
||||
dialog = builder.get_object("LoginDialog") as Gtk.Dialog;
|
||||
dialog.set_type_hint(Gdk.WindowTypeHint.DIALOG);
|
||||
dialog.set_default_response(Gtk.ResponseType.OK);
|
||||
|
||||
entry_real_name = builder.get_object("real_name") as Gtk.Entry;
|
||||
combo_service = builder.get_object("service") as Gtk.ComboBoxText;
|
||||
entry_username = builder.get_object("username") as Gtk.Entry;
|
||||
entry_password = builder.get_object("password") as Gtk.Entry;
|
||||
check_remember_password = builder.get_object("remember_password") as Gtk.CheckButton;
|
||||
entry_real_name = builder.get_object("entry: real_name") as Gtk.Entry;
|
||||
combo_service = builder.get_object("combo: service") as Gtk.ComboBoxText;
|
||||
entry_email = builder.get_object("entry: email") as Gtk.Entry;
|
||||
label_password = builder.get_object("label: password") as Gtk.Label;
|
||||
entry_password = builder.get_object("entry: password") as Gtk.Entry;
|
||||
check_remember_password = builder.get_object("check: remember_password") as Gtk.CheckButton;
|
||||
|
||||
other_info = builder.get_object("other_info") as Gtk.Alignment;
|
||||
other_info = builder.get_object("container: other_info") as Gtk.Alignment;
|
||||
|
||||
entry_imap_host = builder.get_object("imap host") as Gtk.Entry;
|
||||
entry_imap_port = builder.get_object("imap port") as Gtk.Entry;
|
||||
radio_imap_none = builder.get_object("imap none") as Gtk.RadioButton;
|
||||
radio_imap_ssl = builder.get_object("imap ssl") as Gtk.RadioButton;
|
||||
radio_imap_starttls = builder.get_object("imap starttls") as Gtk.RadioButton;
|
||||
// IMAP info widgets.
|
||||
entry_imap_host = builder.get_object("entry: imap host") as Gtk.Entry;
|
||||
entry_imap_port = builder.get_object("entry: imap port") as Gtk.Entry;
|
||||
entry_imap_username = builder.get_object("entry: imap username") as Gtk.Entry;
|
||||
entry_imap_password = builder.get_object("entry: imap password") as Gtk.Entry;
|
||||
check_imap_remember_password = builder.get_object("check: imap remember_password") as Gtk.CheckButton;
|
||||
radio_imap_none = builder.get_object("radio: imap none") as Gtk.RadioButton;
|
||||
radio_imap_ssl = builder.get_object("radio: imap ssl") as Gtk.RadioButton;
|
||||
radio_imap_starttls = builder.get_object("radio: imap starttls") as Gtk.RadioButton;
|
||||
|
||||
entry_smtp_host = builder.get_object("smtp host") as Gtk.Entry;
|
||||
entry_smtp_port = builder.get_object("smtp port") as Gtk.Entry;
|
||||
radio_smtp_none = builder.get_object("smtp none") as Gtk.RadioButton;
|
||||
radio_smtp_ssl = builder.get_object("smtp ssl") as Gtk.RadioButton;
|
||||
radio_smtp_starttls = builder.get_object("smtp starttls") as Gtk.RadioButton;
|
||||
// SMTP info widgets.
|
||||
entry_smtp_host = builder.get_object("entry: smtp host") as Gtk.Entry;
|
||||
entry_smtp_port = builder.get_object("entry: smtp port") as Gtk.Entry;
|
||||
entry_smtp_username = builder.get_object("entry: smtp username") as Gtk.Entry;
|
||||
entry_smtp_password = builder.get_object("entry: smtp password") as Gtk.Entry;
|
||||
check_smtp_remember_password = builder.get_object("check: smtp remember_password") as Gtk.CheckButton;
|
||||
radio_smtp_none = builder.get_object("radio: smtp none") as Gtk.RadioButton;
|
||||
radio_smtp_ssl = builder.get_object("radio: smtp ssl") as Gtk.RadioButton;
|
||||
radio_smtp_starttls = builder.get_object("radio: smtp starttls") as Gtk.RadioButton;
|
||||
|
||||
combo_service.changed.connect(on_service_changed);
|
||||
|
||||
|
|
@ -88,18 +131,28 @@ public class LoginDialog {
|
|||
|
||||
// Set defaults (other than service provider, which is set above)
|
||||
entry_real_name.set_text(initial_real_name ?? "");
|
||||
entry_username.set_text(initial_username ?? "");
|
||||
entry_password.set_text(initial_password ?? "");
|
||||
check_remember_password.active = initial_remember_password;
|
||||
entry_email.set_text(initial_email ?? "");
|
||||
bool use_imap_password = initial_imap_password == initial_smtp_password &&
|
||||
initial_imap_password != null;
|
||||
entry_password.set_text(use_imap_password ? initial_imap_password : "");
|
||||
check_remember_password.active = initial_imap_remember_password && initial_smtp_remember_password;
|
||||
|
||||
// Set defaults for IMAP info
|
||||
entry_imap_host.set_text(initial_default_imap_host ?? "");
|
||||
entry_imap_port.set_text(initial_default_imap_port.to_string());
|
||||
entry_imap_username.set_text(initial_imap_username ?? "");
|
||||
entry_imap_password.set_text(initial_imap_password ?? "");
|
||||
check_imap_remember_password.active = initial_imap_remember_password;
|
||||
radio_imap_none.active = true;
|
||||
radio_imap_ssl.active = initial_default_imap_ssl;
|
||||
radio_imap_starttls.active = initial_default_imap_starttls;
|
||||
|
||||
// Set defaults for SMTP info
|
||||
entry_smtp_host.set_text(initial_default_smtp_host ?? "");
|
||||
entry_smtp_port.set_text(initial_default_smtp_port.to_string());
|
||||
entry_smtp_username.set_text(initial_smtp_username ?? "");
|
||||
entry_smtp_password.set_text(initial_smtp_password ?? "");
|
||||
check_smtp_remember_password.active = initial_smtp_remember_password;
|
||||
radio_smtp_none.active = true;
|
||||
radio_smtp_ssl.active = initial_default_smtp_ssl;
|
||||
radio_smtp_starttls.active = initial_default_smtp_starttls;
|
||||
|
|
@ -107,17 +160,25 @@ public class LoginDialog {
|
|||
if (Geary.String.is_empty(entry_real_name.text))
|
||||
entry_real_name.grab_focus();
|
||||
else
|
||||
entry_username.grab_focus();
|
||||
entry_email.grab_focus();
|
||||
|
||||
entry_username.changed.connect(on_changed);
|
||||
entry_email.changed.connect(on_changed);
|
||||
entry_password.changed.connect(on_changed);
|
||||
entry_real_name.changed.connect(on_changed);
|
||||
check_remember_password.toggled.connect(on_changed);
|
||||
combo_service.changed.connect(on_changed);
|
||||
entry_imap_host.changed.connect(on_changed);
|
||||
entry_imap_port.changed.connect(on_changed);
|
||||
entry_imap_username.changed.connect(on_changed);
|
||||
entry_imap_password.changed.connect(on_changed);
|
||||
entry_smtp_host.changed.connect(on_changed);
|
||||
entry_smtp_port.changed.connect(on_changed);
|
||||
entry_smtp_username.changed.connect(on_changed);
|
||||
entry_smtp_password.changed.connect(on_changed);
|
||||
|
||||
entry_email.changed.connect(on_email_changed);
|
||||
entry_password.changed.connect(on_password_changed);
|
||||
check_remember_password.toggled.connect(on_remember_password_toggled);
|
||||
|
||||
radio_imap_none.toggled.connect(on_radio_imap_toggled);
|
||||
radio_imap_ssl.toggled.connect(on_radio_imap_toggled);
|
||||
|
|
@ -133,7 +194,7 @@ public class LoginDialog {
|
|||
dialog.add_action_widget(new Gtk.Button.from_stock(Gtk.Stock.CANCEL), Gtk.ResponseType.CANCEL);
|
||||
ok_button = new Gtk.Button.from_stock(Gtk.Stock.OK);
|
||||
ok_button.can_default = true;
|
||||
ok_button.sensitive = false;
|
||||
ok_button.sensitive = is_complete();
|
||||
dialog.add_action_widget(ok_button, Gtk.ResponseType.OK);
|
||||
dialog.set_default_response(Gtk.ResponseType.OK);
|
||||
}
|
||||
|
|
@ -148,12 +209,34 @@ public class LoginDialog {
|
|||
if (response != Gtk.ResponseType.OK)
|
||||
return false;
|
||||
|
||||
Geary.Credentials credentials = new Geary.Credentials(entry_username.text.strip(),
|
||||
entry_password.text.strip());
|
||||
account_information = new Geary.AccountInformation(credentials);
|
||||
bool use_extra_info = get_service_provider() == Geary.ServiceProvider.OTHER;
|
||||
|
||||
string email = entry_email.text.strip();
|
||||
string imap_username = use_extra_info ? entry_imap_username.text.strip() : email;
|
||||
string imap_password = (use_extra_info ? entry_imap_password : entry_password).text.strip();
|
||||
bool imap_remember_password = use_extra_info ? check_imap_remember_password.active :
|
||||
check_remember_password.active;
|
||||
Geary.Credentials imap_credentials = new Geary.Credentials(imap_username, imap_password);
|
||||
|
||||
string smtp_username = use_extra_info ? entry_smtp_username.text.strip() : email;
|
||||
string smtp_password = (use_extra_info ? entry_smtp_password : entry_password).text.strip();
|
||||
bool smtp_remember_password = use_extra_info ? check_smtp_remember_password.active :
|
||||
check_remember_password.active;
|
||||
Geary.Credentials smtp_credentials = new Geary.Credentials(smtp_username, smtp_password);
|
||||
|
||||
try {
|
||||
account_information = Geary.Engine.get_account_for_email(email);
|
||||
} catch (Error err) {
|
||||
debug("Unable to open account information for %s: %s", email, err.message);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
account_information.real_name = entry_real_name.text.strip();
|
||||
account_information.remember_password = check_remember_password.active;
|
||||
account_information.imap_credentials = imap_credentials;
|
||||
account_information.smtp_credentials = smtp_credentials;
|
||||
account_information.imap_remember_password = imap_remember_password;
|
||||
account_information.smtp_remember_password = smtp_remember_password;
|
||||
account_information.service_provider = get_service_provider();
|
||||
account_information.default_imap_server_host = entry_imap_host.text.strip();
|
||||
account_information.default_imap_server_port = (uint16) int.parse(entry_imap_port.text.strip());
|
||||
|
|
@ -170,10 +253,34 @@ public class LoginDialog {
|
|||
return true;
|
||||
}
|
||||
|
||||
// TODO: Only reset if not manually set by user.
|
||||
private void on_email_changed() {
|
||||
entry_imap_username.text = entry_email.text;
|
||||
entry_smtp_username.text = entry_email.text;
|
||||
}
|
||||
|
||||
// TODO: Only reset if not manually set by user.
|
||||
private void on_password_changed() {
|
||||
entry_imap_password.text = entry_password.text;
|
||||
entry_smtp_password.text = entry_password.text;
|
||||
}
|
||||
|
||||
// TODO: Only reset if not manually set by user.
|
||||
private void on_remember_password_toggled() {
|
||||
check_imap_remember_password.active = check_remember_password.active;
|
||||
check_smtp_remember_password.active = check_remember_password.active;
|
||||
}
|
||||
|
||||
private void on_service_changed() {
|
||||
if (get_service_provider() == Geary.ServiceProvider.OTHER) {
|
||||
label_password.hide();
|
||||
entry_password.hide();
|
||||
check_remember_password.hide();
|
||||
other_info.show();
|
||||
} else {
|
||||
label_password.show();
|
||||
entry_password.show();
|
||||
check_remember_password.show();
|
||||
other_info.hide();
|
||||
dialog.resize(1, 1);
|
||||
}
|
||||
|
|
@ -233,22 +340,40 @@ public class LoginDialog {
|
|||
return (Geary.ServiceProvider) combo_service.get_active();
|
||||
}
|
||||
|
||||
private bool is_complete() {
|
||||
if (Geary.String.is_null_or_whitespace(entry_username.text.strip()) ||
|
||||
Geary.String.is_null_or_whitespace(entry_password.text.strip()))
|
||||
private bool is_valid_port(string text) {
|
||||
uint64 port;
|
||||
if (!uint64.try_parse(text, out port))
|
||||
return false;
|
||||
|
||||
// For "other" providers, check server settings.
|
||||
if (get_service_provider() == Geary.ServiceProvider.OTHER) {
|
||||
if (Geary.String.is_empty(entry_imap_host.text.strip()) ||
|
||||
Geary.String.is_empty(entry_imap_port.text) ||
|
||||
Geary.String.is_empty(entry_smtp_host.text.strip()) ||
|
||||
Geary.String.is_empty(entry_smtp_port.text) ||
|
||||
int.parse(entry_imap_port.text) > uint16.MAX ||
|
||||
int.parse(entry_smtp_port.text) > uint16.MAX)
|
||||
return false;
|
||||
return (port <= uint16.MAX);
|
||||
}
|
||||
|
||||
private bool is_complete() {
|
||||
switch (get_service_provider()) {
|
||||
case Geary.ServiceProvider.OTHER:
|
||||
if (Geary.String.is_empty_or_whitespace(entry_email.text) ||
|
||||
Geary.String.is_empty_or_whitespace(entry_imap_host.text) ||
|
||||
Geary.String.is_empty_or_whitespace(entry_imap_port.text) ||
|
||||
Geary.String.is_empty_or_whitespace(entry_imap_username.text) ||
|
||||
Geary.String.is_empty_or_whitespace(entry_imap_password.text) ||
|
||||
Geary.String.is_empty_or_whitespace(entry_smtp_host.text) ||
|
||||
Geary.String.is_empty_or_whitespace(entry_smtp_port.text) ||
|
||||
Geary.String.is_empty_or_whitespace(entry_smtp_username.text) ||
|
||||
Geary.String.is_empty_or_whitespace(entry_smtp_password.text) ||
|
||||
!is_valid_port(entry_imap_port.text) ||
|
||||
!is_valid_port(entry_smtp_port.text))
|
||||
return false;
|
||||
break;
|
||||
|
||||
// GMAIL and YAHOO
|
||||
default:
|
||||
if (Geary.String.is_empty_or_whitespace(entry_email.text) ||
|
||||
Geary.String.is_empty_or_whitespace(entry_password.text))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ public class FormattedMessageData : Object {
|
|||
// TODO: Should we use a more sophisticated algorithm than "first word" to get the
|
||||
// first name?
|
||||
string first_name = tokens[0].strip();
|
||||
if (Geary.String.is_null_or_whitespace(first_name))
|
||||
if (Geary.String.is_empty_or_whitespace(first_name))
|
||||
continue;
|
||||
|
||||
if (authors_builder.len > 0)
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ public class MessageViewer : Object {
|
|||
private Gtk.Menu? attachment_menu = null;
|
||||
private FileMonitor? user_style_monitor = null;
|
||||
private weak Geary.Folder? current_folder = null;
|
||||
private Geary.AccountSettings? current_settings = null;
|
||||
private bool load_external_images = false;
|
||||
|
||||
public MessageViewer() {
|
||||
|
|
@ -235,7 +236,7 @@ public class MessageViewer : Object {
|
|||
continue;
|
||||
|
||||
string src = element.get_attribute("src");
|
||||
if (Geary.String.is_null_or_whitespace(src) || is_always_loaded(src))
|
||||
if (Geary.String.is_empty_or_whitespace(src) || is_always_loaded(src))
|
||||
continue;
|
||||
|
||||
// Refresh the image source. Requests are denied when load_external_images
|
||||
|
|
@ -364,7 +365,7 @@ public class MessageViewer : Object {
|
|||
}
|
||||
|
||||
// Removes all displayed e-mails from the view.
|
||||
public void clear(Geary.Folder? new_folder) {
|
||||
public void clear(Geary.Folder? new_folder, Geary.AccountSettings? settings) {
|
||||
// Remove all messages from DOM.
|
||||
try {
|
||||
foreach (WebKit.DOM.HTMLElement element in email_to_element.values) {
|
||||
|
|
@ -378,6 +379,7 @@ public class MessageViewer : Object {
|
|||
messages.clear();
|
||||
|
||||
current_folder = new_folder;
|
||||
current_settings = settings;
|
||||
}
|
||||
|
||||
// Converts an email ID into HTML ID used by the <div> for the email.
|
||||
|
|
@ -395,7 +397,7 @@ public class MessageViewer : Object {
|
|||
|
||||
public void show_multiple_selected(uint selected_count) {
|
||||
// Remove any messages and hide the message container, then show the counter.
|
||||
clear(current_folder);
|
||||
clear(current_folder, current_settings);
|
||||
try {
|
||||
hide_element_by_id(MESSAGE_CONTAINER_ID);
|
||||
show_element_by_id(SELECTION_COUNTER_ID);
|
||||
|
|
@ -478,21 +480,13 @@ public class MessageViewer : Object {
|
|||
|
||||
email_to_element.set(email.id, div_message);
|
||||
|
||||
string username;
|
||||
try {
|
||||
// TODO: Multiple accounts.
|
||||
username = Geary.Engine.get_usernames().get(0);
|
||||
} catch (Error e) {
|
||||
error("Unable to get username. Error: %s", e.message);
|
||||
}
|
||||
|
||||
insert_header_address(ref header, _("From:"), email.from != null ? email.from : email.sender,
|
||||
true);
|
||||
|
||||
// Only include to string if it's not just this account.
|
||||
// TODO: multiple accounts.
|
||||
if (email.to != null) {
|
||||
if (!(email.to.get_all().size == 1 && email.to.get_all().get(0).address == username))
|
||||
if (email.to != null && current_settings != null) {
|
||||
if (!(email.to.get_all().size == 1 && email.to.get_all().get(0).address == current_settings.email.address))
|
||||
insert_header_address(ref header, _("To:"), email.to);
|
||||
}
|
||||
|
||||
|
|
@ -1372,7 +1366,7 @@ public class MessageViewer : Object {
|
|||
foreach (Geary.Attachment attachment in attachments) {
|
||||
// Generate the attachment table.
|
||||
WebKit.DOM.HTMLElement attachment_table = Util.DOM.clone_node(attachment_template);
|
||||
string filename = Geary.String.is_null_or_whitespace(attachment.filename) ?
|
||||
string filename = Geary.String.is_empty_or_whitespace(attachment.filename) ?
|
||||
_("none") : attachment.filename;
|
||||
Util.DOM.select(attachment_table, ".info .filename")
|
||||
.set_inner_text(filename);
|
||||
|
|
|
|||
|
|
@ -17,15 +17,23 @@ public class PasswordDialog {
|
|||
private const string PRIMARY_TEXT_REPEATED_TRY = _("Unable to login to email server");
|
||||
|
||||
private Gtk.Dialog dialog;
|
||||
private Gtk.Entry password_entry;
|
||||
private Gtk.CheckButton remember_password_checkbutton;
|
||||
private Gtk.Entry entry_imap_password;
|
||||
private Gtk.CheckButton check_imap_remember_password;
|
||||
private Gtk.Entry entry_smtp_password;
|
||||
private Gtk.CheckButton check_smtp_remember_password;
|
||||
private Gtk.Button ok_button;
|
||||
private Gtk.Grid grid_imap;
|
||||
private Gtk.Grid grid_smtp;
|
||||
private PasswordTypeFlag password_flags;
|
||||
|
||||
public string password { get; private set; default = ""; }
|
||||
public string imap_password { get; private set; default = ""; }
|
||||
public string smtp_password { get; private set; default = ""; }
|
||||
public bool imap_remember_password { get; private set; }
|
||||
public bool smtp_remember_password { get; private set; }
|
||||
|
||||
public bool remember_password { get; private set; }
|
||||
|
||||
public PasswordDialog(Geary.AccountInformation account_information, bool first_try) {
|
||||
public PasswordDialog(Geary.AccountInformation account_information, bool first_try,
|
||||
PasswordTypeFlag password_flags) {
|
||||
this.password_flags = password_flags;
|
||||
Gtk.Builder builder = GearyApplication.instance.create_builder("password-dialog.glade");
|
||||
|
||||
// Load dialog
|
||||
|
|
@ -34,19 +42,26 @@ public class PasswordDialog {
|
|||
dialog.set_default_response(Gtk.ResponseType.OK);
|
||||
|
||||
// Load editable widgets
|
||||
password_entry = (Gtk.Entry) builder.get_object("password_entry");
|
||||
remember_password_checkbutton = (Gtk.CheckButton) builder.get_object("remember_password_checkbutton");
|
||||
entry_imap_password = (Gtk.Entry) builder.get_object("entry: imap password");
|
||||
check_imap_remember_password = (Gtk.CheckButton) builder.get_object("check: imap remember_password");
|
||||
entry_smtp_password = (Gtk.Entry) builder.get_object("entry: smtp password");
|
||||
check_smtp_remember_password = (Gtk.CheckButton) builder.get_object("check: smtp remember_password");
|
||||
|
||||
// Load non-editable widgets
|
||||
Gtk.Label email_label = (Gtk.Label) builder.get_object("email_label");
|
||||
Gtk.Label real_name_label = (Gtk.Label) builder.get_object("real_name_label");
|
||||
Gtk.Label service_label = (Gtk.Label) builder.get_object("service_label");
|
||||
Gtk.Label imap_server_label = (Gtk.Label) builder.get_object("imap_server_label");
|
||||
Gtk.Label imap_port_label = (Gtk.Label) builder.get_object("imap_port_label");
|
||||
Gtk.Label imap_encryption_label = (Gtk.Label) builder.get_object("imap_encryption_label");
|
||||
Gtk.Label smtp_server_label = (Gtk.Label) builder.get_object("smtp_server_label");
|
||||
Gtk.Label smtp_port_label = (Gtk.Label) builder.get_object("smtp_port_label");
|
||||
Gtk.Label smtp_encryption_label = (Gtk.Label) builder.get_object("smtp_encryption_label");
|
||||
Gtk.Label label_real_name = (Gtk.Label) builder.get_object("label: real_name");
|
||||
Gtk.Label label_service = (Gtk.Label) builder.get_object("label: service");
|
||||
|
||||
grid_imap = (Gtk.Grid) builder.get_object("grid: imap");
|
||||
Gtk.Label label_imap_username = (Gtk.Label) builder.get_object("label: imap username");
|
||||
Gtk.Label label_imap_server = (Gtk.Label) builder.get_object("label: imap server");
|
||||
Gtk.Label label_imap_port = (Gtk.Label) builder.get_object("label: imap port");
|
||||
Gtk.Label label_imap_encryption = (Gtk.Label) builder.get_object("label: imap encryption");
|
||||
|
||||
grid_smtp = (Gtk.Grid) builder.get_object("grid: smtp");
|
||||
Gtk.Label label_smtp_username = (Gtk.Label) builder.get_object("label: smtp username");
|
||||
Gtk.Label label_smtp_server = (Gtk.Label) builder.get_object("label: smtp server");
|
||||
Gtk.Label label_smtp_port = (Gtk.Label) builder.get_object("label: smtp port");
|
||||
Gtk.Label label_smtp_encryption = (Gtk.Label) builder.get_object("label: smtp encryption");
|
||||
|
||||
// Load translated text for labels with markup unsupported by glade.
|
||||
Gtk.Label primary_text_label = (Gtk.Label) builder.get_object("primary_text_label");
|
||||
|
|
@ -70,17 +85,23 @@ public class PasswordDialog {
|
|||
bool smtp_server_ssl= (smtp_endpoint.flags & Geary.Endpoint.Flags.SSL) != 0;
|
||||
|
||||
// Load initial values
|
||||
email_label.set_text(account_information.credentials.user ?? "");
|
||||
password_entry.set_text(account_information.credentials.pass ?? "");
|
||||
remember_password_checkbutton.active = account_information.remember_password;
|
||||
real_name_label.set_text(account_information.real_name ?? "");
|
||||
service_label.set_text(account_information.service_provider.display_name() ?? "");
|
||||
imap_server_label.set_text(imap_server_host);
|
||||
imap_port_label.set_text(imap_server_port.to_string());
|
||||
imap_encryption_label.set_text(imap_server_ssl ? "on" : "off");
|
||||
smtp_server_label.set_text(smtp_server_host);
|
||||
smtp_port_label.set_text(smtp_server_port.to_string());
|
||||
smtp_encryption_label.set_text(smtp_server_ssl ? "on" : "off");
|
||||
// TODO: Use email, imap/smtp credentials, imap/smtp remember.
|
||||
label_real_name.set_text(account_information.real_name ?? "");
|
||||
label_service.set_text(account_information.service_provider.display_name() ?? "");
|
||||
|
||||
label_imap_username.set_text(account_information.imap_credentials.user ?? "");
|
||||
entry_imap_password.set_text(account_information.imap_credentials.pass ?? "");
|
||||
check_imap_remember_password.active = account_information.imap_remember_password;
|
||||
label_imap_server.set_text(imap_server_host);
|
||||
label_imap_port.set_text(imap_server_port.to_string());
|
||||
label_imap_encryption.set_text(imap_server_ssl ? "on" : "off");
|
||||
|
||||
label_smtp_username.set_text(account_information.smtp_credentials.user ?? "");
|
||||
entry_smtp_password.set_text(account_information.smtp_credentials.pass ?? "");
|
||||
check_smtp_remember_password.active = account_information.smtp_remember_password;
|
||||
label_smtp_server.set_text(smtp_server_host);
|
||||
label_smtp_port.set_text(smtp_server_port.to_string());
|
||||
label_smtp_encryption.set_text(smtp_server_ssl ? "on" : "off");
|
||||
|
||||
// Add action buttons
|
||||
Gtk.Button cancel_button = new Gtk.Button.from_stock(Gtk.Stock.CANCEL);
|
||||
|
|
@ -92,7 +113,8 @@ public class PasswordDialog {
|
|||
|
||||
// Setup listeners
|
||||
refresh_ok_button_sensitivity();
|
||||
password_entry.changed.connect(refresh_ok_button_sensitivity);
|
||||
entry_imap_password.changed.connect(refresh_ok_button_sensitivity);
|
||||
entry_smtp_password.changed.connect(refresh_ok_button_sensitivity);
|
||||
}
|
||||
|
||||
private string get_primary_text_markup(bool first_try) {
|
||||
|
|
@ -100,24 +122,31 @@ public class PasswordDialog {
|
|||
}
|
||||
|
||||
private void refresh_ok_button_sensitivity() {
|
||||
ok_button.sensitive = !Geary.String.is_null_or_whitespace(password_entry.get_text());
|
||||
ok_button.sensitive = !Geary.String.is_empty_or_whitespace(entry_imap_password.get_text()) ||
|
||||
!Geary.String.is_empty_or_whitespace(entry_smtp_password.get_text());
|
||||
}
|
||||
|
||||
public bool run() {
|
||||
dialog.show();
|
||||
dialog.get_action_area().show_all();
|
||||
|
||||
Gtk.ResponseType response = (Gtk.ResponseType)dialog.run();
|
||||
if (response != Gtk.ResponseType.OK) {
|
||||
dialog.destroy();
|
||||
return false;
|
||||
if (!password_flags.has_imap())
|
||||
grid_imap.hide();
|
||||
|
||||
if (!password_flags.has_smtp())
|
||||
grid_smtp.hide();
|
||||
|
||||
Gtk.ResponseType response = (Gtk.ResponseType) dialog.run();
|
||||
if (response == Gtk.ResponseType.OK) {
|
||||
imap_password = entry_imap_password.get_text();
|
||||
imap_remember_password = check_imap_remember_password.active;
|
||||
smtp_password = entry_smtp_password.get_text();
|
||||
smtp_remember_password = check_smtp_remember_password.active;
|
||||
}
|
||||
|
||||
password = password_entry.get_text();
|
||||
remember_password = remember_password_checkbutton.active;
|
||||
|
||||
dialog.destroy();
|
||||
return true;
|
||||
|
||||
return (response == Gtk.ResponseType.OK);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ public class WebViewEditFixer {
|
|||
child = node.child_nodes.item(i);
|
||||
if (child.node_name == BR_NAME)
|
||||
continue;
|
||||
if (child.node_name == TEXT_NAME && Geary.String.is_null_or_whitespace(child.node_value))
|
||||
if (child.node_name == TEXT_NAME && Geary.String.is_empty_or_whitespace(child.node_value))
|
||||
continue;
|
||||
if (child.node_name == DIV_NAME && !is_substantial(child))
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -4,27 +4,79 @@
|
|||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
const string GEARY_USERNAME_PREFIX = "org.yorba.geary username:";
|
||||
const string OLD_GEARY_USERNAME_PREFIX = "org.yorba.geary username:";
|
||||
|
||||
public static bool keyring_save_password(Geary.Credentials credentials) {
|
||||
string name = GEARY_USERNAME_PREFIX + credentials.user;
|
||||
public enum PasswordType {
|
||||
IMAP,
|
||||
SMTP;
|
||||
|
||||
GnomeKeyring.Result result = GnomeKeyring.store_password_sync(GnomeKeyring.NETWORK_PASSWORD,
|
||||
null, name, credentials.pass, "user", name);
|
||||
|
||||
return result == GnomeKeyring.Result.OK;
|
||||
public string get_prefix() {
|
||||
switch (this) {
|
||||
case IMAP:
|
||||
return "org.yorba.geary imap_username:";
|
||||
|
||||
case SMTP:
|
||||
return "org.yorba.geary smtp_username:";
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void keyring_delete_password(string username) {
|
||||
[Flags]
|
||||
public enum PasswordTypeFlag {
|
||||
IMAP,
|
||||
SMTP;
|
||||
|
||||
public bool has_imap() {
|
||||
return (this & IMAP) == IMAP;
|
||||
}
|
||||
|
||||
public bool has_smtp() {
|
||||
return (this & SMTP) == SMTP;
|
||||
}
|
||||
}
|
||||
|
||||
private static string keyring_get_key(PasswordType password_type, string username) {
|
||||
return password_type.get_prefix() + username;
|
||||
}
|
||||
|
||||
public static bool keyring_save_password(Geary.Credentials credentials, PasswordType password_type) {
|
||||
string key = keyring_get_key(password_type, credentials.user);
|
||||
|
||||
GnomeKeyring.Result result = GnomeKeyring.store_password_sync(GnomeKeyring.NETWORK_PASSWORD,
|
||||
null, key, credentials.pass, "user", key);
|
||||
|
||||
if (result != GnomeKeyring.Result.OK)
|
||||
debug("Unable to store password in GNOME keyring: %s", result.to_string());
|
||||
|
||||
return (result == GnomeKeyring.Result.OK);
|
||||
}
|
||||
|
||||
public static void keyring_delete_password(string username, PasswordType password_type) {
|
||||
// delete new-style and old-style locations
|
||||
GnomeKeyring.delete_password_sync(GnomeKeyring.NETWORK_PASSWORD, "user",
|
||||
GEARY_USERNAME_PREFIX + username);
|
||||
keyring_get_key(password_type, username));
|
||||
GnomeKeyring.delete_password_sync(GnomeKeyring.NETWORK_PASSWORD, "user",
|
||||
OLD_GEARY_USERNAME_PREFIX + username);
|
||||
}
|
||||
|
||||
// Returns the password for the given username, or null if not set.
|
||||
public static string? keyring_get_password(string username) {
|
||||
public static string? keyring_get_password(string username, PasswordType password_type) {
|
||||
string password;
|
||||
GnomeKeyring.Result res = GnomeKeyring.find_password_sync(GnomeKeyring.NETWORK_PASSWORD,
|
||||
out password, "user", GEARY_USERNAME_PREFIX + username);
|
||||
GnomeKeyring.Result result = GnomeKeyring.find_password_sync(GnomeKeyring.NETWORK_PASSWORD,
|
||||
out password, "user", keyring_get_key(password_type, username));
|
||||
|
||||
return res == GnomeKeyring.Result.OK ? password : null;
|
||||
if (result != GnomeKeyring.Result.OK) {
|
||||
// fallback to the old keyring key string for upgrading users
|
||||
result = GnomeKeyring.find_password_sync(GnomeKeyring.NETWORK_PASSWORD, out password,
|
||||
"user", OLD_GEARY_USERNAME_PREFIX + username);
|
||||
}
|
||||
|
||||
if (result != GnomeKeyring.Result.OK)
|
||||
debug("Unable to fetch password in GNOME keyring: %s", result.to_string());
|
||||
|
||||
return (result == GnomeKeyring.Result.OK) ? password : null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ public class Geary.DBus.Controller {
|
|||
public DBusConnection connection { get; private set; }
|
||||
|
||||
private string[] args;
|
||||
private Geary.EngineAccount account;
|
||||
private Geary.Account account;
|
||||
private Geary.DBus.Conversations conversations;
|
||||
|
||||
public static void init(string[] args) {
|
||||
|
|
@ -32,9 +32,12 @@ public class Geary.DBus.Controller {
|
|||
connection = yield Bus.get(GLib.BusType.SESSION);
|
||||
|
||||
// Open the account.
|
||||
Geary.Credentials credentials = new Geary.Credentials(args[1], args[2]);
|
||||
Geary.AccountInformation account_information = new Geary.AccountInformation(credentials);
|
||||
account_information.load_info_from_file();
|
||||
// TODO: Don't assume username is email, allow separate imap/smtp credentials.
|
||||
Geary.AccountInformation account_information = Geary.Engine.get_account_for_email(args[1]);
|
||||
account_information.imap_credentials = new Geary.Credentials(args[1], args[2]);
|
||||
account_information.smtp_credentials = new Geary.Credentials(args[1], args[2]);
|
||||
|
||||
// convert AccountInformation into an Account
|
||||
try {
|
||||
account = account_information.get_account();
|
||||
} catch (EngineError err) {
|
||||
|
|
@ -80,7 +83,7 @@ public class Geary.DBus.Controller {
|
|||
return File.new_for_path(Environment.get_current_dir());
|
||||
}
|
||||
|
||||
private void on_report_problem(Geary.Account.Problem problem, Geary.Credentials? credentials,
|
||||
private void on_report_problem(Geary.Account.Problem problem, Geary.AccountSettings settings,
|
||||
Error? err) {
|
||||
debug("Reported problem: %s Error: %s", problem.to_string(), err != null ? err.message : "(N/A)");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,15 +5,13 @@
|
|||
*/
|
||||
|
||||
public abstract class Geary.AbstractAccount : Object, Geary.Account {
|
||||
public Geary.AccountSettings settings { get; protected set; }
|
||||
|
||||
private string name;
|
||||
|
||||
public AbstractAccount(string name) {
|
||||
public AbstractAccount(string name, AccountSettings settings) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public virtual void notify_report_problem(Geary.Account.Problem problem,
|
||||
Geary.Credentials? credentials, Error? err) {
|
||||
report_problem(problem, credentials, err);
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
protected virtual void notify_folders_added_removed(Gee.Collection<Geary.Folder>? added,
|
||||
|
|
@ -29,6 +27,15 @@ public abstract class Geary.AbstractAccount : Object, Geary.Account {
|
|||
closed();
|
||||
}
|
||||
|
||||
protected virtual void notify_email_sent(RFC822.Message message) {
|
||||
email_sent(message);
|
||||
}
|
||||
|
||||
protected virtual void notify_report_problem(Geary.Account.Problem problem,
|
||||
Geary.AccountSettings? settings, Error? err) {
|
||||
report_problem(problem, settings, err);
|
||||
}
|
||||
|
||||
public abstract async void open_async(Cancellable? cancellable = null) throws Error;
|
||||
|
||||
public abstract async void close_async(Cancellable? cancellable = null) throws Error;
|
||||
|
|
@ -44,6 +51,9 @@ public abstract class Geary.AbstractAccount : Object, Geary.Account {
|
|||
public abstract async Geary.Folder fetch_folder_async(Geary.FolderPath path,
|
||||
Cancellable? cancellable = null) throws Error;
|
||||
|
||||
public abstract async void send_email_async(Geary.ComposedEmail composed, Cancellable? cancellable = null)
|
||||
throws Error;
|
||||
|
||||
public virtual string to_string() {
|
||||
return name;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,10 @@ public class Geary.AccountInformation : Object {
|
|||
private const string GROUP = "AccountInformation";
|
||||
private const string REAL_NAME_KEY = "real_name";
|
||||
private const string SERVICE_PROVIDER_KEY = "service_provider";
|
||||
private const string REMEMBER_PASSWORD_KEY = "remember_password";
|
||||
private const string IMAP_USERNAME_KEY = "imap_username";
|
||||
private const string IMAP_REMEMBER_PASSWORD_KEY = "imap_remember_password";
|
||||
private const string SMTP_USERNAME_KEY = "smtp_username";
|
||||
private const string SMTP_REMEMBER_PASSWORD_KEY = "smtp_remember_password";
|
||||
private const string IMAP_HOST = "imap_host";
|
||||
private const string IMAP_PORT = "imap_port";
|
||||
private const string IMAP_SSL = "imap_ssl";
|
||||
|
|
@ -21,9 +24,11 @@ public class Geary.AccountInformation : Object {
|
|||
|
||||
public const string SETTINGS_FILENAME = "geary.ini";
|
||||
|
||||
internal File? settings_dir;
|
||||
internal File? file = null;
|
||||
internal File settings_dir;
|
||||
internal File file;
|
||||
|
||||
public string real_name { get; set; }
|
||||
public string email { get; set; }
|
||||
public Geary.ServiceProvider service_provider { get; set; }
|
||||
public bool imap_server_pipeline { get; set; default = true; }
|
||||
|
||||
|
|
@ -37,17 +42,16 @@ public class Geary.AccountInformation : Object {
|
|||
public bool default_smtp_server_ssl { get; set; }
|
||||
public bool default_smtp_server_starttls { get; set; }
|
||||
|
||||
public Geary.Credentials credentials { get; private set; }
|
||||
public bool remember_password { get; set; default = true; }
|
||||
public Geary.Credentials imap_credentials { get; set; default = new Geary.Credentials(null, null); }
|
||||
public bool imap_remember_password { get; set; default = true; }
|
||||
public Geary.Credentials smtp_credentials { get; set; default = new Geary.Credentials(null, null); }
|
||||
public bool smtp_remember_password { get; set; default = true; }
|
||||
|
||||
public AccountInformation(Geary.Credentials credentials) {
|
||||
this.credentials = credentials;
|
||||
|
||||
this.settings_dir = Geary.Engine.user_data_dir.get_child(credentials.user);
|
||||
internal AccountInformation(File directory) {
|
||||
this.email = directory.get_basename();
|
||||
this.settings_dir = directory;
|
||||
this.file = settings_dir.get_child(SETTINGS_FILENAME);
|
||||
}
|
||||
|
||||
public void load_info_from_file() {
|
||||
|
||||
KeyFile key_file = new KeyFile();
|
||||
try {
|
||||
key_file.load_from_file(file.get_path() ?? "", KeyFileFlags.NONE);
|
||||
|
|
@ -57,9 +61,12 @@ public class Geary.AccountInformation : Object {
|
|||
// It's no big deal if we couldn't load the key file -- just means we give you the defaults.
|
||||
} finally {
|
||||
real_name = get_string_value(key_file, GROUP, REAL_NAME_KEY);
|
||||
remember_password = get_bool_value(key_file, GROUP, REMEMBER_PASSWORD_KEY, true);
|
||||
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);
|
||||
smtp_remember_password = get_bool_value(key_file, GROUP, SMTP_REMEMBER_PASSWORD_KEY, true);
|
||||
service_provider = Geary.ServiceProvider.from_string(get_string_value(key_file, GROUP,
|
||||
SERVICE_PROVIDER_KEY));
|
||||
SERVICE_PROVIDER_KEY, Geary.ServiceProvider.GMAIL.to_string()));
|
||||
|
||||
imap_server_pipeline = get_bool_value(key_file, GROUP, IMAP_PIPELINE, true);
|
||||
|
||||
|
|
@ -82,33 +89,55 @@ public class Geary.AccountInformation : Object {
|
|||
public async bool validate_async(Cancellable? cancellable = null) throws EngineError {
|
||||
AccountSettings settings = new AccountSettings(this);
|
||||
|
||||
Geary.Imap.ClientSession client_session = new Imap.ClientSession(settings.imap_endpoint, true);
|
||||
// validate IMAP, which requires logging in and establishing an AUTHORIZED cx state
|
||||
bool imap_valid = false;
|
||||
Geary.Imap.ClientSession? imap_session = new Imap.ClientSession(settings.imap_endpoint, true);
|
||||
try {
|
||||
yield client_session.connect_async(cancellable);
|
||||
yield client_session.initiate_session_async(settings.credentials, cancellable);
|
||||
yield imap_session.connect_async(cancellable);
|
||||
yield imap_session.initiate_session_async(settings.imap_credentials, cancellable);
|
||||
|
||||
// Connected and initiated, still need to be sure connection authorized
|
||||
string current_mailbox;
|
||||
if (imap_session.get_context(out current_mailbox) == Imap.ClientSession.Context.AUTHORIZED)
|
||||
imap_valid = true;
|
||||
} catch (Error err) {
|
||||
debug("Error validating account info: %s", err.message);
|
||||
debug("Error validating IMAP account info: %s", err.message);
|
||||
|
||||
try {
|
||||
yield client_session.disconnect_async(cancellable);
|
||||
} catch (Error disconnect_err) {
|
||||
// ignored
|
||||
}
|
||||
|
||||
return false;
|
||||
// fall through so session can be disconnected
|
||||
}
|
||||
|
||||
// Connected and initiated, still need to be sure connection authorized
|
||||
string current_mailbox;
|
||||
bool valid = (client_session.get_context(out current_mailbox) == Imap.ClientSession.Context.AUTHORIZED);
|
||||
|
||||
try {
|
||||
yield client_session.disconnect_async(cancellable);
|
||||
yield imap_session.disconnect_async(cancellable);
|
||||
} catch (Error err) {
|
||||
// ignored
|
||||
} finally {
|
||||
imap_session = null;
|
||||
}
|
||||
|
||||
return valid;
|
||||
if (!imap_valid)
|
||||
return false;
|
||||
|
||||
// SMTP is simpler, merely see if login works and done (throws an SmtpError if not)
|
||||
bool smtp_valid = false;
|
||||
Geary.Smtp.ClientSession? smtp_session = new Geary.Smtp.ClientSession(settings.smtp_endpoint);
|
||||
try {
|
||||
yield smtp_session.login_async(settings.smtp_credentials, cancellable);
|
||||
smtp_valid = true;
|
||||
} catch (Error err) {
|
||||
debug("Error validating SMTP account info: %s", err.message);
|
||||
|
||||
// fall through so session can be disconnected
|
||||
}
|
||||
|
||||
try {
|
||||
yield smtp_session.logout_async(cancellable);
|
||||
} catch (Error err) {
|
||||
// ignored
|
||||
} finally {
|
||||
smtp_session = null;
|
||||
}
|
||||
|
||||
return smtp_valid;
|
||||
}
|
||||
|
||||
public Endpoint get_imap_endpoint() throws EngineError {
|
||||
|
|
@ -159,23 +188,23 @@ public class Geary.AccountInformation : Object {
|
|||
}
|
||||
}
|
||||
|
||||
public Geary.EngineAccount get_account() throws EngineError {
|
||||
public Geary.Account get_account() throws EngineError {
|
||||
AccountSettings settings = new AccountSettings(this);
|
||||
|
||||
ImapDB.Account local_account = new ImapDB.Account(settings);
|
||||
Imap.Account remote_account = new Imap.Account(settings);
|
||||
|
||||
|
||||
switch (service_provider) {
|
||||
case ServiceProvider.GMAIL:
|
||||
return new ImapEngine.GmailAccount("Gmail account %s".printf(credentials.to_string()),
|
||||
return new ImapEngine.GmailAccount("Gmail account %s".printf(email),
|
||||
settings, remote_account, local_account);
|
||||
|
||||
case ServiceProvider.YAHOO:
|
||||
return new ImapEngine.YahooAccount("Yahoo account %s".printf(credentials.to_string()),
|
||||
return new ImapEngine.YahooAccount("Yahoo account %s".printf(email),
|
||||
settings, remote_account, local_account);
|
||||
|
||||
case ServiceProvider.OTHER:
|
||||
return new ImapEngine.OtherAccount("Other account %s".printf(credentials.to_string()),
|
||||
return new ImapEngine.OtherAccount("Other account %s".printf(email),
|
||||
settings, remote_account, local_account);
|
||||
|
||||
default:
|
||||
|
|
@ -184,34 +213,34 @@ public class Geary.AccountInformation : Object {
|
|||
}
|
||||
}
|
||||
|
||||
private string get_string_value(KeyFile key_file, string group, string key, string _default = "") {
|
||||
string v = _default;
|
||||
private string get_string_value(KeyFile key_file, string group, string key, string def = "") {
|
||||
try {
|
||||
v = key_file.get_value(group, key);
|
||||
return key_file.get_value(group, key);
|
||||
} catch(KeyFileError err) {
|
||||
// Ignore.
|
||||
}
|
||||
return v;
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
private bool get_bool_value(KeyFile key_file, string group, string key, bool _default = false) {
|
||||
bool v = _default;
|
||||
private bool get_bool_value(KeyFile key_file, string group, string key, bool def = false) {
|
||||
try {
|
||||
v = key_file.get_boolean(group, key);
|
||||
return key_file.get_boolean(group, key);
|
||||
} catch(KeyFileError err) {
|
||||
// Ignore.
|
||||
}
|
||||
return v;
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
private uint16 get_uint16_value(KeyFile key_file, string group, string key, uint16 _default = 0) {
|
||||
uint16 v = _default;
|
||||
private uint16 get_uint16_value(KeyFile key_file, string group, string key, uint16 def = 0) {
|
||||
try {
|
||||
v = (uint16) key_file.get_integer(group, key);
|
||||
return (uint16) key_file.get_integer(group, key);
|
||||
} catch(KeyFileError err) {
|
||||
// Ignore.
|
||||
}
|
||||
return v;
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
public async void store_async(Cancellable? cancellable = null) {
|
||||
|
|
@ -221,7 +250,7 @@ public class Geary.AccountInformation : Object {
|
|||
try {
|
||||
settings_dir.make_directory_with_parents();
|
||||
} catch (Error err) {
|
||||
error("Error creating settings directory for user '%s': %s", credentials.user,
|
||||
error("Error creating settings directory for email '%s': %s", email,
|
||||
err.message);
|
||||
}
|
||||
}
|
||||
|
|
@ -238,7 +267,10 @@ public class Geary.AccountInformation : Object {
|
|||
|
||||
key_file.set_value(GROUP, REAL_NAME_KEY, real_name);
|
||||
key_file.set_value(GROUP, SERVICE_PROVIDER_KEY, service_provider.to_string());
|
||||
key_file.set_boolean(GROUP, REMEMBER_PASSWORD_KEY, remember_password);
|
||||
key_file.set_value(GROUP, IMAP_USERNAME_KEY, imap_credentials.user);
|
||||
key_file.set_boolean(GROUP, IMAP_REMEMBER_PASSWORD_KEY, imap_remember_password);
|
||||
key_file.set_value(GROUP, SMTP_USERNAME_KEY, smtp_credentials.user);
|
||||
key_file.set_boolean(GROUP, SMTP_REMEMBER_PASSWORD_KEY, smtp_remember_password);
|
||||
|
||||
key_file.set_boolean(GROUP, IMAP_PIPELINE, imap_server_pipeline);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,25 +7,34 @@
|
|||
/**
|
||||
* AccountSettings is a complement to AccountInformation. AccountInformation stores these settings
|
||||
* as well as defaults and provides validation and persistence functionality. Settings is simply
|
||||
* the values loaded from a backing store, perhaps chosen from defaults, and validated filtered
|
||||
* down to a set of working settings for the Account to use.
|
||||
* the values loaded from a backing store, perhaps chosen from defaults, and validated, then filtered
|
||||
* down to a set of working settings for the Account to use. Changes made to AccountInformation
|
||||
* are not reflected here; a new AccountSettings object must be created.
|
||||
*/
|
||||
|
||||
public class Geary.AccountSettings {
|
||||
public RFC822.MailboxAddress email { get; private set; }
|
||||
public string real_name { get; private set; }
|
||||
public Geary.Credentials credentials { get; private set; }
|
||||
public Geary.Credentials imap_credentials { get; private set; }
|
||||
public Geary.Credentials smtp_credentials { get; private set; }
|
||||
public Geary.ServiceProvider service_provider { get; private set; }
|
||||
public bool imap_server_pipeline { get; private set; }
|
||||
public Endpoint imap_endpoint { get; private set; }
|
||||
public Endpoint smtp_endpoint { get; private set; }
|
||||
|
||||
internal File settings_dir { get; private set; }
|
||||
|
||||
internal AccountSettings(AccountInformation info) throws EngineError {
|
||||
email = new RFC822.MailboxAddress(info.real_name, info.email);
|
||||
real_name = info.real_name;
|
||||
credentials = info.credentials;
|
||||
imap_credentials = info.imap_credentials;
|
||||
smtp_credentials = info.smtp_credentials;
|
||||
service_provider = info.service_provider;
|
||||
imap_server_pipeline = info.imap_server_pipeline;
|
||||
imap_endpoint = info.get_imap_endpoint();
|
||||
smtp_endpoint = info.get_smtp_endpoint();
|
||||
|
||||
settings_dir = info.settings_dir;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,17 +6,22 @@
|
|||
|
||||
public interface Geary.Account : Object {
|
||||
public enum Problem {
|
||||
LOGIN_FAILED,
|
||||
RECV_EMAIL_LOGIN_FAILED,
|
||||
SEND_EMAIL_LOGIN_FAILED,
|
||||
HOST_UNREACHABLE,
|
||||
NETWORK_UNAVAILABLE,
|
||||
DATABASE_FAILURE
|
||||
}
|
||||
|
||||
public abstract Geary.AccountSettings settings { get; protected set; }
|
||||
|
||||
public signal void opened();
|
||||
|
||||
public signal void closed();
|
||||
|
||||
public signal void report_problem(Geary.Account.Problem problem, Geary.Credentials? credentials,
|
||||
public signal void email_sent(Geary.RFC822.Message rfc822);
|
||||
|
||||
public signal void report_problem(Geary.Account.Problem problem, Geary.AccountSettings settings,
|
||||
Error? err);
|
||||
|
||||
public signal void folders_added_removed(Gee.Collection<Geary.Folder>? added,
|
||||
|
|
@ -32,11 +37,16 @@ public interface Geary.Account : Object {
|
|||
*/
|
||||
protected abstract void notify_closed();
|
||||
|
||||
/**
|
||||
* Signal notification method for subclasses to use.
|
||||
*/
|
||||
protected abstract void notify_email_sent(Geary.RFC822.Message rfc822);
|
||||
|
||||
/**
|
||||
* Signal notification method for subclasses to use.
|
||||
*/
|
||||
protected abstract void notify_report_problem(Geary.Account.Problem problem,
|
||||
Geary.Credentials? credentials, Error? err);
|
||||
Geary.AccountSettings? settings, Error? err);
|
||||
|
||||
/**
|
||||
* Signal notification method for subclasses to use.
|
||||
|
|
@ -93,6 +103,15 @@ public interface Geary.Account : Object {
|
|||
public abstract async Geary.Folder fetch_folder_async(Geary.FolderPath path,
|
||||
Cancellable? cancellable = null) throws Error;
|
||||
|
||||
/**
|
||||
* Submits a ComposedEmail for delivery. Messages may be scheduled for later delivery or immediately
|
||||
* sent. Subscribe to the "email-sent" signal to be notified of delivery. Note that that signal
|
||||
* does not return the ComposedEmail object but an RFC822-formatted object. Allowing for the
|
||||
* subscriber to attach some kind of token for later comparison is being considered.
|
||||
*/
|
||||
public abstract async void send_email_async(Geary.ComposedEmail composed, Cancellable? cancellable = null)
|
||||
throws Error;
|
||||
|
||||
/**
|
||||
* Used only for debugging. Should not be used for user-visible strings.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -4,17 +4,43 @@
|
|||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Credentials represent a username and a password authenticating a user for access to a resource.
|
||||
* More sophisticated schemes exist; this suffices for now.
|
||||
*
|
||||
* Either property (user, pass) may be null. This indicates the Credentials are incomplete and
|
||||
* need further information (i.e. prompt user for username, fetch password from keyring, etc.)
|
||||
* Either field may be a non-null zero-length string; this is considered valid and is_complete()
|
||||
* will return true in this case.
|
||||
*
|
||||
* Note that Geary will hold Credentials in memory for the long-term, usually the duration of the
|
||||
* application. This is because network resources often have to be connected (or reconnected) to
|
||||
* in the background and asking the user to reauthenticate each time is deemed inconvenient.
|
||||
*/
|
||||
|
||||
public class Geary.Credentials {
|
||||
public string user { get; private set; }
|
||||
public string pass { get; set; }
|
||||
public string? user { get; set; }
|
||||
public string? pass { get; set; }
|
||||
|
||||
/**
|
||||
* user and pass may be null here, but the properties will always be a non-null zero-length
|
||||
* string. See is_empty().
|
||||
*/
|
||||
public Credentials(string? user, string? pass) {
|
||||
this.user = user ?? "";
|
||||
this.pass = pass ?? "";
|
||||
this.user = user;
|
||||
this.pass = pass;
|
||||
}
|
||||
|
||||
public bool is_complete() {
|
||||
return (user != null) && (pass != null);
|
||||
}
|
||||
|
||||
public Credentials copy() {
|
||||
return new Credentials(user, pass);
|
||||
}
|
||||
|
||||
public string to_string() {
|
||||
return "%s".printf(user);
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@
|
|||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An Endpoint represents the location of an Internet TCP connection as represented by a host,
|
||||
* a port, and flags and other parameters that specify the nature of the connection itself.
|
||||
*/
|
||||
|
||||
public class Geary.Endpoint : Object {
|
||||
[Flags]
|
||||
public enum Flags {
|
||||
|
|
@ -21,6 +26,12 @@ public class Geary.Endpoint : Object {
|
|||
}
|
||||
}
|
||||
|
||||
public enum AttemptStarttls {
|
||||
YES,
|
||||
NO,
|
||||
HALT
|
||||
}
|
||||
|
||||
public string host_specifier { get; private set; }
|
||||
public uint16 default_port { get; private set; }
|
||||
public Flags flags { get; private set; }
|
||||
|
|
@ -69,7 +80,27 @@ public class Geary.Endpoint : Object {
|
|||
|
||||
return cx;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if a STARTTLS command should be attempted on the connection:
|
||||
* (a) STARTTLS is reported available (a parameter specified by the caller to this method),
|
||||
* (b) not using SSL (so TLS is not required), and (c) STARTTLS is specified as a flag on
|
||||
* the Endpoint.
|
||||
*
|
||||
* If AttemptStarttls.HALT is returned, the caller should not proceed to pass any
|
||||
* authentication information down the connection; this situation indicates the connection is
|
||||
* insecure and the Endpoint is configured otherwise.
|
||||
*/
|
||||
public AttemptStarttls attempt_starttls(bool starttls_available) {
|
||||
if (is_ssl || !use_starttls)
|
||||
return AttemptStarttls.NO;
|
||||
|
||||
if (!starttls_available)
|
||||
return AttemptStarttls.HALT;
|
||||
|
||||
return AttemptStarttls.YES;
|
||||
}
|
||||
|
||||
public string to_string() {
|
||||
return "%s/default:%u".printf(host_specifier, default_port);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
/* Copyright 2011-2012 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 abstract class Geary.EngineAccount : Geary.AbstractAccount {
|
||||
public virtual Geary.AccountSettings settings { get; private set; }
|
||||
|
||||
public virtual signal void email_sent(Geary.RFC822.Message rfc822) {
|
||||
}
|
||||
|
||||
internal EngineAccount(string name, AccountSettings settings) {
|
||||
base (name);
|
||||
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
protected virtual void notify_email_sent(Geary.RFC822.Message rfc822) {
|
||||
email_sent(rfc822);
|
||||
}
|
||||
|
||||
public abstract async void send_email_async(Geary.ComposedEmail composed, Cancellable? cancellable = null)
|
||||
throws Error;
|
||||
}
|
||||
|
|
@ -9,7 +9,11 @@ public class Geary.Engine {
|
|||
public static File? resource_dir { get; private set; default = null; }
|
||||
|
||||
private static bool inited = false;
|
||||
|
||||
|
||||
/**
|
||||
* Geary.Engine.init() should be the first call any application makes prior to calling into
|
||||
* the Geary engine.
|
||||
*/
|
||||
public static void init(File _user_data_dir, File _resource_dir) {
|
||||
if (inited)
|
||||
return;
|
||||
|
|
@ -23,9 +27,18 @@ public class Geary.Engine {
|
|||
inited = true;
|
||||
}
|
||||
|
||||
// Returns a list of usernames associated with Geary.
|
||||
public static Gee.List<string> get_usernames() throws Error {
|
||||
Gee.ArrayList<string> list = new Gee.ArrayList<string>();
|
||||
/**
|
||||
* Returns a list of AccountInformation objects representing accounts setup for use by the Geary
|
||||
* engine.
|
||||
*/
|
||||
public static Gee.List<AccountInformation> get_accounts() throws Error {
|
||||
Gee.ArrayList<AccountInformation> list = new Gee.ArrayList<AccountInformation>();
|
||||
|
||||
if (!inited) {
|
||||
debug("Geary.Engine.get_accounts(): not initialized");
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
FileEnumerator enumerator = user_data_dir.enumerate_children("standard::*",
|
||||
FileQueryInfoFlags.NONE);
|
||||
|
|
@ -33,9 +46,22 @@ public class Geary.Engine {
|
|||
FileInfo? info = null;
|
||||
while ((info = enumerator.next_file()) != null) {
|
||||
if (info.get_file_type() == FileType.DIRECTORY)
|
||||
list.add(info.get_name());
|
||||
list.add(new AccountInformation(user_data_dir.get_child(info.get_name())));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Geary.AccountInformation for the specified email address. If the account
|
||||
* has not been set up previously, an object is returned, although it's merely backed by memory
|
||||
* and filled with defaults. Otherwise, the account information for that address is loaded.
|
||||
*
|
||||
* "email" in this case means the Internet mailbox for the account, i.e. username@domain.com.
|
||||
* Use the "address" field of RFC822.MailboxAddress for this parameter.
|
||||
*/
|
||||
public static Geary.AccountInformation get_account_for_email(string email) throws Error {
|
||||
return new Geary.AccountInformation(user_data_dir.get_child(email));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,11 +18,6 @@ private class Geary.ImapDB.Account : Object {
|
|||
// Only available when the Account is opened
|
||||
public SmtpOutboxFolder? outbox { get; private set; default = null; }
|
||||
|
||||
// TODO: This should be updated when Geary no longer assumes username is email.
|
||||
public string account_owner_email {
|
||||
get { return settings.credentials.user; }
|
||||
}
|
||||
|
||||
private string name;
|
||||
private AccountSettings settings;
|
||||
private ImapDB.Database? db = null;
|
||||
|
|
@ -34,7 +29,7 @@ private class Geary.ImapDB.Account : Object {
|
|||
this.settings = settings;
|
||||
contact_store = new ContactStore();
|
||||
|
||||
name = "IMAP database account for %s".printf(settings.credentials.user);
|
||||
name = "IMAP database account for %s".printf(settings.imap_credentials.user);
|
||||
}
|
||||
|
||||
private void check_open() throws Error {
|
||||
|
|
@ -47,7 +42,7 @@ private class Geary.ImapDB.Account : Object {
|
|||
if (db != null)
|
||||
throw new EngineError.ALREADY_OPEN("IMAP database already open");
|
||||
|
||||
db = new ImapDB.Database(user_data_dir, schema_dir, account_owner_email);
|
||||
db = new ImapDB.Database(user_data_dir, schema_dir, settings.email.address);
|
||||
|
||||
try {
|
||||
db.open(Db.DatabaseFlags.CREATE_DIRECTORY | Db.DatabaseFlags.CREATE_FILE, null,
|
||||
|
|
@ -361,7 +356,7 @@ private class Geary.ImapDB.Account : Object {
|
|||
}
|
||||
|
||||
// create folder
|
||||
folder = new Geary.ImapDB.Folder(db, path, contact_store, account_owner_email, folder_id,
|
||||
folder = new Geary.ImapDB.Folder(db, path, contact_store, settings.email.address, folder_id,
|
||||
properties);
|
||||
|
||||
// build a reference to it
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@ private class Geary.SmtpOutboxFolder : Geary.AbstractFolder, Geary.FolderSupport
|
|||
}
|
||||
}
|
||||
|
||||
public signal void report_problem(Geary.Account.Problem problem, Geary.AccountSettings settings,
|
||||
Error? err);
|
||||
|
||||
private static FolderRoot? path = null;
|
||||
|
||||
private ImapDB.Database db;
|
||||
|
|
@ -119,6 +122,9 @@ private class Geary.SmtpOutboxFolder : Geary.AbstractFolder, Geary.FolderSupport
|
|||
} catch (Error send_err) {
|
||||
debug("Outbox postman send error, retrying: %s", send_err.message);
|
||||
|
||||
if (send_err is SmtpError.AUTHENTICATION_FAILED)
|
||||
report_problem(Geary.Account.Problem.SEND_EMAIL_LOGIN_FAILED, settings, send_err);
|
||||
|
||||
try {
|
||||
outbox_queue.send(row);
|
||||
} catch (Error send_err) {
|
||||
|
|
@ -477,7 +483,7 @@ private class Geary.SmtpOutboxFolder : Geary.AbstractFolder, Geary.FolderSupport
|
|||
|
||||
private async void send_email_async(Geary.RFC822.Message rfc822, Cancellable? cancellable)
|
||||
throws Error {
|
||||
yield smtp.login_async(settings.credentials, cancellable);
|
||||
yield smtp.login_async(settings.smtp_credentials, cancellable);
|
||||
try {
|
||||
yield smtp.send_email_async(rfc822, cancellable);
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
private abstract class Geary.ImapEngine.GenericAccount : Geary.EngineAccount {
|
||||
private abstract class Geary.ImapEngine.GenericAccount : Geary.AbstractAccount {
|
||||
private static Geary.FolderPath? inbox_path = null;
|
||||
private static Geary.FolderPath? outbox_path = null;
|
||||
|
||||
|
|
@ -52,8 +52,10 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.EngineAccount {
|
|||
if (open)
|
||||
throw new EngineError.ALREADY_OPEN("Account %s already opened", to_string());
|
||||
|
||||
yield local.open_async(Engine.user_data_dir.get_child(settings.credentials.user),
|
||||
Engine.resource_dir.get_child("sql"), cancellable);
|
||||
yield local.open_async(settings.settings_dir, Engine.resource_dir.get_child("sql"), cancellable);
|
||||
|
||||
// outbox is now available
|
||||
local.outbox.report_problem.connect(notify_report_problem);
|
||||
|
||||
// need to back out local.open_async() if remote fails
|
||||
try {
|
||||
|
|
@ -78,6 +80,8 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.EngineAccount {
|
|||
if (!open)
|
||||
return;
|
||||
|
||||
local.outbox.report_problem.disconnect(notify_report_problem);
|
||||
|
||||
// attempt to close both regardless of errors
|
||||
Error? local_err = null;
|
||||
try {
|
||||
|
|
@ -316,7 +320,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.EngineAccount {
|
|||
}
|
||||
|
||||
private void on_login_failed(Geary.Credentials? credentials) {
|
||||
notify_report_problem(Geary.Account.Problem.LOGIN_FAILED, credentials, null);
|
||||
notify_report_problem(Geary.Account.Problem.RECV_EMAIL_LOGIN_FAILED, settings, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ private class Geary.Imap.Account : Object {
|
|||
public signal void login_failed(Geary.Credentials cred);
|
||||
|
||||
public Account(Geary.AccountSettings settings) {
|
||||
name = "IMAP Account for %s".printf(settings.credentials.to_string());
|
||||
name = "IMAP Account for %s".printf(settings.imap_credentials.to_string());
|
||||
this.settings = settings;
|
||||
|
||||
session_mgr = new ClientSessionManager(settings);
|
||||
|
|
@ -185,7 +185,7 @@ private class Geary.Imap.Account : Object {
|
|||
}
|
||||
|
||||
private void on_login_failed() {
|
||||
login_failed(settings.credentials);
|
||||
login_failed(settings.imap_credentials);
|
||||
}
|
||||
|
||||
public string to_string() {
|
||||
|
|
|
|||
|
|
@ -17,30 +17,15 @@ public class Geary.Imap.Capabilities : Geary.GenericCapabilities {
|
|||
* example).
|
||||
*/
|
||||
public Capabilities(int revision) {
|
||||
base ("=");
|
||||
|
||||
this.revision = revision;
|
||||
}
|
||||
|
||||
public bool add_parameter(StringParameter stringp) {
|
||||
string[] tokens = stringp.value.split("=", 2);
|
||||
if (tokens.length == 1)
|
||||
add_capability(tokens[0]);
|
||||
else if (tokens.length == 2)
|
||||
add_capability(tokens[0], tokens[1]);
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return parse_and_add_capability(stringp.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like get_setting(), but returns a StringParameter representing the capability.
|
||||
*/
|
||||
public StringParameter? get_parameter(string name) {
|
||||
string? setting = get_setting(name);
|
||||
|
||||
return new StringParameter(String.is_empty(setting) ? name : "%s=%s".printf(name, setting));
|
||||
}
|
||||
|
||||
public override string to_string() {
|
||||
return "#%d: %s".printf(revision, base.to_string());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ public class Geary.Imap.ClientSessionManager {
|
|||
|
||||
try {
|
||||
yield new_session.connect_async(cancellable);
|
||||
yield new_session.initiate_session_async(settings.credentials, cancellable);
|
||||
yield new_session.initiate_session_async(settings.imap_credentials, cancellable);
|
||||
} catch (Error err) {
|
||||
debug("[%s] Connect failure: %s", new_session.to_string(), err.message);
|
||||
|
||||
|
|
|
|||
|
|
@ -547,7 +547,7 @@ public class Geary.Imap.ClientSession {
|
|||
* Performs the LOGIN command using the supplied credentials. See initiate_session_async() for
|
||||
* a more full-featured version of login_async().
|
||||
*/
|
||||
public async void login_async(Geary.Credentials credentials, Cancellable? cancellable = null)
|
||||
public async CommandResponse login_async(Geary.Credentials credentials, Cancellable? cancellable = null)
|
||||
throws Error {
|
||||
LoginParams params = new LoginParams(credentials.user, credentials.pass, cancellable,
|
||||
login_async.callback);
|
||||
|
|
@ -558,6 +558,11 @@ public class Geary.Imap.ClientSession {
|
|||
|
||||
if (params.err != null)
|
||||
throw params.err;
|
||||
|
||||
// No Error means a response had better be available
|
||||
assert(params.cmd_response != null);
|
||||
|
||||
return params.cmd_response;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -572,28 +577,48 @@ public class Geary.Imap.ClientSession {
|
|||
|
||||
Imap.Capabilities caps = get_capabilities();
|
||||
|
||||
// Attempt TLS if specified or if available and not an SSL connection
|
||||
debug("[%s] use_starttls=%s is_ssl=%s starttls=%s", to_string(), imap_endpoint.use_starttls.to_string(),
|
||||
imap_endpoint.is_ssl.to_string(), caps.has_capability(Capabilities.STARTTLS).to_string());
|
||||
if (imap_endpoint.use_starttls
|
||||
|| (!imap_endpoint.is_ssl && caps.has_capability(Capabilities.STARTTLS))) {
|
||||
debug("[%s] Attempting STARTTLS...", to_string());
|
||||
CommandResponse resp = yield send_command_async(new StarttlsCommand());
|
||||
if (resp.status_response.status == Status.OK) {
|
||||
yield cx.starttls_async(cancellable);
|
||||
debug("[%s] STARTTLS completed", to_string());
|
||||
} else {
|
||||
debug("[%s} STARTTLS refused: %s", to_string(), resp.status_response.to_string());
|
||||
switch (imap_endpoint.attempt_starttls(caps.has_capability(Capabilities.STARTTLS))) {
|
||||
case Endpoint.AttemptStarttls.YES:
|
||||
debug("[%s] Attempting STARTTLS...", to_string());
|
||||
CommandResponse resp;
|
||||
try {
|
||||
resp = yield send_command_async(new StarttlsCommand());
|
||||
} catch (Error err) {
|
||||
debug("Error attempting STARTTLS command on %s: %s", to_string(), err.message);
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
// throw an exception and fail rather than send credentials under suspect
|
||||
// conditions
|
||||
throw new ImapError.NOT_SUPPORTED("STARTTLS refused by %s: %s", to_string(),
|
||||
resp.status_response.to_string());
|
||||
}
|
||||
if (resp.status_response.status == Status.OK) {
|
||||
yield cx.starttls_async(cancellable);
|
||||
debug("[%s] STARTTLS completed", to_string());
|
||||
} else {
|
||||
debug("[%s} STARTTLS refused: %s", to_string(), resp.status_response.to_string());
|
||||
|
||||
// throw an exception and fail rather than send credentials under suspect
|
||||
// conditions
|
||||
throw new ImapError.NOT_SUPPORTED("STARTTLS refused by %s: %s", to_string(),
|
||||
resp.status_response.to_string());
|
||||
}
|
||||
break;
|
||||
|
||||
case Endpoint.AttemptStarttls.NO:
|
||||
debug("[%s] No STARTTLS attempted", to_string());
|
||||
break;
|
||||
|
||||
case Endpoint.AttemptStarttls.HALT:
|
||||
default:
|
||||
throw new ImapError.NOT_SUPPORTED("STARTTLS unavailable for %s", to_string());
|
||||
}
|
||||
|
||||
// Login after STARTTLS
|
||||
yield login_async(credentials, cancellable);
|
||||
CommandResponse login_resp = yield login_async(credentials, cancellable);
|
||||
if (login_resp.status_response.status != Status.OK) {
|
||||
throw new ImapError.UNAUTHENTICATED("Unable to login to %s with supplied credentials",
|
||||
to_string());
|
||||
}
|
||||
|
||||
// if new capabilities not offered after login, get them now
|
||||
if (caps.revision == get_capabilities().revision)
|
||||
|
|
|
|||
|
|
@ -26,5 +26,9 @@ public interface Geary.Smtp.Authenticator : Object {
|
|||
* server. Generally this leaves the connection in a bad state and should be closed.
|
||||
*/
|
||||
public abstract uint8[]? challenge(int step, Response response) throws SmtpError;
|
||||
|
||||
public virtual string to_string() {
|
||||
return get_name();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
public class Geary.Smtp.Capabilities : Geary.GenericCapabilities {
|
||||
public static const string STARTTLS = "starttls";
|
||||
|
||||
public Capabilities(){
|
||||
public Capabilities() {
|
||||
base ("=");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,30 +56,39 @@ public class Geary.Smtp.ClientConnection {
|
|||
public async Response authenticate_async(Authenticator authenticator, Cancellable? cancellable = null)
|
||||
throws Error {
|
||||
check_connected();
|
||||
|
||||
// Use STARTTLS if it has been explicitly enabled or if the server supports it and we are
|
||||
// not using SSL encryption.
|
||||
Response response;
|
||||
if (endpoint.use_starttls || (!endpoint.is_ssl && capabilities.has_capability(Capabilities.STARTTLS))) {
|
||||
response = yield transaction_async(new Request(Command.STARTTLS));
|
||||
if (!response.code.is_starttls_ready()) {
|
||||
throw new SmtpError.STARTTLS_FAILED("STARTTLS failed: %s", response.to_string());
|
||||
}
|
||||
|
||||
// TLS started, lets wrap the connection and shake hands.
|
||||
TlsClientConnection tls_cx = TlsClientConnection.new(cx, socket_cx.get_remote_address());
|
||||
cx = tls_cx;
|
||||
tls_cx.set_validation_flags(TlsCertificateFlags.UNKNOWN_CA);
|
||||
set_data_streams(tls_cx);
|
||||
yield tls_cx.handshake_async(Priority.DEFAULT, cancellable);
|
||||
|
||||
// Now that we are on an encrypted line we need to say hello again in order to get the
|
||||
// updated capabilities.
|
||||
yield say_hello_async(cancellable);
|
||||
|
||||
switch (endpoint.attempt_starttls(capabilities.has_capability(Capabilities.STARTTLS))) {
|
||||
case Endpoint.AttemptStarttls.YES:
|
||||
Response response = yield transaction_async(new Request(Command.STARTTLS));
|
||||
if (!response.code.is_starttls_ready()) {
|
||||
throw new SmtpError.STARTTLS_FAILED("STARTTLS failed: %s", response.to_string());
|
||||
}
|
||||
|
||||
// TLS started, lets wrap the connection and shake hands.
|
||||
TlsClientConnection tls_cx = TlsClientConnection.new(cx, socket_cx.get_remote_address());
|
||||
cx = tls_cx;
|
||||
tls_cx.set_validation_flags(TlsCertificateFlags.UNKNOWN_CA);
|
||||
set_data_streams(tls_cx);
|
||||
yield tls_cx.handshake_async(Priority.DEFAULT, cancellable);
|
||||
|
||||
// Now that we are on an encrypted line we need to say hello again in order to get the
|
||||
// updated capabilities.
|
||||
yield say_hello_async(cancellable);
|
||||
break;
|
||||
|
||||
case Endpoint.AttemptStarttls.NO:
|
||||
// do nothing
|
||||
break;
|
||||
|
||||
case Endpoint.AttemptStarttls.HALT:
|
||||
default:
|
||||
throw new SmtpError.NOT_SUPPORTED("STARTTLS not available for %s", endpoint.to_string());
|
||||
}
|
||||
|
||||
response = yield transaction_async(authenticator.initiate(), cancellable);
|
||||
|
||||
|
||||
Response response = yield transaction_async(authenticator.initiate(), cancellable);
|
||||
|
||||
debug("Initiating SMTP %s authentication", authenticator.to_string());
|
||||
|
||||
// Possible for initiate() Request to:
|
||||
// (a) immediately generate success (due to valid authentication being passed in Request);
|
||||
// (b) immediately fails;
|
||||
|
|
@ -92,14 +101,17 @@ public class Geary.Smtp.ClientConnection {
|
|||
uint8[]? data = authenticator.challenge(step++, response);
|
||||
if (data == null || data.length == 0)
|
||||
data = DataFormat.CANCEL_AUTHENTICATION.data;
|
||||
|
||||
|
||||
Logging.debug(Logging.Flag.NETWORK, "[%s] SMTP AUTH Response: %s <%ldb>", to_string(),
|
||||
data.length);
|
||||
|
||||
yield Stream.write_all_async(douts, data, 0, -1, Priority.DEFAULT, cancellable);
|
||||
douts.put_string(DataFormat.LINE_TERMINATOR);
|
||||
yield douts.flush_async(Priority.DEFAULT, cancellable);
|
||||
|
||||
|
||||
response = yield recv_response_async(cancellable);
|
||||
}
|
||||
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
|
@ -120,6 +132,8 @@ public class Geary.Smtp.ClientConnection {
|
|||
if (!response.code.is_start_data())
|
||||
return response;
|
||||
|
||||
Logging.debug(Logging.Flag.NETWORK, "[%s] SMTP Data: <%ldb>", data.length);
|
||||
|
||||
yield Stream.write_all_async(douts, data, 0, -1, Priority.DEFAULT, cancellable);
|
||||
douts.put_string(DataFormat.DATA_TERMINATOR);
|
||||
yield douts.flush_async(Priority.DEFAULT, cancellable);
|
||||
|
|
@ -130,6 +144,8 @@ public class Geary.Smtp.ClientConnection {
|
|||
public async void send_request_async(Request request, Cancellable? cancellable = null) throws Error {
|
||||
check_connected();
|
||||
|
||||
Logging.debug(Logging.Flag.NETWORK, "[%s] SMTP Request: %s", to_string(), request.to_string());
|
||||
|
||||
douts.put_string(request.serialize());
|
||||
douts.put_string(DataFormat.LINE_TERMINATOR);
|
||||
yield douts.flush_async(Priority.DEFAULT, cancellable);
|
||||
|
|
@ -150,12 +166,15 @@ public class Geary.Smtp.ClientConnection {
|
|||
// lines should never be empty; if it is, then somebody didn't throw an exception
|
||||
assert(lines.size > 0);
|
||||
|
||||
return new Response(lines);
|
||||
Response response = new Response(lines);
|
||||
Logging.debug(Logging.Flag.NETWORK, "[%s] SMTP Response: %s", to_string(), response.to_string());
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public async Response say_hello_async(Cancellable? cancellable = null) throws Error {
|
||||
// try EHLO first, then fall back on HELO
|
||||
Response response = yield transaction_async(new Request(Command.EHLO), cancellable);
|
||||
Response response = yield transaction_async(new EhloRequest.for_endpoint(endpoint), cancellable);
|
||||
if (response.code.is_success_completed()) {
|
||||
// save list of caps returned in EHLO command, skipping first line because it's the
|
||||
// EHLO response
|
||||
|
|
@ -165,10 +184,14 @@ public class Geary.Smtp.ClientConnection {
|
|||
capabilities.add_capability(response.lines[ctr].explanation);
|
||||
}
|
||||
} else {
|
||||
response = yield transaction_async(new Request(Command.HELO), cancellable);
|
||||
if (!response.code.is_success_completed())
|
||||
throw new SmtpError.SERVER_ERROR("Refused service: %s", response.to_string());
|
||||
string first_response = response.to_string().strip();
|
||||
response = yield transaction_async(new HeloRequest.for_endpoint(endpoint), cancellable);
|
||||
if (!response.code.is_success_completed()) {
|
||||
throw new SmtpError.SERVER_ERROR("Refused service: \"%s\" and \"%s\"", first_response,
|
||||
response.to_string().strip());
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
|
@ -180,7 +203,7 @@ public class Geary.Smtp.ClientConnection {
|
|||
public async Response transaction_async(Request request, Cancellable? cancellable = null)
|
||||
throws Error {
|
||||
yield send_request_async(request, cancellable);
|
||||
|
||||
|
||||
return yield recv_response_async(cancellable);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ public errordomain Geary.SmtpError {
|
|||
SERVER_ERROR,
|
||||
ALREADY_CONNECTED,
|
||||
NOT_CONNECTED,
|
||||
REQUIRED_FIELD
|
||||
REQUIRED_FIELD,
|
||||
NOT_SUPPORTED
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,26 @@ public class Geary.Smtp.Request {
|
|||
}
|
||||
}
|
||||
|
||||
public class Geary.Smtp.HeloRequest : Geary.Smtp.Request {
|
||||
public HeloRequest(string domain) {
|
||||
base (Command.HELO, { domain });
|
||||
}
|
||||
|
||||
public HeloRequest.for_endpoint(Geary.Endpoint endpoint) {
|
||||
this (endpoint.host_specifier);
|
||||
}
|
||||
}
|
||||
|
||||
public class Geary.Smtp.EhloRequest : Geary.Smtp.Request {
|
||||
public EhloRequest(string domain) {
|
||||
base (Command.EHLO, { domain });
|
||||
}
|
||||
|
||||
public EhloRequest.for_endpoint(Geary.Endpoint endpoint) {
|
||||
this (endpoint.host_specifier);
|
||||
}
|
||||
}
|
||||
|
||||
public class Geary.Smtp.MailRequest : Geary.Smtp.Request {
|
||||
public MailRequest(Geary.RFC822.MailboxAddress from) {
|
||||
base (Command.MAIL, { "from:%s".printf(from.get_simple_address()) });
|
||||
|
|
|
|||
|
|
@ -5,22 +5,37 @@
|
|||
*/
|
||||
|
||||
public class Geary.GenericCapabilities : Object {
|
||||
private Gee.ArrayList<string> list = new Gee.ArrayList<string>(String.stri_equal);
|
||||
private Gee.HashMap<string, string?> map = new Gee.HashMap<string, string?>(
|
||||
String.stri_hash, String.stri_equal);
|
||||
public string separator { get; private set; }
|
||||
|
||||
private Gee.HashMultiMap<string, string?> map = new Gee.HashMultiMap<string, string?>(
|
||||
String.stri_hash, String.stri_equal, String.nullable_stri_hash, String.nullable_stri_equal);
|
||||
|
||||
/**
|
||||
* Creates an empty set of capabilities.
|
||||
*/
|
||||
public GenericCapabilities(){
|
||||
public GenericCapabilities(string separator) {
|
||||
assert(!String.is_empty(separator));
|
||||
|
||||
this.separator = separator;
|
||||
}
|
||||
|
||||
public bool is_empty() {
|
||||
return map.is_empty;
|
||||
return (map.size == 0);
|
||||
}
|
||||
|
||||
public bool parse_and_add_capability(string text) {
|
||||
string[] tokens = text.split(separator, 2);
|
||||
if (tokens.length == 1)
|
||||
add_capability(tokens[0]);
|
||||
else if (tokens.length == 2)
|
||||
add_capability(tokens[0], tokens[1]);
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void add_capability(string name, string? setting = null) {
|
||||
list.add(name);
|
||||
map.set(name, String.is_empty(setting) ? null : setting);
|
||||
}
|
||||
|
||||
|
|
@ -28,7 +43,7 @@ public class Geary.GenericCapabilities : Object {
|
|||
* Returns true only if the capability was named as available by the server.
|
||||
*/
|
||||
public bool has_capability(string name) {
|
||||
return map.has_key(name);
|
||||
return map.contains(name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -36,40 +51,57 @@ public class Geary.GenericCapabilities : Object {
|
|||
* by the server.
|
||||
*/
|
||||
public bool has_setting(string name, string? setting) {
|
||||
if (!map.has_key(name)) {
|
||||
if (!map.contains(name))
|
||||
return false;
|
||||
} else if (String.is_empty(setting)) {
|
||||
|
||||
if (String.is_empty(setting))
|
||||
return true;
|
||||
} else {
|
||||
string? stored_setting = map.get(name);
|
||||
return !String.is_empty(stored_setting) && String.stri_equal(stored_setting, setting);
|
||||
}
|
||||
|
||||
return map.get(name).contains(setting);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null if either the capability is available but has no associated setting, or if the
|
||||
* Returns null if either the capability is available but has no associated settings, or if the
|
||||
* capability is not available. Thus, use has_capability() to determine if available, then
|
||||
* this method to get its value (if one is expected). Often has_setting() is a better choice.
|
||||
*/
|
||||
public string? get_setting(string name) {
|
||||
return map.get(name);
|
||||
public Gee.Collection<string>? get_settings(string name) {
|
||||
Gee.Collection<string> settings = map.get(name);
|
||||
|
||||
return (settings.size > 0) ? settings : null;
|
||||
}
|
||||
|
||||
public Gee.List<string> get_all_names() {
|
||||
return list.read_only_view;
|
||||
public Gee.Set<string>? get_all_names() {
|
||||
Gee.Set<string> names = map.get_keys();
|
||||
|
||||
return (names.size > 0) ? names : null;
|
||||
}
|
||||
|
||||
private void append(StringBuilder builder, string text) {
|
||||
if (!String.is_empty(builder.str))
|
||||
builder.append_c(' ');
|
||||
|
||||
builder.append(text);
|
||||
}
|
||||
|
||||
public virtual string to_string() {
|
||||
Gee.Set<string>? names = get_all_names();
|
||||
if (names == null || names.size == 0)
|
||||
return "";
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
foreach (string name in list) {
|
||||
if (!String.is_empty(builder.str))
|
||||
builder.append_c(' ');
|
||||
|
||||
string? setting = map.get(name);
|
||||
if (String.is_empty(setting))
|
||||
builder.append(name);
|
||||
else
|
||||
builder.append_printf("%s=%s", name, setting);
|
||||
foreach (string name in names) {
|
||||
Gee.Collection<string>? settings = get_settings(name);
|
||||
if (settings == null || settings.size == 0) {
|
||||
append(builder, name);
|
||||
} else {
|
||||
foreach (string setting in settings) {
|
||||
if (String.is_empty(setting))
|
||||
append(builder, name);
|
||||
else
|
||||
append(builder, "%s%s%s".printf(name, separator, setting));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return builder.str;
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ extern string glib_substring(string str, long start_pos, long end_pos);
|
|||
|
||||
namespace Geary.String {
|
||||
|
||||
public inline bool is_null_or_whitespace(string? str) {
|
||||
return (str == null || str.strip()[0] == 0);
|
||||
public bool is_empty_or_whitespace(string? str) {
|
||||
return (str == null || str[0] == 0 || str.strip()[0] == 0);
|
||||
}
|
||||
|
||||
public inline bool is_empty(string? str) {
|
||||
|
|
@ -50,10 +50,25 @@ public uint stri_hash(void *str) {
|
|||
return str_hash(((string *) str)->down());
|
||||
}
|
||||
|
||||
public uint nullable_stri_hash(void *str) {
|
||||
return (str != null) ? stri_hash(str) : 0;
|
||||
}
|
||||
|
||||
public bool stri_equal(void *a, void *b) {
|
||||
return str_equal(((string *) a)->down(), ((string *) b)->down());
|
||||
}
|
||||
|
||||
public bool nullable_stri_equal(void *a, void *b) {
|
||||
if (a == null)
|
||||
return (b == null);
|
||||
|
||||
// a != null, so always false
|
||||
if (b == null)
|
||||
return false;
|
||||
|
||||
return stri_equal(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns char from 0 to 9 converted to an int. If a non-numeric value, -1 is returned.
|
||||
*/
|
||||
|
|
|
|||
518
ui/login.glade
518
ui/login.glade
|
|
@ -54,7 +54,7 @@
|
|||
<property name="row_spacing">2</property>
|
||||
<property name="column_spacing">4</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="username">
|
||||
<object class="GtkEntry" id="entry: email">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
|
|
@ -73,7 +73,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="password">
|
||||
<object class="GtkEntry" id="entry: password">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
|
|
@ -92,13 +92,13 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label: username">
|
||||
<object class="GtkLabel" id="label: email">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">_Email address:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">username</property>
|
||||
<property name="mnemonic_widget">entry: email</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
|
|
@ -114,7 +114,7 @@
|
|||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">_Password:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">password</property>
|
||||
<property name="mnemonic_widget">entry: password</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
|
|
@ -124,7 +124,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="service">
|
||||
<object class="GtkComboBoxText" id="combo: service">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
|
|
@ -143,7 +143,7 @@
|
|||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">_Service:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">service</property>
|
||||
<property name="mnemonic_widget">combo: service</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
|
|
@ -159,7 +159,7 @@
|
|||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">N_ame:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">real_name</property>
|
||||
<property name="mnemonic_widget">entry: real_name</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
|
|
@ -169,7 +169,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="real_name">
|
||||
<object class="GtkEntry" id="entry: real_name">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
|
|
@ -187,7 +187,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="remember_password">
|
||||
<object class="GtkCheckButton" id="check: remember_password">
|
||||
<property name="label" translatable="yes">Re_member password</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="visible">True</property>
|
||||
|
|
@ -217,18 +217,20 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="other_info">
|
||||
<object class="GtkAlignment" id="container: other_info">
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkGrid" id="grid1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="row_spacing">2</property>
|
||||
<property name="column_spacing">4</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label1">
|
||||
<object class="GtkLabel" id="label: imap">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="ypad">12</property>
|
||||
<property name="ypad">10</property>
|
||||
<property name="label" translatable="yes">IMAP settings</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
|
|
@ -249,7 +251,7 @@
|
|||
<property name="xpad">12</property>
|
||||
<property name="label" translatable="yes">Se_rver:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">imap host</property>
|
||||
<property name="mnemonic_widget">entry: imap host</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
|
|
@ -259,7 +261,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="imap host">
|
||||
<object class="GtkEntry" id="entry: imap host">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
|
|
@ -281,7 +283,7 @@
|
|||
<property name="xpad">12</property>
|
||||
<property name="label" translatable="yes">P_ort:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">imap port</property>
|
||||
<property name="mnemonic_widget">entry: imap port</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">2</property>
|
||||
|
|
@ -291,7 +293,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="imap port">
|
||||
<object class="GtkEntry" id="entry: imap port">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">•</property>
|
||||
|
|
@ -307,43 +309,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label: smtp">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">8</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="ypad">12</property>
|
||||
<property name="label" translatable="yes">SMTP settings</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">5</property>
|
||||
<property name="width">4</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label: host1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="xpad">10</property>
|
||||
<property name="label" translatable="yes">Ser_ver:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">smtp host</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">6</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="smtp host">
|
||||
<object class="GtkEntry" id="entry: smtp host">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">•</property>
|
||||
|
|
@ -352,30 +318,13 @@
|
|||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">6</property>
|
||||
<property name="top_attach">9</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label: port1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="xpad">12</property>
|
||||
<property name="label" translatable="yes">Por_t:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">smtp port</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">2</property>
|
||||
<property name="top_attach">6</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="smtp port">
|
||||
<object class="GtkEntry" id="entry: smtp port">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">•</property>
|
||||
|
|
@ -385,140 +334,393 @@
|
|||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">3</property>
|
||||
<property name="top_attach">6</property>
|
||||
<property name="top_attach">9</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="smtp none">
|
||||
<property name="label" translatable="yes">No encrypt_ion</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="margin_left">12</property>
|
||||
<property name="margin_right">12</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">7</property>
|
||||
<property name="width">4</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="smtp starttls">
|
||||
<property name="label" translatable="yes">STARTTLS aut_hentication</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="margin_left">12</property>
|
||||
<property name="margin_right">12</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<property name="group">smtp none</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">9</property>
|
||||
<property name="width">4</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="smtp ssl">
|
||||
<property name="label" translatable="yes">SSL/TLS encr_yption</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="margin_left">12</property>
|
||||
<property name="margin_right">12</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<property name="group">smtp none</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">8</property>
|
||||
<property name="width">4</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="imap none">
|
||||
<object class="GtkRadioButton" id="radio: imap none">
|
||||
<property name="label" translatable="yes">_No encryption</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="margin_left">12</property>
|
||||
<property name="margin_right">12</property>
|
||||
<property name="margin_top">2</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="width">4</property>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">5</property>
|
||||
<property name="width">3</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="imap starttls">
|
||||
<object class="GtkRadioButton" id="radio: imap starttls">
|
||||
<property name="label" translatable="yes">STARTTLS a_uthentication</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="margin_left">12</property>
|
||||
<property name="margin_right">12</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<property name="group">imap none</property>
|
||||
<property name="group">radio: imap none</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">4</property>
|
||||
<property name="width">4</property>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">7</property>
|
||||
<property name="width">3</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="imap ssl">
|
||||
<object class="GtkRadioButton" id="radio: imap ssl">
|
||||
<property name="label" translatable="yes">SS_L/TLS encryption</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="margin_left">12</property>
|
||||
<property name="margin_right">12</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<property name="group">imap none</property>
|
||||
<property name="group">radio: imap none</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">6</property>
|
||||
<property name="width">3</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="radio: smtp starttls">
|
||||
<property name="label" translatable="yes">STARTTLS aut_hentication</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.50999999046325684</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<property name="group">radio: smtp none</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">15</property>
|
||||
<property name="width">3</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="radio: smtp ssl">
|
||||
<property name="label" translatable="yes">SSL/TLS encr_yption</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<property name="group">radio: smtp none</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">14</property>
|
||||
<property name="width">3</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="radio: smtp none">
|
||||
<property name="label" translatable="yes">No encrypt_ion</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="margin_top">2</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">13</property>
|
||||
<property name="width">3</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label: smtp host">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="xpad">12</property>
|
||||
<property name="label" translatable="yes">Ser_ver:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">entry: smtp host</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">9</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label: smtp port">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="xpad">12</property>
|
||||
<property name="label" translatable="yes">Por_t:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">entry: smtp port</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">2</property>
|
||||
<property name="top_attach">9</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label: smtp">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">8</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="ypad">10</property>
|
||||
<property name="label" translatable="yes">SMTP settings</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">8</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label: smtp username">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="xpad">12</property>
|
||||
<property name="label" translatable="yes">Username:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">10</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label: smtp password">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="xpad">12</property>
|
||||
<property name="label" translatable="yes">Password:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">11</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="entry: smtp username">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">•</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">10</property>
|
||||
<property name="width">3</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="entry: smtp password">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="visibility">False</property>
|
||||
<property name="invisible_char">•</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">11</property>
|
||||
<property name="width">3</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="check: smtp remember_password">
|
||||
<property name="label" translatable="yes">Remember password</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">12</property>
|
||||
<property name="width">3</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label: imap username">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="xpad">12</property>
|
||||
<property name="label" translatable="yes">Username:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label: imap password">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="xpad">12</property>
|
||||
<property name="label" translatable="yes">Password:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="width">4</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="entry: imap username">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">•</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="width">3</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="entry: imap password">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="visibility">False</property>
|
||||
<property name="invisible_char">•</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="width">3</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="check: imap remember_password">
|
||||
<property name="label" translatable="yes">Remember password</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">4</property>
|
||||
<property name="width">3</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label: imap encryption">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">2</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="xpad">12</property>
|
||||
<property name="label" translatable="yes">Encryption:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">5</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label: smtp encryption">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">2</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="xpad">12</property>
|
||||
<property name="label" translatable="yes">Encryption:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">13</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
|
|
|||
|
|
@ -55,33 +55,18 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid" id="grid1">
|
||||
<object class="GtkGrid" id="grid: imap">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<property name="column_spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label2">
|
||||
<object class="GtkLabel" id="label for: imap username">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Email address:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">_Password:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">password_entry</property>
|
||||
<property name="xpad">6</property>
|
||||
<property name="label" translatable="yes">Username:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
|
|
@ -91,7 +76,24 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="email_label">
|
||||
<object class="GtkLabel" id="label for: imap password">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="xpad">6</property>
|
||||
<property name="label" translatable="yes">_Password:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">entry: imap password</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label: imap username">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
|
|
@ -100,13 +102,13 @@
|
|||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="password_entry">
|
||||
<object class="GtkEntry" id="entry: imap password">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
|
|
@ -117,13 +119,13 @@
|
|||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="remember_password_checkbutton">
|
||||
<object class="GtkCheckButton" id="check: imap remember_password">
|
||||
<property name="label" translatable="yes">_Remember password</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="visible">True</property>
|
||||
|
|
@ -136,11 +138,28 @@
|
|||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label: imap">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">IMAP Credentials</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="width">2</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
|
|
@ -151,6 +170,115 @@
|
|||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid" id="grid: smtp">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<property name="column_spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label: smtp">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">SMTP Credentials</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="width">2</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label for: smtp username">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="xpad">6</property>
|
||||
<property name="label" translatable="yes">Username:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label for: smtp password">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="xpad">6</property>
|
||||
<property name="label" translatable="yes">Password:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label: smtp username">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="xpad">2</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="entry: smtp password">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="visibility">False</property>
|
||||
<property name="invisible_char">•</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="check: smtp remember_password">
|
||||
<property name="label" translatable="yes">Remember password</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkExpander" id="expander1">
|
||||
<property name="visible">True</property>
|
||||
|
|
@ -163,7 +291,7 @@
|
|||
<property name="row_spacing">6</property>
|
||||
<property name="column_spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label5">
|
||||
<object class="GtkLabel" id="label for: service">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
|
|
@ -178,7 +306,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label6">
|
||||
<object class="GtkLabel" id="label for: real_name">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
|
|
@ -193,7 +321,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="service_label">
|
||||
<object class="GtkLabel" id="label: service">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
|
|
@ -206,7 +334,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="real_name_label">
|
||||
<object class="GtkLabel" id="label: real_name">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
|
|
@ -219,7 +347,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="general_category_label">
|
||||
<object class="GtkLabel" id="label: general">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
|
|
@ -237,7 +365,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="imap_settings_category_label">
|
||||
<object class="GtkLabel" id="label: imap settings">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">6</property>
|
||||
|
|
@ -256,7 +384,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label8">
|
||||
<object class="GtkLabel" id="label for: imap server">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
|
|
@ -271,7 +399,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label9">
|
||||
<object class="GtkLabel" id="label for: imap port">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
|
|
@ -286,7 +414,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label10">
|
||||
<object class="GtkLabel" id="label for: imap encryption">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
|
|
@ -301,7 +429,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="imap_server_label">
|
||||
<object class="GtkLabel" id="label: imap server">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
|
|
@ -314,7 +442,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="imap_port_label">
|
||||
<object class="GtkLabel" id="label: imap port">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
|
|
@ -327,7 +455,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="imap_encryption_label">
|
||||
<object class="GtkLabel" id="label: imap encryption">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
|
|
@ -340,7 +468,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="smtp_settings_category_label">
|
||||
<object class="GtkLabel" id="label: smtp settings">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">6</property>
|
||||
|
|
@ -359,7 +487,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label12">
|
||||
<object class="GtkLabel" id="label for: smtp server">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
|
|
@ -374,7 +502,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label13">
|
||||
<object class="GtkLabel" id="label for: smtp port">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
|
|
@ -389,7 +517,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label14">
|
||||
<object class="GtkLabel" id="label for: smtp encryption">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
|
|
@ -404,7 +532,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="smtp_server_label">
|
||||
<object class="GtkLabel" id="label: smtp server">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
|
|
@ -417,7 +545,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="smtp_port_label">
|
||||
<object class="GtkLabel" id="label: smtp port">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
|
|
@ -430,7 +558,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="smtp_encryption_label">
|
||||
<object class="GtkLabel" id="label: smtp encryption">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
|
|
@ -454,7 +582,7 @@
|
|||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel" id="label4">
|
||||
<object class="GtkLabel" id="label: details">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">_Details</property>
|
||||
|
|
@ -465,7 +593,7 @@
|
|||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue