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.Native;
30 using KeePass.Resources;
31 using KeePass.UI;
32 
33 using KeePassLib;
34 using KeePassLib.Security;
35 using KeePassLib.Utility;
36 
37 namespace KeePass.Forms
38 {
39 	public partial class FieldPickerForm : Form
40 	{
41 		private string m_strTitle = null;
42 		private string m_strText = null;
43 		private List<FpField> m_lFields = null;
44 
45 		private FpField m_fpResult = null;
46 		public FpField SelectedField { get { return m_fpResult; } }
47 
ShowAndRestore(string strTitle, string strText, List<FpField> lFields)48 		internal static FpField ShowAndRestore(string strTitle, string strText,
49 			List<FpField> lFields)
50 		{
51 			IntPtr h = IntPtr.Zero;
52 			try { h = NativeMethods.GetForegroundWindowHandle(); }
53 			catch(Exception) { Debug.Assert(false); }
54 
55 			FieldPickerForm dlg = new FieldPickerForm();
56 			dlg.InitEx(strTitle, strText, lFields);
57 
58 			FpField fpResult = null;
59 			if(UIUtil.ShowDialogAndDestroy(dlg) == DialogResult.OK)
60 				fpResult = dlg.SelectedField;
61 
62 			try
63 			{
64 				if(h != IntPtr.Zero)
65 					NativeMethods.EnsureForegroundWindow(h);
66 			}
67 			catch(Exception) { Debug.Assert(false); }
68 
69 			return fpResult;
70 		}
71 
FieldPickerForm()72 		public FieldPickerForm()
73 		{
74 			InitializeComponent();
75 			GlobalWindowManager.InitializeForm(this);
76 		}
77 
InitEx(string strTitle, string strText, List<FpField> lFields)78 		public void InitEx(string strTitle, string strText, List<FpField> lFields)
79 		{
80 			m_strTitle = strTitle;
81 			m_strText = strText;
82 			m_lFields = lFields;
83 		}
84 
OnFormLoad(object sender, EventArgs e)85 		private void OnFormLoad(object sender, EventArgs e)
86 		{
87 			// Can be invoked during auto-type; don't use CenterParent
88 			Debug.Assert(this.StartPosition == FormStartPosition.CenterScreen);
89 
90 			GlobalWindowManager.AddWindow(this);
91 
92 			string strTitle = (m_strTitle ?? string.Empty);
93 			string strTitleEx = strTitle;
94 			if(strTitle.Length > 0) strTitleEx += " - ";
95 			strTitleEx += PwDefs.ShortProductName;
96 
97 			this.Icon = AppIcons.Default;
98 			this.Text = strTitleEx;
99 
100 			BannerFactory.CreateBannerEx(this, m_bannerImage,
101 				Properties.Resources.B48x48_Binary, strTitle,
102 				(m_strText ?? string.Empty));
103 
104 			UIUtil.SetExplorerTheme(m_lvFields, true);
105 
106 			int w = (m_lvFields.ClientSize.Width - UIUtil.GetVScrollBarWidth()) / 2;
107 			m_lvFields.Columns.Add(KPRes.Name, w);
108 			m_lvFields.Columns.Add(KPRes.Value, w);
109 
110 			if(m_lFields != null)
111 			{
112 				ListViewGroup lvg = null;
113 				string strGroup = string.Empty;
114 
115 				foreach(FpField fpf in m_lFields)
116 				{
117 					if(fpf == null) { Debug.Assert(false); continue; }
118 
119 					ListViewItem lvi = new ListViewItem(fpf.Name);
120 					lvi.SubItems.Add(fpf.Value.IsProtected ? PwDefs.HiddenPassword :
121 						StrUtil.MultiToSingleLine(fpf.Value.ReadString()));
122 					lvi.Tag = fpf;
123 
124 					m_lvFields.Items.Add(lvi);
125 
126 					if(fpf.Group.Length > 0)
127 					{
128 						if(fpf.Group != strGroup)
129 						{
130 							strGroup = fpf.Group;
131 							lvg = new ListViewGroup(strGroup, HorizontalAlignment.Left);
132 
133 							m_lvFields.Groups.Add(lvg);
134 						}
135 
136 						lvg.Items.Add(lvi);
137 					}
138 				}
139 			}
140 
141 			this.BringToFront();
142 			this.Activate();
143 			if(m_lvFields.Items.Count > 0)
144 				UIUtil.SetFocusedItem(m_lvFields, m_lvFields.Items[0], true);
145 			UIUtil.SetFocus(m_lvFields, this, true);
146 		}
147 
OnFormClosed(object sender, FormClosedEventArgs e)148 		private void OnFormClosed(object sender, FormClosedEventArgs e)
149 		{
150 			GlobalWindowManager.RemoveWindow(this);
151 		}
152 
ProcessItemSelection()153 		private void ProcessItemSelection()
154 		{
155 			if(this.DialogResult == DialogResult.OK) return; // Already closing
156 
157 			ListView.SelectedListViewItemCollection lvsic =
158 				m_lvFields.SelectedItems;
159 			if((lvsic == null) || (lvsic.Count != 1)) { Debug.Assert(false); return; }
160 
161 			ListViewItem lvi = lvsic[0];
162 			if(lvi == null) { Debug.Assert(false); return; }
163 
164 			FpField fpf = (lvi.Tag as FpField);
165 			if(fpf == null) { Debug.Assert(false); return; }
166 
167 			m_fpResult = fpf;
168 			this.DialogResult = DialogResult.OK;
169 		}
170 
OnFieldItemActivate(object sender, EventArgs e)171 		private void OnFieldItemActivate(object sender, EventArgs e)
172 		{
173 			ProcessItemSelection();
174 		}
175 
176 		// The item activation handler has a slight delay when clicking an
177 		// item, thus as a performance optimization we additionally handle
178 		// item clicks
OnFieldClick(object sender, EventArgs e)179 		private void OnFieldClick(object sender, EventArgs e)
180 		{
181 			ProcessItemSelection();
182 		}
183 	}
184 
185 	public sealed class FpField
186 	{
187 		private readonly string m_strName;
188 		public string Name { get { return m_strName; } }
189 
190 		private readonly ProtectedString m_psValue;
191 		public ProtectedString Value { get { return m_psValue; } }
192 
193 		private readonly string m_strGroup;
194 		public string Group { get { return m_strGroup; } }
195 
FpField(string strName, ProtectedString psValue, string strGroup)196 		public FpField(string strName, ProtectedString psValue, string strGroup)
197 		{
198 			m_strName = (strName ?? string.Empty);
199 			m_psValue = (psValue ?? ProtectedString.Empty);
200 			m_strGroup = (strGroup ?? string.Empty);
201 		}
202 	}
203 }
204