diff options
Diffstat (limited to 'qt4/TelepathyQt4/simple-stream-tube-handler.cpp')
-rw-r--r-- | qt4/TelepathyQt4/simple-stream-tube-handler.cpp | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/qt4/TelepathyQt4/simple-stream-tube-handler.cpp b/qt4/TelepathyQt4/simple-stream-tube-handler.cpp new file mode 100644 index 000000000..057800749 --- /dev/null +++ b/qt4/TelepathyQt4/simple-stream-tube-handler.cpp @@ -0,0 +1,254 @@ +/** + * This file is part of TelepathyQt4 + * + * @copyright Copyright (C) 2011 Collabora Ltd. <http://www.collabora.co.uk/> + * @copyright Copyright (C) 2011 Nokia Corporation + * @license LGPL 2.1 + * + * 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/simple-stream-tube-handler.h" + +#include "TelepathyQt4/_gen/simple-stream-tube-handler.moc.hpp" + +#include "TelepathyQt4/debug-internal.h" + +#include <TelepathyQt4/Account> +#include <TelepathyQt4/ChannelClassSpec> +#include <TelepathyQt4/PendingComposite> +#include <TelepathyQt4/PendingReady> +#include <TelepathyQt4/StreamTubeChannel> + +namespace Tp +{ + +namespace +{ + ChannelClassSpecList buildFilter(const QStringList &p2pServices, + const QStringList &roomServices, bool requested) + { + ChannelClassSpecList filter; + + // Convert to QSet to weed out duplicates + foreach (const QString &service, p2pServices.toSet()) + { + filter.append(requested ? + ChannelClassSpec::outgoingStreamTube(service) : + ChannelClassSpec::incomingStreamTube(service)); + } + + // Convert to QSet to weed out duplicates + foreach (const QString &service, roomServices.toSet()) + { + filter.append(requested ? + ChannelClassSpec::outgoingRoomStreamTube(service) : + ChannelClassSpec::incomingRoomStreamTube(service)); + } + + return filter; + } +} + +SharedPtr<SimpleStreamTubeHandler> SimpleStreamTubeHandler::create( + const QStringList &p2pServices, + const QStringList &roomServices, + bool requested, + bool monitorConnections, + bool bypassApproval) +{ + return SharedPtr<SimpleStreamTubeHandler>( + new SimpleStreamTubeHandler( + p2pServices, + roomServices, + requested, + monitorConnections, + bypassApproval)); +} + +SimpleStreamTubeHandler::SimpleStreamTubeHandler( + const QStringList &p2pServices, + const QStringList &roomServices, + bool requested, + bool monitorConnections, + bool bypassApproval) + : AbstractClient(), + AbstractClientHandler(buildFilter(p2pServices, roomServices, requested)), + mMonitorConnections(monitorConnections), + mBypassApproval(bypassApproval) +{ +} + +SimpleStreamTubeHandler::~SimpleStreamTubeHandler() +{ + if (!mTubes.empty()) { + debug() << "~SSTubeHandler(): Closing" << mTubes.size() << "leftover tubes"; + + foreach (const StreamTubeChannelPtr &tube, mTubes.keys()) { + tube->requestClose(); + } + } +} + +void SimpleStreamTubeHandler::handleChannels( + const MethodInvocationContextPtr<> &context, + const AccountPtr &account, + const ConnectionPtr &connection, + const QList<ChannelPtr> &channels, + const QList<ChannelRequestPtr> &requestsSatisfied, + const QDateTime &userActionTime, + const HandlerInfo &handlerInfo) +{ + debug() << "SimpleStreamTubeHandler::handleChannels() invoked for " << + channels.size() << "channels on account" << account->objectPath(); + + SharedPtr<InvocationData> invocation(new InvocationData()); + QList<PendingOperation *> readyOps; + + foreach (const ChannelPtr &chan, channels) { + StreamTubeChannelPtr tube = StreamTubeChannelPtr::qObjectCast(chan); + + if (!tube) { + // TODO: if Channel ever starts utilizing its immutable props for the immutable + // accessors, use Channel::channelType() here + const QString channelType = + chan->immutableProperties()[QLatin1String( + TELEPATHY_INTERFACE_CHANNEL ".ChannelType")].toString(); + + if (channelType != TP_QT4_IFACE_CHANNEL_TYPE_STREAM_TUBE) { + debug() << "We got a non-StreamTube channel" << chan->objectPath() << + "of type" << channelType << ", ignoring"; + } else { + warning() << "The channel factory used for a simple StreamTube handler must" << + "construct StreamTubeChannel subclasses for stream tubes"; + } + continue; + } + + Features features = StreamTubeChannel::FeatureStreamTube; + if (mMonitorConnections) { + features.insert(StreamTubeChannel::FeatureConnectionMonitoring); + } + readyOps.append(tube->becomeReady(features)); + + invocation->tubes.append(tube); + } + + invocation->ctx = context; + invocation->acc = account; + invocation->time = userActionTime; + + if (!requestsSatisfied.isEmpty()) { + invocation->hints = requestsSatisfied.first()->hints(); + } + + mInvocations.append(invocation); + + if (invocation->tubes.isEmpty()) { + warning() << "SSTH::HandleChannels got no suitable channels, admitting we're Confused"; + invocation->readyOp = 0; + invocation->error = TP_QT4_ERROR_CONFUSED; + invocation->message = QLatin1String("Got no suitable channels"); + onReadyOpFinished(0); + } else { + invocation->readyOp = new PendingComposite(readyOps, SharedPtr<SimpleStreamTubeHandler>(this)); + connect(invocation->readyOp, + SIGNAL(finished(Tp::PendingOperation*)), + SLOT(onReadyOpFinished(Tp::PendingOperation*))); + } +} + +void SimpleStreamTubeHandler::onReadyOpFinished(Tp::PendingOperation *op) +{ + Q_ASSERT(!mInvocations.isEmpty()); + Q_ASSERT(!op || op->isFinished()); + + for (QLinkedList<SharedPtr<InvocationData> >::iterator i = mInvocations.begin(); + op != 0 && i != mInvocations.end(); ++i) { + if ((*i)->readyOp != op) { + continue; + } + + (*i)->readyOp = 0; + + if (op->isError()) { + warning() << "Preparing proxies for SSTubeHandler failed with" << op->errorName() + << op->errorMessage(); + (*i)->error = op->errorName(); + (*i)->message = op->errorMessage(); + } + + break; + } + + while (!mInvocations.isEmpty() && !mInvocations.first()->readyOp) { + SharedPtr<InvocationData> invocation = mInvocations.takeFirst(); + + if (!invocation->error.isEmpty()) { + // We guarantee that the proxies were ready - so we can't invoke the client if they + // weren't made ready successfully. Fix the introspection code if this happens :) + invocation->ctx->setFinishedWithError(invocation->error, invocation->message); + continue; + } + + debug() << "Emitting SSTubeHandler::invokedForTube for" << invocation->tubes.size() + << "tubes"; + + foreach (const StreamTubeChannelPtr &tube, invocation->tubes) { + if (!tube->isValid()) { + debug() << "Skipping already invalidated tube" << tube->objectPath(); + continue; + } + + if (!mTubes.contains(tube)) { + connect(tube.data(), + SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), + SLOT(onTubeInvalidated(Tp::DBusProxy*,QString,QString))); + + mTubes.insert(tube, invocation->acc); + } + + emit invokedForTube( + invocation->acc, + tube, + invocation->time, + invocation->hints); + } + + invocation->ctx->setFinished(); + } +} + +void SimpleStreamTubeHandler::onTubeInvalidated(DBusProxy *proxy, + const QString &errorName, const QString &errorMessage) +{ + StreamTubeChannelPtr tube(qobject_cast<StreamTubeChannel *>(proxy)); + + Q_ASSERT(!tube.isNull()); + Q_ASSERT(mTubes.contains(tube)); + + debug() << "Tube" << tube->objectPath() << "invalidated - " << errorName << ':' << errorMessage; + + AccountPtr acc = mTubes.value(tube); + mTubes.remove(tube); + + emit tubeInvalidated( + acc, + tube, + errorName, + errorMessage); +} + +} // Tp |