/* Shell for kdm conversation plugins Copyright (C) 1997, 1998, 2000 Steffen Hansen Copyright (C) 2000-2004 Oswald Buddenhagen 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 #include "kgverify.h" #include "kdmconfig.h" #include "kdm_greet.h" #include "themer/kdmthemer.h" #include "themer/kdmitem.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // for updateLockStatus() #include // ... 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 // 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(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 ? "" : 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 KGVerify::greetPlugins; PluginList KGVerify::init(const QStringList &plugins) { PluginList pluginList; foreach (const QString& pg, plugins) { GreeterPluginHandle plugin; QLibrary *lib = new QLibrary(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 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", "Changing authentication token"), 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"