← Back to team overview

syncany-team team mailing list archive

[Merge] lp:~mcuelenaere/syncany/trunk into lp:syncany

 

mcuelenaere has proposed merging lp:~mcuelenaere/syncany/trunk into lp:syncany.

Requested reviews:
  Syncany Team (syncany-team)

For more details, see:
https://code.launchpad.net/~mcuelenaere/syncany/trunk/+merge/92642

Adds some minor fixes + Dropbox plugin
-- 
https://code.launchpad.net/~mcuelenaere/syncany/trunk/+merge/92642
Your team Syncany Team is requested to review the proposed merge of lp:~mcuelenaere/syncany/trunk into lp:syncany.
=== modified file 'syncany/README'
--- syncany/README	2011-06-10 18:44:48 +0000
+++ syncany/README	2012-02-11 23:28:18 +0000
@@ -62,3 +62,7 @@
 - The Syncany Rackspace plugin uses the java-cloudfiles library provided by
   Rackspace (https://github.com/rackspace/java-cloudfiles). It is distributed
   under the GPL-compatible MIT License.
+
+- The Dropbox plugin uses the SDK provided by Dropbox
+  (https://www.dropbox.com/developers/reference/sdk). It is distributed under
+  the GPL-compatible MIT License.

=== modified file 'syncany/build.xml'
--- syncany/build.xml	2011-06-05 20:06:20 +0000
+++ syncany/build.xml	2012-02-11 23:28:18 +0000
@@ -163,7 +163,11 @@
             </fileset>			
 		</copy>
 	</target>	
-    
+
+        <target name="run" depends="compile" if="isLinux">
+            <exec dir="bin" executable="./syncany.sh" />
+        </target>
+
     <!--
 
     There exist several targets which are by default empty and which can be 

=== added directory 'syncany/lib/plugins/dropbox'
=== added file 'syncany/lib/plugins/dropbox/dropbox-java-sdk-1.2.3.jar'
Binary files syncany/lib/plugins/dropbox/dropbox-java-sdk-1.2.3.jar	1970-01-01 00:00:00 +0000 and syncany/lib/plugins/dropbox/dropbox-java-sdk-1.2.3.jar	2012-02-11 23:28:18 +0000 differ
=== added file 'syncany/lib/plugins/dropbox/httpmime-4.0.3.jar'
Binary files syncany/lib/plugins/dropbox/httpmime-4.0.3.jar	1970-01-01 00:00:00 +0000 and syncany/lib/plugins/dropbox/httpmime-4.0.3.jar	2012-02-11 23:28:18 +0000 differ
=== added file 'syncany/lib/plugins/dropbox/json_simple-1.1.jar'
Binary files syncany/lib/plugins/dropbox/json_simple-1.1.jar	1970-01-01 00:00:00 +0000 and syncany/lib/plugins/dropbox/json_simple-1.1.jar	2012-02-11 23:28:18 +0000 differ
=== modified file 'syncany/nbproject/project.properties'
--- syncany/nbproject/project.properties	2011-06-05 21:47:40 +0000
+++ syncany/nbproject/project.properties	2012-02-11 23:28:18 +0000
@@ -34,6 +34,7 @@
 excludes=
 file.reference.AbsoluteLayout.jar=lib/AbsoluteLayout.jar
 file.reference.AppFramework-1.03.jar=lib/AppFramework-1.03.jar
+file.reference.bcprov-jdk16-146.jar=lib/bcprov-jdk16-146.jar
 file.reference.box4j-1.4.0.jar=lib/plugins/box/box4j-1.4.0.jar
 file.reference.commons-cli-1.2.jar=lib/commons-cli-1.2.jar
 file.reference.commons-codec-1.4.jar=lib/commons-codec-1.4.jar
@@ -45,6 +46,7 @@
 file.reference.commons-vfs-1.0.jar=lib/commons-vfs-1.0.jar
 file.reference.derby-10.8.1.2.jar=lib/derby-10.8.1.2.jar
 file.reference.dom4j-1.6.1.jar=lib/dom4j-1.6.1.jar
+file.reference.dropbox-java-sdk-1.2.3.jar=lib/plugins/dropbox/dropbox-java-sdk-1.2.3.jar
 file.reference.eclipselink-2.2.0.jar=lib/eclipselink-2.2.0.jar
 file.reference.eclipselink-javax.persistence-2.0.jar=lib/eclipselink-javax.persistence-2.0.jar
 file.reference.gdata-client-1.0.jar=lib/plugins/picasa/gdata-client-1.0.jar
@@ -55,6 +57,7 @@
 file.reference.guava-r09.jar=lib/plugins/picasa/guava-r09.jar
 file.reference.httpclient-4.0.3.jar=lib/httpclient-4.0.3.jar
 file.reference.httpcore-4.1.jar=lib/httpcore-4.1.jar
+file.reference.httpmime-4.0.3.jar=lib/plugins/dropbox/httpmime-4.0.3.jar
 file.reference.inotify-java-recursive-source=../inotify-java-recursive/source
 file.reference.j2ssh-core-0.2.9.jar=lib/plugins/sftp/j2ssh-core-0.2.9.jar
 file.reference.java-cloudfiles.jar=lib/plugins/rackspace/java-cloudfiles.jar
@@ -66,6 +69,7 @@
 file.reference.jets3t-0.8.1.jar-1=lib/plugins/shared/jets3t-0.8.1.jar
 file.reference.jpathwatch-0-94-libs-only.jar=lib/jpathwatch-0-94-libs-only.jar
 file.reference.jsch-0.1.44.jar=lib/jsch-0.1.44.jar
+file.reference.json_simple-1.1.jar=lib/plugins/dropbox/json_simple-1.1.jar
 file.reference.log4j-1.2.jar=lib/log4j-1.2.jar
 file.reference.mx4j-3.0.2.jar=lib/mx4j-3.0.2.jar
 file.reference.mysql-connector-java-5.1.13-bin.jar=lib/mysql-connector-java-5.1.13-bin.jar
@@ -73,6 +77,7 @@
 file.reference.rabin-hash-function-2.0.jar=lib/rabin-hash-function-2.0.jar
 file.reference.sardine.jar=lib/plugins/webdav/sardine.jar
 file.reference.source-java=../inotify-java-recursive/source/java
+file.reference.SSHTools-j2ssh-ext-0.1.0.jar=lib/plugins/sftp/SSHTools-j2ssh-ext-0.1.0.jar
 file.reference.swing-layout-1.0.4.jar=lib/swing-layout-1.0.4.jar
 file.reference.swing-worker-1.1.jar=lib/swing-worker-1.1.jar
 includes=**
@@ -120,8 +125,11 @@
     ${file.reference.rabin-hash-function-2.0.jar}:\
     ${file.reference.swing-layout-1.0.4.jar}:\
     ${file.reference.swing-worker-1.1.jar}:\
+    ${file.reference.dropbox-java-sdk-1.2.3.jar}:\
     ${file.reference.bcprov-jdk16-146.jar}:\
     ${file.reference.SSHTools-j2ssh-ext-0.1.0.jar}:\
+    ${file.reference.httpmime-4.0.3.jar}:\
+    ${file.reference.json_simple-1.1.jar}:\
     ${file.reference.jsch-0.1.44.jar}
 # Space-separated list of extra javac options
 javac.compilerargs=

=== added directory 'syncany/src/org/syncany/connection/plugins/dropbox'
=== added file 'syncany/src/org/syncany/connection/plugins/dropbox/DropboxConfigPanel.form'
--- syncany/src/org/syncany/connection/plugins/dropbox/DropboxConfigPanel.form	1970-01-01 00:00:00 +0000
+++ syncany/src/org/syncany/connection/plugins/dropbox/DropboxConfigPanel.form	2012-02-11 23:28:18 +0000
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+    <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,0,56,0,0,0,-34"/>
+  </AuxValues>
+
+  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
+    <Property name="axis" type="int" value="1"/>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JLabel" name="lblStatus">
+      <Properties>
+        <Property name="horizontalAlignment" type="int" value="2"/>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+          <Connection code="resourceBundle.getString(&quot;dropbox_begin_auth&quot;)" type="code"/>
+        </Property>
+        <Property name="name" type="java.lang.String" value="lblStatus" noResource="true"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JButton" name="btnAuthenticate">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+          <Connection code="resourceBundle.getString(&quot;dropbox_btn_authenticate&quot;)" type="code"/>
+        </Property>
+        <Property name="name" type="java.lang.String" value="btnAuthenticate"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnAuthenticateActionPerformed"/>
+      </Events>
+    </Component>
+  </SubComponents>
+</Form>

=== added file 'syncany/src/org/syncany/connection/plugins/dropbox/DropboxConfigPanel.java'
--- syncany/src/org/syncany/connection/plugins/dropbox/DropboxConfigPanel.java	1970-01-01 00:00:00 +0000
+++ syncany/src/org/syncany/connection/plugins/dropbox/DropboxConfigPanel.java	2012-02-11 23:28:18 +0000
@@ -0,0 +1,126 @@
+/*
+ * Syncany, www.syncany.org
+ * Copyright (C) 2012 Maurus Cuelenaere<mcuelenaere@xxxxxxxxx>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.syncany.connection.plugins.dropbox;
+
+import java.awt.Desktop;
+import java.net.URI;
+import java.util.ResourceBundle;
+import javax.swing.JOptionPane;
+import org.syncany.config.Config;
+import org.syncany.connection.plugins.ConfigPanel;
+import org.syncany.connection.plugins.dropbox.DropboxConnection.DropboxAuthentication;
+
+/**
+ * @author Maurus Cuelenaere <mcuelenaere@xxxxxxxxx>
+ */
+public class DropboxConfigPanel extends ConfigPanel {
+    private ResourceBundle resourceBundle;
+    private DropboxAuthentication pendingAuthentication;
+
+    public DropboxConfigPanel(DropboxConnection connection) {
+        super(connection);
+        resourceBundle = Config.getInstance().getResourceBundle();
+	    initComponents();
+    }
+
+    @Override
+    public void load() {
+        if (getConnection().isAuthenticated()) {
+            lblStatus.setText(resourceBundle.getString("dropbox_auth_success"));
+            btnAuthenticate.setText(resourceBundle.getString("dropbox_btn_reauthenticate"));
+        } else {
+            lblStatus.setText(resourceBundle.getString("dropbox_begin_auth"));
+            btnAuthenticate.setText(resourceBundle.getString("dropbox_btn_authenticate"));
+        }
+    }
+
+    @Override
+    public void save() {
+        // do nothing
+    }
+
+    @Override
+    public DropboxConnection getConnection() {
+        return (DropboxConnection) super.getConnection();
+    }       
+
+    private void browseUrl(String url) {
+        try {
+            Desktop.getDesktop().browse(new URI(url));
+        } catch (Exception ex) {
+            // fallback
+            JOptionPane.showInputDialog(this, resourceBundle.getString("dropbox_browse_url"), url);
+        }
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        lblStatus = new javax.swing.JLabel();
+        btnAuthenticate = new javax.swing.JButton();
+
+        setLayout(new javax.swing.BoxLayout(this, javax.swing.BoxLayout.Y_AXIS));
+
+        lblStatus.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
+        lblStatus.setText(resourceBundle.getString("dropbox_begin_auth"));
+        lblStatus.setName("lblStatus"); // NOI18N
+        add(lblStatus);
+
+        btnAuthenticate.setText(resourceBundle.getString("dropbox_btn_authenticate"));
+        btnAuthenticate.setName("btnAuthenticate");
+        btnAuthenticate.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                btnAuthenticateActionPerformed(evt);
+            }
+        });
+        add(btnAuthenticate);
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void btnAuthenticateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAuthenticateActionPerformed
+        if (pendingAuthentication != null) {
+            boolean result = pendingAuthentication.complete();
+            pendingAuthentication = null;
+
+            if (result) {
+                btnAuthenticate.setText(resourceBundle.getString("dropbox_btn_reauthenticate"));
+                lblStatus.setText(resourceBundle.getString("dropbox_auth_success"));
+            } else {
+                btnAuthenticate.setText(resourceBundle.getString("dropbox_btn_authenticate"));
+                lblStatus.setText(resourceBundle.getString("dropbox_auth_fail"));
+            }
+        } else {
+            pendingAuthentication = getConnection().authenticate();
+
+            browseUrl(pendingAuthentication.getUrl());
+
+            lblStatus.setText(resourceBundle.getString("dropbox_awaiting_auth"));
+            btnAuthenticate.setText(resourceBundle.getString("dropbox_btn_complete_authentication"));
+        }
+    }//GEN-LAST:event_btnAuthenticateActionPerformed
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton btnAuthenticate;
+    private javax.swing.JLabel lblStatus;
+    // End of variables declaration//GEN-END:variables
+}

