QByteArray QxtMailAttachment::mimeData() { bool isMultipart = false; QTextCodec* latin1 = QTextCodec::codecForName("latin1"); if (qxt_d->attachments.count()) { if (!qxt_d->contentType.startsWith("multipart/", Qt::CaseInsensitive)) setExtraHeader(QStringLiteral("Content-Type"), QStringLiteral("multipart/mixed")); } QByteArray rv = "Content-Type: " + qxt_d->contentType.toLatin1() + "\r\n"; if (qxt_d->contentType.startsWith("multipart/", Qt::CaseInsensitive)) { isMultipart = true; } else { rv += "Content-Transfer-Encoding: base64\r\n"; } foreach(const QString& r, qxt_d->extraHeaders.keys()) { rv += qxt_fold_mime_header(r, extraHeader(r), latin1); } rv += "\r\n"; const QByteArray& d = rawData(); int chars = isMultipart? 73 : 57; // multipart preamble supposed to be 7bit latin1 for (int pos = 0; pos < d.length(); pos += chars) { if (isMultipart) { rv += d.mid(pos, chars) + "\r\n"; } else { rv += d.mid(pos, chars).toBase64() + "\r\n"; } } if (isMultipart) { QMutableMapIterator<QString, QxtMailAttachment> it(qxt_d->attachments); while (it.hasNext()) { rv += "--" + qxt_d->boundary + "\r\n"; rv += it.next().value().mimeData(); } rv += "--" + qxt_d->boundary + "--\r\n"; } return rv; }
QByteArray QxtMailMessage::rfc2822() const { // Use quoted-printable if requested bool useQuotedPrintable = (extraHeader(QStringLiteral("Content-Transfer-Encoding")).toLower() == QLatin1String("quoted-printable")); // Use base64 if requested bool useBase64 = (extraHeader(QStringLiteral("Content-Transfer-Encoding")).toLower() == QLatin1String("base64")); // Check to see if plain text is ASCII-clean; assume it isn't if QP or base64 was requested QTextCodec* latin1 = QTextCodec::codecForName("latin1"); bool bodyIsAscii = latin1->canEncode(body()) && !useQuotedPrintable && !useBase64; QHash<QString, QxtMailAttachment> attach = attachments(); QByteArray rv; if (!sender().isEmpty() && !hasExtraHeader(QStringLiteral("From"))) { rv += qxt_fold_mime_header(QStringLiteral("From"), sender(), latin1); } if (!qxt_d->rcptTo.isEmpty()) { rv += qxt_fold_mime_header(QStringLiteral("To"), qxt_d->rcptTo.join(QStringLiteral(", ")), latin1); } if (!qxt_d->rcptCc.isEmpty()) { rv += qxt_fold_mime_header(QStringLiteral("Cc"), qxt_d->rcptCc.join(QStringLiteral(", ")), latin1); } if (!subject().isEmpty()) { rv += qxt_fold_mime_header(QStringLiteral("Subject"), subject(), latin1); } if (!bodyIsAscii) { if (!hasExtraHeader(QStringLiteral("MIME-Version")) && !attach.count()) rv += "MIME-Version: 1.0\r\n"; // If no transfer encoding has been requested, guess. // Heuristic: If >20% of the first 100 characters aren't // 7-bit clean, use base64, otherwise use Q-P. if(!bodyIsAscii && !useQuotedPrintable && !useBase64) { QString b = body(); int nonAscii = 0; int ct = b.length(); for (int i = 0; i < ct && i < 100; i++) { if (QXT_MUST_QP(b[i])) nonAscii++; } useQuotedPrintable = !(nonAscii > 20); useBase64 = !useQuotedPrintable; } } if (attach.count()) { if (qxt_d->boundary.isEmpty()) qxt_d->boundary = QUuid::createUuid().toString().toLatin1().replace("{", "").replace("}", ""); if (!hasExtraHeader(QStringLiteral("MIME-Version"))) rv += "MIME-Version: 1.0\r\n"; if (!hasExtraHeader(QStringLiteral("Content-Type"))) rv += "Content-Type: multipart/mixed; boundary=" + qxt_d->boundary + "\r\n"; } else if (!bodyIsAscii && !hasExtraHeader(QStringLiteral("Content-Transfer-Encoding"))) { if (!useQuotedPrintable) { // base64 rv += "Content-Transfer-Encoding: base64\r\n"; } else { // quoted-printable rv += "Content-Transfer-Encoding: quoted-printable\r\n"; } } for(const QString& r: qxt_d->extraHeaders.keys()) { if ((r.toLower() == QLatin1String("content-type") || r.toLower() == QLatin1String("content-transfer-encoding")) && attach.count()) { // Since we're in multipart mode, we'll be outputting this later continue; } rv += qxt_fold_mime_header(r, extraHeader(r), latin1); } rv += "\r\n"; if (attach.count()) { // we're going to have attachments, so output the lead-in for the message body rv += "This is a message with multiple parts in MIME format.\r\n"; rv += "--" + qxt_d->boundary + "\r\nContent-Type: "; if (hasExtraHeader(QStringLiteral("Content-Type"))) rv += extraHeader(QStringLiteral("Content-Type")).toLatin1() + "\r\n"; else rv += "text/plain; charset=UTF-8\r\n"; if (hasExtraHeader(QStringLiteral("Content-Transfer-Encoding"))) { rv += "Content-Transfer-Encoding: " + extraHeader(QStringLiteral("Content-Transfer-Encoding")).toLatin1() + "\r\n"; } else if (!bodyIsAscii) { if (!useQuotedPrintable) { // base64 rv += "Content-Transfer-Encoding: base64\r\n"; } else { // quoted-printable rv += "Content-Transfer-Encoding: quoted-printable\r\n"; } } rv += "\r\n"; } if (bodyIsAscii) { QByteArray b = latin1->fromUnicode(body()); int len = b.length(); QByteArray line = ""; QByteArray word = ""; for (int i = 0; i < len; i++) { if (b[i] == '\n' || b[i] == '\r') { if (line.isEmpty()) { line = word; word = ""; } else if (line.length() + word.length() + 1 <= 78) { line = line + ' ' + word; word = ""; } if(line[0] == '.') rv += "."; rv += line + "\r\n"; if ((b[i+1] == '\n' || b[i+1] == '\r') && b[i] != b[i+1]) { // If we're looking at a CRLF pair, skip the second half i++; } line = word; } else if (b[i] == ' ') { if (line.length() + word.length() + 1 > 78) { if(line[0] == '.') rv += "."; rv += line + "\r\n"; line = word; } else if (line.isEmpty()) { line = word; } else { line = line + ' ' + word; } word = ""; } else { word += b[i]; } } if (line.length() + word.length() + 1 > 78) { if(line[0] == '.') rv += "."; rv += line + "\r\n"; line = word; } else if (!word.isEmpty()) { line += ' ' + word; } if(!line.isEmpty()) { if(line[0] == '.') rv += "."; rv += line + "\r\n"; } } else if (useQuotedPrintable) { QByteArray b = body().toUtf8(); int ct = b.length(); QByteArray line; for (int i = 0; i < ct; i++) { if(b[i] == '\n' || b[i] == '\r') { if(line[0] == '.') rv += "."; rv += line + "\r\n"; line = ""; if ((b[i+1] == '\n' || b[i+1] == '\r') && b[i] != b[i+1]) { // If we're looking at a CRLF pair, skip the second half i++; } } else if (line.length() > 74) { rv += line + "=\r\n"; line = ""; } if (QXT_MUST_QP(b[i])) { line += "=" + b.mid(i, 1).toHex().toUpper(); } else { line += b[i]; } } if(!line.isEmpty()) { if(line[0] == '.') rv += "."; rv += line + "\r\n"; } } else /* base64 */ { QByteArray b = body().toUtf8().toBase64(); int ct = b.length(); for (int i = 0; i < ct; i += 78) { rv += b.mid(i, 78) + "\r\n"; } } if (attach.count()) { for(const QString& filename: attach.keys()) { rv += "--" + qxt_d->boundary + "\r\n"; rv += qxt_fold_mime_header(QStringLiteral("Content-Disposition"), QDir(filename).dirName(), latin1, "attachment; filename="); rv += attach[filename].mimeData(); } rv += "--" + qxt_d->boundary + "--\r\n"; } return rv; }