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