Use new krsync library to handle remote sync operations

git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdeaddons@1252393 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
v3.5.13-sru
tpearson 13 years ago
parent 59b9e8308d
commit 3aba493dc9

@ -3,8 +3,8 @@ kde_module_LTLIBRARIES = librsyncplugin.la
AM_CPPFLAGS = $(all_includes)
METASOURCES = AUTO
librsyncplugin_la_SOURCES = rsyncplugin.cpp rsyncconfigdialog.cpp
librsyncplugin_la_LIBADD = -lkonq
librsyncplugin_la_SOURCES = rsyncplugin.cpp
librsyncplugin_la_LIBADD = -lkonq -lkrsync
librsyncplugin_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
iconviewdir = $(kde_datadir)/konqiconview/kpartplugins

@ -1,181 +0,0 @@
/*
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 <tqfile.h>
#include <tqtimer.h>
#include <tqapplication.h>
#include <tqpushbutton.h>
#include <tqhbox.h>
#include <tqwhatsthis.h>
#include <tqiconview.h>
#include <tqpainter.h>
#include <tqpixmap.h>
#include <tqlabel.h>
#include <tqlayout.h>
#include <tqpushbutton.h>
#include <tqstring.h>
#include <tqregexp.h>
#include <tqstyle.h>
#include <tqtimer.h>
#include <tqgroupbox.h>
#include <tqradiobutton.h>
#include <tqbuttongroup.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 "rsyncconfigdialog.h"
/*
* RsyncConfigDialog implementation
*/
RsyncConfigDialog::RsyncConfigDialog(TQWidget* parent, const char* name,
const TQString& caption, const TQString& text,
const TQString& localfolder, const TQString& remotefolder,
int syncmode, bool modal)
: KDialogBase(KDialogBase::Plain, caption, KDialogBase::Cancel | KDialogBase::Ok,
KDialogBase::Ok, parent, name, modal),
mAutoClose(true),
mAutoReset(false),
mCancelled(false),
mAllowCancel(true),
mAllowTextEdit(false),
mShown(false)
{
#ifdef TQ_WS_X11
KWin::setIcons(winId(), kapp->icon(), kapp->miniIcon());
#endif
mShowTimer = new TQTimer(this);
showButton(KDialogBase::Close, false);
mCancelText = actionButton(KDialogBase::Cancel)->text();
TQFrame* mainWidget = plainPage();
TQVBoxLayout* tqlayout = new TQVBoxLayout(mainWidget, 10);
mLabel = new TQLabel(TQString("<b>") + text + TQString("</b><br>")+i18n("Setting up synchronization for local folder")+TQString("<br><i>") + localfolder, mainWidget);
tqlayout->addWidget(mLabel);
// Create an exclusive button group
TQButtonGroup *layoutg = new TQButtonGroup( 1, Qt::Horizontal, i18n("Synchronization Method")+TQString(":"), mainWidget);
tqlayout->addWidget( layoutg );
layoutg->setExclusive( TRUE );
// Insert radiobuttons
rsync_rb1 = new TQRadioButton(i18n("&Utilize rsync + ssh for upload to remote server\nExample: servername:/path/to/remote/folder"), layoutg);
rsync_rb2 = new TQRadioButton(i18n("&Utilize rsync + ssh for download from remote server\nExample: servername:/path/to/remote/folder"), layoutg);
rsync_rb3 = new TQRadioButton(i18n("&Utilize unison + ssh for bidirectional synchronization with remote server\nExample: ssh://servername//path/to/remote/folder"), layoutg);
if (syncmode == 1)
rsync_rb1->setChecked( TRUE );
else if (syncmode == 2)
rsync_rb2->setChecked( TRUE );
else if (syncmode == 3)
rsync_rb3->setChecked( TRUE );
//(void)new TQRadioButton( "R&adiobutton 2", layoutg );
//(void)new TQRadioButton( "Ra&diobutton 3", layoutg );
// Create an exclusive button group
TQButtonGroup *layoutm = new TQButtonGroup( 1, Qt::Horizontal, i18n("Remote Folder")+TQString(":"), mainWidget);
tqlayout->addWidget( layoutm );
layoutg->setExclusive( TRUE );
m_rsync_txt = new TQLineEdit(layoutm);
if (remotefolder.isEmpty() == false) {
m_rsync_txt->setText(remotefolder);
}
m_rsync_txt->setFocus();
}
int RsyncConfigDialog::getSyncMode()
{
if (rsync_rb1->isChecked() == true)
return 1;
else if (rsync_rb2->isChecked() == true)
return 2;
else if (rsync_rb3->isChecked() == true)
return 3;
}
TQLineEdit* RsyncConfigDialog::lineEdit()
{
return m_rsync_txt;
}
const TQLineEdit* RsyncConfigDialog::lineEdit() const
{
return m_rsync_txt;
}
#include "rsyncconfigdialog.moc"

