[SCM] ktp-filetransfer-handler packaging branch, master, updated. debian/15.12.1-2-226-g825cd93

Maximiliano Curia maxy at moszumanska.debian.org
Sat May 28 00:11:12 UTC 2016


Gitweb-URL: http://git.debian.org/?p=pkg-kde/applications/ktp-filetransfer-handler.git;a=commitdiff;h=3c53d7c

The following commit has been merged in the master branch:
commit 3c53d7c7ed88d3402622df7f1117456a85b06176
Author: Daniele E. Domenichelli <daniele.domenichelli at gmail.com>
Date:   Mon Jun 6 14:11:18 2011 +0200

    First real commit
---
 .reviewboardrc                                     |   2 +
 CMakeLists.txt                                     |  21 ++
 cmake/modules/FindTelepathyQt4.cmake               |  40 ++++
 src/CMakeLists.txt                                 |  25 +++
 src/KDE.FileTransfer.client                        |   6 +
 src/filetransfer-handler.cpp                       | 155 +++++++++++++++
 src/filetransfer-handler.h                         |  57 ++++++
 src/handle-incoming-file-transfer-channel-job.cpp  | 196 +++++++++++++++++++
 src/handle-incoming-file-transfer-channel-job.h    |  57 ++++++
 src/handle-outgoing-file-transfer-channel-job.cpp  | 216 +++++++++++++++++++++
 src/handle-outgoing-file-transfer-channel-job.h    |  56 ++++++
 src/main.cpp                                       |  47 +++++
 ...op.Telepathy.Client.KDE.FileTransfer.service.in |   3 +
 src/telepathy-base-job.cpp                         | 116 +++++++++++
 src/telepathy-base-job.h                           |  87 +++++++++
 src/telepathy-base-job_p.h                         |  57 ++++++
 16 files changed, 1141 insertions(+)

