3.1.5.3 Identifying Objects and Maintaining Change Numbers

On creation, objects in the mailbox are assigned internal identifiers, commonly known as Folder ID structures ([MS-OXCDATA] section 2.2.1.1) for folders and Message ID structures ([MS-OXCDATA] section 2.2.1.2) for messages. After internal identifiers are assigned to an object, they MUST never be reused, even if the object it was first assigned to no longer exists. Copying of messaging objects within a mailbox or moving messages between folders of the same mailbox translates into creation of new messaging objects and therefore, new internal identifiers MUST be assigned to new copies. All communications with the server MUST be based on these server-compatible internal identifiers. All other observed behavior is an implementation detail, and not a part of the protocol, and therefore MUST NOT be relied upon.

In most cases, the server is responsible for assigning internal identifiers to mailbox objects, which happens during execution of ROPs, such as RopSaveChangesMessage ([MS-OXCROPS] section 2.2.6.3) and RopCopyTo ([MS-OXCROPS] section 2.2.8.12), or while processing events not controlled by the client (such as Message object delivery).

Messaging objects also maintain a change number by using the CN structure, as specified in section 2.2.2.1, which identifies a version of an object and adheres to the same rules as internal identifiers for messaging objects. When a new object is created, it is assigned a change number. A new change number is assigned to a messaging object each time it is modified. For messages, in addition to a change number for the entire message, there are additional mechanisms for tracking changes to their elements, such as the read state, as specified in section 3.2.5.6, and properties and subobjects arranged into groups, as specified in section 3.2.5.7.

For folders, a change number indicates whether the folder itself has changed, it does not indicate whether the contained messages or aggregated folder properties have changed. If a message within a folder changes, the change number is not updated; however, the aggregated property PidTagLocalCommitTimeMax property ([MS-OXCFOLD] section 2.2.2.2.1.14) is modified to reflect that something within the folder has been changed. Also, if a message is deleted within the folder, the value of the folder change number does not change, but the aggregated PidTagDeletedCountTotal property ([MS-OXCFOLD] section 2.2.2.2.1.15) is updated to reflect the change. A client can monitor these aggregated properties on a folder to determine whether the folder has changed and whether the client needs to synchronize the contents of the folder.

A protocol role that generates internal identifiers for messaging objects and changes MUST ensure that the GLOBCNT structure portions, as specified in section 2.2.2.5, of the internal identifiers that share the same REPLGUID structure, as specified in the XID structure in section 2.2.2.2, only increase with time, when compared byte to byte.

Whenever a change number is changed on a messaging object as the result of the direct modification of the object in a replica (1), as opposed to synchronization, its Predecessor Change List (PCL) MUST be merged with the XID value that represents the new change number.

Clients that use ICS upload to synchronize their local replica with a server replica MUST assign identifiers to client-originated objects in a local replica by using one of the mechanisms specified in section 3.3.5.2.1. Clients MUST generate foreign identifiers, as specified in section 3.3.5.2.3, to identify client-side changes to objects that they export through ICS upload.

Upon successful import of a new or changed object using ICS upload, the server MUST do the following when receiving the RopSaveChangesMessage ROP:

  • Assign the object a new internal change number (PidTagChangeNumber property (section 2.2.1.2.3)). This is necessary because the server MUST be able to represent the imported version in the MetaTagCnsetSeen (section 2.2.1.1.2) or MetaTagCnsetSeenFAI (section 2.2.1.1.3) properties, and these properties cannot operate on foreign identifiers for change numbers that a client passes.

  • Assign the object an internal identifier. If the object is a folder, the PidTagFolderId property (section 2.2.1.2.2) is assigned. If the object is a message, the PidTagMid property (section 2.2.1.2.1) is assigned.

    • Convert the GID structure ([MS-OXCDATA] section 2.2.1.3) to a short-term internal identifier and assign it to an imported object, if the external identifier is a GID value.

  • Assign the object the given PidTagChangeKey property value (section 2.2.1.2.7) and PidTagPredecessorChangeList (section 2.2.1.2.8) that equals PCL {PidTagChangeKey}.

If the import of the object triggered detection of a conflict, the server MUST follow the previous steps for a version of the object resulting from the conflict resolution. For details about handling conflict, see section 3.1.5.6.

Foreign identifiers supplied by clients for change identification (such as the PidTagChangeKey property) are replaced whenever their corresponding internal identifiers change. Examples are provided in the following table. The table uses the following notation:

  • Equals sign (=) to specify that a property is set to the value specified and uses the equals and p. For example, PidTagSourceKey = GID(ID1) means that the PidTagSourceKey property (section 2.2.1.2.5) is set to the value of the initial global identifier.

  • Plus sign followed by equals sign (+=) to specify that the value has been incremented. For example, an initial change number of 1 (CN1) increments to 2 (CN2) as changes are made to the message or folder.

    Sequence of client action

    Updates made on the server

    RopSynchronizationImportMessageChange ROP (section 2.2.3.2.4.2) for a new message:

    • PidTagSourceKey = GID(ID1)

    • PidTagChangeKey = XCN1

    Client checkpoints the stored initial ICS state:

    • MetaTagIdsetGiven += ID2

    • PidTagSourceKey = GID(ID1)

    • PidTagMid= ID1

    • PidTagChangeKey = XCN1

    • PidTagChangeNumber = CN2

    • Final ICS state: MetaTagCnsetSeen += CN2

    RopSynchronizationImportMessageChange ROP

    • PidTagSourceKey = GID(ID1)

    • PidTagChangeKey = XCN3

    • PidTagChangeKey = XCN3

    • PidTagChangeNumber = CN4

    • Final ICS state: MetaTagCnsetSeen += CN4

    ICS download of contents

    • PidTagSourceKey = GID(ID1)

    • PidTagMid = ID1

    • PidTagChangeKey = XCN3

    • PidTagChangeNumber = CN4

    RopOpenMessage ROP ([MS-OXCROPS] section 2.2.6.1)

    RopSetProperties ROP ([MS-OXCROPS] section 2.2.8.6)

    RopSaveChangesMessage ROP

    • PidTagChangeNumber = CN5

    ICS download

    • Changes to a message:

      • PidTagSourceKey = GID(ID1)

      • PidTagMid = ID1

      • PidTagChangeKey = GID(CN5)

      • PidTagChangeNumber = CN5

    • Final ICS state: MetaTagCnsetSeen += CN5

    RopSynchronizationImportMessageMove ROP (section 2.2.3.2.4.4)

    • Message is hard deleted in the source folder A.

    • A copy of the message is created in destination folder B with:

      • PidTagMid = ID2

    • PidTagChangeNumber = CN6

    ICS download of contents for folder A

    • Deletions: ID1

    • Final ICS state: MetaTagIdsetGiven -= ID1

    ICS download of contents for folder B

    • New message:

      • PidTagSourceKey = GID(ID2)

      • PidTagMid = ID2

      • PidTagChangeKey = GID(CN6)

      • PidTagChangeNumber = CN6

    • Final ICS state:

      • MetaTagIdsetGiven -= ID2

    • MetaTagCnsetSeen += CN6

    RopSynchronizationImportMessageChange ROP

    • PidTagSourceKey = GID(ID2)

    • PidTagChangeKey = XCN7

    • PidTagChangeKey = XCN7

    • PidTagChangeNumber = CN8