@ -1,89 +0,0 @@
/*
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.
*/
#ifndef __RSYNC_CONFIG_DIALOG_H
#define __RSYNC_CONFIG_DIALOG_H
#include <tqmap.h>
#include <tqstringlist.h>
#include <tqlineedit.h>
#include <tqradiobutton.h>
#include <kurl.h>
#include <kprocess.h>
#include <kfileitem.h>
#include <klibloader.h>
#include <kdialogbase.h>
// NOTE: If ANY of these functions are not utilized in the C file,
// and in a manner identical to these declarations, the plugin will
// mysteriously fail when launched with kshell but work fine under BASH
class RsyncConfigDialog : public KDialogBase
{
Q_OBJECT
TQ_OBJECT
public:
RsyncConfigDialog(TQWidget* parent = 0, const char* name = 0,
const TQString& caption = TQString(),
const TQString& text = TQString(),
const TQString& localfolder = TQString(),
const TQString& remotefolder = TQString(),
int syncmode = 1, bool modal = false);
/**
* Returns the TQLineEdit used in this dialog.
* To set the number of lines or other text box related
* settings, access the KTextEdit object directly via this method.
*/
TQLineEdit* lineEdit();
/**
* Returns the TQLineEdit used in this dialog.
* To set the number of lines or other text box related
* settings, access the KTextEdit object directly via this method.
*/
const TQLineEdit* lineEdit() const;
/**
* Returns index of selected synchronization mode
* 1: Upload
* 2: Download
* 3: Bidirectional
*/
int getSyncMode();
private:
bool mAutoClose;
bool mAutoReset;
bool mCancelled;
bool mAllowCancel;
bool mAllowTextEdit;
bool mShown;
TQString mCancelText;
TQLabel* mLabel;
KProgress* mProgressBar;
KTextEdit* mTextBox;
TQTimer* mShowTimer;
TQLineEdit* m_rsync_txt;
TQRadioButton *rsync_rb1;
TQRadioButton *rsync_rb2;
TQRadioButton *rsync_rb3;
};
#endif

