2 Copyright (C) 2004 Oswald Buddenhagen <ossi@kde.org>
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the Lesser GNU General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 You should have received a copy of the Lesser GNU General Public License
15 along with this program; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
20 #include "kdisplaymanager.h"
24 #include <kapplication.h>
26 #include <QtDBus/QtDBus>
30 #include <X11/Xauth.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
42 static enum { Dunno
, NoDM
, NewKDM
, OldKDM
, GDM
} DMType
= Dunno
;
43 static const char *ctl
, *dpy
;
45 class KDisplayManager::Private
57 KDisplayManager::KDisplayManager() : d(new Private
)
60 struct sockaddr_un sa
;
62 if (DMType
== Dunno
) {
63 if (!(dpy
= ::getenv( "DISPLAY" )))
65 else if ((ctl
= ::getenv( "DM_CONTROL" )))
67 else if ((ctl
= ::getenv( "XDM_MANAGED" )) && ctl
[0] == '/')
69 else if (::getenv( "GDMSESSION" ))
79 if ((d
->fd
= ::socket( PF_UNIX
, SOCK_STREAM
, 0 )) < 0)
81 sa
.sun_family
= AF_UNIX
;
83 strcpy( sa
.sun_path
, "/var/run/gdm_socket" );
84 if (::connect( d
->fd
, (struct sockaddr
*)&sa
, sizeof(sa
) )) {
85 strcpy( sa
.sun_path
, "/tmp/.gdm_socket" );
86 if (::connect( d
->fd
, (struct sockaddr
*)&sa
, sizeof(sa
) )) {
94 if ((ptr
= strchr( dpy
, ':' )))
95 ptr
= strchr( ptr
, '.' );
96 snprintf( sa
.sun_path
, sizeof(sa
.sun_path
),
97 "%s/dmctl-%.*s/socket",
98 ctl
, ptr
? int(ptr
- dpy
) : 512, dpy
);
99 if (::connect( d
->fd
, (struct sockaddr
*)&sa
, sizeof(sa
) )) {
108 tf
.truncate( tf
.indexOf( ',' ) );
109 d
->fd
= ::open( tf
.toLatin1(), O_WRONLY
);
115 KDisplayManager::~KDisplayManager()
121 KDisplayManager::exec( const char *cmd
)
125 return exec( cmd
, buf
);
129 * Execute a KDM/GDM remote control command.
130 * @param cmd the command to execute. FIXME: undocumented yet.
131 * @param buf the result buffer.
133 * @li If true, the command was successfully executed.
134 * @p ret might contain addional results.
135 * @li If false and @p ret is empty, a communication error occurred
136 * (most probably KDM is not running).
137 * @li If false and @p ret is non-empty, it contains the error message
141 KDisplayManager::exec( const char *cmd
, QByteArray
&buf
)
151 if (::write( d
->fd
, cmd
, tl
) != tl
) {
159 if (DMType
== OldKDM
) {
164 if (buf
.size() < 128)
166 else if (buf
.size() < len
* 2)
167 buf
.resize( len
* 2 );
168 if ((tl
= ::read( d
->fd
, buf
.data() + len
, buf
.size() - len
)) <= 0) {
169 if (tl
< 0 && errno
== EINTR
)
174 if (buf
[len
- 1] == '\n') {
176 if (len
> 2 && (buf
[0] == 'o' || buf
[0] == 'O') &&
177 (buf
[1] == 'k' || buf
[1] == 'K') && buf
[2] <= ' ')
186 KDisplayManager::canShutdown()
188 if (DMType
== OldKDM
)
189 return strstr( ctl
, ",maysd" ) != 0;
194 return exec( "QUERY_LOGOUT_ACTION\n", re
) && re
.indexOf( "HALT" ) >= 0;
196 return exec( "caps\n", re
) && re
.indexOf( "\tshutdown" ) >= 0;
200 KDisplayManager::shutdown( KWorkSpace::ShutdownType shutdownType
,
201 KWorkSpace::ShutdownMode shutdownMode
, /* NOT Default */
202 const QString
&bootOption
)
204 if (shutdownType
== KWorkSpace::ShutdownTypeNone
|| shutdownType
== KWorkSpace::ShutdownTypeLogout
)
208 if (DMType
== NewKDM
) {
210 cap_ask
= exec( "caps\n", re
) && re
.indexOf( "\tshutdown ask" ) >= 0;
212 if (!bootOption
.isEmpty())
216 if (!cap_ask
&& shutdownMode
== KWorkSpace::ShutdownModeInteractive
)
217 shutdownMode
= KWorkSpace::ShutdownModeForceNow
;
221 cmd
.append( shutdownMode
== KWorkSpace::ShutdownModeForceNow
?
222 "SET_LOGOUT_ACTION " : "SET_SAFE_LOGOUT_ACTION " );
223 cmd
.append( shutdownType
== KWorkSpace::ShutdownTypeReboot
?
224 "REBOOT\n" : "HALT\n" );
226 cmd
.append( "shutdown\t" );
227 cmd
.append( shutdownType
== KWorkSpace::ShutdownTypeReboot
?
228 "reboot\t" : "halt\t" );
229 if (!bootOption
.isEmpty())
230 cmd
.append( "=" ).append( bootOption
.toLocal8Bit() ).append( "\t" );
231 cmd
.append( shutdownMode
== KWorkSpace::ShutdownModeInteractive
?
233 shutdownMode
== KWorkSpace::ShutdownModeForceNow
?
235 shutdownMode
== KWorkSpace::ShutdownModeTryNow
?
236 "trynow\n" : "schedule\n" );
242 KDisplayManager::bootOptions( QStringList
&opts
, int &defopt
, int ¤t
)
244 if (DMType
!= NewKDM
)
248 if (!exec( "listbootoptions\n", re
))
251 opts
= QString::fromLocal8Bit( re
.data() ).split( '\t', QString::SkipEmptyParts
);
256 defopt
= opts
[2].toInt( &ok
);
259 current
= opts
[3].toInt( &ok
);
263 opts
= opts
[1].split( ' ', QString::SkipEmptyParts
);
264 for (QStringList::Iterator it
= opts
.begin(); it
!= opts
.end(); ++it
)
265 (*it
).replace( "\\s", " " );
271 KDisplayManager::setLock( bool on
)
274 exec( on
? "lock\n" : "unlock\n" );
278 KDisplayManager::isSwitchable()
280 if (DMType
== OldKDM
)
281 return dpy
[0] == ':';
284 return exec( "QUERY_VT\n" );
288 return exec( "caps\n", re
) && re
.indexOf( "\tlocal" ) >= 0;
292 KDisplayManager::numReserve()
297 if (DMType
== OldKDM
)
298 return strstr( ctl
, ",rsvd" ) ? 1 : -1;
303 if (!(exec( "caps\n", re
) && (p
= re
.indexOf( "\treserve " )) >= 0))
305 return atoi( re
.data() + p
+ 9 );
309 KDisplayManager::startReserve()
312 exec("FLEXI_XSERVER\n");
318 KDisplayManager::localSessions( SessList
&list
)
320 if (DMType
== OldKDM
)
326 if (!exec( "CONSOLE_SERVERS\n", re
))
328 const QStringList sess
= QString(re
.data() +3).split( QChar(';'), QString::SkipEmptyParts
);
329 for (QStringList::ConstIterator it
= sess
.constBegin(); it
!= sess
.constEnd(); ++it
) {
330 QStringList ts
= (*it
).split( QChar(',') );
334 se
.vt
= ts
[2].toInt();
335 se
.session
= "<unknown>";
336 se
.self
= ts
[0] == ::getenv( "DISPLAY" ); /* Bleh */
341 if (!exec( "list\talllocal\n", re
))
343 const QStringList sess
= QString(re
.data() + 3).split(QChar('\t'), QString::SkipEmptyParts
);
344 for (QStringList::ConstIterator it
= sess
.constBegin(); it
!= sess
.constEnd(); ++it
) {
345 QStringList ts
= (*it
).split( QChar(',') );
349 se
.from
= ts
[1].mid( 1 ), se
.vt
= 0;
351 se
.vt
= ts
[1].mid( 2 ).toInt();
354 se
.self
= (ts
[4].indexOf( '*' ) >= 0);
355 se
.tty
= (ts
[4].indexOf( 't' ) >= 0);
363 KDisplayManager::sess2Str2( const SessEnt
&se
, QString
&user
, QString
&loc
)
366 user
= i18nc("user: ...", "%1: TTY login", se
.user
);
367 loc
= se
.vt
? QString("vt%1").arg( se
.vt
) : se
.display
;
371 se
.session
.isEmpty() ?
372 i18nc("... location (TTY or X display)", "Unused") :
373 se
.session
== "<remote>" ?
374 i18n("X login on remote host") :
375 i18nc("... host", "X login on %1", se
.session
) :
376 se
.session
== "<unknown>" ?
378 i18nc("user: session type", "%1: %2",
379 se
.user
, se
.session
);
382 QString("%1, vt%2").arg( se
.display
).arg( se
.vt
) :
388 KDisplayManager::sess2Str( const SessEnt
&se
)
392 sess2Str2( se
, user
, loc
);
393 return i18nc("session (location)", "%1 (%2)", user
, loc
);
397 KDisplayManager::switchVT( int vt
)
400 return exec( QString("SET_VT %1\n").arg(vt
).toLatin1() );
402 return exec( QString("activate\tvt%1\n").arg(vt
).toLatin1() );
406 KDisplayManager::lockSwitchVT( int vt
)
410 QDBusInterface
screensaver("org.freedesktop.ScreenSaver", "/ScreenSaver", "org.freedesktop.ScreenSaver");
411 screensaver
.call( "Lock" );
416 KDisplayManager::GDMAuthenticate()
419 const char *dpy
, *dnum
, *dne
;
423 dpy
= DisplayString( QX11Info::display() );
425 dpy
= ::getenv( "DISPLAY" );
429 dnum
= strchr( dpy
, ':' ) + 1;
430 dne
= strchr( dpy
, '.' );
431 dnl
= dne
? dne
- dnum
: strlen( dnum
);
433 /* XXX should do locking */
434 if (!(fp
= fopen( XauFileName(), "r" )))
437 while ((xau
= XauReadAuth( fp
))) {
438 if (xau
->family
== FamilyLocal
&&
439 xau
->number_length
== dnl
&& !memcmp( xau
->number
, dnum
, dnl
) &&
440 xau
->data_length
== 16 &&
441 xau
->name_length
== 18 && !memcmp( xau
->name
, "MIT-MAGIC-COOKIE-1", 18 ))
443 QString
cmd( "AUTH_LOCAL " );
444 for (int i
= 0; i
< 16; i
++)
445 cmd
+= QString::number( (uchar
)xau
->data
[i
], 16 ).rightJustified( 2, '0');
447 if (exec( cmd
.toLatin1() )) {
448 XauDisposeAuth( xau
);
452 XauDisposeAuth( xau
);