Loading .travis.yml +14 −21 Original line number Diff line number Diff line Loading @@ -3,19 +3,12 @@ android: components: - build-tools-22.0.1 - android-19 - android-17 - android-14 - extra-android-support licenses: - 'android-sdk-license-5be876d5' - 'android-sdk-license-598b93a6' jdk: oraclejdk7 before_install: - echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI -c 20M - echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI -c 20M - emulator -avd test -no-skin -no-audio -no-window & - rm pom.xml - android update project -p . before_script: - chmod +x ./wait_for_emulator.sh - ./wait_for_emulator.sh script: Loading @@ -27,8 +20,8 @@ script: - ./gradlew clean build env: global: - secure: f4Kms/mzkYRG4Kp8k6hsvG3Y0ztbJnA2J79OBw3VdqJOKVTzwsxMd1Yh325YDYO7I4HeHxGXy0H4p3rAPzIWr/nrOJ4wmcDwQYDQtVjF7S1ARWsX51FrCEV6A9ec2LAqNCQ8ZC0SoGb+HsmpFCE3uKAxRQt+B5MzOZvKNcvYpMA= - secure: aF4U20Xlu/rfrbxCmoJAiGh1doYTAZ10UEDmajuinT+ZGSJLivuqD7DDY/00sI6IXWg+J1vL+7jJm4JSYusHPg38UHZ4q92k6RmZycW2ATUzZnGT54O5FRnY67MfVwgVpIMK9UOL/6NEciBHEjlIOL0wbKQiJB++1YtBZOQLGL4= - secure: N+ECSwNg8v2GsAFJ2y/tCiffauHDpN76zuFI2pDqf0fjmCtJZHu4BH5ArXBHjyHKmgn20a/8eZXcwJaH1HsJ80bo7vDJ2miShjGIQ90hPcdmUiB2XVJcew4f04CtvMDH5o7DRt4ykWArlbPL2rhVag0jotlSidolHBwRFnbDhDY= - secure: HxHoqnC8mauCKi87zlo7pQcSsSw0W5MtW+iUcB8T11quwTBgUPWIOmycXv2FcmwpST0E43Ct+dhE+mttm+6P+5PSB33HQNLq00hfTVIJ4ttcb/5eWW8MnP7L+kPK8d0EtfDG6GQto7QktaybeG4+sNKKD336ZlFfM7xgPtPv+tg= - secure: WQMw0ciloe8i2ApGhePhuTmmH8UgAV1Ri10C1qhUH9hVOJAr+/1X5A93VPYGrgJ2EH5MdiL6f2XMDCYAgb9efuvZIUKNE0J92xh8m/yRa8nAVWNBE0PBdS4+OycoHpIQfMcUghooERXjP4GUYd/ZwICvWA+sXdOYWDdKjODUgl4= - secure: QPxKT8vC7sm1b/hYJcfkQkLgpwNRBvVKk8S8S0t43mmqPJfs94FJTQHH4kZaGSwOeuDkRQbGuKzYtXOnGOKX2hhUBqKJd1idpJnUID8id8Kqo6VutjG017+XxZQp0hPHmfmDxYkDvlaLeoZpP2NkpwZ1p4TL2MSCr2Ibl6uTWvc= matrix: - ANDROID_TARGET=android-19 ANDROID_ABI=armeabi-v7a build.gradle +1 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ buildscript { classpath 'com.android.tools.build:gradle:1.2.3' } } apply plugin: 'com.android.library' repositories { Loading sample_client/build.gradle +5 −0 Original line number Diff line number Diff line Loading @@ -43,4 +43,9 @@ android { packagingOptions { exclude 'META-INF/LICENSE.txt' } android { lintOptions { abortOnError false } } } src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java +64 −64 Original line number Diff line number Diff line Loading @@ -33,8 +33,12 @@ import java.net.SocketException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; import java.util.ArrayList; import android.accounts.Account; import android.accounts.AccountsException; import javax.net.ssl.SSLException; import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException; import com.owncloud.android.lib.common.network.CertificateCombinedException; import com.owncloud.android.lib.common.utils.Log_OC; import org.apache.commons.httpclient.ConnectTimeoutException; import org.apache.commons.httpclient.Header; Loading @@ -43,17 +47,12 @@ import org.apache.commons.httpclient.HttpStatus; import org.apache.jackrabbit.webdav.DavException; import org.json.JSONException; import android.accounts.Account; import android.accounts.AccountsException; import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException; import com.owncloud.android.lib.common.network.CertificateCombinedException; import com.owncloud.android.lib.common.utils.Log_OC; import javax.net.ssl.SSLException; /** * The result of a remote operation required to an ownCloud server. * * <p/> * Provides a common classification of remote operation results for all the * application. * Loading @@ -62,7 +61,7 @@ import com.owncloud.android.lib.common.utils.Log_OC; public class RemoteOperationResult implements Serializable { /** Generated - should be refreshed every time the class changes!! */; private static final long serialVersionUID = -1909603208238358633L; private static final long serialVersionUID = 1129130415603799707L; private static final String TAG = RemoteOperationResult.class.getSimpleName(); Loading Loading @@ -105,7 +104,9 @@ public class RemoteOperationResult implements Serializable { SHARE_FORBIDDEN, OK_REDIRECT_TO_NON_SECURE_CONNECTION, INVALID_MOVE_INTO_DESCENDANT, INVALID_COPY_INTO_DESCENDANT, PARTIAL_MOVE_DONE, PARTIAL_COPY_DONE, INVALID_CHARACTER_DETECT_IN_SERVER } Loading Loading @@ -428,8 +429,7 @@ public class RemoteOperationResult implements Serializable { * @return boolean true/false */ public boolean isNonSecureRedirection() { return (mRedirectedLocation != null && !(mRedirectedLocation.toLowerCase().startsWith("https://"))); return (mRedirectedLocation != null && !(mRedirectedLocation.toLowerCase().startsWith("https://"))); } public String getAuthenticateHeader() { Loading src/com/owncloud/android/lib/resources/files/CopyRemoteFileOperation.java 0 → 100644 +215 −0 Original line number Diff line number Diff line /* ownCloud Android Library is available under MIT license * Copyright (C) 2014 ownCloud Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * */ package com.owncloud.android.lib.resources.files; import android.util.Log; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.network.WebdavUtils; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; import com.owncloud.android.lib.resources.status.OwnCloudVersion; import org.apache.commons.httpclient.HttpStatus; import org.apache.jackrabbit.webdav.DavException; import org.apache.jackrabbit.webdav.MultiStatusResponse; import org.apache.jackrabbit.webdav.Status; import org.apache.jackrabbit.webdav.client.methods.CopyMethod; import java.io.IOException; /** * Remote operation moving a remote file or folder in the ownCloud server to a different folder * in the same account. * <p/> * Allows renaming the moving file/folder at the same time. * * @author David A. Velasco */ public class CopyRemoteFileOperation extends RemoteOperation { private static final String TAG = CopyRemoteFileOperation.class.getSimpleName(); private static final int COPY_READ_TIMEOUT = 600000; private static final int COPY_CONNECTION_TIMEOUT = 5000; private String mSrcRemotePath; private String mTargetRemotePath; private boolean mOverwrite; /** * Constructor. * <p/> * TODO Paths should finish in "/" in the case of folders. ? * * @param srcRemotePath Remote path of the file/folder to move. * @param targetRemotePath Remove path desired for the file/folder after moving it. */ public CopyRemoteFileOperation(String srcRemotePath, String targetRemotePath, boolean overwrite ) { mSrcRemotePath = srcRemotePath; mTargetRemotePath = targetRemotePath; mOverwrite = overwrite; } /** * Performs the rename operation. * * @param client Client object to communicate with the remote ownCloud server. */ @Override protected RemoteOperationResult run(OwnCloudClient client) { OwnCloudVersion version = client.getOwnCloudVersion(); boolean versionWithForbiddenChars = (version != null && version.isVersionWithForbiddenCharacters()); /// check parameters if (!FileUtils.isValidPath(mTargetRemotePath, versionWithForbiddenChars)) { return new RemoteOperationResult(ResultCode.INVALID_CHARACTER_IN_NAME); } if (mTargetRemotePath.equals(mSrcRemotePath)) { // nothing to do! return new RemoteOperationResult(ResultCode.OK); } if (mTargetRemotePath.startsWith(mSrcRemotePath)) { return new RemoteOperationResult(ResultCode.INVALID_COPY_INTO_DESCENDANT); } /// perform remote operation CopyMethod copyMethod = null; RemoteOperationResult result = null; try { copyMethod = new CopyMethod( client.getWebdavUri() + WebdavUtils.encodePath(mSrcRemotePath), client.getWebdavUri() + WebdavUtils.encodePath(mTargetRemotePath), mOverwrite ); int status = client.executeMethod(copyMethod, COPY_READ_TIMEOUT, COPY_CONNECTION_TIMEOUT); /// process response if (status == HttpStatus.SC_MULTI_STATUS) { result = processPartialError(copyMethod); } else if (status == HttpStatus.SC_PRECONDITION_FAILED && !mOverwrite) { result = new RemoteOperationResult(ResultCode.INVALID_OVERWRITE); client.exhaustResponse(copyMethod.getResponseBodyAsStream()); /// for other errors that could be explicitly handled, check first: /// http://www.webdav.org/specs/rfc4918.html#rfc.section.9.9.4 } else if (status == 400) { result = new RemoteOperationResult(copyMethod.succeeded(), copyMethod.getResponseBodyAsString(), status); } else { result = new RemoteOperationResult( isSuccess(status), // copy.succeeded()? trustful? status, copyMethod.getResponseHeaders() ); client.exhaustResponse(copyMethod.getResponseBodyAsStream()); } Log.i(TAG, "Copy " + mSrcRemotePath + " to " + mTargetRemotePath + ": " + result.getLogMessage()); } catch (Exception e) { result = new RemoteOperationResult(e); Log.e(TAG, "Copy " + mSrcRemotePath + " to " + mTargetRemotePath + ": " + result.getLogMessage(), e); } finally { if (copyMethod != null) copyMethod.releaseConnection(); } return result; } /** * Analyzes a multistatus response from the OC server to generate an appropriate result. * <p/> * In WebDAV, a COPY request on collections (folders) can be PARTIALLY successful: some * children are copied, some other aren't. * <p/> * According to the WebDAV specification, a multistatus response SHOULD NOT include partial * successes (201, 204) nor for descendants of already failed children (424) in the response * entity. But SHOULD NOT != MUST NOT, so take carefully. * * @param copyMethod Copy operation just finished with a multistatus response * @return A result for the {@link com.owncloud.android.lib.resources.files.CopyRemoteFileOperation} caller * @throws java.io.IOException If the response body could not be parsed * @throws org.apache.jackrabbit.webdav.DavException If the status code is other than MultiStatus or if obtaining * the response XML document fails */ private RemoteOperationResult processPartialError(CopyMethod copyMethod) throws IOException, DavException { // Adding a list of failed descendants to the result could be interesting; or maybe not. // For the moment, let's take the easy way. /// check that some error really occurred MultiStatusResponse[] responses = copyMethod.getResponseBodyAsMultiStatus().getResponses(); Status[] status; boolean failFound = false; for (int i = 0; i < responses.length && !failFound; i++) { status = responses[i].getStatus(); failFound = ( status != null && status.length > 0 && status[0].getStatusCode() > 299 ); } RemoteOperationResult result; if (failFound) { result = new RemoteOperationResult(ResultCode.PARTIAL_COPY_DONE); } else { result = new RemoteOperationResult( true, HttpStatus.SC_MULTI_STATUS, copyMethod.getResponseHeaders() ); } return result; } protected boolean isSuccess(int status) { return status == HttpStatus.SC_CREATED || status == HttpStatus.SC_NO_CONTENT; } } Loading
.travis.yml +14 −21 Original line number Diff line number Diff line Loading @@ -3,19 +3,12 @@ android: components: - build-tools-22.0.1 - android-19 - android-17 - android-14 - extra-android-support licenses: - 'android-sdk-license-5be876d5' - 'android-sdk-license-598b93a6' jdk: oraclejdk7 before_install: - echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI -c 20M - echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI -c 20M - emulator -avd test -no-skin -no-audio -no-window & - rm pom.xml - android update project -p . before_script: - chmod +x ./wait_for_emulator.sh - ./wait_for_emulator.sh script: Loading @@ -27,8 +20,8 @@ script: - ./gradlew clean build env: global: - secure: f4Kms/mzkYRG4Kp8k6hsvG3Y0ztbJnA2J79OBw3VdqJOKVTzwsxMd1Yh325YDYO7I4HeHxGXy0H4p3rAPzIWr/nrOJ4wmcDwQYDQtVjF7S1ARWsX51FrCEV6A9ec2LAqNCQ8ZC0SoGb+HsmpFCE3uKAxRQt+B5MzOZvKNcvYpMA= - secure: aF4U20Xlu/rfrbxCmoJAiGh1doYTAZ10UEDmajuinT+ZGSJLivuqD7DDY/00sI6IXWg+J1vL+7jJm4JSYusHPg38UHZ4q92k6RmZycW2ATUzZnGT54O5FRnY67MfVwgVpIMK9UOL/6NEciBHEjlIOL0wbKQiJB++1YtBZOQLGL4= - secure: N+ECSwNg8v2GsAFJ2y/tCiffauHDpN76zuFI2pDqf0fjmCtJZHu4BH5ArXBHjyHKmgn20a/8eZXcwJaH1HsJ80bo7vDJ2miShjGIQ90hPcdmUiB2XVJcew4f04CtvMDH5o7DRt4ykWArlbPL2rhVag0jotlSidolHBwRFnbDhDY= - secure: HxHoqnC8mauCKi87zlo7pQcSsSw0W5MtW+iUcB8T11quwTBgUPWIOmycXv2FcmwpST0E43Ct+dhE+mttm+6P+5PSB33HQNLq00hfTVIJ4ttcb/5eWW8MnP7L+kPK8d0EtfDG6GQto7QktaybeG4+sNKKD336ZlFfM7xgPtPv+tg= - secure: WQMw0ciloe8i2ApGhePhuTmmH8UgAV1Ri10C1qhUH9hVOJAr+/1X5A93VPYGrgJ2EH5MdiL6f2XMDCYAgb9efuvZIUKNE0J92xh8m/yRa8nAVWNBE0PBdS4+OycoHpIQfMcUghooERXjP4GUYd/ZwICvWA+sXdOYWDdKjODUgl4= - secure: QPxKT8vC7sm1b/hYJcfkQkLgpwNRBvVKk8S8S0t43mmqPJfs94FJTQHH4kZaGSwOeuDkRQbGuKzYtXOnGOKX2hhUBqKJd1idpJnUID8id8Kqo6VutjG017+XxZQp0hPHmfmDxYkDvlaLeoZpP2NkpwZ1p4TL2MSCr2Ibl6uTWvc= matrix: - ANDROID_TARGET=android-19 ANDROID_ABI=armeabi-v7a
build.gradle +1 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ buildscript { classpath 'com.android.tools.build:gradle:1.2.3' } } apply plugin: 'com.android.library' repositories { Loading
sample_client/build.gradle +5 −0 Original line number Diff line number Diff line Loading @@ -43,4 +43,9 @@ android { packagingOptions { exclude 'META-INF/LICENSE.txt' } android { lintOptions { abortOnError false } } }
src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java +64 −64 Original line number Diff line number Diff line Loading @@ -33,8 +33,12 @@ import java.net.SocketException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; import java.util.ArrayList; import android.accounts.Account; import android.accounts.AccountsException; import javax.net.ssl.SSLException; import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException; import com.owncloud.android.lib.common.network.CertificateCombinedException; import com.owncloud.android.lib.common.utils.Log_OC; import org.apache.commons.httpclient.ConnectTimeoutException; import org.apache.commons.httpclient.Header; Loading @@ -43,17 +47,12 @@ import org.apache.commons.httpclient.HttpStatus; import org.apache.jackrabbit.webdav.DavException; import org.json.JSONException; import android.accounts.Account; import android.accounts.AccountsException; import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException; import com.owncloud.android.lib.common.network.CertificateCombinedException; import com.owncloud.android.lib.common.utils.Log_OC; import javax.net.ssl.SSLException; /** * The result of a remote operation required to an ownCloud server. * * <p/> * Provides a common classification of remote operation results for all the * application. * Loading @@ -62,7 +61,7 @@ import com.owncloud.android.lib.common.utils.Log_OC; public class RemoteOperationResult implements Serializable { /** Generated - should be refreshed every time the class changes!! */; private static final long serialVersionUID = -1909603208238358633L; private static final long serialVersionUID = 1129130415603799707L; private static final String TAG = RemoteOperationResult.class.getSimpleName(); Loading Loading @@ -105,7 +104,9 @@ public class RemoteOperationResult implements Serializable { SHARE_FORBIDDEN, OK_REDIRECT_TO_NON_SECURE_CONNECTION, INVALID_MOVE_INTO_DESCENDANT, INVALID_COPY_INTO_DESCENDANT, PARTIAL_MOVE_DONE, PARTIAL_COPY_DONE, INVALID_CHARACTER_DETECT_IN_SERVER } Loading Loading @@ -428,8 +429,7 @@ public class RemoteOperationResult implements Serializable { * @return boolean true/false */ public boolean isNonSecureRedirection() { return (mRedirectedLocation != null && !(mRedirectedLocation.toLowerCase().startsWith("https://"))); return (mRedirectedLocation != null && !(mRedirectedLocation.toLowerCase().startsWith("https://"))); } public String getAuthenticateHeader() { Loading
src/com/owncloud/android/lib/resources/files/CopyRemoteFileOperation.java 0 → 100644 +215 −0 Original line number Diff line number Diff line /* ownCloud Android Library is available under MIT license * Copyright (C) 2014 ownCloud Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * */ package com.owncloud.android.lib.resources.files; import android.util.Log; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.network.WebdavUtils; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; import com.owncloud.android.lib.resources.status.OwnCloudVersion; import org.apache.commons.httpclient.HttpStatus; import org.apache.jackrabbit.webdav.DavException; import org.apache.jackrabbit.webdav.MultiStatusResponse; import org.apache.jackrabbit.webdav.Status; import org.apache.jackrabbit.webdav.client.methods.CopyMethod; import java.io.IOException; /** * Remote operation moving a remote file or folder in the ownCloud server to a different folder * in the same account. * <p/> * Allows renaming the moving file/folder at the same time. * * @author David A. Velasco */ public class CopyRemoteFileOperation extends RemoteOperation { private static final String TAG = CopyRemoteFileOperation.class.getSimpleName(); private static final int COPY_READ_TIMEOUT = 600000; private static final int COPY_CONNECTION_TIMEOUT = 5000; private String mSrcRemotePath; private String mTargetRemotePath; private boolean mOverwrite; /** * Constructor. * <p/> * TODO Paths should finish in "/" in the case of folders. ? * * @param srcRemotePath Remote path of the file/folder to move. * @param targetRemotePath Remove path desired for the file/folder after moving it. */ public CopyRemoteFileOperation(String srcRemotePath, String targetRemotePath, boolean overwrite ) { mSrcRemotePath = srcRemotePath; mTargetRemotePath = targetRemotePath; mOverwrite = overwrite; } /** * Performs the rename operation. * * @param client Client object to communicate with the remote ownCloud server. */ @Override protected RemoteOperationResult run(OwnCloudClient client) { OwnCloudVersion version = client.getOwnCloudVersion(); boolean versionWithForbiddenChars = (version != null && version.isVersionWithForbiddenCharacters()); /// check parameters if (!FileUtils.isValidPath(mTargetRemotePath, versionWithForbiddenChars)) { return new RemoteOperationResult(ResultCode.INVALID_CHARACTER_IN_NAME); } if (mTargetRemotePath.equals(mSrcRemotePath)) { // nothing to do! return new RemoteOperationResult(ResultCode.OK); } if (mTargetRemotePath.startsWith(mSrcRemotePath)) { return new RemoteOperationResult(ResultCode.INVALID_COPY_INTO_DESCENDANT); } /// perform remote operation CopyMethod copyMethod = null; RemoteOperationResult result = null; try { copyMethod = new CopyMethod( client.getWebdavUri() + WebdavUtils.encodePath(mSrcRemotePath), client.getWebdavUri() + WebdavUtils.encodePath(mTargetRemotePath), mOverwrite ); int status = client.executeMethod(copyMethod, COPY_READ_TIMEOUT, COPY_CONNECTION_TIMEOUT); /// process response if (status == HttpStatus.SC_MULTI_STATUS) { result = processPartialError(copyMethod); } else if (status == HttpStatus.SC_PRECONDITION_FAILED && !mOverwrite) { result = new RemoteOperationResult(ResultCode.INVALID_OVERWRITE); client.exhaustResponse(copyMethod.getResponseBodyAsStream()); /// for other errors that could be explicitly handled, check first: /// http://www.webdav.org/specs/rfc4918.html#rfc.section.9.9.4 } else if (status == 400) { result = new RemoteOperationResult(copyMethod.succeeded(), copyMethod.getResponseBodyAsString(), status); } else { result = new RemoteOperationResult( isSuccess(status), // copy.succeeded()? trustful? status, copyMethod.getResponseHeaders() ); client.exhaustResponse(copyMethod.getResponseBodyAsStream()); } Log.i(TAG, "Copy " + mSrcRemotePath + " to " + mTargetRemotePath + ": " + result.getLogMessage()); } catch (Exception e) { result = new RemoteOperationResult(e); Log.e(TAG, "Copy " + mSrcRemotePath + " to " + mTargetRemotePath + ": " + result.getLogMessage(), e); } finally { if (copyMethod != null) copyMethod.releaseConnection(); } return result; } /** * Analyzes a multistatus response from the OC server to generate an appropriate result. * <p/> * In WebDAV, a COPY request on collections (folders) can be PARTIALLY successful: some * children are copied, some other aren't. * <p/> * According to the WebDAV specification, a multistatus response SHOULD NOT include partial * successes (201, 204) nor for descendants of already failed children (424) in the response * entity. But SHOULD NOT != MUST NOT, so take carefully. * * @param copyMethod Copy operation just finished with a multistatus response * @return A result for the {@link com.owncloud.android.lib.resources.files.CopyRemoteFileOperation} caller * @throws java.io.IOException If the response body could not be parsed * @throws org.apache.jackrabbit.webdav.DavException If the status code is other than MultiStatus or if obtaining * the response XML document fails */ private RemoteOperationResult processPartialError(CopyMethod copyMethod) throws IOException, DavException { // Adding a list of failed descendants to the result could be interesting; or maybe not. // For the moment, let's take the easy way. /// check that some error really occurred MultiStatusResponse[] responses = copyMethod.getResponseBodyAsMultiStatus().getResponses(); Status[] status; boolean failFound = false; for (int i = 0; i < responses.length && !failFound; i++) { status = responses[i].getStatus(); failFound = ( status != null && status.length > 0 && status[0].getStatusCode() > 299 ); } RemoteOperationResult result; if (failFound) { result = new RemoteOperationResult(ResultCode.PARTIAL_COPY_DONE); } else { result = new RemoteOperationResult( true, HttpStatus.SC_MULTI_STATUS, copyMethod.getResponseHeaders() ); } return result; } protected boolean isSuccess(int status) { return status == HttpStatus.SC_CREATED || status == HttpStatus.SC_NO_CONTENT; } }