diff --git a/src/Umbraco.Core/Configuration/GlobalSettings.cs b/src/Umbraco.Core/Configuration/GlobalSettings.cs
new file mode 100644
index 0000000000..4d67cc78d6
--- /dev/null
+++ b/src/Umbraco.Core/Configuration/GlobalSettings.cs
@@ -0,0 +1,801 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Web;
+using System.Web.Configuration;
+using System.Xml;
+using Umbraco.Core.IO;
+
+namespace Umbraco.Core.Configuration
+{
+ //NOTE: Do not expose this class ever until we cleanup all configuration including removal of static classes, etc...
+ // we have this two tasks logged:
+ // http://issues.umbraco.org/issue/U4-58
+ // http://issues.umbraco.org/issue/U4-115
+
+ //TODO: Re-enable Logging!!!!
+
+ ///
+ /// The GlobalSettings Class contains general settings information for the entire Umbraco instance based on information from web.config appsettings
+ ///
+ internal class GlobalSettings
+ {
+ #region Private static fields
+
+ // CURRENT UMBRACO VERSION ID
+ private const string CurrentUmbracoVersion = "4.8.0";
+
+ private static string _reservedUrlsCache;
+ private static string _reservedPathsCache;
+ private static StartsWithContainer _reservedList = new StartsWithContainer();
+
+ #endregion
+
+ ///
+ /// Gets the reserved urls from web.config.
+ ///
+ /// The reserved urls.
+ public static string ReservedUrls
+ {
+ get
+ {
+ if (HttpContext.Current != null)
+ return ConfigurationManager.AppSettings["umbracoReservedUrls"];
+ return String.Empty;
+ }
+ }
+
+ ///
+ /// Gets the reserved paths from web.config
+ ///
+ /// The reserved paths.
+ public static string ReservedPaths
+ {
+ get
+ {
+ if (HttpContext.Current != null)
+ return ConfigurationManager.AppSettings["umbracoReservedPaths"];
+ return String.Empty;
+ }
+ }
+
+ ///
+ /// Gets the name of the content XML file.
+ ///
+ /// The content XML.
+ public static string ContentXml
+ {
+ get
+ {
+ try
+ {
+ return ConfigurationManager.AppSettings["umbracoContentXML"];
+ }
+ catch
+ {
+ return String.Empty;
+ }
+ }
+ }
+
+ ///
+ /// Gets the path to the storage directory (/data by default).
+ ///
+ /// The storage directory.
+ public static string StorageDirectory
+ {
+ get
+ {
+ try
+ {
+ return ConfigurationManager.AppSettings["umbracoStorageDirectory"];
+ }
+ catch
+ {
+ return String.Empty;
+ }
+ }
+ }
+
+ ///
+ /// Gets the path to umbraco's root directory (/umbraco by default).
+ ///
+ /// The path.
+ public static string Path
+ {
+ get
+ {
+
+ try
+ {
+ return IOHelper.ResolveUrl(ConfigurationManager.AppSettings["umbracoPath"]);
+ }
+ catch
+ {
+ return String.Empty;
+ }
+ }
+ }
+
+ ///
+ /// Gets the path to umbraco's client directory (/umbraco_client by default).
+ /// This is a relative path to the Umbraco Path as it always must exist beside the 'umbraco'
+ /// folder since the CSS paths to images depend on it.
+ ///
+ /// The path.
+ public static string ClientPath
+ {
+ get
+ {
+ return Path + "/../umbraco_client";
+ }
+ }
+
+ ///
+ /// Gets the database connection string
+ ///
+ /// The database connection string.
+ public static string DbDsn
+ {
+ get
+ {
+ try
+ {
+ return ConfigurationManager.AppSettings["umbracoDbDSN"];
+ }
+ catch
+ {
+ return String.Empty;
+ }
+ }
+ set
+ {
+ if (DbDsn != value)
+ {
+ SaveSetting("umbracoDbDSN", value);
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the configuration status. This will return the version number of the currently installed umbraco instance.
+ ///
+ /// The configuration status.
+ public static string ConfigurationStatus
+ {
+ get
+ {
+ try
+ {
+ return ConfigurationManager.AppSettings["umbracoConfigurationStatus"];
+ }
+ catch
+ {
+ return String.Empty;
+ }
+ }
+ set
+ {
+ SaveSetting("umbracoConfigurationStatus", value);
+ }
+ }
+
+
+ ///
+ /// Forces umbraco to be medium trust compatible
+ ///
+ /// If true, umbraco will be medium-trust compatible, no matter what Permission level the server is on.
+ public static bool UseMediumTrust
+ {
+ get
+ {
+ try
+ {
+ var trustLevel = SystemUtilities.GetCurrentTrustLevel();
+ if (trustLevel == AspNetHostingPermissionLevel.High || trustLevel == AspNetHostingPermissionLevel.Unrestricted)
+ return false;
+ else
+ return bool.Parse(ConfigurationManager.AppSettings["umbracoUseMediumTrust"]);
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+ ///
+ /// Saves a setting into the configuration file.
+ ///
+ /// Key of the setting to be saved.
+ /// Value of the setting to be saved.
+ internal static void SaveSetting(string key, string value)
+ {
+ var webConfig = new WebConfigurationFileMap();
+ var vDirs = webConfig.VirtualDirectories;
+ var vDir = FullpathToRoot;
+ foreach (VirtualDirectoryMapping v in webConfig.VirtualDirectories)
+ {
+ if (v.IsAppRoot)
+ {
+ vDir = v.PhysicalDirectory;
+ }
+ }
+
+ var doc = new XmlDocument();
+ doc.Load(String.Concat(vDir, "web.config"));
+ var root = doc.DocumentElement;
+ var setting = doc.SelectSingleNode(String.Concat("//appSettings/add[@key='", key, "']"));
+ setting.Attributes["value"].InnerText = value;
+ doc.Save(String.Concat(vDir, "web.config"));
+ ConfigurationManager.RefreshSection("appSettings");
+ }
+
+ ///
+ /// Gets the full path to root.
+ ///
+ /// The fullpath to root.
+ public static string FullpathToRoot
+ {
+ get { return HttpRuntime.AppDomainAppPath; }
+ }
+
+ ///
+ /// Gets a value indicating whether umbraco is running in [debug mode].
+ ///
+ /// true if [debug mode]; otherwise, false.
+ public static bool DebugMode
+ {
+ get
+ {
+ try
+ {
+ return bool.Parse(ConfigurationManager.AppSettings["umbracoDebugMode"]);
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether the current version of umbraco is configured.
+ ///
+ /// true if configured; otherwise, false.
+ public static bool Configured
+ {
+ get
+ {
+ try
+ {
+ string configStatus = ConfigurationStatus;
+ string currentVersion = CurrentVersion;
+
+
+ if (currentVersion != configStatus)
+ {
+ //Log.Add(LogTypes.Debug, User.GetUser(0), -1,
+ // "CurrentVersion different from configStatus: '" + currentVersion + "','" + configStatus +
+ // "'");
+ }
+
+
+ return (configStatus == currentVersion);
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+ ///
+ /// Gets the time out in minutes.
+ ///
+ /// The time out in minutes.
+ public static int TimeOutInMinutes
+ {
+ get
+ {
+ try
+ {
+ return int.Parse(ConfigurationManager.AppSettings["umbracoTimeOutInMinutes"]);
+ }
+ catch
+ {
+ return 20;
+ }
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether umbraco uses directory urls.
+ ///
+ /// true if umbraco uses directory urls; otherwise, false.
+ public static bool UseDirectoryUrls
+ {
+ get
+ {
+ try
+ {
+ return bool.Parse(ConfigurationManager.AppSettings["umbracoUseDirectoryUrls"]);
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+ ///
+ /// Returns a string value to determine if umbraco should skip version-checking.
+ ///
+ /// The version check period in days (0 = never).
+ public static int VersionCheckPeriod
+ {
+ get
+ {
+ int versionCheckPeriod = 7;
+ if (HttpContext.Current != null)
+ {
+ if (int.TryParse(ConfigurationManager.AppSettings["umbracoVersionCheckPeriod"], out versionCheckPeriod))
+ return versionCheckPeriod;
+
+ }
+ return versionCheckPeriod;
+ }
+ }
+
+ ///
+ /// Gets the URL forbitten characters.
+ ///
+ /// The URL forbitten characters.
+ public static string UrlForbittenCharacters
+ {
+ get
+ {
+ if (HttpContext.Current != null)
+ return ConfigurationManager.AppSettings["umbracoUrlForbittenCharacters"];
+ return "";
+ }
+ }
+
+ ///
+ /// Gets the URL space character.
+ ///
+ /// The URL space character.
+ public static string UrlSpaceCharacter
+ {
+ get
+ {
+ if (HttpContext.Current != null)
+ return ConfigurationManager.AppSettings["umbracoUrlSpaceCharacter"];
+ return "";
+ }
+ }
+
+ ///
+ /// Gets the SMTP server IP-address or hostname.
+ ///
+ /// The SMTP server.
+ public static string SmtpServer
+ {
+ get
+ {
+ try
+ {
+ var mailSettings = ConfigurationManager.GetSection("system.net/mailSettings") as System.Net.Configuration.MailSettingsSectionGroup;
+
+ if (mailSettings != null)
+ return mailSettings.Smtp.Network.Host;
+ else
+ return ConfigurationManager.AppSettings["umbracoSmtpServer"];
+ }
+ catch
+ {
+ return "";
+ }
+ }
+ }
+
+ ///
+ /// Returns a string value to determine if umbraco should disbable xslt extensions
+ ///
+ /// "true" if version xslt extensions are disabled, otherwise, "false"
+ public static string DisableXsltExtensions
+ {
+ get
+ {
+ if (HttpContext.Current != null)
+ return ConfigurationManager.AppSettings["umbracoDisableXsltExtensions"];
+ return "";
+ }
+ }
+
+ ///
+ /// Returns a string value to determine if umbraco should use Xhtml editing mode in the wysiwyg editor
+ ///
+ /// "true" if Xhtml mode is enable, otherwise, "false"
+ public static string EditXhtmlMode
+ {
+ get
+ {
+ if (HttpContext.Current != null)
+ return ConfigurationManager.AppSettings["umbracoEditXhtmlMode"];
+ return "";
+ }
+ }
+
+ ///
+ /// Gets the default UI language.
+ ///
+ /// The default UI language.
+ public static string DefaultUILanguage
+ {
+ get
+ {
+ if (HttpContext.Current != null)
+ return ConfigurationManager.AppSettings["umbracoDefaultUILanguage"];
+ return "";
+ }
+ }
+
+ ///
+ /// Gets the profile URL.
+ ///
+ /// The profile URL.
+ public static string ProfileUrl
+ {
+ get
+ {
+ if (HttpContext.Current != null)
+ return ConfigurationManager.AppSettings["umbracoProfileUrl"];
+ return "";
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether umbraco should hide top level nodes from generated urls.
+ ///
+ ///
+ /// true if umbraco hides top level nodes from urls; otherwise, false.
+ ///
+ public static bool HideTopLevelNodeFromPath
+ {
+ get
+ {
+ if (HttpContext.Current != null)
+ return bool.Parse(ConfigurationManager.AppSettings["umbracoHideTopLevelNodeFromPath"]);
+ return false;
+ }
+ }
+
+ ///
+ /// Gets the current version.
+ ///
+ /// The current version.
+ public static string CurrentVersion
+ {
+ get
+ {
+ // change this to be hardcoded in the binary
+ return CurrentUmbracoVersion;
+ }
+ }
+
+ ///
+ /// Gets the major version number.
+ ///
+ /// The major version number.
+ public static int VersionMajor
+ {
+ get
+ {
+ string[] version = CurrentVersion.Split(".".ToCharArray());
+ return int.Parse(version[0]);
+ }
+ }
+
+ ///
+ /// Gets the minor version number.
+ ///
+ /// The minor version number.
+ public static int VersionMinor
+ {
+ get
+ {
+ string[] version = CurrentVersion.Split(".".ToCharArray());
+ return int.Parse(version[1]);
+ }
+ }
+
+ ///
+ /// Gets the patch version number.
+ ///
+ /// The patch version number.
+ public static int VersionPatch
+ {
+ get
+ {
+ string[] version = CurrentVersion.Split(".".ToCharArray());
+ return int.Parse(version[2]);
+ }
+ }
+
+ ///
+ /// Gets the version comment (like beta or RC).
+ ///
+ /// The version comment.
+ public static string VersionComment
+ {
+ get
+ {
+ string[] version = CurrentVersion.Split(".".ToCharArray());
+ if (version.Length > 3)
+ return version[3];
+ else
+ return "";
+ }
+ }
+
+
+ ///
+ /// Requests the is in umbraco application directory structure.
+ ///
+ /// The context.
+ ///
+ public static bool RequestIsInUmbracoApplication(HttpContext context)
+ {
+ return context.Request.Path.ToLower().IndexOf(IOHelper.ResolveUrl(SystemDirectories.Umbraco).ToLower()) > -1;
+ }
+
+ public static bool RequestIsLiveEditRedirector(HttpContext context)
+ {
+ return context.Request.Path.ToLower().IndexOf(SystemDirectories.Umbraco.ToLower() + "/liveediting.aspx") > -1;
+ }
+
+ ///
+ /// Gets a value indicating whether umbraco should force a secure (https) connection to the backoffice.
+ ///
+ /// true if [use SSL]; otherwise, false.
+ public static bool UseSSL
+ {
+ get
+ {
+ try
+ {
+ return bool.Parse(ConfigurationManager.AppSettings["umbracoUseSSL"]);
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+ ///
+ /// Gets the umbraco license.
+ ///
+ /// The license.
+ public static string License
+ {
+ get
+ {
+ string license =
+ "the open source license MIT. The umbraco UI is freeware licensed under the umbraco license.";
+ if (HttpContext.Current != null)
+ {
+ var versionDoc = new XmlDocument();
+ var versionReader = new XmlTextReader(IOHelper.MapPath(SystemDirectories.Umbraco + "/version.xml"));
+ versionDoc.Load(versionReader);
+ versionReader.Close();
+
+ // check for license
+ try
+ {
+ string licenseUrl =
+ versionDoc.SelectSingleNode("/version/licensing/licenseUrl").FirstChild.Value;
+ string licenseValidation =
+ versionDoc.SelectSingleNode("/version/licensing/licenseValidation").FirstChild.Value;
+ string licensedTo =
+ versionDoc.SelectSingleNode("/version/licensing/licensedTo").FirstChild.Value;
+
+ if (licensedTo != "" && licenseUrl != "")
+ {
+ license = "umbraco Commercial License
Registered to:
" +
+ licensedTo.Replace("\n", "
") + "
For use with domain:
" +
+ licenseUrl;
+ }
+ }
+ catch
+ {
+ }
+ }
+ return license;
+ }
+ }
+
+
+ ///
+ /// Developer method to test if configuration settings are loaded properly.
+ ///
+ /// true if succesfull; otherwise, false.
+ internal static bool Test
+ {
+ get
+ {
+ try
+ {
+ HttpContext.Current.Response.Write("ContentXML :" + ContentXml + "\n");
+ HttpContext.Current.Response.Write("DbDSN :" + DbDsn + "\n");
+ HttpContext.Current.Response.Write("DebugMode :" + DebugMode + "\n");
+ HttpContext.Current.Response.Write("DefaultUILanguage :" + DefaultUILanguage + "\n");
+ HttpContext.Current.Response.Write("VersionCheckPeriod :" + VersionCheckPeriod + "\n");
+ HttpContext.Current.Response.Write("DisableXsltExtensions :" + DisableXsltExtensions + "\n");
+ HttpContext.Current.Response.Write("EditXhtmlMode :" + EditXhtmlMode + "\n");
+ HttpContext.Current.Response.Write("HideTopLevelNodeFromPath :" + HideTopLevelNodeFromPath + "\n");
+ HttpContext.Current.Response.Write("Path :" + Path + "\n");
+ HttpContext.Current.Response.Write("ProfileUrl :" + ProfileUrl + "\n");
+ HttpContext.Current.Response.Write("ReservedPaths :" + ReservedPaths + "\n");
+ HttpContext.Current.Response.Write("ReservedUrls :" + ReservedUrls + "\n");
+ HttpContext.Current.Response.Write("StorageDirectory :" + StorageDirectory + "\n");
+ HttpContext.Current.Response.Write("TimeOutInMinutes :" + TimeOutInMinutes + "\n");
+ HttpContext.Current.Response.Write("UrlForbittenCharacters :" + UrlForbittenCharacters + "\n");
+ HttpContext.Current.Response.Write("UrlSpaceCharacter :" + UrlSpaceCharacter + "\n");
+ HttpContext.Current.Response.Write("UseDirectoryUrls :" + UseDirectoryUrls + "\n");
+ return true;
+ }
+ catch
+ {
+ }
+ return false;
+ }
+ }
+
+
+ ///
+ /// Determines whether the specified URL is reserved or is inside a reserved path.
+ ///
+ /// The URL to check.
+ ///
+ /// true if the specified URL is reserved; otherwise, false.
+ ///
+ public static bool IsReservedPathOrUrl(string url)
+ {
+ // check if GlobalSettings.ReservedPaths and GlobalSettings.ReservedUrls are unchanged
+ if (!object.ReferenceEquals(_reservedPathsCache, GlobalSettings.ReservedPaths)
+ || !object.ReferenceEquals(_reservedUrlsCache, GlobalSettings.ReservedUrls))
+ {
+ // store references to strings to determine changes
+ _reservedPathsCache = GlobalSettings.ReservedPaths;
+ _reservedUrlsCache = GlobalSettings.ReservedUrls;
+
+ string _root = SystemDirectories.Root.Trim().ToLower();
+
+ // add URLs and paths to a new list
+ StartsWithContainer _newReservedList = new StartsWithContainer();
+ foreach (string reservedUrl in _reservedUrlsCache.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
+ {
+ //resolves the url to support tilde chars
+ string reservedUrlTrimmed = IOHelper.ResolveUrl(reservedUrl).Trim().ToLower();
+ if (reservedUrlTrimmed.Length > 0)
+ _newReservedList.Add(reservedUrlTrimmed);
+ }
+
+ foreach (string reservedPath in _reservedPathsCache.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
+ {
+ bool trimEnd = !reservedPath.EndsWith("/");
+ //resolves the url to support tilde chars
+ string reservedPathTrimmed = IOHelper.ResolveUrl(reservedPath).Trim().ToLower();
+
+ if (reservedPathTrimmed.Length > 0)
+ _newReservedList.Add(reservedPathTrimmed + (reservedPathTrimmed.EndsWith("/") ? "" : "/"));
+ }
+
+ // use the new list from now on
+ _reservedList = _newReservedList;
+ }
+
+ string res = "";
+ foreach (string st in _reservedList._list.Keys)
+ res += st + ",";
+
+ HttpContext.Current.Trace.Write("umbracoGlobalsettings", "reserverd urls: '" + res + "'");
+
+ // return true if url starts with an element of the reserved list
+ return _reservedList.StartsWith(url.ToLower());
+ }
+
+ ///
+ /// Structure that checks in logarithmic time
+ /// if a given string starts with one of the added keys.
+ ///
+ private class StartsWithContainer
+ {
+ /// Internal sorted list of keys.
+ public SortedList _list
+ = new SortedList(StartsWithComparator.Instance);
+
+ ///
+ /// Adds the specified new key.
+ ///
+ /// The new key.
+ public void Add(string newKey)
+ {
+ // if the list already contains an element that begins with newKey, return
+ if (String.IsNullOrEmpty(newKey) || StartsWith(newKey))
+ return;
+
+ // create a new collection, so the old one can still be accessed
+ SortedList newList
+ = new SortedList(_list.Count + 1, StartsWithComparator.Instance);
+
+ // add only keys that don't already start with newKey, others are unnecessary
+ foreach (string key in _list.Keys)
+ if (!key.StartsWith(newKey))
+ newList.Add(key, null);
+ // add the new key
+ newList.Add(newKey, null);
+
+ // update the list (thread safe, _list was never in incomplete state)
+ _list = newList;
+ }
+
+ ///
+ /// Checks if the given string starts with any of the added keys.
+ ///
+ /// The target.
+ /// true if a key is found that matches the start of target
+ ///
+ /// Runs in O(s*log(n)), with n the number of keys and s the length of target.
+ ///
+ public bool StartsWith(string target)
+ {
+ return _list.ContainsKey(target);
+ }
+
+ /// Comparator that tests if a string starts with another.
+ /// Not a real comparator, since it is not reflexive. (x==y does not imply y==x)
+ private sealed class StartsWithComparator : IComparer
+ {
+ /// Default string comparer.
+ private readonly static Comparer _stringComparer = Comparer.Default;
+
+ /// Gets an instance of the StartsWithComparator.
+ public static readonly StartsWithComparator Instance = new StartsWithComparator();
+
+ ///
+ /// Tests if whole begins with all characters of part.
+ ///
+ /// The part.
+ /// The whole.
+ ///
+ /// Returns 0 if whole starts with part, otherwise performs standard string comparison.
+ ///
+ public int Compare(string part, string whole)
+ {
+ // let the default string comparer deal with null or when part is not smaller then whole
+ if (part == null || whole == null || part.Length >= whole.Length)
+ return _stringComparer.Compare(part, whole);
+
+ // loop through all characters that part and whole have in common
+ int pos = 0;
+ bool match;
+ do
+ {
+ match = (part[pos] == whole[pos]);
+ } while (match && ++pos < part.Length);
+
+ // return result of last comparison
+ return match ? 0 : (part[pos] < whole[pos] ? -1 : 1);
+ }
+ }
+ }
+
+ }
+
+
+
+
+}
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings.cs b/src/Umbraco.Core/Configuration/UmbracoSettings.cs
new file mode 100644
index 0000000000..49a0c45dcc
--- /dev/null
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings.cs
@@ -0,0 +1,1294 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Web;
+using System.Web.Caching;
+using System.Xml;
+
+using System.Collections.Generic;
+
+
+namespace Umbraco.Core.Configuration
+{
+ //NOTE: Do not expose this class ever until we cleanup all configuration including removal of static classes, etc...
+ // we have this two tasks logged:
+ // http://issues.umbraco.org/issue/U4-58
+ // http://issues.umbraco.org/issue/U4-115
+
+ //TODO: Re-enable logging !!!!
+
+ ///
+ /// The UmbracoSettings Class contains general settings information for the entire Umbraco instance based on information from the /config/umbracoSettings.config file
+ ///
+ internal class UmbracoSettings
+ {
+ internal const string TempFriendlyXmlChildContainerNodename = ""; // "children";
+
+ ///
+ /// Gets the umbraco settings document.
+ ///
+ /// The _umbraco settings.
+ internal static XmlDocument UmbracoSettingsXmlDoc
+ {
+ get
+ {
+ var us = (XmlDocument)HttpRuntime.Cache["umbracoSettingsFile"] ?? EnsureSettingsDocument();
+ return us;
+ }
+ }
+
+ private static string _path;
+
+ ///
+ /// Gets/sets the settings file path, the setter can be used in unit tests
+ ///
+ internal static string SettingsFilePath
+ {
+ get { return _path ?? (_path = GlobalSettings.FullpathToRoot + Path.DirectorySeparatorChar + "config" + Path.DirectorySeparatorChar); }
+ set { _path = value; }
+ }
+
+ internal const string Filename = "umbracoSettings.config";
+
+ internal static XmlDocument EnsureSettingsDocument()
+ {
+ var settingsFile = HttpRuntime.Cache["umbracoSettingsFile"];
+
+ // Check for language file in cache
+ if (settingsFile == null)
+ {
+ var temp = new XmlDocument();
+ var settingsReader = new XmlTextReader(SettingsFilePath + Filename);
+ try
+ {
+ temp.Load(settingsReader);
+ HttpRuntime.Cache.Insert("umbracoSettingsFile", temp,
+ new CacheDependency(SettingsFilePath + Filename));
+ }
+ catch (XmlException e)
+ {
+ throw new XmlException("Your umbracoSettings.config file fails to pass as valid XML. Refer to the InnerException for more information", e);
+ }
+ catch (Exception e)
+ {
+ //Log.Add(LogTypes.Error, new User(0), -1, "Error reading umbracoSettings file: " + e.ToString());
+ }
+ settingsReader.Close();
+ return temp;
+ }
+ else
+ return (XmlDocument)settingsFile;
+ }
+
+ internal static void Save()
+ {
+ UmbracoSettingsXmlDoc.Save(SettingsFilePath + Filename);
+ }
+
+
+ ///
+ /// Selects a xml node in the umbraco settings config file.
+ ///
+ /// The xpath query to the specific node.
+ /// If found, it returns the specific configuration xml node.
+ public static XmlNode GetKeyAsNode(string key)
+ {
+ if (key == null)
+ throw new ArgumentException("Key cannot be null");
+ EnsureSettingsDocument();
+ if (UmbracoSettingsXmlDoc == null || UmbracoSettingsXmlDoc.DocumentElement == null)
+ return null;
+ return UmbracoSettingsXmlDoc.DocumentElement.SelectSingleNode(key);
+ }
+
+ ///
+ /// Gets the value of configuration xml node with the specified key.
+ ///
+ /// The key.
+ ///
+ public static string GetKey(string key)
+ {
+ EnsureSettingsDocument();
+
+ var node = UmbracoSettingsXmlDoc.DocumentElement.SelectSingleNode(key);
+ if (node == null || node.FirstChild == null || node.FirstChild.Value == null)
+ return string.Empty;
+ return node.FirstChild.Value;
+ }
+
+ ///
+ /// Gets a value indicating whether the media library will create new directories in the /media directory.
+ ///
+ ///
+ /// true if new directories are allowed otherwise, false.
+ ///
+ public static bool UploadAllowDirectories
+ {
+ get { return bool.Parse(GetKey("/settings/content/UploadAllowDirectories")); }
+ }
+
+ ///
+ /// Gets a value indicating whether logging is enabled in umbracoSettings.config (/settings/logging/enableLogging).
+ ///
+ /// true if logging is enabled; otherwise, false.
+ public static bool EnableLogging
+ {
+ get
+ {
+ // We return true if no enable logging element is present in
+ // umbracoSettings (to enable default behaviour when upgrading)
+ var enableLogging = GetKey("/settings/logging/enableLogging");
+ return String.IsNullOrEmpty(enableLogging) || bool.Parse(enableLogging);
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether logging happens async.
+ ///
+ /// true if async logging is enabled; otherwise, false.
+ public static bool EnableAsyncLogging
+ {
+ get
+ {
+ string value = GetKey("/settings/logging/enableAsyncLogging");
+ bool result;
+ if (!string.IsNullOrEmpty(value) && bool.TryParse(value, out result))
+ return result;
+ return false;
+ }
+ }
+
+ ///
+ /// Gets the assembly of an external logger that can be used to store log items in 3rd party systems
+ ///
+ public static string ExternalLoggerAssembly
+ {
+ get
+ {
+ var value = GetKeyAsNode("/settings/logging/externalLogger");
+ return value != null ? value.Attributes["assembly"].Value : "";
+ }
+ }
+ ///
+ /// Gets the type of an external logger that can be used to store log items in 3rd party systems
+ ///
+ public static string ExternalLoggerType
+ {
+ get
+ {
+ var value = GetKeyAsNode("/settings/logging/externalLogger");
+ return value != null ? value.Attributes["type"].Value : "";
+ }
+ }
+
+ ///
+ /// Long Audit Trail to external log too
+ ///
+ public static bool ExternalLoggerLogAuditTrail
+ {
+ get
+ {
+ var value = GetKeyAsNode("/settings/logging/externalLogger");
+ if (value != null)
+ {
+ var logAuditTrail = value.Attributes["logAuditTrail"].Value;
+ bool result;
+ if (!string.IsNullOrEmpty(logAuditTrail) && bool.TryParse(logAuditTrail, out result))
+ return result;
+ }
+ return false;
+ }
+ }
+
+ ///
+ /// Keep user alive as long as they have their browser open? Default is true
+ ///
+ public static bool KeepUserLoggedIn
+ {
+ get
+ {
+ var value = GetKey("/settings/security/keepUserLoggedIn");
+ bool result;
+ if (!string.IsNullOrEmpty(value) && bool.TryParse(value, out result))
+ return result;
+ return true;
+ }
+ }
+
+ ///
+ /// Show disabled users in the tree in the Users section in the backoffice
+ ///
+ public static bool HideDisabledUsersInBackoffice
+ {
+ get
+ {
+ string value = GetKey("/settings/security/hideDisabledUsersInBackoffice");
+ bool result;
+ if (!string.IsNullOrEmpty(value) && bool.TryParse(value, out result))
+ return result;
+ return false;
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether the logs will be auto cleaned
+ ///
+ /// true if logs are to be automatically cleaned; otherwise, false
+ public static bool AutoCleanLogs
+ {
+ get
+ {
+ string value = GetKey("/settings/logging/autoCleanLogs");
+ bool result;
+ if (!string.IsNullOrEmpty(value) && bool.TryParse(value, out result))
+ return result;
+ return false;
+ }
+ }
+
+ ///
+ /// Gets the value indicating the log cleaning frequency (in miliseconds)
+ ///
+ public static int CleaningMiliseconds
+ {
+ get
+ {
+ string value = GetKey("/settings/logging/cleaningMiliseconds");
+ int result;
+ if (!string.IsNullOrEmpty(value) && int.TryParse(value, out result))
+ return result;
+ return -1;
+ }
+ }
+
+ public static int MaxLogAge
+ {
+ get
+ {
+ string value = GetKey("/settings/logging/maxLogAge");
+ int result;
+ if (!string.IsNullOrEmpty(value) && int.TryParse(value, out result))
+ return result;
+ return -1;
+ }
+ }
+
+ ///
+ /// Gets the disabled log types.
+ ///
+ /// The disabled log types.
+ public static XmlNode DisabledLogTypes
+ {
+ get { return GetKeyAsNode("/settings/logging/disabledLogTypes"); }
+ }
+
+ ///
+ /// Gets the package server url.
+ ///
+ /// The package server url.
+ public static string PackageServer
+ {
+ get { return "packages.umbraco.org"; }
+ }
+
+ ///
+ /// Gets a value indicating whether umbraco will use domain prefixes.
+ ///
+ /// true if umbraco will use domain prefixes; otherwise, false.
+ public static bool UseDomainPrefixes
+ {
+ get
+ {
+ try
+ {
+ bool result;
+ if (bool.TryParse(GetKey("/settings/requestHandler/useDomainPrefixes"), out result))
+ return result;
+ return false;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether umbraco shouldn't add X-Umbraco-Version to the http header.
+ ///
+ /// true if umbraco will not add header; otherwise, false.
+ public static bool RemoveUmbracoVersionHeader
+ {
+ get
+ {
+ try
+ {
+ bool result;
+ if (bool.TryParse(GetKey("/settings/requestHandler/removeUmbracoVersionHeader"), out result))
+ return result;
+ return false;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+ ///
+ /// This will add a trailing slash (/) to urls when in directory url mode
+ /// NOTICE: This will always return false if Directory Urls in not active
+ ///
+ public static bool AddTrailingSlash
+ {
+ get
+ {
+ try
+ {
+ if (GlobalSettings.UseDirectoryUrls)
+ {
+ bool result;
+ if (bool.TryParse(GetKey("/settings/requestHandler/addTrailingSlash"), out result))
+ return result;
+ return false;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether umbraco will use ASP.NET MasterPages for rendering instead of its propriatary templating system.
+ ///
+ /// true if umbraco will use ASP.NET MasterPages; otherwise, false.
+ public static bool UseAspNetMasterPages
+ {
+ get
+ {
+ try
+ {
+ bool result;
+ if (bool.TryParse(GetKey("/settings/templates/useAspNetMasterPages"), out result))
+ return result;
+ return false;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+
+ ///
+ /// Gets a value indicating whether umbraco will attempt to load any skins to override default template files
+ ///
+ /// true if umbraco will override templates with skins if present and configured false.
+ public static bool EnableTemplateFolders
+ {
+ get
+ {
+ try
+ {
+ bool result;
+ if (bool.TryParse(GetKey("/settings/templates/enableTemplateFolders"), out result))
+ return result;
+ return false;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+ ///
+ /// razor DynamicNode typecasting detects XML and returns DynamicXml - Root elements that won't convert to DynamicXml
+ ///
+ public static IEnumerable NotDynamicXmlDocumentElements
+ {
+ get
+ {
+ try
+ {
+ List items = new List();
+ XmlNode root = GetKeyAsNode("/settings/scripting/razor/notDynamicXmlDocumentElements");
+ foreach (XmlNode element in root.SelectNodes(".//element"))
+ {
+ items.Add(element.InnerText);
+ }
+ return items;
+ }
+ catch
+ {
+ return new List() { "p", "div" };
+ }
+ }
+ }
+
+ public static IEnumerable RazorDataTypeModelStaticMapping
+ {
+ get
+ {
+ if (HttpContext.Current != null && HttpContext.Current.Cache != null && HttpContext.Current.Cache["settings.scripting.razor.dataTypeModelStaticMappings"] != null)
+ {
+ return HttpContext.Current.Cache["settings.scripting.razor.dataTypeModelStaticMappings"] as List;
+ }
+ /*
+
+ DigibizAdvancedMediaPicker.RazorModel.ModelBinder
+ DigibizAdvancedMediaPicker.RazorModel.ModelBinder
+
+ */
+ List items = new List();
+ XmlNode root = GetKeyAsNode("/settings/scripting/razor/dataTypeModelStaticMappings");
+ if (root != null)
+ {
+ foreach (XmlNode element in root.SelectNodes(".//mapping"))
+ {
+ string propertyTypeAlias = null, nodeTypeAlias = null;
+ Guid? dataTypeGuid = null;
+ if (!string.IsNullOrEmpty(element.InnerText))
+ {
+ if (element.Attributes["dataTypeGuid"] != null)
+ {
+ dataTypeGuid = (Guid?)new Guid(element.Attributes["dataTypeGuid"].Value);
+ }
+ if (element.Attributes["propertyTypeAlias"] != null && !string.IsNullOrEmpty(element.Attributes["propertyTypeAlias"].Value))
+ {
+ propertyTypeAlias = element.Attributes["propertyTypeAlias"].Value;
+ }
+ if (element.Attributes["nodeTypeAlias"] != null && !string.IsNullOrEmpty(element.Attributes["nodeTypeAlias"].Value))
+ {
+ nodeTypeAlias = element.Attributes["nodeTypeAlias"].Value;
+ }
+ items.Add(new RazorDataTypeModelStaticMappingItem()
+ {
+ DataTypeGuid = dataTypeGuid,
+ PropertyTypeAlias = propertyTypeAlias,
+ NodeTypeAlias = nodeTypeAlias,
+ TypeName = element.InnerText,
+ Raw = element.OuterXml
+ });
+ }
+ }
+ }
+ if (HttpContext.Current != null && HttpContext.Current.Cache != null)
+ {
+ HttpContext.Current.Cache.Add("settings.scripting.razor.dataTypeModelStaticMappings", items, null, Cache.NoAbsoluteExpiration, new TimeSpan(0, 20, 0), CacheItemPriority.AboveNormal, null);
+ }
+ return items;
+
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether umbraco will clone XML cache on publish.
+ ///
+ ///
+ /// true if umbraco will clone XML cache on publish; otherwise, false.
+ ///
+ public static bool CloneXmlCacheOnPublish
+ {
+ get
+ {
+ try
+ {
+ bool result;
+ if (bool.TryParse(GetKey("/settings/content/cloneXmlContent"), out result))
+ return result;
+ return false;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether rich text editor content should be parsed by tidy.
+ ///
+ /// true if content is parsed; otherwise, false.
+ public static bool TidyEditorContent
+ {
+ get { return bool.Parse(GetKey("/settings/content/TidyEditorContent")); }
+ }
+
+ ///
+ /// Gets the encoding type for the tidyied content.
+ ///
+ /// The encoding type as string.
+ public static string TidyCharEncoding
+ {
+ get
+ {
+ string encoding = GetKey("/settings/content/TidyCharEncoding");
+ if (String.IsNullOrEmpty(encoding))
+ {
+ encoding = "UTF8";
+ }
+ return encoding;
+ }
+ }
+
+ ///
+ /// Gets the property context help option, this can either be 'text', 'icon' or 'none'
+ ///
+ /// The property context help option.
+ public static string PropertyContextHelpOption
+ {
+ get { return GetKey("/settings/content/PropertyContextHelpOption").ToLower(); }
+ }
+
+ public static string DefaultBackofficeProvider
+ {
+ get
+ {
+ string defaultProvider = GetKey("/settings/providers/users/DefaultBackofficeProvider");
+ if (String.IsNullOrEmpty(defaultProvider))
+ defaultProvider = "UsersMembershipProvider";
+
+ return defaultProvider;
+ }
+ }
+
+ ///
+ /// Whether to force safe aliases (no spaces, no special characters) at businesslogic level on contenttypes and propertytypes
+ ///
+ public static bool ForceSafeAliases
+ {
+ get
+ {
+ string forceSafeAlias = GetKey("/settings/content/ForceSafeAliases");
+ if (String.IsNullOrEmpty(forceSafeAlias))
+ return true;
+ else
+ {
+ try
+ {
+ return bool.Parse(forceSafeAlias);
+ }
+ catch
+ {
+ return true;
+ }
+ }
+
+ }
+ }
+
+
+ ///
+ /// Gets the allowed image file types.
+ ///
+ /// The allowed image file types.
+ public static string ImageFileTypes
+ {
+ get { return GetKey("/settings/content/imaging/imageFileTypes").ToLowerInvariant(); }
+ }
+
+ ///
+ /// Gets the allowed script file types.
+ ///
+ /// The allowed script file types.
+ public static string ScriptFileTypes
+ {
+ get { return GetKey("/settings/content/scripteditor/scriptFileTypes"); }
+ }
+
+ ///
+ /// Gets the duration in seconds to cache queries to umbraco library member and media methods
+ /// Default is 1800 seconds (30 minutes)
+ ///
+ public static int UmbracoLibraryCacheDuration
+ {
+ get
+ {
+ string libraryCacheDuration = GetKey("/settings/content/UmbracoLibraryCacheDuration");
+ if (String.IsNullOrEmpty(libraryCacheDuration))
+ return 1800;
+ else
+ {
+ try
+ {
+ return int.Parse(libraryCacheDuration);
+ }
+ catch
+ {
+ return 1800;
+ }
+ }
+
+ }
+ }
+
+ ///
+ /// Gets the path to the scripts folder used by the script editor.
+ ///
+ /// The script folder path.
+ public static string ScriptFolderPath
+ {
+ get { return GetKey("/settings/content/scripteditor/scriptFolderPath"); }
+ }
+
+ ///
+ /// Enabled or disable the script/code editor
+ ///
+ public static bool ScriptDisableEditor
+ {
+ get
+ {
+ string _tempValue = GetKey("/settings/content/scripteditor/scriptDisableEditor");
+ if (_tempValue != String.Empty)
+ return bool.Parse(_tempValue);
+ else
+ return false;
+ }
+ }
+
+ ///
+ /// Gets the graphic headline format - png or gif
+ ///
+ /// The graphic headline format.
+ public static string GraphicHeadlineFormat
+ {
+ get { return GetKey("/settings/content/graphicHeadlineFormat"); }
+ }
+
+ ///
+ /// Gets a value indicating whether umbraco will ensure unique node naming.
+ /// This will ensure that nodes cannot have the same url, but will add extra characters to a url.
+ /// ex: existingnodename.aspx would become existingnodename(1).aspx if a node with the same name is found
+ ///
+ /// true if umbraco ensures unique node naming; otherwise, false.
+ public static bool EnsureUniqueNaming
+ {
+ get
+ {
+ try
+ {
+ return bool.Parse(GetKey("/settings/content/ensureUniqueNaming"));
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+ ///
+ /// Gets the notification email sender.
+ ///
+ /// The notification email sender.
+ public static string NotificationEmailSender
+ {
+ get { return GetKey("/settings/content/notifications/email"); }
+ }
+
+ ///
+ /// Gets a value indicating whether notification-emails are HTML.
+ ///
+ ///
+ /// true if html notification-emails are disabled; otherwise, false.
+ ///
+ public static bool NotificationDisableHtmlEmail
+ {
+ get
+ {
+ var tempValue = GetKey("/settings/content/notifications/disableHtmlEmail");
+ return tempValue != String.Empty && bool.Parse(tempValue);
+ }
+ }
+
+ ///
+ /// Gets the allowed attributes on images.
+ ///
+ /// The allowed attributes on images.
+ public static string ImageAllowedAttributes
+ {
+ get { return GetKey("/settings/content/imaging/allowedAttributes"); }
+ }
+
+ public static XmlNode ImageAutoFillImageProperties
+ {
+ get { return GetKeyAsNode("/settings/content/imaging/autoFillImageProperties"); }
+ }
+
+ ///
+ /// Gets the scheduled tasks as XML
+ ///
+ /// The scheduled tasks.
+ public static XmlNode ScheduledTasks
+ {
+ get { return GetKeyAsNode("/settings/scheduledTasks"); }
+ }
+
+ ///
+ /// Gets a list of characters that will be replaced when generating urls
+ ///
+ /// The URL replacement characters.
+ public static XmlNode UrlReplaceCharacters
+ {
+ get { return GetKeyAsNode("/settings/requestHandler/urlReplacing"); }
+ }
+
+ ///
+ /// Whether to replace double dashes from url (ie my--story----from--dash.aspx caused by multiple url replacement chars
+ ///
+ public static bool RemoveDoubleDashesFromUrlReplacing
+ {
+ get
+ {
+ try
+ {
+ return bool.Parse(UrlReplaceCharacters.Attributes.GetNamedItem("removeDoubleDashes").Value);
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether umbraco will use distributed calls.
+ /// This enables umbraco to share cache and content across multiple servers.
+ /// Used for load-balancing high-traffic sites.
+ ///
+ /// true if umbraco uses distributed calls; otherwise, false.
+ public static bool UseDistributedCalls
+ {
+ get
+ {
+ try
+ {
+ return bool.Parse(GetKeyAsNode("/settings/distributedCall").Attributes.GetNamedItem("enable").Value);
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+
+ ///
+ /// Gets the ID of the user with access rights to perform the distributed calls.
+ ///
+ /// The distributed call user.
+ public static int DistributedCallUser
+ {
+ get
+ {
+ try
+ {
+ return int.Parse(GetKey("/settings/distributedCall/user"));
+ }
+ catch
+ {
+ return -1;
+ }
+ }
+ }
+
+ ///
+ /// Gets the html injected into a (x)html page if Umbraco is running in preview mode
+ ///
+ public static string PreviewBadge
+ {
+ get
+ {
+ try
+ {
+ return GetKey("/settings/content/PreviewBadge");
+ }
+ catch
+ {
+ return "In Preview Mode - click to end";
+ }
+ }
+ }
+
+ ///
+ /// Gets IP or hostnames of the distribution servers.
+ /// These servers will receive a call everytime content is created/deleted/removed
+ /// and update their content cache accordingly, ensuring a consistent cache on all servers
+ ///
+ /// The distribution servers.
+ public static XmlNode DistributionServers
+ {
+ get
+ {
+ try
+ {
+ return GetKeyAsNode("/settings/distributedCall/servers");
+ }
+ catch
+ {
+ return null;
+ }
+ }
+ }
+
+ ///
+ /// Gets HelpPage configurations.
+ /// A help page configuration specify language, user type, application, application url and
+ /// the target help page url.
+ ///
+ public static XmlNode HelpPages
+ {
+ get
+ {
+ try
+ {
+ return GetKeyAsNode("/settings/help");
+ }
+ catch
+ {
+ return null;
+ }
+ }
+ }
+
+ ///
+ /// Gets all repositories registered, and returns them as XmlNodes, containing name, alias and webservice url.
+ /// These repositories are used by the build-in package installer and uninstaller to install new packages and check for updates.
+ /// All repositories should have a unique alias.
+ /// All packages installed from a repository gets the repository alias included in the install information
+ ///
+ /// The repository servers.
+ public static XmlNode Repositories
+ {
+ get
+ {
+ try
+ {
+ return GetKeyAsNode("/settings/repositories");
+ }
+ catch
+ {
+ return null;
+ }
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether umbraco will use the viewstate mover module.
+ /// The viewstate mover will move all asp.net viewstate information to the bottom of the aspx page
+ /// to ensure that search engines will index text instead of javascript viewstate information.
+ ///
+ ///
+ /// true if umbraco will use the viewstate mover module; otherwise, false.
+ ///
+ public static bool UseViewstateMoverModule
+ {
+ get
+ {
+ try
+ {
+ return
+ bool.Parse(
+ GetKeyAsNode("/settings/viewstateMoverModule").Attributes.GetNamedItem("enable").Value);
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+
+ ///
+ /// Tells us whether the Xml Content cache is disabled or not
+ /// Default is enabled
+ ///
+ public static bool IsXmlContentCacheDisabled
+ {
+ get
+ {
+ try
+ {
+ bool xmlCacheEnabled;
+ string value = GetKey("/settings/content/XmlCacheEnabled");
+ if (bool.TryParse(value, out xmlCacheEnabled))
+ return !xmlCacheEnabled;
+ // Return default
+ return false;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+ ///
+ /// Check if there's changes to the umbraco.config xml file cache on disk on each request
+ /// Makes it possible to updates environments by syncing the umbraco.config file across instances
+ /// Relates to http://umbraco.codeplex.com/workitem/30722
+ ///
+ public static bool XmlContentCheckForDiskChanges
+ {
+ get
+ {
+ try
+ {
+ bool checkForDiskChanges;
+ string value = GetKey("/settings/content/XmlContentCheckForDiskChanges");
+ if (bool.TryParse(value, out checkForDiskChanges))
+ return checkForDiskChanges;
+ // Return default
+ return false;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+ ///
+ /// If this is enabled, all Umbraco objects will generate data in the preview table (cmsPreviewXml).
+ /// If disabled, only documents will generate data.
+ /// This feature is useful if anyone would like to see how data looked at a given time
+ ///
+ public static bool EnableGlobalPreviewStorage
+ {
+ get
+ {
+ try
+ {
+ bool globalPreviewEnabled = false;
+ string value = GetKey("/settings/content/GlobalPreviewStorageEnabled");
+ if (bool.TryParse(value, out globalPreviewEnabled))
+ return !globalPreviewEnabled;
+ // Return default
+ return false;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+ ///
+ /// Whether to use the new 4.1 schema or the old legacy schema
+ ///
+ ///
+ /// true if yes, use the old node/data model; otherwise, false.
+ ///
+ public static bool UseLegacyXmlSchema
+ {
+ get
+ {
+ string value = GetKey("/settings/content/UseLegacyXmlSchema");
+ bool result;
+ if (!string.IsNullOrEmpty(value) && bool.TryParse(value, out result))
+ return result;
+ return true;
+ }
+ }
+
+ public static IEnumerable AppCodeFileExtensionsList
+ {
+ get
+ {
+ return (from XmlNode x in AppCodeFileExtensions
+ where !String.IsNullOrEmpty(x.InnerText)
+ select x.InnerText).ToList();
+ }
+ }
+
+ [Obsolete("Use AppCodeFileExtensionsList instead")]
+ public static XmlNode AppCodeFileExtensions
+ {
+ get
+ {
+ XmlNode value = GetKeyAsNode("/settings/developer/appCodeFileExtensions");
+ if (value != null)
+ {
+ return value;
+ }
+
+ // default is .cs and .vb
+ value = UmbracoSettingsXmlDoc.CreateElement("appCodeFileExtensions");
+ value.AppendChild(XmlHelper.AddTextNode(UmbracoSettingsXmlDoc, "ext", "cs"));
+ value.AppendChild(XmlHelper.AddTextNode(UmbracoSettingsXmlDoc, "ext", "vb"));
+ return value;
+ }
+ }
+
+ ///
+ /// Tells us whether the Xml to always update disk cache, when changes are made to content
+ /// Default is enabled
+ ///
+ public static bool ContinouslyUpdateXmlDiskCache
+ {
+ get
+ {
+ try
+ {
+ bool updateDiskCache;
+ string value = GetKey("/settings/content/ContinouslyUpdateXmlDiskCache");
+ if (bool.TryParse(value, out updateDiskCache))
+ return updateDiskCache;
+ // Return default
+ return false;
+ }
+ catch
+ {
+ return true;
+ }
+ }
+ }
+
+ ///
+ /// Tells us whether to use a splash page while umbraco is initializing content.
+ /// If not, requests are queued while umbraco loads content. For very large sites (+10k nodes) it might be usefull to
+ /// have a splash page
+ /// Default is disabled
+ ///
+ public static bool EnableSplashWhileLoading
+ {
+ get
+ {
+ try
+ {
+ bool updateDiskCache;
+ string value = GetKey("/settings/content/EnableSplashWhileLoading");
+ if (bool.TryParse(value, out updateDiskCache))
+ return updateDiskCache;
+ // Return default
+ return false;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+ private static bool? _resolveUrlsFromTextString;
+ public static bool ResolveUrlsFromTextString
+ {
+ get
+ {
+ if (_resolveUrlsFromTextString == null)
+ {
+ try
+ {
+ bool enableDictionaryFallBack;
+ var value = GetKey("/settings/content/ResolveUrlsFromTextString");
+ if (value != null)
+ if (bool.TryParse(value, out enableDictionaryFallBack))
+ _resolveUrlsFromTextString = enableDictionaryFallBack;
+ }
+ catch (Exception ex)
+ {
+ Trace.WriteLine("Could not load /settings/content/ResolveUrlsFromTextString from umbracosettings.config:\r\n {0}",
+ ex.Message);
+
+ // set url resolving to true (default (legacy) behavior) to ensure we don't keep writing to trace
+ _resolveUrlsFromTextString = true;
+ }
+ }
+ return _resolveUrlsFromTextString == true;
+ }
+ }
+
+ ///
+ /// Configuration regarding webservices
+ ///
+ /// Put in seperate class for more logik/seperation
+ internal class WebServices
+ {
+ ///
+ /// Gets a value indicating whether this is enabled.
+ ///
+ /// true if enabled; otherwise, false.
+ public static bool Enabled
+ {
+ get
+ {
+ try
+ {
+ return
+ bool.Parse(GetKeyAsNode("/settings/webservices").Attributes.GetNamedItem("enabled").Value);
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+
+ #region "Webservice configuration"
+
+ ///
+ /// Gets the document service users who have access to use the document web service
+ ///
+ /// The document service users.
+ public static string[] DocumentServiceUsers
+ {
+ get
+ {
+ try
+ {
+ return GetKey("/settings/webservices/documentServiceUsers").Split(',');
+ }
+ catch
+ {
+ return new string[0];
+ }
+ }
+ }
+
+ ///
+ /// Gets the file service users who have access to use the file web service
+ ///
+ /// The file service users.
+ public static string[] FileServiceUsers
+ {
+ get
+ {
+ try
+ {
+ return GetKey("/settings/webservices/fileServiceUsers").Split(',');
+ }
+ catch
+ {
+ return new string[0];
+ }
+ }
+ }
+
+
+ ///
+ /// Gets the folders used by the file web service
+ ///
+ /// The file service folders.
+ public static string[] FileServiceFolders
+ {
+ get
+ {
+ try
+ {
+ return GetKey("/settings/webservices/fileServiceFolders").Split(',');
+ }
+ catch
+ {
+ return new string[0];
+ }
+ }
+ }
+
+ ///
+ /// Gets the member service users who have access to use the member web service
+ ///
+ /// The member service users.
+ public static string[] MemberServiceUsers
+ {
+ get
+ {
+ try
+ {
+ return GetKey("/settings/webservices/memberServiceUsers").Split(',');
+ }
+ catch
+ {
+ return new string[0];
+ }
+ }
+ }
+
+ ///
+ /// Gets the stylesheet service users who have access to use the stylesheet web service
+ ///
+ /// The stylesheet service users.
+ public static string[] StylesheetServiceUsers
+ {
+ get
+ {
+ try
+ {
+ return GetKey("/settings/webservices/stylesheetServiceUsers").Split(',');
+ }
+ catch
+ {
+ return new string[0];
+ }
+ }
+ }
+
+ ///
+ /// Gets the template service users who have access to use the template web service
+ ///
+ /// The template service users.
+ public static string[] TemplateServiceUsers
+ {
+ get
+ {
+ try
+ {
+ return GetKey("/settings/webservices/templateServiceUsers").Split(',');
+ }
+ catch
+ {
+ return new string[0];
+ }
+ }
+ }
+
+ ///
+ /// Gets the media service users who have access to use the media web service
+ ///
+ /// The media service users.
+ public static string[] MediaServiceUsers
+ {
+ get
+ {
+ try
+ {
+ return GetKey("/settings/webservices/mediaServiceUsers").Split(',');
+ }
+ catch
+ {
+ return new string[0];
+ }
+ }
+ }
+
+
+ ///
+ /// Gets the maintenance service users who have access to use the maintance web service
+ ///
+ /// The maintenance service users.
+ public static string[] MaintenanceServiceUsers
+ {
+ get
+ {
+ try
+ {
+ return GetKey("/settings/webservices/maintenanceServiceUsers").Split(',');
+ }
+ catch
+ {
+ return new string[0];
+ }
+ }
+ }
+
+ #endregion
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/IO/FileSecurityException.cs b/src/Umbraco.Core/IO/FileSecurityException.cs
new file mode 100644
index 0000000000..8358b5efd2
--- /dev/null
+++ b/src/Umbraco.Core/IO/FileSecurityException.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Umbraco.Core.IO
+{
+ public class FileSecurityException : Exception
+ {
+ public FileSecurityException()
+ {
+
+ }
+
+ public FileSecurityException(string message) : base(message)
+ {
+
+ }
+ }
+}
diff --git a/src/Umbraco.Core/IO/IOHelper.cs b/src/Umbraco.Core/IO/IOHelper.cs
new file mode 100644
index 0000000000..a0b3d69b87
--- /dev/null
+++ b/src/Umbraco.Core/IO/IOHelper.cs
@@ -0,0 +1,206 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.IO;
+using System.Configuration;
+using System.Web;
+using System.Text.RegularExpressions;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Core.IO
+{
+ internal static class IOHelper
+ {
+ private static string _rootDir = "";
+ // static compiled regex for faster performance
+ private readonly static Regex ResolveUrlPattern = new Regex("(=[\"\']?)(\\W?\\~(?:.(?![\"\']?\\s+(?:\\S+)=|[>\"\']))+.)[\"\']?", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
+
+ public static char DirSepChar
+ {
+ get
+ {
+ return Path.DirectorySeparatorChar;
+ }
+ }
+
+ //helper to try and match the old path to a new virtual one
+ public static string FindFile(string virtualPath)
+ {
+ string retval = virtualPath;
+
+ if (virtualPath.StartsWith("~"))
+ retval = virtualPath.Replace("~", SystemDirectories.Root);
+
+ if (virtualPath.StartsWith("/") && !virtualPath.StartsWith(SystemDirectories.Root))
+ retval = SystemDirectories.Root + "/" + virtualPath.TrimStart('/');
+
+ return retval;
+ }
+
+ //Replaces tildes with the root dir
+ public static string ResolveUrl(string virtualPath)
+ {
+ if (virtualPath.StartsWith("~"))
+ return virtualPath.Replace("~", SystemDirectories.Root).Replace("//", "/");
+ else
+ return VirtualPathUtility.ToAbsolute(virtualPath, SystemDirectories.Root);
+ }
+
+
+ public static string ResolveUrlsFromTextString(string text)
+ {
+ if (UmbracoSettings.ResolveUrlsFromTextString)
+ {
+ var sw = new Stopwatch();
+ sw.Start();
+ Debug.WriteLine("Start: " + sw.ElapsedMilliseconds);
+
+ // find all relative urls (ie. urls that contain ~)
+ var tags =
+ ResolveUrlPattern.Matches(text);
+ Debug.WriteLine("After regex: " + sw.ElapsedMilliseconds);
+ foreach (Match tag in tags)
+ {
+ Debug.WriteLine("-- inside regex: " + sw.ElapsedMilliseconds);
+ string url = "";
+ if (tag.Groups[1].Success)
+ url = tag.Groups[1].Value;
+
+ // The richtext editor inserts a slash in front of the url. That's why we need this little fix
+ // if (url.StartsWith("/"))
+ // text = text.Replace(url, ResolveUrl(url.Substring(1)));
+ // else
+ if (!String.IsNullOrEmpty(url))
+ {
+ Debug.WriteLine("---- before resolve: " + sw.ElapsedMilliseconds);
+ string resolvedUrl = (url.Substring(0, 1) == "/") ? ResolveUrl(url.Substring(1)) : ResolveUrl(url);
+ Debug.WriteLine("---- after resolve: " + sw.ElapsedMilliseconds);
+ Debug.WriteLine("---- before replace: " + sw.ElapsedMilliseconds);
+ text = text.Replace(url, resolvedUrl);
+ Debug.WriteLine("---- after replace: " + sw.ElapsedMilliseconds);
+ }
+
+ }
+
+ Debug.WriteLine("total: " + sw.ElapsedMilliseconds);
+ sw.Stop();
+ System.Web.HttpContext.Current.Trace.Write("Resolve Urls", sw.ElapsedMilliseconds.ToString());
+
+ }
+ return text;
+ }
+
+ public static string MapPath(string path, bool useHttpContext)
+ {
+ // Check if the path is already mapped
+ if (path.Length >= 2 && path[1] == Path.VolumeSeparatorChar)
+ return path;
+
+ // Check that we even have an HttpContext! otherwise things will fail anyways
+ // http://umbraco.codeplex.com/workitem/30946
+
+ if (useHttpContext && HttpContext.Current != null)
+ {
+ //string retval;
+ if (!string.IsNullOrEmpty(path) && (path.StartsWith("~") || path.StartsWith(SystemDirectories.Root)))
+ return System.Web.Hosting.HostingEnvironment.MapPath(path);
+ else
+ return System.Web.Hosting.HostingEnvironment.MapPath("~/" + path.TrimStart('/'));
+ }
+
+ //var root = (!string.IsNullOrEmpty(System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath))
+ // ? System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath.TrimEnd(IOHelper.DirSepChar)
+ // : getRootDirectorySafe();
+
+ var root = GetRootDirectorySafe();
+ var newPath = path.TrimStart('~', '/').Replace('/', IOHelper.DirSepChar);
+ var retval = root + IOHelper.DirSepChar.ToString() + newPath;
+
+ return retval;
+ }
+
+ public static string MapPath(string path)
+ {
+ return MapPath(path, true);
+ }
+
+ //use a tilde character instead of the complete path
+ public static string ReturnPath(string settingsKey, string standardPath, bool useTilde)
+ {
+ string retval = ConfigurationManager.AppSettings[settingsKey];
+
+ if (string.IsNullOrEmpty(retval))
+ retval = standardPath;
+
+ return retval.TrimEnd('/');
+ }
+
+
+ public static string ReturnPath(string settingsKey, string standardPath)
+ {
+ return ReturnPath(settingsKey, standardPath, false);
+
+ }
+
+
+ ///
+ /// Validates if the current filepath matches a directory where the user is allowed to edit a file
+ ///
+ /// filepath
+ ///
+ /// true if valid, throws a FileSecurityException if not
+ public static bool ValidateEditPath(string filePath, string validDir)
+ {
+ if (!filePath.StartsWith(MapPath(SystemDirectories.Root)))
+ filePath = MapPath(filePath);
+ if (!validDir.StartsWith(MapPath(SystemDirectories.Root)))
+ validDir = MapPath(validDir);
+
+ if (!filePath.StartsWith(validDir))
+ throw new FileSecurityException(String.Format("The filepath '{0}' is not within an allowed directory for this type of files", filePath.Replace(MapPath(SystemDirectories.Root), "")));
+
+ return true;
+ }
+
+ public static bool ValidateFileExtension(string filePath, List validFileExtensions)
+ {
+ if (!filePath.StartsWith(MapPath(SystemDirectories.Root)))
+ filePath = MapPath(filePath);
+ var f = new FileInfo(filePath);
+
+
+ if (!validFileExtensions.Contains(f.Extension.Substring(1)))
+ throw new FileSecurityException(String.Format("The extension for the current file '{0}' is not of an allowed type for this editor. This is typically controlled from either the installed MacroEngines or based on configuration in /config/umbracoSettings.config", filePath.Replace(MapPath(SystemDirectories.Root), "")));
+
+ return true;
+ }
+
+
+ ///
+ /// Returns the path to the root of the application, by getting the path to where the assembly where this
+ /// method is included is present, then traversing until it's past the /bin directory. Ie. this makes it work
+ /// even if the assembly is in a /bin/debug or /bin/release folder
+ ///
+ ///
+ internal static string GetRootDirectorySafe()
+ {
+ if (!String.IsNullOrEmpty(_rootDir))
+ {
+ return _rootDir;
+ }
+
+ var codeBase = Assembly.GetExecutingAssembly().CodeBase;
+ var uri = new Uri(codeBase);
+ var path = uri.LocalPath;
+ var baseDirectory = Path.GetDirectoryName(path);
+ _rootDir = baseDirectory.Substring(0, baseDirectory.LastIndexOf("bin") - 1);
+
+ return _rootDir;
+
+ }
+
+ }
+}
diff --git a/src/Umbraco.Core/IO/SystemDirectories.cs b/src/Umbraco.Core/IO/SystemDirectories.cs
new file mode 100644
index 0000000000..3ee99750d2
--- /dev/null
+++ b/src/Umbraco.Core/IO/SystemDirectories.cs
@@ -0,0 +1,181 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Configuration;
+
+using System.Web;
+using System.IO;
+
+namespace Umbraco.Core.IO
+{
+ //all paths has a starting but no trailing /
+ internal class SystemDirectories
+ {
+ public static string Bin
+ {
+ get
+ {
+ return IOHelper.ReturnPath("umbracoBinDirectory", "~/bin");
+ }
+ }
+
+ public static string Base
+ {
+ get
+ {
+ return IOHelper.ReturnPath("umbracoBaseDirectory", "~/base");
+ }
+ }
+
+ public static string Config
+ {
+ get
+ {
+ return IOHelper.ReturnPath("umbracoConfigDirectory", "~/config");
+ }
+ }
+
+ public static string Css
+ {
+ get
+ {
+ return IOHelper.ReturnPath("umbracoCssDirectory", "~/css");
+ }
+ }
+
+ public static string Data
+ {
+ get
+ {
+ return IOHelper.ReturnPath("umbracoStorageDirectory", "~/App_Data");
+ }
+ }
+
+ public static string Install
+ {
+ get
+ {
+ return IOHelper.ReturnPath("umbracoInstallPath", "~/install");
+ }
+ }
+
+ public static string Masterpages
+ {
+ get
+ {
+ return IOHelper.ReturnPath("umbracoMasterPagesPath", "~/masterpages");
+ }
+ }
+
+
+ public static string Media
+ {
+ get
+ {
+ return IOHelper.ReturnPath("umbracoMediaPath", "~/media");
+ }
+ }
+
+ [Obsolete("Please use MacroScripts instead!", true)]
+ public static string Python
+ {
+ get
+ {
+ return MacroScripts;
+ }
+ }
+
+ public static string MacroScripts
+ {
+ get
+ {
+ // for legacy we test for the python path first, but else we use the new default location
+ string tempPath = IOHelper.ReturnPath("umbracoPythonPath", "") == String.Empty
+ ? IOHelper.ReturnPath("umbracoMacroScriptPath", "~/macroScripts")
+ : IOHelper.ReturnPath("umbracoPythonPath", "~/python");
+ return tempPath;
+ }
+ }
+
+ public static string Scripts
+ {
+ get
+ {
+ return IOHelper.ReturnPath("umbracoScriptsPath", "~/scripts");
+ }
+ }
+
+ public static string Umbraco
+ {
+ get
+ {
+ return IOHelper.ReturnPath("umbracoPath", "~/umbraco");
+ }
+ }
+
+ public static string UmbracoClient
+ {
+ get
+ {
+ return IOHelper.ReturnPath("umbracoClientPath", "~/umbraco_client");
+ }
+ }
+
+ public static string UserControls
+ {
+ get
+ {
+ return IOHelper.ReturnPath("umbracoUsercontrolsPath", "~/usercontrols");
+ }
+ }
+
+ public static string WebServices
+ {
+ get
+ {
+ return IOHelper.ReturnPath("umbracoWebservicesPath", "~/umbraco/webservices");
+ }
+ }
+
+ public static string Xslt
+ {
+ get {
+ return IOHelper.ReturnPath("umbracoXsltPath", "~/xslt");
+ }
+ }
+
+ public static string Packages
+ {
+ get
+ {
+ //by default the packages folder should exist in the data folder
+ return IOHelper.ReturnPath("umbracoPackagesPath", Data + IOHelper.DirSepChar + "packages");
+ }
+ }
+
+ public static string Preview
+ {
+ get
+ {
+ //by default the packages folder should exist in the data folder
+ return IOHelper.ReturnPath("umbracoPreviewPath", Data + IOHelper.DirSepChar + "preview");
+ }
+ }
+
+ public static string Root
+ {
+ get
+ {
+ string appPath = HttpRuntime.AppDomainAppVirtualPath ?? string.Empty;
+ if (appPath == "/")
+ appPath = string.Empty;
+
+ return appPath;
+ }
+ }
+ }
+
+
+
+}
diff --git a/src/Umbraco.Core/IO/SystemFiles.cs b/src/Umbraco.Core/IO/SystemFiles.cs
new file mode 100644
index 0000000000..59b2debf0a
--- /dev/null
+++ b/src/Umbraco.Core/IO/SystemFiles.cs
@@ -0,0 +1,122 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Web;
+
+namespace Umbraco.Core.IO
+{
+ internal class SystemFiles
+ {
+
+ public static string AccessXml
+ {
+ get
+ {
+ return SystemDirectories.Data + "/access.config";
+ }
+ }
+
+ public static string CreateUiXml
+ {
+ get
+ {
+ return SystemDirectories.Umbraco + "/config/create/UI.xml";
+ }
+ }
+
+ public static string TinyMceConfig
+ {
+ get
+ {
+ return SystemDirectories.Config + "/tinyMceConfig.config";
+ }
+ }
+
+ public static string MetablogConfig
+ {
+ get
+ {
+ return SystemDirectories.Config + "/metablogConfig.config";
+ }
+ }
+
+ public static string DashboardConfig
+ {
+ get
+ {
+ return SystemDirectories.Config + "/dashboard.config";
+ }
+ }
+
+ public static string XsltextensionsConfig
+ {
+ get
+ {
+ return SystemDirectories.Config + "/xsltextensions.config";
+ }
+ }
+
+ public static string RestextensionsConfig
+ {
+ get
+ {
+ return SystemDirectories.Config + "/restextensions.config";
+ }
+ }
+
+
+ public static string SkinningXml
+ {
+ get
+ {
+ return SystemDirectories.Data + "/skinning.config";
+ }
+ }
+
+ public static string NotFoundhandlersConfig
+ {
+ get
+ {
+ return SystemDirectories.Config + "/404handlers.config";
+ }
+ }
+
+ public static string FeedProxyConfig
+ {
+ get
+ {
+ return string.Concat(SystemDirectories.Config, "/feedProxy.config");
+ }
+ }
+
+ public static string ContentCacheXml
+ {
+ get
+ {
+ if (ContentCacheXmlIsEphemeral)
+ {
+ return Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData\umbraco.config");
+ }
+ return IOHelper.ReturnPath("umbracoContentXML", "~/App_Data/umbraco.config");
+ }
+ }
+
+ public static bool ContentCacheXmlIsEphemeral
+ {
+ get
+ {
+ bool returnValue = false;
+ string configSetting = ConfigurationManager.AppSettings["umbracoContentXMLUseLocalTemp"];
+
+ if (!string.IsNullOrEmpty(configSetting))
+ if(bool.TryParse(configSetting, out returnValue))
+ return returnValue;
+
+ return false;
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Logging/LogHelper.cs b/src/Umbraco.Core/Logging/LogHelper.cs
new file mode 100644
index 0000000000..53ede6ce22
--- /dev/null
+++ b/src/Umbraco.Core/Logging/LogHelper.cs
@@ -0,0 +1,153 @@
+//using System;
+//using System.Collections.Generic;
+//using System.Linq;
+//using System.Text;
+//using System.Threading;
+
+//namespace Umbraco.Core.Logging
+//{
+// ///
+// /// Used for logging
+// ///
+// internal static class LogHelper
+// {
+// static LogHelper()
+// {
+// //var appSetting = ConfigurationManager.AppSettings["log4net-config-path"];
+// //if (appSetting != null && File.Exists(appSetting))
+// // XmlConfigurator.ConfigureAndWatch(new FileInfo(appSetting));
+// //else
+// //XmlConfigurator.Configure();
+// }
+
+// ///
+// /// Returns a logger for the type specified
+// ///
+// ///
+// ///
+// public static ILog LoggerFor()
+// {
+// return LogManager.GetLogger(typeof(T));
+// }
+
+// ///
+// /// Returns a logger for the object's type
+// ///
+// ///
+// ///
+// public static ILog LoggerFor(object getTypeFromInstance)
+// {
+// Mandate.ParameterNotNull(getTypeFromInstance, "getTypeFromInstance");
+// return LogManager.GetLogger(getTypeFromInstance.GetType());
+// }
+
+// ///
+// /// Adds an error log
+// ///
+// ///
+// ///
+// ///
+// public static void Error(string message, Exception exception)
+// {
+// var logger = LoggerFor();
+// if (logger != null)
+// logger.Error(PrefixThreadId(message), exception);
+// }
+
+// ///
+// /// Traces a message, only generating the message if tracing is actually enabled. Use this method to avoid calling any long-running methods such as "ToDebugString" if logging is disabled.
+// ///
+// ///
+// /// The generate message format.
+// /// The format items.
+// ///
+// public static void TraceIfEnabled(string generateMessageFormat, params Func