Browse Source

Refactor in order to support multiple handlers (only PuTTY so far, but soon OpenSSH from Cygwin or something else).

Douglas Thrift 10 years ago
parent
commit
90fea65aa6
1 changed files with 160 additions and 92 deletions
  1. 160 92
      ssh-handler/ssh-handler.cs

+ 160 - 92
ssh-handler/ssh-handler.cs

@@ -23,15 +23,142 @@ using System;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
+using System.Linq;
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Windows.Forms;
 using Microsoft.Win32;
 
+public enum Option
+{
+    None,
+    Set,
+    Optional,
+}
+
+public interface Handler
+{
+    IList<string> Usages
+    {
+        get;
+    }
+
+    Option DoMatch(string arg);
+    bool Find();
+    void Execute(Uri uri, string user, string password);
+}
+
+public abstract class FindInPathMixin
+{
+    protected string FindInPath(string program)
+    {
+        foreach (string location in Environment.GetEnvironmentVariable("PATH").Split(Path.PathSeparator))
+        {
+            string path = Path.Combine(location, "putty.exe");
+            if (File.Exists(path))
+                return path;
+        }
+
+        return null;
+    }
+}
+
+public class Putty : FindInPathMixin, Handler
+{
+    private Regex option = new Regex(@"^(?:/|--?)putty(?:[:=](?<putty_path>.*))?$", RegexOptions.IgnoreCase);
+    private string path = null;
+
+    public IList<string> Usages
+    {
+        get
+        {
+            return new string[] { "/putty[:<putty-path>] -- Use PuTTY to connect" };
+        }
+    }
+
+    public Option DoMatch(string arg)
+    {
+        Match match;
+
+        if ((match = option.Match(arg)).Success)
+        {
+            Group group = match.Groups["putty_path"];
+            if (group.Success)
+                path = group.Value;
+            return Option.Set;
+        }
+        else
+            return Option.None;
+    }
+
+    public bool Find()
+    {
+        if (path != null)
+            goto found;
+
+        foreach (RegistryHive hive in new RegistryHive[] { RegistryHive.CurrentUser, RegistryHive.LocalMachine })
+        {
+            IList<RegistryView> views = new List<RegistryView>(new RegistryView[] { RegistryView.Registry32 });
+            if (Environment.Is64BitOperatingSystem)
+                views.Insert(0, RegistryView.Registry64);
+
+            foreach (RegistryView view in views)
+                using (RegistryKey baseKey = RegistryKey.OpenBaseKey(hive, view), key = baseKey.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\PuTTY_is1"))
+                    if (key != null)
+                    {
+                        string location = (string)key.GetValue("InstallLocation");
+                        if (location == null)
+                            continue;
+                        path = Path.Combine(location, "putty.exe");
+                        if (File.Exists(path))
+                        {
+                            Debug.WriteLine("Found PuTTY in registry: {0}", path, null);
+                            goto found;
+                        }
+                        else
+                            path = null;
+                    }
+        }
+
+        if ((path = FindInPath("putty.exe")) != null)
+        {
+            Debug.WriteLine("Found PuTTY in path: {0}", path, null);
+            goto found;
+        }
+
+        return false;
+
+    found:
+        path = path.Trim();
+        return true;
+    }
+
+    public void Execute(Uri uri, string user, string password)
+    {
+        if (!Find())
+            throw new Exception("Could not find PuTTY executable.");
+
+        StringBuilder args = new StringBuilder();
+        if (password != null)
+            args.AppendFormat("-pw {0} ", password);
+        if (uri.Port != -1)
+            args.AppendFormat("-P {0} ", uri.Port);
+        if (user != null)
+            args.AppendFormat("{0}@", user);
+        args.Append(uri.Host);
+
+        Debug.WriteLine("Running PuTTY command: {0} {1}", path, args);
+        Process.Start(path, args.ToString());
+    }
+}
+
 public class SshHandler
 {
-    private enum Handler { Unspecified, Putty };
-    private static Handler handler = Handler.Unspecified;
+    private static IList<Handler> handlers = new Handler[]
+    {
+        new Putty(),
+    };
+    private static Handler handler = null;
     private static string puttyPath = null;
 
     public static int Main(string[] args)
@@ -41,7 +168,6 @@ public class SshHandler
         try
         {
             Regex usage = new Regex(@"^(?:/|--?)(?:h|help|usage|\?)$", RegexOptions.IgnoreCase);
-            Regex putty = new Regex(@"^(?:/|--?)putty(?:[:=](?<putty_path>.*))?$", RegexOptions.IgnoreCase);
             IList<string> uriParts = null;
 
             foreach (string arg in args)
@@ -50,16 +176,7 @@ public class SshHandler
                     if (usage.IsMatch(arg))
                         return Usage(0);
 
-                    Match match;
-
-                    if ((match = putty.Match(arg)).Success)
-                    {
-                        handler = Handler.Putty;
-                        Group group = match.Groups["putty_path"];
-                        if (group.Success)
-                            puttyPath = group.Value;
-                    }
-                    else
+                    if (!MatchHandler(arg))
                         uriParts = new List<string>(new string[] { arg });
                 }
                 else
@@ -68,19 +185,14 @@ public class SshHandler
             if (uriParts != null)
             {
                 Uri uri = new Uri(string.Join(" ", uriParts), UriKind.Absolute);
+                string user, password;
 
-                switch (handler)
-                {
-                    case Handler.Unspecified:
-                        if (FindPutty())
-                            Putty(uri);
-                        else
-                            throw new Exception("Could not find a suitable SSH application.");
-                        break;
-                    case Handler.Putty:
-                        Putty(uri);
-                        break;
-                }
+                SetUserPassword(uri, out user, out password);
+
+                if (handler == null)
+                    handler = FindHandler();
+
+                handler.Execute(uri, user, password);
             }
             else
                 return Usage(1);
@@ -97,11 +209,27 @@ public class SshHandler
     private static int Usage(int code)
     {
         MessageBox.Show("ssh-handler [/putty[:<putty-path>]] <ssh-url>\n\n" +
-            "/putty[:<putty-path>] -- Use PuTTY to connect", "SSH Handler Usage", MessageBoxButtons.OK, MessageBoxIcon.Information);
+            string.Join("\n", handlers.SelectMany(handler => handler.Usages)), "SSH Handler Usage", MessageBoxButtons.OK,
+            MessageBoxIcon.Information);
         return code;
     }
 
-    private static void UserPassword(Uri uri, out string user, out string password)
+    private static bool MatchHandler(string arg)
+    {
+        foreach (Handler handler in handlers)
+            switch (handler.DoMatch(arg))
+            {
+            case Option.Set:
+                SshHandler.handler = handler;
+                goto case Option.Optional;
+            case Option.Optional:
+                return true;
+            }
+
+        return false;
+    }
+
+    private static void SetUserPassword(Uri uri, out string user, out string password)
     {
         if (uri.UserInfo.Length != 0)
         {
@@ -116,72 +244,12 @@ public class SshHandler
         }
     }
 
-    private static bool FindPutty()
-    {
-        if (puttyPath != null)
-            goto found;
-
-        foreach (RegistryHive hive in new RegistryHive[] { RegistryHive.CurrentUser, RegistryHive.LocalMachine })
-        {
-            IList<RegistryView> views = new List<RegistryView>(new RegistryView[] { RegistryView.Registry32 });
-            if (Environment.Is64BitOperatingSystem)
-                views.Insert(0, RegistryView.Registry64);
-
-            foreach (RegistryView view in views)
-                using (RegistryKey baseKey = RegistryKey.OpenBaseKey(hive, view), key = baseKey.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\PuTTY_is1"))
-                    if (key != null)
-                    {
-                        string path = (string)key.GetValue("InstallLocation");
-                        if (path == null)
-                            continue;
-                        puttyPath = Path.Combine(path, "putty.exe");
-                        if (File.Exists(puttyPath))
-                        {
-                            Debug.WriteLine("Found PuTTY in registry: {0}", puttyPath, null);
-                            goto found;
-                        }
-                        else
-                            puttyPath = null;
-                    }
-        }
-
-        foreach (string path in Environment.GetEnvironmentVariable("PATH").Split(Path.PathSeparator))
-        {
-            puttyPath = Path.Combine(path, "putty.exe");
-            if (File.Exists(puttyPath))
-            {
-                Debug.WriteLine("Found PuTTY in path: {0}", puttyPath, null);
-                goto found;
-            }
-            else
-                puttyPath = null;
-        }
-
-        return false;
-
-    found:
-        puttyPath = puttyPath.Trim();
-        return true;
-    }
-
-    private static void Putty(Uri uri)
+    private static Handler FindHandler()
     {
-        if (!FindPutty())
-            throw new Exception("Could not find PuTTY executable.");
-
-        string user, password;
-        UserPassword(uri, out user, out password);
-
-        StringBuilder args = new StringBuilder();
-        if (password != null)
-            args.AppendFormat("-pw {0} ", password);
-        if (uri.Port != -1)
-            args.AppendFormat("-P {0} ", uri.Port);
-        if (user != null)
-            args.AppendFormat("{0}@", user);
-        args.Append(uri.Host);
+        foreach (Handler handler in handlers)
+            if (handler.Find())
+                return handler;
 
-        Debug.WriteLine("Running PuTTY command: {0} {1}", puttyPath, args);
-        Process.Start(puttyPath, args.ToString());
+        throw new Exception("Could not find a suitable SSH application.");
     }
 }