Browse Source

🚮 Remove unused projects

pull/3127/head
database64128 3 years ago
parent
commit
fafaefaf59
No known key found for this signature in database GPG Key ID: 1CA27546BEDB8B01
29 changed files with 1 additions and 6801 deletions
  1. +0
    -10
      shadowsocks-csharp/CommandLineOption.cs
  2. +0
    -733
      shadowsocks-csharp/Controller/ShadowsocksController.cs
  3. +0
    -157
      shadowsocks-csharp/Data/i18n.csv
  4. +0
    -382
      shadowsocks-csharp/Model/Configuration.cs
  5. +0
    -215
      shadowsocks-csharp/Program.cs
  6. +0
    -652
      shadowsocks-csharp/View/ConfigForm.Designer.cs
  7. +0
    -552
      shadowsocks-csharp/View/ConfigForm.cs
  8. +0
    -126
      shadowsocks-csharp/View/ConfigForm.resx
  9. +0
    -100
      shadowsocks-csharp/View/InputBox.Designer.cs
  10. +0
    -24
      shadowsocks-csharp/View/InputBox.cs
  11. +0
    -120
      shadowsocks-csharp/View/InputBox.resx
  12. +0
    -332
      shadowsocks-csharp/View/LogForm.Designer.cs
  13. +0
    -447
      shadowsocks-csharp/View/LogForm.cs
  14. +0
    -150
      shadowsocks-csharp/View/LogForm.resx
  15. +0
    -1001
      shadowsocks-csharp/View/MenuViewController.cs
  16. +0
    -73
      shadowsocks-csharp/app.config
  17. +0
    -76
      shadowsocks-csharp/app.manifest
  18. +0
    -19
      shadowsocks-csharp/packages.config
  19. +0
    -75
      shadowsocks-csharp/shadowsocks-csharp.csproj
  20. +1
    -12
      shadowsocks-windows.sln
  21. +0
    -14
      test/App.config
  22. +0
    -84
      test/CachedNetworkStreamTest.cs
  23. +0
    -141
      test/CryptographyTest.cs
  24. +0
    -713
      test/ProcessEnvironment.cs
  25. +0
    -34
      test/ShadowsocksTest.csproj
  26. +0
    -221
      test/Sip003PluginTest.cs
  27. +0
    -41
      test/TestUtils.cs
  28. +0
    -45
      test/UnitTest.cs
  29. +0
    -252
      test/UrlTest.cs

+ 0
- 10
shadowsocks-csharp/CommandLineOption.cs View File

@@ -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; }
}
}

+ 0
- 733
shadowsocks-csharp/Controller/ShadowsocksController.cs View File

@@ -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
}
}

+ 0
- 157
shadowsocks-csharp/Data/i18n.csv View File

@@ -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"

+ 0
- 382
shadowsocks-csharp/Model/Configuration.cs View File

@@ -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));
}
}
}

+ 0
- 215
shadowsocks-csharp/Program.cs View File

@@ -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;
}
}
}
}

+ 0
- 652
shadowsocks-csharp/View/ConfigForm.Designer.cs View File

@@ -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;
}
}

+ 0
- 552
shadowsocks-csharp/View/ConfigForm.cs View File

@@ -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);
}
}
}

+ 0
- 126
shadowsocks-csharp/View/ConfigForm.resx View File

@@ -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>

+ 0
- 100
shadowsocks-csharp/View/InputBox.Designer.cs View File

@@ -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;
}
}

+ 0
- 24
shadowsocks-csharp/View/InputBox.cs View File

@@ -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; } }
}
}

+ 0
- 120
shadowsocks-csharp/View/InputBox.resx View File

@@ -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>

+ 0
- 332
shadowsocks-csharp/View/LogForm.Designer.cs View File

@@ -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;
}
}

+ 0
- 447
shadowsocks-csharp/View/LogForm.cs View File

@@ -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;
}
}
}
}

+ 0
- 150
shadowsocks-csharp/View/LogForm.resx View File

@@ -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>

+ 0
- 1001
shadowsocks-csharp/View/MenuViewController.cs
File diff suppressed because it is too large
View File


+ 0
- 73
shadowsocks-csharp/app.config View File

@@ -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>

+ 0
- 76
shadowsocks-csharp/app.manifest View File

@@ -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>

+ 0
- 19
shadowsocks-csharp/packages.config View File

@@ -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>

+ 0
- 75
shadowsocks-csharp/shadowsocks-csharp.csproj View File

@@ -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 &amp; 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>

+ 1
- 12
shadowsocks-windows.sln View File

@@ -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


+ 0
- 14
test/App.config View File

@@ -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>

+ 0
- 84
test/CachedNetworkStreamTest.cs View File

@@ -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));
}
}
}

+ 0
- 141
test/CryptographyTest.cs View File

@@ -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");
}
}
}

+ 0
- 713
test/ProcessEnvironment.cs View File

@@ -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);
}
}
}

+ 0
- 34
test/ShadowsocksTest.csproj View File

@@ -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>

+ 0
- 221
test/Sip003PluginTest.cs View File

@@ -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);
}
}
}
}

+ 0
- 41
test/TestUtils.cs View File

@@ -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++;
}
}

}
}

+ 0
- 45
test/UnitTest.cs View File

@@ -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))));
}
}
}

+ 0
- 252
test/UrlTest.cs View File

@@ -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);
}
}
}
}

Loading…
Cancel
Save