4028, 3700 login dialog and password persistence
Adds a login dialog box Support for Glade UI files Gnome keyring for password storage Assumption of single Geary account (for now)
This commit is contained in:
parent
6a5d1fa048
commit
9d2b10530c
9 changed files with 302 additions and 16 deletions
|
|
@ -55,11 +55,38 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
base (NAME, "geary", "org.yorba.geary");
|
||||
}
|
||||
|
||||
public override void startup() {
|
||||
public override int startup() {
|
||||
config = new Configuration(YorbaApplication.instance.get_install_dir() != null,
|
||||
YorbaApplication.instance.get_exec_dir().get_child("build/src/client").get_path());
|
||||
|
||||
Geary.Credentials cred = new Geary.Credentials("imap.gmail.com", args[1], args[2]);
|
||||
// Get saved credentials. If not present, ask user.
|
||||
string username = "";
|
||||
string? password = null;
|
||||
try {
|
||||
Gee.List<string> accounts = Geary.Engine.get_usernames();
|
||||
if (accounts.size > 0) {
|
||||
username = accounts.get(0);
|
||||
password = keyring_get_password(username);
|
||||
}
|
||||
} catch (Error e) {
|
||||
debug("Unable to fetch accounts. Error: %s", e.message);
|
||||
}
|
||||
|
||||
if (password == null) {
|
||||
LoginDialog login = new LoginDialog(username);
|
||||
login.show();
|
||||
if (login.get_response() == Gtk.ResponseType.OK) {
|
||||
username = login.username;
|
||||
password = login.password;
|
||||
|
||||
// TODO: check credentials before saving password in keyring.
|
||||
keyring_save_password(username, password);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
Geary.Credentials cred = new Geary.Credentials("imap.gmail.com", username, password);
|
||||
|
||||
try {
|
||||
account = Geary.Engine.open(cred);
|
||||
|
|
@ -69,6 +96,7 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
main_window.show_all();
|
||||
main_window.start(account);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override void activate() {
|
||||
|
|
|
|||
|
|
@ -8,12 +8,6 @@ int main(string[] args) {
|
|||
// initialize GTK, which modifies the command-line arguments
|
||||
Gtk.init(ref args);
|
||||
|
||||
if (args.length != 3) {
|
||||
stderr.printf("usage: geary <user> <pass>\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
// if already registered, silently exit
|
||||
if (!GearyApplication.instance.register())
|
||||
|
|
|
|||
63
src/client/ui/geary-login.vala
Normal file
63
src/client/ui/geary-login.vala
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/* Copyright 2011 Yorba Foundation
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
// 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_password;
|
||||
private Gtk.ResponseType response;
|
||||
private Gtk.Button ok_button;
|
||||
|
||||
public string username { get; private set; default = ""; }
|
||||
public string password { get; private set; default = ""; }
|
||||
|
||||
public LoginDialog(string default_username = "", string default_password = "") {
|
||||
Gtk.Builder builder = YorbaApplication.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_username = builder.get_object("username") as Gtk.Entry;
|
||||
entry_password = builder.get_object("password") as Gtk.Entry;
|
||||
|
||||
entry_username.set_text(default_username);
|
||||
entry_password.set_text(default_password);
|
||||
|
||||
entry_username.changed.connect(on_changed);
|
||||
entry_password.changed.connect(on_changed);
|
||||
|
||||
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;
|
||||
dialog.add_action_widget(ok_button, Gtk.ResponseType.OK);
|
||||
dialog.set_default_response(Gtk.ResponseType.OK);
|
||||
}
|
||||
|
||||
// Runs the dialog.
|
||||
public void show() {
|
||||
dialog.show_all();
|
||||
response = (Gtk.ResponseType) dialog.run();
|
||||
username = entry_username.text.strip();
|
||||
password = entry_password.text.strip();
|
||||
dialog.destroy();
|
||||
}
|
||||
|
||||
// Call this after Show to get the response. Will either be OK or cancel.
|
||||
public Gtk.ResponseType get_response() {
|
||||
return response;
|
||||
}
|
||||
|
||||
private void on_changed() {
|
||||
ok_button.sensitive = is_complete();
|
||||
}
|
||||
|
||||
private bool is_complete() {
|
||||
return entry_username.text.strip() != "" && entry_password.text.strip() != "";
|
||||
}
|
||||
}
|
||||
25
src/client/util/util-keyring.vala
Normal file
25
src/client/util/util-keyring.vala
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* Copyright 2011 Yorba Foundation
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
const string GEARY_USERNAME_PREFIX = "org.yorba.geary username:";
|
||||
|
||||
public static void keyring_save_password(string username, string password) {
|
||||
string name = GEARY_USERNAME_PREFIX + username;
|
||||
|
||||
GnomeKeyring.Result res = GnomeKeyring.store_password_sync(GnomeKeyring.NETWORK_PASSWORD, null,
|
||||
name, password, "user", name);
|
||||
|
||||
assert(res == GnomeKeyring.Result.OK);
|
||||
}
|
||||
|
||||
// Returns the password for the given username, or null if not set.
|
||||
public static string? keyring_get_password(string username) {
|
||||
string password;
|
||||
GnomeKeyring.Result res = GnomeKeyring.find_password_sync(GnomeKeyring.NETWORK_PASSWORD, out password,
|
||||
"user", GEARY_USERNAME_PREFIX + username);
|
||||
|
||||
return res == GnomeKeyring.Result.OK ? password : null;
|
||||
}
|
||||
|
|
@ -8,21 +8,24 @@ client_src = [
|
|||
'geary-config.vala',
|
||||
'main.vala',
|
||||
|
||||
'ui/geary-login.vala',
|
||||
'ui/folder-list-store.vala',
|
||||
'ui/folder-list-view.vala',
|
||||
'ui/main-window.vala',
|
||||
'ui/message-buffer.vala',
|
||||
'ui/message-list-store.vala',
|
||||
'ui/message-list-view.vala',
|
||||
'ui/message-viewer.vala'
|
||||
'ui/message-viewer.vala',
|
||||
|
||||
'util/util-keyring.vala'
|
||||
]
|
||||
|
||||
gsettings_schemas = [
|
||||
'org.yorba.geary.gschema.xml'
|
||||
]
|
||||
|
||||
client_uselib = 'GLIB GEE GTK'
|
||||
client_packages = [ 'gtk+-2.0', 'glib-2.0', 'gee-1.0' ]
|
||||
client_uselib = 'GLIB GEE GTK GNOME-KEYRING'
|
||||
client_packages = [ 'gtk+-2.0', 'glib-2.0', 'gee-1.0', 'gnome-keyring-1' ]
|
||||
|
||||
app = bld.program(
|
||||
target = 'geary',
|
||||
|
|
|
|||
|
|
@ -37,7 +37,8 @@ public abstract class YorbaApplication {
|
|||
*
|
||||
* The args[] array will be available when this signal is fired.
|
||||
*/
|
||||
public virtual signal void startup() {
|
||||
public virtual signal int startup() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public virtual signal void activate() {
|
||||
|
|
@ -107,10 +108,11 @@ public abstract class YorbaApplication {
|
|||
exec_dir = (File.new_for_path(Environment.find_program_in_path(args[0]))).get_parent();
|
||||
|
||||
running = true;
|
||||
startup();
|
||||
exitcode = startup();
|
||||
|
||||
// enter the main loop
|
||||
Gtk.main();
|
||||
if (exitcode == 0)
|
||||
Gtk.main();
|
||||
|
||||
return exitcode;
|
||||
}
|
||||
|
|
@ -167,5 +169,18 @@ public abstract class YorbaApplication {
|
|||
File prefix_dir = File.new_for_path(PREFIX);
|
||||
return exec_dir.has_prefix(prefix_dir) ? prefix_dir : null;
|
||||
}
|
||||
|
||||
// Creates a GTK builder given the filename of a UI file in the ui directory.
|
||||
public Gtk.Builder create_builder(string ui_filename) {
|
||||
Gtk.Builder builder = new Gtk.Builder();
|
||||
try {
|
||||
builder.add_from_file(get_resource_directory().get_child("ui").get_child(
|
||||
ui_filename).get_path());
|
||||
} catch(GLib.Error error) {
|
||||
warning("Unable to create Gtk.Builder: %s".printf(error.message));
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,4 +20,20 @@ public class Geary.Engine {
|
|||
new Geary.Imap.Account(cred, Imap.ClientConnection.DEFAULT_PORT_TLS),
|
||||
new Geary.Sqlite.Account(cred));
|
||||
}
|
||||
|
||||
// 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>();
|
||||
|
||||
FileEnumerator enumerator = YorbaApplication.instance.get_user_data_directory().
|
||||
enumerate_children("standard::*", FileQueryInfoFlags.NONE);
|
||||
|
||||
FileInfo? info = null;
|
||||
while ((info = enumerator.next_file()) != null) {
|
||||
if (info.get_file_type() == FileType.DIRECTORY)
|
||||
list.add(info.get_name());
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
136
ui/login.glade
Normal file
136
ui/login.glade
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="2.24"/>
|
||||
<!-- interface-naming-policy project-wide -->
|
||||
<object class="GtkDialog" id="LoginDialog">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="border_width">5</property>
|
||||
<property name="type_hint">dialog</property>
|
||||
<child internal-child="vbox">
|
||||
<object class="GtkVBox" id="dialog-vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">2</property>
|
||||
<child internal-child="action_area">
|
||||
<object class="GtkHButtonBox" id="action area">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="layout_style">end</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="padding">6</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="welcome">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xpad">12</property>
|
||||
<property name="ypad">12</property>
|
||||
<property name="label" translatable="yes">Welcome to Geary.</property>
|
||||
<property name="wrap">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTable" id="table1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="n_rows">2</property>
|
||||
<property name="n_columns">2</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label: username">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Username:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options">GTK_FILL</property>
|
||||
<property name="x_padding">6</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label: password">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Password:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="x_padding">6</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="username">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">•</property>
|
||||
<property name="activates_default">True</property>
|
||||
<property name="width_chars">0</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="secondary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">True</property>
|
||||
<property name="secondary_icon_sensitive">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options">GTK_FILL</property>
|
||||
<property name="x_padding">6</property>
|
||||
<property name="y_padding">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="password">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="visibility">False</property>
|
||||
<property name="invisible_char">•</property>
|
||||
<property name="activates_default">True</property>
|
||||
<property name="invisible_char_set">True</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="secondary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">True</property>
|
||||
<property name="secondary_icon_sensitive">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_padding">6</property>
|
||||
<property name="y_padding">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
10
wscript
10
wscript
|
|
@ -80,17 +80,23 @@ def configure(conf):
|
|||
atleast_version='2.4.14',
|
||||
mandatory=1,
|
||||
args='--cflags --libs')
|
||||
|
||||
conf.check_cfg(
|
||||
package='gnome-keyring-1',
|
||||
uselib_store='GNOME-KEYRING',
|
||||
atleast_version='2.32.0',
|
||||
mandatory=1,
|
||||
args='--cflags --libs')
|
||||
|
||||
def build(bld):
|
||||
bld.add_post_fun(post_build)
|
||||
|
||||
bld.env.append_value('CFLAGS', ['-O2', '-g', '-D_PREFIX="' + bld.env.PREFIX + '"'])
|
||||
bld.env.append_value('LINKFLAGS', ['-O2', '-g'])
|
||||
bld.env.append_value('VALAFLAGS', ['-g', '--enable-checking', '--fatal-warnings'])
|
||||
bld.env.append_value('VALAFLAGS', ['-g', '--enable-checking', '--fatal-warnings'])
|
||||
|
||||
bld.recurse('src')
|
||||
|
||||
|
||||
def post_build(bld):
|
||||
# Copy executable to root folder.
|
||||
geary_path = 'build/src/client/geary'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue