Browse Source

Merge branch 'gfwlist' of https://github.com/GangZhuo/shadowsocks-csharp into GangZhuo-gfwlist

tags/3.2
clowwindy 10 years ago
parent
commit
b3e83bbe57
10 changed files with 315 additions and 8 deletions
  1. +90
    -0
      shadowsocks-csharp/Controller/GfwListUpdater.cs
  2. +118
    -1
      shadowsocks-csharp/Controller/PACServer.cs
  3. +35
    -0
      shadowsocks-csharp/Controller/ShadowsocksController.cs
  4. BIN
      shadowsocks-csharp/Data/abp.js.gz
  5. +4
    -0
      shadowsocks-csharp/Data/cn.txt
  6. +2
    -0
      shadowsocks-csharp/Program.cs
  7. +11
    -1
      shadowsocks-csharp/Properties/Resources.Designer.cs
  8. +3
    -0
      shadowsocks-csharp/Properties/Resources.resx
  9. +44
    -0
      shadowsocks-csharp/View/MenuViewController.cs
  10. +8
    -6
      shadowsocks-csharp/shadowsocks-csharp.csproj

+ 90
- 0
shadowsocks-csharp/Controller/GfwListUpdater.cs View File

@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
namespace Shadowsocks.Controller
{
public class GfwListUpdater
{
private const string GFWLIST_URL = "https://autoproxy-gfwlist.googlecode.com/svn/trunk/gfwlist.txt";
public IWebProxy proxy = null;
public class GfwListDownloadCompletedArgs : EventArgs
{
public string Content;
}
public event EventHandler<GfwListDownloadCompletedArgs> DownloadCompleted;
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)
{
DownloadCompleted(this, new GfwListDownloadCompletedArgs
{
Content = response
});
}
}
catch (Exception ex)
{
ReportError(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 string[] GetValidLines()
{
string[] lines = Content.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
List<string> valid_lines = new List<string>(lines.Length);
foreach (string line in lines)
{
if (line.StartsWith("!") || line.StartsWith("["))
continue;
valid_lines.Add(line);
}
return valid_lines.ToArray();
}
}
}
}

+ 118
- 1
shadowsocks-csharp/Controller/PACServer.cs View File

@@ -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
{
@@ -22,6 +23,10 @@ namespace Shadowsocks.Controller
public event EventHandler PACFileChanged;
public event EventHandler UpdatePACFromGFWListCompleted;
public event ErrorEventHandler UpdatePACFromGFWListError;
public void Start(Configuration configuration)
{
try
@@ -137,7 +142,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);
}
@@ -242,5 +247,117 @@ 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("\"");
}
}
}

+ 35
- 0
shadowsocks-csharp/Controller/ShadowsocksController.cs View File

@@ -38,6 +38,10 @@ namespace Shadowsocks.Controller
// when user clicked Edit PAC, and PAC file has already created
public event EventHandler<PathEventArgs> PACFileReadyToOpen;
public event EventHandler UpdatePACFromGFWListCompleted;
public event ErrorEventHandler UpdatePACFromGFWListError;
public event ErrorEventHandler Errored;
public ShadowsocksController()
@@ -128,6 +132,11 @@ namespace Shadowsocks.Controller
{
polipoRunner.Stop();
}
if (pacServer != null)
{
pacServer.Stop();
pacServer = null;
}
if (_config.enabled)
{
SystemProxy.Disable();
@@ -151,6 +160,18 @@ namespace Shadowsocks.Controller
return "ss://" + base64;
}
public void UpdatePACFromGFWList()
{
if (pacServer != null)
{
pacServer.UpdatePACFromGFWList();
}
else if (UpdatePACFromGFWListError != null)
{
UpdatePACFromGFWListError(this, new ErrorEventArgs(new Exception("The PACServer is not run.")));
}
}
protected void Reload()
{
// some logic in configuration updated the config when saving, we need to read it again
@@ -164,6 +185,8 @@ namespace Shadowsocks.Controller
{
pacServer = new PACServer();
pacServer.PACFileChanged += pacServer_PACFileChanged;
pacServer.UpdatePACFromGFWListCompleted += pacServer_UpdatePACFromGFWListCompleted;
pacServer.UpdatePACFromGFWListError += pacServer_UpdatePACFromGFWListError;
}
pacServer.Stop();
@@ -242,6 +265,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));


