Compare commits

...
53 Commits
Author SHA1 Message Date
clowwindy 9a4f724653 bump 2.3.1 2015-03-06 23:21:56 +08:00
clowwindy fcb0adfc3f add comments in cn.txt 2015-03-06 23:18:23 +08:00
clowwindy eb2e5cc242 add GUI for user rule support 2015-03-06 23:02:07 +08:00
clowwindy 3e16978968 Merge branch 'minoscc-master' 2015-03-04 18:33:41 +08:00
Siuzuk Zan 28887b9896 自定义规则使用user-rule.txt保存 2015-03-04 18:33:13 +08:00
clowwindy d4d3e804cb Merge pull request #174 from wenxiao/master
新增了端口占用检测
2015-02-17 23:35:08 +09:00
WenX 336e0368a1 新增了端口占用检测 2015-02-14 00:14:55 +08:00
clowwindy 138e4f0715 language 2015-01-25 01:18:53 +08:00
clowwindy dbaa2372e2 update README for 2.3 2015-01-25 01:15:49 +08:00
clowwindy 19370a88c5 fix date 2015-01-25 01:10:07 +08:00
clowwindy fbc33ad337 update designer.cs 2015-01-25 01:09:55 +08:00
clowwindy ec5cf089c1 cancel socks5 proxy for chrome 2015-01-25 01:04:26 +08:00
clowwindy 7dca90aef5 update CHANGES 2015-01-25 00:52:40 +08:00
clowwindy 5eaa1b9e2b encourage users to report to gfwlist 2015-01-25 00:51:12 +08:00
clowwindy 700cd3a7e7 show less detail 2015-01-25 00:33:50 +08:00
clowwindy 7cb863b0c2 update some menu title 2015-01-24 23:58:18 +08:00
clowwindy 2d18d8306f update CHANGES 2015-01-24 23:48:48 +08:00
clowwindy f4007b685b update name for share over lan 2015-01-24 23:48:48 +08:00
clowwindy 01f033225b fix typo 2015-01-21 18:53:11 +08:00
clowwindy d3365a8fa4 remove unecessary code 2015-01-21 16:48:57 +08:00
clowwindy 09d57ef0c0 revert 2015-01-21 16:44:00 +08:00
clowwindy b6f1def40f Merge branch 'Sharuru' 2015-01-21 16:40:06 +08:00
Sharuru 7918cb4bd2 Show current mode in tray menu 2015-01-21 16:39:12 +08:00
clowwindy ce53273f33 gzip more 2015-01-19 23:13:22 +08:00
clowwindy b7611a7db7 Merge pull request #140 from GangZhuo/master
fix https://github.com/shadowsocks/shadowsocks-csharp/issues/137
2015-01-19 23:06:20 +08:00
Gang Zhuo b57edeb082 fix https://github.com/shadowsocks/shadowsocks-csharp/issues/137 2015-01-19 05:34:01 -05:00
clowwindy fe991db6da filter prerelase version 2015-01-18 20:31:18 +08:00
Jenkins CI Bot 25386c2f8c Update CONTRIBUTING.md 2015-01-18 19:02:42 +08:00
Jenkins CI Bot 24e5235d59 Update CONTRIBUTING.md 2015-01-18 18:54:36 +08:00
clowwindy 1a0f4807c2 use polipo port in port forwarder 2015-01-18 17:56:43 +08:00
clowwindy 3a34bad62f fix port range 2015-01-18 17:38:27 +08:00
clowwindy b2b11bb97b add fallback for access denied 2015-01-18 17:37:52 +08:00
clowwindy 5463b2859a no hard code 8123 2015-01-18 17:30:42 +08:00
clowwindy 8c8c947356 use local port in gfwlist updater 2015-01-18 17:16:01 +08:00
clowwindy 3e56b3d3a4 use local port in update checker 2015-01-18 17:15:06 +08:00
clowwindy 5aa2822904 use local port in pac 2015-01-18 17:12:59 +08:00
clowwindy 43a952d3d7 update readme 2015-01-18 17:03:38 +08:00
clowwindy 65f0257e6d bump 2015-01-18 17:02:28 +08:00
clowwindy 18e6daf47d update system proxy 2015-01-18 17:01:37 +08:00
clowwindy 788d74cefd add port forwarder 2015-01-18 16:44:09 +08:00
clowwindy edde91c17d lint code 2015-01-18 16:27:08 +08:00
clowwindy e81b87e7df move pac server to listener 2015-01-18 16:26:12 +08:00
clowwindy aa6c38ece3 move local to listener service 2015-01-18 15:53:45 +08:00
clowwindy 444fabaa79 local port now is the same for different servers 2015-01-18 14:44:54 +08:00
clowwindy 42c3776aa5 move proxy port out of group box 2015-01-18 14:30:48 +08:00
clowwindy fb51f30fd9 rename Enable 2015-01-18 14:15:57 +08:00
clowwindy d4bdd2e598 bump 2015-01-18 04:01:20 +08:00
clowwindy 3064314a23 Merge pull request #132 from bombless/patch-1
解决 QRcode 地址解析中密码可能带@符号、服务器名可能带冒号的问题
2015-01-17 11:55:21 +08:00
York Xiang 32941478d7 冒号写成逗号了,我错了…… 2015-01-16 23:19:19 +08:00
York Xiang 3aa325edec 解决 QRcode 地址解析中密码可能带@符号、服务器名可能带冒号的问题
关掉 https://github.com/shadowsocks/shadowsocks-csharp/issues/131
我就是爱用中文,哼~
2015-01-16 23:01:06 +08:00
clowwindy 1bf0c8bd46 refine qr code scan 2015-01-15 19:57:26 +08:00
clowwindy 0040972886 support multiple screens 2015-01-15 19:57:25 +08:00
clowwindy 15f57a4d04 Update README.md 2015-01-15 01:12:04 +08:00
25 changed files with 939 additions and 401 deletions
+10
View File
@@ -1,3 +1,13 @@
2.3 2015-01-25
- Use the same port for every profile
- Use the same port for HTTP/Socks5/PAC
- Fix GFWList PAC compatibility issue with IE11
- Encourage users to report to GFWList when no update found
- Minor UI improvements
2.2.1 2015-01-18
- Fix QR Code compatibility
2.2 2015-01-14
- Support updating PAC from GFWList
- Support adding server by scanning QR Code
+2
View File
@@ -20,6 +20,8 @@ a pull request, or ask some of your friends to do so.
3. We don't answer questions of any other types here. Since very few people
are watching the issue tracker here, you'll probably get no help from here.
Read [Troubleshooting] and get help from forums or [mailing lists].
4. Issues in languages other than English will be Google translated into English
later.
[Troubleshooting]: https://github.com/clowwindy/shadowsocks/wiki/Troubleshooting
+8 -7
View File
@@ -17,18 +17,19 @@ Download [latest release].
For <= Windows 7, download Shadowsocks-win-x.x.x.zip.
For >= Windows 8, download Shadowsocks-win-dotnet4.0-x.x.x.zip.
For >= Windows 8, download Shadowsocks-win-dotnet4.0-x.x.x.zip, unless you have .Net 2.0 installed.
#### Usage
1. Find Shadowsocks icon in notification tray
2. You can add multiple servers in servers menu
3. Select Enable menu to enable system proxy
4. Leave Enable menu unchecked, Shadowsocks will still provide an HTTP proxy at 127.0.0.1:8123
5. After you saved PAC file with any editor, Shadowsocks will notify browsers
about the change automatically
6. Please disable other proxy addons in your browser, or set them to use
system proxy
3. Select Enable System Proxy menu to enable system proxy. Please disable other
proxy addons in your browser, or set them to use system proxy
4. You can also configure your browser proxy manually if you don't want to enable
system proxy. Set Socks5 or HTTP proxy to 127.0.0.1:1080. You can change this
port in Server -> Edit Servers
5. You can change PAC rules by editing the PAC file. When you save the PAC file
with any editor, Shadowsocks will notify browsers about the change automatically
### Develop
@@ -6,6 +6,7 @@ using System.IO;
using Shadowsocks.Properties;
using SimpleJson;
using Shadowsocks.Util;
using Shadowsocks.Model;
namespace Shadowsocks.Controller
{
@@ -15,22 +16,53 @@ namespace Shadowsocks.Controller
private static string PAC_FILE = PACServer.PAC_FILE;
public event EventHandler UpdateCompleted;
private static string USER_RULE_FILE = PACServer.USER_RULE_FILE;
public event EventHandler<ResultEventArgs> UpdateCompleted;
public event ErrorEventHandler Error;
public class ResultEventArgs : EventArgs
{
public bool Success;
public ResultEventArgs(bool success)
{
this.Success = success;
}
}
private void http_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
try
{
List<string> lines = ParseResult(e.Result);
if (File.Exists(USER_RULE_FILE))
{
string local = File.ReadAllText(USER_RULE_FILE, Encoding.UTF8);
string[] rules = local.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach(string rule in rules)
{
if (rule.StartsWith("!") || rule.StartsWith("["))
continue;
lines.Add(rule);
}
}
string abpContent = Utils.UnGzip(Resources.abp_js);
abpContent = abpContent.Replace("__RULES__", SimpleJson.SimpleJson.SerializeObject(lines));
if (File.Exists(PAC_FILE))
{
string original = File.ReadAllText(PAC_FILE, Encoding.UTF8);
if (original == abpContent)
{
UpdateCompleted(this, new ResultEventArgs(false));
return;
}
}
File.WriteAllText(PAC_FILE, abpContent, Encoding.UTF8);
if (UpdateCompleted != null)
{
UpdateCompleted(this, new EventArgs());
UpdateCompleted(this, new ResultEventArgs(true));
}
}
catch (Exception ex)
@@ -42,10 +74,10 @@ namespace Shadowsocks.Controller
}
}
public void UpdatePACFromGFWList()
public void UpdatePACFromGFWList(Configuration config)
{
WebClient http = new WebClient();
http.Proxy = new WebProxy(IPAddress.Loopback.ToString(), 8123);
http.Proxy = new WebProxy(IPAddress.Loopback.ToString(), config.localPort);
http.DownloadStringCompleted += http_DownloadStringCompleted;
http.DownloadStringAsync(new Uri(GFWLIST_URL));
}
+4
View File
@@ -18,6 +18,10 @@ namespace Shadowsocks.Controller
string[] lines = Regex.Split(Resources.cn, "\r\n|\r|\n");
foreach (string line in lines)
{
if (line.StartsWith("#"))
{
continue;
}
string[] kv = Regex.Split(line, "=");
if (kv.Length == 2)
{
+163
View File
@@ -0,0 +1,163 @@
using Shadowsocks.Model;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
namespace Shadowsocks.Controller
{
public class Listener
{
public interface Service
{
bool Handle(byte[] firstPacket, int length, Socket socket);
}
Configuration _config;
bool _shareOverLAN;
Socket _socket;
IList<Service> _services;
public Listener(IList<Service> services)
{
this._services = services;
}
private bool CheckIfPortInUse(int port)
{
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
IPEndPoint[] ipEndPoints = ipProperties.GetActiveTcpListeners();
foreach (IPEndPoint endPoint in ipEndPoints)
{
if (endPoint.Port == port)
{
return true;
}
}
return false;
}
public void Start(Configuration config)
{
this._config = config;
this._shareOverLAN = config.shareOverLan;
if (CheckIfPortInUse(_config.localPort))
throw new Exception(I18N.GetString("Port already in use"));
try
{
// Create a TCP/IP socket.
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
IPEndPoint localEndPoint = null;
if (_shareOverLAN)
{
localEndPoint = new IPEndPoint(IPAddress.Any, _config.localPort);
}
else
{
localEndPoint = new IPEndPoint(IPAddress.Loopback, _config.localPort);
}
// Bind the socket to the local endpoint and listen for incoming connections.
_socket.Bind(localEndPoint);
_socket.Listen(1024);
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Shadowsocks started");
_socket.BeginAccept(
new AsyncCallback(AcceptCallback),
_socket);
}
catch (SocketException)
{
_socket.Close();
throw;
}
}
public void Stop()
{
if (_socket != null)
{
_socket.Close();
_socket = null;
}
}
public void AcceptCallback(IAsyncResult ar)
{
Socket listener = (Socket)ar.AsyncState;
try
{
Socket conn = listener.EndAccept(ar);
byte[] buf = new byte[4096];
object[] state = new object[] {
conn,
buf
};
conn.BeginReceive(buf, 0, buf.Length, 0,
new AsyncCallback(ReceiveCallback), state);
}
catch (ObjectDisposedException)
{
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
try
{
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
}
catch (ObjectDisposedException)
{
// do nothing
}
catch (Exception e)
{
Logging.LogUsefulException(e);
}
}
}
private void ReceiveCallback(IAsyncResult ar)
{
object[] state = (object[])ar.AsyncState;
Socket conn = (Socket)state[0];
byte[] buf = (byte[])state[1];
try
{
int bytesRead = conn.EndReceive(ar);
foreach (Service service in _services)
{
if (service.Handle(buf, bytesRead, conn))
{
return;
}
}
// no service found for this
// shouldn't happen
conn.Close();
}
catch (Exception e)
{
Console.WriteLine(e);
conn.Close();
}
}
}
}
+27 -105
View File
@@ -9,105 +9,43 @@ using Shadowsocks.Model;
namespace Shadowsocks.Controller
{
class Local
class Local : Listener.Service
{
private Server _server;
private bool _shareOverLAN;
//private Encryptor encryptor;
Socket _listener;
private Configuration _config;
public Local(Configuration config)
{
this._server = config.GetCurrentServer();
_shareOverLAN = config.shareOverLan;
//this.encryptor = new Encryptor(config.method, config.password);
this._config = config;
}
public void Start()
public bool Handle(byte[] firstPacket, int length, Socket socket)
{
try
if (length < 2 || firstPacket[0] != 5)
{
// 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 (_shareOverLAN)
{
localEndPoint = new IPEndPoint(IPAddress.Any, _server.local_port);
}
else
{
localEndPoint = new IPEndPoint(IPAddress.Loopback, _server.local_port);
}
// Bind the socket to the local endpoint and listen for incoming connections.
_listener.Bind(localEndPoint);
_listener.Listen(100);
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Shadowsocks started");
_listener.BeginAccept(
new AsyncCallback(AcceptCallback),
_listener);
}
catch(SocketException)
{
_listener.Close();
throw;
return false;
}
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
Handler handler = new Handler();
handler.connection = socket;
Server server = _config.GetCurrentServer();
handler.encryptor = EncryptorFactory.GetEncryptor(server.method, server.password);
handler.server = server;
handler.Start(firstPacket, length);
return true;
}
public void Stop()
{
_listener.Close();
}
public void AcceptCallback(IAsyncResult ar)
{
Socket listener = (Socket)ar.AsyncState;
try
{
Socket conn = listener.EndAccept(ar);
conn.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
Handler handler = new Handler();
handler.connection = conn;
handler.encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password);
handler.config = _server;
handler.Start();
}
catch
{
//Console.WriteLine(e.Message);
}
finally
{
try
{
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
}
catch
{
//Console.WriteLine(e.Message);
}
}
}
}
class Handler
{
//public Encryptor encryptor;
public IEncryptor encryptor;
public Server config;
public Server server;
// Client socket.
public Socket remote;
public Socket connection;
private byte[] _firstPacket;
private int _firstPacketLength;
// Size of receive buffer.
public const int RecvSize = 16384;
public const int BufferSize = RecvSize + 32;
@@ -128,19 +66,21 @@ namespace Shadowsocks.Controller
private object encryptionLock = new object();
private object decryptionLock = new object();
public void Start()
public void Start(byte[] firstPacket, int length)
{
this._firstPacket = firstPacket;
this._firstPacketLength = length;
try
{
// TODO async resolving
IPAddress ipAddress;
bool parsed = IPAddress.TryParse(config.server, out ipAddress);
bool parsed = IPAddress.TryParse(server.server, out ipAddress);
if (!parsed)
{
IPHostEntry ipHostInfo = Dns.GetHostEntry(config.server);
IPHostEntry ipHostInfo = Dns.GetHostEntry(server.server);
ipAddress = ipHostInfo.AddressList[0];
}
IPEndPoint remoteEP = new IPEndPoint(ipAddress, config.server_port);
IPEndPoint remoteEP = new IPEndPoint(ipAddress, server.server_port);
remote = new Socket(ipAddress.AddressFamily,
@@ -240,33 +180,15 @@ namespace Shadowsocks.Controller
}
try
{
connection.BeginReceive(connetionRecvBuffer, 0, 256, 0,
new AsyncCallback(HandshakeReceiveCallback), null);
}
catch (Exception e)
{
Logging.LogUsefulException(e);
this.Close();
}
}
private void HandshakeReceiveCallback(IAsyncResult ar)
{
if (closed)
{
return;
}
try
{
int bytesRead = connection.EndReceive(ar);
int bytesRead = _firstPacketLength;
if (bytesRead > 1)
{
byte[] response = { 5, 0 };
if (connetionRecvBuffer[0] != 5)
if (_firstPacket[0] != 5)
{
// reject socks 4
response = new byte[]{ 0, 91 };
response = new byte[] { 0, 91 };
Console.WriteLine("socks 5 protocol error");
}
connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(HandshakeSendCallback), null);
+67 -95
View File
@@ -12,59 +12,76 @@ using System.Text;
namespace Shadowsocks.Controller
{
class PACServer
class PACServer : Listener.Service
{
private static int PORT = 8093;
public static string PAC_FILE = "pac.txt";
private static Configuration config;
Socket _listener;
public static string USER_RULE_FILE = "user-rule.txt";
FileSystemWatcher watcher;
private Configuration _config;
public event EventHandler PACFileChanged;
public void Start(Configuration configuration)
public PACServer()
{
this.WatchPacFile();
}
public void UpdateConfiguration(Configuration config)
{
this._config = config;
}
public bool Handle(byte[] firstPacket, int length, Socket socket)
{
try
{
config = 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 (configuration.shareOverLan)
string request = Encoding.UTF8.GetString(firstPacket, 0, length);
string[] lines = request.Split('\r', '\n');
bool hostMatch = false, pathMatch = false, useSocks = false;
foreach (string line in lines)
{
localEndPoint = new IPEndPoint(IPAddress.Any, PORT);
string[] kv = line.Split(new char[]{':'}, 2);
if (kv.Length == 2)
{
if (kv[0] == "Host")
{
if (kv[1].Trim() == ((IPEndPoint)socket.LocalEndPoint).ToString())
{
hostMatch = true;
}
}
else if (kv[0] == "User-Agent")
{
// we need to drop connections when changing servers
/* if (kv[1].IndexOf("Chrome") >= 0)
{
useSocks = true;
} */
}
}
else if (kv.Length == 1)
{
if (line.IndexOf("pac") >= 0)
{
pathMatch = true;
}
}
}
else
if (hostMatch && pathMatch)
{
localEndPoint = new IPEndPoint(IPAddress.Loopback, PORT);
SendResponse(firstPacket, length, socket, useSocks);
return true;
}
// 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();
return false;
}
catch (SocketException)
catch (ArgumentException)
{
_listener.Close();
throw;
return false;
}
}
public void Stop()
{
if (_listener != null)
{
_listener.Close();
_listener = null;
}
}
public string TouchPACFile()
{
@@ -79,47 +96,16 @@ namespace Shadowsocks.Controller
}
}
// we don't even use it
static byte[] requestBuf = new byte[2048];
public void AcceptCallback(IAsyncResult ar)
internal string TouchUserRuleFile()
{
Socket listener = (Socket)ar.AsyncState;
try
if (File.Exists(USER_RULE_FILE))
{
Socket conn = listener.EndAccept(ar);
object[] state = new object[] {
conn,
requestBuf
};
conn.BeginReceive(requestBuf, 0, requestBuf.Length, 0,
new AsyncCallback(ReceiveCallback), state);
return USER_RULE_FILE;
}
catch (ObjectDisposedException)
else
{
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
try
{
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
}
catch (ObjectDisposedException)
{
// do nothing
}
catch (Exception e)
{
Logging.LogUsefulException(e);
}
File.WriteAllText(USER_RULE_FILE, Resources.user_rule);
return USER_RULE_FILE;
}
}
@@ -135,46 +121,33 @@ namespace Shadowsocks.Controller
}
}
private void ReceiveCallback(IAsyncResult ar)
public void SendResponse(byte[] firstPacket, int length, Socket socket, bool useSocks)
{
object[] state = (object[])ar.AsyncState;
Socket conn = (Socket)state[0];
byte[] requestBuf = (byte[])state[1];
try
{
int bytesRead = conn.EndReceive(ar);
string pac = GetPACContent();
IPEndPoint localEndPoint = (IPEndPoint)conn.LocalEndPoint;
IPEndPoint localEndPoint = (IPEndPoint)socket.LocalEndPoint;
string proxy = GetPACAddress(requestBuf, localEndPoint);
string proxy = GetPACAddress(firstPacket, length, localEndPoint, useSocks);
pac = pac.Replace("__PROXY__", proxy);
if (bytesRead > 0)
{
string text = String.Format(@"HTTP/1.1 200 OK
string text = String.Format(@"HTTP/1.1 200 OK
Server: Shadowsocks
Content-Type: application/x-ns-proxy-autoconfig
Content-Length: {0}
Connection: Close
", System.Text.Encoding.UTF8.GetBytes(pac).Length) + pac;
byte[] response = System.Text.Encoding.UTF8.GetBytes(text);
conn.BeginSend(response, 0, response.Length, 0, new AsyncCallback(SendCallback), conn);
Util.Utils.ReleaseMemory();
}
else
{
conn.Close();
}
byte[] response = System.Text.Encoding.UTF8.GetBytes(text);
socket.BeginSend(response, 0, response.Length, 0, new AsyncCallback(SendCallback), socket);
Util.Utils.ReleaseMemory();
}
catch (Exception e)
{
Console.WriteLine(e);
conn.Close();
socket.Close();
}
}
@@ -213,9 +186,8 @@ Connection: Close
}
}
private string GetPACAddress(byte[] requestBuf, IPEndPoint localEndPoint)
private string GetPACAddress(byte[] requestBuf, int length, IPEndPoint localEndPoint, bool useSocks)
{
string proxy = "PROXY " + localEndPoint.Address + ":8123;";
//try
//{
// string requestString = Encoding.UTF8.GetString(requestBuf);
@@ -229,7 +201,7 @@ Connection: Close
//{
// Console.WriteLine(e);
//}
return proxy;
return (useSocks ? "SOCKS5 " : "PROXY ") + localEndPoint.Address + ":" + this._config.localPort + ";";
}
}
}
+45 -2
View File
@@ -6,6 +6,8 @@ using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Text;
using System.Net.NetworkInformation;
using System.Net;
namespace Shadowsocks.Controller
{
@@ -13,6 +15,7 @@ namespace Shadowsocks.Controller
{
private Process _process;
private static string temppath;
private int _runningPort;
static PolipoRunner()
{
@@ -27,6 +30,14 @@ namespace Shadowsocks.Controller
}
}
public int RunningPort
{
get
{
return _runningPort;
}
}
public void Start(Configuration configuration)
{
Server server = configuration.GetCurrentServer();
@@ -45,8 +56,10 @@ namespace Shadowsocks.Controller
Console.WriteLine(e.ToString());
}
}
string polipoConfig = Resources.polipo_config;
polipoConfig = polipoConfig.Replace("__SOCKS_PORT__", server.local_port.ToString());
string polipoConfig = Resources.polipo_config;
_runningPort = this.GetFreePort();
polipoConfig = polipoConfig.Replace("__SOCKS_PORT__", configuration.localPort.ToString());
polipoConfig = polipoConfig.Replace("__POLIPO_BIND_PORT__", _runningPort.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));
@@ -79,5 +92,35 @@ namespace Shadowsocks.Controller
_process = null;
}
}
private int GetFreePort()
{
int defaultPort = 8123;
try
{
IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties();
IPEndPoint[] tcpEndPoints = properties.GetActiveTcpListeners();
List<int> usedPorts = new List<int>();
foreach (IPEndPoint endPoint in IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners())
{
usedPorts.Add(endPoint.Port);
}
for (int port = defaultPort; port <= 65535; port++)
{
if (!usedPorts.Contains(port))
{
return port;
}
}
}
catch (Exception e)
{
// in case access denied
Logging.LogUsefulException(e);
return defaultPort;
}
throw new Exception("No free port found.");
}
}
}
+264
View File
@@ -0,0 +1,264 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Shadowsocks.Controller
{
class PortForwarder : Listener.Service
{
int _targetPort;
public PortForwarder(int targetPort)
{
this._targetPort = targetPort;
}
public bool Handle(byte[] firstPacket, int length, Socket socket)
{
new Handler().Start(firstPacket, length, socket, this._targetPort);
return true;
}
class Handler
{
private byte[] _firstPacket;
private int _firstPacketLength;
private Socket _local;
private Socket _remote;
private bool _closed = false;
private bool _localShutdown = false;
private bool _remoteShutdown = false;
public const int RecvSize = 16384;
// remote receive buffer
private byte[] remoteRecvBuffer = new byte[RecvSize];
// connection receive buffer
private byte[] connetionRecvBuffer = new byte[RecvSize];
public void Start(byte[] firstPacket, int length, Socket socket, int targetPort)
{
this._firstPacket = firstPacket;
this._firstPacketLength = length;
this._local = socket;
try
{
// TODO async resolving
IPAddress ipAddress;
bool parsed = IPAddress.TryParse("127.0.0.1", out ipAddress);
IPEndPoint remoteEP = new IPEndPoint(ipAddress, targetPort);
_remote = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
_remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
// Connect to the remote endpoint.
_remote.BeginConnect(remoteEP,
new AsyncCallback(ConnectCallback), null);
}
catch (Exception e)
{
Logging.LogUsefulException(e);
this.Close();
}
}
private void ConnectCallback(IAsyncResult ar)
{
if (_closed)
{
return;
}
try
{
_remote.EndConnect(ar);
HandshakeReceive();
}
catch (Exception e)
{
Logging.LogUsefulException(e);
this.Close();
}
}
private void HandshakeReceive()
{
if (_closed)
{
return;
}
try
{
_remote.BeginSend(_firstPacket, 0, _firstPacketLength, 0, new AsyncCallback(StartPipe), null);
}
catch (Exception e)
{
Logging.LogUsefulException(e);
this.Close();
}
}
private void StartPipe(IAsyncResult ar)
{
if (_closed)
{
return;
}
try
{
_remote.EndSend(ar);
_remote.BeginReceive(remoteRecvBuffer, 0, RecvSize, 0,
new AsyncCallback(PipeRemoteReceiveCallback), null);
_local.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0,
new AsyncCallback(PipeConnectionReceiveCallback), null);
}
catch (Exception e)
{
Logging.LogUsefulException(e);
this.Close();
}
}
private void PipeRemoteReceiveCallback(IAsyncResult ar)
{
if (_closed)
{
return;
}
try
{
int bytesRead = _remote.EndReceive(ar);
if (bytesRead > 0)
{
_local.BeginSend(remoteRecvBuffer, 0, bytesRead, 0, new AsyncCallback(PipeConnectionSendCallback), null);
}
else
{
//Console.WriteLine("bytesRead: " + bytesRead.ToString());
_local.Shutdown(SocketShutdown.Send);
_localShutdown = true;
CheckClose();
}
}
catch (Exception e)
{
Logging.LogUsefulException(e);
this.Close();
}
}
private void PipeConnectionReceiveCallback(IAsyncResult ar)
{
if (_closed)
{
return;
}
try
{
int bytesRead = _local.EndReceive(ar);
if (bytesRead > 0)
{
_remote.BeginSend(connetionRecvBuffer, 0, bytesRead, 0, new AsyncCallback(PipeRemoteSendCallback), null);
}
else
{
_remote.Shutdown(SocketShutdown.Send);
_remoteShutdown = true;
CheckClose();
}
}
catch (Exception e)
{
Logging.LogUsefulException(e);
this.Close();
}
}
private void PipeRemoteSendCallback(IAsyncResult ar)
{
if (_closed)
{
return;
}
try
{
_remote.EndSend(ar);
_local.BeginReceive(this.connetionRecvBuffer, 0, RecvSize, 0,
new AsyncCallback(PipeConnectionReceiveCallback), null);
}
catch (Exception e)
{
Logging.LogUsefulException(e);
this.Close();
}
}
private void PipeConnectionSendCallback(IAsyncResult ar)
{
if (_closed)
{
return;
}
try
{
_local.EndSend(ar);
_remote.BeginReceive(this.remoteRecvBuffer, 0, RecvSize, 0,
new AsyncCallback(PipeRemoteReceiveCallback), null);
}
catch (Exception e)
{
Logging.LogUsefulException(e);
this.Close();
}
}
private void CheckClose()
{
if (_localShutdown && _remoteShutdown)
{
this.Close();
}
}
public void Close()
{
lock (this)
{
if (_closed)
{
return;
}
_closed = true;
}
if (_local != null)
{
try
{
_local.Shutdown(SocketShutdown.Both);
_local.Close();
}
catch (Exception e)
{
Logging.LogUsefulException(e);
}
}
if (_remote != null)
{
try
{
_remote.Shutdown(SocketShutdown.Both);
_remote.Close();
}
catch (SocketException e)
{
Logging.LogUsefulException(e);
}
}
}
}
}
}
@@ -17,8 +17,8 @@ namespace Shadowsocks.Controller
private Thread _ramThread;
private Local local;
private PACServer pacServer;
private Listener _listener;
private PACServer _pacServer;
private Configuration _config;
private PolipoRunner polipoRunner;
private GFWListUpdater gfwListUpdater;
@@ -38,8 +38,9 @@ namespace Shadowsocks.Controller
// when user clicked Edit PAC, and PAC file has already created
public event EventHandler<PathEventArgs> PACFileReadyToOpen;
public event EventHandler<PathEventArgs> UserRuleFileReadyToOpen;
public event EventHandler UpdatePACFromGFWListCompleted;
public event EventHandler<GFWListUpdater.ResultEventArgs> UpdatePACFromGFWListCompleted;
public event ErrorEventHandler UpdatePACFromGFWListError;
@@ -74,9 +75,10 @@ namespace Shadowsocks.Controller
return Configuration.Load();
}
public void SaveServers(List<Server> servers)
public void SaveServers(List<Server> servers, int localPort)
{
_config.configs = servers;
_config.localPort = localPort;
SaveConfig(_config);
}
@@ -142,9 +144,9 @@ namespace Shadowsocks.Controller
return;
}
stopped = true;
if (local != null)
if (_listener != null)
{
local.Stop();
_listener.Stop();
}
if (polipoRunner != null)
{
@@ -152,19 +154,28 @@ namespace Shadowsocks.Controller
}
if (_config.enabled)
{
SystemProxy.Disable();
SystemProxy.Update(_config, true);
}
}
public void TouchPACFile()
{
string pacFilename = pacServer.TouchPACFile();
string pacFilename = _pacServer.TouchPACFile();
if (PACFileReadyToOpen != null)
{
PACFileReadyToOpen(this, new PathEventArgs() { Path = pacFilename });
}
}
public void TouchUserRuleFile()
{
string userRuleFilename = _pacServer.TouchUserRuleFile();
if (UserRuleFileReadyToOpen != null)
{
UserRuleFileReadyToOpen(this, new PathEventArgs() { Path = userRuleFilename });
}
}
public string GetQRCodeForCurrentServer()
{
Server server = GetCurrentServer();
@@ -177,7 +188,7 @@ namespace Shadowsocks.Controller
{
if (gfwListUpdater != null)
{
gfwListUpdater.UpdatePACFromGFWList();
gfwListUpdater.UpdatePACFromGFWList(_config);
}
}
@@ -190,11 +201,12 @@ namespace Shadowsocks.Controller
{
polipoRunner = new PolipoRunner();
}
if (pacServer == null)
if (_pacServer == null)
{
pacServer = new PACServer();
pacServer.PACFileChanged += pacServer_PACFileChanged;
_pacServer = new PACServer();
_pacServer.PACFileChanged += pacServer_PACFileChanged;
}
_pacServer.UpdateConfiguration(_config);
if (gfwListUpdater == null)
{
gfwListUpdater = new GFWListUpdater();
@@ -202,11 +214,9 @@ namespace Shadowsocks.Controller
gfwListUpdater.Error += pacServer_PACUpdateError;
}
pacServer.Stop();
if (local != null)
if (_listener != null)
{
local.Stop();
_listener.Stop();
}
// don't put polipoRunner.Start() before pacServer.Stop()
@@ -218,9 +228,13 @@ namespace Shadowsocks.Controller
{
polipoRunner.Start(_config);
local = new Local(_config);
local.Start();
pacServer.Start(_config);
Local local = new Local(_config);
List<Listener.Service> services = new List<Listener.Service>();
services.Add(local);
services.Add(_pacServer);
services.Add(new PortForwarder(polipoRunner.RunningPort));
_listener = new Listener(services);
_listener.Start(_config);
}
catch (Exception e)
{
@@ -259,7 +273,7 @@ namespace Shadowsocks.Controller
{
if (_config.enabled)
{
SystemProxy.Enable(_config.global);
SystemProxy.Update(_config, false);
_systemProxyIsDirty = true;
}
else
@@ -267,7 +281,7 @@ namespace Shadowsocks.Controller
// only switch it off if we have switched it on
if (_systemProxyIsDirty)
{
SystemProxy.Disable();
SystemProxy.Update(_config, false);
_systemProxyIsDirty = false;
}
}
@@ -278,7 +292,7 @@ namespace Shadowsocks.Controller
UpdateSystemProxy();
}
private void pacServer_PACUpdateCompleted(object sender, EventArgs e)
private void pacServer_PACUpdateCompleted(object sender, GFWListUpdater.ResultEventArgs e)
{
if (UpdatePACFromGFWListCompleted != null)
UpdatePACFromGFWListCompleted(this, e);
+22 -27
View File
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.IO;
using Shadowsocks.Model;
namespace Shadowsocks.Controller
{
@@ -25,24 +26,39 @@ namespace Shadowsocks.Controller
_refreshReturn = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0);
}
public static void Enable(bool global)
public static void Update(Configuration config, bool forceDisable)
{
bool global = config.global;
bool enabled = config.enabled;
if (forceDisable)
{
enabled = false;
}
try
{
RegistryKey registry =
Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
true);
if (global)
if (enabled)
{
registry.SetValue("ProxyEnable", 1);
registry.SetValue("ProxyServer", "127.0.0.1:8123");
registry.SetValue("AutoConfigURL", "");
if (global)
{
registry.SetValue("ProxyEnable", 1);
registry.SetValue("ProxyServer", "127.0.0.1:" + config.localPort.ToString());
registry.SetValue("AutoConfigURL", "");
}
else
{
registry.SetValue("ProxyEnable", 0);
registry.SetValue("ProxyServer", "");
registry.SetValue("AutoConfigURL", "http://127.0.0.1:" + config.localPort.ToString() + "/pac?t=" + GetTimestamp(DateTime.Now));
}
}
else
{
registry.SetValue("ProxyEnable", 0);
registry.SetValue("ProxyServer", "");
registry.SetValue("AutoConfigURL", "http://127.0.0.1:8093/pac?t=" + GetTimestamp(DateTime.Now));
registry.SetValue("AutoConfigURL", "");
}
SystemProxy.NotifyIE();
//Must Notify IE first, or the connections do not chanage
@@ -56,27 +72,6 @@ namespace Shadowsocks.Controller
}
}
public static void Disable()
{
try
{
RegistryKey registry =
Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
true);
registry.SetValue("ProxyEnable", 0);
registry.SetValue("ProxyServer", "");
registry.SetValue("AutoConfigURL", "");
SystemProxy.NotifyIE();
CopyProxySettingFromLan();
}
catch (Exception e)
{
Logging.LogUsefulException(e);
// TODO this should be moved into views
MessageBox.Show(I18N.GetString("Failed to update registry"));
}
}
private static void CopyProxySettingFromLan()
{
RegistryKey registry =
@@ -1,4 +1,5 @@
using System;
using Shadowsocks.Model;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
@@ -17,13 +18,13 @@ namespace Shadowsocks.Controller
public string LatestVersionURL;
public event EventHandler NewVersionFound;
public const string Version = "2.2";
public const string Version = "2.3.1";
public void CheckUpdate()
public void CheckUpdate(Configuration config)
{
// TODO test failures
WebClient http = new WebClient();
http.Proxy = new WebProxy(IPAddress.Loopback.ToString(), 8123);
http.Proxy = new WebProxy(IPAddress.Loopback.ToString(), config.localPort);
http.DownloadStringCompleted += http_DownloadStringCompleted;
http.DownloadStringAsync(new Uri(UpdateURL));
}
@@ -74,6 +75,10 @@ namespace Shadowsocks.Controller
private bool IsNewVersion(string url)
{
if (url.IndexOf("prerelease") >= 0)
{
return false;
}
// check dotnet 4.0
AssemblyName[] references = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
Version dotNetVersion = Environment.Version;
Binary file not shown.
+24 -6
View File
@@ -1,19 +1,28 @@
# translation for Simplified Chinese
Shadowsocks=Shadowsocks
Enable=启用代理
Mode=代理模式
# Menu items
Enable System Proxy=启用系统代理
Mode=系统代理模式
PAC=PAC 模式
Global=全局模式
Servers=服务器
Edit Servers...=编辑服务器...
Start on Boot=开机启动
Share over LAN=在局域网共享代理
Allow Clients from LAN=允许来自局域网的连接
Edit PAC File...=编辑 PAC 文件...
Edit User Rule for GFWList...=编辑 GFWList 的用户规则...
Show QRCode...=显示二维码...
Scan QRCode from Screen...=扫描屏幕上的二维码...
Show Logs...=显示日志...
About...=关于...
Quit=退出
Edit Servers=编辑服务器
# Config Form
&Add=添加(&A)
&Delete=删除(&D)
Server=服务器
@@ -26,7 +35,13 @@ Remarks=备注
OK=确定
Cancel=取消
New server=未配置的服务器
# QRCode Form
QRCode=二维码
# Messages
Shadowsocks Error: {0}=Shadowsocks 错误: {0}
Port already in use=端口已被占用
Illegal port number format=非法端口格式
@@ -38,11 +53,14 @@ Shadowsocks {0} Update Found=Shadowsocks {0} 更新
Click here to download=点击这里下载
Shadowsocks is here=Shadowsocks 在这里
You can turn on/off Shadowsocks in the context menu=可以在右键菜单中开关 Shadowsocks
Enabled=已启用代理
Disabled=已禁用代理
System Proxy Enabled=系统代理已启用
System Proxy Disabled=系统代理未启用
Update PAC from GFWList=从 GFWList 更新 PAC
Failed to update PAC file =更新 PAC 文件失败
PAC updated=更新 PAC 成功
No QRCode found. Try to zoom in or move it to the center of the screen.=找不到二维码,尝试把它放大或者移动到靠近屏幕中间的位置
No updates found. Please report to GFWList if you have problems with it.=未发现更新。如有问题请提交给 GFWList。
No QRCode found. Try to zoom in or move it to the center of the screen.=未发现二维码,尝试把它放大或移动到靠近屏幕中间的位置
Failed to decode QRCode=无法解析二维码
Failed to update registry=无法修改注册表
System Proxy On: =系统代理已启用:
Running: Port {0}=正在运行:端口 {0}
+2 -1
View File
@@ -1,4 +1,5 @@
proxyAddress = "__POLIPO_BIND_IP__"
proxyAddress = "__POLIPO_BIND_IP__"
proxyPort = 8123
socksParentProxy = "127.0.0.1:__SOCKS_PORT__"
socksProxyType = socks5
+2
View File
@@ -0,0 +1,2 @@
! Put user rules line by line in this file.
! See https://adblockplus.org/en/filter-cheatsheet
+7 -2
View File
@@ -16,6 +16,7 @@ namespace Shadowsocks.Model
public bool enabled;
public bool shareOverLan;
public bool isDefault;
public int localPort;
private static string CONFIG_FILE = "gui-config.json";
@@ -33,7 +34,6 @@ namespace Shadowsocks.Model
public static void CheckServer(Server server)
{
CheckPort(server.local_port);
CheckPort(server.server_port);
CheckPassword(server.password);
CheckServer(server.server);
@@ -46,6 +46,10 @@ namespace Shadowsocks.Model
string configContent = File.ReadAllText(CONFIG_FILE);
Configuration config = SimpleJson.SimpleJson.DeserializeObject<Configuration>(configContent, new JsonSerializerStrategy());
config.isDefault = false;
if (config.localPort == 0)
{
config.localPort = 1080;
}
return config;
}
catch (Exception e)
@@ -58,6 +62,7 @@ namespace Shadowsocks.Model
{
index = 0,
isDefault = true,
localPort = 1080,
configs = new List<Server>()
{
GetDefaultServer()
@@ -105,7 +110,7 @@ namespace Shadowsocks.Model
}
}
private static void CheckPort(int port)
public static void CheckPort(int port)
{
if (port <= 0 || port > 65535)
{
+22 -9
View File
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
@@ -14,7 +14,6 @@ namespace Shadowsocks.Model
{
public string server;
public int server_port;
public int local_port;
public string password;
public string method;
public string remarks;
@@ -39,7 +38,6 @@ namespace Shadowsocks.Model
{
this.server = "";
this.server_port = 8388;
this.local_port = 1080;
this.method = "aes-256-cfb";
this.password = "";
this.remarks = "";
@@ -50,7 +48,8 @@ namespace Shadowsocks.Model
string[] r1 = Regex.Split(ssURL, "ss://", RegexOptions.IgnoreCase);
string base64 = r1[1].ToString();
byte[] bytes = null;
for (var i = 0; i < 3; i++) {
for (var i = 0; i < 3; i++)
{
try
{
bytes = System.Convert.FromBase64String(base64);
@@ -64,11 +63,25 @@ namespace Shadowsocks.Model
{
throw new FormatException();
}
string[] parts = Encoding.UTF8.GetString(bytes).Split(new char[2] { ':', '@' });
this.method = parts[0].ToString();
this.password = parts[1].ToString();
this.server = parts[2].ToString();
this.server_port = int.Parse(parts[3].ToString());
try
{
string data = Encoding.UTF8.GetString(bytes);
int indexLastAt = data.LastIndexOf('@');
string afterAt = data.Substring(indexLastAt + 1);
int indexLastColon = afterAt.LastIndexOf(':');
this.server_port = int.Parse(afterAt.Substring(indexLastColon + 1));
this.server = afterAt.Substring(0, indexLastColon);
string beforeAt = data.Substring(0, indexLastAt);
string[] parts = beforeAt.Split(new[] { ':' });
this.method = parts[0];
this.password = parts[1];
}
catch (IndexOutOfRangeException)
{
throw new FormatException();
}
}
}
}
+19 -10
View File
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18444
// Runtime Version:4.0.30319.34209
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -72,15 +72,16 @@ namespace Shadowsocks.Properties {
/// <summary>
/// Looks up a localized string similar to Shadowsocks=Shadowsocks
///Enable=启用代理
///Mode=代理模式
///Enable System Proxy=启用系统代理
///Mode=系统代理模式
///PAC=PAC 模式
///Global=全局模式
///Servers=服务器
///Edit Servers...=编辑服务器...
///Start on Boot=开机启动
///Share over LAN=在局域网共享代理
///Allow Clients from LAN=允许来自局域网的连接
///Edit PAC File...=编辑 PAC 文件...
///Edit User Rule for GFWList...=编辑 GFWList 的用户规则...
///Show QRCode...=显示二维码...
///Scan QRCode from Screen...=扫描屏幕上的二维码...
///Show Logs...=显示日志...
@@ -96,11 +97,7 @@ namespace Shadowsocks.Properties {
///Encryption=加密
///Proxy Port=代理端口
///Remarks=备注
///OK=确定
///Cancel=取消
///New server=未配置的服务器
///QRCode=二维码
///Shadowsocks Error: {0}=Shadowsocks [rest of string was truncated]&quot;;.
///OK= [rest of string was truncated]&quot;;.
/// </summary>
internal static string cn {
get {
@@ -119,7 +116,8 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized string similar to proxyAddress = &quot;__POLIPO_BIND_IP__&quot;
/// Looks up a localized string similar to proxyAddress = &quot;__POLIPO_BIND_IP__&quot;
///proxyPort = 8123
///
///socksParentProxy = &quot;127.0.0.1:__SOCKS_PORT__&quot;
///socksProxyType = socks5
@@ -194,5 +192,16 @@ namespace Shadowsocks.Properties {
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized string similar to ! Put user rules line by line in this file.
///! See https://adblockplus.org/en/filter-cheatsheet
///.
/// </summary>
internal static string user_rule {
get {
return ResourceManager.GetString("user_rule", resourceCulture);
}
}
}
}
@@ -148,4 +148,7 @@
<data name="ssw128" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ssw128.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="user_rule" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\data\user-rule.txt;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
</root>
+61 -33
View File
@@ -33,8 +33,6 @@
this.RemarksLabel = new System.Windows.Forms.Label();
this.IPLabel = new System.Windows.Forms.Label();
this.ServerPortLabel = new System.Windows.Forms.Label();
this.ProxyPortTextBox = new System.Windows.Forms.TextBox();
this.ProxyPortLabel = 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();
@@ -49,11 +47,15 @@
this.ServerGroupBox = new System.Windows.Forms.GroupBox();
this.ServersListBox = new System.Windows.Forms.ListBox();
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
this.tableLayoutPanel5 = new System.Windows.Forms.TableLayoutPanel();
this.ProxyPortTextBox = new System.Windows.Forms.TextBox();
this.ProxyPortLabel = new System.Windows.Forms.Label();
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel();
this.tableLayoutPanel1.SuspendLayout();
this.ServerGroupBox.SuspendLayout();
this.tableLayoutPanel2.SuspendLayout();
this.tableLayoutPanel5.SuspendLayout();
this.tableLayoutPanel3.SuspendLayout();
this.tableLayoutPanel4.SuspendLayout();
this.SuspendLayout();
@@ -69,8 +71,6 @@
this.tableLayoutPanel1.Controls.Add(this.RemarksLabel, 0, 5);
this.tableLayoutPanel1.Controls.Add(this.IPLabel, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.ServerPortLabel, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.ProxyPortTextBox, 1, 4);
this.tableLayoutPanel1.Controls.Add(this.ProxyPortLabel, 0, 4);
this.tableLayoutPanel1.Controls.Add(this.PasswordLabel, 0, 2);
this.tableLayoutPanel1.Controls.Add(this.IPTextBox, 1, 0);
this.tableLayoutPanel1.Controls.Add(this.ServerPortTextBox, 1, 1);
@@ -88,13 +88,13 @@
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.Size = new System.Drawing.Size(238, 163);
this.tableLayoutPanel1.Size = new System.Drawing.Size(238, 137);
this.tableLayoutPanel1.TabIndex = 0;
//
// RemarksTextBox
//
this.RemarksTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.RemarksTextBox.Location = new System.Drawing.Point(72, 137);
this.RemarksTextBox.Location = new System.Drawing.Point(72, 111);
this.RemarksTextBox.MaxLength = 32;
this.RemarksTextBox.Name = "RemarksTextBox";
this.RemarksTextBox.Size = new System.Drawing.Size(160, 20);
@@ -105,7 +105,7 @@
//
this.RemarksLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.RemarksLabel.AutoSize = true;
this.RemarksLabel.Location = new System.Drawing.Point(17, 140);
this.RemarksLabel.Location = new System.Drawing.Point(17, 114);
this.RemarksLabel.Name = "RemarksLabel";
this.RemarksLabel.Size = new System.Drawing.Size(49, 13);
this.RemarksLabel.TabIndex = 9;
@@ -131,26 +131,6 @@
this.ServerPortLabel.TabIndex = 1;
this.ServerPortLabel.Text = "Server Port";
//
// ProxyPortTextBox
//
this.ProxyPortTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.ProxyPortTextBox.Location = new System.Drawing.Point(72, 111);
this.ProxyPortTextBox.MaxLength = 10;
this.ProxyPortTextBox.Name = "ProxyPortTextBox";
this.ProxyPortTextBox.Size = new System.Drawing.Size(160, 20);
this.ProxyPortTextBox.TabIndex = 4;
this.ProxyPortTextBox.WordWrap = false;
//
// ProxyPortLabel
//
this.ProxyPortLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.ProxyPortLabel.AutoSize = true;
this.ProxyPortLabel.Location = new System.Drawing.Point(11, 114);
this.ProxyPortLabel.Name = "ProxyPortLabel";
this.ProxyPortLabel.Size = new System.Drawing.Size(55, 13);
this.ProxyPortLabel.TabIndex = 3;
this.ProxyPortLabel.Text = "Proxy Port";
//
// PasswordLabel
//
this.PasswordLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
@@ -292,7 +272,7 @@
this.ServerGroupBox.Location = new System.Drawing.Point(178, 0);
this.ServerGroupBox.Margin = new System.Windows.Forms.Padding(12, 0, 0, 0);
this.ServerGroupBox.Name = "ServerGroupBox";
this.ServerGroupBox.Size = new System.Drawing.Size(249, 200);
this.ServerGroupBox.Size = new System.Drawing.Size(249, 174);
this.ServerGroupBox.TabIndex = 6;
this.ServerGroupBox.TabStop = false;
this.ServerGroupBox.Text = "Server";
@@ -315,6 +295,7 @@
this.tableLayoutPanel2.ColumnCount = 2;
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel5, 1, 1);
this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel3, 1, 2);
this.tableLayoutPanel2.Controls.Add(this.ServersListBox, 0, 0);
this.tableLayoutPanel2.Controls.Add(this.ServerGroupBox, 1, 0);
@@ -326,9 +307,53 @@
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.Size = new System.Drawing.Size(427, 264);
this.tableLayoutPanel2.Size = new System.Drawing.Size(427, 238);
this.tableLayoutPanel2.TabIndex = 7;
//
// tableLayoutPanel5
//
this.tableLayoutPanel5.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Right)));
this.tableLayoutPanel5.AutoSize = true;
this.tableLayoutPanel5.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tableLayoutPanel5.ColumnCount = 2;
this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel5.Controls.Add(this.ProxyPortTextBox, 1, 0);
this.tableLayoutPanel5.Controls.Add(this.ProxyPortLabel, 0, 0);
this.tableLayoutPanel5.Location = new System.Drawing.Point(241, 174);
this.tableLayoutPanel5.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel5.Name = "tableLayoutPanel5";
this.tableLayoutPanel5.Padding = new System.Windows.Forms.Padding(3);
this.tableLayoutPanel5.RowCount = 1;
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 26F));
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 26F));
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 26F));
this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 26F));
this.tableLayoutPanel5.Size = new System.Drawing.Size(186, 32);
this.tableLayoutPanel5.TabIndex = 9;
//
// ProxyPortTextBox
//
this.ProxyPortTextBox.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.ProxyPortTextBox.Location = new System.Drawing.Point(67, 6);
this.ProxyPortTextBox.MaxLength = 10;
this.ProxyPortTextBox.Name = "ProxyPortTextBox";
this.ProxyPortTextBox.Size = new System.Drawing.Size(113, 20);
this.ProxyPortTextBox.TabIndex = 4;
this.ProxyPortTextBox.WordWrap = false;
//
// ProxyPortLabel
//
this.ProxyPortLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.ProxyPortLabel.AutoSize = true;
this.ProxyPortLabel.Location = new System.Drawing.Point(6, 9);
this.ProxyPortLabel.Name = "ProxyPortLabel";
this.ProxyPortLabel.Size = new System.Drawing.Size(55, 13);
this.ProxyPortLabel.TabIndex = 3;
this.ProxyPortLabel.Text = "Proxy Port";
//
// tableLayoutPanel3
//
this.tableLayoutPanel3.AutoSize = true;
@@ -340,7 +365,7 @@
this.tableLayoutPanel3.Controls.Add(this.MyCancelButton, 1, 0);
this.tableLayoutPanel3.Controls.Add(this.OKButton, 0, 0);
this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Right;
this.tableLayoutPanel3.Location = new System.Drawing.Point(268, 235);
this.tableLayoutPanel3.Location = new System.Drawing.Point(268, 209);
this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(3, 3, 0, 3);
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
this.tableLayoutPanel3.RowCount = 1;
@@ -358,7 +383,7 @@
this.tableLayoutPanel4.Controls.Add(this.DeleteButton, 1, 0);
this.tableLayoutPanel4.Controls.Add(this.AddButton, 0, 0);
this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Top;
this.tableLayoutPanel4.Location = new System.Drawing.Point(0, 200);
this.tableLayoutPanel4.Location = new System.Drawing.Point(0, 174);
this.tableLayoutPanel4.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel4.Name = "tableLayoutPanel4";
this.tableLayoutPanel4.RowCount = 1;
@@ -393,6 +418,8 @@
this.ServerGroupBox.PerformLayout();
this.tableLayoutPanel2.ResumeLayout(false);
this.tableLayoutPanel2.PerformLayout();
this.tableLayoutPanel5.ResumeLayout(false);
this.tableLayoutPanel5.PerformLayout();
this.tableLayoutPanel3.ResumeLayout(false);
this.tableLayoutPanel4.ResumeLayout(false);
this.ResumeLayout(false);
@@ -406,11 +433,9 @@
private System.Windows.Forms.Label IPLabel;
private System.Windows.Forms.Label ServerPortLabel;
private System.Windows.Forms.Label PasswordLabel;
private System.Windows.Forms.Label ProxyPortLabel;
private System.Windows.Forms.TextBox IPTextBox;
private System.Windows.Forms.TextBox ServerPortTextBox;
private System.Windows.Forms.TextBox PasswordTextBox;
private System.Windows.Forms.TextBox ProxyPortTextBox;
private System.Windows.Forms.Label EncryptionLabel;
private System.Windows.Forms.ComboBox EncryptionSelect;
private System.Windows.Forms.Panel panel2;
@@ -425,6 +450,9 @@
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel5;
private System.Windows.Forms.TextBox ProxyPortTextBox;
private System.Windows.Forms.Label ProxyPortLabel;
}
}
+5 -3
View File
@@ -79,12 +79,14 @@ namespace Shadowsocks.View
server = IPTextBox.Text,
server_port = int.Parse(ServerPortTextBox.Text),
password = PasswordTextBox.Text,
local_port = int.Parse(ProxyPortTextBox.Text),
method = EncryptionSelect.Text,
remarks = RemarksTextBox.Text
};
int localPort = int.Parse(ProxyPortTextBox.Text);
Configuration.CheckServer(server);
Configuration.CheckPort(localPort);
_modifiedConfiguration.configs[_oldSelectedIndex] = server;
_modifiedConfiguration.localPort = localPort;
return true;
}
@@ -108,7 +110,7 @@ namespace Shadowsocks.View
IPTextBox.Text = server.server;
ServerPortTextBox.Text = server.server_port.ToString();
PasswordTextBox.Text = server.password;
ProxyPortTextBox.Text = server.local_port.ToString();
ProxyPortTextBox.Text = _modifiedConfiguration.localPort.ToString();
EncryptionSelect.Text = server.method ?? "aes-256-cfb";
RemarksTextBox.Text = server.remarks;
ServerGroupBox.Visible = true;
@@ -202,7 +204,7 @@ namespace Shadowsocks.View
MessageBox.Show(I18N.GetString("Please add at least one server"));
return;
}
controller.SaveServers(_modifiedConfiguration.configs);
controller.SaveServers(_modifiedConfiguration.configs, _modifiedConfiguration.localPort);
this.Close();
}
+97 -70
View File
@@ -27,6 +27,7 @@ namespace Shadowsocks.View
private bool _isFirstRun;
private MenuItem enableItem;
private MenuItem modeItem;
private MenuItem AutoStartupItem;
private MenuItem ShareOverLANItem;
private MenuItem SeperatorItem;
@@ -45,7 +46,8 @@ namespace Shadowsocks.View
controller.EnableStatusChanged += controller_EnableStatusChanged;
controller.ConfigChanged += controller_ConfigChanged;
controller.PACFileReadyToOpen += controller_PACFileReadyToOpen;
controller.PACFileReadyToOpen += controller_FileReadyToOpen;
controller.UserRuleFileReadyToOpen += controller_FileReadyToOpen;
controller.ShareOverLANStatusChanged += controller_ShareOverLANStatusChanged;
controller.EnableGlobalChanged += controller_EnableGlobalChanged;
controller.Errored += controller_Errored;
@@ -63,7 +65,7 @@ namespace Shadowsocks.View
LoadCurrentConfiguration();
updateChecker.CheckUpdate();
updateChecker.CheckUpdate(controller.GetConfiguration());
if (controller.GetConfiguration().isDefault)
{
@@ -98,7 +100,9 @@ namespace Shadowsocks.View
{
icon = Resources.ss24;
}
bool enabled = controller.GetConfiguration().enabled;
Configuration config = controller.GetConfiguration();
bool enabled = config.enabled;
bool global = config.global;
if (!enabled)
{
Bitmap iconCopy = new Bitmap(icon);
@@ -107,14 +111,19 @@ namespace Shadowsocks.View
for (int y = 0; y < iconCopy.Height; y++)
{
Color color = icon.GetPixel(x, y);
iconCopy.SetPixel(x, y , Color.FromArgb((byte)(color.A / 1.25), color.R, color.G, color.B));
iconCopy.SetPixel(x, y, Color.FromArgb((byte)(color.A / 1.25), color.R, color.G, color.B));
}
}
icon = iconCopy;
}
_notifyIcon.Icon = Icon.FromHandle(icon.GetHicon());
string text = I18N.GetString("Shadowsocks") + " " + UpdateChecker.Version + "\n" + (enabled ? I18N.GetString("Enabled") : I18N.GetString("Disabled")) + "\n" + controller.GetCurrentServer().FriendlyName();
// we want to show more details but notify icon title is limited to 63 characters
string text = I18N.GetString("Shadowsocks") + " " + UpdateChecker.Version + "\n" +
(enabled ?
I18N.GetString("System Proxy On: ") + (global ? I18N.GetString("Global") : I18N.GetString("PAC")) :
String.Format(I18N.GetString("Running: Port {0}"), config.localPort)) // this feedback is very important because they need to know Shadowsocks is running
+ "\n" + config.GetCurrentServer().FriendlyName();
_notifyIcon.Text = text.Substring(0, Math.Min(63, text.Length));
}
@@ -131,8 +140,8 @@ namespace Shadowsocks.View
private void LoadMenu()
{
this.contextMenu1 = new ContextMenu(new MenuItem[] {
this.enableItem = CreateMenuItem("Enable", new EventHandler(this.EnableItem_Click)),
CreateMenuGroup("Mode", new MenuItem[] {
this.enableItem = CreateMenuItem("Enable System Proxy", new EventHandler(this.EnableItem_Click)),
this.modeItem = CreateMenuGroup("Mode", new MenuItem[] {
this.PACModeItem = CreateMenuItem("PAC", new EventHandler(this.PACModeItem_Click)),
this.globalModeItem = CreateMenuItem("Global", new EventHandler(this.GlobalModeItem_Click))
}),
@@ -143,10 +152,12 @@ namespace Shadowsocks.View
CreateMenuItem("Scan QRCode from Screen...", new EventHandler(this.ScanQRCodeItem_Click))
}),
new MenuItem("-"),
this.AutoStartupItem = CreateMenuItem("Start on Boot", new EventHandler(this.AutoStartupItem_Click)),
this.ShareOverLANItem = CreateMenuItem("Share over LAN", new EventHandler(this.ShareOverLANItem_Click)),
CreateMenuItem("Edit PAC File...", new EventHandler(this.EditPACFileItem_Click)),
CreateMenuItem("Update PAC from GFWList", new EventHandler(this.UpdatePACFromGFWListItem_Click)),
CreateMenuItem("Edit User Rule for GFWList...", new EventHandler(this.EditUserRuleFileForGFWListItem_Click)),
new MenuItem("-"),
this.AutoStartupItem = CreateMenuItem("Start on Boot", new EventHandler(this.AutoStartupItem_Click)),
this.ShareOverLANItem = CreateMenuItem("Allow Clients from LAN", new EventHandler(this.ShareOverLANItem_Click)),
new MenuItem("-"),
CreateMenuItem("Show Logs...", new EventHandler(this.ShowLogItem_Click)),
CreateMenuItem("About...", new EventHandler(this.AboutItem_Click)),
@@ -164,6 +175,7 @@ namespace Shadowsocks.View
private void controller_EnableStatusChanged(object sender, EventArgs e)
{
enableItem.Checked = controller.GetConfiguration().enabled;
modeItem.Enabled = enableItem.Checked;
}
void controller_ShareOverLANStatusChanged(object sender, EventArgs e)
@@ -177,7 +189,7 @@ namespace Shadowsocks.View
PACModeItem.Checked = !globalModeItem.Checked;
}
void controller_PACFileReadyToOpen(object sender, ShadowsocksController.PathEventArgs e)
void controller_FileReadyToOpen(object sender, ShadowsocksController.PathEventArgs e)
{
string argument = @"/select, " + e.Path;
@@ -198,9 +210,10 @@ namespace Shadowsocks.View
Logging.LogUsefulException(e.GetException());
}
void controller_UpdatePACFromGFWListCompleted(object sender, EventArgs e)
void controller_UpdatePACFromGFWListCompleted(object sender, GFWListUpdater.ResultEventArgs e)
{
ShowBalloonTip(I18N.GetString("Shadowsocks"), I18N.GetString("PAC updated"), ToolTipIcon.Info, 1000);
string result = e.Success ? I18N.GetString("PAC updated") : I18N.GetString("No updates found. Please report to GFWList if you have problems with it.");
ShowBalloonTip(I18N.GetString("Shadowsocks"), result, ToolTipIcon.Info, 1000);
}
void updateChecker_NewVersionFound(object sender, EventArgs e)
@@ -222,6 +235,7 @@ namespace Shadowsocks.View
Configuration config = controller.GetConfiguration();
UpdateServersMenu();
enableItem.Checked = config.enabled;
modeItem.Enabled = config.enabled;
globalModeItem.Checked = config.global;
PACModeItem.Checked = !config.global;
ShareOverLANItem.Checked = config.shareOverLan;
@@ -341,6 +355,11 @@ namespace Shadowsocks.View
controller.UpdatePACFromGFWList();
}
private void EditUserRuleFileForGFWListItem_Click(object sender, EventArgs e)
{
controller.TouchUserRuleFile();
}
private void AServerItem_Click(object sender, EventArgs e)
{
MenuItem item = (MenuItem)sender;
@@ -364,74 +383,82 @@ namespace Shadowsocks.View
private void ScanQRCodeItem_Click(object sender, EventArgs e)
{
using (Bitmap fullImage = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
Screen.PrimaryScreen.Bounds.Height))
foreach (Screen screen in Screen.AllScreens)
{
using (Graphics g = Graphics.FromImage(fullImage))
using (Bitmap fullImage = new Bitmap(screen.Bounds.Width,
screen.Bounds.Height))
{
g.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
Screen.PrimaryScreen.Bounds.Y,
0, 0,
fullImage.Size,
CopyPixelOperation.SourceCopy);
}
for (int i = 0; i < 5; i++)
{
int marginLeft = fullImage.Width * i / 3 / 5;
int marginTop = fullImage.Height * i / 3 / 5;
Rectangle cropRect = new Rectangle(marginLeft, marginTop, fullImage.Width - marginLeft * 2, fullImage.Height - marginTop * 2);
Bitmap target = new Bitmap(cropRect.Width, cropRect.Height);
using (Graphics g = Graphics.FromImage(target))
using (Graphics g = Graphics.FromImage(fullImage))
{
g.DrawImage(fullImage, new Rectangle(0, 0, target.Width, target.Height),
cropRect,
GraphicsUnit.Pixel);
g.CopyFromScreen(screen.Bounds.X,
screen.Bounds.Y,
0, 0,
fullImage.Size,
CopyPixelOperation.SourceCopy);
}
var source = new BitmapLuminanceSource(target);
var bitmap = new BinaryBitmap(new HybridBinarizer(source));
QRCodeReader reader = new QRCodeReader();
var result = reader.decode(bitmap);
if (result != null)
int maxTry = 10;
for (int i = 0; i < maxTry; i++)
{
var success = controller.AddServerBySSURL(result.Text);
QRCodeSplashForm splash = new QRCodeSplashForm();
if (success)
int marginLeft = (int)((double)fullImage.Width * i / 2.5 / maxTry);
int marginTop = (int)((double)fullImage.Height * i / 2.5 / maxTry);
Rectangle cropRect = new Rectangle(marginLeft, marginTop, fullImage.Width - marginLeft * 2, fullImage.Height - marginTop * 2);
Bitmap target = new Bitmap(screen.Bounds.Width, screen.Bounds.Height);
double imageScale = (double)screen.Bounds.Width / (double)cropRect.Width;
using (Graphics g = Graphics.FromImage(target))
{
splash.FormClosed += splash_FormClosed;
g.DrawImage(fullImage, new Rectangle(0, 0, target.Width, target.Height),
cropRect,
GraphicsUnit.Pixel);
}
else if (result.Text.StartsWith("http://") || result.Text.StartsWith("https://"))
var source = new BitmapLuminanceSource(target);
var bitmap = new BinaryBitmap(new HybridBinarizer(source));
QRCodeReader reader = new QRCodeReader();
var result = reader.decode(bitmap);
if (result != null)
{
_urlToOpen = result.Text;
splash.FormClosed += openURLFromQRCode;
}
else
{
MessageBox.Show(I18N.GetString("Failed to decode QRCode"));
var success = controller.AddServerBySSURL(result.Text);
QRCodeSplashForm splash = new QRCodeSplashForm();
if (success)
{
splash.FormClosed += splash_FormClosed;
}
else if (result.Text.StartsWith("http://") || result.Text.StartsWith("https://"))
{
_urlToOpen = result.Text;
splash.FormClosed += openURLFromQRCode;
}
else
{
MessageBox.Show(I18N.GetString("Failed to decode QRCode"));
return;
}
double minX = Int32.MaxValue, minY = Int32.MaxValue, maxX = 0, maxY = 0;
foreach (ResultPoint point in result.ResultPoints)
{
minX = Math.Min(minX, point.X);
minY = Math.Min(minY, point.Y);
maxX = Math.Max(maxX, point.X);
maxY = Math.Max(maxY, point.Y);
}
minX /= imageScale;
minY /= imageScale;
maxX /= imageScale;
maxY /= imageScale;
// make it 20% larger
double margin = (maxX - minX) * 0.20f;
minX += -margin + marginLeft;
maxX += margin + marginLeft;
minY += -margin + marginTop;
maxY += margin + marginTop;
splash.Location = new Point(screen.Bounds.X, screen.Bounds.Y);
// we need a panel because a window has a minimal size
// TODO: test on high DPI
splash.TargetRect = new Rectangle((int)minX + screen.Bounds.X, (int)minY + screen.Bounds.Y, (int)maxX - (int)minX, (int)maxY - (int)minY);
splash.Size = new Size(fullImage.Width, fullImage.Height);
splash.Show();
return;
}
float minX = Int32.MaxValue, minY = Int32.MaxValue, maxX = 0, maxY = 0;
foreach (ResultPoint point in result.ResultPoints)
{
minX = Math.Min(minX, point.X);
minY = Math.Min(minY, point.Y);
maxX = Math.Max(maxX, point.X);
maxY = Math.Max(maxY, point.Y);
}
// make it 20% larger
float margin = (maxX - minX) * 0.20f;
minX += -margin + marginLeft;
maxX += margin + marginLeft;
minY += -margin + marginTop;
maxY += margin + marginTop;
splash.Location = new Point(0, 0);
// we need a panel because a window has a minimal size
// TODO: test on high DPI
splash.TargetRect = new Rectangle((int)minX, (int)minY, (int)maxX - (int)minX, (int)maxY - (int)minY);
splash.Size = new Size(fullImage.Width, fullImage.Height);
splash.Show();
return;
}
}
}
@@ -127,7 +127,9 @@
<Compile Include="Controller\FileManager.cs" />
<Compile Include="Controller\GFWListUpdater.cs" />
<Compile Include="Controller\I18N.cs" />
<Compile Include="Controller\Listener.cs" />
<Compile Include="Controller\Logging.cs" />
<Compile Include="Controller\PortForwarder.cs" />
<Compile Include="Controller\UpdateChecker.cs" />
<Compile Include="Encryption\EncryptorBase.cs" />
<Compile Include="Encryption\EncryptorFactory.cs" />
@@ -196,6 +198,7 @@
<None Include="Resources\ss24.png" />
<None Include="Resources\ssw128.png" />
<Content Include="Data\cn.txt" />
<Content Include="Data\user-rule.txt" />
<Content Include="shadowsocks.ico" />
<None Include="Data\polipo_config.txt" />
</ItemGroup>