=== added file 'syncany/src/org/syncany/connection/plugins/dropbox/DropboxConnection.java'
--- syncany/src/org/syncany/connection/plugins/dropbox/DropboxConnection.java	1970-01-01 00:00:00 +0000
+++ syncany/src/org/syncany/connection/plugins/dropbox/DropboxConnection.java	2012-02-11 23:28:18 +0000
@@ -0,0 +1,121 @@
+/*
+ * Syncany, www.syncany.org
+ * Copyright (C) 2012 Maurus Cuelenaere<mcuelenaere@xxxxxxxxx>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.syncany.connection.plugins.dropbox;
+
+import com.dropbox.client2.exception.DropboxException;
+import com.dropbox.client2.session.AccessTokenPair;
+import com.dropbox.client2.session.AppKeyPair;
+import com.dropbox.client2.session.Session;
+import com.dropbox.client2.session.WebAuthSession;
+import com.dropbox.client2.session.WebAuthSession.WebAuthInfo;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.syncany.config.ConfigNode;
+import org.syncany.connection.plugins.ConfigPanel;
+import org.syncany.connection.plugins.Connection;
+import org.syncany.connection.plugins.PluginInfo;
+import org.syncany.connection.plugins.TransferManager;
+import org.syncany.exceptions.ConfigException;
+
+/**
+ * @author Maurus Cuelenaere <mcuelenaere@xxxxxxxxx>
+ */
+public class DropboxConnection implements Connection {
+    private static final AppKeyPair APP_KEY = new AppKeyPair("<FILLME>", "<FILLME>");
+    private static final Logger logger = Logger.getLogger(DropboxConnection.class.getSimpleName());
+
+    private WebAuthSession authSession;
+
+    public DropboxConnection() {
+        authSession = new WebAuthSession(APP_KEY, Session.AccessType.APP_FOLDER);
+    }
+
+    public WebAuthSession getAuthSession() {
+        return authSession;
+    }
+
+    public boolean isAuthenticated() {
+        return authSession.getAccessTokenPair() != null;
+    }
+
+    public class DropboxAuthentication {
+        private final WebAuthInfo authInfo;
+
+        public DropboxAuthentication() throws DropboxException {
+            authInfo = authSession.getAuthInfo();
+        }
+
+        public String getUrl() {
+            return authInfo.url;
+        }
+
+        public boolean complete() {
+            try {
+                authSession.retrieveWebAccessToken(authInfo.requestTokenPair);
+                return true;
+            } catch (DropboxException ex) {
+                logger.log(Level.WARNING, "Couldn't complete Dropbox authentication", ex);
+                return false;
+            }
+        }
+    }
+
+    public DropboxAuthentication authenticate() {
+        try {
+            return new DropboxAuthentication();
+        } catch (DropboxException ex) {
+            logger.log(Level.WARNING, "Couldn't start Dropbox authentication", ex);
+            return null;
+        }
+    }
+
+    @Override
+    public TransferManager createTransferManager() {
+        return new DropboxTransferManager(this);
+    }
+
+    @Override
+    public ConfigPanel createConfigPanel() {
+        return new DropboxConfigPanel(this);
+    }
+
+    @Override
+    public PluginInfo getPluginInfo() {
+        return new DropboxPluginInfo();
+    }
+
+    @Override
+    public void load(ConfigNode node) throws ConfigException {
+        String key = node.getProperty("accessKey");
+        String secret = node.getProperty("accessSecret");
+
+        if (key == null || secret == null)
+            throw new ConfigException("Dropbox connection properties must at least contain the parameters 'accessKey' and 'accessSecret'.");
+
+        authSession.setAccessTokenPair(new AccessTokenPair(key, secret));
+    }
+
+    @Override
+    public void save(ConfigNode node) {
+        AccessTokenPair tokenPair = authSession.getAccessTokenPair();
+
+        node.setAttribute("type", getPluginInfo().getId());
+        node.setProperty("accessKey", tokenPair.key);
+        node.setProperty("accessSecret", tokenPair.secret);
+    }
+}
\ No newline at end of file

