/*
Copyright ( C ) 2000 , 2001 , 2002 Dawit Alemayehu < adawit @ kde . org >
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation .
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 .
*/
# include <unistd.h>
# include <sys/types.h>
# include <signal.h>
# include <sys/socket.h>
# include <sys/un.h>
# include <errno.h>
# include <sys/time.h>
# include <sys/resource.h>
# include <sys/ioctl.h>
# include <sys/stat.h>
# include <fcntl.h>
# define HAVE_TERMIOS_H 1
# define HAVE_GRANTPT 1
# include <stdlib.h>
# ifdef HAVE_PTY_H
# include <pty.h>
# endif
# ifdef HAVE_TERMIOS_H
# include <termios.h>
# endif
# ifdef HAVE_STROPTS
# include <stropts.h>
# endif
# ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
# endif
# ifdef HAVE_LIBUTIL_H
# include <libutil.h>
# endif
# ifdef HAVE_UTIL_H
# include <util.h>
# endif
# include <qfile.h>
# include <qtimer.h>
# include <qapplication.h>
# include <qlabel.h>
# include <qpushbutton.h>
# include <qhbox.h>
# include <qwhatsthis.h>
# include <qiconview.h>
# include <qpainter.h>
# include <qpixmap.h>
# include <qlabel.h>
# include <qlayout.h>
# include <qpushbutton.h>
# include <qstring.h>
# include <qregexp.h>
# include <qstyle.h>
# include <qtimer.h>
# include <kdebug.h>
# include <klocale.h>
# include <kinstance.h>
# include <kwin.h>
# include <kaction.h>
# include <kpopupmenu.h>
# include <kmessagebox.h>
# include <kiconloader.h>
# include <kprogressbox.h>
# include <kpassdlg.h>
# include <klistview.h>
# include <kapplication.h>
# include <kconfigdialog.h>
# include <kdirlister.h>
# include <kstandarddirs.h>
# include <klistviewsearchline.h>
# include <kiconviewsearchline.h>
# include <konq_dirpart.h>
# include <konq_propsview.h>
# include <kstaticdeleter.h>
# include <kgenericfactory.h>
# include <kparts/browserextension.h>
# include <kio/global.h>
# include <kio/slavebase.h>
# include <kio/authinfo.h>
# include "rsyncplugin.h"
# include "rsyncconfigdialog.h"
# define myDebug(x) kdDebug(7127) << __LINE__ << ": " x
// #define myDebug(x) cout << __LINE__ << ": " x
# define infoMessage(x) printf("INFO: %s\n\r", x);
static int open_pty_pair ( int fd [ 2 ] )
{
# if defined(HAVE_TERMIOS_H) && defined(HAVE_GRANTPT) && !defined(HAVE_OPENPTY)
/** with kind regards to The GNU C Library
Reference Manual for Version 2.2 . x of the GNU C Library */
int master , slave ;
char * name ;
struct : : termios ti ;
memset ( & ti , 0 , sizeof ( ti ) ) ;
ti . c_cflag = CLOCAL | CREAD | CS8 ;
ti . c_cc [ VMIN ] = 1 ;
# ifdef HAVE_GETPT
master = getpt ( ) ;
# else
master = open ( " /dev/ptmx " , O_RDWR ) ;
# endif
if ( master < 0 ) return 0 ;
if ( grantpt ( master ) < 0 | | unlockpt ( master ) < 0 ) goto close_master ;
name = ptsname ( master ) ;
if ( name = = NULL ) goto close_master ;
slave = open ( name , O_RDWR ) ;
if ( slave = = - 1 ) goto close_master ;
# if (defined(HAVE_ISASTREAM) || defined(isastream)) && defined(I_PUSH)
if ( isastream ( slave ) & &
( ioctl ( slave , I_PUSH , " ptem " ) < 0 | |
ioctl ( slave , I_PUSH , " ldterm " ) < 0 ) )
goto close_slave ;
# endif
tcsetattr ( slave , TCSANOW , & ti ) ;
fd [ 0 ] = master ;
fd [ 1 ] = slave ;
return 0 ;
# if (defined(HAVE_ISASTREAM) || defined(isastream)) && defined(I_PUSH)
close_slave :
# endif
close ( slave ) ;
close_master :
close ( master ) ;
return - 1 ;
# else
# ifdef HAVE_OPENPTY
struct : : termios ti ;
memset ( & ti , 0 , sizeof ( ti ) ) ;
ti . c_cflag = CLOCAL | CREAD | CS8 ;
ti . c_cc [ VMIN ] = 1 ;
return openpty ( fd , fd + 1 , NULL , & ti , NULL ) ;
# else
# ifdef __GNUC__
# warning "No tty support available. Password dialog won't work."
# endif
return socketpair ( PF_UNIX , SOCK_STREAM , 0 , fd ) ;
# endif
# endif
}
/**
creates the unidirectional sync subprocess
*/
bool RsyncPlugin : : syncUnidirectional ( QString synccommand , QString syncflags , int parameter_order , QString localfolder , QString remotepath ) {
int fd [ 2 ] ;
int rc , flags ;
thisFn = QString : : null ;
rc = open_pty_pair ( fd ) ;
if ( rc = = - 1 ) {
myDebug ( < < " socketpair failed, error: " < < strerror ( errno ) < < endl ) ;
return true ;
}
childPid = fork ( ) ;
if ( childPid = = - 1 ) {
myDebug ( < < " fork failed, error: " < < strerror ( errno ) < < endl ) ;
close ( fd [ 0 ] ) ;
close ( fd [ 1 ] ) ;
childPid = 0 ;
return true ;
}
if ( childPid = = 0 ) {
// Create the rsync command to run
QString execstring ;
if ( parameter_order = = 0 ) {
execstring = synccommand + syncflags + localfolder + QString ( " / " ) + remotepath ;
}
else {
execstring = synccommand + syncflags + remotepath + QString ( " / " ) + localfolder ;
}
// taken from konsole, see TEPty.C for details
// note: if we're running on socket pairs,
// this will fail, but thats what we expect
for ( int sig = 1 ; sig < NSIG ; sig + + ) signal ( sig , SIG_DFL ) ;
struct rlimit rlp ;
getrlimit ( RLIMIT_NOFILE , & rlp ) ;
for ( int i = 0 ; i < ( int ) rlp . rlim_cur ; i + + )
if ( i ! = fd [ 1 ] ) close ( i ) ;
dup2 ( fd [ 1 ] , 0 ) ;
dup2 ( fd [ 1 ] , 1 ) ;
dup2 ( fd [ 1 ] , 2 ) ;
if ( fd [ 1 ] > 2 ) close ( fd [ 1 ] ) ;
setsid ( ) ;
# if defined(TIOCSCTTY)
ioctl ( 0 , TIOCSCTTY , 0 ) ;
# endif
int pgrp = getpid ( ) ;
# if defined( _AIX) || defined( __hpux)
tcsetpgrp ( 0 , pgrp ) ;
# else
ioctl ( 0 , TIOCSPGRP , ( char * ) & pgrp ) ;
# endif
const char * dev = ttyname ( 0 ) ;
setpgid ( 0 , 0 ) ;
if ( dev ) close ( open ( dev , O_WRONLY , 0 ) ) ;
setpgid ( 0 , 0 ) ;
system ( execstring . ascii ( ) ) ;
# undef common_args
myDebug ( < < " could not exec! " < < strerror ( errno ) < < endl ) ;
: : exit ( - 1 ) ;
}
close ( fd [ 1 ] ) ;
rc = fcntl ( fd [ 0 ] , F_GETFL , & flags ) ;
rc = fcntl ( fd [ 0 ] , F_SETFL , flags | O_NONBLOCK ) ;
childFd = fd [ 0 ] ;
fd_set rfds , wfds ;
FD_ZERO ( & rfds ) ;
FD_ZERO ( & wfds ) ;
char buf [ 32768 ] ;
int offset = 0 ;
while ( ! isLoggedIn ) {
FD_SET ( childFd , & rfds ) ;
FD_ZERO ( & wfds ) ;
if ( outBufPos > = 0 ) FD_SET ( childFd , & wfds ) ;
struct timeval timeout ;
timeout . tv_sec = 0 ;
timeout . tv_usec = 1000 ;
rc = select ( childFd + 1 , & rfds , & wfds , NULL , & timeout ) ;
if ( rc < 0 ) {
if ( errno = = EINTR )
continue ;
myDebug ( < < " select failed, rc: " < < rc < < " , error: " < < strerror ( errno ) < < endl ) ;
return true ;
}
if ( FD_ISSET ( childFd , & wfds ) & & outBufPos > = 0 ) {
if ( outBuf ) {
rc = write ( childFd , outBuf + outBufPos , outBufLen - outBufPos ) ;
fflush ( stdout ) ;
}
else {
rc = 0 ;
}
if ( rc > = 0 ) outBufPos + = rc ;
else {
if ( errno = = EINTR )
continue ;
myDebug ( < < " write failed, rc: " < < rc < < " , error: " < < strerror ( errno ) < < endl ) ;
outBufPos = - 1 ;
//return true;
}
if ( outBufPos > = outBufLen ) {
outBufPos = - 1 ;
outBuf = NULL ;
outBufLen = 0 ;
}
}
if ( FD_ISSET ( childFd , & rfds ) ) {
rc = read ( childFd , buf + offset , 32768 - offset ) ;
if ( rc > 0 ) {
int noff = establishConnectionRsync ( buf , rc + offset ) ;
if ( noff < 0 ) return false ;
if ( noff > 0 ) memmove ( buf , buf + offset + rc - noff , noff ) ;
offset = noff ;
} else {
if ( errno = = EINTR )
continue ;
//if (errno == EAGAIN)
// continue;
myDebug ( < < " read failed, rc: " < < rc < < " , error: " < < strerror ( errno ) < < endl ) ;
return true ;
}
}
}
return false ;
}
/**
creates the bidirectional sync subprocess
*/
bool RsyncPlugin : : syncBidirectional ( QString synccommand , QString syncflags , int parameter_order , QString localfolder , QString remotepath ) {
int fd [ 2 ] ;
int rc , flags ;
thisFn = QString : : null ;
// Check for and remove the trailing slash in localfolder
if ( localfolder . endsWith ( " / " ) ) {
localfolder . remove ( localfolder . length ( ) - 1 , 1 ) ;
}
rc = open_pty_pair ( fd ) ;
if ( rc = = - 1 ) {
myDebug ( < < " socketpair failed, error: " < < strerror ( errno ) < < endl ) ;
return true ;
}
childPid = fork ( ) ;
if ( childPid = = - 1 ) {
myDebug ( < < " fork failed, error: " < < strerror ( errno ) < < endl ) ;
close ( fd [ 0 ] ) ;
close ( fd [ 1 ] ) ;
childPid = 0 ;
return true ;
}
if ( childPid = = 0 ) {
// Create the rsync command to run
QString execstring ;
execstring = synccommand + syncflags + localfolder + QString ( " " ) + remotepath ;
// taken from konsole, see TEPty.C for details
// note: if we're running on socket pairs,
// this will fail, but thats what we expect
for ( int sig = 1 ; sig < NSIG ; sig + + ) signal ( sig , SIG_DFL ) ;
struct rlimit rlp ;
getrlimit ( RLIMIT_NOFILE , & rlp ) ;
for ( int i = 0 ; i < ( int ) rlp . rlim_cur ; i + + )
if ( i ! = fd [ 1 ] ) close ( i ) ;
dup2 ( fd [ 1 ] , 0 ) ;
dup2 ( fd [ 1 ] , 1 ) ;
dup2 ( fd [ 1 ] , 2 ) ;
if ( fd [ 1 ] > 2 ) close ( fd [ 1 ] ) ;
setsid ( ) ;
# if defined(TIOCSCTTY)
ioctl ( 0 , TIOCSCTTY , 0 ) ;
# endif
int pgrp = getpid ( ) ;
# if defined( _AIX) || defined( __hpux)
tcsetpgrp ( 0 , pgrp ) ;
# else
ioctl ( 0 , TIOCSPGRP , ( char * ) & pgrp ) ;
# endif
const char * dev = ttyname ( 0 ) ;
setpgid ( 0 , 0 ) ;
if ( dev ) close ( open ( dev , O_WRONLY , 0 ) ) ;
setpgid ( 0 , 0 ) ;
system ( execstring . ascii ( ) ) ;
# undef common_args
myDebug ( < < " could not exec! " < < strerror ( errno ) < < endl ) ;
: : exit ( - 1 ) ;
}
close ( fd [ 1 ] ) ;
rc = fcntl ( fd [ 0 ] , F_GETFL , & flags ) ;
rc = fcntl ( fd [ 0 ] , F_SETFL , flags | O_NONBLOCK ) ;
childFd = fd [ 0 ] ;
fd_set rfds , wfds ;
FD_ZERO ( & rfds ) ;
FD_ZERO ( & wfds ) ;
char buf [ 32768 ] ;
int offset = 0 ;
while ( ! isLoggedIn ) {
FD_SET ( childFd , & rfds ) ;
FD_ZERO ( & wfds ) ;
if ( outBufPos > = 0 ) FD_SET ( childFd , & wfds ) ;
struct timeval timeout ;
timeout . tv_sec = 0 ;
timeout . tv_usec = 1000 ;
rc = select ( childFd + 1 , & rfds , & wfds , NULL , & timeout ) ;
if ( rc < 0 ) {
if ( errno = = EINTR )
continue ;
myDebug ( < < " select failed, rc: " < < rc < < " , error: " < < strerror ( errno ) < < endl ) ;
return true ;
}
if ( FD_ISSET ( childFd , & wfds ) & & outBufPos > = 0 ) {
if ( outBuf ) {
rc = write ( childFd , outBuf + outBufPos , outBufLen - outBufPos ) ;
fflush ( stdout ) ;
}
else {
rc = 0 ;
}
if ( rc > = 0 ) outBufPos + = rc ;
else {
if ( errno = = EINTR )
continue ;
myDebug ( < < " write failed, rc: " < < rc < < " , error: " < < strerror ( errno ) < < endl ) ;
outBufPos = - 1 ;
//return true;
}
if ( outBufPos > = outBufLen ) {
outBufPos = - 1 ;
outBuf = NULL ;
outBufLen = 0 ;
}
}
if ( FD_ISSET ( childFd , & rfds ) ) {
rc = read ( childFd , buf + offset , 32768 - offset ) ;
if ( rc > 0 ) {
int noff = establishConnectionUnison ( buf , rc + offset , localfolder , remotepath ) ;
if ( noff < 0 ) return false ;
if ( noff > 0 ) memmove ( buf , buf + offset + rc - noff , noff ) ;
offset = noff ;
} else {
if ( errno = = EINTR )
continue ;
//if (errno == EAGAIN)
// continue;
myDebug ( < < " read failed, rc: " < < rc < < " , error: " < < strerror ( errno ) < < endl ) ;
return true ;
}
}
}
return false ;
}
/**
writes one chunk of data to stdin of child process
*/
void RsyncPlugin : : writeChild ( const char * buf , KIO : : fileoffset_t len ) {
if ( outBufPos > = 0 & & outBuf ) {
#if 0
QString debug ;
debug . setLatin1 ( outBuf , outBufLen ) ;
if ( len > 0 ) myDebug ( < < " write request while old one is pending, throwing away input ( " < < outBufLen < < " , " < < outBufPos < < " , " < < debug . left ( 10 ) < < " ...) " < < endl ) ;
# endif
return ;
}
outBuf = buf ;
outBufPos = 0 ;
outBufLen = len ;
}
/**
manages initial communication setup including password queries
*/
int RsyncPlugin : : establishConnectionRsync ( char * buffer , KIO : : fileoffset_t len ) {
QString buf ;
buf . setLatin1 ( buffer , len ) ;
int pos ;
// Strip trailing whitespace
while ( buf . length ( ) & & ( buf [ buf . length ( ) - 1 ] = = ' ' ) )
buf . truncate ( buf . length ( ) - 1 ) ;
myDebug ( < < " establishing: got " < < buf < < endl ) ;
while ( childPid & & ( ( pos = buf . find ( ' \n ' ) ) > = 0 | | buf . endsWith ( " : " ) | | buf . endsWith ( " ? " ) ) ) {
if ( m_progressDialogExists = = true ) {
qApp - > processEvents ( ) ;
}
pos + + ;
QString str = buf . left ( pos ) ;
buf = buf . mid ( pos ) ;
if ( str = = " \n " )
continue ;
//if (str.contains("rsync error:")) {
if ( str . contains ( " rsync: " ) | | str . contains ( " failed. " ) | | ( str . contains ( " Could not " ) & & str . endsWith ( " . " ) ) ) {
KMessageBox : : error ( NULL , str ) ;
}
else if ( ! str . isEmpty ( ) ) {
thisFn + = str ;
if ( ( buf . endsWith ( " : " ) = = false ) & & ( buf . endsWith ( " ? " ) = = false ) ) {
// Display a nice little progress bar with text box
if ( m_progressDialogExists = = false ) {
m_progressDialog = new KProgressBoxDialog ( 0 , " rsyncProgress " , i18n ( " Synchronizing Folder... " ) , i18n ( " Synchronizing Folder... " ) , true ) ;
m_progressDialog - > progressBar ( ) - > setFormat ( " %v / %m " ) ;
m_progressDialog - > setAutoClose ( true ) ;
m_progressDialog - > progressBar ( ) - > setTotalSteps ( 2 ) ;
m_progressDialog - > progressBar ( ) - > setValue ( 1 ) ;
connect ( m_progressDialog , SIGNAL ( cancelClicked ( ) ) , SLOT ( slotRsyncCancelled ( ) ) ) ;
m_progressDialog - > show ( ) ;
m_progressDialogExists = true ;
}
}
}
else if ( buf . endsWith ( " : " ) ) {
if ( ! redirectUser . isEmpty ( ) & & connectionUser ! = redirectUser ) {
// FIXME: Possibly do something here; is this the success response?
return - 1 ;
} else if ( ! connectionPassword . isEmpty ( ) ) {
myDebug ( < < " sending cpass " < < endl ) ;
connectionAuth . password = connectionPassword + " \n " ;
connectionPassword = QString : : null ;
writeChild ( connectionAuth . password . latin1 ( ) , connectionAuth . password . length ( ) ) ;
} else {
myDebug ( < < " sending mpass " < < endl ) ;
connectionAuth . prompt = thisFn + buf ;
connectionAuth . password = QString : : null ; // don't prefill
QCString thispass ;
if ( KPasswordDialog : : getPassword ( thispass , i18n ( " Remote authorization required " ) + QString ( " \n " ) + i18n ( " Please input " ) + QString ( " " ) + QString ( buf ) , NULL ) ! = 1 ) {
shutdownConnection ( true , false ) ;
return - 1 ;
}
else {
connectionAuth . password = QString ( thispass ) ;
}
connectionAuth . password + = " \n " ;
myDebug ( < < " sending pass " < < endl ) ;
writeChild ( connectionAuth . password . latin1 ( ) , connectionAuth . password . length ( ) ) ;
}
thisFn = QString : : null ;
return 0 ;
}
else if ( buf . endsWith ( " ? " ) ) {
int rc = KMessageBox : : questionYesNo ( NULL , thisFn + buf ) ;
if ( rc = = KMessageBox : : Yes ) {
writeChild ( " yes \n " , 4 ) ;
} else {
writeChild ( " no \n " , 3 ) ;
}
thisFn = QString : : null ;
return 0 ;
}
if ( m_progressDialogExists = = true ) {
if ( str . contains ( " exit() " ) & & str . contains ( " ICE default IO " ) ) {
if ( m_progressDialogExists = = true ) {
m_progressDialog - > progressBar ( ) - > setValue ( m_progressDialog - > progressBar ( ) - > totalSteps ( ) ) ;
}
}
else {
if ( str . contains ( " , to-check= " ) ) {
// Parse the to-check output
QString tocheck_out_cur ;
QString tocheck_out_tot ;
tocheck_out_cur = str . mid ( str . find ( " , to-check= " ) + 11 , str . length ( ) ) ;
tocheck_out_tot = tocheck_out_cur . mid ( tocheck_out_cur . find ( " / " ) + 1 , tocheck_out_cur . length ( ) ) ;
tocheck_out_cur = tocheck_out_cur . left ( tocheck_out_cur . find ( " / " ) ) ;
tocheck_out_tot = tocheck_out_tot . left ( tocheck_out_tot . find ( " ) " ) ) ;
m_progressDialog - > progressBar ( ) - > setTotalSteps ( tocheck_out_tot . toInt ( ) - 1 ) ;
m_progressDialog - > progressBar ( ) - > setValue ( tocheck_out_tot . toInt ( ) - tocheck_out_cur . toInt ( ) - 2 ) ;
}
else {
m_progressDialog - > textEdit ( ) - > append ( str ) ;
m_progressDialog - > textEdit ( ) - > scrollToBottom ( ) ;
}
}
}
}
return buf . length ( ) ;
}
/**
manages initial communication setup including password queries
*/
int RsyncPlugin : : establishConnectionUnison ( char * buffer , KIO : : fileoffset_t len , QString localfolder , QString remotepath ) {
QString buf ;
buf . setLatin1 ( buffer , len ) ;
int pos ;
// Strip trailing whitespace
while ( buf . length ( ) & & ( buf [ buf . length ( ) - 1 ] = = ' ' ) )
buf . truncate ( buf . length ( ) - 1 ) ;
myDebug ( < < " establishing: got " < < buf < < endl ) ;
while ( childPid & & ( ( ( pos = buf . find ( ' \n ' ) ) > = 0 ) | | buf . endsWith ( " : " ) | | buf . endsWith ( " ? " ) | | buf . endsWith ( " ] " ) ) ) {
if ( m_progressDialogExists = = true ) {
qApp - > processEvents ( ) ;
}
pos + + ;
QString str = buf . left ( pos ) ;
buf = buf . mid ( pos ) ;
if ( str = = " \n " )
continue ;
//if (str.contains("rsync error:")) {
if ( str . contains ( " rsync: " ) | | str . contains ( " failed. " ) | | ( str . contains ( " Could not " ) & & str . endsWith ( " . " ) ) ) {
KMessageBox : : error ( NULL , str ) ;
}
else if ( ! str . isEmpty ( ) ) {
thisFn + = str ;
if ( ( buf . endsWith ( " : " ) = = false ) & & ( buf . endsWith ( " ? " ) = = false ) ) {
// Display a nice little progress bar with text box
if ( m_progressDialogExists = = false ) {
m_progressDialog = new KProgressBoxDialog ( 0 , " rsyncProgress " , i18n ( " Synchronizing Folder... " ) , i18n ( " Synchronizing Folder... " ) , true ) ;
m_progressDialog - > progressBar ( ) - > setFormat ( " %v / %m " ) ;
m_progressDialog - > progressBar ( ) - > setTotalSteps ( 0 ) ;
m_progressDialog - > setAutoClose ( true ) ;
connect ( m_progressDialog , SIGNAL ( cancelClicked ( ) ) , SLOT ( slotUnisonCancelled ( ) ) ) ;
m_progressDialog - > show ( ) ;
m_progressDialogExists = true ;
}
}
}
else if ( buf . endsWith ( " : " ) ) {
if ( ! redirectUser . isEmpty ( ) & & connectionUser ! = redirectUser ) {
// FIXME: Possibly do something here; is this the success response?
return - 1 ;
} else if ( ! connectionPassword . isEmpty ( ) ) {
myDebug ( < < " sending cpass " < < endl ) ;
connectionAuth . password = connectionPassword + " \n " ;
connectionPassword = QString : : null ;
writeChild ( connectionAuth . password . latin1 ( ) , connectionAuth . password . length ( ) ) ;
} else {
myDebug ( < < " sending mpass " < < endl ) ;
connectionAuth . prompt = thisFn + buf ;
connectionAuth . password = QString : : null ; // don't prefill
QCString thispass ;
if ( KPasswordDialog : : getPassword ( thispass , i18n ( " Remote authorization required " ) + QString ( " \n " ) + i18n ( " Please input " ) + QString ( " " ) + QString ( buf ) , NULL ) ! = 1 ) {
slotUnisonCancelled ( ) ;
return - 1 ;
}
else {
connectionAuth . password = QString ( thispass ) ;
}
connectionAuth . password + = " \n " ;
myDebug ( < < " sending pass " < < endl ) ;
writeChild ( connectionAuth . password . latin1 ( ) , connectionAuth . password . length ( ) ) ;
}
thisFn = QString : : null ;
return 0 ;
}
else if ( buf . endsWith ( " ? " ) | | buf . endsWith ( " ? [] " ) ) {
buf . replace ( " [] " , " " ) ;
if ( buf . endsWith ( " ? [] " ) ) {
int rc = KMessageBox : : questionYesNo ( NULL , buf ) ;
if ( rc = = KMessageBox : : Yes ) {
writeChild ( " y \n " , 3 ) ;
} else {
writeChild ( " n \n " , 3 ) ;
}
}
else {
int rc = KMessageBox : : questionYesNo ( NULL , buf ) ;
if ( rc = = KMessageBox : : Yes ) {
writeChild ( " yes \n " , 4 ) ;
} else {
writeChild ( " no \n " , 3 ) ;
}
}
thisFn = QString : : null ;
buf = " " ;
return 0 ;
}
else if ( buf . endsWith ( " ] " ) ) {
if ( m_progressDialogExists = = true ) {
m_progressDialog - > textEdit ( ) - > append ( buf ) ;
m_progressDialog - > textEdit ( ) - > scrollToBottom ( ) ;
int currentPos ;
currentPos = m_progressDialog - > progressBar ( ) - > progress ( ) ;
m_progressDialog - > progressBar ( ) - > setProgress ( + + currentPos ) ;
}
QString file_name ;
file_name = buf ;
file_name . replace ( " [] " , " " ) ;
file_name . replace ( QString ( " changed " ) , " " ) ;
//file_name = file_name.simplifyWhiteSpace();
KDialogBase * dialog = new KDialogBase ( i18n ( " User Intervention Required " ) , KDialogBase : : Yes | KDialogBase : : No | KDialogBase : : Cancel , KDialogBase : : Yes , KDialogBase : : Cancel , NULL , " warningYesNoCancel " , true , true , i18n ( " Use &Local File " ) , i18n ( " Use &Remote File " ) , i18n ( " &Ignore " ) ) ;
int rc = KMessageBox : : createKMessageBox ( dialog , QMessageBox : : Warning , QString ( " <b> " ) + i18n ( " WARNING: Both the local and remote file have been modified " ) + QString ( " </b><p> " ) + i18n ( " Local " ) + QString ( " : " ) + localfolder + QString ( " / " ) + file_name + QString ( " <br> " ) + i18n ( " Remote " ) + QString ( " : " ) + remotepath + QString ( " / " ) + file_name + QString ( " <p> " ) + i18n ( " Please select the file to duplicate (the other will be overwritten) " ) + QString ( " <br> " ) + i18n ( " Or, select Ignore to skip synchronization of this file for now " ) , QStringList ( ) , QString : : null , NULL , 1 ) ;
if ( rc = = KDialogBase : : Yes ) {
writeChild ( " > \n " , 3 ) ;
}
else if ( rc = = KDialogBase : : No ) {
writeChild ( " < \n " , 3 ) ;
}
else {
writeChild ( " / \n " , 3 ) ;
}
return 0 ;
}
if ( m_progressDialogExists = = true ) {
if ( str . contains ( " exit() " ) & & str . contains ( " ICE default IO " ) ) {
if ( m_progressDialogExists = = true ) {
m_progressDialog - > progressBar ( ) - > setFormat ( " %v / %m " ) ;
m_progressDialog - > progressBar ( ) - > setTotalSteps ( 2 ) ;
m_progressDialog - > progressBar ( ) - > setValue ( m_progressDialog - > progressBar ( ) - > totalSteps ( ) ) ;
}
}
else {
m_progressDialog - > textEdit ( ) - > append ( str ) ;
m_progressDialog - > textEdit ( ) - > scrollToBottom ( ) ;
int currentPos ;
currentPos = m_progressDialog - > progressBar ( ) - > progress ( ) ;
m_progressDialog - > progressBar ( ) - > setProgress ( + + currentPos ) ;
}
}
}
return buf . length ( ) ;
}
/**
Forced close of the connection
This function gets called from the application side of the universe ,
it shouldn ' t send any response .
*/
void RsyncPlugin : : closeConnection ( ) {
myDebug ( < < " closeConnection() " < < endl ) ;
shutdownConnection ( true , false ) ;
}
/**
Closes the connection
*/
void RsyncPlugin : : shutdownConnection ( bool forced , bool wait ) {
if ( childPid ) {
kill ( childPid , SIGTERM ) ; // We may not have permission...
childPid = 0 ;
if ( wait = = false ) {
close ( childFd ) ; // ...in which case this should do the trick
childFd = - 1 ;
}
}
outBufPos = - 1 ;
outBuf = NULL ;
outBufLen = 0 ;
isLoggedIn = false ;
}
// --------------------------------------------------------------------------------------------
//
// Here begins the standard load/save/search/Konqy stuff
//
// --------------------------------------------------------------------------------------------
void RsyncPlugin : : saveSettings ( )
{
KConfig cfg ( " rsyncrc " , false , false ) ;
cfg . setGroup ( " General " ) ;
QString longstring = QString ( " " ) ;
for ( QStringList : : Iterator i ( cfgfolderlist . begin ( ) ) ; i ! = cfgfolderlist . end ( ) ; ) {
longstring = longstring + ( * i ) ;
i + + ;
longstring = longstring + QString ( " ; " ) ;
}
cfg . writeEntry ( " LocalFolders " , longstring ) ;
cfg . sync ( ) ;
}
void RsyncPlugin : : loadSettings ( )
{
if ( m_bSettingsLoaded )
return ;
KConfig cfg ( " rsyncrc " , false , false ) ;
cfg . setGroup ( " General " ) ;
cfgfolderlist = cfg . readListEntry ( " LocalFolders " , ' ; ' ) ;
m_bSettingsLoaded = true ;
}
QString RsyncPlugin : : findLocalFolderByName ( QString folderurl )
{
QString folderurl_stripped ;
folderurl_stripped = folderurl ;
folderurl_stripped . replace ( QString ( " file:// " ) , QString ( " " ) ) ;
for ( QStringList : : Iterator i ( cfgfolderlist . begin ( ) ) ; i ! = cfgfolderlist . end ( ) ; + + i ) {
if ( QString : : compare ( ( * i ) , folderurl_stripped ) = = 0 ) {
i + + ;
return ( * i ) ;
i + + ;
i + + ;
}
}
return NULL ;
}
QString RsyncPlugin : : findSyncMethodByName ( QString folderurl )
{
QString folderurl_stripped ;
folderurl_stripped = folderurl ;
folderurl_stripped . replace ( QString ( " file:// " ) , QString ( " " ) ) ;
for ( QStringList : : Iterator i ( cfgfolderlist . begin ( ) ) ; i ! = cfgfolderlist . end ( ) ; + + i ) {
if ( QString : : compare ( ( * i ) , folderurl_stripped ) = = 0 ) {
i + + ;
i + + ;
return ( * i ) ;
i + + ;
}
}
return NULL ;
}
int RsyncPlugin : : deleteLocalFolderByName ( QString folderurl )
{
QString folderurl_stripped ;
folderurl_stripped = folderurl ;
folderurl_stripped . replace ( QString ( " file:// " ) , QString ( " " ) ) ;
for ( QStringList : : Iterator i ( cfgfolderlist . begin ( ) ) ; i ! = cfgfolderlist . end ( ) ; + + i ) {
if ( QString : : compare ( ( * i ) , folderurl_stripped ) = = 0 ) {
i = cfgfolderlist . remove ( i ) ;
i = cfgfolderlist . remove ( i ) ;
i = cfgfolderlist . remove ( i ) ;
cfgfolderlist . remove ( i ) ;
return 0 ;
}
}
return 1 ;
}
int RsyncPlugin : : addLocalFolderByName ( QString folderurl , QString remoteurl , QString syncmethod , QString excludelist )
{
QString folderurl_stripped ;
folderurl_stripped = folderurl ;
folderurl_stripped . replace ( QString ( " file:// " ) , QString ( " " ) ) ;
cfgfolderlist . append ( folderurl ) ;
cfgfolderlist . append ( remoteurl ) ;
cfgfolderlist . append ( syncmethod ) ;
cfgfolderlist . append ( excludelist ) ;
return 1 ;
}
RsyncPlugin : : RsyncPlugin ( QObject * parent , const char * name ,
const QStringList & )
: KParts : : Plugin ( parent , name ) ,
m_pSyncMenu ( 0 )
{
m_part = : : qt_cast < KonqDirPart * > ( parent ) ;
if ( ! m_part | | ! m_part - > scrollWidget ( ) )
return ;
m_pSyncNow = new KAction ( i18n ( " Synchronize F&older " ) , " syncnow " ,
actionCollection ( ) , " syncnow " ) ;
m_pSyncSetup = new KAction ( i18n ( " Setup Syn&chronization " ) , " setupsync " ,
actionCollection ( ) , " setupsync " ) ;
m_pSyncNow - > setIcon ( " remotesync " ) ;
m_pSyncSetup - > setIcon ( " remotesyncconfig " ) ;
m_pSyncNow - > setEnabled ( false ) ;
connect ( m_part , SIGNAL ( aboutToOpenURL ( ) ) , SLOT ( slotOpenURL ( ) ) ) ;
connect ( m_pSyncNow , SIGNAL ( activated ( ) ) , this , SLOT ( slotSync ( ) ) ) ;
connect ( m_pSyncSetup , SIGNAL ( activated ( ) ) , this , SLOT ( slotSetup ( ) ) ) ;
loadSettings ( ) ;
// Initialize the rsync backend variables
childPid = 0 ;
isLoggedIn = false ;
firstLogin = true ;
connectionAuth . keepPassword = true ;
outBufPos = - 1 ;
outBuf = NULL ;
outBufLen = 0 ;
isStat = false ; // FIXME: just a workaround for konq deficiencies
redirectUser = " " ; // FIXME: just a workaround for konq deficiencies
redirectPass = " " ; // FIXME: just a workaround for konq deficiencies
}
RsyncPlugin : : ~ RsyncPlugin ( )
{
delete m_pSyncMenu ;
}
void RsyncPlugin : : slotOpenURL ( )
{
KURL url = m_part - > url ( ) ;
if ( m_pURL ! = url )
{
// See if this URL is in the list of rsync-able directories
if ( findLocalFolderByName ( url . directory ( true , true ) + QString ( " / " ) + url . fileName ( true ) ) ! = NULL ) {
m_pSyncNow - > setEnabled ( true ) ;
}
else {
m_pSyncNow - > setEnabled ( false ) ;
}
}
m_pURL = url ;
}
// void RsyncPlugin::slotShowPopup()
// {
// if (!m_part)
// {
// m_pSyncMenu->setEnabled (false);
// return;
// }
//
// int id = 0;
// uint enableReset = 0;
//
// QString label;
// QStringList inodes;
//
// m_pSyncMenu->popupMenu()->clear();
// m_pSyncMenu->popupMenu()->insertTitle (i18n("Remote Folder Synchronization"));
// id = m_pSyncMenu->popupMenu()->insertItem (i18n("Synchronize Now"), this, SLOT(slotSync()));
// }
void RsyncPlugin : : slotSetup ( )
{
KURL url = m_part - > url ( ) ;
m_pSyncSetup - > setEnabled ( false ) ;
// Look up settings
QString localfolder = url . directory ( true , true ) + QString ( " / " ) + url . fileName ( true ) ;
QString remotefolder = findLocalFolderByName ( url . directory ( true , true ) + QString ( " / " ) + url . fileName ( true ) ) ;
QString syncmethod = findSyncMethodByName ( url . directory ( true , true ) + QString ( " / " ) + url . fileName ( true ) ) ;
int syncint ;
if ( syncmethod = = NULL ) {
syncint = 1 ;
}
else if ( syncmethod = = " rsync_upload " ) {
syncint = 1 ;
}
else if ( syncmethod = = " rsync_download " ) {
syncint = 2 ;
}
else if ( syncmethod = = " rsync_bidirectional " ) {
syncint = 3 ;
}
m_configDialog = new RsyncConfigDialog ( 0 , " rsyncConfig " , i18n ( " Remote Folder Synchronization " ) , i18n ( " Configuring Remote Folder Synchronization " ) , localfolder , remotefolder , syncint , true ) ;
m_configDialog - > show ( ) ;
connect ( m_configDialog , SIGNAL ( okClicked ( ) ) , SLOT ( slotSetupOK ( ) ) ) ;
connect ( m_configDialog , SIGNAL ( cancelClicked ( ) ) , SLOT ( slotSetupCancelled ( ) ) ) ;
}
void RsyncPlugin : : slotSetupOK ( )
{
if ( ! m_part )
return ;
KURL url = m_part - > url ( ) ;
// Look up settings
QString localfolder = url . directory ( true , true ) + QString ( " / " ) + url . fileName ( true ) ;
QString remotefolder = findLocalFolderByName ( localfolder ) ;
QString remotefolder_new = m_configDialog - > lineEdit ( ) - > text ( ) . ascii ( ) ;
int syncmethod = m_configDialog - > getSyncMode ( ) ;
QString syncmethod_new = " " ;
if ( syncmethod = = 1 ) {
syncmethod_new = " rsync_upload " ;
}
else if ( syncmethod = = 2 ) {
syncmethod_new = " rsync_download " ;
}
else if ( syncmethod = = 3 ) {
syncmethod_new = " rsync_bidirectional " ;
}
// See if an old entry has to be deleted
if ( remotefolder . isEmpty ( ) = = false ) {
deleteLocalFolderByName ( localfolder ) ;
}
if ( remotefolder_new . isEmpty ( ) = = false ) {
addLocalFolderByName ( localfolder , remotefolder_new , syncmethod_new , " " ) ;
}
saveSettings ( ) ;
if ( remotefolder_new . isEmpty ( ) = = false ) {
m_pSyncNow - > setEnabled ( true ) ;
}
else {
m_pSyncNow - > setEnabled ( false ) ;
}
m_pSyncSetup - > setEnabled ( true ) ;
}
void RsyncPlugin : : slotSetupCancelled ( )
{
m_pSyncSetup - > setEnabled ( true ) ;
}
void RsyncPlugin : : slotRsyncCancelled ( )
{
shutdownConnection ( true , true ) ;
if ( m_progressDialogExists = = true ) {
m_progressDialog - > progressBar ( ) - > setValue ( m_progressDialog - > progressBar ( ) - > totalSteps ( ) ) ;
}
m_pSyncNow - > setEnabled ( true ) ;
}
void RsyncPlugin : : slotUnisonCancelled ( )
{
shutdownConnection ( true , true ) ;
if ( m_progressDialogExists = = true ) {
m_progressDialog - > progressBar ( ) - > setFormat ( " %v / %m " ) ;
m_progressDialog - > progressBar ( ) - > setTotalSteps ( 2 ) ;
m_progressDialog - > progressBar ( ) - > setValue ( m_progressDialog - > progressBar ( ) - > totalSteps ( ) ) ;
}
m_pSyncNow - > setEnabled ( true ) ;
}
void RsyncPlugin : : slotSync ( )
{
if ( ! m_part )
return ;
KURL url = m_part - > url ( ) ;
m_pSyncNow - > setEnabled ( false ) ;
QString syncmethod = findSyncMethodByName ( url . directory ( true , true ) + QString ( " / " ) + url . fileName ( true ) ) ;
if ( syncmethod = = NULL ) {
// Do nothing
}
else if ( syncmethod = = " rsync_upload " ) {
// Initiate rsync
syncUnidirectional ( QString ( " rsync " ) , QString ( " -avtzAXE --delete --progress " ) , 0 , url . directory ( true , true ) + QString ( " / " ) + url . fileName ( true ) , findLocalFolderByName ( url . directory ( true , true ) + QString ( " / " ) + url . fileName ( true ) ) ) ;
}
else if ( syncmethod = = " rsync_download " ) {
syncUnidirectional ( QString ( " rsync " ) , QString ( " -avtzAXE --delete --progress " ) , 1 , url . directory ( true , true ) + QString ( " / " ) + url . fileName ( true ) , findLocalFolderByName ( url . directory ( true , true ) + QString ( " / " ) + url . fileName ( true ) ) ) ;
}
else if ( syncmethod = = " rsync_bidirectional " ) {
syncBidirectional ( QString ( " unison " ) , QString ( " -ui text -auto " ) , 1 , url . directory ( true , true ) + QString ( " / " ) + url . fileName ( true ) , findLocalFolderByName ( url . directory ( true , true ) + QString ( " / " ) + url . fileName ( true ) ) ) ;
}
m_progressDialogExists = false ;
m_pSyncNow - > setEnabled ( true ) ;
}
typedef KGenericFactory < RsyncPlugin > RsyncFactory ;
K_EXPORT_COMPONENT_FACTORY ( librsyncplugin , RsyncFactory ( " rsyncplugin " ) )
# include "rsyncplugin.moc"