X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmoonshot-identity-manager-app.vala;h=03088ebb95dcd5302520da488da31dbe79a17ecb;hb=95831118f79914d0e685a0bfe929570c414527d3;hp=a65dd60ec6efc25296e06e9f489a5670e2ce8d5d;hpb=b7ddf2ce912daa935cb5ced2468a47c65922de10;p=moonshot-ui.git diff --git a/src/moonshot-identity-manager-app.vala b/src/moonshot-identity-manager-app.vala index a65dd60..03088eb 100644 --- a/src/moonshot-identity-manager-app.vala +++ b/src/moonshot-identity-manager-app.vala @@ -1,20 +1,250 @@ +using Gee; using Gtk; -class IdentityManagerApp : Window { +#if IPC_DBUS +[DBus (name = "org.janet.Moonshot")] +interface IIdentityManager : GLib.Object { +#if IPC_DBUS_GLIB + public abstract bool show_ui() throws DBus.Error; +#else + public abstract bool show_ui() throws IOError; +#endif +} +#endif + +public class IdentityManagerApp { public IdentityManagerModel model; - private IdentityManagerView view; + public IdCard default_id_card; + public bool explicitly_launched; + public IdentityManagerView view; private MoonshotServer ipc_server; + +#if OS_MACOS + public OSXApplication osxApp; + + // the signal handler function. + // the current instance of our app class is passed in the + // id_manager_app_instanceparameter + public static bool on_osx_open_files (OSXApplication osx_app_instance, + string file_name, + IdentityManagerApp id_manager_app_instance ) { + int added_cards = id_manager_app_instance.ipc_server.install_from_file(file_name); + return true; + } +#endif + private const int WINDOW_WIDTH = 400; private const int WINDOW_HEIGHT = 500; + public void show() { + if (view != null) view.show(); + } + + public IdentityManagerApp (bool headless, bool use_flat_file_store) { + use_flat_file_store |= UserForcesFlatFileStore(); +#if GNOME_KEYRING + bool keyring_available = (!use_flat_file_store) && GnomeKeyring.is_available(); +#else + bool keyring_available = false; +#endif + IIdentityCardStore.StoreType store_type; + if (headless || use_flat_file_store || !keyring_available) + store_type = IIdentityCardStore.StoreType.FLAT_FILE; + else + store_type = IIdentityCardStore.StoreType.KEYRING; + + model = new IdentityManagerModel(this, store_type); + /* if headless, but we have nothing in the flat file store + * and keyring is available, switch to keyring */ + if (headless && keyring_available && !use_flat_file_store && !model.HasNonTrivialIdentities()) + model.set_store_type(IIdentityCardStore.StoreType.KEYRING); + + if (!headless) + view = new IdentityManagerView(this); + LinkedList card_list = model.get_card_list() ; + if (card_list.size > 0) + this.default_id_card = card_list.first(); - public IdentityManagerApp () { - model = new IdentityManagerModel(this); - view = new IdentityManagerView(this); init_ipc_server (); - view.show(); + +#if OS_MACOS + + osxApp = OSXApplication.get_instance(); + // The 'correct' way of connrcting wont work in Mac OS with Vala 0.12 e.g. + // osxApp.ns_application_open_file.connect(install_from_file); + // so we have to use this old way + Signal.connect(osxApp, "NSApplicationOpenFile", (GLib.Callback)(on_osx_open_files), this); + +#endif + } + + public bool add_identity (IdCard id, bool force_flat_file_store) { + if (view != null) return view.add_identity(id, force_flat_file_store); + model.add_card(id, force_flat_file_store); + return true; + } + + public void select_identity (IdentityRequest request) { + IdCard identity = null; + + if (request.select_default) + { + identity = default_id_card; + } + + if (identity == null) + { + bool has_nai = request.nai != null && request.nai != ""; + bool has_srv = request.service != null && request.service != ""; + bool confirm = false; + IdCard nai_provided = null; + + foreach (IdCard id in model.get_card_list()) + { + /* If NAI matches we add id card to the candidate list */ + if (has_nai && request.nai == id.nai) + { + nai_provided = id; + request.candidates.append (id); + continue; + } + + /* If any service matches we add id card to the candidate list */ + if (has_srv) + { + foreach (string srv in id.services) + { + if (request.service == srv) + { + request.candidates.append (id); + continue; + } + } + } + } + + /* If more than one candidate we dissasociate service from all ids */ + if (has_srv && request.candidates.length() > 1) + { + foreach (IdCard id in request.candidates) + { + int i = 0; + SList services_list = null; + bool has_service = false; + + foreach (string srv in id.services) + { + if (srv == request.service) + { + has_service = true; + continue; + } + services_list.append (srv); + } + + if (!has_service) + continue; + + if (services_list.length () == 0) + { + id.services = {}; + continue; + } + + string[] services = new string[services_list.length ()]; + foreach (string srv in services_list) + { + services[i] = srv; + i++; + } + + id.services = services; + } + } + +// model.store_id_cards (); + + /* If there are no candidates we use the service matching rules */ + if (request.candidates.length () == 0) + { + foreach (IdCard id in model.get_card_list()) + { + foreach (Rule rule in id.rules) + { + if (!match_service_pattern (request.service, rule.pattern)) + continue; + + request.candidates.append (id); + + if (rule.always_confirm == "true") + confirm = true; + } + } + } + + if (request.candidates.length () > 1) + { + if (has_nai && nai_provided != null) + { + identity = nai_provided; + confirm = false; + } + else + confirm = true; + } + if (identity == null) + identity = request.candidates.nth_data (0); + if ((identity != null) && + ((identity.password == null) || (identity.password == ""))) + identity.password = request.password; + if (identity == null) { + if (has_nai) { + // create a temp identity + string[] components = request.nai.split("@", 2); + identity = new IdCard(); + identity.display_name = request.nai; + identity.username = components[0]; + if (components.length > 1) + identity.issuer = components[1]; + identity.password = request.password; + } else { + confirm = true; + } + } + + /* TODO: If candidate list empty return fail */ + + if (confirm && (view != null)) + { + if (!explicitly_launched) + show(); + view.queue_identity_request(request); + return; + } + } + // Send back the identity (we can't directly run the + // callback because we may be being called from a 'yield') + Idle.add( + () => { + if (view != null) { + identity = view.check_add_password(identity, request, model); + } + request.return_identity (identity); +// The following occasionally causes the app to exit without sending the dbus +// reply, so for now we just don't exit +// if (!explicitly_launched) +// Idle.add( () => { Gtk.main_quit(); return false; } ); + return false; + } + ); + return; + } + + private bool match_service_pattern (string service, string pattern) + { + var pspec = new PatternSpec (pattern); + return pspec.match_string (service); } - #if IPC_MSRPC private void init_ipc_server () { @@ -22,7 +252,7 @@ class IdentityManagerApp : Window { // obtrusive message box, on Windows // this.ipc_server = MoonshotServer.get_instance (); - MoonshotServer.start (this.view); + MoonshotServer.start (this); } #elif IPC_DBUS_GLIB private void init_ipc_server () @@ -35,10 +265,26 @@ class IdentityManagerApp : Window { // try to register service in session bus uint reply = bus.request_name ("org.janet.Moonshot", (uint) 0); - assert (reply == DBus.RequestNameReply.PRIMARY_OWNER); + if (reply == DBus.RequestNameReply.PRIMARY_OWNER) + { + this.ipc_server = new MoonshotServer (this); + conn.register_object ("/org/janet/moonshot", ipc_server); + } else { + bool shown=false; + GLib.Error e; + DBus.Object manager_proxy = conn.get_object ("org.janet.Moonshot", + "/org/janet/moonshot", + "org.janet.Moonshot"); + if (manager_proxy != null) + manager_proxy.call("ShowUi", out e, GLib.Type.INVALID, typeof(bool), out shown, GLib.Type.INVALID); - this.ipc_server = new MoonshotServer (this.view); - conn.register_object ("/org/janet/moonshot", ipc_server); + if (!shown) { + GLib.error ("Couldn't own name org.janet.Moonshot on dbus or show previously launched identity manager."); + } else { + stdout.printf("Showed previously launched identity manager.\n"); + GLib.Process.exit(0); + } + } } catch (DBus.Error e) { @@ -59,22 +305,73 @@ class IdentityManagerApp : Window { private void init_ipc_server () { - this.ipc_server = new MoonshotServer (this.view); + this.ipc_server = new MoonshotServer (this); GLib.Bus.own_name (GLib.BusType.SESSION, "org.janet.Moonshot", GLib.BusNameOwnerFlags.NONE, bus_acquired_cb, (conn, name) => {}, (conn, name) => { - error ("Couldn't own name %s on DBus.", name); + bool shown=false; + try { + IIdentityManager manager = Bus.get_proxy_sync (BusType.SESSION, name, "/org/janet/moonshot"); + shown = manager.show_ui(); + } catch (IOError e) { + } + if (!shown) { + GLib.error ("Couldn't own name %s on dbus or show previously launched identity manager.", name); + } else { + stdout.printf("Showed previously launched identity manager.\n"); + GLib.Process.exit(0); + } }); } #endif } +static bool explicitly_launched = true; +static bool use_flat_file_store = false; +const GLib.OptionEntry[] options = { + {"dbus-launched",0,GLib.OptionFlags.REVERSE,GLib.OptionArg.NONE, + ref explicitly_launched,"launch for dbus rpc use",null}, + {"flat-file-store",0,0,GLib.OptionArg.NONE, + ref use_flat_file_store,"force use of flat file identity store (used by default only for headless operation)",null}, + {null} +}; + public static int main(string[] args){ - Gtk.init(ref args); +#if IPC_MSRPC + bool headless = false; +#else + bool headless = GLib.Environment.get_variable("DISPLAY") == null; +#endif + + if (headless) { + try { + var opt_context = new OptionContext(null); + opt_context.set_help_enabled (true); + opt_context.add_main_entries (options, null); + opt_context.parse(ref args); + } catch (OptionError e) { + stdout.printf(_("error: %s\n"),e.message); + stdout.printf(_("Run '%s --help' to see a full list of available options\n"), args[0]); + return -1; + } + explicitly_launched = false; + } else { + try { + if (!Gtk.init_with_args(ref args, _(""), options, null)) { + stdout.printf(_("unable to initialize window\n")); + return -1; + } + } catch (GLib.Error e) { + stdout.printf(_("error: %s\n"),e.message); + stdout.printf(_("Run '%s --help' to see a full list of available options\n"), args[0]); + return -1; + } + gtk_available = true; + } #if OS_WIN32 // Force specific theme settings on Windows without requiring a gtkrc file @@ -87,11 +384,22 @@ public static int main(string[] args){ Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8"); Intl.textdomain (Config.GETTEXT_PACKAGE); - var app = new IdentityManagerApp(); + + var app = new IdentityManagerApp(headless, use_flat_file_store); + app.explicitly_launched = explicitly_launched; - app.show(); + if (app.explicitly_launched) { + app.show(); + } - Gtk.main(); + if (headless) { +#if !IPC_MSRPC + MainLoop loop = new MainLoop(); + loop.run(); +#endif + } else { + Gtk.main(); + } return 0; }