add new menu to update pac file via gfwlist
This commit is contained in:
@@ -16,186 +16,84 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
private const string GFWLIST_URL = "https://autoproxy-gfwlist.googlecode.com/svn/trunk/gfwlist.txt";
|
||||
|
||||
private const int EXPIRE_HOURS = 6;
|
||||
|
||||
public IWebProxy proxy = null;
|
||||
|
||||
public bool useSystemProxy = true;
|
||||
|
||||
public class GfwListChangedArgs : EventArgs
|
||||
public class GfwListDownloadCompletedArgs : EventArgs
|
||||
{
|
||||
public string[] GfwList { get; set; }
|
||||
public string Content;
|
||||
}
|
||||
|
||||
public event EventHandler<GfwListChangedArgs> GfwListChanged;
|
||||
public event EventHandler<GfwListDownloadCompletedArgs> DownloadCompleted;
|
||||
|
||||
private bool running = false;
|
||||
private bool closed = false;
|
||||
private int jobId = 0;
|
||||
DateTime lastUpdateTimeUtc;
|
||||
string lastUpdateMd5;
|
||||
public event ErrorEventHandler Error;
|
||||
|
||||
private object locker = new object();
|
||||
|
||||
public GfwListUpdater()
|
||||
public void Download()
|
||||
{
|
||||
WebClient http = new WebClient();
|
||||
http.Proxy = proxy;
|
||||
http.DownloadStringCompleted += http_DownloadStringCompleted;
|
||||
http.DownloadStringAsync(new Uri(GFWLIST_URL));
|
||||
}
|
||||
|
||||
~GfwListUpdater()
|
||||
protected void ReportError(Exception e)
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
lock (locker)
|
||||
if (Error != null)
|
||||
{
|
||||
if (running)
|
||||
return;
|
||||
running = true;
|
||||
closed = false;
|
||||
jobId++;
|
||||
new Thread(new ParameterizedThreadStart(UpdateJob)).Start(jobId);
|
||||
Error(this, new ErrorEventArgs(e));
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
lock(locker)
|
||||
{
|
||||
closed = true;
|
||||
running = false;
|
||||
jobId++;
|
||||
}
|
||||
}
|
||||
|
||||
public void ScheduleUpdateTime(int delaySeconds)
|
||||
{
|
||||
lock(locker)
|
||||
{
|
||||
lastUpdateTimeUtc = DateTime.UtcNow.AddHours(-1 * EXPIRE_HOURS).AddSeconds(delaySeconds);
|
||||
}
|
||||
}
|
||||
|
||||
private string DownloadGfwListFile()
|
||||
private void http_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
WebClient http = new WebClient();
|
||||
http.Proxy = useSystemProxy ? WebRequest.GetSystemWebProxy() : proxy;
|
||||
return http.DownloadString(new Uri(GFWLIST_URL));
|
||||
string response = e.Result;
|
||||
if (DownloadCompleted != null)
|
||||
{
|
||||
DownloadCompleted(this, new GfwListDownloadCompletedArgs
|
||||
{
|
||||
Content = response
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.ToString());
|
||||
ReportError(ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool IsExpire()
|
||||
public class Parser
|
||||
{
|
||||
lock (locker)
|
||||
private string _Content;
|
||||
|
||||
public string Content
|
||||
{
|
||||
TimeSpan ts = DateTime.UtcNow - lastUpdateTimeUtc;
|
||||
bool expire = ((int)ts.TotalHours) >= EXPIRE_HOURS;
|
||||
if (expire)
|
||||
lastUpdateTimeUtc = DateTime.UtcNow;
|
||||
return expire;
|
||||
get { return _Content; }
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsJobStop(int currentJobId)
|
||||
{
|
||||
lock (locker)
|
||||
{
|
||||
if (!running || closed || currentJobId != this.jobId)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsGfwListChanged(string content)
|
||||
{
|
||||
byte[] inputBytes = Encoding.UTF8.GetBytes(content);
|
||||
byte[] md5Bytes = MD5.Create().ComputeHash(inputBytes);
|
||||
string md5 = "";
|
||||
for (int i = 0; i < md5Bytes.Length; i++)
|
||||
md5 += md5Bytes[i].ToString("x").PadLeft(2, '0');
|
||||
if (md5 == lastUpdateMd5)
|
||||
return false;
|
||||
lastUpdateMd5 = md5;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ParseGfwList(string response)
|
||||
{
|
||||
if (!IsGfwListChanged(response))
|
||||
return;
|
||||
if (GfwListChanged != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Parser parser = new Parser(response);
|
||||
GfwListChangedArgs args = new GfwListChangedArgs
|
||||
{
|
||||
GfwList = parser.GetReducedDomains()
|
||||
};
|
||||
GfwListChanged(this, args);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateJob(object state)
|
||||
{
|
||||
int currentJobId = (int)state;
|
||||
int retryTimes = 3;
|
||||
while (!IsJobStop(currentJobId))
|
||||
{
|
||||
if (IsExpire())
|
||||
{
|
||||
string response = DownloadGfwListFile();
|
||||
if (response != null)
|
||||
{
|
||||
ParseGfwList(response);
|
||||
}
|
||||
else if (retryTimes > 0)
|
||||
{
|
||||
ScheduleUpdateTime(30); /*Delay 30 seconds to retry*/
|
||||
retryTimes--;
|
||||
}
|
||||
else
|
||||
{
|
||||
retryTimes = 3; /* reset retry times, and wait next update time. */
|
||||
}
|
||||
}
|
||||
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
class Parser
|
||||
{
|
||||
public string Content { get; private set; }
|
||||
|
||||
public Parser(string response)
|
||||
{
|
||||
byte[] bytes = Convert.FromBase64String(response);
|
||||
this.Content = Encoding.ASCII.GetString(bytes);
|
||||
this._Content = Encoding.ASCII.GetString(bytes);
|
||||
}
|
||||
|
||||
public string[] GetLines()
|
||||
public string[] GetValidLines()
|
||||
{
|
||||
return Content.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
string[] lines = Content.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
List<string> valid_lines = new List<string>(lines.Length);
|
||||
foreach (string line in lines)
|
||||
{
|
||||
if (line.StartsWith("!") || line.StartsWith("["))
|
||||
continue;
|
||||
valid_lines.Add(line);
|
||||
}
|
||||
return valid_lines.ToArray();
|
||||
}
|
||||
|
||||
|
||||
/* refer https://github.com/clowwindy/gfwlist2pac/blob/master/gfwlist2pac/main.py */
|
||||
public string[] GetDomains()
|
||||
{
|
||||
List<string> lines = new List<string>(GetLines());
|
||||
List<string> lines = new List<string>(GetValidLines());
|
||||
lines.AddRange(GetBuildIn());
|
||||
List<string> domains = new List<string>(lines.Count);
|
||||
for (int i = 0; i < lines.Count; i++)
|
||||
@@ -222,7 +120,7 @@ namespace Shadowsocks.Controller
|
||||
continue;
|
||||
else if (line.StartsWith("@"))
|
||||
continue; /*ignore white list*/
|
||||
int pos = line.IndexOfAny(new char[] { '/'});
|
||||
int pos = line.IndexOfAny(new char[] { '/' });
|
||||
if (pos >= 0)
|
||||
line = line.Substring(0, pos);
|
||||
if (line.Length > 0)
|
||||
@@ -238,7 +136,7 @@ namespace Shadowsocks.Controller
|
||||
List<string> new_domains = new List<string>(domains.Length);
|
||||
TldIndex tldIndex = GetTldIndex();
|
||||
|
||||
foreach(string domain in domains)
|
||||
foreach (string domain in domains)
|
||||
{
|
||||
string last_root_domain = null;
|
||||
int pos;
|
||||
@@ -246,7 +144,7 @@ namespace Shadowsocks.Controller
|
||||
last_root_domain = domain.Substring(pos + 1);
|
||||
if (!tldIndex.Contains(last_root_domain))
|
||||
continue;
|
||||
while(pos > 0)
|
||||
while (pos > 0)
|
||||
{
|
||||
pos = domain.LastIndexOf('.', pos - 1);
|
||||
last_root_domain = domain.Substring(pos + 1);
|
||||
@@ -266,7 +164,7 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
List<string> list = new List<string>(src.Length);
|
||||
Dictionary<string, string> dic = new Dictionary<string, string>(src.Length);
|
||||
foreach(string s in src)
|
||||
foreach (string s in src)
|
||||
{
|
||||
if (!dic.ContainsKey(s))
|
||||
{
|
||||
@@ -281,9 +179,9 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
string[] tlds = null;
|
||||
byte[] pacGZ = Resources.tld_txt;
|
||||
byte[] buffer = new byte[1024];
|
||||
byte[] buffer = new byte[1024];
|
||||
int n;
|
||||
using(MemoryStream sb = new MemoryStream())
|
||||
using (MemoryStream sb = new MemoryStream())
|
||||
{
|
||||
using (GZipStream input = new GZipStream(new MemoryStream(pacGZ),
|
||||
CompressionMode.Decompress, false))
|
||||
@@ -332,7 +230,7 @@ namespace Shadowsocks.Controller
|
||||
return buildin;
|
||||
}
|
||||
|
||||
class TldIndex
|
||||
public class TldIndex
|
||||
{
|
||||
List<string> patterns = new List<string>();
|
||||
IDictionary<string, string> dic = new Dictionary<string, string>();
|
||||
@@ -355,7 +253,7 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
if (dic.ContainsKey(tld))
|
||||
return true;
|
||||
foreach(string pattern in patterns)
|
||||
foreach (string pattern in patterns)
|
||||
{
|
||||
if (Regex.IsMatch(tld, pattern))
|
||||
return true;
|
||||
@@ -365,7 +263,7 @@ namespace Shadowsocks.Controller
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Shadowsocks.Model;
|
||||
using Shadowsocks.Properties;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
@@ -21,10 +22,12 @@ namespace Shadowsocks.Controller
|
||||
Socket _listener;
|
||||
FileSystemWatcher watcher;
|
||||
|
||||
GfwListUpdater gfwlistUpdater;
|
||||
|
||||
public event EventHandler PACFileChanged;
|
||||
|
||||
public event EventHandler UpdatePACFromGFWListCompleted;
|
||||
|
||||
public event ErrorEventHandler UpdatePACFromGFWListError;
|
||||
|
||||
public void Start(Configuration configuration)
|
||||
{
|
||||
try
|
||||
@@ -51,7 +54,6 @@ namespace Shadowsocks.Controller
|
||||
_listener);
|
||||
|
||||
WatchPacFile();
|
||||
StartGfwListUpdater();
|
||||
}
|
||||
catch (SocketException)
|
||||
{
|
||||
@@ -62,11 +64,6 @@ namespace Shadowsocks.Controller
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (gfwlistUpdater != null)
|
||||
{
|
||||
gfwlistUpdater.Stop();
|
||||
gfwlistUpdater = null;
|
||||
}
|
||||
if (_listener != null)
|
||||
{
|
||||
_listener.Close();
|
||||
@@ -146,7 +143,7 @@ namespace Shadowsocks.Controller
|
||||
using (GZipStream input = new GZipStream(new MemoryStream(pacGZ),
|
||||
CompressionMode.Decompress, false))
|
||||
{
|
||||
while((n = input.Read(buffer, 0, buffer.Length)) > 0)
|
||||
while ((n = input.Read(buffer, 0, buffer.Length)) > 0)
|
||||
{
|
||||
sb.Write(buffer, 0, n);
|
||||
}
|
||||
@@ -252,72 +249,103 @@ Connection: Close
|
||||
return proxy;
|
||||
}
|
||||
|
||||
private void StartGfwListUpdater()
|
||||
public void UpdatePACFromGFWList()
|
||||
{
|
||||
if (gfwlistUpdater != null)
|
||||
{
|
||||
gfwlistUpdater.Stop();
|
||||
gfwlistUpdater = null;
|
||||
}
|
||||
|
||||
gfwlistUpdater = new GfwListUpdater();
|
||||
gfwlistUpdater.GfwListChanged += gfwlistUpdater_GfwListChanged;
|
||||
IPEndPoint localEndPoint = (IPEndPoint)_listener.LocalEndPoint;
|
||||
gfwlistUpdater.proxy = new WebProxy(localEndPoint.Address.ToString(), 8123);
|
||||
gfwlistUpdater.useSystemProxy = false;
|
||||
/* Delay 30 seconds, wait proxy start up. */
|
||||
gfwlistUpdater.ScheduleUpdateTime(30);
|
||||
gfwlistUpdater.Start();
|
||||
|
||||
GfwListUpdater gfwlist = new GfwListUpdater();
|
||||
gfwlist.DownloadCompleted += gfwlist_DownloadCompleted;
|
||||
gfwlist.Error += gfwlist_Error;
|
||||
gfwlist.proxy = new WebProxy(IPAddress.Loopback.ToString(), 8123); /* use polipo proxy*/
|
||||
gfwlist.Download();
|
||||
}
|
||||
|
||||
private void gfwlistUpdater_GfwListChanged(object sender, GfwListUpdater.GfwListChangedArgs e)
|
||||
private void gfwlist_DownloadCompleted(object sender, GfwListUpdater.GfwListDownloadCompletedArgs e)
|
||||
{
|
||||
if (e.GfwList == null || e.GfwList.Length == 0) return;
|
||||
string pacfile = TouchPACFile();
|
||||
string pacContent = File.ReadAllText(pacfile);
|
||||
string oldDomains;
|
||||
if (ClearPacContent(ref pacContent, out oldDomains))
|
||||
GfwListUpdater.Parser parser = new GfwListUpdater.Parser(e.Content);
|
||||
string[] lines = parser.GetValidLines();
|
||||
StringBuilder rules = new StringBuilder(lines.Length * 16);
|
||||
SerializeRules(lines, rules);
|
||||
string abpContent = GetAbpContent();
|
||||
abpContent = abpContent.Replace("__RULES__", rules.ToString());
|
||||
File.WriteAllText(PAC_FILE, abpContent);
|
||||
if (UpdatePACFromGFWListCompleted != null)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine("{");
|
||||
for (int i = 0; i < e.GfwList.Length; i++)
|
||||
UpdatePACFromGFWListCompleted(this, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
private void gfwlist_Error(object sender, ErrorEventArgs e)
|
||||
{
|
||||
if (UpdatePACFromGFWListError != null)
|
||||
{
|
||||
UpdatePACFromGFWListError(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetAbpContent()
|
||||
{
|
||||
byte[] abpGZ = Resources.abp_js;
|
||||
byte[] buffer = new byte[1024]; // builtin pac gzip size: maximum 100K
|
||||
int n;
|
||||
using (MemoryStream sb = new MemoryStream())
|
||||
{
|
||||
using (GZipStream input = new GZipStream(new MemoryStream(abpGZ),
|
||||
CompressionMode.Decompress, false))
|
||||
{
|
||||
if (i == e.GfwList.Length - 1)
|
||||
sb.AppendFormat("\t\"{0}\": {1}\r\n", e.GfwList[i], 1);
|
||||
else
|
||||
sb.AppendFormat("\t\"{0}\": {1},\r\n", e.GfwList[i], 1);
|
||||
while ((n = input.Read(buffer, 0, buffer.Length)) > 0)
|
||||
{
|
||||
sb.Write(buffer, 0, n);
|
||||
}
|
||||
}
|
||||
sb.Append("}");
|
||||
string newDomains = sb.ToString();
|
||||
if (!string.Equals(oldDomains, newDomains))
|
||||
{
|
||||
pacContent = pacContent.Replace("__LAST_MODIFIED__", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||
pacContent = pacContent.Replace("__DOMAINS__", newDomains);
|
||||
File.WriteAllText(pacfile, pacContent);
|
||||
Console.WriteLine("gfwlist updated - " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Broken pac file.");
|
||||
return System.Text.Encoding.UTF8.GetString(sb.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
private bool ClearPacContent(ref string pacContent, out string oldDomains)
|
||||
private static void SerializeRules(string[] rules, StringBuilder builder)
|
||||
{
|
||||
Regex regex = new Regex("(/\\*.*?\\*/\\s*)?var\\s+domains\\s*=\\s*(\\{(\\s*\"[^\"]*\"\\s*:\\s*\\d+\\s*,)*\\s*(\\s*\"[^\"]*\"\\s*:\\s*\\d+\\s*)\\})", RegexOptions.Singleline);
|
||||
Match m = regex.Match(pacContent);
|
||||
if (m.Success)
|
||||
builder.Append("[\n");
|
||||
|
||||
bool first = true;
|
||||
foreach (string rule in rules)
|
||||
{
|
||||
oldDomains = m.Result("$2");
|
||||
pacContent = regex.Replace(pacContent, "/* Last Modified: __LAST_MODIFIED__ */\r\nvar domains = __DOMAINS__");
|
||||
return true;
|
||||
if (!first)
|
||||
builder.Append(",\n");
|
||||
|
||||
SerializeString(rule, builder);
|
||||
|
||||
first = false;
|
||||
}
|
||||
oldDomains = null;
|
||||
return false;
|
||||
|
||||
builder.Append("\n]");
|
||||
}
|
||||
|
||||
private static void SerializeString(string aString, StringBuilder builder)
|
||||
{
|
||||
builder.Append("\t\"");
|
||||
|
||||
char[] charArray = aString.ToCharArray();
|
||||
for (int i = 0; i < charArray.Length; i++)
|
||||
{
|
||||
char c = charArray[i];
|
||||
if (c == '"')
|
||||
builder.Append("\\\"");
|
||||
else if (c == '\\')
|
||||
builder.Append("\\\\");
|
||||
else if (c == '\b')
|
||||
builder.Append("\\b");
|
||||
else if (c == '\f')
|
||||
builder.Append("\\f");
|
||||
else if (c == '\n')
|
||||
builder.Append("\\n");
|
||||
else if (c == '\r')
|
||||
builder.Append("\\r");
|
||||
else if (c == '\t')
|
||||
builder.Append("\\t");
|
||||
else
|
||||
builder.Append(c);
|
||||
}
|
||||
|
||||
builder.Append("\"");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,10 @@ namespace Shadowsocks.Controller
|
||||
// when user clicked Edit PAC, and PAC file has already created
|
||||
public event EventHandler<PathEventArgs> PACFileReadyToOpen;
|
||||
|
||||
public event EventHandler UpdatePACFromGFWListCompleted;
|
||||
|
||||
public event ErrorEventHandler UpdatePACFromGFWListError;
|
||||
|
||||
public event ErrorEventHandler Errored;
|
||||
|
||||
public ShadowsocksController()
|
||||
@@ -156,6 +160,14 @@ namespace Shadowsocks.Controller
|
||||
return "ss://" + base64;
|
||||
}
|
||||
|
||||
public void UpdatePACFromGFWList()
|
||||
{
|
||||
if (pacServer != null)
|
||||
{
|
||||
pacServer.UpdatePACFromGFWList();
|
||||
}
|
||||
}
|
||||
|
||||
protected void Reload()
|
||||
{
|
||||
// some logic in configuration updated the config when saving, we need to read it again
|
||||
@@ -169,6 +181,8 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
pacServer = new PACServer();
|
||||
pacServer.PACFileChanged += pacServer_PACFileChanged;
|
||||
pacServer.UpdatePACFromGFWListCompleted += pacServer_UpdatePACFromGFWListCompleted;
|
||||
pacServer.UpdatePACFromGFWListError += pacServer_UpdatePACFromGFWListError;
|
||||
}
|
||||
|
||||
pacServer.Stop();
|
||||
@@ -247,6 +261,18 @@ namespace Shadowsocks.Controller
|
||||
UpdateSystemProxy();
|
||||
}
|
||||
|
||||
private void pacServer_UpdatePACFromGFWListCompleted(object sender, EventArgs e)
|
||||
{
|
||||
if (UpdatePACFromGFWListCompleted != null)
|
||||
UpdatePACFromGFWListCompleted(this, e);
|
||||
}
|
||||
|
||||
private void pacServer_UpdatePACFromGFWListError(object sender, ErrorEventArgs e)
|
||||
{
|
||||
if (UpdatePACFromGFWListError != null)
|
||||
UpdatePACFromGFWListError(this, e);
|
||||
}
|
||||
|
||||
private void StartReleasingMemory()
|
||||
{
|
||||
_ramThread = new Thread(new ThreadStart(ReleaseMemory));
|
||||
|
||||
Binary file not shown.
@@ -39,3 +39,6 @@ Shadowsocks is here=Shadowsocks 在这里
|
||||
You can turn on/off Shadowsocks in the context menu=可以在右键菜单中开关 Shadowsocks
|
||||
Enabled=已启用代理
|
||||
Disabled=已禁用代理
|
||||
Update PAC File via gfwlist...=基于 gfwlist 更新 PAC 文件...
|
||||
Update PAC file failed=更新 PAC 文件失败
|
||||
Update PAC file succeed=更新 PAC 文件成功
|
||||
|
||||
+35
-25
@@ -1,10 +1,10 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// 此代码由工具生成。
|
||||
// 运行时版本:4.0.30319.34014
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.18444
|
||||
//
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果
|
||||
// 重新生成代码,这些更改将会丢失。
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -13,12 +13,12 @@ namespace Shadowsocks.Properties {
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 一个强类型的资源类,用于查找本地化的字符串等。
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// 此类是由 StronglyTypedResourceBuilder
|
||||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
||||
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
||||
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
@@ -33,7 +33,7 @@ namespace Shadowsocks.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回此类使用的缓存的 ResourceManager 实例。
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
@@ -47,8 +47,8 @@ namespace Shadowsocks.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用此强类型资源类,为所有资源查找
|
||||
/// 重写当前线程的 CurrentUICulture 属性。
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
@@ -61,7 +61,17 @@ namespace Shadowsocks.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Byte[] 类型的本地化资源。
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] abp_js {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("abp_js", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] builtin_txt {
|
||||
get {
|
||||
@@ -71,7 +81,7 @@ namespace Shadowsocks.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Shadowsocks=Shadowsocks
|
||||
/// Looks up a localized string similar to Shadowsocks=Shadowsocks
|
||||
///Enable=启用代理
|
||||
///Mode=代理模式
|
||||
///PAC=PAC 模式
|
||||
@@ -101,7 +111,7 @@ namespace Shadowsocks.Properties {
|
||||
///QRCode=二维码
|
||||
///Shadowsocks Error: {0}=Shadowsocks 错误: {0}
|
||||
///Port already in use=端口已被占用
|
||||
///Il [字符串的其余部分被截断]"; 的本地化字符串。
|
||||
///Il [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string cn {
|
||||
get {
|
||||
@@ -110,7 +120,7 @@ namespace Shadowsocks.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Byte[] 类型的本地化资源。
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] libsscrypto_dll {
|
||||
get {
|
||||
@@ -120,7 +130,7 @@ namespace Shadowsocks.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 proxyAddress = "__POLIPO_BIND_IP__"
|
||||
/// Looks up a localized string similar to proxyAddress = "__POLIPO_BIND_IP__"
|
||||
///
|
||||
///socksParentProxy = "127.0.0.1:__SOCKS_PORT__"
|
||||
///socksProxyType = socks5
|
||||
@@ -128,7 +138,7 @@ namespace Shadowsocks.Properties {
|
||||
///localDocumentRoot = ""
|
||||
///
|
||||
///allowedPorts = 1-65535
|
||||
///tunnelAllowedPorts = 1-65535 的本地化字符串。
|
||||
///tunnelAllowedPorts = 1-65535.
|
||||
/// </summary>
|
||||
internal static string polipo_config {
|
||||
get {
|
||||
@@ -137,7 +147,7 @@ namespace Shadowsocks.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Byte[] 类型的本地化资源。
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] polipo_exe {
|
||||
get {
|
||||
@@ -147,7 +157,7 @@ namespace Shadowsocks.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Byte[] 类型的本地化资源。
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] proxy_pac_txt {
|
||||
get {
|
||||
@@ -157,7 +167,7 @@ namespace Shadowsocks.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap ss16 {
|
||||
get {
|
||||
@@ -167,7 +177,7 @@ namespace Shadowsocks.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap ss20 {
|
||||
get {
|
||||
@@ -177,7 +187,7 @@ namespace Shadowsocks.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap ss24 {
|
||||
get {
|
||||
@@ -187,7 +197,7 @@ namespace Shadowsocks.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap ssw128 {
|
||||
get {
|
||||
@@ -197,7 +207,7 @@ namespace Shadowsocks.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Byte[] 类型的本地化资源。
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] tld_txt {
|
||||
get {
|
||||
|
||||
@@ -118,6 +118,9 @@
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="abp_js" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Data\abp.js.gz;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="builtin_txt" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Data\builtin.txt.gz;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
|
||||
@@ -45,6 +45,8 @@ namespace Shadowsocks.View
|
||||
controller.ShareOverLANStatusChanged += controller_ShareOverLANStatusChanged;
|
||||
controller.EnableGlobalChanged += controller_EnableGlobalChanged;
|
||||
controller.Errored += controller_Errored;
|
||||
controller.UpdatePACFromGFWListCompleted += controller_UpdatePACFromGFWListCompleted;
|
||||
controller.UpdatePACFromGFWListError += controller_UpdatePACFromGFWListError;
|
||||
|
||||
_notifyIcon = new NotifyIcon();
|
||||
UpdateTrayIcon();
|
||||
@@ -138,6 +140,7 @@ namespace Shadowsocks.View
|
||||
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 File via gfwlist...", new EventHandler(this.UpdatePACFromGFWListItem_Click)),
|
||||
new MenuItem("-"),
|
||||
CreateMenuItem("Show QRCode...", new EventHandler(this.QRCodeItem_Click)),
|
||||
CreateMenuItem("Show Logs...", new EventHandler(this.ShowLogItem_Click)),
|
||||
@@ -176,6 +179,23 @@ namespace Shadowsocks.View
|
||||
System.Diagnostics.Process.Start("explorer.exe", argument);
|
||||
}
|
||||
|
||||
void controller_UpdatePACFromGFWListError(object sender, System.IO.ErrorEventArgs e)
|
||||
{
|
||||
_notifyIcon.BalloonTipTitle = I18N.GetString("Update PAC File via gfwlist...");
|
||||
_notifyIcon.BalloonTipText = I18N.GetString("Update PAC file failed");
|
||||
_notifyIcon.BalloonTipIcon = ToolTipIcon.Info;
|
||||
_notifyIcon.ShowBalloonTip(5000);
|
||||
Logging.LogUsefulException(e.GetException());
|
||||
}
|
||||
|
||||
void controller_UpdatePACFromGFWListCompleted(object sender, EventArgs e)
|
||||
{
|
||||
_notifyIcon.BalloonTipTitle = I18N.GetString("Update PAC File via gfwlist...");
|
||||
_notifyIcon.BalloonTipText = I18N.GetString("Update PAC file succeed");
|
||||
_notifyIcon.BalloonTipIcon = ToolTipIcon.Info;
|
||||
_notifyIcon.ShowBalloonTip(5000);
|
||||
}
|
||||
|
||||
void updateChecker_NewVersionFound(object sender, EventArgs e)
|
||||
{
|
||||
_notifyIcon.BalloonTipTitle = String.Format(I18N.GetString("Shadowsocks {0} Update Found"), updateChecker.LatestVersionNumber);
|
||||
@@ -311,6 +331,15 @@ namespace Shadowsocks.View
|
||||
controller.TouchPACFile();
|
||||
}
|
||||
|
||||
private void UpdatePACFromGFWListItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
_notifyIcon.BalloonTipTitle = I18N.GetString("Shadowsocks") + " " + UpdateChecker.Version;
|
||||
_notifyIcon.BalloonTipText = I18N.GetString("Update PAC File via gfwlist...");
|
||||
_notifyIcon.BalloonTipIcon = ToolTipIcon.Info;
|
||||
_notifyIcon.ShowBalloonTip(5000);
|
||||
controller.UpdatePACFromGFWList();
|
||||
}
|
||||
|
||||
private void AServerItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
MenuItem item = (MenuItem)sender;
|
||||
|
||||
@@ -143,6 +143,7 @@
|
||||
<None Include="app.manifest">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
<None Include="Data\abp.js.gz" />
|
||||
<None Include="Data\builtin.txt.gz" />
|
||||
<None Include="Data\libsscrypto.dll.gz" />
|
||||
<None Include="Data\polipo.exe.gz" />
|
||||
|
||||
Reference in New Issue
Block a user