diff options
Diffstat (limited to 'tdersync')
-rw-r--r-- | tdersync/CMakeLists.txt | 50 | ||||
-rw-r--r-- | tdersync/rsyncconfigdialog.cpp | 207 | ||||
-rw-r--r-- | tdersync/rsyncconfigdialog.h | 105 | ||||
-rw-r--r-- | tdersync/tdersync.cpp | 1071 | ||||
-rw-r--r-- | tdersync/tdersync.h | 179 |
5 files changed, 1612 insertions, 0 deletions
diff --git a/tdersync/CMakeLists.txt b/tdersync/CMakeLists.txt new file mode 100644 index 000000000..20ea5b777 --- /dev/null +++ b/tdersync/CMakeLists.txt @@ -0,0 +1,50 @@ +################################################# +# +# (C) 2011 Timothy Pearson +# kb9vqf (AT) pearsoncomputing.net +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + +include_directories( + ${TQT_INCLUDE_DIRS} + ${CMAKE_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_BINARY_DIR}/tdecore + ${CMAKE_SOURCE_DIR}/dcop + ${CMAKE_SOURCE_DIR}/tdecore + ${CMAKE_SOURCE_DIR}/tdeui + ${CMAKE_SOURCE_DIR}/tdefx + ${CMAKE_SOURCE_DIR}/kio + ${CMAKE_SOURCE_DIR}/kio/kio +) + +link_directories( + ${TQT_LIBRARY_DIRS} +) + + +##### headers ################################### + +install( FILES + tdersync.h + DESTINATION ${INCLUDE_INSTALL_DIR}/libtdersync ) + + +##### tdersync #################################### + +set( target tdersync ) + +set( ${target}_SRCS + tdersync.cpp rsyncconfigdialog.cpp +) + +tde_add_library( ${target} SHARED AUTOMOC + SOURCES ${${target}_SRCS} + VERSION 0.0.1 + LINK tdeui-shared kio-shared + DESTINATION ${LIB_INSTALL_DIR} +) diff --git a/tdersync/rsyncconfigdialog.cpp b/tdersync/rsyncconfigdialog.cpp new file mode 100644 index 000000000..0c1cd532a --- /dev/null +++ b/tdersync/rsyncconfigdialog.cpp @@ -0,0 +1,207 @@ +/* + 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 <twin.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 <kstaticdeleter.h> +#include <kgenericfactory.h> +#include <tdeparts/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), + mSyncAutoLogout(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* layout = 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); + layout->addWidget(mLabel); + + // Create an exclusive button group + TQButtonGroup *layoutg = new TQButtonGroup( 1, Qt::Horizontal, i18n("Synchronization Method")+TQString(":"), mainWidget); + layout->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); + layout->addWidget( layoutm ); + layoutg->setExclusive( TRUE ); + + m_rsync_txt = new TQLineEdit(layoutm); + if (remotefolder.isEmpty() == false) { + m_rsync_txt->setText(remotefolder); + } + + // Create an exclusive button group + TQButtonGroup *layouta = new TQButtonGroup( 1, Qt::Horizontal, i18n("Automatic Synchronization")+TQString(":"), mainWidget); + layout->addWidget( layouta ); + layouta->setExclusive( FALSE ); + + m_sync_auto_logout_cb = new TQCheckBox(layouta); + m_sync_auto_logout_cb->setText(i18n("Synchronize on logout")); + m_sync_auto_logout_cb->setChecked(mSyncAutoLogout); + + setFixedSize( sizeHint() ); + + 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; + else + return 0; +} + +int RsyncConfigDialog::getAutoSyncFlags() +{ + int flags = 0; + if (m_sync_auto_logout_cb->isChecked() == true) + flags = flags | 0x1; + + return flags; +} + +void RsyncConfigDialog::setAutoSyncFlags(int flags) { + m_sync_auto_logout_cb->setChecked((flags & 0x1) != 0); +} + +TQLineEdit* RsyncConfigDialog::lineEdit() +{ + return m_rsync_txt; +} + +const TQLineEdit* RsyncConfigDialog::lineEdit() const +{ + return m_rsync_txt; +} + +#include "rsyncconfigdialog.moc" diff --git a/tdersync/rsyncconfigdialog.h b/tdersync/rsyncconfigdialog.h new file mode 100644 index 000000000..3da9e6f79 --- /dev/null +++ b/tdersync/rsyncconfigdialog.h @@ -0,0 +1,105 @@ +/* + 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 <tqcheckbox.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 + + + 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(); + + /** + * Returns the selected autosync flags + * Bit 0: Sync on logout + */ + int getAutoSyncFlags(); + + /** + * Sets the selected autosync flags + * + * @see getAutoSyncFlags() + */ + void setAutoSyncFlags(int flags); + + private: + bool mAutoClose; + bool mAutoReset; + bool mCancelled; + bool mAllowCancel; + bool mAllowTextEdit; + bool mShown; + bool mSyncAutoLogout; + TQString mCancelText; + TQLabel* mLabel; + KProgress* mProgressBar; + KTextEdit* mTextBox; + TQTimer* mShowTimer; + TQLineEdit* m_rsync_txt; + TQCheckBox* m_sync_auto_logout_cb; + TQRadioButton *rsync_rb1; + TQRadioButton *rsync_rb2; + TQRadioButton *rsync_rb3; +}; +#endif diff --git a/tdersync/tdersync.cpp b/tdersync/tdersync.cpp new file mode 100644 index 000000000..3e9e49981 --- /dev/null +++ b/tdersync/tdersync.cpp @@ -0,0 +1,1071 @@ +/* + 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 <kio/global.h> +#include <kio/slavebase.h> + +#include "tdersync.h" +#include "rsyncconfigdialog.h" + +#define myDebug(x) kdDebug(7127) << __LINE__ << ": " x + +#define CONFIGURATION_FILE_SEPARATOR ';' + +KDE_EXPORT KRsync::KRsync (TQObject* parent, const char* name) + : TQObject (parent, name), m_progressDialog(false), m_progressDialogExists(false), m_bSettingsLoaded(false), m_bInSpecialSync(false) +{ + loadSettings(); + + 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 +} + +KDE_EXPORT KRsync::~KRsync() +{ + +} + +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 +*/ +KDE_EXPORT bool KRsync::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); + + if (system(execstring.ascii()) < 0) { + // ERROR + } + #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 +*/ +KDE_EXPORT bool KRsync::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); + + if (system(execstring.ascii()) < 0) { + // ERROR + } + #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 +*/ +KDE_EXPORT void KRsync::writeChild(const char *buf, TDEIO::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 +*/ +KDE_EXPORT int KRsync::establishConnectionRsync(char *buffer, TDEIO::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, i18n("Remote Folder Synchronization")); + } + 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())); + if (m_bInSpecialSync) m_progressDialog->move(0,0); + 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, i18n("Remote Folder Synchronization")); + if (rc == KMessageBox::Yes) { + writeChild("yes\n",4); + } else { + writeChild("no\n",3); + } + thisFn = TQString(); + return 0; + } + + if (m_progressDialogExists == true) { + while (!m_progressDialog) { + usleep(100); + } + while (!m_progressDialog->textEdit()) { + usleep(100); + } + 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 +*/ +KDE_EXPORT int KRsync::establishConnectionUnison(char *buffer, TDEIO::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, i18n("Remote Folder Synchronization")); + } + else if (str.startsWith("Fatal error")) { + TQString fullError = str + buf; + fullError.replace("Fatal error: Server:", TQString("<b>").append(i18n("An error ocurred on the remote system")).append(":</b><br>")); + fullError.replace("\n", ""); + fullError.replace(": unable", ":<br>Unable"); + fullError.replace(")", ")</i><br>"); + fullError.replace("(", "<br><i>("); + KMessageBox::error(NULL, fullError, i18n("Remote Folder Synchronization")); + } + 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())); + if (m_bInSpecialSync) m_progressDialog->move(0,0); + 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("? []")) { + if (buf.startsWith("Proceed with propagating updates")) { + writeChild("y\n",3); + } + else { + int rc = KMessageBox::questionYesNo(NULL, buf, i18n("Remote Folder Synchronization")); + if (rc == KMessageBox::Yes) { + writeChild("y\n",3); + } else { + writeChild("n\n",3); + } + } + } + else { + if (buf.startsWith("Proceed with propagating updates")) { + writeChild("y\n",3); + } + else { + int rc = KMessageBox::questionYesNo(NULL, buf, i18n("Remote Folder Synchronization")); + 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.replace(TQString("new file "), ""); + file_name.replace("<-?->", ""); + file_name = file_name.stripWhiteSpace(); + if (localfolder.endsWith("Press return to continue.[]")) localfolder.truncate(localfolder.length()-TQString("Press return to continue.[]").length()); + if (remotepath.endsWith("Press return to continue.[]")) remotepath.truncate(remotepath.length()-TQString("Press return to continue.[]").length()); + 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")); + TQString prettyremotepath = remotepath; + TQString prettylocalfolder = localfolder; + if (!prettyremotepath.endsWith("/")) prettyremotepath = prettyremotepath + "/"; + if (!prettylocalfolder.endsWith("/")) prettylocalfolder = prettylocalfolder + "/"; + prettyremotepath = prettyremotepath.stripWhiteSpace(); + prettylocalfolder = prettylocalfolder.stripWhiteSpace(); + 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(": ") + prettylocalfolder + file_name + TQString("<br>") + i18n("Remote") + TQString(": ") + prettyremotepath + 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")) || (str.startsWith("Fatal error"))) { + if (m_progressDialogExists == true) { + while (!m_progressDialog) { + usleep(100); + } + while (!m_progressDialog->textEdit()) { + usleep(100); + } + m_progressDialog->progressBar()->setFormat("%v / %m"); + m_progressDialog->progressBar()->setTotalSteps(2); + m_progressDialog->progressBar()->setValue(m_progressDialog->progressBar()->totalSteps()); + } + } + else { + if (m_progressDialogExists == true) { + while (!m_progressDialog) { + usleep(100); + } + while (!m_progressDialog->textEdit()) { + usleep(100); + } + 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. + */ +KDE_EXPORT void KRsync::closeConnection(){ + myDebug( << "closeConnection()" << endl); + shutdownConnection(true, false); +} + +/** +Closes the connection + */ +KDE_EXPORT void KRsync::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 +// +// -------------------------------------------------------------------------------------------- + +KDE_EXPORT void KRsync::saveSettings() +{ + TDEConfig cfg ("rsyncrc", false, false); + cfg.setGroup ("General"); + cfg.writeEntry("LocalFolders", cfgfolderlist, CONFIGURATION_FILE_SEPARATOR); + cfg.writeEntry("AutoSyncOnLogout", cfgautosync_onlogout_list, CONFIGURATION_FILE_SEPARATOR); + cfg.sync(); +} + +KDE_EXPORT void KRsync::loadSettings() +{ + if (m_bSettingsLoaded) + return; + + TDEConfig cfg ("rsyncrc", false, false); + cfg.setGroup ("General"); + + cfgfolderlist = cfg.readListEntry("LocalFolders", CONFIGURATION_FILE_SEPARATOR); + cfgautosync_onlogout_list = cfg.readListEntry("AutoSyncOnLogout", CONFIGURATION_FILE_SEPARATOR); + + m_bSettingsLoaded = true; +} + +KDE_EXPORT void KRsync::executeLogoutAutoSync() +{ + for (TQStringList::Iterator i(cfgautosync_onlogout_list.begin()); i != cfgautosync_onlogout_list.end(); ++i) { + setCurrentDirectoryURL(*i); + m_bInSpecialSync = true; + slotSync(); + m_bInSpecialSync = false; + } +} + +KDE_EXPORT TQString KRsync::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; +} + +KDE_EXPORT TQString KRsync::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; +} + +KDE_EXPORT TQString KRsync::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; +} + +KDE_EXPORT TQString KRsync::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; +} + +KDE_EXPORT TQString KRsync::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; +} + +KDE_EXPORT int KRsync::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; +} + +KDE_EXPORT int KRsync::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; +} + +KDE_EXPORT void KRsync::setCurrentDirectoryURL (KURL url) +{ + m_pURL = url; +} + +KDE_EXPORT void KRsync::slotSetup() +{ + KURL url = m_pURL; + + // 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 = 1; + 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); + + // Handle autosync flags + if (localfolder != "") { + int flags = 0; + if (cfgautosync_onlogout_list.contains(localfolder)) + flags = flags | 0x1; + m_configDialog->setAutoSyncFlags(flags); + } + + m_configDialog->show(); + + connect (m_configDialog, TQT_SIGNAL(okClicked()), TQT_SLOT(slotSetupOK())); + connect (m_configDialog, TQT_SIGNAL(cancelClicked()), TQT_SLOT(slotSetupCancelled())); +} + +KDE_EXPORT void KRsync::slotSetupOK() +{ + KURL url = m_pURL; + + // 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"; + } + + // Handle autosync settings + int autosyncflags = m_configDialog->getAutoSyncFlags(); + cfgautosync_onlogout_list.remove(localfolder); + if (autosyncflags & 0x1) + cfgautosync_onlogout_list.append(localfolder); + + // 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, "", "0", "0", "-1"); + } + saveSettings(); + + emit setupDone(); +} + +KDE_EXPORT void KRsync::slotSetupCancelled() +{ + emit setupDone(); +} + +KDE_EXPORT void KRsync::slotRsyncCancelled() +{ + shutdownConnection(true, true); + if (m_progressDialogExists == true) { + m_progressDialog->progressBar()->setValue(m_progressDialog->progressBar()->totalSteps()); + } + + emit transferDone(); +} + +KDE_EXPORT void KRsync::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()); + } + + emit transferDone(); +} + +KDE_EXPORT void KRsync::slotSync() +{ + KURL url = m_pURL; + + 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; + + emit transferDone(); +} + +#include "tdersync.moc" diff --git a/tdersync/tdersync.h b/tdersync/tdersync.h new file mode 100644 index 000000000..c0af479f2 --- /dev/null +++ b/tdersync/tdersync.h @@ -0,0 +1,179 @@ +/* + 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 _LIBKRSYNC_H +#define _LIBKRSYNC_H + +#include <tqmap.h> +#include <tqstringlist.h> + +#include <kurl.h> +#include <kprocess.h> +#include <kfileitem.h> +#include <klibloader.h> +#include <tdeparts/plugin.h> +#include <kio/global.h> +#include <kio/slavebase.h> + +#include <tqfile.h> +#include <tqtimer.h> +#include <tqapplication.h> +#include <tqlabel.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 <kdebug.h> +#include <klocale.h> +#include <kinstance.h> + +#include <twin.h> +#include <kurl.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 <kstaticdeleter.h> +#include <kgenericfactory.h> +#include <tdeparts/browserextension.h> + +class KActionMenu; +class KonqDirPart; +class KLineEdit; +class RsyncConfigDialog; + +namespace KParts +{ + struct URLArgs; +} + +class KRsync : public TQObject +{ + Q_OBJECT + + +public: + + KRsync (TQObject* parent, const char* name); + virtual ~KRsync(); + +public: + 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, TDEIO::fileoffset_t len); + /** manages initial communication setup including password queries */ + int establishConnectionUnison(char *buffer, TDEIO::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, TDEIO::fileoffset_t len); + /** AuthInfo object used for logging in */ + TDEIO::AuthInfo connectionAuth; + /** + Clean up connection + */ + void shutdownConnection(bool forced=false, bool wait=false); + /** Forced close of the connection */ + void closeConnection(); + /** Set current local directory URL */ + void setCurrentDirectoryURL(KURL url); + +public slots: + void slotSync(); + void slotSetup(); + void slotSetupOK(); + void slotSetupCancelled(); + void slotRsyncCancelled(); + void slotUnisonCancelled(); + void executeLogoutAutoSync(); + +signals: + void setupDone(); + void transferDone(); + +private: + KURL m_pURL; + + KProgressBoxDialog* m_progressDialog; + RsyncConfigDialog* m_configDialog; + + TQStringList cfgfolderlist; + TQStringList cfgautosync_onlogout_list; + bool m_progressDialogExists; + + bool m_bSettingsLoaded; + bool m_bInSpecialSync; + + /** 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 */ + TDEIO::fileoffset_t outBufPos; + /** length of buffer */ + TDEIO::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; +}; +#endif |