diff options
-rw-r--r-- | konq-plugins/Makefile.am | 4 | ||||
-rw-r--r-- | konq-plugins/rsync/Makefile.am | 21 | ||||
-rw-r--r-- | konq-plugins/rsync/cr16-action-remotesync.png | bin | 0 -> 573 bytes | |||
-rw-r--r-- | konq-plugins/rsync/cr16-action-remotesyncconfig.png | bin | 0 -> 650 bytes | |||
-rw-r--r-- | konq-plugins/rsync/cr22-action-remotesync.png | bin | 0 -> 772 bytes | |||
-rw-r--r-- | konq-plugins/rsync/cr22-action-remotesyncconfig.png | bin | 0 -> 667 bytes | |||
-rw-r--r-- | konq-plugins/rsync/rsync_plugin.desktop | 17 | ||||
-rw-r--r-- | konq-plugins/rsync/rsyncconfigdialog.cpp | 162 | ||||
-rw-r--r-- | konq-plugins/rsync/rsyncconfigdialog.h | 255 | ||||
-rw-r--r-- | konq-plugins/rsync/rsyncplugin.cpp | 721 | ||||
-rw-r--r-- | konq-plugins/rsync/rsyncplugin.desktop | 15 | ||||
-rw-r--r-- | konq-plugins/rsync/rsyncplugin.h | 131 | ||||
-rw-r--r-- | konq-plugins/rsync/rsyncplugin.rc | 7 |
13 files changed, 1330 insertions, 3 deletions
diff --git a/konq-plugins/Makefile.am b/konq-plugins/Makefile.am index 16a5bc7..fd50180 100644 --- a/konq-plugins/Makefile.am +++ b/konq-plugins/Makefile.am @@ -1,6 +1,4 @@ SUBDIRS = adblock crashes khtmlsettingsplugin kimgalleryplugin dirfilter uachanger \ babelfish validators domtreeviewer webarchiver sidebar kuick \ imagerotation minitools microformat autorefresh fsview searchbar \ - arkplugin akregator rellinks mediarealfolder - - + arkplugin akregator rellinks mediarealfolder rsync diff --git a/konq-plugins/rsync/Makefile.am b/konq-plugins/rsync/Makefile.am new file mode 100644 index 0000000..4f68035 --- /dev/null +++ b/konq-plugins/rsync/Makefile.am @@ -0,0 +1,21 @@ +INCLUDES = $(all_includes) +METASOURCES = AUTO + +kde_module_LTLIBRARIES = librsyncplugin.la +librsyncplugin_la_SOURCES = rsyncplugin.cpp rsyncconfigdialog.cpp +librsyncplugin_la_LIBADD = -lkonq +librsyncplugin_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) + +iconviewdir = $(kde_datadir)/konqiconview/kpartplugins +iconview_DATA = rsyncplugin.rc rsync_plugin.desktop + +listviewdir = $(kde_datadir)/konqlistview/kpartplugins +listview_DATA = rsyncplugin.rc rsync_plugin.desktop + +appsdir = $(kde_appsdir)/.hidden +apps_DATA = rsyncplugin.desktop + +KDE_ICON = AUTO + +messages: rc.cpp + $(XGETTEXT) *.cpp *.h -o $(podir)/rsyncplugin.pot diff --git a/konq-plugins/rsync/cr16-action-remotesync.png b/konq-plugins/rsync/cr16-action-remotesync.png Binary files differnew file mode 100644 index 0000000..5ef60f9 --- /dev/null +++ b/konq-plugins/rsync/cr16-action-remotesync.png diff --git a/konq-plugins/rsync/cr16-action-remotesyncconfig.png b/konq-plugins/rsync/cr16-action-remotesyncconfig.png Binary files differnew file mode 100644 index 0000000..a8d720b --- /dev/null +++ b/konq-plugins/rsync/cr16-action-remotesyncconfig.png diff --git a/konq-plugins/rsync/cr22-action-remotesync.png b/konq-plugins/rsync/cr22-action-remotesync.png Binary files differnew file mode 100644 index 0000000..3158b67 --- /dev/null +++ b/konq-plugins/rsync/cr22-action-remotesync.png diff --git a/konq-plugins/rsync/cr22-action-remotesyncconfig.png b/konq-plugins/rsync/cr22-action-remotesyncconfig.png Binary files differnew file mode 100644 index 0000000..ddf73f5 --- /dev/null +++ b/konq-plugins/rsync/cr22-action-remotesyncconfig.png diff --git a/konq-plugins/rsync/rsync_plugin.desktop b/konq-plugins/rsync/rsync_plugin.desktop new file mode 100644 index 0000000..14f84e2 --- /dev/null +++ b/konq-plugins/rsync/rsync_plugin.desktop @@ -0,0 +1,17 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=Service +X-KDE-PluginInfo-Author=Timothy Pearson +X-KDE-PluginInfo-Email=kb9vqf@pearsoncomputing.net +X-KDE-PluginInfo-Name=Rsync +X-KDE-PluginInfo-Version=3.4 +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category=Tools +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true +Name=Remote Folder Synchronization Plugin +Comment=Remote folder synchronization plugin +Icon=remotesync +X-KDE-ParentApp=konqueror +DocPath=konq-plugins/rsync/index.html diff --git a/konq-plugins/rsync/rsyncconfigdialog.cpp b/konq-plugins/rsync/rsyncconfigdialog.cpp new file mode 100644 index 0000000..f990fc8 --- /dev/null +++ b/konq-plugins/rsync/rsyncconfigdialog.cpp @@ -0,0 +1,162 @@ +/* + 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 <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 <qgroupbox.h> +#include <qradiobutton.h> +#include <qbuttongroup.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(QWidget* parent, const char* name, + const QString& caption, const QString& text, + const QString& localfolder, const QString& remotefolder, + 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 Q_WS_X11 + KWin::setIcons(winId(), kapp->icon(), kapp->miniIcon()); +#endif + mShowTimer = new QTimer(this); + + showButton(KDialogBase::Close, false); + mCancelText = actionButton(KDialogBase::Cancel)->text(); + + QFrame* mainWidget = plainPage(); + QVBoxLayout* layout = new QVBoxLayout(mainWidget, 10); + mLabel = new QLabel(QString("<b>") + text + QString("</b><br>Setting up synchronization for local folder<br><i>") + localfolder, mainWidget); + layout->addWidget(mLabel); + + // Create an exclusive button group + QButtonGroup *layoutg = new QButtonGroup( 1, QGroupBox::Horizontal, "Synchronization Method:", mainWidget); + layout->addWidget( layoutg ); + layoutg->setExclusive( TRUE ); + + // Insert radiobuttons + QRadioButton *rsync_rb = new QRadioButton("&Utilize rsync + ssh\nExample: servername:/path/to/remote/folder", layoutg); + rsync_rb->setChecked( TRUE ); + //(void)new QRadioButton( "R&adiobutton 2", layoutg ); + //(void)new QRadioButton( "Ra&diobutton 3", layoutg ); + + // Create an exclusive button group + QButtonGroup *layoutm = new QButtonGroup( 1, QGroupBox::Horizontal, "Remote Folder:", mainWidget); + layout->addWidget( layoutm ); + layoutg->setExclusive( TRUE ); + + m_rsync_txt = new QLineEdit(layoutm); + if (remotefolder.isEmpty() == false) { + m_rsync_txt->setText(remotefolder); + } + m_rsync_txt->setFocus(); +} + +QLineEdit* RsyncConfigDialog::lineEdit() +{ + return m_rsync_txt; +} + +const QLineEdit* RsyncConfigDialog::lineEdit() const +{ + return m_rsync_txt; +} + +#include "rsyncconfigdialog.moc" diff --git a/konq-plugins/rsync/rsyncconfigdialog.h b/konq-plugins/rsync/rsyncconfigdialog.h new file mode 100644 index 0000000..83314e8 --- /dev/null +++ b/konq-plugins/rsync/rsyncconfigdialog.h @@ -0,0 +1,255 @@ +/* + 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 <qmap.h> +#include <qstringlist.h> +#include <qlineedit.h> + +#include <kurl.h> +#include <kprocess.h> +#include <kfileitem.h> +#include <klibloader.h> +#include <kdialogbase.h> + +class RsyncConfigDialog : public KDialogBase +{ + Q_OBJECT + + public: + RsyncConfigDialog(QWidget* parent = 0, const char* name = 0, + const QString& caption = QString::null, + const QString& text = QString::null, + const QString& localfolder = QString::null, + const QString& remotefolder = QString::null, + bool modal = false); + + ~RsyncConfigDialog() {} +// +// /** +// * Returns the KProgressBox used in this dialog. +// * To set the number of steps or other progress bar related +// * settings, access the KProgressBox object directly via this method. +// */ +// KProgress* progressBar(); +// + /** + * Returns the QLineEdit used in this dialog. + * To set the number of lines or other text box related + * settings, access the KTextEdit object directly via this method. + */ + QLineEdit* lineEdit(); +// +// /** +// * Returns the KProgressBox used in this dialog. +// * To set the number of steps or other progress bar related +// * settings, access the KProgressBox object directly via this method. +// */ +// const KProgress* progressBar() const; +// + /** + * Returns the QLineEdit 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 QLineEdit* lineEdit() const; + + /** + * Sets the text in the dialog + * + * @param text the text to display + */ + void setLabel(const QString & text); + + /** + * Returns the current dialog text + * @deprecated + */ + // ### Remove this KDE 4.0 + QString labelText() KDE_DEPRECATED; + + /** + * Returns the current dialog text + */ + QString labelText() const; + + /** + * Sets whether or not the user can cancel the process. + * If the dialog is cancellable, the Cancel button will be shown + * and the user can close the window using the window decorations. + * If the process is not (or should not be) interuptable, + * set the dialog to be modal and not cancellable. + * + * @param allowCancel Set to true to make the dialog non-closable + */ + void setAllowCancel(bool allowCancel); + + /** + * Sets whether or not the user can edit the text shown in the textbox. + * + * @param allowTextEdit Set to true to make the text editable + */ + void setAllowTextEdit(bool allowTextEdit); + + /** + * Returns true if the dialog can be canceled, false otherwise + * @deprecated + */ + // ### Remove this KDE 4.0 + bool allowCancel() KDE_DEPRECATED; + + /** + * Returns true if the dialog can be canceled, false otherwise + */ + bool allowCancel() const; + + /** + * Sets whether the cancel button is visible. setAllowCancel(false) + * implies showCancelButton(false) + * + * @param show Whether or not the cancel button should be shown + */ + void showCancelButton(bool show); +// +// /** +// * Sets whether the dialog should close automagically when +// * all the steps in the KProgressBox have been completed. +// */ +// void setAutoClose(bool close); +// +// /** +// * Returns true if the dialog will close upon completion, +// * or false otherwise +// */ +// // ### Remove this KDE 4.0 +// bool autoClose(); +// +// /** +// * Returns true if the dialog will close upon completion, +// * or false otherwise +// */ +// bool autoClose() const; +// +// /** +// * Sets whether the dialog should reset the KProgressBox dialog +// * back to 0 steps compelete when all steps have been completed. +// * This is useful for RsyncConfigDialogs that will be reused. +// */ +// void setAutoReset(bool autoReset); +// +// /** +// * Returns true if the KProgressBox widget will be reset +// * upon completion, or false otherwise +// */ +// // ### Remove this KDE 4.0 +// bool autoReset(); +// +// /** +// * Returns true if the KProgressBox widget will be reset +// * upon completion, or false otherwise +// */ +// bool autoReset() const; +// + /** + * Returns true if the dialog was closed or canceled + * before completion. If the dialog is not cancellable + * it will always return false. + */ + // ### Remove this KDE 4.0 + bool wasCancelled(); + + /** + * Returns true if the dialog was closed or canceled + * before completion. If the dialog is not cancellable + * it will always return false. + */ + bool wasCancelled() const; + + /** + * Ignores the last cancel action if the cancel button was + * pressed. Useful for kdialog when combined with a KMessageBox + * to display a message like "Are you sure you want to cancel?" + * @since 3.5.5 + */ + void ignoreCancel(); + + /** + * Sets the text to appear on the cancel button. + */ + void setButtonText(const QString&); + + /** + * Returns the text on the cancel button + * @deprecated + */ + // ### Remove this KDE 4.0 + QString buttonText() KDE_DEPRECATED; + + /** + * Returns the text on the cancel button + */ + QString buttonText() const; +// +// /** +// * Set the minimum number of milliseconds to wait before +// * actually showing the dialog +// */ +// void setMinimumDuration(int ms); +// +// /** +// * Returns the wait duration in milliseconds +// * @deprecated +// */ +// // ### Remove this KDE 4.0 +// int minimumDuration() KDE_DEPRECATED; +// +// /** +// * Returns the wait duration in milliseconds +// */ +// int minimumDuration() const; +// +// /** +// * Reimplemented for internal reasons, the API is not affected. +// */ +// virtual void show(); +// +// protected slots: +// void slotAutoShow(); +// void slotAutoActions(int percentage); +// void slotCancel(); +// + private: + // ### Move these member variables to d in KDE 4.0 + bool mAutoClose; + bool mAutoReset; + bool mCancelled; + bool mAllowCancel; + bool mAllowTextEdit; + bool mShown; + QString mCancelText; + QLabel* mLabel; + KProgress* mProgressBar; + KTextEdit* mTextBox; + QTimer* mShowTimer; + QLineEdit* m_rsync_txt; +// protected: +// virtual void virtual_hook( int id, void* data ); +}; +#endif diff --git a/konq-plugins/rsync/rsyncplugin.cpp b/konq-plugins/rsync/rsyncplugin.cpp new file mode 100644 index 0000000..11785ac --- /dev/null +++ b/konq-plugins/rsync/rsyncplugin.cpp @@ -0,0 +1,721 @@ +/* + 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 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 subprocess +*/ +bool RsyncPlugin::connectionStart(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; + } + + //myDebug( << "Exec: " << (local ? suPath : rsyncPath) << " Port: " << connectionPort << " User: " << connectionUser << endl); + //infoMessage(rsyncPath); + 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 = QString(rsyncPath) + QString(" -avtzAXE --delete --progress ") + 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 = establishConnection(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; +} + +/** +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::establishConnection(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(); +} + +/** +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"); + + bool min_entry = false; + QString longstring = QString(""); + for (QStringList::Iterator i(cfgfolderlist.begin()); i != cfgfolderlist.end(); ++i) { + if (min_entry) + longstring = longstring + QString(";"); + longstring = longstring + (*i); + i++; + longstring = longstring + QString(";") + (*i); + min_entry = true; + } + + 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); + } + } + 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); + cfgfolderlist.remove(i); + return 0; + } + } + return 1; +} + +int RsyncPlugin::addLocalFolderByName(QString folderurl, QString remoteurl) +{ + QString folderurl_stripped; + folderurl_stripped = folderurl; + folderurl_stripped.replace(QString("file://"), QString("")); + cfgfolderlist.append(folderurl); + cfgfolderlist.append(remoteurl); + 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_pSyncMenu = new KActionMenu (i18n("Remote Folder S&ynchronization"), "syncmenu", + // actionCollection(), "rsync"); + m_pSyncNow->setIcon("remotesync"); + m_pSyncSetup->setIcon("remotesyncconfig"); + m_pSyncNow->setEnabled (false); + //m_pSyncMenu->setDelayed (false); + //m_pSyncMenu->setWhatsThis(i18n("Synchronizes this folder with a remote server.")); + + //connect (m_pSyncMenu->popupMenu(), SIGNAL (aboutToShow()), + // SLOT (slotShowPopup())); + + connect (m_part, SIGNAL(aboutToOpenURL()), SLOT(slotOpenURL())); + +// // add a menu option for konqis icons/list views +// KAction *syncnow = new KAction(i18n("Synchronize folder contents with server"), +// QApplication::reverseLayout() ? "remotesync" : "remotesync", +// 0, 0, 0, actionCollection(), "syncnow"); +// +// syncnow->setWhatsThis(i18n("Synchronize Folder<p>Synchronizes folder contents with remote server.")); +// + connect(m_pSyncNow, SIGNAL(activated()), this, SLOT(slotSync())); + connect(m_pSyncSetup, SIGNAL(activated()), this, SLOT(slotSetup())); + + loadSettings(); + + // Initialize the rsync backend variables + if (rsyncPath == NULL) { + rsyncPath = strdup(QFile::encodeName(KStandardDirs::findExe("rsync"))); + } + if (suPath == NULL) { + suPath = strdup(QFile::encodeName(KStandardDirs::findExe("su"))); + } + childPid = 0; + isLoggedIn = false; + firstLogin = true; + connectionAuth.keepPassword = true; + //connectionAuth.url.setProtocol("fish"); + 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)); + + m_configDialog = new RsyncConfigDialog(0, "rsyncConfig", i18n("Remote Folder Synchronization"), i18n("Configuring Remote Folder Synchronization"), localfolder, remotefolder, 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(); + + // See if an old entry has to be deleted + if (remotefolder.isEmpty() == false) { + deleteLocalFolderByName(localfolder); + } + if (remotefolder_new.isEmpty() == false) { + addLocalFolderByName(localfolder, remotefolder_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::slotSync() +{ + if (!m_part) + return; + + KURL url = m_part->url(); + + m_pSyncNow->setEnabled (false); + + // Initiate rsync + connectionStart(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" diff --git a/konq-plugins/rsync/rsyncplugin.desktop b/konq-plugins/rsync/rsyncplugin.desktop new file mode 100644 index 0000000..a06f228 --- /dev/null +++ b/konq-plugins/rsync/rsyncplugin.desktop @@ -0,0 +1,15 @@ +[Desktop Entry] +X-KDE-PluginInfo-Author=Timothy Pearson +X-KDE-PluginInfo-Email=kb9vqf@pearsoncomputing.net +X-KDE-PluginInfo-Name=Rsync +X-KDE-PluginInfo-Version=3.4 +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category=Tools +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true +Name=Remote Folder Synchronization Plugin +Comment=Remote folder synchronization plugin +Icon=remotesync +X-KDE-ParentApp=konqueror +DocPath=konq-plugins/rsync/index.html diff --git a/konq-plugins/rsync/rsyncplugin.h b/konq-plugins/rsync/rsyncplugin.h new file mode 100644 index 0000000..0e8c22d --- /dev/null +++ b/konq-plugins/rsync/rsyncplugin.h @@ -0,0 +1,131 @@ +/* + 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_PLUGIN_H +#define __RSYNC_PLUGIN_H + +#include <qmap.h> +#include <qstringlist.h> + +#include <kurl.h> +#include <kprocess.h> +#include <kfileitem.h> +#include <klibloader.h> +#include <kparts/plugin.h> +#include <kio/global.h> +#include <kio/slavebase.h> +#include <kio/authinfo.h> + +#include "rsyncconfigdialog.h" + +class KActionMenu; +class KonqDirPart; +class KLineEdit; + + +namespace KParts +{ + struct URLArgs; +} + +namespace KIO +{ + class Job; +} + +class RsyncPlugin : public KParts::Plugin +{ + Q_OBJECT + +public: + + RsyncPlugin (QObject* parent, const char* name, const QStringList &); + ~RsyncPlugin (); + +protected: + void loadSettings(); + void saveSettings(); + QString findLocalFolderByName(QString folderurl); + int deleteLocalFolderByName(QString folderurl); + int addLocalFolderByName(QString folderurl, QString remoteurl); + /** manages initial communication setup including password queries */ + int establishConnection(char *buffer, KIO::fileoffset_t len); + /** creates the subprocess */ + bool connectionStart(QString localfolder, QString 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 slotShowPopup(); + void slotSetupOK(); + void slotSetupCancelled(); + void slotRsyncCancelled(); + +private: + KURL m_pURL; + KonqDirPart* m_part; + KAction* m_pSyncNow; + KAction* m_pSyncSetup; + KActionMenu* m_pSyncMenu; + KProgressBoxDialog* m_progressDialog; + RsyncConfigDialog* m_configDialog; + + QStringList 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 */ + QString redirectUser, redirectPass; + /** user name of current connection */ + QString connectionUser; + /** password of current connection */ + QString connectionPassword; + /** true if this is the first login attempt (== use cached password) */ + bool firstLogin; + + QString thisFn; +}; +#endif diff --git a/konq-plugins/rsync/rsyncplugin.rc b/konq-plugins/rsync/rsyncplugin.rc new file mode 100644 index 0000000..40ec020 --- /dev/null +++ b/konq-plugins/rsync/rsyncplugin.rc @@ -0,0 +1,7 @@ +<!DOCTYPE kpartplugin> +<kpartplugin name="RsyncPlugin" library="librsyncplugin" version = "4"> +<ToolBar fullWidth="true" name="locationToolBar" newline="true"> + <Action name="syncnow"/> + <Action name="setupsync"/> +</ToolBar> +</kpartplugin> |