OpensshHandler.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // OpenSSH Handler
  2. //
  3. // Douglas Thrift
  4. //
  5. // OpensshHandler.cs
  6. /* Copyright 2013 Douglas Thrift
  7. *
  8. * Licensed under the Apache License, Version 2.0 (the "License");
  9. * you may not use this file except in compliance with the License.
  10. * You may obtain a copy of the License at
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  14. * Unless required by applicable law or agreed to in writing, software
  15. * distributed under the License is distributed on an "AS IS" BASIS,
  16. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. * See the License for the specific language governing permissions and
  18. * limitations under the License.
  19. */
  20. using System;
  21. using System.Collections.Generic;
  22. using System.Diagnostics;
  23. using System.IO;
  24. using System.Text;
  25. using System.Text.RegularExpressions;
  26. using Microsoft.Win32;
  27. public class OpensshHandler : AbstractHandler, Handler
  28. {
  29. private Regex regex = new Regex(@"^(?:/|--?)openssh(?:[:=](?<openssh_path>.*))?$", RegexOptions.IgnoreCase);
  30. private Regex cygwinRegex = new Regex(@"^(?:/|--?)cygwin(?:[:=](?<cygwin_path>.*))?$", RegexOptions.IgnoreCase);
  31. private Regex minttyRegex = new Regex(@"^(?:/|--?)mintty(?:[:=](?<mintty_path>.*))?$", RegexOptions.IgnoreCase);
  32. private AutoYesNoOption cygwin = AutoYesNoOption.Auto;
  33. private AutoYesNoOption mintty = AutoYesNoOption.Auto;
  34. private string path = null;
  35. string cygwinPath = null;
  36. string minttyPath = null;
  37. public IList<string> Usages
  38. {
  39. get
  40. {
  41. return new string[]
  42. {
  43. "/openssh[:<openssh-path>] -- Use OpenSSH to connect",
  44. "/cygwin[:(yes|no|<cygwin-path>)] -- Use Cygwin for OpenSSH (by default, Cygwin will be used for OpenSSH if detected)",
  45. "/mintty[:(yes|no|<mintty-path>)] -- Use MinTTY for OpenSSH (by default, MinTTY will be used for OpenSSH if detected)",
  46. };
  47. }
  48. }
  49. public MatchOption DoMatch(string arg)
  50. {
  51. Match match;
  52. if ((match = regex.Match(arg)).Success)
  53. {
  54. Group group = match.Groups["openssh_path"];
  55. if (group.Success)
  56. path = group.Value;
  57. return MatchOption.Set;
  58. }
  59. else if ((match = cygwinRegex.Match(arg)).Success)
  60. {
  61. Group group = match.Groups["cygwin_path"];
  62. if (group.Success)
  63. SetYesNoValue(group.Value, out cygwin, out cygwinPath);
  64. return MatchOption.Option;
  65. }
  66. else if ((match = minttyRegex.Match(arg)).Success)
  67. {
  68. Group group = match.Groups["mintty_path"];
  69. if (group.Success)
  70. SetYesNoValue(group.Value, out mintty, out minttyPath);
  71. return MatchOption.Option;
  72. }
  73. else
  74. return MatchOption.None;
  75. }
  76. public bool Find()
  77. {
  78. if (path != null)
  79. goto Found;
  80. switch (cygwin)
  81. {
  82. case AutoYesNoOption.Auto:
  83. case AutoYesNoOption.Yes:
  84. if (FindCygwin())
  85. goto Found;
  86. break;
  87. }
  88. if ((path = FindInPath("ssh.exe")) != null)
  89. {
  90. Debug.WriteLine("Found OpenSSH in path: {0}", path, null);
  91. goto Found;
  92. }
  93. return false;
  94. Found:
  95. path = path.Trim();
  96. switch (mintty)
  97. {
  98. case AutoYesNoOption.Auto:
  99. case AutoYesNoOption.Yes:
  100. FindMintty();
  101. break;
  102. }
  103. return true;
  104. }
  105. public void Execute(Uri uri, string user, string password)
  106. {
  107. if (!Find())
  108. throw new Exception("Could not find OpenSSH executable.");
  109. string command = path;
  110. StringBuilder args = new StringBuilder();
  111. if (minttyPath != null)
  112. {
  113. command = minttyPath;
  114. if (cygwinPath != null)
  115. {
  116. string icon = Path.Combine(cygwinPath, "Cygwin-Terminal.ico");
  117. if (File.Exists(icon))
  118. args.AppendFormat("-i {0} ", icon);
  119. }
  120. args.AppendFormat("-e {0} ", path);
  121. }
  122. if (password != null)
  123. Debug.WriteLine("Warning: OpenSSH does not support passing a password.");
  124. if (uri.Port != -1)
  125. args.AppendFormat("-p {0} ", uri.Port);
  126. if (user != null)
  127. args.AppendFormat("{0}@", user);
  128. args.Append(uri.Host);
  129. Debug.WriteLine("Running OpenSSH command: {0} {1}", command, args);
  130. Process.Start(command, args.ToString());
  131. }
  132. private bool FindCygwin()
  133. {
  134. if (cygwinPath != null)
  135. goto Found;
  136. foreach (var hive in new RegistryHive[] { RegistryHive.CurrentUser, RegistryHive.LocalMachine })
  137. {
  138. var views = new List<RegistryView>(new RegistryView[] { RegistryView.Registry32 });
  139. if (Environment.Is64BitOperatingSystem)
  140. views.Insert(0, RegistryView.Registry64);
  141. foreach (RegistryView view in views)
  142. using (RegistryKey baseKey = RegistryKey.OpenBaseKey(hive, view), key = baseKey.OpenSubKey(@"SOFTWARE\Cygwin\setup"))
  143. if (key != null)
  144. {
  145. cygwinPath = (string)key.GetValue("rootdir");
  146. if (cygwinPath == null)
  147. continue;
  148. if (Directory.Exists(cygwinPath))
  149. {
  150. Debug.WriteLine("Found Cygwin in registry: {0}", cygwinPath, null);
  151. goto Found;
  152. }
  153. else
  154. cygwinPath = null;
  155. }
  156. }
  157. if (cygwin == AutoYesNoOption.Yes)
  158. throw new Exception("Could not find Cygwin in registry.");
  159. return false;
  160. Found:
  161. cygwinPath = cygwinPath.Trim();
  162. path = Path.Combine(cygwinPath, "bin", "ssh.exe");
  163. if (File.Exists(path))
  164. {
  165. Debug.WriteLine("Found OpenSSH in Cygwin directory: {0}", path, null);
  166. return true;
  167. }
  168. else if (cygwin == AutoYesNoOption.Yes)
  169. throw new Exception("Could not find OpenSSH in Cygwin directory.");
  170. else
  171. {
  172. path = null;
  173. return false;
  174. }
  175. }
  176. private void FindMintty()
  177. {
  178. if (minttyPath != null)
  179. goto Found;
  180. if (cygwinPath != null)
  181. {
  182. minttyPath = Path.Combine(cygwinPath, "bin", "mintty.exe");
  183. if (File.Exists(minttyPath))
  184. {
  185. Debug.WriteLine("Found MinTTY in Cygwin directory: {0}", minttyPath, null);
  186. goto Found;
  187. }
  188. else
  189. minttyPath = null;
  190. }
  191. if ((minttyPath = FindInPath("mintty.exe")) != null)
  192. {
  193. Debug.WriteLine("Found MinTTY in path: {0}", minttyPath, null);
  194. goto Found;
  195. }
  196. if (mintty == AutoYesNoOption.Yes)
  197. throw new Exception("Could no find MinTTY executable.");
  198. return;
  199. Found:
  200. minttyPath = minttyPath.Trim();
  201. }
  202. }