summaryrefslogtreecommitdiff
path: root/liblightdm-qt/usersmodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'liblightdm-qt/usersmodel.cpp')
-rw-r--r--liblightdm-qt/usersmodel.cpp233
1 files changed, 233 insertions, 0 deletions
diff --git a/liblightdm-qt/usersmodel.cpp b/liblightdm-qt/usersmodel.cpp
new file mode 100644
index 00000000..3fcc73db
--- /dev/null
+++ b/liblightdm-qt/usersmodel.cpp
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2010-2011 David Edmundson.
+ * Author: David Edmundson <kde@davidedmundson.co.uk>
+ *
+ * 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 3 of the License, or (at your option) any
+ * later version. See http://www.gnu.org/copyleft/lgpl.html the full text of the
+ * license.
+ */
+
+#include "QLightDM/usersmodel.h"
+
+#include <pwd.h>
+#include <errno.h>
+
+#include <QtCore/QSharedData>
+#include <QtCore/QString>
+#include <QtCore/QFileSystemWatcher>
+#include <QtCore/QFile>
+#include <QtCore/QDir>
+#include <QtCore/QSettings>
+#include <QtCore/QDebug>
+#include <QtGui/QPixmap>
+
+using namespace QLightDM;
+
+class UserItem
+{
+public:
+ QString name;
+ QString realName;
+ QString homeDirectory;
+ QString image;
+ bool isLoggedIn;
+ QString displayName() const;
+};
+
+QString UserItem::displayName() const {
+ if (realName.isEmpty()){
+ return name;
+ }
+ else {
+ return realName;
+ }
+}
+
+
+class UsersModelPrivate {
+public:
+ QList<UserItem> users;
+};
+
+UsersModel::UsersModel(QObject *parent) :
+ QAbstractListModel(parent),
+ d (new UsersModelPrivate())
+{
+ //load users on startup and if the password file changes.
+ QFileSystemWatcher *watcher = new QFileSystemWatcher(this);
+ watcher->addPath("/etc/passwd"); //FIXME harcoded path
+ connect(watcher, SIGNAL(fileChanged(QString)), SLOT(loadUsers()));
+
+ loadUsers();
+}
+
+UsersModel::~UsersModel()
+{
+ delete d;
+}
+
+
+int UsersModel::rowCount(const QModelIndex &parent) const
+{
+ return d->users.count();
+}
+
+QVariant UsersModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid()) {
+ return QVariant();
+ }
+
+ int row = index.row();
+ switch (role) {
+ case Qt::DisplayRole:
+ return d->users[row].displayName();
+ case Qt::DecorationRole:
+ return QPixmap(d->users[row].image);
+ case UsersModel::NameRole:
+ return d->users[row].name;
+ case UsersModel::RealNameRole:
+ return d->users[row].realName;
+ case UsersModel::LoggedInRole:
+ return d->users[row].isLoggedIn;
+ }
+
+ return QVariant();
+}
+
+
+QList<UserItem> UsersModel::getUsers() const
+{
+ QString file = "/etc/lightdm/users.conf"; //FIXME hardcoded path!!
+
+ qDebug() << "Loading user configuration from " << file;
+ QSettings settings(file, QSettings::IniFormat);
+
+ int minimumUid = settings.value("UserAccounts/minimum-uid", QVariant(500)).toInt();
+ QStringList hiddenShells;
+ if (settings.contains("UserAccounts/hidden-shells")) {
+ hiddenShells = settings.value("UserAccounts/hidden-shells").toString().split(" ");
+ }
+ else {
+ hiddenShells = QStringList() << "/bin/false" << "/usr/sbin/nologin";
+ }
+ QStringList hiddenUsers;
+ if (settings.contains("UserAccounts/hidden-users")) {
+ hiddenUsers = settings.value("UserAccounts/hidden-users").toString().split(" ");
+ }
+ else {
+ hiddenUsers = QStringList() << "nobody" << "nobody4" << "noaccess";
+ }
+ QList<UserItem> users;
+
+ setpwent();
+ Q_FOREVER {
+ errno = 0;
+ struct passwd *entry = getpwent();
+ if(!entry) {
+ break;
+ }
+
+ /* Ignore system users */
+ if(entry->pw_uid < minimumUid) {
+ continue;
+ }
+
+ /* Ignore users disabled by shell */
+ if(entry->pw_shell) {
+ if (hiddenShells.contains(entry->pw_shell)) {
+ continue;
+ }
+ }
+
+ if (hiddenUsers.contains(entry->pw_name)) {
+ continue;
+ }
+
+ QStringList tokens = QString(entry->pw_gecos).split(",");
+ QString realName;
+ if(tokens.size() > 0 && tokens.at(0) != "") {
+ realName = tokens.at(0);
+ }
+
+ QDir homeDir(entry->pw_dir);
+ QString image = homeDir.filePath(".face");
+ if(!QFile::exists (image)) {
+ image = homeDir.filePath(".face.icon");
+ if(!QFile::exists (image)) {
+ image = "";
+ }
+ }
+
+ UserItem user;
+ user.name = entry->pw_name;
+ user.realName = realName;
+ user.homeDirectory = entry->pw_dir;
+ user.image = image;
+ user.isLoggedIn = false;
+ users.append(user);
+ }
+
+ if(errno != 0) {
+ qDebug() << "Failed to read password database: " << strerror(errno);
+ }
+ endpwent();
+
+
+ return users;
+}
+
+void UsersModel::loadUsers()
+{
+ QList<UserItem> usersToAdd;
+
+ //might get rid of "User" object, keep as private object (like sessionsmodel) - or make it copyable.
+
+ //loop through all the new list of users, if it's in the list already update it (or do nothing) otherwise append to list of new users
+ QList<UserItem> newUserList = getUsers();
+
+ Q_FOREACH(const UserItem &user, newUserList) {
+ bool alreadyInList = false;
+ for(int i=0; i < d->users.size(); i++) {
+ if (user.name == d->users[i].name) {
+ alreadyInList = true;
+// d->users[i].update(user.name(), user.homeDirectory(), user.image(), user.isLoggedIn());
+ QModelIndex index = createIndex(i,0);
+ dataChanged(index, index);
+ }
+ }
+
+ if (!alreadyInList) {
+ usersToAdd.append(user);
+ }
+ }
+
+ //loop through all the existing users, if they're not in the newly gathered list, remove them.
+
+ //FIXME this isn't perfect, looping like this in a mutating list - use mutable iterator.
+ for (int i=0; i < d->users.size() ; i++) {
+ bool found = false;
+ foreach(const UserItem &user, newUserList) {
+ if (d->users[i].name == user.name) {
+ found = true;
+ }
+ }
+
+ if (!found) {
+ beginRemoveRows(QModelIndex(), i, i);
+ d->users.removeAt(i);
+ endRemoveRows();
+ }
+ }
+
+ //append new users
+ if (usersToAdd.size() > 0) {
+ beginInsertRows(QModelIndex(), d->users.size(), d->users.size() + usersToAdd.size() -1);
+ d->users.append(usersToAdd);
+ endInsertRows();
+ }
+}
+
+#include "usersmodel_moc.cpp"