=== added file 'syncany/src/org/syncany/connection/plugins/dropbox/DropboxPluginInfo.java'
--- syncany/src/org/syncany/connection/plugins/dropbox/DropboxPluginInfo.java	1970-01-01 00:00:00 +0000
+++ syncany/src/org/syncany/connection/plugins/dropbox/DropboxPluginInfo.java	2012-02-11 23:28:18 +0000
@@ -0,0 +1,57 @@
+/*
+ * Syncany, www.syncany.org
+ * Copyright (C) 2012 Maurus Cuelenaere<mcuelenaere@xxxxxxxxx>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.syncany.connection.plugins.dropbox;
+
+import java.util.ResourceBundle;
+import org.syncany.config.Config;
+import org.syncany.connection.plugins.Connection;
+import org.syncany.connection.plugins.PluginInfo;
+
+/**
+ * @author Maurus Cuelenaere <mcuelenaere@xxxxxxxxx>
+ */
+public class DropboxPluginInfo extends PluginInfo {
+    public static final String ID = "dropbox";
+
+    private ResourceBundle resourceBundle = Config.getInstance().getResourceBundle();
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+    @Override
+    public String getName() {
+        return resourceBundle.getString("dropbox_plugin_name");
+    }
+
+    @Override
+    public Integer[] getVersion() {
+        return new Integer[] {0, 1};
+    }
+
+    @Override
+    public String getDescripton() {
+        return resourceBundle.getString("dropbox_plugin_description");
+    }
+
+    @Override
+    public Connection createConnection() {
+        return new DropboxConnection();
+    }
+}

