Skip to content

Commit

Permalink
Merge branch 'jb49173_user_model' into 'master'
Browse files Browse the repository at this point in the history
Add model to access user info

See merge request mer-core/nemo-qml-plugin-systemsettings!134
  • Loading branch information
Tomin1 committed Mar 23, 2020
2 parents 26cc3ae + 6eab714 commit 9fbdef7
Show file tree
Hide file tree
Showing 10 changed files with 933 additions and 4 deletions.
3 changes: 3 additions & 0 deletions rpm/nemo-qml-plugin-systemsettings.spec
Expand Up @@ -12,6 +12,7 @@ Requires: connman
Requires: mce >= 1.83.0
Requires: libsailfishkeyprovider >= 0.0.14
Requires: connman-qt5 >= 1.2.21
Requires: user-managerd
Requires(post): coreutils
BuildRequires: pkgconfig(Qt5Qml)
BuildRequires: pkgconfig(Qt5SystemInfo)
Expand All @@ -32,6 +33,8 @@ BuildRequires: pkgconfig(ssu-sysinfo) >= 1.1.0
BuildRequires: pkgconfig(packagekitqt5)
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(sailfishaccesscontrol)
BuildRequires: pkgconfig(libsystemd)
BuildRequires: pkgconfig(sailfishusermanager)

%description
%{summary}.
Expand Down
1 change: 1 addition & 0 deletions src/logging.cpp
Expand Up @@ -34,3 +34,4 @@
Q_LOGGING_CATEGORY(lcVpnLog, "org.sailfishos.settings.vpn", QtWarningMsg)
Q_LOGGING_CATEGORY(lcDeveloperModeLog, "org.sailfishos.settings.developermode", QtWarningMsg)
Q_LOGGING_CATEGORY(lcMemoryCardLog, "org.sailfishos.settings.memorycard", QtWarningMsg)
Q_LOGGING_CATEGORY(lcUsersLog, "org.sailfishos.settings.users", QtWarningMsg)
1 change: 1 addition & 0 deletions src/logging_p.h
Expand Up @@ -37,5 +37,6 @@
Q_DECLARE_LOGGING_CATEGORY(lcVpnLog)
Q_DECLARE_LOGGING_CATEGORY(lcDeveloperModeLog)
Q_DECLARE_LOGGING_CATEGORY(lcMemoryCardLog)
Q_DECLARE_LOGGING_CATEGORY(lcUsersLog)

#endif
4 changes: 4 additions & 0 deletions src/plugin/plugin.cpp
Expand Up @@ -51,6 +51,8 @@
#include "locationsettings.h"
#include "deviceinfo.h"
#include "nfcsettings.h"
#include "userinfo.h"
#include "usermodel.h"

template<class T>
static QObject *api_factory(QQmlEngine *, QJSEngine *)
Expand Down Expand Up @@ -91,6 +93,8 @@ class SystemSettingsPlugin : public QQmlExtensionPlugin
qmlRegisterType<LocationSettings>(uri, 1, 0, "LocationSettings");
qmlRegisterType<DeviceInfo>(uri, 1, 0, "DeviceInfo");
qmlRegisterType<NfcSettings>(uri, 1, 0, "NfcSettings");
qmlRegisterType<UserInfo>(uri, 1, 0, "UserInfo");
qmlRegisterType<UserModel>(uri, 1, 0, "UserModel");
}
};

Expand Down
13 changes: 9 additions & 4 deletions src/src.pro
Expand Up @@ -7,7 +7,7 @@ QT -= gui

CONFIG += c++11 hide_symbols link_pkgconfig
PKGCONFIG += profile mlite5 mce timed-qt5 libshadowutils blkid libcrypto nemomodels-qt5 libsailfishkeyprovider connman-qt5 glib-2.0
PKGCONFIG += ssu-sysinfo nemodbus packagekitqt5
PKGCONFIG += ssu-sysinfo nemodbus packagekitqt5 libsystemd sailfishusermanager

system(qdbusxml2cpp -p mceiface.h:mceiface.cpp mce.xml)

