diff --git a/plugins/messageviewer/bodypartformatter/vcard/text_vcard.cpp b/plugins/messageviewer/bodypartformatter/vcard/text_vcard.cpp index 6ca12a32..d220f822 100644 --- a/plugins/messageviewer/bodypartformatter/vcard/text_vcard.cpp +++ b/plugins/messageviewer/bodypartformatter/vcard/text_vcard.cpp @@ -1,335 +1,335 @@ /* This file is part of KMail, the KDE mail client. Copyright (c) 2004 Till Adam Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company Copyright (C) 2012-2020 Laurent Montel KMail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. KMail is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include "updatecontactjob.h" #include "vcardmemento.h" #include "vcard_debug.h" #include #include #include #include #include #include #include #include #include using MimeTreeParser::Interface::BodyPart; #include #include #include #include #include #include #include #include #include #include #include #include namespace { class Formatter : public MessageViewer::MessagePartRendererBase { public: Formatter() = default; bool render(const MimeTreeParser::MessagePartPtr &msgPart, MessageViewer::HtmlWriter *writer, MessageViewer::RenderContext *) const override { QMimeDatabase db; auto mt = db.mimeTypeForName(QString::fromLatin1(msgPart->content()->contentType()->mimeType().toLower())); if (!mt.isValid() || mt.name() != QLatin1String("text/vcard")) { return false; } const QString vCard = msgPart->text(); if (vCard.isEmpty()) { return false; } KContacts::VCardConverter vcc; MessageViewer::VcardMemento *memento = dynamic_cast(msgPart->memento()); QStringList lst; // Pre-count the number of non-empty addressees int count = 0; const KContacts::Addressee::List al = vcc.parseVCards(vCard.toUtf8()); for (const KContacts::Addressee &a : al) { if (a.isEmpty()) { continue; } if (!memento) { if (!a.emails().isEmpty()) { lst.append(a.emails().first()); count++; } } } if (!count && !memento) { return false; } writer->write(QStringLiteral("

") +i18np("Attached business card", "Attached business cards", count) +QStringLiteral("

")); count = 0; static QString defaultPixmapPath = QUrl::fromLocalFile(KIconLoader::global()->iconPath(QStringLiteral("user-identity"), KIconLoader::Desktop)).url(); static QString defaultMapIconPath = QUrl::fromLocalFile(KIconLoader::global()->iconPath(QStringLiteral("document-open-remote"), KIconLoader::Small)).url(); if (!memento) { MessageViewer::VcardMemento *memento = new MessageViewer::VcardMemento(lst); msgPart->setMemento(memento); auto nodeHelper = msgPart->nodeHelper(); if (nodeHelper) { QObject::connect(memento, &MessageViewer::VcardMemento::update, nodeHelper, &MimeTreeParser::NodeHelper::update); } } for (const KContacts::Addressee &a : al) { if (a.isEmpty()) { continue; } Akonadi::StandardContactFormatter formatter; formatter.setContact(a); formatter.setDisplayQRCode(false); QString htmlStr = formatter.toHtml(Akonadi::StandardContactFormatter::EmbeddableForm); const KContacts::Picture photo = a.photo(); htmlStr.replace(QStringLiteral("nodeHelper()->createTempDir(QLatin1String("vcard-") + a.uid()); const QString filename = dir + QLatin1Char('/') + a.uid(); img.save(filename, "PNG"); msgPart->nodeHelper()->addTempFile(filename); const QString href = QLatin1String("file:") + QLatin1String(QUrl::toPercentEncoding(filename)); htmlStr.replace(QLatin1String("img src=\"contact_photo\""), QStringLiteral("img src=\"%1\"").arg(href)); } writer->write(htmlStr); if (!memento || (memento && !memento->finished()) || (memento && memento->finished() && !memento->vcardExist(count))) { const QString addToLinkText = i18n("[Add this contact to the address book]"); QString op = QStringLiteral("addToAddressBook:%1").arg(count); writer->write(QStringLiteral("

")); } else { if (memento->address(count) != a) { - const QString addToLinkText = i18n("[Update this contact to the address book]"); + const QString addToLinkText = i18n("[Update this contact in the address book]"); const QString op = QStringLiteral("updateToAddressBook:%1").arg(count); writer->write(QStringLiteral("

")); } else { const QString addToLinkText = i18n("[This contact is already in addressbook]"); writer->write(QStringLiteral("
") +addToLinkText +QStringLiteral("


")); } } count++; } return true; } }; class UrlHandler : public MessageViewer::Interface::BodyPartURLHandler { public: QString name() const override { return QStringLiteral("vcardhandler"); } bool handleClick(MessageViewer::Viewer *viewerInstance, BodyPart *bodyPart, const QString &path) const override { Q_UNUSED(viewerInstance); const QString vCard = bodyPart->content()->decodedText(); if (vCard.isEmpty()) { return true; } KContacts::VCardConverter vcc; const KContacts::Addressee::List al = vcc.parseVCards(vCard.toUtf8()); const int index = path.rightRef(path.length() - path.lastIndexOf(QLatin1Char(':')) - 1).toInt(); if (index == -1 || index >= al.count()) { return true; } const KContacts::Addressee a = al.at(index); if (a.isEmpty()) { return true; } if (path.startsWith(QLatin1String("addToAddressBook"))) { KPIM::AddContactJob *job = new KPIM::AddContactJob(a, nullptr); job->start(); } else if (path.startsWith(QLatin1String("updateToAddressBook"))) { UpdateContactJob *job = new UpdateContactJob(a.emails().first(), a, nullptr); job->start(); } return true; } static KContacts::Addressee findAddressee(BodyPart *part, const QString &path) { const QString vCard = part->content()->decodedText(); if (!vCard.isEmpty()) { KContacts::VCardConverter vcc; const KContacts::Addressee::List al = vcc.parseVCards(vCard.toUtf8()); const int index = path.rightRef(path.length() - path.lastIndexOf(QLatin1Char(':')) - 1).toInt(); if (index >= 0 && index < al.count()) { return al.at(index); } } return KContacts::Addressee(); } bool handleContextMenuRequest(BodyPart *part, const QString &path, const QPoint &point) const override { const QString vCard = part->content()->decodedText(); if (vCard.isEmpty()) { return true; } KContacts::Addressee a = findAddressee(part, path); if (a.isEmpty()) { return true; } QMenu *menu = new QMenu(); QAction *open = menu->addAction(QIcon::fromTheme(QStringLiteral("document-open")), i18n("View Business Card")); QAction *saveas = menu->addAction(QIcon::fromTheme(QStringLiteral("document-save-as")), i18n("Save Business Card As...")); QAction *action = menu->exec(point, nullptr); if (action == open) { openVCard(a, vCard); } else if (action == saveas) { saveAsVCard(a, vCard); } delete menu; return true; } QString statusBarMessage(BodyPart *part, const QString &path) const override { KContacts::Addressee a = findAddressee(part, path); const bool addToAddressBook = path.startsWith(QLatin1String("addToAddressBook")); if (a.realName().isEmpty()) { return addToAddressBook ? i18n("Add this contact to the address book.") : i18n("Update this contact to the address book."); } else { return addToAddressBook ? i18n("Add \"%1\" to the address book.", a.realName()) : i18n("Update \"%1\" to the address book.", a.realName()); } } bool openVCard(const KContacts::Addressee &a, const QString &vCard) const { Q_UNUSED(vCard); Akonadi::ContactViewer *view = new Akonadi::ContactViewer(nullptr); view->setRawContact(a); view->setMinimumSize(300, 400); view->show(); return true; } bool saveAsVCard(const KContacts::Addressee &a, const QString &vCard) const { QString fileName; const QString givenName(a.givenName()); if (givenName.isEmpty()) { fileName = a.familyName() + QStringLiteral(".vcf"); } else { fileName = givenName + QLatin1Char('_') + a.familyName() + QStringLiteral(".vcf"); } // get the saveas file name QUrl saveAsUrl = QFileDialog::getSaveFileUrl(nullptr, i18n("Save Business Card"), QUrl::fromUserInput(fileName)); if (saveAsUrl.isEmpty()) { return false; } // put the attachment in a temporary file and save it QTemporaryFile tmpFile; tmpFile.open(); QByteArray data = vCard.toUtf8(); tmpFile.write(data); tmpFile.flush(); auto job = KIO::file_copy(QUrl::fromLocalFile(tmpFile.fileName()), saveAsUrl, -1, KIO::Overwrite); return job->exec(); } }; class Plugin : public QObject, public MessageViewer::MessagePartRenderPlugin { Q_OBJECT Q_INTERFACES(MessageViewer::MessagePartRenderPlugin) Q_PLUGIN_METADATA(IID "com.kde.messageviewer.bodypartformatter" FILE "text_vcard.json") public: MessageViewer::MessagePartRendererBase *renderer(int index) override { return validIndex(index) ? new Formatter() : nullptr; } const MessageViewer::Interface::BodyPartURLHandler *urlHandler(int idx) const override { return validIndex(idx) ? new UrlHandler() : nullptr; } private: bool validIndex(int idx) const { return idx == 0; } }; } #include "text_vcard.moc" diff --git a/plugins/messageviewer/bodypartformatter/vcard/updatecontactjob.cpp b/plugins/messageviewer/bodypartformatter/vcard/updatecontactjob.cpp index ab5872da..2f4b09ed 100644 --- a/plugins/messageviewer/bodypartformatter/vcard/updatecontactjob.cpp +++ b/plugins/messageviewer/bodypartformatter/vcard/updatecontactjob.cpp @@ -1,106 +1,106 @@ /* Copyright (C) 2012-2020 Laurent Montel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "updatecontactjob.h" #include #include #include #include #include UpdateContactJob::UpdateContactJob(const QString &email, const KContacts::Addressee &contact, QWidget *parentWidget, QObject *parent) : KJob(parent) , mEmail(email) , mContact(contact) , mParentWidget(parentWidget) { } UpdateContactJob::~UpdateContactJob() { } void UpdateContactJob::slotSearchDone(KJob *job) { if (job->error()) { setError(job->error()); setErrorText(job->errorText()); emitResult(); return; } const Akonadi::ContactSearchJob *searchJob = qobject_cast(job); const KContacts::Addressee::List contacts = searchJob->contacts(); if (contacts.isEmpty()) { const QString text = i18n("The vCard's primary email address is not in addressbook."); KMessageBox::information(mParentWidget, text); setError(UserDefinedError); emitResult(); return; } else if (contacts.count() > 1) { const QString text = i18n("There are two or more contacts with same email stored in addressbook."); KMessageBox::information(mParentWidget, text); setError(UserDefinedError); emitResult(); return; } Akonadi::Item item = searchJob->items().at(0); item.setPayload(mContact); Akonadi::ItemModifyJob *modifyJob = new Akonadi::ItemModifyJob(item); connect(modifyJob, &Akonadi::ItemModifyJob::result, this, &UpdateContactJob::slotUpdateContactDone); } void UpdateContactJob::slotUpdateContactDone(KJob *job) { if (job->error()) { setError(job->error()); setErrorText(job->errorText()); emitResult(); return; } - const QString text = i18n("The vCard was updated to your address book; " + const QString text = i18n("The vCard was updated in your address book; " "you can add more information to this " "entry by opening the address book."); KMessageBox::information(mParentWidget, text, QString(), QStringLiteral("updatedtokabc")); emitResult(); } void UpdateContactJob::start() { if (mEmail.isEmpty()) { const QString text = i18n("Email not specified"); KMessageBox::information(mParentWidget, text); setError(UserDefinedError); emitResult(); return; } // first check whether a contact with the same email exists already Akonadi::ContactSearchJob *searchJob = new Akonadi::ContactSearchJob(this); searchJob->setLimit(1); searchJob->setQuery(Akonadi::ContactSearchJob::Email, mEmail.toLower(), Akonadi::ContactSearchJob::ExactMatch); connect(searchJob, &Akonadi::ContactSearchJob::result, this, &UpdateContactJob::slotSearchDone); } #include "moc_updatecontactjob.cpp"