Music Hub ..
A session-wide music playback service
 
Loading...
Searching...
No Matches
track_list_skeleton.cpp
Go to the documentation of this file.
1/*
2 * Copyright © 2015 Canonical Ltd.
3 * Copyright © 2022 UBports Foundation.
4 *
5 * Contact: Alberto Mardegan <mardy@users.sourceforge.net>
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License version 3,
9 * as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY {} without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Authored by: Thomas Voß <thomas.voss@canonical.com>
20 */
21
22#include "track_list_skeleton.h"
23
24#include "apparmor/lomiri.h"
25#include "logging.h"
27
28#include "mpris.h"
29
30#include "util/uri_check.h"
31
32#include <QDBusConnection>
33#include <QDBusMessage>
34
35#include <limits>
36#include <cstdint>
37
39
40using namespace media;
41
42namespace lomiri {
43namespace MediaHubService {
44
46{
47 Q_DECLARE_PUBLIC(TrackListSkeleton)
48
49public:
50 TrackListSkeletonPrivate(const QDBusConnection &bus,
51 const apparmor::lomiri::RequestContextResolver::Ptr& request_context_resolver,
52 const media::apparmor::lomiri::RequestAuthenticator::Ptr& request_authenticator,
55 m_connection(bus),
56 request_context_resolver(request_context_resolver),
57 request_authenticator(request_authenticator),
58 m_impl(impl),
59 q_ptr(q)
60 {
61 }
62
63private:
64 QDBusConnection m_connection;
65 media::apparmor::lomiri::RequestContextResolver::Ptr request_context_resolver;
66 media::apparmor::lomiri::RequestAuthenticator::Ptr request_authenticator;
68 TrackListSkeleton *q_ptr;
69};
70
71}} // namespace
72
73media::TrackListSkeleton::TrackListSkeleton(const QDBusConnection &bus,
74 const media::apparmor::lomiri::RequestContextResolver::Ptr& request_context_resolver,
75 const media::apparmor::lomiri::RequestAuthenticator::Ptr& request_authenticator,
77 QObject *parent):
78 QObject(parent),
79 d_ptr(new TrackListSkeletonPrivate(bus,
80 request_context_resolver,
81 request_authenticator,
82 impl, this))
83{
84 QObject::connect(impl, &TrackListImplementation::trackListReplaced,
85 this, [this](const QVector<media::Track::Id> &tracks,
86 const Track::Id &currentTrack) {
87 QStringList trackList;
88 for (const auto id: tracks) {
89 trackList.append(id);
90 }
91 Q_EMIT TrackListReplaced(trackList, currentTrack);
92 });
93 QObject::connect(impl, &TrackListImplementation::trackAdded,
95 QObject::connect(impl, &TrackListImplementation::tracksAdded,
96 this, [this](const QVector<QUrl> &tracks) {
97 QStringList trackList;
98 for (const auto uri: tracks) {
99 trackList.append(uri.toString());
100 }
101 Q_EMIT TracksAdded(trackList);
102 });
103 QObject::connect(impl, &TrackListImplementation::trackRemoved,
105 QObject::connect(impl, &TrackListImplementation::trackMoved,
107 QObject::connect(impl, &TrackListImplementation::trackChanged,
109 QObject::connect(impl, &TrackListImplementation::trackListReset,
111 // FIXME TrackMetadataChanged is never invoked
112}
113
114media::TrackListSkeleton::~TrackListSkeleton()
115{
116}
117
118QStringList TrackListSkeleton::tracks() const
119{
120 Q_D(const TrackListSkeleton);
121 QStringList trackList;
122 const auto tracks = d->m_impl->tracks();
123 for (const auto id: tracks) {
124 trackList.append(id);
125 }
126 return trackList;
127}
128
130{
131 Q_D(const TrackListSkeleton);
132 return d->m_impl->canEditTracks();
133}
134
135QMap<QString,QString> TrackListSkeleton::GetTracksMetadata(const QString &track)
136{
137 /* FIXME: We should return the metadata, but since the old
138 * implementation always returned an empty map, let's continue
139 * doing the same. We need to fix the signature anyway.
140 Q_D(TrackListSkeleton);
141 Track::MetaData md = d->m_impl->query_meta_data_for_track(track);
142 */
143 Q_UNUSED(track);
144 return QMap<QString,QString>();
145}
146
147QString TrackListSkeleton::GetTracksUri(const QString &track)
148{
150 return d->m_impl->query_uri_for_track(track).toString();
151}
152
153void TrackListSkeleton::AddTrack(const QString &uri, const QString &after,
154 bool makeCurrent)
155{
157
158 MH_TRACE("");
159 QDBusMessage in = message();
160 QDBusConnection bus = connection();
161 in.setDelayedReply(true);
162
163 struct Params {
164 QString uri;
165 QString after;
166 bool makeCurrent;
167 } params = { uri, after, makeCurrent };
168
169 d->request_context_resolver->resolve_context_for_dbus_name_async
170 (in.service(), [this, in, bus, params](const media::apparmor::lomiri::Context& context)
171 {
172 Q_D(TrackListSkeleton);
173 QUrl uri = QUrl::fromUserInput(params.uri);
174 media::Track::Id after = params.after;
175 bool makeCurrent = params.makeCurrent;
176
177 // Make sure the client has adequate apparmor permissions to open the URI
178 const auto result = d->request_authenticator->authenticate_open_uri_request(context, uri);
179
180 UriCheck uri_check(uri);
181 const bool valid_uri = !uri_check.is_local_file() or
182 (uri_check.is_local_file() and uri_check.file_exists());
183 QDBusMessage reply = in.createReply();
184 if (!valid_uri)
185 {
186 const QString err_str = {"Warning: Not adding track " + uri.toString() +
187 " to TrackList because it can't be found."};
188 MH_WARNING() << err_str;
189 reply = in.createErrorReply(
190 mpris::Player::Error::UriNotFound::name,
191 err_str);
192 }
193 else
194 {
195 // Only add the track to the TrackList if it passes the apparmor permissions check
196 if (std::get<0>(result))
197 {
198 d->m_impl->add_track_with_uri_at(uri, after, makeCurrent);
199 }
200 else
201 {
202 const QString err_str = {"Warning: Not adding track " + uri.toString() +
203 " to TrackList because of inadequate client apparmor permissions."};
204 MH_WARNING() << err_str;
205 reply = in.createErrorReply(
207 err_str);
208 }
209 }
210
211 bus.send(reply);
212 });
213}
214
215void TrackListSkeleton::AddTracks(const QStringList &uris,
216 const QString &after)
217{
219 MH_TRACE("");
220 QDBusMessage in = message();
221 QDBusConnection bus = connection();
222 in.setDelayedReply(true);
223
224 struct Params {
225 QStringList uris;
226 QString after;
227 } params = { uris, after };
228
229 d->request_context_resolver->resolve_context_for_dbus_name_async
230 (in.service(), [this, in, bus, params](const media::apparmor::lomiri::Context& context)
231 {
232 Q_D(TrackListSkeleton);
233 const QStringList &uris = params.uris;
234 const media::Track::Id after = params.after;
235
236 bool valid_uri = false;
237 media::apparmor::lomiri::RequestAuthenticator::Result result;
238 QString uri_err_str, err_str;
239 QVector<QUrl> trackUris;
240 QDBusMessage reply;
241 for (const auto uri : uris)
242 {
243 UriCheck uri_check(uri);
244 valid_uri = !uri_check.is_local_file() or
245 (uri_check.is_local_file() and uri_check.file_exists());
246 if (!valid_uri)
247 {
248 uri_err_str = {"Warning: Not adding track " + uri +
249 " to TrackList because it can't be found."};
250 MH_WARNING() << uri_err_str;
251 reply = in.createErrorReply(
252 mpris::Player::Error::UriNotFound::name,
253 err_str);
254 }
255
256 // Make sure the client has adequate apparmor permissions to open the URI
257 result = d->request_authenticator->authenticate_open_uri_request(context, uri);
258 if (not std::get<0>(result))
259 {
260 err_str = {"Warning: Not adding track " + uri +
261 " to TrackList because of inadequate client apparmor permissions."};
262 break;
263 }
264
265 trackUris.append(QUrl::fromUserInput(uri));
266 }
267
268 // Only add the track to the TrackList if it passes the apparmor permissions check
269 if (std::get<0>(result))
270 {
271 reply = in.createReply();
272 d->m_impl->add_tracks_with_uri_at(trackUris, after);
273 }
274 else
275 {
276 MH_WARNING() << err_str;
277 reply = in.createErrorReply(
279 err_str);
280 }
281
282 bus.send(reply);
283 });
284}
285
286void TrackListSkeleton::MoveTrack(const QString &id, const QString &to)
287{
289 try {
290 const bool ret = d->m_impl->move_track(id, to);
291 if (!ret)
292 {
293 const QString err_str = {"Error: Not moving track " + id +
294 " to destination " + to};
295 MH_WARNING() << err_str;
296 sendErrorReply(
298 err_str);
299 }
300 } catch(media::TrackList::Errors::FailedToMoveTrack& e) {
301 sendErrorReply(
303 e.what());
304 } catch(media::TrackList::Errors::FailedToFindMoveTrackSource& e) {
305 sendErrorReply(
307 e.what());
308 } catch(media::TrackList::Errors::FailedToFindMoveTrackDest& e) {
309 sendErrorReply(
311 e.what());
312 }
313}
314
315void TrackListSkeleton::RemoveTrack(const QString &id)
316{
318 try {
319 d->m_impl->remove_track(id);
320 } catch(media::TrackList::Errors::TrackNotFound& e) {
321 sendErrorReply(
323 e.what());
324 }
325}
326
327void TrackListSkeleton::GoTo(const QString &id)
328{
330 d->m_impl->go_to(id);
331}
332
334{
336 d->m_impl->reset();
337}
void tracksAdded(const QVector< QUrl > &tracks)
void trackMoved(const Track::Id &id, const Track::Id &to)
void trackListReplaced(const QVector< Track::Id > &tracks, const Track::Id &currentTrack)
TrackListSkeletonPrivate(const QDBusConnection &bus, const apparmor::lomiri::RequestContextResolver::Ptr &request_context_resolver, const media::apparmor::lomiri::RequestAuthenticator::Ptr &request_authenticator, TrackListImplementation *impl, TrackListSkeleton *q)
void AddTracks(const QStringList &uris, const QString &after)
Q_SCRIPTABLE void TrackListReplaced(const QStringList &tracks, const QString &currentTrack)
QMap< QString, QString > GetTracksMetadata(const QString &id)
Q_SCRIPTABLE void TrackMoved(const QString &id, const QString &to)
Q_SCRIPTABLE void TrackAdded(const QString &id)
void AddTrack(const QString &uri, const QString &after, bool makeCurrent)
Q_SCRIPTABLE void TrackChanged(const QString &id)
void MoveTrack(const QString &id, const QString &to)
Q_SCRIPTABLE void TrackRemoved(const QString &id)
Q_SCRIPTABLE void TracksAdded(const QStringList &trackURIs)
QSharedPointer< RequestContextResolver > Ptr
Definition lomiri.h:85
#define MH_TRACE(...)
Definition logging.h:37
#define MH_WARNING(...)
Definition logging.h:40
static constexpr const char * name
Definition mpris.h:251
static constexpr const char * name
Definition mpris.h:235
static constexpr const char * name
Definition mpris.h:259