Expand Down Expand Up @@ -37,7 +37,9 @@ SOURCES += \
udisks2block.cpp \
udisks2blockdevices.cpp \
udisks2job.cpp \
udisks2monitor.cpp
udisks2monitor.cpp \
userinfo.cpp \
usermodel.cpp

PUBLIC_HEADERS = \
languagemodel.h \
Expand All @@ -60,7 +62,9 @@ PUBLIC_HEADERS = \
systemsettingsglobal.h \
deviceinfo.h \
locationsettings.h \
timezoneinfo.h
timezoneinfo.h \
userinfo.h \
usermodel.h

HEADERS += \
$$PUBLIC_HEADERS \
Expand All @@ -76,7 +80,8 @@ HEADERS += \
partitionmanager_p.h \
udisks2blockdevices_p.h \
udisks2job_p.h \
udisks2monitor_p.h
udisks2monitor_p.h \
userinfo_p.h

DEFINES += \
SYSTEMSETTINGS_BUILD_LIBRARY
Expand Down
289 changes: 289 additions & 0 deletions src/userinfo.cpp
@@ -0,0 +1,289 @@
/*
* Copyright (C) 2020 Open Mobile Platform LLC.
*
* You may use this file under the terms of the BSD license as follows:
*
* "Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Nemo Mobile nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
*/

#include "userinfo.h"
#include "userinfo_p.h"

#include <pwd.h>
#include <sys/types.h>
#include <systemd/sd-login.h>

namespace {

enum SpecialIds : uid_t {
DeviceOwnerId = 100000,
InvalidId = (uid_t)(-1),
};

QString nameFromGecos(const char *gecos)
{
// typically GECOS has (sub)fields separated by ","
// and the first one of them is full name of the user.
// Sometimes it contains just the full name or it might be empty,
// thus do this on best effort basis.
auto name = QString::fromUtf8(gecos);
int i = name.indexOf(QStringLiteral(","));
if (i != -1)
name.truncate(i);
return name;
}

}

UserInfoPrivate::UserInfoPrivate()
: m_uid(InvalidId)
, m_loggedIn(false)
{
}

UserInfoPrivate::UserInfoPrivate(struct passwd *pwd)
: m_uid(pwd->pw_uid)
, m_username(QString::fromUtf8(pwd->pw_name))
, m_name(nameFromGecos(pwd->pw_gecos))
// require_active == false -> both online and active are logged in.
// Specifying seat should make sure that remote users are not
// counted as they don't have seats.
, m_loggedIn(sd_uid_is_on_seat(m_uid, 0, "seat0") > 0)
{
}

UserInfoPrivate::~UserInfoPrivate()
{
}

QWeakPointer<UserInfoPrivate> UserInfoPrivate::s_current;

void UserInfoPrivate::set(struct passwd *pwd)
{
QString username;
QString name;

if (pwd) {
Q_ASSERT(pwd->pw_uid == m_uid);
username = QString::fromUtf8(pwd->pw_name);
name = nameFromGecos(pwd->pw_gecos);
} else if (m_uid != InvalidId) {
m_uid = InvalidId;
emit uidChanged();
}

if (m_username != username) {
m_username = username;
emit usernameChanged();
}

if (m_name != name) {
m_name = name;
emit nameChanged();
}
}

/**
* Construct UserInfo for the current user
*
* If it has been constructed before, this reuses the old data.
*/
UserInfo::UserInfo()
{
if (!UserInfoPrivate::s_current.isNull()) {
d_ptr = QSharedPointer<UserInfoPrivate>(UserInfoPrivate::s_current);
}
if (d_ptr.isNull()) {
uid_t uid = InvalidId;
struct passwd *pwd;
if (sd_seat_get_active("seat0", NULL, &uid) < 0 || uid == InvalidId || !(pwd = getpwuid(uid))) {
d_ptr = QSharedPointer<UserInfoPrivate>(new UserInfoPrivate);
} else {
d_ptr = QSharedPointer<UserInfoPrivate>(new UserInfoPrivate(pwd));
}
// pwd must not be free'd
}
if (current())
UserInfoPrivate::s_current = d_ptr;
connectSignals();
}

