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.Globalization; 26 using System.IO; 27 using System.Text; 28 using System.Threading; 29 using System.Windows.Forms; 30 using System.Xml; 31 32 using KeePass.App; 33 using KeePass.Resources; 34 using KeePass.UI; 35 using KeePass.Util; 36 37 using KeePassLib; 38 using KeePassLib.Delegates; 39 using KeePassLib.Native; 40 using KeePassLib.Serialization; 41 using KeePassLib.Utility; 42 43 namespace KeePass.Forms 44 { 45 public partial class IOConnectionForm : Form 46 { 47 private bool m_bSave = false; 48 private IOConnectionInfo m_ioc = new IOConnectionInfo(); 49 private bool m_bCanRememberCred = true; 50 private bool m_bTestConnection = false; 51 52 private List<KeyValuePair<IocPropertyInfo, Control>> m_lProps = 53 new List<KeyValuePair<IocPropertyInfo, Control>>(); 54 55 public IOConnectionInfo IOConnectionInfo 56 { 57 get { return m_ioc; } 58 } 59 InitEx(bool bSave, IOConnectionInfo ioc, bool bCanRememberCred, bool bTestConnection)60 public void InitEx(bool bSave, IOConnectionInfo ioc, bool bCanRememberCred, 61 bool bTestConnection) 62 { 63 m_bSave = bSave; 64 if(ioc != null) m_ioc = ioc.CloneDeep(); 65 m_bCanRememberCred = bCanRememberCred; 66 m_bTestConnection = bTestConnection; 67 } 68 IOConnectionForm()69 public IOConnectionForm() 70 { 71 InitializeComponent(); 72 73 SecureTextBoxEx.InitEx(ref m_tbPassword); 74 GlobalWindowManager.InitializeForm(this); 75 } 76 OnFormLoad(object sender, EventArgs e)77 private void OnFormLoad(object sender, EventArgs e) 78 { 79 // Must work without a parent window 80 Debug.Assert(this.StartPosition == FormStartPosition.CenterScreen); 81 82 // The password text box should not be focused by default 83 // in order to avoid a Caps Lock warning tooltip bug; 84 // https://sourceforge.net/p/keepass/bugs/1807/ 85 Debug.Assert((m_tbPassword.TabIndex >= 2) && !m_tbPassword.Focused); 86 87 InitAdvancedTab(); // After translation, before resize 88 89 GlobalWindowManager.AddWindow(this); 90 91 string strTitle = (m_bSave ? KPRes.UrlSaveTitle : KPRes.UrlOpenTitle); 92 string strDesc = (m_bSave ? KPRes.UrlSaveDesc : KPRes.UrlOpenDesc); 93 94 BannerFactory.CreateBannerEx(this, m_bannerImage, 95 KeePass.Properties.Resources.B48x48_WWW, strTitle, strDesc); 96 this.Icon = AppIcons.Default; 97 this.Text = strTitle; 98 99 FontUtil.AssignDefaultBold(m_lblUrl); 100 FontUtil.AssignDefaultBold(m_lblUserName); 101 FontUtil.AssignDefaultBold(m_lblPassword); 102 FontUtil.AssignDefaultBold(m_lblRemember); 103 104 m_tbUrl.Text = (m_ioc.IsLocalFile() ? string.Empty : m_ioc.Path); 105 m_tbUserName.Text = m_ioc.UserName; 106 m_tbPassword.Text = m_ioc.Password; 107 108 m_cmbCredSaveMode.Items.Add(KPRes.CredSaveNone); 109 m_cmbCredSaveMode.Items.Add(KPRes.CredSaveUserOnly); 110 m_cmbCredSaveMode.Items.Add(KPRes.CredSaveAll); 111 112 if(m_ioc.CredSaveMode == IOCredSaveMode.UserNameOnly) 113 m_cmbCredSaveMode.SelectedIndex = 1; 114 else if(m_ioc.CredSaveMode == IOCredSaveMode.SaveCred) 115 m_cmbCredSaveMode.SelectedIndex = 2; 116 else 117 m_cmbCredSaveMode.SelectedIndex = 0; 118 119 if(!m_bCanRememberCred) 120 { 121 m_cmbCredSaveMode.SelectedIndex = 0; 122 m_cmbCredSaveMode.Enabled = false; 123 } 124 125 ThreadPool.QueueUserWorkItem(delegate(object state) 126 { 127 try { InitAutoCompletions(); } 128 catch(Exception) { Debug.Assert(false); } 129 }); 130 } 131 OnFormShown(object sender, EventArgs e)132 private void OnFormShown(object sender, EventArgs e) 133 { 134 if((m_tbUrl.TextLength > 0) && (m_tbUserName.TextLength > 0)) 135 UIUtil.ResetFocus(m_tbPassword, this); 136 else if(m_tbUrl.TextLength > 0) 137 UIUtil.SetFocus(m_tbUserName, this); 138 else UIUtil.SetFocus(m_tbUrl, this); 139 } 140 OnBtnOK(object sender, EventArgs e)141 private void OnBtnOK(object sender, EventArgs e) 142 { 143 string strUrl = m_tbUrl.Text; 144 if(strUrl.IndexOf("://") < 0) 145 { 146 // m_ttInvalidUrl.Show(KPRes.InvalidUrl, m_tbUrl); 147 MessageService.ShowWarning(strUrl, KPRes.InvalidUrl); 148 this.DialogResult = DialogResult.None; 149 return; 150 } 151 152 m_ioc.Path = strUrl; 153 m_ioc.UserName = m_tbUserName.Text; 154 m_ioc.Password = m_tbPassword.TextEx.ReadString(); 155 156 if(m_cmbCredSaveMode.SelectedIndex == 1) 157 m_ioc.CredSaveMode = IOCredSaveMode.UserNameOnly; 158 else if(m_cmbCredSaveMode.SelectedIndex == 2) 159 m_ioc.CredSaveMode = IOCredSaveMode.SaveCred; 160 else 161 m_ioc.CredSaveMode = IOCredSaveMode.NoSave; 162 163 IocProperties p = m_ioc.Properties; 164 foreach(KeyValuePair<IocPropertyInfo, Control> kvp in m_lProps) 165 { 166 IocPropertyInfo pi = kvp.Key; 167 string strName = pi.Name; 168 Type t = pi.Type; 169 Control c = kvp.Value; 170 171 try 172 { 173 if(t == typeof(string)) 174 { 175 TextBox tb = (c as TextBox); 176 if(tb != null) p.Set(strName, tb.Text.Trim()); 177 else { Debug.Assert(false); } 178 } 179 else if(t == typeof(bool)) 180 { 181 ComboBox cmb = (c as ComboBox); 182 if(cmb != null) 183 { 184 int iSel = cmb.SelectedIndex; 185 if(iSel == 0) p.SetBool(strName, null); 186 else p.SetBool(strName, (iSel == 1)); 187 } 188 else { Debug.Assert(false); } 189 } 190 else if(t == typeof(long)) 191 { 192 TextBox tb = (c as TextBox); 193 if(tb != null) 194 { 195 string str = tb.Text.Trim(); 196 if(str.Length == 0) p.SetLong(strName, null); 197 else 198 { 199 // Validate and store number 200 long l = long.Parse(str, NumberFormatInfo.InvariantInfo); 201 p.SetLong(strName, l); 202 } 203 } 204 else { Debug.Assert(false); } 205 } 206 else { Debug.Assert(false); } 207 } 208 catch(Exception ex) 209 { 210 string strMsg = KPRes.Field + @" '" + pi.DisplayName + 211 @"':" + MessageService.NewLine + ex.Message; 212 // if(!VistaTaskDialog.ShowMessageBox(strMsg, KPRes.ValidationFailed, 213 // PwDefs.ShortProductName, VtdIcon.Warning, this)) 214 MessageService.ShowWarning(strMsg); 215 216 this.DialogResult = DialogResult.None; 217 return; 218 } 219 } 220 221 if(m_bTestConnection && !m_bSave) 222 { 223 if(!TestConnectionEx()) 224 this.DialogResult = DialogResult.None; 225 } 226 } 227 TestConnectionEx()228 private bool TestConnectionEx() 229 { 230 bool bResult = true; 231 bool bOK = m_btnOK.Enabled, bCancel = m_btnCancel.Enabled; 232 bool bCombo = m_cmbCredSaveMode.Enabled; 233 234 m_btnOK.Enabled = m_btnCancel.Enabled = m_tbUrl.Enabled = 235 m_tbUserName.Enabled = m_tbPassword.Enabled = 236 m_btnHelp.Enabled = m_cmbCredSaveMode.Enabled = false; 237 238 Application.DoEvents(); 239 240 try 241 { 242 if(!IOConnection.FileExists(m_ioc, true)) 243 throw new FileNotFoundException(); 244 } 245 catch(Exception exTest) 246 { 247 if(Program.CommandLineArgs[AppDefs.CommandLineOptions.Debug] != null) 248 MessageService.ShowWarningExcp(m_ioc.GetDisplayName(), exTest); 249 else 250 { 251 string strError = exTest.Message; 252 if((exTest.InnerException != null) && 253 !string.IsNullOrEmpty(exTest.InnerException.Message)) 254 strError += MessageService.NewParagraph + 255 exTest.InnerException.Message; 256 257 MessageService.ShowWarning(m_ioc.GetDisplayName(), strError); 258 } 259 260 bResult = false; 261 } 262 263 m_btnOK.Enabled = bOK; 264 m_btnCancel.Enabled = bCancel; 265 m_cmbCredSaveMode.Enabled = bCombo; 266 m_btnHelp.Enabled = m_tbUserName.Enabled = m_tbUrl.Enabled = 267 m_tbPassword.Enabled = true; 268 return bResult; 269 } 270 OnBtnCancel(object sender, EventArgs e)271 private void OnBtnCancel(object sender, EventArgs e) 272 { 273 } 274 OnBtnHelp(object sender, EventArgs e)275 private void OnBtnHelp(object sender, EventArgs e) 276 { 277 AppHelp.ShowHelp(AppDefs.HelpTopics.IOConnections, null); 278 } 279 OnFormClosed(object sender, FormClosedEventArgs e)280 private void OnFormClosed(object sender, FormClosedEventArgs e) 281 { 282 GlobalWindowManager.RemoveWindow(this); 283 } 284 GetPropertyInfos()285 private static Dictionary<string, List<IocPropertyInfo>> GetPropertyInfos() 286 { 287 Dictionary<string, List<IocPropertyInfo>> d = 288 new Dictionary<string, List<IocPropertyInfo>>(StrUtil.CaseIgnoreComparer); 289 290 foreach(IocPropertyInfo pi in IocPropertyInfoPool.PropertyInfos) 291 { 292 if(pi == null) { Debug.Assert(false); continue; } 293 294 List<string> lPrt = new List<string>(pi.Protocols); 295 lPrt.Sort(StrUtil.CaseIgnoreComparer); 296 StringBuilder sbPrt = new StringBuilder(); 297 foreach(string str in lPrt) 298 { 299 if(sbPrt.Length > 0) sbPrt.Append(" / "); 300 sbPrt.Append(str); 301 } 302 string strPrt = sbPrt.ToString(); 303 304 List<IocPropertyInfo> l; 305 if(d.TryGetValue(strPrt, out l)) l.Add(pi); 306 else 307 { 308 l = new List<IocPropertyInfo>(); 309 l.Add(pi); 310 d[strPrt] = l; 311 } 312 } 313 314 return d; 315 } 316 InitAdvancedTab()317 private void InitAdvancedTab() 318 { 319 IocProperties p = m_ioc.Properties; 320 Dictionary<string, List<IocPropertyInfo>> dProps = GetPropertyInfos(); 321 322 const int d = 7; 323 int hLabel = m_lblUrl.Height; 324 int hTextBox = m_tbUrl.Height; 325 int hComboBox = m_cmbCredSaveMode.Height; 326 Font f = m_lblUrl.Font; 327 328 Debug.Assert(m_pnlAdv.AutoScroll); 329 m_pnlAdv.AutoScrollMargin = new Size(1, d); 330 331 int wPanel = m_pnlAdv.ClientSize.Width - UIUtil.GetVScrollBarWidth() - 1; 332 int wGroup = wPanel - (2 * d); 333 int wCell = (wPanel - (3 * d)) / 2; 334 int xText = d - 1; 335 int xInput = d + wCell + d - 1; 336 int xGroup = xText; 337 338 if(this.RightToLeft == RightToLeft.Yes) 339 { 340 int iTemp = xText; 341 xText = xInput; 342 xInput = iTemp; 343 } 344 345 int y = 1; 346 int iID = 0; 347 348 m_pnlAdv.SuspendLayout(); 349 350 foreach(KeyValuePair<string, List<IocPropertyInfo>> kvp in dProps) 351 { 352 string strGroup = kvp.Key; 353 y += d; 354 355 Label lblGroup = new Label(); 356 lblGroup.Name = "cGroup" + iID.ToString(NumberFormatInfo.InvariantInfo); 357 ++iID; 358 lblGroup.AutoEllipsis = true; 359 lblGroup.AutoSize = false; 360 lblGroup.Dock = DockStyle.None; 361 lblGroup.Location = new Point(xGroup, y); 362 lblGroup.Size = new Size(wGroup, hLabel); 363 lblGroup.Text = strGroup; 364 lblGroup.TextAlign = ContentAlignment.MiddleLeft; 365 // lblGroup.BackColor = Color.Red; 366 FontUtil.AssignDefaultBold(lblGroup); 367 368 m_pnlAdv.Controls.Add(lblGroup); 369 y += hLabel; 370 371 foreach(IocPropertyInfo pi in kvp.Value) 372 { 373 string strName = pi.Name; 374 string strText = pi.DisplayName + ":"; 375 Type t = pi.Type; 376 y += d; 377 378 int hText = hLabel; 379 int wRem = TextRenderer.MeasureText(strText, f).Width; 380 while(wRem >= wCell) 381 { 382 hText += (hLabel + 1); 383 wRem -= wCell; 384 } 385 386 Label lblText = new Label(); 387 lblText.Name = "cText" + iID.ToString(NumberFormatInfo.InvariantInfo); 388 ++iID; 389 lblText.AutoEllipsis = true; 390 lblText.AutoSize = false; 391 lblText.Dock = DockStyle.None; 392 lblText.Size = new Size(wCell, hText); 393 lblText.Text = strText; 394 lblText.TextAlign = ContentAlignment.MiddleLeft; 395 // lblText.BackColor = Color.Green; 396 397 Control cInput = null; 398 if((t == typeof(string)) || (t == typeof(long))) 399 { 400 TextBox tb = new TextBox(); 401 tb.Size = new Size(wCell, hTextBox); 402 403 tb.Text = (p.Get(strName) ?? string.Empty); 404 405 cInput = tb; 406 } 407 else if(t == typeof(bool)) 408 { 409 ComboBox cmb = new ComboBox(); 410 cmb.DropDownStyle = ComboBoxStyle.DropDownList; 411 cmb.Size = new Size(wCell, hComboBox); 412 413 cmb.Items.Add(KPRes.Auto); 414 cmb.Items.Add(KPRes.Yes); 415 cmb.Items.Add(KPRes.No); 416 417 bool? ob = p.GetBool(strName); 418 if(ob.HasValue) cmb.SelectedIndex = (ob.Value ? 1 : 2); 419 else cmb.SelectedIndex = 0; 420 421 cInput = cmb; 422 } 423 else { Debug.Assert(false); continue; } 424 425 cInput.Dock = DockStyle.None; 426 cInput.Name = "cInput" + iID.ToString(NumberFormatInfo.InvariantInfo); 427 ++iID; 428 429 int hDiff = lblText.Height - cInput.Height; 430 if(hDiff >= 0) 431 { 432 lblText.Location = new Point(xText, y); 433 cInput.Location = new Point(xInput, y + (hDiff / 2)); 434 435 y += lblText.Height; 436 } 437 else 438 { 439 lblText.Location = new Point(xText, y - (hDiff / 2)); 440 cInput.Location = new Point(xInput, y); 441 442 y += cInput.Height; 443 } 444 445 m_pnlAdv.Controls.Add(lblText); 446 m_pnlAdv.Controls.Add(cInput); 447 448 m_lProps.Add(new KeyValuePair<IocPropertyInfo, Control>( 449 pi, cInput)); 450 } 451 } 452 453 m_pnlAdv.ResumeLayout(true); 454 } 455 InitAutoCompletion(TextBox tb, Dictionary<string, bool> d)456 private static void InitAutoCompletion(TextBox tb, Dictionary<string, bool> d) 457 { 458 if(d.Count == 0) return; 459 460 string[] v = new string[d.Count]; 461 d.Keys.CopyTo(v, 0); 462 Array.Sort<string>(v, StrUtil.CaseIgnoreComparer); 463 464 // Do not append, because long suggestions hide the start 465 UIUtil.EnableAutoCompletion(tb, false, v); // Invokes 466 } 467 InitAutoCompletions()468 private void InitAutoCompletions() 469 { 470 Dictionary<string, bool> dUrls = new Dictionary<string, bool>(); 471 Dictionary<string, bool> dUsers = new Dictionary<string, bool>(); 472 473 MainForm mf = Program.MainForm; 474 MruList l = ((mf != null) ? mf.FileMruList : null); 475 if(l == null) { Debug.Assert(false); return; } 476 477 for(uint u = 0; u < l.ItemCount; ++u) 478 { 479 IOConnectionInfo ioc = (l.GetItem(u).Value as IOConnectionInfo); 480 if(ioc == null) { Debug.Assert(false); continue; } 481 if(ioc.IsLocalFile()) continue; 482 483 string str = ioc.Path; 484 if(!string.IsNullOrEmpty(str)) dUrls[str] = true; 485 486 str = ioc.UserName; 487 if(!string.IsNullOrEmpty(str)) dUsers[str] = true; 488 } 489 490 InitAutoCompletion(m_tbUrl, dUrls); 491 InitAutoCompletion(m_tbUserName, dUsers); 492 } 493 } 494 } 495