libAccountSetup 1.0
provider-plugin-proxy.cpp
1#include <unistd.h>
2/*
3 * This file is part of accounts-ui
4 *
5 * Copyright (C) 2011 Nokia Corporation.
6 *
7 * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * version 2.1 as published by the Free Software Foundation.
12 *
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 */
23
24#include "provider-plugin-proxy.h"
25#include "provider-plugin-proxy-priv.h"
26
27#include <Accounts/Manager>
28
29#include <QDebug>
30#include <QLocalServer>
31#include <QLocalSocket>
32
33using namespace Accounts;
34using namespace AccountSetup;
35
36
37ProviderPluginProxyPrivate::~ProviderPluginProxyPrivate()
38{
39 qDebug() << Q_FUNC_INFO;
40 if (process) {
41 process->disconnect();
42 process->close();
43 delete process;
44 }
45}
46
47void ProviderPluginProxyPrivate::startProcess(Provider provider,
48 AccountId accountId,
49 const QString &serviceType)
50{
52
53 error = ProviderPluginProxy::NoError;
54 createdAccountId = 0;
55 pluginOutput.clear();
56
57 QString processName;
58 QString pluginFileName;
59
60 if (!findPlugin(provider, processName, pluginFileName)) {
61 error = ProviderPluginProxy::PluginNotFound;
62 emit q->finished();
63 return;
64 }
65 providerName = provider.name();
66 pid_t pid = getpid();
67 socketName = provider.name() + QString::number(pid);
68
69 QStringList arguments;
70 arguments << QLatin1String("--socketName") << socketName;
71
72 if (parentWidget != 0) {
73 WId windowId = parentWidget->effectiveWinId();
74 arguments << QLatin1String("--windowId") << QString::number(windowId);
75 }
76
77 if (accountId != 0) {
78 arguments << QLatin1String("--edit") << QString::number(accountId);
79 setupType = EditExisting;
80 } else {
81 arguments << QLatin1String("--create") << provider.name();
82 setupType = CreateNew;
83 }
84
85 if (!serviceType.isEmpty())
86 arguments << QLatin1String("--serviceType") << serviceType;
87
88 arguments += additionalParameters;
89
90#ifndef QT_NO_DEBUG_OUTPUT
91 arguments << QLatin1String("-output-level") << QLatin1String("debug");
92#endif
93
94 if (!process)
95 process = new QProcess();
96
97 pluginName = pluginFileName;
98
99 qDebug() << Q_FUNC_INFO << processName << arguments;
100
101 connect(process, SIGNAL(readyReadStandardError()),
102 this, SLOT(onReadStandardError()));
103 connect(process, SIGNAL(error(QProcess::ProcessError)),
104 this, SLOT(onError(QProcess::ProcessError)));
105 connect(process, SIGNAL(finished(int, QProcess::ExitStatus)),
106 this, SLOT(onFinished(int, QProcess::ExitStatus)));
107 connect(process, SIGNAL(started()), this, SLOT(setCommunicationChannel()));
108
109 process->start(processName, arguments);
110}
111
112bool ProviderPluginProxyPrivate::findPlugin(Provider provider,
113 QString &pluginPath,
114 QString &pluginFileName)
115{
116 static const char pluginNamePattern[] = "%1plugin";
117 bool pluginTagExists = true;
118
119 QDomElement root(provider.domDocument().documentElement());
120 QString pluginName(root.
121 firstChildElement(QString::fromLatin1("plugin")).
122 text());
123 if (pluginName.isEmpty()) {
124 pluginName = provider.name();
125 pluginTagExists = false;
126 }
127
128 QStringList pluginFileNames;
129 pluginFileNames << QString::fromLatin1(pluginNamePattern).arg(pluginName);
130
131 /* If a plugin for the specified name cannot be found and
132 * the plugin is not specified in the provider file, fallback to
133 * "genericplugin"
134 */
135 if (!pluginTagExists) {
136 pluginFileNames << QString::fromLatin1(pluginNamePattern).
137 arg(QLatin1String("generic"));
138 }
139
140 foreach (QString name, pluginFileNames) {
141 foreach (QString pluginDir, pluginDirs) {
142 QFileInfo pluginFileInfo(pluginDir, name);
143
144 if (pluginFileInfo.exists()) {
145 pluginPath = pluginFileInfo.canonicalFilePath();
146 pluginFileName = name;
147 return true;
148 }
149 }
150 }
151
152 return false;
153}
154
155void ProviderPluginProxyPrivate::setCommunicationChannel()
156{
157 QLocalServer *server = new QLocalServer();
158 QLocalServer::removeServer(socketName);
159 if (!server->listen(socketName))
160 qWarning() << "Server not up";
161 else
162 connect(server, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
163}
164
165void ProviderPluginProxyPrivate::onNewConnection()
166{
167 QLocalServer *server = qobject_cast<QLocalServer*>(sender());
168 QLocalSocket *socket = server->nextPendingConnection();
169 if (!socket->waitForConnected()) {
170 qWarning() << "Server Connection not established";
171 return;
172 }
173 if (!socket->waitForReadyRead()) {
174 qWarning() << "Server data not available for reading";
175 return;
176 }
177 pluginOutput = socket->readAll();
178 socket->close();
179}
180
181
182void ProviderPluginProxyPrivate::onReadStandardError()
183{
184 qDebug() << QString::fromLatin1(process->readAllStandardError());
185}
186
187void ProviderPluginProxyPrivate::onError(QProcess::ProcessError err)
188{
190
191 if (err == QProcess::FailedToStart) {
192 pluginName.clear();
193 error = ProviderPluginProxy::PluginCrashed;
194
195 emit q->finished();
196 if (process) {
197 process->deleteLater();
198 process = NULL;
199 }
200 }
201
202 qDebug() << "Error: " << err;
203}
204
205void ProviderPluginProxyPrivate::onFinished(int exitCode,
206 QProcess::ExitStatus exitStatus)
207{
209 Q_UNUSED(exitCode);
210
211 pluginName.clear();
212
213 if (exitStatus == QProcess::CrashExit) {
214 error = ProviderPluginProxy::PluginCrashed;
215 emit q->finished();
216 process->deleteLater();
217 process = NULL;
218 return;
219 }
220
221 QString value;
222 if (!pluginOutput.isEmpty()) {
223 QDataStream stream(pluginOutput);
224 stream.device()->seek(0);
225 stream >> createdAccountId >> exitData;
226 }
227
228 if (process) {
229 process->deleteLater();
230 process = NULL;
231 }
232
233 emit q->finished();
234}
235
237 QObject(parent),
238 d_ptr(new ProviderPluginProxyPrivate(this))
239{
240}
241
242ProviderPluginProxy::~ProviderPluginProxy()
243{
245 delete d;
246}
247
248void ProviderPluginProxy::createAccount(Accounts::Provider provider,
249 const QString &serviceType)
250{
252
253 if (!provider.isValid()) {
254 qCritical() << " NULL pointer to provider";
255 d->error = ProviderPluginProxy::PluginNotFound;
256 emit finished();
257 return;
258 }
259
260 d->startProcess(provider, 0, serviceType);
261}
262
263void ProviderPluginProxy::editAccount(Accounts::Account *account,
264 const QString &serviceType)
265{
267
268 if (!account) {
269 qCritical() << " NULL pointer to account";
270 d->error = ProviderPluginProxy::AccountNotFound;
271 emit finished();
272 return;
273 }
274
275 Manager *manager = account->manager();
276 Provider provider = manager->provider(account->providerName());
277 d->startProcess(provider, account->id(), serviceType);
278}
279
281{
283 d->parentWidget = parent;
284}
285
286void ProviderPluginProxy::setPluginDirectories(const QStringList &pluginDirs)
287{
289 d->pluginDirs = pluginDirs;
290}
291
293{
294 Q_D(const ProviderPluginProxy);
295 return d->pluginDirs;
296}
297
299{
300 Q_D(const ProviderPluginProxy);
301 return d->createdAccountId != 0;
302}
303
305{
306 Q_D(const ProviderPluginProxy);
307 return d->error;
308}
309
310Accounts::AccountId ProviderPluginProxy::createdAccountId() const
311{
312 Q_D(const ProviderPluginProxy);
313 return d->createdAccountId;
314}
315
317{
319 return d->process != 0;
320}
321
323{
324 Q_D(const ProviderPluginProxy);
325 return d->setupType;
326}
327
329{
330 if (!isPluginRunning())
331 return QString();
332
334 return d->pluginName;
335}
336
338{
339 if (!isPluginRunning())
340 return QString();
342 return d->providerName;
343}
344
345void ProviderPluginProxy::setAdditionalParameters(const QStringList &parameters)
346{
348 d->additionalParameters = parameters;
349}
350
352{
353 Q_D(const ProviderPluginProxy);
354 return d->additionalParameters;
355}
356
358{
360
361 if (d->process == 0)
362 return false;
363
364 d->process->disconnect();
365 d->process->close();
366 delete d->process;
367 d->process = 0;
368
369 return true;
370}
371
373{
375 return d->exitData;
376}
377
Client class for accounts UI plugins.
void setPluginDirectories(const QStringList &pluginDirs)
Set the list of directories which will be searched for provider plugins.
QStringList pluginDirectories() const
Get the list of directories which will be searched for provider plugins.
void createAccount(Accounts::Provider provider, const QString &serviceType)
Runs the account plugin to create an account.
void setParentWidget(QWidget *parent)
Attempt to set the next executed account plugin modal to a given widget.
Error
Error codes for plugin execution.
ProviderPluginProxy(QObject *parent=0)
Constructor.
void finished()
Emitted when the plugin execution has been completed.
void editAccount(Accounts::Account *account, const QString &serviceType)
Runs the account plugin to edit an account.
SetupType setupType() const
Returns the operation being performed by the plugin.
void setAdditionalParameters(const QStringList &parameters)
Sets additional parameters to be passed to the plugin process on the next invocation of createAccount...
bool killRunningPlugin()
Kills the plugin being executed.
Error error() const
Gets the error code of the last plugin execution.
Accounts::AccountId createdAccountId() const
Gets the ID of the newly created account.
bool accountCreated() const
Checks whether an account was created by the plugin executed last.
bool isPluginRunning()
Checks whether a plugin is running.
QStringList additionalParameters() const
Gets the list of additional parameters passed to the plugin process.
SetupType
Operation type.
Definition types.h:38