/*
* Application: HostSwitcher.exe
*
* Authors: Daniel Liedke
*
* Purpose: Quickly and easy change hosts file
*
* ------------------------------------------------------------------------------------------
* CHANGE LOG
* ------------------------------------------------------------------------------------------
* Date Author Change Details
* ------------------------------------------------------------------------------------------
* 06-15-2010 Daniel Liedke Initial version created.
*
*/
using System;
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace HostSwitcher
{
public partial class MainScreen : Form
{
#region Class Variables/Structs
private FileSystemWatcher fileWatcher;
public struct stHost
{
public string HostDescription;
public string HostComment;
public string IP;
public bool Selected;
}
#endregion
#region Initialization
public MainScreen()
{
InitializeComponent();
}
private void MainScreen_Load(object sender, EventArgs e)
{
CreateHostsFileWatcher();
BuildHostsTray();
}
private void tmrUI_Tick(object sender, EventArgs e)
{
// Hides the main screen after load
tmrUI.Enabled = false;
this.Visible = false;
}
#endregion
#region Parse Hosts and Create Host Tray
private IList<stHost> ParseHostsFile(ref bool noHosts)
{
noHosts = true;
IList<string> lineList = new List<string>();
IList<stHost> hostList = new List<stHost>();
try
{
// Reads all lines from hosts file
FileInfo fileInfo = new FileInfo(GetHostsFilename());
StreamReader sr = fileInfo.OpenText();
while (sr.EndOfStream == false)
{
string line = sr.ReadLine();
line = line.Trim();
//if (string.IsNullOrEmpty(line) == false)
{
lineList.Add(line.Replace("\t", " ").Replace("\r", " ").Replace("\n", " "));
}
}
sr.Close();
// Creates a host list
for (int f = 0; f < lineList.Count; f++)
{
// If we found an host entry with a comment in the line before, ex:
//
// # DIT - x.acme.com [host comment]
// #38.25.63.10 acme [host ip] [host address]
//
if (lineList[f].StartsWith("# ") &&
(f + 1) < lineList.Count &&
(StartWithNumberCommented(lineList[f + 1]) || StartWithNumber(lineList[f + 1])))
{
// Get host comment
string hostComment = lineList[f].Replace("# ", "");
// Retrieve host details line
string hostDetailsLine = lineList[f + 1];
// Get host IP
string hostIp = hostDetailsLine.Replace("#", "");
if (hostIp.IndexOf(" ") > -1)
{
hostIp = hostIp.Substring(0, hostIp.IndexOf(" "));
}
// Get host address
string hostAddress = string.Empty;
if ((hostDetailsLine.IndexOf(" ") > -1) && hostDetailsLine.IndexOf(" ") < hostDetailsLine.Length)
{
hostAddress = hostDetailsLine.Substring(hostDetailsLine.IndexOf(" ")).Trim();
}
// Creates the host description with comment, addresss and IP
string hostDescription = hostComment + " [" + hostAddress + " at " + hostIp + "]";
// Check if host is not commented out
bool selected = StartWithNumber(hostDetailsLine);
// Search for repeated IP entries
bool hostAlreadyExists = false;
foreach (stHost hostItemSearch in hostList)
{
if (hostItemSearch.IP == hostIp)
{
hostAlreadyExists = true;
}
}
// Make sure we don´t add repeated IP entries
// And also only entries with host IP and host address
if (hostAlreadyExists == false &&
string.IsNullOrEmpty(hostIp) == false &&
string.IsNullOrEmpty(hostAddress) == false)
{
// Create and add new host object to the list
stHost hostItem = new stHost();
hostItem.HostDescription = hostDescription;
hostItem.HostComment = hostComment;
hostItem.IP = hostIp;
hostItem.Selected = selected;
hostList.Add(hostItem);
// If we found a single selected host, no hosts menu option can´t be enabled
if (selected)
{
noHosts = false;
}
}
}
else if ((StartWithNumberCommented(lineList[f]) || StartWithNumber(lineList[f])) &&
(f - 1) >= 0 &&
lineList[f-1].StartsWith("# ")==false)
{
// Parse strings in both formats:
//
// #102.54.94.97 rhino.acme.com # Rhino server [host ip] [host address] [host comment]
//
// #10.4.2.4 www.test1234567.com [host ip] [host address]
//
// Retrieve host ip
string hostIp = lineList[f].Replace("#", "");
if (hostIp.IndexOf(" ") > -1)
{
hostIp = hostIp.Substring(0, hostIp.IndexOf(" "));
}
// Gets host address and comment
string hostFullText = string.Empty;
if (lineList[f].IndexOf(" ") > -1)
{
hostFullText = lineList[f].Substring(lineList[f].IndexOf(" ") + 1).TrimStart();
}
// Gets only host address
string hostAddress = hostFullText;
if (hostFullText.IndexOf(" ") > -1)
{
hostAddress = hostFullText.Substring(0, hostFullText.IndexOf(" ")).Trim();
}
// Gets only host comment
string hostComment = string.Empty;
if (hostFullText.IndexOf("#") > -1 && ((hostFullText.IndexOf("#") + 1) < hostFullText.Length))
{
hostComment = hostFullText.Substring(hostFullText.IndexOf("#") + 1).Trim();
}
// Creates the host description with comment, addresss and IP
string hostDescription = hostComment + " [" + hostAddress + " at " + hostIp + "]";
// Check if host is not commented out
bool selected = StartWithNumber(lineList[f]);
// Search for repeated IP entries
bool hostAlreadyExists = false;
foreach (stHost hostItemSearch in hostList)
{
if (hostItemSearch.IP == hostIp)
{
hostAlreadyExists = true;
}
}
// Make sure we don´t add repeated IP entries
// And also only entries with host IP and host address
if (hostAlreadyExists == false &&
string.IsNullOrEmpty(hostIp)==false &&
string.IsNullOrEmpty(hostAddress)==false)
{
// Create and add new host object to the list
stHost hostItem = new stHost();
hostItem.HostDescription = hostDescription;
hostItem.HostComment = hostComment;
hostItem.IP = hostIp;
hostItem.Selected = selected;
hostList.Add(hostItem);
// If we found a single selected host, no hosts menu option can´t be enabled
if (selected)
{
noHosts = false;
}
}
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error parsing hosts file: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
return hostList;
}
private void BuildHostsTray()
{
try
{
// Parse current hosts file
bool noHosts = false;
IList<stHost> hostList = ParseHostsFile(ref noHosts);
// Clear tray menu
cmsHosts.Items.Clear();
// Add default "No hosts" option
System.Windows.Forms.ToolStripMenuItem menuItemNone = new System.Windows.Forms.ToolStripMenuItem();
menuItemNone.Name = "";
menuItemNone.Text = "[No hosts]";
menuItemNone.Checked = noHosts;
menuItemNone.MouseUp += new MouseEventHandler(menuItem_MouseUp);
cmsHosts.Items.Add(menuItemNone);
// Add menu separator
System.Windows.Forms.ToolStripSeparator toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); ;
toolStripMenuItem1.Size = new System.Drawing.Size(149, 6);
cmsHosts.Items.Add(toolStripMenuItem1);
// Add all commented host entries
foreach (stHost host in hostList)
{
System.Windows.Forms.ToolStripMenuItem menuItem = new System.Windows.Forms.ToolStripMenuItem();
menuItem.Name = host.IP;
menuItem.Text = host.HostDescription;
menuItem.Tag = host.HostComment;
menuItem.Checked = host.Selected;
menuItem.MouseUp += new MouseEventHandler(menuItem_MouseUp);
cmsHosts.Items.Add(menuItem);
}
// Add menu separator
System.Windows.Forms.ToolStripSeparator toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator();
toolStripMenuItem2.Size = new System.Drawing.Size(149, 6);
cmsHosts.Items.Insert(cmsHosts.Items.Count, toolStripMenuItem2);
// Add "View Hosts File" option
System.Windows.Forms.ToolStripMenuItem viewHostsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
viewHostsToolStripMenuItem.Name = "viewHostsToolStripMenuItem";
viewHostsToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
viewHostsToolStripMenuItem.Text = "&View Hosts File";
viewHostsToolStripMenuItem.Click += new EventHandler(viewHostsToolStripMenuItem_Click);
cmsHosts.Items.Insert(cmsHosts.Items.Count, viewHostsToolStripMenuItem);
// Add menu separator
System.Windows.Forms.ToolStripSeparator toolStripMenuItem3 = new System.Windows.Forms.ToolStripSeparator();
toolStripMenuItem3.Size = new System.Drawing.Size(149, 6);
cmsHosts.Items.Insert(cmsHosts.Items.Count, toolStripMenuItem3);
// Add "Exit" application option
System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
exitToolStripMenuItem.Name = "exitToolStripMenuItem";
exitToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
exitToolStripMenuItem.Text = "&Exit";
exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click);
cmsHosts.Items.Insert(cmsHosts.Items.Count, exitToolStripMenuItem);
}
catch (Exception ex)
{
MessageBox.Show("Error creating tray menu: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
#endregion
#region Update Hosts
private void menuItem_MouseUp(object sender, MouseEventArgs e)
{
try
{
if (e.Button == MouseButtons.Left)
{
// When left clicking menu, update hosts
ToolStripMenuItem itemSelected = ((ToolStripMenuItem)(sender));
string ipHost = itemSelected.Name;
UpdateHosts(ipHost);
// Uncheck all host items
foreach (ToolStripItem item in cmsHosts.Items)
{
if (item.GetType() == typeof(ToolStripMenuItem))
{
((ToolStripMenuItem)item).Checked = false;
}
}
// Check selected host item
itemSelected.Checked = true;
}
else if (e.Button == MouseButtons.Right)
{
// When right clicking menu, copy host name
ToolStripMenuItem itemSelected = ((ToolStripMenuItem)(sender));
Clipboard.SetText(GetHostAddress(itemSelected));
}
}
catch (Exception ex)
{
MessageBox.Show("Error in tray menu mouse up: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private string GetHostAddress(ToolStripMenuItem menuItem)
{
string hostAddress = menuItem.Text;
try
{
string tag = menuItem.Tag as string;
//
// Attempts to get server name from a string like
// DIT - dit.acme.com
//
if (string.IsNullOrEmpty(tag) == false && tag.IndexOf(".") > -1)
{
int f = 0;
for (f = tag.IndexOf("."); f >= 0; f--)
{
if (tag[f] == ' ')
{
break;
}
}
hostAddress = tag.Substring(f + 1);
if (hostAddress.IndexOf(" ") > -1)
{
hostAddress = hostAddress.Substring(hostAddress.IndexOf(" ")).Trim();
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error in GetHostAddress: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
return hostAddress;
}
private void UpdateHosts(string ipHost)
{
try
{
StringBuilder sbHostsNew = new StringBuilder();
// Read hosts file
FileInfo fileInfo = new FileInfo(GetHostsFilename());
StreamReader sr = fileInfo.OpenText();
while (sr.EndOfStream == false)
{
string line = sr.ReadLine();
// Check if we found selected host commented out
if (string.IsNullOrEmpty(ipHost) == false &&
line.Contains(ipHost) &&
line.StartsWith("#" + ipHost))
{
// Uncomment selected host
line = line.Substring(1);
}
else if (((string.IsNullOrEmpty(ipHost) == false) && (line.Contains(ipHost) == false)) ||
string.IsNullOrEmpty(ipHost) == true)
{
// Comment out other entries except already uncommend host entry
if (StartWithNumber(line))
{
line = "#" + line;
}
}
sbHostsNew.Append(line + "\r\n");
}
sr.Close();
// Saves new host file and prevent file watcher from raising event
fileWatcher.EnableRaisingEvents = false;
TextWriter tw = new StreamWriter(GetHostsFilename());
tw.Write(sbHostsNew.ToString());
tw.Flush();
tw.Close();
fileWatcher.EnableRaisingEvents = true;
}
catch (Exception ex)
{
MessageBox.Show("Error updating hosts file: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
#endregion
#region Host File Watcher
private void CreateHostsFileWatcher()
{
try
{
// Make sure to monitor hosts file for changes
fileWatcher = new FileSystemWatcher();
fileWatcher = new FileSystemWatcher(GetHostsPath());
fileWatcher.Changed += new FileSystemEventHandler(fileWatcher_Changed);
fileWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
fileWatcher.EnableRaisingEvents = true;
fileWatcher.Filter = "hosts";
}
catch (Exception ex)
{
MessageBox.Show("Error monitoring hosts file: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void fileWatcher_Changed(object sender, FileSystemEventArgs e)
{
try
{
// Wait a bit for file to be saved and reload
// hosts menu when file is changed externally
//
System.Threading.Thread.Sleep(700);
if (InvokeRequired == false)
{
BuildHostsTray();
}
else
{
Invoke(new FileSystemEventHandler(fileWatcher_Changed), sender, e);
}
}
catch (Exception ex)
{
MessageBox.Show("Error monitoring hosts file: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
#endregion
#region View Hosts File
private void viewHostsToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
// Shows notepad with hosts file
ProcessStartInfo psi = new ProcessStartInfo("notepad.exe");
psi.Arguments = GetHostsFilename();
Process.Start(psi);
}
catch (Exception ex)
{
MessageBox.Show("Error showing hosts file: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
#endregion
#region Exit
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
//
// When exitting and No Hosts is not selected
// ask user if he would like to keep host configuration
// otherwise clear hosts
//
if (((ToolStripMenuItem)cmsHosts.Items[0]).Checked == false)
{
DialogResult dialogResult = MessageBox.Show("Keep current host configuration ?", "Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
if (dialogResult == DialogResult.No)
{
UpdateHosts(string.Empty);
}
}
Application.Exit();
}
catch (Exception ex)
{
MessageBox.Show("Error exitting application: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
#endregion
#region General Methods
private string GetHostsPath()
{
// Gets dynamic hosts path from system folder
string systemPath = Environment.GetFolderPath(Environment.SpecialFolder.System);
string hostsPath = Path.Combine(systemPath, @"drivers\etc");
return hostsPath;
}
private string GetHostsFilename()
{
// Creates full host filename
string hostsFileName = Path.Combine(GetHostsPath(), "hosts");
return hostsFileName;
}
private bool StartWithNumber(string str)
{
// Check if string starts with an ip number
Regex regex = new Regex(@"^\d{1}");
return regex.IsMatch(str);
}
private bool StartWithNumberCommented(string str)
{
// Check if strings starts with a commented ip number
Regex regex = new Regex(@"^#{1}\d{1}");
return regex.IsMatch(str);
}
#endregion
}
}