Compare commits

...
13 Commits
Author SHA1 Message Date
noisyfox b6cd8e0750 Update CHANGES and bump version 2016-12-06 22:43:19 +11:00
noisyfox cc6f77efa5 Refine code 2016-12-06 22:34:17 +11:00
noisyfox 65b9c9f5fa Allow check pre-release version 2016-12-06 22:01:00 +11:00
Syrone Wong 1e7a8de34a Fix privoxy listening port conflict (#920)
Let TCP stack find a free port for us

Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-12-03 03:00:31 +11:00
Syrone Wong 355ab0e63d Use UTF-8 encoding for optional tag in ss url (#918)
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-12-01 00:31:03 +11:00
Syrone Wong 6d01cb074e Add optional tag support for ss url (#917)
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-11-30 22:58:33 +11:00
noisyfox 17c60bf9cc Don't UpdateSystemProxy before SaveConfig.
Otherwise we will update proxy twice.
2016-11-23 03:46:14 +11:00
noisyfox 41827f283e Refine code 2016-11-23 03:22:00 +11:00
noisyfox e7b559f1da Refine code 2016-11-23 02:42:12 +11:00
noisyfox 63816ccdd1 Fix hotkey unregister issue.
Use singleton mode for hotkey callbacks.
2016-11-23 02:34:07 +11:00
noisyfox 206e0b8cb5 Fix a null ref
if user manually deleted the whole 'configs' field in gui-config.json.
Which won't crash the app but will lost all other configs.
2016-11-21 14:12:31 +11:00
noisyfox 86eeba3b7d Fix crash while showing config dialog.
If user manually deleted servers from gui-config.json
2016-11-21 13:50:15 +11:00
noisyfox 6df3250a9f Fix crash on startup when user manually deleted servers from gui-config.json 2016-11-21 13:41:36 +11:00
19 changed files with 475 additions and 389 deletions
+11
View File
@@ -1,3 +1,14 @@
3.3.6 2016-12-6
- Refine system proxy mode switching logic,
merge 'Switch to PAC' and 'Switch to Global' into
'Switch system proxy mode'.
- Don't store LogViewer window size in config file,
now you can sync config between devices with different
resolutions.
- Add tag support for SS url
- Add pre-release channel in update checker
- Bug fixes and improvements
3.3.5 2016-11-7
- Improve system power mode handling
- Update mbed TLS to 2.4.0
@@ -14,9 +14,9 @@ namespace Shadowsocks.Controller
{
class PACServer : Listener.Service
{
public static readonly string PAC_FILE = "pac.txt";
public static readonly string USER_RULE_FILE = "user-rule.txt";
public static readonly string USER_ABP_FILE = "abp.txt";
public const string PAC_FILE = "pac.txt";
public const string USER_RULE_FILE = "user-rule.txt";
public const string USER_ABP_FILE = "abp.txt";
FileSystemWatcher PACFileWatcher;
FileSystemWatcher UserRuleFileWatcher;
@@ -6,6 +6,7 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
@@ -41,17 +42,10 @@ namespace Shadowsocks.Controller
}
}
public int RunningPort
{
get
{
return _runningPort;
}
}
public int RunningPort => _runningPort;
public void Start(Configuration configuration)
{
Server server = configuration.GetCurrentServer();
if (_process == null)
{
Process[] existingPrivoxy = Process.GetProcessesByName("ss_privoxy");
@@ -90,6 +84,7 @@ namespace Shadowsocks.Controller
if (_process != null)
{
KillProcess(_process);
_process.Dispose();
_process = null;
}
RefreshTrayArea();
@@ -160,21 +155,12 @@ namespace Shadowsocks.Controller
int defaultPort = 8123;
try
{
IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties();
IPEndPoint[] tcpEndPoints = properties.GetActiveTcpListeners();
List<int> usedPorts = new List<int>();
foreach (IPEndPoint endPoint in IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners())
{
usedPorts.Add(endPoint.Port);
}
for (int port = defaultPort; port <= 65535; port++)
{
if (!usedPorts.Contains(port))
{
return port;
}
}
// TCP stack please do me a favor
TcpListener l = new TcpListener(IPAddress.Loopback, 0);
l.Start();
var port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop();
return port;
}
catch (Exception e)
{
@@ -182,7 +168,6 @@ namespace Shadowsocks.Controller
Logging.LogUsefulException(e);
return defaultPort;
}
throw new Exception("No free port found.");
}
[StructLayout(LayoutKind.Sequential)]
@@ -18,12 +18,13 @@ namespace Shadowsocks.Controller
private Configuration config;
public bool NewVersionFound;
public string LatestVersionNumber;
public string LatestVersionSuffix;
public string LatestVersionName;
public string LatestVersionURL;
public string LatestVersionLocalName;
public event EventHandler CheckUpdateCompleted;
public const string Version = "3.3.5";
public const string Version = "3.3.6";
private class CheckUpdateTimer : System.Timers.Timer
{
@@ -83,17 +84,21 @@ namespace Shadowsocks.Controller
{
foreach (JObject release in result)
{
if ((bool)release["prerelease"])
var isPreRelease = (bool) release["prerelease"];
if (isPreRelease && !config.checkPreRelease)
{
continue;
}
foreach (JObject asset in (JArray)release["assets"])
{
Asset ass = new Asset();
ass.Parse(asset);
if (ass.IsNewVersion(Version))
Asset ass = Asset.ParseAsset(asset);
if (ass != null)
{
asserts.Add(ass);
ass.prerelease = isPreRelease;
if (ass.IsNewVersion(Version, config.checkPreRelease))
{
asserts.Add(ass);
}
}
}
}
@@ -106,6 +111,7 @@ namespace Shadowsocks.Controller
LatestVersionURL = asset.browser_download_url;
LatestVersionNumber = asset.version;
LatestVersionName = asset.name;
LatestVersionSuffix = asset.suffix == null ? "" : $"-{asset.suffix}";
startDownload();
}
@@ -148,7 +154,7 @@ namespace Shadowsocks.Controller
Logging.LogUsefulException(e.Error);
return;
}
Logging.Debug($"New version {LatestVersionNumber} found: {LatestVersionLocalName}");
Logging.Debug($"New version {LatestVersionNumber}{LatestVersionSuffix} found: {LatestVersionLocalName}");
if (CheckUpdateCompleted != null)
{
CheckUpdateCompleted(this, new EventArgs());
@@ -179,10 +185,38 @@ namespace Shadowsocks.Controller
public string name;
public string version;
public string browser_download_url;
public string suffix;
public bool IsNewVersion(string currentVersion)
public static Asset ParseAsset(JObject assertJObject)
{
if (prerelease)
var name = (string) assertJObject["name"];
Match match = Regex.Match(name, @"^Shadowsocks-(?<version>\d+(?:\.\d+)*)(?:|-(?<suffix>.+))\.\w+$",
RegexOptions.IgnoreCase);
if (match.Success)
{
string version = match.Groups["version"].Value;
var asset = new Asset
{
browser_download_url = (string) assertJObject["browser_download_url"],
name = name,
version = version
};
if (match.Groups["suffix"].Success)
{
asset.suffix = match.Groups["suffix"].Value;
}
return asset;
}
return null;
}
public bool IsNewVersion(string currentVersion, bool checkPreRelease)
{
if (prerelease && !checkPreRelease)
{
return false;
}
@@ -190,28 +224,8 @@ namespace Shadowsocks.Controller
{
return false;
}
return CompareVersion(version, currentVersion) > 0;
}
public void Parse(JObject asset)
{
name = (string)asset["name"];
browser_download_url = (string)asset["browser_download_url"];
version = ParseVersionFromURL(browser_download_url);
prerelease = browser_download_url.IndexOf("prerelease", StringComparison.Ordinal) >= 0;
}
private static string ParseVersionFromURL(string url)
{
Match match = Regex.Match(url, @".*Shadowsocks-win.*?-([\d\.]+)\.\w+", RegexOptions.IgnoreCase);
if (match.Success)
{
if (match.Groups.Count == 2)
{
return match.Groups[1].Value;
}
}
return null;
var cmp = CompareVersion(version, currentVersion);
return cmp > 0;
}
public static int CompareVersion(string l, string r)
@@ -5,6 +5,7 @@ using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Web;
using Newtonsoft.Json;
using Shadowsocks.Controller.Strategy;
@@ -186,7 +187,6 @@ namespace Shadowsocks.Controller
public void ToggleEnable(bool enabled)
{
_config.enabled = enabled;
UpdateSystemProxy();
SaveConfig(_config);
if (EnableStatusChanged != null)
{
@@ -197,7 +197,6 @@ namespace Shadowsocks.Controller
public void ToggleGlobal(bool global)
{
_config.global = global;
UpdateSystemProxy();
SaveConfig(_config);
if (EnableGlobalChanged != null)
{
@@ -301,11 +300,15 @@ namespace Shadowsocks.Controller
public static string GetQRCode(Server server)
{
string parts = server.method;
if (server.auth) parts += "-auth";
parts += ":" + server.password + "@" + server.server + ":" + server.server_port;
string tag = string.Empty;
string auth = server.auth ? "-auth" : string.Empty;
string parts = $"{server.method}{auth}:{server.password}@{server.server}:{server.server_port}";
string base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(parts));
return "ss://" + base64;
if(!server.remarks.IsNullOrEmpty())
{
tag = $"#{HttpUtility.UrlEncode(server.remarks, Encoding.UTF8)}";
}
return $"ss://{base64}{tag}";
}
public void UpdatePACFromGFWList()
@@ -327,7 +330,6 @@ namespace Shadowsocks.Controller
public void SavePACUrl(string pacUrl)
{
_config.pacUrl = pacUrl;
UpdateSystemProxy();
SaveConfig(_config);
if (ConfigChanged != null)
{
@@ -338,7 +340,6 @@ namespace Shadowsocks.Controller
public void UseOnlinePAC(bool useOnlinePac)
{
_config.useOnlinePac = useOnlinePac;
UpdateSystemProxy();
SaveConfig(_config);
if (ConfigChanged != null)
{
@@ -356,6 +357,16 @@ namespace Shadowsocks.Controller
}
}
public void ToggleCheckingPreRelease(bool enabled)
{
_config.checkPreRelease = enabled;
Configuration.Save(_config);
if (ConfigChanged != null)
{
ConfigChanged(this, new EventArgs());
}
}
public void SaveLogViewerConfig(LogViewerConfig newConfig)
{
_config.logViewer = newConfig;
@@ -0,0 +1,115 @@
using System;
using System.Reflection;
namespace Shadowsocks.Controller.Hotkeys
{
public class HotkeyCallbacks
{
public static void InitInstance(ShadowsocksController controller)
{
if (Instance != null)
{
return;
}
Instance = new HotkeyCallbacks(controller);
}
/// <summary>
/// Create hotkey callback handler delegate based on callback name
/// </summary>
/// <param name="methodname"></param>
/// <returns></returns>
public static Delegate GetCallback(string methodname)
{
if (methodname.IsNullOrEmpty()) throw new ArgumentException(nameof(methodname));
MethodInfo dynMethod = typeof(HotkeyCallbacks).GetMethod(methodname,
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase);
return dynMethod == null ? null : Delegate.CreateDelegate(typeof(HotKeys.HotKeyCallBackHandler), Instance, dynMethod);
}
#region Singleton
private static HotkeyCallbacks Instance { get; set; }
private readonly ShadowsocksController _controller;
private HotkeyCallbacks(ShadowsocksController controller)
{
_controller = controller;
}
#endregion
#region Callbacks
private void SwitchSystemProxyCallback()
{
bool enabled = _controller.GetConfigurationCopy().enabled;
_controller.ToggleEnable(!enabled);
}
private void SwitchProxyModeCallback()
{
var config = _controller.GetConfigurationCopy();
if (config.enabled == false) return;
var currStatus = config.global;
_controller.ToggleGlobal(!currStatus);
}
private void SwitchAllowLanCallback()
{
var status = _controller.GetConfigurationCopy().shareOverLan;
_controller.ToggleShareOverLAN(!status);
}
private void ShowLogsCallback()
{
Program.MenuController.ShowLogForm_HotKey();
}
private void ServerMoveUpCallback()
{
int currIndex;
int serverCount;
GetCurrServerInfo(out currIndex, out serverCount);
if (currIndex - 1 < 0)
{
// revert to last server
currIndex = serverCount - 1;
}
else
{
currIndex -= 1;
}
_controller.SelectServerIndex(currIndex);
}
private void ServerMoveDownCallback()
{
int currIndex;
int serverCount;
GetCurrServerInfo(out currIndex, out serverCount);
if (currIndex + 1 == serverCount)
{
// revert to first server
currIndex = 0;
}
else
{
currIndex += 1;
}
_controller.SelectServerIndex(currIndex);
}
private void GetCurrServerInfo(out int currIndex, out int serverCount)
{
var currConfig = _controller.GetCurrentConfiguration();
currIndex = currConfig.index;
serverCount = currConfig.configs.Count;
}
#endregion
}
}
@@ -1,179 +1,174 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Input;
using GlobalHotKey;
namespace Shadowsocks.Util
{
public static class HotKeys
{
private static HotKeyManager _hotKeyManager;
public delegate void HotKeyCallBackHandler();
// map key and corresponding handler function
private static Dictionary<HotKey, HotKeyCallBackHandler> _keymap = new Dictionary<HotKey, HotKeyCallBackHandler>();
public static void Init()
{
_hotKeyManager = new HotKeyManager();
_hotKeyManager.KeyPressed += HotKeyManagerPressed;
}
public static void Destroy()
{
_hotKeyManager.KeyPressed -= HotKeyManagerPressed;
_hotKeyManager.Dispose();
}
private static void HotKeyManagerPressed(object sender, KeyPressedEventArgs e)
{
var hotkey = e.HotKey;
HotKeyCallBackHandler callback;
if (_keymap.TryGetValue(hotkey, out callback))
callback();
}
public static bool IsHotkeyExists( HotKey hotKey )
{
if (hotKey == null) throw new ArgumentNullException(nameof(hotKey));
return _keymap.Any( v => v.Key.Equals( hotKey ) );
}
public static bool IsCallbackExists( HotKeyCallBackHandler cb, out HotKey hotkey)
{
if (cb == null) throw new ArgumentNullException(nameof(cb));
try
{
var key = _keymap.First(x => x.Value == cb).Key;
hotkey = key;
return true;
}
catch (InvalidOperationException)
{
// not found
hotkey = null;
return false;
}
}
public static string HotKey2Str( HotKey key )
{
if (key == null) throw new ArgumentNullException(nameof(key));
return HotKey2Str( key.Key, key.Modifiers );
}
public static string HotKey2Str( Key key, ModifierKeys modifier )
{
if (!Enum.IsDefined(typeof(Key), key))
throw new InvalidEnumArgumentException(nameof(key), (int) key, typeof(Key));
try
{
ModifierKeysConverter mkc = new ModifierKeysConverter();
var keyStr = Enum.GetName(typeof(Key), key);
var modifierStr = mkc.ConvertToInvariantString(modifier);
return $"{modifierStr}+{keyStr}";
}
catch (NotSupportedException)
{
// converter exception
return null;
}
}
public static HotKey Str2HotKey(string s)
{
try
{
if (s.IsNullOrEmpty()) return null;
int offset = s.LastIndexOf("+", StringComparison.OrdinalIgnoreCase);
if (offset <= 0) return null;
string modifierStr = s.Substring(0, offset).Trim();
string keyStr = s.Substring(offset + 1).Trim();
KeyConverter kc = new KeyConverter();
ModifierKeysConverter mkc = new ModifierKeysConverter();
Key key = (Key) kc.ConvertFrom(keyStr.ToUpper());
ModifierKeys modifier = (ModifierKeys) mkc.ConvertFrom(modifierStr.ToUpper());
return new HotKey(key, modifier);
}
catch (NotSupportedException)
{
// converter exception
return null;
}
catch (NullReferenceException)
{
return null;
}
}
public static bool Regist( HotKey key, HotKeyCallBackHandler callBack )
{
if (key == null)
throw new ArgumentNullException(nameof(key));
if (callBack == null)
throw new ArgumentNullException(nameof(callBack));
try
{
_hotKeyManager.Register(key);
_keymap[key] = callBack;
return true;
}
catch (ArgumentException)
{
// already called this method with the specific hotkey
// return success silently
return true;
}
catch (Win32Exception)
{
// this hotkey already registered by other programs
// notify user to change key
return false;
}
}
public static bool Regist(Key key, ModifierKeys modifiers, HotKeyCallBackHandler callBack)
{
if (!Enum.IsDefined(typeof(Key), key))
throw new InvalidEnumArgumentException(nameof(key), (int) key, typeof(Key));
try
{
var hotkey = _hotKeyManager.Register(key, modifiers);
_keymap[hotkey] = callBack;
return true;
}
catch (ArgumentException)
{
// already called this method with the specific hotkey
// return success silently
return true;
}
catch (Win32Exception)
{
// already registered by other programs
// notify user to change key
return false;
}
}
public static void UnRegist(HotKey key)
{
if (key == null)
throw new ArgumentNullException(nameof(key));
_hotKeyManager.Unregister(key);
if(_keymap.ContainsKey(key))
_keymap.Remove(key);
}
public static IEnumerable<TControl> GetChildControls<TControl>(this Control control) where TControl : Control
{
var children = control.Controls.Count > 0 ? control.Controls.OfType<TControl>() : Enumerable.Empty<TControl>();
return children.SelectMany(c => GetChildControls<TControl>(c)).Concat(children);
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Input;
using GlobalHotKey;
namespace Shadowsocks.Controller.Hotkeys
{
public static class HotKeys
{
private static HotKeyManager _hotKeyManager;
public delegate void HotKeyCallBackHandler();
// map key and corresponding handler function
private static Dictionary<HotKey, HotKeyCallBackHandler> _keymap = new Dictionary<HotKey, HotKeyCallBackHandler>();
public static void Init(ShadowsocksController controller)
{
_hotKeyManager = new HotKeyManager();
_hotKeyManager.KeyPressed += HotKeyManagerPressed;
HotkeyCallbacks.InitInstance(controller);
}
public static void Destroy()
{
_hotKeyManager.KeyPressed -= HotKeyManagerPressed;
_hotKeyManager.Dispose();
}
private static void HotKeyManagerPressed(object sender, KeyPressedEventArgs e)
{
var hotkey = e.HotKey;
HotKeyCallBackHandler callback;
if (_keymap.TryGetValue(hotkey, out callback))
callback();
}
public static bool IsHotkeyExists( HotKey hotKey )
{
if (hotKey == null) throw new ArgumentNullException(nameof(hotKey));
return _keymap.Any( v => v.Key.Equals( hotKey ) );
}
public static bool IsCallbackExists( HotKeyCallBackHandler cb, out HotKey hotkey)
{
if (cb == null) throw new ArgumentNullException(nameof(cb));
try
{
var key = _keymap.First(x => x.Value == cb).Key;
hotkey = key;
return true;
}
catch (InvalidOperationException)
{
// not found
hotkey = null;
return false;
}
}
public static string HotKey2Str( HotKey key )
{
if (key == null) throw new ArgumentNullException(nameof(key));
return HotKey2Str( key.Key, key.Modifiers );
}
public static string HotKey2Str( Key key, ModifierKeys modifier )
{
if (!Enum.IsDefined(typeof(Key), key))
throw new InvalidEnumArgumentException(nameof(key), (int) key, typeof(Key));
try
{
ModifierKeysConverter mkc = new ModifierKeysConverter();
var keyStr = Enum.GetName(typeof(Key), key);
var modifierStr = mkc.ConvertToInvariantString(modifier);
return $"{modifierStr}+{keyStr}";
}
catch (NotSupportedException)
{
// converter exception
return null;
}
}
public static HotKey Str2HotKey(string s)
{
try
{
if (s.IsNullOrEmpty()) return null;
int offset = s.LastIndexOf("+", StringComparison.OrdinalIgnoreCase);
if (offset <= 0) return null;
string modifierStr = s.Substring(0, offset).Trim();
string keyStr = s.Substring(offset + 1).Trim();
KeyConverter kc = new KeyConverter();
ModifierKeysConverter mkc = new ModifierKeysConverter();
Key key = (Key) kc.ConvertFrom(keyStr.ToUpper());
ModifierKeys modifier = (ModifierKeys) mkc.ConvertFrom(modifierStr.ToUpper());
return new HotKey(key, modifier);
}
catch (NotSupportedException)
{
// converter exception
return null;
}
catch (NullReferenceException)
{
return null;
}
}
public static bool Regist( HotKey key, HotKeyCallBackHandler callBack )
{
if (key == null)
throw new ArgumentNullException(nameof(key));
if (callBack == null)
throw new ArgumentNullException(nameof(callBack));
try
{
_hotKeyManager.Register(key);
_keymap[key] = callBack;
return true;
}
catch (ArgumentException)
{
// already called this method with the specific hotkey
// return success silently
return true;
}
catch (Win32Exception)
{
// this hotkey already registered by other programs
// notify user to change key
return false;
}
}
public static bool Regist(Key key, ModifierKeys modifiers, HotKeyCallBackHandler callBack)
{
if (!Enum.IsDefined(typeof(Key), key))
throw new InvalidEnumArgumentException(nameof(key), (int) key, typeof(Key));
try
{
var hotkey = _hotKeyManager.Register(key, modifiers);
_keymap[hotkey] = callBack;
return true;
}
catch (ArgumentException)
{
// already called this method with the specific hotkey
// return success silently
return true;
}
catch (Win32Exception)
{
// already registered by other programs
// notify user to change key
return false;
}
}
public static void UnRegist(HotKey key)
{
if (key == null)
throw new ArgumentNullException(nameof(key));
_hotKeyManager.Unregister(key);
if(_keymap.ContainsKey(key))
_keymap.Remove(key);
}
}
}
+1
View File
@@ -27,6 +27,7 @@ Verbose Logging=详细记录日志
Updates...=更新...
Check for Updates...=检查更新
Check for Updates at Startup=启动时检查更新
Check Pre-release Version=检查测试版更新
Edit Hotkeys...=编辑快捷键...
About...=关于...
Quit=退出
+1
View File
@@ -27,6 +27,7 @@ Verbose Logging=詳細記錄日誌
Updates...=更新...
Check for Updates...=檢查更新
Check for Updates at Startup=啟動時檢查更新
Check Pre-release Version=檢查測試版更新
Edit Hotkeys...=編輯捷徑鍵...
About...=關於...
Quit=退出
+6
View File
@@ -24,6 +24,7 @@ namespace Shadowsocks.Model
public bool useOnlinePac;
public bool availabilityStatistics;
public bool autoCheckUpdate;
public bool checkPreRelease;
public bool isVerboseLogging;
public LogViewerConfig logViewer;
public ProxyConfig proxy;
@@ -54,6 +55,11 @@ namespace Shadowsocks.Model
string configContent = File.ReadAllText(CONFIG_FILE);
Configuration config = JsonConvert.DeserializeObject<Configuration>(configContent);
config.isDefault = false;
if (config.configs == null)
config.configs = new List<Server>();
if (config.configs.Count == 0)
config.configs.Add(GetDefaultServer());
if (config.localPort == 0)
config.localPort = 1080;
if (config.index == -1 && config.strategy == null)
+6 -3
View File
@@ -1,7 +1,7 @@
using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using Shadowsocks.Controller;
namespace Shadowsocks.Model
@@ -10,8 +10,8 @@ namespace Shadowsocks.Model
public class Server
{
public static readonly Regex
UrlFinder = new Regex("^ss://((?:[A-Za-z0-9+/]+)|((?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?))$",
RegexOptions.Compiled | RegexOptions.IgnoreCase),
UrlFinder = new Regex("^(?i)ss://([A-Za-z0-9+-/=_]+)(#(.+))?$",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
DetailsParser = new Regex("^((?<method>.+?)(?<auth>-auth)??:(?<password>.*)@(?<hostname>.+?)" +
":(?<port>\\d+?))$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
@@ -79,6 +79,9 @@ namespace Shadowsocks.Model
var match = UrlFinder.Match(ssURL);
if (!match.Success) throw new FormatException();
var base64 = match.Groups[1].Value;
var tag = match.Groups[3].Value;
if (!tag.IsNullOrEmpty())
remarks = HttpUtility.UrlDecode(tag, Encoding.UTF8);
match = DetailsParser.Match(Encoding.UTF8.GetString(Convert.FromBase64String(
base64.PadRight(base64.Length + (4 - base64.Length % 4) % 4, '='))));
method = match.Groups["method"].Value;
+15 -15
View File
@@ -6,6 +6,7 @@ using System.Windows.Forms;
using Microsoft.Win32;
using Shadowsocks.Controller;
using Shadowsocks.Controller.Hotkeys;
using Shadowsocks.Util;
using Shadowsocks.View;
@@ -13,9 +14,8 @@ namespace Shadowsocks
{
static class Program
{
private static ShadowsocksController _controller;
// XXX: Don't change this name
private static MenuViewController _viewController;
public static ShadowsocksController MainController { get; private set; }
public static MenuViewController MenuController { get; private set; }
/// <summary>
/// 应用程序的主入口点。
@@ -79,10 +79,10 @@ namespace Shadowsocks
#else
Logging.OpenLogFile();
#endif
_controller = new ShadowsocksController();
_viewController = new MenuViewController(_controller);
HotKeys.Init();
_controller.Start();
MainController = new ShadowsocksController();
MenuController = new MenuViewController(MainController);
HotKeys.Init(MainController);
MainController.Start();
Application.Run();
}
}
@@ -120,7 +120,7 @@ namespace Shadowsocks
{
case PowerModes.Resume:
Logging.Info("os wake up");
if (_controller != null)
if (MainController != null)
{
System.Timers.Timer timer = new System.Timers.Timer(10 * 1000);
timer.Elapsed += Timer_Elapsed;
@@ -130,9 +130,9 @@ namespace Shadowsocks
}
break;
case PowerModes.Suspend:
if (_controller != null)
if (MainController != null)
{
_controller.Stop();
MainController.Stop();
Logging.Info("controller stopped");
}
Logging.Info("os suspend");
@@ -144,9 +144,9 @@ namespace Shadowsocks
{
try
{
if (_controller != null)
if (MainController != null)
{
_controller.Start();
MainController.Start();
Logging.Info("controller started");
}
}
@@ -177,10 +177,10 @@ namespace Shadowsocks
SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
Application.ThreadException -= Application_ThreadException;
HotKeys.Destroy();
if (_controller != null)
if (MainController != null)
{
_controller.Stop();
_controller = null;
MainController.Stop();
MainController = null;
}
}
}
+1 -1
View File
@@ -23,7 +23,7 @@ namespace Shadowsocks.Util
}
}
public class Utils
public static class Utils
{
private static bool? _portableMode;
private static string TempPath = null;
+21
View File
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace Shadowsocks.Util
{
public static class ViewUtils
{
public static IEnumerable<TControl> GetChildControls<TControl>(this Control control) where TControl : Control
{
if (control.Controls.Count == 0)
{
return Enumerable.Empty<TControl>();
}
var children = control.Controls.OfType<TControl>().ToList();
return children.SelectMany(GetChildControls<TControl>).Concat(children);
}
}
}
+1 -1
View File
@@ -151,7 +151,7 @@ namespace Shadowsocks.View
_modifiedConfiguration = controller.GetConfigurationCopy();
LoadConfiguration(_modifiedConfiguration);
_lastSelectedIndex = _modifiedConfiguration.index;
if (_lastSelectedIndex < 0)
if (_lastSelectedIndex < 0 || _lastSelectedIndex >= ServersListBox.Items.Count)
{
_lastSelectedIndex = 0;
}
+32 -122
View File
@@ -7,6 +7,7 @@ using System.Text;
using System.Windows.Forms;
using Shadowsocks.Controller;
using Shadowsocks.Controller.Hotkeys;
using Shadowsocks.Model;
using Shadowsocks.Properties;
using Shadowsocks.Util;
@@ -15,23 +16,18 @@ namespace Shadowsocks.View
{
public partial class HotkeySettingsForm : Form
{
private ShadowsocksController _controller;
private readonly ShadowsocksController _controller;
// this is a copy of configuration that we are working on
private HotkeyConfig _modifiedConfig;
private StringBuilder _sb = new StringBuilder();
private IEnumerable<TextBox> _allTextBoxes;
private Label _lb = null;
private HotKeys.HotKeyCallBackHandler _callBack = null;
private readonly IEnumerable<TextBox> _allTextBoxes;
public HotkeySettingsForm(ShadowsocksController controller)
{
InitializeComponent();
UpdateTexts();
this.Icon = Icon.FromHandle(Resources.ssw128.GetHicon());
Icon = Icon.FromHandle(Resources.ssw128.GetHicon());
_controller = controller;
_controller.ConfigChanged += controller_ConfigChanged;
@@ -39,7 +35,7 @@ namespace Shadowsocks.View
LoadCurrentConfiguration();
// get all textboxes belong to this form
_allTextBoxes = HotKeys.GetChildControls<TextBox>(this.tableLayoutPanel1);
_allTextBoxes = tableLayoutPanel1.GetChildControls<TextBox>();
if (!_allTextBoxes.Any()) throw new Exception("Cannot get all textboxes");
}
@@ -76,7 +72,7 @@ namespace Shadowsocks.View
btnOK.Text = I18N.GetString("OK");
btnCancel.Text = I18N.GetString("Cancel");
btnRegisterAll.Text = I18N.GetString("Reg All");
this.Text = I18N.GetString("Edit Hotkeys...");
Text = I18N.GetString("Edit Hotkeys...");
}
/// <summary>
@@ -84,7 +80,7 @@ namespace Shadowsocks.View
/// </summary>
private void HotkeyDown(object sender, KeyEventArgs e)
{
_sb.Length = 0;
StringBuilder sb = new StringBuilder();
//Combination key only
if (e.Modifiers != 0)
{
@@ -92,15 +88,15 @@ namespace Shadowsocks.View
// Windows key is reserved by operating system, we deny this key.
if (e.Control)
{
_sb.Append("Ctrl+");
sb.Append("Ctrl+");
}
if (e.Alt)
{
_sb.Append("Alt+");
sb.Append("Alt+");
}
if (e.Shift)
{
_sb.Append("Shift+");
sb.Append("Shift+");
}
Keys keyvalue = (Keys) e.KeyValue;
@@ -108,18 +104,18 @@ namespace Shadowsocks.View
(keyvalue >= Keys.A && keyvalue <= Keys.Z) ||
(keyvalue >= Keys.F1 && keyvalue <= Keys.F12))
{
_sb.Append(e.KeyCode);
sb.Append(e.KeyCode);
}
else if (keyvalue >= Keys.D0 && keyvalue <= Keys.D9)
{
_sb.Append('D').Append((char) e.KeyValue);
sb.Append('D').Append((char) e.KeyValue);
}
else if (keyvalue >= Keys.NumPad0 && keyvalue <= Keys.NumPad9)
{
_sb.Append("NumPad").Append((char) (e.KeyValue - 48));
sb.Append("NumPad").Append((char) (e.KeyValue - 48));
}
}
((TextBox) sender).Text = _sb.ToString();
((TextBox) sender).Text = sb.ToString();
}
/// <summary>
@@ -127,8 +123,8 @@ namespace Shadowsocks.View
/// </summary>
private void HotkeyUp(object sender, KeyEventArgs e)
{
TextBox tb = sender as TextBox;
string content = tb.Text.TrimEnd();
var tb = (TextBox) sender;
var content = tb.Text.TrimEnd();
if (content.Length >= 1 && content[content.Length - 1] == '+')
{
tb.Text = "";
@@ -137,7 +133,7 @@ namespace Shadowsocks.View
private void TextBox_TextChanged(object sender, EventArgs e)
{
TextBox tb = sender as TextBox;
var tb = (TextBox) sender;
if (tb.Text == "")
{
@@ -148,15 +144,17 @@ namespace Shadowsocks.View
private void UnregHotkey(TextBox tb)
{
HotKeys.HotKeyCallBackHandler callBack;
Label lb;
PrepareForHotkey(tb, out _callBack, out _lb);
PrepareForHotkey(tb, out callBack, out lb);
UnregPrevHotkey(_callBack);
UnregPrevHotkey(callBack);
}
private void CancelButton_Click(object sender, EventArgs e)
{
this.Close();
Close();
}
private void OKButton_Click(object sender, EventArgs e)
@@ -177,7 +175,7 @@ namespace Shadowsocks.View
// All check passed, saving
SaveConfig();
this.Close();
Close();
}
private void RegisterAllButton_Click(object sender, EventArgs e)
@@ -202,9 +200,12 @@ namespace Shadowsocks.View
return false;
}
PrepareForHotkey(tb, out _callBack, out _lb);
HotKeys.HotKeyCallBackHandler callBack;
Label lb;
UnregPrevHotkey(_callBack);
PrepareForHotkey(tb, out callBack, out lb);
UnregPrevHotkey(callBack);
// try to register keys
// if already registered by other progs
@@ -217,8 +218,8 @@ namespace Shadowsocks.View
// or change to another one
// Transparent without color: first run or empty config
bool regResult = HotKeys.Regist(hotkey, _callBack);
_lb.BackColor = regResult ? Color.Green : Color.Yellow;
bool regResult = HotKeys.Regist(hotkey, callBack);
lb.BackColor = regResult ? Color.Green : Color.Yellow;
return regResult;
}
@@ -243,81 +244,7 @@ namespace Shadowsocks.View
_controller.SaveHotkeyConfig(_modifiedConfig);
}
#region Callbacks
private void SwitchSystemProxyCallback()
{
bool enabled = _controller.GetConfigurationCopy().enabled;
_controller.ToggleEnable(!enabled);
}
private void SwitchProxyModeCallback()
{
var config = _controller.GetConfigurationCopy();
if (config.enabled == false) return;
var currStatus = config.global;
_controller.ToggleGlobal(!currStatus);
}
private void SwitchAllowLanCallback()
{
var status = _controller.GetConfigurationCopy().shareOverLan;
_controller.ToggleShareOverLAN(!status);
}
private void ShowLogsCallback()
{
// Get the current MenuViewController in this program via reflection
FieldInfo fi = Assembly.GetExecutingAssembly().GetType("Shadowsocks.Program")
.GetField("_viewController",
BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.IgnoreCase);
// To retrieve the value of a static field, pass null here
var mvc = fi.GetValue(null) as MenuViewController;
mvc.ShowLogForm_HotKey();
}
private void ServerMoveUpCallback()
{
int currIndex;
int serverCount;
GetCurrServerInfo(out currIndex, out serverCount);
if (currIndex - 1 < 0)
{
// revert to last server
currIndex = serverCount - 1;
}
else
{
currIndex -= 1;
}
_controller.SelectServerIndex(currIndex);
}
private void ServerMoveDownCallback()
{
int currIndex;
int serverCount;
GetCurrServerInfo(out currIndex, out serverCount);
if (currIndex + 1 == serverCount)
{
// revert to first server
currIndex = 0;
}
else
{
currIndex += 1;
}
_controller.SelectServerIndex(currIndex);
}
private void GetCurrServerInfo(out int currIndex, out int serverCount)
{
var currConfig = _controller.GetCurrentConfiguration();
currIndex = currConfig.index;
serverCount = currConfig.configs.Count;
}
#endregion
#region Prepare hotkey
@@ -343,14 +270,14 @@ namespace Shadowsocks.View
var labelName = rawName + "Label";
var callbackName = rawName + "Callback";
var callback = GetDelegateViaMethodName(this.GetType(), callbackName);
var callback = HotkeyCallbacks.GetCallback(callbackName);
if (callback == null)
{
throw new Exception($"{callbackName} not found");
}
cb = callback as HotKeys.HotKeyCallBackHandler;
object label = GetFieldViaName(this.GetType(), labelName, this);
var label = GetFieldViaName(GetType(), labelName, this);
if (label == null)
{
throw new Exception($"{labelName} not found");
@@ -375,23 +302,6 @@ namespace Shadowsocks.View
return fi == null ? null : fi.GetValue(obj);
}
/// <summary>
/// Create hotkey callback handler delegate based on callback name
/// </summary>
/// <param name="type"></param>
/// <param name="methodname"></param>
/// <returns></returns>
private Delegate GetDelegateViaMethodName(Type type, string methodname)
{
if (type == null) throw new ArgumentNullException(nameof(type));
if (methodname.IsNullOrEmpty()) throw new ArgumentException(nameof(methodname));
//HotkeySettingsForm form = new HotkeySettingsForm(_controller);
Type delegateType = Type.GetType("Shadowsocks.Util.HotKeys").GetNestedType("HotKeyCallBackHandler");
MethodInfo dynMethod = type.GetMethod(methodname,
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase);
return dynMethod == null ? null : Delegate.CreateDelegate(delegateType, this, dynMethod);
}
#endregion
}
}
+11 -1
View File
@@ -48,6 +48,7 @@ namespace Shadowsocks.View
private MenuItem editGFWUserRuleItem;
private MenuItem editOnlinePACItem;
private MenuItem autoCheckUpdatesToggleItem;
private MenuItem checkPreReleaseToggleItem;
private MenuItem proxyItem;
private MenuItem hotKeyItem;
private MenuItem VerboseLoggingToggleItem;
@@ -283,6 +284,7 @@ namespace Shadowsocks.View
CreateMenuItem("Check for Updates...", new EventHandler(this.checkUpdatesItem_Click)),
new MenuItem("-"),
this.autoCheckUpdatesToggleItem = CreateMenuItem("Check for Updates at Startup", new EventHandler(this.autoCheckUpdatesToggleItem_Click)),
this.checkPreReleaseToggleItem = CreateMenuItem("Check Pre-release Version", new EventHandler(this.checkPreReleaseToggleItem_Click)),
}),
CreateMenuItem("About...", new EventHandler(this.AboutItem_Click)),
new MenuItem("-"),
@@ -352,7 +354,7 @@ namespace Shadowsocks.View
{
if (updateChecker.NewVersionFound)
{
ShowBalloonTip(String.Format(I18N.GetString("Shadowsocks {0} Update Found"), updateChecker.LatestVersionNumber), I18N.GetString("Click here to update"), ToolTipIcon.Info, 5000);
ShowBalloonTip(String.Format(I18N.GetString("Shadowsocks {0} Update Found"), updateChecker.LatestVersionNumber + updateChecker.LatestVersionSuffix), I18N.GetString("Click here to update"), ToolTipIcon.Info, 5000);
}
else if (!_isStartupChecking)
{
@@ -816,6 +818,7 @@ namespace Shadowsocks.View
{
Configuration configuration = controller.GetConfigurationCopy();
autoCheckUpdatesToggleItem.Checked = configuration.autoCheckUpdate;
checkPreReleaseToggleItem.Checked = configuration.checkPreRelease;
}
private void autoCheckUpdatesToggleItem_Click(object sender, EventArgs e)
@@ -825,6 +828,13 @@ namespace Shadowsocks.View
UpdateUpdateMenu();
}
private void checkPreReleaseToggleItem_Click(object sender, EventArgs e)
{
Configuration configuration = controller.GetConfigurationCopy();
controller.ToggleCheckingPreRelease(!configuration.checkPreRelease);
UpdateUpdateMenu();
}
private void checkUpdatesItem_Click(object sender, EventArgs e)
{
updateChecker.CheckUpdate(controller.GetConfigurationCopy());
+4 -1
View File
@@ -81,6 +81,7 @@
<Reference Include="System.Drawing" />
<Reference Include="System.Management" />
<Reference Include="System.Net" />
<Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Windows.Forms.DataVisualization" />
<Reference Include="System.XML" />
@@ -139,6 +140,7 @@
<Compile Include="3rd\zxing\ResultPoint.cs" />
<Compile Include="3rd\zxing\ResultPointCallback.cs" />
<Compile Include="3rd\zxing\WriterException.cs" />
<Compile Include="Controller\System\Hotkeys\HotkeyCallbacks.cs" />
<Compile Include="Model\HotKeyConfig.cs" />
<Compile Include="Model\ProxyConfig.cs" />
<Compile Include="Properties\Settings.Designer.cs">
@@ -186,7 +188,7 @@
<Compile Include="Proxy\Socks5Proxy.cs" />
<Compile Include="Settings.cs" />
<Compile Include="StringEx.cs" />
<Compile Include="Util\Hotkeys.cs" />
<Compile Include="Controller\System\Hotkeys\Hotkeys.cs" />
<Compile Include="Util\ProcessManagement\Job.cs" />
<Compile Include="Util\ProcessManagement\ThreadUtil.cs" />
<Compile Include="Encryption\RNG.cs" />
@@ -201,6 +203,7 @@
<Compile Include="Util\SystemProxy\RAS.cs" />
<Compile Include="Util\SystemProxy\WinINet.cs" />
<Compile Include="Util\Util.cs" />
<Compile Include="Util\ViewUtils.cs" />
<Compile Include="View\ConfigForm.cs">
<SubType>Form</SubType>
</Compile>
+1 -1
View File
@@ -2,11 +2,11 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shadowsocks.Controller;
using Shadowsocks.Encryption;
using Shadowsocks.Util;
using GlobalHotKey;
using System.Windows.Input;
using System.Threading;
using System.Collections.Generic;
using Shadowsocks.Controller.Hotkeys;
namespace test
{