From b10d06dd4b9687fc3026e16c96a0fd29c3a8e17c Mon Sep 17 00:00:00 2001 From: sin_sin Date: Wed, 7 Jan 2015 15:43:05 +0800 Subject: [PATCH 01/23] * Add logging timestamp, ref #113 --- shadowsocks-csharp/Controller/Local.cs | 1 + shadowsocks-csharp/Controller/Logging.cs | 27 +++++++++++++++++++++++++- shadowsocks-csharp/Controller/UpdateChecker.cs | 2 +- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/shadowsocks-csharp/Controller/Local.cs b/shadowsocks-csharp/Controller/Local.cs index cd6d2f96..ba507c14 100755 --- a/shadowsocks-csharp/Controller/Local.cs +++ b/shadowsocks-csharp/Controller/Local.cs @@ -61,6 +61,7 @@ namespace Shadowsocks.Controller public void Stop() { _listener.Close(); + // Console.WriteLine("Shadowsocks stopped"); } diff --git a/shadowsocks-csharp/Controller/Logging.cs b/shadowsocks-csharp/Controller/Logging.cs index 22b5b9b1..208051e6 100755 --- a/shadowsocks-csharp/Controller/Logging.cs +++ b/shadowsocks-csharp/Controller/Logging.cs @@ -18,7 +18,7 @@ namespace Shadowsocks.Controller LogFile = Path.Combine(temppath, "shadowsocks.log"); FileStream fs = new FileStream(LogFile, FileMode.Append); TextWriter tmp = Console.Out; - StreamWriter sw = new StreamWriter(fs); + StreamWriterWithTimestamp sw = new StreamWriterWithTimestamp(fs); sw.AutoFlush = true; Console.SetOut(sw); Console.SetError(sw); @@ -61,5 +61,30 @@ namespace Shadowsocks.Controller Console.WriteLine(e); } } + + } + + // Simply extened System.IO.StreamWriter for adding timestamp workaround + public class StreamWriterWithTimestamp : StreamWriter + { + public StreamWriterWithTimestamp(Stream stream) : base(stream) + { + } + + private string GetTimestamp() + { + return "[" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "] "; + } + + public override void WriteLine(string value) + { + base.WriteLine(GetTimestamp() + value); + } + + public override void Write(string value) + { + base.Write(GetTimestamp() + value); + } } + } diff --git a/shadowsocks-csharp/Controller/UpdateChecker.cs b/shadowsocks-csharp/Controller/UpdateChecker.cs index e71d95c9..d6653468 100755 --- a/shadowsocks-csharp/Controller/UpdateChecker.cs +++ b/shadowsocks-csharp/Controller/UpdateChecker.cs @@ -145,7 +145,7 @@ namespace Shadowsocks.Controller } catch (Exception ex) { - Console.Write(ex.ToString()); + Console.WriteLine(ex.ToString()); return; } } From f1c821a9cdbe800dab0514c409a1d2808c990ffe Mon Sep 17 00:00:00 2001 From: Gang Zhuo Date: Wed, 7 Jan 2015 23:08:25 +0800 Subject: [PATCH 02/23] 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 03/23] 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 04/23] auto update gfwlist, see https://github.com/shadowsocks/shadowsocks-csharp/issues/115 --- shadowsocks-csharp/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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

