~phablet-team/telephony-service/trunk

« back to all changes in this revision

Viewing changes to approver/greetercontacts.cpp

  • Committer: CI bot
  • Author(s): Michael Terry
  • Date: 2014-02-06 14:19:18 UTC
  • mfrom: (762.2.2 greeter)
  • Revision ID: ps-jenkins@lists.canonical.com-20140206141918-68sl1hbl9wcomb3s
Share current call contact info with the greeter. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2013 Canonical, Ltd.
 
3
 *
 
4
 * Authors:
 
5
 *  Michael Terry <michael.terry@canonical.com>
 
6
 *
 
7
 * This file is part of telephony-service.
 
8
 *
 
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.
 
12
 *
 
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.
 
17
 *
 
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/>.
 
20
 */
 
21
 
 
22
#include "greetercontacts.h"
 
23
 
 
24
#include <pwd.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>
 
33
#include <QDir>
 
34
#include <QFile>
 
35
#include <unistd.h>
 
36
 
 
37
QTCONTACTS_USE_NAMESPACE
 
38
 
 
39
GreeterContacts::GreeterContacts(QObject *parent)
 
40
: QObject(parent),
 
41
  mFilter(QContactInvalidFilter()),
 
42
  mActiveUser(),
 
43
  mContacts()
 
44
{
 
45
    // Watch for changes
 
46
 
 
47
    QDBusConnection connection = QDBusConnection::sessionBus();
 
48
    connection.connect("com.canonical.UnityGreeter",
 
49
                       "/list",
 
50
                       "org.freedesktop.DBus.Properties",
 
51
                       "PropertiesChanged",
 
52
                       this,
 
53
                       SLOT(greeterPropertiesChanged(QString, QVariantMap, QStringList)));
 
54
 
 
55
    connection = QDBusConnection::AS_BUSNAME();
 
56
    connection.connect("org.freedesktop.Accounts",
 
57
                       nullptr,
 
58
                       "org.freedesktop.DBus.Properties",
 
59
                       "PropertiesChanged",
 
60
                       this,
 
61
                       SLOT(accountsPropertiesChanged(QString, QVariantMap, QStringList, QDBusMessage)));
 
62
 
 
63
    // Start initial queries
 
64
 
 
65
    queryEntry();
 
66
 
 
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 *)));
 
75
}
 
76
 
 
77
GreeterContacts::~GreeterContacts()
 
78
{
 
79
}
 
80
 
 
81
void GreeterContacts::setFilter(const QContactFilter &filter)
 
82
{
 
83
    mFilter = filter;
 
84
    signalIfNeeded();
 
85
}
 
86
 
 
87
void GreeterContacts::greeterPropertiesChanged(const QString &interface,
 
88
                                               const QVariantMap &changed,
 
89
                                               const QStringList &invalidated)
 
90
{
 
91
    if (interface == "com.canonical.UnityGreeter.List") {
 
92
        if (changed.contains("ActiveEntry")) {
 
93
            updateActiveUser(changed.value("ActiveEntry").toString());
 
94
        } else if (invalidated.contains("ActiveEntry")) {
 
95
            queryEntry();
 
96
        }
 
97
    }
 
98
}
 
99
 
 
100
void GreeterContacts::accountsPropertiesChanged(const QString &interface,
 
101
                                                const QVariantMap &changed,
 
102
                                                const QStringList &invalidated,
 
103
                                                const QDBusMessage &message)
 
104
{
 
105
    if (interface == "com.canonical.TelephonyServiceApprover") {
 
106
        if (changed.contains("CurrentContact")) {
 
107
            mContacts.insert(message.path(), qdbus_cast<QVariantMap>(changed.value("CurrentContact")));
 
108
            signalIfNeeded();
 
109
        } else if (invalidated.contains("CurrentContact")) {
 
110
            queryContact(message.path());
 
111
        }
 
112
    }
 
113
}
 
114
 
 
115
void GreeterContacts::greeterGetEntryReply(QDBusPendingCallWatcher *watcher)
 
116
{
 
117
    QDBusPendingReply<QVariant> reply = *watcher;
 
118
    if (!reply.isError()) {
 
119
        updateActiveUser(reply.argumentAt<0>().toString());
 
120
    } else {
 
121
        qWarning() << "Failed to get active entry from Unity Greeter:" << reply.error().message();
 
122
    }
 
123
    watcher->deleteLater();
 
124
}
 
125
 
 
126
void GreeterContacts::accountsGetUsersReply(QDBusPendingCallWatcher *watcher)
 
