add more spacing
[personal-kdebase.git] / workspace / libs / kdm / kgreet_winbind.cpp
blob8d650957f731d24ee4abfc6e6617bcc5572e28fb
1 /*
3 Conversation widget for kdm greeter
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 "kgreet_winbind.h"
26 #include "themer/kdmthemer.h"
27 #include "themer/kdmitem.h"
29 #include <klocale.h>
30 #include <kglobal.h>
31 #include <kdebug.h>
32 #include <kcombobox.h>
33 #include <klineedit.h>
34 #include <kuser.h>
35 #include <kprocess.h>
37 #include <QRegExp>
38 #include <QLayout>
39 #include <QLabel>
40 #include <QContextMenuEvent>
41 #include <QGridLayout>
42 #include <QTextStream>
44 #include <stdlib.h>
45 #include <stdio.h>
47 static int echoMode;
49 class KDMPasswordEdit : public KLineEdit {
50 public:
51 KDMPasswordEdit( QWidget *parent ) : KLineEdit( parent )
53 if (::echoMode == -1)
54 setPasswordMode(true);
55 else
56 setEchoMode( ::echoMode ? Password : NoEcho );
57 setContextMenuPolicy( Qt::NoContextMenu );
61 static char separator;
62 static QStringList staticDomains;
63 static QString defaultDomain;
65 static void
66 splitEntity( const QString &ent, QString &dom, QString &usr )
68 int pos = ent.indexOf( separator );
69 if (pos < 0)
70 dom = "<local>", usr = ent;
71 else
72 dom = ent.left( pos ), usr = ent.mid( pos + 1 );
75 KWinbindGreeter::KWinbindGreeter( KGreeterPluginHandler *_handler,
76 QWidget *parent,
77 const QString &_fixedEntity,
78 Function _func, Context _ctx ) :
79 QObject(),
80 KGreeterPlugin( _handler ),
81 func( _func ),
82 ctx( _ctx ),
83 exp( -1 ),
84 pExp( -1 ),
85 running( false )
87 QGridLayout *grid = 0;
89 int line = 0;
91 if (!_handler->gplugHasNode( "domain-entry" ) ||
92 !_handler->gplugHasNode( "user-entry" ) ||
93 !_handler->gplugHasNode( "pw-entry" ))
95 parent = new QWidget( parent );
96 parent->setObjectName( "talker" );
97 widgetList << parent;
98 grid = new QGridLayout( parent );
99 grid->setMargin( 0 );
102 domainLabel = loginLabel = passwdLabel = passwd1Label = passwd2Label = 0;
103 domainCombo = 0;
104 loginEdit = 0;
105 passwdEdit = passwd1Edit = passwd2Edit = 0;
106 if (ctx == ExUnlock || ctx == ExChangeTok)
107 splitEntity( KUser().loginName(), fixedDomain, fixedUser );
108 else
109 splitEntity( _fixedEntity, fixedDomain, fixedUser );
110 if (func != ChAuthTok) {
111 if (fixedUser.isEmpty()) {
112 domainCombo = new KComboBox( parent );
113 connect( domainCombo, SIGNAL(activated( const QString & )),
114 SLOT(slotChangedDomain( const QString & )) );
115 connect( domainCombo, SIGNAL(activated( const QString & )),
116 SLOT(slotLoginLostFocus()) );
117 connect( domainCombo, SIGNAL(activated( const QString & )),
118 SLOT(slotChanged()) );
119 // should handle loss of focus
120 loginEdit = new KLineEdit( parent );
121 loginEdit->setContextMenuPolicy( Qt::NoContextMenu );
123 if (!grid) {
124 loginEdit->setObjectName( "user-entry" );
125 domainCombo->setObjectName( "domain-entry" );
126 widgetList << domainCombo << loginEdit;
127 } else {
128 domainLabel = new QLabel( i18n("&Domain:"), parent );
129 domainLabel->setBuddy( domainCombo );
130 loginLabel = new QLabel( i18n("&Username:"), parent );
131 loginLabel->setBuddy( loginEdit );
132 grid->addWidget( domainLabel, line, 0 );
133 grid->addWidget( domainCombo, line++, 1 );
134 grid->addWidget( loginLabel, line, 0 );
135 grid->addWidget( loginEdit, line++, 1 );
137 connect( loginEdit, SIGNAL(editingFinished()), SLOT(slotLoginLostFocus()) );
138 connect( loginEdit, SIGNAL(editingFinished()), SLOT(slotChanged()) );
139 connect( loginEdit, SIGNAL(textChanged( const QString & )), SLOT(slotChanged()) );
140 connect( loginEdit, SIGNAL(selectionChanged()), SLOT(slotChanged()) );
141 domainCombo->addItems( staticDomains );
142 QTimer::singleShot( 0, this, SLOT(slotStartDomainList()) );
143 } else if (ctx != Login && ctx != Shutdown && grid) {
144 domainLabel = new QLabel( i18n("Domain:"), parent );
145 grid->addWidget( domainLabel, line, 0 );
146 grid->addWidget( new QLabel( fixedDomain, parent ), line++, 1 );
147 loginLabel = new QLabel( i18n("Username:"), parent );
148 grid->addWidget( loginLabel, line, 0 );
149 grid->addWidget( new QLabel( fixedUser, parent ), line++, 1 );
151 passwdEdit = new KDMPasswordEdit( parent );
152 connect( passwdEdit, SIGNAL(textChanged( const QString & )),
153 SLOT(slotChanged()) );
154 connect( passwdEdit, SIGNAL(editingFinished()), SLOT(slotChanged()) );
156 if (!grid) {
157 passwdEdit->setObjectName( "pw-entry" );
158 widgetList << passwdEdit;
159 } else {
160 passwdLabel = new QLabel( func == Authenticate ?
161 i18n("&Password:") :
162 i18n("Current &password:"),
163 parent );
164 passwdLabel->setBuddy( passwdEdit );
165 grid->addWidget( passwdLabel, line, 0 );
166 grid->addWidget( passwdEdit, line++, 1 );
169 if (loginEdit)
170 loginEdit->setFocus();
171 else
172 passwdEdit->setFocus();
174 if (func != Authenticate) {
175 passwd1Edit = new KDMPasswordEdit( parent );
176 passwd1Label = new QLabel( i18n("&New password:"), parent );
177 passwd1Label->setBuddy( passwd1Edit );
178 passwd2Edit = new KDMPasswordEdit( parent );
179 passwd2Label = new QLabel( i18n("Con&firm password:"), parent );
180 passwd2Label->setBuddy( passwd2Edit );
181 if (grid) {
182 grid->addWidget( passwd1Label, line, 0 );
183 grid->addWidget( passwd1Edit, line++, 1 );
184 grid->addWidget( passwd2Label, line, 0 );
185 grid->addWidget( passwd2Edit, line, 1 );
187 if (!passwdEdit)
188 passwd1Edit->setFocus();
192 // virtual
193 KWinbindGreeter::~KWinbindGreeter()
195 abort();
196 qDeleteAll( widgetList );
199 void
200 KWinbindGreeter::slotChangedDomain( const QString &dom )
202 if (!loginEdit->completionObject())
203 return;
204 QStringList users;
205 if (dom == "<local>") {
206 for (QStringList::ConstIterator it = allUsers.constBegin(); it != allUsers.constEnd(); ++it)
207 if ((*it).indexOf( separator ) < 0)
208 users << *it;
209 } else {
210 QString st( dom + separator );
211 for (QStringList::ConstIterator it = allUsers.constBegin(); it != allUsers.constEnd(); ++it)
212 if ((*it).startsWith( st ))
213 users << (*it).mid( st.length() );
215 loginEdit->completionObject()->setItems( users );
218 void // virtual
219 KWinbindGreeter::loadUsers( const QStringList &users )
221 allUsers = users;
222 KCompletion *userNamesCompletion = new KCompletion;
223 loginEdit->setCompletionObject( userNamesCompletion );
224 loginEdit->setAutoDeleteCompletionObject( true );
225 loginEdit->setCompletionMode( KGlobalSettings::CompletionAuto );
226 slotChangedDomain( defaultDomain );
229 void // virtual
230 KWinbindGreeter::presetEntity( const QString &entity, int field )
232 QString dom, usr;
233 splitEntity( entity, dom, usr );
234 domainCombo->setCurrentItem( dom, true );
235 slotChangedDomain( dom );
236 loginEdit->setText( usr );
237 if (field > 1)
238 passwdEdit->setFocus();
239 else if (field == 1 || field == -1) {
240 if (field == -1) {
241 passwdEdit->setText( " " );
242 passwdEdit->setEnabled( false );
243 authTok = false;
245 loginEdit->setFocus();
246 loginEdit->selectAll();
248 curUser = entity;
251 QString // virtual
252 KWinbindGreeter::getEntity() const
254 QString dom, usr;
255 if (fixedUser.isEmpty()) {
256 dom = domainCombo->currentText();
257 usr = loginEdit->text().trimmed();
258 loginEdit->setText( usr );
259 } else {
260 dom = fixedDomain;
261 usr = fixedUser;
263 return dom == "<local>" ? usr : dom + separator + usr;
266 void // virtual
267 KWinbindGreeter::setUser( const QString &user )
269 // assert (fixedUser.isEmpty());
270 curUser = user;
271 QString dom, usr;
272 splitEntity( user, dom, usr );
273 domainCombo->setCurrentItem( dom, true );
274 slotChangedDomain( dom );
275 loginEdit->setText( usr );
276 passwdEdit->setFocus();
277 passwdEdit->selectAll();
280 void // virtual
281 KWinbindGreeter::setEnabled( bool enable )
283 // assert( !passwd1Label );
284 // assert( func == Authenticate && ctx == Shutdown );
285 // if (domainCombo)
286 // domainCombo->setEnabled( enable );
287 // if (loginLabel)
288 // loginLabel->setEnabled( enable );
289 passwdLabel->setEnabled( enable );
290 setActive( enable );
291 if (enable)
292 passwdEdit->setFocus();
295 void // private
296 KWinbindGreeter::returnData()
298 switch (exp) {
299 case 0:
300 handler->gplugReturnText( getEntity().toLocal8Bit(),
301 KGreeterPluginHandler::IsUser );
302 break;
303 case 1:
304 handler->gplugReturnText( passwdEdit->text().toLocal8Bit(),
305 KGreeterPluginHandler::IsPassword |
306 KGreeterPluginHandler::IsSecret );
307 break;
308 case 2:
309 handler->gplugReturnText( passwd1Edit->text().toLocal8Bit(),
310 KGreeterPluginHandler::IsSecret );
311 break;
312 default: // case 3:
313 handler->gplugReturnText( passwd2Edit->text().toLocal8Bit(),
314 KGreeterPluginHandler::IsNewPassword |
315 KGreeterPluginHandler::IsSecret );
316 break;
320 bool // virtual
321 KWinbindGreeter::textMessage( const char *text, bool err )
323 if (!err &&
324 QString( text ).indexOf( QRegExp( "^Changing password for [^ ]+$" ) ) >= 0)
325 return true;
326 return false;
329 void // virtual
330 KWinbindGreeter::textPrompt( const char *prompt, bool echo, bool nonBlocking )
332 pExp = exp;
333 if (echo)
334 exp = 0;
335 else if (!authTok)
336 exp = 1;
337 else {
338 QString pr( prompt );
339 if (pr.indexOf( QRegExp( "\\b(old|current)\\b", Qt::CaseInsensitive ) ) >= 0) {
340 handler->gplugReturnText( "",
341 KGreeterPluginHandler::IsOldPassword |
342 KGreeterPluginHandler::IsSecret );
343 return;
344 } else if (pr.indexOf( QRegExp( "\\b(re-?(enter|type)|again|confirm|repeat)\\b",
345 Qt::CaseInsensitive ) ) >= 0)
346 exp = 3;
347 else if (pr.indexOf( QRegExp( "\\bnew\\b", Qt::CaseInsensitive ) ) >= 0)
348 exp = 2;
349 else {
350 handler->gplugMsgBox( QMessageBox::Critical,
351 i18n("Unrecognized prompt \"%1\"",
352 prompt ) );
353 handler->gplugReturnText( 0, 0 );
354 exp = -1;
355 return;
359 if (pExp >= 0 && pExp >= exp) {
360 revive();
361 has = -1;
364 if (has >= exp || nonBlocking)
365 returnData();
368 bool // virtual
369 KWinbindGreeter::binaryPrompt( const char *, bool )
371 // this simply cannot happen ... :}
372 return true;
375 void // virtual
376 KWinbindGreeter::start()
378 authTok = !(passwdEdit && passwdEdit->isEnabled());
379 exp = has = -1;
380 running = true;
383 void // virtual
384 KWinbindGreeter::suspend()
388 void // virtual
389 KWinbindGreeter::resume()
393 void // virtual
394 KWinbindGreeter::next()
396 // assert( running );
397 if (domainCombo && domainCombo->hasFocus())
398 loginEdit->setFocus();
399 else if (loginEdit && loginEdit->hasFocus()) {
400 passwdEdit->setFocus(); // will cancel running login if necessary
401 has = 0;
402 } else if (passwdEdit && passwdEdit->hasFocus()) {
403 if (passwd1Edit)
404 passwd1Edit->setFocus();
405 has = 1;
406 } else if (passwd1Edit) {
407 if (passwd1Edit->hasFocus()) {
408 passwd2Edit->setFocus();
409 has = 1; // sic!
410 } else
411 has = 3;
412 } else
413 has = 1;
414 if (exp < 0)
415 handler->gplugStart();
416 else if (has >= exp)
417 returnData();
420 void // virtual
421 KWinbindGreeter::abort()
423 running = false;
424 if (exp >= 0) {
425 exp = -1;
426 handler->gplugReturnText( 0, 0 );
430 void // virtual
431 KWinbindGreeter::succeeded()
433 // assert( running || timed_login );
434 if (!authTok) {
435 setActive( false );
436 if (passwd1Edit) {
437 authTok = true;
438 return;
440 } else
441 setActive2( false );
442 exp = -1;
443 running = false;
446 void // virtual
447 KWinbindGreeter::failed()
449 // assert( running || timed_login );
450 setActive( false );
451 setActive2( false );
452 exp = -1;
453 running = false;
456 void // virtual
457 KWinbindGreeter::revive()
459 // assert( !running );
460 setActive2( true );
461 if (authTok) {
462 passwd1Edit->clear();
463 passwd2Edit->clear();
464 passwd1Edit->setFocus();
465 } else {
466 passwdEdit->clear();
467 if (loginEdit && loginEdit->isEnabled())
468 passwdEdit->setEnabled( true );
469 else {
470 setActive( true );
471 if (loginEdit && loginEdit->text().isEmpty())
472 loginEdit->setFocus();
473 else
474 passwdEdit->setFocus();
479 void // virtual
480 KWinbindGreeter::clear()
482 // assert( !running && !passwd1Edit );
483 passwdEdit->clear();
484 if (loginEdit) {
485 domainCombo->setCurrentItem( defaultDomain );
486 slotChangedDomain( defaultDomain );
487 loginEdit->clear();
488 loginEdit->setFocus();
489 curUser.clear();
490 } else
491 passwdEdit->setFocus();
495 // private
497 void
498 KWinbindGreeter::setActive( bool enable )
500 if (domainCombo)
501 domainCombo->setEnabled( enable );
502 if (loginEdit)
503 loginEdit->setEnabled( enable );
504 if (passwdEdit)
505 passwdEdit->setEnabled( enable );
508 void
509 KWinbindGreeter::setActive2( bool enable )
511 if (passwd1Edit) {
512 passwd1Edit->setEnabled( enable );
513 passwd2Edit->setEnabled( enable );
517 void
518 KWinbindGreeter::slotLoginLostFocus()
520 if (!running)
521 return;
522 QString ent( getEntity() );
523 if (exp > 0) {
524 if (curUser == ent)
525 return;
526 exp = -1;
527 handler->gplugReturnText( 0, 0 );
529 curUser = ent;
530 handler->gplugSetUser( curUser );
533 void
534 KWinbindGreeter::slotChanged()
536 if (running)
537 handler->gplugChanged();
540 void
541 KWinbindGreeter::slotStartDomainList()
543 m_domainLister = new KProcess( this );
544 (*m_domainLister) << "wbinfo" << "--own-domain" << "--trusted-domains";
545 m_domainLister->setOutputChannelMode( KProcess::OnlyStdoutChannel );
546 connect( m_domainLister, SIGNAL(finished( int, QProcess::ExitStatus )),
547 SLOT(slotEndDomainList()) );
548 m_domainLister->start();
551 void
552 KWinbindGreeter::slotEndDomainList()
554 QStringList domainList;
556 while (!m_domainLister->atEnd()) {
557 QString dom = m_domainLister->readLine();
558 dom.chop( 1 );
559 if (!staticDomains.contains( dom ))
560 domainList.append( dom );
563 delete m_domainLister;
565 for (int i = domainCombo->count(), min = staticDomains.count(); --i >= min; ) {
566 int dli = domainList.indexOf( domainCombo->itemText( i ) );
567 if (dli < 0) {
568 if (i == domainCombo->currentIndex())
569 domainCombo->setCurrentItem( defaultDomain );
570 domainCombo->removeItem( i );
571 } else
572 domainList.removeAt( dli );
574 domainCombo->addItems( domainList );
576 QTimer::singleShot( 5 * 1000, this, SLOT(slotStartDomainList()) );
579 // factory
581 static bool init( const QString &,
582 QVariant (*getConf)( void *, const char *, const QVariant & ),
583 void *ctx )
585 echoMode = getConf( ctx, "EchoPasswd", QVariant( -1 ) ).toInt();
587 staticDomains = getConf( ctx, "winbind.Domains", QVariant( "" ) ).toString().split( ':', QString::SkipEmptyParts );
588 if (!staticDomains.size())
589 staticDomains << "<local>";
590 defaultDomain = getConf( ctx, "winbind.DefaultDomain", QVariant( staticDomains.first() ) ).toString();
591 QString sepstr = getConf( ctx, "winbind.Separator", QVariant( QString() ) ).toString();
592 if (sepstr.isNull()) {
593 FILE *sepfile = popen( "wbinfo --separator 2>/dev/null", "r" );
594 if (sepfile) {
595 QTextStream( sepfile ) >> sepstr;
596 if (pclose( sepfile ))
597 sepstr = "\\";
598 } else
599 sepstr = "\\";
601 separator = sepstr[0].toLatin1();
603 KGlobal::locale()->insertCatalog( "kgreet_winbind" );
604 return true;
607 static void done( void )
609 KGlobal::locale()->removeCatalog( "kgreet_winbind" );
610 // avoid static deletion problems ... hopefully
611 staticDomains.clear();
612 defaultDomain.clear();
615 static KGreeterPlugin *
616 create( KGreeterPluginHandler *handler,
617 QWidget *parent,
618 const QString &fixedEntity,
619 KGreeterPlugin::Function func,
620 KGreeterPlugin::Context ctx )
622 return new KWinbindGreeter( handler, parent, fixedEntity, func, ctx );
625 KDE_EXPORT KGreeterPluginInfo kgreeterplugin_info = {
626 I18N_NOOP2("@item:inmenu authentication method", "Winbind / Samba"), "classic",
627 KGreeterPluginInfo::Local | KGreeterPluginInfo::Fielded | KGreeterPluginInfo::Presettable,
628 init, done, create
631 #include "kgreet_winbind.moc"