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.Drawing; 25 using System.Reflection; 26 using System.Text; 27 using System.Windows.Forms; 28 using System.Xml; 29 using System.Xml.Serialization; 30 31 using KeePass.UI; 32 using KeePass.Util; 33 using KeePass.Util.XmlSerialization; 34 35 using KeePassLib; 36 using KeePassLib.Delegates; 37 using KeePassLib.Native; 38 using KeePassLib.Serialization; 39 using KeePassLib.Utility; 40 41 namespace KeePass.App.Configuration 42 { 43 [XmlType(AppConfigEx.StrXmlTypeName)] 44 public sealed class AppConfigEx 45 { 46 internal const string StrXmlTypeName = "Configuration"; 47 48 private string m_strSearchString = null; 49 AppConfigEx()50 public AppConfigEx() 51 { 52 } 53 54 #if DEBUG ~AppConfigEx()55 ~AppConfigEx() 56 { 57 Debug.Assert(m_strSearchString == null); 58 } 59 #endif 60 61 private AceMeta m_meta = null; 62 public AceMeta Meta 63 { 64 get 65 { 66 if(m_meta == null) m_meta = new AceMeta(); 67 return m_meta; 68 } 69 set 70 { 71 if(value == null) throw new ArgumentNullException("value"); 72 m_meta = value; 73 } 74 } 75 76 private AceApplication m_aceApp = null; 77 public AceApplication Application 78 { 79 get 80 { 81 if(m_aceApp == null) m_aceApp = new AceApplication(); 82 return m_aceApp; 83 } 84 set 85 { 86 if(value == null) throw new ArgumentNullException("value"); 87 m_aceApp = value; 88 } 89 } 90 91 private AceLogging m_aceLogging = null; 92 public AceLogging Logging 93 { 94 get 95 { 96 if(m_aceLogging == null) m_aceLogging = new AceLogging(); 97 return m_aceLogging; 98 } 99 set 100 { 101 if(value == null) throw new ArgumentNullException("value"); 102 m_aceLogging = value; 103 } 104 } 105 106 private AceMainWindow m_uiMainWindow = null; 107 public AceMainWindow MainWindow 108 { 109 get 110 { 111 if(m_uiMainWindow == null) m_uiMainWindow = new AceMainWindow(); 112 return m_uiMainWindow; 113 } 114 set 115 { 116 if(value == null) throw new ArgumentNullException("value"); 117 m_uiMainWindow = value; 118 } 119 } 120 121 private AceUI m_aceUI = null; 122 public AceUI UI 123 { 124 get 125 { 126 if(m_aceUI == null) m_aceUI = new AceUI(); 127 return m_aceUI; 128 } 129 set 130 { 131 if(value == null) throw new ArgumentNullException("value"); 132 m_aceUI = value; 133 } 134 } 135 136 private AceSecurity m_sec = null; 137 public AceSecurity Security 138 { 139 get 140 { 141 if(m_sec == null) m_sec = new AceSecurity(); 142 return m_sec; 143 } 144 set 145 { 146 if(value == null) throw new ArgumentNullException("value"); 147 m_sec = value; 148 } 149 } 150 151 private AceNative m_native = null; 152 public AceNative Native 153 { 154 get 155 { 156 if(m_native == null) m_native = new AceNative(); 157 return m_native; 158 } 159 set 160 { 161 if(value == null) throw new ArgumentNullException("value"); 162 m_native = value; 163 } 164 } 165 166 private AcePasswordGenerator m_pwGen = null; 167 public AcePasswordGenerator PasswordGenerator 168 { 169 get 170 { 171 if(m_pwGen == null) m_pwGen = new AcePasswordGenerator(); 172 return m_pwGen; 173 } 174 set 175 { 176 if(value == null) throw new ArgumentNullException("value"); 177 m_pwGen = value; 178 } 179 } 180 181 private AceSearch m_aceSearch = null; 182 public AceSearch Search 183 { 184 get 185 { 186 if(m_aceSearch == null) m_aceSearch = new AceSearch(); 187 return m_aceSearch; 188 } 189 set 190 { 191 if(value == null) throw new ArgumentNullException("value"); 192 m_aceSearch = value; 193 } 194 } 195 196 private AceDefaults m_def = null; 197 public AceDefaults Defaults 198 { 199 get 200 { 201 if(m_def == null) m_def = new AceDefaults(); 202 return m_def; 203 } 204 set 205 { 206 if(value == null) throw new ArgumentNullException("value"); 207 m_def = value; 208 } 209 } 210 211 private AceIntegration m_int = null; 212 public AceIntegration Integration 213 { 214 get 215 { 216 if(m_int == null) m_int = new AceIntegration(); 217 return m_int; 218 } 219 set 220 { 221 if(value == null) throw new ArgumentNullException("value"); 222 m_int = value; 223 } 224 } 225 226 private AceCustomConfig m_cc = null; 227 [XmlIgnore] 228 public AceCustomConfig CustomConfig 229 { 230 get 231 { 232 if(m_cc == null) m_cc = new AceCustomConfig(); 233 return m_cc; 234 } 235 set 236 { 237 if(value == null) throw new ArgumentNullException("value"); 238 m_cc = value; 239 } 240 } 241 242 [XmlArray("Custom")] 243 [XmlArrayItem("Item")] 244 public AceKvp[] CustomSerialized 245 { 246 get 247 { 248 return this.CustomConfig.Serialize(); // m_cc might be null 249 } 250 set 251 { 252 if(value == null) throw new ArgumentNullException("value"); 253 this.CustomConfig.Deserialize(value); // m_cc might be null 254 } 255 } 256 257 /// <summary> 258 /// Prepare for saving the configuration to disk. None of the 259 /// modifications in this method need to be rolled back 260 /// (for rollback, use <c>OnSavePre</c> / <c>OnSavePost</c>). 261 /// </summary> PrepareSave()262 private void PrepareSave() 263 { 264 AceMeta aceMeta = this.Meta; // m_meta might be null 265 AceApplication aceApp = this.Application; // m_aceApp might be null 266 AceSearch aceSearch = this.Search; // m_aceSearch might be null 267 AceDefaults aceDef = this.Defaults; // m_def might be null 268 269 aceMeta.OmitItemsWithDefaultValues = true; 270 aceMeta.DpiFactorX = DpiUtil.FactorX; // For new (not loaded) cfgs. 271 aceMeta.DpiFactorY = DpiUtil.FactorY; 272 273 aceApp.LastUsedFile.ClearCredentials(true); 274 275 foreach(IOConnectionInfo iocMru in aceApp.MostRecentlyUsed.Items) 276 iocMru.ClearCredentials(true); 277 278 if(aceDef.RememberKeySources == false) 279 aceDef.KeySources.Clear(); 280 281 aceApp.TriggerSystem = Program.TriggerSystem; 282 283 SearchUtil.PrepareForSerialize(aceSearch.LastUsedProfile); 284 foreach(SearchParameters sp in aceSearch.UserProfiles) 285 SearchUtil.PrepareForSerialize(sp); 286 287 const int m = 64; // Maximum number of compatibility items 288 List<string> l = aceApp.PluginCompatibility; 289 if(l.Count > m) l.RemoveRange(m, l.Count - m); // See reg. 290 } 291 OnLoad()292 internal void OnLoad() 293 { 294 AceMainWindow aceMW = this.MainWindow; // m_uiMainWindow might be null 295 AceSearch aceSearch = this.Search; // m_aceSearch might be null 296 AceDefaults aceDef = this.Defaults; // m_def might be null 297 298 // aceInt.UrlSchemeOverrides.SetDefaultsIfEmpty(); 299 300 ObfuscateCred(false); 301 ChangePathsRelAbs(true); 302 303 // Remove invalid columns 304 List<AceColumn> lColumns = aceMW.EntryListColumns; 305 int i = 0; 306 while(i < lColumns.Count) 307 { 308 if(((int)lColumns[i].Type < 0) || ((int)lColumns[i].Type >= 309 (int)AceColumnType.Count)) 310 lColumns.RemoveAt(i); 311 else ++i; 312 } 313 314 SearchUtil.FinishDeserialize(aceSearch.LastUsedProfile); 315 foreach(SearchParameters sp in aceSearch.UserProfiles) 316 SearchUtil.FinishDeserialize(sp); 317 318 DpiScale(); 319 320 if(aceMW.EscMinimizesToTray) // For backward compatibility 321 { 322 aceMW.EscMinimizesToTray = false; // Default value 323 aceMW.EscAction = AceEscAction.MinimizeToTray; 324 } 325 326 if(NativeLib.IsUnix()) 327 { 328 this.Security.MasterKeyOnSecureDesktop = false; 329 330 AceIntegration aceInt = this.Integration; 331 aceInt.HotKeyGlobalAutoType = (long)Keys.None; 332 aceInt.HotKeyGlobalAutoTypePassword = (long)Keys.None; 333 aceInt.HotKeySelectedAutoType = (long)Keys.None; 334 aceInt.HotKeyShowWindow = (long)Keys.None; 335 aceInt.HotKeyEntryMenu = (long)Keys.None; 336 } 337 338 if(MonoWorkarounds.IsRequired(1378)) 339 { 340 AceWorkspaceLocking aceWL = this.Security.WorkspaceLocking; 341 aceWL.LockOnSessionSwitch = false; 342 aceWL.LockOnSuspend = false; 343 aceWL.LockOnRemoteControlChange = false; 344 } 345 346 if(MonoWorkarounds.IsRequired(1418)) 347 { 348 aceMW.MinimizeAfterOpeningDatabase = false; 349 this.Application.Start.MinimizedAndLocked = false; 350 } 351 352 if(MonoWorkarounds.IsRequired(1976)) 353 { 354 aceMW.FocusQuickFindOnRestore = false; 355 aceMW.FocusQuickFindOnUntray = false; 356 } 357 } 358 OnSavePre()359 internal void OnSavePre() 360 { 361 PrepareSave(); 362 363 ChangePathsRelAbs(false); 364 ObfuscateCred(true); 365 RemoveSensitiveInfo(true); 366 } 367 OnSavePost()368 internal void OnSavePost() 369 { 370 RemoveSensitiveInfo(false); 371 ObfuscateCred(false); 372 ChangePathsRelAbs(true); 373 } 374 ChangePathsRelAbs(bool bMakeAbsolute)375 private void ChangePathsRelAbs(bool bMakeAbsolute) 376 { 377 AceApplication aceApp = this.Application; // m_aceApp might be null 378 AceDefaults aceDef = this.Defaults; // m_def might be null 379 380 ChangePathRelAbs(aceApp.LastUsedFile, bMakeAbsolute); 381 382 foreach(IOConnectionInfo iocMru in aceApp.MostRecentlyUsed.Items) 383 ChangePathRelAbs(iocMru, bMakeAbsolute); 384 385 List<string> lWDKeys = aceApp.GetWorkingDirectoryContexts(); 386 foreach(string strWDKey in lWDKeys) 387 aceApp.SetWorkingDirectory(strWDKey, ChangePathRelAbsStr( 388 aceApp.GetWorkingDirectory(strWDKey), bMakeAbsolute)); 389 390 foreach(AceKeyAssoc kfp in aceDef.KeySources) 391 { 392 kfp.DatabasePath = ChangePathRelAbsStr(kfp.DatabasePath, bMakeAbsolute); 393 kfp.KeyFilePath = ChangePathRelAbsStr(kfp.KeyFilePath, bMakeAbsolute); 394 } 395 } 396 ChangePathRelAbs(IOConnectionInfo ioc, bool bMakeAbsolute)397 private static void ChangePathRelAbs(IOConnectionInfo ioc, bool bMakeAbsolute) 398 { 399 if(ioc == null) { Debug.Assert(false); return; } 400 401 if(!ioc.IsLocalFile()) return; 402 403 // Update path separators for current system 404 ioc.Path = UrlUtil.ConvertSeparators(ioc.Path); 405 406 string strBase = WinUtil.GetExecutable(); 407 bool bIsAbs = UrlUtil.IsAbsolutePath(ioc.Path); 408 409 if(bMakeAbsolute && !bIsAbs) 410 ioc.Path = UrlUtil.MakeAbsolutePath(strBase, ioc.Path); 411 else if(!bMakeAbsolute && bIsAbs) 412 ioc.Path = UrlUtil.MakeRelativePath(strBase, ioc.Path); 413 } 414 ChangePathRelAbsStr(string strPath, bool bMakeAbsolute)415 private static string ChangePathRelAbsStr(string strPath, bool bMakeAbsolute) 416 { 417 if(strPath == null) { Debug.Assert(false); return string.Empty; } 418 if(strPath.Length == 0) return strPath; 419 420 IOConnectionInfo ioc = IOConnectionInfo.FromPath(strPath); 421 ChangePathRelAbs(ioc, bMakeAbsolute); 422 return ioc.Path; 423 } 424 ObfuscateCred(bool bObf)425 private void ObfuscateCred(bool bObf) 426 { 427 AceApplication aceApp = this.Application; // m_aceApp might be null 428 AceIntegration aceInt = this.Integration; // m_int might be null 429 430 if(aceApp.LastUsedFile == null) { Debug.Assert(false); } 431 else aceApp.LastUsedFile.Obfuscate(bObf); 432 433 foreach(IOConnectionInfo iocMru in aceApp.MostRecentlyUsed.Items) 434 { 435 if(iocMru == null) { Debug.Assert(false); } 436 else iocMru.Obfuscate(bObf); 437 } 438 439 if(bObf) aceInt.ProxyUserName = StrUtil.Obfuscate(aceInt.ProxyUserName); 440 else aceInt.ProxyUserName = StrUtil.Deobfuscate(aceInt.ProxyUserName); 441 442 if(bObf) aceInt.ProxyPassword = StrUtil.Obfuscate(aceInt.ProxyPassword); 443 else aceInt.ProxyPassword = StrUtil.Deobfuscate(aceInt.ProxyPassword); 444 } 445 RemoveSensitiveInfo(bool bRemove)446 private void RemoveSensitiveInfo(bool bRemove) 447 { 448 SearchParameters sp = this.Search.LastUsedProfile; 449 450 if(bRemove) 451 { 452 Debug.Assert(m_strSearchString == null); 453 m_strSearchString = sp.SearchString; 454 sp.SearchString = string.Empty; 455 } 456 else 457 { 458 if(m_strSearchString != null) 459 { 460 sp.SearchString = m_strSearchString; 461 m_strSearchString = null; 462 } 463 else { Debug.Assert(false); } 464 } 465 } 466 DpiScale()467 private void DpiScale() 468 { 469 AceMeta aceMeta = this.Meta; // m_meta might be null 470 double dCfgX = aceMeta.DpiFactorX, dCfgY = aceMeta.DpiFactorY; 471 double dScrX = DpiUtil.FactorX, dScrY = DpiUtil.FactorY; 472 473 if((dScrX == dCfgX) && (dScrY == dCfgY)) return; 474 475 // When this method returns, all positions and sizes are in pixels 476 // for the current screen DPI 477 aceMeta.DpiFactorX = dScrX; 478 aceMeta.DpiFactorY = dScrY; 479 480 // Backward compatibility; configuration files created by KeePass 481 // 2.37 and earlier do not contain DpiFactor* values, they default 482 // to 0.0 and all positions and sizes are in pixels for the current 483 // screen DPI; so, do not perform any DPI scaling in this case 484 if((dCfgX == 0.0) || (dCfgY == 0.0)) return; 485 486 double sX = dScrX / dCfgX, sY = dScrY / dCfgY; 487 GFunc<int, int> fX = delegate(int x) 488 { 489 return (int)Math.Round((double)x * sX); 490 }; 491 GFunc<int, int> fY = delegate(int y) 492 { 493 return (int)Math.Round((double)y * sY); 494 }; 495 GFunc<string, string> fWsr = delegate(string strRect) 496 { 497 return UIUtil.ScaleWindowScreenRect(strRect, sX, sY); 498 }; 499 GFunc<string, string> fVX = delegate(string strArray) 500 { 501 if(string.IsNullOrEmpty(strArray)) return strArray; 502 503 try 504 { 505 int[] v = StrUtil.DeserializeIntArray(strArray); 506 if(v == null) { Debug.Assert(false); return strArray; } 507 508 for(int i = 0; i < v.Length; ++i) 509 v[i] = (int)Math.Round((double)v[i] * sX); 510 511 return StrUtil.SerializeIntArray(v); 512 } 513 catch(Exception) { Debug.Assert(false); } 514 515 return strArray; 516 }; 517 Action<AceFont> fFont = delegate(AceFont f) 518 { 519 if(f == null) { Debug.Assert(false); return; } 520 521 if(f.GraphicsUnit == GraphicsUnit.Pixel) 522 f.Size = (float)(f.Size * sY); 523 }; 524 525 AceMainWindow mw = this.MainWindow; 526 AceUI ui = this.UI; 527 528 if(mw.X != AppDefs.InvalidWindowValue) mw.X = fX(mw.X); 529 if(mw.Y != AppDefs.InvalidWindowValue) mw.Y = fY(mw.Y); 530 if(mw.Width != AppDefs.InvalidWindowValue) mw.Width = fX(mw.Width); 531 if(mw.Height != AppDefs.InvalidWindowValue) mw.Height = fY(mw.Height); 532 533 foreach(AceColumn c in mw.EntryListColumns) 534 { 535 if(c.Width >= 0) c.Width = fX(c.Width); 536 } 537 538 ui.DataViewerRect = fWsr(ui.DataViewerRect); 539 ui.DataEditorRect = fWsr(ui.DataEditorRect); 540 ui.CharPickerRect = fWsr(ui.CharPickerRect); 541 ui.AutoTypeCtxRect = fWsr(ui.AutoTypeCtxRect); 542 ui.AutoTypeCtxColumnWidths = fVX(ui.AutoTypeCtxColumnWidths); 543 544 fFont(ui.StandardFont); 545 fFont(ui.PasswordFont); 546 fFont(ui.DataEditorFont); 547 } 548 549 private static Dictionary<object, string> m_dictXmlPathCache = 550 new Dictionary<object, string>(); IsOptionEnforced(object pContainer, PropertyInfo pi)551 public static bool IsOptionEnforced(object pContainer, PropertyInfo pi) 552 { 553 if(pContainer == null) { Debug.Assert(false); return false; } 554 if(pi == null) { Debug.Assert(false); return false; } 555 556 XmlDocument xdEnforced = AppConfigSerializer.EnforcedConfigXml; 557 if(xdEnforced == null) return false; 558 559 string strObjPath; 560 if(!m_dictXmlPathCache.TryGetValue(pContainer, out strObjPath)) 561 { 562 strObjPath = XmlUtil.GetObjectXmlPath(Program.Config, pContainer); 563 if(string.IsNullOrEmpty(strObjPath)) { Debug.Assert(false); return false; } 564 565 m_dictXmlPathCache[pContainer] = strObjPath; 566 } 567 568 string strProp = XmlSerializerEx.GetXmlName(pi); 569 if(string.IsNullOrEmpty(strProp)) { Debug.Assert(false); return false; } 570 571 string strPre = strObjPath; 572 if(!strPre.EndsWith("/")) strPre += "/"; 573 string strXPath = strPre + strProp; 574 575 XmlNode xn = xdEnforced.SelectSingleNode(strXPath); 576 if(xn == null) return false; 577 578 XmContext ctx = new XmContext(null, AppConfigEx.GetNodeOptions, 579 AppConfigEx.GetNodeKey); 580 return XmlUtil.IsAlwaysEnforced(xn, strXPath, ctx); 581 } 582 IsOptionEnforced(object pContainer, string strPropertyName)583 public static bool IsOptionEnforced(object pContainer, string strPropertyName) 584 { 585 if(pContainer == null) { Debug.Assert(false); return false; } 586 if(string.IsNullOrEmpty(strPropertyName)) { Debug.Assert(false); return false; } 587 588 // To improve performance (avoid type queries), check here, too 589 XmlDocument xdEnforced = AppConfigSerializer.EnforcedConfigXml; 590 if(xdEnforced == null) return false; 591 592 Type tContainer = pContainer.GetType(); 593 PropertyInfo pi = tContainer.GetProperty(strPropertyName); 594 return IsOptionEnforced(pContainer, pi); 595 } 596 ClearXmlPathCache()597 public static void ClearXmlPathCache() 598 { 599 m_dictXmlPathCache.Clear(); 600 } 601 Apply(AceApplyFlags f)602 public void Apply(AceApplyFlags f) 603 { 604 AceApplication aceApp = this.Application; // m_aceApp might be null 605 AceSecurity aceSec = this.Security; // m_sec might be null 606 AceIntegration aceInt = this.Integration; // m_int might be null 607 608 if((f & AceApplyFlags.Proxy) != AceApplyFlags.None) 609 IOConnection.SetProxy(aceInt.ProxyType, aceInt.ProxyAddress, 610 aceInt.ProxyPort, aceInt.ProxyAuthType, aceInt.ProxyUserName, 611 aceInt.ProxyPassword); 612 613 if((f & AceApplyFlags.Ssl) != AceApplyFlags.None) 614 IOConnection.SslCertsAcceptInvalid = aceSec.SslCertsAcceptInvalid; 615 616 if((f & AceApplyFlags.FileTransactions) != AceApplyFlags.None) 617 FileTransactionEx.ExtraSafe = aceApp.FileTxExtra; 618 } 619 GetNodeOptions(XmNodeOptions o, string strXPath)620 internal static void GetNodeOptions(XmNodeOptions o, string strXPath) 621 { 622 if(o == null) { Debug.Assert(false); return; } 623 if(string.IsNullOrEmpty(strXPath)) { Debug.Assert(false); return; } 624 Debug.Assert(strXPath.IndexOf('[') < 0); 625 626 switch(strXPath) 627 { 628 // Sync. with documentation 629 630 case "/Configuration/Application/PluginCompatibility": 631 case "/Configuration/Meta/DpiFactorX": 632 case "/Configuration/Meta/DpiFactorY": 633 o.NodeMode = XmNodeMode.None; 634 break; 635 636 case "/Configuration/Application/TriggerSystem/Triggers/Trigger": 637 case "/Configuration/Defaults/KeySources/Association": 638 case "/Configuration/PasswordGenerator/AutoGeneratedPasswordsProfile": 639 case "/Configuration/PasswordGenerator/LastUsedProfile": 640 case "/Configuration/PasswordGenerator/UserProfiles/Profile": 641 case "/Configuration/Search/LastUsedProfile": 642 case "/Configuration/Search/UserProfiles/Profile": 643 o.ContentMode = XmContentMode.Replace; 644 break; 645 646 // Nodes that do not have child elements: 647 // case "/Configuration/Application/WorkingDirectories/Item": 648 // case "/Configuration/Integration/AutoTypeAbortOnWindows/Window": 649 650 // Nodes where the mode 'Merge' may be more useful: 651 // case "/Configuration/Application/MostRecentlyUsed/Items/ConnectionInfo": 652 // (allow users to save credentials) 653 // case "/Configuration/Custom/Item": 654 // (empty Value explicitly only) 655 // case "/Configuration/Defaults/SearchParameters": 656 // (admin might only want to turn off case-sensitivity) 657 // case "/Configuration/Integration/UrlSchemeOverrides/CustomOverrides/Override": 658 // (allow users to enable/disable the item) 659 // case "/Configuration/MainWindow/EntryListColumnCollection/Column": 660 // (allow users to change the width) 661 662 default: break; 663 } 664 } 665 GetNodeKey(XmlNode xn, string strXPath)666 internal static string GetNodeKey(XmlNode xn, string strXPath) 667 { 668 if(xn == null) { Debug.Assert(false); return null; } 669 if(string.IsNullOrEmpty(strXPath)) { Debug.Assert(false); return null; } 670 671 Debug.Assert(xn is XmlElement); 672 Debug.Assert((strXPath == xn.Name) || strXPath.EndsWith("/" + xn.Name)); 673 Debug.Assert(strXPath.IndexOf('[') < 0); 674 675 string strA = null, strB = null; 676 switch(strXPath) 677 { 678 // Sync. with documentation 679 680 case "/Configuration/Application/PluginCompatibility/Item": 681 case "/Configuration/Application/WorkingDirectories/Item": 682 case "/Configuration/Integration/AutoTypeAbortOnWindows/Window": 683 strA = XmlUtil.SafeInnerXml(xn); 684 break; 685 686 case "/Configuration/Application/MostRecentlyUsed/Items/ConnectionInfo": 687 strA = XmlUtil.SafeInnerXml(xn, "Path"); 688 strB = XmlUtil.SafeInnerXml(xn, "UserName"); // Cf. MRU display name 689 break; 690 691 case "/Configuration/Application/TriggerSystem/Triggers/Trigger": 692 strA = XmlUtil.SafeInnerXml(xn, "Guid"); 693 break; 694 695 case "/Configuration/Custom/Item": 696 strA = XmlUtil.SafeInnerXml(xn, "Key"); 697 break; 698 699 case "/Configuration/Defaults/KeySources/Association": 700 strA = XmlUtil.SafeInnerXml(xn, "DatabasePath"); 701 break; 702 703 case "/Configuration/Integration/UrlSchemeOverrides/CustomOverrides/Override": 704 strA = XmlUtil.SafeInnerXml(xn, "Scheme"); 705 strB = XmlUtil.SafeInnerXml(xn, "UrlOverride"); 706 break; 707 708 case "/Configuration/MainWindow/EntryListColumnCollection/Column": 709 strA = XmlUtil.SafeInnerXml(xn, "Type"); 710 strB = XmlUtil.SafeInnerXml(xn, "CustomName"); 711 break; 712 713 case "/Configuration/PasswordGenerator/UserProfiles/Profile": 714 case "/Configuration/Search/UserProfiles/Profile": 715 strA = XmlUtil.SafeInnerXml(xn, "Name"); 716 break; 717 718 default: break; 719 } 720 721 Debug.Assert((strA == null) || (strA.IndexOf('<') < 0)); 722 Debug.Assert((strB == null) || (strB.IndexOf('<') < 0)); 723 Debug.Assert((strB == null) || (strA != null)); // B => A 724 Debug.Assert((strA == null) || (strA.Length != 0)); 725 726 if(strB != null) return ((strA ?? string.Empty) + " <> " + strB); 727 return strA; 728 } 729 GetEmptyConfigXml()730 internal static string GetEmptyConfigXml() 731 { 732 return ("<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" + 733 "<" + StrXmlTypeName + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\r\n" + 734 "\t<Meta />\r\n" + 735 "</" + StrXmlTypeName + ">"); 736 } 737 } 738 739 [Flags] 740 public enum AceApplyFlags 741 { 742 None = 0, 743 Proxy = 0x1, 744 Ssl = 0x2, 745 FileTransactions = 0x4, 746 747 All = 0x7FFF 748 } 749 750 public sealed class AceMeta 751 { AceMeta()752 public AceMeta() 753 { 754 } 755 756 private bool m_bPrefLocalCfg = false; 757 public bool PreferUserConfiguration 758 { 759 get { return m_bPrefLocalCfg; } 760 set { m_bPrefLocalCfg = value; } 761 } 762 763 // private bool m_bIsEnforced = false; 764 // [XmlIgnore] 765 // public bool IsEnforcedConfiguration 766 // { 767 // get { return m_bIsEnforced; } 768 // set { m_bIsEnforced = value; } 769 // } 770 771 private bool m_bOmitDefaultValues = true; 772 // Informational property only (like an XML comment); 773 // currently doesn't have any effect (the XmlSerializer 774 // always omits default values, independent of this 775 // property) 776 public bool OmitItemsWithDefaultValues 777 { 778 get { return m_bOmitDefaultValues; } 779 set { m_bOmitDefaultValues = value; } 780 } 781 782 private double m_dDpiFactorX = 0.0; // See AppConfigEx.DpiScale() 783 [DefaultValue(0.0)] 784 public double DpiFactorX 785 { 786 get { return m_dDpiFactorX; } 787 set { m_dDpiFactorX = value; } 788 } 789 790 private double m_dDpiFactorY = 0.0; // See AppConfigEx.DpiScale() 791 [DefaultValue(0.0)] 792 public double DpiFactorY 793 { 794 get { return m_dDpiFactorY; } 795 set { m_dDpiFactorY = value; } 796 } 797 } 798 } 799