2 * Copyright (C) 2010-2011 David Edmundson.
3 * Author: David Edmundson <kde@davidedmundson.co.uk>
5 * This library is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU Lesser General Public License as published by the Free
7 * Software Foundation; either version 3 of the License, or (at your option) any
8 * later version. See http://www.gnu.org/copyleft/lgpl.html the full text of the
12 #include "usersmodel.h"
18 #include <QtCore/QString>
19 #include <QtCore/QFileSystemWatcher>
20 #include <QtCore/QFile>
21 #include <QtCore/QDir>
22 #include <QtCore/QSettings>
23 #include <QtCore/QDebug>
25 #include <QtGui/QPixmap>
27 using namespace QLightDM;
29 class UsersModelPrivate {
34 UsersModel::UsersModel(QObject *parent) :
35 QAbstractListModel(parent),
36 d (new UsersModelPrivate())
38 //load users on startup and if the password file changes.
39 QFileSystemWatcher *watcher = new QFileSystemWatcher(this);
40 watcher->addPath("/etc/passwd"); //FIXME harcoded path
41 connect(watcher, SIGNAL(fileChanged(QString)), SLOT(loadUsers()));
46 UsersModel::~UsersModel()
52 int UsersModel::rowCount(const QModelIndex &parent) const
54 return d->users.count();
57 QVariant UsersModel::data(const QModelIndex &index, int role) const
59 if (!index.isValid()) {
63 int row = index.row();
66 return d->users[row].displayName();
67 case Qt::DecorationRole:
68 return QPixmap(d->users[row].image());
69 case UsersModel::NameRole:
70 return d->users[row].name();
71 case UsersModel::RealNameRole:
72 return d->users[row].realName();
73 case UsersModel::LoggedInRole:
74 return d->users[row].isLoggedIn();
81 QList<User> UsersModel::getUsers()
83 QString file = "/etc/lightdm/users.conf";
84 qDebug() << "Loading user configuration from " << file;
85 QSettings *settings = new QSettings(file, QSettings::IniFormat);
87 int minimumUid = settings->value("UserAccounts/minimum-uid", QVariant(500)).toInt();
88 QStringList hiddenShells;
89 if (settings->contains("UserAccounts/hidden-shells"))
90 hiddenShells = settings->value("UserAccounts/hidden-shells").toString().split(" ");
92 hiddenShells = QStringList() << "/bin/false" << "/usr/sbin/nologin";
93 QStringList hiddenUsers;
94 if (settings->contains("UserAccounts/hidden-users"))
95 hiddenUsers = settings->value("UserAccounts/hidden-users").toString().split(" ");
97 hiddenUsers = QStringList() << "nobody" << "nobody4" << "noaccess";
104 struct passwd *entry;
106 QString realName, image;
116 /* Ignore system users */
117 if(entry->pw_uid < minimumUid) {
121 /* Ignore users disabled by shell */
122 if(entry->pw_shell) {
123 if (hiddenShells.contains(entry->pw_shell)) {
128 if (hiddenUsers.contains(entry->pw_name)) {
132 tokens = QString(entry->pw_gecos).split(",");
133 if(tokens.size() > 0 && tokens.at(i) != "")
134 realName = tokens.at(i);
136 //replace this with QFile::exists();
137 QDir homeDir(entry->pw_dir);
138 imageFile = new QFile(homeDir.filePath(".face"));
139 if(!imageFile->exists()) {
141 imageFile = new QFile(homeDir.filePath(".face.icon"));
143 if(imageFile->exists())
149 User user(entry->pw_name, realName, entry->pw_dir, imageFile->fileName(), false);
154 qDebug() << "Failed to read password database: " << strerror(errno);
163 void UsersModel::loadUsers()
165 QList<User> usersToAdd;
167 //FIXME accidently not got the "if contact removed" code. Need to restore that.
168 //should call beginRemoveRows, and then remove the row from the model.
169 //might get rid of "User" object, keep as private object (like sessionsmodel) - or make it copyable.
171 //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
172 QList<User> newUserList = getUsers();
174 foreach(const User &user, newUserList) {
175 bool alreadyInList = false;
176 for(int i=0; i < d->users.size(); i++) {
177 if (user.name() == d->users[i].name()) {
178 alreadyInList = true;
179 d->users[i].update(user.name(), user.homeDirectory(), user.image(), user.isLoggedIn());
180 QModelIndex index = createIndex(i,0);
181 dataChanged(index, index);
185 if (!alreadyInList) {
186 usersToAdd.append(user);
190 //loop through all the existing users, if they're not in the newly gathered list, remove them.
192 //FIXME this isn't perfect, looping like this in a mutating list - use mutable iterator.
193 for (int i=0; i < d->users.size() ; i++) {
195 foreach(const User &user, newUserList) {
196 if (d->users[i].name() == user.name()) {
202 beginRemoveRows(QModelIndex(), i, i);
203 d->users.removeAt(i);
209 if (usersToAdd.size() > 0) {
210 beginInsertRows(QModelIndex(), d->users.size(), d->users.size() + usersToAdd.size() -1);
211 d->users.append(usersToAdd);