complete merging of Keepass 2.35, fix auto-merge errors
This commit is contained in:
		@@ -96,13 +96,6 @@ namespace KeePassLib.Cryptography
 | 
			
		||||
				m_hash = null;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void Flush()
 | 
			
		||||
		{
 | 
			
		||||
			m_sBaseStream.Flush();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
#if KeePassRT
 | 
			
		||||
		protected override void Dispose(bool disposing)
 | 
			
		||||
		{
 | 
			
		||||
			if(disposing)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/*
 | 
			
		||||
  KeePass Password Safe - The Open-Source Password Manager
 | 
			
		||||
  Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
 | 
			
		||||
  Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
 | 
			
		||||
 | 
			
		||||
  This program is free software; you can redistribute it and/or modify
 | 
			
		||||
  it under the terms of the GNU General Public License as published by
 | 
			
		||||
@@ -19,14 +19,12 @@
 | 
			
		||||
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
 | 
			
		||||
#if !KeePassUAP
 | 
			
		||||
using System.Security.Cryptography;
 | 
			
		||||
#endif
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
using KeePassLib.Security;
 | 
			
		||||
using KeePassLib.Utility;
 | 
			
		||||
 | 
			
		||||
namespace KeePassLib.Cryptography.PasswordGenerator
 | 
			
		||||
{
 | 
			
		||||
@@ -48,58 +46,51 @@ namespace KeePassLib.Cryptography.PasswordGenerator
 | 
			
		||||
			CustomPwGeneratorPool pwAlgorithmPool)
 | 
			
		||||
		{
 | 
			
		||||
			Debug.Assert(pwProfile != null);
 | 
			
		||||
			if(pwProfile == null) throw new ArgumentNullException("pwProfile");
 | 
			
		||||
			if (pwProfile == null) throw new ArgumentNullException("pwProfile");
 | 
			
		||||
 | 
			
		||||
			CryptoRandomStream crs = CreateCryptoStream(pbUserEntropy);
 | 
			
		||||
			PwgError e = PwgError.Unknown;
 | 
			
		||||
			CryptoRandomStream crs = null;
 | 
			
		||||
			byte[] pbKey = null;
 | 
			
		||||
			try
 | 
			
		||||
			{
 | 
			
		||||
				crs = CreateRandomStream(pbUserEntropy, out pbKey);
 | 
			
		||||
 | 
			
		||||
			if(pwProfile.GeneratorType == PasswordGeneratorType.CharSet)
 | 
			
		||||
			if (pwProfile.GeneratorType == PasswordGeneratorType.CharSet)
 | 
			
		||||
				e = CharSetBasedGenerator.Generate(out psOut, pwProfile, crs);
 | 
			
		||||
			else if(pwProfile.GeneratorType == PasswordGeneratorType.Pattern)
 | 
			
		||||
			else if (pwProfile.GeneratorType == PasswordGeneratorType.Pattern)
 | 
			
		||||
				e = PatternBasedGenerator.Generate(out psOut, pwProfile, crs);
 | 
			
		||||
			else if(pwProfile.GeneratorType == PasswordGeneratorType.Custom)
 | 
			
		||||
			else if (pwProfile.GeneratorType == PasswordGeneratorType.Custom)
 | 
			
		||||
				e = GenerateCustom(out psOut, pwProfile, crs, pwAlgorithmPool);
 | 
			
		||||
			else { Debug.Assert(false); psOut = ProtectedString.Empty; }
 | 
			
		||||
			}
 | 
			
		||||
			finally
 | 
			
		||||
			{
 | 
			
		||||
				if(crs != null) crs.Dispose();
 | 
			
		||||
				if(pbKey != null) MemUtil.ZeroByteArray(pbKey);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return e;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private static CryptoRandomStream CreateRandomStream(byte[] pbAdditionalEntropy,
 | 
			
		||||
			out byte[] pbKey)
 | 
			
		||||
		private static CryptoRandomStream CreateCryptoStream(byte[] pbAdditionalEntropy)
 | 
			
		||||
		{
 | 
			
		||||
			pbKey = CryptoRandom.Instance.GetRandomBytes(256);
 | 
			
		||||
			byte[] pbKey = CryptoRandom.Instance.GetRandomBytes(128);
 | 
			
		||||
 | 
			
		||||
			// Mix in additional entropy
 | 
			
		||||
			if((pbAdditionalEntropy != null) && (pbAdditionalEntropy.Length > 0))
 | 
			
		||||
			Debug.Assert(pbKey.Length >= 64);
 | 
			
		||||
			if ((pbAdditionalEntropy != null) && (pbAdditionalEntropy.Length > 0))
 | 
			
		||||
			{
 | 
			
		||||
				for(int nKeyPos = 0; nKeyPos < pbKey.Length; ++nKeyPos)
 | 
			
		||||
					pbKey[nKeyPos] ^= pbAdditionalEntropy[nKeyPos % pbAdditionalEntropy.Length];
 | 
			
		||||
				using (SHA512Managed h = new SHA512Managed())
 | 
			
		||||
				{
 | 
			
		||||
					byte[] pbHash = h.ComputeHash(pbAdditionalEntropy);
 | 
			
		||||
					MemUtil.XorArray(pbHash, 0, pbKey, 0, pbHash.Length);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return new CryptoRandomStream(CrsAlgorithm.Salsa20, pbKey);
 | 
			
		||||
			return new CryptoRandomStream(CrsAlgorithm.ChaCha20, pbKey);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal static char GenerateCharacter(PwProfile pwProfile,
 | 
			
		||||
			PwCharSet pwCharSet, CryptoRandomStream crsRandomSource)
 | 
			
		||||
		{
 | 
			
		||||
			if(pwCharSet.Size == 0) return char.MinValue;
 | 
			
		||||
			if (pwCharSet.Size == 0) return char.MinValue;
 | 
			
		||||
 | 
			
		||||
			ulong uIndex = crsRandomSource.GetRandomUInt64();
 | 
			
		||||
			uIndex %= (ulong)pwCharSet.Size;
 | 
			
		||||
 | 
			
		||||
			char ch = pwCharSet[(uint)uIndex];
 | 
			
		||||
 | 
			
		||||
			if(pwProfile.NoRepeatingCharacters)
 | 
			
		||||
			if (pwProfile.NoRepeatingCharacters)
 | 
			
		||||
				pwCharSet.Remove(ch);
 | 
			
		||||
 | 
			
		||||
			return ch;
 | 
			
		||||
@@ -109,21 +100,21 @@ namespace KeePassLib.Cryptography.PasswordGenerator
 | 
			
		||||
		{
 | 
			
		||||
			pwCharSet.Remove(PwCharSet.Invalid);
 | 
			
		||||
 | 
			
		||||
			if(pwProfile.ExcludeLookAlike) pwCharSet.Remove(PwCharSet.LookAlike);
 | 
			
		||||
			if (pwProfile.ExcludeLookAlike) pwCharSet.Remove(PwCharSet.LookAlike);
 | 
			
		||||
 | 
			
		||||
			if(pwProfile.ExcludeCharacters.Length > 0)
 | 
			
		||||
			if (pwProfile.ExcludeCharacters.Length > 0)
 | 
			
		||||
				pwCharSet.Remove(pwProfile.ExcludeCharacters);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal static void ShufflePassword(char[] pPassword,
 | 
			
		||||
			CryptoRandomStream crsRandomSource)
 | 
			
		||||
		{
 | 
			
		||||
			Debug.Assert(pPassword != null); if(pPassword == null) return;
 | 
			
		||||
			Debug.Assert(crsRandomSource != null); if(crsRandomSource == null) return;
 | 
			
		||||
			Debug.Assert(pPassword != null); if (pPassword == null) return;
 | 
			
		||||
			Debug.Assert(crsRandomSource != null); if (crsRandomSource == null) return;
 | 
			
		||||
 | 
			
		||||
			if(pPassword.Length <= 1) return; // Nothing to shuffle
 | 
			
		||||
			if (pPassword.Length <= 1) return; // Nothing to shuffle
 | 
			
		||||
 | 
			
		||||
			for(int nSelect = 0; nSelect < pPassword.Length; ++nSelect)
 | 
			
		||||
			for (int nSelect = 0; nSelect < pPassword.Length; ++nSelect)
 | 
			
		||||
			{
 | 
			
		||||
				ulong uRandomIndex = crsRandomSource.GetRandomUInt64();
 | 
			
		||||
				uRandomIndex %= (ulong)(pPassword.Length - nSelect);
 | 
			
		||||
@@ -141,18 +132,18 @@ namespace KeePassLib.Cryptography.PasswordGenerator
 | 
			
		||||
			psOut = ProtectedString.Empty;
 | 
			
		||||
 | 
			
		||||
			Debug.Assert(pwProfile.GeneratorType == PasswordGeneratorType.Custom);
 | 
			
		||||
			if(pwAlgorithmPool == null) return PwgError.UnknownAlgorithm;
 | 
			
		||||
			if (pwAlgorithmPool == null) return PwgError.UnknownAlgorithm;
 | 
			
		||||
 | 
			
		||||
			string strID = pwProfile.CustomAlgorithmUuid;
 | 
			
		||||
			if(string.IsNullOrEmpty(strID)) { Debug.Assert(false); return PwgError.UnknownAlgorithm; }
 | 
			
		||||
			if (string.IsNullOrEmpty(strID)) { Debug.Assert(false); return PwgError.UnknownAlgorithm; }
 | 
			
		||||
 | 
			
		||||
			byte[] pbUuid = Convert.FromBase64String(strID);
 | 
			
		||||
			PwUuid uuid = new PwUuid(pbUuid);
 | 
			
		||||
			CustomPwGenerator pwg = pwAlgorithmPool.Find(uuid);
 | 
			
		||||
			if(pwg == null) { Debug.Assert(false); return PwgError.UnknownAlgorithm; }
 | 
			
		||||
			if (pwg == null) { Debug.Assert(false); return PwgError.UnknownAlgorithm; }
 | 
			
		||||
 | 
			
		||||
			ProtectedString pwd = pwg.Generate(pwProfile.CloneDeep(), crs);
 | 
			
		||||
			if(pwd == null) return PwgError.Unknown;
 | 
			
		||||
			if (pwd == null) return PwgError.Unknown;
 | 
			
		||||
 | 
			
		||||
			psOut = pwd;
 | 
			
		||||
			return PwgError.Success;
 | 
			
		||||
 
 | 
			
		||||
@@ -60,6 +60,7 @@
 | 
			
		||||
    </Reference>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Compile Include="Collections\ProtectedBinarySet.cs" />
 | 
			
		||||
    <Compile Include="Collections\VariantDictionary.cs" />
 | 
			
		||||
    <Compile Include="Cryptography\Cipher\ChaCha20Cipher.cs" />
 | 
			
		||||
    <Compile Include="Cryptography\Cipher\ChaCha20Engine.cs" />
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,8 @@
 | 
			
		||||
/*
 | 
			
		||||
  KeePass Password Safe - The Open-Source Password Manager
 | 
			
		||||
  Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
 | 
			
		||||
  Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
 | 
			
		||||
  
 | 
			
		||||
  Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
 | 
			
		||||
 | 
			
		||||
  This program is free software; you can redistribute it and/or modify
 | 
			
		||||
  it under the terms of the GNU General Public License as published by
 | 
			
		||||
@@ -41,7 +43,7 @@ namespace KeePassLib.Keys
 | 
			
		||||
		private ProtectedBinary m_pbKeyData = null;
 | 
			
		||||
 | 
			
		||||
		// Constant initialization vector (unique for KeePass)
 | 
			
		||||
		private static readonly byte[] m_pbEntropy = new byte[] {
 | 
			
		||||
		private static readonly byte[] m_pbEntropy = new byte[]{
 | 
			
		||||
			0xDE, 0x13, 0x5B, 0x5F, 0x18, 0xA3, 0x46, 0x70,
 | 
			
		||||
			0xB2, 0x57, 0x24, 0x29, 0x69, 0x88, 0x98, 0xE6
 | 
			
		||||
		};
 | 
			
		||||
@@ -63,22 +65,7 @@ namespace KeePassLib.Keys
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public KcpUserAccount()
 | 
			
		||||
		{
 | 
			
		||||
			// Test if ProtectedData is supported -- throws an exception
 | 
			
		||||
			// when running on an old system (Windows 98 / ME).
 | 
			
		||||
			byte[] pbDummyData = new byte[128];
 | 
			
		||||
			ProtectedData.Protect(pbDummyData, m_pbEntropy,
 | 
			
		||||
				DataProtectionScope.CurrentUser);
 | 
			
		||||
 | 
			
		||||
			byte[] pbKey = LoadUserKey(false);
 | 
			
		||||
			if(pbKey == null) pbKey = CreateUserKey();
 | 
			
		||||
			if(pbKey == null) // Should never happen
 | 
			
		||||
			{
 | 
			
		||||
				Debug.Assert(false);
 | 
			
		||||
				throw new SecurityException(KLRes.UserAccountKeyError);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			m_pbKeyData = new ProtectedBinary(true, pbKey);
 | 
			
		||||
			MemUtil.ZeroByteArray(pbKey);
 | 
			
		||||
			throw new NotSupportedException("DataProtection not supported on MonoForAndroid!");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// public void Clear()
 | 
			
		||||
@@ -88,8 +75,8 @@ namespace KeePassLib.Keys
 | 
			
		||||
 | 
			
		||||
		private static string GetUserKeyFilePath(bool bCreate)
 | 
			
		||||
		{
 | 
			
		||||
#if KeePassUAP
 | 
			
		||||
			string strUserDir = EnvironmentExt.AppDataRoamingFolderPath;
 | 
			
		||||
#if KeePassRT
 | 
			
		||||
			string strUserDir = Windows.Storage.ApplicationData.Current.RoamingFolder.Path;
 | 
			
		||||
#else
 | 
			
		||||
			string strUserDir = Environment.GetFolderPath(
 | 
			
		||||
				Environment.SpecialFolder.ApplicationData);
 | 
			
		||||
@@ -98,29 +85,26 @@ namespace KeePassLib.Keys
 | 
			
		||||
			strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false);
 | 
			
		||||
			strUserDir += PwDefs.ShortProductName;
 | 
			
		||||
 | 
			
		||||
			if(bCreate && !Directory.Exists(strUserDir))
 | 
			
		||||
			if (bCreate && !Directory.Exists(strUserDir))
 | 
			
		||||
				Directory.CreateDirectory(strUserDir);
 | 
			
		||||
 | 
			
		||||
			strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false);
 | 
			
		||||
			return (strUserDir + UserKeyFileName);
 | 
			
		||||
			return strUserDir + UserKeyFileName;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private static byte[] LoadUserKey(bool bThrow)
 | 
			
		||||
		private static byte[] LoadUserKey(bool bShowWarning)
 | 
			
		||||
		{
 | 
			
		||||
			byte[] pbKey = null;
 | 
			
		||||
 | 
			
		||||
#if !KeePassLibSD
 | 
			
		||||
			try
 | 
			
		||||
			{
 | 
			
		||||
				string strFilePath = GetUserKeyFilePath(false);
 | 
			
		||||
				byte[] pbProtectedKey = File.ReadAllBytes(strFilePath);
 | 
			
		||||
 | 
			
		||||
				pbKey = ProtectedData.Unprotect(pbProtectedKey, m_pbEntropy,
 | 
			
		||||
					DataProtectionScope.CurrentUser);
 | 
			
		||||
				throw new NotSupportedException("DataProtection not supported on MonoForAndroid!");
 | 
			
		||||
			}
 | 
			
		||||
			catch(Exception)
 | 
			
		||||
			catch (Exception exLoad)
 | 
			
		||||
			{
 | 
			
		||||
				if(bThrow) throw;
 | 
			
		||||
				if (bShowWarning) MessageService.ShowWarning(exLoad);
 | 
			
		||||
 | 
			
		||||
				pbKey = null;
 | 
			
		||||
			}
 | 
			
		||||
#endif
 | 
			
		||||
@@ -130,23 +114,17 @@ namespace KeePassLib.Keys
 | 
			
		||||
 | 
			
		||||
		private static byte[] CreateUserKey()
 | 
			
		||||
		{
 | 
			
		||||
#if KeePassLibSD
 | 
			
		||||
			return null;
 | 
			
		||||
#else
 | 
			
		||||
			string strFilePath = GetUserKeyFilePath(true);
 | 
			
		||||
			byte[] pbKey = null;
 | 
			
		||||
 | 
			
		||||
			byte[] pbRandomKey = CryptoRandom.Instance.GetRandomBytes(64);
 | 
			
		||||
			byte[] pbProtectedKey = ProtectedData.Protect(pbRandomKey,
 | 
			
		||||
				m_pbEntropy, DataProtectionScope.CurrentUser);
 | 
			
		||||
 | 
			
		||||
			File.WriteAllBytes(strFilePath, pbProtectedKey);
 | 
			
		||||
 | 
			
		||||
			byte[] pbKey = LoadUserKey(true);
 | 
			
		||||
			Debug.Assert(MemUtil.ArraysEqual(pbKey, pbRandomKey));
 | 
			
		||||
 | 
			
		||||
			MemUtil.ZeroByteArray(pbRandomKey);
 | 
			
		||||
			return pbKey;
 | 
			
		||||
#if !KeePassLibSD
 | 
			
		||||
			try
 | 
			
		||||
			{
 | 
			
		||||
				throw new NotSupportedException("DataProtection not supported on MonoForAndroid!");
 | 
			
		||||
			}
 | 
			
		||||
			catch (Exception) { pbKey = null; }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
			return pbKey;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,6 @@ namespace KeePassLib
 | 
			
		||||
		private PwUuid m_uuid = PwUuid.Zero;
 | 
			
		||||
		private PwGroup m_pParentGroup = null;
 | 
			
		||||
		private DateTime m_tParentGroupLastMod = PwDefs.DtDefaultNow;
 | 
			
		||||
		private string m_tParentGroupLastModLazy;
 | 
			
		||||
 | 
			
		||||
		private ProtectedStringDictionary m_listStrings = new ProtectedStringDictionary();
 | 
			
		||||
		private ProtectedBinaryDictionary m_listBinaries = new ProtectedBinaryDictionary();
 | 
			
		||||
@@ -59,12 +58,6 @@ namespace KeePassLib
 | 
			
		||||
		private DateTime m_tLastMod = PwDefs.DtDefaultNow;
 | 
			
		||||
		private DateTime m_tLastAccess = PwDefs.DtDefaultNow;
 | 
			
		||||
		private DateTime m_tExpire = PwDefs.DtDefaultNow;
 | 
			
		||||
 | 
			
		||||
		private string m_tCreationLazy;
 | 
			
		||||
		private string m_tLastModLazy;
 | 
			
		||||
		private string m_tLastAccessLazy;
 | 
			
		||||
		private string m_tExpireLazy;
 | 
			
		||||
 | 
			
		||||
		private bool m_bExpires = false;
 | 
			
		||||
		private ulong m_uUsageCount = 0;
 | 
			
		||||
 | 
			
		||||
@@ -82,7 +75,7 @@ namespace KeePassLib
 | 
			
		||||
			get { return m_uuid; }
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
 | 
			
		||||
				Debug.Assert(value != null); if (value == null) throw new ArgumentNullException("value");
 | 
			
		||||
				m_uuid = value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -103,14 +96,10 @@ namespace KeePassLib
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public DateTime LocationChanged
 | 
			
		||||
		{
 | 
			
		||||
			get { return GetLazyTime(ref m_tParentGroupLastModLazy, ref m_tParentGroupLastMod); }
 | 
			
		||||
			set { m_tParentGroupLastMod = value; m_tParentGroupLastModLazy = null; }
 | 
			
		||||
			get { return m_tParentGroupLastMod; }
 | 
			
		||||
			set { m_tParentGroupLastMod = value; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void SetLazyLocationChanged(string xmlDateTime)
 | 
			
		||||
		{
 | 
			
		||||
			m_tParentGroupLastModLazy = xmlDateTime;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Get or set all entry strings.
 | 
			
		||||
@@ -120,7 +109,7 @@ namespace KeePassLib
 | 
			
		||||
			get { return m_listStrings; }
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
 | 
			
		||||
				Debug.Assert(value != null); if (value == null) throw new ArgumentNullException("value");
 | 
			
		||||
				m_listStrings = value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -133,7 +122,7 @@ namespace KeePassLib
 | 
			
		||||
			get { return m_listBinaries; }
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
 | 
			
		||||
				Debug.Assert(value != null); if (value == null) throw new ArgumentNullException("value");
 | 
			
		||||
				m_listBinaries = value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -146,7 +135,7 @@ namespace KeePassLib
 | 
			
		||||
			get { return m_listAutoType; }
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
 | 
			
		||||
				Debug.Assert(value != null); if (value == null) throw new ArgumentNullException("value");
 | 
			
		||||
				m_listAutoType = value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -159,7 +148,7 @@ namespace KeePassLib
 | 
			
		||||
			get { return m_listHistory; }
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
 | 
			
		||||
				Debug.Assert(value != null); if (value == null) throw new ArgumentNullException("value");
 | 
			
		||||
				m_listHistory = value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -183,7 +172,7 @@ namespace KeePassLib
 | 
			
		||||
			get { return m_pwCustomIconID; }
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
 | 
			
		||||
				Debug.Assert(value != null); if (value == null) throw new ArgumentNullException("value");
 | 
			
		||||
				m_pwCustomIconID = value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -211,27 +200,8 @@ namespace KeePassLib
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public DateTime CreationTime
 | 
			
		||||
		{
 | 
			
		||||
			get { return GetLazyTime(ref m_tCreationLazy, ref m_tCreation); }
 | 
			
		||||
			set { m_tCreation = value; m_tCreationLazy = null; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void SetLazyCreationTime(string xmlDateTime)
 | 
			
		||||
		{
 | 
			
		||||
			m_tCreationLazy = xmlDateTime;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// The date/time when this entry was last accessed (read).
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public DateTime LastAccessTime
 | 
			
		||||
		{
 | 
			
		||||
			get { return GetLazyTime(ref m_tLastAccessLazy, ref m_tLastAccess); }
 | 
			
		||||
			set { m_tLastAccess = value; m_tLastAccessLazy = null; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void SetLazyLastAccessTime(string xmlDateTime)
 | 
			
		||||
		{
 | 
			
		||||
			m_tLastAccessLazy = xmlDateTime;
 | 
			
		||||
			get { return m_tCreation; }
 | 
			
		||||
			set { m_tCreation = value; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -239,13 +209,17 @@ namespace KeePassLib
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public DateTime LastModificationTime
 | 
			
		||||
		{
 | 
			
		||||
			get { return GetLazyTime(ref m_tLastModLazy, ref m_tLastMod); }
 | 
			
		||||
			set { m_tLastMod = value; m_tLastModLazy = null; }
 | 
			
		||||
			get { return m_tLastMod; }
 | 
			
		||||
			set { m_tLastMod = value; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void SetLazyLastModificationTime(string xmlDateTime)
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// The date/time when this entry was last accessed (read).
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public DateTime LastAccessTime
 | 
			
		||||
		{
 | 
			
		||||
			m_tLastModLazy = xmlDateTime;
 | 
			
		||||
			get { return m_tLastAccess; }
 | 
			
		||||
			set { m_tLastAccess = value; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -254,13 +228,8 @@ namespace KeePassLib
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public DateTime ExpiryTime
 | 
			
		||||
		{
 | 
			
		||||
			get { return GetLazyTime(ref m_tExpireLazy, ref m_tExpire); }
 | 
			
		||||
			set { m_tExpire = value; m_tExpireLazy = null; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void SetLazyExpiryTime(string xmlDateTime)
 | 
			
		||||
		{
 | 
			
		||||
			m_tExpireLazy = xmlDateTime;
 | 
			
		||||
			get { return m_tExpire; }
 | 
			
		||||
			set { m_tExpire = value; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -290,7 +259,7 @@ namespace KeePassLib
 | 
			
		||||
			get { return m_strOverrideUrl; }
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				if(value == null) throw new ArgumentNullException("value");
 | 
			
		||||
				if (value == null) throw new ArgumentNullException("value");
 | 
			
		||||
				m_strOverrideUrl = value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -303,7 +272,7 @@ namespace KeePassLib
 | 
			
		||||
			get { return m_vTags; }
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				if(value == null) throw new ArgumentNullException("value");
 | 
			
		||||
				if (value == null) throw new ArgumentNullException("value");
 | 
			
		||||
				m_vTags = value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -320,7 +289,7 @@ namespace KeePassLib
 | 
			
		||||
			get { return m_dCustomData; }
 | 
			
		||||
			internal set
 | 
			
		||||
			{
 | 
			
		||||
				if(value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); }
 | 
			
		||||
				if (value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); }
 | 
			
		||||
				m_dCustomData = value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -339,9 +308,9 @@ namespace KeePassLib
 | 
			
		||||
		/// and last access times will be set to the current system time.</param>
 | 
			
		||||
		public PwEntry(bool bCreateNewUuid, bool bSetTimes)
 | 
			
		||||
		{
 | 
			
		||||
			if(bCreateNewUuid) m_uuid = new PwUuid(true);
 | 
			
		||||
			if (bCreateNewUuid) m_uuid = new PwUuid(true);
 | 
			
		||||
 | 
			
		||||
			if(bSetTimes)
 | 
			
		||||
			if (bSetTimes)
 | 
			
		||||
			{
 | 
			
		||||
				DateTime dtNow = DateTime.UtcNow;
 | 
			
		||||
				m_tCreation = dtNow;
 | 
			
		||||
@@ -367,9 +336,9 @@ namespace KeePassLib
 | 
			
		||||
		{
 | 
			
		||||
			m_pParentGroup = pwParentGroup;
 | 
			
		||||
 | 
			
		||||
			if(bCreateNewUuid) m_uuid = new PwUuid(true);
 | 
			
		||||
			if (bCreateNewUuid) m_uuid = new PwUuid(true);
 | 
			
		||||
 | 
			
		||||
			if(bSetTimes)
 | 
			
		||||
			if (bSetTimes)
 | 
			
		||||
			{
 | 
			
		||||
				DateTime dtNow = DateTime.UtcNow;
 | 
			
		||||
				m_tCreation = dtNow;
 | 
			
		||||
@@ -400,7 +369,6 @@ namespace KeePassLib
 | 
			
		||||
			peNew.m_uuid = m_uuid; // PwUuid is immutable
 | 
			
		||||
			peNew.m_pParentGroup = m_pParentGroup;
 | 
			
		||||
			peNew.m_tParentGroupLastMod = m_tParentGroupLastMod;
 | 
			
		||||
			peNew.m_tParentGroupLastModLazy = m_tParentGroupLastModLazy;
 | 
			
		||||
 | 
			
		||||
			peNew.m_listStrings = m_listStrings.CloneDeep();
 | 
			
		||||
			peNew.m_listBinaries = m_listBinaries.CloneDeep();
 | 
			
		||||
@@ -419,11 +387,6 @@ namespace KeePassLib
 | 
			
		||||
			peNew.m_tExpire = m_tExpire;
 | 
			
		||||
			peNew.m_bExpires = m_bExpires;
 | 
			
		||||
			peNew.m_uUsageCount = m_uUsageCount;
 | 
			
		||||
			
 | 
			
		||||
			peNew.m_tCreationLazy = m_tCreationLazy;
 | 
			
		||||
			peNew.m_tLastModLazy = m_tLastModLazy;
 | 
			
		||||
			peNew.m_tLastAccessLazy = m_tLastAccessLazy;
 | 
			
		||||
			peNew.m_tExpireLazy = m_tExpireLazy;
 | 
			
		||||
 | 
			
		||||
			peNew.m_strOverrideUrl = m_strOverrideUrl;
 | 
			
		||||
 | 
			
		||||
@@ -440,7 +403,6 @@ namespace KeePassLib
 | 
			
		||||
 | 
			
		||||
			peNew.m_uuid = m_uuid; // PwUuid is immutable
 | 
			
		||||
			peNew.m_tParentGroupLastMod = m_tParentGroupLastMod;
 | 
			
		||||
			peNew.m_tParentGroupLastModLazy = m_tParentGroupLastModLazy;
 | 
			
		||||
			// Do not assign m_pParentGroup
 | 
			
		||||
 | 
			
		||||
			return peNew;
 | 
			
		||||
@@ -451,11 +413,11 @@ namespace KeePassLib
 | 
			
		||||
			bool bIgnoreThisLastBackup)
 | 
			
		||||
		{
 | 
			
		||||
			PwCompareOptions pwOpt = PwCompareOptions.None;
 | 
			
		||||
			if(bIgnoreParentGroup) pwOpt |= PwCompareOptions.IgnoreParentGroup;
 | 
			
		||||
			if(bIgnoreLastMod) pwOpt |= PwCompareOptions.IgnoreLastMod;
 | 
			
		||||
			if(bIgnoreLastAccess) pwOpt |= PwCompareOptions.IgnoreLastAccess;
 | 
			
		||||
			if(bIgnoreHistory) pwOpt |= PwCompareOptions.IgnoreHistory;
 | 
			
		||||
			if(bIgnoreThisLastBackup) pwOpt |= PwCompareOptions.IgnoreLastBackup;
 | 
			
		||||
			if (bIgnoreParentGroup) pwOpt |= PwCompareOptions.IgnoreParentGroup;
 | 
			
		||||
			if (bIgnoreLastMod) pwOpt |= PwCompareOptions.IgnoreLastMod;
 | 
			
		||||
			if (bIgnoreLastAccess) pwOpt |= PwCompareOptions.IgnoreLastAccess;
 | 
			
		||||
			if (bIgnoreHistory) pwOpt |= PwCompareOptions.IgnoreHistory;
 | 
			
		||||
			if (bIgnoreThisLastBackup) pwOpt |= PwCompareOptions.IgnoreLastBackup;
 | 
			
		||||
			return pwOpt;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -480,7 +442,7 @@ namespace KeePassLib
 | 
			
		||||
		public bool EqualsEntry(PwEntry pe, PwCompareOptions pwOpt,
 | 
			
		||||
			MemProtCmpMode mpCmpStr)
 | 
			
		||||
		{
 | 
			
		||||
			if(pe == null) { Debug.Assert(false); return false; }
 | 
			
		||||
			if (pe == null) { Debug.Assert(false); return false; }
 | 
			
		||||
 | 
			
		||||
			bool bNeEqStd = ((pwOpt & PwCompareOptions.NullEmptyEquivStd) !=
 | 
			
		||||
				PwCompareOptions.None);
 | 
			
		||||
@@ -489,70 +451,70 @@ namespace KeePassLib
 | 
			
		||||
			bool bIgnoreLastMod = ((pwOpt & PwCompareOptions.IgnoreLastMod) !=
 | 
			
		||||
				PwCompareOptions.None);
 | 
			
		||||
 | 
			
		||||
			if(!m_uuid.Equals(pe.m_uuid)) return false;
 | 
			
		||||
			if((pwOpt & PwCompareOptions.IgnoreParentGroup) == PwCompareOptions.None)
 | 
			
		||||
			if (!m_uuid.Equals(pe.m_uuid)) return false;
 | 
			
		||||
			if ((pwOpt & PwCompareOptions.IgnoreParentGroup) == PwCompareOptions.None)
 | 
			
		||||
			{
 | 
			
		||||
				if(m_pParentGroup != pe.m_pParentGroup) return false;
 | 
			
		||||
				if(!bIgnoreLastMod && (LocationChanged != pe.LocationChanged))
 | 
			
		||||
				if (m_pParentGroup != pe.m_pParentGroup) return false;
 | 
			
		||||
				if (!bIgnoreLastMod && (m_tParentGroupLastMod != pe.m_tParentGroupLastMod))
 | 
			
		||||
					return false;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if(!m_listStrings.EqualsDictionary(pe.m_listStrings, pwOpt, mpCmpStr))
 | 
			
		||||
			if (!m_listStrings.EqualsDictionary(pe.m_listStrings, pwOpt, mpCmpStr))
 | 
			
		||||
				return false;
 | 
			
		||||
			if(!m_listBinaries.EqualsDictionary(pe.m_listBinaries)) return false;
 | 
			
		||||
			if (!m_listBinaries.EqualsDictionary(pe.m_listBinaries)) return false;
 | 
			
		||||
 | 
			
		||||
			if(!m_listAutoType.Equals(pe.m_listAutoType)) return false;
 | 
			
		||||
			if (!m_listAutoType.Equals(pe.m_listAutoType)) return false;
 | 
			
		||||
 | 
			
		||||
			if((pwOpt & PwCompareOptions.IgnoreHistory) == PwCompareOptions.None)
 | 
			
		||||
			if ((pwOpt & PwCompareOptions.IgnoreHistory) == PwCompareOptions.None)
 | 
			
		||||
			{
 | 
			
		||||
				bool bIgnoreLastBackup = ((pwOpt & PwCompareOptions.IgnoreLastBackup) !=
 | 
			
		||||
					PwCompareOptions.None);
 | 
			
		||||
 | 
			
		||||
				if(!bIgnoreLastBackup && (m_listHistory.UCount != pe.m_listHistory.UCount))
 | 
			
		||||
				if (!bIgnoreLastBackup && (m_listHistory.UCount != pe.m_listHistory.UCount))
 | 
			
		||||
					return false;
 | 
			
		||||
				if(bIgnoreLastBackup && (m_listHistory.UCount == 0))
 | 
			
		||||
				if (bIgnoreLastBackup && (m_listHistory.UCount == 0))
 | 
			
		||||
				{
 | 
			
		||||
					Debug.Assert(false);
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				if(bIgnoreLastBackup && ((m_listHistory.UCount - 1) != pe.m_listHistory.UCount))
 | 
			
		||||
				if (bIgnoreLastBackup && ((m_listHistory.UCount - 1) != pe.m_listHistory.UCount))
 | 
			
		||||
					return false;
 | 
			
		||||
 | 
			
		||||
				PwCompareOptions cmpSub = PwCompareOptions.IgnoreParentGroup;
 | 
			
		||||
				if(bNeEqStd) cmpSub |= PwCompareOptions.NullEmptyEquivStd;
 | 
			
		||||
				if(bIgnoreLastMod) cmpSub |= PwCompareOptions.IgnoreLastMod;
 | 
			
		||||
				if(bIgnoreLastAccess) cmpSub |= PwCompareOptions.IgnoreLastAccess;
 | 
			
		||||
				if (bNeEqStd) cmpSub |= PwCompareOptions.NullEmptyEquivStd;
 | 
			
		||||
				if (bIgnoreLastMod) cmpSub |= PwCompareOptions.IgnoreLastMod;
 | 
			
		||||
				if (bIgnoreLastAccess) cmpSub |= PwCompareOptions.IgnoreLastAccess;
 | 
			
		||||
 | 
			
		||||
				for(uint uHist = 0; uHist < pe.m_listHistory.UCount; ++uHist)
 | 
			
		||||
				for (uint uHist = 0; uHist < pe.m_listHistory.UCount; ++uHist)
 | 
			
		||||
				{
 | 
			
		||||
					if(!m_listHistory.GetAt(uHist).EqualsEntry(pe.m_listHistory.GetAt(
 | 
			
		||||
					if (!m_listHistory.GetAt(uHist).EqualsEntry(pe.m_listHistory.GetAt(
 | 
			
		||||
						uHist), cmpSub, MemProtCmpMode.None))
 | 
			
		||||
						return false;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if(m_pwIcon != pe.m_pwIcon) return false;
 | 
			
		||||
			if(!m_pwCustomIconID.Equals(pe.m_pwCustomIconID)) return false;
 | 
			
		||||
			if (m_pwIcon != pe.m_pwIcon) return false;
 | 
			
		||||
			if (!m_pwCustomIconID.Equals(pe.m_pwCustomIconID)) return false;
 | 
			
		||||
 | 
			
		||||
			if(m_clrForeground != pe.m_clrForeground) return false;
 | 
			
		||||
			if(m_clrBackground != pe.m_clrBackground) return false;
 | 
			
		||||
			if (m_clrForeground != pe.m_clrForeground) return false;
 | 
			
		||||
			if (m_clrBackground != pe.m_clrBackground) return false;
 | 
			
		||||
 | 
			
		||||
			if(CreationTime != pe.CreationTime) return false;
 | 
			
		||||
			if(!bIgnoreLastMod && (LastModificationTime != pe.LastModificationTime)) return false;
 | 
			
		||||
			if(!bIgnoreLastAccess && (LastAccessTime != pe.LastAccessTime)) return false;
 | 
			
		||||
			if(ExpiryTime != pe.ExpiryTime) return false;
 | 
			
		||||
			if(m_bExpires != pe.m_bExpires) return false;
 | 
			
		||||
			if(!bIgnoreLastAccess && (m_uUsageCount != pe.m_uUsageCount)) return false;
 | 
			
		||||
			if (m_tCreation != pe.m_tCreation) return false;
 | 
			
		||||
			if (!bIgnoreLastMod && (m_tLastMod != pe.m_tLastMod)) return false;
 | 
			
		||||
			if (!bIgnoreLastAccess && (m_tLastAccess != pe.m_tLastAccess)) return false;
 | 
			
		||||
			if (m_tExpire != pe.m_tExpire) return false;
 | 
			
		||||
			if (m_bExpires != pe.m_bExpires) return false;
 | 
			
		||||
			if (!bIgnoreLastAccess && (m_uUsageCount != pe.m_uUsageCount)) return false;
 | 
			
		||||
 | 
			
		||||
			if(m_strOverrideUrl != pe.m_strOverrideUrl) return false;
 | 
			
		||||
			if (m_strOverrideUrl != pe.m_strOverrideUrl) return false;
 | 
			
		||||
 | 
			
		||||
			if(m_vTags.Count != pe.m_vTags.Count) return false;
 | 
			
		||||
			for(int iTag = 0; iTag < m_vTags.Count; ++iTag)
 | 
			
		||||
			if (m_vTags.Count != pe.m_vTags.Count) return false;
 | 
			
		||||
			for (int iTag = 0; iTag < m_vTags.Count; ++iTag)
 | 
			
		||||
			{
 | 
			
		||||
				if(m_vTags[iTag] != pe.m_vTags[iTag]) return false;
 | 
			
		||||
				if (m_vTags[iTag] != pe.m_vTags[iTag]) return false;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if(!m_dCustomData.Equals(pe.m_dCustomData)) return false;
 | 
			
		||||
			if (!m_dCustomData.Equals(pe.m_dCustomData)) return false;
 | 
			
		||||
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
@@ -570,21 +532,23 @@ namespace KeePassLib
 | 
			
		||||
		public void AssignProperties(PwEntry peTemplate, bool bOnlyIfNewer,
 | 
			
		||||
			bool bIncludeHistory, bool bAssignLocationChanged)
 | 
			
		||||
		{
 | 
			
		||||
			if(peTemplate == null) { Debug.Assert(false); throw new ArgumentNullException("peTemplate"); }
 | 
			
		||||
			if (peTemplate == null) { Debug.Assert(false); throw new ArgumentNullException("peTemplate"); }
 | 
			
		||||
 | 
			
		||||
			if(bOnlyIfNewer && (TimeUtil.Compare(peTemplate.LastModificationTime,LastModificationTime,true) < 0)) return;
 | 
			
		||||
			if (bOnlyIfNewer && (TimeUtil.Compare(peTemplate.m_tLastMod,
 | 
			
		||||
				m_tLastMod, true) < 0))
 | 
			
		||||
				return;
 | 
			
		||||
 | 
			
		||||
			// Template UUID should be the same as the current one
 | 
			
		||||
			Debug.Assert(m_uuid.Equals(peTemplate.m_uuid));
 | 
			
		||||
			m_uuid = peTemplate.m_uuid;
 | 
			
		||||
 | 
			
		||||
			if(bAssignLocationChanged)
 | 
			
		||||
				m_tParentGroupLastMod = peTemplate.LocationChanged;
 | 
			
		||||
			if (bAssignLocationChanged)
 | 
			
		||||
				m_tParentGroupLastMod = peTemplate.m_tParentGroupLastMod;
 | 
			
		||||
 | 
			
		||||
			m_listStrings = peTemplate.m_listStrings.CloneDeep();
 | 
			
		||||
			m_listBinaries = peTemplate.m_listBinaries.CloneDeep();
 | 
			
		||||
			m_listAutoType = peTemplate.m_listAutoType.CloneDeep();
 | 
			
		||||
			if(bIncludeHistory)
 | 
			
		||||
			if (bIncludeHistory)
 | 
			
		||||
				m_listHistory = peTemplate.m_listHistory.CloneDeep();
 | 
			
		||||
 | 
			
		||||
			m_pwIcon = peTemplate.m_pwIcon;
 | 
			
		||||
@@ -593,10 +557,10 @@ namespace KeePassLib
 | 
			
		||||
			m_clrForeground = peTemplate.m_clrForeground;
 | 
			
		||||
			m_clrBackground = peTemplate.m_clrBackground;
 | 
			
		||||
 | 
			
		||||
			m_tCreation = peTemplate.CreationTime;
 | 
			
		||||
			m_tLastMod = peTemplate.LastModificationTime;
 | 
			
		||||
			m_tLastAccess = peTemplate.LastAccessTime;
 | 
			
		||||
			m_tExpire = peTemplate.ExpiryTime;
 | 
			
		||||
			m_tCreation = peTemplate.m_tCreation;
 | 
			
		||||
			m_tLastMod = peTemplate.m_tLastMod;
 | 
			
		||||
			m_tLastAccess = peTemplate.m_tLastAccess;
 | 
			
		||||
			m_tExpire = peTemplate.m_tExpire;
 | 
			
		||||
			m_bExpires = peTemplate.m_bExpires;
 | 
			
		||||
			m_uUsageCount = peTemplate.m_uUsageCount;
 | 
			
		||||
 | 
			
		||||
@@ -631,16 +595,16 @@ namespace KeePassLib
 | 
			
		||||
			m_tLastAccess = DateTime.UtcNow;
 | 
			
		||||
			++m_uUsageCount;
 | 
			
		||||
 | 
			
		||||
			if(bModified) m_tLastMod = m_tLastAccess;
 | 
			
		||||
			if (bModified) m_tLastMod = m_tLastAccess;
 | 
			
		||||
 | 
			
		||||
			if(this.Touched != null)
 | 
			
		||||
			if (this.Touched != null)
 | 
			
		||||
				this.Touched(this, new ObjectTouchedEventArgs(this,
 | 
			
		||||
					bModified, bTouchParents));
 | 
			
		||||
			if(PwEntry.EntryTouched != null)
 | 
			
		||||
			if (PwEntry.EntryTouched != null)
 | 
			
		||||
				PwEntry.EntryTouched(this, new ObjectTouchedEventArgs(this,
 | 
			
		||||
					bModified, bTouchParents));
 | 
			
		||||
 | 
			
		||||
			if(bTouchParents && (m_pParentGroup != null))
 | 
			
		||||
			if (bTouchParents && (m_pParentGroup != null))
 | 
			
		||||
				m_pParentGroup.Touch(bModified, true);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -669,7 +633,7 @@ namespace KeePassLib
 | 
			
		||||
 | 
			
		||||
			m_listHistory.Add(peCopy); // Must be added at end, see EqualsEntry
 | 
			
		||||
 | 
			
		||||
			if(pwHistMntcSettings != null) MaintainBackups(pwHistMntcSettings);
 | 
			
		||||
			if (pwHistMntcSettings != null) MaintainBackups(pwHistMntcSettings);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -695,11 +659,11 @@ namespace KeePassLib
 | 
			
		||||
		public void RestoreFromBackup(uint uBackupIndex, PwDatabase pwHistMntcSettings)
 | 
			
		||||
		{
 | 
			
		||||
			Debug.Assert(uBackupIndex < m_listHistory.UCount);
 | 
			
		||||
			if(uBackupIndex >= m_listHistory.UCount)
 | 
			
		||||
			if (uBackupIndex >= m_listHistory.UCount)
 | 
			
		||||
				throw new ArgumentOutOfRangeException("uBackupIndex");
 | 
			
		||||
 | 
			
		||||
			PwEntry pe = m_listHistory.GetAt(uBackupIndex);
 | 
			
		||||
			Debug.Assert(pe != null); if(pe == null) throw new InvalidOperationException();
 | 
			
		||||
			Debug.Assert(pe != null); if (pe == null) throw new InvalidOperationException();
 | 
			
		||||
 | 
			
		||||
			CreateBackup(pwHistMntcSettings); // Backup current data before restoring
 | 
			
		||||
			AssignProperties(pe, false, false, false);
 | 
			
		||||
@@ -708,16 +672,16 @@ namespace KeePassLib
 | 
			
		||||
		public bool HasBackupOfData(PwEntry peData, bool bIgnoreLastMod,
 | 
			
		||||
			bool bIgnoreLastAccess)
 | 
			
		||||
		{
 | 
			
		||||
			if(peData == null) { Debug.Assert(false); return false; }
 | 
			
		||||
			if (peData == null) { Debug.Assert(false); return false; }
 | 
			
		||||
 | 
			
		||||
			PwCompareOptions cmpOpt = (PwCompareOptions.IgnoreParentGroup |
 | 
			
		||||
				PwCompareOptions.IgnoreHistory | PwCompareOptions.NullEmptyEquivStd);
 | 
			
		||||
			if(bIgnoreLastMod) cmpOpt |= PwCompareOptions.IgnoreLastMod;
 | 
			
		||||
			if(bIgnoreLastAccess) cmpOpt |= PwCompareOptions.IgnoreLastAccess;
 | 
			
		||||
			if (bIgnoreLastMod) cmpOpt |= PwCompareOptions.IgnoreLastMod;
 | 
			
		||||
			if (bIgnoreLastAccess) cmpOpt |= PwCompareOptions.IgnoreLastAccess;
 | 
			
		||||
 | 
			
		||||
			foreach(PwEntry pe in m_listHistory)
 | 
			
		||||
			foreach (PwEntry pe in m_listHistory)
 | 
			
		||||
			{
 | 
			
		||||
				if(pe.EqualsEntry(peData, cmpOpt, MemProtCmpMode.None)) return true;
 | 
			
		||||
				if (pe.EqualsEntry(peData, cmpOpt, MemProtCmpMode.None)) return true;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return false;
 | 
			
		||||
@@ -731,14 +695,14 @@ namespace KeePassLib
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public bool MaintainBackups(PwDatabase pwSettings)
 | 
			
		||||
		{
 | 
			
		||||
			if(pwSettings == null) { Debug.Assert(false); return false; }
 | 
			
		||||
			if (pwSettings == null) { Debug.Assert(false); return false; }
 | 
			
		||||
 | 
			
		||||
			bool bDeleted = false;
 | 
			
		||||
 | 
			
		||||
			int nMaxItems = pwSettings.HistoryMaxItems;
 | 
			
		||||
			if(nMaxItems >= 0)
 | 
			
		||||
			if (nMaxItems >= 0)
 | 
			
		||||
			{
 | 
			
		||||
				while(m_listHistory.UCount > (uint)nMaxItems)
 | 
			
		||||
				while (m_listHistory.UCount > (uint)nMaxItems)
 | 
			
		||||
				{
 | 
			
		||||
					RemoveOldestBackup();
 | 
			
		||||
					bDeleted = true;
 | 
			
		||||
@@ -746,14 +710,14 @@ namespace KeePassLib
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			long lMaxSize = pwSettings.HistoryMaxSize;
 | 
			
		||||
			if(lMaxSize >= 0)
 | 
			
		||||
			if (lMaxSize >= 0)
 | 
			
		||||
			{
 | 
			
		||||
				while(true)
 | 
			
		||||
				while (true)
 | 
			
		||||
				{
 | 
			
		||||
					ulong uHistSize = 0;
 | 
			
		||||
					foreach(PwEntry pe in m_listHistory) { uHistSize += pe.GetSize(); }
 | 
			
		||||
					foreach (PwEntry pe in m_listHistory) { uHistSize += pe.GetSize(); }
 | 
			
		||||
 | 
			
		||||
					if(uHistSize > (ulong)lMaxSize)
 | 
			
		||||
					if (uHistSize > (ulong)lMaxSize)
 | 
			
		||||
					{
 | 
			
		||||
						RemoveOldestBackup();
 | 
			
		||||
						bDeleted = true;
 | 
			
		||||
@@ -770,24 +734,24 @@ namespace KeePassLib
 | 
			
		||||
			DateTime dtMin = TimeUtil.SafeMaxValueUtc;
 | 
			
		||||
			uint idxRemove = uint.MaxValue;
 | 
			
		||||
 | 
			
		||||
			for(uint u = 0; u < m_listHistory.UCount; ++u)
 | 
			
		||||
			for (uint u = 0; u < m_listHistory.UCount; ++u)
 | 
			
		||||
			{
 | 
			
		||||
				PwEntry pe = m_listHistory.GetAt(u);
 | 
			
		||||
				if(TimeUtil.Compare(pe.LastModificationTime, dtMin, true) < 0)
 | 
			
		||||
				if (TimeUtil.Compare(pe.LastModificationTime, dtMin, true) < 0)
 | 
			
		||||
				{
 | 
			
		||||
					idxRemove = u;
 | 
			
		||||
					dtMin = pe.LastModificationTime;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if(idxRemove != uint.MaxValue) m_listHistory.RemoveAt(idxRemove);
 | 
			
		||||
			if (idxRemove != uint.MaxValue) m_listHistory.RemoveAt(idxRemove);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool GetAutoTypeEnabled()
 | 
			
		||||
		{
 | 
			
		||||
			if(!m_listAutoType.Enabled) return false;
 | 
			
		||||
			if (!m_listAutoType.Enabled) return false;
 | 
			
		||||
 | 
			
		||||
			if(m_pParentGroup != null)
 | 
			
		||||
			if (m_pParentGroup != null)
 | 
			
		||||
				return m_pParentGroup.GetAutoTypeEnabledInherited();
 | 
			
		||||
 | 
			
		||||
			return PwGroup.DefaultAutoTypeEnabled;
 | 
			
		||||
@@ -798,23 +762,23 @@ namespace KeePassLib
 | 
			
		||||
			string strSeq = m_listAutoType.DefaultSequence;
 | 
			
		||||
 | 
			
		||||
			PwGroup pg = m_pParentGroup;
 | 
			
		||||
			while(pg != null)
 | 
			
		||||
			while (pg != null)
 | 
			
		||||
			{
 | 
			
		||||
				if(strSeq.Length != 0) break;
 | 
			
		||||
				if (strSeq.Length != 0) break;
 | 
			
		||||
 | 
			
		||||
				strSeq = pg.DefaultAutoTypeSequence;
 | 
			
		||||
				pg = pg.ParentGroup;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if(strSeq.Length != 0) return strSeq;
 | 
			
		||||
			if (strSeq.Length != 0) return strSeq;
 | 
			
		||||
 | 
			
		||||
			if(PwDefs.IsTanEntry(this)) return PwDefs.DefaultAutoTypeSequenceTan;
 | 
			
		||||
			if (PwDefs.IsTanEntry(this)) return PwDefs.DefaultAutoTypeSequenceTan;
 | 
			
		||||
			return PwDefs.DefaultAutoTypeSequence;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool GetSearchingEnabled()
 | 
			
		||||
		{
 | 
			
		||||
			if(m_pParentGroup != null)
 | 
			
		||||
			if (m_pParentGroup != null)
 | 
			
		||||
				return m_pParentGroup.GetSearchingEnabledInherited();
 | 
			
		||||
 | 
			
		||||
			return PwGroup.DefaultSearchingEnabled;
 | 
			
		||||
@@ -829,34 +793,34 @@ namespace KeePassLib
 | 
			
		||||
		{
 | 
			
		||||
			ulong uSize = 128; // Approx fixed length data
 | 
			
		||||
 | 
			
		||||
			foreach(KeyValuePair<string, ProtectedString> kvpStr in m_listStrings)
 | 
			
		||||
			foreach (KeyValuePair<string, ProtectedString> kvpStr in m_listStrings)
 | 
			
		||||
			{
 | 
			
		||||
				uSize += (ulong)kvpStr.Key.Length;
 | 
			
		||||
				uSize += (ulong)kvpStr.Value.Length;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			foreach(KeyValuePair<string, ProtectedBinary> kvpBin in m_listBinaries)
 | 
			
		||||
			foreach (KeyValuePair<string, ProtectedBinary> kvpBin in m_listBinaries)
 | 
			
		||||
			{
 | 
			
		||||
				uSize += (ulong)kvpBin.Key.Length;
 | 
			
		||||
				uSize += kvpBin.Value.Length;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			uSize += (ulong)m_listAutoType.DefaultSequence.Length;
 | 
			
		||||
			foreach(AutoTypeAssociation a in m_listAutoType.Associations)
 | 
			
		||||
			foreach (AutoTypeAssociation a in m_listAutoType.Associations)
 | 
			
		||||
			{
 | 
			
		||||
				uSize += (ulong)a.WindowName.Length;
 | 
			
		||||
				uSize += (ulong)a.Sequence.Length;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			foreach(PwEntry peHistory in m_listHistory)
 | 
			
		||||
			foreach (PwEntry peHistory in m_listHistory)
 | 
			
		||||
				uSize += peHistory.GetSize();
 | 
			
		||||
 | 
			
		||||
			uSize += (ulong)m_strOverrideUrl.Length;
 | 
			
		||||
 | 
			
		||||
			foreach(string strTag in m_vTags)
 | 
			
		||||
			foreach (string strTag in m_vTags)
 | 
			
		||||
				uSize += (ulong)strTag.Length;
 | 
			
		||||
 | 
			
		||||
			foreach(KeyValuePair<string, string> kvp in m_dCustomData)
 | 
			
		||||
			foreach (KeyValuePair<string, string> kvp in m_dCustomData)
 | 
			
		||||
				uSize += (ulong)kvp.Key.Length + (ulong)kvp.Value.Length;
 | 
			
		||||
 | 
			
		||||
			return uSize;
 | 
			
		||||
@@ -864,11 +828,11 @@ namespace KeePassLib
 | 
			
		||||
 | 
			
		||||
		public bool HasTag(string strTag)
 | 
			
		||||
		{
 | 
			
		||||
			if(string.IsNullOrEmpty(strTag)) { Debug.Assert(false); return false; }
 | 
			
		||||
			if (string.IsNullOrEmpty(strTag)) { Debug.Assert(false); return false; }
 | 
			
		||||
 | 
			
		||||
			for(int i = 0; i < m_vTags.Count; ++i)
 | 
			
		||||
			for (int i = 0; i < m_vTags.Count; ++i)
 | 
			
		||||
			{
 | 
			
		||||
				if(m_vTags[i].Equals(strTag, StrUtil.CaseIgnoreCmp)) return true;
 | 
			
		||||
				if (m_vTags[i].Equals(strTag, StrUtil.CaseIgnoreCmp)) return true;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return false;
 | 
			
		||||
@@ -876,11 +840,11 @@ namespace KeePassLib
 | 
			
		||||
 | 
			
		||||
		public bool AddTag(string strTag)
 | 
			
		||||
		{
 | 
			
		||||
			if(string.IsNullOrEmpty(strTag)) { Debug.Assert(false); return false; }
 | 
			
		||||
			if (string.IsNullOrEmpty(strTag)) { Debug.Assert(false); return false; }
 | 
			
		||||
 | 
			
		||||
			for(int i = 0; i < m_vTags.Count; ++i)
 | 
			
		||||
			for (int i = 0; i < m_vTags.Count; ++i)
 | 
			
		||||
			{
 | 
			
		||||
				if(m_vTags[i].Equals(strTag, StrUtil.CaseIgnoreCmp)) return false;
 | 
			
		||||
				if (m_vTags[i].Equals(strTag, StrUtil.CaseIgnoreCmp)) return false;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			m_vTags.Add(strTag);
 | 
			
		||||
@@ -889,11 +853,11 @@ namespace KeePassLib
 | 
			
		||||
 | 
			
		||||
		public bool RemoveTag(string strTag)
 | 
			
		||||
		{
 | 
			
		||||
			if(string.IsNullOrEmpty(strTag)) { Debug.Assert(false); return false; }
 | 
			
		||||
			if (string.IsNullOrEmpty(strTag)) { Debug.Assert(false); return false; }
 | 
			
		||||
 | 
			
		||||
			for(int i = 0; i < m_vTags.Count; ++i)
 | 
			
		||||
			for (int i = 0; i < m_vTags.Count; ++i)
 | 
			
		||||
			{
 | 
			
		||||
				if(m_vTags[i].Equals(strTag, StrUtil.CaseIgnoreCmp))
 | 
			
		||||
				if (m_vTags[i].Equals(strTag, StrUtil.CaseIgnoreCmp))
 | 
			
		||||
				{
 | 
			
		||||
					m_vTags.RemoveAt(i);
 | 
			
		||||
					return true;
 | 
			
		||||
@@ -906,9 +870,9 @@ namespace KeePassLib
 | 
			
		||||
		public bool IsContainedIn(PwGroup pgContainer)
 | 
			
		||||
		{
 | 
			
		||||
			PwGroup pgCur = m_pParentGroup;
 | 
			
		||||
			while(pgCur != null)
 | 
			
		||||
			while (pgCur != null)
 | 
			
		||||
			{
 | 
			
		||||
				if(pgCur == pgContainer) return true;
 | 
			
		||||
				if (pgCur == pgContainer) return true;
 | 
			
		||||
 | 
			
		||||
				pgCur = pgCur.ParentGroup;
 | 
			
		||||
			}
 | 
			
		||||
@@ -920,26 +884,15 @@ namespace KeePassLib
 | 
			
		||||
		{
 | 
			
		||||
			this.Uuid = pwNewUuid;
 | 
			
		||||
 | 
			
		||||
			if(bAlsoChangeHistoryUuids)
 | 
			
		||||
			if (bAlsoChangeHistoryUuids)
 | 
			
		||||
			{
 | 
			
		||||
				foreach(PwEntry peHist in m_listHistory)
 | 
			
		||||
				foreach (PwEntry peHist in m_listHistory)
 | 
			
		||||
				{
 | 
			
		||||
					peHist.Uuid = pwNewUuid;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private DateTime GetLazyTime(ref string lazyTime, ref DateTime dateTime)
 | 
			
		||||
		{
 | 
			
		||||
			if (lazyTime != null)
 | 
			
		||||
			{
 | 
			
		||||
				dateTime = TimeUtil.DeserializeUtcOrDefault(lazyTime, dateTime);
 | 
			
		||||
				lazyTime = null;
 | 
			
		||||
			}
 | 
			
		||||
			return dateTime; 
 | 
			
		||||
		}		
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
		public void SetCreatedNow()
 | 
			
		||||
		{
 | 
			
		||||
			DateTime dt = DateTime.UtcNow;
 | 
			
		||||
@@ -968,7 +921,7 @@ namespace KeePassLib
 | 
			
		||||
		public PwEntryComparer(string strFieldName, bool bCaseInsensitive,
 | 
			
		||||
			bool bCompareNaturally)
 | 
			
		||||
		{
 | 
			
		||||
			if(strFieldName == null) throw new ArgumentNullException("strFieldName");
 | 
			
		||||
			if (strFieldName == null) throw new ArgumentNullException("strFieldName");
 | 
			
		||||
 | 
			
		||||
			m_strFieldName = strFieldName;
 | 
			
		||||
			m_bCaseInsensitive = bCaseInsensitive;
 | 
			
		||||
@@ -980,7 +933,7 @@ namespace KeePassLib
 | 
			
		||||
			string strA = a.Strings.ReadSafe(m_strFieldName);
 | 
			
		||||
			string strB = b.Strings.ReadSafe(m_strFieldName);
 | 
			
		||||
 | 
			
		||||
			if(m_bCompareNaturally) return StrUtil.CompareNaturally(strA, strB);
 | 
			
		||||
			if (m_bCompareNaturally) return StrUtil.CompareNaturally(strA, strB);
 | 
			
		||||
 | 
			
		||||
			return string.Compare(strA, strB, m_bCaseInsensitive);
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,6 @@ namespace KeePassLib
 | 
			
		||||
		private PwObjectList<PwEntry> m_listEntries = new PwObjectList<PwEntry>();
 | 
			
		||||
		private PwGroup m_pParentGroup = null;
 | 
			
		||||
		private DateTime m_tParentGroupLastMod = PwDefs.DtDefaultNow;
 | 
			
		||||
		private string m_tParentGroupLastModLazy;
 | 
			
		||||
 | 
			
		||||
		private PwUuid m_uuid = PwUuid.Zero;
 | 
			
		||||
		private string m_strName = string.Empty;
 | 
			
		||||
@@ -63,12 +62,6 @@ namespace KeePassLib
 | 
			
		||||
		private bool m_bExpires = false;
 | 
			
		||||
		private ulong m_uUsageCount = 0;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		private string m_tCreationLazy;
 | 
			
		||||
		private string m_tLastModLazy;
 | 
			
		||||
		private string m_tLastAccessLazy;
 | 
			
		||||
		private string m_tExpireLazy;
 | 
			
		||||
 | 
			
		||||
		private bool m_bIsExpanded = true;
 | 
			
		||||
		private bool m_bVirtual = false;
 | 
			
		||||
 | 
			
		||||
@@ -160,12 +153,8 @@ namespace KeePassLib
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public DateTime LocationChanged
 | 
			
		||||
		{
 | 
			
		||||
			get { return GetLazyTime(ref m_tParentGroupLastModLazy, ref m_tParentGroupLastMod); }
 | 
			
		||||
			set { m_tParentGroupLastMod = value; m_tParentGroupLastModLazy = null; }
 | 
			
		||||
		}
 | 
			
		||||
		public void SetLazyLocationChanged(string xmlDateTime)
 | 
			
		||||
		{
 | 
			
		||||
			m_tParentGroupLastModLazy = xmlDateTime;
 | 
			
		||||
			get { return m_tParentGroupLastMod; }
 | 
			
		||||
			set { m_tParentGroupLastMod = value; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -183,13 +172,8 @@ namespace KeePassLib
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public DateTime CreationTime
 | 
			
		||||
		{
 | 
			
		||||
			get { return GetLazyTime(ref m_tCreationLazy, ref m_tCreation); }
 | 
			
		||||
			set { m_tCreation = value; m_tCreationLazy = null; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void SetLazyCreationTime(string xmlDateTime)
 | 
			
		||||
		{
 | 
			
		||||
			m_tCreationLazy = xmlDateTime;
 | 
			
		||||
			get { return m_tCreation; }
 | 
			
		||||
			set { m_tCreation = value; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -197,13 +181,8 @@ namespace KeePassLib
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public DateTime LastModificationTime
 | 
			
		||||
		{
 | 
			
		||||
			get { return GetLazyTime(ref m_tLastModLazy, ref m_tLastMod); }
 | 
			
		||||
			set { m_tLastMod = value; m_tLastModLazy = null; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void SetLazyLastModificationTime(string xmlDateTime)
 | 
			
		||||
		{
 | 
			
		||||
			m_tLastModLazy = xmlDateTime;
 | 
			
		||||
			get { return m_tLastMod; }
 | 
			
		||||
			set { m_tLastMod = value; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -211,13 +190,8 @@ namespace KeePassLib
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public DateTime LastAccessTime
 | 
			
		||||
		{
 | 
			
		||||
			get { return GetLazyTime(ref m_tLastAccessLazy, ref m_tLastAccess); }
 | 
			
		||||
			set { m_tLastAccess = value; m_tLastAccessLazy = null; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void SetLazyLastAccessTime(string xmlDateTime)
 | 
			
		||||
		{
 | 
			
		||||
			m_tLastAccessLazy = xmlDateTime;
 | 
			
		||||
			get { return m_tLastAccess; }
 | 
			
		||||
			set { m_tLastAccess = value; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -225,12 +199,8 @@ namespace KeePassLib
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public DateTime ExpiryTime
 | 
			
		||||
		{
 | 
			
		||||
			get { return GetLazyTime(ref m_tExpireLazy, ref m_tExpire); }
 | 
			
		||||
			set { m_tExpire = value; m_tExpireLazy = null; }
 | 
			
		||||
		}
 | 
			
		||||
		public void SetLazyExpiryTime(string xmlDateTime)
 | 
			
		||||
		{
 | 
			
		||||
			m_tExpireLazy = xmlDateTime;
 | 
			
		||||
			get { return m_tExpire; }
 | 
			
		||||
			set { m_tExpire = value; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -406,7 +376,6 @@ namespace KeePassLib
 | 
			
		||||
			pg.m_listEntries = m_listEntries.CloneDeep();
 | 
			
		||||
			pg.m_pParentGroup = m_pParentGroup;
 | 
			
		||||
			pg.m_tParentGroupLastMod = m_tParentGroupLastMod;
 | 
			
		||||
			pg.m_tParentGroupLastModLazy = m_tParentGroupLastModLazy;
 | 
			
		||||
 | 
			
		||||
			pg.m_strName = m_strName;
 | 
			
		||||
			pg.m_strNotes = m_strNotes;
 | 
			
		||||
@@ -421,11 +390,6 @@ namespace KeePassLib
 | 
			
		||||
			pg.m_bExpires = m_bExpires;
 | 
			
		||||
			pg.m_uUsageCount = m_uUsageCount;
 | 
			
		||||
 | 
			
		||||
			pg.m_tCreationLazy = m_tCreationLazy;
 | 
			
		||||
			pg.m_tLastModLazy = m_tLastModLazy;
 | 
			
		||||
			pg.m_tLastAccessLazy = m_tLastAccessLazy;
 | 
			
		||||
			pg.m_tExpireLazy = m_tExpireLazy;
 | 
			
		||||
 | 
			
		||||
			pg.m_bIsExpanded = m_bIsExpanded;
 | 
			
		||||
			pg.m_bVirtual = m_bVirtual;
 | 
			
		||||
 | 
			
		||||
@@ -483,7 +447,7 @@ namespace KeePassLib
 | 
			
		||||
			if (!m_pwCustomIconID.Equals(pg.m_pwCustomIconID)) return false;
 | 
			
		||||
 | 
			
		||||
			if (m_tCreation != pg.m_tCreation) return false;
 | 
			
		||||
			if (!bIgnoreLastMod && (LastModificationTime != pg.LastModificationTime)) return false;
 | 
			
		||||
			if(!bIgnoreLastMod && (m_tLastMod != pg.m_tLastMod)) return false;
 | 
			
		||||
			if (!bIgnoreLastAccess && (m_tLastAccess != pg.m_tLastAccess)) return false;
 | 
			
		||||
			if (m_tExpire != pg.m_tExpire) return false;
 | 
			
		||||
			if (m_bExpires != pg.m_bExpires) return false;
 | 
			
		||||
@@ -541,9 +505,9 @@ namespace KeePassLib
 | 
			
		||||
		public void AssignProperties(PwGroup pgTemplate, bool bOnlyIfNewer,
 | 
			
		||||
			bool bAssignLocationChanged)
 | 
			
		||||
		{
 | 
			
		||||
			Debug.Assert(pgTemplate != null); if (pgTemplate == null) throw new ArgumentNullException("pgTemplate");
 | 
			
		||||
			Debug.Assert(pgTemplate != null); if(pgTemplate == null) throw new ArgumentNullException("pgTemplate");
 | 
			
		||||
 | 
			
		||||
			if (bOnlyIfNewer && (TimeUtil.Compare(pgTemplate.LastModificationTime, LastModificationTime,
 | 
			
		||||
			if(bOnlyIfNewer && (TimeUtil.Compare(pgTemplate.m_tLastMod, m_tLastMod,
 | 
			
		||||
				true) < 0))
 | 
			
		||||
				return;
 | 
			
		||||
 | 
			
		||||
@@ -551,7 +515,7 @@ namespace KeePassLib
 | 
			
		||||
			Debug.Assert(m_uuid.Equals(pgTemplate.m_uuid));
 | 
			
		||||
			m_uuid = pgTemplate.m_uuid;
 | 
			
		||||
 | 
			
		||||
			if (bAssignLocationChanged)
 | 
			
		||||
			if(bAssignLocationChanged)
 | 
			
		||||
				m_tParentGroupLastMod = pgTemplate.m_tParentGroupLastMod;
 | 
			
		||||
 | 
			
		||||
			m_strName = pgTemplate.m_strName;
 | 
			
		||||
@@ -560,11 +524,10 @@ namespace KeePassLib
 | 
			
		||||
			m_pwIcon = pgTemplate.m_pwIcon;
 | 
			
		||||
			m_pwCustomIconID = pgTemplate.m_pwCustomIconID;
 | 
			
		||||
 | 
			
		||||
			m_tCreation = pgTemplate.CreationTime;
 | 
			
		||||
			m_tLastMod = pgTemplate.LastModificationTime;
 | 
			
		||||
			m_tLastAccess = pgTemplate.LastAccessTime;
 | 
			
		||||
			m_tExpire = pgTemplate.ExpiryTime;
 | 
			
		||||
 | 
			
		||||
			m_tCreation = pgTemplate.m_tCreation;
 | 
			
		||||
			m_tLastMod = pgTemplate.m_tLastMod;
 | 
			
		||||
			m_tLastAccess = pgTemplate.m_tLastAccess;
 | 
			
		||||
			m_tExpire = pgTemplate.m_tExpire;
 | 
			
		||||
			m_bExpires = pgTemplate.m_bExpires;
 | 
			
		||||
			m_uUsageCount = pgTemplate.m_uUsageCount;
 | 
			
		||||
 | 
			
		||||
@@ -602,16 +565,16 @@ namespace KeePassLib
 | 
			
		||||
			m_tLastAccess = DateTime.Now;
 | 
			
		||||
			++m_uUsageCount;
 | 
			
		||||
 | 
			
		||||
			if (bModified) m_tLastMod = m_tLastAccess;
 | 
			
		||||
			if(bModified) m_tLastMod = m_tLastAccess;
 | 
			
		||||
 | 
			
		||||
			if (this.Touched != null)
 | 
			
		||||
			if(this.Touched != null)
 | 
			
		||||
				this.Touched(this, new ObjectTouchedEventArgs(this,
 | 
			
		||||
					bModified, bTouchParents));
 | 
			
		||||
			if (PwGroup.GroupTouched != null)
 | 
			
		||||
			if(PwGroup.GroupTouched != null)
 | 
			
		||||
				PwGroup.GroupTouched(this, new ObjectTouchedEventArgs(this,
 | 
			
		||||
					bModified, bTouchParents));
 | 
			
		||||
 | 
			
		||||
			if (bTouchParents && (m_pParentGroup != null))
 | 
			
		||||
			if(bTouchParents && (m_pParentGroup != null))
 | 
			
		||||
				m_pParentGroup.Touch(bModified, true);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -628,13 +591,13 @@ namespace KeePassLib
 | 
			
		||||
		/// <param name="uNumEntries">Number of entries.</param>
 | 
			
		||||
		public void GetCounts(bool bRecursive, out uint uNumGroups, out uint uNumEntries)
 | 
			
		||||
		{
 | 
			
		||||
			if (bRecursive)
 | 
			
		||||
			if(bRecursive)
 | 
			
		||||
			{
 | 
			
		||||
				uint uTotalGroups = m_listGroups.UCount;
 | 
			
		||||
				uint uTotalEntries = m_listEntries.UCount;
 | 
			
		||||
				uint uSubGroupCount, uSubEntryCount;
 | 
			
		||||
 | 
			
		||||
				foreach (PwGroup pg in m_listGroups)
 | 
			
		||||
				foreach(PwGroup pg in m_listGroups)
 | 
			
		||||
				{
 | 
			
		||||
					pg.GetCounts(true, out uSubGroupCount, out uSubEntryCount);
 | 
			
		||||
 | 
			
		||||
@@ -678,7 +641,7 @@ namespace KeePassLib
 | 
			
		||||
		{
 | 
			
		||||
			bool bRet = false;
 | 
			
		||||
 | 
			
		||||
			switch (tm)
 | 
			
		||||
			switch(tm)
 | 
			
		||||
			{
 | 
			
		||||
				case TraversalMethod.None:
 | 
			
		||||
					bRet = true;
 | 
			
		||||
@@ -696,26 +659,26 @@ namespace KeePassLib
 | 
			
		||||
 | 
			
		||||
		private bool PreOrderTraverseTree(GroupHandler groupHandler, EntryHandler entryHandler)
 | 
			
		||||
		{
 | 
			
		||||
			if (entryHandler != null)
 | 
			
		||||
			if(entryHandler != null)
 | 
			
		||||
			{
 | 
			
		||||
				foreach (PwEntry pe in m_listEntries)
 | 
			
		||||
				foreach(PwEntry pe in m_listEntries)
 | 
			
		||||
				{
 | 
			
		||||
					if (!entryHandler(pe)) return false;
 | 
			
		||||
					if(!entryHandler(pe)) return false;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (groupHandler != null)
 | 
			
		||||
			if(groupHandler != null)
 | 
			
		||||
			{
 | 
			
		||||
				foreach (PwGroup pg in m_listGroups)
 | 
			
		||||
				foreach(PwGroup pg in m_listGroups)
 | 
			
		||||
				{
 | 
			
		||||
					if (!groupHandler(pg)) return false;
 | 
			
		||||
					if(!groupHandler(pg)) return false;
 | 
			
		||||
 | 
			
		||||
					pg.PreOrderTraverseTree(groupHandler, entryHandler);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else // groupHandler == null
 | 
			
		||||
			{
 | 
			
		||||
				foreach (PwGroup pg in m_listGroups)
 | 
			
		||||
				foreach(PwGroup pg in m_listGroups)
 | 
			
		||||
				{
 | 
			
		||||
					pg.PreOrderTraverseTree(null, entryHandler);
 | 
			
		||||
				}
 | 
			
		||||
@@ -732,11 +695,11 @@ namespace KeePassLib
 | 
			
		||||
		{
 | 
			
		||||
			LinkedList<PwGroup> list = new LinkedList<PwGroup>();
 | 
			
		||||
 | 
			
		||||
			foreach (PwGroup pg in m_listGroups)
 | 
			
		||||
			foreach(PwGroup pg in m_listGroups)
 | 
			
		||||
			{
 | 
			
		||||
				list.AddLast(pg);
 | 
			
		||||
 | 
			
		||||
				if (pg.Groups.UCount != 0)
 | 
			
		||||
				if(pg.Groups.UCount != 0)
 | 
			
		||||
					LinearizeGroupRecursive(list, pg, 1);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@@ -745,13 +708,13 @@ namespace KeePassLib
 | 
			
		||||
 | 
			
		||||
		private void LinearizeGroupRecursive(LinkedList<PwGroup> list, PwGroup pg, ushort uLevel)
 | 
			
		||||
		{
 | 
			
		||||
			Debug.Assert(pg != null); if (pg == null) return;
 | 
			
		||||
			Debug.Assert(pg != null); if(pg == null) return;
 | 
			
		||||
 | 
			
		||||
			foreach (PwGroup pwg in pg.Groups)
 | 
			
		||||
			foreach(PwGroup pwg in pg.Groups)
 | 
			
		||||
			{
 | 
			
		||||
				list.AddLast(pwg);
 | 
			
		||||
 | 
			
		||||
				if (pwg.Groups.UCount != 0)
 | 
			
		||||
				if(pwg.Groups.UCount != 0)
 | 
			
		||||
					LinearizeGroupRecursive(list, pwg, (ushort)(uLevel + 1));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -765,12 +728,12 @@ namespace KeePassLib
 | 
			
		||||
		/// <returns>Flat list of all entries.</returns>
 | 
			
		||||
		public static LinkedList<PwEntry> GetFlatEntryList(LinkedList<PwGroup> flatGroupList)
 | 
			
		||||
		{
 | 
			
		||||
			Debug.Assert(flatGroupList != null); if (flatGroupList == null) return null;
 | 
			
		||||
			Debug.Assert(flatGroupList != null); if(flatGroupList == null) return null;
 | 
			
		||||
 | 
			
		||||
			LinkedList<PwEntry> list = new LinkedList<PwEntry>();
 | 
			
		||||
			foreach (PwGroup pg in flatGroupList)
 | 
			
		||||
			foreach(PwGroup pg in flatGroupList)
 | 
			
		||||
			{
 | 
			
		||||
				foreach (PwEntry pe in pg.Entries)
 | 
			
		||||
				foreach(PwEntry pe in pg.Entries)
 | 
			
		||||
					list.AddLast(pe);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@@ -794,7 +757,7 @@ namespace KeePassLib
 | 
			
		||||
				pe.Strings.EnableProtection(strFieldName, bEnable);
 | 
			
		||||
 | 
			
		||||
				// Do the same for all history items
 | 
			
		||||
				foreach (PwEntry peHistory in pe.History)
 | 
			
		||||
				foreach(PwEntry peHistory in pe.History)
 | 
			
		||||
				{
 | 
			
		||||
					peHistory.Strings.EnableProtection(strFieldName, bEnable);
 | 
			
		||||
				}
 | 
			
		||||
@@ -1723,15 +1686,6 @@ namespace KeePassLib
 | 
			
		||||
 | 
			
		||||
			return pg;
 | 
			
		||||
		}
 | 
			
		||||
		private DateTime GetLazyTime(ref string lazyTime, ref DateTime dateTime)
 | 
			
		||||
		{
 | 
			
		||||
			if (lazyTime != null)
 | 
			
		||||
			{
 | 
			
		||||
				dateTime = TimeUtil.DeserializeUtcOrDefault(lazyTime, m_tLastMod);
 | 
			
		||||
				lazyTime = null;
 | 
			
		||||
			}
 | 
			
		||||
			return dateTime;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public sealed class PwGroupComparer : IComparer<PwGroup>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/*
 | 
			
		||||
  KeePass Password Safe - The Open-Source Password Manager
 | 
			
		||||
  Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
 | 
			
		||||
  Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de>
 | 
			
		||||
  
 | 
			
		||||
  Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
 | 
			
		||||
 | 
			
		||||
@@ -53,185 +53,6 @@ namespace KeePassLib.Serialization
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	internal abstract class WrapperStream : Stream
 | 
			
		||||
	{
 | 
			
		||||
		private readonly Stream m_s;
 | 
			
		||||
		protected Stream BaseStream
 | 
			
		||||
		{
 | 
			
		||||
			get { return m_s; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override bool CanRead
 | 
			
		||||
		{
 | 
			
		||||
			get { return m_s.CanRead; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override bool CanSeek
 | 
			
		||||
		{
 | 
			
		||||
			get { return m_s.CanSeek; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override bool CanTimeout
 | 
			
		||||
		{
 | 
			
		||||
			get { return m_s.CanTimeout; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override bool CanWrite
 | 
			
		||||
		{
 | 
			
		||||
			get { return m_s.CanWrite; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override long Length
 | 
			
		||||
		{
 | 
			
		||||
			get { return m_s.Length; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override long Position
 | 
			
		||||
		{
 | 
			
		||||
			get { return m_s.Position; }
 | 
			
		||||
			set { m_s.Position = value; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override int ReadTimeout
 | 
			
		||||
		{
 | 
			
		||||
			get { return m_s.ReadTimeout; }
 | 
			
		||||
			set { m_s.ReadTimeout = value; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override int WriteTimeout
 | 
			
		||||
		{
 | 
			
		||||
			get { return m_s.WriteTimeout; }
 | 
			
		||||
			set { m_s.WriteTimeout = value; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public WrapperStream(Stream sBase) : base()
 | 
			
		||||
		{
 | 
			
		||||
			if(sBase == null) throw new ArgumentNullException("sBase");
 | 
			
		||||
 | 
			
		||||
			m_s = sBase;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
#if !KeePassUAP
 | 
			
		||||
		public override IAsyncResult BeginRead(byte[] buffer, int offset,
 | 
			
		||||
			int count, AsyncCallback callback, object state)
 | 
			
		||||
		{
 | 
			
		||||
			return m_s.BeginRead(buffer, offset, count, callback, state);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override IAsyncResult BeginWrite(byte[] buffer, int offset,
 | 
			
		||||
			int count, AsyncCallback callback, object state)
 | 
			
		||||
		{
 | 
			
		||||
			return BeginWrite(buffer, offset, count, callback, state);
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		protected override void Dispose(bool disposing)
 | 
			
		||||
		{
 | 
			
		||||
			if(disposing) m_s.Dispose();
 | 
			
		||||
 | 
			
		||||
			base.Dispose(disposing);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
#if !KeePassUAP
 | 
			
		||||
		public override int EndRead(IAsyncResult asyncResult)
 | 
			
		||||
		{
 | 
			
		||||
			return m_s.EndRead(asyncResult);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void EndWrite(IAsyncResult asyncResult)
 | 
			
		||||
		{
 | 
			
		||||
			m_s.EndWrite(asyncResult);
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		public override void Flush()
 | 
			
		||||
		{
 | 
			
		||||
			m_s.Flush();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override int Read(byte[] buffer, int offset, int count)
 | 
			
		||||
		{
 | 
			
		||||
			return m_s.Read(buffer, offset, count);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override int ReadByte()
 | 
			
		||||
		{
 | 
			
		||||
			return m_s.ReadByte();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override long Seek(long offset, SeekOrigin origin)
 | 
			
		||||
		{
 | 
			
		||||
			return m_s.Seek(offset, origin);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void SetLength(long value)
 | 
			
		||||
		{
 | 
			
		||||
			m_s.SetLength(value);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void Write(byte[] buffer, int offset, int count)
 | 
			
		||||
		{
 | 
			
		||||
			m_s.Write(buffer, offset, count);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void WriteByte(byte value)
 | 
			
		||||
		{
 | 
			
		||||
			m_s.WriteByte(value);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	internal sealed class IocStream : WrapperStream
 | 
			
		||||
	{
 | 
			
		||||
		private readonly bool m_bWrite; // Initially opened for writing
 | 
			
		||||
		private bool m_bDisposed = false;
 | 
			
		||||
 | 
			
		||||
		public IocStream(Stream sBase) : base(sBase)
 | 
			
		||||
		{
 | 
			
		||||
			m_bWrite = sBase.CanWrite;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		protected override void Dispose(bool disposing)
 | 
			
		||||
		{
 | 
			
		||||
			base.Dispose(disposing);
 | 
			
		||||
 | 
			
		||||
			if(disposing && MonoWorkarounds.IsRequired(10163) && m_bWrite &&
 | 
			
		||||
				!m_bDisposed)
 | 
			
		||||
			{
 | 
			
		||||
				try
 | 
			
		||||
				{
 | 
			
		||||
					Stream s = this.BaseStream;
 | 
			
		||||
					Type t = s.GetType();
 | 
			
		||||
					if(t.Name == "WebConnectionStream")
 | 
			
		||||
					{
 | 
			
		||||
						PropertyInfo pi = t.GetProperty("Request",
 | 
			
		||||
							BindingFlags.Instance | BindingFlags.NonPublic);
 | 
			
		||||
						if(pi != null)
 | 
			
		||||
						{
 | 
			
		||||
							WebRequest wr = (pi.GetValue(s, null) as WebRequest);
 | 
			
		||||
							if(wr != null)
 | 
			
		||||
								IOConnection.DisposeResponse(wr.GetResponse(), false);
 | 
			
		||||
							else { Debug.Assert(false); }
 | 
			
		||||
						}
 | 
			
		||||
						else { Debug.Assert(false); }
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				catch(Exception) { Debug.Assert(false); }
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			m_bDisposed = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static Stream WrapIfRequired(Stream s)
 | 
			
		||||
		{
 | 
			
		||||
			if(s == null) { Debug.Assert(false); return null; }
 | 
			
		||||
 | 
			
		||||
			if(MonoWorkarounds.IsRequired(10163) && s.CanWrite)
 | 
			
		||||
				return new IocStream(s);
 | 
			
		||||
 | 
			
		||||
			return s;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static class IOConnection
 | 
			
		||||
	{
 | 
			
		||||
#if (!KeePassLibSD && !KeePassRT)
 | 
			
		||||
 
 | 
			
		||||
@@ -499,22 +499,21 @@ namespace KeePassLib.Serialization
 | 
			
		||||
					Debug.Assert(tl != null);
 | 
			
		||||
 | 
			
		||||
					if(xr.Name == ElemCreationTime)
 | 
			
		||||
						tl.SetLazyCreationTime(ReadString(xr));
 | 
			
		||||
					else if (xr.Name == ElemLastModTime)
 | 
			
		||||
						tl.SetLazyLastModificationTime(ReadString(xr));
 | 
			
		||||
					else if (xr.Name == ElemLastAccessTime)
 | 
			
		||||
						tl.SetLazyLastAccessTime(ReadString(xr));
 | 
			
		||||
					else if (xr.Name == ElemExpiryTime)
 | 
			
		||||
						tl.SetLazyExpiryTime(ReadString(xr));
 | 
			
		||||
					else if (xr.Name == ElemExpires)
 | 
			
		||||
						tl.CreationTime = ReadTime(xr);
 | 
			
		||||
					else if(xr.Name == ElemLastModTime)
 | 
			
		||||
						tl.LastModificationTime = ReadTime(xr);
 | 
			
		||||
					else if(xr.Name == ElemLastAccessTime)
 | 
			
		||||
						tl.LastAccessTime = ReadTime(xr);
 | 
			
		||||
					else if(xr.Name == ElemExpiryTime)
 | 
			
		||||
						tl.ExpiryTime = ReadTime(xr);
 | 
			
		||||
					else if(xr.Name == ElemExpires)
 | 
			
		||||
						tl.Expires = ReadBool(xr, false);
 | 
			
		||||
					else if(xr.Name == ElemUsageCount)
 | 
			
		||||
						tl.UsageCount = ReadULong(xr, 0);
 | 
			
		||||
					else if(xr.Name == ElemLocationChanged)
 | 
			
		||||
						tl.SetLazyLocationChanged(ReadString(xr));
 | 
			
		||||
						tl.LocationChanged = ReadTime(xr);
 | 
			
		||||
					else ReadUnknown(xr);
 | 
			
		||||
					break;
 | 
			
		||||
 | 
			
		||||
				case KdbContext.EntryString:
 | 
			
		||||
					if(xr.Name == ElemKey)
 | 
			
		||||
						m_ctxStringName = ReadString(xr);
 | 
			
		||||
 
 | 
			
		||||
@@ -225,7 +225,7 @@ namespace KeePassLib.Serialization
 | 
			
		||||
				
 | 
			
		||||
				if (fmt == KdbxFormat.ProtocolBuffers)
 | 
			
		||||
				{
 | 
			
		||||
					KdbpFile.ReadDocument(m_pwDatabase, sXml, m_pbProtectedStreamKey, m_pbHashOfHeader);
 | 
			
		||||
					KdbpFile.ReadDocument(m_pwDatabase, sXml, m_pbInnerRandomStreamKey, m_pbHashOfHeader);
 | 
			
		||||
 | 
			
		||||
					Kp2aLog.Log(String.Format("KdbpFile.ReadDocument: {0}ms", stopWatch.ElapsedMilliseconds));
 | 
			
		||||
 | 
			
		||||
@@ -577,8 +577,6 @@ namespace KeePassLib.Serialization
 | 
			
		||||
				else { Debug.Assert(false); }
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return vEntries; */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
			return vEntries; */
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -209,7 +209,7 @@ namespace KeePassLib.Serialization
 | 
			
		||||
 | 
			
		||||
				if (m_format == KdbxFormat.ProtocolBuffers)
 | 
			
		||||
				{
 | 
			
		||||
					KdbpFile.WriteDocument(m_pwDatabase, sXml, m_pbProtectedStreamKey, m_pbHashOfHeader);
 | 
			
		||||
					KdbpFile.WriteDocument(m_pwDatabase, sXml, m_pbInnerRandomStreamKey, m_pbHashOfHeader);
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
@@ -1014,17 +1014,12 @@ namespace KeePassLib.Serialization
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static bool WriteEntries(Stream msOutput, PwDatabase pdContext,
 | 
			
		||||
			PwEntry[] vEntries)
 | 
			
		||||
	PwEntry[] vEntries)
 | 
			
		||||
		{
 | 
			
		||||
			if(msOutput == null) { Debug.Assert(false); return false; }
 | 
			
		||||
		/// <summary>
 | 
			
		||||
			if(vEntries == null) { Debug.Assert(false); return false; }
 | 
			
		||||
		/// Write entries to a stream.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// <param name="msOutput">Output stream to which the entries will be written.</param>
 | 
			
		||||
		/// <param name="vEntries">Entries to serialize.</param>
 | 
			
		||||
		/// <returns>Returns <c>true</c>, if the entries were written successfully
 | 
			
		||||
		/// to the stream.</returns>
 | 
			
		||||
			if (msOutput == null) { Debug.Assert(false); return false; }
 | 
			
		||||
			// pdContext may be null
 | 
			
		||||
			if (vEntries == null) { Debug.Assert(false); return false; }
 | 
			
		||||
 | 
			
		||||
			/* KdbxFile f = new KdbxFile(pwDatabase);
 | 
			
		||||
			f.m_format = KdbxFormat.PlainXml;
 | 
			
		||||
 | 
			
		||||
@@ -1047,31 +1042,36 @@ namespace KeePassLib.Serialization
 | 
			
		||||
 | 
			
		||||
			xtw.WriteEndElement();
 | 
			
		||||
			xtw.WriteEndDocument();
 | 
			
		||||
 | 
			
		||||
			xtw.Flush();
 | 
			
		||||
			xtw.Close();
 | 
			
		||||
			return true; */
 | 
			
		||||
 | 
			
		||||
			PwDatabase pd = new PwDatabase();
 | 
			
		||||
			pd.New(new IOConnectionInfo(), new CompositeKey());
 | 
			
		||||
 | 
			
		||||
			PwGroup pg = pd.RootGroup;
 | 
			
		||||
			if(pg == null) { Debug.Assert(false); return false; }
 | 
			
		||||
			xtw.Flush();
 | 
			
		||||
			foreach(PwEntry pe in vEntries)
 | 
			
		||||
			if (pg == null) { Debug.Assert(false); return false; }
 | 
			
		||||
 | 
			
		||||
			foreach (PwEntry pe in vEntries)
 | 
			
		||||
			{
 | 
			
		||||
				PwUuid pu = pe.CustomIconUuid;
 | 
			
		||||
				if(!pu.Equals(PwUuid.Zero) && (pd.GetCustomIconIndex(pu) < 0))
 | 
			
		||||
				if (!pu.Equals(PwUuid.Zero) && (pd.GetCustomIconIndex(pu) < 0))
 | 
			
		||||
				{
 | 
			
		||||
					int i = -1;
 | 
			
		||||
					if(pdContext != null) i = pdContext.GetCustomIconIndex(pu);
 | 
			
		||||
					if(i >= 0)
 | 
			
		||||
					if (pdContext != null) i = pdContext.GetCustomIconIndex(pu);
 | 
			
		||||
					if (i >= 0)
 | 
			
		||||
					{
 | 
			
		||||
						PwCustomIcon ci = pdContext.CustomIcons[i];
 | 
			
		||||
						pd.CustomIcons.Add(ci);
 | 
			
		||||
					}
 | 
			
		||||
					else { Debug.Assert(pdContext == null); }
 | 
			
		||||
				}
 | 
			
		||||
			xtw.Close();
 | 
			
		||||
 | 
			
		||||
				PwEntry peCopy = pe.CloneDeep();
 | 
			
		||||
				pg.AddEntry(peCopy, true);
 | 
			
		||||
			}
 | 
			
		||||
			return true; */
 | 
			
		||||
 | 
			
		||||
			KdbxFile f = new KdbxFile(pd);
 | 
			
		||||
			f.Save(msOutput, null, KdbxFormat.PlainXml, null);
 | 
			
		||||
			return true;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,8 @@
 | 
			
		||||
/*
 | 
			
		||||
  KeePass Password Safe - The Open-Source Password Manager
 | 
			
		||||
  Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
 | 
			
		||||
  Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de>
 | 
			
		||||
  
 | 
			
		||||
  Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
 | 
			
		||||
 | 
			
		||||
  This program is free software; you can redistribute it and/or modify
 | 
			
		||||
  it under the terms of the GNU General Public License as published by
 | 
			
		||||
@@ -20,29 +22,45 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Collections.Specialized;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
#if !KeePassUAP
 | 
			
		||||
using System.Windows.Forms;
 | 
			
		||||
#endif
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
 | 
			
		||||
using KeePassLib.Resources;
 | 
			
		||||
using KeePassLib.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace KeePassLib.Utility
 | 
			
		||||
{
 | 
			
		||||
	public enum MessageBoxButtons
 | 
			
		||||
	{
 | 
			
		||||
		OK, OKCancel, AbortRetryIgnore, YesNoCancel, YesNo, RetryCancel
 | 
			
		||||
	}
 | 
			
		||||
	public enum MessageBoxIcon
 | 
			
		||||
	{
 | 
			
		||||
		Information, Warning, Error, Question
 | 
			
		||||
	}
 | 
			
		||||
	public enum MessageBoxDefaultButton
 | 
			
		||||
	{
 | 
			
		||||
		Button1, Button2, Button3
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public enum DialogResult
 | 
			
		||||
	{
 | 
			
		||||
		Yes, No, Cancel, Retry, Abort
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	public sealed class MessageServiceEventArgs : EventArgs
 | 
			
		||||
	{
 | 
			
		||||
		private string m_strTitle = string.Empty;
 | 
			
		||||
		private string m_strText = string.Empty;
 | 
			
		||||
		private MessageBoxButtons m_msgButtons = MessageBoxButtons.OK;
 | 
			
		||||
		private MessageBoxIcon m_msgIcon = MessageBoxIcon.None;
 | 
			
		||||
		//private MessageBoxButtons m_msgButtons = MessageBoxButtons.OK;
 | 
			
		||||
		//private MessageBoxIcon m_msgIcon = MessageBoxIcon.None;
 | 
			
		||||
 | 
			
		||||
		public string Title { get { return m_strTitle; } }
 | 
			
		||||
		public string Text { get { return m_strText; } }
 | 
			
		||||
		public MessageBoxButtons Buttons { get { return m_msgButtons; } }
 | 
			
		||||
		public MessageBoxIcon Icon { get { return m_msgIcon; } }
 | 
			
		||||
		//public MessageBoxButtons Buttons { get { return m_msgButtons; } }
 | 
			
		||||
		//public MessageBoxIcon Icon { get { return m_msgIcon; } }
 | 
			
		||||
 | 
			
		||||
		public MessageServiceEventArgs() { }
 | 
			
		||||
 | 
			
		||||
@@ -51,8 +69,7 @@ namespace KeePassLib.Utility
 | 
			
		||||
		{
 | 
			
		||||
			m_strTitle = (strTitle ?? string.Empty);
 | 
			
		||||
			m_strText = (strText ?? string.Empty);
 | 
			
		||||
			m_msgButtons = msgButtons;
 | 
			
		||||
			m_msgIcon = msgIcon;
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -65,14 +82,12 @@ namespace KeePassLib.Utility
 | 
			
		||||
		private const MessageBoxIcon m_mbiWarning = MessageBoxIcon.Warning;
 | 
			
		||||
		private const MessageBoxIcon m_mbiFatal = MessageBoxIcon.Error;
 | 
			
		||||
 | 
			
		||||
		private const MessageBoxOptions m_mboRtl = (MessageBoxOptions.RtlReading |
 | 
			
		||||
			MessageBoxOptions.RightAlign);
 | 
			
		||||
#else
 | 
			
		||||
		private const MessageBoxIcon m_mbiInfo = MessageBoxIcon.Asterisk;
 | 
			
		||||
		private const MessageBoxIcon m_mbiWarning = MessageBoxIcon.Exclamation;
 | 
			
		||||
		private const MessageBoxIcon m_mbiFatal = MessageBoxIcon.Hand;
 | 
			
		||||
#endif
 | 
			
		||||
		private const MessageBoxIcon m_mbiQuestion = MessageBoxIcon.Question;
 | 
			
		||||
		//private const MessageBoxIcon m_mbiQuestion = MessageBoxIcon.Question;
 | 
			
		||||
 | 
			
		||||
		public static string NewLine
 | 
			
		||||
		{
 | 
			
		||||
@@ -97,9 +112,7 @@ namespace KeePassLib.Utility
 | 
			
		||||
			get { return m_uCurrentMessageCount; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
#if !KeePassUAP
 | 
			
		||||
		public static event EventHandler<MessageServiceEventArgs> MessageShowing;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		private static string ObjectsToMessage(object[] vLines)
 | 
			
		||||
		{
 | 
			
		||||
@@ -108,52 +121,52 @@ namespace KeePassLib.Utility
 | 
			
		||||
 | 
			
		||||
		private static string ObjectsToMessage(object[] vLines, bool bFullExceptions)
 | 
			
		||||
		{
 | 
			
		||||
			if(vLines == null) return string.Empty;
 | 
			
		||||
			if (vLines == null) return string.Empty;
 | 
			
		||||
 | 
			
		||||
			string strNewPara = MessageService.NewParagraph;
 | 
			
		||||
 | 
			
		||||
			StringBuilder sbText = new StringBuilder();
 | 
			
		||||
			bool bSeparator = false;
 | 
			
		||||
 | 
			
		||||
			foreach(object obj in vLines)
 | 
			
		||||
			foreach (object obj in vLines)
 | 
			
		||||
			{
 | 
			
		||||
				if(obj == null) continue;
 | 
			
		||||
				if (obj == null) continue;
 | 
			
		||||
 | 
			
		||||
				string strAppend = null;
 | 
			
		||||
 | 
			
		||||
				Exception exObj = (obj as Exception);
 | 
			
		||||
				string strObj = (obj as string);
 | 
			
		||||
#if !KeePassLibSD
 | 
			
		||||
#if (!KeePassLibSD && !KeePassRT)
 | 
			
		||||
				StringCollection scObj = (obj as StringCollection);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
				if(exObj != null)
 | 
			
		||||
				if (exObj != null)
 | 
			
		||||
				{
 | 
			
		||||
					if(bFullExceptions)
 | 
			
		||||
					if (bFullExceptions)
 | 
			
		||||
						strAppend = StrUtil.FormatException(exObj);
 | 
			
		||||
					else if((exObj.Message != null) && (exObj.Message.Length > 0))
 | 
			
		||||
					else if ((exObj.Message != null) && (exObj.Message.Length > 0))
 | 
			
		||||
						strAppend = exObj.Message;
 | 
			
		||||
				}
 | 
			
		||||
#if !KeePassLibSD
 | 
			
		||||
				else if(scObj != null)
 | 
			
		||||
#if (!KeePassLibSD && !KeePassRT)
 | 
			
		||||
				else if (scObj != null)
 | 
			
		||||
				{
 | 
			
		||||
					StringBuilder sb = new StringBuilder();
 | 
			
		||||
					foreach(string strCollLine in scObj)
 | 
			
		||||
					foreach (string strCollLine in scObj)
 | 
			
		||||
					{
 | 
			
		||||
						if(sb.Length > 0) sb.AppendLine();
 | 
			
		||||
						if (sb.Length > 0) sb.AppendLine();
 | 
			
		||||
						sb.Append(strCollLine.TrimEnd());
 | 
			
		||||
					}
 | 
			
		||||
					strAppend = sb.ToString();
 | 
			
		||||
				}
 | 
			
		||||
#endif
 | 
			
		||||
				else if(strObj != null)
 | 
			
		||||
				else if (strObj != null)
 | 
			
		||||
					strAppend = strObj;
 | 
			
		||||
				else
 | 
			
		||||
					strAppend = obj.ToString();
 | 
			
		||||
 | 
			
		||||
				if(!string.IsNullOrEmpty(strAppend))
 | 
			
		||||
				if (!string.IsNullOrEmpty(strAppend))
 | 
			
		||||
				{
 | 
			
		||||
					if(bSeparator) sbText.Append(strNewPara);
 | 
			
		||||
					if (bSeparator) sbText.Append(strNewPara);
 | 
			
		||||
					else bSeparator = true;
 | 
			
		||||
 | 
			
		||||
					sbText.Append(strAppend);
 | 
			
		||||
@@ -163,24 +176,30 @@ namespace KeePassLib.Utility
 | 
			
		||||
			return sbText.ToString();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
#if (!KeePassLibSD && !KeePassUAP)
 | 
			
		||||
		internal static Form GetTopForm()
 | 
			
		||||
#if (!KeePassLibSD && !KeePassRT)
 | 
			
		||||
		/*internal static Form GetTopForm()
 | 
			
		||||
		{
 | 
			
		||||
			FormCollection fc = Application.OpenForms;
 | 
			
		||||
			if((fc == null) || (fc.Count == 0)) return null;
 | 
			
		||||
 | 
			
		||||
			return fc[fc.Count - 1];
 | 
			
		||||
		}
 | 
			
		||||
		}*/
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if !KeePassUAP
 | 
			
		||||
		internal static DialogResult SafeShowMessageBox(string strText, string strTitle,
 | 
			
		||||
		private static DialogResult SafeShowMessageBox(string strText, string strTitle,
 | 
			
		||||
			MessageBoxButtons mb, MessageBoxIcon mi, MessageBoxDefaultButton mdb)
 | 
			
		||||
		{
 | 
			
		||||
#if KeePassLibSD
 | 
			
		||||
#if (KeePassLibSD || KeePassRT)
 | 
			
		||||
			return MessageBox.Show(strText, strTitle, mb, mi, mdb);
 | 
			
		||||
#else
 | 
			
		||||
			IWin32Window wnd = null;
 | 
			
		||||
 | 
			
		||||
			if (mb == MessageBoxButtons.OK)
 | 
			
		||||
			{
 | 
			
		||||
				//Android.Widget.Toast toast = ..
 | 
			
		||||
			}
 | 
			
		||||
			//this might help: http://www.gregshackles.com/2011/04/using-background-threads-in-mono-for-android-applications/
 | 
			
		||||
			throw new NotImplementedException();
 | 
			
		||||
			/*IWin32Window wnd = null;
 | 
			
		||||
			try
 | 
			
		||||
			{
 | 
			
		||||
				Form f = GetTopForm();
 | 
			
		||||
@@ -209,11 +228,12 @@ namespace KeePassLib.Utility
 | 
			
		||||
			if(StrUtil.RightToLeft)
 | 
			
		||||
				return MessageBox.Show(strText, strTitle, mb, mi, mdb, m_mboRtl);
 | 
			
		||||
			return MessageBox.Show(strText, strTitle, mb, mi, mdb);
 | 
			
		||||
			*/
 | 
			
		||||
#endif
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
#if !KeePassLibSD
 | 
			
		||||
		internal delegate DialogResult SafeShowMessageBoxInternalDelegate(IWin32Window iParent,
 | 
			
		||||
#if (!KeePassLibSD && !KeePassRT)
 | 
			
		||||
		/*	internal delegate DialogResult SafeShowMessageBoxInternalDelegate(IWin32Window iParent,
 | 
			
		||||
			string strText, string strTitle, MessageBoxButtons mb, MessageBoxIcon mi,
 | 
			
		||||
			MessageBoxDefaultButton mdb);
 | 
			
		||||
 | 
			
		||||
@@ -224,7 +244,7 @@ namespace KeePassLib.Utility
 | 
			
		||||
			if(StrUtil.RightToLeft)
 | 
			
		||||
				return MessageBox.Show(iParent, strText, strTitle, mb, mi, mdb, m_mboRtl);
 | 
			
		||||
			return MessageBox.Show(iParent, strText, strTitle, mb, mi, mdb);
 | 
			
		||||
		}
 | 
			
		||||
		}*/
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		public static void ShowInfo(params object[] vLines)
 | 
			
		||||
@@ -239,7 +259,7 @@ namespace KeePassLib.Utility
 | 
			
		||||
			strTitle = (strTitle ?? PwDefs.ShortProductName);
 | 
			
		||||
			string strText = ObjectsToMessage(vLines);
 | 
			
		||||
 | 
			
		||||
			if(MessageService.MessageShowing != null)
 | 
			
		||||
			if (MessageService.MessageShowing != null)
 | 
			
		||||
				MessageService.MessageShowing(null, new MessageServiceEventArgs(
 | 
			
		||||
					strTitle, strText, MessageBoxButtons.OK, m_mbiInfo));
 | 
			
		||||
 | 
			
		||||
@@ -266,7 +286,7 @@ namespace KeePassLib.Utility
 | 
			
		||||
			string strTitle = PwDefs.ShortProductName;
 | 
			
		||||
			string strText = ObjectsToMessage(vLines, bFullExceptions);
 | 
			
		||||
 | 
			
		||||
			if(MessageService.MessageShowing != null)
 | 
			
		||||
			if (MessageService.MessageShowing != null)
 | 
			
		||||
				MessageService.MessageShowing(null, new MessageServiceEventArgs(
 | 
			
		||||
					strTitle, strText, MessageBoxButtons.OK, m_mbiWarning));
 | 
			
		||||
 | 
			
		||||
@@ -289,18 +309,17 @@ namespace KeePassLib.Utility
 | 
			
		||||
 | 
			
		||||
			try
 | 
			
		||||
			{
 | 
			
		||||
				string strDetails = ObjectsToMessage(vLines, true);
 | 
			
		||||
 | 
			
		||||
#if KeePassLibSD
 | 
			
		||||
				Clipboard.SetDataObject(strDetails);
 | 
			
		||||
#if !KeePassLibSD
 | 
			
		||||
				/* nicht benoetigt - hoffentlich :-)
 | 
			
		||||
Clipboard.Clear();
 | 
			
		||||
Clipboard.SetText(ObjectsToMessage(vLines, true));*/
 | 
			
		||||
#else
 | 
			
		||||
				Clipboard.Clear();
 | 
			
		||||
				Clipboard.SetText(strDetails);
 | 
			
		||||
				Clipboard.SetDataObject(ObjectsToMessage(vLines, true));
 | 
			
		||||
#endif
 | 
			
		||||
			}
 | 
			
		||||
			catch(Exception) { Debug.Assert(false); }
 | 
			
		||||
			catch (Exception) { Debug.Assert(false); }
 | 
			
		||||
 | 
			
		||||
			if(MessageService.MessageShowing != null)
 | 
			
		||||
			if (MessageService.MessageShowing != null)
 | 
			
		||||
				MessageService.MessageShowing(null, new MessageServiceEventArgs(
 | 
			
		||||
					strTitle, strText, MessageBoxButtons.OK, m_mbiFatal));
 | 
			
		||||
 | 
			
		||||
@@ -318,12 +337,12 @@ namespace KeePassLib.Utility
 | 
			
		||||
			string strTextEx = (strText ?? string.Empty);
 | 
			
		||||
			string strTitleEx = (strTitle ?? PwDefs.ShortProductName);
 | 
			
		||||
 | 
			
		||||
			if(MessageService.MessageShowing != null)
 | 
			
		||||
			if (MessageService.MessageShowing != null)
 | 
			
		||||
				MessageService.MessageShowing(null, new MessageServiceEventArgs(
 | 
			
		||||
					strTitleEx, strTextEx, mbb, m_mbiQuestion));
 | 
			
		||||
					strTitleEx, strTextEx, mbb, MessageBoxIcon.Question));
 | 
			
		||||
 | 
			
		||||
			DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx, mbb,
 | 
			
		||||
				m_mbiQuestion, MessageBoxDefaultButton.Button1);
 | 
			
		||||
												 MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
 | 
			
		||||
 | 
			
		||||
			--m_uCurrentMessageCount;
 | 
			
		||||
			return dr;
 | 
			
		||||
@@ -337,12 +356,12 @@ namespace KeePassLib.Utility
 | 
			
		||||
			string strTextEx = (strText ?? string.Empty);
 | 
			
		||||
			string strTitleEx = (strTitle ?? PwDefs.ShortProductName);
 | 
			
		||||
 | 
			
		||||
			if(MessageService.MessageShowing != null)
 | 
			
		||||
			if (MessageService.MessageShowing != null)
 | 
			
		||||
				MessageService.MessageShowing(null, new MessageServiceEventArgs(
 | 
			
		||||
					strTitleEx, strTextEx, MessageBoxButtons.YesNo, mbi));
 | 
			
		||||
					strTitleEx, strTextEx, MessageBoxButtons.YesNo, MessageBoxIcon.Question));
 | 
			
		||||
 | 
			
		||||
			DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx,
 | 
			
		||||
				MessageBoxButtons.YesNo, mbi, bDefaultToYes ?
 | 
			
		||||
												 MessageBoxButtons.YesNo, MessageBoxIcon.Question, bDefaultToYes ?
 | 
			
		||||
				MessageBoxDefaultButton.Button1 : MessageBoxDefaultButton.Button2);
 | 
			
		||||
 | 
			
		||||
			--m_uCurrentMessageCount;
 | 
			
		||||
