Browse Source

Checkpoint of work on adding a Bash login shell option for ssh-agent support.

Douglas Thrift 10 years ago
parent
commit
a05ed0d8ba
3 changed files with 140 additions and 58 deletions
  1. 44 14
      ssh-handler/AbstractHandler.cs
  2. 94 37
      ssh-handler/OpensshHandler.cs
  3. 2 7
      ssh-handler/PuttyHandler.cs

+ 44 - 14
ssh-handler/AbstractHandler.cs

@@ -20,7 +20,10 @@
  */
 
 using System;
+using System.Collections.Generic;
 using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
 
 public abstract class AbstractHandler
 {
@@ -36,21 +39,48 @@ public abstract class AbstractHandler
         return null;
     }
 
-    protected void SetYesNoValue(string input, out AutoYesNoOption option, out string value)
+    protected MatchOption SetValue(Match match, string groupName, ref string value)
     {
-        value = null;
+        Group group = match.Groups[groupName];
+        if (group.Success)
+            value = group.Value;
 
-        switch (input.ToLowerInvariant())
-        {
-        case "yes":
-            option = AutoYesNoOption.Yes;
-            break;
-        case "no":
-            option = AutoYesNoOption.No;
-            break;
-        default:
-            value = input;
-            goto case "yes";
-        }
+        return MatchOption.Set;
+    }
+
+    protected MatchOption SetBooleanValue(Match match, string groupName, out bool option, ref string value)
+    {
+        Group group = match.Groups[groupName];
+        if (group.Success)
+            switch (group.Value.ToLowerInvariant())
+            {
+            case "yes":
+                option = true;
+                break;
+            case "no":
+                option = false;
+                break;
+            default:
+                value = group.Value;
+                goto case "yes";
+            }
+        else
+            option = true;
+
+        return MatchOption.Option;
+    }
+
+    protected MatchOption SetYesNoValue(Match match, string groupName, out AutoYesNoOption option, ref string value)
+    {
+        bool optionValue;
+        MatchOption matchOption = SetBooleanValue(match, groupName, out optionValue, ref value);
+        option = optionValue ? AutoYesNoOption.Yes : AutoYesNoOption.No;
+
+        return matchOption;
+    }
+
+    protected void AddArguments(List<string> command, params object[] arguments)
+    {
+        command.AddRange(arguments.Select(argument => argument.ToString()));
     }
 }

+ 94 - 37
ssh-handler/OpensshHandler.cs

@@ -23,6 +23,7 @@ using System;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
+using System.Linq;
 using System.Text;
 using System.Text.RegularExpressions;
 using Microsoft.Win32;
@@ -32,11 +33,14 @@ public class OpensshHandler : AbstractHandler, Handler
     private Regex regex = new Regex(@"^(?:/|--?)openssh(?:[:=](?<openssh_path>.*))?$", RegexOptions.IgnoreCase);
     private Regex cygwinRegex = new Regex(@"^(?:/|--?)cygwin(?:[:=](?<cygwin_path>.*))?$", RegexOptions.IgnoreCase);
     private Regex minttyRegex = new Regex(@"^(?:/|--?)mintty(?:[:=](?<mintty_path>.*))?$", RegexOptions.IgnoreCase);
+    private Regex bashRegex = new Regex(@"^(?:/|--?)bash(?:[:=](?<bash_path>.*))?$", RegexOptions.IgnoreCase);
     private AutoYesNoOption cygwin = AutoYesNoOption.Auto;
     private AutoYesNoOption mintty = AutoYesNoOption.Auto;
+    private bool bash = false;
     private string path = null;
     string cygwinPath = null;
     string minttyPath = null;
+    string bashPath = null;
 
     public IList<string> Usages
     {
@@ -47,6 +51,7 @@ public class OpensshHandler : AbstractHandler, Handler
                 "/openssh[:<openssh-path>] -- Use OpenSSH to connect",
                 "/cygwin[:(yes|no|<cygwin-path>)] -- Use Cygwin for OpenSSH (by default, Cygwin will be used for OpenSSH if detected)",
                 "/mintty[:(yes|no|<mintty-path>)] -- Use MinTTY for OpenSSH (by default, MinTTY will be used for OpenSSH if detected)",
+                "/bash[:(yes|no|<bash-path>)] -- Use Bash login shell for use with ssh-agent",
             };
         }
     }
@@ -56,26 +61,13 @@ public class OpensshHandler : AbstractHandler, Handler
         Match match;
 
         if ((match = regex.Match(arg)).Success)
-        {
-            Group group = match.Groups["openssh_path"];
-            if (group.Success)
-                path = group.Value;
-            return MatchOption.Set;
-        }
+            return SetValue(match, "openssh_path", ref path);
         else if ((match = cygwinRegex.Match(arg)).Success)
-        {
-            Group group = match.Groups["cygwin_path"];
-            if (group.Success)
-                SetYesNoValue(group.Value, out cygwin, out cygwinPath);
-            return MatchOption.Option;
-        }
+            return SetYesNoValue(match, "cygwin_path", out cygwin, ref cygwinPath);
         else if ((match = minttyRegex.Match(arg)).Success)
-        {
-            Group group = match.Groups["mintty_path"];
-            if (group.Success)
-                SetYesNoValue(group.Value, out mintty, out minttyPath);
-            return MatchOption.Option;
-        }
+            return SetYesNoValue(match, "mintty_path", out mintty, ref minttyPath);
+        else if ((match = bashRegex.Match(arg)).Success)
+            return SetBooleanValue(match, "bash_path", out bash, ref bashPath);
         else
             return MatchOption.None;
     }