UserInfo::UserInfo(const UserInfo &other)
: QObject(other.parent())
, d_ptr(other.d_ptr)
{
connectSignals();
}

/**
* Construct UserInfo by uid
*/
UserInfo::UserInfo(int uid)
{
struct passwd *pwd = (uid_t)uid != InvalidId ? getpwuid((uid_t)uid) : nullptr;
if (pwd) {
d_ptr = QSharedPointer<UserInfoPrivate>(new UserInfoPrivate(pwd));
} else {
d_ptr = QSharedPointer<UserInfoPrivate>(new UserInfoPrivate);
}
// pwd must not be free'd
if (current())
UserInfoPrivate::s_current = d_ptr;
connectSignals();
}

/**
* Construct UserInfo by username
*/
UserInfo::UserInfo(QString username)
{
struct passwd *pwd = getpwnam(username.toUtf8().constData());
if (pwd) {
d_ptr = QSharedPointer<UserInfoPrivate>(new UserInfoPrivate(pwd));
} else {
d_ptr = QSharedPointer<UserInfoPrivate>(new UserInfoPrivate);
}
// pwd must not be free'd
if (current())
UserInfoPrivate::s_current = d_ptr;
connectSignals();
}

/**
* Construct a placeholder user that doesn't exist
*
* Placeholder users are always invalid.
*/
UserInfo UserInfo::placeholder()
{
return UserInfo(InvalidId);
}

UserInfo::~UserInfo()
{
}

/**
* Returns true if user exists
*/
bool UserInfo::isValid() const
{
Q_D(const UserInfo);
return d->m_uid != InvalidId;
}

QString UserInfo::username() const
{
Q_D(const UserInfo);
return d->m_username;
}

void UserInfo::setUsername(QString username)
{
Q_D(UserInfo);
if (d->m_username != username) {
d->m_username = username;
emit d_ptr->usernameChanged();
}
}

QString UserInfo::name() const
{
Q_D(const UserInfo);
return d->m_name;
}

void UserInfo::setName(QString name)
{
Q_D(UserInfo);
if (d->m_name != name) {
d->m_name = name;
emit d_ptr->nameChanged();
}
}

UserInfo::UserType UserInfo::type() const
{
Q_D(const UserInfo);
// Device lock considers user with id 100000 as device owner.
// Some other places consider the user belonging to sailfish-system
// as device owner. We have to pick one here.
return (d->m_uid == DeviceOwnerId) ? DeviceOwner : User;
}

int UserInfo::uid() const
{
Q_D(const UserInfo);
return (int)d->m_uid;
}

/**
* Returs true if user is logged in on seat0 and is the active user, i.e. the current user
*/
bool UserInfo::current() const
{
Q_D(const UserInfo);
// Any logged in user (on seat0) must be the current one
// since we don't have multisession.
return d->m_loggedIn;
}

void UserInfo::reset()
{
Q_D(UserInfo);
d->set((isValid()) ? getpwuid(d->m_uid) : nullptr);
}

UserInfo &UserInfo::operator=(const UserInfo &other)
{
if (this == &other)
return *this;

d_ptr = other.d_ptr;

return *this;
}

bool UserInfo::operator==(const UserInfo &other) const
{
if (!isValid())
return false;
return d_ptr == other.d_ptr;
}

bool UserInfo::operator!=(const UserInfo &other) const
{
if (!isValid())
return true;
return d_ptr != other.d_ptr;
}

void UserInfo::connectSignals()
{
connect(d_ptr.data(), &UserInfoPrivate::usernameChanged, this, &UserInfo::usernameChanged);
connect(d_ptr.data(), &UserInfoPrivate::nameChanged, this, &UserInfo::nameChanged);
connect(d_ptr.data(), &UserInfoPrivate::uidChanged, this, &UserInfo::uidChanged);
}

0 comments on commit 9fbdef7

Please sign in to comment.