1 /*
2   KeePass Password Safe - The Open-Source Password Manager
3   Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
4 
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19 
20 using System;
21 using System.Collections.Generic;
22 using System.ComponentModel;
23 using System.Diagnostics;
24 using System.Drawing;
25 using System.Text;
26 using System.Windows.Forms;
27 
28 using KeePass.App;
29 using KeePass.Resources;
30 using KeePass.UI;
31 
32 using KeePassLib;
33 using KeePassLib.Collections;
34 using KeePassLib.Delegates;
35 
36 namespace KeePass.Forms
37 {
38 	public partial class DatabaseOperationsForm : Form, IGwmWindow
39 	{
40 		private PwDatabase m_pwDatabase = null;
41 		private bool m_bModified = false;
42 
43 		private StringDictionaryEx m_sdCustomData = null;
44 
45 		public bool CanCloseWithoutDataLoss { get { return true; } }
46 		public bool HasModifiedDatabase { get { return m_bModified; } }
47 
InitEx(PwDatabase pwDatabase)48 		public void InitEx(PwDatabase pwDatabase)
49 		{
50 			m_pwDatabase = pwDatabase;
51 		}
52 
DatabaseOperationsForm()53 		public DatabaseOperationsForm()
54 		{
55 			InitializeComponent();
56 			GlobalWindowManager.InitializeForm(this);
57 		}
58 
OnFormLoad(object sender, EventArgs e)59 		private void OnFormLoad(object sender, EventArgs e)
60 		{
61 			Debug.Assert(m_pwDatabase != null); if(m_pwDatabase == null) throw new InvalidOperationException();
62 
63 			GlobalWindowManager.AddWindow(this, this);
64 
65 			BannerFactory.CreateBannerEx(this, m_bannerImage,
66 				Properties.Resources.B48x48_Package_Settings, KPRes.DatabaseMaintenance,
67 				KPRes.DatabaseMaintenanceDesc);
68 			this.Icon = AppIcons.Default;
69 			this.Text = KPRes.DatabaseMaintenance;
70 
71 			m_numHistoryDays.Value = m_pwDatabase.MaintenanceHistoryDays;
72 
73 			m_sdCustomData = m_pwDatabase.CustomData.CloneDeep();
74 			UIUtil.StrDictListInit(m_lvCustomData);
75 			UIUtil.StrDictListUpdate(m_lvCustomData, m_sdCustomData, false);
76 
77 			m_pbStatus.Visible = false;
78 			EnableControlsEx();
79 		}
80 
OnBtnClose(object sender, EventArgs e)81 		private void OnBtnClose(object sender, EventArgs e)
82 		{
83 			m_pwDatabase.MaintenanceHistoryDays = (uint)m_numHistoryDays.Value;
84 
85 			if(m_sdCustomData.Count != m_pwDatabase.CustomData.Count)
86 			{
87 				m_pwDatabase.CustomData = m_sdCustomData;
88 				m_bModified = true;
89 			}
90 			else { Debug.Assert(m_sdCustomData.Equals(m_pwDatabase.CustomData)); }
91 		}
92 
EnableControlsEx()93 		private void EnableControlsEx()
94 		{
95 			m_btnCDDel.Enabled = (m_lvCustomData.SelectedIndices.Count > 0);
96 		}
97 
EnableStatusMsgEx(bool bEnable)98 		private void EnableStatusMsgEx(bool bEnable)
99 		{
100 			if(bEnable)
101 			{
102 				m_btnClose.Enabled = m_btnHistoryEntriesDelete.Enabled =
103 					m_btnRemoveDelObjInfo.Enabled = false;
104 				if(!m_pbStatus.Visible) m_pbStatus.Visible = true;
105 
106 				m_pbStatus.Value = 0;
107 			}
108 			else
109 			{
110 				m_btnClose.Enabled = m_btnHistoryEntriesDelete.Enabled =
111 					m_btnRemoveDelObjInfo.Enabled = true;
112 
113 				m_pbStatus.Value = m_pbStatus.Maximum;
114 			}
115 		}
116 
OnBtnDelete(object sender, EventArgs e)117 		private void OnBtnDelete(object sender, EventArgs e)
118 		{
119 			EnableStatusMsgEx(true);
120 
121 			DateTime dtNow = DateTime.UtcNow;
122 			TimeSpan tsSpan = new TimeSpan((int)m_numHistoryDays.Value, 0, 0, 0);
123 
124 			uint uNumGroups, uNumEntries;
125 			m_pwDatabase.RootGroup.GetCounts(true, out uNumGroups, out uNumEntries);
126 
127 			uint uCurEntryNumber = 1;
128 			EntryHandler eh = delegate(PwEntry pe)
129 			{
130 				for(uint u = 0; u < pe.History.UCount; ++u)
131 				{
132 					PwEntry peHist = pe.History.GetAt(u);
133 
134 					if((dtNow - peHist.LastModificationTime) >= tsSpan)
135 					{
136 						pe.History.Remove(peHist);
137 						--u;
138 
139 						m_bModified = true;
140 					}
141 				}
142 
143 				m_pbStatus.Value = (int)((uCurEntryNumber * 100) / uNumEntries);
144 				++uCurEntryNumber;
145 				return true;
146 			};
147 
148 			m_pwDatabase.RootGroup.TraverseTree(TraversalMethod.PreOrder, null, eh);
149 
150 			EnableStatusMsgEx(false); // Database is set modified by parent
151 		}
152 
OnFormClosed(object sender, FormClosedEventArgs e)153 		private void OnFormClosed(object sender, FormClosedEventArgs e)
154 		{
155 			GlobalWindowManager.RemoveWindow(this);
156 		}
157 
OnBtnRemoveDelObjInfo(object sender, EventArgs e)158 		private void OnBtnRemoveDelObjInfo(object sender, EventArgs e)
159 		{
160 			EnableStatusMsgEx(true);
161 
162 			if(m_pwDatabase.DeletedObjects.UCount > 0)
163 			{
164 				m_pwDatabase.DeletedObjects.Clear();
165 				m_bModified = true;
166 			}
167 
168 			EnableStatusMsgEx(false); // Database is set modified by parent
169 		}
170 
OnCustomDataSelectedIndexChanged(object sender, EventArgs e)171 		private void OnCustomDataSelectedIndexChanged(object sender, EventArgs e)
172 		{
173 			EnableControlsEx();
174 		}
175 
OnBtnCDDel(object sender, EventArgs e)176 		private void OnBtnCDDel(object sender, EventArgs e)
177 		{
178 			UIUtil.StrDictListDeleteSel(m_lvCustomData, m_sdCustomData, false);
179 			UIUtil.SetFocus(m_lvCustomData, this);
180 			EnableControlsEx();
181 		}
182 	}
183 }
184