diff options
Diffstat (limited to 'krsync/krsync.cpp')
-rw-r--r-- | krsync/krsync.cpp | 1100 |
1 files changed, 1100 insertions, 0 deletions
diff --git a/krsync/krsync.cpp b/krsync/krsync.cpp new file mode 100644 index 000000000..96de71b10 --- /dev/null +++ b/krsync/krsync.cpp @@ -0,0 +1,1100 @@ +/* + 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 <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 <kwin.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 <kparts/browserextension.h> + +#include <kio/global.h> +#include <kio/slavebase.h> + +#include "krsync.h" +#include "rsyncconfigdialog.h" + +#define myDebug(x) kdDebug(7127) << __LINE__ << ": " x + +#define CONFIGURATION_FILE_SEPARATOR ';' + +KRsync::KRsync (TQObject* parent, const char* name) + : TQObject (parent, name) +{ + 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 +} + +KRsync::~KRsync() +{ + +} + +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 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); + + 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 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); + + 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 KRsync::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 KRsync::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) { + 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 +*/ +int KRsync::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.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); + } + 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("? []")) { + if (buf.startsWith("Proceed with propagating updates")) { + writeChild("y\n",3); + } + else { + int rc = KMessageBox::questionYesNo(NULL, buf); + 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); + 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")) { + 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. + */ +void KRsync::closeConnection(){ + myDebug( << "closeConnection()" << endl); + shutdownConnection(true, false); +} + +/** +Closes the connection + */ +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 +// +// -------------------------------------------------------------------------------------------- + +void KRsync::saveSettings() +{ + KConfig 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(); +} + +void KRsync::loadSettings() +{ + if (m_bSettingsLoaded) + return; + + KConfig 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; +} + +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; +} + +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; +} + +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; +} + +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; +} + +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; +} + +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; +} + +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; +} + +void KRsync::setCurrentDirectoryURL (KURL url) +{ + m_pURL = url; +} + +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; + 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())); +} + +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(); +} + +void KRsync::slotSetupCancelled() +{ + emit setupDone(); +} + +void KRsync::slotRsyncCancelled() +{ + shutdownConnection(true, true); + if (m_progressDialogExists == true) { + m_progressDialog->progressBar()->setValue(m_progressDialog->progressBar()->totalSteps()); + } + + emit transferDone(); +} + +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(); +} + +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 "krsync.moc" |