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 |
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.
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.
OCPF is a pretty new library and it currently has a some limitations:
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.
The general OCPF syntax is pretty basic. It mostly consists of top-level keywords, sections and properties types.
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:
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.
TYPE "IPM.Appointment"
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:
Note:
FOLDER can only be defined once.
Examples:
FOLDER "olFolderCalendar"
or
FOLDER D0x9504000000000001
or
SET $folder_id = D0x9504000000000001 FOLDER $folder_id
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.
SET $var1 = 0xdeadbeef
SET $var2 = "Hello World"
SET $var3 = T2008-03-06 23:30:00
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.
OLEGUID PSETID_Appointment "00062002-0000-0000-c000-000000000046"
[...]
NPROPERTY {
OOM:Label:PSETID_Appointment = T2008-03-06 23:30:00
[...]
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.
RECIPIENT TO "recipient1";"recipient2";"recipient3" RECIPIENT CC "recipient4" RECIPIENT BCC "recipient5@remote.corp";"recipient6"
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.
PROPERTY { PR_SUBJECT = "Hello World" 0x1000001e = "Sample body content" };
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.
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; };
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.
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
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
.
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.
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"
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 */
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" }
OCPF uses the following format for BOOLEAN values:
B"true" B"false"
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.
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.
OCPF uses the following format for PT_I8 (uint64_t) values:
D0x9504000000000001
OCPF defines a string as a set of characters (A-Za-z0-9_) enclosed with double quotes:
"I am a STRING"
OCPF defines a unicode string as a set of characters enclosed with double quotes and prefixed with W:
W"I am a UNICODE string"
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:
T2008-03-06 22:30:00 /* 2008, 6th of March 10:30:00PM */
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" }
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.
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">
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 */
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:
Process specified OCPF files, display syntax errors if detected and dump OCPF context content on standard output.
Process specified OCPF files and create/send a message using OCPF context contents.
openchangeclient --ocpf_sender \ --ocpf-file=libocpf/examples/sample_appointment.ocpf
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)
![]() ![]() ![]() |
This content is licensed under the Creative Commons Attribution ShareAlike License v. 3.0: http://creativecommons.org/licenses/by-sa/3.0/ |