OpenChange Property File (OCPF)

0.9

OpenChange Property File (OCPF)

Contents


Revision History

Date

Revision Number

Author

Revision Content

01/04/08

0.5

Julien Kerihuel

Add RECIPIENT support

29/03/08

0.4

Julien Kerihuel

Add PT_UNICODE support and ocpf_dump option

06/03/08

0.3

Julien Kerihuel

Add PT_BINARY and Streams support

05/03/08

0.2

Julien Kerihuel

Improve PT_MV_STRING8 support

03/03/08

0.1

Julien Kerihuel

Initial Revision


1. Introduction

OCPF stands for OpenChange Property Files. This is a tiny file format designed for scripting and which facilitates third-party applications interaction and developers work using OpenChange. The main objective of OCPF is to offer the possibility to go beyond OpenChange tools default properties and create a custom message with user-defined fields.

2. Purpose and Scope

OCPF is designed to be used in various kind of applications and for different purposes:

  • Research on properties: OpenChange developers have often requested for an easy way to test properties and properties values. Prior to OCPF, developers had to write an application linked with libmapi and compile it so that they could test properties. Moreover, adding new named properties in trunk was kept under OpenChange commiters agreement. OCPF solves this issue and allow developers to write OCPF files with custom properties that they can send using OpenChange tools. Furthermore OCPF will provide the community a convenient way to agree on a particular property.

  • Web Applications: OCPF offers a scripted language with substitution variables which makes it possible to use OCPF templates and use OCPF in conjunction with Web Forms. Since OCPF API supports the parsing of multiple files, developers can plan to have a file with variable declarations and a separate OCPF template that just specifies variables.

  • Backup/Restore: OCPF format may offer an easy way for a restore/backup application to dump to the local filesystem and restore messages on Exchange server. Furthermore, substitution of variables can possibly be used to maintain the new hierarchy, such as changing folders ID across Exchange servers and help migrating database from a server to another.


3. Limitations and Bugs

OCPF is a pretty new library and it currently has a some limitations:

  • It only supports a very limited set of property types
  • It doesn't support attachment yet

These limitations will be removed in later versions of OCPF.

If you find bugs, limitations or encounter issues while using the OCPF library, please consider reporting them on http://trac.openchange.org and select the libocpf component. (Note: registration is required to create new tickets).

For questions about its usage or about libocpf development, please post on the OpenChange devel mailing-list.

4. Syntax

The general OCPF syntax is pretty basic. It mostly consists of top-level keywords, sections and properties types.

5. Top Level Keywords

5.1 TYPE

  • Format:

          TYPE STRING
    

  • Description:

    This keyword specifies the message class of the message. Users can either specify their custom type or use on of the following standard values:

    • "IPM.Appointment"
    • "IPM.Contact"
    • "IPM.Journal"
    • "IPM.Note"
    • "IPM.StickyNote"
    • "IPM.Task"
    • "IPM.Post"
  • Note:

    TYPE can only be defined once and takes a string value as parameter. String values must be quoted otherwise a syntax error will be displayed on output.

  • Example:
          TYPE "IPM.Appointment" 
    


5.2 FOLDER

  • Format:
          FOLDER STRING
          FOLDER DOUBLE
          FOLDER VAR
    
  • Description:

    This keyword defines the destination folder of the message. Users can either specify a default folder using the string value or a custom folder ID using its PR_FID double value. It is also possible to substitute the value with a variable, but it is limited to DOUBLE value.

    When FOLDER is set with DOUBLE custom value and ocpf_OpenFolder public function used, it can be set to any folder identifier within the message store. The function will loop over mailbox folders until it finds the folder with the given folder ID and opens it.

    Possible STRING values:

    • olFolderTopInformationStore
    • olFolderDeletedItems
    • olFolderOutbox
    • olFolderSentMail
    • olFolderInbox
    • olFolderCommonView
    • olFolderCalendar
    • olFolderContacts
    • olFolderJournal
    • olFolderNotes
    • olFolderTasks
  • Note:

    FOLDER can only be defined once.

  • Examples:

    FOLDER "olFolderCalendar"
    

    or

    FOLDER D0x9504000000000001
    

    or

    SET    $folder_id = D0x9504000000000001
    FOLDER $folder_id
    


