// // OpenVPN Administrator // // Author(s): Everaldo Canuto // // (C) 2006 Everaldo Canuto // (C) 2006 The Gang // // This library is free software; you can redistribute it and/or // modify it undecr the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // using System; using Mono.Unix; using Gtk; using Gdk; #if MAEMO using Hildon; #endif namespace OpenVPN.Admin { public class MainWindow : BaseMainWindow { #region Fields private Gtk.Action actionQuit; private Gtk.Action actionNew; private Gtk.Action actionProperties; private Gtk.Action actionDelete; private Gtk.Action actionConnect; private Gtk.Action actionDisconnect; private Gtk.Action actionReconnect; private Gtk.Action actionRefresh; private Gtk.Action actionLog; private Gtk.Action actionWizard; private Gtk.Action actionCert; private Gtk.Action actionAbout; private Gtk.TreeView listView; private Gtk.ListStore listStore; private Gtk.TreeViewColumn columnStatus; private Gtk.TreeViewColumn columnName; #if !MAEMO private Gtk.TreeViewColumn columnDevice; private Gtk.TreeViewColumn columnRemote; private Gtk.TreeViewColumn columnDescription; #endif private Gdk.Pixbuf connectedImage; private Gdk.Pixbuf disconnectedImage; private Gtk.AboutDialog aboutDialog; private int activeConnections; #if WIN32 System.Windows.Forms.ContextMenu contextMenu; System.Windows.Forms.NotifyIcon trayIcon; #endif #endregion #region Initialization public static void Main(string[] args) { Application.Init(); Catalog.Init("openvpn-admin", Defines.LOCALE_DIR); #if WIN32 Win32Theme.SetupStockIcons(); Win32Theme.SetupColors(); #endif /*MainWindow mainwindow =*/ new MainWindow(); //mainwindow.ShowAll(); Application.Run(); } public MainWindow() : base() { InitializeComponent(); RefreshAllEntries(); #if WIN32 contextMenu = new System.Windows.Forms.ContextMenu(); contextMenu.Popup += new EventHandler(on_trayicon_popup); trayIcon = new System.Windows.Forms.NotifyIcon(); trayIcon.Text = Title; trayIcon.ContextMenu = contextMenu; trayIcon.Icon = new System.Drawing.Icon("openvpn-admin.ico"); trayIcon.DoubleClick += new EventHandler(on_trayicon_click); trayIcon.Visible = true; #else #if !MAEMO EventBox eb = new EventBox(); eb.Add(new Gtk.Image(Icon.ScaleSimple(24, 24, Gdk.InterpType.Hyper))); eb.ButtonPressEvent += new ButtonPressEventHandler(on_trayicon_mouseclick); TrayIcon icon = new TrayIcon("OpenVPN Admin"); icon.Add(eb); icon.ShowAll(); #endif #endif } private void InitializeComponent() { this.Title = "OpenVPN Admin"; this.Icon = Gdk.Pixbuf.LoadFromResource("openvpn-admin.png"); this.DefaultWidth = 540; this.DefaultHeight = 380; CreateActions(); CreateMenu(); CreateToolbar(); CreateTreeView(); StatusText = ""; } private void CreateActions() { actionQuit = new Gtk.Action("quit", Catalog.GetString("_Quit"), null, "gtk-quit"); actionNew = new Gtk.Action("new", Catalog.GetString("_New"), null, "gtk-new"); actionProperties = new Gtk.Action("properties", Catalog.GetString("_Properties"), null, "gtk-properties"); actionDelete = new Gtk.Action("delete", Catalog.GetString("_Delete"), null, "gtk-delete"); actionConnect = new Gtk.Action("connect", Catalog.GetString("_Connect"), null, "gtk-connect"); actionDisconnect = new Gtk.Action("disconnect", Catalog.GetString("Disconnec_t"), null, "gtk-disconnect"); actionReconnect = new Gtk.Action("reconnect", Catalog.GetString("Rec_onnect"), null, "gtk-connect"); actionRefresh = new Gtk.Action("refresh", Catalog.GetString("_Refresh"), null, "gtk-refresh"); actionLog = new Gtk.Action("log", Catalog.GetString("_Logging"), null, "gtk-dialog-info"); actionWizard = new Gtk.Action("wizard", Catalog.GetString("Certificate _Wizard"), null, null); actionCert = new Gtk.Action("keys", Catalog.GetString("Certificate _Management"), null, null); actionAbout = new Gtk.Action("about", Catalog.GetString("_About"), null, "gtk-about"); actionQuit.Activated += new EventHandler(on_exit_activate); actionNew.Activated += new EventHandler(on_new_activate); actionProperties.Activated += new EventHandler(on_properties_activate); actionDelete.Activated += new EventHandler(on_delete_activate); actionConnect.Activated += new EventHandler(on_connect_activate); actionDisconnect.Activated += new EventHandler(on_disconnect_activate); actionReconnect.Activated += new EventHandler(on_reconnect_activate); actionRefresh.Activated += new EventHandler(on_refresh_activate); actionLog.Activated += new EventHandler(on_logging_activate); actionWizard.Activated += new EventHandler(on_certificate_activate); actionCert.Activated += new EventHandler(on_keys_activate); actionAbout.Activated += new EventHandler(on_about_activate); // Accelerators ConnectAccelerator(actionQuit, "Q"); ConnectAccelerator(actionNew, "N"); ConnectAccelerator(actionConnect, "C"); ConnectAccelerator(actionDisconnect, "D"); ConnectAccelerator(actionReconnect, "R"); } private void CreateMenu() { // File #if !MAEMO Gtk.Menu file_menu = new Gtk.Menu(); Gtk.MenuItem file_item = new Gtk.MenuItem(Catalog.GetString("_File")); file_item.Submenu = file_menu; file_menu.Append(actionQuit.CreateMenuItem()); MainMenu.Append(file_item); #endif // Profile Gtk.Menu prof_menu = new Gtk.Menu(); Gtk.MenuItem prof_item = new Gtk.MenuItem(Catalog.GetString("_Profile")); prof_item.Submenu = prof_menu; prof_menu.Append(actionNew.CreateMenuItem()); prof_menu.Append(actionProperties.CreateMenuItem()); prof_menu.Append(actionDelete.CreateMenuItem()); prof_menu.Append(new SeparatorMenuItem()); prof_menu.Append(actionConnect.CreateMenuItem()); prof_menu.Append(actionDisconnect.CreateMenuItem()); prof_menu.Append(actionReconnect.CreateMenuItem()); prof_menu.Append(actionLog.CreateMenuItem()); prof_menu.Append(new SeparatorMenuItem()); prof_menu.Append(actionRefresh.CreateMenuItem()); // Tools Gtk.Menu tool_menu = new Gtk.Menu(); Gtk.MenuItem tool_item = new Gtk.MenuItem(Catalog.GetString("_Tools")); tool_item.Submenu = tool_menu; tool_menu.Append(actionWizard.CreateMenuItem()); tool_menu.Append(actionCert.CreateMenuItem()); // Help Gtk.Menu help_menu = new Gtk.Menu(); Gtk.MenuItem help_item = new Gtk.MenuItem(Catalog.GetString("_Help")); help_item.Submenu = help_menu; help_menu.Append(actionAbout.CreateMenuItem()); // Main menu MainMenu.Append(prof_item); MainMenu.Append(tool_item); MainMenu.Append(help_item); #if MAEMO MainMenu.Append(actionQuit.CreateMenuItem()); #endif MainMenu.ShowAll(); } private void CreateToolbar() { Toolbar.Add(actionNew.CreateToolItem()); Toolbar.Add(actionProperties.CreateToolItem()); Toolbar.Add(actionDelete.CreateToolItem()); Toolbar.Add(new SeparatorToolItem()); Toolbar.Add(actionConnect.CreateToolItem()); Toolbar.Add(actionDisconnect.CreateToolItem()); #if MAEMO Toolbar.Add(actionLog.CreateToolItem()); #endif Toolbar.Add(new SeparatorToolItem()); Toolbar.Add(actionRefresh.CreateToolItem()); #if MAEMO Toolbar.ToolbarStyle = ToolbarStyle.Icons; #else Toolbar.ToolbarStyle = ToolbarStyle.Both; #endif } private void CreateTreeView() { // listStore listStore = new Gtk.ListStore( typeof(Gdk.Pixbuf), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string)); // listView listView = new Gtk.TreeView(listStore); listView.RulesHint = true; listView.Reorderable = false; listView.EnableSearch = true; listView.SearchColumn = 3; listView.RowActivated += new RowActivatedHandler(on_listView_row_activated); listView.Selection.Changed += new EventHandler(on_listView_selection_change); #if !MAEMO listView.HeadersVisible = true; #endif Gtk.ScrolledWindow scroll = new Gtk.ScrolledWindow(); scroll.ShadowType = ShadowType.None; scroll.SetPolicy(PolicyType.Automatic, PolicyType.Automatic); scroll.Add(listView); this.Appview.Add(scroll); listView.HasFocus = true; // columnStatus columnStatus = listView.AppendColumn(Catalog.GetString("Status"), new CellRendererPixbuf(), "pixbuf", 0);; columnStatus.Sizing = TreeViewColumnSizing.Autosize; columnStatus.Resizable = true; columnStatus.Reorderable = true; // columnName columnName = listView.AppendColumn(Catalog.GetString("Nickname"), new CellRendererText (), "text", 3); columnName.Sizing = TreeViewColumnSizing.Autosize; columnName.Resizable = true; columnName.Reorderable = true; #if !MAEMO // columnStatus:Text CellRendererText text = new CellRendererText(); columnStatus.PackStart (text, true); columnStatus.AddAttribute(text, "text", 1); // columnDevice columnDevice = listView.AppendColumn(Catalog.GetString("Device"), new CellRendererText (), "text", 2);; columnDevice.Sizing = TreeViewColumnSizing.Autosize; columnDevice.Resizable = true; columnDevice.Reorderable = true; // columnRemote columnRemote = listView.AppendColumn(Catalog.GetString("Remote"), new CellRendererText (), "text", 4); columnRemote.Sizing = TreeViewColumnSizing.Autosize; columnRemote.Resizable = true; columnRemote.Reorderable = true; // columnDescription columnDescription = listView.AppendColumn(Catalog.GetString("Description"), new CellRendererText (), "text", 5); columnDescription.Sizing = TreeViewColumnSizing.Autosize; columnDescription.Resizable = true; columnDescription.Reorderable = true; #endif // Images connectedImage = Gdk.Pixbuf.LoadFromResource("gtk-connected.png"); disconnectedImage = Gdk.Pixbuf.LoadFromResource("gtk-disconnected.png"); } #endregion #region Private methods private void RefreshEntry(Configuration config, TreeIter iter) { listStore.SetValue(iter, 0, config.Active ? connectedImage : disconnectedImage); listStore.SetValue(iter, 3, config["name"]); #if !MAEMO listStore.SetValue(iter, 1, config["active"]); listStore.SetValue(iter, 2, config["dev"]); listStore.SetValue(iter, 4, config["remote"]); listStore.SetValue(iter, 5, config.Description); #endif } private void RefreshCurrentEntry() { RefreshEntry(new Configuration(SelectedEntry), SelectedIter); RefreshActions(); } private void RefreshAllEntries() { activeConnections = 0; listStore.Clear(); foreach (string entry in Configuration.Entries) { Configuration config = new Configuration(entry); if (config.Active) activeConnections = activeConnections + 1; RefreshEntry(config, listStore.Append()); } actionProperties.Sensitive = false; actionDelete.Sensitive = false; actionConnect.Sensitive = false; actionDisconnect.Sensitive = false; actionReconnect.Sensitive = false; actionLog.Sensitive = false; listView.Selection.SelectPath(new TreePath("0")); } private void RefreshActions() { TreeModel model; TreeIter iter; if (listView.Selection.GetSelected(out model, out iter)) { actionProperties.Sensitive = true; actionConnect.Sensitive = ((Gdk.Pixbuf) model.GetValue(iter, 0) == disconnectedImage); actionDisconnect.Sensitive = ! actionConnect.Sensitive; actionReconnect.Sensitive = ! actionConnect.Sensitive; actionDelete.Sensitive = (actionConnect.Sensitive && !Configuration.IsLocked(model.GetValue(iter, 3) as string)); } else { actionProperties.Sensitive = false; actionDelete.Sensitive = false; actionConnect.Sensitive = false; actionDisconnect.Sensitive = false; actionReconnect.Sensitive = false; } actionLog.Sensitive = true; } private bool UpdateStatusBar() { TreeModel model; TreeIter iter; if (listView.Selection.GetSelected(out model, out iter)) { StatusText = Configuration.GetStatusFromEntry(this.SelectedEntry); if (StatusText != "Inactive") GLib.Timeout.Add(1000, new GLib.TimeoutHandler(UpdateStatusBar)); } return false; } #endregion #region Events private void on_exit_activate(object o, EventArgs args) { #if WIN32 trayIcon.Visible = false; trayIcon.Dispose(); #endif Application.Quit(); } private void on_new_activate(object o, EventArgs args) { DetailForm form = new DetailForm(); if (form.ShowModal() == Gtk.ResponseType.Ok) { RefreshAllEntries(); } } private void on_properties_activate(object o, EventArgs args) { DetailForm form = new DetailForm(this.SelectedEntry); if (form.ShowModal() == Gtk.ResponseType.Ok) { RefreshCurrentEntry(); } } private void on_delete_activate(object o, EventArgs args) { MessageDialog question = new MessageDialog(this, DialogFlags.DestroyWithParent, MessageType.Question, ButtonsType.YesNo, Catalog.GetString("Are you sure you want to delete?")); ResponseType result = (ResponseType) question.Run(); question.Destroy(); if (result == ResponseType.Yes) { try { Configuration.Delete(this.SelectedEntry); RefreshAllEntries(); } catch (Exception e) { MessageDialog dialog = new MessageDialog(this, DialogFlags.DestroyWithParent, MessageType.Error, ButtonsType.Ok, e.Message); dialog.Run(); dialog.Destroy(); } } } private void RequestPassword(System.IO.StreamWriter input, bool askname) { PassForm form = new PassForm(askname); if (form.Show() == Gtk.ResponseType.Ok) { if (askname) input.WriteLine(form.Username); input.WriteLine(form.Password); } else { input.WriteLine(""); if (askname) input.WriteLine(""); } } private void on_connect_activate(object o, EventArgs args) { try { if (this.activeConnections > 0) { MessageDialog question = new MessageDialog(this, DialogFlags.DestroyWithParent, MessageType.Question, ButtonsType.YesNo, Catalog.GetString("There are another active connection. Are you sure to start another connection?")); ResponseType result = (ResponseType) question.Run(); question.Destroy(); if (result != ResponseType.Yes) return; } if (Configuration.Activate(this.SelectedEntry, new ConnectionActivateDelegate(RequestPassword))) { this.activeConnections = this.activeConnections + 1; this.RefreshCurrentEntry(); MessageDialog dialog = new MessageDialog(this, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Ok, Catalog.GetString("Connection established!")); dialog.Run(); dialog.Destroy(); UpdateStatusBar(); } else { LogForm form = new LogForm(this.SelectedEntry); form.ShowModal(); form.Destroy(); } } catch (Exception e) { MessageDialog dialog = new MessageDialog(this, DialogFlags.DestroyWithParent, MessageType.Error, ButtonsType.Ok, e.Message); dialog.Run(); dialog.Destroy(); } } private void on_disconnect_activate(object o, EventArgs args) { try { Configuration.Deactivate(this.SelectedEntry); this.activeConnections = this.activeConnections - 1; this.RefreshCurrentEntry(); this.UpdateStatusBar(); } catch (Exception e) { MessageDialog dialog = new MessageDialog(this, DialogFlags.DestroyWithParent, MessageType.Error, ButtonsType.Ok, e.Message); dialog.Run(); dialog.Destroy(); } } private void on_reconnect_activate(object o, EventArgs args) { on_disconnect_activate(o, args); on_connect_activate(o, args); } private void on_logging_activate(object o, EventArgs args) { LogForm form = new LogForm(this.SelectedEntry); form.ShowModal(); form.Destroy(); } private void on_refresh_activate(object o, EventArgs args) { RefreshAllEntries(); } private void on_certificate_activate(object o, EventArgs args) { CertForm form = new CertForm(); form.Show(); } private void on_keys_activate(object o, EventArgs args) { KeysForm form = new KeysForm(); form.ShowModal(); } private void on_about_activate(object o, EventArgs args) { if (aboutDialog != null) { aboutDialog.Present(); return; } System.Reflection.AssemblyName asm = System.Reflection.Assembly.GetEntryAssembly().GetName(); aboutDialog = new AboutDialog(); aboutDialog.Logo = Icon; aboutDialog.Name = "OpenVPN Admin"; aboutDialog.Version = String.Format("{0}.{1}.{2}", asm.Version.Major, asm.Version.Minor, asm.Version.Build); aboutDialog.Comments = Catalog.GetString("Multiplatform administration GUI for OpenVPN"); #if WIN32 aboutDialog.Copyright = "Copyright 2006 Everado Canuto\nCopyright 2006 The Gang."; #else aboutDialog.Copyright = "Copyright \xA9 2006 Everaldo Canuto\nCopyright \xA9 2006 The Gang"; #endif aboutDialog.Authors = new string [] {"Everaldo Canuto ", "Reiner Jung "}; aboutDialog.TranslatorCredits = Catalog.GetString("translator-credits"); aboutDialog.License = Catalog.GetString("This program is free software; you can redistribute it and/or modify\n" + "it under the terms of the GNU Lesser General Public License as\n" + "published by the Free Software Foundation; either version 2.1 of the\n" + "License, or (at your option) any later version.") + "\n\n" + Catalog.GetString("This program is distributed in the hope that it will be useful, but\n" + "WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "GNU Lesser General Public License for more details.") + "\n\n" + Catalog.GetString("You should have received a copy of the GNU Lesser General Public\n" + "License along with this program; if not, write to the Free Software\n" + "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307\n" + "USA") + "\n\n"; aboutDialog.TransientFor = this; aboutDialog.Destroyed += new EventHandler(on_about_destroyed); aboutDialog.Show(); } private void on_about_destroyed(object o, EventArgs args) { aboutDialog = null; } private void on_listView_row_activated(object o, RowActivatedArgs args) { on_properties_activate(o, args); } private void on_listView_selection_change(object o, EventArgs args) { RefreshActions(); UpdateStatusBar(); } private void on_trayicon_mouseclick(object o, ButtonPressEventArgs args) { switch (args.Event.Button) { case 1: on_trayicon_click(o, args); break; case 3: on_trayicon_popup(0, args); break; } } private void on_trayicon_click(object o, EventArgs args) { if (Visible) Hide(); else ShowAll(); } private void on_trayicon_popup(object o, EventArgs args) { #if WIN32 contextMenu.MenuItems.Clear(); #else Menu popupMenu = new Menu(); #endif int i = 0; foreach (string entry in Configuration.Entries) { Configuration config = new Configuration(entry); #if WIN32 System.Windows.Forms.MenuItem conn = new System.Windows.Forms.MenuItem(Catalog.GetString("Connect")); conn.Enabled = ! config.Active; conn.Click += new EventHandler(on_trayicon_connect); System.Windows.Forms.MenuItem disc = new System.Windows.Forms.MenuItem(Catalog.GetString("Disconnect")); disc.Enabled = config.Active; disc.Click += new EventHandler(on_trayicon_disconnect); System.Windows.Forms.MenuItem recn = new System.Windows.Forms.MenuItem(Catalog.GetString("Reconnect")); recn.Enabled = config.Active; recn.Click += new EventHandler(on_trayicon_reconnect); System.Windows.Forms.MenuItem item = new System.Windows.Forms.MenuItem(config["name"]); item.MenuItems.Add(conn); item.MenuItems.Add(disc); item.MenuItems.Add(recn); contextMenu.MenuItems.Add(item); #else Gtk.Menu submenu = new Gtk.Menu(); ImageMenuItem conn = new ImageMenuItem(Catalog.GetString("Connect")); conn.Name = "conn" + i.ToString(); conn.Sensitive = ! config.Active; conn.Image = new Gtk.Image("gtk-connect", IconSize.Menu); conn.Activated += new EventHandler(on_trayicon_connect); submenu.Append(conn); ImageMenuItem disc = new ImageMenuItem(Catalog.GetString("Disconnect")); disc.Name = "disc" + i.ToString(); disc.Sensitive = ! conn.Sensitive; disc.Image = new Gtk.Image("gtk-disconnect", IconSize.Menu); disc.Activated += new EventHandler(on_trayicon_disconnect); submenu.Append(disc); ImageMenuItem recn = new ImageMenuItem(Catalog.GetString("Reconnect")); recn.Name = "recn" + i.ToString(); recn.Sensitive = ! conn.Sensitive; recn.Image = new Gtk.Image("gtk-connect", IconSize.Menu); recn.Activated += new EventHandler(on_trayicon_reconnect); submenu.Append(recn); ImageMenuItem item = new ImageMenuItem(config["name"]); item.Image = new Gtk.Image(config.Active ? connectedImage : disconnectedImage); item.Submenu = submenu; popupMenu.Add(item); #endif i++; } #if WIN32 contextMenu.MenuItems.Add(new System.Windows.Forms.MenuItem("-")); System.Windows.Forms.MenuItem quit = new System.Windows.Forms.MenuItem(actionQuit.Label.Replace("_", "&")); quit.Click += new EventHandler(on_exit_activate); contextMenu.MenuItems.Add(quit); #else popupMenu.Add(new SeparatorMenuItem()); popupMenu.Add(actionQuit.CreateMenuItem()); popupMenu.ShowAll(); popupMenu.Popup(); #endif } private void on_trayicon_connect(object o, EventArgs args) { #if WIN32 System.Windows.Forms.MenuItem par = (o as System.Windows.Forms.MenuItem); System.Windows.Forms.MenuItem ite = (par.Parent as System.Windows.Forms.MenuItem); listView.Selection.SelectPath(new TreePath(ite.Index.ToString())); #else ImageMenuItem item = (o as ImageMenuItem); listView.Selection.SelectPath(new TreePath(item.Name.Substring(4))); #endif on_connect_activate(o, args); } private void on_trayicon_disconnect(object o, EventArgs args) { #if WIN32 System.Windows.Forms.MenuItem par = (o as System.Windows.Forms.MenuItem); System.Windows.Forms.MenuItem ite = (par.Parent as System.Windows.Forms.MenuItem); listView.Selection.SelectPath(new TreePath(ite.Index.ToString())); #else ImageMenuItem item = (o as ImageMenuItem); listView.Selection.SelectPath(new TreePath(item.Name.Substring(4))); #endif on_disconnect_activate(o, args); } private void on_trayicon_reconnect(object o, EventArgs args) { on_trayicon_disconnect(o, args); on_trayicon_connect(o, args); } #endregion #region Public properties public string SelectedEntry { get { return (string) listView.Model.GetValue(SelectedIter, 3); } } public TreeIter SelectedIter { get { TreeModel model; TreeIter iter; listView.Selection.GetSelected(out model, out iter); return iter; } } #endregion } }