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"
32 #include <kcombobox.h>
33 #include <klineedit.h>
40 #include <QContextMenuEvent>
41 #include <QGridLayout>
42 #include <QTextStream>
49 class KDMPasswordEdit
: public KLineEdit
{
51 KDMPasswordEdit( QWidget
*parent
) : KLineEdit( parent
)
54 setPasswordMode(true);
56 setEchoMode( ::echoMode
? Password
: NoEcho
);
57 setContextMenuPolicy( Qt::NoContextMenu
);
61 static char separator
;
62 static QStringList staticDomains
;
63 static QString defaultDomain
;
66 splitEntity( const QString
&ent
, QString
&dom
, QString
&usr
)
68 int pos
= ent
.indexOf( separator
);
70 dom
= "<local>", usr
= ent
;
72 dom
= ent
.left( pos
), usr
= ent
.mid( pos
+ 1 );
75 KWinbindGreeter::KWinbindGreeter( KGreeterPluginHandler
*_handler
,
77 const QString
&_fixedEntity
,
78 Function _func
, Context _ctx
) :
80 KGreeterPlugin( _handler
),
87 QGridLayout
*grid
= 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" );
98 grid
= new QGridLayout( parent
);
102 domainLabel
= loginLabel
= passwdLabel
= passwd1Label
= passwd2Label
= 0;
105 passwdEdit
= passwd1Edit
= passwd2Edit
= 0;
106 if (ctx
== ExUnlock
|| ctx
== ExChangeTok
)
107 splitEntity( KUser().loginName(), fixedDomain
, fixedUser
);
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
);
124 loginEdit
->setObjectName( "user-entry" );
125 domainCombo
->setObjectName( "domain-entry" );
126 widgetList
<< domainCombo
<< loginEdit
;
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()) );
157 passwdEdit
->setObjectName( "pw-entry" );
158 widgetList
<< passwdEdit
;
160 passwdLabel
= new QLabel( func
== Authenticate
?
162 i18n("Current &password:"),
164 passwdLabel
->setBuddy( passwdEdit
);
165 grid
->addWidget( passwdLabel
, line
, 0 );
166 grid
->addWidget( passwdEdit
, line
++, 1 );
170 loginEdit
->setFocus();
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
);
182 grid
->addWidget( passwd1Label
, line
, 0 );
183 grid
->addWidget( passwd1Edit
, line
++, 1 );
184 grid
->addWidget( passwd2Label
, line
, 0 );
185 grid
->addWidget( passwd2Edit
, line
, 1 );
188 passwd1Edit
->setFocus();
193 KWinbindGreeter::~KWinbindGreeter()
196 qDeleteAll( widgetList
);
200 KWinbindGreeter::slotChangedDomain( const QString
&dom
)
202 if (!loginEdit
->completionObject())
205 if (dom
== "<local>") {
206 for (QStringList::ConstIterator it
= allUsers
.constBegin(); it
!= allUsers
.constEnd(); ++it
)
207 if ((*it
).indexOf( separator
) < 0)
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
);
219 KWinbindGreeter::loadUsers( const QStringList
&users
)
222 KCompletion
*userNamesCompletion
= new KCompletion
;
223 loginEdit
->setCompletionObject( userNamesCompletion
);
224 loginEdit
->setAutoDeleteCompletionObject( true );
225 loginEdit
->setCompletionMode( KGlobalSettings::CompletionAuto
);
226 slotChangedDomain( defaultDomain
);
230 KWinbindGreeter::presetEntity( const QString
&entity
, int field
)
233 splitEntity( entity
, dom
, usr
);
234 domainCombo
->setCurrentItem( dom
, true );
235 slotChangedDomain( dom
);
236 loginEdit
->setText( usr
);
238 passwdEdit
->setFocus();
239 else if (field
== 1 || field
== -1) {
241 passwdEdit
->setText( " " );
242 passwdEdit
->setEnabled( false );
245 loginEdit
->setFocus();
246 loginEdit
->selectAll();
252 KWinbindGreeter::getEntity() const
255 if (fixedUser
.isEmpty()) {
256 dom
= domainCombo
->currentText();
257 usr
= loginEdit
->text().trimmed();
258 loginEdit
->setText( usr
);
263 return dom
== "<local>" ? usr
: dom
+ separator
+ usr
;
267 KWinbindGreeter::setUser( const QString
&user
)
269 // assert (fixedUser.isEmpty());
272 splitEntity( user
, dom
, usr
);
273 domainCombo
->setCurrentItem( dom
, true );
274 slotChangedDomain( dom
);
275 loginEdit
->setText( usr
);
276 passwdEdit
->setFocus();
277 passwdEdit
->selectAll();
281 KWinbindGreeter::setEnabled( bool enable
)
283 // assert( !passwd1Label );
284 // assert( func == Authenticate && ctx == Shutdown );
286 // domainCombo->setEnabled( enable );
288 // loginLabel->setEnabled( enable );
289 passwdLabel
->setEnabled( enable
);
292 passwdEdit
->setFocus();
296 KWinbindGreeter::returnData()
300 handler
->gplugReturnText( getEntity().toLocal8Bit(),
301 KGreeterPluginHandler::IsUser
);
304 handler
->gplugReturnText( passwdEdit
->text().toLocal8Bit(),
305 KGreeterPluginHandler::IsPassword
|
306 KGreeterPluginHandler::IsSecret
);
309 handler
->gplugReturnText( passwd1Edit
->text().toLocal8Bit(),
310 KGreeterPluginHandler::IsSecret
);
313 handler
->gplugReturnText( passwd2Edit
->text().toLocal8Bit(),
314 KGreeterPluginHandler::IsNewPassword
|
315 KGreeterPluginHandler::IsSecret
);
321 KWinbindGreeter::textMessage( const char *text
, bool err
)
324 QString( text
).indexOf( QRegExp( "^Changing password for [^ ]+$" ) ) >= 0)
330 KWinbindGreeter::textPrompt( const char *prompt
, bool echo
, bool nonBlocking
)
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
);
344 } else if (pr
.indexOf( QRegExp( "\\b(re-?(enter|type)|again|confirm|repeat)\\b",
345 Qt::CaseInsensitive
) ) >= 0)
347 else if (pr
.indexOf( QRegExp( "\\bnew\\b", Qt::CaseInsensitive
) ) >= 0)
350 handler
->gplugMsgBox( QMessageBox::Critical
,
351 i18n("Unrecognized prompt \"%1\"",
353 handler
->gplugReturnText( 0, 0 );
359 if (pExp
>= 0 && pExp
>= exp
) {
364 if (has
>= exp
|| nonBlocking
)
369 KWinbindGreeter::binaryPrompt( const char *, bool )
371 // this simply cannot happen ... :}
376 KWinbindGreeter::start()
378 authTok
= !(passwdEdit
&& passwdEdit
->isEnabled());
384 KWinbindGreeter::suspend()
389 KWinbindGreeter::resume()
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
402 } else if (passwdEdit
&& passwdEdit
->hasFocus()) {
404 passwd1Edit
->setFocus();
406 } else if (passwd1Edit
) {
407 if (passwd1Edit
->hasFocus()) {
408 passwd2Edit
->setFocus();
415 handler
->gplugStart();
421 KWinbindGreeter::abort()
426 handler
->gplugReturnText( 0, 0 );
431 KWinbindGreeter::succeeded()
433 // assert( running || timed_login );
447 KWinbindGreeter::failed()
449 // assert( running || timed_login );
457 KWinbindGreeter::revive()
459 // assert( !running );
462 passwd1Edit
->clear();
463 passwd2Edit
->clear();
464 passwd1Edit
->setFocus();
467 if (loginEdit
&& loginEdit
->isEnabled())
468 passwdEdit
->setEnabled( true );
471 if (loginEdit
&& loginEdit
->text().isEmpty())
472 loginEdit
->setFocus();
474 passwdEdit
->setFocus();
480 KWinbindGreeter::clear()
482 // assert( !running && !passwd1Edit );
485 domainCombo
->setCurrentItem( defaultDomain
);
486 slotChangedDomain( defaultDomain
);
488 loginEdit
->setFocus();
491 passwdEdit
->setFocus();
498 KWinbindGreeter::setActive( bool enable
)
501 domainCombo
->setEnabled( enable
);
503 loginEdit
->setEnabled( enable
);
505 passwdEdit
->setEnabled( enable
);
509 KWinbindGreeter::setActive2( bool enable
)
512 passwd1Edit
->setEnabled( enable
);
513 passwd2Edit
->setEnabled( enable
);
518 KWinbindGreeter::slotLoginLostFocus()
522 QString
ent( getEntity() );
527 handler
->gplugReturnText( 0, 0 );
530 handler
->gplugSetUser( curUser
);
534 KWinbindGreeter::slotChanged()
537 handler
->gplugChanged();
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();
552 KWinbindGreeter::slotEndDomainList()
554 QStringList domainList
;
556 while (!m_domainLister
->atEnd()) {
557 QString dom
= m_domainLister
->readLine();
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
) );
568 if (i
== domainCombo
->currentIndex())
569 domainCombo
->setCurrentItem( defaultDomain
);
570 domainCombo
->removeItem( i
);
572 domainList
.removeAt( dli
);
574 domainCombo
->addItems( domainList
);
576 QTimer::singleShot( 5 * 1000, this, SLOT(slotStartDomainList()) );
581 static bool init( const QString
&,
582 QVariant (*getConf
)( void *, const char *, const QVariant
& ),
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" );
595 QTextStream( sepfile
) >> sepstr
;
596 if (pclose( sepfile
))
601 separator
= sepstr
[0].toLatin1();
603 KGlobal::locale()->insertCatalog( "kgreet_winbind" );
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
,
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
,
631 #include "kgreet_winbind.moc"