File indexing completed on 2024-11-24 04:52:55
0001 /* Copyright (C) 2013 Pali Rohár <pali.rohar@gmail.com> 0002 0003 This file is part of the Trojita Qt IMAP e-mail client, 0004 http://trojita.flaska.net/ 0005 0006 This program is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU General Public License as 0008 published by the Free Software Foundation; either version 2 of 0009 the License or (at your option) version 3 or any later version 0010 accepted by the membership of KDE e.V. (or its successor approved 0011 by the membership of KDE e.V.), which shall act as a proxy 0012 defined in Section 14 of version 3 of the license. 0013 0014 This program is distributed in the hope that it will be useful, 0015 but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0017 GNU General Public License for more details. 0018 0019 You should have received a copy of the GNU General Public License 0020 along with this program. If not, see <http://www.gnu.org/licenses/>. 0021 */ 0022 0023 #include <QByteArray> 0024 #include <QList> 0025 #include <QPair> 0026 #include <QString> 0027 #include <QStringList> 0028 #include <QUrl> 0029 #include <QUrlQuery> 0030 0031 #include "Mailto.h" 0032 #include "Recipients.h" 0033 0034 #include "Imap/Encoders.h" 0035 0036 namespace { 0037 0038 QString fromRFC2047PercentEncoding(const QByteArray &str) 0039 { 0040 return Imap::decodeRFC2047String(QByteArray::fromPercentEncoding(str)); 0041 } 0042 0043 QStringList stringListFromRFC2047PercentEncoding(const QByteArray &str) 0044 { 0045 const QList<QByteArray> &list = str.split(','); 0046 QStringList ret; 0047 Q_FOREACH(const QByteArray &a, list) { 0048 if (a.isEmpty()) 0049 continue; 0050 ret << fromRFC2047PercentEncoding(a); 0051 } 0052 return ret; 0053 } 0054 0055 QList<QByteArray> arrayListFromPercentEncoding(const QByteArray &str) 0056 { 0057 const QList<QByteArray> &list = str.split(','); 0058 QList<QByteArray> ret; 0059 Q_FOREACH(const QByteArray &a, list) { 0060 if (a.isEmpty()) 0061 continue; 0062 ret << QByteArray::fromPercentEncoding(a); 0063 } 0064 return ret; 0065 } 0066 0067 } 0068 0069 namespace Composer { 0070 0071 void parseRFC6068Mailto(const QUrl &url, QString &subject, QString &body, 0072 QList<QPair<Composer::RecipientKind, QString>> &recipients, 0073 QList<QByteArray> &inReplyTo, QList<QByteArray> &references) 0074 { 0075 if (url.isEmpty() || url.scheme() != QLatin1String("mailto")) 0076 return; 0077 0078 Q_FOREACH(const QString &addr, stringListFromRFC2047PercentEncoding(url.path(QUrl::FullyEncoded).toUtf8())) { 0079 recipients << qMakePair(Composer::ADDRESS_TO, addr); 0080 } 0081 0082 const QList<QPair<QString,QString>> &stringItems = QUrlQuery(url).queryItems(QUrl::FullyEncoded); 0083 QList<QPair<QByteArray,QByteArray>> items; 0084 for (int i = 0; i < stringItems.size(); ++i) { 0085 items << qMakePair(stringItems[i].first.toUtf8(), stringItems[i].second.toUtf8()); 0086 } 0087 0088 for (int i = 0; i < items.size(); ++i) { 0089 if (items[i].first.toLower() == "to") { 0090 Q_FOREACH(const QString &addr, stringListFromRFC2047PercentEncoding(items[i].second)) 0091 recipients << qMakePair(Composer::ADDRESS_TO, addr); 0092 } else if (items[i].first.toLower() == "cc") { 0093 Q_FOREACH(const QString &addr, stringListFromRFC2047PercentEncoding(items[i].second)) 0094 recipients << qMakePair(Composer::ADDRESS_CC, addr); 0095 } else if (items[i].first.toLower() == "bcc") { 0096 Q_FOREACH(const QString &addr, stringListFromRFC2047PercentEncoding(items[i].second)) 0097 recipients << qMakePair(Composer::ADDRESS_BCC, addr); 0098 } else if (items[i].first.toLower() == "subject") { 0099 subject = fromRFC2047PercentEncoding(items[i].second); 0100 } else if (items[i].first.toLower() == "body") { 0101 // RFC 6068: Body does not contain MIME encoded words 0102 body = QUrl::fromPercentEncoding(items[i].second); 0103 } else if (items[i].first.toLower() == "in-reply-to") { 0104 inReplyTo << arrayListFromPercentEncoding(items[i].second); 0105 } else if (items[i].first.toLower() == "references") { 0106 references << arrayListFromPercentEncoding(items[i].second); 0107 } 0108 } 0109 } 0110 0111 /** @short Extract just the plain old user.name@example.org from a mailto: URL 0112 0113 It is an error if there is more than one recipients in that URL. All fancy data are also stripped awaya. 0114 */ 0115 QString extractOneMailAddress(const QUrl &url) 0116 { 0117 QString subj, body; 0118 QList<QPair<Composer::RecipientKind, QString>> recipients; 0119 QList<QByteArray> inReplyTo, references; 0120 parseRFC6068Mailto(url, subj, body, recipients, inReplyTo, references); 0121 if (recipients.size() == 1) { 0122 return recipients[0].second; 0123 } else { 0124 return QString(); 0125 } 0126 } 0127 0128 }