diff --git a/cockatrice/src/carddatabase.cpp b/cockatrice/src/carddatabase.cpp index 48b72b31..983f1733 100644 --- a/cockatrice/src/carddatabase.cpp +++ b/cockatrice/src/carddatabase.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -534,11 +535,21 @@ LoadStatus CardDatabase::loadCardDatabases() loadCardDatabase(SettingsCache::instance().getTokenDatabasePath()); // load tokens database loadCardDatabase(SettingsCache::instance().getSpoilerCardDatabasePath()); // load spoilers database - // load custom card databases - QDir dir(SettingsCache::instance().getCustomCardDatabasePath()); - for (const QString &fileName : - dir.entryList(QStringList("*.xml"), QDir::Files | QDir::Readable, QDir::Name | QDir::IgnoreCase)) { - loadCardDatabase(dir.absoluteFilePath(fileName)); + // find all custom card databases, recursively & following symlinks + // then load them alphabetically + QDirIterator customDatabaseIterator(SettingsCache::instance().getCustomCardDatabasePath(), QStringList() << "*.xml", + QDir::Files, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks); + QStringList databasePaths; + while (customDatabaseIterator.hasNext()) { + customDatabaseIterator.next(); + databasePaths.push_back(customDatabaseIterator.filePath()); + } + databasePaths.sort(); + + for (auto i = 0; i < databasePaths.size(); ++i) { + const auto &databasePath = databasePaths.at(i); + qDebug() << "Loading Custom Set" << i << "(" << databasePath << ")"; + loadCardDatabase(databasePath); } // AFTER all the cards have been loaded diff --git a/servatrice/src/smtp/qxtmailattachment.h b/servatrice/src/smtp/qxtmailattachment.h index 397b117f..62a0e9ad 100644 --- a/servatrice/src/smtp/qxtmailattachment.h +++ b/servatrice/src/smtp/qxtmailattachment.h @@ -27,41 +27,41 @@ #include "qxtglobal.h" -#include -#include #include +#include +#include #include #include -#include +#include struct QxtMailAttachmentPrivate; class QXT_NETWORK_EXPORT QxtMailAttachment { public: QxtMailAttachment(); - QxtMailAttachment(const QxtMailAttachment& other); - QxtMailAttachment(const QByteArray& content, const QString& contentType = QString("application/octet-stream")); - QxtMailAttachment(QIODevice* content, const QString& contentType = QString("application/octet-stream")); - QxtMailAttachment& operator=(const QxtMailAttachment& other); + QxtMailAttachment(const QxtMailAttachment &other); + QxtMailAttachment(const QByteArray &content, const QString &contentType = QString("application/octet-stream")); + QxtMailAttachment(QIODevice *content, const QString &contentType = QString("application/octet-stream")); + QxtMailAttachment &operator=(const QxtMailAttachment &other); ~QxtMailAttachment(); - static QxtMailAttachment fromFile(const QString& filename); + static QxtMailAttachment fromFile(const QString &filename); - QIODevice* content() const; - void setContent(const QByteArray& content); - void setContent(QIODevice* content); + QIODevice *content() const; + void setContent(const QByteArray &content); + void setContent(QIODevice *content); bool deleteContent() const; void setDeleteContent(bool enable); QString contentType() const; - void setContentType(const QString& contentType); + void setContentType(const QString &contentType); QHash extraHeaders() const; - QByteArray extraHeader(const QString&) const; - bool hasExtraHeader(const QString&) const; - void setExtraHeader(const QString& key, const QString& value); - void setExtraHeaders(const QHash&); - void removeExtraHeader(const QString& key); + QByteArray extraHeader(const QString &) const; + bool hasExtraHeader(const QString &) const; + void setExtraHeader(const QString &key, const QString &value); + void setExtraHeaders(const QHash &); + void removeExtraHeader(const QString &key); QByteArray mimeData(); diff --git a/servatrice/src/smtp/qxtmailmessage.cpp b/servatrice/src/smtp/qxtmailmessage.cpp index 9d6de47d..45452aed 100644 --- a/servatrice/src/smtp/qxtmailmessage.cpp +++ b/servatrice/src/smtp/qxtmailmessage.cpp @@ -23,7 +23,6 @@ ** ****************************************************************************/ - /*! * \class QxtMailMessage * \inmodule QxtNetwork @@ -31,22 +30,26 @@ * TODO: {implicitshared} */ - #include "qxtmailmessage.h" + #include "qxtmail_p.h" + +#include #include #include -#include #include - struct QxtMailMessagePrivate : public QSharedData { - QxtMailMessagePrivate() {} - QxtMailMessagePrivate(const QxtMailMessagePrivate& other) - : QSharedData(other), rcptTo(other.rcptTo), rcptCc(other.rcptCc), rcptBcc(other.rcptBcc), - subject(other.subject), body(other.body), sender(other.sender), - extraHeaders(other.extraHeaders), attachments(other.attachments) {} + QxtMailMessagePrivate() + { + } + QxtMailMessagePrivate(const QxtMailMessagePrivate &other) + : QSharedData(other), rcptTo(other.rcptTo), rcptCc(other.rcptCc), rcptBcc(other.rcptBcc), + subject(other.subject), body(other.body), sender(other.sender), extraHeaders(other.extraHeaders), + attachments(other.attachments) + { + } QStringList rcptTo, rcptCc, rcptBcc; QString subject, body, sender; QHash extraHeaders; @@ -59,12 +62,12 @@ QxtMailMessage::QxtMailMessage() qxt_d = new QxtMailMessagePrivate; } -QxtMailMessage::QxtMailMessage(const QxtMailMessage& other) : qxt_d(other.qxt_d) +QxtMailMessage::QxtMailMessage(const QxtMailMessage &other) : qxt_d(other.qxt_d) { // trivial copy constructor } -QxtMailMessage::QxtMailMessage(const QString& sender, const QString& recipient) +QxtMailMessage::QxtMailMessage(const QString &sender, const QString &recipient) { qxt_d = new QxtMailMessagePrivate; setSender(sender); @@ -76,7 +79,7 @@ QxtMailMessage::~QxtMailMessage() // trivial destructor } -QxtMailMessage& QxtMailMessage::operator=(const QxtMailMessage & other) +QxtMailMessage &QxtMailMessage::operator=(const QxtMailMessage &other) { qxt_d = other.qxt_d; return *this; @@ -87,7 +90,7 @@ QString QxtMailMessage::sender() const return qxt_d->sender; } -void QxtMailMessage::setSender(const QString& a) +void QxtMailMessage::setSender(const QString &a) { qxt_d->sender = a; } @@ -97,7 +100,7 @@ QString QxtMailMessage::subject() const return qxt_d->subject; } -void QxtMailMessage::setSubject(const QString& a) +void QxtMailMessage::setSubject(const QString &a) { qxt_d->subject = a; } @@ -107,7 +110,7 @@ QString QxtMailMessage::body() const return qxt_d->body; } -void QxtMailMessage::setBody(const QString& a) +void QxtMailMessage::setBody(const QString &a) { qxt_d->body = a; } @@ -121,7 +124,7 @@ QStringList QxtMailMessage::recipients(QxtMailMessage::RecipientType type) const return qxt_d->rcptTo; } -void QxtMailMessage::addRecipient(const QString& a, QxtMailMessage::RecipientType type) +void QxtMailMessage::addRecipient(const QString &a, QxtMailMessage::RecipientType type) { if (type == Bcc) qxt_d->rcptBcc.append(a); @@ -131,7 +134,7 @@ void QxtMailMessage::addRecipient(const QString& a, QxtMailMessage::RecipientTyp qxt_d->rcptTo.append(a); } -void QxtMailMessage::removeRecipient(const QString& a) +void QxtMailMessage::removeRecipient(const QString &a) { qxt_d->rcptTo.removeAll(a); qxt_d->rcptCc.removeAll(a); @@ -143,32 +146,31 @@ QHash QxtMailMessage::extraHeaders() const return qxt_d->extraHeaders; } -QByteArray QxtMailMessage::extraHeader(const QString& key) const +QByteArray QxtMailMessage::extraHeader(const QString &key) const { return qxt_d->extraHeaders[key.toLower()].toLatin1(); } -bool QxtMailMessage::hasExtraHeader(const QString& key) const +bool QxtMailMessage::hasExtraHeader(const QString &key) const { return qxt_d->extraHeaders.contains(key.toLower()); } -void QxtMailMessage::setExtraHeader(const QString& key, const QString& value) +void QxtMailMessage::setExtraHeader(const QString &key, const QString &value) { qxt_d->extraHeaders[key.toLower()] = value; } -void QxtMailMessage::setExtraHeaders(const QHash& a) +void QxtMailMessage::setExtraHeaders(const QHash &a) { - QHash& headers = qxt_d->extraHeaders; + QHash &headers = qxt_d->extraHeaders; headers.clear(); - foreach(const QString& key, a.keys()) - { + foreach (const QString &key, a.keys()) { headers[key.toLower()] = a[key]; } } -void QxtMailMessage::removeExtraHeader(const QString& key) +void QxtMailMessage::removeExtraHeader(const QString &key) { qxt_d->extraHeaders.remove(key.toLower()); } @@ -178,46 +180,40 @@ QHash QxtMailMessage::attachments() const return qxt_d->attachments; } -QxtMailAttachment QxtMailMessage::attachment(const QString& filename) const +QxtMailAttachment QxtMailMessage::attachment(const QString &filename) const { return qxt_d->attachments[filename]; } -void QxtMailMessage::addAttachment(const QString& filename, const QxtMailAttachment& attach) +void QxtMailMessage::addAttachment(const QString &filename, const QxtMailAttachment &attach) { - if (qxt_d->attachments.contains(filename)) - { + if (qxt_d->attachments.contains(filename)) { qWarning() << "QxtMailMessage::addAttachment: " << filename << " already in use"; int i = 1; - while (qxt_d->attachments.contains(filename + "." + QString::number(i))) - { + while (qxt_d->attachments.contains(filename + "." + QString::number(i))) { i++; } - qxt_d->attachments[filename+"."+QString::number(i)] = attach; - } - else - { + qxt_d->attachments[filename + "." + QString::number(i)] = attach; + } else { qxt_d->attachments[filename] = attach; } } -void QxtMailMessage::removeAttachment(const QString& filename) +void QxtMailMessage::removeAttachment(const QString &filename) { qxt_d->attachments.remove(filename); } -QByteArray qxt_fold_mime_header(const QString& key, const QString& value, QTextCodec* latin1, const QByteArray& prefix) +QByteArray qxt_fold_mime_header(const QString &key, const QString &value, QTextCodec *latin1, const QByteArray &prefix) { QByteArray rv = ""; QByteArray line = key.toLatin1() + ": "; - if (!prefix.isEmpty()) line += prefix; - if (!value.contains("=?") && latin1->canEncode(value)) - { + if (!prefix.isEmpty()) + line += prefix; + if (!value.contains("=?") && latin1->canEncode(value)) { bool firstWord = true; - foreach(const QByteArray& word, value.toLatin1().split(' ')) - { - if (line.size() > 78) - { + foreach (const QByteArray &word, value.toLatin1().split(' ')) { + if (line.size() > 78) { rv = rv + line + "\r\n"; line.clear(); } @@ -227,9 +223,7 @@ QByteArray qxt_fold_mime_header(const QString& key, const QString& value, QTextC line += " " + word; firstWord = false; } - } - else - { + } else { // The text cannot be losslessly encoded as Latin-1. Therefore, we // must use quoted-printable or base64 encoding. This is a quick // heuristic based on the first 100 characters to see which @@ -237,43 +231,33 @@ QByteArray qxt_fold_mime_header(const QString& key, const QString& value, QTextC QByteArray utf8 = value.toUtf8(); int ct = utf8.length(); int nonAscii = 0; - for (int i = 0; i < ct && i < 100; i++) - { - if (QXT_MUST_QP(utf8[i])) nonAscii++; + for (int i = 0; i < ct && i < 100; i++) { + if (QXT_MUST_QP(utf8[i])) + nonAscii++; } - if (nonAscii > 20) - { + if (nonAscii > 20) { // more than 20%-ish non-ASCII characters: use base64 QByteArray base64 = utf8.toBase64(); ct = base64.length(); line += "=?utf-8?b?"; - for (int i = 0; i < ct; i += 4) - { - if (line.length() > 72) - { + for (int i = 0; i < ct; i += 4) { + if (line.length() > 72) { rv += line + "?\r\n"; line = " =?utf-8?b?"; } line = line + base64.mid(i, 4); } - } - else - { + } else { // otherwise use Q-encoding line += "=?utf-8?q?"; - for (int i = 0; i < ct; i++) - { - if (line.length() > 73) - { + for (int i = 0; i < ct; i++) { + if (line.length() > 73) { rv += line + "?\r\n"; line = " =?utf-8?q?"; } - if (QXT_MUST_QP(utf8[i]) || utf8[i] == ' ') - { + if (QXT_MUST_QP(utf8[i]) || utf8[i] == ' ') { line += "=" + utf8.mid(i, 1).toHex().toUpper(); - } - else - { + } else { line += utf8[i]; } } @@ -290,81 +274,67 @@ QByteArray QxtMailMessage::rfc2822() const // Use base64 if requested bool useBase64 = (extraHeader("Content-Transfer-Encoding").toLower() == "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"); + QTextCodec *latin1 = QTextCodec::codecForName("latin1"); bool bodyIsAscii = latin1->canEncode(body()) && !useQuotedPrintable && !useBase64; QHash attach = attachments(); QByteArray rv; - if (!sender().isEmpty() && !hasExtraHeader("From")) - { + if (!sender().isEmpty() && !hasExtraHeader("From")) { rv += qxt_fold_mime_header("From", sender(), latin1); } - if (!qxt_d->rcptTo.isEmpty()) - { + if (!qxt_d->rcptTo.isEmpty()) { rv += qxt_fold_mime_header("To", qxt_d->rcptTo.join(", "), latin1); } - if (!qxt_d->rcptCc.isEmpty()) - { + if (!qxt_d->rcptCc.isEmpty()) { rv += qxt_fold_mime_header("Cc", qxt_d->rcptCc.join(", "), latin1); } - if (!subject().isEmpty()) - { + if (!subject().isEmpty()) { rv += qxt_fold_mime_header("Subject", subject(), latin1); } - if (!bodyIsAscii) - { + if (!bodyIsAscii) { if (!hasExtraHeader("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) - { + 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++; + 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 (attach.count()) { if (qxt_d->boundary.isEmpty()) qxt_d->boundary = QUuid::createUuid().toString().toLatin1().replace("{", "").replace("}", ""); if (!hasExtraHeader("MIME-Version")) rv += "MIME-Version: 1.0\r\n"; if (!hasExtraHeader("Content-Type")) rv += "Content-Type: multipart/mixed; boundary=" + qxt_d->boundary + "\r\n"; - } - else if (!bodyIsAscii && !hasExtraHeader("Content-Transfer-Encoding")) - { - if (!useQuotedPrintable) - { + } else if (!bodyIsAscii && !hasExtraHeader("Content-Transfer-Encoding")) { + if (!useQuotedPrintable) { // base64 rv += "Content-Transfer-Encoding: base64\r\n"; - } - else - { + } else { // quoted-printable rv += "Content-Transfer-Encoding: quoted-printable\r\n"; } } - foreach(const QString& r, qxt_d->extraHeaders.keys()) - { - if ((r.toLower() == "content-type" || r.toLower() == "content-transfer-encoding") && attach.count()) - { + foreach (const QString &r, qxt_d->extraHeaders.keys()) { + if ((r.toLower() == "content-type" || r.toLower() == "content-transfer-encoding") && attach.count()) { // Since we're in multipart mode, we'll be outputting this later continue; } @@ -373,8 +343,7 @@ QByteArray QxtMailMessage::rfc2822() const rv += "\r\n"; - if (attach.count()) - { + 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: "; @@ -382,19 +351,13 @@ QByteArray QxtMailMessage::rfc2822() const rv += extraHeader("Content-Type") + "\r\n"; else rv += "text/plain; charset=UTF-8\r\n"; - if (hasExtraHeader("Content-Transfer-Encoding")) - { + if (hasExtraHeader("Content-Transfer-Encoding")) { rv += "Content-Transfer-Encoding: " + extraHeader("Content-Transfer-Encoding") + "\r\n"; - } - else if (!bodyIsAscii) - { - if (!useQuotedPrintable) - { + } else if (!bodyIsAscii) { + if (!useQuotedPrintable) { // base64 rv += "Content-Transfer-Encoding: base64\r\n"; - } - else - { + } else { // quoted-printable rv += "Content-Transfer-Encoding: quoted-printable\r\n"; } @@ -402,132 +365,100 @@ QByteArray QxtMailMessage::rfc2822() const rv += "\r\n"; } - if (bodyIsAscii) - { + 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()) - { + 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) - { + } else if (line.length() + word.length() + 1 <= 78) { line = line + ' ' + word; word = ""; } - if(line[0] == '.') + if (line[0] == '.') rv += "."; rv += line + "\r\n"; - if ((b[i+1] == '\n' || b[i+1] == '\r') && b[i] != b[i+1]) - { + 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] == '.') + } 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()) - { + } else if (line.isEmpty()) { line = word; - } - else - { + } else { line = line + ' ' + word; } word = ""; - } - else - { + } else { word += b[i]; } } - if (line.length() + word.length() + 1 > 78) - { - if(line[0] == '.') + if (line.length() + word.length() + 1 > 78) { + if (line[0] == '.') rv += "."; rv += line + "\r\n"; line = word; - } - else if (!word.isEmpty()) - { + } else if (!word.isEmpty()) { line += ' ' + word; } - if(!line.isEmpty()) { - if(line[0] == '.') + if (!line.isEmpty()) { + if (line[0] == '.') rv += "."; rv += line + "\r\n"; } - } - else if (useQuotedPrintable) - { + } 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] == '.') + 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 ((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) - { + } else if (line.length() > 74) { rv += line + "=\r\n"; line = ""; } - if (QXT_MUST_QP(b[i])) - { + if (QXT_MUST_QP(b[i])) { line += "=" + b.mid(i, 1).toHex().toUpper(); - } - else - { + } else { line += b[i]; } } - if(!line.isEmpty()) { - if(line[0] == '.') + if (!line.isEmpty()) { + if (line[0] == '.') rv += "."; rv += line + "\r\n"; } - } - else /* base64 */ + } else /* base64 */ { QByteArray b = body().toUtf8().toBase64(); int ct = b.length(); - for (int i = 0; i < ct; i += 78) - { + for (int i = 0; i < ct; i += 78) { rv += b.mid(i, 78) + "\r\n"; } } - if (attach.count()) - { - foreach(const QString& filename, attach.keys()) - { + if (attach.count()) { + foreach (const QString &filename, attach.keys()) { rv += "--" + qxt_d->boundary + "\r\n"; - rv += qxt_fold_mime_header("Content-Disposition", QDir(filename).dirName(), latin1, "attachment; filename="); + rv += + qxt_fold_mime_header("Content-Disposition", QDir(filename).dirName(), latin1, "attachment; filename="); rv += attach[filename].mimeData(); } rv += "--" + qxt_d->boundary + "--\r\n";