33 std::string folded(
const std::string & ) ;
34 std::string xnormalise(
const std::string & ) ;
35 std::string readLine( std::istream & ,
bool * =
nullptr ) ;
36 std::string readValue( std::istream & ,
const std::string & ,
bool * =
nullptr ) ;
37 std::string value(
const std::string & ) ;
38 std::string readFormat( std::istream & stream ,
bool * ) ;
39 void readUtf8Mailboxes( std::istream & ,
Envelope & ) ;
40 void readBodyType( std::istream & ,
Envelope & ) ;
41 void readFrom( std::istream & ,
Envelope & ) ;
42 void readFromAuthIn( std::istream & ,
Envelope & ) ;
43 void readFromAuthOut( std::istream & ,
Envelope & ) ;
44 void readForwardTo( std::istream & ,
Envelope & ) ;
45 void readForwardToAddress( std::istream & ,
Envelope & ) ;
46 void readClientAccountSelector( std::istream & ,
Envelope & ) ;
47 void readToList( std::istream & ,
Envelope & ) ;
48 void readAuthentication( std::istream & ,
Envelope & ) ;
49 void readClientSocketAddress( std::istream & ,
Envelope & ) ;
50 void readClientSocketName( std::istream & ,
Envelope & ) ;
51 void readClientCertificate( std::istream & ,
Envelope & ) ;
52 void readEnd( std::istream & ,
Envelope & ) ;
53 std::string_view bodyTypeName( MessageStore::BodyType ) ;
54 MessageStore::BodyType parseSmtpBodyType( std::string_view , MessageStore::BodyType ) ;
55 std::string_view smtpBodyType( MessageStore::BodyType ) ;
61 namespace imp = GStore::EnvelopeImp ;
63 std::string_view crlf =
"\r\n"_sv ;
65 std::streampos pos = stream.tellp() ;
67 stream.setstate( std::ios_base::failbit ) ;
72 stream << x <<
"Content: " << imp::bodyTypeName(e.body_type) << crlf ;
73 stream << x <<
"From: " << e.from << crlf ;
74 stream << x <<
"ToCount: " << (e.to_local.size()+e.to_remote.size()) << crlf ;
76 auto to_p = e.to_local.begin() ;
77 for( ; to_p != e.to_local.end() ; ++to_p )
78 stream << x <<
"To-Local: " << *to_p << crlf ;
81 auto to_p = e.to_remote.begin() ;
82 for( ; to_p != e.to_remote.end() ; ++to_p )
83 stream << x <<
"To-Remote: " << *to_p << crlf ;
85 stream << x <<
"Authentication: " <<
G::Xtext::encode(e.authentication) << crlf ;
86 stream << x <<
"Client: " << e.client_socket_address << crlf ;
87 stream << x <<
"ClientCertificate: " << imp::folded(e.client_certificate) << crlf ;
88 stream << x <<
"MailFromAuthIn: " << imp::xnormalise(e.from_auth_in) << crlf ;
89 stream << x <<
"MailFromAuthOut: " << imp::xnormalise(e.from_auth_out) << crlf ;
90 stream << x <<
"ForwardTo: " << imp::xnormalise(e.forward_to) << crlf ;
91 stream << x <<
"ForwardToAddress: " << e.forward_to_address << crlf ;
92 stream << x <<
"ClientAccountSelector: " << e.client_account_selector << crlf ;
93 stream << x <<
"Utf8MailboxNames: " << (e.utf8_mailboxes?
"1":
"0") << crlf ;
94 stream << x <<
"End: 1" << crlf ;
96 return stream.fail() ? std::size_t(0U) :
static_cast<std::size_t
>( stream.tellp() - pos ) ;
106 out << line <<
"\r\n" ;
108 if( in.bad() || (in.fail()&&!in.eof()) )
110 in.clear( std::ios_base::eofbit ) ;
115 namespace imp = GStore::EnvelopeImp ;
116 std::streampos oldpos = stream.tellg() ;
117 std::string format = imp::readFormat( stream , &e.crlf ) ;
118 imp::readBodyType( stream , e ) ;
119 imp::readFrom( stream , e ) ;
120 imp::readToList( stream , e ) ;
121 imp::readAuthentication( stream , e ) ;
122 imp::readClientSocketAddress( stream , e ) ;
125 imp::readClientCertificate( stream , e ) ;
126 imp::readFromAuthIn( stream , e ) ;
127 imp::readFromAuthOut( stream , e ) ;
128 imp::readForwardTo( stream , e ) ;
129 imp::readForwardToAddress( stream , e ) ;
130 imp::readClientAccountSelector( stream , e ) ;
131 imp::readUtf8Mailboxes( stream , e ) ;
135 imp::readClientCertificate( stream , e ) ;
136 imp::readFromAuthIn( stream , e ) ;
137 imp::readFromAuthOut( stream , e ) ;
138 imp::readForwardTo( stream , e ) ;
139 imp::readForwardToAddress( stream , e ) ;
140 imp::readUtf8Mailboxes( stream , e ) ;
144 imp::readClientCertificate( stream , e ) ;
145 imp::readFromAuthIn( stream , e ) ;
146 imp::readFromAuthOut( stream , e ) ;
147 imp::readForwardTo( stream , e ) ;
148 imp::readForwardToAddress( stream , e ) ;
152 imp::readClientCertificate( stream , e ) ;
153 imp::readFromAuthIn( stream , e ) ;
154 imp::readFromAuthOut( stream , e ) ;
158 imp::readClientSocketName( stream , e ) ;
159 imp::readClientCertificate( stream , e ) ;
161 imp::readEnd( stream , e ) ;
165 else if( stream.fail() && stream.eof() )
166 stream.clear( std::ios_base::eofbit ) ;
168 std::streampos newpos = stream.tellg() ;
169 if( newpos <= 0 || newpos < oldpos )
172 e.endpos =
static_cast<std::size_t
>(newpos-oldpos) ;
177 namespace imp = GStore::EnvelopeImp ;
178 return imp::parseSmtpBodyType( {s.data(),s.size()} , default_ ) ;
184 namespace imp = GStore::EnvelopeImp ;
185 return G::sv_to_string( imp::smtpBodyType( type ) ) ;
191std::string GStore::EnvelopeImp::folded(
const std::string & s_in )
193 std::string s = s_in ;
200std::string GStore::EnvelopeImp::xnormalise(
const std::string & s )
205std::string GStore::EnvelopeImp::readFormat( std::istream & stream ,
bool * crlf )
207 std::string format = readValue( stream ,
"Format" , crlf ) ;
209 throw Envelope::ReadError(
"unknown format id" , format ) ;
213void GStore::EnvelopeImp::readUtf8Mailboxes( std::istream & stream , Envelope & e )
215 e.utf8_mailboxes = readValue(stream,
"Utf8MailboxNames") ==
"1" ;
218void GStore::EnvelopeImp::readBodyType( std::istream & stream , Envelope & e )
220 std::string body_type = readValue( stream ,
"Content" ) ;
221 if( body_type == bodyTypeName(MessageStore::BodyType::SevenBit) )
222 e.body_type = MessageStore::BodyType::SevenBit ;
223 else if( body_type == bodyTypeName(MessageStore::BodyType::EightBitMime) )
224 e.body_type = MessageStore::BodyType::EightBitMime ;
225 else if( body_type == bodyTypeName(MessageStore::BodyType::BinaryMime) )
226 e.body_type = MessageStore::BodyType::BinaryMime ;
228 e.body_type = MessageStore::BodyType::Unknown ;
231void GStore::EnvelopeImp::readFrom( std::istream & stream , Envelope & e )
233 e.from = readValue( stream ,
"From" ) ;
236void GStore::EnvelopeImp::readFromAuthIn( std::istream & stream , Envelope & e )
238 e.from_auth_in = readValue( stream ,
"MailFromAuthIn" ) ;
239 if( !e.from_auth_in.empty() && e.from_auth_in !=
"+" && !
G::Xtext::valid(e.from_auth_in) )
240 throw Envelope::ReadError(
"invalid mail-from-auth-in encoding" ) ;
243void GStore::EnvelopeImp::readFromAuthOut( std::istream & stream , Envelope & e )
245 e.from_auth_out = readValue( stream ,
"MailFromAuthOut" ) ;
246 if( !e.from_auth_out.empty() && e.from_auth_out !=
"+" && !
G::Xtext::valid(e.from_auth_out) )
247 throw Envelope::ReadError(
"invalid mail-from-auth-out encoding" ) ;
250void GStore::EnvelopeImp::readForwardTo( std::istream & stream , Envelope & e )
252 e.forward_to = readValue( stream ,
"ForwardTo" ) ;
255void GStore::EnvelopeImp::readForwardToAddress( std::istream & stream , Envelope & e )
257 e.forward_to_address = readValue( stream ,
"ForwardToAddress" ) ;
260void GStore::EnvelopeImp::readToList( std::istream & stream , Envelope & e )
263 e.to_remote.clear() ;
265 unsigned int to_count =
G::Str::toUInt( readValue(stream,
"ToCount") ) ;
267 for(
unsigned int i = 0U ; i < to_count ; i++ )
269 std::string to_line = readLine( stream ) ;
270 bool is_local = to_line.find(
FileStore::x().append(
"To-Local: ")) == 0U ;
271 bool is_remote = to_line.find(
FileStore::x().append(
"To-Remote: ")) == 0U ;
272 if( ! is_local && ! is_remote )
273 throw Envelope::ReadError(
"bad 'to' line" ) ;
276 e.to_local.push_back( value(to_line) ) ;
278 e.to_remote.push_back( value(to_line) ) ;
282void GStore::EnvelopeImp::readAuthentication( std::istream & stream , Envelope & e )
287void GStore::EnvelopeImp::readClientAccountSelector( std::istream & stream , Envelope & e )
289 e.client_account_selector = readValue( stream ,
"ClientAccountSelector" ) ;
292void GStore::EnvelopeImp::readClientSocketAddress( std::istream & stream , Envelope & e )
294 e.client_socket_address = readValue( stream ,
"Client" ) ;
297void GStore::EnvelopeImp::readClientSocketName( std::istream & stream , Envelope & )
302void GStore::EnvelopeImp::readClientCertificate( std::istream & stream , Envelope & e )
304 e.client_certificate = readValue( stream ,
"ClientCertificate" ) ;
307void GStore::EnvelopeImp::readEnd( std::istream & stream , Envelope & )
309 std::string end = readLine( stream ) ;
311 throw Envelope::ReadError(
"no end line" ) ;
314std::string GStore::EnvelopeImp::readValue( std::istream & stream ,
const std::string & expected_key ,
bool * crlf )
316 std::string line = readLine( stream , crlf ) ;
318 std::string prefix =
FileStore::x().append(expected_key).append(1U,
':') ;
322 prefix.append( 1U ,
' ' ) ;
323 std::size_t pos = line.find( prefix ) ;
325 throw Envelope::ReadError( std::string(
"expected \"").append(
FileStore::x()).append(expected_key).append(
":\"") ) ;
330 int c = stream.peek() ;
331 if( c ==
' ' || c ==
'\t' )
333 std::string next_line = readLine( stream ) ;
334 if( next_line.empty() || (next_line[0]!=
' '&&next_line[0]!=
'\t') )
335 throw Envelope::ReadError() ;
336 next_line[0] =
'\n' ;
337 line.append( next_line ) ;
343 return value( line ) ;
346std::string GStore::EnvelopeImp::readLine( std::istream & stream ,
bool * crlf )
350 if( crlf && !line.empty() )
351 *crlf = line.at(line.size()-1U) ==
'\r' ;
357std::string GStore::EnvelopeImp::value(
const std::string & line )
362std::string_view GStore::EnvelopeImp::bodyTypeName( MessageStore::BodyType type )
364 if( type == MessageStore::BodyType::EightBitMime )
366 else if( type == MessageStore::BodyType::SevenBit )
368 else if( type == MessageStore::BodyType::BinaryMime )
369 return "binarymime"_sv ;
371 return "unknown"_sv ;
374GStore::MessageStore::BodyType GStore::EnvelopeImp::parseSmtpBodyType( std::string_view s , MessageStore::BodyType default_ )
379 return MessageStore::BodyType::SevenBit ;
381 return MessageStore::BodyType::EightBitMime ;
383 return MessageStore::BodyType::BinaryMime ;
385 return MessageStore::BodyType::Unknown ;
388std::string_view GStore::EnvelopeImp::smtpBodyType( MessageStore::BodyType type )
390 if( type == MessageStore::BodyType::EightBitMime )
391 return "8BITMIME"_sv ;
392 else if( type == MessageStore::BodyType::SevenBit )
394 else if( type == MessageStore::BodyType::BinaryMime )
395 return "BINARYMIME"_sv ;
A structure containing the contents of an envelope file, with support for file reading,...
static void copyExtra(std::istream &, std::ostream &)
A convenience function to copy extra envelope lines from an envelope input stream to an output stream...
static std::size_t write(std::ostream &, const Envelope &)
Writes an envelope to a seekable stream.
static std::string smtpBodyType(MessageStore::BodyType)
Converts a body type enum into the corresponding SMTP keyword.
static void read(std::istream &, Envelope &)
Reads an envelope from a stream.
static MessageStore::BodyType parseSmtpBodyType(const std::string &, MessageStore::BodyType default_=MessageStore::BodyType::Unknown)
Parses an SMTP MAIL-FROM BODY= parameter.
static std::string x()
Returns the prefix for envelope header lines.
static std::string format(int generation=0)
Returns an identifier for the storage format implemented by this class, or some older generation of i...
static bool knownFormat(const std::string &format)
Returns true if the storage format string is recognised and supported for reading.
static std::string & trimRight(std::string &s, std::string_view ws, std::size_t limit=0U)
Trims the rhs of s, taking off up to 'limit' of the 'ws' characters.
static bool imatch(char, char) noexcept
Returns true if the two characters are the same, ignoring seven-bit case.
static std::istream & readLine(std::istream &stream, std::string &result, std::string_view eol={}, bool pre_erase_result=true, std::size_t limit=0U)
Reads a line from the stream using the given line terminator, which may be multi-character.
static std::string & trim(std::string &s, std::string_view ws)
Trims both ends of s, taking off any of the 'ws' characters.
static std::string tail(std::string_view in, std::size_t pos, std::string_view default_={})
Returns the last part of the string after the given position.
static std::string readLineFrom(std::istream &stream, std::string_view eol={})
Reads a line from the stream using the given line terminator.
static unsigned int toUInt(std::string_view s)
Converts string 's' to an unsigned int.
static unsigned int replaceAll(std::string &s, std::string_view from, std::string_view to)
Does a global replace on string 's', replacing all occurrences of sub-string 'from' with 'to'.
static std::string_view ws() noexcept
Returns a string of standard whitespace characters.
static std::string trimmed(const std::string &s, std::string_view ws)
Returns a trim()med version of s.
static std::string encode(std::string_view)
Encodes the given string.
static std::string decode(std::string_view)
Decodes the given string.
static bool valid(std::string_view, bool strict=false)
Returns true if a valid encoding, or empty.