1 | /* |
2 | |
3 | Conversation widget for kdm greeter |
4 | |
5 | Copyright (C) 1997, 1998, 2000 Steffen Hansen <hansen@kde.org> |
6 | Copyright (C) 2000-2003 Oswald Buddenhagen <ossi@kde.org> |
7 | |
8 | |
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. |
13 | |
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. |
18 | |
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. |
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 | |
36 | static int echoMode; |
37 | |
38 | class KDMPasswordEdit : public KLineEdit { |
39 | public: |
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 | |
50 | KClassicGreeter::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 |
137 | KClassicGreeter::~KClassicGreeter() |
138 | { |
139 | abort(); |
140 | qDeleteAll(widgetList); |
141 | } |
142 | |
143 | void // virtual |
144 | KClassicGreeter::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 | |
153 | void // virtual |
154 | KClassicGreeter::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 | |
171 | QString // virtual |
172 | KClassicGreeter::getEntity() const |
173 | { |
174 | return fixedUser.isEmpty() ? loginEdit->text() : fixedUser; |
175 | } |
176 | |
177 | void // virtual |
178 | KClassicGreeter::setUser(const QString &user) |
179 | { |
180 | // assert(fixedUser.isEmpty()); |
181 | curUser = user; |
182 | loginEdit->setText(user); |
183 | passwdEdit->setFocus(); |
184 | passwdEdit->selectAll(); |
185 | } |
186 | |
187 | void // virtual |
188 | KClassicGreeter::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 | |
200 | void // private |
201 | KClassicGreeter::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 | |
229 | bool // virtual |
230 | KClassicGreeter::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 | |
238 | void // virtual |
239 | KClassicGreeter::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 | |
277 | bool // virtual |
278 | KClassicGreeter::binaryPrompt(const char *, bool) |
279 | { |
280 | // this simply cannot happen ... :} |
281 | return true; |
282 | } |
283 | |
284 | void // virtual |
285 | KClassicGreeter::start() |
286 | { |
287 | authTok = !(passwdEdit && passwdEdit->isEnabled()); |
288 | exp = has = -1; |
289 | running = true; |
290 | } |
291 | |
292 | void // virtual |
293 | KClassicGreeter::suspend() |
294 | { |
295 | } |
296 | |
297 | void // virtual |
298 | KClassicGreeter::resume() |
299 | { |
300 | } |
301 | |
302 | void // virtual |
303 | KClassicGreeter::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 | |
330 | void // virtual |
331 | KClassicGreeter::abort() |
332 | { |
333 | running = false; |
334 | if (exp >= 0) { |
335 | exp = -1; |
336 | handler->gplugReturnText(0, 0); |
337 | } |
338 | } |
339 | |
340 | void // virtual |
341 | KClassicGreeter::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 | |
357 | void // virtual |
358 | KClassicGreeter::failed() |
359 | { |
360 | // assert(running || timed_login); |
361 | setActive(false); |
362 | setActive2(false); |
363 | exp = -1; |
364 | running = false; |
365 | } |
366 | |
367 | void // virtual |
368 | KClassicGreeter::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 | |
390 | void // virtual |
391 | KClassicGreeter::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 | |
407 | void |
408 | KClassicGreeter::setActive(bool enable) |
409 | { |
410 | if (loginEdit) |
411 | loginEdit->setEnabled(enable); |
412 | if (passwdEdit) |
413 | passwdEdit->setEnabled(enable); |
414 | } |
415 | |
416 | void |
417 | KClassicGreeter::setActive2(bool enable) |
418 | { |
419 | if (passwd1Edit) { |
420 | passwd1Edit->setEnabled(enable); |
421 | passwd2Edit->setEnabled(enable); |
422 | } |
423 | } |
424 | |
425 | void |
426 | KClassicGreeter::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 | |
441 | void |
442 | KClassicGreeter::slotChanged() |
443 | { |
444 | if (running) |
445 | handler->gplugChanged(); |
446 | } |
447 | |
448 | // factory |
449 | |
450 | static 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 | |
459 | static void done(void) |
460 | { |
461 | KGlobal::locale()->removeCatalog("kgreet_classic" ); |
462 | } |
463 | |
464 | static KGreeterPlugin * |
465 | create(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 | |
474 | KDE_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 | |