summaryrefslogtreecommitdiffstats
path: root/kdmlib
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit4aed2c8219774f5d797760606b8489a92ddc5163 (patch)
tree3f8c130f7d269626bf6a9447407ef6c35954426a /kdmlib
downloadtdebase-4aed2c8219774f5d797760606b8489a92ddc5163.tar.gz
tdebase-4aed2c8219774f5d797760606b8489a92ddc5163.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kdmlib')
-rw-r--r--kdmlib/Makefile.am26
-rw-r--r--kdmlib/dmctl.cpp442
-rw-r--r--kdmlib/dmctl.h93
-rw-r--r--kdmlib/kgreet_classic.cpp505
-rw-r--r--kdmlib/kgreet_classic.h87
-rw-r--r--kdmlib/kgreet_winbind.cpp671
-rw-r--r--kdmlib/kgreet_winbind.h100
-rw-r--r--kdmlib/kgreeterplugin.h401
8 files changed, 2325 insertions, 0 deletions
diff --git a/kdmlib/Makefile.am b/kdmlib/Makefile.am
new file mode 100644
index 000000000..91218a8c3
--- /dev/null
+++ b/kdmlib/Makefile.am
@@ -0,0 +1,26 @@
+AM_CPPFLAGS = -I$(top_srcdir)/kdm/kfrontend $(all_includes)
+
+kde_module_LTLIBRARIES = kgreet_classic.la kgreet_winbind.la
+
+kgreet_classic_la_SOURCES = kgreet_classic.cpp
+kgreet_classic_la_LDFLAGS = -module -no-undefined $(KDE_PLUGIN) $(all_libraries)
+kgreet_classic_la_LIBADD = $(LIB_KDEUI)
+
+kgreet_winbind_la_SOURCES = kgreet_winbind.cpp
+kgreet_winbind_la_LDFLAGS = -module -no-undefined $(KDE_PLUGIN) $(all_libraries)
+kgreet_winbind_la_LIBADD = $(LIB_KDEUI)
+
+noinst_LTLIBRARIES = libdmctl.la
+libdmctl_la_SOURCES = dmctl.cpp
+libdmctl_la_LDFLAGS = $(all_libraries) -no-undefined
+libdmctl_la_LIBADD = $(LIB_KDECORE) -lXau
+
+METASOURCES = AUTO
+
+noinst_HEADERS = dmctl.h kgreet_classic.h kgreet_winbind.h
+include_HEADERS = kgreeterplugin.h
+
+messages:
+ $(XGETTEXT) $(kgreet_classic_la_SOURCES) -o $(podir)/kgreet_classic.pot
+ $(XGETTEXT) $(kgreet_winbind_la_SOURCES) -o $(podir)/kgreet_winbind.pot
+ $(XGETTEXT) $(libdmctl_la_SOURCES) -o $(podir)/libdmctl.pot
diff --git a/kdmlib/dmctl.cpp b/kdmlib/dmctl.cpp
new file mode 100644
index 000000000..4475ae1e7
--- /dev/null
+++ b/kdmlib/dmctl.cpp
@@ -0,0 +1,442 @@
+/*
+ Copyright (C) 2004 Oswald Buddenhagen <ossi@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the Lesser GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "dmctl.h"
+
+#ifdef Q_WS_X11
+
+#include <klocale.h>
+#include <dcopclient.h>
+
+#include <qregexp.h>
+
+#include <X11/Xauth.h>
+#include <X11/Xlib.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+
+static enum { Dunno, NoDM, NewKDM, OldKDM, GDM } DMType = Dunno;
+static const char *ctl, *dpy;
+
+DM::DM() : fd( -1 )
+{
+ const char *ptr;
+ struct sockaddr_un sa;
+
+ if (DMType == Dunno) {
+ if (!(dpy = ::getenv( "DISPLAY" )))
+ DMType = NoDM;
+ else if ((ctl = ::getenv( "DM_CONTROL" )))
+ DMType = NewKDM;
+ else if ((ctl = ::getenv( "XDM_MANAGED" )) && ctl[0] == '/')
+ DMType = OldKDM;
+ else if (::getenv( "GDMSESSION" ))
+ DMType = GDM;
+ else
+ DMType = NoDM;
+ }
+ switch (DMType) {
+ default:
+ return;
+ case NewKDM:
+ case GDM:
+ if ((fd = ::socket( PF_UNIX, SOCK_STREAM, 0 )) < 0)
+ return;
+ sa.sun_family = AF_UNIX;
+ if (DMType == GDM) {
+ strcpy( sa.sun_path, "/var/run/gdm_socket" );
+ if (::connect( fd, (struct sockaddr *)&sa, sizeof(sa) )) {
+ strcpy( sa.sun_path, "/tmp/.gdm_socket" );
+ if (::connect( fd, (struct sockaddr *)&sa, sizeof(sa) )) {
+ ::close( fd );
+ fd = -1;
+ break;
+ }
+ }
+ GDMAuthenticate();
+ } else {
+ if ((ptr = strchr( dpy, ':' )))
+ ptr = strchr( ptr, '.' );
+ snprintf( sa.sun_path, sizeof(sa.sun_path),
+ "%s/dmctl-%.*s/socket",
+ ctl, ptr ? int(ptr - dpy) : 512, dpy );
+ if (::connect( fd, (struct sockaddr *)&sa, sizeof(sa) )) {
+ ::close( fd );
+ fd = -1;
+ }
+ }
+ break;
+ case OldKDM:
+ {
+ QString tf( ctl );
+ tf.truncate( tf.find( ',' ) );
+ fd = ::open( tf.latin1(), O_WRONLY );
+ }
+ break;
+ }
+}
+
+DM::~DM()
+{
+ if (fd >= 0)
+ close( fd );
+}
+
+bool
+DM::exec( const char *cmd )
+{
+ QCString buf;
+
+ return exec( cmd, buf );
+}
+
+/**
+ * Execute a KDM/GDM remote control command.
+ * @param cmd the command to execute. FIXME: undocumented yet.
+ * @param buf the result buffer.
+ * @return result:
+ * @li If true, the command was successfully executed.
+ * @p ret might contain addional results.
+ * @li If false and @p ret is empty, a communication error occurred
+ * (most probably KDM is not running).
+ * @li If false and @p ret is non-empty, it contains the error message
+ * from KDM.
+ */
+bool
+DM::exec( const char *cmd, QCString &buf )
+{
+ bool ret = false;
+ int tl;
+ unsigned len = 0;
+
+ if (fd < 0)
+ goto busted;
+
+ tl = strlen( cmd );
+ if (::write( fd, cmd, tl ) != tl) {
+ bust:
+ ::close( fd );
+ fd = -1;
+ busted:
+ buf.resize( 0 );
+ return false;
+ }
+ if (DMType == OldKDM) {
+ buf.resize( 0 );
+ return true;
+ }
+ for (;;) {
+ if (buf.size() < 128)
+ buf.resize( 128 );
+ else if (buf.size() < len * 2)
+ buf.resize( len * 2 );
+ if ((tl = ::read( fd, buf.data() + len, buf.size() - len)) <= 0) {
+ if (tl < 0 && errno == EINTR)
+ continue;
+ goto bust;
+ }
+ len += tl;
+ if (buf[len - 1] == '\n') {
+ buf[len - 1] = 0;
+ if (len > 2 && (buf[0] == 'o' || buf[0] == 'O') &&
+ (buf[1] == 'k' || buf[1] == 'K') && buf[2] <= 32)
+ ret = true;
+ break;
+ }
+ }
+ return ret;
+}
+
+bool
+DM::canShutdown()
+{
+ if (DMType == OldKDM)
+ return strstr( ctl, ",maysd" ) != 0;
+
+ QCString re;
+
+ if (DMType == GDM)
+ return exec( "QUERY_LOGOUT_ACTION\n", re ) && re.find("HALT") >= 0;
+
+ return exec( "caps\n", re ) && re.find( "\tshutdown" ) >= 0;
+}
+
+void
+DM::shutdown( KApplication::ShutdownType shutdownType,
+ KApplication::ShutdownMode shutdownMode, /* NOT Default */
+ const QString &bootOption )
+{
+ if (shutdownType == KApplication::ShutdownTypeNone)
+ return;
+
+ bool cap_ask;
+ if (DMType == NewKDM) {
+ QCString re;
+ cap_ask = exec( "caps\n", re ) && re.find( "\tshutdown ask" ) >= 0;
+ } else {
+ if (!bootOption.isEmpty())
+ return;
+ cap_ask = false;
+ }
+ if (!cap_ask && shutdownMode == KApplication::ShutdownModeInteractive)
+ shutdownMode = KApplication::ShutdownModeForceNow;
+
+ QCString cmd;
+ if (DMType == GDM) {
+ cmd.append( shutdownMode == KApplication::ShutdownModeForceNow ?
+ "SET_LOGOUT_ACTION " : "SET_SAFE_LOGOUT_ACTION " );
+ cmd.append( shutdownType == KApplication::ShutdownTypeReboot ?
+ "REBOOT\n" : "HALT\n" );
+ } else {
+ cmd.append( "shutdown\t" );
+ cmd.append( shutdownType == KApplication::ShutdownTypeReboot ?
+ "reboot\t" : "halt\t" );
+ if (!bootOption.isEmpty())
+ cmd.append( "=" ).append( bootOption.local8Bit() ).append( "\t" );
+ cmd.append( shutdownMode == KApplication::ShutdownModeInteractive ?
+ "ask\n" :
+ shutdownMode == KApplication::ShutdownModeForceNow ?
+ "forcenow\n" :
+ shutdownMode == KApplication::ShutdownModeTryNow ?
+ "trynow\n" : "schedule\n" );
+ }
+ exec( cmd.data() );
+}
+
+bool
+DM::bootOptions( QStringList &opts, int &defopt, int &current )
+{
+ if (DMType != NewKDM)
+ return false;
+
+ QCString re;
+ if (!exec( "listbootoptions\n", re ))
+ return false;
+
+ opts = QStringList::split( '\t', QString::fromLocal8Bit( re.data() ) );
+ if (opts.size() < 4)
+ return false;
+
+ bool ok;
+ defopt = opts[2].toInt( &ok );
+ if (!ok)
+ return false;
+ current = opts[3].toInt( &ok );
+ if (!ok)
+ return false;
+
+ opts = QStringList::split( ' ', opts[1] );
+ for (QStringList::Iterator it = opts.begin(); it != opts.end(); ++it)
+ (*it).replace( "\\s", " " );
+
+ return true;
+}
+
+void
+DM::setLock( bool on )
+{
+ if (DMType != GDM)
+ exec( on ? "lock\n" : "unlock\n" );
+}
+
+bool
+DM::isSwitchable()
+{
+ if (DMType == OldKDM)
+ return dpy[0] == ':';
+
+ if (DMType == GDM)
+ return exec( "QUERY_VT\n" );
+
+ QCString re;
+
+ return exec( "caps\n", re ) && re.find( "\tlocal" ) >= 0;
+}
+
+int
+DM::numReserve()
+{
+ if (DMType == GDM)
+ return 1; /* Bleh */
+
+ if (DMType == OldKDM)
+ return strstr( ctl, ",rsvd" ) ? 1 : -1;
+
+ QCString re;
+ int p;
+
+ if (!(exec( "caps\n", re ) && (p = re.find( "\treserve " )) >= 0))
+ return -1;
+ return atoi( re.data() + p + 9 );
+}
+
+void
+DM::startReserve()
+{
+ if (DMType == GDM)
+ exec("FLEXI_XSERVER\n");
+ else
+ exec("reserve\n");
+}
+
+bool
+DM::localSessions( SessList &list )
+{
+ if (DMType == OldKDM)
+ return false;
+
+ QCString re;
+
+ if (DMType == GDM) {
+ if (!exec( "CONSOLE_SERVERS\n", re ))
+ return false;
+ QStringList sess = QStringList::split( QChar(';'), re.data() + 3 );
+ for (QStringList::ConstIterator it = sess.begin(); it != sess.end(); ++it) {
+ QStringList ts = QStringList::split( QChar(','), *it, true );
+ SessEnt se;
+ se.display = ts[0];
+ se.user = ts[1];
+ se.vt = ts[2].toInt();
+ se.session = "<unknown>";
+ se.self = ts[0] == ::getenv( "DISPLAY" ); /* Bleh */
+ se.tty = false;
+ list.append( se );
+ }
+ } else {
+ if (!exec( "list\talllocal\n", re ))
+ return false;
+ QStringList sess = QStringList::split( QChar('\t'), re.data() + 3 );
+ for (QStringList::ConstIterator it = sess.begin(); it != sess.end(); ++it) {
+ QStringList ts = QStringList::split( QChar(','), *it, true );
+ SessEnt se;
+ se.display = ts[0];
+ if (ts[1][0] == '@')
+ se.from = ts[1].mid( 1 ), se.vt = 0;
+ else
+ se.vt = ts[1].mid( 2 ).toInt();
+ se.user = ts[2];
+ se.session = ts[3];
+ se.self = (ts[4].find( '*' ) >= 0);
+ se.tty = (ts[4].find( 't' ) >= 0);
+ list.append( se );
+ }
+ }
+ return true;
+}
+
+void
+DM::sess2Str2( const SessEnt &se, QString &user, QString &loc )
+{
+ if (se.tty) {
+ user = i18n("user: ...", "%1: TTY login").arg( se.user );
+ loc = se.vt ? QString("vt%1").arg( se.vt ) : se.display ;
+ } else {
+ user =
+ se.user.isEmpty() ?
+ se.session.isEmpty() ?
+ i18n("Unused") :
+ se.session == "<remote>" ?
+ i18n("X login on remote host") :
+ i18n("... host", "X login on %1").arg( se.session ) :
+ se.session == "<unknown>" ?
+ se.user :
+ i18n("user: session type", "%1: %2")
+ .arg( se.user ).arg( se.session );
+ loc =
+ se.vt ?
+ QString("%1, vt%2").arg( se.display ).arg( se.vt ) :
+ se.display;
+ }
+}
+
+QString
+DM::sess2Str( const SessEnt &se )
+{
+ QString user, loc;
+
+ sess2Str2( se, user, loc );
+ return i18n("session (location)", "%1 (%2)").arg( user ).arg( loc );
+}
+
+bool
+DM::switchVT( int vt )
+{
+ if (DMType == GDM)
+ return exec( QString("SET_VT %1\n").arg(vt).latin1() );
+
+ return exec( QString("activate\tvt%1\n").arg(vt).latin1() );
+}
+
+void
+DM::lockSwitchVT( int vt )
+{
+ if (switchVT( vt ))
+ kapp->dcopClient()->send( "kdesktop", "KScreensaverIface", "lock()", "" );
+}
+
+void
+DM::GDMAuthenticate()
+{
+ FILE *fp;
+ const char *dpy, *dnum, *dne;
+ int dnl;
+ Xauth *xau;
+
+ dpy = DisplayString( QPaintDevice::x11AppDisplay() );
+ if (!dpy) {
+ dpy = ::getenv( "DISPLAY" );
+ if (!dpy)
+ return;
+ }
+ dnum = strchr( dpy, ':' ) + 1;
+ dne = strchr( dpy, '.' );
+ dnl = dne ? dne - dnum : strlen( dnum );
+
+ /* XXX should do locking */
+ if (!(fp = fopen( XauFileName(), "r" )))
+ return;
+
+ while ((xau = XauReadAuth( fp ))) {
+ if (xau->family == FamilyLocal &&
+ xau->number_length == dnl && !memcmp( xau->number, dnum, dnl ) &&
+ xau->data_length == 16 &&
+ xau->name_length == 18 && !memcmp( xau->name, "MIT-MAGIC-COOKIE-1", 18 ))
+ {
+ QString cmd( "AUTH_LOCAL " );
+ for (int i = 0; i < 16; i++)
+ cmd += QString::number( (uchar)xau->data[i], 16 ).rightJustify( 2, '0');
+ cmd += "\n";
+ if (exec( cmd.latin1() )) {
+ XauDisposeAuth( xau );
+ break;
+ }
+ }
+ XauDisposeAuth( xau );
+ }
+
+ fclose (fp);
+}
+
+#endif // Q_WS_X11
diff --git a/kdmlib/dmctl.h b/kdmlib/dmctl.h
new file mode 100644
index 000000000..aadc89bdb
--- /dev/null
+++ b/kdmlib/dmctl.h
@@ -0,0 +1,93 @@
+/*
+ Copyright (C) 2004,2005 Oswald Buddenhagen <ossi@kde.org>
+ Copyright (C) 2005 Stephan Kulow <coolo@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the Lesser GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef DMCTL_H
+#define DMCTL_H
+
+#include <kapplication.h>
+
+struct SessEnt {
+ QString display, from, user, session;
+ int vt;
+ bool self:1, tty:1;
+};
+
+typedef QValueList<SessEnt> SessList;
+
+class DM {
+
+#ifdef Q_WS_X11
+
+public:
+ DM();
+ ~DM();
+
+ bool canShutdown();
+ void shutdown( KApplication::ShutdownType shutdownType,
+ KApplication::ShutdownMode shutdownMode,
+ const QString &bootOption = QString::null );
+
+ void setLock( bool on );
+
+ bool isSwitchable();
+ int numReserve();
+ void startReserve();
+ bool localSessions( SessList &list );
+ bool switchVT( int vt );
+ void lockSwitchVT( int vt );
+
+ bool bootOptions( QStringList &opts, int &dflt, int &curr );
+
+ static QString sess2Str( const SessEnt &se );
+ static void sess2Str2( const SessEnt &se, QString &user, QString &loc );
+
+private:
+ int fd;
+
+ bool exec( const char *cmd, QCString &ret );
+ bool exec( const char *cmd );
+
+ void GDMAuthenticate();
+
+#else // Q_WS_X11
+
+public:
+ DM() {}
+
+ bool canShutdown() { return false; }
+ void shutdown( KApplication::ShutdownType shutdownType,
+ KApplication::ShutdownMode shutdownMode,
+ const QString &bootOption = QString::null ) {}
+
+ void setLock( bool ) {}
+
+ bool isSwitchable() { return false; }
+ int numReserve() { return -1; }
+ void startReserve() {}
+ bool localSessions( SessList &list ) { return false; }
+ void switchVT( int vt ) {}
+
+ bool bootOptions( QStringList &opts, int &dflt, int &curr );
+
+#endif // Q_WS_X11
+
+}; // class DM
+
+#endif // DMCTL_H
diff --git a/kdmlib/kgreet_classic.cpp b/kdmlib/kgreet_classic.cpp
new file mode 100644
index 000000000..b38e979d0
--- /dev/null
+++ b/kdmlib/kgreet_classic.cpp
@@ -0,0 +1,505 @@
+/*
+
+Conversation widget for kdm greeter
+
+Copyright (C) 1997, 1998, 2000 Steffen Hansen <hansen@kde.org>
+Copyright (C) 2000-2003 Oswald Buddenhagen <ossi@kde.org>
+
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+*/
+
+#include "kgreet_classic.h"
+#include "themer/kdmthemer.h"
+#include "themer/kdmitem.h"
+
+#include <klocale.h>
+#include <klineedit.h>
+#include <kpassdlg.h>
+#include <kuser.h>
+
+#include <qregexp.h>
+#include <qlayout.h>
+#include <qlabel.h>
+
+class KDMPasswordEdit : public KPasswordEdit {
+public:
+ KDMPasswordEdit( QWidget *parent ) : KPasswordEdit( parent, 0 ) {}
+ KDMPasswordEdit( KPasswordEdit::EchoModes echoMode, QWidget *parent ) : KPasswordEdit( echoMode, parent, 0 ) {}
+protected:
+ virtual void contextMenuEvent( QContextMenuEvent * ) {}
+};
+
+static int echoMode;
+
+KClassicGreeter::KClassicGreeter( KGreeterPluginHandler *_handler,
+ KdmThemer *themer,
+ QWidget *parent, QWidget *pred,
+ const QString &_fixedEntity,
+ Function _func, Context _ctx ) :
+ QObject(),
+ KGreeterPlugin( _handler ),
+ fixedUser( _fixedEntity ),
+ func( _func ),
+ ctx( _ctx ),
+ exp( -1 ),
+ pExp( -1 ),
+ running( false )
+{
+ KdmItem *user_entry = 0, *pw_entry = 0;
+ QGridLayout *grid = 0;
+ int line = 0;
+
+ layoutItem = 0;
+
+ if (themer &&
+ (!(user_entry = themer->findNode( "user-entry" )) ||
+ !(pw_entry = themer->findNode( "pw-entry" ))))
+ themer = 0;
+
+ if (!themer)
+ layoutItem = grid = new QGridLayout( 0, 0, 10 );
+
+ loginLabel = passwdLabel = passwd1Label = passwd2Label = 0;
+ loginEdit = 0;
+ passwdEdit = passwd1Edit = passwd2Edit = 0;
+ if (ctx == ExUnlock || ctx == ExChangeTok)
+ fixedUser = KUser().loginName();
+ if (func != ChAuthTok) {
+ if (fixedUser.isEmpty()) {
+ loginEdit = new KLineEdit( parent );
+ loginEdit->setContextMenuEnabled( false );
+ connect( loginEdit, SIGNAL(lostFocus()), SLOT(slotLoginLostFocus()) );
+ connect( loginEdit, SIGNAL(lostFocus()), SLOT(slotActivity()) );
+ connect( loginEdit, SIGNAL(textChanged( const QString & )), SLOT(slotActivity()) );
+ connect( loginEdit, SIGNAL(selectionChanged()), SLOT(slotActivity()) );
+ if (pred) {
+ parent->setTabOrder( pred, loginEdit );
+ pred = loginEdit;
+ }
+ if (!grid) {
+ loginEdit->adjustSize();
+ user_entry->setWidget( loginEdit );
+ } else {
+ loginLabel = new QLabel( loginEdit, i18n("&Username:"), parent );
+ grid->addWidget( loginLabel, line, 0 );
+ grid->addWidget( loginEdit, line++, 1 );
+ }
+ } else if (ctx != Login && ctx != Shutdown && grid) {
+ loginLabel = new QLabel( i18n("Username:"), parent );
+ grid->addWidget( loginLabel, line, 0 );
+ grid->addWidget( new QLabel( fixedUser, parent ), line++, 1 );
+ }
+ if (echoMode == -1)
+ passwdEdit = new KDMPasswordEdit( parent );
+ else
+ passwdEdit = new KDMPasswordEdit( (KPasswordEdit::EchoModes)echoMode,
+ parent );
+ connect( passwdEdit, SIGNAL(textChanged( const QString & )),
+ SLOT(slotActivity()) );
+ connect( passwdEdit, SIGNAL(lostFocus()), SLOT(slotActivity()) );
+ if (pred) {
+ parent->setTabOrder( pred, passwdEdit );
+ pred = passwdEdit;
+ }
+ if (!grid) {
+ passwdEdit->adjustSize();
+ pw_entry->setWidget( passwdEdit );
+ } else {
+ passwdLabel = new QLabel( passwdEdit,
+ func == Authenticate ?
+ i18n("&Password:") :
+ i18n("Current &password:"),
+ parent );
+ grid->addWidget( passwdLabel, line, 0 );
+ grid->addWidget( passwdEdit, line++, 1 );
+ }
+ if (loginEdit)
+ loginEdit->setFocus();
+ else
+ passwdEdit->setFocus();
+ }
+ if (func != Authenticate) {
+ if (echoMode == -1) {
+ passwd1Edit = new KDMPasswordEdit( (KPasswordEdit::EchoModes)echoMode, parent );
+ passwd2Edit = new KDMPasswordEdit( (KPasswordEdit::EchoModes)echoMode, parent );
+ } else {
+ passwd1Edit = new KDMPasswordEdit( parent );
+ passwd2Edit = new KDMPasswordEdit( parent );
+ }
+ passwd1Label = new QLabel( passwd1Edit, i18n("&New password:"), parent );
+ passwd2Label = new QLabel( passwd2Edit, i18n("Con&firm password:"), parent );
+ if (pred) {
+ parent->setTabOrder( pred, passwd1Edit );
+ parent->setTabOrder( passwd1Edit, passwd2Edit );
+ }
+ if (grid) {
+ grid->addWidget( passwd1Label, line, 0 );
+ grid->addWidget( passwd1Edit, line++, 1 );
+ grid->addWidget( passwd2Label, line, 0 );
+ grid->addWidget( passwd2Edit, line, 1 );
+ }
+ if (!passwdEdit)
+ passwd1Edit->setFocus();
+ }
+}
+
+// virtual
+KClassicGreeter::~KClassicGreeter()
+{
+ abort();
+ if (!layoutItem) {
+ delete loginEdit;
+ delete passwdEdit;
+ return;
+ }
+ QLayoutIterator it = static_cast<QLayout *>(layoutItem)->iterator();
+ for (QLayoutItem *itm = it.current(); itm; itm = ++it)
+ delete itm->widget();
+ delete layoutItem;
+}
+
+void // virtual
+KClassicGreeter::loadUsers( const QStringList &users )
+{
+ KCompletion *userNamesCompletion = new KCompletion;
+ userNamesCompletion->setItems( users );
+ loginEdit->setCompletionObject( userNamesCompletion );
+ loginEdit->setAutoDeleteCompletionObject( true );
+ loginEdit->setCompletionMode( KGlobalSettings::CompletionAuto );
+}
+
+void // virtual
+KClassicGreeter::presetEntity( const QString &entity, int field )
+{
+ loginEdit->setText( entity );
+ if (field == 1)
+ passwdEdit->setFocus();
+ else {
+ loginEdit->setFocus();
+ loginEdit->selectAll();
+ if (field == -1) {
+ passwdEdit->setText( " " );
+ passwdEdit->setEnabled( false );
+ authTok = false;
+ }
+ }
+ curUser = entity;
+}
+
+QString // virtual
+KClassicGreeter::getEntity() const
+{
+ return fixedUser.isEmpty() ? loginEdit->text() : fixedUser;
+}
+
+void // virtual
+KClassicGreeter::setUser( const QString &user )
+{
+ // assert( fixedUser.isEmpty() );
+ curUser = user;
+ loginEdit->setText( user );
+ passwdEdit->setFocus();
+ passwdEdit->selectAll();
+}
+
+void // virtual
+KClassicGreeter::setEnabled( bool enable )
+{
+ // assert( !passwd1Label );
+ // assert( func == Authenticate && ctx == Shutdown );
+// if (loginLabel)
+// loginLabel->setEnabled( enable );
+ passwdLabel->setEnabled( enable );
+ setActive( enable );
+ if (enable)
+ passwdEdit->setFocus();
+}
+
+void // private
+KClassicGreeter::returnData()
+{
+ switch (exp) {
+ case 0:
+ handler->gplugReturnText( (loginEdit ? loginEdit->text() :
+ fixedUser).local8Bit(),
+ KGreeterPluginHandler::IsUser );
+ break;
+ case 1:
+ handler->gplugReturnText( passwdEdit->password(),
+ KGreeterPluginHandler::IsPassword |
+ KGreeterPluginHandler::IsSecret );
+ break;
+ case 2:
+ handler->gplugReturnText( passwd1Edit->password(),
+ KGreeterPluginHandler::IsSecret );
+ break;
+ default: // case 3:
+ handler->gplugReturnText( passwd2Edit->password(),
+ KGreeterPluginHandler::IsNewPassword |
+ KGreeterPluginHandler::IsSecret );
+ break;
+ }
+}
+
+bool // virtual
+KClassicGreeter::textMessage( const char *text, bool err )
+{
+ if (!err &&
+ QString( text ).find( QRegExp( "^Changing password for [^ ]+$" ) ) >= 0)
+ return true;
+ return false;
+}
+
+void // virtual
+KClassicGreeter::textPrompt( const char *prompt, bool echo, bool nonBlocking )
+{
+ pExp = exp;
+ if (echo)
+ exp = 0;
+ else if (!authTok)
+ exp = 1;
+ else {
+ QString pr( prompt );
+ if (pr.find( QRegExp( "\\bpassword\\b", false ) ) >= 0) {
+ if (pr.find( QRegExp( "\\b(re-?(enter|type)|again|confirm|repeat)\\b",
+ false ) ) >= 0)
+ exp = 3;
+ else if (pr.find( QRegExp( "\\bnew\\b", false ) ) >= 0)
+ exp = 2;
+ else { // QRegExp( "\\b(old|current)\\b", false ) is too strict
+ handler->gplugReturnText( "",
+ KGreeterPluginHandler::IsOldPassword |
+ KGreeterPluginHandler::IsSecret );
+ return;
+ }
+ } else {
+ handler->gplugMsgBox( QMessageBox::Critical,
+ i18n("Unrecognized prompt \"%1\"")
+ .arg( prompt ) );
+ handler->gplugReturnText( 0, 0 );
+ exp = -1;
+ return;
+ }
+ }
+
+ if (pExp >= 0 && pExp >= exp) {
+ revive();
+ has = -1;
+ }
+
+ if (has >= exp || nonBlocking)
+ returnData();
+}
+
+bool // virtual
+KClassicGreeter::binaryPrompt( const char *, bool )
+{
+ // this simply cannot happen ... :}
+ return true;
+}
+
+void // virtual
+KClassicGreeter::start()
+{
+ authTok = !(passwdEdit && passwdEdit->isEnabled());
+ exp = has = -1;
+ running = true;
+}
+
+void // virtual
+KClassicGreeter::suspend()
+{
+}
+
+void // virtual
+KClassicGreeter::resume()
+{
+}
+
+void // virtual
+KClassicGreeter::next()
+{
+ // assert( running );
+ if (loginEdit && loginEdit->hasFocus()) {
+ passwdEdit->setFocus(); // will cancel running login if necessary
+ has = 0;
+ } else if (passwdEdit && passwdEdit->hasFocus()) {
+ if (passwd1Edit)
+ passwd1Edit->setFocus();
+ has = 1;
+ } else if (passwd1Edit) {
+ if (passwd1Edit->hasFocus()) {
+ passwd2Edit->setFocus();
+ has = 1; // sic!
+ } else
+ has = 3;
+ } else
+ has = 1;
+ if (exp < 0)
+ handler->gplugStart();
+ else if (has >= exp)
+ returnData();
+}
+
+void // virtual
+KClassicGreeter::abort()
+{
+ running = false;
+ if (exp >= 0) {
+ exp = -1;
+ handler->gplugReturnText( 0, 0 );
+ }
+}
+
+void // virtual
+KClassicGreeter::succeeded()
+{
+ // assert( running || timed_login );
+ if (!authTok) {
+ setActive( false );
+ if (passwd1Edit) {
+ authTok = true;
+ return;
+ }
+ } else
+ setActive2( false );
+ exp = -1;
+ running = false;
+}
+
+void // virtual
+KClassicGreeter::failed()
+{
+ // assert( running || timed_login );
+ setActive( false );
+ setActive2( false );
+ exp = -1;
+ running = false;
+}
+
+void // virtual
+KClassicGreeter::revive()
+{
+ // assert( !running );
+ setActive2( true );
+ if (authTok) {
+ passwd1Edit->erase();
+ passwd2Edit->erase();
+ passwd1Edit->setFocus();
+ } else {
+ passwdEdit->erase();
+ if (loginEdit && loginEdit->isEnabled())
+ passwdEdit->setEnabled( true );
+ else {
+ setActive( true );
+ if (loginEdit && loginEdit->text().isEmpty())
+ loginEdit->setFocus();
+ else
+ passwdEdit->setFocus();
+ }
+ }
+}
+
+void // virtual
+KClassicGreeter::clear()
+{
+ // assert( !running && !passwd1Edit );
+ passwdEdit->erase();
+ if (loginEdit) {
+ loginEdit->clear();
+ loginEdit->setFocus();
+ curUser = QString::null;
+ } else
+ passwdEdit->setFocus();
+}
+
+
+// private
+
+void
+KClassicGreeter::setActive( bool enable )
+{
+ if (loginEdit)
+ loginEdit->setEnabled( enable );
+ if (passwdEdit)
+ passwdEdit->setEnabled( enable );
+}
+
+void
+KClassicGreeter::setActive2( bool enable )
+{
+ if (passwd1Edit) {
+ passwd1Edit->setEnabled( enable );
+ passwd2Edit->setEnabled( enable );
+ }
+}
+
+void
+KClassicGreeter::slotLoginLostFocus()
+{
+ if (!running)
+ return;
+ if (exp > 0) {
+ if (curUser == loginEdit->text())
+ return;
+ exp = -1;
+ handler->gplugReturnText( 0, 0 );
+ }
+ curUser = loginEdit->text();
+ handler->gplugSetUser( curUser );
+}
+
+void
+KClassicGreeter::slotActivity()
+{
+ if (running)
+ handler->gplugActivity();
+}
+
+// factory
+
+static bool init( const QString &,
+ QVariant (*getConf)( void *, const char *, const QVariant & ),
+ void *ctx )
+{
+ echoMode = getConf( ctx, "EchoMode", QVariant( -1 ) ).toInt();
+ KGlobal::locale()->insertCatalogue( "kgreet_classic" );
+ return true;
+}
+
+static void done( void )
+{
+ KGlobal::locale()->removeCatalogue( "kgreet_classic" );
+}
+
+static KGreeterPlugin *
+create( KGreeterPluginHandler *handler, KdmThemer *themer,
+ QWidget *parent, QWidget *predecessor,
+ const QString &fixedEntity,
+ KGreeterPlugin::Function func,
+ KGreeterPlugin::Context ctx )
+{
+ return new KClassicGreeter( handler, themer, parent, predecessor, fixedEntity, func, ctx );
+}
+
+KDE_EXPORT kgreeterplugin_info kgreeterplugin_info = {
+ I18N_NOOP("Username + password (classic)"), "classic",
+ kgreeterplugin_info::Local | kgreeterplugin_info::Presettable,
+ init, done, create
+};
+
+#include "kgreet_classic.moc"
diff --git a/kdmlib/kgreet_classic.h b/kdmlib/kgreet_classic.h
new file mode 100644
index 000000000..64d39799a
--- /dev/null
+++ b/kdmlib/kgreet_classic.h
@@ -0,0 +1,87 @@
+/*
+
+Conversation widget for kdm greeter
+
+Copyright (C) 1997, 1998 Steffen Hansen <hansen@kde.org>
+Copyright (C) 2000-2003 Oswald Buddenhagen <ossi@kde.org>
+
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+*/
+
+
+#ifndef KGREET_CLASSIC_H
+#define KGREET_CLASSIC_H
+
+#include "kgreeterplugin.h"
+
+#include <qobject.h>
+
+class KLineEdit;
+class KPasswordEdit;
+class KSimpleConfig;
+class QGridLayout;
+class QLabel;
+
+class KClassicGreeter : public QObject, public KGreeterPlugin {
+ Q_OBJECT
+
+ public:
+ KClassicGreeter( KGreeterPluginHandler *handler,
+ KdmThemer *themer,
+ QWidget *parent, QWidget *predecessor,
+ const QString &fixedEntitiy,
+ Function func, Context ctx );
+ ~KClassicGreeter();
+ virtual void loadUsers( const QStringList &users );
+ virtual void presetEntity( const QString &entity, int field );
+ virtual QString getEntity() const;
+ virtual void setUser( const QString &user );
+ virtual void setEnabled( bool on );
+ virtual bool textMessage( const char *message, bool error );
+ virtual void textPrompt( const char *prompt, bool echo, bool nonBlocking );
+ virtual bool binaryPrompt( const char *prompt, bool nonBlocking );
+ virtual void start();
+ virtual void suspend();
+ virtual void resume();
+ virtual void next();
+ virtual void abort();
+ virtual void succeeded();
+ virtual void failed();
+ virtual void revive();
+ virtual void clear();
+
+ public slots:
+ void slotLoginLostFocus();
+ void slotActivity();
+
+ private:
+ void setActive( bool enable );
+ void setActive2( bool enable );
+ void returnData();
+
+ QLabel *loginLabel, *passwdLabel, *passwd1Label, *passwd2Label;
+ KLineEdit *loginEdit;
+ KPasswordEdit *passwdEdit, *passwd1Edit, *passwd2Edit;
+ KSimpleConfig *stsFile;
+ QString fixedUser, curUser;
+ Function func;
+ Context ctx;
+ int exp, pExp, has;
+ bool running, authTok;
+};
+
+#endif /* KGREET_CLASSIC_H */
diff --git a/kdmlib/kgreet_winbind.cpp b/kdmlib/kgreet_winbind.cpp
new file mode 100644
index 000000000..eeef08b01
--- /dev/null
+++ b/kdmlib/kgreet_winbind.cpp
@@ -0,0 +1,671 @@
+/*
+
+Conversation widget for kdm greeter
+
+Copyright (C) 1997, 1998, 2000 Steffen Hansen <hansen@kde.org>
+Copyright (C) 2000-2004 Oswald Buddenhagen <ossi@kde.org>
+
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+*/
+
+#include "kgreet_winbind.h"
+#include "themer/kdmthemer.h"
+#include "themer/kdmitem.h"
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kcombobox.h>
+#include <klineedit.h>
+#include <kpassdlg.h>
+#include <kuser.h>
+#include <kprocio.h>
+
+#include <qregexp.h>
+#include <qlayout.h>
+#include <qlabel.h>
+
+#include <stdlib.h>
+
+class KDMPasswordEdit : public KPasswordEdit {
+public:
+ KDMPasswordEdit( QWidget *parent ) : KPasswordEdit( parent, 0 ) {}
+ KDMPasswordEdit( KPasswordEdit::EchoModes echoMode, QWidget *parent ) : KPasswordEdit( echoMode, parent, 0 ) {}
+protected:
+ virtual void contextMenuEvent( QContextMenuEvent * ) {}
+};
+
+static int echoMode;
+static char separator;
+static QStringList staticDomains;
+static QString defaultDomain;
+
+static void
+splitEntity( const QString &ent, QString &dom, QString &usr )
+{
+ int pos = ent.find( separator );
+ if (pos < 0)
+ dom = "<local>", usr = ent;
+ else
+ dom = ent.left( pos ), usr = ent.mid( pos + 1 );
+}
+
+KWinbindGreeter::KWinbindGreeter( KGreeterPluginHandler *_handler,
+ KdmThemer *themer,
+ QWidget *parent, QWidget *pred,
+ const QString &_fixedEntity,
+ Function _func, Context _ctx ) :
+ QObject(),
+ KGreeterPlugin( _handler ),
+ func( _func ),
+ ctx( _ctx ),
+ exp( -1 ),
+ pExp( -1 ),
+ running( false )
+{
+ KdmItem *user_entry = 0, *pw_entry = 0, *domain_entry = 0;
+ QGridLayout *grid = 0;
+
+ int line = 0;
+ layoutItem = 0;
+
+ if (themer &&
+ (!(user_entry = themer->findNode( "user-entry" )) ||
+ !(pw_entry = themer->findNode( "pw-entry" )) ||
+ !(domain_entry = themer->findNode( "domain-entry" ))))
+ themer = 0;
+
+ if (!themer)
+ layoutItem = grid = new QGridLayout( 0, 0, 10 );
+
+ domainLabel = loginLabel = passwdLabel = passwd1Label = passwd2Label = 0;
+ domainCombo = 0;
+ loginEdit = 0;
+ passwdEdit = passwd1Edit = passwd2Edit = 0;
+ m_domainLister = 0;
+ if (ctx == ExUnlock || ctx == ExChangeTok)
+ splitEntity( KUser().loginName(), fixedDomain, fixedUser );
+ else
+ splitEntity( _fixedEntity, fixedDomain, fixedUser );
+ if (func != ChAuthTok) {
+ if (fixedUser.isEmpty()) {
+ domainCombo = new KComboBox( parent );
+ connect( domainCombo, SIGNAL(activated( const QString & )),
+ SLOT(slotChangedDomain( const QString & )) );
+ connect( domainCombo, SIGNAL(activated( const QString & )),
+ SLOT(slotLoginLostFocus()) );
+ connect( domainCombo, SIGNAL(activated( const QString & )),
+ SLOT(slotActivity()) );
+ // should handle loss of focus
+ loginEdit = new KLineEdit( parent );
+ loginEdit->setContextMenuEnabled( false );
+
+ if (pred) {
+ parent->setTabOrder( pred, domainCombo );
+ parent->setTabOrder( domainCombo, loginEdit );
+ pred = loginEdit;
+ }
+ if (!grid) {
+ loginEdit->adjustSize();
+ domainCombo->adjustSize();
+ user_entry->setWidget( loginEdit );
+ domain_entry->setWidget( domainCombo );
+ } else {
+ domainLabel = new QLabel( domainCombo, i18n("&Domain:"), parent );
+ loginLabel = new QLabel( loginEdit, i18n("&Username:"), parent );
+ grid->addWidget( domainLabel, line, 0 );
+ grid->addWidget( domainCombo, line++, 1 );
+ grid->addWidget( loginLabel, line, 0 );
+ grid->addWidget( loginEdit, line++, 1 );
+ }
+ connect( loginEdit, SIGNAL(lostFocus()), SLOT(slotLoginLostFocus()) );
+ connect( loginEdit, SIGNAL(lostFocus()), SLOT(slotActivity()) );
+ connect( loginEdit, SIGNAL(textChanged( const QString & )), SLOT(slotActivity()) );
+ connect( loginEdit, SIGNAL(selectionChanged()), SLOT(slotActivity()) );
+ connect(&mDomainListTimer, SIGNAL(timeout()), SLOT(slotStartDomainList()));
+ domainCombo->insertStringList( staticDomains );
+ QTimer::singleShot(0, this, SLOT(slotStartDomainList()));
+ } else if (ctx != Login && ctx != Shutdown && grid) {
+ domainLabel = new QLabel( i18n("Domain:"), parent );
+ grid->addWidget( domainLabel, line, 0 );
+ grid->addWidget( new QLabel( fixedDomain, parent ), line++, 1 );
+ loginLabel = new QLabel( i18n("Username:"), parent );
+ grid->addWidget( loginLabel, line, 0 );
+ grid->addWidget( new QLabel( fixedUser, parent ), line++, 1 );
+ }
+ if (echoMode == -1)
+ passwdEdit = new KDMPasswordEdit( parent );
+ else
+ passwdEdit = new KDMPasswordEdit( (KPasswordEdit::EchoModes)echoMode,
+ parent );
+ connect( passwdEdit, SIGNAL(textChanged( const QString & )),
+ SLOT(slotActivity()) );
+ connect( passwdEdit, SIGNAL(lostFocus()), SLOT(slotActivity()) );
+
+ if (!grid) {
+ passwdEdit->adjustSize();
+ pw_entry->setWidget( passwdEdit );
+ } else {
+ passwdLabel = new QLabel( passwdEdit,
+ func == Authenticate ?
+ i18n("&Password:") :
+ i18n("Current &password:"),
+ parent );
+ if (pred) {
+ parent->setTabOrder( pred, passwdEdit );
+ pred = passwdEdit;
+ }
+ grid->addWidget( passwdLabel, line, 0 );
+ grid->addWidget( passwdEdit, line++, 1 );
+ }
+
+ if (loginEdit)
+ loginEdit->setFocus();
+ else
+ passwdEdit->setFocus();
+ }
+ if (func != Authenticate) {
+ if (echoMode == -1) {
+ passwd1Edit = new KDMPasswordEdit( (KPasswordEdit::EchoModes)echoMode, parent );
+ passwd2Edit = new KDMPasswordEdit( (KPasswordEdit::EchoModes)echoMode, parent );
+ } else {
+ passwd1Edit = new KDMPasswordEdit( parent );
+ passwd2Edit = new KDMPasswordEdit( parent );
+ }
+ passwd1Label = new QLabel( passwd1Edit, i18n("&New password:"), parent );
+ passwd2Label = new QLabel( passwd2Edit, i18n("Con&firm password:"), parent );
+ if (pred) {
+ parent->setTabOrder( pred, passwd1Edit );
+ parent->setTabOrder( passwd1Edit, passwd2Edit );
+ }
+ if (grid) {
+ grid->addWidget( passwd1Label, line, 0 );
+ grid->addWidget( passwd1Edit, line++, 1 );
+ grid->addWidget( passwd2Label, line, 0 );
+ grid->addWidget( passwd2Edit, line, 1 );
+ }
+ if (!passwdEdit)
+ passwd1Edit->setFocus();
+ }
+}
+
+// virtual
+KWinbindGreeter::~KWinbindGreeter()
+{
+ abort();
+ if (!layoutItem) {
+ delete loginEdit;
+ delete passwdEdit;
+ delete domainCombo;
+ return;
+ }
+ QLayoutIterator it = static_cast<QLayout *>(layoutItem)->iterator();
+ for (QLayoutItem *itm = it.current(); itm; itm = ++it)
+ delete itm->widget();
+ delete layoutItem;
+ delete m_domainLister;
+}
+
+void
+KWinbindGreeter::slotChangedDomain( const QString &dom )
+{
+ if (!loginEdit->completionObject())
+ return;
+ QStringList users;
+ if (dom == "<local>") {
+ for (QStringList::ConstIterator it = allUsers.begin(); it != allUsers.end(); ++it)
+ if ((*it).find( separator ) < 0)
+ users << *it;
+ } else {
+ QString st( dom + separator );
+ for (QStringList::ConstIterator it = allUsers.begin(); it != allUsers.end(); ++it)
+ if ((*it).startsWith( st ))
+ users << (*it).mid( st.length() );
+ }
+ loginEdit->completionObject()->setItems( users );
+}
+
+void // virtual
+KWinbindGreeter::loadUsers( const QStringList &users )
+{
+ allUsers = users;
+ KCompletion *userNamesCompletion = new KCompletion;
+ loginEdit->setCompletionObject( userNamesCompletion );
+ loginEdit->setAutoDeleteCompletionObject( true );
+ loginEdit->setCompletionMode( KGlobalSettings::CompletionAuto );
+ slotChangedDomain( defaultDomain );
+}
+
+void // virtual
+KWinbindGreeter::presetEntity( const QString &entity, int field )
+{
+ QString dom, usr;
+ splitEntity( entity, dom, usr );
+ domainCombo->setCurrentItem( dom, true );
+ slotChangedDomain( dom );
+ loginEdit->setText( usr );
+ if (field > 1)
+ passwdEdit->setFocus();
+ else if (field == 1 || field == -1) {
+ if (field == -1) {
+ passwdEdit->setText( " " );
+ passwdEdit->setEnabled( false );
+ authTok = false;
+ }
+ loginEdit->setFocus();
+ loginEdit->selectAll();
+ }
+ curUser = entity;
+}
+
+QString // virtual
+KWinbindGreeter::getEntity() const
+{
+ QString dom, usr;
+ if (fixedUser.isEmpty())
+ dom = domainCombo->currentText(), usr = loginEdit->text();
+ else
+ dom = fixedDomain, usr = fixedUser;
+ return dom == "<local>" ? usr : dom + separator + usr;
+}
+
+void // virtual
+KWinbindGreeter::setUser( const QString &user )
+{
+ // assert (fixedUser.isEmpty());
+ curUser = user;
+ QString dom, usr;
+ splitEntity( user, dom, usr );
+ domainCombo->setCurrentItem( dom, true );
+ slotChangedDomain( dom );
+ loginEdit->setText( usr );
+ passwdEdit->setFocus();
+ passwdEdit->selectAll();
+}
+
+void // virtual
+KWinbindGreeter::setEnabled( bool enable )
+{
+ // assert( !passwd1Label );
+ // assert( func == Authenticate && ctx == Shutdown );
+// if (domainCombo)
+// domainCombo->setEnabled( enable );
+// if (loginLabel)
+// loginLabel->setEnabled( enable );
+ passwdLabel->setEnabled( enable );
+ setActive( enable );
+ if (enable)
+ passwdEdit->setFocus();
+}
+
+void // private
+KWinbindGreeter::returnData()
+{
+ switch (exp) {
+ case 0:
+ handler->gplugReturnText( getEntity().local8Bit(),
+ KGreeterPluginHandler::IsUser );
+ break;
+ case 1:
+ handler->gplugReturnText( passwdEdit->password(),
+ KGreeterPluginHandler::IsPassword |
+ KGreeterPluginHandler::IsSecret );
+ break;
+ case 2:
+ handler->gplugReturnText( passwd1Edit->password(),
+ KGreeterPluginHandler::IsSecret );
+ break;
+ default: // case 3:
+ handler->gplugReturnText( passwd2Edit->password(),
+ KGreeterPluginHandler::IsNewPassword |
+ KGreeterPluginHandler::IsSecret );
+ break;
+ }
+}
+
+bool // virtual
+KWinbindGreeter::textMessage( const char *text, bool err )
+{
+ if (!err &&
+ QString( text ).find( QRegExp( "^Changing password for [^ ]+$" ) ) >= 0)
+ return true;
+ return false;
+}
+
+void // virtual
+KWinbindGreeter::textPrompt( const char *prompt, bool echo, bool nonBlocking )
+{
+ pExp = exp;
+ if (echo)
+ exp = 0;
+ else if (!authTok)
+ exp = 1;
+ else {
+ QString pr( prompt );
+ if (pr.find( QRegExp( "\\b(old|current)\\b", false ) ) >= 0) {
+ handler->gplugReturnText( "",
+ KGreeterPluginHandler::IsOldPassword |
+ KGreeterPluginHandler::IsSecret );
+ return;
+ } else if (pr.find( QRegExp( "\\b(re-?(enter|type)|again|confirm|repeat)\\b",
+ false ) ) >= 0)
+ exp = 3;
+ else if (pr.find( QRegExp( "\\bnew\\b", false ) ) >= 0)
+ exp = 2;
+ else {
+ handler->gplugMsgBox( QMessageBox::Critical,
+ i18n("Unrecognized prompt \"%1\"")
+ .arg( prompt ) );
+ handler->gplugReturnText( 0, 0 );
+ exp = -1;
+ return;
+ }
+ }
+
+ if (pExp >= 0 && pExp >= exp) {
+ revive();
+ has = -1;
+ }
+
+ if (has >= exp || nonBlocking)
+ returnData();
+}
+
+bool // virtual
+KWinbindGreeter::binaryPrompt( const char *, bool )
+{
+ // this simply cannot happen ... :}
+ return true;
+}
+
+void // virtual
+KWinbindGreeter::start()
+{
+ authTok = !(passwdEdit && passwdEdit->isEnabled());
+ exp = has = -1;
+ running = true;
+}
+
+void // virtual
+KWinbindGreeter::suspend()
+{
+}
+
+void // virtual
+KWinbindGreeter::resume()
+{
+}
+
+void // virtual
+KWinbindGreeter::next()
+{
+ // assert( running );
+ if (domainCombo && domainCombo->hasFocus())
+ loginEdit->setFocus();
+ else if (loginEdit && loginEdit->hasFocus()) {
+ passwdEdit->setFocus(); // will cancel running login if necessary
+ has = 0;
+ } else if (passwdEdit && passwdEdit->hasFocus()) {
+ if (passwd1Edit)
+ passwd1Edit->setFocus();
+ has = 1;
+ } else if (passwd1Edit) {
+ if (passwd1Edit->hasFocus()) {
+ passwd2Edit->setFocus();
+ has = 1; // sic!
+ } else
+ has = 3;
+ } else
+ has = 1;
+ if (exp < 0)
+ handler->gplugStart();
+ else if (has >= exp)
+ returnData();
+}
+
+void // virtual
+KWinbindGreeter::abort()
+{
+ running = false;
+ if (exp >= 0) {
+ exp = -1;
+ handler->gplugReturnText( 0, 0 );
+ }
+}
+
+void // virtual
+KWinbindGreeter::succeeded()
+{
+ // assert( running || timed_login );
+ if (!authTok) {
+ setActive( false );
+ if (passwd1Edit) {
+ authTok = true;
+ return;
+ }
+ } else
+ setActive2( false );
+ exp = -1;
+ running = false;
+}
+
+void // virtual
+KWinbindGreeter::failed()
+{
+ // assert( running || timed_login );
+ setActive( false );
+ setActive2( false );
+ exp = -1;
+ running = false;
+}
+
+void // virtual
+KWinbindGreeter::revive()
+{
+ // assert( !running );
+ setActive2( true );
+ if (authTok) {
+ passwd1Edit->erase();
+ passwd2Edit->erase();
+ passwd1Edit->setFocus();
+ } else {
+ passwdEdit->erase();
+ if (loginEdit && loginEdit->isEnabled())
+ passwdEdit->setEnabled( true );
+ else {
+ setActive( true );
+ if (loginEdit && loginEdit->text().isEmpty())
+ loginEdit->setFocus();
+ else
+ passwdEdit->setFocus();
+ }
+ }
+}
+
+void // virtual
+KWinbindGreeter::clear()
+{
+ // assert( !running && !passwd1Edit );
+ passwdEdit->erase();
+ if (loginEdit) {
+ domainCombo->setCurrentItem( defaultDomain );
+ slotChangedDomain( defaultDomain );
+ loginEdit->clear();
+ loginEdit->setFocus();
+ curUser = QString::null;
+ } else
+ passwdEdit->setFocus();
+}
+
+
+// private
+
+void
+KWinbindGreeter::setActive( bool enable )
+{
+ if (domainCombo)
+ domainCombo->setEnabled( enable );
+ if (loginEdit)
+ loginEdit->setEnabled( enable );
+ if (passwdEdit)
+ passwdEdit->setEnabled( enable );
+}
+
+void
+KWinbindGreeter::setActive2( bool enable )
+{
+ if (passwd1Edit) {
+ passwd1Edit->setEnabled( enable );
+ passwd2Edit->setEnabled( enable );
+ }
+}
+
+void
+KWinbindGreeter::slotLoginLostFocus()
+{
+ if (!running)
+ return;
+ QString ent( getEntity() );
+ if (exp > 0) {
+ if (curUser == ent)
+ return;
+ exp = -1;
+ handler->gplugReturnText( 0, 0 );
+ }
+ curUser = ent;
+ handler->gplugSetUser( curUser );
+}
+
+void
+KWinbindGreeter::slotActivity()
+{
+ if (running)
+ handler->gplugActivity();
+}
+
+void
+KWinbindGreeter::slotStartDomainList()
+{
+ mDomainListTimer.stop();
+ mDomainListing.clear();
+
+ m_domainLister = new KProcIO;
+ connect(m_domainLister, SIGNAL(readReady(KProcIO*)), SLOT(slotReadDomainList()));
+ connect(m_domainLister, SIGNAL(processExited(KProcess*)), SLOT(slotEndDomainList()));
+
+ (*m_domainLister) << "wbinfo" << "--own-domain" << "--trusted-domains";
+ m_domainLister->setComm (KProcess::Stdout);
+ m_domainLister->start();
+}
+
+void
+KWinbindGreeter::slotReadDomainList()
+{
+ QString line;
+
+ while ( m_domainLister->readln( line ) != -1 ) {
+ mDomainListing.append(line);
+ }
+}
+
+void
+KWinbindGreeter::slotEndDomainList()
+{
+ delete m_domainLister;
+ m_domainLister = 0;
+
+ QStringList domainList;
+ domainList = staticDomains;
+
+ for (QStringList::const_iterator it = mDomainListing.begin();
+ it != mDomainListing.end(); ++it) {
+
+ if (!domainList.contains(*it))
+ domainList.append(*it);
+ }
+
+ QString current = domainCombo->currentText();
+
+ for (int i = 0; i < domainList.count(); ++i) {
+ if (i < domainCombo->count())
+ domainCombo->changeItem(domainList[i], i);
+ else
+ domainCombo->insertItem(domainList[i], i);
+ }
+
+ while (domainCombo->count() > domainList.count())
+ domainCombo->removeItem(domainCombo->count()-1);
+
+ domainCombo->setCurrentItem( current );
+
+ if (domainCombo->currentText() != current)
+ domainCombo->setCurrentItem( defaultDomain );
+
+ mDomainListTimer.start(5 * 1000);
+}
+
+// factory
+
+static bool init( const QString &,
+ QVariant (*getConf)( void *, const char *, const QVariant & ),
+ void *ctx )
+{
+ echoMode = getConf( ctx, "EchoMode", QVariant( -1 ) ).toInt();
+ staticDomains = QStringList::split( ':', getConf( ctx, "winbind.Domains", QVariant( "" ) ).toString() );
+ if (!staticDomains.contains("<local>"))
+ staticDomains << "<local>";
+
+ defaultDomain = getConf( ctx, "winbind.DefaultDomain", QVariant( staticDomains.first() ) ).toString();
+ QString sepstr = getConf( ctx, "winbind.Separator", QVariant( QString::null ) ).toString();
+ if (sepstr.isNull()) {
+ FILE *sepfile = popen( "wbinfo --separator 2>/dev/null", "r" );
+ if (sepfile) {
+ QTextIStream( sepfile ) >> sepstr;
+ if (pclose( sepfile ))
+ sepstr = "\\";
+ } else
+ sepstr = "\\";
+ }
+ separator = sepstr[0].latin1();
+ KGlobal::locale()->insertCatalogue( "kgreet_winbind" );
+ return true;
+}
+
+static void done( void )
+{
+ KGlobal::locale()->removeCatalogue( "kgreet_winbind" );
+ // avoid static deletion problems ... hopefully
+ staticDomains.clear();
+ defaultDomain = QString::null;
+}
+
+static KGreeterPlugin *
+create( KGreeterPluginHandler *handler, KdmThemer *themer,
+ QWidget *parent, QWidget *predecessor,
+ const QString &fixedEntity,
+ KGreeterPlugin::Function func,
+ KGreeterPlugin::Context ctx )
+{
+ return new KWinbindGreeter( handler, themer, parent, predecessor, fixedEntity, func, ctx );
+}
+
+KDE_EXPORT kgreeterplugin_info kgreeterplugin_info = {
+ I18N_NOOP("Winbind / Samba"), "classic",
+ kgreeterplugin_info::Local | kgreeterplugin_info::Fielded | kgreeterplugin_info::Presettable,
+ init, done, create
+};
+
+#include "kgreet_winbind.moc"
diff --git a/kdmlib/kgreet_winbind.h b/kdmlib/kgreet_winbind.h
new file mode 100644
index 000000000..7fc6a1c77
--- /dev/null
+++ b/kdmlib/kgreet_winbind.h
@@ -0,0 +1,100 @@
+/*
+
+Conversation widget for kdm greeter
+
+Copyright (C) 1997, 1998 Steffen Hansen <hansen@kde.org>
+Copyright (C) 2000-2003 Oswald Buddenhagen <ossi@kde.org>
+
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+*/
+
+
+#ifndef KGREET_WINBIND_H
+#define KGREET_WINBIND_H
+
+#include "kgreeterplugin.h"
+
+#include <qobject.h>
+#include <qtimer.h>
+
+class KComboBox;
+class KLineEdit;
+class KPasswordEdit;
+class KSimpleConfig;
+class QGridLayout;
+class QLabel;
+class KdmThemer;
+class KProcIO;
+
+class KWinbindGreeter : public QObject, public KGreeterPlugin {
+ Q_OBJECT
+
+ public:
+ KWinbindGreeter( KGreeterPluginHandler *handler,
+ KdmThemer *themer,
+ QWidget *parent, QWidget *predecessor,
+ const QString &fixedEntitiy,
+ Function func, Context ctx );
+ ~KWinbindGreeter();
+ virtual void loadUsers( const QStringList &users );
+ virtual void presetEntity( const QString &entity, int field );
+ virtual QString getEntity() const;
+ virtual void setUser( const QString &user );
+ virtual void setEnabled( bool on );
+ virtual bool textMessage( const char *message, bool error );
+ virtual void textPrompt( const char *prompt, bool echo, bool nonBlocking );
+ virtual bool binaryPrompt( const char *prompt, bool nonBlocking );
+ virtual void start();
+ virtual void suspend();
+ virtual void resume();
+ virtual void next();
+ virtual void abort();
+ virtual void succeeded();
+ virtual void failed();
+ virtual void revive();
+ virtual void clear();
+
+ public slots:
+ void slotLoginLostFocus();
+ void slotChangedDomain( const QString &dom );
+ void slotActivity();
+ void slotStartDomainList();
+ void slotReadDomainList();
+ void slotEndDomainList();
+
+ private:
+ void setActive( bool enable );
+ void setActive2( bool enable );
+ void returnData();
+
+ QLabel *domainLabel, *loginLabel, *passwdLabel, *passwd1Label, *passwd2Label;
+ KComboBox *domainCombo;
+ KLineEdit *loginEdit;
+ KPasswordEdit *passwdEdit, *passwd1Edit, *passwd2Edit;
+ KSimpleConfig *stsFile;
+ QString fixedDomain, fixedUser, curUser;
+ QStringList allUsers, mDomainListing;
+ KProcIO* m_domainLister;
+ QTimer mDomainListTimer;
+
+ Function func;
+ Context ctx;
+ int exp, pExp, has;
+ bool running, authTok;
+};
+
+#endif /* KGREET_WINBIND_H */
diff --git a/kdmlib/kgreeterplugin.h b/kdmlib/kgreeterplugin.h
new file mode 100644
index 000000000..e7677415c
--- /dev/null
+++ b/kdmlib/kgreeterplugin.h
@@ -0,0 +1,401 @@
+/*
+
+ Authentication method specific conversation plugin for KDE's greeter widgets
+
+ Copyright (C) 2003 Oswald Buddenhagen <ossi@kde.org>
+ Copyright (C) 2003 Fabian Kaiser <xfk@softpro.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KGREETERPLUGIN_H
+#define KGREETERPLUGIN_H
+
+#include <qvariant.h>
+#include <qmessagebox.h>
+#include <kdemacros.h>
+
+class KdmThemer;
+
+class QWidget;
+class QLayoutItem;
+
+class KGreeterPluginHandler {
+public:
+ /* keep in sync with V_IS_* */
+ enum { IsSecret = 1, IsUser = 2, IsPassword = 4, IsOldPassword = 8,
+ IsNewPassword = 16 };
+ /**
+ * Reply to textPrompt().
+ * @param text text to return to core; null to abort auth cycle
+ * @param tag zero or one of Is*
+ */
+ virtual void gplugReturnText( const char *text, int tag ) = 0;
+ /**
+ * Reply to binaryPrompt().
+ * @param data data in pam_client format to return to the core;
+ * null to abort auth cycle
+ */
+ virtual void gplugReturnBinary( const char *data ) = 0;
+ /**
+ * Tell the greeter who is logging in.
+ * Call this preferably before gplugStart, as otherwise the .dmrc
+ * load will be delayed. Don't call at all if your plugin doesn't
+ * have the Local flag set. Call only for internally generated
+ * user changes.
+ * @param user the user logging in
+ */
+ virtual void gplugSetUser( const QString &user ) = 0;
+ /**
+ * Start processing.
+ */
+ virtual void gplugStart() = 0;
+ /**
+ * Plugins that expect user input from a different device than the mouse or
+ * keyboard must call this when user activity is detected to prevent the
+ * greeter from resetting/going away. Events should be compressed to no
+ * more than ten per second; one every five seconds is actually enough.
+ * Events should be actual changes to the input fields, not random motion.
+ */
+ virtual void gplugActivity() = 0;
+ /**
+ * Show a message box on behalf of the talker.
+ * @param type message severity
+ * @param text message text
+ */
+ virtual void gplugMsgBox( QMessageBox::Icon type, const QString &text ) = 0;
+};
+
+/**
+ * Abstract base class for conversation plugins ("talkers") to be used with
+ * KDM, kdesktop_lock, etc.
+ * The authentication method used by a particular instance of a plugin
+ * may be configurable, but the instance must handle exactly one method,
+ * i.e., info->method must be determined at the latest at init() time.
+ */
+class KGreeterPlugin {
+public:
+ KGreeterPlugin( KGreeterPluginHandler *h ) : handler( h ) {}
+ virtual ~KGreeterPlugin() {}
+
+ /**
+ * Variations of the talker:
+ * - Authenticate: authentication
+ * - AuthChAuthTok: authentication and password change
+ * - ChAuthTok: password change
+ */
+ enum Function { Authenticate, AuthChAuthTok, ChAuthTok };
+
+ /**
+ * Contexts the talker can be used in:
+ * - Login: kdm login dialog
+ * - Shutdown: kdm shutdown dialog
+ * - Unlock: kdm unlock dialog (TODO)
+ * - ChangeTok: kdm password change dialog (TODO)
+ * - ExUnlock: kdesktop_lock unlock dialog
+ * - ExChangeTok: kdepasswd password change dialog (TODO)
+ *
+ * The Ex* contexts exist within a running session; the talker must know
+ * how to obtain the currently logged in user (+ domain/realm, etc.)
+ * itself (i.e., fixedEntity will be null). The non-Ex variants will have
+ * a fixedEntity passed in.
+ */
+ enum Context { Login, Shutdown, Unlock, ChangeTok,
+ ExUnlock, ExChangeTok };
+
+ /**
+ * Provide the talker with a list of selectable users. This can be used
+ * for autocompletion, etc.
+ * Will be called only when not running.
+ * @param users the users to load.
+ */
+ virtual void loadUsers( const QStringList &users ) = 0;
+
+ /**
+ * Preload the talker with an (opaque to the greeter) entity.
+ * Will be called only when not running.
+ * @param entity the entity to preload the talker with. That
+ * will usually be something like "user" or "user@domain".
+ * @param field the sub-widget (probably line edit) to put the cursor into.
+ * If -1, preselect the user for timed login. This means pre-filling
+ * the password field with anything, disabling it, and placing the
+ * cursor in the user name field.
+ */
+ virtual void presetEntity( const QString &entity, int field ) = 0;
+
+ /**
+ * Obtain the actually logged in entity.
+ * Will be called only after succeeded() was called.
+ */
+ virtual QString getEntity() const = 0;
+
+ /**
+ * "Push" a user into the talker. That can be a click into the user list
+ * or successful authentication without the talker calling gplugSetUser.
+ * Will be called only when running.
+ * @param user the user to set. Note that this is a UNIX login, not a
+ * canonical entity
+ */
+ virtual void setUser( const QString &user ) = 0;
+
+ /**
+ * En-/disable any widgets contained in the talker.
+ * Will be called only when not running.
+ * @param on the state to set
+ */
+ virtual void setEnabled( bool on ) = 0;
+
+ /**
+ * Called when a message from the authentication backend arrives.
+ * @param message the message received from the backend
+ * @param error if true, @p message is an error message, otherwise it's
+ * an informational message
+ * @return true means that the talker already handled the message, false
+ * that the greeter should display it in a message box
+ *
+ * FIXME: Filtering a message usually means that the backend issued a
+ * prompt and obtains the authentication data itself. However, in that
+ * state the backend is unresponsive, e.g., no shutdown is possible.
+ * The frontend could send the backend a signal, but the "escape path"
+ * within the backend is unclear (PAM won't like simply longjmp()ing
+ * out of it).
+ */
+ virtual bool textMessage( const char *message, bool error ) = 0;
+
+ /**
+ * Prompt the user for data. Reply by calling handler->gplugReturnText().
+ * @param propmt the prompt to display. It may be null, in which case
+ * "Username"/"Password" should be shown and the replies should be tagged
+ * with the respective Is* flag.
+ * @param echo if true, a normal input widget can be used, otherwise one that
+ * visually obscures the user's input.
+ * @param nonBlocking if true, report whatever is already available,
+ * otherwise wait for user input.
+ */
+ virtual void textPrompt( const char *prompt, bool echo, bool nonBlocking ) = 0;
+
+ /**
+ * Request binary authentication data from the talker. Reply by calling
+ * handler->gplugReturnBinary().
+ * @param prompt prompt in pam_client format
+ * @param nonBlocking if true, report whatever is already available,
+ * otherwise wait for user input.
+ * @return always true for now
+ *
+ * TODO:
+ * @return if true, the prompt was handled by the talker, otherwise the
+ * handler has to use libpam_client to obtain the authentication data.
+ * In that state the talker still can abort the data fetch by
+ * gplugReturn()ing a null array. When the data was obtained, another
+ * binaryPrompt with a null prompt will be issued.
+ */
+ virtual bool binaryPrompt( const char *prompt, bool nonBlocking ) = 0;
+
+ /**
+ * This can either
+ * - Start a processing cycle. Will be called only when not running.
+ * - Restart authTok cycle - will be called while running and implies
+ * revive(). PAM is a bit too clever, so we need this.
+ * In any case the talker is running afterwards.
+ */
+ virtual void start() = 0;
+
+ /**
+ * Request to suspend the auth. Make sure that a second talker of any
+ * type will be able to operate while this one is suspended (no busy
+ * device nodes, etc.).
+ * Will be called only if running within Login context. (Actually it
+ * won't be called at all, but be prepared.)
+ */
+ virtual void suspend() = 0;
+
+ /**
+ * Request to resume the auth from the point it was suspended at.
+ * Will be called only when suspended.
+ */
+ virtual void resume() = 0;
+
+ /**
+ * The "login" button was pressed in the greeter.
+ * This might call gplugReturn* or gplugStart.
+ * Will be called only when running.
+ */
+ virtual void next() = 0;
+
+ /**
+ * Abort auth cycle. Note that this should _not_ clear out already
+ * entered auth tokens if they are still on the screen.
+ * Will be called only when running and stops it.
+ */
+ virtual void abort() = 0;
+
+ /**
+ * Indicate successful end of the current phase.
+ * This is more or less a request to disable editable widgets
+ * responsible for the that phase.
+ * There will be no further attempt to enter that phase until the
+ * widget is destroyed.
+ * Will be called only when running and stops it.
+ */
+ virtual void succeeded() = 0;
+
+ /**
+ * Indicate unsuccessful end of the current phase.
+ * This is mostly a request to disable all editable widgets.
+ * The widget will be treated as dead until revive() is called.
+ * Will be called only when running and stops it.
+ */
+ virtual void failed() = 0;
+
+ /**
+ * Prepare retrying the previously failed phase.
+ * This is mostly a request to re-enable all editable widgets failed()
+ * disabled previously, clear the probably incorrect authentication tokens
+ * and to set the input focus appropriately.
+ * Will be called only after failed() (possibly with clear() in between),
+ * or after presetEntity() with field -1.
+ */
+ virtual void revive() = 0;
+
+ /**
+ * Clear any edit widgets, particularily anything set by setUser.
+ * Will be called only when not running.
+ */
+ virtual void clear() = 0;
+
+ /**
+ * Obtain the QLayoutItem containg the widget(s) to actually handle the
+ * conversation. See QLayout and QWidgetItem for possible implementations.
+ */
+ QLayoutItem *getLayoutItem() const { return layoutItem; }
+
+protected:
+ KGreeterPluginHandler *handler;
+ QLayoutItem *layoutItem;
+};
+
+struct KDE_EXPORT kgreeterplugin_info {
+ /**
+ * Human readable name of this plugin (should be a little more
+ * informative than just the libary name). Must be I18N_NOOP()ed.
+ */
+ const char *name;
+
+ /**
+ * The authentication method to use - the meaning is up to the backend,
+ * but will usually be related to the PAM service.
+ */
+ const char *method;
+
+ /**
+ * Capabilities.
+ */
+ enum {
+ /**
+ * All users exist on the local system permanently (will be listed
+ * by getpwent()); an entity corresponds to a UNIX user.
+ */
+ Local = 1,
+ /**
+ * The entities consist of multiple fields.
+ * PluginOptions/<plugin>.FocusField is used instead of FocusPasswd.
+ */
+ Fielded = 2,
+ /**
+ * An entity can be preset, the talker has a widget where a user can
+ * be selected explicitly. If the method is "classic", timed login
+ * is possible, too.
+ * This also means that setUser/gplugSetUser can be used and a
+ * userlist can be shown at all - provided Local is set as well.
+ */
+ Presettable = 4
+ };
+
+ /*
+ * Capability flags.
+ */
+ int flags;
+
+ /**
+ * Call after loading the plugin.
+ *
+ * @param method if non-empty and the plugin is unable to handle that
+ * method, return false. If the plugin has a constant method defined
+ * above, it can ignore this parameter.
+ * @param getConf can be used to obtain configuration items from the
+ * greeter; you have to pass it the @p ctx pointer.
+ * The only predefined key (in KDM) is "EchoMode", which is an int
+ * (in fact, KPasswordEdit::EchoModes).
+ * Other keys are obtained from the PluginOptions option; see kdmrc
+ * for details.
+ * If the key is unknown, dflt is returned.
+ * @param ctx context pointer for @p getConf
+ * @return if false, unload the plugin again (don't call done() first)
+ */
+ bool (*init)( const QString &method,
+ QVariant (*getConf)( void *ctx, const char *key,
+ const QVariant &dflt ),
+ void *ctx );
+
+ /**
+ * Call before unloading the plugin.
+ * This pointer can be null.
+ */
+ void (*done)( void );
+
+ /**
+ * Factory method to create an instance of the plugin.
+ * Note that multiple instances can exist at one time, but only
+ * one of them is active at any moment (the others would be suspended
+ * or not running at all).
+ * @param handler the object offering the necessary callbacks
+ * @param parent parent widget
+ * @param predecessor the focus widget before the conversation widget
+ * @param fixedEntity see below
+ * @param func see below
+ * @param ctx see below
+ * @return an instance of this conversation plugin
+ *
+ * Valid combinations of Function and Context:
+ * - Authenticate:Login - init
+ * - Authenticate:Shutdown - init, for now "root" is passed as fixedEntitiy
+ * and it is not supposed to be displayed. Plugins with Local not set
+ * might have to conjure something up to make getEntity() return a
+ * canonical entitiy. FIXME: don't restrict shutdown to root.
+ * - AuthChAuthTok:Login, AuthChAuthTok:Shutdown - cont/cont,
+ * only relevant for classic method (as it is relevant only for password-
+ * less logins, which always use classic). The login should not be shown -
+ * it is known to the user already; the backend won't ask for it, either.
+ * - ChAuthTok:Login & ChAuthTok:Shutdown - cont
+ * - Authenticate:Unlock & Authenticate:ExUnlock - init,
+ * AuthChAuthTok:ChangeTok & AuthChAuthTok:ExChangeTok - init/cont,
+ * display fixedEntity as labels. The backend does not ask for the UNIX
+ * login, as it already knows it - but it will ask for all components of
+ * the entity if it is no UNIX login.
+ *
+ * "init" means that the plugin is supposed to call gplugStart, "cont"
+ * that the backend is already in a cycle of the method the plugin was
+ * initialized with.
+ */
+ KGreeterPlugin *(*create)( KGreeterPluginHandler *handler,
+ KdmThemer *themer,
+ QWidget *parent, QWidget *predecessor,
+ const QString &fixedEntity,
+ KGreeterPlugin::Function func,
+ KGreeterPlugin::Context ctx );
+};
+
+#endif