=== added file 'syncany/src/org/syncany/connection/plugins/dropbox/DropboxTransferManager.java'
--- syncany/src/org/syncany/connection/plugins/dropbox/DropboxTransferManager.java	1970-01-01 00:00:00 +0000
+++ syncany/src/org/syncany/connection/plugins/dropbox/DropboxTransferManager.java	2012-02-11 23:28:18 +0000
@@ -0,0 +1,145 @@
+/*
+ * Syncany, www.syncany.org
+ * Copyright (C) 2012 Maurus Cuelenaere<mcuelenaere@xxxxxxxxx>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.syncany.connection.plugins.dropbox;
+
+import com.dropbox.client2.DropboxAPI;
+import com.dropbox.client2.exception.DropboxException;
+import com.dropbox.client2.exception.DropboxServerException;
+import com.dropbox.client2.session.WebAuthSession;
+import java.io.*;
+import java.util.HashMap;
+import java.util.Map;
+import org.syncany.connection.plugins.AbstractTransferManager;
+import org.syncany.exceptions.LocalFileNotFoundException;
+import org.syncany.exceptions.RemoteFileNotFoundException;
+import org.syncany.exceptions.StorageConnectException;
+import org.syncany.exceptions.StorageException;
+import org.syncany.repository.files.RemoteFile;
+
+/**
+ * @author Maurus Cuelenaere <mcuelenaere@xxxxxxxxx>
+ */
+public class DropboxTransferManager extends AbstractTransferManager {
+    private final DropboxAPI<WebAuthSession> api;
+    private String cachedListHash;
+    private Map<String, RemoteFile> cachedListResult;
+
+    public DropboxTransferManager(DropboxConnection connection) {
+        super(connection);
+
+        api = new DropboxAPI<WebAuthSession>(connection.getAuthSession());
+    }
+
+    @Override
+    public void connect() throws StorageConnectException {
+    }
+
+    @Override
+    public void disconnect() throws StorageException {
+    }
+
+    @Override
+    public void download(RemoteFile remoteFile, File localFile) throws RemoteFileNotFoundException, StorageException {
+        String name = "/" + remoteFile.getName();
+        OutputStream out = null;
+        try {
+            out = new FileOutputStream(localFile);
+            api.getFile(name, null, out, null);
+        } catch (Exception ex) {
+            if (ex instanceof DropboxServerException) {
+                DropboxServerException sex = (DropboxServerException) ex;
+                if (sex.error == 404)
+                    throw new RemoteFileNotFoundException(ex);
+            }
+
+            throw new StorageException(ex);
+        } finally {
+            if (out != null) {
+                try {
+                    out.close();
+                } catch (IOException ex) {
+                    throw new StorageException(ex);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void upload(File localFile, RemoteFile remoteFile) throws LocalFileNotFoundException, StorageException {
+        if (!localFile.exists())
+            throw new LocalFileNotFoundException();
+
+        String name = "/" + remoteFile.getName();
+        InputStream in = null;
+        try {
+            in = new FileInputStream(localFile);
+            api.putFile(name, in, localFile.length(), null, null);
+        } catch (Exception ex) {
+            throw new StorageException(ex);
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException ex) {
+                    throw new StorageException(ex);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void delete(RemoteFile remoteFile) throws RemoteFileNotFoundException, StorageException {
+        try {
+            api.delete(remoteFile.getName());
+        } catch (DropboxException ex) {
+            throw new StorageException(ex);
+        }
+    }
+
+    @Override
+    public Map<String, RemoteFile> list() throws StorageException {
+        try {
+            Map<String, RemoteFile> result = new HashMap<String, RemoteFile>();
+            DropboxAPI.Entry entry = api.metadata("", 0, cachedListHash, true, null);
+            assert(!entry.isDir);
+
+            for (DropboxAPI.Entry child : entry.contents) {
+                if (child.isDeleted || child.isDir)
+                    continue;
+
+                String name = child.path.substring(1); // skip the first slash
+                RemoteFile file = new RemoteFile(name, child.bytes);
+                result.put(name, file);
+            }
+
+            // update cache
+            cachedListHash = entry.hash;
+            cachedListResult = result;
+
+            return result;
+        } catch (DropboxException ex) {
+            if (ex instanceof DropboxServerException) {
+                DropboxServerException sex = (DropboxServerException) ex;
+                if (sex.error == 304)
+                    return cachedListResult;
+            }
+
+            throw new StorageException(ex);
+        }
+    }
+}

=== modified file 'syncany/src/org/syncany/i18n/I18n_en_US.properties'
--- syncany/src/org/syncany/i18n/I18n_en_US.properties	2011-06-04 00:29:53 +0000
+++ syncany/src/org/syncany/i18n/I18n_en_US.properties	2012-02-11 23:28:18 +0000
@@ -290,3 +290,17 @@
 webdav_path = Path:
 webdav_name = WebDAV
 webdav_plugin_description = Uses a WebDAV folder as data repository.
+
+## DROPBOX PLUGIN
+## DROPBOX PLUGIN INFO
+dropbox_plugin_name = Dropbox
+dropbox_plugin_description = Uses Dropbox as data repository
+## DROPBOX PLUGIN CONFIG PANEL
+dropbox_auth_success = Authentication successfull!
+dropbox_auth_fail = Couldn't complete authentication!
+dropbox_begin_auth = Please start authentication
+dropbox_awaiting_auth = Awaiting authentication completion...
+dropbox_btn_authenticate = Authenticate
+dropbox_btn_reauthenticate = Re-authenticate
+dropbox_btn_complete_authentication = Complete authentication
+dropbox_browse_url = Browse to the following url:
\ No newline at end of file