Browse Source

Merge remote-tracking branch 'upstream/master' into dev

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.cs
pull/44/head
wzxjohn 10 years ago
parent
commit
b339808928
22 changed files with 579 additions and 193 deletions
  1. +3
    -2
      .gitignore
  2. +8
    -3
      CHANGES
  3. +3
    -0
      README.md
  4. +9
    -0
      shadowsocks-csharp.sln
  5. +15
    -32
      shadowsocks-csharp/Controller/Local.cs
  6. +34
    -0
      shadowsocks-csharp/Controller/Logging.cs
  7. +35
    -33
      shadowsocks-csharp/Controller/PACServer.cs
  8. +9
    -16
      shadowsocks-csharp/Controller/PolipoRunner.cs
  9. +57
    -40
      shadowsocks-csharp/Controller/ShadowsocksController.cs
  10. +152
    -0
      shadowsocks-csharp/Controller/UpdateChecker.cs
  11. +1
    -1
      shadowsocks-csharp/Data/polipo_config.txt
  12. +1
    -0
      shadowsocks-csharp/Model/Configuration.cs
  13. +2
    -1
      shadowsocks-csharp/Program.cs
  14. +1
    -1
      shadowsocks-csharp/Properties/AssemblyInfo.cs
  15. +1
    -1
      shadowsocks-csharp/Properties/Resources.Designer.cs
  16. +26
    -35
      shadowsocks-csharp/View/ConfigForm.Designer.cs
  17. +43
    -6
      shadowsocks-csharp/View/ConfigForm.cs
  18. +37
    -22
      shadowsocks-csharp/View/QRCodeForm.cs
  19. +3
    -0
      shadowsocks-csharp/shadowsocks-csharp.csproj
  20. +36
    -0
      test/Properties/AssemblyInfo.cs
  21. +22
    -0
      test/UnitTest.cs
  22. +81
    -0
      test/test.csproj

+ 3
- 2
.gitignore View File

@@ -1,6 +1,7 @@
Backup/
shadowsocks-csharp/bin/
shadowsocks-csharp/obj/
bin/
obj/
shadowsocks-csharp/shadowsocks-csharp.csproj.user
TestResults
*.suo


+ 8
- 3
CHANGES View File

@@ -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
- Remove all configuration except x86

2.0.3
2.0.3 2014-11-08
- Support QRCode generation
- Fix compatibility issues with some Chrome version

2.0.2
2.0.2 2014-11-08
- Add remarks
- Fix error when polipo is killed



+ 3
- 0
README.md View File

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

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

1. Find Shadowsocks icon in notification tray


+ 9
- 0
shadowsocks-csharp.sln View File

@@ -3,6 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# 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}"
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
GlobalSection(SolutionConfigurationPlatforms) = preSolution
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}.Release|x86.ActiveCfg = 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
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE


+ 15
- 32
shadowsocks-csharp/Controller/Local.cs View File

