@@ -1,10 +0,0 @@ | |||
using CommandLine; | |||
namespace Shadowsocks | |||
{ | |||
public class CommandLineOption | |||
{ | |||
[Option("open-url",Required = false,HelpText = "Add an ss:// URL")] | |||
public string OpenUrl { get; set; } | |||
} | |||
} |
@@ -1,733 +0,0 @@ | |||
using System; | |||
using System.Collections.Concurrent; | |||
using System.Collections.Generic; | |||
using System.IO; | |||
using System.Linq; | |||
using System.Net; | |||
using System.Net.Http; | |||
using System.Net.Sockets; | |||
using System.Text; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
using System.Web; | |||
using System.Windows.Forms; | |||
using NLog; | |||
using Shadowsocks.Controller.Service; | |||
using Shadowsocks.Controller.Strategy; | |||
using Shadowsocks.Model; | |||
using Shadowsocks.Util; | |||
using WPFLocalizeExtension.Engine; | |||
namespace Shadowsocks.Controller | |||
{ | |||
public class ShadowsocksController | |||
{ | |||
private readonly Logger logger; | |||
private readonly HttpClient httpClient; | |||
// controller: | |||
// handle user actions | |||
// manipulates UI | |||
// interacts with low level logic | |||
#region Member definition | |||
private Thread _trafficThread; | |||
private TCPListener _tcpListener; | |||
private UDPListener _udpListener; | |||
private PACDaemon _pacDaemon; | |||
private PACServer _pacServer; | |||
private Configuration _config; | |||
private StrategyManager _strategyManager; | |||
private PrivoxyRunner privoxyRunner; | |||
private readonly ConcurrentDictionary<Server, Sip003Plugin> _pluginsByServer; | |||
private long _inboundCounter = 0; | |||
private long _outboundCounter = 0; | |||
public long InboundCounter => Interlocked.Read(ref _inboundCounter); | |||
public long OutboundCounter => Interlocked.Read(ref _outboundCounter); | |||
public Queue<TrafficPerSecond> trafficPerSecondQueue; | |||
private bool stopped = false; | |||
public class PathEventArgs : EventArgs | |||
{ | |||
public string Path; | |||
} | |||
public class UpdatedEventArgs : EventArgs | |||
{ | |||
public string OldVersion; | |||
public string NewVersion; | |||
} | |||
public class TrafficPerSecond | |||
{ | |||
public long inboundCounter; | |||
public long outboundCounter; | |||
public long inboundIncreasement; | |||
public long outboundIncreasement; | |||
} | |||
public event EventHandler ConfigChanged; | |||
public event EventHandler EnableStatusChanged; | |||
public event EventHandler EnableGlobalChanged; | |||
public event EventHandler ShareOverLANStatusChanged; | |||
public event EventHandler VerboseLoggingStatusChanged; | |||
public event EventHandler ShowPluginOutputChanged; | |||
public event EventHandler TrafficChanged; | |||
// when user clicked Edit PAC, and PAC file has already created | |||
public event EventHandler<PathEventArgs> PACFileReadyToOpen; | |||
public event EventHandler<PathEventArgs> UserRuleFileReadyToOpen; | |||
public event EventHandler<GeositeResultEventArgs> UpdatePACFromGeositeCompleted; | |||
public event ErrorEventHandler UpdatePACFromGeositeError; | |||
public event ErrorEventHandler Errored; | |||
// Invoked when controller.Start(); | |||
public event EventHandler<UpdatedEventArgs> ProgramUpdated; | |||
#endregion | |||
public ShadowsocksController() | |||
{ | |||
logger = LogManager.GetCurrentClassLogger(); | |||
httpClient = new HttpClient(); | |||
_config = Configuration.Load(); | |||
Configuration.Process(ref _config); | |||
_strategyManager = new StrategyManager(this); | |||
_pluginsByServer = new ConcurrentDictionary<Server, Sip003Plugin>(); | |||
StartTrafficStatistics(61); | |||
ProgramUpdated += (o, e) => | |||
{ | |||
// version update precedures | |||
if (e.OldVersion == "4.3.0.0" || e.OldVersion == "4.3.1.0") | |||
_config.geositeDirectGroups.Add("private"); | |||
logger.Info($"Updated from {e.OldVersion} to {e.NewVersion}"); | |||
}; | |||
} | |||
#region Basic | |||
public void Start(bool systemWakeUp = false) | |||
{ | |||
if (_config.firstRunOnNewVersion && !systemWakeUp) | |||
{ | |||
ProgramUpdated.Invoke(this, new UpdatedEventArgs() | |||
{ | |||
OldVersion = _config.version, | |||
NewVersion = UpdateChecker.Version, | |||
}); | |||
// delete pac.txt when regeneratePacOnUpdate is true | |||
if (_config.regeneratePacOnUpdate) | |||
try | |||
{ | |||
File.Delete(PACDaemon.PAC_FILE); | |||
logger.Info("Deleted pac.txt from previous version."); | |||
} | |||
catch (Exception e) | |||
{ | |||
logger.LogUsefulException(e); | |||
} | |||
// finish up first run of new version | |||
_config.firstRunOnNewVersion = false; | |||
_config.version = UpdateChecker.Version; | |||
Configuration.Save(_config); | |||
} | |||
Reload(); | |||
if (!systemWakeUp) | |||
HotkeyReg.RegAllHotkeys(); | |||
} | |||
public void Stop() | |||
{ | |||
if (stopped) | |||
{ | |||
return; | |||
} | |||
stopped = true; | |||
_tcpListener?.Stop(); | |||
_udpListener?.Stop(); | |||
StopPlugins(); | |||
if (privoxyRunner != null) | |||
{ | |||
privoxyRunner.Stop(); | |||
} | |||
if (_config.enabled) | |||
{ | |||
SystemProxy.Update(_config, true, null); | |||
} | |||
} | |||
protected void Reload() | |||
{ | |||
Encryption.RNG.Reload(); | |||
// some logic in configuration updated the config when saving, we need to read it again | |||
_config = Configuration.Load(); | |||
Configuration.Process(ref _config); | |||
NLogConfig.LoadConfiguration(); | |||
logger.Info($"WPF Localization Extension|Current culture: {LocalizeDictionary.CurrentCulture}"); | |||
// set User-Agent for httpClient | |||
try | |||
{ | |||
if (!string.IsNullOrWhiteSpace(_config.userAgentString)) | |||
httpClient.DefaultRequestHeaders.Add("User-Agent", _config.userAgentString); | |||
} | |||
catch | |||
{ | |||
// reset userAgent to default and reapply | |||
Configuration.ResetUserAgent(_config); | |||
httpClient.DefaultRequestHeaders.Add("User-Agent", _config.userAgentString); | |||
} | |||
privoxyRunner = privoxyRunner ?? new PrivoxyRunner(); | |||
_pacDaemon = _pacDaemon ?? new PACDaemon(_config); | |||
_pacDaemon.PACFileChanged += PacDaemon_PACFileChanged; | |||
_pacDaemon.UserRuleFileChanged += PacDaemon_UserRuleFileChanged; | |||
_pacServer = _pacServer ?? new PACServer(_pacDaemon); | |||
_pacServer.UpdatePACURL(_config); // So PACServer works when system proxy disabled. | |||
GeositeUpdater.ResetEvent(); | |||
GeositeUpdater.UpdateCompleted += PacServer_PACUpdateCompleted; | |||
GeositeUpdater.Error += PacServer_PACUpdateError; | |||
_tcpListener?.Stop(); | |||
_udpListener?.Stop(); | |||
StopPlugins(); | |||
// don't put PrivoxyRunner.Start() before pacServer.Stop() | |||
// or bind will fail when switching bind address from 0.0.0.0 to 127.0.0.1 | |||
// though UseShellExecute is set to true now | |||
// http://stackoverflow.com/questions/10235093/socket-doesnt-close-after-application-exits-if-a-launched-process-is-open | |||
privoxyRunner.Stop(); | |||
try | |||
{ | |||
var strategy = GetCurrentStrategy(); | |||
strategy?.ReloadServers(); | |||
StartPlugin(); | |||
privoxyRunner.Start(_config); | |||
TCPRelay tcpRelay = new TCPRelay(this, _config); | |||
tcpRelay.OnInbound += UpdateInboundCounter; | |||
tcpRelay.OnOutbound += UpdateOutboundCounter; | |||
tcpRelay.OnFailed += (o, e) => GetCurrentStrategy()?.SetFailure(e.server); | |||
UDPRelay udpRelay = new UDPRelay(this); | |||
_tcpListener = new TCPListener(_config, new List<IStreamService> | |||
{ | |||
tcpRelay, | |||
_pacServer, | |||
new PortForwarder(privoxyRunner.RunningPort), | |||
}); | |||
_tcpListener.Start(); | |||
_udpListener = new UDPListener(_config, new List<IDatagramService> | |||
{ | |||
udpRelay, | |||
}); | |||
_udpListener.Start(); | |||
} | |||
catch (Exception e) | |||
{ | |||
// 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 | |||
if (e is SocketException se) | |||
{ | |||
if (se.SocketErrorCode == SocketError.AddressAlreadyInUse) | |||
{ | |||
e = new Exception(I18N.GetString("Port {0} already in use", _config.localPort), e); | |||
} | |||
else if (se.SocketErrorCode == SocketError.AccessDenied) | |||
{ | |||
e = new Exception(I18N.GetString("Port {0} is reserved by system", _config.localPort), e); | |||
} | |||
} | |||
logger.LogUsefulException(e); | |||
ReportError(e); | |||
} | |||
ConfigChanged?.Invoke(this, new EventArgs()); | |||
UpdateSystemProxy(); | |||
} | |||
protected void SaveConfig(Configuration newConfig) | |||
{ | |||
Configuration.Save(newConfig); | |||
Reload(); | |||
} | |||
protected void ReportError(Exception e) | |||
{ | |||
Errored?.Invoke(this, new ErrorEventArgs(e)); | |||
} | |||
public HttpClient GetHttpClient() => httpClient; | |||
public Server GetCurrentServer() => _config.GetCurrentServer(); | |||
public Configuration GetCurrentConfiguration() => _config; | |||
public Server GetAServer(IStrategyCallerType type, IPEndPoint localIPEndPoint, EndPoint destEndPoint) | |||
{ | |||
IStrategy strategy = GetCurrentStrategy(); | |||
if (strategy != null) | |||
{ | |||
return strategy.GetAServer(type, localIPEndPoint, destEndPoint); | |||
} | |||
if (_config.index < 0) | |||
{ | |||
_config.index = 0; | |||
} | |||
return GetCurrentServer(); | |||
} | |||
public void SaveServers(List<Server> servers, int localPort, bool portableMode) | |||
{ | |||
_config.configs = servers; | |||
_config.localPort = localPort; | |||
_config.portableMode = portableMode; | |||
Configuration.Save(_config); | |||
} | |||
public void SelectServerIndex(int index) | |||
{ | |||
_config.index = index; | |||
_config.strategy = null; | |||
SaveConfig(_config); | |||
} | |||
public void ToggleShareOverLAN(bool enabled) | |||
{ | |||
_config.shareOverLan = enabled; | |||
SaveConfig(_config); | |||
ShareOverLANStatusChanged?.Invoke(this, new EventArgs()); | |||
} | |||
#endregion | |||
#region OS Proxy | |||
public void ToggleEnable(bool enabled) | |||
{ | |||
_config.enabled = enabled; | |||
SaveConfig(_config); | |||
EnableStatusChanged?.Invoke(this, new EventArgs()); | |||
} | |||
public void ToggleGlobal(bool global) | |||
{ | |||
_config.global = global; | |||
SaveConfig(_config); | |||
EnableGlobalChanged?.Invoke(this, new EventArgs()); | |||
} | |||
public void SaveProxy(ForwardProxyConfig proxyConfig) | |||
{ | |||
_config.proxy = proxyConfig; | |||
SaveConfig(_config); | |||
} | |||
private void UpdateSystemProxy() | |||
{ | |||
SystemProxy.Update(_config, false, _pacServer); | |||
} | |||
#endregion | |||
#region PAC | |||
private void PacDaemon_PACFileChanged(object sender, EventArgs e) | |||
{ | |||
UpdateSystemProxy(); | |||
} | |||
private void PacServer_PACUpdateCompleted(object sender, GeositeResultEventArgs e) | |||
{ | |||
UpdatePACFromGeositeCompleted?.Invoke(this, e); | |||
} | |||
private void PacServer_PACUpdateError(object sender, ErrorEventArgs e) | |||
{ | |||
UpdatePACFromGeositeError?.Invoke(this, e); | |||
} | |||
private static readonly IEnumerable<char> IgnoredLineBegins = new[] { '!', '[' }; | |||
private void PacDaemon_UserRuleFileChanged(object sender, EventArgs e) | |||
{ | |||
GeositeUpdater.MergeAndWritePACFile(_config.geositeDirectGroups, _config.geositeProxiedGroups, _config.geositePreferDirect); | |||
UpdateSystemProxy(); | |||
} | |||
public void CopyPacUrl() | |||
{ | |||
Clipboard.SetDataObject(_pacServer.PacUrl); | |||
} | |||
public void SavePACUrl(string pacUrl) | |||
{ | |||
_config.pacUrl = pacUrl; | |||
SaveConfig(_config); | |||
ConfigChanged?.Invoke(this, new EventArgs()); | |||
} | |||
public void UseOnlinePAC(bool useOnlinePac) | |||
{ | |||
_config.useOnlinePac = useOnlinePac; | |||
SaveConfig(_config); | |||
ConfigChanged?.Invoke(this, new EventArgs()); | |||
} | |||
public void TouchPACFile() | |||
{ | |||
string pacFilename = _pacDaemon.TouchPACFile(); | |||
PACFileReadyToOpen?.Invoke(this, new PathEventArgs() { Path = pacFilename }); | |||
} | |||
public void TouchUserRuleFile() | |||
{ | |||
string userRuleFilename = _pacDaemon.TouchUserRuleFile(); | |||
UserRuleFileReadyToOpen?.Invoke(this, new PathEventArgs() { Path = userRuleFilename }); | |||
} | |||
public void ToggleSecureLocalPac(bool enabled) | |||
{ | |||
_config.secureLocalPac = enabled; | |||
SaveConfig(_config); | |||
ConfigChanged?.Invoke(this, new EventArgs()); | |||
} | |||
public void ToggleRegeneratePacOnUpdate(bool enabled) | |||
{ | |||
_config.regeneratePacOnUpdate = enabled; | |||
SaveConfig(_config); | |||
ConfigChanged?.Invoke(this, new EventArgs()); | |||
} | |||
#endregion | |||
#region SIP002 | |||
public bool AskAddServerBySSURL(string ssURL) | |||
{ | |||
var dr = MessageBox.Show(I18N.GetString("Import from URL: {0} ?", ssURL), I18N.GetString("Shadowsocks"), MessageBoxButtons.YesNo); | |||
if (dr == DialogResult.Yes) | |||
{ | |||
if (AddServerBySSURL(ssURL)) | |||
{ | |||
MessageBox.Show(I18N.GetString("Successfully imported from {0}", ssURL)); | |||
return true; | |||
} | |||
else | |||
{ | |||
MessageBox.Show(I18N.GetString("Failed to import. Please check if the link is valid.")); | |||
} | |||
} | |||
return false; | |||
} | |||
public bool AddServerBySSURL(string ssURL) | |||
{ | |||
try | |||
{ | |||
if (string.IsNullOrWhiteSpace(ssURL)) | |||
return false; | |||
var servers = Server.GetServers(ssURL); | |||
if (servers == null || servers.Count == 0) | |||
return false; | |||
foreach (var server in servers) | |||
{ | |||
_config.configs.Add(server); | |||
} | |||
_config.index = _config.configs.Count - 1; | |||
SaveConfig(_config); | |||
return true; | |||
} | |||
catch (Exception e) | |||
{ | |||
logger.LogUsefulException(e); | |||
return false; | |||
} | |||
} | |||
public string GetServerURLForCurrentServer() | |||
{ | |||
return GetCurrentServer().GetURL(_config.generateLegacyUrl); | |||
} | |||
#endregion | |||
#region Misc | |||
public void ToggleVerboseLogging(bool enabled) | |||
{ | |||
_config.isVerboseLogging = enabled; | |||
SaveConfig(_config); | |||
NLogConfig.LoadConfiguration(); // reload nlog | |||
VerboseLoggingStatusChanged?.Invoke(this, new EventArgs()); | |||
} | |||
public void ToggleCheckingUpdate(bool enabled) | |||
{ | |||
_config.autoCheckUpdate = enabled; | |||
Configuration.Save(_config); | |||
ConfigChanged?.Invoke(this, new EventArgs()); | |||
} | |||
public void ToggleCheckingPreRelease(bool enabled) | |||
{ | |||
_config.checkPreRelease = enabled; | |||
Configuration.Save(_config); | |||
ConfigChanged?.Invoke(this, new EventArgs()); | |||
} | |||
public void SaveSkippedUpdateVerion(string version) | |||
{ | |||
_config.skippedUpdateVersion = version; | |||
Configuration.Save(_config); | |||
} | |||
public void SaveLogViewerConfig(LogViewerConfig newConfig) | |||
{ | |||
_config.logViewer = newConfig; | |||
newConfig.SaveSize(); | |||
Configuration.Save(_config); | |||
ConfigChanged?.Invoke(this, new EventArgs()); | |||
} | |||
public void SaveHotkeyConfig(HotkeyConfig newConfig) | |||
{ | |||
_config.hotkey = newConfig; | |||
SaveConfig(_config); | |||
ConfigChanged?.Invoke(this, new EventArgs()); | |||
} | |||
#endregion | |||
#region Strategy | |||
public void SelectStrategy(string strategyID) | |||
{ | |||
_config.index = -1; | |||
_config.strategy = strategyID; | |||
SaveConfig(_config); | |||
} | |||
public IList<IStrategy> GetStrategies() | |||
{ | |||
return _strategyManager.GetStrategies(); | |||
} | |||
public IStrategy GetCurrentStrategy() | |||
{ | |||
foreach (var strategy in _strategyManager.GetStrategies()) | |||
{ | |||
if (strategy.ID == _config.strategy) | |||
{ | |||
return strategy; | |||
} | |||
} | |||
return null; | |||
} | |||
public void UpdateInboundCounter(object sender, SSTransmitEventArgs args) | |||
{ | |||
GetCurrentStrategy()?.UpdateLastRead(args.server); | |||
Interlocked.Add(ref _inboundCounter, args.length); | |||
} | |||
public void UpdateOutboundCounter(object sender, SSTransmitEventArgs args) | |||
{ | |||
GetCurrentStrategy()?.UpdateLastWrite(args.server); | |||
Interlocked.Add(ref _outboundCounter, args.length); | |||
} | |||
#endregion | |||
#region SIP003 | |||
private void StartPlugin() | |||
{ | |||
var server = _config.GetCurrentServer(); | |||
GetPluginLocalEndPointIfConfigured(server); | |||
} | |||
private void StopPlugins() | |||
{ | |||
foreach (var serverAndPlugin in _pluginsByServer) | |||
{ | |||
serverAndPlugin.Value?.Dispose(); | |||
} | |||
_pluginsByServer.Clear(); | |||
} | |||
public EndPoint GetPluginLocalEndPointIfConfigured(Server server) | |||
{ | |||
var plugin = _pluginsByServer.GetOrAdd( | |||
server, | |||
x => Sip003Plugin.CreateIfConfigured(x, _config.showPluginOutput)); | |||
if (plugin == null) | |||
{ | |||
return null; | |||
} | |||
try | |||
{ | |||
if (plugin.StartIfNeeded()) | |||
{ | |||
logger.Info( | |||
$"Started SIP003 plugin for {server.Identifier()} on {plugin.LocalEndPoint} - PID: {plugin.ProcessId}"); | |||
} | |||
} | |||
catch (Exception ex) | |||
{ | |||
logger.Error("Failed to start SIP003 plugin: " + ex.Message); | |||
throw; | |||
} | |||
return plugin.LocalEndPoint; | |||
} | |||
public void ToggleShowPluginOutput(bool enabled) | |||
{ | |||
_config.showPluginOutput = enabled; | |||
SaveConfig(_config); | |||
ShowPluginOutputChanged?.Invoke(this, new EventArgs()); | |||
} | |||
#endregion | |||
#region Traffic Statistics | |||
private void StartTrafficStatistics(int queueMaxSize) | |||
{ | |||
trafficPerSecondQueue = new Queue<TrafficPerSecond>(); | |||
for (int i = 0; i < queueMaxSize; i++) | |||
{ | |||
trafficPerSecondQueue.Enqueue(new TrafficPerSecond()); | |||
} | |||
_trafficThread = new Thread(new ThreadStart(() => TrafficStatistics(queueMaxSize))) | |||
{ | |||
IsBackground = true | |||
}; | |||
_trafficThread.Start(); | |||
} | |||
private void TrafficStatistics(int queueMaxSize) | |||
{ | |||
TrafficPerSecond previous, current; | |||
while (true) | |||
{ | |||
previous = trafficPerSecondQueue.Last(); | |||
current = new TrafficPerSecond | |||
{ | |||
inboundCounter = InboundCounter, | |||
outboundCounter = OutboundCounter | |||
}; | |||
current.inboundIncreasement = current.inboundCounter - previous.inboundCounter; | |||
current.outboundIncreasement = current.outboundCounter - previous.outboundCounter; | |||
trafficPerSecondQueue.Enqueue(current); | |||
if (trafficPerSecondQueue.Count > queueMaxSize) | |||
trafficPerSecondQueue.Dequeue(); | |||
TrafficChanged?.Invoke(this, new EventArgs()); | |||
Thread.Sleep(1000); | |||
} | |||
} | |||
#endregion | |||
#region SIP008 | |||
public async Task<int> UpdateOnlineConfigInternal(string url) | |||
{ | |||
var onlineServer = await OnlineConfigResolver.GetOnline(url); | |||
_config.configs = Configuration.SortByOnlineConfig( | |||
_config.configs | |||
.Where(c => c.group != url) | |||
.Concat(onlineServer) | |||
); | |||
logger.Info($"updated {onlineServer.Count} server from {url}"); | |||
return onlineServer.Count; | |||
} | |||
public async Task<bool> UpdateOnlineConfig(string url) | |||
{ | |||
var selected = GetCurrentServer(); | |||
try | |||
{ | |||
int count = await UpdateOnlineConfigInternal(url); | |||
} | |||
catch (Exception e) | |||
{ | |||
logger.LogUsefulException(e); | |||
return false; | |||
} | |||
_config.index = _config.configs.IndexOf(selected); | |||
SaveConfig(_config); | |||
return true; | |||
} | |||
public async Task<List<string>> UpdateAllOnlineConfig() | |||
{ | |||
var selected = GetCurrentServer(); | |||
var failedUrls = new List<string>(); | |||
foreach (var url in _config.onlineConfigSource) | |||
{ | |||
try | |||
{ | |||
await UpdateOnlineConfigInternal(url); | |||
} | |||
catch (Exception e) | |||
{ | |||
logger.LogUsefulException(e); | |||
failedUrls.Add(url); | |||
} | |||
} | |||
_config.index = _config.configs.IndexOf(selected); | |||
SaveConfig(_config); | |||
return failedUrls; | |||
} | |||
public void SaveOnlineConfigSource(List<string> sources) | |||
{ | |||
_config.onlineConfigSource = sources; | |||
SaveConfig(_config); | |||
} | |||
public void RemoveOnlineConfig(string url) | |||
{ | |||
_config.onlineConfigSource.RemoveAll(v => v == url); | |||
_config.configs = Configuration.SortByOnlineConfig( | |||
_config.configs.Where(c => c.group != url) | |||
); | |||
SaveConfig(_config); | |||
} | |||
#endregion | |||
} | |||
} |
@@ -1,157 +0,0 @@ | |||
en,ru-RU,zh-CN,zh-TW,ja,ko,fr | |||
#Restart program to apply translation,,,,,, | |||
#This is comment line,,,,,, | |||
#Always keep language name at head of file,,,,,, | |||
#Language name is output in log,,,,,, | |||
"#You can find it by search ""Current language is:""",,,,,, | |||
#Please use UTF-8 with BOM encoding so we can edit it in Excel,,,,,, | |||
,,,,,, | |||
Shadowsocks,Shadowsocks,Shadowsocks,Shadowsocks,Shadowsocks,Shadowsocks,Shadowsocks | |||
,,,,,, | |||
#Menu,,,,,, | |||
,,,,,, | |||
System Proxy,Системный прокси-сервер,系统代理,系統代理,システムプロキシ,시스템 프록시,Proxy système | |||
Disable,Отключен,禁用,禁用,無効,비활성화,Désactiver | |||
PAC,Сценарий настройки (PAC),PAC 模式,PAC 模式,PACモード,프록시 자동 구성 (PAC),PAC | |||
Global,Для всей системы,全局模式,全局模式,グローバルプロキシ,전역,Global | |||
Servers,Серверы,服务器,伺服器,サーバー,서버,Serveurs | |||
Edit Servers...,Редактировать серверы…,编辑服务器...,編輯伺服器...,サーバーの編集...,서버 수정…,Éditer serveurs… | |||
Online Config...,,在线配置...,線上配置...,,, | |||
Start on Boot,Автозагрузка,开机启动,開機啟動,システム起動時に実行,시스템 시작 시에 시작하기,Démarrage automatique | |||
Associate ss:// Links,Ассоциированный ss:// Ссылки,关联 ss:// 链接,關聯 ss:// 鏈接,ss:// リンクの関連付け,ss:// 링크 연결, | |||
Forward Proxy...,Прямой прокси…,正向代理设置...,正向 Proxy 設定...,フォワードプロキシの設定...,포워드 프록시,Forward-proxy… | |||
Allow other Devices to connect,Общий доступ к подключению,允许其他设备连入,允許其他裝置連入,他のデバイスからの接続を許可する,다른 기기에서 연결 허용,Autoriser d'autres appareils à se connecter | |||
Local PAC,Локальный PAC,使用本地 PAC,使用本機 PAC,ローカル PAC,로컬 프록시 자동 구성,PAC local | |||
Online PAC,Удаленный PAC,使用在线 PAC,使用線上 PAC,オンライン PAC,온라인 프록시 자동 구성,PAC en ligne | |||
Edit Local PAC File...,Редактировать локальный PAC…,编辑本地 PAC 文件...,編輯本機 PAC 檔案...,ローカル PAC ファイルの編集...,로컬 프록시 자동 구성 파일 수정,Modifier le fichier PAC local ... | |||
Update Local PAC from Geosite,Обновить локальный PAC из Geosite,从 Geosite 更新本地 PAC,從 Geosite 更新本機 PAC,Geosite からローカル PAC を更新,Geosite에서 로컬 프록시 자동 구성 파일 업데이트,Mettre à jour le PAC local à partir de Geosite | |||
Edit User Rule for Geosite...,Редактировать свои правила для Geosite,编辑 Geosite 的用户规则...,編輯 Geosite 的使用者規則...,ユーザールールの編集...,Geosite 사용자 수정,Modifier la règle utilisateur pour Geosite ... | |||
Secure Local PAC,Безопасный URL локального PAC,保护本地 PAC,安全本機 PAC,ローカル PAC を保護,로컬 프록시 자동 구성 파일 암호화,Sécuriser PAC local | |||
Regenerate local PAC on version update,,版本更新后重新生成本地 PAC,版本更新後重新生成本地 PAC,,, | |||
Copy Local PAC URL,Копировать URL локального PAC,复制本地 PAC 网址,複製本機 PAC 網址,ローカル PAC URL をコピー,로컬 프록시 자동 구성 파일 URL 복사,Copier l'URL du PAC local | |||
Share Server Config...,Поделиться конфигурацией сервера…,分享服务器配置...,分享伺服器設定檔...,サーバーの設定を共有...,서버 설정 공유,Partager la configuration du serveur ... | |||
Scan QRCode from Screen...,Сканировать QRCode с экрана…,扫描屏幕上的二维码...,掃描螢幕上的 QR 碼...,画面から QR コードをスキャン...,화면에서 QR코드 스캔,Scanner le QRCode à partir de l'écran ... | |||
Import URL from Clipboard...,Импорт адреса из буфера обмена…,从剪贴板导入URL...,從剪貼簿匯入 URL...,クリップボードから URL をインポート...,클립보드에서 URL 가져오기…,Importer l'URL du presse-papiers ... | |||
Availability Statistics,Статистика доступности,统计可用性,統計可用性,可用性の統計,가용성 통계,Statistiques de disponibilité | |||
Show Logs...,Показать журнал…,显示日志...,顯示記錄檔...,ログの表示...,로그 보기…,Afficher les journaux ... | |||
Verbose Logging,Подробный журнал,详细记录日志,詳細資訊記錄,詳細なログを記録,자세한 로깅 사용,Journalisation détaillée | |||
Updates...,Обновления…,更新...,更新...,アップデート...,업데이트…,Mettre à jour… | |||
Check for Updates...,Проверить обновления…,检查更新,檢查更新,アップデートを確認...,업데이트 확인하기…,Vérifier les mises à jour ... | |||
Check for Updates at Startup,Проверять при запуске,启动时检查更新,啟動時檢查更新,起動時にアップデートを確認,시스템 시작 시 업데이트 확인하기,Vérifier les mises à jour au démarrage | |||
Check Pre-release Version,Проверять предрелизные версии,检查测试版更新,檢查發行前版本更新,ベータ版のアップデートも確認,개발 버전 업데이트 확인하기,Vérifier la version préliminaire | |||
Edit Hotkeys...,Горячие клавиши…,编辑快捷键...,編輯快速鍵...,ホットキーの編集...,단축키 수정…,Modifier les raccourcis clavier ... | |||
About...,О программе…,关于...,關於...,Shadowsocks について...,정보…,A propos | |||
Help,Помощь,帮助,說明,ヘルプ,도움말,Aide | |||
Quit,Выход,退出,結束,終了,종료,Quitter | |||
Edit Servers,Редактирование серверов,编辑服务器,編輯伺服器,サーバーの編集,서버 수정,Éditer serveurs | |||
Load Balance,Балансировка нагрузки,负载均衡,負載平衡,サーバーロードバランス,로드밸런싱,Répartition de charge | |||
High Availability,Высокая доступность,高可用,高可用性,高可用性,고가용성,Haute disponibilité | |||
Show Plugin Output,События плагинов в журнале,显示插件输出,,プラグインの出力情報を表示,플러그인 출력 보이기,Afficher la sortie du plugin | |||
Write translation template,Создать шаблон для перевода,写入翻译模板,,翻訳テンプレートファイルを書き込む,번역 템플릿 쓰기,Écrire un modèle de traduction | |||
,,,,,, | |||
# Config Form,,,,,, | |||
,,,,,, | |||
Statistics configuration,Настройки статистики,统计配置,,統計の設定,통계 설정,Configuration des statistiques | |||
&Add,Добавить,添加(&A),新增 (&A),新規 (&A),추가 (&A),Ajouter | |||
&Delete,Удалить,删除(&D),移除 (&D),削除 (&D),삭제 (&D),Supprimer | |||
Dupli&cate,Дублир-ть,复制(&C),複製 (&C),コピー (&C),복제 (&C),Dupliquer | |||
Server,Сервер,服务器,伺服器,サーバー,서버,Serveur | |||
Server IP,IP-адрес,服务器地址,伺服器位址,サーバーアドレス,서버 IP,Serveur IP | |||
Server Port,Порт,服务器端口,伺服器連接埠,サーバーポート,서버 포트,Port de serveur | |||
Password,Пароль,密码,密碼,パスワード,비밀번호,Mot de passe | |||
Show Password,Показать пароль,显示密码,顯示密碼,パスワードを表示する,비밀번호 보이기,Montrer le mot de passe | |||
Encryption,Шифрование,加密,加密,暗号化,암호화,Chiffrement | |||
Plugin Program,Плагин,插件程序,外掛程式,プラグインプログラム,플러그인 프로그램,Programme de plugin | |||
Plugin Options,Опции плагина,插件选项,外掛程式選項,プラグインのオプション,플러그인 설정,Options de plugin | |||
Need Plugin Argument,Требуются аргументы,需要命令行参数,,コマンドライン引数を有効にする,플러그인 인자가 필요함,Besoin d'un argument de plugin | |||
Plugin Arguments,Аргументы,插件参数,外掛程式參數,プラグインの引数,플러그인 인자,Arguments du plugin | |||
Proxy Port,Порт прокси,代理端口,Proxy 連接埠,プロキシポート,프록시 포트,Port proxy | |||
Portable Mode,Переносимый режим,便携模式,便攜模式,ポータブルモード,포터블 모드,Mode portable | |||
Restart required,Требуется перезапуск программы,需要重新启动SS,需要重新啟動SS,再起動が必要,재시작이 필요합니다,Redémarrage nécessaire | |||
Remarks,Примечания,备注,註解,付記,알림,Remarques | |||
Timeout(Sec),Таймаут(сек),超时(秒),逾時 (秒),タイムアウト (秒),시간 초과 (초),Délai d'attente(sec) | |||
OK,ОК,确定,確定,OK,확인,OK | |||
Cancel,Отмена,取消,取消,キャンセル,취소,Annuler | |||
Apply,Применить,应用,應用,適用,적용,Appliquer | |||
New server,Новый сервер,未配置的服务器,新伺服器,新規サーバー,새 서버,Nouveau serveur | |||
Move &Up,Выше,上移(&U),上移 (&U),上に移動 (&U),위로 (&U),Monter | |||
Move D&own,Ниже,下移(&O),下移 (&O),下に移動 (&O),아래로 (&O),Descendre | |||
deprecated,Устаревшее,不推荐,不推薦,非推奨,더 이상 사용되지 않음,Obsolète | |||
"Encryption method {0} not exist, will replace with {1}",,加密方法{0}不存在,将使用{1}代替,,暗号化方式{0}が存在しません,{1}に置換します,{0} 암호화 방식이 존재하지 않으므로 {1}로 대체될 것입니다.,"Méthode de chiffrement {0} n'existe pas, sera remplacée par {1}" | |||
,,,,,, | |||
# Log Form,,,,,, | |||
,,,,,, | |||
&File,Файл,文件(&F),檔案 (&F),ファイル (&F),파일 (&F),Fichier | |||
&Open Location,Расположение файла,在资源管理器中打开(&O),在檔案總管中開啟 (&O),ファイルの場所を開く (&O),위치 열기 (&O),Ouvrier | |||
E&xit,Выход,退出(&X),結束 (&X),終了 (&X),종료 (&X),Quitter | |||
&View,Вид,视图(&V),檢視 (&V),表示 (&V),보기 (&V),Afficher | |||
&Clear Logs,Очистить журнал,清空日志(&C),清除記錄檔 (&C),ログの削除 (&C),로그 초기화 (&C),Effacer les journaux | |||
Change &Font,Шрифт…,设置字体(&F),變更字型 (&F),フォント (&F),글꼴 변경 (&F),Définir la police | |||
&Wrap Text,Перенос строк,自动换行(&W),自動換行 (&W),右端で折り返す (&W),텍스트 감싸기 (&W),Retour à la ligne | |||
&Top Most,Поверх всех окон,置顶(&T),置頂 (&T),常に最前面に表示 (&T),상단 우선 (Top Most) (&T),Metter en haut | |||
&Show Toolbar,Панель инструментов,显示工具栏(&S),顯示工具列 (&S),ツールバーの表示 (&S),툴바 보여주기 (&S),Afficher la barre d'outils | |||
Log Viewer,Просмотр журнала,日志查看器,記錄檔檢視器,ログビューア,로그 뷰어,Visionneuse de journaux | |||
Inbound,Входящая,入站,輸入,受信,"인바운드 (Rx, 다운로드)",Entrant | |||
Outbound,Исходящая,出站,輸出,送信,"아웃바운드 (Tx, 업로드)",Sortant | |||
,,,,,, | |||
# QRCode Form,,,,,, | |||
,,,,,, | |||
QRCode and URL,QRCode и URL,二维码与 URL,QR 碼與 URL,QR コードと URL,QR코드와 URL,QRCode et URL | |||
,,,,,, | |||
# PAC Url Form,,,,,, | |||
,,,,,, | |||
Edit Online PAC URL,Изменение URL удаленного PAC,编辑在线 PAC 网址,編輯線上 PAC 網址,オンライン PAC URL の編集,온라인 프록시 자동 구성 URL 수정,Modifier l'URL du PAC en ligne | |||
Edit Online PAC URL...,Редактировать URL удаленного PAC…,编辑在线 PAC 网址...,編輯線上 PAC 網址...,オンライン PAC URL の編集...,온라인 프록시 자동 구성 URL 수정…,Modifier l'URL du PAC en ligne ... | |||
Please input PAC Url,Введите URL адрес для PAC-файла,请输入 PAC 网址,請輸入 PAC 網址,PAC URLを入力して下さい,프록시 자동 구성 URL을 입력하세요,Veuillez saisir l'URL PAC | |||
,,,,,, | |||
# Messages,,,,,, | |||
,,,,,, | |||
Shadowsocks Error: {0},Ошибка Shadowsocks: {0},Shadowsocks 错误: {0},Shadowsocks 錯誤: {0},Shadowsocks エラー: {0},Shadowsocks 오류: {0},Erreur shadowsocks: {0} | |||
Port {0} already in use,Порт {0} уже используется,端口 {0} 已被占用,連接埠號碼 {0} 已被使用,ポート番号 {0} は既に使用されています。,{0}번 포트는 이미 사용 중입니다.,Port {0} déjà utilisé | |||
Port {0} is reserved by system,Порт {0} зарезервирован системой,端口 {0} 是系统保留端口,連接埠號碼 {0} 由系統保留, ポート番号 {0} はシステムによって予約されています,{0}번 포트는 시스템에서 사용 중입니다.,Port {0} réservé par le système | |||
Invalid server address,Неверный адрес сервера,非法服务器地址,無效伺服器位址,サーバーアドレスが無効です。,올바르지 않은 서버 주소입니다.,Adresse de serveur non valide | |||
Illegal port number format,Неверный числовой формат порта,非法端口格式,無效連接埠號碼格式,ポート番号のフォーマットが無効です。,올바르지 않은 포트 번호 형식입니다.,Format de numéro de port illégal | |||
Illegal timeout format,Неверный формат таймаута,非法超时格式,無效逾時格式,タイムアウト値のフォーマットが無効です。,올바르지 않은 시간 초과 형식입니다.,Format de délai d'attente illégal | |||
Server IP can not be blank,IP-адрес сервера не может быть пустым,服务器 IP 不能为空,伺服器 IP 不能為空,サーバー IP が指定されていません。,서버 IP는 비어있으면 안됩니다.,L'adresse IP du serveur ne peut pas être vide | |||
Password can not be blank,Пароль не может быть пустым,密码不能为空,密碼不能為空,パスワードが指定されていません。,비밀번호는 비어있으면 안됩니다.,Le mot de passe ne peut pas être vide | |||
Port out of range,Порт выходит за допустимый диапазон,端口超出范围,連接埠號碼超出範圍,ポート番号は範囲外です。,올바른 포트 범위가 아닙니다.,Port hors de portée | |||
Port can't be 8123,Адрес порта 8123 не может быть использован,端口不能为 8123,連接埠號碼不能為 8123,8123 番以外のポート番号を指定して下さい。,8123번 포트는 사용할 수 없습니다.,Le port ne peut pas être 8123 | |||
No update is available,Обновлений не обнаружено,没有可用的更新,沒有可用的更新,お使いのバージョンは最新です。,사용 가능한 업데이트가 없습니다.,Aucune mise à jour n'est disponible | |||
Shadowsocks is here,Shadowsocks находится здесь,Shadowsocks 在这里,Shadowsocks 在這裡,Shadowsocks はここです。,Shadowsocks는 여기에 있습니다,Veuillez trouver Shadowsocks ici | |||
You can turn on/off Shadowsocks in the context menu,Вы можете управлять Shadowsocks из контекстного меню,可以在右键菜单中开关 Shadowsocks,可以在右鍵選項單中開關 Shadowsocks,コンテキストメニューを使って、Shadowsocks を有効または無効にすることができます。,프로그램 메뉴에서 Shadowsocks를 끄고 켤 수 있습니다.,Vous pouvez activer / désactiver Shadowsocks dans le menu contextuel | |||
System Proxy Enabled,Системный прокси включен,系统代理已启用,系統 Proxy 已啟用,システム プロキシが有効です。,시스템 프록시가 활성화되었습니다.,Proxy système activé | |||
System Proxy Disabled,Системный прокси отключен,系统代理未启用,系統 Proxy 未啟用,システム プロキシが無効です。,시스템 프록시가 비활성화되었습니다.,Proxy système désactivé | |||
Failed to update PAC file ,Не удалось обновить PAC файл,更新 PAC 文件失败,更新 PAC 檔案失敗,PAC の更新に失敗しました。,프록시 자동 구성 파일을 업데이트하는데 실패했습니다.,Impossible de mettre à jour le fichier PAC | |||
PAC updated,PAC файл обновлен,更新 PAC 成功,更新 PAC 成功,PAC を更新しました。,프록시 자동 구성 파일이 업데이트되었습니다.,PAC mis à jour | |||
No updates found. Please report to Geosite if you have problems with it.,Обновлений не найдено. Сообщите авторам Geosite если у вас возникли проблемы.,未发现更新。如有问题请提交给 Geosite。,未發現更新。如有問題請報告至 Geosite。,お使いのバージョンは最新です。問題がある場合は、GFWList に報告して下さい。,사용 가능한 업데이트를 찾지 못했습니다. 문제가 있다면 Geosite로 전송해주세요.,Aucune mise à jour trouvée. Veuillez signaler à Geosite si vous avez des problèmes concernant. | |||
No QRCode found. Try to zoom in or move it to the center of the screen.,QRCode не обнаружен. Попробуйте увеличить изображение или переместить его в центр экрана.,未发现二维码,尝试把它放大或移动到靠近屏幕中间的位置,未發現 QR 碼,嘗試把它放大或移動到靠近熒幕中間的位置,QR コードが見つかりませんでした。コードを大きくするか、画面の中央に移動して下さい。,QR코드를 찾을 수 없습니다. 가운데로 화면을 이동시키거나 확대해보세요.,Aucun QRCode trouvé. Essayez de zoomer ou de le déplacer vers le centre de l'écran. | |||
Shadowsocks is already running.,Shadowsocks уже запущен.,Shadowsocks 已经在运行。,Shadowsocks 已經在執行。,Shadowsocks 実行中,Shadowsocks가 이미 실행 중입니다.,Shadowsocks est déjà en cours d'exécution. | |||
Find Shadowsocks icon in your notify tray.,Значок Shadowsocks можно найти в области уведомлений.,请在任务栏里寻找 Shadowsocks 图标。,請在工作列裡尋找 Shadowsocks 圖示。,通知領域には Shadowsocks のアイコンがあります。,트레이에서 Shadowsocks를 찾아주세요.,Trouvez l'icône Shadowsocks dans votre barre de notification. | |||
"If you want to start multiple Shadowsocks, make a copy in another directory.","Если вы хотите запустить несколько копий Shadowsocks одновременно, создайте отдельную папку на каждую копию.",如果想同时启动多个,可以另外复制一份到别的目录。,如果想同時啟動多個,可以另外複製一份至別的目錄。,複数起動したい場合は、プログラムファイルを別のフォルダーにコピーしてから、もう一度実行して下さい。,"만약 여러 개의 Shadowsocks를 사용하고 싶으시다면, 파일을 다른 곳에 복사해주세요.","Si vous souhaitez démarrer plusieurs Shadowsocks, faites une copie dans un autre répertoire." | |||
Invalid QR Code content: {0},,无效二维码内容: {0},無效二維碼內容: {0},,, | |||
Failed to update registry,Не удалось обновить запись в реестре,无法修改注册表,無法修改登錄檔,レジストリの更新に失敗しました。,레지스트리를 업데이트하는데에 실패했습니다.,Impossible de mettre à jour de la base de registre | |||
Import from URL: {0} ?,импортировать из адреса: {0} ?,从URL导入: {0} ?,從URL匯入: {0} ?,{0}:このURLからインポートしますか?,, | |||
Successfully imported from {0},Успешно импортировано из {0},导入成功:{0},導入成功:{0},{0}:インポートしました。,, | |||
Failed to import. Please check if the link is valid.,,导入失败,请检查链接是否有效。,導入失敗,請檢查鏈接是否有效。,インポートに失敗しました。リンクの有効性を確認してください。,, | |||
System Proxy On: ,Системный прокси:,系统代理已启用:,系統 Proxy 已啟用:,システム プロキシが有効:,시스템 프록시 활성화됨: ,Proxy système activé: | |||
Running: Port {0},Запущен на порту {0},正在运行:端口 {0},正在執行:連接埠號碼 {0},実行中:ポート {0},실행 중: 포트 {0}번,En cours d'exécution: port {0} | |||
"Unexpected error, shadowsocks will exit. Please report to","Непредвиденная ошибка, пожалуйста сообщите на",非预期错误,Shadowsocks将退出。请提交此错误到,非預期錯誤,Shadowsocks 將結束。請報告此錯誤至,予想外のエラーが発生したため、Shadowsocks を終了します。詳しくは下記までお問い合わせ下さい:,알 수 없는 오류로 Shadowsocks가 종료될 것입니다. 오류를 여기로 제보해주세요:,Shadowsocks va quitter en présence d/érreur inattendue. Veuillez signaler à | |||
"Unsupported operating system, use Windows Vista at least.","Операционная система не поддерживается, минимальные системные требования: Windows Vista или выше.",不支持的操作系统版本,最低需求为Windows Vista。,不支援的作業系統版本,最低需求為 Windows Vista。,お使いの OS はサポートされていません。Windows Vista 以降の OS で実行して下さい。,지원하지 않는 운영체제입니다. 최소 Windows Vista가 필요합니다.,"Système d'exploitation incompatible, veuillez utiliser Windows Vista ou ultérieure." | |||
"Unsupported .NET Framework, please update to {0} or later.","Версия .NET Framework не поддерживается, минимальные системные требования: {0} или выше.",当前 .NET Framework 版本过低,请升级至{0}或更新版本。,目前 .NET Framework 版本過低,最低需求為{0}。,お使いの .NET Framework はサポートされていません。{0} 以降のバンジョーをインストールして下さい。,지원하지 않는 .NET 프레임워크입니다. {0} 또는 상위 버전으로 업데이트해주세요.,".NET Framework incompatible, veuillez mettre à jour vers {0} ou ultérieure." | |||
Proxy request failed,Не удалось выполнить запрос,代理请求失败,Proxy 要求失敗,プロキシリクエストが失敗しました。,프록시 요청에 실패했습니다.,Échec de la demande de proxy | |||
Proxy handshake failed,Не удалось выполнить хэндшейк,代理握手失败,Proxy 交握失敗,プロキシ ハンドシェイクに失敗しました。,프록시 핸드쉐이크에 실패했습니다.,Échec de la prise de contact par proxy | |||
Register hotkey failed,Не удалось применить настройки горячих клавиш,注册快捷键失败,註冊快速鍵失敗,ホットキーの登錄に失敗しました。,단축키 등록에 실패했습니다.,Échec de l'enregistrement du raccourci clavier | |||
Cannot parse hotkey: {0},Не удалось распознать следующие горячие клавиши: {0},解析快捷键失败: {0},剖析快速鍵失敗: {0},ホットキーを解析できません: {0},단축키를 해석할 수 없습니다: {0},Impossible d'analyser le raccourci clavier: {0} | |||
"Timeout is invalid, it should not exceed {0}",Таймаут не может превышать значение {0},超时无效,不应超过 {0},逾時無效,不應超過 {0},タイムアウト値が無効です。{0} 以下の値を指定して下さい。,올바르지 않은 시간 초과 설정입니다. {0}을 초과하지 않아야 합니다.,"Le délai d'attente invalide, il ne doit pas dépasser {0}" | |||
Cannot find the plugin program file,Файл плагина не найден,找不到插件程序文件,找不到外掛程式文件,プラグインプログラムが見つかりません,플러그인 프로그램 파일을 찾을 수 없습니다.,Impossible de trouver le fichier du programme du plugin | |||
,,,,,, | |||
Operation failure,Операция завершилась неудачей,操作失败,,操作に失敗しました,작업에 실패했습니다.,Operation failure | |||
Auto save failed,Автоматическое сохранение не удалось,自动保存失败,,オートセーブに失敗しました,자동 저장에 실패했습니다.,Échec de l'enregistrement automatique | |||
Whether to discard unconfigured servers,Внесенные изменения будут утеряны,是否丢弃未配置的服务器,,未設定のサーバーを破棄しますか,구성되지 않은 서버 설정 변경 사항을 폐기하시겠습니까?,Eliminer les serveurs non configurés ou non | |||
"Invalid server address, Cannot automatically save or discard changes",Неверный адрес сервера. Невозможно сохранить или отменить изменения,非法服务器地址,无法自动保存,是否丢弃修改,,サーバーアドレスが無効なため、オートセーブできません。変更を破棄しますか,"서버 주소가 올바르지 않아 자동 저장 할 수 없습니다, 변경 사항을 폐기하시겠습니까?","Adresse de serveur invalide, impossible d'enregistrer ou d'annuler automatiquement les modifications" | |||
"Illegal port number format, Cannot automatically save or discard changes",Неверный числовой адрес порта. Невозможно сохранить или отменить изменения,非法端口格式,无法自动保存,是否丢弃修改,,ポート番号のフォーマットが無効なため、オートセーブできません。変更を破棄しますか,"포트 번호가 올바르지 않아 자동 저장 할 수 없습니다, 변경 사항을 폐기하시겠습니까?","Format de numéro de port illégal, impossible d'enregistrer ou d'annuler automatiquement les modifications" | |||
"Password can not be blank, Cannot automatically save or discard changes",Пароль не может быть пустым. Невозможно сохранить или отменить изменения,密码不能为空,无法自动保存,是否丢弃修改,,サーバーアドレスが無効なため、オートセーブできません。変更を破棄しますか,"비밀번호를 입력하지 않아 자동 저장 할 수 없습니다, 변경 사항을 폐기하시겠습니까?","Le mot de passe ne peut pas être vide, impossible d'enregistrer ou d'annuler automatiquement les modifications" | |||
"Illegal timeout format, Cannot automatically save or discard changes",Неверный формат таймаута. Невозможно сохранить или отменить изменения,非法超时格式,无法自动保存,是否丢弃修改,,パスワードが指定されていないため、オートセーブできません。変更を破棄しますか,시간 초과 형식이 올바르지 않아 자동 저장 할 수 없습니다. 변경 사항을 폐기하시겠습니까?,"Format de délai d'attente illégal, impossible d'enregistrer ou d'annuler automatiquement les modifications" | |||
,,,,タイムアウト値のフォーマットが無効なため、オートセーブできません。変更を破棄しますか,, | |||
"Error occured when process proxy setting, do you want reset current setting and retry?",Произошла ошибка при обработке настроек. Хотите сбросить текущие настройки и попробовать снова?,处理代理设置时发生错误,是否重置当前代理设置并重试?,,プロキシ設定の処理にエラーが発生しました、現在のプロキシ設定をリセットし、再試行してもいいですか,프록시 설정을 처리하는데에 오류가 발생했습니다. 현재 설정을 폐기하고 다시 시도하시겠습니까?,Une erreur s'est produite lors du processus de configuration du proxy. Voulez-vous réinitialiser le paramètre actuel et réessayer? | |||
"Unrecoverable proxy setting error occured, see log for detail","Произошла серьезная ошибка, подробности можно узнать в журналах",发生不可恢复的代理设置错误,查看日志以取得详情,,プロキシ設定に回復不能なエラーが発生しました、ログで詳細をご確認ください,복구 불가능한 프록시 설정 오류가 발생했습니다. 자세한 정보는 로그를 참조하세요.,"Une erreur de paramètre de proxy irrécupérable s'est produite, consultez le journal pour plus de détails" |
@@ -1,382 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.IO; | |||
using System.Linq; | |||
using System.Net; | |||
using System.Windows; | |||
using Newtonsoft.Json; | |||
using NLog; | |||
using Shadowsocks.Controller; | |||
namespace Shadowsocks.Model | |||
{ | |||
[Serializable] | |||
public class Configuration | |||
{ | |||
[JsonIgnore] | |||
private static readonly Logger logger = LogManager.GetCurrentClassLogger(); | |||
public string version; | |||
public List<Server> configs; | |||
public List<string> onlineConfigSource; | |||
// when strategy is set, index is ignored | |||
public string strategy; | |||
public int index; | |||
public bool global; | |||
public bool enabled; | |||
public bool shareOverLan; | |||
public bool firstRun; | |||
public int localPort; | |||
public bool portableMode; | |||
public bool showPluginOutput; | |||
public string pacUrl; | |||
public bool useOnlinePac; | |||
public bool secureLocalPac; // enable secret for PAC server | |||
public bool regeneratePacOnUpdate; // regenerate pac.txt on version update | |||
public bool autoCheckUpdate; | |||
public bool checkPreRelease; | |||
public string skippedUpdateVersion; // skip the update with this version number | |||
public bool isVerboseLogging; | |||
// hidden options | |||
public bool isIPv6Enabled; // for experimental ipv6 support | |||
public bool generateLegacyUrl; // for pre-sip002 url compatibility | |||
public string geositeUrl; // for custom geosite source (and rule group) | |||
public List<string> geositeDirectGroups; // groups of domains that we connect without the proxy | |||
public List<string> geositeProxiedGroups; // groups of domains that we connect via the proxy | |||
public bool geositePreferDirect; // a.k.a blacklist mode | |||
public string userAgent; | |||
//public NLogConfig.LogLevel logLevel; | |||
public LogViewerConfig logViewer; | |||
public ForwardProxyConfig proxy; | |||
public HotkeyConfig hotkey; | |||
[JsonIgnore] | |||
public bool firstRunOnNewVersion; | |||
public Configuration() | |||
{ | |||
version = UpdateChecker.Version; | |||
strategy = ""; | |||
index = 0; | |||
global = false; | |||
enabled = false; | |||
shareOverLan = false; | |||
firstRun = true; | |||
localPort = 1080; | |||
portableMode = true; | |||
showPluginOutput = false; | |||
pacUrl = ""; | |||
useOnlinePac = false; | |||
secureLocalPac = true; | |||
regeneratePacOnUpdate = true; | |||
autoCheckUpdate = false; | |||
checkPreRelease = false; | |||
skippedUpdateVersion = ""; | |||
isVerboseLogging = false; | |||
// hidden options | |||
isIPv6Enabled = false; | |||
generateLegacyUrl = false; | |||
geositeUrl = ""; | |||
geositeDirectGroups = new List<string>() | |||
{ | |||
"private", | |||
"cn", | |||
"geolocation-!cn@cn", | |||
}; | |||
geositeProxiedGroups = new List<string>() | |||
{ | |||
"geolocation-!cn", | |||
}; | |||
geositePreferDirect = false; | |||
userAgent = "ShadowsocksWindows/$version"; | |||
logViewer = new LogViewerConfig(); | |||
proxy = new ForwardProxyConfig(); | |||
hotkey = new HotkeyConfig(); | |||
firstRunOnNewVersion = false; | |||
configs = new List<Server>(); | |||
onlineConfigSource = new List<string>(); | |||
} | |||
[JsonIgnore] | |||
public string userAgentString; // $version substituted with numeral version in it | |||
[JsonIgnore] | |||
NLogConfig nLogConfig; | |||
private static readonly string CONFIG_FILE = "gui-config.json"; | |||
#if DEBUG | |||
private static readonly NLogConfig.LogLevel verboseLogLevel = NLogConfig.LogLevel.Trace; | |||
#else | |||
private static readonly NLogConfig.LogLevel verboseLogLevel = NLogConfig.LogLevel.Debug; | |||
#endif | |||
[JsonIgnore] | |||
public string LocalHost => isIPv6Enabled ? "[::1]" : "127.0.0.1"; | |||
public Server GetCurrentServer() | |||
{ | |||
if (index >= 0 && index < configs.Count) | |||
return configs[index]; | |||
else | |||
return GetDefaultServer(); | |||
} | |||
public WebProxy WebProxy => enabled | |||
? new WebProxy( | |||
isIPv6Enabled | |||
? $"[{IPAddress.IPv6Loopback}]" | |||
: IPAddress.Loopback.ToString(), | |||
localPort) | |||
: null; | |||
/// <summary> | |||
/// Used by multiple forms to validate a server. | |||
/// Communication is done by throwing exceptions. | |||
/// </summary> | |||
/// <param name="server"></param> | |||
public static void CheckServer(Server server) | |||
{ | |||
CheckServer(server.server); | |||
CheckPort(server.server_port); | |||
CheckPassword(server.password); | |||
CheckTimeout(server.timeout, Server.MaxServerTimeoutSec); | |||
} | |||
/// <summary> | |||
/// Loads the configuration from file. | |||
/// </summary> | |||
/// <returns>An Configuration object.</returns> | |||
public static Configuration Load() | |||
{ | |||
Configuration config; | |||
if (File.Exists(CONFIG_FILE)) | |||
{ | |||
try | |||
{ | |||
string configContent = File.ReadAllText(CONFIG_FILE); | |||
config = JsonConvert.DeserializeObject<Configuration>(configContent, new JsonSerializerSettings() | |||
{ | |||
ObjectCreationHandling = ObjectCreationHandling.Replace | |||
}); | |||
return config; | |||
} | |||
catch (Exception e) | |||
{ | |||
if (!(e is FileNotFoundException)) | |||
logger.LogUsefulException(e); | |||
} | |||
} | |||
config = new Configuration(); | |||
return config; | |||
} | |||
/// <summary> | |||
/// Process the loaded configurations and set up things. | |||
/// </summary> | |||
/// <param name="config">A reference of Configuration object.</param> | |||
public static void Process(ref Configuration config) | |||
{ | |||
// Verify if the configured geosite groups exist. | |||
// Reset to default if ANY one of the configured group doesn't exist. | |||
if (!ValidateGeositeGroupList(config.geositeDirectGroups)) | |||
ResetGeositeDirectGroup(ref config.geositeDirectGroups); | |||
if (!ValidateGeositeGroupList(config.geositeProxiedGroups)) | |||
ResetGeositeProxiedGroup(ref config.geositeProxiedGroups); | |||
// Mark the first run of a new version. | |||
var appVersion = new Version(UpdateChecker.Version); | |||
var configVersion = new Version(config.version); | |||
if (appVersion.CompareTo(configVersion) > 0) | |||
{ | |||
config.firstRunOnNewVersion = true; | |||
} | |||
// Add an empty server configuration | |||
if (config.configs.Count == 0) | |||
config.configs.Add(GetDefaultServer()); | |||
// Selected server | |||
if (config.index == -1 && string.IsNullOrEmpty(config.strategy)) | |||
config.index = 0; | |||
if (config.index >= config.configs.Count) | |||
config.index = config.configs.Count - 1; | |||
// Check OS IPv6 support | |||
if (!System.Net.Sockets.Socket.OSSupportsIPv6) | |||
config.isIPv6Enabled = false; | |||
config.proxy.CheckConfig(); | |||
// Replace $version with the version number. | |||
config.userAgentString = config.userAgent.Replace("$version", config.version); | |||
// NLog log level | |||
try | |||
{ | |||
config.nLogConfig = NLogConfig.LoadXML(); | |||
switch (config.nLogConfig.GetLogLevel()) | |||
{ | |||
case NLogConfig.LogLevel.Fatal: | |||
case NLogConfig.LogLevel.Error: | |||
case NLogConfig.LogLevel.Warn: | |||
case NLogConfig.LogLevel.Info: | |||
config.isVerboseLogging = false; | |||
break; | |||
case NLogConfig.LogLevel.Debug: | |||
case NLogConfig.LogLevel.Trace: | |||
config.isVerboseLogging = true; | |||
break; | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
MessageBox.Show($"Cannot get the log level from NLog config file. Please check if the nlog config file exists with corresponding XML nodes.\n{e.Message}"); | |||
} | |||
} | |||
/// <summary> | |||
/// Saves the Configuration object to file. | |||
/// </summary> | |||
/// <param name="config">A Configuration object.</param> | |||
public static void Save(Configuration config) | |||
{ | |||
config.configs = SortByOnlineConfig(config.configs); | |||
FileStream configFileStream = null; | |||
StreamWriter configStreamWriter = null; | |||
try | |||
{ | |||
configFileStream = File.Open(CONFIG_FILE, FileMode.Create); | |||
configStreamWriter = new StreamWriter(configFileStream); | |||
var jsonString = JsonConvert.SerializeObject(config, Formatting.Indented); | |||
configStreamWriter.Write(jsonString); | |||
configStreamWriter.Flush(); | |||
// NLog | |||
config.nLogConfig.SetLogLevel(config.isVerboseLogging ? verboseLogLevel : NLogConfig.LogLevel.Info); | |||
NLogConfig.SaveXML(config.nLogConfig); | |||
} | |||
catch (Exception e) | |||
{ | |||
logger.LogUsefulException(e); | |||
} | |||
finally | |||
{ | |||
if (configStreamWriter != null) | |||
configStreamWriter.Dispose(); | |||
if (configFileStream != null) | |||
configFileStream.Dispose(); | |||
} | |||
} | |||
public static List<Server> SortByOnlineConfig(IEnumerable<Server> servers) | |||
{ | |||
var groups = servers.GroupBy(s => s.group); | |||
List<Server> ret = new List<Server>(); | |||
ret.AddRange(groups.Where(g => string.IsNullOrEmpty(g.Key)).SelectMany(g => g)); | |||
ret.AddRange(groups.Where(g => !string.IsNullOrEmpty(g.Key)).SelectMany(g => g)); | |||
return ret; | |||
} | |||
/// <summary> | |||
/// Validates if the groups in the list are all valid. | |||
/// </summary> | |||
/// <param name="groups">The list of groups to validate.</param> | |||
/// <returns> | |||
/// True if all groups are valid. | |||
/// False if any one of them is invalid. | |||
/// </returns> | |||
public static bool ValidateGeositeGroupList(List<string> groups) | |||
{ | |||
foreach (var geositeGroup in groups) | |||
if (!GeositeUpdater.CheckGeositeGroup(geositeGroup)) // found invalid group | |||
{ | |||
#if DEBUG | |||
logger.Debug($"Available groups:"); | |||
foreach (var group in GeositeUpdater.Geosites.Keys) | |||
logger.Debug($"{group}"); | |||
#endif | |||
logger.Warn($"The Geosite group {geositeGroup} doesn't exist. Resetting to default groups."); | |||
return false; | |||
} | |||
return true; | |||
} | |||
public static void ResetGeositeDirectGroup(ref List<string> geositeDirectGroups) | |||
{ | |||
geositeDirectGroups.Clear(); | |||
geositeDirectGroups.Add("private"); | |||
geositeDirectGroups.Add("cn"); | |||
geositeDirectGroups.Add("geolocation-!cn@cn"); | |||
} | |||
public static void ResetGeositeProxiedGroup(ref List<string> geositeProxiedGroups) | |||
{ | |||
geositeProxiedGroups.Clear(); | |||
geositeProxiedGroups.Add("geolocation-!cn"); | |||
} | |||
public static void ResetUserAgent(Configuration config) | |||
{ | |||
config.userAgent = "ShadowsocksWindows/$version"; | |||
config.userAgentString = config.userAgent.Replace("$version", config.version); | |||
} | |||
public static Server AddDefaultServerOrServer(Configuration config, Server server = null, int? index = null) | |||
{ | |||
if (config?.configs != null) | |||
{ | |||
server = (server ?? GetDefaultServer()); | |||
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; | |||
} | |||
public static Server GetDefaultServer() | |||
{ | |||
return new Server(); | |||
} | |||
public static void CheckPort(int port) | |||
{ | |||
if (port <= 0 || port > 65535) | |||
throw new ArgumentException(I18N.GetString("Port out of range")); | |||
} | |||
public static void CheckLocalPort(int port) | |||
{ | |||
CheckPort(port); | |||
if (port == 8123) | |||
throw new ArgumentException(I18N.GetString("Port can't be 8123")); | |||
} | |||
private static void CheckPassword(string password) | |||
{ | |||
if (string.IsNullOrEmpty(password)) | |||
throw new ArgumentException(I18N.GetString("Password can not be blank")); | |||
} | |||
public static void CheckServer(string server) | |||
{ | |||
if (string.IsNullOrEmpty(server)) | |||
throw new ArgumentException(I18N.GetString("Server IP can not be blank")); | |||
} | |||
public static void CheckTimeout(int timeout, int maxTimeout) | |||
{ | |||
if (timeout <= 0 || timeout > maxTimeout) | |||
throw new ArgumentException( | |||
I18N.GetString("Timeout is invalid, it should not exceed {0}", maxTimeout)); | |||
} | |||
} | |||
} |
@@ -1,215 +0,0 @@ | |||
using System; | |||
using System.Diagnostics; | |||
using System.IO; | |||
using System.IO.Pipes; | |||
using System.Net; | |||
using System.Reflection; | |||
using System.Text; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
using System.Windows.Forms; | |||
using CommandLine; | |||
using Microsoft.Win32; | |||
using NLog; | |||
using ReactiveUI; | |||
using Shadowsocks.Controller; | |||
using Shadowsocks.Controller.Hotkeys; | |||
using Shadowsocks.Util; | |||
using Shadowsocks.View; | |||
using Splat; | |||
using WPFLocalizeExtension.Engine; | |||
namespace Shadowsocks | |||
{ | |||
internal static class Program | |||
{ | |||
private static readonly Logger logger = LogManager.GetCurrentClassLogger(); | |||
public static ShadowsocksController MainController { get; private set; } | |||
public static MenuViewController MenuController { get; private set; } | |||
public static CommandLineOption Options { get; private set; } | |||
public static string[] Args { get; private set; } | |||
// https://github.com/dotnet/runtime/issues/13051#issuecomment-510267727 | |||
public static readonly string ExecutablePath = Process.GetCurrentProcess().MainModule?.FileName; | |||
public static readonly string WorkingDirectory = Path.GetDirectoryName(ExecutablePath); | |||
private static readonly Mutex mutex = new Mutex(true, $"Shadowsocks_{ExecutablePath.GetHashCode()}"); | |||
/// <summary> | |||
/// 应用程序的主入口点。 | |||
/// </summary> | |||
[STAThread] | |||
static void Main(string[] args) | |||
{ | |||
#region Single Instance and IPC | |||
bool hasAnotherInstance = !mutex.WaitOne(TimeSpan.Zero, true); | |||
// store args for further use | |||
Args = args; | |||
Parser.Default.ParseArguments<CommandLineOption>(args) | |||
.WithParsed(opt => Options = opt) | |||
.WithNotParsed(e => e.Output()); | |||
if (hasAnotherInstance) | |||
{ | |||
if (!string.IsNullOrWhiteSpace(Options.OpenUrl)) | |||
{ | |||
IPCService.RequestOpenUrl(Options.OpenUrl); | |||
} | |||
else | |||
{ | |||
MessageBox.Show(I18N.GetString("Find Shadowsocks icon in your notify tray.") | |||
+ Environment.NewLine | |||
+ I18N.GetString("If you want to start multiple Shadowsocks, make a copy in another directory."), | |||
I18N.GetString("Shadowsocks is already running.")); | |||
} | |||
return; | |||
} | |||
#endregion | |||
#region Enviroment Setup | |||
Directory.SetCurrentDirectory(WorkingDirectory); | |||
// todo: initialize the NLog configuartion | |||
Model.NLogConfig.TouchAndApplyNLogConfig(); | |||
#endregion | |||
#region Event Handlers Setup | |||
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); | |||
// handle UI exceptions | |||
Application.ThreadException += Application_ThreadException; | |||
// handle non-UI exceptions | |||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; | |||
Application.ApplicationExit += Application_ApplicationExit; | |||
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; | |||
Application.EnableVisualStyles(); | |||
Application.SetCompatibleTextRenderingDefault(false); | |||
AutoStartup.RegisterForRestart(true); | |||
#endregion | |||
// See https://github.com/dotnet/runtime/issues/13051 | |||
// we have to do this for self-contained executables | |||
Directory.SetCurrentDirectory(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName)); | |||
// We would use this in v5. | |||
// Parameters would have to be dropped from views' constructors (VersionUpdatePromptView) | |||
//Locator.CurrentMutable.RegisterViewsForViewModels(Assembly.GetCallingAssembly()); | |||
// Workaround for hosting WPF controls in a WinForms app. | |||
// We have to manually set the culture for the LocalizeDictionary instance. | |||
// https://stackoverflow.com/questions/374518/localizing-a-winforms-application-with-embedded-wpf-user-controls | |||
// https://stackoverflow.com/questions/14668640/wpf-localize-extension-translate-window-at-run-time | |||
LocalizeDictionary.Instance.Culture = Thread.CurrentThread.CurrentCulture; | |||
#if DEBUG | |||
// truncate privoxy log file while debugging | |||
string privoxyLogFilename = Utils.GetTempPath("privoxy.log"); | |||
if (File.Exists(privoxyLogFilename)) | |||
using (new FileStream(privoxyLogFilename, FileMode.Truncate)) { } | |||
#endif | |||
MainController = new ShadowsocksController(); | |||
MenuController = new MenuViewController(MainController); | |||
HotKeys.Init(MainController); | |||
MainController.Start(); | |||
// Update online config | |||
Task.Run(async () => | |||
{ | |||
await Task.Delay(10 * 1000); | |||
await MainController.UpdateAllOnlineConfig(); | |||
}); | |||
#region IPC Handler and Arguement Process | |||
IPCService ipcService = new IPCService(); | |||
Task.Run(() => ipcService.RunServer()); | |||
ipcService.OpenUrlRequested += (_1, e) => MainController.AskAddServerBySSURL(e.Url); | |||
if (!string.IsNullOrWhiteSpace(Options.OpenUrl)) | |||
{ | |||
MainController.AskAddServerBySSURL(Options.OpenUrl); | |||
} | |||
#endregion | |||
Application.Run(); | |||
} | |||
private static int exited = 0; | |||
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) | |||
{ | |||
if (Interlocked.Increment(ref exited) == 1) | |||
{ | |||
string errMsg = e.ExceptionObject.ToString(); | |||
logger.Error(errMsg); | |||
MessageBox.Show( | |||
$"{I18N.GetString("Unexpected error, shadowsocks will exit. Please report to")} https://github.com/shadowsocks/shadowsocks-windows/issues {Environment.NewLine}{errMsg}", | |||
"Shadowsocks non-UI Error", MessageBoxButtons.OK, MessageBoxIcon.Error); | |||
Application.Exit(); | |||
} | |||
} | |||
private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) | |||
{ | |||
if (Interlocked.Increment(ref exited) == 1) | |||
{ | |||
string errorMsg = $"Exception Detail: {Environment.NewLine}{e.Exception}"; | |||
logger.Error(errorMsg); | |||
MessageBox.Show( | |||
$"{I18N.GetString("Unexpected error, shadowsocks will exit. Please report to")} https://github.com/shadowsocks/shadowsocks-windows/issues {Environment.NewLine}{errorMsg}", | |||
"Shadowsocks UI Error", MessageBoxButtons.OK, MessageBoxIcon.Error); | |||
Application.Exit(); | |||
} | |||
} | |||
private static void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e) | |||
{ | |||
switch (e.Mode) | |||
{ | |||
case PowerModes.Resume: | |||
logger.Info("os wake up"); | |||
if (MainController != null) | |||
{ | |||
Task.Factory.StartNew(() => | |||
{ | |||
Thread.Sleep(10 * 1000); | |||
try | |||
{ | |||
MainController.Start(true); | |||
logger.Info("controller started"); | |||
} | |||
catch (Exception ex) | |||
{ | |||
logger.LogUsefulException(ex); | |||
} | |||
}); | |||
} | |||
break; | |||
case PowerModes.Suspend: | |||
if (MainController != null) | |||
{ | |||
MainController.Stop(); | |||
logger.Info("controller stopped"); | |||
} | |||
logger.Info("os suspend"); | |||
break; | |||
} | |||
} | |||
private static void Application_ApplicationExit(object sender, EventArgs e) | |||
{ | |||
// detach static event handlers | |||
Application.ApplicationExit -= Application_ApplicationExit; | |||
SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged; | |||
Application.ThreadException -= Application_ThreadException; | |||
HotKeys.Destroy(); | |||
if (MainController != null) | |||
{ | |||
MainController.Stop(); | |||
MainController = null; | |||
} | |||
} | |||
} | |||
} |
@@ -1,652 +0,0 @@ | |||
namespace Shadowsocks.View | |||
{ | |||
partial class ConfigForm | |||
{ | |||
/// <summary> | |||
/// Required designer variable. | |||
/// </summary> | |||
private System.ComponentModel.IContainer components = null; | |||
/// <summary> | |||
/// Clean up any resources being used. | |||
/// </summary> | |||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> | |||
protected override void Dispose(bool disposing) | |||
{ | |||
if (disposing && (components != null)) | |||
{ | |||
components.Dispose(); | |||
} | |||
base.Dispose(disposing); | |||
} | |||
#region Windows Form Designer generated code | |||
/// <summary> | |||
/// Required method for Designer support - do not modify | |||
/// the contents of this method with the code editor. | |||
/// </summary> | |||
private void InitializeComponent() | |||
{ | |||
this.components = new System.ComponentModel.Container(); | |||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); | |||
this.PluginOptionsLabel = new System.Windows.Forms.Label(); | |||
this.PluginTextBox = new System.Windows.Forms.TextBox(); | |||
this.RemarksTextBox = new System.Windows.Forms.TextBox(); | |||
this.IPLabel = new System.Windows.Forms.Label(); | |||
this.ServerPortLabel = new System.Windows.Forms.Label(); | |||
this.PasswordLabel = new System.Windows.Forms.Label(); | |||
this.IPTextBox = new System.Windows.Forms.TextBox(); | |||
this.ServerPortTextBox = new System.Windows.Forms.TextBox(); | |||
this.PasswordTextBox = new System.Windows.Forms.TextBox(); | |||
this.EncryptionLabel = new System.Windows.Forms.Label(); | |||
this.EncryptionSelect = new System.Windows.Forms.ComboBox(); | |||
this.TimeoutLabel = new System.Windows.Forms.Label(); | |||
this.TimeoutTextBox = new System.Windows.Forms.TextBox(); | |||
this.PluginLabel = new System.Windows.Forms.Label(); | |||
this.PluginOptionsTextBox = new System.Windows.Forms.TextBox(); | |||
this.ShowPasswdCheckBox = new System.Windows.Forms.CheckBox(); | |||
this.PluginArgumentsTextBox = new System.Windows.Forms.TextBox(); | |||
this.PluginArgumentsLabel = new System.Windows.Forms.Label(); | |||
this.RemarksLabel = new System.Windows.Forms.Label(); | |||
this.NeedPluginArgCheckBox = new System.Windows.Forms.CheckBox(); | |||
this.panel2 = new System.Windows.Forms.Panel(); | |||
this.OKButton = new System.Windows.Forms.Button(); | |||
this.MyCancelButton = new System.Windows.Forms.Button(); | |||
this.ApplyButton = new System.Windows.Forms.Button(); | |||
this.DeleteButton = new System.Windows.Forms.Button(); | |||
this.AddButton = new System.Windows.Forms.Button(); | |||
this.ServerGroupBox = new System.Windows.Forms.GroupBox(); | |||
this.ServersListBox = new System.Windows.Forms.ListBox(); | |||
this.MoveDownButton = new System.Windows.Forms.Button(); | |||
this.MoveUpButton = new System.Windows.Forms.Button(); | |||
this.ProxyPortTextBox = new System.Windows.Forms.TextBox(); | |||
this.ProxyPortLabel = new System.Windows.Forms.Label(); | |||
this.PortableModeCheckBox = new System.Windows.Forms.CheckBox(); | |||
this.DuplicateButton = new System.Windows.Forms.Button(); | |||
this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); | |||
this.tableLayoutPanel7 = new System.Windows.Forms.TableLayoutPanel(); | |||
this.GroupLabel = new System.Windows.Forms.Label(); | |||
this.GroupTextBox = new System.Windows.Forms.TextBox(); | |||
this.tableLayoutPanel1.SuspendLayout(); | |||
this.ServerGroupBox.SuspendLayout(); | |||
this.tableLayoutPanel7.SuspendLayout(); | |||
this.SuspendLayout(); | |||
// | |||
// tableLayoutPanel1 | |||
// | |||
this.tableLayoutPanel1.AutoSize = true; | |||
this.tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; | |||
this.tableLayoutPanel1.ColumnCount = 2; | |||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); | |||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); | |||
this.tableLayoutPanel1.Controls.Add(this.PluginOptionsLabel, 0, 6); | |||
this.tableLayoutPanel1.Controls.Add(this.PluginTextBox, 1, 5); | |||
this.tableLayoutPanel1.Controls.Add(this.RemarksTextBox, 1, 10); | |||
this.tableLayoutPanel1.Controls.Add(this.IPLabel, 0, 0); | |||
this.tableLayoutPanel1.Controls.Add(this.ServerPortLabel, 0, 1); | |||
this.tableLayoutPanel1.Controls.Add(this.PasswordLabel, 0, 2); | |||
this.tableLayoutPanel1.Controls.Add(this.IPTextBox, 1, 0); | |||
this.tableLayoutPanel1.Controls.Add(this.ServerPortTextBox, 1, 1); | |||
this.tableLayoutPanel1.Controls.Add(this.PasswordTextBox, 1, 2); | |||
this.tableLayoutPanel1.Controls.Add(this.EncryptionLabel, 0, 4); | |||
this.tableLayoutPanel1.Controls.Add(this.EncryptionSelect, 1, 4); | |||
this.tableLayoutPanel1.Controls.Add(this.TimeoutLabel, 0, 11); | |||
this.tableLayoutPanel1.Controls.Add(this.TimeoutTextBox, 1, 11); | |||
this.tableLayoutPanel1.Controls.Add(this.PluginLabel, 0, 5); | |||
this.tableLayoutPanel1.Controls.Add(this.PluginOptionsTextBox, 1, 6); | |||
this.tableLayoutPanel1.Controls.Add(this.ShowPasswdCheckBox, 1, 3); | |||
this.tableLayoutPanel1.Controls.Add(this.PluginArgumentsTextBox, 1, 8); | |||
this.tableLayoutPanel1.Controls.Add(this.PluginArgumentsLabel, 0, 8); | |||
this.tableLayoutPanel1.Controls.Add(this.NeedPluginArgCheckBox, 1, 7); | |||
this.tableLayoutPanel1.Controls.Add(this.GroupTextBox, 1, 12); | |||
this.tableLayoutPanel1.Controls.Add(this.GroupLabel, 0, 12); | |||
this.tableLayoutPanel1.Controls.Add(this.RemarksLabel, 0, 10); | |||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.tableLayoutPanel1.Location = new System.Drawing.Point(4, 22); | |||
this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(0); | |||
this.tableLayoutPanel1.Name = "tableLayoutPanel1"; | |||
this.tableLayoutPanel1.Padding = new System.Windows.Forms.Padding(4); | |||
this.tableLayoutPanel1.RowCount = 14; | |||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); | |||
this.tableLayoutPanel1.Size = new System.Drawing.Size(362, 399); | |||
this.tableLayoutPanel1.TabIndex = 0; | |||
// | |||
// PluginOptionsLabel | |||
// | |||
this.PluginOptionsLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; | |||
this.PluginOptionsLabel.AutoSize = true; | |||
this.PluginOptionsLabel.Location = new System.Drawing.Point(24, 199); | |||
this.PluginOptionsLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); | |||
this.PluginOptionsLabel.Name = "PluginOptionsLabel"; | |||
this.PluginOptionsLabel.Size = new System.Drawing.Size(119, 15); | |||
this.PluginOptionsLabel.TabIndex = 6; | |||
this.PluginOptionsLabel.Text = "Plugin Options"; | |||
this.toolTip1.SetToolTip(this.PluginOptionsLabel, "Environment variables for plugin program"); | |||
// | |||
// PluginTextBox | |||
// | |||
this.PluginTextBox.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.PluginTextBox.Location = new System.Drawing.Point(150, 163); | |||
this.PluginTextBox.MaxLength = 256; | |||
this.PluginTextBox.Name = "PluginTextBox"; | |||
this.PluginTextBox.Size = new System.Drawing.Size(205, 25); | |||
this.PluginTextBox.TabIndex = 5; | |||
this.PluginTextBox.WordWrap = false; | |||
// | |||
// RemarksTextBox | |||
// | |||
this.RemarksTextBox.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.RemarksTextBox.Location = new System.Drawing.Point(150, 283); | |||
this.RemarksTextBox.MaxLength = 32; | |||
this.RemarksTextBox.Name = "RemarksTextBox"; | |||
this.RemarksTextBox.Size = new System.Drawing.Size(205, 25); | |||
this.RemarksTextBox.TabIndex = 8; | |||
this.RemarksTextBox.WordWrap = false; | |||
// | |||
// IPLabel | |||
// | |||
this.IPLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; | |||
this.IPLabel.AutoSize = true; | |||
this.IPLabel.Location = new System.Drawing.Point(64, 12); | |||
this.IPLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); | |||
this.IPLabel.Name = "IPLabel"; | |||
this.IPLabel.Size = new System.Drawing.Size(79, 15); | |||
this.IPLabel.TabIndex = 0; | |||
this.IPLabel.Text = "Server IP"; | |||
// | |||
// ServerPortLabel | |||
// | |||
this.ServerPortLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; | |||
this.ServerPortLabel.AutoSize = true; | |||
this.ServerPortLabel.Location = new System.Drawing.Point(48, 43); | |||
this.ServerPortLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); | |||
this.ServerPortLabel.Name = "ServerPortLabel"; | |||
this.ServerPortLabel.Size = new System.Drawing.Size(95, 15); | |||
this.ServerPortLabel.TabIndex = 1; | |||
this.ServerPortLabel.Text = "Server Port"; | |||
// | |||
// PasswordLabel | |||
// | |||
this.PasswordLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; | |||
this.PasswordLabel.AutoSize = true; | |||
this.PasswordLabel.Location = new System.Drawing.Point(72, 74); | |||
this.PasswordLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); | |||
this.PasswordLabel.Name = "PasswordLabel"; | |||
this.PasswordLabel.Size = new System.Drawing.Size(71, 15); | |||
this.PasswordLabel.TabIndex = 2; | |||
this.PasswordLabel.Text = "Password"; | |||
this.PasswordLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; | |||
// | |||
// IPTextBox | |||
// | |||
this.IPTextBox.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.IPTextBox.Location = new System.Drawing.Point(150, 7); | |||
this.IPTextBox.MaxLength = 512; | |||
this.IPTextBox.Name = "IPTextBox"; | |||
this.IPTextBox.Size = new System.Drawing.Size(205, 25); | |||
this.IPTextBox.TabIndex = 0; | |||
this.IPTextBox.WordWrap = false; | |||
// | |||
// ServerPortTextBox | |||
// | |||
this.ServerPortTextBox.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.ServerPortTextBox.Location = new System.Drawing.Point(150, 38); | |||
this.ServerPortTextBox.MaxLength = 10; | |||
this.ServerPortTextBox.Name = "ServerPortTextBox"; | |||
this.ServerPortTextBox.Size = new System.Drawing.Size(205, 25); | |||
this.ServerPortTextBox.TabIndex = 1; | |||
this.ServerPortTextBox.WordWrap = false; | |||
// | |||
// PasswordTextBox | |||
// | |||
this.PasswordTextBox.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.PasswordTextBox.Font = new System.Drawing.Font("Consolas", 9F); | |||
this.PasswordTextBox.Location = new System.Drawing.Point(150, 69); | |||
this.PasswordTextBox.MaxLength = 256; | |||
this.PasswordTextBox.Name = "PasswordTextBox"; | |||
this.PasswordTextBox.Size = new System.Drawing.Size(205, 25); | |||
this.PasswordTextBox.TabIndex = 2; | |||
this.PasswordTextBox.UseSystemPasswordChar = true; | |||
this.PasswordTextBox.WordWrap = false; | |||
// | |||
// EncryptionLabel | |||
// | |||
this.EncryptionLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; | |||
this.EncryptionLabel.AutoSize = true; | |||
this.EncryptionLabel.Location = new System.Drawing.Point(56, 134); | |||
this.EncryptionLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); | |||
this.EncryptionLabel.Name = "EncryptionLabel"; | |||
this.EncryptionLabel.Size = new System.Drawing.Size(87, 15); | |||
this.EncryptionLabel.TabIndex = 4; | |||
this.EncryptionLabel.Text = "Encryption"; | |||
// | |||
// EncryptionSelect | |||
// | |||
this.EncryptionSelect.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.EncryptionSelect.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; | |||
this.EncryptionSelect.FormattingEnabled = true; | |||
this.EncryptionSelect.ImeMode = System.Windows.Forms.ImeMode.NoControl; | |||
this.EncryptionSelect.ItemHeight = 15; | |||
this.EncryptionSelect.Location = new System.Drawing.Point(150, 129); | |||
this.EncryptionSelect.Margin = new System.Windows.Forms.Padding(3, 5, 3, 8); | |||
this.EncryptionSelect.Name = "EncryptionSelect"; | |||
this.EncryptionSelect.Size = new System.Drawing.Size(205, 23); | |||
this.EncryptionSelect.TabIndex = 4; | |||
// | |||
// TimeoutLabel | |||
// | |||
this.TimeoutLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; | |||
this.TimeoutLabel.AutoSize = true; | |||
this.TimeoutLabel.Location = new System.Drawing.Point(40, 319); | |||
this.TimeoutLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); | |||
this.TimeoutLabel.Name = "TimeoutLabel"; | |||
this.TimeoutLabel.RightToLeft = System.Windows.Forms.RightToLeft.No; | |||
this.TimeoutLabel.Size = new System.Drawing.Size(103, 15); | |||
this.TimeoutLabel.TabIndex = 9; | |||
this.TimeoutLabel.Text = "Timeout(Sec)"; | |||
// | |||
// TimeoutTextBox | |||
// | |||
this.TimeoutTextBox.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.TimeoutTextBox.Location = new System.Drawing.Point(150, 314); | |||
this.TimeoutTextBox.MaxLength = 5; | |||
this.TimeoutTextBox.Name = "TimeoutTextBox"; | |||
this.TimeoutTextBox.Size = new System.Drawing.Size(205, 25); | |||
this.TimeoutTextBox.TabIndex = 9; | |||
// | |||
// PluginLabel | |||
// | |||
this.PluginLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; | |||
this.PluginLabel.AutoSize = true; | |||
this.PluginLabel.Location = new System.Drawing.Point(24, 168); | |||
this.PluginLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); | |||
this.PluginLabel.Name = "PluginLabel"; | |||
this.PluginLabel.Size = new System.Drawing.Size(119, 15); | |||
this.PluginLabel.TabIndex = 5; | |||
this.PluginLabel.Text = "Plugin Program"; | |||
// | |||
// PluginOptionsTextBox | |||
// | |||
this.PluginOptionsTextBox.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.PluginOptionsTextBox.Location = new System.Drawing.Point(150, 194); | |||
this.PluginOptionsTextBox.MaxLength = 256; | |||
this.PluginOptionsTextBox.Name = "PluginOptionsTextBox"; | |||
this.PluginOptionsTextBox.Size = new System.Drawing.Size(205, 25); | |||
this.PluginOptionsTextBox.TabIndex = 6; | |||
this.PluginOptionsTextBox.WordWrap = false; | |||
// | |||
// ShowPasswdCheckBox | |||
// | |||
this.ShowPasswdCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | |||
| System.Windows.Forms.AnchorStyles.Left))); | |||
this.ShowPasswdCheckBox.AutoSize = true; | |||
this.ShowPasswdCheckBox.Location = new System.Drawing.Point(151, 101); | |||
this.ShowPasswdCheckBox.Margin = new System.Windows.Forms.Padding(4); | |||
this.ShowPasswdCheckBox.Name = "ShowPasswdCheckBox"; | |||
this.ShowPasswdCheckBox.Size = new System.Drawing.Size(133, 19); | |||
this.ShowPasswdCheckBox.TabIndex = 3; | |||
this.ShowPasswdCheckBox.Text = "Show Password"; | |||
this.ShowPasswdCheckBox.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; | |||
this.ShowPasswdCheckBox.UseVisualStyleBackColor = true; | |||
this.ShowPasswdCheckBox.CheckedChanged += new System.EventHandler(this.ShowPasswdCheckBox_CheckedChanged); | |||
// | |||
// PluginArgumentsTextBox | |||
// | |||
this.PluginArgumentsTextBox.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.PluginArgumentsTextBox.Location = new System.Drawing.Point(150, 252); | |||
this.PluginArgumentsTextBox.MaxLength = 512; | |||
this.PluginArgumentsTextBox.Name = "PluginArgumentsTextBox"; | |||
this.PluginArgumentsTextBox.Size = new System.Drawing.Size(205, 25); | |||
this.PluginArgumentsTextBox.TabIndex = 7; | |||
this.PluginArgumentsTextBox.WordWrap = false; | |||
// | |||
// PluginArgumentsLabel | |||
// | |||
this.PluginArgumentsLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; | |||
this.PluginArgumentsLabel.AutoSize = true; | |||
this.PluginArgumentsLabel.Location = new System.Drawing.Point(8, 257); | |||
this.PluginArgumentsLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); | |||
this.PluginArgumentsLabel.Name = "PluginArgumentsLabel"; | |||
this.PluginArgumentsLabel.Size = new System.Drawing.Size(135, 15); | |||
this.PluginArgumentsLabel.TabIndex = 7; | |||
this.PluginArgumentsLabel.Text = "Plugin Arguments"; | |||
this.toolTip1.SetToolTip(this.PluginArgumentsLabel, "Not a SIP003 standard. Used as CLI arguments.\r\nMandatory:\r\n%SS_LOCAL_HOST%, %SS_L" + | |||
"OCAL_PORT%, %SS_REMOTE_HOST%, %SS_REMOTE_PORT%\r\nOptional:\r\n%SS_PLUGIN_OPTIONS%"); | |||
// | |||
// RemarksLabel | |||
// | |||
this.RemarksLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; | |||
this.RemarksLabel.AutoSize = true; | |||
this.RemarksLabel.Location = new System.Drawing.Point(80, 288); | |||
this.RemarksLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); | |||
this.RemarksLabel.Name = "RemarksLabel"; | |||
this.RemarksLabel.Size = new System.Drawing.Size(63, 15); | |||
this.RemarksLabel.TabIndex = 8; | |||
this.RemarksLabel.Text = "Remarks"; | |||
// | |||
// NeedPluginArgCheckBox | |||
// | |||
this.NeedPluginArgCheckBox.AutoSize = true; | |||
this.NeedPluginArgCheckBox.Location = new System.Drawing.Point(151, 226); | |||
this.NeedPluginArgCheckBox.Margin = new System.Windows.Forms.Padding(4); | |||
this.NeedPluginArgCheckBox.Name = "NeedPluginArgCheckBox"; | |||
this.NeedPluginArgCheckBox.Size = new System.Drawing.Size(189, 19); | |||
this.NeedPluginArgCheckBox.TabIndex = 10; | |||
this.NeedPluginArgCheckBox.Text = "Need Plugin Argument"; | |||
this.NeedPluginArgCheckBox.UseVisualStyleBackColor = true; | |||
this.NeedPluginArgCheckBox.CheckedChanged += new System.EventHandler(this.UsePluginArgCheckBox_CheckedChanged); | |||
// | |||
// panel2 | |||
// | |||
this.panel2.Anchor = System.Windows.Forms.AnchorStyles.Top; | |||
this.panel2.AutoSize = true; | |||
this.panel2.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; | |||
this.panel2.Location = new System.Drawing.Point(190, 229); | |||
this.panel2.Margin = new System.Windows.Forms.Padding(4); | |||
this.panel2.Name = "panel2"; | |||
this.panel2.Size = new System.Drawing.Size(0, 0); | |||
this.panel2.TabIndex = 1; | |||
// | |||
// OKButton | |||
// | |||
this.OKButton.DialogResult = System.Windows.Forms.DialogResult.OK; | |||
this.OKButton.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.OKButton.Location = new System.Drawing.Point(282, 501); | |||
this.OKButton.Name = "OKButton"; | |||
this.OKButton.Size = new System.Drawing.Size(87, 29); | |||
this.OKButton.TabIndex = 17; | |||
this.OKButton.Text = "OK"; | |||
this.OKButton.UseVisualStyleBackColor = true; | |||
this.OKButton.Click += new System.EventHandler(this.OKButton_Click); | |||
// | |||
// MyCancelButton | |||
// | |||
this.MyCancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; | |||
this.MyCancelButton.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.MyCancelButton.Location = new System.Drawing.Point(375, 501); | |||
this.MyCancelButton.Name = "MyCancelButton"; | |||
this.MyCancelButton.Size = new System.Drawing.Size(87, 29); | |||
this.MyCancelButton.TabIndex = 18; | |||
this.MyCancelButton.Text = "Cancel"; | |||
this.MyCancelButton.UseVisualStyleBackColor = true; | |||
this.MyCancelButton.Click += new System.EventHandler(this.CancelButton_Click); | |||
// | |||
// ApplyButton | |||
// | |||
this.ApplyButton.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.ApplyButton.Enabled = false; | |||
this.ApplyButton.Location = new System.Drawing.Point(468, 501); | |||
this.ApplyButton.Name = "ApplyButton"; | |||
this.ApplyButton.Size = new System.Drawing.Size(91, 29); | |||
this.ApplyButton.TabIndex = 19; | |||
this.ApplyButton.Text = "Apply"; | |||
this.ApplyButton.UseVisualStyleBackColor = true; | |||
this.ApplyButton.Click += new System.EventHandler(this.ApplyButton_Click); | |||
// | |||
// DeleteButton | |||
// | |||
this.DeleteButton.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.DeleteButton.Location = new System.Drawing.Point(96, 431); | |||
this.DeleteButton.Name = "DeleteButton"; | |||
this.DeleteButton.Size = new System.Drawing.Size(87, 29); | |||
this.DeleteButton.TabIndex = 13; | |||
this.DeleteButton.Text = "&Delete"; | |||
this.DeleteButton.UseVisualStyleBackColor = true; | |||
this.DeleteButton.Click += new System.EventHandler(this.DeleteButton_Click); | |||
// | |||
// AddButton | |||
// | |||
this.AddButton.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.AddButton.Location = new System.Drawing.Point(3, 431); | |||
this.AddButton.Name = "AddButton"; | |||
this.AddButton.Size = new System.Drawing.Size(87, 29); | |||
this.AddButton.TabIndex = 12; | |||
this.AddButton.Text = "&Add"; | |||
this.AddButton.UseVisualStyleBackColor = true; | |||
this.AddButton.Click += new System.EventHandler(this.AddButton_Click); | |||
// | |||
// ServerGroupBox | |||
// | |||
this.ServerGroupBox.AutoSize = true; | |||
this.ServerGroupBox.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; | |||
this.tableLayoutPanel7.SetColumnSpan(this.ServerGroupBox, 4); | |||
this.ServerGroupBox.Controls.Add(this.tableLayoutPanel1); | |||
this.ServerGroupBox.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.ServerGroupBox.Location = new System.Drawing.Point(189, 0); | |||
this.ServerGroupBox.Margin = new System.Windows.Forms.Padding(3, 0, 3, 3); | |||
this.ServerGroupBox.Name = "ServerGroupBox"; | |||
this.ServerGroupBox.Padding = new System.Windows.Forms.Padding(4); | |||
this.ServerGroupBox.Size = new System.Drawing.Size(370, 425); | |||
this.ServerGroupBox.TabIndex = 0; | |||
this.ServerGroupBox.TabStop = false; | |||
this.ServerGroupBox.Text = "Server"; | |||
// | |||
// ServersListBox | |||
// | |||
this.tableLayoutPanel7.SetColumnSpan(this.ServersListBox, 2); | |||
this.ServersListBox.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.ServersListBox.FormattingEnabled = true; | |||
this.ServersListBox.IntegralHeight = false; | |||
this.ServersListBox.ItemHeight = 15; | |||
this.ServersListBox.Location = new System.Drawing.Point(3, 3); | |||
this.ServersListBox.Name = "ServersListBox"; | |||
this.ServersListBox.Size = new System.Drawing.Size(180, 422); | |||
this.ServersListBox.TabIndex = 11; | |||
this.ServersListBox.SelectedIndexChanged += new System.EventHandler(this.ServersListBox_SelectedIndexChanged); | |||
// | |||
// MoveDownButton | |||
// | |||
this.MoveDownButton.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.MoveDownButton.Location = new System.Drawing.Point(96, 501); | |||
this.MoveDownButton.Name = "MoveDownButton"; | |||
this.MoveDownButton.Size = new System.Drawing.Size(87, 29); | |||
this.MoveDownButton.TabIndex = 16; | |||
this.MoveDownButton.Text = "Move D&own"; | |||
this.MoveDownButton.UseVisualStyleBackColor = true; | |||
this.MoveDownButton.Click += new System.EventHandler(this.MoveDownButton_Click); | |||
// | |||
// MoveUpButton | |||
// | |||
this.MoveUpButton.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.MoveUpButton.Location = new System.Drawing.Point(3, 501); | |||
this.MoveUpButton.Name = "MoveUpButton"; | |||
this.MoveUpButton.Size = new System.Drawing.Size(87, 29); | |||
this.MoveUpButton.TabIndex = 15; | |||
this.MoveUpButton.Text = "Move &Up"; | |||
this.MoveUpButton.UseVisualStyleBackColor = true; | |||
this.MoveUpButton.Click += new System.EventHandler(this.MoveUpButton_Click); | |||
// | |||
// ProxyPortTextBox | |||
// | |||
this.tableLayoutPanel7.SetColumnSpan(this.ProxyPortTextBox, 2); | |||
this.ProxyPortTextBox.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.ProxyPortTextBox.Location = new System.Drawing.Point(283, 432); | |||
this.ProxyPortTextBox.Margin = new System.Windows.Forms.Padding(4); | |||
this.ProxyPortTextBox.MaxLength = 10; | |||
this.ProxyPortTextBox.Name = "ProxyPortTextBox"; | |||
this.ProxyPortTextBox.Size = new System.Drawing.Size(178, 25); | |||
this.ProxyPortTextBox.TabIndex = 10; | |||
this.ProxyPortTextBox.WordWrap = false; | |||
// | |||
// ProxyPortLabel | |||
// | |||
this.ProxyPortLabel.AutoSize = true; | |||
this.ProxyPortLabel.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.ProxyPortLabel.Location = new System.Drawing.Point(190, 428); | |||
this.ProxyPortLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); | |||
this.ProxyPortLabel.Name = "ProxyPortLabel"; | |||
this.ProxyPortLabel.Size = new System.Drawing.Size(85, 35); | |||
this.ProxyPortLabel.TabIndex = 10; | |||
this.ProxyPortLabel.Text = "Proxy Port"; | |||
this.ProxyPortLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight; | |||
// | |||
// PortableModeCheckBox | |||
// | |||
this.PortableModeCheckBox.AutoSize = true; | |||
this.tableLayoutPanel7.SetColumnSpan(this.PortableModeCheckBox, 2); | |||
this.PortableModeCheckBox.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.PortableModeCheckBox.Location = new System.Drawing.Point(283, 467); | |||
this.PortableModeCheckBox.Margin = new System.Windows.Forms.Padding(4); | |||
this.PortableModeCheckBox.Name = "PortableModeCheckBox"; | |||
this.PortableModeCheckBox.Size = new System.Drawing.Size(178, 27); | |||
this.PortableModeCheckBox.TabIndex = 11; | |||
this.PortableModeCheckBox.Text = "Portable Mode"; | |||
this.toolTip1.SetToolTip(this.PortableModeCheckBox, "restart required"); | |||
this.PortableModeCheckBox.UseVisualStyleBackColor = true; | |||
// | |||
// DuplicateButton | |||
// | |||
this.DuplicateButton.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.DuplicateButton.Location = new System.Drawing.Point(3, 466); | |||
this.DuplicateButton.Name = "DuplicateButton"; | |||
this.DuplicateButton.Size = new System.Drawing.Size(87, 29); | |||
this.DuplicateButton.TabIndex = 14; | |||
this.DuplicateButton.Text = "Dupli&cate"; | |||
this.DuplicateButton.UseVisualStyleBackColor = true; | |||
this.DuplicateButton.Click += new System.EventHandler(this.DuplicateButton_Click); | |||
// | |||
// tableLayoutPanel7 | |||
// | |||
this.tableLayoutPanel7.AutoSize = true; | |||
this.tableLayoutPanel7.ColumnCount = 6; | |||
this.tableLayoutPanel7.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); | |||
this.tableLayoutPanel7.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); | |||
this.tableLayoutPanel7.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); | |||
this.tableLayoutPanel7.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); | |||
this.tableLayoutPanel7.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); | |||
this.tableLayoutPanel7.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); | |||
this.tableLayoutPanel7.Controls.Add(this.ApplyButton, 5, 3); | |||
this.tableLayoutPanel7.Controls.Add(this.MyCancelButton, 4, 3); | |||
this.tableLayoutPanel7.Controls.Add(this.OKButton, 3, 3); | |||
this.tableLayoutPanel7.Controls.Add(this.ProxyPortTextBox, 3, 1); | |||
this.tableLayoutPanel7.Controls.Add(this.MoveDownButton, 1, 3); | |||
this.tableLayoutPanel7.Controls.Add(this.ProxyPortLabel, 2, 1); | |||
this.tableLayoutPanel7.Controls.Add(this.MoveUpButton, 0, 3); | |||
this.tableLayoutPanel7.Controls.Add(this.AddButton, 0, 1); | |||
this.tableLayoutPanel7.Controls.Add(this.DeleteButton, 1, 1); | |||
this.tableLayoutPanel7.Controls.Add(this.DuplicateButton, 0, 2); | |||
this.tableLayoutPanel7.Controls.Add(this.ServersListBox, 0, 0); | |||
this.tableLayoutPanel7.Controls.Add(this.ServerGroupBox, 2, 0); | |||
this.tableLayoutPanel7.Controls.Add(this.PortableModeCheckBox, 3, 2); | |||
this.tableLayoutPanel7.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.tableLayoutPanel7.GrowStyle = System.Windows.Forms.TableLayoutPanelGrowStyle.FixedSize; | |||
this.tableLayoutPanel7.Location = new System.Drawing.Point(10, 10); | |||
this.tableLayoutPanel7.Name = "tableLayoutPanel7"; | |||
this.tableLayoutPanel7.RowCount = 4; | |||
this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); | |||
this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel7.Size = new System.Drawing.Size(562, 533); | |||
this.tableLayoutPanel7.TabIndex = 8; | |||
// | |||
// GroupLabel | |||
// | |||
this.GroupLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; | |||
this.GroupLabel.AutoSize = true; | |||
this.GroupLabel.Location = new System.Drawing.Point(96, 350); | |||
this.GroupLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); | |||
this.GroupLabel.Name = "GroupLabel"; | |||
this.GroupLabel.RightToLeft = System.Windows.Forms.RightToLeft.No; | |||
this.GroupLabel.Size = new System.Drawing.Size(47, 15); | |||
this.GroupLabel.TabIndex = 11; | |||
this.GroupLabel.Text = "Group"; | |||
// | |||
// GroupTextBox | |||
// | |||
this.GroupTextBox.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.GroupTextBox.Location = new System.Drawing.Point(150, 345); | |||
this.GroupTextBox.MaxLength = 5; | |||
this.GroupTextBox.Name = "GroupTextBox"; | |||
this.GroupTextBox.ReadOnly = true; | |||
this.GroupTextBox.Size = new System.Drawing.Size(205, 25); | |||
this.GroupTextBox.TabIndex = 12; | |||
// | |||
// ConfigForm | |||
// | |||
this.AcceptButton = this.OKButton; | |||
this.AutoScaleDimensions = new System.Drawing.SizeF(120F, 120F); | |||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; | |||
this.CancelButton = this.MyCancelButton; | |||
this.ClientSize = new System.Drawing.Size(582, 553); | |||
this.Controls.Add(this.tableLayoutPanel7); | |||
this.Controls.Add(this.panel2); | |||
this.Margin = new System.Windows.Forms.Padding(4); | |||
this.MinimizeBox = false; | |||
this.MinimumSize = new System.Drawing.Size(400, 575); | |||
this.Name = "ConfigForm"; | |||
this.Padding = new System.Windows.Forms.Padding(10); | |||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; | |||
this.Text = "Edit Servers"; | |||
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.ConfigForm_FormClosed); | |||
this.Shown += new System.EventHandler(this.ConfigForm_Shown); | |||
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ConfigForm_KeyDown); | |||
this.tableLayoutPanel1.ResumeLayout(false); | |||
this.tableLayoutPanel1.PerformLayout(); | |||
this.ServerGroupBox.ResumeLayout(false); | |||
this.ServerGroupBox.PerformLayout(); | |||
this.tableLayoutPanel7.ResumeLayout(false); | |||
this.tableLayoutPanel7.PerformLayout(); | |||
this.ResumeLayout(false); | |||
this.PerformLayout(); | |||
} | |||
#endregion | |||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; | |||
private System.Windows.Forms.Label IPLabel; | |||
private System.Windows.Forms.Label ServerPortLabel; | |||
private System.Windows.Forms.Label PasswordLabel; | |||
private System.Windows.Forms.TextBox IPTextBox; | |||
private System.Windows.Forms.TextBox ServerPortTextBox; | |||
private System.Windows.Forms.Label EncryptionLabel; | |||
private System.Windows.Forms.ComboBox EncryptionSelect; | |||
private System.Windows.Forms.Panel panel2; | |||
private System.Windows.Forms.Button OKButton; | |||
private System.Windows.Forms.Button MyCancelButton; | |||
private System.Windows.Forms.Button ApplyButton; | |||
private System.Windows.Forms.Button DeleteButton; | |||
private System.Windows.Forms.Button AddButton; | |||
private System.Windows.Forms.GroupBox ServerGroupBox; | |||
private System.Windows.Forms.ListBox ServersListBox; | |||
private System.Windows.Forms.TextBox RemarksTextBox; | |||
private System.Windows.Forms.Label RemarksLabel; | |||
private System.Windows.Forms.TextBox ProxyPortTextBox; | |||
private System.Windows.Forms.Label ProxyPortLabel; | |||
private System.Windows.Forms.Button MoveDownButton; | |||
private System.Windows.Forms.Button MoveUpButton; | |||
private System.Windows.Forms.Button DuplicateButton; | |||
private System.Windows.Forms.Label TimeoutLabel; | |||
private System.Windows.Forms.TextBox TimeoutTextBox; | |||
private System.Windows.Forms.Label PluginOptionsLabel; | |||
private System.Windows.Forms.TextBox PluginTextBox; | |||
private System.Windows.Forms.Label PluginLabel; | |||
private System.Windows.Forms.TextBox PluginOptionsTextBox; | |||
private System.Windows.Forms.CheckBox ShowPasswdCheckBox; | |||
private System.Windows.Forms.TextBox PasswordTextBox; | |||
private System.Windows.Forms.TextBox PluginArgumentsTextBox; | |||
private System.Windows.Forms.Label PluginArgumentsLabel; | |||
private System.Windows.Forms.ToolTip toolTip1; | |||
private System.Windows.Forms.CheckBox PortableModeCheckBox; | |||
private System.Windows.Forms.CheckBox NeedPluginArgCheckBox; | |||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel7; | |||
private System.Windows.Forms.Label GroupLabel; | |||
private System.Windows.Forms.TextBox GroupTextBox; | |||
} | |||
} | |||
@@ -1,552 +0,0 @@ | |||
using Shadowsocks.Controller; | |||
using Shadowsocks.Encryption; | |||
using Shadowsocks.Model; | |||
using Shadowsocks.Properties; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Drawing; | |||
using System.Linq; | |||
using System.Windows.Forms; | |||
namespace Shadowsocks.View | |||
{ | |||
public partial class ConfigForm : Form | |||
{ | |||
private ShadowsocksController controller; | |||
// this is a copy of configuration that we are working on | |||
private Configuration _modifiedConfiguration; | |||
private int _lastSelectedIndex = -1; | |||
private bool isChange = false; | |||
public ConfigForm(ShadowsocksController controller) | |||
{ | |||
Font = SystemFonts.MessageBoxFont; | |||
InitializeComponent(); | |||
EncryptionSelect.Items.AddRange(EncryptorFactory.ListAvaliableCiphers().ToArray()); | |||
PerformLayout(); | |||
UpdateTexts(); | |||
SetupValueChangedListeners(); | |||
Icon = Icon.FromHandle(Resources.ssw128.GetHicon()); | |||
this.controller = controller; | |||
controller.ConfigChanged += Controller_ConfigChanged; | |||
LoadCurrentConfiguration(); | |||
} | |||
private void UpdateTexts() | |||
{ | |||
I18N.TranslateForm(this); | |||
toolTip1.SetToolTip(PortableModeCheckBox, I18N.GetString("Restart required")); | |||
} | |||
private void SetupValueChangedListeners() | |||
{ | |||
IPTextBox.TextChanged += ConfigValueChanged; | |||
ProxyPortTextBox.TextChanged += ConfigValueChanged; | |||
PasswordTextBox.TextChanged += ConfigValueChanged; | |||
EncryptionSelect.SelectedIndexChanged += ConfigValueChanged; | |||
PluginTextBox.TextChanged += ConfigValueChanged; | |||
PluginArgumentsTextBox.TextChanged += ConfigValueChanged; | |||
PluginOptionsTextBox.TextChanged += ConfigValueChanged; | |||
RemarksTextBox.TextChanged += ConfigValueChanged; | |||
TimeoutTextBox.TextChanged += ConfigValueChanged; | |||
PortableModeCheckBox.CheckedChanged += ConfigValueChanged; | |||
ServerPortTextBox.TextChanged += ConfigValueChanged; | |||
} | |||
private void Controller_ConfigChanged(object sender, EventArgs e) | |||
{ | |||
LoadCurrentConfiguration(); | |||
} | |||
private void ConfigValueChanged(object sender, EventArgs e) | |||
{ | |||
isChange = true; | |||
ApplyButton.Enabled = true; | |||
} | |||
private bool ValidateAndSaveSelectedServerDetails(bool isSave = false, bool isCopy = false) | |||
{ | |||
try | |||
{ | |||
if (_lastSelectedIndex == -1 || _lastSelectedIndex >= _modifiedConfiguration.configs.Count) | |||
{ | |||
return true; | |||
} | |||
bool verify = GetServerDetailsFromUI(out Server server, isSave, isCopy); | |||
if (server != null) | |||
{ | |||
if (isSave || isCopy) | |||
Configuration.CheckServer(server); | |||
_modifiedConfiguration.configs[_lastSelectedIndex] = server; | |||
} | |||
return verify; | |||
} | |||
catch (Exception ex) | |||
{ | |||
MessageBox.Show(ex.Message); | |||
} | |||
return false; | |||
} | |||
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 = ((CipherInfo)EncryptionSelect.SelectedItem).Name, | |||
plugin = PluginTextBox.Text, | |||
plugin_opts = PluginOptionsTextBox.Text, | |||
plugin_args = PluginArgumentsTextBox.Text, | |||
remarks = RemarksTextBox.Text, | |||
timeout = timeout.Value, | |||
group = GroupTextBox.Text | |||
}; | |||
return true; | |||
} | |||
if (checkIP == null || checkPort == null || checkTimeout == null) | |||
{ | |||
_modifiedConfiguration.configs.RemoveAt(_lastSelectedIndex); | |||
ServersListBox.SelectedIndexChanged -= ServersListBox_SelectedIndexChanged; | |||
int lastIndex = ServersListBox.SelectedIndex; | |||
LoadServerNameListToUI(_modifiedConfiguration); | |||
_lastSelectedIndex = (ServersListBox.SelectedIndex = (_lastSelectedIndex == ServersListBox.Items.Count ? lastIndex : lastIndex - 1)); | |||
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 (isChange && !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 (isChange && !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) | |||
{ | |||
password = null; | |||
string outPassword; | |||
if (string.IsNullOrWhiteSpace(outPassword = PasswordTextBox.Text)) | |||
{ | |||
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 (isChange && !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; | |||
} | |||
else | |||
{ | |||
password = outPassword; | |||
} | |||
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 (isChange && !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 | |||
{ | |||
timeout = outTimeout; | |||
} | |||
return true; | |||
} | |||
#endregion | |||
private void LoadSelectedServerDetails() | |||
{ | |||
if (ServersListBox.SelectedIndex >= 0 && ServersListBox.SelectedIndex < _modifiedConfiguration.configs.Count) | |||
{ | |||
Server server = _modifiedConfiguration.configs[ServersListBox.SelectedIndex]; | |||
SetServerDetailsToUI(server); | |||
} | |||
} | |||
private void SetServerDetailsToUI(Server server) | |||
{ | |||
IPTextBox.Text = server.server; | |||
ServerPortTextBox.Text = server.server_port.ToString(); | |||
PasswordTextBox.Text = server.password; | |||
EncryptionSelect.SelectedItem = EncryptorFactory.GetCipherInfo(server.method ?? Server.DefaultMethod); | |||
PluginTextBox.Text = server.plugin; | |||
PluginOptionsTextBox.Text = server.plugin_opts; | |||
PluginArgumentsTextBox.Text = server.plugin_args; | |||
bool showPluginArgInput = !string.IsNullOrEmpty(server.plugin_args); | |||
NeedPluginArgCheckBox.Checked = showPluginArgInput; | |||
ShowHidePluginArgInput(showPluginArgInput); | |||
RemarksTextBox.Text = server.remarks; | |||
TimeoutTextBox.Text = server.timeout.ToString(); | |||
GroupTextBox.Text = server.group; | |||
isChange = false; | |||
} | |||
private void ShowHidePluginArgInput(bool show) | |||
{ | |||
PluginArgumentsTextBox.Visible = show; | |||
PluginArgumentsLabel.Visible = show; | |||
} | |||
private void LoadServerNameListToUI(Configuration configuration) | |||
{ | |||
ServersListBox.Items.Clear(); | |||
foreach (Server server in configuration.configs) | |||
{ | |||
ServersListBox.Items.Add(server.ToString()); | |||
} | |||
} | |||
private void LoadCurrentConfiguration() | |||
{ | |||
_modifiedConfiguration = controller.GetCurrentConfiguration(); | |||
LoadServerNameListToUI(_modifiedConfiguration); | |||
_lastSelectedIndex = _modifiedConfiguration.index; | |||
if (_lastSelectedIndex < 0 || _lastSelectedIndex >= ServersListBox.Items.Count) | |||
{ | |||
_lastSelectedIndex = 0; | |||
} | |||
ServersListBox.SelectedIndex = _lastSelectedIndex; | |||
UpdateButtons(); | |||
LoadSelectedServerDetails(); | |||
ProxyPortTextBox.Text = _modifiedConfiguration.localPort.ToString(); | |||
PortableModeCheckBox.Checked = _modifiedConfiguration.portableMode; | |||
ApplyButton.Enabled = false; | |||
} | |||
private bool SaveValidConfiguration() | |||
{ | |||
if (!ValidateAndSaveSelectedServerDetails(isSave: true)) | |||
{ | |||
return false; | |||
} | |||
int localPort = int.Parse(ProxyPortTextBox.Text); | |||
Configuration.CheckLocalPort(localPort); | |||
_modifiedConfiguration.localPort = localPort; | |||
_modifiedConfiguration.portableMode = PortableModeCheckBox.Checked; | |||
controller.SaveServers(_modifiedConfiguration.configs, _modifiedConfiguration.localPort, _modifiedConfiguration.portableMode); | |||
// SelectedIndex remains valid | |||
// We handled this in event handlers, e.g. Add/DeleteButton, SelectedIndexChanged | |||
// and move operations | |||
controller.SelectServerIndex(ServersListBox.SelectedIndex); | |||
return true; | |||
} | |||
private void ConfigForm_KeyDown(object sender, KeyEventArgs e) | |||
{ | |||
// Sometimes the users may hit enter key by mistake, and the form will close without saving entries. | |||
if (e.KeyCode == Keys.Enter) | |||
{ | |||
SaveValidConfiguration(); | |||
} | |||
} | |||
private void ServersListBox_SelectedIndexChanged(object sender, EventArgs e) | |||
{ | |||
if (!ServersListBox.CanSelect) | |||
{ | |||
return; | |||
} | |||
if (_lastSelectedIndex == ServersListBox.SelectedIndex) | |||
{ | |||
// we are moving back to oldSelectedIndex or doing a force move | |||
return; | |||
} | |||
if (!ValidateAndSaveSelectedServerDetails()) | |||
{ | |||
// why this won't cause stack overflow? | |||
ServersListBox.SelectedIndex = _lastSelectedIndex; | |||
return; | |||
} | |||
if (_lastSelectedIndex >= 0 && _lastSelectedIndex < _modifiedConfiguration.configs.Count) | |||
{ | |||
ServersListBox.Items[_lastSelectedIndex] = _modifiedConfiguration.configs[_lastSelectedIndex].ToString(); | |||
} | |||
UpdateButtons(); | |||
LoadSelectedServerDetails(); | |||
_lastSelectedIndex = ServersListBox.SelectedIndex; | |||
} | |||
private void AddButton_Click(object sender, EventArgs e) | |||
{ | |||
if (ValidateAndSaveSelectedServerDetails(isSave: true)) | |||
{ | |||
Configuration.AddDefaultServerOrServer(_modifiedConfiguration); | |||
LoadServerNameListToUI(_modifiedConfiguration); | |||
_lastSelectedIndex = (ServersListBox.SelectedIndex = _modifiedConfiguration.configs.Count - 1); | |||
} | |||
} | |||
private void DuplicateButton_Click(object sender, EventArgs e) | |||
{ | |||
if (ValidateAndSaveSelectedServerDetails(isCopy: true)) | |||
{ | |||
Server currServer = _modifiedConfiguration.configs[_lastSelectedIndex]; | |||
Configuration.AddDefaultServerOrServer(_modifiedConfiguration, currServer, _lastSelectedIndex + 1); | |||
LoadServerNameListToUI(_modifiedConfiguration); | |||
_lastSelectedIndex = (ServersListBox.SelectedIndex = (_lastSelectedIndex + 1)); | |||
} | |||
} | |||
private void DeleteButton_Click(object sender, EventArgs e) | |||
{ | |||
_modifiedConfiguration.configs.RemoveAt(_lastSelectedIndex); | |||
if (_modifiedConfiguration.configs.Count == 0) | |||
{ | |||
Configuration.AddDefaultServerOrServer(_modifiedConfiguration); | |||
} | |||
LoadServerNameListToUI(_modifiedConfiguration); | |||
ServersListBox.SelectedIndexChanged -= ServersListBox_SelectedIndexChanged; | |||
_lastSelectedIndex = (ServersListBox.SelectedIndex = (_lastSelectedIndex >= _modifiedConfiguration.configs.Count ? (_modifiedConfiguration.configs.Count - 1) : _lastSelectedIndex)); | |||
ServersListBox.SelectedIndexChanged += ServersListBox_SelectedIndexChanged; | |||
LoadSelectedServerDetails(); | |||
UpdateButtons(); | |||
} | |||
private void UpdateButtons() | |||
{ | |||
DeleteButton.Enabled = (ServersListBox.Items.Count > 0); | |||
MoveUpButton.Enabled = (ServersListBox.SelectedIndex > 0); | |||
MoveDownButton.Enabled = (ServersListBox.SelectedIndex < ServersListBox.Items.Count - 1); | |||
} | |||
private void MoveUpButton_Click(object sender, EventArgs e) | |||
{ | |||
if (ServersListBox.SelectedIndex > 0) | |||
{ | |||
MoveConfigItem(-1); // -1 means move backward | |||
} | |||
} | |||
private void MoveDownButton_Click(object sender, EventArgs e) | |||
{ | |||
if (ServersListBox.SelectedIndex < ServersListBox.Items.Count - 1) | |||
{ | |||
MoveConfigItem(+1); // +1 means move forward | |||
} | |||
} | |||
private void MoveConfigItem(int step) | |||
{ | |||
var server = _modifiedConfiguration.configs[_lastSelectedIndex]; | |||
var newIndex = _lastSelectedIndex + step; | |||
_modifiedConfiguration.configs.RemoveAt(_lastSelectedIndex); | |||
_modifiedConfiguration.configs.Insert(newIndex, server); | |||
ServersListBox.BeginUpdate(); | |||
LoadServerNameListToUI(_modifiedConfiguration); | |||
_lastSelectedIndex = newIndex; | |||
ServersListBox.SelectedIndex = newIndex; | |||
ServersListBox.EndUpdate(); | |||
UpdateButtons(); | |||
} | |||
private void OKButton_Click(object sender, EventArgs e) | |||
{ | |||
if (SaveValidConfiguration()) | |||
{ | |||
Close(); | |||
} | |||
} | |||
private void CancelButton_Click(object sender, EventArgs e) | |||
{ | |||
Close(); | |||
} | |||
private void ApplyButton_Click(object sender, EventArgs e) | |||
{ | |||
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) | |||
{ | |||
PasswordTextBox.UseSystemPasswordChar = !ShowPasswdCheckBox.Checked; | |||
} | |||
private void UsePluginArgCheckBox_CheckedChanged(object sender, EventArgs e) | |||
{ | |||
ShowHidePluginArgInput(NeedPluginArgCheckBox.Checked); | |||
} | |||
} | |||
} |
@@ -1,126 +0,0 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<root> | |||
<!-- | |||
Microsoft ResX Schema | |||
Version 2.0 | |||
The primary goals of this format is to allow a simple XML format | |||
that is mostly human readable. The generation and parsing of the | |||
various data types are done through the TypeConverter classes | |||
associated with the data types. | |||
Example: | |||
... ado.net/XML headers & schema ... | |||
<resheader name="resmimetype">text/microsoft-resx</resheader> | |||
<resheader name="version">2.0</resheader> | |||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | |||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | |||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> | |||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | |||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | |||
<value>[base64 mime encoded serialized .NET Framework object]</value> | |||
</data> | |||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | |||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> | |||
<comment>This is a comment</comment> | |||
</data> | |||
There are any number of "resheader" rows that contain simple | |||
name/value pairs. | |||
Each data row contains a name, and value. The row also contains a | |||
type or mimetype. Type corresponds to a .NET class that support | |||
text/value conversion through the TypeConverter architecture. | |||
Classes that don't support this are serialized and stored with the | |||
mimetype set. | |||
The mimetype is used for serialized objects, and tells the | |||
ResXResourceReader how to depersist the object. This is currently not | |||
extensible. For a given mimetype the value must be set accordingly: | |||
Note - application/x-microsoft.net.object.binary.base64 is the format | |||
that the ResXResourceWriter will generate, however the reader can | |||
read any of the formats listed below. | |||
mimetype: application/x-microsoft.net.object.binary.base64 | |||
value : The object must be serialized with | |||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter | |||
: and then encoded with base64 encoding. | |||
mimetype: application/x-microsoft.net.object.soap.base64 | |||
value : The object must be serialized with | |||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | |||
: and then encoded with base64 encoding. | |||
mimetype: application/x-microsoft.net.object.bytearray.base64 | |||
value : The object must be serialized into a byte array | |||
: using a System.ComponentModel.TypeConverter | |||
: and then encoded with base64 encoding. | |||
--> | |||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | |||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> | |||
<xsd:element name="root" msdata:IsDataSet="true"> | |||
<xsd:complexType> | |||
<xsd:choice maxOccurs="unbounded"> | |||
<xsd:element name="metadata"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" use="required" type="xsd:string" /> | |||
<xsd:attribute name="type" type="xsd:string" /> | |||
<xsd:attribute name="mimetype" type="xsd:string" /> | |||
<xsd:attribute ref="xml:space" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="assembly"> | |||
<xsd:complexType> | |||
<xsd:attribute name="alias" type="xsd:string" /> | |||
<xsd:attribute name="name" type="xsd:string" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="data"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> | |||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | |||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | |||
<xsd:attribute ref="xml:space" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="resheader"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" type="xsd:string" use="required" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
</xsd:choice> | |||
</xsd:complexType> | |||
</xsd:element> | |||
</xsd:schema> | |||
<resheader name="resmimetype"> | |||
<value>text/microsoft-resx</value> | |||
</resheader> | |||
<resheader name="version"> | |||
<value>2.0</value> | |||
</resheader> | |||
<resheader name="reader"> | |||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
<resheader name="writer"> | |||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
<metadata name="toolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> | |||
<value>17, 17</value> | |||
</metadata> | |||
<metadata name="toolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> | |||
<value>17, 17</value> | |||
</metadata> | |||
</root> |
@@ -1,100 +0,0 @@ | |||
namespace Shadowsocks.View | |||
{ | |||
partial class InputBox | |||
{ | |||
/// <summary> | |||
/// Required designer variable. | |||
/// </summary> | |||
private System.ComponentModel.IContainer components = null; | |||
/// <summary> | |||
/// Clean up any resources being used. | |||
/// </summary> | |||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> | |||
protected override void Dispose(bool disposing) | |||
{ | |||
if (disposing && (components != null)) | |||
{ | |||
components.Dispose(); | |||
} | |||
base.Dispose(disposing); | |||
} | |||
#region Windows Form Designer generated code | |||
/// <summary> | |||
/// Required method for Designer support - do not modify | |||
/// the contents of this method with the code editor. | |||
/// </summary> | |||
private void InitializeComponent() | |||
{ | |||
this.label1 = new System.Windows.Forms.Label(); | |||
this.textBox1 = new System.Windows.Forms.TextBox(); | |||
this.btnOK = new System.Windows.Forms.Button(); | |||
this.button2 = new System.Windows.Forms.Button(); | |||
this.SuspendLayout(); | |||
// | |||
// label1 | |||
// | |||
this.label1.AutoSize = true; | |||
this.label1.Location = new System.Drawing.Point(12, 9); | |||
this.label1.Name = "label1"; | |||
this.label1.Size = new System.Drawing.Size(55, 15); | |||
this.label1.TabIndex = 0; | |||
this.label1.Text = "label1"; | |||
// | |||
// textBox1 | |||
// | |||
this.textBox1.Location = new System.Drawing.Point(13, 51); | |||
this.textBox1.Name = "textBox1"; | |||
this.textBox1.Size = new System.Drawing.Size(484, 25); | |||
this.textBox1.TabIndex = 1; | |||
// | |||
// btnOK | |||
// | |||
this.btnOK.Location = new System.Drawing.Point(321, 91); | |||
this.btnOK.Name = "btnOK"; | |||
this.btnOK.Size = new System.Drawing.Size(75, 31); | |||
this.btnOK.TabIndex = 2; | |||
this.btnOK.Text = "OK"; | |||
this.btnOK.UseVisualStyleBackColor = true; | |||
// | |||
// button2 | |||
// | |||
this.button2.Location = new System.Drawing.Point(422, 91); | |||
this.button2.Name = "button2"; | |||
this.button2.Size = new System.Drawing.Size(75, 31); | |||
this.button2.TabIndex = 3; | |||
this.button2.Text = "Cancel"; | |||
this.button2.UseVisualStyleBackColor = true; | |||
// | |||
// InputBox | |||
// | |||
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F); | |||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; | |||
this.ClientSize = new System.Drawing.Size(554, 134); | |||
this.Controls.Add(this.button2); | |||
this.Controls.Add(this.btnOK); | |||
this.Controls.Add(this.textBox1); | |||
this.Controls.Add(this.label1); | |||
this.DoubleBuffered = true; | |||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; | |||
this.MaximizeBox = false; | |||
this.MinimizeBox = false; | |||
this.Name = "InputBox"; | |||
this.ShowInTaskbar = false; | |||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; | |||
this.Text = "InputBox"; | |||
this.ResumeLayout(false); | |||
this.PerformLayout(); | |||
} | |||
#endregion | |||
private System.Windows.Forms.Label label1; | |||
private System.Windows.Forms.TextBox textBox1; | |||
private System.Windows.Forms.Button btnOK; | |||
private System.Windows.Forms.Button button2; | |||
} | |||
} |
@@ -1,24 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.ComponentModel; | |||
using System.Data; | |||
using System.Drawing; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using System.Windows.Forms; | |||
namespace Shadowsocks.View | |||
{ | |||
internal partial class InputBox : Form | |||
{ | |||
public InputBox() | |||
{ | |||
InitializeComponent(); | |||
} | |||
internal string Prompt { get { return label1.Text; } set { label1.Text = value; } } | |||
internal string Response { get { return textBox1.Text; } set { textBox1.Text = value; } } | |||
} | |||
} |
@@ -1,120 +0,0 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<root> | |||
<!-- | |||
Microsoft ResX Schema | |||
Version 2.0 | |||
The primary goals of this format is to allow a simple XML format | |||
that is mostly human readable. The generation and parsing of the | |||
various data types are done through the TypeConverter classes | |||
associated with the data types. | |||
Example: | |||
... ado.net/XML headers & schema ... | |||
<resheader name="resmimetype">text/microsoft-resx</resheader> | |||
<resheader name="version">2.0</resheader> | |||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | |||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | |||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> | |||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | |||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | |||
<value>[base64 mime encoded serialized .NET Framework object]</value> | |||
</data> | |||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | |||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> | |||
<comment>This is a comment</comment> | |||
</data> | |||
There are any number of "resheader" rows that contain simple | |||
name/value pairs. | |||
Each data row contains a name, and value. The row also contains a | |||
type or mimetype. Type corresponds to a .NET class that support | |||
text/value conversion through the TypeConverter architecture. | |||
Classes that don't support this are serialized and stored with the | |||
mimetype set. | |||
The mimetype is used for serialized objects, and tells the | |||
ResXResourceReader how to depersist the object. This is currently not | |||
extensible. For a given mimetype the value must be set accordingly: | |||
Note - application/x-microsoft.net.object.binary.base64 is the format | |||
that the ResXResourceWriter will generate, however the reader can | |||
read any of the formats listed below. | |||
mimetype: application/x-microsoft.net.object.binary.base64 | |||
value : The object must be serialized with | |||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter | |||
: and then encoded with base64 encoding. | |||
mimetype: application/x-microsoft.net.object.soap.base64 | |||
value : The object must be serialized with | |||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | |||
: and then encoded with base64 encoding. | |||
mimetype: application/x-microsoft.net.object.bytearray.base64 | |||
value : The object must be serialized into a byte array | |||
: using a System.ComponentModel.TypeConverter | |||
: and then encoded with base64 encoding. | |||
--> | |||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | |||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> | |||
<xsd:element name="root" msdata:IsDataSet="true"> | |||
<xsd:complexType> | |||
<xsd:choice maxOccurs="unbounded"> | |||
<xsd:element name="metadata"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" use="required" type="xsd:string" /> | |||
<xsd:attribute name="type" type="xsd:string" /> | |||
<xsd:attribute name="mimetype" type="xsd:string" /> | |||
<xsd:attribute ref="xml:space" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="assembly"> | |||
<xsd:complexType> | |||
<xsd:attribute name="alias" type="xsd:string" /> | |||
<xsd:attribute name="name" type="xsd:string" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="data"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> | |||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | |||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | |||
<xsd:attribute ref="xml:space" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="resheader"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" type="xsd:string" use="required" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
</xsd:choice> | |||
</xsd:complexType> | |||
</xsd:element> | |||
</xsd:schema> | |||
<resheader name="resmimetype"> | |||
<value>text/microsoft-resx</value> | |||
</resheader> | |||
<resheader name="version"> | |||
<value>2.0</value> | |||
</resheader> | |||
<resheader name="reader"> | |||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
<resheader name="writer"> | |||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
</root> |
@@ -1,332 +0,0 @@ | |||
namespace Shadowsocks.View | |||
{ | |||
partial class LogForm | |||
{ | |||
/// <summary> | |||
/// Required designer variable. | |||
/// </summary> | |||
private System.ComponentModel.IContainer components = null; | |||
/// <summary> | |||
/// Clean up any resources being used. | |||
/// </summary> | |||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> | |||
protected override void Dispose(bool disposing) | |||
{ | |||
if (disposing && (components != null)) | |||
{ | |||
components.Dispose(); | |||
} | |||
base.Dispose(disposing); | |||
} | |||
#region Windows Form Designer generated code | |||
/// <summary> | |||
/// Required method for Designer support - do not modify | |||
/// the contents of this method with the code editor. | |||
/// </summary> | |||
private void InitializeComponent() | |||
{ | |||
this.components = new System.ComponentModel.Container(); | |||
System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea(); | |||
System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend(); | |||
System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series(); | |||
System.Windows.Forms.DataVisualization.Charting.Series series2 = new System.Windows.Forms.DataVisualization.Charting.Series(); | |||
this.LogMessageTextBox = new System.Windows.Forms.TextBox(); | |||
this.MainMenu = new System.Windows.Forms.MenuStrip(); | |||
this.FileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); | |||
this.OpenLocationToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); | |||
this.ExitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); | |||
this.ViewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); | |||
this.ClearLogsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); | |||
this.ChangeFontToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); | |||
this.WrapTextToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); | |||
this.TopMostToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); | |||
this.ToolStripMenuItemSeparater = new System.Windows.Forms.ToolStripMenuItem(); | |||
this.ShowToolbarToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); | |||
this.TopMostCheckBox = new System.Windows.Forms.CheckBox(); | |||
this.ChangeFontButton = new System.Windows.Forms.Button(); | |||
this.ClearLogsButton = new System.Windows.Forms.Button(); | |||
this.WrapTextCheckBox = new System.Windows.Forms.CheckBox(); | |||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); | |||
this.ToolbarFlowLayoutPanel = new System.Windows.Forms.FlowLayoutPanel(); | |||
this.splitContainer1 = new System.Windows.Forms.SplitContainer(); | |||
this.trafficChart = new System.Windows.Forms.DataVisualization.Charting.Chart(); | |||
this.tableLayoutPanel1.SuspendLayout(); | |||
this.ToolbarFlowLayoutPanel.SuspendLayout(); | |||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); | |||
this.splitContainer1.Panel1.SuspendLayout(); | |||
this.splitContainer1.Panel2.SuspendLayout(); | |||
this.splitContainer1.SuspendLayout(); | |||
((System.ComponentModel.ISupportInitialize)(this.trafficChart)).BeginInit(); | |||
this.SuspendLayout(); | |||
// | |||
// LogMessageTextBox | |||
// | |||
this.LogMessageTextBox.BackColor = System.Drawing.Color.Black; | |||
this.LogMessageTextBox.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.LogMessageTextBox.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); | |||
this.LogMessageTextBox.ForeColor = System.Drawing.Color.White; | |||
this.LogMessageTextBox.Location = new System.Drawing.Point(0, 0); | |||
this.LogMessageTextBox.MaxLength = 2147483647; | |||
this.LogMessageTextBox.Multiline = true; | |||
this.LogMessageTextBox.Name = "LogMessageTextBox"; | |||
this.LogMessageTextBox.ReadOnly = true; | |||
this.LogMessageTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both; | |||
this.LogMessageTextBox.Size = new System.Drawing.Size(378, 74); | |||
this.LogMessageTextBox.TabIndex = 0; | |||
// | |||
// MainMenu | |||
// | |||
this.MainMenu.Items.AddRange(new System.Windows.Forms.ToolStripMenuItem[] { | |||
this.FileToolStripMenuItem, | |||
this.ViewToolStripMenuItem}); | |||
// | |||
// FileToolStripMenuItem | |||
// | |||
this.FileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripMenuItem[] { | |||
this.OpenLocationToolStripMenuItem, | |||
this.ExitToolStripMenuItem}); | |||
this.FileToolStripMenuItem.Text = "&File"; | |||
// | |||
// OpenLocationToolStripMenuItem | |||
// | |||
this.OpenLocationToolStripMenuItem.Text = "&Open Location"; | |||
this.OpenLocationToolStripMenuItem.Click += new System.EventHandler(this.OpenLocationToolStripMenuItem_Click); | |||
// | |||
// ExitToolStripMenuItem | |||
// | |||
this.ExitToolStripMenuItem.Text = "E&xit"; | |||
this.ExitToolStripMenuItem.Click += new System.EventHandler(this.ExitToolStripMenuItem_Click); | |||
// | |||
// ViewToolStripMenuItem | |||
// | |||
this.ViewToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripMenuItem[] { | |||
this.ClearLogsToolStripMenuItem, | |||
this.ChangeFontToolStripMenuItem, | |||
this.WrapTextToolStripMenuItem, | |||
this.TopMostToolStripMenuItem, | |||
this.ToolStripMenuItemSeparater, | |||
this.ShowToolbarToolStripMenuItem}); | |||
this.ViewToolStripMenuItem.Text = "&View"; | |||
// | |||
// ClearLogsToolStripMenuItem | |||
// | |||
this.ClearLogsToolStripMenuItem.Text = "&Clear Logs"; | |||
this.ClearLogsToolStripMenuItem.Click += new System.EventHandler(this.ClearLogsToolStripMenuItem_Click); | |||
// | |||
// ChangeFontToolStripMenuItem | |||
// | |||
this.ChangeFontToolStripMenuItem.Text = "Change &Font"; | |||
this.ChangeFontToolStripMenuItem.Click += new System.EventHandler(this.ChangeFontToolStripMenuItem_Click); | |||
// | |||
// WrapTextToolStripMenuItem | |||
// | |||
this.WrapTextToolStripMenuItem.Text = "&Wrap Text"; | |||
this.WrapTextToolStripMenuItem.Click += new System.EventHandler(this.WrapTextToolStripMenuItem_Click); | |||
// | |||
// TopMostToolStripMenuItem | |||
// | |||
this.TopMostToolStripMenuItem.Text = "&Top Most"; | |||
this.TopMostToolStripMenuItem.Click += new System.EventHandler(this.TopMostToolStripMenuItem_Click); | |||
// | |||
// ToolStripMenuItemSeparater | |||
// | |||
this.ToolStripMenuItemSeparater.Text = "-"; | |||
// | |||
// ShowToolbarToolStripMenuItem | |||
// | |||
this.ShowToolbarToolStripMenuItem.Text = "&Show Toolbar"; | |||
this.ShowToolbarToolStripMenuItem.Click += new System.EventHandler(this.ShowToolbarToolStripMenuItem_Click); | |||
// | |||
// TopMostCheckBox | |||
// | |||
this.TopMostCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | |||
| System.Windows.Forms.AnchorStyles.Left))); | |||
this.TopMostCheckBox.AutoSize = true; | |||
this.TopMostCheckBox.Location = new System.Drawing.Point(249, 3); | |||
this.TopMostCheckBox.Name = "TopMostCheckBox"; | |||
this.TopMostCheckBox.Size = new System.Drawing.Size(72, 23); | |||
this.TopMostCheckBox.TabIndex = 3; | |||
this.TopMostCheckBox.Text = "&Top Most"; | |||
this.TopMostCheckBox.UseVisualStyleBackColor = true; | |||
this.TopMostCheckBox.CheckedChanged += new System.EventHandler(this.TopMostCheckBox_CheckedChanged); | |||
// | |||
// ChangeFontButton | |||
// | |||
this.ChangeFontButton.AutoSize = true; | |||
this.ChangeFontButton.Location = new System.Drawing.Point(84, 3); | |||
this.ChangeFontButton.Name = "ChangeFontButton"; | |||
this.ChangeFontButton.Size = new System.Drawing.Size(75, 23); | |||
this.ChangeFontButton.TabIndex = 2; | |||
this.ChangeFontButton.Text = "&Font"; | |||
this.ChangeFontButton.UseVisualStyleBackColor = true; | |||
this.ChangeFontButton.Click += new System.EventHandler(this.ChangeFontButton_Click); | |||
// | |||
// ClearLogsButton | |||
// | |||
this.ClearLogsButton.AutoSize = true; | |||
this.ClearLogsButton.Location = new System.Drawing.Point(3, 3); | |||
this.ClearLogsButton.Name = "ClearLogsButton"; | |||
this.ClearLogsButton.Size = new System.Drawing.Size(75, 23); | |||
this.ClearLogsButton.TabIndex = 1; | |||
this.ClearLogsButton.Text = "&Clear Logs"; | |||
this.ClearLogsButton.UseVisualStyleBackColor = true; | |||
this.ClearLogsButton.Click += new System.EventHandler(this.ClearLogsButton_Click); | |||
// | |||
// WrapTextCheckBox | |||
// | |||
this.WrapTextCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | |||
| System.Windows.Forms.AnchorStyles.Left))); | |||
this.WrapTextCheckBox.AutoSize = true; | |||
this.WrapTextCheckBox.Location = new System.Drawing.Point(165, 3); | |||
this.WrapTextCheckBox.Name = "WrapTextCheckBox"; | |||
this.WrapTextCheckBox.Size = new System.Drawing.Size(78, 23); | |||
this.WrapTextCheckBox.TabIndex = 0; | |||
this.WrapTextCheckBox.Text = "&Wrap Text"; | |||
this.WrapTextCheckBox.UseVisualStyleBackColor = true; | |||
this.WrapTextCheckBox.CheckedChanged += new System.EventHandler(this.WrapTextCheckBox_CheckedChanged); | |||
// | |||
// tableLayoutPanel1 | |||
// | |||
this.tableLayoutPanel1.ColumnCount = 1; | |||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); | |||
this.tableLayoutPanel1.Controls.Add(this.ToolbarFlowLayoutPanel, 0, 0); | |||
this.tableLayoutPanel1.Controls.Add(this.splitContainer1, 0, 1); | |||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); | |||
this.tableLayoutPanel1.Name = "tableLayoutPanel1"; | |||
this.tableLayoutPanel1.RowCount = 2; | |||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); | |||
this.tableLayoutPanel1.Size = new System.Drawing.Size(384, 161); | |||
this.tableLayoutPanel1.TabIndex = 2; | |||
// | |||
// ToolbarFlowLayoutPanel | |||
// | |||
this.ToolbarFlowLayoutPanel.AutoSize = true; | |||
this.ToolbarFlowLayoutPanel.Controls.Add(this.ClearLogsButton); | |||
this.ToolbarFlowLayoutPanel.Controls.Add(this.ChangeFontButton); | |||
this.ToolbarFlowLayoutPanel.Controls.Add(this.WrapTextCheckBox); | |||
this.ToolbarFlowLayoutPanel.Controls.Add(this.TopMostCheckBox); | |||
this.ToolbarFlowLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.ToolbarFlowLayoutPanel.Location = new System.Drawing.Point(3, 3); | |||
this.ToolbarFlowLayoutPanel.Name = "ToolbarFlowLayoutPanel"; | |||
this.ToolbarFlowLayoutPanel.Size = new System.Drawing.Size(378, 29); | |||
this.ToolbarFlowLayoutPanel.TabIndex = 2; | |||
// | |||
// splitContainer1 | |||
// | |||
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; | |||
this.splitContainer1.Location = new System.Drawing.Point(3, 38); | |||
this.splitContainer1.Name = "splitContainer1"; | |||
this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal; | |||
// | |||
// splitContainer1.Panel1 | |||
// | |||
this.splitContainer1.Panel1.Controls.Add(this.LogMessageTextBox); | |||
// | |||
// splitContainer1.Panel2 | |||
// | |||
this.splitContainer1.Panel2.Controls.Add(this.trafficChart); | |||
this.splitContainer1.Size = new System.Drawing.Size(378, 120); | |||
this.splitContainer1.SplitterDistance = 74; | |||
this.splitContainer1.TabIndex = 3; | |||
// | |||
// trafficChart | |||
// | |||
chartArea1.AxisX.LabelStyle.Enabled = false; | |||
chartArea1.AxisX.MajorGrid.Interval = 5D; | |||
chartArea1.AxisX.MajorGrid.LineColor = System.Drawing.Color.LightGray; | |||
chartArea1.AxisX.MajorTickMark.Enabled = false; | |||
chartArea1.AxisX.Maximum = 61D; | |||
chartArea1.AxisX.Minimum = 1D; | |||
chartArea1.AxisY.IntervalAutoMode = System.Windows.Forms.DataVisualization.Charting.IntervalAutoMode.VariableCount; | |||
chartArea1.AxisY.LabelAutoFitMaxFontSize = 8; | |||
chartArea1.AxisY.LabelStyle.Interval = 0D; | |||
chartArea1.AxisY.MajorGrid.LineColor = System.Drawing.Color.LightGray; | |||
chartArea1.AxisY.MajorTickMark.Enabled = false; | |||
chartArea1.AxisY2.MajorGrid.LineColor = System.Drawing.Color.LightGray; | |||
chartArea1.AxisY2.Minimum = 0D; | |||
chartArea1.Name = "ChartArea1"; | |||
this.trafficChart.ChartAreas.Add(chartArea1); | |||
this.trafficChart.Dock = System.Windows.Forms.DockStyle.Fill; | |||
legend1.MaximumAutoSize = 25F; | |||
legend1.Name = "Legend1"; | |||
this.trafficChart.Legends.Add(legend1); | |||
this.trafficChart.Location = new System.Drawing.Point(0, 0); | |||
this.trafficChart.Name = "trafficChart"; | |||
this.trafficChart.Palette = System.Windows.Forms.DataVisualization.Charting.ChartColorPalette.None; | |||
series1.BorderWidth = 2; | |||
series1.ChartArea = "ChartArea1"; | |||
series1.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Spline; | |||
series1.Color = System.Drawing.Color.FromArgb(255, 128, 0); | |||
series1.IsXValueIndexed = true; | |||
series1.Legend = "Legend1"; | |||
series1.Name = "Inbound"; | |||
series2.BorderWidth = 2; | |||
series2.ChartArea = "ChartArea1"; | |||
series2.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Spline; | |||
series2.Color = System.Drawing.Color.FromArgb(128, 128, 255); | |||
series2.IsXValueIndexed = true; | |||
series2.Legend = "Legend1"; | |||
series2.Name = "Outbound"; | |||
this.trafficChart.Series.Add(series1); | |||
this.trafficChart.Series.Add(series2); | |||
this.trafficChart.Size = new System.Drawing.Size(378, 42); | |||
this.trafficChart.TabIndex = 0; | |||
this.trafficChart.Text = "chart1"; | |||
// | |||
// LogForm | |||
// | |||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); | |||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; | |||
this.ClientSize = new System.Drawing.Size(384, 161); | |||
this.Controls.Add(this.tableLayoutPanel1); | |||
this.MainMenuStrip = this.MainMenu; | |||
this.MinimumSize = new System.Drawing.Size(400, 200); | |||
this.Name = "LogForm"; | |||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; | |||
this.Text = "Log Viewer"; | |||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.LogForm_FormClosing); | |||
this.Load += new System.EventHandler(this.LogForm_Load); | |||
this.Shown += new System.EventHandler(this.LogForm_Shown); | |||
this.tableLayoutPanel1.ResumeLayout(false); | |||
this.tableLayoutPanel1.PerformLayout(); | |||
this.ToolbarFlowLayoutPanel.ResumeLayout(false); | |||
this.ToolbarFlowLayoutPanel.PerformLayout(); | |||
this.splitContainer1.Panel1.ResumeLayout(false); | |||
this.splitContainer1.Panel1.PerformLayout(); | |||
this.splitContainer1.Panel2.ResumeLayout(false); | |||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); | |||
this.splitContainer1.ResumeLayout(false); | |||
((System.ComponentModel.ISupportInitialize)(this.trafficChart)).EndInit(); | |||
this.ResumeLayout(false); | |||
} | |||
#endregion | |||
private System.Windows.Forms.TextBox LogMessageTextBox; | |||
private System.Windows.Forms.MenuStrip MainMenu; | |||
private System.Windows.Forms.ToolStripMenuItem FileToolStripMenuItem; | |||
private System.Windows.Forms.ToolStripMenuItem OpenLocationToolStripMenuItem; | |||
private System.Windows.Forms.ToolStripMenuItem ExitToolStripMenuItem; | |||
private System.Windows.Forms.CheckBox WrapTextCheckBox; | |||
private System.Windows.Forms.Button ClearLogsButton; | |||
private System.Windows.Forms.Button ChangeFontButton; | |||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; | |||
private System.Windows.Forms.CheckBox TopMostCheckBox; | |||
private System.Windows.Forms.ToolStripMenuItem ViewToolStripMenuItem; | |||
private System.Windows.Forms.ToolStripMenuItem ClearLogsToolStripMenuItem; | |||
private System.Windows.Forms.ToolStripMenuItem ChangeFontToolStripMenuItem; | |||
private System.Windows.Forms.ToolStripMenuItem WrapTextToolStripMenuItem; | |||
private System.Windows.Forms.ToolStripMenuItem TopMostToolStripMenuItem; | |||
private System.Windows.Forms.FlowLayoutPanel ToolbarFlowLayoutPanel; | |||
private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemSeparater; | |||
private System.Windows.Forms.ToolStripMenuItem ShowToolbarToolStripMenuItem; | |||
private System.Windows.Forms.SplitContainer splitContainer1; | |||
private System.Windows.Forms.DataVisualization.Charting.Chart trafficChart; | |||
} | |||
} |
@@ -1,447 +0,0 @@ | |||
using System; | |||
using System.Drawing; | |||
using System.IO; | |||
using System.Windows.Forms; | |||
using System.Windows.Forms.DataVisualization.Charting; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using Shadowsocks.Controller; | |||
using Shadowsocks.Properties; | |||
using Shadowsocks.Model; | |||
using Shadowsocks.Util; | |||
using System.Text; | |||
using NLog; | |||
namespace Shadowsocks.View | |||
{ | |||
public partial class LogForm : Form | |||
{ | |||
private static Logger logger = LogManager.GetCurrentClassLogger(); | |||
long lastOffset; | |||
string filename; | |||
Timer timer; | |||
const int BACK_OFFSET = 65536; | |||
ShadowsocksController controller; | |||
// global traffic update lock, make it static | |||
private static readonly object _lock = new object(); | |||
#region Traffic Chart | |||
Queue<TrafficInfo> trafficInfoQueue = new Queue<TrafficInfo>(); | |||
const int queueMaxLength = 60; | |||
long lastInbound, lastOutbound; | |||
long maxSpeed = 0, lastMaxSpeed = 0; | |||
const long minScale = 50; | |||
BandwidthScaleInfo bandwidthScale; | |||
List<float> inboundPoints = new List<float>(); | |||
List<float> outboundPoints = new List<float>(); | |||
TextAnnotation inboundAnnotation = new TextAnnotation(); | |||
TextAnnotation outboundAnnotation = new TextAnnotation(); | |||
#endregion | |||
public LogForm(ShadowsocksController controller) | |||
{ | |||
this.controller = controller; | |||
InitializeComponent(); | |||
Icon = Icon.FromHandle(Resources.ssw128.GetHicon()); | |||
var nLogConfig = NLogConfig.LoadXML(); | |||
try | |||
{ | |||
this.filename = nLogConfig.GetLogFileName(); | |||
} | |||
catch(Exception) | |||
{ | |||
// failed to get the file name | |||
} | |||
if (string.IsNullOrEmpty(this.filename)) | |||
{ | |||
LogMessageTextBox.AppendText("Cannot get the log file name from NLog config file. Please check if the nlog config file exists with corresponding XML nodes."); | |||
} | |||
LogViewerConfig config = controller.GetCurrentConfiguration().logViewer; | |||
topMostTrigger = config.topMost; | |||
wrapTextTrigger = config.wrapText; | |||
toolbarTrigger = config.toolbarShown; | |||
LogMessageTextBox.BackColor = config.BackgroundColor; | |||
LogMessageTextBox.ForeColor = config.TextColor; | |||
LogMessageTextBox.Font = config.Font; | |||
controller.TrafficChanged += controller_TrafficChanged; | |||
UpdateTexts(); | |||
} | |||
private void UpdateTrafficChart() | |||
{ | |||
lock (_lock) | |||
{ | |||
if (trafficInfoQueue.Count == 0) | |||
return; | |||
inboundPoints.Clear(); | |||
outboundPoints.Clear(); | |||
maxSpeed = 0; | |||
foreach (var trafficInfo in trafficInfoQueue) | |||
{ | |||
inboundPoints.Add(trafficInfo.inbound); | |||
outboundPoints.Add(trafficInfo.outbound); | |||
maxSpeed = Math.Max(maxSpeed, Math.Max(trafficInfo.inbound, trafficInfo.outbound)); | |||
} | |||
lastInbound = trafficInfoQueue.Last().inbound; | |||
lastOutbound = trafficInfoQueue.Last().outbound; | |||
} | |||
if (maxSpeed > 0) | |||
{ | |||
lastMaxSpeed -= lastMaxSpeed / 32; | |||
maxSpeed = Math.Max(minScale, Math.Max(maxSpeed, lastMaxSpeed)); | |||
lastMaxSpeed = maxSpeed; | |||
} | |||
else | |||
{ | |||
maxSpeed = lastMaxSpeed = minScale; | |||
} | |||
bandwidthScale = Utils.GetBandwidthScale(maxSpeed); | |||
// re-scale the original data points, since it is List<float>, .ForEach does not work | |||
inboundPoints = inboundPoints.Select(p => p / bandwidthScale.unit).ToList(); | |||
outboundPoints = outboundPoints.Select(p => p / bandwidthScale.unit).ToList(); | |||
if (trafficChart.IsHandleCreated) | |||
{ | |||
trafficChart.Series["Inbound"].Points.DataBindY(inboundPoints); | |||
trafficChart.Series["Outbound"].Points.DataBindY(outboundPoints); | |||
trafficChart.ChartAreas[0].AxisY.LabelStyle.Format = "{0:0.##} " + bandwidthScale.unitName; | |||
trafficChart.ChartAreas[0].AxisY.Maximum = bandwidthScale.value; | |||
inboundAnnotation.AnchorDataPoint = trafficChart.Series["Inbound"].Points.Last(); | |||
inboundAnnotation.Text = Utils.FormatBandwidth(lastInbound); | |||
outboundAnnotation.AnchorDataPoint = trafficChart.Series["Outbound"].Points.Last(); | |||
outboundAnnotation.Text = Utils.FormatBandwidth(lastOutbound); | |||
trafficChart.Annotations.Clear(); | |||
trafficChart.Annotations.Add(inboundAnnotation); | |||
trafficChart.Annotations.Add(outboundAnnotation); | |||
} | |||
} | |||
private void controller_TrafficChanged(object sender, EventArgs e) | |||
{ | |||
lock (_lock) | |||
{ | |||
if (trafficInfoQueue.Count == 0) | |||
{ | |||
// Init an empty queue | |||
for (int i = 0; i < queueMaxLength; i++) | |||
{ | |||
trafficInfoQueue.Enqueue(new TrafficInfo(0, 0)); | |||
} | |||
foreach (var trafficPerSecond in controller.trafficPerSecondQueue) | |||
{ | |||
trafficInfoQueue.Enqueue(new TrafficInfo(trafficPerSecond.inboundIncreasement, | |||
trafficPerSecond.outboundIncreasement)); | |||
if (trafficInfoQueue.Count > queueMaxLength) | |||
trafficInfoQueue.Dequeue(); | |||
} | |||
} | |||
else | |||
{ | |||
var lastTraffic = controller.trafficPerSecondQueue.Last(); | |||
trafficInfoQueue.Enqueue(new TrafficInfo(lastTraffic.inboundIncreasement, | |||
lastTraffic.outboundIncreasement)); | |||
if (trafficInfoQueue.Count > queueMaxLength) | |||
trafficInfoQueue.Dequeue(); | |||
} | |||
} | |||
} | |||
private void UpdateTexts() | |||
{ | |||
I18N.TranslateForm(this); | |||
trafficChart.Series["Inbound"].LegendText = I18N.GetString("Inbound"); | |||
trafficChart.Series["Outbound"].LegendText = I18N.GetString("Outbound"); | |||
} | |||
private void Timer_Tick(object sender, EventArgs e) | |||
{ | |||
UpdateContent(); | |||
UpdateTrafficChart(); | |||
} | |||
private void InitContent() | |||
{ | |||
if (string.IsNullOrEmpty(filename) || !File.Exists(filename)) | |||
return; | |||
using (StreamReader reader = new StreamReader(new FileStream(filename, | |||
FileMode.Open, FileAccess.Read, FileShare.ReadWrite))) | |||
{ | |||
if (reader.BaseStream.Length > BACK_OFFSET) | |||
{ | |||
reader.BaseStream.Seek(-BACK_OFFSET, SeekOrigin.End); | |||
reader.ReadLine(); | |||
} | |||
string line = ""; | |||
StringBuilder appendText = new StringBuilder(1024); | |||
while ((line = reader.ReadLine()) != null) | |||
appendText.AppendLine(line); | |||
LogMessageTextBox.AppendText(appendText.ToString()); | |||
LogMessageTextBox.ScrollToCaret(); | |||
lastOffset = reader.BaseStream.Position; | |||
} | |||
} | |||
private void UpdateContent() | |||
{ | |||
this.Text = I18N.GetString("Log Viewer") + | |||
$" [in: {Utils.FormatBytes(controller.InboundCounter)}, out: {Utils.FormatBytes(controller.OutboundCounter)}]"; | |||
if (string.IsNullOrEmpty(filename) || !File.Exists(filename)) | |||
return; | |||
try | |||
{ | |||
using (StreamReader reader = new StreamReader(new FileStream(filename, | |||
FileMode.Open, FileAccess.Read, FileShare.ReadWrite))) | |||
{ | |||
reader.BaseStream.Seek(lastOffset, SeekOrigin.Begin); | |||
string line = ""; | |||
bool changed = false; | |||
StringBuilder appendText = new StringBuilder(128); | |||
while ((line = reader.ReadLine()) != null) | |||
{ | |||
changed = true; | |||
appendText.AppendLine(line); | |||
} | |||
if (changed) | |||
{ | |||
LogMessageTextBox.AppendText(appendText.ToString()); | |||
LogMessageTextBox.ScrollToCaret(); | |||
} | |||
lastOffset = reader.BaseStream.Position; | |||
} | |||
} | |||
catch (FileNotFoundException) | |||
{ | |||
} | |||
} | |||
private void LogForm_Load(object sender, EventArgs e) | |||
{ | |||
InitContent(); | |||
timer = new Timer(); | |||
timer.Interval = 100; | |||
timer.Tick += Timer_Tick; | |||
timer.Start(); | |||
LogViewerConfig config = controller.GetCurrentConfiguration().logViewer; | |||
Height = config.Height; | |||
Width = config.Width; | |||
Top = config.BestTop; | |||
Left = config.BestLeft; | |||
if (config.Maximized) | |||
{ | |||
WindowState = FormWindowState.Maximized; | |||
} | |||
topMostTriggerLock = true; | |||
TopMost = TopMostToolStripMenuItem.Checked = TopMostCheckBox.Checked = topMostTrigger; | |||
topMostTriggerLock = false; | |||
wrapTextTriggerLock = true; | |||
LogMessageTextBox.WordWrap = WrapTextToolStripMenuItem.Checked = WrapTextCheckBox.Checked = wrapTextTrigger; | |||
wrapTextTriggerLock = false; | |||
ToolbarFlowLayoutPanel.Visible = ShowToolbarToolStripMenuItem.Checked = toolbarTrigger; | |||
} | |||
private void LogForm_FormClosing(object sender, FormClosingEventArgs e) | |||
{ | |||
timer.Stop(); | |||
controller.TrafficChanged -= controller_TrafficChanged; | |||
LogViewerConfig config = controller.GetCurrentConfiguration().logViewer; | |||
config.topMost = topMostTrigger; | |||
config.wrapText = wrapTextTrigger; | |||
config.toolbarShown = toolbarTrigger; | |||
config.Font = LogMessageTextBox.Font; | |||
config.BackgroundColor = LogMessageTextBox.BackColor; | |||
config.TextColor = LogMessageTextBox.ForeColor; | |||
if (WindowState != FormWindowState.Minimized && !(config.Maximized = WindowState == FormWindowState.Maximized)) | |||
{ | |||
config.Top = Top; | |||
config.Left = Left; | |||
config.Height = Height; | |||
config.Width = Width; | |||
} | |||
controller.SaveLogViewerConfig(config); | |||
} | |||
private void OpenLocationToolStripMenuItem_Click(object sender, EventArgs e) | |||
{ | |||
string argument = "/select, \"" + filename + "\""; | |||
logger.Debug(argument); | |||
System.Diagnostics.Process.Start("explorer.exe", argument); | |||
} | |||
private void ExitToolStripMenuItem_Click(object sender, EventArgs e) | |||
{ | |||
Close(); | |||
} | |||
private void LogForm_Shown(object sender, EventArgs e) | |||
{ | |||
LogMessageTextBox.ScrollToCaret(); | |||
} | |||
#region Clean up the content in LogMessageTextBox. | |||
private void DoClearLogs() | |||
{ | |||
try | |||
{ | |||
File.Delete(filename); | |||
} | |||
catch { } | |||
lastOffset = 0; | |||
LogMessageTextBox.Clear(); | |||
} | |||
private void ClearLogsToolStripMenuItem_Click(object sender, EventArgs e) | |||
{ | |||
DoClearLogs(); | |||
} | |||
private void ClearLogsButton_Click(object sender, EventArgs e) | |||
{ | |||
DoClearLogs(); | |||
} | |||
#endregion | |||
#region Change the font settings applied in LogMessageTextBox. | |||
private void DoChangeFont() | |||
{ | |||
try | |||
{ | |||
FontDialog fd = new FontDialog(); | |||
fd.Font = LogMessageTextBox.Font; | |||
if (fd.ShowDialog() == DialogResult.OK) | |||
{ | |||
LogMessageTextBox.Font = new Font(fd.Font.FontFamily, fd.Font.Size, fd.Font.Style); | |||
} | |||
} | |||
catch (Exception ex) | |||
{ | |||
logger.LogUsefulException(ex); | |||
MessageBox.Show(ex.Message); | |||
} | |||
} | |||
private void ChangeFontToolStripMenuItem_Click(object sender, EventArgs e) | |||
{ | |||
DoChangeFont(); | |||
} | |||
private void ChangeFontButton_Click(object sender, EventArgs e) | |||
{ | |||
DoChangeFont(); | |||
} | |||
#endregion | |||
#region Trigger the log messages to wrapable, or not. | |||
bool wrapTextTrigger = false; | |||
bool wrapTextTriggerLock = false; | |||
private void TriggerWrapText() | |||
{ | |||
wrapTextTriggerLock = true; | |||
wrapTextTrigger = !wrapTextTrigger; | |||
LogMessageTextBox.WordWrap = wrapTextTrigger; | |||
LogMessageTextBox.ScrollToCaret(); | |||
WrapTextToolStripMenuItem.Checked = WrapTextCheckBox.Checked = wrapTextTrigger; | |||
wrapTextTriggerLock = false; | |||
} | |||
private void WrapTextToolStripMenuItem_Click(object sender, EventArgs e) | |||
{ | |||
if (!wrapTextTriggerLock) | |||
{ | |||
TriggerWrapText(); | |||
} | |||
} | |||
private void WrapTextCheckBox_CheckedChanged(object sender, EventArgs e) | |||
{ | |||
if (!wrapTextTriggerLock) | |||
{ | |||
TriggerWrapText(); | |||
} | |||
} | |||
#endregion | |||
#region Trigger the window to top most, or not. | |||
bool topMostTrigger = false; | |||
bool topMostTriggerLock = false; | |||
private void TriggerTopMost() | |||
{ | |||
topMostTriggerLock = true; | |||
topMostTrigger = !topMostTrigger; | |||
TopMost = topMostTrigger; | |||
TopMostToolStripMenuItem.Checked = TopMostCheckBox.Checked = topMostTrigger; | |||
topMostTriggerLock = false; | |||
} | |||
private void TopMostCheckBox_CheckedChanged(object sender, EventArgs e) | |||
{ | |||
if (!topMostTriggerLock) | |||
{ | |||
TriggerTopMost(); | |||
} | |||
} | |||
private void TopMostToolStripMenuItem_Click(object sender, EventArgs e) | |||
{ | |||
if (!topMostTriggerLock) | |||
{ | |||
TriggerTopMost(); | |||
} | |||
} | |||
#endregion | |||
private bool toolbarTrigger = false; | |||
private void ShowToolbarToolStripMenuItem_Click(object sender, EventArgs e) | |||
{ | |||
toolbarTrigger = !toolbarTrigger; | |||
ToolbarFlowLayoutPanel.Visible = toolbarTrigger; | |||
ShowToolbarToolStripMenuItem.Checked = toolbarTrigger; | |||
} | |||
private class TrafficInfo | |||
{ | |||
public long inbound; | |||
public long outbound; | |||
public TrafficInfo(long inbound, long outbound) | |||
{ | |||
this.inbound = inbound; | |||
this.outbound = outbound; | |||
} | |||
} | |||
} | |||
} |
@@ -1,150 +0,0 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<root> | |||
<!-- | |||
Microsoft ResX Schema | |||
Version 2.0 | |||
The primary goals of this format is to allow a simple XML format | |||
that is mostly human readable. The generation and parsing of the | |||
various data types are done through the TypeConverter classes | |||
associated with the data types. | |||
Example: | |||
... ado.net/XML headers & schema ... | |||
<resheader name="resmimetype">text/microsoft-resx</resheader> | |||
<resheader name="version">2.0</resheader> | |||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | |||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | |||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> | |||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | |||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | |||
<value>[base64 mime encoded serialized .NET Framework object]</value> | |||
</data> | |||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | |||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> | |||
<comment>This is a comment</comment> | |||
</data> | |||
There are any number of "resheader" rows that contain simple | |||
name/value pairs. | |||
Each data row contains a name, and value. The row also contains a | |||
type or mimetype. Type corresponds to a .NET class that support | |||
text/value conversion through the TypeConverter architecture. | |||
Classes that don't support this are serialized and stored with the | |||
mimetype set. | |||
The mimetype is used for serialized objects, and tells the | |||
ResXResourceReader how to depersist the object. This is currently not | |||
extensible. For a given mimetype the value must be set accordingly: | |||
Note - application/x-microsoft.net.object.binary.base64 is the format | |||
that the ResXResourceWriter will generate, however the reader can | |||
read any of the formats listed below. | |||
mimetype: application/x-microsoft.net.object.binary.base64 | |||
value : The object must be serialized with | |||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter | |||
: and then encoded with base64 encoding. | |||
mimetype: application/x-microsoft.net.object.soap.base64 | |||
value : The object must be serialized with | |||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | |||
: and then encoded with base64 encoding. | |||
mimetype: application/x-microsoft.net.object.bytearray.base64 | |||
value : The object must be serialized into a byte array | |||
: using a System.ComponentModel.TypeConverter | |||
: and then encoded with base64 encoding. | |||
--> | |||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | |||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> | |||
<xsd:element name="root" msdata:IsDataSet="true"> | |||
<xsd:complexType> | |||
<xsd:choice maxOccurs="unbounded"> | |||
<xsd:element name="metadata"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" use="required" type="xsd:string" /> | |||
<xsd:attribute name="type" type="xsd:string" /> | |||
<xsd:attribute name="mimetype" type="xsd:string" /> | |||
<xsd:attribute ref="xml:space" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="assembly"> | |||
<xsd:complexType> | |||
<xsd:attribute name="alias" type="xsd:string" /> | |||
<xsd:attribute name="name" type="xsd:string" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="data"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> | |||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | |||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | |||
<xsd:attribute ref="xml:space" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="resheader"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" type="xsd:string" use="required" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
</xsd:choice> | |||
</xsd:complexType> | |||
</xsd:element> | |||
</xsd:schema> | |||
<resheader name="resmimetype"> | |||
<value>text/microsoft-resx</value> | |||
</resheader> | |||
<resheader name="version"> | |||
<value>2.0</value> | |||
</resheader> | |||
<resheader name="reader"> | |||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
<resheader name="writer"> | |||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
<metadata name="LogMessageTextBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> | |||
<value>True</value> | |||
</metadata> | |||
<metadata name="MainMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> | |||
<value>17, 17</value> | |||
</metadata> | |||
<metadata name="TopMostCheckBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> | |||
<value>True</value> | |||
</metadata> | |||
<metadata name="ChangeFontButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> | |||
<value>True</value> | |||
</metadata> | |||
<metadata name="ClearLogsButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> | |||
<value>True</value> | |||
</metadata> | |||
<metadata name="WrapTextCheckBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> | |||
<value>True</value> | |||
</metadata> | |||
<metadata name="tableLayoutPanel1.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> | |||
<value>True</value> | |||
</metadata> | |||
<metadata name="ToolbarFlowLayoutPanel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> | |||
<value>True</value> | |||
</metadata> | |||
<metadata name="$this.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> | |||
<value>True</value> | |||
</metadata> | |||
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> | |||
<value>39</value> | |||
</metadata> | |||
</root> |
@@ -1,73 +0,0 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<configuration> | |||
<configSections> | |||
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> | |||
<section name="Shadowsocks.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/> | |||
</sectionGroup> | |||
</configSections> | |||
<userSettings> | |||
<Shadowsocks.Properties.Settings> | |||
<setting name="LogViewerWidth" serializeAs="String"> | |||
<value>600</value> | |||
</setting> | |||
<setting name="LogViewerHeight" serializeAs="String"> | |||
<value>400</value> | |||
</setting> | |||
<setting name="LogViewerMaximized" serializeAs="String"> | |||
<value>True</value> | |||
</setting> | |||
<setting name="LogViewerTop" serializeAs="String"> | |||
<value>0</value> | |||
</setting> | |||
<setting name="LogViewerLeft" serializeAs="String"> | |||
<value>0</value> | |||
</setting> | |||
</Shadowsocks.Properties.Settings> | |||
</userSettings> | |||
<!-- Uncomment to dump network tracing info | |||
<system.diagnostics> | |||
<sources> | |||
<source name="System.Net" tracemode="includehex" maxdatasize="1024"> | |||
<listeners> | |||
<add name="System.Net"/> | |||
</listeners> | |||
</source> | |||
<source name="System.Net.Cache"> | |||
<listeners> | |||
<add name="System.Net"/> | |||
</listeners> | |||
</source> | |||
<source name="System.Net.Http"> | |||
<listeners> | |||
<add name="System.Net"/> | |||
</listeners> | |||
</source> | |||
<source name="System.Net.Sockets"> | |||
<listeners> | |||
<add name="System.Net"/> | |||
</listeners> | |||
</source> | |||
<source name="System.Net.WebSockets"> | |||
<listeners> | |||
<add name="System.Net"/> | |||
</listeners> | |||
</source> | |||
</sources> | |||
<switches> | |||
<add name="System.Net" value="Verbose"/> | |||
<add name="System.Net.Cache" value="Verbose"/> | |||
<add name="System.Net.Http" value="Verbose"/> | |||
<add name="System.Net.Sockets" value="Verbose"/> | |||
<add name="System.Net.WebSockets" value="Verbose"/> | |||
</switches> | |||
<sharedListeners> | |||
<add name="System.Net" | |||
type="System.Diagnostics.TextWriterTraceListener" | |||
initializeData="network-tracing.log" | |||
/> | |||
</sharedListeners> | |||
<trace autoflush="true"/> | |||
</system.diagnostics> | |||
--> | |||
</configuration> |
@@ -1,76 +0,0 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"> | |||
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/> | |||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> | |||
<security> | |||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> | |||
<!-- UAC Manifest Options | |||
If you want to change the Windows User Account Control level replace the | |||
requestedExecutionLevel node with one of the following. | |||
<requestedExecutionLevel level="asInvoker" uiAccess="false" /> | |||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> | |||
<requestedExecutionLevel level="highestAvailable" uiAccess="false" /> | |||
Specifying requestedExecutionLevel element will disable file and registry virtualization. | |||
Remove this element if your application requires this virtualization for backwards | |||
compatibility. | |||
--> | |||
<requestedExecutionLevel level="asInvoker" uiAccess="false" /> | |||
</requestedPrivileges> | |||
</security> | |||
</trustInfo> | |||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> | |||
<application> | |||
<!-- A list of the Windows versions that this application has been tested on | |||
and is designed to work with. Uncomment the appropriate elements | |||
and Windows will automatically select the most compatible environment. --> | |||
<!-- Windows Vista --> | |||
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />--> | |||
<!-- Windows 7 --> | |||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" /> | |||
<!-- Windows 8 --> | |||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" /> | |||
<!-- Windows 8.1 --> | |||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" /> | |||
<!-- Windows 10 --> | |||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" /> | |||
</application> | |||
</compatibility> | |||
<!-- Indicates that the application is DPI-aware and will not be automatically scaled by Windows at higher | |||
DPIs. Windows Presentation Foundation (WPF) applications are automatically DPI-aware and do not need | |||
to opt in. Windows Forms applications targeting .NET Framework 4.6 that opt into this setting, should | |||
also set the 'EnableWindowsFormsHighDpiAutoResizing' setting to 'true' in their app.config. --> | |||
<application xmlns="urn:schemas-microsoft-com:asm.v3"> | |||
<windowsSettings> | |||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor, System</dpiAwareness> | |||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware> | |||
</windowsSettings> | |||
</application> | |||
<!-- Enable themes for Windows common controls and dialogs (Windows XP and later) --> | |||
<!-- | |||
<dependency> | |||
<dependentAssembly> | |||
<assemblyIdentity | |||
type="win32" | |||
name="Microsoft.Windows.Common-Controls" | |||
version="6.0.0.0" | |||
processorArchitecture="*" | |||
publicKeyToken="6595b64144ccf1df" | |||
language="*" | |||
/> | |||
</dependentAssembly> | |||
</dependency> | |||
--> | |||
</assembly> |
@@ -1,19 +0,0 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<packages> | |||
<package id="BouncyCastle" version="1.8.5" targetFramework="net472" /> | |||
<package id="Caseless.Fody" version="1.8.3" targetFramework="net472" /> | |||
<package id="CommandLineParser" version="2.8.0" targetFramework="net472" /> | |||
<package id="Costura.Fody" version="3.3.3" targetFramework="net472" /> | |||
<package id="Fody" version="4.2.1" targetFramework="net472" developmentDependency="true" /> | |||
<package id="GlobalHotKey" version="1.1.0" targetFramework="net472" /> | |||
<package id="Google.Protobuf" version="3.15.2" targetFramework="net472" /> | |||
<package id="NaCl.Core" version="1.2.0" targetFramework="net472" /> | |||
<package id="Newtonsoft.Json" version="12.0.2" targetFramework="net472" /> | |||
<package id="NLog" version="4.6.8" targetFramework="net472" /> | |||
<package id="StringEx.CS" version="0.3.1" targetFramework="net472" developmentDependency="true" /> | |||
<package id="System.Buffers" version="4.4.0" targetFramework="net472" /> | |||
<package id="System.Memory" version="4.5.2" targetFramework="net472" /> | |||
<package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net472" /> | |||
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net472" /> | |||
<package id="ZXing.Net" version="0.16.5" targetFramework="net472" /> | |||
</packages> |
@@ -1,75 +0,0 @@ | |||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> | |||
<PropertyGroup> | |||
<OutputType>WinExe</OutputType> | |||
<TargetFramework>netcoreapp3.1</TargetFramework> | |||
<UseWPF>true</UseWPF> | |||
<UseWindowsForms>true</UseWindowsForms> | |||
<Authors>clowwindy & community 2020</Authors> | |||
<PackageId>Shadowsocks.Legacy</PackageId> | |||
<Product>Shadowsocks Legacy Project</Product> | |||
<Version>4.3.0.0</Version> | |||
<ApplicationIcon>shadowsocks.ico</ApplicationIcon> | |||
<StartupObject>Shadowsocks.Program</StartupObject> | |||
<ApplicationManifest>app.manifest</ApplicationManifest> | |||
<RootNamespace>Shadowsocks.Legacy</RootNamespace> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<None Remove="app.config" /> | |||
<None Remove="app.manifest" /> | |||
<None Remove="Data\i18n.csv" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<PackageReference Include="BouncyCastle.NetCore" Version="1.8.8" /> | |||
<!--TODO: Remove Fody related stuff, as they're either not actually used or has NET Core built-in alternate--> | |||
<PackageReference Include="Caseless.Fody" Version="1.9.0"> | |||
<PrivateAssets>all</PrivateAssets> | |||
</PackageReference> | |||
<PackageReference Include="CommandLineParser" Version="2.8.0" /> | |||
<PackageReference Include="Costura.Fody" Version="4.1.0"> | |||
<PrivateAssets>all</PrivateAssets> | |||
</PackageReference> | |||
<PackageReference Include="Fody" Version="6.3.0"> | |||
<PrivateAssets>all</PrivateAssets> | |||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | |||
</PackageReference> | |||
<PackageReference Include="GlobalHotKeyCore" Version="1.2.0" /> | |||
<PackageReference Include="Google.Protobuf" Version="3.15.2" /> | |||
<PackageReference Include="MdXaml" Version="1.9.0" /> | |||
<PackageReference Include="Microsoft.VisualBasic" Version="10.3.0" /> | |||
<PackageReference Include="NaCl.Core" Version="1.2.0" /> | |||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> | |||
<PackageReference Include="NLog" Version="4.7.5" /> | |||
<PackageReference Include="ReactiveUI.Events.WPF" Version="13.1.1" /> | |||
<PackageReference Include="ReactiveUI.Fody" Version="13.0.38" /> | |||
<PackageReference Include="ReactiveUI.Validation" Version="2.1.1" /> | |||
<PackageReference Include="ReactiveUI.WPF" Version="13.0.38" /> | |||
<PackageReference Include="System.Data.SqlClient" Version="4.8.2" /> | |||
<PackageReference Include="System.Management" Version="4.7.0" /> | |||
<PackageReference Include="System.Windows.Forms.DataVisualization" Version="1.0.0-prerelease.20110.1" /> | |||
<PackageReference Include="WPFLocalizeExtension" Version="3.8.0" /> | |||
<PackageReference Include="ZXing.Net" Version="0.16.6" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Resource Include="Data\i18n.csv" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Compile Update="Properties\Settings.Designer.cs"> | |||
<DesignTimeSharedInput>True</DesignTimeSharedInput> | |||
<AutoGen>True</AutoGen> | |||
<DependentUpon>Settings.settings</DependentUpon> | |||
</Compile> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<None Update="Properties\Settings.settings"> | |||
<Generator>SettingsSingleFileGenerator</Generator> | |||
<LastGenOutput>Settings.Designer.cs</LastGenOutput> | |||
</None> | |||
</ItemGroup> | |||
</Project> |
@@ -3,13 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 | |||
# Visual Studio Version 16 | |||
VisualStudioVersion = 16.0.29709.97 | |||
MinimumVisualStudioVersion = 10.0.40219.1 | |||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "shadowsocks-csharp", "shadowsocks-csharp\shadowsocks-csharp.csproj", "{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}" | |||
EndProject | |||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ShadowsocksTest", "test\ShadowsocksTest.csproj", "{45913187-0685-4903-B250-DCEF0479CD86}" | |||
ProjectSection(ProjectDependencies) = postProject | |||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062} = {8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062} | |||
EndProjectSection | |||
EndProject | |||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7BD54B24-BBD7-4DD8-99EF-DAEE6684B673}" | |||
ProjectSection(SolutionItems) = preProject | |||
.editorconfig = .editorconfig | |||
@@ -39,7 +32,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shadowsocks.WPF.Tests", "Sh | |||
EndProject | |||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shadowsocks.CLI", "Shadowsocks.CLI\Shadowsocks.CLI.csproj", "{78EB3006-81B0-4C13-9B80-E91766874A57}" | |||
EndProject | |||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shadowsocks.Protocol", "Shadowsocks.Protocol\Shadowsocks.Protocol.csproj", "{94DE5045-4D09-437B-BDE3-679FCAF07A2D}" | |||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shadowsocks.Protocol", "Shadowsocks.Protocol\Shadowsocks.Protocol.csproj", "{94DE5045-4D09-437B-BDE3-679FCAF07A2D}" | |||
EndProject | |||
Global | |||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||
@@ -47,10 +40,6 @@ Global | |||
Release|Any CPU = Release|Any CPU | |||
EndGlobalSection | |||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{45913187-0685-4903-B250-DCEF0479CD86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{45913187-0685-4903-B250-DCEF0479CD86}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{DFE11C77-62FA-4011-8398-38626C02E382}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{DFE11C77-62FA-4011-8398-38626C02E382}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{DFE11C77-62FA-4011-8398-38626C02E382}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
@@ -1,14 +0,0 @@ | |||
<?xml version="1.0" encoding="utf-8" ?> | |||
<configuration> | |||
<configSections> | |||
<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/> | |||
</configSections> | |||
<nlog> | |||
<targets> | |||
<target name="logconsole" type="Debugger" /> | |||
</targets> | |||
<rules> | |||
<logger name="*" minlevel="Trace" writeTo="logconsole" /> | |||
</rules> | |||
</nlog> | |||
</configuration> |
@@ -1,84 +0,0 @@ | |||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.IO; | |||
using System.Text; | |||
using Shadowsocks.Controller; | |||
namespace Shadowsocks.Test | |||
{ | |||
[TestClass] | |||
public class CachedNetworkStreamTest | |||
{ | |||
byte[] b0 = new byte[256]; | |||
byte[] b1 = new byte[256]; | |||
byte[] b2 = new byte[1024]; | |||
// [TestInitialize] | |||
[TestInitialize] | |||
public void init() | |||
{ | |||
for (int i = 0; i < 256; i++) | |||
{ | |||
b0[i] = (byte)i; | |||
b1[i] = (byte)(255 - i); | |||
} | |||
b0.CopyTo(b2, 0); | |||
b1.CopyTo(b2, 256); | |||
b0.CopyTo(b2, 512); | |||
} | |||
[TestMethod] | |||
public void StreamTest() | |||
{ | |||
using MemoryStream ms = new MemoryStream(b2); | |||
using CachedNetworkStream s = new CachedNetworkStream(ms); | |||
byte[] o = new byte[128]; | |||
Assert.AreEqual(128, s.Read(o, 0, 128)); | |||
TestUtils.ArrayEqual(b0[0..128], o); | |||
Assert.AreEqual(64, s.Read(o, 0, 64)); | |||
TestUtils.ArrayEqual(b0[128..192], o[0..64]); | |||
s.Seek(0, SeekOrigin.Begin); | |||
Assert.AreEqual(64, s.Read(o, 0, 64)); | |||
TestUtils.ArrayEqual(b0[0..64], o[0..64]); | |||
// refuse to go out of cached range | |||
Assert.ThrowsException<NotSupportedException>(() => | |||
{ | |||
s.Seek(193, SeekOrigin.Begin); | |||
}); | |||
Assert.AreEqual(128, s.Read(o, 0, 128)); | |||
TestUtils.ArrayEqual(b0[64..192], o); | |||
Assert.IsTrue(s.CanSeek); | |||
Assert.AreEqual(128, s.Read(o, 0, 128)); | |||
TestUtils.ArrayEqual(b0[192..256], o[0..64]); | |||
TestUtils.ArrayEqual(b1[0..64], o[64..128]); | |||
Assert.IsFalse(s.CanSeek); | |||
// refuse to go back when non-cache data has been read | |||
Assert.ThrowsException<NotSupportedException>(() => | |||
{ | |||
s.Seek(0, SeekOrigin.Begin); | |||
}); | |||
// read in non-cache range | |||
Assert.AreEqual(64, s.Read(o, 0, 64)); | |||
s.Read(o, 0, 128); | |||
Assert.AreEqual(512, s.Position); | |||
Assert.AreEqual(128, s.Read(o, 0, 128)); | |||
TestUtils.ArrayEqual(b0[0..128], o); | |||
s.Read(o, 0, 128); | |||
s.Read(o, 0, 128); | |||
s.Read(o, 0, 128); | |||
// read at eos | |||
Assert.AreEqual(0, s.Read(o, 0, 128)); | |||
} | |||
} | |||
} |
@@ -1,141 +0,0 @@ | |||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||
using Shadowsocks.Encryption; | |||
using Shadowsocks.Encryption.Stream; | |||
using Shadowsocks.Encryption.AEAD; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Threading; | |||
namespace Shadowsocks.Test | |||
{ | |||
[TestClass] | |||
public class CryptographyTest | |||
{ | |||
readonly Random random = new Random(); | |||
[TestMethod] | |||
public void TestMD5() | |||
{ | |||
for (int len = 1; len < 64; len++) | |||
{ | |||
System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create(); | |||
byte[] bytes = new byte[len]; | |||
random.NextBytes(bytes); | |||
string md5str = Convert.ToBase64String(md5.ComputeHash(bytes)); | |||
string md5str2 = Convert.ToBase64String(CryptoUtils.MD5(bytes)); | |||
Assert.IsTrue(md5str == md5str2); | |||
} | |||
} | |||
#region Encryptor test tools | |||
private void SingleEncryptionTestCase(IEncryptor encryptor, IEncryptor decryptor, int length) | |||
{ | |||
RNG.Reload(); | |||
byte[] plain = new byte[length]; | |||
byte[] cipher = new byte[plain.Length + 100];// AEAD with IPv4 address type needs +100 | |||
byte[] plain2 = new byte[plain.Length + 16]; | |||
random.NextBytes(plain); | |||
int outLen = encryptor.Encrypt(plain, cipher); | |||
int outLen2 = decryptor.Decrypt(plain2, cipher.AsSpan(0, outLen)); | |||
//encryptor.Encrypt(plain, length, cipher, out int outLen); | |||
//decryptor.Decrypt(cipher, outLen, plain2, out int outLen2); | |||
Assert.AreEqual(length, outLen2); | |||
TestUtils.ArrayEqual<byte>(plain.AsSpan(0, length).ToArray(), plain2.AsSpan(0, length).ToArray()); | |||
} | |||
const string password = "barfoo!"; | |||
private void RunSingleEncryptionThread(Type enc, Type dec, string method) | |||
{ | |||
var ector = enc.GetConstructor(new Type[] { typeof(string), typeof(string) }); | |||
var dctor = dec.GetConstructor(new Type[] { typeof(string), typeof(string) }); | |||
try | |||
{ | |||
IEncryptor encryptor = (IEncryptor)ector.Invoke(new object[] { method, password }); | |||
IEncryptor decryptor = (IEncryptor)dctor.Invoke(new object[] { method, password }); | |||
for (int i = 0; i < 16; i++) | |||
{ | |||
RunEncryptionRound(encryptor, decryptor); | |||
} | |||
} | |||
catch | |||
{ | |||
encryptionFailed = true; | |||
throw; | |||
} | |||
} | |||
private static bool encryptionFailed = false; | |||
private void TestEncryptionMethod(Type enc, string method) | |||
{ | |||
TestEncryptionMethod(enc, enc, method); | |||
} | |||
private void TestEncryptionMethod(Type enc, Type dec, string method) | |||
{ | |||
encryptionFailed = false; | |||
// run it once before the multi-threading test to initialize global tables | |||
RunSingleEncryptionThread(enc, dec, method); | |||
List<Thread> threads = new List<Thread>(); | |||
for (int i = 0; i < 8; i++) | |||
{ | |||
Thread t = new Thread(new ThreadStart(() => RunSingleEncryptionThread(enc, dec, method))); threads.Add(t); | |||
t.Start(); | |||
} | |||
foreach (Thread t in threads) | |||
{ | |||
t.Join(); | |||
} | |||
Assert.IsFalse(encryptionFailed); | |||
} | |||
#endregion | |||
// encryption test cases | |||
private void RunEncryptionRound(IEncryptor encryptor, IEncryptor decryptor) | |||
{ | |||
SingleEncryptionTestCase(encryptor, decryptor, 7); // for not aligned data | |||
SingleEncryptionTestCase(encryptor, decryptor, 1000); | |||
SingleEncryptionTestCase(encryptor, decryptor, 12333); | |||
SingleEncryptionTestCase(encryptor, decryptor, 16384); | |||
} | |||
[TestMethod] | |||
public void TestAEADAesGcmNativeEncryption() | |||
{ | |||
TestEncryptionMethod(typeof(AEADAesGcmNativeEncryptor), "aes-128-gcm"); | |||
TestEncryptionMethod(typeof(AEADAesGcmNativeEncryptor), "aes-192-gcm"); | |||
TestEncryptionMethod(typeof(AEADAesGcmNativeEncryptor), "aes-256-gcm"); | |||
} | |||
[TestMethod] | |||
public void TestAEADNaClEncryption() | |||
{ | |||
TestEncryptionMethod(typeof(AEADNaClEncryptor), "chacha20-ietf-poly1305"); | |||
TestEncryptionMethod(typeof(AEADNaClEncryptor), "xchacha20-ietf-poly1305"); | |||
} | |||
[TestMethod] | |||
public void TestStreamNativeEncryption() | |||
{ | |||
TestEncryptionMethod(typeof(StreamPlainNativeEncryptor), "plain"); | |||
TestEncryptionMethod(typeof(StreamRc4NativeEncryptor), "rc4"); | |||
TestEncryptionMethod(typeof(StreamRc4NativeEncryptor), "rc4-md5"); | |||
} | |||
[TestMethod] | |||
public void TestStreamAesCfbBouncyCastleEncryption() | |||
{ | |||
TestEncryptionMethod(typeof(StreamAesCfbBouncyCastleEncryptor), "aes-128-cfb"); | |||
TestEncryptionMethod(typeof(StreamAesCfbBouncyCastleEncryptor), "aes-192-cfb"); | |||
TestEncryptionMethod(typeof(StreamAesCfbBouncyCastleEncryptor), "aes-256-cfb"); | |||
} | |||
[TestMethod] | |||
public void TestStreamChachaNaClEncryption() | |||
{ | |||
TestEncryptionMethod(typeof(StreamChachaNaClEncryptor), "chacha20-ietf"); | |||
} | |||
} | |||
} |
@@ -1,713 +0,0 @@ | |||
/* *************************************************************************** | |||
The component allows to read the environment variables of another process | |||
running in a Windows system. | |||
History: | |||
- v1.2.ss Add GetCommandLine for convenience. | |||
- v1.2: Added support for inspection of 64 bit processes from 32 bit host | |||
- v1.1: Fixed issue with environment block size detection | |||
- v1.0: Initial | |||
****************************************************************************** | |||
The MIT License (MIT) | |||
Copyright (c) 2011-2014 Oleksiy Gapotchenko | |||
Copyright (c) 2018 Shadowsocks Project | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in | |||
all copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||
THE SOFTWARE. | |||
*************************************************************************** */ | |||
using System; | |||
using System.Collections.Specialized; | |||
using System.Diagnostics; | |||
using System.Linq; | |||
using System.Management; | |||
using System.Runtime.CompilerServices; | |||
using System.Runtime.InteropServices; | |||
using System.Text; | |||
namespace Shadowsocks.Test | |||
{ | |||
static class ProcessEnvironment | |||
{ | |||
public static StringDictionary ReadEnvironmentVariables(this Process process) | |||
{ | |||
return _GetEnvironmentVariablesCore(process.Handle); | |||
} | |||
public static StringDictionary TryReadEnvironmentVariables(this Process process) | |||
{ | |||
try | |||
{ | |||
return ReadEnvironmentVariables(process); | |||
} | |||
catch | |||
{ | |||
return null; | |||
} | |||
} | |||
public static string GetCommandLine(this Process process) | |||
{ | |||
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + process.Id)) | |||
using (ManagementObjectCollection objects = searcher.Get()) | |||
{ | |||
return objects.Cast<ManagementBaseObject>().SingleOrDefault()?["CommandLine"]?.ToString(); | |||
} | |||
} | |||
/// <summary> | |||
/// Universal pointer. | |||
/// </summary> | |||
struct UniPtr | |||
{ | |||
public UniPtr(IntPtr p) | |||
{ | |||
Value = p.ToInt64(); | |||
Size = IntPtr.Size; | |||
} | |||
public UniPtr(long p) | |||
{ | |||
Value = p; | |||
Size = sizeof(long); | |||
} | |||
public long Value; | |||
public int Size; | |||
public static implicit operator IntPtr(UniPtr p) | |||
{ | |||
return new IntPtr(p.Value); | |||
} | |||
public static implicit operator UniPtr(IntPtr p) | |||
{ | |||
return new UniPtr(p); | |||
} | |||
public override string ToString() | |||
{ | |||
return Value.ToString(); | |||
} | |||
public bool FitsInNativePointer | |||
{ | |||
get | |||
{ | |||
return Size <= IntPtr.Size; | |||
} | |||
} | |||
public bool CanBeRepresentedByNativePointer | |||
{ | |||
get | |||
{ | |||
int actualSize = Size; | |||
if (actualSize == 8) | |||
{ | |||
if (Value >> 32 == 0) | |||
actualSize = 4; | |||
} | |||
return actualSize <= IntPtr.Size; | |||
} | |||
} | |||
public long ToInt64() | |||
{ | |||
return Value; | |||
} | |||
} | |||
static StringDictionary _GetEnvironmentVariablesCore(IntPtr hProcess) | |||
{ | |||
var penv = _GetPenv(hProcess); | |||
const int maxEnvSize = 32767; | |||
byte[] envData; | |||
if (penv.CanBeRepresentedByNativePointer) | |||
{ | |||
int dataSize; | |||
if (!_HasReadAccess(hProcess, penv, out dataSize)) | |||
throw new Exception("Unable to read environment block."); | |||
if (dataSize > maxEnvSize) | |||
dataSize = maxEnvSize; | |||
envData = new byte[dataSize]; | |||
var res_len = IntPtr.Zero; | |||
bool b = WindowsApi.ReadProcessMemory( | |||
hProcess, | |||
penv, | |||
envData, | |||
new IntPtr(dataSize), | |||
ref res_len); | |||
if (!b || (int)res_len != dataSize) | |||
throw new Exception("Unable to read environment block data."); | |||
} | |||
else if (penv.Size == 8 && IntPtr.Size == 4) | |||
{ | |||
// Accessing 64 bit process under 32 bit host. | |||
int dataSize; | |||
if (!_HasReadAccessWow64(hProcess, penv.ToInt64(), out dataSize)) | |||
throw new Exception("Unable to read environment block with WOW64 API."); | |||
if (dataSize > maxEnvSize) | |||
dataSize = maxEnvSize; | |||
envData = new byte[dataSize]; | |||
long res_len = 0; | |||
int result = WindowsApi.NtWow64ReadVirtualMemory64( | |||
hProcess, | |||
penv.ToInt64(), | |||
envData, | |||
dataSize, | |||
ref res_len); | |||
if (result != WindowsApi.STATUS_SUCCESS || res_len != dataSize) | |||
throw new Exception("Unable to read environment block data with WOW64 API."); | |||
} | |||
else | |||
{ | |||
throw new Exception("Unable to access process memory due to unsupported bitness cardinality."); | |||
} | |||
return _EnvToDictionary(envData); | |||
} | |||
static StringDictionary _EnvToDictionary(byte[] env) | |||
{ | |||
var result = new StringDictionary(); | |||
int len = env.Length; | |||
if (len < 4) | |||
return result; | |||
int n = len - 3; | |||
for (int i = 0; i < n; ++i) | |||
{ | |||
byte c1 = env[i]; | |||
byte c2 = env[i + 1]; | |||
byte c3 = env[i + 2]; | |||
byte c4 = env[i + 3]; | |||
if (c1 == 0 && c2 == 0 && c3 == 0 && c4 == 0) | |||
{ | |||
len = i + 3; | |||
break; | |||
} | |||
} | |||
char[] environmentCharArray = Encoding.Unicode.GetChars(env, 0, len); | |||
for (int i = 0; i < environmentCharArray.Length; i++) | |||
{ | |||
int startIndex = i; | |||
while ((environmentCharArray[i] != '=') && (environmentCharArray[i] != '\0')) | |||
{ | |||
i++; | |||
} | |||
if (environmentCharArray[i] != '\0') | |||
{ | |||
if ((i - startIndex) == 0) | |||
{ | |||
while (environmentCharArray[i] != '\0') | |||
{ | |||
i++; | |||
} | |||
} | |||
else | |||
{ | |||
string str = new string(environmentCharArray, startIndex, i - startIndex); | |||
i++; | |||
int num3 = i; | |||
while (environmentCharArray[i] != '\0') | |||
{ | |||
i++; | |||
} | |||
string str2 = new string(environmentCharArray, num3, i - num3); | |||
result[str] = str2; | |||
} | |||
} | |||
} | |||
return result; | |||
} | |||
static bool _TryReadIntPtr32(IntPtr hProcess, IntPtr ptr, out IntPtr readPtr) | |||
{ | |||
bool result; | |||
RuntimeHelpers.PrepareConstrainedRegions(); | |||
try | |||
{ | |||
} | |||
finally | |||
{ | |||
int dataSize = sizeof(Int32); | |||
var data = Marshal.AllocHGlobal(dataSize); | |||
IntPtr res_len = IntPtr.Zero; | |||
bool b = WindowsApi.ReadProcessMemory( | |||
hProcess, | |||
ptr, | |||
data, | |||
new IntPtr(dataSize), | |||
ref res_len); | |||
readPtr = new IntPtr(Marshal.ReadInt32(data)); | |||
Marshal.FreeHGlobal(data); | |||
if (!b || (int)res_len != dataSize) | |||
result = false; | |||
else | |||
result = true; | |||
} | |||
return result; | |||
} | |||
static bool _TryReadIntPtr(IntPtr hProcess, IntPtr ptr, out IntPtr readPtr) | |||
{ | |||
bool result; | |||
RuntimeHelpers.PrepareConstrainedRegions(); | |||
try | |||
{ | |||
} | |||
finally | |||
{ | |||
int dataSize = IntPtr.Size; | |||
var data = Marshal.AllocHGlobal(dataSize); | |||
IntPtr res_len = IntPtr.Zero; | |||
bool b = WindowsApi.ReadProcessMemory( | |||
hProcess, | |||
ptr, | |||
data, | |||
new IntPtr(dataSize), | |||
ref res_len); | |||
readPtr = Marshal.ReadIntPtr(data); | |||
Marshal.FreeHGlobal(data); | |||
if (!b || (int)res_len != dataSize) | |||
result = false; | |||
else | |||
result = true; | |||
} | |||
return result; | |||
} | |||
static bool _TryReadIntPtrWow64(IntPtr hProcess, long ptr, out long readPtr) | |||
{ | |||
bool result; | |||
RuntimeHelpers.PrepareConstrainedRegions(); | |||
try | |||
{ | |||
} | |||
finally | |||
{ | |||
int dataSize = sizeof(long); | |||
var data = Marshal.AllocHGlobal(dataSize); | |||
long res_len = 0; | |||
int status = WindowsApi.NtWow64ReadVirtualMemory64( | |||
hProcess, | |||
ptr, | |||
data, | |||
dataSize, | |||
ref res_len); | |||
readPtr = Marshal.ReadInt64(data); | |||
Marshal.FreeHGlobal(data); | |||
if (status != WindowsApi.STATUS_SUCCESS || res_len != dataSize) | |||
result = false; | |||
else | |||
result = true; | |||
} | |||
return result; | |||
} | |||
static UniPtr _GetPenv(IntPtr hProcess) | |||
{ | |||
int processBitness = _GetProcessBitness(hProcess); | |||
if (processBitness == 64) | |||
{ | |||
if (Environment.Is64BitProcess) | |||
{ | |||
// Accessing 64 bit process under 64 bit host. | |||
IntPtr pPeb = _GetPeb64(hProcess); | |||
IntPtr ptr; | |||
if (!_TryReadIntPtr(hProcess, pPeb + 0x20, out ptr)) | |||
throw new Exception("Unable to read PEB."); | |||
IntPtr penv; | |||
if (!_TryReadIntPtr(hProcess, ptr + 0x80, out penv)) | |||
throw new Exception("Unable to read RTL_USER_PROCESS_PARAMETERS."); | |||
return penv; | |||
} | |||
else | |||
{ | |||
// Accessing 64 bit process under 32 bit host. | |||
var pPeb = _GetPeb64(hProcess); | |||
long ptr; | |||
if (!_TryReadIntPtrWow64(hProcess, pPeb.ToInt64() + 0x20, out ptr)) | |||
throw new Exception("Unable to read PEB."); | |||
long penv; | |||
if (!_TryReadIntPtrWow64(hProcess, ptr + 0x80, out penv)) | |||
throw new Exception("Unable to read RTL_USER_PROCESS_PARAMETERS."); | |||
return new UniPtr(penv); | |||
} | |||
} | |||
else | |||
{ | |||
// Accessing 32 bit process under 32 bit host. | |||
IntPtr pPeb = _GetPeb32(hProcess); | |||
IntPtr ptr; | |||
if (!_TryReadIntPtr32(hProcess, pPeb + 0x10, out ptr)) | |||
throw new Exception("Unable to read PEB."); | |||
IntPtr penv; | |||
if (!_TryReadIntPtr32(hProcess, ptr + 0x48, out penv)) | |||
throw new Exception("Unable to read RTL_USER_PROCESS_PARAMETERS."); | |||
return penv; | |||
} | |||
} | |||
static int _GetProcessBitness(IntPtr hProcess) | |||
{ | |||
if (Environment.Is64BitOperatingSystem) | |||
{ | |||
bool wow64; | |||
if (!WindowsApi.IsWow64Process(hProcess, out wow64)) | |||
return 32; | |||
if (wow64) | |||
return 32; | |||
return 64; | |||
} | |||
else | |||
{ | |||
return 32; | |||
} | |||
} | |||
static IntPtr _GetPeb32(IntPtr hProcess) | |||
{ | |||
if (Environment.Is64BitProcess) | |||
{ | |||
var ptr = IntPtr.Zero; | |||
int res_len = 0; | |||
int pbiSize = IntPtr.Size; | |||
int status = WindowsApi.NtQueryInformationProcess( | |||
hProcess, | |||
WindowsApi.ProcessWow64Information, | |||
ref ptr, | |||
pbiSize, | |||
ref res_len); | |||
if (res_len != pbiSize) | |||
throw new Exception("Unable to query process information."); | |||
return ptr; | |||
} | |||
else | |||
{ | |||
return _GetPebNative(hProcess); | |||
} | |||
} | |||
static IntPtr _GetPebNative(IntPtr hProcess) | |||
{ | |||
var pbi = new WindowsApi.PROCESS_BASIC_INFORMATION(); | |||
int res_len = 0; | |||
int pbiSize = Marshal.SizeOf(pbi); | |||
int status = WindowsApi.NtQueryInformationProcess( | |||
hProcess, | |||
WindowsApi.ProcessBasicInformation, | |||
ref pbi, | |||
pbiSize, | |||
ref res_len); | |||
if (res_len != pbiSize) | |||
throw new Exception("Unable to query process information."); | |||
return pbi.PebBaseAddress; | |||
} | |||
static UniPtr _GetPeb64(IntPtr hProcess) | |||
{ | |||
if (Environment.Is64BitProcess) | |||
{ | |||
return _GetPebNative(hProcess); | |||
} | |||
else | |||
{ | |||
// Get PEB via WOW64 API. | |||
var pbi = new WindowsApi.PROCESS_BASIC_INFORMATION_WOW64(); | |||
int res_len = 0; | |||
int pbiSize = Marshal.SizeOf(pbi); | |||
int status = WindowsApi.NtWow64QueryInformationProcess64( | |||
hProcess, | |||
WindowsApi.ProcessBasicInformation, | |||
ref pbi, | |||
pbiSize, | |||
ref res_len); | |||
if (res_len != pbiSize) | |||
throw new Exception("Unable to query process information."); | |||
return new UniPtr(pbi.PebBaseAddress); | |||
} | |||
} | |||
static bool _HasReadAccess(IntPtr hProcess, IntPtr address, out int size) | |||
{ | |||
size = 0; | |||
var memInfo = new WindowsApi.MEMORY_BASIC_INFORMATION(); | |||
int result = WindowsApi.VirtualQueryEx( | |||
hProcess, | |||
address, | |||
ref memInfo, | |||
Marshal.SizeOf(memInfo)); | |||
if (result == 0) | |||
return false; | |||
if (memInfo.Protect == WindowsApi.PAGE_NOACCESS || memInfo.Protect == WindowsApi.PAGE_EXECUTE) | |||
return false; | |||
try | |||
{ | |||
size = Convert.ToInt32(memInfo.RegionSize.ToInt64() - (address.ToInt64() - memInfo.BaseAddress.ToInt64())); | |||
} | |||
catch (OverflowException) | |||
{ | |||
return false; | |||
} | |||
if (size <= 0) | |||
return false; | |||
return true; | |||
} | |||
static bool _HasReadAccessWow64(IntPtr hProcess, long address, out int size) | |||
{ | |||
size = 0; | |||
WindowsApi.MEMORY_BASIC_INFORMATION_WOW64 memInfo; | |||
var memInfoType = typeof(WindowsApi.MEMORY_BASIC_INFORMATION_WOW64); | |||
int memInfoLength = Marshal.SizeOf(memInfoType); | |||
const int memInfoAlign = 8; | |||
long resultLength = 0; | |||
int result; | |||
IntPtr hMemInfo = Marshal.AllocHGlobal(memInfoLength + memInfoAlign * 2); | |||
try | |||
{ | |||
// Align to 64 bits. | |||
IntPtr hMemInfoAligned = new IntPtr(hMemInfo.ToInt64() & ~(memInfoAlign - 1L)); | |||
result = WindowsApi.NtWow64QueryVirtualMemory64( | |||
hProcess, | |||
address, | |||
WindowsApi.MEMORY_INFORMATION_CLASS.MemoryBasicInformation, | |||
hMemInfoAligned, | |||
memInfoLength, | |||
ref resultLength); | |||
memInfo = (WindowsApi.MEMORY_BASIC_INFORMATION_WOW64)Marshal.PtrToStructure(hMemInfoAligned, memInfoType); | |||
} | |||
finally | |||
{ | |||
Marshal.FreeHGlobal(hMemInfo); | |||
} | |||
if (result != WindowsApi.STATUS_SUCCESS) | |||
return false; | |||
if (memInfo.Protect == WindowsApi.PAGE_NOACCESS || memInfo.Protect == WindowsApi.PAGE_EXECUTE) | |||
return false; | |||
try | |||
{ | |||
size = Convert.ToInt32(memInfo.RegionSize - (address - memInfo.BaseAddress)); | |||
} | |||
catch (OverflowException) | |||
{ | |||
return false; | |||
} | |||
if (size <= 0) | |||
return false; | |||
return true; | |||
} | |||
static class WindowsApi | |||
{ | |||
[StructLayout(LayoutKind.Sequential, Pack = 1)] | |||
public struct PROCESS_BASIC_INFORMATION | |||
{ | |||
public IntPtr Reserved1; | |||
public IntPtr PebBaseAddress; | |||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] | |||
public IntPtr[] Reserved2; | |||
public IntPtr UniqueProcessId; | |||
public IntPtr Reserved3; | |||
} | |||
public const int ProcessBasicInformation = 0; | |||
public const int ProcessWow64Information = 26; | |||
[DllImport("ntdll.dll", SetLastError = true)] | |||
public static extern int NtQueryInformationProcess( | |||
IntPtr hProcess, | |||
int pic, | |||
ref PROCESS_BASIC_INFORMATION pbi, | |||
int cb, | |||
ref int pSize); | |||
[DllImport("ntdll.dll", SetLastError = true)] | |||
public static extern int NtQueryInformationProcess( | |||
IntPtr hProcess, | |||
int pic, | |||
ref IntPtr pi, | |||
int cb, | |||
ref int pSize); | |||
[DllImport("ntdll.dll", SetLastError = true)] | |||
public static extern int NtQueryInformationProcess( | |||
IntPtr hProcess, | |||
int pic, | |||
ref long pi, | |||
int cb, | |||
ref int pSize); | |||
[StructLayout(LayoutKind.Sequential, Pack = 1)] | |||
public struct PROCESS_BASIC_INFORMATION_WOW64 | |||
{ | |||
public long Reserved1; | |||
public long PebBaseAddress; | |||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] | |||
public long[] Reserved2; | |||
public long UniqueProcessId; | |||
public long Reserved3; | |||
} | |||
[DllImport("ntdll.dll", SetLastError = true)] | |||
public static extern int NtWow64QueryInformationProcess64( | |||
IntPtr hProcess, | |||
int pic, | |||
ref PROCESS_BASIC_INFORMATION_WOW64 pbi, | |||
int cb, | |||
ref int pSize); | |||
[DllImport("kernel32.dll", SetLastError = true)] | |||
public static extern bool ReadProcessMemory( | |||
IntPtr hProcess, | |||
IntPtr lpBaseAddress, | |||
[Out] byte[] lpBuffer, | |||
IntPtr dwSize, | |||
ref IntPtr lpNumberOfBytesRead); | |||
[DllImport("kernel32.dll", SetLastError = true)] | |||
public static extern bool ReadProcessMemory( | |||
IntPtr hProcess, | |||
IntPtr lpBaseAddress, | |||
IntPtr lpBuffer, | |||
IntPtr dwSize, | |||
ref IntPtr lpNumberOfBytesRead); | |||
[DllImport("ntdll.dll", SetLastError = true)] | |||
public static extern int NtWow64ReadVirtualMemory64( | |||
IntPtr hProcess, | |||
long lpBaseAddress, | |||
IntPtr lpBuffer, | |||
long dwSize, | |||
ref long lpNumberOfBytesRead); | |||
[DllImport("ntdll.dll", SetLastError = true)] | |||
public static extern int NtWow64ReadVirtualMemory64( | |||
IntPtr hProcess, | |||
long lpBaseAddress, | |||
[Out] byte[] lpBuffer, | |||
long dwSize, | |||
ref long lpNumberOfBytesRead); | |||
public const int STATUS_SUCCESS = 0; | |||
public const int PAGE_NOACCESS = 0x01; | |||
public const int PAGE_EXECUTE = 0x10; | |||
[StructLayout(LayoutKind.Sequential)] | |||
public struct MEMORY_BASIC_INFORMATION | |||
{ | |||
public IntPtr BaseAddress; | |||
public IntPtr AllocationBase; | |||
public int AllocationProtect; | |||
public IntPtr RegionSize; | |||
public int State; | |||
public int Protect; | |||
public int Type; | |||
} | |||
[DllImport("kernel32.dll")] | |||
public static extern int VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, ref MEMORY_BASIC_INFORMATION lpBuffer, int dwLength); | |||
[StructLayout(LayoutKind.Sequential)] | |||
public struct MEMORY_BASIC_INFORMATION_WOW64 | |||
{ | |||
public long BaseAddress; | |||
public long AllocationBase; | |||
public int AllocationProtect; | |||
public long RegionSize; | |||
public int State; | |||
public int Protect; | |||
public int Type; | |||
} | |||
public enum MEMORY_INFORMATION_CLASS | |||
{ | |||
MemoryBasicInformation | |||
} | |||
[DllImport("ntdll.dll")] | |||
public static extern int NtWow64QueryVirtualMemory64( | |||
IntPtr hProcess, | |||
long lpAddress, | |||
MEMORY_INFORMATION_CLASS memoryInformationClass, | |||
IntPtr lpBuffer, // MEMORY_BASIC_INFORMATION_WOW64, pointer must be 64-bit aligned | |||
long memoryInformationLength, | |||
ref long returnLength); | |||
[DllImport("kernel32.dll")] | |||
public static extern bool IsWow64Process(IntPtr hProcess, out bool wow64Process); | |||
} | |||
} | |||
} |
@@ -1,34 +0,0 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
<PropertyGroup> | |||
<TargetFramework>netcoreapp3.1</TargetFramework> | |||
<IsPackable>false</IsPackable> | |||
<RootNamespace>Shadowsocks.Legacy.Test</RootNamespace> | |||
</PropertyGroup> | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> | |||
<WarningLevel>0</WarningLevel> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<PackageReference Include="GlobalHotKeyCore" Version="1.2.0" /> | |||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" /> | |||
<PackageReference Include="MSTest.TestAdapter" Version="2.1.0" /> | |||
<PackageReference Include="MSTest.TestFramework" Version="2.1.0" /> | |||
<PackageReference Include="coverlet.collector" Version="3.0.3"> | |||
<PrivateAssets>all</PrivateAssets> | |||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | |||
</PackageReference> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ProjectReference Include="..\shadowsocks-csharp\shadowsocks-csharp.csproj" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Folder Include="Properties\" /> | |||
</ItemGroup> | |||
</Project> |
@@ -1,221 +0,0 @@ | |||
using System; | |||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||
using System.Threading; | |||
using System.Collections.Generic; | |||
using Shadowsocks.Model; | |||
using Shadowsocks.Controller.Service; | |||
using System.Diagnostics; | |||
using System.Net; | |||
namespace Shadowsocks.Test | |||
{ | |||
[TestClass] | |||
public class Sip003PluginTest | |||
{ | |||
string fake_plugin = "ftp"; | |||
[TestMethod] | |||
public void TestSip003Plugin_NoPlugin() | |||
{ | |||
var NoPlugin = Sip003Plugin.CreateIfConfigured( | |||
new Server | |||
{ | |||
server = "192.168.100.1", | |||
server_port = 8888, | |||
password = "test", | |||
method = "bf-cfb" | |||
}, | |||
false); | |||
RunPluginSupportTest( | |||
NoPlugin, | |||
"", | |||
"", | |||
"", | |||
"192.168.100.1", | |||
8888); | |||
} | |||
[TestMethod] | |||
public void TestSip003Plugin_Plugin() | |||
{ | |||
var Plugin = Sip003Plugin.CreateIfConfigured( | |||
new Server | |||
{ | |||
server = "192.168.100.1", | |||
server_port = 8888, | |||
password = "test", | |||
method = "bf-cfb", | |||
plugin = fake_plugin | |||
}, | |||
false); | |||
RunPluginSupportTest( | |||
Plugin, | |||
fake_plugin, | |||
"", | |||
"", | |||
"192.168.100.1", | |||
8888); | |||
} | |||
[TestMethod] | |||
public void TestSip003Plugin_PluginWithOpts() | |||
{ | |||
var PluginWithOpts = Sip003Plugin.CreateIfConfigured( | |||
new Server | |||
{ | |||
server = "192.168.100.1", | |||
server_port = 8888, | |||
password = "test", | |||
method = "bf-cfb", | |||
plugin = fake_plugin, | |||
plugin_opts = "_option" | |||
}, | |||
false); | |||
RunPluginSupportTest( | |||
PluginWithOpts, | |||
fake_plugin, | |||
"_option", | |||
"", | |||
"192.168.100.1", | |||
8888); | |||
} | |||
[TestMethod] | |||
public void TestSip003Plugin_PluginWithArgs() | |||
{ | |||
var PluginWithArgs = Sip003Plugin.CreateIfConfigured( | |||
new Server | |||
{ | |||
server = "192.168.100.1", | |||
server_port = 8888, | |||
password = "test", | |||
method = "bf-cfb", | |||
plugin = fake_plugin, | |||
plugin_args = "_test" | |||
}, | |||
false); | |||
RunPluginSupportTest( | |||
PluginWithArgs, | |||
fake_plugin, | |||
"", | |||
"_test", | |||
"192.168.100.1", | |||
8888); | |||
} | |||
[TestMethod] | |||
public void TestSip003Plugin_PluginWithOptsAndArgs() | |||
{ | |||
var PluginWithOptsAndArgs = Sip003Plugin.CreateIfConfigured( | |||
new Server | |||
{ | |||
server = "192.168.100.1", | |||
server_port = 8888, | |||
password = "test", | |||
method = "bf-cfb", | |||
plugin = fake_plugin, | |||
plugin_opts = "_option", | |||
plugin_args = "_test" | |||
}, | |||
false); | |||
RunPluginSupportTest( | |||
PluginWithOptsAndArgs, | |||
fake_plugin, | |||
"_option", | |||
"_test", | |||
"192.168.100.1", | |||
8888); | |||
} | |||
[TestMethod] | |||
public void TestSip003Plugin_PluginWithArgsReplaced() | |||
{ | |||
var PluginWithArgsReplaced = Sip003Plugin.CreateIfConfigured( | |||
new Server | |||
{ | |||
server = "192.168.100.1", | |||
server_port = 8888, | |||
password = "test", | |||
method = "bf-cfb", | |||
plugin = fake_plugin, | |||
plugin_args = "_test,%SS_REMOTE_HOST%" | |||
}, | |||
false); | |||
RunPluginSupportTest( | |||
PluginWithArgsReplaced, | |||
fake_plugin, | |||
"", | |||
"_test,192.168.100.1", | |||
"192.168.100.1", | |||
8888); | |||
} | |||
[TestMethod] | |||
public void TestSip003Plugin_PluginWithOptsAndArgsReplaced() | |||
{ | |||
var PluginWithOptsAndArgsReplaced = Sip003Plugin.CreateIfConfigured( | |||
new Server | |||
{ | |||
server = "192.168.100.1", | |||
server_port = 8888, | |||
password = "test", | |||
method = "bf-cfb", | |||
plugin = fake_plugin, | |||
plugin_opts = "_option", | |||
plugin_args = "_test,%SS_REMOTE_HOST%,%SS_PLUGIN_OPTIONS%" | |||
}, | |||
false); | |||
RunPluginSupportTest( | |||
PluginWithOptsAndArgsReplaced, | |||
fake_plugin, | |||
"_option", | |||
"_test,192.168.100.1,_option", | |||
"192.168.100.1", | |||
8888); | |||
} | |||
private static void RunPluginSupportTest(Sip003Plugin plugin, string pluginName, string pluginOpts, string pluginArgs, string serverAddress, int serverPort) | |||
{ | |||
if (string.IsNullOrWhiteSpace(pluginName)) return; | |||
plugin.StartIfNeeded(); | |||
Process[] processes = Process.GetProcessesByName(pluginName); | |||
Assert.AreEqual(processes.Length, 1); | |||
Process p = processes[0]; | |||
var penv = ProcessEnvironment.ReadEnvironmentVariables(p); | |||
var pcmd = ProcessEnvironment.GetCommandLine(p).Trim(); | |||
pcmd = pcmd.IndexOf(' ') >= 0 ? pcmd.Substring(pcmd.IndexOf(' ') + 1) : ""; | |||
Assert.AreEqual(penv["SS_REMOTE_HOST"], serverAddress); | |||
Assert.AreEqual(penv["SS_REMOTE_PORT"], serverPort.ToString()); | |||
Assert.AreEqual(penv["SS_LOCAL_HOST"], IPAddress.Loopback.ToString()); | |||
int _ignored; | |||
Assert.IsTrue(int.TryParse(penv["SS_LOCAL_PORT"], out _ignored)); | |||
Assert.AreEqual(penv["SS_PLUGIN_OPTIONS"], pluginOpts); | |||
Assert.AreEqual(pcmd, pluginArgs); | |||
plugin.Dispose(); | |||
for (int i = 0; i < 50; i++) | |||
{ | |||
if (Process.GetProcessesByName(pluginName).Length == 0) return; | |||
Thread.Sleep(50); | |||
} | |||
} | |||
} | |||
} |
@@ -1,41 +0,0 @@ | |||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace Shadowsocks.Test | |||
{ | |||
class TestUtils | |||
{ | |||
public static void ArrayEqual<T>(IEnumerable<T> expected, IEnumerable<T> actual, string msg = "") | |||
{ | |||
var e1 = expected.GetEnumerator(); | |||
var e2 = actual.GetEnumerator(); | |||
int ctr = 0; | |||
while (true) | |||
{ | |||
var e1next = e1.MoveNext(); | |||
var e2next = e2.MoveNext(); | |||
if (e1next && e2next) | |||
{ | |||
Assert.AreEqual(e1.Current, e2.Current, "at " + ctr); | |||
} | |||
else if (!e1next && !e2next) | |||
{ | |||
return; | |||
} | |||
else if (!e1next) | |||
{ | |||
Assert.Fail($"actual longer than expected ({ctr}) {msg}"); | |||
} | |||
else | |||
{ | |||
Assert.Fail($"actual shorter than expected ({ctr}) {msg}"); | |||
} | |||
ctr++; | |||
} | |||
} | |||
} | |||
} |
@@ -1,45 +0,0 @@ | |||
using System; | |||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||
using Shadowsocks.Controller; | |||
using GlobalHotKey; | |||
using System.Windows.Input; | |||
using System.Threading; | |||
using System.Collections.Generic; | |||
using Shadowsocks.Controller.Hotkeys; | |||
using System.Diagnostics; | |||
namespace Shadowsocks.Test | |||
{ | |||
[TestClass] | |||
public class UnitTest | |||
{ | |||
[TestMethod] | |||
public void TestHotKey2Str() | |||
{ | |||
Assert.AreEqual("Ctrl+A", HotKeys.HotKey2Str(Key.A, ModifierKeys.Control)); | |||
Assert.AreEqual("Ctrl+Alt+D2", HotKeys.HotKey2Str(Key.D2, (ModifierKeys.Alt | ModifierKeys.Control))); | |||
Assert.AreEqual("Ctrl+Alt+Shift+NumPad7", HotKeys.HotKey2Str(Key.NumPad7, (ModifierKeys.Alt | ModifierKeys.Control | ModifierKeys.Shift))); | |||
Assert.AreEqual("Ctrl+Alt+Shift+F6", HotKeys.HotKey2Str(Key.F6, (ModifierKeys.Alt | ModifierKeys.Control | ModifierKeys.Shift))); | |||
Assert.AreNotEqual("Ctrl+Shift+Alt+F6", HotKeys.HotKey2Str(Key.F6, (ModifierKeys.Alt | ModifierKeys.Control | ModifierKeys.Shift))); | |||
} | |||
[TestMethod] | |||
public void TestStr2HotKey() | |||
{ | |||
Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+A").Equals(new HotKey(Key.A, ModifierKeys.Control))); | |||
Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+Alt+A").Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Alt)))); | |||
Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+Shift+A").Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Shift)))); | |||
Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+Alt+Shift+A").Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Alt | ModifierKeys.Shift)))); | |||
HotKey testKey0 = HotKeys.Str2HotKey("Ctrl+Alt+Shift+A"); | |||
Assert.IsTrue(testKey0 != null && testKey0.Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Alt | ModifierKeys.Shift)))); | |||
HotKey testKey1 = HotKeys.Str2HotKey("Ctrl+Alt+Shift+F2"); | |||
Assert.IsTrue(testKey1 != null && testKey1.Equals(new HotKey(Key.F2, (ModifierKeys.Control | ModifierKeys.Alt | ModifierKeys.Shift)))); | |||
HotKey testKey2 = HotKeys.Str2HotKey("Ctrl+Shift+Alt+D7"); | |||
Assert.IsTrue(testKey2 != null && testKey2.Equals(new HotKey(Key.D7, (ModifierKeys.Control | ModifierKeys.Alt | ModifierKeys.Shift)))); | |||
HotKey testKey3 = HotKeys.Str2HotKey("Ctrl+Shift+Alt+NumPad7"); | |||
Assert.IsTrue(testKey3 != null && testKey3.Equals(new HotKey(Key.NumPad7, (ModifierKeys.Control | ModifierKeys.Alt | ModifierKeys.Shift)))); | |||
} | |||
} | |||
} |
@@ -1,252 +0,0 @@ | |||
using System; | |||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||
using Shadowsocks.Controller; | |||
using System.Threading; | |||
using System.Collections.Generic; | |||
using Shadowsocks.Model; | |||
using System.Diagnostics; | |||
namespace Shadowsocks.Test | |||
{ | |||
[TestClass] | |||
public class UrlTest | |||
{ | |||
Server server1, server1WithRemark, server1WithPlugin, server1WithPluginAndRemark; | |||
string server1CanonUrl, server1WithRemarkCanonUrl, server1WithPluginCanonUrl, server1WithPluginAndRemarkCanonUrl; | |||
Server server2, server2WithRemark, server2WithPlugin, server2WithPluginAndRemark; | |||
string server2CanonUrl, server2WithRemarkCanonUrl, server2WithPluginCanonUrl, server2WithPluginAndRemarkCanonUrl; | |||
[TestInitialize] | |||
public void PrepareTestData() | |||
{ | |||
server1 = new Server | |||
{ | |||
server = "192.168.100.1", | |||
server_port = 8888, | |||
password = "test", | |||
method = "bf-cfb" | |||
}; | |||
server1CanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4"; | |||
// server2 has base64 padding | |||
server2 = new Server | |||
{ | |||
server = "192.168.1.1", | |||
server_port = 8388, | |||
password = "test", | |||
method = "bf-cfb" | |||
}; | |||
server2CanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA=="; | |||
server1WithRemark = new Server | |||
{ | |||
server = server1.server, | |||
server_port = server1.server_port, | |||
password = server1.password, | |||
method = server1.method, | |||
remarks = "example-server 1" | |||
}; | |||
server1WithRemarkCanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4#example-server+1"; | |||
server2WithRemark = new Server | |||
{ | |||
server = server2.server, | |||
server_port = server2.server_port, | |||
password = server2.password, | |||
method = server2.method, | |||
remarks = "example-server 2" | |||
}; | |||
server2WithRemarkCanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==#example-server+2"; | |||
server1WithPlugin = new Server | |||
{ | |||
server = server1.server, | |||
server_port = server1.server_port, | |||
password = server1.password, | |||
method = server1.method, | |||
plugin = "obfs-local", | |||
plugin_opts = "obfs=http;obfs-host=google.com" | |||
}; | |||
server1WithPluginCanonUrl = | |||
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com"; | |||
server2WithPlugin = new Server | |||
{ | |||
server = server2.server, | |||
server_port = server2.server_port, | |||
password = server2.password, | |||
method = server2.method, | |||
plugin = "obfs-local", | |||
plugin_opts = "obfs=http;obfs-host=google.com" | |||
}; | |||
server2WithPluginCanonUrl = | |||
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com"; | |||
server1WithPluginAndRemark = new Server | |||
{ | |||
server = server1.server, | |||
server_port = server1.server_port, | |||
password = server1.password, | |||
method = server1.method, | |||
plugin = server1WithPlugin.plugin, | |||
plugin_opts = server1WithPlugin.plugin_opts, | |||
remarks = server1WithRemark.remarks | |||
}; | |||
server1WithPluginAndRemarkCanonUrl = | |||
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com#example-server+1"; | |||
server2WithPluginAndRemark = new Server | |||
{ | |||
server = server2.server, | |||
server_port = server2.server_port, | |||
password = server2.password, | |||
method = server2.method, | |||
plugin = server2WithPlugin.plugin, | |||
plugin_opts = server2WithPlugin.plugin_opts, | |||
remarks = server2WithRemark.remarks | |||
}; | |||
server2WithPluginAndRemarkCanonUrl = | |||
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com#example-server+2"; | |||
} | |||
[TestMethod] | |||
public void TestParseUrl_Server1() | |||
{ | |||
RunParseShadowsocksUrlTest( | |||
string.Join( | |||
"\r\n", | |||
server1CanonUrl, | |||
"\r\n", | |||
"ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4/", | |||
server1WithRemarkCanonUrl, | |||
"ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4/#example-server+1"), | |||
new[] | |||
{ | |||
server1, | |||
server1, | |||
server1WithRemark, | |||
server1WithRemark | |||
}); | |||
RunParseShadowsocksUrlTest( | |||
string.Join( | |||
"\r\n", | |||
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888", | |||
"\r\n", | |||
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/", | |||
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888#example-server+1", | |||
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/#example-server+1", | |||
server1WithPluginCanonUrl, | |||
server1WithPluginAndRemarkCanonUrl, | |||
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com&unsupported=1#example-server+1"), | |||
new[] | |||
{ | |||
server1, | |||
server1, | |||
server1WithRemark, | |||
server1WithRemark, | |||
server1WithPlugin, | |||
server1WithPluginAndRemark, | |||
server1WithPluginAndRemark | |||
}); | |||
} | |||
[TestMethod] | |||
public void TestParseUrl_Server2() | |||
{ | |||
RunParseShadowsocksUrlTest( | |||
string.Join( | |||
"\r\n", | |||
server2CanonUrl, | |||
"\r\n", | |||
"ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==/", | |||
server2WithRemarkCanonUrl, | |||
"ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==/#example-server+2"), | |||
new[] | |||
{ | |||
server2, | |||
server2, | |||
server2WithRemark, | |||
server2WithRemark | |||
}); | |||
RunParseShadowsocksUrlTest( | |||
string.Join( | |||
"\r\n", | |||
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388", | |||
"\r\n", | |||
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/", | |||
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388#example-server+2", | |||
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/#example-server+2", | |||
server2WithPluginCanonUrl, | |||
server2WithPluginAndRemarkCanonUrl, | |||
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com&unsupported=1#example-server+2"), | |||
new[] | |||
{ | |||
server2, | |||
server2, | |||
server2WithRemark, | |||
server2WithRemark, | |||
server2WithPlugin, | |||
server2WithPluginAndRemark, | |||
server2WithPluginAndRemark | |||
}); | |||
} | |||
[TestMethod] | |||
public void TestUrlGenerate() | |||
{ | |||
var generateUrlCases = new Dictionary<string, Server> | |||
{ | |||
[server1CanonUrl] = server1, | |||
[server1WithRemarkCanonUrl] = server1WithRemark, | |||
[server1WithPluginCanonUrl] = server1WithPlugin, | |||
[server1WithPluginAndRemarkCanonUrl] = server1WithPluginAndRemark | |||
}; | |||
RunGenerateShadowsocksUrlTest(generateUrlCases); | |||
} | |||
private static void RunParseShadowsocksUrlTest(string testCase, IReadOnlyList<Server> expected) | |||
{ | |||
var actual = Server.GetServers(testCase); | |||
if (actual.Count != expected.Count) | |||
{ | |||
Assert.Fail("Wrong number of configs. Expected: {0}. Actual: {1}", expected.Count, actual.Count); | |||
} | |||
for (int i = 0; i < expected.Count; i++) | |||
{ | |||
var expectedServer = expected[i]; | |||
var actualServer = actual[i]; | |||
Assert.AreEqual(expectedServer.server, actualServer.server); | |||
Assert.AreEqual(expectedServer.server_port, actualServer.server_port); | |||
Assert.AreEqual(expectedServer.password, actualServer.password); | |||
Assert.AreEqual(expectedServer.method, actualServer.method); | |||
Assert.AreEqual(expectedServer.plugin, actualServer.plugin); | |||
Assert.AreEqual(expectedServer.plugin_opts, actualServer.plugin_opts); | |||
Assert.AreEqual(expectedServer.remarks, actualServer.remarks); | |||
Assert.AreEqual(expectedServer.timeout, actualServer.timeout); | |||
} | |||
} | |||
private static void RunGenerateShadowsocksUrlTest(IReadOnlyDictionary<string, Server> testCases) | |||
{ | |||
foreach (var testCase in testCases) | |||
{ | |||
string expected = testCase.Key; | |||
Server config = testCase.Value; | |||
var actual = config.GetURL(true); | |||
Assert.AreEqual(expected, actual); | |||
} | |||
} | |||
} | |||
} |