1 /*
2   KeePass Password Safe - The Open-Source Password Manager
3   Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
4 
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19 
20 using System;
21 using System.Collections.Generic;
22 using System.ComponentModel;
23 using System.Diagnostics;
24 using System.Text;
25 using System.Xml.Serialization;
26 
27 using KeePass.Ecas;
28 using KeePass.Util;
29 
30 using KeePassLib.Serialization;
31 using KeePassLib.Utility;
32 
33 namespace KeePass.App.Configuration
34 {
35 	public sealed class AceApplication
36 	{
AceApplication()37 		public AceApplication()
38 		{
39 		}
40 
41 		private bool m_bConfigSave = true;
42 		[DefaultValue(true)]
43 		public bool ConfigSave
44 		{
45 			get { return m_bConfigSave; }
46 			set { m_bConfigSave = value; }
47 		}
48 
49 		private string m_strLanguageFile = string.Empty; // = English
50 		[DefaultValue("")]
51 		public string LanguageFile
52 		{
53 			get { return m_strLanguageFile; }
54 			set
55 			{
56 				if(value == null) throw new ArgumentNullException("value");
57 				m_strLanguageFile = value;
58 			}
59 		}
60 
61 		private bool m_bHelpUseLocal = false;
62 		[DefaultValue(false)]
63 		public bool HelpUseLocal
64 		{
65 			get { return m_bHelpUseLocal; }
66 			set { m_bHelpUseLocal = value; }
67 		}
68 
69 		private string m_strHelpUrl = string.Empty;
70 		[DefaultValue("")]
71 		public string HelpUrl
72 		{
73 			get { return m_strHelpUrl; }
74 			set
75 			{
76 				if(value == null) throw new ArgumentNullException("value");
77 				m_strHelpUrl = value;
78 			}
79 		}
80 
81 		// Serialize DateTime with TimeUtil
82 		private string m_strLastUpdChk = string.Empty;
83 		[DefaultValue("")]
84 		public string LastUpdateCheck
85 		{
86 			get { return m_strLastUpdChk; }
87 			set
88 			{
89 				if(value == null) throw new ArgumentNullException("value");
90 				m_strLastUpdChk = value;
91 			}
92 		}
93 
94 		private IOConnectionInfo m_ioLastDb = null;
95 		public IOConnectionInfo LastUsedFile
96 		{
97 			get
98 			{
99 				if(m_ioLastDb == null) m_ioLastDb = new IOConnectionInfo();
100 				return m_ioLastDb;
101 			}
102 			set
103 			{
104 				if(value == null) throw new ArgumentNullException("value");
105 				m_ioLastDb = value;
106 			}
107 		}
108 
109 		private AceMru m_mru = null;
110 		public AceMru MostRecentlyUsed
111 		{
112 			get
113 			{
114 				if(m_mru == null) m_mru = new AceMru();
115 				return m_mru;
116 			}
117 			set
118 			{
119 				if(value == null) throw new ArgumentNullException("value");
120 				m_mru = value;
121 			}
122 		}
123 
124 		private bool m_bRememberWorkDirs = true;
125 		[DefaultValue(true)]
126 		public bool RememberWorkingDirectories
127 		{
128 			get { return m_bRememberWorkDirs; }
129 			set { m_bRememberWorkDirs = value; }
130 		}
131 
132 		private Dictionary<string, string> m_dictWorkingDirs =
133 			new Dictionary<string, string>();
134 
135 		/// <summary>
136 		/// For serialization only; use the <c>*WorkingDirectory</c>
137 		/// methods instead.
138 		/// </summary>
139 		[XmlArray("WorkingDirectories")]
140 		[XmlArrayItem("Item")]
141 		public string[] WorkingDirectoriesSerialized
142 		{
143 			get { return SerializeWorkingDirectories(); }
144 			set
145 			{
146 				if(value == null) throw new ArgumentNullException("value");
147 				DeserializeWorkingDirectories(value);
148 			}
149 		}
150 
151 		private AceStartUp m_su = null;
152 		public AceStartUp Start
153 		{
154 			get
155 			{
156 				if(m_su == null) m_su = new AceStartUp();
157 				return m_su;
158 			}
159 			set
160 			{
161 				if(value == null) throw new ArgumentNullException("value");
162 				m_su = value;
163 			}
164 		}
165 
166 		private AceOpenDb m_fo = null;
167 		public AceOpenDb FileOpening
168 		{
169 			get
170 			{
171 				if(m_fo == null) m_fo = new AceOpenDb();
172 				return m_fo;
173 			}
174 			set
175 			{
176 				if(value == null) throw new ArgumentNullException("value");
177 				m_fo = value;
178 			}
179 		}
180 
181 		private bool m_bVerifyFile = true;
182 		[DefaultValue(true)]
183 		public bool VerifyWrittenFileAfterSaving
184 		{
185 			get { return m_bVerifyFile; }
186 			set { m_bVerifyFile = value; }
187 		}
188 
189 		private bool m_bTransactedFileWrites = true;
190 		[DefaultValue(true)]
191 		public bool UseTransactedFileWrites
192 		{
193 			get { return m_bTransactedFileWrites; }
194 			set { m_bTransactedFileWrites = value; }
195 		}
196 
197 		private bool m_bTransactedConfigWrites = true;
198 		[DefaultValue(true)]
199 		public bool UseTransactedConfigWrites
200 		{
201 			get { return m_bTransactedConfigWrites; }
202 			set { m_bTransactedConfigWrites = value; }
203 		}
204 
205 		private bool m_bFileTxExtra = false;
206 		[DefaultValue(false)]
207 		public bool FileTxExtra
208 		{
209 			get { return m_bFileTxExtra; }
210 			set { m_bFileTxExtra = value; }
211 		}
212 
213 		private bool m_bFileLocks = false;
214 		[DefaultValue(false)]
215 		public bool UseFileLocks
216 		{
217 			get { return m_bFileLocks; }
218 			set { m_bFileLocks = value; }
219 		}
220 
221 		private bool m_bSaveForceSync = false;
222 		[DefaultValue(false)]
223 		public bool SaveForceSync
224 		{
225 			get { return m_bSaveForceSync; }
226 			set { m_bSaveForceSync = value; }
227 		}
228 
229 		private bool m_bAutoSaveAfterEntryEdit = false;
230 		[DefaultValue(false)]
231 		public bool AutoSaveAfterEntryEdit
232 		{
233 			get { return m_bAutoSaveAfterEntryEdit; }
234 			set { m_bAutoSaveAfterEntryEdit = value; }
235 		}
236 
237 		private AceCloseDb m_fc = new AceCloseDb();
238 		public AceCloseDb FileClosing
239 		{
240 			get { return m_fc; }
241 			set
242 			{
243 				if(value == null) throw new ArgumentNullException("value");
244 				m_fc = value;
245 			}
246 		}
247 
248 		private EcasTriggerSystem m_triggers = new EcasTriggerSystem();
249 		public EcasTriggerSystem TriggerSystem
250 		{
251 			get { return m_triggers; }
252 			set
253 			{
254 				if(value == null) throw new ArgumentNullException("value");
255 				m_triggers = value;
256 			}
257 		}
258 
259 		private string m_strPluginCachePath = string.Empty;
260 		[DefaultValue("")]
261 		public string PluginCachePath
262 		{
263 			get { return m_strPluginCachePath; }
264 			set
265 			{
266 				if(value == null) throw new ArgumentNullException("value");
267 				m_strPluginCachePath = value;
268 			}
269 		}
270 
271 		private List<string> m_lPluginCompat = new List<string>();
272 		[XmlArrayItem("Item")]
273 		public List<string> PluginCompatibility
274 		{
275 			get { return m_lPluginCompat; }
276 			set
277 			{
278 				if(value == null) throw new ArgumentNullException("value");
279 				m_lPluginCompat = value;
280 			}
281 		}
282 
283 		private int m_iExpirySoonDays = 7;
284 		[DefaultValue(7)]
285 		public int ExpirySoonDays
286 		{
287 			get { return m_iExpirySoonDays; }
288 			set { m_iExpirySoonDays = value; }
289 		}
290 
GetLanguagesDir(AceDir d, bool bTermSep)291 		internal static string GetLanguagesDir(AceDir d, bool bTermSep)
292 		{
293 			string str;
294 
295 			if(d == AceDir.App)
296 				str = UrlUtil.GetFileDirectory(WinUtil.GetExecutable(),
297 					true, false) + AppDefs.LanguagesDir;
298 			else if(d == AceDir.User)
299 				str = UrlUtil.EnsureTerminatingSeparator(
300 					AppConfigSerializer.AppDataDirectory, false) +
301 					AppDefs.LanguagesDir;
302 			else { Debug.Assert(false); return string.Empty; }
303 
304 			if(bTermSep) str = UrlUtil.EnsureTerminatingSeparator(str, false);
305 
306 			return str;
307 		}
308 
309 		private const string LngPrefixUser = "UL::";
310 
GetLanguageFilePath()311 		internal string GetLanguageFilePath()
312 		{
313 			string str = m_strLanguageFile;
314 			if(str.Length == 0) return string.Empty;
315 
316 			string strDir, strName;
317 			if(str.StartsWith(LngPrefixUser, StrUtil.CaseIgnoreCmp))
318 			{
319 				strDir = GetLanguagesDir(AceDir.User, true);
320 				strName = str.Substring(LngPrefixUser.Length);
321 			}
322 			else
323 			{
324 				strDir = GetLanguagesDir(AceDir.App, true);
325 				strName = str;
326 			}
327 
328 			// File name must not contain a directory separator
329 			// (language files must be directly in the directory,
330 			// not any subdirectory of it or somewhere else)
331 			if(UrlUtil.GetFileName(strName) != strName)
332 			{
333 				Debug.Assert(false);
334 				return string.Empty;
335 			}
336 
337 			return (strDir + strName);
338 		}
339 
SetLanguageFilePath(string strPath)340 		internal void SetLanguageFilePath(string strPath)
341 		{
342 			m_strLanguageFile = string.Empty;
343 			if(string.IsNullOrEmpty(strPath)) return;
344 
345 			string str = GetLanguagesDir(AceDir.App, true);
346 			if(strPath.StartsWith(str, StrUtil.CaseIgnoreCmp))
347 			{
348 				m_strLanguageFile = strPath.Substring(str.Length);
349 				return;
350 			}
351 
352 			str = GetLanguagesDir(AceDir.User, true);
353 			if(strPath.StartsWith(str, StrUtil.CaseIgnoreCmp))
354 			{
355 				m_strLanguageFile = LngPrefixUser + strPath.Substring(str.Length);
356 				return;
357 			}
358 
359 			Debug.Assert(false);
360 		}
361 
GetWorkingDirectory(string strContext)362 		public string GetWorkingDirectory(string strContext)
363 		{
364 			// strContext may be null
365 
366 			if(!m_bRememberWorkDirs) return null;
367 
368 			string str;
369 			m_dictWorkingDirs.TryGetValue(strContext ?? string.Empty, out str);
370 			return str;
371 		}
372 
SetWorkingDirectory(string strContext, string strDir)373 		public void SetWorkingDirectory(string strContext, string strDir)
374 		{
375 			// Both parameters may be null
376 
377 			// if(!m_bRememberWorkDirs) return;
378 
379 			if(string.IsNullOrEmpty(strContext)) return;
380 			m_dictWorkingDirs[strContext] = (strDir ?? string.Empty);
381 		}
382 
GetWorkingDirectoryContexts()383 		internal List<string> GetWorkingDirectoryContexts()
384 		{
385 			if(!m_bRememberWorkDirs) return new List<string>();
386 
387 			return new List<string>(m_dictWorkingDirs.Keys);
388 		}
389 
SerializeWorkingDirectories()390 		private string[] SerializeWorkingDirectories()
391 		{
392 			if(!m_bRememberWorkDirs) return new string[0];
393 
394 			List<string> l = new List<string>();
395 			foreach(KeyValuePair<string, string> kvp in m_dictWorkingDirs)
396 				l.Add(kvp.Key + @"@" + kvp.Value);
397 			return l.ToArray();
398 		}
399 
DeserializeWorkingDirectories(string[] v)400 		private void DeserializeWorkingDirectories(string[] v)
401 		{
402 			// Do not check m_bRememberWorkDirs, because it might not
403 			// have been deserialized yet
404 
405 			m_dictWorkingDirs.Clear();
406 
407 			foreach(string str in v)
408 			{
409 				if(str == null) { Debug.Assert(false); continue; }
410 
411 				int iSep = str.IndexOf('@');
412 				if(iSep <= 0) { Debug.Assert(false); continue; }
413 
414 				m_dictWorkingDirs[str.Substring(0, iSep)] = str.Substring(iSep + 1);
415 			}
416 		}
417 
IsPluginCompat(string strHash)418 		internal bool IsPluginCompat(string strHash)
419 		{
420 			if(string.IsNullOrEmpty(strHash)) { Debug.Assert(false); return false; }
421 
422 			string str = "@" + strHash + "@" + WinUtil.GetAssemblyVersion() + "@1";
423 
424 			return m_lPluginCompat.Contains(str);
425 		}
426 
SetPluginCompat(string strHash)427 		internal void SetPluginCompat(string strHash)
428 		{
429 			if(string.IsNullOrEmpty(strHash)) { Debug.Assert(false); return; }
430 
431 			string str = "@" + strHash + "@" + WinUtil.GetAssemblyVersion() + "@1";
432 
433 			if(m_lPluginCompat.Contains(str)) { Debug.Assert(false); return; }
434 			m_lPluginCompat.Insert(0, str); // See auto. maintenance
435 		}
436 	}
437 
438 	internal enum AceDir
439 	{
440 		App = 0,
441 		User
442 	}
443 
444 	public sealed class AceStartUp
445 	{
AceStartUp()446 		public AceStartUp()
447 		{
448 		}
449 
450 		private bool m_bOpenLastDb = true;
451 		[DefaultValue(true)]
452 		public bool OpenLastFile
453 		{
454 			get { return m_bOpenLastDb; }
455 			set { m_bOpenLastDb = value; }
456 		}
457 
458 		private bool m_bCheckForUpdate = false;
459 		// [DefaultValue(false)] // Avoid user confusion with 'Configured' setting
460 		public bool CheckForUpdate
461 		{
462 			get { return m_bCheckForUpdate; }
463 			set { m_bCheckForUpdate = value; }
464 		}
465 
466 		private bool m_bCheckForUpdateCfg = false;
467 		[DefaultValue(false)]
468 		public bool CheckForUpdateConfigured
469 		{
470 			get { return m_bCheckForUpdateCfg; }
471 			set { m_bCheckForUpdateCfg = value; }
472 		}
473 
474 		private bool m_bMinimizedAndLocked = false;
475 		[DefaultValue(false)]
476 		public bool MinimizedAndLocked
477 		{
478 			get { return m_bMinimizedAndLocked; }
479 			set { m_bMinimizedAndLocked = value; }
480 		}
481 
482 		private bool m_bPlgDeleteOld = true;
483 		[DefaultValue(true)]
484 		public bool PluginCacheDeleteOld
485 		{
486 			get { return m_bPlgDeleteOld; }
487 			set { m_bPlgDeleteOld = value; }
488 		}
489 
490 		private bool m_bClearPlgCache = false;
491 		[DefaultValue(false)]
492 		public bool PluginCacheClearOnce
493 		{
494 			get { return m_bClearPlgCache; }
495 			set { m_bClearPlgCache = value; }
496 		}
497 	}
498 
499 	public sealed class AceOpenDb
500 	{
AceOpenDb()501 		public AceOpenDb()
502 		{
503 		}
504 
505 		private bool m_bShowExpiredEntries = false;
506 		[DefaultValue(false)]
507 		public bool ShowExpiredEntries
508 		{
509 			get { return m_bShowExpiredEntries; }
510 			set { m_bShowExpiredEntries = value; }
511 		}
512 
513 		private bool m_bShowSoonToExpireEntries = false;
514 		[DefaultValue(false)]
515 		public bool ShowSoonToExpireEntries
516 		{
517 			get { return m_bShowSoonToExpireEntries; }
518 			set { m_bShowSoonToExpireEntries = value; }
519 		}
520 	}
521 
522 	public sealed class AceCloseDb
523 	{
AceCloseDb()524 		public AceCloseDb()
525 		{
526 		}
527 
528 		private bool m_bAutoSave = false;
529 		[DefaultValue(false)]
530 		public bool AutoSave
531 		{
532 			get { return m_bAutoSave; }
533 			set { m_bAutoSave = value; }
534 		}
535 	}
536 
537 	public sealed class AceMru
538 	{
539 		public static readonly uint DefaultMaxItemCount = 12;
540 
AceMru()541 		public AceMru()
542 		{
543 		}
544 
545 		private uint m_uMaxItems = DefaultMaxItemCount;
546 		public uint MaxItemCount
547 		{
548 			get { return m_uMaxItems; }
549 			set { m_uMaxItems = value; }
550 		}
551 
552 		private List<IOConnectionInfo> m_lItems = new List<IOConnectionInfo>();
553 		[XmlArrayItem("ConnectionInfo")]
554 		public List<IOConnectionInfo> Items
555 		{
556 			get { return m_lItems; }
557 			set
558 			{
559 				if(value == null) throw new ArgumentNullException("value");
560 				m_lItems = value;
561 			}
562 		}
563 	}
564 }
565