KeePassTrueCryptMount / src / KeepassTrueCryptMount / KeepassTrueCryptMountExt.cs

/*
  Plugin for KeePass Password Safe - The Open-Source Password Manager
  KeePassTrueCryptMount
  Copyright (C) 2010-2013 Patrick Schaller

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program 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 General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

namespace KeePassTrueCryptMount
{
    /* 
     * It seems like a mistake, but the plugin namespace must the same
     * than the plugin class name (with suffix Ext), so no dots allowed. 
     * The assembly file must also have the name of the namespace.
     */

    using System;
    using System.Diagnostics;
    using System.Drawing;
    using System.IO;
    using System.Windows.Forms;

    using KeePass.Plugins;
    using KeePass.TrueCryptMount;

    public sealed class KeePassTrueCryptMountExt : Plugin
    {
        private IPluginHost pluginHost;
        private ToolStripMenuItem mnuEntryTrueCryptMount;
        private ToolStripMenuItem mnuToolsTrueCryptOptions;
        private bool doNotHideMountWindowByShiftKey;

        public KeePassTrueCryptMountExt()
        {
        }

        public override Image SmallIcon
        {
            get
            {
                return TrueCryptInfo.ExecutableExists(this.pluginHost.GetTrueCryptExecutable())
                    ? Resources.TrueCryptNormal
                    : Resources.TrueCryptError;
            }
        }

        private bool IsMountMenuIstAlwaysVisible
        {
            get
            {
                return this.pluginHost.GetTrueCryptMenuItemAlwaysVisible();
            }
        }
        
        public override bool Initialize(IPluginHost host)
        {
            this.pluginHost = host;

            // insert the options menu item inside of the tools menu.
            var toolsMenuItem = this.pluginHost.MainWindow.ToolsMenu;

            this.mnuToolsTrueCryptOptions = new ToolStripMenuItem(LanguageTexts.TCOptionsMenuItemText + LanguageTexts.MenuItemOpenDialogSuffix);
            this.mnuToolsTrueCryptOptions.Image = Resources.TrueCryptNormal;
            this.mnuToolsTrueCryptOptions.Click += this.OnTrueCryptOptionsMenuItemClicked;

            toolsMenuItem.DropDownItems.Add(this.mnuToolsTrueCryptOptions);

            // insert the mount menu item inside of the entry menu.
            this.pluginHost.MainWindow.EntryContextMenu.KeyDown += this.OnEntryContextMenuKeyDown;
            this.pluginHost.MainWindow.EntryContextMenu.KeyUp += this.OnEntryContextMenuKeyUp;
            this.pluginHost.MainWindow.EntryContextMenu.Opened += this.OnEntryContextMenuOpened;
            this.mnuEntryTrueCryptMount = new ToolStripMenuItem();
            this.mnuEntryTrueCryptMount.ShortcutKeys = Keys.Control | Keys.T;
            this.mnuEntryTrueCryptMount.ShowShortcutKeys = true;
            this.mnuEntryTrueCryptMount.Click += this.OnTrueCryptMenuItemClicked;
            this.mnuEntryTrueCryptMount.Image = Resources.TrueCryptNormal;
            this.pluginHost.MainWindow.EntryContextMenu.Items.Insert(4, this.mnuEntryTrueCryptMount);

            this.SetTrueCryptMountMenuMenuAppearance();

            return true;
        }
        
        public override void Terminate()
        {
            this.pluginHost.MainWindow.ToolsMenu.DropDownItems.Remove(this.mnuToolsTrueCryptOptions);
            this.mnuToolsTrueCryptOptions.Click -= this.OnTrueCryptOptionsMenuItemClicked;
            this.mnuToolsTrueCryptOptions.Dispose();
            
            this.pluginHost.MainWindow.EntryContextMenu.KeyDown -= this.OnEntryContextMenuKeyDown;
            this.pluginHost.MainWindow.EntryContextMenu.KeyUp -= this.OnEntryContextMenuKeyUp;
            this.pluginHost.MainWindow.EntryContextMenu.Opened -= this.OnEntryContextMenuOpened;
            this.pluginHost.MainWindow.EntryContextMenu.Items.Remove(this.mnuEntryTrueCryptMount);
            this.mnuEntryTrueCryptMount.Click -= this.OnTrueCryptMenuItemClicked;
            this.mnuEntryTrueCryptMount.Dispose();
            base.Terminate();
        }

        private void OnEntryContextMenuKeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.ShiftKey && this.ShouldMountMenuItemAccessible())
            {
                this.mnuEntryTrueCryptMount.Text = LanguageTexts.TCMountMenuItemText + LanguageTexts.MenuItemOpenDialogSuffix;
                this.mnuEntryTrueCryptMount.Visible = true;
                this.doNotHideMountWindowByShiftKey = true;
            }
        }
        
        private void OnEntryContextMenuKeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.ShiftKey)
            {
                if (!this.ShouldMountMenuItemAccessible())
                {
                    return;
                }

                var entry = this.pluginHost.MainWindow.GetSelectedEntry(false);

                if (entry.ShouldHideMountDialog())
                {
                    this.mnuEntryTrueCryptMount.Text = LanguageTexts.TCMountMenuItemText;
                }
                else
                {
                    this.mnuEntryTrueCryptMount.Text = LanguageTexts.TCMountMenuItemText + LanguageTexts.MenuItemOpenDialogSuffix;
                }

                this.doNotHideMountWindowByShiftKey = false;

                this.mnuEntryTrueCryptMount.Visible = this.IsMountMenuIstAlwaysVisible || entry.HasMountSettings();
            }
        }

        private void OnEntryContextMenuOpened(object sender, EventArgs e)
        {
            if (!this.ShouldMountMenuItemAccessible())
            {
                return;
            }

            var entry = this.pluginHost.MainWindow.GetSelectedEntry(false);
            
            if (entry.ShouldHideMountDialog())
            {
                this.mnuEntryTrueCryptMount.Text = LanguageTexts.TCMountMenuItemText;
            }
            else
            {
                this.mnuEntryTrueCryptMount.Text = LanguageTexts.TCMountMenuItemText + LanguageTexts.MenuItemOpenDialogSuffix;
            }  

            this.mnuEntryTrueCryptMount.Visible = this.IsMountMenuIstAlwaysVisible || entry.HasMountSettings();
        }

        private void OnTrueCryptMenuItemClicked(object sender, EventArgs e)
        {
            var entry = this.pluginHost.MainWindow.GetSelectedEntry(false);

            if (entry == null)
            {
                return;
            }

            bool hideDialog = entry.ShouldHideMountDialog();

            if (!hideDialog || this.doNotHideMountWindowByShiftKey)
            {
                var dialog = new TrueCryptMountForm()
                    .WithShowInTaskBar(false)
                    .WithStartPosition(FormStartPosition.CenterParent)
                    .ReadFrom(entry);

                var result = dialog.ShowDialog(this.pluginHost.MainWindow);

                if (result == DialogResult.Cancel)
                {
                    // exit here, save nothing, mount nothing
                    return;
                }

                // save settings
                if (dialog.ChangesApplied)
                {
                    dialog.WriteTo(entry);
                    entry.Touch(true);
                    this.pluginHost.Database.Modified = true;
                    this.pluginHost.MainWindow.UpdateUI(false, null, false, null, false, null, true);
                }
            }

            // do mount...
            new ProcessStartInfo(this.pluginHost.GetTrueCryptExecutable())
                .HideExecution()
                .WithCommandLine(entry.ToTrueCryptArguments())
                .Execute();
        }

        private void OnTrueCryptOptionsMenuItemClicked(object sender, EventArgs e)
        {
            // open the plugin options dialog.
            using (var optionsDialog = new TrueCryptOptionsForm(this.pluginHost))
            {
                optionsDialog.WithShowInTaskBar(false)
                             .WithStartPosition(FormStartPosition.CenterParent)
                             .ShowDialog(this.pluginHost.MainWindow);
            }

            this.SetTrueCryptMountMenuMenuAppearance();
        }

        /// <summary>
        /// Changes the appearance and accessibilty of the mount menu item after option change.
        /// </summary>
        private void SetTrueCryptMountMenuMenuAppearance()
        {
            // in case of missing executeable, disable the menu item and load another overlay image.
            if (!TrueCryptInfo.ExecutableExists(this.pluginHost.GetTrueCryptExecutable()))
            {
                this.mnuEntryTrueCryptMount.Enabled = false;
                this.mnuEntryTrueCryptMount.Image = Resources.TrueCryptError;
            }
            else
            {
                this.mnuEntryTrueCryptMount.Enabled = true;
                this.mnuEntryTrueCryptMount.Image = Resources.TrueCryptNormal;
            }
        }

        /// <summary>
        /// Checks if it is neccessary to show the mount menu item.
        /// When nothing or more than one entries selected it hides the mount menu item.
        /// </summary>
        /// <returns><c>True</c> when it is neccessary to show the menu item; otherwise <c>false</c>.</returns>
        private bool ShouldMountMenuItemAccessible()
        {
            var selectedEntryCount = this.pluginHost.MainWindow.GetSelectedEntriesCount();

            // it makes no sense to show the menu item when no item selected or more than one.
            if (selectedEntryCount == 0 || selectedEntryCount > 1 )
            {
                this.mnuEntryTrueCryptMount.Visible = false;
                return false;
            }

            return true;
        }
    }
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.