'\" t
.\"<!-- Copyright 2001-2007 S. Varshavchik.  See COPYING for -->
.\"<!-- distribution information. -->
.\"     Title: rfc2045
.\"    Author: Sam Varshavchik
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
.\"      Date: 06/16/2026
.\"    Manual: S. Varshavchik.
.\"    Source: Courier Mail Server
.\"  Language: English
.\"
.TH "RFC2045" "3" "06/16/2026" "Courier Mail Server" "S\&. Varshavchik\&."
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\" http://bugs.debian.org/507673
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.ie \n(.g .ds Aq \(aq
.el       .ds Aq '
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
.ad l
.\" -----------------------------------------------------------------
.\" * MAIN CONTENT STARTS HERE *
.\" -----------------------------------------------------------------
.SH "NAME"
rfc2045 \- RFC 2045 (MIME) parsing library
.SH "SYNOPSIS"
.sp
.nf
#include <rfc822\&.h>
#include <rfc2045\&.h>

g++ \&.\&.\&. \-lrfc2045 \-lrfc822 \-lcourier\-unicode
.fi
.SH "DESCRIPTION"
.PP
The rfc2045 library parses MIME\-formatted messages\&. The rfc2045 library is used to:
.PP
1) Parse the structure of a MIME formatted message
.PP
2) Examine the contents of each MIME section
.PP
3) Optionally rewrite and reformat the message\&.
.SS "Creating an rfc2045 structure"
.sp
.if n \{\
.RS 4
.\}
.nf
#include <rfc2045\&.h>

rfc2045::entity entity;

std::istreambuf_iterator<char> b{input_stream}, e;

rfc2045::entity::line_iter<false> parser{b, e};