diff --git a/.reviewboardrc b/.reviewboardrc
new file mode 100644
index 0000000..a8dcf36
--- /dev/null
+++ b/.reviewboardrc
@@ -0,0 +1,2 @@
+REVIEWBOARD_URL = 'https://git.reviewboard.kde.org'
+REPOSITORY = 'git://anongit.kde.org/telepathy-filetransfer-handler'
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..5d7e4ae
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,21 @@
+project (telepathy-kde-filetransfer-handler)
+
+set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ${CMAKE_MODULE_PATH})
+
+set(KDE_MIN_VERSION "4.6.0")
+find_package (KDE4 ${KDE_MIN_VERSION} REQUIRED)
+find_package (TelepathyQt4 REQUIRED)
+
+include (CheckIncludeFiles)
+include (KDE4Defaults)
+include (MacroLibrary)
+
+add_definitions (${KDE4_DEFINITIONS}
+                 -DQT_NO_CAST_FROM_ASCII
+)
+
+include_directories (${KDE4_INCLUDES}
+                     ${TELEPATHY_QT4_INCLUDE_DIR}
+)
+
+add_subdirectory(src)
diff --git a/cmake/modules/FindTelepathyQt4.cmake b/cmake/modules/FindTelepathyQt4.cmake
new file mode 100644
index 0000000..4bed08a
--- /dev/null
+++ b/cmake/modules/FindTelepathyQt4.cmake
@@ -0,0 +1,40 @@
+# Try to find the Qt binding of the Telepathy library
+# TELEPATHY_QT_FOUND - system has TelepathyQt4
+# TELEPATHY_QT_INCLUDE_DIR - the TelepathyQt4 include directory
+# TELEPATHY_QT_LIBRARIES - Link these to use TelepathyQt4
+
+# Copyright (c) 2008, Allen Winter <winter at kde.org>
+# Copyright (c) 2009, Andre Moreira Magalhaes <andrunko at gmail.com>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+set(TELEPATHY_QT4_FIND_REQUIRED ${TelepathyQt4_FIND_REQUIRED})
+if(TELEPATHY_QT4_INCLUDE_DIR AND TELEPATHY_QT4_LIBRARIES)
+  # Already in cache, be silent
+  set(TELEPATHY_QT4_FIND_QUIETLY TRUE)
+endif(TELEPATHY_QT4_INCLUDE_DIR AND TELEPATHY_QT4_LIBRARIES)
+
+find_package(PkgConfig)
+if(PKG_CONFIG_FOUND)
+    pkg_check_modules(PC_TELEPATHY_QT4 QUIET TelepathyQt4>=0.2.0)
+endif(PKG_CONFIG_FOUND)
+
+find_path(TELEPATHY_QT4_INCLUDE_DIR
+          NAMES TelepathyQt4/Types
+          HINTS
+          ${PC_TELEPATHY_QT4_INCLUDEDIR}
+          ${PC_TELEPATHY_QT4_INCLUDE_DIRS}
+          ${PC_TELEPATHY_QT4_INCLUDES}
+)
+
+find_library(TELEPATHY_QT4_LIBRARIES
+             NAMES telepathy-qt4
+             HINTS
+             ${PC_TELEPATHY_QT4_LIBDIR}
+             ${PC_TELEPATHY_QT4_LIBRARY_DIRS}
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(TELEPATHY_QT4 DEFAULT_MSG
+                                  TELEPATHY_QT4_LIBRARIES TELEPATHY_QT4_INCLUDE_DIR)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..9e84a8b
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,25 @@
+set (telepathy_kde_filetransfer_handler_SRCS
+     main.cpp
+     filetransfer-handler.cpp
+     telepathy-base-job.cpp
+     handle-incoming-file-transfer-channel-job.cpp
+     handle-outgoing-file-transfer-channel-job.cpp
+)
+
+kde4_add_executable(telepathy-kde-filetransfer-handler ${telepathy_kde_filetransfer_handler_SRCS})
+
+target_link_libraries(telepathy-kde-filetransfer-handler
+            ${KDE4_KDECORE_LIBS}
+            ${KDE4_KDEUI_LIBS}
+            ${KDE4_KIO_LIBS}
+            ${TELEPATHY_QT4_LIBRARIES}
+)
+
+configure_file(org.freedesktop.Telepathy.Client.KDE.FileTransfer.service.in
+               ${CMAKE_CURRENT_BINARY_DIR}/org.freedesktop.Telepathy.Client.KDE.FileTransfer.service)
+
+install(TARGETS telepathy-kde-filetransfer-handler ${INSTALL_TARGETS_DEFAULT_ARGS})
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.freedesktop.Telepathy.Client.KDE.FileTransfer.service
+        DESTINATION ${DBUS_SERVICES_INSTALL_DIR})
+install(FILES KDE.FileTransfer.client DESTINATION ${SHARE_INSTALL_PREFIX}/telepathy/clients/)
+
diff --git a/src/KDE.FileTransfer.client b/src/KDE.FileTransfer.client
new file mode 100644
index 0000000..6c8ef8f
--- /dev/null
+++ b/src/KDE.FileTransfer.client
@@ -0,0 +1,6 @@
+[org.freedesktop.Telepathy.Client]
+Interfaces=org.freedesktop.Telepathy.Client.Handler;
+
+[org.freedesktop.Telepathy.Client.Handler.HandlerChannelFilter 0]
+org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.FileTransfer
+org.freedesktop.Telepathy.Channel.TargetHandleType u=1
diff --git a/src/filetransfer-handler.cpp b/src/filetransfer-handler.cpp
new file mode 100644
index 0000000..029e117
--- /dev/null
+++ b/src/filetransfer-handler.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2010, 2011 Daniele E. Domenichelli <daniele.domenichelli at gmail.com>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "filetransfer-handler.h"
+#include "handle-incoming-file-transfer-channel-job.h"
+#include "handle-outgoing-file-transfer-channel-job.h"
+
+#include <TelepathyQt4/ClientRegistrar>
+#include <TelepathyQt4/ChannelFactory>
+#include <TelepathyQt4/ChannelClassSpecList>
+#include <TelepathyQt4/ChannelClassSpec>
+#include <TelepathyQt4/Channel>
+#include <TelepathyQt4/FileTransferChannel>
+#include <TelepathyQt4/IncomingFileTransferChannel>
+#include <TelepathyQt4/OutgoingFileTransferChannel>
+#include <TelepathyQt4/PendingOperation>
+#include <TelepathyQt4/Constants>
+
+#include <KSharedConfig>
+#include <KConfigGroup>
+#include <KDebug>
+#include <KLocalizedString>
+#include <KJob>
+#include <KNotification>
+#include <kio/global.h>
+#include <kjobtrackerinterface.h>
+
+
+FileTransferHandler::FileTransferHandler(QObject *parent) : QObject(parent),
+    Tp::AbstractClientHandler(Tp::ChannelClassSpecList() << Tp::ChannelClassSpec::incomingFileTransfer()
+                                                         << Tp::ChannelClassSpec::outgoingFileTransfer())
+{
+    Tp::AccountFactoryPtr accountFactory = Tp::AccountFactory::create(QDBusConnection::sessionBus());
+
+    Tp::ConnectionFactoryPtr  connectionFactory = Tp::ConnectionFactory::create(QDBusConnection::sessionBus());
+
+    Tp::ChannelFactoryPtr channelFactory = Tp::ChannelFactory::create(QDBusConnection::sessionBus());
+    channelFactory->addCommonFeatures(Tp::Channel::FeatureCore);
+    channelFactory->addFeaturesForIncomingFileTransfers(Tp::FileTransferChannel::FeatureCore);
+    channelFactory->addFeaturesForOutgoingFileTransfers(Tp::FileTransferChannel::FeatureCore);
+
+    Tp::ContactFactoryPtr contactFactory = Tp::ContactFactory::create();
+
+
+    registrar = Tp::ClientRegistrar::create(accountFactory,
+                                            connectionFactory,
+                                            channelFactory,
+                                            contactFactory);
+    registrar->registerClient(Tp::AbstractClientPtr(Tp::SharedPtr<FileTransferHandler>(this)),
+                              QLatin1String("KDE.FileTransfer"));
+}
+
+
+FileTransferHandler::~FileTransferHandler()
+{
+}
+
+bool FileTransferHandler::bypassApproval() const
+{
+    return false;
+}
+
+void FileTransferHandler::handleChannels(const Tp::MethodInvocationContextPtr<> &context,
+                                         const Tp::AccountPtr &account,
+                                         const Tp::ConnectionPtr &connection,
+                                         const QList<Tp::ChannelPtr> &channels,
+                                         const QList<Tp::ChannelRequestPtr> &requestsSatisfied,
+                                         const QDateTime &userActionTime,
+                                         const Tp::AbstractClientHandler::HandlerInfo &handlerInfo)
+{
+    Q_UNUSED(account);
+    Q_UNUSED(connection);
+    Q_UNUSED(requestsSatisfied);
+    Q_UNUSED(userActionTime);
+    Q_UNUSED(handlerInfo);
+
+    foreach(const Tp::ChannelPtr &channel, channels) {
+        kDebug() << "Handling new file transfer";
+
+        QVariantMap properties = channel->immutableProperties();
+        kDebug() << properties;
+
+        KJob* job = NULL;
+        if (Tp::IncomingFileTransferChannelPtr incomingFileTransferChannel = Tp::IncomingFileTransferChannelPtr::dynamicCast(channel)) {
+            context->setFinished();
+
+            kDebug() << "Incoming File Transfer";
+
+            KSharedConfigPtr config = KSharedConfig::openConfig(QLatin1String("ktelepathyrc"));
+            KConfigGroup filetransferConfig = config->group(QLatin1String("File Transfers"));
+
+            QString downloadDirectory = filetransferConfig.readPathEntry(QLatin1String("downloadDirectory"),
+                    QDir::homePath() + QLatin1String("/") + i18nc("This is the download directory in user's home", "Downloads"));
+            kDebug() << "Download directory:" << downloadDirectory;
+            // TODO Check if directory exists
+
+            job = new HandleIncomingFileTransferChannelJob(incomingFileTransferChannel, downloadDirectory, this);
+        } else if (Tp::OutgoingFileTransferChannelPtr outgoingFileTransferChannel = Tp::OutgoingFileTransferChannelPtr::dynamicCast(channel)) {
+            if (outgoingFileTransferChannel->uri().isEmpty())
+            {
+                context->setFinishedWithError(QLatin1String(TELEPATHY_QT4_ERROR_INCONSISTENT),
+                                              QLatin1String("Cannot handle outgoing file transfer without URI"));
+            }
+            context->setFinished();
+            job = new HandleOutgoingFileTransferChannelJob(outgoingFileTransferChannel, this);
+        } else {
+            context->setFinishedWithError(QLatin1String(TELEPATHY_QT4_ERROR_INCONSISTENT),
+                                          QLatin1String("Unknown channel type"));
+            kDebug() << "If you are reading this, then telepathy is broken";
+        }
+
+        if (job)
+        {
+            KIO::getJobTracker()->registerJob(job);
+            connect(job,
+                    SIGNAL(infoMessage(KJob*, QString, QString)),
+                    SLOT(onInfoMessage(KJob*, QString, QString)));
+            connect(job,
+                    SIGNAL(result(KJob*)),
+                    SLOT  (handleResult(KJob*)));
+            job->start();
+        }
+    }
+}
+
+void FileTransferHandler::onInfoMessage(KJob* job, const QString &plain, const QString &rich)
+{
+    Q_UNUSED(job);
+    Q_UNUSED(rich);
+    kDebug() << plain;
+
+//    KNotification::event("newOfferFileTransferEvent", plain, rich);
+}
+
+void FileTransferHandler::handleResult(KJob* job)
+{
+    if ( job->error() ) {
+        kWarning() << job->errorString();
+        // TODO do something;
+    }
+}
\ No newline at end of file
diff --git a/src/filetransfer-handler.h b/src/filetransfer-handler.h
new file mode 100644
index 0000000..394a0af
--- /dev/null
+++ b/src/filetransfer-handler.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2010, 2011 Daniele E. Domenichelli <daniele.domenichelli at gmail.com>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TELEPATHY_KDE_FILETRANSFER_HANDLER_H
+#define TELEPATHY_KDE_FILETRANSFER_HANDLER_H
+
+#include <TelepathyQt4/AbstractClientHandler>
+#include <TelepathyQt4/Types>
+
+class KJob;
+namespace Tp
+{
+    class PendingOperation;
+}
+
+class FileTransferHandler : public QObject, public Tp::AbstractClientHandler
+{
+    Q_OBJECT
+    Q_DISABLE_COPY(FileTransferHandler);
+
+public:
+    FileTransferHandler(QObject* parent = 0);
+    virtual ~FileTransferHandler();
+
+    virtual bool bypassApproval() const;
+    void handleChannels(const Tp::MethodInvocationContextPtr<> &context,
+                        const Tp::AccountPtr &account,
+                        const Tp::ConnectionPtr &connection,
+                        const QList<Tp::ChannelPtr> &channels,
+                        const QList<Tp::ChannelRequestPtr> &requestsSatisfied,
+                        const QDateTime &userActionTime,
+                        const Tp::AbstractClientHandler::HandlerInfo &handlerInfo);
+
+private Q_SLOTS:
+    void onInfoMessage(KJob* job, const QString &plain, const QString &rich);
+    void handleResult(KJob* job);
+
+
+private:
+    Tp::ClientRegistrarPtr registrar;
+};
+
+#endif // TELEPATHY_KDE_FILETRANSFER_HANDLER_H
diff --git a/src/handle-incoming-file-transfer-channel-job.cpp b/src/handle-incoming-file-transfer-channel-job.cpp
new file mode 100644
index 0000000..30181cc
--- /dev/null
+++ b/src/handle-incoming-file-transfer-channel-job.cpp
@@ -0,0 +1,196 @@
+/*
+* Copyright (C) 2010, 2011 Daniele E. Domenichelli <daniele.domenichelli at gmail.com>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library 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
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+
+#include "handle-incoming-file-transfer-channel-job.h"
+#include "telepathy-base-job_p.h"
+
+#include <QTimer>
+
+#include <KLocalizedString>
+#include <KDebug>
+#include <KUrl>
+
+#include <TelepathyQt4/IncomingFileTransferChannel>
+#include <TelepathyQt4/PendingReady>
+#include <TelepathyQt4/PendingOperation>
+
+class HandleIncomingFileTransferChannelJobPrivate : public KTelepathy::TelepathyBaseJobPrivate
+{
+    Q_DECLARE_PUBLIC(HandleIncomingFileTransferChannelJob)
+
+    public:
+        HandleIncomingFileTransferChannelJobPrivate();
+        virtual ~HandleIncomingFileTransferChannelJobPrivate();
+
+        Tp::IncomingFileTransferChannelPtr channel;
+        QString downloadDirectory;
+        qulonglong offset;
+        QFile* file;
+
+        void __k__start();
+        void __k__onSetUrlOperationFinished(Tp::PendingOperation* op);
+        void __k__onFileTransferChannelStateChanged(Tp::FileTransferState state, Tp::FileTransferStateChangeReason reason);
+        void __k__onFileTransferChannelTransferredBytesChanged(qulonglong count);
+        void __k__onAcceptFileFinished(Tp::PendingOperation* op);
+        void __k__onInvalidated();
+
+        bool transferCompleted;
+};
+
+HandleIncomingFileTransferChannelJob::HandleIncomingFileTransferChannelJob(Tp::IncomingFileTransferChannelPtr channel,
+                                                                           const QString downloadDirectory,
+                                                                           QObject* parent)
+    : TelepathyBaseJob(*new HandleIncomingFileTransferChannelJobPrivate(), parent)
+{
+    Q_D(HandleIncomingFileTransferChannelJob);
+
+    if (channel.isNull())
+    {
+        kError() << "Channel cannot be NULL"; // TODO print a serious message
+        // TODO set error
+    }
+
+    Tp::Features features = Tp::Features() << Tp::FileTransferChannel::FeatureCore;
+    if (!channel->isReady(Tp::Features() << Tp::FileTransferChannel::FeatureCore))
+    {
+        kError() << "Channel must be ready with Tp::FileTransferChannel::FeatureCore"; // TODO print a serious message
+        // TODO set error
+    }
+
+    d->channel = channel;
+    d->downloadDirectory = downloadDirectory;
+}
+
+HandleIncomingFileTransferChannelJob::~HandleIncomingFileTransferChannelJob()
+{
+}
+
+void HandleIncomingFileTransferChannelJob::start()
+{
+    QTimer::singleShot(0, this, SLOT(__k__start()));
+}
+
+HandleIncomingFileTransferChannelJobPrivate::HandleIncomingFileTransferChannelJobPrivate()
+    : file(0)
+{
+}
+
+HandleIncomingFileTransferChannelJobPrivate::~HandleIncomingFileTransferChannelJobPrivate()
+{
+}
+
+void HandleIncomingFileTransferChannelJobPrivate::__k__start()
+{
+    kDebug();
+    Q_Q(HandleIncomingFileTransferChannelJob);
+
+    q->connect(channel.data(), SIGNAL(invalidated(Tp::DBusProxy *, const QString &, const QString &)),
+               q, SLOT(__k__onInvalidated()));
+    q->connect(channel.data(),
+               SIGNAL(stateChanged(Tp::FileTransferState, Tp::FileTransferStateChangeReason)),
+               SLOT(__k__onFileTransferChannelStateChanged(Tp::FileTransferState, Tp::FileTransferStateChangeReason)));
+    q->connect(channel.data(),
+               SIGNAL(transferredBytesChanged(qulonglong)),
+               SLOT(__k__onFileTransferChannelTransferredBytesChanged(qulonglong)));
+
+    KUrl url(downloadDirectory);
+    url.addPath(channel->fileName());
+    url.setScheme(QLatin1String("file"));
+    kDebug() << "File name:" << url;
+
+    file = new QFile(url.toLocalFile(), q->parent());
+    kDebug() << i18n("Saving file as") << file->fileName();
+
+    //TODO check if file already exists and if file should be overwritten, resumed or renamed
+    //     (also set offset accordingly)
+    offset = 0;
+
+    Tp::PendingOperation* setUrlOperation = channel->setUri(url.url());
+    q->connect(setUrlOperation, SIGNAL(finished(Tp::PendingOperation*)),
+               q, SLOT(__k__onSetUrlOperationFinished(Tp::PendingOperation*)));
+}
+
+void HandleIncomingFileTransferChannelJobPrivate::__k__onSetUrlOperationFinished(Tp::PendingOperation* op)
+{
+    kDebug();
+    Q_Q(HandleIncomingFileTransferChannelJob);
+
+    if (op->isError()) {
+        kWarning() << i18n("Unable to set the URI") << "-" <<
+            op->errorName() << ":" << op->errorMessage();
+        __k__onInvalidated();
+        return;
+    }
+
+    Tp::PendingOperation* acceptFileOperation = channel->acceptFile(offset, file);
+    q->connect(acceptFileOperation, SIGNAL(finished(Tp::PendingOperation*)),
+               q, SLOT(__k__onAcceptFileFinished(Tp::PendingOperation*)));
+    addOperation(acceptFileOperation);
+}
+
+void HandleIncomingFileTransferChannelJobPrivate::__k__onFileTransferChannelStateChanged(Tp::FileTransferState state,
+                                                                          Tp::FileTransferStateChangeReason stateReason)
+{
+    kDebug();
+    Q_Q(HandleIncomingFileTransferChannelJob);
+
+    kDebug() << i18n("File transfer channel state changed to") << state << i18n("with reason") << stateReason;
+    transferCompleted = (state == Tp::FileTransferStateCompleted);
+    if (transferCompleted) {
+        kDebug() << i18n("Transfer completed, saved at") << file->fileName();
+        Q_EMIT q->infoMessage(q, i18n("Transfer completed!"));
+
+        QTimer::singleShot(0, q, SLOT(__k__doEmitResult()));
+    }
+}
+
+void HandleIncomingFileTransferChannelJobPrivate::__k__onFileTransferChannelTransferredBytesChanged(qulonglong count)
+{
+    kDebug();
+    Q_Q(HandleIncomingFileTransferChannelJob);
+
+    kDebug().nospace() << i18n("Receiving") << channel->fileName() << "-"
+                       << i18n("transferred bytes") << "=" << count << " ("
+                       << ((int) (((double) count / channel->size()) * 100)) << "%" << i18n("done") << ")";
+    Q_EMIT q->infoMessage(q, i18n("Transferred bytes"));
+}
+
+void HandleIncomingFileTransferChannelJobPrivate::__k__onAcceptFileFinished(Tp::PendingOperation* op)
+{
+    kDebug();
+    if (op->isError()) {
+        kWarning() << i18n("Unable to accept file") << "-" <<
+            op->errorName() << ":" << op->errorMessage();
+        __k__onInvalidated();
+        return;
+    }
+}
+
+void HandleIncomingFileTransferChannelJobPrivate::__k__onInvalidated()
+{
+    Q_Q(HandleIncomingFileTransferChannelJob);
+
+    kWarning() << i18n("File transfer invalidated!");
+    Q_EMIT q->infoMessage(q, i18n("File transfer invalidated!"));
+
+    QTimer::singleShot(0, q, SLOT(__k__doEmitResult()));
+}
+
+
+#include "handle-incoming-file-transfer-channel-job.moc"
diff --git a/src/handle-incoming-file-transfer-channel-job.h b/src/handle-incoming-file-transfer-channel-job.h
new file mode 100644
index 0000000..442f740
--- /dev/null
+++ b/src/handle-incoming-file-transfer-channel-job.h
@@ -0,0 +1,57 @@
+/*
+* Copyright (C) 2010, 2011 Daniele E. Domenichelli <daniele.domenichelli at gmail.com>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library 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
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#ifndef HANDLE_INCOMING_FILE_TRANSFER_CHANNEL_JOB_H
+#define HANDLE_INCOMING_FILE_TRANSFER_CHANNEL_JOB_H
+
+#include <telepathy-base-job.h>
+
+#include <TelepathyQt4/Constants>
+#include <TelepathyQt4/Types>
+
+namespace Tp {
+    class PendingOperation;
+}
+
+
+class HandleIncomingFileTransferChannelJobPrivate;
+class HandleIncomingFileTransferChannelJob : public KTelepathy::TelepathyBaseJob
+{
+    Q_OBJECT
+    Q_DISABLE_COPY(HandleIncomingFileTransferChannelJob)
+    Q_DECLARE_PRIVATE(HandleIncomingFileTransferChannelJob)
+
+//     // Our Q_PRIVATE_SLOTS who perform the real job
+    Q_PRIVATE_SLOT(d_func(), void __k__start())
+    Q_PRIVATE_SLOT(d_func(), void __k__onSetUrlOperationFinished(Tp::PendingOperation* op))
+    Q_PRIVATE_SLOT(d_func(), void __k__onFileTransferChannelStateChanged(Tp::FileTransferState state, Tp::FileTransferStateChangeReason reason))
+    Q_PRIVATE_SLOT(d_func(), void __k__onFileTransferChannelTransferredBytesChanged(qulonglong count))
+    Q_PRIVATE_SLOT(d_func(), void __k__onAcceptFileFinished(Tp::PendingOperation* op))
+    Q_PRIVATE_SLOT(d_func(), void __k__onInvalidated())
+
+public:
+    HandleIncomingFileTransferChannelJob(Tp::IncomingFileTransferChannelPtr channel,
+                                         const QString outputFileName,
+                                         QObject* parent = 0);
+    virtual ~HandleIncomingFileTransferChannelJob();
+
+    virtual void start();
+};
+
+
+#endif // HANDLE_INCOMING_FILE_TRANSFER_CHANNEL_JOB_H
diff --git a/src/handle-outgoing-file-transfer-channel-job.cpp b/src/handle-outgoing-file-transfer-channel-job.cpp
new file mode 100644
index 0000000..88849e2
--- /dev/null
+++ b/src/handle-outgoing-file-transfer-channel-job.cpp
@@ -0,0 +1,216 @@
+/*
+* Copyright (C) 2010, 2011 Daniele E. Domenichelli <daniele.domenichelli at gmail.com>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library 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
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+
+#include "handle-outgoing-file-transfer-channel-job.h"
+#include "telepathy-base-job_p.h"
+
+#include <QTimer>
+
+#include <KLocalizedString>
+#include <KDebug>
+#include <KUrl>
+
+#include <TelepathyQt4/OutgoingFileTransferChannel>
+#include <TelepathyQt4/PendingReady>
+#include <TelepathyQt4/PendingOperation>
+
+class HandleOutgoingFileTransferChannelJobPrivate : public KTelepathy::TelepathyBaseJobPrivate
+{
+    Q_DECLARE_PUBLIC(HandleOutgoingFileTransferChannelJob)
+
+    public:
+        HandleOutgoingFileTransferChannelJobPrivate();
+        virtual ~HandleOutgoingFileTransferChannelJobPrivate();
+
+        Tp::OutgoingFileTransferChannelPtr channel;
+        QFile* file;
+
+        void __k__start();
+        void __k__onFileTransferChannelStateChanged(Tp::FileTransferState state, Tp::FileTransferStateChangeReason reason);
+        void __k__provideFile();
+        void __k__onFileTransferChannelTransferredBytesChanged(qulonglong count);
+        void __k__onProvideFileFinished(Tp::PendingOperation* op);
+        void __k__onInvalidated();
+};
+
+HandleOutgoingFileTransferChannelJob::HandleOutgoingFileTransferChannelJob(Tp::OutgoingFileTransferChannelPtr channel,
+                                                                           QObject* parent)
+    : TelepathyBaseJob(*new HandleOutgoingFileTransferChannelJobPrivate(), parent)
+{
+    kDebug();
+    Q_D(HandleOutgoingFileTransferChannelJob);
+
+    if (channel.isNull())
+    {
+        kError() << "Channel cannot be NULL"; // TODO print a serious message
+        // TODO set error
+    }
+
+    Tp::Features features = Tp::Features() << Tp::FileTransferChannel::FeatureCore;
+    if (!channel->isReady(Tp::Features() << Tp::FileTransferChannel::FeatureCore))
+    {
+        kError() << "Channel must be ready with Tp::FileTransferChannel::FeatureCore"; // TODO print a serious message
+        // TODO set error
+    }
+
+    connect(channel.data(),
+            SIGNAL(invalidated(Tp::DBusProxy *, const QString &, const QString &)),
+            SLOT(__k__onInvalidated()));
+
+    d->channel = channel;
+    kDebug() << "END";
+}
+
+HandleOutgoingFileTransferChannelJob::~HandleOutgoingFileTransferChannelJob()
+{
+    kDebug();
+}
+
+void HandleOutgoingFileTransferChannelJob::start()
+{
+    kDebug();
+    QTimer::singleShot(0, this, SLOT(__k__start()));
+}
+
+HandleOutgoingFileTransferChannelJobPrivate::HandleOutgoingFileTransferChannelJobPrivate()
+    : file(0)
+{
+    kDebug();
+}
+
+HandleOutgoingFileTransferChannelJobPrivate::~HandleOutgoingFileTransferChannelJobPrivate()
+{
+    kDebug();
+}
+
+void HandleOutgoingFileTransferChannelJobPrivate::__k__start()
+{
+    kDebug();
+    Q_Q(HandleOutgoingFileTransferChannelJob);
+
+    q->connect(channel.data(),
+               SIGNAL(stateChanged(Tp::FileTransferState, Tp::FileTransferStateChangeReason)),
+               SLOT(__k__onFileTransferChannelStateChanged(Tp::FileTransferState, Tp::FileTransferStateChangeReason)));
+    q->connect(channel.data(),
+               SIGNAL(transferredBytesChanged(qulonglong)),
+               SLOT(__k__onFileTransferChannelTransferredBytesChanged(qulonglong)));
+
+    if (channel->state() == Tp::FileTransferStateAccepted) {
+        __k__provideFile();
+    }
+}
+
+void HandleOutgoingFileTransferChannelJobPrivate::__k__onFileTransferChannelStateChanged(Tp::FileTransferState state,
+                                                                                         Tp::FileTransferStateChangeReason stateReason)
+{
+    kDebug();
+    Q_Q(HandleOutgoingFileTransferChannelJob);
+
+    kDebug() << i18n("File transfer channel state changed to") << state << i18n("with reason") << stateReason;
+
+    switch (state)
+    {
+        case Tp::FileTransferStateNone:
+            // This is bad
+            kWarning() << i18n("An error occurred.");
+            q->setError(KTelepathy::InvalidOperationError);
+            QTimer::singleShot(0, q, SLOT(__k__doEmitResult()));
+        case Tp::FileTransferStateCompleted:
+            kDebug() << i18n("Transfer completed");
+            Q_EMIT q->infoMessage(q, i18n("Transfer completed"));
+            QTimer::singleShot(0, q, SLOT(__k__doEmitResult())); //TODO here?
+            break;
+        case Tp::FileTransferStateCancelled:
+            kWarning() << i18n("Transfer was canceled.");
+            q->setError(KTelepathy::InvalidOperationError); //TODO
+            q->setErrorText(i18n("Transfer was canceled."));
+            QTimer::singleShot(0, q, SLOT(__k__doEmitResult()));
+            break;
+        case Tp::FileTransferStateAccepted:
+            QTimer::singleShot(0, q, SLOT(__k__provideFile()));
+            break;
+        case Tp::FileTransferStatePending:
+        case Tp::FileTransferStateOpen:
+        default:
+            break;
+    }
+}
+
+void HandleOutgoingFileTransferChannelJobPrivate::__k__provideFile()
+{
+    kDebug();
+    Q_Q(HandleOutgoingFileTransferChannelJob);
+    KUrl uri(channel->uri());
+    if (uri.isEmpty())
+    {
+        qWarning() << "URI property missing";
+        // TODO set error
+        QTimer::singleShot(0, q, SLOT(__k__doEmitResult()));
+    }
+    if (uri.scheme() != QLatin1String("file"))
+    {
+        qWarning() << "Not a local file";
+        // TODO handle this!
+        // TODO set error
+        QTimer::singleShot(0, q, SLOT(__k__doEmitResult()));
+    }
+
+    file = new QFile(uri.toLocalFile(), q->parent());
+    kDebug() << i18n("Providing file") << file->fileName();
+
+    Tp::PendingOperation* provideFileOperation = channel->provideFile(file);
+    q->connect(provideFileOperation, SIGNAL(finished(Tp::PendingOperation*)),
+               q, SLOT(__k__onProvideFileFinished(Tp::PendingOperation*)));
+    addOperation(provideFileOperation);
+}
+
+void HandleOutgoingFileTransferChannelJobPrivate::__k__onFileTransferChannelTransferredBytesChanged(qulonglong count)
+{
+    kDebug();
+    Q_Q(HandleOutgoingFileTransferChannelJob);
+
+    kDebug().nospace() << i18n("Receiving") << channel->fileName() << "-"
+                       << i18n("Transferred bytes") << "=" << count << " ("
+                       << ((int) (((double) count / channel->size()) * 100)) << "%" << i18n("done") << ")";
+    Q_EMIT q->infoMessage(q, i18n("Transferred bytes"));
+}
+
+void HandleOutgoingFileTransferChannelJobPrivate::__k__onProvideFileFinished(Tp::PendingOperation* op)
+{
+    kDebug();
+    if (op->isError()) {
+        kWarning() << i18n("Unable to provide file") << "-" <<
+            op->errorName() << ":" << op->errorMessage();
+        __k__onInvalidated();
+        return;
+    }
+}
+
+void HandleOutgoingFileTransferChannelJobPrivate::__k__onInvalidated()
+{
+    Q_Q(HandleOutgoingFileTransferChannelJob);
+
+    kWarning() << i18n("File transfer invalidated!");
+    Q_EMIT q->infoMessage(q, i18n("File transfer invalidated!"));
+
+    QTimer::singleShot(0, q, SLOT(__k__doEmitResult()));
+}
+
+
+#include "handle-outgoing-file-transfer-channel-job.moc"
diff --git a/src/handle-outgoing-file-transfer-channel-job.h b/src/handle-outgoing-file-transfer-channel-job.h
new file mode 100644
index 0000000..d0e5c77
--- /dev/null
+++ b/src/handle-outgoing-file-transfer-channel-job.h
@@ -0,0 +1,56 @@
+/*
+* Copyright (C) 2010, 2011 Daniele E. Domenichelli <daniele.domenichelli at gmail.com>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library 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
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#ifndef HANDLE_OUTGOING_FILE_TRANSFER_CHANNEL_JOB_H
+#define HANDLE_OUTGOING_FILE_TRANSFER_CHANNEL_JOB_H
+
+#include <telepathy-base-job.h>
+
+#include <TelepathyQt4/Constants>
+#include <TelepathyQt4/Types>
+
+namespace Tp {
+    class PendingOperation;
+}
+
+
+class HandleOutgoingFileTransferChannelJobPrivate;
+class HandleOutgoingFileTransferChannelJob : public KTelepathy::TelepathyBaseJob
+{
+    Q_OBJECT
+    Q_DISABLE_COPY(HandleOutgoingFileTransferChannelJob)
+    Q_DECLARE_PRIVATE(HandleOutgoingFileTransferChannelJob)
+
+//     // Our Q_PRIVATE_SLOTS who perform the real job
+    Q_PRIVATE_SLOT(d_func(), void __k__start())
+    Q_PRIVATE_SLOT(d_func(), void __k__onFileTransferChannelStateChanged(Tp::FileTransferState state, Tp::FileTransferStateChangeReason reason))
+    Q_PRIVATE_SLOT(d_func(), void __k__provideFile())
+    Q_PRIVATE_SLOT(d_func(), void __k__onFileTransferChannelTransferredBytesChanged(qulonglong count))
+    Q_PRIVATE_SLOT(d_func(), void __k__onProvideFileFinished(Tp::PendingOperation* op))
+    Q_PRIVATE_SLOT(d_func(), void __k__onInvalidated())
+
+public:
+    HandleOutgoingFileTransferChannelJob(Tp::OutgoingFileTransferChannelPtr channel,
+                                         QObject* parent = 0);
+    virtual ~HandleOutgoingFileTransferChannelJob();
+
+    virtual void start();
+};
+
+
+#endif // HANDLE_OUTGOING_FILE_TRANSFER_CHANNEL_JOB_H
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..4082e67
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2010, 2011 Daniele E. Domenichelli <daniele.domenichelli at gmail.com>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "filetransfer-handler.h"
+
+#include <TelepathyQt4/Debug>
+
+#include <KAboutData>
+#include <KCmdLineArgs>
+#include <KApplication>
+
+int main(int argc, char* argv[])
+{
+    KAboutData aboutData("telepathy-kde-filetransfer-handler",
+                         0,
+                         ki18n("Telepathy File Transfer Handler"),
+                         "0.1");
+    aboutData.addAuthor(ki18n("Daniele E. Domenichelli"), ki18n("Developer"), "daniele.domenichelli at gmail.com");
+    aboutData.setProductName("telepathy/filetransfer");
+
+    KCmdLineArgs::init(argc, argv, &aboutData);
+    KApplication app;
+
+    Tp::registerTypes();
+    //Enable telepathy-Qt4 debug
+    Tp::enableDebug(true);
+    Tp::enableWarnings(true);
+
+
+    Tp::SharedPtr<FileTransferHandler> fth = Tp::SharedPtr<FileTransferHandler>(new FileTransferHandler);
+
+    return app.exec();
+}
diff --git a/src/org.freedesktop.Telepathy.Client.KDE.FileTransfer.service.in b/src/org.freedesktop.Telepathy.Client.KDE.FileTransfer.service.in
new file mode 100644
index 0000000..afb91ea
--- /dev/null
+++ b/src/org.freedesktop.Telepathy.Client.KDE.FileTransfer.service.in
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.freedesktop.Telepathy.Client.KDE.FileTransfer
+Exec=@CMAKE_INSTALL_PREFIX@/bin/telepathy-kde-filetransfer-handler
diff --git a/src/telepathy-base-job.cpp b/src/telepathy-base-job.cpp
new file mode 100644
index 0000000..5d3ab82
--- /dev/null
+++ b/src/telepathy-base-job.cpp
@@ -0,0 +1,116 @@
+/*
+ * This file is part of telepathy-contactslist-prototype
+ *
+ * Copyright (C) 2009-2010 Collabora Ltd. <info at collabora.co.uk>
+ *   @Author Dario Freddi <dario.freddi at collabora.co.uk>
+ * Copyright (C) 2011 Daniele E. Domenichelli <daniele.domenichelli at gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "telepathy-base-job_p.h"
+
+#include <TelepathyQt4/PendingOperation>
+
+#include <KLocalizedString>
+
+using namespace KTelepathy;
+
+TelepathyBaseJobPrivate::TelepathyBaseJobPrivate()
+    : q_ptr(0)
+{
+}
+
+TelepathyBaseJobPrivate::~TelepathyBaseJobPrivate()
+{
+}
+
+void TelepathyBaseJobPrivate::addOperation(Tp::PendingOperation *op)
+{
+    Q_Q(TelepathyBaseJob);
+
+    // Add the operation to the list
+    operations << op;
+
+    // Attach the operation to our listener
+    q->connect(op, SIGNAL(finished(Tp::PendingOperation*)), q, SLOT(__k__tpOperationFinished(Tp::PendingOperation*)));
+}
+
+TelepathyBaseJob::TelepathyBaseJob(TelepathyBaseJobPrivate& dd, QObject* parent)
+    : KJob(parent)
+    , d_ptr(&dd)
+{
+    d_ptr->q_ptr = this;
+}
+
+TelepathyBaseJob::~TelepathyBaseJob()
+{
+    delete d_ptr;
+}
+
+void TelepathyBaseJobPrivate::__k__tpOperationFinished(Tp::PendingOperation* op)
+{
+    // First of all check if the operation is in our list
+    if (!operations.contains(op)) {
+        // WTF?
+        // TODO: This should never happen, should we do something?
+        return;
+    }
+
+    if (op->isError()) {
+        // Ouch. Add it to the error roster
+        telepathyErrors << qMakePair(op->errorName(), op->errorMessage());
+    }
+
+    // Remove it from the list
+    operations.removeOne(op);
+
+    // Ok, are we done yet?
+    if (operations.isEmpty()) {
+        // It looks like we are. Let's pass the ball to doEmitResult.
+        __k__doEmitResult();
+    }
+}
+
+void TelepathyBaseJobPrivate::__k__doEmitResult()
+{
+    Q_Q(TelepathyBaseJob);
+
+    // Before streaming out: are there any telepathy errors?
+    if (!telepathyErrors.isEmpty()) {
+        // Hmm, bad stuff. Let's handle them here.
+        // FIXME: Maybe there's a better formatting for this specific error string?
+
+        QString errorMessage = i18np("Telepathy reported an error while performing the requested operation:",
+                                     "Telepathy reported %1 errors while performing the requested operation:",
+                                     telepathyErrors.size());
+
+        QList< QPair< QString, QString > >::const_iterator i;
+        for (i = telepathyErrors.constBegin(); i != telepathyErrors.constEnd(); ++i) {
+            errorMessage.append(QLatin1Char('
'));
+            errorMessage.append(i18nc("The following format is: ' - <error name>: <error message>'", " - %1: %2",
+                                      (*i).first, (*i).second));
+        }
+
+        // Ok, let's set the errors now
+        q->setError(KTelepathy::TelepathyErrorError);
+        q->setErrorText(errorMessage);
+    }
+
+    // The job has been finished
+    q->emitResult();
+}
+
+#include "telepathy-base-job.moc"
diff --git a/src/telepathy-base-job.h b/src/telepathy-base-job.h
new file mode 100644
index 0000000..7d7d829
--- /dev/null
+++ b/src/telepathy-base-job.h
@@ -0,0 +1,87 @@
+/*
+ * This file is part of telepathy-contactslist-prototype
+ *
+ * Copyright (C) 2009-2010 Collabora Ltd. <info at collabora.co.uk>
+ *   @Author Dario Freddi <dario.freddi at collabora.co.uk>
+ * Copyright (C) 2011 Daniele E. Domenichelli <daniele.domenichelli at gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef LIBKTELEPATHY_TELEPATHY_BASE_JOB_H
+#define LIBKTELEPATHY_TELEPATHY_BASE_JOB_H
+
+#include <kdemacros.h>
+#include <KJob>
+
+namespace KTelepathy {
+
+    /**
+     * This enum defines the error code for a job spawned by one of the functions inside 
-- 
ktp-filetransfer-handler packaging



More information about the pkg-kde-commits mailing list