2013-10-03 19:04:55 +04:00
|
|
|
/*
|
|
|
|
* Copyright (C) by Dominik Schmidt <dev@dominik-schmidt.de>
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "socketapi.h"
|
|
|
|
|
|
|
|
#include "mirall/mirallconfigfile.h"
|
|
|
|
#include "mirall/folderman.h"
|
|
|
|
#include "mirall/folder.h"
|
|
|
|
#include "mirall/utility.h"
|
|
|
|
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QUrl>
|
|
|
|
#include <QLocalSocket>
|
|
|
|
#include <QLocalServer>
|
|
|
|
#include <QMetaObject>
|
|
|
|
#include <QStringList>
|
|
|
|
#include <QFile>
|
|
|
|
#include <QDir>
|
|
|
|
#include <QApplication>
|
|
|
|
|
2013-10-23 16:48:44 +04:00
|
|
|
#include "mirall/utility.h"
|
|
|
|
|
2013-10-03 19:04:55 +04:00
|
|
|
namespace Mirall {
|
|
|
|
|
|
|
|
#define DEBUG qDebug() << "SocketApi: "
|
|
|
|
|
|
|
|
SocketApi::SocketApi(QObject* parent, const QUrl& localFile)
|
|
|
|
: QObject(parent)
|
|
|
|
, _localServer(0)
|
|
|
|
{
|
2013-10-23 16:48:44 +04:00
|
|
|
QString socketPath;
|
|
|
|
if (Utility::isWindows()) {
|
|
|
|
socketPath = QLatin1String("\\\\.\\pipe\\");
|
|
|
|
} else {
|
|
|
|
socketPath = localFile.toLocalFile();
|
|
|
|
|
|
|
|
}
|
2013-10-03 19:04:55 +04:00
|
|
|
DEBUG << "ctor: " << socketPath;
|
|
|
|
|
|
|
|
// setup socket
|
|
|
|
_localServer = new QLocalServer(this);
|
|
|
|
QLocalServer::removeServer(socketPath);
|
|
|
|
if(!_localServer->listen(socketPath))
|
|
|
|
DEBUG << "can't start server";
|
|
|
|
else
|
|
|
|
DEBUG << "server started";
|
|
|
|
connect(_localServer, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
|
|
|
|
|
|
|
|
// folder watcher
|
|
|
|
connect(FolderMan::instance(), SIGNAL(folderSyncStateChange(QString)), SLOT(onSyncStateChanged(QString)));
|
|
|
|
}
|
|
|
|
|
|
|
|
SocketApi::~SocketApi()
|
|
|
|
{
|
|
|
|
DEBUG << "dtor";
|
|
|
|
_localServer->close();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SocketApi::onNewConnection()
|
|
|
|
{
|
|
|
|
QLocalSocket* socket = _localServer->nextPendingConnection();
|
|
|
|
DEBUG << "New connection " << socket;
|
|
|
|
connect(socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
|
|
|
|
connect(socket, SIGNAL(disconnected()), this, SLOT(onLostConnection()));
|
|
|
|
Q_ASSERT(socket->readAll().isEmpty());
|
|
|
|
|
|
|
|
_listeners.append(socket);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SocketApi::onLostConnection()
|
|
|
|
{
|
|
|
|
DEBUG << "Lost connection " << sender();
|
|
|
|
|
|
|
|
QLocalSocket* socket = qobject_cast< QLocalSocket* >(sender());
|
|
|
|
_listeners.removeAll(socket);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SocketApi::onReadyRead()
|
|
|
|
{
|
|
|
|
QLocalSocket* socket = qobject_cast<QLocalSocket*>(sender());
|
|
|
|
Q_ASSERT(socket);
|
|
|
|
|
|
|
|
while(socket->canReadLine())
|
|
|
|
{
|
|
|
|
QString line = QString::fromUtf8(socket->readLine()).trimmed();
|
|
|
|
QString command = line.split(":").first();
|
|
|
|
QString function = QString(QLatin1String("command_")).append(command);
|
|
|
|
|
|
|
|
QString functionWithArguments = function + QLatin1String("(QString,QLocalSocket*)");
|
|
|
|
int indexOfMethod = this->metaObject()->indexOfMethod(functionWithArguments.toAscii());
|
|
|
|
|
|
|
|
QString argument = line.remove(0, command.length()+1).trimmed();
|
|
|
|
if(indexOfMethod != -1)
|
|
|
|
{
|
|
|
|
QMetaObject::invokeMethod(this, function.toAscii(), Q_ARG(QString, argument), Q_ARG(QLocalSocket*, socket));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DEBUG << "The command is not supported by this version of the client:" << command << "with argument:" << argument;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SocketApi::onSyncStateChanged(const QString&)
|
|
|
|
{
|
|
|
|
DEBUG << "Sync state changed";
|
|
|
|
|
|
|
|
broadcastMessage("UPDATE_VIEW");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SocketApi::sendMessage(QLocalSocket* socket, const QString& message)
|
|
|
|
{
|
|
|
|
DEBUG << "Sending message: " << message;
|
|
|
|
QString localMessage = message;
|
|
|
|
socket->write(localMessage.append("\n").toUtf8());
|
|
|
|
}
|
|
|
|
|
|
|
|
void SocketApi::broadcastMessage(const QString& message)
|
|
|
|
{
|
|
|
|
DEBUG << "Broadcasting to" << _listeners.count() << "listeners: " << message;
|
|
|
|
foreach(QLocalSocket* current, _listeners)
|
|
|
|
{
|
|
|
|
sendMessage(current, message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SocketApi::command_RETRIEVE_FOLDER_STATUS(const QString& argument, QLocalSocket* socket)
|
|
|
|
{
|
|
|
|
qDebug() << Q_FUNC_INFO << argument;
|
|
|
|
//TODO: do security checks?!
|
|
|
|
Folder* folder = FolderMan::instance()->folderForPath( argument );
|
|
|
|
// this can happen in offline mode e.g.: nothing to worry about
|
|
|
|
if(!folder)
|
|
|
|
{
|
|
|
|
DEBUG << "folder offline or not watched:" << argument;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QDir dir(argument);
|
|
|
|
foreach(QString entry, dir.entryList(QDir::AllEntries|QDir::NoDotAndDotDot))
|
|
|
|
{
|
|
|
|
QString absoluteFilePath = dir.absoluteFilePath(entry);
|
|
|
|
QString statusString;
|
|
|
|
SyncFileStatus fileStatus = folder->fileStatus(absoluteFilePath.mid(folder->path().length()));
|
|
|
|
switch(fileStatus)
|
|
|
|
{
|
2013-10-03 19:55:32 +04:00
|
|
|
case FILE_STATUS_NONE:
|
2013-10-03 19:04:55 +04:00
|
|
|
statusString = QLatin1String("STATUS_NONE");
|
|
|
|
break;
|
2013-10-03 19:55:32 +04:00
|
|
|
case FILE_STATUS_EVAL:
|
2013-10-03 19:04:55 +04:00
|
|
|
statusString = QLatin1String("STATUS_EVAL");
|
|
|
|
break;
|
2013-10-03 19:55:32 +04:00
|
|
|
case FILE_STATUS_REMOVE:
|
2013-10-03 19:04:55 +04:00
|
|
|
statusString = QLatin1String("STATUS_REMOVE");
|
|
|
|
break;
|
2013-10-03 19:55:32 +04:00
|
|
|
case FILE_STATUS_RENAME:
|
2013-10-03 19:04:55 +04:00
|
|
|
statusString = QLatin1String("STATUS_RENAME");
|
|
|
|
break;
|
2013-10-03 19:55:32 +04:00
|
|
|
case FILE_STATUS_NEW:
|
2013-10-03 19:04:55 +04:00
|
|
|
statusString = QLatin1String("STATUS_NEW");
|
|
|
|
break;
|
2013-10-03 19:55:32 +04:00
|
|
|
case FILE_STATUS_CONFLICT:
|
2013-10-03 19:04:55 +04:00
|
|
|
statusString = QLatin1String("STATUS_CONFLICT");
|
|
|
|
break;
|
2013-10-03 19:55:32 +04:00
|
|
|
case FILE_STATUS_IGNORE:
|
2013-10-03 19:04:55 +04:00
|
|
|
statusString = QLatin1String("STATUS_IGNORE");
|
|
|
|
break;
|
2013-10-03 19:55:32 +04:00
|
|
|
case FILE_STATUS_SYNC:
|
2013-10-03 19:04:55 +04:00
|
|
|
statusString = QLatin1String("STATUS_SYNC");
|
|
|
|
break;
|
2013-10-03 19:55:32 +04:00
|
|
|
case FILE_STATUS_STAT_ERROR:
|
2013-10-03 19:04:55 +04:00
|
|
|
statusString = QLatin1String("STATUS_STAT_ERROR");
|
|
|
|
break;
|
2013-10-03 19:55:32 +04:00
|
|
|
case FILE_STATUS_ERROR:
|
2013-10-03 19:04:55 +04:00
|
|
|
statusString = QLatin1String("STATUS_ERROR");
|
|
|
|
break;
|
2013-10-03 19:55:32 +04:00
|
|
|
case FILE_STATUS_UPDATED:
|
2013-10-03 19:04:55 +04:00
|
|
|
statusString = QLatin1String("STATUS_UPDATED");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
qWarning() << "not all SyncFileStatus items checked!";
|
|
|
|
Q_ASSERT(false);
|
|
|
|
statusString = QLatin1String("STATUS_NONE");
|
|
|
|
|
|
|
|
}
|
|
|
|
QString message("%1:%2:%3");
|
|
|
|
message = message.arg("STATUS").arg(statusString).arg(absoluteFilePath);
|
|
|
|
sendMessage(socket, message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Mirall
|