8&9X>GdJSKBOpy6wZ*+Jfr}Jl=v|veoWzv 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 -// 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 05/23] Log more error information --- shadowsocks-csharp/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 06/23] 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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ν zi+Ih*<^gXSt1vQ8u|2)Ue7rMygYwS$3S0M^S8wYk(QNf|;ir$nHa@km3>{Z{T)PMG zT*UtYZR6LQ9v-Giis}J&Dm;c2@1m`+bje!OrPZ^}Y?9ceDpm;YEZIV9YimpfluxFg z!ovf<-vl6cuOGIBCdSzYn&k?X8s$&5ZHqU}M}(vo@{_p#w8mtby29jg^$J>e)qB{Y zXr(oTi_qCbtx#cbYu!uugV_A;tIqDamcL+44!&Sb4nAv54nAZ}4!&Sb4!&Sb4!v=r z4qF~N?A3$AFFFav$s3L=jH8Fk!MR;G$nyc$8o^<2!)}@zI16JO>>!a1xEUMHLHr-Q zpCanzMH_Ib26?xQJ-AWAhMi~my@|?)24K#P%wFt5X5@&+68*~YccUbKl;n+)hEb9? z?z&0hp9G%-pTslnDV^XfIQmPHI^&bx^n395MKWf5%$t5sOm{7QIeX+VghSgizU)oE z6Vo&Q1`cS?w^JcRQa$Z{?J`aB54tflqKw4ZdiG0W+x8ks>X6$rduVU;I0YdLZYfE0 z49|^+Qw-*8z4+Si z`h)m72o4Uv{PZAi9^}o#u6Mh>6Q<*@ypzLkb&|?Xg6ib$PTnRjBnEiFAK+Z=9!|eB za7dy@xa~Z_Ir+u*{CJkIW(j1LSZ4`&mRRRqA2_)|;6QKdei$f5Q^zucBV3fAZ@s7* zcG=-DdI_;lYK*AgeKn9S6U{S-9vVa|ku!J+)XVE$a4){RyyNjjQ@0za7kpU zGxBN>&q44Y0g2dYPA zZm$yC&hD`G3qDbiAU7+rT@5NH^1b1cPlXL#;fB4P6|?qcJd{u|XK=vb-vvky_jXnhFG153 z&0#i21qN)VQ%MPd{$tKdhf7Fsit`7z@vz{AKqXE~kBdDryN1P$nww4U)MMOlxwuOy zoXaMH*Dfb{ZyIy<_rkWP#x#XJjfL*5q8A!H%nFzfw)aKw_Bew_#ix12EGLzM)y^dr zYu4Agp!e4HjU8LtudbxaQpH@>61|;U3P-V>?d?tRy;D)B=-giA%JqBW6;~4Ms9}_P zC3ZPYy(tZGPZmR=!{QZ3;;1D$11;$QyY=@1Sh7Jau(@5`XfF^}PM914&*1)=^a$4H&`$8x;QQ_-@71WKvt@bRbul7O^cv3)Zau}FM)0BZ3$ zU{Z9N%|R#eHY@08Ga60>2V zG;5y)(<1H13khXmCrDqbWW>*Ssm{VYTj#@*eIgs({-!j{G}csNL|P9ksF_{IWxm<4 zXi)=LQe5?&#Eqnde5wE0)~RBHO36gzH*KyqyAC&HJ{@kuoGZ5>)uL!Jx(dgOu{n&U z$sxdIKv`X^?xLVFNcODa2P$Ph7j;UFaximO*vYGB+Ei&Q_5Q9r#GW;?mK3;f@E2v2 zG$iRIC794#io`bStW=FfBRazF(+Ib%3~a5S43vVm?QMd-$UN>{)s}+ob>p%<2_Pw_ z(wkaR;U4FEawe!%->C6Vwke8=`utv*pj69b)@VD>ju%{|JSg#25D5mZ*qASMb|%-` zDU>j%AA4OGEv$Aqjdgsltr9f*`sDUbhkZ0On7S2i9yD#=S>2@5%HSL{O9ptcy^f9y zpTe|cC6(59bWl~w>LZ{;N19rxfXJ$MM_sT-FghW<=f%3j`nhOaVwS;?$x6czja}*Q zRDgACs#3?$;b2^8QaqM8t}2b##_a;uTjqjU>TrS|i<}VTv}}%Q(fTPogb>5yBpLNC-Mb_E!=LzT83rVu-~rGi=qSu5cyg#)@U^j1kCEWX)H zt_cdt);eT@WIRWCq8$0-(G)d&!jQ3)&xwKyrCv^kbU0}MQu6z{3pnBOhpZn@mhAmg z;c&!*N_Raen}iG-l_lb6+|#KLhW)K=0tw50EwXpAIJ{Hx%e|kQYkt;+To8<#Z0SwX zgOevdY*0+xJRn2UdWd^qkl0GP*lA*z4GhMD!a;@b`P^I9; zMyXTb%!Z}Gbs4k?h7QFp1tWdXyH+O{7+Zg3Ea+zQPN7x8LT~+XD9JcuZKFIt+vAax zga)vP(A%K^SKF6DBvuVOgi}iCe9TShOf8tY7Z*xUxM;uhQpDbsUHRW`Y@pel0^A2G{L`LyvDQYGzg3nYwIK zSW=Bx1GNfiO1_9I^xO9oW9Fdhqelr-2hgkV%4~>_v=Mv#NSY@x%~R|K>DgYra|LSsqcQhtFie|`a&XSr#Mn`bCC~{T1bNG zoCyi4)kQWa{&k^ets!yZadAa~M&2v_rUjAt)2d9pfh5ytMrkjwcQ?MIg9fYn_rYR2 zxPCDhvih2mF0AymrMY7B7*7)w1B!%!lxwNHK}~4j9B1kBiBr-*+-QR@6He&yU2iq3 z4S>Nny4L)lo{Xh)B4+Sw=|+gB#FEbP8X=>z^uh&O)TcQ0SV9~sc00OO7tk6?DUTcLIPphn(J<+@__oU%WjL{!$Q=!jZ8puX zMg`nFi(OWzU|Vr7Ngp1p^OX$Tk#I9jRwZSvY>3fZRBmB7sOjp_s@a>-UdjHLD&KlO&Q7Jr8~uFreW%zWaO0e1X@uc~Ny7rn z_?oW*Zl#8AWeUz8sQ30{gH5L*0vdd$OiEHiIOT%zWABRUBS9y8*JM;>eKe8Ddn`$t47E+_ipB!yX-nd)SIiKmnFKu)XjCf`6Qx-_ z3UWzE;$7%3>l(i8WiEF3`b%vrXd+tGcttTwbH>_i?c=OiRVEjWE~3Je?ci4=vF#R$I~t3jue`3ZTx08#ZR$-Vj z8WiK~tS1`7a`q?XnVRg$_v(cSb6VA8IE`kOrBw|(P{S=oR3NXGl-fxx?h!VZ9z9&# z{ccqoyjtA~ZjCYu7qzCm9CErAd)Q3AL92G6RlBMH@Sv{0#l9{R5yULYc3n=^sOF(9 zebAk?lQQ&{&6+mMrqLH}Ejo1Z*OCCzOhHRNS+yma+3U5tg;eEIF~w^&zp|EETY0{& zbe~ivWTXbQx`3AXOD=b(^jY)~GUm zb$!#j(#yTH=5?k1LyrirWK)NepAxTa>>EE*Ry+=#4Q^4q8ra?ac4kzNT#LW_i(h{D z%Rl|)fB5Bhi2AF9e){IqpM3hsr~jDv;j%Lp=EsFMU=Fg!iyfp=_IeGn*NYt9F30Wy zhc`N1;t&p$>|2ukUxRE7BWIEbhAZ#wxk^k|-r{qW_^vU&tHgJe_^uMqHAirjfUgoT z;jiWO*8;r8$rd;q$ZPTZdN;_nvq83<4YH?fklkm4Y&#=|^Ky$hxM2s?efK-idkue1 z;7(5@`=j9uk;8t;jW)-KooM)N_;(HX9bV)2fGcL{b*2yaT`u^&iXXps{KU)eAVIY$ zj@=kHv5nYOh+OQ(qxd^=p2)%2jhvb6Q*y8=kQ`PaU>6SQ!U?#rPs+2T z2gE57k}4u3VMIvUKqRC}AqI(aB*x@bl1hY6G5Pc;rJ2Y%VIlbn={=o(VwV*4lA^k# zluKSrH`|jLI7M&YSBz}05x8&PzArS{Tl_wm>I3F%O)uO{>Wj?HarC!Qay5#%hM|<>vrSU|u zX68)8K`gj1?dQp|feq&E8^v{QroPDr5kP8j)Dtp2dydccQgA&cY%iuQ^xOA^p`l)U zXE@{NTOS3H;!&J`a!<37LL7WJ`-BJbCp6{`n+Bi75}x`F(6b1xze%b1K;K z0hr&upGXY&D5M-i=2JAGvrQOqNm8)#MsJoynrfKNw(m^L585XN7B(^$^rTFldC&<{ zHrNDFvDO%lv8D9GvfJOdDN+4UL8eTaBf=7K%cN6B#Oe=RPTgjnqtItcxx-n z!iD_y-F|udt{{et*XF!NSaCFfj-qS^8bfoqk-(K?5fB1KjWl-LOMi<5RYs)nwE=0V zW^Pil6Gh_?9$g4I=I4^fVCM`ZlE&9kbVP_06G4_#dKgm>x|D(tON_!uWw$oij@3&+ zuiY%l6t=0jsSyxK0k%&hLtEtSn*xz3l@ovwbZTA@jF=pvVtTOa5sP?HBVeOQs&isQ z@$acN-oCp;Eadv%o73T7E~{Un)_MEx1~9{3#1cA>D`jsB<;)x-I+LoJV-STluAr`Y z`>xO!PewPU)6RWr^FqfqkGL@Ra_XF7DUp$Pse<=PyX?;-08&g$rgA#lnbfb8+2 z5;fn>&#tIIY&UJ1b1aVc8~Wdz-@ec6+Ss$m^WJyzI>arty{Mck#mvmDO?A7!b-6f2 z6YSr9kSPBOCQ}mMJ*B7OkqyjWGh(xA#V4dp3uwf?_ z8dW;=a?;JA9%54LBK;-Y1YMGVfWjW9c!auqs51?X^9Nlu3MsYlw-bTtwHjll@y)V&AmaSuNyUykkBQ}>9 zx^EL-5J$w7ti(R%{YZUKloRT-5Rs&b$RO(dm^#zr{Pu%H;ZV3hZz6^9 zJlxxCLy5GJ(m;>JRBMLV<>71;b$|Q?1>&d*{!sH~?WK%}O5wFMX0)NJnAl&nF4jwX zwnNMwk#iHJ1avA^qH~C6pOQnpY9f2ji%TG*Z8)1Txi%3Om#|_;w6hy>G^7l;dZ;%b z4<|`qM+QXU+Ibasjn>P_G}y$<6!w%yO3D@o+UHD&T%F8*5CJ*8eK(V48e9T1i8ebQ ztr)W43~?sbGI<;Z($5OPt>2M|O_r!^8JZA_%XFjfSKlRLp!-jMsCeuzX5miVGass0 zWb8qPL^dr>sJBdnNQKmRPu%fgKR;UM?1xYupj{0lVlO=6LMl4)lsZiXxkVb!>5LN> z@y#>#M`ka6FLFQx_0mEe#fhBgbj(|-t{8@5GD|_jl8Vec=AP?>;t+UE+UvANxjkKy zhB)0Yihwb;WSxwjuwEH%!gHBM-snen_YKvWZ+C@u;C>kYTh5jo5+iKHk?cVY7r@MYkeJ)l07y&pK}=10Jjhc} zFwY=*&ripXX<$;8UOZXACb2oM2Z?~R;bKi1~8_2rch)cAfy-y zUD}kM1~`dd6Yral$Jf;G-)NR9HhHAc1*!JgT*S1PVcrn`_T31O-$7hAX4M5|RKdB$ zhS*HO#G+#|mCmIM0lLfE4>Hp_ds@)Xo7mBl&oS#XcrDzh>;dXG3)88<)c~V4uK1z) zQyeMys6u*EhAE&)n=|RnUMw0=(W2=sNv8~O8gseWAYU%z;b9rYVXTgv@w$ofI8csbQim0n!6qu!?qHGz;jM#nq{f_H3W@7A#*ozz zQOSqxPiu%&jMerjQfe?MSZZPKC)!gVCtdR3X)Kv&vOi;~6S+_a1G^-}R)znTl;<#F#Xe0$JBoEY$R*AdzJhaEMg^ zeh-^@UYp2A-N92Zc{(OoY0~RRy>M$HNqs_VvJV!J5et1OZnrF%CYg9LxdUbPh|Qyk z@#={pJ0o2J>yi?AWJ?0bE9Emuo3KuLrP(Bc)LTg2*%(^$rOOQ_jg@AyJw&;|7&OVS zm<@l~j0jt1EQucDd>4~ZRSKOV$>t(9KPBI6p*Yc1yeTT_HnK#bNV?z?LY2vs7xjQe zUYT*3Z*41K@Dg22)!Ppg<5RY&H%Lh$Lp#a~p@sIdC?f(B_P>ryOlGU;zg z*#OP75sga9T8LoE{8n(-(%(fm>7gnWwP#A`ro>(!7bt##|f$1{_j~gv=^{NU^xoy9d{wO)QP1 z{%DZA>M3X;U3Ajyw40VooS5!te0+&XWjZC6e9tm3FQi!C17Q=1JuypL3|0kM%KNg9UOYaO-q*;2H`f7fZ8G7LLJ6^qUF>|R5Jk-E|W6eO$=V)V+ z9soi;dV&IP#7)U9G#@PuDSwLbaZnCas3ofV#?sJ<+bVC@VRvlP)FsifOmik9H80fR z>|A5Um7;U<)W=szXd;y)X7Rn)Aq)EJxadQuI@-(QaFAWtzEhmxU#|iKR#U zqD7oMM-58UMdrLfk-a2^Fy^89LV}i=l}24-?gWKHixn;k_qqfpGd>s7NLhi9qB@w< z!RFiiHWXvVbCx4KeUE`u6!nEW<>}x>(W= zslH=Tk|Py%fq9bam*ifw(j|_3F3IA(6pQy_;xGkqM9P~~M5YbtjrZH2UP+kDRLSg^ zFJ18kb8Pb~7#bO3KgxKGeiZV%uf}ON&b+l|oa06hxwdDNJD*0m>}izCo<_M33fzj9 z@1&x!|HR83XQiJi!G;*8=<;siKcW8_Z#&d~4}PD_OfcNy5h^@!wh1ad9ZB-cWb)8Z0CCIZ6} zT8~fg^z1sG69>fyrx@ZVoR=O4Jm&Rq@;D9T7?AKebNy~Q@UOo*!`^vw4!Jl;6t^@o z$3fz-HyrG9gNsQ^CXiEd?%1*oY9Wonkx3453AU5;lODcEV9QGCe7SY}!oS+%TSX|0 znUgUjp3Ax4t=CtH8Zy;piqfBG> zhGd5x3$sXt9q`JHqdVLwpynRQz{za-we>uk2;u4X7(X$^QMbKsB?~PH#C`NqwsY?e zQp~eC+p82nO5@pF{T#iLbzn!8^>ZRR98tUrb$0^^+x@BW{df~-p3EUWotO0<(Qse) zk)(o+N$Bh(admc?V@A8)HzZU{`aJ@_MbFgh?dQ8~g&Cz9h#*t{8ilZ17YVR86UWxu zJ$7X>)#7-Gkau$qg5nE8UNYbN;T{P}AZMXp_YzINc2bsu=~IYAVz+aU^2fL4uieHm)M?=|_7J4-^#$KRrfnA?!h3fbqCF1*Tm7=G3?~9ZeCE^h4 z4C&z%V2Z;_a7-pCVI~QkFxS507CkvB!zoto6rOmNDRtE zrFham+1I>6Ph5q*lhDml`V)-~u3S!-$QXpUnkOnhrf+*3UI0ZRf0qF81(r@U(^*80 z64vw*Q@~AdLabAyJPprMj&YuVO8P0u3yIDlg^N#Cszih587$E2)$|=}w{Ue$k|Ux? zyplp7ZuILJhdo3yQae4wM?~MEWa0!vk>jQHA}H86&gorlhto~e(IRz5aqrOzPQuKC zi|`!oQ9`bU^KiA)%?L%(wsPFp-XHo*n5)EcMY5rPgdx$FlwN1{1oBR$!Idfuj3Opt z4ELlCK-`m*w<2@oj8gnlxpFDba@pl9mtB%GP57mry~PLS zLH3JrObjFlaOdvCC;zEcfW_bx2pD|ErgO97H>nz^J^6-d$M5dv8@DEq)UB9Bd>-~3 zH||GE?u~4f=o1${inkMWUC<;#UvRF18LUNPGKuMx#@ph@KJl3cqDYtANy8%3Gj*&I zuA_mazj!9^CwmbT8;Ia|%88kupk0Y2Lt(geF46d~6;lJQdFvuG^PN0Q-X$^J;l!bJ zcCd4di^__cn2*sB*BL%9$;^cvH+vy)5VjR+aN?q)8^rf)0zO+X$B@>2jFd8+DS6hr z$;Mpc&iY0k^9P=z`y@pVlA0AL8glxJq>HTY*>XCD7|1#gsUkg0iqc$+SKuY+m%N0r_f1Za>%N2B=^fW$|<5pOgGjDYJWl)8dC8IQ;M< z(s#HmDw4yBJ2m3%Q374o*Pwd-G2`B`-vK`(|KNb~eqOuK-UdcI|I8fQ#6Q%-a*UI( zeE6P-89z*gaN<`N{^7t^{9N(F@!#-sXTNe%Dag^JAV-seoJk6De2E+!haxA)WKWRE zo*=V4LFRmdOz)5r+%BBSu%{t_c$aCBAk!;BrWb-thL95m5^0`-2&4EHV={~)cR@@{ zawc5n1OkUg;RZ2Jf?T~F#7ZG2%%lh*$w90zc1Em(G>mcZ3-0tY?lpgGR4h7jI1ggx z1+nkgkj2fSlLZ}&UtrOJWYY!&HAgw>7vzXvxbP%ZkTZMa%#g{;F1(g_UQ_cGk7CpX zvF3uQ@%j41N*C zg4)9Ga%SIWHn_>bOJ|Ok93+jL*30h&4pag;NFX_EPr|i~(tr#OQbrCd9C9&j2e#WS zQtJyQrz8@dA6;b1bCC(qMZQ3>$TaC9Uz=ED?v$KG#Dg5%B1_H@nUm27IgT0`J4+9j zS`s^!9gbxbHLxT}A|g$aEi7}<^E}Sc4dSeD2HZ@=K5NA_7VdSKboyweT2f zk%0)mL8Aw9&wd}^^2tJS<8&YpnSdsWkF6qHu2*Rei?kHHaoH`>T`bavEYdeD(rql# zqbzcglpNQvmzD#g7de^ax2LXw+%NzBNB{L7e#q3{ef`TH{|Tti|MU;Oc>nvL7MAmc zWq!G{5Z>db7l@Fo-ggLDzDEIvbB2#q;1>dZ$7ed|mwEyEU8Un%rB_;|$6EOa=_;Ms zDxDcTp6m?U_NJIjlU*xs3UhLbxh%nD&J!nZb^OZ_9cKA;gEdU?+s!DymTGUpO{(bV z8F5<#lLRCuOpa_CgPb@kNB+g&;EAuQbn&I`B)>EOlGHNkBPsXeF*(?t?3K{DTj6iS z-#AyDv+@e8e6iKQaiMmz{N98M{42h15@*jv+jBW%7&1!Q`ZeaE7hf0gJupTi7aGP0 zGCI(b0^i854JHvnO+Ei&ll6sx*`2;_^FkUSXSZofn73PaHb!(sSvvci1;gVj?_Dn zgJpGc_^Ly4$1uV%9sletY&a$S?aGILv`V7})>7@ecgfz_E`U`^f%B_CKEZ_sqWo|6cf)WAXgd za~?hCZsHgxre}^TaF~I^TsYq4HGWr)@xp#CLi4*<`DOgdaa}pC?qB@gD=AH;`b^E4 z3YoemN=le1pQ$BLQrb+}L>+U;ZGKluAC$|Ols{AXjaUyvbvZ3vPJN%>9SW608FC7w zj+n~f4LS8g4tdD=7;`?x9Nw72lR9MToT(vGmrUi9`uv8^CGK-MPdW8d#^#*nkkhi{ z)Ju(nT63B&`Hf4#a>&<0Wq%?EheH$t5Pc%%M1(}#BN5x!AqoJ9B@$BoAZ#R#DZn

