Conflicts: shadowsocks-csharp/Controller/Local.cs shadowsocks-csharp/Controller/PACServer.cs shadowsocks-csharp/Controller/PolipoRunner.cs shadowsocks-csharp/Controller/ShadowsocksController.cs shadowsocks-csharp/Program.cs shadowsocks-csharp/View/ConfigForm.Designer.cs shadowsocks-csharp/View/ConfigForm.cspull/44/head
@@ -1,6 +1,7 @@ | |||||
Backup/ | Backup/ | ||||
shadowsocks-csharp/bin/ | |||||
shadowsocks-csharp/obj/ | |||||
bin/ | |||||
obj/ | |||||
shadowsocks-csharp/shadowsocks-csharp.csproj.user | shadowsocks-csharp/shadowsocks-csharp.csproj.user | ||||
TestResults | |||||
*.suo | *.suo | ||||
@@ -1,12 +1,17 @@ | |||||
2.0.4 | |||||
2.0.5 2014-11-09 | |||||
- Fix QRCode size | |||||
- Share over LAN option | |||||
- Log to temp path instead | |||||
2.0.4 2014-11-09 | |||||
- Try to fix data corruption | - Try to fix data corruption | ||||
- Remove all configuration except x86 | - Remove all configuration except x86 | ||||
2.0.3 | |||||
2.0.3 2014-11-08 | |||||
- Support QRCode generation | - Support QRCode generation | ||||
- Fix compatibility issues with some Chrome version | - Fix compatibility issues with some Chrome version | ||||
2.0.2 | |||||
2.0.2 2014-11-08 | |||||
- Add remarks | - Add remarks | ||||
- Fix error when polipo is killed | - Fix error when polipo is killed | ||||
@@ -20,6 +20,9 @@ For Windows 7 and older, please download Shadowsocks-win-x.x.x.zip. | |||||
For Windows 8.1 and newer, please download Shadowsocks-win-dotnet4.0-x.x.x.zip. | For Windows 8.1 and newer, please download Shadowsocks-win-dotnet4.0-x.x.x.zip. | ||||
Notice there's a bug on .Net 4.0 version. If you encounter crashes, try using | |||||
.Net 2.0 version. Please help us resolve this issue if you have any clue. | |||||
### Usage | ### Usage | ||||
1. Find Shadowsocks icon in notification tray | 1. Find Shadowsocks icon in notification tray | ||||
@@ -3,6 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 | |||||
# Visual Studio Express 2012 for Windows Desktop | # Visual Studio Express 2012 for Windows Desktop | ||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "shadowsocks-csharp", "shadowsocks-csharp\shadowsocks-csharp.csproj", "{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}" | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "shadowsocks-csharp", "shadowsocks-csharp\shadowsocks-csharp.csproj", "{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}" | ||||
EndProject | EndProject | ||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "test", "test\test.csproj", "{45913187-0685-4903-B250-DCEF0479CD86}" | |||||
ProjectSection(ProjectDependencies) = postProject | |||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062} = {8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062} | |||||
EndProjectSection | |||||
EndProject | |||||
Global | Global | ||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||
Debug|x86 = Debug|x86 | Debug|x86 = Debug|x86 | ||||
@@ -14,6 +19,10 @@ Global | |||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x86.Deploy.0 = Debug|x86 | {8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x86.Deploy.0 = Debug|x86 | ||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Release|x86.ActiveCfg = Release|x86 | {8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Release|x86.ActiveCfg = Release|x86 | ||||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Release|x86.Build.0 = Release|x86 | {8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Release|x86.Build.0 = Release|x86 | ||||
{45913187-0685-4903-B250-DCEF0479CD86}.Debug|x86.ActiveCfg = Debug|x86 | |||||
{45913187-0685-4903-B250-DCEF0479CD86}.Debug|x86.Build.0 = Debug|x86 | |||||
{45913187-0685-4903-B250-DCEF0479CD86}.Release|x86.ActiveCfg = Release|x86 | |||||
{45913187-0685-4903-B250-DCEF0479CD86}.Release|x86.Build.0 = Release|x86 | |||||
EndGlobalSection | EndGlobalSection | ||||
GlobalSection(SolutionProperties) = preSolution | GlobalSection(SolutionProperties) = preSolution | ||||
HideSolutionNode = FALSE | HideSolutionNode = FALSE | ||||
@@ -10,14 +10,15 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
class Local | class Local | ||||
{ | |||||
private Server config; | |||||
public bool openOnLan; | |||||
{ | |||||
private Server _server; | |||||
private bool _shareOverLAN; | |||||
//private Encryptor encryptor; | //private Encryptor encryptor; | ||||
Socket _listener; | Socket _listener; | ||||
public Local(Server config) | |||||
public Local(Configuration config) | |||||
{ | { | ||||
this.config = config; | |||||
this._server = config.GetCurrentServer(); | |||||
_shareOverLAN = config.shareOverLan; | |||||
//this.encryptor = new Encryptor(config.method, config.password); | //this.encryptor = new Encryptor(config.method, config.password); | ||||
} | } | ||||
@@ -25,17 +26,17 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
try | try | ||||
{ | { | ||||
// Create a TCP/IP socket. | |||||
_listener = new Socket(AddressFamily.InterNetwork, | |||||
SocketType.Stream, ProtocolType.Tcp); | |||||
// Create a TCP/IP socket. | |||||
_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); | |||||
_listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); | |||||
IPEndPoint localEndPoint = null; | IPEndPoint localEndPoint = null; | ||||
if (openOnLan) | |||||
if (_shareOverLAN) | |||||
{ | { | ||||
localEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), config.local_port); | |||||
localEndPoint = new IPEndPoint(IPAddress.Any, _server.local_port); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
localEndPoint = new IPEndPoint(IPAddress.Loopback, config.local_port); | |||||
localEndPoint = new IPEndPoint(IPAddress.Loopback, _server.local_port); | |||||
} | } | ||||
// Bind the socket to the local endpoint and listen for incoming connections. | // Bind the socket to the local endpoint and listen for incoming connections. | ||||
@@ -67,37 +68,19 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
try | try | ||||
{ | { | ||||
// Get the socket that handles the client request. | |||||
Socket listener = (Socket)ar.AsyncState; | Socket listener = (Socket)ar.AsyncState; | ||||
//if (!listener.Connected) | |||||
//{ | |||||
// return; | |||||
//} | |||||
Socket conn = listener.EndAccept(ar); | Socket conn = listener.EndAccept(ar); | ||||
listener.BeginAccept( | listener.BeginAccept( | ||||
new AsyncCallback(AcceptCallback), | new AsyncCallback(AcceptCallback), | ||||
listener); | listener); | ||||
// Create the state object. | |||||
Handler handler = new Handler(); | Handler handler = new Handler(); | ||||
handler.connection = conn; | handler.connection = conn; | ||||
//if (encryptor.method == "table") | |||||
//{ | |||||
// handler.encryptor = encryptor; | |||||
//} | |||||
//else | |||||
//{ | |||||
// handler.encryptor = new Encryptor(config.method, config.password); | |||||
//} | |||||
handler.encryptor = EncryptorFactory.GetEncryptor(config.method, config.password); | |||||
handler.config = config; | |||||
handler.encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password); | |||||
handler.config = _server; | |||||
handler.Start(); | handler.Start(); | ||||
//handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, | |||||
// new AsyncCallback(ReadCallback), state); | |||||
} | } | ||||
catch | catch | ||||
{ | { | ||||
@@ -331,7 +314,7 @@ namespace Shadowsocks.Controller | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
Console.WriteLine("bytesRead: " + bytesRead.ToString()); | |||||
//Console.WriteLine("bytesRead: " + bytesRead.ToString()); | |||||
this.Close(); | this.Close(); | ||||
} | } | ||||
} | } | ||||
@@ -0,0 +1,34 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.IO; | |||||
using System.Text; | |||||
namespace Shadowsocks.Controller | |||||
{ | |||||
public class Logging | |||||
{ | |||||
public static string LogFile; | |||||
public static bool OpenLogFile() | |||||
{ | |||||
try | |||||
{ | |||||
string temppath = Path.GetTempPath(); | |||||
LogFile = Path.Combine(temppath, "shadowsocks.log"); | |||||
FileStream fs = new FileStream(LogFile, FileMode.Append); | |||||
TextWriter tmp = Console.Out; | |||||
StreamWriter sw = new StreamWriter(fs); | |||||
sw.AutoFlush = true; | |||||
Console.SetOut(sw); | |||||
Console.SetError(sw); | |||||
return true; | |||||
} | |||||
catch (IOException e) | |||||
{ | |||||
Console.WriteLine(e.ToString()); | |||||
return false; | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -1,4 +1,5 @@ | |||||
using Shadowsocks.Properties; | |||||
using Shadowsocks.Model; | |||||
using Shadowsocks.Properties; | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Diagnostics; | using System.Diagnostics; | ||||
@@ -12,51 +13,51 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
class PACServer | class PACServer | ||||
{ | { | ||||
private static int PORT = 8090; | |||||
private static string PAC_FILE = "pac.txt"; | private static string PAC_FILE = "pac.txt"; | ||||
public bool openOnLan; | |||||
Socket _listener; | Socket _listener; | ||||
FileSystemWatcher watcher; | FileSystemWatcher watcher; | ||||
public event EventHandler PACFileChanged; | public event EventHandler PACFileChanged; | ||||
public void Start() | |||||
public void Start(Configuration configuration) | |||||
{ | { | ||||
// Create a TCP/IP socket. | |||||
_listener = new Socket(AddressFamily.InterNetwork, | |||||
SocketType.Stream, ProtocolType.Tcp); | |||||
_listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); | |||||
IPEndPoint localEndPoint = null; | |||||
if (openOnLan) | |||||
try | |||||
{ | { | ||||
localEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 8090); | |||||
// Create a TCP/IP socket. | |||||
_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); | |||||
_listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); | |||||
IPEndPoint localEndPoint = null; | |||||
if (configuration.shareOverLan) | |||||
{ | |||||
localEndPoint = new IPEndPoint(IPAddress.Any, PORT); | |||||
} | |||||
else | |||||
{ | |||||
localEndPoint = new IPEndPoint(IPAddress.Loopback, PORT); | |||||
} | |||||
// Bind the socket to the local endpoint and listen for incoming connections. | |||||
_listener.Bind(localEndPoint); | |||||
_listener.Listen(100); | |||||
_listener.BeginAccept( | |||||
new AsyncCallback(AcceptCallback), | |||||
_listener); | |||||
WatchPacFile(); | |||||
} | } | ||||
else | |||||
catch (SocketException) | |||||
{ | { | ||||
localEndPoint = new IPEndPoint(IPAddress.Loopback, 8090); | |||||
_listener.Close(); | |||||
throw; | |||||
} | } | ||||
// Bind the socket to the local endpoint and listen for incoming connections. | |||||
_listener.Bind(localEndPoint); | |||||
_listener.Listen(100); | |||||
_listener.BeginAccept( | |||||
new AsyncCallback(AcceptCallback), | |||||
_listener); | |||||
WatchPacFile(); | |||||
} | } | ||||
public void Stop() | public void Stop() | ||||
{ | { | ||||
try | |||||
{ | |||||
_listener.Close(); | |||||
} | |||||
catch (Exception) | |||||
{ | |||||
throw; | |||||
} | |||||
_listener.Close(); | |||||
_listener = null; | |||||
} | } | ||||
public string TouchPACFile() | public string TouchPACFile() | ||||
@@ -78,10 +79,10 @@ namespace Shadowsocks.Controller | |||||
try | try | ||||
{ | { | ||||
Socket listener = (Socket)ar.AsyncState; | Socket listener = (Socket)ar.AsyncState; | ||||
Socket conn = listener.EndAccept(ar); | |||||
listener.BeginAccept( | listener.BeginAccept( | ||||
new AsyncCallback(AcceptCallback), | new AsyncCallback(AcceptCallback), | ||||
listener); | listener); | ||||
Socket conn = listener.EndAccept(ar); | |||||
conn.BeginReceive(new byte[1024], 0, 1024, 0, | conn.BeginReceive(new byte[1024], 0, 1024, 0, | ||||
new AsyncCallback(ReceiveCallback), conn); | new AsyncCallback(ReceiveCallback), conn); | ||||
@@ -115,7 +116,6 @@ namespace Shadowsocks.Controller | |||||
return System.Text.Encoding.UTF8.GetString(buffer, 0, n); | return System.Text.Encoding.UTF8.GetString(buffer, 0, n); | ||||
} | } | ||||
} | } | ||||
WatchPacFile(); | |||||
} | } | ||||
private void ReceiveCallback(IAsyncResult ar) | private void ReceiveCallback(IAsyncResult ar) | ||||
@@ -127,7 +127,9 @@ namespace Shadowsocks.Controller | |||||
string pac = GetPACContent(); | string pac = GetPACContent(); | ||||
string proxy = "PROXY 127.0.0.1:8123;"; | |||||
IPEndPoint localEndPoint = (IPEndPoint)conn.LocalEndPoint; | |||||
string proxy = "PROXY " + localEndPoint.Address + ":8123;"; | |||||
pac = pac.Replace("__PROXY__", proxy); | pac = pac.Replace("__PROXY__", proxy); | ||||
@@ -14,8 +14,9 @@ namespace Shadowsocks.Controller | |||||
private Process _process; | private Process _process; | ||||
public bool openOnLan; | public bool openOnLan; | ||||
public void Start(Server config) | |||||
public void Start(Configuration configuration) | |||||
{ | { | ||||
Server server = configuration.GetCurrentServer(); | |||||
if (_process == null) | if (_process == null) | ||||
{ | { | ||||
Process[] existingPolipo = Process.GetProcessesByName("ss_polipo"); | Process[] existingPolipo = Process.GetProcessesByName("ss_polipo"); | ||||
@@ -31,17 +32,10 @@ namespace Shadowsocks.Controller | |||||
Console.WriteLine(e.ToString()); | Console.WriteLine(e.ToString()); | ||||
} | } | ||||
} | } | ||||
string temppath = Path.GetTempPath(); | |||||
string polipoConfig = Resources.polipo_config; | |||||
polipoConfig = polipoConfig.Replace("__SOCKS_PORT__", config.local_port.ToString()); | |||||
if (openOnLan) | |||||
{ | |||||
polipoConfig = polipoConfig.Replace("\"127.0.0.1\"", "\"0.0.0.0\""); | |||||
} | |||||
else | |||||
{ | |||||
polipoConfig = polipoConfig.Replace("\"0.0.0.0\"", "\"127.0.0.1\""); | |||||
} | |||||
string temppath = Path.GetTempPath(); | |||||
string polipoConfig = Resources.polipo_config; | |||||
polipoConfig = polipoConfig.Replace("__SOCKS_PORT__", server.local_port.ToString()); | |||||
polipoConfig = polipoConfig.Replace("__POLIPO_BIND_IP__", configuration.shareOverLan ? "0.0.0.0" : "127.0.0.1"); | |||||
FileManager.ByteArrayToFile(temppath + "/polipo.conf", System.Text.Encoding.UTF8.GetBytes(polipoConfig)); | FileManager.ByteArrayToFile(temppath + "/polipo.conf", System.Text.Encoding.UTF8.GetBytes(polipoConfig)); | ||||
FileManager.UncompressFile(temppath + "/ss_polipo.exe", Resources.polipo_exe); | FileManager.UncompressFile(temppath + "/ss_polipo.exe", Resources.polipo_exe); | ||||
@@ -50,11 +44,10 @@ namespace Shadowsocks.Controller | |||||
_process.StartInfo.FileName = temppath + "/ss_polipo.exe"; | _process.StartInfo.FileName = temppath + "/ss_polipo.exe"; | ||||
_process.StartInfo.Arguments = "-c \"" + temppath + "/polipo.conf\""; | _process.StartInfo.Arguments = "-c \"" + temppath + "/polipo.conf\""; | ||||
_process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; | _process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; | ||||
_process.StartInfo.UseShellExecute = false; | |||||
_process.StartInfo.UseShellExecute = true; | |||||
_process.StartInfo.CreateNoWindow = true; | _process.StartInfo.CreateNoWindow = true; | ||||
_process.StartInfo.RedirectStandardOutput = true; | |||||
_process.StartInfo.RedirectStandardError = true; | |||||
//process.StandardOutput | |||||
//_process.StartInfo.RedirectStandardOutput = true; | |||||
//_process.StartInfo.RedirectStandardError = true; | |||||
_process.Start(); | _process.Start(); | ||||
} | } | ||||
} | } | ||||
@@ -3,6 +3,7 @@ using Shadowsocks.Model; | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Text; | using System.Text; | ||||
using System.Threading; | |||||
namespace Shadowsocks.Controller | namespace Shadowsocks.Controller | ||||
{ | { | ||||
@@ -27,6 +28,7 @@ namespace Shadowsocks.Controller | |||||
public event EventHandler ConfigChanged; | public event EventHandler ConfigChanged; | ||||
public event EventHandler EnableStatusChanged; | public event EventHandler EnableStatusChanged; | ||||
public event EventHandler ShareOverLANStatusChanged; | |||||
// when user clicked Edit PAC, and PAC file has already created | // when user clicked Edit PAC, and PAC file has already created | ||||
public event EventHandler<PathEventArgs> PACFileReadyToOpen; | public event EventHandler<PathEventArgs> PACFileReadyToOpen; | ||||
@@ -40,19 +42,15 @@ namespace Shadowsocks.Controller | |||||
} | } | ||||
openOnLan = _config.openOnLan; | openOnLan = _config.openOnLan; | ||||
polipoRunner = new PolipoRunner(); | |||||
polipoRunner.openOnLan = openOnLan; | |||||
polipoRunner.Start(_config.GetCurrentServer()); | |||||
local = new Local(_config.GetCurrentServer()); | |||||
local.openOnLan = openOnLan; | |||||
polipoRunner = new PolipoRunner(); | |||||
polipoRunner.Start(_config); | |||||
local = new Local(_config); | |||||
try | try | ||||
{ | { | ||||
local.Start(); | local.Start(); | ||||
pacServer = new PACServer(); | pacServer = new PACServer(); | ||||
pacServer.PACFileChanged += pacServer_PACFileChanged; | |||||
pacServer.openOnLan = openOnLan; | |||||
pacServer.Start(); | |||||
pacServer.PACFileChanged += pacServer_PACFileChanged; | |||||
pacServer.Start(_config); | |||||
} | } | ||||
catch (Exception e) | catch (Exception e) | ||||
{ | { | ||||
@@ -61,37 +59,7 @@ namespace Shadowsocks.Controller | |||||
UpdateSystemProxy(); | UpdateSystemProxy(); | ||||
} | } | ||||
public void SaveConfig(Configuration newConfig) | |||||
{ | |||||
Configuration.Save(newConfig); | |||||
if (newConfig.noChange && newConfig.openOnLan == openOnLan) | |||||
{ | |||||
return; | |||||
} | |||||
// some logic in configuration updated the config when saving, we need to read it again | |||||
_config = Configuration.Load(); | |||||
openOnLan = _config.openOnLan; | |||||
local.Stop(); | |||||
polipoRunner.Stop(); | |||||
polipoRunner.openOnLan = openOnLan; | |||||
polipoRunner.Start(_config.GetCurrentServer()); | |||||
local = new Local(_config.GetCurrentServer()); | |||||
local.openOnLan = openOnLan; | |||||
local.Start(); | |||||
pacServer.Stop(); | |||||
pacServer.openOnLan = openOnLan; | |||||
pacServer.Start(); | |||||
if (ConfigChanged != null) | |||||
{ | |||||
ConfigChanged(this, new EventArgs()); | |||||
} | |||||
} | |||||
public Server GetCurrentServer() | public Server GetCurrentServer() | ||||
{ | { | ||||
return _config.GetCurrentServer(); | return _config.GetCurrentServer(); | ||||
@@ -103,6 +71,11 @@ namespace Shadowsocks.Controller | |||||
return Configuration.Load(); | return Configuration.Load(); | ||||
} | } | ||||
public void SaveServers(List<Server> servers) | |||||
{ | |||||
_config.configs = servers; | |||||
SaveConfig(_config); | |||||
} | |||||
public void ToggleEnable(bool enabled) | public void ToggleEnable(bool enabled) | ||||
{ | { | ||||
@@ -115,6 +88,22 @@ namespace Shadowsocks.Controller | |||||
} | } | ||||
} | } | ||||
public void ToggleShareOverLAN(bool enabled) | |||||
{ | |||||
_config.shareOverLan = enabled; | |||||
SaveConfig(_config); | |||||
if (ShareOverLANStatusChanged != null) | |||||
{ | |||||
ShareOverLANStatusChanged(this, new EventArgs()); | |||||
} | |||||
} | |||||
public void SelectServerIndex(int index) | |||||
{ | |||||
_config.index = index; | |||||
SaveConfig(_config); | |||||
} | |||||
public void Stop() | public void Stop() | ||||
{ | { | ||||
if (stopped) | if (stopped) | ||||
@@ -147,6 +136,34 @@ namespace Shadowsocks.Controller | |||||
return "ss://" + base64; | return "ss://" + base64; | ||||
} | } | ||||
protected void SaveConfig(Configuration newConfig) | |||||
{ | |||||
Configuration.Save(newConfig); | |||||
// some logic in configuration updated the config when saving, we need to read it again | |||||
_config = Configuration.Load(); | |||||
pacServer.Stop(); | |||||
local.Stop(); | |||||
// don't put polipoRunner.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 | |||||
polipoRunner.Stop(); | |||||
polipoRunner.Start(_config); | |||||
local = new Local(_config); | |||||
local.Start(); | |||||
pacServer.Start(_config); | |||||
if (ConfigChanged != null) | |||||
{ | |||||
ConfigChanged(this, new EventArgs()); | |||||
} | |||||
} | |||||
private void UpdateSystemProxy() | private void UpdateSystemProxy() | ||||
{ | { | ||||
if (_config.enabled) | if (_config.enabled) | ||||
@@ -0,0 +1,152 @@ | |||||
using System; | |||||
using System.Collections; | |||||
using System.Collections.Generic; | |||||
using System.Net; | |||||
using System.Reflection; | |||||
using System.Text; | |||||
using System.Text.RegularExpressions; | |||||
using System.Xml; | |||||
namespace Shadowsocks.Controller | |||||
{ | |||||
public class UpdateChecker | |||||
{ | |||||
private const string UpdateURL = "https://sourceforge.net/api/file/index/project-id/1817190/path/dist/mtime/desc/limit/10/rss"; | |||||
public string LatestVersionNumber; | |||||
public string LatestVersionURL; | |||||
public event EventHandler NewVersionFound; | |||||
public void CheckUpdate() | |||||
{ | |||||
// TODO test failures | |||||
WebClient http = new WebClient(); | |||||
http.DownloadStringCompleted += http_DownloadStringCompleted; | |||||
http.DownloadStringAsync(new Uri(UpdateURL)); | |||||
} | |||||
public static int CompareVersion(string l, string r) | |||||
{ | |||||
var ls = l.Split('.'); | |||||
var rs = r.Split('.'); | |||||
for (int i = 0; i < Math.Max(ls.Length, rs.Length); i++) | |||||
{ | |||||
int lp = (i < ls.Length) ? int.Parse(ls[i]) : 0; | |||||
int rp = (i < rs.Length) ? int.Parse(rs[i]) : 0; | |||||
if (lp != rp) | |||||
{ | |||||
return lp - rp; | |||||
} | |||||
} | |||||
return 0; | |||||
} | |||||
public class VersionComparer : IComparer<string> | |||||
{ | |||||
// Calls CaseInsensitiveComparer.Compare with the parameters reversed. | |||||
public int Compare(string x, string y) | |||||
{ | |||||
return CompareVersion(ParseVersionFromURL(x), ParseVersionFromURL(y)); | |||||
} | |||||
} | |||||
private static string ParseVersionFromURL(string url) | |||||
{ | |||||
Match match = Regex.Match(url, @".*Shadowsocks-win.*?-([\d\.]+)\.\w+", RegexOptions.IgnoreCase); | |||||
if (match.Success) | |||||
{ | |||||
if (match.Groups.Count == 2) | |||||
{ | |||||
return match.Groups[1].Value; | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
private void SortVersions(List<string> versions) | |||||
{ | |||||
versions.Sort(new VersionComparer()); | |||||
} | |||||
private bool IsNewVersion(string url) | |||||
{ | |||||
// check dotnet 4.0 | |||||
AssemblyName[] references = Assembly.GetExecutingAssembly().GetReferencedAssemblies(); | |||||
Version dotNetVersion = Environment.Version; | |||||
foreach (AssemblyName reference in references) | |||||
{ | |||||
if (reference.Name == "mscorlib") | |||||
{ | |||||
dotNetVersion = reference.Version; | |||||
} | |||||
} | |||||
if (dotNetVersion.Major >= 4) | |||||
{ | |||||
if (url.IndexOf("dotnet4.0") < 0) | |||||
{ | |||||
return false; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
if (url.IndexOf("dotnet4.0") >= 0) | |||||
{ | |||||
return false; | |||||
} | |||||
} | |||||
string version = ParseVersionFromURL(url); | |||||
if (version == null) | |||||
{ | |||||
return false; | |||||
} | |||||
string currentVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); | |||||
return CompareVersion(version, currentVersion) > 0; | |||||
} | |||||
private void http_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) | |||||
{ | |||||
try | |||||
{ | |||||
string response = e.Result; | |||||
XmlDocument xmlDoc = new XmlDocument(); | |||||
xmlDoc.LoadXml(response); | |||||
XmlNodeList elements = xmlDoc.GetElementsByTagName("media:content"); | |||||
List<string> versions = new List<string>(); | |||||
foreach (XmlNode el in elements) | |||||
{ | |||||
foreach (XmlAttribute attr in el.Attributes) | |||||
{ | |||||
if (attr.Name == "url") | |||||
{ | |||||
Console.WriteLine(attr.Value); | |||||
if (IsNewVersion(attr.Value)) | |||||
{ | |||||
versions.Add(attr.Value); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
if (versions.Count == 0) | |||||
{ | |||||
return; | |||||
} | |||||
// sort versions | |||||
SortVersions(versions); | |||||
LatestVersionURL = versions[versions.Count - 1]; | |||||
LatestVersionNumber = ParseVersionFromURL(LatestVersionURL); | |||||
if (NewVersionFound != null) | |||||
{ | |||||
NewVersionFound(this, new EventArgs()); | |||||
} | |||||
} | |||||
catch (Exception ex) | |||||
{ | |||||
Console.Write(ex.ToString()); | |||||
return; | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -1,4 +1,4 @@ | |||||
proxyAddress = "127.0.0.1" | |||||
proxyAddress = "__POLIPO_BIND_IP__" | |||||
socksParentProxy = "127.0.0.1:__SOCKS_PORT__" | socksParentProxy = "127.0.0.1:__SOCKS_PORT__" | ||||
socksProxyType = socks5 | socksProxyType = socks5 | ||||
@@ -15,6 +15,7 @@ namespace Shadowsocks.Model | |||||
public List<Server> configs; | public List<Server> configs; | ||||
public int index; | public int index; | ||||
public bool enabled; | public bool enabled; | ||||
public bool shareOverLan; | |||||
public bool isDefault; | public bool isDefault; | ||||
public bool openOnLan; | public bool openOnLan; | ||||
public bool enableLog; | public bool enableLog; | ||||
@@ -46,7 +46,8 @@ namespace Shadowsocks | |||||
Console.WriteLine(e.ToString()); | Console.WriteLine(e.ToString()); | ||||
} | } | ||||
LoadLibrary(dllPath); | LoadLibrary(dllPath); | ||||
Logging.OpenLogFile(); | |||||
Application.EnableVisualStyles(); | Application.EnableVisualStyles(); | ||||
Application.SetCompatibleTextRenderingDefault(false); | Application.SetCompatibleTextRenderingDefault(false); | ||||
ShadowsocksController controller = new ShadowsocksController(); | ShadowsocksController controller = new ShadowsocksController(); | ||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices; | |||||
// 可以指定所有这些值,也可以使用“内部版本号”和“修订号”的默认值, | // 可以指定所有这些值,也可以使用“内部版本号”和“修订号”的默认值, | ||||
// 方法是按如下所示使用“*”: | // 方法是按如下所示使用“*”: | ||||
// [assembly: AssemblyVersion("1.0.*")] | // [assembly: AssemblyVersion("1.0.*")] | ||||
[assembly: AssemblyVersion("2.0.4")] | |||||
[assembly: AssemblyVersion("2.0.5")] | |||||
// [assembly: AssemblyFileVersion("2.0.0")] | // [assembly: AssemblyFileVersion("2.0.0")] |
@@ -71,7 +71,7 @@ namespace Shadowsocks.Properties { | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
/// Looks up a localized string similar to proxyAddress = "127.0.0.1" | |||||
/// Looks up a localized string similar to proxyAddress = "__POLIPO_BIND_IP__" | |||||
/// | /// | ||||
///socksParentProxy = "127.0.0.1:__SOCKS_PORT__" | ///socksParentProxy = "127.0.0.1:__SOCKS_PORT__" | ||||
///socksProxyType = socks5 | ///socksProxyType = socks5 | ||||
@@ -50,12 +50,14 @@ | |||||
this.panel1 = new System.Windows.Forms.Panel(); | this.panel1 = new System.Windows.Forms.Panel(); | ||||
this.contextMenu1 = new System.Windows.Forms.ContextMenu(); | this.contextMenu1 = new System.Windows.Forms.ContextMenu(); | ||||
this.enableItem = new System.Windows.Forms.MenuItem(); | this.enableItem = new System.Windows.Forms.MenuItem(); | ||||
this.ShareOverLANItem = new System.Windows.Forms.MenuItem(); | |||||
this.ServersItem = new System.Windows.Forms.MenuItem(); | this.ServersItem = new System.Windows.Forms.MenuItem(); | ||||
this.SeperatorItem = new System.Windows.Forms.MenuItem(); | this.SeperatorItem = new System.Windows.Forms.MenuItem(); | ||||
this.ConfigItem = new System.Windows.Forms.MenuItem(); | this.ConfigItem = new System.Windows.Forms.MenuItem(); | ||||
this.menuItem4 = new System.Windows.Forms.MenuItem(); | this.menuItem4 = new System.Windows.Forms.MenuItem(); | ||||
this.editPACFileItem = new System.Windows.Forms.MenuItem(); | this.editPACFileItem = new System.Windows.Forms.MenuItem(); | ||||
this.QRCodeItem = new System.Windows.Forms.MenuItem(); | this.QRCodeItem = new System.Windows.Forms.MenuItem(); | ||||
this.ShowLogItem = new System.Windows.Forms.MenuItem(); | |||||
this.aboutItem = new System.Windows.Forms.MenuItem(); | this.aboutItem = new System.Windows.Forms.MenuItem(); | ||||
this.menuItem3 = new System.Windows.Forms.MenuItem(); | this.menuItem3 = new System.Windows.Forms.MenuItem(); | ||||
this.quitItem = new System.Windows.Forms.MenuItem(); | this.quitItem = new System.Windows.Forms.MenuItem(); | ||||
@@ -64,8 +66,6 @@ | |||||
this.AddButton = new System.Windows.Forms.Button(); | this.AddButton = new System.Windows.Forms.Button(); | ||||
this.ServerGroupBox = new System.Windows.Forms.GroupBox(); | this.ServerGroupBox = new System.Windows.Forms.GroupBox(); | ||||
this.ServersListBox = new System.Windows.Forms.ListBox(); | this.ServersListBox = new System.Windows.Forms.ListBox(); | ||||
this.openOnLanBox = new System.Windows.Forms.CheckBox(); | |||||
this.enableLogBox = new System.Windows.Forms.CheckBox(); | |||||
this.tableLayoutPanel1.SuspendLayout(); | this.tableLayoutPanel1.SuspendLayout(); | ||||
this.panel1.SuspendLayout(); | this.panel1.SuspendLayout(); | ||||
this.panel3.SuspendLayout(); | this.panel3.SuspendLayout(); | ||||
@@ -287,10 +287,12 @@ | |||||
// | // | ||||
this.contextMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { | this.contextMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { | ||||
this.enableItem, | this.enableItem, | ||||
this.ShareOverLANItem, | |||||
this.ServersItem, | this.ServersItem, | ||||
this.menuItem4, | this.menuItem4, | ||||
this.editPACFileItem, | this.editPACFileItem, | ||||
this.QRCodeItem, | this.QRCodeItem, | ||||
this.ShowLogItem, | |||||
this.aboutItem, | this.aboutItem, | ||||
this.menuItem3, | this.menuItem3, | ||||
this.quitItem}); | this.quitItem}); | ||||
@@ -301,9 +303,15 @@ | |||||
this.enableItem.Text = "&Enable"; | this.enableItem.Text = "&Enable"; | ||||
this.enableItem.Click += new System.EventHandler(this.EnableItem_Click); | this.enableItem.Click += new System.EventHandler(this.EnableItem_Click); | ||||
// | // | ||||
// ShareOverLANItem | |||||
// | |||||
this.ShareOverLANItem.Index = 1; | |||||
this.ShareOverLANItem.Text = "Share over LAN"; | |||||
this.ShareOverLANItem.Click += new System.EventHandler(this.ShareOverLANItem_Click); | |||||
// | |||||
// ServersItem | // ServersItem | ||||
// | // | ||||
this.ServersItem.Index = 1; | |||||
this.ServersItem.Index = 2; | |||||
this.ServersItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { | this.ServersItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { | ||||
this.SeperatorItem, | this.SeperatorItem, | ||||
this.ConfigItem}); | this.ConfigItem}); | ||||
@@ -322,35 +330,41 @@ | |||||
// | // | ||||
// menuItem4 | // menuItem4 | ||||
// | // | ||||
this.menuItem4.Index = 2; | |||||
this.menuItem4.Index = 3; | |||||
this.menuItem4.Text = "-"; | this.menuItem4.Text = "-"; | ||||
// | // | ||||
// editPACFileItem | // editPACFileItem | ||||
// | // | ||||
this.editPACFileItem.Index = 3; | |||||
this.editPACFileItem.Index = 4; | |||||
this.editPACFileItem.Text = "Edit &PAC File..."; | this.editPACFileItem.Text = "Edit &PAC File..."; | ||||
this.editPACFileItem.Click += new System.EventHandler(this.EditPACFileItem_Click); | this.editPACFileItem.Click += new System.EventHandler(this.EditPACFileItem_Click); | ||||
// | // | ||||
// QRCodeItem | // QRCodeItem | ||||
// | // | ||||
this.QRCodeItem.Index = 4; | |||||
this.QRCodeItem.Index = 5; | |||||
this.QRCodeItem.Text = "Show &QRCode..."; | this.QRCodeItem.Text = "Show &QRCode..."; | ||||
this.QRCodeItem.Click += new System.EventHandler(this.QRCodeItem_Click); | this.QRCodeItem.Click += new System.EventHandler(this.QRCodeItem_Click); | ||||
// | // | ||||
// ShowLogItem | |||||
// | |||||
this.ShowLogItem.Index = 6; | |||||
this.ShowLogItem.Text = "Show Logs..."; | |||||
this.ShowLogItem.Click += new System.EventHandler(this.ShowLogItem_Click); | |||||
// | |||||
// aboutItem | // aboutItem | ||||
// | // | ||||
this.aboutItem.Index = 5; | |||||
this.aboutItem.Index = 7; | |||||
this.aboutItem.Text = "About..."; | this.aboutItem.Text = "About..."; | ||||
this.aboutItem.Click += new System.EventHandler(this.AboutItem_Click); | this.aboutItem.Click += new System.EventHandler(this.AboutItem_Click); | ||||
// | // | ||||
// menuItem3 | // menuItem3 | ||||
// | // | ||||
this.menuItem3.Index = 6; | |||||
this.menuItem3.Index = 8; | |||||
this.menuItem3.Text = "-"; | this.menuItem3.Text = "-"; | ||||
// | // | ||||
// quitItem | // quitItem | ||||
// | // | ||||
this.quitItem.Index = 7; | |||||
this.quitItem.Index = 9; | |||||
this.quitItem.Text = "&Quit"; | this.quitItem.Text = "&Quit"; | ||||
this.quitItem.Click += new System.EventHandler(this.Quit_Click); | this.quitItem.Click += new System.EventHandler(this.Quit_Click); | ||||
// | // | ||||
@@ -404,27 +418,6 @@ | |||||
this.ServersListBox.TabIndex = 5; | this.ServersListBox.TabIndex = 5; | ||||
this.ServersListBox.SelectedIndexChanged += new System.EventHandler(this.ServersListBox_SelectedIndexChanged); | this.ServersListBox.SelectedIndexChanged += new System.EventHandler(this.ServersListBox_SelectedIndexChanged); | ||||
// | // | ||||
// openOnLanBox | |||||
// | |||||
this.openOnLanBox.AutoSize = true; | |||||
this.openOnLanBox.Location = new System.Drawing.Point(16, 260); | |||||
this.openOnLanBox.Name = "openOnLanBox"; | |||||
this.openOnLanBox.Size = new System.Drawing.Size(90, 17); | |||||
this.openOnLanBox.TabIndex = 7; | |||||
this.openOnLanBox.Text = "Open On Lan"; | |||||
this.openOnLanBox.UseVisualStyleBackColor = true; | |||||
// | |||||
// enableLogBox | |||||
// | |||||
this.enableLogBox.AutoSize = true; | |||||
this.enableLogBox.Location = new System.Drawing.Point(112, 260); | |||||
this.enableLogBox.Name = "enableLogBox"; | |||||
this.enableLogBox.Size = new System.Drawing.Size(80, 17); | |||||
this.enableLogBox.TabIndex = 7; | |||||
this.enableLogBox.Text = "Enable Log"; | |||||
this.enableLogBox.UseVisualStyleBackColor = true; | |||||
this.enableLogBox.CheckedChanged += new System.EventHandler(this.enableLogBox_CheckedChanged); | |||||
// | |||||
// ConfigForm | // ConfigForm | ||||
// | // | ||||
this.AcceptButton = this.OKButton; | this.AcceptButton = this.OKButton; | ||||
@@ -433,8 +426,6 @@ | |||||
this.AutoSize = true; | this.AutoSize = true; | ||||
this.CancelButton = this.MyCancelButton; | this.CancelButton = this.MyCancelButton; | ||||
this.ClientSize = new System.Drawing.Size(489, 286); | this.ClientSize = new System.Drawing.Size(489, 286); | ||||
this.Controls.Add(this.enableLogBox); | |||||
this.Controls.Add(this.openOnLanBox); | |||||
this.Controls.Add(this.ServersListBox); | this.Controls.Add(this.ServersListBox); | ||||
this.Controls.Add(this.ServerGroupBox); | this.Controls.Add(this.ServerGroupBox); | ||||
this.Controls.Add(this.panel1); | this.Controls.Add(this.panel1); | ||||
@@ -446,7 +437,7 @@ | |||||
this.MinimizeBox = false; | this.MinimizeBox = false; | ||||
this.Name = "ConfigForm"; | this.Name = "ConfigForm"; | ||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; | ||||
this.Text = "Shadowsocks"; | |||||
this.Text = "Edit Servers"; | |||||
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.ConfigForm_FormClosed); | this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.ConfigForm_FormClosed); | ||||
this.Load += new System.EventHandler(this.ConfigForm_Load); | this.Load += new System.EventHandler(this.ConfigForm_Load); | ||||
this.Shown += new System.EventHandler(this.ConfigForm_Shown); | this.Shown += new System.EventHandler(this.ConfigForm_Shown); | ||||
@@ -497,8 +488,8 @@ | |||||
private System.Windows.Forms.TextBox RemarksTextBox; | private System.Windows.Forms.TextBox RemarksTextBox; | ||||
private System.Windows.Forms.Label label6; | private System.Windows.Forms.Label label6; | ||||
private System.Windows.Forms.MenuItem QRCodeItem; | private System.Windows.Forms.MenuItem QRCodeItem; | ||||
private System.Windows.Forms.CheckBox openOnLanBox; | |||||
private System.Windows.Forms.CheckBox enableLogBox; | |||||
private System.Windows.Forms.MenuItem ShowLogItem; | |||||
private System.Windows.Forms.MenuItem ShareOverLANItem; | |||||
} | } | ||||
} | } | ||||
@@ -13,6 +13,7 @@ namespace Shadowsocks.View | |||||
public partial class ConfigForm : Form | public partial class ConfigForm : Form | ||||
{ | { | ||||
private ShadowsocksController controller; | private ShadowsocksController controller; | ||||
private UpdateChecker updateChecker; | |||||
// this is a copy of configuration that we are working on | // this is a copy of configuration that we are working on | ||||
private Configuration _modifiedConfiguration; | private Configuration _modifiedConfiguration; | ||||
@@ -29,6 +30,10 @@ namespace Shadowsocks.View | |||||
controller.EnableStatusChanged += controller_EnableStatusChanged; | controller.EnableStatusChanged += controller_EnableStatusChanged; | ||||
controller.ConfigChanged += controller_ConfigChanged; | controller.ConfigChanged += controller_ConfigChanged; | ||||
controller.PACFileReadyToOpen += controller_PACFileReadyToOpen; | controller.PACFileReadyToOpen += controller_PACFileReadyToOpen; | ||||
controller.ShareOverLANStatusChanged += controller_ShareOverLANStatusChanged; | |||||
this.updateChecker = new UpdateChecker(); | |||||
updateChecker.NewVersionFound += updateChecker_NewVersionFound; | |||||
LoadCurrentConfiguration(); | LoadCurrentConfiguration(); | ||||
} | } | ||||
@@ -43,6 +48,11 @@ namespace Shadowsocks.View | |||||
enableItem.Checked = controller.GetConfiguration().enabled; | enableItem.Checked = controller.GetConfiguration().enabled; | ||||
} | } | ||||
void controller_ShareOverLANStatusChanged(object sender, EventArgs e) | |||||
{ | |||||
ShareOverLANItem.Checked = controller.GetConfiguration().shareOverLan; | |||||
} | |||||
void controller_PACFileReadyToOpen(object sender, ShadowsocksController.PathEventArgs e) | void controller_PACFileReadyToOpen(object sender, ShadowsocksController.PathEventArgs e) | ||||
{ | { | ||||
string argument = @"/select, " + e.Path; | string argument = @"/select, " + e.Path; | ||||
@@ -50,6 +60,21 @@ namespace Shadowsocks.View | |||||
System.Diagnostics.Process.Start("explorer.exe", argument); | System.Diagnostics.Process.Start("explorer.exe", argument); | ||||
} | } | ||||
void updateChecker_NewVersionFound(object sender, EventArgs e) | |||||
{ | |||||
notifyIcon1.BalloonTipTitle = "Shadowsocks " + updateChecker.LatestVersionNumber + " Update Found"; | |||||
notifyIcon1.BalloonTipText = "You can click here to download"; | |||||
notifyIcon1.BalloonTipIcon = ToolTipIcon.Info; | |||||
notifyIcon1.BalloonTipClicked += notifyIcon1_BalloonTipClicked; | |||||
notifyIcon1.ShowBalloonTip(5000); | |||||
_isFirstRun = false; | |||||
} | |||||
void notifyIcon1_BalloonTipClicked(object sender, EventArgs e) | |||||
{ | |||||
Process.Start(updateChecker.LatestVersionURL); | |||||
} | |||||
private void ShowWindow() | private void ShowWindow() | ||||
{ | { | ||||
@@ -151,7 +176,7 @@ namespace Shadowsocks.View | |||||
UpdateServersMenu(); | UpdateServersMenu(); | ||||
enableItem.Checked = _modifiedConfiguration.enabled; | enableItem.Checked = _modifiedConfiguration.enabled; | ||||
openOnLanBox.Checked = _modifiedConfiguration.openOnLan; | |||||
ShareOverLANItem.Checked = _modifiedConfiguration.shareOverLan; | |||||
} | } | ||||
private void UpdateServersMenu() | private void UpdateServersMenu() | ||||
@@ -192,6 +217,7 @@ namespace Shadowsocks.View | |||||
{ | { | ||||
_isFirstRun = true; | _isFirstRun = true; | ||||
} | } | ||||
updateChecker.CheckUpdate(); | |||||
} | } | ||||
private void ServersListBox_SelectedIndexChanged(object sender, EventArgs e) | private void ServersListBox_SelectedIndexChanged(object sender, EventArgs e) | ||||
@@ -258,6 +284,7 @@ namespace Shadowsocks.View | |||||
{ | { | ||||
notifyIcon1.BalloonTipTitle = "Shadowsocks is here"; | notifyIcon1.BalloonTipTitle = "Shadowsocks is here"; | ||||
notifyIcon1.BalloonTipText = "You can turn on/off Shadowsocks in the context menu"; | notifyIcon1.BalloonTipText = "You can turn on/off Shadowsocks in the context menu"; | ||||
notifyIcon1.BalloonTipIcon = ToolTipIcon.Info; | |||||
notifyIcon1.ShowBalloonTip(0); | notifyIcon1.ShowBalloonTip(0); | ||||
_isFirstRun = false; | _isFirstRun = false; | ||||
} | } | ||||
@@ -274,8 +301,7 @@ namespace Shadowsocks.View | |||||
MessageBox.Show("Please add at least one server"); | MessageBox.Show("Please add at least one server"); | ||||
return; | return; | ||||
} | } | ||||
_modifiedConfiguration.openOnLan = openOnLanBox.Checked; | |||||
controller.SaveConfig(_modifiedConfiguration); | |||||
controller.SaveServers(_modifiedConfiguration.configs); | |||||
this.Hide(); | this.Hide(); | ||||
ShowFirstTimeBalloon(); | ShowFirstTimeBalloon(); | ||||
} | } | ||||
@@ -309,6 +335,12 @@ namespace Shadowsocks.View | |||||
controller.ToggleEnable(enableItem.Checked); | controller.ToggleEnable(enableItem.Checked); | ||||
} | } | ||||
private void ShareOverLANItem_Click(object sender, EventArgs e) | |||||
{ | |||||
ShareOverLANItem.Checked = !ShareOverLANItem.Checked; | |||||
controller.ToggleShareOverLAN(ShareOverLANItem.Checked); | |||||
} | |||||
private void EditPACFileItem_Click(object sender, EventArgs e) | private void EditPACFileItem_Click(object sender, EventArgs e) | ||||
{ | { | ||||
controller.TouchPACFile(); | controller.TouchPACFile(); | ||||
@@ -317,9 +349,14 @@ namespace Shadowsocks.View | |||||
private void AServerItem_Click(object sender, EventArgs e) | private void AServerItem_Click(object sender, EventArgs e) | ||||
{ | { | ||||
MenuItem item = (MenuItem)sender; | MenuItem item = (MenuItem)sender; | ||||
Configuration configuration = controller.GetConfiguration(); | |||||
configuration.index = (int)item.Tag; | |||||
controller.SaveConfig(configuration); | |||||
controller.SelectServerIndex((int)item.Tag); | |||||
} | |||||
private void ShowLogItem_Click(object sender, EventArgs e) | |||||
{ | |||||
string argument = Logging.LogFile; | |||||
System.Diagnostics.Process.Start("notepad.exe", argument); | |||||
} | } | ||||
private void ConfigForm_Shown(object sender, EventArgs e) | private void ConfigForm_Shown(object sender, EventArgs e) | ||||
@@ -25,35 +25,50 @@ namespace Shadowsocks.View | |||||
private void GenQR(string ssconfig) | private void GenQR(string ssconfig) | ||||
{ | { | ||||
string qrText = ssconfig; | string qrText = ssconfig; | ||||
QRCode4CS.QRCode qrCoded = new QRCode4CS.QRCode(6, QRErrorCorrectLevel.H); | |||||
qrCoded.AddData(qrText); | |||||
qrCoded.Make(); | |||||
int blockSize = 5; | |||||
Bitmap drawArea = new Bitmap((qrCoded.GetModuleCount() * blockSize), (qrCoded.GetModuleCount() * blockSize)); | |||||
for (int row = 0; row < qrCoded.GetModuleCount(); row++) | |||||
QRCode4CS.Options options = new QRCode4CS.Options(); | |||||
options.Text = qrText; | |||||
QRCode4CS.QRCode qrCoded = null; | |||||
bool success = false; | |||||
foreach (var level in new QRErrorCorrectLevel[]{QRErrorCorrectLevel.H, QRErrorCorrectLevel.Q, QRErrorCorrectLevel.M, QRErrorCorrectLevel.L}) | |||||
{ | { | ||||
for (int col = 0; col < qrCoded.GetModuleCount(); col++) | |||||
for (int i = 3; i < 10; i++) | |||||
{ | { | ||||
bool isDark = qrCoded.IsDark(row, col); | |||||
if (isDark) | |||||
try | |||||
{ | { | ||||
for (int y = 0; y < blockSize; y++) | |||||
{ | |||||
int myCol = (blockSize * (col - 1)) + (y + blockSize); | |||||
for (int x = 0; x < blockSize; x++) | |||||
{ | |||||
drawArea.SetPixel((blockSize * (row - 1)) + (x + blockSize), myCol, Color.Black); | |||||
} | |||||
} | |||||
options.TypeNumber = i; | |||||
options.CorrectLevel = level; | |||||
qrCoded = new QRCode4CS.QRCode(options); | |||||
qrCoded.Make(); | |||||
success = true; | |||||
break; | |||||
} | |||||
catch | |||||
{ | |||||
qrCoded = null; | |||||
continue; | |||||
} | } | ||||
else | |||||
} | |||||
if (success) | |||||
break; | |||||
} | |||||
if (qrCoded == null) | |||||
{ | |||||
return; | |||||
} | |||||
int blockSize = Math.Max(200 / qrCoded.GetModuleCount(), 1); | |||||
Bitmap drawArea = new Bitmap((qrCoded.GetModuleCount() * blockSize), (qrCoded.GetModuleCount() * blockSize)); | |||||
using (Graphics g = Graphics.FromImage(drawArea)) | |||||
{ | |||||
g.Clear(Color.White); | |||||
using (Brush b = new SolidBrush(Color.Black)) | |||||
{ | |||||
for (int row = 0; row < qrCoded.GetModuleCount(); row++) | |||||
{ | { | ||||
for (int y = 0; y < blockSize; y++) | |||||
for (int col = 0; col < qrCoded.GetModuleCount(); col++) | |||||
{ | { | ||||
int myCol = (blockSize * (col - 1)) + (y + blockSize); | |||||
for (int x = 0; x < blockSize; x++) | |||||
if (qrCoded.IsDark(row, col)) | |||||
{ | { | ||||
drawArea.SetPixel((blockSize * (row - 1)) + (x + blockSize), myCol, Color.White); | |||||
g.FillRectangle(b, blockSize * row, blockSize * col, blockSize, blockSize); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -63,11 +63,14 @@ | |||||
<Reference Include="System.Data" /> | <Reference Include="System.Data" /> | ||||
<Reference Include="System.Drawing" /> | <Reference Include="System.Drawing" /> | ||||
<Reference Include="System.Windows.Forms" /> | <Reference Include="System.Windows.Forms" /> | ||||
<Reference Include="System.XML" /> | |||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<Compile Include="3rd\QRCodeCS.cs" /> | <Compile Include="3rd\QRCodeCS.cs" /> | ||||
<Compile Include="3rd\SimpleJson.cs" /> | <Compile Include="3rd\SimpleJson.cs" /> | ||||
<Compile Include="Controller\FileManager.cs" /> | <Compile Include="Controller\FileManager.cs" /> | ||||
<Compile Include="Controller\Logging.cs" /> | |||||
<Compile Include="Controller\UpdateChecker.cs" /> | |||||
<Compile Include="Encrypt\EncryptorBase.cs" /> | <Compile Include="Encrypt\EncryptorBase.cs" /> | ||||
<Compile Include="Encrypt\EncryptorFactory.cs" /> | <Compile Include="Encrypt\EncryptorFactory.cs" /> | ||||
<Compile Include="Encrypt\PolarSSL.cs" /> | <Compile Include="Encrypt\PolarSSL.cs" /> | ||||
@@ -0,0 +1,36 @@ | |||||
using System.Reflection; | |||||
using System.Runtime.CompilerServices; | |||||
using System.Runtime.InteropServices; | |||||
// General Information about an assembly is controlled through the following | |||||
// set of attributes. Change these attribute values to modify the information | |||||
// associated with an assembly. | |||||
[assembly: AssemblyTitle("test")] | |||||
[assembly: AssemblyDescription("")] | |||||
[assembly: AssemblyConfiguration("")] | |||||
[assembly: AssemblyCompany("")] | |||||
[assembly: AssemblyProduct("test")] | |||||
[assembly: AssemblyCopyright("Copyright © 2014")] | |||||
[assembly: AssemblyTrademark("")] | |||||
[assembly: AssemblyCulture("")] | |||||
// Setting ComVisible to false makes the types in this assembly not visible | |||||
// to COM components. If you need to access a type in this assembly from | |||||
// COM, set the ComVisible attribute to true on that type. | |||||
[assembly: ComVisible(false)] | |||||
// The following GUID is for the ID of the typelib if this project is exposed to COM | |||||
[assembly: Guid("f74e87ac-7e3a-444b-a1d9-8b91a674c60f")] | |||||
// Version information for an assembly consists of the following four values: | |||||
// | |||||
// Major Version | |||||
// Minor Version | |||||
// Build Number | |||||
// Revision | |||||
// | |||||
// You can specify all the values or you can default the Build and Revision Numbers | |||||
// by using the '*' as shown below: | |||||
// [assembly: AssemblyVersion("1.0.*")] | |||||
[assembly: AssemblyVersion("1.0.0.0")] | |||||
[assembly: AssemblyFileVersion("1.0.0.0")] |
@@ -0,0 +1,22 @@ | |||||
using System; | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using Shadowsocks.Controller; | |||||
namespace test | |||||
{ | |||||
[TestClass] | |||||
public class UnitTest | |||||
{ | |||||
[TestMethod] | |||||
public void TestCompareVersion() | |||||
{ | |||||
Assert.IsTrue(UpdateChecker.CompareVersion("2.3.1.0", "2.3.1") == 0); | |||||
Assert.IsTrue(UpdateChecker.CompareVersion("1.2", "1.3") < 0); | |||||
Assert.IsTrue(UpdateChecker.CompareVersion("1.3", "1.2") > 0); | |||||
Assert.IsTrue(UpdateChecker.CompareVersion("1.3", "1.3") == 0); | |||||
Assert.IsTrue(UpdateChecker.CompareVersion("1.2.1", "1.2") > 0); | |||||
Assert.IsTrue(UpdateChecker.CompareVersion("2.3.1", "2.4") < 0); | |||||
Assert.IsTrue(UpdateChecker.CompareVersion("1.3.2", "1.3.1") > 0); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,81 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<PropertyGroup> | |||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | |||||
<ProjectGuid>{45913187-0685-4903-B250-DCEF0479CD86}</ProjectGuid> | |||||
<OutputType>Library</OutputType> | |||||
<AppDesignerFolder>Properties</AppDesignerFolder> | |||||
<RootNamespace>test</RootNamespace> | |||||
<AssemblyName>test</AssemblyName> | |||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> | |||||
<FileAlignment>512</FileAlignment> | |||||
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> | |||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion> | |||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> | |||||
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath> | |||||
<IsCodedUITest>False</IsCodedUITest> | |||||
<TestProjectType>UnitTest</TestProjectType> | |||||
<TargetFrameworkProfile /> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'"> | |||||
<OutputPath>bin\x86\Debug\</OutputPath> | |||||
<PlatformTarget>x86</PlatformTarget> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'"> | |||||
<OutputPath>bin\x86\Release\</OutputPath> | |||||
<PlatformTarget>x86</PlatformTarget> | |||||
</PropertyGroup> | |||||
<ItemGroup> | |||||
<Reference Include="System" /> | |||||
</ItemGroup> | |||||
<Choose> | |||||
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'"> | |||||
<ItemGroup> | |||||
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" /> | |||||
</ItemGroup> | |||||
</When> | |||||
<Otherwise> | |||||
<ItemGroup> | |||||
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" /> | |||||
</ItemGroup> | |||||
</Otherwise> | |||||
</Choose> | |||||
<ItemGroup> | |||||
<Compile Include="UnitTest.cs" /> | |||||
<Compile Include="Properties\AssemblyInfo.cs" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<ProjectReference Include="..\shadowsocks-csharp\shadowsocks-csharp.csproj"> | |||||
<Project>{8c02d2f7-7cdb-4d55-9f25-cd03ef4aa062}</Project> | |||||
<Name>shadowsocks-csharp</Name> | |||||
</ProjectReference> | |||||
</ItemGroup> | |||||
<Choose> | |||||
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'"> | |||||
<ItemGroup> | |||||
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||||
<Private>False</Private> | |||||
</Reference> | |||||
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||||
<Private>False</Private> | |||||
</Reference> | |||||
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||||
<Private>False</Private> | |||||
</Reference> | |||||
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||||
<Private>False</Private> | |||||
</Reference> | |||||
</ItemGroup> | |||||
</When> | |||||
</Choose> | |||||
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" /> | |||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | |||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. | |||||
Other similar extension points exist, see Microsoft.Common.targets. | |||||
<Target Name="BeforeBuild"> | |||||
</Target> | |||||
<Target Name="AfterBuild"> | |||||
</Target> | |||||
--> | |||||
</Project> |