Compare commits

...
12 Commits
Author SHA1 Message Date
Syrone Wong 8c76ac3401 Update CHANGES and bump version
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-12-30 19:24:12 +08:00
Syrone Wong 8f3994c7d8 Set LAN even if the RAS query fails
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-12-30 19:12:55 +08:00
Syrone Wong db1eafbfd8 Tweak OTA mask
sync with shadowsocks-libev

Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-12-30 17:28:21 +08:00
LNDDYL 32225ed655 Update translation for Traditional Chinese (#973)
Credit to @LNDDYL
2016-12-30 17:13:46 +08:00
Syrone Wong 9e529361c4 Misc
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-12-23 21:48:30 +08:00
Syrone Wong d21162318e Workaround NotifyIcon's 63 chars limit(#965)
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-12-23 21:41:11 +08:00
Syrone Wong f9ed9174cc Fix crash when reading pac user rules
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-12-23 12:16:26 +08:00
Syrone Wong 675a5801d8 Fix appveyor link
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-12-21 10:39:20 +08:00
Syrone Wong 4407095d01 Fix auto startup
other minor cleanup

Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-12-21 10:36:21 +08:00
Syrone Wong 1a283aa4ea Drop obsolete tray area refreshing code
- naming private vars
- object initializer

Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-12-21 10:36:21 +08:00
Syrone Wong 97d08e4d40 Tweak privoxy config
only redirect
enable critical logging

Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-12-21 10:36:21 +08:00
Syrone Wong 673d6b3c44 update sysproxy
This will reduce false positives on virus detection.
2016-12-21 10:34:27 +08:00
15 changed files with 178 additions and 171 deletions
+8
View File
@@ -1,3 +1,11 @@
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)
+2 -2
View File
@@ -103,8 +103,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
+25 -3
View File
@@ -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;
}
}
} }
} }
@@ -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)
@@ -135,7 +134,7 @@ namespace Shadowsocks.Controller
{ {
var cmd = process.GetCommandLine(); var cmd = process.GetCommandLine();
return cmd.Contains(UniqueConfigFile); return cmd.Contains(_uniqueConfigFile);
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -169,48 +168,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);
}
} }
} }
@@ -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.2.1";
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;
} }
} }
+2
View File
@@ -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.
+83 -81
View File
@@ -10,105 +10,107 @@ 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=退出 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 +118,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}
+1 -1
View File
@@ -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;
+14
View File
@@ -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)