mirror of
https://github.com/netchx/netch.git
synced 2026-03-14 17:43:18 +08:00
1113 lines
45 KiB
C#
1113 lines
45 KiB
C#
using Netch.Controllers;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.ServiceProcess;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
|
|
namespace Netch.Forms
|
|
{
|
|
public partial class MainForm : Form
|
|
{
|
|
/// <summary>
|
|
/// 当前状态
|
|
/// </summary>
|
|
public Models.State State = Models.State.Waiting;
|
|
|
|
/// <summary>
|
|
/// 主控制器
|
|
/// </summary>
|
|
public MainController MainController;
|
|
|
|
/// <summary>
|
|
/// 上一次上传的流量
|
|
/// </summary>
|
|
public long LastUploadBandwidth = 0;
|
|
|
|
/// <summary>
|
|
/// 上一次下载的流量
|
|
/// </summary>
|
|
public long LastDownloadBandwidth = 0;
|
|
|
|
/// <summary>
|
|
/// 是否第一次打开
|
|
/// </summary>
|
|
public bool IsFirstOpened = true;
|
|
|
|
public List<Button> ProfileButtons = new List<Button>();
|
|
|
|
public MainForm()
|
|
{
|
|
InitializeComponent();
|
|
VersionLabel.Text = UpdateChecker.Version;
|
|
|
|
CheckForIllegalCrossThreadCalls = false;
|
|
// MenuStrip.Renderer = new Override.ToolStripProfessionalRender();
|
|
}
|
|
|
|
private void CheckUpdate()
|
|
{
|
|
var updater = new UpdateChecker();
|
|
updater.NewVersionFound += (o, args) =>
|
|
{
|
|
NotifyIcon.ShowBalloonTip(5,
|
|
UpdateChecker.Name,
|
|
$"{Utils.i18N.Translate(@"New version available")}{Utils.i18N.Translate(@": ")}{updater.LatestVersionNumber}",
|
|
ToolTipIcon.Info);
|
|
};
|
|
updater.Check(false, false);
|
|
}
|
|
|
|
public void TestServer()
|
|
{
|
|
Parallel.ForEach(Global.Settings.Server, new ParallelOptions { MaxDegreeOfParallelism = 16 }, server =>
|
|
{
|
|
server.Test();
|
|
});
|
|
}
|
|
|
|
public void InitServer()
|
|
{
|
|
ServerComboBox.Items.Clear();
|
|
ServerComboBox.Items.AddRange(Global.Settings.Server.ToArray());
|
|
|
|
// 如果值合法,选中该位置
|
|
if (Global.Settings.ServerComboBoxSelectedIndex > 0 && Global.Settings.ServerComboBoxSelectedIndex < ServerComboBox.Items.Count)
|
|
{
|
|
ServerComboBox.SelectedIndex = Global.Settings.ServerComboBoxSelectedIndex;
|
|
}
|
|
// 如果值非法,且当前 ServerComboBox 中有元素,选择第一个位置
|
|
else if (ServerComboBox.Items.Count > 0)
|
|
{
|
|
ServerComboBox.SelectedIndex = 0;
|
|
}
|
|
|
|
// 如果当前 ServerComboBox 中没元素,不做处理
|
|
}
|
|
|
|
public void SelectLastMode()
|
|
{
|
|
// 如果值合法,选中该位置
|
|
if (Global.Settings.ModeComboBoxSelectedIndex > 0 && Global.Settings.ModeComboBoxSelectedIndex < ModeComboBox.Items.Count)
|
|
{
|
|
ModeComboBox.SelectedIndex = Global.Settings.ModeComboBoxSelectedIndex;
|
|
}
|
|
// 如果值非法,且当前 ModeComboBox 中有元素,选择第一个位置
|
|
else if (ModeComboBox.Items.Count > 0)
|
|
{
|
|
ModeComboBox.SelectedIndex = 0;
|
|
}
|
|
|
|
// 如果当前 ModeComboBox 中没元素,不做处理
|
|
}
|
|
|
|
public void InitMode()
|
|
{
|
|
ModeComboBox.Items.Clear();
|
|
Global.ModeFiles.Clear();
|
|
|
|
if (Directory.Exists("mode"))
|
|
{
|
|
foreach (var name in Directory.GetFiles("mode", "*.txt"))
|
|
{
|
|
var ok = true;
|
|
var mode = new Models.Mode();
|
|
|
|
using (var sr = new StringReader(File.ReadAllText(name)))
|
|
{
|
|
var i = 0;
|
|
string text;
|
|
|
|
while ((text = sr.ReadLine()) != null)
|
|
{
|
|
if (i == 0)
|
|
{
|
|
var splited = text.Trim().Substring(1).Split(',');
|
|
|
|
if (splited.Length == 0)
|
|
{
|
|
ok = false;
|
|
break;
|
|
}
|
|
|
|
if (splited.Length >= 1)
|
|
{
|
|
mode.Remark = splited[0].Trim();
|
|
}
|
|
|
|
if (splited.Length >= 2)
|
|
{
|
|
if (int.TryParse(splited[1], out int result))
|
|
{
|
|
mode.Type = result;
|
|
}
|
|
else
|
|
{
|
|
ok = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (splited.Length >= 3)
|
|
{
|
|
if (int.TryParse(splited[2], out int result))
|
|
{
|
|
mode.BypassChina = (result == 1);
|
|
}
|
|
else
|
|
{
|
|
ok = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!text.StartsWith("#") && !String.IsNullOrWhiteSpace(text))
|
|
{
|
|
mode.Rule.Add(text.Trim());
|
|
}
|
|
}
|
|
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (ok)
|
|
{
|
|
mode.FileName = Path.GetFileNameWithoutExtension(name);
|
|
Global.ModeFiles.Add(mode);
|
|
}
|
|
}
|
|
|
|
var array = Global.ModeFiles.ToArray();
|
|
Array.Sort(array, (a, b) => String.Compare(a.Remark, b.Remark, StringComparison.Ordinal));
|
|
|
|
ModeComboBox.Items.AddRange(array);
|
|
|
|
SelectLastMode();
|
|
}
|
|
}
|
|
|
|
public void AddMode(Models.Mode mode)
|
|
{
|
|
ModeComboBox.Items.Clear();
|
|
Global.ModeFiles.Add(mode);
|
|
var array = Global.ModeFiles.ToArray();
|
|
Array.Sort(array, (a, b) => String.Compare(a.Remark, b.Remark, StringComparison.Ordinal));
|
|
ModeComboBox.Items.AddRange(array);
|
|
|
|
SelectLastMode();
|
|
}
|
|
|
|
private void SaveConfigs()
|
|
{
|
|
Global.Settings.ServerComboBoxSelectedIndex = ServerComboBox.SelectedIndex;
|
|
if (ModeComboBox.Tag is object[] list)
|
|
{
|
|
Global.Settings.ModeComboBoxSelectedIndex = list.ToList().IndexOf(ModeComboBox.SelectedItem);
|
|
}
|
|
else
|
|
{
|
|
Global.Settings.ModeComboBoxSelectedIndex = ModeComboBox.Items.IndexOf(ModeComboBox.SelectedItem);
|
|
}
|
|
Utils.Configuration.Save();
|
|
}
|
|
|
|
private void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
|
|
{
|
|
var cbx = sender as ComboBox;
|
|
|
|
// 绘制背景颜色
|
|
e.Graphics.FillRectangle(new SolidBrush(Color.White), e.Bounds);
|
|
|
|
if (e.Index >= 0)
|
|
{
|
|
// 绘制 备注/名称 字符串
|
|
e.Graphics.DrawString(cbx.Items[e.Index].ToString(), cbx.Font, new SolidBrush(Color.Black), e.Bounds);
|
|
|
|
if (cbx.Items[e.Index] is Models.Server)
|
|
{
|
|
var item = cbx.Items[e.Index] as Models.Server;
|
|
|
|
// 计算延迟底色
|
|
SolidBrush brush;
|
|
if (item.Delay > 200)
|
|
{
|
|
// 红色
|
|
brush = new SolidBrush(Color.Red);
|
|
}
|
|
else if (item.Delay > 80)
|
|
{
|
|
// 黄色
|
|
brush = new SolidBrush(Color.Yellow);
|
|
}
|
|
else if (item.Delay >= 0)
|
|
{
|
|
// 绿色
|
|
brush = new SolidBrush(Color.FromArgb(50, 255, 56));
|
|
}
|
|
else
|
|
{
|
|
// 灰色
|
|
brush = new SolidBrush(Color.Gray);
|
|
}
|
|
|
|
// 绘制延迟底色
|
|
e.Graphics.FillRectangle(brush, ServerComboBox.Size.Width - 60, e.Bounds.Y, 60, e.Bounds.Height);
|
|
|
|
// 绘制延迟字符串
|
|
e.Graphics.DrawString(item.Delay.ToString(), cbx.Font, new SolidBrush(Color.Black), ServerComboBox.Size.Width - 58, e.Bounds.Y);
|
|
}
|
|
else if (cbx.Items[e.Index] is Models.Mode)
|
|
{
|
|
var item = cbx.Items[e.Index] as Models.Mode;
|
|
|
|
// 绘制延迟底色
|
|
e.Graphics.FillRectangle(new SolidBrush(Color.Gray), ServerComboBox.Size.Width - 60, e.Bounds.Y, 60, e.Bounds.Height);
|
|
|
|
// 绘制延迟字符串
|
|
e.Graphics.DrawString(item.Rule.Count.ToString(), cbx.Font, new SolidBrush(Color.Black), ServerComboBox.Size.Width - 58, e.Bounds.Y);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void MainForm_Load(object sender, EventArgs e)
|
|
{
|
|
// 加载配置
|
|
Utils.Configuration.Load();
|
|
|
|
// 加载服务器
|
|
InitServer();
|
|
|
|
// 加载模式
|
|
InitMode();
|
|
|
|
// 加载翻译
|
|
ServerToolStripMenuItem.Text = Utils.i18N.Translate(ServerToolStripMenuItem.Text);
|
|
ImportServersFromClipboardToolStripMenuItem.Text = Utils.i18N.Translate(ImportServersFromClipboardToolStripMenuItem.Text);
|
|
AddSocks5ServerToolStripMenuItem.Text = Utils.i18N.Translate(AddSocks5ServerToolStripMenuItem.Text);
|
|
AddShadowsocksServerToolStripMenuItem.Text = Utils.i18N.Translate(AddShadowsocksServerToolStripMenuItem.Text);
|
|
AddShadowsocksRServerToolStripMenuItem.Text = Utils.i18N.Translate(AddShadowsocksRServerToolStripMenuItem.Text);
|
|
AddVMessServerToolStripMenuItem.Text = Utils.i18N.Translate(AddVMessServerToolStripMenuItem.Text);
|
|
ModeToolStripMenuItem.Text = Utils.i18N.Translate(ModeToolStripMenuItem.Text);
|
|
CreateProcessModeToolStripMenuItem.Text = Utils.i18N.Translate(CreateProcessModeToolStripMenuItem.Text);
|
|
SubscribeToolStripMenuItem.Text = Utils.i18N.Translate(SubscribeToolStripMenuItem.Text);
|
|
ManageSubscribeLinksToolStripMenuItem.Text = Utils.i18N.Translate(ManageSubscribeLinksToolStripMenuItem.Text);
|
|
UpdateServersFromSubscribeLinksToolStripMenuItem.Text = Utils.i18N.Translate(UpdateServersFromSubscribeLinksToolStripMenuItem.Text);
|
|
OptionsToolStripMenuItem.Text = Utils.i18N.Translate(OptionsToolStripMenuItem.Text);
|
|
RestartServiceToolStripMenuItem.Text = Utils.i18N.Translate(RestartServiceToolStripMenuItem.Text);
|
|
UninstallServiceToolStripMenuItem.Text = Utils.i18N.Translate(UninstallServiceToolStripMenuItem.Text);
|
|
ReloadModesToolStripMenuItem.Text = Utils.i18N.Translate(ReloadModesToolStripMenuItem.Text);
|
|
CleanDNSCacheToolStripMenuItem.Text = Utils.i18N.Translate(CleanDNSCacheToolStripMenuItem.Text);
|
|
AboutToolStripButton.Text = Utils.i18N.Translate(AboutToolStripButton.Text);
|
|
ConfigurationGroupBox.Text = Utils.i18N.Translate(ConfigurationGroupBox.Text);
|
|
ServerLabel.Text = Utils.i18N.Translate(ServerLabel.Text);
|
|
ModeLabel.Text = Utils.i18N.Translate(ModeLabel.Text);
|
|
ProfileLabel.Text = Utils.i18N.Translate(ProfileLabel.Text);
|
|
ProfileGroupBox.Text = Utils.i18N.Translate(ProfileGroupBox.Text);
|
|
SettingsButton.Text = Utils.i18N.Translate(SettingsButton.Text);
|
|
ControlButton.Text = Utils.i18N.Translate(ControlButton.Text);
|
|
UsedBandwidthLabel.Text = $@"{Utils.i18N.Translate("Used")}{Utils.i18N.Translate(": ")}0 KB";
|
|
StatusLabel.Text = $@"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Waiting for command")}";
|
|
ShowMainFormToolStripButton.Text = Utils.i18N.Translate(ShowMainFormToolStripButton.Text);
|
|
ExitToolStripButton.Text = Utils.i18N.Translate(ExitToolStripButton.Text);
|
|
|
|
InitProfile();
|
|
|
|
// 自动检测延迟
|
|
Task.Run(() =>
|
|
{
|
|
while (true)
|
|
{
|
|
if (State == Models.State.Waiting || State == Models.State.Stopped)
|
|
{
|
|
TestServer();
|
|
|
|
Thread.Sleep(10000);
|
|
}
|
|
else
|
|
{
|
|
Thread.Sleep(200);
|
|
}
|
|
}
|
|
});
|
|
|
|
// 打开软件时启动加速,产生开始按钮点击事件
|
|
if (Global.Settings.StartWhenOpened)
|
|
{
|
|
ControlButton.PerformClick();
|
|
}
|
|
|
|
// 检查更新
|
|
if (Global.Settings.CheckUpdateWhenOpened)
|
|
{
|
|
CheckUpdate();
|
|
}
|
|
}
|
|
|
|
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
|
|
{
|
|
if (e.CloseReason == CloseReason.UserClosing && State != Models.State.Terminating)
|
|
{
|
|
// 取消"关闭窗口"事件
|
|
e.Cancel = true; // 取消关闭窗体
|
|
|
|
// 如果未勾选关闭窗口时退出,隐藏至右下角托盘图标
|
|
if (!Global.Settings.ExitWhenClosed)
|
|
{
|
|
// 使关闭时窗口向右下角缩小的效果
|
|
WindowState = FormWindowState.Minimized;
|
|
NotifyIcon.Visible = true;
|
|
|
|
if (IsFirstOpened)
|
|
{
|
|
// 显示提示语
|
|
NotifyIcon.ShowBalloonTip(5,
|
|
UpdateChecker.Name,
|
|
Utils.i18N.Translate("Netch is now minimized to the notification bar, double click this icon to restore."),
|
|
ToolTipIcon.Info);
|
|
|
|
IsFirstOpened = false;
|
|
}
|
|
|
|
Hide();
|
|
}
|
|
// 如果勾选了关闭时退出,自动点击退出按钮
|
|
else
|
|
{
|
|
ExitToolStripButton.PerformClick();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ImportServersFromClipboardToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
var texts = Clipboard.GetText();
|
|
if (!String.IsNullOrWhiteSpace(texts))
|
|
{
|
|
var result = Utils.ShareLink.Parse(texts);
|
|
|
|
if (result != null)
|
|
{
|
|
Global.Settings.Server.AddRange(result);
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show(Utils.i18N.Translate("Import servers error!"), Utils.i18N.Translate("Error"), MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
|
}
|
|
|
|
InitServer();
|
|
Utils.Configuration.Save();
|
|
}
|
|
}
|
|
|
|
private void AddSocks5ServerToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
(new Server.Socks5()).Show();
|
|
Hide();
|
|
}
|
|
|
|
private void AddShadowsocksServerToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
(new Server.Shadowsocks()).Show();
|
|
Hide();
|
|
}
|
|
|
|
private void AddShadowsocksRServerToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
(new Server.ShadowsocksR()).Show();
|
|
Hide();
|
|
}
|
|
|
|
private void AddVMessServerToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
(new Server.VMess()).Show();
|
|
Hide();
|
|
}
|
|
|
|
private void CreateProcessModeToolStripButton_Click(object sender, EventArgs e)
|
|
{
|
|
(new Mode.Process()).Show();
|
|
Hide();
|
|
}
|
|
|
|
private void ManageSubscribeLinksToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
(new SubscribeForm()).Show();
|
|
Hide();
|
|
}
|
|
|
|
private void UpdateServersFromSubscribeLinksToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
if (Global.Settings.UseProxyToUpdateSubscription)
|
|
{
|
|
// 当前 ServerComboBox 中至少有一项
|
|
if (ServerComboBox.SelectedIndex == -1)
|
|
{
|
|
MessageBox.Show(Utils.i18N.Translate("Please select a server first"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
return;
|
|
}
|
|
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ControlButton.Enabled = SettingsButton.Enabled = false;
|
|
ControlButton.Text = "...";
|
|
}
|
|
|
|
if (Global.Settings.SubscribeLink.Count > 0)
|
|
{
|
|
DeletePictureBox.Enabled = false;
|
|
|
|
UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled = false;
|
|
Task.Run(() =>
|
|
{
|
|
if (Global.Settings.UseProxyToUpdateSubscription)
|
|
{
|
|
var mode = new Models.Mode()
|
|
{
|
|
Remark = "ProxyUpdate",
|
|
Type = 5
|
|
};
|
|
MainController = new MainController();
|
|
MainController.Start(ServerComboBox.SelectedItem as Models.Server, mode);
|
|
}
|
|
foreach (var item in Global.Settings.SubscribeLink)
|
|
{
|
|
using var client = new Override.WebClient();
|
|
try
|
|
{
|
|
if (!String.IsNullOrEmpty(item.UserAgent))
|
|
{
|
|
client.Headers.Add("User-Agent", item.UserAgent);
|
|
}
|
|
else
|
|
{
|
|
client.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36");
|
|
}
|
|
|
|
if (Global.Settings.UseProxyToUpdateSubscription)
|
|
{
|
|
client.Proxy = new System.Net.WebProxy($"http://127.0.0.1:{Global.Settings.HTTPLocalPort}");
|
|
}
|
|
|
|
var response = client.DownloadString(item.Link);
|
|
|
|
try
|
|
{
|
|
response = Utils.ShareLink.URLSafeBase64Decode(response);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// 跳过
|
|
}
|
|
|
|
Global.Settings.Server = Global.Settings.Server.Where(server => server.Group != item.Remark).ToList();
|
|
var result = Utils.ShareLink.Parse(response);
|
|
|
|
if (result != null)
|
|
{
|
|
foreach (var x in result)
|
|
{
|
|
x.Group = item.Remark;
|
|
}
|
|
Global.Settings.Server.AddRange(result);
|
|
NotifyIcon.ShowBalloonTip(5,
|
|
UpdateChecker.Name,
|
|
string.Format(Utils.i18N.Translate("Update {1} server(s) from {0}"), item.Remark, result.Count),
|
|
ToolTipIcon.Info);
|
|
}
|
|
else
|
|
{
|
|
NotifyIcon.ShowBalloonTip(5,
|
|
UpdateChecker.Name,
|
|
string.Format(Utils.i18N.Translate("Update servers error from {0}"), item.Remark),
|
|
ToolTipIcon.Error);
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
InitServer();
|
|
DeletePictureBox.Enabled = true;
|
|
if (Global.Settings.UseProxyToUpdateSubscription)
|
|
{
|
|
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ControlButton.Enabled = SettingsButton.Enabled = true;
|
|
ControlButton.Text = Utils.i18N.Translate("Start");
|
|
MainController.Stop();
|
|
}
|
|
Utils.Configuration.Save();
|
|
}).ContinueWith(task =>
|
|
{
|
|
BeginInvoke(new Action(() =>
|
|
{
|
|
UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled = true;
|
|
}));
|
|
});
|
|
|
|
NotifyIcon.ShowBalloonTip(5,
|
|
UpdateChecker.Name,
|
|
Utils.i18N.Translate("Updating in the background"),
|
|
ToolTipIcon.Info);
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show(Utils.i18N.Translate("No subscription link"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
}
|
|
|
|
private void RestartServiceToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
Enabled = false;
|
|
StatusLabel.Text = $"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Restarting service")}";
|
|
|
|
Task.Run(() =>
|
|
{
|
|
try
|
|
{
|
|
var service = new ServiceController("netfilter2");
|
|
if (service.Status == ServiceControllerStatus.Stopped)
|
|
{
|
|
service.Start();
|
|
service.WaitForStatus(ServiceControllerStatus.Running);
|
|
}
|
|
else if (service.Status == ServiceControllerStatus.Running)
|
|
{
|
|
service.Stop();
|
|
service.WaitForStatus(ServiceControllerStatus.Stopped);
|
|
service.Start();
|
|
service.WaitForStatus(ServiceControllerStatus.Running);
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
nfapinet.NFAPI.nf_registerDriver("netfilter2");
|
|
}
|
|
|
|
MessageBox.Show(this, Utils.i18N.Translate("Service has been restarted"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
Enabled = true;
|
|
});
|
|
}
|
|
|
|
private void UninstallServiceToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
Enabled = false;
|
|
StatusLabel.Text = $"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Uninstalling Service")}";
|
|
|
|
Task.Run(() =>
|
|
{
|
|
var driver = $"{Environment.SystemDirectory}\\drivers\\netfilter2.sys";
|
|
if (File.Exists(driver))
|
|
{
|
|
try
|
|
{
|
|
var service = new ServiceController("netfilter2");
|
|
if (service.Status == ServiceControllerStatus.Running)
|
|
{
|
|
service.Stop();
|
|
service.WaitForStatus(ServiceControllerStatus.Stopped);
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// 跳过
|
|
}
|
|
|
|
try
|
|
{
|
|
nfapinet.NFAPI.nf_unRegisterDriver("netfilter2");
|
|
|
|
File.Delete(driver);
|
|
|
|
MessageBox.Show(this, Utils.i18N.Translate("Service has been uninstalled"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show(this, Utils.i18N.Translate("Error") + Utils.i18N.Translate(": ") + ex.ToString(), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show(this, Utils.i18N.Translate("Service has been uninstalled"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
|
|
Enabled = true;
|
|
});
|
|
}
|
|
|
|
private void ReloadModesToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
Enabled = false;
|
|
SaveConfigs();
|
|
Task.Run(() =>
|
|
{
|
|
InitMode();
|
|
|
|
MessageBox.Show(this, Utils.i18N.Translate("Modes have been reload"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
Enabled = true;
|
|
});
|
|
}
|
|
|
|
private void CleanDNSCacheToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
Enabled = false;
|
|
Task.Run(() =>
|
|
{
|
|
Utils.DNS.Cache.Clear();
|
|
|
|
MessageBox.Show(this, Utils.i18N.Translate("DNS cache cleanup succeeded"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
StatusLabel.Text = $"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("DNS cache cleanup succeeded")}";
|
|
Enabled = true;
|
|
});
|
|
}
|
|
|
|
private void VersionLabel_Click(object sender, EventArgs e)
|
|
{
|
|
Process.Start("https://github.com/NetchX/Netch/releases");
|
|
}
|
|
|
|
private void EditPictureBox_Click(object sender, EventArgs e)
|
|
{
|
|
SaveConfigs();
|
|
// 当前ServerComboBox中至少有一项
|
|
if (ServerComboBox.SelectedIndex != -1)
|
|
{
|
|
switch (Global.Settings.Server[ServerComboBox.SelectedIndex].Type)
|
|
{
|
|
case "Socks5":
|
|
(new Server.Socks5(ServerComboBox.SelectedIndex)).Show();
|
|
break;
|
|
case "SS":
|
|
(new Server.Shadowsocks(ServerComboBox.SelectedIndex)).Show();
|
|
break;
|
|
case "SSR":
|
|
(new Server.ShadowsocksR(ServerComboBox.SelectedIndex)).Show();
|
|
break;
|
|
case "VMess":
|
|
(new Server.VMess(ServerComboBox.SelectedIndex)).Show();
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
Hide();
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show(Utils.i18N.Translate("Please select a server first"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
}
|
|
|
|
private void DeletePictureBox_Click(object sender, EventArgs e)
|
|
{
|
|
// 当前 ServerComboBox 中至少有一项
|
|
if (ServerComboBox.SelectedIndex != -1)
|
|
{
|
|
var index = ServerComboBox.SelectedIndex;
|
|
|
|
Global.Settings.Server.Remove(ServerComboBox.SelectedItem as Models.Server);
|
|
ServerComboBox.Items.RemoveAt(index);
|
|
|
|
if (ServerComboBox.Items.Count > 0)
|
|
{
|
|
ServerComboBox.SelectedIndex = (index != 0) ? index - 1 : index;
|
|
}
|
|
Utils.Configuration.Save();
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show(Utils.i18N.Translate("Please select a server first"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
}
|
|
|
|
private void SpeedPictureBox_Click(object sender, EventArgs e)
|
|
{
|
|
Enabled = false;
|
|
StatusLabel.Text = $"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Testing")}";
|
|
|
|
Task.Run(() =>
|
|
{
|
|
TestServer();
|
|
|
|
Enabled = true;
|
|
StatusLabel.Text = $"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Test done")}";
|
|
Refresh();
|
|
Utils.Configuration.Save();
|
|
});
|
|
}
|
|
|
|
private void ControlButton_Click(object sender, EventArgs e)
|
|
{
|
|
if (State == Models.State.Waiting || State == Models.State.Stopped)
|
|
{
|
|
// 当前 ServerComboBox 中至少有一项
|
|
if (ServerComboBox.SelectedIndex == -1)
|
|
{
|
|
MessageBox.Show(Utils.i18N.Translate("Please select a server first"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
return;
|
|
}
|
|
|
|
// 当前 ModeComboBox 中至少有一项
|
|
if (ModeComboBox.SelectedIndex == -1)
|
|
{
|
|
MessageBox.Show(Utils.i18N.Translate("Please select an mode first"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
return;
|
|
}
|
|
|
|
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ControlButton.Enabled = SettingsButton.Enabled = false;
|
|
ControlButton.Text = "...";
|
|
StatusLabel.Text = $"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Starting")}";
|
|
State = Models.State.Starting;
|
|
|
|
Task.Run(() =>
|
|
{
|
|
var server = ServerComboBox.SelectedItem as Models.Server;
|
|
var mode = ModeComboBox.SelectedItem as Models.Mode;
|
|
|
|
MainController = new MainController();
|
|
if (MainController.Start(server, mode))
|
|
{
|
|
// UsedBandwidthLabel.Visible = UploadSpeedLabel.Visible = DownloadSpeedLabel.Visible = true;
|
|
// MainController.pNFController.OnBandwidthUpdated += OnBandwidthUpdated;
|
|
|
|
ControlButton.Enabled = true;
|
|
ControlButton.Text = Utils.i18N.Translate("Stop");
|
|
|
|
if (mode.Type != 3 && mode.Type != 5)
|
|
{
|
|
if (server.Type != "Socks5")
|
|
{
|
|
if (Global.Settings.LocalAddress == "0.0.0.0")
|
|
{
|
|
|
|
StatusLabel.Text = $"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Started")} ({Utils.i18N.Translate("Allow other Devices to connect")} Socks5 {Utils.i18N.Translate("Local Port")}{Utils.i18N.Translate(": ")}{Global.Settings.Socks5LocalPort})";
|
|
}
|
|
else
|
|
{
|
|
StatusLabel.Text = $"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Started")} (Socks5 {Utils.i18N.Translate("Local Port")}{Utils.i18N.Translate(": ")}{Global.Settings.Socks5LocalPort}{")"}";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StatusLabel.Text = $"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Started")}";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (server.Type != "Socks5")
|
|
{
|
|
if (Global.Settings.LocalAddress == "0.0.0.0")
|
|
StatusLabel.Text = $"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Started")} ({Utils.i18N.Translate("Allow other Devices to connect")} Socks5 {Utils.i18N.Translate("Local Port")}{Utils.i18N.Translate(": ")}{Global.Settings.Socks5LocalPort} | HTTP {Utils.i18N.Translate("Local Port")}{Utils.i18N.Translate(": ")}{Global.Settings.HTTPLocalPort}{")"}";
|
|
else
|
|
{
|
|
StatusLabel.Text = $"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Started")} (Socks5 {Utils.i18N.Translate("Local Port")}{Utils.i18N.Translate(": ")}{Global.Settings.Socks5LocalPort} | HTTP {Utils.i18N.Translate("Local Port")}{Utils.i18N.Translate(": ")}{Global.Settings.HTTPLocalPort})";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Global.Settings.LocalAddress == "0.0.0.0")
|
|
StatusLabel.Text = $"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Started")} ({Utils.i18N.Translate("Allow other Devices to connect")} HTTP {Utils.i18N.Translate("Local Port")}{Utils.i18N.Translate(": ")}{Global.Settings.HTTPLocalPort}{")"}";
|
|
else
|
|
{
|
|
StatusLabel.Text = $"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Started")} (HTTP {Utils.i18N.Translate("Local Port")}{Utils.i18N.Translate(": ")}{Global.Settings.HTTPLocalPort})";
|
|
}
|
|
}
|
|
}
|
|
|
|
State = Models.State.Started;
|
|
}
|
|
else
|
|
{
|
|
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ControlButton.Enabled = SettingsButton.Enabled = true;
|
|
ControlButton.Text = Utils.i18N.Translate("Start");
|
|
StatusLabel.Text = $"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Start failed")}";
|
|
State = Models.State.Stopped;
|
|
}
|
|
});
|
|
}
|
|
else
|
|
{
|
|
ControlButton.Enabled = false;
|
|
ControlButton.Text = "...";
|
|
StatusLabel.Text = $"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Stopping")}";
|
|
State = Models.State.Stopping;
|
|
|
|
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = SettingsButton.Enabled = true;
|
|
|
|
ProfileGroupBox.Enabled = false;
|
|
|
|
Task.Run(() =>
|
|
{
|
|
var server = ServerComboBox.SelectedItem as Models.Server;
|
|
var mode = ModeComboBox.SelectedItem as Models.Mode;
|
|
|
|
MainController.Stop();
|
|
|
|
// LastUploadBandwidth = 0;
|
|
// LastDownloadBandwidth = 0;
|
|
// UploadSpeedLabel.Text = "↑: 0 KB/s";
|
|
// DownloadSpeedLabel.Text = "↓: 0 KB/s";
|
|
// UsedBandwidthLabel.Text = $"{Utils.i18N.Translate("Used")}{Utils.i18N.Translate(": ")}0 KB";
|
|
// UsedBandwidthLabel.Visible = UploadSpeedLabel.Visible = DownloadSpeedLabel.Visible = false;
|
|
|
|
ControlButton.Enabled = true;
|
|
ProfileGroupBox.Enabled = true;
|
|
|
|
ControlButton.Text = Utils.i18N.Translate("Start");
|
|
StatusLabel.Text = $"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Stopped")}";
|
|
State = Models.State.Stopped;
|
|
|
|
TestServer();
|
|
});
|
|
}
|
|
}
|
|
|
|
private void ShowMainFormToolStripButton_Click(object sender, EventArgs e)
|
|
{
|
|
if (WindowState == FormWindowState.Minimized)
|
|
{
|
|
Visible = true;
|
|
ShowInTaskbar = true; // 显示在系统任务栏
|
|
WindowState = FormWindowState.Normal; // 还原窗体
|
|
NotifyIcon.Visible = true; // 托盘图标隐藏
|
|
}
|
|
|
|
Activate();
|
|
}
|
|
|
|
private void ExitToolStripButton_Click(object sender, EventArgs e)
|
|
{
|
|
// 当前状态如果不是已停止状态
|
|
if (State != Models.State.Waiting && State != Models.State.Stopped)
|
|
{
|
|
// 如果未勾选退出时停止,要求先点击停止按钮
|
|
if (!Global.Settings.StopWhenExited)
|
|
{
|
|
MessageBox.Show(Utils.i18N.Translate("Please press Stop button first"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
|
|
Visible = true;
|
|
ShowInTaskbar = true; // 显示在系统任务栏
|
|
WindowState = FormWindowState.Normal; // 还原窗体
|
|
NotifyIcon.Visible = true; // 托盘图标隐藏
|
|
|
|
return;
|
|
}
|
|
// 否则直接调用停止按钮的方法
|
|
else
|
|
{
|
|
ControlButton_Click(sender, e);
|
|
}
|
|
}
|
|
|
|
SaveConfigs();
|
|
|
|
State = Models.State.Terminating;
|
|
NotifyIcon.Visible = false;
|
|
Close();
|
|
Dispose();
|
|
Environment.Exit(Environment.ExitCode);
|
|
}
|
|
|
|
private void NotifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
|
|
{
|
|
if (WindowState == FormWindowState.Minimized)
|
|
{
|
|
Visible = true;
|
|
ShowInTaskbar = true; //显示在系统任务栏
|
|
WindowState = FormWindowState.Normal; //还原窗体
|
|
NotifyIcon.Visible = true; //托盘图标隐藏
|
|
}
|
|
Activate();
|
|
}
|
|
|
|
private void SettingsButton_Click(object sender, EventArgs e)
|
|
{
|
|
(Global.SettingForm = new SettingForm()).Show();
|
|
Hide();
|
|
}
|
|
|
|
private void AboutToolStripButton_Click(object sender, EventArgs e)
|
|
{
|
|
(new AboutForm()).Show();
|
|
Hide();
|
|
}
|
|
|
|
public void OnBandwidthUpdated(long upload, long download)
|
|
{
|
|
UsedBandwidthLabel.Text = $"{Utils.i18N.Translate("Used")}{Utils.i18N.Translate(": ")}{Utils.Bandwidth.Compute(upload + download)}";
|
|
UploadSpeedLabel.Text = $"↑: {Utils.Bandwidth.Compute(upload - LastUploadBandwidth)}/s";
|
|
DownloadSpeedLabel.Text = $"↓: {Utils.Bandwidth.Compute(download - LastDownloadBandwidth)}/s";
|
|
|
|
LastUploadBandwidth = upload;
|
|
LastDownloadBandwidth = download;
|
|
Refresh();
|
|
}
|
|
|
|
|
|
private void ProfileButton_Click(object sender, EventArgs e)
|
|
{
|
|
int index = ProfileButtons.IndexOf((Button)sender);
|
|
|
|
//Utils.Logging.Info(String.Format("Button no.{0} clicked", index));
|
|
|
|
if (Control.ModifierKeys == Keys.Control)
|
|
{
|
|
if (ServerComboBox.SelectedIndex == -1)
|
|
{
|
|
MessageBox.Show(Utils.i18N.Translate("Please select a server first"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
return;
|
|
}
|
|
else if (ModeComboBox.SelectedIndex == -1)
|
|
{
|
|
MessageBox.Show(Utils.i18N.Translate("Please select an mode first"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
SaveProfile(index);
|
|
ProfileButtons[index].Text = ProfileNameText.Text;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
ProfileNameText.Text = LoadProfile(index);
|
|
|
|
// start the profile
|
|
bool need2ndStart = true;
|
|
if (State == Models.State.Waiting || State == Models.State.Stopped)
|
|
{
|
|
need2ndStart = false;
|
|
}
|
|
|
|
ControlButton.PerformClick();
|
|
|
|
if (need2ndStart)
|
|
{
|
|
Task.Run(() =>
|
|
{
|
|
while (State != Models.State.Stopped)
|
|
{
|
|
Thread.Sleep(200);
|
|
}
|
|
|
|
ControlButton.PerformClick();
|
|
});
|
|
}
|
|
}
|
|
catch (Exception ee)
|
|
{
|
|
Task.Run(() =>
|
|
{
|
|
Utils.Logging.Info(ee.Message);
|
|
ProfileButtons[index].Text = Utils.i18N.Translate("Error");
|
|
Thread.Sleep(1200);
|
|
ProfileButtons[index].Text = Utils.i18N.Translate("None");
|
|
});
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
public void InitProfile()
|
|
{
|
|
int num_profile = 4;
|
|
ProfileTable.ColumnCount = num_profile;
|
|
|
|
while (Global.Settings.profiles.Count < num_profile)
|
|
{
|
|
Global.Settings.profiles.Add(new Models.Profile());
|
|
}
|
|
|
|
// buttons
|
|
for (int i = 0; i < num_profile; ++i)
|
|
{
|
|
var b = new Button();
|
|
ProfileTable.Controls.Add(b, i, 0);
|
|
b.Location = new Point(i * 100, 0);
|
|
b.Click += new EventHandler(ProfileButton_Click);
|
|
b.Dock = DockStyle.Fill;
|
|
b.Text = "None";
|
|
ProfileButtons.Add(b);
|
|
|
|
if (!Global.Settings.profiles[i].IsDummy)
|
|
{
|
|
b.Text = Global.Settings.profiles[i].ProfileName;
|
|
}
|
|
else
|
|
{
|
|
b.Text = Utils.i18N.Translate(b.Text);
|
|
}
|
|
}
|
|
|
|
// equal column
|
|
this.ProfileTable.ColumnStyles.Clear();
|
|
for (int i = 1; i <= this.ProfileTable.RowCount; i++)
|
|
{
|
|
ProfileTable.RowStyles.Add(new RowStyle(SizeType.Percent, 1));
|
|
}
|
|
for (int i = 1; i <= this.ProfileTable.ColumnCount; i++)
|
|
{
|
|
ProfileTable.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 1));
|
|
}
|
|
}
|
|
|
|
private String LoadProfile(int index)
|
|
{
|
|
Models.Profile p = Global.Settings.profiles[index];
|
|
|
|
if (p.IsDummy)
|
|
throw new Exception("Profile not found.");
|
|
|
|
bool result = false;
|
|
|
|
foreach (Models.Server server in ServerComboBox.Items)
|
|
{
|
|
if (server.Remark.Equals(p.ServerRemark))
|
|
{
|
|
ServerComboBox.SelectedItem = server;
|
|
result = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!result)
|
|
throw new Exception("Server not found.");
|
|
|
|
result = false;
|
|
foreach (Models.Mode mode in ModeComboBox.Items)
|
|
{
|
|
if (mode.Remark.Equals(p.ModeRemark))
|
|
{
|
|
ModeComboBox.SelectedItem = mode;
|
|
result = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!result)
|
|
throw new Exception("Mode not found.");
|
|
|
|
return p.ProfileName;
|
|
}
|
|
|
|
private void SaveProfile(int index)
|
|
{
|
|
var selectedServer = (Models.Server)ServerComboBox.SelectedItem;
|
|
var selectedMode = (Models.Mode)ModeComboBox.SelectedItem;
|
|
String name = ProfileNameText.Text;
|
|
|
|
Global.Settings.profiles[index] = new Models.Profile(selectedServer, selectedMode, name);
|
|
|
|
}
|
|
}
|
|
}
|