private bool SearchEntriesSingle(SearchParameters spIn, PwObjectList <PwEntry> listStorage, IDictionary <PwUuid, KeyValuePair <string, string> > resultContexts, IStatusLogger slStatus, ref ulong uCurEntries, ulong uTotalEntries) { SearchParameters sp = spIn.Clone(); if (sp.SearchString == null) { Debug.Assert(false); return(true); } sp.SearchString = sp.SearchString.Trim(); bool bTitle = sp.SearchInTitles; bool bUserName = sp.SearchInUserNames; bool bPassword = sp.SearchInPasswords; bool bUrl = sp.SearchInUrls; bool bNotes = sp.SearchInNotes; bool bOther = sp.SearchInOther; bool bUuids = sp.SearchInUuids; bool bGroupName = sp.SearchInGroupNames; bool bTags = sp.SearchInTags; bool bExcludeExpired = sp.ExcludeExpired; bool bRespectEntrySearchingDisabled = sp.RespectEntrySearchingDisabled; DateTime dtNow = DateTime.Now; Regex rx = null; if (sp.RegularExpression) { RegexOptions ro = RegexOptions.None; // RegexOptions.Compiled if ((sp.ComparisonMode == StringComparison.CurrentCultureIgnoreCase) || #if !KeePassUAP (sp.ComparisonMode == StringComparison.InvariantCultureIgnoreCase) || #endif (sp.ComparisonMode == StringComparison.OrdinalIgnoreCase)) { ro |= RegexOptions.IgnoreCase; } rx = new Regex(sp.SearchString, ro); } ulong uLocalCurEntries = uCurEntries; EntryHandler eh = null; if (sp.SearchString.Length <= 0) // Report all { eh = delegate(PwEntry pe) { if (slStatus != null) { if (!slStatus.SetProgress((uint)((uLocalCurEntries * 100UL) / uTotalEntries))) { return(false); } ++uLocalCurEntries; } if (bRespectEntrySearchingDisabled && !pe.GetSearchingEnabled()) { return(true); // Skip } if (bExcludeExpired && pe.Expires && (dtNow > pe.ExpiryTime)) { return(true); // Skip } listStorage.Add(pe); return(true); }; } else { eh = delegate(PwEntry pe) { if (slStatus != null) { if (!slStatus.SetProgress((uint)((uLocalCurEntries * 100UL) / uTotalEntries))) { return(false); } ++uLocalCurEntries; } if (bRespectEntrySearchingDisabled && !pe.GetSearchingEnabled()) { return(true); // Skip } if (bExcludeExpired && pe.Expires && (dtNow > pe.ExpiryTime)) { return(true); // Skip } uint uInitialResults = listStorage.UCount; foreach (KeyValuePair <string, ProtectedString> kvp in pe.Strings) { string strKey = kvp.Key; if (strKey == PwDefs.TitleField) { if (bTitle) { SearchEvalAdd(sp, kvp.Value.ReadString(), rx, pe, listStorage, resultContexts, strKey); } } else if (strKey == PwDefs.UserNameField) { if (bUserName) { SearchEvalAdd(sp, kvp.Value.ReadString(), rx, pe, listStorage, resultContexts, strKey); } } else if (strKey == PwDefs.PasswordField) { if (bPassword) { SearchEvalAdd(sp, kvp.Value.ReadString(), rx, pe, listStorage, resultContexts, strKey); } } else if (strKey == PwDefs.UrlField) { if (bUrl) { SearchEvalAdd(sp, kvp.Value.ReadString(), rx, pe, listStorage, resultContexts, strKey); } } else if (strKey == PwDefs.NotesField) { if (bNotes) { SearchEvalAdd(sp, kvp.Value.ReadString(), rx, pe, listStorage, resultContexts, strKey); } } else if (bOther) { SearchEvalAdd(sp, kvp.Value.ReadString(), rx, pe, listStorage, resultContexts, strKey); } // An entry can match only once => break if we have added it if (listStorage.UCount > uInitialResults) { break; } } if (bUuids && (listStorage.UCount == uInitialResults)) { SearchEvalAdd(sp, pe.Uuid.ToHexString(), rx, pe, listStorage, resultContexts, SearchContextTags); } if (bGroupName && (listStorage.UCount == uInitialResults) && (pe.ParentGroup != null)) { SearchEvalAdd(sp, pe.ParentGroup.Name, rx, pe, listStorage, resultContexts, SearchContextParentGroup); } if (bTags) { foreach (string strTag in pe.Tags) { if (listStorage.UCount != uInitialResults) { break; // Match } SearchEvalAdd(sp, strTag, rx, pe, listStorage, resultContexts, SearchContextTags); } } return(true); }; } if (!PreOrderTraverseTree(null, eh)) { return(false); } uCurEntries = uLocalCurEntries; return(true); }
private void SrsmSearch(SearchParameters sp, PwObjectList <PwEntry> lResults, IStatusLogger sl) { PwObjectList <PwEntry> lAll = GetEntries(true); DateTime dtNow = DateTime.UtcNow; List <PwEntry> l = new List <PwEntry>(); foreach (PwEntry pe in lAll) { if (sp.ExcludeExpired && pe.Expires && (pe.ExpiryTime <= dtNow)) { continue; } if (sp.RespectEntrySearchingDisabled && !pe.GetSearchingEnabled()) { continue; } l.Add(pe); } List <string> lTerms; if (sp.SearchMode == PwSearchMode.Simple) { lTerms = StrUtil.SplitSearchTerms(sp.SearchString); } else { lTerms = new List <string>(); lTerms.Add(sp.SearchString); } // Search longer strings first (for improved performance) lTerms.Sort(StrUtil.CompareLengthGt); SearchParameters spSub = sp.Clone(); for (int iTerm = 0; iTerm < lTerms.Count; ++iTerm) { string strTerm = lTerms[iTerm]; // No trim if (string.IsNullOrEmpty(strTerm)) { continue; } bool bNegate = false; if ((sp.SearchMode == PwSearchMode.Simple) && (strTerm.Length >= 2) && (strTerm[0] == '-')) { strTerm = strTerm.Substring(1); bNegate = true; } spSub.SearchString = strTerm; ulong uStEntriesDone = (ulong)iTerm * (ulong)l.Count; ulong uStEntriesMax = (ulong)lTerms.Count * (ulong)l.Count; List <PwEntry> lOut; if (!SrsmSearchSingle(spSub, l, out lOut, sl, uStEntriesDone, uStEntriesMax)) { l.Clear(); // Do not return non-matching entries break; } if (bNegate) { List <PwEntry> lNew = new List <PwEntry>(); int iNeg = 0; foreach (PwEntry pe in l) { if ((iNeg < lOut.Count) && object.ReferenceEquals(lOut[iNeg], pe)) { ++iNeg; } else { Debug.Assert(!lOut.Contains(pe)); lNew.Add(pe); } } Debug.Assert(lNew.Count == (l.Count - lOut.Count)); l = lNew; } else { l = lOut; } } lResults.Add(l); }