Browse Source

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

Douglas Thrift 10 năm trước cách đây
mục cha
commit
90fea65aa6
1 tập tin đã thay đổi với 160 bổ sung92 xóa
  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.");
     }
 }