From f1c821a9cdbe800dab0514c409a1d2808c990ffe Mon Sep 17 00:00:00 2001 From: Gang Zhuo Date: Wed, 7 Jan 2015 23:08:25 +0800 Subject: [PATCH 01/15] call controller.Stop() when application exit --- shadowsocks-csharp/Program.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shadowsocks-csharp/Program.cs b/shadowsocks-csharp/Program.cs index 716e0df7..c3c0537a 100755 --- a/shadowsocks-csharp/Program.cs +++ b/shadowsocks-csharp/Program.cs @@ -45,6 +45,8 @@ namespace Shadowsocks controller.Start(); Application.Run(); + + controller.Stop(); } } } From a984e907272ad3834f415430c79c7ecc9458690c Mon Sep 17 00:00:00 2001 From: Gang Zhuo Date: Wed, 7 Jan 2015 23:10:12 +0800 Subject: [PATCH 02/15] Stop the PACServer when controller stop --- shadowsocks-csharp/Controller/ShadowsocksController.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index 080390be..3d9d5119 100755 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -128,6 +128,11 @@ namespace Shadowsocks.Controller { polipoRunner.Stop(); } + if (pacServer != null) + { + pacServer.Stop(); + pacServer = null; + } if (_config.enabled) { SystemProxy.Disable(); From a2f3116ca805828e89258f22a67c478536c4965d Mon Sep 17 00:00:00 2001 From: Gang Zhuo Date: Thu, 8 Jan 2015 00:54:12 +0800 Subject: [PATCH 03/15] auto update gfwlist, see https://github.com/shadowsocks/shadowsocks-csharp/issues/115 --- .../Controller/GfwListUpdater.cs | 283 ++++++++++++++++++ shadowsocks-csharp/Controller/PACServer.cs | 77 +++++ shadowsocks-csharp/Data/tld.txt.gz | Bin 0 -> 26402 bytes .../Properties/Resources.Designer.cs | 58 ++-- shadowsocks-csharp/Properties/Resources.resx | 3 + shadowsocks-csharp/shadowsocks-csharp.csproj | 2 + 6 files changed, 399 insertions(+), 24 deletions(-) create mode 100644 shadowsocks-csharp/Controller/GfwListUpdater.cs create mode 100644 shadowsocks-csharp/Data/tld.txt.gz diff --git a/shadowsocks-csharp/Controller/GfwListUpdater.cs b/shadowsocks-csharp/Controller/GfwListUpdater.cs new file mode 100644 index 00000000..294422d4 --- /dev/null +++ b/shadowsocks-csharp/Controller/GfwListUpdater.cs @@ -0,0 +1,283 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Net; +using System.IO; +using System.IO.Compression; +using System.Security.Cryptography; +using Shadowsocks.Model; +using Shadowsocks.Properties; + +namespace Shadowsocks.Controller +{ + public class GfwListUpdater + { + 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 string[] GfwList { get; set; } + } + + public event EventHandler GfwListChanged; + + private bool running = false; + private bool closed = false; + private int jobId = 0; + DateTime lastUpdateTimeUtc; + string lastUpdateMd5; + + private object locker = new object(); + + public GfwListUpdater() + { + } + + ~GfwListUpdater() + { + Stop(); + } + + public void Start() + { + lock (locker) + { + if (running) + return; + running = true; + closed = false; + jobId++; + new Thread(new ParameterizedThreadStart(UpdateJob)).Start(jobId); + } + } + + 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() + { + try + { + WebClient http = new WebClient(); + http.Proxy = useSystemProxy ? WebRequest.GetSystemWebProxy() : proxy; + return http.DownloadString(new Uri(GFWLIST_URL)); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + return null; + } + + private bool IsExpire() + { + lock (locker) + { + TimeSpan ts = DateTime.UtcNow - lastUpdateTimeUtc; + bool expire = ((int)ts.TotalHours) >= EXPIRE_HOURS; + if (expire) + lastUpdateTimeUtc = DateTime.UtcNow; + return expire; + } + } + + 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) + { + Parser parser = new Parser(response); + GfwListChangedArgs args = new GfwListChangedArgs { + GfwList = parser.GetReducedDomains() + }; + GfwListChanged(this, args); + } + } + + 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); + } + + public string[] GetLines() + { + return Content.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + } + + /* refer https://github.com/clowwindy/gfwlist2pac/blob/master/gfwlist2pac/main.py */ + public string[] GetDomains() + { + string[] lines = GetLines(); + List domains = new List(lines.Length); + for(int i =0;i < lines.Length;i++) + { + string line = lines[i]; + if (line.IndexOf(".*") >= 0) + continue; + else if (line.IndexOf("*") >= 0) + line = line.Replace("*", "/"); + if (line.StartsWith("||")) + line = line.Substring(2); + else if (line.StartsWith("|")) + line = line.Substring(1); + else if (line.StartsWith(".")) + line = line.Substring(1); + if (line.StartsWith("!")) + continue; + else if (line.StartsWith("[")) + continue; + else if (line.StartsWith("@")) + continue; /*ignore white list*/ + domains.Add(line); + } + return domains.ToArray(); + } + + /* refer https://github.com/clowwindy/gfwlist2pac/blob/master/gfwlist2pac/main.py */ + public string[] GetReducedDomains() + { + string[] domains = GetDomains(); + List new_domains = new List(domains.Length); + IDictionary tld_dic = GetTldDictionary(); + + foreach(string domain in domains) + { + string last_root_domain = null; + int pos; + pos = domain.LastIndexOf('.'); + last_root_domain = domain.Substring(pos + 1); + if (!tld_dic.ContainsKey(last_root_domain)) + continue; + while(pos > 0) + { + pos = domain.LastIndexOf('.', pos - 1); + last_root_domain = domain.Substring(pos + 1); + if (tld_dic.ContainsKey(last_root_domain)) + continue; + else + break; + } + if (last_root_domain != null) + new_domains.Add(last_root_domain); + } + + return new_domains.ToArray(); + } + + private string[] GetTlds() + { + string[] tlds = null; + byte[] pacGZ = Resources.tld_txt; + byte[] buffer = new byte[1024]; + int n; + using(MemoryStream sb = new MemoryStream()) + { + using (GZipStream input = new GZipStream(new MemoryStream(pacGZ), + CompressionMode.Decompress, false)) + { + while ((n = input.Read(buffer, 0, buffer.Length)) > 0) + { + sb.Write(buffer, 0, n); + } + } + tlds = System.Text.Encoding.UTF8.GetString(sb.ToArray()) + .Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + } + return tlds; + } + + private IDictionary GetTldDictionary() + { + string[] tlds = GetTlds(); + IDictionary dic = new Dictionary(tlds.Length); + foreach (string tld in tlds) + { + if (!dic.ContainsKey(tld)) + dic.Add(tld, tld); + } + return dic; + } + + } + + } +} diff --git a/shadowsocks-csharp/Controller/PACServer.cs b/shadowsocks-csharp/Controller/PACServer.cs index f02476ae..17351b19 100755 --- a/shadowsocks-csharp/Controller/PACServer.cs +++ b/shadowsocks-csharp/Controller/PACServer.cs @@ -8,6 +8,7 @@ using System.IO.Compression; using System.Net; using System.Net.Sockets; using System.Text; +using System.Text.RegularExpressions; namespace Shadowsocks.Controller { @@ -20,6 +21,8 @@ namespace Shadowsocks.Controller Socket _listener; FileSystemWatcher watcher; + GfwListUpdater gfwlistUpdater; + public event EventHandler PACFileChanged; public void Start(Configuration configuration) @@ -48,6 +51,7 @@ namespace Shadowsocks.Controller _listener); WatchPacFile(); + StartGfwListUpdater(); } catch (SocketException) { @@ -58,6 +62,11 @@ namespace Shadowsocks.Controller public void Stop() { + if (gfwlistUpdater != null) + { + gfwlistUpdater.Stop(); + gfwlistUpdater = null; + } if (_listener != null) { _listener.Close(); @@ -242,5 +251,73 @@ Connection: Close //} return proxy; } + + private void StartGfwListUpdater() + { + 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(); + + } + + private void gfwlistUpdater_GfwListChanged(object sender, GfwListUpdater.GfwListChangedArgs 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)) + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine("{"); + for (int i = 0; i < e.GfwList.Length; i++) + { + 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); + } + 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."); + } + } + + private bool ClearPacContent(ref string pacContent, out string oldDomains) + { + 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) + { + oldDomains = m.Result("$2"); + pacContent = regex.Replace(pacContent, "/* Last Modified: __LAST_MODIFIED__ */\r\nvar domains = __DOMAINS__"); + return true; + } + oldDomains = null; + return false; + } + + } } diff --git a/shadowsocks-csharp/Data/tld.txt.gz b/shadowsocks-csharp/Data/tld.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..a502a241c14500b08eb05346fcaa8625cdfdd405 GIT binary patch literal 26402 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ν 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 z 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 BaYX -// This code was generated by a tool. -// Runtime Version:4.0.30319.18444 +// 此代码由工具生成。 +// 运行时版本:4.0.30319.34014 // -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 // //------------------------------------------------------------------------------ @@ -13,12 +13,12 @@ namespace Shadowsocks.Properties { /// - /// A strongly-typed resource class, for looking up localized strings, etc. + /// 一个强类型的资源类,用于查找本地化的字符串等。 /// - // 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. + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 [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 { } /// - /// Returns the cached ResourceManager instance used by this class. + /// 返回此类使用的缓存的 ResourceManager 实例。 /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { @@ -47,8 +47,8 @@ namespace Shadowsocks.Properties { } /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. + /// 使用此强类型资源类,为所有资源查找 + /// 重写当前线程的 CurrentUICulture 属性。 /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { @@ -61,14 +61,14 @@ namespace Shadowsocks.Properties { } /// - /// Looks up a localized string similar to Shadowsocks=Shadowsocks + /// 查找类似 Shadowsocks=Shadowsocks ///Enable=启用代理 ///Mode=代理模式 ///PAC=PAC 模式 ///Global=全局模式 ///Servers=服务器选择 ///Edit Servers...=编辑服务器... - ///Start on Boot=自动启动 + ///Start on Boot=开机启动 ///Share over LAN=在局域网共享代理 ///Edit PAC File...=编辑 PAC 文件... ///Show QRCode...=显示二维码... @@ -91,7 +91,7 @@ namespace Shadowsocks.Properties { ///QRCode=二维码 ///Shadowsocks Error: {0}=Shadowsocks 错误: {0} ///Port already in use=端口已被占用 - ///Il [rest of string was truncated]";. + ///Il [字符串的其余部分被截断]"; 的本地化字符串。 /// internal static string cn { get { @@ -100,7 +100,7 @@ namespace Shadowsocks.Properties { } /// - /// Looks up a localized resource of type System.Byte[]. + /// 查找 System.Byte[] 类型的本地化资源。 /// internal static byte[] libsscrypto_dll { get { @@ -110,7 +110,7 @@ namespace Shadowsocks.Properties { } /// - /// Looks up a localized string similar to proxyAddress = "__POLIPO_BIND_IP__" + /// 查找类似 proxyAddress = "__POLIPO_BIND_IP__" /// ///socksParentProxy = "127.0.0.1:__SOCKS_PORT__" ///socksProxyType = socks5 @@ -118,7 +118,7 @@ namespace Shadowsocks.Properties { ///localDocumentRoot = "" /// ///allowedPorts = 1-65535 - ///tunnelAllowedPorts = 1-65535. + ///tunnelAllowedPorts = 1-65535 的本地化字符串。 /// internal static string polipo_config { get { @@ -127,7 +127,7 @@ namespace Shadowsocks.Properties { } /// - /// Looks up a localized resource of type System.Byte[]. + /// 查找 System.Byte[] 类型的本地化资源。 /// internal static byte[] polipo_exe { get { @@ -137,7 +137,7 @@ namespace Shadowsocks.Properties { } /// - /// Looks up a localized resource of type System.Byte[]. + /// 查找 System.Byte[] 类型的本地化资源。 /// internal static byte[] proxy_pac_txt { get { @@ -147,7 +147,7 @@ namespace Shadowsocks.Properties { } /// - /// Looks up a localized resource of type System.Drawing.Bitmap. + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 /// internal static System.Drawing.Bitmap ss16 { get { @@ -157,7 +157,7 @@ namespace Shadowsocks.Properties { } /// - /// Looks up a localized resource of type System.Drawing.Bitmap. + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 /// internal static System.Drawing.Bitmap ss20 { get { @@ -167,7 +167,7 @@ namespace Shadowsocks.Properties { } /// - /// Looks up a localized resource of type System.Drawing.Bitmap. + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 /// internal static System.Drawing.Bitmap ss24 { get { @@ -177,7 +177,7 @@ namespace Shadowsocks.Properties { } /// - /// Looks up a localized resource of type System.Drawing.Bitmap. + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 /// internal static System.Drawing.Bitmap ssw128 { get { @@ -185,5 +185,15 @@ namespace Shadowsocks.Properties { return ((System.Drawing.Bitmap)(obj)); } } + + /// + /// 查找 System.Byte[] 类型的本地化资源。 + /// + internal static byte[] tld_txt { + get { + object obj = ResourceManager.GetObject("tld_txt", resourceCulture); + return ((byte[])(obj)); + } + } } } diff --git a/shadowsocks-csharp/Properties/Resources.resx b/shadowsocks-csharp/Properties/Resources.resx index d8fb470d..b5e75b3f 100755 --- a/shadowsocks-csharp/Properties/Resources.resx +++ b/shadowsocks-csharp/Properties/Resources.resx @@ -145,4 +145,7 @@ ..\Resources\ssw128.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Data\tld.txt.gz;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + \ No newline at end of file diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index e044d4fb..b192d0fd 100755 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -86,6 +86,7 @@ + @@ -147,6 +148,7 @@ + From b7a8360449e99f7921505066aeb83d02ff75bad2 Mon Sep 17 00:00:00 2001 From: Gang Zhuo Date: Thu, 8 Jan 2015 01:40:08 +0800 Subject: [PATCH 04/15] Log more error information --- .../Controller/GfwListUpdater.cs | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/shadowsocks-csharp/Controller/GfwListUpdater.cs b/shadowsocks-csharp/Controller/GfwListUpdater.cs index 294422d4..ef200930 100644 --- a/shadowsocks-csharp/Controller/GfwListUpdater.cs +++ b/shadowsocks-csharp/Controller/GfwListUpdater.cs @@ -86,7 +86,7 @@ namespace Shadowsocks.Controller } catch (Exception ex) { - Console.WriteLine(ex.Message); + Console.WriteLine(ex.ToString()); } return null; } @@ -132,11 +132,19 @@ namespace Shadowsocks.Controller return; if (GfwListChanged != null) { - Parser parser = new Parser(response); - GfwListChangedArgs args = new GfwListChangedArgs { - GfwList = parser.GetReducedDomains() - }; - GfwListChanged(this, args); + try + { + Parser parser = new Parser(response); + GfwListChangedArgs args = new GfwListChangedArgs + { + GfwList = parser.GetReducedDomains() + }; + GfwListChanged(this, args); + } + catch(Exception ex) + { + Console.WriteLine(ex.ToString()); + } } } From 78c58b3a232044f2abe9be4045e088a1aa967436 Mon Sep 17 00:00:00 2001 From: Gang Zhuo Date: Thu, 8 Jan 2015 03:06:15 +0800 Subject: [PATCH 05/15] add co.hk --- shadowsocks-csharp/Data/tld.txt.gz | Bin 26402 -> 26403 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/shadowsocks-csharp/Data/tld.txt.gz b/shadowsocks-csharp/Data/tld.txt.gz index a502a241c14500b08eb05346fcaa8625cdfdd405..693a6e8c69c34c409ddc37c5807f229fb445394b 100644 GIT binary patch literal 26403 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

O#HUfBW_yeE#i! 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ν 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 z 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 BaYX Date: Thu, 8 Jan 2015 03:07:26 +0800 Subject: [PATCH 06/15] support build in gfwlist --- .../Controller/GfwListUpdater.cs | 77 +++++++++++++++--- shadowsocks-csharp/Data/builtin.txt.gz | Bin 0 -> 104 bytes .../Properties/Resources.Designer.cs | 10 +++ shadowsocks-csharp/Properties/Resources.resx | 3 + shadowsocks-csharp/shadowsocks-csharp.csproj | 1 + 5 files changed, 81 insertions(+), 10 deletions(-) create mode 100644 shadowsocks-csharp/Data/builtin.txt.gz diff --git a/shadowsocks-csharp/Controller/GfwListUpdater.cs b/shadowsocks-csharp/Controller/GfwListUpdater.cs index ef200930..97f0cb2e 100644 --- a/shadowsocks-csharp/Controller/GfwListUpdater.cs +++ b/shadowsocks-csharp/Controller/GfwListUpdater.cs @@ -6,6 +6,7 @@ using System.Net; using System.IO; using System.IO.Compression; using System.Security.Cryptography; +using System.Text.RegularExpressions; using Shadowsocks.Model; using Shadowsocks.Properties; @@ -194,9 +195,10 @@ namespace Shadowsocks.Controller /* refer https://github.com/clowwindy/gfwlist2pac/blob/master/gfwlist2pac/main.py */ public string[] GetDomains() { - string[] lines = GetLines(); - List domains = new List(lines.Length); - for(int i =0;i < lines.Length;i++) + List lines = new List(GetLines()); + lines.AddRange(GetBuildIn()); + List domains = new List(lines.Count); + for (int i = 0; i < lines.Count; i++) { string line = lines[i]; if (line.IndexOf(".*") >= 0) @@ -225,7 +227,7 @@ namespace Shadowsocks.Controller { string[] domains = GetDomains(); List new_domains = new List(domains.Length); - IDictionary tld_dic = GetTldDictionary(); + TldIndex tldIndex = GetTldIndex(); foreach(string domain in domains) { @@ -233,13 +235,13 @@ namespace Shadowsocks.Controller int pos; pos = domain.LastIndexOf('.'); last_root_domain = domain.Substring(pos + 1); - if (!tld_dic.ContainsKey(last_root_domain)) + if (!tldIndex.Contains(last_root_domain)) continue; while(pos > 0) { pos = domain.LastIndexOf('.', pos - 1); last_root_domain = domain.Substring(pos + 1); - if (tld_dic.ContainsKey(last_root_domain)) + if (tldIndex.Contains(last_root_domain)) continue; else break; @@ -273,18 +275,73 @@ namespace Shadowsocks.Controller return tlds; } - private IDictionary GetTldDictionary() + private TldIndex GetTldIndex() { string[] tlds = GetTlds(); - IDictionary dic = new Dictionary(tlds.Length); + TldIndex index = new TldIndex(); foreach (string tld in tlds) { - if (!dic.ContainsKey(tld)) + index.Add(tld); + } + return index; + } + + private string[] GetBuildIn() + { + string[] buildin = null; + byte[] builtinGZ = Resources.builtin_txt; + byte[] buffer = new byte[1024]; + int n; + using (MemoryStream sb = new MemoryStream()) + { + using (GZipStream input = new GZipStream(new MemoryStream(builtinGZ), + CompressionMode.Decompress, false)) + { + while ((n = input.Read(buffer, 0, buffer.Length)) > 0) + { + sb.Write(buffer, 0, n); + } + } + buildin = System.Text.Encoding.UTF8.GetString(sb.ToArray()) + .Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + } + return buildin; + } + + class TldIndex + { + List patterns = new List(); + IDictionary dic = new Dictionary(); + + public void Add(string tld) + { + if (string.IsNullOrEmpty(tld)) + return; + if (tld.IndexOfAny(new char[] { '*', '?' }) >= 0) + { + patterns.Add("^" + Regex.Escape(tld).Replace("\\*", ".*").Replace("\\?", ".") + "$"); + } + else if (!dic.ContainsKey(tld)) + { dic.Add(tld, tld); + } } - return dic; + + public bool Contains(string tld) + { + if (dic.ContainsKey(tld)) + return true; + foreach(string pattern in patterns) + { + if (Regex.IsMatch(tld, pattern)) + return true; + } + return false; + } + } + } } diff --git a/shadowsocks-csharp/Data/builtin.txt.gz b/shadowsocks-csharp/Data/builtin.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..c846e6448a7ec005ee03576b0d40e751c51f85f7 GIT binary patch literal 104 zcmV-u0GIzCiwFp_d973c17dY)Y; + /// 查找 System.Byte[] 类型的本地化资源。 + /// + internal static byte[] builtin_txt { + get { + object obj = ResourceManager.GetObject("builtin_txt", resourceCulture); + return ((byte[])(obj)); + } + } + ///

/// 查找类似 Shadowsocks=Shadowsocks ///Enable=启用代理 diff --git a/shadowsocks-csharp/Properties/Resources.resx b/shadowsocks-csharp/Properties/Resources.resx index b5e75b3f..2b53c8e1 100755 --- a/shadowsocks-csharp/Properties/Resources.resx +++ b/shadowsocks-csharp/Properties/Resources.resx @@ -118,6 +118,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Data\builtin.txt.gz;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + ..\data\cn.txt;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index b192d0fd..6ed7cf4f 100755 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -143,6 +143,7 @@ Designer + From dd0051658766c6c0206b1562701ee72803d4d8fb Mon Sep 17 00:00:00 2001 From: Gang Zhuo Date: Thu, 8 Jan 2015 03:30:55 +0800 Subject: [PATCH 07/15] refine, remove duplicate domains --- .../Controller/GfwListUpdater.cs | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/shadowsocks-csharp/Controller/GfwListUpdater.cs b/shadowsocks-csharp/Controller/GfwListUpdater.cs index 97f0cb2e..ef4fe4eb 100644 --- a/shadowsocks-csharp/Controller/GfwListUpdater.cs +++ b/shadowsocks-csharp/Controller/GfwListUpdater.cs @@ -203,23 +203,32 @@ namespace Shadowsocks.Controller string line = lines[i]; if (line.IndexOf(".*") >= 0) continue; - else if (line.IndexOf("*") >= 0) + if (line.StartsWith("http://")) + line = line.Substring(7); + else if (line.StartsWith("https://")) + line = line.Substring(8); + if (line.IndexOf("*") >= 0) line = line.Replace("*", "/"); if (line.StartsWith("||")) - line = line.Substring(2); + while (line.StartsWith("||")) + line = line.Substring(2); else if (line.StartsWith("|")) - line = line.Substring(1); + line = line.TrimStart('|'); else if (line.StartsWith(".")) - line = line.Substring(1); + line = line.TrimStart('.'); if (line.StartsWith("!")) continue; else if (line.StartsWith("[")) continue; else if (line.StartsWith("@")) continue; /*ignore white list*/ - domains.Add(line); + int pos = line.IndexOfAny(new char[] { '/'}); + if (pos >= 0) + line = line.Substring(0, pos); + if (line.Length > 0) + domains.Add(line); } - return domains.ToArray(); + return RemoveDuplicate(domains.ToArray()); } /* refer https://github.com/clowwindy/gfwlist2pac/blob/master/gfwlist2pac/main.py */ @@ -250,7 +259,22 @@ namespace Shadowsocks.Controller new_domains.Add(last_root_domain); } - return new_domains.ToArray(); + return RemoveDuplicate(new_domains.ToArray()); + } + + private string[] RemoveDuplicate(string[] src) + { + List list = new List(src.Length); + Dictionary dic = new Dictionary(src.Length); + foreach(string s in src) + { + if (!dic.ContainsKey(s)) + { + dic.Add(s, s); + list.Add(s); + } + } + return list.ToArray(); } private string[] GetTlds() From c24c1d44b702285f487ef82aea2f045dc7ff1951 Mon Sep 17 00:00:00 2001 From: Gang Zhuo Date: Wed, 7 Jan 2015 23:41:45 -0500 Subject: [PATCH 08/15] add new menu to update pac file via gfwlist --- .../Controller/GfwListUpdater.cs | 196 +++++------------- shadowsocks-csharp/Controller/PACServer.cs | 140 ++++++++----- .../Controller/ShadowsocksController.cs | 26 +++ shadowsocks-csharp/Data/abp.js.gz | Bin 0 -> 4594 bytes shadowsocks-csharp/Data/cn.txt | 3 + .../Properties/Resources.Designer.cs | 60 +++--- shadowsocks-csharp/Properties/Resources.resx | 3 + shadowsocks-csharp/View/MenuViewController.cs | 29 +++ shadowsocks-csharp/shadowsocks-csharp.csproj | 1 + 9 files changed, 228 insertions(+), 230 deletions(-) create mode 100644 shadowsocks-csharp/Data/abp.js.gz diff --git a/shadowsocks-csharp/Controller/GfwListUpdater.cs b/shadowsocks-csharp/Controller/GfwListUpdater.cs index ef4fe4eb..c377efd2 100644 --- a/shadowsocks-csharp/Controller/GfwListUpdater.cs +++ b/shadowsocks-csharp/Controller/GfwListUpdater.cs @@ -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 GfwListChanged; - - private bool running = false; - private bool closed = false; - private int jobId = 0; - DateTime lastUpdateTimeUtc; - string lastUpdateMd5; - - private object locker = new object(); + public event EventHandler DownloadCompleted; - public GfwListUpdater() - { - } + public event ErrorEventHandler Error; - ~GfwListUpdater() + public void Download() { - Stop(); + WebClient http = new WebClient(); + http.Proxy = proxy; + http.DownloadStringCompleted += http_DownloadStringCompleted; + http.DownloadStringAsync(new Uri(GFWLIST_URL)); } - public void Start() + protected void ReportError(Exception e) { - 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) - { - TimeSpan ts = DateTime.UtcNow - lastUpdateTimeUtc; - bool expire = ((int)ts.TotalHours) >= EXPIRE_HOURS; - if (expire) - lastUpdateTimeUtc = DateTime.UtcNow; - return expire; - } - } + private string _Content; - private bool IsJobStop(int currentJobId) - { - lock (locker) + public string Content { - if (!running || closed || currentJobId != this.jobId) - return true; + get { return _Content; } } - 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) + public Parser(string response) { - try - { - Parser parser = new Parser(response); - GfwListChangedArgs args = new GfwListChangedArgs - { - GfwList = parser.GetReducedDomains() - }; - GfwListChanged(this, args); - } - catch(Exception ex) - { - Console.WriteLine(ex.ToString()); - } + byte[] bytes = Convert.FromBase64String(response); + this._Content = Encoding.ASCII.GetString(bytes); } - } - private void UpdateJob(object state) - { - int currentJobId = (int)state; - int retryTimes = 3; - while (!IsJobStop(currentJobId)) + public string[] GetValidLines() { - if (IsExpire()) + string[] lines = Content.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + List valid_lines = new List(lines.Length); + foreach (string line in lines) { - 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. */ - } + if (line.StartsWith("!") || line.StartsWith("[")) + continue; + valid_lines.Add(line); } - - 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); + return valid_lines.ToArray(); } - public string[] GetLines() - { - return Content.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); - } - /* refer https://github.com/clowwindy/gfwlist2pac/blob/master/gfwlist2pac/main.py */ public string[] GetDomains() { - List lines = new List(GetLines()); + List lines = new List(GetValidLines()); lines.AddRange(GetBuildIn()); List domains = new List(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 new_domains = new List(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 list = new List(src.Length); Dictionary dic = new Dictionary(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 patterns = new List(); IDictionary dic = new Dictionary(); @@ -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 } - + } } diff --git a/shadowsocks-csharp/Controller/PACServer.cs b/shadowsocks-csharp/Controller/PACServer.cs index 17351b19..52b838ba 100755 --- a/shadowsocks-csharp/Controller/PACServer.cs +++ b/shadowsocks-csharp/Controller/PACServer.cs @@ -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() + { + 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 gfwlist_DownloadCompleted(object sender, GfwListUpdater.GfwListDownloadCompletedArgs e) { - if (gfwlistUpdater != null) + 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) { - gfwlistUpdater.Stop(); - gfwlistUpdater = null; + UpdatePACFromGFWListCompleted(this, new EventArgs()); } + } - 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(); - + private void gfwlist_Error(object sender, ErrorEventArgs e) + { + if (UpdatePACFromGFWListError != null) + { + UpdatePACFromGFWListError(this, e); + } } - private void gfwlistUpdater_GfwListChanged(object sender, GfwListUpdater.GfwListChangedArgs e) + private string GetAbpContent() { - 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)) + byte[] abpGZ = Resources.abp_js; + byte[] buffer = new byte[1024]; // builtin pac gzip size: maximum 100K + int n; + using (MemoryStream sb = new MemoryStream()) { - StringBuilder sb = new StringBuilder(); - sb.AppendLine("{"); - for (int i = 0; i < e.GfwList.Length; i++) - { - 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); - } - sb.Append("}"); - string newDomains = sb.ToString(); - if (!string.Equals(oldDomains, newDomains)) + using (GZipStream input = new GZipStream(new MemoryStream(abpGZ), + CompressionMode.Decompress, false)) { - 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")); + while ((n = input.Read(buffer, 0, buffer.Length)) > 0) + { + sb.Write(buffer, 0, n); + } } + return System.Text.Encoding.UTF8.GetString(sb.ToArray()); } - else + } + + private static void SerializeRules(string[] rules, StringBuilder builder) + { + builder.Append("[\n"); + + bool first = true; + foreach (string rule in rules) { - Console.WriteLine("Broken pac file."); + if (!first) + builder.Append(",\n"); + + SerializeString(rule, builder); + + first = false; } + + builder.Append("\n]"); } - private bool ClearPacContent(ref string pacContent, out string oldDomains) + private static void SerializeString(string aString, 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("\t\""); + + char[] charArray = aString.ToCharArray(); + for (int i = 0; i < charArray.Length; i++) { - oldDomains = m.Result("$2"); - pacContent = regex.Replace(pacContent, "/* Last Modified: __LAST_MODIFIED__ */\r\nvar domains = __DOMAINS__"); - return true; + 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); } - oldDomains = null; - return false; - } + builder.Append("\""); + } } } diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index 3d9d5119..427fe9bf 100755 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -38,6 +38,10 @@ namespace Shadowsocks.Controller // when user clicked Edit PAC, and PAC file has already created public event EventHandler 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)); diff --git a/shadowsocks-csharp/Data/abp.js.gz b/shadowsocks-csharp/Data/abp.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..4742149658d7de5482c3dad933840410cd7358bb GIT binary patch literal 4594 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 -// 此代码由工具生成。 -// 运行时版本: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. // //------------------------------------------------------------------------------ @@ -13,12 +13,12 @@ namespace Shadowsocks.Properties { /// - /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// A strongly-typed resource class, for looking up localized strings, etc. /// - // 此类是由 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 { } /// - /// 返回此类使用的缓存的 ResourceManager 实例。 + /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { @@ -47,8 +47,8 @@ namespace Shadowsocks.Properties { } /// - /// 使用此强类型资源类,为所有资源查找 - /// 重写当前线程的 CurrentUICulture 属性。 + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { @@ -61,7 +61,17 @@ namespace Shadowsocks.Properties { } /// - /// 查找 System.Byte[] 类型的本地化资源。 + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] abp_js { + get { + object obj = ResourceManager.GetObject("abp_js", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. /// internal static byte[] builtin_txt { get { @@ -71,7 +81,7 @@ namespace Shadowsocks.Properties { } /// - /// 查找类似 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]";. /// internal static string cn { get { @@ -110,7 +120,7 @@ namespace Shadowsocks.Properties { } /// - /// 查找 System.Byte[] 类型的本地化资源。 + /// Looks up a localized resource of type System.Byte[]. /// internal static byte[] libsscrypto_dll { get { @@ -120,7 +130,7 @@ namespace Shadowsocks.Properties { } /// - /// 查找类似 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. /// internal static string polipo_config { get { @@ -137,7 +147,7 @@ namespace Shadowsocks.Properties { } /// - /// 查找 System.Byte[] 类型的本地化资源。 + /// Looks up a localized resource of type System.Byte[]. /// internal static byte[] polipo_exe { get { @@ -147,7 +157,7 @@ namespace Shadowsocks.Properties { } /// - /// 查找 System.Byte[] 类型的本地化资源。 + /// Looks up a localized resource of type System.Byte[]. /// internal static byte[] proxy_pac_txt { get { @@ -157,7 +167,7 @@ namespace Shadowsocks.Properties { } /// - /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// Looks up a localized resource of type System.Drawing.Bitmap. /// internal static System.Drawing.Bitmap ss16 { get { @@ -167,7 +177,7 @@ namespace Shadowsocks.Properties { } /// - /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// Looks up a localized resource of type System.Drawing.Bitmap. /// internal static System.Drawing.Bitmap ss20 { get { @@ -177,7 +187,7 @@ namespace Shadowsocks.Properties { } /// - /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// Looks up a localized resource of type System.Drawing.Bitmap. /// internal static System.Drawing.Bitmap ss24 { get { @@ -187,7 +197,7 @@ namespace Shadowsocks.Properties { } /// - /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// Looks up a localized resource of type System.Drawing.Bitmap. /// internal static System.Drawing.Bitmap ssw128 { get { @@ -197,7 +207,7 @@ namespace Shadowsocks.Properties { } /// - /// 查找 System.Byte[] 类型的本地化资源。 + /// Looks up a localized resource of type System.Byte[]. /// internal static byte[] tld_txt { get { diff --git a/shadowsocks-csharp/Properties/Resources.resx b/shadowsocks-csharp/Properties/Resources.resx index 2b53c8e1..24d1b168 100755 --- a/shadowsocks-csharp/Properties/Resources.resx +++ b/shadowsocks-csharp/Properties/Resources.resx @@ -118,6 +118,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Data\abp.js.gz;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + ..\Data\builtin.txt.gz;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index a22a8b05..649ac44c 100755 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -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; diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index 6ed7cf4f..314ea6a3 100755 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -143,6 +143,7 @@ Designer + From d4f2ea676578eedc74178de465609b417af3e029 Mon Sep 17 00:00:00 2001 From: Gang Zhuo Date: Thu, 8 Jan 2015 00:10:26 -0500 Subject: [PATCH 09/15] fix abp.js error --- shadowsocks-csharp/Data/abp.js.gz | Bin 4594 -> 4597 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/shadowsocks-csharp/Data/abp.js.gz b/shadowsocks-csharp/Data/abp.js.gz index 4742149658d7de5482c3dad933840410cd7358bb..d265cfd68a7aaa331fbd0be03ca58ece548b2099 100644 GIT binary patch delta 4541 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%0AfAgmvea5`Wen5<|UHg9I4D615 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 E09pgf_W%F@ From 45d4667aa931a2d48f04cfe9654154cb1ac66c77 Mon Sep 17 00:00:00 2001 From: Gang Zhuo Date: Thu, 8 Jan 2015 00:21:02 -0500 Subject: [PATCH 10/15] prompt user when the job which update pac via gfwlist have been ran on background --- shadowsocks-csharp/Data/cn.txt | 1 + shadowsocks-csharp/View/MenuViewController.cs | 25 +++++++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/shadowsocks-csharp/Data/cn.txt b/shadowsocks-csharp/Data/cn.txt index f8ceb92b..b97a05b9 100644 --- a/shadowsocks-csharp/Data/cn.txt +++ b/shadowsocks-csharp/Data/cn.txt @@ -42,3 +42,4 @@ Disabled=已禁用代理 Update PAC File via gfwlist...=基于 gfwlist 更新 PAC 文件... Update PAC file failed=更新 PAC 文件失败 Update PAC file succeed=更新 PAC 文件成功 +Job running...=任务正在执行中... diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index 649ac44c..561ce092 100755 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -33,6 +33,8 @@ namespace Shadowsocks.View private MenuItem PACModeItem; private ConfigForm configForm; + private bool isUpdatePACFromGFWListRunning = false; + public MenuViewController(ShadowsocksController controller) { this.controller = controller; @@ -181,6 +183,7 @@ namespace Shadowsocks.View void controller_UpdatePACFromGFWListError(object sender, System.IO.ErrorEventArgs e) { + isUpdatePACFromGFWListRunning = false; _notifyIcon.BalloonTipTitle = I18N.GetString("Update PAC File via gfwlist..."); _notifyIcon.BalloonTipText = I18N.GetString("Update PAC file failed"); _notifyIcon.BalloonTipIcon = ToolTipIcon.Info; @@ -190,6 +193,7 @@ namespace Shadowsocks.View void controller_UpdatePACFromGFWListCompleted(object sender, EventArgs e) { + isUpdatePACFromGFWListRunning = false; _notifyIcon.BalloonTipTitle = I18N.GetString("Update PAC File via gfwlist..."); _notifyIcon.BalloonTipText = I18N.GetString("Update PAC file succeed"); _notifyIcon.BalloonTipIcon = ToolTipIcon.Info; @@ -333,11 +337,22 @@ namespace Shadowsocks.View 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(); + if (isUpdatePACFromGFWListRunning) + { + _notifyIcon.BalloonTipTitle = I18N.GetString("Update PAC File via gfwlist..."); + _notifyIcon.BalloonTipText = I18N.GetString("Job running..."); + _notifyIcon.BalloonTipIcon = ToolTipIcon.Info; + _notifyIcon.ShowBalloonTip(5000); + } + else + { + isUpdatePACFromGFWListRunning = true; + _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) From 74c61ca76a3c032760c0b08190a6599b68ed4127 Mon Sep 17 00:00:00 2001 From: Gang Zhuo Date: Thu, 8 Jan 2015 00:24:34 -0500 Subject: [PATCH 11/15] remove unuse code and resources --- .../Controller/GfwListUpdater.cs | 174 ------------------ shadowsocks-csharp/Data/builtin.txt.gz | Bin 104 -> 0 bytes shadowsocks-csharp/Data/tld.txt.gz | Bin 26403 -> 0 bytes .../Properties/Resources.Designer.cs | 20 -- shadowsocks-csharp/Properties/Resources.resx | 6 - shadowsocks-csharp/shadowsocks-csharp.csproj | 14 +- 6 files changed, 6 insertions(+), 208 deletions(-) delete mode 100644 shadowsocks-csharp/Data/builtin.txt.gz delete mode 100644 shadowsocks-csharp/Data/tld.txt.gz diff --git a/shadowsocks-csharp/Controller/GfwListUpdater.cs b/shadowsocks-csharp/Controller/GfwListUpdater.cs index c377efd2..2bebdcbf 100644 --- a/shadowsocks-csharp/Controller/GfwListUpdater.cs +++ b/shadowsocks-csharp/Controller/GfwListUpdater.cs @@ -90,180 +90,6 @@ namespace Shadowsocks.Controller return valid_lines.ToArray(); } - /* refer https://github.com/clowwindy/gfwlist2pac/blob/master/gfwlist2pac/main.py */ - public string[] GetDomains() - { - List lines = new List(GetValidLines()); - lines.AddRange(GetBuildIn()); - List domains = new List(lines.Count); - for (int i = 0; i < lines.Count; i++) - { - string line = lines[i]; - if (line.IndexOf(".*") >= 0) - continue; - if (line.StartsWith("http://")) - line = line.Substring(7); - else if (line.StartsWith("https://")) - line = line.Substring(8); - if (line.IndexOf("*") >= 0) - line = line.Replace("*", "/"); - if (line.StartsWith("||")) - while (line.StartsWith("||")) - line = line.Substring(2); - else if (line.StartsWith("|")) - line = line.TrimStart('|'); - else if (line.StartsWith(".")) - line = line.TrimStart('.'); - if (line.StartsWith("!")) - continue; - else if (line.StartsWith("[")) - continue; - else if (line.StartsWith("@")) - continue; /*ignore white list*/ - int pos = line.IndexOfAny(new char[] { '/' }); - if (pos >= 0) - line = line.Substring(0, pos); - if (line.Length > 0) - domains.Add(line); - } - return RemoveDuplicate(domains.ToArray()); - } - - /* refer https://github.com/clowwindy/gfwlist2pac/blob/master/gfwlist2pac/main.py */ - public string[] GetReducedDomains() - { - string[] domains = GetDomains(); - List new_domains = new List(domains.Length); - TldIndex tldIndex = GetTldIndex(); - - foreach (string domain in domains) - { - string last_root_domain = null; - int pos; - pos = domain.LastIndexOf('.'); - last_root_domain = domain.Substring(pos + 1); - if (!tldIndex.Contains(last_root_domain)) - continue; - while (pos > 0) - { - pos = domain.LastIndexOf('.', pos - 1); - last_root_domain = domain.Substring(pos + 1); - if (tldIndex.Contains(last_root_domain)) - continue; - else - break; - } - if (last_root_domain != null) - new_domains.Add(last_root_domain); - } - - return RemoveDuplicate(new_domains.ToArray()); - } - - private string[] RemoveDuplicate(string[] src) - { - List list = new List(src.Length); - Dictionary dic = new Dictionary(src.Length); - foreach (string s in src) - { - if (!dic.ContainsKey(s)) - { - dic.Add(s, s); - list.Add(s); - } - } - return list.ToArray(); - } - - private string[] GetTlds() - { - string[] tlds = null; - byte[] pacGZ = Resources.tld_txt; - byte[] buffer = new byte[1024]; - int n; - using (MemoryStream sb = new MemoryStream()) - { - using (GZipStream input = new GZipStream(new MemoryStream(pacGZ), - CompressionMode.Decompress, false)) - { - while ((n = input.Read(buffer, 0, buffer.Length)) > 0) - { - sb.Write(buffer, 0, n); - } - } - tlds = System.Text.Encoding.UTF8.GetString(sb.ToArray()) - .Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); - } - return tlds; - } - - private TldIndex GetTldIndex() - { - string[] tlds = GetTlds(); - TldIndex index = new TldIndex(); - foreach (string tld in tlds) - { - index.Add(tld); - } - return index; - } - - private string[] GetBuildIn() - { - string[] buildin = null; - byte[] builtinGZ = Resources.builtin_txt; - byte[] buffer = new byte[1024]; - int n; - using (MemoryStream sb = new MemoryStream()) - { - using (GZipStream input = new GZipStream(new MemoryStream(builtinGZ), - CompressionMode.Decompress, false)) - { - while ((n = input.Read(buffer, 0, buffer.Length)) > 0) - { - sb.Write(buffer, 0, n); - } - } - buildin = System.Text.Encoding.UTF8.GetString(sb.ToArray()) - .Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); - } - return buildin; - } - - public class TldIndex - { - List patterns = new List(); - IDictionary dic = new Dictionary(); - - public void Add(string tld) - { - if (string.IsNullOrEmpty(tld)) - return; - if (tld.IndexOfAny(new char[] { '*', '?' }) >= 0) - { - patterns.Add("^" + Regex.Escape(tld).Replace("\\*", ".*").Replace("\\?", ".") + "$"); - } - else if (!dic.ContainsKey(tld)) - { - dic.Add(tld, tld); - } - } - - public bool Contains(string tld) - { - if (dic.ContainsKey(tld)) - return true; - foreach (string pattern in patterns) - { - if (Regex.IsMatch(tld, pattern)) - return true; - } - return false; - } - - } - - } } diff --git a/shadowsocks-csharp/Data/builtin.txt.gz b/shadowsocks-csharp/Data/builtin.txt.gz deleted file mode 100644 index c846e6448a7ec005ee03576b0d40e751c51f85f7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 104 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

O#HUfBW_yeE#i! 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 - /// Looks up a localized resource of type System.Byte[]. - ///

- internal static byte[] builtin_txt { - get { - object obj = ResourceManager.GetObject("builtin_txt", resourceCulture); - return ((byte[])(obj)); - } - } - /// /// Looks up a localized string similar to Shadowsocks=Shadowsocks ///Enable=启用代理 @@ -205,15 +195,5 @@ namespace Shadowsocks.Properties { return ((System.Drawing.Bitmap)(obj)); } } - - /// - /// Looks up a localized resource of type System.Byte[]. - /// - internal static byte[] tld_txt { - get { - object obj = ResourceManager.GetObject("tld_txt", resourceCulture); - return ((byte[])(obj)); - } - } } } diff --git a/shadowsocks-csharp/Properties/Resources.resx b/shadowsocks-csharp/Properties/Resources.resx index 24d1b168..ee5f98ea 100755 --- a/shadowsocks-csharp/Properties/Resources.resx +++ b/shadowsocks-csharp/Properties/Resources.resx @@ -121,9 +121,6 @@ ..\Data\abp.js.gz;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - ..\Data\builtin.txt.gz;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - ..\data\cn.txt;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 @@ -151,7 +148,4 @@ ..\Resources\ssw128.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Data\tld.txt.gz;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - \ No newline at end of file diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index 314ea6a3..1848edd9 100755 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -102,6 +102,11 @@ + + True + True + Resources.resx + Form @@ -128,14 +133,9 @@ ResXFileCodeGenerator - Resources.Designer.cs Designer + Resources.Designer.cs - - True - Resources.resx - True - QRCodeForm.cs @@ -144,13 +144,11 @@ Designer - - From 77aa5e82801ec1188852a5c86f6eebe5b4f781b9 Mon Sep 17 00:00:00 2001 From: Gang Zhuo Date: Thu, 8 Jan 2015 00:45:47 -0500 Subject: [PATCH 12/15] change prompt message --- shadowsocks-csharp/Data/cn.txt | 2 +- shadowsocks-csharp/View/MenuViewController.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shadowsocks-csharp/Data/cn.txt b/shadowsocks-csharp/Data/cn.txt index b97a05b9..5dd129c0 100644 --- a/shadowsocks-csharp/Data/cn.txt +++ b/shadowsocks-csharp/Data/cn.txt @@ -42,4 +42,4 @@ Disabled=已禁用代理 Update PAC File via gfwlist...=基于 gfwlist 更新 PAC 文件... Update PAC file failed=更新 PAC 文件失败 Update PAC file succeed=更新 PAC 文件成功 -Job running...=任务正在执行中... +Job already running...=任务已经运行... diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index 561ce092..b7ce3f2d 100755 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -340,7 +340,7 @@ namespace Shadowsocks.View if (isUpdatePACFromGFWListRunning) { _notifyIcon.BalloonTipTitle = I18N.GetString("Update PAC File via gfwlist..."); - _notifyIcon.BalloonTipText = I18N.GetString("Job running..."); + _notifyIcon.BalloonTipText = I18N.GetString("Job already running..."); _notifyIcon.BalloonTipIcon = ToolTipIcon.Info; _notifyIcon.ShowBalloonTip(5000); } From 4860d5b32a530c9e34feda3a7d995815e63212b6 Mon Sep 17 00:00:00 2001 From: Gang Zhuo Date: Thu, 8 Jan 2015 01:29:22 -0500 Subject: [PATCH 13/15] fire error event when the pac server is not run --- shadowsocks-csharp/Controller/ShadowsocksController.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index 427fe9bf..9b2b9ba3 100755 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -166,6 +166,10 @@ namespace Shadowsocks.Controller { pacServer.UpdatePACFromGFWList(); } + else if (UpdatePACFromGFWListError != null) + { + UpdatePACFromGFWListError(this, new ErrorEventArgs(new Exception("The PACServer is not run."))); + } } protected void Reload() From a984014267636d267d38a3cb416bf7f8103de8a9 Mon Sep 17 00:00:00 2001 From: Gang Zhuo Date: Thu, 8 Jan 2015 01:54:21 -0500 Subject: [PATCH 14/15] remove unuse import packages --- shadowsocks-csharp/Controller/GfwListUpdater.cs | 6 ------ shadowsocks-csharp/Controller/PACServer.cs | 2 -- 2 files changed, 8 deletions(-) diff --git a/shadowsocks-csharp/Controller/GfwListUpdater.cs b/shadowsocks-csharp/Controller/GfwListUpdater.cs index 2bebdcbf..2b3db383 100644 --- a/shadowsocks-csharp/Controller/GfwListUpdater.cs +++ b/shadowsocks-csharp/Controller/GfwListUpdater.cs @@ -1,14 +1,8 @@ using System; using System.Collections.Generic; using System.Text; -using System.Threading; using System.Net; using System.IO; -using System.IO.Compression; -using System.Security.Cryptography; -using System.Text.RegularExpressions; -using Shadowsocks.Model; -using Shadowsocks.Properties; namespace Shadowsocks.Controller { diff --git a/shadowsocks-csharp/Controller/PACServer.cs b/shadowsocks-csharp/Controller/PACServer.cs index 52b838ba..867c81ac 100755 --- a/shadowsocks-csharp/Controller/PACServer.cs +++ b/shadowsocks-csharp/Controller/PACServer.cs @@ -1,7 +1,6 @@ using Shadowsocks.Model; using Shadowsocks.Properties; using System; -using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -9,7 +8,6 @@ using System.IO.Compression; using System.Net; using System.Net.Sockets; using System.Text; -using System.Text.RegularExpressions; namespace Shadowsocks.Controller { From 075069ef167c3b4d9308d92ea47dc6543fabeec2 Mon Sep 17 00:00:00 2001 From: Gang Zhuo Date: Thu, 8 Jan 2015 05:28:43 -0500 Subject: [PATCH 15/15] not update all pac.txt, but only update the rules --- shadowsocks-csharp/Controller/PACServer.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/shadowsocks-csharp/Controller/PACServer.cs b/shadowsocks-csharp/Controller/PACServer.cs index 867c81ac..fbd1989b 100755 --- a/shadowsocks-csharp/Controller/PACServer.cs +++ b/shadowsocks-csharp/Controller/PACServer.cs @@ -8,6 +8,7 @@ using System.IO.Compression; using System.Net; using System.Net.Sockets; using System.Text; +using System.Text.RegularExpressions; namespace Shadowsocks.Controller { @@ -264,7 +265,7 @@ Connection: Close SerializeRules(lines, rules); string abpContent = GetAbpContent(); abpContent = abpContent.Replace("__RULES__", rules.ToString()); - File.WriteAllText(PAC_FILE, abpContent); + File.WriteAllText(PAC_FILE, abpContent, Encoding.UTF8); if (UpdatePACFromGFWListCompleted != null) { UpdatePACFromGFWListCompleted(this, new EventArgs()); @@ -281,6 +282,18 @@ Connection: Close private string GetAbpContent() { + string content; + if (File.Exists(PAC_FILE)) + { + content = File.ReadAllText(PAC_FILE, Encoding.UTF8); + Regex regex = new Regex("var\\s+rules\\s*=\\s*(\\[(\\s*\"[^\"]*\"\\s*,)*(\\s*\"[^\"]*\")\\s*\\])", RegexOptions.Singleline); + Match m = regex.Match(content); + if (m.Success) + { + content = regex.Replace(content, "var rules = __RULES__"); + return content; + } + } byte[] abpGZ = Resources.abp_js; byte[] buffer = new byte[1024]; // builtin pac gzip size: maximum 100K int n; @@ -294,8 +307,9 @@ Connection: Close sb.Write(buffer, 0, n); } } - return System.Text.Encoding.UTF8.GetString(sb.ToArray()); + content = System.Text.Encoding.UTF8.GetString(sb.ToArray()); } + return content; } private static void SerializeRules(string[] rules, StringBuilder builder)