@@ -10,14 +10,15 @@ namespace Shadowsocks.Controller
{
class Local
{
private Server config;
public bool openOnLan;
{
private Server _server;
private bool _shareOverLAN;
//private Encryptor encryptor;
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);
}
@@ -25,17 +26,17 @@ namespace Shadowsocks.Controller
{
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;
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
{
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.
@@ -67,37 +68,19 @@ namespace Shadowsocks.Controller
{
try
{
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
//if (!listener.Connected)
//{
// return;
//}
Socket conn = listener.EndAccept(ar);
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Create the state object.
Handler handler = new Handler();
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.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
// new AsyncCallback(ReadCallback), state);
}
catch
{
@@ -331,7 +314,7 @@ namespace Shadowsocks.Controller
}
else
{
Console.WriteLine("bytesRead: " + bytesRead.ToString());
//Console.WriteLine("bytesRead: " + bytesRead.ToString());
this.Close();
}
}


+ 34
- 0
shadowsocks-csharp/Controller/Logging.cs View File

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

+ 35
- 33
shadowsocks-csharp/Controller/PACServer.cs View File

@@ -1,4 +1,5 @@
using Shadowsocks.Properties;
using Shadowsocks.Model;
using Shadowsocks.Properties;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -12,51 +13,51 @@ namespace Shadowsocks.Controller
{
class PACServer
{
private static int PORT = 8090;
private static string PAC_FILE = "pac.txt";
public bool openOnLan;
Socket _listener;
FileSystemWatcher watcher;
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()
{
try
{
_listener.Close();
}
catch (Exception)
{
throw;
}
_listener.Close();
_listener = null;
}
public string TouchPACFile()
@@ -78,10 +79,10 @@ namespace Shadowsocks.Controller
try
{
Socket listener = (Socket)ar.AsyncState;
Socket conn = listener.EndAccept(ar);
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
Socket conn = listener.EndAccept(ar);
conn.BeginReceive(new byte[1024], 0, 1024, 0,
new AsyncCallback(ReceiveCallback), conn);
@@ -115,7 +116,6 @@ namespace Shadowsocks.Controller
return System.Text.Encoding.UTF8.GetString(buffer, 0, n);
}
}
WatchPacFile();
}
private void ReceiveCallback(IAsyncResult ar)
@@ -127,7 +127,9 @@ namespace Shadowsocks.Controller
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);


+ 9
- 16
shadowsocks-csharp/Controller/PolipoRunner.cs View File

@@ -14,8 +14,9 @@ namespace Shadowsocks.Controller
private Process _process;
public bool openOnLan;
public void Start(Server config)
public void Start(Configuration configuration)
{
Server server = configuration.GetCurrentServer();
if (_process == null)
{
Process[] existingPolipo = Process.GetProcessesByName("ss_polipo");
@@ -31,17 +32,10 @@ namespace Shadowsocks.Controller
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.UncompressFile(temppath + "/ss_polipo.exe", Resources.polipo_exe);
@@ -50,11 +44,10 @@ namespace Shadowsocks.Controller
_process.StartInfo.FileName = temppath + "/ss_polipo.exe";
_process.StartInfo.Arguments = "-c \"" + temppath + "/polipo.conf\"";
_process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
_process.StartInfo.UseShellExecute = false;
_process.StartInfo.UseShellExecute = 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();
}
}


+ 57
- 40
shadowsocks-csharp/Controller/ShadowsocksController.cs View File

@@ -3,6 +3,7 @@ using Shadowsocks.Model;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace Shadowsocks.Controller
{
@@ -27,6 +28,7 @@ namespace Shadowsocks.Controller
public event EventHandler ConfigChanged;
public event EventHandler EnableStatusChanged;
public event EventHandler ShareOverLANStatusChanged;
// when user clicked Edit PAC, and PAC file has already created
public event EventHandler<PathEventArgs> PACFileReadyToOpen;
@@ -40,19 +42,15 @@ namespace Shadowsocks.Controller
}
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
{
local.Start();
pacServer = new PACServer();
pacServer.PACFileChanged += pacServer_PACFileChanged;
pacServer.openOnLan = openOnLan;
pacServer.Start();
pacServer.PACFileChanged += pacServer_PACFileChanged;
pacServer.Start(_config);
}
catch (Exception e)
{
@@ -61,37 +59,7 @@ namespace Shadowsocks.Controller
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()
{
return _config.GetCurrentServer();
@@ -103,6 +71,11 @@ namespace Shadowsocks.Controller
return Configuration.Load();
}
public void SaveServers(List<Server> servers)
{
_config.configs = servers;
SaveConfig(_config);
}
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()
{
if (stopped)
@@ -147,6 +136,34 @@ namespace Shadowsocks.Controller
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()
{
if (_config.enabled)


+ 152
- 0
shadowsocks-csharp/Controller/UpdateChecker.cs View File

@@ -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
- 1
shadowsocks-csharp/Data/polipo_config.txt View File

@@ -1,4 +1,4 @@
proxyAddress = "127.0.0.1"
proxyAddress = "__POLIPO_BIND_IP__"

socksParentProxy = "127.0.0.1:__SOCKS_PORT__"
socksProxyType = socks5


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

@@ -15,6 +15,7 @@ namespace Shadowsocks.Model
public List<Server> configs;
public int index;
public bool enabled;
public bool shareOverLan;
public bool isDefault;
public bool openOnLan;
public bool enableLog;


+ 2
- 1
shadowsocks-csharp/Program.cs View File

@@ -46,7 +46,8 @@ namespace Shadowsocks
Console.WriteLine(e.ToString());
}
LoadLibrary(dllPath);

Logging.OpenLogFile();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
ShadowsocksController controller = new ShadowsocksController();


+ 1
- 1
shadowsocks-csharp/Properties/AssemblyInfo.cs View File

@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// 可以指定所有这些值,也可以使用“内部版本号”和“修订号”的默认值,
// 方法是按如下所示使用“*”:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2.0.4")]
[assembly: AssemblyVersion("2.0.5")]
// [assembly: AssemblyFileVersion("2.0.0")]

+ 1
- 1
shadowsocks-csharp/Properties/Resources.Designer.cs View File

@@ -71,7 +71,7 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized string similar to proxyAddress = &quot;127.0.0.1&quot;
/// Looks up a localized string similar to proxyAddress = &quot;__POLIPO_BIND_IP__&quot;
///
///socksParentProxy = &quot;127.0.0.1:__SOCKS_PORT__&quot;
///socksProxyType = socks5


+ 26
- 35
shadowsocks-csharp/View/ConfigForm.Designer.cs View File

@@ -50,12 +50,14 @@
this.panel1 = new System.Windows.Forms.Panel();
this.contextMenu1 = new System.Windows.Forms.ContextMenu();
this.enableItem = new System.Windows.Forms.MenuItem();
this.ShareOverLANItem = new System.Windows.Forms.MenuItem();
this.ServersItem = new System.Windows.Forms.MenuItem();
this.SeperatorItem = new System.Windows.Forms.MenuItem();
this.ConfigItem = new System.Windows.Forms.MenuItem();
this.menuItem4 = new System.Windows.Forms.MenuItem();
this.editPACFileItem = 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.menuItem3 = new System.Windows.Forms.MenuItem();
this.quitItem = new System.Windows.Forms.MenuItem();
@@ -64,8 +66,6 @@
this.AddButton = new System.Windows.Forms.Button();
this.ServerGroupBox = new System.Windows.Forms.GroupBox();
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.panel1.SuspendLayout();
this.panel3.SuspendLayout();
@@ -287,10 +287,12 @@
//
this.contextMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.enableItem,
this.ShareOverLANItem,
this.ServersItem,
this.menuItem4,
this.editPACFileItem,
this.QRCodeItem,
this.ShowLogItem,
this.aboutItem,
this.menuItem3,
this.quitItem});
@@ -301,9 +303,15 @@
this.enableItem.Text = "&Enable";
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
//
this.ServersItem.Index = 1;
this.ServersItem.Index = 2;
this.ServersItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.SeperatorItem,
this.ConfigItem});
@@ -322,35 +330,41 @@
//
// menuItem4
//
this.menuItem4.Index = 2;
this.menuItem4.Index = 3;
this.menuItem4.Text = "-";
//
// editPACFileItem
//
this.editPACFileItem.Index = 3;
this.editPACFileItem.Index = 4;
this.editPACFileItem.Text = "Edit &PAC File...";
this.editPACFileItem.Click += new System.EventHandler(this.EditPACFileItem_Click);
//
// QRCodeItem
//
this.QRCodeItem.Index = 4;
this.QRCodeItem.Index = 5;
this.QRCodeItem.Text = "Show &QRCode...";
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
//
this.aboutItem.Index = 5;
this.aboutItem.Index = 7;
this.aboutItem.Text = "About...";
this.aboutItem.Click += new System.EventHandler(this.AboutItem_Click);
//
// menuItem3
//
this.menuItem3.Index = 6;
this.menuItem3.Index = 8;
this.menuItem3.Text = "-";
//
// quitItem
//
this.quitItem.Index = 7;
this.quitItem.Index = 9;
this.quitItem.Text = "&Quit";
this.quitItem.Click += new System.EventHandler(this.Quit_Click);
//
@@ -404,27 +418,6 @@
this.ServersListBox.TabIndex = 5;
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
//
this.AcceptButton = this.OKButton;
@@ -433,8 +426,6 @@
this.AutoSize = true;
this.CancelButton = this.MyCancelButton;
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.ServerGroupBox);
this.Controls.Add(this.panel1);
@@ -446,7 +437,7 @@
this.MinimizeBox = false;
this.Name = "ConfigForm";
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.Load += new System.EventHandler(this.ConfigForm_Load);
this.Shown += new System.EventHandler(this.ConfigForm_Shown);
@@ -497,8 +488,8 @@
private System.Windows.Forms.TextBox RemarksTextBox;
private System.Windows.Forms.Label label6;
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;
}
}