8&9X>GdJSKBOpy6wZ*+Jfr}Jl=v|veoWzv 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 Date: Thu, 8 Jan 2015 03:07:26 +0800 Subject: [PATCH 07/23] support build in gfwlist --- shadowsocks-csharp/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=启用代理 ///Mode=代理模式 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 08/23] refine, remove duplicate domains --- shadowsocks-csharp/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 8a1ea1eee4f89619b2cf79c718535fc3bd4bf2a3 Mon Sep 17 00:00:00 2001 From: sin_sin Date: Thu, 8 Jan 2015 10:29:38 +0800 Subject: [PATCH 09/23] * Clean unused tmp, fix spelling of the comment --- shadowsocks-csharp/Controller/Logging.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/shadowsocks-csharp/Controller/Logging.cs b/shadowsocks-csharp/Controller/Logging.cs index 208051e6..81f16dd8 100755 --- a/shadowsocks-csharp/Controller/Logging.cs +++ b/shadowsocks-csharp/Controller/Logging.cs @@ -17,7 +17,6 @@ namespace Shadowsocks.Controller string temppath = Path.GetTempPath(); LogFile = Path.Combine(temppath, "shadowsocks.log"); FileStream fs = new FileStream(LogFile, FileMode.Append); - TextWriter tmp = Console.Out; StreamWriterWithTimestamp sw = new StreamWriterWithTimestamp(fs); sw.AutoFlush = true; Console.SetOut(sw); @@ -64,7 +63,7 @@ namespace Shadowsocks.Controller } - // Simply extened System.IO.StreamWriter for adding timestamp workaround + // Simply extended System.IO.StreamWriter for adding timestamp workaround public class StreamWriterWithTimestamp : StreamWriter { public StreamWriterWithTimestamp(Stream stream) : base(stream) From c24c1d44b702285f487ef82aea2f045dc7ff1951 Mon Sep 17 00:00:00 2001 From: Gang Zhuo Date: Wed, 7 Jan 2015 23:41:45 -0500 Subject: [PATCH 10/23] add new menu to update pac file via gfwlist --- shadowsocks-csharp/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 zcmV@U2t;17TutE^2cC?Hp@U8cX)OzoO-4vy2izV>GKV1`#8BHM)p( zZwibx4ui~QoS|k0k&WKpzNeql-SYy&Zr$2is+6I-&!bPDSD$XE)zD|#vja1-2k3T& z?uJv>38T%iX(7i$3}y!i&RU)32|zRs+o$dB zR|FC{Zg;=5E-%sXc?UJnMWfSgH?K|`9dvQkxj4UURS~+hF;h0c=g4MAqzls?*pcbD zA)WJASdI`la|dW-KG?7dLS#X!DNmcD=Hf+KUNUDh-Ta2#En3;e?0GzM%qxl zxdB^<{F@u-@+Pj!JEKY9u`zoq&l3JSJ360w7Xd715Y3M4&-JWr( z&Jf|Y>c|WwfHEFokO6d$~qe{lp>ZGag{Viv$4G=fH(tjAArP|RW|YlgA?_@j3*YXu0ksY!j@6Sb8xVk%Tnhf;;Hgg zkff}shGQ7YXcab{$)0nq$QwTIDPYel>eI8LMaPZ{9jK<^UOt*kKaV{o}6@-M+%dUv~$0;HRWV2GoF3{bU&W2*A3%UO;8Q&JNt1g z)BFS!`nBp>zlQO?`r{zR3^*(O5HMgCD(O8y=|IBoQ;Eg|`mf3_Kq+Ay2L64Qs(@G# zSx2xQ6BTi|3Mt~xSiF>xJ&Z+hc+^?5_2qPWbipk_wh^zZL&FOoI7!1+*E zDmHE6N%%D80Rd4)Y=VMk5j$|;*pqCn?LC;TGmsd>F3t>NC(USBrt6lmrdN=}22p)F zo{+;2*!)-^P_S1JfB(UF!lS9ltvnktS1DpE;zrO^U}c&ri3Yqq*vh;I{=MmV;rtV) z0GIwGutz3g*d~i zBtOFNbh&5I!H7b>G6^U(9AU((i7}E83qv3$L?5b=FF@sRu1=M6iFZLUXb5?9q)d}* zf{|nzgH~PJyMtU6T+s%4{hFWy*Mz;(DtM~gJNU4K;rwJW7?_ngTuLxVA5Ysp&<;g7Rf#483VQrolK z$$;!jGbACUVf(1Q2X7ycv|iA#zCN!^Vyoa{(K9OkT15WY^zcj2qYv|~0)8b|f-}ZZ z?qlEu*@3(_ay)(c@@W$3(}l{G7G;VDbKP8u8Dj*p6@kBWf#S?F3d$P`i7}y}i!hi} zfBB_qb@tfo^<5PabTJO+^+4IwxvkT8Z0ecop6w{8V_TKvkmoDXG5|GR#pC6Tg2)oc z5Vi?%A{#c@%KpO%Y4&jL(U2`g?1695whD*TW4Lew5Wz1Q^0I-$LwS{fpr zf&F+sEVEH+C^Nu^)s2GCu9?BJ!qh4!$?}kL5jIs1HDp2%MM!j_c&)Rr7P(KAf?$Cd zHha!@mNB_>;Ee2HI>M#SG8RbgR$kzAQYK!M45VmkPhia4#p4%twjSiYAS-1yT%k%; zJz!vNIRw_L0@iN9H+;|IAYGcw&2mEPXd`tg(k3pHbn<;`3O2zFF?_f;BWr}0Lu_{| zSoFc*!h{{3h$mtbEbn0Tt+0ebfW;*ei7XZ!4s5zzkY$v|?aR!{g$|5Ru%3!W^a2v` ztfPo$n#+T$CC~Tt=ZY+eI50)tJ&#iT22>$ax$1uny^3PKkw*S#pI%EsQ8D8@v0p_1YaU zuvRjp#&7*65(K^}t-q0x{r;=hN^`%zMmnl%TJty3j7!%2{$suV2L5ku;eXrYv5Eg3 z!@su;{CTSm|K1(q$9FCGw~asVkk32E*H5nu8T&Ut|AhYtmwXsZDP~5t}omGCetXI87W66@sVVyPImXDUoc-KZCKIK5>_2@695uur8a^) z{J^>E>PM6OkSIavgTXZ?lu0%oPgt|a|aTZLv zdmGp4K7<=+Me(gv)&v4r8&8DD>lM)o45#g4Zd~6Vw{h<_t@X+cA2>gv@VmY)_2->m zP(VP*F!UriZ7+_8KbY<$=~BeX@*IZ13#9Qf?5FL|HK>pK#rt&52E)&!s3B6f;p)mI zVCxl)``j}X9f^p{Z*WY$Nt-1Dan#*Z6+4bIb6hlGeYdkOZwK;0@k=$}`aBg&8RTg{ zmFXUxQ*OxyC*9Kg;~F^j-|7-<7=H@sq&xR&V%Ipo_+Ia$KXT+3&wmj~5;2}Ny3LcD zX5+F|cmyZ=>3PnmbW(r3kXCLDB8%A3`B|g=h3E*Dl|N(_k53!%9mk>L*@Fd69SQWJ zOmt7$oueCkeei1`DRn#l67jy6+KU9-JU=~cT+FeQQs8~jv|d8!MKii=cU!-hN2Ut@&Ln0gI{XLJxQt~_$Nh6fc~5@e1c@=yJ#I2g$<d|@g>a6vp%g%Io$^*bW+YoV`4=vHt8w{`t8{H><m1f%i_OWiw!vb{CT?M#cTZX!QDnPpcG?%+U9?F*w$B=$ zTf1nBb#}j=wk}UvEg0~gHk}{-z14(|8{2Hi)gjl1UG$b=iCeZArr!@w1<8x{m(SwE z?`Nkc-R?!F^^dF8CFY~PrBJ#70-|%P{x?SUsCy((oVAYH4b0Ko_l(-{Ipt<&o8dZa zG=KfvIluaHB<6N;esOgH^tRt`y?wX!j^S;cw$4u4M<9ZY`p(;(t&R7aTM3D#niH`X zR8F-RjukzndlbTpa%P6sB5lT7UN4LCb?E83QPS=`noLPKT7SXu=i)XXI=u=eY!M9!a{gLLyBd z8AbVq<4ei)II;?(oO=BuCmIW8#*=WA6z_Ac7WE_*z}&EIMVkWq-hZ&?QmECrRB9#FFw;<$@3H{u=2&XQb|=JR)v)asVbB5<(0(d zB`G%Tn{&xY%eCo(612*XRDVvAeL+cCyS^h8{sCl@oF9;bgnWu=2L{OrTc$T~1`ygp z4x(&n>0xBK*866@`B(kT-~O_8-D6MJKi*cJ%lMl{qRXh=X`)$;@&DAijLdM9;aB!j zl&a}ZJS>Ba?VX*S&5d_yV@{dH$;DRnx^@M*IP!}b#Fw`5EpF}ZcG9&7Km|$9xz4)u zOOH_~=P@vNb~5_|^41d_*W739>g8g(UB`GnDDogh1%iHGX@C7XCMRy4C{ilE&BRPu z;7NKNb!7-6S%bvV=xpT|SSW&oHZk`E(&MRPfpg-AipAkoA#i6$OeK%~U`|p?$qW|> z(hC(GQck7WTyG$Ox4x5Hh-CB9L>V7oJj*y|UOcH->?;>ZvmNr3KlLjX@q!UIOb?Qa z%tJw$SFe=Rft}mG@U(v3>xWwYt#XvGs#qb^%LNT@w(R=_iP*%kX2d5sC?%qhjHsw~ zDbwtw8jchY$TmQ^;j`2TLgR!UK2pwS={W8@G#e>Cs+DpvfA2#f^b0OB`twAj z4760y)PJHX1C|p;rf1;_hgR##Ej7e*0eX4mfSg#X39SH;xOSz?{-eAfO+i18Obg^1 zv$1%kVp&3_B$p%SVqAY7Q7^Kw{waCO>0~VS+=}8N`J}c4bKqS#b^i}cUl3pFWVkaf0GcrOeE -// 此代码由工具生成。 -// 运行时版本: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 11/23] 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 12/23] 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 13/23] remove unuse code and resources --- shadowsocks-csharp/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 KcmV+b0RR6000031 literal 104 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 xc?OPez_g2ePj - /// 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=启用代理 ///Mode=代理模式 @@ -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 14/23] 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 15/23] 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 1d21f2504df726727760bfccfab9a7e0fed2b455 Mon Sep 17 00:00:00 2001 From: sin_sin Date: Thu, 8 Jan 2015 15:10:26 +0800 Subject: [PATCH 16/23] * Remove stop event log --- shadowsocks-csharp/Controller/Local.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/shadowsocks-csharp/Controller/Local.cs b/shadowsocks-csharp/Controller/Local.cs index ba507c14..cd6d2f96 100755 --- a/shadowsocks-csharp/Controller/Local.cs +++ b/shadowsocks-csharp/Controller/Local.cs @@ -61,7 +61,6 @@ namespace Shadowsocks.Controller public void Stop() { _listener.Close(); - // Console.WriteLine("Shadowsocks stopped"); } From a984014267636d267d38a3cb416bf7f8103de8a9 Mon Sep 17 00:00:00 2001 From: Gang Zhuo Date: Thu, 8 Jan 2015 01:54:21 -0500 Subject: [PATCH 17/23] 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 18/23] 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) From 082494d587cec92bc697bd45cf2a59e98d6e9b58 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Thu, 8 Jan 2015 20:14:43 +0800 Subject: [PATCH 19/23] combine duplicated code --- shadowsocks-csharp/Data/cn.txt | 7 ++-- shadowsocks-csharp/View/MenuViewController.cs | 48 +++++++++------------------ 2 files changed, 18 insertions(+), 37 deletions(-) diff --git a/shadowsocks-csharp/Data/cn.txt b/shadowsocks-csharp/Data/cn.txt index 5dd129c0..f67af0d2 100644 --- a/shadowsocks-csharp/Data/cn.txt +++ b/shadowsocks-csharp/Data/cn.txt @@ -39,7 +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 文件成功 -Job already running...=任务已经运行... +Update PAC File via GFWList...=从 GFWList 更新 PAC 文件... +Failed to update PAC file =更新 PAC 文件失败 +PAC updated=更新 PAC 成功 diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index b7ce3f2d..1ab517f9 100755 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; +using System.IO; using System.Text; using System.Windows.Forms; @@ -33,8 +34,6 @@ namespace Shadowsocks.View private MenuItem PACModeItem; private ConfigForm configForm; - private bool isUpdatePACFromGFWListRunning = false; - public MenuViewController(ShadowsocksController controller) { this.controller = controller; @@ -181,38 +180,36 @@ namespace Shadowsocks.View System.Diagnostics.Process.Start("explorer.exe", argument); } - void controller_UpdatePACFromGFWListError(object sender, System.IO.ErrorEventArgs e) + void ShowBalloonTip(string title, string content, ToolTipIcon icon, int timeout) + { + _notifyIcon.BalloonTipTitle = title; + _notifyIcon.BalloonTipText = content; + _notifyIcon.BalloonTipIcon = icon; + _notifyIcon.ShowBalloonTip(timeout); + } + + void controller_UpdatePACFromGFWListError(object sender, 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; - _notifyIcon.ShowBalloonTip(5000); + ShowBalloonTip(I18N.GetString("Failed to update PAC file"), e.GetException().Message, ToolTipIcon.Error, 5000); Logging.LogUsefulException(e.GetException()); } 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; - _notifyIcon.ShowBalloonTip(5000); + ShowBalloonTip(I18N.GetString("Shadowsocks"), I18N.GetString("PAC updated"), ToolTipIcon.Info, 1000); } void updateChecker_NewVersionFound(object sender, EventArgs e) { - _notifyIcon.BalloonTipTitle = String.Format(I18N.GetString("Shadowsocks {0} Update Found"), updateChecker.LatestVersionNumber); - _notifyIcon.BalloonTipText = I18N.GetString("Click here to download"); - _notifyIcon.BalloonTipIcon = ToolTipIcon.Info; + ShowBalloonTip(String.Format(I18N.GetString("Shadowsocks {0} Update Found"), updateChecker.LatestVersionNumber), I18N.GetString("Click here to download"), ToolTipIcon.Info, 5000); _notifyIcon.BalloonTipClicked += notifyIcon1_BalloonTipClicked; - _notifyIcon.ShowBalloonTip(5000); _isFirstRun = false; } void notifyIcon1_BalloonTipClicked(object sender, EventArgs e) { System.Diagnostics.Process.Start(updateChecker.LatestVersionURL); + _notifyIcon.BalloonTipClicked -= notifyIcon1_BalloonTipClicked; } @@ -337,22 +334,7 @@ namespace Shadowsocks.View private void UpdatePACFromGFWListItem_Click(object sender, EventArgs e) { - if (isUpdatePACFromGFWListRunning) - { - _notifyIcon.BalloonTipTitle = I18N.GetString("Update PAC File via gfwlist..."); - _notifyIcon.BalloonTipText = I18N.GetString("Job already 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(); - } + controller.UpdatePACFromGFWList(); } private void AServerItem_Click(object sender, EventArgs e) From 6192e099704ce47296422c9cbd43ef674cec3d1e Mon Sep 17 00:00:00 2001 From: clowwindy Date: Thu, 8 Jan 2015 21:16:45 +0800 Subject: [PATCH 20/23] revert stop call --- shadowsocks-csharp/Controller/ShadowsocksController.cs | 5 ----- shadowsocks-csharp/Program.cs | 2 -- 2 files changed, 7 deletions(-) diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index 9b2b9ba3..2610bbab 100755 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -132,11 +132,6 @@ namespace Shadowsocks.Controller { polipoRunner.Stop(); } - if (pacServer != null) - { - pacServer.Stop(); - pacServer = null; - } if (_config.enabled) { SystemProxy.Disable(); diff --git a/shadowsocks-csharp/Program.cs b/shadowsocks-csharp/Program.cs index c3c0537a..716e0df7 100755 --- a/shadowsocks-csharp/Program.cs +++ b/shadowsocks-csharp/Program.cs @@ -45,8 +45,6 @@ namespace Shadowsocks controller.Start(); Application.Run(); - - controller.Stop(); } } } From a0a5cafe3d1654ba75da7e8ef8f262cdada751f7 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Thu, 8 Jan 2015 21:57:51 +0800 Subject: [PATCH 21/23] lint code --- shadowsocks-csharp/3rd/SimpleJson.cs | 6 +- shadowsocks-csharp/Controller/GfwListUpdater.cs | 94 ++++++-------- shadowsocks-csharp/Controller/PACServer.cs | 136 +-------------------- .../Controller/ShadowsocksController.cs | 25 ++-- shadowsocks-csharp/Data/abp.js.gz | Bin 4597 -> 4461 bytes shadowsocks-csharp/Data/cn.txt | 2 +- shadowsocks-csharp/Program.cs | 2 +- shadowsocks-csharp/Util/Util.cs | 22 +++- shadowsocks-csharp/View/MenuViewController.cs | 4 +- shadowsocks-csharp/shadowsocks-csharp.csproj | 2 +- 10 files changed, 84 insertions(+), 209 deletions(-) mode change 100644 => 100755 shadowsocks-csharp/Data/abp.js.gz diff --git a/shadowsocks-csharp/3rd/SimpleJson.cs b/shadowsocks-csharp/3rd/SimpleJson.cs index 2850137d..6581e84b 100644 --- a/shadowsocks-csharp/3rd/SimpleJson.cs +++ b/shadowsocks-csharp/3rd/SimpleJson.cs @@ -1035,13 +1035,13 @@ namespace SimpleJson protected static bool SerializeArray(IJsonSerializerStrategy jsonSerializerStrategy, IEnumerable anArray, StringBuilder builder) { - builder.Append("["); + builder.Append("[\r\n "); bool first = true; foreach (object value in anArray) { if (!first) - builder.Append(","); + builder.Append(",\r\n "); if (!SerializeValue(jsonSerializerStrategy, value, builder)) return false; @@ -1049,7 +1049,7 @@ namespace SimpleJson first = false; } - builder.Append("]"); + builder.Append("\r\n]"); return true; } diff --git a/shadowsocks-csharp/Controller/GfwListUpdater.cs b/shadowsocks-csharp/Controller/GfwListUpdater.cs index 2b3db383..fded3a59 100644 --- a/shadowsocks-csharp/Controller/GfwListUpdater.cs +++ b/shadowsocks-csharp/Controller/GfwListUpdater.cs @@ -3,88 +3,70 @@ using System.Collections.Generic; using System.Text; using System.Net; using System.IO; +using Shadowsocks.Properties; +using System.IO.Compression; +using System.Text.RegularExpressions; +using SimpleJson; +using Shadowsocks.Util; namespace Shadowsocks.Controller { - public class GfwListUpdater + public class GFWListUpdater { private const string GFWLIST_URL = "https://autoproxy-gfwlist.googlecode.com/svn/trunk/gfwlist.txt"; - public IWebProxy proxy = null; + private static string PAC_FILE = PACServer.PAC_FILE; - public class GfwListDownloadCompletedArgs : EventArgs - { - public string Content; - } - - public event EventHandler DownloadCompleted; + public event EventHandler UpdateCompleted; public event ErrorEventHandler Error; - public void Download() - { - WebClient http = new WebClient(); - http.Proxy = proxy; - http.DownloadStringCompleted += http_DownloadStringCompleted; - http.DownloadStringAsync(new Uri(GFWLIST_URL)); - } - - protected void ReportError(Exception e) - { - if (Error != null) - { - Error(this, new ErrorEventArgs(e)); - } - } - private void http_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { try { - string response = e.Result; - if (DownloadCompleted != null) + string[] lines = ParseResult(e.Result); + + JsonArray rules = new JsonArray(); + rules.AddRange(lines); + string abpContent = Utils.UnGzip(Resources.abp_js); + abpContent = abpContent.Replace("__RULES__", rules.ToString()); + File.WriteAllText(PAC_FILE, abpContent, Encoding.UTF8); + if (UpdateCompleted != null) { - DownloadCompleted(this, new GfwListDownloadCompletedArgs - { - Content = response - }); + UpdateCompleted(this, new EventArgs()); } } catch (Exception ex) { - ReportError(ex); + if (Error != null) + { + Error(this, new ErrorEventArgs(ex)); + } } } - public class Parser - { - private string _Content; - - public string Content - { - get { return _Content; } - } - public Parser(string response) - { - byte[] bytes = Convert.FromBase64String(response); - this._Content = Encoding.ASCII.GetString(bytes); - } + public void UpdatePACFromGFWList() + { + WebClient http = new WebClient(); + http.DownloadStringCompleted += http_DownloadStringCompleted; + http.DownloadStringAsync(new Uri(GFWLIST_URL)); + } - public string[] GetValidLines() + public string[] ParseResult(string response) + { + byte[] bytes = Convert.FromBase64String(response); + string content = Encoding.ASCII.GetString(bytes); + string[] lines = content.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + List valid_lines = new List(lines.Length); + foreach (string line in lines) { - string[] lines = Content.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); - List valid_lines = new List(lines.Length); - foreach (string line in lines) - { - if (line.StartsWith("!") || line.StartsWith("[")) - continue; - valid_lines.Add(line); - } - return valid_lines.ToArray(); + if (line.StartsWith("!") || line.StartsWith("[")) + continue; + valid_lines.Add(line); } - + return valid_lines.ToArray(); } - } } diff --git a/shadowsocks-csharp/Controller/PACServer.cs b/shadowsocks-csharp/Controller/PACServer.cs index fbd1989b..b2456e18 100755 --- a/shadowsocks-csharp/Controller/PACServer.cs +++ b/shadowsocks-csharp/Controller/PACServer.cs @@ -1,5 +1,6 @@ using Shadowsocks.Model; using Shadowsocks.Properties; +using Shadowsocks.Util; using System; using System.Collections.Generic; using System.Diagnostics; @@ -8,14 +9,13 @@ using System.IO.Compression; using System.Net; using System.Net.Sockets; using System.Text; -using System.Text.RegularExpressions; namespace Shadowsocks.Controller { class PACServer { private static int PORT = 8093; - private static string PAC_FILE = "pac.txt"; + public static string PAC_FILE = "pac.txt"; private static Configuration config; Socket _listener; @@ -23,10 +23,6 @@ namespace Shadowsocks.Controller public event EventHandler PACFileChanged; - public event EventHandler UpdatePACFromGFWListCompleted; - - public event ErrorEventHandler UpdatePACFromGFWListError; - public void Start(Configuration configuration) { try @@ -135,19 +131,7 @@ namespace Shadowsocks.Controller } else { - byte[] pacGZ = Resources.proxy_pac_txt; - byte[] buffer = new byte[1024]; // builtin pac gzip size: maximum 100K - MemoryStream sb = new MemoryStream(); - int n; - 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); - } - return System.Text.Encoding.UTF8.GetString(sb.ToArray()); - } + return Utils.UnGzip(Resources.proxy_pac_txt); } } @@ -180,7 +164,7 @@ Connection: Close ", System.Text.Encoding.UTF8.GetBytes(pac).Length) + pac; byte[] response = System.Text.Encoding.UTF8.GetBytes(text); conn.BeginSend(response, 0, response.Length, 0, new AsyncCallback(SendCallback), conn); - Util.Util.ReleaseMemory(); + Util.Utils.ReleaseMemory(); } else { @@ -247,117 +231,5 @@ Connection: Close //} return proxy; } - - 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) - { - 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, Encoding.UTF8); - if (UpdatePACFromGFWListCompleted != null) - { - UpdatePACFromGFWListCompleted(this, new EventArgs()); - } - } - - private void gfwlist_Error(object sender, ErrorEventArgs e) - { - if (UpdatePACFromGFWListError != null) - { - UpdatePACFromGFWListError(this, e); - } - } - - 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; - using (MemoryStream sb = new MemoryStream()) - { - using (GZipStream input = new GZipStream(new MemoryStream(abpGZ), - CompressionMode.Decompress, false)) - { - while ((n = input.Read(buffer, 0, buffer.Length)) > 0) - { - sb.Write(buffer, 0, n); - } - } - content = System.Text.Encoding.UTF8.GetString(sb.ToArray()); - } - return content; - } - - private static void SerializeRules(string[] rules, StringBuilder builder) - { - builder.Append("[\n"); - - bool first = true; - foreach (string rule in rules) - { - if (!first) - builder.Append(",\n"); - - SerializeString(rule, builder); - - first = 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("\""); - } - } } diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index 2610bbab..1e193158 100755 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -21,6 +21,7 @@ namespace Shadowsocks.Controller private PACServer pacServer; private Configuration _config; private PolipoRunner polipoRunner; + private GFWListUpdater gfwListUpdater; private bool stopped = false; private bool _systemProxyIsDirty = false; @@ -157,13 +158,9 @@ namespace Shadowsocks.Controller public void UpdatePACFromGFWList() { - if (pacServer != null) + if (gfwListUpdater != null) { - pacServer.UpdatePACFromGFWList(); - } - else if (UpdatePACFromGFWListError != null) - { - UpdatePACFromGFWListError(this, new ErrorEventArgs(new Exception("The PACServer is not run."))); + gfwListUpdater.UpdatePACFromGFWList(); } } @@ -180,8 +177,12 @@ namespace Shadowsocks.Controller { pacServer = new PACServer(); pacServer.PACFileChanged += pacServer_PACFileChanged; - pacServer.UpdatePACFromGFWListCompleted += pacServer_UpdatePACFromGFWListCompleted; - pacServer.UpdatePACFromGFWListError += pacServer_UpdatePACFromGFWListError; + } + if (gfwListUpdater == null) + { + gfwListUpdater = new GFWListUpdater(); + gfwListUpdater.UpdateCompleted += pacServer_PACUpdateCompleted; + gfwListUpdater.Error += pacServer_PACUpdateError; } pacServer.Stop(); @@ -226,7 +227,7 @@ namespace Shadowsocks.Controller } UpdateSystemProxy(); - Util.Util.ReleaseMemory(); + Util.Utils.ReleaseMemory(); } @@ -260,13 +261,13 @@ namespace Shadowsocks.Controller UpdateSystemProxy(); } - private void pacServer_UpdatePACFromGFWListCompleted(object sender, EventArgs e) + private void pacServer_PACUpdateCompleted(object sender, EventArgs e) { if (UpdatePACFromGFWListCompleted != null) UpdatePACFromGFWListCompleted(this, e); } - private void pacServer_UpdatePACFromGFWListError(object sender, ErrorEventArgs e) + private void pacServer_PACUpdateError(object sender, ErrorEventArgs e) { if (UpdatePACFromGFWListError != null) UpdatePACFromGFWListError(this, e); @@ -283,7 +284,7 @@ namespace Shadowsocks.Controller { while (true) { - Util.Util.ReleaseMemory(); + Util.Utils.ReleaseMemory(); Thread.Sleep(30 * 1000); } } diff --git a/shadowsocks-csharp/Data/abp.js.gz b/shadowsocks-csharp/Data/abp.js.gz old mode 100644 new mode 100755 index d265cfd68a7aaa331fbd0be03ca58ece548b2099..e049c0a42c42adc3f42601e8535f3c48f93daf99 GIT binary patch literal 4461 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 literal 4597 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 diff --git a/shadowsocks-csharp/Data/cn.txt b/shadowsocks-csharp/Data/cn.txt index f67af0d2..9f8c6da1 100644 --- a/shadowsocks-csharp/Data/cn.txt +++ b/shadowsocks-csharp/Data/cn.txt @@ -39,6 +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 from GFWList=从 GFWList 更新 PAC Failed to update PAC file =更新 PAC 文件失败 PAC updated=更新 PAC 成功 diff --git a/shadowsocks-csharp/Program.cs b/shadowsocks-csharp/Program.cs index 716e0df7..8ca485d7 100755 --- a/shadowsocks-csharp/Program.cs +++ b/shadowsocks-csharp/Program.cs @@ -18,7 +18,7 @@ namespace Shadowsocks [STAThread] static void Main() { - Util.Util.ReleaseMemory(); + Util.Utils.ReleaseMemory(); using (Mutex mutex = new Mutex(false, "Global\\" + "71981632-A427-497F-AB91-241CD227EC1F")) { Application.EnableVisualStyles(); diff --git a/shadowsocks-csharp/Util/Util.cs b/shadowsocks-csharp/Util/Util.cs index afb5539a..15463a3a 100755 --- a/shadowsocks-csharp/Util/Util.cs +++ b/shadowsocks-csharp/Util/Util.cs @@ -1,12 +1,14 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; +using System.IO.Compression; using System.Runtime.InteropServices; using System.Text; namespace Shadowsocks.Util { - public class Util + public class Utils { public static void ReleaseMemory() { @@ -22,6 +24,24 @@ namespace Shadowsocks.Util (UIntPtr)0xFFFFFFFF, (UIntPtr)0xFFFFFFFF); } + public static string UnGzip(byte[] buf) + { + byte[] buffer = new byte[1024]; + int n; + using (MemoryStream sb = new MemoryStream()) + { + using (GZipStream input = new GZipStream(new MemoryStream(buf), + CompressionMode.Decompress, false)) + { + while ((n = input.Read(buffer, 0, buffer.Length)) > 0) + { + sb.Write(buffer, 0, n); + } + } + return System.Text.Encoding.UTF8.GetString(sb.ToArray()); + } + } + [DllImport("kernel32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool SetProcessWorkingSetSize(IntPtr process, diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index 1ab517f9..76da6036 100755 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -141,7 +141,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)), + CreateMenuItem("Update PAC from GFWList", new EventHandler(this.UpdatePACFromGFWListItem_Click)), new MenuItem("-"), CreateMenuItem("Show QRCode...", new EventHandler(this.QRCodeItem_Click)), CreateMenuItem("Show Logs...", new EventHandler(this.ShowLogItem_Click)), @@ -265,7 +265,7 @@ namespace Shadowsocks.View void configForm_FormClosed(object sender, FormClosedEventArgs e) { configForm = null; - Util.Util.ReleaseMemory(); + Util.Utils.ReleaseMemory(); ShowFirstTimeBalloon(); } diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index 1848edd9..d14d7287 100755 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -86,7 +86,7 @@ - + From b9b9202cdef616ed964884ee3afff78d4c02046a Mon Sep 17 00:00:00 2001 From: clowwindy Date: Thu, 8 Jan 2015 22:06:12 +0800 Subject: [PATCH 22/23] lint code --- shadowsocks-csharp/Controller/GfwListUpdater.cs | 16 ++++++---------- shadowsocks-csharp/Controller/UpdateChecker.cs | 1 + shadowsocks-csharp/View/MenuViewController.cs | 3 +-- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/shadowsocks-csharp/Controller/GfwListUpdater.cs b/shadowsocks-csharp/Controller/GfwListUpdater.cs index fded3a59..7abe9445 100644 --- a/shadowsocks-csharp/Controller/GfwListUpdater.cs +++ b/shadowsocks-csharp/Controller/GfwListUpdater.cs @@ -4,8 +4,6 @@ using System.Text; using System.Net; using System.IO; using Shadowsocks.Properties; -using System.IO.Compression; -using System.Text.RegularExpressions; using SimpleJson; using Shadowsocks.Util; @@ -25,12 +23,10 @@ namespace Shadowsocks.Controller { try { - string[] lines = ParseResult(e.Result); + List lines = ParseResult(e.Result); - JsonArray rules = new JsonArray(); - rules.AddRange(lines); string abpContent = Utils.UnGzip(Resources.abp_js); - abpContent = abpContent.Replace("__RULES__", rules.ToString()); + abpContent = abpContent.Replace("__RULES__", SimpleJson.SimpleJson.SerializeObject(lines)); File.WriteAllText(PAC_FILE, abpContent, Encoding.UTF8); if (UpdateCompleted != null) { @@ -46,15 +42,15 @@ namespace Shadowsocks.Controller } } - public void UpdatePACFromGFWList() { WebClient http = new WebClient(); + http.Proxy = new WebProxy(IPAddress.Loopback.ToString(), 8123); http.DownloadStringCompleted += http_DownloadStringCompleted; http.DownloadStringAsync(new Uri(GFWLIST_URL)); } - public string[] ParseResult(string response) + public List ParseResult(string response) { byte[] bytes = Convert.FromBase64String(response); string content = Encoding.ASCII.GetString(bytes); @@ -66,7 +62,7 @@ namespace Shadowsocks.Controller continue; valid_lines.Add(line); } - return valid_lines.ToArray(); + return valid_lines; } } -} +} \ No newline at end of file diff --git a/shadowsocks-csharp/Controller/UpdateChecker.cs b/shadowsocks-csharp/Controller/UpdateChecker.cs index d6653468..7996a687 100755 --- a/shadowsocks-csharp/Controller/UpdateChecker.cs +++ b/shadowsocks-csharp/Controller/UpdateChecker.cs @@ -23,6 +23,7 @@ namespace Shadowsocks.Controller { // TODO test failures WebClient http = new WebClient(); + http.Proxy = new WebProxy(IPAddress.Loopback.ToString(), 8123); http.DownloadStringCompleted += http_DownloadStringCompleted; http.DownloadStringAsync(new Uri(UpdateURL)); } diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index 76da6036..3d875f3e 100755 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; -using System.IO; using System.Text; using System.Windows.Forms; @@ -188,7 +187,7 @@ namespace Shadowsocks.View _notifyIcon.ShowBalloonTip(timeout); } - void controller_UpdatePACFromGFWListError(object sender, ErrorEventArgs e) + void controller_UpdatePACFromGFWListError(object sender, System.IO.ErrorEventArgs e) { ShowBalloonTip(I18N.GetString("Failed to update PAC file"), e.GetException().Message, ToolTipIcon.Error, 5000); Logging.LogUsefulException(e.GetException()); From 797bd863aa4033f9d093a404991bd860a9f4abae Mon Sep 17 00:00:00 2001 From: clowwindy Date: Fri, 9 Jan 2015 07:59:45 +0800 Subject: [PATCH 23/23] add develop section --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 3304cffc..05c1dfd0 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,10 @@ about the change automatically 6. Please disable other proxy addons in your browser, or set them to use system proxy +### Develop + +Visual Studio Express 2012 is recommended. + #### License GPLv3