p≡p MIME library
You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Go to file
Volker Birk 645b9385c3 will not work as DLL, use static LIB 4 months ago
build-macOS/pEpMIME rename macOS build dir to follow pEp standard; add 64bit Windows build 4 months ago
build-win64 will not work as DLL, use static LIB 4 months ago
build-windows Remove fuzz.cc from Windows project 3 years ago
src update NFC data from Unicode 13.0.0 to Unicode 14.0.0. 2 years ago
.gitignore rename macOS build dir to follow pEp standard; add 64bit Windows build 4 months ago
LICENSE.txt adding LICENSE and README 4 years ago
README.md add design criteria of pEpMIME to README.md :-) 2 years ago


Build Instructions


Solve the cyclic dependency to pEpEngine

To build p≡p MIME it's necessary that header files of p≡p engine are already installed. Because of the dependency loop of p≡p MIME needing these headers and p≡p engine depending on p≡p MIME you best do things in this sequence:

  1. cd pEpEngine && make -C src install_headers
  2. cd pEpMIME/src && make install
  3. cd pEpEngine && make install

The build of p≡p MIME can be customized. Makefile variable PREFIX is the install directory. The environment variables CXXFLAGS and LDFLAGS are being used. So a typical build on macOS i.e. looks like this:

CXXFLAGS=-I/opt/local/include LDFLAGS=-L/opt/local/lib make PREFIX=$HOME -j4 all install

Design criteria of pEpMIME


pEpMIME "normalizes" the MIME messages during parsing, and uses some heuristics especially for non-MIME-compliant inputs. The generated struct message always

  • contains UTF-8 NFC-compliant text in longmsg and longmsg_formatted
  • contains appropriate MIME headers, e.g. Mime-Type and charset

The MIME generator also serializes data in a special and predictive manner:

  • Non-7bit data in MIME leaves' headers and bodies are always base64 encoded. "quoted printable" encoding is never generated.
  • MIME delimiter are short and predictive "=pEp=#=", where # is the smallest possible hexadecimal number so the delimiter does not occur in the message.

Due to this normalization there is no round-trip guarantee that a generated MIME message is identical to the original MIME message:

  1. "MIME_text" --> struct message --> "MIME_text2" "MIME text" and "MIME_text2" usually differ due to normalization

  2. struct message msg1 --> "MIME_text" --> struct message msg2 The content of msg1 and msg2 is identical, except … (FIXME: AFAIK there are special bizarre cases, but I don't remember at the moment)

Special Headers

Additionally pEpMIME adds some internal annotations into message->opt_fields using keys that start with ":pEp:MIME:", a string that can never occur in MIME messages, so they cannot be set by external attackers. The MIME generator of pEpMIME is aware of these special header lines, acts appropriately and skips any element in message->opt_fields that start with ":", so they will never occur as MIME header in the generated MIME message.

Adapters and clients are allowed to use these special header fields and might also define their own (with another prefix, so they won't interfere with future pEpMIME headers).

Currently these special headers are used by pEpMIME:

  • :pEp:MIME:longmsg:format and :pEp:MIME:longmsg:delsp: to store the special annotations for plaintext bodies, according to RFC 3676 https://datatracker.ietf.org/doc/html/rfc3676.
  • :pEp:MIME:attachment1:forwarded: represents the flag has_possible_pEp_msg / has_pEp_msg_attachment. This field is used only internally and does not occur in the returned struct message.