//#define USE_KWIN
# include "kdialogd.h"
# include <iostream>
# include <tdediroperator.h>
# include <kuniqueapplication.h>
# include <tqsocketnotifier.h>
# include <tdeio/netaccess.h>
# include <tdemessagebox.h>
# include <tdelocale.h>
# include <tdeconfig.h>
# include <kurlcombobox.h>
# ifdef USE_KWIN
# include <twin.h>
# else
# include <X11/Xlib.h>
# endif
# include <sys/un.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <sys/errno.h>
# include <ksockaddr.h>
# include <kdebug.h>
# include <tdeversion.h>
# include <tqtimer.h>
# ifdef KDIALOGD_APP
# include <tdecmdlineargs.h>
# include <tdeaboutdata.h>
# endif
# include <fstream>
TDEConfig * KDialogD : : theirConfig = NULL ;
# define CFG_KEY_DIALOG_SIZE "KDialogDSize"
# define CFG_TIMEOUT_GROUP "General"
# ifdef KDIALOGD_APP
# define CFG_TIMEOUT_KEY "Timeout"
# define DEFAULT_TIMEOUT 30
# endif
static TQString groupName ( const TQString & app , bool fileDialog = true )
{
return TQString ( fileDialog ? " KFileDialog " : " KDirSelectDialog " ) + app ;
}
// from tdebase/tdesu
static int createSocket ( )
{
int sockitsFd ;
ksocklen_t addrlen ;
struct stat s ;
const char * sock = getSockName ( ) ;
int stat_err = lstat ( sock , & s ) ;
if ( ! stat_err & & S_ISLNK ( s . st_mode ) )
{
kdWarning ( ) < < " Someone is running a symlink attack on you " < < endl ;
if ( unlink ( sock ) )
{
kdWarning ( ) < < " Could not delete symlink " < < endl ;
return - 1 ;
}
}
if ( ! access ( sock , R_OK | W_OK ) )
{
kdWarning ( ) < < " stale socket exists " < < endl ;
if ( unlink ( sock ) )
{
kdWarning ( ) < < " Could not delete stale socket " < < endl ;
return - 1 ;
}
}
sockitsFd = socket ( PF_UNIX , SOCK_STREAM , 0 ) ;
if ( sockitsFd < 0 )
{
kdError ( ) < < " socket(): " < < errno < < endl ;
return - 1 ;
}
struct sockaddr_un addr ;
addr . sun_family = AF_UNIX ;
strncpy ( addr . sun_path , sock , sizeof ( addr . sun_path ) - 1 ) ;
addr . sun_path [ sizeof ( addr . sun_path ) - 1 ] = ' \000 ' ;
addrlen = SUN_LEN ( & addr ) ;
if ( bind ( sockitsFd , ( struct sockaddr * ) & addr , addrlen ) < 0 )
{
kdError ( ) < < " bind(): " < < errno < < endl ;
return - 1 ;
}
struct linger lin ;
lin . l_onoff = lin . l_linger = 0 ;
if ( setsockopt ( sockitsFd , SOL_SOCKET , SO_LINGER , ( char * ) & lin , sizeof ( linger ) ) < 0 )
{
kdError ( ) < < " setsockopt(SO_LINGER): " < < errno < < endl ;
return - 1 ;
}
int opt = 1 ;
if ( setsockopt ( sockitsFd , SOL_SOCKET , SO_REUSEADDR , ( char * ) & opt , sizeof ( opt ) ) < 0 )
{
kdError ( ) < < " setsockopt(SO_REUSEADDR): " < < errno < < endl ;
return - 1 ;
}
opt = 1 ;
if ( setsockopt ( sockitsFd , SOL_SOCKET , SO_KEEPALIVE , ( char * ) & opt , sizeof ( opt ) ) < 0 )
{
kdError ( ) < < " setsockopt(SO_KEEPALIVE): " < < errno < < endl ;
return - 1 ;
}
if ( : : listen ( sockitsFd , 1 ) < 0 )
{
kdError ( ) < < " listen(1): " < < errno < < endl ;
return - 1 ;
}
//chmod(sock, 0600);
return sockitsFd ;
}
static void urls2Local ( KURL : : List & urls , TQStringList & items , TQWidget * parent )
{
KURL : : List : : Iterator it ( urls . begin ( ) ) ,
end ( urls . end ( ) ) ;
for ( ; it ! = end ; + + it )
if ( ( * it ) . isLocalFile ( ) )
items . append ( ( * it ) . path ( ) ) ;
else
{
# if KDE_IS_VERSION(3, 5, 0)
KURL url ( TDEIO : : NetAccess : : mostLocalURL ( * it , parent ) ) ;
if ( url . isLocalFile ( ) )
items . append ( url . path ( ) ) ;
else
break ;
# else
break ;
# endif
}
}
KDialogD : : KDialogD ( TQObject * parent )
: TQObject ( parent ) ,
# ifdef KDIALOGD_APP
itsTimer ( NULL ) ,
itsTimeoutVal ( DEFAULT_TIMEOUT ) ,
# endif
itsFd ( : : createSocket ( ) ) ,
itsNumConnections ( 0 )
{
if ( itsFd < 0 )
{
kdError ( ) < < " KDialogD could not create socket " < < endl ;
# ifdef KDIALOGD_APP
kapp - > exit ( ) ;
# endif
}
else
{
std : : ofstream f ( getPidFileName ( ) ) ;
if ( f )
{
f < < getpid ( ) ;
f . close ( ) ;
}
if ( ! theirConfig )
theirConfig = new TDEConfig ( " kdialogdrc " , false , false ) ;
connect ( new TQSocketNotifier ( itsFd , TQSocketNotifier : : Read , this ) ,
TQ_SIGNAL ( activated ( int ) ) , this , TQ_SLOT ( newConnection ( ) ) ) ;
# ifdef KDIALOGD_APP
if ( theirConfig - > hasGroup ( CFG_TIMEOUT_GROUP ) )
{
theirConfig - > setGroup ( CFG_TIMEOUT_GROUP ) ;
itsTimeoutVal = theirConfig - > readNumEntry ( CFG_TIMEOUT_KEY , DEFAULT_TIMEOUT ) ;
if ( itsTimeoutVal < 0 )
itsTimeoutVal = DEFAULT_TIMEOUT ;
theirConfig - > setGroup ( TQString ( ) ) ;
}
kdDebug ( ) < < " Timeout: " < < itsTimeoutVal < < endl ;
if ( itsTimeoutVal )
connect ( itsTimer = new TQTimer ( this ) , TQ_SIGNAL ( timeout ( ) ) , this , TQ_SLOT ( timeout ( ) ) ) ;
# endif
}
}
KDialogD : : ~ KDialogD ( )
{
if ( - 1 ! = itsFd )
close ( itsFd ) ;
if ( theirConfig )
delete theirConfig ;
theirConfig = NULL ;
}
void KDialogD : : newConnection ( )
{
kdDebug ( ) < < " New connection " < < endl ;
ksocklen_t addrlen = 64 ;
struct sockaddr_un clientname ;
int connectedFD ;
if ( ( connectedFD = : : accept ( itsFd , ( struct sockaddr * ) & clientname , & addrlen ) ) > = 0 )
{
int appNameLen ;
if ( readBlock ( connectedFD , ( char * ) & appNameLen , 4 ) )
{
bool ok = true ;
TQCString appName ;
if ( 0 = = appNameLen )
appName = " Generic " ;
else
{
appName . resize ( appNameLen ) ;
ok = readBlock ( connectedFD , appName . data ( ) , appNameLen ) ;
}
if ( ok )
{
itsNumConnections + + ;
# ifdef KDIALOGD_APP
if ( itsTimer )
itsTimer - > stop ( ) ;
# endif
connect ( new KDialogDClient ( connectedFD , appName , this ) ,
TQ_SIGNAL ( error ( KDialogDClient * ) ) ,
this , TQ_SLOT ( deleteConnection ( KDialogDClient * ) ) ) ;
}
}
}
}
void KDialogD : : deleteConnection ( KDialogDClient * client )
{
kdDebug ( ) < < " Delete client " < < endl ;
delete client ;
# ifdef KDIALOGD_APP
if ( 0 = = - - itsNumConnections )
if ( itsTimeoutVal )
itsTimer - > start ( itsTimeoutVal * 1000 , true ) ; // Only single shot...
else
timeout ( ) ;
# endif
}
void KDialogD : : timeout ( )
{
# ifdef KDIALOGD_APP
if ( 0 = = itsNumConnections )
if ( grabLock ( 0 ) > 0 ) // 0=> no wait...
{
kdDebug ( ) < < " Timeout occured, and no connections, so exit " < < endl ;
kapp - > exit ( ) ;
}
else //...unlock lock file...
{
kdDebug ( ) < < " Timeout occured, but unable to grab lock file - app must be connecting " < < endl ;
releaseLock ( ) ;
}
# endif
}
KDialogDClient : : KDialogDClient ( int sock , const TQString & an , TQObject * parent )
: TQObject ( parent ) ,
itsFd ( sock ) ,
itsDlg ( NULL ) ,
itsAccepted ( false ) ,
itsAppName ( an )
{
kdDebug ( ) < < " new client... " < < itsAppName < < " ( " < < itsFd < < " ) " < < endl ;
connect ( new TQSocketNotifier ( itsFd , TQSocketNotifier : : Read , this ) , TQ_SIGNAL ( activated ( int ) ) , this , TQ_SLOT ( read ( ) ) ) ;
connect ( new TQSocketNotifier ( itsFd , TQSocketNotifier : : Exception , this ) , TQ_SIGNAL ( activated ( int ) ) , this , TQ_SLOT ( close ( ) ) ) ;
}
KDialogDClient : : ~ KDialogDClient ( )
{
kdDebug ( ) < < " Deleted client " < < endl ;
if ( - 1 ! = itsFd )
: : close ( itsFd ) ;
if ( KDialogD : : config ( ) )
KDialogD : : config ( ) - > sync ( ) ;
}
void KDialogDClient : : close ( )
{
kdDebug ( ) < < " close " < < itsFd < < endl ;
: : close ( itsFd ) ;
itsFd = - 1 ;
if ( itsDlg )
{
itsDlg - > close ( ) ;
itsDlg - > delayedDestruct ( ) ;
itsDlg = NULL ;
}
emit error ( this ) ;
}
void KDialogDClient : : read ( )
{
kdDebug ( ) < < " read " < < endl ;
if ( - 1 = = itsFd )
return ;
char request ;
TQString caption ;
unsigned int xid = 0 ;
if ( ! itsDlg & & readData ( & request , 1 ) & & request > = ( char ) OP_FILE_OPEN & & request < = ( char ) OP_FOLDER & &
readData ( ( char * ) & xid , 4 ) & & readString ( caption ) )
{
if ( " . " = = caption )
switch ( ( Operation ) request )
{
case OP_FILE_OPEN :
case OP_FILE_OPEN_MULTIPLE :
caption = i18n ( " Open " ) ;
break ;
case OP_FILE_SAVE :
caption = i18n ( " Save As " ) ;
break ;
case OP_FOLDER :
caption = i18n ( " Select Folder " ) ;
break ;
default :
break ;
}
if ( OP_FOLDER = = ( Operation ) request )
{
TQString intialFolder ;
if ( readString ( intialFolder ) )
{
initDialog ( caption , new KDialogDDirSelectDialog ( itsAppName , intialFolder , true , NULL ,
" folderdialog " , false ) , xid ) ;
return ;
}
}
else
{
TQString intialFolder ,
filter ;
char overW = 0 ;
if ( readString ( intialFolder ) & & readString ( filter ) & &
( OP_FILE_SAVE ! = ( Operation ) request | | readData ( & overW , 1 ) ) )
{
initDialog ( caption , new KDialogDFileDialog ( itsAppName , ( Operation ) request , intialFolder ,
filter , overW ? true : false ) , xid ) ;
return ;
}
}
}
kdDebug ( ) < < " Comms error, closing connection... " < < itsFd < < endl ;
// If we get here something was wrong, close connection...
close ( ) ;
}
void KDialogDClient : : finished ( )
{
if ( - 1 = = itsFd )
return ;
//
// * finished is emitted when a dialog is ok'ed/cancel'ed/closed
// * if the user just closes the dialog - neither ok nor cancel are emitted
// * the dir select dialog doesnt seem to set the TQDialog result parameter
// when it is accepted - so for this reason if ok is clicked we store an
// 'accepted' value there, and check for that after the dialog is finished.
kdDebug ( ) < < " finished " < < endl ;
if ( itsDlg & & ! ( itsAccepted | | TQDialog : : Accepted = = itsDlg - > result ( ) ) )
cancel ( ) ;
}
void KDialogDClient : : ok ( const TQStringList & items )
{
kdDebug ( ) < < " ok " < < endl ;
int num = items . count ( ) ;
TQStringList : : ConstIterator it ( items . begin ( ) ) ,
end ( items . end ( ) ) ;
bool error = ! writeData ( ( char * ) & num , 4 ) ;
for ( ; ! error & & it ! = end ; + + it )
error = ! writeString ( * it ) ;
if ( error )
close ( ) ;
else
itsAccepted = true ;
if ( itsDlg )
itsDlg - > delayedDestruct ( ) ;
itsDlg = NULL ;
}
void KDialogDClient : : cancel ( )
{
if ( itsDlg )
{
kdDebug ( ) < < " cancel " < < endl ;
int rv = 0 ;
if ( ! writeData ( ( char * ) & rv , 4 ) )
close ( ) ;
if ( itsDlg )
itsDlg - > delayedDestruct ( ) ;
itsDlg = NULL ;
}
}
bool KDialogDClient : : readData ( TQCString & buffer , int size )
{
buffer . resize ( size ) ;
return : : readBlock ( itsFd , buffer . data ( ) , size ) ;
}
bool KDialogDClient : : readString ( TQString & str )
{
int size ;
if ( ! readData ( ( char * ) & size , 4 ) )
return false ;
TQCString buffer ;
buffer . resize ( size ) ;
if ( ! readData ( buffer . data ( ) , size ) )
return false ;
str = TQString : : fromUtf8 ( buffer . data ( ) ) ;
return true ;
}
bool KDialogDClient : : writeString ( const TQString & str )
{
TQCString utf8 ( str . utf8 ( ) ) ;
int size = utf8 . length ( ) + 1 ;
return writeData ( ( char * ) & size , 4 ) & & writeData ( utf8 . data ( ) , size ) ;
}
void KDialogDClient : : initDialog ( const TQString & caption , KDialogBase * d , unsigned int xid )
{
itsAccepted = false ;
itsDlg = d ;
if ( ! caption . isEmpty ( ) )
itsDlg - > setPlainCaption ( caption ) ;
if ( xid )
{
# ifdef USE_KWIN
KWin : : setMainWindow ( itsDlg , xid ) ;
KWin : : setState ( itsDlg - > winId ( ) , NET : : Modal ) ;
KWin : : WindowInfo wi ( KWin : : windowInfo ( xid , NET : : WMGeometry , NET : : WM2UserTime ) ) ;
TQRect geom ( wi . geometry ( ) ) ;
int rx = geom . x ( ) ,
ry = geom . y ( ) ;
rx = ( rx + ( geom . width ( ) / 2 ) ) - ( itsDlg - > width ( ) / 2 ) ;
if ( rx < 0 )
rx = 0 ;
ry = ( ry + ( geom . height ( ) / 2 ) ) - ( itsDlg - > height ( ) / 2 ) ;
if ( ry < 0 )
ry = 0 ;
itsDlg - > move ( rx , ry ) ;
# else
XWindowAttributes attr ;
int rx , ry ;
Window juntwin ;
XSetTransientForHint ( tqt_xdisplay ( ) , itsDlg - > winId ( ) , xid ) ;
if ( XGetWindowAttributes ( tqt_xdisplay ( ) , xid , & attr ) )
{
XTranslateCoordinates ( tqt_xdisplay ( ) , xid , attr . root ,
- attr . border_width , - 16 ,
& rx , & ry , & juntwin ) ;
rx = ( rx + ( attr . width / 2 ) ) - ( itsDlg - > width ( ) / 2 ) ;
if ( rx < 0 )
rx = 0 ;
ry = ( ry + ( attr . height / 2 ) ) - ( itsDlg - > height ( ) / 2 ) ;
if ( ry < 0 )
ry = 0 ;
itsDlg - > move ( rx , ry ) ;
}
# endif
}
connect ( itsDlg , TQ_SIGNAL ( ok ( const TQStringList & ) ) , this , TQ_SLOT ( ok ( const TQStringList & ) ) ) ;
connect ( itsDlg , TQ_SIGNAL ( finished ( ) ) , this , TQ_SLOT ( finished ( ) ) ) ;
itsDlg - > show ( ) ;
}
KDialogDFileDialog : : KDialogDFileDialog ( TQString & an , Operation op , const TQString & startDir ,
const TQString & filter , bool confirmOw )
: KFileDialog ( startDir . isEmpty ( ) | | " ~ " = = startDir ? TQDir : : homeDirPath ( ) : startDir ,
filter , NULL , NULL , false ) ,
itsConfirmOw ( confirmOw ) ,
itsAppName ( an )
{
kdDebug ( ) < < " startDir: " < < startDir < < endl ;
switch ( op )
{
case OP_FILE_OPEN :
setOperationMode ( KFileDialog : : Opening ) ;
setMode ( ( KFile : : Mode ) ( KFile : : File | KFile : : ExistingOnly ) ) ;
break ;
case OP_FILE_OPEN_MULTIPLE :
setOperationMode ( KFileDialog : : Opening ) ;
setMode ( ( KFile : : Mode ) ( KFile : : Files | KFile : : ExistingOnly ) ) ;
break ;
case OP_FILE_SAVE :
setOperationMode ( KFileDialog : : Saving ) ;
setMode ( KFile : : File ) ;
break ;
default :
break ;
}
if ( KDialogD : : config ( ) )
{
TQString oldGrp ( KDialogD : : config ( ) - > group ( ) ) ,
grp ( groupName ( itsAppName ) ) ;
TQSize defaultSize ( 600 , 400 ) ;
readConfig ( KDialogD : : config ( ) , grp ) ;
KDialogD : : config ( ) - > setGroup ( grp ) ;
resize ( KDialogD : : config ( ) - > readSizeEntry ( CFG_KEY_DIALOG_SIZE , & defaultSize ) ) ;
KDialogD : : config ( ) - > setGroup ( oldGrp ) ;
}
ops - > clearHistory ( ) ;
}
void KDialogDFileDialog : : accept ( )
{
kdDebug ( ) < < " KDialogDFileDialog::accept " < < endl ;
}
void KDialogDFileDialog : : slotOk ( )
{
setResult ( TQDialog : : Accepted ) ;
KFileDialog : : slotOk ( ) ;
kdDebug ( ) < < " KDialogDFileDialog::slotOk " < < endl ;
KURL : : List urls ;
TQStringList items ;
bool good = true ;
if ( mode ( ) & KFile : : Files )
urls = selectedURLs ( ) ;
else if ( ! locationEdit - > currentText ( ) . isEmpty ( ) )
urls . append ( selectedURL ( ) ) ;
if ( urls . count ( ) )
{
urls2Local ( urls , items , this ) ;
if ( urls . count ( ) ! = items . count ( ) )
{
KMessageBox : : sorry ( this , i18n ( " You can only select local files. " ) ,
i18n ( " Remote Files Not Accepted " ) ) ;
good = false ;
}
else if ( itsConfirmOw & & KFileDialog : : Saving = = operationMode ( ) )
good = ! TDEIO : : NetAccess : : exists ( urls . first ( ) , false , this ) | |
KMessageBox : : Continue = = KMessageBox : : warningContinueCancel ( this ,
i18n ( " File %1 exists. \n Do you want to replace it? " )
. arg ( urls . first ( ) . prettyURL ( ) ) ,
i18n ( " File Exists " ) ,
Bring filenew, fileopen, fileprint, filequickprint, filesave, filesaveas, fileclose, editclear, editcopy, editcut, editdelete, editpaste, folder_new, and gohome icons into XDG compliance
il y a 10 ans
KGuiItem ( i18n ( " Replace " ) , " document-save-as " ) , TQString ( ) ,
KMessageBox : : Notify | KMessageBox : : PlainCaption ) ;
if ( good )
{
TQString filter ( currentFilter ( ) ) ;
if ( ! filter . isEmpty ( ) )
items . append ( filter ) ;
emit ok ( items ) ;
hide ( ) ;
KFileDialog : : accept ( ) ;
}
else
setResult ( TQDialog : : Rejected ) ;
}
}
KDialogDFileDialog : : ~ KDialogDFileDialog ( )
{
kdDebug ( ) < < " ~KDialogDFileDialog " < < endl ;
if ( KDialogD : : config ( ) )
{
TQString oldGrp ( KDialogD : : config ( ) - > group ( ) ) ,
grp ( groupName ( itsAppName ) ) ;
writeConfig ( KDialogD : : config ( ) , grp ) ;
KDialogD : : config ( ) - > setGroup ( grp ) ;
KDialogD : : config ( ) - > writeEntry ( CFG_KEY_DIALOG_SIZE , size ( ) ) ;
KDialogD : : config ( ) - > setGroup ( oldGrp ) ;
}
}
KDialogDDirSelectDialog : : KDialogDDirSelectDialog ( TQString & an , const TQString & startDir , bool localOnly ,
TQWidget * parent , const char * name , bool modal )
: KDirSelectDialog ( startDir . isEmpty ( ) | | " ~ " = = startDir
? TQDir : : homeDirPath ( ) : startDir ,
localOnly , parent , name , modal ) ,
itsAppName ( an )
{
kdDebug ( ) < < " startDir: " < < startDir < < endl ;
if ( KDialogD : : config ( ) )
{
TQString oldGrp ( KDialogD : : config ( ) - > group ( ) ) ,
grp ( groupName ( itsAppName , false ) ) ;
TQSize defaultSize ( 600 , 400 ) ;
//readConfig(KDialogD::config(), grp);
KDialogD : : config ( ) - > setGroup ( grp ) ;
resize ( KDialogD : : config ( ) - > readSizeEntry ( CFG_KEY_DIALOG_SIZE , & defaultSize ) ) ;
KDialogD : : config ( ) - > setGroup ( oldGrp ) ;
}
}
KDialogDDirSelectDialog : : ~ KDialogDDirSelectDialog ( )
{
kdDebug ( ) < < " ~KDialogDDirSelectDialog " < < endl ;
if ( KDialogD : : config ( ) )
{
TQString oldGrp ( KDialogD : : config ( ) - > group ( ) ) ,
grp ( groupName ( itsAppName , false ) ) ;
//writeConfig(KDialogD::config(), grp);
KDialogD : : config ( ) - > setGroup ( grp ) ;
KDialogD : : config ( ) - > writeEntry ( CFG_KEY_DIALOG_SIZE , size ( ) ) ;
KDialogD : : config ( ) - > setGroup ( oldGrp ) ;
}
}
void KDialogDDirSelectDialog : : slotOk ( )
{
kdDebug ( ) < < " KDialogDDirSelectDialog::slotOk " < < endl ;
KURL : : List urls ;
TQStringList items ;
urls . append ( url ( ) ) ;
urls2Local ( urls , items , this ) ;
if ( urls . count ( ) ! = items . count ( ) )
KMessageBox : : sorry ( this , i18n ( " You can only select local folders. " ) ,
i18n ( " Remote Folders Not Accepted " ) ) ;
else
{
emit ok ( items ) ;
hide ( ) ;
}
}
# ifdef KDIALOGD_APP
static TDEAboutData aboutData ( " kdialogd3 " , I18N_NOOP ( " KDialog Daemon " ) , VERSION ,
I18N_NOOP ( " Use TDE dialogs from non-TDE apps. " ) ,
TDEAboutData : : License_GPL ,
I18N_NOOP ( " (c) Craig Drummond, 2006-2007 " ) ) ;
int main ( int argc , char * * argv )
{
TDECmdLineArgs : : init ( argc , argv , & aboutData ) ;
KUniqueApplication * app = new KUniqueApplication ;
KDialogD kdialogd ;
int rv = app - > exec ( ) ;
delete app ;
unlink ( getSockName ( ) ) ;
releaseLock ( ) ;
return rv ;
}
# else
extern " C "
{
KDE_EXPORT KDEDModule * create_kdialogd ( const TQCString & obj )
{
return new KDialogDKDED ( obj ) ;
}
} ;
KDialogDKDED : : KDialogDKDED ( const TQCString & obj )
: KDEDModule ( obj )
{
new KDialogD ( this ) ;
}
# endif
# include "kdialogd.moc"