5.3. SET

  • Format:
          SET VAR = PROPVALUE
    
  • Description:

    This keyword registers a variable named VAR and sets its value to PROPVALUE. Variables must be prefixed with a dollar sign ($) and their value can be set to any supported property type. See section on property values for further information.

  • Note:

    SET can be used as many times as needed by the user, however VAR name must remain unique. When a variable name is registered for the second time, the OCPF parser displays a warning on the standard output and skips the assignment.

  • Example:
         SET $var1 = 0xdeadbeef
         SET $var2 = "Hello World"
         SET $var3 = T2008-03-06 23:30:00
    


5.4. OLEGUID

  • Format:
          OLEGUID IDENTIFIER STRING
    
  • Description:

    This keyword registers an OLEGUID couple (IDENTIFIER and STRING value) that can then be used when declaring named properties (see NPROPERTY). OLEGUID keyword takes two parameters: first the name, used with named properties (PSETID_Appointment, PS_PUBLIC_STRINGS etc.) and secondly a string representing a GUID value.

  • Note:

    OLEGUID are identified by their IDENTIFIER and STRING. Users can't register the same OLEGUID IDENTIFIER or STRING twice. If such case occurs, a warning message will be displayed on stdout.

  • Example:
          OLEGUID PSETID_Appointment "00062002-0000-0000-c000-000000000046"
    
          [...]
    
    NPROPERTY {
              OOM:Label:PSETID_Appointment = T2008-03-06 23:30:00
              [...]
    


5.5. RECIPIENT

  • Format:
          RECIPIENT TO STRING;STRING;STRING
          RECIPIENT CC STRING;STRING
          RECIPIENT BCC STRING
    
  • Description:

    This keyword declares recipients. RECIPIENT is followed by a recipient type (TO, CC or BCC) and a set of STRING (recipients) separated with semicolon.

  • Example:
          RECIPIENT TO "recipient1";"recipient2";"recipient3"
          RECIPIENT CC "recipient4"
          RECIPIENT BCC "recipient5@remote.corp";"recipient6"
    


5.6. PROPERTY section

  • Format:
          PROPERTY {
                   [...]
          };
    
  • Description:

    This keyword declares a known property section. PROPERTY is followed by an opening brace, a set of property declarations and is ended with a closing brace and semicolon. This section only recognizes properties as described in 6. Known properties.

  • Note:

    While we suggest keeping a single PROPERTY section, nothing prevents the user from declaring as many PROPERTY sections as needed.

  • Example:
         PROPERTY {
                  PR_SUBJECT = "Hello World"
                  0x1000001e = "Sample body content"
         };
    


5.7. NPROPERTY section

  • Format:
          NPROPERTY {
                     [...]
                    };
    
  • Description:

    This keyword declares a named property section. NPROPERTY is followed by an opening brace, a set of named properties declarations and is ended with a closing brace and semicolon. This section only recognizes named properties as described in 7. Named Properties.

  • Note:

    While we suggest keeping a single NPROPERTY section, nothing prevents the user from declaring as many NPROPERTY sections as needed.

  • Example:
          NPROPERTY {
                    OOM:Start:PSETID_Appointment = T2008-03-06 22:00:00
                    OOM:Location:PSETID_Appointment = "Home Sweet Home"
                    /* Meeting Status */
                    MNID_ID:0x8217:PSETID_Appointment = 0;
          };
    



6. Known Properties

A known properties is any property where the value doesn't change across Exchange servers and versions. Known properties can only be registered within a PROPERTY section (See 5.6 PROPERTY section). Known properties have the same general syntax:

      IDENTIFIER = [PROPVALUE | VAR]
      INTEGER    = [PROPVALUE | VAR]

OCPF lets the user define known properties using two different methods: property names or property tags.

Please note that OCPF doesn't check whether the value associated with the property matches the property type. For the moment it is the developer's responsibility to ensure that the property type matches its value.

6.1. Property Names

Property Names are defined with an IDENTIFIER which must match one already registered in libmapi/conf/mapi-properties. For example:

      PR_SUBJECT      = "Hello World"
      PR_START_DATE   = T2008-03-06 22:00:00
      PR_PRIORITY     = 2


6.2. Property Tags

Property Tags are the other way to set a property. This is an integer value represented using hexadecimal notation and which has two parts: the upper 16 bits are the property ID and the lower 16 bits are the property type.

While users may prefer to use the property name notation for declaration, libmapi/conf/mapi-properties remains incomplete and there may be cases where you need to use the property tag notation. The example below sets properties described in previous example using their property tag notation.

      0x0037001e     = "Hello World"
      0x00600040     = T2008-03-06 22:00:00
      0x00260003     = 2

.

7. Named Properties

The OCPF syntax for different kind of named properties is quite generic. It supports each of the three kinds of property (OOM, MNID_ID, MNID_STRING) and can set known named properties (those listed in libmapi/conf/mapi-named-properties) or register new named properties (except OOM properties).

The types of properties, and how they can be used, are described below.

7.1. OOM

OOM stands for Outlook Object Model and is a friendly name associated to a named property. It has no meaning to Exchange, but it can be useful for OpenChange or MAPI developers.

OOM are human readable shortcuts for most named properties and OOM values are are considered reliable. This is the reason why OOM can only be used if it exists in libmapi/conf/mapi-named-properties. This method - in our opinion - is the best method to guarantee developers a common and validated mapi-named-properties file.

Theorically, property names can have the same OOM, property ID (MNID_ID) or name (MNID_STRING). The only way to guarantee named property uniqueness is to associate its value with a OLEGUID.

OLEGUID needs to be registered before they can be used with named properties. See 5.4 OLEGUID for more information on how to register a OLEGUID.

OOM named properties have the following syntax:

      OOM:IDENTIFIER:IDENTIFIER = [PROPVALUE | VAR]

The first IDENTIFIER represents the OOM value while the second one represents the OLEGUID. Note that identifiers are not enclosed with quotes. Below are some OOM assignments examples:

      OOM:Label:PSETID_Appointment = 9
      OOM:End:PSETID_Appointment = $end_date
      OOM:Private:PSETID_Common = B"true"


7.2. MNID_ID

Named properties that Exchange converts using their property ID (16 bits) are known as MNID_ID named property kind. OCPF provides two different ways to define MNID_ID. It can either be a new named property or an existing one which wouldn't have any associated OOM.

MNID_ID named property kind has the following syntax:

      MNID_ID:INTEGER:PROPTYPE:IDENTIFIER  = [PROPVALUE | VAR]
      MNID_ID:INTEGER:IDENTIFIER           = [PROPVALUE | VAR]

If the MNID_ID named property doesn't exist within libmapi/conf/mapi-named-property then you must specify its property type.

As described in the example below, the main difference between known and custom MNID_ID named properties is whether or not we specify its property type. If your MNID_ID property has not been referenced within libmapi/conf/mapi-named-property, then you must supply its property type, otherwise you can skip it.

Note: PROPTYPE can be any of the values described in 8. Supported Property Types .

      MNID_ID:0x8501:PT_LONG:PSETID_Common = $reminder  /* Reminder      */
      MNID_ID:0x8217:PSETID_Appointment    = 0          /* MeetingStatus */


7.3. MNID_STRING

Exchange also supports named properties which do not have a property ID but are described using property names. These named properties are known as MNID_STRING named property kind and Exchange maps these names to a temporary property type.

MNID_STRING named property kind has the following syntax:

      MNID_STRING:STRING:IDENTIFIER          = [PROPVALUE | VAR]
      MNID_STRING:STRING:PROPTYPE:IDENTIFIER = [PROPVALUE | VAR]

MNID_STRING difference between known and custom is the same as MNID_ID one. If the MNID_STRING property doesn't exist in libmapi/conf/mapi-named-properties, then users have to supply its PROPTYPE.

NOTE: PROPTYPE can be any of the value described in 8. Supported Property Types .

Considering the behavior described above, we could set the "Keywords" MNID_STRING named property using any of the following example:

       MNID_STRING:"Keywords":PS_PUBLIC_STRINGS               = {"one", "two" , "three" }
       MNID_STRING:"Keywords":PT_MV_STRING8:PS_PUBLIC_STRINGS = {"one", "two" , "three" }


8. Supported Property Types

8.1. PT_BOOLEAN

OCPF uses the following format for BOOLEAN values:

      B"true"
      B"false"


8.2. PT_SHORT

OCPF can use any of the following formats for SHORT values:

     S0x1234
     S32

The short integer can either be in hexadecimal of decimal notation but must be prefixed with a "S" to specify this is a short integer value. If you omit to specify the "S", mismatch property type/value errors will occur while sending the message.

8.3. PT_LONG

OCPF can use any of the following formats for PT_LONG values:

      0xdeadbeef
      L0xdeadbeef
      32

The integer can either be in hexadecimal or decimal notation or prefixed with a "L" to specify this is long value. If you use the hexadecimal notation consider using the 'L' prefixed form since other form may disappear in further versions.

8.4. PT_I8

OCPF uses the following format for PT_I8 (uint64_t) values:

      D0x9504000000000001


8.5. PT_STRING8

OCPF defines a string as a set of characters (A-Za-z0-9_) enclosed with double quotes:

      "I am a STRING"


8.6. PT_UNICODE

OCPF defines a unicode string as a set of characters enclosed with double quotes and prefixed with W:

      W"I am a UNICODE string"


8.7. PT_SYSTIME

OCPF defines date using the following format string:

      TYYYY-MM-DD HH:MM:SS

Dates are prefixed with a 'T' character and its content is represented with the syntax below:

  • YYYY: year
  • MM: month
  • DD: day
  • HH: hours
  • MM: minutes
  • SS: seconds
        T2008-03-06 22:30:00 /* 2008, 6th of March 10:30:00PM */


8.8. PT_MV_STRING8

PT_MV_STRING8 are arrays ("multiple values") of strings. OCPF defines PT_MV_STRING8 property values as STRING property values separated by commas and enclosed within braces.

      { STRING, STRING, ..., STRING }   

At least one STRING property value is required to create a valid PT_MV_STRING8 property. If two or more STRING property values are set, then they must be separated with comma.

      { "single multi-string value" }
      { "one" , "two", "three", "owned" }


8.9. PT_BINARY

PT_BINARY are blobs of data. OCPF defines PT_BINARY property values using two different methods. This can either be raw/inline blob of data or filename/external.

If users wish to add raw data blob for a given property, they need to enclose INTEGER values within braces. However many cases occur where the data blob is large (such as HTML content; PR_HTML has PT_BINARY property type). In such cases, users may rather prefer to write an external file and specify a filename.

        { INTEGER INTEGER [...] INTEGER }
        < STRING >

Note that if the blob of data (raw or pointed by filename) is too large to fit in the property values array, then OCPF will automatically open a stream for the property and write its data in the stream.

        PR_HTML = { 0x48 0x65 0x6c 0x6c 0x6f } /* Hello */
        PR_HTML = <"/tmp/sample.html">

9. Comments

OCPF files can contain comments embedded in normal C-style comment markers. That is, a comment starts with a combination of / followed by *, and ends with combination of * followed by /.

Anything contained with in comment markers is ignored by the OCPF tools, and is only for the convenience of human readers.

/* This is a comment */

10. OCPF and openchangeclient

OCPF support has been added to the openchangeclient utility. It now has the ability to parse and process OCPF files. Two different options are supported; you can either check an OCPF files' syntax (--ocpf_syntax) or process the files (--ocpf_sender).

Users can set OCPF files using --ocpf-file=filename. Note that you can specify --ocpf-file multiple times if you have split the OCPF contents into different files. However the whole OCPF files you specify must only represent a single message.

Sample OCPF files are provided in the distribution (libocpf/examples), and can also be browsed from the Examples section of this documentation:

10.1 ocpf_syntax

Process specified OCPF files, display syntax errors if detected and dump OCPF context content on standard output.

openchangeclient --ocpf-syntax  \
                 --ocpf-file=libocpf/examples/sample_appointment.ocpf 

10.2. ocpf_sender

Process specified OCPF files and create/send a message using OCPF context contents.

openchangeclient --ocpf_sender \
                 --ocpf-file=libocpf/examples/sample_appointment.ocpf

10.3 ocpf_dump

Process specified MAPI message and generates the corresponding OCPF file on the filesystem.

openchangeclient --fetch-items=Appointment
MAILBOX (1 messages)
|== test ==| : AA13000000000001/20C140000000003
        Location: paris
        Start time     :   Sat Mar 29 09:00:00 2008 CET
        End time       :   Sat Mar 29 09:30:00 2008 CET
        Timezone: (GMT+01:00) Brussels, Copenhagen, Madrid, Paris
        Private: False
        Status: Completed
    fetchitems               : MAPI_E_SUCCESS (0x0)

openchangeclient --ocpf-dump=AA13000000000001/20C140000000003
OCPF output file: 20c140000000003.ocpf
    OCPF Dump                : MAPI_E_SUCCESS (0x0)

Creative Commons License
Creative Commons Attribution icon Creative Commons Share Alike icon
This content is licensed under the Creative Commons
Attribution ShareAlike License v. 3.0:
http://creativecommons.org/licenses/by-sa/3.0/