BIN
shadowsocks-csharp/Data/abp.js.gz View File


+ 4
- 0
shadowsocks-csharp/Data/cn.txt View File

@@ -39,3 +39,7 @@ 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...=任务已经运行...

+ 2
- 0
shadowsocks-csharp/Program.cs View File

@@ -45,6 +45,8 @@ namespace Shadowsocks
controller.Start();
Application.Run();
controller.Stop();
}
}
}


+ 11
- 1
shadowsocks-csharp/Properties/Resources.Designer.cs View File

@@ -61,6 +61,16 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] abp_js {
get {
object obj = ResourceManager.GetObject("abp_js", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized string similar to Shadowsocks=Shadowsocks
///Enable=启用代理
///Mode=代理模式
@@ -68,7 +78,7 @@ namespace Shadowsocks.Properties {
///Global=全局模式
///Servers=服务器选择
///Edit Servers...=编辑服务器...
///Start on Boot=自动启动
///Start on Boot=开机启动
///Share over LAN=在局域网共享代理
///Edit PAC File...=编辑 PAC 文件...
///Show QRCode...=显示二维码...


+ 3
- 0
shadowsocks-csharp/Properties/Resources.resx View File

@@ -118,6 +118,9 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="abp_js" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Data\abp.js.gz;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="cn" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\data\cn.txt;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>


+ 44
- 0
shadowsocks-csharp/View/MenuViewController.cs View File

@@ -33,6 +33,8 @@ namespace Shadowsocks.View
private MenuItem PACModeItem;
private ConfigForm configForm;
private bool isUpdatePACFromGFWListRunning = false;
public MenuViewController(ShadowsocksController controller)
{
this.controller = controller;
@@ -45,6 +47,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 +142,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 +181,25 @@ namespace Shadowsocks.View
System.Diagnostics.Process.Start("explorer.exe", argument);
}
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;
_notifyIcon.ShowBalloonTip(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);
}
void updateChecker_NewVersionFound(object sender, EventArgs e)
{
_notifyIcon.BalloonTipTitle = String.Format(I18N.GetString("Shadowsocks {0} Update Found"), updateChecker.LatestVersionNumber);
@@ -311,6 +335,26 @@ namespace Shadowsocks.View
controller.TouchPACFile();
}
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();
}
}
private void AServerItem_Click(object sender, EventArgs e)
{
MenuItem item = (MenuItem)sender;


+ 8
- 6
shadowsocks-csharp/shadowsocks-csharp.csproj View File

@@ -86,6 +86,7 @@
<Compile Include="3rd\zxing\Version.cs" />
<Compile Include="Controller\AutoStartup.cs" />
<Compile Include="Controller\FileManager.cs" />
<Compile Include="Controller\GfwListUpdater.cs" />
<Compile Include="Controller\I18N.cs" />
<Compile Include="Controller\Logging.cs" />
<Compile Include="Controller\UpdateChecker.cs" />
@@ -101,6 +102,11 @@
<Compile Include="Controller\PACServer.cs" />
<Compile Include="Model\Server.cs" />
<Compile Include="Model\Configuration.cs" />
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Util\Util.cs" />
<Compile Include="View\ConfigForm.cs">
<SubType>Form</SubType>
@@ -127,14 +133,9 @@
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<EmbeddedResource Include="View\QRCodeForm.resx">
<DependentUpon>QRCodeForm.cs</DependentUpon>
</EmbeddedResource>
@@ -142,6 +143,7 @@
<None Include="app.manifest">
<SubType>Designer</SubType>
</None>
<None Include="Data\abp.js.gz" />
<None Include="Data\libsscrypto.dll.gz" />
<None Include="Data\polipo.exe.gz" />
<None Include="Data\proxy.pac.txt.gz" />


Loading…
Cancel
Save