1/*
2
3Conversation widget for kdm greeter
4
5Copyright (C) 1997, 1998, 2000 Steffen Hansen <hansen@kde.org>
6Copyright (C) 2000-2003 Oswald Buddenhagen <ossi@kde.org>
7
8
9This program is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published by
11the Free Software Foundation; either version 2 of the License, or
12(at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22
23*/
24
25#include "kgreet_classic.h"
26
27#include <kglobal.h>
28#include <klocale.h>
29#include <klineedit.h>
30#include <kuser.h>
31
32#include <QRegExp>
33#include <QFormLayout>
34#include <QLabel>
35
36static int echoMode;
37
38class KDMPasswordEdit : public KLineEdit {
39public:
40 KDMPasswordEdit(QWidget *parent) : KLineEdit(parent)
41 {
42 if (::echoMode == -1)
43 setPasswordMode(true);
44 else
45 setEchoMode(::echoMode ? Password : NoEcho);
46 setContextMenuPolicy(Qt::NoContextMenu);
47 }
48};
49
50KClassicGreeter::KClassicGreeter(KGreeterPluginHandler *_handler,
51 QWidget *parent,
52 const QString &_fixedEntity,
53 Function _func, Context _ctx) :
54 QObject(),
55 KGreeterPlugin(_handler),
56 fixedUser(_fixedEntity),
57 func(_func),
58 ctx(_ctx),
59 exp(-1),
60 pExp(-1),
61 running(false)
62{
63 QFormLayout *formLay = 0;
64
65 if (!_handler->gplugHasNode("user-entry") ||
66 !_handler->gplugHasNode("pw-entry"))
67 {
68 parent = new QWidget(parent);
69 parent->setObjectName("talker");
70 widgetList << parent;
71 formLay = new QFormLayout(parent);
72 formLay->setMargin(0);
73 }
74
75 loginLabel = passwdLabel = passwd1Label = passwd2Label = 0;
76 loginEdit = 0;
77 passwdEdit = passwd1Edit = passwd2Edit = 0;
78 if (ctx == ExUnlock || ctx == ExChangeTok)
79 fixedUser = KUser().loginName();
80 if (func != ChAuthTok) {
81 if (fixedUser.isEmpty()) {
82 loginEdit = new KLineEdit(parent);
83 loginEdit->setContextMenuPolicy(Qt::NoContextMenu);
84 connect(loginEdit, SIGNAL(editingFinished()), SLOT(slotLoginLostFocus()));
85 connect(loginEdit, SIGNAL(editingFinished()), SLOT(slotChanged()));
86 connect(loginEdit, SIGNAL(textChanged(QString)), SLOT(slotChanged()));
87 connect(loginEdit, SIGNAL(selectionChanged()), SLOT(slotChanged()));
88 if (!formLay) {
89 loginEdit->setObjectName("user-entry");
90 widgetList << loginEdit;
91 } else {
92 loginLabel = new QLabel(i18n("&Username:"), parent);
93 loginLabel->setBuddy(loginEdit);
94 formLay->addRow(loginLabel, loginEdit);
95 }
96 } else if (ctx != Login && ctx != Shutdown && formLay) {
97 loginLabel = new QLabel(i18n("Username:"), parent);
98 formLay->addRow(loginLabel, new QLabel(fixedUser, parent));
99 }
100 passwdEdit = new KDMPasswordEdit(parent);
101 connect(passwdEdit, SIGNAL(textChanged(QString)),
102 SLOT(slotChanged()));
103 connect(passwdEdit, SIGNAL(editingFinished()), SLOT(slotChanged()));
104 if (!formLay) {
105 passwdEdit->setObjectName("pw-entry");
106 widgetList << passwdEdit;
107 } else {
108 passwdLabel = new QLabel(func == Authenticate ?
109 i18n("&Password:") :
110 i18n("Current &password:"),
111 parent);
112 passwdLabel->setBuddy(passwdEdit);
113 formLay->addRow(passwdLabel, passwdEdit);
114 }
115 if (loginEdit)
116 loginEdit->setFocus();
117 else
118 passwdEdit->setFocus();
119 }
120 if (func != Authenticate) {
121 passwd1Edit = new KDMPasswordEdit(parent);
122 passwd1Label = new QLabel(i18n("&New password:"), parent);
123 passwd1Label->setBuddy(passwd1Edit);
124 passwd2Edit = new KDMPasswordEdit(parent);
125 passwd2Label = new QLabel(i18n("Con&firm password:"), parent);
126 passwd2Label->setBuddy(passwd2Edit);
127 if (formLay) {
128 formLay->addRow(passwd1Label, passwd1Edit);
129 formLay->addRow(passwd2Label, passwd2Edit);
130 }
131 if (!passwdEdit)
132 passwd1Edit->setFocus();
133 }
134}
135
136// virtual
137KClassicGreeter::~KClassicGreeter()
138{
139 abort();
140 qDeleteAll(widgetList);
141}
142
143void // virtual
144KClassicGreeter::loadUsers(const QStringList &users)
145{
146 KCompletion *userNamesCompletion = new KCompletion;
147 userNamesCompletion->setItems(users);
148 loginEdit->setCompletionObject(userNamesCompletion);
149 loginEdit->setAutoDeleteCompletionObject(true);
150 loginEdit->setCompletionMode(KGlobalSettings::CompletionAuto);
151}
152
153void // virtual
154KClassicGreeter::presetEntity(const QString &entity, int field)
155{
156 loginEdit->setText(entity);
157 if (field == 1) {
158 passwdEdit->setFocus();
159 } else {
160 loginEdit->setFocus();
161 loginEdit->selectAll();
162 if (field == -1) {
163 passwdEdit->setText(" ");
164 passwdEdit->setEnabled(false);
165 authTok = false;
166 }
167 }
168 curUser = entity;
169}
170
171QString // virtual
172KClassicGreeter::getEntity() const
173{
174 return fixedUser.isEmpty() ? loginEdit->text() : fixedUser;
175}
176
177void // virtual
178KClassicGreeter::setUser(const QString &user)
179{
180 // assert(fixedUser.isEmpty());
181 curUser = user;
182 loginEdit->setText(user);
183 passwdEdit->setFocus();
184 passwdEdit->selectAll();
185}
186
187void // virtual
188KClassicGreeter::setEnabled(bool enable)
189{
190 // assert(!passwd1Label);
191 // assert(func == Authenticate && ctx == Shutdown);
192// if (loginLabel)
193// loginLabel->setEnabled(enable);
194 passwdLabel->setEnabled(enable);
195 setActive(enable);
196 if (enable)
197 passwdEdit->setFocus();
198}
199
200void // private
201KClassicGreeter::returnData()
202{
203 switch (exp) {
204 case 0:
205 handler->gplugReturnText((loginEdit ? loginEdit->text() :
206 fixedUser).toLocal8Bit(),
207 KGreeterPluginHandler::IsUser);
208 break;
209 case 1:
210 Q_ASSERT(passwdEdit);
211 handler->gplugReturnText(passwdEdit->text().toLocal8Bit() ,
212 KGreeterPluginHandler::IsPassword |
213 KGreeterPluginHandler::IsSecret);
214 break;
215 case 2:
216 Q_ASSERT(passwd1Edit);
217 handler->gplugReturnText(passwd1Edit->text().toLocal8Bit(),
218 KGreeterPluginHandler::IsSecret);
219 break;
220 default: // case 3:
221 Q_ASSERT(passwd2Edit);
222 handler->gplugReturnText(passwd2Edit->text().toLocal8Bit(),
223 KGreeterPluginHandler::IsNewPassword |
224 KGreeterPluginHandler::IsSecret);
225 break;
226 }
227}
228
229bool // virtual
230KClassicGreeter::textMessage(const char *text, bool err)
231{
232 if (!err &&
233 QString(text).indexOf(QRegExp("^Changing password for [^ ]+$")) >= 0)
234 return true;
235 return false;
236}
237
238void // virtual
239KClassicGreeter::textPrompt(const char *prompt, bool echo, bool nonBlocking)
240{
241 pExp = exp;
242 if (echo) {
243 exp = 0;
244 } else if (!authTok) {
245 exp = 1;
246 } else {
247 QString pr(prompt);
248 if (pr.indexOf(QRegExp("\\bpassword\\b", Qt::CaseInsensitive)) >= 0) {
249 if (pr.indexOf(QRegExp("\\b(re-?(enter|type)|again|confirm|repeat)\\b",
250 Qt::CaseInsensitive)) >= 0) {
251 exp = 3;
252 } else if (pr.indexOf(QRegExp("\\bnew\\b", Qt::CaseInsensitive)) >= 0) {
253 exp = 2;
254 } else { // QRegExp("\\b(old|current)\\b", Qt::CaseInsensitive) is too strict
255 handler->gplugReturnText("", KGreeterPluginHandler::IsOldPassword |
256 KGreeterPluginHandler::IsSecret);
257 return;
258 }
259 } else {
260 handler->gplugMsgBox(QMessageBox::Critical,
261 i18n("Unrecognized prompt \"%1\"", prompt));
262 handler->gplugReturnText(0, 0);
263 exp = -1;
264 return;
265 }
266 }
267
268 if (pExp >= 0 && pExp >= exp) {
269 revive();
270 has = -1;
271 }
272
273 if (has >= exp || nonBlocking)
274 returnData();
275}
276
277bool // virtual
278KClassicGreeter::binaryPrompt(const char *, bool)
279{
280 // this simply cannot happen ... :}
281 return true;
282}
283
284void // virtual
285KClassicGreeter::start()
286{
287 authTok = !(passwdEdit && passwdEdit->isEnabled());
288 exp = has = -1;
289 running = true;
290}
291
292void // virtual
293KClassicGreeter::suspend()
294{
295}
296
297void // virtual
298KClassicGreeter::resume()
299{
300}
301
302void // virtual
303KClassicGreeter::next()
304{
305 // assert(running);
306 int pHas = has;
307 if (loginEdit && loginEdit->hasFocus()) {
308 passwdEdit->setFocus(); // will cancel running login if necessary
309 has = 0;
310 } else if (passwdEdit && passwdEdit->hasFocus()) {
311 if (passwd1Edit)
312 passwd1Edit->setFocus();
313 has = 1;
314 } else if (passwd1Edit) {
315 if (passwd1Edit->hasFocus()) {
316 passwd2Edit->setFocus();
317 has = 1; // sic!
318 } else {
319 has = 3;
320 }
321 } else {
322 has = 1;
323 }
324 if (exp < 0)
325 handler->gplugStart();
326 else if (has >= exp && has > pHas)
327 returnData();
328}
329
330void // virtual
331KClassicGreeter::abort()
332{
333 running = false;
334 if (exp >= 0) {
335 exp = -1;
336 handler->gplugReturnText(0, 0);
337 }
338}
339
340void // virtual
341KClassicGreeter::succeeded()
342{
343 // assert(running || timed_login);
344 if (!authTok) {
345 setActive(false);
346 if (passwd1Edit) {
347 authTok = true;
348 return;
349 }
350 } else {
351 setActive2(false);
352 }
353 exp = -1;
354 running = false;
355}
356
357void // virtual
358KClassicGreeter::failed()
359{
360 // assert(running || timed_login);
361 setActive(false);
362 setActive2(false);
363 exp = -1;
364 running = false;
365}
366
367void // virtual
368KClassicGreeter::revive()
369{
370 // assert(!running);
371 setActive2(true);
372 if (authTok) {
373 passwd1Edit->clear();
374 passwd2Edit->clear();
375 passwd1Edit->setFocus();
376 } else {
377 passwdEdit->clear();
378 if (loginEdit && loginEdit->isEnabled()) {
379 passwdEdit->setEnabled(true);
380 } else {
381 setActive(true);
382 if (loginEdit && loginEdit->text().isEmpty())
383 loginEdit->setFocus();
384 else
385 passwdEdit->setFocus();
386 }
387 }
388}
389
390void // virtual
391KClassicGreeter::clear()
392{
393 // assert(!running && !passwd1Edit);
394 passwdEdit->clear();
395 if (loginEdit) {
396 loginEdit->clear();
397 loginEdit->setFocus();
398 curUser.clear();
399 } else {
400 passwdEdit->setFocus();
401 }
402}
403
404
405// private
406
407void
408KClassicGreeter::setActive(bool enable)
409{
410 if (loginEdit)
411 loginEdit->setEnabled(enable);
412 if (passwdEdit)
413 passwdEdit->setEnabled(enable);
414}
415
416void
417KClassicGreeter::setActive2(bool enable)
418{
419 if (passwd1Edit) {
420 passwd1Edit->setEnabled(enable);
421 passwd2Edit->setEnabled(enable);
422 }
423}
424
425void
426KClassicGreeter::slotLoginLostFocus()
427{
428 if (!running)
429 return;
430 loginEdit->setText(loginEdit->text().trimmed());
431 if (exp > 0) {
432 if (curUser == loginEdit->text())
433 return;
434 exp = -1;
435 handler->gplugReturnText(0, 0);
436 }
437 curUser = loginEdit->text();
438 handler->gplugSetUser(curUser);
439}
440
441void
442KClassicGreeter::slotChanged()
443{
444 if (running)
445 handler->gplugChanged();
446}
447
448// factory
449
450static bool init(const QString &,
451 QVariant(*getConf)(void *, const char *, const QVariant &),
452 void *ctx)
453{
454 echoMode = getConf(ctx, "EchoPasswd", QVariant(-1)).toInt();
455 KGlobal::locale()->insertCatalog("kgreet_classic");
456 return true;
457}
458
459static void done(void)
460{
461 KGlobal::locale()->removeCatalog("kgreet_classic");
462}
463
464static KGreeterPlugin *
465create(KGreeterPluginHandler *handler,
466 QWidget *parent,
467 const QString &fixedEntity,
468 KGreeterPlugin::Function func,
469 KGreeterPlugin::Context ctx)
470{
471 return new KClassicGreeter(handler, parent, fixedEntity, func, ctx);
472}
473
474KDE_EXPORT KGreeterPluginInfo kgreeterplugin_info = {
475 I18N_NOOP2("@item:inmenu authentication method", "Username + password (classic)"), "classic",
476 KGreeterPluginInfo::Local | KGreeterPluginInfo::Presettable,
477 init, done, create
478};
479
480#include "kgreet_classic.moc"
481