aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Networking
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Networking')
-rw-r--r--MediaBrowser.Networking/Management/NativeMethods.cs72
-rw-r--r--MediaBrowser.Networking/Management/NetworkManager.cs265
-rw-r--r--MediaBrowser.Networking/Management/NetworkShares.cs638
-rw-r--r--MediaBrowser.Networking/MediaBrowser.Networking.csproj14
4 files changed, 989 insertions, 0 deletions
diff --git a/MediaBrowser.Networking/Management/NativeMethods.cs b/MediaBrowser.Networking/Management/NativeMethods.cs
new file mode 100644
index 000000000..9a888fab2
--- /dev/null
+++ b/MediaBrowser.Networking/Management/NativeMethods.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security;
+
+namespace MediaBrowser.Networking.Management
+{
+ /// <summary>
+ /// Class NativeMethods
+ /// </summary>
+ [SuppressUnmanagedCodeSecurity]
+ public static class NativeMethods
+ {
+ //declare the Netapi32 : NetServerEnum method import
+ /// <summary>
+ /// Nets the server enum.
+ /// </summary>
+ /// <param name="ServerName">Name of the server.</param>
+ /// <param name="dwLevel">The dw level.</param>
+ /// <param name="pBuf">The p buf.</param>
+ /// <param name="dwPrefMaxLen">The dw pref max len.</param>
+ /// <param name="dwEntriesRead">The dw entries read.</param>
+ /// <param name="dwTotalEntries">The dw total entries.</param>
+ /// <param name="dwServerType">Type of the dw server.</param>
+ /// <param name="domain">The domain.</param>
+ /// <param name="dwResumeHandle">The dw resume handle.</param>
+ /// <returns>System.Int32.</returns>
+ [DllImport("Netapi32", CharSet = CharSet.Auto, SetLastError = true),
+ SuppressUnmanagedCodeSecurityAttribute]
+
+ public static extern int NetServerEnum(
+ string ServerName, // must be null
+ int dwLevel,
+ ref IntPtr pBuf,
+ int dwPrefMaxLen,
+ out int dwEntriesRead,
+ out int dwTotalEntries,
+ int dwServerType,
+ string domain, // null for login domain
+ out int dwResumeHandle
+ );
+
+ //declare the Netapi32 : NetApiBufferFree method import
+ /// <summary>
+ /// Nets the API buffer free.
+ /// </summary>
+ /// <param name="pBuf">The p buf.</param>
+ /// <returns>System.Int32.</returns>
+ [DllImport("Netapi32", SetLastError = true),
+ SuppressUnmanagedCodeSecurityAttribute]
+
+ public static extern int NetApiBufferFree(
+ IntPtr pBuf);
+ }
+
+ //create a _SERVER_INFO_100 STRUCTURE
+ /// <summary>
+ /// Struct _SERVER_INFO_100
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential)]
+ public struct _SERVER_INFO_100
+ {
+ /// <summary>
+ /// The sv100_platform_id
+ /// </summary>
+ internal int sv100_platform_id;
+ /// <summary>
+ /// The sv100_name
+ /// </summary>
+ [MarshalAs(UnmanagedType.LPWStr)]
+ internal string sv100_name;
+ }
+}
diff --git a/MediaBrowser.Networking/Management/NetworkManager.cs b/MediaBrowser.Networking/Management/NetworkManager.cs
new file mode 100644
index 000000000..fcead43d3
--- /dev/null
+++ b/MediaBrowser.Networking/Management/NetworkManager.cs
@@ -0,0 +1,265 @@
+using MediaBrowser.Common.Net;
+using MediaBrowser.Model.Net;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Management;
+using System.Net;
+using System.Net.Sockets;
+using System.Runtime.InteropServices;
+
+namespace MediaBrowser.Networking.Management
+{
+ /// <summary>
+ /// Class NetUtils
+ /// </summary>
+ public class NetworkManager : INetworkManager
+ {
+ /// <summary>
+ /// Gets the machine's local ip address
+ /// </summary>
+ /// <returns>IPAddress.</returns>
+ public string GetLocalIpAddress()
+ {
+ var host = Dns.GetHostEntry(Dns.GetHostName());
+
+ var ip = host.AddressList.FirstOrDefault(i => i.AddressFamily == AddressFamily.InterNetwork);
+
+ if (ip == null)
+ {
+ return null;
+ }
+
+ return ip.ToString();
+ }
+
+ /// <summary>
+ /// Gets a random port number that is currently available
+ /// </summary>
+ /// <returns>System.Int32.</returns>
+ public int GetRandomUnusedPort()
+ {
+ var listener = new TcpListener(IPAddress.Any, 0);
+ listener.Start();
+ var port = ((IPEndPoint)listener.LocalEndpoint).Port;
+ listener.Stop();
+ return port;
+ }
+
+ /// <summary>
+ /// Creates the netsh URL registration.
+ /// </summary>
+ public void AuthorizeHttpListening(string url)
+ {
+ var startInfo = new ProcessStartInfo
+ {
+ FileName = "netsh",
+ Arguments = string.Format("http add urlacl url={0} user=\"NT AUTHORITY\\Authenticated Users\"", url),
+ CreateNoWindow = true,
+ WindowStyle = ProcessWindowStyle.Hidden,
+ Verb = "runas",
+ ErrorDialog = false
+ };
+
+ using (var process = Process.Start(startInfo))
+ {
+ process.WaitForExit();
+ }
+ }
+
+ /// <summary>
+ /// Adds the windows firewall rule.
+ /// </summary>
+ /// <param name="port">The port.</param>
+ /// <param name="protocol">The protocol.</param>
+ public void AddSystemFirewallRule(int port, NetworkProtocol protocol)
+ {
+ // First try to remove it so we don't end up creating duplicates
+ RemoveSystemFirewallRule(port, protocol);
+
+ var args = string.Format("advfirewall firewall add rule name=\"Port {0}\" dir=in action=allow protocol={1} localport={0}", port, protocol);
+
+ RunNetsh(args);
+ }
+
+ /// <summary>
+ /// Removes the windows firewall rule.
+ /// </summary>
+ /// <param name="port">The port.</param>
+ /// <param name="protocol">The protocol.</param>
+ public void RemoveSystemFirewallRule(int port, NetworkProtocol protocol)
+ {
+ var args = string.Format("advfirewall firewall delete rule name=\"Port {0}\" protocol={1} localport={0}", port, protocol);
+
+ RunNetsh(args);
+ }
+
+ /// <summary>
+ /// Runs the netsh.
+ /// </summary>
+ /// <param name="args">The args.</param>
+ private void RunNetsh(string args)
+ {
+ var startInfo = new ProcessStartInfo
+ {
+ FileName = "netsh",
+ Arguments = args,
+ CreateNoWindow = true,
+ WindowStyle = ProcessWindowStyle.Hidden,
+ Verb = "runas",
+ ErrorDialog = false
+ };
+
+ using (var process = new Process { StartInfo = startInfo })
+ {
+ process.Start();
+ process.WaitForExit();
+ }
+ }
+
+ /// <summary>
+ /// Returns MAC Address from first Network Card in Computer
+ /// </summary>
+ /// <returns>[string] MAC Address</returns>
+ public string GetMacAddress()
+ {
+ var mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
+ var moc = mc.GetInstances();
+ var macAddress = String.Empty;
+ foreach (ManagementObject mo in moc)
+ {
+ if (macAddress == String.Empty) // only return MAC Address from first card
+ {
+ try
+ {
+ if ((bool)mo["IPEnabled"]) macAddress = mo["MacAddress"].ToString();
+ }
+ catch
+ {
+ mo.Dispose();
+ return "";
+ }
+ }
+ mo.Dispose();
+ }
+
+ return macAddress.Replace(":", "");
+ }
+
+ /// <summary>
+ /// Uses the DllImport : NetServerEnum with all its required parameters
+ /// (see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netmgmt/netmgmt/netserverenum.asp
+ /// for full details or method signature) to retrieve a list of domain SV_TYPE_WORKSTATION
+ /// and SV_TYPE_SERVER PC's
+ /// </summary>
+ /// <returns>Arraylist that represents all the SV_TYPE_WORKSTATION and SV_TYPE_SERVER
+ /// PC's in the Domain</returns>
+ public IEnumerable<string> GetNetworkDevices()
+ {
+ //local fields
+ const int MAX_PREFERRED_LENGTH = -1;
+ var SV_TYPE_WORKSTATION = 1;
+ var SV_TYPE_SERVER = 2;
+ var buffer = IntPtr.Zero;
+ var tmpBuffer = IntPtr.Zero;
+ var entriesRead = 0;
+ var totalEntries = 0;
+ var resHandle = 0;
+ var sizeofINFO = Marshal.SizeOf(typeof(_SERVER_INFO_100));
+
+ try
+ {
+ //call the DllImport : NetServerEnum with all its required parameters
+ //see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netmgmt/netmgmt/netserverenum.asp
+ //for full details of method signature
+ var ret = NativeMethods.NetServerEnum(null, 100, ref buffer, MAX_PREFERRED_LENGTH, out entriesRead, out totalEntries, SV_TYPE_WORKSTATION | SV_TYPE_SERVER, null, out resHandle);
+
+ //if the returned with a NERR_Success (C++ term), =0 for C#
+ if (ret == 0)
+ {
+ //loop through all SV_TYPE_WORKSTATION and SV_TYPE_SERVER PC's
+ for (var i = 0; i < totalEntries; i++)
+ {
+ //get pointer to, Pointer to the buffer that received the data from
+ //the call to NetServerEnum. Must ensure to use correct size of
+ //STRUCTURE to ensure correct location in memory is pointed to
+ tmpBuffer = new IntPtr((int)buffer + (i * sizeofINFO));
+ //Have now got a pointer to the list of SV_TYPE_WORKSTATION and
+ //SV_TYPE_SERVER PC's, which is unmanaged memory
+ //Needs to Marshal data from an unmanaged block of memory to a
+ //managed object, again using STRUCTURE to ensure the correct data
+ //is marshalled
+ var svrInfo = (_SERVER_INFO_100)Marshal.PtrToStructure(tmpBuffer, typeof(_SERVER_INFO_100));
+
+ //add the PC names to the ArrayList
+ if (!string.IsNullOrEmpty(svrInfo.sv100_name))
+ {
+ yield return svrInfo.sv100_name;
+ }
+ }
+ }
+ }
+ finally
+ {
+ //The NetApiBufferFree function frees
+ //the memory that the NetApiBufferAllocate function allocates
+ NativeMethods.NetApiBufferFree(buffer);
+ }
+ }
+
+
+ /// <summary>
+ /// Gets the network shares.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>IEnumerable{NetworkShare}.</returns>
+ public IEnumerable<NetworkShare> GetNetworkShares(string path)
+ {
+ return new ShareCollection(path).OfType<Share>().Select(ToNetworkShare);
+ }
+
+ /// <summary>
+ /// To the network share.
+ /// </summary>
+ /// <param name="share">The share.</param>
+ /// <returns>NetworkShare.</returns>
+ private NetworkShare ToNetworkShare(Share share)
+ {
+ return new NetworkShare
+ {
+ Name = share.NetName,
+ Path = share.Path,
+ Remark = share.Remark,
+ Server = share.Server,
+ ShareType = ToNetworkShareType(share.ShareType)
+ };
+ }
+
+ /// <summary>
+ /// To the type of the network share.
+ /// </summary>
+ /// <param name="shareType">Type of the share.</param>
+ /// <returns>NetworkShareType.</returns>
+ /// <exception cref="System.ArgumentException">Unknown share type</exception>
+ private NetworkShareType ToNetworkShareType(ShareType shareType)
+ {
+ switch (shareType)
+ {
+ case ShareType.Device:
+ return NetworkShareType.Device;
+ case ShareType.Disk :
+ return NetworkShareType.Disk;
+ case ShareType.IPC :
+ return NetworkShareType.Ipc;
+ case ShareType.Printer :
+ return NetworkShareType.Printer;
+ case ShareType.Special:
+ return NetworkShareType.Special;
+ default:
+ throw new ArgumentException("Unknown share type");
+ }
+ }
+ }
+
+}
diff --git a/MediaBrowser.Networking/Management/NetworkShares.cs b/MediaBrowser.Networking/Management/NetworkShares.cs
new file mode 100644
index 000000000..0239ddead
--- /dev/null
+++ b/MediaBrowser.Networking/Management/NetworkShares.cs
@@ -0,0 +1,638 @@
+using System;
+using System.IO;
+using System.Collections;
+using System.Runtime.InteropServices;
+
+namespace MediaBrowser.Networking.Management
+{
+ /// <summary>
+ /// Type of share
+ /// </summary>
+ [Flags]
+ public enum ShareType
+ {
+ /// <summary>Disk share</summary>
+ Disk = 0,
+ /// <summary>Printer share</summary>
+ Printer = 1,
+ /// <summary>Device share</summary>
+ Device = 2,
+ /// <summary>IPC share</summary>
+ IPC = 3,
+ /// <summary>Special share</summary>
+ Special = -2147483648, // 0x80000000,
+ }
+
+ #region Share
+
+ /// <summary>
+ /// Information about a local share
+ /// </summary>
+ public class Share
+ {
+ #region Private data
+
+ private string _server;
+ private string _netName;
+ private string _path;
+ private ShareType _shareType;
+ private string _remark;
+
+ #endregion
+
+ #region Constructor
+
+ /// <summary>
+ /// Constructor
+ /// </summary>
+ /// <param name="Server"></param>
+ /// <param name="shi"></param>
+ public Share(string server, string netName, string path, ShareType shareType, string remark)
+ {
+ if (ShareType.Special == shareType && "IPC$" == netName)
+ {
+ shareType |= ShareType.IPC;
+ }
+
+ _server = server;
+ _netName = netName;
+ _path = path;
+ _shareType = shareType;
+ _remark = remark;
+ }
+
+ #endregion
+
+ #region Properties
+
+ /// <summary>
+ /// The name of the computer that this share belongs to
+ /// </summary>
+ public string Server
+ {
+ get { return _server; }
+ }
+
+ /// <summary>
+ /// Share name
+ /// </summary>
+ public string NetName
+ {
+ get { return _netName; }
+ }
+
+ /// <summary>
+ /// Local path
+ /// </summary>
+ public string Path
+ {
+ get { return _path; }
+ }
+
+ /// <summary>
+ /// Share type
+ /// </summary>
+ public ShareType ShareType
+ {
+ get { return _shareType; }
+ }
+
+ /// <summary>
+ /// Comment
+ /// </summary>
+ public string Remark
+ {
+ get { return _remark; }
+ }
+
+ /// <summary>
+ /// Returns true if this is a file system share
+ /// </summary>
+ public bool IsFileSystem
+ {
+ get
+ {
+ // Shared device
+ if (0 != (_shareType & ShareType.Device)) return false;
+ // IPC share
+ if (0 != (_shareType & ShareType.IPC)) return false;
+ // Shared printer
+ if (0 != (_shareType & ShareType.Printer)) return false;
+
+ // Standard disk share
+ if (0 == (_shareType & ShareType.Special)) return true;
+
+ // Special disk share (e.g. C$)
+ return ShareType.Special == _shareType && !string.IsNullOrEmpty(_netName);
+ }
+ }
+
+ /// <summary>
+ /// Get the root of a disk-based share
+ /// </summary>
+ public DirectoryInfo Root
+ {
+ get
+ {
+ if (IsFileSystem)
+ {
+ if (string.IsNullOrEmpty(_server))
+ if (string.IsNullOrEmpty(_path))
+ return new DirectoryInfo(ToString());
+ else
+ return new DirectoryInfo(_path);
+ return new DirectoryInfo(ToString());
+ }
+ return null;
+ }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Returns the path to this share
+ /// </summary>
+ /// <returns></returns>
+ public override string ToString()
+ {
+ if (string.IsNullOrEmpty(_server))
+ {
+ return string.Format(@"\\{0}\{1}", Environment.MachineName, _netName);
+ }
+ return string.Format(@"\\{0}\{1}", _server, _netName);
+ }
+
+ /// <summary>
+ /// Returns true if this share matches the local path
+ /// </summary>
+ /// <param name="path"></param>
+ /// <returns></returns>
+ public bool MatchesPath(string path)
+ {
+ if (!IsFileSystem) return false;
+ if (string.IsNullOrEmpty(path)) return true;
+
+ return path.ToLower().StartsWith(_path.ToLower());
+ }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// A collection of shares
+ /// </summary>
+ public class ShareCollection : ReadOnlyCollectionBase
+ {
+ #region Platform
+
+ /// <summary>
+ /// Is this an NT platform?
+ /// </summary>
+ protected static bool IsNT
+ {
+ get { return (PlatformID.Win32NT == Environment.OSVersion.Platform); }
+ }
+
+ /// <summary>
+ /// Returns true if this is Windows 2000 or higher
+ /// </summary>
+ protected static bool IsW2KUp
+ {
+ get
+ {
+ OperatingSystem os = Environment.OSVersion;
+ if (PlatformID.Win32NT == os.Platform && os.Version.Major >= 5)
+ return true;
+ else
+ return false;
+ }
+ }
+
+ #endregion
+
+ #region Interop
+
+ #region Constants
+
+ /// <summary>Maximum path length</summary>
+ protected const int MAX_PATH = 260;
+ /// <summary>No error</summary>
+ protected const int NO_ERROR = 0;
+ /// <summary>Access denied</summary>
+ protected const int ERROR_ACCESS_DENIED = 5;
+ /// <summary>Access denied</summary>
+ protected const int ERROR_WRONG_LEVEL = 124;
+ /// <summary>More data available</summary>
+ protected const int ERROR_MORE_DATA = 234;
+ /// <summary>Not connected</summary>
+ protected const int ERROR_NOT_CONNECTED = 2250;
+ /// <summary>Level 1</summary>
+ protected const int UNIVERSAL_NAME_INFO_LEVEL = 1;
+ /// <summary>Max extries (9x)</summary>
+ protected const int MAX_SI50_ENTRIES = 20;
+
+ #endregion
+
+ #region Structures
+
+ /// <summary>Unc name</summary>
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ protected struct UNIVERSAL_NAME_INFO
+ {
+ [MarshalAs(UnmanagedType.LPTStr)]
+ public string lpUniversalName;
+ }
+
+ /// <summary>Share information, NT, level 2</summary>
+ /// <remarks>
+ /// Requires admin rights to work.
+ /// </remarks>
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ protected struct SHARE_INFO_2
+ {
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string NetName;
+ public ShareType ShareType;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string Remark;
+ public int Permissions;
+ public int MaxUsers;
+ public int CurrentUsers;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string Path;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string Password;
+ }
+
+ /// <summary>Share information, NT, level 1</summary>
+ /// <remarks>
+ /// Fallback when no admin rights.
+ /// </remarks>
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ protected struct SHARE_INFO_1
+ {
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string NetName;
+ public ShareType ShareType;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string Remark;
+ }
+
+ /// <summary>Share information, Win9x</summary>
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
+ protected struct SHARE_INFO_50
+ {
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 13)]
+ public string NetName;
+
+ public byte bShareType;
+ public ushort Flags;
+
+ [MarshalAs(UnmanagedType.LPTStr)]
+ public string Remark;
+ [MarshalAs(UnmanagedType.LPTStr)]
+ public string Path;
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
+ public string PasswordRW;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
+ public string PasswordRO;
+
+ public ShareType ShareType
+ {
+ get { return (ShareType)((int)bShareType & 0x7F); }
+ }
+ }
+
+ /// <summary>Share information level 1, Win9x</summary>
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
+ protected struct SHARE_INFO_1_9x
+ {
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 13)]
+ public string NetName;
+ public byte Padding;
+
+ public ushort bShareType;
+
+ [MarshalAs(UnmanagedType.LPTStr)]
+ public string Remark;
+
+ public ShareType ShareType
+ {
+ get { return (ShareType)((int)bShareType & 0x7FFF); }
+ }
+ }
+
+ #endregion
+
+ #region Functions
+
+ /// <summary>Get a UNC name</summary>
+ [DllImport("mpr", CharSet = CharSet.Auto)]
+ protected static extern int WNetGetUniversalName(string lpLocalPath,
+ int dwInfoLevel, ref UNIVERSAL_NAME_INFO lpBuffer, ref int lpBufferSize);
+
+ /// <summary>Get a UNC name</summary>
+ [DllImport("mpr", CharSet = CharSet.Auto)]
+ protected static extern int WNetGetUniversalName(string lpLocalPath,
+ int dwInfoLevel, IntPtr lpBuffer, ref int lpBufferSize);
+
+ /// <summary>Enumerate shares (NT)</summary>
+ [DllImport("netapi32", CharSet = CharSet.Unicode)]
+ protected static extern int NetShareEnum(string lpServerName, int dwLevel,
+ out IntPtr lpBuffer, int dwPrefMaxLen, out int entriesRead,
+ out int totalEntries, ref int hResume);
+
+ /// <summary>Enumerate shares (9x)</summary>
+ [DllImport("svrapi", CharSet = CharSet.Ansi)]
+ protected static extern int NetShareEnum(
+ [MarshalAs(UnmanagedType.LPTStr)] string lpServerName, int dwLevel,
+ IntPtr lpBuffer, ushort cbBuffer, out ushort entriesRead,
+ out ushort totalEntries);
+
+ /// <summary>Free the buffer (NT)</summary>
+ [DllImport("netapi32")]
+ protected static extern int NetApiBufferFree(IntPtr lpBuffer);
+
+ #endregion
+
+ #region Enumerate shares
+
+ /// <summary>
+ /// Enumerates the shares on Windows NT
+ /// </summary>
+ /// <param name="server">The server name</param>
+ /// <param name="shares">The ShareCollection</param>
+ protected static void EnumerateSharesNT(string server, ShareCollection shares)
+ {
+ int level = 2;
+ int entriesRead, totalEntries, nRet, hResume = 0;
+ IntPtr pBuffer = IntPtr.Zero;
+
+ try
+ {
+ nRet = NetShareEnum(server, level, out pBuffer, -1,
+ out entriesRead, out totalEntries, ref hResume);
+
+ if (ERROR_ACCESS_DENIED == nRet)
+ {
+ //Need admin for level 2, drop to level 1
+ level = 1;
+ nRet = NetShareEnum(server, level, out pBuffer, -1,
+ out entriesRead, out totalEntries, ref hResume);
+ }
+
+ if (NO_ERROR == nRet && entriesRead > 0)
+ {
+ Type t = (2 == level) ? typeof(SHARE_INFO_2) : typeof(SHARE_INFO_1);
+ int offset = Marshal.SizeOf(t);
+
+ for (int i = 0, lpItem = pBuffer.ToInt32(); i < entriesRead; i++, lpItem += offset)
+ {
+ IntPtr pItem = new IntPtr(lpItem);
+ if (1 == level)
+ {
+ SHARE_INFO_1 si = (SHARE_INFO_1)Marshal.PtrToStructure(pItem, t);
+ shares.Add(si.NetName, string.Empty, si.ShareType, si.Remark);
+ }
+ else
+ {
+ SHARE_INFO_2 si = (SHARE_INFO_2)Marshal.PtrToStructure(pItem, t);
+ shares.Add(si.NetName, si.Path, si.ShareType, si.Remark);
+ }
+ }
+ }
+
+ }
+ finally
+ {
+ // Clean up buffer allocated by system
+ if (IntPtr.Zero != pBuffer)
+ NetApiBufferFree(pBuffer);
+ }
+ }
+
+ /// <summary>
+ /// Enumerates the shares on Windows 9x
+ /// </summary>
+ /// <param name="server">The server name</param>
+ /// <param name="shares">The ShareCollection</param>
+ protected static void EnumerateShares9x(string server, ShareCollection shares)
+ {
+ int level = 50;
+ int nRet = 0;
+ ushort entriesRead, totalEntries;
+
+ Type t = typeof(SHARE_INFO_50);
+ int size = Marshal.SizeOf(t);
+ ushort cbBuffer = (ushort)(MAX_SI50_ENTRIES * size);
+ //On Win9x, must allocate buffer before calling API
+ IntPtr pBuffer = Marshal.AllocHGlobal(cbBuffer);
+
+ try
+ {
+ nRet = NetShareEnum(server, level, pBuffer, cbBuffer,
+ out entriesRead, out totalEntries);
+
+ if (ERROR_WRONG_LEVEL == nRet)
+ {
+ level = 1;
+ t = typeof(SHARE_INFO_1_9x);
+ size = Marshal.SizeOf(t);
+
+ nRet = NetShareEnum(server, level, pBuffer, cbBuffer,
+ out entriesRead, out totalEntries);
+ }
+
+ if (NO_ERROR == nRet || ERROR_MORE_DATA == nRet)
+ {
+ for (int i = 0, lpItem = pBuffer.ToInt32(); i < entriesRead; i++, lpItem += size)
+ {
+ IntPtr pItem = new IntPtr(lpItem);
+
+ if (1 == level)
+ {
+ SHARE_INFO_1_9x si = (SHARE_INFO_1_9x)Marshal.PtrToStructure(pItem, t);
+ shares.Add(si.NetName, string.Empty, si.ShareType, si.Remark);
+ }
+ else
+ {
+ SHARE_INFO_50 si = (SHARE_INFO_50)Marshal.PtrToStructure(pItem, t);
+ shares.Add(si.NetName, si.Path, si.ShareType, si.Remark);
+ }
+ }
+ }
+ else
+ Console.WriteLine(nRet);
+
+ }
+ finally
+ {
+ //Clean up buffer
+ Marshal.FreeHGlobal(pBuffer);
+ }
+ }
+
+ /// <summary>
+ /// Enumerates the shares
+ /// </summary>
+ /// <param name="server">The server name</param>
+ /// <param name="shares">The ShareCollection</param>
+ protected static void EnumerateShares(string server, ShareCollection shares)
+ {
+ if (null != server && 0 != server.Length && !IsW2KUp)
+ {
+ server = server.ToUpper();
+
+ // On NT4, 9x and Me, server has to start with "\\"
+ if (!('\\' == server[0] && '\\' == server[1]))
+ server = @"\\" + server;
+ }
+
+ if (IsNT)
+ EnumerateSharesNT(server, shares);
+ else
+ EnumerateShares9x(server, shares);
+ }
+
+ #endregion
+
+ #endregion
+
+ #region Static methods
+
+ /// <summary>
+ /// Returns true if fileName is a valid local file-name of the form:
+ /// X:\, where X is a drive letter from A-Z
+ /// </summary>
+ /// <param name="fileName">The filename to check</param>
+ /// <returns></returns>
+ public static bool IsValidFilePath(string fileName)
+ {
+ if (null == fileName || 0 == fileName.Length) return false;
+
+ char drive = char.ToUpper(fileName[0]);
+ if ('A' > drive || drive > 'Z')
+ return false;
+
+ else if (Path.VolumeSeparatorChar != fileName[1])
+ return false;
+ else if (Path.DirectorySeparatorChar != fileName[2])
+ return false;
+ else
+ return true;
+ }
+
+ #endregion
+
+ /// <summary>The name of the server this collection represents</summary>
+ private string _server;
+
+ #region Constructor
+
+ /// <summary>
+ /// Default constructor - local machine
+ /// </summary>
+ public ShareCollection()
+ {
+ _server = string.Empty;
+ EnumerateShares(_server, this);
+ }
+
+ /// <summary>
+ /// Constructor
+ /// </summary>
+ /// <param name="Server"></param>
+ public ShareCollection(string server)
+ {
+ _server = server;
+ EnumerateShares(_server, this);
+ }
+
+ #endregion
+
+ #region Add
+
+ protected void Add(Share share)
+ {
+ InnerList.Add(share);
+ }
+
+ protected void Add(string netName, string path, ShareType shareType, string remark)
+ {
+ InnerList.Add(new Share(_server, netName, path, shareType, remark));
+ }
+
+ #endregion
+
+ #region Properties
+
+ /// <summary>
+ /// Returns the name of the server this collection represents
+ /// </summary>
+ public string Server
+ {
+ get { return _server; }
+ }
+
+ /// <summary>
+ /// Returns the <see cref="Share"/> at the specified index.
+ /// </summary>
+ public Share this[int index]
+ {
+ get { return (Share)InnerList[index]; }
+ }
+
+ /// <summary>
+ /// Returns the <see cref="Share"/> which matches a given local path
+ /// </summary>
+ /// <param name="path">The path to match</param>
+ public Share this[string path]
+ {
+ get
+ {
+ if (null == path || 0 == path.Length) return null;
+
+ path = Path.GetFullPath(path);
+ if (!IsValidFilePath(path)) return null;
+
+ Share match = null;
+
+ for (int i = 0; i < InnerList.Count; i++)
+ {
+ Share s = (Share)InnerList[i];
+
+ if (s.IsFileSystem && s.MatchesPath(path))
+ {
+ //Store first match
+ if (null == match)
+ match = s;
+
+ // If this has a longer path,
+ // and this is a disk share or match is a special share,
+ // then this is a better match
+ else if (match.Path.Length < s.Path.Length)
+ {
+ if (ShareType.Disk == s.ShareType || ShareType.Disk != match.ShareType)
+ match = s;
+ }
+ }
+ }
+
+ return match;
+ }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Copy this collection to an array
+ /// </summary>
+ /// <param name="array"></param>
+ /// <param name="index"></param>
+ public void CopyTo(Share[] array, int index)
+ {
+ InnerList.CopyTo(array, index);
+ }
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Networking/MediaBrowser.Networking.csproj b/MediaBrowser.Networking/MediaBrowser.Networking.csproj
index 40ec81db3..194f9e400 100644
--- a/MediaBrowser.Networking/MediaBrowser.Networking.csproj
+++ b/MediaBrowser.Networking/MediaBrowser.Networking.csproj
@@ -32,6 +32,7 @@
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
+ <Reference Include="System.Management" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
@@ -42,8 +43,21 @@
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
+ <Compile Include="Management\NativeMethods.cs" />
+ <Compile Include="Management\NetworkManager.cs" />
+ <Compile Include="Management\NetworkShares.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
+ <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
+ <Name>MediaBrowser.Common</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
+ <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
+ <Name>MediaBrowser.Model</Name>
+ </ProjectReference>
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i</PostBuildEvent>