File indexing completed on 2025-02-02 05:08:36

0001 /*
0002     SPDX-FileCopyrightText: 2023-2024 Laurent Montel <montel.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "resource.h"
0008 #include "accountwizard_debug.h"
0009 
0010 #include <KLocalizedString>
0011 
0012 #include <Akonadi/AgentInstanceCreateJob>
0013 #include <Akonadi/AgentManager>
0014 #include <Akonadi/AgentType>
0015 #include <Akonadi/ServerManager>
0016 
0017 #include <QDBusInterface>
0018 #include <QDBusReply>
0019 #include <QMetaMethod>
0020 
0021 using namespace Akonadi;
0022 
0023 static QMetaType::Type argumentType(const QMetaObject *mo, const QString &method)
0024 {
0025     QMetaMethod m;
0026     const int numberOfMethod(mo->methodCount());
0027     for (int i = 0; i < numberOfMethod; ++i) {
0028         const QString signature = QLatin1StringView(mo->method(i).methodSignature());
0029         if (signature.contains(method + QLatin1Char('('))) {
0030             m = mo->method(i);
0031             break;
0032         }
0033     }
0034 
0035     if (m.methodSignature().isEmpty()) {
0036         qCWarning(ACCOUNTWIZARD_LOG) << "Did not find D-Bus method: " << method << " available methods are:";
0037         for (int i = 0; i < numberOfMethod; ++i) {
0038             qCWarning(ACCOUNTWIZARD_LOG) << mo->method(i).methodSignature();
0039         }
0040         return QMetaType::UnknownType;
0041     }
0042 
0043     const QList<QByteArray> argTypes = m.parameterTypes();
0044     if (argTypes.count() != 1) {
0045         return QMetaType::UnknownType;
0046     }
0047 
0048     return static_cast<QMetaType::Type>(QMetaType::fromName(argTypes.first().constData()).id());
0049 }
0050 
0051 Resource::Resource(QObject *parent)
0052     : SetupBase{parent}
0053 {
0054 }
0055 
0056 Resource::~Resource() = default;
0057 
0058 void Resource::createResource()
0059 {
0060     if (!mResourceInfo.isValid()) {
0061         qCWarning(ACCOUNTWIZARD_LOG) << "mResourceInfo is not valid. It's a bug.";
0062         qCWarning(ACCOUNTWIZARD_LOG) << " mResourceInfo " << mResourceInfo;
0063         deleteLater();
0064         return;
0065     }
0066     const AgentType type = AgentManager::self()->type(mResourceInfo.typeIdentifier);
0067     if (!type.isValid()) {
0068         Q_EMIT error(i18n("Resource type '%1' is not available.", mResourceInfo.typeIdentifier));
0069         deleteLater();
0070         return;
0071     }
0072 
0073     // By default imap/kolab/pop3 can't be unique. Keep it only for be safe.
0074     // check if unique instance already exists
0075     // qCDebug(ACCOUNTWIZARD_LOG) << type.capabilities();
0076     if (type.capabilities().contains(QLatin1StringView("Unique"))) {
0077         const Akonadi::AgentInstance::List lstAgent = AgentManager::self()->instances();
0078         for (const AgentInstance &instance : lstAgent) {
0079             // qCDebug(ACCOUNTWIZARD_LOG) << instance.type().identifier() << (instance.type() == type);
0080             if (instance.type() == type) {
0081                 Q_EMIT finished(i18n("Resource '%1' is already set up.", type.name()));
0082                 deleteLater();
0083                 return;
0084             }
0085         }
0086     }
0087 
0088     Q_EMIT info(i18n("Creating resource instance for '%1'...", type.name()));
0089     auto job = new AgentInstanceCreateJob(type, this);
0090     connect(job, &AgentInstanceCreateJob::result, this, &Resource::instanceCreateResult);
0091     job->start();
0092 }
0093 
0094 void Resource::instanceCreateResult(KJob *job)
0095 {
0096     if (job->error()) {
0097         Q_EMIT error(i18n("Failed to create resource instance: %1", job->errorText()));
0098         deleteLater();
0099         return;
0100     }
0101     mInstance = qobject_cast<AgentInstanceCreateJob *>(job)->instance();
0102 
0103     if (!mResourceInfo.settings.isEmpty()) {
0104         Q_EMIT info(i18n("Configuring resource instance..."));
0105         const auto service = ServerManager::agentServiceName(ServerManager::Resource, mInstance.identifier());
0106         QDBusInterface iface(service, QStringLiteral("/Settings"));
0107         if (!iface.isValid()) {
0108             Q_EMIT error(i18n("Unable to configure resource instance."));
0109             deleteLater();
0110             return;
0111         }
0112 
0113         // configure resource
0114         if (!mResourceInfo.name.isEmpty()) {
0115             mInstance.setName(mResourceInfo.name);
0116         }
0117         QMap<QString, QVariant>::const_iterator end(mResourceInfo.settings.constEnd());
0118         for (QMap<QString, QVariant>::const_iterator it = mResourceInfo.settings.constBegin(); it != end; ++it) {
0119             qCDebug(ACCOUNTWIZARD_LOG) << "Setting up " << it.key() << " for agent " << mInstance.identifier();
0120             const QString methodName = QStringLiteral("set%1").arg(it.key());
0121             const QVariant arg = it.value();
0122             const QMetaType::Type targetType = argumentType(iface.metaObject(), methodName);
0123             if (arg.metaType().id() != targetType) {
0124                 Q_EMIT error(i18n("Could not convert value of setting '%1' to required type %2.", it.key(), QLatin1StringView(QMetaType(targetType).name())));
0125 
0126                 qCWarning(ACCOUNTWIZARD_LOG) << "Impossible to convert argument : " << arg
0127                                              << QStringLiteral("Could not convert value of setting '%1' to required type %2.")
0128                                                     .arg(it.key(), QLatin1StringView(QMetaType(targetType).name()));
0129                 return;
0130             }
0131             // arg.convert(targetType);
0132             QDBusReply<void> reply = iface.call(methodName, arg);
0133             if (!reply.isValid()) {
0134                 Q_EMIT error(i18n("Could not set setting '%1': %2", it.key(), reply.error().message()));
0135                 return;
0136             }
0137         }
0138         QDBusReply<void> reply = iface.call(QStringLiteral("save"));
0139         if (!reply.isValid()) {
0140             Q_EMIT error(i18n("Could not save settings: %1", reply.error().message()));
0141             return;
0142         }
0143         mInstance.reconfigure();
0144     }
0145 
0146     Q_EMIT finished(i18n("Resource setup completed."));
0147     deleteLater();
0148 }
0149 
0150 Resource::ResourceInfo Resource::resourceInfo() const
0151 {
0152     return mResourceInfo;
0153 }
0154 
0155 void Resource::setResourceInfo(const ResourceInfo &newResourceInfo)
0156 {
0157     mResourceInfo = newResourceInfo;
0158 }
0159 
0160 QDebug operator<<(QDebug d, const Resource::ResourceInfo &t)
0161 {
0162     d << "name: " << t.name;
0163     d << "typeIdentifier: " << t.typeIdentifier;
0164     d << "settings: " << t.settings;
0165     return d;
0166 }
0167 
0168 bool Resource::ResourceInfo::isValid() const
0169 {
0170     return !name.isEmpty() && !typeIdentifier.isEmpty() && !settings.isEmpty();
0171 }
0172 
0173 #include "moc_resource.cpp"