[telepathy-qt4/master] OutgoingFileTransferChannel: Added specialized class for outgoing file transfer channels.
Andre Moreira Magalhaes (andrunko)
andre.magalhaes at collabora.co.uk
Wed Sep 16 18:51:51 PDT 2009
---
TelepathyQt4/OutgoingFileTransferChannel | 13 +
TelepathyQt4/outgoing-file-transfer-channel.cpp | 292 +++++++++++++++++++++++
TelepathyQt4/outgoing-file-transfer-channel.h | 76 ++++++
3 files changed, 381 insertions(+), 0 deletions(-)
create mode 100644 TelepathyQt4/OutgoingFileTransferChannel
create mode 100644 TelepathyQt4/outgoing-file-transfer-channel.cpp
create mode 100644 TelepathyQt4/outgoing-file-transfer-channel.h
diff --git a/TelepathyQt4/OutgoingFileTransferChannel b/TelepathyQt4/OutgoingFileTransferChannel
new file mode 100644
index 0000000..792225b
--- /dev/null
+++ b/TelepathyQt4/OutgoingFileTransferChannel
@@ -0,0 +1,13 @@
+#ifndef _TelepathyQt4_OutgoingFileTransferChannel_HEADER_GUARD_
+#define _TelepathyQt4_OutgoingFileTransferChannel_HEADER_GUARD_
+
+#ifndef IN_TELEPATHY_QT4_HEADER
+#define IN_TELEPATHY_QT4_HEADER
+#endif
+
+#include <TelepathyQt4/outgoing-file-transfer-channel.h>
+
+#undef IN_TELEPATHY_QT4_HEADER
+
+#endif
+// vim:set ft=cpp:
diff --git a/TelepathyQt4/outgoing-file-transfer-channel.cpp b/TelepathyQt4/outgoing-file-transfer-channel.cpp
new file mode 100644
index 0000000..aa79127
--- /dev/null
+++ b/TelepathyQt4/outgoing-file-transfer-channel.cpp
@@ -0,0 +1,292 @@
+/*
+ * This file is part of TelepathyQt4
+ *
+ * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * 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 <TelepathyQt4/OutgoingFileTransferChannel>
+
+#include "TelepathyQt4/_gen/outgoing-file-transfer-channel.moc.hpp"
+
+#include "TelepathyQt4/debug-internal.h"
+
+#include <TelepathyQt4/Connection>
+#include <TelepathyQt4/PendingFailure>
+#include <TelepathyQt4/PendingVariant>
+#include <TelepathyQt4/Types>
+
+#include <QIODevice>
+#include <QTcpSocket>
+
+#define BUFFER_SIZE 4096
+
+namespace Tp
+{
+
+struct OutgoingFileTransferChannel::Private
+{
+ Private(OutgoingFileTransferChannel *parent);
+ ~Private();
+
+ // Public object
+ OutgoingFileTransferChannel *parent;
+
+ // Introspection
+ QIODevice *input;
+ QTcpSocket *socket;
+ SocketAddressIPv4 addr;
+};
+
+OutgoingFileTransferChannel::Private::Private(OutgoingFileTransferChannel *parent)
+ : parent(parent),
+ input(0),
+ socket(0)
+{
+}
+
+OutgoingFileTransferChannel::Private::~Private()
+{
+}
+
+/**
+ * \class OutgoingFileTransferChannel
+ * \ingroup clientchannel
+ * \headerfile <TelepathyQt4/outgoing-file-transfer-channel.h> <TelepathyQt4/OutgoingFileTransferChannel>
+ *
+ * High-level proxy object for accessing remote %Channel objects of the
+ * FileTransfer channel type. These channels can be used to transfer one file
+ * to or from a contact.
+ *
+ * This subclass of Channel will eventually provide a high-level API for the
+ * FileTransfer interface. Until then, it's just a Channel.
+ */
+
+const Feature OutgoingFileTransferChannel::FeatureCore = Feature(OutgoingFileTransferChannel::staticMetaObject.className(), 0);
+
+OutgoingFileTransferChannelPtr OutgoingFileTransferChannel::create(const ConnectionPtr &connection,
+ const QString &objectPath, const QVariantMap &immutableProperties)
+{
+ return OutgoingFileTransferChannelPtr(new OutgoingFileTransferChannel(connection, objectPath,
+ immutableProperties));
+}
+
+/**
+ * Creates a OutgoingFileTransferChannel associated with the given object on the
+ * same service as the given connection.
+ *
+ * \param connection Connection owning this OutgoingFileTransferChannel, and
+ * specifying the service.
+ * \param objectPath Path to the object on the service.
+ * \param immutableProperties The immutable properties of the channel, as
+ * signalled by NewChannels or returned by
+ * CreateChannel or EnsureChannel
+ */
+OutgoingFileTransferChannel::OutgoingFileTransferChannel(
+ const ConnectionPtr &connection,
+ const QString &objectPath,
+ const QVariantMap &immutableProperties)
+ : FileTransferChannel(connection, objectPath, immutableProperties),
+ mPriv(new Private(this))
+{
+}
+
+/**
+ * Class destructor.
+ */
+OutgoingFileTransferChannel::~OutgoingFileTransferChannel()
+{
+ delete mPriv;
+}
+
+/**
+ * Provide the file for an outgoing file transfer which has been offered.
+ * The state will change to %FileTransferStateOpen as soon as the transfer
+ * starts.
+ * The given input device should not be destroyed until the state()
+ * changes to %FileTransferStateCompleted or %FileTransferStateCancelled.
+ * If input is a sequential device QIODevice::isSequential(), it should be
+ * closed when no more data is available, so we know when to stop reading.
+ *
+ * \param input A QIODevice object where the data will be read from.
+ * \return A PendingOperation object which will emit PendingOperation::finished
+ * when the call has finished.
+ * \sa stateChanged(), state(), stateReason()
+ */
+PendingOperation *OutgoingFileTransferChannel::provideFile(QIODevice *input)
+{
+ // let's fail here direclty as we may only have one device to handle
+ if (mPriv->input) {
+ warning() << "File transfer can only be started once in the same "
+ "channel";
+ return new PendingFailure(this, TELEPATHY_ERROR_NOT_AVAILABLE,
+ "File transfer can only be started once in the same channel");
+ }
+
+ if ((!input->isOpen() && !input->open(QIODevice::ReadOnly)) &&
+ !input->isReadable()) {
+ warning() << "Unable to open IO device for reading";
+ return new PendingFailure(this, TELEPATHY_ERROR_PERMISSION_DENIED,
+ "Unable to open IO device for reading");
+ }
+
+ mPriv->input = input;
+ connect(input,
+ SIGNAL(aboutToClose()),
+ SLOT(onInputAboutToClose()));
+
+ PendingVariant *pv = new PendingVariant(
+ fileTransferInterface(BypassInterfaceCheck)->ProvideFile(
+ SocketAddressTypeIPv4,
+ SocketAccessControlLocalhost,
+ QDBusVariant(QVariant(QString()))),
+ this);
+ connect(pv,
+ SIGNAL(finished(Tp::PendingOperation*)),
+ SLOT(onProvideFileFinished(Tp::PendingOperation*)));
+ return pv;
+}
+
+void OutgoingFileTransferChannel::onProvideFileFinished(PendingOperation *op)
+{
+ if (op->isError()) {
+ warning() << "Error providing file transfer " <<
+ op->errorName() << ":" << op->errorMessage();
+ return;
+ }
+
+ PendingVariant *pv = qobject_cast<PendingVariant *>(op);
+ mPriv->addr = qdbus_cast<SocketAddressIPv4>(pv->result());
+ debug().nospace() << "Got address " << mPriv->addr.address <<
+ ":" << mPriv->addr.port;
+
+ if (state() == FileTransferStateOpen) {
+ connectToHost();
+ }
+}
+
+void OutgoingFileTransferChannel::connectToHost()
+{
+ if (isConnected() || mPriv->addr.address.isNull()) {
+ return;
+ }
+
+ mPriv->socket = new QTcpSocket(this);
+
+ connect(mPriv->socket, SIGNAL(connected()),
+ SLOT(onSocketConnected()));
+ connect(mPriv->socket, SIGNAL(disconnected()),
+ SLOT(onSocketDisconnected()));
+ connect(mPriv->socket, SIGNAL(error(QAbstractSocket::SocketError)),
+ SLOT(onSocketError(QAbstractSocket::SocketError)));
+ connect(mPriv->socket, SIGNAL(bytesWritten(qint64)),
+ SLOT(doTransfer()));
+
+ debug().nospace() << "Connecting to host " <<
+ mPriv->addr.address << ":" << mPriv->addr.port << "...";
+ mPriv->socket->connectToHost(mPriv->addr.address, mPriv->addr.port);
+}
+
+void OutgoingFileTransferChannel::onSocketConnected()
+{
+ debug() << "Connected to host!";
+ setConnected();
+
+ connect(mPriv->input, SIGNAL(readyRead()),
+ SLOT(doTransfer()));
+
+ debug() << "Starting transfer...";
+ doTransfer();
+}
+
+void OutgoingFileTransferChannel::onSocketDisconnected()
+{
+ debug() << "Disconnected from host!";
+ setFinished();
+}
+
+void OutgoingFileTransferChannel::onSocketError(QAbstractSocket::SocketError error)
+{
+ debug() << "Socket error" << error;
+ setFinished();
+}
+
+void OutgoingFileTransferChannel::onInputAboutToClose()
+{
+ debug() << "Input closed!";
+
+ // in case of sequential devices, we should read everything from it and
+ // write to the socket. Let's not do this for non-sequential devices as we
+ // don't want to read a whole file into memory.
+ if (isConnected() && mPriv->input->isSequential()) {
+ QByteArray data;
+ data = mPriv->input->readAll();
+ mPriv->socket->write(data); // never fails
+ }
+
+ setFinished();
+}
+
+void OutgoingFileTransferChannel::doTransfer()
+{
+ // read 16k each time, as input can be a QFile, we don't want to block
+ // reading the whole file
+ char buffer[16 * 1024];
+ qint64 len = mPriv->input->read(buffer, sizeof(buffer));
+
+ if (len > 0) {
+ mPriv->socket->write(buffer, len); // never fails
+ }
+
+ if (len == -1 || (!mPriv->input->isSequential() && mPriv->input->atEnd())) {
+ // error or EOF
+ setFinished();
+ return;
+ }
+}
+
+void OutgoingFileTransferChannel::setFinished()
+{
+ if (isFinished()) {
+ // it shouldn't happen but let's make sure
+ return;
+ }
+
+ if (mPriv->socket) {
+ disconnect(mPriv->socket, SIGNAL(connected()),
+ this, SLOT(onSocketConnected()));
+ disconnect(mPriv->socket, SIGNAL(disconnected()),
+ this, SLOT(onSocketDisconnected()));
+ disconnect(mPriv->socket, SIGNAL(error(QAbstractSocket::SocketError)),
+ this, SLOT(onSocketError(QAbstractSocket::SocketError)));
+ disconnect(mPriv->socket, SIGNAL(bytesWritten(qint64)),
+ this, SLOT(doTransfer()));
+ mPriv->socket->close();
+ }
+
+ if (mPriv->input) {
+ disconnect(mPriv->input, SIGNAL(aboutToClose()),
+ this, SLOT(onInputAboutToClose()));
+ disconnect(mPriv->input, SIGNAL(readyRead()),
+ this, SLOT(doTransfer()));
+ mPriv->input->close();
+ }
+
+ FileTransferChannel::setFinished();
+}
+
+} // Tp
diff --git a/TelepathyQt4/outgoing-file-transfer-channel.h b/TelepathyQt4/outgoing-file-transfer-channel.h
new file mode 100644
index 0000000..9a4dcba
--- /dev/null
+++ b/TelepathyQt4/outgoing-file-transfer-channel.h
@@ -0,0 +1,76 @@
+/*
+ * This file is part of TelepathyQt4
+ *
+ * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * 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 _TelepathyQt4_outgoing_file_transfer_channel_h_HEADER_GUARD_
+#define _TelepathyQt4_outgoing_file_transfer_channel_h_HEADER_GUARD_
+
+#ifndef IN_TELEPATHY_QT4_HEADER
+#error IN_TELEPATHY_QT4_HEADER
+#endif
+
+#include <TelepathyQt4/FileTransferChannel>
+
+#include <QAbstractSocket>
+
+namespace Tp
+{
+
+class OutgoingFileTransferChannel : public FileTransferChannel
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(OutgoingFileTransferChannel)
+
+public:
+ static const Feature FeatureCore;
+
+ static OutgoingFileTransferChannelPtr create(const ConnectionPtr &connection,
+ const QString &objectPath, const QVariantMap &immutableProperties);
+
+ virtual ~OutgoingFileTransferChannel();
+
+ PendingOperation *provideFile(QIODevice *input);
+
+protected:
+ OutgoingFileTransferChannel(const ConnectionPtr &connection,
+ const QString &objectPath,
+ const QVariantMap &immutableProperties);
+
+private Q_SLOTS:
+ void onProvideFileFinished(Tp::PendingOperation *op);
+
+ void onSocketConnected();
+ void onSocketDisconnected();
+ void onSocketError(QAbstractSocket::SocketError error);
+ void onInputAboutToClose();
+ void doTransfer();
+
+private:
+ void connectToHost();
+ void setFinished();
+
+ struct Private;
+ friend struct Private;
+ Private *mPriv;
+};
+
+} // Tp
+
+#endif
--
1.5.6.5
More information about the telepathy-commits
mailing list