You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1173 lines
30 KiB
1173 lines
30 KiB
/*
|
|
|
|
Greeter widget for kdm
|
|
|
|
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 "kdmconfig.h"
|
|
#include "kdmclock.h"
|
|
#include "kdm_greet.h"
|
|
#include "kdmadmindialog.h"
|
|
#include "themer/kdmthemer.h"
|
|
#include "themer/kdmitem.h"
|
|
#include "themer/kdmlabel.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 <X11/Xlib.h>
|
|
|
|
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 = 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 )
|
|
{
|
|
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 );
|
|
}
|
|
}
|
|
|
|
KGreeter::~KGreeter()
|
|
{
|
|
hide();
|
|
delete userList;
|
|
delete verify;
|
|
delete stsFile;
|
|
}
|
|
|
|
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 ) + '/' :
|
|
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( &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, TQImage::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, TQImage::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 );
|
|
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_KDM_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_KDM_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" ); // kdm ext
|
|
userlist_rect = themer->findNode( "userlist" );
|
|
caps_warning = themer->findNode( "caps-lock-warning" );
|
|
xauth_warning = themer->findNode( "xauth-warning" ); // kdm 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_KDM_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_KDM_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()
|
|
{
|
|
KDMAdmin k(curUser, this);
|
|
if (k.exec()) {
|
|
GSendInt(G_Ready);
|
|
hide();
|
|
done(ex_exit);
|
|
}
|
|
}
|
|
|
|
#include "kgreeter.moc"
|