Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9ba34373b | ||
|
|
4c49f1b736 | ||
|
|
b266bf42f5 | ||
|
|
2e7518d802 | ||
|
|
18e956f34c | ||
|
|
333ad2516f | ||
|
|
9ffcf77ab1 | ||
|
|
d0d6a3cdfa | ||
|
|
8c76ac3401 | ||
|
|
8f3994c7d8 | ||
|
|
db1eafbfd8 | ||
|
|
32225ed655 | ||
|
|
9e529361c4 | ||
|
|
d21162318e | ||
|
|
f9ed9174cc | ||
|
|
675a5801d8 | ||
|
|
4407095d01 | ||
|
|
1a283aa4ea | ||
|
|
97d08e4d40 | ||
|
|
673d6b3c44 |
@@ -1,3 +1,16 @@
|
|||||||
|
3.4.3 2017-1-11
|
||||||
|
- Make the previous portable mode as default
|
||||||
|
- Refine networking by Noisyfox
|
||||||
|
- Bug fixes and improvements
|
||||||
|
|
||||||
|
3.4.2.1 2016-12-30
|
||||||
|
- Refine Traditional Chinese translation by LNDDYL
|
||||||
|
- sysproxy: reduce false positives on virus detection
|
||||||
|
- sysproxy: set LAN proxy settings even if RAS query fails
|
||||||
|
- privoxy: drop obsolete tray area refreshing code
|
||||||
|
- Fix auto startup
|
||||||
|
- Bug fixes and improvements
|
||||||
|
|
||||||
3.4.2 2016-12-16
|
3.4.2 2016-12-16
|
||||||
- Fix null ref in TCPRelay. (#940)
|
- Fix null ref in TCPRelay. (#940)
|
||||||
- Bring Privoxy back. (#948)
|
- Bring Privoxy back. (#948)
|
||||||
|
|||||||
+19
-19
@@ -994,31 +994,31 @@ https://tls.mbed.org
|
|||||||
License: https://raw.githubusercontent.com/ARMmbed/mbedtls/master/LICENSE
|
License: https://raw.githubusercontent.com/ARMmbed/mbedtls/master/LICENSE
|
||||||
|
|
||||||
|
|
||||||
SimpleJson
|
Newtonsoft.Json
|
||||||
----------
|
----------
|
||||||
|
|
||||||
https://github.com/facebook-csharp-sdk/simple-json
|
https://raw.githubusercontent.com/JamesNK/Newtonsoft.Json/master/LICENSE.md
|
||||||
|
|
||||||
Copyright (c) 2011, The Outercurve Foundation
|
The MIT License (MIT)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Copyright (c) 2007 James Newton-King
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
included in all copies or substantial portions of the Software.
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
The above copyright notice and this permission notice shall be included in all
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
copies or substantial portions of the Software.
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
ZXing
|
ZXing
|
||||||
|
|||||||
@@ -89,11 +89,6 @@ if you want to deactivate all, please clear all textboxes.
|
|||||||
|
|
||||||
Please visit [Servers] for more information.
|
Please visit [Servers] for more information.
|
||||||
|
|
||||||
#### Portable Mode
|
|
||||||
|
|
||||||
If you want to put all temporary files into shadowsocks/temp folder instead of
|
|
||||||
system temp folder, create a `shadowsocks_portable_mode.txt` into shadowsocks folder.
|
|
||||||
|
|
||||||
#### Develop
|
#### Develop
|
||||||
|
|
||||||
[Visual Studio 2015] & [.NET Framework 4.6.2 Developer Pack] are required.
|
[Visual Studio 2015] & [.NET Framework 4.6.2 Developer Pack] are required.
|
||||||
@@ -103,8 +98,8 @@ system temp folder, create a `shadowsocks_portable_mode.txt` into shadowsocks fo
|
|||||||
GPLv3
|
GPLv3
|
||||||
|
|
||||||
|
|
||||||
[Appveyor]: https://ci.appveyor.com/project/Noisyfox/shadowsocks-windows
|
[Appveyor]: https://ci.appveyor.com/project/wongsyrone/shadowsocks-windows-pljx3
|
||||||
[Build Status]: https://ci.appveyor.com/api/projects/status/04idbevayrghcrh7/branch/master?svg=true
|
[Build Status]: https://ci.appveyor.com/api/projects/status/otie4km27ws1wak2/branch/master?svg=true
|
||||||
[latest release]: https://github.com/shadowsocks/shadowsocks-csharp/releases
|
[latest release]: https://github.com/shadowsocks/shadowsocks-csharp/releases
|
||||||
[GFWList]: https://github.com/gfwlist/gfwlist
|
[GFWList]: https://github.com/gfwlist/gfwlist
|
||||||
[Servers]: https://github.com/shadowsocks/shadowsocks/wiki/Ports-and-Clients#linux--server-side
|
[Servers]: https://github.com/shadowsocks/shadowsocks/wiki/Ports-and-Clients#linux--server-side
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace Shadowsocks.Controller
|
namespace Shadowsocks.Controller
|
||||||
{
|
{
|
||||||
public class FileManager
|
public static class FileManager
|
||||||
{
|
{
|
||||||
public static bool ByteArrayToFile(string fileName, byte[] content)
|
public static bool ByteArrayToFile(string fileName, byte[] content)
|
||||||
{
|
{
|
||||||
@@ -16,8 +17,7 @@ namespace Shadowsocks.Controller
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Exception caught in process: {0}",
|
Logging.Error(ex);
|
||||||
ex.ToString());
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -39,5 +39,27 @@ namespace Shadowsocks.Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string NonExclusiveReadAllText(string path)
|
||||||
|
{
|
||||||
|
return NonExclusiveReadAllText(path, Encoding.Default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string NonExclusiveReadAllText(string path, Encoding encoding)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||||
|
using (var sr = new StreamReader(fs, encoding))
|
||||||
|
{
|
||||||
|
return sr.ReadToEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Error(ex);
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ namespace Shadowsocks.Controller
|
|||||||
{
|
{
|
||||||
using Shadowsocks.Properties;
|
using Shadowsocks.Properties;
|
||||||
|
|
||||||
public class I18N
|
public static class I18N
|
||||||
{
|
{
|
||||||
protected static Dictionary<string, string> Strings;
|
private static Dictionary<string, string> _strings = new Dictionary<string, string>();
|
||||||
|
|
||||||
static void Init(string res)
|
private static void Init(string res)
|
||||||
{
|
{
|
||||||
using (var sr = new StringReader(res))
|
using (var sr = new StringReader(res))
|
||||||
{
|
{
|
||||||
@@ -23,38 +23,28 @@ namespace Shadowsocks.Controller
|
|||||||
var pos = line.IndexOf('=');
|
var pos = line.IndexOf('=');
|
||||||
if (pos < 1)
|
if (pos < 1)
|
||||||
continue;
|
continue;
|
||||||
Strings[line.Substring(0, pos)] = line.Substring(pos + 1);
|
_strings[line.Substring(0, pos)] = line.Substring(pos + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static I18N()
|
static I18N()
|
||||||
{
|
{
|
||||||
Strings = new Dictionary<string, string>();
|
string name = CultureInfo.CurrentCulture.EnglishName;
|
||||||
string name = CultureInfo.CurrentCulture.Name;
|
if (name.StartsWith("Chinese", StringComparison.OrdinalIgnoreCase))
|
||||||
if (name.StartsWith("zh"))
|
|
||||||
{
|
{
|
||||||
if (name == "zh" || name == "zh-CN")
|
// choose Traditional Chinese only if we get explicit indication
|
||||||
{
|
Init(name.Contains("Traditional")
|
||||||
Init(Resources.cn);
|
? Resources.zh_tw
|
||||||
}
|
: Resources.cn);
|
||||||
else
|
|
||||||
{
|
|
||||||
Init(Resources.zh_tw);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetString(string key)
|
public static string GetString(string key)
|
||||||
{
|
{
|
||||||
if (Strings.ContainsKey(key))
|
return _strings.ContainsKey(key)
|
||||||
{
|
? _strings[key]
|
||||||
return Strings[key];
|
: key;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ namespace Shadowsocks.Controller
|
|||||||
List<string> lines = ParseResult(e.Result);
|
List<string> lines = ParseResult(e.Result);
|
||||||
if (File.Exists(PACServer.USER_RULE_FILE))
|
if (File.Exists(PACServer.USER_RULE_FILE))
|
||||||
{
|
{
|
||||||
string local = File.ReadAllText(PACServer.USER_RULE_FILE, Encoding.UTF8);
|
string local = FileManager.NonExclusiveReadAllText(PACServer.USER_RULE_FILE, Encoding.UTF8);
|
||||||
using (var sr = new StringReader(local))
|
using (var sr = new StringReader(local))
|
||||||
{
|
{
|
||||||
foreach (var rule in sr.NonWhiteSpaceLines())
|
foreach (var rule in sr.NonWhiteSpaceLines())
|
||||||
@@ -53,7 +53,7 @@ namespace Shadowsocks.Controller
|
|||||||
string abpContent;
|
string abpContent;
|
||||||
if (File.Exists(PACServer.USER_ABP_FILE))
|
if (File.Exists(PACServer.USER_ABP_FILE))
|
||||||
{
|
{
|
||||||
abpContent = File.ReadAllText(PACServer.USER_ABP_FILE, Encoding.UTF8);
|
abpContent = FileManager.NonExclusiveReadAllText(PACServer.USER_ABP_FILE, Encoding.UTF8);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -62,7 +62,7 @@ namespace Shadowsocks.Controller
|
|||||||
abpContent = abpContent.Replace("__RULES__", JsonConvert.SerializeObject(lines, Formatting.Indented));
|
abpContent = abpContent.Replace("__RULES__", JsonConvert.SerializeObject(lines, Formatting.Indented));
|
||||||
if (File.Exists(PACServer.PAC_FILE))
|
if (File.Exists(PACServer.PAC_FILE))
|
||||||
{
|
{
|
||||||
string original = File.ReadAllText(PACServer.PAC_FILE, Encoding.UTF8);
|
string original = FileManager.NonExclusiveReadAllText(PACServer.PAC_FILE, Encoding.UTF8);
|
||||||
if (original == abpContent)
|
if (original == abpContent)
|
||||||
{
|
{
|
||||||
UpdateCompleted(this, new ResultEventArgs(false));
|
UpdateCompleted(this, new ResultEventArgs(false));
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.NetworkInformation;
|
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using Shadowsocks.Model;
|
using Shadowsocks.Model;
|
||||||
@@ -19,9 +15,9 @@ namespace Shadowsocks.Controller
|
|||||||
{
|
{
|
||||||
class PrivoxyRunner
|
class PrivoxyRunner
|
||||||
{
|
{
|
||||||
private static int Uid;
|
private static int _uid;
|
||||||
private static string UniqueConfigFile;
|
private static string _uniqueConfigFile;
|
||||||
private static Job PrivoxyJob;
|
private static Job _privoxyJob;
|
||||||
private Process _process;
|
private Process _process;
|
||||||
private int _runningPort;
|
private int _runningPort;
|
||||||
|
|
||||||
@@ -29,9 +25,9 @@ namespace Shadowsocks.Controller
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Uid = Application.StartupPath.GetHashCode(); // Currently we use ss's StartupPath to identify different Privoxy instance.
|
_uid = Application.StartupPath.GetHashCode(); // Currently we use ss's StartupPath to identify different Privoxy instance.
|
||||||
UniqueConfigFile = $"privoxy_{Uid}.conf";
|
_uniqueConfigFile = $"privoxy_{_uid}.conf";
|
||||||
PrivoxyJob = new Job();
|
_privoxyJob = new Job();
|
||||||
|
|
||||||
FileManager.UncompressFile(Utils.GetTempPath("ss_privoxy.exe"), Resources.privoxy_exe);
|
FileManager.UncompressFile(Utils.GetTempPath("ss_privoxy.exe"), Resources.privoxy_exe);
|
||||||
FileManager.UncompressFile(Utils.GetTempPath("mgwz.dll"), Resources.mgwz_dll);
|
FileManager.UncompressFile(Utils.GetTempPath("mgwz.dll"), Resources.mgwz_dll);
|
||||||
@@ -54,29 +50,33 @@ namespace Shadowsocks.Controller
|
|||||||
KillProcess(p);
|
KillProcess(p);
|
||||||
}
|
}
|
||||||
string privoxyConfig = Resources.privoxy_conf;
|
string privoxyConfig = Resources.privoxy_conf;
|
||||||
_runningPort = this.GetFreePort();
|
_runningPort = GetFreePort();
|
||||||
privoxyConfig = privoxyConfig.Replace("__SOCKS_PORT__", configuration.localPort.ToString());
|
privoxyConfig = privoxyConfig.Replace("__SOCKS_PORT__", configuration.localPort.ToString());
|
||||||
privoxyConfig = privoxyConfig.Replace("__PRIVOXY_BIND_PORT__", _runningPort.ToString());
|
privoxyConfig = privoxyConfig.Replace("__PRIVOXY_BIND_PORT__", _runningPort.ToString());
|
||||||
privoxyConfig = privoxyConfig.Replace("__PRIVOXY_BIND_IP__", configuration.shareOverLan ? "0.0.0.0" : "127.0.0.1");
|
privoxyConfig = privoxyConfig.Replace("__PRIVOXY_BIND_IP__", configuration.shareOverLan ? "0.0.0.0" : "127.0.0.1");
|
||||||
FileManager.ByteArrayToFile(Utils.GetTempPath(UniqueConfigFile), Encoding.UTF8.GetBytes(privoxyConfig));
|
FileManager.ByteArrayToFile(Utils.GetTempPath(_uniqueConfigFile), Encoding.UTF8.GetBytes(privoxyConfig));
|
||||||
|
|
||||||
_process = new Process();
|
_process = new Process
|
||||||
// Configure the process using the StartInfo properties.
|
{
|
||||||
_process.StartInfo.FileName = "ss_privoxy.exe";
|
// Configure the process using the StartInfo properties.
|
||||||
_process.StartInfo.Arguments = UniqueConfigFile;
|
StartInfo =
|
||||||
_process.StartInfo.WorkingDirectory = Utils.GetTempPath();
|
{
|
||||||
_process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
|
FileName = "ss_privoxy.exe",
|
||||||
_process.StartInfo.UseShellExecute = true;
|
Arguments = _uniqueConfigFile,
|
||||||
_process.StartInfo.CreateNoWindow = true;
|
WorkingDirectory = Utils.GetTempPath(),
|
||||||
|
WindowStyle = ProcessWindowStyle.Hidden,
|
||||||
|
UseShellExecute = true,
|
||||||
|
CreateNoWindow = true
|
||||||
|
}
|
||||||
|
};
|
||||||
_process.Start();
|
_process.Start();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add this process to job obj associated with this ss process, so that
|
* Add this process to job obj associated with this ss process, so that
|
||||||
* when ss exit unexpectedly, this process will be forced killed by system.
|
* when ss exit unexpectedly, this process will be forced killed by system.
|
||||||
*/
|
*/
|
||||||
PrivoxyJob.AddProcess(_process.Handle);
|
_privoxyJob.AddProcess(_process.Handle);
|
||||||
}
|
}
|
||||||
RefreshTrayArea();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
@@ -87,7 +87,6 @@ namespace Shadowsocks.Controller
|
|||||||
_process.Dispose();
|
_process.Dispose();
|
||||||
_process = null;
|
_process = null;
|
||||||
}
|
}
|
||||||
RefreshTrayArea();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void KillProcess(Process p)
|
private static void KillProcess(Process p)
|
||||||
@@ -122,21 +121,13 @@ namespace Shadowsocks.Controller
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (Utils.IsPortableMode())
|
/*
|
||||||
{
|
* Under PortableMode, we could identify it by the path of ss_privoxy.exe.
|
||||||
/*
|
*/
|
||||||
* Under PortableMode, we could identify it by the path of ss_privoxy.exe.
|
var path = process.MainModule.FileName;
|
||||||
*/
|
|
||||||
var path = process.MainModule.FileName;
|
|
||||||
|
|
||||||
return Utils.GetTempPath("ss_privoxy.exe").Equals(path);
|
return Utils.GetTempPath("ss_privoxy.exe").Equals(path);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var cmd = process.GetCommandLine();
|
|
||||||
|
|
||||||
return cmd.Contains(UniqueConfigFile);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -169,48 +160,5 @@ namespace Shadowsocks.Controller
|
|||||||
return defaultPort;
|
return defaultPort;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public struct RECT
|
|
||||||
{
|
|
||||||
public int left;
|
|
||||||
public int top;
|
|
||||||
public int right;
|
|
||||||
public int bottom;
|
|
||||||
}
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
public static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
|
|
||||||
|
|
||||||
public void RefreshTrayArea()
|
|
||||||
{
|
|
||||||
IntPtr systemTrayContainerHandle = FindWindow("Shell_TrayWnd", null);
|
|
||||||
IntPtr systemTrayHandle = FindWindowEx(systemTrayContainerHandle, IntPtr.Zero, "TrayNotifyWnd", null);
|
|
||||||
IntPtr sysPagerHandle = FindWindowEx(systemTrayHandle, IntPtr.Zero, "SysPager", null);
|
|
||||||
IntPtr notificationAreaHandle = FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "Notification Area");
|
|
||||||
if (notificationAreaHandle == IntPtr.Zero)
|
|
||||||
{
|
|
||||||
notificationAreaHandle = FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "User Promoted Notification Area");
|
|
||||||
IntPtr notifyIconOverflowWindowHandle = FindWindow("NotifyIconOverflowWindow", null);
|
|
||||||
IntPtr overflowNotificationAreaHandle = FindWindowEx(notifyIconOverflowWindowHandle, IntPtr.Zero, "ToolbarWindow32", "Overflow Notification Area");
|
|
||||||
RefreshTrayArea(overflowNotificationAreaHandle);
|
|
||||||
}
|
|
||||||
RefreshTrayArea(notificationAreaHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void RefreshTrayArea(IntPtr windowHandle)
|
|
||||||
{
|
|
||||||
const uint wmMousemove = 0x0200;
|
|
||||||
RECT rect;
|
|
||||||
GetClientRect(windowHandle, out rect);
|
|
||||||
for (var x = 0; x < rect.right; x += 5)
|
|
||||||
for (var y = 0; y < rect.bottom; y += 5)
|
|
||||||
SendMessage(windowHandle, wmMousemove, 0, (y << 16) + x);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -322,24 +322,15 @@ namespace Shadowsocks.Controller
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int atyp = _connetionRecvBuffer[3];
|
if (_command == 1)
|
||||||
|
|
||||||
switch (atyp)
|
|
||||||
{
|
{
|
||||||
case 1: // IPv4 address, 4 bytes
|
byte[] response = { 5, 0, 0, 1, 0, 0, 0, 0, 0, 0 };
|
||||||
ReadAddress(4 + 2 - 1);
|
_connection.BeginSend(response, 0, response.Length, SocketFlags.None,
|
||||||
break;
|
new AsyncCallback(ResponseCallback), null);
|
||||||
case 3: // domain name, length + str
|
}
|
||||||
int len = _connetionRecvBuffer[4];
|
else if (_command == 3)
|
||||||
ReadAddress(len + 2);
|
{
|
||||||
break;
|
ReadAddress(HandleUDPAssociate);
|
||||||
case 4: // IPv6 address, 16 bytes
|
|
||||||
ReadAddress(16 + 2 - 1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Logging.Debug("Unsupported ATYP=" + atyp);
|
|
||||||
Close();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,12 +347,50 @@ namespace Shadowsocks.Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadAddress(int bytesRemain)
|
private void ResponseCallback(IAsyncResult ar)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_connection.EndSend(ar);
|
||||||
|
|
||||||
|
ReadAddress(StartConnect);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logging.LogUsefulException(e);
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReadAddress(Action onSuccess)
|
||||||
|
{
|
||||||
|
int atyp = _connetionRecvBuffer[3];
|
||||||
|
|
||||||
|
switch (atyp)
|
||||||
|
{
|
||||||
|
case 1: // IPv4 address, 4 bytes
|
||||||
|
ReadAddress(4 + 2 - 1, onSuccess);
|
||||||
|
break;
|
||||||
|
case 3: // domain name, length + str
|
||||||
|
int len = _connetionRecvBuffer[4];
|
||||||
|
ReadAddress(len + 2, onSuccess);
|
||||||
|
break;
|
||||||
|
case 4: // IPv6 address, 16 bytes
|
||||||
|
ReadAddress(16 + 2 - 1, onSuccess);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Logging.Debug("Unsupported ATYP=" + atyp);
|
||||||
|
Close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReadAddress(int bytesRemain, Action onSuccess)
|
||||||
{
|
{
|
||||||
Array.Copy(_connetionRecvBuffer, 3, _connetionRecvBuffer, 0, 2);
|
Array.Copy(_connetionRecvBuffer, 3, _connetionRecvBuffer, 0, 2);
|
||||||
|
|
||||||
// Read the remain address bytes
|
// Read the remain address bytes
|
||||||
_connection.BeginReceive(_connetionRecvBuffer, 2, RecvSize - 2, SocketFlags.None, OnAddressFullyRead, bytesRemain);
|
_connection.BeginReceive(_connetionRecvBuffer, 2, RecvSize - 2, SocketFlags.None, OnAddressFullyRead, new object[] {bytesRemain, onSuccess});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAddressFullyRead(IAsyncResult ar)
|
private void OnAddressFullyRead(IAsyncResult ar)
|
||||||
@@ -370,7 +399,12 @@ namespace Shadowsocks.Controller
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
int bytesRead = _connection.EndReceive(ar);
|
int bytesRead = _connection.EndReceive(ar);
|
||||||
int bytesRemain = (int) ar.AsyncState;
|
|
||||||
|
var states = (object[]) ar.AsyncState;
|
||||||
|
|
||||||
|
int bytesRemain = (int)states[0];
|
||||||
|
var onSuccess = (Action) states[1];
|
||||||
|
|
||||||
if (bytesRead >= bytesRemain)
|
if (bytesRead >= bytesRemain)
|
||||||
{
|
{
|
||||||
_firstPacketLength = bytesRead + 2;
|
_firstPacketLength = bytesRead + 2;
|
||||||
@@ -405,16 +439,7 @@ namespace Shadowsocks.Controller
|
|||||||
|
|
||||||
_destEndPoint = SocketUtil.GetEndPoint(dst_addr, dst_port);
|
_destEndPoint = SocketUtil.GetEndPoint(dst_addr, dst_port);
|
||||||
|
|
||||||
if (_command == 1)
|
onSuccess.Invoke();
|
||||||
{
|
|
||||||
byte[] response = {5, 0, 0, 1, 0, 0, 0, 0, 0, 0};
|
|
||||||
_connection.BeginSend(response, 0, response.Length, SocketFlags.None,
|
|
||||||
new AsyncCallback(ResponseCallback), null);
|
|
||||||
}
|
|
||||||
else if (_command == 3)
|
|
||||||
{
|
|
||||||
HandleUDPAssociate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -479,20 +504,6 @@ namespace Shadowsocks.Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ResponseCallback(IAsyncResult ar)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_connection.EndSend(ar);
|
|
||||||
StartConnect();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logging.LogUsefulException(e);
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// inner class
|
// inner class
|
||||||
private class ProxyTimer : Timer
|
private class ProxyTimer : Timer
|
||||||
{
|
{
|
||||||
@@ -716,6 +727,26 @@ namespace Shadowsocks.Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// private static readonly Random Rnd = new Random();
|
||||||
|
|
||||||
|
private void TryReadAvailableData()
|
||||||
|
{
|
||||||
|
int available = Math.Min(_connection.Available, RecvSize - _firstPacketLength);
|
||||||
|
if (available > 0)
|
||||||
|
{
|
||||||
|
// Pick a random chunk size, or is it truly necessary? Random packet size is some sort of 'characteristic' itself.
|
||||||
|
//lock (Rnd)
|
||||||
|
//{
|
||||||
|
// available = Rnd.Next(available + 1);
|
||||||
|
//}
|
||||||
|
|
||||||
|
var size = _connection.Receive(_connetionRecvBuffer, _firstPacketLength, available,
|
||||||
|
SocketFlags.None);
|
||||||
|
|
||||||
|
_firstPacketLength += size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void StartPipe(AsyncSession session)
|
private void StartPipe(AsyncSession session)
|
||||||
{
|
{
|
||||||
if (_closed) return;
|
if (_closed) return;
|
||||||
@@ -723,6 +754,9 @@ namespace Shadowsocks.Controller
|
|||||||
{
|
{
|
||||||
_startReceivingTime = DateTime.Now;
|
_startReceivingTime = DateTime.Now;
|
||||||
session.Remote.BeginReceive(_remoteRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeRemoteReceiveCallback), session);
|
session.Remote.BeginReceive(_remoteRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeRemoteReceiveCallback), session);
|
||||||
|
|
||||||
|
TryReadAvailableData();
|
||||||
|
Logging.Debug($"_firstPacketLength = {_firstPacketLength}");
|
||||||
SendToServer(_firstPacketLength, session);
|
SendToServer(_firstPacketLength, session);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace Shadowsocks.Controller
|
|||||||
public string LatestVersionLocalName;
|
public string LatestVersionLocalName;
|
||||||
public event EventHandler CheckUpdateCompleted;
|
public event EventHandler CheckUpdateCompleted;
|
||||||
|
|
||||||
public const string Version = "3.4.2";
|
public const string Version = "3.4.3";
|
||||||
|
|
||||||
private class CheckUpdateTimer : System.Timers.Timer
|
private class CheckUpdateTimer : System.Timers.Timer
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -557,10 +557,10 @@ namespace Shadowsocks.Controller
|
|||||||
UpdatePACFromGFWList();
|
UpdatePACFromGFWList();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<string> lines = GFWListUpdater.ParseResult(File.ReadAllText(Utils.GetTempPath("gfwlist.txt")));
|
List<string> lines = GFWListUpdater.ParseResult(FileManager.NonExclusiveReadAllText(Utils.GetTempPath("gfwlist.txt")));
|
||||||
if (File.Exists(PACServer.USER_RULE_FILE))
|
if (File.Exists(PACServer.USER_RULE_FILE))
|
||||||
{
|
{
|
||||||
string local = File.ReadAllText(PACServer.USER_RULE_FILE, Encoding.UTF8);
|
string local = FileManager.NonExclusiveReadAllText(PACServer.USER_RULE_FILE, Encoding.UTF8);
|
||||||
using (var sr = new StringReader(local))
|
using (var sr = new StringReader(local))
|
||||||
{
|
{
|
||||||
foreach (var rule in sr.NonWhiteSpaceLines())
|
foreach (var rule in sr.NonWhiteSpaceLines())
|
||||||
@@ -574,7 +574,7 @@ namespace Shadowsocks.Controller
|
|||||||
string abpContent;
|
string abpContent;
|
||||||
if (File.Exists(PACServer.USER_ABP_FILE))
|
if (File.Exists(PACServer.USER_ABP_FILE))
|
||||||
{
|
{
|
||||||
abpContent = File.ReadAllText(PACServer.USER_ABP_FILE, Encoding.UTF8);
|
abpContent = FileManager.NonExclusiveReadAllText(PACServer.USER_ABP_FILE, Encoding.UTF8);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -583,7 +583,7 @@ namespace Shadowsocks.Controller
|
|||||||
abpContent = abpContent.Replace("__RULES__", JsonConvert.SerializeObject(lines, Formatting.Indented));
|
abpContent = abpContent.Replace("__RULES__", JsonConvert.SerializeObject(lines, Formatting.Indented));
|
||||||
if (File.Exists(PACServer.PAC_FILE))
|
if (File.Exists(PACServer.PAC_FILE))
|
||||||
{
|
{
|
||||||
string original = File.ReadAllText(PACServer.PAC_FILE, Encoding.UTF8);
|
string original = FileManager.NonExclusiveReadAllText(PACServer.PAC_FILE, Encoding.UTF8);
|
||||||
if (original == abpContent)
|
if (original == abpContent)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,20 +1,24 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using Shadowsocks.Util;
|
using Shadowsocks.Util;
|
||||||
|
|
||||||
namespace Shadowsocks.Controller
|
namespace Shadowsocks.Controller
|
||||||
{
|
{
|
||||||
class AutoStartup
|
static class AutoStartup
|
||||||
{
|
{
|
||||||
static string Key = "Shadowsocks_" + Application.StartupPath.GetHashCode();
|
// Don't use Application.ExecutablePath
|
||||||
|
// see https://stackoverflow.com/questions/12945805/odd-c-sharp-path-issue
|
||||||
|
private static readonly string ExecutablePath = Assembly.GetEntryAssembly().Location;
|
||||||
|
|
||||||
|
private static string Key = "Shadowsocks_" + Application.StartupPath.GetHashCode();
|
||||||
|
|
||||||
public static bool Set(bool enabled)
|
public static bool Set(bool enabled)
|
||||||
{
|
{
|
||||||
RegistryKey runKey = null;
|
RegistryKey runKey = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string path = Application.ExecutablePath;
|
|
||||||
runKey = Utils.OpenRegKey(@"Software\Microsoft\Windows\CurrentVersion\Run", true);
|
runKey = Utils.OpenRegKey(@"Software\Microsoft\Windows\CurrentVersion\Run", true);
|
||||||
if ( runKey == null ) {
|
if ( runKey == null ) {
|
||||||
Logging.Error( @"Cannot find HKCU\Software\Microsoft\Windows\CurrentVersion\Run" );
|
Logging.Error( @"Cannot find HKCU\Software\Microsoft\Windows\CurrentVersion\Run" );
|
||||||
@@ -22,7 +26,7 @@ namespace Shadowsocks.Controller
|
|||||||
}
|
}
|
||||||
if (enabled)
|
if (enabled)
|
||||||
{
|
{
|
||||||
runKey.SetValue(Key, path);
|
runKey.SetValue(Key, ExecutablePath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -53,7 +57,6 @@ namespace Shadowsocks.Controller
|
|||||||
RegistryKey runKey = null;
|
RegistryKey runKey = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string path = Application.ExecutablePath;
|
|
||||||
runKey = Utils.OpenRegKey(@"Software\Microsoft\Windows\CurrentVersion\Run", true);
|
runKey = Utils.OpenRegKey(@"Software\Microsoft\Windows\CurrentVersion\Run", true);
|
||||||
if (runKey == null) {
|
if (runKey == null) {
|
||||||
Logging.Error(@"Cannot find HKCU\Software\Microsoft\Windows\CurrentVersion\Run");
|
Logging.Error(@"Cannot find HKCU\Software\Microsoft\Windows\CurrentVersion\Run");
|
||||||
@@ -67,10 +70,10 @@ namespace Shadowsocks.Controller
|
|||||||
else if (item.Equals("Shadowsocks", StringComparison.OrdinalIgnoreCase)) // Compatibility with older versions
|
else if (item.Equals("Shadowsocks", StringComparison.OrdinalIgnoreCase)) // Compatibility with older versions
|
||||||
{
|
{
|
||||||
string value = Convert.ToString(runKey.GetValue(item));
|
string value = Convert.ToString(runKey.GetValue(item));
|
||||||
if (path.Equals(value, StringComparison.OrdinalIgnoreCase))
|
if (ExecutablePath.Equals(value, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
runKey.DeleteValue(item);
|
runKey.DeleteValue(item);
|
||||||
runKey.SetValue(Key, path);
|
runKey.SetValue(Key, ExecutablePath);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ Check for Updates at Startup=启动时检查更新
|
|||||||
Check Pre-release Version=检查测试版更新
|
Check Pre-release Version=检查测试版更新
|
||||||
Edit Hotkeys...=编辑快捷键...
|
Edit Hotkeys...=编辑快捷键...
|
||||||
About...=关于...
|
About...=关于...
|
||||||
|
Help=帮助
|
||||||
Quit=退出
|
Quit=退出
|
||||||
Edit Servers=编辑服务器
|
Edit Servers=编辑服务器
|
||||||
Load Balance=负载均衡
|
Load Balance=负载均衡
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
listen-address __PRIVOXY_BIND_IP__:__PRIVOXY_BIND_PORT__
|
listen-address __PRIVOXY_BIND_IP__:__PRIVOXY_BIND_PORT__
|
||||||
|
toggle 0
|
||||||
|
logfile ss_privoxy.log
|
||||||
show-on-task-bar 0
|
show-on-task-bar 0
|
||||||
activity-animation 0
|
activity-animation 0
|
||||||
forward-socks5 / 127.0.0.1:__SOCKS_PORT__ .
|
forward-socks5 / 127.0.0.1:__SOCKS_PORT__ .
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -10,105 +10,108 @@ PAC=PAC 模式
|
|||||||
Global=全局模式
|
Global=全局模式
|
||||||
Servers=伺服器
|
Servers=伺服器
|
||||||
Edit Servers...=編輯伺服器...
|
Edit Servers...=編輯伺服器...
|
||||||
Statistics Config...=統計配置...
|
Statistics Config...=統計設定檔...
|
||||||
Start on Boot=開機啟動
|
Start on Boot=開機啟動
|
||||||
Forward Proxy...=正向代理設置...
|
Forward Proxy...=正向 Proxy 設定...
|
||||||
Allow Clients from LAN=允許來自區域網路的連接
|
Allow Clients from LAN=允許來自區域網路的連線
|
||||||
Local PAC=使用本地 PAC
|
Local PAC=使用本機 PAC
|
||||||
Online PAC=使用在線 PAC
|
Online PAC=使用線上 PAC
|
||||||
Edit Local PAC File...=編輯本地 PAC 文件...
|
Edit Local PAC File...=編輯本機 PAC 檔案...
|
||||||
Update Local PAC from GFWList=從 GFWList 更新本地 PAC
|
Update Local PAC from GFWList=從 GFWList 更新本機 PAC
|
||||||
Edit User Rule for GFWList...=編輯 GFWList 的用戶規則...
|
Edit User Rule for GFWList...=編輯 GFWList 的使用者規則...
|
||||||
Secure Local PAC=保護本地 PAC
|
Secure Local PAC=安全本機 PAC
|
||||||
Copy Local PAC URL=複製本地 PAC 網址
|
Copy Local PAC URL=複製本機 PAC 網址
|
||||||
Share Server Config...=分享伺服器配置...
|
Share Server Config...=分享伺服器設定檔...
|
||||||
Scan QRCode from Screen...=掃描螢幕上的 QR 碼...
|
Scan QRCode from Screen...=掃描螢幕上的 QR 碼...
|
||||||
Import URL from Clipboard...=從剪貼板導入URL...
|
Import URL from Clipboard...=從剪貼簿匯入 URL...
|
||||||
Availability Statistics=統計可用性
|
Availability Statistics=統計可用性
|
||||||
Show Logs...=顯示日誌...
|
Show Logs...=顯示記錄檔...
|
||||||
Verbose Logging=詳細記錄日誌
|
Verbose Logging=詳細資訊記錄
|
||||||
Updates...=更新...
|
Updates...=更新...
|
||||||
Check for Updates...=檢查更新
|
Check for Updates...=檢查更新
|
||||||
Check for Updates at Startup=啟動時檢查更新
|
Check for Updates at Startup=啟動時檢查更新
|
||||||
Check Pre-release Version=檢查測試版更新
|
Check Pre-release Version=檢查發行前版本更新
|
||||||
Edit Hotkeys...=編輯捷徑鍵...
|
Edit Hotkeys...=編輯快速鍵...
|
||||||
About...=關於...
|
About...=關於...
|
||||||
Quit=退出
|
Help=幫助
|
||||||
|
Quit=結束
|
||||||
Edit Servers=編輯伺服器
|
Edit Servers=編輯伺服器
|
||||||
Load Balance=負載均衡
|
Load Balance=負載平衡
|
||||||
High Availability=高可用
|
High Availability=高可用性
|
||||||
Choose by statistics=根據統計
|
Choose by statistics=根據統計
|
||||||
|
|
||||||
# Config Form
|
# Config Form
|
||||||
|
|
||||||
&Add=新增(&A)
|
&Add=新增 (&A)
|
||||||
&Delete=移除(&D)
|
&Delete=移除 (&D)
|
||||||
Dupli&cate=複製(&C)
|
Dupli&cate=複製 (&C)
|
||||||
Server=伺服器
|
Server=伺服器
|
||||||
Server Addr=伺服器位址
|
Server Addr=伺服器位址
|
||||||
Server Port=伺服器連接埠
|
Server Port=伺服器連接埠
|
||||||
Password=密碼
|
Password=密碼
|
||||||
Encryption=加密
|
Encryption=加密
|
||||||
Proxy Port=代理連接埠
|
Proxy Port=Proxy 連接埠
|
||||||
Remarks=備註
|
Remarks=註解
|
||||||
Timeout(Sec)=超時(秒)
|
Timeout(Sec)=逾時 (秒)
|
||||||
Onetime Authentication=單次驗證
|
Onetime Authentication=單次驗證
|
||||||
OK=確定
|
OK=確定
|
||||||
Cancel=取消
|
Cancel=取消
|
||||||
New server=未配置的伺服器
|
New server=新伺服器
|
||||||
Move &Up=上移(&U)
|
Move &Up=上移 (&U)
|
||||||
Move D&own=下移(&O)
|
Move D&own=下移 (&O)
|
||||||
|
|
||||||
# Proxy Form
|
# Proxy Form
|
||||||
|
|
||||||
Edit Proxy=代理設置
|
Edit Proxy=編輯 Proxy
|
||||||
Use Proxy=使用代理
|
Use Proxy=使用 Proxy
|
||||||
Proxy Type=代理類別
|
Proxy Type=Proxy 類型
|
||||||
Proxy Addr=代理位址
|
Proxy Addr=Proxy 位址
|
||||||
Proxy Port=代理連接埠
|
Proxy Port=Proxy 連接埠
|
||||||
|
|
||||||
# Log Form
|
# Log Form
|
||||||
|
|
||||||
&File=文件(&F)
|
&File=檔案 (&F)
|
||||||
&Open Location=在資料總管中打開(&O)
|
&Open Location=在檔案總管中開啟 (&O)
|
||||||
E&xit=退出(&X)
|
E&xit=結束 (&X)
|
||||||
&View=視圖(&V)
|
&View=檢視
|
||||||
&Clean Logs=清空日誌(&C)
|
|
||||||
Change &Font=設置字體(&F)
|
(&V)
|
||||||
&Wrap Text=自動換行(&W)
|
&Clean Logs=清除記錄檔 (&C)
|
||||||
&Top Most=置頂(&T)
|
Change &Font=變更字型 (&F)
|
||||||
&Show Toolbar=顯示工具欄(&S)
|
&Wrap Text=自動換行 (&W)
|
||||||
Log Viewer=日誌查看器
|
&Top Most=置頂 (&T)
|
||||||
Inbound=入站
|
&Show Toolbar=顯示工具列 (&S)
|
||||||
Outbound=出站
|
Log Viewer=記錄檔檢視器
|
||||||
|
Inbound=輸入
|
||||||
|
Outbound=輸出
|
||||||
|
|
||||||
# QRCode Form
|
# QRCode Form
|
||||||
|
|
||||||
QRCode and URL=QR 碼与 URL
|
QRCode and URL=QR 碼與 URL
|
||||||
|
|
||||||
# PAC Url Form
|
# PAC Url Form
|
||||||
|
|
||||||
Edit Online PAC URL=編輯在線 PAC 網址
|
Edit Online PAC URL=編輯線上 PAC 網址
|
||||||
Edit Online PAC URL...=編輯在線 PAC 網址...
|
Edit Online PAC URL...=編輯線上 PAC 網址...
|
||||||
Please input PAC Url=請輸入 PAC 網址
|
Please input PAC Url=請輸入 PAC 網址
|
||||||
|
|
||||||
# HotkeySettings Form
|
# HotkeySettings Form
|
||||||
|
|
||||||
Switch system proxy=切換系統代理狀態
|
Switch system proxy=切換系統 Proxy 狀態
|
||||||
Switch system proxy mode=切換系統代理模式
|
Switch system proxy mode=切換系統 Proxy 模式
|
||||||
Switch share over LAN=切換區域網路共享
|
Switch share over LAN=切換區域網路共用
|
||||||
Show Logs=顯示日誌
|
Show Logs=顯示記錄檔
|
||||||
Switch to prev server=切換上個伺服器
|
Switch to prev server=切換上一個伺服器
|
||||||
Switch to next server=切換下個伺服器
|
Switch to next server=切換下一個伺服器
|
||||||
Reg All=註冊全部捷徑鍵
|
Reg All=註冊所有快速鍵
|
||||||
|
|
||||||
# Messages
|
# Messages
|
||||||
|
|
||||||
Shadowsocks Error: {0}=Shadowsocks 錯誤: {0}
|
Shadowsocks Error: {0}=Shadowsocks 錯誤: {0}
|
||||||
Port already in use=連接埠號碼已被占用
|
Port already in use=連接埠號碼已被使用
|
||||||
Invalid server address=非法伺服器位址
|
Invalid server address=無效伺服器位址
|
||||||
Illegal port number format=非法連接埠號碼格式
|
Illegal port number format=無效連接埠號碼格式
|
||||||
Illegal timeout format=非法超時格式
|
Illegal timeout format=無效逾時格式
|
||||||
Please add at least one server=請新增至少一個伺服器
|
Please add at least one server=請新增至少一個伺服器
|
||||||
Server IP can not be blank=伺服器 IP 不能為空
|
Server IP can not be blank=伺服器 IP 不能為空
|
||||||
Password can not be blank=密碼不能為空
|
Password can not be blank=密碼不能為空
|
||||||
@@ -116,27 +119,27 @@ Port out of range=連接埠號碼超出範圍
|
|||||||
Port can't be 8123=連接埠號碼不能為 8123
|
Port can't be 8123=連接埠號碼不能為 8123
|
||||||
Shadowsocks {0} Update Found=Shadowsocks {0} 更新
|
Shadowsocks {0} Update Found=Shadowsocks {0} 更新
|
||||||
No update is available=沒有可用的更新
|
No update is available=沒有可用的更新
|
||||||
Click here to update=點擊這裏升級
|
Click here to update=點按此處升級
|
||||||
Shadowsocks is here=Shadowsocks 在這裏
|
Shadowsocks is here=Shadowsocks 在這裡
|
||||||
You can turn on/off Shadowsocks in the context menu=可以在右鍵菜單中開關 Shadowsocks
|
You can turn on/off Shadowsocks in the context menu=可以在右鍵選項單中開關 Shadowsocks
|
||||||
System Proxy Enabled=系統代理已啟用
|
System Proxy Enabled=系統 Proxy 已啟用
|
||||||
System Proxy Disabled=系統代理未啟用
|
System Proxy Disabled=系統 Proxy 未啟用
|
||||||
Failed to update PAC file =更新 PAC 文件失敗
|
Failed to update PAC file =更新 PAC 檔案失敗
|
||||||
PAC updated=更新 PAC 成功
|
PAC updated=更新 PAC 成功
|
||||||
No updates found. Please report to GFWList if you have problems with it.=未發現更新。如有問題請提交給 GFWList。
|
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.=未發現 QR 碼,嘗試把它放大或移動到靠近屏幕中間的位置
|
No QRCode found. Try to zoom in or move it to the center of the screen.=未發現 QR 碼,嘗試把它放大或移動到靠近熒幕中間的位置
|
||||||
Shadowsocks is already running.=Shadowsocks 已經在運行。
|
Shadowsocks is already running.=Shadowsocks 已經在執行。
|
||||||
Find Shadowsocks icon in your notify tray.=請在工作列裏尋找 Shadowsocks 圖標。
|
Find Shadowsocks icon in your notify tray.=請在工作列裡尋找 Shadowsocks 圖示。
|
||||||
If you want to start multiple Shadowsocks, make a copy in another directory.=如果想同時啟動多個,可以另外復制一份到別的目錄。
|
If you want to start multiple Shadowsocks, make a copy in another directory.=如果想同時啟動多個,可以另外複製一份至別的目錄。
|
||||||
Failed to decode QRCode=無法解析 QR 碼
|
Failed to decode QRCode=QR 碼解碼失敗
|
||||||
Failed to update registry=無法修改登錄檔
|
Failed to update registry=無法修改登錄檔
|
||||||
System Proxy On: =系統代理已啟用:
|
System Proxy On: =系統 Proxy 已啟用:
|
||||||
Running: Port {0}=正在運行:連接埠號碼 {0}
|
Running: Port {0}=正在執行:連接埠號碼 {0}
|
||||||
Unexpected error, shadowsocks will exit. Please report to=非預期錯誤,Shadowsocks將退出。請提交此錯誤到
|
Unexpected error, shadowsocks will exit. Please report to=非預期錯誤,Shadowsocks 將結束。請報告此錯誤至
|
||||||
Unsupported operating system, use Windows Vista at least.=不支持的作業系統版本,最低需求為Windows Vista。
|
Unsupported operating system, use Windows Vista at least.=不支援的作業系統版本,最低需求為 Windows Vista。
|
||||||
Unsupported .NET Framework, please update to 4.6.2 or later.=當前 .NET Framework 版本過低,最低需求為4.6.2。
|
Unsupported .NET Framework, please update to 4.6.2 or later.=目前 .NET Framework 版本過低,最低需求為4.6.2。
|
||||||
Proxy request failed=代理請求失敗
|
Proxy request failed=Proxy 要求失敗
|
||||||
Proxy handshake failed=代理握手失敗
|
Proxy handshake failed=Proxy 交握失敗
|
||||||
Register hotkey failed=註冊捷徑鍵失敗
|
Register hotkey failed=註冊快速鍵失敗
|
||||||
Cannot parse hotkey: {0}=解析捷徑鍵失敗: {0}
|
Cannot parse hotkey: {0}=剖析快速鍵失敗: {0}
|
||||||
Timeout is invalid, it should not exceed {0}=超時無效,不應超過 {0}
|
Timeout is invalid, it should not exceed {0}=逾時無效,不應超過 {0}
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ namespace Shadowsocks.Encryption
|
|||||||
#region OneTimeAuth
|
#region OneTimeAuth
|
||||||
|
|
||||||
public const int ONETIMEAUTH_FLAG = 0x10;
|
public const int ONETIMEAUTH_FLAG = 0x10;
|
||||||
public const int ADDRTYPE_MASK = 0xF;
|
public const int ADDRTYPE_MASK = 0xEF;
|
||||||
|
|
||||||
public const int ONETIMEAUTH_BYTES = 10;
|
public const int ONETIMEAUTH_BYTES = 10;
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ using System.Runtime.InteropServices;
|
|||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("")]
|
[assembly: AssemblyCompany("")]
|
||||||
[assembly: AssemblyProduct("Shadowsocks")]
|
[assembly: AssemblyProduct("Shadowsocks")]
|
||||||
[assembly: AssemblyCopyright("clowwindy and community 2016")]
|
[assembly: AssemblyCopyright("clowwindy & community 2017")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
|||||||
@@ -25,43 +25,26 @@ namespace Shadowsocks.Util
|
|||||||
|
|
||||||
public static class Utils
|
public static class Utils
|
||||||
{
|
{
|
||||||
private static bool? _portableMode;
|
private static string _tempPath = null;
|
||||||
private static string TempPath = null;
|
|
||||||
|
|
||||||
public static bool IsPortableMode()
|
|
||||||
{
|
|
||||||
if (!_portableMode.HasValue)
|
|
||||||
{
|
|
||||||
_portableMode = File.Exists(Path.Combine(Application.StartupPath, "shadowsocks_portable_mode.txt"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return _portableMode.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return path to store temporary files
|
// return path to store temporary files
|
||||||
public static string GetTempPath()
|
public static string GetTempPath()
|
||||||
{
|
{
|
||||||
if (TempPath == null)
|
if (_tempPath == null)
|
||||||
{
|
{
|
||||||
if (IsPortableMode())
|
try
|
||||||
try
|
{
|
||||||
{
|
Directory.CreateDirectory(Path.Combine(Application.StartupPath, "ss_win_temp"));
|
||||||
Directory.CreateDirectory(Path.Combine(Application.StartupPath, "temp"));
|
// don't use "/", it will fail when we call explorer /select xxx/ss_win_temp\xxx.log
|
||||||
}
|
_tempPath = Path.Combine(Application.StartupPath, "ss_win_temp");
|
||||||
catch (Exception e)
|
}
|
||||||
{
|
catch (Exception e)
|
||||||
TempPath = Path.GetTempPath();
|
{
|
||||||
Logging.LogUsefulException(e);
|
Logging.Error(e);
|
||||||
}
|
throw;
|
||||||
finally
|
}
|
||||||
{
|
|
||||||
// don't use "/", it will fail when we call explorer /select xxx/temp\xxx.log
|
|
||||||
TempPath = Path.Combine(Application.StartupPath, "temp");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
TempPath = Path.GetTempPath();
|
|
||||||
}
|
}
|
||||||
return TempPath;
|
return _tempPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// return a full path with filename combined which pointed to the temporary directory
|
// return a full path with filename combined which pointed to the temporary directory
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace Shadowsocks.Util
|
namespace Shadowsocks.Util
|
||||||
@@ -17,5 +18,18 @@ namespace Shadowsocks.Util
|
|||||||
var children = control.Controls.OfType<TControl>().ToList();
|
var children = control.Controls.OfType<TControl>().ToList();
|
||||||
return children.SelectMany(GetChildControls<TControl>).Concat(children);
|
return children.SelectMany(GetChildControls<TControl>).Concat(children);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Workaround NotifyIcon's 63 chars limit
|
||||||
|
// https://stackoverflow.com/questions/579665/how-can-i-show-a-systray-tooltip-longer-than-63-chars
|
||||||
|
public static void SetNotifyIconText(NotifyIcon ni, string text)
|
||||||
|
{
|
||||||
|
if (text.Length >= 128)
|
||||||
|
throw new ArgumentOutOfRangeException("Text limited to 127 characters");
|
||||||
|
Type t = typeof(NotifyIcon);
|
||||||
|
BindingFlags hidden = BindingFlags.NonPublic | BindingFlags.Instance;
|
||||||
|
t.GetField("text", hidden).SetValue(ni, text);
|
||||||
|
if ((bool)t.GetField("added", hidden).GetValue(ni))
|
||||||
|
t.GetMethod("UpdateIcon", hidden).Invoke(ni, new object[] { true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,13 +180,13 @@ namespace Shadowsocks.View
|
|||||||
{
|
{
|
||||||
serverInfo = config.GetCurrentServer().FriendlyName();
|
serverInfo = config.GetCurrentServer().FriendlyName();
|
||||||
}
|
}
|
||||||
// we want to show more details but notify icon title is limited to 63 characters
|
// show more info by hacking the P/Invoke declaration for NOTIFYICONDATA inside Windows Forms
|
||||||
string text = I18N.GetString("Shadowsocks") + " " + UpdateChecker.Version + "\n" +
|
string text = I18N.GetString("Shadowsocks") + " " + UpdateChecker.Version + "\n" +
|
||||||
(enabled ?
|
(enabled ?
|
||||||
I18N.GetString("System Proxy On: ") + (global ? I18N.GetString("Global") : I18N.GetString("PAC")) :
|
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
|
String.Format(I18N.GetString("Running: Port {0}"), config.localPort)) // this feedback is very important because they need to know Shadowsocks is running
|
||||||
+ "\n" + serverInfo;
|
+ "\n" + serverInfo;
|
||||||
_notifyIcon.Text = text.Substring(0, Math.Min(63, text.Length));
|
ViewUtils.SetNotifyIconText(_notifyIcon, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bitmap getTrayIconByState(Bitmap originIcon, bool enabled, bool global)
|
private Bitmap getTrayIconByState(Bitmap originIcon, bool enabled, bool global)
|
||||||
@@ -197,11 +197,16 @@ namespace Shadowsocks.View
|
|||||||
for (int y = 0; y < iconCopy.Height; y++)
|
for (int y = 0; y < iconCopy.Height; y++)
|
||||||
{
|
{
|
||||||
Color color = originIcon.GetPixel(x, y);
|
Color color = originIcon.GetPixel(x, y);
|
||||||
if (color.A != 0 && color.R > 30)
|
if (color.A != 0)
|
||||||
{
|
{
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
{
|
{
|
||||||
iconCopy.SetPixel(x, y, Color.FromArgb((byte)(color.A / 1.25), color.R, color.G, color.B));
|
Color flyBlue = Color.FromArgb(192, 192, 192);
|
||||||
|
// Multiply with flyBlue
|
||||||
|
int red = color.R * flyBlue.R / 255;
|
||||||
|
int green = color.G * flyBlue.G / 255;
|
||||||
|
int blue = color.B * flyBlue.B / 255;
|
||||||
|
iconCopy.SetPixel(x, y, Color.FromArgb(color.A, red, green, blue));
|
||||||
}
|
}
|
||||||
else if (global)
|
else if (global)
|
||||||
{
|
{
|
||||||
@@ -282,16 +287,18 @@ namespace Shadowsocks.View
|
|||||||
this.AutoStartupItem = CreateMenuItem("Start on Boot", new EventHandler(this.AutoStartupItem_Click)),
|
this.AutoStartupItem = CreateMenuItem("Start on Boot", new EventHandler(this.AutoStartupItem_Click)),
|
||||||
this.ShareOverLANItem = CreateMenuItem("Allow Clients from LAN", new EventHandler(this.ShareOverLANItem_Click)),
|
this.ShareOverLANItem = CreateMenuItem("Allow Clients from LAN", new EventHandler(this.ShareOverLANItem_Click)),
|
||||||
new MenuItem("-"),
|
new MenuItem("-"),
|
||||||
CreateMenuItem("Show Logs...", new EventHandler(this.ShowLogItem_Click)),
|
|
||||||
this.VerboseLoggingToggleItem = CreateMenuItem( "Verbose Logging", new EventHandler(this.VerboseLoggingToggleItem_Click) ),
|
|
||||||
this.hotKeyItem = CreateMenuItem("Edit Hotkeys...", new EventHandler(this.hotKeyItem_Click)),
|
this.hotKeyItem = CreateMenuItem("Edit Hotkeys...", new EventHandler(this.hotKeyItem_Click)),
|
||||||
CreateMenuGroup("Updates...", new MenuItem[] {
|
CreateMenuGroup("Help", new MenuItem[] {
|
||||||
CreateMenuItem("Check for Updates...", new EventHandler(this.checkUpdatesItem_Click)),
|
CreateMenuItem("Show Logs...", new EventHandler(this.ShowLogItem_Click)),
|
||||||
new MenuItem("-"),
|
this.VerboseLoggingToggleItem = CreateMenuItem( "Verbose Logging", new EventHandler(this.VerboseLoggingToggleItem_Click) ),
|
||||||
this.autoCheckUpdatesToggleItem = CreateMenuItem("Check for Updates at Startup", new EventHandler(this.autoCheckUpdatesToggleItem_Click)),
|
CreateMenuGroup("Updates...", new MenuItem[] {
|
||||||
this.checkPreReleaseToggleItem = CreateMenuItem("Check Pre-release Version", new EventHandler(this.checkPreReleaseToggleItem_Click)),
|
CreateMenuItem("Check for Updates...", new EventHandler(this.checkUpdatesItem_Click)),
|
||||||
|
new MenuItem("-"),
|
||||||
|
this.autoCheckUpdatesToggleItem = CreateMenuItem("Check for Updates at Startup", new EventHandler(this.autoCheckUpdatesToggleItem_Click)),
|
||||||
|
this.checkPreReleaseToggleItem = CreateMenuItem("Check Pre-release Version", new EventHandler(this.checkPreReleaseToggleItem_Click)),
|
||||||
|
}),
|
||||||
|
CreateMenuItem("About...", new EventHandler(this.AboutItem_Click)),
|
||||||
}),
|
}),
|
||||||
CreateMenuItem("About...", new EventHandler(this.AboutItem_Click)),
|
|
||||||
new MenuItem("-"),
|
new MenuItem("-"),
|
||||||
CreateMenuItem("Quit", new EventHandler(this.Quit_Click))
|
CreateMenuItem("Quit", new EventHandler(this.Quit_Click))
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user