summaryrefslogtreecommitdiffstats
path: root/tdm/kfrontend/kgreeter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tdm/kfrontend/kgreeter.cpp')
-rw-r--r--tdm/kfrontend/kgreeter.cpp1280
1 files changed, 1280 insertions, 0 deletions
diff --git a/tdm/kfrontend/kgreeter.cpp b/tdm/kfrontend/kgreeter.cpp
new file mode 100644
index 000000000..ee1bf3e72
--- /dev/null
+++ b/tdm/kfrontend/kgreeter.cpp
@@ -0,0 +1,1280 @@
+/*
+
+Greeter widget for tdm
+
+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 "kgreeter.h"
+#include "kconsole.h"
+#include "tdmconfig.h"
+#include "tdmclock.h"
+#include "tdm_greet.h"
+#include "tdmadmindialog.h"
+#include "themer/tdmthemer.h"
+#include "themer/tdmitem.h"
+#include "themer/tdmlabel.h"
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kseparator.h>
+#include <klistview.h>
+#include <ksimpleconfig.h>
+#include <kstringhandler.h>
+#include <kdebug.h>
+
+#undef Unsorted // x headers suck - make tqdir.h work with --enable-final
+#include <tqdir.h>
+#include <tqfile.h>
+#include <tqbuffer.h>
+#include <tqmemarray.h>
+#include <tqimage.h>
+#include <tqmovie.h>
+#include <tqpainter.h>
+#include <tqpopupmenu.h>
+#include <tqtimer.h>
+#include <tqheader.h>
+#include <tqstyle.h>
+#include <tqlayout.h>
+#include <tqlabel.h>
+#include <tqpushbutton.h>
+#include <tqtooltip.h>
+#include <tqaccel.h>
+#include <tqstring.h>
+#include <tqeventloop.h>
+#include <tqbitmap.h>
+
+#include <pwd.h>
+#include <grp.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <utmp.h>
+#include <utmpx.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <termios.h>
+#include <signal.h>
+
+#include <X11/Xlib.h>
+
+#define FIFO_DIR "/tmp/ksocket-global/tdm"
+#define FIFO_FILE "/tmp/ksocket-global/tdm/tdmctl-%1"
+#define FIFO_SAK_FILE "/tmp/ksocket-global/tdm/tdmctl-sak-%1"
+
+class UserListView : public KListView {
+ public:
+ UserListView( bool _them, TQWidget *parent = 0, const char *name = 0 )
+ : KListView( parent, name )
+ , themed(_them), cachedSizeHint( -1, 0 )
+ {
+ setSizePolicy( TQSizePolicy::Preferred, TQSizePolicy::Ignored );
+ header()->hide();
+ addColumn( TQString::null );
+ setColumnAlignment( 0, AlignVCenter );
+ setResizeMode( TQListView::LastColumn );
+ // FIXME: This must be configurable, so disable
+ // painting of list background for now.
+// if (themed) {
+// setBackgroundMode( Qt::NoBackground );
+// viewport()->setBackgroundMode( Qt::NoBackground );
+// setFrameStyle( TQFrame::NoFrame );
+// }
+ }
+
+ bool themed;
+ mutable TQSize cachedSizeHint;
+
+ int sumHeight() const
+ {
+ int sum = 0;
+ for (TQListViewItem *itm = firstChild(); itm; itm = itm->nextSibling()) {
+ sum += itm->height();
+ }
+ return sum;
+ }
+public:
+ virtual TQSize sizeHint() const
+ {
+ if (themed)
+ return KListView::sizeHint();
+
+ if (!cachedSizeHint.isValid()) {
+ constPolish();
+ uint maxw = 0;
+ for (TQListViewItem *itm = firstChild(); itm; itm = itm->nextSibling()) {
+ uint thisw = itm->width( fontMetrics(), this, 0 );
+ if (thisw > maxw)
+ maxw = thisw;
+ }
+ cachedSizeHint.setWidth(
+ style().pixelMetric( TQStyle::PM_ScrollBarExtent ) +
+ frameWidth() * 2 + maxw );
+ }
+ return cachedSizeHint;
+ }
+ virtual void paintEmptyArea ( TQPainter * p, const TQRect & rect )
+ {
+ if (!themed)
+ return KListView::paintEmptyArea(p, rect );
+
+ // FIXME: This must be configurable, so disable
+ // painting of list background for now.
+ return KListView::paintEmptyArea(p, rect );
+
+ const TQPixmap *pm = TQT_TQPIXMAP_CONST(paletteBackgroundPixmap());
+ if (!pm || pm->isNull())
+ return;
+
+ kdDebug() << "paintEmpty " << rect << endl;
+ TQRect devRect = p->xForm( rect );
+ kdDebug() << "paintEmpty2 " << devRect << endl;
+ p->drawPixmap(0, 0, *pm, devRect.left(), devRect.top() );
+ }
+
+ TQPixmap background;
+};
+
+int KGreeter::curPlugin = -1;
+PluginList KGreeter::pluginList;
+
+KGreeter::KGreeter( bool framed )
+ : inherited( framed )
+ , dName( dname )
+ , userView( 0 )
+ , userList( 0 )
+ , nNormals( 0 )
+ , nSpecials( 0 )
+ , curPrev( -1 )
+ , curSel( -1 )
+ , prevValid( true )
+ , needLoad( false )
+ , themed( framed )
+ , mPipe_fd( -1 )
+ , closingDown( false )
+{
+ stsFile = new KSimpleConfig( _stsFile );
+ stsFile->setGroup( "PrevUser" );
+
+ if (_userList) {
+ readFacesList();
+ userView = new UserListView( framed, this );
+ connect( userView, TQT_SIGNAL(clicked( TQListViewItem * )),
+ TQT_SLOT(slotUserClicked( TQListViewItem * )) );
+ connect( userView, TQT_SIGNAL(doubleClicked( TQListViewItem * )),
+ TQT_SLOT(accept()) );
+ }
+ if (_userCompletion)
+ userList = new TQStringList;
+
+ sessMenu = new TQPopupMenu( this );
+ connect( sessMenu, TQT_SIGNAL(activated( int )),
+ TQT_SLOT(slotSessionSelected( int )) );
+ insertSessions();
+
+ if (curPlugin < 0) {
+ curPlugin = 0;
+ pluginList = KGVerify::init( _pluginsLogin );
+ }
+
+ TQTimer::singleShot( 0, this, TQT_SLOT(handleInputPipe()) );
+}
+
+KGreeter::~KGreeter()
+{
+ if (mPipe_fd != -1) {
+ closingDown = true;
+ ::close(mPipe_fd);
+ ::unlink(mPipeFilename.ascii());
+ }
+ hide();
+ delete userList;
+ delete verify;
+ delete stsFile;
+}
+
+void KGreeter::done(int r) {
+ closingDown = true;
+ inherited::done(r);
+}
+
+void KGreeter::handleInputPipe(void) {
+ if (closingDown) {
+ ::unlink(mPipeFilename.ascii());
+ return;
+ }
+
+ if (isShown() == false) {
+ TQTimer::singleShot( 100, this, TQT_SLOT(handleInputPipe()) );
+ return;
+ }
+
+ char readbuf[2048];
+ int displayNumber;
+ TQString currentDisplay;
+ currentDisplay = TQString(getenv("DISPLAY"));
+ currentDisplay = currentDisplay.replace(":", "");
+ displayNumber = currentDisplay.toInt();
+ mPipeFilename = TQString(FIFO_FILE).arg(displayNumber);
+ ::unlink((TQString(FIFO_SAK_FILE).arg(displayNumber)).ascii());
+
+ /* Create the FIFOs if they do not exist */
+ umask(0);
+ struct stat buffer;
+ int status;
+ status = stat(FIFO_DIR, &buffer);
+ if (status == 0) {
+ int file_mode = ((buffer.st_mode & S_IRWXU) >> 6) * 100;
+ file_mode = file_mode + ((buffer.st_mode & S_IRWXG) >> 3) * 10;
+ file_mode = file_mode + ((buffer.st_mode & S_IRWXO) >> 0) * 1;
+ if ((file_mode != 600) || (buffer.st_uid != 0) || (buffer.st_gid != 0)) {
+ ::unlink(mPipeFilename.ascii());
+ printf("[WARNING] Possible security breach! Please check permissions on " FIFO_DIR " (must be 600 and owned by root/root, got %d %d/%d). Not listening for login credentials on remote control socket.\n", file_mode, buffer.st_uid, buffer.st_gid); fflush(stdout);
+ return;
+ }
+ }
+ mkdir(FIFO_DIR,0600);
+ mknod(mPipeFilename.ascii(), S_IFIFO|0600, 0);
+ chmod(mPipeFilename.ascii(), 0600);
+
+ mPipe_fd = ::open(mPipeFilename.ascii(), O_RDONLY | O_NONBLOCK);
+ int numread;
+ TQString inputcommand = "";
+ while ((!inputcommand.contains('\n')) && (!closingDown)) {
+ numread = ::read(mPipe_fd, readbuf, 2048);
+ readbuf[numread] = 0;
+ readbuf[2047] = 0;
+ inputcommand += readbuf;
+ if (!tqApp->hasPendingEvents()) {
+ usleep(500);
+ }
+ tqApp->processEvents();
+ }
+ if (closingDown) {
+ ::unlink(mPipeFilename.ascii());
+ return;
+ }
+ inputcommand = inputcommand.replace('\n', "");
+ TQStringList commandList = TQStringList::split('\t', inputcommand, false);
+ if ((*(commandList.at(0))) == "LOGIN") {
+ if (verify) {
+ verify->setUser( (*(commandList.at(1))) );
+ verify->setPassword( (*(commandList.at(2))) );
+ accept();
+ }
+ }
+ if (!closingDown) {
+ TQTimer::singleShot( 0, this, TQT_SLOT(handleInputPipe()) );
+ ::close(mPipe_fd);
+ ::unlink(mPipeFilename.ascii());
+ }
+ else {
+ ::unlink(mPipeFilename.ascii());
+ }
+}
+
+void KGreeter::readFacesList()
+{
+ FILE *f = fopen( TQFile::encodeName( _faceDir + "/.randomlist" ), "rt" );
+ if ( !f )
+ return;
+ TQTextIStream is( f );
+ while ( !is.eof() )
+ {
+ TQString line = is.readLine().simplifyWhiteSpace();
+ if ( line.isEmpty() )
+ continue;
+ TQString icon;
+ int index = line.find( ' ' );
+ if ( index > 0 ) {
+ icon = line.left( index );
+ line = line.mid( index );
+ } else {
+ icon = line;
+ line = TQString::null;
+ }
+ randomFaces.push_back( icon );
+ TQStringList list = TQStringList::split( ' ', line );
+ for ( TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it )
+ randomFacesMap[*it] = icon;
+ }
+}
+
+class UserListViewItem : public KListViewItem {
+ public:
+ UserListViewItem( UserListView *parent, const TQString &text,
+ const TQPixmap &pixmap, const TQString &username )
+ : KListViewItem( parent )
+ , login( username )
+ {
+ setPixmap( 0, pixmap );
+ setMultiLinesEnabled( true );
+ setText( 0, text );
+ parent->cachedSizeHint.setWidth( -1 );
+ }
+
+ virtual void paintCell(TQPainter *p, const TQColorGroup &cg, int column, int width, int alignment)
+ {
+ if (((UserListView*)listView())->themed)
+ TQListViewItem::paintCell(p, cg, column, width, alignment);
+ else
+ KListViewItem::paintCell(p, cg, column, width, alignment);
+ }
+
+ TQString login;
+};
+
+#define FILE_LIMIT_ICON 20
+#define FILE_LIMIT_IMAGE 200
+
+void
+KGreeter::insertUser( const TQImage &default_pix,
+ const TQString &username, struct passwd *ps )
+{
+ if (setegid( ps->pw_gid ))
+ return;
+ if (seteuid( ps->pw_uid )) {
+ setegid(0);
+ return;
+ }
+
+ if (userList)
+ userList->append( username );
+ if (!userView)
+ return;
+
+ int dp = 0, nd = 0;
+ if (_faceSource == FACE_USER_ONLY ||
+ _faceSource == FACE_PREFER_USER)
+ dp = 1;
+ if (_faceSource != FACE_USER_ONLY &&
+ _faceSource != FACE_ADMIN_ONLY)
+ nd = 1;
+ TQImage p;
+ do {
+ dp ^= 1;
+ TQCString fn = !dp ?
+ TQCString( ps->pw_dir ) + '/' :
+ TQCString(TQFile::encodeName( _faceDir + '/' + username ));
+ fn += ".face.icon";
+ int fd, ico;
+ if ((fd = open( fn.data(), O_RDONLY | O_NONBLOCK )) < 0) {
+ fn.truncate( fn.length() - 5 );
+ if ((fd = open( fn.data(), O_RDONLY | O_NONBLOCK )) < 0)
+ continue;
+ ico = 0;
+ } else
+ ico = 1;
+ TQFile f;
+ f.open( IO_ReadOnly, fd );
+ int fs = f.size();
+ if (fs > (ico ? FILE_LIMIT_ICON : FILE_LIMIT_IMAGE) * 1000) {
+ LogWarn( "%s exceeds file size limit (%dkB)\n",
+ fn.data(), ico ? FILE_LIMIT_ICON : FILE_LIMIT_IMAGE );
+ continue;
+ }
+ TQByteArray fc( fs );
+ int rfs = f.readBlock( fc.data(), fs );
+ ::close( fd );
+ fc.resize( rfs > 0 ? rfs : 0 );
+ TQBuffer buf( fc );
+ buf.open( IO_ReadOnly );
+ TQImageIO ir;
+ ir.setIODevice( TQT_TQIODEVICE(&buf) );
+ if (!ir.read()) {
+ LogInfo( "%s is no valid image\n", fn.data() );
+ continue;
+ }
+ p = ir.image();
+ TQSize ns( 48, 48 );
+ if (p.size() != ns)
+ p = p.convertDepth( 32 ).smoothScale( ns, TQ_ScaleMin );
+ break;
+ } while (--nd >= 0);
+
+ if ( p.isNull() && randomFaces.count() ) {
+ TQString randomFace = randomFacesMap[username];
+ if ( randomFace.isNull() ) {
+ TQStringList::size_type index = 0;
+ for ( size_t i = 0; i < username.length(); ++i )
+ index += ( 0x7f - username.at( i ).latin1() ) % 37;
+ randomFace = randomFaces[ index % randomFaces.count() ];
+ }
+ p.load( _faceDir + "/../pics/users/" + randomFace + ".png" );
+ }
+
+ if ( p.isNull() )
+ p = default_pix;
+
+ TQString realname = KStringHandler::from8Bit( ps->pw_gecos );
+ realname.truncate( realname.find( ',' ) );
+ if (realname.isEmpty() || realname == username)
+ new UserListViewItem( userView, username, TQPixmap( p ), username );
+ else {
+ realname.append( "\n" ).append( username );
+ new UserListViewItem( userView, realname, TQPixmap( p ), username );
+ }
+
+ seteuid( 0 );
+ setegid( 0 );
+}
+
+class KCStringList : public TQValueList<TQCString> {
+ public:
+ bool contains( const char *str ) const
+ {
+ for (ConstIterator it = begin(); it != end(); ++it)
+ if (*it == str)
+ return true;
+ return false;
+ }
+};
+
+class UserList {
+ public:
+ UserList( char **in );
+ bool hasUser( const char *str ) const { return users.contains( str ); }
+ bool hasGroup( gid_t gid ) const
+ { return groups.find( gid ) != groups.end(); }
+ bool hasGroups() const { return !groups.isEmpty(); }
+ KCStringList users;
+
+ private:
+ TQValueList<gid_t> groups;
+};
+
+UserList::UserList( char **in )
+{
+ struct group *grp;
+
+ for (; *in; in++)
+ if (**in == '@') {
+ if ((grp = getgrnam( *in + 1 ))) {
+ for (; *grp->gr_mem; grp->gr_mem++)
+ users.append( *grp->gr_mem );
+ groups.append( grp->gr_gid );
+ }
+ } else
+ users.append( *in );
+}
+
+void
+KGreeter::insertUsers(int limit_users)
+{
+ struct passwd *ps;
+
+ if (!(ps = getpwnam( "nobody" )))
+ return;
+
+ TQImage default_pix;
+ if (userView) {
+ if (!default_pix.load( _faceDir + "/.default.face.icon" ))
+ if (!default_pix.load( _faceDir + "/.default.face" ))
+ LogError( "Can't open default user face\n" );
+ TQSize ns( 48, 48 );
+ if (default_pix.size() != ns)
+ default_pix =
+ default_pix.convertDepth( 32 ).smoothScale( ns, TQ_ScaleMin );
+ }
+ if (_showUsers == SHOW_ALL) {
+ UserList noUsers( _noUsers );
+ TQDict<int> dupes( 1000 ); // Potential crash risk with buffer overrun?
+ TQStringList toinsert;
+ int count = 0;
+ for (setpwent(); (ps = getpwent()) != 0;) {
+ if (*ps->pw_dir && *ps->pw_shell &&
+ ((ps->pw_uid >= (unsigned)_lowUserId) ||
+ ((!ps->pw_uid) && _showRoot)) &&
+ (ps->pw_uid <= (unsigned)_highUserId) &&
+ (!noUsers.hasUser( ps->pw_name )) &&
+ (!noUsers.hasGroup( ps->pw_gid )))
+ {
+ TQString username( TQFile::decodeName( ps->pw_name ) );
+ if (!dupes.find( username )) {
+ dupes.insert( username, (int *)-1 );
+ toinsert.append( username );
+
+ if ( limit_users >= 0 && ++count > limit_users )
+ break;
+ }
+ }
+ }
+ // FIXME: OpenSUSE added this code
+ // For some reason it does not allow LDAP users to be listed (!),
+ // therefore it was deactivated. It should be repaired and reactivated.
+// if ( limit_users >= 0 && ++count > limit_users ) {
+// utmpname( _PATH_WTMP );
+// setutxent();
+// toinsert = TQStringList();
+// dupes.clear();
+//
+// for ( count = 0; count < limit_users; ) {
+// struct utmpx * ent = getutxent();
+// if ( !ent )
+// break;
+// struct passwd *ps = getpwnam( ent->ut_user );
+// if (ps && *ps->pw_dir && *ps->pw_shell &&
+// (ps->pw_uid >= (unsigned)_lowUserId ||
+// !ps->pw_uid && _showRoot) &&
+// ps->pw_uid <= (unsigned)_highUserId &&
+// !noUsers.hasUser( ps->pw_name ) &&
+// !noUsers.hasGroup( ps->pw_gid ))
+// {
+// TQString username( TQFile::decodeName( ent->ut_user ) );
+// if (!dupes.find( username )) {
+// dupes.insert( username, (int *)-1 );
+// toinsert.append( username );
+// count++;
+// }
+// }
+//
+//
+// }
+// endutxent();
+// }
+
+ for ( TQStringList::ConstIterator it = toinsert.begin();
+ it != toinsert.end(); ++it )
+ {
+ // pretty stupid to do another lookup round, but the number is limited
+ // and caching struct passwd is pretty ugly
+ struct passwd *ps = getpwnam( TQFile::encodeName( *it ) );
+ if ( ps )
+ insertUser( default_pix, *it, ps );
+ }
+ } else {
+ UserList users( _users );
+ if (users.hasGroups()) {
+ TQDict<int> dupes( 1000 );
+ for (setpwent(); (ps = getpwent()) != 0;) {
+ if (*ps->pw_dir && *ps->pw_shell &&
+ (ps->pw_uid >= (unsigned)_lowUserId ||
+ ((!ps->pw_uid) && _showRoot)) &&
+ ps->pw_uid <= (unsigned)_highUserId &&
+ (users.hasUser( ps->pw_name ) ||
+ users.hasGroup( ps->pw_gid )))
+ {
+ TQString username( TQFile::decodeName( ps->pw_name ) );
+ if (!dupes.find( username )) {
+ dupes.insert( username, (int *)-1 );
+ insertUser( default_pix, username, ps );
+ }
+ }
+ }
+ } else {
+ KCStringList::ConstIterator it = users.users.begin();
+ for (; it != users.users.end(); ++it)
+ if ((ps = getpwnam( (*it).data() )) &&
+ (ps->pw_uid || _showRoot))
+ insertUser( default_pix, TQFile::decodeName( *it ), ps );
+ }
+ }
+ endpwent();
+ if (_sortUsers) {
+ if (userView)
+ userView->sort();
+ if (userList)
+ userList->sort();
+ }
+}
+
+void
+KGreeter::putSession( const TQString &type, const TQString &name, bool hid, const char *exe )
+{
+ int prio = exe ? (!strcmp( exe, "default" ) ? 0 :
+ !strcmp( exe, "failsafe" ) ? 3 : 2) : 2;
+ for (uint i = 0; i < sessionTypes.size(); i++)
+ if (sessionTypes[i].type == type) {
+ sessionTypes[i].prio = prio;
+ return;
+ }
+ sessionTypes.append( SessType( name, type, hid, prio ) );
+}
+
+void
+KGreeter::insertSessions()
+{
+ for (char **dit = _sessionsDirs; *dit; ++dit) {
+ TQStringList ents = TQDir( *dit ).entryList();
+ for (TQStringList::ConstIterator it = ents.begin(); it != ents.end(); ++it)
+ if ((*it).endsWith( ".desktop" ) && !(*it).endsWith("admin.desktop")) {
+ KSimpleConfig dsk( TQString( *dit ).append( '/' ).append( *it ) );
+ dsk.setGroup( "Desktop Entry" );
+ putSession( (*it).left( (*it).length() - 8 ),
+ dsk.readEntry( "Name" ),
+ (dsk.readBoolEntry( "Hidden", false ) ||
+ (dsk.hasKey( "TryExec" ) &&
+ KStandardDirs::findExe( dsk.readEntry( "TryExec" ) ).isEmpty())),
+ dsk.readEntry( "Exec" ).latin1() );
+ }
+ }
+ putSession( "default", i18n("Default"), false, "default" );
+ putSession( "failsafe", i18n("Failsafe"), false, "failsafe" );
+ qBubbleSort( sessionTypes );
+ for (uint i = 0; i < sessionTypes.size() && !sessionTypes[i].hid; i++) {
+ sessMenu->insertItem( sessionTypes[i].name, i );
+ switch (sessionTypes[i].prio) {
+ case 0: case 1: nSpecials++; break;
+ case 2: nNormals++; break;
+ }
+ }
+}
+
+void
+KGreeter::slotUserEntered()
+{
+ if (userView) {
+ TQListViewItem *item;
+ for (item = userView->firstChild(); item; item = item->nextSibling())
+ if (((UserListViewItem *)item)->login == curUser) {
+ userView->setSelected( item, true );
+ userView->ensureItemVisible( item );
+ goto oke;
+ }
+ userView->clearSelection();
+ }
+ oke:
+ if (isVisible())
+ slotLoadPrevWM();
+ else
+ TQTimer::singleShot( 0, this, TQT_SLOT(slotLoadPrevWM()) );
+}
+
+void
+KGreeter::slotUserClicked( TQListViewItem *item )
+{
+ if (item) {
+ curUser = ((UserListViewItem *)item)->login;
+ verify->setUser( curUser );
+ slotLoadPrevWM();
+ }
+}
+
+void
+KGreeter::slotSessionSelected( int id )
+{
+ if (id != curSel) {
+ sessMenu->setItemChecked( curSel, false );
+ sessMenu->setItemChecked( id, true );
+ curSel = id;
+ verify->gplugActivity();
+ }
+}
+
+void
+KGreeter::reject()
+{
+ verify->reject();
+}
+
+void
+KGreeter::accept()
+{
+ if (userView && userView->hasFocus())
+ slotUserClicked( userView->currentItem() );
+ else
+ verify->accept();
+}
+
+void // private
+KGreeter::setPrevWM( int wm )
+{
+ if (curPrev != wm) {
+ if (curPrev != -1)
+ sessMenu->changeItem( curPrev, sessionTypes[curPrev].name );
+ if (wm != -1)
+ sessMenu->changeItem( wm, sessionTypes[wm].name + i18n(" (previous)") );
+ curPrev = wm;
+ }
+}
+
+void
+KGreeter::slotLoadPrevWM()
+{
+ int len, i, b;
+ unsigned long crc, by;
+ TQCString name;
+ char *sess;
+
+ if (verify->coreLock) {
+ needLoad = true;
+ return;
+ }
+ needLoad = false;
+
+ prevValid = true;
+ name = curUser.local8Bit();
+ GSendInt( G_ReadDmrc );
+ GSendStr( name.data() );
+ GRecvInt(); // ignore status code ...
+ if ((len = name.length())) {
+ GSendInt( G_GetDmrc );
+ GSendStr( "Session" );
+ sess = GRecvStr();
+ if (!sess) { /* no such user */
+ if (!userView && !userList) { // don't fake if user list shown
+ prevValid = false;
+ /* simple crc32 */
+ for (crc = _forgingSeed, i = 0; i < len; i++) {
+ by = (crc & 255) ^ name[i];
+ for (b = 0; b < 8; b++)
+ by = (by >> 1) ^ (-(by & 1) & 0xedb88320);
+ crc = (crc >> 8) ^ by;
+ }
+ /* forge a session with this hash - default & custom more probable */
+ /* XXX - this should do a statistical analysis of the real users */
+#if 1
+ setPrevWM( crc % (nSpecials * 2 + nNormals) % (nSpecials + nNormals) );
+#else
+ i = crc % (nSpecials * 2 + nNormals);
+ if (i < nNormals)
+ setPrevWM( i + nSpecials );
+ else
+ setPrevWM( (i - nNormals) / 2 );
+#endif
+ return;
+ }
+ } else {
+ if (!strcmp(sess, "admin")) {
+ // need to get the original
+ GSendInt( G_GetDmrc);
+ GSendStr( "OrigSession");
+ sess = GRecvStr();
+ if (!sess) {
+ free(sess);
+ sess = strdup("default");
+ }
+ }
+
+ for (uint i = 0; i < sessionTypes.count() && !sessionTypes[i].hid; i++)
+ if (sessionTypes[i].type == sess) {
+ free( sess );
+ setPrevWM( i );
+ return;
+ }
+ if (curSel == -1)
+ MsgBox( sorrybox, i18n("Your saved session type '%1' is not valid any more.\n"
+ "Please select a new one, otherwise 'default' will be used.").arg( sess ) );
+ free( sess );
+ prevValid = false;
+ }
+ }
+ setPrevWM( -1 );
+}
+
+void // protected
+KGreeter::pluginSetup()
+{
+ int field = 0;
+ TQString ent, pn( verify->pluginName() ), dn( dName + '_' + pn );
+
+ if (_preselUser != PRESEL_PREV)
+ stsFile->deleteEntry( verify->entitiesLocal() ? dName : dn, false );
+ if (_preselUser != PRESEL_NONE && verify->entityPresettable()) {
+ if (verify->entitiesLocal())
+ ent = _preselUser == PRESEL_PREV ?
+ stsFile->readEntry( dName ) : _defaultUser;
+ else
+ ent = _preselUser == PRESEL_PREV ?
+ stsFile->readEntry( dn ) :
+ verify->getConf( 0, (pn + ".DefaultEntity").latin1(), TQVariant() ).toString();
+ field = verify->entitiesFielded() ?
+ verify->getConf( 0, (pn + ".FocusField").latin1(), TQVariant( 0 ) ).toInt() :
+ _focusPasswd;
+ }
+ verify->presetEntity( ent, field );
+ if (userList)
+ verify->loadUsers( *userList );
+}
+
+void
+KGreeter::verifyPluginChanged( int id )
+{
+ curPlugin = id;
+ pluginSetup();
+}
+
+void
+KGreeter::verifyClear()
+{
+ curUser = TQString::null;
+ slotUserEntered();
+ slotSessionSelected( -1 );
+}
+
+void
+KGreeter::verifyOk()
+{
+ if (_preselUser == PRESEL_PREV && verify->entityPresettable())
+ stsFile->writeEntry( verify->entitiesLocal() ?
+ dName :
+ dName + '_' + verify->pluginName(),
+ verify->getEntity() );
+ if (curSel != -1) {
+ GSendInt( G_PutDmrc );
+ GSendStr( "Session" );
+ GSendStr( sessionTypes[curSel].type.utf8() );
+ } else if (!prevValid) {
+ GSendInt( G_PutDmrc );
+ GSendStr( "Session" );
+ GSendStr( "default" );
+ }
+ GSendInt( G_Ready );
+ closingDown = true;
+ done( ex_exit );
+}
+
+void
+KGreeter::verifyFailed()
+{
+ if (needLoad)
+ slotLoadPrevWM();
+}
+
+void
+KGreeter::verifySetUser( const TQString &user )
+{
+ curUser = user;
+ slotUserEntered();
+}
+
+KStdGreeter::KStdGreeter()
+ : KGreeter()
+ , clock( 0 )
+ , pixLabel( 0 )
+{
+ TQBoxLayout *main_box;
+#ifdef WITH_TDM_XCONSOLE
+ if (consoleView) {
+ TQBoxLayout *ex_box = new TQVBoxLayout( this, 10, 10 );
+ main_box = new TQHBoxLayout( ex_box, 10 );
+ ex_box->addWidget( consoleView );
+ } else
+#endif
+ main_box = new TQHBoxLayout( this, 10, 10 );
+
+ if (userView)
+ main_box->addWidget( userView );
+
+ TQBoxLayout *inner_box = new TQVBoxLayout( main_box, 10 );
+
+ if (!_authorized && _authComplain) {
+ TQLabel *complainLabel = new TQLabel(
+ i18n("Warning: this is an unsecured session"), this );
+ TQToolTip::add( complainLabel,
+ i18n("This display requires no X authorization.\n"
+ "This means that anybody can connect to it,\n"
+ "open windows on it or intercept your input.") );
+ complainLabel->setAlignment( AlignCenter );
+ complainLabel->setFont( _failFont );
+ complainLabel->setPaletteForegroundColor( Qt::red );
+ inner_box->addWidget( complainLabel );
+ }
+ if (!_greetString.isEmpty()) {
+ TQLabel *welcomeLabel = new TQLabel( _greetString, this );
+ welcomeLabel->setAlignment( AlignCenter );
+ welcomeLabel->setFont( _greetFont );
+ inner_box->addWidget( welcomeLabel );
+ }
+
+ switch (_logoArea) {
+ case LOGO_CLOCK:
+ clock = new KdmClock( this, "clock" );
+ break;
+ case LOGO_LOGO:
+ {
+ TQMovie movie( _logo );
+ kapp->eventLoop()->processEvents( TQEventLoop::ExcludeUserInput | TQEventLoop::ExcludeSocketNotifiers, 100 );
+ TQPixmap pixmap;
+ if (!movie.framePixmap().isNull() || pixmap.load( _logo )) {
+ pixLabel = new TQLabel( this );
+ if (!movie.framePixmap().isNull()) {
+ pixLabel->setMovie( movie );
+ if (!movie.framePixmap().hasAlpha())
+ pixLabel->setFrameStyle( TQFrame::Panel | TQFrame::Sunken );
+ } else {
+ pixLabel->setPixmap( pixmap );
+ if (!pixmap.hasAlpha())
+ pixLabel->setFrameStyle( TQFrame::Panel | TQFrame::Sunken );
+ }
+ pixLabel->setIndent( 0 );
+ }
+ }
+ break;
+ }
+
+ if (userView) {
+ if (clock)
+ inner_box->addWidget( clock, 0, AlignCenter );
+ else if (pixLabel)
+ inner_box->addWidget( pixLabel, 0, AlignCenter );
+ } else {
+ if (clock)
+ main_box->addWidget( clock, 0, AlignCenter );
+ else if (pixLabel)
+ main_box->addWidget( pixLabel, 0, AlignCenter );
+ }
+
+ goButton = new TQPushButton( i18n("L&ogin"), this );
+ goButton->setDefault( true );
+ connect( goButton, TQT_SIGNAL(clicked()), TQT_SLOT(accept()) );
+ menuButton = new TQPushButton( i18n("&Menu"), this );
+ //helpButton
+
+ TQWidget *prec;
+ if (userView)
+ prec = userView;
+#ifdef WITH_TDM_XCONSOLE
+ else if (consoleView)
+ prec = consoleView;
+#endif
+ else
+ prec = menuButton;
+ KGStdVerify *sverify =
+ new KGStdVerify( this, this, prec, TQString::null,
+ pluginList, KGreeterPlugin::Authenticate,
+ KGreeterPlugin::Login );
+ inner_box->addLayout( sverify->getLayout() );
+ TQPopupMenu *plugMenu = sverify->getPlugMenu();
+ sverify->selectPlugin( curPlugin );
+ verify = sverify;
+
+ inner_box->addWidget( new KSeparator( KSeparator::HLine, this ) );
+
+ TQBoxLayout *hbox2 = new TQHBoxLayout( inner_box, 10 );
+ hbox2->addWidget( goButton );
+ hbox2->addStretch( 1 );
+ hbox2->addWidget( menuButton );
+ hbox2->addStretch( 1 );
+
+ if (sessMenu->count() > 1) {
+ inserten( i18n("Session &Type"), 0, sessMenu );
+ needSep = true;
+ }
+
+ if (plugMenu) {
+ inserten( i18n("&Authentication Method"), 0, plugMenu );
+ needSep = true;
+ }
+
+#ifdef XDMCP
+ completeMenu( LOGIN_LOCAL_ONLY, ex_choose, i18n("&Remote Login"), 0 );
+#else
+ completeMenu();
+#endif
+
+ if (userView || userList)
+ insertUsers();
+
+ if (optMenu)
+ menuButton->setPopup( optMenu );
+ else
+ menuButton->hide();
+
+ pluginSetup();
+
+ verify->start();
+}
+
+void
+KStdGreeter::pluginSetup()
+{
+ inherited::pluginSetup();
+ if (userView) {
+ if (verify->entitiesLocal() && verify->entityPresettable())
+ userView->show();
+ else
+ userView->hide();
+ }
+ adjustGeometry();
+ update();
+}
+
+void
+KStdGreeter::verifyFailed()
+{
+ goButton->setEnabled( false );
+ menuButton->setEnabled( false );
+ if (userView)
+ userView->setEnabled( false );
+ inherited::verifyFailed();
+}
+
+void
+KStdGreeter::verifyRetry()
+{
+ goButton->setEnabled( true );
+ menuButton->setEnabled( true );
+ if (userView)
+ userView->setEnabled( true );
+}
+
+
+KThemedGreeter::KThemedGreeter()
+ : KGreeter( true )
+ , themer( 0 )
+// , clock( 0 )
+{
+ // We do all painting ourselves
+ setBackgroundMode( NoBackground );
+ // Allow tracking the mouse position
+ setMouseTracking( true );
+
+ adjustGeometry();
+
+ themer = new KdmThemer( _theme, "console", this );
+ if (!themer->isOK()) {
+ delete themer;
+ themer = 0;
+ return;
+ }
+
+ connect( themer, TQT_SIGNAL(activated( const TQString & )),
+ TQT_SLOT(slotThemeActivated( const TQString & )) );
+
+ console_rect = themer->findNode( "xconsole" ); // tdm ext
+ userlist_rect = themer->findNode( "userlist" );
+ caps_warning = themer->findNode( "caps-lock-warning" );
+ xauth_warning = themer->findNode( "xauth-warning" ); // tdm ext
+ pam_error = themer->findNode( "pam-error" );
+ timed_label = themer->findNode( "timed-label" );
+ if (pam_error && pam_error->isA( "KdmLabel" ))
+ static_cast<KdmLabel*>(pam_error)->setText( i18n("Login Failed.") );
+
+ KdmItem *itm;
+ if ((itm = themer->findNode( "pam-message" ))) // done via msgboxes
+ itm->hide( true );
+ if ((itm = themer->findNode( "language_button" ))) // not implemented yet
+ itm->hide( true );
+
+#ifdef WITH_TDM_XCONSOLE
+ if (console_rect) {
+ if (consoleView)
+ console_rect->setWidget( consoleView );
+ else
+ console_rect->hide( true );
+ }
+#endif
+
+ if (xauth_warning && (_authorized || !_authComplain))
+ xauth_warning->hide( true );
+
+ if (userView || userList)
+ insertUsers( 7 ); // TODO: find out how many are a good value
+
+// if (!_greetString.isEmpty()) {
+// }
+// clock = new KdmClock( this, "clock" );
+
+ TQWidget *prec;
+ if (userView)
+ prec = userView;
+#ifdef WITH_TDM_XCONSOLE
+ else if (consoleView)
+ prec = consoleView;
+#endif
+ else
+ prec = 0;
+ KGThemedVerify *tverify =
+ new KGThemedVerify( this, themer, this, prec, TQString::null,
+ pluginList, KGreeterPlugin::Authenticate,
+ KGreeterPlugin::Login );
+ TQPopupMenu *plugMenu = tverify->getPlugMenu();
+ tverify->selectPlugin( curPlugin );
+ verify = tverify;
+
+ session_button = 0;
+ if ((itm = themer->findNode( "session_button" ))) {
+ if (sessMenu->count() <= 1)
+ itm->hide( true );
+ else
+ session_button = itm;
+ } else {
+ if (sessMenu->count() > 1) {
+ inserten( i18n("Session &Type"), ALT+Key_T, sessMenu );
+ needSep = true;
+ }
+ }
+
+ admin_button = themer->findNode( "admin_button");
+ if ( admin_button ) {
+ if ( !_useAdminSession )
+ admin_button->hide( true );
+ }
+
+ if (plugMenu) {
+ inserten( i18n("&Authentication Method"), ALT+Key_A, plugMenu );
+ needSep = true;
+ }
+
+#ifdef XDMCP
+ completeMenu( LOGIN_LOCAL_ONLY, ex_choose, i18n("&Remote Login"), ALT+Key_R );
+#else
+ completeMenu();
+#endif
+
+ system_button = themer->findNode( "system_button" );
+ TQAccel *accel = new TQAccel( this );
+ accel->insertItem( ALT+Key_M, 0 );
+ connect( accel, TQT_SIGNAL(activated( int )), TQT_SLOT(slotActionMenu()) );
+
+ pluginSetup();
+
+ verify->start();
+}
+
+bool
+KThemedGreeter::event( TQEvent *e )
+{
+ if (themer)
+ themer->widgetEvent( e );
+ return inherited::event( e );
+}
+
+void
+KThemedGreeter::pluginSetup()
+{
+ inherited::pluginSetup();
+
+ if (userView && verify->entitiesLocal() && verify->entityPresettable() && userlist_rect) {
+// userView->setMaximumHeight( userView->sumHeight() );
+ userlist_rect->setWidget( userView );
+ } else {
+ if (userView)
+ userView->hide();
+ if (userlist_rect)
+ userlist_rect->hide( true );
+ }
+
+ update();
+}
+
+void
+KThemedGreeter::verifyFailed()
+{
+// goButton->setEnabled( false );
+ inherited::verifyFailed();
+ if (userView)
+ userView->setEnabled(false);
+}
+
+void
+KThemedGreeter::verifyRetry()
+{
+// goButton->setEnabled( true );
+ if (userView)
+ userView->setEnabled(true);
+
+}
+
+TQString KThemedGreeter::timedUser = TQString::null;
+int KThemedGreeter::timedDelay = -1;
+
+void
+KThemedGreeter::updateStatus( bool fail, bool caps, int timedleft )
+{
+ if (pam_error) {
+ if (fail)
+ pam_error->show( true );
+ else
+ pam_error->hide( true );
+ }
+ if (caps_warning) {
+ if (caps)
+ caps_warning->show( true );
+ else
+ caps_warning->hide( true );
+ }
+ if (timed_label) {
+ if (timedleft) {
+ if (timedleft != timedDelay) {
+ timedDelay = timedleft;
+ timedUser = curUser;
+ timed_label->show( true );
+ timed_label->update();
+ }
+ } else {
+ timedDelay = -1;
+ timed_label->hide( true );
+ }
+ }
+}
+
+void
+KThemedGreeter::slotThemeActivated( const TQString &id )
+{
+ if (id == "login_button")
+ accept();
+ else if (id == "session_button")
+ slotSessMenu();
+ else if (id == "system_button")
+ slotActionMenu();
+ else if (id == "admin_button")
+ slotAskAdminPassword();
+}
+
+void
+KThemedGreeter::slotSessMenu()
+{
+ sessMenu->popup( mapToGlobal( session_button->rect().center() ) );
+}
+
+void
+KThemedGreeter::slotActionMenu()
+{
+ if (system_button)
+ optMenu->popup( mapToGlobal( system_button->rect().center() ) );
+ else
+ optMenu->popup( mapToGlobal( rect().center() ) );
+}
+
+void
+KThemedGreeter::keyPressEvent( TQKeyEvent *e )
+{
+ inherited::keyPressEvent( e );
+ if (!(e->state() & KeyButtonMask) &&
+ (e->key() == Key_Return || e->key() == Key_Enter))
+ accept();
+}
+
+void
+KThemedGreeter::slotAskAdminPassword()
+{
+ TDMAdmin k(curUser, this);
+ if (k.exec()) {
+ GSendInt(G_Ready);
+ hide();
+ closingDown = true;
+ done(ex_exit);
+ }
+}
+
+#include "kgreeter.moc"