Common Adapter Documentation/How to write a p≡p adapter

Goals and Principles

As native as possible

p≡p is a concept intended to be implemented as a seamless part of an app. p≡p should either be implemented directly inside an app, or it should be a plugin. Only if there is no matching app available should p≡p’s concept for implementing complete messaging applications be used.

Support the most common development environment for your platform

p≡p is expected to be available for all common development environments. A p≡p adapter implementation is expected to target one development environment, supporting all common technologies and conforming to all standards and conventions commonly used with this development environment.

Implement the complete p≡p standard

A p≡p adapter must support the complete p≡p API and implement the complete adapter API. Additionally, if a platform is missing important features, the adapter can support high-level features like automated software distribution, search in encrypted messages, etc.


The functions of a p≡p adapter are:

Mapping data types into native data types of the development environment

The data types of p≡p API must be mapped to comparable data types of the development environment, respectively.

string mapping

Strings on the app side of the adapter have to be taken and delivered in the commonly-supported form of the respective development environment; in other words, if the development environment of the adapter is Eclipse with Java, then Java Strings have to be supported. If it is Python then Python strings have to be supported, etc.

On the p≡p engine side, strings have to be UTF-8 encoded NFC normalized. The required transformation of string data is the job of the p≡p adapter.


Timestamps on the app side of the adapter have to be in the data format which is most common in the development environment.

Timestamps on the p≡p engine side have to correspond to the implementation of struct tm, which is supported by the C99 development environment on the platform.

other basic datatypes

All other basic datatypes have to be implemented in the most common paradigm used by the respective development platform.

They have to be mapped into their corresponding datatypes of C99 in p≡p API.

p≡p identity

A p≡p identity has to be represented using the common convention the platform uses to support complex datatypes. The datatypes of p≡p identity are strings, the comm_type enum, a two character code lang, at-least-16bit unsigned integer types for minor and major version number, a boolean flag me, as well as a bit field for flags.

This p≡p identity data type has to be mapped to struct _pEp_identity in pEpEngine.h.

p≡p message

The p≡p message struct is a mandatory component of p≡p. It has to be implemented in the most common format of the development environment. All message data has to be converted from and to this type before calling p≡p API. This is security relevant, so it MUST NOT BE OMITTED!

The p≡p message struct has to be mapped to struct _message in message.h.


p≡p engine uses the concept of sequential collections of uni-typed objects. p≡p engine implements them as lists.

They have to be mapped to data types of the development environment which reflect the properties of being iterable. Whether the datatype being used is a list, an array, or anything else depends on convention of development environment. If it is common to express a fixed type of the members of the collection in the development environment, it should be done for all collections. If not, it should be omitted. For example, in Python, anything iterable will do, while in Windows COM a SAFEARRAY is used to map this.

Mapping the p≡p API to that of the development environment

The p≡p API is the part of p≡p engine API, which is reflected to the app through p≡p adapter’s mapping.

p≡p session handles and parallelization

p≡p is using one session handle per code path (possibly executed in parallel). Thus, if there threads are the common paradigm the development environment uses to describe concurrency, then exactly one p≡p session handle (PEP_SESSION) per thread is required. libpEpAdapter delivers an implementation of that using thread local storage.

Implementing messageToSend

Different p≡p protocols MAY require the app to send a message when the p≡p transport system is not available. Therefore, messageToSend has to be implemented as an application callback.

It MAY be required that the p≡p adapter decouples the callback on the engine side from the callback(s) on the app side. In this case, the p≡p adapter has to implement the common method of callbacks or messaging to the app to deliver the messageToSend.

On the p≡p engine side, messageToSend MAY appear on any thread having a p≡p session for.

mapping functionality

The p≡p API is defined in sync_api.h, message_api.h and keymanagement.h, as well as in transport_api.h. Functions which are marked with DYNAMIC_API and all datatypes which are used in the signature of such functions make up the API.

There are also additional basic API features in pEpEngine.h. These must not be used with the exception of those that cannot be avoided to successfully implement the app. In this case only, functions from the basic API MAY be implemented by the p≡p adapter in order to offer them as part of the p≡p API.

Implementing adapter API

The adapter p≡p is the part of the p≡p engine API which is used for implementing adapter functionality only. None of these functions are given to the app.


libpEpAdapter is a library which already implements common tasks, such as having an extra thread for p≡p sync. The author of the p≡p adapter should consider if this library can be used if at all possible; if so, it’s recommended.

Implementing p≡p sync

There is a complete implementation of p≡p sync in libpEpAdapter. Preferrably, this SHOULD be used.

If libpEpadapter cannot be used, then the p≡p adapter MUST implement the p≡p sync callbacks, which are defined in sync_api.h, as well as a collection like a locked queue or a comparable structure, which can queue p≡p sync messages until they’re being processed.

Implementing key server lookup

If the author of the p≡p adapter wants to support key servers as an option, the key server lookup functions in pEpEngine.h MAY be implemented.

WARNING: key servers compromise privacy! They must be disabled by default in all p≡p implementations!

Hint: if you want to support key servers for better OpenPGP compatibility, consider supporting only, as the older SKS keyservers are broken!


p≡p adapters usually appear as one of two possible implementations:

p≡p adapter as a library

All functionality SHOULD be implemented as a software library in case it’s not meant to be used by desktop apps.

p≡p Desktop adapter

For desktop apps, the p≡p adapter MUST be implemented as a p≡p Desktop adapter.

Implementing as Desktop service

A p≡p Desktop adapter MUST be run as background process with the desktop user’s access rights as a maximum.

The desktop service SHOULD be executed with login.

Native IPC interfacing

The desktop service SHOULD support the most common native IPC interfacing of the desktop environment. Native applications are expected to use the native interface rather than JSON RPC. Examples for native interfaces would be COM on Windows, XPC on macOS and DBus on Linux.

p≡p JSON adapter

The desktop service MUST implement the p≡p JSON adapter, which is available as a library and implements the p≡p API as JSON RPC. p≡p Desktop adapters which only support the p≡p JSON adapter are called p≡p Mini adapters.