From ca0636d7f48754c9b15af88c1e971ce8d1bde1a8 Mon Sep 17 00:00:00 2001
From: tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>
Date: Wed, 31 Mar 2010 03:32:16 +0000
Subject: Added Unison support to remote sync plugin

git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdeaddons@1109340 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
---
 konq-plugins/rsync/rsyncconfigdialog.cpp |   6 +-
 konq-plugins/rsync/rsyncplugin.cpp       | 173 +++++++++++++++++++++++++++++--
 konq-plugins/rsync/rsyncplugin.h         |   7 +-
 3 files changed, 171 insertions(+), 15 deletions(-)

diff --git a/konq-plugins/rsync/rsyncconfigdialog.cpp b/konq-plugins/rsync/rsyncconfigdialog.cpp
index b28a02c..0549356 100644
--- a/konq-plugins/rsync/rsyncconfigdialog.cpp
+++ b/konq-plugins/rsync/rsyncconfigdialog.cpp
@@ -134,14 +134,14 @@ RsyncConfigDialog::RsyncConfigDialog(QWidget* parent, const char* name,
     // Insert radiobuttons
     rsync_rb1 = new QRadioButton(i18n("&Utilize rsync + ssh for upload to remote server\nExample: servername:/path/to/remote/folder"), layoutg);
     rsync_rb2 = new QRadioButton(i18n("&Utilize rsync + ssh for download from remote server\nExample: servername:/path/to/remote/folder"), layoutg);
-    //rsync_rb3 = new QRadioButton(i18n("&Utilize rsync + ssh for synchronization with remote server\nExample: servername:/path/to/remote/folder"), layoutg);
+    rsync_rb3 = new QRadioButton(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 );
+    else if (syncmode == 3)
+        rsync_rb3->setChecked( TRUE );
 
     //(void)new QRadioButton( "R&adiobutton 2", layoutg );
     //(void)new QRadioButton( "Ra&diobutton 3", layoutg );
diff --git a/konq-plugins/rsync/rsyncplugin.cpp b/konq-plugins/rsync/rsyncplugin.cpp
index ebf7dd7..bc16a5a 100644
--- a/konq-plugins/rsync/rsyncplugin.cpp
+++ b/konq-plugins/rsync/rsyncplugin.cpp
@@ -292,7 +292,7 @@ bool RsyncPlugin::syncUnidirectional(QString synccommand, QString syncflags, int
         if (FD_ISSET(childFd,&rfds)) {
             rc = read(childFd,buf+offset,32768-offset);
             if (rc > 0) {
-                int noff = establishConnection(buf,rc+offset);
+                int noff = establishConnectionRsync(buf,rc+offset);
                 if (noff < 0) return false;
                 if (noff > 0) memmove(buf,buf+offset+rc-noff,noff);
                 offset = noff;
@@ -312,11 +312,16 @@ bool RsyncPlugin::syncUnidirectional(QString synccommand, QString syncflags, int
 /**
 creates the bidirectional sync subprocess
 */
-bool RsyncPlugin::syncBidirectional(QString localfolder, QString remotepath) {
+bool RsyncPlugin::syncBidirectional(QString synccommand, QString syncflags, int parameter_order, QString localfolder, QString remotepath) {
     int fd[2];
     int rc, flags;
     thisFn = QString::null;
 
+    // Check for and remove the trailing slash in localfolder
+    if (localfolder.endsWith("/")) {
+        localfolder.remove(localfolder.length()-1, 1);
+    }
+
     rc = open_pty_pair(fd);
     if (rc == -1) {
         myDebug( << "socketpair failed, error: " << strerror(errno) << endl);
@@ -335,8 +340,8 @@ bool RsyncPlugin::syncBidirectional(QString localfolder, QString remotepath) {
         // Create the rsync command to run
         QString execstring;
         // FIXME
-        //execstring = synccommand + syncflags + localfolder + QString("/ ") + remotepath;
-        exit -1;
+        execstring = synccommand + syncflags + localfolder + QString(" ") + remotepath;
+        printf("Will execute %s\n\r", execstring.ascii());
 
         // taken from konsole, see TEPty.C for details
         // note: if we're running on socket pairs,
@@ -426,7 +431,7 @@ bool RsyncPlugin::syncBidirectional(QString localfolder, QString remotepath) {
         if (FD_ISSET(childFd,&rfds)) {
             rc = read(childFd,buf+offset,32768-offset);
             if (rc > 0) {
-                int noff = establishConnection(buf,rc+offset);
+                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;
@@ -463,7 +468,7 @@ void RsyncPlugin::writeChild(const char *buf, KIO::fileoffset_t len) {
 /**
 manages initial communication setup including password queries
 */
-int RsyncPlugin::establishConnection(char *buffer, KIO::fileoffset_t len) {
+int RsyncPlugin::establishConnectionRsync(char *buffer, KIO::fileoffset_t len) {
     QString buf;
     buf.setLatin1(buffer,len);
     int pos;
@@ -568,6 +573,143 @@ int RsyncPlugin::establishConnection(char *buffer, KIO::fileoffset_t len) {
     return buf.length();
 }
 
+/**
+manages initial communication setup including password queries
+*/
+int RsyncPlugin::establishConnectionUnison(char *buffer, KIO::fileoffset_t len, QString localfolder, QString remotepath) {
+    QString buf;
+    buf.setLatin1(buffer,len);
+    int pos;
+    // Strip trailing whitespace
+    while (buf.length() && (buf[buf.length()-1] == ' '))
+       buf.truncate(buf.length()-1);
+
+    myDebug( << "establishing: got " << buf << endl);
+    while (childPid && (((pos = buf.find('\n')) >= 0) || buf.endsWith(":") || buf.endsWith("?") || buf.endsWith("]"))) {
+        if (m_progressDialogExists == true) {
+            qApp->processEvents();
+        }
+        pos++;
+        QString str = buf.left(pos);
+        buf = buf.mid(pos);
+        if (str == "\n")
+            continue;
+        //if (str.contains("rsync error:")) {
+        if (str.contains("rsync:") || str.contains("failed.") || (str.contains("Could not") && str.endsWith("."))) {
+            KMessageBox::error(NULL, str);
+        }
+        else if (!str.isEmpty()) {
+            thisFn += str;
+            if ((buf.endsWith(":") == false) && (buf.endsWith("?") == false)) {
+                // Display a nice little progress bar with text box
+                if (m_progressDialogExists == false) {
+                    m_progressDialog = new KProgressBoxDialog(0, "rsyncProgress", i18n("Synchronizing Folder..."), i18n("Synchronizing Folder..."), true);
+                    m_progressDialog->progressBar()->setFormat("%v / %m");
+                    m_progressDialog->progressBar()->setTotalSteps(0);
+                    m_progressDialog->setAutoClose(true);
+                    connect (m_progressDialog, SIGNAL(cancelClicked()), SLOT(slotUnisonCancelled()));
+                    m_progressDialog->show();
+                    m_progressDialogExists = true;
+                }
+            }
+        }
+        else if (buf.endsWith(":")) {
+            if (!redirectUser.isEmpty() && connectionUser != redirectUser) {
+               // FIXME: Possibly do something here; is this the success response?
+                return -1;
+            } else if (!connectionPassword.isEmpty()) {
+                myDebug( << "sending cpass" << endl);
+                connectionAuth.password = connectionPassword+"\n";
+                connectionPassword = QString::null;
+                writeChild(connectionAuth.password.latin1(),connectionAuth.password.length());
+            } else {
+                myDebug( << "sending mpass" << endl);
+                connectionAuth.prompt = thisFn+buf;
+                connectionAuth.password = QString::null; // don't prefill
+                QCString thispass;
+                if (KPasswordDialog::getPassword (thispass, i18n("Remote authorization required") + QString("\n") + i18n("Please input") + QString(" ") + QString(buf), NULL) != 1) {
+                    slotUnisonCancelled();
+                    return -1;
+                }
+                else {
+                    connectionAuth.password = QString(thispass);
+                }
+                connectionAuth.password += "\n";
+                myDebug( << "sending pass" << endl);
+                writeChild(connectionAuth.password.latin1(),connectionAuth.password.length());
+            }
+            thisFn = QString::null;
+            return 0;
+        }
+        else if (buf.endsWith("?") || buf.endsWith("? []")) {
+            buf.replace("[]", "");
+            if (buf.endsWith("? []")) {
+                int rc = KMessageBox::questionYesNo(NULL, buf);
+                if (rc == KMessageBox::Yes) {
+                    writeChild("y\n",3);
+                } else {
+                    writeChild("n\n",3);
+                }
+            }
+            else {
+                int rc = KMessageBox::questionYesNo(NULL, buf);
+                if (rc == KMessageBox::Yes) {
+                    writeChild("yes\n",4);
+                } else {
+                    writeChild("no\n",3);
+                }
+            }
+            thisFn = QString::null;
+            buf = "";
+            return 0;
+        }
+        else if (buf.endsWith("]")) {
+            if (m_progressDialogExists == true) {
+                m_progressDialog->textEdit()->append(buf);
+                m_progressDialog->textEdit()->scrollToBottom();
+                int currentPos;
+                currentPos = m_progressDialog->progressBar()->progress();
+                m_progressDialog->progressBar()->setProgress(++currentPos);
+            }
+            QString file_name;
+            file_name = buf;
+            file_name.replace("[]", "");
+            file_name.replace(QString("changed "), "");
+            //file_name = file_name.simplifyWhiteSpace();
+            KDialogBase *dialog= new KDialogBase(i18n("User Intervention Required"), KDialogBase::Yes | KDialogBase::No | KDialogBase::Cancel, KDialogBase::Yes, KDialogBase::Cancel, NULL, "warningYesNoCancel", true, true, i18n("Use &Local File"), i18n("Use &Remote File"), i18n("&Ignore"));
+            int rc = KMessageBox::createKMessageBox(dialog, QMessageBox::Warning, QString("<b>") + i18n("WARNING: Both the local and remote file have been modified") + QString("</b><p>") + i18n("Local") + QString(": ") + localfolder + QString("/") + file_name + QString("<br>") + i18n("Remote") + QString(": ") + remotepath + QString("/") + file_name + QString("<p>") + i18n("Please select the file to duplicate (the other will be overwritten)") + QString("<br>") + i18n("Or, select Ignore to skip synchronization of this file for now"), QStringList(), QString::null, NULL, 1);
+            if (rc == KDialogBase::Yes) {
+                writeChild(">\n",3);
+            }
+            else if (rc == KDialogBase::No) {
+                writeChild("<\n",3);
+            }
+            else {
+                writeChild("/\n",3);
+            }
+            return 0;
+        }
+
+        if (m_progressDialogExists == true) {
+            if (str.contains("exit()") && str.contains("ICE default IO")) {
+                if (m_progressDialogExists == true) {
+                    m_progressDialog->progressBar()->setFormat("%v / %m");
+                    m_progressDialog->progressBar()->setTotalSteps(2);
+                    m_progressDialog->progressBar()->setValue(m_progressDialog->progressBar()->totalSteps());
+                }
+            }
+            else {
+                m_progressDialog->textEdit()->append(str);
+                m_progressDialog->textEdit()->scrollToBottom();
+                int currentPos;
+                currentPos = m_progressDialog->progressBar()->progress();
+                m_progressDialog->progressBar()->setProgress(++currentPos);
+            }
+        }
+    }
+    return buf.length();
+}
+
 /**
 Forced close of the connection
 
@@ -879,6 +1021,17 @@ void RsyncPlugin::slotRsyncCancelled()
 	m_pSyncNow->setEnabled (true);
 }
 
+void RsyncPlugin::slotUnisonCancelled()
+{
+        shutdownConnection(true, true);
+        if (m_progressDialogExists == true) {
+            m_progressDialog->progressBar()->setFormat("%v / %m");
+            m_progressDialog->progressBar()->setTotalSteps(2);
+            m_progressDialog->progressBar()->setValue(m_progressDialog->progressBar()->totalSteps());
+        }
+	m_pSyncNow->setEnabled (true);
+}
+
 void RsyncPlugin::slotSync()
 {
 	if (!m_part)
@@ -899,10 +1052,10 @@ void RsyncPlugin::slotSync()
  	else if (syncmethod == "rsync_download") {
  		syncUnidirectional(QString("rsync"), QString(" -avtzAXE --delete --progress "), 1, url.directory(true, true) + QString("/") + url.fileName(true), findLocalFolderByName(url.directory(true, true) + QString("/") + url.fileName(true)));
  	}
-// 	else if (syncmethod == "rsync_bidirectional") {
-// 		syncint = 3;
-// 	}
-	
+ 	else if (syncmethod == "rsync_bidirectional") {
+ 		syncBidirectional(QString("unison"), QString(" -ui text -auto "), 1, url.directory(true, true) + QString("/") + url.fileName(true), findLocalFolderByName(url.directory(true, true) + QString("/") + url.fileName(true)));
+ 	}
+
 	m_progressDialogExists = false;
 	m_pSyncNow->setEnabled (true);
 }
diff --git a/konq-plugins/rsync/rsyncplugin.h b/konq-plugins/rsync/rsyncplugin.h
index 4deb2b3..86aa17f 100644
--- a/konq-plugins/rsync/rsyncplugin.h
+++ b/konq-plugins/rsync/rsyncplugin.h
@@ -65,11 +65,13 @@ protected:
   int addLocalFolderByName(QString folderurl, QString remoteurl, QString syncmethod, QString excludelist);
   QString findSyncMethodByName(QString folderurl);
   /** manages initial communication setup including password queries */
-  int establishConnection(char *buffer, KIO::fileoffset_t len);
+  int establishConnectionRsync(char *buffer, KIO::fileoffset_t len);
+  /** manages initial communication setup including password queries */
+  int establishConnectionUnison(char *buffer, KIO::fileoffset_t len, QString localfolder, QString remotepath);
   /** creates the unidirectional sync subprocess */
   bool syncUnidirectional(QString synccommand, QString syncflags, int parameter_order, QString localfolder, QString remotepath);
   /** creates the bidirectional sync subprocess */
-  bool syncBidirectional(QString localfolder, QString remotepath);
+  bool syncBidirectional(QString synccommand, QString syncflags, int parameter_order, 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 */
@@ -89,6 +91,7 @@ private slots:
   void slotSetupOK();
   void slotSetupCancelled();
   void slotRsyncCancelled();
+  void slotUnisonCancelled();
 
 private:
   KURL m_pURL;
-- 
cgit v1.2.3