+ 43
- 6
shadowsocks-csharp/View/ConfigForm.cs View File

@@ -13,6 +13,7 @@ namespace Shadowsocks.View
public partial class ConfigForm : Form
{
private ShadowsocksController controller;
private UpdateChecker updateChecker;
// this is a copy of configuration that we are working on
private Configuration _modifiedConfiguration;
@@ -29,6 +30,10 @@ namespace Shadowsocks.View
controller.EnableStatusChanged += controller_EnableStatusChanged;
controller.ConfigChanged += controller_ConfigChanged;
controller.PACFileReadyToOpen += controller_PACFileReadyToOpen;
controller.ShareOverLANStatusChanged += controller_ShareOverLANStatusChanged;
this.updateChecker = new UpdateChecker();
updateChecker.NewVersionFound += updateChecker_NewVersionFound;
LoadCurrentConfiguration();
}
@@ -43,6 +48,11 @@ namespace Shadowsocks.View
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)
{
string argument = @"/select, " + e.Path;
@@ -50,6 +60,21 @@ namespace Shadowsocks.View
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()
{
@@ -151,7 +176,7 @@ namespace Shadowsocks.View
UpdateServersMenu();
enableItem.Checked = _modifiedConfiguration.enabled;
openOnLanBox.Checked = _modifiedConfiguration.openOnLan;
ShareOverLANItem.Checked = _modifiedConfiguration.shareOverLan;
}
private void UpdateServersMenu()
@@ -192,6 +217,7 @@ namespace Shadowsocks.View
{
_isFirstRun = true;
}
updateChecker.CheckUpdate();
}
private void ServersListBox_SelectedIndexChanged(object sender, EventArgs e)
@@ -258,6 +284,7 @@ namespace Shadowsocks.View
{
notifyIcon1.BalloonTipTitle = "Shadowsocks is here";
notifyIcon1.BalloonTipText = "You can turn on/off Shadowsocks in the context menu";
notifyIcon1.BalloonTipIcon = ToolTipIcon.Info;
notifyIcon1.ShowBalloonTip(0);
_isFirstRun = false;
}
@@ -274,8 +301,7 @@ namespace Shadowsocks.View
MessageBox.Show("Please add at least one server");
return;
}
_modifiedConfiguration.openOnLan = openOnLanBox.Checked;
controller.SaveConfig(_modifiedConfiguration);
controller.SaveServers(_modifiedConfiguration.configs);
this.Hide();
ShowFirstTimeBalloon();
}
@@ -309,6 +335,12 @@ namespace Shadowsocks.View
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)
{
controller.TouchPACFile();
@@ -317,9 +349,14 @@ namespace Shadowsocks.View
private void AServerItem_Click(object sender, EventArgs e)
{
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)


+ 37
- 22
shadowsocks-csharp/View/QRCodeForm.cs View File

@@ -25,35 +25,50 @@ namespace Shadowsocks.View
private void GenQR(string 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);
}
}
}


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

@@ -63,11 +63,14 @@
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.XML" />
</ItemGroup>
<ItemGroup>
<Compile Include="3rd\QRCodeCS.cs" />
<Compile Include="3rd\SimpleJson.cs" />
<Compile Include="Controller\FileManager.cs" />
<Compile Include="Controller\Logging.cs" />
<Compile Include="Controller\UpdateChecker.cs" />
<Compile Include="Encrypt\EncryptorBase.cs" />
<Compile Include="Encrypt\EncryptorFactory.cs" />
<Compile Include="Encrypt\PolarSSL.cs" />


+ 36
- 0
test/Properties/AssemblyInfo.cs View File

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

+ 22
- 0
test/UnitTest.cs View File

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

+ 81
- 0
test/test.csproj View File

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

Loading…
Cancel
Save