@@ -111,6 +103,8 @@ public class OpensshHandler : AbstractHandler, Handler
             FindMintty();
             break;
         }
+        if (bash)
+            FindBash();
         return true;
     }
 
@@ -119,31 +113,55 @@ public class OpensshHandler : AbstractHandler, Handler
         if (!Find())
             throw new Exception("Could not find OpenSSH executable.");
 
-        string command = path;
-        StringBuilder args = new StringBuilder();
-
-        if (minttyPath != null)
+        if (cygwinPath != null && bash)
         {
-            command = minttyPath;
-            if (cygwinPath != null)
-            {
-                string icon = Path.Combine(cygwinPath, "Cygwin-Terminal.ico");
-                if (File.Exists(icon))
-                    args.AppendFormat("-i {0} ", icon);
-            }
-            args.AppendFormat("-e {0} ", path);
+            ProcessStartInfo info = new ProcessStartInfo(Path.Combine(cygwinPath, "bin", "cygpath.exe"), Quote(path));
+
+            info.CreateNoWindow = true;
+            info.RedirectStandardOutput = true;
+            info.RedirectStandardError = true;
+            info.UseShellExecute = false;
+
+            Process process = Process.Start(info);
+            string error = process.StandardError.ReadToEnd().Trim();
+
+            path = process.StandardOutput.ReadToEnd().Trim();
+
+            process.WaitForExit();
+
+            if (process.ExitCode != 0)
+                throw new Exception(error);
         }
 
+        var command = new List<string>(new string[] { path });
+
+        //if (minttyPath != null)
+        //{
+        //    command = minttyPath;
+        //    if (cygwinPath != null)
+        //    {
+        //        string icon = Path.Combine(cygwinPath, "Cygwin-Terminal.ico");
+        //        if (File.Exists(icon))
+        //            args.AppendFormat("-i \"{0}\" ", icon);
+        //    }
+        //    args.AppendFormat("-e \"{0}\" ", path);
+        //}
+
         if (password != null)
             Debug.WriteLine("Warning: OpenSSH does not support passing a password.");
         if (uri.Port != -1)
-            args.AppendFormat("-p {0} ", uri.Port);
-        if (user != null)
-            args.AppendFormat("{0}@", user);
-        args.Append(uri.Host);
+            AddArguments(command, "-p", uri.Port);
+        AddArguments(command, user != null ? string.Format("{0}@{1}", user, uri.Host) : uri.Host);
 
-        Debug.WriteLine("Running OpenSSH command: {0} {1}", command, args);
-        Process.Start(command, args.ToString());
+        if (bash)
+        {
+            command = new List<string>(new string[] { bashPath, "-lc", Quote(Command(command)) });
+        }
+
+        //Debug.WriteLine("Running OpenSSH command: {0} {1}", command, args);
+        //Process.Start(command, args.ToString());
+
+        command.ForEach(item => Debug.WriteLine(item));
     }
 
     private bool FindCygwin()
@@ -219,10 +237,49 @@ public class OpensshHandler : AbstractHandler, Handler
         }
 
         if (mintty == AutoYesNoOption.Yes)
-            throw new Exception("Could no find MinTTY executable.");
+            throw new Exception("Could not find MinTTY executable.");
         return;
 
     Found:
         minttyPath = minttyPath.Trim();
     }
+
+    private void FindBash()
+    {
+        if (bashPath != null)
+            goto Found;
+
+        if (cygwinPath != null)
+        {
+            bashPath = Path.Combine(cygwinPath, "bin", "bash.exe");
+            if (File.Exists(bashPath))
+            {
+                Debug.WriteLine("Found Bash in Cygwin directory: {0}", bashPath, null);
+                goto Found;
+            }
+            else
+                bashPath = null;
+        }
+
+        if ((bashPath = FindInPath("bash.exe")) != null)
+        {
+            Debug.WriteLine("Found Bash in path: {0}", bashPath, null);
+            goto Found;
+        }
+
+        throw new Exception("Could not find Bash executable.");
+
+    Found:
+        bashPath = bashPath.Trim();
+    }
+
+    private string Quote(string value)
+    {
+        return string.Format("'{0}'", value.Replace("\"", "\\\"").Replace('\'', '"'));
+    }
+
+    private string Command(IList<string> command)
+    {
+        return string.Join(" ", command.Select(item => Quote(item)));
+    }
 }

+ 2 - 7
ssh-handler/PuttyHandler.cs

@@ -45,12 +45,7 @@ public class PuttyHandler : AbstractHandler, Handler
         Match match;
 
         if ((match = regex.Match(arg)).Success)
-        {
-            Group group = match.Groups["putty_path"];
-            if (group.Success)
-                path = group.Value;
-            return MatchOption.Set;
-        }
+            return SetValue(match, "putty_path", ref path);
         else
             return MatchOption.None;
     }
@@ -104,7 +99,7 @@ public class PuttyHandler : AbstractHandler, Handler
 
         StringBuilder args = new StringBuilder();
         if (password != null)
-            args.AppendFormat("-pw {0} ", password);
+            args.AppendFormat("-pw \"{0}\" ", password);
         if (uri.Port != -1)
             args.AppendFormat("-P {0} ", uri.Port);
         if (user != null)