complete merging of Keepass 2.35, fix auto-merge errors

This commit is contained in:
Philipp Crocoll
2017-01-12 05:56:20 +01:00
parent 34e572dad1
commit d0879bfe39
12 changed files with 359 additions and 758 deletions

View File

@@ -96,13 +96,6 @@ namespace KeePassLib.Cryptography
m_hash = null; m_hash = null;
} }
} }
public override void Flush()
{
m_sBaseStream.Flush();
}
#if KeePassRT
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
if(disposing) if(disposing)

View File

@@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@@ -19,14 +19,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.Diagnostics; using System.Diagnostics;
#if !KeePassUAP
using System.Security.Cryptography; using System.Security.Cryptography;
#endif using System.Text;
using KeePassLib.Security; using KeePassLib.Security;
using KeePassLib.Utility;
namespace KeePassLib.Cryptography.PasswordGenerator namespace KeePassLib.Cryptography.PasswordGenerator
{ {
@@ -48,58 +46,51 @@ namespace KeePassLib.Cryptography.PasswordGenerator
CustomPwGeneratorPool pwAlgorithmPool) CustomPwGeneratorPool pwAlgorithmPool)
{ {
Debug.Assert(pwProfile != null); 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; 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); 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); 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); e = GenerateCustom(out psOut, pwProfile, crs, pwAlgorithmPool);
else { Debug.Assert(false); psOut = ProtectedString.Empty; } else { Debug.Assert(false); psOut = ProtectedString.Empty; }
}
finally
{
if(crs != null) crs.Dispose();
if(pbKey != null) MemUtil.ZeroByteArray(pbKey);
}
return e; return e;
} }
private static CryptoRandomStream CreateRandomStream(byte[] pbAdditionalEntropy, private static CryptoRandomStream CreateCryptoStream(byte[] pbAdditionalEntropy)
out byte[] pbKey)
{ {
pbKey = CryptoRandom.Instance.GetRandomBytes(256); byte[] pbKey = CryptoRandom.Instance.GetRandomBytes(128);
// Mix in additional entropy // 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) using (SHA512Managed h = new SHA512Managed())
pbKey[nKeyPos] ^= pbAdditionalEntropy[nKeyPos % pbAdditionalEntropy.Length]; {
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, internal static char GenerateCharacter(PwProfile pwProfile,
PwCharSet pwCharSet, CryptoRandomStream crsRandomSource) PwCharSet pwCharSet, CryptoRandomStream crsRandomSource)
{ {
if(pwCharSet.Size == 0) return char.MinValue; if (pwCharSet.Size == 0) return char.MinValue;
ulong uIndex = crsRandomSource.GetRandomUInt64(); ulong uIndex = crsRandomSource.GetRandomUInt64();
uIndex %= (ulong)pwCharSet.Size; uIndex %= (ulong)pwCharSet.Size;
char ch = pwCharSet[(uint)uIndex]; char ch = pwCharSet[(uint)uIndex];
if(pwProfile.NoRepeatingCharacters) if (pwProfile.NoRepeatingCharacters)
pwCharSet.Remove(ch); pwCharSet.Remove(ch);
return ch; return ch;
@@ -109,21 +100,21 @@ namespace KeePassLib.Cryptography.PasswordGenerator
{ {
pwCharSet.Remove(PwCharSet.Invalid); 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); pwCharSet.Remove(pwProfile.ExcludeCharacters);
} }
internal static void ShufflePassword(char[] pPassword, internal static void ShufflePassword(char[] pPassword,
CryptoRandomStream crsRandomSource) CryptoRandomStream crsRandomSource)
{ {
Debug.Assert(pPassword != null); if(pPassword == null) return; Debug.Assert(pPassword != null); if (pPassword == null) return;
Debug.Assert(crsRandomSource != null); if(crsRandomSource == 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(); ulong uRandomIndex = crsRandomSource.GetRandomUInt64();
uRandomIndex %= (ulong)(pPassword.Length - nSelect); uRandomIndex %= (ulong)(pPassword.Length - nSelect);
@@ -141,18 +132,18 @@ namespace KeePassLib.Cryptography.PasswordGenerator
psOut = ProtectedString.Empty; psOut = ProtectedString.Empty;
Debug.Assert(pwProfile.GeneratorType == PasswordGeneratorType.Custom); Debug.Assert(pwProfile.GeneratorType == PasswordGeneratorType.Custom);
if(pwAlgorithmPool == null) return PwgError.UnknownAlgorithm; if (pwAlgorithmPool == null) return PwgError.UnknownAlgorithm;
string strID = pwProfile.CustomAlgorithmUuid; 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); byte[] pbUuid = Convert.FromBase64String(strID);
PwUuid uuid = new PwUuid(pbUuid); PwUuid uuid = new PwUuid(pbUuid);
CustomPwGenerator pwg = pwAlgorithmPool.Find(uuid); 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); ProtectedString pwd = pwg.Generate(pwProfile.CloneDeep(), crs);
if(pwd == null) return PwgError.Unknown; if (pwd == null) return PwgError.Unknown;
psOut = pwd; psOut = pwd;
return PwgError.Success; return PwgError.Success;

View File

@@ -60,6 +60,7 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Collections\ProtectedBinarySet.cs" />
<Compile Include="Collections\VariantDictionary.cs" /> <Compile Include="Collections\VariantDictionary.cs" />
<Compile Include="Cryptography\Cipher\ChaCha20Cipher.cs" /> <Compile Include="Cryptography\Cipher\ChaCha20Cipher.cs" />
<Compile Include="Cryptography\Cipher\ChaCha20Engine.cs" /> <Compile Include="Cryptography\Cipher\ChaCha20Engine.cs" />

View File

@@ -1,6 +1,8 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 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; private ProtectedBinary m_pbKeyData = null;
// Constant initialization vector (unique for KeePass) // 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, 0xDE, 0x13, 0x5B, 0x5F, 0x18, 0xA3, 0x46, 0x70,
0xB2, 0x57, 0x24, 0x29, 0x69, 0x88, 0x98, 0xE6 0xB2, 0x57, 0x24, 0x29, 0x69, 0x88, 0x98, 0xE6
}; };
@@ -63,22 +65,7 @@ namespace KeePassLib.Keys
/// </summary> /// </summary>
public KcpUserAccount() public KcpUserAccount()
{ {
// Test if ProtectedData is supported -- throws an exception throw new NotSupportedException("DataProtection not supported on MonoForAndroid!");
// 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);
} }
// public void Clear() // public void Clear()
@@ -88,8 +75,8 @@ namespace KeePassLib.Keys
private static string GetUserKeyFilePath(bool bCreate) private static string GetUserKeyFilePath(bool bCreate)
{ {
#if KeePassUAP #if KeePassRT
string strUserDir = EnvironmentExt.AppDataRoamingFolderPath; string strUserDir = Windows.Storage.ApplicationData.Current.RoamingFolder.Path;
#else #else
string strUserDir = Environment.GetFolderPath( string strUserDir = Environment.GetFolderPath(
Environment.SpecialFolder.ApplicationData); Environment.SpecialFolder.ApplicationData);
@@ -98,29 +85,26 @@ namespace KeePassLib.Keys
strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false); strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false);
strUserDir += PwDefs.ShortProductName; strUserDir += PwDefs.ShortProductName;
if(bCreate && !Directory.Exists(strUserDir)) if (bCreate && !Directory.Exists(strUserDir))
Directory.CreateDirectory(strUserDir); Directory.CreateDirectory(strUserDir);
strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false); 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; byte[] pbKey = null;
#if !KeePassLibSD #if !KeePassLibSD
try try
{ {
string strFilePath = GetUserKeyFilePath(false); throw new NotSupportedException("DataProtection not supported on MonoForAndroid!");
byte[] pbProtectedKey = File.ReadAllBytes(strFilePath);
pbKey = ProtectedData.Unprotect(pbProtectedKey, m_pbEntropy,
DataProtectionScope.CurrentUser);
} }
catch(Exception) catch (Exception exLoad)
{ {
if(bThrow) throw; if (bShowWarning) MessageService.ShowWarning(exLoad);
pbKey = null; pbKey = null;
} }
#endif #endif
@@ -130,23 +114,17 @@ namespace KeePassLib.Keys
private static byte[] CreateUserKey() private static byte[] CreateUserKey()
{ {
#if KeePassLibSD byte[] pbKey = null;
return null;
#else
string strFilePath = GetUserKeyFilePath(true);
byte[] pbRandomKey = CryptoRandom.Instance.GetRandomBytes(64); #if !KeePassLibSD
byte[] pbProtectedKey = ProtectedData.Protect(pbRandomKey, try
m_pbEntropy, DataProtectionScope.CurrentUser); {
throw new NotSupportedException("DataProtection not supported on MonoForAndroid!");
File.WriteAllBytes(strFilePath, pbProtectedKey); }
catch (Exception) { pbKey = null; }
byte[] pbKey = LoadUserKey(true);
Debug.Assert(MemUtil.ArraysEqual(pbKey, pbRandomKey));
MemUtil.ZeroByteArray(pbRandomKey);
return pbKey;
#endif #endif
return pbKey;
} }
} }
} }

