1
/***************************************************************************
2
* Copyright (C) 2010 Alejandro Fiestas Olivares <alex@eyeos.org> *
3
* Copyright (C) 2010 UFO Coders <info@ufocoders.com> *
5
* This program is free software; you can redistribute it and/or modify *
6
* it under the terms of the GNU General Public License as published by *
7
* the Free Software Foundation; either version 2 of the License, or *
8
* (at your option) any later version. *
10
* This program is distributed in the hope that it will be useful, *
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13
* GNU General Public License for more details. *
15
* You should have received a copy of the GNU General Public License *
16
* along with this program; if not, write to the *
17
* Free Software Foundation, Inc., *
18
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
19
***************************************************************************/
21
#include "ObexFtpDaemon.h"
22
#include "obexftpmanager.h"
23
#include "obexsession.h"
25
#include <QVariantMap>
28
#include <kdemacros.h>
31
#include <KPluginFactory>
32
#include <kfileplacesmodel.h>
35
#include <bluedevil/bluedevilmanager.h>
36
#include <bluedevil/bluedeviladapter.h>
38
#define ENSURE_SESSION_CREATED(address) if (!d->m_sessionMap.contains(address)) { \
39
kDebug() << "The address " << address << " doesn't has a session"; \
40
stablishConnection(address); \
43
if (d->m_sessionMap[address]->status() == ObexSession::Connecting) { \
44
kDebug() << "The session is waiting to be connected"; \
48
using namespace BlueDevil;
49
K_PLUGIN_FACTORY(ObexFtpFactory,
50
registerPlugin<ObexFtpDaemon>();)
51
K_EXPORT_PLUGIN(ObexFtpFactory("obexftpdaemon", "obexftpdaemon"))
53
struct ObexFtpDaemon::Private
60
QHash <QString, ObexSession*> m_sessionMap;
62
org::openobex::Manager *m_manager;
67
ObexFtpDaemon::ObexFtpDaemon(QObject *parent, const QList<QVariant>&)
74
ki18n("ObexFtp Daemon"),
76
ki18n("ObexFtp Daemon"),
77
KAboutData::License_GPL,
78
ki18n("(c) 2010, UFO Coders")
81
aboutData.addAuthor(ki18n("Alejandro Fiestas Olivares"), ki18n("Maintainer"), "alex@ufocoders.com",
82
"http://www.afiestas.org");
84
connect(Manager::self(), SIGNAL(defaultAdapterChanged(Adapter*)),
85
this, SLOT(defaultAdapterChanged(Adapter*)));
87
d->m_status = Private::Offline;
88
if (Manager::self()->defaultAdapter()) {
92
qDBusRegisterMetaType<QStringMap>();
93
qRegisterMetaType<QStringMap>("QStringMap");
95
connect(d->m_manager, SIGNAL(SessionConnected(QDBusObjectPath)), this, SLOT(SessionConnected(QDBusObjectPath)));
96
connect(d->m_manager, SIGNAL(SessionClosed(QDBusObjectPath)), this, SLOT(SessionClosed(QDBusObjectPath)));
99
ObexFtpDaemon::~ObexFtpDaemon()
101
if (d->m_status == Private::Online) {
107
void ObexFtpDaemon::onlineMode()
110
if (d->m_status == Private::Online) {
111
kDebug() << "Already in onlineMode";
115
d->m_manager = new org::openobex::Manager("org.openobex", "/org/openobex", QDBusConnection::sessionBus(), 0);
117
d->m_status = Private::Online;
120
void ObexFtpDaemon::offlineMode()
122
kDebug() << "Offline mode";
123
if (d->m_status == Private::Offline) {
124
kDebug() << "Already in offlineMode";
128
QHash<QString, ObexSession*>::const_iterator i = d->m_sessionMap.constBegin();
129
while (i != d->m_sessionMap.constEnd()) {
130
if (d->m_sessionMap[i.key()]) {
131
d->m_sessionMap[i.key()]->Disconnect().waitForFinished();
132
d->m_sessionMap[i.key()]->Close().waitForFinished();
133
delete d->m_sessionMap[i.key()];
135
d->m_sessionMap.remove(i.key());
138
d->m_status = Private::Offline;
141
void ObexFtpDaemon::defaultAdapterChanged(Adapter *adapter)
150
void ObexFtpDaemon::stablishConnection(QString dirtyAddress)
152
QString address = cleanAddress(dirtyAddress);
154
kDebug() << "Address: " << address;
155
if (d->m_status == Private::Offline) {
156
kDebug() << "We're offline, so do nothing";
160
if (address.isEmpty()) {
161
kDebug() << "Address is Empty";
164
//We already have a session for that address
165
if (d->m_sessionMap.contains(address)) {
166
//But this session is waiting for being connected
167
if (d->m_sessionMap[address]->status() == ObexSession::Connecting) {
168
kDebug() << "Session for this address is waiting for being connected";
172
kDebug() << "We already have a session, so do nothing";
173
emit sessionConnected(address);
177
kDebug() << "Telling to the manager to create the session";
179
QDBusPendingReply <QDBusObjectPath > rep = d->m_manager->CreateBluetoothSession(address, "00:00:00:00:00:00", "ftp");
181
d->m_sessionMap[address] = new ObexSession("org.openobex", rep.value().path(), QDBusConnection::sessionBus(), 0);
182
kDebug() << "Path: " << rep.value().path();
185
void ObexFtpDaemon::changeCurrentFolder(QString address, QString path)
188
d->m_sessionMap[address]->resetTimer();
189
d->m_sessionMap[address]->ChangeCurrentFolderToRoot().waitForFinished();
191
QStringList list = path.split("/");
192
Q_FOREACH(const QString &dir, list) {
193
if (!dir.isEmpty() && dir != address) {
194
kDebug() << "Changing to: " << dir;
195
QDBusPendingReply <void > a = d->m_sessionMap[address]->ChangeCurrentFolder(dir);
197
kDebug() << "Change Error: " << a.error().message();
199
kDebug() << "Skyping" << dir;
204
QString ObexFtpDaemon::listDir(QString dirtyAddress, QString path)
207
QString address = cleanAddress(dirtyAddress);
208
if (!d->m_sessionMap.contains(address)) {
209
kDebug() << "The address " << address << " doesn't has a session";
210
stablishConnection(address);
213
if (d->m_sessionMap[address]->status() == ObexSession::Connecting) {
214
kDebug() << "The session is waiting to be connected";
218
address.replace("-", ":");
219
changeCurrentFolder(address, path);
221
d->m_sessionMap[address]->resetTimer();
222
QString ret = d->m_sessionMap[address]->RetrieveFolderListing().value();
229
void ObexFtpDaemon::copyRemoteFile(QString dirtyAddress, QString fileName, QString destPath)
231
kDebug() << destPath;
232
QString address = cleanAddress(dirtyAddress);
233
ENSURE_SESSION_CREATED(address);
235
KUrl url = KUrl(fileName);
236
changeCurrentFolder(address, url.directory());
237
kDebug() << d->m_sessionMap[address]->GetCurrentPath().value();
238
kDebug() << url.fileName();
239
d->m_sessionMap[address]->resetTimer();
240
d->m_sessionMap[address]->CopyRemoteFile(url.fileName(), destPath);
243
void ObexFtpDaemon::sendFile(QString dirtyAddress, QString localPath, QString destPath)
245
QString address = cleanAddress(dirtyAddress);
248
ENSURE_SESSION_CREATED(address);
249
changeCurrentFolder(address, destPath);
251
d->m_sessionMap[address]->resetTimer();
252
d->m_sessionMap[address]->SendFile(localPath);
255
void ObexFtpDaemon::createFolder(QString dirtyAddress, QString path)
258
QString address = cleanAddress(dirtyAddress);
259
ENSURE_SESSION_CREATED(address);
262
changeCurrentFolder(address, url.directory());
264
d->m_sessionMap[address]->resetTimer();
265
d->m_sessionMap[address]->CreateFolder(url.fileName()).waitForFinished();
268
void ObexFtpDaemon::deleteRemoteFile(QString dirtyAddress, QString path)
271
QString address = cleanAddress(dirtyAddress);
272
ENSURE_SESSION_CREATED(address);
275
changeCurrentFolder(address, url.directory());
277
d->m_sessionMap[address]->resetTimer();
278
d->m_sessionMap[address]->DeleteRemoteFile(url.fileName()).waitForFinished();;
281
bool ObexFtpDaemon::isBusy(QString dirtyAddress)
284
QString address = cleanAddress(dirtyAddress);
285
if (!d->m_sessionMap.contains(address)) {
286
kDebug() << "The address " << address << " doesn't has a session";
287
stablishConnection(address);
288
return true;//Fake the busy state, so stablishConneciton can work
290
if (d->m_sessionMap[address]->status() == ObexSession::Connecting) {
291
kDebug() << "The session is waiting to be connected";
295
d->m_sessionMap[address]->resetTimer();
296
return d->m_sessionMap[address]->IsBusy().value();
299
void ObexFtpDaemon::Cancel(QString dirtyAddress)
301
QString address = cleanAddress(dirtyAddress);
302
ENSURE_SESSION_CREATED(address)
304
d->m_sessionMap[address]->resetTimer();
305
d->m_sessionMap[address]->Cancel();
309
void ObexFtpDaemon::SessionConnected(QDBusObjectPath path)
311
kDebug() << "SessionConnected!" << path.path();
313
QString address = getAddressFromSession(path.path());
315
d->m_sessionMap[address]->setStatus(ObexSession::Connected);
317
connect(d->m_sessionMap[address], SIGNAL(sessionTimeout()), this, SLOT(sessionDisconnected()));
318
connect(d->m_sessionMap[address], SIGNAL(Closed()), this, SLOT(sessionDisconnected()));
319
connect(d->m_sessionMap[address], SIGNAL(Disconnected()), this, SLOT(sessionDisconnected()));
320
connect(d->m_sessionMap[address], SIGNAL(Cancelled()), this, SIGNAL(Cancelled()));
321
connect(d->m_sessionMap[address], SIGNAL(TransferCompleted()), this, SIGNAL(transferCompleted()));
322
connect(d->m_sessionMap[address], SIGNAL(TransferProgress(qulonglong)), this, SIGNAL(transferProgress(qulonglong)));
323
connect(d->m_sessionMap[address], SIGNAL(ErrorOccurred(QString,QString)), this, SIGNAL(errorOccurred(QString,QString)));
325
emit sessionConnected(address);
328
void ObexFtpDaemon::SessionClosed(QDBusObjectPath path)
331
QHash<QString, ObexSession*>::const_iterator i = d->m_sessionMap.constBegin();
332
while (i != d->m_sessionMap.constEnd()) {
333
//If the session is connected, so not 0
334
if (i.value()->path() == path.path()) {
335
kDebug() << "Removing : " << i.key();
336
d->m_sessionMap.remove(i.key());
343
kDebug() << "Attempt to remove a nto existing session";
346
void ObexFtpDaemon::sessionDisconnected()
348
kDebug() << "Session disconnected";
349
ObexSession* session = static_cast <ObexSession*>(sender());
350
kDebug() << session->path();
351
kDebug() << session->status();
353
d->m_sessionMap.remove(d->m_sessionMap.key(session));
357
QString ObexFtpDaemon::getAddressFromSession(QString path)
360
QStringMap info = d->m_manager->GetSessionInfo(QDBusObjectPath(path)).value();
361
return info["BluetoothTargetAddress"];
364
QString ObexFtpDaemon::cleanAddress(QString& dirtyAddress) const
366
dirtyAddress.replace("-", ":");
367
return dirtyAddress.toLower();