entity\&.parse(parser);
.fi
.if n \{\
.RE
.\}
.PP
The
rfc2045::entity
object represents a MIME object or entity\&. It\*(Aqs created from a message that\*(Aqs defined by a beginning iterator and an ending iterator for the message\*(Aqs contents\&. The iterators are used to create a
rfc2045::entity::line_iter
template instance\&. Its template parameter specifies whether the message uses a
LF
(false) or
CRLF
(true) line sequence\&. If these iterators are passed by reference to the constructor, they must exist until the message is fully parsed\&. After
\fBparse\fR() returns, a successfully\-parsed message results in the beginning iterator advanced to the ending iterator\*(Aqs value\&. If these iterators are passed by value to the constructor they must be copyable and they are copied into the parser object/
.sp
.if n \{\
.RS 4
.\}
.nf
rfc2045::entity_parser<false> parser;

parser\&.parse(std::istreambuf_iterator<char><{input_stream},
std::istreambuf_iterator<char><{});

rfc2045::entity e=parser\&.parsed_entity();
.fi
.if n \{\
.RE
.\}
.PP
rfc2045::entity_parser
is an alternative, push\-based approach for creating an entity object\&. Its
parse() method gets repeatedly invoked with a pair of beginning and ending iterator values, that incrementally defines the contents of the MIME message\&. Afterwards,
parsed_entity() returns the parsed MIME entity object, at which point the entity parser object is no longer usable and can only be destroyed\&.
.if n \{\
.sp
.\}
.RS 4
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBNote\fR
.ps -1
.br
.PP
rfc2045::entity_parser
uses a separate execution thread for creating the new MIME entity object\&. Each call to
parse() copies the entire sequence of characters from the beginning/ending iterator pair into an internal buffer that the background execution thread digests\&. Use reasonably\- sized sequences, and while the main execution thread assembles the next chunk, the background execution thread eats the previous one\&.
.sp .5v
.RE
.if n \{\
.sp
.\}
.RS 4
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBNote\fR
.ps -1
.br
.PP
Although the iterator pair can be anything that meets the definition of a beginning and an ending iterator, several
rfc2045::entity
methods demand a
std::streambuf
from which the MIME entity was constructed from\&. In the case of a pair of
std::istreambuf_iterators, obtaining the original input stream\*(Aqs
rdbuf() meets this criteria\&.
.sp .5v
.RE
.SS "Default MIME character set"
.sp
.if n \{\
.RS 4
.\}
.nf
std::string charset=rfc2045::default_charset;
.fi
.if n \{\
.RE
.\}
.PP
\fIrfc2045::default_charset\fR
gives the default MIME character set, initially set to
\(lqutf\-8\(rq\&. The library uses the
\fIdefault_charset\fR
when it is not specified in the MIME message\&. There\*(Aqs rarely a need to change that\&.
.SS "Structure of a MIME message"
.sp
.if n \{\
.RS 4
.\}
.nf
rfc2045::entity entity;

for (auto &subentity:entity\&.subentities)
{
    // \&.\&.\&.
    rfc2045::entity *ptr=subentity\&.get_parent_entity();
}

rfc2045::entity::errors_t code=entity\&.errors\&.code;

code=entity\&.all_errors();

std::vector<std::string> messages=entity\&.errors\&.describe();
.fi
.if n \{\
.RE
.\}
.PP
The
rfc2045::entity
objects has many members, only some are publicly documented\&. An entity may have sub\-entities\&.
get_parent_entity
returns a sub\-entity\*(Aqs parent entity (or a
nullptr
in the case of a top level MIME entity)\&.
.PP
Various errors that occured while parsing the MIME entity are collected into an error code, which is a bitmask\&.
all_errors() returns a combined bitmask from the MIME entity and all of its subentities\&.
.PP
See the
rfc2045\&.h
header file for a complete list of parsing errors\&.
.SS "Basic MIME information"
.sp
.if n \{\
.RS 4
.\}
.nf
size_t startpos=entity\&.start_pos,
       startbody=entity\&.startbody,
       endbody=entity\&.endbody,

       nlines=entity\&.nlines,
       nbodylines=entity\&.nbodylines;

rfc2231::header content_type=entity\&.content_type;

std::string mime_type=content_type\&.value;

for (auto &[paramname, paramvalue]:content_type\&.parameters)
{
    size_t index=paramvalue\&.index;
    std::string value=paramvalue\&.value,
        charset=paramvalue\&.charset,
        language=paramvalue\&.language;

    value=paramvalue\&.value_in_charset();
    value=paramvalue\&.value_in_charset("iso\-8859\-1");
}

std::string_view charset=entity\&.content_type_charset();

rfc2045::cte content_transfer_encoding=entity\&.content_transfer_encoding;
.fi
.if n \{\
.RE
.\}
.PP
The following
rfc2045::entity
class members define the position of each MIME entity in its character sequence
.PP
\fIstartpos\fR
.RS 4
This is the starting position of the MIME entity\*(Aqs headers\&. The top level MIME entity\*(Aqs starting position is always 0\&.
.RE
.PP
\fIstartbody\fR
.RS 4
This is the starting position of the body portion of the MIME entity\&.
.RE
.PP
\fIendbody\fR
.RS 4
This is one\-past\-the\-end position of the body portion of the MIME entity\&.
.RE
.PP
\fInlines\fR
and
\fInbodylines\fR
also have the number of lines in the MIME entity (header+body) and just the MIME entity\*(Aqs body portion\&.
.PP
\fIcontent_type\fR
is an object that has the parsed contents of the
\(lqContent\-Type\(rq
header\&. The
rfc2231::header
has two members:
.PP
\fIvalue\fR
.RS 4
The header\*(Aqs value (the part before the semicolon\&.
.RE
.PP
\fIparameters\fR
.RS 4
The header\*(Aqs parameters (if any)\&.
.RE
.PP
\fIparameters\fR
is an associative container\&. The key is the parameter name\&. The container\*(Aqs value has the following members\&.
.PP
\fIindex\fR
.RS 4
This member counts each parameter, in the order of its appearance in the header\&. MIME parameters are parsed according to the rules in RFC 2231, so multiple parameters get combined into a single parameter and value\&. It is unspecified which part\*(Aqs original
\fIindex\fR
represents the parameter\&.
.RE
.PP
\fIvalue\fR
.RS 4
This is the value of the parameter\&. If the parameter\*(Aqs value was split into parts using RFC 2231 this is the reassembled value\&.
.RE
.PP
\fIcharset\fR
.RS 4
This is the
\fIvalue\fR
character set, as specified in an RFC 2231\-encoded parameter\&.
\fIcharset\fR
defaults to
\(lqutf\-8\(rq
if unspecified\&.
.RE
.PP
\fIlanguage\fR
.RS 4
This is the RFC 2231\-encoded
\fIvalue\fR\*(Aqs language\&.
\fIlanguage\fR
is an empty string if it\*(Aqs unspecified or if the parameter wasn\*(Aqt encoded using RFC 2231\&.
.RE
.PP
value_in_charset()
.RS 4
This method returns the
\fIvalue\fR
converted to
\fIrfc2045::default_charset\fR\&.
.RE
.PP
value_in_charset(charset)
.RS 4
This method returns the
\fIvalue\fR
converted to the specified character set\&.
.RE
.PP
content_type_charset() is a convenient shortcut for returning the MIME entity\*(Aqs
charset
content type parameter\&.
\fIcontent_transfer_encoding\fR
is one of the following values that reflects the MIME entity\*(Aqs encoding:
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
rfc2045::cte::sevenbit
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
rfc2045::cte::eightbit
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
rfc2045::cte::qp
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
rfc2045::cte::base64
.RE
.if n \{\
.sp
.\}
.RS 4
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBNote\fR
.ps -1
.br
.PP
rfc2045::cte::eightbit
is also encoded for the rare
\(lqbinary\(rq
encoding\&. A
rfc2045::cte::error
value indicates an invalid encoding\&.
.sp .5v
.RE
.sp
.if n \{\
.RS 4
.\}
.nf
std::string content_id=entity\&.content_id;

std::string content_disposition=entity\&.content_disposition;

std::string content_description=entity\&.content_description;

std::string content_base=entity\&.content_base;

std::string content_location=entity\&.content_location;

std::string content_md5=entity\&.content_md5;

std::string content_language=entity\&.content_language;
.fi
.if n \{\
.RE
.\}
.PP
These class members provide the contents of the corresponding MIME headers, if they exist\&. Notably,
\fIcontent_disposition\fR
can be used to instantiate an
rfc2231::header
object in order to parse this header\&.
.SS "Decoding a MIME section"
.sp
.if n \{\
.RS 4
.\}
.nf
rfc2045::mime_decoder decoder{
    []
    (const char *bytes, size_t bytecnt)
    {
    },
    *input_stream\&.rdbuf(),
    "utf\-8"
};

rfc2045::mime_unicode_decoder decoder{
    []
    (const char32_t *bytes, size_t bytecnt)
    {
    },
    *input_stream\&.rdbuf()
};

decoder\&.decode_header=true;
decoder\&.decode_body=true;
decoder\&.add_eol=false;
decoder\&.header_name_lc=true;
decoder\&.header_name_suppress=false;
decoder\&.decode_subentities=true;
decoder\&.headerfilter=[](std::string_view name, std::string_view content)
          \-> bool
    {
        return true;
    };
decoder\&.headerdone=[](std::string_view name)
    {
    };

// \&.\&.\&.

decoder\&.decode<false>(entity);
.fi
.if n \{\
.RE
.\}
.PP
rfc2045::mime_decoder
and
rfc2045::mime_unicode_decoder
extract the contents of the headers and/or the body portion of a MIME entity\&. Extraction involves:
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
Decoding RFC 2047\-encoded headers, and decoding IDN\-encoded domain names\&. Unfolding headers that are folded across multiple lines\&.
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
Decoding the MIME entity\*(Aqs body transfer encoding, and optionally converting it to a specific character set, if the optional third parameter to
rfc2045::mime_decoder\*(Aqs constructor exists\&. If it doesn\*(Aqt exist no character set mapping takes place\&.
.RE
.PP
The first constructor parameter is a callable object, the output sink\&. The output sink gets repeatedly invoked from
\fBdecode\fR() with the contents of the MIME entity\*(Aqs header and/or body, in the original or mapped character set (rfc2045::mime_decoder), or as Unicode characters (rfc2045::mime_unicode_decoder)\&.
\fBdecode\fR\*(Aqs template parameter must match
rfc2045::entity::line_iter
template\*(Aqs parameter that was used to create the MIME entity object\&.
.if n \{\
.sp
.\}
.RS 4
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBNote\fR
.ps -1
.br
.PP
rfc2045::mime_decoder
and
rfc2045::mime_unicode_decoder
are actually templates\&. Their template parameters are deduced from their constructors\*(Aq parameters\&.
.sp .5v
.RE
.PP
The following class members are available to be set prior to calling
\fBdecode\fR():
.PP
\fIdecode_header\fR (default: true)
.RS 4
Whether the MIME entity\*(Aqs headers should be decoded\&.
.RE
.PP
\fIdecode_body\fR (default: true)
.RS 4
Whether the MIME entity\*(Aqs body should be decoded\&.
.RE
.PP
\fIdecode_subentities\fR (default: true)
.RS 4
Whether to decode, recursively, the MIME entity\*(Aqs subentities\&.
.RE
.PP
\fIadd_eol\fR (default: false)
.RS 4
Whether to include an extra newline after decoding each MIME entity\&.
.RE
.PP
\fIheader_name_lc\fR (default: true)
.RS 4
Whether to convert the name of each decoded header to lowercase\&.
.RE
.PP
\fIheader_name_suppress\fR (default: false)
.RS 4
Whether to include only the contents of each header, to not include the header\*(Aqs name (possibly converted to lowercase) and the colon that separates the header\*(Aqs name from its contents\&.
.RE
.PP
\fIheaderfilter\fR (default: [](std::string_view, std::string_view){ return true; })
.RS 4
This is a callable object that\*(Aqs called before extracting each header\&. Return
true
includes it in the decoded content given to the output sink\&. Together with
\fIheader_name_suppress\fR
this provides for targeted means to extract the decoded contents of specific headers, only\&.
.RE
.PP
\fIheaderdone\fR (default: [](std::string_view) {})
.RS 4
This is called after extracting each header
.RE
.SS "Rewriting MIME messages"
.PP
After parsing an
rfc2045::entity, it can be rewritten in order to convert 8\-bit\-encoded data to 7\-bit encoding, or to convert 7\-bit encoded data to full 8\-bit data, if possible\&.
.sp
.if n \{\
.RS 4
.\}
.nf
if (entity\&.autoconvert_check(rfc2045::convert::standardize))
{
    rfc2045::entity::autoconvert_meta metadata;

    metadata\&.appid="courier";

    rfc2045::entity::line_iter<false>::autoconvert(
       entity,
       []
       (const char *ptr, size_t l)
       {
          // \&.\&.\&.
       },
       input_streambuf,
       metadata);
}
.fi
.if n \{\
.RE
.\}
.PP
\fBautoconvert_check\fR
returns
true
if the MIME entity must be rewritten in order to comply with the requested format\&. A
false
return indicates that the MIME entity already complies\&. The subsequent call to
\fBautoconvert\fR() effects the rewrite (its template parameter must match the one that was used to parse the original MIME entity)\&.
\fBautoconvert\fR()\*(Aqs parameters are: the MIME entity to rewrite, a callable object that gets repeatedly invoked with the contents of the rewritten MIME entity, and a
std::streambuf\-like object that corresponds to the current, parsed, MIME entity\&.
.PP
\fBautoconvert\fR() can only be called after a prior
\fBautoconvert_check\fR(), that defines
\fBautoconvert\fR()\*(Aqs marching orders:
.PP
rfc2045::convert::standardize
.RS 4
Do not change the content encoding of the MIME object, only add default values for any missing
\(lqContent\-Type\(rq
and
\(lqContent\-Transfer\-Encoding\(rq
headers\&.
.RE
.PP
rfc2045::convert::sevenbit
.RS 4
Reencode
8bit
with
\(lqquoted\-printable\(rq\&. Also replace any
7bit
content with excessively long lines\&.
.RE
.PP
rfc2045::convert::8bit
.RS 4
Replace
\(lqquoted\-printable\(rq
with
8bit
unless doing so will produce excessively long lines\&.
.RE
.PP
rfc2045::convert::8bit_always
.RS 4
Always replace
\(lqquoted\-printable\(rq
with
8bit
evenf if doing so will produce excessively long lines\&.
.RE
.SH "SEE ALSO"
.PP
\m[blue]\fB\fBrfc822\fR(3)\fR\m[]\&\s-2\u[1]\d\s+2,
\m[blue]\fB\fBreformail\fR(1)\fR\m[]\&\s-2\u[2]\d\s+2,
\m[blue]\fB\fBreformime\fR(1)\fR\m[]\&\s-2\u[3]\d\s+2\&.
.SH "AUTHOR"
.PP
\fBSam Varshavchik\fR
.RS 4
Author
.RE
.SH "NOTES"
.IP " 1." 4
\fBrfc822\fR(3)
.RS 4
\%http://www.courier-mta.org/maildrop/rfc822.html
.RE
.IP " 2." 4
\fBreformail\fR(1)
.RS 4
\%http://www.courier-mta.org/maildrop/reformail.html
.RE
.IP " 3." 4
\fBreformime\fR(1)
.RS 4
\%http://www.courier-mta.org/maildrop/reformime.html
.RE
