diff --git a/src/accountinfo.cpp b/src/accountinfo.cpp index c2ae62d..5949fc7 100644 --- a/src/accountinfo.cpp +++ b/src/accountinfo.cpp @@ -1,462 +1,472 @@ /************************************************************************************* * Copyright (C) 2013 by Alejandro Fiestas Olivares * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * *************************************************************************************/ #include "accountinfo.h" #include "ui_account.h" #include "createavatarjob.h" #include "passworddialog.h" #include "lib/accountmodel.h" #include "passwordedit.h" #include "avatargallery.h" #include #include #include #include #include "user_manager_debug.h" #include #include #include #include #include #include #include #include #include AccountInfo::AccountInfo(AccountModel* model, QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f) , m_info(new Ui::AccountInfo()) , m_model(model) , m_passwordEdit(new PasswordEdit(this)) { m_info->setupUi(this); //If I remove this from the .ui file the layouting gets screwed... m_info->formLayout->removeWidget(m_info->passwordEdit); delete m_info->passwordEdit; connect(m_info->username, SIGNAL(textEdited(QString)), SLOT(hasChanged())); connect(m_info->realName, SIGNAL(textEdited(QString)), SLOT(hasChanged())); connect(m_info->email, SIGNAL(textEdited(QString)), SLOT(hasChanged())); connect(m_info->administrator, SIGNAL(clicked(bool)), SLOT(hasChanged())); connect(m_info->automaticLogin, SIGNAL(clicked(bool)), SLOT(hasChanged())); connect(m_passwordEdit, SIGNAL(focused()), SLOT(changePassword())); connect(m_passwordEdit, SIGNAL(textEdited(QString)), SLOT(changePassword())); connect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(dataChanged(QModelIndex))); m_info->face->setPopupMode(QToolButton::InstantPopup); QMenu* menu = new QMenu(this); QAction *gallery = new QAction(i18n("Choose from Gallery..."), this); gallery->setIcon(QIcon::fromTheme(QLatin1String("shape-choose"))); // TODO proper icon connect(gallery, &QAction::triggered, this, &AccountInfo::openGallery); QAction *openAvatar = new QAction(i18n("Load from file..."), this); openAvatar->setIcon(QIcon::fromTheme(QLatin1String("document-open-folder"))); connect(openAvatar, SIGNAL(triggered(bool)), SLOT(openAvatarSlot())); QAction *editClear = new QAction(i18n("Clear Avatar"), this); editClear->setIcon(QIcon::fromTheme(QLatin1String("edit-clear"))); connect(editClear, SIGNAL(triggered(bool)), SLOT(clearAvatar())); menu->addAction(gallery); menu->addAction(openAvatar); menu->addAction(editClear); int iconSizeX = IconSize(KIconLoader::Dialog); QSize iconSize(iconSizeX, iconSizeX); m_info->face->setIconSize(iconSize); m_info->face->setMinimumSize(iconSize); m_info->face->setMenu(menu); int size = QFontMetrics(QFontDatabase::systemFont(QFontDatabase::FixedFont)).xHeight() * 29; m_info->username->setMinimumWidth(size); m_info->realName->setMinimumWidth(size); m_info->email->setMinimumWidth(size); QWidget::setTabOrder(m_info->email, m_passwordEdit); QWidget::setTabOrder(m_passwordEdit, m_info->administrator); m_passwordEdit->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); m_passwordEdit->setMinimumWidth(size); m_passwordEdit->setEchoMode(QLineEdit::Password); int row; QFormLayout::ItemRole role; m_info->formLayout->getWidgetPosition(m_info->label_2, &row, &role); m_info->formLayout->insertRow(row, m_info->label_3, m_passwordEdit); int pixmapSize = m_info->username->sizeHint().height(); m_negative = QIcon::fromTheme("dialog-cancel").pixmap(pixmapSize, pixmapSize); } AccountInfo::~AccountInfo() { delete m_info; } void AccountInfo::setModelIndex(const QModelIndex& index) { if (!index.isValid() || m_index == index) { return; } m_index = index; m_infoToSave.clear(); loadFromModel(); } QModelIndex AccountInfo::modelIndex() const { return m_index; } void AccountInfo::loadFromModel() { QString username = m_model->data(m_index, AccountModel::Username).toString(); if (!username.isEmpty()) { m_info->username->setDisabled(true);//Do not allow to change the username } else { m_info->username->setDisabled(false); } m_info->username->setText(username); m_info->face->setIcon(QIcon(m_model->data(m_index, AccountModel::Face).value())); m_info->realName->setText(m_model->data(m_index, AccountModel::RealName).toString()); m_info->email->setText(m_model->data(m_index, AccountModel::Email).toString()); m_info->administrator->setChecked(m_model->data(m_index, AccountModel::Administrator).toBool()); m_info->automaticLogin->setChecked(m_model->data(m_index, AccountModel::AutomaticLogin).toBool()); m_passwordEdit->clear(); } bool AccountInfo::save() { if (m_infoToSave.isEmpty()) { return false; } qCDebug(USER_MANAGER_LOG) << "Saving on Index: " << m_index.row(); QList failed; - if (!m_model->setData(m_index, m_info->username->text(), AccountModel::Username)) { - failed.append(AccountModel::Username); + if (m_infoToSave.contains(AccountModel::Username)) { + if (!m_model->setData(m_index, m_info->username->text(), AccountModel::Username)) { + failed.append(AccountModel::Username); + } } - if (!m_model->setData(m_index, m_info->realName->text(), AccountModel::RealName)) { - failed.append(AccountModel::RealName); + if (m_infoToSave.contains(AccountModel::RealName)) { + if (!m_model->setData(m_index, m_info->realName->text(), AccountModel::RealName)) { + failed.append(AccountModel::RealName); + } } - if (!m_model->setData(m_index, m_info->email->text(), AccountModel::Email)) { - failed.append(AccountModel::Email); + if (m_infoToSave.contains(AccountModel::Email)) { + if (!m_model->setData(m_index, m_info->email->text(), AccountModel::Email)) { + failed.append(AccountModel::Email); + } } - if (!m_model->setData(m_index, m_info->administrator->isChecked(), AccountModel::Administrator)) { - failed.append(AccountModel::Administrator); + if (m_infoToSave.contains(AccountModel::Administrator)) { + if (!m_model->setData(m_index, m_info->administrator->isChecked(), AccountModel::Administrator)) { + failed.append(AccountModel::Administrator); + } } - if (!m_model->setData(m_index, m_info->automaticLogin->isChecked(), AccountModel::AutomaticLogin)) { - failed.append(AccountModel::AutomaticLogin); + if (m_infoToSave.contains(AccountModel::AutomaticLogin)) { + if (!m_model->setData(m_index, m_info->automaticLogin->isChecked(), AccountModel::AutomaticLogin)) { + failed.append(AccountModel::AutomaticLogin); + } } if (m_infoToSave.contains(AccountModel::Password)) { if (!m_model->setData(m_index, m_infoToSave[AccountModel::Password], AccountModel::Password)) { failed.append(AccountModel::Password); } } if (m_infoToSave.contains(AccountModel::Face)) { const QString path = m_infoToSave[AccountModel::Face].toString(); QString faceFile = QDesktopServices::storageLocation(QDesktopServices::HomeLocation); faceFile.append(QLatin1String("/.face")); QFile::remove(faceFile); KIO::CopyJob* moveJob = KIO::move(QUrl::fromLocalFile(path), QUrl::fromLocalFile(faceFile), KIO::HideProgressInfo); connect(moveJob, SIGNAL(finished(KJob*)), SLOT(avatarModelChanged(KJob*))); moveJob->setUiDelegate(0); moveJob->start(); QString faceFile2 = QDesktopServices::storageLocation(QDesktopServices::HomeLocation); faceFile2.append(QLatin1String("/.face.icon")); QFile::remove(faceFile2); QFile::link(faceFile, faceFile2); } if (!failed.isEmpty()) { qCDebug(USER_MANAGER_LOG) << "Failed Roles: " << failed; } m_info->username->setEnabled(false); m_infoToSave.clear(); return true; } void AccountInfo::hasChanged() { m_info->nameValidation->setPixmap(m_positive); m_info->usernameValidation->setPixmap(m_positive); m_info->emailValidation->setPixmap(m_positive); QMap infoToSave; const QString name = cleanName(m_info->realName->text()); if (name != m_model->data(m_index, AccountModel::RealName).toString()) { if (validateName(name)) { infoToSave.insert(AccountModel::RealName, name); } } const QString username = cleanUsername(m_info->username->text()); if (username != m_model->data(m_index, AccountModel::Username).toString()) { if (validateUsername(username)) { infoToSave.insert(AccountModel::Username, username); } } const QString email = cleanEmail(m_info->email->text()); if (email != m_model->data(m_index, AccountModel::Email).toString()) { if (validateEmail(email)) { infoToSave.insert(AccountModel::Email, email); } } if (m_info->administrator->isChecked() != m_model->data(m_index, AccountModel::Administrator).toBool()) { infoToSave.insert(AccountModel::Administrator, m_info->administrator->isChecked()); } if (m_info->automaticLogin->isChecked() != m_model->data(m_index, AccountModel::AutomaticLogin).toBool()) { infoToSave.insert(AccountModel::AutomaticLogin, m_info->automaticLogin->isChecked()); } if (m_infoToSave.contains(AccountModel::Face)) { infoToSave[AccountModel::Face] = m_infoToSave[AccountModel::Face]; } if (m_infoToSave.contains(AccountModel::Password)) { infoToSave[AccountModel::Password] = m_infoToSave[AccountModel::Password]; } m_infoToSave = infoToSave; Q_EMIT changed(!m_infoToSave.isEmpty()); } QString AccountInfo::cleanName(QString name) const { return name; } bool AccountInfo::validateName(const QString& name) const { if (!name.isEmpty() && name.trimmed().isEmpty()) { m_info->realName->clear(); return false; } return true; } QString AccountInfo::cleanUsername(QString username) { if (username.isEmpty()) { return username; } if (username[0].isUpper()) { username[0] = username[0].toLower(); } username.remove(' '); m_info->username->setText(username); return username; } bool AccountInfo::validateUsername(QString username) const { if (username.isEmpty()) { return false; } QByteArray userchar = username.toUtf8(); if (getpwnam(userchar) != NULL) { m_info->usernameValidation->setPixmap(m_negative); m_info->usernameValidation->setToolTip(i18n("This username is already used")); return false; } QString errorTooltip; char first = userchar.at(0); bool valid = (first >= 'a' && first <= 'z'); if (!valid) { errorTooltip.append(i18n("The username must start with a letter")); errorTooltip.append("\n"); } Q_FOREACH(const char c, userchar) { valid = ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '_') || (c == '.') || (c == '-') ); if (!valid) { break; } } if (!valid) { errorTooltip.append(i18n("The username can contain only letters, numbers, score, underscore and dot")); errorTooltip.append("\n"); } static const long MAX_USER_NAME_LENGTH = []() { long result = sysconf(_SC_LOGIN_NAME_MAX); if (result < 0) { qWarning("Could not query LOGIN_NAME_MAX, defaulting to 32"); result = 32; } return result; }(); if (username.size() > MAX_USER_NAME_LENGTH) { errorTooltip.append(i18n("The username is too long")); valid = false; } if (!errorTooltip.isEmpty()) { m_info->usernameValidation->setPixmap(m_negative); m_info->usernameValidation->setToolTip(errorTooltip); return false; } return true; } QString AccountInfo::cleanEmail(QString email) { if (email.isEmpty()) { return email; } email = email.toLower().remove(' '); int pos = m_info->email->cursorPosition(); m_info->email->setText(email); m_info->email->setCursorPosition(pos); return email; } bool AccountInfo::validateEmail(const QString& email) const { if (email.isEmpty()) { return false; } QString strPatt = "\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,63}\\b"; QRegExp rx(strPatt); rx.setCaseSensitivity(Qt::CaseInsensitive); rx.setPatternSyntax(QRegExp::RegExp); if (!rx.exactMatch(email)) { m_info->emailValidation->setPixmap(m_negative); m_info->emailValidation->setToolTip(i18n("This e-mail address is incorrect")); } return true; } void AccountInfo::dataChanged(const QModelIndex& index) { if (m_index != index) { return; } //If we have no username, we assume this was user-new if (m_info->username->text().isEmpty()) { loadFromModel(); return; } hasChanged(); } void AccountInfo::openGallery() { QScopedPointer gallery(new AvatarGallery()); if (gallery->exec() != QDialog::Accepted) { return; } CreateAvatarJob *job = new CreateAvatarJob(this); connect(job, &KJob::finished, this, &AccountInfo::avatarCreated); job->setUrl(gallery->url()); job->start(); } void AccountInfo::openAvatarSlot() { KFileDialog dlg(QUrl::fromLocalFile(QDir::homePath()), KImageIO::pattern(KImageIO::Reading), this); dlg.setOperationMode(KFileDialog::Opening); dlg.setWindowTitle(i18nc("@title:window", "Choose Image")); dlg.setMode(KFile::File); KImageFilePreview *imagePreviewer = new KImageFilePreview(&dlg); dlg.setPreviewWidget(imagePreviewer); if (dlg.exec() != QDialog::Accepted) { return; } QUrl url = QUrl::fromLocalFile(dlg.selectedFile()); CreateAvatarJob *job = new CreateAvatarJob(this); connect(job, SIGNAL(finished(KJob*)), SLOT(avatarCreated(KJob*))); job->setUrl(url); job->start(); } void AccountInfo::avatarCreated(KJob* job) { qCDebug(USER_MANAGER_LOG) << "Avatar created"; CreateAvatarJob *aJob = qobject_cast(job); m_info->face->setIcon(QIcon(aJob->avatarPath())); m_infoToSave.insert(AccountModel::Face, aJob->avatarPath()); Q_EMIT changed(true); } void AccountInfo::avatarModelChanged(KJob* job) { KIO::CopyJob* cJob = qobject_cast(job); m_model->setData(m_index, QVariant(cJob->destUrl().path()), AccountModel::Face); m_info->face->setIcon(QIcon(m_model->data(m_index, AccountModel::Face).value())); } void AccountInfo::clearAvatar() { QSize icon(IconSize(KIconLoader::Dialog), IconSize(KIconLoader::Dialog)); m_info->face->setIcon(QIcon::fromTheme("user-identity").pixmap(48, 48)); m_infoToSave.insert(AccountModel::Face, QString()); Q_EMIT changed(true); } void AccountInfo::changePassword() { QScopedPointer dialog(new PasswordDialog(this)); dialog->setUsername(m_model->data(m_index, AccountModel::Username).toByteArray()); dialog->setModal(true); if (!dialog->exec()) { return; } m_infoToSave[AccountModel::Password] = dialog->password(); m_passwordEdit->setText(dialog->password()); Q_EMIT changed(true); } diff --git a/src/lib/accountmodel.cpp b/src/lib/accountmodel.cpp index 10a7301..50006c8 100644 --- a/src/lib/accountmodel.cpp +++ b/src/lib/accountmodel.cpp @@ -1,474 +1,472 @@ /************************************************************************************* * Copyright (C) 2012 by Alejandro Fiestas Olivares * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * *************************************************************************************/ #include "accountmodel.h" #include "usersessions.h" #include "accounts_interface.h" #include "user_interface.h" #include #include "user_manager_debug.h" #include #include #include #include typedef OrgFreedesktopAccountsInterface AccountsManager; typedef OrgFreedesktopAccountsUserInterface Account; AccountModel::AccountModel(QObject* parent) : QAbstractListModel(parent) , m_sessions(new UserSession(this)) { m_dbus = new AccountsManager("org.freedesktop.Accounts", "/org/freedesktop/Accounts", QDBusConnection::systemBus(), this); QDBusPendingReply > reply = m_dbus->ListCachedUsers(); reply.waitForFinished(); if (reply.isError()) { qCDebug(USER_MANAGER_LOG) << reply.error().message(); return; } QList users = reply.value(); Q_FOREACH(const QDBusObjectPath& path, users) { addAccount(path.path()); } //Adding fake "new user" directly into cache addAccountToCache("new-user", 0); m_kEmailSettings.setProfile(m_kEmailSettings.defaultProfileName()); connect(m_dbus, SIGNAL(UserAdded(QDBusObjectPath)), SLOT(UserAdded(QDBusObjectPath))); connect(m_dbus, SIGNAL(UserDeleted(QDBusObjectPath)), SLOT(UserDeleted(QDBusObjectPath))); connect(m_sessions, SIGNAL(userLogged(uint, bool)), SLOT(userLogged(uint, bool))); } AccountModel::~AccountModel() { delete m_dbus; qDeleteAll(m_users); } int AccountModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) { return 0; } return m_userPath.count(); } QVariant AccountModel::data(const QModelIndex& index, int role) const { if(!index.isValid()) { return QVariant(); } if (index.row() >= m_users.count()) { return QVariant(); } QString path = m_userPath.at(index.row()); Account* acc = m_users.value(path); if (!acc) { //new user return newUserData(role); } switch(role) { case Qt::DisplayRole || AccountModel::FriendlyName: if (!acc->realName().isEmpty()) { return acc->realName(); } return acc->userName(); case Qt::DecorationRole || AccountModel::Face: { QFile file(acc->iconFile()); int size = IconSize(KIconLoader::Dialog); if (!file.exists()) { return QIcon::fromTheme("user-identity").pixmap(size, size); } return QPixmap(file.fileName()).scaled(size, size); } case AccountModel::RealName: return acc->realName(); case AccountModel::Username: return acc->userName(); case AccountModel::Email: return acc->email(); case AccountModel::Administrator: return acc->accountType() == 1; case AccountModel::AutomaticLogin: return acc->automaticLogin(); case AccountModel::Logged: if (m_loggedAccounts.contains(path)) { return m_loggedAccounts[path]; } return QVariant(); case AccountModel::Created: return true; } return QVariant(); } bool AccountModel::setData(const QModelIndex& index, const QVariant& value, int role) { if(!index.isValid()) { return false; } if (index.row() >= m_users.count()) { return false; } QString path = m_userPath.at(index.row()); Account* acc = m_users.value(path); if (!acc) { return newUserSetData(index, value, role); } switch(role) { //The modification of the face file should be done outside case AccountModel::Face: if (checkForErrors(acc->SetIconFile(value.toString()))) { return false; } emit dataChanged(index, index); return true; case AccountModel::RealName: if (checkForErrors(acc->SetRealName(value.toString()))) { return false; } m_kEmailSettings.setSetting(KEMailSettings::RealName, value.toString()); - m_dbus->UncacheUser(acc->userName()).waitForFinished(); - m_dbus->CacheUser(acc->userName()); emit dataChanged(index, index); return true; case AccountModel::Username: if (checkForErrors(acc->SetUserName(value.toString()))) { return false; } emit dataChanged(index, index); return true; case AccountModel::Password: if (checkForErrors(acc->SetPassword(cryptPassword(value.toString()), QString()))) { return false; } emit dataChanged(index, index); return true; case AccountModel::Email: if (checkForErrors(acc->SetEmail(value.toString()))) { return false; } m_kEmailSettings.setSetting(KEMailSettings::EmailAddress, value.toString()); emit dataChanged(index, index); return true; case AccountModel::Administrator: if (checkForErrors(acc->SetAccountType(value.toBool() ? 1 : 0))) { return false; } emit dataChanged(index, index); return true; case AccountModel::AutomaticLogin: if (checkForErrors(acc->SetAutomaticLogin(value.toBool()))) { return false; } emit dataChanged(index, index); return true; case AccountModel::Logged: m_loggedAccounts[path] = value.toBool(); emit dataChanged(index, index); return true; case AccountModel::Created: qFatal("AccountModel NewAccount should never be set"); return false; } return QAbstractItemModel::setData(index, value, role); } bool AccountModel::removeRows(int row, int count, const QModelIndex& parent) { Q_UNUSED(count); Q_UNUSED(parent); return removeAccountKeepingFiles(row, true); } bool AccountModel::removeAccountKeepingFiles(int row, bool keepFile) { Account* acc = m_users.value(m_userPath.at(row)); QDBusPendingReply rep = m_dbus->DeleteUser(acc->uid(), keepFile); rep.waitForFinished(); return !rep.isError(); } QVariant AccountModel::newUserData(int role) const { switch(role) { case Qt::DisplayRole || AccountModel::FriendlyName: return i18n("New User"); case Qt::DecorationRole || AccountModel::Face: return QIcon::fromTheme("list-add-user").pixmap(IconSize(KIconLoader::Dialog), IconSize(KIconLoader::Dialog)); case AccountModel::Created: return false; } return QVariant(); } bool AccountModel::newUserSetData(const QModelIndex &index, const QVariant& value, int roleInt) { AccountModel::Role role = (AccountModel::Role) roleInt; m_newUserData[role] = value; QList roles = m_newUserData.keys(); if (!roles.contains(Username) || !roles.contains(RealName) || !roles.contains(Administrator)) { return true; } int userType = m_newUserData[Administrator].toBool() ? 1 : 0; QDBusPendingReply reply = m_dbus->CreateUser(m_newUserData[Username].toString(), m_newUserData[RealName].toString(), userType); reply.waitForFinished(); if (reply.isError()) { qCDebug(USER_MANAGER_LOG) << reply.error().name(); qCDebug(USER_MANAGER_LOG) << reply.error().message(); m_newUserData.clear(); return false; } m_newUserData.remove(Username); m_newUserData.remove(RealName); m_newUserData.remove(Administrator); //If we don't have anything else to set just return if (m_newUserData.isEmpty()) { return true; } UserAdded(reply.value()); QHash::const_iterator i = m_newUserData.constBegin(); while (i != m_newUserData.constEnd()) { qCDebug(USER_MANAGER_LOG) << "Setting extra:" << i.key() << "with value:" << i.value(); setData(index, i.value(), i.key()); ++i; } m_newUserData.clear(); return true; } void AccountModel::addAccount(const QString& path) { Account *acc = new Account("org.freedesktop.Accounts", path, QDBusConnection::systemBus(), this); qulonglong uid = acc->uid(); if (!acc->isValid() || acc->lastError().isValid() || acc->systemAccount()) { return; } connect(acc, SIGNAL(Changed()), SLOT(Changed())); if (uid == getuid()) { addAccountToCache(path, acc, 0); return; } addAccountToCache(path, acc); } void AccountModel::addAccountToCache(const QString& path, Account* acc, int pos) { if (pos > -1) { if (m_userPath.count() > 0) { m_userPath.replace(pos, path); } else { m_userPath.insert(pos, path); } } else { m_userPath.append(path); } m_users.insert(path, acc); m_loggedAccounts[path] = false; } void AccountModel::removeAccount(const QString& path) { m_userPath.removeAll(path); delete m_users.take(path); m_loggedAccounts.remove(path); } bool AccountModel::checkForErrors(QDBusPendingReply reply) const { reply.waitForFinished(); if (reply.isError()) { qCDebug(USER_MANAGER_LOG) << reply.error().name(); qCDebug(USER_MANAGER_LOG) << reply.error().message(); return true; } return false; } QVariant AccountModel::headerData(int section, Qt::Orientation orientation, int role) const { Q_UNUSED(section); if (role != Qt::DisplayRole) { return QVariant(); } if (orientation == Qt::Vertical) { return QVariant(); } return i18n("Users"); } void AccountModel::UserAdded(const QDBusObjectPath& dbusPath) { QString path = dbusPath.path(); if (m_userPath.contains(path)) { qCDebug(USER_MANAGER_LOG) << "We already have:" << path; return; } Account* acc = new Account("org.freedesktop.Accounts", path, QDBusConnection::systemBus(), this); if (acc->systemAccount()) { return; } connect(acc, SIGNAL(Changed()), SLOT(Changed())); //First, we modify "new-user" to become the new created user int row = rowCount(); addAccountToCache(path, acc, row - 1); QModelIndex changedIndex = index(row - 1, 0); emit dataChanged(changedIndex, changedIndex); //Then we add new-user again. beginInsertRows(QModelIndex(), row, row); addAccountToCache("new-user", 0); endInsertRows(); } void AccountModel::UserDeleted(const QDBusObjectPath& path) { if (!m_userPath.contains(path.path())) { qCDebug(USER_MANAGER_LOG) << "User Deleted but not found: " << path.path(); return; } beginRemoveRows(QModelIndex(), m_userPath.indexOf(path.path()), m_userPath.indexOf(path.path())); removeAccount(path.path()); endRemoveRows(); } void AccountModel::Changed() { Account* acc = qobject_cast(sender()); acc->path(); QModelIndex accountIndex = index(m_userPath.indexOf(acc->path()), 0); Q_EMIT dataChanged(accountIndex, accountIndex); } void AccountModel::userLogged(uint uid, bool logged) { QString path = accountPathForUid(uid); int row = m_userPath.indexOf(path); setData(index(row), logged, Logged); } const QString AccountModel::accountPathForUid(uint uid) const { QHash::ConstIterator i; for (i = m_users.constBegin(); i != m_users.constEnd(); ++i) { if (i.value() && i.value()->uid() == uid) { return i.key(); } } return QString(); } QString AccountModel::cryptPassword(const QString& password) const { QString cryptedPassword; QByteArray alpha = "0123456789ABCDEFGHIJKLMNOPQRSTUVXYZ" "abcdefghijklmnopqrstuvxyz./"; QByteArray salt("$6$");//sha512 int len = alpha.count(); for(int i = 0; i < 16; i++){ salt.append(alpha.at((qrand() % len))); } return crypt(password.toUtf8(), salt); } QDebug operator<<(QDebug debug, AccountModel::Role role) { switch(role) { case AccountModel::FriendlyName: debug << "AccountModel::FriendlyName"; break; case AccountModel::Face: debug << "AccountModel::Face"; break; case AccountModel::RealName: debug << "AccountModel::RealName"; break; case AccountModel::Username: debug << "AccountModel::Username"; break; case AccountModel::Password: debug << "AccountModel::Password"; break; case AccountModel::Email: debug << "AccountModel::Email"; break; case AccountModel::Administrator: debug << "AccountModel::Administrator"; break; case AccountModel::AutomaticLogin: debug << "AccountModel::AutomaticLogin"; break; case AccountModel::Logged: debug << "AccountModel::Logged"; break; case AccountModel::Created: debug << "AccountModel::Created"; break; } return debug; }