provider-plugin-proxy.cpp

00001 /*
00002  * This file is part of accounts-ui
00003  *
00004  * Copyright (C) 2011 Nokia Corporation.
00005  *
00006  * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public License
00010  * version 2.1 as published by the Free Software Foundation.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00020  * 02110-1301 USA
00021  */
00022 
00023 #include "provider-plugin-proxy.h"
00024 #include "provider-plugin-proxy-priv.h"
00025 
00026 #include <Accounts/Manager>
00027 
00028 #include <QDebug>
00029 #include <QLocalServer>
00030 #include <QLocalSocket>
00031 
00032 using namespace Accounts;
00033 using namespace AccountSetup;
00034 
00035 
00036 ProviderPluginProxyPrivate::~ProviderPluginProxyPrivate()
00037 {
00038     qDebug() << Q_FUNC_INFO;
00039     if (process) {
00040         process->disconnect();
00041         process->close();
00042         delete process;
00043     }
00044 }
00045 
00046 void ProviderPluginProxyPrivate::startProcess(Provider *provider,
00047                                               AccountId accountId,
00048                                               const QString &serviceType)
00049 {
00050     Q_Q(ProviderPluginProxy);
00051 
00052     error = ProviderPluginProxy::NoError;
00053     createdAccountId = 0;
00054     pluginOutput.clear();
00055 
00056     QString processName;
00057     QString pluginFileName;
00058 
00059     if (!findPlugin(provider, processName, pluginFileName)) {
00060         error = ProviderPluginProxy::PluginNotFound;
00061         emit q->finished();
00062         return;
00063     }
00064     providerName = provider->name();
00065     pid_t pid = getpid();
00066     socketName = provider->name() + QString::number(pid);
00067 
00068     QStringList arguments;
00069     arguments << QLatin1String("--socketName") << socketName;
00070 
00071     if (parentWidget != 0) {
00072         WId windowId = parentWidget->effectiveWinId();
00073         arguments << QLatin1String("--windowId") << QString::number(windowId);
00074     }
00075 
00076     if (accountId != 0) {
00077         arguments << QLatin1String("--edit") << QString::number(accountId);
00078         setupType = EditExisting;
00079     } else {
00080         arguments << QLatin1String("--create") << provider->name();
00081         setupType = CreateNew;
00082     }
00083 
00084     if (!serviceType.isEmpty())
00085         arguments << QLatin1String("--serviceType") << serviceType;
00086 
00087     arguments += additionalParameters;
00088 
00089 #ifndef QT_NO_DEBUG_OUTPUT
00090     arguments << QLatin1String("-output-level") << QLatin1String("debug");
00091 #endif
00092 
00093     if (!process)
00094         process = new QProcess();
00095 
00096     pluginName = pluginFileName;
00097 
00098     qDebug() << Q_FUNC_INFO << processName << arguments;
00099 
00100     connect(process, SIGNAL(readyReadStandardError()),
00101             this, SLOT(onReadStandardError()));
00102     connect(process, SIGNAL(error(QProcess::ProcessError)),
00103             this, SLOT(onError(QProcess::ProcessError)));
00104     connect(process, SIGNAL(finished(int, QProcess::ExitStatus)),
00105             this, SLOT(onFinished(int, QProcess::ExitStatus)));
00106     connect(process, SIGNAL(started()), this, SLOT(setCommunicationChannel()));
00107 
00108     process->start(processName, arguments);
00109 }
00110 
00111 bool ProviderPluginProxyPrivate::findPlugin(Provider *provider,
00112                                             QString &pluginPath,
00113                                             QString &pluginFileName)
00114 {
00115     static const char pluginNamePattern[] = "%1plugin";
00116     bool pluginTagExists = true;
00117 
00118     QDomElement root(provider->domDocument().documentElement());
00119     QString pluginName(root.
00120                        firstChildElement(QString::fromLatin1("plugin")).
00121                        text());
00122     if (pluginName.isEmpty()) {
00123         pluginName = provider->name();
00124         pluginTagExists = false;
00125     }
00126 
00127     QStringList pluginFileNames;
00128     pluginFileNames << QString::fromLatin1(pluginNamePattern).arg(pluginName);
00129 
00130     /* If a plugin for the specified name cannot be found and
00131      * the plugin is not specified in the provider file, fallback to
00132      * "genericplugin"
00133      */
00134     if (!pluginTagExists) {
00135         pluginFileNames << QString::fromLatin1(pluginNamePattern).
00136             arg(QLatin1String("generic"));
00137     }
00138 
00139     foreach (QString name, pluginFileNames) {
00140         foreach (QString pluginDir, pluginDirs) {
00141             QFileInfo pluginFileInfo(pluginDir, name);
00142 
00143             if (pluginFileInfo.exists()) {
00144                 pluginPath = pluginFileInfo.canonicalFilePath();
00145                 pluginFileName = name;
00146                 return true;
00147             }
00148         }
00149     }
00150 
00151     return false;
00152 }
00153 
00154 void ProviderPluginProxyPrivate::setCommunicationChannel()
00155 {
00156     QLocalServer *server = new QLocalServer();
00157     QLocalServer::removeServer(socketName);
00158     if (!server->listen(socketName))
00159         qWarning() << "Server not up";
00160     else
00161         connect(server, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
00162 }
00163 
00164 void ProviderPluginProxyPrivate::onNewConnection()
00165 {
00166     QLocalServer *server = qobject_cast<QLocalServer*>(sender());
00167     QLocalSocket *socket = server->nextPendingConnection();
00168     if (!socket->waitForConnected()) {
00169         qWarning() << "Server Connection not established";
00170         return;
00171     }
00172     if (!socket->waitForReadyRead()) {
00173         qWarning() << "Server data not available for reading";
00174         return;
00175     }
00176     pluginOutput = socket->readAll();
00177     socket->close();
00178 }
00179 
00180 
00181 void ProviderPluginProxyPrivate::onReadStandardError()
00182 {
00183     qDebug() << QString::fromLatin1(process->readAllStandardError());
00184 }
00185 
00186 void ProviderPluginProxyPrivate::onError(QProcess::ProcessError err)
00187 {
00188     Q_Q(ProviderPluginProxy);
00189 
00190     if (err == QProcess::FailedToStart) {
00191         pluginName.clear();
00192         error = ProviderPluginProxy::PluginCrashed;
00193 
00194         emit q->finished();
00195         if (process) {
00196             process->deleteLater();
00197             process = NULL;
00198         }
00199     }
00200 
00201     qDebug() << "Error: " << err;
00202 }
00203 
00204 void ProviderPluginProxyPrivate::onFinished(int exitCode,
00205                                             QProcess::ExitStatus exitStatus)
00206 {
00207     Q_Q(ProviderPluginProxy);
00208     Q_UNUSED(exitCode);
00209 
00210     pluginName.clear();
00211 
00212     if (exitStatus == QProcess::CrashExit) {
00213         error = ProviderPluginProxy::PluginCrashed;
00214         emit q->finished();
00215         process->deleteLater();
00216         process = NULL;
00217         return;
00218     }
00219 
00220     QString value;
00221     if (!pluginOutput.isEmpty()) {
00222         QDataStream stream(pluginOutput);
00223         stream.device()->seek(0);
00224         stream >> createdAccountId >> exitData;
00225     }
00226 
00227     if (process) {
00228         process->deleteLater();
00229         process = NULL;
00230     }
00231 
00232     emit q->finished();
00233 }
00234 
00235 ProviderPluginProxy::ProviderPluginProxy(QObject *parent):
00236     QObject(parent),
00237     d_ptr(new ProviderPluginProxyPrivate(this))
00238 {
00239 }
00240 
00241 ProviderPluginProxy::~ProviderPluginProxy()
00242 {
00243     Q_D(ProviderPluginProxy);
00244     delete d;
00245 }
00246 
00247 void ProviderPluginProxy::createAccount(Accounts::Provider *provider,
00248                                         const QString &serviceType)
00249 {
00250     Q_D(ProviderPluginProxy);
00251 
00252     if (!provider) {
00253         qCritical() << " NULL pointer to provider";
00254         d->error = ProviderPluginProxy::PluginNotFound;
00255         emit finished();
00256         return;
00257     }
00258 
00259     d->startProcess(provider, 0, serviceType);
00260 }
00261 
00262 void ProviderPluginProxy::editAccount(Accounts::Account *account,
00263                                       const QString &serviceType)
00264 {
00265     Q_D(ProviderPluginProxy);
00266 
00267     if (!account) {
00268         qCritical() << " NULL pointer to account";
00269         d->error = ProviderPluginProxy::AccountNotFound;
00270         emit finished();
00271         return;
00272     }
00273 
00274     Manager *manager = account->manager();
00275     Provider *provider = manager->provider(account->providerName());
00276     d->startProcess(provider, account->id(), serviceType);
00277 }
00278 
00279 void ProviderPluginProxy::setParentWidget(QWidget *parent)
00280 {
00281     Q_D(ProviderPluginProxy);
00282     d->parentWidget = parent;
00283 }
00284 
00285 void ProviderPluginProxy::setPluginDirectories(const QStringList &pluginDirs)
00286 {
00287     Q_D(ProviderPluginProxy);
00288     d->pluginDirs = pluginDirs;
00289 }
00290 
00291 QStringList ProviderPluginProxy::pluginDirectories() const
00292 {
00293     Q_D(const ProviderPluginProxy);
00294     return d->pluginDirs;
00295 }
00296 
00297 bool ProviderPluginProxy::accountCreated() const
00298 {
00299     Q_D(const ProviderPluginProxy);
00300     return d->createdAccountId != 0;
00301 }
00302 
00303 ProviderPluginProxy::Error ProviderPluginProxy::error() const
00304 {
00305     Q_D(const ProviderPluginProxy);
00306     return d->error;
00307 }
00308 
00309 Accounts::AccountId ProviderPluginProxy::createdAccountId() const
00310 {
00311     Q_D(const ProviderPluginProxy);
00312     return d->createdAccountId;
00313 }
00314 
00315 bool ProviderPluginProxy::isPluginRunning()
00316 {
00317     Q_D(ProviderPluginProxy);
00318     return d->process != 0;
00319 }
00320 
00321 SetupType ProviderPluginProxy::setupType() const
00322 {
00323     Q_D(const ProviderPluginProxy);
00324     return d->setupType;
00325 }
00326 
00327 QString ProviderPluginProxy::pluginName()
00328 {
00329     if (!isPluginRunning())
00330         return QString();
00331 
00332     Q_D(ProviderPluginProxy);
00333     return d->pluginName;
00334 }
00335 
00336 QString ProviderPluginProxy::providerName()
00337 {
00338     if (!isPluginRunning())
00339         return QString();
00340     Q_D(ProviderPluginProxy);
00341     return d->providerName;
00342 }
00343 
00344 void ProviderPluginProxy::setAdditionalParameters(const QStringList &parameters)
00345 {
00346     Q_D(ProviderPluginProxy);
00347     d->additionalParameters = parameters;
00348 }
00349 
00350 QStringList ProviderPluginProxy::additionalParameters() const
00351 {
00352     Q_D(const ProviderPluginProxy);
00353     return d->additionalParameters;
00354 }
00355 
00356 bool ProviderPluginProxy::killRunningPlugin()
00357 {
00358     Q_D(ProviderPluginProxy);
00359 
00360     if (d->process == 0)
00361         return false;
00362 
00363     d->process->disconnect();
00364     d->process->close();
00365     delete d->process;
00366     d->process = 0;
00367 
00368     return true;
00369 }
00370 
00371 QVariant ProviderPluginProxy::exitData()
00372 {
00373     Q_D(ProviderPluginProxy);
00374     return d->exitData;
00375 }
00376