@@ -1,5 +1,5 @@ | |||||
version: 1.0.{build} | version: 1.0.{build} | ||||
image: Visual Studio 2015 | |||||
image: Visual Studio 2017 | |||||
environment: | environment: | ||||
matrix: | matrix: | ||||
- platform: x86 | - platform: x86 | ||||
@@ -2,21 +2,18 @@ | |||||
using System.Collections.Concurrent; | using System.Collections.Concurrent; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.IO; | using System.IO; | ||||
using System.Linq; | |||||
using System.Net; | using System.Net; | ||||
using System.Net.Sockets; | using System.Net.Sockets; | ||||
using System.Text; | using System.Text; | ||||
using System.Threading; | using System.Threading; | ||||
using System.Web; | using System.Web; | ||||
using System.Windows.Forms; | using System.Windows.Forms; | ||||
using Newtonsoft.Json; | |||||
using Shadowsocks.Controller.Service; | |||||
using Shadowsocks.Controller.Strategy; | using Shadowsocks.Controller.Strategy; | ||||
using Shadowsocks.Model; | using Shadowsocks.Model; | ||||
using Shadowsocks.Properties; | |||||
using Shadowsocks.Util; | using Shadowsocks.Util; | ||||
using System.Linq; | |||||
using Shadowsocks.Controller.Service; | |||||
using Shadowsocks.Proxy; | |||||
namespace Shadowsocks.Controller | namespace Shadowsocks.Controller | ||||
{ | { | ||||
@@ -100,10 +97,7 @@ namespace Shadowsocks.Controller | |||||
protected void ReportError(Exception e) | protected void ReportError(Exception e) | ||||
{ | { | ||||
if (Errored != null) | |||||
{ | |||||
Errored(this, new ErrorEventArgs(e)); | |||||
} | |||||
Errored?.Invoke(this, new ErrorEventArgs(e)); | |||||
} | } | ||||
public Server GetCurrentServer() | public Server GetCurrentServer() | ||||
@@ -132,7 +126,7 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
foreach (var strategy in _strategyManager.GetStrategies()) | foreach (var strategy in _strategyManager.GetStrategies()) | ||||
{ | { | ||||
if (strategy.ID == this._config.strategy) | |||||
if (strategy.ID == _config.strategy) | |||||
{ | { | ||||
return strategy; | return strategy; | ||||
} | } | ||||
@@ -197,9 +191,13 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
try | try | ||||
{ | { | ||||
if (ssURL.IsNullOrEmpty() || ssURL.IsWhiteSpace()) return false; | |||||
if (ssURL.IsNullOrEmpty() || ssURL.IsWhiteSpace()) | |||||
return false; | |||||
var servers = Server.GetServers(ssURL); | var servers = Server.GetServers(ssURL); | ||||
if (servers == null || servers.Count == 0) return false; | |||||
if (servers == null || servers.Count == 0) | |||||
return false; | |||||
foreach (var server in servers) | foreach (var server in servers) | ||||
{ | { | ||||
_config.configs.Add(server); | _config.configs.Add(server); | ||||
@@ -219,30 +217,24 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
_config.enabled = enabled; | _config.enabled = enabled; | ||||
SaveConfig(_config); | SaveConfig(_config); | ||||
if (EnableStatusChanged != null) | |||||
{ | |||||
EnableStatusChanged(this, new EventArgs()); | |||||
} | |||||
EnableStatusChanged?.Invoke(this, new EventArgs()); | |||||
} | } | ||||
public void ToggleGlobal(bool global) | public void ToggleGlobal(bool global) | ||||
{ | { | ||||
_config.global = global; | _config.global = global; | ||||
SaveConfig(_config); | SaveConfig(_config); | ||||
if (EnableGlobalChanged != null) | |||||
{ | |||||
EnableGlobalChanged(this, new EventArgs()); | |||||
} | |||||
EnableGlobalChanged?.Invoke(this, new EventArgs()); | |||||
} | } | ||||
public void ToggleShareOverLAN(bool enabled) | public void ToggleShareOverLAN(bool enabled) | ||||
{ | { | ||||
_config.shareOverLan = enabled; | _config.shareOverLan = enabled; | ||||
SaveConfig(_config); | SaveConfig(_config); | ||||
if (ShareOverLANStatusChanged != null) | |||||
{ | |||||
ShareOverLANStatusChanged(this, new EventArgs()); | |||||
} | |||||
ShareOverLANStatusChanged?.Invoke(this, new EventArgs()); | |||||
} | } | ||||
public void SaveProxy(ProxyConfig proxyConfig) | public void SaveProxy(ProxyConfig proxyConfig) | ||||
@@ -255,10 +247,8 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
_config.isVerboseLogging = enabled; | _config.isVerboseLogging = enabled; | ||||
SaveConfig(_config); | SaveConfig(_config); | ||||
if (VerboseLoggingStatusChanged != null) | |||||
{ | |||||
VerboseLoggingStatusChanged(this, new EventArgs()); | |||||
} | |||||
VerboseLoggingStatusChanged?.Invoke(this, new EventArgs()); | |||||
} | } | ||||
public void SelectServerIndex(int index) | public void SelectServerIndex(int index) | ||||
@@ -310,19 +300,15 @@ namespace Shadowsocks.Controller | |||||
public void TouchPACFile() | public void TouchPACFile() | ||||
{ | { | ||||
string pacFilename = _pacServer.TouchPACFile(); | string pacFilename = _pacServer.TouchPACFile(); | ||||
if (PACFileReadyToOpen != null) | |||||
{ | |||||
PACFileReadyToOpen(this, new PathEventArgs() { Path = pacFilename }); | |||||
} | |||||
PACFileReadyToOpen?.Invoke(this, new PathEventArgs() { Path = pacFilename }); | |||||
} | } | ||||
public void TouchUserRuleFile() | public void TouchUserRuleFile() | ||||
{ | { | ||||
string userRuleFilename = _pacServer.TouchUserRuleFile(); | string userRuleFilename = _pacServer.TouchUserRuleFile(); | ||||
if (UserRuleFileReadyToOpen != null) | |||||
{ | |||||
UserRuleFileReadyToOpen(this, new PathEventArgs() { Path = userRuleFilename }); | |||||
} | |||||
UserRuleFileReadyToOpen?.Invoke(this, new PathEventArgs() { Path = userRuleFilename }); | |||||
} | } | ||||
public string GetServerURLForCurrentServer() | public string GetServerURLForCurrentServer() | ||||
@@ -381,60 +367,51 @@ namespace Shadowsocks.Controller | |||||
public void UpdateStatisticsConfiguration(bool enabled) | public void UpdateStatisticsConfiguration(bool enabled) | ||||
{ | { | ||||
if (availabilityStatistics == null) return; | |||||
availabilityStatistics.UpdateConfiguration(this); | |||||
_config.availabilityStatistics = enabled; | |||||
SaveConfig(_config); | |||||
if (availabilityStatistics != null) | |||||
{ | |||||
availabilityStatistics.UpdateConfiguration(this); | |||||
_config.availabilityStatistics = enabled; | |||||
SaveConfig(_config); | |||||
} | |||||
} | } | ||||
public void SavePACUrl(string pacUrl) | public void SavePACUrl(string pacUrl) | ||||
{ | { | ||||
_config.pacUrl = pacUrl; | _config.pacUrl = pacUrl; | ||||
SaveConfig(_config); | SaveConfig(_config); | ||||
if (ConfigChanged != null) | |||||
{ | |||||
ConfigChanged(this, new EventArgs()); | |||||
} | |||||
ConfigChanged?.Invoke(this, new EventArgs()); | |||||
} | } | ||||
public void UseOnlinePAC(bool useOnlinePac) | public void UseOnlinePAC(bool useOnlinePac) | ||||
{ | { | ||||
_config.useOnlinePac = useOnlinePac; | _config.useOnlinePac = useOnlinePac; | ||||
SaveConfig(_config); | SaveConfig(_config); | ||||
if (ConfigChanged != null) | |||||
{ | |||||
ConfigChanged(this, new EventArgs()); | |||||
} | |||||
ConfigChanged?.Invoke(this, new EventArgs()); | |||||
} | } | ||||
public void ToggleSecureLocalPac(bool enabled) | public void ToggleSecureLocalPac(bool enabled) | ||||
{ | { | ||||
_config.secureLocalPac = enabled; | _config.secureLocalPac = enabled; | ||||
SaveConfig(_config); | SaveConfig(_config); | ||||
if (ConfigChanged != null) | |||||
{ | |||||
ConfigChanged(this, new EventArgs()); | |||||
} | |||||
ConfigChanged?.Invoke(this, new EventArgs()); | |||||
} | } | ||||
public void ToggleCheckingUpdate(bool enabled) | public void ToggleCheckingUpdate(bool enabled) | ||||
{ | { | ||||
_config.autoCheckUpdate = enabled; | _config.autoCheckUpdate = enabled; | ||||
Configuration.Save(_config); | Configuration.Save(_config); | ||||
if (ConfigChanged != null) | |||||
{ | |||||
ConfigChanged(this, new EventArgs()); | |||||
} | |||||
ConfigChanged?.Invoke(this, new EventArgs()); | |||||
} | } | ||||
public void ToggleCheckingPreRelease(bool enabled) | public void ToggleCheckingPreRelease(bool enabled) | ||||
{ | { | ||||
_config.checkPreRelease = enabled; | _config.checkPreRelease = enabled; | ||||
Configuration.Save(_config); | Configuration.Save(_config); | ||||
if (ConfigChanged != null) | |||||
{ | |||||
ConfigChanged(this, new EventArgs()); | |||||
} | |||||
ConfigChanged?.Invoke(this, new EventArgs()); | |||||
} | } | ||||
public void SaveLogViewerConfig(LogViewerConfig newConfig) | public void SaveLogViewerConfig(LogViewerConfig newConfig) | ||||
@@ -442,20 +419,16 @@ namespace Shadowsocks.Controller | |||||
_config.logViewer = newConfig; | _config.logViewer = newConfig; | ||||
newConfig.SaveSize(); | newConfig.SaveSize(); | ||||
Configuration.Save(_config); | Configuration.Save(_config); | ||||
if (ConfigChanged != null) | |||||
{ | |||||
ConfigChanged(this, new EventArgs()); | |||||
} | |||||
ConfigChanged?.Invoke(this, new EventArgs()); | |||||
} | } | ||||
public void SaveHotkeyConfig(HotkeyConfig newConfig) | public void SaveHotkeyConfig(HotkeyConfig newConfig) | ||||
{ | { | ||||
_config.hotkey = newConfig; | _config.hotkey = newConfig; | ||||
SaveConfig(_config); | SaveConfig(_config); | ||||
if (ConfigChanged != null) | |||||
{ | |||||
ConfigChanged(this, new EventArgs()); | |||||
} | |||||
ConfigChanged?.Invoke(this, new EventArgs()); | |||||
} | } | ||||
public void UpdateLatency(Server server, TimeSpan latency) | public void UpdateLatency(Server server, TimeSpan latency) | ||||
@@ -498,15 +471,15 @@ namespace Shadowsocks.Controller | |||||
if (_pacServer == null) | if (_pacServer == null) | ||||
{ | { | ||||
_pacServer = new PACServer(); | _pacServer = new PACServer(); | ||||
_pacServer.PACFileChanged += pacServer_PACFileChanged; | |||||
_pacServer.UserRuleFileChanged += pacServer_UserRuleFileChanged; | |||||
_pacServer.PACFileChanged += PacServer_PACFileChanged; | |||||
_pacServer.UserRuleFileChanged += PacServer_UserRuleFileChanged; | |||||
} | } | ||||
_pacServer.UpdateConfiguration(_config); | _pacServer.UpdateConfiguration(_config); | ||||
if (gfwListUpdater == null) | if (gfwListUpdater == null) | ||||
{ | { | ||||
gfwListUpdater = new GFWListUpdater(); | gfwListUpdater = new GFWListUpdater(); | ||||
gfwListUpdater.UpdateCompleted += pacServer_PACUpdateCompleted; | |||||
gfwListUpdater.Error += pacServer_PACUpdateError; | |||||
gfwListUpdater.UpdateCompleted += PacServer_PACUpdateCompleted; | |||||
gfwListUpdater.Error += PacServer_PACUpdateError; | |||||
} | } | ||||
availabilityStatistics.UpdateConfiguration(this); | availabilityStatistics.UpdateConfiguration(this); | ||||
@@ -536,11 +509,13 @@ namespace Shadowsocks.Controller | |||||
TCPRelay tcpRelay = new TCPRelay(this, _config); | TCPRelay tcpRelay = new TCPRelay(this, _config); | ||||
UDPRelay udpRelay = new UDPRelay(this); | UDPRelay udpRelay = new UDPRelay(this); | ||||
List<Listener.IService> services = new List<Listener.IService>(); | |||||
services.Add(tcpRelay); | |||||
services.Add(udpRelay); | |||||
services.Add(_pacServer); | |||||
services.Add(new PortForwarder(privoxyRunner.RunningPort)); | |||||
List<Listener.IService> services = new List<Listener.IService> | |||||
{ | |||||
tcpRelay, | |||||
udpRelay, | |||||
_pacServer, | |||||
new PortForwarder(privoxyRunner.RunningPort) | |||||
}; | |||||
_listener = new Listener(services); | _listener = new Listener(services); | ||||
_listener.Start(_config); | _listener.Start(_config); | ||||
} | } | ||||
@@ -548,9 +523,8 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
// translate Microsoft language into human language | // translate Microsoft language into human language | ||||
// i.e. An attempt was made to access a socket in a way forbidden by its access permissions => Port already in use | // i.e. An attempt was made to access a socket in a way forbidden by its access permissions => Port already in use | ||||
if (e is SocketException) | |||||
if (e is SocketException se) | |||||
{ | { | ||||
SocketException se = (SocketException)e; | |||||
if (se.SocketErrorCode == SocketError.AddressAlreadyInUse) | if (se.SocketErrorCode == SocketError.AddressAlreadyInUse) | ||||
{ | { | ||||
e = new Exception(I18N.GetString("Port {0} already in use", _config.localPort), e); | e = new Exception(I18N.GetString("Port {0} already in use", _config.localPort), e); | ||||
@@ -564,10 +538,7 @@ namespace Shadowsocks.Controller | |||||
ReportError(e); | ReportError(e); | ||||
} | } | ||||
if (ConfigChanged != null) | |||||
{ | |||||
ConfigChanged(this, new EventArgs()); | |||||
} | |||||
ConfigChanged?.Invoke(this, new EventArgs()); | |||||
UpdateSystemProxy(); | UpdateSystemProxy(); | ||||
Utils.ReleaseMemory(true); | Utils.ReleaseMemory(true); | ||||
@@ -590,25 +561,23 @@ namespace Shadowsocks.Controller | |||||
SystemProxy.Update(_config, false, _pacServer); | SystemProxy.Update(_config, false, _pacServer); | ||||
} | } | ||||
private void pacServer_PACFileChanged(object sender, EventArgs e) | |||||
private void PacServer_PACFileChanged(object sender, EventArgs e) | |||||
{ | { | ||||
UpdateSystemProxy(); | UpdateSystemProxy(); | ||||
} | } | ||||
private void pacServer_PACUpdateCompleted(object sender, GFWListUpdater.ResultEventArgs e) | |||||
private void PacServer_PACUpdateCompleted(object sender, GFWListUpdater.ResultEventArgs e) | |||||
{ | { | ||||
if (UpdatePACFromGFWListCompleted != null) | |||||
UpdatePACFromGFWListCompleted(this, e); | |||||
UpdatePACFromGFWListCompleted?.Invoke(this, e); | |||||
} | } | ||||
private void pacServer_PACUpdateError(object sender, ErrorEventArgs e) | |||||
private void PacServer_PACUpdateError(object sender, ErrorEventArgs e) | |||||
{ | { | ||||
if (UpdatePACFromGFWListError != null) | |||||
UpdatePACFromGFWListError(this, e); | |||||
UpdatePACFromGFWListError?.Invoke(this, e); | |||||
} | } | ||||
private static readonly IEnumerable<char> IgnoredLineBegins = new[] { '!', '[' }; | private static readonly IEnumerable<char> IgnoredLineBegins = new[] { '!', '[' }; | ||||
private void pacServer_UserRuleFileChanged(object sender, EventArgs e) | |||||
private void PacServer_UserRuleFileChanged(object sender, EventArgs e) | |||||
{ | { | ||||
if (!File.Exists(Utils.GetTempPath("gfwlist.txt"))) | if (!File.Exists(Utils.GetTempPath("gfwlist.txt"))) | ||||
{ | { | ||||
@@ -630,8 +599,10 @@ namespace Shadowsocks.Controller | |||||
private void StartReleasingMemory() | private void StartReleasingMemory() | ||||
{ | { | ||||
_ramThread = new Thread(new ThreadStart(ReleaseMemory)); | |||||
_ramThread.IsBackground = true; | |||||
_ramThread = new Thread(new ThreadStart(ReleaseMemory)) | |||||
{ | |||||
IsBackground = true | |||||
}; | |||||
_ramThread.Start(); | _ramThread.Start(); | ||||
} | } | ||||
@@ -655,8 +626,10 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
trafficPerSecondQueue.Enqueue(new TrafficPerSecond()); | trafficPerSecondQueue.Enqueue(new TrafficPerSecond()); | ||||
} | } | ||||
_trafficThread = new Thread(new ThreadStart(() => TrafficStatistics(queueMaxSize))); | |||||
_trafficThread.IsBackground = true; | |||||
_trafficThread = new Thread(new ThreadStart(() => TrafficStatistics(queueMaxSize))) | |||||
{ | |||||
IsBackground = true | |||||
}; | |||||
_trafficThread.Start(); | _trafficThread.Start(); | ||||
} | } | ||||
@@ -666,10 +639,11 @@ namespace Shadowsocks.Controller | |||||
while (true) | while (true) | ||||
{ | { | ||||
previous = trafficPerSecondQueue.Last(); | previous = trafficPerSecondQueue.Last(); | ||||
current = new TrafficPerSecond(); | |||||
current.inboundCounter = InboundCounter; | |||||
current.outboundCounter = OutboundCounter; | |||||
current = new TrafficPerSecond | |||||
{ | |||||
inboundCounter = InboundCounter, | |||||
outboundCounter = OutboundCounter | |||||
}; | |||||
current.inboundIncreasement = current.inboundCounter - previous.inboundCounter; | current.inboundIncreasement = current.inboundCounter - previous.inboundCounter; | ||||
current.outboundIncreasement = current.outboundCounter - previous.outboundCounter; | current.outboundIncreasement = current.outboundCounter - previous.outboundCounter; | ||||
@@ -122,7 +122,6 @@ Port {0} is reserved by system= ポート番号 {0} はシステムによって | |||||
Invalid server address=サーバーアドレスが無効です。 | Invalid server address=サーバーアドレスが無効です。 | ||||
Illegal port number format=ポート番号のフォーマットが無効です。 | Illegal port number format=ポート番号のフォーマットが無効です。 | ||||
Illegal timeout format=タイムアウト値のフォーマットが無効です。 | Illegal timeout format=タイムアウト値のフォーマットが無効です。 | ||||
Please add at least one server=少なくとも一つのサーバーを指定して下さい。 | |||||
Server IP can not be blank=サーバー IP が指定されていません。 | Server IP can not be blank=サーバー IP が指定されていません。 | ||||
Password can not be blank=パスワードが指定されていません。 | Password can not be blank=パスワードが指定されていません。 | ||||
Port out of range=ポート番号は範囲外です。 | Port out of range=ポート番号は範囲外です。 | ||||
@@ -123,7 +123,6 @@ Port {0} is reserved by system=端口 {0} 是系统保留端口 | |||||
Invalid server address=非法服务器地址 | Invalid server address=非法服务器地址 | ||||
Illegal port number format=非法端口格式 | Illegal port number format=非法端口格式 | ||||
Illegal timeout format=非法超时格式 | Illegal timeout format=非法超时格式 | ||||
Please add at least one server=请添加至少一个服务器 | |||||
Server IP can not be blank=服务器 IP 不能为空 | Server IP can not be blank=服务器 IP 不能为空 | ||||
Password can not be blank=密码不能为空 | Password can not be blank=密码不能为空 | ||||
Port out of range=端口超出范围 | Port out of range=端口超出范围 | ||||
@@ -155,6 +154,14 @@ Register hotkey failed=注册快捷键失败 | |||||
Cannot parse hotkey: {0}=解析快捷键失败: {0} | Cannot parse hotkey: {0}=解析快捷键失败: {0} | ||||
Timeout is invalid, it should not exceed {0}=超时无效,不应超过 {0} | Timeout is invalid, it should not exceed {0}=超时无效,不应超过 {0} | ||||
Operation failure=操作失败 | |||||
Auto save failed=自动保存失败 | |||||
Whether to discard unconfigured servers=是否丢弃未配置的服务器 | |||||
Invalid server address, Cannot automatically save or discard changes=非法服务器地址,无法自动保存是否丢弃修改 | |||||
Illegal port number format, Cannot automatically save or discard changes=非法端口格式,无法自动保存是否丢弃修改 | |||||
Password can not be blank, Cannot automatically save or discard changes=密码不能为空,无法自动保存是否丢弃修改 | |||||
Illegal timeout format, Cannot automatically save or discard changes=非法超时格式,无法自动保存是否丢弃修改 | |||||
Error occured when process proxy setting, do you want reset current setting and retry?=处理代理设置时发生错误,是否重置当前代理设置并重试? | Error occured when process proxy setting, do you want reset current setting and retry?=处理代理设置时发生错误,是否重置当前代理设置并重试? | ||||
Unrecoverable proxy setting error occured, see log for detail=发生不可恢复的代理设置错误,查看日志以取得详情 | Unrecoverable proxy setting error occured, see log for detail=发生不可恢复的代理设置错误,查看日志以取得详情 | ||||
Auth user can not be blank=认证用户不能为空 | Auth user can not be blank=认证用户不能为空 |
@@ -122,7 +122,6 @@ Port {0} is reserved by system=連接埠號碼 {0} 由系統保留 | |||||
Invalid server address=無效伺服器位址 | Invalid server address=無效伺服器位址 | ||||
Illegal port number format=無效連接埠號碼格式 | Illegal port number format=無效連接埠號碼格式 | ||||
Illegal timeout format=無效逾時格式 | Illegal timeout format=無效逾時格式 | ||||
Please add at least one server=請新增至少一個伺服器 | |||||
Server IP can not be blank=伺服器 IP 不能為空 | Server IP can not be blank=伺服器 IP 不能為空 | ||||
Password can not be blank=密碼不能為空 | Password can not be blank=密碼不能為空 | ||||
Port out of range=連接埠號碼超出範圍 | Port out of range=連接埠號碼超出範圍 | ||||
@@ -1,9 +1,8 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.IO; | using System.IO; | ||||
using Shadowsocks.Controller; | |||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
using Shadowsocks.Controller; | |||||
namespace Shadowsocks.Model | namespace Shadowsocks.Model | ||||
{ | { | ||||
@@ -34,7 +33,7 @@ namespace Shadowsocks.Model | |||||
public ProxyConfig proxy; | public ProxyConfig proxy; | ||||
public HotkeyConfig hotkey; | public HotkeyConfig hotkey; | ||||
private static string CONFIG_FILE = "gui-config.json"; | |||||
private static readonly string CONFIG_FILE = "gui-config.json"; | |||||
public Server GetCurrentServer() | public Server GetCurrentServer() | ||||
{ | { | ||||
@@ -46,12 +45,25 @@ namespace Shadowsocks.Model | |||||
public static void CheckServer(Server server) | public static void CheckServer(Server server) | ||||
{ | { | ||||
CheckServer(server.server); | |||||
CheckPort(server.server_port); | CheckPort(server.server_port); | ||||
CheckPassword(server.password); | CheckPassword(server.password); | ||||
CheckServer(server.server); | |||||
CheckTimeout(server.timeout, Server.MaxServerTimeoutSec); | CheckTimeout(server.timeout, Server.MaxServerTimeoutSec); | ||||
} | } | ||||
public static bool ChecksServer(Server server) | |||||
{ | |||||
try | |||||
{ | |||||
CheckServer(server); | |||||
return true; | |||||
} | |||||
catch (Exception) | |||||
{ | |||||
return false; | |||||
} | |||||
} | |||||
public static Configuration Load() | public static Configuration Load() | ||||
{ | { | ||||
try | try | ||||
@@ -125,12 +137,18 @@ namespace Shadowsocks.Model | |||||
} | } | ||||
} | } | ||||
public static Server AddDefaultServerOrServer(Configuration config, Server server = null) | |||||
public static Server AddDefaultServerOrServer(Configuration config, Server server = null, int? index = null) | |||||
{ | { | ||||
if (config != null && config.configs != null) | if (config != null && config.configs != null) | ||||
{ | { | ||||
server = (server ?? GetDefaultServer()); | server = (server ?? GetDefaultServer()); | ||||
config.configs.Add(server); | |||||
config.configs.Insert(index.GetValueOrDefault(config.configs.Count), server); | |||||
//if (index.HasValue) | |||||
// config.configs.Insert(index.Value, server); | |||||
//else | |||||
// config.configs.Add(server); | |||||
} | } | ||||
return server; | return server; | ||||
} | } | ||||
@@ -174,8 +192,7 @@ namespace Shadowsocks.Model | |||||
public static void CheckTimeout(int timeout, int maxTimeout) | public static void CheckTimeout(int timeout, int maxTimeout) | ||||
{ | { | ||||
if (timeout <= 0 || timeout > maxTimeout) | if (timeout <= 0 || timeout > maxTimeout) | ||||
throw new ArgumentException( | |||||
I18N.GetString("Timeout is invalid, it should not exceed {0}", maxTimeout)); | |||||
throw new ArgumentException(I18N.GetString("Timeout is invalid, it should not exceed {0}", maxTimeout)); | |||||
} | } | ||||
public static void CheckProxyAuthUser(string user) | public static void CheckProxyAuthUser(string user) | ||||
@@ -1,5 +1,6 @@ | |||||
using System; | using System; | ||||
using System.Drawing; | using System.Drawing; | ||||
using System.Runtime.CompilerServices; | |||||
using System.Windows.Forms; | using System.Windows.Forms; | ||||
using Shadowsocks.Controller; | using Shadowsocks.Controller; | ||||
using Shadowsocks.Model; | using Shadowsocks.Model; | ||||
@@ -17,20 +18,20 @@ namespace Shadowsocks.View | |||||
public ConfigForm(ShadowsocksController controller) | public ConfigForm(ShadowsocksController controller) | ||||
{ | { | ||||
this.Font = SystemFonts.MessageBoxFont; | |||||
Font = SystemFonts.MessageBoxFont; | |||||
InitializeComponent(); | InitializeComponent(); | ||||
// a dirty hack | // a dirty hack | ||||
this.ServersListBox.Dock = DockStyle.Fill; | |||||
this.tableLayoutPanel5.Dock = DockStyle.Fill; | |||||
this.PerformLayout(); | |||||
ServersListBox.Dock = DockStyle.Fill; | |||||
tableLayoutPanel5.Dock = DockStyle.Fill; | |||||
PerformLayout(); | |||||
UpdateTexts(); | UpdateTexts(); | ||||
SetupValueChangedListeners(); | SetupValueChangedListeners(); | ||||
this.Icon = Icon.FromHandle(Resources.ssw128.GetHicon()); | |||||
Icon = Icon.FromHandle(Resources.ssw128.GetHicon()); | |||||
this.controller = controller; | this.controller = controller; | ||||
controller.ConfigChanged += controller_ConfigChanged; | |||||
controller.ConfigChanged += Controller_ConfigChanged; | |||||
LoadCurrentConfiguration(); | LoadCurrentConfiguration(); | ||||
} | } | ||||
@@ -51,7 +52,7 @@ namespace Shadowsocks.View | |||||
NeedPluginArgCheckBox.Text = I18N.GetString("Need Plugin Argument"); | NeedPluginArgCheckBox.Text = I18N.GetString("Need Plugin Argument"); | ||||
ProxyPortLabel.Text = I18N.GetString("Proxy Port"); | ProxyPortLabel.Text = I18N.GetString("Proxy Port"); | ||||
PortableModeCheckBox.Text = I18N.GetString("Portable Mode"); | PortableModeCheckBox.Text = I18N.GetString("Portable Mode"); | ||||
toolTip1.SetToolTip(this.PortableModeCheckBox, I18N.GetString("Restart required")); | |||||
toolTip1.SetToolTip(PortableModeCheckBox, I18N.GetString("Restart required")); | |||||
RemarksLabel.Text = I18N.GetString("Remarks"); | RemarksLabel.Text = I18N.GetString("Remarks"); | ||||
TimeoutLabel.Text = I18N.GetString("Timeout(Sec)"); | TimeoutLabel.Text = I18N.GetString("Timeout(Sec)"); | ||||
ServerGroupBox.Text = I18N.GetString("Server"); | ServerGroupBox.Text = I18N.GetString("Server"); | ||||
@@ -60,7 +61,7 @@ namespace Shadowsocks.View | |||||
ApplyButton.Text = I18N.GetString("Apply"); | ApplyButton.Text = I18N.GetString("Apply"); | ||||
MoveUpButton.Text = I18N.GetString("Move &Up"); | MoveUpButton.Text = I18N.GetString("Move &Up"); | ||||
MoveDownButton.Text = I18N.GetString("Move D&own"); | MoveDownButton.Text = I18N.GetString("Move D&own"); | ||||
this.Text = I18N.GetString("Edit Servers"); | |||||
Text = I18N.GetString("Edit Servers"); | |||||
} | } | ||||
private void SetupValueChangedListeners() | private void SetupValueChangedListeners() | ||||
@@ -78,7 +79,7 @@ namespace Shadowsocks.View | |||||
ServerPortTextBox.TextChanged += ConfigValueChanged; | ServerPortTextBox.TextChanged += ConfigValueChanged; | ||||
} | } | ||||
private void controller_ConfigChanged(object sender, EventArgs e) | |||||
private void Controller_ConfigChanged(object sender, EventArgs e) | |||||
{ | { | ||||
LoadCurrentConfiguration(); | LoadCurrentConfiguration(); | ||||
} | } | ||||
@@ -88,7 +89,13 @@ namespace Shadowsocks.View | |||||
ApplyButton.Enabled = true; | ApplyButton.Enabled = true; | ||||
} | } | ||||
private bool ValidateAndSaveSelectedServerDetails() | |||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||||
private void UpdateIndexToEnd() | |||||
{ | |||||
_lastSelectedIndex = (ServersListBox.SelectedIndex = (_modifiedConfiguration.configs.Count - 1)); | |||||
} | |||||
private bool ValidateAndSaveSelectedServerDetails(bool isSave = false, bool isCopy = false) | |||||
{ | { | ||||
try | try | ||||
{ | { | ||||
@@ -96,15 +103,17 @@ namespace Shadowsocks.View | |||||
{ | { | ||||
return true; | return true; | ||||
} | } | ||||
Server server = GetServerDetailsFromUI(); | |||||
if (server == null) | |||||
bool verify = GetServerDetailsFromUI(out Server server, isSave, isCopy); | |||||
if (server != null) | |||||
{ | { | ||||
return false; | |||||
} | |||||
Configuration.CheckServer(server); | |||||
_modifiedConfiguration.configs[_lastSelectedIndex] = server; | |||||
if (isSave || isCopy) | |||||
Configuration.CheckServer(server); | |||||
return true; | |||||
_modifiedConfiguration.configs[_lastSelectedIndex] = server; | |||||
} | |||||
return verify; | |||||
} | } | ||||
catch (Exception ex) | catch (Exception ex) | ||||
{ | { | ||||
@@ -113,36 +122,209 @@ namespace Shadowsocks.View | |||||
return false; | return false; | ||||
} | } | ||||
private Server GetServerDetailsFromUI() | |||||
private bool GetServerDetailsFromUI(out Server server, bool isSave = false, bool isCopy = false) | |||||
{ | |||||
server = null; | |||||
bool? checkIP = false; | |||||
bool? checkPort = false; | |||||
bool? checkPassword = false; | |||||
bool? checkTimeout = false; | |||||
if ((checkIP = CheckIPTextBox(out string address, isSave, isCopy)).GetValueOrDefault(false) && address != null | |||||
&& (checkPort = CheckServerPortTextBox(out int? addressPort, isSave, isCopy)).GetValueOrDefault(false) && addressPort.HasValue | |||||
&& (checkPassword = CheckPasswordTextBox(out string serverPassword, isSave, isCopy)).GetValueOrDefault(false) && serverPassword != null | |||||
&& (checkTimeout = CheckTimeoutTextBox(out int? timeout, isSave, isCopy)).GetValueOrDefault(false) && timeout.HasValue) | |||||
{ | |||||
server = new Server() | |||||
{ | |||||
server = address, | |||||
server_port = addressPort.Value, | |||||
password = serverPassword, | |||||
method = EncryptionSelect.Text, | |||||
plugin = PluginTextBox.Text, | |||||
plugin_opts = PluginOptionsTextBox.Text, | |||||
plugin_args = PluginArgumentsTextBox.Text, | |||||
remarks = RemarksTextBox.Text, | |||||
timeout = timeout.Value, | |||||
}; | |||||
return true; | |||||
} | |||||
if (checkIP == null || checkPort == null || checkTimeout == null) | |||||
{ | |||||
_modifiedConfiguration.configs.RemoveAt(_lastSelectedIndex); | |||||
ServersListBox.SelectedIndexChanged -= ServersListBox_SelectedIndexChanged; | |||||
LoadServerNameListToUI(_modifiedConfiguration); | |||||
UpdateIndexToEnd(); | |||||
ServersListBox.SelectedIndexChanged += ServersListBox_SelectedIndexChanged; | |||||
return true; | |||||
} | |||||
else | |||||
return false; | |||||
} | |||||
#region GetServerDetailsFromUI Check | |||||
private bool? CheckIPTextBox(out string address, bool isSave, bool isCopy) | |||||
{ | |||||
address = null; | |||||
string outAddress; | |||||
if (Uri.CheckHostName(outAddress = IPTextBox.Text.Trim()) == UriHostNameType.Unknown) | |||||
{ | |||||
if (!isSave && !isCopy && ServersListBox.Items.Count > 1 && I18N.GetString("New server").Equals(ServersListBox.Items[_lastSelectedIndex].ToString())) | |||||
{ | |||||
DialogResult result = MessageBox.Show(I18N.GetString("Whether to discard unconfigured servers"), I18N.GetString("Operation failure"), MessageBoxButtons.OKCancel); | |||||
if (result == DialogResult.OK) | |||||
return null; | |||||
} | |||||
else if (ApplyButton.Enabled && !isSave && !isCopy) | |||||
{ | |||||
var result = MessageBox.Show(I18N.GetString("Invalid server address, Cannot automatically save or discard changes"), I18N.GetString("Auto save failed"), MessageBoxButtons.OKCancel); | |||||
if (result == DialogResult.Cancel) | |||||
return false; | |||||
else | |||||
{ | |||||
address = _modifiedConfiguration.configs[_lastSelectedIndex].server; | |||||
return true; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
MessageBox.Show(I18N.GetString("Invalid server address"), I18N.GetString("Operation failure")); | |||||
IPTextBox.Focus(); | |||||
} | |||||
return false; | |||||
} | |||||
else | |||||
{ | |||||
address = outAddress; | |||||
} | |||||
return true; | |||||
} | |||||
private bool? CheckServerPortTextBox(out int? addressPort, bool isSave, bool isCopy) | |||||
{ | |||||
addressPort = null; | |||||
if (!int.TryParse(ServerPortTextBox.Text, out int outaddressPort)) | |||||
{ | |||||
if (!isSave && !isCopy && ServersListBox.Items.Count > 1 && I18N.GetString("New server").Equals(ServersListBox.Items[_lastSelectedIndex].ToString())) | |||||
{ | |||||
DialogResult result = MessageBox.Show(I18N.GetString("Whether to discard unconfigured servers"), I18N.GetString("Operation failure"), MessageBoxButtons.OKCancel); | |||||
if (result == DialogResult.OK) | |||||
return null; | |||||
} | |||||
else if (!isSave && !isCopy) | |||||
{ | |||||
var result = MessageBox.Show(I18N.GetString("Illegal port number format, Cannot automatically save or discard changes"), I18N.GetString("Auto save failed"), MessageBoxButtons.OKCancel); | |||||
if (result == DialogResult.Cancel) | |||||
return false; | |||||
else | |||||
{ | |||||
addressPort = _modifiedConfiguration.configs[_lastSelectedIndex].server_port; | |||||
return true; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
MessageBox.Show(I18N.GetString("Illegal port number format"), I18N.GetString("Operation failure")); | |||||
ServerPortTextBox.Focus(); | |||||
} | |||||
return false; | |||||
} | |||||
else | |||||
{ | |||||
addressPort = outaddressPort; | |||||
} | |||||
return true; | |||||
} | |||||
private bool? CheckPasswordTextBox(out string password, bool isSave, bool isCopy) | |||||
{ | { | ||||
Server server = new Server(); | |||||
if (Uri.CheckHostName(server.server = IPTextBox.Text.Trim()) == UriHostNameType.Unknown) | |||||
password = null; | |||||
string outPassword; | |||||
if ((outPassword = PasswordTextBox.Text).IsNullOrWhiteSpace()) | |||||
{ | { | ||||
MessageBox.Show(I18N.GetString("Invalid server address")); | |||||
IPTextBox.Focus(); | |||||
return null; | |||||
if (!isSave && !isCopy && ServersListBox.Items.Count > 1 && I18N.GetString("New server").Equals(ServersListBox.Items[_lastSelectedIndex].ToString())) | |||||
{ | |||||
DialogResult result = MessageBox.Show(I18N.GetString("Whether to discard unconfigured servers"), I18N.GetString("Operation failure"), MessageBoxButtons.OKCancel); | |||||
if (result == DialogResult.OK) | |||||
return null; | |||||
} | |||||
else if (ApplyButton.Enabled && !isSave && !isCopy) | |||||
{ | |||||
var result = MessageBox.Show(I18N.GetString("Password can not be blank, Cannot automatically save or discard changes"), I18N.GetString("Auto save failed"), MessageBoxButtons.OKCancel); | |||||
if (result == DialogResult.Cancel) | |||||
return false; | |||||
else | |||||
{ | |||||
password = _modifiedConfiguration.configs[_lastSelectedIndex].password; | |||||
return true; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
MessageBox.Show(I18N.GetString("Password can not be blank"), I18N.GetString("Operation failure")); | |||||
PasswordTextBox.Focus(); | |||||
} | |||||
return false; | |||||
} | } | ||||
if (!int.TryParse(ServerPortTextBox.Text, out server.server_port)) | |||||
else | |||||
{ | { | ||||
MessageBox.Show(I18N.GetString("Illegal port number format")); | |||||
ServerPortTextBox.Focus(); | |||||
return null; | |||||
password = outPassword; | |||||
} | } | ||||
server.password = PasswordTextBox.Text; | |||||
server.method = EncryptionSelect.Text; | |||||
server.plugin = PluginTextBox.Text; | |||||
server.plugin_opts = PluginOptionsTextBox.Text; | |||||
server.plugin_args = PluginArgumentsTextBox.Text; | |||||
server.remarks = RemarksTextBox.Text; | |||||
if (!int.TryParse(TimeoutTextBox.Text, out server.timeout)) | |||||
return true; | |||||
} | |||||
private bool? CheckTimeoutTextBox(out int? timeout, bool isSave, bool isCopy) | |||||
{ | |||||
timeout = null; | |||||
if (!int.TryParse(TimeoutTextBox.Text, out int outTimeout)) | |||||
{ | |||||
if (!isSave && !isCopy && ServersListBox.Items.Count > 1 && I18N.GetString("New server").Equals(ServersListBox.Items[_lastSelectedIndex].ToString())) | |||||
{ | |||||
DialogResult result = MessageBox.Show(I18N.GetString("Whether to discard unconfigured servers"), I18N.GetString("Operation failure"), MessageBoxButtons.OKCancel); | |||||
if (result == DialogResult.OK) | |||||
return null; | |||||
} | |||||
else if (ApplyButton.Enabled && !isSave && !isCopy) | |||||
{ | |||||
var result = MessageBox.Show(I18N.GetString("Illegal timeout format, Cannot automatically save or discard changes"), I18N.GetString("Auto save failed"), MessageBoxButtons.OKCancel); | |||||
if (result == DialogResult.Cancel) | |||||
return false; | |||||
else | |||||
{ | |||||
timeout = _modifiedConfiguration.configs[_lastSelectedIndex].timeout; | |||||
return true; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
MessageBox.Show(I18N.GetString("Illegal timeout format"), I18N.GetString("Operation failure")); | |||||
TimeoutTextBox.Focus(); | |||||
} | |||||
return false; | |||||
} | |||||
else | |||||
{ | { | ||||
MessageBox.Show(I18N.GetString("Illegal timeout format")); | |||||
TimeoutTextBox.Focus(); | |||||
return null; | |||||
timeout = outTimeout; | |||||
} | } | ||||
return server; | |||||
return true; | |||||
} | } | ||||
#endregion | |||||
private void LoadSelectedServerDetails() | private void LoadSelectedServerDetails() | ||||
{ | { | ||||
if (ServersListBox.SelectedIndex >= 0 && ServersListBox.SelectedIndex < _modifiedConfiguration.configs.Count) | if (ServersListBox.SelectedIndex >= 0 && ServersListBox.SelectedIndex < _modifiedConfiguration.configs.Count) | ||||
@@ -168,6 +350,8 @@ namespace Shadowsocks.View | |||||
RemarksTextBox.Text = server.remarks; | RemarksTextBox.Text = server.remarks; | ||||
TimeoutTextBox.Text = server.timeout.ToString(); | TimeoutTextBox.Text = server.timeout.ToString(); | ||||
ApplyButton.Enabled = false; | |||||
} | } | ||||
private void ShowHidePluginArgInput(bool show) | private void ShowHidePluginArgInput(bool show) | ||||
@@ -176,7 +360,6 @@ namespace Shadowsocks.View | |||||
PluginArgumentsLabel.Visible = show; | PluginArgumentsLabel.Visible = show; | ||||
} | } | ||||
private void LoadServerNameListToUI(Configuration configuration) | private void LoadServerNameListToUI(Configuration configuration) | ||||
{ | { | ||||
ServersListBox.Items.Clear(); | ServersListBox.Items.Clear(); | ||||
@@ -200,20 +383,17 @@ namespace Shadowsocks.View | |||||
ServersListBox.SelectedIndex = _lastSelectedIndex; | ServersListBox.SelectedIndex = _lastSelectedIndex; | ||||
UpdateButtons(); | UpdateButtons(); | ||||
LoadSelectedServerDetails(); | LoadSelectedServerDetails(); | ||||
ProxyPortTextBox.Text = _modifiedConfiguration.localPort.ToString(); | ProxyPortTextBox.Text = _modifiedConfiguration.localPort.ToString(); | ||||
PortableModeCheckBox.Checked = _modifiedConfiguration.portableMode; | PortableModeCheckBox.Checked = _modifiedConfiguration.portableMode; | ||||
ApplyButton.Enabled = false; | ApplyButton.Enabled = false; | ||||
} | } | ||||
private bool SaveValidConfiguration() | private bool SaveValidConfiguration() | ||||
{ | { | ||||
if (!ValidateAndSaveSelectedServerDetails()) | |||||
{ | |||||
return false; | |||||
} | |||||
if (_modifiedConfiguration.configs.Count == 0) | |||||
if (!ValidateAndSaveSelectedServerDetails(isSave: true)) | |||||
{ | { | ||||
MessageBox.Show(I18N.GetString("Please add at least one server")); | |||||
return false; | return false; | ||||
} | } | ||||
@@ -269,81 +449,62 @@ namespace Shadowsocks.View | |||||
private void AddButton_Click(object sender, EventArgs e) | private void AddButton_Click(object sender, EventArgs e) | ||||
{ | { | ||||
if (!ValidateAndSaveSelectedServerDetails()) | |||||
if (ValidateAndSaveSelectedServerDetails(isSave: true)) | |||||
{ | { | ||||
return; | |||||
Configuration.AddDefaultServerOrServer(_modifiedConfiguration); | |||||
LoadServerNameListToUI(_modifiedConfiguration); | |||||
UpdateIndexToEnd(); | |||||
} | } | ||||
Configuration.AddDefaultServerOrServer(_modifiedConfiguration); | |||||
LoadServerNameListToUI(_modifiedConfiguration); | |||||
ServersListBox.SelectedIndex = _modifiedConfiguration.configs.Count - 1; | |||||
_lastSelectedIndex = ServersListBox.SelectedIndex; | |||||
} | } | ||||
private void DuplicateButton_Click(object sender, EventArgs e) | private void DuplicateButton_Click(object sender, EventArgs e) | ||||
{ | { | ||||
if (_lastSelectedIndex == -1 || _lastSelectedIndex > _modifiedConfiguration.configs.Count | |||||
|| !ValidateAndSaveSelectedServerDetails()) | |||||
if (ValidateAndSaveSelectedServerDetails(isCopy: true)) | |||||
{ | { | ||||
return; | |||||
Server currServer = _modifiedConfiguration.configs[_lastSelectedIndex]; | |||||
Configuration.AddDefaultServerOrServer(_modifiedConfiguration, currServer); | |||||
LoadServerNameListToUI(_modifiedConfiguration); | |||||
UpdateIndexToEnd(); | |||||
} | } | ||||
Server currServer = _modifiedConfiguration.configs[_lastSelectedIndex]; | |||||
var currIndex = _modifiedConfiguration.configs.IndexOf(currServer); | |||||
_modifiedConfiguration.configs.Insert(currIndex + 1, currServer); | |||||
LoadServerNameListToUI(_modifiedConfiguration); | |||||
ServersListBox.SelectedIndex = currIndex + 1; | |||||
_lastSelectedIndex = ServersListBox.SelectedIndex; | |||||
} | } | ||||
private void DeleteButton_Click(object sender, EventArgs e) | private void DeleteButton_Click(object sender, EventArgs e) | ||||
{ | { | ||||
_lastSelectedIndex = ServersListBox.SelectedIndex; | |||||
if (_lastSelectedIndex >= 0 && _lastSelectedIndex < _modifiedConfiguration.configs.Count) | |||||
{ | |||||
_modifiedConfiguration.configs.RemoveAt(_lastSelectedIndex); | |||||
} | |||||
_modifiedConfiguration.configs.RemoveAt(_lastSelectedIndex); | |||||
if (_modifiedConfiguration.configs.Count == 0) | if (_modifiedConfiguration.configs.Count == 0) | ||||
{ | { | ||||
Configuration.AddDefaultServerOrServer(_modifiedConfiguration); | Configuration.AddDefaultServerOrServer(_modifiedConfiguration); | ||||
} | } | ||||
if (_lastSelectedIndex >= _modifiedConfiguration.configs.Count) | |||||
{ | |||||
// can be -1 | |||||
_lastSelectedIndex = _modifiedConfiguration.configs.Count - 1; | |||||
} | |||||
ServersListBox.SelectedIndex = _lastSelectedIndex; | |||||
LoadServerNameListToUI(_modifiedConfiguration); | LoadServerNameListToUI(_modifiedConfiguration); | ||||
ServersListBox.SelectedIndex = _lastSelectedIndex; | |||||
UpdateIndexToEnd(); | |||||
LoadSelectedServerDetails(); | LoadSelectedServerDetails(); | ||||
UpdateButtons(); | UpdateButtons(); | ||||
} | } | ||||
private void OKButton_Click(object sender, EventArgs e) | |||||
{ | |||||
if (SaveValidConfiguration()) | |||||
{ | |||||
this.Close(); | |||||
} | |||||
} | |||||
private void CancelButton_Click(object sender, EventArgs e) | |||||
{ | |||||
this.Close(); | |||||
} | |||||
private void ApplyButton_Click(object sender, EventArgs e) | |||||
private void UpdateButtons() | |||||
{ | { | ||||
SaveValidConfiguration(); | |||||
DeleteButton.Enabled = (ServersListBox.Items.Count > 0); | |||||
MoveUpButton.Enabled = (ServersListBox.SelectedIndex > 0); | |||||
MoveDownButton.Enabled = (ServersListBox.SelectedIndex < ServersListBox.Items.Count - 1); | |||||
} | } | ||||
private void ConfigForm_Shown(object sender, EventArgs e) | |||||
private void MoveUpButton_Click(object sender, EventArgs e) | |||||
{ | { | ||||
IPTextBox.Focus(); | |||||
if (ServersListBox.SelectedIndex > 0) | |||||
{ | |||||
MoveConfigItem(-1); // -1 means move backward | |||||
} | |||||
} | } | ||||
private void ConfigForm_FormClosed(object sender, FormClosedEventArgs e) | |||||
private void MoveDownButton_Click(object sender, EventArgs e) | |||||
{ | { | ||||
controller.ConfigChanged -= controller_ConfigChanged; | |||||
if (ServersListBox.SelectedIndex < ServersListBox.Items.Count - 1) | |||||
{ | |||||
MoveConfigItem(+1); // +1 means move forward | |||||
} | |||||
} | } | ||||
private void MoveConfigItem(int step) | private void MoveConfigItem(int step) | ||||
@@ -368,45 +529,42 @@ namespace Shadowsocks.View | |||||
UpdateButtons(); | UpdateButtons(); | ||||
} | } | ||||
private void UpdateButtons() | |||||
private void OKButton_Click(object sender, EventArgs e) | |||||
{ | { | ||||
DeleteButton.Enabled = (ServersListBox.Items.Count > 0); | |||||
MoveUpButton.Enabled = (ServersListBox.SelectedIndex > 0); | |||||
MoveDownButton.Enabled = (ServersListBox.SelectedIndex < ServersListBox.Items.Count - 1); | |||||
if (SaveValidConfiguration()) | |||||
{ | |||||
Close(); | |||||
} | |||||
} | } | ||||
private void MoveUpButton_Click(object sender, EventArgs e) | |||||
private void CancelButton_Click(object sender, EventArgs e) | |||||
{ | { | ||||
if (!ValidateAndSaveSelectedServerDetails()) | |||||
{ | |||||
return; | |||||
} | |||||
if (ServersListBox.SelectedIndex > 0) | |||||
{ | |||||
MoveConfigItem(-1); // -1 means move backward | |||||
} | |||||
Close(); | |||||
} | } | ||||
private void MoveDownButton_Click(object sender, EventArgs e) | |||||
private void ApplyButton_Click(object sender, EventArgs e) | |||||
{ | { | ||||
if (!ValidateAndSaveSelectedServerDetails()) | |||||
{ | |||||
return; | |||||
} | |||||
if (ServersListBox.SelectedIndex < ServersListBox.Items.Count - 1) | |||||
{ | |||||
MoveConfigItem(+1); // +1 means move forward | |||||
} | |||||
SaveValidConfiguration(); | |||||
} | |||||
private void ConfigForm_Shown(object sender, EventArgs e) | |||||
{ | |||||
IPTextBox.Focus(); | |||||
} | |||||
private void ConfigForm_FormClosed(object sender, FormClosedEventArgs e) | |||||
{ | |||||
controller.ConfigChanged -= Controller_ConfigChanged; | |||||
} | } | ||||
private void ShowPasswdCheckBox_CheckedChanged(object sender, EventArgs e) | private void ShowPasswdCheckBox_CheckedChanged(object sender, EventArgs e) | ||||
{ | { | ||||
this.PasswordTextBox.UseSystemPasswordChar = !this.ShowPasswdCheckBox.Checked; | |||||
PasswordTextBox.UseSystemPasswordChar = !ShowPasswdCheckBox.Checked; | |||||
} | } | ||||
private void UsePluginArgCheckBox_CheckedChanged(object sender, EventArgs e) | private void UsePluginArgCheckBox_CheckedChanged(object sender, EventArgs e) | ||||
{ | { | ||||
ShowHidePluginArgInput(this.NeedPluginArgCheckBox.Checked); | |||||
ShowHidePluginArgInput(NeedPluginArgCheckBox.Checked); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -438,11 +438,14 @@ namespace Shadowsocks.View | |||||
Configuration configuration = controller.GetConfigurationCopy(); | Configuration configuration = controller.GetConfigurationCopy(); | ||||
foreach (var server in configuration.configs) | foreach (var server in configuration.configs) | ||||
{ | { | ||||
MenuItem item = new MenuItem(server.FriendlyName()); | |||||
item.Tag = i - strategyCount; | |||||
item.Click += AServerItem_Click; | |||||
items.Add(i, item); | |||||
i++; | |||||
if (Configuration.ChecksServer(server)) | |||||
{ | |||||
MenuItem item = new MenuItem(server.FriendlyName()); | |||||
item.Tag = i - strategyCount; | |||||
item.Click += AServerItem_Click; | |||||
items.Add(i, item); | |||||
i++; | |||||
} | |||||
} | } | ||||
foreach (MenuItem item in items) | foreach (MenuItem item in items) | ||||