View File

@@ -42,7 +42,6 @@ namespace KeePassLib
private PwUuid m_uuid = PwUuid.Zero; private PwUuid m_uuid = PwUuid.Zero;
private PwGroup m_pParentGroup = null; private PwGroup m_pParentGroup = null;
private DateTime m_tParentGroupLastMod = PwDefs.DtDefaultNow; private DateTime m_tParentGroupLastMod = PwDefs.DtDefaultNow;
private string m_tParentGroupLastModLazy;
private ProtectedStringDictionary m_listStrings = new ProtectedStringDictionary(); private ProtectedStringDictionary m_listStrings = new ProtectedStringDictionary();
private ProtectedBinaryDictionary m_listBinaries = new ProtectedBinaryDictionary(); private ProtectedBinaryDictionary m_listBinaries = new ProtectedBinaryDictionary();
@@ -59,12 +58,6 @@ namespace KeePassLib
private DateTime m_tLastMod = PwDefs.DtDefaultNow; private DateTime m_tLastMod = PwDefs.DtDefaultNow;
private DateTime m_tLastAccess = PwDefs.DtDefaultNow; private DateTime m_tLastAccess = PwDefs.DtDefaultNow;
private DateTime m_tExpire = 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 bool m_bExpires = false;
private ulong m_uUsageCount = 0; private ulong m_uUsageCount = 0;
@@ -82,7 +75,7 @@ namespace KeePassLib
get { return m_uuid; } get { return m_uuid; }
set 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; m_uuid = value;
} }
} }
@@ -103,14 +96,10 @@ namespace KeePassLib
/// </summary> /// </summary>
public DateTime LocationChanged public DateTime LocationChanged
{ {
get { return GetLazyTime(ref m_tParentGroupLastModLazy, ref m_tParentGroupLastMod); } get { return m_tParentGroupLastMod; }
set { m_tParentGroupLastMod = value; m_tParentGroupLastModLazy = null; } set { m_tParentGroupLastMod = value; }
} }
public void SetLazyLocationChanged(string xmlDateTime)
{
m_tParentGroupLastModLazy = xmlDateTime;
}
/// <summary> /// <summary>
/// Get or set all entry strings. /// Get or set all entry strings.
@@ -120,7 +109,7 @@ namespace KeePassLib
get { return m_listStrings; } get { return m_listStrings; }
set 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; m_listStrings = value;
} }
} }
@@ -133,7 +122,7 @@ namespace KeePassLib
get { return m_listBinaries; } get { return m_listBinaries; }
set 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; m_listBinaries = value;
} }
} }
@@ -146,7 +135,7 @@ namespace KeePassLib
get { return m_listAutoType; } get { return m_listAutoType; }
set 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; m_listAutoType = value;
} }
} }
@@ -159,7 +148,7 @@ namespace KeePassLib
get { return m_listHistory; } get { return m_listHistory; }
set 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; m_listHistory = value;
} }
} }
@@ -183,7 +172,7 @@ namespace KeePassLib
get { return m_pwCustomIconID; } get { return m_pwCustomIconID; }
set 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; m_pwCustomIconID = value;
} }
} }
@@ -211,27 +200,8 @@ namespace KeePassLib
/// </summary> /// </summary>
public DateTime CreationTime public DateTime CreationTime
{ {
get { return GetLazyTime(ref m_tCreationLazy, ref m_tCreation); } get { return m_tCreation; }
set { m_tCreation = value; m_tCreationLazy = null; } set { m_tCreation = value; }
}
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;
} }
/// <summary> /// <summary>
@@ -239,13 +209,17 @@ namespace KeePassLib
/// </summary> /// </summary>
public DateTime LastModificationTime public DateTime LastModificationTime
{ {
get { return GetLazyTime(ref m_tLastModLazy, ref m_tLastMod); } get { return m_tLastMod; }
set { m_tLastMod = value; m_tLastModLazy = null; } 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> /// <summary>
@@ -254,13 +228,8 @@ namespace KeePassLib
/// </summary> /// </summary>
public DateTime ExpiryTime public DateTime ExpiryTime
{ {
get { return GetLazyTime(ref m_tExpireLazy, ref m_tExpire); } get { return m_tExpire; }
set { m_tExpire = value; m_tExpireLazy = null; } set { m_tExpire = value; }
}
public void SetLazyExpiryTime(string xmlDateTime)
{
m_tExpireLazy = xmlDateTime;
} }
/// <summary> /// <summary>
@@ -290,7 +259,7 @@ namespace KeePassLib
get { return m_strOverrideUrl; } get { return m_strOverrideUrl; }
set set
{ {
if(value == null) throw new ArgumentNullException("value"); if (value == null) throw new ArgumentNullException("value");
m_strOverrideUrl = value; m_strOverrideUrl = value;
} }
} }
@@ -303,7 +272,7 @@ namespace KeePassLib
get { return m_vTags; } get { return m_vTags; }
set set
{ {
if(value == null) throw new ArgumentNullException("value"); if (value == null) throw new ArgumentNullException("value");
m_vTags = value; m_vTags = value;
} }
} }
@@ -320,7 +289,7 @@ namespace KeePassLib
get { return m_dCustomData; } get { return m_dCustomData; }
internal set 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; m_dCustomData = value;
} }
} }
@@ -339,9 +308,9 @@ namespace KeePassLib
/// and last access times will be set to the current system time.</param> /// and last access times will be set to the current system time.</param>
public PwEntry(bool bCreateNewUuid, bool bSetTimes) 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; DateTime dtNow = DateTime.UtcNow;
m_tCreation = dtNow; m_tCreation = dtNow;
@@ -367,9 +336,9 @@ namespace KeePassLib
{ {
m_pParentGroup = pwParentGroup; 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; DateTime dtNow = DateTime.UtcNow;
m_tCreation = dtNow; m_tCreation = dtNow;
@@ -400,7 +369,6 @@ namespace KeePassLib
peNew.m_uuid = m_uuid; // PwUuid is immutable peNew.m_uuid = m_uuid; // PwUuid is immutable
peNew.m_pParentGroup = m_pParentGroup; peNew.m_pParentGroup = m_pParentGroup;
peNew.m_tParentGroupLastMod = m_tParentGroupLastMod; peNew.m_tParentGroupLastMod = m_tParentGroupLastMod;
peNew.m_tParentGroupLastModLazy = m_tParentGroupLastModLazy;
peNew.m_listStrings = m_listStrings.CloneDeep(); peNew.m_listStrings = m_listStrings.CloneDeep();
peNew.m_listBinaries = m_listBinaries.CloneDeep(); peNew.m_listBinaries = m_listBinaries.CloneDeep();
@@ -419,11 +387,6 @@ namespace KeePassLib
peNew.m_tExpire = m_tExpire; peNew.m_tExpire = m_tExpire;
peNew.m_bExpires = m_bExpires; peNew.m_bExpires = m_bExpires;
peNew.m_uUsageCount = m_uUsageCount; 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; peNew.m_strOverrideUrl = m_strOverrideUrl;
@@ -440,7 +403,6 @@ namespace KeePassLib
peNew.m_uuid = m_uuid; // PwUuid is immutable peNew.m_uuid = m_uuid; // PwUuid is immutable
peNew.m_tParentGroupLastMod = m_tParentGroupLastMod; peNew.m_tParentGroupLastMod = m_tParentGroupLastMod;
peNew.m_tParentGroupLastModLazy = m_tParentGroupLastModLazy;
// Do not assign m_pParentGroup // Do not assign m_pParentGroup
return peNew; return peNew;
@@ -451,11 +413,11 @@ namespace KeePassLib
bool bIgnoreThisLastBackup) bool bIgnoreThisLastBackup)
{ {
PwCompareOptions pwOpt = PwCompareOptions.None; PwCompareOptions pwOpt = PwCompareOptions.None;
if(bIgnoreParentGroup) pwOpt |= PwCompareOptions.IgnoreParentGroup; if (bIgnoreParentGroup) pwOpt |= PwCompareOptions.IgnoreParentGroup;
if(bIgnoreLastMod) pwOpt |= PwCompareOptions.IgnoreLastMod; if (bIgnoreLastMod) pwOpt |= PwCompareOptions.IgnoreLastMod;
if(bIgnoreLastAccess) pwOpt |= PwCompareOptions.IgnoreLastAccess; if (bIgnoreLastAccess) pwOpt |= PwCompareOptions.IgnoreLastAccess;
if(bIgnoreHistory) pwOpt |= PwCompareOptions.IgnoreHistory; if (bIgnoreHistory) pwOpt |= PwCompareOptions.IgnoreHistory;
if(bIgnoreThisLastBackup) pwOpt |= PwCompareOptions.IgnoreLastBackup; if (bIgnoreThisLastBackup) pwOpt |= PwCompareOptions.IgnoreLastBackup;
return pwOpt; return pwOpt;
} }
@@ -480,7 +442,7 @@ namespace KeePassLib
public bool EqualsEntry(PwEntry pe, PwCompareOptions pwOpt, public bool EqualsEntry(PwEntry pe, PwCompareOptions pwOpt,
MemProtCmpMode mpCmpStr) MemProtCmpMode mpCmpStr)
{ {
if(pe == null) { Debug.Assert(false); return false; } if (pe == null) { Debug.Assert(false); return false; }
bool bNeEqStd = ((pwOpt & PwCompareOptions.NullEmptyEquivStd) != bool bNeEqStd = ((pwOpt & PwCompareOptions.NullEmptyEquivStd) !=
PwCompareOptions.None); PwCompareOptions.None);
@@ -489,70 +451,70 @@ namespace KeePassLib
bool bIgnoreLastMod = ((pwOpt & PwCompareOptions.IgnoreLastMod) != bool bIgnoreLastMod = ((pwOpt & PwCompareOptions.IgnoreLastMod) !=
PwCompareOptions.None); PwCompareOptions.None);
if(!m_uuid.Equals(pe.m_uuid)) return false; if (!m_uuid.Equals(pe.m_uuid)) return false;
if((pwOpt & PwCompareOptions.IgnoreParentGroup) == PwCompareOptions.None) if ((pwOpt & PwCompareOptions.IgnoreParentGroup) == PwCompareOptions.None)
{ {
if(m_pParentGroup != pe.m_pParentGroup) return false; if (m_pParentGroup != pe.m_pParentGroup) return false;
if(!bIgnoreLastMod && (LocationChanged != pe.LocationChanged)) if (!bIgnoreLastMod && (m_tParentGroupLastMod != pe.m_tParentGroupLastMod))
return false; return false;
} }
if(!m_listStrings.EqualsDictionary(pe.m_listStrings, pwOpt, mpCmpStr)) if (!m_listStrings.EqualsDictionary(pe.m_listStrings, pwOpt, mpCmpStr))
return false; 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) != bool bIgnoreLastBackup = ((pwOpt & PwCompareOptions.IgnoreLastBackup) !=
PwCompareOptions.None); PwCompareOptions.None);
if(!bIgnoreLastBackup && (m_listHistory.UCount != pe.m_listHistory.UCount)) if (!bIgnoreLastBackup && (m_listHistory.UCount != pe.m_listHistory.UCount))
return false; return false;
if(bIgnoreLastBackup && (m_listHistory.UCount == 0)) if (bIgnoreLastBackup && (m_listHistory.UCount == 0))
{ {
Debug.Assert(false); Debug.Assert(false);
return 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; return false;
PwCompareOptions cmpSub = PwCompareOptions.IgnoreParentGroup; PwCompareOptions cmpSub = PwCompareOptions.IgnoreParentGroup;
if(bNeEqStd) cmpSub |= PwCompareOptions.NullEmptyEquivStd; if (bNeEqStd) cmpSub |= PwCompareOptions.NullEmptyEquivStd;
if(bIgnoreLastMod) cmpSub |= PwCompareOptions.IgnoreLastMod; if (bIgnoreLastMod) cmpSub |= PwCompareOptions.IgnoreLastMod;
if(bIgnoreLastAccess) cmpSub |= PwCompareOptions.IgnoreLastAccess; 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)) uHist), cmpSub, MemProtCmpMode.None))
return false; return false;
} }
} }
if(m_pwIcon != pe.m_pwIcon) return false; if (m_pwIcon != pe.m_pwIcon) return false;
if(!m_pwCustomIconID.Equals(pe.m_pwCustomIconID)) return false; if (!m_pwCustomIconID.Equals(pe.m_pwCustomIconID)) return false;
if(m_clrForeground != pe.m_clrForeground) return false; if (m_clrForeground != pe.m_clrForeground) return false;
if(m_clrBackground != pe.m_clrBackground) return false; if (m_clrBackground != pe.m_clrBackground) return false;
if(CreationTime != pe.CreationTime) return false; if (m_tCreation != pe.m_tCreation) return false;
if(!bIgnoreLastMod && (LastModificationTime != pe.LastModificationTime)) return false; if (!bIgnoreLastMod && (m_tLastMod != pe.m_tLastMod)) return false;
if(!bIgnoreLastAccess && (LastAccessTime != pe.LastAccessTime)) return false; if (!bIgnoreLastAccess && (m_tLastAccess != pe.m_tLastAccess)) return false;
if(ExpiryTime != pe.ExpiryTime) return false; if (m_tExpire != pe.m_tExpire) return false;
if(m_bExpires != pe.m_bExpires) return false; if (m_bExpires != pe.m_bExpires) return false;
if(!bIgnoreLastAccess && (m_uUsageCount != pe.m_uUsageCount)) 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; if (m_vTags.Count != pe.m_vTags.Count) return false;
for(int iTag = 0; iTag < m_vTags.Count; ++iTag) 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; return true;
} }
@@ -570,21 +532,23 @@ namespace KeePassLib
public void AssignProperties(PwEntry peTemplate, bool bOnlyIfNewer, public void AssignProperties(PwEntry peTemplate, bool bOnlyIfNewer,
bool bIncludeHistory, bool bAssignLocationChanged) 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 // Template UUID should be the same as the current one
Debug.Assert(m_uuid.Equals(peTemplate.m_uuid)); Debug.Assert(m_uuid.Equals(peTemplate.m_uuid));
m_uuid = peTemplate.m_uuid; m_uuid = peTemplate.m_uuid;
if(bAssignLocationChanged) if (bAssignLocationChanged)
m_tParentGroupLastMod = peTemplate.LocationChanged; m_tParentGroupLastMod = peTemplate.m_tParentGroupLastMod;
m_listStrings = peTemplate.m_listStrings.CloneDeep(); m_listStrings = peTemplate.m_listStrings.CloneDeep();
m_listBinaries = peTemplate.m_listBinaries.CloneDeep(); m_listBinaries = peTemplate.m_listBinaries.CloneDeep();
m_listAutoType = peTemplate.m_listAutoType.CloneDeep(); m_listAutoType = peTemplate.m_listAutoType.CloneDeep();
if(bIncludeHistory) if (bIncludeHistory)
m_listHistory = peTemplate.m_listHistory.CloneDeep(); m_listHistory = peTemplate.m_listHistory.CloneDeep();
m_pwIcon = peTemplate.m_pwIcon; m_pwIcon = peTemplate.m_pwIcon;
@@ -593,10 +557,10 @@ namespace KeePassLib
m_clrForeground = peTemplate.m_clrForeground; m_clrForeground = peTemplate.m_clrForeground;
m_clrBackground = peTemplate.m_clrBackground; m_clrBackground = peTemplate.m_clrBackground;
m_tCreation = peTemplate.CreationTime; m_tCreation = peTemplate.m_tCreation;
m_tLastMod = peTemplate.LastModificationTime; m_tLastMod = peTemplate.m_tLastMod;
m_tLastAccess = peTemplate.LastAccessTime; m_tLastAccess = peTemplate.m_tLastAccess;
m_tExpire = peTemplate.ExpiryTime; m_tExpire = peTemplate.m_tExpire;
m_bExpires = peTemplate.m_bExpires; m_bExpires = peTemplate.m_bExpires;
m_uUsageCount = peTemplate.m_uUsageCount; m_uUsageCount = peTemplate.m_uUsageCount;
@@ -631,16 +595,16 @@ namespace KeePassLib
m_tLastAccess = DateTime.UtcNow; m_tLastAccess = DateTime.UtcNow;
++m_uUsageCount; ++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, this.Touched(this, new ObjectTouchedEventArgs(this,
bModified, bTouchParents)); bModified, bTouchParents));
if(PwEntry.EntryTouched != null) if (PwEntry.EntryTouched != null)
PwEntry.EntryTouched(this, new ObjectTouchedEventArgs(this, PwEntry.EntryTouched(this, new ObjectTouchedEventArgs(this,
bModified, bTouchParents)); bModified, bTouchParents));
if(bTouchParents && (m_pParentGroup != null)) if (bTouchParents && (m_pParentGroup != null))
m_pParentGroup.Touch(bModified, true); m_pParentGroup.Touch(bModified, true);
} }
@@ -669,7 +633,7 @@ namespace KeePassLib
m_listHistory.Add(peCopy); // Must be added at end, see EqualsEntry m_listHistory.Add(peCopy); // Must be added at end, see EqualsEntry
if(pwHistMntcSettings != null) MaintainBackups(pwHistMntcSettings); if (pwHistMntcSettings != null) MaintainBackups(pwHistMntcSettings);
} }
/// <summary> /// <summary>
@@ -695,11 +659,11 @@ namespace KeePassLib
public void RestoreFromBackup(uint uBackupIndex, PwDatabase pwHistMntcSettings) public void RestoreFromBackup(uint uBackupIndex, PwDatabase pwHistMntcSettings)
{ {
Debug.Assert(uBackupIndex < m_listHistory.UCount); Debug.Assert(uBackupIndex < m_listHistory.UCount);
if(uBackupIndex >= m_listHistory.UCount) if (uBackupIndex >= m_listHistory.UCount)
throw new ArgumentOutOfRangeException("uBackupIndex"); throw new ArgumentOutOfRangeException("uBackupIndex");
PwEntry pe = m_listHistory.GetAt(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 CreateBackup(pwHistMntcSettings); // Backup current data before restoring
AssignProperties(pe, false, false, false); AssignProperties(pe, false, false, false);
@@ -708,16 +672,16 @@ namespace KeePassLib
public bool HasBackupOfData(PwEntry peData, bool bIgnoreLastMod, public bool HasBackupOfData(PwEntry peData, bool bIgnoreLastMod,
bool bIgnoreLastAccess) bool bIgnoreLastAccess)
{ {
if(peData == null) { Debug.Assert(false); return false; } if (peData == null) { Debug.Assert(false); return false; }
PwCompareOptions cmpOpt = (PwCompareOptions.IgnoreParentGroup | PwCompareOptions cmpOpt = (PwCompareOptions.IgnoreParentGroup |
PwCompareOptions.IgnoreHistory | PwCompareOptions.NullEmptyEquivStd); PwCompareOptions.IgnoreHistory | PwCompareOptions.NullEmptyEquivStd);
if(bIgnoreLastMod) cmpOpt |= PwCompareOptions.IgnoreLastMod; if (bIgnoreLastMod) cmpOpt |= PwCompareOptions.IgnoreLastMod;
if(bIgnoreLastAccess) cmpOpt |= PwCompareOptions.IgnoreLastAccess; 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; return false;
@@ -731,14 +695,14 @@ namespace KeePassLib
/// </summary> /// </summary>
public bool MaintainBackups(PwDatabase pwSettings) public bool MaintainBackups(PwDatabase pwSettings)
{ {
if(pwSettings == null) { Debug.Assert(false); return false; } if (pwSettings == null) { Debug.Assert(false); return false; }
bool bDeleted = false; bool bDeleted = false;
int nMaxItems = pwSettings.HistoryMaxItems; int nMaxItems = pwSettings.HistoryMaxItems;
if(nMaxItems >= 0) if (nMaxItems >= 0)
{ {
while(m_listHistory.UCount > (uint)nMaxItems) while (m_listHistory.UCount > (uint)nMaxItems)
{ {
RemoveOldestBackup(); RemoveOldestBackup();
bDeleted = true; bDeleted = true;
@@ -746,14 +710,14 @@ namespace KeePassLib
} }
long lMaxSize = pwSettings.HistoryMaxSize; long lMaxSize = pwSettings.HistoryMaxSize;
if(lMaxSize >= 0) if (lMaxSize >= 0)
{ {
while(true) while (true)
{ {
ulong uHistSize = 0; 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(); RemoveOldestBackup();
bDeleted = true; bDeleted = true;
@@ -770,24 +734,24 @@ namespace KeePassLib
DateTime dtMin = TimeUtil.SafeMaxValueUtc; DateTime dtMin = TimeUtil.SafeMaxValueUtc;
uint idxRemove = uint.MaxValue; 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); PwEntry pe = m_listHistory.GetAt(u);
if(TimeUtil.Compare(pe.LastModificationTime, dtMin, true) < 0) if (TimeUtil.Compare(pe.LastModificationTime, dtMin, true) < 0)
{ {
idxRemove = u; idxRemove = u;
dtMin = pe.LastModificationTime; dtMin = pe.LastModificationTime;
} }
} }
if(idxRemove != uint.MaxValue) m_listHistory.RemoveAt(idxRemove); if (idxRemove != uint.MaxValue) m_listHistory.RemoveAt(idxRemove);
} }
public bool GetAutoTypeEnabled() 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 m_pParentGroup.GetAutoTypeEnabledInherited();
return PwGroup.DefaultAutoTypeEnabled; return PwGroup.DefaultAutoTypeEnabled;
@@ -798,23 +762,23 @@ namespace KeePassLib
string strSeq = m_listAutoType.DefaultSequence; string strSeq = m_listAutoType.DefaultSequence;
PwGroup pg = m_pParentGroup; PwGroup pg = m_pParentGroup;
while(pg != null) while (pg != null)
{ {
if(strSeq.Length != 0) break; if (strSeq.Length != 0) break;
strSeq = pg.DefaultAutoTypeSequence; strSeq = pg.DefaultAutoTypeSequence;
pg = pg.ParentGroup; 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; return PwDefs.DefaultAutoTypeSequence;
} }
public bool GetSearchingEnabled() public bool GetSearchingEnabled()
{ {
if(m_pParentGroup != null) if (m_pParentGroup != null)
return m_pParentGroup.GetSearchingEnabledInherited(); return m_pParentGroup.GetSearchingEnabledInherited();
return PwGroup.DefaultSearchingEnabled; return PwGroup.DefaultSearchingEnabled;
@@ -829,34 +793,34 @@ namespace KeePassLib
{ {
ulong uSize = 128; // Approx fixed length data 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.Key.Length;
uSize += (ulong)kvpStr.Value.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 += (ulong)kvpBin.Key.Length;
uSize += kvpBin.Value.Length; uSize += kvpBin.Value.Length;
} }
uSize += (ulong)m_listAutoType.DefaultSequence.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.WindowName.Length;
uSize += (ulong)a.Sequence.Length; uSize += (ulong)a.Sequence.Length;
} }
foreach(PwEntry peHistory in m_listHistory) foreach (PwEntry peHistory in m_listHistory)
uSize += peHistory.GetSize(); uSize += peHistory.GetSize();
uSize += (ulong)m_strOverrideUrl.Length; uSize += (ulong)m_strOverrideUrl.Length;
foreach(string strTag in m_vTags) foreach (string strTag in m_vTags)
uSize += (ulong)strTag.Length; 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; uSize += (ulong)kvp.Key.Length + (ulong)kvp.Value.Length;
return uSize; return uSize;
@@ -864,11 +828,11 @@ namespace KeePassLib
public bool HasTag(string strTag) 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; return false;
@@ -876,11 +840,11 @@ namespace KeePassLib
public bool AddTag(string strTag) 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); m_vTags.Add(strTag);
@@ -889,11 +853,11 @@ namespace KeePassLib
public bool RemoveTag(string strTag) 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); m_vTags.RemoveAt(i);
return true; return true;
@@ -906,9 +870,9 @@ namespace KeePassLib
public bool IsContainedIn(PwGroup pgContainer) public bool IsContainedIn(PwGroup pgContainer)
{ {
PwGroup pgCur = m_pParentGroup; PwGroup pgCur = m_pParentGroup;
while(pgCur != null) while (pgCur != null)
{ {
if(pgCur == pgContainer) return true; if (pgCur == pgContainer) return true;
pgCur = pgCur.ParentGroup; pgCur = pgCur.ParentGroup;
} }
@@ -920,26 +884,15 @@ namespace KeePassLib
{ {
this.Uuid = pwNewUuid; this.Uuid = pwNewUuid;
if(bAlsoChangeHistoryUuids) if (bAlsoChangeHistoryUuids)
{ {
foreach(PwEntry peHist in m_listHistory) foreach (PwEntry peHist in m_listHistory)
{ {
peHist.Uuid = pwNewUuid; 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() public void SetCreatedNow()
{ {
DateTime dt = DateTime.UtcNow; DateTime dt = DateTime.UtcNow;
@@ -968,7 +921,7 @@ namespace KeePassLib
public PwEntryComparer(string strFieldName, bool bCaseInsensitive, public PwEntryComparer(string strFieldName, bool bCaseInsensitive,
bool bCompareNaturally) bool bCompareNaturally)
{ {
if(strFieldName == null) throw new ArgumentNullException("strFieldName"); if (strFieldName == null) throw new ArgumentNullException("strFieldName");
m_strFieldName = strFieldName; m_strFieldName = strFieldName;
m_bCaseInsensitive = bCaseInsensitive; m_bCaseInsensitive = bCaseInsensitive;
@@ -980,7 +933,7 @@ namespace KeePassLib
string strA = a.Strings.ReadSafe(m_strFieldName); string strA = a.Strings.ReadSafe(m_strFieldName);
string strB = b.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); return string.Compare(strA, strB, m_bCaseInsensitive);
} }

View File

@@ -47,7 +47,6 @@ namespace KeePassLib
private PwObjectList<PwEntry> m_listEntries = new PwObjectList<PwEntry>(); private PwObjectList<PwEntry> m_listEntries = new PwObjectList<PwEntry>();
private PwGroup m_pParentGroup = null; private PwGroup m_pParentGroup = null;
private DateTime m_tParentGroupLastMod = PwDefs.DtDefaultNow; private DateTime m_tParentGroupLastMod = PwDefs.DtDefaultNow;
private string m_tParentGroupLastModLazy;
private PwUuid m_uuid = PwUuid.Zero; private PwUuid m_uuid = PwUuid.Zero;
private string m_strName = string.Empty; private string m_strName = string.Empty;
@@ -63,12 +62,6 @@ namespace KeePassLib
private bool m_bExpires = false; private bool m_bExpires = false;
private ulong m_uUsageCount = 0; 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_bIsExpanded = true;
private bool m_bVirtual = false; private bool m_bVirtual = false;
@@ -160,12 +153,8 @@ namespace KeePassLib
/// </summary> /// </summary>
public DateTime LocationChanged public DateTime LocationChanged
{ {
get { return GetLazyTime(ref m_tParentGroupLastModLazy, ref m_tParentGroupLastMod); } get { return m_tParentGroupLastMod; }
set { m_tParentGroupLastMod = value; m_tParentGroupLastModLazy = null; } set { m_tParentGroupLastMod = value; }
}
public void SetLazyLocationChanged(string xmlDateTime)
{
m_tParentGroupLastModLazy = xmlDateTime;
} }
/// <summary> /// <summary>
@@ -183,13 +172,8 @@ namespace KeePassLib
/// </summary> /// </summary>
public DateTime CreationTime public DateTime CreationTime
{ {
get { return GetLazyTime(ref m_tCreationLazy, ref m_tCreation); } get { return m_tCreation; }
set { m_tCreation = value; m_tCreationLazy = null; } set { m_tCreation = value; }
}
public void SetLazyCreationTime(string xmlDateTime)
{
m_tCreationLazy = xmlDateTime;
} }
/// <summary> /// <summary>
@@ -197,13 +181,8 @@ namespace KeePassLib
/// </summary> /// </summary>
public DateTime LastModificationTime public DateTime LastModificationTime
{ {
get { return GetLazyTime(ref m_tLastModLazy, ref m_tLastMod); } get { return m_tLastMod; }
set { m_tLastMod = value; m_tLastModLazy = null; } set { m_tLastMod = value; }
}
public void SetLazyLastModificationTime(string xmlDateTime)
{
m_tLastModLazy = xmlDateTime;
} }
/// <summary> /// <summary>
@@ -211,13 +190,8 @@ namespace KeePassLib
/// </summary> /// </summary>
public DateTime LastAccessTime public DateTime LastAccessTime
{ {
get { return GetLazyTime(ref m_tLastAccessLazy, ref m_tLastAccess); } get { return m_tLastAccess; }
set { m_tLastAccess = value; m_tLastAccessLazy = null; } set { m_tLastAccess = value; }
}
public void SetLazyLastAccessTime(string xmlDateTime)
{
m_tLastAccessLazy = xmlDateTime;
} }
/// <summary> /// <summary>
@@ -225,12 +199,8 @@ namespace KeePassLib
/// </summary> /// </summary>
public DateTime ExpiryTime public DateTime ExpiryTime
{ {
get { return GetLazyTime(ref m_tExpireLazy, ref m_tExpire); } get { return m_tExpire; }
set { m_tExpire = value; m_tExpireLazy = null; } set { m_tExpire = value; }
}
public void SetLazyExpiryTime(string xmlDateTime)
{
m_tExpireLazy = xmlDateTime;
} }
/// <summary> /// <summary>
@@ -406,7 +376,6 @@ namespace KeePassLib
pg.m_listEntries = m_listEntries.CloneDeep(); pg.m_listEntries = m_listEntries.CloneDeep();
pg.m_pParentGroup = m_pParentGroup; pg.m_pParentGroup = m_pParentGroup;
pg.m_tParentGroupLastMod = m_tParentGroupLastMod; pg.m_tParentGroupLastMod = m_tParentGroupLastMod;
pg.m_tParentGroupLastModLazy = m_tParentGroupLastModLazy;
pg.m_strName = m_strName; pg.m_strName = m_strName;
pg.m_strNotes = m_strNotes; pg.m_strNotes = m_strNotes;
@@ -421,11 +390,6 @@ namespace KeePassLib
pg.m_bExpires = m_bExpires; pg.m_bExpires = m_bExpires;
pg.m_uUsageCount = m_uUsageCount; 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_bIsExpanded = m_bIsExpanded;
pg.m_bVirtual = m_bVirtual; pg.m_bVirtual = m_bVirtual;
@@ -483,7 +447,7 @@ namespace KeePassLib
if (!m_pwCustomIconID.Equals(pg.m_pwCustomIconID)) return false; if (!m_pwCustomIconID.Equals(pg.m_pwCustomIconID)) return false;
if (m_tCreation != pg.m_tCreation) 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 (!bIgnoreLastAccess && (m_tLastAccess != pg.m_tLastAccess)) return false;
if (m_tExpire != pg.m_tExpire) return false; if (m_tExpire != pg.m_tExpire) return false;
if (m_bExpires != pg.m_bExpires) return false; if (m_bExpires != pg.m_bExpires) return false;
@@ -541,9 +505,9 @@ namespace KeePassLib
public void AssignProperties(PwGroup pgTemplate, bool bOnlyIfNewer, public void AssignProperties(PwGroup pgTemplate, bool bOnlyIfNewer,
bool bAssignLocationChanged) 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)) true) < 0))
return; return;
@@ -551,7 +515,7 @@ namespace KeePassLib
Debug.Assert(m_uuid.Equals(pgTemplate.m_uuid)); Debug.Assert(m_uuid.Equals(pgTemplate.m_uuid));
m_uuid = pgTemplate.m_uuid; m_uuid = pgTemplate.m_uuid;
if (bAssignLocationChanged) if(bAssignLocationChanged)
m_tParentGroupLastMod = pgTemplate.m_tParentGroupLastMod; m_tParentGroupLastMod = pgTemplate.m_tParentGroupLastMod;
m_strName = pgTemplate.m_strName; m_strName = pgTemplate.m_strName;
@@ -560,11 +524,10 @@ namespace KeePassLib
m_pwIcon = pgTemplate.m_pwIcon; m_pwIcon = pgTemplate.m_pwIcon;
m_pwCustomIconID = pgTemplate.m_pwCustomIconID; m_pwCustomIconID = pgTemplate.m_pwCustomIconID;
m_tCreation = pgTemplate.CreationTime; m_tCreation = pgTemplate.m_tCreation;
m_tLastMod = pgTemplate.LastModificationTime; m_tLastMod = pgTemplate.m_tLastMod;
m_tLastAccess = pgTemplate.LastAccessTime; m_tLastAccess = pgTemplate.m_tLastAccess;
m_tExpire = pgTemplate.ExpiryTime; m_tExpire = pgTemplate.m_tExpire;
m_bExpires = pgTemplate.m_bExpires; m_bExpires = pgTemplate.m_bExpires;
m_uUsageCount = pgTemplate.m_uUsageCount; m_uUsageCount = pgTemplate.m_uUsageCount;
@@ -602,16 +565,16 @@ namespace KeePassLib
m_tLastAccess = DateTime.Now; m_tLastAccess = DateTime.Now;
++m_uUsageCount; ++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, this.Touched(this, new ObjectTouchedEventArgs(this,
bModified, bTouchParents)); bModified, bTouchParents));
if (PwGroup.GroupTouched != null) if(PwGroup.GroupTouched != null)
PwGroup.GroupTouched(this, new ObjectTouchedEventArgs(this, PwGroup.GroupTouched(this, new ObjectTouchedEventArgs(this,
bModified, bTouchParents)); bModified, bTouchParents));
if (bTouchParents && (m_pParentGroup != null)) if(bTouchParents && (m_pParentGroup != null))
m_pParentGroup.Touch(bModified, true); m_pParentGroup.Touch(bModified, true);
} }
@@ -628,13 +591,13 @@ namespace KeePassLib
/// <param name="uNumEntries">Number of entries.</param> /// <param name="uNumEntries">Number of entries.</param>
public void GetCounts(bool bRecursive, out uint uNumGroups, out uint uNumEntries) public void GetCounts(bool bRecursive, out uint uNumGroups, out uint uNumEntries)
{ {
if (bRecursive) if(bRecursive)
{ {
uint uTotalGroups = m_listGroups.UCount; uint uTotalGroups = m_listGroups.UCount;
uint uTotalEntries = m_listEntries.UCount; uint uTotalEntries = m_listEntries.UCount;
uint uSubGroupCount, uSubEntryCount; uint uSubGroupCount, uSubEntryCount;
foreach (PwGroup pg in m_listGroups) foreach(PwGroup pg in m_listGroups)
{ {
pg.GetCounts(true, out uSubGroupCount, out uSubEntryCount); pg.GetCounts(true, out uSubGroupCount, out uSubEntryCount);
@@ -678,7 +641,7 @@ namespace KeePassLib
{ {
bool bRet = false; bool bRet = false;
switch (tm) switch(tm)
{ {
case TraversalMethod.None: case TraversalMethod.None:
bRet = true; bRet = true;
@@ -696,26 +659,26 @@ namespace KeePassLib
private bool PreOrderTraverseTree(GroupHandler groupHandler, EntryHandler entryHandler) 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); pg.PreOrderTraverseTree(groupHandler, entryHandler);
} }
} }
else // groupHandler == null else // groupHandler == null
{ {
foreach (PwGroup pg in m_listGroups) foreach(PwGroup pg in m_listGroups)
{ {
pg.PreOrderTraverseTree(null, entryHandler); pg.PreOrderTraverseTree(null, entryHandler);
} }
@@ -732,11 +695,11 @@ namespace KeePassLib
{ {
LinkedList<PwGroup> list = new LinkedList<PwGroup>(); LinkedList<PwGroup> list = new LinkedList<PwGroup>();
foreach (PwGroup pg in m_listGroups) foreach(PwGroup pg in m_listGroups)
{ {
list.AddLast(pg); list.AddLast(pg);
if (pg.Groups.UCount != 0) if(pg.Groups.UCount != 0)
LinearizeGroupRecursive(list, pg, 1); LinearizeGroupRecursive(list, pg, 1);
} }
@@ -745,13 +708,13 @@ namespace KeePassLib
private void LinearizeGroupRecursive(LinkedList<PwGroup> list, PwGroup pg, ushort uLevel) 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); list.AddLast(pwg);
if (pwg.Groups.UCount != 0) if(pwg.Groups.UCount != 0)
LinearizeGroupRecursive(list, pwg, (ushort)(uLevel + 1)); LinearizeGroupRecursive(list, pwg, (ushort)(uLevel + 1));
} }
} }
@@ -765,12 +728,12 @@ namespace KeePassLib
/// <returns>Flat list of all entries.</returns> /// <returns>Flat list of all entries.</returns>
public static LinkedList<PwEntry> GetFlatEntryList(LinkedList<PwGroup> flatGroupList) 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>(); 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); list.AddLast(pe);
} }
@@ -794,7 +757,7 @@ namespace KeePassLib
pe.Strings.EnableProtection(strFieldName, bEnable); pe.Strings.EnableProtection(strFieldName, bEnable);
// Do the same for all history items // Do the same for all history items
foreach (PwEntry peHistory in pe.History) foreach(PwEntry peHistory in pe.History)
{ {
peHistory.Strings.EnableProtection(strFieldName, bEnable); peHistory.Strings.EnableProtection(strFieldName, bEnable);
} }
@@ -1723,15 +1686,6 @@ namespace KeePassLib
return pg; 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> public sealed class PwGroupComparer : IComparer<PwGroup>

View File

@@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
@@ -53,185 +53,6 @@ namespace KeePassLib.Serialization
} }
#endif #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 public static class IOConnection
{ {
#if (!KeePassLibSD && !KeePassRT) #if (!KeePassLibSD && !KeePassRT)

View File

@@ -499,22 +499,21 @@ namespace KeePassLib.Serialization
Debug.Assert(tl != null); Debug.Assert(tl != null);
if(xr.Name == ElemCreationTime) if(xr.Name == ElemCreationTime)
tl.SetLazyCreationTime(ReadString(xr)); tl.CreationTime = ReadTime(xr);
else if (xr.Name == ElemLastModTime) else if(xr.Name == ElemLastModTime)
tl.SetLazyLastModificationTime(ReadString(xr)); tl.LastModificationTime = ReadTime(xr);
else if (xr.Name == ElemLastAccessTime) else if(xr.Name == ElemLastAccessTime)
tl.SetLazyLastAccessTime(ReadString(xr)); tl.LastAccessTime = ReadTime(xr);
else if (xr.Name == ElemExpiryTime) else if(xr.Name == ElemExpiryTime)
tl.SetLazyExpiryTime(ReadString(xr)); tl.ExpiryTime = ReadTime(xr);
else if (xr.Name == ElemExpires) else if(xr.Name == ElemExpires)
tl.Expires = ReadBool(xr, false); tl.Expires = ReadBool(xr, false);
else if(xr.Name == ElemUsageCount) else if(xr.Name == ElemUsageCount)
tl.UsageCount = ReadULong(xr, 0); tl.UsageCount = ReadULong(xr, 0);
else if(xr.Name == ElemLocationChanged) else if(xr.Name == ElemLocationChanged)
tl.SetLazyLocationChanged(ReadString(xr)); tl.LocationChanged = ReadTime(xr);
else ReadUnknown(xr); else ReadUnknown(xr);
break; break;
case KdbContext.EntryString: case KdbContext.EntryString:
if(xr.Name == ElemKey) if(xr.Name == ElemKey)
m_ctxStringName = ReadString(xr); m_ctxStringName = ReadString(xr);

View File

@@ -225,7 +225,7 @@ namespace KeePassLib.Serialization
if (fmt == KdbxFormat.ProtocolBuffers) 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)); Kp2aLog.Log(String.Format("KdbpFile.ReadDocument: {0}ms", stopWatch.ElapsedMilliseconds));
@@ -577,8 +577,6 @@ namespace KeePassLib.Serialization
else { Debug.Assert(false); } else { Debug.Assert(false); }
} }
return vEntries; */
return vEntries; */ return vEntries; */

View File

@@ -209,7 +209,7 @@ namespace KeePassLib.Serialization
if (m_format == KdbxFormat.ProtocolBuffers) if (m_format == KdbxFormat.ProtocolBuffers)
{ {
KdbpFile.WriteDocument(m_pwDatabase, sXml, m_pbProtectedStreamKey, m_pbHashOfHeader); KdbpFile.WriteDocument(m_pwDatabase, sXml, m_pbInnerRandomStreamKey, m_pbHashOfHeader);
} }
else else
{ {
@@ -1014,17 +1014,12 @@ namespace KeePassLib.Serialization
} }
public static bool WriteEntries(Stream msOutput, PwDatabase pdContext, public static bool WriteEntries(Stream msOutput, PwDatabase pdContext,
PwEntry[] vEntries) PwEntry[] vEntries)
{ {
if(msOutput == null) { Debug.Assert(false); return false; } if (msOutput == null) { Debug.Assert(false); return false; }
/// <summary> // pdContext may be null
if(vEntries == null) { Debug.Assert(false); return false; } 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>
/* KdbxFile f = new KdbxFile(pwDatabase); /* KdbxFile f = new KdbxFile(pwDatabase);
f.m_format = KdbxFormat.PlainXml; f.m_format = KdbxFormat.PlainXml;
@@ -1047,31 +1042,36 @@ namespace KeePassLib.Serialization
xtw.WriteEndElement(); xtw.WriteEndElement();
xtw.WriteEndDocument(); xtw.WriteEndDocument();
xtw.Flush();
xtw.Close();
return true; */
PwDatabase pd = new PwDatabase(); PwDatabase pd = new PwDatabase();
pd.New(new IOConnectionInfo(), new CompositeKey()); pd.New(new IOConnectionInfo(), new CompositeKey());
PwGroup pg = pd.RootGroup; PwGroup pg = pd.RootGroup;
if(pg == null) { Debug.Assert(false); return false; } if (pg == null) { Debug.Assert(false); return false; }
xtw.Flush();
foreach(PwEntry pe in vEntries) foreach (PwEntry pe in vEntries)
{ {
PwUuid pu = pe.CustomIconUuid; 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; int i = -1;
if(pdContext != null) i = pdContext.GetCustomIconIndex(pu); if (pdContext != null) i = pdContext.GetCustomIconIndex(pu);
if(i >= 0) if (i >= 0)
{ {
PwCustomIcon ci = pdContext.CustomIcons[i]; PwCustomIcon ci = pdContext.CustomIcons[i];
pd.CustomIcons.Add(ci); pd.CustomIcons.Add(ci);
} }
else { Debug.Assert(pdContext == null); } else { Debug.Assert(pdContext == null); }
} }
xtw.Close();
PwEntry peCopy = pe.CloneDeep(); PwEntry peCopy = pe.CloneDeep();
pg.AddEntry(peCopy, true); pg.AddEntry(peCopy, true);
} }
return true; */
KdbxFile f = new KdbxFile(pd); KdbxFile f = new KdbxFile(pd);
f.Save(msOutput, null, KdbxFormat.PlainXml, null); f.Save(msOutput, null, KdbxFormat.PlainXml, null);
return true; return true;

View File

@@ -1,6 +1,8 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@@ -20,29 +22,45 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Diagnostics;
using System.Text; using System.Text;
#if !KeePassUAP using System.Diagnostics;
using System.Windows.Forms;
#endif
using KeePassLib.Resources; using KeePassLib.Resources;
using KeePassLib.Serialization; using KeePassLib.Serialization;
namespace KeePassLib.Utility 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 public sealed class MessageServiceEventArgs : EventArgs
{ {
private string m_strTitle = string.Empty; private string m_strTitle = string.Empty;
private string m_strText = string.Empty; private string m_strText = string.Empty;
private MessageBoxButtons m_msgButtons = MessageBoxButtons.OK; //private MessageBoxButtons m_msgButtons = MessageBoxButtons.OK;
private MessageBoxIcon m_msgIcon = MessageBoxIcon.None; //private MessageBoxIcon m_msgIcon = MessageBoxIcon.None;
public string Title { get { return m_strTitle; } } public string Title { get { return m_strTitle; } }
public string Text { get { return m_strText; } } public string Text { get { return m_strText; } }
public MessageBoxButtons Buttons { get { return m_msgButtons; } } //public MessageBoxButtons Buttons { get { return m_msgButtons; } }
public MessageBoxIcon Icon { get { return m_msgIcon; } } //public MessageBoxIcon Icon { get { return m_msgIcon; } }
public MessageServiceEventArgs() { } public MessageServiceEventArgs() { }
@@ -51,8 +69,7 @@ namespace KeePassLib.Utility
{ {
m_strTitle = (strTitle ?? string.Empty); m_strTitle = (strTitle ?? string.Empty);
m_strText = (strText ?? 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_mbiWarning = MessageBoxIcon.Warning;
private const MessageBoxIcon m_mbiFatal = MessageBoxIcon.Error; private const MessageBoxIcon m_mbiFatal = MessageBoxIcon.Error;
private const MessageBoxOptions m_mboRtl = (MessageBoxOptions.RtlReading |
MessageBoxOptions.RightAlign);
#else #else
private const MessageBoxIcon m_mbiInfo = MessageBoxIcon.Asterisk; private const MessageBoxIcon m_mbiInfo = MessageBoxIcon.Asterisk;
private const MessageBoxIcon m_mbiWarning = MessageBoxIcon.Exclamation; private const MessageBoxIcon m_mbiWarning = MessageBoxIcon.Exclamation;
private const MessageBoxIcon m_mbiFatal = MessageBoxIcon.Hand; private const MessageBoxIcon m_mbiFatal = MessageBoxIcon.Hand;
#endif #endif
private const MessageBoxIcon m_mbiQuestion = MessageBoxIcon.Question; //private const MessageBoxIcon m_mbiQuestion = MessageBoxIcon.Question;
public static string NewLine public static string NewLine
{ {
@@ -97,9 +112,7 @@ namespace KeePassLib.Utility
get { return m_uCurrentMessageCount; } get { return m_uCurrentMessageCount; }
} }
#if !KeePassUAP
public static event EventHandler<MessageServiceEventArgs> MessageShowing; public static event EventHandler<MessageServiceEventArgs> MessageShowing;
#endif
private static string ObjectsToMessage(object[] vLines) private static string ObjectsToMessage(object[] vLines)
{ {
@@ -108,52 +121,52 @@ namespace KeePassLib.Utility
private static string ObjectsToMessage(object[] vLines, bool bFullExceptions) private static string ObjectsToMessage(object[] vLines, bool bFullExceptions)
{ {
if(vLines == null) return string.Empty; if (vLines == null) return string.Empty;
string strNewPara = MessageService.NewParagraph; string strNewPara = MessageService.NewParagraph;
StringBuilder sbText = new StringBuilder(); StringBuilder sbText = new StringBuilder();
bool bSeparator = false; bool bSeparator = false;
foreach(object obj in vLines) foreach (object obj in vLines)
{ {
if(obj == null) continue; if (obj == null) continue;
string strAppend = null; string strAppend = null;
Exception exObj = (obj as Exception); Exception exObj = (obj as Exception);
string strObj = (obj as string); string strObj = (obj as string);
#if !KeePassLibSD #if (!KeePassLibSD && !KeePassRT)
StringCollection scObj = (obj as StringCollection); StringCollection scObj = (obj as StringCollection);
#endif #endif
if(exObj != null) if (exObj != null)
{ {
if(bFullExceptions) if (bFullExceptions)
strAppend = StrUtil.FormatException(exObj); 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; strAppend = exObj.Message;
} }
#if !KeePassLibSD #if (!KeePassLibSD && !KeePassRT)
else if(scObj != null) else if (scObj != null)
{ {
StringBuilder sb = new StringBuilder(); 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()); sb.Append(strCollLine.TrimEnd());
} }
strAppend = sb.ToString(); strAppend = sb.ToString();
} }
#endif #endif
else if(strObj != null) else if (strObj != null)
strAppend = strObj; strAppend = strObj;
else else
strAppend = obj.ToString(); strAppend = obj.ToString();
if(!string.IsNullOrEmpty(strAppend)) if (!string.IsNullOrEmpty(strAppend))
{ {
if(bSeparator) sbText.Append(strNewPara); if (bSeparator) sbText.Append(strNewPara);
else bSeparator = true; else bSeparator = true;
sbText.Append(strAppend); sbText.Append(strAppend);
@@ -163,24 +176,30 @@ namespace KeePassLib.Utility
return sbText.ToString(); return sbText.ToString();
} }
#if (!KeePassLibSD && !KeePassUAP) #if (!KeePassLibSD && !KeePassRT)
internal static Form GetTopForm() /*internal static Form GetTopForm()
{ {
FormCollection fc = Application.OpenForms; FormCollection fc = Application.OpenForms;
if((fc == null) || (fc.Count == 0)) return null; if((fc == null) || (fc.Count == 0)) return null;
return fc[fc.Count - 1]; return fc[fc.Count - 1];
} }*/
#endif #endif
#if !KeePassUAP private static DialogResult SafeShowMessageBox(string strText, string strTitle,
internal static DialogResult SafeShowMessageBox(string strText, string strTitle,
MessageBoxButtons mb, MessageBoxIcon mi, MessageBoxDefaultButton mdb) MessageBoxButtons mb, MessageBoxIcon mi, MessageBoxDefaultButton mdb)
{ {
#if KeePassLibSD #if (KeePassLibSD || KeePassRT)
return MessageBox.Show(strText, strTitle, mb, mi, mdb); return MessageBox.Show(strText, strTitle, mb, mi, mdb);
#else #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 try
{ {
Form f = GetTopForm(); Form f = GetTopForm();
@@ -209,11 +228,12 @@ namespace KeePassLib.Utility
if(StrUtil.RightToLeft) if(StrUtil.RightToLeft)
return MessageBox.Show(strText, strTitle, mb, mi, mdb, m_mboRtl); return MessageBox.Show(strText, strTitle, mb, mi, mdb, m_mboRtl);
return MessageBox.Show(strText, strTitle, mb, mi, mdb); return MessageBox.Show(strText, strTitle, mb, mi, mdb);
*/
#endif #endif
} }
#if !KeePassLibSD #if (!KeePassLibSD && !KeePassRT)
internal delegate DialogResult SafeShowMessageBoxInternalDelegate(IWin32Window iParent, /* internal delegate DialogResult SafeShowMessageBoxInternalDelegate(IWin32Window iParent,
string strText, string strTitle, MessageBoxButtons mb, MessageBoxIcon mi, string strText, string strTitle, MessageBoxButtons mb, MessageBoxIcon mi,
MessageBoxDefaultButton mdb); MessageBoxDefaultButton mdb);
@@ -224,7 +244,7 @@ namespace KeePassLib.Utility
if(StrUtil.RightToLeft) if(StrUtil.RightToLeft)
return MessageBox.Show(iParent, strText, strTitle, mb, mi, mdb, m_mboRtl); return MessageBox.Show(iParent, strText, strTitle, mb, mi, mdb, m_mboRtl);
return MessageBox.Show(iParent, strText, strTitle, mb, mi, mdb); return MessageBox.Show(iParent, strText, strTitle, mb, mi, mdb);
} }*/
#endif #endif
public static void ShowInfo(params object[] vLines) public static void ShowInfo(params object[] vLines)
@@ -239,7 +259,7 @@ namespace KeePassLib.Utility
strTitle = (strTitle ?? PwDefs.ShortProductName); strTitle = (strTitle ?? PwDefs.ShortProductName);
string strText = ObjectsToMessage(vLines); string strText = ObjectsToMessage(vLines);
if(MessageService.MessageShowing != null) if (MessageService.MessageShowing != null)
MessageService.MessageShowing(null, new MessageServiceEventArgs( MessageService.MessageShowing(null, new MessageServiceEventArgs(
strTitle, strText, MessageBoxButtons.OK, m_mbiInfo)); strTitle, strText, MessageBoxButtons.OK, m_mbiInfo));
@@ -266,7 +286,7 @@ namespace KeePassLib.Utility
string strTitle = PwDefs.ShortProductName; string strTitle = PwDefs.ShortProductName;
string strText = ObjectsToMessage(vLines, bFullExceptions); string strText = ObjectsToMessage(vLines, bFullExceptions);
if(MessageService.MessageShowing != null) if (MessageService.MessageShowing != null)
MessageService.MessageShowing(null, new MessageServiceEventArgs( MessageService.MessageShowing(null, new MessageServiceEventArgs(
strTitle, strText, MessageBoxButtons.OK, m_mbiWarning)); strTitle, strText, MessageBoxButtons.OK, m_mbiWarning));
@@ -289,18 +309,17 @@ namespace KeePassLib.Utility
try try
{ {
string strDetails = ObjectsToMessage(vLines, true); #if !KeePassLibSD
/* nicht benoetigt - hoffentlich :-)
#if KeePassLibSD Clipboard.Clear();
Clipboard.SetDataObject(strDetails); Clipboard.SetText(ObjectsToMessage(vLines, true));*/
#else #else
Clipboard.Clear(); Clipboard.SetDataObject(ObjectsToMessage(vLines, true));
Clipboard.SetText(strDetails);
#endif #endif
} }
catch(Exception) { Debug.Assert(false); } catch (Exception) { Debug.Assert(false); }
if(MessageService.MessageShowing != null) if (MessageService.MessageShowing != null)
MessageService.MessageShowing(null, new MessageServiceEventArgs( MessageService.MessageShowing(null, new MessageServiceEventArgs(
strTitle, strText, MessageBoxButtons.OK, m_mbiFatal)); strTitle, strText, MessageBoxButtons.OK, m_mbiFatal));
@@ -318,12 +337,12 @@ namespace KeePassLib.Utility
string strTextEx = (strText ?? string.Empty); string strTextEx = (strText ?? string.Empty);
string strTitleEx = (strTitle ?? PwDefs.ShortProductName); string strTitleEx = (strTitle ?? PwDefs.ShortProductName);
if(MessageService.MessageShowing != null) if (MessageService.MessageShowing != null)
MessageService.MessageShowing(null, new MessageServiceEventArgs( MessageService.MessageShowing(null, new MessageServiceEventArgs(
strTitleEx, strTextEx, mbb, m_mbiQuestion)); strTitleEx, strTextEx, mbb, MessageBoxIcon.Question));
DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx, mbb, DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx, mbb,
m_mbiQuestion, MessageBoxDefaultButton.Button1); MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
--m_uCurrentMessageCount; --m_uCurrentMessageCount;
return dr; return dr;
@@ -337,12 +356,12 @@ namespace KeePassLib.Utility
string strTextEx = (strText ?? string.Empty); string strTextEx = (strText ?? string.Empty);
string strTitleEx = (strTitle ?? PwDefs.ShortProductName); string strTitleEx = (strTitle ?? PwDefs.ShortProductName);
if(MessageService.MessageShowing != null) if (MessageService.MessageShowing != null)
MessageService.MessageShowing(null, new MessageServiceEventArgs( MessageService.MessageShowing(null, new MessageServiceEventArgs(
strTitleEx, strTextEx, MessageBoxButtons.YesNo, mbi)); strTitleEx, strTextEx, MessageBoxButtons.YesNo, MessageBoxIcon.Question));
DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx, DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx,
MessageBoxButtons.YesNo, mbi, bDefaultToYes ? MessageBoxButtons.YesNo, MessageBoxIcon.Question, bDefaultToYes ?
MessageBoxDefaultButton.Button1 : MessageBoxDefaultButton.Button2); MessageBoxDefaultButton.Button1 : MessageBoxDefaultButton.Button2);
--m_uCurrentMessageCount; --m_uCurrentMessageCount;
@@ -351,17 +370,17 @@ namespace KeePassLib.Utility
public static bool AskYesNo(string strText, string strTitle, bool bDefaultToYes) 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) 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) 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) public static void ShowLoadWarning(string strFilePath, Exception ex)
@@ -372,12 +391,26 @@ namespace KeePassLib.Utility
public static void ShowLoadWarning(string strFilePath, Exception ex, public static void ShowLoadWarning(string strFilePath, Exception ex,
bool bFullException) 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) public static void ShowLoadWarning(IOConnectionInfo ioConnection, Exception ex)
{ {
if(ioConnection != null) if (ioConnection != null)
ShowLoadWarning(ioConnection.GetDisplayName(), ex, false); ShowLoadWarning(ioConnection.GetDisplayName(), ex, false);
else ShowWarning(ex); else ShowWarning(ex);
} }
@@ -386,62 +419,34 @@ namespace KeePassLib.Utility
bool bCorruptionWarning) bool bCorruptionWarning)
{ {
FileLockException fl = (ex as FileLockException); FileLockException fl = (ex as FileLockException);
if(fl != null) if (fl != null)
{ {
ShowWarning(fl.Message); ShowWarning(fl.Message);
return; 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); ShowWarning(str);
} }
public static void ShowSaveWarning(IOConnectionInfo ioConnection, Exception ex, public static void ShowSaveWarning(IOConnectionInfo ioConnection, Exception ex,
bool bCorruptionWarning) bool bCorruptionWarning)
{ {
if(ioConnection != null) if (ioConnection != null)
ShowSaveWarning(ioConnection.GetDisplayName(), ex, bCorruptionWarning); ShowSaveWarning(ioConnection.GetDisplayName(), ex, bCorruptionWarning);
else ShowWarning(ex); 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() public static void ExternalIncrementMessageCount()
{ {

View File

@@ -166,16 +166,7 @@ namespace KeePassLib.Utility
// m_fOwnWindow = fOwnWindow; // 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() 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> /// <summary>
/// Ensure that the file ~/.recently-used is valid (in order to /// Ensure that the file ~/.recently-used is valid (in order to
/// prevent Mono's FileDialog from crashing). /// prevent Mono's FileDialog from crashing).