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.Diagnostics; 23 using System.IO; 24 using System.Text; 25 using System.Threading; 26 using System.Windows.Forms; 27 using System.Xml; 28 29 using KeePass.App; 30 using KeePass.DataExchange.Formats; 31 using KeePass.Ecas; 32 using KeePass.Forms; 33 using KeePass.Native; 34 using KeePass.Resources; 35 using KeePass.UI; 36 using KeePass.Util; 37 38 using KeePassLib; 39 using KeePassLib.Interfaces; 40 using KeePassLib.Keys; 41 using KeePassLib.Resources; 42 using KeePassLib.Security; 43 using KeePassLib.Serialization; 44 using KeePassLib.Utility; 45 46 namespace KeePass.DataExchange 47 { 48 public static class ImportUtil 49 { Import(PwDatabase pwStorage, out bool bAppendedToRootOnly, Form fParent)50 public static bool? Import(PwDatabase pwStorage, out bool bAppendedToRootOnly, 51 Form fParent) 52 { 53 bAppendedToRootOnly = false; 54 55 if(pwStorage == null) throw new ArgumentNullException("pwStorage"); 56 if(!pwStorage.IsOpen) return null; 57 if(!AppPolicy.Try(AppPolicyId.Import)) return null; 58 59 ExchangeDataForm dlgFmt = new ExchangeDataForm(); 60 dlgFmt.InitEx(false, pwStorage, pwStorage.RootGroup); 61 62 if(UIUtil.ShowDialogNotValue(dlgFmt, DialogResult.OK)) return null; 63 64 Debug.Assert(dlgFmt.ResultFormat != null); 65 if(dlgFmt.ResultFormat == null) 66 { 67 MessageService.ShowWarning(KPRes.ImportFailed); 68 UIUtil.DestroyForm(dlgFmt); 69 return false; 70 } 71 72 bAppendedToRootOnly = dlgFmt.ResultFormat.ImportAppendsToRootGroupOnly; 73 FileFormatProvider ffp = dlgFmt.ResultFormat; 74 75 List<IOConnectionInfo> lConnections = new List<IOConnectionInfo>(); 76 foreach(string strSelFile in dlgFmt.ResultFiles) 77 lConnections.Add(IOConnectionInfo.FromPath(strSelFile)); 78 79 UIUtil.DestroyForm(dlgFmt); 80 return Import(pwStorage, ffp, lConnections.ToArray(), 81 false, null, false, fParent); 82 } 83 Import(PwDatabase pwDatabase, FileFormatProvider fmtImp, IOConnectionInfo[] vConnections, bool bSynchronize, IUIOperations uiOps, bool bForceSave, Form fParent)84 public static bool? Import(PwDatabase pwDatabase, FileFormatProvider fmtImp, 85 IOConnectionInfo[] vConnections, bool bSynchronize, IUIOperations uiOps, 86 bool bForceSave, Form fParent) 87 { 88 if(pwDatabase == null) throw new ArgumentNullException("pwDatabase"); 89 if(!pwDatabase.IsOpen) return null; 90 if(fmtImp == null) throw new ArgumentNullException("fmtImp"); 91 if(vConnections == null) throw new ArgumentNullException("vConnections"); 92 93 if(!AppPolicy.Try(AppPolicyId.Import)) return false; 94 if(!fmtImp.TryBeginImport()) return false; 95 96 bool bUseTempDb = (fmtImp.SupportsUuids || fmtImp.RequiresKey); 97 bool bAllSuccess = true; 98 MainForm mf = Program.MainForm; // Null for KPScript 99 100 // if(bSynchronize) { Debug.Assert(vFiles.Length == 1); } 101 102 IStatusLogger dlgStatus; 103 if(Program.Config.UI.ShowImportStatusDialog || 104 ((mf != null) && !mf.HasFormLoaded)) 105 dlgStatus = new OnDemandStatusDialog(false, fParent); 106 else dlgStatus = new UIBlockerStatusLogger(fParent); 107 108 dlgStatus.StartLogging(PwDefs.ShortProductName + " - " + (bSynchronize ? 109 KPRes.Synchronizing : KPRes.ImportingStatusMsg), false); 110 dlgStatus.SetText(bSynchronize ? KPRes.Synchronizing : 111 KPRes.ImportingStatusMsg, LogStatusType.Info); 112 113 if(vConnections.Length == 0) 114 { 115 try { fmtImp.Import(pwDatabase, null, dlgStatus); } 116 catch(Exception exSingular) 117 { 118 if(!string.IsNullOrEmpty(exSingular.Message)) 119 { 120 // slf.SetText(exSingular.Message, LogStatusType.Warning); 121 MessageService.ShowWarning(exSingular); 122 } 123 } 124 125 dlgStatus.EndLogging(); 126 return true; 127 } 128 129 foreach(IOConnectionInfo iocIn in vConnections) 130 { 131 Stream s = null; 132 133 try { s = IOConnection.OpenRead(iocIn); } 134 catch(Exception exFile) 135 { 136 MessageService.ShowWarning(iocIn.GetDisplayName(), exFile); 137 bAllSuccess = false; 138 continue; 139 } 140 if(s == null) { Debug.Assert(false); bAllSuccess = false; continue; } 141 142 PwDatabase pwImp; 143 if(bUseTempDb) 144 { 145 pwImp = new PwDatabase(); 146 pwImp.New(new IOConnectionInfo(), pwDatabase.MasterKey); 147 pwImp.MemoryProtection = pwDatabase.MemoryProtection.CloneDeep(); 148 } 149 else pwImp = pwDatabase; 150 151 if(fmtImp.RequiresKey && !bSynchronize) 152 { 153 KeyPromptForm kpf = new KeyPromptForm(); 154 kpf.InitEx(iocIn, false, true); 155 156 if(UIUtil.ShowDialogNotValue(kpf, DialogResult.OK)) { s.Close(); continue; } 157 158 pwImp.MasterKey = kpf.CompositeKey; 159 UIUtil.DestroyForm(kpf); 160 } 161 else if(bSynchronize) pwImp.MasterKey = pwDatabase.MasterKey; 162 163 dlgStatus.SetText((bSynchronize ? KPRes.Synchronizing : 164 KPRes.ImportingStatusMsg) + " (" + iocIn.GetDisplayName() + 165 ")", LogStatusType.Info); 166 167 try { fmtImp.Import(pwImp, s, dlgStatus); } 168 catch(Exception excpFmt) 169 { 170 string strMsgEx = excpFmt.Message; 171 if(bSynchronize && (excpFmt is InvalidCompositeKeyException)) 172 strMsgEx = KLRes.InvalidCompositeKey + MessageService.NewParagraph + 173 KPRes.SynchronizingHint; 174 175 MessageService.ShowWarning(iocIn.GetDisplayName(), 176 KPRes.FileImportFailed, strMsgEx); 177 178 bAllSuccess = false; 179 continue; 180 } 181 finally { s.Close(); } 182 183 if(bUseTempDb) 184 { 185 PwMergeMethod mm; 186 if(!fmtImp.SupportsUuids) mm = PwMergeMethod.CreateNewUuids; 187 else if(bSynchronize) mm = PwMergeMethod.Synchronize; 188 else 189 { 190 ImportMethodForm imf = new ImportMethodForm(); 191 if(UIUtil.ShowDialogNotValue(imf, DialogResult.OK)) continue; 192 mm = imf.MergeMethod; 193 UIUtil.DestroyForm(imf); 194 } 195 196 try { pwDatabase.MergeIn(pwImp, mm, dlgStatus); } 197 catch(Exception exMerge) 198 { 199 MessageService.ShowWarning(iocIn.GetDisplayName(), 200 KPRes.ImportFailed, exMerge); 201 202 bAllSuccess = false; 203 continue; 204 } 205 } 206 } 207 208 if(bSynchronize && bAllSuccess) 209 { 210 Debug.Assert(uiOps != null); 211 if(uiOps == null) throw new ArgumentNullException("uiOps"); 212 213 dlgStatus.SetText(KPRes.Synchronizing + " (" + 214 KPRes.SavingDatabase + ")", LogStatusType.Info); 215 216 if(mf != null) 217 { 218 try { mf.DocumentManager.ActiveDatabase = pwDatabase; } 219 catch(Exception) { Debug.Assert(false); } 220 } 221 222 if(uiOps.UIFileSave(bForceSave)) 223 { 224 foreach(IOConnectionInfo ioc in vConnections) 225 { 226 try 227 { 228 // dlgStatus.SetText(KPRes.Synchronizing + " (" + 229 // KPRes.SavingDatabase + " " + ioc.GetDisplayName() + 230 // ")", LogStatusType.Info); 231 232 string strSource = pwDatabase.IOConnectionInfo.Path; 233 if(!string.Equals(ioc.Path, strSource, StrUtil.CaseIgnoreCmp)) 234 { 235 bool bSaveAs = true; 236 237 if(pwDatabase.IOConnectionInfo.IsLocalFile() && 238 ioc.IsLocalFile()) 239 { 240 // Do not try to copy an encrypted file; 241 // https://sourceforge.net/p/keepass/discussion/329220/thread/9c9eb989/ 242 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363851.aspx 243 if((long)(File.GetAttributes(strSource) & 244 FileAttributes.Encrypted) == 0) 245 { 246 File.Copy(strSource, ioc.Path, true); 247 bSaveAs = false; 248 } 249 } 250 251 if(bSaveAs) pwDatabase.SaveAs(ioc, false, null); 252 } 253 // else { } // No assert (sync on save) 254 255 if(mf != null) 256 mf.FileMruList.AddItem(ioc.GetDisplayName(), 257 ioc.CloneDeep()); 258 } 259 catch(Exception exSync) 260 { 261 MessageService.ShowWarning(KPRes.SyncFailed, 262 pwDatabase.IOConnectionInfo.GetDisplayName() + 263 MessageService.NewLine + ioc.GetDisplayName(), exSync); 264 265 bAllSuccess = false; 266 continue; 267 } 268 } 269 } 270 else 271 { 272 MessageService.ShowWarning(KPRes.SyncFailed, 273 pwDatabase.IOConnectionInfo.GetDisplayName()); 274 275 bAllSuccess = false; 276 } 277 } 278 279 dlgStatus.EndLogging(); 280 return bAllSuccess; 281 } 282 Import(PwDatabase pd, FileFormatProvider fmtImp, IOConnectionInfo iocImp, PwMergeMethod mm, CompositeKey cmpKey)283 public static bool? Import(PwDatabase pd, FileFormatProvider fmtImp, 284 IOConnectionInfo iocImp, PwMergeMethod mm, CompositeKey cmpKey) 285 { 286 if(pd == null) { Debug.Assert(false); return false; } 287 if(fmtImp == null) { Debug.Assert(false); return false; } 288 if(iocImp == null) { Debug.Assert(false); return false; } 289 if(cmpKey == null) cmpKey = new CompositeKey(); 290 291 if(!AppPolicy.Try(AppPolicyId.Import)) return false; 292 if(!fmtImp.TryBeginImport()) return false; 293 294 PwDatabase pdImp = new PwDatabase(); 295 pdImp.New(new IOConnectionInfo(), cmpKey); 296 pdImp.MemoryProtection = pd.MemoryProtection.CloneDeep(); 297 298 Stream s = IOConnection.OpenRead(iocImp); 299 if(s == null) 300 throw new FileNotFoundException(iocImp.GetDisplayName() + 301 MessageService.NewLine + KPRes.FileNotFoundError); 302 303 try { fmtImp.Import(pdImp, s, null); } 304 finally { s.Close(); } 305 306 pd.MergeIn(pdImp, mm); 307 return true; 308 } 309 Synchronize(PwDatabase pwStorage, IUIOperations uiOps, bool bOpenFromUrl, Form fParent)310 public static bool? Synchronize(PwDatabase pwStorage, IUIOperations uiOps, 311 bool bOpenFromUrl, Form fParent) 312 { 313 if(pwStorage == null) throw new ArgumentNullException("pwStorage"); 314 if(!pwStorage.IsOpen) return null; 315 if(!AppPolicy.Try(AppPolicyId.Import)) return null; 316 317 List<IOConnectionInfo> vConnections = new List<IOConnectionInfo>(); 318 if(bOpenFromUrl == false) 319 { 320 OpenFileDialogEx ofd = UIUtil.CreateOpenFileDialog(KPRes.Synchronize, 321 UIUtil.CreateFileTypeFilter(AppDefs.FileExtension.FileExt, 322 KPRes.KdbxFiles, true), 1, null, true, 323 AppDefs.FileDialogContext.Sync); 324 325 if(ofd.ShowDialog() != DialogResult.OK) return null; 326 327 foreach(string strSelFile in ofd.FileNames) 328 vConnections.Add(IOConnectionInfo.FromPath(strSelFile)); 329 } 330 else // Open URL 331 { 332 IOConnectionForm iocf = new IOConnectionForm(); 333 iocf.InitEx(false, null, true, true); 334 335 if(UIUtil.ShowDialogNotValue(iocf, DialogResult.OK)) return null; 336 337 vConnections.Add(iocf.IOConnectionInfo); 338 UIUtil.DestroyForm(iocf); 339 } 340 341 return Import(pwStorage, new KeePassKdb2x(), vConnections.ToArray(), 342 true, uiOps, false, fParent); 343 } 344 Synchronize(PwDatabase pwStorage, IUIOperations uiOps, IOConnectionInfo iocSyncWith, bool bForceSave, Form fParent)345 public static bool? Synchronize(PwDatabase pwStorage, IUIOperations uiOps, 346 IOConnectionInfo iocSyncWith, bool bForceSave, Form fParent) 347 { 348 if(pwStorage == null) throw new ArgumentNullException("pwStorage"); 349 if(!pwStorage.IsOpen) return null; // No assert or throw 350 if(iocSyncWith == null) throw new ArgumentNullException("iocSyncWith"); 351 if(!AppPolicy.Try(AppPolicyId.Import)) return null; 352 353 Program.TriggerSystem.RaiseEvent(EcasEventIDs.SynchronizingDatabaseFile, 354 EcasProperty.Database, pwStorage); 355 356 List<IOConnectionInfo> vConnections = new List<IOConnectionInfo>(); 357 vConnections.Add(iocSyncWith); 358 359 bool? ob = Import(pwStorage, new KeePassKdb2x(), vConnections.ToArray(), 360 true, uiOps, bForceSave, fParent); 361 362 // Always raise the post event, such that the event pair can 363 // for instance be used to turn off/on other triggers 364 Program.TriggerSystem.RaiseEvent(EcasEventIDs.SynchronizedDatabaseFile, 365 EcasProperty.Database, pwStorage); 366 367 return ob; 368 } 369 CountQuotes(string str, int posMax)370 public static int CountQuotes(string str, int posMax) 371 { 372 int i = 0, n = 0; 373 374 while(true) 375 { 376 i = str.IndexOf('\"', i); 377 if(i < 0) return n; 378 379 ++i; 380 if(i > posMax) return n; 381 382 ++n; 383 } 384 } 385 SplitCsvLine(string strLine, string strDelimiter)386 public static List<string> SplitCsvLine(string strLine, string strDelimiter) 387 { 388 List<string> list = new List<string>(); 389 390 int nOffset = 0; 391 while(true) 392 { 393 int i = strLine.IndexOf(strDelimiter, nOffset); 394 if(i < 0) break; 395 396 int nQuotes = CountQuotes(strLine, i); 397 if((nQuotes & 1) == 0) 398 { 399 list.Add(strLine.Substring(0, i)); 400 strLine = strLine.Remove(0, i + strDelimiter.Length); 401 nOffset = 0; 402 } 403 else 404 { 405 nOffset = i + strDelimiter.Length; 406 if(nOffset >= strLine.Length) break; 407 } 408 } 409 410 list.Add(strLine); 411 return list; 412 } 413 SetStatus(IStatusLogger slLogger, uint uPercent)414 public static bool SetStatus(IStatusLogger slLogger, uint uPercent) 415 { 416 if(slLogger != null) return slLogger.SetProgress(uPercent); 417 return true; 418 } 419 420 private static readonly string[] m_vTitles = { 421 "title", "system", "account", "entry", 422 "item", "itemname", "item name", "subject", 423 "service", "servicename", "service name", 424 "head", "heading", "card", "product", "provider", "bank", 425 "type", 426 427 // Non-English names 428 "seite" 429 }; 430 431 private static readonly string[] m_vTitlesSubstr = { 432 "title", "system", "account", "entry", 433 "item", "subject", "service", "head" 434 }; 435 436 private static readonly string[] m_vUserNames = { 437 "user", "name", "username", "user name", "login name", 438 "login", "form_loginname", "wpname", "mail", 439 "email", "e-mail", "id", "userid", "user id", 440 "loginid", "login id", "log", "uin", 441 "first name", "last name", "card#", "account #", 442 "member", "member #", "owner", 443 444 // Non-English names 445 "nom", "benutzername" 446 }; 447 448 private static readonly string[] m_vUserNamesSubstr = { 449 "user", "name", "login", "mail", "owner" 450 }; 451 452 private static readonly string[] m_vPasswords = { 453 "password", "pass word", "passphrase", "pass phrase", 454 "pass", "code", "code word", "codeword", 455 "secret", "secret word", 456 "key", "keyword", "key word", "keyphrase", "key phrase", 457 "form_pw", "wppassword", "pin", "pwd", "pw", "pword", 458 "p", "serial", "serial#", "license key", "reg #", 459 460 // Non-English names 461 "passwort", "kennwort" 462 }; 463 464 private static readonly string[] m_vPasswordsSubstr = { 465 "pass", "code", "secret", "key", "pw", "pin" 466 }; 467 468 private static readonly string[] m_vUrls = { 469 "url", "hyper link", "hyperlink", "link", 470 "host", "hostname", "host name", "server", "address", 471 "hyper ref", "href", "web", "website", "web site", "site", 472 "web-site", 473 474 // Non-English names 475 "ort", "adresse", "webseite" 476 }; 477 478 private static readonly string[] m_vUrlsSubstr = { 479 "url", "link", "host", "address", "hyper ref", "href", 480 "web", "site" 481 }; 482 483 private static readonly string[] m_vNotes = { 484 "note", "notes", "comment", "comments", "memo", 485 "description", "free form", "freeform", 486 "free text", "freetext", "free", 487 488 // Non-English names 489 "kommentar", "hinweis" 490 }; 491 492 private static readonly string[] m_vNotesSubstr = { 493 "note", "comment", "memo", "description", "free" 494 }; 495 MapNameToStandardField(string strName, bool bAllowFuzzy)496 public static string MapNameToStandardField(string strName, bool bAllowFuzzy) 497 { 498 if(strName == null) { Debug.Assert(false); return string.Empty; } 499 500 string strFind = strName.Trim().ToLower(); 501 502 if(Array.IndexOf<string>(m_vTitles, strFind) >= 0) 503 return PwDefs.TitleField; 504 if(Array.IndexOf<string>(m_vUserNames, strFind) >= 0) 505 return PwDefs.UserNameField; 506 if(Array.IndexOf<string>(m_vPasswords, strFind) >= 0) 507 return PwDefs.PasswordField; 508 if(Array.IndexOf<string>(m_vUrls, strFind) >= 0) 509 return PwDefs.UrlField; 510 if(Array.IndexOf<string>(m_vNotes, strFind) >= 0) 511 return PwDefs.NotesField; 512 513 if(strFind.Equals(KPRes.Title, StrUtil.CaseIgnoreCmp)) 514 return PwDefs.TitleField; 515 if(strFind.Equals(KPRes.UserName, StrUtil.CaseIgnoreCmp)) 516 return PwDefs.UserNameField; 517 if(strFind.Equals(KPRes.Password, StrUtil.CaseIgnoreCmp)) 518 return PwDefs.PasswordField; 519 if(strFind.Equals(KPRes.Url, StrUtil.CaseIgnoreCmp)) 520 return PwDefs.UrlField; 521 if(strFind.Equals(KPRes.Notes, StrUtil.CaseIgnoreCmp)) 522 return PwDefs.NotesField; 523 524 if(!bAllowFuzzy) return string.Empty; 525 526 // Check for passwords first, then user names ("vb_login_password") 527 foreach(string strSub in m_vPasswordsSubstr) 528 { 529 if(strFind.Contains(strSub)) return PwDefs.PasswordField; 530 } 531 foreach(string strSub in m_vUserNamesSubstr) 532 { 533 if(strFind.Contains(strSub)) return PwDefs.UserNameField; 534 } 535 foreach(string strSub in m_vUrlsSubstr) 536 { 537 if(strFind.Contains(strSub)) return PwDefs.UrlField; 538 } 539 foreach(string strSub in m_vNotesSubstr) 540 { 541 if(strFind.Contains(strSub)) return PwDefs.NotesField; 542 } 543 foreach(string strSub in m_vTitlesSubstr) 544 { 545 if(strFind.Contains(strSub)) return PwDefs.TitleField; 546 } 547 548 return string.Empty; 549 } 550 AppendToField(PwEntry pe, string strName, string strValue, PwDatabase pdContext)551 public static void AppendToField(PwEntry pe, string strName, string strValue, 552 PwDatabase pdContext) 553 { 554 AppendToField(pe, strName, strValue, pdContext, null, false); 555 } 556 AppendToField(PwEntry pe, string strName, string strValue, PwDatabase pdContext, string strSeparator, bool bOnlyIfNotDup)557 public static void AppendToField(PwEntry pe, string strName, string strValue, 558 PwDatabase pdContext, string strSeparator, bool bOnlyIfNotDup) 559 { 560 if(pe == null) { Debug.Assert(false); return; } 561 if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return; } 562 563 if(strValue == null) { Debug.Assert(false); strValue = string.Empty; } 564 565 if(strSeparator == null) 566 { 567 if(PwDefs.IsStandardField(strName) && (strName != PwDefs.NotesField)) 568 strSeparator = ", "; 569 else strSeparator = MessageService.NewLine; 570 } 571 572 ProtectedString psPrev = pe.Strings.Get(strName); 573 if((psPrev == null) || psPrev.IsEmpty) 574 { 575 MemoryProtectionConfig mpc = ((pdContext != null) ? 576 pdContext.MemoryProtection : new MemoryProtectionConfig()); 577 bool bProtect = mpc.GetProtection(strName); 578 579 pe.Strings.Set(strName, new ProtectedString(bProtect, strValue)); 580 } 581 else if(strValue.Length != 0) 582 { 583 bool bAppend = true; 584 if(bOnlyIfNotDup) 585 { 586 ProtectedString psValue = new ProtectedString(false, strValue); 587 bAppend = !psPrev.Equals(psValue, false); 588 } 589 590 if(bAppend) 591 pe.Strings.Set(strName, psPrev + (strSeparator + strValue)); 592 } 593 } 594 EntryEquals(PwEntry pe1, PwEntry pe2)595 public static bool EntryEquals(PwEntry pe1, PwEntry pe2) 596 { 597 if(pe1.ParentGroup == null) return false; 598 if(pe2.ParentGroup == null) return false; 599 if(pe1.ParentGroup.Name != pe2.ParentGroup.Name) 600 return false; 601 602 return pe1.Strings.EqualsDictionary(pe2.Strings, 603 PwCompareOptions.NullEmptyEquivStd, MemProtCmpMode.None); 604 } 605 GuiSendRetrieve(string strSendPrefix)606 internal static string GuiSendRetrieve(string strSendPrefix) 607 { 608 if(strSendPrefix.Length > 0) 609 GuiSendKeysPrc(strSendPrefix); 610 611 return GuiRetrieveDataField(); 612 } 613 GuiRetrieveDataField()614 private static string GuiRetrieveDataField() 615 { 616 ClipboardUtil.Clear(); 617 Application.DoEvents(); 618 619 GuiSendKeysPrc(@"^c"); 620 621 try 622 { 623 if(ClipboardUtil.ContainsText()) 624 return (ClipboardUtil.GetText() ?? string.Empty); 625 } 626 catch(Exception) { Debug.Assert(false); } // Opened by other process 627 628 return string.Empty; 629 } 630 GuiSendKeysPrc(string strSend)631 internal static void GuiSendKeysPrc(string strSend) 632 { 633 if(strSend.Length > 0) 634 SendInputEx.SendKeysWait(strSend, false); 635 636 Application.DoEvents(); 637 Thread.Sleep(100); 638 Application.DoEvents(); 639 } 640 GuiSendWaitWindowChange(string strSend)641 internal static void GuiSendWaitWindowChange(string strSend) 642 { 643 IntPtr ptrCur = NativeMethods.GetForegroundWindowHandle(); 644 645 ImportUtil.GuiSendKeysPrc(strSend); 646 647 int nRound = 0; 648 while(true) 649 { 650 Application.DoEvents(); 651 652 IntPtr ptr = NativeMethods.GetForegroundWindowHandle(); 653 if(ptr != ptrCur) break; 654 655 ++nRound; 656 if(nRound > 1000) 657 throw new InvalidOperationException(); 658 659 Thread.Sleep(50); 660 } 661 662 Thread.Sleep(100); 663 Application.DoEvents(); 664 } 665 FixUrl(string strUrl)666 internal static string FixUrl(string strUrl) 667 { 668 strUrl = (strUrl ?? string.Empty).Trim(); 669 670 if((strUrl.Length > 0) && (strUrl.IndexOf('.') >= 0) && 671 (strUrl.IndexOf(':') < 0) && (strUrl.IndexOf('@') < 0)) 672 { 673 string strNew = ("https://" + strUrl.ToLower()); 674 if(strUrl.IndexOf('/') < 0) strNew += "/"; 675 return strNew; 676 } 677 678 return strUrl; 679 } 680 } 681 } 682