diff --git a/src/client/geary-application.vala b/src/client/geary-application.vala index 57b20798..a4f4cc71 100644 --- a/src/client/geary-application.vala +++ b/src/client/geary-application.vala @@ -131,7 +131,7 @@ along with Geary; if not, write to the Free Software Foundation, Inc., Geary.Logging.log_to(stdout); return 0; - } + } public override int startup() { exec_dir = (File.new_for_path(Environment.find_program_in_path(args[0]))).get_parent(); @@ -227,11 +227,11 @@ along with Geary; if not, write to the Free Software Foundation, Inc., account_info.imap_server_host = login.imap_host; account_info.imap_server_port = login.imap_port; - account_info.imap_server_tls = login.imap_tls; + account_info.imap_server_ssl = login.imap_ssl; account_info.imap_server_pipeline = (login.provider != Geary.ServiceProvider.OTHER); account_info.smtp_server_host = login.smtp_host; account_info.smtp_server_port = login.smtp_port; - account_info.smtp_server_tls = login.smtp_tls; + account_info.smtp_server_ssl = login.smtp_ssl; } else { exit(1); return null; diff --git a/src/client/ui/geary-login.vala b/src/client/ui/geary-login.vala index ca8e77f2..a8c2be73 100644 --- a/src/client/ui/geary-login.vala +++ b/src/client/ui/geary-login.vala @@ -15,10 +15,10 @@ public class LoginDialog { private Gtk.Alignment other_info; private Gtk.Entry entry_imap_host; private Gtk.Entry entry_imap_port; - private Gtk.CheckButton check_imap_tls; + private Gtk.CheckButton check_imap_ssl; private Gtk.Entry entry_smtp_host; private Gtk.Entry entry_smtp_port; - private Gtk.CheckButton check_smtp_tls; + private Gtk.CheckButton check_smtp_ssl; private Gtk.ResponseType response; private Gtk.Button ok_button; @@ -34,12 +34,12 @@ public class LoginDialog { public string imap_host { get; private set; default = ""; } public uint16 imap_port { get; private set; - default = Geary.Imap.ClientConnection.DEFAULT_PORT_TLS; } - public bool imap_tls { get; private set; default = true; } + default = Geary.Imap.ClientConnection.DEFAULT_PORT_SSL; } + public bool imap_ssl { get; private set; default = true; } public string smtp_host { get; private set; default = ""; } public uint16 smtp_port { get; private set; - default = Geary.Smtp.ClientConnection.SECURE_SMTP_PORT; } - public bool smtp_tls { get; private set; default = true; } + default = Geary.Smtp.ClientConnection.DEFAULT_PORT_SSL; } + public bool smtp_ssl { get; private set; default = true; } public LoginDialog(string default_real_name = "", string default_username = "", string default_password = "", Geary.AccountInformation? default_account_info = null) { @@ -57,10 +57,10 @@ public class LoginDialog { other_info = builder.get_object("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; - check_imap_tls = builder.get_object("imap tls") as Gtk.CheckButton; + check_imap_ssl = builder.get_object("imap ssl") as Gtk.CheckButton; entry_smtp_host = builder.get_object("smtp host") as Gtk.Entry; entry_smtp_port = builder.get_object("smtp port") as Gtk.Entry; - check_smtp_tls = builder.get_object("smtp tls") as Gtk.CheckButton; + check_smtp_ssl = builder.get_object("smtp ssl") as Gtk.CheckButton; combo_service.changed.connect(on_service_changed); @@ -94,8 +94,8 @@ public class LoginDialog { entry_smtp_host.changed.connect(on_changed); entry_smtp_port.changed.connect(on_changed); - check_imap_tls.toggled.connect(on_check_imap_tls_toggled); - check_smtp_tls.toggled.connect(on_check_smtp_tls_toggled); + check_imap_ssl.toggled.connect(on_check_imap_ssl_toggled); + check_smtp_ssl.toggled.connect(on_check_smtp_ssl_toggled); entry_imap_port.insert_text.connect(on_port_insert_text); entry_smtp_port.insert_text.connect(on_port_insert_text); @@ -122,10 +122,10 @@ public class LoginDialog { provider = get_service_provider(); imap_host = entry_imap_host.text.strip(); imap_port = (uint16) int.parse(entry_imap_port.text.strip()); - imap_tls = check_imap_tls.active; + imap_ssl = check_imap_ssl.active; smtp_host = entry_smtp_host.text.strip(); smtp_port = (uint16) int.parse(entry_smtp_port.text.strip()); - smtp_tls = check_smtp_tls.active; + smtp_ssl = check_smtp_ssl.active; dialog.destroy(); } @@ -160,20 +160,20 @@ public class LoginDialog { } } - private void on_check_imap_tls_toggled() { + private void on_check_imap_ssl_toggled() { if (edited_imap_port) return; - entry_imap_port.text = (check_imap_tls.active ? Geary.Imap.ClientConnection.DEFAULT_PORT_TLS : + entry_imap_port.text = (check_imap_ssl.active ? Geary.Imap.ClientConnection.DEFAULT_PORT_SSL : Geary.Imap.ClientConnection.DEFAULT_PORT).to_string(); edited_imap_port = false; } - private void on_check_smtp_tls_toggled() { + private void on_check_smtp_ssl_toggled() { if (edited_smtp_port) return; - entry_smtp_port.text = (check_smtp_tls.active ? Geary.Smtp.ClientConnection.SECURE_SMTP_PORT : + entry_smtp_port.text = (check_smtp_ssl.active ? Geary.Smtp.ClientConnection.DEFAULT_PORT_SSL : Geary.Smtp.ClientConnection.DEFAULT_PORT).to_string(); edited_smtp_port = false; } diff --git a/src/console/main.vala b/src/console/main.vala index 68a22518..db96582b 100644 --- a/src/console/main.vala +++ b/src/console/main.vala @@ -279,8 +279,8 @@ class ImapConsole : Gtk.Window { check_args(cmd, args, 1, "hostname[:port]"); cx = new Geary.Imap.ClientConnection( - new Geary.Endpoint(args[0], Geary.Imap.ClientConnection.DEFAULT_PORT_TLS, - Geary.Endpoint.Flags.TLS | Geary.Endpoint.Flags.GRACEFUL_DISCONNECT, + new Geary.Endpoint(args[0], Geary.Imap.ClientConnection.DEFAULT_PORT_SSL, + Geary.Endpoint.Flags.SSL | Geary.Endpoint.Flags.GRACEFUL_DISCONNECT, Geary.Imap.ClientConnection.DEFAULT_TIMEOUT_SEC)); cx.sent_command.connect(on_sent_command); diff --git a/src/engine/api/geary-account-information.vala b/src/engine/api/geary-account-information.vala index 0ca45c8d..abdd48e0 100644 --- a/src/engine/api/geary-account-information.vala +++ b/src/engine/api/geary-account-information.vala @@ -10,24 +10,24 @@ public class Geary.AccountInformation : Object { private const string SERVICE_PROVIDER_KEY = "service_provider"; private const string IMAP_HOST = "imap_host"; private const string IMAP_PORT = "imap_port"; - private const string IMAP_TLS = "imap_tls"; + private const string IMAP_SSL = "imap_ssl"; private const string IMAP_PIPELINE = "imap_pipeline"; private const string SMTP_HOST = "smtp_host"; private const string SMTP_PORT = "smtp_port"; - private const string SMTP_TLS = "smtp_tls"; + private const string SMTP_SSL = "smtp_ssl"; internal File? file = null; public string real_name { get; set; } public Geary.ServiceProvider service_provider { get; set; } public string imap_server_host { get; set; default = ""; } - public uint16 imap_server_port { get; set; default = Imap.ClientConnection.DEFAULT_PORT_TLS; } - public bool imap_server_tls { get; set; default = true; } + public uint16 imap_server_port { get; set; default = Imap.ClientConnection.DEFAULT_PORT_SSL; } + public bool imap_server_ssl { get; set; default = true; } public bool imap_server_pipeline { get; set; default = true; } public string smtp_server_host { get; set; default = ""; } - public uint16 smtp_server_port { get; set; default = Smtp.ClientConnection.SECURE_SMTP_PORT; } - public bool smtp_server_tls { get; set; default = true; } + public uint16 smtp_server_port { get; set; default = Smtp.ClientConnection.DEFAULT_PORT_SSL; } + public bool smtp_server_ssl { get; set; default = true; } public AccountInformation() { } @@ -46,14 +46,14 @@ public class Geary.AccountInformation : Object { imap_server_host = get_string_value(key_file, GROUP, IMAP_HOST); imap_server_port = get_uint16_value(key_file, GROUP, IMAP_PORT, - Imap.ClientConnection.DEFAULT_PORT_TLS); - imap_server_tls = get_bool_value(key_file, GROUP, IMAP_TLS, true); + Imap.ClientConnection.DEFAULT_PORT_SSL); + imap_server_ssl = get_bool_value(key_file, GROUP, IMAP_SSL, true); imap_server_pipeline = get_bool_value(key_file, GROUP, IMAP_PIPELINE, true); smtp_server_host = get_string_value(key_file, GROUP, SMTP_HOST); smtp_server_port = get_uint16_value(key_file, GROUP, SMTP_PORT, - Geary.Smtp.ClientConnection.SECURE_SMTP_PORT); - smtp_server_tls = get_bool_value(key_file, GROUP, SMTP_TLS, true); + Geary.Smtp.ClientConnection.DEFAULT_PORT_SSL); + smtp_server_ssl = get_bool_value(key_file, GROUP, SMTP_SSL, true); } } @@ -99,12 +99,12 @@ public class Geary.AccountInformation : Object { key_file.set_value(GROUP, IMAP_HOST, imap_server_host); key_file.set_integer(GROUP, IMAP_PORT, imap_server_port); - key_file.set_boolean(GROUP, IMAP_TLS, imap_server_tls); + key_file.set_boolean(GROUP, IMAP_SSL, imap_server_ssl); key_file.set_boolean(GROUP, IMAP_PIPELINE, imap_server_pipeline); key_file.set_value(GROUP, SMTP_HOST, smtp_server_host); key_file.set_integer(GROUP, SMTP_PORT, smtp_server_port); - key_file.set_boolean(GROUP, SMTP_TLS, smtp_server_tls); + key_file.set_boolean(GROUP, SMTP_SSL, smtp_server_ssl); string data = key_file.to_data(); string new_etag; diff --git a/src/engine/api/geary-endpoint.vala b/src/engine/api/geary-endpoint.vala index 9b87c827..68f2a55b 100644 --- a/src/engine/api/geary-endpoint.vala +++ b/src/engine/api/geary-endpoint.vala @@ -8,7 +8,8 @@ public class Geary.Endpoint : Object { [Flags] public enum Flags { NONE = 0, - TLS, + SSL, + STARTTLS, GRACEFUL_DISCONNECT; public inline bool is_all_set(Flags flags) { @@ -37,30 +38,30 @@ public class Geary.Endpoint : Object { public SocketClient get_socket_client() { if (socket_client != null) return socket_client; - + socket_client = new SocketClient(); - - if (flags.is_all_set(Flags.TLS)) { + + if (flags.is_all_set(Flags.SSL)) { socket_client.set_tls(true); socket_client.set_tls_validation_flags(TlsCertificateFlags.UNKNOWN_CA); } - + socket_client.set_timeout(timeout_sec); - + return socket_client; } - + public async SocketConnection connect_async(Cancellable? cancellable = null) throws Error { SocketConnection cx = yield get_socket_client().connect_to_host_async(host_specifier, default_port, cancellable); - + TcpConnection? tcp = cx as TcpConnection; if (tcp != null) tcp.set_graceful_disconnect(flags.is_all_set(Flags.GRACEFUL_DISCONNECT)); - + return cx; } - + public string to_string() { return "%s/default:%u".printf(host_specifier, default_port); } diff --git a/src/engine/api/geary-engine.vala b/src/engine/api/geary-engine.vala index 08ec29f6..6b1e026e 100644 --- a/src/engine/api/geary-engine.vala +++ b/src/engine/api/geary-engine.vala @@ -50,11 +50,11 @@ public class Geary.Engine { account_info), new Geary.Sqlite.Account(cred, user_data_dir, resource_dir)); case ServiceProvider.OTHER: - Endpoint.Flags imap_flags = account_info.imap_server_tls ? Endpoint.Flags.TLS + Endpoint.Flags imap_flags = account_info.imap_server_ssl ? Endpoint.Flags.SSL : Endpoint.Flags.NONE; imap_flags |= Endpoint.Flags.GRACEFUL_DISCONNECT; - Endpoint.Flags smtp_flags = account_info.smtp_server_tls ? Endpoint.Flags.TLS + Endpoint.Flags smtp_flags = account_info.smtp_server_ssl ? Endpoint.Flags.SSL : Endpoint.Flags.NONE; smtp_flags |= Geary.Endpoint.Flags.GRACEFUL_DISCONNECT; diff --git a/src/engine/imap/transport/imap-client-connection.vala b/src/engine/imap/transport/imap-client-connection.vala index ced9ffb5..80105f20 100644 --- a/src/engine/imap/transport/imap-client-connection.vala +++ b/src/engine/imap/transport/imap-client-connection.vala @@ -6,7 +6,7 @@ public class Geary.Imap.ClientConnection { public const uint16 DEFAULT_PORT = 143; - public const uint16 DEFAULT_PORT_TLS = 993; + public const uint16 DEFAULT_PORT_SSL = 993; // TODO: This is set very high to allow for IDLE connections to remain connected even when // there is no traffic on them. The side-effect is that if the physical connection is dropped, diff --git a/src/engine/impl/geary-gmail-account.vala b/src/engine/impl/geary-gmail-account.vala index a8b07a2d..2ac93e2d 100644 --- a/src/engine/impl/geary-gmail-account.vala +++ b/src/engine/impl/geary-gmail-account.vala @@ -12,8 +12,8 @@ private class Geary.GmailAccount : Geary.GenericImapAccount { if (_imap_endpoint == null) { _imap_endpoint = new Geary.Endpoint( "imap.gmail.com", - Imap.ClientConnection.DEFAULT_PORT_TLS, - Geary.Endpoint.Flags.TLS | Geary.Endpoint.Flags.GRACEFUL_DISCONNECT, + Imap.ClientConnection.DEFAULT_PORT_SSL, + Geary.Endpoint.Flags.SSL | Geary.Endpoint.Flags.GRACEFUL_DISCONNECT, Imap.ClientConnection.DEFAULT_TIMEOUT_SEC); } @@ -25,8 +25,8 @@ private class Geary.GmailAccount : Geary.GenericImapAccount { if (_smtp_endpoint == null) { _smtp_endpoint = new Geary.Endpoint( "smtp.gmail.com", - Smtp.ClientConnection.SECURE_SMTP_PORT, - Geary.Endpoint.Flags.TLS | Geary.Endpoint.Flags.GRACEFUL_DISCONNECT, + Smtp.ClientConnection.DEFAULT_PORT_SSL, + Geary.Endpoint.Flags.SSL | Geary.Endpoint.Flags.GRACEFUL_DISCONNECT, Smtp.ClientConnection.DEFAULT_TIMEOUT_SEC); } diff --git a/src/engine/impl/geary-yahoo-account.vala b/src/engine/impl/geary-yahoo-account.vala index 7f9a6a45..d0a3508c 100644 --- a/src/engine/impl/geary-yahoo-account.vala +++ b/src/engine/impl/geary-yahoo-account.vala @@ -10,8 +10,8 @@ private class Geary.YahooAccount : Geary.GenericImapAccount { if (_imap_endpoint == null) { _imap_endpoint = new Geary.Endpoint( "imap.mail.yahoo.com", - Imap.ClientConnection.DEFAULT_PORT_TLS, - Geary.Endpoint.Flags.TLS | Geary.Endpoint.Flags.GRACEFUL_DISCONNECT, + Imap.ClientConnection.DEFAULT_PORT_SSL, + Geary.Endpoint.Flags.SSL | Geary.Endpoint.Flags.GRACEFUL_DISCONNECT, Imap.ClientConnection.DEFAULT_TIMEOUT_SEC); } @@ -23,8 +23,8 @@ private class Geary.YahooAccount : Geary.GenericImapAccount { if (_smtp_endpoint == null) { _smtp_endpoint = new Geary.Endpoint( "smtp.mail.yahoo.com", - Smtp.ClientConnection.SECURE_SMTP_PORT, - Geary.Endpoint.Flags.TLS | Geary.Endpoint.Flags.GRACEFUL_DISCONNECT, + Smtp.ClientConnection.DEFAULT_PORT_SSL, + Geary.Endpoint.Flags.SSL | Geary.Endpoint.Flags.GRACEFUL_DISCONNECT, Smtp.ClientConnection.DEFAULT_TIMEOUT_SEC); } diff --git a/src/engine/smtp/smtp-client-connection.vala b/src/engine/smtp/smtp-client-connection.vala index 824c3924..34ac4cb9 100644 --- a/src/engine/smtp/smtp-client-connection.vala +++ b/src/engine/smtp/smtp-client-connection.vala @@ -6,15 +6,17 @@ public class Geary.Smtp.ClientConnection { public const uint16 DEFAULT_PORT = 25; - public const uint16 SUBMISSION_PORT = 587; - public const uint16 SECURE_SMTP_PORT = 465; + public const uint16 DEFAULT_PORT_SSL = 465; + public const uint16 DEFAULT_PORT_STARTTLS = 587; public const uint DEFAULT_TIMEOUT_SEC = 60; private Geary.Endpoint endpoint; - private SocketConnection? cx = null; + private IOStream? cx = null; + private SocketConnection? socket_cx = null; private DataInputStream? dins = null; private DataOutputStream douts = null; + private Gee.List? capabilities = null; public ClientConnection(Geary.Endpoint endpoint) { this.endpoint = endpoint; @@ -31,11 +33,8 @@ public class Geary.Smtp.ClientConnection { return null; } - cx = yield endpoint.connect_async(cancellable); - - dins = new DataInputStream(cx.input_stream); - dins.set_newline_type(DataFormat.LINE_TERMINATOR_TYPE); - douts = new DataOutputStream(cx.output_stream); + cx = socket_cx = yield endpoint.connect_async(cancellable); + set_data_streams(cx); // read and deserialize the greeting return Greeting.deserialize(yield read_line_async(cancellable)); @@ -50,16 +49,35 @@ public class Geary.Smtp.ClientConnection { return true; } - + /** * Returns the final Response of the challenge-response. */ public async Response authenticate_async(Authenticator authenticator, Cancellable? cancellable = null) throws Error { check_connected(); - - Response response = yield transaction_async(authenticator.initiate(), cancellable); - + + Response response; + if (endpoint.flags.is_all_set(Endpoint.Flags.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); + } + + response = yield transaction_async(authenticator.initiate(), cancellable); + // Possible for initiate() Request to: // (a) immediately generate success (due to valid authentication being passed in Request); // (b) immediately fails; @@ -72,17 +90,17 @@ public class Geary.Smtp.ClientConnection { uint8[]? data = authenticator.challenge(step++, response); if (data == null || data.length == 0) data = DataFormat.CANCEL_AUTHENTICATION.data; - + 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; } - + /** * Sends a block of data (mail message) by first issuing the DATA command and transmitting * the block if the appropriate response is sent. The data block should *not* have the SMTP @@ -132,11 +150,35 @@ public class Geary.Smtp.ClientConnection { return new Response(lines); } - + + 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); + if (response.code.is_success_completed()) { + // save list of caps returned in EHLO command, skipping first line because it's the + // EHLO response + capabilities = new Gee.ArrayList(); + for (int ctr = 1; ctr < response.lines.size; ctr++) { + if (!String.is_empty(response.lines[ctr].explanation)) + capabilities.add(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()); + } + return response; + } + + public async Response quit_async(Cancellable? cancellable = null) throws Error { + capabilities = null; + return yield transaction_async(new Request(Command.QUIT), cancellable); + } + public async Response transaction_async(Request request, Cancellable? cancellable = null) throws Error { yield send_request_async(request, cancellable); - + return yield recv_response_async(cancellable); } @@ -158,5 +200,13 @@ public class Geary.Smtp.ClientConnection { public string to_string() { return endpoint.to_string(); } + + private void set_data_streams(IOStream stream) { + dins = new DataInputStream(stream.input_stream); + dins.set_newline_type(DataFormat.LINE_TERMINATOR_TYPE); + dins.set_close_base_stream(false); + douts = new DataOutputStream(stream.output_stream); + douts.set_close_base_stream(false); + } } diff --git a/src/engine/smtp/smtp-client-session.vala b/src/engine/smtp/smtp-client-session.vala index bdcc0594..84579876 100644 --- a/src/engine/smtp/smtp-client-session.vala +++ b/src/engine/smtp/smtp-client-session.vala @@ -6,7 +6,6 @@ public class Geary.Smtp.ClientSession { private ClientConnection cx; - private Gee.List? capabilities = null; private bool rset_required = false; public virtual signal void connected(Greeting greeting) { @@ -37,35 +36,21 @@ public class Geary.Smtp.ClientSession { public async Greeting? login_async(Credentials? creds, Cancellable? cancellable = null) throws Error { if (cx.is_connected()) throw new SmtpError.ALREADY_CONNECTED("Connection to %s already exists", to_string()); - + + // Greet the SMTP server. Greeting? greeting = yield cx.connect_async(cancellable); if (greeting == null) throw new SmtpError.ALREADY_CONNECTED("Connection to %s already exists", to_string()); - - // try EHLO first, then fall back on HELO - Response response = yield cx.transaction_async(new Request(Command.EHLO), cancellable); - if (response.code.is_success_completed()) { - // save list of caps returned in EHLO command, skipping first line because it's the - // EHLO response - capabilities = new Gee.ArrayList(); - for (int ctr = 1; ctr < response.lines.size; ctr++) { - if (!String.is_empty(response.lines[ctr].explanation)) - capabilities.add(response.lines[ctr].explanation); - } - } else { - response = yield cx.transaction_async(new Request(Command.HELO), cancellable); - if (!response.code.is_success_completed()) - throw new SmtpError.SERVER_ERROR("Refused service: %s", response.to_string()); - } - + yield cx.say_hello_async(cancellable); + notify_connected(greeting); - + // authenticate if credentials supplied (in almost every case they should be) // TODO: Select an authentication method based on AUTH capabilities line, falling back on // LOGIN or PLAIN if none match or are present if (creds != null) { Authenticator authenticator = new LoginAuthenticator(creds); - response = yield cx.authenticate_async(authenticator, cancellable); + Response response = yield cx.authenticate_async(authenticator, cancellable); if (!response.code.is_success_completed()) throw new SmtpError.AUTHENTICATION_FAILED("Unable to authenticate with %s", to_string()); @@ -74,11 +59,11 @@ public class Geary.Smtp.ClientSession { return greeting; } - + public async Response? logout_async(Cancellable? cancellable = null) throws Error { Response? response = null; try { - response = yield cx.transaction_async(new Request(Command.QUIT), cancellable); + response = yield cx.quit_async(cancellable); } catch (Error err) { // catch because although error occurred, still attempt to close the connection message("Unable to QUIT: %s", err.message); @@ -93,8 +78,7 @@ public class Geary.Smtp.ClientSession { } rset_required = false; - capabilities = null; - + return response; } diff --git a/src/engine/smtp/smtp-command.vala b/src/engine/smtp/smtp-command.vala index 88c27990..012610f6 100644 --- a/src/engine/smtp/smtp-command.vala +++ b/src/engine/smtp/smtp-command.vala @@ -14,7 +14,8 @@ public enum Geary.Smtp.Command { AUTH, MAIL, RCPT, - DATA; + DATA, + STARTTLS; public string serialize() { switch (this) { @@ -47,7 +48,10 @@ public enum Geary.Smtp.Command { case DATA: return "data"; - + + case STARTTLS: + return "starttls"; + default: assert_not_reached(); } @@ -84,7 +88,10 @@ public enum Geary.Smtp.Command { case "data": return DATA; - + + case "starttls": + return STARTTLS; + default: throw new SmtpError.PARSE_ERROR("Unknown command \"%s\"", str); } diff --git a/src/engine/smtp/smtp-error.vala b/src/engine/smtp/smtp-error.vala index cbcb691d..e3538f15 100644 --- a/src/engine/smtp/smtp-error.vala +++ b/src/engine/smtp/smtp-error.vala @@ -6,6 +6,7 @@ public errordomain Geary.SmtpError { PARSE_ERROR, + STARTTLS_FAILED, AUTHENTICATION_FAILED, SERVER_ERROR, ALREADY_CONNECTED, diff --git a/src/engine/smtp/smtp-response-code.vala b/src/engine/smtp/smtp-response-code.vala index a4c800c3..c731060a 100644 --- a/src/engine/smtp/smtp-response-code.vala +++ b/src/engine/smtp/smtp-response-code.vala @@ -11,6 +11,7 @@ public class Geary.Smtp.ResponseCode { public const int MAX = 599; public const string START_DATA_CODE = "354"; + public const string STARTTLS_READY_CODE = "220"; public enum Status { POSITIVE_PRELIMINARY = 1, @@ -95,11 +96,15 @@ public class Geary.Smtp.ResponseCode { return false; } } - + public bool is_start_data() { return str == START_DATA_CODE; } - + + public bool is_starttls_ready() { + return str == STARTTLS_READY_CODE; + } + public string serialize() { return str; } diff --git a/src/mailer/main.vala b/src/mailer/main.vala index a1e4899d..15ed0982 100644 --- a/src/mailer/main.vala +++ b/src/mailer/main.vala @@ -47,6 +47,7 @@ void on_main_completed(Object? object, AsyncResult result) { string arg_hostname; int arg_port = 25; +bool arg_debug = false; bool arg_gmail = false; bool arg_no_tls = false; string arg_user; @@ -55,6 +56,7 @@ string arg_from; string arg_to; int arg_count = 1; const OptionEntry[] options = { + { "debug", 0, 0, OptionArg.NONE, ref arg_debug, "Output debugging information", null }, { "host", 'h', 0, OptionArg.STRING, ref arg_hostname, "SMTP server host", "" }, { "port", 'P', 0, OptionArg.INT, ref arg_port, "SMTP server port", "" }, { "gmail", 'G', 0, OptionArg.NONE, ref arg_gmail, "Gmail SMTP (no-tls ignored)", null }, @@ -105,18 +107,22 @@ int main(string[] args) { arg_count = 1; if (arg_gmail) { - endpoint = new Geary.Endpoint("smtp.gmail.com", Geary.Smtp.ClientConnection.SECURE_SMTP_PORT, - Geary.Endpoint.Flags.TLS | Geary.Endpoint.Flags.GRACEFUL_DISCONNECT, + endpoint = new Geary.Endpoint("smtp.gmail.com", Geary.Smtp.ClientConnection.DEFAULT_PORT_STARTTLS, + Geary.Endpoint.Flags.STARTTLS | Geary.Endpoint.Flags.GRACEFUL_DISCONNECT, Geary.Smtp.ClientConnection.DEFAULT_TIMEOUT_SEC); } else { Geary.Endpoint.Flags flags = Geary.Endpoint.Flags.GRACEFUL_DISCONNECT; if (!arg_no_tls) - flags |= Geary.Endpoint.Flags.TLS; + flags |= Geary.Endpoint.Flags.SSL; endpoint = new Geary.Endpoint(arg_hostname, (uint16) arg_port, flags, Geary.Smtp.ClientConnection.DEFAULT_TIMEOUT_SEC); } - + + stdout.printf("Enabling debug: %s\n", arg_debug.to_string()); + if (arg_debug) + Geary.Logging.log_to(stdout); + credentials = new Geary.Credentials(arg_user, arg_pass); composed_email = new Geary.ComposedEmail(new DateTime.now_local(), diff --git a/ui/login.glade b/ui/login.glade index 9e29f779..cb4e1285 100644 --- a/ui/login.glade +++ b/ui/login.glade @@ -293,7 +293,7 @@ - + SS_L/TLS encryption False True @@ -398,7 +398,7 @@ - + SS_L/TLS encryption False True