#region Disclaimer / License // Copyright (C) 2011, Kenneth Bergeron, IAP Worldwide Services, Inc // NOAA :: National Marine Fisheries Service // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // #endregion using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Duplicati.Scheduler.Data { /// /// Tools for the Scheduler DataSet /// public partial class SchedulerDataSet { /// /// The last time we loaded the XML file /// public DateTime LastLoaded { get; set; } /// /// a Kinda good user time format /// public static string DateFormat = "ddd MM/dd/yyy hh:mm tt"; /// /// Makes sure the path exists and returns it /// /// File to combine with app path /// Full path with file name public static string GetAppData(string aFileName) { string Result = Utility.User.GetApplicationDirectory( @"Duplicati" ); if (!System.IO.Directory.Exists(Result)) System.IO.Directory.CreateDirectory(Result); return System.IO.Path.Combine(Result, aFileName); } /// /// Returns the delfault XML file name with path /// /// The delfault XML file name with path public static string DefaultPath() { return GetAppData(DefaultName); } /// /// The XML file last loaded /// public string XMLPath { get; set; } /// /// The default XML file without path /// public const string DefaultName = "Scheduler.xml"; /// /// Load the default XML file /// /// null if OK or exception thrown public Exception Load() { return Load(string.Empty); } /// /// Checks to see if the XML file changed since we last loaded /// /// true if the file is younger than the last load public bool NeedsLoading() { return NeedsLoading(GetAppData(DefaultName)); } /// /// Checks to see if the XML file changed since we last loaded /// /// File to check /// true if the file is younger than the last load public bool NeedsLoading(string aFullPath) { if (LastLoaded == null) return false; DateTime LastWrite = (new System.IO.FileInfo(aFullPath)).LastWriteTime; return LastLoaded != LastWrite; } /// /// Load from a file /// /// File to load or use default if null or empty /// null if OK or exception thrown public Exception Load(string aFullPath) { if (string.IsNullOrEmpty(aFullPath)) aFullPath = DefaultPath(); if (!System.IO.File.Exists(aFullPath)) return new Exception("File not found: " + aFullPath); this.Clear(); Exception Result = null; try { this.ReadXml(aFullPath); XMLPath = aFullPath; LastLoaded = (new System.IO.FileInfo(aFullPath)).LastWriteTime; } catch (Exception Ex) { Result = Ex; } return Result; } /// /// Saves the dataset to the default XML file /// /// null if OK or exception thrown public Exception Save() { return Save(GetAppData(DefaultName)); } /// /// Loads the database /// /// XML file to load /// null if OK or exception thrown public Exception Save(string aFullPath) { Exception Result = null; try { this.WriteXml(aFullPath); LastLoaded = (new System.IO.FileInfo(aFullPath)).LastWriteTime; } catch (Exception Ex) { Result = Ex; } return Result; } /// /// Tools for the row /// public partial class JobsRow { /// /// Returns the Options /// public Dictionary Options { get { Dictionary Result = (from OptionsRow qRow in this.GetOptionsRows() select new { Key = qRow.Parameter, Value = qRow.Value }). ToDictionary(n => n.Key, n => n.Value); if (GetCheckSrc() == 0 || Checksum.Length == 0) Result["no-encryption"] = string.Empty; else Result["Checksum"] = System.Convert.ToBase64String(Checksum); if (!string.IsNullOrEmpty(Filter)) Result["Filter"] = Filter; return Result; } } /// /// Returns the GuiOptions /// public Dictionary GuiOptions { get { return (from GuiOptionsRow qRow in this.GetGuiOptionsRows() select new { Key = qRow.Parameter, Value = qRow.Value }). ToDictionary(n => n.Key, n => n.Value); } } /// /// This is only local and is not saved in XML - Enabled should be fetched from the trigger /// But, this is used for temporary storage by the editor /// public bool Enabled { get; set; } /// /// Separator used in Filters /// public const char Separator = (char)3; // ETX /// /// Filters as a string array /// public string[] FilterLines { get { if (this.IsFilterNull() || string.IsNullOrEmpty(this.Filter)) return new string[0]; return this.Filter.Split(Separator); } set { if (value == null || value.Length == 0) Filter = string.Empty; else Filter = string.Join(Separator.ToString(), value); } } /// /// Save as options /// /// Options to save /// OK if saved public bool SetOptions(Dictionary aOptions) { System.Data.DataRelation dr = this.tableJobs.ChildRelations["Jobs_Options"]; if (dr == null) return false; SchedulerDataSet.OptionsDataTable ChildTable = (SchedulerDataSet.OptionsDataTable)dr.ChildTable; foreach (SchedulerDataSet.OptionsRow Row in this.GetOptionsRows()) Row.Delete(); foreach (KeyValuePair kvp in aOptions) ChildTable.AddOptionsRow(this, kvp.Key, kvp.Value); return true; } /// /// Save as GuiOptions /// /// Options to save /// OK if saved public bool SetGuiOptions(Dictionary aOptions) { System.Data.DataRelation dr = this.tableJobs.ChildRelations["Jobs_GuiOptions"]; if (dr == null) return false; SchedulerDataSet.GuiOptionsDataTable ChildTable = (SchedulerDataSet.GuiOptionsDataTable)dr.ChildTable; foreach (SchedulerDataSet.GuiOptionsRow Row in this.GetGuiOptionsRows()) Row.Delete(); foreach (KeyValuePair kvp in aOptions) ChildTable.AddGuiOptionsRow(this, kvp.Key, kvp.Value); return true; } /// /// Creates a task name for this job /// /// Job Name /// User Name with Domain /// Task Name public static string MakeTaskName(string aName, string aUserName) { return "DUP." + aName + '.' + aUserName.Replace('\\', '.'); } /// /// Returns the Task Name for this job /// public string TaskName { get { return MakeTaskName(this.Name, Utility.User.UserName); } } /// /// Returns the settings row for this job /// private SettingsRow Settings { get { return ((SchedulerDataSet)this.Table.DataSet).Settings.Values; } } /// /// Returns the Check Source [0==none, 1==Local, 2==global] /// /// Check Source [0==none, 1==Local, 2==global] public int GetCheckSrc() { if (this.IsCheckSrcNull() || string.IsNullOrEmpty(this.CheckSrc) || this.CheckSrc.Equals("none", StringComparison.InvariantCultureIgnoreCase)) return 0; else if (this.CheckSrc.StartsWith("g", StringComparison.InvariantCultureIgnoreCase)) return 2; return 1; } /// /// Sets the check source [0==none, 1==Local, 2==global] /// /// [0==none, 1==Local, 2==global] public void SetCheckSrc(int aSet) { this.CheckSrc = new string[] { "none", "local", "global" }[aSet & 3]; } /// /// Returns checksum based on source /// public byte[] Checksum { get { switch (GetCheckSrc()) { case 0: return new byte[0]; case 2: return Settings.Checksum; default: return LocalChecksum; } } set { this.LocalChecksum = value; } } /// /// Returns the Check Module based on Source /// public string CheckMod { get { switch (GetCheckSrc()) { case 0: return string.Empty; case 2: return ((SchedulerDataSet)this.Table.DataSet).Settings.Values.CheckMod; default: return LocalCheckMod; } } set { this.LocalCheckMod = value; } } /// /// Drive mappings at time of last save /// public Dictionary DriveMaps { get { Dictionary Result = new Dictionary(); foreach (DriveMapsRow Row in GetDriveMapsRows()) Result.Add(Row.DriveLetter, Row.UNC); return Result; } } /// /// Creates the drive map table /// /// Map to save /// true if saved OK public bool SetDriveMaps(Dictionary aDriveMap) { System.Data.DataRelation dr = this.tableJobs.ChildRelations["Jobs_DriveMaps"]; if (dr == null) return false; SchedulerDataSet.DriveMapsDataTable ChildTable = (SchedulerDataSet.DriveMapsDataTable)dr.ChildTable; foreach (SchedulerDataSet.DriveMapsRow Row in this.GetDriveMapsRows()) Row.Delete(); foreach (KeyValuePair kvp in aDriveMap) ChildTable.AddDriveMapsRow(this, kvp.Key, kvp.Value); return true; } /// /// Delete this job /// public new void Delete() { // Get rid of the options foreach (OptionsRow oRow in GetOptionsRows()) oRow.Delete(); foreach (GuiOptionsRow oRow in GetGuiOptionsRows()) oRow.Delete(); // And the maps foreach (DriveMapsRow dRow in GetDriveMapsRows()) dRow.Delete(); // And the history using(HistoryDataSet hds = new HistoryDataSet()) { hds.Load(); hds.History.DeleteJob(this.Name); foreach( HistoryDataSet.HistoryRow hRow in hds.History.Select("Name = '"+this.Name+'\'')) hRow.Delete(); hds.Save(); } base.Delete(); } } /// /// Data table tools /// public partial class JobsDataTable { /// /// Get options /// /// Job name /// Options public Dictionary GetOptions(string aName) { JobsRow Row = this.FindByName(aName); if (Row == null) return new Dictionary(); return Row.Options; } /// /// Get GuiOptions /// /// Job name /// Options public Dictionary GetGuiOptions(string aName) { JobsRow Row = this.FindByName(aName); if (Row == null) return new Dictionary(); return Row.GuiOptions; } /// /// Create a new row with defaults /// /// /// public SchedulerDataSet.JobsRow NewJobsRow(string aName) { SchedulerDataSet.JobsRow Result = NewJobsRow(); Result.Name = aName; Result.CheckMod = string.Empty; Result.Checksum = new byte[0]; Result.Destination = string.Empty; Result.Filter = string.Empty; Result.FullOnly = false; Result.FullRepeatDays = 10; Result.FullAfterN = 8; Result.MaxAgeDays = 0; Result.MaxFulls = 4; Result.Source = string.Empty; Result.MapDrives = true; Result.AutoCleanup = true; return Result; } } /// /// Settings /// public partial class SettingsDataTable { /// /// Only 1st row used /// public SettingsRow Values { get { if (this.Count == 0) this.AddSettingsRow(0, new byte[0], string.Empty, true, false, string.Empty, DateTime.Now); return (SettingsRow)this.Rows[0]; } } /// /// Is the global password set? /// public bool UseGlobalPassword { get { return Values.CheckSrc && Values.Checksum.Length > 0; } } public string[] DisabledMonitors { get { return Values.DisabledMonitors.Split(';'); } set { Values.DisabledMonitors = string.Join(";", value); } } public void EnableMonitor(string aName, bool aEnable) { if (aEnable && DisabledMonitors.Contains(aName)) DisabledMonitors = DisabledMonitors.Where(qR => qR != aName).ToArray(); else if (!aEnable && !DisabledMonitors.Contains(aName)) DisabledMonitors = DisabledMonitors.Concat(new string[] { aName }).ToArray(); } } /// /// Options /// public partial class OptionsDataTable { /// /// As dictionary /// public Dictionary OptionsDict { get { return (from OptionsRow qRow in this select new { Key = qRow.Parameter, Value = qRow.Value }).ToDictionary(n => n.Key, n => n.Value); } } } } }