mirror of
https://github.com/owncloud/android-library.git
synced 2025-06-07 16:06:08 +00:00
Compare commits
50 Commits
master
...
2.0-beta.1
Author | SHA1 | Date | |
---|---|---|---|
|
5a8f267325 | ||
|
a01829870d | ||
|
b2b5af9a69 | ||
|
01c4f52104 | ||
|
c69c2144be | ||
|
2f0c5a8f1a | ||
|
84996b410b | ||
|
08d75d347b | ||
|
39cdd109f0 | ||
|
dbe516edf4 | ||
|
0de5cd0b38 | ||
|
c6b41e42c5 | ||
|
fa2ea6e415 | ||
|
20cae87245 | ||
|
5bb0e56b61 | ||
|
cf5831d7da | ||
|
2314e41cbb | ||
|
e5fc25c3ae | ||
|
2c75099a95 | ||
|
61314fe6d9 | ||
|
13abe1135f | ||
|
03b314c4a2 | ||
|
49c1ec1be9 | ||
|
ad56db8d66 | ||
|
e68d3a6112 | ||
|
19710f9975 | ||
|
49a298cfc4 | ||
|
dbc42c3e4c | ||
|
94eafae901 | ||
|
8ea70d77fa | ||
|
0d4d73eee0 | ||
|
967e629559 | ||
|
86eb5fdf70 | ||
|
bfade365d9 | ||
|
e3e2569114 | ||
|
9d39235693 | ||
|
82abe5fdaa | ||
|
96c8e87a5f | ||
|
ce8ac204e1 | ||
|
72df6ddf82 | ||
|
762d1b6d4d | ||
|
d900ca3ba9 | ||
|
eaa88b7ca0 | ||
|
82dbc64f59 | ||
|
bca1844403 | ||
|
332a5ac1cb | ||
|
8047c257fd | ||
|
7dc938a1f4 | ||
|
780c5fe8cd | ||
|
bcb14fd493 |
@ -1,6 +1,7 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'kotlin-parcelize'
|
||||
|
||||
dependencies {
|
||||
api 'com.squareup.okhttp3:okhttp:4.6.0'
|
||||
|
@ -36,7 +36,7 @@ import java.net.URL
|
||||
class CopyMethod(
|
||||
val url: URL,
|
||||
private val destinationUrl: String,
|
||||
private val forceOverride: Boolean
|
||||
private val forceOverride: Boolean = false
|
||||
) : DavMethod(url) {
|
||||
@Throws(Exception::class)
|
||||
public override fun onDavExecute(davResource: DavOCResource): Int {
|
||||
|
@ -36,7 +36,7 @@ import java.net.URL
|
||||
class MoveMethod(
|
||||
url: URL,
|
||||
private val destinationUrl: String,
|
||||
private val forceOverride: Boolean
|
||||
private val forceOverride: Boolean = false
|
||||
) : DavMethod(url) {
|
||||
@Throws(Exception::class)
|
||||
override fun onDavExecute(davResource: DavOCResource): Int {
|
||||
|
@ -53,7 +53,7 @@ class PropfindMethod(
|
||||
depth = depth,
|
||||
reqProp = propertiesToRequest,
|
||||
listOfHeaders = super.getRequestHeadersAsHashMap(),
|
||||
callback = { response: Response, hrefRelation: HrefRelation? ->
|
||||
callback = { response: Response, hrefRelation: HrefRelation ->
|
||||
when (hrefRelation) {
|
||||
HrefRelation.MEMBER -> members.add(response)
|
||||
HrefRelation.SELF -> this.root = response
|
||||
|
@ -1,114 +0,0 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* 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.common.network;
|
||||
|
||||
import okhttp3.MediaType;
|
||||
import okio.BufferedSink;
|
||||
import timber.log.Timber;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* A Request body that represents a file chunk and include information about the progress when uploading it
|
||||
*
|
||||
* @author David González Verdugo
|
||||
*/
|
||||
public class ChunkFromFileRequestBody extends FileRequestBody {
|
||||
|
||||
private final FileChannel mChannel;
|
||||
private final long mChunkSize;
|
||||
private long mOffset;
|
||||
private long mTransferred;
|
||||
private ByteBuffer mBuffer = ByteBuffer.allocate(4096);
|
||||
|
||||
public ChunkFromFileRequestBody(File file, MediaType contentType, FileChannel channel, long chunkSize) {
|
||||
super(file, contentType);
|
||||
if (channel == null) {
|
||||
throw new IllegalArgumentException("File may not be null");
|
||||
}
|
||||
if (chunkSize <= 0) {
|
||||
throw new IllegalArgumentException("Chunk size must be greater than zero");
|
||||
}
|
||||
this.mChannel = channel;
|
||||
this.mChunkSize = chunkSize;
|
||||
mOffset = 0;
|
||||
mTransferred = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long contentLength() {
|
||||
try {
|
||||
return Math.min(mChunkSize, mChannel.size() - mChannel.position());
|
||||
} catch (IOException e) {
|
||||
return mChunkSize;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(BufferedSink sink) {
|
||||
int readCount;
|
||||
Iterator<OnDatatransferProgressListener> it;
|
||||
|
||||
try {
|
||||
mChannel.position(mOffset);
|
||||
long size = mFile.length();
|
||||
if (size == 0) {
|
||||
size = -1;
|
||||
}
|
||||
long maxCount = Math.min(mOffset + mChunkSize, mChannel.size());
|
||||
while (mChannel.position() < maxCount) {
|
||||
|
||||
readCount = mChannel.read(mBuffer);
|
||||
|
||||
int bytesToWriteInBuffer = (int) Math.min(readCount, mFile.length() - mTransferred);
|
||||
sink.getBuffer().write(mBuffer.array(), 0, bytesToWriteInBuffer);
|
||||
|
||||
sink.flush();
|
||||
|
||||
mBuffer.clear();
|
||||
if (mTransferred < maxCount) { // condition to avoid accumulate progress for repeated chunks
|
||||
mTransferred += readCount;
|
||||
}
|
||||
synchronized (mDataTransferListeners) {
|
||||
it = mDataTransferListeners.iterator();
|
||||
while (it.hasNext()) {
|
||||
it.next().onTransferProgress(readCount, mTransferred, size, mFile.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception exception) {
|
||||
Timber.e(exception, "Transferred " + mTransferred + " bytes from a total of " + mFile.length());
|
||||
}
|
||||
}
|
||||
|
||||
public void setOffset(long offset) {
|
||||
this.mOffset = offset;
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2022 ownCloud GmbH.
|
||||
*
|
||||
* 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.common.network
|
||||
|
||||
import com.owncloud.android.lib.resources.files.chunks.ChunkedUploadFromFileSystemOperation.Companion.CHUNK_SIZE
|
||||
import okhttp3.MediaType
|
||||
import okio.BufferedSink
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.channels.FileChannel
|
||||
|
||||
/**
|
||||
* A Request body that represents a file chunk and include information about the progress when uploading it
|
||||
*
|
||||
* @author David González Verdugo
|
||||
*/
|
||||
class ChunkFromFileRequestBody(
|
||||
file: File,
|
||||
contentType: MediaType?,
|
||||
private val channel: FileChannel,
|
||||
private val chunkSize: Long = CHUNK_SIZE
|
||||
) : FileRequestBody(file, contentType) {
|
||||
|
||||
private var offset: Long = 0
|
||||
private var alreadyTransferred: Long = 0
|
||||
private val buffer = ByteBuffer.allocate(4_096)
|
||||
|
||||
init {
|
||||
require(chunkSize > 0) { "Chunk size must be greater than zero" }
|
||||
}
|
||||
|
||||
override fun contentLength(): Long {
|
||||
return chunkSize.coerceAtMost(channel.size() - channel.position())
|
||||
}
|
||||
|
||||
override fun writeTo(sink: BufferedSink) {
|
||||
var readCount: Int
|
||||
var iterator: Iterator<OnDatatransferProgressListener>
|
||||
try {
|
||||
channel.position(offset)
|
||||
|
||||
val maxCount = (offset + chunkSize).coerceAtMost(channel.size())
|
||||
while (channel.position() < maxCount) {
|
||||
readCount = channel.read(buffer)
|
||||
val bytesToWriteInBuffer = readCount.toLong().coerceAtMost(file.length() - alreadyTransferred).toInt()
|
||||
sink.buffer.write(buffer.array(), 0, bytesToWriteInBuffer)
|
||||
sink.flush()
|
||||
buffer.clear()
|
||||
|
||||
if (alreadyTransferred < maxCount) { // condition to avoid accumulate progress for repeated chunks
|
||||
alreadyTransferred += readCount.toLong()
|
||||
}
|
||||
|
||||
synchronized(dataTransferListeners) {
|
||||
iterator = dataTransferListeners.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
iterator.next().onTransferProgress(readCount.toLong(), alreadyTransferred, file.length(), file.absolutePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
Timber.e(exception, "Transferred " + alreadyTransferred + " bytes from a total of " + file.length())
|
||||
}
|
||||
}
|
||||
|
||||
fun setOffset(newOffset: Long) {
|
||||
offset = newOffset
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2022 ownCloud GmbH.
|
||||
*
|
||||
* 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.common.network
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.net.Uri
|
||||
import android.provider.OpenableColumns
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.RequestBody
|
||||
import okio.BufferedSink
|
||||
import okio.Source
|
||||
import okio.source
|
||||
import timber.log.Timber
|
||||
import java.io.IOException
|
||||
|
||||
class ContentUriRequestBody(
|
||||
private val contentResolver: ContentResolver,
|
||||
private val contentUri: Uri
|
||||
) : RequestBody(), ProgressiveDataTransferer {
|
||||
|
||||
private val dataTransferListeners: MutableSet<OnDatatransferProgressListener> = HashSet()
|
||||
|
||||
val fileSize: Long = contentResolver.query(contentUri, null, null, null, null)?.use { cursor ->
|
||||
val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)
|
||||
cursor.moveToFirst()
|
||||
cursor.getLong(sizeIndex)
|
||||
} ?: -1
|
||||
|
||||
override fun contentType(): MediaType? {
|
||||
val contentType = contentResolver.getType(contentUri) ?: return null
|
||||
return contentType.toMediaTypeOrNull()
|
||||
}
|
||||
|
||||
override fun contentLength(): Long {
|
||||
return fileSize
|
||||
}
|
||||
|
||||
override fun writeTo(sink: BufferedSink) {
|
||||
val inputStream = contentResolver.openInputStream(contentUri)
|
||||
?: throw IOException("Couldn't open content URI for reading: $contentUri")
|
||||
|
||||
val previousTime = System.currentTimeMillis()
|
||||
|
||||
sink.writeAndUpdateProgress(inputStream.source())
|
||||
inputStream.source().close()
|
||||
|
||||
val laterTime = System.currentTimeMillis()
|
||||
|
||||
Timber.d("Difference - ${laterTime - previousTime} milliseconds")
|
||||
}
|
||||
|
||||
private fun BufferedSink.writeAndUpdateProgress(source: Source) {
|
||||
var iterator: Iterator<OnDatatransferProgressListener>
|
||||
|
||||
try {
|
||||
var totalBytesRead = 0L
|
||||
var read: Long
|
||||
while (source.read(this.buffer, BYTES_TO_READ).also { read = it } != -1L) {
|
||||
totalBytesRead += read
|
||||
this.flush()
|
||||
synchronized(dataTransferListeners) {
|
||||
iterator = dataTransferListeners.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
iterator.next().onTransferProgress(read, totalBytesRead, fileSize, contentUri.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun addDatatransferProgressListener(listener: OnDatatransferProgressListener) {
|
||||
synchronized(dataTransferListeners) {
|
||||
dataTransferListeners.add(listener)
|
||||
}
|
||||
}
|
||||
|
||||
override fun addDatatransferProgressListeners(listeners: MutableCollection<OnDatatransferProgressListener>) {
|
||||
synchronized(dataTransferListeners) {
|
||||
dataTransferListeners.addAll(listeners)
|
||||
}
|
||||
}
|
||||
|
||||
override fun removeDatatransferProgressListener(listener: OnDatatransferProgressListener) {
|
||||
synchronized(dataTransferListeners) {
|
||||
dataTransferListeners.remove(listener)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val BYTES_TO_READ = 4_096L
|
||||
}
|
||||
}
|
@ -1,119 +0,0 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* 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.common.network;
|
||||
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.RequestBody;
|
||||
import okio.BufferedSink;
|
||||
import okio.Okio;
|
||||
import okio.Source;
|
||||
import timber.log.Timber;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A Request body that represents a file and include information about the progress when uploading it
|
||||
*
|
||||
* @author David González Verdugo
|
||||
*/
|
||||
public class FileRequestBody extends RequestBody implements ProgressiveDataTransferer {
|
||||
|
||||
final Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<>();
|
||||
protected File mFile;
|
||||
private MediaType mContentType;
|
||||
|
||||
public FileRequestBody(File file, MediaType contentType) {
|
||||
mFile = file;
|
||||
mContentType = contentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOneShot() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaType contentType() {
|
||||
return mContentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long contentLength() {
|
||||
return mFile.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(BufferedSink sink) {
|
||||
Source source;
|
||||
Iterator<OnDatatransferProgressListener> it;
|
||||
try {
|
||||
source = Okio.source(mFile);
|
||||
|
||||
long transferred = 0;
|
||||
long read;
|
||||
|
||||
while ((read = source.read(sink.buffer(), 4096)) != -1) {
|
||||
transferred += read;
|
||||
sink.flush();
|
||||
synchronized (mDataTransferListeners) {
|
||||
it = mDataTransferListeners.iterator();
|
||||
while (it.hasNext()) {
|
||||
it.next().onTransferProgress(read, transferred, mFile.length(), mFile.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timber.d("File with name " + mFile.getName() + " and size " + mFile.length() + " written in request body");
|
||||
|
||||
} catch (Exception e) {
|
||||
Timber.e(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
|
||||
synchronized (mDataTransferListeners) {
|
||||
mDataTransferListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
|
||||
synchronized (mDataTransferListeners) {
|
||||
mDataTransferListeners.addAll(listeners);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
|
||||
synchronized (mDataTransferListeners) {
|
||||
mDataTransferListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2022 ownCloud GmbH.
|
||||
*
|
||||
* 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.common.network
|
||||
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.RequestBody
|
||||
import okio.BufferedSink
|
||||
import okio.Source
|
||||
import okio.source
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.util.HashSet
|
||||
|
||||
/**
|
||||
* A Request body that represents a file and include information about the progress when uploading it
|
||||
*
|
||||
* @author David González Verdugo
|
||||
*/
|
||||
open class FileRequestBody(
|
||||
val file: File,
|
||||
private val contentType: MediaType?,
|
||||
) : RequestBody(), ProgressiveDataTransferer {
|
||||
|
||||
val dataTransferListeners: MutableSet<OnDatatransferProgressListener> = HashSet()
|
||||
|
||||
override fun isOneShot(): Boolean = true
|
||||
|
||||
override fun contentType(): MediaType? = contentType
|
||||
|
||||
override fun contentLength(): Long = file.length()
|
||||
|
||||
override fun writeTo(sink: BufferedSink) {
|
||||
val source: Source
|
||||
var it: Iterator<OnDatatransferProgressListener>
|
||||
try {
|
||||
source = file.source()
|
||||
var transferred: Long = 0
|
||||
var read: Long
|
||||
while (source.read(sink.buffer, BYTES_TO_READ).also { read = it } != -1L) {
|
||||
transferred += read
|
||||
sink.flush()
|
||||
synchronized(dataTransferListeners) {
|
||||
it = dataTransferListeners.iterator()
|
||||
while (it.hasNext()) {
|
||||
it.next().onTransferProgress(read, transferred, file.length(), file.absolutePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
Timber.d("File with name ${file.name} and size ${file.length()} written in request body")
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun addDatatransferProgressListener(listener: OnDatatransferProgressListener) {
|
||||
synchronized(dataTransferListeners) {
|
||||
dataTransferListeners.add(listener)
|
||||
}
|
||||
}
|
||||
|
||||
override fun addDatatransferProgressListeners(listeners: Collection<OnDatatransferProgressListener>) {
|
||||
synchronized(dataTransferListeners) {
|
||||
dataTransferListeners.addAll(listeners)
|
||||
}
|
||||
}
|
||||
|
||||
override fun removeDatatransferProgressListener(listener: OnDatatransferProgressListener) {
|
||||
synchronized(dataTransferListeners) {
|
||||
dataTransferListeners.remove(listener)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val BYTES_TO_READ = 4_096L
|
||||
}
|
||||
}
|
@ -22,24 +22,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package com.owncloud.android.lib.resources.files.chunks;
|
||||
package com.owncloud.android.lib.common.utils
|
||||
|
||||
import com.owncloud.android.lib.resources.files.CreateRemoteFolderOperation;
|
||||
|
||||
/**
|
||||
* Remote operation performing the creation of a new folder to save chunks during an upload to the ownCloud server.
|
||||
*
|
||||
* @author David González Verdugo
|
||||
*/
|
||||
public class CreateRemoteChunkFolderOperation extends CreateRemoteFolderOperation {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param remotePath Full path to the new directory to create in the remote server.
|
||||
* @param createFullPath 'True' means that all the ancestor folders should be created.
|
||||
*/
|
||||
public CreateRemoteChunkFolderOperation(String remotePath, boolean createFullPath) {
|
||||
super(remotePath, createFullPath);
|
||||
createChunksFolder = true;
|
||||
}
|
||||
}
|
||||
fun Any.isOneOf(vararg values: Any): Boolean {
|
||||
return this in values
|
||||
}
|
@ -1,130 +0,0 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* 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 com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.http.HttpConstants;
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.CopyMethod;
|
||||
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 timber.log.Timber;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Remote operation moving a remote file or folder in the ownCloud server to a different folder
|
||||
* in the same account.
|
||||
*
|
||||
* Allows renaming the moving file/folder at the same time.
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* @author Christian Schabesberger
|
||||
* @author David González V.
|
||||
*/
|
||||
public class CopyRemoteFileOperation extends RemoteOperation<String> {
|
||||
|
||||
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<String> run(OwnCloudClient client) {
|
||||
|
||||
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
|
||||
RemoteOperationResult result;
|
||||
try {
|
||||
CopyMethod copyMethod =
|
||||
new CopyMethod(
|
||||
new URL(client.getUserFilesWebDavUri() + WebdavUtils.encodePath(mSrcRemotePath)),
|
||||
client.getUserFilesWebDavUri() + WebdavUtils.encodePath(mTargetRemotePath),
|
||||
mOverwrite);
|
||||
|
||||
copyMethod.setReadTimeout(COPY_READ_TIMEOUT, TimeUnit.SECONDS);
|
||||
copyMethod.setConnectionTimeout(COPY_CONNECTION_TIMEOUT, TimeUnit.SECONDS);
|
||||
|
||||
final int status = client.executeHttpMethod(copyMethod);
|
||||
|
||||
if (status == HttpConstants.HTTP_CREATED || status == HttpConstants.HTTP_NO_CONTENT) {
|
||||
String fileRemoteId = copyMethod.getResponseHeader(HttpConstants.OC_FILE_REMOTE_ID);
|
||||
result = new RemoteOperationResult<>(ResultCode.OK);
|
||||
result.setData(fileRemoteId);
|
||||
} else if (status == HttpConstants.HTTP_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 {
|
||||
|
||||
result = new RemoteOperationResult<>(copyMethod);
|
||||
client.exhaustResponse(copyMethod.getResponseBodyAsStream());
|
||||
}
|
||||
|
||||
Timber.i("Copy " + mSrcRemotePath + " to " + mTargetRemotePath + ": " + result.getLogMessage());
|
||||
|
||||
} catch (Exception e) {
|
||||
result = new RemoteOperationResult<>(e);
|
||||
Timber.e(e, "Copy " + mSrcRemotePath + " to " + mTargetRemotePath + ": " + result.getLogMessage());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2022 ownCloud GmbH.
|
||||
*
|
||||
* 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 com.owncloud.android.lib.common.OwnCloudClient
|
||||
import com.owncloud.android.lib.common.http.HttpConstants
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.CopyMethod
|
||||
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.common.utils.isOneOf
|
||||
import timber.log.Timber
|
||||
import java.net.URL
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* Remote operation copying a remote file or folder in the ownCloud server to a different folder
|
||||
* in the same account.
|
||||
*
|
||||
* Allows renaming the copying file/folder at the same time.
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* @author Christian Schabesberger
|
||||
* @author David González V.
|
||||
*
|
||||
* @param srcRemotePath Remote path of the file/folder to copy.
|
||||
* @param targetRemotePath Remote path desired for the file/folder to copy it.
|
||||
*/
|
||||
class CopyRemoteFileOperation(
|
||||
private val srcRemotePath: String,
|
||||
private val targetRemotePath: String,
|
||||
) : RemoteOperation<String>() {
|
||||
/**
|
||||
* Performs the rename operation.
|
||||
*
|
||||
* @param client Client object to communicate with the remote ownCloud server.
|
||||
*/
|
||||
override fun run(client: OwnCloudClient): RemoteOperationResult<String> {
|
||||
if (targetRemotePath == srcRemotePath) {
|
||||
// nothing to do!
|
||||
return RemoteOperationResult(ResultCode.OK)
|
||||
}
|
||||
if (targetRemotePath.startsWith(srcRemotePath)) {
|
||||
return RemoteOperationResult(ResultCode.INVALID_COPY_INTO_DESCENDANT)
|
||||
}
|
||||
|
||||
/// perform remote operation
|
||||
var result: RemoteOperationResult<String>
|
||||
try {
|
||||
val copyMethod = CopyMethod(
|
||||
URL(client.userFilesWebDavUri.toString() + WebdavUtils.encodePath(srcRemotePath)),
|
||||
client.userFilesWebDavUri.toString() + WebdavUtils.encodePath(targetRemotePath),
|
||||
).apply {
|
||||
setReadTimeout(COPY_READ_TIMEOUT, TimeUnit.SECONDS)
|
||||
setConnectionTimeout(COPY_CONNECTION_TIMEOUT, TimeUnit.SECONDS)
|
||||
}
|
||||
val status = client.executeHttpMethod(copyMethod)
|
||||
when {
|
||||
isSuccess(status) -> {
|
||||
val fileRemoteId = copyMethod.getResponseHeader(HttpConstants.OC_FILE_REMOTE_ID)
|
||||
result = RemoteOperationResult(ResultCode.OK)
|
||||
result.setData(fileRemoteId)
|
||||
}
|
||||
isPreconditionFailed(status) -> {
|
||||
result = 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 -> {
|
||||
result = RemoteOperationResult(copyMethod)
|
||||
client.exhaustResponse(copyMethod.getResponseBodyAsStream())
|
||||
}
|
||||
}
|
||||
Timber.i("Copy $srcRemotePath to $targetRemotePath: ${result.logMessage}")
|
||||
} catch (e: Exception) {
|
||||
result = RemoteOperationResult(e)
|
||||
Timber.e(e, "Copy $srcRemotePath to $targetRemotePath: ${result.logMessage}")
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun isSuccess(status: Int) = status.isOneOf(HttpConstants.HTTP_CREATED, HttpConstants.HTTP_NO_CONTENT)
|
||||
|
||||
private fun isPreconditionFailed(status: Int) = status == HttpConstants.HTTP_PRECONDITION_FAILED
|
||||
|
||||
companion object {
|
||||
private const val COPY_READ_TIMEOUT = 10L
|
||||
private const val COPY_CONNECTION_TIMEOUT = 6L
|
||||
}
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2019 ownCloud GmbH.
|
||||
*
|
||||
* 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.net.Uri;
|
||||
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.http.HttpConstants;
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.MkColMethod;
|
||||
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 timber.log.Timber;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Remote operation performing the creation of a new folder in the ownCloud server.
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
*/
|
||||
public class CreateRemoteFolderOperation extends RemoteOperation {
|
||||
|
||||
private static final int READ_TIMEOUT = 30000;
|
||||
private static final int CONNECTION_TIMEOUT = 5000;
|
||||
|
||||
private String mRemotePath;
|
||||
private boolean mCreateFullPath;
|
||||
protected boolean createChunksFolder;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param remotePath Full path to the new directory to create in the remote server.
|
||||
* @param createFullPath 'True' means that all the ancestor folders should be created.
|
||||
*/
|
||||
public CreateRemoteFolderOperation(String remotePath, boolean createFullPath) {
|
||||
mRemotePath = remotePath;
|
||||
mCreateFullPath = createFullPath;
|
||||
createChunksFolder = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the operation
|
||||
*
|
||||
* @param client Client object to communicate with the remote ownCloud server.
|
||||
*/
|
||||
@Override
|
||||
protected RemoteOperationResult run(OwnCloudClient client) {
|
||||
RemoteOperationResult result = createFolder(client);
|
||||
if (!result.isSuccess() && mCreateFullPath &&
|
||||
RemoteOperationResult.ResultCode.CONFLICT == result.getCode()) {
|
||||
result = createParentFolder(FileUtils.getParentPath(mRemotePath), client);
|
||||
if (result.isSuccess()) {
|
||||
result = createFolder(client); // second (and last) try
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private RemoteOperationResult createFolder(OwnCloudClient client) {
|
||||
RemoteOperationResult result;
|
||||
try {
|
||||
Uri webDavUri = createChunksFolder ? client.getUploadsWebDavUri() : client.getUserFilesWebDavUri();
|
||||
final MkColMethod mkcol = new MkColMethod(
|
||||
new URL(webDavUri + WebdavUtils.encodePath(mRemotePath)));
|
||||
mkcol.setReadTimeout(READ_TIMEOUT, TimeUnit.SECONDS);
|
||||
mkcol.setConnectionTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS);
|
||||
final int status = client.executeHttpMethod(mkcol);
|
||||
|
||||
result = (status == HttpConstants.HTTP_CREATED)
|
||||
? new RemoteOperationResult<>(ResultCode.OK)
|
||||
: new RemoteOperationResult<>(mkcol);
|
||||
Timber.d("Create directory " + mRemotePath + ": " + result.getLogMessage());
|
||||
client.exhaustResponse(mkcol.getResponseBodyAsStream());
|
||||
|
||||
} catch (Exception e) {
|
||||
result = new RemoteOperationResult<>(e);
|
||||
Timber.e(e, "Create directory " + mRemotePath + ": " + result.getLogMessage());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private RemoteOperationResult createParentFolder(String parentPath, OwnCloudClient client) {
|
||||
RemoteOperation operation = new CreateRemoteFolderOperation(parentPath, mCreateFullPath);
|
||||
return operation.execute(client);
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* 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 com.owncloud.android.lib.common.OwnCloudClient
|
||||
import com.owncloud.android.lib.common.http.HttpConstants
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.MkColMethod
|
||||
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 timber.log.Timber
|
||||
import java.net.URL
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* Remote operation performing the creation of a new folder in the ownCloud server.
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
*
|
||||
* @param remotePath Full path to the new directory to create in the remote server.
|
||||
* @param createFullPath 'True' means that all the ancestor folders should be created.
|
||||
*/
|
||||
class CreateRemoteFolderOperation(
|
||||
val remotePath: String,
|
||||
private val createFullPath: Boolean,
|
||||
private val isChunksFolder: Boolean = false
|
||||
) : RemoteOperation<Unit>() {
|
||||
|
||||
override fun run(client: OwnCloudClient): RemoteOperationResult<Unit> {
|
||||
|
||||
var result = createFolder(client)
|
||||
if (!result.isSuccess && createFullPath && result.code == ResultCode.CONFLICT) {
|
||||
result = createParentFolder(FileUtils.getParentPath(remotePath), client)
|
||||
|
||||
if (result.isSuccess) {
|
||||
// Second and last try
|
||||
result = createFolder(client)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun createFolder(client: OwnCloudClient): RemoteOperationResult<Unit> {
|
||||
var result: RemoteOperationResult<Unit>
|
||||
try {
|
||||
val webDavUri = if (isChunksFolder) {
|
||||
client.uploadsWebDavUri
|
||||
} else {
|
||||
client.userFilesWebDavUri
|
||||
}
|
||||
|
||||
val mkCol = MkColMethod(
|
||||
URL(webDavUri.toString() + WebdavUtils.encodePath(remotePath))
|
||||
).apply {
|
||||
setReadTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
|
||||
setConnectionTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS)
|
||||
}
|
||||
|
||||
val status = client.executeHttpMethod(mkCol)
|
||||
result =
|
||||
if (status == HttpConstants.HTTP_CREATED) {
|
||||
RemoteOperationResult(ResultCode.OK)
|
||||
} else {
|
||||
RemoteOperationResult(mkCol)
|
||||
}
|
||||
|
||||
Timber.d("Create directory $remotePath: ${result.logMessage}")
|
||||
client.exhaustResponse(mkCol.getResponseBodyAsStream())
|
||||
|
||||
} catch (e: Exception) {
|
||||
result = RemoteOperationResult(e)
|
||||
Timber.e(e, "Create directory $remotePath: ${result.logMessage}")
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun createParentFolder(parentPath: String, client: OwnCloudClient): RemoteOperationResult<Unit> {
|
||||
val operation: RemoteOperation<Unit> = CreateRemoteFolderOperation(parentPath, createFullPath)
|
||||
return operation.execute(client)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val READ_TIMEOUT: Long = 30_000
|
||||
private const val CONNECTION_TIMEOUT: Long = 5_000
|
||||
}
|
||||
}
|
@ -1,221 +0,0 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2016 ownCloud GmbH.
|
||||
*
|
||||
* 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 com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.http.HttpConstants;
|
||||
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod;
|
||||
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
|
||||
import com.owncloud.android.lib.common.network.WebdavUtils;
|
||||
import com.owncloud.android.lib.common.operations.OperationCancelledException;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import timber.log.Timber;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Remote operation performing the download of a remote file in the ownCloud server.
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
*/
|
||||
|
||||
public class DownloadRemoteFileOperation extends RemoteOperation {
|
||||
|
||||
private static final int FORBIDDEN_ERROR = 403;
|
||||
private static final int SERVICE_UNAVAILABLE_ERROR = 503;
|
||||
private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
|
||||
private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<>();
|
||||
private long mModificationTimestamp = 0;
|
||||
private String mEtag = "";
|
||||
private GetMethod mGet;
|
||||
|
||||
private String mRemotePath;
|
||||
private String mLocalFolderPath;
|
||||
|
||||
public DownloadRemoteFileOperation(String remotePath, String localFolderPath) {
|
||||
mRemotePath = remotePath;
|
||||
mLocalFolderPath = localFolderPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RemoteOperationResult run(OwnCloudClient client) {
|
||||
RemoteOperationResult result;
|
||||
|
||||
/// download will be performed to a temporal file, then moved to the final location
|
||||
File tmpFile = new File(getTmpPath());
|
||||
|
||||
/// perform the download
|
||||
try {
|
||||
tmpFile.getParentFile().mkdirs();
|
||||
result = downloadFile(client, tmpFile);
|
||||
Timber.i("Download of " + mRemotePath + " to " + getTmpPath() + ": " + result.getLogMessage());
|
||||
|
||||
} catch (Exception e) {
|
||||
result = new RemoteOperationResult<>(e);
|
||||
Timber.e(e, "Download of " + mRemotePath + " to " + getTmpPath() + ": " + result.getLogMessage());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private RemoteOperationResult downloadFile(OwnCloudClient client, File targetFile) throws
|
||||
Exception {
|
||||
|
||||
RemoteOperationResult result;
|
||||
int status;
|
||||
boolean savedFile = false;
|
||||
mGet = new GetMethod(new URL(client.getUserFilesWebDavUri() + WebdavUtils.encodePath(mRemotePath)));
|
||||
Iterator<OnDatatransferProgressListener> it;
|
||||
|
||||
FileOutputStream fos = null;
|
||||
BufferedInputStream bis = null;
|
||||
try {
|
||||
status = client.executeHttpMethod(mGet);
|
||||
if (isSuccess(status)) {
|
||||
targetFile.createNewFile();
|
||||
bis = new BufferedInputStream(mGet.getResponseBodyAsStream());
|
||||
fos = new FileOutputStream(targetFile);
|
||||
long transferred = 0;
|
||||
|
||||
String contentLength = mGet.getResponseHeader(HttpConstants.CONTENT_LENGTH_HEADER);
|
||||
long totalToTransfer =
|
||||
(contentLength != null
|
||||
&& contentLength.length() > 0)
|
||||
? Long.parseLong(contentLength)
|
||||
: 0;
|
||||
|
||||
byte[] bytes = new byte[4096];
|
||||
int readResult;
|
||||
while ((readResult = bis.read(bytes)) != -1) {
|
||||
synchronized (mCancellationRequested) {
|
||||
if (mCancellationRequested.get()) {
|
||||
mGet.abort();
|
||||
throw new OperationCancelledException();
|
||||
}
|
||||
}
|
||||
fos.write(bytes, 0, readResult);
|
||||
transferred += readResult;
|
||||
synchronized (mDataTransferListeners) {
|
||||
it = mDataTransferListeners.iterator();
|
||||
while (it.hasNext()) {
|
||||
it.next().onTransferProgress(readResult, transferred, totalToTransfer,
|
||||
targetFile.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (transferred == totalToTransfer) { // Check if the file is completed
|
||||
savedFile = true;
|
||||
final String modificationTime =
|
||||
mGet.getResponseHeaders().get("Last-Modified") != null
|
||||
? mGet.getResponseHeaders().get("Last-Modified")
|
||||
: mGet.getResponseHeader("last-modified");
|
||||
|
||||
if (modificationTime != null) {
|
||||
final Date d = WebdavUtils.parseResponseDate(modificationTime);
|
||||
mModificationTimestamp = (d != null) ? d.getTime() : 0;
|
||||
} else {
|
||||
Timber.e("Could not read modification time from response downloading %s", mRemotePath);
|
||||
}
|
||||
|
||||
mEtag = WebdavUtils.getEtagFromResponse(mGet);
|
||||
|
||||
// Get rid of extra quotas
|
||||
mEtag = mEtag.replace("\"", "");
|
||||
|
||||
if (mEtag.length() == 0) {
|
||||
Timber.e("Could not read eTag from response downloading %s", mRemotePath);
|
||||
}
|
||||
|
||||
} else {
|
||||
Timber.e("Content-Length not equal to transferred bytes.");
|
||||
Timber.d("totalToTransfer = %d, transferred = %d", totalToTransfer, transferred);
|
||||
client.exhaustResponse(mGet.getResponseBodyAsStream());
|
||||
// TODO some kind of error control!
|
||||
}
|
||||
|
||||
} else if (status != FORBIDDEN_ERROR && status != SERVICE_UNAVAILABLE_ERROR) {
|
||||
client.exhaustResponse(mGet.getResponseBodyAsStream());
|
||||
|
||||
} // else, body read by RemoteOperationResult constructor
|
||||
|
||||
result = isSuccess(status)
|
||||
? new RemoteOperationResult<>(RemoteOperationResult.ResultCode.OK)
|
||||
: new RemoteOperationResult<>(mGet);
|
||||
} finally {
|
||||
if (fos != null) {
|
||||
fos.close();
|
||||
}
|
||||
if (bis != null) {
|
||||
bis.close();
|
||||
}
|
||||
if (!savedFile && targetFile.exists()) {
|
||||
targetFile.delete();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isSuccess(int status) {
|
||||
return (status == HttpConstants.HTTP_OK);
|
||||
}
|
||||
|
||||
private String getTmpPath() {
|
||||
return mLocalFolderPath + mRemotePath;
|
||||
}
|
||||
|
||||
public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
|
||||
synchronized (mDataTransferListeners) {
|
||||
mDataTransferListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
|
||||
synchronized (mDataTransferListeners) {
|
||||
mDataTransferListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
mCancellationRequested.set(true); // atomic set; there is no need of synchronizing it
|
||||
}
|
||||
|
||||
public long getModificationTimestamp() {
|
||||
return mModificationTimestamp;
|
||||
}
|
||||
|
||||
public String getEtag() {
|
||||
return mEtag;
|
||||
}
|
||||
}
|
@ -0,0 +1,184 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* 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 com.owncloud.android.lib.common.OwnCloudClient
|
||||
import com.owncloud.android.lib.common.http.HttpConstants
|
||||
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod
|
||||
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener
|
||||
import com.owncloud.android.lib.common.network.WebdavUtils
|
||||
import com.owncloud.android.lib.common.operations.OperationCancelledException
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperation
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
||||
import timber.log.Timber
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.net.URL
|
||||
import java.util.HashSet
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
/**
|
||||
* Remote operation performing the download of a remote file in the ownCloud server.
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
*/
|
||||
class DownloadRemoteFileOperation(
|
||||
private val remotePath: String,
|
||||
localFolderPath: String
|
||||
) : RemoteOperation<Unit>() {
|
||||
|
||||
private val cancellationRequested = AtomicBoolean(false)
|
||||
private val dataTransferListeners: MutableSet<OnDatatransferProgressListener> = HashSet()
|
||||
|
||||
var modificationTimestamp: Long = 0
|
||||
private set
|
||||
|
||||
var etag: String = ""
|
||||
private set
|
||||
|
||||
override fun run(client: OwnCloudClient): RemoteOperationResult<Unit> {
|
||||
// download will be performed to a temporal file, then moved to the final location
|
||||
val tmpFile = File(tmpPath)
|
||||
|
||||
// perform the download
|
||||
return try {
|
||||
tmpFile.parentFile?.mkdirs()
|
||||
downloadFile(client, tmpFile).also { result ->
|
||||
Timber.i("Download of $remotePath to $tmpPath: ${result.logMessage}")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
RemoteOperationResult<Unit>(e).also { result ->
|
||||
Timber.e(e, "Download of $remotePath to $tmpPath: ${result.logMessage}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
private fun downloadFile(client: OwnCloudClient, targetFile: File): RemoteOperationResult<Unit> {
|
||||
val result: RemoteOperationResult<Unit>
|
||||
var it: Iterator<OnDatatransferProgressListener>
|
||||
var fos: FileOutputStream? = null
|
||||
var bis: BufferedInputStream? = null
|
||||
var savedFile = false
|
||||
|
||||
val getMethod = GetMethod(URL(client.userFilesWebDavUri.toString() + WebdavUtils.encodePath(remotePath)))
|
||||
|
||||
try {
|
||||
val status = client.executeHttpMethod(getMethod)
|
||||
|
||||
if (isSuccess(status)) {
|
||||
targetFile.createNewFile()
|
||||
bis = BufferedInputStream(getMethod.getResponseBodyAsStream())
|
||||
fos = FileOutputStream(targetFile)
|
||||
var transferred: Long = 0
|
||||
val contentLength = getMethod.getResponseHeader(HttpConstants.CONTENT_LENGTH_HEADER)
|
||||
val totalToTransfer = if (!contentLength.isNullOrEmpty()) {
|
||||
contentLength.toLong()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
val bytes = ByteArray(4096)
|
||||
var readResult: Int
|
||||
while (bis.read(bytes).also { readResult = it } != -1) {
|
||||
synchronized(cancellationRequested) {
|
||||
if (cancellationRequested.get()) {
|
||||
getMethod.abort()
|
||||
throw OperationCancelledException()
|
||||
}
|
||||
}
|
||||
fos.write(bytes, 0, readResult)
|
||||
transferred += readResult.toLong()
|
||||
synchronized(dataTransferListeners) {
|
||||
it = dataTransferListeners.iterator()
|
||||
while (it.hasNext()) {
|
||||
it.next()
|
||||
.onTransferProgress(readResult.toLong(), transferred, totalToTransfer, targetFile.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (transferred == totalToTransfer) { // Check if the file is completed
|
||||
savedFile = true
|
||||
val modificationTime =
|
||||
getMethod.getResponseHeaders()?.get("Last-Modified")
|
||||
?: getMethod.getResponseHeader("last-modified")
|
||||
|
||||
if (modificationTime != null) {
|
||||
val modificationDate = WebdavUtils.parseResponseDate(modificationTime)
|
||||
modificationTimestamp = modificationDate?.time ?: 0
|
||||
} else {
|
||||
Timber.e("Could not read modification time from response downloading %s", remotePath)
|
||||
}
|
||||
etag = WebdavUtils.getEtagFromResponse(getMethod)
|
||||
|
||||
// Get rid of extra quotas
|
||||
etag = etag.replace("\"", "")
|
||||
if (etag.isEmpty()) {
|
||||
Timber.e("Could not read eTag from response downloading %s", remotePath)
|
||||
}
|
||||
} else {
|
||||
Timber.e("Content-Length not equal to transferred bytes.")
|
||||
Timber.d("totalToTransfer = $totalToTransfer, transferred = $transferred")
|
||||
client.exhaustResponse(getMethod.getResponseBodyAsStream())
|
||||
// TODO some kind of error control!
|
||||
}
|
||||
|
||||
} else if (status != HttpConstants.HTTP_FORBIDDEN && status != HttpConstants.HTTP_SERVICE_UNAVAILABLE) {
|
||||
client.exhaustResponse(getMethod.getResponseBodyAsStream())
|
||||
} // else, body read by RemoteOperationResult constructor
|
||||
|
||||
result =
|
||||
if (isSuccess(status)) {
|
||||
RemoteOperationResult(RemoteOperationResult.ResultCode.OK)
|
||||
} else {
|
||||
RemoteOperationResult(getMethod)
|
||||
}
|
||||
} finally {
|
||||
fos?.close()
|
||||
bis?.close()
|
||||
if (!savedFile && targetFile.exists()) {
|
||||
targetFile.delete()
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun isSuccess(status: Int) = status == HttpConstants.HTTP_OK
|
||||
|
||||
private val tmpPath: String = localFolderPath + remotePath
|
||||
|
||||
fun addDatatransferProgressListener(listener: OnDatatransferProgressListener) {
|
||||
synchronized(dataTransferListeners) { dataTransferListeners.add(listener) }
|
||||
}
|
||||
|
||||
fun removeDatatransferProgressListener(listener: OnDatatransferProgressListener?) {
|
||||
synchronized(dataTransferListeners) { dataTransferListeners.remove(listener) }
|
||||
}
|
||||
|
||||
fun cancel() {
|
||||
cancellationRequested.set(true) // atomic set; there is no need of synchronizing it
|
||||
}
|
||||
}
|
@ -32,6 +32,7 @@ public class FileUtils {
|
||||
public static final String FINAL_CHUNKS_FILE = ".file";
|
||||
public static final String MIME_DIR = "DIR";
|
||||
public static final String MIME_DIR_UNIX = "httpd/unix-directory";
|
||||
public static final String MODE_READ_ONLY = "r";
|
||||
|
||||
static String getParentPath(String remotePath) {
|
||||
String parentPath = new File(remotePath).getParent();
|
||||
|
@ -1,146 +0,0 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* 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.net.Uri;
|
||||
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.http.HttpConstants;
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.MoveMethod;
|
||||
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 timber.log.Timber;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @author David González Verdugo
|
||||
*/
|
||||
public class MoveRemoteFileOperation extends RemoteOperation {
|
||||
|
||||
private static final int MOVE_READ_TIMEOUT = 600000;
|
||||
private static final int MOVE_CONNECTION_TIMEOUT = 5000;
|
||||
|
||||
private String mSrcRemotePath;
|
||||
private String mTargetRemotePath;
|
||||
private boolean mOverwrite;
|
||||
|
||||
protected boolean moveChunkedFile = false;
|
||||
protected String mFileLastModifTimestamp;
|
||||
protected long mFileLength;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* <p>
|
||||
* TODO Paths should finish in "/" in the case of folders. ?
|
||||
*
|
||||
* @param srcRemotePath Remote path of the file/folder to move.
|
||||
* @param targetRemotePath Remote path desired for the file/folder after moving it.
|
||||
*/
|
||||
public MoveRemoteFileOperation(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) {
|
||||
if (mTargetRemotePath.equals(mSrcRemotePath)) {
|
||||
// nothing to do!
|
||||
return new RemoteOperationResult<>(ResultCode.OK);
|
||||
}
|
||||
|
||||
if (mTargetRemotePath.startsWith(mSrcRemotePath)) {
|
||||
return new RemoteOperationResult<>(ResultCode.INVALID_MOVE_INTO_DESCENDANT);
|
||||
}
|
||||
|
||||
/// perform remote operation
|
||||
RemoteOperationResult result;
|
||||
try {
|
||||
// After finishing a chunked upload, we have to move the resulting file from uploads folder to files one,
|
||||
// so this uri has to be customizable
|
||||
Uri srcWebDavUri = moveChunkedFile ? client.getUploadsWebDavUri() : client.getUserFilesWebDavUri();
|
||||
|
||||
final MoveMethod move = new MoveMethod(
|
||||
new URL(srcWebDavUri + WebdavUtils.encodePath(mSrcRemotePath)),
|
||||
client.getUserFilesWebDavUri() + WebdavUtils.encodePath(mTargetRemotePath),
|
||||
mOverwrite);
|
||||
|
||||
if (moveChunkedFile) {
|
||||
move.addRequestHeader(HttpConstants.OC_X_OC_MTIME_HEADER, mFileLastModifTimestamp);
|
||||
move.addRequestHeader(HttpConstants.OC_TOTAL_LENGTH_HEADER, String.valueOf(mFileLength));
|
||||
}
|
||||
|
||||
move.setReadTimeout(MOVE_READ_TIMEOUT, TimeUnit.SECONDS);
|
||||
move.setConnectionTimeout(MOVE_CONNECTION_TIMEOUT, TimeUnit.SECONDS);
|
||||
|
||||
final int status = client.executeHttpMethod(move);
|
||||
/// process response
|
||||
if (isSuccess(status)) {
|
||||
result = new RemoteOperationResult<>(ResultCode.OK);
|
||||
} else if (status == HttpConstants.HTTP_PRECONDITION_FAILED && !mOverwrite) {
|
||||
|
||||
result = new RemoteOperationResult<>(ResultCode.INVALID_OVERWRITE);
|
||||
client.exhaustResponse(move.getResponseBodyAsStream());
|
||||
|
||||
/// for other errors that could be explicitly handled, check first:
|
||||
/// http://www.webdav.org/specs/rfc4918.html#rfc.section.9.9.4
|
||||
|
||||
} else {
|
||||
result = new RemoteOperationResult<>(move);
|
||||
client.exhaustResponse(move.getResponseBodyAsStream());
|
||||
}
|
||||
|
||||
Timber.i("Move " + mSrcRemotePath + " to " + mTargetRemotePath + ": " + result.getLogMessage());
|
||||
|
||||
} catch (Exception e) {
|
||||
result = new RemoteOperationResult<>(e);
|
||||
Timber.e(e, "Move " + mSrcRemotePath + " to " + mTargetRemotePath + ": " + result.getLogMessage());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected boolean isSuccess(int status) {
|
||||
return status == HttpConstants.HTTP_CREATED || status == HttpConstants.HTTP_NO_CONTENT;
|
||||
}
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2021 ownCloud GmbH.
|
||||
*
|
||||
* 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.net.Uri
|
||||
import com.owncloud.android.lib.common.OwnCloudClient
|
||||
import com.owncloud.android.lib.common.http.HttpConstants
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.MoveMethod
|
||||
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.common.utils.isOneOf
|
||||
import timber.log.Timber
|
||||
import java.net.URL
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* Remote operation moving a remote file or folder in the ownCloud server to a different folder
|
||||
* in the same account.
|
||||
*
|
||||
* Allows renaming the moving file/folder at the same time.
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* @author David González Verdugo
|
||||
* @author Abel García de Prada
|
||||
*/
|
||||
open class MoveRemoteFileOperation(
|
||||
private val sourceRemotePath: String,
|
||||
private val targetRemotePath: String,
|
||||
) : RemoteOperation<Unit>() {
|
||||
|
||||
/**
|
||||
* Performs the rename operation.
|
||||
*
|
||||
* @param client Client object to communicate with the remote ownCloud server.
|
||||
*/
|
||||
override fun run(client: OwnCloudClient): RemoteOperationResult<Unit> {
|
||||
if (targetRemotePath == sourceRemotePath) {
|
||||
// nothing to do!
|
||||
return RemoteOperationResult(ResultCode.OK)
|
||||
}
|
||||
|
||||
if (targetRemotePath.startsWith(sourceRemotePath)) {
|
||||
return RemoteOperationResult(ResultCode.INVALID_MOVE_INTO_DESCENDANT)
|
||||
}
|
||||
|
||||
/// perform remote operation
|
||||
var result: RemoteOperationResult<Unit>
|
||||
try {
|
||||
// After finishing a chunked upload, we have to move the resulting file from uploads folder to files one,
|
||||
// so this uri has to be customizable
|
||||
val srcWebDavUri = getSrcWebDavUriForClient(client)
|
||||
val moveMethod = MoveMethod(
|
||||
url = URL(srcWebDavUri.toString() + WebdavUtils.encodePath(sourceRemotePath)),
|
||||
destinationUrl = client.userFilesWebDavUri.toString() + WebdavUtils.encodePath(targetRemotePath),
|
||||
).apply {
|
||||
addRequestHeaders(this)
|
||||
setReadTimeout(MOVE_READ_TIMEOUT, TimeUnit.SECONDS)
|
||||
setConnectionTimeout(MOVE_CONNECTION_TIMEOUT, TimeUnit.SECONDS)
|
||||
}
|
||||
|
||||
val status = client.executeHttpMethod(moveMethod)
|
||||
|
||||
when {
|
||||
isSuccess(status) -> {
|
||||
result = RemoteOperationResult<Unit>(ResultCode.OK)
|
||||
}
|
||||
isPreconditionFailed(status) -> {
|
||||
result = RemoteOperationResult<Unit>(ResultCode.INVALID_OVERWRITE)
|
||||
client.exhaustResponse(moveMethod.getResponseBodyAsStream())
|
||||
|
||||
/// for other errors that could be explicitly handled, check first:
|
||||
/// http://www.webdav.org/specs/rfc4918.html#rfc.section.9.9.4
|
||||
}
|
||||
else -> {
|
||||
result = RemoteOperationResult<Unit>(moveMethod)
|
||||
client.exhaustResponse(moveMethod.getResponseBodyAsStream())
|
||||
}
|
||||
}
|
||||
|
||||
Timber.i("Move $sourceRemotePath to $targetRemotePath: ${result.logMessage}")
|
||||
} catch (e: Exception) {
|
||||
result = RemoteOperationResult<Unit>(e)
|
||||
Timber.e(e, "Move $sourceRemotePath to $targetRemotePath: ${result.logMessage}")
|
||||
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* For standard moves, we will use [OwnCloudClient.getUserFilesWebDavUri].
|
||||
* In case we need a different source Uri, override this method.
|
||||
*/
|
||||
open fun getSrcWebDavUriForClient(client: OwnCloudClient): Uri = client.userFilesWebDavUri
|
||||
|
||||
/**
|
||||
* For standard moves, we won't need any special headers.
|
||||
* In case new headers are needed, override this method
|
||||
*/
|
||||
open fun addRequestHeaders(moveMethod: MoveMethod) {
|
||||
}
|
||||
|
||||
private fun isSuccess(status: Int) = status.isOneOf(HttpConstants.HTTP_CREATED, HttpConstants.HTTP_NO_CONTENT)
|
||||
|
||||
private fun isPreconditionFailed(status: Int) = status == HttpConstants.HTTP_PRECONDITION_FAILED
|
||||
|
||||
companion object {
|
||||
private const val MOVE_READ_TIMEOUT = 10L
|
||||
private const val MOVE_CONNECTION_TIMEOUT = 6L
|
||||
}
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2016 ownCloud GmbH.
|
||||
*
|
||||
* 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 com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.accounts.AccountUtils;
|
||||
import com.owncloud.android.lib.common.http.HttpConstants;
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.DavUtils;
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.PropfindMethod;
|
||||
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 timber.log.Timber;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.owncloud.android.lib.common.http.methods.webdav.DavConstants.DEPTH_0;
|
||||
import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK;
|
||||
|
||||
/**
|
||||
* Remote operation performing the read a file from the ownCloud server.
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
* @author David González Verdugo
|
||||
*/
|
||||
|
||||
public class ReadRemoteFileOperation extends RemoteOperation<RemoteFile> {
|
||||
|
||||
private static final int SYNC_READ_TIMEOUT = 40000;
|
||||
private static final int SYNC_CONNECTION_TIMEOUT = 5000;
|
||||
|
||||
private String mRemotePath;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param remotePath Remote path of the file.
|
||||
*/
|
||||
public ReadRemoteFileOperation(String remotePath) {
|
||||
mRemotePath = remotePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the read operation.
|
||||
*
|
||||
* @param client Client object to communicate with the remote ownCloud server.
|
||||
*/
|
||||
@Override
|
||||
protected RemoteOperationResult<RemoteFile> run(OwnCloudClient client) {
|
||||
PropfindMethod propfind;
|
||||
RemoteOperationResult<RemoteFile> result;
|
||||
|
||||
/// take the duty of check the server for the current state of the file there
|
||||
try {
|
||||
// remote request
|
||||
propfind = new PropfindMethod(
|
||||
new URL(client.getUserFilesWebDavUri() + WebdavUtils.encodePath(mRemotePath)),
|
||||
DEPTH_0,
|
||||
DavUtils.getAllPropset());
|
||||
|
||||
propfind.setReadTimeout(SYNC_READ_TIMEOUT, TimeUnit.SECONDS);
|
||||
propfind.setConnectionTimeout(SYNC_CONNECTION_TIMEOUT, TimeUnit.SECONDS);
|
||||
final int status = client.executeHttpMethod(propfind);
|
||||
|
||||
if (status == HttpConstants.HTTP_MULTI_STATUS
|
||||
|| status == HttpConstants.HTTP_OK) {
|
||||
|
||||
final RemoteFile file = new RemoteFile(propfind.getRoot(), AccountUtils.getUserId(mAccount, mContext));
|
||||
|
||||
result = new RemoteOperationResult<>(OK);
|
||||
result.setData(file);
|
||||
|
||||
} else {
|
||||
result = new RemoteOperationResult<>(propfind);
|
||||
client.exhaustResponse(propfind.getResponseBodyAsStream());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
result = new RemoteOperationResult<>(e);
|
||||
Timber.e(e, "Synchronizing file %s", mRemotePath);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2016 ownCloud GmbH.
|
||||
*
|
||||
* 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 com.owncloud.android.lib.common.OwnCloudClient
|
||||
import com.owncloud.android.lib.common.accounts.AccountUtils
|
||||
import com.owncloud.android.lib.common.http.HttpConstants.HTTP_MULTI_STATUS
|
||||
import com.owncloud.android.lib.common.http.HttpConstants.HTTP_OK
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.DavConstants.DEPTH_0
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.DavUtils
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.PropfindMethod
|
||||
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.utils.isOneOf
|
||||
import timber.log.Timber
|
||||
import java.net.URL
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* Remote operation performing the read a file from the ownCloud server.
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
* @author David González Verdugo
|
||||
*/
|
||||
|
||||
class ReadRemoteFileOperation(val remotePath: String) : RemoteOperation<RemoteFile>() {
|
||||
|
||||
/**
|
||||
* Performs the read operation.
|
||||
*
|
||||
* @param client Client object to communicate with the remote ownCloud server.
|
||||
*/
|
||||
@Override
|
||||
override fun run(client: OwnCloudClient): RemoteOperationResult<RemoteFile> {
|
||||
try {
|
||||
val propFind = PropfindMethod(
|
||||
url = URL("${client.userFilesWebDavUri}${WebdavUtils.encodePath(remotePath)}"),
|
||||
depth = DEPTH_0,
|
||||
propertiesToRequest = DavUtils.allPropset
|
||||
).apply {
|
||||
setReadTimeout(SYNC_READ_TIMEOUT, TimeUnit.SECONDS)
|
||||
setConnectionTimeout(SYNC_CONNECTION_TIMEOUT, TimeUnit.SECONDS)
|
||||
}
|
||||
|
||||
val status = client.executeHttpMethod(propFind)
|
||||
Timber.i("Read remote file $remotePath with status ${propFind.statusCode}")
|
||||
|
||||
return if (isSuccess(status)) {
|
||||
// TODO: Remove that !!
|
||||
val remoteFile = RemoteFile.getRemoteFileFromDav(
|
||||
propFind.root!!,
|
||||
AccountUtils.getUserId(mAccount, mContext), mAccount.name
|
||||
)
|
||||
|
||||
RemoteOperationResult<RemoteFile>(RemoteOperationResult.ResultCode.OK).apply {
|
||||
data = remoteFile
|
||||
}
|
||||
} else {
|
||||
RemoteOperationResult<RemoteFile>(propFind).also {
|
||||
client.exhaustResponse(propFind.getResponseBodyAsStream())
|
||||
}
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
return RemoteOperationResult(exception)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSuccess(status: Int) = status.isOneOf(HTTP_MULTI_STATUS, HTTP_OK)
|
||||
|
||||
companion object {
|
||||
private const val SYNC_READ_TIMEOUT = 40_000L
|
||||
private const val SYNC_CONNECTION_TIMEOUT = 5_000L
|
||||
}
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* 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 at.bitfire.dav4jvm.PropertyRegistry;
|
||||
import at.bitfire.dav4jvm.Response;
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.accounts.AccountUtils;
|
||||
import com.owncloud.android.lib.common.http.HttpConstants;
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.DavConstants;
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.DavUtils;
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.PropfindMethod;
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.properties.OCShareTypes;
|
||||
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 timber.log.Timber;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK;
|
||||
|
||||
/**
|
||||
* Remote operation performing the read of remote file or folder in the ownCloud server.
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
* @author David González Verdugo
|
||||
*/
|
||||
|
||||
public class ReadRemoteFolderOperation extends RemoteOperation<ArrayList<RemoteFile>> {
|
||||
|
||||
private String mRemotePath;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param remotePath Remote path of the file.
|
||||
*/
|
||||
public ReadRemoteFolderOperation(String remotePath) {
|
||||
mRemotePath = remotePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the read operation.
|
||||
*
|
||||
* @param client Client object to communicate with the remote ownCloud server.
|
||||
*/
|
||||
@Override
|
||||
protected RemoteOperationResult<ArrayList<RemoteFile>> run(OwnCloudClient client) {
|
||||
RemoteOperationResult<ArrayList<RemoteFile>> result = null;
|
||||
|
||||
try {
|
||||
PropertyRegistry.INSTANCE.register(OCShareTypes.Factory.class.newInstance());
|
||||
PropfindMethod propfindMethod = new PropfindMethod(
|
||||
new URL(client.getUserFilesWebDavUri() + WebdavUtils.encodePath(mRemotePath)),
|
||||
DavConstants.DEPTH_1,
|
||||
DavUtils.getAllPropset());
|
||||
|
||||
int status = client.executeHttpMethod(propfindMethod);
|
||||
|
||||
if (isSuccess(status)) {
|
||||
ArrayList<RemoteFile> mFolderAndFiles = new ArrayList<>();
|
||||
|
||||
// parse data from remote folder
|
||||
mFolderAndFiles.add(
|
||||
new RemoteFile(propfindMethod.getRoot(), AccountUtils.getUserId(mAccount, mContext))
|
||||
);
|
||||
|
||||
// loop to update every child
|
||||
for (Response resource : propfindMethod.getMembers()) {
|
||||
RemoteFile file = new RemoteFile(resource, AccountUtils.getUserId(mAccount, mContext));
|
||||
mFolderAndFiles.add(file);
|
||||
}
|
||||
|
||||
// Result of the operation
|
||||
result = new RemoteOperationResult<>(OK);
|
||||
result.setData(mFolderAndFiles);
|
||||
|
||||
} else { // synchronization failed
|
||||
result = new RemoteOperationResult<>(propfindMethod);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
result = new RemoteOperationResult<>(e);
|
||||
} finally {
|
||||
if (result == null) {
|
||||
Timber.e("Synchronized " + mRemotePath + ": result is null");
|
||||
} else if (result.isSuccess()) {
|
||||
Timber.i("Synchronized " + mRemotePath + ": " + result.getLogMessage());
|
||||
} else {
|
||||
if (result.isException()) {
|
||||
Timber.e(result.getException(), "Synchronized " + mRemotePath + ": " + result.getLogMessage());
|
||||
} else {
|
||||
Timber.e("Synchronized " + mRemotePath + ": " + result.getLogMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isSuccess(int status) {
|
||||
return status == HttpConstants.HTTP_MULTI_STATUS || status == HttpConstants.HTTP_OK;
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* 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 at.bitfire.dav4jvm.PropertyRegistry
|
||||
import com.owncloud.android.lib.common.OwnCloudClient
|
||||
import com.owncloud.android.lib.common.accounts.AccountUtils
|
||||
import com.owncloud.android.lib.common.http.HttpConstants.HTTP_MULTI_STATUS
|
||||
import com.owncloud.android.lib.common.http.HttpConstants.HTTP_OK
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.DavConstants
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.DavUtils
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.PropfindMethod
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.properties.OCShareTypes
|
||||
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.common.utils.isOneOf
|
||||
import timber.log.Timber
|
||||
import java.net.URL
|
||||
|
||||
/**
|
||||
* Remote operation performing the read of remote file or folder in the ownCloud server.
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
* @author David González Verdugo
|
||||
*/
|
||||
class ReadRemoteFolderOperation(
|
||||
val remotePath: String
|
||||
) : RemoteOperation<ArrayList<RemoteFile>>() {
|
||||
|
||||
/**
|
||||
* Performs the read operation.
|
||||
*
|
||||
* @param client Client object to communicate with the remote ownCloud server.
|
||||
*/
|
||||
override fun run(client: OwnCloudClient): RemoteOperationResult<ArrayList<RemoteFile>> {
|
||||
try {
|
||||
PropertyRegistry.register(OCShareTypes.Factory())
|
||||
|
||||
val propfindMethod = PropfindMethod(
|
||||
URL(client.userFilesWebDavUri.toString() + WebdavUtils.encodePath(remotePath)),
|
||||
DavConstants.DEPTH_1,
|
||||
DavUtils.allPropset
|
||||
)
|
||||
|
||||
val status = client.executeHttpMethod(propfindMethod)
|
||||
|
||||
if (isSuccess(status)) {
|
||||
val mFolderAndFiles = ArrayList<RemoteFile>()
|
||||
|
||||
// parse data from remote folder
|
||||
// TODO: Remove that !!
|
||||
val remoteFolder = RemoteFile.getRemoteFileFromDav(
|
||||
davResource = propfindMethod.root!!,
|
||||
userId = AccountUtils.getUserId(mAccount, mContext),
|
||||
userName = mAccount.name
|
||||
)
|
||||
mFolderAndFiles.add(remoteFolder)
|
||||
|
||||
// loop to update every child
|
||||
propfindMethod.members.forEach { resource ->
|
||||
val remoteFile = RemoteFile.getRemoteFileFromDav(
|
||||
davResource = resource,
|
||||
userId = AccountUtils.getUserId(mAccount, mContext),
|
||||
userName = mAccount.name
|
||||
)
|
||||
mFolderAndFiles.add(remoteFile)
|
||||
}
|
||||
|
||||
// Result of the operation
|
||||
return RemoteOperationResult<ArrayList<RemoteFile>>(ResultCode.OK).apply {
|
||||
data = mFolderAndFiles
|
||||
Timber.i("Synchronized $remotePath with ${mFolderAndFiles.size} files. ${this.logMessage}")
|
||||
}
|
||||
} else { // synchronization failed
|
||||
return RemoteOperationResult<ArrayList<RemoteFile>>(propfindMethod).also {
|
||||
Timber.w("Synchronized $remotePath ${it.logMessage}")
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
return RemoteOperationResult<ArrayList<RemoteFile>>(e).also {
|
||||
Timber.e(it.exception, "Synchronized $remotePath")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSuccess(status: Int): Boolean = status.isOneOf(HTTP_OK, HTTP_MULTI_STATUS)
|
||||
}
|
@ -1,363 +0,0 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* 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.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import at.bitfire.dav4jvm.Property;
|
||||
import at.bitfire.dav4jvm.Response;
|
||||
import at.bitfire.dav4jvm.property.CreationDate;
|
||||
import at.bitfire.dav4jvm.property.GetContentLength;
|
||||
import at.bitfire.dav4jvm.property.GetContentType;
|
||||
import at.bitfire.dav4jvm.property.GetETag;
|
||||
import at.bitfire.dav4jvm.property.GetLastModified;
|
||||
import at.bitfire.dav4jvm.property.OCId;
|
||||
import at.bitfire.dav4jvm.property.OCPermissions;
|
||||
import at.bitfire.dav4jvm.property.OCPrivatelink;
|
||||
import at.bitfire.dav4jvm.property.OCSize;
|
||||
import at.bitfire.dav4jvm.property.QuotaAvailableBytes;
|
||||
import at.bitfire.dav4jvm.property.QuotaUsedBytes;
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.properties.OCShareTypes;
|
||||
import com.owncloud.android.lib.resources.shares.ShareType;
|
||||
import timber.log.Timber;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Contains the data of a Remote File from a WebDavEntry
|
||||
*
|
||||
* @author masensio
|
||||
* @author Christian Schabesberger
|
||||
*/
|
||||
|
||||
public class RemoteFile implements Parcelable, Serializable {
|
||||
|
||||
/**
|
||||
* Parcelable Methods
|
||||
*/
|
||||
public static final Parcelable.Creator<RemoteFile> CREATOR = new Parcelable.Creator<RemoteFile>() {
|
||||
@Override
|
||||
public RemoteFile createFromParcel(Parcel source) {
|
||||
return new RemoteFile(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteFile[] newArray(int size) {
|
||||
return new RemoteFile[size];
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Generated - should be refreshed every time the class changes!!
|
||||
*/
|
||||
private static final long serialVersionUID = -8965995357413958539L;
|
||||
private String mRemotePath;
|
||||
private String mMimeType;
|
||||
private long mLength;
|
||||
private long mCreationTimestamp;
|
||||
private long mModifiedTimestamp;
|
||||
private String mEtag;
|
||||
private String mPermissions;
|
||||
private String mRemoteId;
|
||||
private long mSize;
|
||||
private BigDecimal mQuotaUsedBytes;
|
||||
private BigDecimal mQuotaAvailableBytes;
|
||||
private String mPrivateLink;
|
||||
private boolean mSharedByLink;
|
||||
private boolean mSharedWithSharee;
|
||||
|
||||
public RemoteFile() {
|
||||
resetData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new {@link RemoteFile} with given path.
|
||||
* <p>
|
||||
* The path received must be URL-decoded. Path separator must be File.separator, and it must be the first
|
||||
* character in 'path'.
|
||||
*
|
||||
* @param path The remote path of the file.
|
||||
*/
|
||||
public RemoteFile(String path) {
|
||||
resetData();
|
||||
if (path == null || path.length() <= 0 || !path.startsWith(File.separator)) {
|
||||
throw new IllegalArgumentException("Trying to create a OCFile with a non valid remote path: " + path);
|
||||
}
|
||||
mRemotePath = path;
|
||||
mCreationTimestamp = 0;
|
||||
mLength = 0;
|
||||
mMimeType = FileUtils.MIME_DIR;
|
||||
mQuotaUsedBytes = BigDecimal.ZERO;
|
||||
mQuotaAvailableBytes = BigDecimal.ZERO;
|
||||
mPrivateLink = null;
|
||||
}
|
||||
|
||||
public RemoteFile(final Response davResource, String userId) {
|
||||
this(RemoteFileUtil.Companion.getRemotePathFromUrl(davResource.getHref(), userId));
|
||||
final List<Property> properties = davResource.getProperties();
|
||||
|
||||
for (Property property : properties) {
|
||||
if (property instanceof CreationDate) {
|
||||
this.setCreationTimestamp(
|
||||
Long.parseLong(((CreationDate) property).getCreationDate()));
|
||||
}
|
||||
if (property instanceof GetContentLength) {
|
||||
this.setLength(((GetContentLength) property).getContentLength());
|
||||
}
|
||||
if (property instanceof GetContentType) {
|
||||
this.setMimeType(((GetContentType) property).getType());
|
||||
}
|
||||
if (property instanceof GetLastModified) {
|
||||
this.setModifiedTimestamp(((GetLastModified) property).getLastModified());
|
||||
}
|
||||
if (property instanceof GetETag) {
|
||||
this.setEtag(((GetETag) property).getETag());
|
||||
}
|
||||
if (property instanceof OCPermissions) {
|
||||
this.setPermissions(((OCPermissions) property).getPermission());
|
||||
}
|
||||
if (property instanceof OCId) {
|
||||
this.setRemoteId(((OCId) property).getId());
|
||||
}
|
||||
if (property instanceof OCSize) {
|
||||
this.setSize(((OCSize) property).getSize());
|
||||
}
|
||||
if (property instanceof QuotaUsedBytes) {
|
||||
this.setQuotaUsedBytes(
|
||||
BigDecimal.valueOf(((QuotaUsedBytes) property).getQuotaUsedBytes()));
|
||||
}
|
||||
if (property instanceof QuotaAvailableBytes) {
|
||||
this.setQuotaAvailableBytes(
|
||||
BigDecimal.valueOf(((QuotaAvailableBytes) property).getQuotaAvailableBytes()));
|
||||
}
|
||||
if (property instanceof OCPrivatelink) {
|
||||
this.setPrivateLink(((OCPrivatelink) property).getLink());
|
||||
}
|
||||
if (property instanceof OCShareTypes) {
|
||||
LinkedList<String> list = ((OCShareTypes) property).getShareTypes();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
ShareType shareType = ShareType.Companion.fromValue(Integer.parseInt(list.get(i)));
|
||||
if (shareType == null) {
|
||||
Timber.d("Illegal share type value: " + list.get(i));
|
||||
continue;
|
||||
}
|
||||
if (shareType.equals(ShareType.PUBLIC_LINK)) {
|
||||
this.setSharedViaLink(true);
|
||||
} else if (shareType.equals(ShareType.USER) ||
|
||||
shareType.equals(ShareType.FEDERATED) ||
|
||||
shareType.equals(ShareType.GROUP)) {
|
||||
this.setSharedWithSharee(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconstruct from parcel
|
||||
*
|
||||
* @param source The source parcel
|
||||
*/
|
||||
protected RemoteFile(Parcel source) {
|
||||
readFromParcel(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to find out if this file is a folder.
|
||||
*
|
||||
* @return true if it is a folder
|
||||
*/
|
||||
public boolean isFolder() {
|
||||
return mMimeType != null && (mMimeType.equals(FileUtils.MIME_DIR) || mMimeType.equals(FileUtils.MIME_DIR_UNIX));
|
||||
}
|
||||
|
||||
/**
|
||||
* Getters and Setters
|
||||
*/
|
||||
|
||||
public String getRemotePath() {
|
||||
return mRemotePath;
|
||||
}
|
||||
|
||||
public void setRemotePath(String remotePath) {
|
||||
this.mRemotePath = remotePath;
|
||||
}
|
||||
|
||||
public String getMimeType() {
|
||||
return mMimeType;
|
||||
}
|
||||
|
||||
public void setMimeType(String mimeType) {
|
||||
this.mMimeType = mimeType;
|
||||
}
|
||||
|
||||
public long getLength() {
|
||||
return mLength;
|
||||
}
|
||||
|
||||
public void setLength(long length) {
|
||||
this.mLength = length;
|
||||
}
|
||||
|
||||
public long getCreationTimestamp() {
|
||||
return mCreationTimestamp;
|
||||
}
|
||||
|
||||
public void setCreationTimestamp(long creationTimestamp) {
|
||||
this.mCreationTimestamp = creationTimestamp;
|
||||
}
|
||||
|
||||
public long getModifiedTimestamp() {
|
||||
return mModifiedTimestamp;
|
||||
}
|
||||
|
||||
public void setModifiedTimestamp(long modifiedTimestamp) {
|
||||
this.mModifiedTimestamp = modifiedTimestamp;
|
||||
}
|
||||
|
||||
public String getEtag() {
|
||||
return mEtag;
|
||||
}
|
||||
|
||||
public void setEtag(String etag) {
|
||||
this.mEtag = etag;
|
||||
}
|
||||
|
||||
public String getPermissions() {
|
||||
return mPermissions;
|
||||
}
|
||||
|
||||
public void setPermissions(String permissions) {
|
||||
this.mPermissions = permissions;
|
||||
}
|
||||
|
||||
public String getRemoteId() {
|
||||
return mRemoteId;
|
||||
}
|
||||
|
||||
public void setRemoteId(String remoteId) {
|
||||
this.mRemoteId = remoteId;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
public void setSize(long size) {
|
||||
mSize = size;
|
||||
}
|
||||
|
||||
public void setQuotaUsedBytes(BigDecimal quotaUsedBytes) {
|
||||
mQuotaUsedBytes = quotaUsedBytes;
|
||||
}
|
||||
|
||||
public void setQuotaAvailableBytes(BigDecimal quotaAvailableBytes) {
|
||||
mQuotaAvailableBytes = quotaAvailableBytes;
|
||||
}
|
||||
|
||||
public String getPrivateLink() {
|
||||
return mPrivateLink;
|
||||
}
|
||||
|
||||
public void setPrivateLink(String privateLink) {
|
||||
mPrivateLink = privateLink;
|
||||
}
|
||||
|
||||
public void setSharedWithSharee(boolean shareWithSharee) {
|
||||
mSharedWithSharee = shareWithSharee;
|
||||
}
|
||||
|
||||
public boolean isSharedWithSharee() {
|
||||
return mSharedWithSharee;
|
||||
}
|
||||
|
||||
public void setSharedViaLink(boolean sharedViaLink) {
|
||||
mSharedByLink = sharedViaLink;
|
||||
}
|
||||
|
||||
public boolean isSharedByLink() {
|
||||
return mSharedByLink;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used internally. Reset all file properties
|
||||
*/
|
||||
private void resetData() {
|
||||
mRemotePath = null;
|
||||
mMimeType = null;
|
||||
mLength = 0;
|
||||
mCreationTimestamp = 0;
|
||||
mModifiedTimestamp = 0;
|
||||
mEtag = null;
|
||||
mPermissions = null;
|
||||
mRemoteId = null;
|
||||
mSize = 0;
|
||||
mQuotaUsedBytes = null;
|
||||
mQuotaAvailableBytes = null;
|
||||
mPrivateLink = null;
|
||||
mSharedWithSharee = false;
|
||||
mSharedByLink = false;
|
||||
}
|
||||
|
||||
public void readFromParcel(Parcel source) {
|
||||
mRemotePath = source.readString();
|
||||
mMimeType = source.readString();
|
||||
mLength = source.readLong();
|
||||
mCreationTimestamp = source.readLong();
|
||||
mModifiedTimestamp = source.readLong();
|
||||
mEtag = source.readString();
|
||||
mPermissions = source.readString();
|
||||
mRemoteId = source.readString();
|
||||
mSize = source.readLong();
|
||||
mQuotaUsedBytes = (BigDecimal) source.readSerializable();
|
||||
mQuotaAvailableBytes = (BigDecimal) source.readSerializable();
|
||||
mPrivateLink = source.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return this.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(mRemotePath);
|
||||
dest.writeString(mMimeType);
|
||||
dest.writeLong(mLength);
|
||||
dest.writeLong(mCreationTimestamp);
|
||||
dest.writeLong(mModifiedTimestamp);
|
||||
dest.writeString(mEtag);
|
||||
dest.writeString(mPermissions);
|
||||
dest.writeString(mRemoteId);
|
||||
dest.writeLong(mSize);
|
||||
dest.writeSerializable(mQuotaUsedBytes);
|
||||
dest.writeSerializable(mQuotaAvailableBytes);
|
||||
dest.writeString(mPrivateLink);
|
||||
}
|
||||
}
|
@ -0,0 +1,177 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* 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.net.Uri
|
||||
import android.os.Parcelable
|
||||
import at.bitfire.dav4jvm.Response
|
||||
import at.bitfire.dav4jvm.property.CreationDate
|
||||
import at.bitfire.dav4jvm.property.GetContentLength
|
||||
import at.bitfire.dav4jvm.property.GetContentType
|
||||
import at.bitfire.dav4jvm.property.GetETag
|
||||
import at.bitfire.dav4jvm.property.GetLastModified
|
||||
import at.bitfire.dav4jvm.property.OCId
|
||||
import at.bitfire.dav4jvm.property.OCPermissions
|
||||
import at.bitfire.dav4jvm.property.OCPrivatelink
|
||||
import at.bitfire.dav4jvm.property.OCSize
|
||||
import at.bitfire.dav4jvm.property.QuotaAvailableBytes
|
||||
import at.bitfire.dav4jvm.property.QuotaUsedBytes
|
||||
import com.owncloud.android.lib.common.OwnCloudClient
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.properties.OCShareTypes
|
||||
import com.owncloud.android.lib.resources.shares.ShareType
|
||||
import com.owncloud.android.lib.resources.shares.ShareType.Companion.fromValue
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import com.owncloud.android.lib.common.utils.isOneOf
|
||||
import okhttp3.HttpUrl
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
* Contains the data of a Remote File from a WebDavEntry
|
||||
*
|
||||
* The path received must be URL-decoded. Path separator must be File.separator, and it must be the first character in 'path'.
|
||||
*
|
||||
* @author masensio
|
||||
* @author Christian Schabesberger
|
||||
* @author Abel García de Prada
|
||||
*/
|
||||
@Parcelize
|
||||
data class RemoteFile(
|
||||
var remotePath: String,
|
||||
var mimeType: String = "DIR",
|
||||
var length: Long = 0,
|
||||
var creationTimestamp: Long = 0,
|
||||
var modifiedTimestamp: Long = 0,
|
||||
var etag: String? = null,
|
||||
var permissions: String? = null,
|
||||
var remoteId: String? = null,
|
||||
var size: Long = 0,
|
||||
var quotaUsedBytes: BigDecimal? = null,
|
||||
var quotaAvailableBytes: BigDecimal? = null,
|
||||
var privateLink: String? = null,
|
||||
var owner: String,
|
||||
var sharedByLink: Boolean = false,
|
||||
var sharedWithSharee: Boolean = false,
|
||||
) : Parcelable {
|
||||
|
||||
// TODO: Quotas not used. Use or remove them.
|
||||
init {
|
||||
require(
|
||||
!(remotePath.isEmpty() || !remotePath.startsWith(File.separator))
|
||||
) { "Trying to create a OCFile with a non valid remote path: $remotePath" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to find out if this file is a folder.
|
||||
*
|
||||
* @return true if it is a folder
|
||||
*/
|
||||
val isFolder
|
||||
get() = mimeType.isOneOf(MIME_DIR, MIME_DIR_UNIX)
|
||||
|
||||
companion object {
|
||||
|
||||
const val MIME_DIR = "DIR"
|
||||
const val MIME_DIR_UNIX = "httpd/unix-directory"
|
||||
|
||||
fun getRemoteFileFromDav(davResource: Response, userId: String, userName: String): RemoteFile {
|
||||
val remotePath = getRemotePathFromUrl(davResource.href, userId)
|
||||
val remoteFile = RemoteFile(remotePath = remotePath, owner = userName)
|
||||
val properties = davResource.properties
|
||||
|
||||
for (property in properties) {
|
||||
when (property) {
|
||||
is CreationDate -> {
|
||||
remoteFile.creationTimestamp = property.creationDate.toLong()
|
||||
}
|
||||
is GetContentLength -> {
|
||||
remoteFile.length = property.contentLength
|
||||
}
|
||||
is GetContentType -> {
|
||||
property.type?.let { remoteFile.mimeType = it }
|
||||
}
|
||||
is GetLastModified -> {
|
||||
remoteFile.modifiedTimestamp = property.lastModified
|
||||
}
|
||||
is GetETag -> {
|
||||
remoteFile.etag = property.eTag
|
||||
}
|
||||
is OCPermissions -> {
|
||||
remoteFile.permissions = property.permission
|
||||
}
|
||||
is OCId -> {
|
||||
remoteFile.remoteId = property.id
|
||||
}
|
||||
is OCSize -> {
|
||||
remoteFile.size = property.size
|
||||
}
|
||||
is QuotaUsedBytes -> {
|
||||
remoteFile.quotaUsedBytes = BigDecimal.valueOf(property.quotaUsedBytes)
|
||||
}
|
||||
is QuotaAvailableBytes -> {
|
||||
remoteFile.quotaAvailableBytes = BigDecimal.valueOf(property.quotaAvailableBytes)
|
||||
}
|
||||
is OCPrivatelink -> {
|
||||
remoteFile.privateLink = property.link
|
||||
}
|
||||
is OCShareTypes -> {
|
||||
val list = property.shareTypes
|
||||
for (i in list.indices) {
|
||||
val shareType = fromValue(list[i].toInt())
|
||||
if (shareType == null) {
|
||||
Timber.d("Illegal share type value: " + list[i])
|
||||
continue
|
||||
}
|
||||
if (shareType == ShareType.PUBLIC_LINK) {
|
||||
remoteFile.sharedByLink = true
|
||||
} else if (shareType == ShareType.USER || shareType == ShareType.FEDERATED || shareType == ShareType.GROUP) {
|
||||
remoteFile.sharedWithSharee = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return remoteFile
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a relative path from a remote file url
|
||||
*
|
||||
*
|
||||
* Example: url:port/remote.php/dav/files/username/Documents/text.txt => /Documents/text.txt
|
||||
*
|
||||
* @param url remote file url
|
||||
* @param userId file owner
|
||||
* @return remote relative path of the file
|
||||
*/
|
||||
private fun getRemotePathFromUrl(url: HttpUrl, userId: String): String {
|
||||
val davFilesPath = OwnCloudClient.WEBDAV_FILES_PATH_4_0 + userId
|
||||
val absoluteDavPath = Uri.decode(url.encodedPath)
|
||||
val pathToOc = absoluteDavPath.split(davFilesPath).first()
|
||||
return absoluteDavPath.replace(pathToOc + davFilesPath, "")
|
||||
}
|
||||
}
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* 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.net.Uri;
|
||||
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.http.HttpConstants;
|
||||
import com.owncloud.android.lib.common.http.methods.nonwebdav.DeleteMethod;
|
||||
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 timber.log.Timber;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK;
|
||||
|
||||
/**
|
||||
* Remote operation performing the removal of a remote file or folder in the ownCloud server.
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
* @author David González Verdugo
|
||||
*/
|
||||
public class RemoveRemoteFileOperation extends RemoteOperation {
|
||||
private String mRemotePath;
|
||||
|
||||
protected boolean removeChunksFolder = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param remotePath RemotePath of the remote file or folder to remove from the server
|
||||
*/
|
||||
public RemoveRemoteFileOperation(String remotePath) {
|
||||
mRemotePath = remotePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the rename operation.
|
||||
*
|
||||
* @param client Client object to communicate with the remote ownCloud server.
|
||||
*/
|
||||
@Override
|
||||
protected RemoteOperationResult run(OwnCloudClient client) {
|
||||
RemoteOperationResult result;
|
||||
|
||||
try {
|
||||
Uri srcWebDavUri = removeChunksFolder ? client.getUploadsWebDavUri() : client.getUserFilesWebDavUri();
|
||||
|
||||
DeleteMethod deleteMethod = new DeleteMethod(
|
||||
new URL(srcWebDavUri + WebdavUtils.encodePath(mRemotePath)));
|
||||
|
||||
int status = client.executeHttpMethod(deleteMethod);
|
||||
|
||||
result = isSuccess(status) ?
|
||||
new RemoteOperationResult<>(OK) :
|
||||
new RemoteOperationResult<>(deleteMethod);
|
||||
|
||||
Timber.i("Remove " + mRemotePath + ": " + result.getLogMessage());
|
||||
|
||||
} catch (Exception e) {
|
||||
result = new RemoteOperationResult<>(e);
|
||||
Timber.e(e, "Remove " + mRemotePath + ": " + result.getLogMessage());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isSuccess(int status) {
|
||||
return status == HttpConstants.HTTP_OK || status == HttpConstants.HTTP_NO_CONTENT;
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* 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.net.Uri
|
||||
import com.owncloud.android.lib.common.OwnCloudClient
|
||||
import com.owncloud.android.lib.common.http.HttpConstants.HTTP_NO_CONTENT
|
||||
import com.owncloud.android.lib.common.http.HttpConstants.HTTP_OK
|
||||
import com.owncloud.android.lib.common.http.methods.nonwebdav.DeleteMethod
|
||||
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.common.utils.isOneOf
|
||||
import timber.log.Timber
|
||||
import java.net.URL
|
||||
|
||||
/**
|
||||
* Remote operation performing the removal of a remote file or folder in the ownCloud server.
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
* @author David González Verdugo
|
||||
* @author Abel García de Prada
|
||||
*/
|
||||
open class RemoveRemoteFileOperation(
|
||||
private val remotePath: String
|
||||
) : RemoteOperation<Unit>() {
|
||||
|
||||
override fun run(client: OwnCloudClient): RemoteOperationResult<Unit> {
|
||||
var result: RemoteOperationResult<Unit>
|
||||
try {
|
||||
val srcWebDavUri = getSrcWebDavUriForClient(client)
|
||||
val deleteMethod = DeleteMethod(
|
||||
URL(srcWebDavUri.toString() + WebdavUtils.encodePath(remotePath))
|
||||
)
|
||||
val status = client.executeHttpMethod(deleteMethod)
|
||||
|
||||
result = if (isSuccess(status)) {
|
||||
RemoteOperationResult<Unit>(ResultCode.OK)
|
||||
} else {
|
||||
RemoteOperationResult<Unit>(deleteMethod)
|
||||
}
|
||||
Timber.i("Remove $remotePath: ${result.logMessage}")
|
||||
} catch (e: Exception) {
|
||||
result = RemoteOperationResult<Unit>(e)
|
||||
Timber.e(e, "Remove $remotePath: ${result.logMessage}")
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* For standard removals, we will use [OwnCloudClient.getUserFilesWebDavUri].
|
||||
* In case we need a different source Uri, override this method.
|
||||
*/
|
||||
open fun getSrcWebDavUriForClient(client: OwnCloudClient): Uri = client.userFilesWebDavUri
|
||||
|
||||
private fun isSuccess(status: Int) = status.isOneOf(HTTP_OK, HTTP_NO_CONTENT)
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2019 ownCloud GmbH.
|
||||
*
|
||||
* 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 com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.http.HttpConstants;
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.MoveMethod;
|
||||
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 timber.log.Timber;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Remote operation performing the rename of a remote file or folder in the ownCloud server.
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
*/
|
||||
public class RenameRemoteFileOperation extends RemoteOperation {
|
||||
|
||||
private static final int RENAME_READ_TIMEOUT = 600000;
|
||||
private static final int RENAME_CONNECTION_TIMEOUT = 5000;
|
||||
|
||||
private String mOldName;
|
||||
private String mOldRemotePath;
|
||||
private String mNewName;
|
||||
private String mNewRemotePath;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param oldName Old name of the file.
|
||||
* @param oldRemotePath Old remote path of the file.
|
||||
* @param newName New name to set as the name of file.
|
||||
* @param isFolder 'true' for folder and 'false' for files
|
||||
*/
|
||||
public RenameRemoteFileOperation(String oldName, String oldRemotePath, String newName,
|
||||
boolean isFolder) {
|
||||
mOldName = oldName;
|
||||
mOldRemotePath = oldRemotePath;
|
||||
mNewName = newName;
|
||||
|
||||
String parent = (new File(mOldRemotePath)).getParent();
|
||||
parent = (parent.endsWith(File.separator)) ? parent : parent + File.separator;
|
||||
mNewRemotePath = parent + mNewName;
|
||||
if (isFolder) {
|
||||
mNewRemotePath += File.separator;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the rename operation.
|
||||
*
|
||||
* @param client Client object to communicate with the remote ownCloud server.
|
||||
*/
|
||||
@Override
|
||||
protected RemoteOperationResult run(OwnCloudClient client) {
|
||||
try {
|
||||
if (mNewName.equals(mOldName)) {
|
||||
return new RemoteOperationResult<>(ResultCode.OK);
|
||||
}
|
||||
|
||||
if (targetPathIsUsed(client)) {
|
||||
return new RemoteOperationResult<>(ResultCode.INVALID_OVERWRITE);
|
||||
}
|
||||
|
||||
final MoveMethod move = new MoveMethod(
|
||||
new URL(client.getUserFilesWebDavUri() +
|
||||
WebdavUtils.encodePath(mOldRemotePath)),
|
||||
client.getUserFilesWebDavUri() + WebdavUtils.encodePath(mNewRemotePath), false);
|
||||
|
||||
move.setReadTimeout(RENAME_READ_TIMEOUT, TimeUnit.SECONDS);
|
||||
move.setConnectionTimeout(RENAME_READ_TIMEOUT, TimeUnit.SECONDS);
|
||||
|
||||
final int status = client.executeHttpMethod(move);
|
||||
final RemoteOperationResult result =
|
||||
(status == HttpConstants.HTTP_CREATED || status == HttpConstants.HTTP_NO_CONTENT)
|
||||
? new RemoteOperationResult<>(ResultCode.OK)
|
||||
: new RemoteOperationResult<>(move);
|
||||
|
||||
Timber.i("Rename " + mOldRemotePath + " to " + mNewRemotePath + ": " + result.getLogMessage());
|
||||
client.exhaustResponse(move.getResponseBodyAsStream());
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
final RemoteOperationResult result = new RemoteOperationResult<>(e);
|
||||
Timber.e(e,
|
||||
"Rename " + mOldRemotePath + " to " + ((mNewRemotePath == null) ? mNewName : mNewRemotePath) + ":" +
|
||||
" " + result.getLogMessage());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a file with the new name already exists.
|
||||
*
|
||||
* @return 'True' if the target path is already used by an existing file.
|
||||
*/
|
||||
private boolean targetPathIsUsed(OwnCloudClient client) {
|
||||
CheckPathExistenceRemoteOperation checkPathExistenceRemoteOperation =
|
||||
new CheckPathExistenceRemoteOperation(mNewRemotePath, false);
|
||||
RemoteOperationResult exists = checkPathExistenceRemoteOperation.execute(client);
|
||||
return exists.isSuccess();
|
||||
}
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2021 ownCloud GmbH.
|
||||
*
|
||||
* 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 com.owncloud.android.lib.common.OwnCloudClient
|
||||
import com.owncloud.android.lib.common.http.HttpConstants
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.MoveMethod
|
||||
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.common.utils.isOneOf
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* Remote operation performing the rename of a remote file or folder in the ownCloud server.
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
*/
|
||||
class RenameRemoteFileOperation(
|
||||
private val oldName: String,
|
||||
private val oldRemotePath: String,
|
||||
private val newName: String,
|
||||
isFolder: Boolean,
|
||||
) : RemoteOperation<Unit>() {
|
||||
|
||||
private var newRemotePath: String
|
||||
|
||||
init {
|
||||
var parent = (File(oldRemotePath)).parent ?: throw IllegalArgumentException()
|
||||
if (!parent.endsWith(File.separator)) {
|
||||
parent = parent.plus(File.separator)
|
||||
}
|
||||
newRemotePath = parent.plus(newName)
|
||||
if (isFolder) {
|
||||
newRemotePath.plus(File.separator)
|
||||
}
|
||||
}
|
||||
|
||||
override fun run(client: OwnCloudClient): RemoteOperationResult<Unit> {
|
||||
var result: RemoteOperationResult<Unit>
|
||||
try {
|
||||
if (newName == oldName) {
|
||||
return RemoteOperationResult<Unit>(ResultCode.OK)
|
||||
}
|
||||
|
||||
if (targetPathIsUsed(client)) {
|
||||
return RemoteOperationResult<Unit>(ResultCode.INVALID_OVERWRITE)
|
||||
}
|
||||
|
||||
val moveMethod: MoveMethod = MoveMethod(
|
||||
url = URL(client.userFilesWebDavUri.toString() + WebdavUtils.encodePath(oldRemotePath)),
|
||||
destinationUrl = client.userFilesWebDavUri.toString() + WebdavUtils.encodePath(newRemotePath),
|
||||
).apply {
|
||||
setReadTimeout(RENAME_READ_TIMEOUT, TimeUnit.MILLISECONDS)
|
||||
setConnectionTimeout(RENAME_CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)
|
||||
}
|
||||
val status = client.executeHttpMethod(moveMethod)
|
||||
|
||||
result = if (isSuccess(status)) {
|
||||
RemoteOperationResult<Unit>(ResultCode.OK)
|
||||
} else {
|
||||
RemoteOperationResult<Unit>(moveMethod)
|
||||
}
|
||||
|
||||
Timber.i("Rename $oldRemotePath to $newRemotePath: ${result.logMessage}")
|
||||
client.exhaustResponse(moveMethod.getResponseBodyAsStream())
|
||||
return result
|
||||
} catch (exception: Exception) {
|
||||
result = RemoteOperationResult<Unit>(exception)
|
||||
Timber.e(exception, "Rename $oldRemotePath to $newName: ${result.logMessage}")
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a file with the new name already exists.
|
||||
*
|
||||
* @return 'True' if the target path is already used by an existing file.
|
||||
*/
|
||||
private fun targetPathIsUsed(client: OwnCloudClient): Boolean {
|
||||
val checkPathExistenceRemoteOperation = CheckPathExistenceRemoteOperation(newRemotePath, false)
|
||||
val exists = checkPathExistenceRemoteOperation.execute(client)
|
||||
return exists.isSuccess
|
||||
}
|
||||
|
||||
private fun isSuccess(status: Int) = status.isOneOf(HttpConstants.HTTP_CREATED, HttpConstants.HTTP_NO_CONTENT)
|
||||
|
||||
companion object {
|
||||
private const val RENAME_READ_TIMEOUT = 10_000L
|
||||
private const val RENAME_CONNECTION_TIMEOUT = 5_000L
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2021 ownCloud GmbH.
|
||||
* Copyright (C) 2022 ownCloud GmbH.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -24,22 +24,15 @@
|
||||
|
||||
package com.owncloud.android.lib.resources.files
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.net.Uri
|
||||
import android.provider.OpenableColumns
|
||||
import com.owncloud.android.lib.common.OwnCloudClient
|
||||
import com.owncloud.android.lib.common.http.HttpConstants
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.PutMethod
|
||||
import com.owncloud.android.lib.common.network.ContentUriRequestBody
|
||||
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 okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.RequestBody
|
||||
import okio.BufferedSink
|
||||
import okio.source
|
||||
import com.owncloud.android.lib.common.utils.isOneOf
|
||||
import timber.log.Timber
|
||||
import java.io.IOException
|
||||
import java.net.URL
|
||||
|
||||
class UploadFileFromContentUriOperation(
|
||||
@ -70,34 +63,6 @@ class UploadFileFromContentUriOperation(
|
||||
}
|
||||
|
||||
fun isSuccess(status: Int): Boolean {
|
||||
return status == HttpConstants.HTTP_OK || status == HttpConstants.HTTP_CREATED || status == HttpConstants.HTTP_NO_CONTENT
|
||||
}
|
||||
}
|
||||
|
||||
class ContentUriRequestBody(
|
||||
private val contentResolver: ContentResolver,
|
||||
private val contentUri: Uri
|
||||
) : RequestBody() {
|
||||
|
||||
override fun contentType(): MediaType? {
|
||||
val contentType = contentResolver.getType(contentUri) ?: return null
|
||||
return contentType.toMediaTypeOrNull()
|
||||
}
|
||||
|
||||
override fun contentLength(): Long {
|
||||
contentResolver.query(contentUri, null, null, null, null)?.use { cursor ->
|
||||
val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)
|
||||
cursor.moveToFirst()
|
||||
return cursor.getLong(sizeIndex)
|
||||
} ?: return -1
|
||||
}
|
||||
|
||||
override fun writeTo(sink: BufferedSink) {
|
||||
val inputStream = contentResolver.openInputStream(contentUri)
|
||||
?: throw IOException("Couldn't open content URI for reading: $contentUri")
|
||||
|
||||
inputStream.source().use { source ->
|
||||
sink.writeAll(source)
|
||||
}
|
||||
return status.isOneOf(HttpConstants.HTTP_OK, HttpConstants.HTTP_CREATED, HttpConstants.HTTP_NO_CONTENT)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,145 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2022 ownCloud GmbH.
|
||||
*
|
||||
* 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
|
||||
* NONINFINGEMENT. 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 com.owncloud.android.lib.common.OwnCloudClient
|
||||
import com.owncloud.android.lib.common.http.HttpConstants
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.PutMethod
|
||||
import com.owncloud.android.lib.common.network.FileRequestBody
|
||||
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener
|
||||
import com.owncloud.android.lib.common.network.WebdavUtils
|
||||
import com.owncloud.android.lib.common.operations.OperationCancelledException
|
||||
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.common.utils.isOneOf
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
/**
|
||||
* Remote operation performing the upload of a remote file to the ownCloud server.
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
* @author David González Verdugo
|
||||
* @author Abel García de Prada
|
||||
*/
|
||||
open class UploadFileFromFileSystemOperation(
|
||||
val localPath: String,
|
||||
val remotePath: String,
|
||||
val mimeType: String,
|
||||
val lastModifiedTimestamp: String,
|
||||
val requiredEtag: String?,
|
||||
) : RemoteOperation<Unit>() {
|
||||
|
||||
protected val cancellationRequested = AtomicBoolean(false)
|
||||
protected var putMethod: PutMethod? = null
|
||||
protected val dataTransferListener: MutableSet<OnDatatransferProgressListener> = HashSet()
|
||||
protected var fileRequestBody: FileRequestBody? = null
|
||||
|
||||
var etag: String = ""
|
||||
|
||||
override fun run(client: OwnCloudClient): RemoteOperationResult<Unit> {
|
||||
var result: RemoteOperationResult<Unit>
|
||||
try {
|
||||
if (cancellationRequested.get()) {
|
||||
// the operation was cancelled before getting it's turn to be executed in the queue of uploads
|
||||
result = RemoteOperationResult<Unit>(OperationCancelledException())
|
||||
Timber.i("Upload of $localPath to $remotePath has been cancelled")
|
||||
} else {
|
||||
// perform the upload
|
||||
result = uploadFile(client)
|
||||
Timber.i("Upload of $localPath to $remotePath: ${result.logMessage}")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
if (putMethod?.isAborted == true) {
|
||||
result = RemoteOperationResult<Unit>(OperationCancelledException())
|
||||
Timber.e(result.exception, "Upload of $localPath to $remotePath has been aborted with this message: ${result.logMessage}")
|
||||
} else {
|
||||
result = RemoteOperationResult<Unit>(e)
|
||||
Timber.e(result.exception, "Upload of $localPath to $remotePath has failed with this message: ${result.logMessage}")
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
protected open fun uploadFile(client: OwnCloudClient): RemoteOperationResult<Unit> {
|
||||
val fileToUpload = File(localPath)
|
||||
val mediaType: MediaType? = mimeType.toMediaTypeOrNull()
|
||||
|
||||
fileRequestBody = FileRequestBody(fileToUpload, mediaType).also {
|
||||
synchronized(dataTransferListener) { it.addDatatransferProgressListeners(dataTransferListener) }
|
||||
}
|
||||
|
||||
putMethod = PutMethod(URL(client.userFilesWebDavUri.toString() + WebdavUtils.encodePath(remotePath)), fileRequestBody!!).apply {
|
||||
retryOnConnectionFailure = false
|
||||
if (!requiredEtag.isNullOrBlank()) {
|
||||
addRequestHeader(HttpConstants.IF_MATCH_HEADER, requiredEtag)
|
||||
}
|
||||
addRequestHeader(HttpConstants.OC_TOTAL_LENGTH_HEADER, fileToUpload.length().toString())
|
||||
addRequestHeader(HttpConstants.OC_X_OC_MTIME_HEADER, lastModifiedTimestamp)
|
||||
}
|
||||
|
||||
val status = client.executeHttpMethod(putMethod)
|
||||
return if (isSuccess(status)) {
|
||||
etag = WebdavUtils.getEtagFromResponse(putMethod)
|
||||
// Get rid of extra quotas
|
||||
etag = etag.replace("\"", "")
|
||||
if (etag.isEmpty()) {
|
||||
Timber.e("Could not read eTag from response uploading %s", localPath)
|
||||
} else {
|
||||
Timber.d("File uploaded successfully. New etag for file ${fileToUpload.name} is $etag")
|
||||
}
|
||||
RemoteOperationResult<Unit>(ResultCode.OK).apply { data = Unit }
|
||||
} else { // synchronization failed
|
||||
RemoteOperationResult<Unit>(putMethod)
|
||||
}
|
||||
}
|
||||
|
||||
fun addDataTransferProgressListener(listener: OnDatatransferProgressListener) {
|
||||
synchronized(dataTransferListener) { dataTransferListener.add(listener) }
|
||||
fileRequestBody?.addDatatransferProgressListener(listener)
|
||||
}
|
||||
|
||||
fun removeDataTransferProgressListener(listener: OnDatatransferProgressListener) {
|
||||
synchronized(dataTransferListener) { dataTransferListener.remove(listener) }
|
||||
fileRequestBody?.removeDatatransferProgressListener(listener)
|
||||
}
|
||||
|
||||
fun cancel() {
|
||||
synchronized(cancellationRequested) {
|
||||
cancellationRequested.set(true)
|
||||
putMethod?.abort()
|
||||
}
|
||||
}
|
||||
|
||||
fun isSuccess(status: Int): Boolean {
|
||||
return status.isOneOf(HttpConstants.HTTP_OK, HttpConstants.HTTP_CREATED, HttpConstants.HTTP_NO_CONTENT)
|
||||
}
|
||||
}
|
@ -1,181 +0,0 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* 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 com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.http.HttpConstants;
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.PutMethod;
|
||||
import com.owncloud.android.lib.common.network.FileRequestBody;
|
||||
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
|
||||
import com.owncloud.android.lib.common.network.WebdavUtils;
|
||||
import com.owncloud.android.lib.common.operations.OperationCancelledException;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import okhttp3.MediaType;
|
||||
import timber.log.Timber;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK;
|
||||
|
||||
/**
|
||||
* Remote operation performing the upload of a remote file to the ownCloud server.
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
* @author David González Verdugo
|
||||
*/
|
||||
|
||||
public class UploadRemoteFileOperation extends RemoteOperation {
|
||||
|
||||
protected final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
|
||||
protected String mLocalPath;
|
||||
protected String mRemotePath;
|
||||
protected String mMimeType;
|
||||
protected String mFileLastModifTimestamp;
|
||||
protected PutMethod mPutMethod = null;
|
||||
protected String mRequiredEtag = null;
|
||||
protected Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<>();
|
||||
|
||||
protected FileRequestBody mFileRequestBody = null;
|
||||
|
||||
public UploadRemoteFileOperation(String localPath, String remotePath, String mimeType,
|
||||
String fileLastModifTimestamp) {
|
||||
mLocalPath = localPath;
|
||||
mRemotePath = remotePath;
|
||||
mMimeType = mimeType;
|
||||
mFileLastModifTimestamp = fileLastModifTimestamp;
|
||||
}
|
||||
|
||||
public UploadRemoteFileOperation(String localPath, String remotePath, String mimeType,
|
||||
String requiredEtag, String fileLastModifTimestamp) {
|
||||
this(localPath, remotePath, mimeType, fileLastModifTimestamp);
|
||||
mRequiredEtag = requiredEtag;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RemoteOperationResult run(OwnCloudClient client) {
|
||||
RemoteOperationResult result;
|
||||
|
||||
try {
|
||||
|
||||
if (mCancellationRequested.get()) {
|
||||
// the operation was cancelled before getting it's turn to be executed in the queue of uploads
|
||||
result = new RemoteOperationResult<>(new OperationCancelledException());
|
||||
} else {
|
||||
// perform the upload
|
||||
result = uploadFile(client);
|
||||
Timber.i("Upload of " + mLocalPath + " to " + mRemotePath + ": " + result.getLogMessage());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
if (mPutMethod != null && mPutMethod.isAborted()) {
|
||||
result = new RemoteOperationResult<>(new OperationCancelledException());
|
||||
Timber.e(result.getException(),
|
||||
"Upload of " + mLocalPath + " to " + mRemotePath + ": " + result.getLogMessage());
|
||||
} else {
|
||||
result = new RemoteOperationResult<>(e);
|
||||
Timber.e(e, "Upload of " + mLocalPath + " to " + mRemotePath + ": " + result.getLogMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected RemoteOperationResult<?> uploadFile(OwnCloudClient client) throws Exception {
|
||||
|
||||
File fileToUpload = new File(mLocalPath);
|
||||
|
||||
MediaType mediaType = MediaType.parse(mMimeType);
|
||||
|
||||
mFileRequestBody = new FileRequestBody(fileToUpload, mediaType);
|
||||
|
||||
synchronized (mDataTransferListeners) {
|
||||
mFileRequestBody.addDatatransferProgressListeners(mDataTransferListeners);
|
||||
}
|
||||
|
||||
mPutMethod = new PutMethod(
|
||||
new URL(client.getUserFilesWebDavUri() + WebdavUtils.encodePath(mRemotePath)), mFileRequestBody);
|
||||
|
||||
mPutMethod.setRetryOnConnectionFailure(false);
|
||||
|
||||
if (mRequiredEtag != null && mRequiredEtag.length() > 0) {
|
||||
mPutMethod.addRequestHeader(HttpConstants.IF_MATCH_HEADER, mRequiredEtag);
|
||||
}
|
||||
|
||||
mPutMethod.addRequestHeader(HttpConstants.OC_TOTAL_LENGTH_HEADER, String.valueOf(fileToUpload.length()));
|
||||
mPutMethod.addRequestHeader(HttpConstants.OC_X_OC_MTIME_HEADER, mFileLastModifTimestamp);
|
||||
|
||||
int status = client.executeHttpMethod(mPutMethod);
|
||||
|
||||
if (isSuccess(status)) {
|
||||
return new RemoteOperationResult<>(OK);
|
||||
|
||||
} else { // synchronization failed
|
||||
return new RemoteOperationResult<>(mPutMethod);
|
||||
}
|
||||
}
|
||||
|
||||
public Set<OnDatatransferProgressListener> getDataTransferListeners() {
|
||||
return mDataTransferListeners;
|
||||
}
|
||||
|
||||
public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
|
||||
synchronized (mDataTransferListeners) {
|
||||
mDataTransferListeners.add(listener);
|
||||
}
|
||||
if (mFileRequestBody != null) {
|
||||
mFileRequestBody.addDatatransferProgressListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
|
||||
synchronized (mDataTransferListeners) {
|
||||
mDataTransferListeners.remove(listener);
|
||||
}
|
||||
if (mFileRequestBody != null) {
|
||||
mFileRequestBody.removeDatatransferProgressListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
synchronized (mCancellationRequested) {
|
||||
mCancellationRequested.set(true);
|
||||
if (mPutMethod != null) {
|
||||
mPutMethod.abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSuccess(int status) {
|
||||
return ((status == HttpConstants.HTTP_OK || status == HttpConstants.HTTP_CREATED ||
|
||||
status == HttpConstants.HTTP_NO_CONTENT));
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2022 ownCloud GmbH.
|
||||
*
|
||||
* 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.chunks
|
||||
|
||||
import com.owncloud.android.lib.common.OwnCloudClient
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.PutMethod
|
||||
import com.owncloud.android.lib.common.network.ChunkFromFileRequestBody
|
||||
import com.owncloud.android.lib.common.operations.OperationCancelledException
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode
|
||||
import com.owncloud.android.lib.resources.files.FileUtils.MODE_READ_ONLY
|
||||
import com.owncloud.android.lib.resources.files.UploadFileFromFileSystemOperation
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.io.RandomAccessFile
|
||||
import java.net.URL
|
||||
import java.nio.channels.FileChannel
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.math.ceil
|
||||
|
||||
/**
|
||||
* Remote operation performing the chunked upload of a remote file to the ownCloud server.
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* @author David González Verdugo
|
||||
* @author Abel García de Prada
|
||||
*/
|
||||
class ChunkedUploadFromFileSystemOperation(
|
||||
private val transferId: String,
|
||||
localPath: String,
|
||||
remotePath: String,
|
||||
mimeType: String,
|
||||
lastModifiedTimestamp: String,
|
||||
requiredEtag: String?,
|
||||
) : UploadFileFromFileSystemOperation(
|
||||
localPath = localPath,
|
||||
remotePath = remotePath,
|
||||
mimeType = mimeType,
|
||||
lastModifiedTimestamp = lastModifiedTimestamp,
|
||||
requiredEtag = requiredEtag
|
||||
) {
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun uploadFile(client: OwnCloudClient): RemoteOperationResult<Unit> {
|
||||
lateinit var result: RemoteOperationResult<Unit>
|
||||
|
||||
val fileToUpload = File(localPath)
|
||||
val mediaType: MediaType? = mimeType.toMediaTypeOrNull()
|
||||
val raf = RandomAccessFile(fileToUpload, MODE_READ_ONLY)
|
||||
val channel: FileChannel = raf.channel
|
||||
|
||||
val fileRequestBody = ChunkFromFileRequestBody(fileToUpload, mediaType, channel).also {
|
||||
synchronized(dataTransferListener) { it.addDatatransferProgressListeners(dataTransferListener) }
|
||||
}
|
||||
|
||||
val uriPrefix = client.uploadsWebDavUri.toString() + File.separator + transferId
|
||||
val totalLength = fileToUpload.length()
|
||||
val chunkCount = ceil(totalLength.toDouble() / CHUNK_SIZE).toLong()
|
||||
var offset: Long = 0
|
||||
|
||||
for (chunkIndex in 0..chunkCount) {
|
||||
fileRequestBody.setOffset(offset)
|
||||
|
||||
if (cancellationRequested.get()) {
|
||||
result = RemoteOperationResult<Unit>(OperationCancelledException())
|
||||
break
|
||||
} else {
|
||||
putMethod = PutMethod(URL(uriPrefix + File.separator + chunkIndex), fileRequestBody).apply {
|
||||
if (chunkIndex == chunkCount - 1) {
|
||||
// Added a high timeout to the last chunk due to when the last chunk
|
||||
// arrives to the server with the last PUT, all chunks get assembled
|
||||
// within that PHP request, so last one takes longer.
|
||||
setReadTimeout(LAST_CHUNK_TIMEOUT.toLong(), TimeUnit.MILLISECONDS)
|
||||
}
|
||||
}
|
||||
|
||||
val status = client.executeHttpMethod(putMethod)
|
||||
|
||||
Timber.d("Upload of $localPath to $remotePath, chunk index $chunkIndex, count $chunkCount, HTTP result status $status")
|
||||
|
||||
if (isSuccess(status)) {
|
||||
result = RemoteOperationResult<Unit>(ResultCode.OK)
|
||||
} else {
|
||||
result = RemoteOperationResult<Unit>(putMethod)
|
||||
break
|
||||
}
|
||||
}
|
||||
offset += CHUNK_SIZE
|
||||
}
|
||||
channel.close()
|
||||
raf.close()
|
||||
return result
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val CHUNK_SIZE = 10_240_000L // 10 MB
|
||||
private const val LAST_CHUNK_TIMEOUT = 900_000 // 15 mins.
|
||||
}
|
||||
}
|
@ -1,130 +0,0 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* 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.chunks;
|
||||
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.PutMethod;
|
||||
import com.owncloud.android.lib.common.network.ChunkFromFileRequestBody;
|
||||
import com.owncloud.android.lib.common.operations.OperationCancelledException;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.resources.files.UploadRemoteFileOperation;
|
||||
import okhttp3.MediaType;
|
||||
import timber.log.Timber;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK;
|
||||
|
||||
/**
|
||||
* Remote operation performing the chunked upload of a remote file to the ownCloud server.
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* @author David González Verdugo
|
||||
*/
|
||||
public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation {
|
||||
|
||||
public static final long CHUNK_SIZE = 1024000;
|
||||
private static final int LAST_CHUNK_TIMEOUT = 900000; //15 mins.
|
||||
|
||||
private String mTransferId;
|
||||
|
||||
public ChunkedUploadRemoteFileOperation(String transferId, String localPath, String remotePath, String mimeType,
|
||||
String requiredEtag, String fileLastModifTimestamp) {
|
||||
super(localPath, remotePath, mimeType, requiredEtag, fileLastModifTimestamp);
|
||||
mTransferId = transferId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RemoteOperationResult uploadFile(OwnCloudClient client) throws Exception {
|
||||
int status;
|
||||
RemoteOperationResult result = null;
|
||||
FileChannel channel;
|
||||
RandomAccessFile raf;
|
||||
|
||||
File fileToUpload = new File(mLocalPath);
|
||||
MediaType mediaType = MediaType.parse(mMimeType);
|
||||
|
||||
raf = new RandomAccessFile(fileToUpload, "r");
|
||||
channel = raf.getChannel();
|
||||
|
||||
mFileRequestBody = new ChunkFromFileRequestBody(fileToUpload, mediaType, channel, CHUNK_SIZE);
|
||||
|
||||
synchronized (mDataTransferListeners) {
|
||||
mFileRequestBody.addDatatransferProgressListeners(mDataTransferListeners);
|
||||
}
|
||||
|
||||
long offset = 0;
|
||||
String uriPrefix = client.getUploadsWebDavUri() + File.separator + mTransferId;
|
||||
long totalLength = fileToUpload.length();
|
||||
long chunkCount = (long) Math.ceil((double) totalLength / CHUNK_SIZE);
|
||||
|
||||
for (int chunkIndex = 0; chunkIndex < chunkCount; chunkIndex++, offset += CHUNK_SIZE) {
|
||||
|
||||
((ChunkFromFileRequestBody) mFileRequestBody).setOffset(offset);
|
||||
|
||||
if (mCancellationRequested.get()) {
|
||||
result = new RemoteOperationResult<>(new OperationCancelledException());
|
||||
break;
|
||||
} else {
|
||||
mPutMethod = new PutMethod(
|
||||
new URL(uriPrefix + File.separator + chunkIndex), mFileRequestBody);
|
||||
|
||||
if (chunkIndex == chunkCount - 1) {
|
||||
// Added a high timeout to the last chunk due to when the last chunk
|
||||
// arrives to the server with the last PUT, all chunks get assembled
|
||||
// within that PHP request, so last one takes longer.
|
||||
mPutMethod.setReadTimeout(LAST_CHUNK_TIMEOUT, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
status = client.executeHttpMethod(mPutMethod);
|
||||
|
||||
Timber.d("Upload of " + mLocalPath + " to " + mRemotePath +
|
||||
", chunk index " + chunkIndex + ", count " + chunkCount +
|
||||
", HTTP result status " + status);
|
||||
|
||||
if (isSuccess(status)) {
|
||||
result = new RemoteOperationResult<>(OK);
|
||||
} else {
|
||||
result = new RemoteOperationResult<>(mPutMethod);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (channel != null) {
|
||||
channel.close();
|
||||
}
|
||||
|
||||
if (raf != null) {
|
||||
raf.close();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
* Copyright (C) 2021 ownCloud GmbH.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -21,30 +21,38 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
package com.owncloud.android.lib.resources.files.chunks
|
||||
|
||||
package com.owncloud.android.lib.resources.files.chunks;
|
||||
|
||||
import com.owncloud.android.lib.resources.files.MoveRemoteFileOperation;
|
||||
import android.net.Uri
|
||||
import com.owncloud.android.lib.common.OwnCloudClient
|
||||
import com.owncloud.android.lib.common.http.HttpConstants
|
||||
import com.owncloud.android.lib.common.http.methods.webdav.MoveMethod
|
||||
import com.owncloud.android.lib.resources.files.MoveRemoteFileOperation
|
||||
|
||||
/**
|
||||
* Remote operation to move the file built from chunks after uploading it
|
||||
*
|
||||
* @author David González Verdugo
|
||||
* @author Abel García de Prada
|
||||
*/
|
||||
public class MoveRemoteChunksFileOperation extends MoveRemoteFileOperation {
|
||||
class MoveRemoteChunksFileOperation(
|
||||
sourceRemotePath: String,
|
||||
targetRemotePath: String,
|
||||
private val fileLastModificationTimestamp: String,
|
||||
private val fileLength: Long
|
||||
) : MoveRemoteFileOperation(
|
||||
sourceRemotePath = sourceRemotePath,
|
||||
targetRemotePath = targetRemotePath,
|
||||
) {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param srcRemotePath Remote path of the file/folder to move.
|
||||
* @param targetRemotePath Remove path desired for the file/folder after moving it.
|
||||
* @param overwrite
|
||||
*/
|
||||
public MoveRemoteChunksFileOperation(String srcRemotePath, String targetRemotePath, boolean overwrite,
|
||||
String fileLastModifTimestamp, long fileLength) {
|
||||
super(srcRemotePath, targetRemotePath, overwrite);
|
||||
moveChunkedFile = true;
|
||||
mFileLastModifTimestamp = fileLastModifTimestamp;
|
||||
mFileLength = fileLength;
|
||||
override fun getSrcWebDavUriForClient(client: OwnCloudClient): Uri = client.uploadsWebDavUri
|
||||
|
||||
override fun addRequestHeaders(moveMethod: MoveMethod) {
|
||||
super.addRequestHeaders(moveMethod)
|
||||
|
||||
moveMethod.apply {
|
||||
addRequestHeader(HttpConstants.OC_X_OC_MTIME_HEADER, fileLastModificationTimestamp)
|
||||
addRequestHeader(HttpConstants.OC_TOTAL_LENGTH_HEADER, fileLength.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -22,20 +22,12 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
package com.owncloud.android.lib.resources.files.chunks
|
||||
|
||||
package com.owncloud.android.lib.resources.files.chunks;
|
||||
import android.net.Uri
|
||||
import com.owncloud.android.lib.common.OwnCloudClient
|
||||
import com.owncloud.android.lib.resources.files.RemoveRemoteFileOperation
|
||||
|
||||
import com.owncloud.android.lib.resources.files.RemoveRemoteFileOperation;
|
||||
|
||||
public class RemoveRemoteChunksFolderOperation extends RemoveRemoteFileOperation {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param remotePath RemotePath of the remote file or folder to remove from the server
|
||||
*/
|
||||
public RemoveRemoteChunksFolderOperation(String remotePath) {
|
||||
super(remotePath);
|
||||
removeChunksFolder = true;
|
||||
}
|
||||
}
|
||||
class RemoveRemoteChunksFolderOperation(remotePath: String) : RemoveRemoteFileOperation(remotePath) {
|
||||
override fun getSrcWebDavUriForClient(client: OwnCloudClient): Uri = client.uploadsWebDavUri
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
* Copyright (C) 2021 ownCloud GmbH.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -21,29 +21,21 @@
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
package com.owncloud.android.lib.resources.files
|
||||
|
||||
import android.net.Uri
|
||||
import com.owncloud.android.lib.common.OwnCloudClient
|
||||
import okhttp3.HttpUrl
|
||||
package com.owncloud.android.lib.resources.files.services
|
||||
|
||||
class RemoteFileUtil {
|
||||
companion object {
|
||||
/**
|
||||
* Retrieves a relative path from a remote file url
|
||||
*
|
||||
*
|
||||
* Example: url:port/remote.php/dav/files/username/Documents/text.txt => /Documents/text.txt
|
||||
*
|
||||
* @param url remote file url
|
||||
* @param userId file owner
|
||||
* @return remote relative path of the file
|
||||
*/
|
||||
fun getRemotePathFromUrl(url: HttpUrl, userId: String): String? {
|
||||
val davFilesPath = OwnCloudClient.WEBDAV_FILES_PATH_4_0 + userId
|
||||
val absoluteDavPath = Uri.decode(url.encodedPath)
|
||||
val pathToOc = absoluteDavPath.split(davFilesPath)[0]
|
||||
return absoluteDavPath.replace(pathToOc + davFilesPath, "")
|
||||
}
|
||||
}
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
||||
import com.owncloud.android.lib.resources.Service
|
||||
|
||||
interface ChunkService : Service {
|
||||
fun removeFile(
|
||||
remotePath: String
|
||||
): RemoteOperationResult<Unit>
|
||||
|
||||
fun moveFile(
|
||||
sourceRemotePath: String,
|
||||
targetRemotePath: String,
|
||||
fileLastModificationTimestamp: String,
|
||||
fileLength: Long
|
||||
): RemoteOperationResult<Unit>
|
||||
}
|
@ -25,8 +25,53 @@ package com.owncloud.android.lib.resources.files.services
|
||||
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
||||
import com.owncloud.android.lib.resources.Service
|
||||
import com.owncloud.android.lib.resources.files.RemoteFile
|
||||
|
||||
interface FileService : Service {
|
||||
fun checkPathExistence(path: String, isUserLogged: Boolean): RemoteOperationResult<Boolean>
|
||||
fun getUrlToOpenInWeb(openWebEndpoint: String, fileId: String): RemoteOperationResult<String>
|
||||
|
||||
fun checkPathExistence(
|
||||
path: String,
|
||||
isUserLogged: Boolean
|
||||
): RemoteOperationResult<Boolean>
|
||||
|
||||
fun copyFile(
|
||||
sourceRemotePath: String,
|
||||
targetRemotePath: String,
|
||||
): RemoteOperationResult<String>
|
||||
|
||||
fun createFolder(
|
||||
remotePath: String,
|
||||
createFullPath: Boolean,
|
||||
isChunkFolder: Boolean = false
|
||||
): RemoteOperationResult<Unit>
|
||||
|
||||
fun downloadFile(
|
||||
remotePath: String,
|
||||
localTempPath: String
|
||||
): RemoteOperationResult<Unit>
|
||||
|
||||
fun moveFile(
|
||||
sourceRemotePath: String,
|
||||
targetRemotePath: String,
|
||||
): RemoteOperationResult<Unit>
|
||||
|
||||
fun readFile(
|
||||
remotePath: String
|
||||
): RemoteOperationResult<RemoteFile>
|
||||
|
||||
fun refreshFolder(
|
||||
remotePath: String
|
||||
): RemoteOperationResult<ArrayList<RemoteFile>>
|
||||
|
||||
fun removeFile(
|
||||
remotePath: String
|
||||
): RemoteOperationResult<Unit>
|
||||
|
||||
fun renameFile(
|
||||
oldName: String,
|
||||
oldRemotePath: String,
|
||||
newName: String,
|
||||
isFolder: Boolean,
|
||||
): RemoteOperationResult<Unit>
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
/* ownCloud Android Library is available under MIT license
|
||||
* Copyright (C) 2021 ownCloud GmbH.
|
||||
*
|
||||
* 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.services.implementation
|
||||
|
||||
import com.owncloud.android.lib.common.OwnCloudClient
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
||||
import com.owncloud.android.lib.resources.files.chunks.MoveRemoteChunksFileOperation
|
||||
import com.owncloud.android.lib.resources.files.chunks.RemoveRemoteChunksFolderOperation
|
||||
import com.owncloud.android.lib.resources.files.services.ChunkService
|
||||
|
||||
class OCChunkService(override val client: OwnCloudClient) : ChunkService {
|
||||
|
||||
override fun removeFile(remotePath: String): RemoteOperationResult<Unit> =
|
||||
RemoveRemoteChunksFolderOperation(remotePath = remotePath).execute(client)
|
||||
|
||||
override fun moveFile(
|
||||
sourceRemotePath: String,
|
||||
targetRemotePath: String,
|
||||
fileLastModificationTimestamp: String,
|
||||
fileLength: Long
|
||||
): RemoteOperationResult<Unit> =
|
||||
MoveRemoteChunksFileOperation(
|
||||
sourceRemotePath = sourceRemotePath,
|
||||
targetRemotePath = targetRemotePath,
|
||||
fileLastModificationTimestamp = fileLastModificationTimestamp,
|
||||
fileLength = fileLength,
|
||||
).execute(client)
|
||||
}
|
@ -26,12 +26,24 @@ package com.owncloud.android.lib.resources.files.services.implementation
|
||||
import com.owncloud.android.lib.common.OwnCloudClient
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
||||
import com.owncloud.android.lib.resources.files.CheckPathExistenceRemoteOperation
|
||||
import com.owncloud.android.lib.resources.files.CopyRemoteFileOperation
|
||||
import com.owncloud.android.lib.resources.files.CreateRemoteFolderOperation
|
||||
import com.owncloud.android.lib.resources.files.DownloadRemoteFileOperation
|
||||
import com.owncloud.android.lib.resources.files.GetUrlToOpenInWebRemoteOperation
|
||||
import com.owncloud.android.lib.resources.files.MoveRemoteFileOperation
|
||||
import com.owncloud.android.lib.resources.files.ReadRemoteFileOperation
|
||||
import com.owncloud.android.lib.resources.files.ReadRemoteFolderOperation
|
||||
import com.owncloud.android.lib.resources.files.RemoteFile
|
||||
import com.owncloud.android.lib.resources.files.RemoveRemoteFileOperation
|
||||
import com.owncloud.android.lib.resources.files.RenameRemoteFileOperation
|
||||
import com.owncloud.android.lib.resources.files.services.FileService
|
||||
|
||||
class OCFileService(override val client: OwnCloudClient) :
|
||||
FileService {
|
||||
override fun checkPathExistence(path: String, isUserLogged: Boolean): RemoteOperationResult<Boolean> =
|
||||
class OCFileService(override val client: OwnCloudClient) : FileService {
|
||||
|
||||
override fun checkPathExistence(
|
||||
path: String,
|
||||
isUserLogged: Boolean
|
||||
): RemoteOperationResult<Boolean> =
|
||||
CheckPathExistenceRemoteOperation(
|
||||
remotePath = path,
|
||||
isUserLoggedIn = isUserLogged
|
||||
@ -40,4 +52,75 @@ class OCFileService(override val client: OwnCloudClient) :
|
||||
override fun getUrlToOpenInWeb(openWebEndpoint: String, fileId: String): RemoteOperationResult<String> =
|
||||
GetUrlToOpenInWebRemoteOperation(openWithWebEndpoint = openWebEndpoint, fileId = fileId).execute(client)
|
||||
|
||||
override fun copyFile(
|
||||
sourceRemotePath: String,
|
||||
targetRemotePath: String
|
||||
): RemoteOperationResult<String> =
|
||||
CopyRemoteFileOperation(
|
||||
srcRemotePath = sourceRemotePath,
|
||||
targetRemotePath = targetRemotePath
|
||||
).execute(client)
|
||||
|
||||
override fun createFolder(
|
||||
remotePath: String,
|
||||
createFullPath: Boolean,
|
||||
isChunkFolder: Boolean
|
||||
): RemoteOperationResult<Unit> =
|
||||
CreateRemoteFolderOperation(
|
||||
remotePath = remotePath,
|
||||
createFullPath = createFullPath,
|
||||
isChunksFolder = isChunkFolder
|
||||
).execute(client)
|
||||
|
||||
override fun downloadFile(
|
||||
remotePath: String,
|
||||
localTempPath: String
|
||||
): RemoteOperationResult<Unit> =
|
||||
DownloadRemoteFileOperation(
|
||||
remotePath = remotePath,
|
||||
localFolderPath = localTempPath
|
||||
).execute(client)
|
||||
|
||||
override fun moveFile(
|
||||
sourceRemotePath: String,
|
||||
targetRemotePath: String,
|
||||
): RemoteOperationResult<Unit> =
|
||||
MoveRemoteFileOperation(
|
||||
sourceRemotePath = sourceRemotePath,
|
||||
targetRemotePath = targetRemotePath,
|
||||
).execute(client)
|
||||
|
||||
override fun readFile(
|
||||
remotePath: String
|
||||
): RemoteOperationResult<RemoteFile> =
|
||||
ReadRemoteFileOperation(
|
||||
remotePath = remotePath
|
||||
).execute(client)
|
||||
|
||||
override fun refreshFolder(
|
||||
remotePath: String
|
||||
): RemoteOperationResult<ArrayList<RemoteFile>> =
|
||||
ReadRemoteFolderOperation(
|
||||
remotePath = remotePath
|
||||
).execute(client)
|
||||
|
||||
override fun removeFile(
|
||||
remotePath: String
|
||||
): RemoteOperationResult<Unit> =
|
||||
RemoveRemoteFileOperation(
|
||||
remotePath = remotePath
|
||||
).execute(client)
|
||||
|
||||
override fun renameFile(
|
||||
oldName: String,
|
||||
oldRemotePath: String,
|
||||
newName: String,
|
||||
isFolder: Boolean
|
||||
): RemoteOperationResult<Unit> =
|
||||
RenameRemoteFileOperation(
|
||||
oldName = oldName,
|
||||
oldRemotePath = oldRemotePath,
|
||||
newName = newName,
|
||||
isFolder = isFolder
|
||||
).execute(client)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user