2
* Copyright (C) 2013 Canonical, Ltd.
5
* Michael Terry <michael.terry@canonical.com>
7
* This file is part of telephony-service.
9
* telephony-service is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; version 3.
13
* telephony-service is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program. If not, see <http://www.gnu.org/licenses/>.
22
#include "greetercontacts.h"
25
#include <QContactAvatar>
26
#include <QContactInvalidFilter>
27
#include <QContactManagerEngine>
28
#include <QContactName>
29
#include <QContactPhoneNumber>
30
#include <QDBusInterface>
31
#include <QDBusPendingCall>
32
#include <QDBusPendingReply>
37
QTCONTACTS_USE_NAMESPACE
39
GreeterContacts::GreeterContacts(QObject *parent)
41
mFilter(QContactInvalidFilter()),
47
QDBusConnection connection = QDBusConnection::sessionBus();
48
connection.connect("com.canonical.UnityGreeter",
50
"org.freedesktop.DBus.Properties",
53
SLOT(greeterPropertiesChanged(QString, QVariantMap, QStringList)));
55
connection = QDBusConnection::AS_BUSNAME();
56
connection.connect("org.freedesktop.Accounts",
58
"org.freedesktop.DBus.Properties",
61
SLOT(accountsPropertiesChanged(QString, QVariantMap, QStringList, QDBusMessage)));
63
// Start initial queries
67
QDBusInterface iface("org.freedesktop.Accounts",
68
"/org/freedesktop/Accounts",
69
"org.freedesktop.Accounts",
70
QDBusConnection::AS_BUSNAME());
71
QDBusPendingCall call = iface.asyncCall("ListCachedUsers");
72
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
73
connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)),
74
this, SLOT(accountsGetUsersReply(QDBusPendingCallWatcher *)));
77
GreeterContacts::~GreeterContacts()
81
void GreeterContacts::setFilter(const QContactFilter &filter)
87
void GreeterContacts::greeterPropertiesChanged(const QString &interface,
88
const QVariantMap &changed,
89
const QStringList &invalidated)
91
if (interface == "com.canonical.UnityGreeter.List") {
92
if (changed.contains("ActiveEntry")) {
93
updateActiveUser(changed.value("ActiveEntry").toString());
94
} else if (invalidated.contains("ActiveEntry")) {
100
void GreeterContacts::accountsPropertiesChanged(const QString &interface,
101
const QVariantMap &changed,
102
const QStringList &invalidated,
103
const QDBusMessage &message)
105
if (interface == "com.canonical.TelephonyServiceApprover") {
106
if (changed.contains("CurrentContact")) {
107
mContacts.insert(message.path(), qdbus_cast<QVariantMap>(changed.value("CurrentContact")));
109
} else if (invalidated.contains("CurrentContact")) {
110
queryContact(message.path());
115
void GreeterContacts::greeterGetEntryReply(QDBusPendingCallWatcher *watcher)
117
QDBusPendingReply<QVariant> reply = *watcher;
118
if (!reply.isError()) {
119
updateActiveUser(reply.argumentAt<0>().toString());
121
qWarning() << "Failed to get active entry from Unity Greeter:" << reply.error().message();
123
watcher->deleteLater();
126
void GreeterContacts::accountsGetUsersReply(QDBusPendingCallWatcher *watcher)
128
QDBusPendingReply<QList<QDBusObjectPath>> reply = *watcher;
129
if (!reply.isError()) {
130
Q_FOREACH (const QDBusObjectPath &user, reply.argumentAt<0>()) {
131
queryContact(user.path());
134
qWarning() << "Failed to get user list from AccountsService:" << reply.error().message();
136
watcher->deleteLater();
139
void GreeterContacts::accountsGetContactReply(QDBusPendingCallWatcher *watcher)
141
QDBusPendingReply<QVariant> reply = *watcher;
142
if (!reply.isError()) {
143
mContacts.insert(watcher->property("telepathyPath").toString(), qdbus_cast<QVariantMap>(reply.argumentAt<0>()));
146
qWarning() << "Failed to get user's contact from AccountsService:" << reply.error().message();
148
watcher->deleteLater();
151
void GreeterContacts::queryEntry()
153
QDBusInterface iface("com.canonical.UnityGreeter",
155
"org.freedesktop.DBus.Properties",
156
QDBusConnection::sessionBus());
157
QDBusPendingCall call = iface.asyncCall("Get", "com.canonical.UnityGreeter.List", "ActiveEntry");
158
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
159
connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)),
160
this, SLOT(greeterGetEntryReply(QDBusPendingCallWatcher *)));
163
void GreeterContacts::queryContact(const QString &user)
165
QDBusInterface iface("org.freedesktop.Accounts",
167
"org.freedesktop.DBus.Properties",
168
QDBusConnection::AS_BUSNAME());
169
QDBusPendingCall call = iface.asyncCall("Get", "com.canonical.TelephonyServiceApprover", "CurrentContact");
170
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
171
watcher->setProperty("telepathyPath", QVariant(user));
172
connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)),
173
this, SLOT(accountsGetContactReply(QDBusPendingCallWatcher *)));
176
void GreeterContacts::updateActiveUser(const QString &username)
178
struct passwd *pwinfo = getpwnam(username.toLatin1());
180
mActiveUser = "/org/freedesktop/Accounts/User" + QString::number(pwinfo->pw_uid);
185
QContact GreeterContacts::lookupContact()
187
// For now, only ever look at active user's contact info. In future,
188
// maybe we should search all users for any matching info.
189
QVariantMap contactInfo = mContacts.value(mActiveUser);
190
if (!contactInfo.empty()) {
191
QContact contact = mapToContact(contactInfo);
192
if (QContactManagerEngine::testFilter(mFilter, contact)) {
200
void GreeterContacts::signalIfNeeded()
202
QContact contact = lookupContact();
203
if (!contact.isEmpty()) {
204
Q_EMIT contactUpdated(contact);
208
void GreeterContacts::emitContact(const QContact &contact)
210
QString uid = QString::number(getuid());
211
QVariantMap map = contactToMap(contact);
213
if (!map.value("Image").toString().isEmpty()) {
214
// OK, so we want to tell LightDM about our contact. But LightDM won't
215
// have access to our image file in their normal location managed by
216
// evolution. And rather than give world-readable permissions to our
217
// evolution dir, we minimize the damage by copying the image to a new
218
// more accessible location.
219
// TODO: This is not ideal because this new location is still
220
// world-readable and thus leaks a contact picture and because if the
221
// user's home directory is encrypted, LightDM can't read it.
222
// Hopefully LightDM will soon allow a /run/user style location for
223
// users to share data with it.
224
QFile imageFile(QDir::home().filePath(".telephony-service-contact-image"));
226
if (QFile(map.value("Image").toString()).copy(imageFile.fileName())) {
227
map.insert("Image", imageFile.fileName());
231
QDBusInterface iface("org.freedesktop.Accounts",
232
"/org/freedesktop/Accounts/User" + uid,
233
"org.freedesktop.DBus.Properties",
234
QDBusConnection::AS_BUSNAME());
235
iface.asyncCall("Set", "com.canonical.TelephonyServiceApprover", "CurrentContact", QVariant::fromValue(QDBusVariant(QVariant(map))));
238
QVariantMap GreeterContacts::contactToMap(const QContact &contact)
242
QContactAvatar avatarDetail = contact.detail<QContactAvatar>();
243
map.insert("Image", avatarDetail.imageUrl().toLocalFile());
245
QContactName nameDetail = contact.detail<QContactName>();
246
map.insert("FirstName", nameDetail.firstName());
247
map.insert("LastName", nameDetail.lastName());
249
QContactPhoneNumber numberDetail = contact.detail<QContactPhoneNumber>();
250
map.insert("PhoneNumber", numberDetail.number());
255
QContact GreeterContacts::mapToContact(const QVariantMap &map)
259
QContactAvatar avatarDetail;
260
avatarDetail.setValue(QContactAvatar::FieldImageUrl, QUrl::fromLocalFile(map.value("Image").toString()));
261
contact.saveDetail(&avatarDetail);
263
// We only use FirstName and LastName right now in ContactUtils::formatContactName().
264
// If/When we use more, we should save more detail values here.
265
QContactName nameDetail;
266
nameDetail.setValue(QContactName::FieldFirstName, map.value("FirstName"));
267
nameDetail.setValue(QContactName::FieldLastName, map.value("LastName"));
268
contact.saveDetail(&nameDetail);
270
QContactPhoneNumber numberDetail;
271
numberDetail.setValue(QContactPhoneNumber::FieldNumber, map.value("PhoneNumber"));
272
contact.saveDetail(&numberDetail);