kde-workspace/kdm/kfrontend/kgverify.cpp
Ivailo Monev 3feb8972de generic: use QLibrary::resolve() instead of KLibrary::resolveSymbol()
they are the same, KLibrary::resolveSymbol() just calls resolve()
from QLibrary

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
2015-10-30 14:27:45 +02:00

1295 lines
34 KiB
C++

/*
Shell for kdm conversation plugins
Copyright (C) 1997, 1998, 2000 Steffen Hansen <hansen@kde.org>
Copyright (C) 2000-2004 Oswald Buddenhagen <ossi@kde.org>
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 <config-workspace.h>
#include "kgverify.h"
#include "kdmconfig.h"
#include "kdm_greet.h"
#include "themer/kdmthemer.h"
#include "themer/kdmitem.h"
#include <KColorScheme>
#include <kguiitem.h>
#include <klibrary.h>
#include <klocale.h>
#include <kpushbutton.h>
#include <krandom.h>
#include <kseparator.h>
#include <KStandardGuiItem>
#include <QAction>
#include <QApplication>
#include <QEvent>
#include <QtGui/qevent.h>
#include <QLabel>
#include <QMenu>
#include <QSocketNotifier>
#include <QtGui/qx11info_x11.h>
#include <X11/Xlib.h> // for updateLockStatus()
#include <fixx11h.h> // ... and make eventFilter() work again
#define FULL_GREET_TO 40 // normal inactivity timeout
#define TIMED_GREET_TO 20 // inactivity timeout when persisting timed login
#define MIN_TIMED_TO 5 // minimal timed login delay
#define DEAD_TIMED_TO 2 // <enter> dead time after re-activating timed login
#define SECONDS 1000 // reduce to 100 to speed up testing
void KGVerifyHandler::verifyClear()
{
}
void KGVerifyHandler::updateStatus(bool, bool, int)
{
}
KGVerify::KGVerify(KGVerifyHandler *_handler,
QWidget *_parent, QWidget *_predecessor,
const QString &_fixedUser,
const PluginList &_pluginList,
KGreeterPlugin::Function _func,
KGreeterPlugin::Context _ctx)
: inherited()
, coreState(CoreIdle)
, fixedEntity(_fixedUser)
, pluginList(_pluginList)
, handler(_handler)
, parent(_parent)
, predecessor(_predecessor)
, plugMenu(0)
, curPlugin(-1)
, timedLeft(0)
, func(_func)
, ctx(_ctx)
, enabled(true)
, running(false)
, suspended(false)
, failed(false)
, isClear(true)
{
sockNot = new QSocketNotifier(rfd, QSocketNotifier::Read, this);
sockNot->setEnabled(false);
connect(sockNot, SIGNAL(activated(int)), SLOT(handleVerify()));
connect(&timer, SIGNAL(timeout()), SLOT(slotTimeout()));
connect(qApp, SIGNAL(activity()), SLOT(slotActivity()));
_parent->installEventFilter(this);
}
KGVerify::~KGVerify()
{
debug("delete %s\n", pName.data());
delete greet;
}
QMenu *
KGVerify::getPlugMenu()
{
// assert(coreState != CoreBusy);
if (!plugMenu) {
uint np = pluginList.count();
if (np > 1) {
plugMenu = new QMenu(parent);
QActionGroup *plugGroup = new QActionGroup(parent);
connect(plugMenu, SIGNAL(triggered(QAction*)),
SLOT(slotPluginSelected(QAction*)));
for (uint i = 0; i < np; i++) {
int pid = pluginList[i];
greetPlugins[pid].action = plugGroup->addAction(
i18nc("@item:inmenu authentication method",
greetPlugins[pid].info->name));
greetPlugins[pid].action->setData(i);
greetPlugins[pid].action->setCheckable(true);
}
plugMenu->addActions(plugGroup->actions());
}
}
return plugMenu;
}
bool // public
KGVerify::entitiesLocal() const
{
return greetPlugins[pluginList[curPlugin]].info->flags & KGreeterPluginInfo::Local;
}
bool // public
KGVerify::entitiesFielded() const
{
return greetPlugins[pluginList[curPlugin]].info->flags & KGreeterPluginInfo::Fielded;
}
bool // public
KGVerify::entityPresettable() const
{
return greetPlugins[pluginList[curPlugin]].info->flags & KGreeterPluginInfo::Presettable;
}
bool // public
KGVerify::isClassic() const
{
return !strcmp(greetPlugins[pluginList[curPlugin]].info->method, "classic");
}
QString // public
KGVerify::pluginName() const
{
QString name(greetPlugins[pluginList[curPlugin]].library->fileName());
uint st = name.lastIndexOf('/') + 1;
uint en = name.indexOf('.', st);
if (en - st > 7 && QString::fromRawData(name.unicode() + st, 7) == QLatin1String("kgreet_"))
st += 7;
return name.mid(st, en - st);
}
static void
setTabOrder(QWidget *&pred, const QObjectList &list)
{
foreach (QObject *o, list)
if (QWidget *w = qobject_cast<QWidget *>(o)) {
if (w->focusPolicy() & Qt::TabFocus) {
QWidget::setTabOrder(pred, w);
pred = w;
} else {
setTabOrder(pred, o->children());
}
}
}
void // public
KGVerify::selectPlugin(int id)
{
if (pluginList.isEmpty()) {
msgBox(errorbox, i18n("No greeter widget plugin loaded. Check the configuration."));
::exit(EX_UNMANAGE_DPY);
}
curPlugin = id;
if (plugMenu)
greetPlugins[pluginList[id]].action->setChecked(true);
pName = ("greet_" + pluginName()).toLatin1();
debug("new %s\n", pName.data());
greet = greetPlugins[pluginList[id]].info->create(this, parent, fixedEntity, func, ctx);
if (QWidget *pred = predecessor)
setTabOrder(pred, *(const QObjectList *)&greet->getWidgets());
timeable = _autoLoginDelay && entityPresettable() && isClassic();
}
void // private slot
KGVerify::slotPluginSelected(QAction *action)
{
if (failed)
return;
int id = action->data().toInt();
if (id != curPlugin) {
parent->setUpdatesEnabled(false);
debug("delete %s\n", pName.data());
delete greet;
selectPlugin(id);
handler->verifyPluginChanged(id);
if (running)
start();
parent->setUpdatesEnabled(true);
}
}
void // public
KGVerify::loadUsers(const QStringList &users)
{
debug("%s->loadUsers(...)\n", pName.data());
greet->loadUsers(users);
}
void // public
KGVerify::presetEntity(const QString &entity, int field)
{
presEnt = entity;
presFld = field;
}
bool // private
KGVerify::applyPreset()
{
if (!presEnt.isEmpty()) {
debug("%s->presetEntity(%\"s, %d)\n", pName.data(),
qPrintable(presEnt), presFld);
greet->presetEntity(presEnt, presFld);
if (entitiesLocal()) {
curUser = presEnt;
pamUser.clear();
handler->verifySetUser(presEnt);
}
return true;
}
return false;
}
bool // private
KGVerify::scheduleAutoLogin(bool initial)
{
if (timeable) {
debug("%s->presetEntity(%\"s, -1)\n", pName.data(),
qPrintable(_autoLoginUser), -1);
greet->presetEntity(_autoLoginUser, -1);
curUser = _autoLoginUser;
handler->verifySetUser(_autoLoginUser);
timer.start(1000);
if (initial) {
timedLeft = _autoLoginDelay;
deadTicks = 0;
} else {
timedLeft = qMax(_autoLoginDelay - TIMED_GREET_TO, MIN_TIMED_TO);
deadTicks = DEAD_TIMED_TO;
}
updateStatus();
sockNot->setEnabled(false);
running = false;
isClear = true;
return true;
}
return false;
}
void // private
KGVerify::performAutoLogin()
{
// timer.stop();
gSendInt(G_AutoLogin);
coreState = CoreBusy;
sockNot->setEnabled(true);
}
QString // public
KGVerify::getEntity() const
{
debug("%s->getEntity()\n", pName.data());
QString ent = greet->getEntity();
debug(" entity: %s\n", qPrintable(ent));
return ent;
}
void
KGVerify::setUser(const QString &user)
{
// assert(fixedEntity.isEmpty());
curUser = user;
debug("%s->setUser(%\"s)\n", pName.data(), qPrintable(user));
greet->setUser(user);
talkerEdits();
}
void
KGVerify::start()
{
authTok = (func == KGreeterPlugin::ChAuthTok);
if (func == KGreeterPlugin::Authenticate && ctx == KGreeterPlugin::Login) {
if (scheduleAutoLogin(true)) {
if (!_autoLoginAgain)
_autoLoginDelay = 0, timeable = false;
return;
} else {
applyPreset();
}
if (_isReserve)
timer.start(FULL_GREET_TO * SECONDS);
}
sockNot->setEnabled(true);
running = true;
if (!(func == KGreeterPlugin::Authenticate ||
ctx == KGreeterPlugin::ChangeTok ||
ctx == KGreeterPlugin::ExChangeTok))
{
coreState = CoreBusy;
}
debug("%s->start()\n", pName.data());
greet->start();
}
void
KGVerify::abort()
{
debug("%s->abort()\n", pName.data());
greet->abort();
sockNot->setEnabled(false);
running = false;
}
void
KGVerify::suspend()
{
// assert(coreState != CoreBusy);
if (running) {
debug("%s->abort()\n", pName.data());
greet->abort();
}
suspended = true;
updateStatus();
timer.suspend();
sockNot->setEnabled(false);
}
void
KGVerify::resume()
{
sockNot->setEnabled(true);
timer.resume();
suspended = false;
updateLockStatus();
if (running) {
debug("%s->start()\n", pName.data());
greet->start();
} else if (delayed) {
delayed = false;
running = true;
sockNot->setEnabled(true);
debug("%s->start()\n", pName.data());
greet->start();
}
}
void // not a slot - called manually by greeter
KGVerify::accept()
{
debug("%s->next()\n", pName.data());
greet->next();
}
void // private
KGVerify::doReject(bool initial)
{
// assert(coreState != CoreBusy);
if (running) {
debug("%s->abort()\n", pName.data());
greet->abort();
}
handler->verifyClear();
debug("%s->clear()\n", pName.data());
greet->clear();
curUser.clear();
pamUser.clear();
if (!scheduleAutoLogin(initial)) {
isClear = !(isClear && applyPreset());
if (running) {
debug("%s->start()\n", pName.data());
greet->start();
}
if (!failed)
timer.stop();
}
}
void // not a slot - called manually by greeter
KGVerify::reject()
{
doReject(true);
}
void
KGVerify::setEnabled(bool on)
{
debug("%s->setEnabled(%s)\n", pName.data(), on ? "true" : "false");
greet->setEnabled(on);
enabled = on;
updateStatus();
}
void // private
KGVerify::slotTimeout()
{
if (failed) {
failed = false;
updateStatus();
debug("%s->revive()\n", pName.data());
greet->revive();
handler->verifyRetry();
if (suspended) {
delayed = true;
} else {
running = true;
sockNot->setEnabled(true);
debug("%s->start()\n", pName.data());
greet->start();
slotActivity();
talkerEdits();
}
} else if (timedLeft) {
deadTicks--;
if (!--timedLeft)
performAutoLogin();
else
timer.start(1000);
updateStatus();
} else if (_isReserve) {
// assert(ctx == Login && running);
abort();
::exit(EX_RESERVE);
} else {
// assert(ctx == Login);
isClear = true;
doReject(false);
}
}
void
KGVerify::slotActivity()
{
if (timedLeft) {
// timed login countdown running. cancel and reschedule it.
debug("%s->revive()\n", pName.data());
greet->revive();
debug("%s->start()\n", pName.data());
greet->start();
sockNot->setEnabled(true);
running = true;
timedLeft = 0;
updateStatus();
timer.start(TIMED_GREET_TO * SECONDS);
} else if (timeable) {
// timed login is possible and thus scheduled. reschedule it.
timer.start(TIMED_GREET_TO * SECONDS);
} else if (_isReserve) {
timer.start(FULL_GREET_TO * SECONDS);
}
}
void
KGVerify::talkerEdits()
{
if (func == KGreeterPlugin::Authenticate &&
ctx == KGreeterPlugin::Login)
{
isClear = false;
if (!timeable)
timer.start(FULL_GREET_TO * SECONDS);
}
}
void // private static
KGVerify::vrfMsgBox(QWidget *parent, const QString &user,
QMessageBox::Icon type, const QString &mesg)
{
KFMsgBox::box(parent, type, user.isEmpty() ?
mesg : i18n("Logging in %1...\n\n", user) + mesg);
}
static const char * const msgs[] = {
I18N_NOOP("You are required to change your password immediately (password aged)."),
I18N_NOOP("You are required to change your password immediately (root enforced)."),
I18N_NOOP("You are not allowed to login at the moment."),
I18N_NOOP("Home folder not available."),
I18N_NOOP("Logins are not allowed at the moment.\nTry again later."),
I18N_NOOP("Your login shell is not listed in /etc/shells."),
I18N_NOOP("Root logins are not allowed."),
I18N_NOOP("Your account has expired; please contact your system administrator.")
};
void // private static
KGVerify::vrfErrBox(QWidget *parent, const QString &user, const char *msg)
{
QMessageBox::Icon icon;
QString mesg;
if (!msg) {
mesg = i18n("A critical error occurred.\n"
"Please look at KDM's logfile(s) for more information\n"
"or contact your system administrator.");
icon = errorbox;
} else {
mesg = QString::fromLocal8Bit(msg);
QString mesg1 = mesg + '.';
for (uint i = 0; i < as(msgs); i++)
if (mesg1 == msgs[i]) {
mesg = i18n(msgs[i]);
break;
}
icon = sorrybox;
}
vrfMsgBox(parent, user, icon, mesg);
}
void // private static
KGVerify::vrfInfoBox(QWidget *parent, const QString &user, const char *msg)
{
QString mesg = QString::fromLocal8Bit(msg);
QRegExp rx("^Warning: your account will expire in (\\d+) day");
if (rx.indexIn(mesg) >= 0) {
int expire = rx.cap(1).toInt();
mesg = expire ?
i18np("Your account expires tomorrow.",
"Your account expires in %1 days.", expire) :
i18n("Your account expires today.");
} else {
rx.setPattern("^Warning: your password will expire in (\\d+) day");
if (rx.indexIn(mesg) >= 0) {
int expire = rx.cap(1).toInt();
mesg = expire ?
i18np("Your password expires tomorrow.",
"Your password expires in %1 days.", expire) :
i18n("Your password expires today.");
}
}
vrfMsgBox(parent, user, infobox, mesg);
}
bool // public static
KGVerify::handleFailVerify(QWidget *parent, bool showUser)
{
char *msg;
QString user;
debug("handleFailVerify ...\n");
if (showUser) {
msg = gRecvStr();
user = QString::fromLocal8Bit(msg);
free(msg);
}
for (;;) {
int ret = gRecvInt();
// non-terminal status
switch (ret) {
/* case V_PUT_USER: cannot happen - we are in "classic" mode */
/* case V_PRE_OK: cannot happen - not in ChTok dialog */
/* case V_CHTOK: cannot happen - called by non-interactive verify */
case V_CHTOK_AUTH:
debug(" V_CHTOK_AUTH\n");
{
QStringList pgs(_pluginsLogin);
pgs += _pluginsShutdown;
foreach (const QString& pg, pgs)
if (pg == "classic" || pg == "modern") {
pgs = QStringList(pg);
goto gotit;
} else if (pg == "generic") {
pgs = QStringList("modern");
goto gotit;
}
pgs = QStringList("classic");
gotit:
KGChTok chtok(parent, user, init(pgs), 0,
KGreeterPlugin::AuthChAuthTok,
KGreeterPlugin::Login);
return chtok.exec();
}
case V_MSG_ERR:
debug(" V_MSG_ERR\n");
msg = gRecvStr();
debug(" message %\"s\n", msg);
vrfErrBox(parent, user, msg);
free(msg);
gSendInt(0);
continue;
case V_MSG_INFO_AUTH: // should not happen
case V_MSG_INFO:
debug(" V_MSG_INFO\n");
msg = gRecvStr();
debug(" message %\"s\n", msg);
vrfInfoBox(parent, user, msg);
free(msg);
gSendInt(0);
continue;
}
// terminal status
switch (ret) {
case V_OK:
debug(" V_OK\n");
return true;
case V_AUTH:
debug(" V_AUTH\n");
vrfMsgBox(parent, user, sorrybox, i18n("Authentication failed"));
return false;
case V_FAIL:
debug(" V_FAIL\n");
return false;
default:
logPanic("Unknown V_xxx code %d from core\n", ret);
}
}
}
void // private
KGVerify::handleVerify()
{
debug("handleVerify ...\n");
QString user;
char *msg;
int ret, echo, ndelay;
KGreeterPlugin::Function nfunc;
ret = gRecvInt();
// requests
coreState = CorePrompting;
switch (ret) {
case V_GET_TEXT:
debug(" V_GET_TEXT\n");
msg = gRecvStr();
debug(" prompt %\"s\n", msg);
echo = gRecvInt();
debug(" echo = %d\n", echo);
ndelay = gRecvInt();
debug(" ndelay = %d\n%s->textPrompt(...)\n", ndelay, pName.data());
greet->textPrompt(msg, echo, ndelay);
free(msg);
return;
case V_GET_BINARY:
debug(" V_GET_BINARY\n");
msg = gRecvArr(&ret);
debug(" %d bytes prompt\n", ret);
ndelay = gRecvInt();
debug(" ndelay = %d\n%s->binaryPrompt(...)\n", ndelay, pName.data());
greet->binaryPrompt(msg, ndelay);
free(msg);
return;
}
// non-terminal status
coreState = CoreBusy;
switch (ret) {
case V_PUT_USER:
debug(" V_PUT_USER\n");
msg = gRecvStr();
curUser = pamUser = QString::fromLocal8Bit(msg);
// greet needs this to be able to return something useful from
// getEntity(). but the backend is still unable to tell a domain ...
debug(" %s->setUser(%\"s)\n", pName.data(), qPrintable(user));
greet->setUser(curUser);
handler->verifySetUser(curUser);
free(msg);
return;
case V_PRE_OK: // this is only for func == AuthChAuthTok
debug(" V_PRE_OK\n");
// With the "classic" method, the wrong user simply cannot be
// authenticated, even with the generic plugin. Other methods
// could do so, but this applies only to ctx == ChangeTok, which
// is not implemented yet.
authTok = true;
debug("%s->succeeded()\n", pName.data());
greet->succeeded();
return;
case V_MSG_ERR:
debug(" V_MSG_ERR\n");
timer.suspend();
msg = gRecvStr();
debug(" %s->textMessage(%\"s, true)\n", pName.data(), msg);
if (!greet->textMessage(msg, true)) { // XXX little point in filtering
debug(" message passed\n");
vrfErrBox(parent, pamUser, msg);
} else {
debug(" message swallowed\n");
}
free(msg);
gSendInt(0);
timer.resume();
return;
case V_MSG_INFO_AUTH:
debug(" V_MSG_INFO_AUTH\n");
timer.suspend();
msg = gRecvStr();
debug(" %s->textMessage(%\"s, false)\n", pName.data(), msg);
if (!greet->textMessage(msg, false)) {
debug(" message passed\n");
vrfInfoBox(parent, pamUser, msg);
} else {
debug(" message swallowed\n");
}
free(msg);
gSendInt(0);
timer.resume();
return;
case V_MSG_INFO:
debug(" V_MSG_INFO\n");
timer.suspend();
msg = gRecvStr();
debug(" display %\"s\n", msg);
vrfInfoBox(parent, pamUser, msg);
free(msg);
gSendInt(0);
timer.resume();
return;
}
// terminal status
coreState = CoreIdle;
running = false;
sockNot->setEnabled(false);
timer.stop();
// These codes are not really terminal as far as the core is concerned,
// but the branches as a whole are.
if (ret == V_CHTOK_AUTH) {
debug(" V_CHTOK_AUTH\n");
nfunc = KGreeterPlugin::AuthChAuthTok;
user = curUser;
goto dchtok;
} else if (ret == V_CHTOK) {
debug(" V_CHTOK\n");
nfunc = KGreeterPlugin::ChAuthTok;
user.clear();
dchtok:
debug("%s->succeeded()\n", pName.data());
greet->succeeded();
KGChTok chtok(parent, user, pluginList, curPlugin, nfunc, KGreeterPlugin::Login);
if (!chtok.exec())
goto retry;
handler->verifyOk();
return;
}
if (ret == V_OK) {
debug(" V_OK\n");
if (!fixedEntity.isEmpty()) {
debug(" %s->getEntity()\n", pName.data());
QString ent = greet->getEntity();
debug(" entity %\"s\n", qPrintable(ent));
if (ent != fixedEntity) {
debug("%s->failed()\n", pName.data());
greet->failed();
msgBox(sorrybox,
i18n("Authenticated user (%1) does not match requested user (%2).\n",
ent, fixedEntity));
goto retry;
}
}
debug("%s->succeeded()\n", pName.data());
greet->succeeded();
handler->verifyOk();
return;
}
debug("%s->failed()\n", pName.data());
greet->failed();
if (ret == V_AUTH) {
debug(" V_AUTH\n");
failed = true;
updateStatus();
handler->verifyFailed();
timer.start(1500 + KRandom::random() / (RAND_MAX / 1000));
return;
}
if (ret != V_FAIL)
logPanic("Unknown V_xxx code %d from core\n", ret);
debug(" V_FAIL\n");
retry:
debug("%s->revive()\n", pName.data());
greet->revive();
sockNot->setEnabled(true);
running = true;
debug("%s->start()\n", pName.data());
greet->start();
slotActivity();
talkerEdits();
}
void
KGVerify::gplugReturnText(const char *text, int tag)
{
debug("%s: gplugReturnText(%\"s, %d)\n", pName.data(),
tag & V_IS_SECRET ? "<masked>" : text, tag);
gSendStr(text);
if (text) {
gSendInt(tag);
coreState = CoreBusy;
} else {
coreState = CoreIdle;
}
}
void
KGVerify::gplugReturnBinary(const char *data)
{
if (data) {
unsigned const char *up = (unsigned const char *)data;
int len = up[3] | (up[2] << 8) | (up[1] << 16) | (up[0] << 24);
debug("%s: gplugReturnBinary(%d bytes)\n", pName.data(), len);
gSendArr(len, data);
coreState = CoreBusy;
} else {
debug("%s: gplugReturnBinary(NULL)\n", pName.data());
gSendArr(0, 0);
coreState = CoreIdle;
}
}
void
KGVerify::gplugSetUser(const QString &user)
{
debug("%s: gplugSetUser(%\"s)\n", pName.data(), qPrintable(user));
curUser = user;
handler->verifySetUser(user);
}
void
KGVerify::gplugStart()
{
// XXX handle func != Authenticate
if (coreState != CoreIdle)
return;
debug("%s: gplugStart()\n", pName.data());
gSendInt(ctx == KGreeterPlugin::Shutdown ? G_VerifyRootOK : G_Verify);
gSendStr(greetPlugins[pluginList[curPlugin]].info->method);
coreState = CoreBusy;
}
void
KGVerify::gplugChanged()
{
debug("%s: gplugChanged()\n", pName.data());
if (parent->isActiveWindow())
talkerEdits();
}
void
KGVerify::gplugActivity()
{
debug("%s: gplugActivity()\n", pName.data());
slotActivity();
}
void
KGVerify::gplugMsgBox(QMessageBox::Icon type, const QString &text)
{
debug("%s: gplugMsgBox(%d, %\"s)\n", pName.data(), type, qPrintable(text));
msgBox(type, text);
}
bool
KGVerify::eventFilter(QObject *o, QEvent *e)
{
switch (e->type()) {
case QEvent::KeyPress:
if (timedLeft) {
QKeyEvent *ke = (QKeyEvent *)e;
if (ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter) {
if (deadTicks <= 0) {
timedLeft = 0;
performAutoLogin();
}
return true;
}
}
/* fall through */
case QEvent::KeyRelease:
updateLockStatus();
/* fall through */
default:
break;
}
return inherited::eventFilter(o, e);
}
void
KGVerify::updateLockStatus()
{
unsigned int lmask;
Window dummy1, dummy2;
int dummy3, dummy4, dummy5, dummy6;
XQueryPointer(QX11Info::display(), DefaultRootWindow(QX11Info::display()),
&dummy1, &dummy2, &dummy3, &dummy4, &dummy5, &dummy6,
&lmask);
capsLocked = lmask & LockMask;
updateStatus();
}
void
KGVerify::msgBox(QMessageBox::Icon typ, const QString &msg)
{
timer.suspend();
KFMsgBox::box(parent, typ, msg);
timer.resume();
}
QVariant // public static
KGVerify::getConf(void *, const char *key, const QVariant &dflt)
{
if (!qstrcmp(key, "EchoPasswd")) {
return QVariant(_echoPasswd);
} else {
QString fkey = QString::fromLatin1(key) + '=';
foreach (const QString& pgo, _pluginOptions)
if (pgo.startsWith(fkey))
return pgo.mid(fkey.length());
return dflt;
}
}
QVector<GreeterPluginHandle> KGVerify::greetPlugins;
PluginList
KGVerify::init(const QStringList &plugins)
{
PluginList pluginList;
foreach (const QString& pg, plugins) {
GreeterPluginHandle plugin;
KLibrary *lib = new KLibrary(pg[0] == '/' ? pg : "kgreet_" + pg);
if (lib->fileName().isEmpty()) {
logError("GreeterPlugin %s does not exist\n", qPrintable(pg));
delete lib;
continue;
}
uint i, np = greetPlugins.count();
for (i = 0; i < np; i++)
if (greetPlugins[i].library->fileName() == lib->fileName()) {
delete lib;
goto next;
}
if (!lib->load()) {
logError("Cannot load GreeterPlugin %s (%s)\n",
qPrintable(pg), qPrintable(lib->fileName()));
delete lib;
continue;
}
plugin.library = lib;
plugin.info = (KGreeterPluginInfo *)lib->resolve("kgreeterplugin_info");
if (!plugin.info) {
logError("GreeterPlugin %s (%s) is no valid greet widget plugin\n",
qPrintable(pg), qPrintable(lib->fileName()));
lib->unload();
delete lib;
continue;
}
if (!plugin.info->init(QString(), getConf, 0)) {
logError("GreeterPlugin %s (%s) refuses to serve\n",
qPrintable(pg), qPrintable(lib->fileName()));
lib->unload();
delete lib;
continue;
}
debug("GreeterPlugin %s (%s) loaded\n", qPrintable(pg), plugin.info->name);
plugin.action = 0;
greetPlugins.append(plugin);
next:
pluginList.append(i);
}
return pluginList;
}
void
KGVerify::done()
{
for (int i = 0; i < greetPlugins.count(); i++) {
if (greetPlugins[i].info->done)
greetPlugins[i].info->done();
greetPlugins[i].library->unload();
}
}
KGStdVerify::KGStdVerify(KGVerifyHandler *_handler, QWidget *_parent,
QWidget *_predecessor, const QString &_fixedUser,
const PluginList &_pluginList,
KGreeterPlugin::Function _func,
KGreeterPlugin::Context _ctx)
: inherited(_handler, _parent, _predecessor, _fixedUser,
_pluginList, _func, _ctx)
, failedLabelState(0)
{
grid = new QGridLayout;
grid->setAlignment(Qt::AlignCenter);
failedLabel = new QLabel(parent);
failedLabel->setFont(*_failFont);
grid->addWidget(failedLabel, 1, 0, Qt::AlignCenter);
updateLockStatus();
}
KGStdVerify::~KGStdVerify()
{
}
bool
KGStdVerify::gplugHasNode(const QString &)
{
return false;
}
void // public
KGStdVerify::selectPlugin(int id)
{
inherited::selectPlugin(id);
QWidget *w = greet->getWidgets().first();
grid->addWidget(w, 0, 0);
w->show();
}
void
KGStdVerify::updateStatus()
{
int nfls;
if (!enabled)
nfls = 1;
else if (failed)
nfls = 2;
else if (timedLeft)
nfls = -timedLeft;
else if (!suspended && capsLocked)
nfls = 3;
else
nfls = 1;
if (failedLabelState != nfls) {
failedLabelState = nfls;
QPalette p;
if (nfls < 0) {
failedLabel->setText(i18np("Automatic login in 1 second...",
"Automatic login in %1 seconds...",
timedLeft));
} else {
switch (nfls) {
default:
failedLabel->clear();
break;
case 3:
p.setBrush(QPalette::WindowText,
KColorScheme(QPalette::Active, KColorScheme::Window)
.foreground(KColorScheme::NegativeText));
failedLabel->setText(i18n("Warning: Caps Lock is on"));
break;
case 2:
failedLabel->setText(authTok ?
i18n("Change failed") :
fixedEntity.isEmpty() ?
i18n("Login failed") :
i18n("Authentication failed"));
break;
}
}
failedLabel->setPalette(p);
}
}
KGThemedVerify::KGThemedVerify(KGVerifyHandler *_handler,
KdmThemer *_themer,
QWidget *_parent, QWidget *_predecessor,
const QString &_fixedUser,
const PluginList &_pluginList,
KGreeterPlugin::Function _func,
KGreeterPlugin::Context _ctx)
: inherited(_handler, _parent, _predecessor, _fixedUser,
_pluginList, _func, _ctx)
, themer(_themer)
{
updateLockStatus();
}
KGThemedVerify::~KGThemedVerify()
{
}
bool
KGThemedVerify::gplugHasNode(const QString &id)
{
return themer->findNode(id) != 0;
}
void // public
KGThemedVerify::selectPlugin(int id)
{
if (curPlugin != -1)
themer->setTypeVisible(QString("plugin-specific-").append(pluginName()), false);
inherited::selectPlugin(id);
themer->setTypeVisible(QString("plugin-specific-").append(pluginName()), true);
QSet<QString> oldTypes = showTypes;
showTypes.clear();
foreach (QWidget *w, greet->getWidgets())
if (KdmItem *n = themer->findNode(w->objectName())) {
QString tn(QString("plugin-").append(w->objectName()));
themer->setTypeVisible(tn, true);
showTypes.insert(tn);
oldTypes.remove(tn);
n->setWidget(w);
} else {
msgBox(errorbox,
i18n("Theme not usable with authentication method '%1'.",
i18n(greetPlugins[pluginList[id]].info->name)));
break;
}
foreach (const QString &t, oldTypes)
themer->setTypeVisible(t, false);
}
void
KGThemedVerify::updateStatus()
{
handler->updateStatus(enabled && failed,
enabled && !suspended && capsLocked,
timedLeft);
}
KGChTok::KGChTok(QWidget *_parent, const QString &user,
const PluginList &pluginList, int curPlugin,
KGreeterPlugin::Function func,
KGreeterPlugin::Context ctx)
: inherited(_parent)
, verify(0)
{
QSizePolicy fp(QSizePolicy::Fixed, QSizePolicy::Fixed);
okButton = new KPushButton(KStandardGuiItem::ok(), this);
okButton->setSizePolicy(fp);
okButton->setDefault(true);
cancelButton = new KPushButton(KStandardGuiItem::cancel(), this);
cancelButton->setSizePolicy(fp);
verify = new KGStdVerify(this, this, cancelButton, user, pluginList, func, ctx);
verify->selectPlugin(curPlugin);
QVBoxLayout *box = new QVBoxLayout(this);
box->addWidget(new QLabel(i18nc("@title:window",
"<qt><b>Changing authentication token</b></qt>"),
this), 0, Qt::AlignHCenter | Qt::AlignTop);
box->addLayout(verify->getLayout());
box->addWidget(new KSeparator(Qt::Horizontal, this));
QHBoxLayout *hlay = new QHBoxLayout();
box->addLayout(hlay);
hlay->addStretch(1);
hlay->addWidget(okButton);
hlay->addStretch(1);
hlay->addWidget(cancelButton);
hlay->addStretch(1);
connect(okButton, SIGNAL(clicked()), SLOT(accept()));
connect(cancelButton, SIGNAL(clicked()), SLOT(reject()));
QTimer::singleShot(0, verify, SLOT(start()));
}
KGChTok::~KGChTok()
{
hide();
delete verify;
}
void
KGChTok::accept()
{
verify->accept();
}
void
KGChTok::verifyPluginChanged(int)
{
// cannot happen
}
void
KGChTok::verifyOk()
{
inherited::accept();
}
void
KGChTok::verifyFailed()
{
okButton->setEnabled(false);
cancelButton->setEnabled(false);
}
void
KGChTok::verifyRetry()
{
okButton->setEnabled(true);
cancelButton->setEnabled(true);
}
void
KGChTok::verifySetUser(const QString &)
{
// cannot happen
}
////// helper class, nuke when qtimer supports suspend()/resume()
QXTimer::QXTimer()
: inherited(0)
, left(-1)
{
connect(&timer, SIGNAL(timeout()), SLOT(slotTimeout()));
}
void
QXTimer::start(int msec)
{
left = msec;
timer.setSingleShot(true);
timer.start(left);
gettimeofday(&stv, 0);
}
void
QXTimer::stop()
{
timer.stop();
left = -1;
}
void
QXTimer::suspend()
{
if (timer.isActive()) {
timer.stop();
struct timeval tv;
gettimeofday(&tv, 0);
left -= (tv.tv_sec - stv.tv_sec) * 1000 + (tv.tv_usec - stv.tv_usec) / 1000;
if (left < 0)
left = 0;
}
}
void
QXTimer::resume()
{
if (left >= 0 && !timer.isActive()) {
timer.setSingleShot(true);
timer.start(left);
gettimeofday(&stv, 0);
}
}
void
QXTimer::slotTimeout()
{
left = -1;
emit timeout();
}
#include "moc_kgverify.cpp"