Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03c087db6d | ||
|
|
5741133d5c | ||
|
|
28954600a2 | ||
|
|
6ddd3d486b | ||
|
|
dd269ac89d | ||
|
|
09d89b424d | ||
|
|
5e973adb77 | ||
|
|
f149851e3b | ||
|
|
511a658fd3 | ||
|
|
efe6d5ba81 | ||
|
|
1f47812eca | ||
|
|
7a39c2c71f | ||
|
|
dc48546fed | ||
|
|
eef990f529 | ||
|
|
f66638d14c | ||
|
|
0c055caffd | ||
|
|
efc486c733 | ||
|
|
b7b92a4af9 | ||
|
|
a447feece2 | ||
|
|
2a0dd88525 | ||
|
|
5650b1d847 | ||
|
|
b972cb250b | ||
|
|
f363b94fd6 | ||
|
|
a08993519f | ||
|
|
8a68a3515b | ||
|
|
76fbd808e3 | ||
|
|
557c797a9a | ||
|
|
ac45b44c09 | ||
|
|
c0299090c4 | ||
|
|
de4a2f862b | ||
|
|
430137495c | ||
|
|
566a0fcfa5 | ||
|
|
2c15520230 | ||
|
|
9cdb71875a | ||
|
|
b04c59d8e6 | ||
|
|
f2b8e91f81 | ||
|
|
d1e8f38767 | ||
|
|
f9e39fdd1d | ||
|
|
5ba0dffa5d | ||
|
|
0d4d01af3b | ||
|
|
a61b10bb67 | ||
|
|
be3cc3f3a6 | ||
|
|
5c5f753721 | ||
|
|
264b91d6b0 | ||
|
|
4b067346bf | ||
|
|
9e51b4a41b | ||
|
|
983c1adb28 | ||
|
|
22d8cdeff7 | ||
|
|
b6cd8e0750 | ||
|
|
cc6f77efa5 | ||
|
|
65b9c9f5fa | ||
|
|
1e7a8de34a | ||
|
|
355ab0e63d | ||
|
|
6d01cb074e | ||
|
|
17c60bf9cc | ||
|
|
41827f283e | ||
|
|
e7b559f1da | ||
|
|
63816ccdd1 | ||
|
|
206e0b8cb5 | ||
|
|
86eeba3b7d | ||
|
|
6df3250a9f |
@@ -1,3 +1,33 @@
|
||||
3.4.2 2016-12-16
|
||||
- Fix null ref in TCPRelay. (#940)
|
||||
- Bring Privoxy back. (#948)
|
||||
- Bug fixes and improvements.
|
||||
|
||||
3.4.1 (pre-release) 2016-12-13
|
||||
- Fix crash if user input an invaild server address. (#933)
|
||||
- Fix ERR_TOO_MANY_REDIRECTS with http proxy. (#937)
|
||||
- Show SS URL in QRCode form.
|
||||
- Add import URL from clipboard.
|
||||
- Bug fixes and improvements.
|
||||
|
||||
3.4.0 (pre-release) 2016-12-9
|
||||
- Replace Privoxy with built-in http proxy.
|
||||
- Try fix system proxy settings on windows 10 insider preview.
|
||||
- Secure local pac.
|
||||
- Update bypass list.
|
||||
- Bug fixes and improvements.
|
||||
|
||||
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
|
||||
|
||||
@@ -5,18 +5,22 @@ using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
using Shadowsocks.Encryption;
|
||||
using Shadowsocks.Model;
|
||||
using Shadowsocks.Properties;
|
||||
using Shadowsocks.Util;
|
||||
|
||||
namespace Shadowsocks.Controller
|
||||
{
|
||||
class PACServer : Listener.Service
|
||||
public 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";
|
||||
|
||||
private string PacSecret { get; set; } = "";
|
||||
|
||||
public string PacUrl { get; private set; } = "";
|
||||
|
||||
FileSystemWatcher PACFileWatcher;
|
||||
FileSystemWatcher UserRuleFileWatcher;
|
||||
@@ -34,6 +38,25 @@ namespace Shadowsocks.Controller
|
||||
public void UpdateConfiguration(Configuration config)
|
||||
{
|
||||
this._config = config;
|
||||
|
||||
if (config.secureLocalPac)
|
||||
{
|
||||
var rd = new byte[32];
|
||||
RNG.GetBytes(rd);
|
||||
PacSecret = $"&secret={Convert.ToBase64String(rd)}";
|
||||
}
|
||||
else
|
||||
{
|
||||
PacSecret = "";
|
||||
}
|
||||
|
||||
PacUrl = $"http://127.0.0.1:{config.localPort}/pac?t={GetTimestamp(DateTime.Now)}{PacSecret}";
|
||||
}
|
||||
|
||||
|
||||
private static string GetTimestamp(DateTime value)
|
||||
{
|
||||
return value.ToString("yyyyMMddHHmmssfff");
|
||||
}
|
||||
|
||||
public override bool Handle(byte[] firstPacket, int length, Socket socket, object state)
|
||||
@@ -47,6 +70,7 @@ namespace Shadowsocks.Controller
|
||||
string request = Encoding.UTF8.GetString(firstPacket, 0, length);
|
||||
string[] lines = request.Split('\r', '\n');
|
||||
bool hostMatch = false, pathMatch = false, useSocks = false;
|
||||
bool secretMatch = PacSecret.IsNullOrEmpty();
|
||||
foreach (string line in lines)
|
||||
{
|
||||
string[] kv = line.Split(new char[] { ':' }, 2);
|
||||
@@ -74,11 +98,25 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
pathMatch = true;
|
||||
}
|
||||
if (!secretMatch)
|
||||
{
|
||||
if(line.IndexOf(PacSecret, StringComparison.Ordinal) >= 0)
|
||||
{
|
||||
secretMatch = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hostMatch && pathMatch)
|
||||
{
|
||||
SendResponse(firstPacket, length, socket, useSocks);
|
||||
if (!secretMatch)
|
||||
{
|
||||
socket.Close(); // Close immediately
|
||||
}
|
||||
else
|
||||
{
|
||||
SendResponse(firstPacket, length, socket, useSocks);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -230,16 +230,21 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
try
|
||||
|
||||
if (_currentRemoteSession != null)
|
||||
{
|
||||
var remote = _currentRemoteSession.Remote;
|
||||
remote.Shutdown(SocketShutdown.Both);
|
||||
remote.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
try
|
||||
{
|
||||
var remote = _currentRemoteSession.Remote;
|
||||
remote.Shutdown(SocketShutdown.Both);
|
||||
remote.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
}
|
||||
|
||||
lock (_encryptionLock)
|
||||
{
|
||||
lock (_decryptionLock)
|
||||
@@ -540,7 +545,16 @@ namespace Shadowsocks.Controller
|
||||
}
|
||||
|
||||
var session = new AsyncSession(remote);
|
||||
_currentRemoteSession = session;
|
||||
lock (_closeConnLock)
|
||||
{
|
||||
if (_closed)
|
||||
{
|
||||
remote.Close();
|
||||
return;
|
||||
}
|
||||
|
||||
_currentRemoteSession = session;
|
||||
}
|
||||
|
||||
ProxyTimer proxyTimer = new ProxyTimer(_proxyTimeout);
|
||||
proxyTimer.AutoReset = false;
|
||||
|
||||
@@ -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.4.2";
|
||||
|
||||
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());
|
||||
@@ -170,19 +176,47 @@ namespace Shadowsocks.Controller
|
||||
|
||||
private void SortByVersions(List<Asset> asserts)
|
||||
{
|
||||
asserts.Sort(new VersionComparer());
|
||||
asserts.Sort();
|
||||
}
|
||||
|
||||
public class Asset
|
||||
public class Asset : IComparable<Asset>
|
||||
{
|
||||
public bool prerelease;
|
||||
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)
|
||||
@@ -229,14 +243,10 @@ namespace Shadowsocks.Controller
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class VersionComparer : IComparer<Asset>
|
||||
{
|
||||
// Calls CaseInsensitiveComparer.Compare with the parameters reversed.
|
||||
public int Compare(Asset x, Asset y)
|
||||
public int CompareTo(Asset other)
|
||||
{
|
||||
return Asset.CompareVersion(x.version, y.version);
|
||||
return CompareVersion(version, other.version);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using System.Windows.Forms;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using Shadowsocks.Controller.Strategy;
|
||||
@@ -186,7 +188,6 @@ namespace Shadowsocks.Controller
|
||||
public void ToggleEnable(bool enabled)
|
||||
{
|
||||
_config.enabled = enabled;
|
||||
UpdateSystemProxy();
|
||||
SaveConfig(_config);
|
||||
if (EnableStatusChanged != null)
|
||||
{
|
||||
@@ -197,7 +198,6 @@ namespace Shadowsocks.Controller
|
||||
public void ToggleGlobal(bool global)
|
||||
{
|
||||
_config.global = global;
|
||||
UpdateSystemProxy();
|
||||
SaveConfig(_config);
|
||||
if (EnableGlobalChanged != null)
|
||||
{
|
||||
@@ -221,12 +221,13 @@ namespace Shadowsocks.Controller
|
||||
SaveConfig(_config);
|
||||
}
|
||||
|
||||
public void EnableProxy(int type, string proxy, int port)
|
||||
public void EnableProxy(int type, string proxy, int port, int timeout)
|
||||
{
|
||||
_config.proxy.useProxy = true;
|
||||
_config.proxy.proxyType = type;
|
||||
_config.proxy.proxyServer = proxy;
|
||||
_config.proxy.proxyPort = port;
|
||||
_config.proxy.proxyTimeout = timeout;
|
||||
SaveConfig(_config);
|
||||
}
|
||||
|
||||
@@ -270,7 +271,7 @@ namespace Shadowsocks.Controller
|
||||
}
|
||||
if (_config.enabled)
|
||||
{
|
||||
SystemProxy.Update(_config, true);
|
||||
SystemProxy.Update(_config, true, null);
|
||||
}
|
||||
Encryption.RNG.Close();
|
||||
}
|
||||
@@ -301,11 +302,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 +332,6 @@ namespace Shadowsocks.Controller
|
||||
public void SavePACUrl(string pacUrl)
|
||||
{
|
||||
_config.pacUrl = pacUrl;
|
||||
UpdateSystemProxy();
|
||||
SaveConfig(_config);
|
||||
if (ConfigChanged != null)
|
||||
{
|
||||
@@ -338,7 +342,16 @@ namespace Shadowsocks.Controller
|
||||
public void UseOnlinePAC(bool useOnlinePac)
|
||||
{
|
||||
_config.useOnlinePac = useOnlinePac;
|
||||
UpdateSystemProxy();
|
||||
SaveConfig(_config);
|
||||
if (ConfigChanged != null)
|
||||
{
|
||||
ConfigChanged(this, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
public void ToggleSecureLocalPac(bool enabled)
|
||||
{
|
||||
_config.secureLocalPac = enabled;
|
||||
SaveConfig(_config);
|
||||
if (ConfigChanged != null)
|
||||
{
|
||||
@@ -356,10 +369,9 @@ namespace Shadowsocks.Controller
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveLogViewerConfig(LogViewerConfig newConfig)
|
||||
public void ToggleCheckingPreRelease(bool enabled)
|
||||
{
|
||||
_config.logViewer = newConfig;
|
||||
newConfig.SaveSize();
|
||||
_config.checkPreRelease = enabled;
|
||||
Configuration.Save(_config);
|
||||
if (ConfigChanged != null)
|
||||
{
|
||||
@@ -367,9 +379,10 @@ namespace Shadowsocks.Controller
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveProxyConfig(ProxyConfig newConfig)
|
||||
public void SaveLogViewerConfig(LogViewerConfig newConfig)
|
||||
{
|
||||
_config.proxy = newConfig;
|
||||
_config.logViewer = newConfig;
|
||||
newConfig.SaveSize();
|
||||
Configuration.Save(_config);
|
||||
if (ConfigChanged != null)
|
||||
{
|
||||
@@ -504,7 +517,7 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
if (_config.enabled)
|
||||
{
|
||||
SystemProxy.Update(_config, false);
|
||||
SystemProxy.Update(_config, false, _pacServer);
|
||||
_systemProxyIsDirty = true;
|
||||
}
|
||||
else
|
||||
@@ -512,7 +525,7 @@ namespace Shadowsocks.Controller
|
||||
// only switch it off if we have switched it on
|
||||
if (_systemProxyIsDirty)
|
||||
{
|
||||
SystemProxy.Update(_config, false);
|
||||
SystemProxy.Update(_config, false, _pacServer);
|
||||
_systemProxyIsDirty = false;
|
||||
}
|
||||
}
|
||||
@@ -579,6 +592,11 @@ namespace Shadowsocks.Controller
|
||||
File.WriteAllText(PACServer.PAC_FILE, abpContent, Encoding.UTF8);
|
||||
}
|
||||
|
||||
public void CopyPacUrl()
|
||||
{
|
||||
Clipboard.SetDataObject(_pacServer.PacUrl);
|
||||
}
|
||||
|
||||
#region Memory Management
|
||||
|
||||
private void StartReleasingMemory()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
+173
-178
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ namespace Shadowsocks.Controller
|
||||
return value.ToString("yyyyMMddHHmmssfff");
|
||||
}
|
||||
|
||||
public static void Update(Configuration config, bool forceDisable)
|
||||
public static void Update(Configuration config, bool forceDisable, PACServer pacSrv)
|
||||
{
|
||||
bool global = config.global;
|
||||
bool enabled = config.enabled;
|
||||
@@ -27,21 +27,25 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
if (global)
|
||||
{
|
||||
WinINet.SetIEProxy(true, true, "127.0.0.1:" + config.localPort.ToString(), "");
|
||||
Sysproxy.SetIEProxy(true, true, "127.0.0.1:" + config.localPort.ToString(), "");
|
||||
}
|
||||
else
|
||||
{
|
||||
string pacUrl;
|
||||
if (config.useOnlinePac && !config.pacUrl.IsNullOrEmpty())
|
||||
{
|
||||
pacUrl = config.pacUrl;
|
||||
}
|
||||
else
|
||||
pacUrl = $"http://127.0.0.1:{config.localPort}/pac?t={GetTimestamp(DateTime.Now)}";
|
||||
WinINet.SetIEProxy(true, false, "", pacUrl);
|
||||
{
|
||||
pacUrl = pacSrv.PacUrl;
|
||||
}
|
||||
Sysproxy.SetIEProxy(true, false, "", pacUrl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WinINet.SetIEProxy(false, false, "", "");
|
||||
Sysproxy.SetIEProxy(false, false, "", "");
|
||||
}
|
||||
}
|
||||
catch (ProxyException ex)
|
||||
|
||||
@@ -19,14 +19,18 @@ Online PAC=使用在线 PAC
|
||||
Edit Local PAC File...=编辑本地 PAC 文件...
|
||||
Update Local PAC from GFWList=从 GFWList 更新本地 PAC
|
||||
Edit User Rule for GFWList...=编辑 GFWList 的用户规则...
|
||||
Show QRCode...=显示二维码...
|
||||
Secure Local PAC=保护本地 PAC
|
||||
Copy Local PAC URL=复制本地 PAC 网址
|
||||
Share Server Config...=分享服务器配置...
|
||||
Scan QRCode from Screen...=扫描屏幕上的二维码...
|
||||
Import URL from Clipboard...=从剪贴板导入URL...
|
||||
Availability Statistics=统计可用性
|
||||
Show Logs...=显示日志...
|
||||
Verbose Logging=详细记录日志
|
||||
Updates...=更新...
|
||||
Check for Updates...=检查更新
|
||||
Check for Updates at Startup=启动时检查更新
|
||||
Check Pre-release Version=检查测试版更新
|
||||
Edit Hotkeys...=编辑快捷键...
|
||||
About...=关于...
|
||||
Quit=退出
|
||||
@@ -80,7 +84,7 @@ Outbound=出站
|
||||
|
||||
# QRCode Form
|
||||
|
||||
QRCode=二维码
|
||||
QRCode and URL=二维码与 URL
|
||||
|
||||
# PAC Url Form
|
||||
|
||||
@@ -102,6 +106,7 @@ Reg All=注册全部热键
|
||||
|
||||
Shadowsocks Error: {0}=Shadowsocks 错误: {0}
|
||||
Port already in use=端口已被占用
|
||||
Invalid server address=非法服务器地址
|
||||
Illegal port number format=非法端口格式
|
||||
Illegal timeout format=非法超时格式
|
||||
Please add at least one server=请添加至少一个服务器
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -19,14 +19,18 @@ Online PAC=使用在線 PAC
|
||||
Edit Local PAC File...=編輯本地 PAC 文件...
|
||||
Update Local PAC from GFWList=從 GFWList 更新本地 PAC
|
||||
Edit User Rule for GFWList...=編輯 GFWList 的用戶規則...
|
||||
Show QRCode...=顯示 QR 碼...
|
||||
Secure Local PAC=保護本地 PAC
|
||||
Copy Local PAC URL=複製本地 PAC 網址
|
||||
Share Server Config...=分享伺服器配置...
|
||||
Scan QRCode from Screen...=掃描螢幕上的 QR 碼...
|
||||
Import URL from Clipboard...=從剪貼板導入URL...
|
||||
Availability Statistics=統計可用性
|
||||
Show Logs...=顯示日誌...
|
||||
Verbose Logging=詳細記錄日誌
|
||||
Updates...=更新...
|
||||
Check for Updates...=檢查更新
|
||||
Check for Updates at Startup=啟動時檢查更新
|
||||
Check Pre-release Version=檢查測試版更新
|
||||
Edit Hotkeys...=編輯捷徑鍵...
|
||||
About...=關於...
|
||||
Quit=退出
|
||||
@@ -80,7 +84,7 @@ Outbound=出站
|
||||
|
||||
# QRCode Form
|
||||
|
||||
QRCode=QR 碼
|
||||
QRCode and URL=QR 碼与 URL
|
||||
|
||||
# PAC Url Form
|
||||
|
||||
@@ -102,6 +106,7 @@ Reg All=註冊全部捷徑鍵
|
||||
|
||||
Shadowsocks Error: {0}=Shadowsocks 錯誤: {0}
|
||||
Port already in use=連接埠號碼已被占用
|
||||
Invalid server address=非法伺服器位址
|
||||
Illegal port number format=非法連接埠號碼格式
|
||||
Illegal timeout format=非法超時格式
|
||||
Please add at least one server=請新增至少一個伺服器
|
||||
|
||||
@@ -20,11 +20,7 @@ namespace Shadowsocks.Encryption
|
||||
string dllPath = Utils.GetTempPath("libsscrypto.dll");
|
||||
try
|
||||
{
|
||||
#if _X64
|
||||
FileManager.UncompressFile(dllPath, Resources.libsscrypto64_dll);
|
||||
#else
|
||||
FileManager.UncompressFile(dllPath, Resources.libsscrypto_dll);
|
||||
#endif
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
|
||||
@@ -26,6 +26,11 @@ namespace Shadowsocks.Encryption
|
||||
Init();
|
||||
}
|
||||
|
||||
public static void GetBytes(byte[] buf)
|
||||
{
|
||||
_rng.GetBytes(buf);
|
||||
}
|
||||
|
||||
public static void GetBytes(byte[] buf, int len)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -17,11 +17,7 @@ namespace Shadowsocks.Encryption
|
||||
string dllPath = Utils.GetTempPath("libsscrypto.dll");
|
||||
try
|
||||
{
|
||||
#if _X64
|
||||
FileManager.UncompressFile(dllPath, Resources.libsscrypto64_dll);
|
||||
#else
|
||||
FileManager.UncompressFile(dllPath, Resources.libsscrypto_dll);
|
||||
#endif
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
|
||||
Executable → Regular
+7
@@ -22,8 +22,10 @@ namespace Shadowsocks.Model
|
||||
public int localPort;
|
||||
public string pacUrl;
|
||||
public bool useOnlinePac;
|
||||
public bool secureLocalPac = true;
|
||||
public bool availabilityStatistics;
|
||||
public bool autoCheckUpdate;
|
||||
public bool checkPreRelease;
|
||||
public bool isVerboseLogging;
|
||||
public LogViewerConfig logViewer;
|
||||
public ProxyConfig proxy;
|
||||
@@ -54,6 +56,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)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using System.Web;
|
||||
using Shadowsocks.Controller;
|
||||
|
||||
namespace Shadowsocks.Model
|
||||
@@ -10,10 +10,9 @@ 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),
|
||||
DetailsParser = new Regex("^((?<method>.+?)(?<auth>-auth)??:(?<password>.*)@(?<hostname>.+?)" +
|
||||
":(?<port>\\d+?))$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
":(?<port>\\d+?))$", RegexOptions.IgnoreCase);
|
||||
|
||||
private const int DefaultServerTimeoutSec = 5;
|
||||
public const int MaxServerTimeoutSec = 20;
|
||||
@@ -46,9 +45,7 @@ namespace Shadowsocks.Model
|
||||
string serverStr;
|
||||
// CheckHostName() won't do a real DNS lookup
|
||||
var hostType = Uri.CheckHostName( server );
|
||||
if ( hostType == UriHostNameType.Unknown ) {
|
||||
throw new FormatException("Invalid Server Address.");
|
||||
}
|
||||
|
||||
switch ( hostType ) {
|
||||
case UriHostNameType.IPv6:
|
||||
serverStr = $"[{server}]:{server_port}";
|
||||
@@ -79,6 +76,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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+43
-33
@@ -111,16 +111,6 @@ namespace Shadowsocks.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Byte[] 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static byte[] libsscrypto64_dll {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("libsscrypto64_dll", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Byte[] 类型的本地化资源。
|
||||
/// </summary>
|
||||
@@ -225,6 +215,26 @@ namespace Shadowsocks.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Byte[] 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static byte[] sysproxy_exe {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("sysproxy_exe", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Byte[] 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static byte[] sysproxy64_exe {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("sysproxy64_exe", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 ! Put user rules line by line in this file.
|
||||
///! See https://adblockplus.org/en/filter-cheatsheet
|
||||
@@ -237,29 +247,29 @@ namespace Shadowsocks.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 # translation for Traditional Chinese
|
||||
///
|
||||
///Shadowsocks=Shadowsocks
|
||||
///
|
||||
///# Menu items
|
||||
///
|
||||
///Enable System Proxy=啟用系統代理
|
||||
///Mode=系統代理模式
|
||||
///PAC=PAC 模式
|
||||
///Global=全局模式
|
||||
///Servers=伺服器
|
||||
///Edit Servers...=編輯伺服器...
|
||||
///Statistics Config...=統計配置...
|
||||
///Start on Boot=開機啟動
|
||||
///Forward Proxy...=正向代理設置...
|
||||
///Allow Clients from LAN=允許來自區域網路的連接
|
||||
///Local PAC=使用本地 PAC
|
||||
///Online PAC=使用在線 PAC
|
||||
///Edit Local PAC File...=編輯本地 PAC 文件...
|
||||
///Update Local PAC from GFWList=從 GFWList 更新本地 PAC
|
||||
///Edit User Rule for GFWList...=編輯 GFWList 的用戶規則...
|
||||
///Show QRCode...=顯示 QR 碼...
|
||||
///S [字符串的其余部分被截断]"; 的本地化字符串。
|
||||
/// 查找类似 # translation for Traditional Chinese
|
||||
///
|
||||
///Shadowsocks=Shadowsocks
|
||||
///
|
||||
///# Menu items
|
||||
///
|
||||
///Enable System Proxy=啟用系統代理
|
||||
///Mode=系統代理模式
|
||||
///PAC=PAC 模式
|
||||
///Global=全局模式
|
||||
///Servers=伺服器
|
||||
///Edit Servers...=編輯伺服器...
|
||||
///Statistics Config...=統計配置...
|
||||
///Start on Boot=開機啟動
|
||||
///Forward Proxy...=正向代理設置...
|
||||
///Allow Clients from LAN=允許來自區域網路的連接
|
||||
///Local PAC=使用本地 PAC
|
||||
///Online PAC=使用在線 PAC
|
||||
///Edit Local PAC File...=編輯本地 PAC 文件...
|
||||
///Update Local PAC from GFWList=從 GFWList 更新本地 PAC
|
||||
///Edit User Rule for GFWList...=編輯 GFWList 的用戶規則...
|
||||
///Show QRCode...=顯示 QR 碼...
|
||||
///Scan QRCode from Screen [字符串的其余部分被截断]"; 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string zh_tw {
|
||||
get {
|
||||
|
||||
@@ -124,11 +124,8 @@
|
||||
<data name="cn" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\data\cn.txt;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
|
||||
</data>
|
||||
<data name="libsscrypto64_dll" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Data\libsscrypto64.dll.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="libsscrypto_dll" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Data\libsscrypto.dll.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>..\data\libsscrypto.dll.gz;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="mgwz_dll" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\data\mgwz.dll.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
@@ -160,6 +157,12 @@
|
||||
<data name="ssw128" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\ssw128.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="sysproxy64_exe" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Data\sysproxy64.exe.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="sysproxy_exe" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Data\sysproxy.exe.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="user_rule" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\data\user-rule.txt;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
|
||||
</data>
|
||||
|
||||
@@ -165,7 +165,7 @@ namespace Shadowsocks.Proxy
|
||||
st.innerState.ex = ex;
|
||||
}
|
||||
|
||||
private static readonly Regex HttpRespondHeaderRegex = new Regex(@"^(HTTP/1\.\d) (\d{3}) (.+)$");
|
||||
private static readonly Regex HttpRespondHeaderRegex = new Regex(@"^(HTTP/1\.\d) (\d{3}) (.+)$", RegexOptions.Compiled);
|
||||
private int _respondLineCount = 0;
|
||||
private bool _established = false;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Shadowsocks.Util.Sockets
|
||||
// Only used during connection and close, so it won't cost too much.
|
||||
private SpinLock _socketSyncLock = new SpinLock();
|
||||
|
||||
private volatile bool _disposed;
|
||||
private bool _disposed;
|
||||
private bool Connected => _activeSocket != null;
|
||||
private Socket _activeSocket;
|
||||
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/****************************** Module Header ******************************\
|
||||
Module Name: INTERNET_OPTION.cs
|
||||
Project: CSWebBrowserWithProxy
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
This enum contains 4 WinINet constants used in method InternetQueryOption and
|
||||
InternetSetOption functions.
|
||||
Visit http://msdn.microsoft.com/en-us/library/aa385328(VS.85).aspx to get the
|
||||
whole constants list.
|
||||
|
||||
This source is subject to the Microsoft Public License.
|
||||
See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
|
||||
All other rights reserved.
|
||||
|
||||
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
||||
EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
\***************************************************************************/
|
||||
|
||||
namespace Shadowsocks.Util.SystemProxy
|
||||
{
|
||||
public enum INTERNET_OPTION
|
||||
{
|
||||
// Sets or retrieves an INTERNET_PER_CONN_OPTION_LIST structure that specifies
|
||||
// a list of options for a particular connection.
|
||||
INTERNET_OPTION_PER_CONNECTION_OPTION = 75,
|
||||
|
||||
// Notify the system that the registry settings have been changed so that
|
||||
// it verifies the settings on the next call to InternetConnect.
|
||||
INTERNET_OPTION_SETTINGS_CHANGED = 39,
|
||||
|
||||
// Causes the proxy data to be reread from the registry for a handle.
|
||||
INTERNET_OPTION_REFRESH = 37,
|
||||
|
||||
// Alerts the current WinInet instance that proxy settings have changed
|
||||
// and that they must update with the new settings.
|
||||
// To alert all available WinInet instances, set the Buffer parameter of
|
||||
// InternetSetOption to NULL and BufferLength to 0 when passing this option.
|
||||
INTERNET_OPTION_PROXY_SETTINGS_CHANGED = 95
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
/****************************** Module Header ******************************\
|
||||
Module Name: INTERNET_PER_CONN_OPTION.cs
|
||||
Project: CSWebBrowserWithProxy
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
This file defines the struct INTERNET_PER_CONN_OPTION and constants used by it.
|
||||
The struct INTERNET_PER_CONN_OPTION contains the value of an option that to be
|
||||
set to internet settings.
|
||||
Visit http://msdn.microsoft.com/en-us/library/aa385145(VS.85).aspx to get the
|
||||
detailed description.
|
||||
|
||||
This source is subject to the Microsoft Public License.
|
||||
See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
|
||||
All other rights reserved.
|
||||
|
||||
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
||||
EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
\***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Shadowsocks.Util.SystemProxy
|
||||
{
|
||||
/// <summary>
|
||||
/// Constants used in INTERNET_PER_CONN_OPTION_OptionUnion struct.
|
||||
/// </summary>
|
||||
public enum INTERNET_PER_CONN_OptionEnum
|
||||
{
|
||||
INTERNET_PER_CONN_FLAGS = 1,
|
||||
INTERNET_PER_CONN_PROXY_SERVER = 2,
|
||||
INTERNET_PER_CONN_PROXY_BYPASS = 3,
|
||||
INTERNET_PER_CONN_AUTOCONFIG_URL = 4,
|
||||
INTERNET_PER_CONN_AUTODISCOVERY_FLAGS = 5,
|
||||
INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL = 6,
|
||||
INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS = 7,
|
||||
INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME = 8,
|
||||
INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL = 9,
|
||||
INTERNET_PER_CONN_FLAGS_UI = 10
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constants used in INTERNET_PER_CONN_OPTON struct.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum INTERNET_OPTION_PER_CONN_FLAGS
|
||||
{
|
||||
PROXY_TYPE_DIRECT = 0x00000001, // direct to net
|
||||
PROXY_TYPE_PROXY = 0x00000002, // via named proxy
|
||||
PROXY_TYPE_AUTO_PROXY_URL = 0x00000004, // autoproxy URL
|
||||
PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constants used in INTERNET_PER_CONN_OPTON struct.
|
||||
/// Windows 7 and later:
|
||||
/// Clients that support Internet Explorer 8 should query the connection type using INTERNET_PER_CONN_FLAGS_UI.
|
||||
/// If this query fails, then the system is running a previous version of Internet Explorer and the client should
|
||||
/// query again with INTERNET_PER_CONN_FLAGS.
|
||||
/// Restore the connection type using INTERNET_PER_CONN_FLAGS regardless of the version of Internet Explorer.
|
||||
/// XXX: If fails, notify user to upgrade Internet Explorer
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum INTERNET_OPTION_PER_CONN_FLAGS_UI
|
||||
{
|
||||
PROXY_TYPE_DIRECT = 0x00000001, // direct to net
|
||||
PROXY_TYPE_PROXY = 0x00000002, // via named proxy
|
||||
PROXY_TYPE_AUTO_PROXY_URL = 0x00000004, // autoproxy URL
|
||||
PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used in INTERNET_PER_CONN_OPTION.
|
||||
/// When create a instance of OptionUnion, only one filed will be used.
|
||||
/// The StructLayout and FieldOffset attributes could help to decrease the struct size.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct INTERNET_PER_CONN_OPTION_OptionUnion : IDisposable
|
||||
{
|
||||
// A value in INTERNET_OPTION_PER_CONN_FLAGS.
|
||||
[FieldOffset(0)]
|
||||
public int dwValue;
|
||||
[FieldOffset(0)]
|
||||
public System.IntPtr pszValue;
|
||||
[FieldOffset(0)]
|
||||
public System.Runtime.InteropServices.ComTypes.FILETIME ftValue;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (pszValue != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(pszValue);
|
||||
pszValue = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct INTERNET_PER_CONN_OPTION
|
||||
{
|
||||
// A value in INTERNET_PER_CONN_OptionEnum.
|
||||
public int dwOption;
|
||||
public INTERNET_PER_CONN_OPTION_OptionUnion Value;
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/****************************** Module Header ******************************\
|
||||
Module Name: INTERNET_PER_CONN_OPTION_LIST.cs
|
||||
Project: CSWebBrowserWithProxy
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
The struct INTERNET_PER_CONN_OPTION contains a list of options that to be
|
||||
set to internet connection.
|
||||
Visit http://msdn.microsoft.com/en-us/library/aa385146(VS.85).aspx to get the
|
||||
detailed description.
|
||||
|
||||
This source is subject to the Microsoft Public License.
|
||||
See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
|
||||
All other rights reserved.
|
||||
|
||||
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
||||
EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
\***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Shadowsocks.Util.SystemProxy
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
public struct INTERNET_PER_CONN_OPTION_LIST : IDisposable
|
||||
{
|
||||
public int Size;
|
||||
|
||||
// The connection to be set. NULL means LAN.
|
||||
public System.IntPtr Connection;
|
||||
|
||||
public int OptionCount;
|
||||
public int OptionError;
|
||||
|
||||
// List of INTERNET_PER_CONN_OPTIONs.
|
||||
public System.IntPtr pOptions;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose( true );
|
||||
GC.SuppressFinalize( this );
|
||||
}
|
||||
|
||||
private void Dispose( bool disposing )
|
||||
{
|
||||
if ( disposing )
|
||||
{
|
||||
if ( Connection != IntPtr.Zero )
|
||||
{
|
||||
Marshal.FreeHGlobal( Connection );
|
||||
Connection = IntPtr.Zero;
|
||||
}
|
||||
|
||||
if ( pOptions != IntPtr.Zero )
|
||||
{
|
||||
Marshal.FreeHGlobal( pOptions );
|
||||
pOptions = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/****************************** Module Header ******************************\
|
||||
Module Name: NativeMethods.cs
|
||||
Project: CSWebBrowserWithProxy
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
This class is a simple .NET wrapper of wininet.dll. It contains 4 extern
|
||||
methods in wininet.dll. They are InternetOpen, InternetCloseHandle,
|
||||
InternetSetOption and InternetQueryOption.
|
||||
|
||||
This source is subject to the Microsoft Public License.
|
||||
See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
|
||||
All other rights reserved.
|
||||
|
||||
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
||||
EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
\***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Shadowsocks.Util.SystemProxy
|
||||
{
|
||||
internal static class NativeMethods
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets an Internet option.
|
||||
/// </summary>
|
||||
[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
internal static extern bool InternetSetOption(
|
||||
IntPtr hInternet,
|
||||
INTERNET_OPTION dwOption,
|
||||
IntPtr lpBuffer,
|
||||
int lpdwBufferLength);
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Shadowsocks.Util.SystemProxy
|
||||
{
|
||||
internal static class RemoteAccessService
|
||||
{
|
||||
private enum RasFieldSizeConstants
|
||||
{
|
||||
#region original header
|
||||
|
||||
//#if (WINVER >= 0x400)
|
||||
//#define RAS_MaxEntryName 256
|
||||
//#define RAS_MaxDeviceName 128
|
||||
//#define RAS_MaxCallbackNumber RAS_MaxPhoneNumber
|
||||
//#else
|
||||
//#define RAS_MaxEntryName 20
|
||||
//#define RAS_MaxDeviceName 32
|
||||
//#define RAS_MaxCallbackNumber 48
|
||||
//#endif
|
||||
|
||||
#endregion
|
||||
|
||||
RAS_MaxEntryName = 256,
|
||||
RAS_MaxPath = 260
|
||||
}
|
||||
|
||||
private const int ERROR_SUCCESS = 0;
|
||||
private const int RASBASE = 600;
|
||||
private const int ERROR_BUFFER_TOO_SMALL = RASBASE + 3;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
private struct RasEntryName
|
||||
{
|
||||
#region original header
|
||||
|
||||
//#define RASENTRYNAMEW struct tagRASENTRYNAMEW
|
||||
//RASENTRYNAMEW
|
||||
//{
|
||||
// DWORD dwSize;
|
||||
// WCHAR szEntryName[RAS_MaxEntryName + 1];
|
||||
//
|
||||
//#if (WINVER >= 0x500)
|
||||
// //
|
||||
// // If this flag is REN_AllUsers then its a
|
||||
// // system phonebook.
|
||||
// //
|
||||
// DWORD dwFlags;
|
||||
// WCHAR szPhonebookPath[MAX_PATH + 1];
|
||||
//#endif
|
||||
//};
|
||||
//
|
||||
//#define RASENTRYNAMEA struct tagRASENTRYNAMEA
|
||||
//RASENTRYNAMEA
|
||||
//{
|
||||
// DWORD dwSize;
|
||||
// CHAR szEntryName[RAS_MaxEntryName + 1];
|
||||
//
|
||||
//#if (WINVER >= 0x500)
|
||||
// DWORD dwFlags;
|
||||
// CHAR szPhonebookPath[MAX_PATH + 1];
|
||||
//#endif
|
||||
//};
|
||||
|
||||
#endregion
|
||||
|
||||
public int dwSize;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=(int)RasFieldSizeConstants.RAS_MaxEntryName + 1)]
|
||||
public string szEntryName;
|
||||
|
||||
public int dwFlags;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=(int)RasFieldSizeConstants.RAS_MaxPath + 1)]
|
||||
public string szPhonebookPath;
|
||||
}
|
||||
|
||||
[DllImport("rasapi32.dll", CharSet = CharSet.Auto)]
|
||||
private static extern uint RasEnumEntries(
|
||||
// reserved, must be NULL
|
||||
string reserved,
|
||||
// pointer to full path and file name of phone-book file
|
||||
string lpszPhonebook,
|
||||
// buffer to receive phone-book entries
|
||||
[In, Out] RasEntryName[] lprasentryname,
|
||||
// size in bytes of buffer
|
||||
ref int lpcb,
|
||||
// number of entries written to buffer
|
||||
out int lpcEntries
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Get all entries from RAS
|
||||
/// </summary>
|
||||
/// <param name="allConns"></param>
|
||||
/// <returns>
|
||||
/// 0: success with entries
|
||||
/// 1: success but no entries found
|
||||
/// 2: failed
|
||||
/// </returns>
|
||||
public static uint GetAllConns(ref string[] allConns)
|
||||
{
|
||||
int lpNames = 0;
|
||||
int entryNameSize = 0;
|
||||
int lpSize = 0;
|
||||
uint retval = ERROR_SUCCESS;
|
||||
RasEntryName[] names = null;
|
||||
|
||||
entryNameSize = Marshal.SizeOf(typeof(RasEntryName));
|
||||
|
||||
// Windows Vista or later: To determine the required buffer size, call RasEnumEntries
|
||||
// with lprasentryname set to NULL. The variable pointed to by lpcb should be set to zero.
|
||||
// The function will return the required buffer size in lpcb and an error code of ERROR_BUFFER_TOO_SMALL.
|
||||
retval = RasEnumEntries(null, null, null, ref lpSize, out lpNames);
|
||||
|
||||
if (retval == ERROR_BUFFER_TOO_SMALL)
|
||||
{
|
||||
names = new RasEntryName[lpNames];
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
{
|
||||
names[i].dwSize = entryNameSize;
|
||||
}
|
||||
|
||||
retval = RasEnumEntries(null, null, names, ref lpSize, out lpNames);
|
||||
}
|
||||
|
||||
if (retval == ERROR_SUCCESS)
|
||||
{
|
||||
if (lpNames == 0)
|
||||
{
|
||||
// no entries found.
|
||||
return 1;
|
||||
}
|
||||
|
||||
allConns = new string[names.Length];
|
||||
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
{
|
||||
allConns[i] = names[i].szEntryName;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Shadowsocks.Controller;
|
||||
using Shadowsocks.Properties;
|
||||
|
||||
namespace Shadowsocks.Util.SystemProxy
|
||||
{
|
||||
public static class Sysproxy
|
||||
{
|
||||
|
||||
enum RET_ERRORS : int
|
||||
{
|
||||
RET_NO_ERROR = 0,
|
||||
INVALID_FORMAT = 1,
|
||||
NO_PERMISSION = 2,
|
||||
SYSCALL_FAILED = 3,
|
||||
NO_MEMORY = 4,
|
||||
INVAILD_OPTION_COUNT = 5,
|
||||
};
|
||||
|
||||
static Sysproxy()
|
||||
{
|
||||
try
|
||||
{
|
||||
FileManager.UncompressFile(Utils.GetTempPath("sysproxy.exe"),
|
||||
Environment.Is64BitOperatingSystem ? Resources.sysproxy64_exe : Resources.sysproxy_exe);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetIEProxy(bool enable, bool global, string proxyServer, string pacURL)
|
||||
{
|
||||
string arguments;
|
||||
|
||||
if (enable)
|
||||
{
|
||||
if (global)
|
||||
{
|
||||
arguments = $"global {proxyServer} <local>;localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;172.32.*;192.168.*";
|
||||
}
|
||||
else
|
||||
{
|
||||
arguments = $"pac {pacURL}";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
arguments = "off";
|
||||
}
|
||||
|
||||
using (var process = new Process())
|
||||
{
|
||||
// Configure the process using the StartInfo properties.
|
||||
process.StartInfo.FileName = Utils.GetTempPath("sysproxy.exe");
|
||||
process.StartInfo.Arguments = arguments;
|
||||
process.StartInfo.WorkingDirectory = Utils.GetTempPath();
|
||||
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
|
||||
process.StartInfo.UseShellExecute = false;
|
||||
process.StartInfo.RedirectStandardError = true;
|
||||
process.StartInfo.CreateNoWindow = true;
|
||||
process.Start();
|
||||
|
||||
var error = process.StandardError.ReadToEnd();
|
||||
|
||||
process.WaitForExit();
|
||||
|
||||
var exitCode = process.ExitCode;
|
||||
if (exitCode != (int) RET_ERRORS.RET_NO_ERROR)
|
||||
{
|
||||
throw new ProxyException(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
/****************************** Module Header ******************************\
|
||||
Module Name: WinINet.cs
|
||||
Project: CSWebBrowserWithProxy
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
This class is used to set the proxy. or restore to the system proxy for the
|
||||
current application
|
||||
|
||||
This source is subject to the Microsoft Public License.
|
||||
See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
|
||||
All other rights reserved.
|
||||
|
||||
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
||||
EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
\***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Shadowsocks.Controller;
|
||||
|
||||
namespace Shadowsocks.Util.SystemProxy
|
||||
{
|
||||
public static class WinINet
|
||||
{
|
||||
/// <summary>
|
||||
/// Set IE settings.
|
||||
/// </summary>
|
||||
private static void SetIEProxy(bool enable, bool global, string proxyServer, string pacURL, string connName)
|
||||
{
|
||||
List<INTERNET_PER_CONN_OPTION> _optionlist = new List<INTERNET_PER_CONN_OPTION>();
|
||||
|
||||
if (enable)
|
||||
{
|
||||
if (global)
|
||||
{
|
||||
// global proxy
|
||||
_optionlist.Add(new INTERNET_PER_CONN_OPTION
|
||||
{
|
||||
dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_FLAGS_UI,
|
||||
Value = { dwValue = (int)(INTERNET_OPTION_PER_CONN_FLAGS_UI.PROXY_TYPE_PROXY
|
||||
| INTERNET_OPTION_PER_CONN_FLAGS_UI.PROXY_TYPE_DIRECT) }
|
||||
});
|
||||
_optionlist.Add(new INTERNET_PER_CONN_OPTION
|
||||
{
|
||||
dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_PROXY_SERVER,
|
||||
Value = { pszValue = Marshal.StringToHGlobalAuto(proxyServer) }
|
||||
});
|
||||
_optionlist.Add(new INTERNET_PER_CONN_OPTION
|
||||
{
|
||||
dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_PROXY_BYPASS,
|
||||
Value = { pszValue = Marshal.StringToHGlobalAuto("<local>") }
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// pac
|
||||
_optionlist.Add(new INTERNET_PER_CONN_OPTION
|
||||
{
|
||||
dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_FLAGS_UI,
|
||||
Value = { dwValue = (int)INTERNET_OPTION_PER_CONN_FLAGS_UI.PROXY_TYPE_AUTO_PROXY_URL }
|
||||
});
|
||||
_optionlist.Add(new INTERNET_PER_CONN_OPTION
|
||||
{
|
||||
dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_AUTOCONFIG_URL,
|
||||
Value = { pszValue = Marshal.StringToHGlobalAuto(pacURL) }
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// direct
|
||||
_optionlist.Add(new INTERNET_PER_CONN_OPTION
|
||||
{
|
||||
dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_FLAGS_UI,
|
||||
Value = { dwValue = (int)(INTERNET_OPTION_PER_CONN_FLAGS_UI.PROXY_TYPE_AUTO_DETECT
|
||||
| INTERNET_OPTION_PER_CONN_FLAGS_UI.PROXY_TYPE_DIRECT) }
|
||||
});
|
||||
}
|
||||
|
||||
// Get total length of INTERNET_PER_CONN_OPTIONs
|
||||
var len = _optionlist.Sum(each => Marshal.SizeOf(each));
|
||||
|
||||
// Allocate a block of memory of the options.
|
||||
IntPtr buffer = Marshal.AllocCoTaskMem(len);
|
||||
|
||||
IntPtr current = buffer;
|
||||
|
||||
// Marshal data from a managed object to an unmanaged block of memory.
|
||||
foreach (INTERNET_PER_CONN_OPTION eachOption in _optionlist)
|
||||
{
|
||||
Marshal.StructureToPtr(eachOption, current, false);
|
||||
current = (IntPtr)(current.ToInt64() + Marshal.SizeOf(eachOption));
|
||||
}
|
||||
|
||||
// Initialize a INTERNET_PER_CONN_OPTION_LIST instance.
|
||||
INTERNET_PER_CONN_OPTION_LIST optionList = new INTERNET_PER_CONN_OPTION_LIST();
|
||||
|
||||
// Point to the allocated memory.
|
||||
optionList.pOptions = buffer;
|
||||
|
||||
// Return the unmanaged size of an object in bytes.
|
||||
optionList.Size = Marshal.SizeOf(optionList);
|
||||
|
||||
optionList.Connection = connName.IsNullOrEmpty()
|
||||
? IntPtr.Zero // NULL means LAN
|
||||
: Marshal.StringToHGlobalAuto(connName); // TODO: not working if contains Chinese
|
||||
|
||||
optionList.OptionCount = _optionlist.Count;
|
||||
optionList.OptionError = 0;
|
||||
int optionListSize = Marshal.SizeOf(optionList);
|
||||
|
||||
// Allocate memory for the INTERNET_PER_CONN_OPTION_LIST instance.
|
||||
IntPtr intptrStruct = Marshal.AllocCoTaskMem(optionListSize);
|
||||
|
||||
// Marshal data from a managed object to an unmanaged block of memory.
|
||||
Marshal.StructureToPtr(optionList, intptrStruct, true);
|
||||
|
||||
// Set internet settings.
|
||||
bool bReturn = NativeMethods.InternetSetOption(
|
||||
IntPtr.Zero,
|
||||
INTERNET_OPTION.INTERNET_OPTION_PER_CONNECTION_OPTION,
|
||||
intptrStruct, optionListSize);
|
||||
|
||||
// Free the allocated memory.
|
||||
Marshal.FreeCoTaskMem(buffer);
|
||||
Marshal.FreeCoTaskMem(intptrStruct);
|
||||
|
||||
// Throw an exception if this operation failed.
|
||||
if (!bReturn)
|
||||
{
|
||||
throw new ProxyException("InternetSetOption failed.", new Win32Exception());
|
||||
}
|
||||
|
||||
// Notify the system that the registry settings have been changed and cause
|
||||
// the proxy data to be reread from the registry for a handle.
|
||||
bReturn = NativeMethods.InternetSetOption(
|
||||
IntPtr.Zero,
|
||||
INTERNET_OPTION.INTERNET_OPTION_PROXY_SETTINGS_CHANGED,
|
||||
IntPtr.Zero, 0);
|
||||
if (!bReturn)
|
||||
{
|
||||
Logging.Error("InternetSetOption:INTERNET_OPTION_PROXY_SETTINGS_CHANGED");
|
||||
}
|
||||
|
||||
bReturn = NativeMethods.InternetSetOption(
|
||||
IntPtr.Zero,
|
||||
INTERNET_OPTION.INTERNET_OPTION_REFRESH,
|
||||
IntPtr.Zero, 0);
|
||||
if (!bReturn)
|
||||
{
|
||||
Logging.Error("InternetSetOption:INTERNET_OPTION_REFRESH");
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetIEProxy(bool enable, bool global, string proxyServer, string pacURL)
|
||||
{
|
||||
string[] allConnections = null;
|
||||
var ret = RemoteAccessService.GetAllConns(ref allConnections);
|
||||
|
||||
if (ret == 2)
|
||||
throw new ProxyException("Cannot get all connections");
|
||||
|
||||
if (ret == 1)
|
||||
{
|
||||
// no entries, only set LAN
|
||||
SetIEProxy(enable, global, proxyServer, pacURL, null);
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
// found entries, set LAN and each connection
|
||||
SetIEProxy(enable, global, proxyServer, pacURL, null);
|
||||
foreach (string connName in allConnections)
|
||||
{
|
||||
SetIEProxy(enable, global, proxyServer, pacURL, connName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ namespace Shadowsocks.Util
|
||||
}
|
||||
}
|
||||
|
||||
public class Utils
|
||||
public static class Utils
|
||||
{
|
||||
private static bool? _portableMode;
|
||||
private static string TempPath = null;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,28 +80,26 @@ namespace Shadowsocks.View
|
||||
return true;
|
||||
}
|
||||
Server server = new Server();
|
||||
server.server = IPTextBox.Text.Trim();
|
||||
try
|
||||
|
||||
if (Uri.CheckHostName(server.server = IPTextBox.Text.Trim()) == UriHostNameType.Unknown)
|
||||
{
|
||||
server.server_port = int.Parse(ServerPortTextBox.Text);
|
||||
MessageBox.Show(I18N.GetString("Invalid server address"));
|
||||
IPTextBox.Focus();
|
||||
return false;
|
||||
}
|
||||
catch (FormatException)
|
||||
if (!int.TryParse(ServerPortTextBox.Text, out server.server_port))
|
||||
{
|
||||
MessageBox.Show(I18N.GetString("Illegal port number format"));
|
||||
ServerPortTextBox.Clear();
|
||||
ServerPortTextBox.Focus();
|
||||
return false;
|
||||
}
|
||||
server.password = PasswordTextBox.Text;
|
||||
server.method = EncryptionSelect.Text;
|
||||
server.remarks = RemarksTextBox.Text;
|
||||
try
|
||||
{
|
||||
server.timeout = int.Parse(TimeoutTextBox.Text);
|
||||
}
|
||||
catch (FormatException)
|
||||
if (!int.TryParse(TimeoutTextBox.Text, out server.timeout))
|
||||
{
|
||||
MessageBox.Show(I18N.GetString("Illegal timeout format"));
|
||||
TimeoutTextBox.Clear();
|
||||
TimeoutTextBox.Focus();
|
||||
return false;
|
||||
}
|
||||
server.auth = OneTimeAuth.Checked;
|
||||
@@ -151,7 +149,7 @@ namespace Shadowsocks.View
|
||||
_modifiedConfiguration = controller.GetConfigurationCopy();
|
||||
LoadConfiguration(_modifiedConfiguration);
|
||||
_lastSelectedIndex = _modifiedConfiguration.index;
|
||||
if (_lastSelectedIndex < 0)
|
||||
if (_lastSelectedIndex < 0 || _lastSelectedIndex >= ServersListBox.Items.Count)
|
||||
{
|
||||
_lastSelectedIndex = 0;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,9 @@ namespace Shadowsocks.View
|
||||
private MenuItem updateFromGFWListItem;
|
||||
private MenuItem editGFWUserRuleItem;
|
||||
private MenuItem editOnlinePACItem;
|
||||
private MenuItem secureLocalPacUrlToggleItem;
|
||||
private MenuItem autoCheckUpdatesToggleItem;
|
||||
private MenuItem checkPreReleaseToggleItem;
|
||||
private MenuItem proxyItem;
|
||||
private MenuItem hotKeyItem;
|
||||
private MenuItem VerboseLoggingToggleItem;
|
||||
@@ -259,8 +261,10 @@ namespace Shadowsocks.View
|
||||
this.SeperatorItem = new MenuItem("-"),
|
||||
this.ConfigItem = CreateMenuItem("Edit Servers...", new EventHandler(this.Config_Click)),
|
||||
CreateMenuItem("Statistics Config...", StatisticsConfigItem_Click),
|
||||
CreateMenuItem("Show QRCode...", new EventHandler(this.QRCodeItem_Click)),
|
||||
CreateMenuItem("Scan QRCode from Screen...", new EventHandler(this.ScanQRCodeItem_Click))
|
||||
new MenuItem("-"),
|
||||
CreateMenuItem("Share Server Config...", new EventHandler(this.QRCodeItem_Click)),
|
||||
CreateMenuItem("Scan QRCode from Screen...", new EventHandler(this.ScanQRCodeItem_Click)),
|
||||
CreateMenuItem("Import URL from Clipboard...", new EventHandler(this.ImportURLItem_Click))
|
||||
}),
|
||||
CreateMenuGroup("PAC ", new MenuItem[] {
|
||||
this.localPACItem = CreateMenuItem("Local PAC", new EventHandler(this.LocalPACItem_Click)),
|
||||
@@ -269,6 +273,8 @@ namespace Shadowsocks.View
|
||||
this.editLocalPACItem = CreateMenuItem("Edit Local PAC File...", new EventHandler(this.EditPACFileItem_Click)),
|
||||
this.updateFromGFWListItem = CreateMenuItem("Update Local PAC from GFWList", new EventHandler(this.UpdatePACFromGFWListItem_Click)),
|
||||
this.editGFWUserRuleItem = CreateMenuItem("Edit User Rule for GFWList...", new EventHandler(this.EditUserRuleFileForGFWListItem_Click)),
|
||||
this.secureLocalPacUrlToggleItem = CreateMenuItem("Secure Local PAC", new EventHandler(this.SecureLocalPacUrlToggleItem_Click)),
|
||||
CreateMenuItem("Copy Local PAC URL", new EventHandler(this.CopyLocalPacUrlItem_Click)),
|
||||
this.editOnlinePACItem = CreateMenuItem("Edit Online PAC URL...", new EventHandler(this.UpdateOnlinePACURLItem_Click)),
|
||||
}),
|
||||
this.proxyItem = CreateMenuItem("Forward Proxy...", new EventHandler(this.proxyItem_Click)),
|
||||
@@ -283,6 +289,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 +359,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)
|
||||
{
|
||||
@@ -395,6 +402,7 @@ namespace Shadowsocks.View
|
||||
AutoStartupItem.Checked = AutoStartup.Check();
|
||||
onlinePACItem.Checked = onlinePACItem.Enabled && config.useOnlinePac;
|
||||
localPACItem.Checked = !onlinePACItem.Checked;
|
||||
secureLocalPacUrlToggleItem.Checked = config.secureLocalPac;
|
||||
UpdatePACItemsEnabledStatus();
|
||||
UpdateUpdateMenu();
|
||||
}
|
||||
@@ -733,6 +741,15 @@ namespace Shadowsocks.View
|
||||
MessageBox.Show(I18N.GetString("No QRCode found. Try to zoom in or move it to the center of the screen."));
|
||||
}
|
||||
|
||||
private void ImportURLItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var success = controller.AddServerBySSURL(Clipboard.GetText(TextDataFormat.Text));
|
||||
if (success)
|
||||
{
|
||||
ShowConfigForm();
|
||||
}
|
||||
}
|
||||
|
||||
void splash_FormClosed(object sender, FormClosedEventArgs e)
|
||||
{
|
||||
ShowConfigForm();
|
||||
@@ -794,6 +811,17 @@ namespace Shadowsocks.View
|
||||
}
|
||||
}
|
||||
|
||||
private void SecureLocalPacUrlToggleItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Configuration configuration = controller.GetConfigurationCopy();
|
||||
controller.ToggleSecureLocalPac(!configuration.secureLocalPac);
|
||||
}
|
||||
|
||||
private void CopyLocalPacUrlItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
controller.CopyPacUrl();
|
||||
}
|
||||
|
||||
private void UpdatePACItemsEnabledStatus()
|
||||
{
|
||||
if (this.localPACItem.Checked)
|
||||
@@ -812,10 +840,12 @@ namespace Shadowsocks.View
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void UpdateUpdateMenu()
|
||||
{
|
||||
Configuration configuration = controller.GetConfigurationCopy();
|
||||
autoCheckUpdatesToggleItem.Checked = configuration.autoCheckUpdate;
|
||||
checkPreReleaseToggleItem.Checked = configuration.checkPreRelease;
|
||||
}
|
||||
|
||||
private void autoCheckUpdatesToggleItem_Click(object sender, EventArgs e)
|
||||
@@ -825,6 +855,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());
|
||||
|
||||
@@ -58,35 +58,25 @@ namespace Shadowsocks.View
|
||||
|
||||
private void OKButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var type = ProxyTypeComboBox.SelectedIndex;
|
||||
var proxy = ProxyServerTextBox.Text;
|
||||
var port = 0;
|
||||
var timeout = 3;
|
||||
|
||||
if (UseProxyCheckBox.Checked)
|
||||
{
|
||||
try
|
||||
{
|
||||
port = int.Parse(ProxyPortTextBox.Text);
|
||||
}
|
||||
catch (FormatException)
|
||||
int port;
|
||||
int timeout;
|
||||
if (!int.TryParse(ProxyPortTextBox.Text, out port))
|
||||
{
|
||||
MessageBox.Show(I18N.GetString("Illegal port number format"));
|
||||
ProxyPortTextBox.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
timeout = int.Parse(ProxyTimeoutTextBox.Text);
|
||||
}
|
||||
catch (FormatException)
|
||||
if (!int.TryParse(ProxyTimeoutTextBox.Text, out timeout))
|
||||
{
|
||||
MessageBox.Show(I18N.GetString("Illegal timeout format"));
|
||||
ProxyTimeoutTextBox.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
var type = ProxyTypeComboBox.SelectedIndex;
|
||||
var proxy = ProxyServerTextBox.Text;
|
||||
try
|
||||
{
|
||||
Configuration.CheckServer(proxy);
|
||||
@@ -99,20 +89,13 @@ namespace Shadowsocks.View
|
||||
return;
|
||||
}
|
||||
|
||||
controller.EnableProxy(type, proxy, port);
|
||||
controller.EnableProxy(type, proxy, port, timeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
controller.DisableProxy();
|
||||
}
|
||||
|
||||
_modifiedConfiguration.useProxy = UseProxyCheckBox.Checked;
|
||||
_modifiedConfiguration.proxyType = type;
|
||||
_modifiedConfiguration.proxyServer = proxy;
|
||||
_modifiedConfiguration.proxyPort = port;
|
||||
_modifiedConfiguration.proxyTimeout = timeout;
|
||||
controller.SaveProxyConfig(_modifiedConfiguration);
|
||||
|
||||
this.Close();
|
||||
}
|
||||
|
||||
@@ -142,9 +125,6 @@ namespace Shadowsocks.View
|
||||
}
|
||||
else
|
||||
{
|
||||
ProxyServerTextBox.Clear();
|
||||
ProxyPortTextBox.Clear();
|
||||
ProxyTimeoutTextBox.Clear();
|
||||
ProxyServerTextBox.Enabled = false;
|
||||
ProxyPortTextBox.Enabled = false;
|
||||
ProxyTimeoutTextBox.Enabled = false;
|
||||
|
||||
+16
-3
@@ -30,6 +30,7 @@
|
||||
{
|
||||
this.pictureBox1 = new System.Windows.Forms.PictureBox();
|
||||
this.listBox1 = new System.Windows.Forms.ListBox();
|
||||
this.textBoxURL = new System.Windows.Forms.TextBox();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
@@ -39,7 +40,7 @@
|
||||
this.pictureBox1.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.pictureBox1.Name = "pictureBox1";
|
||||
this.pictureBox1.Size = new System.Drawing.Size(210, 210);
|
||||
this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
||||
this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
|
||||
this.pictureBox1.TabIndex = 1;
|
||||
this.pictureBox1.TabStop = false;
|
||||
//
|
||||
@@ -56,6 +57,15 @@
|
||||
this.listBox1.ValueMember = "Key";
|
||||
this.listBox1.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged);
|
||||
//
|
||||
// textBoxURL
|
||||
//
|
||||
this.textBoxURL.Location = new System.Drawing.Point(10, 227);
|
||||
this.textBoxURL.Name = "textBoxURL";
|
||||
this.textBoxURL.ReadOnly = true;
|
||||
this.textBoxURL.Size = new System.Drawing.Size(441, 21);
|
||||
this.textBoxURL.TabIndex = 3;
|
||||
this.textBoxURL.Click += new System.EventHandler(this.textBoxURL_Click);
|
||||
//
|
||||
// QRCodeForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
@@ -63,7 +73,8 @@
|
||||
this.AutoSize = true;
|
||||
this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||
this.BackColor = System.Drawing.Color.White;
|
||||
this.ClientSize = new System.Drawing.Size(457, 228);
|
||||
this.ClientSize = new System.Drawing.Size(457, 257);
|
||||
this.Controls.Add(this.textBoxURL);
|
||||
this.Controls.Add(this.listBox1);
|
||||
this.Controls.Add(this.pictureBox1);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
@@ -72,10 +83,11 @@
|
||||
this.Name = "QRCodeForm";
|
||||
this.Padding = new System.Windows.Forms.Padding(10);
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "QRCode";
|
||||
this.Text = "QRCode and URL";
|
||||
this.Load += new System.EventHandler(this.QRCodeForm_Load);
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
@@ -83,5 +95,6 @@
|
||||
|
||||
private System.Windows.Forms.PictureBox pictureBox1;
|
||||
private System.Windows.Forms.ListBox listBox1;
|
||||
private System.Windows.Forms.TextBox textBoxURL;
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ namespace Shadowsocks.View
|
||||
this.code = code;
|
||||
InitializeComponent();
|
||||
this.Icon = Icon.FromHandle(Resources.ssw128.GetHicon());
|
||||
this.Text = I18N.GetString("QRCode");
|
||||
this.Text = I18N.GetString("QRCode and URL");
|
||||
}
|
||||
|
||||
private void GenQR(string ssconfig)
|
||||
@@ -33,6 +33,14 @@ namespace Shadowsocks.View
|
||||
QRCode code = ZXing.QrCode.Internal.Encoder.encode(qrText, ErrorCorrectionLevel.M);
|
||||
ByteMatrix m = code.Matrix;
|
||||
int blockSize = Math.Max(pictureBox1.Height/m.Height, 1);
|
||||
|
||||
var qrWidth = m.Width*blockSize;
|
||||
var qrHeight = m.Height*blockSize;
|
||||
var dWidth = pictureBox1.Width - qrWidth;
|
||||
var dHeight = pictureBox1.Height - qrHeight;
|
||||
var maxD = Math.Max(dWidth, dHeight);
|
||||
pictureBox1.SizeMode = maxD >= 7*blockSize ? PictureBoxSizeMode.Zoom : PictureBoxSizeMode.CenterImage;
|
||||
|
||||
Bitmap drawArea = new Bitmap((m.Width*blockSize), (m.Height*blockSize));
|
||||
using (Graphics g = Graphics.FromImage(drawArea))
|
||||
{
|
||||
@@ -69,7 +77,14 @@ namespace Shadowsocks.View
|
||||
|
||||
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
GenQR((sender as ListBox)?.SelectedValue.ToString());
|
||||
var url = (sender as ListBox)?.SelectedValue.ToString();
|
||||
GenQR(url);
|
||||
textBoxURL.Text = url;
|
||||
}
|
||||
|
||||
private void textBoxURL_Click(object sender, EventArgs e)
|
||||
{
|
||||
textBoxURL.SelectAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
<OldToolsVersion>3.5</OldToolsVersion>
|
||||
<TargetFrameworkProfile>
|
||||
</TargetFrameworkProfile>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
@@ -39,6 +37,8 @@
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -65,25 +65,6 @@
|
||||
<PropertyGroup>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;_X64</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>ManagedMinimumRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;_X64</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>ManagedMinimumRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="GlobalHotKey, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>3rd\GlobalHotKey.1.1.0\lib\GlobalHotKey.dll</HintPath>
|
||||
@@ -100,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" />
|
||||
@@ -158,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">
|
||||
@@ -205,21 +188,17 @@
|
||||
<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" />
|
||||
<Compile Include="Util\Sockets\LineReader.cs" />
|
||||
<Compile Include="Util\Sockets\SocketUtil.cs" />
|
||||
<Compile Include="Util\Sockets\WrappedSocket.cs" />
|
||||
<Compile Include="Util\SystemProxy\INTERNET_OPTION.cs" />
|
||||
<Compile Include="Util\SystemProxy\INTERNET_PER_CONN_OPTION.cs" />
|
||||
<Compile Include="Util\SystemProxy\INTERNET_PER_CONN_OPTION_LIST.cs" />
|
||||
<Compile Include="Util\SystemProxy\NativeMethods.cs" />
|
||||
<Compile Include="Util\SystemProxy\ProxyException.cs" />
|
||||
<Compile Include="Util\SystemProxy\RAS.cs" />
|
||||
<Compile Include="Util\SystemProxy\WinINet.cs" />
|
||||
<Compile Include="Util\SystemProxy\Sysproxy.cs" />
|
||||
<Compile Include="Util\Util.cs" />
|
||||
<Compile Include="Util\ViewUtils.cs" />
|
||||
<Compile Include="View\ConfigForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
@@ -305,12 +284,13 @@
|
||||
</None>
|
||||
<None Include="Data\abp.js.gz" />
|
||||
<None Include="Data\libsscrypto.dll.gz" />
|
||||
<None Include="Data\libsscrypto64.dll.gz" />
|
||||
<None Include="Data\mgwz.dll.gz" />
|
||||
<None Include="Data\privoxy.exe.gz" />
|
||||
<None Include="Data\proxy.pac.txt.gz" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Data\sysproxy.exe.gz" />
|
||||
<None Include="Data\sysproxy64.exe.gz" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\DataSources\Shadowsocks.Model.StatisticsStrategyConfiguration.datasource" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
@@ -376,25 +356,25 @@
|
||||
<Using xmlns="http://schemas.microsoft.com/developer/msbuild/2003" Namespace="System" />
|
||||
<Using xmlns="http://schemas.microsoft.com/developer/msbuild/2003" Namespace="System.IO" />
|
||||
<Using xmlns="http://schemas.microsoft.com/developer/msbuild/2003" Namespace="System.Xml.Linq" />
|
||||
<Code xmlns="http://schemas.microsoft.com/developer/msbuild/2003" Type="Fragment" Language="cs"><![CDATA[
|
||||
var config = XElement.Load(Config.ItemSpec).Elements("Costura").FirstOrDefault();
|
||||
|
||||
if (config == null) return true;
|
||||
|
||||
var excludedAssemblies = new List<string>();
|
||||
var attribute = config.Attribute("ExcludeAssemblies");
|
||||
if (attribute != null)
|
||||
foreach (var item in attribute.Value.Split('|').Select(x => x.Trim()).Where(x => x != string.Empty))
|
||||
excludedAssemblies.Add(item);
|
||||
var element = config.Element("ExcludeAssemblies");
|
||||
if (element != null)
|
||||
foreach (var item in element.Value.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).Where(x => x != string.Empty))
|
||||
excludedAssemblies.Add(item);
|
||||
|
||||
var filesToCleanup = Files.Select(f => f.ItemSpec).Where(f => !excludedAssemblies.Contains(Path.GetFileNameWithoutExtension(f), StringComparer.InvariantCultureIgnoreCase));
|
||||
|
||||
foreach (var item in filesToCleanup)
|
||||
File.Delete(item);
|
||||
<Code xmlns="http://schemas.microsoft.com/developer/msbuild/2003" Type="Fragment" Language="cs"><![CDATA[
|
||||
var config = XElement.Load(Config.ItemSpec).Elements("Costura").FirstOrDefault();
|
||||
|
||||
if (config == null) return true;
|
||||
|
||||
var excludedAssemblies = new List<string>();
|
||||
var attribute = config.Attribute("ExcludeAssemblies");
|
||||
if (attribute != null)
|
||||
foreach (var item in attribute.Value.Split('|').Select(x => x.Trim()).Where(x => x != string.Empty))
|
||||
excludedAssemblies.Add(item);
|
||||
var element = config.Element("ExcludeAssemblies");
|
||||
if (element != null)
|
||||
foreach (var item in element.Value.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).Where(x => x != string.Empty))
|
||||
excludedAssemblies.Add(item);
|
||||
|
||||
var filesToCleanup = Files.Select(f => f.ItemSpec).Where(f => !excludedAssemblies.Contains(Path.GetFileNameWithoutExtension(f), StringComparer.InvariantCultureIgnoreCase));
|
||||
|
||||
foreach (var item in filesToCleanup)
|
||||
File.Delete(item);
|
||||
]]></Code>
|
||||
</Task>
|
||||
</UsingTask>
|
||||
@@ -408,11 +388,11 @@ foreach (var item in filesToCleanup)
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('3rd\Fody.1.29.4\build\dotnet\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '3rd\Fody.1.29.4\build\dotnet\Fody.targets'))" />
|
||||
</Target>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
+1
-11
@@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
VisualStudioVersion = 14.0.24720.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "shadowsocks-csharp", "shadowsocks-csharp\shadowsocks-csharp.csproj", "{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}"
|
||||
EndProject
|
||||
@@ -12,27 +12,17 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "test", "test\test.csproj",
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x64.Build.0 = Debug|x64
|
||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x86.Build.0 = Debug|x86
|
||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x86.Deploy.0 = Debug|x86
|
||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Release|x64.ActiveCfg = Release|x64
|
||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Release|x64.Build.0 = Release|x64
|
||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Release|x86.ActiveCfg = Release|x86
|
||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Release|x86.Build.0 = Release|x86
|
||||
{45913187-0685-4903-B250-DCEF0479CD86}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{45913187-0685-4903-B250-DCEF0479CD86}.Debug|x64.Build.0 = Debug|x64
|
||||
{45913187-0685-4903-B250-DCEF0479CD86}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{45913187-0685-4903-B250-DCEF0479CD86}.Debug|x86.Build.0 = Debug|x86
|
||||
{45913187-0685-4903-B250-DCEF0479CD86}.Release|x64.ActiveCfg = Release|x64
|
||||
{45913187-0685-4903-B250-DCEF0479CD86}.Release|x64.Build.0 = Release|x64
|
||||
{45913187-0685-4903-B250-DCEF0479CD86}.Release|x86.ActiveCfg = Release|x86
|
||||
{45913187-0685-4903-B250-DCEF0479CD86}.Release|x86.Build.0 = Release|x86
|
||||
EndGlobalSection
|
||||
|
||||
+1
-1
@@ -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
|
||||
{
|
||||
|
||||
@@ -34,20 +34,6 @@
|
||||
<PropertyGroup>
|
||||
<StartupObject />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG</DefineConstants>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="GlobalHotKey, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\shadowsocks-csharp\3rd\GlobalHotKey.1.1.0\lib\GlobalHotKey.dll</HintPath>
|
||||
|
||||
Reference in New Issue
Block a user