public void MSOXORULE_S02_TC13_ServerExecuteRule_Action_OP_MOVE_FolderInThisStore() { this.CheckMAPIHTTPTransportSupported(); #region Prepare value for ruleProperties variable. RuleProperties ruleProperties = AdapterHelper.GenerateRuleProperties(this.Site, Constants.RuleNameMoveOne); #endregion #region TestUser1 creates folder1 in server store. RopCreateFolderResponse createFolderResponse; uint newFolderHandle = this.OxoruleAdapter.RopCreateFolder(this.InboxFolderHandle, Common.GenerateResourceName(this.Site, "User1Folder01"), "TestForOP_MOVE", out createFolderResponse); ulong newFolderId = createFolderResponse.FolderId; Site.Assert.AreEqual<uint>(0, createFolderResponse.ReturnValue, "Creating folder operation should succeed."); #endregion #region Prepare rules' data MoveCopyActionData moveCopyActionData = new MoveCopyActionData(); // Get the created folder1 entry id. ServerEID serverEID = new ServerEID(BitConverter.GetBytes(newFolderId)); byte[] folder1EId = serverEID.Serialize(); // Get the store object's entry id byte[] storeEId = this.GetStoreObjectEntryID(StoreObjectType.Mailbox, this.Server, this.User1ESSDN); moveCopyActionData.FolderInThisStore = 1; moveCopyActionData.FolderEID = folder1EId; moveCopyActionData.StoreEID = storeEId; moveCopyActionData.FolderEIDSize = (ushort)folder1EId.Length; moveCopyActionData.StoreEIDSize = (ushort)storeEId.Length; IActionData[] moveCopyAction = { moveCopyActionData }; #endregion #region Generate test RuleData. // Add rule for move without rule Provider Data. ruleProperties.ProviderData = string.Empty; RuleData ruleForMoveFolder = AdapterHelper.GenerateValidRuleDataWithFlavor(new ActionType[] { ActionType.OP_MOVE }, 0, RuleState.ST_ENABLED, moveCopyAction, new uint[] { 0 }, ruleProperties); #endregion #region TestUser1 adds OP_MOVE rule to the Inbox folder. RopModifyRulesResponse modifyRulesResponse = this.OxoruleAdapter.RopModifyRules(this.InboxFolderHandle, ModifyRuleFlag.Modify_ReplaceAll, new RuleData[] { ruleForMoveFolder }); Site.Assert.AreEqual<uint>(0, modifyRulesResponse.ReturnValue, "Adding Move rule should succeed."); #endregion #region TestUser2 delivers a message to TestUser1 to trigger the rule. // TestUser2 deliver a message to trigger the rule. string mailSubject = Common.GenerateResourceName(this.Site, ruleProperties.ConditionSubjectName + "Title"); this.SUTAdapter.SendMailToRecipient(this.User2Name, this.User2Password, this.User1Name, mailSubject); // Wait for the mail to be received and the rule to take effect. Thread.Sleep(this.WaitForTheRuleToTakeEffect); #endregion #region TestUser1 gets the message content to verify the rule evaluation. uint inboxFolderContentsTableHandle = 0; PropertyTag[] propertyTagList = new PropertyTag[1]; propertyTagList[0].PropertyId = (ushort)PropertyId.PidTagSubject; propertyTagList[0].PropertyType = (ushort)PropertyType.PtypString; bool doesOriginalMessageExist = this.CheckUnexpectedMessageExist(this.InboxFolderHandle, ref inboxFolderContentsTableHandle, propertyTagList, mailSubject); uint newFolder1ContentsTableHandle = 0; uint rowCount = 0; RopQueryRowsResponse getNewFolder1MailMessageContent = this.GetExpectedMessage(newFolderHandle, ref newFolder1ContentsTableHandle, propertyTagList, ref rowCount, 1, mailSubject); Site.Assert.IsFalse(doesOriginalMessageExist, "The original message shouldn't exist anymore."); Site.Assert.AreEqual<uint>(0, getNewFolder1MailMessageContent.ReturnValue, "getNewFolder1MailMessageContent should succeed."); // Add the debug information this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R956"); // Verify MS-OXORULE requirement: MS-OXORULE_R956 // Since the destination folder is created in the user's mailbox, if the Email can be found in the destination folder, MS-OXORULE_R956 can be verified. this.Site.CaptureRequirementIfAreNotEqual<uint>( 0, getNewFolder1MailMessageContent.RowCount, 956, @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Standard Rules] The destination folder for a Move action in a standard rule can be in the user's mailbox."); #endregion if (Common.IsRequirementEnabled(294, this.Site)) { #region TestUser1 gets a rule table. RopGetRulesTableResponse ropGetRulesTableResponse; uint ruleTableHandle = this.OxoruleAdapter.RopGetRulesTable(this.InboxFolderHandle, TableFlags.Normal, out ropGetRulesTableResponse); Site.Assert.AreEqual<uint>(0, ropGetRulesTableResponse.ReturnValue, "Getting rule table should succeed."); #endregion #region TestUser1 retrieves rule information to check if the rule exists. PropertyTag[] propertyTags = new PropertyTag[2]; propertyTags[0].PropertyId = (ushort)PropertyId.PidTagRuleName; propertyTags[0].PropertyType = (ushort)PropertyType.PtypString; propertyTags[1].PropertyId = (ushort)PropertyId.PidTagRuleActions; propertyTags[1].PropertyType = (ushort)PropertyType.PtypRuleAction; // Retrieves rows from the rule table. RopQueryRowsResponse queryRowResponse = this.OxoruleAdapter.QueryPropertiesInTable(ruleTableHandle, propertyTags); Site.Assert.AreEqual<uint>(0, queryRowResponse.ReturnValue, "Retrieving rows from the rule table should succeed."); MoveCopyActionData moveActionDataOfQueryRowsResponse = new MoveCopyActionData(); RuleAction ruleAction = new RuleAction(); for (int i = 0; i < queryRowResponse.RowCount; i++) { System.Text.UnicodeEncoding converter = new UnicodeEncoding(); string ruleName = converter.GetString(queryRowResponse.RowData.PropertyRows.ToArray()[i].PropertyValues[0].Value); if (ruleName == ruleProperties.Name + "\0") { // Verify structure RuleAction ruleAction.Deserialize(queryRowResponse.RowData.PropertyRows[i].PropertyValues[1].Value); moveActionDataOfQueryRowsResponse.Deserialize(ruleAction.Actions[0].ActionDataValue.Serialize()); break; } } #region Capture Code // Add the debug information this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R736"); ServerEID serverEIDOfResponse = new ServerEID(new byte[] { }); serverEIDOfResponse.Deserialize(moveActionDataOfQueryRowsResponse.FolderEID); bool isVerifiedR736 = moveActionDataOfQueryRowsResponse.FolderInThisStore == 0x01 && serverEIDOfResponse.FolderID != null && serverEIDOfResponse.MessageID != null && serverEIDOfResponse.Instance != null; // Verify MS-OXORULE requirement: MS-OXORULE_R736 this.Site.CaptureRequirementIfIsTrue( isVerifiedR736, 736, @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Standard Rules] If the value of the FolderInThisStore field is 0x01, this field [FolderEID] contains a ServerEid structure, as specified in section 2.2.5.1.2.1.1. "); FolderID folderId = new FolderID(); folderId.Deserialize(BitConverter.ToUInt64(serverEIDOfResponse.FolderID, 0)); // Add the debug information this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R983"); bool isVerifiedR983 = folderId.ReplicaId != null && folderId.GlobalCounter != null; // Verify MS-OXORULE requirement: MS-OXORULE_R983 this.Site.CaptureRequirementIfIsTrue( isVerifiedR983, 983, @"[In ServerEid Structure] FolderId (8 bytes): A Folder ID structure, as specified in [MS-OXCDATA] section 2.2.1.1, identifies the destination folder."); if (Common.IsRequirementEnabled(7032, this.Site)) { // Add the debug information this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R7032"); bool isVerifiedR703 = moveActionDataOfQueryRowsResponse.FolderInThisStore == 0x01 && getNewFolder1MailMessageContent.RowCount != 0; // Verify MS-OXORULE requirement: MS-OXORULE_R7032 this.Site.CaptureRequirementIfIsTrue( isVerifiedR703, 7032, @"[In Appendix A: Product Behavior] Implementation does set this field (FolderInThisStore) to 0x01 if the destination folder is in the user's mailbox. (Exchange 2007 and Exchange 2016 follow this behavior)."); } #endregion #endregion } #region Delete the newly created folder. RopDeleteFolderResponse deleteFolder = this.OxoruleAdapter.RopDeleteFolder(this.InboxFolderHandle, newFolderId); Site.Assert.AreEqual<uint>(0, deleteFolder.ReturnValue, "Deleting folder should succeed."); #endregion }
/// <summary> /// Verify RuleAction buffer for stand rule. /// </summary> /// <param name="ruleAction">RuleAction structure to be verified.</param> private void VerifyRuleAction(RuleAction ruleAction) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R232, The value of NoOfActions is {0}", ruleAction.NoOfActions); // Verify MS-OXORULE requirement: MS-OXORULE_R232. // NoOfActions can be either unsigned-integer or unsigned-short. uint actionsNumber = (ruleAction.NoOfActions is uint) ? ((uint)ruleAction.NoOfActions) : ((ushort)ruleAction.NoOfActions); bool isVerifyR232 = actionsNumber > 0; Site.CaptureRequirementIfIsTrue( isVerifyR232, 232, @"[In RuleAction Structure] NoOfActions (2 bytes): This number MUST be greater than zero."); foreach (ActionBlock actionBlock in ruleAction.Actions) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R236"); // Verify MS-OXORULE requirement: MS-OXORULE_R236. // There are 2 or 4 bytes of the ActionLength in the ActionBlocks, // so the cumulative length in bytes of the subsequent fields of the ActionLength must equal to the length of ActionBlock.length - lengthOfActionLength. int lengthOfActionLength = actionBlock.ActionLength is ushort ? 2 : 4; bool isVerifyR236 = (actionBlock.ActionLength is ushort ? (ushort)actionBlock.ActionLength : (uint)actionBlock.ActionLength) == (actionBlock.Serialize().Length - lengthOfActionLength); Site.CaptureRequirementIfIsTrue( isVerifyR236, 236, @"[In ActionBlock Structure] ActionLength (2 bytes): An integer that specifies the cumulative length, in bytes, of the subsequent fields in this ActionBlock structure."); // Verify MS-OXORULE requirement: MS-OXORULE_R947. bool isVerifyR947 = (byte)actionBlock.ActionType == 0x01 || (byte)actionBlock.ActionType == 0x02 || (byte)actionBlock.ActionType == 0x03 || (byte)actionBlock.ActionType == 0x04 || (byte)actionBlock.ActionType == 0x05 || (byte)actionBlock.ActionType == 0x06 || (byte)actionBlock.ActionType == 0x07 || (byte)actionBlock.ActionType == 0x08 || (byte)actionBlock.ActionType == 0x09 || (byte)actionBlock.ActionType == 0x0A || (byte)actionBlock.ActionType == 0x0B; Site.CaptureRequirementIfIsTrue( isVerifyR947, 947, @"[In RuleAction Structure] ActionBlocks (variable): An array of ActionBlock structures, each of which specifies an action (2) of the rule (2), as specified in section 2.2.5.1."); } // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R231"); // Verify MS-OXORULE requirement: MS-OXORULE_R231. Site.CaptureRequirementIfAreEqual<uint>( (uint)ruleAction.Actions.Length, actionsNumber, 231, @"[In RuleAction Structure] NoOfActions (2 bytes): Specifies the number of structures that are contained in the ActionBlocks field."); // isVerifyR274 is used to verify R274 and R272. bool isVerifyR274 = false; // isVerifyR287 is used to verify R287 and R272. bool isVerifyR287 = false; // isVerifyR879 is used to verify R879 and R272. bool isVerifyR879 = false; for (int i = 0; i < ruleAction.Actions.Length; i++) { ActionBlock actionBlock = ruleAction.Actions[i]; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R245", "The value of the actionBlock.ActionType{0} should be one of 0x01 to 0x0b", actionBlock.ActionType); // Verify MS-OXORULE requirement: MS-OXORULE_R245. bool isVerifyR245 = (byte)actionBlock.ActionType == 0x01 || (byte)actionBlock.ActionType == 0x02 || (byte)actionBlock.ActionType == 0x03 || (byte)actionBlock.ActionType == 0x04 || (byte)actionBlock.ActionType == 0x05 || (byte)actionBlock.ActionType == 0x06 || (byte)actionBlock.ActionType == 0x07 || (byte)actionBlock.ActionType == 0x08 || (byte)actionBlock.ActionType == 0x09 || (byte)actionBlock.ActionType == 0x0A || (byte)actionBlock.ActionType == 0x0B; Site.CaptureRequirementIfIsTrue( isVerifyR245, 245, @"[In ActionBlock Structure] The valid actions (2) [of ActionType] are listed in the following table: OP_MOVE, OP_COPY, OP_REPLY, OP_OOF_REPLY, OP_DEFER_ACTION, OP_BOUNCE, OP_FORWARD, OP_DELEGATE, OP_TAG, OP_DELETE, OP_MARK_AS_READ."); if ((actionBlock.ActionType == ActionType.OP_MOVE) || (actionBlock.ActionType == ActionType.OP_COPY)) { MoveCopyActionData moveCopyActionData = (MoveCopyActionData)actionBlock.ActionDataValue; ServerEID serverEID = new ServerEID(moveCopyActionData.FolderEID); // The storeObjectEntryID structure could only verified in ExchangeServer2007, R632 also only executed in ExchangeServer2007. if (Common.IsRequirementEnabled(632, this.Site)) { StoreObjectEntryID storeObjectEntryID = new StoreObjectEntryID(); storeObjectEntryID.Deserialize(moveCopyActionData.StoreEID); this.VerifyStoreObjectEntryID(storeObjectEntryID); } // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R982: the value of Ours is {0}", serverEID.Ours); // Verify MS-OXORULE_R982. Site.CaptureRequirementIfAreEqual<ushort>( 0x01, serverEID.Ours, 982, @"[In ServerEid Structure] Ours (1 byte): This field MUST be set to 0x01."); // Add the debug information this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R980"); // Verify MS-OXORULE requirement: MS-OXORULE_R980 // Verify MS-OXORULE_R982 has verified the value of Ours is 0x01, MS-OXORULE_R980 verifies the instance's type. this.Site.CaptureRequirementIfIsInstanceOfType( serverEID, typeof(ServerEID), 980, @"[In ServerEid Structure] Ours (1 byte): The value 0x01 indicates that the remaining bytes conform to this structure [ServerEid]."); if (moveCopyActionData.StoreEIDSize != 0) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R297"); // Verify MS-OXORULE_R297. Site.CaptureRequirementIfAreEqual<ushort>( (ushort)moveCopyActionData.StoreEID.Length, moveCopyActionData.StoreEIDSize, 297, @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Standard Rules] StoreEIDSize (2 bytes): An integer that specifies the size, in bytes, of the StoreEID field."); } // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R300"); // Verify MS-OXORULE_R300. Site.CaptureRequirementIfAreEqual<ushort>( (ushort)moveCopyActionData.FolderEID.Length, moveCopyActionData.FolderEIDSize, 300, @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Standard Rules] FolderEIDSize (2 bytes): An integer that specifies the size, in bytes, of the FolderEID field."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R294"); // Verify MS-OXORULE_R294. // The structure of the OP_MOVE Action Date Buffer is verified by the requirements MS-OXORULE_R297, MS-OXORULE_R298, MS-OXORULE_R300, and MS-OXORULE_R301. Site.CaptureRequirement( 294, @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Standard Rules] The OP_MOVE ActionData structure MUST be in the following format for a standard rule. [FolderInThisStore, StoreEIDSize, StoreEID, FolderEIDSize, and FolderEID]."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R880"); // Verify MS-OXORULE_R880. // The structure of the OP_MOVE Action Date Buffer is verified by the requirements MS-OXORULE_R297, MS-OXORULE_R298, MS-OXORULE_R300, and MS-OXORULE_R301. Site.CaptureRequirement( 880, @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Standard Rules] The OP_COPY ActionData structure MUST be in the following format for a standard rule. [FolderInThisStore, StoreEIDSize, StoreEID, FolderEIDSize, and FolderEID]."); } if (actionBlock.ActionType == ActionType.OP_COPY) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R249"); // Verify MS-OXORULE requirement: MS-OXORULE_R249. // If the ActionType of the actionBlock equals the value ActionType.OP_COPY means server could parse the ActionType 0x02. Site.CaptureRequirement( 249, @"[In ActionBlock Structure] The value of action type OP_COPY: 0x02."); } if (actionBlock.ActionType == ActionType.OP_MOVE) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R246"); // Verify MS-OXORULE requirement: MS-OXORULE_R246. // If the ActionType of the actionBlock equals the value ActionType.OP_MOVE means server could parse the ActionType 0x01. Site.CaptureRequirement( 246, @"[In ActionBlock Structure] The value of action type OP_MOVE: 0x01."); } if (actionBlock.ActionType == ActionType.OP_FORWARD) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R261"); // Verify MS-OXORULE requirement: MS-OXORULE_R261. // If the ActionType of the actionBlock equals the value ActionType.OP_FORWARD means server could parse the ActionType 0x07. Site.CaptureRequirement( 261, @"[In ActionBlock Structure] The value of action type OP_FORWARD: 0x07."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R274, the value of ActionFlavor is {0}, the ActionFlavorsForward.x is {1}.", actionBlock.ActionFlavor, ActionFlavorsForward.x); // Verify MS-OXORULE requirement: MS-OXORULE_R274. // In ActionFlavor, the not used Flags must not be set, the used Flags can be set or all the bits are not set, it means ActionFlavor is set according to the description in this requirement. isVerifyR274 = (actionBlock.ActionFlavor & (uint)ActionFlavorsForward.x) == 0; Site.CaptureRequirementIfIsTrue( isVerifyR274, 274, @"[In Action Flavors] If the value of the ActionType field is ""OP_FORWARD"", the ActionFlavor field contains a combination of the bitwise flags [XXXX (TM) (AT) (NC) (PR) XXXXXXXXXXXXXXXXXXXXXXXXXX] specified as follows."); } if ((actionBlock.ActionType == ActionType.OP_REPLY) || (actionBlock.ActionType == ActionType.OP_OOF_REPLY)) { ReplyActionData actionData = new ReplyActionData(); actionData.Deserialize(ruleAction.Actions[0].ActionDataValue.Serialize()); if (actionBlock.ActionType == ActionType.OP_REPLY) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R287, the value of ActionFlavor is {0}, it should be one of ActionFlavorsReply.NS({1}), ActionFlavorsReply.ST({2}), or 0x00000000", actionBlock.ActionFlavor, ActionFlavorsReply.NS, ActionFlavorsReply.ST); // Verify MS-OXORULE requirement: MS-OXORULE_R287. // According to open specification, in this condition, the allowed value of ActionFlavor are NS, ST and 0x00000000. isVerifyR287 = (actionBlock.ActionFlavor == (uint)ActionFlavorsReply.NS) || (actionBlock.ActionFlavor == (uint)ActionFlavorsReply.ST) || (actionBlock.ActionFlavor == 0x00000000); Site.CaptureRequirementIfIsTrue( isVerifyR287, 287, @"[In Action Flavors] If the ActionType field value is ""OP_REPLY"", the ActionFlavor field MUST have one of the values specified in the following table [XXXXXX (ST) (NS) XXXXXXXXXXXXXXXXXXXXXXXX] or zero (0x00000000)."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R252"); // Verify MS-OXORULE requirement: MS-OXORULE_R252. // If the ActionType of the actionBlock equals the value ActionType.OP_REPLY means server could parse the ActionType 0x03. Site.CaptureRequirement( 252, @"[In ActionBlock Structure] The value of action type OP_REPLY: 0x03."); bool isVerifyR992 = actionData.ReplyTemplateGUID.Length != 0 && actionData.ReplyTemplateFID != 0 && actionData.ReplyTemplateMID != 0; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R992"); // Verify MS-OXORULE requirement: MS-OXORULE_R992. // If ReplyTemplateFID, ReplyTemplateMID, ReplyTemplateGUID in the ActionData is not null, R992 can be verified. Site.CaptureRequirementIfIsTrue( isVerifyR992, 992, @"[OP_REPLY and OP_OOF_REPLY ActionData Structure] [Buffer Format for Standard Rules] The OP_REPLY ActionData structure MUST be in the following format for a standard rule. [ReplyTemplateFID, ReplyTemplateMID, ReplyTemplateGUID]"); } ReplyActionData replyActionData = (ReplyActionData)actionBlock.ActionDataValue; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R308"); // Verify MS-OXORULE requirement: MS-OXORULE_R308. Site.CaptureRequirementIfIsTrue( Common.IsGUID(replyActionData.ReplyTemplateGUID), 308, @"[OP_REPLY and OP_OOF_REPLY ActionData Structure] [Buffer Format for Standard Rules] ReplyTemplateGUID (16 bytes): A GUID that is generated by the client in the process of creating a reply template."); if (actionBlock.ActionType == ActionType.OP_OOF_REPLY) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R879, the value of ActionFlavor is {0}", "it should be one of ActionFlavorsReply.NS({1}), ActionFlavorsReply.ST({2}), or 0x00000000", actionBlock.ActionFlavor, ActionFlavorsReply.NS, ActionFlavorsReply.ST); // Verify MS-OXORULE requirement: MS-OXORULE_R879. // According to open specification, in this condition, the allowed value of ActionFlavor are NS, ST and 0x00000000. isVerifyR879 = (actionBlock.ActionFlavor == (uint)ActionFlavorsReply.NS) || (actionBlock.ActionFlavor == (uint)ActionFlavorsReply.ST) || (actionBlock.ActionFlavor == 0x00000000); Site.CaptureRequirementIfIsTrue( isVerifyR879, 879, @"[In Action Flavors] If the ActionType field value is ""OP_OOF_REPLY"", the ActionFlavor field MUST have one of the values specified in the following table [XXXXXX (ST) (NS) XXXXXXXXXXXXXXXXXXXXXXXX] or zero (0x00000000). "); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R254"); // Verify MS-OXORULE requirement: MS-OXORULE_R254. // If the ActionType of the actionBlock equals the value ActionType. OP_OOF_REPLY means server could parse the ActionType and its value must be 0x04. Site.CaptureRequirement( 254, @"[In ActionBlock Structure] The value of action type OP_OOF_REPLY: 0x04."); bool isVerifyR993 = actionData.ReplyTemplateGUID.Length != 0 && actionData.ReplyTemplateFID != 0 && actionData.ReplyTemplateMID != 0; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R993"); // Verify MS-OXORULE requirement: MS-OXORULE_R993. // If ReplyTemplateFID, ReplyTemplateMID, ReplyTemplateGUID in the ActionData is not null, R993 can be verified. Site.CaptureRequirementIfIsTrue( isVerifyR993, 993, @"[OP_REPLY and OP_OOF_REPLY ActionData Structure] [Buffer Format for Standard Rules] The OP_OOF_REPLY ActionData structure MUST be in the following format for a standard rule. [ReplyTemplateFID, ReplyTemplateMID, ReplyTemplateGUID]"); } FolderID folderID = new FolderID(); folderID.Deserialize(replyActionData.ReplyTemplateFID); if (folderID != null) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R2175"); // Verify MS-OXCDATA requirement: MS-OXCDATA_R2175. Site.CaptureRequirementIfAreEqual<int>( 8, folderID.Size, "MS-OXCDATA", 2175, @"[In Folder ID Structure] It [Folder ID] is an 8-byte structure."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R2176"); // Verify MS-OXCDATA requirement: MS-OXCDATA_R2176. // "Identifying a Store object" is informative. Site.CaptureRequirementIfAreEqual<int>( 2, folderID.ReplicaId.Length, "MS-OXCDATA", 2176, @"[In Folder ID Structure] ReplicaId (2 bytes): An unsigned integer identifying a Store object."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R2177"); // Verify MS-OXCDATA requirement: MS-OXCDATA_R2177. // "Identifying the folder within its Store object" is informative. Site.CaptureRequirementIfAreEqual<int>( 6, folderID.GlobalCounter.Length, "MS-OXCDATA", 2177, @"[In Folder ID Structure] GlobalCounter (6 bytes): An unsigned integer identifying the folder within its Store object."); } MessageID messageID = new MessageID(); messageID.Deserialize(replyActionData.ReplyTemplateMID); if (messageID != null) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R2180"); // Verify MS-OXCDATA requirement: MS-OXCDATA_R2180. Site.CaptureRequirementIfAreEqual<int>( 8, messageID.Size, "MS-OXCDATA", 2180, @"[In Message ID Structure] It [Message ID] is an 8-byte structure."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R2181"); // Verify MS-OXCDATA requirement: MS-OXCDATA_R2181. // "Identifying a Store object" is informative. Site.CaptureRequirementIfAreEqual<int>( 2, messageID.ReplicaId.Length, "MS-OXCDATA", 2181, @"[In Message ID Structure] ReplicaId (2 bytes): An unsigned integer identifying a Store object."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R2182"); // Verify MS-OXCDATA requirement: MS-OXCDATA_R2182. // "Identifying the message within its Store object" is informative. Site.CaptureRequirementIfAreEqual<int>( 6, messageID.GlobalCounter.Length, "MS-OXCDATA", 2182, @"[In Message ID Structure] GlobalCounter (6 bytes): An unsigned integer identifying the message within its Store object."); } } if (actionBlock.ActionType == ActionType.OP_DEFER_ACTION) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R256"); // Verify MS-OXORULE requirement: MS-OXORULE_R256. // If the ActionType of the actionBlock equals the value ActionType.OP_DEFER_ACTION means server could parse the ActionType 0x05. Site.CaptureRequirement( 256, @"[In ActionBlock Structure] The value of action type OP_DEFER_ACTION: 0x05."); } if (actionBlock.ActionType == ActionType.OP_TAG) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R265"); // Verify MS-OXORULE requirement: MS-OXORULE_R265. // If the ActionType of the actionBlock equals the value ActionType.OP_TAG means server could parse the ActionType 0x09. Site.CaptureRequirement( 265, @"[In ActionBlock Structure] The value of action type OP_TAG: 0x09."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R739"); // Verify MS-OXORULE requirement: MS-OXORULE_R739. // If the taggedPropertyValueOP_TAG is not null means the action data buffer can be parsed by the TaggedPropertyValue. TaggedPropertyValue taggedPropertyValueOP_Tag = AdapterHelper.ReadTaggedProperty(actionBlock.ActionDataValue.Serialize()); Site.CaptureRequirementIfIsNotNull( taggedPropertyValueOP_Tag, 739, @"[In OP_TAG ActionData Structure] An OP_TAG ActionData structure is a TaggedPropertyValue structure, packaged as specified in [MS-OXCDATA] section 2.11.4."); } if ((actionBlock.ActionType == ActionType.OP_FORWARD) || (actionBlock.ActionType == ActionType.OP_REPLY) || (actionBlock.ActionType == ActionType.OP_OOF_REPLY)) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R272", "The value of the ActionFlavor is {0}, and the ActionType is {1}", actionBlock.ActionFlavor, actionBlock.ActionType); // Verify MS-OXORULE requirement: MS-OXORULE_R272. // According to open specification, the only action types that support the Action Flavor are OP_REPLY, OP_OOF_REPLY and OP_FORWARD. // The setting of ActionFlavor is verified in R274 and R287, so the condition to verify R272 is "isVerifyR274 || isVerifyR287". Site.CaptureRequirementIfIsTrue( isVerifyR274 || isVerifyR287 || isVerifyR879, 272, @"[In Action Flavors] The only ActionType field values that currently support an Action Flavor are ""OP_REPLY"", ""OP_OOF_REPLY"" and ""OP_FORWARD""."); } else { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R273"); // Verify MS-OXORULE requirement: MS-OXORULE_R273. Site.CaptureRequirementIfAreEqual<uint>( 0, actionBlock.ActionFlavor, 273, @"[In Action Flavors] The value of the ActionFlavor field MUST be 0x00000000 if the value of the ActionType field is not one of these values [OP_REPLY, OP_OOF_REPLY, and OP_FORWARD]."); } // When the AT flag in ActionFlavor is set. if ((actionBlock.ActionFlavor & (uint)ActionFlavorsForward.AT) == (uint)ActionFlavorsForward.AT) { // Verify MS-OXORULE requirement: MS-OXORULE_R280. uint otherActionFlavorFlags = (uint)ActionFlavorsForward.PR | (uint)ActionFlavorsForward.NC | (uint)ActionFlavorsForward.TM | (uint)ActionFlavorsForward.x; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R280, the value of ActionFlavor is {0}, this value should not be combined with otherActionFlavorFlags({1}).", actionBlock.ActionFlavor, otherActionFlavorFlags); // To verify whether the other ActionFlavor Flags are 0 when the AT flag in ActionFlavor is set. bool isVerifyR280 = (actionBlock.ActionFlavor & otherActionFlavorFlags) == 0; Site.CaptureRequirementIfIsTrue( isVerifyR280, 280, @"[In Action Flavors] AT (Bitmask 0x00000004): This value MUST NOT be combined with other ActionFlavor flags."); } // When the TM flag in ActionFlavor is set. if ((actionBlock.ActionFlavor & (uint)ActionFlavorsForward.TM) == (uint)ActionFlavorsForward.TM) { // Verify MS-OXORULE requirement: MS-OXORULE_R283. uint otherActionFlavorFlags = (uint)ActionFlavorsForward.PR | (uint)ActionFlavorsForward.NC | (uint)ActionFlavorsForward.AT | (uint)ActionFlavorsForward.x; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R283, the value of ActionFlavor is {0}, this value should not be combined with otherActionFlavorFlags({1}).", actionBlock.ActionFlavor, otherActionFlavorFlags); // To verify whether the other ActionFlavor Flags are 0 when the TM flag in ActionFlavor is set. bool isVerifyR283 = (actionBlock.ActionFlavor & otherActionFlavorFlags) == 0; Site.CaptureRequirementIfIsTrue( isVerifyR283, 283, @"[In Action Flavors] TM (Bitmask 0x00000008): This value MUST NOT be combined with other ActionFlavor flags."); } if (actionBlock.ActionType == ActionType.OP_FORWARD && Common.IsRequirementEnabled(636, this.Site)) { ForwardDelegateActionData forwardOrDelegateData = (ForwardDelegateActionData)actionBlock.ActionDataValue; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R636"); // Verify MS-OXORULE requirement: MS-OXORULE_R636. bool isVerifyR636 = true; foreach (RecipientBlock recipientBlock in forwardOrDelegateData.RecipientsData) { // Whether the PidTagEntryId exists. bool hasPidTagEntryId = false; foreach (TaggedPropertyValue property in recipientBlock.PropertiesData) { // propertyID of PidTagEntryId is 0x0FFF. if (property.PropertyTag.PropertyId == 0x0FFF) { hasPidTagEntryId = true; } } if (!hasPidTagEntryId) { isVerifyR636 = false; break; } } Site.CaptureRequirementIfIsTrue( isVerifyR636, 636, @"[In Appendix A: Product Behavior] Implementation does require the PidTagEntryId property for action ""OP_FORWARD"". [<8> Section 2.2.5.1.2.4.1: Exchange 2003 and Exchange 2007 also require the PidTagEntryId property for action ""OP_FORWARD"".]"); } if ((actionBlock.ActionType == ActionType.OP_FORWARD) || (actionBlock.ActionType == ActionType.OP_DELEGATE)) { if (actionBlock.ActionType == ActionType.OP_DELEGATE) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R263"); // Verify MS-OXORULE requirement: MS-OXORULE_R263. // If the ActionType of the actionBlock equals the value ActionType.DELEGATE means server could parse the ActionType 0x08. Site.CaptureRequirement( 263, @"[In ActionBlock Structure] The value of action type OP_DELEGATE: 0x08."); } ForwardDelegateActionData forwardOrDelegateData = (ForwardDelegateActionData)actionBlock.ActionDataValue; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R323, the recipient count is {0}.", forwardOrDelegateData.RecipientCount); // Verify MS-OXORULE requirement: MS-OXORULE_R323. bool isVerifyR323 = (forwardOrDelegateData.RecipientCount is ushort ? (ushort)forwardOrDelegateData.RecipientCount : (uint)forwardOrDelegateData.RecipientCount) == forwardOrDelegateData.RecipientsData.Length; Site.CaptureRequirementIfIsTrue( isVerifyR323, 323, @"[In OP_FORWARD and OP_DELEGATE ActionData Structure] RecipientCount (4 bytes): An integer that specifies the number of RecipientBlockData structures, as specified in section 2.2.5.1.2.4.1, contained in the RecipientBlocks field. "); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R324", "The value of the RecipientCount is {0}, it should greater than 0.", forwardOrDelegateData.RecipientCount); // Verify MS-OXORULE requirement: MS-OXORULE_R324. // The RecipientCount can be either unsigned-integer or unsigned-short. uint recipientCount = (forwardOrDelegateData.RecipientCount is uint) ? ((uint)forwardOrDelegateData.RecipientCount) : ((ushort)forwardOrDelegateData.RecipientCount); bool isVerifyR324 = recipientCount > 0; Site.CaptureRequirementIfIsTrue( isVerifyR324, 324, @"[In OP_FORWARD and OP_DELEGATE ActionData Structure] RecipientCount (4 bytes): This number MUST be greater than zero."); bool isVerifyR633 = true; bool isVerifyR632 = true; bool isVerifyR331 = true; foreach (RecipientBlock recipientBlock in forwardOrDelegateData.RecipientsData) { if (Common.IsRequirementEnabled(633, this.Site)) { if (recipientBlock.Reserved != 0x00) { isVerifyR633 = false; break; } } if (Common.IsRequirementEnabled(632, this.Site)) { if (recipientBlock.Reserved != 0x01) { isVerifyR632 = false; break; } } // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R330, the NoOfProperties of the RecipientBlock is {0}.", recipientBlock.NoOfProperties); // Verify MS-OXORULE requirement: MS-OXORULE_R330. bool isVerifyR330 = (recipientBlock.NoOfProperties is ushort ? (ushort)recipientBlock.NoOfProperties : (uint)recipientBlock.NoOfProperties) == (ulong)recipientBlock.PropertiesData.Length; Site.CaptureRequirementIfIsTrue( isVerifyR330, 330, @"[In RecipientBlockData Structure] NoOfProperties (4 bytes): An integer that specifies the number of structures present in the PropertyValues field."); TaggedPropertyValue[] taggedPropertyValue = recipientBlock.PropertiesData; bool isVerifyR468 = taggedPropertyValue[0].PropertyTag.PropertyId != 0 && taggedPropertyValue[0].PropertyTag.PropertyType != 0; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R468"); // Verify MS-OXCDATA requirement: MS-OXCDATA_R468. Site.CaptureRequirementIfIsTrue( isVerifyR468, "MS-OXCDATA", 468, @"[In TaggedPropertyValue Structure] PropertyTag (4 bytes): A PropertyTag structure, as specified in section 2.9, giving the values of the PropertyId and PropertyType fields for the property."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R469"); PropertyValue propertyValue = (PropertyValue)taggedPropertyValue[0]; // Verify MS-OXCDATA requirement: MS-OXCDATA_R469. Site.CaptureRequirementIfIsInstanceOfType( propertyValue, typeof(PropertyValue), "MS-OXCDATA", 469, @"[In TaggedPropertyValue Structure] PropertyValue (variable): A PropertyValue structure, as specified in section 2.11.2.1."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R1008"); // Verify MS-OXORULE requirement: MS-OXORULE_R1008. // The format of the TaggedPropertyValue structure has been verified by MS-OXCDATA_R468, and MS-OXCDATA_R469. Site.CaptureRequirement( 1008, @"[In RecipientBlockData Structure] The format of the TaggedPropertyValue structure is specified in [MS-OXCDATA] section 2.11.4."); // Verify MS-OXORULE requirement: MS-OXORULE_R331. uint properties = (recipientBlock.NoOfProperties is uint) ? ((uint)recipientBlock.NoOfProperties) : ((ushort)recipientBlock.NoOfProperties); if (properties <= 0) { isVerifyR331 = false; break; } } if (Common.IsRequirementEnabled(633, this.Site)) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R633"); Site.CaptureRequirementIfIsTrue( isVerifyR633, 633, @"[[In Appendix A: Product Behavior] Implementation does set this value [Reserved (1 byte)] to 0x00. [<9> Section 2.2.5.1.2.4.1: Exchange 2010, Exchange 2013, and Exchange 2016 set this value to 0x00.]"); } if (Common.IsRequirementEnabled(632, this.Site)) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R632"); Site.CaptureRequirementIfIsTrue( isVerifyR632, 632, @"[In Appendix A: Product Behavior] Implementation does set this value [Reserved (1 byte)] to 0x01. [<9> Section 2.2.5.1.2.4.1: Exchange 2003 and Exchange 2007 set this value to 0x01.]"); } // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R331"); // Verify MS-OXORULE requirement: MS-OXORULE_R331. Site.CaptureRequirementIfIsTrue( isVerifyR331, 331, @"[In RecipientBlockData Structure] NoOfProperties (4 bytes): This number MUST be greater than zero."); if (Common.IsRequirementEnabled(895, this.Site)) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R895"); // Verify requirement: MS-OXORULE_R895. bool isVerifyR895 = true; foreach (RecipientBlock recipientBlock in forwardOrDelegateData.RecipientsData) { // Whether the PidTagDisplayName exists. bool hasPidTagDisplayName = false; // Whether the PidTagEmailAddress exists. bool hasPidTagEmailAddress = false; // Whether the PidTagRecipientType exists. bool hasPidTagRecipientType = false; foreach (TaggedPropertyValue property in recipientBlock.PropertiesData) { // propertyID of hasPidTagDisplayName is 0x3001. if (property.PropertyTag.PropertyId == 0x3001) { hasPidTagDisplayName = true; } // propertyID of PidTagEmailAddress is 0x3003. if (property.PropertyTag.PropertyId == 0x3003) { hasPidTagEmailAddress = true; } // propertyID of PidTagRecipientType is 0x0C15. if (property.PropertyTag.PropertyId == 0x0C15) { hasPidTagRecipientType = true; } } if (!(hasPidTagDisplayName && hasPidTagEmailAddress && hasPidTagRecipientType)) { isVerifyR895 = false; break; } } // Verify MS-OXORULE requirement: MS-OXORULE_R895. Site.CaptureRequirementIfIsTrue( isVerifyR895, 895, @"[In RecipientBlock Data Buffer Packet Structure] No rules (2) does require more [specify values for more properties besides the PidTagDisplayName, PidTagEmailAddress, and PidTagRecipientType in the forward/delegate ActionData buffer] on the implementation. (Exchange 2010 and above follow this behavior.)"); } } if (actionBlock.ActionType == ActionType.OP_BOUNCE) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R259"); // Verify MS-OXORULE requirement: MS-OXORULE_R259. // If the ActionType of the actionBlock equals the value ActionType.OP_COPY means server could parse the ActionType 0x06. Site.CaptureRequirement( 259, @"[In ActionBlock Structure] The value of action type OP_BOUNCE: 0x06."); BounceActionData bounceActionData = (BounceActionData)actionBlock.ActionDataValue; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R340", "The value of the BounceCode field is {0}.", bounceActionData.Bounce); // Verify MS-OXORULE requirement: MS-OXORULE_R340. bool isVerifyR340 = (uint)bounceActionData.Bounce == 0x0000000D || (uint)bounceActionData.Bounce == 0x0000001F || (uint)bounceActionData.Bounce == 0x00000026; Site.CaptureRequirementIfIsTrue( isVerifyR340, 340, @"[In OP_BOUNCE ActionData Structure] The bounce code MUST be one of the following values. [0x0000000D, 0x0000001F, and 0x00000026]."); } if ((actionBlock.ActionType == ActionType.OP_DELETE) || (actionBlock.ActionType == ActionType.OP_MARK_AS_READ)) { if (actionBlock.ActionType == ActionType.OP_DELETE) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R267"); // If the ActionType of the actionBlock equals the value ActionType.OP_MOVE means server could parse the ActionType 0x0A. Site.CaptureRequirement( 267, @"[In ActionBlock Structure] The value of action type OP_DELETE: 0x0A."); } if (actionBlock.ActionType == ActionType.OP_MARK_AS_READ) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R269"); // If the ActionType of the actionBlock equals the value ActionType.OP_COPY means server could parse the ActionType 0x0B. Site.CaptureRequirement( 269, @"[In ActionBlock Structure] The value of action type OP_MARK_AS_READ: 0x0B."); } // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R346"); // Verify MS-OXORULE requirement: MS-OXORULE_R346. // If the Size of ActionDataValue is 0, it means these actions have no ActionData buffer. Site.CaptureRequirementIfAreEqual<int>( 0, actionBlock.ActionDataValue.Size(), 346, @"[In OP_DELETE or OP_MARK_AS_READ ActionData Structure] These actions [OP_DELETE, OP_MARK_AS_READ] (3) have no ActionData structure."); } } }