127
{
 
128
    QDBusPendingReply<QList<QDBusObjectPath>> reply = *watcher;
 
129
    if (!reply.isError()) {
 
130
        Q_FOREACH (const QDBusObjectPath &user, reply.argumentAt<0>()) {
 
131
            queryContact(user.path());
 
132
        }
 
133
    } else {
 
134
        qWarning() << "Failed to get user list from AccountsService:" << reply.error().message();
 
135
    }
 
136
    watcher->deleteLater();
 
137
}
 
138
 
 
139
void GreeterContacts::accountsGetContactReply(QDBusPendingCallWatcher *watcher)
 
140
{
 
141
    QDBusPendingReply<QVariant> reply = *watcher;
 
142
    if (!reply.isError()) {
 
143
        mContacts.insert(watcher->property("telepathyPath").toString(), qdbus_cast<QVariantMap>(reply.argumentAt<0>()));
 
144
        signalIfNeeded();
 
145
    } else {
 
146
        qWarning() << "Failed to get user's contact from AccountsService:" << reply.error().message();
 
147
    }
 
148
    watcher->deleteLater();
 
149
}
 
150
 
 
151
void GreeterContacts::queryEntry()
 
152
{
 
153
    QDBusInterface iface("com.canonical.UnityGreeter",
 
154
                         "/list",
 
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 *)));
 
161
}
 
162
 
 
163
void GreeterContacts::queryContact(const QString &user)
 
164
{
 
165
    QDBusInterface iface("org.freedesktop.Accounts",
 
166
                         user,
 
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 *)));
 
174
}
 
175
 
 
176
void GreeterContacts::updateActiveUser(const QString &username)
 
177
{
 
178
    struct passwd *pwinfo = getpwnam(username.toLatin1());
 
179
    if (pwinfo) {
 
180
        mActiveUser = "/org/freedesktop/Accounts/User" + QString::number(pwinfo->pw_uid);
 
181
        signalIfNeeded();
 
182
    }
 
183
}
 
184
 
 
185
QContact GreeterContacts::lookupContact()
 
186
{
 
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)) {
 
193
            return contact;
 
194
        }
 
195
    }
 
196
 
 
197
    return QContact();
 
198
}
 
199
 
 
200
void GreeterContacts::signalIfNeeded()
 
201
{
 
202
    QContact contact = lookupContact();
 
203
    if (!contact.isEmpty()) {
 
204
        Q_EMIT contactUpdated(contact);
 
205
    }
 
206
}
 
207
 
 
208
void GreeterContacts::emitContact(const QContact &contact)
 
209
{
 
210
    QString uid = QString::number(getuid());
 
211
    QVariantMap map = contactToMap(contact);
 
212
 
 
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"));
 
225
        imageFile.remove();
 
226
        if (QFile(map.value("Image").toString()).copy(imageFile.fileName())) {
 
227
            map.insert("Image", imageFile.fileName());
 
228
        }
 
229
    }
 
230
 
 
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))));
 
236
}
 
237
 
 
238
QVariantMap GreeterContacts::contactToMap(const QContact &contact)
 
239
{
 
240
    QVariantMap map;
 
241
 
 
242
    QContactAvatar avatarDetail = contact.detail<QContactAvatar>();
 
243
    map.insert("Image", avatarDetail.imageUrl().toLocalFile());
 
244
 
 
245
    QContactName nameDetail = contact.detail<QContactName>();
 
246
    map.insert("FirstName", nameDetail.firstName());
 
247
    map.insert("LastName", nameDetail.lastName());
 
248
 
 
249
    QContactPhoneNumber numberDetail = contact.detail<QContactPhoneNumber>();
 
250
    map.insert("PhoneNumber", numberDetail.number());
 
251
 
 
252
    return map;
 
253
}
 
254
 
 
255
QContact GreeterContacts::mapToContact(const QVariantMap &map)
 
256
{
 
257
    QContact contact;
 
258
 
 
259
    QContactAvatar avatarDetail;
 
260
    avatarDetail.setValue(QContactAvatar::FieldImageUrl, QUrl::fromLocalFile(map.value("Image").toString()));
 
261
    contact.saveDetail(&avatarDetail);
 
262
 
 
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);
 
269
 
 
270
    QContactPhoneNumber numberDetail;
 
271
    numberDetail.setValue(QContactPhoneNumber::FieldNumber, map.value("PhoneNumber"));
 
272
    contact.saveDetail(&numberDetail);
 
273
 
 
274
    return contact;
 
275
}