@ -98,10 +98,11 @@
#include <kio/slavebase.h>
#include "rsyncplugin.h"
#include "rsyncconfigdialog.h"
#define myDebug(x) kdDebug(7127) << __LINE__ << ": " x
#define CONFIGURATION_FILE_SEPARATOR ';'
typedef KGenericFactory<RsyncPlugin> RsyncPluginFactory;
K_EXPORT_COMPONENT_FACTORY(librsyncplugin,
RsyncPluginFactory("rsyncplugin"))
@ -125,23 +126,17 @@ RsyncPlugin::RsyncPlugin (TQObject* parent, const char* name,
m_pSyncSetup->setIcon("remotesyncconfig");
m_pSyncNow->setEnabled (false);
m_rSync = new KRsync(parent, name);
connect (m_part, TQT_SIGNAL(aboutToOpenURL()), TQT_SLOT(slotOpenURL()));
connect(m_pSyncNow, TQT_SIGNAL(activated()), this, TQT_SLOT(slotSync()));
connect(m_pSyncSetup, TQT_SIGNAL(activated()), this, TQT_SLOT(slotSetup()));
loadSettings();
connect(m_rSync, TQT_SIGNAL(setupDone()), this, TQT_SLOT(slotSetupDone()));
connect(m_rSync, TQT_SIGNAL(transferDone()), this, TQT_SLOT(slotTransferDone()));
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
m_rSync->loadSettings();
}
RsyncPlugin::~RsyncPlugin()
@ -150,807 +145,16 @@ RsyncPlugin::~RsyncPlugin()
delete m_pSyncSetup;
}
static char *rsyncPath = NULL;
static char *suPath = NULL;
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(TQString synccommand, TQString syncflags, int parameter_order, TQString localfolder, TQString remotepath) {
int fd[2];
int rc, flags;
thisFn = TQString();
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
TQString execstring;
if (parameter_order == 0) {
execstring = synccommand + syncflags + localfolder + TQString("/ ") + remotepath;
}
else {
execstring = synccommand + syncflags + remotepath + TQString("/ ") + 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(TQString synccommand, TQString syncflags, int parameter_order, TQString localfolder, TQString remotepath) {
int fd[2];
int rc, flags;
thisFn = TQString();
// 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
TQString execstring;
execstring = synccommand + syncflags + localfolder + TQString(" ") + 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
TQString 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) {
TQString 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) {
tqApp->processEvents();
}
pos++;
TQString 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, TQT_SIGNAL(cancelClicked()), TQT_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 = TQString();
writeChild(connectionAuth.password.latin1(),connectionAuth.password.length());
} else {
myDebug( << "sending mpass" << endl);
connectionAuth.prompt = thisFn+buf;
connectionAuth.password = TQString(); // don't prefill
TQCString thispass;
if (KPasswordDialog::getPassword (thispass, i18n("Remote authorization required") + TQString("\n") + i18n("Please input") + TQString(" ") + TQString(buf), NULL) != 1) {
shutdownConnection(true, false);
return -1;
}
else {
connectionAuth.password = TQString(thispass);
}
connectionAuth.password += "\n";
myDebug( << "sending pass" << endl);
writeChild(connectionAuth.password.latin1(),connectionAuth.password.length());
}
thisFn = TQString();
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 = TQString();
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
TQString tocheck_out_cur;
TQString 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, TQString localfolder, TQString remotepath) {
TQString 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) {
tqApp->processEvents();
}
pos++;
TQString 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, TQT_SIGNAL(cancelClicked()), TQT_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 = TQString();
writeChild(connectionAuth.password.latin1(),connectionAuth.password.length());
} else {
myDebug( << "sending mpass" << endl);
connectionAuth.prompt = thisFn+buf;
connectionAuth.password = TQString(); // don't prefill
TQCString thispass;
if (KPasswordDialog::getPassword (thispass, i18n("Remote authorization required") + TQString("\n") + i18n("Please input") + TQString(" ") + TQString(buf), NULL) != 1) {
slotUnisonCancelled();
return -1;
}
else {
connectionAuth.password = TQString(thispass);
}
connectionAuth.password += "\n";
myDebug( << "sending pass" << endl);
writeChild(connectionAuth.password.latin1(),connectionAuth.password.length());
}
thisFn = TQString();
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 = TQString();
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);
}
TQString file_name;
file_name = buf;
file_name.replace("[]", "");
file_name.replace(TQString("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, TQMessageBox::Warning, TQString("<b>") + i18n("WARNING: Both the local and remote file have been modified") + TQString("</b><p>") + i18n("Local") + TQString(": ") + localfolder + TQString("/") + file_name + TQString("<br>") + i18n("Remote") + TQString(": ") + remotepath + TQString("/") + file_name + TQString("<p>") + i18n("Please select the file to duplicate (the other will be overwritten)") + TQString("<br>") + i18n("Or, select Ignore to skip synchronization of this file for now"), TQStringList(), TQString(), 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");
TQString longstring = TQString("");
for (TQStringList::Iterator i(cfgfolderlist.begin()); i != cfgfolderlist.end();) {
longstring = longstring + (*i);
i++;
longstring = longstring + TQString(";");
}
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;
}
TQString RsyncPlugin::findLocalFolderByName(TQString folderurl)
{
TQString folderurl_stripped;
folderurl_stripped = folderurl;
folderurl_stripped.replace(TQString("file://"), TQString(""));
for (TQStringList::Iterator i(cfgfolderlist.begin()); i != cfgfolderlist.end(); ++i) {
if (TQString::compare((*i), folderurl_stripped) == 0) {
i++;
return (*i);
i++;
i++;
i++;
i++;
i++;
}
}
return NULL;
}
TQString RsyncPlugin::findSyncMethodByName(TQString folderurl)
{
TQString folderurl_stripped;
folderurl_stripped = folderurl;
folderurl_stripped.replace(TQString("file://"), TQString(""));
for (TQStringList::Iterator i(cfgfolderlist.begin()); i != cfgfolderlist.end(); ++i) {
if (TQString::compare((*i), folderurl_stripped) == 0) {
i++;
i++;
return (*i);
i++;
i++;
i++;
i++;
}
}
return NULL;
}
TQString RsyncPlugin::findLoginSyncEnabledByName(TQString folderurl)
{
TQString folderurl_stripped;
folderurl_stripped = folderurl;
folderurl_stripped.replace(TQString("file://"), TQString(""));
for (TQStringList::Iterator i(cfgfolderlist.begin()); i != cfgfolderlist.end(); ++i) {
if (TQString::compare((*i), folderurl_stripped) == 0) {
i++;
i++;
i++;
i++;
return (*i);
i++;
i++;
}
}
return NULL;
}
TQString RsyncPlugin::findLogoutSyncEnabledByName(TQString folderurl)
{
TQString folderurl_stripped;
folderurl_stripped = folderurl;
folderurl_stripped.replace(TQString("file://"), TQString(""));
for (TQStringList::Iterator i(cfgfolderlist.begin()); i != cfgfolderlist.end(); ++i) {
if (TQString::compare((*i), folderurl_stripped) == 0) {
i++;
i++;
i++;
i++;
i++;
return (*i);
i++;
}
}
return NULL;
}
TQString RsyncPlugin::findTimedSyncEnabledByName(TQString folderurl)
{
TQString folderurl_stripped;
folderurl_stripped = folderurl;
folderurl_stripped.replace(TQString("file://"), TQString(""));
for (TQStringList::Iterator i(cfgfolderlist.begin()); i != cfgfolderlist.end(); ++i) {
if (TQString::compare((*i), folderurl_stripped) == 0) {
i++;
i++;
i++;
i++;
i++;
i++;
return (*i);
}
}
return NULL;
}
int RsyncPlugin::deleteLocalFolderByName(TQString folderurl)
{
TQString folderurl_stripped;
folderurl_stripped = folderurl;
folderurl_stripped.replace(TQString("file://"), TQString(""));
for (TQStringList::Iterator i(cfgfolderlist.begin()); i != cfgfolderlist.end(); ++i) {
if (TQString::compare((*i), folderurl_stripped) == 0) {
i=cfgfolderlist.remove(i);
i=cfgfolderlist.remove(i);
i=cfgfolderlist.remove(i);
i=cfgfolderlist.remove(i);
i=cfgfolderlist.remove(i);
i=cfgfolderlist.remove(i);
cfgfolderlist.remove(i);
return 0;
}
}
return 1;
}
int RsyncPlugin::addLocalFolderByName(TQString folderurl, TQString remoteurl, TQString syncmethod, TQString excludelist, TQString sync_on_login, TQString sync_on_logout, TQString sync_timed_interval)
{
TQString folderurl_stripped;
folderurl_stripped = folderurl;
folderurl_stripped.replace(TQString("file://"), TQString(""));
cfgfolderlist.append(folderurl);
cfgfolderlist.append(remoteurl);
cfgfolderlist.append(syncmethod);
cfgfolderlist.append(excludelist);
cfgfolderlist.append(sync_on_login);
cfgfolderlist.append(sync_on_logout);
cfgfolderlist.append(sync_timed_interval);
return 1;
}
void RsyncPlugin::slotOpenURL ()
{
KURL url = m_part->url();
m_rSync->setCurrentDirectoryURL(url);
if (m_pURL != url)
{
@ -976,7 +180,7 @@ void RsyncPlugin::slotOpenURL ()
m_pSyncSetup->setEnabled(true);
// See if this URL is in the list of rsync-able directories
if (findLocalFolderByName(url.directory(true, true) + TQString("/") + url.fileName(true)) != NULL) {
if (m_rSync->findLocalFolderByName(url.directory(true, true) + TQString("/") + url.fileName(true)) != NULL) {
m_pSyncNow->setEnabled (true);
}
else {
@ -990,97 +194,19 @@ void RsyncPlugin::slotOpenURL ()
void RsyncPlugin::slotSetup()
{
KURL url = m_part->url();
m_rSync->setCurrentDirectoryURL(url);
m_pSyncSetup->setEnabled (false);
// Look up settings
TQString localfolder = url.directory(true, true) + TQString("/") + url.fileName(true);
TQString remotefolder = findLocalFolderByName(url.directory(true, true) + TQString("/") + url.fileName(true));
TQString syncmethod = findSyncMethodByName(url.directory(true, true) + TQString("/") + 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, TQT_SIGNAL(okClicked()), TQT_SLOT(slotSetupOK()));
connect (m_configDialog, TQT_SIGNAL(cancelClicked()), TQT_SLOT(slotSetupCancelled()));
}
void RsyncPlugin::slotSetupOK()
{
if (!m_part)
return;
KURL url = m_part->url();
// Look up settings
TQString localfolder = url.directory(true, true) + TQString("/") + url.fileName(true);
TQString remotefolder = findLocalFolderByName(localfolder);
TQString remotefolder_new = m_configDialog->lineEdit()->text().ascii();
int syncmethod = m_configDialog->getSyncMode();
TQString 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);
m_rSync->slotSetup();
}
if (remotefolder_new.isEmpty() == false) {
addLocalFolderByName(localfolder, remotefolder_new, syncmethod_new, "", "0", "0", "-1");
}
saveSettings();
if (remotefolder_new.isEmpty() == false) {
m_pSyncNow->setEnabled (true);
}
else {
m_pSyncNow->setEnabled (false);
}
m_pSyncSetup->setEnabled (true);
}
void RsyncPlugin::slotSetupCancelled()
void RsyncPlugin::slotSetupDone()
{
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()
void RsyncPlugin::slotTransferDone()
{
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);
}
@ -1090,26 +216,9 @@ void RsyncPlugin::slotSync()
return;
KURL url = m_part->url();
m_rSync->setCurrentDirectoryURL(url);
m_pSyncNow->setEnabled (false);
TQString syncmethod = findSyncMethodByName(url.directory(true, true) + TQString("/") + url.fileName(true));
if (syncmethod == NULL) {
// Do nothing
}
else if (syncmethod == "rsync_upload") {
// Initiate rsync
syncUnidirectional(TQString("rsync"), TQString(" -avtzAXE --delete --progress "), 0, url.directory(true, true) + TQString("/") + url.fileName(true), findLocalFolderByName(url.directory(true, true) + TQString("/") + url.fileName(true)));
}
else if (syncmethod == "rsync_download") {
syncUnidirectional(TQString("rsync"), TQString(" -avtzAXE --delete --progress "), 1, url.directory(true, true) + TQString("/") + url.fileName(true), findLocalFolderByName(url.directory(true, true) + TQString("/") + url.fileName(true)));
}
else if (syncmethod == "rsync_bidirectional") {
syncBidirectional(TQString("unison"), TQString(" -ui text -auto "), 1, url.directory(true, true) + TQString("/") + url.fileName(true), findLocalFolderByName(url.directory(true, true) + TQString("/") + url.fileName(true)));
}
m_progressDialogExists = false;
m_pSyncNow->setEnabled (true);
m_rSync->slotSync();
}
#include "rsyncplugin.moc"

@ -30,7 +30,7 @@
#include <kio/global.h>
#include <kio/slavebase.h>
#include "rsyncconfigdialog.h"
#include <libkrsync/krsync.h>
// NOTE: If ANY of these functions are not utilized in the C file,
// and in a manner identical to these declarations, the plugin will
@ -55,82 +55,18 @@ public:
RsyncPlugin (TQObject* parent, const char* name, const TQStringList &);
virtual ~RsyncPlugin();
protected:
void loadSettings();
void saveSettings();
TQString findLocalFolderByName(TQString folderurl);
TQString findLoginSyncEnabledByName(TQString folderurl);
TQString findLogoutSyncEnabledByName(TQString folderurl);
TQString findTimedSyncEnabledByName(TQString folderurl);
int deleteLocalFolderByName(TQString folderurl);
int addLocalFolderByName(TQString folderurl, TQString remoteurl, TQString syncmethod, TQString excludelist, TQString sync_on_login, TQString sync_on_logout, TQString sync_timed_interval);
TQString findSyncMethodByName(TQString folderurl);
/** manages initial communication setup including password queries */
int establishConnectionRsync(char *buffer, KIO::fileoffset_t len);
/** manages initial communication setup including password queries */
int establishConnectionUnison(char *buffer, KIO::fileoffset_t len, TQString localfolder, TQString remotepath);
/** creates the unidirectional sync subprocess */
bool syncUnidirectional(TQString synccommand, TQString syncflags, int parameter_order, TQString localfolder, TQString remotepath);
/** creates the bidirectional sync subprocess */
bool syncBidirectional(TQString synccommand, TQString syncflags, int parameter_order, TQString localfolder, TQString remotepath);
/** writes one chunk of data to stdin of child process */
void writeChild(const char *buf, KIO::fileoffset_t len);
/** AuthInfo object used for logging in */
KIO::AuthInfo connectionAuth;
/**
Clean up connection
*/
void shutdownConnection(bool forced=false, bool wait=false);
/** Forced close of the connection */
void closeConnection();
private slots:
void slotSync();
void slotSetup();
void slotOpenURL();
void slotSetupOK();
void slotSetupCancelled();
void slotRsyncCancelled();
void slotUnisonCancelled();
void slotSetupDone();
void slotTransferDone();
private:
KURL m_pURL;
KonqDirPart* m_part;
KAction* m_pSyncNow;
KAction* m_pSyncSetup;
KProgressBoxDialog* m_progressDialog;
RsyncConfigDialog* m_configDialog;
TQStringList cfgfolderlist;
bool m_progressDialogExists;
bool m_bSettingsLoaded;
/** true if connection is logged in successfully */
bool isLoggedIn;
/** the rsync process used to communicate with the remote end */
pid_t childPid;
/** fd for reading and writing to the process */
int childFd;
/** buffer for data to be written */
const char *outBuf;
/** current write position in buffer */
KIO::fileoffset_t outBufPos;
/** length of buffer */
KIO::fileoffset_t outBufLen;
/** use su if true else use ssh */
//bool local;
/** // FIXME: just a workaround for konq deficiencies */
bool isStat;
/** // FIXME: just a workaround for konq deficiencies */
TQString redirectUser, redirectPass;
/** user name of current connection */
TQString connectionUser;
/** password of current connection */
TQString connectionPassword;
/** true if this is the first login attempt (== use cached password) */
bool firstLogin;
TQString thisFn;
KRsync* m_rSync;
};
#endif

Loading…
Cancel
Save