1/*
2
3Conversation widget for kdm greeter
4
5Copyright (C) 2008 Dirk Mueller <mueller@kde.org>
6Copyright (C) 2008 Oswald Buddenhagen <ossi@kde.org>
7
8based on classic kdm greeter:
9
10 Copyright (C) 1997, 1998, 2000 Steffen Hansen <hansen@kde.org>
11 Copyright (C) 2000-2003 Oswald Buddenhagen <ossi@kde.org>
12
13This program is free software; you can redistribute it and/or modify
14it under the terms of the GNU General Public License as published by
15the Free Software Foundation; either version 2 of the License, or
16(at your option) any later version.
17
18This program is distributed in the hope that it will be useful,
19but WITHOUT ANY WARRANTY; without even the implied warranty of
20MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21GNU General Public License for more details.
22
23You should have received a copy of the GNU General Public License
24along with this program; if not, write to the Free Software
25Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26
27*/
28
29#include "kgreet_generic.h"
30
31#include <kglobal.h>
32#include <klocale.h>
33#include <klineedit.h>
34#include <kuser.h>
35
36#include <QLayout>
37#include <QLabel>
38#include <QTextDocument>
39
40extern KDE_EXPORT KGreeterPluginInfo kgreeterplugin_info; // defined at bottom
41
42static int echoMode;
43
44class KDMPasswordEdit : public KLineEdit {
45public:
46 KDMPasswordEdit(QWidget *parent = 0) : KLineEdit(parent)
47 {
48 if (::echoMode == -1)
49 setPasswordMode(true);
50 else
51 setEchoMode(::echoMode ? Password : NoEcho);
52 setContextMenuPolicy(Qt::NoContextMenu);
53 }
54};
55
56KGenericGreeter::KGenericGreeter(KGreeterPluginHandler *_handler,
57 QWidget *parent,
58 const QString &_fixedEntity,
59 Function _func, Context _ctx) :
60 QObject(),
61 KGreeterPlugin(_handler),
62 m_lineEdit(0),
63 fixedUser(_fixedEntity),
64 func(_func),
65 ctx(_ctx),
66 exp(-1),
67 running(false)
68{
69 m_parentWidget = new QWidget(parent);
70 m_parentWidget->setObjectName("talker");
71 // XXX set some minimal size
72 widgetList << m_parentWidget;
73 m_grid = new QGridLayout(m_parentWidget);
74 m_grid->setMargin(0);
75
76 if (ctx == ExUnlock || ctx == ExChangeTok)
77 fixedUser = KUser().loginName();
78}
79
80// virtual
81KGenericGreeter::~KGenericGreeter()
82{
83 abort();
84 delete m_parentWidget;
85}
86
87void // virtual
88KGenericGreeter::loadUsers(const QStringList &users)
89{
90 m_users = users;
91}
92
93void // virtual
94KGenericGreeter::presetEntity(const QString &entity, int /* field */)
95{
96 // assert(!running);
97 curUser = entity;
98}
99
100QString // virtual
101KGenericGreeter::getEntity() const
102{
103 return fixedUser.isEmpty() ? curUser : fixedUser;
104}
105
106void // virtual
107KGenericGreeter::setUser(const QString &user)
108{
109 // assert(running);
110 // assert(fixedUser.isEmpty());
111 if (!(kgreeterplugin_info.flags & KGreeterPluginInfo::Presettable))
112 return; // Not interested in PAM telling us who logged in
113 if (exp) {
114 abort();
115 start();
116 }
117 curUser = user;
118 if (m_lineEdit) { // could be null if plugin is misconfigured
119 m_lineEdit->setText(user);
120 m_lineEdit->selectAll();
121 m_lineEdit->setFocus();
122 }
123}
124
125void // virtual
126KGenericGreeter::setEnabled(bool enable)
127{
128 // assert(func == Authenticate && ctx == Shutdown);
129 // XXX this is likely to bear some bogosity
130 foreach (QWidget *w, m_children)
131 w->setEnabled(enable);
132 if (enable && m_lineEdit)
133 m_lineEdit->setFocus();
134}
135
136bool // virtual
137KGenericGreeter::textMessage(const char *text, bool err)
138{
139 if (err)
140 return false;
141
142 if (m_infoMsgs.isEmpty())
143 revive();
144 QString qtext = QString::fromUtf8(text);
145 m_infoMsgs.append(qtext);
146 QLabel *label = new QLabel(qtext, m_parentWidget);
147 m_grid->addWidget(label, m_line++, 0, 1, 2);
148 m_children.append(label);
149
150 return true;
151}
152
153void // virtual
154KGenericGreeter::textPrompt(const char *prompt, bool echo, bool /* nonBlocking */)
155{
156 exp =
157 exp >= 0 ||
158 func != Authenticate ||
159 !(kgreeterplugin_info.flags & KGreeterPluginInfo::Presettable);
160
161 if (!exp && !fixedUser.isEmpty()) {
162 handler->gplugReturnText(fixedUser.toLocal8Bit(),
163 KGreeterPluginHandler::IsUser);
164 return;
165 }
166
167 if (m_infoMsgs.isEmpty())
168 revive();
169 else
170 m_infoMsgs.clear();
171
172 QLabel *label = new QLabel(QString::fromUtf8(prompt).trimmed());
173 m_grid->addWidget(label, m_line, 0);
174 m_children.append(label);
175 m_echo = echo;
176 if (echo) {
177 m_lineEdit = new KLineEdit;
178 m_lineEdit->setContextMenuPolicy(Qt::NoContextMenu);
179 if (!exp) {
180 if (!m_users.isEmpty()) {
181 KCompletion *userNamesCompletion = new KCompletion;
182 userNamesCompletion->setItems(m_users);
183 m_lineEdit->setCompletionObject(userNamesCompletion);
184 m_lineEdit->setAutoDeleteCompletionObject(true);
185 m_lineEdit->setCompletionMode(KGlobalSettings::CompletionAuto);
186 }
187 if (!curUser.isEmpty()) {
188 m_lineEdit->setText(curUser);
189 m_lineEdit->selectAll();
190 connect(m_lineEdit, SIGNAL(selectionChanged()), SLOT(slotChanged()));
191 }
192 connect(m_lineEdit, SIGNAL(editingFinished()), SLOT(slotLoginLostFocus()));
193 }
194 connect(m_lineEdit, SIGNAL(editingFinished()), SLOT(slotChanged()));
195 connect(m_lineEdit, SIGNAL(textChanged(QString)), SLOT(slotChanged()));
196 } else {
197 m_lineEdit = new KDMPasswordEdit;
198 }
199 m_lineEdit->setMinimumWidth(
200 m_lineEdit->fontMetrics().width("This is a long password"));
201 m_grid->addWidget(m_lineEdit, m_line, 1);
202 m_children.append(m_lineEdit);
203 m_lineEdit->show();
204 m_lineEdit->setFocus();
205}
206
207bool // virtual
208KGenericGreeter::binaryPrompt(const char *, bool)
209{
210 // FIXME
211 return true;
212}
213
214void // virtual
215KGenericGreeter::start()
216{
217 exp = -1;
218 running = true;
219 handler->gplugStart();
220}
221
222void // virtual
223KGenericGreeter::suspend()
224{
225}
226
227void // virtual
228KGenericGreeter::resume()
229{
230}
231
232void // virtual
233KGenericGreeter::next()
234{
235 if (m_lineEdit) {
236 m_lineEdit->setEnabled(false);
237 QString text = m_lineEdit->text();
238 m_lineEdit = 0;
239 handler->gplugReturnText(text.toLocal8Bit(),
240 !m_echo ?
241 KGreeterPluginHandler::IsSecret :
242 !exp ?
243 KGreeterPluginHandler::IsUser : 0);
244 }
245}
246
247void // virtual
248KGenericGreeter::abort()
249{
250 running = false;
251 if (exp >= 0) {
252 exp = -1;
253 handler->gplugReturnText(0, 0);
254 }
255}
256
257void // virtual
258KGenericGreeter::succeeded()
259{
260 failed(); // redefining terms :-D
261}
262
263void // virtual
264KGenericGreeter::failed()
265{
266 // assert(running || timed_login);
267 if (!m_infoMsgs.isEmpty()) {
268 QString text = "<qt>";
269 foreach (const QString &msg, m_infoMsgs)
270 text += "<p>" + Qt::escape(msg) + "</p>";
271 text += "</qt>";
272 revive();
273 handler->gplugMsgBox(QMessageBox::Information, text);
274 } else {
275 foreach (QWidget *w, m_children)
276 w->setEnabled(false);
277 }
278 exp = -1;
279 running = false;
280}
281
282void // virtual
283KGenericGreeter::revive()
284{
285 // assert(!running);
286 foreach (QWidget *w, m_children)
287 w->deleteLater();
288 m_children.clear();
289 m_infoMsgs.clear();
290 m_lineEdit = 0;
291 m_line = 0;
292}
293
294void // virtual
295KGenericGreeter::clear()
296{
297 // assert(!running && !passwd1Edit);
298 revive();
299 curUser = QString::null;
300}
301
302
303// private
304void
305KGenericGreeter::slotLoginLostFocus()
306{
307 m_lineEdit->setText(m_lineEdit->text().trimmed());
308 if (curUser != m_lineEdit->text()) {
309 curUser = m_lineEdit->text();
310 handler->gplugSetUser(curUser);
311 }
312}
313
314void
315KGenericGreeter::slotChanged()
316{
317 handler->gplugChanged();
318}
319
320// factory
321static bool init(const QString &,
322 QVariant(*getConf)(void *, const char *, const QVariant &),
323 void *ctx)
324{
325 echoMode = getConf(ctx, "EchoMode", QVariant(-1)).toInt();
326 // Fielded entities are not supported per se.
327 // This implies that the first field is the presettable entity, if any.
328 if (getConf(ctx, "generic.Presettable", QVariant(false)).toBool())
329 kgreeterplugin_info.flags |= KGreeterPluginInfo::Presettable;
330 KGlobal::locale()->insertCatalog("kgreet_generic");
331 return true;
332}
333
334static void done(void)
335{
336 KGlobal::locale()->removeCatalog("kgreet_generic");
337}
338
339static KGreeterPlugin *
340create(KGreeterPluginHandler *handler,
341 QWidget *parent,
342 const QString &fixedEntity,
343 KGreeterPlugin::Function func,
344 KGreeterPlugin::Context ctx)
345{
346 return new KGenericGreeter(handler, parent, fixedEntity, func, ctx);
347}
348
349KDE_EXPORT KGreeterPluginInfo kgreeterplugin_info = {
350 I18N_NOOP2("@item:inmenu authentication method", "Generic"), "generic",
351 KGreeterPluginInfo::Local,
352 init, done, create
353};
354
355#include "kgreet_generic.moc"
356