feat: responsive compact mail view + folder unread badges

- CompactMailDelegate: card-based view for narrow panels (<420px)
  * Avatar with hash-based color, sender + date (relative format)
  * Subject line with attachment icon
  * Action buttons: flag, delete, category, more (context menu)
  * Unread highlight with light blue background + bold sender
- MailListView: automatic switch between tree/table (wide) and list/cards (narrow)
  * QStackedWidget with QTreeView + QListView sharing same proxy model
  * resizeEvent threshold at 420px
  * Signals forwarded to MainMainWindow for actions
- FolderTreeDelegate: custom paint for folder tree
  * Unread count badge (blue pill) right-aligned on folder nodes
  * Account nodes bold, folder nodes normal weight
  * Proper indentation per depth level
- MailItemDao::countUnreadByFolderId() for real-time unread counts
- MainMainWindow handlers for compact actions (flag, delete, category, more menu)
This commit is contained in:
2026-08-24 23:25:13 +02:00
parent 705fe32e66
commit 4c4fec7a0a
846 changed files with 498002 additions and 52534 deletions
+125
View File
@@ -0,0 +1,125 @@
/*
base64.hpp
----------
Copyright (C) 2016, Tomislav Karastojkovic (http://www.alepho.com).
Distributed under the FreeBSD license, see the accompanying file LICENSE or
copy at http://www.freebsd.org/copyright/freebsd-license.html.
*/
#pragma once
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4251)
#endif
#include <string>
#include <vector>
#include "codec.hpp"
#include "export.hpp"
namespace mailio
{
/**
Base64 codec.
@todo Add static method `string encode(string)` to be used by `smtp`?
@todo Does it need the first line policy?
**/
class MAILIO_EXPORT base64 : public codec
{
public:
/**
Base64 character set.
**/
static const std::string CHARSET;
/**
Setting the encoder and decoder line policies.
Since Base64 encodes three characters into four, the split is made after each fourth character. It seems that email clients do not merge properly
many lines of encoded text if the split is not grouped by four characters. For that reason, the constructor sets line policies to be divisible by
the number four.
@param line1_policy First line policy to set.
@param lines_policy Other lines policy than the first one to set.
**/
base64(std::string::size_type line1_policy, std::string::size_type lines_policy);
base64(const base64&) = delete;
base64(base64&&) = delete;
/**
Default destructor.
**/
~base64() = default;
void operator=(const base64&) = delete;
void operator=(base64&&) = delete;
/**
Encoding a string into vector of Base64 encoded strings by applying the line policy.
@param text String to encode.
@return Vector of Base64 encoded strings.
**/
std::vector<std::string> encode(const std::string& text) const;
/**
Decoding a vector of Base64 encoded strings to string by applying the line policy.
@param text Vector of Base64 encoded strings.
@return Decoded string.
@throw codec_error Bad character.
@todo Line policy not verified.
**/
std::string decode(const std::vector<std::string>& text) const;
/**
Decoding a Base64 string to a string.
@param text Base64 encoded string.
@return Encoded string.
@throw * `decode(const std::vector<std::string>&)`.
**/
std::string decode(const std::string& text) const;
private:
/**
Checking if the given character is in the base64 character set.
@param ch Character to check.
@return True if it is, false if not.
**/
bool is_allowed(char ch) const;
/**
Number of six bit chunks.
**/
static constexpr unsigned short SEXTETS_NO = 4;
/**
Number of eight bit characters.
**/
static constexpr unsigned short OCTETS_NO = SEXTETS_NO - 1;
};
} // namespace mailio
#ifdef _MSC_VER
#pragma warning(pop)
#endif
+73
View File
@@ -0,0 +1,73 @@
/*
binary.hpp
----------
Copyright (C) 2016, Tomislav Karastojkovic (http://www.alepho.com).
Distributed under the FreeBSD license, see the accompanying file LICENSE or
copy at http://www.freebsd.org/copyright/freebsd-license.html.
*/
#pragma once
#include <string>
#include <vector>
#include "codec.hpp"
#include "export.hpp"
namespace mailio
{
/**
Binary codec.
**/
class MAILIO_EXPORT binary : public codec
{
public:
/**
Setting the encoder and decoder line policies.
@param line1_policy First line policy to set.
@param lines_policy Other lines policy than the first one to set.
**/
binary(std::string::size_type line1_policy, std::string::size_type lines_policy);
binary(const binary&) = delete;
binary(binary&&) = delete;
/**
Default destructor.
**/
~binary() = default;
void operator=(const binary&) = delete;
void operator=(binary&&) = delete;
/**
Encoding a string into vector of binary encoded strings.
@param text String to encode.
@return Vector with binary encoded strings.
**/
std::vector<std::string> encode(const std::string& text) const;
/**
Decoding a vector of binary encoded strings.
@param text Vector of binary encoded strings.
@return Decoded string.
@todo Line policy to be verified.
**/
std::string decode(const std::vector<std::string>& text) const;
};
} // namespace mailio
+85
View File
@@ -0,0 +1,85 @@
/*
bit7.hpp
--------
Copyright (C) 2016, Tomislav Karastojkovic (http://www.alepho.com).
Distributed under the FreeBSD license, see the accompanying file LICENSE or
copy at http://www.freebsd.org/copyright/freebsd-license.html.
*/
#pragma once
#include <string>
#include <vector>
#include "codec.hpp"
#include "export.hpp"
namespace mailio
{
/**
Seven bit codec.
**/
class MAILIO_EXPORT bit7 : public codec
{
public:
/**
Setting the encoder and decoder line policies.
@param line1_policy First line policy to set.
@param lines_policy Other lines policy than the first one to set.
**/
bit7(std::string::size_type line1_policy, std::string::size_type lines_policy);
bit7(const bit7&) = delete;
bit7(bit7&&) = delete;
/**
Default destructor.
**/
~bit7() = default;
void operator=(const bit7&) = delete;
void operator=(bit7&&) = delete;
/**
Encoding a string into vector of 7bit encoded strings by applying the line policy.
@param text String to encode.
@return Vector of seven bit encoded strings.
@throw codec_error Bad character.
**/
std::vector<std::string> encode(const std::string& text) const;
/**
Decoding a vector of 7bit encoded strings to string by applying the line policy.
@param text Vector of 7bit encoded strings.
@return Decoded string.
@throw codec_error Line policy overflow.
@throw codec_error Bad character.
**/
std::string decode(const std::vector<std::string>& text) const;
private:
/**
Checking if a character is in the 7bit character set.
@param ch Character to check.
@return True if it is, false if not.
**/
bool is_allowed(char ch) const;
};
} // namespace mailio
+86
View File
@@ -0,0 +1,86 @@
/*
bit8.hpp
--------
Copyright (C) 2016, Tomislav Karastojkovic (http://www.alepho.com).
Distributed under the FreeBSD license, see the accompanying file LICENSE or
copy at http://www.freebsd.org/copyright/freebsd-license.html.
*/
#pragma once
#include <string>
#include <vector>
#include "codec.hpp"
#include "export.hpp"
namespace mailio
{
/**
Eight bit codec.
**/
class MAILIO_EXPORT bit8 : public codec
{
public:
/**
Setting the encoder and decoder line policies.
@param line1_policy First line policy to set.
@param lines_policy Other lines policy than the first one to set.
**/
bit8(std::string::size_type line1_policy, std::string::size_type lines_policy);
bit8(const bit8&) = delete;
bit8(bit8&&) = delete;
/**
Default destructor.
**/
~bit8() = default;
void operator=(const bit8&) = delete;
void operator=(bit8&&) = delete;
/**
Encoding a string into vector of 8bit encoded strings by applying the line policy.
@param text String to encode.
@return Vector of eight bit encoded strings.
@throw codec_error Bad character.
**/
std::vector<std::string> encode(const std::string& text) const;
/**
Decoding a vector of 8bit strings to string by applying the line policy.
@param text Vector of eight bit encoded strings.
@return Decoded string.
@throw codec_error Line policy overflow.
@throw codec_error Bad character.
**/
std::string decode(const std::vector<std::string>& text) const;
private:
/**
Checking if a character is in the 8bit character set.
@param ch Character to check.
@return True if it is, false if not.
**/
bool is_allowed(char ch) const;
};
} // namespace mailio
+889
View File
@@ -0,0 +1,889 @@
/*
codec.hpp
---------
Copyright (C) 2016, Tomislav Karastojkovic (http://www.alepho.com).
Distributed under the FreeBSD license, see the accompanying file LICENSE or
copy at http://www.freebsd.org/copyright/freebsd-license.html.
*/
#pragma once
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4251)
#endif
#include <string>
#include <stdexcept>
#include <boost/algorithm/string.hpp>
#include "export.hpp"
namespace mailio
{
/**
Base class for codecs, contains various constants and miscellaneous functions for encoding/decoding purposes.
@todo `encode()` and `decode()` as abstract methods?
**/
class MAILIO_EXPORT codec
{
public:
/**
Calculating value of the given hex digit.
**/
static int hex_digit_to_int(char digit);
/**
Checking if a character is eight bit.
@param ch Character to check.
@return True if eight bit, false if seven bit.
**/
static bool is_8bit_char(char ch);
/**
Escaping the specified characters in the given string.
@param text String where to escape certain characters.
@param escaping_chars Characters to be escaped.
@return The given string with the escaped characters.
**/
static std::string escape_string(const std::string& text, const std::string& escaping_chars);
/**
Surrounding the given string with the given character.
@param text String to surround.
@param surround_char Character to be used for the surrounding.
@return Surrounded string.
**/
static std::string surround_string(const std::string& text, char surround_char = '"');
/**
Checking if a string is eight bit encoded.
@param txt String to check.
@return True if it's eight bit, false if not.
**/
static bool is_utf8_string(const std::string& txt);
/**
Nil character.
**/
static const char NIL_CHAR = '\0';
/**
Carriage return character.
**/
static const char CR_CHAR = '\r';
/**
Line feed character.
**/
static const char LF_CHAR = '\n';
/**
Plus character.
**/
static const char PLUS_CHAR = '+';
/**
Minus character.
**/
static const char MINUS_CHAR = '-';
/**
Percent character.
**/
static const char PERCENT_HEX_FLAG = '%';
/**
Slash character.
**/
static const char SLASH_CHAR = '/';
/**
Backslash character.
**/
static const char BACKSLASH_CHAR = '\\';
/**
Equal character.
**/
static const char EQUAL_CHAR = '=';
/**
Equal character as string.
**/
static const std::string EQUAL_STR;
/**
Space character.
**/
static const char SPACE_CHAR = ' ';
/**
Space character as string.
**/
static const std::string SPACE_STR;
/**
Exclamation mark character.
**/
static const char EXCLAMATION_CHAR = '!';
/**
Question mark character.
**/
static const char QUESTION_MARK_CHAR = '?';
/**
Dot character.
**/
static const char DOT_CHAR = '.';
/**
Dot character string.
**/
static const std::string DOT_STR;
/**
Comma character.
**/
static const char COMMA_CHAR = ',';
/**
Comma character as string.
**/
static const std::string COMMA_STR;
/**
Colon character.
**/
static const char COLON_CHAR = ':';
/**
Colon character as string.
**/
static const std::string COLON_STR;
/**
Semicolon character.
**/
static const char SEMICOLON_CHAR = ';';
/**
Semicolon character as string.
**/
static const std::string SEMICOLON_STR;
/**
Zero number character.
**/
static const char ZERO_CHAR = '0';
/**
Nine number character.
**/
static const char NINE_CHAR = '9';
/**
Letter A character.
**/
static const char A_CHAR = 'A';
/**
Tilde character.
**/
static const char TILDE_CHAR = '~';
/**
Quote character.
**/
static const char QUOTE_CHAR = '"';
/**
Quote character as string.
**/
static const std::string QUOTE_STR;
/**
Left parenthesis character.
**/
static const char LEFT_PARENTHESIS_CHAR = '(';
/**
Right parenthesis character.
**/
static const char RIGHT_PARENTHESIS_CHAR = ')';
/**
Left bracket chartacter.
**/
static const char LEFT_BRACKET_CHAR = '[';
/**
Right bracket chartacter.
**/
static const char RIGHT_BRACKET_CHAR = ']';
/**
Left brace character.
**/
static const char LEFT_BRACE_CHAR = '{';
/**
Right brace character.
**/
static const char RIGHT_BRACE_CHAR = '}';
/**
Monkey character.
**/
static const char MONKEY_CHAR = '@';
/**
Less than character.
**/
static const char LESS_THAN_CHAR = '<';
/**
Less than character as string.
**/
static const std::string LESS_THAN_STR;
/**
Greater than character.
**/
static const char GREATER_THAN_CHAR = '>';
/**
Greater than character as string.
**/
static const std::string GREATER_THAN_STR;
/**
Underscore character.
**/
static const char UNDERSCORE_CHAR = '_';
/**
Hexadecimal alphabet.
**/
static const std::string HEX_DIGITS;
/**
Carriage return plus line feed string.
**/
static const std::string END_OF_LINE;
/**
Dot character is the end of message for SMTP.
**/
static const std::string END_OF_MESSAGE;
/**
ASCII charset label.
**/
static const std::string CHARSET_ASCII;
/**
UTF-8 charset label.
**/
static const std::string CHARSET_UTF8;
/**
Attribute indicator for the charset and language parameters.
**/
static const char ATTRIBUTE_CHARSET_SEPARATOR{'\''};
/**
Attribute indicator for the charset and language parameters as string.
**/
static const std::string ATTRIBUTE_CHARSET_SEPARATOR_STR;
/**
Line length policy.
**/
enum class line_len_policy_t : std::string::size_type {RECOMMENDED = 78, MANDATORY = 998, NONE = UINT_MAX,
VERYLARGE [[deprecated]] = 16384};
/**
Methods used for the MIME header encoding/decoding.
**/
enum class codec_t {ASCII, BASE64, QUOTED_PRINTABLE, UTF8, PERCENT};
/**
Setting the encoder and decoder line policies.
@param line1_policy First line policy to set.
@param lines_policy Other lines policy than the first one to set.
**/
codec(std::string::size_type line1_policy, std::string::size_type lines_policy);
codec(const codec&) = delete;
codec(codec&&) = delete;
/**
Default destructor.
**/
virtual ~codec() = default;
void operator=(const codec&) = delete;
void operator=(codec&&) = delete;
/**
Enabling/disabling the strict mode.
@param mode True to enable strict mode, false to disable.
**/
void strict_mode(bool mode);
/**
Returning the strict mode status.
@return True if strict mode enabled, false if disabled.
**/
bool strict_mode() const;
protected:
/**
Policy applied for encoding of the first line.
**/
std::string::size_type line1_policy_;
/**
Policy applied for encoding of the lines other than first one, and for decoding of all lines including the first one.
**/
std::string::size_type lines_policy_;
/**
Strict mode for encoding/decoding.
**/
bool strict_mode_;
};
/**
Error thrown by codecs.
**/
class codec_error : public std::runtime_error
{
public:
/**
Calling parent constructor.
@param msg Error message.
**/
explicit codec_error(const std::string& msg) : std::runtime_error(msg)
{
}
/**
Calling parent constructor.
@param msg Error message.
**/
explicit codec_error(const char* msg) : std::runtime_error(msg)
{
}
};
/**
String which contains charset together with the representation.
**/
template<typename Buf, typename Char>
struct String
{
/**
String content.
**/
Buf buffer;
/**
String charset.
**/
std::string charset;
/**
String codec.
**/
codec::codec_t codec_type;
/**
Default constructor.
**/
String() : buffer(), charset(codec::CHARSET_ASCII), codec_type(codec::codec_t::ASCII)
{
}
/**
Default copy constructor.
**/
String(const String&) = default;
/**
Default move constructor.
**/
String(String&&) = default;
/**
Initializing of the buffer and charset.
@param buffer_s Content of the string.
@param charset_s Charset of the string.
@param codec_s Codec of the string.
**/
String(const Buf& buffer_s, const std::string& charset_s = codec::CHARSET_ASCII, codec::codec_t codec_s = codec::codec_t::ASCII) :
buffer(buffer_s), charset(boost::to_upper_copy(charset_s)), codec_type(codec_s)
{
}
/**
Initializing of the buffer with the string literal.
@param str String literal.
@param charset_s Charset of the string.
@param codec_s Codec of the string.
**/
String(const Char* str, const std::string& charset_s = codec::CHARSET_ASCII, codec::codec_t codec_s = codec::codec_t::ASCII) :
String(Buf(str), charset_s, codec_s)
{
}
/**
Default copy assignment.
**/
String& operator=(const String& other) = default;
/**
Default move assignment.
**/
String& operator=(String&& other) = default;
/**
Conversion to the buffer type.
**/
operator Buf() const
{
return buffer;
}
bool empty() const
{
return buffer.empty();
}
};
/**
Output stream standard insert operator.
@param os Output stream to insert into.
@oaram str String to insert.
@return The output stream itself.
**/
template<typename Buf, typename Char>
std::ostream& operator<<(std::ostream& os, const String<Buf, Char>& str)
{
return os << str.buffer;
}
using string_t = String<std::string, char>;
#if defined(__cpp_char8_t)
using u8string_t = String<std::u8string, char8_t>;
#endif
// String operators.
/**
Deals only with the buffers. The left character set is taken, the right is ignored.
@param lhs First string to add.
@param rhs Second string to add.
@result Concatenated given strings.
**/
template<typename Buf, typename Char>
String<Buf, Char> operator+(const String<Buf, Char>& lhs, const String<Buf, Char>& rhs)
{
String<Buf, Char> result;
result.buffer = lhs.buffer + rhs.buffer;
result.charset = lhs.charset;
return result;
}
/**
Deals only with the buffers. The left character set is taken, the right is ignored.
@param lhs String to be added to.
@param rhs String to add.
@result Second string concatenated to the first one.
**/
template<typename Buf, typename Char>
String<Buf, Char>& operator+=(String<Buf, Char>& lhs, const String<Buf, Char>& rhs)
{
lhs.buffer += rhs.buffer;
return lhs;
}
/**
Checking whether the strings are equal by the content and charset.
@param lhs First string to compare.
@param rhs Second string to compare.
@return True if they are equal, false if not.
**/
template<typename Buf, typename Char>
bool operator==(const String<Buf, Char>& lhs, const String<Buf, Char>& rhs)
{
return lhs.buffer == rhs.buffer && lhs.charset == rhs.charset && lhs.codec_type == rhs.codec_type;
}
/**
Checking whether the strings are not equal by the content or charset.
@param lhs First string to compare.
@param rhs Second string to compare.
@return True if they are not equal, false if they are.
**/
template<typename Buf, typename Char>
bool operator!=(const String<Buf, Char>& lhs, const String<Buf, Char>& rhs)
{
return !operator==(lhs, rhs);
}
/**
Checking whether the first string is less than the second one.
@param lhs First string to compare.
@param rhs Second string to compare.
@return True if the first one is less than the second one, false otherwise.
**/
template<typename Buf, typename Char>
bool operator<(const String<Buf, Char>& lhs, const String<Buf, Char>& rhs)
{
return lhs.buffer < rhs.buffer;
}
/**
Checking whether the first string is greater than the second one.
@param lhs First string to compare.
@param rhs Second string to compare.
@return True if the first one is greater than the second one, false otherwise.
**/
template<typename Buf, typename Char>
bool operator>(const String<Buf, Char>& lhs, const String<Buf, Char>& rhs)
{
return operator<(rhs, lhs);
}
/**
Checking whether the first string is less or equal than the second one.
@param lhs First string to compare.
@param rhs Second string to compare.
@return True if the first one is less or equal than the second one, false otherwise.
**/
template<typename Buf, typename Char>
bool operator<=(const String<Buf, Char>& lhs, const String<Buf, Char>& rhs)
{
return !operator>(rhs, lhs);
}
/**
Checking whether the first string is greater or equal than the second one.
@param lhs First string to compare.
@param rhs Second string to compare.
@return True if the first one is greater or equal than the second one, false otherwise.
**/
template<typename Buf, typename Char>
bool operator>=(const String<Buf, Char>& lhs, const String<Buf, Char>& rhs)
{
return !operator<(rhs, lhs);
}
// String and std::string.
/**
Deals only with the buffers. The left character set is taken.
@param lhs First string to add.
@param rhs Second string to add.
@result Concatenated given strings.
**/
template<typename Buf, typename Char>
String<Buf, Char> operator+(const String<Buf, Char>& lhs, const std::string& rhs)
{
String<Buf, Char> result;
result.buffer = lhs.buffer + rhs;
result.charset = lhs.charset;
return result;
}
/**
Deals only with the buffers. The left character set is taken.
@param lhs String to be added to.
@param rhs String to add.
@result Second string concatenated to the first one.
**/
template<typename Buf, typename Char>
String<Buf, Char>& operator+=(String<Buf, Char>& lhs, const std::string& rhs)
{
lhs.buffer += rhs;
return lhs;
}
/**
Checking whether the strings are equal by the content.
@param lhs First string to compare.
@param rhs Second string to compare.
@return True if they are equal, false if not.
**/
template<typename Buf, typename Char>
bool operator==(const String<Buf, Char>& lhs, const std::string& rhs)
{
return lhs.buffer == rhs;
}
/**
Checking whether the strings are not equal by the content.
@param lhs First string to compare.
@param rhs Second string to compare.
@return True if they are not equal, false if they are.
**/
template<typename Buf, typename Char>
bool operator!=(const String<Buf, Char>& lhs, const std::string& rhs)
{
return !operator==(lhs, rhs);
}
/**
Checking whether the first string is less than the second one.
@param lhs First string to compare.
@param rhs Second string to compare.
@return True if the first one is less than the second one, false otherwise.
**/
template<typename Buf, typename Char>
bool operator<(const String<Buf, Char>& lhs, const std::string& rhs)
{
return lhs.buffer < rhs;
}
/**
Checking whether the first string is greater than the second one.
@param lhs First string to compare.
@param rhs Second string to compare.
@return True if the first one is greater than the second one, false otherwise.
**/
template<typename Buf, typename Char>
bool operator>(const String<Buf, Char>& lhs, const std::string& rhs)
{
return lhs.buffer > rhs;
}
/**
Checking whether the first string is less or equal than the second one.
@param lhs First string to compare.
@param rhs Second string to compare.
@return True if the first one is less or equal than the second one, false otherwise.
**/
template<typename Buf, typename Char>
bool operator<=(const String<Buf, Char>& lhs, const std::string& rhs)
{
return !operator>(rhs, lhs);
}
/**
Checking whether the first string is greater or equal than the second one.
@param lhs First string to compare.
@param rhs Second string to compare.
@return True if the first one is greater or equal than the second one, false otherwise.
**/
template<typename Buf, typename Char>
bool operator>=(const String<Buf, Char>& lhs, const std::string& rhs)
{
return !operator<(rhs, lhs);
}
#if defined(__cpp_char8_t)
// String and std::u8string.
/**
Deals only with the buffers. The left character set is taken.
@param lhs First string to add.
@param rhs Second string to add.
@result Concatenated given strings.
**/
template<typename Buf, typename Char>
String<Buf, Char> operator+(const String<Buf, Char>& lhs, const std::u8string& rhs)
{
String<Buf, Char> result;
result.buffer = lhs.buffer + rhs;
result.charset = lhs.charset;
return result;
}
/**
Deals only with the buffers. The left character set is taken.
@param lhs String to be added to.
@param rhs String to add.
@result Second string concatenated to the first one.
**/
template<typename Buf, typename Char>
String<Buf, Char>& operator+=(String<Buf, Char>& lhs, const std::u8string& rhs)
{
lhs.buffer += rhs;
return lhs;
}
/**
Checking whether the strings are equal by the content.
@param lhs First string to compare.
@param rhs Second string to compare.
@return True if they are equal, false if not.
**/
template<typename Buf, typename Char>
bool operator==(const String<Buf, Char>& lhs, const std::u8string& rhs)
{
return lhs.buffer == rhs;
}
/**
Checking whether the strings are not equal by the content.
@param lhs First string to compare.
@param rhs Second string to compare.
@return True if they are not equal, false if they are.
**/
template<typename Buf, typename Char>
bool operator!=(const String<Buf, Char>& lhs, const std::u8string& rhs)
{
return !operator==(lhs, rhs);
}
/**
Checking whether the first string is less than the second one.
@param lhs First string to compare.
@param rhs Second string to compare.
@return True if the first one is less than the second one, false otherwise.
**/
template<typename Buf, typename Char>
bool operator<(const String<Buf, Char>& lhs, const std::u8string& rhs)
{
return lhs.buffer < rhs;
}
/**
Checking whether the first string is greater than the second one.
@param lhs First string to compare.
@param rhs Second string to compare.
@return True if the first one is greater than the second one, false otherwise.
**/
template<typename Buf, typename Char>
bool operator>(const String<Buf, Char>& lhs, const std::u8string& rhs)
{
return lhs.buffer > rhs;
}
/**
Checking whether the first string is less or equal than the second one.
@param lhs First string to compare.
@param rhs Second string to compare.
@return True if the first one is less or equal than the second one, false otherwise.
**/
template<typename Buf, typename Char>
bool operator<=(const String<Buf, Char>& lhs, const std::u8string& rhs)
{
return !operator>(rhs, lhs);
}
/**
Checking whether the first string is greater or equal than the second one.
@param lhs First string to compare.
@param rhs Second string to compare.
@return True if the first one is greater or equal than the second one, false otherwise.
**/
template<typename Buf, typename Char>
bool operator>=(const String<Buf, Char>& lhs, const std::u8string& rhs)
{
return !operator<(rhs, lhs);
}
#endif
} // namespace
#ifdef _MSC_VER
#pragma warning(pop)
#endif
+371
View File
@@ -0,0 +1,371 @@
/*
dialog.hpp
----------
Copyright (C) 2016, Tomislav Karastojkovic (http://www.alepho.com).
Distributed under the FreeBSD license, see the accompanying file LICENSE or
copy at http://www.freebsd.org/copyright/freebsd-license.html.
*/
#pragma once
#include <string>
#include <stdexcept>
#include <chrono>
#include <memory>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include "export.hpp"
namespace mailio
{
/**
Dealing with network in a line oriented fashion.
**/
class dialog : public std::enable_shared_from_this<dialog>
{
public:
/**
Making a connection to the server.
@param hostname Server hostname.
@param port Server port.
@param timeout Network timeout after which I/O operations fail. If zero, then no timeout is set i.e. I/O operations are synchronous.
@throw dialog_error Server connecting failed.
@throw * `connect_async()`.
**/
dialog(const std::string& hostname, unsigned port, std::chrono::milliseconds timeout);
/**
Copy constructor.
@param other Object to copy.
**/
dialog(const dialog& other);
/**
Closing the connection.
**/
virtual ~dialog() = default;
dialog(dialog&&) = delete;
void operator=(const dialog&) = delete;
void operator=(dialog&&) = delete;
virtual void connect();
/**
Sending a line to network synchronously or asynchronously, depending of the timeout value.
@param line Line to send.
@throw * `send_sync<Socket>(Socket&, const std::string&)`, `send_async<Socket>(Socket&, const std::string&)`.
**/
virtual void send(const std::string& line);
/**
Receiving a line from network.
@param raw Flag if the receiving is raw (no CRLF is truncated) or not.
@return Line read from network.
@throw * `receive_sync<Socket>(Socket&, bool)`, `receive_async<Socket>(Socket&, bool)`.
**/
virtual std::string receive(bool raw = false);
protected:
/**
Sending a line to network in synchronous manner.
@param socket Socket to use for I/O.
@param line Line to send.
@throw dialog_error Network sending error.
**/
template<typename Socket>
void send_sync(Socket& socket, const std::string& line);
/**
Receiving a line from network in synchronous manner.
@param socket Socket to use for I/O.
@param raw Flag if the receiving is raw (no CRLF is truncated) or not.
@return line Line received.
@throw dialog_error Network sending error.
**/
template<typename Socket>
std::string receive_sync(Socket& socket, bool raw);
/**
Connecting to the host within the given timeout period.
@throw dialog_error Server connecting failed.
@throw dialog_error Server connecting timed out.
**/
void connect_async();
/**
Sending a line over network within the given timeout period.
@param socket Socket to use for I/O.
@param line Line to send.
@throw dialog_error Network sending failed.
@throw dialog_error Network sending timed out.
**/
template<typename Socket>
void send_async(Socket& socket, std::string line);
/**
Receiving a line over network within the given timeout period.
@param socket Socket to use for I/O.
@param raw Flag if the receiving is raw (no CRLF is truncated) or not.
@return line Line received.
@throw dialog_error Network receiving failed.
@throw dialog_error Network receiving timed out.
**/
template<typename Socket>
std::string receive_async(Socket& socket, bool raw);
/**
Waiting for an asynchronous, reporting an error when the timer expires.
@param has_op Asynchronous operation flag whether it finishes.
@param op_error Flag whether an operation encountered an error.
@param expired_msg Message when an operation times out.
@param op_msg Message when a network operation fails.
@todo `op_error` becomes redundant by `error`.
**/
void wait_async(const bool& has_op, const bool& op_error, const char* expired_msg, const char* op_msg,
const boost::system::error_code& error);
/**
Checking if the timeout is reached.
**/
void check_timeout();
/**
Timeout handler which sets the timer flag to expired.
@param error Result of the asynchronous operation.
**/
void timeout_handler(const boost::system::error_code& error);
/**
Server hostname.
**/
const std::string hostname_;
/**
Server port.
**/
const unsigned int port_;
/**
Asio input/output service.
**/
static boost::asio::io_context ios_;
/**
Socket connection.
**/
std::shared_ptr<boost::asio::ip::tcp::socket> socket_;
/**
Timer to check the timeout.
**/
std::shared_ptr<boost::asio::steady_timer> timer_;
/**
Timeout on I/O operations in milliseconds.
**/
std::chrono::milliseconds timeout_;
/**
Flag to show whether the timeout has expired.
@todo Should be atomic?
**/
bool timer_expired_;
/**
Stream buffer associated to the socket.
**/
std::shared_ptr<boost::asio::streambuf> strmbuf_;
/**
Input stream associated to the buffer.
**/
std::shared_ptr<std::istream> istrm_;
};
/**
Secure version of `dialog` class.
**/
class dialog_ssl : public dialog
{
public:
/**
SSL options to set on a socket.
**/
struct ssl_options_t
{
/**
Methods as supported by Asio.
**/
boost::asio::ssl::context::method method;
/**
Peer verification bitmask supported by Asio.
**/
boost::asio::ssl::verify_mode verify_mode;
};
/**
Making a connection to the server.
@param hostname Server hostname.
@param port Server port.
@param timeout Network timeout after which I/O operations fail. If zero, then no timeout is set i.e. I/O operations are synchronous.
@param options SSL options to set.
@throw * `dialog::dialog(const std::string&, unsigned)`.
**/
dialog_ssl(const std::string& hostname, unsigned port, std::chrono::milliseconds timeout, const ssl_options_t& options);
/**
Calling the parent constructor, initializing the SSL socket.
@param other Plain connection to use for the SSL.
@param options SSL options to set.
**/
dialog_ssl(const dialog& other, const ssl_options_t& options);
/**
Default copy constructor.
**/
dialog_ssl(const dialog_ssl&) = default;
/**
Default destructor.
**/
virtual ~dialog_ssl() = default;
dialog_ssl(dialog_ssl&&) = delete;
void operator=(const dialog_ssl&) = delete;
void operator=(dialog_ssl&&) = delete;
/**
Sending an encrypted or unecrypted line, depending of SSL flag.
@param line Line to send.
@throw * `dialog::send(const std::string&)`, `send_sync<Socket>(Socket&, const std::string&)`, `send_async<Socket>(Socket&, const std::string&)`.
**/
void send(const std::string& line);
/**
Receiving an encrypted or unecrypted line, depending of SSL state.
@param raw Flag if the receiving is raw (no CRLF is truncated) or not.
@return Line read from network
@throw * `dialog::receive()`, `receive_sync<Socket>(Socket&, bool)`, `receive_async<Socket>(Socket&, bool)`.
**/
std::string receive(bool raw = false);
/**
Replacing a TCP socket with an SSL one.
@param dlg TCP socket to be replaced.
@param options SSL options of the socket.
@throw * `dialog_ssl::dialog_ssl(dialog&, const ssl_options_t&)`.
**/
static std::shared_ptr<dialog_ssl> to_ssl(const std::shared_ptr<dialog> dlg, const dialog_ssl::ssl_options_t& options);
protected:
/**
Flag if SSL is chosen or not.
**/
bool ssl_;
/**
SSL context (when used).
**/
std::shared_ptr<boost::asio::ssl::context> context_;
/**
SSL socket (when used).
**/
std::shared_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket&>> ssl_socket_;
};
/**
Error thrown by `dialog` client.
**/
class dialog_error : public std::runtime_error
{
public:
/**
Calling the parent constructor.
@param msg Error message.
@param details Detailed message.
**/
dialog_error(const std::string& msg, const std::string& details) : std::runtime_error(msg), details_(details)
{
}
/**
Calling the parent constructor.
@param msg Error message.
@param details Detailed message.
**/
dialog_error(const char* msg, const std::string& details) : std::runtime_error(msg), details_(details)
{
}
dialog_error(const dialog_error&) = default;
dialog_error(dialog_error&&) = default;
~dialog_error() = default;
dialog_error& operator=(const dialog_error&) = default;
dialog_error& operator=(dialog_error&&) = default;
/**
Gets the detailed error message.
@return Detailed error message.
**/
std::string details() const;
protected:
/**
Message provided by Asio.
**/
std::string details_;
};
} // namespace mailio
+43
View File
@@ -0,0 +1,43 @@
#ifndef MAILIO_EXPORT_H
#define MAILIO_EXPORT_H
#ifdef MAILIO_STATIC_DEFINE
# define MAILIO_EXPORT
# define MAILIO_NO_EXPORT
#else
# ifndef MAILIO_EXPORT
# ifdef mailio_EXPORTS
/* We are building this library */
# define MAILIO_EXPORT __attribute__((visibility("default")))
# else
/* We are using this library */
# define MAILIO_EXPORT __attribute__((visibility("default")))
# endif
# endif
# ifndef MAILIO_NO_EXPORT
# define MAILIO_NO_EXPORT __attribute__((visibility("hidden")))
# endif
#endif
#ifndef MAILIO_DEPRECATED
# define MAILIO_DEPRECATED __attribute__ ((__deprecated__))
#endif
#ifndef MAILIO_DEPRECATED_EXPORT
# define MAILIO_DEPRECATED_EXPORT MAILIO_EXPORT MAILIO_DEPRECATED
#endif
#ifndef MAILIO_DEPRECATED_NO_EXPORT
# define MAILIO_DEPRECATED_NO_EXPORT MAILIO_NO_EXPORT MAILIO_DEPRECATED
#endif
/* NOLINTNEXTLINE(readability-avoid-unconditional-preprocessor-if) */
#if 0 /* DEFINE_NO_DEPRECATED */
# ifndef MAILIO_NO_DEPRECATED
# define MAILIO_NO_DEPRECATED
# endif
#endif
#endif /* MAILIO_EXPORT_H */
File diff suppressed because it is too large Load Diff
+198
View File
@@ -0,0 +1,198 @@
/*
mailboxes.hpp
-------------
Copyright (C) 2017, Tomislav Karastojkovic (http://www.alepho.com).
Distributed under the FreeBSD license, see the accompanying file LICENSE or
copy at http://www.freebsd.org/copyright/freebsd-license.html.
*/
#pragma once
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4251)
#endif
#include <string>
#include <vector>
#include "codec.hpp"
#include "export.hpp"
namespace mailio
{
/**
Mail as name and address.
**/
struct MAILIO_EXPORT mail_address
{
/**
Name part of the mail.
**/
string_t name;
/**
Address part of the mail.
**/
std::string address;
/**
Default constructor.
**/
mail_address() = default;
/**
Setting a mail name and address.
@param mail_name Name to set.
@param mail_address Address to set.
**/
mail_address(const string_t& mail_name, const std::string& mail_address);
/**
Checking if a mail is empty, i.e. name and address are empty.
@return True if empty, false if not.
**/
bool empty() const;
/**
Clearing name and address.
**/
void clear();
};
/**
Mail group with the name and members.
**/
struct MAILIO_EXPORT mail_group
{
/**
Mail group name.
**/
std::string name;
/**
Mail group members.
**/
std::vector<mail_address> members;
/**
Default constructor.
**/
mail_group() = default;
/**
Setting a group name and members.
@param group_name Name of a group.
@param group_mails Members of a group.
**/
mail_group(const std::string& group_name, const std::vector<mail_address>& group_mails);
/**
Default destructor.
**/
~mail_group() = default;
/**
Adding a list of mails to members.
@param mails Mail list to add.
**/
void add(const std::vector<mail_address>& mails);
/**
Adding a mail to members.
@param mail Mail to add.
**/
void add(const mail_address& mail);
/**
Clearing the group name and members.
**/
void clear();
};
/**
List of mail addresses and groups.
**/
struct MAILIO_EXPORT mailboxes
{
/**
Mail addresses.
**/
std::vector<mail_address> addresses;
/**
Mail groups.
**/
std::vector<mail_group> groups;
/**
Default constructor.
**/
mailboxes() = default;
/**
Default copy constructor.
**/
mailboxes(const mailboxes&) = default;
/**
Default move constructor.
**/
mailboxes(mailboxes&&) = default;
/**
Creating a mailbox with the given addresses and groups.
@param address_list Mail addresses to set.
@param group_list Mail groups to set.
**/
mailboxes(std::vector<mail_address> address_list, std::vector<mail_group> group_list);
/**
Default destructor.
**/
~mailboxes() = default;
/**
Default copy assignment operator.
**/
mailboxes& operator=(const mailboxes&) = default;
/**
Default move assignment operator.
**/
mailboxes& operator=(mailboxes&&) = default;
/**
Checking if the mailbox is empty.
@return True if empty, false if not.
**/
bool empty() const;
/**
Clearing the list of addresses.
**/
void clear();
};
} // namespace mailio
#ifdef _MSC_VER
#pragma warning(pop)
#endif
+803
View File
@@ -0,0 +1,803 @@
/*
message.hpp
-----------
Copyright (C) 2016, Tomislav Karastojkovic (http://www.alepho.com).
Distributed under the FreeBSD license, see the accompanying file LICENSE or
copy at http://www.freebsd.org/copyright/freebsd-license.html.
*/
#pragma once
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4251)
#endif
#include <string>
#include <vector>
#include <list>
#include <utility>
#include <stdexcept>
#include <memory>
#include <tuple>
#include <istream>
#include <boost/date_time.hpp>
#include "q_codec.hpp"
#include "mime.hpp"
#include "mailboxes.hpp"
#include "export.hpp"
namespace mailio
{
/**
Options to customize the formatting of a message. Used by message::format().
**/
struct message_format_options_t
{
/**
Flag if the leading dot should be escaped.
**/
bool dot_escape = false;
/**
Flag whether bcc addresses should be added.
**/
bool add_bcc_header = false;
};
/**
Mail message and applied parsing/formatting algorithms.
**/
class MAILIO_EXPORT message : public mime
{
public:
/**
Character to separate mail addresses in a list.
**/
static const char ADDRESS_SEPARATOR = ',';
/**
Mail group name separator from the list of addresses.
**/
static const char MAILGROUP_NAME_SEPARATOR = ':';
/**
Separator of several mail groups.
**/
static const char MAILGROUP_SEPARATOR = ';';
/**
Calling parent destructor, initializing date and time to local time in utc time zone, other members set to default.
**/
message();
/**
Default copy constructor.
**/
message(const message&) = default;
/**
Default move constructor.
@todo Default implementation is probably a bug, but not manifested yet.
**/
message(message&&) = default;
/**
Default destructor.
**/
~message() = default;
/**
Default assignment operator.
**/
message& operator=(const message&) = default;
/**
Default move assignment operator.
@todo Default implementation is probably a bug, but not manifested yet.
**/
message& operator=(message&&) = default;
/**
Formatting the message to a string.
If a line contains leading dot, then it can be escaped as required by mail protocols.
@param message_str Resulting message as string.
@param opts Options to customize formatting.
@throw * `format_header(format_options)`, `format_content(bool)`, `mime::format(string&, bool)`.
**/
void format(std::string& message_str, const message_format_options_t& opts = message_format_options_t{}) const;
/**
Overload of `format(string&, const message_format_options&)`.
Because of the way the u8string is comverted to string, it's more expensive when used with C++20.
**/
#if defined(__cpp_char8_t)
void format(std::u8string& message_str, const message_format_options_t& = message_format_options_t{}) const;
#endif
/**
Parsing a message from a string.
Essentially, the method calls the same one from `mime` and checks for errors.
@param message_str String to parse.
@param dot_escape Flag if the leading dot should be escaped.
@throw message_error No author address.
@throw * `mime::parse(const string&, bool)`.
**/
void parse(const std::string& message_str, bool dot_escape = false);
/**
Overload of `parse(const string&, bool)`.
Because of the way the u8string is comverted to string, it's more expensive when used with C++20.
**/
#if defined(__cpp_char8_t)
void parse(const std::u8string& mime_string, bool dot_escape = false);
#endif
/**
Checking if the mail is empty.
@return True if empty, false if not.
**/
bool empty() const;
/**
Setting the author to a given address.
The given address is set as the only one, others are deleted.
@param mail Mail address to set.
**/
void from(const mail_address& mail);
/**
Getting the author address.
@return Author mail address.
**/
mailboxes from() const;
/**
Adding an addrress to the author field.
@param mail Mail address to set.
**/
void add_from(const mail_address& mail);
/**
Formatting the author as string.
@return Author name and address as formatted string.
@throw * `format_address(const string&, const string&)`.
**/
std::string from_to_string() const;
/**
Setting the sender to the given address.
@param mail Mail address to set.
**/
void sender(const mail_address& mail);
/**
Getting the sender address.
@return Sender mail address.
**/
mail_address sender() const;
/**
Formatting the sender as string.
@return Sender name and address as formatted string.
@throw * `format_address(const string&, const string&)`.
**/
std::string sender_to_string() const;
/**
Setting the reply address.
@param mail Reply mail address.
**/
void reply_address(const mail_address& mail);
/**
Getting the reply address.
@return Reply mail address.
**/
mail_address reply_address() const;
/**
Formatting the reply name and address as string.
@return Reply name and address as string.
@throw * `format_address(const string&, const string&)`.
**/
std::string reply_address_to_string() const;
/**
Adding a recipent name and address.
@param mail Address to add.
**/
void add_recipient(const mail_address& mail);
/**
Adding a recipient group.
@param group Group to add.
**/
void add_recipient(const mail_group& group);
/**
Getting the recipients.
@return List of recipients.
**/
mailboxes recipients() const;
/**
Getting the recipients names and addresses as string.
@return Recipients names and addresses as string.
@throw * `format_mailbox`.
**/
std::string recipients_to_string() const;
/**
Adding a CC recipent name and address.
@param mail Mail address to set.
**/
void add_cc_recipient(const mail_address& mail);
/**
Adding a CC recipient group.
@param group Group to add.
**/
void add_cc_recipient(const mail_group& group);
/**
Getting the CC recipients names and addresses.
@return List of CC recipients.
**/
mailboxes cc_recipients() const;
/**
Getting the CC recipients names and addresses as string.
@return CC recipients names and addresses as string.
@throw * `format_mailbox`.
**/
std::string cc_recipients_to_string() const;
/**
Adding a BCC recipent name and address.
@param mail Mail address to set.
**/
void add_bcc_recipient(const mail_address& mail);
/**
Adding a BCC recipient group.
@param group Group to add.
**/
void add_bcc_recipient(const mail_group& group);
/**
Getting the BCC recipients names and addresses.
@return List of BCC recipients.
**/
mailboxes bcc_recipients() const;
/**
Getting the BCC recipients names and addresses as string.
@return BCC recipients names and addresses as string.
@throw * `format_mailbox`.
**/
std::string bcc_recipients_to_string() const;
/**
Setting the disposition notification mail address.
@param mail Mail address to set.
**/
void disposition_notification(const mail_address& mail);
/**
Getting the disposition notification mail address.
@return Dispostion notification mail address.
**/
mail_address disposition_notification() const;
/**
Getting the disposition notification mail address as string.
@return Disposition notification mail address as string.
@throw * `format_address(const string&, const string&)`.
**/
std::string disposition_notification_to_string() const;
/**
Setting the message ID.
@param id The message ID in the format `string1@string2`.
@throw message_error Invalid message ID.
**/
void message_id(std::string id);
/**
Getting the message ID.
@return Message ID.
**/
std::string message_id() const;
/**
Adding the in-reply-to ID.
@param in-reply ID of the in-reply-to header.
**/
void add_in_reply_to(const std::string& in_reply);
/**
Getting the in-reply-to ID.
@return List of in-reply-to IDs.
**/
std::vector<std::string> in_reply_to() const;
/**
Adding the reference ID to the list.
@param reference_id Reference ID.
**/
void add_references(const std::string& reference_id);
/**
Getting the references list of IDs.
@return List of references IDs.
**/
std::vector<std::string> references() const;
/**
Setting the subject.
@param mail_subject Subject to set.
@param sub_codec Codec of the subject to use.
*/
void subject(const std::string& mail_subject, codec::codec_t sub_codec = codec::codec_t::ASCII);
/**
Setting the raw subject.
@param mail_subject Subject to set.
*/
void subject_raw(const string_t& mail_subject);
#if defined(__cpp_char8_t)
/**
Setting the subject.
@param mail_subject Subject to set.
@param sub_codec Codec of the subject to use.
*/
void subject(const std::u8string& mail_subject, codec::codec_t sub_codec = codec::codec_t::ASCII);
/**
Setting the raw subject.
@param mail_subject Subject to set.
*/
void subject_raw(const u8string_t& mail_subject);
#endif
/**
Getting the subject.
@return Subject value.
**/
std::string subject() const;
/**
Getting the raw subject.
@return Subject value.
**/
string_t subject_raw() const;
/**
Getting the date, time and zone.
@return Date, time and zone.
**/
boost::local_time::local_date_time date_time() const;
/**
Setting the date, time and zone.
@param the_date_time Date, time and zone to set.
**/
void date_time(const boost::local_time::local_date_time& mail_dt);
/**
Attaching a list of streams.
If the content is set, attaching a file moves the content to the first MIME part. Thus, the content and the attached files are MIME parts, as described in
RFC 2046 section 5.1. The consequence is that the content remains empty afterwards.
@param attachments Files to attach. Each tuple consists of a stream, attachment name and content type.
@throw * `mime::content_type(const content_type_t&)`, `mime::content_transfer_encoding(content_transfer_encoding_t)`,
`mime::content_disposition(content_disposition_t)`.
**/
void attach(const std::list<std::tuple<std::istream&, string_t, content_type_t>>& attachments);
/**
Getting the number of attachments.
@return Number of attachments.
**/
std::size_t attachments_size() const;
/**
Getting the attachment at the given index.
@param index Index of the attachment.
@param att_strm Stream to write the attachment.
@param att_name Name of the attachment.
@throw message_error Bad attachment index.
@todo The attachment name should be also `string_t`.
**/
void attachment(std::size_t index, std::ostream& att_strm, string_t& att_name) const;
/**
Adding another header.
Adding a header defined by other methods leads to the undefined behaviour.
@param name Header name.
@param value Header value.
@todo Disallowing standard headers defined elsewhere?
**/
void add_header(const std::string& name, const std::string& value);
/**
Removing another header.
Removing a header defined by other methods leads to the undefined behaviour.
@param name Header to remove.
**/
void remove_header(const std::string& name);
/**
Returning the other headers.
@return Message headers.
**/
const headers_t& headers() const;
/**
Getting a list of message flags.
@return Vector of flags as strings.
**/
const std::vector<std::string>& flags() const;
/**
Setting a list of message flags.
@param flag_list Flags to set.
**/
void flags(const std::vector<std::string>& flag_list);
/**
Adding a single flag.
@param flag Flag to add.
**/
void add_flag(const std::string& flag);
protected:
/**
Printable ASCII characters without the alphanumerics, double quote, comma, colon, semicolon, angle and square brackets and monkey.
**/
static const std::string ATEXT;
/**
Printable ASCII characters without the alphanumerics, brackets and backslash.
**/
static const std::string DTEXT;
/**
`From` header name.
**/
static const std::string FROM_HEADER;
/**
`Sender` header name.
**/
static const std::string SENDER_HEADER;
/**
`Reply-To` header name.
**/
static const std::string REPLY_TO_HEADER;
/**
`To` header name.
**/
static const std::string TO_HEADER;
/**
`Cc` header name.
**/
static const std::string CC_HEADER;
/**
`Bcc` header name.
**/
static const std::string BCC_HEADER;
/**
`Message-ID` header name.
**/
static const std::string MESSAGE_ID_HEADER;
/**
`In-Reply-To` header name.
**/
static const std::string IN_REPLY_TO_HEADER;
/**
`References` header name.
**/
static const std::string REFERENCES_HEADER;
/**
Subject header name.
**/
static const std::string SUBJECT_HEADER;
/**
Date header name.
**/
static const std::string DATE_HEADER;
/**
Disposition notification header name.
**/
static const std::string DISPOSITION_NOTIFICATION_HEADER;
/**
Mime version header name.
**/
static const std::string MIME_VERSION_HEADER;
/**
Formatting the header to a string.
@return Header as string.
@throw message_error No boundary for multipart message.
@throw message_error No author.
@throw message_error No sender for multiple authors.
@throw * `mime::format_header()`.
**/
virtual std::string format_header(bool add_bcc_header) const;
/**
Parsing a header line for a specific header.
@param header_line Header line to be parsed.
@throw message_error Line policy overflow in a header.
@throw message_error Empty author header.
@throw * `mime::parse_header_line(const string&)`, `mime::parse_header_name_value(const string&, string&, string&)`,
`parse_address_list(const string&)`, `parse_subject(const string&)`, `parse_date(const string&)`.
**/
virtual void parse_header_line(const std::string& header_line);
/**
Formatting a list of addresses to string.
Multiple addresses are put into separate lines.
@param mailbox_list Mailbox to format.
@return Mailbox as string.
@throw message_error Formatting failure of address list, bad group name.
@throw * `format_address(const string&, const string&)`.
**/
std::string format_address_list(const mailboxes& mailbox_list, const std::string& header_name = "") const;
/**
Formatting a name and an address.
If the name is in ASCII or the header codec set to UTF8, then it is written in raw format. Otherwise, the encoding is performed. The header folding is
performed if necessary.
@param name Mail name.
@param address Mail address.
@param header_name Header name of the address header.
@return The mail name and address formatted.
@throw message_error Formatting failure of name.
@throw message_error Formatting failure of address.
**/
std::string format_address(const string_t& name, const std::string& address, const std::string& header_name) const;
/**
Formatting the subject which can be ASCII or UTF-8.
@return Formatted subject.
**/
std::string format_subject() const;
/**
Formatting email date.
@return Date for the email format.
**/
std::string format_date() const;
/**
Parsing a string into vector of names and addresses.
@param address_list String to parse.
@return Vector of names and addresses.
@throw message_error Parsing failure of address or group at.
@throw message_error Parsing failure of group at.
@throw message_error Parsing failure of name or address at.
@throw message_error Parsing failure of address at.
@throw message_error Parsing failure of name at.
@throw message_error Parsing failure of comment at.
**/
mailboxes parse_address_list(const std::string& address_list);
/**
Parsing a string into date and time.
@param date_str Date string to parse.
@return Date and time translated to local time zone.
@throw message_error Parsing failure of date.
**/
boost::local_time::local_date_time parse_date(const std::string& date_str) const;
/**
Splitting string with Q encoded fragments into separate strings.
@param text String with Q encoded fragments.
@return Q encoded fragments as separate strings.
**/
static std::vector<std::string> split_qc_string(const std::string& text);
/**
Parsing a subject which can be ASCII or UTF-8.
The result is string either ASCII or UTF-8 encoded. If another encoding is used like ISO-8859-X, then the result is undefined.
@param subject Subject to parse.
@return Parsed subject and charset.
@throw message_error Parsing failure of Q encoding.
@throw * `q_codec::decode(const string&)`.
**/
std::tuple<std::string, std::string, codec::codec_t>
parse_subject(const std::string& subject);
/**
Parsing a name part of a mail ASCII or UTF-8 encoded.
The result is string ASCII or UTF-8 encoded. If another encoding is used, then it should be decoded by the method caller.
@param address_name Name part of mail.
@return Parsed name part of the address.
@throw message_error Inconsistent Q encodings.
@todo Not tested with charsets different than ASCII and UTF-8.
@todo Throwing errors when Q codec is invalid?
**/
string_t parse_address_name(const std::string& address_name);
/**
From name and address.
**/
mailboxes from_;
/**
Sender name and address.
**/
mail_address sender_;
/**
Reply address.
**/
mail_address reply_address_;
/**
List of recipients.
**/
mailboxes recipients_;
/**
List of CC recipients.
**/
mailboxes cc_recipients_;
/**
List of BCC recipients.
**/
mailboxes bcc_recipients_;
/**
Disposition notification address.
**/
mail_address disposition_notification_;
/**
Message ID.
**/
std::string message_id_;
/**
In reply to list of IDs.
**/
std::vector<std::string> in_reply_to_;
/**
References list of IDs.
**/
std::vector<std::string> references_;
/**
Message subject.
**/
string_t subject_;
/**
Message date and time with time zone.
**/
boost::local_time::local_date_time date_time_;
/**
Other headers not included into the known ones.
**/
headers_t headers_;
/**
Message flags obtained over the IMAP.
**/
std::vector<std::string> flags_;
};
[[deprecated]]
typedef mime_error message_error;
} // namespace mailio
#ifdef _MSC_VER
#pragma warning(pop)
#endif
File diff suppressed because it is too large Load Diff
+77
View File
@@ -0,0 +1,77 @@
/*
percent.hpp
-----------
Copyright (C) 2024, Tomislav Karastojkovic (http://www.alepho.com).
Distributed under the FreeBSD license, see the accompanying file LICENSE or
copy at http://www.freebsd.org/copyright/freebsd-license.html.
*/
#pragma once
#include <string>
#include <vector>
#include "codec.hpp"
#include "export.hpp"
namespace mailio
{
/**
Percent encoding and decoding as described in RFC 2231 section 4.
@todo Line policies not implemented.
**/
class MAILIO_EXPORT percent : public codec
{
public:
/**
Setting the encoder and decoder line policies.
@param line1_policy First line policy to set.
@param lines_policy Other lines policy than the first one to set.
**/
percent(std::string::size_type line1_policy, std::string::size_type lines_policy);
percent(const percent&) = delete;
percent(percent&&) = delete;
/**
Default destructor.
**/
~percent() = default;
void operator=(const percent&) = delete;
void operator=(percent&&) = delete;
/**
Encoding a string.
@param txt String to encode.
@return Encoded string.
@todo Implement the line policies.
@todo Replace `txt` to be `string_t`, then no need for the charset parameter.
**/
std::vector<std::string> encode(const std::string& txt, const std::string& charset) const;
/**
Decoding a percent encoded string.
@param txt String to decode.
@return Decoded string.
@todo Implement the line policies.
**/
std::string decode(const std::string& txt) const;
};
} // namespace mailio
+368
View File
@@ -0,0 +1,368 @@
/*
pop3.hpp
--------
Copyright (C) 2016, Tomislav Karastojkovic (http://www.alepho.com).
Distributed under the FreeBSD license, see the accompanying file LICENSE or
copy at http://www.freebsd.org/copyright/freebsd-license.html.
*/
#pragma once
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4251)
#endif
#include <string>
#include <vector>
#include <map>
#include <utility>
#include <istream>
#include <chrono>
#include <optional>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/asio/streambuf.hpp>
#include "dialog.hpp"
#include "message.hpp"
#include "export.hpp"
namespace mailio
{
/**
POP3 client implementation.
The order of connection is prioritized as: start tls, ssl, plain tcp. By default, POP3 tries to connect over start tls. If the start tls is switched off, then it
connects over ssl. If the ssl is switched off, then it connects over plain tcp.
The start tls needs ssl options to be set so they could be used once the connection is switched from tcp to tls. For that reason, the ssl options are
internally set to default values, but they can be modified over `ssl_options()`. If a user does not want the start tls, it can turn it off over
`start_tls(false)`. Turning off the start tls switches POP3 to the ssl connection. In order to switch off ssl completely, it has to be done explicitly by setting
`ssl_options(std::nullopt)`. With both start tls and ssl switched off, the POP3 connection is plain tcp.
**/
class MAILIO_EXPORT pop3
{
public:
/**
Available authentication methods.
The following mechanisms are allowed:
- LOGIN: The username and password are sent in plain format.
**/
enum class auth_method_t {LOGIN};
/**
Messages indexed by their order number containing sizes in octets.
**/
typedef std::map<unsigned, unsigned long> message_list_t;
/**
Message order numbers and their corresponding unique IDs (a UIDL response from server).
**/
typedef std::map<unsigned, std::string> uidl_list_t;
/**
Mailbox statistics structure.
**/
struct mailbox_stat_t
{
/**
Number of messages in the mailbox.
**/
unsigned int messages_no;
/**
Size of the mailbox.
**/
unsigned long mailbox_size;
/**
Setting the number of messages and mailbox size to zero.
**/
mailbox_stat_t() : messages_no(0), mailbox_size(0)
{
}
};
/**
Making connection to a server.
@param hostname Hostname of the server.
@param port Port of the server.
@param timeout Network timeout after which I/O operations fail. If zero, then no timeout is set i.e. I/O operations are synchronous.
@throw * `dialog::dialog(const string&, unsigned)`.
**/
pop3(const std::string& hostname, unsigned port, std::chrono::milliseconds timeout = std::chrono::milliseconds(0));
/**
Sending the quit command and closing the connection.
**/
virtual ~pop3();
pop3(const pop3&) = delete;
pop3(pop3&&) = delete;
void operator=(const pop3&) = delete;
void operator=(pop3&&) = delete;
/**
Authentication with the given credentials.
The method should be called only once on an existing object - it is not possible to authenticate again within the same connection.
@param username Username to authenticate.
@param password Password to authenticate.
@param method Authentication method to use.
@return The server greeting message.
@throw * `connect()`, `auth_login(const string&, const string&)`.
**/
std::string authenticate(const std::string& username, const std::string& password, auth_method_t method);
/**
Listing the size in octets of a message or all messages in a mailbox.
@param message_no Number of the message to list. If zero, then all messages are listed.
@return Message list.
@throw pop3_error Listing message failure.
@throw pop3_error Listing all messages failure.
@throw pop3_error Parser failure.
@throw * `parse_status(const string&)`, `dialog::send(const string&)`, `dialog::receive()`.
@todo This method is perhaps useless and should be removed.
**/
message_list_t list(unsigned message_no = 0);
/**
Getting the unique ID of a message or all messages in a mailbox (UIDL command; might not be supported by server).
@param message_no Number of the message to get ID for. If zero, then all messages are listed.
@return Uidl list.
@throw pop3_error Listing message failure.
@throw pop3_error Listing all messages failure.
@throw pop3_error Parser failure.
@throw * `parse_status(const string&)`, `dialog::send(const string&)`, `dialog::receive()`.
**/
uidl_list_t uidl(unsigned message_no = 0);
/**
Fetching the mailbox statistics.
@return Number of messages and mailbox size in octets.
@throw pop3_error Reading statistics failure.
@throw pop3_error Parser failure.
@throw * `parse_status(const string&)`, `dialog::send(const string&)`, `dialog::receive()`.
**/
mailbox_stat_t statistics();
/**
Fetching a message.
The flag for fetching the header only uses a different POP3 command (than for retrieving the full messsage) which is not mandatory by POP3. In case the
command fails, the method will not report an error but rather the `msg` parameter will be empty.
@param message_no Message number to fetch.
@param msg Fetched message.
@param header_only Flag if only the message header should be fetched.
@throw pop3_error Fetching message failure.
@throw * `parse_status(const string&)`, `dialog::send(const string&)`, `dialog::receive()`.
**/
void fetch(unsigned long message_no, message& msg, bool header_only = false);
/**
Removing a message in the mailbox.
@param message_no Message number to remove.
@throw pop3_error Removing message failure.
@throw * `parse_status(const string&)`, `dialog::send(const string&)`, `dialog::receive()`.
**/
void remove(unsigned long message_no);
/**
Setting the start TLS option.
@param is_tls If true, the start TLS option is turned on, otherwise is turned off.
**/
void start_tls(bool is_tls);
/**
Setting SSL options.
@param options SSL options to set.
**/
void ssl_options(const std::optional<dialog_ssl::ssl_options_t> options = std::nullopt);
protected:
/**
Character used by POP3 to separate tokens.
**/
static const char TOKEN_SEPARATOR_CHAR{' '};
/**
Initializing a connection to the server.
@return The server greeting message.
@throw pop3_error Connection to server failure.
@throw * `parse_status(const string&)`, `dialog::receive()`.
**/
std::string connect();
/**
Authentication of a user.
@param username Username to authenticate.
@param password Password to authenticate.
@throw pop3_error Username rejection.
@throw pop3_error Password rejection.
@throw * `parse_status(const string&)`, `dialog::send(const string&)`, `dialog::receive()`.
**/
void auth_login(const std::string& username, const std::string& password);
/**
Switching to TLS layer.
@throw pop3_error Start TLS failure.
@throw * `parse_status(const string&)`, `dialog::send(const string&)`, `dialog::receive()`, `dialog::to_ssl()`.
**/
void switch_tls();
/**
Parsing a response line for the status.
@param line Response line to parse.
@return Tuple with the status and rest of the line.
@throw pop3_error Response status unknown.
**/
std::tuple<std::string, std::string> parse_status(const std::string& line);
/**
Dialog to use for send/receive operations.
**/
std::shared_ptr<dialog> dlg_;
/**
SSL options to set.
**/
std::optional<dialog_ssl::ssl_options_t> ssl_options_;
/**
Flag to switch to the TLS.
**/
bool is_start_tls_;
};
/**
Secure version of POP3 client.
**/
class MAILIO_DEPRECATED pop3s : public pop3
{
public:
/**
Available authentication methods over the TLS connection.
The following mechanisms are allowed:
- LOGIN: The username and password are sent in plain format.
- START_TLS: For the TCP connection, a TLS negotiation is asked before sending the login parameters.
**/
enum class auth_method_t {LOGIN, START_TLS};
/**
Making a connection to server.
Parent constructor is called to do all the work.
@param hostname Hostname of the server.
@param port Port of the server.
@param timeout Network timeout after which I/O operations fail. If zero, then no timeout is set i.e. I/O operations are synchronous.
@throw * `pop3::pop3(const string&, unsigned)`.
**/
pop3s(const std::string& hostname, unsigned port, std::chrono::milliseconds timeout = std::chrono::milliseconds(0));
/**
Sending the quit command and closing the connection.
Parent destructor is called to do all the work.
**/
~pop3s() = default;
pop3s(const pop3s&) = delete;
pop3s(pop3s&&) = delete;
void operator=(const pop3s&) = delete;
void operator=(pop3s&&) = delete;
/**
Authenticating with the given credentials.
@param username Username to authenticate.
@param password Password to authenticate.
@param method Authentication method to use.
@return The server greeting message.
@throw * `start_tls()`, `pop3::auth_login(const string&, const string&)`.
**/
std::string authenticate(const std::string& username, const std::string& password, auth_method_t method);
/**
Setting SSL options.
@param options SSL options to set.
**/
void ssl_options(const dialog_ssl::ssl_options_t& options);
};
/**
Error thrown by POP3 client.
**/
class pop3_error : public dialog_error
{
public:
/**
Calling the parent constructor.
@param msg Error message.
@param details Detailed message.
**/
pop3_error(const std::string& msg, const std::string& details);
/**
Calling the parent constructor.
@param msg Error message.
@param details Detailed message.
**/
pop3_error(const char* msg, const std::string& details);
pop3_error(const pop3_error&) = default;
pop3_error(pop3_error&&) = default;
~pop3_error() = default;
pop3_error& operator=(const pop3_error&) = default;
pop3_error& operator=(pop3_error&&) = default;
};
} // namespace mailio
#ifdef _MSC_VER
#pragma warning(pop)
#endif
+135
View File
@@ -0,0 +1,135 @@
/*
q_codec.hpp
-----------
Copyright (C) 2017, Tomislav Karastojkovic (http://www.alepho.com).
Distributed under the FreeBSD license, see the accompanying file LICENSE or
copy at http://www.freebsd.org/copyright/freebsd-license.html.
*/
#pragma once
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4251)
#endif
#include <string>
#include <vector>
#include <tuple>
#include "codec.hpp"
#include "export.hpp"
namespace mailio
{
/**
Q codec.
ASCII and UTF-8 charsets are recognized.
**/
class MAILIO_EXPORT q_codec : public codec
{
public:
/**
Setting the encoder and decoder line policies.
@param line1_policy First line policy to set.
@param lines_policy Other lines policy than the first one to set.
@param codec_method Method for encoding/decoding.
@throw codec_error Bad encoding method.
**/
q_codec(std::string::size_type line1_policy, std::string::size_type lines_policy);
q_codec(const q_codec&) = delete;
q_codec(q_codec&&) = delete;
/**
Default destructor.
**/
~q_codec() = default;
void operator=(const q_codec&) = delete;
void operator=(q_codec&&) = delete;
/**
Encoding a text by applying the given method.
@param text String to encode.
@param charset Charset used by the string.
@param method Allowed encoding methods.
@return Encoded string.
@todo Merge text and charset into a single parameter of type `string_t`.
@todo It must take another parameter for the header name length in order to remove the hardcoded constant.
**/
std::vector<std::string> encode(const std::string& text, const std::string& charset, codec_t method) const;
/**
Decoding a string.
@param text String to decode.
@return Decoded string, its charset and its codec method.
@throw codec_error Missing Q codec separator for charset.
@throw codec_error Missing Q codec separator for codec type.
@throw codec_error Missing last Q codec separator.
@throw codec_error Bad encoding method.
@throw * `decode_qp(const string&)`, `base64::decode(const string&)`.
**/
std::tuple<std::string, std::string, codec_t> decode(const std::string& text) const;
/**
Checking if a string is Q encoded and decodes it.
@param text String to decode.
@return Decoded string, its charset and its codec method.
@throw codec_error Bad Q codec format.
@todo Returning value to hold `string_t` instead of two `std::string`.
**/
std::tuple<std::string, std::string, codec_t> check_decode(const std::string& text) const;
private:
/**
String representation of Base64 method.
**/
static const std::string BASE64_CODEC_STR;
/**
String representation of Quoted Printable method.
**/
static const std::string QP_CODEC_STR;
/**
Decoding by using variation of the Quoted Printable method.
@param text String to decode.
@return Decoded string.
@throw * `quoted_printable::decode(const vector<string>&)`
**/
std::string decode_qp(const std::string& text) const;
/**
Checking if a character is allowed.
@param ch Character to check.
@return True if allowed, false if not.
**/
bool is_q_allowed(char ch) const;
};
} // namespace mailio
#ifdef _MSC_VER
#pragma warning(pop)
#endif
+101
View File
@@ -0,0 +1,101 @@
/*
quoted_printable.hpp
--------------------
Copyright (C) 2016, Tomislav Karastojkovic (http://www.alepho.com).
Distributed under the FreeBSD license, see the accompanying file LICENSE or
copy at http://www.freebsd.org/copyright/freebsd-license.html.
*/
#pragma once
#include <string>
#include <vector>
#include "codec.hpp"
#include "export.hpp"
namespace mailio
{
/**
Quoted Printable codec.
@todo Remove the Q codec flag.
**/
class MAILIO_EXPORT quoted_printable : public codec
{
public:
/**
Setting the encoder and decoder line policies.
@param line1_policy First line policy to set.
@param lines_policy Other lines policy than the first one to set.
**/
quoted_printable(std::string::size_type line1_policy, std::string::size_type lines_policy);
quoted_printable(const quoted_printable&) = delete;
quoted_printable(quoted_printable&&) = delete;
/**
Default destructor.
**/
~quoted_printable() = default;
void operator=(const quoted_printable&) = delete;
void operator=(quoted_printable&&) = delete;
/**
Encoding a string into vector of quoted printable encoded strings by applying the line policy.
@param text String to encode.
@return Vector of quoted printable strings.
@throw codec_error Bad character.
@throw codec_error Bad CRLF sequence.
**/
std::vector<std::string> encode(const std::string& text) const;
/**
Decoding a vector of quoted printable strings to string by applying the line policy.
@param text Vector of quoted printable encoded strings.
@return Decoded string.
@throw codec_error Bad line policy.
@throw codec_error Bad character.
@throw codec_error Bad hexadecimal digit.
**/
std::string decode(const std::vector<std::string>& text) const;
/**
Setting Q codec mode.
@param mode True to set, false to unset.
**/
void q_codec_mode(bool mode);
private:
/**
Check if a character is in the Quoted Printable character set.
@param ch Character to check.
@return True if it is, false if not.
**/
bool is_allowed(char ch) const;
/**
Flag for the Q codec mode.
**/
bool q_codec_mode_;
};
} // namespace mailio
+372
View File
@@ -0,0 +1,372 @@
/*
smtp.hpp
--------
Copyright (C) 2016, Tomislav Karastojkovic (http://www.alepho.com).
Distributed under the FreeBSD license, see the accompanying file LICENSE or
copy at http://www.freebsd.org/copyright/freebsd-license.html.
*/
#pragma once
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4251)
#endif
#include <string>
#include <memory>
#include <tuple>
#include <stdexcept>
#include <chrono>
#include <optional>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/asio/streambuf.hpp>
#include "message.hpp"
#include "dialog.hpp"
#include "export.hpp"
namespace mailio
{
/**
SMTP client implementation.
The order of connection is prioritized as: start tls, ssl, plain tcp. By default, SMTP tries to connect over start tls. If the start tls is switched off, then it
connects over ssl. If the ssl is switched off, then it connects over plain tcp.
The start tls needs ssl options to be set so they could be used once the connection is switched from tcp to tls. For that reason, the ssl options are
internally set to default values, but they can be modified over `ssl_options()`. If a user does not want the start tls, it can turn it off over
`start_tls(false)`. Turning off the start tls switches SMTP to the ssl connection. In order to switch off ssl completely, it has to be done explicitly by setting
`ssl_options(std::nullopt)`. With both start tls and ssl switched off, the SMTP connection is plain tcp.
**/
class MAILIO_EXPORT smtp
{
public:
/**
Available authentication methods.
The following mechanisms are allowed:
- NONE: No username or password are required, so just use the empty strings when authenticating. Nowadays, it's not probably that such authentication
mechanism is allowed.
- LOGIN: The username and password are sent in Base64 format.
**/
enum class auth_method_t {NONE, LOGIN};
/**
Making a connection to the server.
@param hostname Hostname of the server.
@param port Port of the server.
@param timeout Network timeout after which I/O operations fail. If zero, then no timeout is set i.e. I/O operations are synchronous.
@throw smtp_error Empty source hostname not allowed.
@throw * `dialog::dialog`, `read_hostname`.
**/
smtp(const std::string& hostname, unsigned port, std::chrono::milliseconds timeout = std::chrono::milliseconds(0));
/**
Sending the quit command and closing the connection.
**/
virtual ~smtp();
smtp(const smtp&) = delete;
smtp(smtp&&) = delete;
void operator=(const smtp&) = delete;
void operator=(smtp&&) = delete;
/**
Authenticating with the given credentials.
The method should be called only once on an existing object - it is not possible to authenticate again within the same connection.
@param username Username to authenticate.
@param password Password to authenticate.
@param method Authentication method to use.
@return The server greeting message.
@throw * `connect()`, `ehlo()`, `auth_login(const string&, const string&)`.
**/
std::string authenticate(const std::string& username, const std::string& password, auth_method_t method);
/**
Submitting a message.
@param msg Mail message to send.
@return The SMTP server's reply on accepting the message.
@throw smtp_error Mail sender rejection.
@throw smtp_error Mail recipient rejection.
@throw smtp_error Mail group recipient rejection.
@throw smtp_error Mail cc recipient rejection.
@throw smtp_error Mail group cc recipient rejection.
@throw smtp_error Mail bcc recipient rejection.
@throw smtp_error Mail group bcc recipient rejection.
@throw smtp_error Mail message rejection.
@throw * `parse_line(const string&)`, `dialog::send(const string&)`, `dialog::receive()`.
**/
std::string submit(const message& msg);
/**
Setting the source hostname.
@param src_host Source hostname to set.
**/
void source_hostname(const std::string& src_host);
/**
Getting source hostname.
@return Source hostname.
**/
std::string source_hostname() const;
/**
Setting the start TLS option.
@param is_tls If true, the start TLS option is turned on, otherwise is turned off.
**/
void start_tls(bool is_tls);
/**
Setting SSL options.
In case the null is set, then no SSL options is set, meaning that no TLS connection is available.
@param options SSL options to set.
**/
void ssl_options(const std::optional<dialog_ssl::ssl_options_t> options = std::nullopt);
protected:
/**
SMTP response status.
**/
enum smtp_status_t {POSITIVE_COMPLETION = 2, POSITIVE_INTERMEDIATE = 3, TRANSIENT_NEGATIVE = 4, PERMANENT_NEGATIVE = 5};
/**
Initializing the connection to the server.
@throw smtp_error Connection rejection.
@throw * `parse_line(const string&)`, `dialog::receive()`.
**/
std::string connect();
/**
Authenticating with the login method.
@param username Username to authenticate.
@param password Password to authenticate.
@throw smtp_error Authentication rejection.
@throw smtp_error Username rejection.
@throw smtp_error Password rejection.
@throw * `parse_line(const string&)`, `dialog::send(const string&)`, `dialog::receive()`.
**/
void auth_login(const std::string& username, const std::string& password);
/**
Issuing `EHLO` and/or `HELO` commands.
@throw smtp_error Initial message rejection.
@throw * `parse_line(const string&)`, `dialog::send(const string&)`, `dialog::receive()`.
**/
void ehlo();
/**
Switching to TLS layer.
@throw smtp_error Start TLS refused by server.
@throw * `parse_line(const string&)`, `ehlo()`, `dialog::send(const string&)`, `dialog::receive()`, `dialog_ssl::to_ssl()`.
**/
void switch_tls();
/**
Reading the source hostname.
@return Source hostname.
@throw smtp_error Reading hostname failure.
**/
std::string read_hostname();
/**
Parsing the response line into three tokens.
@param response Response line to parse.
@return Tuple with a status number, flag if the line is the last one and status message.
@throw smtp_error Parsing server failure.
**/
static std::tuple<int, bool, std::string> parse_line(const std::string& response);
/**
Checking if the status is 2XX.
@param status Status to check.
@return True if does, false if not.
**/
static bool positive_completion(int status);
/**
Checking if the status is 3XX.
@param status Status to check.
@return True if does, false if not.
**/
static bool positive_intermediate(int status);
/**
Checking if the status is 4XX.
@param status Status to check.
@return True if does, false if not.
**/
static bool transient_negative(int status);
/**
Checking if the status is 5XX.
@param status Status to check.
@return True if does, false if not.
**/
static bool permanent_negative(int status);
/**
Server status when ready.
**/
static const uint16_t SERVICE_READY_STATUS = 220;
/**
Name of the host which client is connecting from.
**/
std::string src_host_;
/**
Dialog to use for send/receive operations.
**/
std::shared_ptr<dialog> dlg_;
/**
SSL options to set.
**/
std::optional<dialog_ssl::ssl_options_t> ssl_options_;
/**
Flag to switch to the TLS.
**/
bool is_start_tls_;
};
/**
Secure version of SMTP client.
**/
class MAILIO_DEPRECATED smtps : public smtp
{
public:
/**
Available authentication methods over the TLS connection.
The following mechanisms are allowed:
- NONE: No username or password are required, so just use the empty strings when authenticating. Nowadays, it's not probably that such authentication
mechanism is allowed.
- LOGIN: The username and password are sent in Base64 format.
- START_TLS: For the TCP connection, a TLS negotiation is asked before sending the login parameters.
**/
enum class auth_method_t {NONE, LOGIN, START_TLS};
/**
Making a connection to the server.
Parent constructor is called to do all the work.
@param hostname Hostname of the server.
@param port Port of the server.
@param timeout Network timeout after which I/O operations fail. If zero, then no timeout is set i.e. I/O operations are synchronous.
@throw * `smtp::smtp(const string&, unsigned)`.
**/
smtps(const std::string& hostname, unsigned port, std::chrono::milliseconds timeout = std::chrono::milliseconds(0));
/**
Sending the quit command and closing the connection.
Parent destructor is called to do all the work.
**/
~smtps() = default;
smtps(const smtps&) = delete;
smtps(smtps&&) = delete;
void operator=(const smtps&) = delete;
void operator=(smtps&&) = delete;
/**
Authenticating with the given credentials.
@param username Username to authenticate.
@param password Password to authenticate.
@param method Authentication method to use.
@return The server greeting message.
@throw * `start_tls()`, `switch_to_ssl()`, `ehlo()`, `auth_login(const string&, const string&)`, `connect()`.
**/
std::string authenticate(const std::string& username, const std::string& password, auth_method_t method);
/**
Setting SSL options.
@param options SSL options to set.
**/
void ssl_options(const dialog_ssl::ssl_options_t& options);
};
/**
Error thrown by SMTP client.
**/
class smtp_error : public dialog_error
{
public:
/**
Calling the parent constructor.
@param msg Error message.
@param details Detailed message.
**/
smtp_error(const std::string& msg, const std::string& details);
/**
Calling the parent constructor.
@param msg Error message.
@param details Detailed message.
**/
smtp_error(const char* msg, const std::string& details);
smtp_error(const smtp_error&) = default;
smtp_error(smtp_error&&) = default;
~smtp_error() = default;
smtp_error& operator=(const smtp_error&) = default;
smtp_error& operator=(smtp_error&&) = default;
};
} // namespace mailio
#ifdef _MSC_VER
#pragma warning(pop)
#endif
+3
View File
@@ -0,0 +1,3 @@
#define MAILIO_VERSION_MAJOR 0
#define MAILIO_VERSION_MINOR 26
#define MAILIO_VERSION_PATCH 0
@@ -0,0 +1,65 @@
# This is a basic version file for the Config-mode of find_package().
# It is used by write_basic_package_version_file() as input file for configure_file()
# to create a version-file which can be installed along a config.cmake file.
#
# The created file sets PACKAGE_VERSION_EXACT if the current version string and
# the requested version string are exactly the same and it sets
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version,
# but only if the requested major version is the same as the current one.
# The variable CVF_VERSION must be set before calling configure_file().
set(PACKAGE_VERSION "0.26.0")
if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
if("0.26.0" MATCHES "^([0-9]+)\\.")
set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}")
if(NOT CVF_VERSION_MAJOR VERSION_EQUAL 0)
string(REGEX REPLACE "^0+" "" CVF_VERSION_MAJOR "${CVF_VERSION_MAJOR}")
endif()
else()
set(CVF_VERSION_MAJOR "0.26.0")
endif()
if(PACKAGE_FIND_VERSION_RANGE)
# both endpoints of the range must have the expected major version
math (EXPR CVF_VERSION_MAJOR_NEXT "${CVF_VERSION_MAJOR} + 1")
if (NOT PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR
OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX_MAJOR STREQUAL CVF_VERSION_MAJOR)
OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX VERSION_LESS_EQUAL CVF_VERSION_MAJOR_NEXT)))
set(PACKAGE_VERSION_COMPATIBLE FALSE)
elseif(PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR
AND ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS_EQUAL PACKAGE_FIND_VERSION_MAX)
OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MAX)))
set(PACKAGE_VERSION_COMPATIBLE TRUE)
else()
set(PACKAGE_VERSION_COMPATIBLE FALSE)
endif()
else()
if(PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR)
set(PACKAGE_VERSION_COMPATIBLE TRUE)
else()
set(PACKAGE_VERSION_COMPATIBLE FALSE)
endif()
if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
endif()
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "")
return()
endif()
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8")
math(EXPR installedBits "8 * 8")
set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
set(PACKAGE_VERSION_UNSUITABLE TRUE)
endif()
+33
View File
@@ -0,0 +1,33 @@
####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() #######
####### Any changes to this file will be overwritten by the next CMake run ####
####### The input file was mailio-config.cmake.in ########
get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)
macro(set_and_check _var _file)
set(${_var} "${_file}")
if(NOT EXISTS "${_file}")
message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
endif()
endmacro()
macro(check_required_components _NAME)
foreach(comp ${${_NAME}_FIND_COMPONENTS})
if(NOT ${_NAME}_${comp}_FOUND)
if(${_NAME}_FIND_REQUIRED_${comp})
set(${_NAME}_FOUND FALSE)
endif()
endif()
endforeach()
endmacro()
####################################################################################
include("CMakeFindDependencyMacro")
find_dependency("Boost" COMPONENTS "date_time" "regex")
find_dependency("OpenSSL" COMPONENTS "SSL")
include("${CMAKE_CURRENT_LIST_DIR}/mailio-targets.cmake")
check_required_components("mailio")
@@ -0,0 +1,19 @@
#----------------------------------------------------------------
# Generated CMake target import file for configuration "Release".
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
# Import target "mailio::mailio" for configuration "Release"
set_property(TARGET mailio::mailio APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(mailio::mailio PROPERTIES
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libmailio.so"
IMPORTED_SONAME_RELEASE "libmailio.so"
)
list(APPEND _cmake_import_check_targets mailio::mailio )
list(APPEND _cmake_import_check_files_for_mailio::mailio "${_IMPORT_PREFIX}/lib/libmailio.so" )
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
+107
View File
@@ -0,0 +1,107 @@
# Generated by CMake
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8)
message(FATAL_ERROR "CMake >= 2.8.12 required")
endif()
if(CMAKE_VERSION VERSION_LESS "2.8.12")
message(FATAL_ERROR "CMake >= 2.8.12 required")
endif()
cmake_policy(PUSH)
cmake_policy(VERSION 2.8.12...4.0)
#----------------------------------------------------------------
# Generated CMake target import file.
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
# Protect against multiple inclusion, which would fail when already imported targets are added once more.
set(_cmake_targets_defined "")
set(_cmake_targets_not_defined "")
set(_cmake_expected_targets "")
foreach(_cmake_expected_target IN ITEMS mailio::mailio)
list(APPEND _cmake_expected_targets "${_cmake_expected_target}")
if(TARGET "${_cmake_expected_target}")
list(APPEND _cmake_targets_defined "${_cmake_expected_target}")
else()
list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}")
endif()
endforeach()
unset(_cmake_expected_target)
if(_cmake_targets_defined STREQUAL _cmake_expected_targets)
unset(_cmake_targets_defined)
unset(_cmake_targets_not_defined)
unset(_cmake_expected_targets)
unset(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)
return()
endif()
if(NOT _cmake_targets_defined STREQUAL "")
string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}")
string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}")
message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n")
endif()
unset(_cmake_targets_defined)
unset(_cmake_targets_not_defined)
unset(_cmake_expected_targets)
# Compute the installation prefix relative to this file.
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
if(_IMPORT_PREFIX STREQUAL "/")
set(_IMPORT_PREFIX "")
endif()
# Create imported target mailio::mailio
add_library(mailio::mailio SHARED IMPORTED)
set_target_properties(mailio::mailio PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include/;${_IMPORT_PREFIX}/include/;/tmp/openssl-dev/usr/include;/tmp/openssl-dev/usr/include/x86_64-linux-gnu;${_IMPORT_PREFIX}/include"
INTERFACE_LINK_LIBRARIES "Boost::date_time;Boost::regex;OpenSSL::SSL"
)
# Load information for each installed configuration.
file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/mailio-targets-*.cmake")
foreach(_cmake_config_file IN LISTS _cmake_config_files)
include("${_cmake_config_file}")
endforeach()
unset(_cmake_config_file)
unset(_cmake_config_files)
# Cleanup temporary variables.
set(_IMPORT_PREFIX)
# Loop over all imported files and verify that they actually exist
foreach(_cmake_target IN LISTS _cmake_import_check_targets)
if(CMAKE_VERSION VERSION_LESS "3.28"
OR NOT DEFINED _cmake_import_check_xcframework_for_${_cmake_target}
OR NOT IS_DIRECTORY "${_cmake_import_check_xcframework_for_${_cmake_target}}")
foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}")
if(NOT EXISTS "${_cmake_file}")
message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file
\"${_cmake_file}\"
but this file does not exist. Possible reasons include:
* The file was deleted, renamed, or moved to another location.
* An install or uninstall procedure did not complete successfully.
* The installation package was faulty and contained
\"${CMAKE_CURRENT_LIST_FILE}\"
but not all the files it references.
")
endif()
endforeach()
endif()
unset(_cmake_file)
unset("_cmake_import_check_files_for_${_cmake_target}")
endforeach()
unset(_cmake_target)
unset(_cmake_import_check_targets)
# This file does not depend on other imported targets which have
# been exported from the same project but in a separate export set.
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)
Binary file not shown.
+12
View File
@@ -0,0 +1,12 @@
prefix=/usr/local
exec_prefix=/usr/local
libdir=lib
sharedlibdir=lib
includedir=include
Name: mailio
Description: Cross-platform MIME library for SMTP, POP3, and IMAP protocols.
Version: 0.26.0
Requires:
Libs: -L${libdir} -L${sharedlibdir} -lmailio
Cflags: -I${includedir}