public void MSOXCFOLD_S03_TC01_StaticSearchVerification() { this.CheckWhetherSupportTransport(); this.Adapter.DoConnect(ConnectionType.PrivateMailboxServer); this.GenericFolderInitialization(); #region Step 1. The client calls RopCreateFolder to create the general folder [MSOXCFOLDSubfolder1] under the root folder. RopCreateFolderRequest createFolderRequest = new RopCreateFolderRequest { RopId = (byte)RopId.RopCreateFolder, LogonId = Constants.CommonLogonId, InputHandleIndex = Constants.CommonInputHandleIndex, OutputHandleIndex = Constants.CommonOutputHandleIndex, FolderType = (byte)FolderType.Genericfolder, UseUnicodeStrings = 0x0, OpenExisting = 0x00, Reserved = 0x0, DisplayName = Encoding.ASCII.GetBytes(Constants.Subfolder1), Comment = Encoding.ASCII.GetBytes(Constants.Subfolder1) }; RopCreateFolderResponse createFolderResponse = this.Adapter.CreateFolder(createFolderRequest, this.RootFolderHandle, ref this.responseHandles); Site.Assert.AreEqual<uint>(Constants.SuccessCode, createFolderResponse.ReturnValue, "RopCreateFolder ROP operation performs successfully!"); uint subfolderHandle1 = this.responseHandles[0][createFolderResponse.OutputHandleIndex]; ulong subfolderId1 = createFolderResponse.FolderId; #endregion #region Step 2. The client creates two general messages under the folder [MSOXCFOLDSubfolder1]. uint messageHandle1 = 0; ulong messageId1 = 0; this.CreateSaveMessage(subfolderHandle1, subfolderId1, ref messageId1, ref messageHandle1); uint messageHandle2 = 0; ulong messageId2 = 0; this.CreateSaveMessage(subfolderHandle1, subfolderId1, ref messageId2, ref messageHandle2); #endregion #region Step 3. The client calls RopCreateFolder to create the search folder [MSOXCFOLDSearchFolder2] under the root folder. createFolderRequest.FolderType = (byte)FolderType.Searchfolder; createFolderRequest.DisplayName = Encoding.ASCII.GetBytes(Constants.SearchFolder2); createFolderRequest.Comment = Encoding.ASCII.GetBytes(Constants.SearchFolder2); createFolderResponse = this.Adapter.CreateFolder(createFolderRequest, this.RootFolderHandle, ref this.responseHandles); Site.Assert.AreEqual<uint>(Constants.SuccessCode, createFolderResponse.ReturnValue, "RopCreateFolder ROP operation performs successfully!"); uint searchFolderHandle2 = this.responseHandles[0][createFolderResponse.OutputHandleIndex]; #endregion #region Step 4. The client calls RopSetSearchCriteria to establish search criteria for [MSOXCFOLDSearchFolder2]. RopSetSearchCriteriaRequest setSearchCriteriaRequest = new RopSetSearchCriteriaRequest { RopId = (byte)RopId.RopSetSearchCriteria, LogonId = Constants.CommonLogonId, InputHandleIndex = Constants.CommonInputHandleIndex }; PropertyTag propertyTag = new PropertyTag { PropertyId = (ushort)MessagePropertyId.PidTagMessageClass, PropertyType = (ushort)PropertyType.PtypString }; ExistRestriction existRestriction = new ExistRestriction { PropTag = propertyTag }; setSearchCriteriaRequest.RestrictionDataSize = (ushort)existRestriction.Size(); setSearchCriteriaRequest.RestrictionData = existRestriction.Serialize(); setSearchCriteriaRequest.FolderIds = new ulong[] { subfolderId1 }; setSearchCriteriaRequest.FolderIdCount = (ushort)setSearchCriteriaRequest.FolderIds.Length; setSearchCriteriaRequest.SearchFlags = (uint)SetSearchFlags.ContentIndexedSearch | (uint)SetSearchFlags.StaticSearch | (uint)SetSearchFlags.RestartSearch; RopSetSearchCriteriaResponse setSearchCriteriaResponse = this.Adapter.SetSearchCriteria(setSearchCriteriaRequest, searchFolderHandle2, ref this.responseHandles); Site.Assert.AreEqual<uint>(Constants.SuccessCode, setSearchCriteriaResponse.ReturnValue, "RopSearchCriteria ROP operation performs successfully!"); #endregion #region Step 5. The client calls RopGetSearchCriteria to obtain the search criteria and the status of the search folder [MSOXCFOLDSearchFolder2]. RopGetSearchCriteriaRequest getSearchCriteriaRequest = new RopGetSearchCriteriaRequest { RopId = (byte)RopId.RopGetSearchCriteria, LogonId = Constants.CommonLogonId, InputHandleIndex = Constants.CommonInputHandleIndex, UseUnicode = 0x00, IncludeRestriction = 0x01, IncludeFolders = 0x01 }; RopGetSearchCriteriaResponse getSearchCriteriaResponse = this.Adapter.GetSearchCriteria(getSearchCriteriaRequest, searchFolderHandle2, ref this.responseHandles); Site.Assert.AreEqual<uint>(Constants.SuccessCode, getSearchCriteriaResponse.ReturnValue, "RopGetSearchCriteria ROP operation performs successfully!"); #region Verify the requirements: MS-OXCFOLD_R1200 and MS-OXCFOLD_R1233. // Add the debug information Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCFOLD_R1200"); // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R1200 // SHALLOW_SEARCH bit in the RopSetSearchCriteria ROP request means the search includes only the search folder containers that are specified in the FolderIds field. // If the bit SEARCH_RECURSIVE in the RopGetSearchCriteria ROP response is not set means only the search folder containers that are specified in the last RopSetSearchCriteria ROP request are being searched. // So, if the bit SEARCH_RECURSIVE in getSearchCriteriaResponse is not set, R1200 can be verified. Site.CaptureRequirementIfAreNotEqual<uint>( (uint)GetSearchFlags.Recursive, getSearchCriteriaResponse.SearchFlags & (uint)GetSearchFlags.Recursive, 1200, @"[In RopSetSearchCriteria ROP Request Buffer] SearchFlags (4 bytes): If neither bit [RECURSIVE_SEARCH or SHALLOW_SEARCH] is set, the default is SHALLOW_SEARCH."); // Add the debug information this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCFOLD_R1233"); List<ulong> folderIdsInGetSearchCriteriaResponse = new List<ulong>(); folderIdsInGetSearchCriteriaResponse.AddRange(getSearchCriteriaResponse.FolderIds); // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R1233 this.Site.CaptureRequirementIfIsFalse( folderIdsInGetSearchCriteriaResponse.Contains(createFolderResponse.FolderId), 1233, @"[In Setting Up a Search Folder] [A search folder cannot be included in its own search scope] Therefore, the FolderIds field MUST NOT include the FID of the search folder."); #endregion #endregion #region Step 6. The client calls RopGetContentsTable to retrieve the contents table for the search folder [MSOXCFOLDSearchFolder2]. RopGetContentsTableRequest getContentsTableRequest = new RopGetContentsTableRequest(); RopGetContentsTableResponse getContentsTableResponse; getContentsTableRequest.RopId = (byte)RopId.RopGetContentsTable; getContentsTableRequest.LogonId = Constants.CommonLogonId; getContentsTableRequest.InputHandleIndex = Constants.CommonInputHandleIndex; getContentsTableRequest.OutputHandleIndex = Constants.CommonOutputHandleIndex; getContentsTableRequest.TableFlags = (byte)FolderTableFlags.None; int count = 0; do { getContentsTableResponse = this.Adapter.GetContentsTable(getContentsTableRequest, searchFolderHandle2, ref this.responseHandles); Site.Assert.AreEqual<uint>(Constants.SuccessCode, getContentsTableResponse.ReturnValue, "RopGetContentsTable ROP operation performs successfully!"); if (getContentsTableResponse.RowCount != 2) { Thread.Sleep(this.WaitTime); } else { break; } count++; } while (count < this.RetryCount); uint rowCountBeforeHardDel = getContentsTableResponse.RowCount; Site.Assert.AreEqual<uint>(2, rowCountBeforeHardDel, "The two general messages created in step 2 were fetched in search folder."); #endregion #region Step 7. The client calls RopHardDeleteMessage ROP operation to hard delete a message in the general folder [MSOXCFOLDSubfolder1] under the root folder. ulong[] messageIds = new ulong[] { messageId1 }; RopHardDeleteMessagesRequest hardDeleteMessagesRequest = new RopHardDeleteMessagesRequest { RopId = (byte)RopId.RopHardDeleteMessages, LogonId = Constants.CommonLogonId, InputHandleIndex = Constants.CommonInputHandleIndex, WantAsynchronous = 0x00, NotifyNonRead = 0x00, MessageIdCount = (ushort)messageIds.Length, MessageIds = messageIds }; RopHardDeleteMessagesResponse hardDeleteMessagesResponse = this.Adapter.HardDeleteMessages(hardDeleteMessagesRequest, subfolderHandle1, ref this.responseHandles); Site.Assert.AreEqual<uint>(Constants.SuccessCode, hardDeleteMessagesResponse.ReturnValue, "RopHardDeleteMessages ROP operation performs successfully!"); Site.Assert.AreEqual<uint>(0x00, hardDeleteMessagesResponse.PartialCompletion, "RopHardDeleteMessages ROP operation is complete!"); #endregion #region Step 8. The client calls RopGetContentsTable to retrieve the contents table for the search folder [MSOXCFOLDSearchFolder2]. count = 0; bool searchFolderNotChange = false; do { getContentsTableResponse = this.Adapter.GetContentsTable(getContentsTableRequest, searchFolderHandle2, ref this.responseHandles); Site.Assert.AreEqual<uint>(Constants.SuccessCode, getContentsTableResponse.ReturnValue, "RopGetContentsTable ROP operation performs successfully!"); if (getContentsTableResponse.RowCount != rowCountBeforeHardDel) { Thread.Sleep(this.WaitTime); } else { searchFolderNotChange = true; break; } count++; } while (count < this.RetryCount); #region Verify the requirements: MS-OXCFOLD_R795, MS-OXCFOLD_R784, MS-OXCFOLD_R1084, MS-OXCFOLD_R549, MS-OXCFOLD_R1093, MS-OXCFOLD_R1094. // Add the debug information Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCFOLD_R795"); // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R795 // The search folder contents didn't change after the message has been hard deleted, it indicates the current search is static search. Site.CaptureRequirementIfIsTrue( searchFolderNotChange, 795, @"[In RopGetSearchCriteria ROP Response Buffer] SearchFlags (4 bytes): SEARCH_STATIC (0x00010000) means that the search is static."); // Add the debug information Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCFOLD_R784"); // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R784 Site.CaptureRequirementIfIsTrue( searchFolderNotChange, 784, @"[In RopSetSearchCriteria ROP Request Buffer] SearchFlags (4 bytes): STATIC_SEARCH (0x00040000) means that the search is static, if set."); // Add the debug information Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCFOLD_R1084"); // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R1084 Site.CaptureRequirementIfIsTrue( searchFolderNotChange, 1084, @"[In Processing a RopSetSearchCriteria ROP Request] For static search folders, the contents of the search folder are not updated after the initial population is complete."); // Add the debug information Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCFOLD_R549"); // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R549 Site.CaptureRequirementIfIsTrue( searchFolderNotChange, 549, @"[In Processing a RopSetSearchCriteria ROP Request] A static search causes the search folder to be populated once with all messages that match the search criteria at the point in time when the search is started or restarted."); // Add the debug information Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCFOLD_R1093"); // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R1093 Site.CaptureRequirementIfIsTrue( searchFolderNotChange, 1093, @"[In Processing a RopSetSearchCriteria ROP Request] The server MUST NOT update the search folder after the initial population when new messages that match the search criteria arrive in the search scope."); // Add the debug information Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCFOLD_R1094"); // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R1094 Site.CaptureRequirementIfIsTrue( searchFolderNotChange, 1094, @"[In Processing a RopSetSearchCriteria ROP Request] Or the server MUST NOT update the search folder after the initial population when existing messages that fit the search criteria are deleted."); #endregion #endregion #region Step 9. The client calls RopSetSearchCriteria to restart the search for [MSOXCFOLDSearchFolder2]. setSearchCriteriaRequest.SearchFlags = (uint)SetSearchFlags.ContentIndexedSearch | (uint)SetSearchFlags.RestartSearch; setSearchCriteriaResponse = this.Adapter.SetSearchCriteria(setSearchCriteriaRequest, searchFolderHandle2, ref this.responseHandles); Site.Assert.AreEqual<uint>(Constants.SuccessCode, setSearchCriteriaResponse.ReturnValue, "RopSearchCriteria ROP operation performs successfully!"); #endregion #region Step 10. The client calls RopGetContentsTable to retrieve the contents table for the search folder [MSOXCFOLDSearchFolder2]. count = 0; do { getContentsTableResponse = this.Adapter.GetContentsTable(getContentsTableRequest, searchFolderHandle2, ref this.responseHandles); Site.Assert.AreEqual<uint>(Constants.SuccessCode, getContentsTableResponse.ReturnValue, "RopGetContentsTable ROP operation performs successfully!"); if (getContentsTableResponse.RowCount != 1) { Thread.Sleep(this.WaitTime); } else { break; } count++; } while (count < this.RetryCount); // Add the debug information Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCFOLD_R551"); // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R551 // There should be 1 message found and copy to the search folder, so the RowCount should be 1. Site.CaptureRequirementIfAreEqual<uint>( 1, getContentsTableResponse.RowCount, 551, @"[In Processing a RopSetSearchCriteria ROP Request] To trigger an update, another RopSetSearchCriteria ROP request with the RESTART_SEARCH bit set in the SearchFlags field, as specified in section 2.2.1.4.1, is required."); #endregion #region Step 11. The client calls RopSetSearchCriteria to establish search criteria for [MSOXCFOLDSearchFolder2] by a new RestrictionData. setSearchCriteriaRequest = new RopSetSearchCriteriaRequest(); setSearchCriteriaRequest.RopId = (byte)RopId.RopSetSearchCriteria; setSearchCriteriaRequest.LogonId = Constants.CommonLogonId; setSearchCriteriaRequest.InputHandleIndex = Constants.CommonInputHandleIndex; ContentRestriction contentRestriction = new ContentRestriction { FuzzyLevelLow = FuzzyLevelLowValues.FL_PREFIX, FuzzyLevelHigh = FuzzyLevelHighValues.FL_IGNORECASE }; propertyTag = new PropertyTag { PropertyId = (ushort)MessagePropertyId.PidTagMessageClass, PropertyType = (ushort)PropertyType.PtypString }; contentRestriction.PropertyTag = propertyTag; TaggedPropertyValue taggedProperty = new TaggedPropertyValue { PropertyTag = propertyTag, Value = Encoding.Unicode.GetBytes("IPM.Task" + Constants.StringNullTerminated) }; contentRestriction.TaggedValue = taggedProperty; setSearchCriteriaRequest.RestrictionDataSize = (ushort)contentRestriction.Size(); setSearchCriteriaRequest.RestrictionData = contentRestriction.Serialize(); setSearchCriteriaRequest.FolderIds = new ulong[] { subfolderId1 }; setSearchCriteriaRequest.FolderIdCount = (ushort)setSearchCriteriaRequest.FolderIds.Length; setSearchCriteriaRequest.SearchFlags = (uint)SetSearchFlags.ContentIndexedSearch | (uint)SetSearchFlags.RestartSearch | (uint)SetSearchFlags.StaticSearch; setSearchCriteriaResponse = this.Adapter.SetSearchCriteria(setSearchCriteriaRequest, searchFolderHandle2, ref this.responseHandles); Site.Assert.AreEqual<uint>(Constants.SuccessCode, setSearchCriteriaResponse.ReturnValue, "RopSearchCriteria ROP operation performs successfully!"); #endregion #region Step 12. The client calls RopGetContentsTable to retrieve the contents table for the search folder [MSOXCFOLDSearchFolder2]. count = 0; do { getContentsTableResponse = this.Adapter.GetContentsTable(getContentsTableRequest, searchFolderHandle2, ref this.responseHandles); Site.Assert.AreEqual<uint>(Constants.SuccessCode, getContentsTableResponse.ReturnValue, "RopGetContentsTable ROP operation performs successfully!"); if (getContentsTableResponse.RowCount != 0) { Thread.Sleep(this.WaitTime); } else { break; } count++; } while (count < this.RetryCount); // Add the debug information Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCFOLD_R519"); // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R519 // For no message should be found so the search folder should empty, which means the RowCount is 0. Site.CaptureRequirementIfAreEqual<uint>( 0, getContentsTableResponse.RowCount, 519, @"[In Processing a RopSetSearchCriteria ROP Request] When new search criteria are applied, the server modifies the search folder to include only the messages that match the new search criteria."); #endregion }