@@ -351,17 +370,17 @@ namespace KeePassLib.Utility
 | 
			
		||||
 | 
			
		||||
		public static bool AskYesNo(string strText, string strTitle, bool bDefaultToYes)
 | 
			
		||||
		{
 | 
			
		||||
			return AskYesNo(strText, strTitle, bDefaultToYes, m_mbiQuestion);
 | 
			
		||||
			return AskYesNo(strText, strTitle, bDefaultToYes, MessageBoxIcon.Question);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static bool AskYesNo(string strText, string strTitle)
 | 
			
		||||
		{
 | 
			
		||||
			return AskYesNo(strText, strTitle, true, m_mbiQuestion);
 | 
			
		||||
			return AskYesNo(strText, strTitle, true, MessageBoxIcon.Question);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static bool AskYesNo(string strText)
 | 
			
		||||
		{
 | 
			
		||||
			return AskYesNo(strText, null, true, m_mbiQuestion);
 | 
			
		||||
			return AskYesNo(strText, null, true, MessageBoxIcon.Question);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static void ShowLoadWarning(string strFilePath, Exception ex)
 | 
			
		||||
@@ -372,12 +391,26 @@ namespace KeePassLib.Utility
 | 
			
		||||
		public static void ShowLoadWarning(string strFilePath, Exception ex,
 | 
			
		||||
			bool bFullException)
 | 
			
		||||
		{
 | 
			
		||||
			ShowWarning(GetLoadWarningMessage(strFilePath, ex, bFullException));
 | 
			
		||||
			string str = string.Empty;
 | 
			
		||||
 | 
			
		||||
			if ((strFilePath != null) && (strFilePath.Length > 0))
 | 
			
		||||
				str += strFilePath + MessageService.NewParagraph;
 | 
			
		||||
 | 
			
		||||
			str += KLRes.FileLoadFailed;
 | 
			
		||||
 | 
			
		||||
			if ((ex != null) && (ex.Message != null) && (ex.Message.Length > 0))
 | 
			
		||||
			{
 | 
			
		||||
				str += MessageService.NewParagraph;
 | 
			
		||||
				if (!bFullException) str += ex.Message;
 | 
			
		||||
				else str += ObjectsToMessage(new object[] { ex }, true);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			ShowWarning(str);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static void ShowLoadWarning(IOConnectionInfo ioConnection, Exception ex)
 | 
			
		||||
		{
 | 
			
		||||
			if(ioConnection != null)
 | 
			
		||||
			if (ioConnection != null)
 | 
			
		||||
				ShowLoadWarning(ioConnection.GetDisplayName(), ex, false);
 | 
			
		||||
			else ShowWarning(ex);
 | 
			
		||||
		}
 | 
			
		||||
@@ -386,62 +419,34 @@ namespace KeePassLib.Utility
 | 
			
		||||
			bool bCorruptionWarning)
 | 
			
		||||
		{
 | 
			
		||||
			FileLockException fl = (ex as FileLockException);
 | 
			
		||||
			if(fl != null)
 | 
			
		||||
			if (fl != null)
 | 
			
		||||
			{
 | 
			
		||||
				ShowWarning(fl.Message);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			string str = GetSaveWarningMessage(strFilePath, ex, bCorruptionWarning);
 | 
			
		||||
			string str = string.Empty;
 | 
			
		||||
			if ((strFilePath != null) && (strFilePath.Length > 0))
 | 
			
		||||
				str += strFilePath + MessageService.NewParagraph;
 | 
			
		||||
 | 
			
		||||
			str += KLRes.FileSaveFailed;
 | 
			
		||||
 | 
			
		||||
			if ((ex != null) && (ex.Message != null) && (ex.Message.Length > 0))
 | 
			
		||||
				str += MessageService.NewParagraph + ex.Message;
 | 
			
		||||
 | 
			
		||||
			if (bCorruptionWarning)
 | 
			
		||||
				str += MessageService.NewParagraph + KLRes.FileSaveCorruptionWarning;
 | 
			
		||||
 | 
			
		||||
			ShowWarning(str);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static void ShowSaveWarning(IOConnectionInfo ioConnection, Exception ex,
 | 
			
		||||
			bool bCorruptionWarning)
 | 
			
		||||
		{
 | 
			
		||||
			if(ioConnection != null)
 | 
			
		||||
			if (ioConnection != null)
 | 
			
		||||
				ShowSaveWarning(ioConnection.GetDisplayName(), ex, bCorruptionWarning);
 | 
			
		||||
			else ShowWarning(ex);
 | 
			
		||||
		}
 | 
			
		||||
#endif // !KeePassUAP
 | 
			
		||||
 | 
			
		||||
		internal static string GetLoadWarningMessage(string strFilePath,
 | 
			
		||||
			Exception ex, bool bFullException)
 | 
			
		||||
		{
 | 
			
		||||
			string str = string.Empty;
 | 
			
		||||
 | 
			
		||||
			if(!string.IsNullOrEmpty(strFilePath))
 | 
			
		||||
				str += strFilePath + MessageService.NewParagraph;
 | 
			
		||||
 | 
			
		||||
			str += KLRes.FileLoadFailed;
 | 
			
		||||
 | 
			
		||||
			if((ex != null) && !string.IsNullOrEmpty(ex.Message))
 | 
			
		||||
			{
 | 
			
		||||
				str += MessageService.NewParagraph;
 | 
			
		||||
				if(!bFullException) str += ex.Message;
 | 
			
		||||
				else str += ObjectsToMessage(new object[] { ex }, true);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return str;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal static string GetSaveWarningMessage(string strFilePath,
 | 
			
		||||
			Exception ex, bool bCorruptionWarning)
 | 
			
		||||
		{
 | 
			
		||||
			string str = string.Empty;
 | 
			
		||||
			if(!string.IsNullOrEmpty(strFilePath))
 | 
			
		||||
				str += strFilePath + MessageService.NewParagraph;
 | 
			
		||||
 | 
			
		||||
			str += KLRes.FileSaveFailed;
 | 
			
		||||
 | 
			
		||||
			if((ex != null) && !string.IsNullOrEmpty(ex.Message))
 | 
			
		||||
				str += MessageService.NewParagraph + ex.Message;
 | 
			
		||||
 | 
			
		||||
			if(bCorruptionWarning)
 | 
			
		||||
				str += MessageService.NewParagraph + KLRes.FileSaveCorruptionWarning;
 | 
			
		||||
 | 
			
		||||
			return str;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static void ExternalIncrementMessageCount()
 | 
			
		||||
		{
 | 
			
		||||
 
 | 
			
		||||
@@ -166,16 +166,7 @@ namespace KeePassLib.Utility
 | 
			
		||||
 | 
			
		||||
			// m_fOwnWindow = fOwnWindow;
 | 
			
		||||
 | 
			
		||||
			if(IsRequired(1530))
 | 
			
		||||
			{
 | 
			
		||||
				try
 | 
			
		||||
				{
 | 
			
		||||
					ThreadStart ts = new ThreadStart(MonoWorkarounds.FixClipThread);
 | 
			
		||||
					m_thFixClip = new Thread(ts);
 | 
			
		||||
					m_thFixClip.Start();
 | 
			
		||||
				}
 | 
			
		||||
				catch(Exception) { Debug.Assert(false); }
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal static void Terminate()
 | 
			
		||||
@@ -189,89 +180,6 @@ namespace KeePassLib.Utility
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private static void FixClipThread()
 | 
			
		||||
		{
 | 
			
		||||
			try
 | 
			
		||||
			{
 | 
			
		||||
#if !KeePassUAP
 | 
			
		||||
				const string strXSel = "xsel";
 | 
			
		||||
				const AppRunFlags rfW = AppRunFlags.WaitForExit;
 | 
			
		||||
 | 
			
		||||
				string strLast = null;
 | 
			
		||||
				while(true)
 | 
			
		||||
				{
 | 
			
		||||
					string str = NativeLib.RunConsoleApp(strXSel,
 | 
			
		||||
						"--output --clipboard");
 | 
			
		||||
					if(str == null) return; // 'xsel' not installed
 | 
			
		||||
 | 
			
		||||
					if(str != strLast)
 | 
			
		||||
					{
 | 
			
		||||
						if(NeedClipboardWorkaround())
 | 
			
		||||
							NativeLib.RunConsoleApp(strXSel,
 | 
			
		||||
								"--input --clipboard", str, rfW);
 | 
			
		||||
 | 
			
		||||
						strLast = str;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					Thread.Sleep(250);
 | 
			
		||||
				}
 | 
			
		||||
#endif
 | 
			
		||||
			}
 | 
			
		||||
			catch(ThreadAbortException)
 | 
			
		||||
			{
 | 
			
		||||
				try { Thread.ResetAbort(); }
 | 
			
		||||
				catch(Exception) { Debug.Assert(false); }
 | 
			
		||||
			}
 | 
			
		||||
			catch(Exception) { Debug.Assert(false); }
 | 
			
		||||
			finally { m_thFixClip = null; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private static bool NeedClipboardWorkaround()
 | 
			
		||||
		{
 | 
			
		||||
			const bool bDef = true;
 | 
			
		||||
 | 
			
		||||
			try
 | 
			
		||||
			{
 | 
			
		||||
				string strHandle = (NativeLib.RunConsoleApp("xdotool",
 | 
			
		||||
					"getactivewindow") ?? string.Empty).Trim();
 | 
			
		||||
				if(strHandle.Length == 0) return bDef;
 | 
			
		||||
 | 
			
		||||
				// IntPtr h = new IntPtr(long.Parse(strHandle));
 | 
			
		||||
				long.Parse(strHandle); // Validate
 | 
			
		||||
 | 
			
		||||
				// Detection of own windows based on Form.Handle
 | 
			
		||||
				// comparisons doesn't work reliably (Mono's handles
 | 
			
		||||
				// are usually off by 1)
 | 
			
		||||
				// Predicate<IntPtr> fOwnWindow = m_fOwnWindow;
 | 
			
		||||
				// if(fOwnWindow != null)
 | 
			
		||||
				// {
 | 
			
		||||
				//	if(fOwnWindow(h)) return true;
 | 
			
		||||
				// }
 | 
			
		||||
				// else { Debug.Assert(false); }
 | 
			
		||||
 | 
			
		||||
				string strWmClass = (NativeLib.RunConsoleApp("xprop",
 | 
			
		||||
					"-id " + strHandle + " WM_CLASS") ?? string.Empty);
 | 
			
		||||
 | 
			
		||||
				if(strWmClass.IndexOf("\"" + PwDefs.ResClass + "\"",
 | 
			
		||||
					StrUtil.CaseIgnoreCmp) >= 0) return true;
 | 
			
		||||
 | 
			
		||||
				// Workaround for Remmina
 | 
			
		||||
				if(strWmClass.IndexOf("\"Remmina\"",
 | 
			
		||||
					StrUtil.CaseIgnoreCmp) >= 0) return true;
 | 
			
		||||
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			catch(ThreadAbortException) { throw; }
 | 
			
		||||
			catch(Exception) { Debug.Assert(false); }
 | 
			
		||||
 | 
			
		||||
			return bDef;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
#if !KeePassUAP
 | 
			
		||||
		public static void ApplyTo(Form f)
 | 
			
		||||
		{
 | 
			
		||||
			if(!MonoWorkarounds.IsRequired()) return;
 | 
			
		||||
			if(f == null) { Debug.Assert(false); return; }
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Ensure that the file ~/.recently-used is valid (in order to
 | 
			
		||||
		/// prevent Mono's FileDialog from crashing).
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user