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 }