source: branches/eraser6/pluginsRewrite/Eraser.Manager/Settings.cs @ 2293

Revision 2293, 20.0 KB checked in by lowjoel, 4 years ago (diff)

Rename the PluginInstance? class to be the PluginInfo? class.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2008-2010 The Eraser Project
4 * Original Author: Joel Low <lowjoel@users.sourceforge.net>
5 * Modified By:
6 *
7 * This file is part of Eraser.
8 *
9 * Eraser is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
13 *
14 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 *
18 * A copy of the GNU General Public License can be found at
19 * <http://www.gnu.org/licenses/>.
20 */
21
22using System;
23using System.Collections.Generic;
24using System.Text;
25using System.Reflection;
26using System.Runtime.InteropServices;
27using System.Globalization;
28
29using Eraser.Util;
30using Eraser.Plugins;
31
32namespace Eraser.Manager
33{
34    public abstract class SettingsManager
35    {
36        /// <summary>
37        /// Saves all the settings to persistent storage.
38        /// </summary>
39        public abstract void Save();
40
41        /// <summary>
42        /// Gets the dictionary holding settings for the calling assembly.
43        /// </summary>
44        public Settings ModuleSettings
45        {
46            get
47            {
48                return GetSettings(new Guid(((GuidAttribute)Assembly.GetCallingAssembly().
49                    GetCustomAttributes(typeof(GuidAttribute), false)[0]).Value));
50            }
51        }
52
53        /// <summary>
54        /// Gets the settings from the data source.
55        /// </summary>
56        /// <param name="value">The GUID of the calling plugin</param>
57        /// <returns>The Settings object which will act as the data store.</returns>
58        protected abstract Settings GetSettings(Guid value);
59    }
60
61    /// <summary>
62    /// Settings class. Represents settings to a given client.
63    /// </summary>
64    public abstract class Settings
65    {
66        /// <summary>
67        /// Gets the setting for the given name, coercing the object stored in the backend
68        /// to the given type <typeparamref name="T"/>.
69        /// </summary>
70        /// <typeparam name="T">The type of the setting that is currently stored in the
71        /// backend.</typeparam>
72        /// <param name="name">The name of the setting that is used to uniquely refer
73        /// to the value.</param>
74        /// <param name="defaultValue">The default to return if the no data is assocated
75        /// with the given setting.</param>
76        /// <returns>The value stored in the backend, or null if none exists.</returns>
77        public abstract T GetValue<T>(string name, T defaultValue);
78
79        /// <summary>
80        /// Overload for <see cref="GetValue"/> which returns a default for the given type.
81        /// </summary>
82        /// <typeparam name="T">The type of the setting that is currently stored in the
83        /// backend.</typeparam>
84        /// <param name="name">The name of the setting that is used to uniquely refer
85        /// to the value.</param>
86        /// <param name="defaultValue">The default to return if the no data is assocated
87        /// with the given setting.</param>
88        /// <returns>The value stored in the backend, or null if none exists.</returns>
89        public T GetValue<T>(string name)
90        {
91            return GetValue<T>(name, default(T));
92        }
93
94        /// <summary>
95        /// Sets the setting with the given name.
96        /// </summary>
97        /// <param name="name">The name of the setting.</param>
98        /// <param name="value">The value to store in the backend. This may be serialised.</param>
99        public abstract void SetValue(string name, object value);
100
101        /// <summary>
102        /// Gets or sets the given setting, without type hinting. This will not attempt to coerce
103        /// a type from an old version of the assembly to its current type.
104        /// </summary>
105        /// <param name="setting">The name of the setting.</param>
106        /// <returns>The object stored in the settings database, or null if undefined.</returns>
107        [Obsolete("Use the GetValue<T> and SetValue functions instead")]
108        public object this[string setting]
109        {
110            get
111            {
112                return GetValue<object>(setting);
113            }
114            set
115            {
116                SetValue(setting, value);
117            }
118        }
119    }
120
121    #region Default attributes
122    /// <summary>
123    /// Indicates that the marked class should be used as a default when no
124    /// settings have been set by the user.
125    /// </summary>
126    [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
127    public abstract class DefaultAttribute : Attribute
128    {
129        /// <summary>
130        /// Constructor.
131        /// </summary>
132        /// <param name="priority">The priority of the current element in terms of
133        /// it being the default.</param>
134        protected DefaultAttribute(int priority)
135        {
136            Priority = priority;
137        }
138
139        /// <summary>
140        /// The priority of the default.
141        /// </summary>
142        public int Priority
143        {
144            get
145            {
146                return priority;
147            }
148            private set
149            {
150                priority = value;
151            }
152        }
153
154        private int priority;
155    }
156
157    /// <summary>
158    /// Indicates that the marked class should be used as the default file erasure
159    /// method.
160    /// </summary>
161    [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = false)]
162    public sealed class DefaultFileErasureAttribute : DefaultAttribute
163    {
164        /// <summary>
165        /// Constructor.
166        /// </summary>
167        /// <param name="priority">The priority of the current element in terms of
168        /// it being the default.</param>
169        public DefaultFileErasureAttribute(int priority)
170            : base(priority)
171        {
172        }
173    }
174
175    /// <summary>
176    /// Indicates that the marked class should be used as the default unused space
177    /// erasure method.
178    /// </summary>
179    [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = false)]
180    public sealed class DefaultUnusedSpaceErasureAttribute : DefaultAttribute
181    {
182        /// <summary>
183        /// Constructor.
184        /// </summary>
185        /// <param name="priority">The priority of the current element in terms of
186        /// it being the default.</param>
187        public DefaultUnusedSpaceErasureAttribute(int priority)
188            : base(priority)
189        {
190        }
191    }
192
193    /// <summary>
194    /// Indicates that the marked class should be used as the default PRNG.
195    /// </summary>
196    [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = false)]
197    public sealed class DefaultPrngAttribute : DefaultAttribute
198    {
199        /// <summary>
200        /// Constructor.
201        /// </summary>
202        /// <param name="priority">The priority of the current element in terms of
203        /// it being the default.</param>
204        public DefaultPrngAttribute(int priority)
205            : base(priority)
206        {
207        }
208    }
209    #endregion
210
211    /// <summary>
212    /// Presents an opaque type for the management of the Manager settings.
213    /// </summary>
214    public class ManagerSettings
215    {
216        /// <summary>
217        /// Constructor.
218        /// </summary>
219        /// <param name="settings">The Settings object which is the data store for
220        /// this object.</param>
221        public ManagerSettings()
222        {
223            settings = ManagerLibrary.Instance.SettingsManager.ModuleSettings;
224        }
225
226        /// <summary>
227        /// The default file erasure method. This is a GUID since methods are
228        /// implemented through plugins and plugins may not be loaded and missing
229        /// references may follow.
230        /// </summary>
231        public Guid DefaultFileErasureMethod
232        {
233            get
234            {
235                //If the user did not define anything for this field, check all plugins
236                //and use the method which was declared by us to be the highest
237                //priority default
238                Guid result = settings.GetValue<Guid>("DefaultFileErasureMethod");
239                if (result == Guid.Empty)
240                    result = FindHighestPriorityDefault(typeof(ErasureMethod),
241                        typeof(DefaultFileErasureAttribute));
242                if (result == Guid.Empty)
243                    result = new Guid("{1407FC4E-FEFF-4375-B4FB-D7EFBB7E9922}");
244
245                return result;
246            }
247            set
248            {
249                settings.SetValue("DefaultFileErasureMethod", value);
250            }
251        }
252
253        /// <summary>
254        /// The default unused space erasure method. This is a GUID since methods
255        /// are implemented through plugins and plugins may not be loaded and
256        /// missing references may follow.
257        /// </summary>
258        public Guid DefaultUnusedSpaceErasureMethod
259        {
260            get
261            {
262                Guid result = settings.GetValue<Guid>("DefaultUnusedSpaceErasureMethod");
263                if (result == Guid.Empty)
264                    result = FindHighestPriorityDefault(typeof(UnusedSpaceErasureMethod),
265                        typeof(DefaultUnusedSpaceErasureAttribute));
266                if (result == Guid.Empty)
267                    result = new Guid("{BF8BA267-231A-4085-9BF9-204DE65A6641}");
268                return result;
269            }
270            set
271            {
272                settings.SetValue("DefaultUnusedSpaceErasureMethod", value);
273            }
274        }
275
276        /// <summary>
277        /// The PRNG used. This is a GUID since PRNGs are implemented through
278        /// plugins and plugins may not be loaded and missing references may follow.
279        /// </summary>
280        public Guid ActivePrng
281        {
282            get
283            {
284                Guid result = settings.GetValue<Guid>("ActivePRNG");
285                if (result == Guid.Empty)
286                    result = FindHighestPriorityDefault(typeof(Prng), typeof(DefaultPrngAttribute));
287                if (result == Guid.Empty)
288                    result = new Guid("{6BF35B8E-F37F-476e-B6B2-9994A92C3B0C}");
289                return result;
290            }
291            set
292            {
293                settings.SetValue("ActivePRNG", value);
294            }
295        }
296
297        /// <summary>
298        /// Whether files which are locked when being erased should be forcibly
299        /// unlocked for erasure.
300        /// </summary>
301        public bool ForceUnlockLockedFiles
302        {
303            get
304            {
305                return settings.GetValue("ForceUnlockLockedFiles", true);
306            }
307            set
308            {
309                settings.SetValue("ForceUnlockLockedFiles", value);
310            }
311        }
312
313        /// <summary>
314        /// Whether missed tasks should be run when the program next starts.
315        /// </summary>
316        public bool ExecuteMissedTasksImmediately
317        {
318            get
319            {
320                return settings.GetValue("ExecuteMissedTasksImmediately", true);
321            }
322            set
323            {
324                settings.SetValue("ExecuteMissedTasksImmediately", value);
325            }
326        }
327
328        /// <summary>
329        /// Whether erasures should be run with plausible deniability. This is
330        /// achieved by the executor copying files over the file to be removed
331        /// before removing it.
332        /// </summary>
333        /// <seealso cref="PlausibleDeniabilityFiles"/>
334        public bool PlausibleDeniability
335        {
336            get
337            {
338                return settings.GetValue("PlausibleDeniability", false);
339            }
340            set
341            {
342                settings.SetValue("PlausibleDeniability", value);
343            }
344        }
345
346        /// <summary>
347        /// The files which are overwritten with when a file has been erased.
348        /// </summary>
349        public IList<string> PlausibleDeniabilityFiles
350        {
351            get
352            {
353                return new SettingsList<string>(settings, "PlausibleDeniabilityFiles");
354            }
355        }
356
357        #region Default Attributes retrieval
358        /// <summary>
359        /// Finds the type for the given attribute that is the default (i.e. the
360        /// DefaultAttribute value is the highest) and that the type inherits
361        /// from the given <paramref name="superClass"/>.
362        /// </summary>
363        /// <param name="superClass">A class that the default must inherit from.</param>
364        /// <param name="attributeType">The attribute to look for.</param>
365        /// <returns>The GUID of the type that is the default.</returns>
366        private static Guid FindHighestPriorityDefault(Type superClass,
367            Type attributeType)
368        {
369            //Check if we've computed the value before. If so, we return the cached
370            //value.
371            if (DefaultForAttributes.ContainsKey(attributeType) &&
372                DefaultForAttributes[attributeType].ContainsKey(superClass))
373            {
374                return DefaultForAttributes[attributeType][superClass];
375            }
376
377            //We have not computed the value. Compute the default.
378            IList<PluginInfo> plugins = Host.Instance.Plugins;
379            SortedList<int, Guid> priorities = new SortedList<int, Guid>();
380
381            foreach (PluginInfo plugin in plugins)
382            {
383                //Check whether the plugin is signed by us.
384                byte[] pluginKey = plugin.Assembly.GetName().GetPublicKey();
385                byte[] ourKey = Assembly.GetExecutingAssembly().GetName().GetPublicKey();
386
387                if (pluginKey.Length != ourKey.Length ||
388                    !Security.VerifyStrongName(plugin.Assembly.Location))
389                    continue;
390                bool officialPlugin = true;
391                for (int i = 0, j = ourKey.Length; i != j; ++i)
392                    if (pluginKey[i] != ourKey[i])
393                        officialPlugin = false;
394                if (!officialPlugin)
395                    continue;
396
397                Type[] types = FindTypeAttributeInAssembly(plugin.Assembly,
398                    superClass, attributeType);
399
400                //Prioritize the types.
401                if (types != null)
402                    foreach (Type type in types)
403                    {
404                        object[] guids =
405                            type.GetCustomAttributes(typeof(GuidAttribute), false);
406                        DefaultAttribute defaultAttr = (DefaultAttribute)
407                            type.GetCustomAttributes(attributeType, false)[0];
408
409                        if (guids.Length == 1)
410                            priorities.Add(defaultAttr.Priority,
411                                new Guid(((GuidAttribute)guids[0]).Value));
412                    }
413            }
414
415            //If we actually have a result, cache it then return the result.
416            if (priorities.Count > 0)
417            {
418                Guid result = priorities[priorities.Keys[priorities.Count - 1]];
419                if (!DefaultForAttributes.ContainsKey(attributeType))
420                    DefaultForAttributes.Add(attributeType, new Dictionary<Type, Guid>());
421                DefaultForAttributes[attributeType].Add(superClass, result);
422                return result;
423            }
424
425            //If we do not have any results, don't store it.
426            return Guid.Empty;
427        }
428
429        /// <summary>
430        /// Finds a type with the given characteristics in the provided assembly.
431        /// </summary>
432        /// <param name="assembly">The assembly to look into.</param>
433        /// <param name="superClass">A class the type must inherit from.</param>
434        /// <param name="attributeType">The attribute the class must possess.</param>
435        /// <returns>An array of types with the given characteristics.</returns>
436        private static Type[] FindTypeAttributeInAssembly(Assembly assembly, Type superClass,
437            Type attributeType)
438        {
439            //Yes, if we got here the plugin is signed by us. Find the
440            //type which inherits from ErasureMethod.
441            Type[] types = assembly.GetExportedTypes();
442            List<Type> result = new List<Type>();
443            foreach (Type type in types)
444            {
445                if (!type.IsPublic || type.IsAbstract)
446                    //Not interesting.
447                    continue;
448
449                //Try to see if this class inherits from the specified super class.
450                if (!type.IsSubclassOf(superClass))
451                    continue;
452
453                //See if this class has the DefaultFileErasureAttribute
454                object[] attributes = type.GetCustomAttributes(attributeType, false);
455                if (attributes.Length > 0)
456                    result.Add(type);
457            }
458
459            return result.ToArray();
460        }
461
462        /// <summary>
463        /// Caches the defaults as computed by FindHighestPriorityDefault. The first
464        /// key is the attribute type, the second key is the superclass, the
465        /// value is the Guid.
466        /// </summary>
467        private static Dictionary<Type, Dictionary<Type, Guid>> DefaultForAttributes =
468            new Dictionary<Type, Dictionary<Type, Guid>>();
469        #endregion
470
471        /// <summary>
472        /// Holds user decisions on whether the plugin will be loaded at the next
473        /// start up.
474        /// </summary>
475        public IDictionary<Guid, bool> PluginApprovals
476        {
477            get
478            {
479                return new SettingsDictionary<Guid, bool>(settings, "ApprovedPlugins");
480            }
481        }
482
483        /// <summary>
484        /// The Settings object which is the data store of this object.
485        /// </summary>
486        private Settings settings;
487
488        /// <summary>
489        /// Encapsulates an abstract list that is used to store settings.
490        /// </summary>
491        /// <typeparam name="T">The type of the list element.</typeparam>
492        private class SettingsList<T> : IList<T>
493        {
494            public SettingsList(Settings settings, string settingName)
495            {
496                Settings = settings;
497                SettingName = settingName;
498                List = new List<T>();
499
500                T[] values = settings.GetValue<T[]>(settingName);
501                if (values != null)
502                    List.AddRange(values);
503            }
504
505            ~SettingsList()
506            {
507                Save();
508            }
509
510            #region IList<T> Members
511
512            public int IndexOf(T item)
513            {
514                return List.IndexOf(item);
515            }
516
517            public void Insert(int index, T item)
518            {
519                List.Insert(index, item);
520                Save();
521            }
522
523            public void RemoveAt(int index)
524            {
525                List.RemoveAt(index);
526                Save();
527            }
528
529            public T this[int index]
530            {
531                get
532                {
533                    return List[index];
534                }
535                set
536                {
537                    List[index] = value;
538                    Save();
539                }
540            }
541
542            #endregion
543
544            #region ICollection<T> Members
545
546            public void Add(T item)
547            {
548                List.Add(item);
549                Save();
550            }
551
552            public void Clear()
553            {
554                List.Clear();
555                Save();
556            }
557
558            public bool Contains(T item)
559            {
560                return List.Contains(item);
561            }
562
563            public void CopyTo(T[] array, int arrayIndex)
564            {
565                List.CopyTo(array, arrayIndex);
566            }
567
568            public int Count
569            {
570                get { return List.Count; }
571            }
572
573            public bool IsReadOnly
574            {
575                get { return false; }
576            }
577
578            public bool Remove(T item)
579            {
580                bool result = List.Remove(item);
581                Save();
582                return result;
583            }
584
585            #endregion
586
587            #region IEnumerable<T> Members
588
589            public IEnumerator<T> GetEnumerator()
590            {
591                return List.GetEnumerator();
592            }
593
594            #endregion
595
596            #region IEnumerable Members
597
598            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
599            {
600                return List.GetEnumerator();
601            }
602
603            #endregion
604
605            /// <summary>
606            /// Saves changes made to the list to the settings manager.
607            /// </summary>
608            private void Save()
609            {
610                Settings.SetValue(SettingName, List);
611            }
612
613            /// <summary>
614            /// The settings object storing the settings.
615            /// </summary>
616            private Settings Settings;
617
618            /// <summary>
619            /// The name of the setting we are encapsulating.
620            /// </summary>
621            private string SettingName;
622
623            /// <summary>
624            /// The list we are using as scratch.
625            /// </summary>
626            private List<T> List;
627        }
628
629        /// <summary>
630        /// Encapsulates an abstract dictionary that is used to store settings.
631        /// </summary>
632        /// <typeparam name="TKey">The key type of the dictionary.</typeparam>
633        /// <typeparam name="TValue">The value type of the dictionary.</typeparam>
634        private class SettingsDictionary<TKey, TValue> : IDictionary<TKey, TValue>
635        {
636            public SettingsDictionary(Settings settings, string settingName)
637            {
638                Settings = settings;
639                SettingName = settingName;
640                Dictionary = settings.GetValue<Dictionary<TKey, TValue>>(settingName);
641                if (Dictionary == null)
642                    Dictionary = new Dictionary<TKey, TValue>();
643            }
644
645            ~SettingsDictionary()
646            {
647                Save();
648            }
649
650            #region IDictionary<TKey,TValue> Members
651
652            public void Add(TKey key, TValue value)
653            {
654                Dictionary.Add(key, value);
655                Save();
656            }
657
658            public bool ContainsKey(TKey key)
659            {
660                return Dictionary.ContainsKey(key);
661            }
662
663            public ICollection<TKey> Keys
664            {
665                get { return Dictionary.Keys; }
666            }
667
668            public bool Remove(TKey key)
669            {
670                bool result = Dictionary.Remove(key);
671                Save();
672                return result;
673            }
674
675            public bool TryGetValue(TKey key, out TValue value)
676            {
677                return Dictionary.TryGetValue(key, out value);
678            }
679
680            public ICollection<TValue> Values
681            {
682                get { return Dictionary.Values; }
683            }
684
685            public TValue this[TKey key]
686            {
687                get
688                {
689                    return Dictionary[key];
690                }
691                set
692                {
693                    Dictionary[key] = value;
694                    Save();
695                }
696            }
697
698            #endregion
699
700            #region ICollection<KeyValuePair<TKey,TValue>> Members
701
702            public void Add(KeyValuePair<TKey, TValue> item)
703            {
704                Dictionary.Add(item.Key, item.Value);
705                Save();
706            }
707
708            public void Clear()
709            {
710                Dictionary.Clear();
711                Save();
712            }
713
714            public bool Contains(KeyValuePair<TKey, TValue> item)
715            {
716                return Dictionary.ContainsKey(item.Key) && Dictionary[item.Key].Equals(item.Value);
717            }
718
719            public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
720            {
721                throw new NotImplementedException();
722            }
723
724            public int Count
725            {
726                get { return Dictionary.Count; }
727            }
728
729            public bool IsReadOnly
730            {
731                get { return false; }
732            }
733
734            public bool Remove(KeyValuePair<TKey, TValue> item)
735            {
736                if (Dictionary.ContainsKey(item.Key) && Dictionary[item.Key].Equals(item.Value))
737                {
738                    bool result = Dictionary.Remove(item.Key);
739                    Save();
740                    return result;
741                }
742
743                return false;
744            }
745
746            #endregion
747
748            #region IEnumerable<KeyValuePair<TKey,TValue>> Members
749
750            public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
751            {
752                return Dictionary.GetEnumerator();
753            }
754
755            #endregion
756
757            #region IEnumerable Members
758
759            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
760            {
761                return Dictionary.GetEnumerator();
762            }
763
764            #endregion
765
766            /// <summary>
767            /// Saves changes made to the list to the settings manager.
768            /// </summary>
769            private void Save()
770            {
771                Settings.SetValue(SettingName, Dictionary);
772            }
773
774            /// <summary>
775            /// The settings object storing the settings.
776            /// </summary>
777            private Settings Settings;
778
779            /// <summary>
780            /// The name of the setting we are encapsulating.
781            /// </summary>
782            private string SettingName;
783
784            /// <summary>
785            /// The list we are using as scratch.
786            /// </summary>
787            private Dictionary<TKey, TValue> Dictionary;
788        }
789
790    }
791}
Note: See TracBrowser for help on using the repository browser.