using System; using System.IO; using System.Net.NetworkInformation; using System.Reflection; using System.Threading; using Gtk; using MelonVPNCore; using Notify; public partial class MainWindow : Window { private Label statusLabel; private Button startBtn; private Button stopBtn; private Button refreshBtn; private ScrolledWindow clientsListScroller; private TextView clientsListText; private Thread startupCheckThread; private ThreadWrapper wrapper; private StatusIcon trayIcon; private bool ConnectedToVPN; public static readonly string MelonIconImg = "MiniMelonVPNIcon.png"; public static readonly string MelonOnlineImg = "MiniMelonVPNOnline.png"; public MainWindow() : base(WindowType.Toplevel) { Build(); Title = "Melon VPN"; UpdateIcon(MelonIconImg); SetSizeRequest(300, 300); SetDefaultSize(300, 300); SetPosition(WindowPosition.CenterAlways); Resizable = false; TypeHint = Gdk.WindowTypeHint.Dialog; ShowAll(); Present(); statusLabel = new Label { Visible = true, Text = "Loading..." }; fixed1.Put(statusLabel, 10, 10); startBtn = new Button { Visible = true, Label = "Start" }; startBtn.SetSizeRequest(80, 30); startBtn.Clicked += OnStartClicked; fixed1.Put(startBtn, 10, 40); stopBtn = new Button { Visible = true, Label = "Stop" }; stopBtn.SetSizeRequest(80, 30); stopBtn.Clicked += OnStopClicked; fixed1.Put(stopBtn, 100, 40); refreshBtn = new Button { Visible = true, Label = "Refresh" }; refreshBtn.SetSizeRequest(80, 30); refreshBtn.Clicked += OnRefreshClicked; fixed1.Put(refreshBtn, 190, 40); clientsListText = new TextView { Visible = true, Editable = false }; clientsListScroller = new ScrolledWindow { Visible = true }; clientsListScroller.SetSizeRequest(280, 200); clientsListScroller.Add(clientsListText); fixed1.Put(clientsListScroller, 10, 80); GUISocketServer.Receive += delegate (object sender, ClientResponseState s) { Console.WriteLine(s); Application.Invoke(delegate { UpdateStatus(s); }); }; GUISocketServer.ClientListUpdate += delegate (object sender, ConnectedClient[] clients) { Console.WriteLine(clients.Length); string[][] a = new string[clients.Length][]; for (int i = 0; i < clients.Length; i++) a[i] = new string[] { clients[i].name, clients[i].ip }; clientsListText.Buffer.Text = GenerateTable(a); }; wrapper = new ThreadWrapper(GUISocketServer.StartServer); startupCheckThread = new Thread(StartupCheckMethod) { IsBackground = true }; startupCheckThread.Start(); trayIcon = new StatusIcon { Visible = true, TooltipText = "Melon VPN" }; trayIcon.Activate += OnActivateTrayIcon; trayIcon.PopupMenu += OnTrayIconPopup; } private void OnActivateTrayIcon(object sender, EventArgs args) { Visible = !Visible; } private void OnTrayIconPopup(object o, PopupMenuArgs args) { Menu popupMenu = new Menu(); ImageMenuItem menuItemToggle = new ImageMenuItem(ConnectedToVPN ? "Disconnect" : "Connect"); Image toggleimg = new Image(ConnectedToVPN ? Stock.MediaPause : Stock.MediaPlay); menuItemToggle.Image = toggleimg; popupMenu.Add(menuItemToggle); menuItemToggle.Activated += OnToggleMenuItem; ImageMenuItem menuItemQuit = new ImageMenuItem("Quit"); Image appimg = new Image(Stock.Quit, IconSize.Menu); menuItemQuit.Image = appimg; popupMenu.Add(menuItemQuit); menuItemQuit.Activated += delegate { QuitApp(); }; popupMenu.ShowAll(); popupMenu.Popup(); } void OnToggleMenuItem(object sender, EventArgs args) { if (ConnectedToVPN) OnStopClicked(this, new EventArgs()); else OnStartClicked(this, new EventArgs()); } void UpdateIcon(string file) { DirectoryInfo ExeLocation = Directory.GetParent(Assembly.GetEntryAssembly().Location); string IconPath = System.IO.Path.Combine(ExeLocation.FullName, file); Console.WriteLine("Trying to update icon to: " + IconPath); if (File.Exists(IconPath)) { Icon = new Gdk.Pixbuf(IconPath); if (trayIcon != null) trayIcon.Icon = new Gdk.Pixbuf(IconPath); } } string GenerateTable(string[][] a) { if (a.Length == 0) return ""; int maxlength = a[0][0].Length; foreach (string b in a[0]) { if (b.Length > maxlength) maxlength = b.Length; } string[] c = new string[a.Length]; for (int i = 0; i < a.Length; i++) c[i] = a[i][0].PadRight(maxlength, ' ') + a[i][1]; return string.Join("\n", c); } string GetVpnInternalIp() { if (NetworkInterface.GetIsNetworkAvailable()) { foreach (NetworkInterface f in NetworkInterface.GetAllNetworkInterfaces()) { IPInterfaceProperties p = f.GetIPProperties(); IPAddressInformationCollection addressesColl = p.AnycastAddresses; foreach (IPAddressInformation ip in addressesColl) { if (ip.Address.ToString().StartsWith("10.137.248.", StringComparison.CurrentCulture)) { return ip.Address.ToString(); } } } } return ""; } void StartupCheckMethod() { ClientResponseState s = Client.SendDataMessage(DataMessage.Status); Console.WriteLine(s); Application.Invoke(delegate { UpdateStatus(s); }); } void Refresh() { ClientResponseState s = Client.SendDataMessage(DataMessage.Status); switch (s) { case ClientResponseState.Error: case ClientResponseState.ServerError: UpdateStatus(s); MessageDialog md = new MessageDialog(this, DialogFlags.DestroyWithParent, MessageType.Error, ButtonsType.Ok, "Error stopping VPN. Is the daemon running?"); md.Run(); md.Destroy(); break; case ClientResponseState.Online: case ClientResponseState.Offline: UpdateStatus(s); break; } } void UpdateStatus(ClientResponseState s) { bool oldState = ConnectedToVPN; switch (s) { case ClientResponseState.Error: statusLabel.Text = "Client Error"; ConnectedToVPN = false; break; case ClientResponseState.ServerError: statusLabel.Text = "Server Error"; ConnectedToVPN = false; break; case ClientResponseState.Blank: statusLabel.Text = "No reply"; ConnectedToVPN = false; break; case ClientResponseState.Online: statusLabel.Text = "Online - " + GetVpnInternalIp(); ConnectedToVPN = true; break; case ClientResponseState.Offline: statusLabel.Text = "Offline"; ConnectedToVPN = false; break; } if (ConnectedToVPN) UpdateIcon(MelonOnlineImg); else UpdateIcon(MelonIconImg); NotifyStateUpdate(oldState,ConnectedToVPN); } void NotifyStateUpdate(bool old, bool current) { if(old!=current) { if(current==true) { Notification pop = new Notification("Melon VPN", "Connected to the VPN"); pop.Show(); } else { Notification pop = new Notification("Melon VPN", "Disconnected from the VPN"); pop.Show(); } } } protected void OnDeleteEvent(object sender, DeleteEventArgs a) { if (ConnectedToVPN) Visible = false; else QuitApp(); a.RetVal = true; } protected void QuitApp() { if (wrapper != null) { wrapper.Kill(); wrapper.Join(); } if (trayIcon != null) trayIcon.Dispose(); Application.Quit(); } void OnStartClicked(object sender, EventArgs e) { ClientResponseState s = Client.SendDataMessage(DataMessage.Start); switch (s) { case ClientResponseState.Error: case ClientResponseState.ServerError: case ClientResponseState.Offline: UpdateStatus(s); MessageDialog md = new MessageDialog(this, DialogFlags.DestroyWithParent, MessageType.Error, ButtonsType.Ok, "Error starting VPN. Is the daemon running?"); md.Run(); md.Destroy(); break; } } void OnStopClicked(object sender, EventArgs e) { ClientResponseState s = Client.SendDataMessage(DataMessage.Stop); switch (s) { case ClientResponseState.Error: case ClientResponseState.ServerError: case ClientResponseState.Online: UpdateStatus(s); MessageDialog md = new MessageDialog(this, DialogFlags.DestroyWithParent, MessageType.Error, ButtonsType.Ok, "Error stopping VPN. Is the daemon running?"); md.Run(); md.Destroy(); break; } } void OnRefreshClicked(object sender, EventArgs e) { Refresh(); } void OnViewClientsClicked(object sender, EventArgs e) { Refresh(); } }