namespace {
const char *kStyle = R"CSS(
body { font-family: sans-serif; font-size: 10pt; margin: 12px; }
pre.plain { white-space: pre-wrap; word-wrap: break-word;
font-family: monospace; margin: 0; }
span.quote { color: #4a6f8a; }
.message { border-top: 1px solid #bbb; padding: 10px 0; }
.message:first-child { border-top: none; }
.msg-header { font-size: 9pt; color: #555; margin-bottom: 8px; }
.msg-header .who { font-weight: bold; color: #000; }
.stub { font-size: 9pt; color: #666; padding: 4px 0;
border-top: 1px solid #ddd; }
)CSS";
} // namespace
QString HtmlBuilder::renderPlain(const QString &text)
{
QString out;
out += QStringLiteral("");
const QStringList lines = text.split(QLatin1Char('\n'));
for (int i = 0; i < lines.size(); ++i) {
const QString &line = lines.at(i);
const bool quoted = line.startsWith(QLatin1Char('>'));
if (quoted)
out += QStringLiteral("");
out += line.toHtmlEscaped();
if (quoted)
out += QStringLiteral("");
if (i + 1 < lines.size())
out += QLatin1Char('\n');
}
out += QStringLiteral("");
return out;
}
QString HtmlBuilder::document(const QString &bodyHtml)
{
return QStringLiteral(
""
"%2")
.arg(QString::fromUtf8(kStyle), bodyHtml);
}
QString HtmlBuilder::namespaceCids(const QString &html, const QString &prefix)
{
if (prefix.isEmpty())
return html;
// The '!' separator is only unambiguous if prefix itself never contains
// one: the FIRST '!' in "cid:!" is always taken as the
// separator, so a hostile Content-ID containing '!' only extends the id
// half, never collides with a different prefix. This concatenation is
// performed independently in two places (here and
// CidSchemeHandler::namespacedKey); neither trusts the other to have
// checked it, so both assert it directly. Q_ASSERT is compiled out in
// release builds — the property that matters there is pinned by
// TestHtmlBuilder::namespacedKeyRejectsPrefixContainingSeparator instead.
Q_ASSERT_X(!prefix.contains(QLatin1Char('!')), "HtmlBuilder::namespaceCids",
"cidPrefix must never contain '!': it is the separator, and a "
"prefix containing one would make the split ambiguous");
// This runs on the sender's raw, unescaped HTML markup (not on text that
// has been through toHtmlEscaped()), so no double-escaping happens here;
// it is purely a URL rewrite over the existing markup.
//
// Two independent patterns are needed:
//
// 1. Attribute values: src=, href=, background=, poster= (the common
// real-world attributes that can carry a cid: reference in HTML
// email), quoted with " or ', quoted the other way, or entirely
// unquoted (
is valid HTML and unquoted references are
// seen in the wild). Attribute name is matched case-insensitively and
// whitespace/newlines are tolerated around '='.
//
// 2. CSS url(cid:...): appears both inside a style="" attribute value
// and inside a