add more spacing
[personal-kdebase.git] / workspace / kdm / kfrontend / kgverify.cpp
blobea2e179d8b72db25c214f436edb5aaca2aa2a710
1 /*
3 Shell for kdm conversation plugins
5 Copyright (C) 1997, 1998, 2000 Steffen Hansen <hansen@kde.org>
6 Copyright (C) 2000-2004 Oswald Buddenhagen <ossi@kde.org>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #include <config-workspace.h>
27 #include "kgverify.h"
28 #include "kdmconfig.h"
29 #include "kdm_greet.h"
31 #include "themer/kdmthemer.h"
32 #include "themer/kdmitem.h"
34 #include <KColorScheme>
35 #include <kguiitem.h>
36 #include <klibrary.h>
37 #include <klocale.h>
38 #include <kpushbutton.h>
39 #include <krandom.h>
40 #include <kseparator.h>
41 #include <KStandardGuiItem>
43 #include <QAction>
44 #include <QApplication>
45 #include <QEvent>
46 #include <QKeyEvent>
47 #include <QLabel>
48 #include <QMenu>
49 #include <QX11Info>
51 #include <X11/Xlib.h> // for updateLockStatus()
52 #include <fixx11h.h> // ... and make eventFilter() work again
54 #define FULL_GREET_TO 40 // normal inactivity timeout
55 #define TIMED_GREET_TO 20 // inactivity timeout when persisting timed login
56 #define MIN_TIMED_TO 5 // minimal timed login delay
57 #define DEAD_TIMED_TO 2 // <enter> dead time after re-activating timed login
58 #define SECONDS 1000 // reduce to 100 to speed up testing
60 void KGVerifyHandler::verifyClear()
64 void KGVerifyHandler::updateStatus( bool, bool, int )
68 KGVerify::KGVerify( KGVerifyHandler *_handler,
69 QWidget *_parent, QWidget *_predecessor,
70 const QString &_fixedUser,
71 const PluginList &_pluginList,
72 KGreeterPlugin::Function _func,
73 KGreeterPlugin::Context _ctx )
74 : inherited()
75 , coreLock( 0 )
76 , fixedEntity( _fixedUser )
77 , pluginList( _pluginList )
78 , handler( _handler )
79 , parent( _parent )
80 , predecessor( _predecessor )
81 , plugMenu( 0 )
82 , curPlugin( -1 )
83 , timedLeft( 0 )
84 , func( _func )
85 , ctx( _ctx )
86 , enabled( true )
87 , running( false )
88 , suspended( false )
89 , failed( false )
90 , isClear( true )
92 connect( &timer, SIGNAL(timeout()), SLOT(slotTimeout()) );
93 connect( qApp, SIGNAL(activity()), SLOT(slotActivity()) );
95 _parent->installEventFilter( this );
98 KGVerify::~KGVerify()
100 debug( "delete %s\n", pName.data() );
101 delete greet;
104 QMenu *
105 KGVerify::getPlugMenu()
107 // assert( !cont );
108 if (!plugMenu) {
109 uint np = pluginList.count();
110 if (np > 1) {
111 plugMenu = new QMenu( parent );
112 QActionGroup *plugGroup = new QActionGroup( parent );
113 connect( plugMenu, SIGNAL(triggered( QAction * )),
114 SLOT(slotPluginSelected( QAction * )) );
115 for (uint i = 0; i < np; i++) {
116 int pid = pluginList[i];
117 greetPlugins[pid].action = plugGroup->addAction(
118 i18nc("@item:inmenu authentication method",
119 greetPlugins[pid].info->name) );
120 greetPlugins[pid].action->setData( i );
121 greetPlugins[pid].action->setCheckable( true );
123 plugMenu->addActions( plugGroup->actions() );
126 return plugMenu;
129 bool // public
130 KGVerify::entitiesLocal() const
132 return greetPlugins[pluginList[curPlugin]].info->flags & KGreeterPluginInfo::Local;
135 bool // public
136 KGVerify::entitiesFielded() const
138 return greetPlugins[pluginList[curPlugin]].info->flags & KGreeterPluginInfo::Fielded;
141 bool // public
142 KGVerify::entityPresettable() const
144 return greetPlugins[pluginList[curPlugin]].info->flags & KGreeterPluginInfo::Presettable;
147 bool // public
148 KGVerify::isClassic() const
150 return !strcmp( greetPlugins[pluginList[curPlugin]].info->method, "classic" );
153 QString // public
154 KGVerify::pluginName() const
156 QString name( greetPlugins[pluginList[curPlugin]].library->fileName() );
157 uint st = name.lastIndexOf( '/' ) + 1;
158 uint en = name.indexOf( '.', st );
159 if (en - st > 7 && QString::fromRawData( name.unicode() + st, 7 ) == QLatin1String("kgreet_"))
160 st += 7;
161 return name.mid( st, en - st );
164 static void
165 setTabOrder( QWidget *&pred, const QObjectList &list )
167 foreach (QObject *o, list)
168 if (QWidget *w = qobject_cast<QWidget *>(o)) {
169 if (w->focusPolicy() & Qt::TabFocus) {
170 QWidget::setTabOrder( pred, w );
171 pred = w;
172 } else
173 setTabOrder( pred, o->children() );
177 void // public
178 KGVerify::selectPlugin( int id )
180 if (pluginList.isEmpty()) {
181 msgBox( errorbox, i18n("No greeter widget plugin loaded. Check the configuration.") );
182 ::exit( EX_UNMANAGE_DPY );
184 curPlugin = id;
185 if (plugMenu)
186 greetPlugins[pluginList[id]].action->setChecked( true );
187 pName = ("greet_" + pluginName()).toLatin1();
188 debug( "new %s\n", pName.data() );
189 greet = greetPlugins[pluginList[id]].info->create( this, parent, fixedEntity, func, ctx );
190 if (QWidget *pred = predecessor)
191 setTabOrder( pred, *(const QObjectList *)&greet->getWidgets() );
192 timeable = _autoLoginDelay && entityPresettable() && isClassic();
195 void // private slot
196 KGVerify::slotPluginSelected( QAction *action )
198 if (failed)
199 return;
200 int id = action->data().toInt();
201 if (id != curPlugin) {
202 parent->setUpdatesEnabled( false );
203 debug( "delete %s\n", pName.data() );
204 delete greet;
205 selectPlugin( id );
206 handler->verifyPluginChanged( id );
207 if (running)
208 start();
209 parent->setUpdatesEnabled( true );
213 void // public
214 KGVerify::loadUsers( const QStringList &users )
216 debug( "%s->loadUsers(...)\n", pName.data() );
217 greet->loadUsers( users );
220 void // public
221 KGVerify::presetEntity( const QString &entity, int field )
223 presEnt = entity;
224 presFld = field;
227 bool // private
228 KGVerify::applyPreset()
230 if (!presEnt.isEmpty()) {
231 debug( "%s->presetEntity(%\"s, %d)\n", pName.data(),
232 qPrintable( presEnt ), presFld );
233 greet->presetEntity( presEnt, presFld );
234 if (entitiesLocal()) {
235 curUser = presEnt;
236 handler->verifySetUser( presEnt );
238 return true;
240 return false;
243 bool // private
244 KGVerify::scheduleAutoLogin( bool initial )
246 if (timeable) {
247 debug( "%s->presetEntity(%\"s, -1)\n", pName.data(),
248 qPrintable( _autoLoginUser ), -1 );
249 greet->presetEntity( _autoLoginUser, -1 );
250 curUser = _autoLoginUser;
251 handler->verifySetUser( _autoLoginUser );
252 timer.start( 1000 );
253 if (initial) {
254 timedLeft = _autoLoginDelay;
255 deadTicks = 0;
256 } else {
257 timedLeft = qMax( _autoLoginDelay - TIMED_GREET_TO, MIN_TIMED_TO );
258 deadTicks = DEAD_TIMED_TO;
260 updateStatus();
261 running = false;
262 isClear = true;
263 return true;
265 return false;
268 void // private
269 KGVerify::performAutoLogin()
271 // timer.stop();
272 gSendInt( G_AutoLogin );
273 handleVerify();
276 QString // public
277 KGVerify::getEntity() const
279 debug( "%s->getEntity()\n", pName.data() );
280 QString ent = greet->getEntity();
281 debug( " entity: %s\n", qPrintable( ent ) );
282 return ent;
285 void
286 KGVerify::setUser( const QString &user )
288 // assert( fixedEntity.isEmpty() );
289 curUser = user;
290 debug( "%s->setUser(%\"s)\n", pName.data(), qPrintable( user ) );
291 greet->setUser( user );
292 gplugChanged();
295 void
296 KGVerify::start()
298 authTok = (func == KGreeterPlugin::ChAuthTok);
299 cont = false;
300 if (func == KGreeterPlugin::Authenticate && ctx == KGreeterPlugin::Login) {
301 if (scheduleAutoLogin( true )) {
302 if (!_autoLoginAgain)
303 _autoLoginDelay = 0, timeable = false;
304 return;
305 } else
306 applyPreset();
308 running = true;
309 if (!(func == KGreeterPlugin::Authenticate ||
310 ctx == KGreeterPlugin::ChangeTok ||
311 ctx == KGreeterPlugin::ExChangeTok))
313 cont = true;
315 debug( "%s->start()\n", pName.data() );
316 greet->start();
317 if (cont)
318 handleVerify();
321 void
322 KGVerify::abort()
324 debug( "%s->abort()\n", pName.data() );
325 greet->abort();
326 running = false;
329 void
330 KGVerify::suspend()
332 // assert( !cont );
333 if (running) {
334 debug( "%s->abort()\n", pName.data() );
335 greet->abort();
337 suspended = true;
338 updateStatus();
339 timer.suspend();
342 void
343 KGVerify::resume()
345 timer.resume();
346 suspended = false;
347 updateLockStatus();
348 if (running) {
349 debug( "%s->start()\n", pName.data() );
350 greet->start();
351 } else if (delayed) {
352 delayed = false;
353 running = true;
354 debug( "%s->start()\n", pName.data() );
355 greet->start();
359 void // not a slot - called manually by greeter
360 KGVerify::accept()
362 debug( "%s->next()\n", pName.data() );
363 greet->next();
366 void // private
367 KGVerify::doReject( bool initial )
369 // assert( !cont );
370 if (running) {
371 debug( "%s->abort()\n", pName.data() );
372 greet->abort();
374 handler->verifyClear();
375 debug( "%s->clear()\n", pName.data() );
376 greet->clear();
377 curUser.clear();
378 if (!scheduleAutoLogin( initial )) {
379 isClear = !(isClear && applyPreset());
380 if (running) {
381 debug( "%s->start()\n", pName.data() );
382 greet->start();
384 if (!failed)
385 timer.stop();
389 void // not a slot - called manually by greeter
390 KGVerify::reject()
392 doReject( true );
395 void
396 KGVerify::setEnabled( bool on )
398 debug( "%s->setEnabled(%s)\n", pName.data(), on ? "true" : "false" );
399 greet->setEnabled( on );
400 enabled = on;
401 updateStatus();
404 void // private
405 KGVerify::slotTimeout()
407 if (failed) {
408 failed = false;
409 updateStatus();
410 debug( "%s->revive()\n", pName.data() );
411 greet->revive();
412 handler->verifyRetry();
413 if (suspended)
414 delayed = true;
415 else {
416 running = true;
417 debug( "%s->start()\n", pName.data() );
418 greet->start();
419 slotActivity();
420 gplugChanged();
421 if (cont)
422 handleVerify();
424 } else if (timedLeft) {
425 deadTicks--;
426 if (!--timedLeft)
427 performAutoLogin();
428 else
429 timer.start( 1000 );
430 updateStatus();
431 } else {
432 // assert( ctx == Login );
433 isClear = true;
434 doReject( false );
438 void
439 KGVerify::slotActivity()
441 if (timedLeft) {
442 // timed login countdown running. cancel and reschedule it.
443 debug( "%s->revive()\n", pName.data() );
444 greet->revive();
445 debug( "%s->start()\n", pName.data() );
446 greet->start();
447 running = true;
448 timedLeft = 0;
449 updateStatus();
450 timer.start( TIMED_GREET_TO * SECONDS );
451 } else if (timeable)
452 // timed login is possible and thus scheduled. reschedule it.
453 timer.start( TIMED_GREET_TO * SECONDS );
457 void // private static
458 KGVerify::vrfMsgBox( QWidget *parent, const QString &user,
459 QMessageBox::Icon type, const QString &mesg )
461 KFMsgBox::box( parent, type, user.isEmpty() ?
462 mesg : i18n("Logging in %1...\n\n", user ) + mesg );
465 static const char *msgs[]= {
466 I18N_NOOP( "You are required to change your password immediately (password aged)." ),
467 I18N_NOOP( "You are required to change your password immediately (root enforced)." ),
468 I18N_NOOP( "You are not allowed to login at the moment." ),
469 I18N_NOOP( "Home folder not available." ),
470 I18N_NOOP( "Logins are not allowed at the moment.\nTry again later." ),
471 I18N_NOOP( "Your login shell is not listed in /etc/shells." ),
472 I18N_NOOP( "Root logins are not allowed." ),
473 I18N_NOOP( "Your account has expired; please contact your system administrator." )
476 void // private static
477 KGVerify::vrfErrBox( QWidget *parent, const QString &user, const char *msg )
479 QMessageBox::Icon icon;
480 QString mesg;
482 if (!msg) {
483 mesg = i18n("A critical error occurred.\n"
484 "Please look at KDM's logfile(s) for more information\n"
485 "or contact your system administrator.");
486 icon = errorbox;
487 } else {
488 mesg = QString::fromLocal8Bit( msg );
489 QString mesg1 = mesg + '.';
490 for (uint i = 0; i < as(msgs); i++)
491 if (mesg1 == msgs[i]) {
492 mesg = i18n(msgs[i]);
493 break;
495 icon = sorrybox;
497 vrfMsgBox( parent, user, icon, mesg );
500 void // private static
501 KGVerify::vrfInfoBox( QWidget *parent, const QString &user, const char *msg )
503 QString mesg = QString::fromLocal8Bit( msg );
504 QRegExp rx( "^Warning: your account will expire in (\\d+) day" );
505 if (rx.indexIn( mesg ) >= 0) {
506 int expire = rx.cap( 1 ).toInt();
507 mesg = expire ?
508 i18np("Your account expires tomorrow.",
509 "Your account expires in %1 days.", expire) :
510 i18n("Your account expires today.");
511 } else {
512 rx.setPattern( "^Warning: your password will expire in (\\d+) day" );
513 if (rx.indexIn( mesg ) >= 0) {
514 int expire = rx.cap( 1 ).toInt();
515 mesg = expire ?
516 i18np("Your password expires tomorrow.",
517 "Your password expires in %1 days.", expire) :
518 i18n("Your password expires today.");
521 vrfMsgBox( parent, user, infobox, mesg );
524 bool // public static
525 KGVerify::handleFailVerify( QWidget *parent, bool showUser )
527 char *msg;
528 QString user;
530 debug( "handleFailVerify ...\n" );
532 if (showUser) {
533 msg = gRecvStr();
534 user = QString::fromLocal8Bit( msg );
535 free( msg );
538 for (;;) {
539 int ret = gRecvInt();
541 // non-terminal status
542 switch (ret) {
543 /* case V_PUT_USER: cannot happen - we are in "classic" mode */
544 /* case V_PRE_OK: cannot happen - not in ChTok dialog */
545 /* case V_CHTOK: cannot happen - called by non-interactive verify */
546 case V_CHTOK_AUTH:
547 debug( " V_CHTOK_AUTH\n" );
549 QStringList pgs( _pluginsLogin );
550 pgs += _pluginsShutdown;
551 foreach (const QString& pg, pgs)
552 if (pg == "classic" || pg == "modern") {
553 pgs = QStringList( pg );
554 goto gotit;
555 } else if (pg == "generic") {
556 pgs = QStringList( "modern" );
557 goto gotit;
559 pgs = QStringList( "classic" );
560 gotit:
561 KGChTok chtok( parent, user, init( pgs ), 0,
562 KGreeterPlugin::AuthChAuthTok,
563 KGreeterPlugin::Login );
564 return chtok.exec();
566 case V_MSG_ERR:
567 debug( " V_MSG_ERR\n" );
568 msg = gRecvStr();
569 debug( " message %\"s\n", msg );
570 vrfErrBox( parent, user, msg );
571 if (msg)
572 free( msg );
573 gSendInt( 0 );
574 continue;
575 case V_MSG_INFO_AUTH: // should not happen
576 case V_MSG_INFO:
577 debug( " V_MSG_INFO\n" );
578 msg = gRecvStr();
579 debug( " message %\"s\n", msg );
580 vrfInfoBox( parent, user, msg );
581 free( msg );
582 gSendInt( 0 );
583 continue;
586 // terminal status
587 switch (ret) {
588 case V_OK:
589 debug( " V_OK\n" );
590 return true;
591 case V_AUTH:
592 debug( " V_AUTH\n" );
593 vrfMsgBox( parent, user, sorrybox, i18n("Authentication failed") );
594 return false;
595 case V_FAIL:
596 debug( " V_FAIL\n" );
597 return false;
598 default:
599 logPanic( "Unknown V_xxx code %d from core\n", ret );
604 void // private
605 KGVerify::handleVerify()
607 QString user;
609 debug( "handleVerify ...\n" );
610 for (;;) {
611 char *msg;
612 int ret, echo, ndelay;
613 KGreeterPlugin::Function nfunc;
615 ret = gRecvInt();
617 // requests
618 coreLock = 1;
619 switch (ret) {
620 case V_GET_TEXT:
621 debug( " V_GET_TEXT\n" );
622 msg = gRecvStr();
623 debug( " prompt %\"s\n", msg );
624 echo = gRecvInt();
625 debug( " echo = %d\n", echo );
626 ndelay = gRecvInt();
627 debug( " ndelay = %d\n%s->textPrompt(...)\n", ndelay, pName.data() );
628 greet->textPrompt( msg, echo, ndelay );
629 if (msg)
630 free( msg );
631 return;
632 case V_GET_BINARY:
633 debug( " V_GET_BINARY\n" );
634 msg = gRecvArr( &ret );
635 debug( " %d bytes prompt\n", ret );
636 ndelay = gRecvInt();
637 debug( " ndelay = %d\n%s->binaryPrompt(...)\n", ndelay, pName.data() );
638 greet->binaryPrompt( msg, ndelay );
639 if (msg)
640 free( msg );
641 return;
644 // non-terminal status
645 coreLock = 2;
646 switch (ret) {
647 case V_PUT_USER:
648 debug( " V_PUT_USER\n" );
649 msg = gRecvStr();
650 curUser = user = QString::fromLocal8Bit( msg );
651 // greet needs this to be able to return something useful from
652 // getEntity(). but the backend is still unable to tell a domain ...
653 debug( " %s->setUser(%\"s)\n", pName.data(), qPrintable( user ) );
654 greet->setUser( curUser );
655 handler->verifySetUser( curUser );
656 if (msg)
657 free( msg );
658 continue;
659 case V_PRE_OK: // this is only for func == AuthChAuthTok
660 debug( " V_PRE_OK\n" );
661 // With the "classic" method, the wrong user simply cannot be
662 // authenticated, even with the generic plugin. Other methods
663 // could do so, but this applies only to ctx == ChangeTok, which
664 // is not implemented yet.
665 authTok = true;
666 cont = true;
667 debug( "%s->succeeded()\n", pName.data() );
668 greet->succeeded();
669 continue;
670 case V_CHTOK_AUTH:
671 debug( " V_CHTOK_AUTH\n" );
672 nfunc = KGreeterPlugin::AuthChAuthTok;
673 user = curUser;
674 goto dchtok;
675 case V_CHTOK:
676 debug( " V_CHTOK\n" );
677 nfunc = KGreeterPlugin::ChAuthTok;
678 user.clear();
679 dchtok:
681 timer.stop();
682 debug( "%s->succeeded()\n", pName.data() );
683 greet->succeeded();
684 KGChTok chtok( parent, user, pluginList, curPlugin, nfunc, KGreeterPlugin::Login );
685 if (!chtok.exec())
686 goto retry;
687 handler->verifyOk();
688 return;
690 case V_MSG_ERR:
691 debug( " V_MSG_ERR\n" );
692 msg = gRecvStr();
693 debug( " %s->textMessage(%\"s, true)\n", pName.data(), msg );
694 if (!greet->textMessage( msg, true )) { // XXX little point in filtering
695 debug( " message passed\n" );
696 vrfErrBox( parent, user, msg );
697 } else
698 debug( " message swallowed\n" );
699 if (msg)
700 free( msg );
701 gSendInt( 0 );
702 continue;
703 case V_MSG_INFO_AUTH:
704 debug( " V_MSG_INFO_AUTH\n" );
705 msg = gRecvStr();
706 debug( " %s->textMessage(%\"s, false)\n", pName.data(), msg );
707 if (!greet->textMessage( msg, false )) {
708 debug( " message passed\n" );
709 vrfInfoBox( parent, user, msg );
710 } else
711 debug( " message swallowed\n" );
712 free( msg );
713 gSendInt( 0 );
714 continue;
715 case V_MSG_INFO:
716 debug( " V_MSG_INFO\n" );
717 msg = gRecvStr();
718 debug( " display %\"s\n", msg );
719 vrfInfoBox( parent, user, msg );
720 free( msg );
721 gSendInt( 0 );
722 continue;
725 // terminal status
726 coreLock = 0;
727 running = false;
728 timer.stop();
730 if (ret == V_OK) {
731 debug( " V_OK\n" );
732 if (!fixedEntity.isEmpty()) {
733 debug( " %s->getEntity()\n", pName.data() );
734 QString ent = greet->getEntity();
735 debug( " entity %\"s\n", qPrintable( ent ) );
736 if (ent != fixedEntity) {
737 debug( "%s->failed()\n", pName.data() );
738 greet->failed();
739 msgBox( sorrybox,
740 i18n("Authenticated user (%1) does not match requested user (%2).\n",
741 ent, fixedEntity ) );
742 goto retry;
745 debug( "%s->succeeded()\n", pName.data() );
746 greet->succeeded();
747 handler->verifyOk();
748 return;
751 debug( "%s->failed()\n", pName.data() );
752 greet->failed();
754 if (ret == V_AUTH) {
755 debug( " V_AUTH\n" );
756 failed = true;
757 updateStatus();
758 handler->verifyFailed();
759 timer.start( 1500 + KRandom::random()/(RAND_MAX/1000) );
760 return;
762 if (ret != V_FAIL)
763 logPanic( "Unknown V_xxx code %d from core\n", ret );
764 debug( " V_FAIL\n" );
765 retry:
766 debug( "%s->revive()\n", pName.data() );
767 greet->revive();
768 running = true;
769 debug( "%s->start()\n", pName.data() );
770 greet->start();
771 if (!cont)
772 return;
773 user.clear();
777 void
778 KGVerify::gplugReturnText( const char *text, int tag )
780 debug( "%s: gplugReturnText(%\"s, %d)\n", pName.data(),
781 tag & V_IS_SECRET ? "<masked>" : text, tag );
782 gSendStr( text );
783 if (text) {
784 gSendInt( tag );
785 handleVerify();
786 } else
787 coreLock = 0;
790 void
791 KGVerify::gplugReturnBinary( const char *data )
793 if (data) {
794 unsigned const char *up = (unsigned const char *)data;
795 int len = up[3] | (up[2] << 8) | (up[1] << 16) | (up[0] << 24);
796 debug( "%s: gplugReturnBinary(%d bytes)\n", pName.data(), len );
797 gSendArr( len, data );
798 handleVerify();
799 } else {
800 debug( "%s: gplugReturnBinary(NULL)\n", pName.data() );
801 gSendArr( 0, 0 );
802 coreLock = 0;
806 void
807 KGVerify::gplugSetUser( const QString &user )
809 debug( "%s: gplugSetUser(%\"s)\n", pName.data(), qPrintable( user ) );
810 curUser = user;
811 handler->verifySetUser( user );
814 void
815 KGVerify::gplugStart()
817 // XXX handle func != Authenticate
818 if (cont)
819 return;
820 debug( "%s: gplugStart()\n", pName.data() );
821 gSendInt( ctx == KGreeterPlugin::Shutdown ? G_VerifyRootOK : G_Verify );
822 gSendStr( greetPlugins[pluginList[curPlugin]].info->method );
823 handleVerify();
826 void
827 KGVerify::gplugChanged()
829 debug( "%s: gplugChanged()\n", pName.data() );
830 if (func == KGreeterPlugin::Authenticate &&
831 ctx == KGreeterPlugin::Login)
833 isClear = false;
834 if (!timeable)
835 timer.start( FULL_GREET_TO * SECONDS );
839 void
840 KGVerify::gplugActivity()
842 debug( "%s: gplugActivity()\n", pName.data() );
843 slotActivity();
846 void
847 KGVerify::gplugMsgBox( QMessageBox::Icon type, const QString &text )
849 debug( "%s: gplugMsgBox(%d, %\"s)\n", pName.data(), type, qPrintable( text ) );
850 msgBox( type, text );
853 bool
854 KGVerify::eventFilter( QObject *o, QEvent *e )
856 switch (e->type()) {
857 case QEvent::KeyPress:
858 if (timedLeft) {
859 QKeyEvent *ke = (QKeyEvent *)e;
860 if (ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter) {
861 if (deadTicks <= 0) {
862 timedLeft = 0;
863 performAutoLogin();
865 return true;
868 /* fall through */
869 case QEvent::KeyRelease:
870 updateLockStatus();
871 /* fall through */
872 default:
873 break;
875 return inherited::eventFilter( o, e );
878 void
879 KGVerify::updateLockStatus()
881 unsigned int lmask;
882 Window dummy1, dummy2;
883 int dummy3, dummy4, dummy5, dummy6;
884 XQueryPointer( QX11Info::display(), DefaultRootWindow( QX11Info::display() ),
885 &dummy1, &dummy2, &dummy3, &dummy4, &dummy5, &dummy6,
886 &lmask );
887 capsLocked = lmask & LockMask;
888 updateStatus();
891 void
892 KGVerify::msgBox( QMessageBox::Icon typ, const QString &msg )
894 timer.suspend();
895 KFMsgBox::box( parent, typ, msg );
896 timer.resume();
900 QVariant // public static
901 KGVerify::getConf( void *, const char *key, const QVariant &dflt )
903 if (!qstrcmp( key, "EchoPasswd" ))
904 return QVariant( _echoPasswd );
905 else {
906 QString fkey = QString::fromLatin1( key ) + '=';
907 foreach (const QString& pgo, _pluginOptions)
908 if (pgo.startsWith( fkey ))
909 return pgo.mid( fkey.length() );
910 return dflt;
914 QVector<GreeterPluginHandle> KGVerify::greetPlugins;
916 PluginList
917 KGVerify::init( const QStringList &plugins )
919 PluginList pluginList;
921 foreach (const QString& pg, plugins) {
922 GreeterPluginHandle plugin;
923 KLibrary *lib = new KLibrary( pg[0] == '/' ? pg : "kgreet_" + pg );
924 if (lib->fileName().isEmpty()) {
925 logError( "GreeterPlugin %s does not exist\n", qPrintable( pg ) );
926 delete lib;
927 continue;
929 uint i, np = greetPlugins.count();
930 for (i = 0; i < np; i++)
931 if (greetPlugins[i].library->fileName() == lib->fileName()) {
932 delete lib;
933 goto next;
935 if (!lib->load()) {
936 logError( "Cannot load GreeterPlugin %s (%s)\n",
937 qPrintable( pg ), qPrintable( lib->fileName() ) );
938 delete lib;
939 continue;
941 plugin.library = lib;
942 plugin.info = (KGreeterPluginInfo *)lib->resolveSymbol( "kgreeterplugin_info" );
943 if (!plugin.info) {
944 logError( "GreeterPlugin %s (%s) is no valid greet widget plugin\n",
945 qPrintable( pg ), qPrintable( lib->fileName() ) );
946 lib->unload();
947 delete lib;
948 continue;
951 if (!plugin.info->init( QString(), getConf, 0 )) {
952 logError( "GreeterPlugin %s (%s) refuses to serve\n",
953 qPrintable( pg ), qPrintable( lib->fileName() ) );
954 lib->unload();
955 delete lib;
956 continue;
958 debug( "GreeterPlugin %s (%s) loaded\n", qPrintable( pg ), plugin.info->name );
959 greetPlugins.append( plugin );
960 next:
961 pluginList.append( i );
963 return pluginList;
966 void
967 KGVerify::done()
969 for (int i = 0; i < greetPlugins.count(); i++) {
970 if (greetPlugins[i].info->done)
971 greetPlugins[i].info->done();
972 greetPlugins[i].library->unload();
977 KGStdVerify::KGStdVerify( KGVerifyHandler *_handler, QWidget *_parent,
978 QWidget *_predecessor, const QString &_fixedUser,
979 const PluginList &_pluginList,
980 KGreeterPlugin::Function _func,
981 KGreeterPlugin::Context _ctx )
982 : inherited( _handler, _parent, _predecessor, _fixedUser,
983 _pluginList, _func, _ctx )
984 , failedLabelState( 0 )
986 grid = new QGridLayout;
987 grid->setAlignment( Qt::AlignCenter );
989 failedLabel = new QLabel( parent );
990 failedLabel->setFont( *_failFont );
991 grid->addWidget( failedLabel, 1, 0, Qt::AlignCenter );
993 updateLockStatus();
996 KGStdVerify::~KGStdVerify()
1000 bool
1001 KGStdVerify::gplugHasNode( const QString & )
1003 return false;
1006 void // public
1007 KGStdVerify::selectPlugin( int id )
1009 inherited::selectPlugin( id );
1010 QWidget *w = greet->getWidgets().first();
1011 grid->addWidget( w, 0, 0 );
1012 w->show();
1015 void
1016 KGStdVerify::updateStatus()
1018 int nfls;
1020 if (!enabled)
1021 nfls = 1;
1022 else if (failed)
1023 nfls = 2;
1024 else if (timedLeft)
1025 nfls = -timedLeft;
1026 else if (!suspended && capsLocked)
1027 nfls = 3;
1028 else
1029 nfls = 1;
1031 if (failedLabelState != nfls) {
1032 failedLabelState = nfls;
1033 QPalette p;
1034 if (nfls < 0) {
1035 failedLabel->setText( i18np( "Automatic login in 1 second...",
1036 "Automatic login in %1 seconds...",
1037 timedLeft ) );
1038 } else {
1039 switch (nfls) {
1040 default:
1041 failedLabel->clear();
1042 break;
1043 case 3:
1044 p.setBrush( QPalette::WindowText,
1045 KColorScheme( QPalette::Active, KColorScheme::Window )
1046 .foreground( KColorScheme::NegativeText ) );
1047 failedLabel->setText( i18n("Warning: Caps Lock is on") );
1048 break;
1049 case 2:
1050 failedLabel->setText( authTok ?
1051 i18n("Change failed") :
1052 fixedEntity.isEmpty() ?
1053 i18n("Login failed") :
1054 i18n("Authentication failed") );
1055 break;
1058 failedLabel->setPalette( p );
1062 KGThemedVerify::KGThemedVerify( KGVerifyHandler *_handler,
1063 KdmThemer *_themer,
1064 QWidget *_parent, QWidget *_predecessor,
1065 const QString &_fixedUser,
1066 const PluginList &_pluginList,
1067 KGreeterPlugin::Function _func,
1068 KGreeterPlugin::Context _ctx )
1069 : inherited( _handler, _parent, _predecessor, _fixedUser,
1070 _pluginList, _func, _ctx )
1071 , themer( _themer )
1073 updateLockStatus();
1076 KGThemedVerify::~KGThemedVerify()
1080 bool
1081 KGThemedVerify::gplugHasNode( const QString &id )
1083 return themer->findNode( id ) != 0;
1086 void // public
1087 KGThemedVerify::selectPlugin( int id )
1089 if (curPlugin != -1)
1090 themer->setTypeVisible( QString( "plugin-specific-" ).append( pluginName() ), false );
1091 inherited::selectPlugin( id );
1092 themer->setTypeVisible( QString( "plugin-specific-" ).append( pluginName() ), true );
1093 QSet<QString> oldTypes = showTypes;
1094 showTypes.clear();
1095 foreach (QWidget *w, greet->getWidgets())
1096 if (KdmItem *n = themer->findNode( w->objectName() )) {
1097 QString tn( QString( "plugin-" ).append( w->objectName() ) );
1098 themer->setTypeVisible( tn, true );
1099 showTypes.insert( tn );
1100 oldTypes.remove( tn );
1101 n->setWidget( w );
1102 } else {
1103 msgBox( errorbox,
1104 i18n( "Theme not usable with authentication method '%1'.",
1105 i18n( greetPlugins[pluginList[id]].info->name ) ) );
1106 break;
1108 foreach (const QString& t, oldTypes)
1109 themer->setTypeVisible( t, false );
1112 void
1113 KGThemedVerify::updateStatus()
1115 handler->updateStatus( enabled && failed,
1116 enabled && !suspended && capsLocked,
1117 timedLeft );
1121 KGChTok::KGChTok( QWidget *_parent, const QString &user,
1122 const PluginList &pluginList, int curPlugin,
1123 KGreeterPlugin::Function func,
1124 KGreeterPlugin::Context ctx )
1125 : inherited( _parent )
1126 , verify( 0 )
1128 QSizePolicy fp( QSizePolicy::Fixed, QSizePolicy::Fixed );
1129 okButton = new KPushButton( KStandardGuiItem::ok(), this );
1130 okButton->setSizePolicy( fp );
1131 okButton->setDefault( true );
1132 cancelButton = new KPushButton( KStandardGuiItem::cancel(), this );
1133 cancelButton->setSizePolicy( fp );
1135 verify = new KGStdVerify( this, this, cancelButton, user, pluginList, func, ctx );
1136 verify->selectPlugin( curPlugin );
1138 QVBoxLayout *box = new QVBoxLayout( this );
1140 box->addWidget( new QLabel( i18nc("@title:window",
1141 "<qt><b>Changing authentication token</b></qt>"),
1142 this ), 0, Qt::AlignHCenter|Qt::AlignTop );
1144 box->addLayout( verify->getLayout() );
1146 box->addWidget( new KSeparator( Qt::Horizontal, this ) );
1148 QHBoxLayout *hlay = new QHBoxLayout();
1149 box->addLayout( hlay );
1150 hlay->addStretch( 1 );
1151 hlay->addWidget( okButton );
1152 hlay->addStretch( 1 );
1153 hlay->addWidget( cancelButton );
1154 hlay->addStretch( 1 );
1156 connect( okButton, SIGNAL(clicked()), SLOT(accept()) );
1157 connect( cancelButton, SIGNAL(clicked()), SLOT(reject()) );
1159 QTimer::singleShot( 0, verify, SLOT(start()) );
1162 KGChTok::~KGChTok()
1164 hide();
1165 delete verify;
1168 void
1169 KGChTok::accept()
1171 verify->accept();
1174 void
1175 KGChTok::verifyPluginChanged( int )
1177 // cannot happen
1180 void
1181 KGChTok::verifyOk()
1183 inherited::accept();
1186 void
1187 KGChTok::verifyFailed()
1189 okButton->setEnabled( false );
1190 cancelButton->setEnabled( false );
1193 void
1194 KGChTok::verifyRetry()
1196 okButton->setEnabled( true );
1197 cancelButton->setEnabled( true );
1200 void
1201 KGChTok::verifySetUser( const QString & )
1203 // cannot happen
1207 ////// helper class, nuke when qtimer supports suspend()/resume()
1209 QXTimer::QXTimer()
1210 : inherited( 0 )
1211 , left( -1 )
1213 connect( &timer, SIGNAL(timeout()), SLOT(slotTimeout()) );
1216 void
1217 QXTimer::start( int msec )
1219 left = msec;
1220 timer.setSingleShot( true );
1221 timer.start( left );
1222 gettimeofday( &stv, 0 );
1225 void
1226 QXTimer::stop()
1228 timer.stop();
1229 left = -1;
1232 void
1233 QXTimer::suspend()
1235 if (timer.isActive()) {
1236 timer.stop();
1237 struct timeval tv;
1238 gettimeofday( &tv, 0 );
1239 left -= (tv.tv_sec - stv.tv_sec) * 1000 + (tv.tv_usec - stv.tv_usec) / 1000;
1240 if (left < 0)
1241 left = 0;
1245 void
1246 QXTimer::resume()
1248 if (left >= 0 && !timer.isActive()) {
1249 timer.setSingleShot( true );
1250 timer.start( left );
1251 gettimeofday( &stv, 0 );
1255 void
1256 QXTimer::slotTimeout()
1258 left = 0;
1259 emit timeout();
1263 #include "kgverify.moc"