/// <summary> /// Gets LongTermIds. /// </summary> /// <returns>A list of LongTermIds.</returns> public List<LongTermId> GetLongTermIds() { List<LongTermId> idlist = new List<LongTermId>(); if (this.globset != null && this.globset.GLOBCNTList != null) { List<GLOBCNT> cntList = this.globset.GLOBCNTList; for (int i = 0; i < cntList.Count; i++) { LongTermId lid = new LongTermId { DatabaseGuid = this.replguid.ToByteArray(), GlobalCounter = StructureSerializer.Serialize(cntList[i]) }; idlist.Add(lid); } } return idlist; }
/// <summary> /// Initializes a new instance of the FolderReplicaInfo structure. /// </summary> /// <param name="stream">A FastTransferStream.</param> public FolderReplicaInfo(FastTransferStream stream) { this.Flags = stream.ReadUInt32(); this.Depth = stream.ReadUInt32(); this.FolderLongTermId = new LongTermId { DatabaseGuid = stream.ReadGuid().ToByteArray(), GlobalCounter = new byte[6] }; stream.Read( this.FolderLongTermId.GlobalCounter, 0, this.FolderLongTermId.GlobalCounter.Length); stream.Read(new byte[2], 0, 2); this.ServerDNCount = stream.ReadUInt32(); this.CheapServerDNCount = stream.ReadUInt32(); this.ServerDNArray = new string[this.ServerDNCount]; for (int i = 0; i < this.ServerDNCount; i++) { this.ServerDNArray[i] = stream.ReadString8(); } }
/// <summary> /// Create values for SynchronizationImportHierarchyChange. /// </summary> /// <param name="serverId">server id.</param> /// <param name="folderIdIndex">Folder id index.</param> /// <param name="parentFolderHandleIndex">Parent folder handle index.</param> /// <param name="folderId">Folder id.</param> /// <param name="conflictType">Conflict type </param> /// <returns>Return the constructed hierarchy values.</returns> private TaggedPropertyValue[] CreateSampleHierarchyValues(int serverId, int folderIdIndex, int parentFolderHandleIndex, out ulong folderId, ConflictTypes conflictType) { folderId = 0; TaggedPropertyValue[] hierarchyValues = new TaggedPropertyValue[6]; TaggedPropertyValue propertyValue = new TaggedPropertyValue(); byte[] currentChangeNumber = new byte[6]; // PidTagParentSourceKey equal to the PidTagSourceKey of the parent folder propertyValue = new TaggedPropertyValue { PropertyTag = new PropertyTag(0x65E1, 0x0102) }; Sequence<string> propertyTag = new Sequence<string>("PidTagSourceKey"); this.GetPropertiesSpecific(serverId, parentFolderHandleIndex, propertyTag); propertyValue.Value = this.propertyValuesSpecific["PidTagSourceKey"]; hierarchyValues[0] = propertyValue; if (conflictType == ConflictTypes.NONE) { // Whether the hierarchy already exists. if (this.objectIdContainer.ContainsKey(folderIdIndex)) { // Construct PidTagSourceKey value. propertyValue = new TaggedPropertyValue { PropertyTag = new PropertyTag(0x65E0, 0x0102) }; byte[] sampleForPidTagSourceKey = this.propertyValuesSpecific["PidTagSourceKey"]; propertyValue.Value = sampleForPidTagSourceKey; hierarchyValues[1] = propertyValue; folderId = this.objectIdContainer[folderIdIndex]; // Construct PidTagLastModificationTime value. propertyValue = new TaggedPropertyValue { PropertyTag = new PropertyTag(0x3008, 0x0040) }; byte[] sampleForPidTagLastModificationTime = BitConverter.GetBytes(DateTime.Now.ToFileTimeUtc()); propertyValue.Value = sampleForPidTagLastModificationTime; hierarchyValues[2] = propertyValue; // Construct PidTagChangeKey value. propertyValue = new TaggedPropertyValue { PropertyTag = new PropertyTag(0x65E2, 0x0102) }; byte[] sampleForPidTagChangeKey = this.propertyValuesSpecific["PidTagChangeKey"]; // Modify ChangeKey to generate a new ChangeKey. byte[] temp = new byte[4]; Array.Copy(sampleForPidTagChangeKey, sampleForPidTagChangeKey.Length - 4, temp, 0, 4); Array.Reverse(temp); int add = BitConverter.ToInt32(temp, 0); // Modify the changeNumber to a newer version. add++; temp = BitConverter.GetBytes(add); Array.Reverse(temp); Array.Copy(temp, 0, sampleForPidTagChangeKey, sampleForPidTagChangeKey.Length - 4, 4); propertyValue.Value = sampleForPidTagChangeKey; hierarchyValues[3] = propertyValue; // Construct PidTagPredecessorChangeList value propertyValue = new TaggedPropertyValue { PropertyTag = new PropertyTag(0x65E3, 0x0102) }; byte[] sampleForPidTagPredecessorChangeList = new byte[this.propertyValuesSpecific["PidTagPredecessorChangeList"].Length + sampleForPidTagChangeKey.Length]; Array.Copy(this.propertyValuesSpecific["PidTagPredecessorChangeList"], 0, sampleForPidTagPredecessorChangeList, 0, this.propertyValuesSpecific["PidTagPredecessorChangeList"].Length); Array.Copy(sampleForPidTagChangeKey, 0, sampleForPidTagPredecessorChangeList, this.propertyValuesSpecific["PidTagPredecessorChangeList"].Length, sampleForPidTagChangeKey.Length); propertyValue.Value = sampleForPidTagPredecessorChangeList; hierarchyValues[4] = propertyValue; } else if (folderIdIndex == 0) { // Get a local id from the id set given by server. byte[] sub = new byte[4]; byte[] currentLocalId = this.localId; Array.Copy(currentLocalId, 2, sub, 0, currentLocalId.Length - 2); Array.Reverse(sub); int totalNum = BitConverter.ToInt32(sub, 0); totalNum += this.localIdOffSet; sub = BitConverter.GetBytes(totalNum); Array.Reverse(sub); Array.Copy(sub, 0, currentLocalId, 2, currentLocalId.Length - 2); this.localIdOffSet++; // Construct PidTagSourceKey value. propertyValue = new TaggedPropertyValue { PropertyTag = new PropertyTag(0x65E0, 0x0102) }; byte[] sampleForPidTagSourceKey = new byte[24]; int length = 0; int index = 0; // The combination of first two bytes indicates the length of value field. length = (short)(this.serverReplicaGuid.ToByteArray().Length + currentLocalId.Length); Array.Copy(BitConverter.GetBytes(length), 0, sampleForPidTagSourceKey, 0, sizeof(short)); index += sizeof(short); Array.Copy(this.serverReplicaGuid.ToByteArray(), 0, sampleForPidTagSourceKey, index, this.serverReplicaGuid.ToByteArray().Length); index += this.serverReplicaGuid.ToByteArray().Length; Array.Copy(currentLocalId, 0, sampleForPidTagSourceKey, index, currentLocalId.Length); Array.Copy(currentLocalId, 0, currentChangeNumber, 0, currentLocalId.Length); propertyValue.Value = sampleForPidTagSourceKey; hierarchyValues[1] = propertyValue; // Convert long term id to id . LongTermId longTermId = new LongTermId { DatabaseGuid = this.serverReplicaGuid.ToByteArray(), GlobalCounter = currentLocalId }; folderId = this.GetIdFromLongTerm(serverId, longTermId); // Construct PidTagLastModificationTime value. propertyValue = new TaggedPropertyValue { PropertyTag = new PropertyTag(0x3008, 0x0040) }; byte[] sampleForPidTagLastModificationTime = BitConverter.GetBytes(DateTime.Now.ToFileTimeUtc()); propertyValue.Value = sampleForPidTagLastModificationTime; hierarchyValues[2] = propertyValue; // Construct PidTagChangeKey value. propertyValue = new TaggedPropertyValue { PropertyTag = new PropertyTag(0x65E2, 0x0102) }; byte[] sampleForPidTagChangeKey = new byte[24]; index = 0; length = 0; length = (short)GidLength; // The combination of first two bytes indicates the length of value field. Array.Copy(BitConverter.GetBytes(length), 0, sampleForPidTagChangeKey, 0, sizeof(short)); index += sizeof(short); Array.Copy(this.localReplicaGuid.ToByteArray(), 0, sampleForPidTagChangeKey, index, this.localReplicaGuid.ToByteArray().Length); index += this.localReplicaGuid.ToByteArray().Length; Array.Copy(currentChangeNumber, 0, sampleForPidTagChangeKey, index, currentChangeNumber.Length); propertyValue.Value = sampleForPidTagChangeKey; hierarchyValues[3] = propertyValue; // Construct PidTagPredecessorChangeList value propertyValue = new TaggedPropertyValue { PropertyTag = new PropertyTag(0x65E3, 0x0102) }; byte[] sampleForPidTagPredecessorChangeList = new byte[25]; index = 0; length = 0; length = (short)(GidLength + 1); Array.Copy(BitConverter.GetBytes(length), 0, sampleForPidTagPredecessorChangeList, 0, sizeof(short)); index += sizeof(short); sampleForPidTagPredecessorChangeList[2] = Convert.ToByte(this.localReplicaGuid.ToByteArray().Length + currentChangeNumber.Length); // 16 index += 1; Array.Copy(this.localReplicaGuid.ToByteArray(), 0, sampleForPidTagPredecessorChangeList, index, this.localReplicaGuid.ToByteArray().Length); index += this.localReplicaGuid.ToByteArray().Length; Array.Copy(currentChangeNumber, 0, sampleForPidTagPredecessorChangeList, index, currentChangeNumber.Length); propertyValue.Value = sampleForPidTagPredecessorChangeList; hierarchyValues[4] = propertyValue; } } else { // Get a local id from the id set given by server. byte[] sub = new byte[4]; byte[] currentLocalId = this.localId; Array.Copy(currentLocalId, 2, sub, 0, currentLocalId.Length - 2); Array.Reverse(sub); int totalNum = BitConverter.ToInt32(sub, 0); totalNum += this.localIdOffSet; sub = BitConverter.GetBytes(totalNum); Array.Reverse(sub); Array.Copy(sub, 0, currentLocalId, 2, currentLocalId.Length - 2); this.localIdOffSet++; // Construct PidTagSourceKey value. propertyValue = new TaggedPropertyValue { PropertyTag = new PropertyTag(0x65E0, 0x0102) }; byte[] sampleForPidTagSourceKey = new byte[24]; int length = 0; int index = 0; // The combination of first two bytes indicates the length of value field. length = (short)(this.serverReplicaGuid.ToByteArray().Length + currentLocalId.Length); Array.Copy(BitConverter.GetBytes(length), 0, sampleForPidTagSourceKey, 0, sizeof(short)); index += sizeof(short); Array.Copy(this.serverReplicaGuid.ToByteArray(), 0, sampleForPidTagSourceKey, index, this.serverReplicaGuid.ToByteArray().Length); index += this.serverReplicaGuid.ToByteArray().Length; Array.Copy(currentLocalId, 0, sampleForPidTagSourceKey, index, currentLocalId.Length); Array.Copy(currentLocalId, 0, currentChangeNumber, 0, currentLocalId.Length); propertyValue.Value = sampleForPidTagSourceKey; hierarchyValues[1] = propertyValue; // Convert long term id to id . LongTermId longTermId = new LongTermId { DatabaseGuid = this.serverReplicaGuid.ToByteArray(), GlobalCounter = currentLocalId }; folderId = this.GetIdFromLongTerm(serverId, longTermId); // Construct PidTagLastModificationTime value. propertyValue = new TaggedPropertyValue { PropertyTag = new PropertyTag(0x3008, 0x0040) }; byte[] sampleForPidTagLastModificationTime = BitConverter.GetBytes(DateTime.Now.ToFileTimeUtc()); propertyValue.Value = sampleForPidTagLastModificationTime; hierarchyValues[2] = propertyValue; // Construct PidTagChangeKey value. propertyValue = new TaggedPropertyValue { PropertyTag = new PropertyTag(0x65E2, 0x0102) }; byte[] sampleForPidTagChangeKey = new byte[24]; index = 0; length = 0; length = (short)GidLength; // The combination of first two bytes indicates the length of value field. Array.Copy(BitConverter.GetBytes(length), 0, sampleForPidTagChangeKey, 0, sizeof(short)); index += sizeof(short); Array.Copy(this.localReplicaGuid.ToByteArray(), 0, sampleForPidTagChangeKey, index, this.localReplicaGuid.ToByteArray().Length); index += this.localReplicaGuid.ToByteArray().Length; Array.Copy(currentChangeNumber, 0, sampleForPidTagChangeKey, index, currentChangeNumber.Length); propertyValue.Value = sampleForPidTagChangeKey; hierarchyValues[3] = propertyValue; // Construct PidTagPredecessorChangeList value propertyValue = new TaggedPropertyValue { PropertyTag = new PropertyTag(0x65E3, 0x0102) }; byte[] sampleForPidTagPredecessorChangeList; if (conflictType == ConflictTypes.AINCLUDEB) { sampleForPidTagPredecessorChangeList = new byte[25]; index = 0; length = 0; length = (short)(GidLength + 1); Array.Copy(BitConverter.GetBytes(length), 0, sampleForPidTagPredecessorChangeList, 0, sizeof(short)); index += sizeof(short); sampleForPidTagPredecessorChangeList[2] = Convert.ToByte(this.localReplicaGuid.ToByteArray().Length + currentChangeNumber.Length); // 16 index += 1; Array.Copy(this.localReplicaGuid.ToByteArray(), 0, sampleForPidTagPredecessorChangeList, index, this.localReplicaGuid.ToByteArray().Length); index += this.localReplicaGuid.ToByteArray().Length; Array.Copy(currentChangeNumber, 0, sampleForPidTagPredecessorChangeList, index, currentChangeNumber.Length); this.lastConflictInfo.PCLB = sampleForPidTagPredecessorChangeList; sampleForPidTagPredecessorChangeList[24] += 1; this.lastConflictInfo.PCLA = sampleForPidTagPredecessorChangeList; this.lastConflictInfo.PCLXFromMath = sampleForPidTagPredecessorChangeList; this.lastConflictInfo.DetectedResult = conflictType; propertyValue.Value = sampleForPidTagPredecessorChangeList; hierarchyValues[4] = propertyValue; } else if (conflictType == ConflictTypes.BINCLUDEA) { sampleForPidTagPredecessorChangeList = new byte[25]; index = 0; length = 0; length = (short)(GidLength + 1); Array.Copy(BitConverter.GetBytes(length), 0, sampleForPidTagPredecessorChangeList, 0, sizeof(short)); index += sizeof(short); sampleForPidTagPredecessorChangeList[2] = Convert.ToByte(this.localReplicaGuid.ToByteArray().Length + currentChangeNumber.Length); // 16 index += 1; Array.Copy(this.localReplicaGuid.ToByteArray(), 0, sampleForPidTagPredecessorChangeList, index, this.localReplicaGuid.ToByteArray().Length); index += this.localReplicaGuid.ToByteArray().Length; Array.Copy(currentChangeNumber, 0, sampleForPidTagPredecessorChangeList, index, currentChangeNumber.Length); this.lastConflictInfo.PCLB = sampleForPidTagPredecessorChangeList; this.lastConflictInfo.PCLXFromMath = sampleForPidTagPredecessorChangeList; sampleForPidTagPredecessorChangeList[24] -= 1; this.lastConflictInfo.PCLA = sampleForPidTagPredecessorChangeList; this.lastConflictInfo.DetectedResult = conflictType; propertyValue.Value = sampleForPidTagPredecessorChangeList; hierarchyValues[4] = propertyValue; } if (conflictType == ConflictTypes.CONFLICT) { // If the versions from client and server are in conflict, the value of PidTagPredecessorChangeList property in client should not include // the one in server. And the changelist value in server should not include or be equal to the one in client, which means the changelist value in client // should be different with server, just like the second example in section 4.6.2. sampleForPidTagPredecessorChangeList = new byte[25]; index = 0; length = 0; length = (short)(GidLength + 1); Array.Copy(BitConverter.GetBytes(length), 0, sampleForPidTagPredecessorChangeList, 0, sizeof(short)); index += sizeof(short); sampleForPidTagPredecessorChangeList[2] = Convert.ToByte(this.localReplicaGuid.ToByteArray().Length + currentChangeNumber.Length); // 16 index += 1; Array.Copy(this.localReplicaGuid.ToByteArray(), 0, sampleForPidTagPredecessorChangeList, index, this.localReplicaGuid.ToByteArray().Length); index += this.localReplicaGuid.ToByteArray().Length; Array.Copy(currentChangeNumber, 0, sampleForPidTagPredecessorChangeList, index, currentChangeNumber.Length); this.lastConflictInfo.PCLB = sampleForPidTagPredecessorChangeList; // The parameter change is used to save the changelist value in client. byte[] change = new byte[48]; Array.Copy(BitConverter.GetBytes(46), 0, change, 0, sizeof(short)); Array.Copy(sampleForPidTagPredecessorChangeList, 2, change, 2, 23); Array.Copy(BitConverter.GetBytes(22), 0, change, 25, sizeof(short)); // Modify the value of PidTagPredecessorChangeList property in client via adding one in GUID field and adding one in GLOBCNT field. byte[] namespaceGuidPartValue = new byte[8]; Array.Copy(sampleForPidTagPredecessorChangeList, 10, namespaceGuidPartValue, 2, namespaceGuidPartValue.Length - 2); Array.Reverse(namespaceGuidPartValue); long namespaceGuidPartValueInt = BitConverter.ToInt64(namespaceGuidPartValue, 0); namespaceGuidPartValueInt += 1; namespaceGuidPartValue = BitConverter.GetBytes(namespaceGuidPartValueInt); Array.Reverse(namespaceGuidPartValue); Array.Copy(namespaceGuidPartValue, 2, sampleForPidTagPredecessorChangeList, 10, namespaceGuidPartValue.Length - 2); Array.Copy(sampleForPidTagPredecessorChangeList, 3, change, 26, 22); change[47] += 1; this.lastConflictInfo.PCLA = change; this.lastConflictInfo.PCLXFromMath = change; this.lastConflictInfo.DetectedResult = conflictType; propertyValue.Value = change; hierarchyValues[4] = propertyValue; } } // Construct PidTagDisplayName value. propertyValue = new TaggedPropertyValue { PropertyTag = new PropertyTag(0x3001, 0x001F) }; byte[] sampleForPidTagDisplayName = new byte[Encoding.Unicode.GetByteCount("TestFolder" + "\0")]; Array.Copy( Encoding.Unicode.GetBytes("TestFolder" + "\0"), 0, sampleForPidTagDisplayName, 0, Encoding.Unicode.GetByteCount("TestFolder" + "\0")); propertyValue.Value = sampleForPidTagDisplayName; hierarchyValues[5] = propertyValue; return hierarchyValues; }
/// <summary> /// Convert longTermId to id. /// </summary> /// <param name="serverId">server id.</param> /// <param name="longTermId">longTerm id.</param> /// <returns>Converted short term id.</returns> private ulong GetIdFromLongTerm(int serverId, LongTermId longTermId) { RopIdFromLongTermIdRequest ropIdFromLongTermRequest = new RopIdFromLongTermIdRequest(); RopIdFromLongTermIdResponse ropIdFromLongTermResponse = new RopIdFromLongTermIdResponse(); ropIdFromLongTermRequest.RopId = 0x44; ropIdFromLongTermRequest.LogonId = 0x00; ropIdFromLongTermRequest.InputHandleIndex = 0x00; ropIdFromLongTermRequest.LongTermId = longTermId; ropIdFromLongTermResponse = (RopIdFromLongTermIdResponse)this.Process(serverId, ropIdFromLongTermRequest, this.logonHandleOut); return ropIdFromLongTermResponse.ObjectId; }
/// <summary> /// Identifies that a set of IDs either belongs to deleted messages in the specified folder or will never be used for any messages in the specified folder. /// </summary> /// <param name="serverId">A 32-bit signed integer represent the Identity of server.</param> /// <param name="folderhandleIndex">A Folder object handle index.</param> /// <param name="longTermIdRangeIndex">An array of LongTermIdRange structures defines a range of IDs, which are reported as unused or deleted.</param> /// <returns>Indicate the result of this ROP operation.</returns> public RopResult SetLocalReplicaMidsetDeleted(int serverId, int folderhandleIndex, Sequence<int> longTermIdRangeIndex) { // Initialize ROP data. RopResult result = RopResult.InvalidParameter; uint folderHandle = this.handleContainer[folderhandleIndex]; LongTermIdRange[] idranges = new LongTermIdRange[longTermIdRangeIndex.Count]; // Get the Mid need to be deleted. for (int i = 0; i < longTermIdRangeIndex.Count; i++) { LongTermId max = new LongTermId(); LongTermId min = new LongTermId(); // Max Mid max.DatabaseGuid = this.serverReplicaGuid.ToByteArray(); max.GlobalCounter = new byte[6]; Array.Copy(this.localId, 0, max.GlobalCounter, 0, 6); byte[] sub = new byte[4]; Array.Copy(max.GlobalCounter, 2, sub, 0, 4); Array.Reverse(sub); int num = BitConverter.ToInt32(sub, 0); // Make the Mid to the mid to be deleted one. num += longTermIdRangeIndex[i]; sub = BitConverter.GetBytes(num); Array.Reverse(sub); Array.Copy(sub, 0, max.GlobalCounter, 2, 4); // Min Mid min.DatabaseGuid = this.serverReplicaGuid.ToByteArray(); min.GlobalCounter = new byte[6]; Array.Copy(this.localId, 0, min.GlobalCounter, 0, 6); sub = new byte[4]; Array.Copy(min.GlobalCounter, 2, sub, 0, 4); Array.Reverse(sub); num = BitConverter.ToInt32(sub, 0); // Make the Mid to the mid to be deleted one. num += longTermIdRangeIndex[i]; sub = BitConverter.GetBytes(num); Array.Reverse(sub); Array.Copy(sub, 0, min.GlobalCounter, 2, 4); // ID range data idranges[i].MaxLongTermId = max.Serialize(); idranges[i].MinLongTermId = min.Serialize(); } // Construct the RopGetLocalReplicaIds request. RopSetLocalReplicaMidsetDeletedRequest req = new RopSetLocalReplicaMidsetDeletedRequest { RopId = 0x93 }; byte logonId = 0; req.LogonId = logonId; req.InputHandleIndex = 0; req.DataSize = (ushort)((sizeof(byte) * 48 * idranges.Length) + 4); req.LongTermIdRangeCount = (uint)idranges.Length; // Set idCount, which specifies the number of IDs to reserve, req.LongTermIdRanges = idranges; // Send request and get response. RopSetLocalReplicaMidsetDeletedResponse setLocalReplicaMidsetDeletedResponse = (RopSetLocalReplicaMidsetDeletedResponse)this.Process(serverId, req, folderHandle); result = (RopResult)setLocalReplicaMidsetDeletedResponse.ReturnValue; if (result == RopResult.Success) { // Verify ROP SetLocalReplicaMidsetDeleted this.VerifyRopSetLocalReplicaMidsetDeleted(setLocalReplicaMidsetDeletedResponse); } return result; }
/// <summary> /// Imports information about moving a message between two existing folders within the same mailbox. /// </summary> /// <param name="serverId">A 32-bit signed integer represent the Identity of server.</param> /// <param name="synchronizationUploadContextHandleIndex">The index of the synchronization upload context configured for collecting changes to the contents of the message move destination folder.</param> /// <param name="sourceFolderIdIndex">The index of the source folder id in object id container.</param> /// <param name="destinationFolderIdIndex">The index of the destination folder id in object id container.</param> /// <param name="sourceMessageIdIndex">The index of source message id in object id container.</param> /// <param name="sourceFolderHandleIndex">The index of source folder handle in handleContainer.</param> /// <param name="destinationFolderHandleIndex">The index of destination folder handle in handle container.</param> /// <param name="inewerClientChange">If the client has a newer message.</param> /// <param name="iolderversion">If the server have an older version of a message .</param> /// <param name="icnpc">Verify if the change number has been used.</param> /// <returns>Indicate the result of this ROP operation.</returns> public RopResult SynchronizationImportMessageMove(int serverId, int synchronizationUploadContextHandleIndex, int sourceFolderIdIndex, int destinationFolderIdIndex, int sourceMessageIdIndex, int sourceFolderHandleIndex, int destinationFolderHandleIndex, bool inewerClientChange, out bool iolderversion, out bool icnpc) { // Initialize return value. iolderversion = false; icnpc = true; RopResult result = RopResult.InvalidParameter; uint synchronizationUploadContextHandle = this.handleContainer[synchronizationUploadContextHandleIndex]; uint sourceFolderHandle = this.handleContainer[sourceFolderHandleIndex]; ulong sourceFID = this.objectIdContainer[sourceFolderIdIndex]; ulong sourceMID = this.objectIdContainer[sourceMessageIdIndex]; // Construct the RopSynchronizationImportMessageMove request. RopSynchronizationImportMessageMoveRequest importMessageMoveRequest = new RopSynchronizationImportMessageMoveRequest { RopId = 0x78, LogonId = 0x00, InputHandleIndex = 0x00 }; // Get source folder id. byte[] fidLongTermId = this.GetLongTermIdByte(serverId, sourceFID); importMessageMoveRequest.SourceFolderIdSize = (uint)fidLongTermId.Length; byte[] sourceFolderId = new byte[fidLongTermId.Length]; Array.Copy(fidLongTermId, 0, sourceFolderId, 0, fidLongTermId.Length); importMessageMoveRequest.SourceFolderId = sourceFolderId; // Get source message id byte[] midLongTermId = this.GetLongTermIdByte(serverId, sourceMID); importMessageMoveRequest.SourceMessageIdSize = (uint)midLongTermId.Length; byte[] sourceMessageId = new byte[midLongTermId.Length]; Array.Copy(midLongTermId, 0, sourceMessageId, 0, midLongTermId.Length); importMessageMoveRequest.SourceMessageId = sourceMessageId; // Get destination message id byte[] sub = new byte[4]; byte[] currentLocalId = this.localId; // Get local id. Array.Copy(currentLocalId, 2, sub, 0, currentLocalId.Length - 2); Array.Reverse(sub); int tempLocalId = BitConverter.ToInt32(sub, 0); tempLocalId += this.localIdOffSet; sub = BitConverter.GetBytes(tempLocalId); Array.Reverse(sub); Array.Copy(sub, 0, currentLocalId, 2, currentLocalId.Length - 2); this.localIdOffSet++; importMessageMoveRequest.DestinationMessageIdSize = (uint)(this.serverReplicaGuid.ToByteArray().Length + currentLocalId.Length); byte[] destinationMessageId = new byte[this.serverReplicaGuid.ToByteArray().Length + currentLocalId.Length]; Array.Copy(this.serverReplicaGuid.ToByteArray(), 0, destinationMessageId, 0, this.serverReplicaGuid.ToByteArray().Length); Array.Copy(currentLocalId, 0, destinationMessageId, this.serverReplicaGuid.ToByteArray().Length, currentLocalId.Length); LongTermId longtermid = new LongTermId { DatabaseGuid = this.serverReplicaGuid.ToByteArray(), GlobalCounter = currentLocalId }; // Get Mid from long termid. ulong destinationMID = this.GetIdFromLongTerm(serverId, longtermid); importMessageMoveRequest.DestinationMessageId = destinationMessageId; // Change number byte[] tempChangeNumber = this.GetChangeNumber(serverId, sourceMID, sourceFID, sourceFolderHandle); importMessageMoveRequest.ChangeNumberSize = (uint)tempChangeNumber.Length; // Generate a new change number. byte[] tempBytes = new byte[4]; Array.Copy(tempChangeNumber, tempChangeNumber.Length - 4, tempBytes, 0, 4); Array.Reverse(tempBytes); int num = BitConverter.ToInt32(tempBytes, 0); if (inewerClientChange == false) { // Make the message version older in client than that in server. num--; iolderversion = false; } else { // Make the message version newer in client than that in server. num++; iolderversion = true; } tempBytes = BitConverter.GetBytes(num); Array.Reverse(tempBytes); Array.Copy(tempBytes, 0, tempChangeNumber, tempChangeNumber.Length - 4, tempBytes.Length); importMessageMoveRequest.ChangeNumber = tempChangeNumber; // Set the PCL size value. importMessageMoveRequest.PredecessorChangeListSize = (uint)(tempChangeNumber.Length + 1); importMessageMoveRequest.PredecessorChangeList = new byte[tempChangeNumber.Length + 1]; importMessageMoveRequest.PredecessorChangeList[0] = (byte)tempChangeNumber.Length; Array.Copy(tempChangeNumber, 0, importMessageMoveRequest.PredecessorChangeList, 1, tempChangeNumber.Length); // Send request and get response. RopSynchronizationImportMessageMoveResponse synchronizationImportMessageMoveResponse = (RopSynchronizationImportMessageMoveResponse)this.Process(serverId, importMessageMoveRequest, synchronizationUploadContextHandle); result = (RopResult)synchronizationImportMessageMoveResponse.ReturnValue; if (result == RopResult.Success) { // Verify ROP SynchronizationImportMessageMove this.VerifyRopSynchronizationImportMessageMove(synchronizationImportMessageMoveResponse); int messageIdIndex = AdapterHelper.GetObjectIdIndex(); this.objectIdContainer.Add(messageIdIndex, destinationMID); icnpc = false; this.isNonImportMessageChangeOperation = true; } else if (result == RopResult.NewerClientChange) { // Verify ROP SynchronizationImportMessageMove this.VerifyRopSynchronizationImportMessageMove(synchronizationImportMessageMoveResponse); } this.isImportMessageMoveROP = true; return result; }
/// <summary> /// Get content sync data. /// </summary> /// <param name="serverID">server id.</param> /// <param name="stateIndex">Start index.</param> /// <param name="cs">Content sync object</param> /// <returns>The AbstractFastTransferStream</returns> public AbstractFastTransferStream GetAbstractContentSync( int serverID, int stateIndex, ContentsSync cs) { AbstractFastTransferStream afts = new AbstractFastTransferStream(); AbstractContentsSync acs = new AbstractContentsSync { AbstractDeletion = new AbstractDeletion { IdSetDeleted = new Modeling.Set<int>() } }; // If the deletion is not null change the AbstractDeletion's field, // else do not change the Deletions field of the AbstractContentsSync if (cs.Deletions != null) { // If the deletion is not null the deletion is present. acs.AbstractDeletion = new AbstractDeletion { IsDeletionPresent = true, IsPidTagIdsetExpiredExist = cs.Deletions.PropList.HasPidTagIdsetExpired, // Check pidtags in the deletions property list. IsPidTagIdsetNoLongerInScopeExist = cs.Deletions.PropList.HasPidTagIdsetNoLongerInScope, IdSetDeleted = new Modeling.Set<int>() }; // Check Idset in the deletion. // If the Idset that can be got from PidTagIdsetDeleted value // in the PropList of the deletions is contained in the objectIdContainer // add it to the IdsetDeleted field in the AbstractDeletion List<ulong> ids = cs.Deletions.IdsetDeleted; foreach (int key in this.objectIdContainer.Keys) { if (ids.Contains(this.objectIdContainer[key])) { acs.AbstractDeletion.IdSetDeleted = acs.AbstractDeletion.IdSetDeleted.Add(key); } } this.VerifyMetaTagIdsetDeletedProperty(this.hasExecuteSynchronizationImportDeletes, this.importDelFlag, ids, this.delObjId); this.hasExecuteSynchronizationImportDeletes = false; } // Whether ProgressTotal is present. acs.IsprogessTotalPresent = cs.ProgressTotal != null; // Whether ReadStateChanges is present. acs.IsReadStateChangesExist = cs.ReadStateChanges != null; acs.MessageInfo = new Modeling.Set<AbstractMessageChangeInfo>(); if (cs.MessageChangeTuples != null) { for (int i = 0; i < cs.MessageChangeTuples.Count; i++) { AbstractMessageChangeInfo info = new AbstractMessageChangeInfo(); Tuple<ProgressPerMessage, MessageChange> msg = cs.MessageChangeTuples[i]; info.IsMessageChangeFull = msg.Item2 is MessageChangeFull; // Whether ProgressPerMessagePresent is present. info.IsProgressPerMessagePresent = msg.Item1 != null; if (msg.Item1 != null) { // If ProgressPerMessagePresent is present, // whether the message followed is a FAI message. info.FollowedFAIMessage = msg.Item1.IsFollowedFAIMessage; } info.IsPidTagChangeNumberExist = msg.Item2.HasPidTagChangeNumber; info.IsPidTagMessageSizeExist = msg.Item2.HasPidTagMessageSize; info.IsPidTagMidExist = msg.Item2.HasPidTagMid; // convert the SourceKey in the messageChangeHeader of the messageChange // to a GID structure, then use this GID to build a LongTermId, // get the id corresponding to the LongTermId,if the id is maintained in the // objectIdContainer,find its index, else set the messageIdIndex of the // AbstractMessageChangeInfo to -1. byte[] buffer = msg.Item2.SourceKey; GID gid = StructureSerializer.Deserialize<GID>(buffer); LongTermId lid = new LongTermId { DatabaseGuid = gid.DatabaseGuid.ToByteArray(), GlobalCounter = gid.GlobalCounter }; ulong id = this.GetIdFromLongTerm(serverID, lid); info.MessageIdIndex = -1; foreach (int k in this.objectIdContainer.Keys) { if (this.objectIdContainer[k] == id) { info.MessageIdIndex = k; break; } } // If messageChangeFull, whether its PropList contains PidTagRtfCompressed. if (msg.Item2 is MessageChangeFull) { info.IsRTFformat = (msg.Item2 as MessageChangeFull).IsRTFFormat; } // Add the AbstractMessageChangeInfo to the MessageInfo of the AbstractContentsSync acs.MessageInfo = acs.MessageInfo.Add(info); } // if there is more than 1 messageChange presents. // whether their order is in descending order. if (cs.MessageChangeTuples.Count > 1) { acs.IsSortByLastModificationTime = true; acs.IsSortByMessageDeliveryTime = true; DateTime prev = cs.MessageChangeTuples[0].Item2.LastModificationTime; for (int i = 1; i < cs.MessageChangeTuples.Count; i++) { DateTime curr = cs.MessageChangeTuples[i].Item2.LastModificationTime; // If one is not in descending order. // set flags to false. if (prev < curr) { acs.IsSortByLastModificationTime = false; acs.IsSortByMessageDeliveryTime = false; break; } } // If the OrderByDeliveryTime flag of the SynchronizationExtraFlag field is not set, there is no requirement on the server to return items in a specific order. if (this.isOrderByDeliveryTimeExtraFlagNotSet) { acs.IsSortByLastModificationTime = false; acs.IsSortByMessageDeliveryTime = false; } } } // Get FinalICSState. acs.FinalICSState = this.GetAbstractState(serverID, stateIndex, cs.State); afts.AbstractContentsSync = acs; afts.StreamType = FastTransferStreamType.contentsSync; afts.AbstractState = new AbstractState(); return afts; }
/// <summary> /// Deserialize from a stream. /// </summary> /// <param name="stream">A stream contains serialize.</param> /// <param name="size">Must be -1.</param> /// <returns>The number of bytes read from the stream.</returns> public int Deserialize(System.IO.Stream stream, int size) { AdapterHelper.Site.Assert.AreEqual(-1, size, "The size value should be -1, but the actual value is {0}.", size); int bytesRead = 0; this.Flags = StreamHelper.ReadUInt32(stream); bytesRead += 4; this.Depth = StreamHelper.ReadUInt32(stream); bytesRead += 4; this.FolderLongTermId = StreamHelper.ReadLongTermId(stream); bytesRead += 0x10 + 6 + 2; this.ServerDNCount = StreamHelper.ReadUInt32(stream); bytesRead += 4; this.CheapServerDNCount = StreamHelper.ReadUInt32(stream); bytesRead += 4; this.ServerDNArray = new string[this.ServerDNCount]; for (int i = 0; i < this.ServerDNCount; i++) { this.ServerDNArray[i] = StreamHelper.ReadString8(stream); } AdapterHelper.Site.Assert.AreEqual(this.ServerDNArray.Length, (int)this.ServerDNCount, "The deserialized serverDN count is not equal to the original server DN count. The expected value of the deserialized server DN is {0}, but the actual value is {1}.", this.ServerDNCount, this.ServerDNArray.Length); bytesRead += Common.GetBytesFromMutiUnicodeString(this.ServerDNArray).Length; return bytesRead; }
/// <summary> /// Read a LongTermId from a stream /// and advances the position within the stream by 24. /// </summary> /// <param name="stream">The stream.</param> /// <returns>The number of bytes read from the stream.</returns> public static LongTermId ReadLongTermId(Stream stream) { LongTermId id = new LongTermId(); id.DatabaseGuid = StreamHelper.ReadGuid(stream).ToByteArray(); id.GlobalCounter = new byte[6]; stream.Read(id.GlobalCounter, 0, 6); stream.Read(new byte[2], 0, 2); return id; }
/// <summary> /// Write a LongTermId value to a stream /// and advances the position within the stream by 24. /// </summary> /// <param name="stream">The stream.</param> /// <param name="id">A LongTermId value.</param> /// <returns>The number of bytes written to the stream.</returns> public static int WriteLongTermId(Stream stream, LongTermId id) { int size = 0; size += StreamHelper.WriteGuid(stream, new Guid(id.DatabaseGuid)); size += StreamHelper.WriteBuffer(stream, id.GlobalCounter); size += StreamHelper.WriteBuffer(stream, new byte[2] { 0x00, 0x00 }); return size; }
/// <summary> /// Get the object ID form specified LongTermId. /// </summary> /// <param name="longTermID">The specified LongTermID.</param> /// <param name="logonHandle">The logon handle.</param> /// <returns>Return the object ID that mapping with specified LongTermID.</returns> protected ulong GetObjectIdFormLongTermID(LongTermId longTermID, uint logonHandle) { RopIdFromLongTermIdRequest ropIdFromLongTermIdRequest = new RopIdFromLongTermIdRequest() { RopId = (byte)RopId.RopIdFromLongTermId, LogonId = CommonLogonId, InputHandleIndex = CommonInputHandleIndex, LongTermId = longTermID, }; this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(ropIdFromLongTermIdRequest, logonHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None); RopIdFromLongTermIdResponse ropIdFromLongTermIdResponse = (RopIdFromLongTermIdResponse)this.response; Site.Assert.AreEqual<uint>(TestSuiteBase.Success, ropIdFromLongTermIdResponse.ReturnValue, "Call RopIdFromLongTermId should be success."); return ropIdFromLongTermIdResponse.ObjectId; }